diff --git a/Libraries/LibGfx/Bitmap.cpp b/Libraries/LibGfx/Bitmap.cpp index b5e8a8164c..581397dbb7 100644 --- a/Libraries/LibGfx/Bitmap.cpp +++ b/Libraries/LibGfx/Bitmap.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -44,6 +45,12 @@ namespace Gfx { +struct BackingStore { + void* data { nullptr }; + size_t pitch { 0 }; + size_t size_in_bytes { 0 }; +}; + size_t Bitmap::minimum_pitch(size_t width, BitmapFormat format) { size_t element_size; @@ -76,39 +83,32 @@ static bool size_would_overflow(BitmapFormat format, const IntSize& size) RefPtr Bitmap::create(BitmapFormat format, const IntSize& size) { - if (size_would_overflow(format, size)) + auto backing_store = Bitmap::allocate_backing_store(format, size, Purgeable::No); + if (!backing_store.has_value()) return nullptr; - return adopt(*new Bitmap(format, size, Purgeable::No)); + return adopt(*new Bitmap(format, size, Purgeable::No, backing_store.value())); } RefPtr Bitmap::create_purgeable(BitmapFormat format, const IntSize& size) { - if (size_would_overflow(format, size)) + auto backing_store = Bitmap::allocate_backing_store(format, size, Purgeable::Yes); + if (!backing_store.has_value()) return nullptr; - return adopt(*new Bitmap(format, size, Purgeable::Yes)); + return adopt(*new Bitmap(format, size, Purgeable::Yes, backing_store.value())); } -Bitmap::Bitmap(BitmapFormat format, const IntSize& size, Purgeable purgeable) +Bitmap::Bitmap(BitmapFormat format, const IntSize& size, Purgeable purgeable, const BackingStore& backing_store) : m_size(size) - , m_pitch(minimum_pitch(size.width(), format)) + , m_data(backing_store.data) + , m_pitch(backing_store.pitch) , m_format(format) , m_purgeable(purgeable == Purgeable::Yes) { ASSERT(!m_size.is_empty()); ASSERT(!size_would_overflow(format, size)); - allocate_palette_from_format(format, {}); -#ifdef __serenity__ - int map_flags = purgeable == Purgeable::Yes ? (MAP_PURGEABLE | MAP_PRIVATE) : (MAP_ANONYMOUS | MAP_PRIVATE); - m_data = mmap_with_name(nullptr, size_in_bytes(), PROT_READ | PROT_WRITE, map_flags, 0, 0, String::format("GraphicsBitmap [%dx%d]", width(), height()).characters()); -#else - int map_flags = (MAP_ANONYMOUS | MAP_PRIVATE); - m_data = mmap(nullptr, size_in_bytes(), PROT_READ | PROT_WRITE, map_flags, 0, 0); -#endif - if (m_data == MAP_FAILED) { - perror("mmap"); - ASSERT_NOT_REACHED(); - } ASSERT(m_data); + ASSERT(backing_store.size_in_bytes == size_in_bytes()); + allocate_palette_from_format(format, {}); m_needs_munmap = true; } @@ -336,6 +336,30 @@ ShareableBitmap Bitmap::to_shareable_bitmap(pid_t peer_pid) const return ShareableBitmap(*bitmap); } +Optional Bitmap::allocate_backing_store(BitmapFormat format, const IntSize& size, Purgeable purgeable) +{ + if (size_would_overflow(format, size)) + return {}; + + const auto pitch = minimum_pitch(size.width(), format); + const auto data_size_in_bytes = size_in_bytes(pitch, size.height()); + + void* data = nullptr; +#ifdef __serenity__ + int map_flags = purgeable == Purgeable::Yes ? (MAP_PURGEABLE | MAP_PRIVATE) : (MAP_ANONYMOUS | MAP_PRIVATE); + data = mmap_with_name(nullptr, data_size_in_bytes, PROT_READ | PROT_WRITE, map_flags, 0, 0, String::format("GraphicsBitmap [%dx%d]", size.width(), size.height()).characters()); +#else + UNUSED_PARAM(purgeable); + int map_flags = (MAP_ANONYMOUS | MAP_PRIVATE); + data = mmap(nullptr, data_size_in_bytes, PROT_READ | PROT_WRITE, map_flags, 0, 0); +#endif + if (data == MAP_FAILED) { + perror("mmap"); + return {}; + } + return { { data, pitch, data_size_in_bytes } }; +} + void Bitmap::allocate_palette_from_format(BitmapFormat format, const Vector& source_palette) { size_t size = palette_size(format); diff --git a/Libraries/LibGfx/Bitmap.h b/Libraries/LibGfx/Bitmap.h index 3a514543f5..66b42cf241 100644 --- a/Libraries/LibGfx/Bitmap.h +++ b/Libraries/LibGfx/Bitmap.h @@ -79,6 +79,8 @@ static StorageFormat determine_storage_format(BitmapFormat format) } } +struct BackingStore; + enum RotationDirection { Left, Right @@ -192,7 +194,8 @@ public: void set_mmap_name(const StringView&); - size_t size_in_bytes() const { return m_pitch * m_size.height(); } + static constexpr size_t size_in_bytes(size_t pitch, int height) { return pitch * height; } + size_t size_in_bytes() const { return size_in_bytes(m_pitch, height()); } Color palette_color(u8 index) const { return Color::from_rgba(m_palette[index]); } void set_palette_color(u8 index, Color color) { m_palette[index] = color.value(); } @@ -223,10 +226,12 @@ private: No, Yes }; - Bitmap(BitmapFormat, const IntSize&, Purgeable); + Bitmap(BitmapFormat, const IntSize&, Purgeable, const BackingStore&); Bitmap(BitmapFormat, const IntSize&, size_t pitch, void*); Bitmap(BitmapFormat, NonnullRefPtr&&, const IntSize&, const Vector& palette); + static Optional allocate_backing_store(BitmapFormat, const IntSize&, Purgeable); + void allocate_palette_from_format(BitmapFormat, const Vector& source_palette); IntSize m_size;