Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/gfx/webrender_bindings/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 11 kB image not shown  

Quelle  RenderCompositorSWGL.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 "RenderCompositorSWGL.h"

#include "mozilla/gfx/Logging.h"
#include "mozilla/widget/CompositorWidget.h"

#ifdef MOZ_WIDGET_GTK
#  include "mozilla/WidgetUtilsGtk.h"
#endif

namespace mozilla {
using namespace gfx;

namespace wr {

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

/* static */
UniquePtr<RenderCompositor> RenderCompositorSWGL::Create(
    const RefPtr<widget::CompositorWidget>& aWidget, nsACString& aError) {
  void* ctx = wr_swgl_create_context();
  if (!ctx) {
    gfxCriticalNote << "Failed SWGL context creation for WebRender";
    return nullptr;
  }
  return MakeUnique<RenderCompositorSWGL>(aWidget, ctx);
}

RenderCompositorSWGL::RenderCompositorSWGL(
    const RefPtr<widget::CompositorWidget>& aWidget, void* aContext)
    : RenderCompositor(aWidget), mContext(aContext) {
  MOZ_ASSERT(mContext);
  LOG("RenderCompositorSWGL::RenderCompositorSWGL()");
}

RenderCompositorSWGL::~RenderCompositorSWGL() {
  LOG("RenderCompositorSWGL::~RenderCompositorSWGL()");

  wr_swgl_destroy_context(mContext);
}

void RenderCompositorSWGL::ClearMappedBuffer() {
  mMappedData = nullptr;
  mMappedStride = 0;
  mDT = nullptr;
}

bool RenderCompositorSWGL::MakeCurrent() {
  wr_swgl_make_current(mContext);
  return true;
}

bool RenderCompositorSWGL::BeginFrame() {
  mRenderWidgetSize = Some(mWidget->GetClientSize());
#ifdef MOZ_WIDGET_GTK
  if (mLastRenderWidgetSize != mRenderWidgetSize.value()) {
    mLastRenderWidgetSize = mRenderWidgetSize.value();
    mRequestFullRender = true;
  }
#endif
  // Set up a temporary region representing the entire window surface in case a
  // dirty region is not supplied.
  ClearMappedBuffer();
  mDirtyRegion = LayoutDeviceIntRect(LayoutDeviceIntPoint(), GetBufferSize());
  wr_swgl_make_current(mContext);
  return true;
}

bool RenderCompositorSWGL::AllocateMappedBuffer(
    const wr::DeviceIntRect* aOpaqueRects, size_t aNumOpaqueRects) {
  // Request a new draw target to use from the widget...
  MOZ_ASSERT(!mDT);
  layers::BufferMode bufferMode = layers::BufferMode::BUFFERED;
  mDT = mWidget->StartRemoteDrawingInRegion(mDirtyRegion, &bufferMode);
  if (!mDT) {
    gfxCriticalNoteOnce
        << "RenderCompositorSWGL failed mapping default framebuffer, no dt";
    return false;
  }
  // Attempt to lock the underlying buffer directly from the draw target.
  // Verify that the size at least matches what the widget claims and that
  // the format is BGRA8 as SWGL requires.
  uint8_t* data = nullptr;
  gfx::IntSize size;
  int32_t stride = 0;
  gfx::SurfaceFormat format = gfx::SurfaceFormat::UNKNOWN;
  if (bufferMode != layers::BufferMode::BUFFERED && !mSurface &&
      mDT->LockBits(&data, &size, &stride, &format) &&
      (format != gfx::SurfaceFormat::B8G8R8A8 &&
       format != gfx::SurfaceFormat::B8G8R8X8)) {
    // We tried to lock the DT and it succeeded, but the size or format
    // of the data is not compatible, so just release it and fall back below...
    mDT->ReleaseBits(data);
    data = nullptr;
  }
  LayoutDeviceIntRect bounds = mDirtyRegion.GetBounds();
  // If locking succeeded above, just use that.
  if (data) {
    mMappedData = data;
    mMappedStride = stride;
    // Disambiguate whether the widget's draw target has its origin at zero or
    // if it is offset to the dirty region origin. The DT might either enclose
    // only the region itself, the region including the origin, or the entire
    // widget. Thus, if the DT doesn't only enclose the region, we assume it
    // contains the origin.
    if (size != bounds.Size().ToUnknownSize()) {
      // Update the bounds to include zero if the origin is at zero.
      bounds.ExpandToEnclose(LayoutDeviceIntPoint(0, 0));
    }
    // Sometimes we end up racing on the widget size, and it can shrink between
    // BeginFrame and StartCompositing. We calculated our dirty region based on
    // the previous widget size, so we need to clamp the bounds here to ensure
    // we remain within the buffer.
    bounds.IntersectRect(
        bounds,
        LayoutDeviceIntRect(bounds.TopLeft(),
                            LayoutDeviceIntSize(size.width, size.height)));
  } else {
    // If we couldn't lock the DT above, then allocate a data surface and map
    // that for usage with SWGL.
    size = bounds.Size().ToUnknownSize();
    if (!mSurface || mSurface->GetSize() != size) {
      mSurface = gfx::Factory::CreateDataSourceSurface(
          size, gfx::SurfaceFormat::B8G8R8A8);
    }
    gfx::DataSourceSurface::MappedSurface map = {nullptr, 0};
    if (!mSurface || !mSurface->Map(gfx::DataSourceSurface::READ_WRITE, &map)) {
      // We failed mapping the data surface, so need to cancel the frame.
      mWidget->EndRemoteDrawingInRegion(mDT, mDirtyRegion);
      ClearMappedBuffer();
      gfxCriticalNoteOnce
          << "RenderCompositorSWGL failed mapping default framebuffer, no surf";
      return false;
    }
    mMappedData = map.mData;
    mMappedStride = map.mStride;
  }
  MOZ_ASSERT(mMappedData != nullptr && mMappedStride > 0);
  wr_swgl_init_default_framebuffer(mContext, bounds.x, bounds.y, bounds.width,
                                   bounds.height, mMappedStride, mMappedData);

  LayoutDeviceIntRegion opaque;
  for (size_t i = 0; i < aNumOpaqueRects; i++) {
    const auto& rect = aOpaqueRects[i];
    opaque.OrWith(LayoutDeviceIntRect(rect.min.x, rect.min.y, rect.width(),
                                      rect.height()));
  }

  LayoutDeviceIntRegion clear = mWidget->GetTransparentRegion();
  clear.AndWith(mDirtyRegion);
  clear.SubOut(opaque);
  for (auto iter = clear.RectIter(); !iter.Done(); iter.Next()) {
    const auto& rect = iter.Get();
    wr_swgl_clear_color_rect(mContext, 0, rect.x, rect.y, rect.width,
                             rect.height, 0, 0, 0, 0);
  }

  return true;
}

void RenderCompositorSWGL::StartCompositing(
    wr::ColorF aClearColor, const wr::DeviceIntRect* aDirtyRects,
    size_t aNumDirtyRects, const wr::DeviceIntRect* aOpaqueRects,
    size_t aNumOpaqueRects) {
  if (mDT) {
    // Cancel any existing buffers that might accidentally be left from updates
    CommitMappedBuffer(false);
    // Reset the region to the widget bounds
    mDirtyRegion = LayoutDeviceIntRect(LayoutDeviceIntPoint(), GetBufferSize());
  }
  if (aNumDirtyRects) {
    // Install the dirty rects into the bounds of the existing region
    auto bounds = mDirtyRegion.GetBounds();
    mDirtyRegion.SetEmpty();
    for (size_t i = 0; i < aNumDirtyRects; i++) {
      const auto& rect = aDirtyRects[i];
      mDirtyRegion.OrWith(LayoutDeviceIntRect(rect.min.x, rect.min.y,
                                              rect.width(), rect.height()));
    }
    // Ensure the region lies within the widget bounds
    mDirtyRegion.AndWith(bounds);
  }
  // Now that the dirty rects have been supplied and the composition region
  // is known, allocate and install a framebuffer encompassing the composition
  // region.
  if (mDirtyRegion.IsEmpty() ||
      !AllocateMappedBuffer(aOpaqueRects, aNumOpaqueRects)) {
    // If allocation of the mapped default framebuffer failed, then just install
    // a temporary framebuffer (with a minimum size of 2x2) so compositing can
    // still proceed.
    auto bounds = mDirtyRegion.GetBounds();
    bounds.width = std::max(bounds.width, 2);
    bounds.height = std::max(bounds.height, 2);
    wr_swgl_init_default_framebuffer(mContext, bounds.x, bounds.y, bounds.width,
                                     bounds.height, 0, nullptr);
  }
}

void RenderCompositorSWGL::CommitMappedBuffer(bool aDirty) {
  if (!mDT) {
    mDirtyRegion.SetEmpty();
    return;
  }
  // Force any delayed clears to resolve.
  if (aDirty) {
    wr_swgl_resolve_framebuffer(mContext, 0);
  }
  // Clear out the old framebuffer in case something tries to access it after
  // the frame.
  wr_swgl_init_default_framebuffer(mContext, 0, 0, 0, 0, 0, nullptr);
  // If we have a draw target at this point, mapping must have succeeded.
  MOZ_ASSERT(mMappedData != nullptr);
  if (mSurface) {
    // If we're using a data surface, unmap it and draw it to the DT if there
    // are any supplied dirty rects.
    mSurface->Unmap();
    if (aDirty) {
      // The temporary source surface is always a partial region of the widget
      // that is offset from the origin to the actual bounds of the dirty
      // region. The destination DT may also be an offset partial region, but we
      // must check to see if its size matches the region bounds to verify this.
      LayoutDeviceIntRect bounds = mDirtyRegion.GetBounds();
      gfx::IntPoint srcOffset = bounds.TopLeft().ToUnknownPoint();
      gfx::IntPoint dstOffset = mDT->GetSize() == bounds.Size().ToUnknownSize()
                                    ? srcOffset
                                    : gfx::IntPoint(0, 0);
      for (auto iter = mDirtyRegion.RectIter(); !iter.Done(); iter.Next()) {
        gfx::IntRect dirtyRect = iter.Get().ToUnknownRect();
        mDT->CopySurface(mSurface, dirtyRect - srcOffset,
                         dirtyRect.TopLeft() - dstOffset);
      }
    }
  } else {
    // Otherwise, we had locked the DT directly. Just release the data.
    mDT->ReleaseBits(mMappedData);
  }
  mDT->Flush();

  // Done with the DT. Hand it back to the widget and clear out any trace of it.
  mWidget->EndRemoteDrawingInRegion(mDT, mDirtyRegion);
  mDirtyRegion.SetEmpty();
  ClearMappedBuffer();
}

void RenderCompositorSWGL::CancelFrame() {
  CommitMappedBuffer(false);
  mRenderWidgetSize = Nothing();
}

RenderedFrameId RenderCompositorSWGL::EndFrame(
    const nsTArray<DeviceIntRect>& aDirtyRects) {
  // Dirty rects have already been set inside StartCompositing. We need to keep
  // those dirty rects exactly the same here so we supply the same exact region
  // to EndRemoteDrawingInRegion as for StartRemoteDrawingInRegion.
  RenderedFrameId frameId = GetNextRenderFrameId();
  CommitMappedBuffer();
  mRenderWidgetSize = Nothing();
  return frameId;
}

bool RenderCompositorSWGL::RequestFullRender() {
#ifdef MOZ_WIDGET_ANDROID
  // XXX Add partial present support.
  return true;
#endif
#ifdef MOZ_WIDGET_GTK
  // We're requested to do full render after Resume() on Wayland.
  if (mRequestFullRender) {
    mRequestFullRender = false;
    return true;
  }
#endif
  return false;
}

void RenderCompositorSWGL::Pause() {}

bool RenderCompositorSWGL::Resume() {
#ifdef MOZ_WIDGET_GTK
  mRequestFullRender = true;
#endif
  return true;
}

LayoutDeviceIntSize RenderCompositorSWGL::GetBufferSize() {
  // If we're between BeginFrame() and EndFrame()/CancelFrame() calls
  // return recent rendering size instead of actual underlying widget
  // size. It prevents possible rendering artifacts if widget size was changed.
  return mRenderWidgetSize ? mRenderWidgetSize.value()
                           : mWidget->GetClientSize();
}

void RenderCompositorSWGL::GetCompositorCapabilities(
    CompositorCapabilities* aCaps) {
  // Always support a single update rect for SwCompositor
  aCaps->max_update_rects = 1;

  // On uncomposited desktops such as X11 without compositor or Window 7 with
  // Aero disabled we need to force a full redraw when the window contents may
  // be damaged.
#ifdef MOZ_WIDGET_GTK
  aCaps->redraw_on_invalidation = widget::GdkIsX11Display();
#else
  aCaps->redraw_on_invalidation = true;
#endif
}

}  // namespace wr
}  // namespace mozilla

Messung V0.5
C=92 H=98 G=94

¤ Dauer der Verarbeitung: 0.3 Sekunden  ¤

*© 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.