mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 07:07:45 +00:00
LibGfx: Saner memory usage of indexed bitmaps
Indexed bitmaps used to allocate four times the required amount of memory. Also, we should acknowledge that the underlying data is not always RGBA32, and instead cast it only when the true type is known.
This commit is contained in:
parent
d6673b384e
commit
9c3a33762b
5 changed files with 89 additions and 86 deletions
|
@ -56,6 +56,29 @@ enum class BitmapFormat {
|
|||
RGBA32,
|
||||
};
|
||||
|
||||
enum class StorageFormat {
|
||||
Indexed8,
|
||||
RGB32,
|
||||
RGBA32,
|
||||
};
|
||||
|
||||
static StorageFormat determine_storage_format(BitmapFormat format)
|
||||
{
|
||||
switch (format) {
|
||||
case BitmapFormat::RGB32:
|
||||
return StorageFormat::RGB32;
|
||||
case BitmapFormat::RGBA32:
|
||||
return StorageFormat::RGBA32;
|
||||
case BitmapFormat::Indexed1:
|
||||
case BitmapFormat::Indexed2:
|
||||
case BitmapFormat::Indexed4:
|
||||
case BitmapFormat::Indexed8:
|
||||
return StorageFormat::Indexed8;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
enum RotationDirection {
|
||||
Left,
|
||||
Right
|
||||
|
@ -65,7 +88,7 @@ class Bitmap : public RefCounted<Bitmap> {
|
|||
public:
|
||||
static RefPtr<Bitmap> create(BitmapFormat, const IntSize&);
|
||||
static RefPtr<Bitmap> create_purgeable(BitmapFormat, const IntSize&);
|
||||
static RefPtr<Bitmap> create_wrapper(BitmapFormat, const IntSize&, size_t pitch, RGBA32*);
|
||||
static RefPtr<Bitmap> create_wrapper(BitmapFormat, const IntSize&, size_t pitch, void*);
|
||||
static RefPtr<Bitmap> load_from_file(const StringView& path);
|
||||
static RefPtr<Bitmap> create_with_shared_buffer(BitmapFormat, NonnullRefPtr<SharedBuffer>&&, const IntSize&);
|
||||
static RefPtr<Bitmap> create_with_shared_buffer(BitmapFormat, NonnullRefPtr<SharedBuffer>&&, const IntSize&, const Vector<RGBA32>& palette);
|
||||
|
@ -153,6 +176,8 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
static size_t minimum_pitch(size_t width, BitmapFormat);
|
||||
|
||||
unsigned bpp() const
|
||||
{
|
||||
return bpp_for_format(m_format);
|
||||
|
@ -170,31 +195,17 @@ public:
|
|||
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(); }
|
||||
|
||||
template<BitmapFormat>
|
||||
Color get_pixel(int x, int y) const
|
||||
{
|
||||
(void)x;
|
||||
(void)y;
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
template<StorageFormat>
|
||||
Color get_pixel(int x, int y) const;
|
||||
Color get_pixel(int x, int y) const;
|
||||
|
||||
Color get_pixel(const IntPoint& position) const
|
||||
{
|
||||
return get_pixel(position.x(), position.y());
|
||||
}
|
||||
|
||||
template<BitmapFormat>
|
||||
void set_pixel(int x, int y, Color)
|
||||
{
|
||||
(void)x;
|
||||
(void)y;
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
template<StorageFormat>
|
||||
void set_pixel(int x, int y, Color);
|
||||
void set_pixel(int x, int y, Color);
|
||||
|
||||
void set_pixel(const IntPoint& position, Color color)
|
||||
{
|
||||
set_pixel(position.x(), position.y(), color);
|
||||
|
@ -211,13 +222,13 @@ private:
|
|||
Yes
|
||||
};
|
||||
Bitmap(BitmapFormat, const IntSize&, Purgeable);
|
||||
Bitmap(BitmapFormat, const IntSize&, size_t pitch, RGBA32*);
|
||||
Bitmap(BitmapFormat, const IntSize&, size_t pitch, void*);
|
||||
Bitmap(BitmapFormat, NonnullRefPtr<SharedBuffer>&&, const IntSize&, const Vector<RGBA32>& palette);
|
||||
|
||||
void allocate_palette_from_format(BitmapFormat, const Vector<RGBA32>& source_palette);
|
||||
|
||||
IntSize m_size;
|
||||
RGBA32* m_data { nullptr };
|
||||
void* m_data { nullptr };
|
||||
RGBA32* m_palette { nullptr };
|
||||
size_t m_pitch { 0 };
|
||||
BitmapFormat m_format { BitmapFormat::Invalid };
|
||||
|
@ -229,12 +240,12 @@ private:
|
|||
|
||||
inline u8* Bitmap::scanline_u8(int y)
|
||||
{
|
||||
return (u8*)m_data + (y * m_pitch);
|
||||
return reinterpret_cast<u8*>(m_data) + (y * m_pitch);
|
||||
}
|
||||
|
||||
inline const u8* Bitmap::scanline_u8(int y) const
|
||||
{
|
||||
return (const u8*)m_data + (y * m_pitch);
|
||||
return reinterpret_cast<const u8*>(m_data) + (y * m_pitch);
|
||||
}
|
||||
|
||||
inline RGBA32* Bitmap::scanline(int y)
|
||||
|
@ -248,86 +259,57 @@ inline const RGBA32* Bitmap::scanline(int y) const
|
|||
}
|
||||
|
||||
template<>
|
||||
inline Color Bitmap::get_pixel<BitmapFormat::RGB32>(int x, int y) const
|
||||
inline Color Bitmap::get_pixel<StorageFormat::RGB32>(int x, int y) const
|
||||
{
|
||||
return Color::from_rgb(scanline(y)[x]);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Color Bitmap::get_pixel<BitmapFormat::RGBA32>(int x, int y) const
|
||||
inline Color Bitmap::get_pixel<StorageFormat::RGBA32>(int x, int y) const
|
||||
{
|
||||
return Color::from_rgba(scanline(y)[x]);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Color Bitmap::get_pixel<BitmapFormat::Indexed1>(int x, int y) const
|
||||
{
|
||||
return Color::from_rgb(m_palette[scanline_u8(y)[x]]);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Color Bitmap::get_pixel<BitmapFormat::Indexed2>(int x, int y) const
|
||||
{
|
||||
return Color::from_rgb(m_palette[scanline_u8(y)[x]]);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Color Bitmap::get_pixel<BitmapFormat::Indexed4>(int x, int y) const
|
||||
{
|
||||
return Color::from_rgb(m_palette[scanline_u8(y)[x]]);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Color Bitmap::get_pixel<BitmapFormat::Indexed8>(int x, int y) const
|
||||
inline Color Bitmap::get_pixel<StorageFormat::Indexed8>(int x, int y) const
|
||||
{
|
||||
return Color::from_rgb(m_palette[scanline_u8(y)[x]]);
|
||||
}
|
||||
|
||||
inline Color Bitmap::get_pixel(int x, int y) const
|
||||
{
|
||||
switch (m_format) {
|
||||
case BitmapFormat::RGB32:
|
||||
return get_pixel<BitmapFormat::RGB32>(x, y);
|
||||
case BitmapFormat::RGBA32:
|
||||
return get_pixel<BitmapFormat::RGBA32>(x, y);
|
||||
case BitmapFormat::Indexed1:
|
||||
return get_pixel<BitmapFormat::Indexed1>(x, y);
|
||||
case BitmapFormat::Indexed2:
|
||||
return get_pixel<BitmapFormat::Indexed2>(x, y);
|
||||
case BitmapFormat::Indexed4:
|
||||
return get_pixel<BitmapFormat::Indexed4>(x, y);
|
||||
case BitmapFormat::Indexed8:
|
||||
return get_pixel<BitmapFormat::Indexed8>(x, y);
|
||||
switch (determine_storage_format(m_format)) {
|
||||
case StorageFormat::RGB32:
|
||||
return get_pixel<StorageFormat::RGB32>(x, y);
|
||||
case StorageFormat::RGBA32:
|
||||
return get_pixel<StorageFormat::RGBA32>(x, y);
|
||||
case StorageFormat::Indexed8:
|
||||
return get_pixel<StorageFormat::Indexed8>(x, y);
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void Bitmap::set_pixel<BitmapFormat::RGB32>(int x, int y, Color color)
|
||||
inline void Bitmap::set_pixel<StorageFormat::RGB32>(int x, int y, Color color)
|
||||
{
|
||||
scanline(y)[x] = color.value();
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void Bitmap::set_pixel<BitmapFormat::RGBA32>(int x, int y, Color color)
|
||||
inline void Bitmap::set_pixel<StorageFormat::RGBA32>(int x, int y, Color color)
|
||||
{
|
||||
scanline(y)[x] = color.value();
|
||||
scanline(y)[x] = color.value(); // drop alpha
|
||||
}
|
||||
|
||||
inline void Bitmap::set_pixel(int x, int y, Color color)
|
||||
{
|
||||
switch (m_format) {
|
||||
case BitmapFormat::RGB32:
|
||||
set_pixel<BitmapFormat::RGB32>(x, y, color);
|
||||
switch (determine_storage_format(m_format)) {
|
||||
case StorageFormat::RGB32:
|
||||
set_pixel<StorageFormat::RGB32>(x, y, color);
|
||||
break;
|
||||
case BitmapFormat::RGBA32:
|
||||
set_pixel<BitmapFormat::RGBA32>(x, y, color);
|
||||
case StorageFormat::RGBA32:
|
||||
set_pixel<StorageFormat::RGBA32>(x, y, color);
|
||||
break;
|
||||
case BitmapFormat::Indexed1:
|
||||
case BitmapFormat::Indexed2:
|
||||
case BitmapFormat::Indexed4:
|
||||
case BitmapFormat::Indexed8:
|
||||
case StorageFormat::Indexed8:
|
||||
ASSERT_NOT_REACHED();
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue