diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2016-01-26 10:51:22 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2016-03-07 17:09:00 +0000 |
commit | 56714be7d05afb94c63b658a4fdb2bedd1bee645 (patch) | |
tree | abd103a44bf0dd5ea9ce9731db417606a307da0e | |
parent | 6ac33ac828b3a17cf7db7a80b3c043d51ba646a1 (diff) |
-rw-r--r-- | src/core/chromium_gpu_helper.cpp | 25 | ||||
-rw-r--r-- | src/core/chromium_gpu_helper.h | 5 | ||||
-rw-r--r-- | src/core/delegated_frame_node.cpp | 231 | ||||
-rw-r--r-- | src/core/delegated_frame_node.h | 10 | ||||
-rw-r--r-- | src/core/web_engine_context.cpp | 3 |
5 files changed, 127 insertions, 147 deletions
diff --git a/src/core/chromium_gpu_helper.cpp b/src/core/chromium_gpu_helper.cpp index c955837b8..349506dbd 100644 --- a/src/core/chromium_gpu_helper.cpp +++ b/src/core/chromium_gpu_helper.cpp @@ -57,25 +57,6 @@ #include "content/common/gpu/stream_texture_qnx.h" #endif -static void addSyncPointCallbackDelegate(gpu::SyncPointManager *syncPointManager, uint32 sync_point, const base::Closure& callback) -{ - syncPointManager->AddSyncPointCallback(sync_point, callback); -} - -QMap<uint32, gfx::TransferableFence> transferFences() -{ - QMap<uint32, gfx::TransferableFence> ret; - content::GpuChannelManager *gpuChannelManager = content::GpuChildThread::instance()->ChannelManager(); - content::GpuChannelManager::SyncPointGLFences::iterator it = gpuChannelManager->sync_point_gl_fences_.begin(); - content::GpuChannelManager::SyncPointGLFences::iterator end = gpuChannelManager->sync_point_gl_fences_.end(); - for (; it != end; ++it) { - ret[it->first] = it->second->Transfer(); - delete it->second; - } - gpuChannelManager->sync_point_gl_fences_.clear(); - return ret; -} - base::MessageLoop *gpu_message_loop() { return content::GpuChildThread::instance()->message_loop(); @@ -87,12 +68,6 @@ gpu::SyncPointManager *sync_point_manager() return gpuChannelManager->sync_point_manager(); } -void AddSyncPointCallbackOnGpuThread(base::MessageLoop *gpuMessageLoop, gpu::SyncPointManager *syncPointManager, uint32 sync_point, const base::Closure& callback) -{ - // We need to set our callback from the GPU thread, where the SyncPointManager lives. - gpuMessageLoop->PostTask(FROM_HERE, base::Bind(&addSyncPointCallbackDelegate, syncPointManager, sync_point, callback)); -} - gpu::gles2::MailboxManager *mailbox_manager() { content::GpuChannelManager *gpuChannelManager = content::GpuChildThread::instance()->ChannelManager(); diff --git a/src/core/chromium_gpu_helper.h b/src/core/chromium_gpu_helper.h index 254143db9..02fe2d3bb 100644 --- a/src/core/chromium_gpu_helper.h +++ b/src/core/chromium_gpu_helper.h @@ -43,9 +43,6 @@ #include <QtGlobal> // We need this for the Q_OS_QNX define. #include <QMap> -#include "base/callback.h" -#include "ui/gl/gl_fence.h" - namespace base { class MessageLoop; } @@ -64,12 +61,10 @@ class Texture; // From the outside, types from incompatible headers referenced in these // functions should only be forward-declared and considered as opaque types. -QMap<uint32, gfx::TransferableFence> transferFences(); base::MessageLoop *gpu_message_loop(); gpu::SyncPointManager *sync_point_manager(); gpu::gles2::MailboxManager *mailbox_manager(); -void AddSyncPointCallbackOnGpuThread(base::MessageLoop *gpuMessageLoop, gpu::SyncPointManager *syncPointManager, uint32 sync_point, const base::Closure& callback); gpu::gles2::Texture* ConsumeTexture(gpu::gles2::MailboxManager *mailboxManager, unsigned target, const gpu::Mailbox& mailbox); unsigned int service_id(gpu::gles2::Texture *tex); diff --git a/src/core/delegated_frame_node.cpp b/src/core/delegated_frame_node.cpp index 51c858abc..b181f04e3 100644 --- a/src/core/delegated_frame_node.cpp +++ b/src/core/delegated_frame_node.cpp @@ -67,6 +67,10 @@ #include "cc/quads/tile_draw_quad.h" #include "cc/quads/yuv_video_draw_quad.h" #include "content/common/host_shared_bitmap_manager.h" +#include "gpu/command_buffer/service/mailbox_manager.h" +#include "ui/gl/gl_context.h" +#include "ui/gl/gl_fence.h" + #include <QOpenGLContext> #include <QOpenGLFunctions> #include <QSGSimpleRectNode> @@ -373,7 +377,6 @@ cc::ReturnedResource ResourceHolder::returnResource() // ack directly from our rendering thread. At this point (in updatePaintNode) we know that // a frame that was compositing any of those resources has already been swapped and we thus // don't need to use this mechanism. - returned.sync_point = 0; returned.id = m_resource.id; returned.count = m_importCount; m_importCount = 0; @@ -413,92 +416,8 @@ void DelegatedFrameNode::preprocess() mailboxesToFetch.append(static_cast<MailboxTexture *>((*it)->texture())); } - if (!mailboxesToFetch.isEmpty()) { - QMap<uint32, gfx::TransferableFence> transferredFences; - { - QMutexLocker lock(&m_mutex); - base::MessageLoop *gpuMessageLoop = gpu_message_loop(); - gpu::SyncPointManager *syncPointManager = sync_point_manager(); - - Q_FOREACH (MailboxTexture *mailboxTexture, mailboxesToFetch) { - m_numPendingSyncPoints++; - AddSyncPointCallbackOnGpuThread(gpuMessageLoop, syncPointManager, mailboxTexture->mailboxHolder().sync_point, base::Bind(&DelegatedFrameNode::syncPointRetired, this, &mailboxesToFetch)); - } - - m_mailboxesFetchedWaitCond.wait(&m_mutex); - m_mailboxGLFences.swap(transferredFences); - } - -#if defined(USE_X11) - // Workaround when context is not shared QTBUG-48969 - // Make slow copy between two contexts. - QOpenGLContext *currentContext = QOpenGLContext::currentContext() ; - QOpenGLContext *sharedContext = qt_gl_global_share_context(); - if (!QOpenGLContext::areSharing(currentContext,sharedContext)) { - static bool allowNotSharedContextWarningShown = true; - if (allowNotSharedContextWarningShown) { - allowNotSharedContextWarningShown = false; - qWarning("Context is not shared, textures will be copied between contexts."); - } - - Q_FOREACH (MailboxTexture *mailboxTexture, mailboxesToFetch) { - gfx::TransferableFence fence = transferredFences.take(mailboxTexture->mailboxHolder().sync_point); - waitChromiumSync(&fence); - deleteChromiumSync(&fence); - - QSurface *surface = currentContext->surface(); - // Read texture into QImage from shared context. - // Switch to shared context. - QOffscreenSurface offsurface; - offsurface.create(); - sharedContext->makeCurrent(&offsurface); - QOpenGLFunctions *funcs = sharedContext->functions(); - QImage img(mailboxTexture->textureSize(), QImage::Format_RGBA8888_Premultiplied); - GLuint fbo = 0; - funcs->glGenFramebuffers(1, &fbo); - funcs->glBindFramebuffer(GL_FRAMEBUFFER, fbo); - funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mailboxTexture->m_textureId, 0); - GLenum status = funcs->glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - qWarning("fbo error, skipping slow copy..."); - continue; - } - - funcs->glReadPixels(0, 0, mailboxTexture->textureSize().width(), mailboxTexture->textureSize().height(), GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); - funcs->glBindFramebuffer(GL_FRAMEBUFFER, 0); - - // Restore current context. - currentContext->makeCurrent(surface); - // Create texture from QImage in current context. - GLuint texture = 0; - funcs = currentContext->functions(); - funcs->glGenTextures(1, &texture); - funcs->glBindTexture(GL_TEXTURE_2D, texture); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mailboxTexture->textureSize().width(), mailboxTexture->textureSize().height(), 0, - GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); - mailboxTexture->m_textureId = texture; - } - } else -#endif - { - // Tell GL to wait until Chromium is done generating resource textures on the GPU thread - // for each mailbox. We can safely start referencing those textures onto geometries afterward. - Q_FOREACH (MailboxTexture *mailboxTexture, mailboxesToFetch) { - gfx::TransferableFence fence = transferredFences.take(mailboxTexture->mailboxHolder().sync_point); - waitChromiumSync(&fence); - deleteChromiumSync(&fence); - } - } - // We transferred all sync point fences from Chromium, - // destroy all the ones not referenced by one of our mailboxes without waiting. - QMap<uint32, gfx::TransferableFence>::iterator end = transferredFences.end(); - for (QMap<uint32, gfx::TransferableFence>::iterator it = transferredFences.begin(); it != end; ++it) - deleteChromiumSync(&*it); - } + if (!mailboxesToFetch.isEmpty()) + fetchAndSyncMailboxes(mailboxesToFetch); // Then render any intermediate RenderPass in order. typedef QPair<cc::RenderPassId, QSharedPointer<QSGLayer> > Pair; @@ -572,10 +491,10 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, // parent, with the last one in the list being the root RenderPass, the one // that we displayed to the user. // All RenderPasses except the last one are rendered to an FBO. - cc::RenderPass *rootRenderPass = frameData->render_pass_list.back(); + cc::RenderPass *rootRenderPass = frameData->render_pass_list.back().get(); for (unsigned i = 0; i < frameData->render_pass_list.size(); ++i) { - cc::RenderPass *pass = frameData->render_pass_list.at(i); + cc::RenderPass *pass = frameData->render_pass_list.at(i).get(); QSGNode *renderPassParent = 0; if (pass != rootRenderPass) { @@ -768,36 +687,124 @@ QSGTexture *DelegatedFrameNode::initAndHoldTexture(ResourceHolder *resource, boo return m_sgObjects.textureStrongRefs.last().data(); } -void DelegatedFrameNode::fetchTexturesAndUnlockQt(DelegatedFrameNode *frameNode, QList<MailboxTexture *> *mailboxesToFetch) +void DelegatedFrameNode::fetchAndSyncMailboxes(QList<MailboxTexture *> &mailboxesToFetch) { - // Fetch texture IDs from the mailboxes while we're on the GPU thread, where the MailboxManager lives. - gpu::gles2::MailboxManager *mailboxManager = mailbox_manager(); - Q_FOREACH (MailboxTexture *mailboxTexture, *mailboxesToFetch) - mailboxTexture->fetchTexture(mailboxManager); + QList<gfx::TransferableFence> transferredFences; + { + QMutexLocker lock(&m_mutex); + + gpu::SyncPointManager *syncPointManager = sync_point_manager(); + if (!m_syncPointClient) + m_syncPointClient = syncPointManager->CreateSyncPointClientWaiter(); + base::MessageLoop *gpuMessageLoop = gpu_message_loop(); + Q_ASSERT(m_numPendingSyncPoints == 0); + m_numPendingSyncPoints = mailboxesToFetch.count(); + auto it = mailboxesToFetch.constBegin(); + auto end = mailboxesToFetch.constEnd(); + for (; it != end; ++it) { + MailboxTexture *mailboxTexture = *it; + gpu::SyncToken &syncToken = mailboxTexture->mailboxHolder().sync_token; + if (syncToken.HasData()) { + scoped_refptr<gpu::SyncPointClientState> release_state = + syncPointManager->GetSyncPointClientState(syncToken.namespace_id(), syncToken.command_buffer_id()); + if (release_state && !release_state->IsFenceSyncReleased(syncToken.release_count())) { + m_syncPointClient->WaitOutOfOrderNonThreadSafe( + release_state.get(), syncToken.release_count(), + gpuMessageLoop->task_runner(), base::Bind(&DelegatedFrameNode::pullTexture, this, mailboxTexture)); + continue; + } + } + gpuMessageLoop->PostTask(FROM_HERE, base::Bind(&DelegatedFrameNode::pullTexture, this, mailboxTexture)); + } - // Pick fences that we can ask GL to wait for before trying to sample the mailbox texture IDs. - QMap<uint32, gfx::TransferableFence> transferredFences = transferFences(); + m_mailboxesFetchedWaitCond.wait(&m_mutex); + m_textureFences.swap(transferredFences); + } - // Chromium provided everything we were waiting for, let Qt start rendering. - QMutexLocker lock(&frameNode->m_mutex); - Q_ASSERT(frameNode->m_mailboxGLFences.isEmpty()); - frameNode->m_mailboxGLFences.swap(transferredFences); - frameNode->m_mailboxesFetchedWaitCond.wakeOne(); + Q_FOREACH (gfx::TransferableFence sync, transferredFences) { + // We need to wait on the fences on the Qt current context, and + // can therefore not use GLFence routines that uses a different + // concept of current context. + waitChromiumSync(&sync); + deleteChromiumSync(&sync); + } +#if defined(USE_X11) + // Workaround when context is not shared QTBUG-48969 + // Make slow copy between two contexts. + QOpenGLContext *currentContext = QOpenGLContext::currentContext() ; + QOpenGLContext *sharedContext = qt_gl_global_share_context(); + if (!QOpenGLContext::areSharing(currentContext,sharedContext)) { + static bool allowNotSharedContextWarningShown = true; + if (allowNotSharedContextWarningShown) { + allowNotSharedContextWarningShown = false; + qWarning("Context is not shared, textures will be copied between contexts."); + } + + Q_FOREACH (MailboxTexture *mailboxTexture, mailboxesToFetch) { + QSurface *surface = currentContext->surface(); + // Read texture into QImage from shared context. + // Switch to shared context. + QOffscreenSurface offsurface; + offsurface.create(); + sharedContext->makeCurrent(&offsurface); + QOpenGLFunctions *funcs = sharedContext->functions(); + QImage img(mailboxTexture->textureSize(), QImage::Format_RGBA8888_Premultiplied); + GLuint fbo = 0; + funcs->glGenFramebuffers(1, &fbo); + funcs->glBindFramebuffer(GL_FRAMEBUFFER, fbo); + funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mailboxTexture->m_textureId, 0); + GLenum status = funcs->glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + qWarning("fbo error, skipping slow copy..."); + continue; + } + + funcs->glReadPixels(0, 0, mailboxTexture->textureSize().width(), mailboxTexture->textureSize().height(), GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); + funcs->glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // Restore current context. + currentContext->makeCurrent(surface); + // Create texture from QImage in current context. + GLuint texture = 0; + funcs = currentContext->functions(); + funcs->glGenTextures(1, &texture); + funcs->glBindTexture(GL_TEXTURE_2D, texture); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mailboxTexture->textureSize().width(), mailboxTexture->textureSize().height(), 0, + GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); + mailboxTexture->m_textureId = texture; + } + } +#endif } -void DelegatedFrameNode::syncPointRetired(DelegatedFrameNode *frameNode, QList<MailboxTexture *> *mailboxesToFetch) + +void DelegatedFrameNode::pullTexture(DelegatedFrameNode *frameNode, MailboxTexture *texture) +{ + gpu::gles2::MailboxManager *mailboxManager = mailbox_manager(); + gpu::SyncToken &syncToken = texture->mailboxHolder().sync_token; + if (syncToken.HasData()) + mailboxManager->PullTextureUpdates(syncToken); + texture->fetchTexture(mailboxManager); + if (!!gfx::GLContext::GetCurrent()) { + // Create a fence on the Chromium GPU-thread and context + gfx::GLFence *fence = gfx::GLFence::Create(); + // But transfer it to something generic since we need to read it using Qt's OpenGL. + frameNode->m_textureFences.append(fence->Transfer()); + delete fence; + } + if (--frameNode->m_numPendingSyncPoints == 0) + base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&DelegatedFrameNode::fenceAndUnlockQt, frameNode)); +} + +void DelegatedFrameNode::fenceAndUnlockQt(DelegatedFrameNode *frameNode) { - // The way that sync points are normally used by the GpuCommandBufferStub is that it asks - // the GpuScheduler to resume the work of the associated GL command stream / context once - // the sync point has been retired by the dependency's context. In other words, a produced - // texture means that the mailbox can be consumed, but the texture itself isn't expected - // to be ready until to control is given back to the GpuScheduler through the event loop. - // Do the same for our implementation by posting a message to the event loop once the last - // of our syncpoints has been retired (the syncpoint callback is called synchronously) and - // only at this point we wake the Qt rendering thread. QMutexLocker lock(&frameNode->m_mutex); - if (!--frameNode->m_numPendingSyncPoints) - base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&DelegatedFrameNode::fetchTexturesAndUnlockQt, frameNode, mailboxesToFetch)); + // Signal preprocess() the textures are ready + frameNode->m_mailboxesFetchedWaitCond.wakeOne(); } } // namespace QtWebEngineCore diff --git a/src/core/delegated_frame_node.h b/src/core/delegated_frame_node.h index 9c05cb872..8a37f6b4c 100644 --- a/src/core/delegated_frame_node.h +++ b/src/core/delegated_frame_node.h @@ -43,6 +43,8 @@ #include "base/memory/scoped_ptr.h" #include "cc/quads/render_pass.h" #include "cc/resources/transferable_resource.h" +#include "gpu/command_buffer/service/sync_point_manager.h" +#include "ui/gl/gl_fence.h" #include <QMutex> #include <QSGNode> #include <QSharedData> @@ -83,10 +85,11 @@ public: void commit(ChromiumCompositorData *chromiumCompositorData, cc::ReturnedResourceArray *resourcesToRelease, RenderWidgetHostViewQtDelegate *apiDelegate); private: + void fetchAndSyncMailboxes(QList<MailboxTexture *> &mailboxesToFetch); // Making those callbacks static bypasses base::Bind's ref-counting requirement // of the this pointer when the callback is a method. - static void fetchTexturesAndUnlockQt(DelegatedFrameNode *frameNode, QList<MailboxTexture *> *mailboxesToFetch); - static void syncPointRetired(DelegatedFrameNode *frameNode, QList<MailboxTexture *> *mailboxesToFetch); + static void pullTexture(DelegatedFrameNode *frameNode, MailboxTexture *mailbox); + static void fenceAndUnlockQt(DelegatedFrameNode *frameNode); ResourceHolder *findAndHoldResource(unsigned resourceId, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates); QSGTexture *initAndHoldTexture(ResourceHolder *resource, bool quadIsAllOpaque, RenderWidgetHostViewQtDelegate *apiDelegate = 0); @@ -98,9 +101,10 @@ private: QVector<QSharedPointer<QSGTexture> > textureStrongRefs; } m_sgObjects; int m_numPendingSyncPoints; - QMap<uint32, gfx::TransferableFence> m_mailboxGLFences; QWaitCondition m_mailboxesFetchedWaitCond; QMutex m_mutex; + QList<gfx::TransferableFence> m_textureFences; + scoped_ptr<gpu::SyncPointClient> m_syncPointClient; }; } // namespace QtWebEngineCore diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index 7cb3184b2..3f81f7a95 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -236,8 +236,7 @@ WebEngineContext::WebEngineContext() parsedCommandLine->AppendSwitch(switches::kInProcessGPU); // These are currently only default on OS X, and we don't support them: parsedCommandLine->AppendSwitch(switches::kDisableZeroCopy); - parsedCommandLine->AppendSwitch(switches::kDisableNativeGpuMemoryBuffers); - parsedCommandLine->AppendSwitch(switches::kDisableGpuMemoryBufferVideoFrames); + parsedCommandLine->AppendSwitch(switches::kDisableGpuMemoryBufferCompositorResources); if (useEmbeddedSwitches) { // Inspired by the Android port's default switches |