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(¤tCounter); 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(¤tCounter); 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