193
194 if (m_pendingWakeupInfo && m_pendingWakeupInfo->shouldPerformWakeup(imageBufferResourceIdentifier))
195 resumeFromPendingWakeupInformation();
196 }
197
198 RemoteRenderingBackend::ReplayerDelegate::ReplayerDelegate(WebCore::ImageBuffer& destination, RemoteRenderingBackend& remoteRenderingBackend, ProcessIdentifier webProcessIdentifier)
199 : m_destination(destination)
200 , m_remoteRenderingBackend(remoteRenderingBackend)
201 , m_webProcessIdentifier(webProcessIdentifier)
202 {
203 }
204
205 bool RemoteRenderingBackend::ReplayerDelegate::apply(WebCore::DisplayList::ItemHandle item, WebCore::GraphicsContext& graphicsContext)
206 {
207 auto apply = [&](auto&& destination) {
208 return destination.apply(item, graphicsContext);
209 };
210
211 if (m_destination.renderingMode() == RenderingMode::Accelerated)
212 return apply(static_cast<AcceleratedRemoteImageBuffer&>(m_destination));
213 return apply(static_cast<UnacceleratedRemoteImageBuffer&>(m_destination));
214 }
215
216 void RemoteRenderingBackend::ReplayerDelegate::didCreateMaskImageBuffer(WebCore::ImageBuffer& imageBuffer)
217 {
218 m_remoteRenderingBackend.didCreateMaskImageBuffer(imageBuffer);
219 }
220
221 void RemoteRenderingBackend::ReplayerDelegate::didResetMaskImageBuffer()
222 {
223 m_remoteRenderingBackend.didResetMaskImageBuffer();
224 }
225
226 void RemoteRenderingBackend::ReplayerDelegate::recordResourceUse(RenderingResourceIdentifier renderingResourceIdentifier)
227 {
228 m_remoteRenderingBackend.remoteResourceCache().recordResourceUse({ renderingResourceIdentifier, m_webProcessIdentifier });
229 }
230
231 DisplayList::ReplayResult RemoteRenderingBackend::submit(const DisplayList::DisplayList& displayList, ImageBuffer& destination)
232 {
233 if (displayList.isEmpty())
234 return { };
235
236 ReplayerDelegate replayerDelegate(destination, *this, m_gpuConnectionToWebProcess->webProcessIdentifier());
237
238 return WebCore::DisplayList::Replayer {
239 destination.context(),
240 displayList,
241 &remoteResourceCache().resourceHeap(),
242 m_currentMaskImageBuffer.get(),
243 &replayerDelegate
244 }.replay();
245 }
246
247 RefPtr<ImageBuffer> RemoteRenderingBackend::nextDestinationImageBufferAfterApplyingDisplayLists(ImageBuffer& initialDestination, size_t initialOffset, DisplayListReaderHandle& handle, GPUProcessWakeupReason reason, ProcessIdentifier webProcessIdentifier)
248 {
249 RefPtr destination { &initialDestination };
250 Ref handleProtector { handle };
251
252 auto offset = initialOffset;
253 size_t sizeToRead = 0;
254 do {
255 sizeToRead = handle.unreadBytes();
256 } while (!sizeToRead);
257
258 while (destination) {
259 auto displayList = handle.displayListForReading(offset, sizeToRead, *this);
260 MESSAGE_CHECK_WITH_RETURN_VALUE(displayList, nullptr, "Failed to map display list from shared memory");
261
262 #if !LOG_DISABLED
263 auto startTime = MonotonicTime::now();
264 #endif
265 auto result = submit(*displayList, *destination);
266 LOG_WITH_STREAM(SharedDisplayLists, stream << "Read [" << offset << ", " << offset + result.numberOfBytesRead << "]; Items[" << handle.identifier() << "] => Image(" << destination->renderingResourceIdentifier() << ") in " << MonotonicTime::now() - startTime);
267 MESSAGE_CHECK_WITH_RETURN_VALUE(result.reasonForStopping != DisplayList::StopReplayReason::InvalidItemOrExtent, nullptr, "Detected invalid display list item or extent");
268 MESSAGE_CHECK_WITH_RETURN_VALUE(result.reasonForStopping != DisplayList::StopReplayReason::OutOfMemory, nullptr, "Cound not allocate memory");
269
270 auto advanceResult = handle.advance(result.numberOfBytesRead);
271 MESSAGE_CHECK_WITH_RETURN_VALUE(advanceResult, nullptr, "Failed to advance display list reader handle");
272 sizeToRead = *advanceResult;
273
274 CheckedSize checkedOffset = offset;
275 checkedOffset += result.numberOfBytesRead;
276 MESSAGE_CHECK_WITH_RETURN_VALUE(!checkedOffset.hasOverflowed(), nullptr, "Overflowed when advancing shared display list handle offset");
277
278 offset = checkedOffset;
279 MESSAGE_CHECK_WITH_RETURN_VALUE(offset <= handle.sharedMemory().size(), nullptr, "Out-of-bounds offset into shared display list handle");
280
281 if (result.reasonForStopping == DisplayList::StopReplayReason::ChangeDestinationImageBuffer) {
282 destination = m_remoteResourceCache.cachedImageBuffer({ *result.nextDestinationImageBuffer, m_gpuConnectionToWebProcess->webProcessIdentifier() });
283 if (!destination) {
284 ASSERT(!m_pendingWakeupInfo);
285 m_pendingWakeupInfo = {{
286 handle.identifier(),
287 offset,
288 { *result.nextDestinationImageBuffer, webProcessIdentifier },
289 reason,
290 std::nullopt,
291 RemoteRenderingBackendState::WaitingForDestinationImageBuffer
292 }};
293 }
294 }
295
296 if (result.reasonForStopping == DisplayList::StopReplayReason::MissingCachedResource) {
297 m_pendingWakeupInfo = {{
298 handle.identifier(),
299 offset,
300 { destination->renderingResourceIdentifier(), webProcessIdentifier },
301 reason,
302 { { *result.missingCachedResourceIdentifier, webProcessIdentifier } },
303 RemoteRenderingBackendState::WaitingForCachedResource
304 }};
305 }
306
307 if (m_pendingWakeupInfo)
308 break;
309
310 if (!sizeToRead) {
311 if (reason != GPUProcessWakeupReason::ItemCountHysteresisExceeded)
312 break;
313
314 handle.startWaiting();
315 m_resumeDisplayListSemaphore.waitFor(30_us);
316
317 auto stopWaitingResult = handle.stopWaiting();
318 MESSAGE_CHECK_WITH_RETURN_VALUE(stopWaitingResult, nullptr, "Invalid waiting status detected when resuming display list processing");
319
320 auto resumeReadingInfo = stopWaitingResult.value();
321 if (!resumeReadingInfo)
322 break;
323
324 sizeToRead = handle.unreadBytes();
325 MESSAGE_CHECK_WITH_RETURN_VALUE(sizeToRead, nullptr, "No unread bytes when resuming display list processing");
326
327 auto newDestinationIdentifier = makeObjectIdentifier<RenderingResourceIdentifierType>(resumeReadingInfo->destination);
328 MESSAGE_CHECK_WITH_RETURN_VALUE(newDestinationIdentifier.isValid(), nullptr, "Invalid image buffer destination when resuming display list processing");
329
330 destination = m_remoteResourceCache.cachedImageBuffer({ newDestinationIdentifier, m_gpuConnectionToWebProcess->webProcessIdentifier() });
331 MESSAGE_CHECK_WITH_RETURN_VALUE(destination, nullptr, "Missing image buffer destination when resuming display list processing");
332
333 offset = resumeReadingInfo->offset;
334 }
335 }
336
337 return destination;
338 }
339
340 void RemoteRenderingBackend::wakeUpAndApplyDisplayList(const GPUProcessWakeupMessageArguments& arguments)
341 {
342 // Immediately turn the RenderingResourceIdentifier (which is error-prone) to a QualifiedRenderingResourceIdentifier,
343 // and use a helper function to make sure that don't accidentally use the RenderingResourceIdentifier (because the helper function can't see it).
344 wakeUpAndApplyDisplayListWithQualifiedIdentifier(arguments.itemBufferIdentifier, arguments.offset, { arguments.destinationImageBufferIdentifier, m_gpuConnectionToWebProcess->webProcessIdentifier() }, arguments.reason);
345 }
346
347 void RemoteRenderingBackend::wakeUpAndApplyDisplayListWithQualifiedIdentifier(WebCore::DisplayList::ItemBufferIdentifier itemBufferIdentifier, uint64_t offset, QualifiedRenderingResourceIdentifier destinationImageBufferIdentifier, GPUProcessWakeupReason reason)
348 {
349 ASSERT(!RunLoop::isMain());
350
351 TraceScope tracingScope(WakeUpAndApplyDisplayListStart, WakeUpAndApplyDisplayListEnd);
352
353 updateLastKnownState(RemoteRenderingBackendState::BeganReplayingDisplayList);
354
355 RefPtr destinationImageBuffer = m_remoteResourceCache.cachedImageBuffer(destinationImageBufferIdentifier);
356 MESSAGE_CHECK(destinationImageBuffer, "Missing destination image buffer");
357
358 auto initialHandle = m_sharedDisplayListHandles.get(itemBufferIdentifier);
359 MESSAGE_CHECK(initialHandle, "Missing initial shared display list handle");
360
361 LOG_WITH_STREAM(SharedDisplayLists, stream << "Waking up to Items[" << itemBufferIdentifier << "] => Image(" << destinationImageBufferIdentifier.object() << ") at " << offset);
362 destinationImageBuffer = nextDestinationImageBufferAfterApplyingDisplayLists(*destinationImageBuffer, offset, *initialHandle, reason, m_gpuConnectionToWebProcess->webProcessIdentifier());
363
364 // FIXME: All the callers pass m_pendingWakeupInfo's fields so the body of this function should just be this loop.
365 while (destinationImageBuffer && m_pendingWakeupInfo) {
366 if (m_pendingWakeupInfo->missingCachedResourceIdentifier)
367 break;
368
369 auto nextHandle = m_sharedDisplayListHandles.get(m_pendingWakeupInfo->itemBufferIdentifier);
370 if (!nextHandle) {
371 // If the handle identifier is currently unknown, wait until the GPU process receives an
372 // IPC message with a shared memory handle to the next item buffer.
373 break;
374 }
375
376 // Otherwise, continue reading the next display list item buffer from the start.
377 auto offset = m_pendingWakeupInfo->offset;
378 auto reason = m_pendingWakeupInfo->reason;
379 m_pendingWakeupInfo = std::nullopt;
380 destinationImageBuffer = nextDestinationImageBufferAfterApplyingDisplayLists(*destinationImageBuffer, offset, *nextHandle, reason, m_gpuConnectionToWebProcess->webProcessIdentifier());
381 }
382 LOG_WITH_STREAM(SharedDisplayLists, stream << "Going back to sleep.");
383
384 if (m_pendingWakeupInfo)
385 updateLastKnownState(m_pendingWakeupInfo->state);
386 else
387 updateLastKnownState(RemoteRenderingBackendState::FinishedReplayingDisplayList);
388 }
389
390 void RemoteRenderingBackend::setNextItemBufferToRead(DisplayList::ItemBufferIdentifier identifier, QualifiedRenderingResourceIdentifier destinationIdentifier)
391 {
392 m_pendingWakeupInfo = {{
393 identifier,
394 SharedDisplayListHandle::headerSize(),
395 destinationIdentifier,
396 GPUProcessWakeupReason::Unspecified,
397 std::nullopt,
398 RemoteRenderingBackendState::WaitingForItemBuffer
399 }};