Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  SharedSurfacesParent.cpp   Sprache: C

 
/* -*- 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 "SharedSurfacesParent.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/StaticPrefs_image.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/GPUProcessManager.h"
#include "mozilla/layers/SharedSurfacesMemoryReport.h"
#include "mozilla/layers/SourceSurfaceSharedData.h"
#include "mozilla/layers/CompositorManagerParent.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/webrender/RenderSharedSurfaceTextureHost.h"
#include "mozilla/webrender/RenderThread.h"
#include "nsThreadUtils.h"  // for GetCurrentSerialEventTarget

namespace mozilla {
namespace layers {

using namespace mozilla::gfx;

StaticMutex SharedSurfacesParent::sMutex;
StaticAutoPtr<SharedSurfacesParent> SharedSurfacesParent::sInstance;

void SharedSurfacesParent::MappingTracker::NotifyExpiredLocked(
    SourceSurfaceSharedDataWrapper* aSurface,
    const StaticMutexAutoLock& aAutoLock) {
  RemoveObjectLocked(aSurface, aAutoLock);
  mExpired.AppendElement(aSurface);
}

void SharedSurfacesParent::MappingTracker::TakeExpired(
    nsTArray<RefPtr<gfx::SourceSurfaceSharedDataWrapper>>& aExpired,
    const StaticMutexAutoLock& aAutoLock) {
  aExpired = std::move(mExpired);
}

void SharedSurfacesParent::MappingTracker::NotifyHandlerEnd() {
  nsTArray<RefPtr<gfx::SourceSurfaceSharedDataWrapper>> expired;
  {
    StaticMutexAutoLock lock(sMutex);
    TakeExpired(expired, lock);
  }

  SharedSurfacesParent::ExpireMap(expired);
}

SharedSurfacesParent::SharedSurfacesParent()
    : mTracker(
          StaticPrefs::image_mem_shared_unmap_min_expiration_ms_AtStartup(),
          mozilla::GetCurrentSerialEventTarget()) {}

/* static */
void SharedSurfacesParent::Initialize() {
  MOZ_ASSERT(NS_IsMainThread());
  StaticMutexAutoLock lock(sMutex);
  if (!sInstance) {
    sInstance = new SharedSurfacesParent();
  }
}

/* static */
void SharedSurfacesParent::ShutdownRenderThread() {
  // The main thread should blocked on waiting for the render thread to
  // complete so this should be safe to release off the main thread.
  MOZ_ASSERT(wr::RenderThread::IsInRenderThread());
  StaticMutexAutoLock lock(sMutex);
  MOZ_ASSERT(sInstance);

  for (const auto& key : sInstance->mSurfaces.Keys()) {
    // There may be lingering consumers of the surfaces that didn't get shutdown
    // yet but since we are here, we know the render thread is finished and we
    // can unregister everything.
    wr::RenderThread::Get()->UnregisterExternalImageDuringShutdown(
        wr::ToExternalImageId(key));
  }
}

/* static */
void SharedSurfacesParent::Shutdown() {
  // The compositor thread and render threads are shutdown, so this is the last
  // thread that could use it. The expiration tracker needs to be freed on the
  // main thread.
  MOZ_ASSERT(NS_IsMainThread());
  StaticMutexAutoLock lock(sMutex);
  sInstance = nullptr;
}

/* static */
already_AddRefed<DataSourceSurface> SharedSurfacesParent::Get(
    const wr::ExternalImageId& aId) {
  RefPtr<SourceSurfaceSharedDataWrapper> surface;

  {
    StaticMutexAutoLock lock(sMutex);
    if (!sInstance) {
      gfxCriticalNote << "SSP:Get " << wr::AsUint64(aId) << " shtd";
      return nullptr;
    }

    if (sInstance->mSurfaces.Get(wr::AsUint64(aId), getter_AddRefs(surface))) {
      return surface.forget();
    }
  }

  // We cannot block the compositor thread since that's the thread the necessary
  // IPDL events would come in on.
  if (NS_WARN_IF(CompositorThreadHolder::IsInCompositorThread())) {
    return nullptr;
  }

  // Block until we see the relevant resource come in or the actor is destroyed.
  CompositorManagerParent::WaitForSharedSurface(aId);

  StaticMutexAutoLock lock(sMutex);
  if (!sInstance) {
    gfxCriticalNote << "SSP:Get " << wr::AsUint64(aId) << " shtd";
    return nullptr;
  }

  sInstance->mSurfaces.Get(wr::AsUint64(aId), getter_AddRefs(surface));
  return surface.forget();
}

/* static */
already_AddRefed<DataSourceSurface> SharedSurfacesParent::Acquire(
    const wr::ExternalImageId& aId) {
  StaticMutexAutoLock lock(sMutex);
  if (!sInstance) {
    gfxCriticalNote << "SSP:Acq " << wr::AsUint64(aId) << " shtd";
    return nullptr;
  }

  RefPtr<SourceSurfaceSharedDataWrapper> surface;
  sInstance->mSurfaces.Get(wr::AsUint64(aId), getter_AddRefs(surface));

  if (surface) {
    DebugOnly<bool> rv = surface->AddConsumer();
    MOZ_ASSERT(!rv);
  }
  return surface.forget();
}

