Home | History | Annotate | Download | only in gl
      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