diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /gfx/webrender_bindings/RenderCompositorLayersSWGL.cpp | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/webrender_bindings/RenderCompositorLayersSWGL.cpp')
-rw-r--r-- | gfx/webrender_bindings/RenderCompositorLayersSWGL.cpp | 482 |
1 files changed, 482 insertions, 0 deletions
diff --git a/gfx/webrender_bindings/RenderCompositorLayersSWGL.cpp b/gfx/webrender_bindings/RenderCompositorLayersSWGL.cpp new file mode 100644 index 0000000000..1e4550e9e8 --- /dev/null +++ b/gfx/webrender_bindings/RenderCompositorLayersSWGL.cpp @@ -0,0 +1,482 @@ +/* -*- 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 "RenderCompositorLayersSWGL.h" + +#include "GLContext.h" +#include "GLContextEGL.h" +#include "mozilla/layers/BuildConstants.h" +#include "mozilla/layers/Effects.h" +#include "mozilla/layers/TextureHostOGL.h" +#include "mozilla/widget/CompositorWidget.h" +#include "RenderCompositorRecordedFrame.h" + +#if defined(XP_WIN) +# include "mozilla/webrender/RenderCompositorD3D11SWGL.h" +#else +# include "mozilla/webrender/RenderCompositorOGLSWGL.h" +#endif + +namespace mozilla { +using namespace layers; +using namespace gfx; + +namespace wr { + +UniquePtr<RenderCompositor> RenderCompositorLayersSWGL::Create( + const RefPtr<widget::CompositorWidget>& aWidget, nsACString& aError) { +#ifdef XP_WIN + return RenderCompositorD3D11SWGL::Create(aWidget, aError); +#else + return RenderCompositorOGLSWGL::Create(aWidget, aError); +#endif +} + +RenderCompositorLayersSWGL::RenderCompositorLayersSWGL( + Compositor* aCompositor, const RefPtr<widget::CompositorWidget>& aWidget, + void* aContext) + : RenderCompositor(aWidget), + mCompositor(aCompositor), + mContext(aContext), + mCurrentTileId(wr::NativeTileId()) { + MOZ_ASSERT(mCompositor); + MOZ_ASSERT(mContext); +} + +RenderCompositorLayersSWGL::~RenderCompositorLayersSWGL() { + wr_swgl_destroy_context(mContext); +} + +bool RenderCompositorLayersSWGL::MakeCurrent() { + wr_swgl_make_current(mContext); + return true; +} + +bool RenderCompositorLayersSWGL::BeginFrame() { + MOZ_ASSERT(!mInFrame); + MakeCurrent(); + mInFrame = true; + return true; +} + +void RenderCompositorLayersSWGL::CancelFrame() { + MOZ_ASSERT(mInFrame); + mInFrame = false; + if (mCompositingStarted) { + mCompositor->CancelFrame(); + mCompositingStarted = false; + } +} + +void RenderCompositorLayersSWGL::StartCompositing( + wr::ColorF aClearColor, const wr::DeviceIntRect* aDirtyRects, + size_t aNumDirtyRects, const wr::DeviceIntRect* aOpaqueRects, + size_t aNumOpaqueRects) { + MOZ_RELEASE_ASSERT(!mCompositingStarted); + + if (!mInFrame || aNumDirtyRects == 0) { + return; + } + + gfx::IntRect bounds(gfx::IntPoint(0, 0), GetBufferSize().ToUnknownSize()); + nsIntRegion dirty; + + MOZ_RELEASE_ASSERT(aNumDirtyRects > 0); + for (size_t i = 0; i < aNumDirtyRects; i++) { + const auto& rect = aDirtyRects[i]; + dirty.OrWith( + gfx::IntRect(rect.min.x, rect.min.y, rect.width(), rect.height())); + } + dirty.AndWith(bounds); + + nsIntRegion opaque(bounds); + opaque.SubOut(mWidget->GetTransparentRegion().ToUnknownRegion()); + for (size_t i = 0; i < aNumOpaqueRects; i++) { + const auto& rect = aOpaqueRects[i]; + opaque.OrWith( + gfx::IntRect(rect.min.x, rect.min.y, rect.width(), rect.height())); + } + + mCompositor->SetClearColor(gfx::DeviceColor(aClearColor.r, aClearColor.g, + aClearColor.b, aClearColor.a)); + + if (!mCompositor->BeginFrameForWindow(dirty, Nothing(), bounds, opaque)) { + return; + } + mCompositingStarted = true; +} + +void RenderCompositorLayersSWGL::CompositorEndFrame() { + nsTArray<FrameSurface> frameSurfaces = std::move(mFrameSurfaces); + + if (!mCompositingStarted) { + return; + } + + for (auto& frameSurface : frameSurfaces) { + auto surfaceCursor = mSurfaces.find(frameSurface.mId); + MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end()); + Surface* surface = surfaceCursor->second.get(); + + for (auto it = surface->mTiles.begin(); it != surface->mTiles.end(); ++it) { + if (!it->second->IsValid()) { + continue; + } + + gfx::Point tileOffset(it->first.mX * surface->mTileSize.width, + it->first.mY * surface->mTileSize.height); + gfx::Rect drawRect = it->second->mValidRect + tileOffset; + + RefPtr<TexturedEffect> texturedEffect = + new EffectRGB(it->second->GetTextureSource(), + /* aPremultiplied */ true, frameSurface.mFilter); + if (surface->mIsOpaque) { + texturedEffect->mPremultipliedCopy = true; + } + + texturedEffect->mTextureCoords = + gfx::Rect(it->second->mValidRect.x / surface->mTileSize.width, + it->second->mValidRect.y / surface->mTileSize.height, + it->second->mValidRect.width / surface->mTileSize.width, + it->second->mValidRect.height / surface->mTileSize.height); + + EffectChain effect; + effect.mPrimaryEffect = texturedEffect; + mCompositor->DrawQuad(drawRect, frameSurface.mClipRect, effect, 1.0, + frameSurface.mTransform, drawRect); + } + + if (surface->mExternalImage) { + HandleExternalImage(surface->mExternalImage, frameSurface); + } + } +} + +RenderedFrameId RenderCompositorLayersSWGL::EndFrame( + const nsTArray<DeviceIntRect>& aDirtyRects) { + MOZ_ASSERT(mInFrame); + mInFrame = false; + if (mCompositingStarted) { + mCompositor->EndFrame(); + mCompositingStarted = false; + } + return GetNextRenderFrameId(); +} + +LayoutDeviceIntSize RenderCompositorLayersSWGL::GetBufferSize() { + return mWidget->GetClientSize(); +} + +void RenderCompositorLayersSWGL::Bind(wr::NativeTileId aId, + wr::DeviceIntPoint* aOffset, + uint32_t* aFboId, + wr::DeviceIntRect aDirtyRect, + wr::DeviceIntRect aValidRect) { + MOZ_RELEASE_ASSERT(false); +} + +void RenderCompositorLayersSWGL::Unbind() { MOZ_RELEASE_ASSERT(false); } + +bool RenderCompositorLayersSWGL::MapTile(wr::NativeTileId aId, + wr::DeviceIntRect aDirtyRect, + wr::DeviceIntRect aValidRect, + void** aData, int32_t* aStride) { + auto surfaceCursor = mSurfaces.find(aId.surface_id); + MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end()); + Surface* surface = surfaceCursor->second.get(); + + auto layerCursor = surface->mTiles.find(TileKey(aId.x, aId.y)); + MOZ_RELEASE_ASSERT(layerCursor != surface->mTiles.end()); + + mCurrentTile = layerCursor->second.get(); + mCurrentTileId = aId; + mCurrentTileDirty = gfx::IntRect(aDirtyRect.min.x, aDirtyRect.min.y, + aDirtyRect.width(), aDirtyRect.height()); + + if (!mCurrentTile->Map(aDirtyRect, aValidRect, aData, aStride)) { + gfxCriticalNote << "MapTile failed aValidRect: " + << gfx::Rect(aValidRect.min.x, aValidRect.min.y, + aValidRect.width(), aValidRect.height()); + return false; + } + + // Store the new valid rect, so that we can composite only those pixels + mCurrentTile->mValidRect = gfx::Rect(aValidRect.min.x, aValidRect.min.y, + aValidRect.width(), aValidRect.height()); + return true; +} + +void RenderCompositorLayersSWGL::UnmapTile() { + mCurrentTile->Unmap(mCurrentTileDirty); + mCurrentTile = nullptr; +} + +void RenderCompositorLayersSWGL::CreateSurface( + wr::NativeSurfaceId aId, wr::DeviceIntPoint aVirtualOffset, + wr::DeviceIntSize aTileSize, bool aIsOpaque) { + MOZ_RELEASE_ASSERT(mSurfaces.find(aId) == mSurfaces.end()); + auto surface = DoCreateSurface(aTileSize, aIsOpaque); + mSurfaces.insert({aId, std::move(surface)}); +} + +UniquePtr<RenderCompositorLayersSWGL::Surface> +RenderCompositorLayersSWGL::DoCreateSurface(wr::DeviceIntSize aTileSize, + bool aIsOpaque) { + return MakeUnique<Surface>(aTileSize, aIsOpaque); +} + +void RenderCompositorLayersSWGL::CreateExternalSurface(wr::NativeSurfaceId aId, + bool aIsOpaque) { + MOZ_RELEASE_ASSERT(mSurfaces.find(aId) == mSurfaces.end()); + auto surface = MakeUnique<Surface>(wr::DeviceIntSize{}, aIsOpaque); + surface->mIsExternal = true; + mSurfaces.insert({aId, std::move(surface)}); +} + +void RenderCompositorLayersSWGL::DestroySurface(NativeSurfaceId aId) { + auto surfaceCursor = mSurfaces.find(aId); + MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end()); + mSurfaces.erase(surfaceCursor); +} + +void RenderCompositorLayersSWGL::CreateTile(wr::NativeSurfaceId aId, int32_t aX, + int32_t aY) { + auto surfaceCursor = mSurfaces.find(aId); + MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end()); + Surface* surface = surfaceCursor->second.get(); + MOZ_RELEASE_ASSERT(!surface->mIsExternal); + + auto tile = DoCreateTile(surface); + surface->mTiles.insert({TileKey(aX, aY), std::move(tile)}); +} + +void RenderCompositorLayersSWGL::DestroyTile(wr::NativeSurfaceId aId, + int32_t aX, int32_t aY) { + auto surfaceCursor = mSurfaces.find(aId); + MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end()); + Surface* surface = surfaceCursor->second.get(); + MOZ_RELEASE_ASSERT(!surface->mIsExternal); + + auto layerCursor = surface->mTiles.find(TileKey(aX, aY)); + MOZ_RELEASE_ASSERT(layerCursor != surface->mTiles.end()); + surface->mTiles.erase(layerCursor); +} + +void RenderCompositorLayersSWGL::AttachExternalImage( + wr::NativeSurfaceId aId, wr::ExternalImageId aExternalImage) { + RenderTextureHost* image = + RenderThread::Get()->GetRenderTexture(aExternalImage); + MOZ_ASSERT(image); + if (!image) { + gfxCriticalNoteOnce + << "Failed to get RenderTextureHost for D3D11SWGL extId:" + << AsUint64(aExternalImage); + return; + } +#if defined(XP_WIN) + MOZ_RELEASE_ASSERT(image->AsRenderDXGITextureHost() || + image->AsRenderDXGIYCbCrTextureHost()); +#elif defined(ANDROID) + MOZ_RELEASE_ASSERT(image->AsRenderAndroidHardwareBufferTextureHost() || + image->AsRenderAndroidSurfaceTextureHost() || + image->IsWrappingAsyncRemoteTexture()); +#endif + + auto surfaceCursor = mSurfaces.find(aId); + MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end()); + + Surface* surface = surfaceCursor->second.get(); + surface->mExternalImage = image; + MOZ_RELEASE_ASSERT(surface->mTiles.empty()); + MOZ_RELEASE_ASSERT(surface->mIsExternal); +} + +// static +gfx::SamplingFilter RenderCompositorLayersSWGL::ToSamplingFilter( + wr::ImageRendering aImageRendering) { + if (aImageRendering == wr::ImageRendering::Auto) { + return gfx::SamplingFilter::LINEAR; + } + return gfx::SamplingFilter::POINT; +} + +void RenderCompositorLayersSWGL::AddSurface( + wr::NativeSurfaceId aId, const wr::CompositorSurfaceTransform& aTransform, + wr::DeviceIntRect aClipRect, wr::ImageRendering aImageRendering) { + 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); + gfx::IntRect clipRect(aClipRect.min.x, aClipRect.min.y, aClipRect.width(), + aClipRect.height()); + + mFrameSurfaces.AppendElement(FrameSurface{aId, transform, clipRect, + ToSamplingFilter(aImageRendering)}); +} + +void RenderCompositorLayersSWGL::MaybeRequestAllowFrameRecording( + bool aWillRecord) { + mCompositor->RequestAllowFrameRecording(aWillRecord); +} + +class WindowLMC : public profiler_screenshots::Window { + public: + explicit WindowLMC(Compositor* aCompositor) : mCompositor(aCompositor) {} + + already_AddRefed<profiler_screenshots::RenderSource> GetWindowContents( + const gfx::IntSize& aWindowSize) override; + already_AddRefed<profiler_screenshots::DownscaleTarget> CreateDownscaleTarget( + const gfx::IntSize& aSize) override; + already_AddRefed<profiler_screenshots::AsyncReadbackBuffer> + CreateAsyncReadbackBuffer(const gfx::IntSize& aSize) override; + + protected: + Compositor* mCompositor; +}; + +class RenderSourceLMC : public profiler_screenshots::RenderSource { + public: + explicit RenderSourceLMC(CompositingRenderTarget* aRT) + : RenderSource(aRT->GetSize()), mRT(aRT) {} + + const auto& RenderTarget() { return mRT; } + + protected: + virtual ~RenderSourceLMC() {} + + RefPtr<CompositingRenderTarget> mRT; +}; + +class DownscaleTargetLMC : public profiler_screenshots::DownscaleTarget { + public: + explicit DownscaleTargetLMC(CompositingRenderTarget* aRT, + Compositor* aCompositor) + : profiler_screenshots::DownscaleTarget(aRT->GetSize()), + mRenderSource(new RenderSourceLMC(aRT)), + mCompositor(aCompositor) {} + + already_AddRefed<profiler_screenshots::RenderSource> AsRenderSource() + override { + return do_AddRef(mRenderSource); + } + + bool DownscaleFrom(profiler_screenshots::RenderSource* aSource, + const IntRect& aSourceRect, + const IntRect& aDestRect) override { + MOZ_RELEASE_ASSERT(aSourceRect.TopLeft() == IntPoint()); + MOZ_RELEASE_ASSERT(aDestRect.TopLeft() == IntPoint()); + RefPtr<CompositingRenderTarget> previousTarget = + mCompositor->GetCurrentRenderTarget(); + + mCompositor->SetRenderTarget(mRenderSource->RenderTarget()); + bool result = mCompositor->BlitRenderTarget( + static_cast<RenderSourceLMC*>(aSource)->RenderTarget(), + aSourceRect.Size(), aDestRect.Size()); + + // Restore the old render target. + mCompositor->SetRenderTarget(previousTarget); + + return result; + } + + protected: + virtual ~DownscaleTargetLMC() {} + + RefPtr<RenderSourceLMC> mRenderSource; + Compositor* mCompositor; +}; + +class AsyncReadbackBufferLMC + : public profiler_screenshots::AsyncReadbackBuffer { + public: + AsyncReadbackBufferLMC(mozilla::layers::AsyncReadbackBuffer* aARB, + Compositor* aCompositor) + : profiler_screenshots::AsyncReadbackBuffer(aARB->GetSize()), + mARB(aARB), + mCompositor(aCompositor) {} + void CopyFrom(profiler_screenshots::RenderSource* aSource) override { + mCompositor->ReadbackRenderTarget( + static_cast<RenderSourceLMC*>(aSource)->RenderTarget(), mARB); + } + bool MapAndCopyInto(DataSourceSurface* aSurface, + const IntSize& aReadSize) override { + return mARB->MapAndCopyInto(aSurface, aReadSize); + } + + protected: + virtual ~AsyncReadbackBufferLMC() {} + + RefPtr<mozilla::layers::AsyncReadbackBuffer> mARB; + Compositor* mCompositor; +}; + +already_AddRefed<profiler_screenshots::RenderSource> +WindowLMC::GetWindowContents(const gfx::IntSize& aWindowSize) { + RefPtr<CompositingRenderTarget> rt = mCompositor->GetWindowRenderTarget(); + if (!rt) { + return nullptr; + } + return MakeAndAddRef<RenderSourceLMC>(rt); +} + +already_AddRefed<profiler_screenshots::DownscaleTarget> +WindowLMC::CreateDownscaleTarget(const gfx::IntSize& aSize) { + RefPtr<CompositingRenderTarget> rt = + mCompositor->CreateRenderTarget(IntRect({}, aSize), INIT_MODE_NONE); + return MakeAndAddRef<DownscaleTargetLMC>(rt, mCompositor); +} + +already_AddRefed<profiler_screenshots::AsyncReadbackBuffer> +WindowLMC::CreateAsyncReadbackBuffer(const gfx::IntSize& aSize) { + RefPtr<AsyncReadbackBuffer> carb = + mCompositor->CreateAsyncReadbackBuffer(aSize); + if (!carb) { + return nullptr; + } + return MakeAndAddRef<AsyncReadbackBufferLMC>(carb, mCompositor); +} + +bool RenderCompositorLayersSWGL::MaybeRecordFrame( + layers::CompositionRecorder& aRecorder) { + WindowLMC window(mCompositor); + gfx::IntSize size = GetBufferSize().ToUnknownSize(); + RefPtr<layers::profiler_screenshots::RenderSource> snapshot = + window.GetWindowContents(size); + if (!snapshot) { + return true; + } + + RefPtr<layers::profiler_screenshots::AsyncReadbackBuffer> buffer = + window.CreateAsyncReadbackBuffer(size); + buffer->CopyFrom(snapshot); + + RefPtr<layers::RecordedFrame> frame = + new RenderCompositorRecordedFrame(TimeStamp::Now(), std::move(buffer)); + aRecorder.RecordFrame(frame); + return false; +} + +bool RenderCompositorLayersSWGL::MaybeGrabScreenshot( + const gfx::IntSize& aWindowSize) { + if (!mCompositingStarted) { + return true; + } + WindowLMC window(mCompositor); + mProfilerScreenshotGrabber.MaybeGrabScreenshot(window, aWindowSize); + return true; +} + +bool RenderCompositorLayersSWGL::MaybeProcessScreenshotQueue() { + mProfilerScreenshotGrabber.MaybeProcessQueue(); + return true; +} + +} // namespace wr +} // namespace mozilla |