Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  RenderCompositorLayerNative.cpp

  Sprache: C
 

/* 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 "RenderCompositorLayerNative.h"

#include "GLContext.h"
#include "GLContextProvider.h"
#include "mozilla/ProfilerLabels.h"
#include "mozilla/ProfilerMarkers.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/layers/CompositionRecorder.h"
#include "mozilla/layers/GpuFence.h"
#include "mozilla/layers/NativeLayer.h"
#include "mozilla/layers/ProfilerScreenshots.h"
#include "mozilla/layers/SurfacePool.h"
#include "mozilla/StaticPrefs_gfx.h"
#include "mozilla/webrender/RenderTextureHost.h"
#include "mozilla/webrender/RenderThread.h"
#include "mozilla/widget/CompositorWidget.h"
#include "RenderCompositorRecordedFrame.h"

#if defined(MOZ_WAYLAND)
#  include "mozilla/layers/NativeLayerWayland.h"
#endif

namespace mozilla::wr {

extern LazyLogModule gRenderThreadLog;
#define LOG(...) MOZ_LOG(gRenderThreadLog, LogLevel::Debug, (__VA_ARGS__))

RenderCompositorLayerNative::RenderCompositorLayerNative(
    const RefPtr<widget::CompositorWidget>& aWidget, gl::GLContext* aGL)
    : RenderCompositor(aWidget),
      mNativeLayerRoot(GetWidget()->GetNativeLayerRoot()) {
  LOG("RenderCompositorLayerNative::RenderCompositorLayerNative()");

  MOZ_ASSERT(mNativeLayerRoot);
#if defined(MOZ_WAYLAND)
  if (auto* rootWayland = mNativeLayerRoot->AsNativeLayerRootWayland()) {
    rootWayland->SetGLContext(aGL);
  }
#endif

#if defined(XP_DARWIN) || defined(MOZ_WAYLAND)
  auto pool = RenderThread::Get()->SharedSurfacePool();
  if (pool) {
    mSurfacePoolHandle = pool->GetHandleForGL(aGL);
  }
#endif
  MOZ_RELEASE_ASSERT(mSurfacePoolHandle);
}

RenderCompositorLayerNative::~RenderCompositorLayerNative() {
  LOG("RRenderCompositorLayerNative::~RenderCompositorLayerNative()");

  mProfilerScreenshotGrabber.Destroy();
  mNativeLayerRoot->SetLayers({});
  mNativeLayerRootSnapshotter = nullptr;
  mNativeLayerRoot = nullptr;
}

bool RenderCompositorLayerNative::BeginFrame() {
  if (!MakeCurrent()) {
    gfxCriticalNote << "Failed to make render context current, can't draw.";
    return false;
  }

  if (!InitDefaultFramebuffer()) {
    return false;
  }

  return true;
}

RenderedFrameId RenderCompositorLayerNative::EndFrame(
    const nsTArray<DeviceIntRect>& aDirtyRects) {
  RenderedFrameId frameId = GetNextRenderFrameId();

  DoSwap();

  MOZ_ASSERT(mPendingGpuFeces.empty());

  return frameId;
}

void RenderCompositorLayerNative::Pause() {}

bool RenderCompositorLayerNative::Resume() { return true; }

inline layers::WebRenderCompositor RenderCompositorLayerNative::CompositorType()
    const {
#if defined(XP_DARWIN)
  return layers::WebRenderCompositor::CORE_ANIMATION;
#elif defined(MOZ_WAYLAND)
  return layers::WebRenderCompositor::WAYLAND;
#else
  MOZ_ASSERT_UNREACHABLE("Unexpected to be called!");
  return layers::WebRenderCompositor::Unknown;
#endif
}

LayoutDeviceIntSize RenderCompositorLayerNative::GetBufferSize() {
  return mWidget->GetClientSize();
}

bool RenderCompositorLayerNative::ShouldUseNativeCompositor() { return false; }

bool RenderCompositorLayerNative::ShouldUseLayerCompositor() const {
  return UseLayerCompositor();
}

bool RenderCompositorLayerNative::UseLayerCompositor() const { return true; }

bool RenderCompositorLayerNative::EnableAsyncScreenshot() {
#if defined(XP_DARWIN)
  // On macOS, NativeLayerRootSnapshotterCA supports to take snapshot with
  // multiple layers.
  return true;
#else
  // Request WebRender to use only one layer for content rendering during taking
  // snapshot. In addition to the content layer, one debug layer could exist.
  mAsyncScreenshotLastFrameUsed = mCurrentFrame;
  if (!mEnableAsyncScreenshot) {
    mEnableAsyncScreenshotInNextFrame = true;
    return false;
  }
  return true;
#endif
}

void RenderCompositorLayerNative::GetCompositorCapabilities(
    CompositorCapabilities* aCaps) {
  RenderCompositor::GetCompositorCapabilities(aCaps);
}

void RenderCompositorLayerNative::GetWindowProperties(
    WindowProperties* aProperties) {
  // XXX
  aProperties->is_opaque = false;
  aProperties->enable_screenshot = mEnableAsyncScreenshot;
}

RenderCompositorLayerNative::Surface::~Surface() = default;

RenderCompositorLayerNative::Surface::Surface(wr::DeviceIntSize aSize,
                                              bool aIsOpaque)
    : mSize(aSize), mIsOpaque(aIsOpaque) {}

bool RenderCompositorLayerNative::MaybeReadback(
    const gfx::IntSize& aReadbackSize, const wr::ImageFormat& aReadbackFormat,
    const Range<uint8_t>& aReadbackBuffer, bool* aNeedsYFlip) {
  MOZ_RELEASE_ASSERT(aReadbackFormat == wr::ImageFormat::BGRA8);

  if (!mNativeLayerRootSnapshotter) {
    mNativeLayerRootSnapshotter = mNativeLayerRoot->CreateSnapshotter();

    if (!mNativeLayerRootSnapshotter) {
      return false;
    }
  }
  bool success = mNativeLayerRootSnapshotter->ReadbackPixels(
      aReadbackSize, gfx::SurfaceFormat::B8G8R8A8, aReadbackBuffer);

  // ReadbackPixels might have changed the current context. Make sure GL is
  // current again.
  MakeCurrent();

  if (aNeedsYFlip) {
    *aNeedsYFlip = true;
  }

  return success;
}

bool RenderCompositorLayerNative::MaybeRecordFrame(
    layers::CompositionRecorder& aRecorder) {
  if (!mNativeLayerRootSnapshotter) {
    mNativeLayerRootSnapshotter = mNativeLayerRoot->CreateSnapshotter();
  }

  if (!mNativeLayerRootSnapshotter) {
    return true;
  }

  gfx::IntSize size = GetBufferSize().ToUnknownSize();
  RefPtr<layers::profiler_screenshots::RenderSource> snapshot =
      mNativeLayerRootSnapshotter->GetWindowContents(size);
  if (!snapshot) {
    return true;
  }

  RefPtr<layers::profiler_screenshots::AsyncReadbackBuffer> buffer =
      mNativeLayerRootSnapshotter->CreateAsyncReadbackBuffer(size);
  buffer->CopyFrom(snapshot);

  RefPtr<layers::RecordedFrame> frame =
      new RenderCompositorRecordedFrame(TimeStamp::Now(), std::move(buffer));
  aRecorder.RecordFrame(frame);

  // GetWindowContents might have changed the current context. Make sure our
  // context is current again.
  MakeCurrent();
  return true;
}

bool RenderCompositorLayerNative::MaybeGrabScreenshot(
    const gfx::IntSize& aWindowSize) {
  if (!mozilla::layers::ProfilerScreenshots::IsEnabled()) {
    return false;
  }

  if (!mNativeLayerRootSnapshotter) {
    mNativeLayerRootSnapshotter = mNativeLayerRoot->CreateSnapshotter();
  }

  if (mNativeLayerRootSnapshotter) {
    mProfilerScreenshotGrabber.MaybeGrabScreenshot(*mNativeLayerRootSnapshotter,
                                                   aWindowSize);

    // MaybeGrabScreenshot might have changed the current context. Make sure our
    // context is current again.
    MakeCurrent();
  }

  return true;
}

bool RenderCompositorLayerNative::MaybeProcessScreenshotQueue() {
  mProfilerScreenshotGrabber.MaybeProcessQueue();

  // MaybeProcessQueue might have changed the current context. Make sure our
  // context is current again.
  MakeCurrent();

  return true;
}

void RenderCompositorLayerNative::WaitUntilPresentationFlushed() {
  mNativeLayerRoot->WaitUntilCommitToScreenHasBeenProcessed();
}

void RenderCompositorLayerNative::CompositorBeginFrame() {
  mAddedLayers.Clear();
  mBeginFrameTimeStamp = TimeStamp::Now();
  mSurfacePoolHandle->OnBeginFrame();
  mNativeLayerRoot->PrepareForCommit();
  mCurrentFrame++;
  if (mEnableAsyncScreenshotInNextFrame) {
    mEnableAsyncScreenshot = true;
    mEnableAsyncScreenshotInNextFrame = false;
  }
}

void RenderCompositorLayerNative::CompositorEndFrame() {
#if defined(XP_DARWIN)
  // MacOS fails rendering without the flush here.
  DoFlush();
#endif

  mAddedLayers.Reverse();

  mNativeLayerRoot->SetLayers(mAddedLayers);
  mNativeLayerRoot->CommitToScreen();
  mSurfacePoolHandle->OnEndFrame();
  if (mEnableAsyncScreenshot &&
      (mCurrentFrame - mAsyncScreenshotLastFrameUsed) > 1) {
    mEnableAsyncScreenshot = false;
  }
}

void RenderCompositorLayerNative::BindNativeLayer(wr::NativeSurfaceId aId) {
  MOZ_RELEASE_ASSERT(!mCurrentlyBoundNativeLayer);

  auto surfaceCursor = mSurfaces.find(aId);
  MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
  Surface& surface = surfaceCursor->second;

  mCurrentlyBoundNativeLayer = surface.mNativeLayer;
}

void RenderCompositorLayerNative::UnbindNativeLayer() {
  MOZ_RELEASE_ASSERT(mCurrentlyBoundNativeLayer);

  mCurrentlyBoundNativeLayer->NotifySurfaceReady();
  mCurrentlyBoundNativeLayer = nullptr;
}

void RenderCompositorLayerNative::CreateSurface(
    wr::NativeSurfaceId aId, wr::DeviceIntPoint aVirtualOffset,
    wr::DeviceIntSize aTileSize, bool aIsOpaque) {
  MOZ_ASSERT_UNREACHABLE("Unexpected to be called!");
}

void RenderCompositorLayerNative::CreateExternalSurface(wr::NativeSurfaceId aId,
                                                        bool aIsOpaque) {
  MOZ_RELEASE_ASSERT(mSurfaces.find(aId) == mSurfaces.end());

  RefPtr<layers::NativeLayer> layer =
      mNativeLayerRoot->CreateLayerForExternalTexture(aIsOpaque);

  Surface surface{DeviceIntSize{}, aIsOpaque};
  surface.mIsExternal = true;
  surface.mNativeLayer = layer;

  mSurfaces.insert({aId, std::move(surface)});
}

void RenderCompositorLayerNative::CreateSwapChainSurface(
    wr::NativeSurfaceId aId, wr::DeviceIntSize aSize, bool aIsOpaque,
    bool aNeedsSyncDcompCommit) {
  MOZ_RELEASE_ASSERT(mSurfaces.find(aId) == mSurfaces.end());

  Surface surface{aSize, aIsOpaque};
  surface.mNativeLayer = mNativeLayerRoot->CreateLayer(
      surface.Size(), aIsOpaque, mSurfacePoolHandle);

  mSurfaces.insert({aId, std::move(surface)});
}

void RenderCompositorLayerNative::ResizeSwapChainSurface(
    wr::NativeSurfaceId aId, wr::DeviceIntSize aSize) {
  auto surfaceCursor = mSurfaces.find(aId);
  MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
  Surface& surface = surfaceCursor->second;

  MOZ_ASSERT(!surface.mIsExternal);

  if (aSize == surface.mSize) {
    return;
  }

  surface.mSize = aSize;
  surface.mNativeLayer = mNativeLayerRoot->CreateLayer(
      surface.Size(), surface.mIsOpaque, mSurfacePoolHandle);
}

void RenderCompositorLayerNative::AttachExternalImage(
    wr::NativeSurfaceId aId, wr::ExternalImageId aExternalImage) {
  RenderTextureHost* image =
      RenderThread::Get()->GetRenderTexture(aExternalImage);
  MOZ_RELEASE_ASSERT(image);

  auto surfaceCursor = mSurfaces.find(aId);
  MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());

  Surface& surface = surfaceCursor->second;
  MOZ_RELEASE_ASSERT(surface.mNativeLayer);
  MOZ_RELEASE_ASSERT(surface.mIsExternal);
  surface.mNativeLayer->AttachExternalImage(image);
}

void RenderCompositorLayerNativeOGL::AttachExternalImage(
    wr::NativeSurfaceId aId, wr::ExternalImageId aExternalImage) {
  RenderTextureHost* image =
      RenderThread::Get()->GetRenderTexture(aExternalImage);

  // image->Lock only uses the channel index to populate the returned
  // `WrExternalImage`. Since we don't use that, it doesn't matter
  // what channel index we pass.
  image->Lock(0, mGL);

  RenderCompositorLayerNative::AttachExternalImage(aId, aExternalImage);
}

void RenderCompositorLayerNative::DestroySurface(NativeSurfaceId aId) {
  auto surfaceCursor = mSurfaces.find(aId);
  MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());

  mSurfaces.erase(surfaceCursor);
}

void RenderCompositorLayerNative::CreateTile(wr::NativeSurfaceId aId, int aX,
                                             int aY) {
  MOZ_ASSERT_UNREACHABLE("Unexpected to be called!");
}

void RenderCompositorLayerNative::DestroyTile(wr::NativeSurfaceId aId, int aX,
                                              int aY) {
  MOZ_ASSERT_UNREACHABLE("Unexpected to be called!");
}

/* static */
gfx::SamplingFilter RenderCompositorLayerNative::ToSamplingFilter(
    wr::ImageRendering aImageRendering) {
  if (aImageRendering == wr::ImageRendering::Auto) {
    return gfx::SamplingFilter::LINEAR;
  }
  return gfx::SamplingFilter::POINT;
}

