LibGfx: Make non-shared Bitmap used malloc() instead of mmap()

This drastically reduces the cost (in time AND space) of allocating
a Gfx::Bitmap.

Anything that needs to be shared is already using Core::AnonymousBuffer
anyway, so this shouldn't break anything important.

Do note that this makes it an error to create an empty (0x0) Bitmap,
which was previously allowed for some reason. Some small tweaks are
included to bail gracefully in such scenarios.
This commit is contained in:
Andreas Kling 2024-04-28 12:40:55 +02:00
commit 1db1ef9ea9
Notes: sideshowbarker 2024-07-16 22:54:10 +09:00
2 changed files with 10 additions and 16 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2023, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2018-2024, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2022, Timothy Slater <tslater2006@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
@ -23,9 +23,7 @@
#include <LibGfx/ImageFormats/ImageDecoder.h>
#include <LibGfx/ShareableBitmap.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/mman.h>
namespace Gfx {
@ -93,7 +91,7 @@ Bitmap::Bitmap(BitmapFormat format, IntSize size, int scale_factor, BackingStore
VERIFY(!size_would_overflow(format, size, scale_factor));
VERIFY(m_data);
VERIFY(backing_store.size_in_bytes == size_in_bytes());
m_needs_munmap = true;
m_data_is_malloced = true;
}
ErrorOr<NonnullRefPtr<Bitmap>> Bitmap::create_wrapper(BitmapFormat format, IntSize size, int scale_factor, size_t pitch, void* data)
@ -550,9 +548,8 @@ ErrorOr<NonnullRefPtr<Gfx::Bitmap>> Bitmap::inverted() const
Bitmap::~Bitmap()
{
if (m_needs_munmap) {
int rc = munmap(m_data, size_in_bytes());
VERIFY(rc == 0);
if (m_data_is_malloced) {
kfree_sized(m_data, size_in_bytes());
}
m_data = nullptr;
}
@ -583,20 +580,17 @@ Gfx::ShareableBitmap Bitmap::to_shareable_bitmap() const
ErrorOr<BackingStore> Bitmap::allocate_backing_store(BitmapFormat format, IntSize size, int scale_factor)
{
if (size.is_empty())
return Error::from_string_literal("Gfx::Bitmap backing store size is empty");
if (size_would_overflow(format, size, scale_factor))
return Error::from_string_literal("Gfx::Bitmap backing store size overflow");
auto const pitch = minimum_pitch(size.width() * scale_factor, format);
auto const data_size_in_bytes = size_in_bytes(pitch, size.height() * scale_factor);
int map_flags = MAP_ANONYMOUS | MAP_PRIVATE;
#ifdef AK_OS_SERENITY
map_flags |= MAP_PURGEABLE;
void* data = mmap_with_name(nullptr, data_size_in_bytes, PROT_READ | PROT_WRITE, map_flags, 0, 0, ByteString::formatted("GraphicsBitmap [{}]", size).characters());
#else
void* data = mmap(nullptr, data_size_in_bytes, PROT_READ | PROT_WRITE, map_flags, -1, 0);
#endif
if (data == MAP_FAILED)
void* data = kcalloc(1, data_size_in_bytes);
if (data == nullptr)
return Error::from_errno(errno);
return BackingStore { data, pitch, data_size_in_bytes };
}

View file

@ -244,7 +244,7 @@ private:
void* m_data { nullptr };
size_t m_pitch { 0 };
BitmapFormat m_format { BitmapFormat::Invalid };
bool m_needs_munmap { false };
bool m_data_is_malloced { false };
Core::AnonymousBuffer m_buffer;
};