Pārlūkot izejas kodu

LibWeb+LibImageDecoderClient: Reuse ImageDecoder service process

The overhead from spawning a new ImageDecoder for every decoding job is
way too large and causing other problems as well (#5421)

Let's keep the same decoder open and reuse it as long as it's working.
Andreas Kling 4 gadi atpakaļ
vecāks
revīzija
3b9f110161

+ 6 - 0
Userland/Libraries/LibImageDecoderClient/Client.cpp

@@ -35,6 +35,12 @@ Client::Client()
     handshake();
 }
 
+void Client::die()
+{
+    if (on_death)
+        on_death();
+}
+
 void Client::handshake()
 {
     send_sync<Messages::ImageDecoderServer::Greet>();

+ 5 - 1
Userland/Libraries/LibImageDecoderClient/Client.h

@@ -44,7 +44,7 @@ struct DecodedImage {
     Vector<Frame> frames;
 };
 
-class Client
+class Client final
     : public IPC::ServerConnection<ImageDecoderClientEndpoint, ImageDecoderServerEndpoint>
     , public ImageDecoderClientEndpoint {
     C_OBJECT(Client);
@@ -54,9 +54,13 @@ public:
 
     Optional<DecodedImage> decode_image(const ByteBuffer&);
 
+    Function<void()> on_death;
+
 private:
     Client();
 
+    virtual void die() override;
+
     virtual void handle(const Messages::ImageDecoderClient::Dummy&) override;
 };
 

+ 15 - 2
Userland/Libraries/LibWeb/Loader/ImageResource.cpp

@@ -48,6 +48,18 @@ int ImageResource::frame_duration(size_t frame_index) const
     return m_decoded_frames[frame_index].duration;
 }
 
+static ImageDecoderClient::Client& image_decoder_client()
+{
+    static RefPtr<ImageDecoderClient::Client> image_decoder_client;
+    if (!image_decoder_client) {
+        image_decoder_client = ImageDecoderClient::Client::construct();
+        image_decoder_client->on_death = [&] {
+            image_decoder_client = nullptr;
+        };
+    }
+    return *image_decoder_client;
+}
+
 void ImageResource::decode_if_needed() const
 {
     if (!has_encoded_data())
@@ -59,8 +71,9 @@ void ImageResource::decode_if_needed() const
     if (!m_decoded_frames.is_empty())
         return;
 
-    auto image_decoder_client = ImageDecoderClient::Client::construct();
-    auto image = image_decoder_client->decode_image(encoded_data());
+    NonnullRefPtr decoder = image_decoder_client();
+    auto image = decoder->decode_image(encoded_data());
+
     if (image.has_value()) {
         m_loop_count = image.value().loop_count;
         m_animated = image.value().is_animated;