1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 07:27:45 +00:00

LibGfx: Use anonymous buffer instead of raw anon_fd for Gfx::Bitmap

Instead of using a low-level, proprietary API inside LibGfx, let's use
Core::AnonymousBuffer which already abstracts anon_fd and offers a
higher-level API too.
This commit is contained in:
Jean-Baptiste Boric 2021-05-24 12:24:38 +02:00 committed by Andreas Kling
parent de395a3df2
commit e4394b1605
5 changed files with 41 additions and 75 deletions

View file

@ -23,7 +23,6 @@
#include <LibGUI/WindowServerConnection.h> #include <LibGUI/WindowServerConnection.h>
#include <LibGfx/Bitmap.h> #include <LibGfx/Bitmap.h>
#include <fcntl.h> #include <fcntl.h>
#include <serenity.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
@ -744,7 +743,7 @@ void Window::set_hovered_widget(Widget* widget)
void Window::set_current_backing_store(WindowBackingStore& backing_store, bool flush_immediately) void Window::set_current_backing_store(WindowBackingStore& backing_store, bool flush_immediately)
{ {
auto& bitmap = backing_store.bitmap(); auto& bitmap = backing_store.bitmap();
WindowServerConnection::the().set_window_backing_store(m_window_id, 32, bitmap.pitch(), bitmap.anon_fd(), backing_store.serial(), bitmap.has_alpha_channel(), bitmap.size(), flush_immediately); WindowServerConnection::the().set_window_backing_store(m_window_id, 32, bitmap.pitch(), bitmap.anonymous_buffer().fd(), backing_store.serial(), bitmap.has_alpha_channel(), bitmap.size(), flush_immediately);
} }
void Window::flip(const Vector<Gfx::IntRect, 32>& dirty_rects) void Window::flip(const Vector<Gfx::IntRect, 32>& dirty_rects)
@ -777,14 +776,14 @@ OwnPtr<WindowBackingStore> Window::create_backing_store(const Gfx::IntSize& size
size_t pitch = Gfx::Bitmap::minimum_pitch(size.width(), format); size_t pitch = Gfx::Bitmap::minimum_pitch(size.width(), format);
size_t size_in_bytes = size.height() * pitch; size_t size_in_bytes = size.height() * pitch;
auto anon_fd = anon_create(round_up_to_power_of_two(size_in_bytes, PAGE_SIZE), O_CLOEXEC); auto buffer = Core::AnonymousBuffer::create_with_size(round_up_to_power_of_two(size_in_bytes, PAGE_SIZE));
if (anon_fd < 0) { if (!buffer.is_valid()) {
perror("anon_create"); perror("anon_create");
return {}; return {};
} }
// FIXME: Plumb scale factor here eventually. // FIXME: Plumb scale factor here eventually.
auto bitmap = Gfx::Bitmap::create_with_anon_fd(format, anon_fd, size, 1, {}, Gfx::Bitmap::ShouldCloseAnonymousFile::No); auto bitmap = Gfx::Bitmap::create_with_anonymous_buffer(format, buffer, size, 1, {});
if (!bitmap) if (!bitmap)
return {}; return {};
return make<WindowBackingStore>(bitmap.release_nonnull()); return make<WindowBackingStore>(bitmap.release_nonnull());

View file

@ -26,10 +26,6 @@
#include <stdio.h> #include <stdio.h>
#include <sys/mman.h> #include <sys/mman.h>
#ifdef __serenity__
# include <serenity.h>
#endif
namespace Gfx { namespace Gfx {
struct BackingStore { struct BackingStore {
@ -85,7 +81,6 @@ RefPtr<Bitmap> Bitmap::create_purgeable(BitmapFormat format, const IntSize& size
return adopt_ref(*new Bitmap(format, size, scale_factor, Purgeable::Yes, backing_store.value())); return adopt_ref(*new Bitmap(format, size, scale_factor, Purgeable::Yes, backing_store.value()));
} }
#ifdef __serenity__
RefPtr<Bitmap> Bitmap::create_shareable(BitmapFormat format, const IntSize& size, int scale_factor) RefPtr<Bitmap> Bitmap::create_shareable(BitmapFormat format, const IntSize& size, int scale_factor)
{ {
if (size_would_overflow(format, size, scale_factor)) if (size_would_overflow(format, size, scale_factor))
@ -94,12 +89,11 @@ RefPtr<Bitmap> Bitmap::create_shareable(BitmapFormat format, const IntSize& size
const auto pitch = minimum_pitch(size.width() * scale_factor, format); const auto pitch = minimum_pitch(size.width() * scale_factor, format);
const auto data_size = size_in_bytes(pitch, size.height() * scale_factor); const auto data_size = size_in_bytes(pitch, size.height() * scale_factor);
auto anon_fd = anon_create(round_up_to_power_of_two(data_size, PAGE_SIZE), O_CLOEXEC); auto buffer = Core::AnonymousBuffer::create_with_size(round_up_to_power_of_two(data_size, PAGE_SIZE));
if (anon_fd < 0) if (!buffer.is_valid())
return nullptr; return nullptr;
return Bitmap::create_with_anon_fd(format, anon_fd, size, scale_factor, {}, ShouldCloseAnonymousFile::No); return Bitmap::create_with_anonymous_buffer(format, buffer, size, scale_factor, {});
} }
#endif
Bitmap::Bitmap(BitmapFormat format, const IntSize& size, int scale_factor, Purgeable purgeable, const BackingStore& backing_store) Bitmap::Bitmap(BitmapFormat format, const IntSize& size, int scale_factor, Purgeable purgeable, const BackingStore& backing_store)
: m_size(size) : m_size(size)
@ -194,33 +188,12 @@ static bool check_size(const IntSize& size, int scale_factor, BitmapFormat forma
return true; return true;
} }
RefPtr<Bitmap> Bitmap::create_with_anon_fd(BitmapFormat format, int anon_fd, const IntSize& size, int scale_factor, const Vector<RGBA32>& palette, ShouldCloseAnonymousFile should_close_anon_fd) RefPtr<Bitmap> Bitmap::create_with_anonymous_buffer(BitmapFormat format, Core::AnonymousBuffer buffer, const IntSize& size, int scale_factor, const Vector<RGBA32>& palette)
{ {
void* data = nullptr; if (size_would_overflow(format, size, scale_factor))
{ return nullptr;
// If ShouldCloseAnonymousFile::Yes, it's our responsibility to close 'anon_fd' no matter what.
ScopeGuard close_guard = [&] {
if (should_close_anon_fd == ShouldCloseAnonymousFile::Yes) {
int rc = close(anon_fd);
VERIFY(rc == 0);
anon_fd = -1;
}
};
if (size_would_overflow(format, size, scale_factor)) return adopt_ref(*new Bitmap(format, buffer, size, scale_factor, palette));
return nullptr;
const auto pitch = minimum_pitch(size.width() * scale_factor, format);
const auto data_size_in_bytes = size_in_bytes(pitch, size.height() * scale_factor);
data = mmap(nullptr, round_up_to_power_of_two(data_size_in_bytes, PAGE_SIZE), PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, anon_fd, 0);
if (data == MAP_FAILED) {
perror("mmap");
return nullptr;
}
}
return adopt_ref(*new Bitmap(format, anon_fd, size, scale_factor, data, palette));
} }
/// Read a bitmap as described by: /// Read a bitmap as described by:
@ -310,15 +283,14 @@ ByteBuffer Bitmap::serialize_to_byte_buffer() const
return buffer; return buffer;
} }
Bitmap::Bitmap(BitmapFormat format, int anon_fd, const IntSize& size, int scale_factor, void* data, const Vector<RGBA32>& palette) Bitmap::Bitmap(BitmapFormat format, Core::AnonymousBuffer buffer, const IntSize& size, int scale_factor, const Vector<RGBA32>& palette)
: m_size(size) : m_size(size)
, m_scale(scale_factor) , m_scale(scale_factor)
, m_data(data) , m_data(buffer.data<void>())
, m_pitch(minimum_pitch(size.width() * scale_factor, format)) , m_pitch(minimum_pitch(size.width() * scale_factor, format))
, m_format(format) , m_format(format)
, m_needs_munmap(true)
, m_purgeable(true) , m_purgeable(true)
, m_anon_fd(anon_fd) , m_buffer(buffer)
{ {
VERIFY(!is_indexed() || !palette.is_empty()); VERIFY(!is_indexed() || !palette.is_empty());
VERIFY(!size_would_overflow(format, size, scale_factor)); VERIFY(!size_would_overflow(format, size, scale_factor));
@ -522,21 +494,19 @@ RefPtr<Gfx::Bitmap> Bitmap::cropped(Gfx::IntRect crop) const
return new_bitmap; return new_bitmap;
} }
#ifdef __serenity__ RefPtr<Bitmap> Bitmap::to_bitmap_backed_by_anonymous_buffer() const
RefPtr<Bitmap> Bitmap::to_bitmap_backed_by_anon_fd() const
{ {
if (m_anon_fd != -1) if (m_buffer.is_valid())
return *this; return *this;
auto anon_fd = anon_create(round_up_to_power_of_two(size_in_bytes(), PAGE_SIZE), O_CLOEXEC); auto buffer = Core::AnonymousBuffer::create_with_size(round_up_to_power_of_two(size_in_bytes(), PAGE_SIZE));
if (anon_fd < 0) if (!buffer.is_valid())
return nullptr; return nullptr;
auto bitmap = Bitmap::create_with_anon_fd(m_format, anon_fd, size(), scale(), palette_to_vector(), ShouldCloseAnonymousFile::No); auto bitmap = Bitmap::create_with_anonymous_buffer(m_format, buffer, size(), scale(), palette_to_vector());
if (!bitmap) if (!bitmap)
return nullptr; return nullptr;
memcpy(bitmap->scanline(0), scanline(0), size_in_bytes()); memcpy(bitmap->scanline(0), scanline(0), size_in_bytes());
return bitmap; return bitmap;
} }
#endif
Bitmap::~Bitmap() Bitmap::~Bitmap()
{ {
@ -544,10 +514,6 @@ Bitmap::~Bitmap()
int rc = munmap(m_data, size_in_bytes()); int rc = munmap(m_data, size_in_bytes());
VERIFY(rc == 0); VERIFY(rc == 0);
} }
if (m_anon_fd != -1) {
int rc = close(m_anon_fd);
VERIFY(rc == 0);
}
m_data = nullptr; m_data = nullptr;
delete[] m_palette; delete[] m_palette;
} }
@ -602,15 +568,13 @@ void Bitmap::set_volatile()
return rc == 0; return rc == 0;
} }
#ifdef __serenity__
ShareableBitmap Bitmap::to_shareable_bitmap() const ShareableBitmap Bitmap::to_shareable_bitmap() const
{ {
auto bitmap = to_bitmap_backed_by_anon_fd(); auto bitmap = to_bitmap_backed_by_anonymous_buffer();
if (!bitmap) if (!bitmap)
return {}; return {};
return ShareableBitmap(*bitmap); return ShareableBitmap(*bitmap);
} }
#endif
Optional<BackingStore> Bitmap::allocate_backing_store(BitmapFormat format, const IntSize& size, int scale_factor, [[maybe_unused]] Purgeable purgeable) Optional<BackingStore> Bitmap::allocate_backing_store(BitmapFormat format, const IntSize& size, int scale_factor, [[maybe_unused]] Purgeable purgeable)
{ {

View file

@ -9,6 +9,7 @@
#include <AK/Forward.h> #include <AK/Forward.h>
#include <AK/RefCounted.h> #include <AK/RefCounted.h>
#include <AK/RefPtr.h> #include <AK/RefPtr.h>
#include <LibCore/AnonymousBuffer.h>
#include <LibGfx/Color.h> #include <LibGfx/Color.h>
#include <LibGfx/Forward.h> #include <LibGfx/Forward.h>
#include <LibGfx/Rect.h> #include <LibGfx/Rect.h>
@ -89,17 +90,12 @@ enum RotationDirection {
class Bitmap : public RefCounted<Bitmap> { class Bitmap : public RefCounted<Bitmap> {
public: public:
enum class ShouldCloseAnonymousFile {
No,
Yes,
};
static RefPtr<Bitmap> create(BitmapFormat, const IntSize&, int intrinsic_scale = 1); static RefPtr<Bitmap> create(BitmapFormat, const IntSize&, int intrinsic_scale = 1);
static RefPtr<Bitmap> create_shareable(BitmapFormat, const IntSize&, int intrinsic_scale = 1); static RefPtr<Bitmap> create_shareable(BitmapFormat, const IntSize&, int intrinsic_scale = 1);
static RefPtr<Bitmap> create_purgeable(BitmapFormat, const IntSize&, int intrinsic_scale = 1); static RefPtr<Bitmap> create_purgeable(BitmapFormat, const IntSize&, int intrinsic_scale = 1);
static RefPtr<Bitmap> create_wrapper(BitmapFormat, const IntSize&, int intrinsic_scale, size_t pitch, void*); static RefPtr<Bitmap> create_wrapper(BitmapFormat, const IntSize&, int intrinsic_scale, size_t pitch, void*);
static RefPtr<Bitmap> load_from_file(String const& path, int scale_factor = 1); static RefPtr<Bitmap> load_from_file(String const& path, int scale_factor = 1);
static RefPtr<Bitmap> create_with_anon_fd(BitmapFormat, int anon_fd, const IntSize&, int intrinsic_scale, const Vector<RGBA32>& palette, ShouldCloseAnonymousFile); static RefPtr<Bitmap> create_with_anonymous_buffer(BitmapFormat, Core::AnonymousBuffer, const IntSize&, int intrinsic_scale, const Vector<RGBA32>& palette);
static RefPtr<Bitmap> create_from_serialized_byte_buffer(ByteBuffer&& buffer); static RefPtr<Bitmap> create_from_serialized_byte_buffer(ByteBuffer&& buffer);
static bool is_path_a_supported_image_format(const StringView& path) static bool is_path_a_supported_image_format(const StringView& path)
{ {
@ -119,7 +115,7 @@ public:
RefPtr<Gfx::Bitmap> scaled(int sx, int sy) const; RefPtr<Gfx::Bitmap> scaled(int sx, int sy) const;
RefPtr<Gfx::Bitmap> scaled(float sx, float sy) const; RefPtr<Gfx::Bitmap> scaled(float sx, float sy) const;
RefPtr<Gfx::Bitmap> cropped(Gfx::IntRect) const; RefPtr<Gfx::Bitmap> cropped(Gfx::IntRect) const;
RefPtr<Bitmap> to_bitmap_backed_by_anon_fd() const; RefPtr<Bitmap> to_bitmap_backed_by_anonymous_buffer() const;
ByteBuffer serialize_to_byte_buffer() const; ByteBuffer serialize_to_byte_buffer() const;
ShareableBitmap to_shareable_bitmap() const; ShareableBitmap to_shareable_bitmap() const;
@ -234,7 +230,8 @@ public:
void set_volatile(); void set_volatile();
[[nodiscard]] bool set_nonvolatile(); [[nodiscard]] bool set_nonvolatile();
int anon_fd() const { return m_anon_fd; } Core::AnonymousBuffer& anonymous_buffer() { return m_buffer; }
const Core::AnonymousBuffer& anonymous_buffer() const { return m_buffer; }
private: private:
enum class Purgeable { enum class Purgeable {
@ -243,7 +240,7 @@ private:
}; };
Bitmap(BitmapFormat, const IntSize&, int, Purgeable, const BackingStore&); Bitmap(BitmapFormat, const IntSize&, int, Purgeable, const BackingStore&);
Bitmap(BitmapFormat, const IntSize&, int, size_t pitch, void*); Bitmap(BitmapFormat, const IntSize&, int, size_t pitch, void*);
Bitmap(BitmapFormat, int anon_fd, const IntSize&, int, void*, const Vector<RGBA32>& palette); Bitmap(BitmapFormat, Core::AnonymousBuffer, const IntSize&, int, const Vector<RGBA32>& palette);
static Optional<BackingStore> allocate_backing_store(BitmapFormat, const IntSize&, int, Purgeable); static Optional<BackingStore> allocate_backing_store(BitmapFormat, const IntSize&, int, Purgeable);
@ -258,7 +255,7 @@ private:
bool m_needs_munmap { false }; bool m_needs_munmap { false };
bool m_purgeable { false }; bool m_purgeable { false };
bool m_volatile { false }; bool m_volatile { false };
int m_anon_fd { -1 }; Core::AnonymousBuffer m_buffer;
}; };
inline u8* Bitmap::scanline_u8(int y) inline u8* Bitmap::scanline_u8(int y)

View file

@ -14,7 +14,7 @@
namespace Gfx { namespace Gfx {
ShareableBitmap::ShareableBitmap(const Bitmap& bitmap) ShareableBitmap::ShareableBitmap(const Bitmap& bitmap)
: m_bitmap(bitmap.to_bitmap_backed_by_anon_fd()) : m_bitmap(bitmap.to_bitmap_backed_by_anonymous_buffer())
{ {
} }
@ -33,7 +33,7 @@ bool encode(Encoder& encoder, const Gfx::ShareableBitmap& shareable_bitmap)
if (!shareable_bitmap.is_valid()) if (!shareable_bitmap.is_valid())
return true; return true;
auto& bitmap = *shareable_bitmap.bitmap(); auto& bitmap = *shareable_bitmap.bitmap();
encoder << IPC::File(bitmap.anon_fd()); encoder << IPC::File(bitmap.anonymous_buffer().fd());
encoder << bitmap.size(); encoder << bitmap.size();
encoder << bitmap.scale(); encoder << bitmap.scale();
encoder << (u32)bitmap.format(); encoder << (u32)bitmap.format();
@ -73,7 +73,10 @@ bool decode(Decoder& decoder, Gfx::ShareableBitmap& shareable_bitmap)
if (!decoder.decode(palette)) if (!decoder.decode(palette))
return false; return false;
} }
auto bitmap = Gfx::Bitmap::create_with_anon_fd(bitmap_format, anon_file.take_fd(), size, scale, palette, Gfx::Bitmap::ShouldCloseAnonymousFile::Yes); auto buffer = Core::AnonymousBuffer::create_from_anon_fd(anon_file.take_fd(), Gfx::Bitmap::size_in_bytes(Gfx::Bitmap::minimum_pitch(size.width(), bitmap_format), size.height()));
if (!buffer.is_valid())
return false;
auto bitmap = Gfx::Bitmap::create_with_anonymous_buffer(bitmap_format, buffer, size, scale, palette);
if (!bitmap) if (!bitmap)
return false; return false;
shareable_bitmap = Gfx::ShareableBitmap { bitmap.release_nonnull(), Gfx::ShareableBitmap::ConstructWithKnownGoodBitmap }; shareable_bitmap = Gfx::ShareableBitmap { bitmap.release_nonnull(), Gfx::ShareableBitmap::ConstructWithKnownGoodBitmap };

View file

@ -20,7 +20,6 @@
#include <WindowServer/WindowManager.h> #include <WindowServer/WindowManager.h>
#include <WindowServer/WindowSwitcher.h> #include <WindowServer/WindowSwitcher.h>
#include <errno.h> #include <errno.h>
#include <serenity.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
@ -587,13 +586,17 @@ void ClientConnection::set_window_backing_store(i32 window_id, [[maybe_unused]]
window.swap_backing_stores(); window.swap_backing_stores();
} else { } else {
// FIXME: Plumb scale factor here eventually. // FIXME: Plumb scale factor here eventually.
auto backing_store = Gfx::Bitmap::create_with_anon_fd( Core::AnonymousBuffer buffer = Core::AnonymousBuffer::create_from_anon_fd(anon_file.take_fd(), pitch * size.height());
if (!buffer.is_valid()) {
did_misbehave("SetWindowBackingStore: Failed to create anonymous buffer for window backing store");
return;
}
auto backing_store = Gfx::Bitmap::create_with_anonymous_buffer(
has_alpha_channel ? Gfx::BitmapFormat::BGRA8888 : Gfx::BitmapFormat::BGRx8888, has_alpha_channel ? Gfx::BitmapFormat::BGRA8888 : Gfx::BitmapFormat::BGRx8888,
anon_file.take_fd(), buffer,
size, size,
1, 1,
{}, {});
Gfx::Bitmap::ShouldCloseAnonymousFile::Yes);
window.set_backing_store(move(backing_store), serial); window.set_backing_store(move(backing_store), serial);
} }