mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 23:05:42 +00:00
Bug 1265824 - Wait on texture handles with IPC r=jld,mattwoodrow
There's a lot going on here, but it all fits under the idea of being able to communicate about texture locking statuses without spinning on IsReadLocked. This is a bit of a trade - we could just always allocate/grab a texture from the pool, which would put a smaller cap on the amount of time we can possibly spend when a texture is locked. However, this eats up more CPU and memory than waiting on the textures to unlock, and could take longer, especially if there were a large number of textures which we just need to wait for for a short amount of time. In any case, we very rarely hit the case where we actually need to wait on the sync IPC to the compositor - most of the time the textures are already unlocked. There is also an async IPC call in here, which we make before flushing async paints. This just causes the compositor to check whether the GPU is done with its textures or not and unlock them if it is. This helps us avoid the case where we take a long time painting asynchronously, turn IPC back on at the end of that, and then have to wait for the compositor to to get into TiledLayerBufferComposite::UseTiles before getting a response. Specifically this eliminates several talos regressions which use ASAP mode. Lastly, there seem to be no other cases of static Monitors being used. This seems like it falls under similar use cases as StaticMutexes, so I added it in. I can move it into its own file if we think it might be generally useful in the future. MozReview-Commit-ID: IYQLwUqMxg2 --HG-- extra : rebase_source : 67f6fee8b89933561a48e6f7f531b6969893a574
This commit is contained in:
parent
f0121c2b2b
commit
ac1648320e
@ -6,6 +6,10 @@
|
||||
|
||||
#include "mozilla/layers/TextureSourceProvider.h"
|
||||
#include "mozilla/layers/TextureHost.h"
|
||||
#include "mozilla/layers/PTextureParent.h"
|
||||
#ifdef XP_DARWIN
|
||||
#include "mozilla/layers/TextureSync.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
@ -18,9 +22,30 @@ TextureSourceProvider::~TextureSourceProvider()
|
||||
void
|
||||
TextureSourceProvider::ReadUnlockTextures()
|
||||
{
|
||||
#ifdef XP_DARWIN
|
||||
nsClassHashtable<nsUint32HashKey, nsTArray<uint64_t>> texturesIdsToUnlockByPid;
|
||||
for (auto& texture : mUnlockAfterComposition) {
|
||||
auto bufferTexture = texture->AsBufferTextureHost();
|
||||
if (bufferTexture && bufferTexture->IsDirectMap()) {
|
||||
texture->ReadUnlock();
|
||||
auto actor = texture->GetIPDLActor();
|
||||
if (actor) {
|
||||
base::ProcessId pid = actor->OtherPid();
|
||||
nsTArray<uint64_t>* textureIds = texturesIdsToUnlockByPid.LookupOrAdd(pid);
|
||||
textureIds->AppendElement(TextureHost::GetTextureSerial(actor));
|
||||
}
|
||||
} else {
|
||||
texture->ReadUnlock();
|
||||
}
|
||||
}
|
||||
for (auto it = texturesIdsToUnlockByPid.ConstIter(); !it.Done(); it.Next()) {
|
||||
TextureSync::SetTexturesUnlocked(it.Key(), *it.UserData());
|
||||
}
|
||||
#else
|
||||
for (auto& texture : mUnlockAfterComposition) {
|
||||
texture->ReadUnlock();
|
||||
}
|
||||
#endif
|
||||
mUnlockAfterComposition.Clear();
|
||||
}
|
||||
|
||||
|
@ -74,6 +74,9 @@ public:
|
||||
/// Returns true if notified, false otherwise.
|
||||
virtual bool NotifyNotUsedAfterComposition(TextureHost* aTextureHost);
|
||||
|
||||
virtual void MaybeUnlockBeforeNextComposition(TextureHost* aTextureHost) {}
|
||||
virtual void TryUnlockTextures() {}
|
||||
|
||||
// If overridden, make sure to call the base function.
|
||||
virtual void Destroy();
|
||||
|
||||
|
287
gfx/layers/TextureSync.cpp
Normal file
287
gfx/layers/TextureSync.cpp
Normal file
@ -0,0 +1,287 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "TextureSync.h"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include "chrome/common/mach_ipc_mac.h"
|
||||
#include "mozilla/ipc/SharedMemoryBasic.h"
|
||||
#include "mozilla/layers/CompositorThread.h"
|
||||
#include "mozilla/StaticMonitor.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define LOG_ERROR(str, args...) \
|
||||
PR_BEGIN_MACRO \
|
||||
mozilla::SmprintfPointer msg = mozilla::Smprintf(str, ## args); \
|
||||
NS_WARNING(msg.get()); \
|
||||
PR_END_MACRO
|
||||
#else
|
||||
#define LOG_ERROR(str, args...) do { /* nothing */ } while(0)
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace layers {
|
||||
|
||||
// Hold raw pointers and trust that TextureSourceProviders will be
|
||||
// unregistered in their destructors - we don't want to keep these
|
||||
// alive, and destroying them from the main thread will be an
|
||||
// error anyway.
|
||||
StaticAutoPtr<nsTArray<TextureSourceProvider*>> gTextureSourceProviders;
|
||||
|
||||
static std::map<pid_t, std::unordered_set<uint64_t>> gProcessTextureIds;
|
||||
static StaticMonitor gTextureLockMonitor;
|
||||
|
||||
const int kSendMessageTimeout = 1000;
|
||||
const int kTextureLockTimeout = 32; // We really don't want to wait more than
|
||||
// two frames for a texture to unlock. This
|
||||
// will in any case be very uncommon.
|
||||
|
||||
struct WaitForTexturesReply
|
||||
{
|
||||
bool success;
|
||||
};
|
||||
|
||||
struct WaitForTexturesRequest
|
||||
{
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
std::unordered_set<uint64_t>*
|
||||
GetLockedTextureIdsForProcess(pid_t pid)
|
||||
{
|
||||
gTextureLockMonitor.AssertCurrentThreadOwns();
|
||||
|
||||
if (gProcessTextureIds.find(pid) == gProcessTextureIds.end()) {
|
||||
gProcessTextureIds[pid] = std::unordered_set<uint64_t>();
|
||||
}
|
||||
|
||||
return &gProcessTextureIds.at(pid);
|
||||
}
|
||||
|
||||
bool
|
||||
WaitForTextureIdsToUnlock(pid_t pid, const Span<const uint64_t>& textureIds)
|
||||
{
|
||||
{
|
||||
StaticMonitorAutoLock lock(gTextureLockMonitor);
|
||||
std::unordered_set<uint64_t>* freedTextureIds = GetLockedTextureIdsForProcess(pid);
|
||||
|
||||
TimeStamp start = TimeStamp::Now();
|
||||
while (true) {
|
||||
bool allCleared = true;
|
||||
for (uint64_t textureId : textureIds) {
|
||||
if (freedTextureIds->find(textureId) != freedTextureIds->end()) {
|
||||
allCleared = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (allCleared) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (lock.Wait(TimeDuration::FromMilliseconds(kTextureLockTimeout)) == CVStatus::Timeout) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// In case the monitor gets signaled multiple times, each less than kTextureLockTimeout.
|
||||
// This ensures that the total time we wait is < 2 * kTextureLockTimeout
|
||||
if ((TimeStamp::Now() - start).ToMilliseconds() > (double)kTextureLockTimeout) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CheckTexturesForUnlock()
|
||||
{
|
||||
if (gTextureSourceProviders) {
|
||||
for (auto it = gTextureSourceProviders->begin(); it != gTextureSourceProviders->end(); ++it) {
|
||||
(*it)->TryUnlockTextures();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TextureSync::DispatchCheckTexturesForUnlock()
|
||||
{
|
||||
RefPtr<Runnable> task = NS_NewRunnableFunction(
|
||||
"CheckTexturesForUnlock",
|
||||
&CheckTexturesForUnlock);
|
||||
CompositorThreadHolder::Loop()->PostTask(task.forget());
|
||||
}
|
||||
|
||||
void
|
||||
TextureSync::HandleWaitForTexturesMessage(MachReceiveMessage* rmsg, ipc::MemoryPorts* ports)
|
||||
{
|
||||
WaitForTexturesRequest* req = reinterpret_cast<WaitForTexturesRequest*>(rmsg->GetData());
|
||||
uint64_t* textureIds = (uint64_t*)(req + 1);
|
||||
uint32_t textureIdsLength = (rmsg->GetDataLength() - sizeof(WaitForTexturesRequest)) / sizeof(uint64_t);
|
||||
|
||||
bool success = WaitForTextureIdsToUnlock(req->pid, MakeSpan<uint64_t>(textureIds, textureIdsLength));
|
||||
|
||||
if (!success) {
|
||||
LOG_ERROR("Waiting for textures to unlock failed.\n");
|
||||
}
|
||||
|
||||
MachSendMessage msg(ipc::kReturnWaitForTexturesMsg);
|
||||
WaitForTexturesReply replydata;
|
||||
replydata.success = success;
|
||||
msg.SetData(&replydata, sizeof(WaitForTexturesReply));
|
||||
kern_return_t err = ports->mSender->SendMessage(msg, kSendMessageTimeout);
|
||||
if (KERN_SUCCESS != err) {
|
||||
LOG_ERROR("SendMessage failed 0x%x %s\n", err, mach_error_string(err));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TextureSync::RegisterTextureSourceProvider(TextureSourceProvider* textureSourceProvider)
|
||||
{
|
||||
if (!gTextureSourceProviders) {
|
||||
gTextureSourceProviders = new nsTArray<TextureSourceProvider*>();
|
||||
}
|
||||
MOZ_RELEASE_ASSERT(!gTextureSourceProviders->Contains(textureSourceProvider));
|
||||
gTextureSourceProviders->AppendElement(textureSourceProvider);
|
||||
}
|
||||
|
||||
void
|
||||
TextureSync::UnregisterTextureSourceProvider(TextureSourceProvider* textureSourceProvider)
|
||||
{
|
||||
if (gTextureSourceProviders) {
|
||||
MOZ_ASSERT(gTextureSourceProviders->Contains(textureSourceProvider));
|
||||
gTextureSourceProviders->RemoveElement(textureSourceProvider);
|
||||
if (gTextureSourceProviders->Length() == 0) {
|
||||
gTextureSourceProviders = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TextureSync::SetTexturesLocked(pid_t pid, const nsTArray<uint64_t>& textureIds)
|
||||
{
|
||||
StaticMonitorAutoLock mal(gTextureLockMonitor);
|
||||
std::unordered_set<uint64_t>* lockedTextureIds = GetLockedTextureIdsForProcess(pid);
|
||||
for (uint64_t textureId : textureIds) {
|
||||
lockedTextureIds->insert(textureId);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TextureSync::SetTexturesUnlocked(pid_t pid, const nsTArray<uint64_t>& textureIds)
|
||||
{
|
||||
bool oneErased = false;
|
||||
{
|
||||
StaticMonitorAutoLock mal(gTextureLockMonitor);
|
||||
std::unordered_set<uint64_t>* lockedTextureIds = GetLockedTextureIdsForProcess(pid);
|
||||
for (uint64_t textureId : textureIds) {
|
||||
if (lockedTextureIds->erase(textureId)) {
|
||||
oneErased = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oneErased) {
|
||||
gTextureLockMonitor.NotifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TextureSync::Shutdown()
|
||||
{
|
||||
{
|
||||
StaticMonitorAutoLock lock(gTextureLockMonitor);
|
||||
|
||||
for (auto& lockedTextureIds : gProcessTextureIds) {
|
||||
lockedTextureIds.second.clear();
|
||||
}
|
||||
}
|
||||
|
||||
gTextureLockMonitor.NotifyAll();
|
||||
|
||||
{
|
||||
StaticMonitorAutoLock lock(gTextureLockMonitor);
|
||||
gProcessTextureIds.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TextureSync::UpdateTextureLocks(base::ProcessId aProcessId)
|
||||
{
|
||||
if (aProcessId == getpid()) {
|
||||
DispatchCheckTexturesForUnlock();
|
||||
return;
|
||||
}
|
||||
|
||||
MachSendMessage smsg(ipc::kUpdateTextureLocksMsg);
|
||||
smsg.SetData(&aProcessId, sizeof(aProcessId));
|
||||
ipc::SharedMemoryBasic::SendMachMessage(aProcessId, smsg, NULL);
|
||||
}
|
||||
|
||||
bool
|
||||
TextureSync::WaitForTextures(base::ProcessId aProcessId, const nsTArray<uint64_t>& textureIds)
|
||||
{
|
||||
if (aProcessId == getpid()) {
|
||||
bool success = WaitForTextureIdsToUnlock(aProcessId, MakeSpan<uint64_t>(textureIds));
|
||||
if (!success) {
|
||||
LOG_ERROR("Failed waiting for textures to unlock.\n");
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
MachSendMessage smsg(ipc::kWaitForTexturesMsg);
|
||||
size_t messageSize = sizeof(WaitForTexturesRequest) + textureIds.Length() * sizeof(uint64_t);
|
||||
UniquePtr<uint8_t[]> messageData = MakeUnique<uint8_t[]>(messageSize);
|
||||
WaitForTexturesRequest* req = (WaitForTexturesRequest*)messageData.get();
|
||||
uint64_t* reqTextureIds = (uint64_t*)(req + 1);
|
||||
|
||||
for (uint32_t i = 0; i < textureIds.Length(); ++i) {
|
||||
reqTextureIds[i] = textureIds[i];
|
||||
}
|
||||
|
||||
req->pid = getpid();
|
||||
bool dataWasSet = smsg.SetData(req, messageSize);
|
||||
|
||||
if (!dataWasSet) {
|
||||
LOG_ERROR("Data was too large: %zu\n", messageSize);
|
||||
return false;
|
||||
}
|
||||
|
||||
MachReceiveMessage msg;
|
||||
bool success = ipc::SharedMemoryBasic::SendMachMessage(aProcessId, smsg, &msg);
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (msg.GetDataLength() != sizeof(WaitForTexturesReply)) {
|
||||
LOG_ERROR("Improperly formatted reply\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
WaitForTexturesReply* msg_data = reinterpret_cast<WaitForTexturesReply*>(msg.GetData());
|
||||
if (!msg_data->success) {
|
||||
LOG_ERROR("Failed waiting for textures to unlock.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TextureSync::CleanupForPid(base::ProcessId aProcessId)
|
||||
{
|
||||
{
|
||||
StaticMonitorAutoLock lock(gTextureLockMonitor);
|
||||
std::unordered_set<uint64_t>* lockedTextureIds = GetLockedTextureIdsForProcess(aProcessId);
|
||||
lockedTextureIds->clear();
|
||||
}
|
||||
gTextureLockMonitor.NotifyAll();
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
|
||||
} // namespace mozilla
|
44
gfx/layers/TextureSync.h
Normal file
44
gfx/layers/TextureSync.h
Normal file
@ -0,0 +1,44 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_TEXTURESYNC_H
|
||||
#define MOZILLA_LAYERS_TEXTURESYNC_H
|
||||
|
||||
#include "base/process.h"
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/layers/TextureSourceProvider.h"
|
||||
|
||||
#include "SharedMemory.h"
|
||||
|
||||
class MachReceiveMessage;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
struct MemoryPorts;
|
||||
} // namespace ipc
|
||||
|
||||
namespace layers {
|
||||
|
||||
class TextureSync
|
||||
{
|
||||
public:
|
||||
static void RegisterTextureSourceProvider(layers::TextureSourceProvider* aTextureSourceProvider);
|
||||
static void UnregisterTextureSourceProvider(layers::TextureSourceProvider* aTextureSourceProvider);
|
||||
static void DispatchCheckTexturesForUnlock();
|
||||
static void HandleWaitForTexturesMessage(MachReceiveMessage* rmsg, ipc::MemoryPorts* ports);
|
||||
static void UpdateTextureLocks(base::ProcessId aProcessId);
|
||||
static bool WaitForTextures(base::ProcessId aProcessId, const nsTArray<uint64_t>& aTextureIds);
|
||||
static void SetTexturesLocked(base::ProcessId aProcessId, const nsTArray<uint64_t>& aTextureIds);
|
||||
static void SetTexturesUnlocked(base::ProcessId aProcessId, const nsTArray<uint64_t>& aTextureIds);
|
||||
static void Shutdown();
|
||||
static void CleanupForPid(base::ProcessId aProcessId);
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -317,6 +317,15 @@ ClientLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData,
|
||||
EndTransactionFlags)
|
||||
{
|
||||
// This just causes the compositor to check whether the GPU is done with its
|
||||
// textures or not and unlock them if it is. This helps us avoid the case
|
||||
// where we take a long time painting asynchronously, turn IPC back on at
|
||||
// the end of that, and then have to wait for the compositor to to get into
|
||||
// TiledLayerBufferComposite::UseTiles before getting a response.
|
||||
if (mForwarder) {
|
||||
mForwarder->UpdateTextureLocks();
|
||||
}
|
||||
|
||||
// Wait for any previous async paints to complete before starting to paint again.
|
||||
// Do this outside the profiler and telemetry block so this doesn't count as time
|
||||
// spent rasterizing.
|
||||
|
@ -140,6 +140,42 @@ ClientMultiTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
||||
mCallbackData = nullptr;
|
||||
}
|
||||
|
||||
void ClientMultiTiledLayerBuffer::MaybeSyncTextures(const nsIntRegion& aPaintRegion,
|
||||
const TilesPlacement& aNewTiles,
|
||||
const IntSize& aScaledTileSize)
|
||||
{
|
||||
if (mManager->AsShadowForwarder()->SupportsTextureDirectMapping()) {
|
||||
AutoTArray<uint64_t, 10> syncTextureSerials;
|
||||
SurfaceMode mode;
|
||||
Unused << GetContentType(&mode);
|
||||
|
||||
// Pre-pass through the tiles (mirroring the filter logic below) to gather
|
||||
// texture IDs that we need to ensure are unused by the GPU before we
|
||||
// continue.
|
||||
if (!aPaintRegion.IsEmpty()) {
|
||||
MOZ_ASSERT(mPaintStates.size() == 0);
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); ++i) {
|
||||
const TileCoordIntPoint tileCoord = aNewTiles.TileCoord(i);
|
||||
|
||||
IntPoint tileOffset = GetTileOffset(tileCoord);
|
||||
nsIntRegion tileDrawRegion = IntRect(tileOffset, aScaledTileSize);
|
||||
tileDrawRegion.AndWith(aPaintRegion);
|
||||
|
||||
if (tileDrawRegion.IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TileClient& tile = mRetainedTiles[i];
|
||||
tile.GetSyncTextureSerials(mode, syncTextureSerials);
|
||||
}
|
||||
}
|
||||
|
||||
if (syncTextureSerials.Length() > 0) {
|
||||
mManager->AsShadowForwarder()->SyncTextures(syncTextureSerials);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClientMultiTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
|
||||
const nsIntRegion& aPaintRegion,
|
||||
const nsIntRegion& aDirtyRegion,
|
||||
@ -181,6 +217,9 @@ void ClientMultiTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
|
||||
|
||||
nsIntRegion paintRegion = aPaintRegion;
|
||||
nsIntRegion dirtyRegion = aDirtyRegion;
|
||||
|
||||
MaybeSyncTextures(paintRegion, newTiles, scaledTileSize);
|
||||
|
||||
if (!paintRegion.IsEmpty()) {
|
||||
MOZ_ASSERT(mPaintStates.size() == 0);
|
||||
for (size_t i = 0; i < newTileCount; ++i) {
|
||||
|
@ -156,6 +156,10 @@ private:
|
||||
nsIntRegion& aRegionToPaint,
|
||||
BasicTiledLayerPaintData* aPaintData,
|
||||
bool aIsRepeated);
|
||||
|
||||
void MaybeSyncTextures(const nsIntRegion& aPaintRegion,
|
||||
const TilesPlacement& aNewTiles,
|
||||
const gfx::IntSize& aScaledTileSize);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -140,6 +140,15 @@ ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
||||
mTile.SetTextureAllocator(this);
|
||||
}
|
||||
|
||||
|
||||
if (mManager->AsShadowForwarder()->SupportsTextureDirectMapping()) {
|
||||
AutoTArray<uint64_t, 2> syncTextureSerials;
|
||||
mTile.GetSyncTextureSerials(mode, syncTextureSerials);
|
||||
if (syncTextureSerials.Length() > 0) {
|
||||
mManager->AsShadowForwarder()->SyncTextures(syncTextureSerials);
|
||||
}
|
||||
}
|
||||
|
||||
// The dirty region relative to the top-left of the tile.
|
||||
nsIntRegion tileVisibleRegion = aNewValidRegion.MovedBy(-mTilingOrigin);
|
||||
nsIntRegion tileDirtyRegion = paintRegion.MovedBy(-mTilingOrigin);
|
||||
|
@ -664,6 +664,32 @@ CreateBackBufferTexture(TextureClient* aCurrentTexture,
|
||||
return texture.forget();
|
||||
}
|
||||
|
||||
void
|
||||
TileClient::GetSyncTextureSerials(SurfaceMode aMode, nsTArray<uint64_t>& aSerials)
|
||||
{
|
||||
if (mFrontBuffer &&
|
||||
mFrontBuffer->HasIntermediateBuffer() &&
|
||||
!mFrontBuffer->IsReadLocked() &&
|
||||
(aMode != SurfaceMode::SURFACE_COMPONENT_ALPHA || (
|
||||
mFrontBufferOnWhite && !mFrontBufferOnWhite->IsReadLocked())))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mBackBuffer &&
|
||||
!mBackBuffer->HasIntermediateBuffer() &&
|
||||
mBackBuffer->IsReadLocked()) {
|
||||
aSerials.AppendElement(mBackBuffer->GetSerial());
|
||||
}
|
||||
|
||||
if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA &&
|
||||
mBackBufferOnWhite &&
|
||||
!mBackBufferOnWhite->HasIntermediateBuffer() &&
|
||||
mBackBufferOnWhite->IsReadLocked()) {
|
||||
aSerials.AppendElement(mBackBufferOnWhite->GetSerial());
|
||||
}
|
||||
}
|
||||
|
||||
TextureClient*
|
||||
TileClient::GetBackBuffer(CompositableClient& aCompositable,
|
||||
const nsIntRegion& aDirtyRegion,
|
||||
@ -722,17 +748,18 @@ TileClient::GetBackBuffer(CompositableClient& aCompositable,
|
||||
mInvalidBack = IntRect(IntPoint(), mBackBuffer->GetSize());
|
||||
}
|
||||
|
||||
if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA
|
||||
&& (!mBackBufferOnWhite || mBackBufferOnWhite->IsReadLocked())) {
|
||||
mBackBufferOnWhite = CreateBackBufferTexture(
|
||||
mBackBufferOnWhite, aCompositable, mAllocator
|
||||
);
|
||||
if (!mBackBufferOnWhite) {
|
||||
DiscardBackBuffer();
|
||||
DiscardFrontBuffer();
|
||||
return nullptr;
|
||||
if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
|
||||
if (!mBackBufferOnWhite || mBackBufferOnWhite->IsReadLocked()) {
|
||||
mBackBufferOnWhite = CreateBackBufferTexture(
|
||||
mBackBufferOnWhite, aCompositable, mAllocator
|
||||
);
|
||||
if (!mBackBufferOnWhite) {
|
||||
DiscardBackBuffer();
|
||||
DiscardFrontBuffer();
|
||||
return nullptr;
|
||||
}
|
||||
mInvalidBack = IntRect(IntPoint(), mBackBufferOnWhite->GetSize());
|
||||
}
|
||||
mInvalidBack = IntRect(IntPoint(), mBackBufferOnWhite->GetSize());
|
||||
}
|
||||
|
||||
ValidateBackBufferFromFront(aDirtyRegion, aVisibleRegion, aAddPaintedRegion, aFlags, aCopies, aClients);
|
||||
|
@ -114,6 +114,8 @@ struct TileClient
|
||||
CompositableClient::DumpTextureClient(aStream, mFrontBuffer, aCompress);
|
||||
}
|
||||
|
||||
void GetSyncTextureSerials(SurfaceMode aMode, nsTArray<uint64_t>& aSerials);
|
||||
|
||||
/**
|
||||
* Returns an unlocked TextureClient that can be used for writing new
|
||||
* data to the tile. This may flip the front-buffer to the back-buffer if
|
||||
@ -325,6 +327,9 @@ public:
|
||||
LayerManager::DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData,
|
||||
TilePaintFlags aFlags) = 0;
|
||||
virtual void GetSyncTextureSerials(const nsIntRegion& aPaintRegion,
|
||||
const nsIntRegion& aDirtyRegion,
|
||||
nsTArray<uint64_t>& aSerials) { return; }
|
||||
|
||||
virtual bool SupportsProgressiveUpdate() = 0;
|
||||
virtual bool ProgressiveUpdate(const nsIntRegion& aValidRegion,
|
||||
|
@ -21,6 +21,9 @@
|
||||
#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
|
||||
#include "mozilla/layers/ImageDataSerializer.h"
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#ifdef XP_DARWIN
|
||||
#include "mozilla/layers/TextureSync.h"
|
||||
#endif
|
||||
#include "mozilla/layers/GPUVideoTextureHost.h"
|
||||
#include "mozilla/layers/WebRenderTextureHost.h"
|
||||
#include "mozilla/webrender/RenderBufferTextureHost.h"
|
||||
@ -370,11 +373,14 @@ TextureHost::TextureHost(TextureFlags aFlags)
|
||||
|
||||
TextureHost::~TextureHost()
|
||||
{
|
||||
// If we still have a ReadLock, unlock it. At this point we don't care about
|
||||
// the texture client being written into on the other side since it should be
|
||||
// destroyed by now. But we will hit assertions if we don't ReadUnlock before
|
||||
// destroying the lock itself.
|
||||
ReadUnlock();
|
||||
if (mReadLocked) {
|
||||
// If we still have a ReadLock, unlock it. At this point we don't care about
|
||||
// the texture client being written into on the other side since it should be
|
||||
// destroyed by now. But we will hit assertions if we don't ReadUnlock before
|
||||
// destroying the lock itself.
|
||||
ReadUnlock();
|
||||
MaybeNotifyUnlocked();
|
||||
}
|
||||
}
|
||||
|
||||
void TextureHost::Finalize()
|
||||
@ -400,6 +406,7 @@ TextureHost::UnbindTextureSource()
|
||||
// GetCompositor returned null which means no compositor can be using this
|
||||
// texture. We can ReadUnlock right away.
|
||||
ReadUnlock();
|
||||
MaybeNotifyUnlocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -701,6 +708,9 @@ TextureHost::SetReadLocked()
|
||||
// side should not have been able to write into this texture and read lock again!
|
||||
MOZ_ASSERT(!mReadLocked);
|
||||
mReadLocked = true;
|
||||
if (mProvider) {
|
||||
mProvider->MaybeUnlockBeforeNextComposition(this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -890,12 +900,25 @@ void
|
||||
BufferTextureHost::ReadUnlock()
|
||||
{
|
||||
if (mFirstSource) {
|
||||
mFirstSource->Sync();
|
||||
mFirstSource->Sync(true);
|
||||
}
|
||||
|
||||
TextureHost::ReadUnlock();
|
||||
}
|
||||
|
||||
void
|
||||
BufferTextureHost::MaybeNotifyUnlocked()
|
||||
{
|
||||
#ifdef XP_DARWIN
|
||||
auto actor = GetIPDLActor();
|
||||
if (actor) {
|
||||
AutoTArray<uint64_t, 1> serials;
|
||||
serials.AppendElement(TextureHost::GetTextureSerial(actor));
|
||||
TextureSync::SetTexturesUnlocked(actor->OtherPid(), serials);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
BufferTextureHost::UnbindTextureSource()
|
||||
{
|
||||
@ -911,6 +934,7 @@ BufferTextureHost::UnbindTextureSource()
|
||||
// If the texture has an intermediate buffer we don't care either because
|
||||
// texture uploads are also performed synchronously for BufferTextureHost.
|
||||
ReadUnlock();
|
||||
MaybeNotifyUnlocked();
|
||||
}
|
||||
|
||||
gfx::SurfaceFormat
|
||||
@ -977,6 +1001,7 @@ BufferTextureHost::MaybeUpload(nsIntRegion *aRegion)
|
||||
// We just did the texture upload, the content side can now freely write
|
||||
// into the shared buffer.
|
||||
ReadUnlock();
|
||||
MaybeNotifyUnlocked();
|
||||
}
|
||||
|
||||
// We no longer have an invalid region.
|
||||
@ -1290,9 +1315,12 @@ TextureParent::Destroy()
|
||||
return;
|
||||
}
|
||||
|
||||
// ReadUnlock here to make sure the ReadLock's shmem does not outlive the
|
||||
// protocol that created it.
|
||||
mTextureHost->ReadUnlock();
|
||||
if (mTextureHost->mReadLocked) {
|
||||
// ReadUnlock here to make sure the ReadLock's shmem does not outlive the
|
||||
// protocol that created it.
|
||||
mTextureHost->ReadUnlock();
|
||||
mTextureHost->MaybeNotifyUnlocked();
|
||||
}
|
||||
|
||||
if (mTextureHost->GetFlags() & TextureFlags::DEALLOCATE_CLIENT) {
|
||||
mTextureHost->ForgetSharedData();
|
||||
|
@ -188,8 +188,10 @@ public:
|
||||
virtual bool IsDirectMap() { return false; }
|
||||
// The direct-map cpu buffer should be alive when gpu uses it. And it
|
||||
// should not be updated while gpu reads it. This Sync() function
|
||||
// implements this synchronized behavior.
|
||||
virtual void Sync() { }
|
||||
// implements this synchronized behavior by allowing us to check if
|
||||
// the GPU is done with the texture, and block on it if aBlocking is
|
||||
// true.
|
||||
virtual bool Sync(bool aBlocking) { return true; }
|
||||
|
||||
protected:
|
||||
|
||||
@ -670,11 +672,15 @@ public:
|
||||
*/
|
||||
virtual MacIOSurface* GetMacIOSurface() { return nullptr; }
|
||||
|
||||
virtual bool IsDirectMap() { return false; }
|
||||
|
||||
protected:
|
||||
virtual void ReadUnlock();
|
||||
|
||||
void RecycleTexture(TextureFlags aFlags);
|
||||
|
||||
virtual void MaybeNotifyUnlocked() {}
|
||||
|
||||
virtual void UpdatedInternal(const nsIntRegion *Region) {}
|
||||
|
||||
/**
|
||||
@ -777,6 +783,9 @@ public:
|
||||
const Range<wr::ImageKey>& aImageKeys) override;
|
||||
|
||||
virtual void ReadUnlock() override;
|
||||
virtual bool IsDirectMap() override { return mFirstSource && mFirstSource->IsDirectMap(); };
|
||||
|
||||
bool CanUnlock() { return !mFirstSource || mFirstSource->Sync(false); }
|
||||
|
||||
protected:
|
||||
bool Upload(nsIntRegion *aRegion = nullptr);
|
||||
@ -785,6 +794,8 @@ protected:
|
||||
bool EnsureWrappingTextureSource();
|
||||
|
||||
virtual void UpdatedInternal(const nsIntRegion* aRegion = nullptr) override;
|
||||
virtual void MaybeNotifyUnlocked() override;
|
||||
|
||||
|
||||
BufferDescriptor mDescriptor;
|
||||
RefPtr<Compositor> mCompositor;
|
||||
|
@ -15,6 +15,9 @@
|
||||
#include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc
|
||||
#include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
|
||||
#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
|
||||
#ifdef XP_DARWIN
|
||||
#include "mozilla/layers/TextureSync.h" // for TextureSync
|
||||
#endif
|
||||
#include "nsAString.h"
|
||||
#include "nsDebug.h" // for NS_WARNING
|
||||
#include "nsPoint.h" // for IntPoint
|
||||
@ -298,6 +301,9 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
|
||||
TextureSourceRecycler oldRetainedTiles(std::move(mRetainedTiles));
|
||||
mRetainedTiles.SetLength(tileDescriptors.Length());
|
||||
|
||||
AutoTArray<uint64_t, 10> lockedTextureSerials;
|
||||
base::ProcessId lockedTexturePid = 0;
|
||||
|
||||
// Step 1, deserialize the incoming set of tiles into mRetainedTiles, and attempt
|
||||
// to recycle the TextureSource for any repeated tiles.
|
||||
//
|
||||
@ -322,6 +328,15 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
|
||||
tile.mTextureHost = TextureHost::AsTextureHost(texturedDesc.textureParent());
|
||||
if (texturedDesc.readLocked()) {
|
||||
tile.mTextureHost->SetReadLocked();
|
||||
auto actor = tile.mTextureHost->GetIPDLActor();
|
||||
if (actor && tile.mTextureHost->IsDirectMap()) {
|
||||
lockedTextureSerials.AppendElement(TextureHost::GetTextureSerial(actor));
|
||||
|
||||
if (lockedTexturePid) {
|
||||
MOZ_ASSERT(lockedTexturePid == actor->OtherPid());
|
||||
}
|
||||
lockedTexturePid = actor->OtherPid();
|
||||
}
|
||||
}
|
||||
|
||||
if (texturedDesc.textureOnWhite().type() == MaybeTexture::TPTextureParent) {
|
||||
@ -330,6 +345,10 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
|
||||
);
|
||||
if (texturedDesc.readLockedOnWhite()) {
|
||||
tile.mTextureHostOnWhite->SetReadLocked();
|
||||
auto actor = tile.mTextureHostOnWhite->GetIPDLActor();
|
||||
if (actor && tile.mTextureHostOnWhite->IsDirectMap()) {
|
||||
lockedTextureSerials.AppendElement(TextureHost::GetTextureSerial(actor));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -354,6 +373,12 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef XP_DARWIN
|
||||
if (lockedTextureSerials.Length() > 0) {
|
||||
TextureSync::SetTexturesLocked(lockedTexturePid, lockedTextureSerials);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Step 2, attempt to recycle unused texture sources from the old tile set into new tiles.
|
||||
//
|
||||
// For gralloc, binding a new TextureHost to the existing TextureSource is the fastest way
|
||||
|
@ -32,6 +32,9 @@
|
||||
#include "mozilla/layers/LayerTransactionChild.h"
|
||||
#include "mozilla/layers/PTextureChild.h"
|
||||
#include "mozilla/layers/SyncObject.h"
|
||||
#ifdef XP_DARWIN
|
||||
#include "mozilla/layers/TextureSync.h"
|
||||
#endif
|
||||
#include "ShadowLayerUtils.h"
|
||||
#include "mozilla/layers/TextureClient.h" // for TextureClient
|
||||
#include "mozilla/mozalloc.h" // for operator new, etc
|
||||
@ -813,6 +816,38 @@ ShadowLayerForwarder::SetLayerObserverEpoch(uint64_t aLayerObserverEpoch)
|
||||
Unused << mShadowManager->SendSetLayerObserverEpoch(aLayerObserverEpoch);
|
||||
}
|
||||
|
||||
void
|
||||
ShadowLayerForwarder::UpdateTextureLocks()
|
||||
{
|
||||
#ifdef XP_DARWIN
|
||||
if (!IPCOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto compositorBridge = GetCompositorBridgeChild();
|
||||
if (compositorBridge) {
|
||||
auto pid = compositorBridge->OtherPid();
|
||||
TextureSync::UpdateTextureLocks(pid);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ShadowLayerForwarder::SyncTextures(const nsTArray<uint64_t>& aSerials)
|
||||
{
|
||||
#ifdef XP_DARWIN
|
||||
if (!IPCOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto compositorBridge = GetCompositorBridgeChild();
|
||||
if (compositorBridge) {
|
||||
auto pid = compositorBridge->OtherPid();
|
||||
TextureSync::WaitForTextures(pid, aSerials);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ShadowLayerForwarder::ReleaseLayer(const LayerHandle& aHandle)
|
||||
{
|
||||
|
@ -361,6 +361,9 @@ public:
|
||||
virtual void UpdateFwdTransactionId() override;
|
||||
virtual uint64_t GetFwdTransactionId() override;
|
||||
|
||||
void UpdateTextureLocks();
|
||||
void SyncTextures(const nsTArray<uint64_t>& aSerials);
|
||||
|
||||
void ReleaseLayer(const LayerHandle& aHandle);
|
||||
|
||||
bool InForwarderThread() override {
|
||||
|
@ -274,6 +274,7 @@ if CONFIG['MOZ_X11']:
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
EXPORTS.mozilla.layers += [
|
||||
'opengl/GLManager.h',
|
||||
'TextureSync.h',
|
||||
]
|
||||
EXPORTS += [
|
||||
'MacIOSurfaceHelpers.h',
|
||||
@ -281,6 +282,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
]
|
||||
UNIFIED_SOURCES += [
|
||||
'opengl/GLManager.cpp',
|
||||
'TextureSync.cpp',
|
||||
]
|
||||
SOURCES += [
|
||||
'ipc/ShadowLayerUtilsMac.cpp',
|
||||
|
@ -31,6 +31,10 @@
|
||||
#include "mozilla/layers/Effects.h" // for EffectChain, TexturedEffect, etc
|
||||
#include "mozilla/layers/TextureHost.h" // for TextureSource, etc
|
||||
#include "mozilla/layers/TextureHostOGL.h" // for TextureSourceOGL, etc
|
||||
#include "mozilla/layers/PTextureParent.h" // for OtherPid() on PTextureParent
|
||||
#ifdef XP_DARWIN
|
||||
#include "mozilla/layers/TextureSync.h" // for TextureSync::etc.
|
||||
#endif
|
||||
#include "mozilla/mozalloc.h" // for operator delete, etc
|
||||
#include "nsAppRunner.h"
|
||||
#include "nsAString.h"
|
||||
@ -183,11 +187,17 @@ CompositorOGL::CompositorOGL(CompositorBridgeParent* aParent,
|
||||
, mViewportSize(0, 0)
|
||||
, mCurrentProgram(nullptr)
|
||||
{
|
||||
#ifdef XP_DARWIN
|
||||
TextureSync::RegisterTextureSourceProvider(this);
|
||||
#endif
|
||||
MOZ_COUNT_CTOR(CompositorOGL);
|
||||
}
|
||||
|
||||
CompositorOGL::~CompositorOGL()
|
||||
{
|
||||
#ifdef XP_DARWIN
|
||||
TextureSync::UnregisterTextureSourceProvider(this);
|
||||
#endif
|
||||
MOZ_COUNT_DTOR(CompositorOGL);
|
||||
Destroy();
|
||||
}
|
||||
@ -246,6 +256,10 @@ CompositorOGL::Destroy()
|
||||
mTexturePool = nullptr;
|
||||
}
|
||||
|
||||
#ifdef XP_DARWIN
|
||||
mMaybeUnlockBeforeNextComposition.Clear();
|
||||
#endif
|
||||
|
||||
if (!mDestroyed) {
|
||||
mDestroyed = true;
|
||||
CleanupResources();
|
||||
@ -1923,6 +1937,38 @@ CompositorOGL::CreateDataTextureSourceAroundYCbCr(TextureHost* aTexture)
|
||||
return srcY.forget();
|
||||
}
|
||||
|
||||
#ifdef XP_DARWIN
|
||||
void
|
||||
CompositorOGL::MaybeUnlockBeforeNextComposition(TextureHost* aTextureHost)
|
||||
{
|
||||
auto bufferTexture = aTextureHost->AsBufferTextureHost();
|
||||
if (bufferTexture) {
|
||||
mMaybeUnlockBeforeNextComposition.AppendElement(bufferTexture);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CompositorOGL::TryUnlockTextures()
|
||||
{
|
||||
nsClassHashtable<nsUint32HashKey, nsTArray<uint64_t>> texturesIdsToUnlockByPid;
|
||||
for (auto& texture : mMaybeUnlockBeforeNextComposition) {
|
||||
if (texture->IsDirectMap() && texture->CanUnlock()) {
|
||||
texture->ReadUnlock();
|
||||
auto actor = texture->GetIPDLActor();
|
||||
if (actor) {
|
||||
base::ProcessId pid = actor->OtherPid();
|
||||
nsTArray<uint64_t>* textureIds = texturesIdsToUnlockByPid.LookupOrAdd(pid);
|
||||
textureIds->AppendElement(TextureHost::GetTextureSerial(actor));
|
||||
}
|
||||
}
|
||||
}
|
||||
mMaybeUnlockBeforeNextComposition.Clear();
|
||||
for (auto it = texturesIdsToUnlockByPid.ConstIter(); !it.Done(); it.Next()) {
|
||||
TextureSync::SetTexturesUnlocked(it.Key(), *it.UserData());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
already_AddRefed<DataTextureSource>
|
||||
CompositorOGL::CreateDataTextureSourceAround(gfx::DataSourceSurface* aSurface)
|
||||
{
|
||||
|
@ -44,6 +44,7 @@ class CompositingRenderTargetOGL;
|
||||
class DataTextureSource;
|
||||
class GLManagerCompositor;
|
||||
class TextureSource;
|
||||
class BufferTextureHost;
|
||||
struct Effect;
|
||||
struct EffectChain;
|
||||
class GLBlitTextureImageHelper;
|
||||
@ -235,6 +236,11 @@ public:
|
||||
GLContext* gl() const { return mGLContext; }
|
||||
GLContext* GetGLContext() const override { return mGLContext; }
|
||||
|
||||
#ifdef XP_DARWIN
|
||||
virtual void MaybeUnlockBeforeNextComposition(TextureHost* aTextureHost) override;
|
||||
virtual void TryUnlockTextures() override;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Clear the program state. This must be called
|
||||
* before operating on the GLContext directly. */
|
||||
@ -288,6 +294,10 @@ private:
|
||||
UniquePtr<GLBlitTextureImageHelper> mBlitTextureImageHelper;
|
||||
gfx::Matrix4x4 mProjMatrix;
|
||||
|
||||
#ifdef XP_DARWIN
|
||||
nsTArray<RefPtr<BufferTextureHost>> mMaybeUnlockBeforeNextComposition;
|
||||
#endif
|
||||
|
||||
/** The size of the surface we are rendering to */
|
||||
gfx::IntSize mSurfaceSize;
|
||||
|
||||
|
@ -337,13 +337,18 @@ DirectMapTextureSource::Update(gfx::DataSourceSurface* aSurface,
|
||||
return UpdateInternal(aSurface, aDestRegion, aSrcOffset, false);
|
||||
}
|
||||
|
||||
void
|
||||
DirectMapTextureSource::Sync()
|
||||
bool
|
||||
DirectMapTextureSource::Sync(bool aBlocking)
|
||||
{
|
||||
gl()->MakeCurrent();
|
||||
if (!gl()->IsDestroyed()) {
|
||||
gl()->fFinishObjectAPPLE(LOCAL_GL_TEXTURE, mTextureHandle);
|
||||
if (aBlocking) {
|
||||
gl()->fFinishObjectAPPLE(LOCAL_GL_TEXTURE, mTextureHandle);
|
||||
} else {
|
||||
return gl()->fTestObjectAPPLE(LOCAL_GL_TEXTURE, mTextureHandle);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -304,8 +304,10 @@ public:
|
||||
|
||||
virtual bool IsDirectMap() override { return true; }
|
||||
|
||||
// Wait until this texture source is not used by the compositor.
|
||||
virtual void Sync() override;
|
||||
// If aBlocking is false, check if this texture is no longer being used
|
||||
// by the GPU - if aBlocking is true, this will block until the GPU is
|
||||
// done with it.
|
||||
virtual bool Sync(bool aBlocking) override;
|
||||
|
||||
private:
|
||||
bool UpdateInternal(gfx::DataSourceSurface* aSurface,
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "SharedMemory.h"
|
||||
#include <mach/port.h>
|
||||
#include "chrome/common/mach_ipc_mac.h"
|
||||
|
||||
#ifdef FUZZING
|
||||
#include "SharedMemoryFuzzer.h"
|
||||
@ -28,6 +29,27 @@ class ReceivePort;
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
enum {
|
||||
kGetPortsMsg = 1,
|
||||
kSharePortsMsg,
|
||||
kWaitForTexturesMsg,
|
||||
kUpdateTextureLocksMsg,
|
||||
kReturnIdMsg,
|
||||
kReturnWaitForTexturesMsg,
|
||||
kReturnPortsMsg,
|
||||
kShutdownMsg,
|
||||
kCleanupMsg,
|
||||
};
|
||||
|
||||
struct MemoryPorts {
|
||||
MachPortSender* mSender;
|
||||
ReceivePort* mReceiver;
|
||||
|
||||
MemoryPorts() = default;
|
||||
MemoryPorts(MachPortSender* sender, ReceivePort* receiver)
|
||||
: mSender(sender), mReceiver(receiver) {}
|
||||
};
|
||||
|
||||
class SharedMemoryBasic final : public SharedMemoryCommon<mach_port_t>
|
||||
{
|
||||
public:
|
||||
@ -42,6 +64,10 @@ public:
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
static bool SendMachMessage(pid_t pid,
|
||||
MachSendMessage& message,
|
||||
MachReceiveMessage* response);
|
||||
|
||||
SharedMemoryBasic();
|
||||
|
||||
virtual bool SetHandle(const Handle& aHandle, OpenRights aRights) override;
|
||||
|
@ -22,11 +22,11 @@
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include "SharedMemoryBasic.h"
|
||||
#include "chrome/common/mach_ipc_mac.h"
|
||||
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
#include "mozilla/Printf.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "mozilla/layers/TextureSync.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define LOG_ERROR(str, args...) \
|
||||
@ -82,29 +82,10 @@
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
struct MemoryPorts {
|
||||
MachPortSender* mSender;
|
||||
ReceivePort* mReceiver;
|
||||
|
||||
MemoryPorts() = default;
|
||||
MemoryPorts(MachPortSender* sender, ReceivePort* receiver)
|
||||
: mSender(sender), mReceiver(receiver) {}
|
||||
};
|
||||
|
||||
// Protects gMemoryCommPorts and gThreads.
|
||||
static StaticMutex gMutex;
|
||||
|
||||
static std::map<pid_t, MemoryPorts> gMemoryCommPorts;
|
||||
|
||||
enum {
|
||||
kGetPortsMsg = 1,
|
||||
kSharePortsMsg,
|
||||
kReturnIdMsg,
|
||||
kReturnPortsMsg,
|
||||
kShutdownMsg,
|
||||
kCleanupMsg,
|
||||
};
|
||||
|
||||
const int kTimeout = 1000;
|
||||
const int kLongTimeout = 60 * kTimeout;
|
||||
|
||||
@ -154,6 +135,7 @@ SetupMachMemory(pid_t pid,
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
|
||||
int err = pthread_create(&thread, &attr, PortServerThread, listen_ports);
|
||||
if (err) {
|
||||
LOG_ERROR("pthread_create failed with %x\n", err);
|
||||
@ -405,30 +387,36 @@ PortServerThread(void *argument)
|
||||
delete ports;
|
||||
return nullptr;
|
||||
}
|
||||
StaticMutexAutoLock smal(gMutex);
|
||||
switch (rmsg.GetMessageID()) {
|
||||
case kSharePortsMsg:
|
||||
HandleSharePortsMessage(&rmsg, ports);
|
||||
break;
|
||||
case kGetPortsMsg:
|
||||
HandleGetPortsMessage(&rmsg, ports);
|
||||
break;
|
||||
case kCleanupMsg:
|
||||
if (gParentPid == 0) {
|
||||
LOG_ERROR("Cleanup message not valid for parent process");
|
||||
continue;
|
||||
}
|
||||
if (rmsg.GetMessageID() == kWaitForTexturesMsg) {
|
||||
layers::TextureSync::HandleWaitForTexturesMessage(&rmsg, ports);
|
||||
} else if (rmsg.GetMessageID() == kUpdateTextureLocksMsg) {
|
||||
layers::TextureSync::DispatchCheckTexturesForUnlock();
|
||||
} else {
|
||||
StaticMutexAutoLock smal(gMutex);
|
||||
switch (rmsg.GetMessageID()) {
|
||||
case kSharePortsMsg:
|
||||
HandleSharePortsMessage(&rmsg, ports);
|
||||
break;
|
||||
case kGetPortsMsg:
|
||||
HandleGetPortsMessage(&rmsg, ports);
|
||||
break;
|
||||
case kCleanupMsg:
|
||||
if (gParentPid == 0) {
|
||||
LOG_ERROR("Cleanup message not valid for parent process");
|
||||
continue;
|
||||
}
|
||||
|
||||
pid_t* pid;
|
||||
if (rmsg.GetDataLength() != sizeof(pid_t)) {
|
||||
LOG_ERROR("Improperly formatted message\n");
|
||||
continue;
|
||||
pid_t* pid;
|
||||
if (rmsg.GetDataLength() != sizeof(pid_t)) {
|
||||
LOG_ERROR("Improperly formatted message\n");
|
||||
continue;
|
||||
}
|
||||
pid = reinterpret_cast<pid_t*>(rmsg.GetData());
|
||||
SharedMemoryBasic::CleanupForPid(*pid);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Unknown message\n");
|
||||
}
|
||||
pid = reinterpret_cast<pid_t*>(rmsg.GetData());
|
||||
SharedMemoryBasic::CleanupForPid(*pid);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Unknown message\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -450,6 +438,8 @@ SharedMemoryBasic::Shutdown()
|
||||
{
|
||||
StaticMutexAutoLock smal(gMutex);
|
||||
|
||||
layers::TextureSync::Shutdown();
|
||||
|
||||
for (auto& thread : gThreads) {
|
||||
MachSendMessage shutdownMsg(kShutdownMsg);
|
||||
thread.second.mPorts->mReceiver->SendMessageToSelf(shutdownMsg, kTimeout);
|
||||
@ -469,6 +459,9 @@ SharedMemoryBasic::CleanupForPid(pid_t pid)
|
||||
if (gThreads.find(pid) == gThreads.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
layers::TextureSync::CleanupForPid(pid);
|
||||
|
||||
const ListeningThread& listeningThread = gThreads[pid];
|
||||
MachSendMessage shutdownMsg(kShutdownMsg);
|
||||
kern_return_t ret = listeningThread.mPorts->mReceiver->SendMessageToSelf(shutdownMsg, kTimeout);
|
||||
@ -493,6 +486,40 @@ SharedMemoryBasic::CleanupForPid(pid_t pid)
|
||||
gMemoryCommPorts.erase(pid);
|
||||
}
|
||||
|
||||
bool
|
||||
SharedMemoryBasic::SendMachMessage(pid_t pid,
|
||||
MachSendMessage& message,
|
||||
MachReceiveMessage* response)
|
||||
{
|
||||
StaticMutexAutoLock smal(gMutex);
|
||||
ipc::MemoryPorts* ports = GetMemoryPortsForPid(pid);
|
||||
if (!ports) {
|
||||
LOG_ERROR("Unable to get ports for process.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
kern_return_t err = ports->mSender->SendMessage(message, kTimeout);
|
||||
if (err != KERN_SUCCESS) {
|
||||
LOG_ERROR("Failed updating texture locks.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (response) {
|
||||
err = ports->mReceiver->WaitForMessage(response, kTimeout);
|
||||
if (err != KERN_SUCCESS) {
|
||||
LOG_ERROR("short timeout didn't get an id %s %x\n", mach_error_string(err), err);
|
||||
err = ports->mReceiver->WaitForMessage(response, kLongTimeout);
|
||||
|
||||
if (err != KERN_SUCCESS) {
|
||||
LOG_ERROR("long timeout didn't get an id %s %x\n", mach_error_string(err), err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SharedMemoryBasic::SharedMemoryBasic()
|
||||
: mPort(MACH_PORT_NULL)
|
||||
, mMemory(nullptr)
|
||||
|
Loading…
Reference in New Issue
Block a user