summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpiman@chromium.org <piman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-05 23:35:16 +0000
committerpiman@chromium.org <piman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-05 23:35:16 +0000
commitc02f93e47ba08e8dd00c6904e0cc788db647b07e (patch)
treef27b51946855f3718d24d2150d1f8173354df2d8
parente47aee08984a9a341ceccb8e4d342ac616982d2c (diff)
downloadchromium_src-c02f93e47ba08e8dd00c6904e0cc788db647b07e.zip
chromium_src-c02f93e47ba08e8dd00c6904e0cc788db647b07e.tar.gz
chromium_src-c02f93e47ba08e8dd00c6904e0cc788db647b07e.tar.bz2
GPU: Adding sync points for cross-channel synchronization
Theory of operation: command buffer 1 calls InsertSyncPoint, it returns an ID, command buffer 2 calls WaitSyncPoint on that ID (even if on another channel). The wait is pipelined. InsertSyncPoint is handled on the IO thread in the GPU process, so it's presumably fast, but its effect is ordered wrt the other messages. Some benefits of the approach: - once InsertSyncPoint returns the ID, the sync point is already enqueued to be eventually retired, so it makes it very hard to cause deadlocks by incorrect operation on the client side. - the wait will return if the command buffer that inserted the sync point gets destroyed. This primitive should be enough for guaranteeing browser->renderer ordering. Additional changes are needed to safely handle renderer->browser ordering (especially in case of buggy/malicious renderer). BUG=112299 TEST=manual (With other patches) Review URL: https://chromiumcodereview.appspot.com/10510013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@140653 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/common/gpu/client/command_buffer_proxy_impl.cc10
-rw-r--r--content/common/gpu/client/command_buffer_proxy_impl.h2
-rw-r--r--content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc11
-rw-r--r--content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h3
-rw-r--r--content/common/gpu/gpu_channel.cc108
-rw-r--r--content/common/gpu/gpu_channel_manager.cc4
-rw-r--r--content/common/gpu/gpu_channel_manager.h4
-rw-r--r--content/common/gpu/gpu_command_buffer_stub.cc36
-rw-r--r--content/common/gpu/gpu_command_buffer_stub.h16
-rw-r--r--content/common/gpu/gpu_messages.h17
-rw-r--r--content/common/gpu/sync_point_manager.cc56
-rw-r--r--content/common/gpu/sync_point_manager.h54
-rw-r--r--content/content_common.gypi2
-rw-r--r--gpu/ipc/command_buffer_proxy.h11
-rw-r--r--ppapi/proxy/ppapi_command_buffer_proxy.cc10
-rw-r--r--ppapi/proxy/ppapi_command_buffer_proxy.h2
16 files changed, 339 insertions, 7 deletions
diff --git a/content/common/gpu/client/command_buffer_proxy_impl.cc b/content/common/gpu/client/command_buffer_proxy_impl.cc
index 6c7cef8..8f3f4ce 100644
--- a/content/common/gpu/client/command_buffer_proxy_impl.cc
+++ b/content/common/gpu/client/command_buffer_proxy_impl.cc
@@ -416,6 +416,16 @@ bool CommandBufferProxyImpl::EnsureBackbuffer() {
return Send(new GpuCommandBufferMsg_EnsureBackbuffer(route_id_));
}
+uint32 CommandBufferProxyImpl::InsertSyncPoint() {
+ uint32 sync_point = 0;
+ Send(new GpuCommandBufferMsg_InsertSyncPoint(route_id_, &sync_point));
+ return sync_point;
+}
+
+void CommandBufferProxyImpl::WaitSyncPoint(uint32 sync_point) {
+ Send(new GpuCommandBufferMsg_WaitSyncPoint(route_id_, sync_point));
+}
+
bool CommandBufferProxyImpl::SetParent(
CommandBufferProxy* parent_command_buffer,
uint32 parent_texture_id) {
diff --git a/content/common/gpu/client/command_buffer_proxy_impl.h b/content/common/gpu/client/command_buffer_proxy_impl.h
index 9a49114..787455b 100644
--- a/content/common/gpu/client/command_buffer_proxy_impl.h
+++ b/content/common/gpu/client/command_buffer_proxy_impl.h
@@ -65,6 +65,8 @@ class CommandBufferProxyImpl
virtual bool SetSurfaceVisible(bool visible) OVERRIDE;
virtual bool DiscardBackbuffer() OVERRIDE;
virtual bool EnsureBackbuffer() OVERRIDE;
+ virtual uint32 InsertSyncPoint() OVERRIDE;
+ virtual void WaitSyncPoint(uint32 sync_point) OVERRIDE;
virtual void SetMemoryAllocationChangedCallback(
const base::Callback<void(const GpuMemoryAllocationForRenderer&)>&
callback) OVERRIDE;
diff --git a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
index e59a87e..b8b8950 100644
--- a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
+++ b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
@@ -426,6 +426,17 @@ bool WebGraphicsContext3DCommandBufferImpl::setParentContext(
return SetParent(parent_context_impl);
}
+unsigned int WebGraphicsContext3DCommandBufferImpl::insertSyncPoint() {
+ gl_->helper()->CommandBufferHelper::Flush();
+ return command_buffer_->InsertSyncPoint();
+}
+
+void WebGraphicsContext3DCommandBufferImpl::waitSyncPoint(
+ unsigned int sync_point) {
+ gl_->helper()->CommandBufferHelper::Flush();
+ command_buffer_->WaitSyncPoint(sync_point);
+}
+
bool WebGraphicsContext3DCommandBufferImpl::SetParent(
WebGraphicsContext3DCommandBufferImpl* new_parent) {
if (parent_ == new_parent)
diff --git a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
index 2cabdd3..8e8b649 100644
--- a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
+++ b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
@@ -142,6 +142,9 @@ class WebGraphicsContext3DCommandBufferImpl
virtual bool setParentContext(WebGraphicsContext3D* parent_context);
+ virtual unsigned int insertSyncPoint();
+ virtual void waitSyncPoint(unsigned int);
+
virtual void reshape(int width, int height);
virtual bool readBackFramebuffer(unsigned char* pixels, size_t buffer_size);
diff --git a/content/common/gpu/gpu_channel.cc b/content/common/gpu/gpu_channel.cc
index 41d86ba..fc6eab1 100644
--- a/content/common/gpu/gpu_channel.cc
+++ b/content/common/gpu/gpu_channel.cc
@@ -11,14 +11,18 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/debug/trace_event.h"
+#include "base/message_loop_proxy.h"
#include "base/process_util.h"
#include "base/string_util.h"
#include "content/common/child_process.h"
#include "content/common/gpu/gpu_channel_manager.h"
#include "content/common/gpu/gpu_messages.h"
+#include "content/common/gpu/sync_point_manager.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
#include "gpu/command_buffer/service/mailbox_manager.h"
+#include "ipc/ipc_channel.h"
+#include "ipc/ipc_channel_proxy.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_surface.h"
@@ -32,7 +36,101 @@ namespace {
// allow a pattern of alternating fast and slow frames to occur.
const int64 kHandleMoreWorkPeriodMs = 2;
const int64 kHandleMoreWorkPeriodBusyMs = 1;
-}
+
+// This filter handles the GpuCommandBufferMsg_InsertSyncPoint message on the IO
+// thread, generating the sync point ID and responding immediately, and then
+// posting a task to insert the GpuCommandBufferMsg_RetireSyncPoint message into
+// the channel's queue.
+class SyncPointMessageFilter : public IPC::ChannelProxy::MessageFilter {
+ public:
+ // Takes ownership of gpu_channel (see below).
+ SyncPointMessageFilter(base::WeakPtr<GpuChannel>* gpu_channel,
+ scoped_refptr<SyncPointManager> sync_point_manager,
+ scoped_refptr<base::MessageLoopProxy> message_loop)
+ : gpu_channel_(gpu_channel),
+ channel_(NULL),
+ sync_point_manager_(sync_point_manager),
+ message_loop_(message_loop) {
+ }
+
+ virtual void OnFilterAdded(IPC::Channel* channel) {
+ DCHECK(!channel_);
+ channel_ = channel;
+ }
+
+ virtual void OnFilterRemoved() {
+ DCHECK(channel_);
+ channel_ = NULL;
+ }
+
+ virtual bool OnMessageReceived(const IPC::Message& message) {
+ DCHECK(channel_);
+ if (message.type() == GpuCommandBufferMsg_InsertSyncPoint::ID) {
+ uint32 sync_point = sync_point_manager_->GenerateSyncPoint();
+ IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message);
+ GpuCommandBufferMsg_InsertSyncPoint::WriteReplyParams(reply, sync_point);
+ channel_->Send(reply);
+ message_loop_->PostTask(FROM_HERE, base::Bind(
+ &SyncPointMessageFilter::InsertSyncPointOnMainThread,
+ gpu_channel_,
+ sync_point_manager_,
+ message.routing_id(),
+ sync_point));
+ return true;
+ } else if (message.type() == GpuCommandBufferMsg_RetireSyncPoint::ID) {
+ // This message should not be sent explicitly by the renderer.
+ NOTREACHED();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ protected:
+ virtual ~SyncPointMessageFilter() {
+ message_loop_->PostTask(FROM_HERE, base::Bind(
+ &SyncPointMessageFilter::DeleteWeakPtrOnMainThread, gpu_channel_));
+ }
+
+ private:
+ static void InsertSyncPointOnMainThread(
+ base::WeakPtr<GpuChannel>* gpu_channel,
+ scoped_refptr<SyncPointManager> manager,
+ int32 routing_id,
+ uint32 sync_point) {
+ // This function must ensure that the sync point will be retired. Normally
+ // we'll find the stub based on the routing ID, and associate the sync point
+ // with it, but if that fails for any reason (channel or stub already
+ // deleted, invalid routing id), we need to retire the sync point
+ // immediately.
+ if (gpu_channel->get()) {
+ GpuCommandBufferStub* stub = gpu_channel->get()->LookupCommandBuffer(
+ routing_id);
+ if (stub) {
+ stub->AddSyncPoint(sync_point);
+ GpuCommandBufferMsg_RetireSyncPoint message(routing_id, sync_point);
+ gpu_channel->get()->OnMessageReceived(message);
+ return;
+ }
+ }
+ manager->RetireSyncPoint(sync_point);
+ }
+
+ static void DeleteWeakPtrOnMainThread(
+ base::WeakPtr<GpuChannel>* gpu_channel) {
+ delete gpu_channel;
+ }
+
+ // NOTE: this is a pointer to a weak pointer. It is never dereferenced on the
+ // IO thread, it's only passed through - therefore the WeakPtr assumptions are
+ // respected.
+ base::WeakPtr<GpuChannel>* gpu_channel_;
+ IPC::Channel* channel_;
+ scoped_refptr<SyncPointManager> sync_point_manager_;
+ scoped_refptr<base::MessageLoopProxy> message_loop_;
+};
+
+} // anonymous namespace
GpuChannel::GpuChannel(GpuChannelManager* gpu_channel_manager,
GpuWatchdog* watchdog,
@@ -73,6 +171,14 @@ bool GpuChannel::Init(base::MessageLoopProxy* io_message_loop,
false,
shutdown_event));
+ base::WeakPtr<GpuChannel>* weak_ptr(new base::WeakPtr<GpuChannel>(
+ weak_factory_.GetWeakPtr()));
+ scoped_refptr<SyncPointMessageFilter> filter(new SyncPointMessageFilter(
+ weak_ptr,
+ gpu_channel_manager_->sync_point_manager(),
+ base::MessageLoopProxy::current()));
+ channel_->AddFilter(filter);
+
return true;
}
diff --git a/content/common/gpu/gpu_channel_manager.cc b/content/common/gpu/gpu_channel_manager.cc
index 46b6d8c..4d4b26a 100644
--- a/content/common/gpu/gpu_channel_manager.cc
+++ b/content/common/gpu/gpu_channel_manager.cc
@@ -9,6 +9,7 @@
#include "content/common/gpu/gpu_channel.h"
#include "content/common/gpu/gpu_memory_manager.h"
#include "content/common/gpu/gpu_messages.h"
+#include "content/common/gpu/sync_point_manager.h"
#include "ui/gl/gl_share_group.h"
GpuChannelManager::GpuChannelManager(ChildThread* gpu_child_thread,
@@ -21,7 +22,8 @@ GpuChannelManager::GpuChannelManager(ChildThread* gpu_child_thread,
gpu_child_thread_(gpu_child_thread),
ALLOW_THIS_IN_INITIALIZER_LIST(gpu_memory_manager_(this,
GpuMemoryManager::kDefaultMaxSurfacesWithFrontbufferSoftLimit)),
- watchdog_(watchdog) {
+ watchdog_(watchdog),
+ sync_point_manager_(new SyncPointManager) {
DCHECK(gpu_child_thread);
DCHECK(io_message_loop);
DCHECK(shutdown_event);
diff --git a/content/common/gpu/gpu_channel_manager.h b/content/common/gpu/gpu_channel_manager.h
index 9fe1b26..187e6f5 100644
--- a/content/common/gpu/gpu_channel_manager.h
+++ b/content/common/gpu/gpu_channel_manager.h
@@ -32,6 +32,7 @@ class ChildThread;
class GpuChannel;
class GpuWatchdog;
struct GPUCreateCommandBufferConfig;
+class SyncPointManager;
// A GpuChannelManager is a thread responsible for issuing rendering commands
// managing the lifetimes of GPU channels and forwarding IPC requests from the
@@ -78,6 +79,8 @@ class GpuChannelManager : public IPC::Channel::Listener,
GpuChannel* LookupChannel(int32 client_id);
+ SyncPointManager* sync_point_manager() { return sync_point_manager_; }
+
private:
// Message handlers.
void OnEstablishChannel(int client_id, bool share_context);
@@ -106,6 +109,7 @@ class GpuChannelManager : public IPC::Channel::Listener,
scoped_refptr<gfx::GLShareGroup> share_group_;
GpuMemoryManager gpu_memory_manager_;
GpuWatchdog* watchdog_;
+ scoped_refptr<SyncPointManager> sync_point_manager_;
DISALLOW_COPY_AND_ASSIGN(GpuChannelManager);
};
diff --git a/content/common/gpu/gpu_command_buffer_stub.cc b/content/common/gpu/gpu_command_buffer_stub.cc
index f19ab61..35f9a58 100644
--- a/content/common/gpu/gpu_command_buffer_stub.cc
+++ b/content/common/gpu/gpu_command_buffer_stub.cc
@@ -18,6 +18,7 @@
#include "content/common/gpu/gpu_messages.h"
#include "content/common/gpu/gpu_watchdog.h"
#include "content/common/gpu/image_transport_surface.h"
+#include "content/common/gpu/sync_point_manager.h"
#include "gpu/command_buffer/common/constants.h"
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
#include "ui/gl/gl_bindings.h"
@@ -131,6 +132,10 @@ bool GpuCommandBufferStub::OnMessageReceived(const IPC::Message& message) {
OnDiscardBackbuffer)
IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_EnsureBackbuffer,
OnEnsureBackbuffer)
+ IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_RetireSyncPoint,
+ OnRetireSyncPoint)
+ IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_WaitSyncPoint,
+ OnWaitSyncPoint)
IPC_MESSAGE_HANDLER(
GpuCommandBufferMsg_SetClientHasMemoryAllocationChangedCallback,
OnSetClientHasMemoryAllocationChangedCallback)
@@ -200,6 +205,9 @@ void GpuCommandBufferStub::OnReschedule() {
}
void GpuCommandBufferStub::Destroy() {
+ while (!sync_points_.empty())
+ OnRetireSyncPoint(sync_points_.front());
+
// The scheduler has raw references to the decoder and the command buffer so
// destroy it before those.
scheduler_.reset();
@@ -608,6 +616,34 @@ void GpuCommandBufferStub::OnEnsureBackbuffer() {
surface_->SetBackbufferAllocation(true);
}
+void GpuCommandBufferStub::AddSyncPoint(uint32 sync_point) {
+ sync_points_.push_back(sync_point);
+}
+
+void GpuCommandBufferStub::OnRetireSyncPoint(uint32 sync_point) {
+ DCHECK(!sync_points_.empty() && sync_points_.front() == sync_point);
+ sync_points_.pop_front();
+ GpuChannelManager* manager = channel_->gpu_channel_manager();
+ manager->sync_point_manager()->RetireSyncPoint(sync_point);
+}
+
+void GpuCommandBufferStub::OnWaitSyncPoint(uint32 sync_point) {
+ if (!scheduler_.get())
+ return;
+ scheduler_->SetScheduled(false);
+ GpuChannelManager* manager = channel_->gpu_channel_manager();
+ manager->sync_point_manager()->AddSyncPointCallback(
+ sync_point,
+ base::Bind(&GpuCommandBufferStub::OnSyncPointRetired,
+ this->AsWeakPtr()));
+}
+
+void GpuCommandBufferStub::OnSyncPointRetired() {
+ if (!scheduler_.get())
+ return;
+ scheduler_->SetScheduled(true);
+}
+
void GpuCommandBufferStub::OnSetClientHasMemoryAllocationChangedCallback(
bool has_callback) {
TRACE_EVENT0(
diff --git a/content/common/gpu/gpu_command_buffer_stub.h b/content/common/gpu/gpu_command_buffer_stub.h
index 2c81c98..ee4f463 100644
--- a/content/common/gpu/gpu_command_buffer_stub.h
+++ b/content/common/gpu/gpu_command_buffer_stub.h
@@ -6,8 +6,7 @@
#define CONTENT_COMMON_GPU_GPU_COMMAND_BUFFER_STUB_H_
#pragma once
-#if defined(ENABLE_GPU)
-
+#include <deque>
#include <string>
#include <vector>
@@ -167,6 +166,10 @@ class GpuCommandBufferStub
void AddDestructionObserver(DestructionObserver* observer);
void RemoveDestructionObserver(DestructionObserver* observer);
+ // Associates a sync point to this stub. When the stub is destroyed, it will
+ // retire all sync points that haven't been previously retired.
+ void AddSyncPoint(uint32 sync_point);
+
private:
void Destroy();
@@ -205,6 +208,10 @@ class GpuCommandBufferStub
void OnDiscardBackbuffer();
void OnEnsureBackbuffer();
+ void OnRetireSyncPoint(uint32 sync_point);
+ void OnWaitSyncPoint(uint32 sync_point);
+ void OnSyncPointRetired();
+
void OnSetClientHasMemoryAllocationChangedCallback(bool);
void OnReschedule();
@@ -255,9 +262,10 @@ class GpuCommandBufferStub
ObserverList<DestructionObserver> destruction_observers_;
+ // A queue of sync points associated with this stub.
+ std::deque<uint32> sync_points_;
+
DISALLOW_COPY_AND_ASSIGN(GpuCommandBufferStub);
};
-#endif // defined(ENABLE_GPU)
-
#endif // CONTENT_COMMON_GPU_GPU_COMMAND_BUFFER_STUB_H_
diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h
index 945928b..cd8a7b5 100644
--- a/content/common/gpu/gpu_messages.h
+++ b/content/common/gpu/gpu_messages.h
@@ -458,6 +458,23 @@ IPC_MESSAGE_ROUTED1(
GpuCommandBufferMsg_SetClientHasMemoryAllocationChangedCallback,
bool /* has_callback */)
+// Inserts a sync point into the channel. This is handled on the IO thread, so
+// can be expected to be reasonably fast, but the sync point is actually
+// retired in order with respect to the other calls. The sync point is shared
+// across channels.
+IPC_SYNC_MESSAGE_ROUTED0_1(GpuCommandBufferMsg_InsertSyncPoint,
+ uint32 /* sync_point */)
+
+// Retires the sync point. Note: this message is not sent explicitly by the
+// renderer, but is synthesized by the GPU process.
+IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_RetireSyncPoint,
+ uint32 /* sync_point */)
+
+// Makes this command buffer wait on a sync point. Command buffer message
+// execution will be delayed until the sync point has been reached.
+IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_WaitSyncPoint,
+ uint32 /* sync_point */)
+
//------------------------------------------------------------------------------
// Accelerated Video Decoder Messages
// These messages are sent from Renderer process to GPU process.
diff --git a/content/common/gpu/sync_point_manager.cc b/content/common/gpu/sync_point_manager.cc
new file mode 100644
index 0000000..edf5104
--- /dev/null
+++ b/content/common/gpu/sync_point_manager.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/gpu/sync_point_manager.h"
+
+#include "base/logging.h"
+
+SyncPointManager::SyncPointManager()
+ : next_sync_point_(1) {
+}
+
+SyncPointManager::~SyncPointManager() {
+}
+
+uint32 SyncPointManager::GenerateSyncPoint() {
+ base::AutoLock lock(lock_);
+ uint32 sync_point = next_sync_point_++;
+
+ // Note: wrapping would take days for a buggy/compromized renderer that would
+ // insert sync points in a loop, but if that were to happen, better explicitly
+ // crash the GPU process than risk worse.
+ // For normal operation (at most a few per frame), it would take ~a year to
+ // wrap.
+ CHECK(sync_point_map_.find(sync_point) == sync_point_map_.end());
+ sync_point_map_.insert(std::make_pair(sync_point, ClosureList()));
+ return sync_point;
+}
+
+void SyncPointManager::RetireSyncPoint(uint32 sync_point) {
+ DCHECK(CalledOnValidThread());
+ ClosureList list;
+ {
+ base::AutoLock lock(lock_);
+ SyncPointMap::iterator it = sync_point_map_.find(sync_point);
+ DCHECK(it != sync_point_map_.end());
+ list.swap(it->second);
+ sync_point_map_.erase(it);
+ }
+ for (ClosureList::iterator i = list.begin(); i != list.end(); ++i)
+ i->Run();
+}
+
+void SyncPointManager::AddSyncPointCallback(uint32 sync_point,
+ const base::Closure& callback) {
+ DCHECK(CalledOnValidThread());
+ {
+ base::AutoLock lock(lock_);
+ SyncPointMap::iterator it = sync_point_map_.find(sync_point);
+ if (it != sync_point_map_.end()) {
+ it->second.push_back(callback);
+ return;
+ }
+ }
+ callback.Run();
+}
diff --git a/content/common/gpu/sync_point_manager.h b/content/common/gpu/sync_point_manager.h
new file mode 100644
index 0000000..589aace
--- /dev/null
+++ b/content/common/gpu/sync_point_manager.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_GPU_SYNC_POINT_MANAGER_H_
+#define CONTENT_COMMON_GPU_SYNC_POINT_MANAGER_H_
+#pragma once
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
+
+// This class manages the sync points, which allow cross-channel
+// synchronization.
+class SyncPointManager : public base::RefCountedThreadSafe<SyncPointManager>,
+ public base::ThreadChecker {
+ public:
+ SyncPointManager();
+
+ // Generates a sync point, returning its ID. This can me called on any thread.
+ // IDs start at 1.
+ uint32 GenerateSyncPoint();
+
+ // Retires a sync point. This will call all the registered callbacks for this
+ // sync point. This can only be called on the main thread.
+ void RetireSyncPoint(uint32 sync_point);
+
+ // Adds a callback to the sync point. The callback will be called when the
+ // sync point is retired, or immediately (from within that function) if the
+ // sync point was already retired (or not created yet). This can only be
+ // called on the main thread.
+ void AddSyncPointCallback(uint32 sync_point, const base::Closure& callback);
+
+ private:
+ friend class base::RefCountedThreadSafe<SyncPointManager>;
+ typedef std::vector<base::Closure> ClosureList;
+ typedef base::hash_map<uint32, ClosureList > SyncPointMap;
+
+ ~SyncPointManager();
+
+ // Protects the 2 fields below. Note: callbacks shouldn't be called with this
+ // held.
+ base::Lock lock_;
+ SyncPointMap sync_point_map_;
+ uint32 next_sync_point_;
+
+ DISALLOW_COPY_AND_ASSIGN(SyncPointManager);
+};
+
+#endif // CONTENT_COMMON_GPU_SYNC_POINT_MANAGER_H_
diff --git a/content/content_common.gypi b/content/content_common.gypi
index a838085..767602c 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -199,6 +199,8 @@
'common/gpu/media/mac_video_decode_accelerator.mm',
'common/gpu/media/gpu_video_decode_accelerator.cc',
'common/gpu/media/gpu_video_decode_accelerator.h',
+ 'common/gpu/sync_point_manager.h',
+ 'common/gpu/sync_point_manager.cc',
'common/gpu/texture_image_transport_surface.h',
'common/gpu/texture_image_transport_surface.cc',
'common/handle_enumerator_win.cc',
diff --git a/gpu/ipc/command_buffer_proxy.h b/gpu/ipc/command_buffer_proxy.h
index 4f53fb0..d4412f0 100644
--- a/gpu/ipc/command_buffer_proxy.h
+++ b/gpu/ipc/command_buffer_proxy.h
@@ -37,6 +37,17 @@ class GPU_EXPORT CommandBufferProxy : public gpu::CommandBuffer {
virtual bool DiscardBackbuffer() = 0;
virtual bool EnsureBackbuffer() = 0;
+ // Inserts a sync point, returning its ID. This is handled on the IO thread of
+ // the GPU process, and so should be relatively fast, but its effect is
+ // ordered wrt other messages (in particular, Flush). Sync point IDs are
+ // global and can be used for cross-channel synchronization.
+ virtual uint32 InsertSyncPoint() = 0;
+
+ // Makes this command buffer wait on a sync point. This command buffer will be
+ // unscheduled until the command buffer that inserted that sync point reaches
+ // it, or gets destroyed.
+ virtual void WaitSyncPoint(uint32) = 0;
+
// Register a callback to invoke whenever we recieve a new memory allocation.
virtual void SetMemoryAllocationChangedCallback(
const base::Callback<void(const GpuMemoryAllocationForRenderer&)>&
diff --git a/ppapi/proxy/ppapi_command_buffer_proxy.cc b/ppapi/proxy/ppapi_command_buffer_proxy.cc
index d3fed94a..371870e 100644
--- a/ppapi/proxy/ppapi_command_buffer_proxy.cc
+++ b/ppapi/proxy/ppapi_command_buffer_proxy.cc
@@ -60,6 +60,15 @@ bool PpapiCommandBufferProxy::EnsureBackbuffer() {
return true;
}
+uint32 PpapiCommandBufferProxy::InsertSyncPoint() {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+void PpapiCommandBufferProxy::WaitSyncPoint(uint32 sync_point) {
+ NOTIMPLEMENTED();
+}
+
void PpapiCommandBufferProxy::SetMemoryAllocationChangedCallback(
const base::Callback<void(const GpuMemoryAllocationForRenderer&)>&
callback) {
@@ -277,4 +286,3 @@ void PpapiCommandBufferProxy::UpdateState(
} // namespace proxy
} // namespace ppapi
-
diff --git a/ppapi/proxy/ppapi_command_buffer_proxy.h b/ppapi/proxy/ppapi_command_buffer_proxy.h
index 015ce38..0a5cde5 100644
--- a/ppapi/proxy/ppapi_command_buffer_proxy.h
+++ b/ppapi/proxy/ppapi_command_buffer_proxy.h
@@ -36,6 +36,8 @@ class PPAPI_PROXY_EXPORT PpapiCommandBufferProxy : public CommandBufferProxy {
virtual bool SetSurfaceVisible(bool visible) OVERRIDE;
virtual bool DiscardBackbuffer() OVERRIDE;
virtual bool EnsureBackbuffer() OVERRIDE;
+ virtual uint32 InsertSyncPoint() OVERRIDE;
+ virtual void WaitSyncPoint(uint32 sync_point) OVERRIDE;
virtual void SetMemoryAllocationChangedCallback(
const base::Callback<void(const GpuMemoryAllocationForRenderer&)>&
callback) OVERRIDE;