| // 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 "ui/gl/gl_fence.h" |
| |
| #include "base/compiler_specific.h" |
| #include "ui/gl/gl_bindings.h" |
| #include "ui/gl/gl_context.h" |
| |
| namespace { |
| |
| class GLFenceNVFence: public gfx::GLFence { |
| public: |
| GLFenceNVFence(bool flush) { |
| // What if either of these GL calls fails? TestFenceNV will return true. |
| // See spec: |
| // http://www.opengl.org/registry/specs/NV/fence.txt |
| // |
| // What should happen if TestFenceNV is called for a name before SetFenceNV |
| // is called? |
| // We generate an INVALID_OPERATION error, and return TRUE. |
| // This follows the semantics for texture object names before |
| // they are bound, in that they acquire their state upon binding. |
| // We will arbitrarily return TRUE for consistency. |
| glGenFencesNV(1, &fence_); |
| glSetFenceNV(fence_, GL_ALL_COMPLETED_NV); |
| if (flush) |
| glFlush(); |
| } |
| |
| virtual bool HasCompleted() OVERRIDE { |
| return !!glTestFenceNV(fence_); |
| } |
| |
| virtual void ClientWait() OVERRIDE { |
| glFinishFenceNV(fence_); |
| } |
| |
| virtual void ServerWait() OVERRIDE { |
| glFinishFenceNV(fence_); |
| } |
| |
| private: |
| virtual ~GLFenceNVFence() { |
| glDeleteFencesNV(1, &fence_); |
| } |
| |
| GLuint fence_; |
| }; |
| |
| class GLFenceARBSync: public gfx::GLFence { |
| public: |
| GLFenceARBSync(bool flush) { |
| sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); |
| if (flush) |
| glFlush(); |
| } |
| |
| virtual bool HasCompleted() OVERRIDE { |
| // Handle the case where FenceSync failed. |
| if (!sync_) |
| return true; |
| |
| // We could potentially use glGetSynciv here, but it doesn't work |
| // on OSX 10.7 (always says the fence is not signaled yet). |
| // glClientWaitSync works better, so let's use that instead. |
| return glClientWaitSync(sync_, 0, 0) != GL_TIMEOUT_EXPIRED; |
| } |
| |
| virtual void ClientWait() OVERRIDE { |
| glClientWaitSync(sync_, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED); |
| } |
| |
| virtual void ServerWait() OVERRIDE { |
| glWaitSync(sync_, 0, GL_TIMEOUT_IGNORED); |
| } |
| |
| private: |
| virtual ~GLFenceARBSync() { |
| glDeleteSync(sync_); |
| } |
| |
| GLsync sync_; |
| }; |
| |
| #if !defined(OS_MACOSX) |
| class EGLFenceSync : public gfx::GLFence { |
| public: |
| EGLFenceSync(bool flush) { |
| display_ = eglGetCurrentDisplay(); |
| sync_ = eglCreateSyncKHR(display_, EGL_SYNC_FENCE_KHR, NULL); |
| if (flush) |
| glFlush(); |
| } |
| |
| virtual bool HasCompleted() OVERRIDE { |
| EGLint value = 0; |
| eglGetSyncAttribKHR(display_, sync_, EGL_SYNC_STATUS_KHR, &value); |
| DCHECK(value == EGL_SIGNALED_KHR || value == EGL_UNSIGNALED_KHR); |
| return !value || value == EGL_SIGNALED_KHR; |
| } |
| |
| virtual void ClientWait() OVERRIDE { |
| EGLint flags = 0; |
| EGLTimeKHR time = EGL_FOREVER_KHR; |
| eglClientWaitSyncKHR(display_, sync_, flags, time); |
| } |
| |
| virtual void ServerWait() OVERRIDE { |
| EGLint flags = 0; |
| eglWaitSyncKHR(display_, sync_, flags); |
| } |
| |
| |
| private: |
| virtual ~EGLFenceSync() { |
| eglDestroySyncKHR(display_, sync_); |
| } |
| |
| EGLSyncKHR sync_; |
| EGLDisplay display_; |
| }; |
| #endif // !OS_MACOSX |
| |
| // static |
| gfx::GLFence* CreateFence(bool flush) { |
| #if !defined(OS_MACOSX) |
| if (gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync) |
| return new EGLFenceSync(flush); |
| #endif |
| if (gfx::g_driver_gl.ext.b_GL_NV_fence) |
| return new GLFenceNVFence(flush); |
| if (gfx::g_driver_gl.ext.b_GL_ARB_sync) |
| return new GLFenceARBSync(flush); |
| return NULL; |
| } |
| |
| } // namespace |
| |
| namespace gfx { |
| |
| GLFence::GLFence() { |
| } |
| |
| GLFence::~GLFence() { |
| } |
| |
| GLFence* GLFence::Create() { |
| return CreateFence(true); |
| } |
| |
| GLFence* GLFence::CreateWithoutFlush() { |
| return CreateFence(false); |
| } |
| |
| } // namespace gfx |