1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/gl/gl_fence.h"
7 #include "base/compiler_specific.h"
8 #include "ui/gl/gl_bindings.h"
9 #include "ui/gl/gl_context.h"
10 #include "ui/gl/gl_version_info.h"
14 class GLFenceNVFence
: public gfx::GLFence
{
16 GLFenceNVFence(bool flush
) {
17 // What if either of these GL calls fails? TestFenceNV will return true.
19 // http://www.opengl.org/registry/specs/NV/fence.txt
21 // What should happen if TestFenceNV is called for a name before SetFenceNV
23 // We generate an INVALID_OPERATION error, and return TRUE.
24 // This follows the semantics for texture object names before
25 // they are bound, in that they acquire their state upon binding.
26 // We will arbitrarily return TRUE for consistency.
27 glGenFencesNV(1, &fence_
);
28 glSetFenceNV(fence_
, GL_ALL_COMPLETED_NV
);
32 flush_event_
= gfx::GLContext::GetCurrent()->SignalFlush();
36 virtual bool HasCompleted() OVERRIDE
{
37 return !!glTestFenceNV(fence_
);
40 virtual void ClientWait() OVERRIDE
{
41 if (!flush_event_
|| flush_event_
->IsSignaled()) {
42 glFinishFenceNV(fence_
);
44 LOG(ERROR
) << "Trying to wait for uncommitted fence. Skipping...";
48 virtual void ServerWait() OVERRIDE
{
53 virtual ~GLFenceNVFence() {
54 glDeleteFencesNV(1, &fence_
);
58 scoped_refptr
<gfx::GLContext::FlushEvent
> flush_event_
;
61 class GLFenceARBSync
: public gfx::GLFence
{
63 GLFenceARBSync(bool flush
) {
64 sync_
= glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE
, 0);
68 flush_event_
= gfx::GLContext::GetCurrent()->SignalFlush();
72 virtual bool HasCompleted() OVERRIDE
{
73 // Handle the case where FenceSync failed.
77 // We could potentially use glGetSynciv here, but it doesn't work
78 // on OSX 10.7 (always says the fence is not signaled yet).
79 // glClientWaitSync works better, so let's use that instead.
80 return glClientWaitSync(sync_
, 0, 0) != GL_TIMEOUT_EXPIRED
;
83 virtual void ClientWait() OVERRIDE
{
84 if (!flush_event_
|| flush_event_
->IsSignaled()) {
85 glClientWaitSync(sync_
, GL_SYNC_FLUSH_COMMANDS_BIT
, GL_TIMEOUT_IGNORED
);
87 LOG(ERROR
) << "Trying to wait for uncommitted fence. Skipping...";
91 virtual void ServerWait() OVERRIDE
{
92 if (!flush_event_
|| flush_event_
->IsSignaled()) {
93 glWaitSync(sync_
, 0, GL_TIMEOUT_IGNORED
);
95 LOG(ERROR
) << "Trying to wait for uncommitted fence. Skipping...";
100 virtual ~GLFenceARBSync() {
105 scoped_refptr
<gfx::GLContext::FlushEvent
> flush_event_
;
108 #if !defined(OS_MACOSX)
109 class EGLFenceSync
: public gfx::GLFence
{
111 EGLFenceSync(bool flush
) {
112 display_
= eglGetCurrentDisplay();
113 sync_
= eglCreateSyncKHR(display_
, EGL_SYNC_FENCE_KHR
, NULL
);
117 flush_event_
= gfx::GLContext::GetCurrent()->SignalFlush();
121 virtual bool HasCompleted() OVERRIDE
{
123 eglGetSyncAttribKHR(display_
, sync_
, EGL_SYNC_STATUS_KHR
, &value
);
124 DCHECK(value
== EGL_SIGNALED_KHR
|| value
== EGL_UNSIGNALED_KHR
);
125 return !value
|| value
== EGL_SIGNALED_KHR
;
128 virtual void ClientWait() OVERRIDE
{
129 if (!flush_event_
|| flush_event_
->IsSignaled()) {
131 EGLTimeKHR time
= EGL_FOREVER_KHR
;
132 eglClientWaitSyncKHR(display_
, sync_
, flags
, time
);
134 LOG(ERROR
) << "Trying to wait for uncommitted fence. Skipping...";
138 virtual void ServerWait() OVERRIDE
{
139 if (!flush_event_
|| flush_event_
->IsSignaled()) {
141 eglWaitSyncKHR(display_
, sync_
, flags
);
143 LOG(ERROR
) << "Trying to wait for uncommitted fence. Skipping...";
149 virtual ~EGLFenceSync() {
150 eglDestroySyncKHR(display_
, sync_
);
155 scoped_refptr
<gfx::GLContext::FlushEvent
> flush_event_
;
160 gfx::GLFence
* CreateFence(bool flush
) {
161 DCHECK(gfx::GLContext::GetCurrent())
162 << "Trying to create fence with no context";
164 #if !defined(OS_MACOSX)
165 if (gfx::g_driver_egl
.ext
.b_EGL_KHR_fence_sync
)
166 return new EGLFenceSync(flush
);
168 // Prefer ARB_sync which supports server-side wait.
169 if (gfx::g_driver_gl
.ext
.b_GL_ARB_sync
||
170 gfx::GLContext::GetCurrent()->GetVersionInfo()->is_es3
)
171 return new GLFenceARBSync(flush
);
172 if (gfx::g_driver_gl
.ext
.b_GL_NV_fence
)
173 return new GLFenceNVFence(flush
);
184 GLFence::~GLFence() {
187 GLFence
* GLFence::Create() {
188 return CreateFence(true);
191 GLFence
* GLFence::CreateWithoutFlush() {
192 return CreateFence(false);