1bdf2d80f459d43f5a6df074431bacf41584f81b7shannon.woods@transgaming.com#include "precompiled.h"
2d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org//
35defc5c0d5c53456d37992fe7ac14af493c12d17shannon.woods@transgaming.com// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
4d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org// Use of this source code is governed by a BSD-style license that can be
5d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org// found in the LICENSE file.
6d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org//
7d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org
8d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org// Fence.cpp: Implements the gl::Fence class, which supports the GL_NV_fence extension.
9d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org
10cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill// Important note on accurate timers in Windows:
11cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill//
12cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill// QueryPerformanceCounter has a few major issues, including being 10x as expensive to call
13cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill// as timeGetTime on laptops and "jumping" during certain hardware events.
14cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill//
15cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill// See the comments at the top of the Chromium source file "chromium/src/base/time/time_win.cc"
16cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill//   https://code.google.com/p/chromium/codesearch#chromium/src/base/time/time_win.cc
17cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill//
18cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill// We still opt to use QPC. In the present and moving forward, most newer systems will not suffer
19cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill// from buggy implementations.
20cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill
21d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org#include "libGLESv2/Fence.h"
225defc5c0d5c53456d37992fe7ac14af493c12d17shannon.woods@transgaming.com#include "libGLESv2/renderer/FenceImpl.h"
23486d9e9b6b4ed31f66d2624b8e822020fe40a1f7shannon.woods@transgaming.com#include "libGLESv2/renderer/Renderer.h"
2409752369e814a809e3033973aa294ede4b4fb9bcJamie Madill#include "libGLESv2/main.h"
25d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org
26d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.orgnamespace gl
27d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org{
28d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org
2933dc84394ba08700d700a3da692e8de18433a031Jamie MadillFenceNV::FenceNV(rx::Renderer *renderer)
30563c0a533544792bb1df86338866a5d38d749597apatrick@chromium.org{
315defc5c0d5c53456d37992fe7ac14af493c12d17shannon.woods@transgaming.com    mFence = renderer->createFence();
32d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org}
33d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org
3433dc84394ba08700d700a3da692e8de18433a031Jamie MadillFenceNV::~FenceNV()
35d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org{
365defc5c0d5c53456d37992fe7ac14af493c12d17shannon.woods@transgaming.com    delete mFence;
37d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org}
38d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org
3933dc84394ba08700d700a3da692e8de18433a031Jamie MadillGLboolean FenceNV::isFence() const
40d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org{
4109752369e814a809e3033973aa294ede4b4fb9bcJamie Madill    // GL_NV_fence spec:
4209752369e814a809e3033973aa294ede4b4fb9bcJamie Madill    // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an existing fence.
4309752369e814a809e3033973aa294ede4b4fb9bcJamie Madill    return (mFence->isSet() ? GL_TRUE : GL_FALSE);
44d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org}
45d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org
4633dc84394ba08700d700a3da692e8de18433a031Jamie Madillvoid FenceNV::setFence(GLenum condition)
47d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org{
4809752369e814a809e3033973aa294ede4b4fb9bcJamie Madill    mFence->set();
4909752369e814a809e3033973aa294ede4b4fb9bcJamie Madill
5009752369e814a809e3033973aa294ede4b4fb9bcJamie Madill    mCondition = condition;
5109752369e814a809e3033973aa294ede4b4fb9bcJamie Madill    mStatus = GL_FALSE;
52d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org}
53d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org
5433dc84394ba08700d700a3da692e8de18433a031Jamie MadillGLboolean FenceNV::testFence()
55d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org{
5609752369e814a809e3033973aa294ede4b4fb9bcJamie Madill    // Flush the command buffer by default
5709752369e814a809e3033973aa294ede4b4fb9bcJamie Madill    bool result = mFence->test(true);
5809752369e814a809e3033973aa294ede4b4fb9bcJamie Madill
5909752369e814a809e3033973aa294ede4b4fb9bcJamie Madill    mStatus = (result ? GL_TRUE : GL_FALSE);
6009752369e814a809e3033973aa294ede4b4fb9bcJamie Madill    return mStatus;
61d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org}
62d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org
6333dc84394ba08700d700a3da692e8de18433a031Jamie Madillvoid FenceNV::finishFence()
64d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org{
65fb9a7409515cb0a8f9926974511ff486361909d7Jamie Madill    ASSERT(mFence->isSet());
6609752369e814a809e3033973aa294ede4b4fb9bcJamie Madill
6709752369e814a809e3033973aa294ede4b4fb9bcJamie Madill    while (!mFence->test(true))
6809752369e814a809e3033973aa294ede4b4fb9bcJamie Madill    {
6909752369e814a809e3033973aa294ede4b4fb9bcJamie Madill        Sleep(0);
7009752369e814a809e3033973aa294ede4b4fb9bcJamie Madill    }
71d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org}
72d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org
7333dc84394ba08700d700a3da692e8de18433a031Jamie MadillGLint FenceNV::getFencei(GLenum pname)
74d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org{
75fb9a7409515cb0a8f9926974511ff486361909d7Jamie Madill    ASSERT(mFence->isSet());
7609752369e814a809e3033973aa294ede4b4fb9bcJamie Madill
7709752369e814a809e3033973aa294ede4b4fb9bcJamie Madill    switch (pname)
7809752369e814a809e3033973aa294ede4b4fb9bcJamie Madill    {
7909752369e814a809e3033973aa294ede4b4fb9bcJamie Madill      case GL_FENCE_STATUS_NV:
8009752369e814a809e3033973aa294ede4b4fb9bcJamie Madill        {
8109752369e814a809e3033973aa294ede4b4fb9bcJamie Madill            // GL_NV_fence spec:
8209752369e814a809e3033973aa294ede4b4fb9bcJamie Madill            // Once the status of a fence has been finished (via FinishFenceNV) or tested and the returned status is TRUE (via either TestFenceNV
8309752369e814a809e3033973aa294ede4b4fb9bcJamie Madill            // or GetFenceivNV querying the FENCE_STATUS_NV), the status remains TRUE until the next SetFenceNV of the fence.
8409752369e814a809e3033973aa294ede4b4fb9bcJamie Madill            if (mStatus == GL_TRUE)
8509752369e814a809e3033973aa294ede4b4fb9bcJamie Madill            {
86fb9a7409515cb0a8f9926974511ff486361909d7Jamie Madill                return GL_TRUE;
8709752369e814a809e3033973aa294ede4b4fb9bcJamie Madill            }
8809752369e814a809e3033973aa294ede4b4fb9bcJamie Madill
8909752369e814a809e3033973aa294ede4b4fb9bcJamie Madill            mStatus = (mFence->test(false) ? GL_TRUE : GL_FALSE);
90fb9a7409515cb0a8f9926974511ff486361909d7Jamie Madill            return mStatus;
9109752369e814a809e3033973aa294ede4b4fb9bcJamie Madill        }
9209752369e814a809e3033973aa294ede4b4fb9bcJamie Madill
9309752369e814a809e3033973aa294ede4b4fb9bcJamie Madill      case GL_FENCE_CONDITION_NV:
94fb9a7409515cb0a8f9926974511ff486361909d7Jamie Madill        return mCondition;
9509752369e814a809e3033973aa294ede4b4fb9bcJamie Madill
96fb9a7409515cb0a8f9926974511ff486361909d7Jamie Madill      default: UNREACHABLE(); return 0;
9709752369e814a809e3033973aa294ede4b4fb9bcJamie Madill    }
98d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org}
99d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org
100cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie MadillFenceSync::FenceSync(rx::Renderer *renderer, GLuint id)
101cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    : RefCountObject(id)
102cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill{
103cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    mFence = renderer->createFence();
104cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill
105d21656c1fbdb761428e99309d28e1787196e359dGeoff Lang    LARGE_INTEGER counterFreqency = { 0 };
106af88d7290afacb0a8abd13d331f7ed7290d4918bNicolas Capens    BOOL success = QueryPerformanceFrequency(&counterFreqency);
1079cd1915c96800fc998ec25b88b0e3081f0aa6109Geoff Lang    UNUSED_ASSERTION_VARIABLE(success);
108af88d7290afacb0a8abd13d331f7ed7290d4918bNicolas Capens    ASSERT(success);
109cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill
110cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    mCounterFrequency = counterFreqency.QuadPart;
111cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill}
112cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill
113cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie MadillFenceSync::~FenceSync()
114cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill{
115cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    delete mFence;
116cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill}
117cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill
118cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madillvoid FenceSync::set(GLenum condition)
119cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill{
120cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    mCondition = condition;
121cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    mFence->set();
122cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill}
123cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill
124cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie MadillGLenum FenceSync::clientWait(GLbitfield flags, GLuint64 timeout)
125cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill{
126cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    ASSERT(mFence->isSet());
127cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill
128cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    bool flushCommandBuffer = ((flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0);
129cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill
130cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    if (mFence->test(flushCommandBuffer))
131cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    {
132cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill        return GL_ALREADY_SIGNALED;
133cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    }
134cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill
135cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    if (mFence->hasError())
136cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    {
137cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill        return GL_WAIT_FAILED;
138cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    }
139cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill
140cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    if (timeout == 0)
141cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    {
142cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill        return GL_TIMEOUT_EXPIRED;
143cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    }
144cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill
145d21656c1fbdb761428e99309d28e1787196e359dGeoff Lang    LARGE_INTEGER currentCounter = { 0 };
146af88d7290afacb0a8abd13d331f7ed7290d4918bNicolas Capens    BOOL success = QueryPerformanceCounter(&currentCounter);
1479cd1915c96800fc998ec25b88b0e3081f0aa6109Geoff Lang    UNUSED_ASSERTION_VARIABLE(success);
148af88d7290afacb0a8abd13d331f7ed7290d4918bNicolas Capens    ASSERT(success);
149cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill
150cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    LONGLONG timeoutInSeconds = static_cast<LONGLONG>(timeout) * static_cast<LONGLONG>(1000000ll);
151cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    LONGLONG endCounter = currentCounter.QuadPart + mCounterFrequency * timeoutInSeconds;
152cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill
153cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    while (currentCounter.QuadPart < endCounter && !mFence->test(flushCommandBuffer))
154cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    {
155cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill        Sleep(0);
156af88d7290afacb0a8abd13d331f7ed7290d4918bNicolas Capens        BOOL success = QueryPerformanceCounter(&currentCounter);
1579cd1915c96800fc998ec25b88b0e3081f0aa6109Geoff Lang        UNUSED_ASSERTION_VARIABLE(success);
158af88d7290afacb0a8abd13d331f7ed7290d4918bNicolas Capens        ASSERT(success);
159cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    }
160cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill
161cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    if (mFence->hasError())
162cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    {
163cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill        return GL_WAIT_FAILED;
164cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    }
165cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill
166cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    if (currentCounter.QuadPart >= endCounter)
167cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    {
168cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill        return GL_TIMEOUT_EXPIRED;
169cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    }
170cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill
171cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    return GL_CONDITION_SATISFIED;
172cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill}
173cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill
174cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madillvoid FenceSync::serverWait()
175cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill{
176cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    // Because our API is currently designed to be called from a single thread, we don't need to do
177cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    // extra work for a server-side fence. GPU commands issued after the fence is created will always
178cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    // be processed after the fence is signaled.
179cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill}
180cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill
181cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie MadillGLenum FenceSync::getStatus() const
182cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill{
183cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    if (mFence->test(false))
184cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    {
185cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill        // The spec does not specify any way to report errors during the status test (e.g. device lost)
186cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill        // so we report the fence is unblocked in case of error or signaled.
187cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill        return GL_SIGNALED;
188cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    }
189cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill
190cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill    return GL_UNSIGNALED;
191cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill}
192cd055f81f941b108b936fa0eaf2523793ddf7b4fJamie Madill
193d3bd0ad320fb246d9b42a0161c27eeb56c7e9160apatrick@chromium.org}
194