import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1201329 - Use AlignedStorage2 instead of char[] for IPDL union members. r=billm (420db1710)
- Bug 1146214 - Remove unused set fence functions. r=nical (148188894)
- Bug 1146214 - Combine FenceHandle and FenceHandleFromChild. r=nical (9d33cdedc)
- Bug 1147894 - Remove the redundant OpUpdateTexture IPDL message. r=sotaro (c3b037c92)
- Bug 1146214 - Implement fence delivery. Combine ipc messages and remove reply fence delivery message. r=nical (cd115f0db)
- Bug 1146214 - Remove the unused code after refactoring. r=nical (2582f1dfa)
- Bug 1146214 - Rename some functions after refactoring. r=nical (fd7655c71)
- Bug 1150381 - [LayerScope]: Don't showing the same texture in the same frame on LayerScope. r=chiajung (7a5310113)
- Bug 1162395 - [LayerScope]: No need to read and send the texture when the same texture id contains in a frame. r=cku (2c67a0994)
- Bug 1168015 - Dump source image from graphic buffer directly on B2G. r=kamidphish, r=hshih (108f3dd5a)
- Bug 1158575: Support using GDI rendering for opaque surfaces when using cross-process layers. r=jrmuizel (8913ea2ff)
- Bug 1155498 - Use FdObj to replace FenceHandle's android fence. r=sotaro (ac0f66f02)
- Bug 1155498 - Part 2 - Use new FenceHandle to handle the fence in TextureHost. r=sotaro (8c3cd6427)
- Bug 1152370 part 1 - Add android aosp VirtualDisplaySurface r=mwu (795674527)
- Bug 1152370 part 2 - Add DisplaySurface r=mwu (f4e7cb123)
- Bug 1151936 - Update GLContextEGL's EGLSurface override handling r=jgilbert (a1a72947b)
- Bug 1154313 - Move sUsingHwc to gfxPrefs r=mwu,nical (d315f572a)
- Bug 1152361 - Ensure outbufAcquireFenceFd is initialized during boot animation. r=mwu (c17f9bc1a)
- Bug 1152135 - Split EGLSurface buffer swap and HWC buffer swap r=mwu,nical,jgilbert (2ec0aaccc)
- Bug 1148149 - Support Android Presentation API. r=snorp, r=jgilbert (60ae01557)
- Bug 1150518 - Remove glClear() on blit composition r=Sushil (24b242a14)
- Bug 1152370 part 3 - Use DisplaySurface r=mwu (c531c0b44)
- Bug 1157661 - Fix a null-check in CompositorOGL::DrawQuad. r=nical (c00d429d3)
- Bug 1113425 part 1 - Fix some bad CSS comment syntax in animation tests; r=mattwoodrow (7abbbb3de)
- Bug 1113425 part 2 - Apply async properties when querying the animated transform; r=mattwoodrow (52e778eeb)
- Bug 1113425 part 4 - Enable test_deferred_start.html on all platforms; r=mattwoodrow (3884a02a3)
- Bug 1113425 part 3 - Make test_deferred_start.html wait an extra frame; r=mattwoodrow (0971c8836)
- Bug 1148949 - Apply async properties when querying the animated transform for cross-process compositor parents too; r=mattwoodrow (8bdeafc25)
- Bug 1157066. When reading back the OMTA transfrom of a layer don't include transforms from async panning or zooming. r=kats,birtles (43c1bab02)
- Bug 1129133 - Clean up GeckoTouchDispatcher so that it's a real singleton. r=kats,mwu (ac97ee5f4)
- Bug 1140578 - Remove some redundant code and an unused return value. r=mchang (9d02a9794)
- Bug 1140578 - Simplify some code. r=mchang (5a2f95805)
- Bug 1140578 - Add a explicit flag to track if we have pending touch moves to process. r=mchang (3255a2ac8)
- Bug 1140578 - Prevent resampling moves across non-move touch events. r=mchang (5a2622f6c)
- Bug 1146987 - Deal with cases where we get a batch of interleaved move and non-move events on the libui thread before anything is processed, with resampling disabled. r=mchang (462ce355c)
- Bug 1149412 - Remove bad assertion. r=mchang (d9d2db4ba)
- Bug 1137151: Marked destructor of |GeckoTouchDispatcher| as protected, r=mwu (21fae6af2)
- Bug 1138502. Reset vsync unobserve count if a force composite occurs. r=mstange (9682c9e62)
- Bug 1148583 - Dispatch touch events before composites. r=kats (cfabb0eef)
- Bug 1128690 - Ensure Talos Performance Tests still work with silk enabled. r=mstange (089e87b89)
- Bug 1138181 - Be more aggressive in updating plugin geometry in the compositor, avoids filtering out important offset updates that don't involve remote layer tree updates. r=roc (e341636de)
- comment coming from Bug 1143249 (2f6c7bdc8)
- Bug 1154614 - Don't try to pick up the same non-reentrant lock twice. r=dvander a=RyanVM (c69cba3d9)
- Bug 1156981 - Split CompositorParent's scheduling of composition to CompositorScheduler r=mchang (bf87b2ba3)
- Bug 1139541 - Make HWC skip opacity=0 layers. r=sotaro (cd6d5114c)
- Bug 1149646 - Delete non-uniform vsync interval warning. r=kats (5bc0cd3fa)
- Bug 1155498 - Part 3 - Use new FenceHandle to handle the fence in Compositor. r=sotaro (f5c685606)
-  Bug 1155498 - Part 4 - Use new FenceHandle to handle the fence in TextureClient. r=sotaro (0390d19fd)
- Bug 1155498 - Part 5 - Use new FenceHandle to handle Decoder fence. r=sotaro (a99b62351)
- Bug 1164513 - Add nullptr check r=milan (41053d048)
- Bug 1155495 - Part 1: Remove TextureHostOGL and integrate the platform specific API into TextureHost. r=nical, r=sotaro (9c909e5e2)
- Bug 1155495 - Part 2: Remove unnecessary class inheritance and casting. r=nical, r=sotaro (4ce5869ff)
- Bug 1133007 - Send the content of a texture only if its was altered since previous transmission. r=kamidphish, r=boris (f78a07160)
- Bug 1156456 patch 1 - Reftests comparing a 3-D transformed cube generated by main-thread paths and off-main-thread animations paths. r=birtles (f0f5309d9)
- Bug 1156456 patch 2 - Transform the z component just like the x and y. r=birtles (cc36b5b91)
- Bug 1156456 patch 3 - Send transform origin and perspective origin to layer in device pixels rather than CSS pixels. r=birtles (94ea8a04a)
- Bug 1156456 followup - Also annotate as fuzzy on Mulet, on a CLOSED TREE. (712c97eff)
- Bug 1156456 followup - Add a simple reftest for off-main-thread animation of opacity. (eac0fe0e4)
- Bug 1157455 patch 1 - Add tests for OMTA transforms in degrees in addition to those in radians. r=birtles (83fb5b7af)
- Bug 1157455 patch 2 - Send angles (in CSS transform functions) to the compositor thread with their units rather than sending all such angles in radians. r=birtles (a8b47f5b0)
- Bug 1157455 patch 3 - When interpolating angles, preserve units when possible in order to avoid floating point error. r=birtles (ace148e00)
- Bug 1157455 followup - fix test_transitions_per_property.html to expect different angle interpolation results, on a CLOSED TREE. (270ef56eb)
- Bug 1022080 - Don't force intermediate surfaces when dumping textures, unless explicitly specified. r=nical (0a010b6c8)
- Bug 1022080 - Make non-HTML dumping of textures work better. r=nical (304939544)
This commit is contained in:
2020-12-02 09:53:44 +08:00
parent 538b35a4ee
commit a057fcd85b
112 changed files with 3858 additions and 1943 deletions
@@ -14,7 +14,7 @@
to { transform: translate(100px) }
}
.target {
// Element needs geometry to be eligible for layerization
/* Element needs geometry to be eligible for layerization */
width: 100px;
height: 100px;
background-color: white;
-1
View File
@@ -28,4 +28,3 @@ skip-if = buildapp == 'mulet'
[document-timeline/test_request_animation_frame.html]
skip-if = buildapp == 'mulet'
[mozilla/test_deferred_start.html]
skip-if = buildapp == 'mulet' || buildapp == 'b2g' # bug 1113425, 1119981
@@ -11,7 +11,7 @@
to { transform: translate(100px); }
}
.target {
// Element needs geometry to be eligible for layerization
/* Element needs geometry to be eligible for layerization */
width: 100px;
height: 100px;
background-color: white;
@@ -60,13 +60,18 @@ async_test(function(t) {
assert_unreached('ready promise was rejected');
});
// We need to wait for up to two frames since the animation may not start
// until the beginning of the next refresh driver tick and it won't queue
// the ready Promise callback until that point.
}).then(waitForFrame).then(waitForFrame).then(t.step_func(function() {
// We need to wait for up to three frames. This is because in some
// cases it can take up to two frames for the initial layout
// to take place. Even after that happens we don't actually resolve the
// ready promise until the following tick.
})
.then(waitForFrame)
.then(waitForFrame)
.then(waitForFrame)
.then(t.step_func(function() {
assert_true(promiseCallbackDone,
'ready promise callback was called before the next'
+ ' requestAnimationFrame callback');
'ready promise for an empty animation was resolved'
+ ' within three animation frames');
t.done();
}));
}, 'Animation.ready is resolved for an empty animation');
+7 -14
View File
@@ -790,16 +790,9 @@ MediaCodecReader::TextureClientRecycleCallback(TextureClient* aClient)
return;
}
#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
sp<Fence> fence = aClient->GetReleaseFenceHandle().mFence;
if (fence.get() && fence->isValid()) {
mPendingReleaseItems.AppendElement(ReleaseItem(index, fence));
} else {
mPendingReleaseItems.AppendElement(ReleaseItem(index, nullptr));
}
#else
mPendingReleaseItems.AppendElement(ReleaseItem(index));
#endif
FenceHandle handle = aClient->GetAndResetReleaseFenceHandle();
mPendingReleaseItems.AppendElement(ReleaseItem(index, handle));
mTextureClientIndexes.Remove(aClient);
}
@@ -822,13 +815,13 @@ MediaCodecReader::WaitFenceAndReleaseOutputBuffer()
}
for (size_t i = 0; i < releasingItems.Length(); i++) {
if (releasingItems[i].mReleaseFence.IsValid()) {
#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
sp<Fence> fence;
fence = releasingItems[i].mReleaseFence;
if (fence.get() && fence->isValid()) {
nsRefPtr<FenceHandle::FdObj> fdObj = releasingItems[i].mReleaseFence.GetAndResetFdObj();
sp<Fence> fence = new Fence(fdObj->GetAndResetFd());
fence->waitForever("MediaCodecReader");
}
#endif
}
if (mVideoTrack.mCodec != nullptr) {
mVideoTrack.mCodec->releaseOutputBuffer(releasingItems[i].mReleaseIndex);
}
+2 -10
View File
@@ -436,25 +436,17 @@ private:
int64_t mNextParserPosition;
int64_t mParsedDataLength;
nsAutoPtr<MP3FrameParser> mMP3FrameParser;
#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
// mReleaseIndex corresponding to a graphic buffer, and the mReleaseFence is
// the graohic buffer's fence. We must wait for the fence signaled by
// compositor, otherwise we will see the flicker because the HW decoder and
// compositor use the buffer concurrently.
struct ReleaseItem {
ReleaseItem(size_t aIndex, const android::sp<android::Fence>& aFence)
ReleaseItem(size_t aIndex, const FenceHandle& aFence)
: mReleaseIndex(aIndex)
, mReleaseFence(aFence) {}
size_t mReleaseIndex;
android::sp<android::Fence> mReleaseFence;
FenceHandle mReleaseFence;
};
#else
struct ReleaseItem {
ReleaseItem(size_t aIndex)
: mReleaseIndex(aIndex) {}
size_t mReleaseIndex;
};
#endif
nsTArray<ReleaseItem> mPendingReleaseItems;
};
+5 -8
View File
@@ -355,7 +355,7 @@ void OmxDecoder::ReleaseMediaResources() {
GrallocTextureClientOGL* client = static_cast<GrallocTextureClientOGL*>(*it);
client->ClearRecycleCallback();
if (client->GetMediaBuffer()) {
mPendingVideoBuffers.push(BufferItem(client->GetMediaBuffer(), client->GetReleaseFenceHandle()));
mPendingVideoBuffers.push(BufferItem(client->GetMediaBuffer(), client->GetAndResetReleaseFenceHandle()));
}
}
mPendingRecycleTexutreClients.clear();
@@ -869,12 +869,9 @@ void OmxDecoder::ReleaseAllPendingVideoBuffersLocked()
MediaBuffer *buffer;
buffer = releasingVideoBuffers[i].mMediaBuffer;
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
android::sp<Fence> fence;
int fenceFd = -1;
fence = releasingVideoBuffers[i].mReleaseFenceHandle.mFence;
if (fence.get() && fence->isValid()) {
fenceFd = fence->dup();
}
nsRefPtr<FenceHandle::FdObj> fdObj = releasingVideoBuffers.editItemAt(i).mReleaseFenceHandle.GetAndResetFdObj();
int fenceFd = fdObj->GetAndResetFd();
MOZ_ASSERT(buffer->refcount() == 1);
// This code expect MediaBuffer's ref count is 1.
// Return gralloc buffer to ANativeWindow
@@ -906,7 +903,7 @@ void OmxDecoder::RecycleCallbackImp(TextureClient* aClient)
mPendingRecycleTexutreClients.erase(aClient);
GrallocTextureClientOGL* client = static_cast<GrallocTextureClientOGL*>(aClient);
if (client->GetMediaBuffer()) {
mPendingVideoBuffers.push(BufferItem(client->GetMediaBuffer(), client->GetReleaseFenceHandle()));
mPendingVideoBuffers.push(BufferItem(client->GetMediaBuffer(), client->GetAndResetReleaseFenceHandle()));
}
}
sp<AMessage> notify =
+14
View File
@@ -14,6 +14,8 @@
#include "HwcComposer2D.h"
#endif
class nsIWidget;
namespace mozilla {
namespace gl {
@@ -46,6 +48,10 @@ public:
return static_cast<GLContextEGL*>(gl);
}
static EGLSurface CreateSurfaceForWindow(nsIWidget* aWidget);
static void DestroySurface(EGLSurface aSurface);
bool Init() override;
virtual bool IsDoubleBuffered() const override {
@@ -90,6 +96,14 @@ public:
return mContext;
}
EGLSurface GetEGLSurface() {
return mSurface;
}
EGLDisplay GetEGLDisplay() {
return EGL_DISPLAY();
}
bool BindTex2DOffscreen(GLContext *aOffscreen);
void UnbindTex2DOffscreen(GLContext *aOffscreen);
void BindOffscreenFramebuffer();
+76 -23
View File
@@ -228,17 +228,6 @@ GLContextEGL::GLContextEGL(
#ifdef DEBUG
printf_stderr("Initializing context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
#endif
#if defined(MOZ_WIDGET_GONK)
if (!mIsOffscreen) {
mHwc = HwcComposer2D::GetInstance();
MOZ_ASSERT(!mHwc->Initialized());
if (mHwc->Init(EGL_DISPLAY(), mSurface, this)) {
NS_WARNING("HWComposer initialization failed!");
mHwc = nullptr;
}
}
#endif
}
GLContextEGL::~GLContextEGL()
@@ -358,7 +347,7 @@ GLContextEGL::SetEGLSurfaceOverride(EGLSurface surf) {
Screen()->AssureBlitted();
}
mSurfaceOverride = surf ? (EGLSurface) surf : mSurface;
mSurfaceOverride = surf;
MakeCurrent(true);
}
@@ -442,7 +431,10 @@ GLContextEGL::RenewSurface() {
void
GLContextEGL::ReleaseSurface() {
if (mOwnsContext) {
DestroySurface(mSurface);
mozilla::gl::DestroySurface(mSurface);
}
if (mSurface == mSurfaceOverride) {
mSurfaceOverride = EGL_NO_SURFACE;
}
mSurface = EGL_NO_SURFACE;
}
@@ -457,17 +449,17 @@ GLContextEGL::SetupLookupFunction()
bool
GLContextEGL::SwapBuffers()
{
if (mSurface) {
#ifdef MOZ_WIDGET_GONK
EGLSurface surface = mSurfaceOverride != EGL_NO_SURFACE
? mSurfaceOverride
: mSurface;
if (surface) {
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION < 17
if (!mIsOffscreen) {
if (mHwc) {
return mHwc->Render(EGL_DISPLAY(), mSurface);
} else {
return GetGonkDisplay()->SwapBuffers(EGL_DISPLAY(), mSurface);
}
} else
// eglSwapBuffers() is called by hwcomposer.
return true;
}
#endif
return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), mSurface);
return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), surface);
} else {
return false;
}
@@ -480,6 +472,32 @@ GLContextEGL::HoldSurface(gfxASurface *aSurf) {
mThebesSurface = aSurf;
}
/* static */ EGLSurface
GLContextEGL::CreateSurfaceForWindow(nsIWidget* aWidget)
{
if (!sEGLLibrary.EnsureInitialized()) {
MOZ_CRASH("Failed to load EGL library!\n");
return nullptr;
}
EGLConfig config;
if (!CreateConfig(&config)) {
MOZ_CRASH("Failed to create EGLConfig!\n");
return nullptr;
}
EGLSurface surface = mozilla::gl::CreateSurfaceForWindow(aWidget, config);
return surface;
}
/* static */ void
GLContextEGL::DestroySurface(EGLSurface aSurface)
{
if (aSurface != EGL_NO_SURFACE) {
sEGLLibrary.fDestroySurface(EGL_DISPLAY(), aSurface);
}
}
already_AddRefed<GLContextEGL>
GLContextEGL::CreateGLContext(const SurfaceCaps& caps,
GLContextEGL *shareContext,
@@ -772,7 +790,7 @@ GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget)
if (!glContext) {
MOZ_CRASH("Failed to create EGLContext!\n");
DestroySurface(surface);
mozilla::gl::DestroySurface(surface);
return nullptr;
}
@@ -782,6 +800,41 @@ GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget)
return glContext.forget();
}
#if defined(ANDROID)
EGLSurface
GLContextProviderEGL::CreateEGLSurface(void* aWindow)
{
if (!sEGLLibrary.EnsureInitialized()) {
MOZ_CRASH("Failed to load EGL library!\n");
}
EGLConfig config;
if (!CreateConfig(&config)) {
MOZ_CRASH("Failed to create EGLConfig!\n");
}
MOZ_ASSERT(aWindow);
EGLSurface surface = sEGLLibrary.fCreateWindowSurface(EGL_DISPLAY(), config, aWindow, 0);
if (surface == EGL_NO_SURFACE) {
MOZ_CRASH("Failed to create EGLSurface!\n");
}
return surface;
}
void
GLContextProviderEGL::DestroyEGLSurface(EGLSurface surface)
{
if (!sEGLLibrary.EnsureInitialized()) {
MOZ_CRASH("Failed to load EGL library!\n");
}
sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
}
#endif // defined(ANDROID)
already_AddRefed<GLContextEGL>
GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& size)
{
+8
View File
@@ -10,6 +10,9 @@
#ifndef GL_CONTEXT_PROVIDER_NAME
#error GL_CONTEXT_PROVIDER_NAME not defined
#endif
#if defined(ANDROID)
typedef void* EGLSurface;
#endif // defined(ANDROID)
class GL_CONTEXT_PROVIDER_NAME
{
@@ -76,6 +79,11 @@ public:
static already_AddRefed<GLContext>
CreateWrappingExisting(void* aContext, void* aSurface);
#if defined(ANDROID)
static EGLSurface CreateEGLSurface(void* aWindow);
static void DestroyEGLSurface(EGLSurface surface);
#endif // defined(ANDROID)
/**
* Get a pointer to the global context, creating it if it doesn't exist.
*/
+1 -3
View File
@@ -194,9 +194,7 @@ SharedSurface_Gralloc::Fence()
int fenceFd = mEGL->fDupNativeFenceFDANDROID(mEGL->Display(), sync);
if (fenceFd != -1) {
mEGL->fDestroySync(mEGL->Display(), sync);
android::sp<android::Fence> fence(new android::Fence(fenceFd));
FenceHandle handle = FenceHandle(fence);
mTextureClient->SetAcquireFenceHandle(handle);
mTextureClient->SetAcquireFenceHandle(FenceHandle(new FenceHandle::FdObj(fenceFd)));
} else {
mSync = sync;
}
+1 -1
View File
@@ -337,7 +337,7 @@ public:
*/
virtual void EndFrame() = 0;
virtual void SetFBAcquireFence(Layer* aLayer) {}
virtual void SetDispAcquireFence(Layer* aLayer) {}
virtual FenceHandle GetReleaseFence()
{
+12 -5
View File
@@ -74,6 +74,7 @@ struct TexturedEffect : public Effect
TextureSource* mTexture;
bool mPremultiplied;
gfx::Filter mFilter;
LayerRenderState mState;
};
// Support an alpha mask.
@@ -248,7 +249,8 @@ inline already_AddRefed<TexturedEffect>
CreateTexturedEffect(gfx::SurfaceFormat aFormat,
TextureSource* aSource,
const gfx::Filter& aFilter,
bool isAlphaPremultiplied)
bool isAlphaPremultiplied,
const LayerRenderState &state = LayerRenderState())
{
MOZ_ASSERT(aSource);
RefPtr<TexturedEffect> result;
@@ -268,6 +270,8 @@ CreateTexturedEffect(gfx::SurfaceFormat aFormat,
break;
}
result->mState = state;
return result.forget();
}
@@ -281,7 +285,8 @@ inline already_AddRefed<TexturedEffect>
CreateTexturedEffect(TextureSource* aSource,
TextureSource* aSourceOnWhite,
const gfx::Filter& aFilter,
bool isAlphaPremultiplied)
bool isAlphaPremultiplied,
const LayerRenderState &state = LayerRenderState())
{
MOZ_ASSERT(aSource);
if (aSourceOnWhite) {
@@ -293,7 +298,8 @@ CreateTexturedEffect(TextureSource* aSource,
return CreateTexturedEffect(aSource->GetFormat(),
aSource,
aFilter,
isAlphaPremultiplied);
isAlphaPremultiplied,
state);
}
/**
@@ -303,9 +309,10 @@ CreateTexturedEffect(TextureSource* aSource,
*/
inline already_AddRefed<TexturedEffect>
CreateTexturedEffect(TextureSource *aTexture,
const gfx::Filter& aFilter)
const gfx::Filter& aFilter,
const LayerRenderState &state = LayerRenderState())
{
return CreateTexturedEffect(aTexture, nullptr, aFilter, true);
return CreateTexturedEffect(aTexture, nullptr, aFilter, true, state);
}
+370 -123
View File
@@ -48,6 +48,7 @@
#include "nsIAsyncInputStream.h"
#include "nsIEventTarget.h"
#include "nsProxyRelease.h"
#include <list>
// Undo the damage done by mozzconf.h
#undef compress
@@ -177,37 +178,141 @@ private:
nsCOMPtr<nsIServerSocket> mServerSocket;
};
// Static class to create and destory LayerScopeWebSocketManager object
class WebSocketHelper
class DrawSession {
public:
DrawSession()
: mOffsetX(0.0)
, mOffsetY(0.0)
, mRects(0)
{ }
float mOffsetX;
float mOffsetY;
gfx::Matrix4x4 mMVMatrix;
size_t mRects;
gfx::Rect mLayerRects[4];
};
class ContentMonitor {
public:
using THArray = nsTArray<const TextureHost *>;
// Notify the content of a TextureHost was changed.
void SetChangedHost(const TextureHost* host) {
if (THArray::NoIndex == mChangedHosts.IndexOf(host)) {
mChangedHosts.AppendElement(host);
}
}
// Clear changed flag of a host.
void ClearChangedHost(const TextureHost* host) {
if (THArray::NoIndex != mChangedHosts.IndexOf(host)) {
mChangedHosts.RemoveElement(host);
}
}
// Return true iff host is a new one or the content of it had been changed.
bool IsChangedOrNew(const TextureHost* host) {
if (THArray::NoIndex == mSeenHosts.IndexOf(host)) {
mSeenHosts.AppendElement(host);
return true;
}
if (decltype(mChangedHosts)::NoIndex != mChangedHosts.IndexOf(host)) {
return true;
}
return false;
}
void Empty() {
mSeenHosts.SetLength(0);
mChangedHosts.SetLength(0);
}
private:
THArray mSeenHosts;
THArray mChangedHosts;
};
// Hold all singleton objects used by LayerScope
class LayerScopeManager
{
public:
static void CreateServerSocket()
void CreateServerSocket()
{
// Create Web Server Socket (which has to be on the main thread)
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
if (!sWebSocketManager) {
sWebSocketManager = new LayerScopeWebSocketManager();
// WebSocketManager must be created on the main thread.
if (NS_IsMainThread()) {
mWebSocketManager = mozilla::MakeUnique<LayerScopeWebSocketManager>();
} else {
// Dispatch creation to main thread, and make sure we
// dispatch this only once after booting
static bool dispatched = false;
if (dispatched) {
return;
}
DebugOnly<nsresult> rv =
NS_DispatchToMainThread(new CreateServerSocketRunnable(this));
MOZ_ASSERT(NS_SUCCEEDED(rv),
"Failed to dispatch WebSocket Creation to main thread");
dispatched = true;
}
}
static void DestroyServerSocket()
void DestroyServerSocket()
{
// Destroy Web Server Socket
if (sWebSocketManager) {
sWebSocketManager->RemoveAllConnections();
if (mWebSocketManager) {
mWebSocketManager->RemoveAllConnections();
}
}
static LayerScopeWebSocketManager* GetSocketManager()
LayerScopeWebSocketManager* GetSocketManager()
{
return sWebSocketManager;
return mWebSocketManager.get();
}
ContentMonitor* GetContentMonitor()
{
if (!mContentMonitor.get()) {
mContentMonitor = mozilla::MakeUnique<ContentMonitor>();
}
return mContentMonitor.get();
}
void NewDrawSession() {
mSession = mozilla::MakeUnique<DrawSession>();
}
DrawSession& CurrentSession() {
return *mSession;
}
private:
static StaticAutoPtr<LayerScopeWebSocketManager> sWebSocketManager;
friend class CreateServerSocketRunnable;
class CreateServerSocketRunnable : public nsRunnable
{
public:
CreateServerSocketRunnable(LayerScopeManager *aLayerScopeManager)
: mLayerScopeManager(aLayerScopeManager)
{
}
NS_IMETHOD Run() {
mLayerScopeManager->mWebSocketManager =
mozilla::MakeUnique<LayerScopeWebSocketManager>();
return NS_OK;
}
private:
LayerScopeManager* mLayerScopeManager;
};
mozilla::UniquePtr<LayerScopeWebSocketManager> mWebSocketManager;
mozilla::UniquePtr<DrawSession> mSession;
mozilla::UniquePtr<ContentMonitor> mContentMonitor;
};
StaticAutoPtr<LayerScopeWebSocketManager> WebSocketHelper::sWebSocketManager;
LayerScopeManager gLayerScopeManager;
/*
* DebugGLData is the base class of
@@ -229,13 +334,13 @@ public:
protected:
static bool WriteToStream(Packet& aPacket) {
if (!WebSocketHelper::GetSocketManager())
if (!gLayerScopeManager.GetSocketManager())
return true;
uint32_t size = aPacket.ByteSize();
auto data = MakeUnique<uint8_t[]>(size);
aPacket.SerializeToArray(data.get(), size);
return WebSocketHelper::GetSocketManager()->WriteAll(data.get(), size);
return gLayerScopeManager.GetSocketManager()->WriteAll(data.get(), size);
}
Packet::DataType mDataType;
@@ -269,6 +374,95 @@ protected:
int64_t mFrameStamp;
};
#ifdef MOZ_WIDGET_GONK
// B2G optimization.
class DebugGLGraphicBuffer final: public DebugGLData {
public:
DebugGLGraphicBuffer(void *layerRef,
GLenum target,
GLuint name,
const LayerRenderState &aState)
: DebugGLData(Packet::TEXTURE),
mLayerRef(reinterpret_cast<uint64_t>(layerRef)),
mTarget(target),
mName(name),
mState(aState)
{
}
virtual bool Write() override {
return WriteToStream(mPacket);
}
bool TryPack(bool packData) {
android::sp<android::GraphicBuffer> buffer = mState.mSurface;
MOZ_ASSERT(buffer.get());
mPacket.set_type(mDataType);
TexturePacket* tp = mPacket.mutable_texture();
tp->set_layerref(mLayerRef);
tp->set_name(mName);
tp->set_target(mTarget);
int pFormat = buffer->getPixelFormat();
if (HAL_PIXEL_FORMAT_RGBA_8888 != pFormat &&
HAL_PIXEL_FORMAT_RGBX_8888 != pFormat) {
return false;
}
int32_t stride = buffer->getStride() * 4;
int32_t height = buffer->getHeight();
int32_t width = buffer->getWidth();
int32_t sourceSize = stride * height;
if (sourceSize <= 0) {
return false;
}
uint32_t dFormat = mState.FormatRBSwapped() ?
LOCAL_GL_BGRA : LOCAL_GL_RGBA;
tp->set_dataformat(dFormat);
tp->set_dataformat((1 << 16 | tp->dataformat()));
tp->set_width(width);
tp->set_height(height);
tp->set_stride(stride);
if (packData) {
uint8_t* grallocData = nullptr;
if (BAD_VALUE == buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN |
GRALLOC_USAGE_SW_WRITE_NEVER,
reinterpret_cast<void**>(&grallocData)))
{
return false;
}
// Do not return before buffer->unlock();
auto compressedData =
MakeUnique<char[]>(LZ4::maxCompressedSize(sourceSize));
int compressedSize = LZ4::compress((char*)grallocData,
sourceSize,
compressedData.get());
if (compressedSize > 0) {
tp->set_data(compressedData.get(), compressedSize);
} else {
buffer->unlock();
return false;
}
buffer->unlock();
}
return true;
}
private:
uint64_t mLayerRef;
GLenum mTarget;
GLuint mName;
const LayerRenderState &mState;
Packet mPacket;
};
#endif
class DebugGLTextureData final: public DebugGLData {
public:
DebugGLTextureData(GLContext* cx,
@@ -494,11 +688,12 @@ public:
NS_IMETHODIMP OnSocketAccepted(nsIServerSocket *aServ,
nsISocketTransport *aTransport) override
{
if (!WebSocketHelper::GetSocketManager())
if (!gLayerScopeManager.GetSocketManager())
return NS_OK;
printf_stderr("*** LayerScope: Accepted connection\n");
WebSocketHelper::GetSocketManager()->AddConnection(aTransport);
gLayerScopeManager.GetSocketManager()->AddConnection(aTransport);
gLayerScopeManager.GetContentMonitor()->Empty();
return NS_OK;
}
@@ -537,8 +732,6 @@ public:
delete d;
}
/* nsIRunnable impl; send the data */
NS_IMETHODIMP Run() override {
DebugGLData *d;
nsresult rv = NS_OK;
@@ -554,7 +747,7 @@ public:
Cleanup();
if (NS_FAILED(rv)) {
WebSocketHelper::DestroyServerSocket();
gLayerScopeManager.DestroyServerSocket();
}
return NS_OK;
@@ -567,15 +760,6 @@ protected:
NS_IMPL_ISUPPORTS(DebugDataSender, nsIRunnable);
class CreateServerSocketRunnable : public nsRunnable
{
public:
NS_IMETHOD Run() {
WebSocketHelper::CreateServerSocket();
return NS_OK;
}
};
/*
* LayerScope SendXXX Structure
* 1. SendLayer
@@ -605,6 +789,9 @@ public:
static bool GetLayersTreeSendable() {return sLayersTreeSendable;}
static void ClearTextureIdList();
// Sender private functions
private:
static void SendColor(void* aLayerRef,
@@ -614,27 +801,60 @@ private:
static void SendTextureSource(GLContext* aGLContext,
void* aLayerRef,
TextureSourceOGL* aSource,
GLuint aTexID,
bool aFlipY);
#ifdef MOZ_WIDGET_GONK
static bool SendGraphicBuffer(void* aLayerRef,
TextureSourceOGL* aSource,
GLuint aTexID,
const TexturedEffect* aEffect);
#endif
static void SendTexturedEffect(GLContext* aGLContext,
void* aLayerRef,
const TexturedEffect* aEffect);
static void SendYCbCrEffect(GLContext* aGLContext,
void* aLayerRef,
const EffectYCbCr* aEffect);
static GLuint GetTextureID(GLContext* aGLContext,
TextureSourceOGL* aSource);
static bool IsTextureIdContainsInList(GLuint aTextureId);
// Data fields
private:
static bool sLayersTreeSendable;
static bool sLayersBufferSendable;
static std::list<GLuint> sTextureIdList;
};
bool SenderHelper::sLayersTreeSendable = true;
bool SenderHelper::sLayersBufferSendable = true;
std::list<GLuint> SenderHelper::sTextureIdList;
// ----------------------------------------------
// SenderHelper implementation
// ----------------------------------------------
void
SenderHelper::ClearTextureIdList()
{
std::list<GLuint>::iterator it;
while (!sTextureIdList.empty()) {
it = sTextureIdList.begin();
sTextureIdList.erase(it);
}
}
bool
SenderHelper::IsTextureIdContainsInList(GLuint aTextureId)
{
for (std::list<GLuint>::iterator it = sTextureIdList.begin();
it != sTextureIdList.end(); ++it) {
if (*it == aTextureId) {
return true;
}
}
return false;
}
void
SenderHelper::SendLayer(LayerComposite* aLayer,
int aWidth,
@@ -681,14 +901,35 @@ SenderHelper::SendColor(void* aLayerRef,
int aWidth,
int aHeight)
{
WebSocketHelper::GetSocketManager()->AppendDebugData(
gLayerScopeManager.GetSocketManager()->AppendDebugData(
new DebugGLColorData(aLayerRef, aColor, aWidth, aHeight));
}
GLuint
SenderHelper::GetTextureID(GLContext* aGLContext,
TextureSourceOGL* aSource) {
GLenum textureTarget = aSource->GetTextureTarget();
aSource->BindTexture(LOCAL_GL_TEXTURE0, gfx::Filter::LINEAR);
GLuint texID = 0;
// This is horrid hack. It assumes that aGLContext matches the context
// aSource has bound to.
if (textureTarget == LOCAL_GL_TEXTURE_2D) {
aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &texID);
} else if (textureTarget == LOCAL_GL_TEXTURE_EXTERNAL) {
aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL, &texID);
} else if (textureTarget == LOCAL_GL_TEXTURE_RECTANGLE) {
aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_RECTANGLE, &texID);
}
return texID;
}
void
SenderHelper::SendTextureSource(GLContext* aGLContext,
void* aLayerRef,
TextureSourceOGL* aSource,
GLuint aTexID,
bool aFlipY)
{
MOZ_ASSERT(aGLContext);
@@ -701,44 +942,75 @@ SenderHelper::SendTextureSource(GLContext* aGLContext,
aSource->GetFormat());
int shaderConfig = config.mFeatures;
aSource->BindTexture(LOCAL_GL_TEXTURE0, gfx::Filter::LINEAR);
GLuint textureId = 0;
// This is horrid hack. It assumes that aGLContext matches the context
// aSource has bound to.
if (textureTarget == LOCAL_GL_TEXTURE_2D) {
aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &textureId);
} else if (textureTarget == LOCAL_GL_TEXTURE_EXTERNAL) {
aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL, &textureId);
} else if (textureTarget == LOCAL_GL_TEXTURE_RECTANGLE) {
aGLContext->GetUIntegerv(LOCAL_GL_TEXTURE_BINDING_RECTANGLE, &textureId);
}
gfx::IntSize size = aSource->GetSize();
// By sending 0 to ReadTextureImage rely upon aSource->BindTexture binding
// texture correctly. textureId is used for tracking in DebugGLTextureData.
// texture correctly. texID is used for tracking in DebugGLTextureData.
RefPtr<DataSourceSurface> img =
aGLContext->ReadTexImageHelper()->ReadTexImage(0, textureTarget,
size,
shaderConfig, aFlipY);
WebSocketHelper::GetSocketManager()->AppendDebugData(
size,
shaderConfig, aFlipY);
gLayerScopeManager.GetSocketManager()->AppendDebugData(
new DebugGLTextureData(aGLContext, aLayerRef, textureTarget,
textureId, img));
aTexID, img));
sTextureIdList.push_back(aTexID);
}
#ifdef MOZ_WIDGET_GONK
bool
SenderHelper::SendGraphicBuffer(void* aLayerRef,
TextureSourceOGL* aSource,
GLuint aTexID,
const TexturedEffect* aEffect) {
if (!aEffect->mState.mSurface.get()) {
return false;
}
GLenum target = aSource->GetTextureTarget();
mozilla::UniquePtr<DebugGLGraphicBuffer> package =
MakeUnique<DebugGLGraphicBuffer>(aLayerRef, target, aTexID, aEffect->mState);
// The texure content in this TexureHost is not altered,
// we don't need to send it again.
bool changed = gLayerScopeManager.GetContentMonitor()->IsChangedOrNew(
aEffect->mState.mTexture);
if (!package->TryPack(changed)) {
return false;
}
// Transfer ownership to SocketManager.
gLayerScopeManager.GetSocketManager()->AppendDebugData(package.release());
sTextureIdList.push_back(aTexID);
gLayerScopeManager.GetContentMonitor()->ClearChangedHost(aEffect->mState.mTexture);
return true;
}
#endif
void
SenderHelper::SendTexturedEffect(GLContext* aGLContext,
void* aLayerRef,
const TexturedEffect* aEffect)
{
TextureSourceOGL* source = aEffect->mTexture->AsSourceOGL();
if (!source)
if (!source) {
return;
}
bool flipY = false;
SendTextureSource(aGLContext, aLayerRef, source, flipY);
GLuint texID = GetTextureID(aGLContext, source);
if (IsTextureIdContainsInList(texID)) {
return;
}
#ifdef MOZ_WIDGET_GONK
if (SendGraphicBuffer(aLayerRef, source, texID, aEffect)) {
return;
}
#endif
// Fallback texture sending path.
// Render to texture and read pixels back.
SendTextureSource(aGLContext, aLayerRef, source, texID, false);
}
void
@@ -755,10 +1027,20 @@ SenderHelper::SendYCbCrEffect(GLContext* aGLContext,
TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL();
TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL();
bool flipY = false;
SendTextureSource(aGLContext, aLayerRef, sourceY, flipY);
SendTextureSource(aGLContext, aLayerRef, sourceCb, flipY);
SendTextureSource(aGLContext, aLayerRef, sourceCr, flipY);
GLuint texID = GetTextureID(aGLContext, sourceY);
if (!IsTextureIdContainsInList(texID)) {
SendTextureSource(aGLContext, aLayerRef, sourceY, texID, false);
}
texID = GetTextureID(aGLContext, sourceCb);
if (!IsTextureIdContainsInList(texID)) {
SendTextureSource(aGLContext, aLayerRef, sourceCb, texID, false);
}
texID = GetTextureID(aGLContext, sourceCr);
if (!IsTextureIdContainsInList(texID)) {
SendTextureSource(aGLContext, aLayerRef, sourceCr, texID, false);
}
}
void
@@ -803,6 +1085,16 @@ SenderHelper::SendEffectChain(GLContext* aGLContext,
// TODO:
}
void
LayerScope::ContentChanged(TextureHost *host)
{
if (!CheckSendable()) {
return;
}
gLayerScopeManager.GetContentMonitor()->SetChangedHost(host);
}
// ----------------------------------------------
// LayerScopeWebSocketHandler implementation
// ----------------------------------------------
@@ -1210,7 +1502,7 @@ LayerScopeWebSocketHandler::HandleDataFrame(uint8_t *aData,
void
LayerScopeWebSocketHandler::CloseConnection()
{
WebSocketHelper::GetSocketManager()->CleanDebugData();
gLayerScopeManager.GetSocketManager()->CleanDebugData();
if (mInputStream) {
mInputStream->AsyncWait(nullptr, 0, 0, nullptr);
mInputStream = nullptr;
@@ -1280,56 +1572,9 @@ LayerScope::Init()
return;
}
if (NS_IsMainThread()) {
WebSocketHelper::CreateServerSocket();
} else {
// Dispatch creation to main thread, and make sure we
// dispatch this only once after booting
static bool dispatched = false;
if (dispatched) {
return;
}
DebugOnly<nsresult> rv = NS_DispatchToMainThread(new CreateServerSocketRunnable());
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to dispatch WebSocket Creation to main thread");
dispatched = true;
}
gLayerScopeManager.CreateServerSocket();
}
class DrawSession {
public:
NS_INLINE_DECL_REFCOUNTING(DrawSession)
DrawSession()
: mOffsetX(0.0),
mOffsetY(0.0),
mRects(0)
{ }
float mOffsetX;
float mOffsetY;
gfx::Matrix4x4 mMVMatrix;
size_t mRects;
gfx::Rect mLayerRects[4];
private:
~DrawSession() {}
};
class DrawSessionHolder {
public:
static void setSession(DrawSession *aSession) {
mSession = aSession;
}
static DrawSession& current() {
return *mSession;
}
private:
static nsRefPtr<DrawSession> mSession;
};
nsRefPtr<DrawSession> DrawSessionHolder::mSession;
void
LayerScope::DrawBegin()
{
@@ -1337,7 +1582,7 @@ LayerScope::DrawBegin()
return;
}
DrawSessionHolder::setSession(new DrawSession());
gLayerScopeManager.NewDrawSession();
}
void LayerScope::SetRenderOffset(float aX, float aY)
@@ -1346,8 +1591,8 @@ void LayerScope::SetRenderOffset(float aX, float aY)
return;
}
DrawSessionHolder::current().mOffsetX = aX;
DrawSessionHolder::current().mOffsetY = aY;
gLayerScopeManager.CurrentSession().mOffsetX = aX;
gLayerScopeManager.CurrentSession().mOffsetY = aY;
}
void LayerScope::SetLayerTransform(const gfx::Matrix4x4& aMatrix)
@@ -1356,7 +1601,7 @@ void LayerScope::SetLayerTransform(const gfx::Matrix4x4& aMatrix)
return;
}
DrawSessionHolder::current().mMVMatrix = aMatrix;
gLayerScopeManager.CurrentSession().mMVMatrix = aMatrix;
}
void LayerScope::SetLayerRects(size_t aRects, const gfx::Rect* aLayerRects)
@@ -1368,10 +1613,10 @@ void LayerScope::SetLayerRects(size_t aRects, const gfx::Rect* aLayerRects)
MOZ_ASSERT(aRects > 0 && aRects <= 4);
MOZ_ASSERT(aLayerRects);
DrawSessionHolder::current().mRects = aRects;
gLayerScopeManager.CurrentSession().mRects = aRects;
for (size_t i = 0; i < aRects; i++){
DrawSessionHolder::current().mLayerRects[i] = aLayerRects[i];
gLayerScopeManager.CurrentSession().mLayerRects[i] = aLayerRects[i];
}
}
@@ -1388,8 +1633,8 @@ LayerScope::DrawEnd(gl::GLContext* aGLContext,
// 1. Send parameters of draw call, such as uniforms and attributes of
// vertex adnd fragment shader.
DrawSession& draws = DrawSessionHolder::current();
WebSocketHelper::GetSocketManager()->AppendDebugData(
DrawSession& draws = gLayerScopeManager.CurrentSession();
gLayerScopeManager.GetSocketManager()->AppendDebugData(
new DebugGLDrawData(draws.mOffsetX, draws.mOffsetY,
draws.mMVMatrix, draws.mRects,
draws.mLayerRects,
@@ -1418,7 +1663,7 @@ LayerScope::SendLayerDump(UniquePtr<Packet> aPacket)
if (!CheckSendable() || !SenderHelper::GetLayersTreeSendable()) {
return;
}
WebSocketHelper::GetSocketManager()->AppendDebugData(
gLayerScopeManager.GetSocketManager()->AppendDebugData(
new DebugGLLayersData(Move(aPacket)));
}
@@ -1431,11 +1676,11 @@ LayerScope::CheckSendable()
if (!gfxPrefs::LayerScopeEnabled()) {
return false;
}
if (!WebSocketHelper::GetSocketManager()) {
if (!gLayerScopeManager.GetSocketManager()) {
Init();
return false;
}
if (!WebSocketHelper::GetSocketManager()->IsConnected()) {
if (!gLayerScopeManager.GetSocketManager()->IsConnected()) {
return false;
}
return true;
@@ -1445,7 +1690,7 @@ void
LayerScope::CleanLayer()
{
if (CheckSendable()) {
WebSocketHelper::GetSocketManager()->CleanDebugData();
gLayerScopeManager.GetSocketManager()->CleanDebugData();
}
}
@@ -1453,7 +1698,7 @@ void
LayerScope::SetHWComposed()
{
if (CheckSendable()) {
WebSocketHelper::GetSocketManager()->AppendDebugData(
gLayerScopeManager.GetSocketManager()->AppendDebugData(
new DebugGLMetaData(Packet::META, true));
}
}
@@ -1476,11 +1721,13 @@ LayerScopeAutoFrame::~LayerScopeAutoFrame()
void
LayerScopeAutoFrame::BeginFrame(int64_t aFrameStamp)
{
SenderHelper::ClearTextureIdList();
if (!LayerScope::CheckSendable()) {
return;
}
WebSocketHelper::GetSocketManager()->AppendDebugData(
gLayerScopeManager.GetSocketManager()->AppendDebugData(
new DebugGLFrameStatusData(Packet::FRAMESTART, aFrameStamp));
}
@@ -1491,9 +1738,9 @@ LayerScopeAutoFrame::EndFrame()
return;
}
WebSocketHelper::GetSocketManager()->AppendDebugData(
gLayerScopeManager.GetSocketManager()->AppendDebugData(
new DebugGLFrameStatusData(Packet::FRAMEEND));
WebSocketHelper::GetSocketManager()->DispatchDebugData();
gLayerScopeManager.GetSocketManager()->DispatchDebugData();
}
} // namespace layers
+1
View File
@@ -40,6 +40,7 @@ public:
static void CleanLayer();
static void SetHWComposed();
static void ContentChanged(TextureHost *host);
private:
static void Init();
};
+27 -19
View File
@@ -267,6 +267,12 @@ Layer::ClearAnimationsForNextTransaction()
mPendingAnimations->Clear();
}
static inline void
SetCSSAngle(const CSSAngle& aAngle, nsCSSValue& aValue)
{
aValue.SetFloatValue(aAngle.value(), nsCSSUnit(aAngle.unit()));
}
static nsCSSValueSharedList*
CreateCSSValueList(const InfallibleTArray<TransformFunction>& aFunctions)
{
@@ -277,34 +283,34 @@ CreateCSSValueList(const InfallibleTArray<TransformFunction>& aFunctions)
switch (aFunctions[i].type()) {
case TransformFunction::TRotationX:
{
float theta = aFunctions[i].get_RotationX().radians();
const CSSAngle& angle = aFunctions[i].get_RotationX().angle();
arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_rotatex,
resultTail);
arr->Item(1).SetFloatValue(theta, eCSSUnit_Radian);
SetCSSAngle(angle, arr->Item(1));
break;
}
case TransformFunction::TRotationY:
{
float theta = aFunctions[i].get_RotationY().radians();
const CSSAngle& angle = aFunctions[i].get_RotationY().angle();
arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_rotatey,
resultTail);
arr->Item(1).SetFloatValue(theta, eCSSUnit_Radian);
SetCSSAngle(angle, arr->Item(1));
break;
}
case TransformFunction::TRotationZ:
{
float theta = aFunctions[i].get_RotationZ().radians();
const CSSAngle& angle = aFunctions[i].get_RotationZ().angle();
arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_rotatez,
resultTail);
arr->Item(1).SetFloatValue(theta, eCSSUnit_Radian);
SetCSSAngle(angle, arr->Item(1));
break;
}
case TransformFunction::TRotation:
{
float theta = aFunctions[i].get_Rotation().radians();
const CSSAngle& angle = aFunctions[i].get_Rotation().angle();
arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_rotate,
resultTail);
arr->Item(1).SetFloatValue(theta, eCSSUnit_Radian);
SetCSSAngle(angle, arr->Item(1));
break;
}
case TransformFunction::TRotation3D:
@@ -312,14 +318,14 @@ CreateCSSValueList(const InfallibleTArray<TransformFunction>& aFunctions)
float x = aFunctions[i].get_Rotation3D().x();
float y = aFunctions[i].get_Rotation3D().y();
float z = aFunctions[i].get_Rotation3D().z();
float theta = aFunctions[i].get_Rotation3D().radians();
const CSSAngle& angle = aFunctions[i].get_Rotation3D().angle();
arr =
StyleAnimationValue::AppendTransformFunction(eCSSKeyword_rotate3d,
resultTail);
arr->Item(1).SetFloatValue(x, eCSSUnit_Number);
arr->Item(2).SetFloatValue(y, eCSSUnit_Number);
arr->Item(3).SetFloatValue(z, eCSSUnit_Number);
arr->Item(4).SetFloatValue(theta, eCSSUnit_Radian);
SetCSSAngle(angle, arr->Item(4));
break;
}
case TransformFunction::TScale:
@@ -344,26 +350,28 @@ CreateCSSValueList(const InfallibleTArray<TransformFunction>& aFunctions)
}
case TransformFunction::TSkewX:
{
float x = aFunctions[i].get_SkewX().x();
const CSSAngle& x = aFunctions[i].get_SkewX().x();
arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_skewx,
resultTail);
arr->Item(1).SetFloatValue(x, eCSSUnit_Radian);
SetCSSAngle(x, arr->Item(1));
break;
}
case TransformFunction::TSkewY:
{
float y = aFunctions[i].get_SkewY().y();
const CSSAngle& y = aFunctions[i].get_SkewY().y();
arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_skewy,
resultTail);
arr->Item(1).SetFloatValue(y, eCSSUnit_Radian);
SetCSSAngle(y, arr->Item(1));
break;
}
case TransformFunction::TSkew:
{
const CSSAngle& x = aFunctions[i].get_Skew().x();
const CSSAngle& y = aFunctions[i].get_Skew().y();
arr = StyleAnimationValue::AppendTransformFunction(eCSSKeyword_skew,
resultTail);
arr->Item(1).SetFloatValue(aFunctions[i].get_Skew().x(), eCSSUnit_Radian);
arr->Item(2).SetFloatValue(aFunctions[i].get_Skew().y(), eCSSUnit_Radian);
SetCSSAngle(x, arr->Item(1));
SetCSSAngle(y, arr->Item(2));
break;
}
case TransformFunction::TTransformMatrix:
@@ -1154,7 +1162,7 @@ ContainerLayer::DefaultComputeEffectiveTransforms(const Matrix4x4& aTransformToS
GetForceIsolatedGroup()) {
useIntermediateSurface = true;
#ifdef MOZ_DUMP_PAINTING
} else if (gfxUtils::sDumpPainting) {
} else if (gfxUtils::sDumpPaintingIntermediate) {
useIntermediateSurface = true;
#endif
} else {
@@ -1423,11 +1431,11 @@ void WriteSnapshotToDumpFile_internal(T* aObj, DataSourceSurface* aSurf)
nsCString string(aObj->Name());
string.Append('-');
string.AppendInt((uint64_t)aObj);
if (gfxUtils::sDumpPaintFile) {
if (gfxUtils::sDumpPaintFile != stderr) {
fprintf_stderr(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading());
}
gfxUtils::DumpAsDataURI(aSurf, gfxUtils::sDumpPaintFile);
if (gfxUtils::sDumpPaintFile) {
if (gfxUtils::sDumpPaintFile != stderr) {
fprintf_stderr(gfxUtils::sDumpPaintFile, "\";");
}
}
+249 -83
View File
@@ -5,6 +5,8 @@
#include "TextureDIB.h"
#include "gfx2DGlue.h"
#include "mozilla/layers/ISurfaceAllocator.h"
#include "mozilla/ipc/ProtocolUtils.h"
namespace mozilla {
@@ -12,37 +14,8 @@ using namespace gfx;
namespace layers {
DIBTextureClient::DIBTextureClient(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat,
TextureFlags aFlags)
: TextureClient(aAllocator, aFlags)
, mFormat(aFormat)
, mIsLocked(false)
{
MOZ_COUNT_CTOR(DIBTextureClient);
}
DIBTextureClient::~DIBTextureClient()
{
MOZ_COUNT_DTOR(DIBTextureClient);
}
already_AddRefed<TextureClient>
DIBTextureClient::CreateSimilar(TextureFlags aFlags,
TextureAllocationFlags aAllocFlags) const
{
RefPtr<TextureClient> tex = new DIBTextureClient(mAllocator, mFormat,
mFlags | aFlags);
if (!tex->AllocateForSurface(mSize, aAllocFlags)) {
return nullptr;
}
return tex.forget();
}
bool
DIBTextureClient::Lock(OpenMode)
TextureClientDIB::Lock(OpenMode)
{
MOZ_ASSERT(!mIsLocked);
if (!IsValid()) {
@@ -53,7 +26,7 @@ DIBTextureClient::Lock(OpenMode)
}
void
DIBTextureClient::Unlock()
TextureClientDIB::Unlock()
{
MOZ_ASSERT(mIsLocked, "Unlocked called while the texture is not locked!");
if (mDrawTarget) {
@@ -70,23 +43,8 @@ DIBTextureClient::Unlock()
mIsLocked = false;
}
bool
DIBTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
{
MOZ_ASSERT(IsValid());
if (!IsAllocated()) {
return false;
}
MOZ_ASSERT(mSurface);
// The host will release this ref when it receives the surface descriptor.
// We AddRef in case we die before the host receives the pointer.
aOutDescriptor = SurfaceDescriptorDIB(reinterpret_cast<uintptr_t>(mSurface.get()));
mSurface->AddRef();
return true;
}
gfx::DrawTarget*
DIBTextureClient::BorrowDrawTarget()
TextureClientDIB::BorrowDrawTarget()
{
MOZ_ASSERT(mIsLocked && IsAllocated());
@@ -98,8 +56,51 @@ DIBTextureClient::BorrowDrawTarget()
return mDrawTarget;
}
TextureClientMemoryDIB::TextureClientMemoryDIB(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat,
TextureFlags aFlags)
: TextureClientDIB(aAllocator, aFormat, aFlags)
{
MOZ_COUNT_CTOR(TextureClientMemoryDIB);
}
TextureClientMemoryDIB::~TextureClientMemoryDIB()
{
MOZ_COUNT_DTOR(TextureClientMemoryDIB);
}
already_AddRefed<TextureClient>
TextureClientMemoryDIB::CreateSimilar(TextureFlags aFlags,
TextureAllocationFlags aAllocFlags) const
{
RefPtr<TextureClient> tex = new TextureClientMemoryDIB(mAllocator, mFormat,
mFlags | aFlags);
if (!tex->AllocateForSurface(mSize, aAllocFlags)) {
return nullptr;
}
return tex.forget();
}
bool
DIBTextureClient::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags)
TextureClientMemoryDIB::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
{
MOZ_ASSERT(IsValid());
if (!IsAllocated()) {
return false;
}
MOZ_ASSERT(mSurface);
// The host will release this ref when it receives the surface descriptor.
// We AddRef in case we die before the host receives the pointer.
aOutDescriptor = SurfaceDescriptorDIB(reinterpret_cast<uintptr_t>(mSurface.get()));
mSurface->AddRef();
return true;
}
bool
TextureClientMemoryDIB::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags)
{
MOZ_ASSERT(!IsAllocated());
mSize = aSize;
@@ -116,10 +117,175 @@ DIBTextureClient::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags
return true;
}
TextureClientShmemDIB::TextureClientShmemDIB(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat,
TextureFlags aFlags)
: TextureClientDIB(aAllocator, aFormat, aFlags)
, mFileMapping(NULL)
, mHostHandle(NULL)
, mDC(NULL)
, mBitmap(NULL)
{
MOZ_COUNT_CTOR(TextureClientShmemDIB);
}
TextureClientShmemDIB::~TextureClientShmemDIB()
{
MOZ_COUNT_DTOR(TextureClientShmemDIB);
::DeleteObject(mBitmap);
::DeleteDC(mDC);
::CloseHandle(mFileMapping);
}
already_AddRefed<TextureClient>
TextureClientShmemDIB::CreateSimilar(TextureFlags aFlags,
TextureAllocationFlags aAllocFlags) const
{
RefPtr<TextureClient> tex = new TextureClientShmemDIB(mAllocator, mFormat,
mFlags | aFlags);
if (!tex->AllocateForSurface(mSize, aAllocFlags)) {
return nullptr;
}
return tex.forget();
}
bool
TextureClientShmemDIB::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
{
MOZ_ASSERT(IsValid());
MOZ_ASSERT(mAllocator->ParentPid() != base::ProcessId());
if (!IsAllocated() || GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
return false;
}
::GdiFlush();
aOutDescriptor = SurfaceDescriptorFileMapping((WindowsHandle)mHostHandle, mFormat, mSize);
return true;
}
bool
TextureClientShmemDIB::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags)
{
MOZ_ASSERT(!IsAllocated());
MOZ_ASSERT(mAllocator->ParentPid() != base::ProcessId());
mSize = aSize;
DWORD mapSize = mSize.width * mSize.height * BytesPerPixel(mFormat);
mFileMapping = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, mapSize, NULL);
if (!mFileMapping) {
gfxCriticalError() << "Failed to create memory file mapping for " << mapSize << " bytes.";
return false;
}
uint8_t* data = (uint8_t*)::MapViewOfFile(mFileMapping, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, mSize.width * mSize.height * BytesPerPixel(mFormat));
memset(data, 0x80, mSize.width * mSize.height * BytesPerPixel(mFormat));
::UnmapViewOfFile(mFileMapping);
BITMAPV4HEADER header;
memset(&header, 0, sizeof(BITMAPV4HEADER));
header.bV4Size = sizeof(BITMAPV4HEADER);
header.bV4Width = mSize.width;
header.bV4Height = -LONG(mSize.height); // top-to-buttom DIB
header.bV4Planes = 1;
header.bV4BitCount = 32;
header.bV4V4Compression = BI_BITFIELDS;
header.bV4RedMask = 0x00FF0000;
header.bV4GreenMask = 0x0000FF00;
header.bV4BlueMask = 0x000000FF;
mDC = ::CreateCompatibleDC(::GetDC(NULL));
if (!mDC) {
::CloseHandle(mFileMapping);
gfxCriticalError() << "Failed to create DC for bitmap.";
return false;
}
void* bits;
mBitmap = ::CreateDIBSection(mDC, (BITMAPINFO*)&header, DIB_RGB_COLORS, &bits, mFileMapping, 0);
if (!mBitmap) {
gfxCriticalError() << "Failed to create DIB section for a bitmap of size " << mSize;
::CloseHandle(mFileMapping);
::DeleteDC(mDC);
return false;
}
::SelectObject(mDC, mBitmap);
mSurface = new gfxWindowsSurface(mDC, 0);
if (mSurface->CairoStatus())
{
::DeleteObject(mBitmap);
::DeleteDC(mDC);
::CloseHandle(mFileMapping);
gfxCriticalError() << "Could not create surface, status: " << mSurface->CairoStatus();
mSurface = nullptr;
return false;
}
if (!ipc::DuplicateHandle(mFileMapping, mAllocator->ParentPid(), &mHostHandle, 0, DUPLICATE_SAME_ACCESS)) {
gfxCriticalError() << "Failed to duplicate handle to parent process for surface.";
::DeleteObject(mBitmap);
::DeleteDC(mDC);
::CloseHandle(mFileMapping);
return false;
}
return true;
}
bool
TextureHostDirectUpload::Lock()
{
MOZ_ASSERT(!mIsLocked);
mIsLocked = true;
return true;
}
void
TextureHostDirectUpload::Unlock()
{
MOZ_ASSERT(mIsLocked);
mIsLocked = false;
}
void
TextureHostDirectUpload::SetCompositor(Compositor* aCompositor)
{
mCompositor = aCompositor;
}
void
TextureHostDirectUpload::DeallocateDeviceData()
{
if (mTextureSource) {
mTextureSource->DeallocateDeviceData();
}
}
bool
TextureHostDirectUpload::BindTextureSource(CompositableTextureSourceRef& aTexture)
{
if (!mTextureSource) {
Updated();
}
aTexture = mTextureSource;
return !!aTexture;
}
DIBTextureHost::DIBTextureHost(TextureFlags aFlags,
const SurfaceDescriptorDIB& aDescriptor)
: TextureHost(aFlags)
, mIsLocked(false)
: TextureHostDirectUpload(aFlags, SurfaceFormat::B8G8R8X8, IntSize())
{
// We added an extra ref for transport, so we shouldn't AddRef now.
mSurface =
@@ -131,19 +297,8 @@ DIBTextureHost::DIBTextureHost(TextureFlags aFlags,
gfxPlatform::GetPlatform()->OptimalFormatForContent(mSurface->GetContentType()));
}
bool
DIBTextureHost::BindTextureSource(CompositableTextureSourceRef& aTexture)
{
if (!mTextureSource) {
Updated();
}
aTexture = mTextureSource;
return !!aTexture;
}
void
DIBTextureHost::Updated(const nsIntRegion* aRegion)
DIBTextureHost::UpdatedInternal(const nsIntRegion* aRegion)
{
if (!mCompositor) {
// This can happen if we send textures to a compositable that isn't yet
@@ -164,33 +319,44 @@ DIBTextureHost::Updated(const nsIntRegion* aRegion)
}
}
bool
DIBTextureHost::Lock()
TextureHostFileMapping::TextureHostFileMapping(TextureFlags aFlags,
const SurfaceDescriptorFileMapping& aDescriptor)
: TextureHostDirectUpload(aFlags, aDescriptor.format(), aDescriptor.size())
, mFileMapping((HANDLE)aDescriptor.handle())
{
MOZ_ASSERT(!mIsLocked);
mIsLocked = true;
return true;
}
TextureHostFileMapping::~TextureHostFileMapping()
{
::CloseHandle(mFileMapping);
}
void
DIBTextureHost::Unlock()
TextureHostFileMapping::UpdatedInternal(const nsIntRegion* aRegion)
{
MOZ_ASSERT(mIsLocked);
mIsLocked = false;
}
void
DIBTextureHost::SetCompositor(Compositor* aCompositor)
{
mCompositor = aCompositor;
}
void
DIBTextureHost::DeallocateDeviceData()
{
if (mTextureSource) {
mTextureSource->DeallocateDeviceData();
if (!mCompositor) {
// This can happen if we send textures to a compositable that isn't yet
// attached to a layer.
return;
}
if (!mTextureSource) {
mTextureSource = mCompositor->CreateDataTextureSource(mFlags);
}
uint8_t* data = (uint8_t*)::MapViewOfFile(mFileMapping, FILE_MAP_READ, 0, 0, mSize.width * mSize.height * BytesPerPixel(mFormat));
if (data) {
RefPtr<DataSourceSurface> surf = Factory::CreateWrappingDataSourceSurface(data, mSize.width * BytesPerPixel(mFormat), mSize, mFormat);
if (!mTextureSource->Update(surf, const_cast<nsIntRegion*>(aRegion))) {
mTextureSource = nullptr;
}
} else {
mTextureSource = nullptr;
}
::UnmapViewOfFile(data);
}
}
+118 -34
View File
@@ -15,22 +15,9 @@
namespace mozilla {
namespace layers {
/**
* Can only be drawn into through Cairo.
* Prefer CairoTextureClient when possible.
* The coresponding TextureHost depends on the compositor
*/
class DIBTextureClient : public TextureClient
class TextureClientDIB : public TextureClient
{
public:
DIBTextureClient(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat,
TextureFlags aFlags);
virtual ~DIBTextureClient();
// TextureClient
virtual bool IsAllocated() const override { return !!mSurface; }
virtual bool Lock(OpenMode aOpenMode) override;
@@ -39,8 +26,6 @@ public:
virtual bool IsLocked() const override{ return mIsLocked; }
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) override;
virtual gfx::IntSize GetSize() const override { return mSize; }
virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
@@ -49,16 +34,15 @@ public:
virtual gfx::DrawTarget* BorrowDrawTarget() override;
virtual bool AllocateForSurface(gfx::IntSize aSize,
TextureAllocationFlags aFlags = ALLOC_DEFAULT) override;
virtual bool HasInternalBuffer() const override { return true; }
virtual already_AddRefed<TextureClient>
CreateSimilar(TextureFlags aFlags = TextureFlags::DEFAULT,
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
protected:
TextureClientDIB(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat, TextureFlags aFlags)
: TextureClient(aAllocator, aFlags)
, mFormat(aFormat)
, mIsLocked(false)
{ }
nsRefPtr<gfxWindowsSurface> mSurface;
RefPtr<gfx::DrawTarget> mDrawTarget;
gfx::IntSize mSize;
@@ -66,13 +50,82 @@ protected:
bool mIsLocked;
};
class DIBTextureHost : public TextureHost
/**
* Can only be drawn into through Cairo.
* Prefer CairoTextureClient when possible.
* The coresponding TextureHost depends on the compositor
*/
class TextureClientMemoryDIB : public TextureClientDIB
{
public:
DIBTextureHost(TextureFlags aFlags,
const SurfaceDescriptorDIB& aDescriptor);
TextureClientMemoryDIB(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat,
TextureFlags aFlags);
virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override;
virtual ~TextureClientMemoryDIB();
// TextureClient
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) override;
virtual bool AllocateForSurface(gfx::IntSize aSize,
TextureAllocationFlags aFlags = ALLOC_DEFAULT) override;
virtual already_AddRefed<TextureClient>
CreateSimilar(TextureFlags aFlags = TextureFlags::DEFAULT,
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
};
/**
* Can only be drawn into through Cairo.
* Prefer CairoTextureClient when possible.
* The coresponding TextureHost depends on the compositor
*/
class TextureClientShmemDIB : public TextureClientDIB
{
public:
TextureClientShmemDIB(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat,
TextureFlags aFlags);
virtual ~TextureClientShmemDIB();
// TextureClient
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) override;
virtual bool AllocateForSurface(gfx::IntSize aSize,
TextureAllocationFlags aFlags = ALLOC_DEFAULT) override;
virtual already_AddRefed<TextureClient>
CreateSimilar(TextureFlags aFlags = TextureFlags::DEFAULT,
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
protected:
HANDLE mFileMapping;
HANDLE mHostHandle;
HDC mDC;
HBITMAP mBitmap;
};
/**
* This is meant for a texture host which does a direct upload from
* Updated to a Compositor specific DataTextureSource and therefor doesn't
* need any specific Lock/Unlock magic.
*/
class TextureHostDirectUpload : public TextureHost
{
public:
TextureHostDirectUpload(TextureFlags aFlags,
gfx::SurfaceFormat aFormat,
gfx::IntSize aSize)
: TextureHost(aFlags)
, mFormat(aFormat)
, mSize(aSize)
, mIsLocked(false)
{ }
virtual void DeallocateDeviceData() override;
@@ -86,15 +139,9 @@ public:
virtual void Unlock() override;
virtual void Updated(const nsIntRegion* aRegion = nullptr) override;
virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override
{
return nullptr; // TODO: cf bug 872568
}
virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override;
protected:
nsRefPtr<gfxWindowsSurface> mSurface;
RefPtr<DataTextureSource> mTextureSource;
RefPtr<Compositor> mCompositor;
gfx::SurfaceFormat mFormat;
@@ -102,6 +149,43 @@ protected:
bool mIsLocked;
};
class DIBTextureHost : public TextureHostDirectUpload
{
public:
DIBTextureHost(TextureFlags aFlags,
const SurfaceDescriptorDIB& aDescriptor);
virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override
{
return nullptr; // TODO: cf bug 872568
}
protected:
virtual void UpdatedInternal(const nsIntRegion* aRegion = nullptr) override;
nsRefPtr<gfxWindowsSurface> mSurface;
};
class TextureHostFileMapping : public TextureHostDirectUpload
{
public:
TextureHostFileMapping(TextureFlags aFlags,
const SurfaceDescriptorFileMapping& aDescriptor);
~TextureHostFileMapping();
virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override
{
MOZ_CRASH(); // Not implemented! It would be tricky to keep track of the
// scope of the file mapping. We could do this through UserData
// on the DataSourceSurface but we don't need this right now.
}
protected:
virtual void UpdatedInternal(const nsIntRegion* aRegion = nullptr) override;
HANDLE mFileMapping;
};
}
}
-8
View File
@@ -237,14 +237,6 @@ public:
virtual const nsIntRegion& GetValidLowPrecisionRegion() const = 0;
virtual const nsIntRegion& GetValidRegion() const = 0;
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
/**
* Store a fence that will signal when the current buffer is no longer being read.
* Similar to android's GLConsumer::setReleaseFence()
*/
virtual void SetReleaseFence(const android::sp<android::Fence>& aReleaseFence) = 0;
#endif
};
// Normal integer division truncates towards zero,
-2
View File
@@ -112,7 +112,6 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
}
if (updated) {
GetForwarder()->UpdatedTexture(this, mBuffer, nullptr);
GetForwarder()->UseTexture(this, mBuffer);
mBuffer->SyncWithObject(GetForwarder()->GetSyncObject());
}
@@ -404,7 +403,6 @@ CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
// Use the new TexClient.
mFrontTex = newTex;
forwarder->UpdatedTexture(this, mFrontTex, nullptr);
forwarder->UseTexture(this, mFrontTex);
}
-1
View File
@@ -245,7 +245,6 @@ ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlag
}
mFrontBuffer = texture;
GetForwarder()->UpdatedTexture(this, texture, nullptr);
GetForwarder()->UseTexture(this, texture);
UpdatePictureRect(image->GetPictureRect());
+5 -2
View File
@@ -368,9 +368,12 @@ TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator,
if (!texture && aFormat == SurfaceFormat::B8G8R8X8 &&
aAllocator->IsSameProcess() &&
aMoz2DBackend == gfx::BackendType::CAIRO) {
texture = new DIBTextureClient(aAllocator, aFormat, aTextureFlags);
if (aAllocator->IsSameProcess()) {
texture = new TextureClientMemoryDIB(aAllocator, aFormat, aTextureFlags);
} else {
texture = new TextureClientShmemDIB(aAllocator, aFormat, aTextureFlags);
}
}
#endif
#ifdef MOZ_X11
+6 -4
View File
@@ -428,17 +428,19 @@ public:
*/
void ForceRemove(bool sync = false);
virtual void SetReleaseFenceHandle(FenceHandle aReleaseFenceHandle)
virtual void SetReleaseFenceHandle(const FenceHandle& aReleaseFenceHandle)
{
mReleaseFenceHandle.Merge(aReleaseFenceHandle);
}
const FenceHandle& GetReleaseFenceHandle() const
FenceHandle GetAndResetReleaseFenceHandle()
{
return mReleaseFenceHandle;
FenceHandle fence;
mReleaseFenceHandle.TransferToAnotherFenceHandle(fence);
return fence;
}
virtual void SetAcquireFenceHandle(FenceHandle aAcquireFenceHandle)
virtual void SetAcquireFenceHandle(const FenceHandle& aAcquireFenceHandle)
{
mAcquireFenceHandle = aAcquireFenceHandle;
}
@@ -400,16 +400,9 @@ SampleValue(float aPortion, Animation& aAnimation, StyleAnimationValue& aStart,
TransformData& data = aAnimation.data().get_TransformData();
nsPoint origin = data.origin();
// we expect all our transform data to arrive in css pixels, so here we must
// adjust to dev pixels.
double cssPerDev = double(nsDeviceContext::AppUnitsPerCSSPixel())
/ double(data.appUnitsPerDevPixel());
// we expect all our transform data to arrive in device pixels
Point3D transformOrigin = data.transformOrigin();
transformOrigin.x = transformOrigin.x * cssPerDev;
transformOrigin.y = transformOrigin.y * cssPerDev;
Point3D perspectiveOrigin = data.perspectiveOrigin();
perspectiveOrigin.x = perspectiveOrigin.x * cssPerDev;
perspectiveOrigin.y = perspectiveOrigin.y * cssPerDev;
nsDisplayTransform::FrameTransformProperties props(interpolatedList,
transformOrigin,
perspectiveOrigin,
@@ -1020,7 +1013,8 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
}
bool
AsyncCompositionManager::TransformShadowTree(TimeStamp aCurrentFrame)
AsyncCompositionManager::TransformShadowTree(TimeStamp aCurrentFrame,
TransformsToSkip aSkip)
{
PROFILER_LABEL("AsyncCompositionManager", "TransformShadowTree",
js::ProfileEntry::Category::GRAPHICS);
@@ -1035,29 +1029,31 @@ AsyncCompositionManager::TransformShadowTree(TimeStamp aCurrentFrame)
// transforms.
bool wantNextFrame = SampleAnimations(root, aCurrentFrame);
// FIXME/bug 775437: unify this interface with the ~native-fennec
// derived code
//
// Attempt to apply an async content transform to any layer that has
// an async pan zoom controller (which means that it is rendered
// async using Gecko). If this fails, fall back to transforming the
// primary scrollable layer. "Failing" here means that we don't
// find a frame that is async scrollable. Note that the fallback
// code also includes Fennec which is rendered async. Fennec uses
// its own platform-specific async rendering that is done partially
// in Gecko and partially in Java.
wantNextFrame |= SampleAPZAnimations(LayerMetricsWrapper(root), aCurrentFrame);
if (!ApplyAsyncContentTransformToTree(root)) {
nsAutoTArray<Layer*,1> scrollableLayers;
if (!(aSkip & TransformsToSkip::APZ)) {
// FIXME/bug 775437: unify this interface with the ~native-fennec
// derived code
//
// Attempt to apply an async content transform to any layer that has
// an async pan zoom controller (which means that it is rendered
// async using Gecko). If this fails, fall back to transforming the
// primary scrollable layer. "Failing" here means that we don't
// find a frame that is async scrollable. Note that the fallback
// code also includes Fennec which is rendered async. Fennec uses
// its own platform-specific async rendering that is done partially
// in Gecko and partially in Java.
wantNextFrame |= SampleAPZAnimations(LayerMetricsWrapper(root), aCurrentFrame);
if (!ApplyAsyncContentTransformToTree(root)) {
nsAutoTArray<Layer*,1> scrollableLayers;
#ifdef MOZ_WIDGET_ANDROID
mLayerManager->GetRootScrollableLayers(scrollableLayers);
mLayerManager->GetRootScrollableLayers(scrollableLayers);
#else
mLayerManager->GetScrollableLayers(scrollableLayers);
mLayerManager->GetScrollableLayers(scrollableLayers);
#endif
for (uint32_t i = 0; i < scrollableLayers.Length(); i++) {
if (scrollableLayers[i]) {
TransformScrollableLayer(scrollableLayers[i]);
for (uint32_t i = 0; i < scrollableLayers.Length(); i++) {
if (scrollableLayers[i]) {
TransformScrollableLayer(scrollableLayers[i]);
}
}
}
}
@@ -95,7 +95,9 @@ public:
// Sample transforms for layer trees. Return true to request
// another animation frame.
bool TransformShadowTree(TimeStamp aCurrentFrame);
enum class TransformsToSkip : uint8_t { NoneOfThem = 0, APZ = 1 };
bool TransformShadowTree(TimeStamp aCurrentFrame,
TransformsToSkip aSkip = TransformsToSkip::NoneOfThem);
// Calculates the correct rotation and applies the transform to
// our layer manager
@@ -208,6 +210,8 @@ private:
gfx::Matrix mWorldTransform;
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(AsyncCompositionManager::TransformsToSkip)
class MOZ_STACK_CLASS AutoResolveRefLayers {
public:
explicit AutoResolveRefLayers(AsyncCompositionManager* aManager) : mManager(aManager)
+30 -11
View File
@@ -63,7 +63,8 @@ ContentHostTexture::Composite(EffectChain& aEffectChain,
RefPtr<TexturedEffect> effect = CreateTexturedEffect(mTextureSource.get(),
mTextureSourceOnWhite.get(),
aFilter, true);
aFilter, true,
GetRenderState());
if (!effect) {
return;
}
@@ -261,23 +262,40 @@ ContentHostTexture::Dump(std::stringstream& aStream,
bool aDumpHtml)
{
#ifdef MOZ_DUMP_PAINTING
if (!aDumpHtml) {
return;
if (aDumpHtml) {
aStream << "<ul>";
}
aStream << "<ul>";
if (mTextureHost) {
aStream << aPrefix;
aStream << "<li> <a href=";
if (aDumpHtml) {
aStream << "<li> <a href=";
} else {
aStream << "Front buffer: ";
}
DumpTextureHost(aStream, mTextureHost);
aStream << "> Front buffer </a></li> ";
if (aDumpHtml) {
aStream << "> Front buffer </a></li> ";
} else {
aStream << "\n";
}
}
if (mTextureHostOnWhite) {
aStream << aPrefix;
aStream << "<li> <a href=";
aStream << aPrefix;
if (aDumpHtml) {
aStream << "<li> <a href=";
} else {
aStream << "Front buffer on white: ";
}
DumpTextureHost(aStream, mTextureHostOnWhite);
aStream << "> Front buffer on white </a> </li> ";
if (aDumpHtml) {
aStream << "> Front buffer on white </a> </li> ";
} else {
aStream << "\n";
}
}
if (aDumpHtml) {
aStream << "</ul>";
}
aStream << "</ul>";
#endif
}
@@ -443,7 +461,8 @@ ContentHostTexture::GenEffect(const gfx::Filter& aFilter)
}
return CreateTexturedEffect(mTextureSource.get(),
mTextureSourceOnWhite.get(),
aFilter, true);
aFilter, true,
GetRenderState());
}
already_AddRefed<gfx::DataSourceSurface>
+5 -2
View File
@@ -43,6 +43,7 @@ ImageHost::UseTextureHost(TextureHost* aTexture)
CompositableHost::UseTextureHost(aTexture);
mFrontBuffer = aTexture;
if (mFrontBuffer) {
mFrontBuffer->Updated();
mFrontBuffer->PrepareTextureSource(mTextureSource);
}
}
@@ -105,7 +106,8 @@ ImageHost::Composite(EffectChain& aEffectChain,
RefPtr<TexturedEffect> effect = CreateTexturedEffect(mFrontBuffer->GetFormat(),
mTextureSource.get(),
aFilter,
isAlphaPremultiplied);
isAlphaPremultiplied,
GetRenderState());
if (!effect) {
return;
}
@@ -297,7 +299,8 @@ ImageHost::GenEffect(const gfx::Filter& aFilter)
return CreateTexturedEffect(mFrontBuffer->GetFormat(),
mTextureSource,
aFilter,
isAlphaPremultiplied);
isAlphaPremultiplied,
GetRenderState());
}
#ifdef MOZ_WIDGET_GONK
+189 -9
View File
@@ -55,6 +55,11 @@
#include "nsRegion.h" // for nsIntRegion, etc
#ifdef MOZ_WIDGET_ANDROID
#include <android/log.h>
#include "AndroidBridge.h"
#include "opengl/CompositorOGL.h"
#include "GLContextEGL.h"
#include "GLContextProvider.h"
#include "ScopedGLHelpers.h"
#endif
#include "GeckoProfiler.h"
#include "TextRenderer.h" // for TextRenderer
@@ -307,6 +312,9 @@ LayerManagerComposite::EndTransaction(DrawPaintedLayerCallback aCallback,
ApplyOcclusionCulling(mRoot, opaque);
Render();
#ifdef MOZ_WIDGET_ANDROID
RenderToPresentationSurface();
#endif
mGeometryChanged = false;
} else {
// Modified layer tree
@@ -653,14 +661,13 @@ LayerManagerComposite::Render()
/** Our more efficient but less powerful alter ego, if one is available. */
nsRefPtr<Composer2D> composer2D;
composer2D = mCompositor->GetWidget()->GetComposer2D();
// We can't use composert2D if we have layer effects, so only get it
// when we don't have any effects.
if (!haveLayerEffects) {
composer2D = mCompositor->GetWidget()->GetComposer2D();
}
if (!mTarget && composer2D && composer2D->TryRender(mRoot, mGeometryChanged)) {
// We can't use composert2D if we have layer effects
if (!mTarget && !haveLayerEffects &&
gfxPrefs::Composer2DCompositionEnabled() &&
composer2D && composer2D->HasHwc() && composer2D->TryRenderWithHwc(mRoot, mGeometryChanged))
{
LayerScope::SetHWComposed();
if (mFPS) {
double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now());
@@ -673,7 +680,7 @@ LayerManagerComposite::Render()
mInvalidRegion.SetEmpty();
mLastFrameMissedHWC = false;
return;
} else if (!mTarget) {
} else if (!mTarget && !haveLayerEffects) {
mLastFrameMissedHWC = !!composer2D;
}
@@ -761,7 +768,11 @@ LayerManagerComposite::Render()
js::ProfileEntry::Category::GRAPHICS);
mCompositor->EndFrame();
mCompositor->SetFBAcquireFence(mRoot);
mCompositor->SetDispAcquireFence(mRoot);
}
if (composer2D) {
composer2D->Render();
}
mCompositor->GetWidget()->PostRender(this);
@@ -769,6 +780,175 @@ LayerManagerComposite::Render()
RecordFrame();
}
#ifdef MOZ_WIDGET_ANDROID
class ScopedCompositorProjMatrix {
public:
ScopedCompositorProjMatrix(CompositorOGL* aCompositor, const Matrix4x4& aProjMatrix):
mCompositor(aCompositor),
mOriginalProjMatrix(mCompositor->GetProjMatrix())
{
mCompositor->SetProjMatrix(aProjMatrix);
}
~ScopedCompositorProjMatrix()
{
mCompositor->SetProjMatrix(mOriginalProjMatrix);
}
private:
CompositorOGL* const mCompositor;
const Matrix4x4 mOriginalProjMatrix;
};
class ScopedCompostitorSurfaceSize {
public:
ScopedCompostitorSurfaceSize(CompositorOGL* aCompositor, const gfx::IntSize& aSize) :
mCompositor(aCompositor),
mOriginalSize(mCompositor->GetDestinationSurfaceSize())
{
mCompositor->SetDestinationSurfaceSize(aSize);
}
~ScopedCompostitorSurfaceSize()
{
mCompositor->SetDestinationSurfaceSize(mOriginalSize);
}
private:
CompositorOGL* const mCompositor;
const gfx::IntSize mOriginalSize;
};
class ScopedCompositorRenderOffset {
public:
ScopedCompositorRenderOffset(CompositorOGL* aCompositor, const ScreenPoint& aOffset) :
mCompositor(aCompositor),
mOriginalOffset(mCompositor->GetScreenRenderOffset())
{
mCompositor->SetScreenRenderOffset(aOffset);
}
~ScopedCompositorRenderOffset()
{
mCompositor->SetScreenRenderOffset(mOriginalOffset);
}
private:
CompositorOGL* const mCompositor;
const ScreenPoint mOriginalOffset;
};
class ScopedContextSurfaceOverride {
public:
ScopedContextSurfaceOverride(GLContextEGL* aContext, void* aSurface) :
mContext(aContext)
{
MOZ_ASSERT(aSurface);
mContext->SetEGLSurfaceOverride(aSurface);
mContext->MakeCurrent(true);
}
~ScopedContextSurfaceOverride()
{
mContext->SetEGLSurfaceOverride(EGL_NO_SURFACE);
mContext->MakeCurrent(true);
}
private:
GLContextEGL* const mContext;
};
void
LayerManagerComposite::RenderToPresentationSurface()
{
if (!AndroidBridge::Bridge()) {
return;
}
void* window = AndroidBridge::Bridge()->GetPresentationWindow();
if (!window) {
return;
}
EGLSurface surface = AndroidBridge::Bridge()->GetPresentationSurface();
if (!surface) {
//create surface;
surface = GLContextProviderEGL::CreateEGLSurface(window);
if (!surface) {
return;
}
AndroidBridge::Bridge()->SetPresentationSurface(surface);
}
CompositorOGL* compositor = static_cast<CompositorOGL*>(mCompositor.get());
GLContext* gl = compositor->gl();
GLContextEGL* egl = GLContextEGL::Cast(gl);
if (!egl) {
return;
}
const IntSize windowSize = AndroidBridge::Bridge()->GetNativeWindowSize(window);
if ((windowSize.width <= 0) || (windowSize.height <= 0)) {
return;
}
const int actualWidth = windowSize.width;
const int actualHeight = windowSize.height;
const gfx::IntSize originalSize = compositor->GetDestinationSurfaceSize();
const int pageWidth = originalSize.width;
const int pageHeight = originalSize.height;
float scale = 1.0;
if ((pageWidth > actualWidth) || (pageHeight > actualHeight)) {
const float scaleWidth = (float)actualWidth / (float)pageWidth;
const float scaleHeight = (float)actualHeight / (float)pageHeight;
scale = scaleWidth <= scaleHeight ? scaleWidth : scaleHeight;
}
const gfx::IntSize actualSize(actualWidth, actualHeight);
ScopedCompostitorSurfaceSize overrideSurfaceSize(compositor, actualSize);
const ScreenPoint offset((actualWidth - (int)(scale * pageWidth)) / 2, 0);
ScopedCompositorRenderOffset overrideRenderOffset(compositor, offset);
ScopedContextSurfaceOverride overrideSurface(egl, surface);
nsIntRegion invalid;
Rect bounds(0.0f, 0.0f, scale * pageWidth, (float)actualHeight);
Rect rect, actualBounds;
mCompositor->BeginFrame(invalid, nullptr, bounds, &rect, &actualBounds);
// Override the projection matrix since the presentation frame buffer
// is probably not the same size as the device frame buffer. The override
// projection matrix also scales the content to fit into the presentation
// frame buffer.
Matrix viewMatrix;
viewMatrix.PreTranslate(-1.0, 1.0);
viewMatrix.PreScale((2.0f * scale) / (float)actualWidth, (2.0f * scale) / (float)actualHeight);
viewMatrix.PreScale(1.0f, -1.0f);
viewMatrix.PreTranslate((int)((float)offset.x / scale), offset.y);
Matrix4x4 projMatrix = Matrix4x4::From2D(viewMatrix);
ScopedCompositorProjMatrix overrideProjMatrix(compositor, projMatrix);
// The Java side of Fennec sets a scissor rect that accounts for
// chrome such as the URL bar. Override that so that the entire frame buffer
// is cleared.
ScopedScissorRect screen(egl, 0, 0, actualWidth, actualHeight);
egl->fClearColor(0.0, 0.0, 0.0, 0.0);
egl->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
const nsIntRect clipRect = nsIntRect(0, 0, (int)(scale * pageWidth), actualHeight);
RootLayer()->Prepare(RenderTargetPixel::FromUntyped(clipRect));
RootLayer()->RenderLayer(clipRect);
mCompositor->EndFrame();
mCompositor->SetDispAcquireFence(mRoot);
}
#endif
static void
SubtractTransformedRegion(nsIntRegion& aRegion,
const nsIntRegion& aRegionToSubtract,
@@ -273,6 +273,9 @@ private:
* Render the current layer tree to the active target.
*/
void Render();
#ifdef MOZ_WIDGET_ANDROID
void RenderToPresentationSurface();
#endif
/**
* Render debug overlays such as the FPS/FrameCounter above the frame.
+42 -13
View File
@@ -144,22 +144,39 @@ TextureHost::GetIPDLActor()
return mActor;
}
bool
TextureHost::SetReleaseFenceHandle(const FenceHandle& aReleaseFenceHandle)
{
if (!aReleaseFenceHandle.IsValid()) {
// HWC might not provide Fence.
// In this case, HWC implicitly handles buffer's fence.
return false;
}
mReleaseFenceHandle.Merge(aReleaseFenceHandle);
return true;
}
FenceHandle
TextureHost::GetAndResetReleaseFenceHandle()
{
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
TextureHostOGL* hostOGL = this->AsHostOGL();
if (!hostOGL) {
return FenceHandle();
}
FenceHandle fence;
mReleaseFenceHandle.TransferToAnotherFenceHandle(fence);
return fence;
}
android::sp<android::Fence> fence = hostOGL->GetAndResetReleaseFence();
if (fence.get() && fence->isValid()) {
FenceHandle handle = FenceHandle(fence);
return handle;
}
#endif
return FenceHandle();
void
TextureHost::SetAcquireFenceHandle(const FenceHandle& aAcquireFenceHandle)
{
mAcquireFenceHandle = aAcquireFenceHandle;
}
FenceHandle
TextureHost::GetAndResetAcquireFenceHandle()
{
nsRefPtr<FenceHandle::FdObj> fdObj = mAcquireFenceHandle.GetAndResetFdObj();
return FenceHandle(fdObj);
}
// implemented in TextureHostOGL.cpp
@@ -192,6 +209,7 @@ TextureHost::Create(const SurfaceDescriptor& aDesc,
case SurfaceDescriptor::TSurfaceDescriptorShmem:
case SurfaceDescriptor::TSurfaceDescriptorMemory:
case SurfaceDescriptor::TSurfaceDescriptorDIB:
case SurfaceDescriptor::TSurfaceDescriptorFileMapping:
return CreateBackendIndependentTextureHost(aDesc, aDeallocator, aFlags);
case SurfaceDescriptor::TEGLImageDescriptor:
@@ -260,6 +278,10 @@ CreateBackendIndependentTextureHost(const SurfaceDescriptor& aDesc,
result = new DIBTextureHost(aFlags, aDesc);
break;
}
case SurfaceDescriptor::TSurfaceDescriptorFileMapping: {
result = new TextureHostFileMapping(aFlags, aDesc);
break;
}
#endif
default: {
NS_WARNING("No backend independent TextureHost for this descriptor type");
@@ -331,6 +353,13 @@ TextureHost::PrintInfo(std::stringstream& aStream, const char* aPrefix)
#endif
}
void
TextureHost::Updated(const nsIntRegion* aRegion)
{
LayerScope::ContentChanged(this);
UpdatedInternal(aRegion);
}
TextureSource::TextureSource()
: mCompositableCount(0)
{
@@ -379,7 +408,7 @@ BufferTextureHost::~BufferTextureHost()
{}
void
BufferTextureHost::Updated(const nsIntRegion* aRegion)
BufferTextureHost::UpdatedInternal(const nsIntRegion* aRegion)
{
++mUpdateSerial;
// If the last frame wasn't uploaded yet, and we -don't- have a partial update,
+29 -10
View File
@@ -388,7 +388,7 @@ public:
* @param aRegion The region that has been changed, if nil, it means that the
* entire surface should be updated.
*/
virtual void Updated(const nsIntRegion* aRegion = nullptr) {}
void Updated(const nsIntRegion* aRegion = nullptr);
/**
* Sets this TextureHost's compositor.
@@ -470,8 +470,6 @@ public:
*/
PTextureParent* GetIPDLActor();
FenceHandle GetAndResetReleaseFenceHandle();
/**
* Specific to B2G's Composer2D
* XXX - more doc here
@@ -500,11 +498,6 @@ public:
*/
virtual bool HasInternalBuffer() const { return false; }
/**
* Cast to a TextureHost for each backend.
*/
virtual TextureHostOGL* AsHostOGL() { return nullptr; }
void AddCompositableRef() { ++mCompositableCount; }
void ReleaseCompositableRef()
@@ -518,9 +511,35 @@ public:
int NumCompositableRefs() const { return mCompositableCount; }
/**
* Store a fence that will signal when the current buffer is no longer being read.
* Similar to android's GLConsumer::setReleaseFence()
*/
bool SetReleaseFenceHandle(const FenceHandle& aReleaseFenceHandle);
/**
* Return a releaseFence's Fence and clear a reference to the Fence.
*/
FenceHandle GetAndResetReleaseFenceHandle();
void SetAcquireFenceHandle(const FenceHandle& aAcquireFenceHandle);
/**
* Return a acquireFence's Fence and clear a reference to the Fence.
*/
FenceHandle GetAndResetAcquireFenceHandle();
virtual void WaitAcquireFenceHandleSyncComplete() {};
protected:
FenceHandle mReleaseFenceHandle;
FenceHandle mAcquireFenceHandle;
void RecycleTexture(TextureFlags aFlags);
virtual void UpdatedInternal(const nsIntRegion *Region) {}
PTextureParent* mActor;
TextureFlags mFlags;
int mCompositableCount;
@@ -553,8 +572,6 @@ public:
virtual size_t GetBufferSize() = 0;
virtual void Updated(const nsIntRegion* aRegion = nullptr) override;
virtual bool Lock() override;
virtual void Unlock() override;
@@ -586,6 +603,8 @@ protected:
void InitSize();
virtual void UpdatedInternal(const nsIntRegion* aRegion = nullptr) override;
RefPtr<Compositor> mCompositor;
RefPtr<DataTextureSource> mFirstSource;
nsIntRegion mMaybeUpdatedRegion;
+6 -18
View File
@@ -225,23 +225,6 @@ TiledLayerBufferComposite::SetCompositor(Compositor* aCompositor)
}
}
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
void
TiledLayerBufferComposite::SetReleaseFence(const android::sp<android::Fence>& aReleaseFence)
{
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
if (!mRetainedTiles[i].mTextureHost) {
continue;
}
TextureHostOGL* texture = mRetainedTiles[i].mTextureHost->AsHostOGL();
if (!texture) {
continue;
}
texture->SetReleaseFence(new android::Fence(aReleaseFence->dup()));
}
}
#endif
TiledContentHost::TiledContentHost(const TextureInfo& aTextureInfo)
: ContentHost(aTextureInfo)
, mTiledBuffer(TiledLayerBufferComposite())
@@ -516,7 +499,12 @@ TiledContentHost::RenderTile(const TileHost& aTile,
return;
}
RefPtr<TexturedEffect> effect = CreateTexturedEffect(aTile.mTextureSource, aTile.mTextureSourceOnWhite, aFilter, true);
RefPtr<TexturedEffect> effect =
CreateTexturedEffect(aTile.mTextureSource,
aTile.mTextureSourceOnWhite,
aFilter,
true,
aTile.mTextureHost->GetRenderState());
if (!effect) {
return;
}
-16
View File
@@ -150,10 +150,6 @@ public:
bool IsValid() const { return mIsValid; }
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
virtual void SetReleaseFence(const android::sp<android::Fence>& aReleaseFence);
#endif
// Recycle callback for TextureHost.
// Used when TiledContentClient is present in client side.
static void RecycleCallback(TextureHost* textureHost, void* aClosure);
@@ -267,18 +263,6 @@ public:
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
/**
* Store a fence that will signal when the current buffer is no longer being read.
* Similar to android's GLConsumer::setReleaseFence()
*/
virtual void SetReleaseFence(const android::sp<android::Fence>& aReleaseFence)
{
mTiledBuffer.SetReleaseFence(aReleaseFence);
mLowPrecisionTiledBuffer.SetReleaseFence(aReleaseFence);
}
#endif
private:
void RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
+1 -1
View File
@@ -914,7 +914,7 @@ DataTextureSourceD3D9::UpdateFromTexture(IDirect3DTexture9* aTexture,
}
void
TextureHostD3D9::Updated(const nsIntRegion* aRegion)
TextureHostD3D9::UpdatedInternal(const nsIntRegion* aRegion)
{
MOZ_ASSERT(mTexture);
if (!mTexture) {
+2 -2
View File
@@ -308,8 +308,6 @@ public:
virtual void Unlock() override;
virtual void Updated(const nsIntRegion* aRegion) override;
virtual gfx::IntSize GetSize() const override { return mSize; }
virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override
@@ -323,6 +321,8 @@ protected:
TextureHostD3D9(TextureFlags aFlags);
IDirect3DDevice9* GetDevice();
virtual void UpdatedInternal(const nsIntRegion* aRegion) override;
RefPtr<DataTextureSourceD3D9> mTextureSource;
RefPtr<IDirect3DTexture9> mTexture;
RefPtr<CompositorD3D9> mCompositor;
-32
View File
@@ -185,38 +185,6 @@ protected:
static std::map<uint64_t, AsyncTransactionTrackersHolder*> sTrackersHolders;
};
/**
* FenceDeliveryTracker puts off releasing a Fence until a transaction complete.
*/
class FenceDeliveryTracker : public AsyncTransactionTracker {
public:
explicit FenceDeliveryTracker(FenceHandle& aFenceHandle)
: mFenceHandle(aFenceHandle)
{
MOZ_COUNT_CTOR(FenceDeliveryTracker);
}
protected:
~FenceDeliveryTracker()
{
MOZ_COUNT_DTOR(FenceDeliveryTracker);
}
public:
virtual void Complete() override
{
mFenceHandle = FenceHandle();
}
virtual void Cancel() override
{
mFenceHandle = FenceHandle();
}
private:
FenceHandle mFenceHandle;
};
} // namespace layers
} // namespace mozilla
-24
View File
@@ -133,16 +133,6 @@ public:
mTexturesToRemove.Clear();
}
virtual void HoldTransactionsToRespond(uint64_t aTransactionId)
{
mTransactionsToRespond.push_back(aTransactionId);
}
virtual void ClearTransactionsToRespond()
{
mTransactionsToRespond.clear();
}
/**
* Tell the CompositableHost on the compositor side what texture to use for
* the next composition.
@@ -153,19 +143,6 @@ public:
TextureClient* aClientOnBlack,
TextureClient* aClientOnWhite) = 0;
/**
* Tell the compositor side that the shared data has been modified so that
* it can react accordingly (upload textures, etc.).
*/
virtual void UpdatedTexture(CompositableClient* aCompositable,
TextureClient* aTexture,
nsIntRegion* aRegion) = 0;
virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
PTextureChild* aTexture,
const FenceHandle& aFence) = 0;
virtual void SendPendingAsyncMessges() = 0;
void IdentifyTextureHost(const TextureFactoryIdentifier& aIdentifier);
@@ -209,7 +186,6 @@ public:
protected:
TextureFactoryIdentifier mTextureFactoryIdentifier;
nsTArray<RefPtr<TextureClient> > mTexturesToRemove;
std::vector<uint64_t> mTransactionsToRespond;
RefPtr<SyncObject> mSyncObject;
const int32_t mSerial;
static mozilla::Atomic<int32_t> sSerialCounter;
@@ -145,7 +145,7 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
if (!IsAsync() && ImageBridgeParent::GetInstance(GetChildProcessId())) {
// send FenceHandle if present via ImageBridge.
ImageBridgeParent::SendFenceHandleToTrackerIfPresent(
ImageBridgeParent::AppendDeliverFenceMessage(
GetChildProcessId(),
op.holderId(),
op.transactionId(),
@@ -156,15 +156,13 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
// Send message back via PImageBridge.
ImageBridgeParent::ReplyRemoveTexture(
GetChildProcessId(),
OpReplyRemoveTexture(true, // isMain
op.holderId(),
OpReplyRemoveTexture(op.holderId(),
op.transactionId()));
} else {
// send FenceHandle if present.
SendFenceHandleIfPresent(op.textureParent(), compositable);
ReplyRemoveTexture(OpReplyRemoveTexture(false, // isMain
op.holderId(),
ReplyRemoveTexture(OpReplyRemoveTexture(op.holderId(),
op.transactionId()));
}
break;
@@ -177,6 +175,14 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
MOZ_ASSERT(tex.get());
compositable->UseTextureHost(tex);
MaybeFence maybeFence = op.fence();
if (maybeFence.type() == MaybeFence::TFenceHandle) {
FenceHandle fence = maybeFence.get_FenceHandle();
if (fence.IsValid() && tex) {
tex->SetAcquireFenceHandle(fence);
}
}
if (IsAsync() && compositable->GetLayer()) {
ScheduleComposition(op);
// Async layer updates don't trigger invalidation, manually tell the layer
@@ -208,17 +214,6 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
break;
}
#endif
case CompositableOperation::TOpUpdateTexture: {
const OpUpdateTexture& op = aEdit.get_OpUpdateTexture();
RefPtr<TextureHost> texture = TextureHost::AsTextureHost(op.textureParent());
MOZ_ASSERT(texture);
texture->Updated(op.region().type() == MaybeRegion::TnsIntRegion
? &op.region().get_nsIntRegion()
: nullptr); // no region means invalidate the entire surface
break;
}
default: {
MOZ_ASSERT(false, "bad type");
}
@@ -228,7 +223,7 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
}
void
CompositableParentManager::SendPendingAsyncMessges()
CompositableParentManager::SendPendingAsyncMessages()
{
if (mPendingAsyncMessage.empty()) {
return;
@@ -26,19 +26,14 @@ typedef std::vector<mozilla::layers::EditReply> EditReplyVector;
// so both manager protocols implement this and we keep a reference to them
// through this interface.
class CompositableParentManager : public ISurfaceAllocator
, public AsyncTransactionTrackersHolder
{
public:
virtual void SendFenceHandleIfPresent(PTextureParent* aTexture,
CompositableHost* aCompositableHost) = 0;
virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
PTextureParent* aTexture,
const FenceHandle& aFence) = 0;
virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) = 0;
void SendPendingAsyncMessges();
void SendPendingAsyncMessages();
/**
* Get child side's process Id.
+338 -175
View File
@@ -215,43 +215,226 @@ static void SetThreadPriority()
hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR);
}
CompositorVsyncObserver::CompositorVsyncObserver(CompositorParent* aCompositorParent, nsIWidget* aWidget)
: mNeedsComposite(false)
CompositorScheduler::CompositorScheduler(CompositorParent* aCompositorParent)
: mCompositorParent(aCompositorParent)
, mCurrentCompositeTask(nullptr)
{
}
CompositorScheduler::~CompositorScheduler()
{
MOZ_ASSERT(!mCompositorParent);
}
void
CompositorScheduler::CancelCurrentCompositeTask()
{
if (mCurrentCompositeTask) {
mCurrentCompositeTask->Cancel();
mCurrentCompositeTask = nullptr;
}
}
void
CompositorScheduler::ScheduleTask(CancelableTask* aTask, int aTime)
{
MOZ_ASSERT(CompositorParent::CompositorLoop());
MOZ_ASSERT(aTime >= 0);
CompositorParent::CompositorLoop()->PostDelayedTask(FROM_HERE, aTask, aTime);
}
void
CompositorScheduler::ResumeComposition()
{
mLastCompose = TimeStamp::Now();
ComposeToTarget(nullptr);
}
void
CompositorScheduler::ForceComposeToTarget(gfx::DrawTarget* aTarget, const nsIntRect* aRect)
{
mLastCompose = TimeStamp::Now();
ComposeToTarget(aTarget, aRect);
}
void
CompositorScheduler::ComposeToTarget(gfx::DrawTarget* aTarget, const nsIntRect* aRect)
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
MOZ_ASSERT(mCompositorParent);
mCompositorParent->CompositeToTarget(aTarget, aRect);
}
void
CompositorScheduler::Destroy()
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
CancelCurrentCompositeTask();
mCompositorParent = nullptr;
}
CompositorSoftwareTimerScheduler::CompositorSoftwareTimerScheduler(CompositorParent* aCompositorParent)
: CompositorScheduler(aCompositorParent)
{
}
CompositorSoftwareTimerScheduler::~CompositorSoftwareTimerScheduler()
{
MOZ_ASSERT(!mCurrentCompositeTask);
}
// Used when layout.frame_rate is -1. Needs to be kept in sync with
// DEFAULT_FRAME_RATE in nsRefreshDriver.cpp.
static const int32_t kDefaultFrameRate = 60;
static int32_t
CalculateCompositionFrameRate()
{
int32_t compositionFrameRatePref = gfxPrefs::LayersCompositionFrameRate();
if (compositionFrameRatePref < 0) {
// Use the same frame rate for composition as for layout.
int32_t layoutFrameRatePref = gfxPrefs::LayoutFrameRate();
if (layoutFrameRatePref < 0) {
// TODO: The main thread frame scheduling code consults the actual
// monitor refresh rate in this case. We should do the same.
return kDefaultFrameRate;
}
return layoutFrameRatePref;
}
return compositionFrameRatePref;
}
void
CompositorSoftwareTimerScheduler::ScheduleComposition()
{
if (mCurrentCompositeTask) {
return;
}
bool initialComposition = mLastCompose.IsNull();
TimeDuration delta;
if (!initialComposition) {
delta = TimeStamp::Now() - mLastCompose;
}
int32_t rate = CalculateCompositionFrameRate();
// If rate == 0 (ASAP mode), minFrameDelta must be 0 so there's no delay.
TimeDuration minFrameDelta = TimeDuration::FromMilliseconds(
rate == 0 ? 0.0 : std::max(0.0, 1000.0 / rate));
mCurrentCompositeTask = NewRunnableMethod(this,
&CompositorSoftwareTimerScheduler::CallComposite);
if (!initialComposition && delta < minFrameDelta) {
TimeDuration delay = minFrameDelta - delta;
#ifdef COMPOSITOR_PERFORMANCE_WARNING
mExpectedComposeStartTime = TimeStamp::Now() + delay;
#endif
ScheduleTask(mCurrentCompositeTask, delay.ToMilliseconds());
} else {
#ifdef COMPOSITOR_PERFORMANCE_WARNING
mExpectedComposeStartTime = TimeStamp::Now();
#endif
ScheduleTask(mCurrentCompositeTask, 0);
}
}
bool
CompositorSoftwareTimerScheduler::NeedsComposite()
{
return mCurrentCompositeTask ? true : false;
}
void
CompositorSoftwareTimerScheduler::CallComposite()
{
Composite(TimeStamp::Now());
}
void
CompositorSoftwareTimerScheduler::Composite(TimeStamp aTimestamp)
{
mCurrentCompositeTask = nullptr;
mLastCompose = aTimestamp;
ComposeToTarget(nullptr);
}
CompositorVsyncScheduler::Observer::Observer(CompositorVsyncScheduler* aOwner)
: mMutex("CompositorVsyncScheduler.Observer.Mutex")
, mOwner(aOwner)
{
}
CompositorVsyncScheduler::Observer::~Observer()
{
MOZ_ASSERT(!mOwner);
}
bool
CompositorVsyncScheduler::Observer::NotifyVsync(TimeStamp aVsyncTimestamp)
{
MutexAutoLock lock(mMutex);
if (!mOwner) {
return false;
}
return mOwner->NotifyVsync(aVsyncTimestamp);
}
void
CompositorVsyncScheduler::Observer::Destroy()
{
MutexAutoLock lock(mMutex);
mOwner = nullptr;
}
CompositorVsyncScheduler::CompositorVsyncScheduler(CompositorParent* aCompositorParent, nsIWidget* aWidget)
: CompositorScheduler(aCompositorParent)
, mNeedsComposite(false)
, mIsObservingVsync(false)
, mVsyncNotificationsSkipped(0)
, mCompositorParent(aCompositorParent)
, mCurrentCompositeTaskMonitor("CurrentCompositeTaskMonitor")
, mCurrentCompositeTask(nullptr)
, mSetNeedsCompositeMonitor("SetNeedsCompositeMonitor")
, mSetNeedsCompositeTask(nullptr)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aWidget != nullptr);
mVsyncObserver = new Observer(this);
mCompositorVsyncDispatcher = aWidget->GetCompositorVsyncDispatcher();
#ifdef MOZ_WIDGET_GONK
GeckoTouchDispatcher::SetCompositorVsyncObserver(this);
GeckoTouchDispatcher::GetInstance()->SetCompositorVsyncScheduler(this);
#endif
}
CompositorVsyncObserver::~CompositorVsyncObserver()
CompositorVsyncScheduler::~CompositorVsyncScheduler()
{
MOZ_ASSERT(!mIsObservingVsync);
MOZ_ASSERT(!mVsyncObserver);
// The CompositorVsyncDispatcher is cleaned up before this in the nsBaseWidget, which stops vsync listeners
mCompositorParent = nullptr;
mCompositorVsyncDispatcher = nullptr;
}
void
CompositorVsyncObserver::Destroy()
CompositorVsyncScheduler::Destroy()
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
UnobserveVsync();
CancelCurrentCompositeTask();
mVsyncObserver->Destroy();
mVsyncObserver = nullptr;
CancelCurrentSetNeedsCompositeTask();
CompositorScheduler::Destroy();
}
void
CompositorVsyncObserver::CancelCurrentSetNeedsCompositeTask()
CompositorVsyncScheduler::ScheduleComposition()
{
SetNeedsComposite(true);
}
void
CompositorVsyncScheduler::CancelCurrentSetNeedsCompositeTask()
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
MonitorAutoLock lock(mSetNeedsCompositeMonitor);
@@ -270,15 +453,14 @@ CompositorVsyncObserver::CancelCurrentSetNeedsCompositeTask()
* How many skipped vsync events until we stop listening to vsync events?
*/
void
CompositorVsyncObserver::SetNeedsComposite(bool aNeedsComposite)
CompositorVsyncScheduler::SetNeedsComposite(bool aNeedsComposite)
{
if (!CompositorParent::IsInCompositorThread()) {
MonitorAutoLock lock(mSetNeedsCompositeMonitor);
mSetNeedsCompositeTask = NewRunnableMethod(this,
&CompositorVsyncObserver::SetNeedsComposite,
&CompositorVsyncScheduler::SetNeedsComposite,
aNeedsComposite);
MOZ_ASSERT(CompositorParent::CompositorLoop());
CompositorParent::CompositorLoop()->PostTask(FROM_HERE, mSetNeedsCompositeTask);
ScheduleTask(mSetNeedsCompositeTask, 0);
return;
} else {
MonitorAutoLock lock(mSetNeedsCompositeMonitor);
@@ -292,7 +474,7 @@ CompositorVsyncObserver::SetNeedsComposite(bool aNeedsComposite)
}
bool
CompositorVsyncObserver::NotifyVsync(TimeStamp aVsyncTimestamp)
CompositorVsyncScheduler::NotifyVsync(TimeStamp aVsyncTimestamp)
{
// Called from the vsync dispatch thread
MOZ_ASSERT(!CompositorParent::IsInCompositorThread());
@@ -301,27 +483,23 @@ CompositorVsyncObserver::NotifyVsync(TimeStamp aVsyncTimestamp)
MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
if (mCurrentCompositeTask == nullptr) {
mCurrentCompositeTask = NewRunnableMethod(this,
&CompositorVsyncObserver::Composite,
&CompositorVsyncScheduler::Composite,
aVsyncTimestamp);
MOZ_ASSERT(CompositorParent::CompositorLoop());
CompositorParent::CompositorLoop()->PostTask(FROM_HERE, mCurrentCompositeTask);
ScheduleTask(mCurrentCompositeTask, 0);
}
return true;
}
void
CompositorVsyncObserver::CancelCurrentCompositeTask()
CompositorVsyncScheduler::CancelCurrentCompositeTask()
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread() || NS_IsMainThread());
MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
if (mCurrentCompositeTask) {
mCurrentCompositeTask->Cancel();
mCurrentCompositeTask = nullptr;
}
CompositorScheduler::CancelCurrentCompositeTask();
}
void
CompositorVsyncObserver::Composite(TimeStamp aVsyncTimestamp)
CompositorVsyncScheduler::Composite(TimeStamp aVsyncTimestamp)
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
{
@@ -329,34 +507,59 @@ CompositorVsyncObserver::Composite(TimeStamp aVsyncTimestamp)
mCurrentCompositeTask = nullptr;
}
if (mNeedsComposite && mCompositorParent) {
DispatchTouchEvents(aVsyncTimestamp);
if (mNeedsComposite) {
mNeedsComposite = false;
mCompositorParent->CompositeCallback(aVsyncTimestamp);
mLastCompose = aVsyncTimestamp;
ComposeToTarget(nullptr);
mVsyncNotificationsSkipped = 0;
} else if (mVsyncNotificationsSkipped++ > gfxPrefs::CompositorUnobserveCount()) {
UnobserveVsync();
}
}
DispatchTouchEvents(aVsyncTimestamp);
void
CompositorVsyncScheduler::OnForceComposeToTarget()
{
/**
* bug 1138502 - There are cases such as during long-running window resizing events
* where we receive many sync RecvFlushComposites. We also get vsync notifications which
* will increment mVsyncNotificationsSkipped because a composite just occurred. After
* enough vsyncs and RecvFlushComposites occurred, we will disable vsync. Then at the next
* ScheduleComposite, we will enable vsync, then get a RecvFlushComposite, which will
* force us to unobserve vsync again. On some platforms, enabling/disabling vsync is not
* free and this oscillating behavior causes a performance hit. In order to avoid this problem,
* we reset the mVsyncNotificationsSkipped counter to keep vsync enabled.
*/
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
mVsyncNotificationsSkipped = 0;
}
void
CompositorVsyncScheduler::ForceComposeToTarget(gfx::DrawTarget* aTarget, const nsIntRect* aRect)
{
OnForceComposeToTarget();
CompositorScheduler::ForceComposeToTarget(aTarget, aRect);
}
bool
CompositorVsyncObserver::NeedsComposite()
CompositorVsyncScheduler::NeedsComposite()
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
return mNeedsComposite;
}
void
CompositorVsyncObserver::ObserveVsync()
CompositorVsyncScheduler::ObserveVsync()
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
mCompositorVsyncDispatcher->SetCompositorVsyncObserver(this);
mCompositorVsyncDispatcher->SetCompositorVsyncObserver(mVsyncObserver);
mIsObservingVsync = true;
}
void
CompositorVsyncObserver::UnobserveVsync()
CompositorVsyncScheduler::UnobserveVsync()
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
mCompositorVsyncDispatcher->SetCompositorVsyncObserver(nullptr);
@@ -364,10 +567,10 @@ CompositorVsyncObserver::UnobserveVsync()
}
void
CompositorVsyncObserver::DispatchTouchEvents(TimeStamp aVsyncTimestamp)
CompositorVsyncScheduler::DispatchTouchEvents(TimeStamp aVsyncTimestamp)
{
#ifdef MOZ_WIDGET_GONK
GeckoTouchDispatcher::NotifyVsync(aVsyncTimestamp);
GeckoTouchDispatcher::GetInstance()->NotifyVsync(aVsyncTimestamp);
#endif
}
@@ -400,11 +603,28 @@ MessageLoop* CompositorParent::CompositorLoop()
return CompositorThread() ? CompositorThread()->message_loop() : nullptr;
}
static bool
IsInCompositorAsapMode()
{
// Returns true if the compositor is allowed to be in ASAP mode
// and layout is not in ASAP mode
return gfxPrefs::LayersCompositionFrameRate() == 0 &&
!gfxPlatform::IsInLayoutAsapMode();
}
static bool
UseVsyncComposition()
{
return gfxPrefs::VsyncAlignedCompositor()
&& gfxPrefs::HardwareVsyncEnabled()
&& !IsInCompositorAsapMode()
&& !gfxPlatform::IsInLayoutAsapMode();
}
CompositorParent::CompositorParent(nsIWidget* aWidget,
bool aUseExternalSurfaceSize,
int aSurfaceWidth, int aSurfaceHeight)
: mWidget(aWidget)
, mCurrentCompositeTask(nullptr)
, mIsTesting(false)
, mPendingTransaction(0)
, mPaused(false)
@@ -415,7 +635,7 @@ CompositorParent::CompositorParent(nsIWidget* aWidget,
, mOverrideComposeReadiness(false)
, mForceCompositionTask(nullptr)
, mCompositorThreadHolder(sCompositorThreadHolder)
, mCompositorVsyncObserver(nullptr)
, mCompositorScheduler(nullptr)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(CompositorThread(),
@@ -442,8 +662,11 @@ CompositorParent::CompositorParent(nsIWidget* aWidget,
mApzcTreeManager = new APZCTreeManager();
}
if (gfxPrefs::VsyncAlignedCompositor() && gfxPrefs::HardwareVsyncEnabled()) {
mCompositorVsyncObserver = new CompositorVsyncObserver(this, aWidget);
if (UseVsyncComposition()) {
NS_WARNING("Enabling vsync compositor\n");
mCompositorScheduler = new CompositorVsyncScheduler(this, aWidget);
} else {
mCompositorScheduler = new CompositorSoftwareTimerScheduler(this);
}
gfxPlatform::GetPlatform()->ComputeTileSize();
@@ -490,10 +713,8 @@ CompositorParent::Destroy()
MonitorAutoLock lock(*sIndirectLayerTreesLock);
sIndirectLayerTrees.erase(mRootLayerTreeID);
}
if (mCompositorVsyncObserver) {
mCompositorVsyncObserver->Destroy();
mCompositorVsyncObserver = nullptr;
}
mCompositorScheduler->Destroy();
}
void
@@ -577,17 +798,11 @@ CompositorParent::RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
bool
CompositorParent::RecvFlushRendering()
{
if (mCompositorVsyncObserver && mCompositorVsyncObserver->NeedsComposite()) {
mCompositorVsyncObserver->SetNeedsComposite(false);
CancelCurrentCompositeTask();
ForceComposeToTarget(nullptr);
} else if (mCurrentCompositeTask) {
// If we're waiting to do a composite, then cancel it
// and do it immediately instead.
if (mCompositorScheduler->NeedsComposite())
{
CancelCurrentCompositeTask();
ForceComposeToTarget(nullptr);
}
return true;
}
@@ -700,8 +915,7 @@ CompositorParent::ResumeComposition()
mPaused = false;
mLastCompose = TimeStamp::Now();
CompositeToTarget(nullptr);
mCompositorScheduler->ResumeComposition();
// if anyone's waiting to make sure that composition really got resumed, tell them
lock.NotifyAll();
@@ -718,12 +932,7 @@ CompositorParent::ForceComposition()
void
CompositorParent::CancelCurrentCompositeTask()
{
if (mCompositorVsyncObserver) {
mCompositorVsyncObserver->CancelCurrentCompositeTask();
} else if (mCurrentCompositeTask) {
mCurrentCompositeTask->Cancel();
mCurrentCompositeTask = nullptr;
}
mCompositorScheduler->CancelCurrentCompositeTask();
}
void
@@ -761,6 +970,22 @@ CompositorParent::SchedulePauseOnCompositorThread()
lock.Wait();
}
bool
CompositorParent::ScheduleResumeOnCompositorThread()
{
MonitorAutoLock lock(mResumeCompositionMonitor);
CancelableTask *resumeTask =
NewRunnableMethod(this, &CompositorParent::ResumeComposition);
MOZ_ASSERT(CompositorLoop());
CompositorLoop()->PostTask(FROM_HERE, resumeTask);
// Wait until the resume has actually been processed by the compositor thread
lock.Wait();
return !mPaused;
}
bool
CompositorParent::ScheduleResumeOnCompositorThread(int width, int height)
{
@@ -807,65 +1032,6 @@ CompositorParent::NotifyShadowTreeTransaction(uint64_t aId, bool aIsFirstPaint,
}
}
// Used when layout.frame_rate is -1. Needs to be kept in sync with
// DEFAULT_FRAME_RATE in nsRefreshDriver.cpp.
static const int32_t kDefaultFrameRate = 60;
static int32_t
CalculateCompositionFrameRate()
{
int32_t compositionFrameRatePref = gfxPrefs::LayersCompositionFrameRate();
if (compositionFrameRatePref < 0) {
// Use the same frame rate for composition as for layout.
int32_t layoutFrameRatePref = gfxPrefs::LayoutFrameRate();
if (layoutFrameRatePref < 0) {
// TODO: The main thread frame scheduling code consults the actual
// monitor refresh rate in this case. We should do the same.
return kDefaultFrameRate;
}
return layoutFrameRatePref;
}
return compositionFrameRatePref;
}
void
CompositorParent::ScheduleSoftwareTimerComposition()
{
MOZ_ASSERT(!mCompositorVsyncObserver);
if (mCurrentCompositeTask) {
return;
}
bool initialComposition = mLastCompose.IsNull();
TimeDuration delta;
if (!initialComposition)
delta = TimeStamp::Now() - mLastCompose;
int32_t rate = CalculateCompositionFrameRate();
// If rate == 0 (ASAP mode), minFrameDelta must be 0 so there's no delay.
TimeDuration minFrameDelta = TimeDuration::FromMilliseconds(
rate == 0 ? 0.0 : std::max(0.0, 1000.0 / rate));
mCurrentCompositeTask = NewRunnableMethod(this,
&CompositorParent::CompositeCallback,
TimeStamp::Now());
if (!initialComposition && delta < minFrameDelta) {
TimeDuration delay = minFrameDelta - delta;
#ifdef COMPOSITOR_PERFORMANCE_WARNING
mExpectedComposeStartTime = TimeStamp::Now() + delay;
#endif
ScheduleTask(mCurrentCompositeTask, delay.ToMilliseconds());
} else {
#ifdef COMPOSITOR_PERFORMANCE_WARNING
mExpectedComposeStartTime = TimeStamp::Now();
#endif
ScheduleTask(mCurrentCompositeTask, 0);
}
}
void
CompositorParent::ScheduleComposition()
{
@@ -874,27 +1040,7 @@ CompositorParent::ScheduleComposition()
return;
}
if (mCompositorVsyncObserver) {
mCompositorVsyncObserver->SetNeedsComposite(true);
} else {
ScheduleSoftwareTimerComposition();
}
}
void
CompositorParent::CompositeCallback(TimeStamp aScheduleTime)
{
if (mCompositorVsyncObserver) {
// Align OMTA to vsync time.
// TODO: ensure it aligns with the refresh / start time of
// animations
mLastCompose = aScheduleTime;
} else {
mLastCompose = TimeStamp::Now();
}
mCurrentCompositeTask = nullptr;
CompositeToTarget(nullptr);
mCompositorScheduler->ScheduleComposition();
}
// Go down the composite layer tree, setting properties to match their
@@ -929,7 +1075,7 @@ CompositorParent::CompositeToTarget(DrawTarget* aTarget, const gfx::IntRect* aRe
TimeStamp start = TimeStamp::Now();
#ifdef COMPOSITOR_PERFORMANCE_WARNING
TimeDuration scheduleDelta = TimeStamp::Now() - mExpectedComposeStartTime;
TimeDuration scheduleDelta = TimeStamp::Now() - mCompositorScheduler->GetExpectedComposeStartTime();
if (scheduleDelta > TimeDuration::FromMilliseconds(2) ||
scheduleDelta < TimeDuration::FromMilliseconds(-2)) {
printf_stderr("Compositor: Compose starting off schedule by %4.1f ms\n",
@@ -963,7 +1109,7 @@ CompositorParent::CompositeToTarget(DrawTarget* aTarget, const gfx::IntRect* aRe
mCompositionManager->ComputeRotation();
TimeStamp time = mIsTesting ? mTestTime : mLastCompose;
TimeStamp time = mIsTesting ? mTestTime : mCompositorScheduler->GetLastComposeTime();
bool requestNextFrame = mCompositionManager->TransformShadowTree(time);
if (requestNextFrame) {
ScheduleComposition();
@@ -989,7 +1135,7 @@ CompositorParent::CompositeToTarget(DrawTarget* aTarget, const gfx::IntRect* aRe
}
#ifdef COMPOSITOR_PERFORMANCE_WARNING
TimeDuration executionTime = TimeStamp::Now() - mLastCompose;
TimeDuration executionTime = TimeStamp::Now() - mCompositorScheduler->GetLastComposeTime();
TimeDuration frameBudget = TimeDuration::FromMilliseconds(15);
int32_t frameRate = CalculateCompositionFrameRate();
if (frameRate > 0) {
@@ -1020,9 +1166,7 @@ CompositorParent::ForceComposeToTarget(DrawTarget* aTarget, const gfx::IntRect*
AutoRestore<bool> override(mOverrideComposeReadiness);
mOverrideComposeReadiness = true;
mLastCompose = TimeStamp::Now();
CompositeToTarget(aTarget, aRect);
mCompositorScheduler->ForceComposeToTarget(aTarget, aRect);
}
bool
@@ -1092,26 +1236,6 @@ CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
if (mPaused) {
DidComposite();
}
// When testing we synchronously update the shadow tree with the animated
// values to avoid race conditions when calling GetAnimationTransform etc.
// (since the above SetShadowProperties will remove animation effects).
// However, we only do this update when a composite operation is already
// scheduled in order to better match the behavior under regular sampling
// conditions.
bool needTestComposite = mIsTesting && root &&
(mCurrentCompositeTask ||
(mCompositorVsyncObserver &&
mCompositorVsyncObserver->NeedsComposite()));
if (needTestComposite) {
AutoResolveRefLayers resolve(mCompositionManager);
bool requestNextFrame =
mCompositionManager->TransformShadowTree(mTestTime);
if (!requestNextFrame) {
CancelCurrentCompositeTask();
// Pretend we composited in case someone is waiting for this event.
DidComposite();
}
}
}
mLayerManager->NotifyShadowTreeTransaction();
}
@@ -1133,9 +1257,8 @@ CompositorParent::SetTestSampleTime(LayerTransactionParent* aLayerTree,
mIsTesting = true;
mTestTime = aTime;
bool testComposite = mCompositionManager && (mCurrentCompositeTask ||
(mCompositorVsyncObserver
&& mCompositorVsyncObserver->NeedsComposite()));
bool testComposite = mCompositionManager &&
mCompositorScheduler->NeedsComposite();
// Update but only if we were already scheduled to animate
if (testComposite) {
@@ -1157,6 +1280,30 @@ CompositorParent::LeaveTestMode(LayerTransactionParent* aLayerTree)
mIsTesting = false;
}
void
CompositorParent::ApplyAsyncProperties(LayerTransactionParent* aLayerTree)
{
// NOTE: This should only be used for testing. For example, when mIsTesting is
// true or when called from test-only methods like
// LayerTransactionParent::RecvGetAnimationTransform.
// Synchronously update the layer tree
if (aLayerTree->GetRoot()) {
AutoResolveRefLayers resolve(mCompositionManager);
SetShadowProperties(mLayerManager->GetRoot());
TimeStamp time = mIsTesting ? mTestTime : mCompositorScheduler->GetLastComposeTime();
bool requestNextFrame =
mCompositionManager->TransformShadowTree(time,
AsyncCompositionManager::TransformsToSkip::APZ);
if (!requestNextFrame) {
CancelCurrentCompositeTask();
// Pretend we composited in case someone is waiting for this event.
DidComposite();
}
}
}
bool
CompositorParent::RecvRequestOverfill()
{
@@ -1462,6 +1609,7 @@ InsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp)
/*static */ void
CompositorParent::PostInsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp)
{
// Called in the vsync thread
if (profiler_is_active() && sCompositorThreadHolder) {
CompositorLoop()->PostTask(FROM_HERE,
NewRunnableFunction(InsertVsyncProfilerMarker, aVsyncTimestamp));
@@ -1565,6 +1713,8 @@ public:
virtual bool SetTestSampleTime(LayerTransactionParent* aLayerTree,
const TimeStamp& aTime) override;
virtual void LeaveTestMode(LayerTransactionParent* aLayerTree) override;
virtual void ApplyAsyncProperties(LayerTransactionParent* aLayerTree)
override;
virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree,
APZTestData* aOutData) override;
virtual void SetConfirmedTargetAPZC(const LayerTransactionParent* aLayerTree,
@@ -1811,8 +1961,7 @@ UpdatePluginWindowState(uint64_t aId)
}
bool shouldComposePlugin = !!lts.mRoot &&
!!lts.mRoot->GetParent() &&
lts.mUpdatedPluginDataAvailable;
!!lts.mRoot->GetParent();
bool shouldHidePlugin = (!lts.mRoot ||
!lts.mRoot->GetParent()) &&
@@ -1825,6 +1974,7 @@ UpdatePluginWindowState(uint64_t aId)
// calculating clipping.
nsTArray<uintptr_t> aVisibleIdList;
unused << lts.mParent->SendUpdatePluginVisibility(aVisibleIdList);
lts.mUpdatedPluginDataAvailable = false;
return;
}
@@ -1942,6 +2092,22 @@ CrossProcessCompositorParent::LeaveTestMode(LayerTransactionParent* aLayerTree)
state->mParent->LeaveTestMode(aLayerTree);
}
void
CrossProcessCompositorParent::ApplyAsyncProperties(
LayerTransactionParent* aLayerTree)
{
uint64_t id = aLayerTree->GetId();
MOZ_ASSERT(id != 0);
const CompositorParent::LayerTreeState* state =
CompositorParent::GetIndirectShadowTree(id);
if (!state) {
return;
}
MOZ_ASSERT(state->mParent);
state->mParent->ApplyAsyncProperties(aLayerTree);
}
void
CrossProcessCompositorParent::GetAPZTestData(const LayerTransactionParent* aLayerTree,
APZTestData* aOutData)
@@ -1959,16 +2125,13 @@ CrossProcessCompositorParent::SetConfirmedTargetAPZC(const LayerTransactionParen
{
uint64_t id = aLayerTree->GetId();
MOZ_ASSERT(id != 0);
CompositorParent* parent = nullptr;
{
MonitorAutoLock lock(*sIndirectLayerTreesLock);
const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(id);
if (!state || !state->mParent) {
return;
}
parent = state->mParent;
const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(id);
if (!state) {
return;
}
parent->SetConfirmedTargetAPZC(aLayerTree, aInputBlockId, aTargets);
MOZ_ASSERT(state->mParent);
state->mParent->SetConfirmedTargetAPZC(aLayerTree, aInputBlockId, aTargets);
}
AsyncCompositionManager*
+89 -21
View File
@@ -88,42 +88,114 @@ private:
friend class CompositorParent;
};
class CompositorScheduler
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorScheduler)
explicit CompositorScheduler(CompositorParent* aCompositorParent);
virtual void ScheduleComposition() = 0;
virtual void CancelCurrentCompositeTask();
virtual bool NeedsComposite() = 0;
virtual void Composite(TimeStamp aTimestamp) = 0;
virtual void ScheduleTask(CancelableTask*, int);
virtual void ResumeComposition();
virtual void ForceComposeToTarget(gfx::DrawTarget* aTarget, const nsIntRect* aRect);
virtual void ComposeToTarget(gfx::DrawTarget* aTarget, const nsIntRect* aRect = nullptr);
virtual void Destroy();
const TimeStamp& GetLastComposeTime()
{
return mLastCompose;
}
#ifdef COMPOSITOR_PERFORMANCE_WARNING
const TimeStamp& GetExpectedComposeStartTime()
{
return mExpectedComposeStartTime;
}
#endif
protected:
virtual ~CompositorScheduler();
CompositorParent* mCompositorParent;
TimeStamp mLastCompose;
CancelableTask* mCurrentCompositeTask;
#ifdef COMPOSITOR_PERFORMANCE_WARNING
TimeStamp mExpectedComposeStartTime;
#endif
};
class CompositorSoftwareTimerScheduler final : public CompositorScheduler
{
public:
explicit CompositorSoftwareTimerScheduler(CompositorParent* aCompositorParent);
// from CompositorScheduler
virtual void ScheduleComposition() override;
virtual bool NeedsComposite() override;
virtual void Composite(TimeStamp aTimestamp) override;
void CallComposite();
private:
virtual ~CompositorSoftwareTimerScheduler();
};
/**
* Manages the vsync (de)registration and tracking on behalf of the
* compositor when it need to paint.
* Turns vsync notifications into scheduled composites.
**/
class CompositorVsyncObserver final : public VsyncObserver
class CompositorVsyncScheduler final : public CompositorScheduler
{
friend class CompositorParent;
public:
explicit CompositorVsyncObserver(CompositorParent* aCompositorParent, nsIWidget* aWidget);
virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) override;
explicit CompositorVsyncScheduler(CompositorParent* aCompositorParent, nsIWidget* aWidget);
bool NotifyVsync(TimeStamp aVsyncTimestamp);
void SetNeedsComposite(bool aSchedule);
bool NeedsComposite();
void CancelCurrentCompositeTask();
void Destroy();
void OnForceComposeToTarget();
// from CompositorScheduler
virtual void ScheduleComposition() override;
virtual void CancelCurrentCompositeTask() override;
virtual bool NeedsComposite() override;
virtual void Composite(TimeStamp aVsyncTimestamp) override;
virtual void ForceComposeToTarget(gfx::DrawTarget* aTarget, const nsIntRect* aRect) override;
virtual void Destroy() override;
private:
virtual ~CompositorVsyncObserver();
virtual ~CompositorVsyncScheduler();
void Composite(TimeStamp aVsyncTimestamp);
void NotifyCompositeTaskExecuted();
void ObserveVsync();
void UnobserveVsync();
void DispatchTouchEvents(TimeStamp aVsyncTimestamp);
void CancelCurrentSetNeedsCompositeTask();
class Observer final : public VsyncObserver
{
public:
explicit Observer(CompositorVsyncScheduler* aOwner);
virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) override;
void Destroy();
private:
virtual ~Observer();
Mutex mMutex;
// Hold raw pointer to avoid mutual reference.
CompositorVsyncScheduler* mOwner;
};
bool mNeedsComposite;
bool mIsObservingVsync;
int32_t mVsyncNotificationsSkipped;
nsRefPtr<CompositorParent> mCompositorParent;
CompositorParent* mCompositorParent;
nsRefPtr<CompositorVsyncDispatcher> mCompositorVsyncDispatcher;
nsRefPtr<CompositorVsyncScheduler::Observer> mVsyncObserver;
mozilla::Monitor mCurrentCompositeTaskMonitor;
CancelableTask* mCurrentCompositeTask;
mozilla::Monitor mSetNeedsCompositeMonitor;
CancelableTask* mSetNeedsCompositeTask;
@@ -144,7 +216,7 @@ class CompositorParent final : public PCompositorParent,
public ShadowLayersManager
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorParent)
friend class CompositorVsyncObserver;
friend class CompositorScheduler;
public:
explicit CompositorParent(nsIWidget* aWidget,
@@ -192,6 +264,8 @@ public:
virtual bool SetTestSampleTime(LayerTransactionParent* aLayerTree,
const TimeStamp& aTime) override;
virtual void LeaveTestMode(LayerTransactionParent* aLayerTree) override;
virtual void ApplyAsyncProperties(LayerTransactionParent* aLayerTree)
override;
virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree,
APZTestData* aOutData) override;
virtual void SetConfirmedTargetAPZC(const LayerTransactionParent* aLayerTree,
@@ -222,6 +296,7 @@ public:
* Returns true if a surface was obtained and the resume succeeded; false
* otherwise.
*/
bool ScheduleResumeOnCompositorThread();
bool ScheduleResumeOnCompositorThread(int width, int height);
virtual void ScheduleComposition();
@@ -358,7 +433,6 @@ protected:
bool* aSuccess) override;
virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) override;
virtual void ScheduleTask(CancelableTask*, int);
void CompositeCallback(TimeStamp aScheduleTime);
void CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr);
void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr);
@@ -370,7 +444,6 @@ protected:
void ResumeCompositionAndResize(int width, int height);
void ForceComposition();
void CancelCurrentCompositeTask();
void ScheduleSoftwareTimerComposition();
/**
* Add a compositor to the global compositor map.
@@ -393,13 +466,8 @@ protected:
nsRefPtr<Compositor> mCompositor;
RefPtr<AsyncCompositionManager> mCompositionManager;
nsIWidget* mWidget;
CancelableTask *mCurrentCompositeTask;
TimeStamp mLastCompose;
TimeStamp mTestTime;
bool mIsTesting;
#ifdef COMPOSITOR_PERFORMANCE_WARNING
TimeStamp mExpectedComposeStartTime;
#endif
uint64_t mPendingTransaction;
@@ -420,7 +488,7 @@ protected:
nsRefPtr<APZCTreeManager> mApzcTreeManager;
nsRefPtr<CompositorThreadHolder> mCompositorThreadHolder;
nsRefPtr<CompositorVsyncObserver> mCompositorVsyncObserver;
nsRefPtr<CompositorScheduler> mCompositorScheduler;
DISALLOW_EVIL_CONSTRUCTORS(CompositorParent);
};
+111
View File
@@ -0,0 +1,111 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* 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/. */
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
#pragma GCC visibility push(default)
#include "sync/sync.h" // for sync_merge
#pragma GCC visibility pop
#endif
#include "FenceUtils.h"
using namespace mozilla::layers;
namespace IPC {
void
ParamTraits<FenceHandle>::Write(Message* aMsg,
const paramType& aParam)
{
FenceHandle handle = aParam;
MOZ_ASSERT(handle.IsValid());
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
nsRefPtr<FenceHandle::FdObj> fence = handle.GetAndResetFdObj();
aMsg->WriteFileDescriptor(base::FileDescriptor(fence->GetAndResetFd(), true));
#endif
}
bool
ParamTraits<FenceHandle>::Read(const Message* aMsg,
void** aIter, paramType* aResult)
{
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
base::FileDescriptor fd;
if (aMsg->ReadFileDescriptor(aIter, &fd)) {
aResult->Merge(FenceHandle(new FenceHandle::FdObj(fd.fd)));
}
#endif
return true;
}
} // namespace IPC
namespace mozilla {
namespace layers {
FenceHandle::FenceHandle()
: mFence(new FdObj())
{
}
FenceHandle::FenceHandle(FdObj* aFdObj)
: mFence(aFdObj)
{
MOZ_ASSERT(aFdObj);
}
void
FenceHandle::Merge(const FenceHandle& aFenceHandle)
{
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
if (!aFenceHandle.IsValid()) {
return;
}
if (!IsValid()) {
mFence = aFenceHandle.mFence;
} else {
int result = sync_merge("FenceHandle", mFence->mFd, aFenceHandle.mFence->mFd);
if (result == -1) {
mFence = aFenceHandle.mFence;
} else {
mFence = new FdObj(result);
}
}
#endif
}
void
FenceHandle::TransferToAnotherFenceHandle(FenceHandle& aFenceHandle)
{
aFenceHandle.mFence = this->GetAndResetFdObj();
}
already_AddRefed<FenceHandle::FdObj>
FenceHandle::GetAndResetFdObj()
{
nsRefPtr<FdObj> fence = mFence;
mFence = new FdObj();
return fence.forget();
}
already_AddRefed<FenceHandle::FdObj>
FenceHandle::GetDupFdObj()
{
nsRefPtr<FdObj> fdObj;
if (IsValid()) {
fdObj = new FenceHandle::FdObj(dup(mFence->mFd));
} else {
fdObj = new FenceHandle::FdObj();
}
return fdObj.forget();
}
} // namespace layers
} // namespace mozilla
+51 -32
View File
@@ -9,56 +9,75 @@
#define IPC_FencerUtils_h
#include "ipc/IPCMessageUtils.h"
#include "mozilla/RefPtr.h" // for nsRefPtr
/**
* FenceHandle is used for delivering Fence object via ipc.
*/
#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
# include "mozilla/layers/FenceUtilsGonk.h"
#else
namespace mozilla {
namespace layers {
struct FenceHandleFromChild;
class FenceHandle {
public:
class FdObj {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FdObj)
friend class FenceHandle;
public:
FdObj()
: mFd(-1) {}
explicit FdObj(int aFd)
: mFd(aFd) {}
int GetAndResetFd()
{
int fd = mFd;
mFd = -1;
return fd;
}
struct FenceHandle {
FenceHandle() {}
explicit FenceHandle(const FenceHandleFromChild& aFenceHandle) {}
bool operator==(const FenceHandle&) const { return false; }
bool IsValid() const { return false; }
void Merge(const FenceHandle& aFenceHandle) {}
};
private:
virtual ~FdObj() {
if (mFd != -1) {
close(mFd);
}
}
struct FenceHandleFromChild {
FenceHandleFromChild() {}
explicit FenceHandleFromChild(const FenceHandle& aFence) {}
bool operator==(const FenceHandle&) const { return false; }
bool operator==(const FenceHandleFromChild&) const { return false; }
bool IsValid() const { return false; }
int mFd;
};
FenceHandle();
explicit FenceHandle(FdObj* aFdObj);
bool operator==(const FenceHandle& aOther) const {
return mFence.get() == aOther.mFence.get();
}
bool IsValid() const
{
return (mFence->mFd != -1);
}
void Merge(const FenceHandle& aFenceHandle);
void TransferToAnotherFenceHandle(FenceHandle& aFenceHandle);
already_AddRefed<FdObj> GetAndResetFdObj();
already_AddRefed<FdObj> GetDupFdObj();
private:
nsRefPtr<FdObj> mFence;
};
} // namespace layers
} // namespace mozilla
#endif // MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
namespace IPC {
#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
#else
template <>
struct ParamTraits<mozilla::layers::FenceHandle> {
typedef mozilla::layers::FenceHandle paramType;
static void Write(Message*, const paramType&) {}
static bool Read(const Message*, void**, paramType*) { return false; }
};
template <>
struct ParamTraits<mozilla::layers::FenceHandleFromChild> {
typedef mozilla::layers::FenceHandleFromChild paramType;
static void Write(Message*, const paramType&) {}
static bool Read(const Message*, void**, paramType*) { return false; }
static void Write(Message* aMsg, const paramType& aParam);
static bool Read(const Message* aMsg, void** aIter, paramType* aResult);
};
#endif // MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
} // namespace IPC
-259
View File
@@ -1,259 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* 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 "mozilla/unused.h"
#include "nsXULAppAPI.h"
#include "FenceUtilsGonk.h"
using namespace android;
using namespace mozilla::layers;
using base::FileDescriptor;
namespace IPC {
void
ParamTraits<FenceHandle>::Write(Message* aMsg,
const paramType& aParam)
{
#if ANDROID_VERSION >= 19
sp<Fence> flattenable = aParam.mFence;
#else
Flattenable *flattenable = aParam.mFence.get();
#endif
size_t nbytes = flattenable->getFlattenedSize();
size_t nfds = flattenable->getFdCount();
char data[nbytes];
int fds[nfds];
#if ANDROID_VERSION >= 19
// Make a copy of "data" and "fds" for flatten() to avoid casting problem
void *pdata = (void *)data;
int *pfds = fds;
flattenable->flatten(pdata, nbytes, pfds, nfds);
// In Kitkat, flatten() will change the value of nbytes and nfds, which dues
// to multiple parcelable object consumption. The actual size and fd count
// which returned by getFlattenedSize() and getFdCount() are not changed.
// So we change nbytes and nfds back by call corresponding calls.
nbytes = flattenable->getFlattenedSize();
nfds = flattenable->getFdCount();
#else
flattenable->flatten(data, nbytes, fds, nfds);
#endif
aMsg->WriteSize(nbytes);
aMsg->WriteSize(nfds);
aMsg->WriteBytes(data, nbytes);
for (size_t n = 0; n < nfds; ++n) {
// These buffers can't die in transit because they're created
// synchonously and the parent-side buffer can only be dropped if
// there's a crash.
aMsg->WriteFileDescriptor(FileDescriptor(fds[n], false));
}
}
bool
ParamTraits<FenceHandle>::Read(const Message* aMsg,
void** aIter, paramType* aResult)
{
size_t nbytes;
size_t nfds;
const char* data;
if (!aMsg->ReadSize(aIter, &nbytes) ||
!aMsg->ReadSize(aIter, &nfds) ||
!aMsg->ReadBytes(aIter, &data, nbytes)) {
return false;
}
// Check if nfds is correct.
// aMsg->num_fds() could include fds of another ParamTraits<>s.
if (nfds > aMsg->num_fds()) {
return false;
}
int fds[nfds];
for (size_t n = 0; n < nfds; ++n) {
FileDescriptor fd;
if (!aMsg->ReadFileDescriptor(aIter, &fd)) {
return false;
}
// If the GraphicBuffer was shared cross-process, SCM_RIGHTS does
// the right thing and dup's the fd. If it's shared cross-thread,
// SCM_RIGHTS doesn't dup the fd. That's surprising, but we just
// deal with it here. NB: only the "default" (master) process can
// alloc gralloc buffers.
bool sameProcess = (XRE_GetProcessType() == GeckoProcessType_Default);
int dupFd = sameProcess ? dup(fd.fd) : fd.fd;
fds[n] = dupFd;
}
sp<Fence> buffer(new Fence());
#if ANDROID_VERSION >= 19
// Make a copy of "data" and "fds" for unflatten() to avoid casting problem
void const *pdata = (void const *)data;
int const *pfds = fds;
if (NO_ERROR == buffer->unflatten(pdata, nbytes, pfds, nfds)) {
#else
Flattenable *flattenable = buffer.get();
if (NO_ERROR == flattenable->unflatten(data, nbytes, fds, nfds)) {
#endif
aResult->mFence = buffer;
return true;
}
return false;
}
void
ParamTraits<FenceHandleFromChild>::Write(Message* aMsg,
const paramType& aParam)
{
#if ANDROID_VERSION >= 19
sp<Fence> flattenable = aParam.mFence;
#else
Flattenable *flattenable = aParam.mFence.get();
#endif
size_t nbytes = flattenable->getFlattenedSize();
size_t nfds = flattenable->getFdCount();
char data[nbytes];
int fds[nfds];
#if ANDROID_VERSION >= 19
// Make a copy of "data" and "fds" for flatten() to avoid casting problem
void *pdata = (void *)data;
int *pfds = fds;
flattenable->flatten(pdata, nbytes, pfds, nfds);
// In Kitkat, flatten() will change the value of nbytes and nfds, which dues
// to multiple parcelable object consumption. The actual size and fd count
// which returned by getFlattenedSize() and getFdCount() are not changed.
// So we change nbytes and nfds back by call corresponding calls.
nbytes = flattenable->getFlattenedSize();
nfds = flattenable->getFdCount();
#else
flattenable->flatten(data, nbytes, fds, nfds);
#endif
aMsg->WriteSize(nbytes);
aMsg->WriteSize(nfds);
aMsg->WriteBytes(data, nbytes);
for (size_t n = 0; n < nfds; ++n) {
// If the Fence was shared cross-process, SCM_RIGHTS does
// the right thing and dup's the fd. If it's shared cross-thread,
// SCM_RIGHTS doesn't dup the fd. That's surprising, but we just
// deal with it here. NB: only the "default" (master) process can
// alloc gralloc buffers.
bool sameProcess = (XRE_GetProcessType() == GeckoProcessType_Default);
int dupFd = sameProcess ? dup(fds[n]) : fds[n];
//int dupFd = fds[n];
// These buffers can't die in transit because they're created
// synchonously and the parent-side buffer can only be dropped if
// there's a crash.
aMsg->WriteFileDescriptor(FileDescriptor(dupFd, false));
}
}
bool
ParamTraits<FenceHandleFromChild>::Read(const Message* aMsg,
void** aIter, paramType* aResult)
{
size_t nbytes;
size_t nfds;
const char* data;
if (!aMsg->ReadSize(aIter, &nbytes) ||
!aMsg->ReadSize(aIter, &nfds) ||
!aMsg->ReadBytes(aIter, &data, nbytes)) {
return false;
}
// Check if nfds is correct.
// aMsg->num_fds() could include fds of another ParamTraits<>s.
if (nfds > aMsg->num_fds()) {
return false;
}
int fds[nfds];
for (size_t n = 0; n < nfds; ++n) {
FileDescriptor fd;
if (!aMsg->ReadFileDescriptor(aIter, &fd)) {
return false;
}
fds[n] = fd.fd;
}
sp<Fence> buffer(new Fence());
#if ANDROID_VERSION >= 19
// Make a copy of "data" and "fds" for unflatten() to avoid casting problem
void const *pdata = (void const *)data;
int const *pfds = fds;
if (NO_ERROR == buffer->unflatten(pdata, nbytes, pfds, nfds)) {
#else
Flattenable *flattenable = buffer.get();
if (NO_ERROR == flattenable->unflatten(data, nbytes, fds, nfds)) {
#endif
aResult->mFence = buffer;
return true;
}
return false;
}
} // namespace IPC
namespace mozilla {
namespace layers {
FenceHandle::FenceHandle(const sp<Fence>& aFence)
: mFence(aFence)
{
}
FenceHandle::FenceHandle(const FenceHandleFromChild& aFenceHandle) {
mFence = aFenceHandle.mFence;
}
void
FenceHandle::Merge(const FenceHandle& aFenceHandle)
{
if (!aFenceHandle.IsValid()) {
return;
}
if (!IsValid()) {
mFence = aFenceHandle.mFence;
} else {
android::sp<android::Fence> mergedFence = android::Fence::merge(
android::String8::format("FenceHandle"),
mFence, aFenceHandle.mFence);
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.
mFence = aFenceHandle.mFence;
return;
}
mFence = mergedFence;
}
}
FenceHandleFromChild::FenceHandleFromChild(const sp<Fence>& aFence)
: mFence(aFence)
{
}
} // namespace layers
} // namespace mozilla
-94
View File
@@ -1,94 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* 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/. */
#ifndef mozilla_layers_FenceUtilsGonk_h
#define mozilla_layers_FenceUtilsGonk_h
#include <unistd.h>
#include <ui/Fence.h>
#include "ipc/IPCMessageUtils.h"
namespace mozilla {
namespace layers {
struct FenceHandleFromChild;
struct FenceHandle {
typedef android::Fence Fence;
FenceHandle()
{ }
explicit FenceHandle(const android::sp<Fence>& aFence);
explicit FenceHandle(const FenceHandleFromChild& aFenceHandle);
bool operator==(const FenceHandle& aOther) const {
return mFence.get() == aOther.mFence.get();
}
bool IsValid() const
{
return mFence.get() && mFence->isValid();
}
void Merge(const FenceHandle& aFenceHandle);
android::sp<Fence> mFence;
};
struct FenceHandleFromChild {
typedef android::Fence Fence;
FenceHandleFromChild()
{ }
explicit FenceHandleFromChild(const android::sp<Fence>& aFence);
explicit FenceHandleFromChild(const FenceHandle& aFence) {
mFence = aFence.mFence;
}
bool operator==(const FenceHandle& aOther) const {
return mFence.get() == aOther.mFence.get();
}
bool operator==(const FenceHandleFromChild& aOther) const {
return mFence.get() == aOther.mFence.get();
}
bool IsValid() const
{
return mFence.get() && mFence->isValid();
}
android::sp<Fence> mFence;
};
} // namespace layers
} // namespace mozilla
namespace IPC {
template <>
struct ParamTraits<mozilla::layers::FenceHandle> {
typedef mozilla::layers::FenceHandle paramType;
static void Write(Message* aMsg, const paramType& aParam);
static bool Read(const Message* aMsg, void** aIter, paramType* aResult);
};
template <>
struct ParamTraits<mozilla::layers::FenceHandleFromChild> {
typedef mozilla::layers::FenceHandleFromChild paramType;
static void Write(Message* aMsg, const paramType& aParam);
static bool Read(const Message* aMsg, void** aIter, paramType* aResult);
};
} // namespace IPC
#endif // mozilla_layers_FenceUtilsGonk_h
+1
View File
@@ -158,6 +158,7 @@ public:
virtual bool IPCOpen() const { return true; }
virtual bool IsSameProcess() const = 0;
virtual base::ProcessId ParentPid() const { return base::ProcessId(); }
virtual bool IsImageBridgeChild() const { return false; }
+4 -59
View File
@@ -111,15 +111,11 @@ ImageBridgeChild::UseTexture(CompositableClient* aCompositable,
MOZ_ASSERT(aTexture);
MOZ_ASSERT(aCompositable->GetIPDLActor());
MOZ_ASSERT(aTexture->GetIPDLActor());
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
FenceHandle handle = aTexture->GetAcquireFenceHandle();
if (handle.IsValid()) {
RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(handle);
SendFenceHandle(tracker, aTexture->GetIPDLActor(), handle);
}
#endif
FenceHandle fence = aTexture->GetAcquireFenceHandle();
mTxn->AddNoSwapEdit(OpUseTexture(nullptr, aCompositable->GetIPDLActor(),
nullptr, aTexture->GetIPDLActor()));
nullptr, aTexture->GetIPDLActor(),
fence.IsValid() ? MaybeFence(fence) : MaybeFence(null_t())));
}
void
@@ -149,35 +145,6 @@ ImageBridgeChild::UseOverlaySource(CompositableClient* aCompositable,
}
#endif
void
ImageBridgeChild::UpdatedTexture(CompositableClient* aCompositable,
TextureClient* aTexture,
nsIntRegion* aRegion)
{
MOZ_ASSERT(aCompositable);
MOZ_ASSERT(aTexture);
MOZ_ASSERT(aCompositable->GetIPDLActor());
MOZ_ASSERT(aTexture->GetIPDLActor());
MaybeRegion region = aRegion ? MaybeRegion(*aRegion)
: MaybeRegion(null_t());
mTxn->AddNoSwapEdit(OpUpdateTexture(nullptr, aCompositable->GetIPDLActor(),
nullptr, aTexture->GetIPDLActor(),
region));
}
void
ImageBridgeChild::SendFenceHandle(AsyncTransactionTracker* aTracker,
PTextureChild* aTexture,
const FenceHandle& aFence)
{
HoldUntilComplete(aTracker);
InfallibleTArray<AsyncChildMessageData> messages;
messages.AppendElement(OpDeliverFenceFromChild(aTracker->GetId(),
nullptr, aTexture,
FenceHandleFromChild(aFence)));
SendChildAsyncMessages(messages);
}
void
ImageBridgeChild::UpdatePictureRect(CompositableClient* aCompositable,
const gfx::IntRect& aRect)
@@ -849,7 +816,6 @@ ImageBridgeChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageDat
if (texture) {
texture->SetReleaseFenceHandle(fence);
}
HoldTransactionsToRespond(op.transactionId());
break;
}
case AsyncParentMessageData::TOpDeliverFenceToTracker: {
@@ -859,15 +825,6 @@ ImageBridgeChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageDat
AsyncTransactionTrackersHolder::SetReleaseFenceHandle(fence,
op.destHolderId(),
op.destTransactionId());
// Send back a response.
InfallibleTArray<AsyncChildMessageData> replies;
replies.AppendElement(OpReplyDeliverFence(op.transactionId()));
SendChildAsyncMessages(replies);
break;
}
case AsyncParentMessageData::TOpReplyDeliverFence: {
const OpReplyDeliverFence& op = message.get_OpReplyDeliverFence();
TransactionCompleteted(op.transactionId());
break;
}
case AsyncParentMessageData::TOpReplyRemoveTexture: {
@@ -962,18 +919,6 @@ bool ImageBridgeChild::IsSameProcess() const
void ImageBridgeChild::SendPendingAsyncMessges()
{
if (!IsCreated() ||
mTransactionsToRespond.empty()) {
return;
}
// Send OpReplyDeliverFence messages
InfallibleTArray<AsyncChildMessageData> replies;
replies.SetCapacity(mTransactionsToRespond.size());
for (size_t i = 0; i < mTransactionsToRespond.size(); i++) {
replies.AppendElement(OpReplyDeliverFence(mTransactionsToRespond[i]));
}
mTransactionsToRespond.clear();
SendChildAsyncMessages(replies);
}
} // namespace layers
-11
View File
@@ -205,13 +205,6 @@ public:
virtual void Connect(CompositableClient* aCompositable) override;
/**
* See CompositableForwarder::UpdatedTexture
*/
virtual void UpdatedTexture(CompositableClient* aCompositable,
TextureClient* aTexture,
nsIntRegion* aRegion) override;
virtual bool IsImageBridgeChild() const override { return true; }
/**
@@ -227,10 +220,6 @@ public:
const OverlaySource& aOverlay) override;
#endif
virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
PTextureChild* aTexture,
const FenceHandle& aFence) override;
virtual void RemoveTextureFromCompositable(CompositableClient* aCompositable,
TextureClient* aTexture) override;
+20 -80
View File
@@ -103,7 +103,7 @@ public:
~AutoImageBridgeParentAsyncMessageSender()
{
mImageBridge->SendPendingAsyncMessges();
mImageBridge->SendPendingAsyncMessages();
}
private:
ImageBridgeParent* mImageBridge;
@@ -242,19 +242,6 @@ ImageBridgeParent::DeallocPTextureParent(PTextureParent* actor)
return TextureHost::DestroyIPDLActor(actor);
}
void
ImageBridgeParent::SendFenceHandle(AsyncTransactionTracker* aTracker,
PTextureParent* aTexture,
const FenceHandle& aFence)
{
HoldUntilComplete(aTracker);
InfallibleTArray<AsyncParentMessageData> messages;
messages.AppendElement(OpDeliverFence(aTracker->GetId(),
aTexture, nullptr,
aFence));
mozilla::unused << SendParentAsyncMessages(messages);
}
void
ImageBridgeParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage)
{
@@ -264,41 +251,6 @@ ImageBridgeParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageDat
bool
ImageBridgeParent::RecvChildAsyncMessages(InfallibleTArray<AsyncChildMessageData>&& aMessages)
{
for (AsyncChildMessageArray::index_type i = 0; i < aMessages.Length(); ++i) {
const AsyncChildMessageData& message = aMessages[i];
switch (message.type()) {
case AsyncChildMessageData::TOpDeliverFenceFromChild: {
const OpDeliverFenceFromChild& op = message.get_OpDeliverFenceFromChild();
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
FenceHandle fence = FenceHandle(op.fence());
PTextureParent* parent = op.textureParent();
TextureHostOGL* hostOGL = nullptr;
RefPtr<TextureHost> texture = TextureHost::AsTextureHost(parent);
if (texture) {
hostOGL = texture->AsHostOGL();
}
if (hostOGL) {
hostOGL->SetAcquireFence(fence.mFence);
}
#endif
// Send back a response.
InfallibleTArray<AsyncParentMessageData> replies;
replies.AppendElement(OpReplyDeliverFence(op.transactionId()));
mozilla::unused << SendParentAsyncMessages(replies);
break;
}
case AsyncChildMessageData::TOpReplyDeliverFence: {
const OpReplyDeliverFence& op = message.get_OpReplyDeliverFence();
TransactionCompleteted(op.transactionId());
break;
}
default:
NS_ERROR("unknown AsyncChildMessageData type");
return false;
}
}
return true;
}
@@ -373,10 +325,7 @@ ImageBridgeParent::SendFenceHandleIfPresent(PTextureParent* aTexture,
if (aCompositableHost && aCompositableHost->GetCompositor()) {
FenceHandle fence = aCompositableHost->GetCompositor()->GetReleaseFence();
if (fence.IsValid()) {
RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
HoldUntilComplete(tracker);
mPendingAsyncMessage.push_back(OpDeliverFence(tracker->GetId(),
aTexture, nullptr,
mPendingAsyncMessage.push_back(OpDeliverFence(aTexture, nullptr,
fence));
}
}
@@ -384,19 +333,16 @@ ImageBridgeParent::SendFenceHandleIfPresent(PTextureParent* aTexture,
// Send a ReleaseFence that is set by HwcComposer2D.
FenceHandle fence = texture->GetAndResetReleaseFenceHandle();
if (fence.IsValid()) {
RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
HoldUntilComplete(tracker);
mPendingAsyncMessage.push_back(OpDeliverFence(tracker->GetId(),
aTexture, nullptr,
mPendingAsyncMessage.push_back(OpDeliverFence(aTexture, nullptr,
fence));
}
}
void
ImageBridgeParent::SendFenceHandleToTrackerIfPresent(uint64_t aDestHolderId,
uint64_t aTransactionId,
PTextureParent* aTexture,
CompositableHost* aCompositableHost)
ImageBridgeParent::AppendDeliverFenceMessage(uint64_t aDestHolderId,
uint64_t aTransactionId,
PTextureParent* aTexture,
CompositableHost* aCompositableHost)
{
RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
if (!texture) {
@@ -407,10 +353,7 @@ ImageBridgeParent::SendFenceHandleToTrackerIfPresent(uint64_t aDestHolderId,
if (aCompositableHost && aCompositableHost->GetCompositor()) {
FenceHandle fence = aCompositableHost->GetCompositor()->GetReleaseFence();
if (fence.IsValid()) {
RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
HoldUntilComplete(tracker);
mPendingAsyncMessage.push_back(OpDeliverFenceToTracker(tracker->GetId(),
aDestHolderId,
mPendingAsyncMessage.push_back(OpDeliverFenceToTracker(aDestHolderId,
aTransactionId,
fence));
}
@@ -419,40 +362,37 @@ ImageBridgeParent::SendFenceHandleToTrackerIfPresent(uint64_t aDestHolderId,
// Send a ReleaseFence that is set by HwcComposer2D.
FenceHandle fence = texture->GetAndResetReleaseFenceHandle();
if (fence.IsValid()) {
RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
HoldUntilComplete(tracker);
mPendingAsyncMessage.push_back(OpDeliverFenceToTracker(tracker->GetId(),
aDestHolderId,
mPendingAsyncMessage.push_back(OpDeliverFenceToTracker(aDestHolderId,
aTransactionId,
fence));
}
}
/*static*/ void
ImageBridgeParent::SendFenceHandleToTrackerIfPresent(base::ProcessId aChildProcessId,
uint64_t aDestHolderId,
uint64_t aTransactionId,
PTextureParent* aTexture,
CompositableHost* aCompositableHost)
ImageBridgeParent::AppendDeliverFenceMessage(base::ProcessId aChildProcessId,
uint64_t aDestHolderId,
uint64_t aTransactionId,
PTextureParent* aTexture,
CompositableHost* aCompositableHost)
{
ImageBridgeParent* imageBridge = ImageBridgeParent::GetInstance(aChildProcessId);
if (!imageBridge) {
return;
}
imageBridge->SendFenceHandleToTrackerIfPresent(aDestHolderId,
aTransactionId,
aTexture,
aCompositableHost);
imageBridge->AppendDeliverFenceMessage(aDestHolderId,
aTransactionId,
aTexture,
aCompositableHost);
}
/*static*/ void
ImageBridgeParent::SendPendingAsyncMessges(base::ProcessId aChildProcessId)
ImageBridgeParent::SendPendingAsyncMessages(base::ProcessId aChildProcessId)
{
ImageBridgeParent* imageBridge = ImageBridgeParent::GetInstance(aChildProcessId);
if (!imageBridge) {
return;
}
imageBridge->SendPendingAsyncMessges();
imageBridge->SendPendingAsyncMessages();
}
} // namespace layers
+11 -15
View File
@@ -59,10 +59,6 @@ public:
virtual void SendFenceHandleIfPresent(PTextureParent* aTexture,
CompositableHost* aCompositableHost) override;
virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
PTextureParent* aTexture,
const FenceHandle& aFence) override;
virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
virtual base::ProcessId GetChildProcessId() override
@@ -123,19 +119,19 @@ public:
static void ReplyRemoveTexture(base::ProcessId aChildProcessId,
const OpReplyRemoveTexture& aReply);
void SendFenceHandleToTrackerIfPresent(uint64_t aDestHolderId,
uint64_t aTransactionId,
PTextureParent* aTexture,
CompositableHost* aCompositableHost);
void AppendDeliverFenceMessage(uint64_t aDestHolderId,
uint64_t aTransactionId,
PTextureParent* aTexture,
CompositableHost* aCompositableHost);
static void SendFenceHandleToTrackerIfPresent(base::ProcessId aChildProcessId,
uint64_t aDestHolderId,
uint64_t aTransactionId,
PTextureParent* aTexture,
CompositableHost* aCompositableHost);
static void AppendDeliverFenceMessage(base::ProcessId aChildProcessId,
uint64_t aDestHolderId,
uint64_t aTransactionId,
PTextureParent* aTexture,
CompositableHost* aCompositableHost);
using CompositableParentManager::SendPendingAsyncMessges;
static void SendPendingAsyncMessges(base::ProcessId aChildProcessId);
using CompositableParentManager::SendPendingAsyncMessages;
static void SendPendingAsyncMessages(base::ProcessId aChildProcessId);
static ImageBridgeParent* GetInstance(ProcessId aId);
-26
View File
@@ -90,19 +90,6 @@ LayerTransactionChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessa
if (texture) {
texture->SetReleaseFenceHandle(fence);
}
if (mForwarder) {
mForwarder->HoldTransactionsToRespond(op.transactionId());
} else {
// Send back a response.
InfallibleTArray<AsyncChildMessageData> replies;
replies.AppendElement(OpReplyDeliverFence(op.transactionId()));
SendChildAsyncMessages(replies);
}
break;
}
case AsyncParentMessageData::TOpReplyDeliverFence: {
const OpReplyDeliverFence& op = message.get_OpReplyDeliverFence();
TransactionCompleteted(op.transactionId());
break;
}
case AsyncParentMessageData::TOpReplyRemoveTexture: {
@@ -120,19 +107,6 @@ LayerTransactionChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessa
return true;
}
void
LayerTransactionChild::SendFenceHandle(AsyncTransactionTracker* aTracker,
PTextureChild* aTexture,
const FenceHandle& aFence)
{
HoldUntilComplete(aTracker);
InfallibleTArray<AsyncChildMessageData> messages;
messages.AppendElement(OpDeliverFenceFromChild(aTracker->GetId(),
nullptr, aTexture,
FenceHandleFromChild(aFence)));
SendChildAsyncMessages(messages);
}
void
LayerTransactionChild::ActorDestroy(ActorDestroyReason why)
{
-4
View File
@@ -47,10 +47,6 @@ public:
mForwarder = aForwarder;
}
virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
PTextureChild* aTexture,
const FenceHandle& aFence);
uint64_t GetId() const { return mId; }
protected:
+16 -57
View File
@@ -211,8 +211,8 @@ public:
~AutoLayerTransactionParentAsyncMessageSender()
{
mLayerTransaction->SendPendingAsyncMessges();
ImageBridgeParent::SendPendingAsyncMessges(mLayerTransaction->GetChildProcessId());
mLayerTransaction->SendPendingAsyncMessages();
ImageBridgeParent::SendPendingAsyncMessages(mLayerTransaction->GetChildProcessId());
}
private:
LayerTransactionParent* mLayerTransaction;
@@ -662,6 +662,8 @@ LayerTransactionParent::RecvGetOpacity(PLayerParent* aParent,
return false;
}
mShadowLayersManager->ApplyAsyncProperties(this);
*aOpacity = layer->GetLocalOpacity();
return true;
}
@@ -679,6 +681,12 @@ LayerTransactionParent::RecvGetAnimationTransform(PLayerParent* aParent,
return false;
}
// Make sure we apply the latest animation style or else we can end up with
// a race between when we temporarily clear the animation transform (in
// CompositorParent::SetShadowProperties) and when animation recalculates
// the value.
mShadowLayersManager->ApplyAsyncProperties(this);
// This method is specific to transforms applied by animation.
// This is because this method uses the information stored with an animation
// such as the origin of the reference frame corresponding to the layer, to
@@ -712,9 +720,7 @@ LayerTransactionParent::RecvGetAnimationTransform(PLayerParent* aParent,
Point3D(NS_round(NSAppUnitsToFloatPixels(data.origin().x, scale)),
NS_round(NSAppUnitsToFloatPixels(data.origin().y, scale)),
0.0f);
double cssPerDev =
double(nsDeviceContext::AppUnitsPerCSSPixel()) / double(scale);
transformOrigin = data.transformOrigin() * cssPerDev;
transformOrigin = data.transformOrigin();
break;
}
}
@@ -907,32 +913,6 @@ LayerTransactionParent::RecvChildAsyncMessages(InfallibleTArray<AsyncChildMessag
const AsyncChildMessageData& message = aMessages[i];
switch (message.type()) {
case AsyncChildMessageData::TOpDeliverFenceFromChild: {
const OpDeliverFenceFromChild& op = message.get_OpDeliverFenceFromChild();
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
FenceHandle fence = FenceHandle(op.fence());
PTextureParent* parent = op.textureParent();
TextureHostOGL* hostOGL = nullptr;
RefPtr<TextureHost> texture = TextureHost::AsTextureHost(parent);
if (texture) {
hostOGL = texture->AsHostOGL();
}
if (hostOGL) {
hostOGL->SetAcquireFence(fence.mFence);
}
#endif
// Send back a response.
InfallibleTArray<AsyncParentMessageData> replies;
replies.AppendElement(OpReplyDeliverFence(op.transactionId()));
mozilla::unused << SendParentAsyncMessages(replies);
break;
}
case AsyncChildMessageData::TOpReplyDeliverFence: {
const OpReplyDeliverFence& op = message.get_OpReplyDeliverFence();
TransactionCompleteted(op.transactionId());
break;
}
case AsyncChildMessageData::TOpRemoveTextureAsync: {
const OpRemoveTextureAsync& op = message.get_OpRemoveTextureAsync();
CompositableHost* compositable = CompositableHost::FromIPDLActor(op.compositableParent());
@@ -944,7 +924,7 @@ LayerTransactionParent::RecvChildAsyncMessages(InfallibleTArray<AsyncChildMessag
MOZ_ASSERT(ImageBridgeParent::GetInstance(GetChildProcessId()));
if (ImageBridgeParent::GetInstance(GetChildProcessId())) {
// send FenceHandle if present via ImageBridge.
ImageBridgeParent::SendFenceHandleToTrackerIfPresent(
ImageBridgeParent::AppendDeliverFenceMessage(
GetChildProcessId(),
op.holderId(),
op.transactionId(),
@@ -953,9 +933,8 @@ LayerTransactionParent::RecvChildAsyncMessages(InfallibleTArray<AsyncChildMessag
// Send message back via PImageBridge.
ImageBridgeParent::ReplyRemoveTexture(
GetChildProcessId(),
OpReplyRemoveTexture(true, // isMain
op.holderId(),
op.transactionId()));
OpReplyRemoveTexture(op.holderId(),
op.transactionId()));
} else {
NS_ERROR("ImageBridgeParent should exist");
}
@@ -972,7 +951,6 @@ LayerTransactionParent::RecvChildAsyncMessages(InfallibleTArray<AsyncChildMessag
void
LayerTransactionParent::ActorDestroy(ActorDestroyReason why)
{
DestroyAsyncTransactionTrackersHolder();
}
bool LayerTransactionParent::IsSameProcess() const
@@ -993,10 +971,7 @@ LayerTransactionParent::SendFenceHandleIfPresent(PTextureParent* aTexture,
if (aCompositableHost && aCompositableHost->GetCompositor()) {
FenceHandle fence = aCompositableHost->GetCompositor()->GetReleaseFence();
if (fence.IsValid()) {
RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
HoldUntilComplete(tracker);
mPendingAsyncMessage.push_back(OpDeliverFence(tracker->GetId(),
aTexture, nullptr,
mPendingAsyncMessage.push_back(OpDeliverFence(aTexture, nullptr,
fence));
}
}
@@ -1004,27 +979,11 @@ LayerTransactionParent::SendFenceHandleIfPresent(PTextureParent* aTexture,
// Send a ReleaseFence that is set by HwcComposer2D.
FenceHandle fence = texture->GetAndResetReleaseFenceHandle();
if (fence.IsValid()) {
RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
HoldUntilComplete(tracker);
mPendingAsyncMessage.push_back(OpDeliverFence(tracker->GetId(),
aTexture, nullptr,
mPendingAsyncMessage.push_back(OpDeliverFence(aTexture, nullptr,
fence));
}
}
void
LayerTransactionParent::SendFenceHandle(AsyncTransactionTracker* aTracker,
PTextureParent* aTexture,
const FenceHandle& aFence)
{
HoldUntilComplete(aTracker);
InfallibleTArray<AsyncParentMessageData> messages;
messages.AppendElement(OpDeliverFence(aTracker->GetId(),
aTexture, nullptr,
aFence));
mozilla::unused << SendParentAsyncMessages(messages);
}
void
LayerTransactionParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage)
{
-4
View File
@@ -89,10 +89,6 @@ public:
virtual void SendFenceHandleIfPresent(PTextureParent* aTexture,
CompositableHost* aCompositableHost) override;
virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
PTextureParent* aTexture,
const FenceHandle& aFence) override;
virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
virtual base::ProcessId GetChildProcessId() override
+23 -34
View File
@@ -41,7 +41,6 @@ using mozilla::layers::DiagnosticTypes from "mozilla/layers/CompositorTypes.h";
using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
using struct mozilla::layers::FenceHandle from "mozilla/layers/FenceUtils.h";
using struct mozilla::layers::FenceHandleFromChild from "mozilla/layers/FenceUtils.h";
using std::string from "string";
namespace mozilla {
@@ -95,26 +94,33 @@ union TimingFunction {
StepFunction;
};
// Send the angle with units rather than sending all angles in radians
// to avoid having floating point error introduced by unit switching.
struct CSSAngle {
float value;
int unit; // an nsCSSUnit that is valid for angles
};
struct LayerColor { gfxRGBA value; };
struct Perspective { float value; };
struct RotationX { float radians; };
struct RotationY { float radians; };
struct RotationZ { float radians; };
struct Rotation { float radians; };
struct RotationX { CSSAngle angle; };
struct RotationY { CSSAngle angle; };
struct RotationZ { CSSAngle angle; };
struct Rotation { CSSAngle angle; };
struct Rotation3D {
float x;
float y;
float z;
float radians;
CSSAngle angle;
};
struct Scale {
float x;
float y;
float z;
};
struct Skew { float x; float y; };
struct SkewX { float x; };
struct SkewY { float y; };
struct Skew { CSSAngle x; CSSAngle y; };
struct SkewX { CSSAngle x; };
struct SkewY { CSSAngle y; };
struct TransformMatrix { Matrix4x4 value; };
struct Translation {
float x;
@@ -155,9 +161,9 @@ struct AnimationSegment {
struct TransformData {
// the origin of the frame being transformed in app units
nsPoint origin;
// the transform-origin property for the transform in css pixels
// the transform-origin property for the transform in device pixels
Point3D transformOrigin;
// the perspective-origin property for the transform in css pixels
// the perspective-origin property for the transform in device pixels
Point3D perspectiveOrigin;
nsRect bounds;
nscoord perspective;
@@ -368,11 +374,15 @@ struct OpRemoveTextureAsync {
};
struct OpReplyRemoveTexture {
bool isMain;
uint64_t holderId;
uint64_t transactionId;
};
union MaybeFence {
FenceHandle;
null_t;
};
/**
* Tells the compositor-side which texture to use (for example, as front buffer
* if there is several textures for double buffering)
@@ -380,6 +390,7 @@ struct OpReplyRemoveTexture {
struct OpUseTexture {
PCompositable compositable;
PTexture texture;
MaybeFence fence;
};
struct OpUseComponentAlphaTextures {
@@ -393,35 +404,17 @@ union MaybeRegion {
null_t;
};
struct OpUpdateTexture {
PCompositable compositable;
PTexture texture;
MaybeRegion region;
};
struct OpDeliverFence {
uint64_t transactionId;
PTexture texture;
FenceHandle fence;
};
struct OpDeliverFenceToTracker {
uint64_t transactionId;
uint64_t destHolderId;
uint64_t destTransactionId;
FenceHandle fence;
};
struct OpDeliverFenceFromChild {
uint64_t transactionId;
PTexture texture;
FenceHandleFromChild fence;
};
struct OpReplyDeliverFence {
uint64_t transactionId;
};
union CompositableOperation {
OpUpdatePictureRect;
@@ -432,7 +425,6 @@ union CompositableOperation {
OpRemoveTexture;
OpRemoveTextureAsync;
OpUpdateTexture;
OpUseTexture;
OpUseComponentAlphaTextures;
OpUseOverlaySource;
@@ -488,13 +480,10 @@ union EditReply {
union AsyncParentMessageData {
OpDeliverFence;
OpDeliverFenceToTracker;
OpReplyDeliverFence;
OpReplyRemoveTexture;
};
union AsyncChildMessageData {
OpDeliverFenceFromChild;
OpReplyDeliverFence;
OpRemoveTextureAsync;
};
+7
View File
@@ -38,6 +38,12 @@ struct SurfaceDescriptorD3D9 {
uintptr_t texture;
};
struct SurfaceDescriptorFileMapping {
WindowsHandle handle;
SurfaceFormat format;
IntSize size;
};
struct SurfaceDescriptorDIB {
// gfxWindowsSurface*
uintptr_t surface;
@@ -112,6 +118,7 @@ union SurfaceDescriptor {
SurfaceDescriptorD3D9;
SurfaceDescriptorDIB;
SurfaceDescriptorD3D10;
SurfaceDescriptorFileMapping;
SurfaceDescriptorDXGIYCbCr;
SurfaceDescriptorX11;
SurfaceTextureDescriptor;
+22 -49
View File
@@ -358,28 +358,6 @@ ShadowLayerForwarder::UpdatePictureRect(CompositableClient* aCompositable,
mTxn->AddNoSwapPaint(OpUpdatePictureRect(nullptr, aCompositable->GetIPDLActor(), aRect));
}
void
ShadowLayerForwarder::UpdatedTexture(CompositableClient* aCompositable,
TextureClient* aTexture,
nsIntRegion* aRegion)
{
MOZ_ASSERT(aCompositable);
MOZ_ASSERT(aTexture);
MOZ_ASSERT(aCompositable->GetIPDLActor());
MOZ_ASSERT(aTexture->GetIPDLActor());
MaybeRegion region = aRegion ? MaybeRegion(*aRegion)
: MaybeRegion(null_t());
if (aTexture->GetFlags() & TextureFlags::IMMEDIATE_UPLOAD) {
mTxn->AddPaint(OpUpdateTexture(nullptr, aCompositable->GetIPDLActor(),
nullptr, aTexture->GetIPDLActor(),
region));
} else {
mTxn->AddNoSwapPaint(OpUpdateTexture(nullptr, aCompositable->GetIPDLActor(),
nullptr, aTexture->GetIPDLActor(),
region));
}
}
void
ShadowLayerForwarder::UseTexture(CompositableClient* aCompositable,
TextureClient* aTexture)
@@ -388,15 +366,18 @@ ShadowLayerForwarder::UseTexture(CompositableClient* aCompositable,
MOZ_ASSERT(aTexture);
MOZ_ASSERT(aCompositable->GetIPDLActor());
MOZ_ASSERT(aTexture->GetIPDLActor());
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
FenceHandle handle = aTexture->GetAcquireFenceHandle();
if (handle.IsValid()) {
RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(handle);
SendFenceHandle(tracker, aTexture->GetIPDLActor(), handle);
}
#endif
FenceHandle fence = aTexture->GetAcquireFenceHandle();
mTxn->AddEdit(OpUseTexture(nullptr, aCompositable->GetIPDLActor(),
nullptr, aTexture->GetIPDLActor()));
nullptr, aTexture->GetIPDLActor(),
fence.IsValid() ? MaybeFence(fence) : MaybeFence(null_t())));
if (aTexture->GetFlags() & TextureFlags::IMMEDIATE_UPLOAD
&& aTexture->HasInternalBuffer()) {
// We use IMMEDIATE_UPLOAD when we want to be sure that the upload cannot
// race with updates on the main thread. In this case we want the transaction
// to be synchronous.
mTxn->MarkSyncTransaction();
}
}
void
@@ -426,17 +407,6 @@ ShadowLayerForwarder::UseOverlaySource(CompositableClient* aCompositable,
}
#endif
void
ShadowLayerForwarder::SendFenceHandle(AsyncTransactionTracker* aTracker,
PTextureChild* aTexture,
const FenceHandle& aFence)
{
if (!HasShadowManager() || !mShadowManager->IPCOpen()) {
return;
}
mShadowManager->SendFenceHandle(aTracker, aTexture, aFence);
}
void
ShadowLayerForwarder::RemoveTextureFromCompositable(CompositableClient* aCompositable,
TextureClient* aTexture)
@@ -754,6 +724,16 @@ ShadowLayerForwarder::IsSameProcess() const
return mShadowManager->OtherPid() == base::GetCurrentProcId();
}
base::ProcessId
ShadowLayerForwarder::ParentPid() const
{
if (!HasShadowManager() || !mShadowManager->IPCOpen()) {
return base::ProcessId();
}
return mShadowManager->OtherPid();
}
/**
* We bail out when we have no shadow manager. That can happen when the
* layer manager is created by the preallocated process.
@@ -867,22 +847,15 @@ void ShadowLayerForwarder::SendPendingAsyncMessges()
{
if (!HasShadowManager() ||
!mShadowManager->IPCOpen()) {
mTransactionsToRespond.clear();
mPendingAsyncMessages.clear();
return;
}
if (mTransactionsToRespond.empty() && mPendingAsyncMessages.empty()) {
if (mPendingAsyncMessages.empty()) {
return;
}
InfallibleTArray<AsyncChildMessageData> replies;
replies.SetCapacity(mTransactionsToRespond.size());
// Prepare OpReplyDeliverFence messages.
for (size_t i = 0; i < mTransactionsToRespond.size(); i++) {
replies.AppendElement(OpReplyDeliverFence(mTransactionsToRespond[i]));
}
mTransactionsToRespond.clear();
// Prepare pending messages.
for (size_t i = 0; i < mPendingAsyncMessages.size(); i++) {
replies.AppendElement(mPendingAsyncMessages[i]);
+1 -10
View File
@@ -241,13 +241,6 @@ public:
void UpdatePictureRect(CompositableClient* aCompositable,
const gfx::IntRect& aRect) override;
/**
* See CompositableForwarder::UpdatedTexture
*/
virtual void UpdatedTexture(CompositableClient* aCompositable,
TextureClient* aTexture,
nsIntRegion* aRegion) override;
/**
* See CompositableForwarder::UseTexture
*/
@@ -260,9 +253,6 @@ public:
virtual void UseOverlaySource(CompositableClient* aCompositable,
const OverlaySource& aOverlay) override;
#endif
virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
PTextureChild* aTexture,
const FenceHandle& aFence) override;
/**
* End the current transaction and forward it to LayerManagerComposite.
@@ -351,6 +341,7 @@ public:
virtual bool IPCOpen() const override;
virtual bool IsSameProcess() const override;
virtual base::ProcessId ParentPid() const override;
/**
* Construct a shadow of |aLayer| on the "other side", at the
+1
View File
@@ -35,6 +35,7 @@ public:
virtual bool SetTestSampleTime(LayerTransactionParent* aLayerTree,
const TimeStamp& aTime) { return true; }
virtual void LeaveTestMode(LayerTransactionParent* aLayerTree) { }
virtual void ApplyAsyncProperties(LayerTransactionParent* aLayerTree) = 0;
virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree,
APZTestData* aOutData) { }
virtual void SetConfirmedTargetAPZC(const LayerTransactionParent* aLayerTree,
+5 -1
View File
@@ -349,7 +349,11 @@ android::sp<android::GraphicBuffer>
SharedBufferManagerParent::GetGraphicBuffer(GrallocBufferRef aRef)
{
MonitorAutoLock lock(*sManagerMonitor.get());
return GetInstance(aRef.mOwner)->GetGraphicBuffer(aRef.mKey);
SharedBufferManagerParent* parent = GetInstance(aRef.mOwner);
if (!parent) {
return nullptr;
}
return parent->GetGraphicBuffer(aRef.mKey);
}
#endif
+6 -8
View File
@@ -209,18 +209,15 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
'opengl/GrallocTextureHost.cpp',
]
LOCAL_INCLUDES += ['/widget/gonk']
CXXFLAGS += [
'-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [
'system/core/libsync/include'
]
]
SOURCES += [
'ipc/ShadowLayerUtilsGralloc.cpp',
]
if CONFIG['ANDROID_VERSION'] >= '17':
EXPORTS.mozilla.layers += [
'ipc/FenceUtilsGonk.h',
]
SOURCES += [
'ipc/FenceUtilsGonk.cpp',
]
UNIFIED_SOURCES += [
'apz/src/APZCTreeManager.cpp',
'apz/src/AsyncPanZoomController.cpp',
@@ -290,6 +287,7 @@ UNIFIED_SOURCES += [
'ipc/CompositorBench.cpp',
'ipc/CompositorChild.cpp',
'ipc/CompositorParent.cpp',
'ipc/FenceUtils.cpp',
'ipc/ImageBridgeChild.cpp',
'ipc/ImageBridgeParent.cpp',
'ipc/ISurfaceAllocator.cpp',
+13 -1
View File
@@ -47,7 +47,19 @@ public:
* Currently, when TryRender() returns true, the entire framebuffer
* must have been rendered.
*/
virtual bool TryRender(Layer* aRoot, bool aGeometryChanged) = 0;
virtual bool TryRenderWithHwc(Layer* aRoot, bool aGeometryChanged) = 0;
/**
* Return true if Composer2D does composition. Return false if Composer2D
* failed the composition.
*/
virtual bool Render() = 0;
/**
* Return true if Composer2D has a fast composition hardware.
* Return false if Composer2D does not have a fast composition hardware.
*/
virtual bool HasHwc() = 0;
};
} // namespace layers
+17 -12
View File
@@ -131,13 +131,19 @@ CompositorOGL::CreateContext()
caps, requireCompatProfile);
}
if (!context)
if (!context) {
context = gl::GLContextProvider::CreateForWindow(mWidget);
}
if (!context) {
NS_WARNING("Failed to create CompositorOGL context");
}
#ifdef MOZ_WIDGET_GONK
mWidget->SetNativeData(NS_NATIVE_OPENGL_CONTEXT,
reinterpret_cast<uintptr_t>(context.get()));
#endif
return context.forget();
}
@@ -1081,7 +1087,7 @@ CompositorOGL::DrawQuad(const Rect& aRect,
TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL();
TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL();
if (!sourceY && !sourceCb && !sourceCr) {
if (!sourceY || !sourceCb || !sourceCr) {
NS_WARNING("Invalid layer texture.");
return;
}
@@ -1279,12 +1285,12 @@ CompositorOGL::EndFrame()
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
void
CompositorOGL::SetFBAcquireFence(Layer* aLayer)
CompositorOGL::SetDispAcquireFence(Layer* aLayer)
{
// OpenGL does not provide ReleaseFence for rendering.
// Instead use FBAcquireFence as layer buffer's ReleaseFence
// Instead use DispAcquireFence as layer buffer's ReleaseFence
// to prevent flickering and tearing.
// FBAcquireFence is FramebufferSurface's AcquireFence.
// DispAcquireFence is DisplaySurface's AcquireFence.
// AcquireFence will be signaled when a buffer's content is available.
// See Bug 974152.
@@ -1292,11 +1298,8 @@ CompositorOGL::SetFBAcquireFence(Layer* aLayer)
return;
}
android::sp<android::Fence> fence = new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd());
if (fence.get() && fence->isValid()) {
FenceHandle handle = FenceHandle(fence);
mReleaseFenceHandle.Merge(handle);
}
RefPtr<FenceHandle::FdObj> fence = new FenceHandle::FdObj(GetGonkDisplay()->GetPrevDispAcquireFd());
mReleaseFenceHandle.Merge(FenceHandle(fence));
}
FenceHandle
@@ -1305,12 +1308,14 @@ CompositorOGL::GetReleaseFence()
if (!mReleaseFenceHandle.IsValid()) {
return FenceHandle();
}
return FenceHandle(new android::Fence(mReleaseFenceHandle.mFence->dup()));
nsRefPtr<FenceHandle::FdObj> fdObj = mReleaseFenceHandle.GetDupFdObj();
return FenceHandle(fdObj);
}
#else
void
CompositorOGL::SetFBAcquireFence(Layer* aLayer)
CompositorOGL::SetDispAcquireFence(Layer* aLayer)
{
}
+14 -4
View File
@@ -32,9 +32,6 @@
#include "nsThreadUtils.h" // for nsRunnable
#include "nsXULAppAPI.h" // for XRE_GetProcessType
#include "nscore.h" // for NS_IMETHOD
#ifdef MOZ_WIDGET_GONK
#include <ui/GraphicBuffer.h>
#endif
#include "gfxVR.h"
class nsIWidget;
@@ -235,7 +232,7 @@ public:
const gfx::Matrix4x4 &aTransform) override;
virtual void EndFrame() override;
virtual void SetFBAcquireFence(Layer* aLayer) override;
virtual void SetDispAcquireFence(Layer* aLayer) override;
virtual FenceHandle GetReleaseFence() override;
virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) override;
@@ -302,6 +299,19 @@ public:
const gfx::Matrix4x4& GetProjMatrix() const {
return mProjMatrix;
}
void SetProjMatrix(const gfx::Matrix4x4& aProjMatrix) {
mProjMatrix = aProjMatrix;
}
const gfx::IntSize GetDestinationSurfaceSize() const {
return gfx::IntSize (mSurfaceSize.width, mSurfaceSize.height);
}
const ScreenPoint& GetScreenRenderOffset() const {
return mRenderOffset;
}
private:
virtual gfx::IntSize GetWidgetSize() const override
{
+4 -7
View File
@@ -91,7 +91,8 @@ GrallocTextureClientOGL::WaitForBufferOwnership(bool aWaitReleaseFence)
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
if (mReleaseFenceHandle.IsValid()) {
android::sp<Fence> fence = mReleaseFenceHandle.mFence;
nsRefPtr<FenceHandle::FdObj> fdObj = mReleaseFenceHandle.GetAndResetFdObj();
android::sp<Fence> fence = new Fence(fdObj->GetAndResetFd());
#if ANDROID_VERSION == 17
fence->waitForever(1000, "GrallocTextureClientOGL::Lock");
// 1000 is what Android uses. It is a warning timeout in ms.
@@ -130,14 +131,10 @@ GrallocTextureClientOGL::Lock(OpenMode aMode)
usage |= GRALLOC_USAGE_SW_WRITE_OFTEN;
}
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
android::sp<Fence> fence = android::Fence::NO_FENCE;
if (mReleaseFenceHandle.IsValid()) {
fence = mReleaseFenceHandle.mFence;
}
mReleaseFenceHandle = FenceHandle();
nsRefPtr<FenceHandle::FdObj> fdObj = mReleaseFenceHandle.GetAndResetFdObj();
int32_t rv = mGraphicBuffer->lockAsync(usage,
reinterpret_cast<void**>(&mMappedBuffer),
fence->dup());
fdObj->GetAndResetFd());
#else
int32_t rv = mGraphicBuffer->lock(usage,
reinterpret_cast<void**>(&mMappedBuffer));
+42 -1
View File
@@ -8,6 +8,7 @@
#include "gfx2DGlue.h"
#include <ui/GraphicBuffer.h>
#include "GrallocImages.h" // for GrallocImage
#include "GLLibraryEGL.h" // for GLLibraryEGL
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/DataSurfaceHelpers.h"
#include "mozilla/layers/GrallocTextureHost.h"
@@ -19,6 +20,7 @@ namespace mozilla {
namespace layers {
using namespace android;
using namespace mozilla::gl;
static gfx::SurfaceFormat
SurfaceFormatForAndroidPixelFormat(android::PixelFormat aFormat,
@@ -231,6 +233,9 @@ GrallocTextureHostOGL::GetRenderState()
already_AddRefed<gfx::DataSourceSurface>
GrallocTextureHostOGL::GetAsSurface() {
android::GraphicBuffer* graphicBuffer = GetGraphicBufferFromDesc(mGrallocHandle).get();
if (!graphicBuffer) {
return nullptr;
}
uint8_t* grallocData;
graphicBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&grallocData));
RefPtr<gfx::DataSourceSurface> grallocTempSurf =
@@ -373,6 +378,42 @@ GrallocTextureHostOGL::PrepareTextureSource(CompositableTextureSourceRef& aTextu
}
}
void
GrallocTextureHostOGL::WaitAcquireFenceHandleSyncComplete()
{
if (!mAcquireFenceHandle.IsValid()) {
return;
}
nsRefPtr<FenceHandle::FdObj> fence = mAcquireFenceHandle.GetAndResetFdObj();
int fenceFd = fence->GetAndResetFd();
EGLint attribs[] = {
LOCAL_EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd,
LOCAL_EGL_NONE
};
EGLSync sync = sEGLLibrary.fCreateSync(EGL_DISPLAY(),
LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID,
attribs);
if (!sync) {
NS_WARNING("failed to create native fence sync");
return;
}
// Wait sync complete with timeout.
// If a source of the fence becomes invalid because of error,
// fene complete is not signaled. See Bug 1061435.
EGLint status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(),
sync,
0,
400000000 /*400 usec*/);
if (status != LOCAL_EGL_CONDITION_SATISFIED) {
NS_ERROR("failed to wait native fence sync");
}
MOZ_ALWAYS_TRUE( sEGLLibrary.fDestroySync(EGL_DISPLAY(), sync) );
}
bool
GrallocTextureHostOGL::BindTextureSource(CompositableTextureSourceRef& aTextureSource)
{
@@ -391,7 +432,7 @@ GrallocTextureHostOGL::BindTextureSource(CompositableTextureSourceRef& aTextureS
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
// Wait until it's ready.
WaitAcquireFenceSyncComplete();
WaitAcquireFenceHandleSyncComplete();
#endif
return true;
}
+2 -12
View File
@@ -16,9 +16,6 @@ namespace mozilla {
namespace layers {
class GrallocTextureHostOGL : public TextureHost
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
, public TextureHostOGL
#endif
{
friend class GrallocBufferActor;
public:
@@ -27,8 +24,6 @@ public:
virtual ~GrallocTextureHostOGL();
virtual void Updated(const nsIntRegion* aRegion) override {}
virtual bool Lock() override;
virtual void Unlock() override;
@@ -53,15 +48,10 @@ public:
virtual void UnbindTextureSource() override;
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
virtual TextureHostOGL* AsHostOGL() override
{
return this;
}
#endif
virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override;
virtual void WaitAcquireFenceHandleSyncComplete() override;
bool IsValid() const;
virtual const char* Name() override { return "GrallocTextureHostOGL"; }
-95
View File
@@ -110,101 +110,6 @@ FlagsToGLFlags(TextureFlags aFlags)
return static_cast<gl::TextureImage::Flags>(result);
}
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
bool
TextureHostOGL::SetReleaseFence(const android::sp<android::Fence>& 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<android::Fence> 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<android::Fence>
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;
}
void
TextureHostOGL::SetAcquireFence(const android::sp<android::Fence>& aAcquireFence)
{
mAcquireFence = aAcquireFence;
}
android::sp<android::Fence>
TextureHostOGL::GetAndResetAcquireFence()
{
android::sp<android::Fence> fence = mAcquireFence;
// Reset current AcquireFence.
mAcquireFence = android::Fence::NO_FENCE;
return fence;
}
void
TextureHostOGL::WaitAcquireFenceSyncComplete()
{
if (!mAcquireFence.get() || !mAcquireFence->isValid()) {
return;
}
int fenceFd = mAcquireFence->dup();
if (fenceFd == -1) {
NS_WARNING("failed to dup fence fd");
return;
}
EGLint attribs[] = {
LOCAL_EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd,
LOCAL_EGL_NONE
};
EGLSync sync = sEGLLibrary.fCreateSync(EGL_DISPLAY(),
LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID,
attribs);
if (!sync) {
NS_WARNING("failed to create native fence sync");
return;
}
// Wait sync complete with timeout.
// If a source of the fence becomes invalid because of error,
// fene complete is not signaled. See Bug 1061435.
EGLint status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(),
sync,
0,
400000000 /*400 usec*/);
if (status != LOCAL_EGL_CONDITION_SATISFIED) {
NS_ERROR("failed to wait native fence sync");
}
MOZ_ALWAYS_TRUE( sEGLLibrary.fDestroySync(EGL_DISPLAY(), sync) );
mAcquireFence = nullptr;
}
#endif
bool
TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface,
nsIntRegion* aDestRegion,
-48
View File
@@ -30,12 +30,6 @@
#include "nsDebug.h" // for NS_WARNING
#include "nsISupportsImpl.h" // for TextureImage::Release, etc
#include "OGLShaderProgram.h" // for ShaderProgramType, etc
#ifdef MOZ_WIDGET_GONK
#include <ui/GraphicBuffer.h>
#if ANDROID_VERSION >= 17
#include <ui/Fence.h>
#endif
#endif
class nsIntRegion;
@@ -128,48 +122,6 @@ private:
bool mHasCachedFilter;
};
/**
* TextureHostOGL provides the necessary API for platform specific composition.
*/
class TextureHostOGL
{
public:
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
/**
* Store a fence that will signal when the current buffer is no longer being read.
* Similar to android's GLConsumer::setReleaseFence()
*/
virtual bool SetReleaseFence(const android::sp<android::Fence>& aReleaseFence);
/**
* Return a releaseFence's Fence and clear a reference to the Fence.
*/
virtual android::sp<android::Fence> GetAndResetReleaseFence();
virtual void SetAcquireFence(const android::sp<android::Fence>& aAcquireFence);
/**
* Return a acquireFence's Fence and clear a reference to the Fence.
*/
virtual android::sp<android::Fence> GetAndResetAcquireFence();
virtual void WaitAcquireFenceSyncComplete();
protected:
android::sp<android::Fence> mReleaseFence;
android::sp<android::Fence> mAcquireFence;
/**
* Hold previous ReleaseFence to prevent Fence delivery failure via gecko IPC.
* Fence is a kernel object and its lifetime is managed by a reference count.
* Until the Fence is delivered to client side, need to hold Fence on host side.
*/
android::sp<android::Fence> mPrevReleaseFence;
#endif
};
/**
* A TextureSource backed by a TextureImage.
*
+12
View File
@@ -2447,3 +2447,15 @@ gfxPlatform::CreateHardwareVsyncSource()
nsRefPtr<mozilla::gfx::VsyncSource> softwareVsync = new SoftwareVsyncSource();
return softwareVsync.forget();
}
/* static */ bool
gfxPlatform::IsInLayoutAsapMode()
{
// There are 2 modes of ASAP mode.
// 1 is that the refresh driver and compositor are in lock step
// the second is that the compositor goes ASAP and the refresh driver
// goes at whatever the configurated rate is. This only checks the version
// talos uses, which is the refresh driver and compositor are in lockstep.
return Preferences::GetInt("layout.frame_rate", -1) == 0;
}
+7
View File
@@ -617,6 +617,13 @@ public:
return mVsyncSource;
}
/**
* True if layout rendering should use ASAP mode, which means
* the refresh driver and compositor should render ASAP.
* Used for talos testing purposes
*/
static bool IsInLayoutAsapMode();
/**
* Used to test which input types are handled via APZ.
*/
+1
View File
@@ -275,6 +275,7 @@ private:
// preference value, defaulting to true.
DECL_GFX_PREF(Once, "layers.componentalpha.enabled", ComponentAlphaEnabled, bool, true);
#endif
DECL_GFX_PREF(Live, "layers.composer2d.enabled", Composer2DCompositionEnabled, bool, false);
DECL_GFX_PREF(Once, "layers.d3d11.disable-warp", LayersD3D11DisableWARP, bool, false);
DECL_GFX_PREF(Once, "layers.d3d11.force-warp", LayersD3D11ForceWARP, bool, false);
DECL_GFX_PREF(Live, "layers.draw-bigimage-borders", DrawBigImageBorders, bool, false);
+2
View File
@@ -1453,9 +1453,11 @@ FILE *gfxUtils::sDumpPaintFile = stderr;
#ifdef MOZ_DUMP_PAINTING
bool gfxUtils::sDumpPainting = getenv("MOZ_DUMP_PAINT") != 0;
bool gfxUtils::sDumpPaintingIntermediate = getenv("MOZ_DUMP_PAINT_INTERMEDIATE") != 0;
bool gfxUtils::sDumpPaintingToFile = getenv("MOZ_DUMP_PAINT_TO_FILE") != 0;
#else
bool gfxUtils::sDumpPainting = false;
bool gfxUtils::sDumpPaintingIntermediate = false;
bool gfxUtils::sDumpPaintingToFile = false;
#endif
+1
View File
@@ -293,6 +293,7 @@ public:
static bool DumpDisplayList();
static bool sDumpPainting;
static bool sDumpPaintingIntermediate;
static bool sDumpPaintingToFile;
static FILE* sDumpPaintFile;
};
+3 -3
View File
@@ -790,7 +790,7 @@ IPDL union type."""
if self.recursive:
return self.ptrToType()
else:
return TypeArray(Type('char'), ExprSizeof(self.internalType()))
return Type('mozilla::AlignedStorage2', T=self.internalType())
def unionValue(self):
# NB: knows that Union's storage C union is named |mValue|
@@ -852,14 +852,14 @@ IPDL union type."""
if self.recursive:
return v
else:
return ExprCast(ExprAddrOf(v), self.ptrToType(), reinterpret=1)
return ExprCall(ExprSelect(v, '.', 'addr'))
def constptrToSelfExpr(self):
"""|*constptrToSelfExpr()| has type |self.constType()|"""
v = self.unionValue()
if self.recursive:
return v
return ExprCast(ExprAddrOf(v), self.constPtrToType(), reinterpret=1)
return ExprCall(ExprSelect(v, '.', 'addr'))
def ptrToInternalType(self):
t = self.ptrToType()
+20 -13
View File
@@ -106,6 +106,12 @@ GetTransformRootFrame(nsIFrame* aFrame)
return nsLayoutUtils::GetTransformRootFrame(aFrame);
}
static inline CSSAngle
MakeCSSAngle(const nsCSSValue& aValue)
{
return CSSAngle(aValue.GetAngleValue(), aValue.GetUnit());
}
static void AddTransformFunctions(nsCSSValueList* aList,
nsStyleContext* aContext,
nsPresContext* aPresContext,
@@ -125,25 +131,25 @@ static void AddTransformFunctions(nsCSSValueList* aList,
switch (nsStyleTransformMatrix::TransformFunctionOf(array)) {
case eCSSKeyword_rotatex:
{
double theta = array->Item(1).GetAngleValueInRadians();
CSSAngle theta = MakeCSSAngle(array->Item(1));
aFunctions.AppendElement(RotationX(theta));
break;
}
case eCSSKeyword_rotatey:
{
double theta = array->Item(1).GetAngleValueInRadians();
CSSAngle theta = MakeCSSAngle(array->Item(1));
aFunctions.AppendElement(RotationY(theta));
break;
}
case eCSSKeyword_rotatez:
{
double theta = array->Item(1).GetAngleValueInRadians();
CSSAngle theta = MakeCSSAngle(array->Item(1));
aFunctions.AppendElement(RotationZ(theta));
break;
}
case eCSSKeyword_rotate:
{
double theta = array->Item(1).GetAngleValueInRadians();
CSSAngle theta = MakeCSSAngle(array->Item(1));
aFunctions.AppendElement(Rotation(theta));
break;
}
@@ -152,7 +158,7 @@ static void AddTransformFunctions(nsCSSValueList* aList,
double x = array->Item(1).GetFloatValue();
double y = array->Item(2).GetFloatValue();
double z = array->Item(3).GetFloatValue();
double theta = array->Item(4).GetAngleValueInRadians();
CSSAngle theta = MakeCSSAngle(array->Item(4));
aFunctions.AppendElement(Rotation3D(x, y, z, theta));
break;
}
@@ -246,23 +252,23 @@ static void AddTransformFunctions(nsCSSValueList* aList,
}
case eCSSKeyword_skewx:
{
double x = array->Item(1).GetAngleValueInRadians();
CSSAngle x = MakeCSSAngle(array->Item(1));
aFunctions.AppendElement(SkewX(x));
break;
}
case eCSSKeyword_skewy:
{
double y = array->Item(1).GetAngleValueInRadians();
CSSAngle y = MakeCSSAngle(array->Item(1));
aFunctions.AppendElement(SkewY(y));
break;
}
case eCSSKeyword_skew:
{
double x = array->Item(1).GetAngleValueInRadians();
CSSAngle x = MakeCSSAngle(array->Item(1));
// skew(x) is shorthand for skew(x, 0)
double y = 0;
CSSAngle y(0.0f, eCSSUnit_Degree);
if (array->Count() == 3) {
y = array->Item(2).GetAngleValueInRadians();
y = MakeCSSAngle(array->Item(2));
}
aFunctions.AppendElement(Skew(x, y));
break;
@@ -530,8 +536,9 @@ nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer,
AnimationData data;
if (aProperty == eCSSProperty_transform) {
nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(aFrame);
// all data passed directly to the compositor should be in css pixels
float scale = nsDeviceContext::AppUnitsPerCSSPixel();
// all data passed directly to the compositor should be in dev pixels
int32_t devPixelsToAppUnits = aFrame->PresContext()->AppUnitsPerDevPixel();
float scale = devPixelsToAppUnits;
Point3D offsetToTransformOrigin =
nsDisplayTransform::GetDeltaToTransformOrigin(aFrame, scale, &bounds);
Point3D offsetToPerspectiveOrigin =
@@ -557,7 +564,7 @@ nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer,
data = TransformData(origin, offsetToTransformOrigin,
offsetToPerspectiveOrigin, bounds, perspective,
aFrame->PresContext()->AppUnitsPerDevPixel());
devPixelsToAppUnits);
} else if (aProperty == eCSSProperty_opacity) {
data = null_t();
}
+5 -1
View File
@@ -853,10 +853,14 @@ CreateVsyncRefreshTimer()
// ready.
gfxPrefs::GetSingleton();
if (!gfxPrefs::VsyncAlignedRefreshDriver() || !gfxPrefs::HardwareVsyncEnabled()) {
if (!gfxPrefs::VsyncAlignedRefreshDriver()
|| !gfxPrefs::HardwareVsyncEnabled()
|| gfxPlatform::IsInLayoutAsapMode()) {
return;
}
NS_WARNING("Enabling vsync refresh driver\n");
if (XRE_IsParentProcess()) {
// Make sure all vsync systems are ready.
gfxPlatform::GetPlatform();
@@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<html>
<title>Reftest, bug 1156456</title>
<style>
body {
background: #2a4;
}
div {
width: 200px; height: 200px;
background: #c37;
opacity: 0.6;
will-change: opacity;
}
</style>
<div></div>
@@ -0,0 +1,23 @@
<!DOCTYPE HTML>
<html>
<title>Reftest, bug 1156456</title>
<style>
body {
background: #2a4;
}
@keyframes HoldOpacity {
from, to {
opacity: 0.6;
}
}
div {
width: 200px; height: 200px;
background: #c37;
animation: 10s HoldOpacity infinite;
}
</style>
<div></div>
@@ -2,3 +2,4 @@
!= screen-animations.html screen-animations-notref.html
fails == print-no-animations.html print-no-animations-ref.html # reftest harness doesn't actually make pres context non-dynamic for reftest-print tests
fails != print-no-animations.html print-no-animations-notref.html # reftest harness doesn't actually make pres context non-dynamic for reftest-print tests
== animate-opacity.html animate-opacity-ref.html
@@ -0,0 +1,46 @@
<!DOCTYPE HTML>
<html>
<title>Reftest, bug 1156456</title>
<style>
html, body {
height: 100%;
}
body {
background: white;
perspective: 1000px;
}
div, div::before, div::after {
width: 200px; height: 200px;
}
div {
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
margin: auto;
transform-origin: 50% 50% 100px;
background: #006;
transform: rotateY(-120deg) rotateX(60deg);
transform-style: preserve-3d;
}
div::before, div::after {
position: absolute;
top: 0; left: 0;
content: "";
}
div::before {
background: #00f;
transform: translate3D(100px, 0, 100px) rotateY(90deg);
}
div::after {
background: #00c;
transform: translate3D(0, -100px, 100px) rotateX(90deg);
}
</style>
<div></div>
@@ -0,0 +1,46 @@
<!DOCTYPE HTML>
<html reftest-zoom="1.5">
<title>Reftest, bug 1156456</title>
<style>
html, body {
height: 100%;
}
body {
background: white;
perspective: 1000px;
}
div, div::before, div::after {
width: 200px; height: 200px;
}
div {
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
margin: auto;
transform-origin: 50% 50% 100px;
background: #006;
transform: rotateY(-120deg) rotateX(60deg);
transform-style: preserve-3d;
}
div::before, div::after {
position: absolute;
top: 0; left: 0;
content: "";
}
div::before {
background: #00f;
transform: translate3D(100px, 0, 100px) rotateY(90deg);
}
div::after {
background: #00c;
transform: translate3D(0, -100px, 100px) rotateX(90deg);
}
</style>
<div></div>
@@ -0,0 +1,52 @@
<!DOCTYPE HTML>
<html reftest-zoom="1.5">
<title>Reftest, bug 1156456</title>
<style>
html, body {
height: 100%;
}
body {
background: white;
perspective: 1000px;
}
div, div::before, div::after {
width: 200px; height: 200px;
}
@keyframes HoldTransform {
from, to {
transform: rotateY(-120deg) rotateX(60deg);
}
}
div {
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
margin: auto;
transform-origin: 50% 50% 100px;
background: #006;
transform-style: preserve-3d;
animation: 10s HoldTransform infinite;
}
div::before, div::after {
position: absolute;
top: 0; left: 0;
content: "";
}
div::before {
background: #00f;
transform: translate3D(100px, 0, 100px) rotateY(90deg);
}
div::after {
background: #00c;
transform: translate3D(0, -100px, 100px) rotateX(90deg);
}
</style>
<div></div>
@@ -0,0 +1,52 @@
<!DOCTYPE HTML>
<html>
<title>Reftest, bug 1156456</title>
<style>
html, body {
height: 100%;
}
body {
background: white;
perspective: 1000px;
}
div, div::before, div::after {
width: 200px; height: 200px;
}
@keyframes HoldTransform {
from, to {
transform: rotateY(-120deg) rotateX(60deg);
}
}
div {
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
margin: auto;
transform-origin: 50% 50% 100px;
background: #006;
transform-style: preserve-3d;
animation: 10s HoldTransform infinite;
}
div::before, div::after {
position: absolute;
top: 0; left: 0;
content: "";
}
div::before {
background: #00f;
transform: translate3D(100px, 0, 100px) rotateY(90deg);
}
div::after {
background: #00c;
transform: translate3D(0, -100px, 100px) rotateX(90deg);
}
</style>
<div></div>
@@ -0,0 +1,47 @@
<!DOCTYPE HTML>
<html>
<title>Reftest, bug 1156456</title>
<style>
html, body {
height: 100%;
}
body {
background: white;
perspective: 1000px;
}
div, div::before, div::after {
width: 200px; height: 200px;
}
div {
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
margin: auto;
transform-origin: 50% 50% 100px;
background: #006;
/* approximately rotateY(-120deg) rotateX(60deg); */
transform: rotateY(-2.0944rad) rotateX(1.0472rad);
transform-style: preserve-3d;
}
div::before, div::after {
position: absolute;
top: 0; left: 0;
content: "";
}
div::before {
background: #00f;
transform: translate3D(100px, 0, 100px) rotateY(90deg);
}
div::after {
background: #00c;
transform: translate3D(0, -100px, 100px) rotateX(90deg);
}
</style>
<div></div>
@@ -0,0 +1,47 @@
<!DOCTYPE HTML>
<html reftest-zoom="1.5">
<title>Reftest, bug 1156456</title>
<style>
html, body {
height: 100%;
}
body {
background: white;
perspective: 1000px;
}
div, div::before, div::after {
width: 200px; height: 200px;
}
div {
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
margin: auto;
transform-origin: 50% 50% 100px;
background: #006;
/* approximately rotateY(-120deg) rotateX(60deg); */
transform: rotateY(-2.0944rad) rotateX(1.0472rad);
transform-style: preserve-3d;
}
div::before, div::after {
position: absolute;
top: 0; left: 0;
content: "";
}
div::before {
background: #00f;
transform: translate3D(100px, 0, 100px) rotateY(90deg);
}
div::after {
background: #00c;
transform: translate3D(0, -100px, 100px) rotateX(90deg);
}
</style>
<div></div>
@@ -0,0 +1,53 @@
<!DOCTYPE HTML>
<html reftest-zoom="1.5">
<title>Reftest, bug 1156456</title>
<style>
html, body {
height: 100%;
}
body {
background: white;
perspective: 1000px;
}
div, div::before, div::after {
width: 200px; height: 200px;
}
@keyframes HoldTransform {
from, to {
/* approximately rotateY(-120deg) rotateX(60deg); */
transform: rotateY(-2.0944rad) rotateX(1.0472rad);
}
}
div {
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
margin: auto;
transform-origin: 50% 50% 100px;
background: #006;
transform-style: preserve-3d;
animation: 10s HoldTransform infinite;
}
div::before, div::after {
position: absolute;
top: 0; left: 0;
content: "";
}
div::before {
background: #00f;
transform: translate3D(100px, 0, 100px) rotateY(90deg);
}
div::after {
background: #00c;
transform: translate3D(0, -100px, 100px) rotateX(90deg);
}
</style>
<div></div>
@@ -0,0 +1,53 @@
<!DOCTYPE HTML>
<html>
<title>Reftest, bug 1156456</title>
<style>
html, body {
height: 100%;
}
body {
background: white;
perspective: 1000px;
}
div, div::before, div::after {
width: 200px; height: 200px;
}
@keyframes HoldTransform {
from, to {
/* approximately rotateY(-120deg) rotateX(60deg); */
transform: rotateY(-2.0944rad) rotateX(1.0472rad);
}
}
div {
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
margin: auto;
transform-origin: 50% 50% 100px;
background: #006;
transform-style: preserve-3d;
animation: 10s HoldTransform infinite;
}
div::before, div::after {
position: absolute;
top: 0; left: 0;
content: "";
}
div::before {
background: #00f;
transform: translate3D(100px, 0, 100px) rotateY(90deg);
}
div::after {
background: #00c;
transform: translate3D(0, -100px, 100px) rotateX(90deg);
}
</style>
<div></div>
@@ -57,3 +57,9 @@ pref(layout.css.will-change.enabled,true) != willchange-containing-block.html?wi
fuzzy-if(winWidget&&!layersGPUAccelerated,1,606) == scroll-perspective-1.html scroll-perspective-1-ref.html
# Bugs
fails-if(!layersGPUAccelerated) == 1035611-1.html 1035611-1-ref.html # Bug 1072898 for !layersGPUAccelerated failures
== animate-cube-radians.html animate-cube-radians-ref.html
fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated,16,6) fuzzy-if(Mulet,16,9) == animate-cube-radians-zoom.html animate-cube-radians-zoom-ref.html
!= animate-cube-radians-ref.html animate-cube-radians-zoom-ref.html
== animate-cube-degrees.html animate-cube-degrees-ref.html
== animate-cube-degrees-zoom.html animate-cube-degrees-zoom-ref.html
!= animate-cube-degrees-ref.html animate-cube-degrees-zoom-ref.html
+10 -3
View File
@@ -1041,9 +1041,16 @@ AddCSSValueAngle(double aCoeff1, const nsCSSValue &aValue1,
double aCoeff2, const nsCSSValue &aValue2,
nsCSSValue &aResult)
{
aResult.SetFloatValue(aCoeff1 * aValue1.GetAngleValueInRadians() +
aCoeff2 * aValue2.GetAngleValueInRadians(),
eCSSUnit_Radian);
if (aValue1.GetUnit() == aValue2.GetUnit()) {
// To avoid floating point error, if the units match, maintain the unit.
aResult.SetFloatValue(aCoeff1 * aValue1.GetFloatValue() +
aCoeff2 * aValue2.GetFloatValue(),
aValue1.GetUnit());
} else {
aResult.SetFloatValue(aCoeff1 * aValue1.GetAngleValueInRadians() +
aCoeff2 * aValue2.GetAngleValueInRadians(),
eCSSUnit_Radian);
}
}
static bool
@@ -643,21 +643,21 @@ var filterTests = [
expected: ["contrast", 0.375] },
// hue-rotate with different angle values
{ start: "hue-rotate(0deg)", end: "hue-rotate(720deg)",
expected: ["hue-rotate", Math.PI.toFixed(5)] },
expected: ["hue-rotate", "180deg"] },
{ start: "hue-rotate(0rad)", end: "hue-rotate("+4*Math.PI+"rad)",
expected: ["hue-rotate", Math.PI.toFixed(5)] },
expected: ["hue-rotate", Math.PI.toFixed(5)+"rad"] },
{ start: "hue-rotate(0grad)", end: "hue-rotate(800grad)",
expected: ["hue-rotate", Math.PI.toFixed(5)] },
expected: ["hue-rotate", "200grad"] },
{ start: "hue-rotate(0turn)", end: "hue-rotate(2turn)",
expected: ["hue-rotate", Math.PI.toFixed(5)] },
expected: ["hue-rotate", "0.5turn"] },
{ start: "hue-rotate(0deg)", end: "hue-rotate("+4*Math.PI+"rad)",
expected: ["hue-rotate", Math.PI.toFixed(5)] },
expected: ["hue-rotate", Math.PI.toFixed(5)+"rad"] },
{ start: "hue-rotate(0turn)", end: "hue-rotate(800grad)",
expected: ["hue-rotate", Math.PI.toFixed(5)] },
expected: ["hue-rotate", Math.PI.toFixed(5)+"rad"] },
{ start: "hue-rotate(0grad)", end: "hue-rotate("+4*Math.PI+"rad)",
expected: ["hue-rotate", Math.PI.toFixed(5)] },
expected: ["hue-rotate", Math.PI.toFixed(5)+"rad"] },
{ start: "hue-rotate(0grad)", end: "hue-rotate(0turn)",
expected: ["hue-rotate", 0] },
expected: ["hue-rotate", "0rad"] },
// multiple matching functions, same length
{ start: "contrast(25%) brightness(0.25) blur(25px) sepia(75%)",
end: "contrast(75%) brightness(0.75) blur(75px) sepia(25%)",
@@ -1215,12 +1215,8 @@ function filter_function_list_equals(computedValStr, expectedList)
}
functionValue = functionValue.substring(0, functionValue.length - 2);
} else if (functionName == "hue-rotate") {
// Last two characters must be "rad".
if (functionValue.search("rad") != functionValue.length - 3) {
return false;
}
tolerance = 0.001;
functionValue = functionValue.substring(0, functionValue.length - 3);
// Just check for string equality.
return functionValue == expected;
} else if (functionName == "drop-shadow" || functionName == "url") {
if (functionValue != expected) {
return false;
+5
View File
@@ -256,6 +256,11 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
'mtp',
]
if int(CONFIG['ANDROID_VERSION']) >= 17:
OS_LIBS += [
'sync',
]
if 'rtsp' in CONFIG['NECKO_PROTOCOLS']:
OS_LIBS += [
'stagefright_foundation',
+61 -38
View File
@@ -51,8 +51,20 @@ static const uint64_t kInputExpirationThresholdMs = 1000;
static StaticRefPtr<GeckoTouchDispatcher> sTouchDispatcher;
/* static */ GeckoTouchDispatcher*
GeckoTouchDispatcher::GetInstance()
{
if (!sTouchDispatcher) {
sTouchDispatcher = new GeckoTouchDispatcher();
ClearOnShutdown(&sTouchDispatcher);
}
return sTouchDispatcher;
}
GeckoTouchDispatcher::GeckoTouchDispatcher()
: mTouchQueueLock("GeckoTouchDispatcher::mTouchQueueLock")
, mHavePendingTouchMoves(false)
, mInflightNonMoveEvents(0)
, mTouchEventsFiltered(false)
{
// Since GeckoTouchDispatcher is initialized when input is initialized
@@ -70,72 +82,82 @@ GeckoTouchDispatcher::GeckoTouchDispatcher()
mMaxPredict = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleMaxPredict());
mOldTouchThreshold = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleOldTouchThreshold());
mDelayedVsyncThreshold = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleVsyncDelayThreshold());
sTouchDispatcher = this;
ClearOnShutdown(&sTouchDispatcher);
}
/* static */ void
GeckoTouchDispatcher::SetCompositorVsyncObserver(mozilla::layers::CompositorVsyncObserver *aObserver)
void
GeckoTouchDispatcher::SetCompositorVsyncScheduler(mozilla::layers::CompositorVsyncScheduler *aObserver)
{
MOZ_ASSERT(sTouchDispatcher != nullptr);
MOZ_ASSERT(NS_IsMainThread());
// We assume on b2g that there is only 1 CompositorParent
MOZ_ASSERT(sTouchDispatcher->mCompositorVsyncObserver == nullptr);
if (sTouchDispatcher->mResamplingEnabled) {
sTouchDispatcher->mCompositorVsyncObserver = aObserver;
MOZ_ASSERT(mCompositorVsyncScheduler == nullptr);
if (mResamplingEnabled) {
mCompositorVsyncScheduler = aObserver;
}
}
// Timestamp is in nanoseconds
/* static */ bool
void
GeckoTouchDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp)
{
if (sTouchDispatcher == nullptr) {
return false;
}
MOZ_ASSERT(sTouchDispatcher->mResamplingEnabled);
bool haveTouchData = false;
{
MutexAutoLock lock(sTouchDispatcher->mTouchQueueLock);
haveTouchData = !sTouchDispatcher->mTouchMoveEvents.empty();
}
if (haveTouchData) {
layers::APZThreadUtils::AssertOnControllerThread();
sTouchDispatcher->DispatchTouchMoveEvents(aVsyncTimestamp);
}
return haveTouchData;
MOZ_ASSERT(mResamplingEnabled);
layers::APZThreadUtils::AssertOnControllerThread();
DispatchTouchMoveEvents(aVsyncTimestamp);
}
// Touch data timestamps are in milliseconds, aEventTime is in nanoseconds
void
GeckoTouchDispatcher::NotifyTouch(MultiTouchInput& aTouch, TimeStamp aEventTime)
{
if (mCompositorVsyncObserver) {
mCompositorVsyncObserver->SetNeedsComposite(true);
if (mCompositorVsyncScheduler) {
mCompositorVsyncScheduler->SetNeedsComposite(true);
}
if (aTouch.mType == MultiTouchInput::MULTITOUCH_MOVE) {
MutexAutoLock lock(mTouchQueueLock);
if (mResamplingEnabled) {
mTouchMoveEvents.push_back(aTouch);
if (mInflightNonMoveEvents > 0) {
// If we have any pending non-move events, we shouldn't resample the
// move events because we might end up dispatching events out of order.
// Instead, fall back to a non-resampling in-order dispatch until we're
// done processing the non-move events.
layers::APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
this, &GeckoTouchDispatcher::DispatchTouchEvent, aTouch));
return;
}
if (mTouchMoveEvents.empty()) {
mTouchMoveEvents.push_back(aTouch);
} else {
// Coalesce touch move events
mTouchMoveEvents.back() = aTouch;
mTouchMoveEvents.push_back(aTouch);
mHavePendingTouchMoves = true;
if (mResamplingEnabled) {
return;
}
layers::APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
this, &GeckoTouchDispatcher::DispatchTouchMoveEvents, TimeStamp::Now()));
} else {
{ // scope lock
MutexAutoLock lock(mTouchQueueLock);
mInflightNonMoveEvents++;
}
layers::APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
this, &GeckoTouchDispatcher::DispatchTouchEvent, aTouch));
this, &GeckoTouchDispatcher::DispatchTouchNonMoveEvent, aTouch));
}
}
void
GeckoTouchDispatcher::DispatchTouchNonMoveEvent(MultiTouchInput aInput)
{
layers::APZThreadUtils::AssertOnControllerThread();
if (mResamplingEnabled) {
// Flush pending touch move events, if there are any
// (DispatchTouchMoveEvents will check the mHavePendingTouchMoves flag and
// bail out if there's nothing to be done).
NotifyVsync(TimeStamp::Now());
}
DispatchTouchEvent(aInput);
{ // scope lock
MutexAutoLock lock(mTouchQueueLock);
mInflightNonMoveEvents--;
MOZ_ASSERT(mInflightNonMoveEvents >= 0);
}
}
@@ -146,9 +168,10 @@ GeckoTouchDispatcher::DispatchTouchMoveEvents(TimeStamp aVsyncTime)
{
MutexAutoLock lock(mTouchQueueLock);
if (mTouchMoveEvents.empty()) {
if (!mHavePendingTouchMoves) {
return;
}
mHavePendingTouchMoves = false;
if (mResamplingEnabled) {
int touchCount = mTouchMoveEvents.size();
+16 -8
View File
@@ -28,7 +28,7 @@ class nsIWidget;
namespace mozilla {
namespace layers {
class CompositorVsyncObserver;
class CompositorVsyncScheduler;
}
// Used to resample touch events whenever a vsync event occurs. It batches
@@ -41,28 +41,36 @@ class CompositorVsyncObserver;
// this sample time, we extrapolate the last two touch events to the sample
// time. The magic numbers defined as constants are taken from android
// InputTransport.cpp.
class GeckoTouchDispatcher
class GeckoTouchDispatcher final
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GeckoTouchDispatcher)
public:
GeckoTouchDispatcher();
static GeckoTouchDispatcher* GetInstance();
void NotifyTouch(MultiTouchInput& aTouch, TimeStamp aEventTime);
void DispatchTouchEvent(MultiTouchInput aMultiTouch);
void DispatchTouchNonMoveEvent(MultiTouchInput aInput);
void DispatchTouchMoveEvents(TimeStamp aVsyncTime);
static bool NotifyVsync(TimeStamp aVsyncTimestamp);
static void SetCompositorVsyncObserver(layers::CompositorVsyncObserver* aObserver);
void NotifyVsync(TimeStamp aVsyncTimestamp);
void SetCompositorVsyncScheduler(layers::CompositorVsyncScheduler* aObserver);
protected:
~GeckoTouchDispatcher() {}
private:
GeckoTouchDispatcher();
void ResampleTouchMoves(MultiTouchInput& aOutTouch, TimeStamp vsyncTime);
void SendTouchEvent(MultiTouchInput& aData);
void DispatchMouseEvent(MultiTouchInput& aMultiTouch,
bool aForwardToChildren);
// mTouchQueueLock are used to protect the vector below
// as it is accessed on the vsync thread and main thread
// mTouchQueueLock is used to protect the vector and state below
// as it is accessed on multiple threads.
Mutex mTouchQueueLock;
std::vector<MultiTouchInput> mTouchMoveEvents;
bool mHavePendingTouchMoves;
int mInflightNonMoveEvents;
// end stuff protected by mTouchQueueLock
bool mResamplingEnabled;
bool mTouchEventsFiltered;
@@ -82,7 +90,7 @@ private:
// How far ahead can vsync events get ahead of touch events.
TimeDuration mOldTouchThreshold;
nsRefPtr<layers::CompositorVsyncObserver> mCompositorVsyncObserver;
nsRefPtr<layers::CompositorVsyncScheduler> mCompositorVsyncScheduler;
};
} // namespace mozilla
+66 -88
View File
@@ -34,7 +34,7 @@
#include "VsyncSource.h"
#if ANDROID_VERSION >= 17
#include "libdisplay/FramebufferSurface.h"
#include "libdisplay/DisplaySurface.h"
#include "gfxPrefs.h"
#include "nsThreadUtils.h"
#endif
@@ -110,15 +110,12 @@ static StaticRefPtr<HwcComposer2D> sInstance;
HwcComposer2D::HwcComposer2D()
: mHwc(nullptr)
, mList(nullptr)
, mDpy(EGL_NO_DISPLAY)
, mSur(EGL_NO_SURFACE)
, mGLContext(nullptr)
, mMaxLayerCount(0)
, mColorFill(false)
, mRBSwapSupport(false)
#if ANDROID_VERSION >= 17
, mPrevRetireFence(Fence::NO_FENCE)
, mPrevDisplayFence(Fence::NO_FENCE)
, mLastVsyncTime(0)
#endif
, mPrepared(false)
, mHasHWVsync(false)
, mLock("mozilla.HwcComposer2D.mLock")
@@ -126,21 +123,11 @@ HwcComposer2D::HwcComposer2D()
#if ANDROID_VERSION >= 17
RegisterHwcEventCallback();
#endif
}
HwcComposer2D::~HwcComposer2D() {
free(mList);
}
int
HwcComposer2D::Init(hwc_display_t dpy, hwc_surface_t sur, gl::GLContext* aGLContext)
{
MOZ_ASSERT(!Initialized());
mHwc = (HwcDevice*)GetGonkDisplay()->GetHWCDevice();
if (!mHwc) {
LOGE("Failed to initialize hwc");
return -1;
LOGD("no hwc support");
return;
}
nsIntSize screenSize;
@@ -170,12 +157,10 @@ HwcComposer2D::Init(hwc_display_t dpy, hwc_surface_t sur, gl::GLContext* aGLCont
mColorFill = (atoi(propValue) == 1) ? true : false;
mRBSwapSupport = true;
#endif
}
mDpy = dpy;
mSur = sur;
mGLContext = aGLContext;
return 0;
HwcComposer2D::~HwcComposer2D() {
free(mList);
}
HwcComposer2D*
@@ -229,12 +214,6 @@ void
HwcComposer2D::Vsync(int aDisplay, nsecs_t aVsyncTimestamp)
{
TimeStamp vsyncTime = mozilla::TimeStamp::FromSystemTime(aVsyncTimestamp);
nsecs_t vsyncInterval = aVsyncTimestamp - mLastVsyncTime;
if (vsyncInterval < 16000000 || vsyncInterval > 17000000) {
LOGE("Non-uniform vsync interval: %lld\n", vsyncInterval);
}
mLastVsyncTime = aVsyncTimestamp;
gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay().NotifyVsync(vsyncTime);
}
@@ -242,7 +221,7 @@ HwcComposer2D::Vsync(int aDisplay, nsecs_t aVsyncTimestamp)
void
HwcComposer2D::Invalidate()
{
if (!Initialized()) {
if (!mHwc) {
LOGE("HwcComposer2D::Invalidate failed!");
return;
}
@@ -261,6 +240,14 @@ HwcComposer2D::SetCompositorParent(CompositorParent* aCompositorParent)
mCompositorParent = aCompositorParent;
}
void
HwcComposer2D::SetEGLInfo(hwc_display_t aDisplay, hwc_surface_t aSurface, gl::GLContext* aGLContext)
{
mDpy = aDisplay;
mSur = aSurface;
mGLContext = aGLContext;
}
bool
HwcComposer2D::ReallocLayerList()
{
@@ -328,6 +315,10 @@ HwcComposer2D::PrepareLayerList(Layer* aLayer,
}
uint8_t opacity = std::min(0xFF, (int)(aLayer->GetEffectiveOpacity() * 256.0));
if (opacity == 0) {
LOGD("%s Layer has zero opacity; skipping", aLayer->Name());
return true;
}
#if ANDROID_VERSION < 18
if (opacity < 0xFF) {
LOGD("%s Layer has planar semitransparency which is unsupported by hwcomposer", aLayer->Name());
@@ -668,10 +659,10 @@ HwcComposer2D::PrepareLayerList(Layer* aLayer,
bool
HwcComposer2D::TryHwComposition()
{
FramebufferSurface* fbsurface = (FramebufferSurface*)(GetGonkDisplay()->GetFBSurface());
DisplaySurface* dispSurface = (DisplaySurface*)(GetGonkDisplay()->GetDispSurface());
if (!(fbsurface && fbsurface->lastHandle)) {
LOGD("H/W Composition failed. FBSurface not initialized.");
if (!(dispSurface && dispSurface->lastHandle)) {
LOGD("H/W Composition failed. DispSurface not initialized.");
return false;
}
@@ -684,7 +675,7 @@ HwcComposer2D::TryHwComposition()
}
}
Prepare(fbsurface->lastHandle, -1);
Prepare(dispSurface->lastHandle, -1);
/* Possible composition paths, after hwc prepare:
1. GPU Composition
@@ -738,53 +729,44 @@ HwcComposer2D::TryHwComposition()
// GPU or partial OVERLAY Composition
return false;
} else if (blitComposite) {
// Some EGLSurface implementations require glClear() on blit composition.
// See bug 1029856.
if (mGLContext) {
mGLContext->MakeCurrent();
mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
}
// BLIT Composition, flip FB target
GetGonkDisplay()->UpdateFBSurface(mDpy, mSur);
FramebufferSurface* fbsurface = (FramebufferSurface*)(GetGonkDisplay()->GetFBSurface());
if (!fbsurface) {
LOGE("H/W Composition failed. NULL FBSurface.");
// BLIT Composition, flip DispSurface target
GetGonkDisplay()->UpdateDispSurface(mDpy, mSur);
DisplaySurface* dispSurface = (DisplaySurface*)(GetGonkDisplay()->GetDispSurface());
if (!dispSurface) {
LOGE("H/W Composition failed. NULL DispSurface.");
return false;
}
mList->hwLayers[idx].handle = fbsurface->lastHandle;
mList->hwLayers[idx].acquireFenceFd = fbsurface->GetPrevFBAcquireFd();
mList->hwLayers[idx].handle = dispSurface->lastHandle;
mList->hwLayers[idx].acquireFenceFd = dispSurface->GetPrevDispAcquireFd();
}
}
// BLIT or full OVERLAY Composition
Commit();
GetGonkDisplay()->SetFBReleaseFd(mList->hwLayers[idx].releaseFenceFd);
GetGonkDisplay()->SetDispReleaseFd(mList->hwLayers[idx].releaseFenceFd);
mList->hwLayers[idx].releaseFenceFd = -1;
return true;
}
bool
HwcComposer2D::Render(EGLDisplay dpy, EGLSurface sur)
HwcComposer2D::Render()
{
if (!mList) {
// After boot, HWC list hasn't been created yet
return GetGonkDisplay()->SwapBuffers(dpy, sur);
// HWC module does not exist or mList is not created yet.
if (!mHwc || !mList) {
return GetGonkDisplay()->SwapBuffers(mDpy, mSur);
}
GetGonkDisplay()->UpdateFBSurface(dpy, sur);
FramebufferSurface* fbsurface = (FramebufferSurface*)(GetGonkDisplay()->GetFBSurface());
if (!fbsurface) {
LOGE("H/W Composition failed. FBSurface not initialized.");
DisplaySurface* dispSurface = (DisplaySurface*)(GetGonkDisplay()->GetDispSurface());
if (!dispSurface) {
LOGE("H/W Composition failed. DispSurface not initialized.");
return false;
}
if (mPrepared) {
// No mHwc prepare, if already prepared in current draw cycle
mList->hwLayers[mList->numHwLayers - 1].handle = fbsurface->lastHandle;
mList->hwLayers[mList->numHwLayers - 1].acquireFenceFd = fbsurface->GetPrevFBAcquireFd();
mList->hwLayers[mList->numHwLayers - 1].handle = dispSurface->lastHandle;
mList->hwLayers[mList->numHwLayers - 1].acquireFenceFd = dispSurface->GetPrevDispAcquireFd();
} else {
mList->flags = HWC_GEOMETRY_CHANGED;
mList->numHwLayers = 2;
@@ -795,19 +777,19 @@ HwcComposer2D::Render(EGLDisplay dpy, EGLSurface sur)
mList->hwLayers[0].acquireFenceFd = -1;
mList->hwLayers[0].releaseFenceFd = -1;
mList->hwLayers[0].displayFrame = {0, 0, mScreenRect.width, mScreenRect.height};
Prepare(fbsurface->lastHandle, fbsurface->GetPrevFBAcquireFd());
Prepare(dispSurface->lastHandle, dispSurface->GetPrevDispAcquireFd());
}
// GPU or partial HWC Composition
Commit();
GetGonkDisplay()->SetFBReleaseFd(mList->hwLayers[mList->numHwLayers - 1].releaseFenceFd);
GetGonkDisplay()->SetDispReleaseFd(mList->hwLayers[mList->numHwLayers - 1].releaseFenceFd);
mList->hwLayers[mList->numHwLayers - 1].releaseFenceFd = -1;
return true;
}
void
HwcComposer2D::Prepare(buffer_handle_t fbHandle, int fence)
HwcComposer2D::Prepare(buffer_handle_t dispHandle, int fence)
{
int idx = mList->numHwLayers - 1;
const hwc_rect_t r = {0, 0, mScreenRect.width, mScreenRect.height};
@@ -821,7 +803,7 @@ HwcComposer2D::Prepare(buffer_handle_t fbHandle, int fence)
mList->hwLayers[idx].hints = 0;
mList->hwLayers[idx].flags = 0;
mList->hwLayers[idx].transform = 0;
mList->hwLayers[idx].handle = fbHandle;
mList->hwLayers[idx].handle = dispHandle;
mList->hwLayers[idx].blending = HWC_BLENDING_PREMULT;
mList->hwLayers[idx].compositionType = HWC_FRAMEBUFFER_TARGET;
setCrop(&mList->hwLayers[idx], r);
@@ -856,41 +838,34 @@ HwcComposer2D::Commit()
if (!state.mTexture) {
continue;
}
TextureHostOGL* texture = state.mTexture->AsHostOGL();
if (!texture) {
continue;
}
sp<Fence> fence = texture->GetAndResetAcquireFence();
if (fence.get() && fence->isValid()) {
mList->hwLayers[j].acquireFenceFd = fence->dup();
FenceHandle fence = state.mTexture->GetAndResetAcquireFenceHandle();
if (fence.IsValid()) {
nsRefPtr<FenceHandle::FdObj> fdObj = fence.GetAndResetFdObj();
mList->hwLayers[j].acquireFenceFd = fdObj->GetAndResetFd();
}
}
int err = mHwc->set(mHwc, HWC_NUM_DISPLAY_TYPES, displays);
mPrevDisplayFence = mPrevRetireFence;
mPrevRetireFence = Fence::NO_FENCE;
mPrevRetireFence.TransferToAnotherFenceHandle(mPrevDisplayFence);
for (uint32_t j=0; j < (mList->numHwLayers - 1); j++) {
if (mList->hwLayers[j].releaseFenceFd >= 0) {
int fd = mList->hwLayers[j].releaseFenceFd;
mList->hwLayers[j].releaseFenceFd = -1;
sp<Fence> fence = new Fence(fd);
nsRefPtr<FenceHandle::FdObj> fdObj = new FenceHandle::FdObj(fd);
FenceHandle fence(fdObj);
LayerRenderState state = mHwcLayerMap[j]->GetLayer()->GetRenderState();
if (!state.mTexture) {
continue;
}
TextureHostOGL* texture = state.mTexture->AsHostOGL();
if (!texture) {
continue;
}
texture->SetReleaseFence(fence);
}
}
state.mTexture->SetReleaseFenceHandle(fence);
}
}
if (mList->retireFenceFd >= 0) {
mPrevRetireFence = new Fence(mList->retireFenceFd);
mPrevRetireFence = FenceHandle(new FenceHandle::FdObj(mList->retireFenceFd));
}
mPrepared = false;
@@ -914,9 +889,9 @@ HwcComposer2D::TryHwComposition()
}
bool
HwcComposer2D::Render(EGLDisplay dpy, EGLSurface sur)
HwcComposer2D::Render()
{
return GetGonkDisplay()->SwapBuffers(dpy, sur);
return GetGonkDisplay()->SwapBuffers(mDpy, mSur);
}
void
@@ -927,10 +902,13 @@ HwcComposer2D::Reset()
#endif
bool
HwcComposer2D::TryRender(Layer* aRoot,
bool aGeometryChanged)
HwcComposer2D::TryRenderWithHwc(Layer* aRoot,
bool aGeometryChanged)
{
MOZ_ASSERT(Initialized());
if (!mHwc) {
return false;
}
if (mList) {
setHwcGeometry(aGeometryChanged);
mList->numHwLayers = 0;
@@ -959,7 +937,7 @@ HwcComposer2D::TryRender(Layer* aRoot,
SendtoLayerScope();
if (!TryHwComposition()) {
LOGD("H/W Composition failed");
LOGD("Full HWC Composition failed. Fallback to GPU Composition or partial OVERLAY Composition");
LayerScope::CleanLayer();
return false;
}
+16 -16
View File
@@ -20,6 +20,7 @@
#include "Composer2D.h"
#include "Layers.h"
#include "mozilla/Mutex.h"
#include "mozilla/layers/FenceUtils.h" // for FenceHandle
#include <vector>
#include <list>
@@ -76,19 +77,17 @@ public:
HwcComposer2D();
virtual ~HwcComposer2D();
int Init(hwc_display_t aDisplay, hwc_surface_t aSurface, gl::GLContext* aGLContext);
bool Initialized() const { return mHwc; }
static HwcComposer2D* GetInstance();
// Returns TRUE if the container has been succesfully rendered
// Returns FALSE if the container cannot be fully rendered
// by this composer so nothing was rendered at all
bool TryRender(layers::Layer* aRoot,
bool aGeometryChanged) override;
virtual bool TryRenderWithHwc(layers::Layer* aRoot,
bool aGeometryChanged) override;
bool Render(EGLDisplay dpy, EGLSurface sur);
virtual bool Render() override;
virtual bool HasHwc() override { return mHwc; }
bool EnableVsync(bool aEnable);
#if ANDROID_VERSION >= 17
@@ -98,9 +97,13 @@ public:
#endif
void SetCompositorParent(layers::CompositorParent* aCompositorParent);
// Set EGL info of primary display. Used for BLIT Composition.
// XXX Add multiple displays compostion support.
void SetEGLInfo(hwc_display_t aDisplay, hwc_surface_t aSurface, gl::GLContext* aGLContext);
private:
void Reset();
void Prepare(buffer_handle_t fbHandle, int fence);
void Prepare(buffer_handle_t dispHandle, int fence);
bool Commit();
bool TryHwComposition();
bool ReallocLayerList();
@@ -112,9 +115,9 @@ private:
HwcDevice* mHwc;
HwcList* mList;
hwc_display_t mDpy;
hwc_surface_t mSur;
gl::GLContext* mGLContext;
hwc_display_t mDpy; // Store for BLIT Composition and GonkDisplayICS
hwc_surface_t mSur; // Store for BLIT Composition and GonkDisplayICS
gl::GLContext* mGLContext; // Store for BLIT Composition
nsIntRect mScreenRect;
int mMaxLayerCount;
bool mColorFill;
@@ -122,11 +125,8 @@ private:
//Holds all the dynamically allocated RectVectors needed
//to render the current frame
std::list<RectVector> mVisibleRegions;
#if ANDROID_VERSION >= 17
android::sp<android::Fence> mPrevRetireFence;
android::sp<android::Fence> mPrevDisplayFence;
nsecs_t mLastVsyncTime;
#endif
layers::FenceHandle mPrevRetireFence;
layers::FenceHandle mPrevDisplayFence;
nsTArray<layers::LayerComposite*> mHwcLayerMap;
bool mPrepared;
bool mHasHWVsync;
+114
View File
@@ -0,0 +1,114 @@
/*
* Copyright 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_SF_DISPLAY_SURFACE_H
#define ANDROID_SF_DISPLAY_SURFACE_H
#include <gui/ConsumerBase.h>
#include <system/window.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <utils/StrongPointer.h>
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
class IGraphicBufferProducer;
class String8;
#if ANDROID_VERSION >= 21
typedef IGraphicBufferConsumer StreamConsumer;
#else
typedef BufferQueue StreamConsumer;
#endif
class DisplaySurface : public ConsumerBase {
public:
// beginFrame is called at the beginning of the composition loop, before
// the configuration is known. The DisplaySurface should do anything it
// needs to do to enable HWComposer to decide how to compose the frame.
// We pass in mustRecompose so we can keep VirtualDisplaySurface's state
// machine happy without actually queueing a buffer if nothing has changed.
virtual status_t beginFrame(bool mustRecompose) = 0;
// prepareFrame is called after the composition configuration is known but
// before composition takes place. The DisplaySurface can use the
// composition type to decide how to manage the flow of buffers between
// GLES and HWC for this frame.
enum CompositionType {
COMPOSITION_UNKNOWN = 0,
COMPOSITION_GLES = 1,
COMPOSITION_HWC = 2,
COMPOSITION_MIXED = COMPOSITION_GLES | COMPOSITION_HWC
};
virtual status_t prepareFrame(CompositionType compositionType) = 0;
// Should be called when composition rendering is complete for a frame (but
// eglSwapBuffers hasn't necessarily been called). Required by certain
// older drivers for synchronization.
// TODO: Remove this when we drop support for HWC 1.0.
virtual status_t compositionComplete() = 0;
// Inform the surface that GLES composition is complete for this frame, and
// the surface should make sure that HWComposer has the correct buffer for
// this frame. Some implementations may only push a new buffer to
// HWComposer if GLES composition took place, others need to push a new
// buffer on every frame.
//
// advanceFrame must be followed by a call to onFrameCommitted before
// advanceFrame may be called again.
virtual status_t advanceFrame() = 0;
// onFrameCommitted is called after the frame has been committed to the
// hardware composer. The surface collects the release fence for this
// frame's buffer.
virtual void onFrameCommitted() = 0;
virtual void dump(String8& result) const = 0;
virtual void resizeBuffers(const uint32_t w, const uint32_t h) = 0;
// setReleaseFenceFd stores a fence file descriptor that will signal when the
// current buffer is no longer being read. This fence will be returned to
// the producer when the current buffer is released by updateTexImage().
// Multiple fences can be set for a given buffer; they will be merged into
// a single union fence. The SurfaceTexture will close the file descriptor
// when finished with it.
virtual status_t setReleaseFenceFd(int fenceFd) = 0;
virtual int GetPrevDispAcquireFd() = 0;
buffer_handle_t lastHandle;
protected:
DisplaySurface(const sp<StreamConsumer>& sc)
#if ANDROID_VERSION >= 19
: ConsumerBase(sc, true)
#else
: ConsumerBase(sc)
#endif
, lastHandle(0)
{ }
virtual ~DisplaySurface() {}
};
// ---------------------------------------------------------------------------
} // namespace android
// ---------------------------------------------------------------------------
#endif // ANDROID_SF_DISPLAY_SURFACE_H
+22 -15
View File
@@ -54,15 +54,10 @@ FramebufferSurface::FramebufferSurface(int disp,
uint32_t height,
uint32_t format,
const sp<StreamConsumer>& sc)
#if ANDROID_VERSION >= 19
: ConsumerBase(sc, true)
#else
: ConsumerBase(sc)
#endif
: DisplaySurface(sc)
, mDisplayType(disp)
, mCurrentBufferSlot(-1)
, mCurrentBuffer(0)
, lastHandle(0)
{
mName = "FramebufferSurface";
@@ -81,6 +76,21 @@ FramebufferSurface::FramebufferSurface(int disp,
consumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS);
}
status_t FramebufferSurface::beginFrame(bool /*mustRecompose*/) {
return NO_ERROR;
}
status_t FramebufferSurface::prepareFrame(CompositionType /*compositionType*/) {
return NO_ERROR;
}
status_t FramebufferSurface::advanceFrame() {
// Once we remove FB HAL support, we can call nextBuffer() from here
// instead of using onFrameAvailable(). No real benefit, except it'll be
// more like VirtualDisplaySurface.
return NO_ERROR;
}
status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence) {
Mutex::Autolock lock(mMutex);
@@ -170,28 +180,25 @@ status_t FramebufferSurface::setReleaseFenceFd(int fenceFd) {
return err;
}
int FramebufferSurface::GetPrevFBAcquireFd() {
int FramebufferSurface::GetPrevDispAcquireFd() {
if (mPrevFBAcquireFence.get() && mPrevFBAcquireFence->isValid()) {
return mPrevFBAcquireFence->dup();
}
return -1;
}
status_t FramebufferSurface::setUpdateRectangle(const Rect& r)
{
return INVALID_OPERATION;
void FramebufferSurface::onFrameCommitted() {
// XXX This role is almost same to setReleaseFenceFd().
}
status_t FramebufferSurface::compositionComplete()
{
// Actual implementaiton is in GonkDisplay::SwapBuffers()
// XXX need to move that to here.
return NO_ERROR;
}
void FramebufferSurface::dump(String8& result) {
ConsumerBase::dump(result);
}
void FramebufferSurface::dump(String8& result, const char* prefix) {
void FramebufferSurface::dump(String8& result) const {
ConsumerBase::dump(result);
}
+15 -16
View File
@@ -20,7 +20,7 @@
#include <stdint.h>
#include <sys/types.h>
#include <gui/ConsumerBase.h>
#include "DisplaySurface.h"
// ---------------------------------------------------------------------------
namespace android {
@@ -29,24 +29,24 @@ namespace android {
class Rect;
class String8;
#if ANDROID_VERSION >= 21
typedef IGraphicBufferConsumer StreamConsumer;
#else
typedef BufferQueue StreamConsumer;
#endif
// ---------------------------------------------------------------------------
class FramebufferSurface : public ConsumerBase {
class FramebufferSurface : public DisplaySurface {
public:
FramebufferSurface(int disp, uint32_t width, uint32_t height, uint32_t format, const sp<StreamConsumer>& sc);
bool isUpdateOnDemand() const { return false; }
status_t setUpdateRectangle(const Rect& updateRect);
status_t compositionComplete();
virtual void dump(String8& result);
virtual void dump(String8& result, const char* prefix);
// From DisplaySurface
virtual status_t beginFrame(bool mustRecompose);
virtual status_t prepareFrame(CompositionType compositionType);
virtual status_t compositionComplete();
virtual status_t advanceFrame();
virtual void onFrameCommitted();
// Implementation of DisplaySurface::dump(). Note that ConsumerBase also
// has a non-virtual dump() with the same signature.
virtual void dump(String8& result) const;
// Cannot resize a buffers in a FramebufferSurface. Only works with virtual
// displays.
virtual void resizeBuffers(const uint32_t /*w*/, const uint32_t /*h*/) { };
// setReleaseFenceFd stores a fence file descriptor that will signal when the
// current buffer is no longer being read. This fence will be returned to
@@ -56,9 +56,8 @@ public:
// when finished with it.
status_t setReleaseFenceFd(int fenceFd);
virtual int GetPrevFBAcquireFd();
virtual int GetPrevDispAcquireFd();
buffer_handle_t lastHandle;
private:
virtual ~FramebufferSurface() { }; // this class cannot be overloaded
+7 -4
View File
@@ -36,28 +36,31 @@ public:
virtual void* GetHWCDevice() = 0;
virtual void* GetFBSurface() = 0;
virtual void* GetDispSurface() = 0;
/**
* Only GonkDisplayICS uses arguments.
*/
virtual bool SwapBuffers(EGLDisplay dpy, EGLSurface sur) = 0;
virtual ANativeWindowBuffer* DequeueBuffer() = 0;
virtual bool QueueBuffer(ANativeWindowBuffer* buf) = 0;
virtual void UpdateFBSurface(EGLDisplay dpy, EGLSurface sur) = 0;
virtual void UpdateDispSurface(EGLDisplay dpy, EGLSurface sur) = 0;
/**
* Set FramebufferSurface ReleaseFence's file descriptor.
* ReleaseFence will be signaled after the HWC has finished reading
* from a buffer.
*/
virtual void SetFBReleaseFd(int fd) = 0;
virtual void SetDispReleaseFd(int fd) = 0;
/**
* Get FramebufferSurface AcquireFence's file descriptor
* AcquireFence will be signaled when a buffer's content is available.
*/
virtual int GetPrevFBAcquireFd() = 0;
virtual int GetPrevDispAcquireFd() = 0;
float xdpi;
int32_t surfaceformat;
+5 -10
View File
@@ -173,12 +173,6 @@ GonkDisplayICS::GetHWCDevice()
return mHwc;
}
void*
GonkDisplayICS::GetFBSurface()
{
return mFBSurface.get();
}
bool
GonkDisplayICS::SwapBuffers(EGLDisplay dpy, EGLSurface sur)
{
@@ -186,8 +180,9 @@ GonkDisplayICS::SwapBuffers(EGLDisplay dpy, EGLSurface sur)
// Only HWC v1.0 needs this call. ICS gonk always needs the call.
mFBSurface->compositionComplete();
if (!mHwc)
return eglSwapBuffers(dpy, sur);
if (!mHwc) {
return true;
}
mHwc->prepare(mHwc, nullptr);
return !mHwc->set(mHwc, dpy, sur, 0);
@@ -210,13 +205,13 @@ GonkDisplayICS::QueueBuffer(ANativeWindowBuffer *buf)
}
void
GonkDisplayICS::UpdateFBSurface(EGLDisplay dpy, EGLSurface sur)
GonkDisplayICS::UpdateDispSurface(EGLDisplay dpy, EGLSurface sur)
{
eglSwapBuffers(dpy, sur);
}
void
GonkDisplayICS::SetFBReleaseFd(int fd)
GonkDisplayICS::SetDispReleaseFd(int fd)
{
}

Some files were not shown because too many files have changed in this diff Show More