/* static */
bool SharedSurfacesParent::Release(const wr::ExternalImageId& aId,
                                   bool aForCreator) {
  StaticMutexAutoLock lock(sMutex);
  if (!sInstance) {
    return false;
  }

  uint64_t id = wr::AsUint64(aId);
  RefPtr<SourceSurfaceSharedDataWrapper> surface;
  sInstance->mSurfaces.Get(wr::AsUint64(aId), getter_AddRefs(surface));
  if (!surface) {
    return false;
  }

  if (surface->RemoveConsumer(aForCreator)) {
    RemoveTrackingLocked(surface, lock);
    wr::RenderThread::Get()->UnregisterExternalImage(wr::ToExternalImageId(id));
    sInstance->mSurfaces.Remove(id);
  }

  return true;
}

/* static */
void SharedSurfacesParent::AddSameProcess(const wr::ExternalImageId& aId,
                                          SourceSurfaceSharedData* aSurface) {
  MOZ_ASSERT(XRE_IsParentProcess());
  MOZ_ASSERT(NS_IsMainThread());
  StaticMutexAutoLock lock(sMutex);
  if (!sInstance) {
    gfxCriticalNote << "SSP:Ads " << wr::AsUint64(aId) << " shtd";
    return;
  }

  // If the child bridge detects it is in the combined UI/GPU process, then it
  // will insert a wrapper surface holding the shared memory buffer directly.
  // This is good because we avoid mapping the same shared memory twice, but
  // still allow the original surface to be freed and remove the wrapper from
  // the table when it is no longer needed.
  RefPtr<SourceSurfaceSharedDataWrapper> surface =
      new SourceSurfaceSharedDataWrapper();
  surface->Init(aSurface);

  uint64_t id = wr::AsUint64(aId);
  if (sInstance->mSurfaces.Contains(id)) {
    gfxCriticalNote << "SSP:Ads " << wr::AsUint64(aId) << " dupe";
    SharedSurfacesParent::RemoveTrackingLocked(surface, lock);
    MOZ_DIAGNOSTIC_CRASH("External image ID reused!");
    return;
  }

  auto texture = MakeRefPtr<wr::RenderSharedSurfaceTextureHost>(surface);
  wr::RenderThread::Get()->RegisterExternalImage(aId, texture.forget());

  sInstance->mSurfaces.InsertOrUpdate(id, std::move(surface));
}

/* static */
void SharedSurfacesParent::RemoveAll(uint32_t aNamespace) {
  StaticMutexAutoLock lock(sMutex);
  if (!sInstance) {
    return;
  }

  auto* renderThread = wr::RenderThread::Get();

  // Note that the destruction of a parent may not be cheap if it still has a
  // lot of surfaces still bound that require unmapping.
  for (auto i = sInstance->mSurfaces.Iter(); !i.Done(); i.Next()) {
    if (static_cast<uint32_t>(i.Key() >> 32) != aNamespace) {
      continue;
    }

    SourceSurfaceSharedDataWrapper* surface = i.Data();
    if (surface->HasCreatorRef() &&
        surface->RemoveConsumer(/* aForCreator */ true)) {
      RemoveTrackingLocked(surface, lock);
      if (renderThread) {
        renderThread->UnregisterExternalImage(wr::ToExternalImageId(i.Key()));
      }
      i.Remove();
    }
  }
}

/* static */
void SharedSurfacesParent::Add(const wr::ExternalImageId& aId,
                               SurfaceDescriptorShared&& aDesc,
                               base::ProcessId aPid) {
  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
  MOZ_ASSERT(aPid != base::GetCurrentProcId());

  RefPtr<SourceSurfaceSharedDataWrapper> surface =
      new SourceSurfaceSharedDataWrapper();

  // We preferentially map in new surfaces when they are initially received
  // because we are likely to reference them in a display list soon. The unmap
  // will ensure we add the surface to the expiration tracker. We do it outside
  // the mutex to ensure we always lock the surface mutex first, and our mutex
  // second, to avoid deadlock.
  //
  // Note that the surface wrapper maps in the given handle as read only.
  surface->Init(aDesc.size(), aDesc.stride(), aDesc.format(),
                std::move(aDesc.handle()), aPid);

  StaticMutexAutoLock lock(sMutex);
  if (!sInstance) {
    gfxCriticalNote << "SSP:Add " << wr::AsUint64(aId) << " shtd";
    return;
  }

  uint64_t id = wr::AsUint64(aId);
  if (sInstance->mSurfaces.Contains(id)) {
    gfxCriticalNote << "SSP:Add " << wr::AsUint64(aId) << " dupe";
    SharedSurfacesParent::RemoveTrackingLocked(surface, lock);
    MOZ_DIAGNOSTIC_CRASH("External image ID reused!");
    return;
  }

  auto texture = MakeRefPtr<wr::RenderSharedSurfaceTextureHost>(surface);
  wr::RenderThread::Get()->RegisterExternalImage(aId, texture.forget());

  sInstance->mSurfaces.InsertOrUpdate(id, std::move(surface));
}

