blob: 31d149d629fdfac6cd47e657ebe5aae4d7a4a0db [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
apatrick@chromium.orgd3bd0ad2010-08-30 18:55:36 +00002//
shannon.woods@transgaming.com5defc5c2013-02-28 23:03:41 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
apatrick@chromium.orgd3bd0ad2010-08-30 18:55:36 +00004// 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
Jamie Madillcd055f82013-07-26 11:55:15 -040010// 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
apatrick@chromium.orgd3bd0ad2010-08-30 18:55:36 +000021#include "libGLESv2/Fence.h"
shannon.woods@transgaming.com5defc5c2013-02-28 23:03:41 +000022#include "libGLESv2/renderer/FenceImpl.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000023#include "libGLESv2/renderer/Renderer.h"
Jamie Madill09752362013-07-26 11:54:57 -040024#include "libGLESv2/main.h"
apatrick@chromium.orgd3bd0ad2010-08-30 18:55:36 +000025
26namespace gl
27{
28
Jamie Madill33dc8432013-07-26 11:55:05 -040029FenceNV::FenceNV(rx::Renderer *renderer)
apatrick@chromium.org563c0a52012-03-23 21:18:42 +000030{
shannon.woods@transgaming.com5defc5c2013-02-28 23:03:41 +000031 mFence = renderer->createFence();
apatrick@chromium.orgd3bd0ad2010-08-30 18:55:36 +000032}
33
Jamie Madill33dc8432013-07-26 11:55:05 -040034FenceNV::~FenceNV()
apatrick@chromium.orgd3bd0ad2010-08-30 18:55:36 +000035{
shannon.woods@transgaming.com5defc5c2013-02-28 23:03:41 +000036 delete mFence;
apatrick@chromium.orgd3bd0ad2010-08-30 18:55:36 +000037}
38
Jamie Madill33dc8432013-07-26 11:55:05 -040039GLboolean FenceNV::isFence() const
apatrick@chromium.orgd3bd0ad2010-08-30 18:55:36 +000040{
Jamie Madill09752362013-07-26 11:54:57 -040041 // 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);
apatrick@chromium.orgd3bd0ad2010-08-30 18:55:36 +000044}
45
Jamie Madill33dc8432013-07-26 11:55:05 -040046void FenceNV::setFence(GLenum condition)
apatrick@chromium.orgd3bd0ad2010-08-30 18:55:36 +000047{
Jamie Madill09752362013-07-26 11:54:57 -040048 mFence->set();
49
50 mCondition = condition;
51 mStatus = GL_FALSE;
apatrick@chromium.orgd3bd0ad2010-08-30 18:55:36 +000052}
53
Jamie Madill33dc8432013-07-26 11:55:05 -040054GLboolean FenceNV::testFence()
apatrick@chromium.orgd3bd0ad2010-08-30 18:55:36 +000055{
Jamie Madill09752362013-07-26 11:54:57 -040056 // Flush the command buffer by default
57 bool result = mFence->test(true);
58
59 mStatus = (result ? GL_TRUE : GL_FALSE);
60 return mStatus;
apatrick@chromium.orgd3bd0ad2010-08-30 18:55:36 +000061}
62
Jamie Madill33dc8432013-07-26 11:55:05 -040063void FenceNV::finishFence()
apatrick@chromium.orgd3bd0ad2010-08-30 18:55:36 +000064{
Jamie Madillfb9a7402013-07-26 11:55:01 -040065 ASSERT(mFence->isSet());
Jamie Madill09752362013-07-26 11:54:57 -040066
67 while (!mFence->test(true))
68 {
69 Sleep(0);
70 }
apatrick@chromium.orgd3bd0ad2010-08-30 18:55:36 +000071}
72
Jamie Madill33dc8432013-07-26 11:55:05 -040073GLint FenceNV::getFencei(GLenum pname)
apatrick@chromium.orgd3bd0ad2010-08-30 18:55:36 +000074{
Jamie Madillfb9a7402013-07-26 11:55:01 -040075 ASSERT(mFence->isSet());
Jamie Madill09752362013-07-26 11:54:57 -040076
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 {
Jamie Madillfb9a7402013-07-26 11:55:01 -040086 return GL_TRUE;
Jamie Madill09752362013-07-26 11:54:57 -040087 }
88
89 mStatus = (mFence->test(false) ? GL_TRUE : GL_FALSE);
Jamie Madillfb9a7402013-07-26 11:55:01 -040090 return mStatus;
Jamie Madill09752362013-07-26 11:54:57 -040091 }
92
93 case GL_FENCE_CONDITION_NV:
Jamie Madillfb9a7402013-07-26 11:55:01 -040094 return mCondition;
Jamie Madill09752362013-07-26 11:54:57 -040095
Jamie Madillfb9a7402013-07-26 11:55:01 -040096 default: UNREACHABLE(); return 0;
Jamie Madill09752362013-07-26 11:54:57 -040097 }
apatrick@chromium.orgd3bd0ad2010-08-30 18:55:36 +000098}
99
Jamie Madillcd055f82013-07-26 11:55:15 -0400100FenceSync::FenceSync(rx::Renderer *renderer, GLuint id)
101 : RefCountObject(id)
102{
103 mFence = renderer->createFence();
104
Geoff Langd21656c2013-08-02 11:45:23 -0400105 LARGE_INTEGER counterFreqency = { 0 };
Nicolas Capensaf88d722013-08-02 16:56:32 -0400106 BOOL success = QueryPerformanceFrequency(&counterFreqency);
Geoff Lang9cd19152014-05-28 15:54:34 -0400107 UNUSED_ASSERTION_VARIABLE(success);
Nicolas Capensaf88d722013-08-02 16:56:32 -0400108 ASSERT(success);
Jamie Madillcd055f82013-07-26 11:55:15 -0400109
110 mCounterFrequency = counterFreqency.QuadPart;
111}
112
113FenceSync::~FenceSync()
114{
115 delete mFence;
116}
117
118void FenceSync::set(GLenum condition)
119{
120 mCondition = condition;
121 mFence->set();
122}
123
124GLenum 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
Geoff Langd21656c2013-08-02 11:45:23 -0400145 LARGE_INTEGER currentCounter = { 0 };
Nicolas Capensaf88d722013-08-02 16:56:32 -0400146 BOOL success = QueryPerformanceCounter(&currentCounter);
Geoff Lang9cd19152014-05-28 15:54:34 -0400147 UNUSED_ASSERTION_VARIABLE(success);
Nicolas Capensaf88d722013-08-02 16:56:32 -0400148 ASSERT(success);
Jamie Madillcd055f82013-07-26 11:55:15 -0400149
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);
Nicolas Capensaf88d722013-08-02 16:56:32 -0400156 BOOL success = QueryPerformanceCounter(&currentCounter);
Geoff Lang9cd19152014-05-28 15:54:34 -0400157 UNUSED_ASSERTION_VARIABLE(success);
Nicolas Capensaf88d722013-08-02 16:56:32 -0400158 ASSERT(success);
Jamie Madillcd055f82013-07-26 11:55:15 -0400159 }
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
174void 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
181GLenum 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
apatrick@chromium.orgd3bd0ad2010-08-30 18:55:36 +0000193}