1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "RenderCompositorNative.h"
8 
9 #include "GLContext.h"
10 #include "GLContextProvider.h"
11 #include "mozilla/ProfilerLabels.h"
12 #include "mozilla/ProfilerMarkers.h"
13 #include "mozilla/gfx/gfxVars.h"
14 #include "mozilla/gfx/Logging.h"
15 #include "mozilla/layers/CompositionRecorder.h"
16 #include "mozilla/layers/NativeLayer.h"
17 #include "mozilla/layers/SurfacePool.h"
18 #include "mozilla/StaticPrefs_gfx.h"
19 #include "mozilla/webrender/RenderThread.h"
20 #include "mozilla/widget/CompositorWidget.h"
21 #include "RenderCompositorRecordedFrame.h"
22 
23 namespace mozilla::wr {
24 
RenderCompositorNative(const RefPtr<widget::CompositorWidget> & aWidget,gl::GLContext * aGL)25 RenderCompositorNative::RenderCompositorNative(
26     const RefPtr<widget::CompositorWidget>& aWidget, gl::GLContext* aGL)
27     : RenderCompositor(aWidget),
28       mNativeLayerRoot(GetWidget()->GetNativeLayerRoot()) {
29 #if defined(XP_MACOSX) || defined(MOZ_WAYLAND)
30   auto pool = RenderThread::Get()->SharedSurfacePool();
31   if (pool) {
32     mSurfacePoolHandle = pool->GetHandleForGL(aGL);
33   }
34 #endif
35   MOZ_RELEASE_ASSERT(mSurfacePoolHandle);
36 }
37 
~RenderCompositorNative()38 RenderCompositorNative::~RenderCompositorNative() {
39   Pause();
40   mProfilerScreenshotGrabber.Destroy();
41   mNativeLayerRoot->SetLayers({});
42   mNativeLayerForEntireWindow = nullptr;
43   mNativeLayerRootSnapshotter = nullptr;
44   mNativeLayerRoot = nullptr;
45 }
46 
BeginFrame()47 bool RenderCompositorNative::BeginFrame() {
48   if (!MakeCurrent()) {
49     gfxCriticalNote << "Failed to make render context current, can't draw.";
50     return false;
51   }
52 
53   gfx::IntSize bufferSize = GetBufferSize().ToUnknownSize();
54   if (!ShouldUseNativeCompositor()) {
55     if (bufferSize.IsEmpty()) {
56       return false;
57     }
58     if (mNativeLayerForEntireWindow &&
59         mNativeLayerForEntireWindow->GetSize() != bufferSize) {
60       mNativeLayerRoot->RemoveLayer(mNativeLayerForEntireWindow);
61       mNativeLayerForEntireWindow = nullptr;
62     }
63     if (!mNativeLayerForEntireWindow) {
64       mNativeLayerForEntireWindow =
65           mNativeLayerRoot->CreateLayer(bufferSize, false, mSurfacePoolHandle);
66       mNativeLayerRoot->AppendLayer(mNativeLayerForEntireWindow);
67     }
68   }
69 
70   gfx::IntRect bounds({}, bufferSize);
71   if (!InitDefaultFramebuffer(bounds)) {
72     return false;
73   }
74 
75   return true;
76 }
77 
EndFrame(const nsTArray<DeviceIntRect> & aDirtyRects)78 RenderedFrameId RenderCompositorNative::EndFrame(
79     const nsTArray<DeviceIntRect>& aDirtyRects) {
80   RenderedFrameId frameId = GetNextRenderFrameId();
81 
82   DoSwap();
83 
84   if (mNativeLayerForEntireWindow) {
85     mNativeLayerForEntireWindow->NotifySurfaceReady();
86     mNativeLayerRoot->CommitToScreen();
87   }
88 
89   return frameId;
90 }
91 
Pause()92 void RenderCompositorNative::Pause() { mNativeLayerRoot->PauseCompositor(); }
93 
Resume()94 bool RenderCompositorNative::Resume() {
95   return mNativeLayerRoot->ResumeCompositor();
96 }
97 
CompositorType() const98 inline layers::WebRenderCompositor RenderCompositorNative::CompositorType()
99     const {
100   if (gfx::gfxVars::UseWebRenderCompositor()) {
101 #if defined(XP_MACOSX)
102     return layers::WebRenderCompositor::CORE_ANIMATION;
103 #elif defined(MOZ_WAYLAND)
104     return layers::WebRenderCompositor::WAYLAND;
105 #endif
106   }
107   return layers::WebRenderCompositor::DRAW;
108 }
109 
GetBufferSize()110 LayoutDeviceIntSize RenderCompositorNative::GetBufferSize() {
111   return mWidget->GetClientSize();
112 }
113 
ShouldUseNativeCompositor()114 bool RenderCompositorNative::ShouldUseNativeCompositor() {
115   return gfx::gfxVars::UseWebRenderCompositor();
116 }
117 
MaybeReadback(const gfx::IntSize & aReadbackSize,const wr::ImageFormat & aReadbackFormat,const Range<uint8_t> & aReadbackBuffer,bool * aNeedsYFlip)118 bool RenderCompositorNative::MaybeReadback(
119     const gfx::IntSize& aReadbackSize, const wr::ImageFormat& aReadbackFormat,
120     const Range<uint8_t>& aReadbackBuffer, bool* aNeedsYFlip) {
121   if (!ShouldUseNativeCompositor()) {
122     return false;
123   }
124 
125   MOZ_RELEASE_ASSERT(aReadbackFormat == wr::ImageFormat::BGRA8);
126   if (!mNativeLayerRootSnapshotter) {
127     mNativeLayerRootSnapshotter = mNativeLayerRoot->CreateSnapshotter();
128 
129     if (!mNativeLayerRootSnapshotter) {
130       return false;
131     }
132   }
133   bool success = mNativeLayerRootSnapshotter->ReadbackPixels(
134       aReadbackSize, gfx::SurfaceFormat::B8G8R8A8, aReadbackBuffer);
135 
136   // ReadbackPixels might have changed the current context. Make sure GL is
137   // current again.
138   MakeCurrent();
139 
140   if (aNeedsYFlip) {
141     *aNeedsYFlip = true;
142   }
143 
144   return success;
145 }
146 
MaybeRecordFrame(layers::CompositionRecorder & aRecorder)147 bool RenderCompositorNative::MaybeRecordFrame(
148     layers::CompositionRecorder& aRecorder) {
149   if (!ShouldUseNativeCompositor()) {
150     return false;
151   }
152 
153   if (!mNativeLayerRootSnapshotter) {
154     mNativeLayerRootSnapshotter = mNativeLayerRoot->CreateSnapshotter();
155   }
156 
157   if (!mNativeLayerRootSnapshotter) {
158     return true;
159   }
160 
161   gfx::IntSize size = GetBufferSize().ToUnknownSize();
162   RefPtr<layers::profiler_screenshots::RenderSource> snapshot =
163       mNativeLayerRootSnapshotter->GetWindowContents(size);
164   if (!snapshot) {
165     return true;
166   }
167 
168   RefPtr<layers::profiler_screenshots::AsyncReadbackBuffer> buffer =
169       mNativeLayerRootSnapshotter->CreateAsyncReadbackBuffer(size);
170   buffer->CopyFrom(snapshot);
171 
172   RefPtr<layers::RecordedFrame> frame =
173       new RenderCompositorRecordedFrame(TimeStamp::Now(), std::move(buffer));
174   aRecorder.RecordFrame(frame);
175 
176   // GetWindowContents might have changed the current context. Make sure our
177   // context is current again.
178   MakeCurrent();
179   return true;
180 }
181 
MaybeGrabScreenshot(const gfx::IntSize & aWindowSize)182 bool RenderCompositorNative::MaybeGrabScreenshot(
183     const gfx::IntSize& aWindowSize) {
184   if (!ShouldUseNativeCompositor()) {
185     return false;
186   }
187 
188   if (!mNativeLayerRootSnapshotter) {
189     mNativeLayerRootSnapshotter = mNativeLayerRoot->CreateSnapshotter();
190   }
191 
192   if (mNativeLayerRootSnapshotter) {
193     mProfilerScreenshotGrabber.MaybeGrabScreenshot(*mNativeLayerRootSnapshotter,
194                                                    aWindowSize);
195 
196     // MaybeGrabScreenshot might have changed the current context. Make sure our
197     // context is current again.
198     MakeCurrent();
199   }
200 
201   return true;
202 }
203 
MaybeProcessScreenshotQueue()204 bool RenderCompositorNative::MaybeProcessScreenshotQueue() {
205   if (!ShouldUseNativeCompositor()) {
206     return false;
207   }
208 
209   mProfilerScreenshotGrabber.MaybeProcessQueue();
210 
211   // MaybeProcessQueue might have changed the current context. Make sure our
212   // context is current again.
213   MakeCurrent();
214 
215   return true;
216 }
217 
CompositorBeginFrame()218 void RenderCompositorNative::CompositorBeginFrame() {
219   mAddedLayers.Clear();
220   mAddedTilePixelCount = 0;
221   mAddedClippedPixelCount = 0;
222   mBeginFrameTimeStamp = TimeStamp::NowUnfuzzed();
223   mSurfacePoolHandle->OnBeginFrame();
224 }
225 
CompositorEndFrame()226 void RenderCompositorNative::CompositorEndFrame() {
227   if (profiler_thread_is_being_profiled()) {
228     auto bufferSize = GetBufferSize();
229     [[maybe_unused]] uint64_t windowPixelCount =
230         uint64_t(bufferSize.width) * bufferSize.height;
231     int nativeLayerCount = 0;
232     for (const auto& it : mSurfaces) {
233       nativeLayerCount += int(it.second.mNativeLayers.size());
234     }
235     PROFILER_MARKER_TEXT(
236         "WR OS Compositor frame", GRAPHICS,
237         MarkerTiming::IntervalUntilNowFrom(mBeginFrameTimeStamp),
238         nsPrintfCString("%d%% painting, %d%% overdraw, %d used "
239                         "layers (%d%% memory) + %d unused layers (%d%% memory)",
240                         int(mDrawnPixelCount * 100 / windowPixelCount),
241                         int(mAddedClippedPixelCount * 100 / windowPixelCount),
242                         int(mAddedLayers.Length()),
243                         int(mAddedTilePixelCount * 100 / windowPixelCount),
244                         int(nativeLayerCount - mAddedLayers.Length()),
245                         int((mTotalTilePixelCount - mAddedTilePixelCount) *
246                             100 / windowPixelCount)));
247   }
248   mDrawnPixelCount = 0;
249 
250   DoFlush();
251 
252   mNativeLayerRoot->SetLayers(mAddedLayers);
253   mNativeLayerRoot->CommitToScreen();
254   mSurfacePoolHandle->OnEndFrame();
255 }
256 
BindNativeLayer(wr::NativeTileId aId,const gfx::IntRect & aDirtyRect)257 void RenderCompositorNative::BindNativeLayer(wr::NativeTileId aId,
258                                              const gfx::IntRect& aDirtyRect) {
259   MOZ_RELEASE_ASSERT(!mCurrentlyBoundNativeLayer);
260 
261   auto surfaceCursor = mSurfaces.find(aId.surface_id);
262   MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
263   Surface& surface = surfaceCursor->second;
264 
265   auto layerCursor = surface.mNativeLayers.find(TileKey(aId.x, aId.y));
266   MOZ_RELEASE_ASSERT(layerCursor != surface.mNativeLayers.end());
267   RefPtr<layers::NativeLayer> layer = layerCursor->second;
268 
269   mCurrentlyBoundNativeLayer = layer;
270 
271   mDrawnPixelCount += aDirtyRect.Area();
272 }
273 
UnbindNativeLayer()274 void RenderCompositorNative::UnbindNativeLayer() {
275   MOZ_RELEASE_ASSERT(mCurrentlyBoundNativeLayer);
276 
277   mCurrentlyBoundNativeLayer->NotifySurfaceReady();
278   mCurrentlyBoundNativeLayer = nullptr;
279 }
280 
CreateSurface(wr::NativeSurfaceId aId,wr::DeviceIntPoint aVirtualOffset,wr::DeviceIntSize aTileSize,bool aIsOpaque)281 void RenderCompositorNative::CreateSurface(wr::NativeSurfaceId aId,
282                                            wr::DeviceIntPoint aVirtualOffset,
283                                            wr::DeviceIntSize aTileSize,
284                                            bool aIsOpaque) {
285   MOZ_RELEASE_ASSERT(mSurfaces.find(aId) == mSurfaces.end());
286   mSurfaces.insert({aId, Surface{aTileSize, aIsOpaque}});
287 }
288 
CreateExternalSurface(wr::NativeSurfaceId aId,bool aIsOpaque)289 void RenderCompositorNative::CreateExternalSurface(wr::NativeSurfaceId aId,
290                                                    bool aIsOpaque) {
291   MOZ_RELEASE_ASSERT(mSurfaces.find(aId) == mSurfaces.end());
292 
293   RefPtr<layers::NativeLayer> layer =
294       mNativeLayerRoot->CreateLayerForExternalTexture(aIsOpaque);
295 
296   Surface surface{DeviceIntSize{}, aIsOpaque};
297   surface.mIsExternal = true;
298   surface.mNativeLayers.insert({TileKey(0, 0), layer});
299 
300   mSurfaces.insert({aId, std::move(surface)});
301 }
302 
AttachExternalImage(wr::NativeSurfaceId aId,wr::ExternalImageId aExternalImage)303 void RenderCompositorNative::AttachExternalImage(
304     wr::NativeSurfaceId aId, wr::ExternalImageId aExternalImage) {
305   RenderTextureHost* image =
306       RenderThread::Get()->GetRenderTexture(aExternalImage);
307   MOZ_RELEASE_ASSERT(image);
308 
309   auto surfaceCursor = mSurfaces.find(aId);
310   MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
311 
312   Surface& surface = surfaceCursor->second;
313   MOZ_RELEASE_ASSERT(surface.mNativeLayers.size() == 1);
314   MOZ_RELEASE_ASSERT(surface.mIsExternal);
315   surface.mNativeLayers.begin()->second->AttachExternalImage(image);
316 }
317 
DestroySurface(NativeSurfaceId aId)318 void RenderCompositorNative::DestroySurface(NativeSurfaceId aId) {
319   auto surfaceCursor = mSurfaces.find(aId);
320   MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
321 
322   Surface& surface = surfaceCursor->second;
323   if (!surface.mIsExternal) {
324     for (const auto& iter : surface.mNativeLayers) {
325       mTotalTilePixelCount -= gfx::IntRect({}, iter.second->GetSize()).Area();
326     }
327   }
328 
329   mSurfaces.erase(surfaceCursor);
330 }
331 
CreateTile(wr::NativeSurfaceId aId,int aX,int aY)332 void RenderCompositorNative::CreateTile(wr::NativeSurfaceId aId, int aX,
333                                         int aY) {
334   auto surfaceCursor = mSurfaces.find(aId);
335   MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
336   Surface& surface = surfaceCursor->second;
337   MOZ_RELEASE_ASSERT(!surface.mIsExternal);
338 
339   RefPtr<layers::NativeLayer> layer = mNativeLayerRoot->CreateLayer(
340       surface.TileSize(), surface.mIsOpaque, mSurfacePoolHandle);
341   surface.mNativeLayers.insert({TileKey(aX, aY), layer});
342   mTotalTilePixelCount += gfx::IntRect({}, layer->GetSize()).Area();
343 }
344 
DestroyTile(wr::NativeSurfaceId aId,int aX,int aY)345 void RenderCompositorNative::DestroyTile(wr::NativeSurfaceId aId, int aX,
346                                          int aY) {
347   auto surfaceCursor = mSurfaces.find(aId);
348   MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
349   Surface& surface = surfaceCursor->second;
350   MOZ_RELEASE_ASSERT(!surface.mIsExternal);
351 
352   auto layerCursor = surface.mNativeLayers.find(TileKey(aX, aY));
353   MOZ_RELEASE_ASSERT(layerCursor != surface.mNativeLayers.end());
354   RefPtr<layers::NativeLayer> layer = std::move(layerCursor->second);
355   surface.mNativeLayers.erase(layerCursor);
356   mTotalTilePixelCount -= gfx::IntRect({}, layer->GetSize()).Area();
357 
358   // If the layer is currently present in mNativeLayerRoot, it will be destroyed
359   // once CompositorEndFrame() replaces mNativeLayerRoot's layers and drops that
360   // reference. So until that happens, the layer still needs to hold on to its
361   // front buffer. However, we can tell it to drop its back buffers now, because
362   // we know that we will never draw to it again.
363   // Dropping the back buffers now puts them back in the surface pool, so those
364   // surfaces can be immediately re-used for drawing in other layers in the
365   // current frame.
366   layer->DiscardBackbuffers();
367 }
368 
ToSamplingFilter(wr::ImageRendering aImageRendering)369 gfx::SamplingFilter ToSamplingFilter(wr::ImageRendering aImageRendering) {
370   if (aImageRendering == wr::ImageRendering::Auto) {
371     return gfx::SamplingFilter::LINEAR;
372   }
373   return gfx::SamplingFilter::POINT;
374 }
375 
AddSurface(wr::NativeSurfaceId aId,const wr::CompositorSurfaceTransform & aTransform,wr::DeviceIntRect aClipRect,wr::ImageRendering aImageRendering)376 void RenderCompositorNative::AddSurface(
377     wr::NativeSurfaceId aId, const wr::CompositorSurfaceTransform& aTransform,
378     wr::DeviceIntRect aClipRect, wr::ImageRendering aImageRendering) {
379   MOZ_RELEASE_ASSERT(!mCurrentlyBoundNativeLayer);
380 
381   auto surfaceCursor = mSurfaces.find(aId);
382   MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
383   const Surface& surface = surfaceCursor->second;
384 
385   gfx::Matrix4x4 transform(
386       aTransform.m11, aTransform.m12, aTransform.m13, aTransform.m14,
387       aTransform.m21, aTransform.m22, aTransform.m23, aTransform.m24,
388       aTransform.m31, aTransform.m32, aTransform.m33, aTransform.m34,
389       aTransform.m41, aTransform.m42, aTransform.m43, aTransform.m44);
390 
391   for (auto it = surface.mNativeLayers.begin();
392        it != surface.mNativeLayers.end(); ++it) {
393     RefPtr<layers::NativeLayer> layer = it->second;
394     gfx::IntSize layerSize = layer->GetSize();
395     gfx::IntPoint layerPosition(surface.mTileSize.width * it->first.mX,
396                                 surface.mTileSize.height * it->first.mY);
397     layer->SetPosition(layerPosition);
398     gfx::IntRect clipRect(aClipRect.min.x, aClipRect.min.y, aClipRect.width(),
399                           aClipRect.height());
400     layer->SetClipRect(Some(clipRect));
401     layer->SetTransform(transform);
402     layer->SetSamplingFilter(ToSamplingFilter(aImageRendering));
403     mAddedLayers.AppendElement(layer);
404 
405     if (!surface.mIsExternal) {
406       mAddedTilePixelCount += layerSize.width * layerSize.height;
407     }
408     gfx::Rect r = transform.TransformBounds(
409         gfx::Rect(layer->CurrentSurfaceDisplayRect()));
410     gfx::IntRect visibleRect =
411         clipRect.Intersect(RoundedToInt(r) + layerPosition);
412     mAddedClippedPixelCount += visibleRect.Area();
413   }
414 }
415 
416 /* static */
Create(const RefPtr<widget::CompositorWidget> & aWidget,nsACString & aError)417 UniquePtr<RenderCompositor> RenderCompositorNativeOGL::Create(
418     const RefPtr<widget::CompositorWidget>& aWidget, nsACString& aError) {
419   RefPtr<gl::GLContext> gl = RenderThread::Get()->SingletonGL();
420   if (!gl) {
421     gl = gl::GLContextProvider::CreateForCompositorWidget(
422         aWidget, /* aHardwareWebRender */ true, /* aForceAccelerated */ true);
423     RenderThread::MaybeEnableGLDebugMessage(gl);
424   }
425   if (!gl || !gl->MakeCurrent()) {
426     gfxCriticalNote << "Failed GL context creation for WebRender: "
427                     << gfx::hexa(gl.get());
428     return nullptr;
429   }
430   return MakeUnique<RenderCompositorNativeOGL>(aWidget, std::move(gl));
431 }
432 
RenderCompositorNativeOGL(const RefPtr<widget::CompositorWidget> & aWidget,RefPtr<gl::GLContext> && aGL)433 RenderCompositorNativeOGL::RenderCompositorNativeOGL(
434     const RefPtr<widget::CompositorWidget>& aWidget,
435     RefPtr<gl::GLContext>&& aGL)
436     : RenderCompositorNative(aWidget, aGL), mGL(aGL) {
437   MOZ_ASSERT(mGL);
438 }
439 
~RenderCompositorNativeOGL()440 RenderCompositorNativeOGL::~RenderCompositorNativeOGL() {
441   if (!mGL->MakeCurrent()) {
442     gfxCriticalNote
443         << "Failed to make render context current during destroying.";
444     // Leak resources!
445     mPreviousFrameDoneSync = nullptr;
446     mThisFrameDoneSync = nullptr;
447     return;
448   }
449 
450   if (mPreviousFrameDoneSync) {
451     mGL->fDeleteSync(mPreviousFrameDoneSync);
452   }
453   if (mThisFrameDoneSync) {
454     mGL->fDeleteSync(mThisFrameDoneSync);
455   }
456 }
457 
InitDefaultFramebuffer(const gfx::IntRect & aBounds)458 bool RenderCompositorNativeOGL::InitDefaultFramebuffer(
459     const gfx::IntRect& aBounds) {
460   if (mNativeLayerForEntireWindow) {
461     Maybe<GLuint> fbo = mNativeLayerForEntireWindow->NextSurfaceAsFramebuffer(
462         aBounds, aBounds, true);
463     if (!fbo) {
464       return false;
465     }
466     mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, *fbo);
467   } else {
468     mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mGL->GetDefaultFramebuffer());
469   }
470   return true;
471 }
472 
DoSwap()473 void RenderCompositorNativeOGL::DoSwap() {
474   InsertFrameDoneSync();
475   if (mNativeLayerForEntireWindow) {
476     mGL->fFlush();
477   }
478 }
479 
DoFlush()480 void RenderCompositorNativeOGL::DoFlush() { mGL->fFlush(); }
481 
InsertFrameDoneSync()482 void RenderCompositorNativeOGL::InsertFrameDoneSync() {
483 #ifdef XP_MACOSX
484   // Only do this on macOS.
485   // On other platforms, SwapBuffers automatically applies back-pressure.
486   if (mThisFrameDoneSync) {
487     mGL->fDeleteSync(mThisFrameDoneSync);
488   }
489   mThisFrameDoneSync = mGL->fFenceSync(LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
490 #endif
491 }
492 
WaitForGPU()493 bool RenderCompositorNativeOGL::WaitForGPU() {
494   if (mPreviousFrameDoneSync) {
495     AUTO_PROFILER_LABEL("Waiting for GPU to finish previous frame", GRAPHICS);
496     mGL->fClientWaitSync(mPreviousFrameDoneSync,
497                          LOCAL_GL_SYNC_FLUSH_COMMANDS_BIT,
498                          LOCAL_GL_TIMEOUT_IGNORED);
499     mGL->fDeleteSync(mPreviousFrameDoneSync);
500   }
501   mPreviousFrameDoneSync = mThisFrameDoneSync;
502   mThisFrameDoneSync = nullptr;
503 
504   return true;
505 }
506 
Bind(wr::NativeTileId aId,wr::DeviceIntPoint * aOffset,uint32_t * aFboId,wr::DeviceIntRect aDirtyRect,wr::DeviceIntRect aValidRect)507 void RenderCompositorNativeOGL::Bind(wr::NativeTileId aId,
508                                      wr::DeviceIntPoint* aOffset,
509                                      uint32_t* aFboId,
510                                      wr::DeviceIntRect aDirtyRect,
511                                      wr::DeviceIntRect aValidRect) {
512   gfx::IntRect validRect(aValidRect.min.x, aValidRect.min.y, aValidRect.width(),
513                          aValidRect.height());
514   gfx::IntRect dirtyRect(aDirtyRect.min.x, aDirtyRect.min.y, aDirtyRect.width(),
515                          aDirtyRect.height());
516 
517   BindNativeLayer(aId, dirtyRect);
518 
519   Maybe<GLuint> fbo = mCurrentlyBoundNativeLayer->NextSurfaceAsFramebuffer(
520       validRect, dirtyRect, true);
521 
522   *aFboId = *fbo;
523   *aOffset = wr::DeviceIntPoint{0, 0};
524 }
525 
Unbind()526 void RenderCompositorNativeOGL::Unbind() {
527   mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
528 
529   UnbindNativeLayer();
530 }
531 
532 /* static */
Create(const RefPtr<widget::CompositorWidget> & aWidget,nsACString & aError)533 UniquePtr<RenderCompositor> RenderCompositorNativeSWGL::Create(
534     const RefPtr<widget::CompositorWidget>& aWidget, nsACString& aError) {
535   void* ctx = wr_swgl_create_context();
536   if (!ctx) {
537     gfxCriticalNote << "Failed SWGL context creation for WebRender";
538     return nullptr;
539   }
540   return MakeUnique<RenderCompositorNativeSWGL>(aWidget, ctx);
541 }
542 
RenderCompositorNativeSWGL(const RefPtr<widget::CompositorWidget> & aWidget,void * aContext)543 RenderCompositorNativeSWGL::RenderCompositorNativeSWGL(
544     const RefPtr<widget::CompositorWidget>& aWidget, void* aContext)
545     : RenderCompositorNative(aWidget), mContext(aContext) {
546   MOZ_ASSERT(mContext);
547 }
548 
~RenderCompositorNativeSWGL()549 RenderCompositorNativeSWGL::~RenderCompositorNativeSWGL() {
550   wr_swgl_destroy_context(mContext);
551 }
552 
MakeCurrent()553 bool RenderCompositorNativeSWGL::MakeCurrent() {
554   wr_swgl_make_current(mContext);
555   return true;
556 }
557 
InitDefaultFramebuffer(const gfx::IntRect & aBounds)558 bool RenderCompositorNativeSWGL::InitDefaultFramebuffer(
559     const gfx::IntRect& aBounds) {
560   if (mNativeLayerForEntireWindow) {
561     if (!MapNativeLayer(mNativeLayerForEntireWindow, aBounds, aBounds)) {
562       return false;
563     }
564     wr_swgl_init_default_framebuffer(mContext, aBounds.x, aBounds.y,
565                                      aBounds.width, aBounds.height,
566                                      mLayerStride, mLayerValidRectData);
567   }
568   return true;
569 }
570 
CancelFrame()571 void RenderCompositorNativeSWGL::CancelFrame() {
572   if (mNativeLayerForEntireWindow && mLayerTarget) {
573     wr_swgl_init_default_framebuffer(mContext, 0, 0, 0, 0, 0, nullptr);
574     UnmapNativeLayer();
575   }
576 }
577 
DoSwap()578 void RenderCompositorNativeSWGL::DoSwap() {
579   if (mNativeLayerForEntireWindow && mLayerTarget) {
580     wr_swgl_init_default_framebuffer(mContext, 0, 0, 0, 0, 0, nullptr);
581     UnmapNativeLayer();
582   }
583 }
584 
MapNativeLayer(layers::NativeLayer * aLayer,const gfx::IntRect & aDirtyRect,const gfx::IntRect & aValidRect)585 bool RenderCompositorNativeSWGL::MapNativeLayer(
586     layers::NativeLayer* aLayer, const gfx::IntRect& aDirtyRect,
587     const gfx::IntRect& aValidRect) {
588   uint8_t* data = nullptr;
589   gfx::IntSize size;
590   int32_t stride = 0;
591   gfx::SurfaceFormat format = gfx::SurfaceFormat::UNKNOWN;
592   RefPtr<gfx::DrawTarget> dt = aLayer->NextSurfaceAsDrawTarget(
593       aValidRect, gfx::IntRegion(aDirtyRect), gfx::BackendType::SKIA);
594   if (!dt || !dt->LockBits(&data, &size, &stride, &format)) {
595     return false;
596   }
597   MOZ_ASSERT(format == gfx::SurfaceFormat::B8G8R8A8 ||
598              format == gfx::SurfaceFormat::B8G8R8X8);
599   mLayerTarget = std::move(dt);
600   mLayerData = data;
601   mLayerValidRectData = data + aValidRect.y * stride + aValidRect.x * 4;
602   mLayerStride = stride;
603   return true;
604 }
605 
UnmapNativeLayer()606 void RenderCompositorNativeSWGL::UnmapNativeLayer() {
607   MOZ_ASSERT(mLayerTarget && mLayerData);
608   mLayerTarget->ReleaseBits(mLayerData);
609   mLayerTarget = nullptr;
610   mLayerData = nullptr;
611   mLayerValidRectData = nullptr;
612   mLayerStride = 0;
613 }
614 
MapTile(wr::NativeTileId aId,wr::DeviceIntRect aDirtyRect,wr::DeviceIntRect aValidRect,void ** aData,int32_t * aStride)615 bool RenderCompositorNativeSWGL::MapTile(wr::NativeTileId aId,
616                                          wr::DeviceIntRect aDirtyRect,
617                                          wr::DeviceIntRect aValidRect,
618                                          void** aData, int32_t* aStride) {
619   if (mNativeLayerForEntireWindow) {
620     return false;
621   }
622   gfx::IntRect dirtyRect(aDirtyRect.min.x, aDirtyRect.min.y, aDirtyRect.width(),
623                          aDirtyRect.height());
624   gfx::IntRect validRect(aValidRect.min.x, aValidRect.min.y, aValidRect.width(),
625                          aValidRect.height());
626   BindNativeLayer(aId, dirtyRect);
627   if (!MapNativeLayer(mCurrentlyBoundNativeLayer, dirtyRect, validRect)) {
628     UnbindNativeLayer();
629     return false;
630   }
631   *aData = mLayerValidRectData;
632   *aStride = mLayerStride;
633   return true;
634 }
635 
UnmapTile()636 void RenderCompositorNativeSWGL::UnmapTile() {
637   if (!mNativeLayerForEntireWindow && mCurrentlyBoundNativeLayer) {
638     UnmapNativeLayer();
639     UnbindNativeLayer();
640   }
641 }
642 
643 }  // namespace mozilla::wr
644