void RenderCompositorLayerNative::AddSurface(
    wr::NativeSurfaceId aId, const wr::CompositorSurfaceTransform& aTransform,
    wr::DeviceIntRect aClipRect, wr::ImageRendering aImageRendering,
    wr::DeviceIntRect aRoundedClipRect, wr::ClipRadius aClipRadius) {
  MOZ_RELEASE_ASSERT(!mCurrentlyBoundNativeLayer);

  auto surfaceCursor = mSurfaces.find(aId);
  MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
  const Surface& surface = surfaceCursor->second;

  float sx = aTransform.scale.x;
  float sy = aTransform.scale.y;
  float tx = aTransform.offset.x;
  float ty = aTransform.offset.y;
  gfx::Matrix4x4 transform(sx, 0.00.00.00.0, sy, 0.00.00.00.01.0,
                           0.0, tx, ty, 0.01.0);

  RefPtr<layers::NativeLayer> layer = surface.mNativeLayer;
  gfx::IntPoint layerPosition(00);
  layer->SetPosition(layerPosition);
  gfx::IntRect clipRect(aClipRect.min.x, aClipRect.min.y, aClipRect.width(),
                        aClipRect.height());
  layer->SetClipRect(Some(clipRect));
  gfx::Rect roundedClipRect(aRoundedClipRect.min.x, aRoundedClipRect.min.y,
                            aRoundedClipRect.width(),
                            aRoundedClipRect.height());
  gfx::RectCornerRadii clipRadius(aClipRadius.top_left, aClipRadius.top_right,
                                  aClipRadius.bottom_right,
                                  aClipRadius.bottom_left);
  gfx::RoundedRect roundedClip(roundedClipRect, clipRadius);
  layer->SetRoundedClipRect(Some(roundedClip));
  layer->SetTransform(transform);
  layer->SetSamplingFilter(ToSamplingFilter(aImageRendering));
  mAddedLayers.AppendElement(layer);

  if (surface.mIsExternal) {
    RefPtr<layers::GpuFence> fence = layer->GetGpuFence();
    if (fence && BackendType() == layers::WebRenderBackend::HARDWARE) {
      mPendingGpuFeces.emplace_back(fence);
    }
  }
}

