ImageDecoder: Pass decoded images as Gfx::Bitmap over IPC

Before this change, we were passing them as Gfx::ShareableBitmap. The
problem is that shareable bitmaps keep their underlying file descriptor
open, so that they can be shared again with someone else.

When a Gfx::Bitmap is decoded from an IPC message, the file descriptor
is closed and recovered immediately.

This fixes an issue where we'd accumulate one file descriptor for every
image decoded. This eventually led to descriptor starvation after enough
images were loaded and still referenced at the same time.
This commit is contained in:
Andreas Kling 2024-07-17 19:14:44 +02:00 committed by Andreas Kling
parent 9f1a853cc8
commit 166e603c5e
Notes: sideshowbarker 2024-07-18 23:47:04 +09:00
5 changed files with 9 additions and 9 deletions

View file

@ -57,7 +57,7 @@ NonnullRefPtr<Core::Promise<DecodedImage>> Client::decode_image(ReadonlyBytes en
return promise;
}
void Client::did_decode_image(i64 image_id, bool is_animated, u32 loop_count, Vector<Gfx::ShareableBitmap> const& bitmaps, Vector<u32> const& durations, Gfx::FloatPoint scale)
void Client::did_decode_image(i64 image_id, bool is_animated, u32 loop_count, Vector<Optional<NonnullRefPtr<Gfx::Bitmap>>> const& bitmaps, Vector<u32> const& durations, Gfx::FloatPoint scale)
{
VERIFY(!bitmaps.is_empty());
@ -74,13 +74,13 @@ void Client::did_decode_image(i64 image_id, bool is_animated, u32 loop_count, Ve
image.scale = scale;
image.frames.ensure_capacity(bitmaps.size());
for (size_t i = 0; i < bitmaps.size(); ++i) {
if (!bitmaps[i].is_valid()) {
if (!bitmaps[i].has_value()) {
dbgln("ImageDecoderClient: Invalid bitmap for request {} at index {}", image_id, i);
promise->reject(Error::from_string_literal("Invalid bitmap"));
return;
}
image.frames.empend(*bitmaps[i].bitmap(), durations[i]);
image.frames.empend(*bitmaps[i], durations[i]);
}
promise->resolve(move(image));

View file

@ -41,7 +41,7 @@ public:
private:
virtual void die() override;
virtual void did_decode_image(i64 image_id, bool is_animated, u32 loop_count, Vector<Gfx::ShareableBitmap> const& bitmaps, Vector<u32> const& durations, Gfx::FloatPoint scale) override;
virtual void did_decode_image(i64 image_id, bool is_animated, u32 loop_count, Vector<Optional<NonnullRefPtr<Gfx::Bitmap>>> const& bitmaps, Vector<u32> const& durations, Gfx::FloatPoint scale) override;
virtual void did_fail_to_decode_image(i64 image_id, String const& error_message) override;
HashMap<i64, NonnullRefPtr<Core::Promise<DecodedImage>>> m_pending_decoded_images;

View file

@ -75,16 +75,16 @@ Messages::ImageDecoderServer::ConnectNewClientsResponse ConnectionFromClient::co
return files;
}
static void decode_image_to_bitmaps_and_durations_with_decoder(Gfx::ImageDecoder const& decoder, Optional<Gfx::IntSize> ideal_size, Vector<Gfx::ShareableBitmap>& bitmaps, Vector<u32>& durations)
static void decode_image_to_bitmaps_and_durations_with_decoder(Gfx::ImageDecoder const& decoder, Optional<Gfx::IntSize> ideal_size, Vector<Optional<NonnullRefPtr<Gfx::Bitmap>>>& bitmaps, Vector<u32>& durations)
{
for (size_t i = 0; i < decoder.frame_count(); ++i) {
auto frame_or_error = decoder.frame(i, ideal_size);
if (frame_or_error.is_error()) {
bitmaps.append(Gfx::ShareableBitmap {});
bitmaps.append({});
durations.append(0);
} else {
auto frame = frame_or_error.release_value();
bitmaps.append(frame.image->to_shareable_bitmap());
bitmaps.append(frame.image.release_nonnull());
durations.append(frame.duration);
}
}

View file

@ -28,7 +28,7 @@ public:
bool is_animated = false;
u32 loop_count = 0;
Gfx::FloatPoint scale { 1, 1 };
Vector<Gfx::ShareableBitmap> bitmaps;
Vector<Optional<NonnullRefPtr<Gfx::Bitmap>>> bitmaps;
Vector<u32> durations;
};

View file

@ -2,6 +2,6 @@
endpoint ImageDecoderClient
{
did_decode_image(i64 image_id, bool is_animated, u32 loop_count, Vector<Gfx::ShareableBitmap> bitmaps, Vector<u32> durations, Gfx::FloatPoint scale) =|
did_decode_image(i64 image_id, bool is_animated, u32 loop_count, Vector<Optional<NonnullRefPtr<Gfx::Bitmap>>> bitmaps, Vector<u32> durations, Gfx::FloatPoint scale) =|
did_fail_to_decode_image(i64 image_id, String error_message) =|
}