| /* |
| * Copyright (C) 2020 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "RemoteRenderingBackendProxy.h" |
| |
| #if ENABLE(GPU_PROCESS) |
| |
| #include "DisplayListWriterHandle.h" |
| #include "GPUConnectionToWebProcess.h" |
| #include "ImageDataReference.h" |
| #include "PlatformRemoteImageBufferProxy.h" |
| #include "RemoteRenderingBackendMessages.h" |
| #include "RemoteRenderingBackendProxyMessages.h" |
| #include "SharedMemory.h" |
| #include "WebProcess.h" |
| |
| namespace WebKit { |
| |
| using namespace WebCore; |
| |
| std::unique_ptr<RemoteRenderingBackendProxy> RemoteRenderingBackendProxy::create() |
| { |
| return std::unique_ptr<RemoteRenderingBackendProxy>(new RemoteRenderingBackendProxy()); |
| } |
| |
| RemoteRenderingBackendProxy::RemoteRenderingBackendProxy() |
| { |
| connectToGPUProcess(); |
| } |
| |
| RemoteRenderingBackendProxy::~RemoteRenderingBackendProxy() |
| { |
| // Un-register itself as a MessageReceiver. |
| IPC::MessageReceiverMap& messageReceiverMap = WebProcess::singleton().ensureGPUProcessConnection().messageReceiverMap(); |
| messageReceiverMap.removeMessageReceiver(*this); |
| |
| // Release the RemoteRenderingBackend. |
| send(Messages::GPUConnectionToWebProcess::ReleaseRenderingBackend(m_renderingBackendIdentifier), 0); |
| } |
| |
| void RemoteRenderingBackendProxy::connectToGPUProcess() |
| { |
| auto& connection = WebProcess::singleton().ensureGPUProcessConnection(); |
| connection.addClient(*this); |
| connection.messageReceiverMap().addMessageReceiver(Messages::RemoteRenderingBackendProxy::messageReceiverName(), m_renderingBackendIdentifier.toUInt64(), *this); |
| |
| send(Messages::GPUConnectionToWebProcess::CreateRenderingBackend(m_renderingBackendIdentifier), 0); |
| } |
| |
| template<typename T> |
| static void recreateImageBuffer(RemoteRenderingBackendProxy& proxy, T& imageBuffer, RenderingResourceIdentifier resourceIdentifier, RenderingBackendIdentifier renderingBackendIdentifier) |
| { |
| imageBuffer.clearBackend(); |
| proxy.send(Messages::RemoteRenderingBackend::CreateImageBuffer(imageBuffer.size(), imageBuffer.renderingMode(), imageBuffer.resolutionScale(), imageBuffer.colorSpace(), imageBuffer.pixelFormat(), resourceIdentifier), renderingBackendIdentifier); |
| } |
| |
| void RemoteRenderingBackendProxy::reestablishGPUProcessConnection() |
| { |
| connectToGPUProcess(); |
| |
| for (auto& pair : m_remoteResourceCacheProxy.imageBuffers()) { |
| if (auto& baseImageBuffer = pair.value) { |
| if (is<AcceleratedRemoteImageBufferMappedProxy>(*baseImageBuffer)) |
| recreateImageBuffer(*this, downcast<AcceleratedRemoteImageBufferMappedProxy>(*baseImageBuffer), pair.key, m_renderingBackendIdentifier); |
| else if (is<AcceleratedRemoteImageBufferProxy>(*baseImageBuffer)) |
| recreateImageBuffer(*this, downcast<AcceleratedRemoteImageBufferProxy>(*baseImageBuffer), pair.key, m_renderingBackendIdentifier); |
| else |
| recreateImageBuffer(*this, downcast<UnacceleratedRemoteImageBufferProxy>(*baseImageBuffer), pair.key, m_renderingBackendIdentifier); |
| } |
| } |
| } |
| |
| void RemoteRenderingBackendProxy::gpuProcessConnectionDidClose(GPUProcessConnection& previousConnection) |
| { |
| previousConnection.removeClient(*this); |
| |
| m_identifiersOfReusableHandles.clear(); |
| m_identifiersOfHandlesAvailableForWriting.clear(); |
| m_sharedDisplayListHandles.clear(); |
| |
| reestablishGPUProcessConnection(); |
| } |
| |
| IPC::Connection* RemoteRenderingBackendProxy::messageSenderConnection() const |
| { |
| return &WebProcess::singleton().ensureGPUProcessConnection().connection(); |
| } |
| |
| uint64_t RemoteRenderingBackendProxy::messageSenderDestinationID() const |
| { |
| return m_renderingBackendIdentifier.toUInt64(); |
| } |
| |
| bool RemoteRenderingBackendProxy::waitForImageBufferBackendWasCreated() |
| { |
| Ref<IPC::Connection> connection = WebProcess::singleton().ensureGPUProcessConnection().connection(); |
| return connection->waitForAndDispatchImmediately<Messages::RemoteRenderingBackendProxy::ImageBufferBackendWasCreated>(m_renderingBackendIdentifier, 1_s, IPC::WaitForOption::InterruptWaitingIfSyncMessageArrives); |
| } |
| |
| bool RemoteRenderingBackendProxy::waitForDidFlush() |
| { |
| Ref<IPC::Connection> connection = WebProcess::singleton().ensureGPUProcessConnection().connection(); |
| return connection->waitForAndDispatchImmediately<Messages::RemoteRenderingBackendProxy::DidFlush>(m_renderingBackendIdentifier, 1_s, IPC::WaitForOption::InterruptWaitingIfSyncMessageArrives); |
| } |
| |
| RefPtr<ImageBuffer> RemoteRenderingBackendProxy::createImageBuffer(const FloatSize& size, RenderingMode renderingMode, float resolutionScale, ColorSpace colorSpace, PixelFormat pixelFormat) |
| { |
| RefPtr<ImageBuffer> imageBuffer; |
| |
| if (renderingMode == RenderingMode::Accelerated) { |
| // Unless DOM rendering is always enabled when any GPU process rendering is enabled, |
| // we need to create ImageBuffers for e.g. Canvas that are actually mapped into the |
| // Web Content process, so they can be painted into the tiles. |
| if (!WebProcess::singleton().shouldUseRemoteRenderingFor(RenderingPurpose::DOM)) |
| imageBuffer = AcceleratedRemoteImageBufferMappedProxy::create(size, renderingMode, resolutionScale, colorSpace, pixelFormat, *this); |
| else |
| imageBuffer = AcceleratedRemoteImageBufferProxy::create(size, renderingMode, resolutionScale, colorSpace, pixelFormat, *this); |
| } |
| |
| if (!imageBuffer) |
| imageBuffer = UnacceleratedRemoteImageBufferProxy::create(size, renderingMode, resolutionScale, colorSpace, pixelFormat, *this); |
| |
| if (imageBuffer) { |
| send(Messages::RemoteRenderingBackend::CreateImageBuffer(size, renderingMode, resolutionScale, colorSpace, pixelFormat, imageBuffer->renderingResourceIdentifier()), m_renderingBackendIdentifier); |
| return imageBuffer; |
| } |
| |
| return nullptr; |
| } |
| |
| RefPtr<ImageData> RemoteRenderingBackendProxy::getImageData(AlphaPremultiplication outputFormat, const IntRect& srcRect, RenderingResourceIdentifier renderingResourceIdentifier) |
| { |
| IPC::ImageDataReference imageDataReference; |
| sendSync(Messages::RemoteRenderingBackend::GetImageData(outputFormat, srcRect, renderingResourceIdentifier), Messages::RemoteRenderingBackend::GetImageData::Reply(imageDataReference), m_renderingBackendIdentifier, 1_s); |
| return imageDataReference.buffer(); |
| } |
| |
| void RemoteRenderingBackendProxy::submitDisplayList(const DisplayList::DisplayList& displayList, RenderingResourceIdentifier destinationBufferIdentifier) |
| { |
| Optional<std::pair<DisplayList::ItemBufferIdentifier, size_t>> identifierAndOffsetForWakeUpMessage; |
| bool isFirstHandle = true; |
| |
| displayList.forEachItemBuffer([&] (auto& handle) { |
| m_identifiersOfHandlesAvailableForWriting.add(handle.identifier); |
| |
| auto* sharedHandle = m_sharedDisplayListHandles.get(handle.identifier); |
| RELEASE_ASSERT_WITH_MESSAGE(sharedHandle, "%s failed to find shared display list", WTF_PRETTY_FUNCTION); |
| |
| bool unreadCountWasEmpty = sharedHandle->advance(handle.capacity) == handle.capacity; |
| if (isFirstHandle && unreadCountWasEmpty) |
| identifierAndOffsetForWakeUpMessage = {{ handle.identifier, handle.data - sharedHandle->data() }}; |
| |
| isFirstHandle = false; |
| }); |
| |
| if (identifierAndOffsetForWakeUpMessage) { |
| auto [identifier, offset] = *identifierAndOffsetForWakeUpMessage; |
| send(Messages::RemoteRenderingBackend::WakeUpAndApplyDisplayList(identifier, offset, destinationBufferIdentifier), m_renderingBackendIdentifier); |
| } |
| } |
| |
| void RemoteRenderingBackendProxy::cacheNativeImage(NativeImage& image) |
| { |
| send(Messages::RemoteRenderingBackend::CacheNativeImage(makeRef(image)), m_renderingBackendIdentifier); |
| } |
| |
| void RemoteRenderingBackendProxy::releaseRemoteResource(RenderingResourceIdentifier renderingResourceIdentifier) |
| { |
| send(Messages::RemoteRenderingBackend::ReleaseRemoteResource(renderingResourceIdentifier), m_renderingBackendIdentifier); |
| } |
| |
| void RemoteRenderingBackendProxy::imageBufferBackendWasCreated(const FloatSize& logicalSize, const IntSize& backendSize, float resolutionScale, ColorSpace colorSpace, PixelFormat pixelFormat, ImageBufferBackendHandle handle, RenderingResourceIdentifier renderingResourceIdentifier) |
| { |
| auto imageBuffer = m_remoteResourceCacheProxy.cachedImageBuffer(renderingResourceIdentifier); |
| if (!imageBuffer) |
| return; |
| |
| if (is<AcceleratedRemoteImageBufferMappedProxy>(*imageBuffer)) |
| downcast<AcceleratedRemoteImageBufferMappedProxy>(*imageBuffer).createBackend(logicalSize, backendSize, resolutionScale, colorSpace, pixelFormat, WTFMove(handle)); |
| else if (is<AcceleratedRemoteImageBufferProxy>(*imageBuffer)) |
| downcast<AcceleratedRemoteImageBufferProxy>(*imageBuffer).createBackend(logicalSize, backendSize, resolutionScale, colorSpace, pixelFormat, WTFMove(handle)); |
| else |
| downcast<UnacceleratedRemoteImageBufferProxy>(*imageBuffer).createBackend(logicalSize, backendSize, resolutionScale, colorSpace, pixelFormat, WTFMove(handle)); |
| } |
| |
| void RemoteRenderingBackendProxy::didFlush(DisplayList::FlushIdentifier flushIdentifier, RenderingResourceIdentifier renderingResourceIdentifier) |
| { |
| auto imageBuffer = m_remoteResourceCacheProxy.cachedImageBuffer(renderingResourceIdentifier); |
| if (!imageBuffer) |
| return; |
| |
| if (is<AcceleratedRemoteImageBufferMappedProxy>(*imageBuffer)) |
| downcast<AcceleratedRemoteImageBufferMappedProxy>(*imageBuffer).didFlush(flushIdentifier); |
| else if (is<AcceleratedRemoteImageBufferProxy>(*imageBuffer)) |
| downcast<AcceleratedRemoteImageBufferProxy>(*imageBuffer).didFlush(flushIdentifier); |
| else |
| downcast<UnacceleratedRemoteImageBufferProxy>(*imageBuffer).didFlush(flushIdentifier); |
| } |
| |
| void RemoteRenderingBackendProxy::updateReusableHandles() |
| { |
| for (auto identifier : m_identifiersOfHandlesAvailableForWriting) { |
| auto* handle = m_sharedDisplayListHandles.get(identifier); |
| if (!handle->resetWritableOffsetIfPossible()) |
| continue; |
| |
| if (m_identifiersOfReusableHandles.contains(identifier)) |
| continue; |
| |
| m_identifiersOfReusableHandles.append(identifier); |
| } |
| } |
| |
| DisplayList::ItemBufferHandle RemoteRenderingBackendProxy::createItemBuffer(size_t capacity, RenderingResourceIdentifier destinationBufferIdentifier) |
| { |
| updateReusableHandles(); |
| |
| while (!m_identifiersOfReusableHandles.isEmpty()) { |
| auto identifier = m_identifiersOfReusableHandles.first(); |
| auto* reusableHandle = m_sharedDisplayListHandles.get(identifier); |
| RELEASE_ASSERT_WITH_MESSAGE(reusableHandle, "%s failed to find shared display list", WTF_PRETTY_FUNCTION); |
| |
| if (m_identifiersOfHandlesAvailableForWriting.contains(identifier) && reusableHandle->availableCapacity() >= capacity) { |
| m_identifiersOfHandlesAvailableForWriting.remove(identifier); |
| return reusableHandle->createHandle(); |
| } |
| |
| m_identifiersOfReusableHandles.removeFirst(); |
| } |
| |
| static constexpr size_t defaultSharedItemBufferSize = 1 << 16; |
| static_assert(defaultSharedItemBufferSize > SharedDisplayListHandle::headerSize()); |
| |
| auto sharedMemory = SharedMemory::allocate(std::max(defaultSharedItemBufferSize, capacity + SharedDisplayListHandle::headerSize())); |
| if (!sharedMemory) |
| return { }; |
| |
| SharedMemory::Handle sharedMemoryHandle; |
| sharedMemory->createHandle(sharedMemoryHandle, SharedMemory::Protection::ReadWrite); |
| |
| auto identifier = DisplayList::ItemBufferIdentifier::generate(); |
| send(Messages::RemoteRenderingBackend::DidCreateSharedDisplayListHandle(identifier, { WTFMove(sharedMemoryHandle), sharedMemory->size() }, destinationBufferIdentifier), m_renderingBackendIdentifier); |
| |
| auto newHandle = DisplayListWriterHandle::create(identifier, sharedMemory.releaseNonNull()); |
| auto displayListHandle = newHandle->createHandle(); |
| |
| m_identifiersOfReusableHandles.append(identifier); |
| m_sharedDisplayListHandles.set(identifier, WTFMove(newHandle)); |
| |
| return displayListHandle; |
| } |
| |
| } // namespace WebKit |
| |
| #endif // ENABLE(GPU_PROCESS) |