mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 02:09:05 +02:00 
			
		
		
		
	Original work by Nika Layzell and Ted Mielczarek. Of note: - GLdouble and GLclampd are not defined in the iPhoneOS SDK opengl headers. - GL_CONTEXT_PROVIDER_DEFAULT was defined too early for GLContextProviderEAGL to be used as intended. - GLContextProviderEAGL::CreateForCompositorWidget was aligned with GLContextProviderCGL::CreateForCompositorWidget. There is a ton of overlap between both, but sharing more code was left out of scope. - MacIOSurface::BindTexImage and SurfacePoolCA::LockedPool::GetFramebufferForSurface were left unimplemented. - RootSnapshotter is disabled. Differential Revision: https://phabricator.services.mozilla.com/D204323
		
			
				
	
	
		
			672 lines
		
	
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			672 lines
		
	
	
	
		
			22 KiB
		
	
	
	
		
			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 "RenderCompositorNative.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/NativeLayer.h"
 | 
						|
#include "mozilla/layers/SurfacePool.h"
 | 
						|
#include "mozilla/StaticPrefs_gfx.h"
 | 
						|
#include "mozilla/webrender/RenderThread.h"
 | 
						|
#include "mozilla/widget/CompositorWidget.h"
 | 
						|
#include "RenderCompositorRecordedFrame.h"
 | 
						|
 | 
						|
