/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebEngine module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "compositor_resource_tracker.h" #include "chromium_gpu_helper.h" #include "render_widget_host_view_qt_delegate.h" #include "web_engine_context.h" #include "base/message_loop/message_loop.h" #include "base/task/post_task.h" #include "components/viz/common/quads/compositor_frame.h" #include "components/viz/common/resources/returned_resource.h" #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "content/browser/browser_main_loop.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/gpu/content_gpu_client.h" #include "gpu/command_buffer/service/mailbox_manager.h" #include "gpu/command_buffer/service/sync_point_manager.h" namespace QtWebEngineCore { CompositorResourceTracker::CompositorResourceTracker() {} CompositorResourceTracker::~CompositorResourceTracker() {} void CompositorResourceTracker::submitResources(const viz::CompositorFrame &frame, base::OnceClosure callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(!m_submitCallback); DCHECK(m_pendingResources.empty()); DCHECK(m_pendingImports.empty()); DCHECK(m_pendingResourceUpdates == 0); m_submitCallback = std::move(callback); m_pendingResources.reserve(frame.resource_list.size()); m_pendingImports.reserve(frame.resource_list.size()); for (const viz::TransferableResource &transferableResource : frame.resource_list) { auto it = m_committedResources.find(transferableResource.id); if (it != m_committedResources.end()) m_pendingImports.push_back(&*it); else m_pendingResources.emplace_back(transferableResource); } if (m_pendingResources.empty()) { scheduleRunSubmitCallback(); return; } m_pendingResourceUpdates = m_pendingResources.size(); std::vector batch; batch.reserve(m_pendingResources.size()); for (CompositorResource &resource : m_pendingResources) { if (resource.is_software) updateBitmap(&resource); else if (!scheduleUpdateMailbox(&resource)) batch.push_back(&resource); } if (!batch.empty()) scheduleUpdateMailboxes(std::move(batch)); } void CompositorResourceTracker::commitResources() { // DCHECK_CURRENTLY_ON(content::BrowserThread::UI); // // This might be called from a Qt Quick render thread, but the UI thread // will still be blocked for the duration of this call. DCHECK(m_pendingResourceUpdates == 0); for (CompositorResource *resource : m_pendingImports) resource->import_count++; m_pendingImports.clear(); m_committedResources.insert(std::make_move_iterator(m_pendingResources.begin()), std::make_move_iterator(m_pendingResources.end())); m_pendingResources.clear(); ++m_committedFrameId; } std::vector CompositorResourceTracker::returnResources() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); std::vector returnedResources; base::EraseIf(m_committedResources, [&](const CompositorResource &resource) { if (resource.last_used_for_frame != m_committedFrameId) { viz::ReturnedResource returnedResource; returnedResource.id = resource.id; returnedResource.count = resource.import_count; returnedResources.push_back(std::move(returnedResource)); return true; } return false; }); return returnedResources; } const CompositorResource *CompositorResourceTracker::findResource(CompositorResourceId id) const { auto it = m_committedResources.find(id); DCHECK(it != m_committedResources.end()); const_cast(*it).last_used_for_frame = m_committedFrameId; return &*it; } void CompositorResourceTracker::updateBitmap(CompositorResource *resource) { content::BrowserMainLoop *browserMainLoop = content::BrowserMainLoop::GetInstance(); viz::ServerSharedBitmapManager *bitmapManager = browserMainLoop->GetServerSharedBitmapManager(); resource->bitmap = bitmapManager->GetSharedBitmapFromId( resource->size, viz::BGRA_8888, resource->mailbox_holder.mailbox); if (--m_pendingResourceUpdates == 0) scheduleRunSubmitCallback(); } quint32 CompositorResourceTracker::consumeMailbox(const gpu::MailboxHolder &mailboxHolder) { #if QT_CONFIG(opengl) gpu::MailboxManager *mailboxManager = mailbox_manager(); DCHECK(mailboxManager); if (mailboxHolder.sync_token.HasData()) mailboxManager->PullTextureUpdates(mailboxHolder.sync_token); return service_id(mailboxManager->ConsumeTexture(mailboxHolder.mailbox)); #else NOTREACHED(); #endif // QT_CONFIG(OPENGL) } bool CompositorResourceTracker::scheduleUpdateMailbox(CompositorResource *resource) { #if QT_CONFIG(opengl) gpu::SyncPointManager *syncPointManager = WebEngineContext::syncPointManager(); DCHECK(syncPointManager); return syncPointManager->WaitOutOfOrder( resource->mailbox_holder.sync_token, base::BindOnce(&CompositorResourceTracker::updateMailbox, m_weakPtrFactory.GetWeakPtr(), resource)); #else NOTREACHED(); #endif // QT_CONFIG(OPENGL) } void CompositorResourceTracker::updateMailbox(CompositorResource *resource) { #if QT_CONFIG(opengl) resource->texture_id = consumeMailbox(resource->mailbox_holder); resource->texture_fence = CompositorResourceFence::create(); if (--m_pendingResourceUpdates == 0) scheduleRunSubmitCallback(); #else NOTREACHED(); #endif // QT_CONFIG(OPENGL) } void CompositorResourceTracker::scheduleUpdateMailboxes(std::vector resources) { #if QT_CONFIG(opengl) scoped_refptr gpuTaskRunner = gpu_task_runner(); DCHECK(gpuTaskRunner); gpuTaskRunner->PostTask( FROM_HERE, base::BindOnce(&CompositorResourceTracker::updateMailboxes, m_weakPtrFactory.GetWeakPtr(), std::move(resources))); #else NOTREACHED(); #endif // QT_CONFIG(OPENGL) } void CompositorResourceTracker::updateMailboxes(std::vector resources) { #if QT_CONFIG(opengl) for (CompositorResource *resource : resources) resource->texture_id = consumeMailbox(resource->mailbox_holder); scoped_refptr fence = CompositorResourceFence::create(); for (CompositorResource *resource : resources) resource->texture_fence = fence; if ((m_pendingResourceUpdates -= resources.size()) == 0) scheduleRunSubmitCallback(); #else NOTREACHED(); #endif // QT_CONFIG(OPENGL) } void CompositorResourceTracker::scheduleRunSubmitCallback() { base::PostTaskWithTraits( FROM_HERE, { content::BrowserThread::UI, base::TaskPriority::USER_VISIBLE }, base::BindOnce(&CompositorResourceTracker::runSubmitCallback, m_weakPtrFactory.GetWeakPtr())); } void CompositorResourceTracker::runSubmitCallback() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); std::move(m_submitCallback).Run(); } } // namespace QtWebEngineCore