Bug 1803984 - Add tests for the interaction between speculative preloading and module...
[gecko.git] / gfx / layers / CanvasDrawEventRecorder.h
blob30bb028f4d8281ca9ab18b66ae3f8c5bbea69b80
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_layers_CanvasDrawEventRecorder_h
8 #define mozilla_layers_CanvasDrawEventRecorder_h
10 #include "mozilla/gfx/DrawEventRecorder.h"
11 #include "mozilla/ipc/CrossProcessSemaphore.h"
12 #include "mozilla/ipc/SharedMemoryBasic.h"
14 namespace mozilla {
15 namespace layers {
17 class CanvasEventRingBuffer final : public gfx::EventRingBuffer {
18 public:
19 /**
20 * WriterServices allows consumers of CanvasEventRingBuffer to provide
21 * functions required by the write side of a CanvasEventRingBuffer without
22 * introducing unnecessary dependencies on IPC code.
24 class WriterServices {
25 public:
26 virtual ~WriterServices() = default;
28 /**
29 * @returns true if the reader of the CanvasEventRingBuffer has permanently
30 * stopped processing, otherwise returns false.
32 virtual bool ReaderClosed() = 0;
34 /**
35 * Causes the reader to resume processing when it is in a stopped state.
37 virtual void ResumeReader() = 0;
40 /**
41 * ReaderServices allows consumers of CanvasEventRingBuffer to provide
42 * functions required by the read side of a CanvasEventRingBuffer without
43 * introducing unnecessary dependencies on IPC code.
45 class ReaderServices {
46 public:
47 virtual ~ReaderServices() = default;
49 /**
50 * @returns true if the writer of the CanvasEventRingBuffer has permanently
51 * stopped processing, otherwise returns false.
53 virtual bool WriterClosed() = 0;
56 CanvasEventRingBuffer() {}
58 /**
59 * Initialize the write side of a CanvasEventRingBuffer returning handles to
60 * the shared memory for the buffer and the two semaphores for waiting in the
61 * reader and the writer.
63 * @param aOtherPid process ID to share the handles to
64 * @param aReadHandle handle to the shared memory for the buffer
65 * @param aReaderSem reading blocked semaphore
66 * @param aWriterSem writing blocked semaphore
67 * @param aWriterServices provides functions required by the writer
68 * @returns true if initialization succeeds
70 bool InitWriter(base::ProcessId aOtherPid,
71 ipc::SharedMemoryBasic::Handle* aReadHandle,
72 CrossProcessSemaphoreHandle* aReaderSem,
73 CrossProcessSemaphoreHandle* aWriterSem,
74 UniquePtr<WriterServices> aWriterServices);
76 /**
77 * Initialize the read side of a CanvasEventRingBuffer.
79 * @param aReadHandle handle to the shared memory for the buffer
80 * @param aReaderSem reading blocked semaphore
81 * @param aWriterSem writing blocked semaphore
82 * @param aReaderServices provides functions required by the reader
83 * @returns true if initialization succeeds
85 bool InitReader(ipc::SharedMemoryBasic::Handle aReadHandle,
86 CrossProcessSemaphoreHandle aReaderSem,
87 CrossProcessSemaphoreHandle aWriterSem,
88 UniquePtr<ReaderServices> aReaderServices);
90 bool good() const final { return mGood; }
92 bool WriterFailed() const { return mWrite->state == State::Failed; }
94 void SetIsBad() final {
95 mGood = false;
96 mRead->state = State::Failed;
99 void write(const char* const aData, const size_t aSize) final;
101 bool HasDataToRead();
104 * This will put the reader into a stopped state if there is no more data to
105 * read. If this returns false the caller is responsible for continuing
106 * translation at a later point. If it returns false the writer will start the
107 * translation again when more data is written.
109 * @returns true if stopped
111 bool StopIfEmpty();
114 * Waits for data to become available. This will wait for aTimeout duration
115 * aRetryCount number of times, checking to see if the other side is closed in
116 * between each one.
118 * @param aTimeout duration to wait
119 * @param aRetryCount number of times to retry
120 * @returns true if data is available to read.
122 bool WaitForDataToRead(TimeDuration aTimeout, int32_t aRetryCount);
124 int32_t ReadNextEvent();
126 void read(char* const aOut, const size_t aSize) final;
129 * Writes a checkpoint event to the buffer.
131 * @returns the write count after the checkpoint has been written
133 uint32_t CreateCheckpoint();
136 * Waits until the given checkpoint has been read from the buffer.
138 * @params aCheckpoint the checkpoint to wait for
139 * @params aTimeout duration to wait while reader is not active
140 * @returns true if the checkpoint was reached, false if the reader is closed
141 * or we timeout.
143 bool WaitForCheckpoint(uint32_t aCheckpoint);
146 * Used to send data back to the writer. This is done through the same shared
147 * memory so the writer must wait and read the response after it has submitted
148 * the event that uses this.
150 * @param aData the data to be written back to the writer
151 * @param aSize the number of chars to write
153 void ReturnWrite(const char* aData, size_t aSize);
156 * Used to read data sent back from the reader via ReturnWrite. This is done
157 * through the same shared memory so the writer must wait until all expected
158 * data is read before writing new events to the buffer.
160 * @param aOut the pointer to read into
161 * @param aSize the number of chars to read
163 void ReturnRead(char* aOut, size_t aSize);
165 protected:
166 bool WaitForAndRecalculateAvailableSpace() final;
167 void UpdateWriteTotalsBy(uint32_t aCount) final;
169 private:
170 enum class State : uint32_t {
171 Processing,
174 * This is the important state to make sure the other side signals or starts
175 * us as soon as data or space is available. We set AboutToWait first and
176 * then re-check the condition. If we went straight to Waiting or Stopped
177 * then in between the last check and setting the state, the other side
178 * could have used all available data or space and never have signaled us
179 * because it didn't know we were about to wait, causing a deadlock.
180 * While we are in this state, the other side must wait until we resolve the
181 * AboutToWait state to one of the other states and then signal or start us
182 * if it needs to.
184 AboutToWait,
185 Waiting,
186 Stopped,
187 Failed,
190 struct ReadFooter {
191 Atomic<uint32_t> count;
192 Atomic<uint32_t> returnCount;
193 Atomic<State> state;
196 struct WriteFooter {
197 Atomic<uint32_t> count;
198 Atomic<uint32_t> returnCount;
199 Atomic<uint32_t> requiredDifference;
200 Atomic<State> state;
203 CanvasEventRingBuffer(const CanvasEventRingBuffer&) = delete;
204 void operator=(const CanvasEventRingBuffer&) = delete;
206 void IncrementWriteCountBy(uint32_t aCount);
208 bool WaitForReadCount(uint32_t aReadCount, TimeDuration aTimeout);
210 bool WaitForAndRecalculateAvailableData();
212 void UpdateReadTotalsBy(uint32_t aCount);
213 void IncrementReadCountBy(uint32_t aCount);
215 void CheckAndSignalReader();
217 void CheckAndSignalWriter();
219 uint32_t WaitForBytesToWrite();
221 uint32_t WaitForBytesToRead();
223 RefPtr<ipc::SharedMemoryBasic> mSharedMemory;
224 UniquePtr<CrossProcessSemaphore> mReaderSemaphore;
225 UniquePtr<CrossProcessSemaphore> mWriterSemaphore;
226 UniquePtr<WriterServices> mWriterServices;
227 UniquePtr<ReaderServices> mReaderServices;
228 char* mBuf = nullptr;
229 uint32_t mOurCount = 0;
230 WriteFooter* mWrite = nullptr;
231 ReadFooter* mRead = nullptr;
232 bool mGood = false;
235 class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate {
236 public:
237 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(CanvasDrawEventRecorder, final)
238 explicit CanvasDrawEventRecorder(){};
240 bool Init(base::ProcessId aOtherPid, ipc::SharedMemoryBasic::Handle* aHandle,
241 CrossProcessSemaphoreHandle* aReaderSem,
242 CrossProcessSemaphoreHandle* aWriterSem,
243 UniquePtr<CanvasEventRingBuffer::WriterServices> aWriterServices) {
244 return mOutputStream.InitWriter(aOtherPid, aHandle, aReaderSem, aWriterSem,
245 std::move(aWriterServices));
248 void RecordEvent(const gfx::RecordedEvent& aEvent) final {
249 if (!mOutputStream.good()) {
250 return;
253 aEvent.RecordToStream(mOutputStream);
256 void StoreSourceSurfaceRecording(gfx::SourceSurface* aSurface,
257 const char* aReason) final;
259 void Flush() final {}
261 void ReturnRead(char* aOut, size_t aSize) {
262 mOutputStream.ReturnRead(aOut, aSize);
265 uint32_t CreateCheckpoint() { return mOutputStream.CreateCheckpoint(); }
268 * Waits until the given checkpoint has been read by the translator.
270 * @params aCheckpoint the checkpoint to wait for
271 * @returns true if the checkpoint was reached, false if the reader is closed
272 * or we timeout.
274 bool WaitForCheckpoint(uint32_t aCheckpoint) {
275 return mOutputStream.WaitForCheckpoint(aCheckpoint);
278 private:
279 CanvasEventRingBuffer mOutputStream;
282 } // namespace layers
283 } // namespace mozilla
285 #endif // mozilla_layers_CanvasDrawEventRecorder_h