Bug 1764201 Part 3: Remove screen info stuff from gfxPlatform. r=jgilbert,geckoview...
[gecko.git] / gfx / layers / SurfacePoolWayland.cpp
blobe1229fcaaa3a2015402a86107aad110a96f3d44a
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nullptr; c-basic-offset: 2
2 * -*- This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/layers/SurfacePoolWayland.h"
8 #include "GLBlitHelper.h"
9 #include "mozilla/gfx/DataSurfaceHelpers.h"
11 namespace mozilla::layers {
13 using gfx::IntSize;
14 using gl::DepthAndStencilBuffer;
15 using gl::GLContext;
16 using gl::MozFramebuffer;
17 using widget::WaylandBuffer;
19 /* static */ RefPtr<SurfacePool> SurfacePool::Create(size_t aPoolSizeLimit) {
20 return new SurfacePoolWayland(aPoolSizeLimit);
23 SurfacePoolWayland::SurfacePoolWayland(size_t aPoolSizeLimit)
24 : mMutex("SurfacePoolWayland"), mPoolSizeLimit(aPoolSizeLimit) {}
26 RefPtr<SurfacePoolHandle> SurfacePoolWayland::GetHandleForGL(GLContext* aGL) {
27 return new SurfacePoolHandleWayland(this, aGL);
30 template <typename F>
31 void SurfacePoolWayland::ForEachEntry(F aFn) {
32 for (auto& iter : mInUseEntries) {
33 aFn(iter.second);
35 for (auto& entry : mPendingEntries) {
36 aFn(entry);
38 for (auto& entry : mAvailableEntries) {
39 aFn(entry);
43 void SurfacePoolWayland::DestroyGLResourcesForContext(GLContext* aGL) {
44 MutexAutoLock lock(mMutex);
46 ForEachEntry([&](SurfacePoolEntry& entry) {
47 if (entry.mGLResources && entry.mGLResources->mGL == aGL) {
48 entry.mGLResources = Nothing();
49 entry.mWaylandBuffer->DestroyGLResources();
51 });
52 mDepthBuffers.RemoveElementsBy(
53 [&](const DepthBufferEntry& entry) { return entry.mGL == aGL; });
56 bool SurfacePoolWayland::CanRecycleSurfaceForRequest(
57 const MutexAutoLock& aProofOfLock, const SurfacePoolEntry& aEntry,
58 const IntSize& aSize, GLContext* aGL) {
59 if (aEntry.mSize != aSize) {
60 return false;
62 if (aEntry.mGLResources) {
63 return aEntry.mGLResources->mGL == aGL;
65 return aGL == nullptr;
68 RefPtr<WaylandBuffer> SurfacePoolWayland::ObtainBufferFromPool(
69 const IntSize& aSize, GLContext* aGL) {
70 MutexAutoLock lock(mMutex);
72 auto iterToRecycle = std::find_if(
73 mAvailableEntries.begin(), mAvailableEntries.end(),
74 [&](const SurfacePoolEntry& aEntry) {
75 return CanRecycleSurfaceForRequest(lock, aEntry, aSize, aGL);
76 });
77 if (iterToRecycle != mAvailableEntries.end()) {
78 RefPtr<WaylandBuffer> buffer = iterToRecycle->mWaylandBuffer;
79 mInUseEntries.insert({buffer.get(), std::move(*iterToRecycle)});
80 mAvailableEntries.RemoveElementAt(iterToRecycle);
81 return buffer;
84 RefPtr<WaylandBuffer> buffer;
85 if (aGL) {
86 buffer = widget::WaylandBufferDMABUF::Create(
87 LayoutDeviceIntSize::FromUnknownSize(aSize), aGL);
88 } else {
89 buffer = widget::WaylandBufferSHM::Create(
90 LayoutDeviceIntSize::FromUnknownSize(aSize));
92 if (buffer) {
93 mInUseEntries.insert({buffer.get(), SurfacePoolEntry{aSize, buffer, {}}});
96 return buffer;
99 void SurfacePoolWayland::ReturnBufferToPool(
100 const RefPtr<WaylandBuffer>& aBuffer) {
101 MutexAutoLock lock(mMutex);
103 auto inUseEntryIter = mInUseEntries.find(aBuffer);
104 MOZ_RELEASE_ASSERT(inUseEntryIter != mInUseEntries.end());
106 if (aBuffer->IsAttached()) {
107 mPendingEntries.AppendElement(std::move(inUseEntryIter->second));
108 mInUseEntries.erase(inUseEntryIter);
109 } else {
110 mAvailableEntries.AppendElement(std::move(inUseEntryIter->second));
111 mInUseEntries.erase(inUseEntryIter);
115 void SurfacePoolWayland::EnforcePoolSizeLimit() {
116 MutexAutoLock lock(mMutex);
118 // Enforce the pool size limit, removing least-recently-used entries as
119 // necessary.
120 while (mAvailableEntries.Length() > mPoolSizeLimit) {
121 mAvailableEntries.RemoveElementAt(0);
124 NS_WARNING_ASSERTION(mPendingEntries.Length() < mPoolSizeLimit * 2,
125 "Are we leaking pending entries?");
126 NS_WARNING_ASSERTION(mInUseEntries.size() < mPoolSizeLimit * 2,
127 "Are we leaking in-use entries?");
130 void SurfacePoolWayland::CollectPendingSurfaces() {
131 MutexAutoLock lock(mMutex);
132 mPendingEntries.RemoveElementsBy([&](auto& entry) {
133 if (!entry.mWaylandBuffer->IsAttached()) {
134 mAvailableEntries.AppendElement(std::move(entry));
135 return true;
137 return false;
141 Maybe<GLuint> SurfacePoolWayland::GetFramebufferForBuffer(
142 const RefPtr<WaylandBuffer>& aBuffer, GLContext* aGL,
143 bool aNeedsDepthBuffer) {
144 MutexAutoLock lock(mMutex);
145 MOZ_RELEASE_ASSERT(aGL);
147 auto inUseEntryIter = mInUseEntries.find(aBuffer);
148 MOZ_RELEASE_ASSERT(inUseEntryIter != mInUseEntries.end());
150 SurfacePoolEntry& entry = inUseEntryIter->second;
151 if (entry.mGLResources) {
152 // We have an existing framebuffer.
153 MOZ_RELEASE_ASSERT(entry.mGLResources->mGL == aGL,
154 "Recycled surface that still had GL resources from a "
155 "different GL context. "
156 "This shouldn't happen.");
157 if (!aNeedsDepthBuffer || entry.mGLResources->mFramebuffer->HasDepth()) {
158 return Some(entry.mGLResources->mFramebuffer->mFB);
162 // No usable existing framebuffer, we need to create one.
164 if (!aGL->MakeCurrent()) {
165 // Context may have been destroyed.
166 return {};
169 const GLuint tex = aBuffer->GetTexture();
170 auto fb = CreateFramebufferForTexture(lock, aGL, entry.mSize, tex,
171 aNeedsDepthBuffer);
172 if (!fb) {
173 // Framebuffer completeness check may have failed.
174 return {};
177 GLuint fbo = fb->mFB;
178 entry.mGLResources = Some(GLResourcesForBuffer{aGL, std::move(fb)});
179 return Some(fbo);
182 RefPtr<gl::DepthAndStencilBuffer> SurfacePoolWayland::GetDepthBufferForSharing(
183 const MutexAutoLock& aProofOfLock, GLContext* aGL, const IntSize& aSize) {
184 // Clean out entries for which the weak pointer has become null.
185 mDepthBuffers.RemoveElementsBy(
186 [&](const DepthBufferEntry& entry) { return !entry.mBuffer; });
188 for (const auto& entry : mDepthBuffers) {
189 if (entry.mGL == aGL && entry.mSize == aSize) {
190 return entry.mBuffer.get();
193 return nullptr;
196 UniquePtr<MozFramebuffer> SurfacePoolWayland::CreateFramebufferForTexture(
197 const MutexAutoLock& aProofOfLock, GLContext* aGL, const IntSize& aSize,
198 GLuint aTexture, bool aNeedsDepthBuffer) {
199 if (aNeedsDepthBuffer) {
200 // Try to find an existing depth buffer of aSize in aGL and create a
201 // framebuffer that shares it.
202 if (auto buffer = GetDepthBufferForSharing(aProofOfLock, aGL, aSize)) {
203 return MozFramebuffer::CreateForBackingWithSharedDepthAndStencil(
204 aSize, 0, LOCAL_GL_TEXTURE_2D, aTexture, buffer);
208 // No depth buffer needed or we didn't find one. Create a framebuffer with a
209 // new depth buffer and store a weak pointer to the new depth buffer in
210 // mDepthBuffers.
211 UniquePtr<MozFramebuffer> fb = MozFramebuffer::CreateForBacking(
212 aGL, aSize, 0, aNeedsDepthBuffer, LOCAL_GL_TEXTURE_2D, aTexture);
213 if (fb && fb->GetDepthAndStencilBuffer()) {
214 mDepthBuffers.AppendElement(
215 DepthBufferEntry{aGL, aSize, fb->GetDepthAndStencilBuffer().get()});
218 return fb;
221 SurfacePoolHandleWayland::SurfacePoolHandleWayland(
222 RefPtr<SurfacePoolWayland> aPool, GLContext* aGL)
223 : mPool(std::move(aPool)), mGL(aGL) {}
225 void SurfacePoolHandleWayland::OnBeginFrame() {
226 mPool->CollectPendingSurfaces();
229 void SurfacePoolHandleWayland::OnEndFrame() { mPool->EnforcePoolSizeLimit(); }
231 RefPtr<WaylandBuffer> SurfacePoolHandleWayland::ObtainBufferFromPool(
232 const IntSize& aSize) {
233 return mPool->ObtainBufferFromPool(aSize, mGL);
236 void SurfacePoolHandleWayland::ReturnBufferToPool(
237 const RefPtr<WaylandBuffer>& aBuffer) {
238 mPool->ReturnBufferToPool(aBuffer);
241 Maybe<GLuint> SurfacePoolHandleWayland::GetFramebufferForBuffer(
242 const RefPtr<WaylandBuffer>& aBuffer, bool aNeedsDepthBuffer) {
243 return mPool->GetFramebufferForBuffer(aBuffer, mGL, aNeedsDepthBuffer);
246 } // namespace mozilla::layers