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