Edit

kc3-lang/angle/src/libGLESv2/Fence.cpp

Branch :

  • Show log

    Commit

  • Author : Geoff Lang
    Date : 2014-09-30 11:26:07
    Hash : 882033e7
    Message : Updated the FenceSync and FenceNV objects to use Error objects. BUG=angle:520 Change-Id: I1e49b35905d8916baadb129c8aa58a11bd721500 Reviewed-on: https://chromium-review.googlesource.com/220781 Reviewed-by: Shannon Woods <shannonwoods@chromium.org> Tested-by: Geoff Lang <geofflang@chromium.org>

  • src/libGLESv2/Fence.cpp
  • //
    // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    
    // Fence.cpp: Implements the gl::Fence class, which supports the GL_NV_fence extension.
    
    // Important note on accurate timers in Windows:
    //
    // QueryPerformanceCounter has a few major issues, including being 10x as expensive to call
    // as timeGetTime on laptops and "jumping" during certain hardware events.
    //
    // See the comments at the top of the Chromium source file "chromium/src/base/time/time_win.cc"
    //   https://code.google.com/p/chromium/codesearch#chromium/src/base/time/time_win.cc
    //
    // We still opt to use QPC. In the present and moving forward, most newer systems will not suffer
    // from buggy implementations.
    
    #include "libGLESv2/Fence.h"
    #include "libGLESv2/renderer/FenceImpl.h"
    #include "libGLESv2/renderer/Renderer.h"
    #include "libGLESv2/main.h"
    
    #include "angle_gl.h"
    
    namespace gl
    {
    
    FenceNV::FenceNV(rx::Renderer *renderer)
        : mFence(renderer->createFence()),
          mIsSet(false),
          mStatus(GL_FALSE),
          mCondition(GL_NONE)
    {
    }
    
    FenceNV::~FenceNV()
    {
        SafeDelete(mFence);
    }
    
    GLboolean FenceNV::isFence() const
    {
        // GL_NV_fence spec:
        // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an existing fence.
        return (mIsSet ? GL_TRUE : GL_FALSE);
    }
    
    Error FenceNV::setFence(GLenum condition)
    {
        Error error = mFence->set();
        if (error.isError())
        {
            return error;
        }
    
        mCondition = condition;
        mStatus = GL_FALSE;
        mIsSet = true;
    
        return Error(GL_NO_ERROR);
    }
    
    Error FenceNV::testFence(GLboolean *outResult)
    {
        // Flush the command buffer by default
        Error error = mFence->test(true, &mStatus);
        if (error.isError())
        {
            return error;
        }
    
        *outResult = mStatus;
        return Error(GL_NO_ERROR);
    }
    
    Error FenceNV::finishFence()
    {
        ASSERT(mIsSet);
    
        while (mStatus != GL_TRUE)
        {
            Error error = mFence->test(true, &mStatus);
            if (error.isError())
            {
                return error;
            }
    
            Sleep(0);
        }
    
        return Error(GL_NO_ERROR);
    }
    
    Error FenceNV::getFencei(GLenum pname, GLint *params)
    {
        ASSERT(mIsSet);
    
        switch (pname)
        {
          case GL_FENCE_STATUS_NV:
            // GL_NV_fence spec:
            // Once the status of a fence has been finished (via FinishFenceNV) or tested and the returned status is TRUE (via either TestFenceNV
            // or GetFenceivNV querying the FENCE_STATUS_NV), the status remains TRUE until the next SetFenceNV of the fence.
            if (mStatus != GL_TRUE)
            {
                Error error = mFence->test(false, &mStatus);
                if (error.isError())
                {
                    return error;
                }
            }
            *params = mStatus;
            break;
    
          case GL_FENCE_CONDITION_NV:
            *params = mCondition;
            break;
    
          default:
            UNREACHABLE();
            return gl::Error(GL_INVALID_OPERATION);
        }
    
        return Error(GL_NO_ERROR);
    }
    
    FenceSync::FenceSync(rx::Renderer *renderer, GLuint id)
        : RefCountObject(id),
          mFence(renderer->createFence()),
          mCounterFrequency(0),
          mCondition(GL_NONE)
    {
        LARGE_INTEGER counterFreqency = { 0 };
        BOOL success = QueryPerformanceFrequency(&counterFreqency);
        UNUSED_ASSERTION_VARIABLE(success);
        ASSERT(success);
    
        mCounterFrequency = counterFreqency.QuadPart;
    }
    
    FenceSync::~FenceSync()
    {
        SafeDelete(mFence);
    }
    
    Error FenceSync::set(GLenum condition)
    {
        Error error = mFence->set();
        if (error.isError())
        {
            return error;
        }
    
        mCondition = condition;
        return Error(GL_NO_ERROR);
    }
    
    Error FenceSync::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult)
    {
        ASSERT(mCondition != GL_NONE);
    
        bool flushCommandBuffer = ((flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0);
    
        GLboolean result = GL_FALSE;
        Error error = mFence->test(flushCommandBuffer, &result);
        if (error.isError())
        {
            *outResult = GL_WAIT_FAILED;
            return error;
        }
    
        if (result == GL_TRUE)
        {
            *outResult = GL_ALREADY_SIGNALED;
            return Error(GL_NO_ERROR);
        }
    
        if (timeout == 0)
        {
            *outResult = GL_TIMEOUT_EXPIRED;
            return Error(GL_NO_ERROR);
        }
    
        LARGE_INTEGER currentCounter = { 0 };
        BOOL success = QueryPerformanceCounter(&currentCounter);
        UNUSED_ASSERTION_VARIABLE(success);
        ASSERT(success);
    
        LONGLONG timeoutInSeconds = static_cast<LONGLONG>(timeout) * static_cast<LONGLONG>(1000000ll);
        LONGLONG endCounter = currentCounter.QuadPart + mCounterFrequency * timeoutInSeconds;
    
        while (currentCounter.QuadPart < endCounter && !result)
        {
            Sleep(0);
            BOOL success = QueryPerformanceCounter(&currentCounter);
            UNUSED_ASSERTION_VARIABLE(success);
            ASSERT(success);
    
            error = mFence->test(flushCommandBuffer, &result);
            if (error.isError())
            {
                *outResult = GL_WAIT_FAILED;
                return error;
            }
        }
    
        if (currentCounter.QuadPart >= endCounter)
        {
            *outResult = GL_TIMEOUT_EXPIRED;
        }
        else
        {
            *outResult = GL_CONDITION_SATISFIED;
        }
    
        return Error(GL_NO_ERROR);
    }
    
    Error FenceSync::serverWait()
    {
        // Because our API is currently designed to be called from a single thread, we don't need to do
        // extra work for a server-side fence. GPU commands issued after the fence is created will always
        // be processed after the fence is signaled.
        return Error(GL_NO_ERROR);
    }
    
    Error FenceSync::getStatus(GLint *outResult) const
    {
        GLboolean result = GL_FALSE;
        Error error = mFence->test(false, &result);
        if (error.isError())
        {
            // The spec does not specify any way to report errors during the status test (e.g. device lost)
            // so we report the fence is unblocked in case of error or signaled.
            *outResult = GL_SIGNALED;
    
            return error;
        }
    
        *outResult = (result ? GL_SIGNALED : GL_UNSIGNALED);
        return Error(GL_NO_ERROR);
    }
    
    }