diff --git a/chromium/content/common/gpu/gpu_channel_manager.cc b/chromium/content/common/gpu/gpu_channel_manager.cc index 2c93ef449102e6772691f4dae088726d5fea56b1..97bbbbb0b813607f3df103e1b45bc4ad59769084 100644 --- a/chromium/content/common/gpu/gpu_channel_manager.cc +++ b/chromium/content/common/gpu/gpu_channel_manager.cc @@ -56,6 +56,7 @@ GpuChannelManager::~GpuChannelManager() { default_offscreen_surface_ = NULL; } DCHECK(image_operations_.empty()); + DCHECK(sync_point_gl_fences_.empty()); } gpu::gles2::ProgramCache* GpuChannelManager::program_cache() { diff --git a/chromium/content/common/gpu/gpu_channel_manager.h b/chromium/content/common/gpu/gpu_channel_manager.h index 4c23f8009d0c81f00102e3c3fcb46f8aefae311c..dcaf3f11c05df3ba8134dd2240eae50f695485de 100644 --- a/chromium/content/common/gpu/gpu_channel_manager.h +++ b/chromium/content/common/gpu/gpu_channel_manager.h @@ -27,6 +27,7 @@ class WaitableEvent; } namespace gfx { +class GLFence; class GLShareGroup; struct GpuMemoryBufferHandle; } @@ -97,6 +98,8 @@ class GpuChannelManager : public IPC::Listener, GpuChannel* LookupChannel(int32 client_id); SyncPointManager* sync_point_manager() { return sync_point_manager_.get(); } + typedef base::hash_map<uint32, gfx::GLFence*> SyncPointGLFences; + SyncPointGLFences sync_point_gl_fences_; gfx::GLSurface* GetDefaultOffscreenSurface(); diff --git a/chromium/content/common/gpu/gpu_command_buffer_stub.cc b/chromium/content/common/gpu/gpu_command_buffer_stub.cc index 37f50a8cdf4c5b597c27a323d10d63d07bfffefd..84d611a8ce209f073e4ee40cab67675292ada5cb 100644 --- a/chromium/content/common/gpu/gpu_command_buffer_stub.cc +++ b/chromium/content/common/gpu/gpu_command_buffer_stub.cc @@ -35,6 +35,7 @@ #include "gpu/command_buffer/service/memory_tracking.h" #include "gpu/command_buffer/service/query_manager.h" #include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_fence.h" #include "ui/gl/gl_switches.h" #if defined(OS_WIN) @@ -111,6 +112,15 @@ const int64 kHandleMoreWorkPeriodBusyMs = 1; // Prevents idle work from being starved. const int64 kMaxTimeSinceIdleMs = 10; +void DestroyGLFence(GpuChannelManager::SyncPointGLFences &fences, uint32 sync_point) +{ + GpuChannelManager::SyncPointGLFences::iterator it = fences.find(sync_point); + if (it != fences.end()) { + delete it->second; + fences.erase(it); + } +} + } // namespace GpuCommandBufferStub::GpuCommandBufferStub( @@ -143,6 +153,7 @@ GpuCommandBufferStub::GpuCommandBufferStub( last_memory_allocation_valid_(false), watchdog_(watchdog), sync_point_wait_count_(0), + last_fence_sync_point_(0), delayed_work_scheduled_(false), previous_messages_processed_(0), active_url_(active_url), @@ -194,7 +205,10 @@ bool GpuCommandBufferStub::OnMessageReceived(const IPC::Message& message) { if (decoder_.get() && message.type() != GpuCommandBufferMsg_Echo::ID && message.type() != GpuCommandBufferMsg_WaitForTokenInRange::ID && message.type() != GpuCommandBufferMsg_WaitForGetOffsetInRange::ID && +#if !defined(TOOLKIT_QT) + // Qt needs the context to be current here to insert/destroy fences. message.type() != GpuCommandBufferMsg_RetireSyncPoint::ID && +#endif message.type() != GpuCommandBufferMsg_SetLatencyInfo::ID) { if (!MakeCurrent()) return false; @@ -402,6 +416,7 @@ void GpuCommandBufferStub::Destroy() { OnWillDestroyStub()); if (decoder_) { + DestroyGLFence(channel_->gpu_channel_manager()->sync_point_gl_fences_, last_fence_sync_point_); decoder_->Destroy(have_context); decoder_.reset(); } @@ -835,6 +850,23 @@ void GpuCommandBufferStub::OnRetireSyncPoint(uint32 sync_point) { if (context_group_->mailbox_manager()->UsesSync() && MakeCurrent()) context_group_->mailbox_manager()->PushTextureUpdates(); GpuChannelManager* manager = channel_->gpu_channel_manager(); + +#if defined(TOOLKIT_QT) + // Only keep the last fence alive to keep its temporary ownership in GpuCommandBufferStub + // simple in case where Qt would not pick this fence to eventually destroy it. + DestroyGLFence(manager->sync_point_gl_fences_, last_fence_sync_point_); + // We submitted all resource-producing GL commands, convert the logical sync point into a GL fence + // to allow Qt's GL context to wait for the results of commands submitted in this context using the + // sync point as reference. + scoped_ptr<gfx::GLFence> fence = scoped_ptr<gfx::GLFence>(gfx::GLFence::CreateWithoutFlush()); + if (fence) + manager->sync_point_gl_fences_.insert(std::make_pair(sync_point, fence.release())); + // Flush regardless of the success of the fence creation to at least make sure that commands + // producing our textures are in the pipe before the scene graph inserts its own on the other thread. + glFlush(); + last_fence_sync_point_ = sync_point; +#endif + manager->sync_point_manager()->RetireSyncPoint(sync_point); } diff --git a/chromium/content/common/gpu/gpu_command_buffer_stub.h b/chromium/content/common/gpu/gpu_command_buffer_stub.h index f660f1df3e89c77458a5e943466429c83b4c9050..d6dfb6fbba8bb8332672fc74a4dd7ba4da3101e2 100644 --- a/chromium/content/common/gpu/gpu_command_buffer_stub.h +++ b/chromium/content/common/gpu/gpu_command_buffer_stub.h @@ -266,6 +266,7 @@ class GpuCommandBufferStub // A queue of sync points associated with this stub. std::deque<uint32> sync_points_; int sync_point_wait_count_; + uint32 last_fence_sync_point_; bool delayed_work_scheduled_; uint64 previous_messages_processed_; diff --git a/chromium/ui/gl/gl_fence.cc b/chromium/ui/gl/gl_fence.cc index 073e6eea31465443db2bb2fad5b70b01a41378c2..69714e7d36e8bf107ba07cbd0b8bc2a683ffcb3e 100644 --- a/chromium/ui/gl/gl_fence.cc +++ b/chromium/ui/gl/gl_fence.cc @@ -33,6 +33,10 @@ class GLFenceNVFence: public gfx::GLFence { } } + virtual gfx::TransferableFence Transfer() OVERRIDE { + return gfx::TransferableFence(); + } + virtual bool HasCompleted() OVERRIDE { return !!glTestFenceNV(fence_); } @@ -69,6 +73,16 @@ class GLFenceARBSync: public gfx::GLFence { } } + virtual gfx::TransferableFence Transfer() OVERRIDE { + gfx::TransferableFence ret; + if (sync_) { + ret.type = gfx::TransferableFence::ArbSync; + ret.arb.sync = sync_; + sync_ = 0; + } + return ret; + } + virtual bool HasCompleted() OVERRIDE { // Handle the case where FenceSync failed. if (!sync_) @@ -98,7 +112,8 @@ class GLFenceARBSync: public gfx::GLFence { private: virtual ~GLFenceARBSync() { - glDeleteSync(sync_); + if (sync_) + glDeleteSync(sync_); } GLsync sync_; @@ -118,6 +133,15 @@ class EGLFenceSync : public gfx::GLFence { } } + virtual gfx::TransferableFence Transfer() OVERRIDE { + gfx::TransferableFence ret; + ret.type = gfx::TransferableFence::EglSync; + ret.egl.display = display_; + ret.egl.sync = sync_; + sync_ = 0; + return ret; + } + virtual bool HasCompleted() OVERRIDE { EGLint value = 0; eglGetSyncAttribKHR(display_, sync_, EGL_SYNC_STATUS_KHR, &value); diff --git a/chromium/ui/gl/gl_fence.h b/chromium/ui/gl/gl_fence.h index 021f3456f132c831417cb80f0a9f90f3b1d8709d..1d4e4cb72a080a597b4a13a08b989a4369b3df22 100644 --- a/chromium/ui/gl/gl_fence.h +++ b/chromium/ui/gl/gl_fence.h @@ -8,8 +8,34 @@ #include "base/basictypes.h" #include "ui/gl/gl_export.h" +typedef void *EGLDisplay; +typedef void *EGLSyncKHR; +typedef struct __GLsync *GLsync; + namespace gfx { +union TransferableFence { + enum SyncType { + NoSync, + EglSync, + ArbSync + }; + SyncType type; + struct { + SyncType type; + EGLDisplay display; + EGLSyncKHR sync; + } egl; + struct { + SyncType type; + GLsync sync; + } arb; + + TransferableFence() : type(NoSync) { } + operator bool() { return type != NoSync; } + void reset() { type = NoSync; } +}; + class GL_EXPORT GLFence { public: GLFence(); @@ -23,6 +49,8 @@ class GL_EXPORT GLFence { // context. static GLFence* CreateWithoutFlush(); + virtual TransferableFence Transfer() = 0; + virtual bool HasCompleted() = 0; virtual void ClientWait() = 0;