/* static */
UniquePtr<RenderCompositor> RenderCompositorLayerNativeOGL::Create(
    const RefPtr<widget::CompositorWidget>& aWidget, nsACString& aError) {
  RefPtr<gl::GLContext> gl = RenderThread::Get()->SingletonGL();
  if (!gl) {
    gl = gl::GLContextProvider::CreateForCompositorWidget(
        aWidget, /* aHardwareWebRender */ true, /* aForceAccelerated */ true);
    RenderThread::MaybeEnableGLDebugMessage(gl);
  }
  if (!gl || !gl->MakeCurrent()) {
    gfxCriticalNote << "Failed GL context creation for WebRender: "
                    << gfx::hexa(gl.get());
    return nullptr;
  }
  return MakeUnique<RenderCompositorLayerNativeOGL>(aWidget, std::move(gl));
}

RenderCompositorLayerNativeOGL::RenderCompositorLayerNativeOGL(
    const RefPtr<widget::CompositorWidget>& aWidget,
    RefPtr<gl::GLContext>&& aGL)
    : RenderCompositorLayerNative(aWidget, aGL), mGL(aGL) {
  MOZ_ASSERT(mGL);
}

RenderCompositorLayerNativeOGL::~RenderCompositorLayerNativeOGL() {
  if (!mGL->MakeCurrent()) {
    gfxCriticalNote
        << "Failed to make render context current during destroying.";
    // Leak resources!
    mPreviousFrameDoneFences = nullptr;
    mThisFrameDoneFences = nullptr;
    return;
  }

  if (mPreviousFrameDoneFences && mPreviousFrameDoneFences->mSync) {
    mGL->fDeleteSync(mPreviousFrameDoneFences->mSync);
  }
  if (mThisFrameDoneFences && mThisFrameDoneFences->mSync) {
    mGL->fDeleteSync(mThisFrameDoneFences->mSync);
  }
}

