shannon.woods@transgaming.com | bdf2d80 | 2013-02-28 23:16:20 +0000 | [diff] [blame] | 1 | #include "precompiled.h" |
apatrick@chromium.org | d3bd0ad | 2010-08-30 18:55:36 +0000 | [diff] [blame] | 2 | // |
shannon.woods@transgaming.com | 5defc5c | 2013-02-28 23:03:41 +0000 | [diff] [blame] | 3 | // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. |
apatrick@chromium.org | d3bd0ad | 2010-08-30 18:55:36 +0000 | [diff] [blame] | 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 | |
Jamie Madill | cd055f8 | 2013-07-26 11:55:15 -0400 | [diff] [blame] | 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 | |
apatrick@chromium.org | d3bd0ad | 2010-08-30 18:55:36 +0000 | [diff] [blame] | 21 | #include "libGLESv2/Fence.h" |
shannon.woods@transgaming.com | 5defc5c | 2013-02-28 23:03:41 +0000 | [diff] [blame] | 22 | #include "libGLESv2/renderer/FenceImpl.h" |
shannon.woods@transgaming.com | 486d9e9 | 2013-02-28 23:15:41 +0000 | [diff] [blame] | 23 | #include "libGLESv2/renderer/Renderer.h" |
Jamie Madill | 0975236 | 2013-07-26 11:54:57 -0400 | [diff] [blame] | 24 | #include "libGLESv2/main.h" |
apatrick@chromium.org | d3bd0ad | 2010-08-30 18:55:36 +0000 | [diff] [blame] | 25 | |
| 26 | namespace gl |
| 27 | { |
| 28 | |
Jamie Madill | 33dc843 | 2013-07-26 11:55:05 -0400 | [diff] [blame] | 29 | FenceNV::FenceNV(rx::Renderer *renderer) |
apatrick@chromium.org | 563c0a5 | 2012-03-23 21:18:42 +0000 | [diff] [blame] | 30 | { |
shannon.woods@transgaming.com | 5defc5c | 2013-02-28 23:03:41 +0000 | [diff] [blame] | 31 | mFence = renderer->createFence(); |
apatrick@chromium.org | d3bd0ad | 2010-08-30 18:55:36 +0000 | [diff] [blame] | 32 | } |
| 33 | |
Jamie Madill | 33dc843 | 2013-07-26 11:55:05 -0400 | [diff] [blame] | 34 | FenceNV::~FenceNV() |
apatrick@chromium.org | d3bd0ad | 2010-08-30 18:55:36 +0000 | [diff] [blame] | 35 | { |
shannon.woods@transgaming.com | 5defc5c | 2013-02-28 23:03:41 +0000 | [diff] [blame] | 36 | delete mFence; |
apatrick@chromium.org | d3bd0ad | 2010-08-30 18:55:36 +0000 | [diff] [blame] | 37 | } |
| 38 | |
Jamie Madill | 33dc843 | 2013-07-26 11:55:05 -0400 | [diff] [blame] | 39 | GLboolean FenceNV::isFence() const |
apatrick@chromium.org | d3bd0ad | 2010-08-30 18:55:36 +0000 | [diff] [blame] | 40 | { |
Jamie Madill | 0975236 | 2013-07-26 11:54:57 -0400 | [diff] [blame] | 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); |
apatrick@chromium.org | d3bd0ad | 2010-08-30 18:55:36 +0000 | [diff] [blame] | 44 | } |
| 45 | |
Jamie Madill | 33dc843 | 2013-07-26 11:55:05 -0400 | [diff] [blame] | 46 | void FenceNV::setFence(GLenum condition) |
apatrick@chromium.org | d3bd0ad | 2010-08-30 18:55:36 +0000 | [diff] [blame] | 47 | { |
Jamie Madill | 0975236 | 2013-07-26 11:54:57 -0400 | [diff] [blame] | 48 | mFence->set(); |
| 49 | |
| 50 | mCondition = condition; |
| 51 | mStatus = GL_FALSE; |
apatrick@chromium.org | d3bd0ad | 2010-08-30 18:55:36 +0000 | [diff] [blame] | 52 | } |
| 53 | |
Jamie Madill | 33dc843 | 2013-07-26 11:55:05 -0400 | [diff] [blame] | 54 | GLboolean FenceNV::testFence() |
apatrick@chromium.org | d3bd0ad | 2010-08-30 18:55:36 +0000 | [diff] [blame] | 55 | { |
Jamie Madill | 0975236 | 2013-07-26 11:54:57 -0400 | [diff] [blame] | 56 | // 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.org | d3bd0ad | 2010-08-30 18:55:36 +0000 | [diff] [blame] | 61 | } |
| 62 | |
Jamie Madill | 33dc843 | 2013-07-26 11:55:05 -0400 | [diff] [blame] | 63 | void FenceNV::finishFence() |
apatrick@chromium.org | d3bd0ad | 2010-08-30 18:55:36 +0000 | [diff] [blame] | 64 | { |
Jamie Madill | fb9a740 | 2013-07-26 11:55:01 -0400 | [diff] [blame] | 65 | ASSERT(mFence->isSet()); |
Jamie Madill | 0975236 | 2013-07-26 11:54:57 -0400 | [diff] [blame] | 66 | |
| 67 | while (!mFence->test(true)) |
| 68 | { |
| 69 | Sleep(0); |
| 70 | } |
apatrick@chromium.org | d3bd0ad | 2010-08-30 18:55:36 +0000 | [diff] [blame] | 71 | } |
| 72 | |
Jamie Madill | 33dc843 | 2013-07-26 11:55:05 -0400 | [diff] [blame] | 73 | GLint FenceNV::getFencei(GLenum pname) |
apatrick@chromium.org | d3bd0ad | 2010-08-30 18:55:36 +0000 | [diff] [blame] | 74 | { |
Jamie Madill | fb9a740 | 2013-07-26 11:55:01 -0400 | [diff] [blame] | 75 | ASSERT(mFence->isSet()); |
Jamie Madill | 0975236 | 2013-07-26 11:54:57 -0400 | [diff] [blame] | 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 | { |
Jamie Madill | fb9a740 | 2013-07-26 11:55:01 -0400 | [diff] [blame] | 86 | return GL_TRUE; |
Jamie Madill | 0975236 | 2013-07-26 11:54:57 -0400 | [diff] [blame] | 87 | } |
| 88 | |
| 89 | mStatus = (mFence->test(false) ? GL_TRUE : GL_FALSE); |
Jamie Madill | fb9a740 | 2013-07-26 11:55:01 -0400 | [diff] [blame] | 90 | return mStatus; |
Jamie Madill | 0975236 | 2013-07-26 11:54:57 -0400 | [diff] [blame] | 91 | } |
| 92 | |
| 93 | case GL_FENCE_CONDITION_NV: |
Jamie Madill | fb9a740 | 2013-07-26 11:55:01 -0400 | [diff] [blame] | 94 | return mCondition; |
Jamie Madill | 0975236 | 2013-07-26 11:54:57 -0400 | [diff] [blame] | 95 | |
Jamie Madill | fb9a740 | 2013-07-26 11:55:01 -0400 | [diff] [blame] | 96 | default: UNREACHABLE(); return 0; |
Jamie Madill | 0975236 | 2013-07-26 11:54:57 -0400 | [diff] [blame] | 97 | } |
apatrick@chromium.org | d3bd0ad | 2010-08-30 18:55:36 +0000 | [diff] [blame] | 98 | } |
| 99 | |
Jamie Madill | cd055f8 | 2013-07-26 11:55:15 -0400 | [diff] [blame] | 100 | FenceSync::FenceSync(rx::Renderer *renderer, GLuint id) |
| 101 | : RefCountObject(id) |
| 102 | { |
| 103 | mFence = renderer->createFence(); |
| 104 | |
Geoff Lang | d21656c | 2013-08-02 11:45:23 -0400 | [diff] [blame] | 105 | LARGE_INTEGER counterFreqency = { 0 }; |
Nicolas Capens | af88d72 | 2013-08-02 16:56:32 -0400 | [diff] [blame] | 106 | BOOL success = QueryPerformanceFrequency(&counterFreqency); |
Geoff Lang | 9cd1915 | 2014-05-28 15:54:34 -0400 | [diff] [blame] | 107 | UNUSED_ASSERTION_VARIABLE(success); |
Nicolas Capens | af88d72 | 2013-08-02 16:56:32 -0400 | [diff] [blame] | 108 | ASSERT(success); |
Jamie Madill | cd055f8 | 2013-07-26 11:55:15 -0400 | [diff] [blame] | 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 | |
Geoff Lang | d21656c | 2013-08-02 11:45:23 -0400 | [diff] [blame] | 145 | LARGE_INTEGER currentCounter = { 0 }; |
Nicolas Capens | af88d72 | 2013-08-02 16:56:32 -0400 | [diff] [blame] | 146 | BOOL success = QueryPerformanceCounter(¤tCounter); |
Geoff Lang | 9cd1915 | 2014-05-28 15:54:34 -0400 | [diff] [blame] | 147 | UNUSED_ASSERTION_VARIABLE(success); |
Nicolas Capens | af88d72 | 2013-08-02 16:56:32 -0400 | [diff] [blame] | 148 | ASSERT(success); |
Jamie Madill | cd055f8 | 2013-07-26 11:55:15 -0400 | [diff] [blame] | 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); |
Nicolas Capens | af88d72 | 2013-08-02 16:56:32 -0400 | [diff] [blame] | 156 | BOOL success = QueryPerformanceCounter(¤tCounter); |
Geoff Lang | 9cd1915 | 2014-05-28 15:54:34 -0400 | [diff] [blame] | 157 | UNUSED_ASSERTION_VARIABLE(success); |
Nicolas Capens | af88d72 | 2013-08-02 16:56:32 -0400 | [diff] [blame] | 158 | ASSERT(success); |
Jamie Madill | cd055f8 | 2013-07-26 11:55:15 -0400 | [diff] [blame] | 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 | |
apatrick@chromium.org | d3bd0ad | 2010-08-30 18:55:36 +0000 | [diff] [blame] | 193 | } |