• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
FenceNV(rx::Renderer * renderer)30 FenceNV::FenceNV(rx::Renderer *renderer)
31 {
32     mFence = renderer->createFence();
33 }
34 
~FenceNV()35 FenceNV::~FenceNV()
36 {
37     delete mFence;
38 }
39 
isFence() const40 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 
setFence(GLenum condition)47 void FenceNV::setFence(GLenum condition)
48 {
49     mFence->set();
50 
51     mCondition = condition;
52     mStatus = GL_FALSE;
53 }
54 
testFence()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 
finishFence()64 void FenceNV::finishFence()
65 {
66     ASSERT(mFence->isSet());
67 
68     while (!mFence->test(true))
69     {
70         Sleep(0);
71     }
72 }
73 
getFencei(GLenum pname)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 
FenceSync(rx::Renderer * renderer,GLuint id)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 
~FenceSync()114 FenceSync::~FenceSync()
115 {
116     delete mFence;
117 }
118 
set(GLenum condition)119 void FenceSync::set(GLenum condition)
120 {
121     mCondition = condition;
122     mFence->set();
123 }
124 
clientWait(GLbitfield flags,GLuint64 timeout)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 
serverWait()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 
getStatus() const182 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