namespace mozilla::wr {
 | 
						|
 | 
						|
extern LazyLogModule gRenderThreadLog;
 | 
						|
#define LOG(...) MOZ_LOG(gRenderThreadLog, LogLevel::Debug, (__VA_ARGS__))
 | 
						|
 | 
						|
RenderCompositorNative::RenderCompositorNative(
 | 
						|
    const RefPtr<widget::CompositorWidget>& aWidget, gl::GLContext* aGL)
 | 
						|
    : RenderCompositor(aWidget),
 | 
						|
      mNativeLayerRoot(GetWidget()->GetNativeLayerRoot()) {
 | 
						|
  LOG("RenderCompositorNative::RenderCompositorNative()");
 | 
						|
 | 
						|
#if defined(XP_DARWIN) || defined(MOZ_WAYLAND)
 | 
						|
  auto pool = RenderThread::Get()->SharedSurfacePool();
 | 
						|
  if (pool) {
 | 
						|
    mSurfacePoolHandle = pool->GetHandleForGL(aGL);
 | 
						|
  }
 | 
						|
#endif
 | 
						|
  MOZ_RELEASE_ASSERT(mSurfacePoolHandle);
 | 
						|
}
 | 
						|
 | 
						|
RenderCompositorNative::~RenderCompositorNative() {
 | 
						|
  LOG("RRenderCompositorNative::~RenderCompositorNative()");
 | 
						|
 | 
						|
  Pause();
 | 
						|
  mProfilerScreenshotGrabber.Destroy();
 | 
						|
  mNativeLayerRoot->SetLayers({});
 | 
						|
  mNativeLayerForEntireWindow = nullptr;
 | 
						|
  mNativeLayerRootSnapshotter = nullptr;
 | 
						|
  mNativeLayerRoot = nullptr;
 | 
						|
}
 | 
						|
 | 
						|
bool RenderCompositorNative::BeginFrame() {
 | 
						|
  if (!MakeCurrent()) {
 | 
						|
    gfxCriticalNote << "Failed to make render context current, can't draw.";
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  gfx::IntSize bufferSize = GetBufferSize().ToUnknownSize();
 | 
						|
  if (!ShouldUseNativeCompositor()) {
 | 
						|
    if (bufferSize.IsEmpty()) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    if (mNativeLayerForEntireWindow &&
 | 
						|
        mNativeLayerForEntireWindow->GetSize() != bufferSize) {
 | 
						|
      mNativeLayerRoot->RemoveLayer(mNativeLayerForEntireWindow);
 | 
						|
      mNativeLayerForEntireWindow = nullptr;
 | 
						|
    }
 | 
						|
    if (!mNativeLayerForEntireWindow) {
 | 
						|
      mNativeLayerForEntireWindow =
 | 
						|
          mNativeLayerRoot->CreateLayer(bufferSize, false, mSurfacePoolHandle);
 | 
						|
      mNativeLayerRoot->AppendLayer(mNativeLayerForEntireWindow);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  gfx::IntRect bounds({}, bufferSize);
 | 
						|
  if (!InitDefaultFramebuffer(bounds)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
RenderedFrameId RenderCompositorNative::EndFrame(
 | 
						|
    const nsTArray<DeviceIntRect>& aDirtyRects) {
 | 
						|
  RenderedFrameId frameId = GetNextRenderFrameId();
 | 
						|
 | 
						|
  DoSwap();
 | 
						|
 | 
						|
  if (mNativeLayerForEntireWindow) {
 | 
						|
    mNativeLayerForEntireWindow->NotifySurfaceReady();
 | 
						|
    mNativeLayerRoot->CommitToScreen();
 | 
						|
  }
 | 
						|
 | 
						|
  return frameId;
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNative::Pause() {}
 | 
						|
 | 
						|
bool RenderCompositorNative::Resume() { return true; }
 | 
						|
 | 
						|
inline layers::WebRenderCompositor RenderCompositorNative::CompositorType()
 | 
						|
    const {
 | 
						|
  if (gfx::gfxVars::UseWebRenderCompositor()) {
 | 
						|
#if defined(XP_DARWIN)
 | 
						|
    return layers::WebRenderCompositor::CORE_ANIMATION;
 | 
						|
#elif defined(MOZ_WAYLAND)
 | 
						|
    return layers::WebRenderCompositor::WAYLAND;
 | 
						|
#endif
 | 
						|
  }
 | 
						|
  return layers::WebRenderCompositor::DRAW;
 | 
						|
}
 | 
						|
 | 
						|
LayoutDeviceIntSize RenderCompositorNative::GetBufferSize() {
 | 
						|
  return mWidget->GetClientSize();
 | 
						|
}
 | 
						|
 | 
						|
bool RenderCompositorNative::ShouldUseNativeCompositor() {
 | 
						|
  return gfx::gfxVars::UseWebRenderCompositor();
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNative::GetCompositorCapabilities(
 | 
						|
    CompositorCapabilities* aCaps) {
 | 
						|
  RenderCompositor::GetCompositorCapabilities(aCaps);
 | 
						|
#if defined(XP_DARWIN)
 | 
						|
  aCaps->supports_surface_for_backdrop = !gfx::gfxVars::UseSoftwareWebRender();
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
bool RenderCompositorNative::MaybeReadback(
 | 
						|
    const gfx::IntSize& aReadbackSize, const wr::ImageFormat& aReadbackFormat,
 | 
						|
    const Range<uint8_t>& aReadbackBuffer, bool* aNeedsYFlip) {
 | 
						|
  if (!ShouldUseNativeCompositor()) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  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 RenderCompositorNative::MaybeRecordFrame(
 | 
						|
    layers::CompositionRecorder& aRecorder) {
 | 
						|
  if (!ShouldUseNativeCompositor()) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  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 RenderCompositorNative::MaybeGrabScreenshot(
 | 
						|
    const gfx::IntSize& aWindowSize) {
 | 
						|
  if (!ShouldUseNativeCompositor()) {
 | 
						|
    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 RenderCompositorNative::MaybeProcessScreenshotQueue() {
 | 
						|
  if (!ShouldUseNativeCompositor()) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  mProfilerScreenshotGrabber.MaybeProcessQueue();
 | 
						|
 | 
						|
  // MaybeProcessQueue might have changed the current context. Make sure our
 | 
						|
  // context is current again.
 | 
						|
  MakeCurrent();
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNative::CompositorBeginFrame() {
 | 
						|
  mAddedLayers.Clear();
 | 
						|
  mAddedTilePixelCount = 0;
 | 
						|
  mAddedClippedPixelCount = 0;
 | 
						|
  mBeginFrameTimeStamp = TimeStamp::Now();
 | 
						|
  mSurfacePoolHandle->OnBeginFrame();
 | 
						|
  mNativeLayerRoot->PrepareForCommit();
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNative::CompositorEndFrame() {
 | 
						|
  if (profiler_thread_is_being_profiled_for_markers()) {
 | 
						|
    auto bufferSize = GetBufferSize();
 | 
						|
    [[maybe_unused]] uint64_t windowPixelCount =
 | 
						|
        uint64_t(bufferSize.width) * bufferSize.height;
 | 
						|
    int nativeLayerCount = 0;
 | 
						|
    for (const auto& it : mSurfaces) {
 | 
						|
      nativeLayerCount += int(it.second.mNativeLayers.size());
 | 
						|
    }
 | 
						|
    PROFILER_MARKER_TEXT(
 | 
						|
        "WR OS Compositor frame", GRAPHICS,
 | 
						|
        MarkerTiming::IntervalUntilNowFrom(mBeginFrameTimeStamp),
 | 
						|
        nsPrintfCString("%d%% painting, %d%% overdraw, %d used "
 | 
						|
                        "layers (%d%% memory) + %d unused layers (%d%% memory)",
 | 
						|
                        int(mDrawnPixelCount * 100 / windowPixelCount),
 | 
						|
                        int(mAddedClippedPixelCount * 100 / windowPixelCount),
 | 
						|
                        int(mAddedLayers.Length()),
 | 
						|
                        int(mAddedTilePixelCount * 100 / windowPixelCount),
 | 
						|
                        int(nativeLayerCount - mAddedLayers.Length()),
 | 
						|
                        int((mTotalTilePixelCount - mAddedTilePixelCount) *
 | 
						|
                            100 / windowPixelCount)));
 | 
						|
  }
 | 
						|
  mDrawnPixelCount = 0;
 | 
						|
 | 
						|
  DoFlush();
 | 
						|
 | 
						|
  mNativeLayerRoot->SetLayers(mAddedLayers);
 | 
						|
  mNativeLayerRoot->CommitToScreen();
 | 
						|
  mSurfacePoolHandle->OnEndFrame();
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNative::BindNativeLayer(wr::NativeTileId aId,
 | 
						|
                                             const gfx::IntRect& aDirtyRect) {
 | 
						|
  MOZ_RELEASE_ASSERT(!mCurrentlyBoundNativeLayer);
 | 
						|
 | 
						|
  auto surfaceCursor = mSurfaces.find(aId.surface_id);
 | 
						|
  MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
 | 
						|
  Surface& surface = surfaceCursor->second;
 | 
						|
 | 
						|
  auto layerCursor = surface.mNativeLayers.find(TileKey(aId.x, aId.y));
 | 
						|
  MOZ_RELEASE_ASSERT(layerCursor != surface.mNativeLayers.end());
 | 
						|
  RefPtr<layers::NativeLayer> layer = layerCursor->second;
 | 
						|
 | 
						|
  mCurrentlyBoundNativeLayer = layer;
 | 
						|
 | 
						|
  mDrawnPixelCount += aDirtyRect.Area();
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNative::UnbindNativeLayer() {
 | 
						|
  MOZ_RELEASE_ASSERT(mCurrentlyBoundNativeLayer);
 | 
						|
 | 
						|
  mCurrentlyBoundNativeLayer->NotifySurfaceReady();
 | 
						|
  mCurrentlyBoundNativeLayer = nullptr;
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNative::CreateSurface(wr::NativeSurfaceId aId,
 | 
						|
                                           wr::DeviceIntPoint aVirtualOffset,
 | 
						|
                                           wr::DeviceIntSize aTileSize,
 | 
						|
                                           bool aIsOpaque) {
 | 
						|
  MOZ_RELEASE_ASSERT(mSurfaces.find(aId) == mSurfaces.end());
 | 
						|
  mSurfaces.insert({aId, Surface{aTileSize, aIsOpaque}});
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNative::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.mNativeLayers.insert({TileKey(0, 0), layer});
 | 
						|
 | 
						|
  mSurfaces.insert({aId, std::move(surface)});
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNative::CreateBackdropSurface(wr::NativeSurfaceId aId,
 | 
						|
                                                   wr::ColorF aColor) {
 | 
						|
  MOZ_RELEASE_ASSERT(mSurfaces.find(aId) == mSurfaces.end());
 | 
						|
 | 
						|
  gfx::DeviceColor color(aColor.r, aColor.g, aColor.b, aColor.a);
 | 
						|
  RefPtr<layers::NativeLayer> layer =
 | 
						|
      mNativeLayerRoot->CreateLayerForColor(color);
 | 
						|
 | 
						|
  Surface surface{DeviceIntSize{}, (aColor.a >= 1.0f)};
 | 
						|
  surface.mNativeLayers.insert({TileKey(0, 0), layer});
 | 
						|
 | 
						|
  mSurfaces.insert({aId, std::move(surface)});
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNative::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.mNativeLayers.size() == 1);
 | 
						|
  MOZ_RELEASE_ASSERT(surface.mIsExternal);
 | 
						|
  surface.mNativeLayers.begin()->second->AttachExternalImage(image);
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNative::DestroySurface(NativeSurfaceId aId) {
 | 
						|
  auto surfaceCursor = mSurfaces.find(aId);
 | 
						|
  MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
 | 
						|
 | 
						|
  Surface& surface = surfaceCursor->second;
 | 
						|
  if (!surface.mIsExternal) {
 | 
						|
    for (const auto& iter : surface.mNativeLayers) {
 | 
						|
      mTotalTilePixelCount -= gfx::IntRect({}, iter.second->GetSize()).Area();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  mSurfaces.erase(surfaceCursor);
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNative::CreateTile(wr::NativeSurfaceId aId, int aX,
 | 
						|
                                        int aY) {
 | 
						|
  auto surfaceCursor = mSurfaces.find(aId);
 | 
						|
  MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
 | 
						|
  Surface& surface = surfaceCursor->second;
 | 
						|
  MOZ_RELEASE_ASSERT(!surface.mIsExternal);
 | 
						|
 | 
						|
  RefPtr<layers::NativeLayer> layer = mNativeLayerRoot->CreateLayer(
 | 
						|
      surface.TileSize(), surface.mIsOpaque, mSurfacePoolHandle);
 | 
						|
  surface.mNativeLayers.insert({TileKey(aX, aY), layer});
 | 
						|
  mTotalTilePixelCount += gfx::IntRect({}, layer->GetSize()).Area();
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNative::DestroyTile(wr::NativeSurfaceId aId, int aX,
 | 
						|
                                         int aY) {
 | 
						|
  auto surfaceCursor = mSurfaces.find(aId);
 | 
						|
  MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
 | 
						|
  Surface& surface = surfaceCursor->second;
 | 
						|
  MOZ_RELEASE_ASSERT(!surface.mIsExternal);
 | 
						|
 | 
						|
  auto layerCursor = surface.mNativeLayers.find(TileKey(aX, aY));
 | 
						|
  MOZ_RELEASE_ASSERT(layerCursor != surface.mNativeLayers.end());
 | 
						|
  RefPtr<layers::NativeLayer> layer = std::move(layerCursor->second);
 | 
						|
  surface.mNativeLayers.erase(layerCursor);
 | 
						|
  mTotalTilePixelCount -= gfx::IntRect({}, layer->GetSize()).Area();
 | 
						|
 | 
						|
  // If the layer is currently present in mNativeLayerRoot, it will be destroyed
 | 
						|
  // once CompositorEndFrame() replaces mNativeLayerRoot's layers and drops that
 | 
						|
  // reference. So until that happens, the layer still needs to hold on to its
 | 
						|
  // front buffer. However, we can tell it to drop its back buffers now, because
 | 
						|
  // we know that we will never draw to it again.
 | 
						|
  // Dropping the back buffers now puts them back in the surface pool, so those
 | 
						|
  // surfaces can be immediately re-used for drawing in other layers in the
 | 
						|
  // current frame.
 | 
						|
  layer->DiscardBackbuffers();
 | 
						|
}
 | 
						|
 | 
						|
gfx::SamplingFilter ToSamplingFilter(wr::ImageRendering aImageRendering) {
 | 
						|
  if (aImageRendering == wr::ImageRendering::Auto) {
 | 
						|
    return gfx::SamplingFilter::LINEAR;
 | 
						|
  }
 | 
						|
  return gfx::SamplingFilter::POINT;
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNative::AddSurface(
 | 
						|
    wr::NativeSurfaceId aId, const wr::CompositorSurfaceTransform& aTransform,
 | 
						|
    wr::DeviceIntRect aClipRect, wr::ImageRendering aImageRendering) {
 | 
						|
  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.0, 0.0, 0.0, 0.0, sy, 0.0, 0.0, 0.0, 0.0, 1.0,
 | 
						|
                           0.0, tx, ty, 0.0, 1.0);
 | 
						|
 | 
						|
  for (auto it = surface.mNativeLayers.begin();
 | 
						|
       it != surface.mNativeLayers.end(); ++it) {
 | 
						|
    RefPtr<layers::NativeLayer> layer = it->second;
 | 
						|
    gfx::IntSize layerSize = layer->GetSize();
 | 
						|
    gfx::IntPoint layerPosition(surface.mTileSize.width * it->first.mX,
 | 
						|
                                surface.mTileSize.height * it->first.mY);
 | 
						|
    layer->SetPosition(layerPosition);
 | 
						|
    gfx::IntRect clipRect(aClipRect.min.x, aClipRect.min.y, aClipRect.width(),
 | 
						|
                          aClipRect.height());
 | 
						|
    layer->SetClipRect(Some(clipRect));
 | 
						|
    layer->SetTransform(transform);
 | 
						|
    layer->SetSamplingFilter(ToSamplingFilter(aImageRendering));
 | 
						|
    mAddedLayers.AppendElement(layer);
 | 
						|
 | 
						|
    if (!surface.mIsExternal) {
 | 
						|
      mAddedTilePixelCount += layerSize.width * layerSize.height;
 | 
						|
    }
 | 
						|
    gfx::Rect r = transform.TransformBounds(
 | 
						|
        gfx::Rect(layer->CurrentSurfaceDisplayRect()));
 | 
						|
    gfx::IntRect visibleRect =
 | 
						|
        clipRect.Intersect(RoundedToInt(r) + layerPosition);
 | 
						|
    mAddedClippedPixelCount += visibleRect.Area();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
UniquePtr<RenderCompositor> RenderCompositorNativeOGL::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<RenderCompositorNativeOGL>(aWidget, std::move(gl));
 | 
						|
}
 | 
						|
 | 
						|
RenderCompositorNativeOGL::RenderCompositorNativeOGL(
 | 
						|
    const RefPtr<widget::CompositorWidget>& aWidget,
 | 
						|
    RefPtr<gl::GLContext>&& aGL)
 | 
						|
    : RenderCompositorNative(aWidget, aGL), mGL(aGL) {
 | 
						|
  MOZ_ASSERT(mGL);
 | 
						|
}
 | 
						|
 | 
						|
RenderCompositorNativeOGL::~RenderCompositorNativeOGL() {
 | 
						|
  if (!mGL->MakeCurrent()) {
 | 
						|
    gfxCriticalNote
 | 
						|
        << "Failed to make render context current during destroying.";
 | 
						|
    // Leak resources!
 | 
						|
    mPreviousFrameDoneSync = nullptr;
 | 
						|
    mThisFrameDoneSync = nullptr;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (mPreviousFrameDoneSync) {
 | 
						|
    mGL->fDeleteSync(mPreviousFrameDoneSync);
 | 
						|
  }
 | 
						|
  if (mThisFrameDoneSync) {
 | 
						|
    mGL->fDeleteSync(mThisFrameDoneSync);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool RenderCompositorNativeOGL::InitDefaultFramebuffer(
 | 
						|
    const gfx::IntRect& aBounds) {
 | 
						|
  if (mNativeLayerForEntireWindow) {
 | 
						|
    Maybe<GLuint> fbo = mNativeLayerForEntireWindow->NextSurfaceAsFramebuffer(
 | 
						|
        aBounds, aBounds, true);
 | 
						|
    if (!fbo) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, *fbo);
 | 
						|
  } else {
 | 
						|
    mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mGL->GetDefaultFramebuffer());
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNativeOGL::DoSwap() {
 | 
						|
  InsertFrameDoneSync();
 | 
						|
  if (mNativeLayerForEntireWindow) {
 | 
						|
    mGL->fFlush();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNativeOGL::DoFlush() { mGL->fFlush(); }
 | 
						|
 | 
						|
void RenderCompositorNativeOGL::InsertFrameDoneSync() {
 | 
						|
#ifdef XP_DARWIN
 | 
						|
  // Only do this on macOS.
 | 
						|
  // On other platforms, SwapBuffers automatically applies back-pressure.
 | 
						|
  if (mThisFrameDoneSync) {
 | 
						|
    mGL->fDeleteSync(mThisFrameDoneSync);
 | 
						|
  }
 | 
						|
  mThisFrameDoneSync = mGL->fFenceSync(LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
bool RenderCompositorNativeOGL::WaitForGPU() {
 | 
						|
  if (mPreviousFrameDoneSync) {
 | 
						|
    AUTO_PROFILER_LABEL("Waiting for GPU to finish previous frame", GRAPHICS);
 | 
						|
    mGL->fClientWaitSync(mPreviousFrameDoneSync,
 | 
						|
                         LOCAL_GL_SYNC_FLUSH_COMMANDS_BIT,
 | 
						|
                         LOCAL_GL_TIMEOUT_IGNORED);
 | 
						|
    mGL->fDeleteSync(mPreviousFrameDoneSync);
 | 
						|
  }
 | 
						|
  mPreviousFrameDoneSync = mThisFrameDoneSync;
 | 
						|
  mThisFrameDoneSync = nullptr;
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNativeOGL::Bind(wr::NativeTileId aId,
 | 
						|
                                     wr::DeviceIntPoint* aOffset,
 | 
						|
                                     uint32_t* aFboId,
 | 
						|
                                     wr::DeviceIntRect aDirtyRect,
 | 
						|
                                     wr::DeviceIntRect aValidRect) {
 | 
						|
  gfx::IntRect validRect(aValidRect.min.x, aValidRect.min.y, aValidRect.width(),
 | 
						|
                         aValidRect.height());
 | 
						|
  gfx::IntRect dirtyRect(aDirtyRect.min.x, aDirtyRect.min.y, aDirtyRect.width(),
 | 
						|
                         aDirtyRect.height());
 | 
						|
 | 
						|
  BindNativeLayer(aId, dirtyRect);
 | 
						|
 | 
						|
  Maybe<GLuint> fbo = mCurrentlyBoundNativeLayer->NextSurfaceAsFramebuffer(
 | 
						|
      validRect, dirtyRect, true);
 | 
						|
 | 
						|
  *aFboId = *fbo;
 | 
						|
  *aOffset = wr::DeviceIntPoint{0, 0};
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNativeOGL::Unbind() {
 | 
						|
  mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
 | 
						|
 | 
						|
  UnbindNativeLayer();
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
UniquePtr<RenderCompositor> RenderCompositorNativeSWGL::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<RenderCompositorNativeSWGL>(aWidget, ctx);
 | 
						|
}
 | 
						|
 | 
						|
RenderCompositorNativeSWGL::RenderCompositorNativeSWGL(
 | 
						|
    const RefPtr<widget::CompositorWidget>& aWidget, void* aContext)
 | 
						|
    : RenderCompositorNative(aWidget), mContext(aContext) {
 | 
						|
  MOZ_ASSERT(mContext);
 | 
						|
}
 | 
						|
 | 
						|
RenderCompositorNativeSWGL::~RenderCompositorNativeSWGL() {
 | 
						|
  wr_swgl_destroy_context(mContext);
 | 
						|
}
 | 
						|
 | 
						|
bool RenderCompositorNativeSWGL::MakeCurrent() {
 | 
						|
  wr_swgl_make_current(mContext);
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool RenderCompositorNativeSWGL::InitDefaultFramebuffer(
 | 
						|
    const gfx::IntRect& aBounds) {
 | 
						|
  if (mNativeLayerForEntireWindow) {
 | 
						|
    if (!MapNativeLayer(mNativeLayerForEntireWindow, aBounds, aBounds)) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    wr_swgl_init_default_framebuffer(mContext, aBounds.x, aBounds.y,
 | 
						|
                                     aBounds.width, aBounds.height,
 | 
						|
                                     mLayerStride, mLayerValidRectData);
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNativeSWGL::CancelFrame() {
 | 
						|
  if (mNativeLayerForEntireWindow && mLayerTarget) {
 | 
						|
    wr_swgl_init_default_framebuffer(mContext, 0, 0, 0, 0, 0, nullptr);
 | 
						|
    UnmapNativeLayer();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNativeSWGL::DoSwap() {
 | 
						|
  if (mNativeLayerForEntireWindow && mLayerTarget) {
 | 
						|
    wr_swgl_init_default_framebuffer(mContext, 0, 0, 0, 0, 0, nullptr);
 | 
						|
    UnmapNativeLayer();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool RenderCompositorNativeSWGL::MapNativeLayer(
 | 
						|
    layers::NativeLayer* aLayer, const gfx::IntRect& aDirtyRect,
 | 
						|
    const gfx::IntRect& aValidRect) {
 | 
						|
  uint8_t* data = nullptr;
 | 
						|
  gfx::IntSize size;
 | 
						|
  int32_t stride = 0;
 | 
						|
  gfx::SurfaceFormat format = gfx::SurfaceFormat::UNKNOWN;
 | 
						|
  RefPtr<gfx::DrawTarget> dt = aLayer->NextSurfaceAsDrawTarget(
 | 
						|
      aValidRect, gfx::IntRegion(aDirtyRect), gfx::BackendType::SKIA);
 | 
						|
  if (!dt || !dt->LockBits(&data, &size, &stride, &format)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  MOZ_ASSERT(format == gfx::SurfaceFormat::B8G8R8A8 ||
 | 
						|
             format == gfx::SurfaceFormat::B8G8R8X8);
 | 
						|
  mLayerTarget = std::move(dt);
 | 
						|
  mLayerData = data;
 | 
						|
  mLayerValidRectData = data + aValidRect.y * stride + aValidRect.x * 4;
 | 
						|
  mLayerStride = stride;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNativeSWGL::UnmapNativeLayer() {
 | 
						|
  MOZ_ASSERT(mLayerTarget && mLayerData);
 | 
						|
  mLayerTarget->ReleaseBits(mLayerData);
 | 
						|
  mLayerTarget = nullptr;
 | 
						|
  mLayerData = nullptr;
 | 
						|
  mLayerValidRectData = nullptr;
 | 
						|
  mLayerStride = 0;
 | 
						|
}
 | 
						|
 | 
						|
bool RenderCompositorNativeSWGL::MapTile(wr::NativeTileId aId,
 | 
						|
                                         wr::DeviceIntRect aDirtyRect,
 | 
						|
                                         wr::DeviceIntRect aValidRect,
 | 
						|
                                         void** aData, int32_t* aStride) {
 | 
						|
  if (mNativeLayerForEntireWindow) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  gfx::IntRect dirtyRect(aDirtyRect.min.x, aDirtyRect.min.y, aDirtyRect.width(),
 | 
						|
                         aDirtyRect.height());
 | 
						|
  gfx::IntRect validRect(aValidRect.min.x, aValidRect.min.y, aValidRect.width(),
 | 
						|
                         aValidRect.height());
 | 
						|
  BindNativeLayer(aId, dirtyRect);
 | 
						|
  if (!MapNativeLayer(mCurrentlyBoundNativeLayer, dirtyRect, validRect)) {
 | 
						|
    UnbindNativeLayer();
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  *aData = mLayerValidRectData;
 | 
						|
  *aStride = mLayerStride;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
void RenderCompositorNativeSWGL::UnmapTile() {
 | 
						|
  if (!mNativeLayerForEntireWindow && mCurrentlyBoundNativeLayer) {
 | 
						|
    UnmapNativeLayer();
 | 
						|
    UnbindNativeLayer();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace mozilla::wr
 |