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