Backed out 2 changesets (bug 1931901) for causing build bustages in TelemetryScalar...
[gecko.git] / gfx / layers / NativeLayerWayland.cpp
blob55250b3de0cbdcd471cb91e3da30e852f18c06e7
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "mozilla/layers/NativeLayerWayland.h"
7 #include <dlfcn.h>
8 #include <utility>
9 #include <algorithm>
11 #include "gfxUtils.h"
12 #include "nsGtkUtils.h"
13 #include "GLContextProvider.h"
14 #include "GLBlitHelper.h"
15 #include "mozilla/gfx/DataSurfaceHelpers.h"
16 #include "mozilla/gfx/Logging.h"
17 #include "mozilla/layers/SurfacePoolWayland.h"
18 #include "mozilla/StaticPrefs_widget.h"
19 #include "mozilla/webrender/RenderThread.h"
21 namespace mozilla::layers {
23 using gfx::BackendType;
24 using gfx::DrawTarget;
25 using gfx::IntPoint;
26 using gfx::IntRect;
27 using gfx::IntRegion;
28 using gfx::IntSize;
29 using gfx::Matrix4x4;
30 using gfx::Point;
31 using gfx::Rect;
32 using gfx::SamplingFilter;
33 using gfx::Size;
35 static const struct wl_callback_listener sFrameListenerNativeLayerWayland = {
36 NativeLayerWayland::FrameCallbackHandler};
38 CallbackMultiplexHelper::CallbackMultiplexHelper(CallbackFunc aCallbackFunc,
39 void* aCallbackData)
40 : mCallbackFunc(aCallbackFunc), mCallbackData(aCallbackData) {}
42 void CallbackMultiplexHelper::Callback(uint32_t aTime) {
43 if (!mActive) {
44 return;
46 mActive = false;
48 // This is likely the first of a batch of frame callbacks being processed and
49 // may trigger the setup of a successive one. In order to avoid complexity,
50 // defer calling the callback function until we had a chance to process
51 // all pending frame callbacks.
53 AddRef();
54 nsCOMPtr<nsIRunnable> runnable = NewRunnableMethod<uint32_t>(
55 "layers::CallbackMultiplexHelper::RunCallback", this,
56 &CallbackMultiplexHelper::RunCallback, aTime);
57 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThreadQueue(
58 runnable.forget(), EventQueuePriority::Vsync));
61 void CallbackMultiplexHelper::RunCallback(uint32_t aTime) {
62 mCallbackFunc(mCallbackData, aTime);
63 Release();
66 /* static */
67 already_AddRefed<NativeLayerRootWayland>
68 NativeLayerRootWayland::CreateForMozContainer(MozContainer* aContainer) {
69 RefPtr<NativeLayerRootWayland> layerRoot =
70 new NativeLayerRootWayland(aContainer);
71 return layerRoot.forget();
74 NativeLayerRootWayland::NativeLayerRootWayland(MozContainer* aContainer)
75 : mMutex("NativeLayerRootWayland"), mContainer(aContainer) {
76 g_object_ref(mContainer);
79 NativeLayerRootWayland::~NativeLayerRootWayland() {
80 GdkWindow* gdkWindow = gtk_widget_get_window(GTK_WIDGET(mContainer));
81 if (gdkWindow) {
82 GdkFrameClock* frameClock = gdk_window_get_frame_clock(gdkWindow);
83 g_signal_handlers_disconnect_by_data(frameClock, this);
85 g_object_unref(mContainer);
88 already_AddRefed<NativeLayer> NativeLayerRootWayland::CreateLayer(
89 const IntSize& aSize, bool aIsOpaque,
90 SurfacePoolHandle* aSurfacePoolHandle) {
91 RefPtr<NativeLayer> layer = new NativeLayerWayland(
92 aSize, aIsOpaque, aSurfacePoolHandle->AsSurfacePoolHandleWayland());
93 return layer.forget();
96 already_AddRefed<NativeLayer>
97 NativeLayerRootWayland::CreateLayerForExternalTexture(bool aIsOpaque) {
98 RefPtr<NativeLayer> layer = new NativeLayerWayland(aIsOpaque);
99 return layer.forget();
102 void NativeLayerRootWayland::AppendLayer(NativeLayer* aLayer) {
103 MOZ_RELEASE_ASSERT(false);
104 MutexAutoLock lock(mMutex);
106 RefPtr<NativeLayerWayland> layerWayland = aLayer->AsNativeLayerWayland();
107 MOZ_RELEASE_ASSERT(layerWayland);
109 mSublayers.AppendElement(layerWayland);
112 void NativeLayerRootWayland::RemoveLayer(NativeLayer* aLayer) {
113 MOZ_RELEASE_ASSERT(false);
114 MutexAutoLock lock(mMutex);
116 RefPtr<NativeLayerWayland> layerWayland = aLayer->AsNativeLayerWayland();
117 MOZ_RELEASE_ASSERT(layerWayland);
119 mSublayers.RemoveElement(layerWayland);
122 void NativeLayerRootWayland::SetLayers(
123 const nsTArray<RefPtr<NativeLayer>>& aLayers) {
124 MutexAutoLock lock(mMutex);
126 nsTArray<RefPtr<NativeLayerWayland>> newSublayers(aLayers.Length());
127 for (const RefPtr<NativeLayer>& sublayer : aLayers) {
128 RefPtr<NativeLayerWayland> layer = sublayer->AsNativeLayerWayland();
129 newSublayers.AppendElement(layer);
132 if (newSublayers != mSublayers) {
133 for (const RefPtr<NativeLayerWayland>& layer : mSublayers) {
134 if (!newSublayers.Contains(layer)) {
135 mOldSublayers.AppendElement(layer);
138 mSublayers = std::move(newSublayers);
139 mNewLayers = true;
143 bool NativeLayerRootWayland::CommitToScreen() {
144 MutexAutoLock lock(mMutex);
145 return CommitToScreen(lock);
148 bool NativeLayerRootWayland::CommitToScreen(const MutexAutoLock& aProofOfLock) {
149 mFrameInProcess = false;
151 MozContainerSurfaceLock lock(mContainer);
152 struct wl_surface* containerSurface = lock.GetSurface();
153 if (!containerSurface) {
154 if (!mCallbackRequested) {
155 RefPtr<NativeLayerRootWayland> self(this);
156 moz_container_wayland_add_initial_draw_callback_locked(
157 mContainer, [self]() -> void {
158 MutexAutoLock lock(self->mMutex);
159 if (!self->mFrameInProcess) {
160 self->CommitToScreen(lock);
162 self->mCallbackRequested = false;
164 mCallbackRequested = true;
166 return true;
169 wl_surface* previousSurface = nullptr;
170 for (RefPtr<NativeLayerWayland>& layer : mSublayers) {
171 layer->EnsureParentSurface(containerSurface);
173 if (mNewLayers) {
174 wl_subsurface_place_above(layer->mWlSubsurface, previousSurface
175 ? previousSurface
176 : containerSurface);
177 previousSurface = layer->mWlSurface;
180 MOZ_RELEASE_ASSERT(layer->mTransform.Is2D());
181 auto transform2D = layer->mTransform.As2D();
183 Rect surfaceRectClipped =
184 Rect(0, 0, (float)layer->mSize.width, (float)layer->mSize.height);
185 surfaceRectClipped =
186 surfaceRectClipped.Intersect(Rect(layer->mDisplayRect));
188 transform2D.PostTranslate((float)layer->mPosition.x,
189 (float)layer->mPosition.y);
190 surfaceRectClipped = transform2D.TransformBounds(surfaceRectClipped);
192 if (layer->mClipRect) {
193 surfaceRectClipped =
194 surfaceRectClipped.Intersect(Rect(layer->mClipRect.value()));
197 if (roundf(surfaceRectClipped.width) > 0 &&
198 roundf(surfaceRectClipped.height) > 0) {
199 layer->SetBufferTransformFlipped(transform2D._11 < 0.0,
200 transform2D._22 < 0.0);
202 double bufferScale = moz_container_wayland_get_scale(mContainer);
203 layer->SetSubsurfacePosition(floor(surfaceRectClipped.x / bufferScale),
204 floor(surfaceRectClipped.y / bufferScale));
205 layer->SetViewportDestinationSize(
206 ceil(surfaceRectClipped.width / bufferScale),
207 ceil(surfaceRectClipped.height / bufferScale));
209 auto transform2DInversed = transform2D.Inverse();
210 Rect bufferClip = transform2DInversed.TransformBounds(surfaceRectClipped);
211 layer->SetViewportSourceRect(bufferClip);
213 layer->Commit();
214 } else {
215 layer->Unmap();
219 if (mNewLayers) {
220 for (RefPtr<NativeLayerWayland>& layer : mOldSublayers) {
221 layer->Unmap();
223 mOldSublayers.Clear();
225 nsCOMPtr<nsIRunnable> updateLayersRunnable = NewRunnableMethod<>(
226 "layers::NativeLayerRootWayland::UpdateLayersOnMainThread", this,
227 &NativeLayerRootWayland::UpdateLayersOnMainThread);
228 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThreadQueue(
229 updateLayersRunnable.forget(), EventQueuePriority::Normal));
230 mNewLayers = false;
233 if (containerSurface != mWlSurface) {
234 if (!mShmBuffer) {
235 mShmBuffer = widget::WaylandBufferSHM::Create(LayoutDeviceIntSize(1, 1));
236 mShmBuffer->Clear();
238 mShmBuffer->AttachAndCommit(containerSurface);
239 mWlSurface = containerSurface;
240 } else {
241 wl_surface_commit(containerSurface);
244 wl_display_flush(widget::WaylandDisplayGet()->GetDisplay());
245 return true;
248 void NativeLayerRootWayland::RequestFrameCallback(CallbackFunc aCallbackFunc,
249 void* aCallbackData) {
250 MutexAutoLock lock(mMutex);
252 mCallbackMultiplexHelper =
253 new CallbackMultiplexHelper(aCallbackFunc, aCallbackData);
255 for (const RefPtr<NativeLayerWayland>& layer : mSublayersOnMainThread) {
256 layer->RequestFrameCallback(mCallbackMultiplexHelper);
259 MozContainerSurfaceLock lockContainer(mContainer);
260 struct wl_surface* wlSurface = lockContainer.GetSurface();
261 if (wlSurface) {
262 wl_surface_commit(wlSurface);
263 wl_display_flush(widget::WaylandDisplayGet()->GetDisplay());
267 static void sAfterFrameClockAfterPaint(
268 GdkFrameClock* aClock, NativeLayerRootWayland* aNativeLayerRoot) {
269 aNativeLayerRoot->AfterFrameClockAfterPaint();
272 void NativeLayerRootWayland::AfterFrameClockAfterPaint() {
273 MutexAutoLock lock(mMutex);
274 MozContainerSurfaceLock lockContainer(mContainer);
275 struct wl_surface* containerSurface = lockContainer.GetSurface();
276 for (const RefPtr<NativeLayerWayland>& layer : mSublayersOnMainThread) {
277 wl_surface_commit(layer->mWlSurface);
279 if (containerSurface) {
280 wl_surface_commit(containerSurface);
284 void NativeLayerRootWayland::UpdateLayersOnMainThread() {
285 AssertIsOnMainThread();
286 MutexAutoLock lock(mMutex);
288 static auto sGdkWaylandWindowAddCallbackSurface =
289 (void (*)(GdkWindow*, struct wl_surface*))dlsym(
290 RTLD_DEFAULT, "gdk_wayland_window_add_frame_callback_surface");
291 static auto sGdkWaylandWindowRemoveCallbackSurface =
292 (void (*)(GdkWindow*, struct wl_surface*))dlsym(
293 RTLD_DEFAULT, "gdk_wayland_window_remove_frame_callback_surface");
295 MozContainerSurfaceLock lockContainer(mContainer);
296 struct wl_surface* containerSurface = lockContainer.GetSurface();
297 GdkWindow* gdkWindow = gtk_widget_get_window(GTK_WIDGET(mContainer));
299 mSublayersOnMainThread.RemoveElementsBy([&](const auto& layer) {
300 if (!mSublayers.Contains(layer)) {
301 if (layer->IsOpaque() &&
302 StaticPrefs::widget_wayland_opaque_region_enabled_AtStartup() &&
303 sGdkWaylandWindowAddCallbackSurface && gdkWindow) {
304 sGdkWaylandWindowRemoveCallbackSurface(gdkWindow, layer->mWlSurface);
306 wl_compositor* compositor =
307 widget::WaylandDisplayGet()->GetCompositor();
308 wl_region* region = wl_compositor_create_region(compositor);
309 wl_surface_set_opaque_region(layer->mWlSurface, region);
310 wl_region_destroy(region);
311 wl_surface_commit(layer->mWlSurface);
313 return true;
315 return false;
318 for (const RefPtr<NativeLayerWayland>& layer : mSublayers) {
319 if (!mSublayersOnMainThread.Contains(layer)) {
320 if (layer->IsOpaque() &&
321 StaticPrefs::widget_wayland_opaque_region_enabled_AtStartup() &&
322 sGdkWaylandWindowRemoveCallbackSurface && gdkWindow) {
323 sGdkWaylandWindowAddCallbackSurface(gdkWindow, layer->mWlSurface);
325 wl_compositor* compositor =
326 widget::WaylandDisplayGet()->GetCompositor();
327 wl_region* region = wl_compositor_create_region(compositor);
328 wl_region_add(region, 0, 0, INT32_MAX, INT32_MAX);
329 wl_surface_set_opaque_region(layer->mWlSurface, region);
330 wl_region_destroy(region);
331 wl_surface_commit(layer->mWlSurface);
333 if (mCallbackMultiplexHelper && mCallbackMultiplexHelper->IsActive()) {
334 layer->RequestFrameCallback(mCallbackMultiplexHelper);
336 mSublayersOnMainThread.AppendElement(layer);
340 if (containerSurface) {
341 wl_surface_commit(containerSurface);
344 if (!mGdkAfterPaintId && gdkWindow) {
345 GdkFrameClock* frameClock = gdk_window_get_frame_clock(gdkWindow);
346 mGdkAfterPaintId =
347 g_signal_connect_after(frameClock, "after-paint",
348 G_CALLBACK(sAfterFrameClockAfterPaint), this);
352 NativeLayerWayland::NativeLayerWayland(
353 const IntSize& aSize, bool aIsOpaque,
354 SurfacePoolHandleWayland* aSurfacePoolHandle)
355 : mMutex("NativeLayerWayland"),
356 mSurfacePoolHandle(aSurfacePoolHandle),
357 mSize(aSize),
358 mIsOpaque(aIsOpaque) {
359 MOZ_RELEASE_ASSERT(mSurfacePoolHandle,
360 "Need a non-null surface pool handle.");
362 widget::nsWaylandDisplay* waylandDisplay = widget::WaylandDisplayGet();
363 wl_compositor* compositor = waylandDisplay->GetCompositor();
364 mWlSurface = wl_compositor_create_surface(compositor);
366 wl_region* region = wl_compositor_create_region(compositor);
367 wl_surface_set_input_region(mWlSurface, region);
368 wl_region_destroy(region);
370 wp_viewporter* viewporter = waylandDisplay->GetViewporter();
371 mViewport = wp_viewporter_get_viewport(viewporter, mWlSurface);
374 NativeLayerWayland::NativeLayerWayland(bool aIsOpaque)
375 : mMutex("NativeLayerWayland"),
376 mSurfacePoolHandle(nullptr),
377 mIsOpaque(aIsOpaque) {
378 MOZ_RELEASE_ASSERT(false); // external image
381 NativeLayerWayland::~NativeLayerWayland() {
382 MutexAutoLock lock(mMutex);
384 if (mInProgressBuffer) {
385 mSurfacePoolHandle->ReturnBufferToPool(mInProgressBuffer);
386 mInProgressBuffer = nullptr;
388 if (mFrontBuffer) {
389 mSurfacePoolHandle->ReturnBufferToPool(mFrontBuffer);
390 mFrontBuffer = nullptr;
392 MozClearPointer(mCallback, wl_callback_destroy);
393 MozClearPointer(mViewport, wp_viewport_destroy);
394 MozClearPointer(mWlSubsurface, wl_subsurface_destroy);
395 MozClearPointer(mWlSurface, wl_surface_destroy);
398 void NativeLayerWayland::AttachExternalImage(
399 wr::RenderTextureHost* aExternalImage) {
400 MOZ_RELEASE_ASSERT(false);
403 void NativeLayerWayland::SetSurfaceIsFlipped(bool aIsFlipped) {
404 MutexAutoLock lock(mMutex);
406 if (aIsFlipped != mSurfaceIsFlipped) {
407 mSurfaceIsFlipped = aIsFlipped;
411 bool NativeLayerWayland::SurfaceIsFlipped() {
412 MutexAutoLock lock(mMutex);
414 return mSurfaceIsFlipped;
417 IntSize NativeLayerWayland::GetSize() {
418 MutexAutoLock lock(mMutex);
419 return mSize;
422 void NativeLayerWayland::SetPosition(const IntPoint& aPosition) {
423 MutexAutoLock lock(mMutex);
425 if (aPosition != mPosition) {
426 mPosition = aPosition;
430 IntPoint NativeLayerWayland::GetPosition() {
431 MutexAutoLock lock(mMutex);
432 return mPosition;
435 void NativeLayerWayland::SetTransform(const Matrix4x4& aTransform) {
436 MutexAutoLock lock(mMutex);
437 MOZ_ASSERT(aTransform.IsRectilinear());
439 if (aTransform != mTransform) {
440 mTransform = aTransform;
444 void NativeLayerWayland::SetSamplingFilter(SamplingFilter aSamplingFilter) {
445 MutexAutoLock lock(mMutex);
447 if (aSamplingFilter != mSamplingFilter) {
448 mSamplingFilter = aSamplingFilter;
452 Matrix4x4 NativeLayerWayland::GetTransform() {
453 MutexAutoLock lock(mMutex);
454 return mTransform;
457 IntRect NativeLayerWayland::GetRect() {
458 MutexAutoLock lock(mMutex);
459 return IntRect(mPosition, mSize);
462 bool NativeLayerWayland::IsOpaque() {
463 MutexAutoLock lock(mMutex);
464 return mIsOpaque;
467 void NativeLayerWayland::SetClipRect(const Maybe<IntRect>& aClipRect) {
468 MutexAutoLock lock(mMutex);
470 if (aClipRect != mClipRect) {
471 mClipRect = aClipRect;
475 Maybe<IntRect> NativeLayerWayland::ClipRect() {
476 MutexAutoLock lock(mMutex);
477 return mClipRect;
480 IntRect NativeLayerWayland::CurrentSurfaceDisplayRect() {
481 MutexAutoLock lock(mMutex);
482 return mDisplayRect;
485 RefPtr<DrawTarget> NativeLayerWayland::NextSurfaceAsDrawTarget(
486 const IntRect& aDisplayRect, const IntRegion& aUpdateRegion,
487 BackendType aBackendType) {
488 MutexAutoLock lock(mMutex);
490 mDisplayRect = IntRect(aDisplayRect);
491 mDirtyRegion = IntRegion(aUpdateRegion);
493 MOZ_ASSERT(!mInProgressBuffer);
494 if (mFrontBuffer && !mFrontBuffer->IsAttached()) {
495 // the Wayland compositor released the buffer early, we can reuse it
496 mInProgressBuffer = std::move(mFrontBuffer);
497 } else {
498 mInProgressBuffer = mSurfacePoolHandle->ObtainBufferFromPool(mSize);
499 if (mFrontBuffer) {
500 HandlePartialUpdate(lock);
501 mSurfacePoolHandle->ReturnBufferToPool(mFrontBuffer);
504 mFrontBuffer = nullptr;
506 if (!mInProgressBuffer) {
507 gfxCriticalError() << "Failed to obtain buffer";
508 wr::RenderThread::Get()->HandleWebRenderError(
509 wr::WebRenderError::NEW_SURFACE);
510 return nullptr;
513 return mInProgressBuffer->Lock();
516 Maybe<GLuint> NativeLayerWayland::NextSurfaceAsFramebuffer(
517 const IntRect& aDisplayRect, const IntRegion& aUpdateRegion,
518 bool aNeedsDepth) {
519 MutexAutoLock lock(mMutex);
521 mDisplayRect = IntRect(aDisplayRect);
522 mDirtyRegion = IntRegion(aUpdateRegion);
524 MOZ_ASSERT(!mInProgressBuffer);
525 if (mFrontBuffer && !mFrontBuffer->IsAttached()) {
526 // the Wayland compositor released the buffer early, we can reuse it
527 mInProgressBuffer = std::move(mFrontBuffer);
528 mFrontBuffer = nullptr;
529 } else {
530 mInProgressBuffer = mSurfacePoolHandle->ObtainBufferFromPool(mSize);
533 if (!mInProgressBuffer) {
534 gfxCriticalError() << "Failed to obtain buffer";
535 wr::RenderThread::Get()->HandleWebRenderError(
536 wr::WebRenderError::NEW_SURFACE);
537 return Nothing();
540 // get the framebuffer before handling partial damage so we don't accidently
541 // create one without depth buffer
542 Maybe<GLuint> fbo = mSurfacePoolHandle->GetFramebufferForBuffer(
543 mInProgressBuffer, aNeedsDepth);
544 MOZ_RELEASE_ASSERT(fbo, "GetFramebufferForBuffer failed.");
546 if (mFrontBuffer) {
547 HandlePartialUpdate(lock);
548 mSurfacePoolHandle->ReturnBufferToPool(mFrontBuffer);
549 mFrontBuffer = nullptr;
552 return fbo;
555 void NativeLayerWayland::HandlePartialUpdate(
556 const MutexAutoLock& aProofOfLock) {
557 IntRegion copyRegion = IntRegion(mDisplayRect);
558 copyRegion.SubOut(mDirtyRegion);
560 if (!copyRegion.IsEmpty()) {
561 if (mSurfacePoolHandle->gl()) {
562 mSurfacePoolHandle->gl()->MakeCurrent();
563 for (auto iter = copyRegion.RectIter(); !iter.Done(); iter.Next()) {
564 gfx::IntRect r = iter.Get();
565 Maybe<GLuint> sourceFB =
566 mSurfacePoolHandle->GetFramebufferForBuffer(mFrontBuffer, false);
567 Maybe<GLuint> destFB = mSurfacePoolHandle->GetFramebufferForBuffer(
568 mInProgressBuffer, false);
569 MOZ_RELEASE_ASSERT(sourceFB && destFB);
570 mSurfacePoolHandle->gl()->BlitHelper()->BlitFramebufferToFramebuffer(
571 sourceFB.value(), destFB.value(), r, r, LOCAL_GL_NEAREST);
573 } else {
574 RefPtr<gfx::DataSourceSurface> dataSourceSurface =
575 gfx::CreateDataSourceSurfaceFromData(
576 mSize, mFrontBuffer->GetSurfaceFormat(),
577 (const uint8_t*)mFrontBuffer->GetImageData(),
578 mSize.width * BytesPerPixel(mFrontBuffer->GetSurfaceFormat()));
579 RefPtr<DrawTarget> dt = mInProgressBuffer->Lock();
581 for (auto iter = copyRegion.RectIter(); !iter.Done(); iter.Next()) {
582 IntRect r = iter.Get();
583 dt->CopySurface(dataSourceSurface, r, IntPoint(r.x, r.y));
589 void NativeLayerWayland::NotifySurfaceReady() {
590 MOZ_ASSERT(!mFrontBuffer);
591 MOZ_ASSERT(mInProgressBuffer);
592 mFrontBuffer = mInProgressBuffer;
593 mInProgressBuffer = nullptr;
596 void NativeLayerWayland::DiscardBackbuffers() {}
598 void NativeLayerWayland::Commit() {
599 MutexAutoLock lock(mMutex);
601 if (mDirtyRegion.IsEmpty() && mHasBufferAttached) {
602 wl_surface_commit(mWlSurface);
603 return;
606 for (auto iter = mDirtyRegion.RectIter(); !iter.Done(); iter.Next()) {
607 IntRect r = iter.Get();
608 wl_surface_damage_buffer(mWlSurface, r.x, r.y, r.width, r.height);
611 MOZ_ASSERT(mFrontBuffer);
612 mFrontBuffer->AttachAndCommit(mWlSurface);
613 mHasBufferAttached = true;
614 mDirtyRegion.SetEmpty();
617 void NativeLayerWayland::Unmap() {
618 MutexAutoLock lock(mMutex);
620 if (!mHasBufferAttached) {
621 return;
624 wl_surface_attach(mWlSurface, nullptr, 0, 0);
625 wl_surface_commit(mWlSurface);
626 mHasBufferAttached = false;
629 void NativeLayerWayland::EnsureParentSurface(wl_surface* aParentSurface) {
630 MutexAutoLock lock(mMutex);
632 if (aParentSurface != mParentWlSurface) {
633 MozClearPointer(mWlSubsurface, wl_subsurface_destroy);
634 mSubsurfacePosition = IntPoint(0, 0);
636 if (aParentSurface) {
637 wl_subcompositor* subcompositor =
638 widget::WaylandDisplayGet()->GetSubcompositor();
639 mWlSubsurface = wl_subcompositor_get_subsurface(subcompositor, mWlSurface,
640 aParentSurface);
642 mParentWlSurface = aParentSurface;
646 void NativeLayerWayland::SetBufferTransformFlipped(bool aFlippedX,
647 bool aFlippedY) {
648 MutexAutoLock lock(mMutex);
650 if (aFlippedX == mBufferTransformFlippedX &&
651 aFlippedY == mBufferTransformFlippedY) {
652 return;
655 mBufferTransformFlippedX = aFlippedX;
656 mBufferTransformFlippedY = aFlippedY;
658 if (mBufferTransformFlippedY) {
659 if (mBufferTransformFlippedX) {
660 wl_surface_set_buffer_transform(mWlSurface, WL_OUTPUT_TRANSFORM_180);
661 } else {
662 wl_surface_set_buffer_transform(mWlSurface,
663 WL_OUTPUT_TRANSFORM_FLIPPED_180);
665 } else {
666 if (mBufferTransformFlippedX) {
667 wl_surface_set_buffer_transform(mWlSurface, WL_OUTPUT_TRANSFORM_FLIPPED);
668 } else {
669 wl_surface_set_buffer_transform(mWlSurface, WL_OUTPUT_TRANSFORM_NORMAL);
674 void NativeLayerWayland::SetSubsurfacePosition(int aX, int aY) {
675 MutexAutoLock lock(mMutex);
677 if ((aX == mSubsurfacePosition.x && aY == mSubsurfacePosition.y) ||
678 !mWlSubsurface) {
679 return;
682 mSubsurfacePosition.x = aX;
683 mSubsurfacePosition.y = aY;
684 wl_subsurface_set_position(mWlSubsurface, mSubsurfacePosition.x,
685 mSubsurfacePosition.y);
688 void NativeLayerWayland::SetViewportSourceRect(const Rect aSourceRect) {
689 MutexAutoLock lock(mMutex);
691 Rect bufferRect = Rect(0, 0, mSize.width, mSize.height);
692 Rect sourceRect = aSourceRect.Intersect(bufferRect);
694 if (mViewportSourceRect == sourceRect) {
695 return;
698 mViewportSourceRect = sourceRect;
699 wp_viewport_set_source(mViewport, wl_fixed_from_double(mViewportSourceRect.x),
700 wl_fixed_from_double(mViewportSourceRect.y),
701 wl_fixed_from_double(mViewportSourceRect.width),
702 wl_fixed_from_double(mViewportSourceRect.height));
705 void NativeLayerWayland::SetViewportDestinationSize(int aWidth, int aHeight) {
706 MutexAutoLock lock(mMutex);
708 if (aWidth == mViewportDestinationSize.width &&
709 aHeight == mViewportDestinationSize.height) {
710 return;
713 mViewportDestinationSize.width = aWidth;
714 mViewportDestinationSize.height = aHeight;
715 wp_viewport_set_destination(mViewport, mViewportDestinationSize.width,
716 mViewportDestinationSize.height);
719 void NativeLayerWayland::RequestFrameCallback(
720 const RefPtr<CallbackMultiplexHelper>& aMultiplexHelper) {
721 MutexAutoLock lock(mMutex);
722 MOZ_ASSERT(aMultiplexHelper->IsActive());
724 // Avoid piling up old helpers if this surface does not receive callbacks
725 // for a longer time
726 mCallbackMultiplexHelpers.RemoveElementsBy(
727 [&](const auto& object) { return !object->IsActive(); });
729 mCallbackMultiplexHelpers.AppendElement(aMultiplexHelper);
730 if (!mCallback) {
731 mCallback = wl_surface_frame(mWlSurface);
732 wl_callback_add_listener(mCallback, &sFrameListenerNativeLayerWayland,
733 this);
734 wl_surface_commit(mWlSurface);
738 void NativeLayerWayland::FrameCallbackHandler(wl_callback* aCallback,
739 uint32_t aTime) {
740 MutexAutoLock lock(mMutex);
742 MOZ_RELEASE_ASSERT(aCallback == mCallback);
743 MozClearPointer(mCallback, wl_callback_destroy);
745 for (const RefPtr<CallbackMultiplexHelper>& callbackMultiplexHelper :
746 mCallbackMultiplexHelpers) {
747 callbackMultiplexHelper->Callback(aTime);
749 mCallbackMultiplexHelpers.Clear();
752 /* static */
753 void NativeLayerWayland::FrameCallbackHandler(void* aData,
754 wl_callback* aCallback,
755 uint32_t aTime) {
756 auto surface = reinterpret_cast<NativeLayerWayland*>(aData);
757 surface->FrameCallbackHandler(aCallback, aTime);
760 } // namespace mozilla::layers