/* static */
void SharedSurfacesParent::Remove(const wr::ExternalImageId& aId) {
  DebugOnly<bool> rv = Release(aId, /* aForCreator */ true);
  MOZ_ASSERT(rv);
}

/* static */
void SharedSurfacesParent::AddTrackingLocked(
    SourceSurfaceSharedDataWrapper* aSurface,
    const StaticMutexAutoLock& aAutoLock) {
  MOZ_ASSERT(!aSurface->GetExpirationState()->IsTracked());
  MOZ_ASSERT(aSurface->GetConsumers() > 0);
  sInstance->mTracker.AddObjectLocked(aSurface, aAutoLock);
}

/* static */
void SharedSurfacesParent::AddTracking(
    SourceSurfaceSharedDataWrapper* aSurface) {
  StaticMutexAutoLock lock(sMutex);
  if (!sInstance) {
    return;
  }

  AddTrackingLocked(aSurface, lock);
}

/* static */
void SharedSurfacesParent::RemoveTrackingLocked(
    SourceSurfaceSharedDataWrapper* aSurface,
    const StaticMutexAutoLock& aAutoLock) {
  if (!aSurface->GetExpirationState()->IsTracked()) {
    return;
  }

  sInstance->mTracker.RemoveObjectLocked(aSurface, aAutoLock);
}

/* static */
void SharedSurfacesParent::RemoveTracking(
    SourceSurfaceSharedDataWrapper* aSurface) {
  StaticMutexAutoLock lock(sMutex);
  if (!sInstance) {
    return;
  }

  RemoveTrackingLocked(aSurface, lock);
}

/* static */
bool SharedSurfacesParent::AgeOneGenerationLocked(
    nsTArray<RefPtr<SourceSurfaceSharedDataWrapper>>& aExpired,
    const StaticMutexAutoLock& aAutoLock) {
  if (sInstance->mTracker.IsEmptyLocked(aAutoLock)) {
    return false;
  }

  sInstance->mTracker.AgeOneGenerationLocked(aAutoLock);
  sInstance->mTracker.TakeExpired(aExpired, aAutoLock);
  return true;
}

/* static */
bool SharedSurfacesParent::AgeOneGeneration(
    nsTArray<RefPtr<SourceSurfaceSharedDataWrapper>>& aExpired) {
  StaticMutexAutoLock lock(sMutex);
  if (!sInstance) {
    return false;
  }

  return AgeOneGenerationLocked(aExpired, lock);
}

/* static */
bool SharedSurfacesParent::AgeAndExpireOneGeneration() {
  nsTArray<RefPtr<SourceSurfaceSharedDataWrapper>> expired;
  bool aged = AgeOneGeneration(expired);
  ExpireMap(expired);
  return aged;
}

/* static */
void SharedSurfacesParent::ExpireMap(
    nsTArray<RefPtr<SourceSurfaceSharedDataWrapper>>& aExpired) {
  for (auto& surface : aExpired) {
    MOZ_ASSERT(surface->GetConsumers() > 0);
    surface->ExpireMap();
  }
}

/* static */
void SharedSurfacesParent::AccumulateMemoryReport(
    uint32_t aNamespace, SharedSurfacesMemoryReport& aReport) {
  StaticMutexAutoLock lock(sMutex);
  if (!sInstance) {
    return;
  }

  for (const auto& entry : sInstance->mSurfaces) {
    if (static_cast<uint32_t>(entry.GetKey() >> 32) != aNamespace) {
      continue;
    }

    SourceSurfaceSharedDataWrapper* surface = entry.GetData();
    aReport.mSurfaces.insert(std::make_pair(
        entry.GetKey(),
        SharedSurfacesMemoryReport::SurfaceEntry{
            surface->GetCreatorPid(), surface->GetSize(), surface->Stride(),
            surface->GetConsumers(), surface->HasCreatorRef()}));
  }
}

/* static */
bool SharedSurfacesParent::AccumulateMemoryReport(
    SharedSurfacesMemoryReport& aReport) {
  if (XRE_IsParentProcess()) {
    GPUProcessManager* gpm = GPUProcessManager::Get();
    if (!gpm || gpm->GPUProcessPid() != base::kInvalidProcessId) {
      return false;
    }
  } else if (!XRE_IsGPUProcess()) {
    return false;
  }

  StaticMutexAutoLock lock(sMutex);
  if (!sInstance) {
    return true;
  }

  for (const auto& entry : sInstance->mSurfaces) {
    SourceSurfaceSharedDataWrapper* surface = entry.GetData();
    aReport.mSurfaces.insert(std::make_pair(
        entry.GetKey(),
        SharedSurfacesMemoryReport::SurfaceEntry{
            surface->GetCreatorPid(), surface->GetSize(), surface->Stride(),
            surface->GetConsumers(), surface->HasCreatorRef()}));
  }

  return true;
}

}  // namespace layers
}  // namespace mozilla

Messung V0.5
C=88 H=93 G=90

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge