| /* |
| * Copyright (C) 2020-2022 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 "RemoteRenderingBackend.h" |
| |
| #if ENABLE(GPU_PROCESS) |
| |
| #include "BufferIdentifierSet.h" |
| #include "FilterReference.h" |
| #include "GPUConnectionToWebProcess.h" |
| #include "Logging.h" |
| #include "PlatformRemoteImageBuffer.h" |
| #include "QualifiedRenderingResourceIdentifier.h" |
| #include "RemoteDisplayListRecorderMessages.h" |
| #include "RemoteMediaPlayerManagerProxy.h" |
| #include "RemoteMediaPlayerProxy.h" |
| #include "RemoteRenderingBackendCreationParameters.h" |
| #include "RemoteRenderingBackendMessages.h" |
| #include "RemoteRenderingBackendProxyMessages.h" |
| #include "SwapBuffersDisplayRequirement.h" |
| #include "WebCoreArgumentCoders.h" |
| #include <WebCore/HTMLCanvasElement.h> |
| #include <wtf/CheckedArithmetic.h> |
| #include <wtf/StdLibExtras.h> |
| #include <wtf/SystemTracing.h> |
| |
| #if HAVE(IOSURFACE) |
| #include <WebCore/IOSurfacePool.h> |
| #endif |
| |
| #if ENABLE(IPC_TESTING_API) |
| #define WEB_PROCESS_TERMINATE_CONDITION !m_gpuConnectionToWebProcess->connection().ignoreInvalidMessageForTesting() |
| #else |
| #define WEB_PROCESS_TERMINATE_CONDITION true |
| #endif |
| |
| #define TERMINATE_WEB_PROCESS_WITH_MESSAGE(message) \ |
| if (WEB_PROCESS_TERMINATE_CONDITION) { \ |
| RELEASE_LOG_FAULT(IPC, "Requesting termination of web process %" PRIu64 " for reason: %" PUBLIC_LOG_STRING, m_gpuConnectionToWebProcess->webProcessIdentifier().toUInt64(), #message); \ |
| m_gpuConnectionToWebProcess->terminateWebProcess(); \ |
| } |
| |
| #define MESSAGE_CHECK(assertion, message) do { \ |
| if (UNLIKELY(!(assertion))) { \ |
| TERMINATE_WEB_PROCESS_WITH_MESSAGE(message); \ |
| return; \ |
| } \ |
| } while (0) |
| |
| #define MESSAGE_CHECK_WITH_RETURN_VALUE(assertion, returnValue, message) do { \ |
| if (UNLIKELY(!(assertion))) { \ |
| TERMINATE_WEB_PROCESS_WITH_MESSAGE(message); \ |
| return (returnValue); \ |
| } \ |
| } while (0) |
| |
| namespace WebKit { |
| using namespace WebCore; |
| |
| Ref<RemoteRenderingBackend> RemoteRenderingBackend::create(GPUConnectionToWebProcess& gpuConnectionToWebProcess, RemoteRenderingBackendCreationParameters&& creationParameters, IPC::Attachment&& connectionIdentifier, IPC::StreamConnectionBuffer&& streamBuffer) |
| { |
| auto instance = adoptRef(*new RemoteRenderingBackend(gpuConnectionToWebProcess, WTFMove(creationParameters), WTFMove(connectionIdentifier), WTFMove(streamBuffer))); |
| instance->startListeningForIPC(); |
| return instance; |
| } |
| |
| RemoteRenderingBackend::RemoteRenderingBackend(GPUConnectionToWebProcess& gpuConnectionToWebProcess, RemoteRenderingBackendCreationParameters&& creationParameters, IPC::Attachment&& connectionIdentifier, IPC::StreamConnectionBuffer&& streamBuffer) |
| : m_workQueue(IPC::StreamConnectionWorkQueue::create("RemoteRenderingBackend work queue")) |
| , m_streamConnection(IPC::StreamServerConnection::createWithDedicatedConnection(WTFMove(connectionIdentifier), WTFMove(streamBuffer), m_workQueue.get())) |
| , m_remoteResourceCache(gpuConnectionToWebProcess.webProcessIdentifier()) |
| , m_gpuConnectionToWebProcess(gpuConnectionToWebProcess) |
| , m_resourceOwner(gpuConnectionToWebProcess.webProcessIdentity()) |
| , m_renderingBackendIdentifier(creationParameters.identifier) |
| #if HAVE(IOSURFACE) |
| , m_ioSurfacePool(IOSurfacePool::create()) |
| #endif |
| { |
| ASSERT(RunLoop::isMain()); |
| } |
| |
| RemoteRenderingBackend::~RemoteRenderingBackend() = default; |
| |
| void RemoteRenderingBackend::startListeningForIPC() |
| { |
| { |
| Locker locker { m_remoteDisplayListsLock }; |
| m_canRegisterRemoteDisplayLists = true; |
| } |
| m_streamConnection->startReceivingMessages(*this, Messages::RemoteRenderingBackend::messageReceiverName(), m_renderingBackendIdentifier.toUInt64()); |
| m_streamConnection->open(); |
| send(Messages::RemoteRenderingBackendProxy::DidInitialize(m_workQueue->wakeUpSemaphore(), m_streamConnection->clientWaitSemaphore()), m_renderingBackendIdentifier); |
| } |
| |
| void RemoteRenderingBackend::stopListeningForIPC() |
| { |
| ASSERT(RunLoop::isMain()); |
| m_streamConnection->invalidate(); |
| |
| // This item is dispatched to the WorkQueue before calling stopAndWaitForCompletion() such that it will process it last, after any existing work. |
| m_workQueue->dispatch([&] { |
| // Make sure we destroy the ResourceCache on the WorkQueue since it gets populated on the WorkQueue. |
| // Make sure rendering resource request is released after destroying the cache. |
| m_remoteResourceCache = { m_gpuConnectionToWebProcess->webProcessIdentifier() }; |
| m_renderingResourcesRequest = { }; |
| }); |
| m_workQueue->stopAndWaitForCompletion(); |
| |
| m_streamConnection->stopReceivingMessages(Messages::RemoteRenderingBackend::messageReceiverName(), m_renderingBackendIdentifier.toUInt64()); |
| |
| { |
| Locker locker { m_remoteDisplayListsLock }; |
| m_canRegisterRemoteDisplayLists = false; |
| for (auto& remoteContext : std::exchange(m_remoteDisplayLists, { })) |
| remoteContext.value->stopListeningForIPC(); |
| } |
| } |
| |
| void RemoteRenderingBackend::dispatch(Function<void()>&& task) |
| { |
| m_workQueue->dispatch(WTFMove(task)); |
| } |
| |
| IPC::Connection* RemoteRenderingBackend::messageSenderConnection() const |
| { |
| return &m_streamConnection->connection(); |
| } |
| |
| uint64_t RemoteRenderingBackend::messageSenderDestinationID() const |
| { |
| return m_renderingBackendIdentifier.toUInt64(); |
| } |
| |
| void RemoteRenderingBackend::didCreateImageBufferBackend(ImageBufferBackendHandle handle, QualifiedRenderingResourceIdentifier renderingResourceIdentifier, RemoteDisplayListRecorder& remoteDisplayList) |
| { |
| { |
| Locker locker { m_remoteDisplayListsLock }; |
| if (m_canRegisterRemoteDisplayLists) |
| m_remoteDisplayLists.add(renderingResourceIdentifier, remoteDisplayList); |
| } |
| MESSAGE_CHECK(renderingResourceIdentifier.processIdentifier() == m_gpuConnectionToWebProcess->webProcessIdentifier(), "Sending didCreateImageBufferBackend() message to the wrong web process."); |
| send(Messages::RemoteRenderingBackendProxy::DidCreateImageBufferBackend(WTFMove(handle), renderingResourceIdentifier.object()), m_renderingBackendIdentifier); |
| } |
| |
| void RemoteRenderingBackend::didFlush(GraphicsContextFlushIdentifier flushIdentifier, QualifiedRenderingResourceIdentifier renderingResourceIdentifier) |
| { |
| MESSAGE_CHECK(renderingResourceIdentifier.processIdentifier() == m_gpuConnectionToWebProcess->webProcessIdentifier(), "Sending didFlush() message to the wrong web process."); |
| send(Messages::RemoteRenderingBackendProxy::DidFlush(flushIdentifier, renderingResourceIdentifier.object()), m_renderingBackendIdentifier); |
| } |
| |
| void RemoteRenderingBackend::createImageBuffer(const FloatSize& logicalSize, RenderingMode renderingMode, RenderingPurpose purpose, float resolutionScale, const DestinationColorSpace& colorSpace, PixelFormat pixelFormat, RenderingResourceIdentifier imageBufferResourceIdentifier) |
| { |
| // Immediately turn the RenderingResourceIdentifier (which is error-prone) to a QualifiedRenderingResourceIdentifier, |
| // and use a helper function to make sure that don't accidentally use the RenderingResourceIdentifier (because the helper function can't see it). |
| createImageBufferWithQualifiedIdentifier(logicalSize, renderingMode, purpose, resolutionScale, colorSpace, pixelFormat, { imageBufferResourceIdentifier, m_gpuConnectionToWebProcess->webProcessIdentifier() }); |
| } |
| |
| void RemoteRenderingBackend::createImageBufferWithQualifiedIdentifier(const FloatSize& logicalSize, RenderingMode renderingMode, RenderingPurpose purpose, float resolutionScale, const DestinationColorSpace& colorSpace, PixelFormat pixelFormat, QualifiedRenderingResourceIdentifier imageBufferResourceIdentifier) |
| { |
| ASSERT(!RunLoop::isMain()); |
| ASSERT(renderingMode == RenderingMode::Accelerated || renderingMode == RenderingMode::Unaccelerated); |
| |
| RefPtr<ImageBuffer> imageBuffer; |
| |
| if (renderingMode == RenderingMode::Accelerated) { |
| if (auto acceleratedImageBuffer = AcceleratedRemoteImageBuffer::create(logicalSize, resolutionScale, colorSpace, pixelFormat, purpose, *this, imageBufferResourceIdentifier)) { |
| // Mark the IOSurface as being owned by the WebProcess even though it was constructed by the GPUProcess so that Jetsam knows which process to kill. |
| if (m_resourceOwner) |
| acceleratedImageBuffer->setOwnershipIdentity(m_resourceOwner); |
| imageBuffer = WTFMove(acceleratedImageBuffer); |
| } |
| } |
| |
| if (!imageBuffer) |
| imageBuffer = UnacceleratedRemoteImageBuffer::create(logicalSize, resolutionScale, colorSpace, pixelFormat, purpose, *this, imageBufferResourceIdentifier); |
| |
| if (!imageBuffer) { |
| ASSERT_NOT_REACHED(); |
| return; |
| } |
| |
| m_remoteResourceCache.cacheImageBuffer(*imageBuffer, imageBufferResourceIdentifier); |
| } |
| |
| void RemoteRenderingBackend::getPixelBufferForImageBuffer(RenderingResourceIdentifier imageBuffer, PixelBufferFormat&& destinationFormat, IntRect&& srcRect, CompletionHandler<void()>&& completionHandler) |
| { |
| MESSAGE_CHECK(m_getPixelBufferSharedMemory, "No shared memory for getPixelBufferForImageBuffer"); |
| MESSAGE_CHECK(PixelBuffer::supportedPixelFormat(destinationFormat.pixelFormat), "Pixel format not supported"); |
| QualifiedRenderingResourceIdentifier qualifiedImageBuffer { imageBuffer, m_gpuConnectionToWebProcess->webProcessIdentifier() }; |
| if (auto imageBuffer = m_remoteResourceCache.cachedImageBuffer(qualifiedImageBuffer)) { |
| auto pixelBuffer = imageBuffer->getPixelBuffer(destinationFormat, srcRect); |
| if (pixelBuffer) { |
| MESSAGE_CHECK(pixelBuffer->sizeInBytes() <= m_getPixelBufferSharedMemory->size(), "Shmem for return of getPixelBuffer is too small"); |
| memcpy(m_getPixelBufferSharedMemory->data(), pixelBuffer->bytes(), pixelBuffer->sizeInBytes()); |
| } else |
| memset(m_getPixelBufferSharedMemory->data(), 0, m_getPixelBufferSharedMemory->size()); |
| } |
| completionHandler(); |
| } |
| |
| void RemoteRenderingBackend::getPixelBufferForImageBufferWithNewMemory(RenderingResourceIdentifier imageBuffer, SharedMemory::IPCHandle&& handle, PixelBufferFormat&& destinationFormat, IntRect&& srcRect, CompletionHandler<void()>&& completionHandler) |
| { |
| m_getPixelBufferSharedMemory = nullptr; |
| auto sharedMemory = WebKit::SharedMemory::map(handle.handle, WebKit::SharedMemory::Protection::ReadWrite); |
| MESSAGE_CHECK(sharedMemory, "Shared memory could not be mapped."); |
| MESSAGE_CHECK(sharedMemory->size() <= HTMLCanvasElement::maxActivePixelMemory(), "Shared memory too big."); |
| m_getPixelBufferSharedMemory = WTFMove(sharedMemory); |
| getPixelBufferForImageBuffer(imageBuffer, WTFMove(destinationFormat), WTFMove(srcRect), WTFMove(completionHandler)); |
| } |
| |
| void RemoteRenderingBackend::destroyGetPixelBufferSharedMemory() |
| { |
| m_getPixelBufferSharedMemory = nullptr; |
| } |
| |
| void RemoteRenderingBackend::putPixelBufferForImageBuffer(RenderingResourceIdentifier imageBuffer, IPC::PixelBufferReference&& pixelBufferReference, IntRect&& srcRect, IntPoint&& destPoint, AlphaPremultiplication destFormat) |
| { |
| QualifiedRenderingResourceIdentifier qualifiedImageBuffer { imageBuffer, m_gpuConnectionToWebProcess->webProcessIdentifier() }; |
| if (auto imageBuffer = m_remoteResourceCache.cachedImageBuffer(qualifiedImageBuffer)) { |
| auto pixelBuffer = pixelBufferReference.takePixelBuffer(); |
| imageBuffer->putPixelBuffer(pixelBuffer, srcRect, destPoint, destFormat); |
| } |
| } |
| |
| void RemoteRenderingBackend::getDataURLForImageBuffer(const String& mimeType, std::optional<double> quality, PreserveResolution preserveResolution, RenderingResourceIdentifier renderingResourceIdentifier, CompletionHandler<void(String&&)>&& completionHandler) |
| { |
| // Immediately turn the RenderingResourceIdentifier (which is error-prone) to a QualifiedRenderingResourceIdentifier, |
| // and use a helper function to make sure that don't accidentally use the RenderingResourceIdentifier (because the helper function can't see it). |
| getDataURLForImageBufferWithQualifiedIdentifier(mimeType, quality, preserveResolution, { renderingResourceIdentifier, m_gpuConnectionToWebProcess->webProcessIdentifier() }, WTFMove(completionHandler)); |
| } |
| |
| void RemoteRenderingBackend::getDataURLForImageBufferWithQualifiedIdentifier(const String& mimeType, std::optional<double> quality, PreserveResolution preserveResolution, QualifiedRenderingResourceIdentifier renderingResourceIdentifier, CompletionHandler<void(String&&)>&& completionHandler) |
| { |
| ASSERT(!RunLoop::isMain()); |
| |
| String urlString; |
| if (auto imageBuffer = m_remoteResourceCache.cachedImageBuffer(renderingResourceIdentifier)) |
| urlString = imageBuffer->toDataURL(mimeType, quality, preserveResolution); |
| completionHandler(WTFMove(urlString)); |
| } |
| |
| void RemoteRenderingBackend::getDataForImageBuffer(const String& mimeType, std::optional<double> quality, RenderingResourceIdentifier renderingResourceIdentifier, CompletionHandler<void(Vector<uint8_t>&&)>&& completionHandler) |
| { |
| // Immediately turn the RenderingResourceIdentifier (which is error-prone) to a QualifiedRenderingResourceIdentifier, |
| // and use a helper function to make sure that don't accidentally use the RenderingResourceIdentifier (because the helper function can't see it). |
| getDataForImageBufferWithQualifiedIdentifier(mimeType, quality, { renderingResourceIdentifier, m_gpuConnectionToWebProcess->webProcessIdentifier() }, WTFMove(completionHandler)); |
| } |
| |
| void RemoteRenderingBackend::getDataForImageBufferWithQualifiedIdentifier(const String& mimeType, std::optional<double> quality, QualifiedRenderingResourceIdentifier renderingResourceIdentifier, CompletionHandler<void(Vector<uint8_t>&&)>&& completionHandler) |
| { |
| ASSERT(!RunLoop::isMain()); |
| |
| Vector<uint8_t> data; |
| if (auto imageBuffer = m_remoteResourceCache.cachedImageBuffer(renderingResourceIdentifier)) |
| data = imageBuffer->toData(mimeType, quality); |
| completionHandler(WTFMove(data)); |
| } |
| |
| void RemoteRenderingBackend::getShareableBitmapForImageBuffer(RenderingResourceIdentifier identifier, PreserveResolution preserveResolution, CompletionHandler<void(ShareableBitmap::Handle&&)>&& completionHandler) |
| { |
| // Immediately turn the RenderingResourceIdentifier (which is error-prone) to a QualifiedRenderingResourceIdentifier, |
| // and use a helper function to make sure that don't accidentally use the RenderingResourceIdentifier (because the helper function can't see it). |
| getShareableBitmapForImageBufferWithQualifiedIdentifier({ identifier, m_gpuConnectionToWebProcess->webProcessIdentifier() }, preserveResolution, WTFMove(completionHandler)); |
| } |
| |
| void RemoteRenderingBackend::getShareableBitmapForImageBufferWithQualifiedIdentifier(QualifiedRenderingResourceIdentifier identifier, PreserveResolution preserveResolution, CompletionHandler<void(ShareableBitmap::Handle&&)>&& completionHandler) |
| { |
| ASSERT(!RunLoop::isMain()); |
| |
| ShareableBitmap::Handle handle; |
| [&]() { |
| auto imageBuffer = m_remoteResourceCache.cachedImageBuffer(identifier); |
| if (!imageBuffer) |
| return; |
| auto backendSize = imageBuffer->backendSize(); |
| auto logicalSize = imageBuffer->logicalSize(); |
| auto resultSize = preserveResolution == PreserveResolution::Yes ? backendSize : imageBuffer->truncatedLogicalSize(); |
| auto bitmap = ShareableBitmap::create(resultSize, { imageBuffer->colorSpace() }); |
| if (!bitmap) |
| return; |
| auto context = bitmap->createGraphicsContext(); |
| if (!context) |
| return; |
| context->drawImageBuffer(*imageBuffer, FloatRect { { }, resultSize }, FloatRect { { }, logicalSize }, { CompositeOperator::Copy }); |
| bitmap->createHandle(handle); |
| }(); |
| completionHandler(WTFMove(handle)); |
| } |
| |
| void RemoteRenderingBackend::getFilteredImageForImageBuffer(RenderingResourceIdentifier identifier, IPC::FilterReference&& filterReference, CompletionHandler<void(ShareableBitmap::Handle&&)>&& completionHandler) |
| { |
| ASSERT(!RunLoop::isMain()); |
| |
| auto filter = filterReference.takeFilter(); |
| |
| ShareableBitmap::Handle handle; |
| [&]() { |
| auto imageBuffer = m_remoteResourceCache.cachedImageBuffer({ identifier, m_gpuConnectionToWebProcess->webProcessIdentifier() }); |
| if (!imageBuffer) |
| return; |
| auto image = imageBuffer->filteredImage(filter); |
| if (!image) |
| return; |
| auto imageSize = image->size(); |
| auto bitmap = ShareableBitmap::create(IntSize(imageSize), { imageBuffer->colorSpace() }); |
| if (!bitmap) |
| return; |
| auto context = bitmap->createGraphicsContext(); |
| if (!context) |
| return; |
| context->drawImage(*image, FloatPoint()); |
| bitmap->createHandle(handle); |
| }(); |
| completionHandler(WTFMove(handle)); |
| } |
| |
| void RemoteRenderingBackend::cacheNativeImage(const ShareableBitmap::Handle& handle, RenderingResourceIdentifier nativeImageResourceIdentifier) |
| { |
| // Immediately turn the RenderingResourceIdentifier (which is error-prone) to a QualifiedRenderingResourceIdentifier, |
| // and use a helper function to make sure that don't accidentally use the RenderingResourceIdentifier (because the helper function can't see it). |
| cacheNativeImageWithQualifiedIdentifier(handle, { nativeImageResourceIdentifier, m_gpuConnectionToWebProcess->webProcessIdentifier() }); |
| } |
| |
| void RemoteRenderingBackend::cacheNativeImageWithQualifiedIdentifier(const ShareableBitmap::Handle& handle, QualifiedRenderingResourceIdentifier nativeImageResourceIdentifier) |
| { |
| ASSERT(!RunLoop::isMain()); |
| |
| auto bitmap = ShareableBitmap::create(handle); |
| if (!bitmap) |
| return; |
| |
| auto image = NativeImage::create(bitmap->createPlatformImage(DontCopyBackingStore, ShouldInterpolate::Yes), nativeImageResourceIdentifier.object()); |
| if (!image) |
| return; |
| |
| m_remoteResourceCache.cacheNativeImage(image.releaseNonNull(), nativeImageResourceIdentifier); |
| } |
| |
| void RemoteRenderingBackend::cacheFont(Ref<Font>&& font) |
| { |
| // Immediately turn the RenderingResourceIdentifier (which is error-prone) to a QualifiedRenderingResourceIdentifier, |
| // and use a helper function to make sure that don't accidentally use the RenderingResourceIdentifier (because the helper function can't see it). |
| auto renderingResourceIdentifier = font->renderingResourceIdentifier(); |
| cacheFontWithQualifiedIdentifier(WTFMove(font), { renderingResourceIdentifier, m_gpuConnectionToWebProcess->webProcessIdentifier() }); |
| } |
| |
| void RemoteRenderingBackend::cacheFontWithQualifiedIdentifier(Ref<Font>&& font, QualifiedRenderingResourceIdentifier fontResourceIdentifier) |
| { |
| ASSERT(!RunLoop::isMain()); |
| m_remoteResourceCache.cacheFont(WTFMove(font), fontResourceIdentifier); |
| } |
| |
| void RemoteRenderingBackend::cacheDecomposedGlyphs(Ref<DecomposedGlyphs>&& decomposedGlyphs) |
| { |
| // Immediately turn the RenderingResourceIdentifier (which is error-prone) to a QualifiedRenderingResourceIdentifier, |
| // and use a helper function to make sure that don't accidentally use the RenderingResourceIdentifier (because the helper function can't see it). |
| auto renderingResourceIdentifier = decomposedGlyphs->renderingResourceIdentifier(); |
| cacheDecomposedGlyphsWithQualifiedIdentifier(WTFMove(decomposedGlyphs), { renderingResourceIdentifier, m_gpuConnectionToWebProcess->webProcessIdentifier() }); |
| } |
| |
| void RemoteRenderingBackend::cacheDecomposedGlyphsWithQualifiedIdentifier(Ref<DecomposedGlyphs>&& decomposedGlyphs, QualifiedRenderingResourceIdentifier decomposedGlyphsIdentifier) |
| { |
| ASSERT(!RunLoop::isMain()); |
| m_remoteResourceCache.cacheDecomposedGlyphs(WTFMove(decomposedGlyphs), decomposedGlyphsIdentifier); |
| } |
| |
| void RemoteRenderingBackend::deleteAllFonts() |
| { |
| ASSERT(!RunLoop::isMain()); |
| m_remoteResourceCache.deleteAllFonts(); |
| } |
| |
| void RemoteRenderingBackend::releaseRemoteResource(RenderingResourceIdentifier renderingResourceIdentifier) |
| { |
| // Immediately turn the RenderingResourceIdentifier (which is error-prone) to a QualifiedRenderingResourceIdentifier, |
| // and use a helper function to make sure that don't accidentally use the RenderingResourceIdentifier (because the helper function can't see it). |
| releaseRemoteResourceWithQualifiedIdentifier({ renderingResourceIdentifier, m_gpuConnectionToWebProcess->webProcessIdentifier() }); |
| } |
| |
| void RemoteRenderingBackend::releaseRemoteResourceWithQualifiedIdentifier(QualifiedRenderingResourceIdentifier renderingResourceIdentifier) |
| { |
| ASSERT(!RunLoop::isMain()); |
| { |
| Locker locker { m_remoteDisplayListsLock }; |
| if (auto remoteDisplayList = m_remoteDisplayLists.take(renderingResourceIdentifier)) |
| remoteDisplayList->clearImageBufferReference(); |
| } |
| auto success = m_remoteResourceCache.releaseRemoteResource(renderingResourceIdentifier); |
| MESSAGE_CHECK(success, "Resource is being released before being cached."); |
| } |
| |
| static std::optional<ImageBufferBackendHandle> handleFromBuffer(ImageBuffer& buffer) |
| { |
| auto* backend = buffer.ensureBackendCreated(); |
| if (!backend) |
| return std::nullopt; |
| |
| auto* sharing = backend->toBackendSharing(); |
| if (is<ImageBufferBackendHandleSharing>(sharing)) |
| return downcast<ImageBufferBackendHandleSharing>(*sharing).createBackendHandle(); |
| |
| return std::nullopt; |
| } |
| |
| void RemoteRenderingBackend::prepareBuffersForDisplay(Vector<PrepareBackingStoreBuffersInputData> swapBuffersInput, CompletionHandler<void(const Vector<PrepareBackingStoreBuffersOutputData>&)>&& completionHandler) |
| { |
| Vector<PrepareBackingStoreBuffersOutputData> outputData; |
| outputData.resizeToFit(swapBuffersInput.size()); |
| |
| for (unsigned i = 0; i < swapBuffersInput.size(); ++i) |
| prepareLayerBuffersForDisplay(swapBuffersInput[i], outputData[i]); |
| |
| completionHandler(outputData); |
| } |
| |
| // This is the GPU Process version of RemoteLayerBackingStore::prepareBuffers(). |
| void RemoteRenderingBackend::prepareLayerBuffersForDisplay(const PrepareBackingStoreBuffersInputData& inputData, PrepareBackingStoreBuffersOutputData& outputData) |
| { |
| auto fetchBuffer = [&](std::optional<RenderingResourceIdentifier> identifier) -> ImageBuffer* { |
| return identifier ? m_remoteResourceCache.cachedImageBuffer({ *identifier, m_gpuConnectionToWebProcess->webProcessIdentifier() }) : nullptr; |
| }; |
| |
| auto bufferIdentifier = [](ImageBuffer* buffer) -> std::optional<RenderingResourceIdentifier> { |
| if (!buffer) |
| return std::nullopt; |
| return buffer->renderingResourceIdentifier(); |
| }; |
| |
| auto frontBuffer = fetchBuffer(inputData.bufferSet.front); |
| auto backBuffer = fetchBuffer(inputData.bufferSet.back); |
| auto secondaryBackBuffer = fetchBuffer(inputData.bufferSet.secondaryBack); |
| |
| LOG_WITH_STREAM(RemoteRenderingBufferVolatility, stream << "GPU Process: RemoteRenderingBackend::prepareBuffersForDisplay - front " |
| << inputData.bufferSet.front << " (in-use " << (frontBuffer && frontBuffer->isInUse()) << ") " |
| << inputData.bufferSet.back << " (in-use " << (backBuffer && backBuffer->isInUse()) << ") " |
| << inputData.bufferSet.secondaryBack << " (in-use " << (secondaryBackBuffer && secondaryBackBuffer->isInUse()) << ") "); |
| |
| bool needsFullDisplay = false; |
| |
| if (frontBuffer) { |
| auto previousState = frontBuffer->setNonVolatile(); |
| if (previousState == SetNonVolatileResult::Empty) |
| needsFullDisplay = true; |
| } |
| |
| if (frontBuffer && !needsFullDisplay && inputData.hasEmptyDirtyRegion) { |
| // No swap necessary, but we do need to return the front buffer handle. |
| outputData.frontBufferHandle = handleFromBuffer(*frontBuffer); |
| outputData.bufferSet = BufferIdentifierSet { bufferIdentifier(frontBuffer), bufferIdentifier(backBuffer), bufferIdentifier(secondaryBackBuffer) }; |
| outputData.displayRequirement = SwapBuffersDisplayRequirement::NeedsNoDisplay; |
| return; |
| } |
| |
| if (!frontBuffer || !inputData.supportsPartialRepaint) |
| needsFullDisplay = true; |
| |
| if (!backBuffer || backBuffer->isInUse()) { |
| std::swap(backBuffer, secondaryBackBuffer); |
| |
| // When pulling the secondary back buffer out of hibernation (to become |
| // the new front buffer), if it is somehow still in use (e.g. we got |
| // three swaps ahead of the render server), just give up and discard it. |
| if (backBuffer && backBuffer->isInUse()) |
| backBuffer = nullptr; |
| } |
| |
| std::swap(frontBuffer, backBuffer); |
| |
| outputData.bufferSet = BufferIdentifierSet { bufferIdentifier(frontBuffer), bufferIdentifier(backBuffer), bufferIdentifier(secondaryBackBuffer) }; |
| if (frontBuffer) { |
| auto previousState = frontBuffer->setNonVolatile(); |
| if (previousState == SetNonVolatileResult::Empty) |
| needsFullDisplay = true; |
| |
| outputData.frontBufferHandle = handleFromBuffer(*frontBuffer); |
| } else |
| needsFullDisplay = true; |
| |
| LOG_WITH_STREAM(RemoteRenderingBufferVolatility, stream << "GPU Process: prepareBuffersForDisplay - swapped from [" |
| << inputData.bufferSet.front << ", " << inputData.bufferSet.back << ", " << inputData.bufferSet.secondaryBack << "] to [" |
| << outputData.bufferSet.front << ", " << outputData.bufferSet.back << ", " << outputData.bufferSet.secondaryBack << "]"); |
| |
| outputData.displayRequirement = needsFullDisplay ? SwapBuffersDisplayRequirement::NeedsFullDisplay : SwapBuffersDisplayRequirement::NeedsNormalDisplay; |
| } |
| |
| void RemoteRenderingBackend::markSurfacesVolatile(MarkSurfacesAsVolatileRequestIdentifier requestIdentifier, const Vector<RenderingResourceIdentifier>& identifiers) |
| { |
| LOG_WITH_STREAM(RemoteRenderingBufferVolatility, stream << "GPU Process: RemoteRenderingBackend::markSurfacesVolatile " << identifiers); |
| |
| auto makeVolatile = [](ImageBuffer& imageBuffer) { |
| imageBuffer.releaseGraphicsContext(); |
| return imageBuffer.setVolatile(); |
| }; |
| |
| Vector<RenderingResourceIdentifier> markedVolatileBufferIdentifiers; |
| for (auto identifier : identifiers) { |
| auto imageBuffer = m_remoteResourceCache.cachedImageBuffer({ identifier, m_gpuConnectionToWebProcess->webProcessIdentifier() }); |
| if (imageBuffer) { |
| if (makeVolatile(*imageBuffer)) |
| markedVolatileBufferIdentifiers.append(identifier); |
| } else |
| LOG_WITH_STREAM(RemoteRenderingBufferVolatility, stream << " failed to find ImageBuffer for identifier " << identifier); |
| } |
| |
| LOG_WITH_STREAM(RemoteRenderingBufferVolatility, stream << "GPU Process: markSurfacesVolatile - surfaces marked volatile " << markedVolatileBufferIdentifiers); |
| |
| bool didMarkAllLayerAsVolatile = identifiers.size() == markedVolatileBufferIdentifiers.size(); |
| send(Messages::RemoteRenderingBackendProxy::DidMarkLayersAsVolatile(requestIdentifier, markedVolatileBufferIdentifiers, didMarkAllLayerAsVolatile), m_renderingBackendIdentifier); |
| } |
| |
| void RemoteRenderingBackend::finalizeRenderingUpdate(RenderingUpdateID renderingUpdateID) |
| { |
| send(Messages::RemoteRenderingBackendProxy::DidFinalizeRenderingUpdate(renderingUpdateID), m_renderingBackendIdentifier); |
| } |
| |
| void RemoteRenderingBackend::performWithMediaPlayerOnMainThread(MediaPlayerIdentifier identifier, Function<void(MediaPlayer&)>&& callback) |
| { |
| callOnMainRunLoopAndWait([&, gpuConnectionToWebProcess = m_gpuConnectionToWebProcess, identifier] { |
| if (auto player = gpuConnectionToWebProcess->remoteMediaPlayerManagerProxy().mediaPlayer(identifier)) |
| callback(*player); |
| }); |
| } |
| |
| void RemoteRenderingBackend::lowMemoryHandler(Critical, Synchronous) |
| { |
| ASSERT(isMainRunLoop()); |
| #if HAVE(IOSURFACE) |
| m_ioSurfacePool->discardAllSurfaces(); |
| #endif |
| } |
| |
| } // namespace WebKit |
| |
| #endif // ENABLE(GPU_PROCESS) |