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.
4
5 #include "ui/gl/gl_fence.h"
6
7 #include "base/compiler_specific.h"
8 #include "ui/gl/gl_bindings.h"
9 #include "ui/gl/gl_context.h"
10
11 namespace {
12
13 class GLFenceNVFence: public gfx::GLFence {
14 public:
GLFenceNVFence(bool flush)15 GLFenceNVFence(bool flush) {
16 // What if either of these GL calls fails? TestFenceNV will return true.
17 // See spec:
18 // http://www.opengl.org/registry/specs/NV/fence.txt
19 //
20 // What should happen if TestFenceNV is called for a name before SetFenceNV
21 // is called?
22 // We generate an INVALID_OPERATION error, and return TRUE.
23 // This follows the semantics for texture object names before
24 // they are bound, in that they acquire their state upon binding.
25 // We will arbitrarily return TRUE for consistency.
26 glGenFencesNV(1, &fence_);
27 glSetFenceNV(fence_, GL_ALL_COMPLETED_NV);
28 if (flush)
29 glFlush();
30 }
31
HasCompleted()32 virtual bool HasCompleted() OVERRIDE {
33 return !!glTestFenceNV(fence_);
34 }
35
ClientWait()36 virtual void ClientWait() OVERRIDE {
37 glFinishFenceNV(fence_);
38 }
39
ServerWait()40 virtual void ServerWait() OVERRIDE {
41 glFinishFenceNV(fence_);
42 }
43
44 private:
~GLFenceNVFence()45 virtual ~GLFenceNVFence() {
46 glDeleteFencesNV(1, &fence_);
47 }
48
49 GLuint fence_;
50 };
51
52 class GLFenceARBSync: public gfx::GLFence {
53 public:
GLFenceARBSync(bool flush)54 GLFenceARBSync(bool flush) {
55 sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
56 if (flush)
57 glFlush();
58 }
59
HasCompleted()60 virtual bool HasCompleted() OVERRIDE {
61 // Handle the case where FenceSync failed.
62 if (!sync_)
63 return true;
64
65 // We could potentially use glGetSynciv here, but it doesn't work
66 // on OSX 10.7 (always says the fence is not signaled yet).
67 // glClientWaitSync works better, so let's use that instead.
68 return glClientWaitSync(sync_, 0, 0) != GL_TIMEOUT_EXPIRED;
69 }
70
ClientWait()71 virtual void ClientWait() OVERRIDE {
72 glClientWaitSync(sync_, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
73 }
74
ServerWait()75 virtual void ServerWait() OVERRIDE {
76 glWaitSync(sync_, 0, GL_TIMEOUT_IGNORED);
77 }
78
79 private:
~GLFenceARBSync()80 virtual ~GLFenceARBSync() {
81 glDeleteSync(sync_);
82 }
83
84 GLsync sync_;
85 };
86
87 #if !defined(OS_MACOSX)
88 class EGLFenceSync : public gfx::GLFence {
89 public:
EGLFenceSync(bool flush)90 EGLFenceSync(bool flush) {
91 display_ = eglGetCurrentDisplay();
92 sync_ = eglCreateSyncKHR(display_, EGL_SYNC_FENCE_KHR, NULL);
93 if (flush)
94 glFlush();
95 }
96
HasCompleted()97 virtual bool HasCompleted() OVERRIDE {
98 EGLint value = 0;
99 eglGetSyncAttribKHR(display_, sync_, EGL_SYNC_STATUS_KHR, &value);
100 DCHECK(value == EGL_SIGNALED_KHR || value == EGL_UNSIGNALED_KHR);
101 return !value || value == EGL_SIGNALED_KHR;
102 }
103
ClientWait()104 virtual void ClientWait() OVERRIDE {
105 EGLint flags = 0;
106 EGLTimeKHR time = EGL_FOREVER_KHR;
107 eglClientWaitSyncKHR(display_, sync_, flags, time);
108 }
109
ServerWait()110 virtual void ServerWait() OVERRIDE {
111 EGLint flags = 0;
112 eglWaitSyncKHR(display_, sync_, flags);
113 }
114
115
116 private:
~EGLFenceSync()117 virtual ~EGLFenceSync() {
118 eglDestroySyncKHR(display_, sync_);
119 }
120
121 EGLSyncKHR sync_;
122 EGLDisplay display_;
123 };
124 #endif // !OS_MACOSX
125
126 // static
CreateFence(bool flush)127 gfx::GLFence* CreateFence(bool flush) {
128 #if !defined(OS_MACOSX)
129 if (gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync)
130 return new EGLFenceSync(flush);
131 #endif
132 if (gfx::g_driver_gl.ext.b_GL_NV_fence)
133 return new GLFenceNVFence(flush);
134 if (gfx::g_driver_gl.ext.b_GL_ARB_sync)
135 return new GLFenceARBSync(flush);
136 return NULL;
137 }
138
139 } // namespace
140
141 namespace gfx {
142
GLFence()143 GLFence::GLFence() {
144 }
145
~GLFence()146 GLFence::~GLFence() {
147 }
148
Create()149 GLFence* GLFence::Create() {
150 return CreateFence(true);
151 }
152
CreateWithoutFlush()153 GLFence* GLFence::CreateWithoutFlush() {
154 return CreateFence(false);
155 }
156
157 } // namespace gfx
158