File: parkable_image.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (212 lines) | stat: -rw-r--r-- 8,908 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PARKABLE_IMAGE_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PARKABLE_IMAGE_H_

#include "base/containers/span.h"
#include "base/debug/stack_trace.h"
#include "base/feature_list.h"
#include "base/synchronization/lock.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "third_party/blink/public/platform/web_data.h"
#include "third_party/blink/renderer/platform/disk_data_metadata.h"
#include "third_party/blink/renderer/platform/image-decoders/rw_buffer.h"
#include "third_party/blink/renderer/platform/image-decoders/segment_reader.h"
#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"

namespace blink {

class SegmentReader;
class ParkableImageManager;
class ParkableImage;
class ParkableImageSegmentReader;

PLATFORM_EXPORT BASE_DECLARE_FEATURE(kDelayParkingImages);

// Implementation of ParkableImage. See ParkableImage below.
// We split ParkableImage like this because we want to avoid destroying the
// content of the ParkableImage on anything besides the main thread.
// See |ParkableImageManager::MaybeParkImages| for details on this.
class PLATFORM_EXPORT ParkableImageImpl final
    : public ThreadSafeRefCounted<ParkableImageImpl> {
 public:
  ParkableImageImpl& operator=(const ParkableImage&) = delete;
  ParkableImageImpl(const ParkableImage&) = delete;

  // Smallest encoded size that will actually be parked.
  static constexpr size_t kMinSizeToPark = 1024;  // 1 KiB
  // How long to wait before parking an image.
  //
  // Chosen arbitrarily, did not regress metrics in field trials in 2022. From
  // local experiments, images are typically only decoded once, to raster the
  // tile(s) they are a part of, then never used as long as the image decode
  // cache is not emptied and the tiles are not re-rasterized. This is set to
  // something longer than e.g. 1s in case there is a looping GIF for instance,
  // and/or the decoded image cache is too small.
  static constexpr base::TimeDelta kParkingDelay = base::Seconds(30);

 private:
  friend class ThreadSafeRefCounted<ParkableImageImpl>;
  template <typename T, typename... Args>
  friend scoped_refptr<T> base::MakeRefCounted(Args&&... args);
  friend class ParkableImageManager;
  friend class ParkableImage;
  friend class ParkableImageBaseTest;
  friend class ParkableImageSegmentReader;

  // |initial_capacity| reserves space in the internal buffer, if you know how
  // much data you'll be appending in advance.
  explicit ParkableImageImpl(size_t initial_capacity = 0);

  ~ParkableImageImpl();

  // Factory method to construct a ParkableImageImpl.
  static scoped_refptr<ParkableImageImpl> Create(size_t initial_capacity = 0);

  // Implementations of the methods of the same name from ParkableImage.
  void Freeze() LOCKS_EXCLUDED(lock_);
  void Append(WTF::SharedBuffer* buffer, size_t offset = 0)
      LOCKS_EXCLUDED(lock_);
  scoped_refptr<SharedBuffer> Data() LOCKS_EXCLUDED(lock_);
  void LockData() EXCLUSIVE_LOCKS_REQUIRED(lock_);
  void UnlockData() EXCLUSIVE_LOCKS_REQUIRED(lock_);
  size_t size() const;

  bool is_frozen() const { return !frozen_time_.is_null(); }

  bool ShouldReschedule() const LOCKS_EXCLUDED(lock_) {
    base::AutoLock lock(lock_);
    return TransientlyUnableToPark();
  }

  // Attempt to park to disk. Returns false if it cannot be parked right now for
  // whatever reason, true if we will _attempt_ to park it to disk.
  bool MaybePark(scoped_refptr<base::SingleThreadTaskRunner> task_runner)
      LOCKS_EXCLUDED(lock_);

  // Unpark the data from disk. This is blocking, on the same thread (since we
  // cannot expect to continue with anything that needs the data until we have
  // unparked it).
  void Unpark() EXCLUSIVE_LOCKS_REQUIRED(lock_);

  // Tries to write the data from |rw_buffer_| to disk. Then, if the data is
  // successfully written to disk, posts a task to discard |rw_buffer_|.
  static void WriteToDiskInBackground(
      scoped_refptr<ParkableImageImpl>,
      scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner)
      LOCKS_EXCLUDED(lock_);

  // Writes the data referred to by |on_disk_metadata| from disk into the
  // provided |buffer|.
  static size_t ReadFromDiskIntoBuffer(DiskDataMetadata* on_disk_metadata,
                                       base::span<uint8_t> buffer);

  // Attempt to discard the data. This should only be called after we've written
  // the data to disk. Fails if the image can not be parked at the time this is
  // called for whatever reason.
  void MaybeDiscardData() LOCKS_EXCLUDED(lock_);

  // Discards the data in |rw_buffer_|. Caller is responsible for making sure
  // this is only called when the image can be parked.
  void DiscardData() EXCLUSIVE_LOCKS_REQUIRED(lock_);

  // Only larger images are parked, see kMinSizeToPark for the threshold used.
  bool is_below_min_parking_size() const;

  // Returns whether the ParkableImageImpl is locked or not. See |Lock| and
  // |Unlock| for details.
  bool is_locked() const EXCLUSIVE_LOCKS_REQUIRED(lock_);
  bool is_on_disk() const EXCLUSIVE_LOCKS_REQUIRED(lock_) {
    return !rw_buffer_ && on_disk_metadata_;
  }
  // Whether or not a failure of trying to park the image now would be
  // transient (e.g. due to not being frozen) or not.
  bool TransientlyUnableToPark() const EXCLUSIVE_LOCKS_REQUIRED(lock_);

  bool CanParkNow() const EXCLUSIVE_LOCKS_REQUIRED(lock_);

  mutable base::Lock lock_;

  std::unique_ptr<RWBuffer> rw_buffer_ GUARDED_BY(lock_);

  std::unique_ptr<ReservedChunk> reserved_chunk_ GUARDED_BY(lock_);
  // Non-null iff we have the data from |rw_buffer_| saved to disk.
  std::unique_ptr<DiskDataMetadata> on_disk_metadata_ GUARDED_BY(lock_);
  // |size_| is only modified on the main thread.
  size_t size_ = 0;
  // |frozen_time_| is only modified on the main thread. |frozen_time_| is the
  // time we've frozen the ParkableImage, or a null value if it's not yet
  // frozen.
  base::TimeTicks frozen_time_;
  // Counts the number of Lock/Unlock calls. Incremented by Lock, decremented by
  // Unlock. The ParkableImageImpl is unlocked iff |lock_depth_| is 0, i.e.
  // we've called Lock and Unlock the same number of times.
  size_t lock_depth_ GUARDED_BY(lock_) = 0;
  bool background_task_in_progress_ GUARDED_BY(lock_) = false;
  bool used_ GUARDED_BY(lock_) = false;

  THREAD_CHECKER(thread_checker_);
};

// Wraps a RWBuffer containing encoded image data. This buffer can be written
// to/read from disk when not needed, to improve memory usage.
class PLATFORM_EXPORT ParkableImage final
    : public ThreadSafeRefCounted<ParkableImage> {
 public:
  // Factory method to construct a ParkableImage.
  static scoped_refptr<ParkableImage> Create(size_t initial_capacity = 0);

  // Creates a read-only snapshot of the ParkableImage. This can be used
  // from other threads.
  scoped_refptr<SegmentReader> MakeROSnapshot();

  // Freezes the ParkableImage. This changes the following:
  // (1) We are no longer allowed to mutate the internal buffer (e.g. via
  // Append);
  // (2) The image may now be parked to disk.
  void Freeze() LOCKS_EXCLUDED(impl_->lock_);

  // Appends data to the ParkableImage. Cannot be called after the ParkableImage
  // has been frozen. (see: Freeze())
  void Append(WTF::SharedBuffer* buffer, size_t offset = 0)
      LOCKS_EXCLUDED(impl_->lock_);

  // Returns a copy of the data stored in ParkableImage. Calling this will
  // unpark the image from disk if needed.
  scoped_refptr<SharedBuffer> Data() LOCKS_EXCLUDED(impl_->lock_);

  // Returns the size of the encoded image data stored in the ParkableImage. Can
  // be called even if the image is currently parked, and will not unpark it.
  size_t size() const;

  scoped_refptr<SegmentReader> CreateSegmentReader();

 private:
  friend class ThreadSafeRefCounted<ParkableImage>;
  template <typename T, typename... Args>
  friend scoped_refptr<T> base::MakeRefCounted(Args&&... args);
  friend class ParkableImageManager;
  friend class ParkableImageBaseTest;
  friend class ParkableImageSegmentReader;
  friend class ThreadSafeRefCounted<ParkableImageImpl>;

  explicit ParkableImage(size_t initial_capacity = 0);
  ~ParkableImage();

  // Locks and Unlocks the ParkableImageImpl. A locked ParkableImage cannot be
  // parked. Every call to Lock must have a corresponding call to Unlock.
  void LockData() EXCLUSIVE_LOCKS_REQUIRED(impl_->lock_);
  void UnlockData() EXCLUSIVE_LOCKS_REQUIRED(impl_->lock_);

  bool is_on_disk() const EXCLUSIVE_LOCKS_REQUIRED(impl_->lock_);

  scoped_refptr<ParkableImageImpl> impl_;
};

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_PARKABLE_IMAGE_H_