Home | History | Annotate | Download | only in libGLESv2
      1 //
      2 // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 
      7 // Fence.cpp: Implements the gl::Fence class, which supports the GL_NV_fence extension.
      8 
      9 // Important note on accurate timers in Windows:
     10 //
     11 // QueryPerformanceCounter has a few major issues, including being 10x as expensive to call
     12 // as timeGetTime on laptops and "jumping" during certain hardware events.
     13 //
     14 // See the comments at the top of the Chromium source file "chromium/src/base/time/time_win.cc"
     15 //   https://code.google.com/p/chromium/codesearch#chromium/src/base/time/time_win.cc
     16 //
     17 // We still opt to use QPC. In the present and moving forward, most newer systems will not suffer
     18 // from buggy implementations.
     19 
     20 #include "libGLESv2/Fence.h"
     21 #include "libGLESv2/renderer/FenceImpl.h"
     22 #include "libGLESv2/renderer/Renderer.h"
     23 #include "libGLESv2/main.h"
     24 
     25 #include "angle_gl.h"
     26 
     27 namespace gl
     28 {
     29 
     30 FenceNV::FenceNV(rx::Renderer *renderer)
     31 {
     32     mFence = renderer->createFence();
     33 }
     34 
     35 FenceNV::~FenceNV()
     36 {
     37     delete mFence;
     38 }
     39 
     40 GLboolean FenceNV::isFence() const
     41 {
     42     // GL_NV_fence spec:
     43     // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an existing fence.
     44     return (mFence->isSet() ? GL_TRUE : GL_FALSE);
     45 }
     46 
     47 void FenceNV::setFence(GLenum condition)
     48 {
     49     mFence->set();
     50 
     51     mCondition = condition;
     52     mStatus = GL_FALSE;
     53 }
     54 
     55 GLboolean FenceNV::testFence()
     56 {
     57     // Flush the command buffer by default
     58     bool result = mFence->test(true);
     59 
     60     mStatus = (result ? GL_TRUE : GL_FALSE);
     61     return mStatus;
     62 }
     63 
     64 void FenceNV::finishFence()
     65 {
     66     ASSERT(mFence->isSet());
     67 
     68     while (!mFence->test(true))
     69     {
     70         Sleep(0);
     71     }
     72 }
     73 
     74 GLint FenceNV::getFencei(GLenum pname)
     75 {
     76     ASSERT(mFence->isSet());
     77 
     78     switch (pname)
     79     {
     80       case GL_FENCE_STATUS_NV:
     81         {
     82             // GL_NV_fence spec:
     83             // Once the status of a fence has been finished (via FinishFenceNV) or tested and the returned status is TRUE (via either TestFenceNV
     84             // or GetFenceivNV querying the FENCE_STATUS_NV), the status remains TRUE until the next SetFenceNV of the fence.
     85             if (mStatus == GL_TRUE)
     86             {
     87                 return GL_TRUE;
     88             }
     89 
     90             mStatus = (mFence->test(false) ? GL_TRUE : GL_FALSE);
     91             return mStatus;
     92         }
     93 
     94       case GL_FENCE_CONDITION_NV:
     95         return mCondition;
     96 
     97       default: UNREACHABLE(); return 0;
     98     }
     99 }
    100 
    101 FenceSync::FenceSync(rx::Renderer *renderer, GLuint id)
    102     : RefCountObject(id)
    103 {
    104     mFence = renderer->createFence();
    105 
    106     LARGE_INTEGER counterFreqency = { 0 };
    107     BOOL success = QueryPerformanceFrequency(&counterFreqency);
    108     UNUSED_ASSERTION_VARIABLE(success);
    109     ASSERT(success);
    110 
    111     mCounterFrequency = counterFreqency.QuadPart;
    112 }
    113 
    114 FenceSync::~FenceSync()
    115 {
    116     delete mFence;
    117 }
    118 
    119 void FenceSync::set(GLenum condition)
    120 {
    121     mCondition = condition;
    122     mFence->set();
    123 }
    124 
    125 GLenum FenceSync::clientWait(GLbitfield flags, GLuint64 timeout)
    126 {
    127     ASSERT(mFence->isSet());
    128 
    129     bool flushCommandBuffer = ((flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0);
    130 
    131     if (mFence->test(flushCommandBuffer))
    132     {
    133         return GL_ALREADY_SIGNALED;
    134     }
    135 
    136     if (mFence->hasError())
    137     {
    138         return GL_WAIT_FAILED;
    139     }
    140 
    141     if (timeout == 0)
    142     {
    143         return GL_TIMEOUT_EXPIRED;
    144     }
    145 
    146     LARGE_INTEGER currentCounter = { 0 };
    147     BOOL success = QueryPerformanceCounter(&currentCounter);
    148     UNUSED_ASSERTION_VARIABLE(success);
    149     ASSERT(success);
    150 
    151     LONGLONG timeoutInSeconds = static_cast<LONGLONG>(timeout) * static_cast<LONGLONG>(1000000ll);
    152     LONGLONG endCounter = currentCounter.QuadPart + mCounterFrequency * timeoutInSeconds;
    153 
    154     while (currentCounter.QuadPart < endCounter && !mFence->test(flushCommandBuffer))
    155     {
    156         Sleep(0);
    157         BOOL success = QueryPerformanceCounter(&currentCounter);
    158         UNUSED_ASSERTION_VARIABLE(success);
    159         ASSERT(success);
    160     }
    161 
    162     if (mFence->hasError())
    163     {
    164         return GL_WAIT_FAILED;
    165     }
    166 
    167     if (currentCounter.QuadPart >= endCounter)
    168     {
    169         return GL_TIMEOUT_EXPIRED;
    170     }
    171 
    172     return GL_CONDITION_SATISFIED;
    173 }
    174 
    175 void FenceSync::serverWait()
    176 {
    177     // Because our API is currently designed to be called from a single thread, we don't need to do
    178     // extra work for a server-side fence. GPU commands issued after the fence is created will always
    179     // be processed after the fence is signaled.
    180 }
    181 
    182 GLenum FenceSync::getStatus() const
    183 {
    184     if (mFence->test(false))
    185     {
    186         // The spec does not specify any way to report errors during the status test (e.g. device lost)
    187         // so we report the fence is unblocked in case of error or signaled.
    188         return GL_SIGNALED;
    189     }
    190 
    191     return GL_UNSIGNALED;
    192 }
    193 
    194 }
    195