| // 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() { |
| // 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); |
| glFlush(); |
| } |
| |
| virtual bool HasCompleted() OVERRIDE { |
| return IsContextLost() || glTestFenceNV(fence_); |
| } |
| |
| private: |
| virtual ~GLFenceNVFence() { |
| glDeleteFencesNV(1, &fence_); |
| } |
| |
| GLuint fence_; |
| }; |
| |
| class GLFenceARBSync: public gfx::GLFence { |
| public: |
| GLFenceARBSync() { |
| sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); |
| glFlush(); |
| } |
| |
| virtual bool HasCompleted() OVERRIDE { |
| // Handle the case where FenceSync failed. |
| if (!sync_ || IsContextLost()) |
| return true; |
| |
| GLsizei length = 0; |
| GLsizei value = 0; |
| glGetSynciv(sync_, |
| GL_SYNC_STATUS, |
| 1, // bufSize |
| &length, |
| &value); |
| return length == 1 && value == GL_SIGNALED; |
| } |
| |
| private: |
| virtual ~GLFenceARBSync() { |
| glDeleteSync(sync_); |
| } |
| |
| GLsync sync_; |
| }; |
| |
| } // namespace |
| |
| namespace gfx { |
| |
| GLFence::GLFence() { |
| } |
| |
| GLFence::~GLFence() { |
| } |
| |
| // static |
| GLFence* GLFence::Create() { |
| if (gfx::g_GL_NV_fence) { |
| return new GLFenceNVFence(); |
| } else if (gfx::g_GL_ARB_sync) { |
| return new GLFenceARBSync(); |
| } else { |
| return NULL; |
| } |
| } |
| |
| // static |
| bool GLFence::IsContextLost() { |
| if (!gfx::g_GL_ARB_robustness && !gfx::g_GL_EXT_robustness) |
| return false; |
| |
| if (!gfx::GLContext::GetCurrent() || |
| !gfx::GLContext::GetCurrent()-> |
| WasAllocatedUsingRobustnessExtension()) |
| return false; |
| |
| GLenum status = glGetGraphicsResetStatusARB(); |
| return status != GL_NO_ERROR; |
| } |
| |
| } // namespace gfx |