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