15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_fence.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_bindings.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_context.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class GLFenceNVFence: public gfx::GLFence {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
15871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org  GLFenceNVFence(bool flush) {
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // What if either of these GL calls fails? TestFenceNV will return true.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // See spec:
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // http://www.opengl.org/registry/specs/NV/fence.txt
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // What should happen if TestFenceNV is called for a name before SetFenceNV
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // is called?
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //     We generate an INVALID_OPERATION error, and return TRUE.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //     This follows the semantics for texture object names before
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //     they are bound, in that they acquire their state upon binding.
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //     We will arbitrarily return TRUE for consistency.
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    glGenFencesNV(1, &fence_);
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    glSetFenceNV(fence_, GL_ALL_COMPLETED_NV);
28871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org    if (flush)
29871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org      glFlush();
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool HasCompleted() OVERRIDE {
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return !!glTestFenceNV(fence_);
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual void ClientWait() OVERRIDE {
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    glFinishFenceNV(fence_);
38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
40871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org  virtual void ServerWait() OVERRIDE {
41871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org    glFinishFenceNV(fence_);
42871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org  }
43871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~GLFenceNVFence() {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    glDeleteFencesNV(1, &fence_);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GLuint fence_;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class GLFenceARBSync: public gfx::GLFence {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
54871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org  GLFenceARBSync(bool flush) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
56871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org    if (flush)
57871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org      glFlush();
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool HasCompleted() OVERRIDE {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Handle the case where FenceSync failed.
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!sync_)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    // We could potentially use glGetSynciv here, but it doesn't work
66558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    // on OSX 10.7 (always says the fence is not signaled yet).
67558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    // glClientWaitSync works better, so let's use that instead.
68558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    return  glClientWaitSync(sync_, 0, 0) != GL_TIMEOUT_EXPIRED;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual void ClientWait() OVERRIDE {
72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    glClientWaitSync(sync_, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
75871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org  virtual void ServerWait() OVERRIDE {
76871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org    glWaitSync(sync_, 0, GL_TIMEOUT_IGNORED);
77871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org  }
78871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~GLFenceARBSync() {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    glDeleteSync(sync_);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GLsync sync_;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if !defined(OS_MACOSX)
88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass EGLFenceSync : public gfx::GLFence {
89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public:
90871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org  EGLFenceSync(bool flush) {
91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    display_ = eglGetCurrentDisplay();
92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    sync_ = eglCreateSyncKHR(display_, EGL_SYNC_FENCE_KHR, NULL);
93871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org    if (flush)
94871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org      glFlush();
95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual bool HasCompleted() OVERRIDE {
98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    EGLint value = 0;
99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    eglGetSyncAttribKHR(display_, sync_, EGL_SYNC_STATUS_KHR, &value);
100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DCHECK(value == EGL_SIGNALED_KHR || value == EGL_UNSIGNALED_KHR);
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return !value || value == EGL_SIGNALED_KHR;
102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual void ClientWait() OVERRIDE {
105424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    EGLint flags = 0;
106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    EGLTimeKHR time = EGL_FOREVER_KHR;
107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    eglClientWaitSyncKHR(display_, sync_, flags, time);
108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
110871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org  virtual void ServerWait() OVERRIDE {
111871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org    EGLint flags = 0;
112871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org    eglWaitSyncKHR(display_, sync_, flags);
113871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org  }
114871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org
115871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org
116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private:
117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual ~EGLFenceSync() {
118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    eglDestroySyncKHR(display_, sync_);
119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EGLSyncKHR sync_;
122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EGLDisplay display_;
123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif // !OS_MACOSX
125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
126871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org// static
127871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.orggfx::GLFence* CreateFence(bool flush) {
128871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org#if !defined(OS_MACOSX)
129871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org  if (gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync)
130871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org    return new EGLFenceSync(flush);
131871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org#endif
132871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org  if (gfx::g_driver_gl.ext.b_GL_NV_fence)
133871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org    return new GLFenceNVFence(flush);
134871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org  if (gfx::g_driver_gl.ext.b_GL_ARB_sync)
135871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org    return new GLFenceARBSync(flush);
136871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org  return NULL;
137871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org}
138871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace gfx {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GLFence::GLFence() {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GLFence::~GLFence() {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GLFence* GLFence::Create() {
150871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org  return CreateFence(true);
151871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org}
152871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org
153871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.orgGLFence* GLFence::CreateWithoutFlush() {
154871ad5406650fa38062582bc125fffcd2f6d5159sievers@chromium.org  return CreateFence(false);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace gfx
158