diff options
Diffstat (limited to 'gfx/webrender_bindings/RenderCompositorNative.cpp')
-rw-r--r-- | gfx/webrender_bindings/RenderCompositorNative.cpp | 672 |
1 files changed, 672 insertions, 0 deletions
diff --git a/gfx/webrender_bindings/RenderCompositorNative.cpp b/gfx/webrender_bindings/RenderCompositorNative.cpp new file mode 100644 index 0000000000..81cafd1fd6 --- /dev/null +++ b/gfx/webrender_bindings/RenderCompositorNative.cpp @@ -0,0 +1,672 @@ +/* -*- 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_MACOSX) || 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_MACOSX) + 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_MACOSX) + 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_MACOSX + // 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 |