bool RenderCompositorLayerNativeOGL::InitDefaultFramebuffer() {
  mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mGL->GetDefaultFramebuffer());
  return true;
}

void RenderCompositorLayerNativeOGL::DoSwap() { InsertFrameDoneSync(); }

void RenderCompositorLayerNativeOGL::DoFlush() { mGL->fFlush(); }

void RenderCompositorLayerNativeOGL::InsertFrameDoneSync() {
#ifdef XP_DARWIN
  // Only do this on macOS.
  // On other platforms, SwapBuffers automatically applies back-pressure.
  if (mThisFrameDoneFences && mThisFrameDoneFences->mSync) {
    mGL->fDeleteSync(mThisFrameDoneFences->mSync);
  }
  mThisFrameDoneFences =
      MakeUnique<BackPressureFences>(std::move(mPendingGpuFeces));
  mThisFrameDoneFences->mSync =
      mGL->fFenceSync(LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
#endif
}

bool RenderCompositorLayerNativeOGL::WaitForGPU() {
  if (mPreviousFrameDoneFences) {
    bool complete = false;
    while (!complete) {
      complete = true;
      for (const auto& fence : mPreviousFrameDoneFences->mGpuFeces) {
        if (!fence->HasCompleted()) {
          complete = false;
          break;
        }
      }

      if (!complete) {
        PR_Sleep(PR_MillisecondsToInterval(1));
      }
    }

    if (mPreviousFrameDoneFences->mSync) {
      AUTO_PROFILER_LABEL("Waiting for GPU to finish previous frame", GRAPHICS);
      mGL->fClientWaitSync(mPreviousFrameDoneFences->mSync,
                           LOCAL_GL_SYNC_FLUSH_COMMANDS_BIT,
                           LOCAL_GL_TIMEOUT_IGNORED);
      mGL->fDeleteSync(mPreviousFrameDoneFences->mSync);
    }
  }
  mPreviousFrameDoneFences = std::move(mThisFrameDoneFences);
  MOZ_ASSERT(!mThisFrameDoneFences);

  return true;
}

void RenderCompositorLayerNativeOGL::BindSwapChain(
    wr::NativeSurfaceId aId, const wr::DeviceIntRect* aDirtyRects,
    size_t aNumDirtyRects) {
  BindNativeLayer(aId);
  MOZ_ASSERT(mCurrentlyBoundNativeLayer);

  gfx::IntSize size = mCurrentlyBoundNativeLayer->GetSize();
  gfx::IntRect validRect = mCurrentlyBoundNativeLayer->GetRect();

  const auto dirtyRect = [&]() {
    if (aNumDirtyRects > 0) {
      MOZ_RELEASE_ASSERT(aNumDirtyRects == 1);

      const auto& rect = aDirtyRects[0];

      // Clip rect to bufferSize
      int left = std::clamp((int)rect.min.x, 0, size.width);
      int top = std::clamp((int)rect.min.y, 0, size.height);
      int right = std::clamp((int)rect.max.x, 0, size.width);
      int bottom = std::clamp((int)rect.max.y, 0, size.height);

      int width = right - left;
      int height = bottom - top;
      MOZ_RELEASE_ASSERT(width >= 0);
      MOZ_RELEASE_ASSERT(height >= 0);

      return gfx::IntRect(left, top, width, height);
    }

    return gfx::IntRect(00, size.width, size.height);
  }();

  Maybe<GLuint> fbo = mCurrentlyBoundNativeLayer->NextSurfaceAsFramebuffer(
      validRect, dirtyRect, true);
  if (!fbo) {
    // XXX
    return;
  }
  mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, *fbo);
}

void RenderCompositorLayerNativeOGL::PresentSwapChain(
    wr::NativeSurfaceId aId, const wr::DeviceIntRect* aDirtyRects,
    size_t aNumDirtyRects) {
  mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);

  UnbindNativeLayer();
}

}  // namespace mozilla::wr

Messung V0.5 in Prozent
C=74 H=91 G=82

¤ Dauer der Verarbeitung: 0.6 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

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

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=141584
#Domains=752002