summaryrefslogtreecommitdiffstats
path: root/src/core/delegated_frame_node.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/delegated_frame_node.cpp')
-rw-r--r--src/core/delegated_frame_node.cpp231
1 files changed, 119 insertions, 112 deletions
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