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: 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 32 virtual bool HasCompleted() OVERRIDE { 33 return !!glTestFenceNV(fence_); 34 } 35 36 virtual void ClientWait() OVERRIDE { 37 glFinishFenceNV(fence_); 38 } 39 40 virtual void ServerWait() OVERRIDE { 41 glFinishFenceNV(fence_); 42 } 43 44 private: 45 virtual ~GLFenceNVFence() { 46 glDeleteFencesNV(1, &fence_); 47 } 48 49 GLuint fence_; 50 }; 51 52 class GLFenceARBSync: public gfx::GLFence { 53 public: 54 GLFenceARBSync(bool flush) { 55 sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); 56 if (flush) 57 glFlush(); 58 } 59 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 71 virtual void ClientWait() OVERRIDE { 72 glClientWaitSync(sync_, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED); 73 } 74 75 virtual void ServerWait() OVERRIDE { 76 glWaitSync(sync_, 0, GL_TIMEOUT_IGNORED); 77 } 78 79 private: 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: 90 EGLFenceSync(bool flush) { 91 display_ = eglGetCurrentDisplay(); 92 sync_ = eglCreateSyncKHR(display_, EGL_SYNC_FENCE_KHR, NULL); 93 if (flush) 94 glFlush(); 95 } 96 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 104 virtual void ClientWait() OVERRIDE { 105 EGLint flags = 0; 106 EGLTimeKHR time = EGL_FOREVER_KHR; 107 eglClientWaitSyncKHR(display_, sync_, flags, time); 108 } 109 110 virtual void ServerWait() OVERRIDE { 111 EGLint flags = 0; 112 eglWaitSyncKHR(display_, sync_, flags); 113 } 114 115 116 private: 117 virtual ~EGLFenceSync() { 118 eglDestroySyncKHR(display_, sync_); 119 } 120 121 EGLSyncKHR sync_; 122 EGLDisplay display_; 123 }; 124 #endif // !OS_MACOSX 125 126 // static 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 143 GLFence::GLFence() { 144 } 145 146 GLFence::~GLFence() { 147 } 148 149 GLFence* GLFence::Create() { 150 return CreateFence(true); 151 } 152 153 GLFence* GLFence::CreateWithoutFlush() { 154 return CreateFence(false); 155 } 156 157 } // namespace gfx 158