summaryrefslogtreecommitdiff
path: root/Kernel/Memory/SharedFramebufferVMObject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Kernel/Memory/SharedFramebufferVMObject.cpp')
-rw-r--r--Kernel/Memory/SharedFramebufferVMObject.cpp120
1 files changed, 120 insertions, 0 deletions
diff --git a/Kernel/Memory/SharedFramebufferVMObject.cpp b/Kernel/Memory/SharedFramebufferVMObject.cpp
new file mode 100644
index 0000000000..f0ea27e874
--- /dev/null
+++ b/Kernel/Memory/SharedFramebufferVMObject.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/FileSystem/Inode.h>
+#include <Kernel/Locking/Spinlock.h>
+#include <Kernel/Memory/SharedFramebufferVMObject.h>
+
+namespace Kernel::Memory {
+
+ErrorOr<NonnullRefPtr<SharedFramebufferVMObject>> SharedFramebufferVMObject::try_create_for_physical_range(PhysicalAddress paddr, size_t size)
+{
+ auto real_framebuffer_vmobject = TRY(AnonymousVMObject::try_create_for_physical_range(paddr, size));
+ auto new_physical_pages = TRY(VMObject::try_create_physical_pages(size));
+ auto committed_pages = TRY(MM.commit_user_physical_pages(ceil_div(size, static_cast<size_t>(PAGE_SIZE))));
+ auto vm_object = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) SharedFramebufferVMObject(move(new_physical_pages), move(committed_pages), real_framebuffer_vmobject)));
+ TRY(vm_object->create_fake_writes_framebuffer_vm_object());
+ TRY(vm_object->create_real_writes_framebuffer_vm_object());
+ return vm_object;
+}
+
+ErrorOr<NonnullRefPtr<SharedFramebufferVMObject>> SharedFramebufferVMObject::try_create_at_arbitrary_physical_range(size_t size)
+{
+ auto real_framebuffer_vmobject = TRY(AnonymousVMObject::try_create_with_size(size, AllocationStrategy::AllocateNow));
+ auto new_physical_pages = TRY(VMObject::try_create_physical_pages(size));
+ auto committed_pages = TRY(MM.commit_user_physical_pages(ceil_div(size, static_cast<size_t>(PAGE_SIZE))));
+ auto vm_object = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) SharedFramebufferVMObject(move(new_physical_pages), move(committed_pages), real_framebuffer_vmobject)));
+ TRY(vm_object->create_fake_writes_framebuffer_vm_object());
+ TRY(vm_object->create_real_writes_framebuffer_vm_object());
+ return vm_object;
+}
+
+ErrorOr<NonnullRefPtr<SharedFramebufferVMObject::FakeWritesFramebufferVMObject>> SharedFramebufferVMObject::FakeWritesFramebufferVMObject::try_create(Badge<SharedFramebufferVMObject>, SharedFramebufferVMObject const& parent_object)
+{
+ auto new_physical_pages = TRY(VMObject::try_create_physical_pages(0));
+ return adopt_nonnull_ref_or_enomem(new (nothrow) FakeWritesFramebufferVMObject(parent_object, move(new_physical_pages)));
+}
+
+ErrorOr<NonnullRefPtr<SharedFramebufferVMObject::RealWritesFramebufferVMObject>> SharedFramebufferVMObject::RealWritesFramebufferVMObject::try_create(Badge<SharedFramebufferVMObject>, SharedFramebufferVMObject const& parent_object)
+{
+ auto new_physical_pages = TRY(VMObject::try_create_physical_pages(0));
+ return adopt_nonnull_ref_or_enomem(new (nothrow) RealWritesFramebufferVMObject(parent_object, move(new_physical_pages)));
+}
+
+ErrorOr<void> SharedFramebufferVMObject::create_fake_writes_framebuffer_vm_object()
+{
+ m_fake_writes_framebuffer_vmobject = TRY(FakeWritesFramebufferVMObject::try_create({}, *this));
+ return {};
+}
+
+ErrorOr<void> SharedFramebufferVMObject::create_real_writes_framebuffer_vm_object()
+{
+ m_real_writes_framebuffer_vmobject = TRY(RealWritesFramebufferVMObject::try_create({}, *this));
+ return {};
+}
+
+Span<RefPtr<PhysicalPage>> SharedFramebufferVMObject::real_framebuffer_physical_pages()
+{
+ return m_real_framebuffer_vmobject->physical_pages();
+}
+Span<RefPtr<PhysicalPage> const> SharedFramebufferVMObject::real_framebuffer_physical_pages() const
+{
+ return m_real_framebuffer_vmobject->physical_pages();
+}
+
+Span<RefPtr<PhysicalPage>> SharedFramebufferVMObject::fake_sink_framebuffer_physical_pages()
+{
+ return m_physical_pages.span();
+}
+
+Span<RefPtr<PhysicalPage> const> SharedFramebufferVMObject::fake_sink_framebuffer_physical_pages() const
+{
+ return m_physical_pages.span();
+}
+
+void SharedFramebufferVMObject::switch_to_fake_sink_framebuffer_writes(Badge<Kernel::DisplayConnector>)
+{
+ SpinlockLocker locker(m_writes_state_lock);
+ m_writes_are_faked = true;
+ for_each_region([](Region& region) {
+ region.remap();
+ });
+}
+void SharedFramebufferVMObject::switch_to_real_framebuffer_writes(Badge<Kernel::DisplayConnector>)
+{
+ SpinlockLocker locker(m_writes_state_lock);
+ m_writes_are_faked = false;
+ for_each_region([](Region& region) {
+ region.remap();
+ });
+}
+
+Span<RefPtr<PhysicalPage> const> SharedFramebufferVMObject::physical_pages() const
+{
+ SpinlockLocker locker(m_writes_state_lock);
+ if (m_writes_are_faked)
+ return VMObject::physical_pages();
+ return m_real_framebuffer_vmobject->physical_pages();
+}
+Span<RefPtr<PhysicalPage>> SharedFramebufferVMObject::physical_pages()
+{
+ SpinlockLocker locker(m_writes_state_lock);
+ if (m_writes_are_faked)
+ return VMObject::physical_pages();
+ return m_real_framebuffer_vmobject->physical_pages();
+}
+
+SharedFramebufferVMObject::SharedFramebufferVMObject(FixedArray<RefPtr<PhysicalPage>>&& new_physical_pages, CommittedPhysicalPageSet committed_pages, AnonymousVMObject& real_framebuffer_vmobject)
+ : VMObject(move(new_physical_pages))
+ , m_real_framebuffer_vmobject(real_framebuffer_vmobject)
+ , m_committed_pages(move(committed_pages))
+{
+ // Allocate all pages right now. We know we can get all because we committed the amount needed
+ for (size_t i = 0; i < page_count(); ++i)
+ m_physical_pages[i] = m_committed_pages.take_one();
+}
+
+}