Commit caa549c0 by Kenneth Russell

Split FenceImpl into FenceNVImpl and FenceSyncImpl, and refactor.

Move Windows-specific code out of Fence.cpp. Split FenceImpl based on suggestions on previous review https://chromium-review.googlesource.com/221805/ . Refactored further based on code review feedback and added first unit tests. BUG=angleproject:774 Change-Id: I630034e1788e48ddb7722016ca22da474e785798 Reviewed-on: https://chromium-review.googlesource.com/222954Reviewed-by: 's avatarKenneth Russell <kbr@chromium.org> Tested-by: 's avatarKenneth Russell <kbr@chromium.org>
parent 7c9e2167
......@@ -287,7 +287,7 @@ GLuint Context::createFenceNV()
{
GLuint handle = mFenceNVHandleAllocator.allocate();
mFenceNVMap[handle] = new FenceNV(mRenderer);
mFenceNVMap[handle] = new FenceNV(mRenderer->createFenceNV());
return handle;
}
......
......@@ -4,18 +4,8 @@
// 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.
// Fence.cpp: Implements the gl::FenceNV and gl::FenceSync classes, which support the GL_NV_fence
// extension and GLES3 sync objects.
#include "libGLESv2/Fence.h"
#include "libGLESv2/renderer/FenceImpl.h"
......@@ -27,8 +17,8 @@
namespace gl
{
FenceNV::FenceNV(rx::Renderer *renderer)
: mFence(renderer->createFence()),
FenceNV::FenceNV(rx::FenceNVImpl *impl)
: mFence(impl),
mIsSet(false),
mStatus(GL_FALSE),
mCondition(GL_NONE)
......@@ -79,65 +69,14 @@ 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);
return mFence->finishFence(&mStatus);
}
FenceSync::FenceSync(rx::Renderer *renderer, GLuint id)
FenceSync::FenceSync(rx::FenceSyncImpl *impl, GLuint id)
: RefCountObject(id),
mFence(renderer->createFence()),
mCounterFrequency(0),
mFence(impl),
mCondition(GL_NONE)
{
LARGE_INTEGER counterFreqency = { 0 };
BOOL success = QueryPerformanceFrequency(&counterFreqency);
UNUSED_ASSERTION_VARIABLE(success);
ASSERT(success);
mCounterFrequency = counterFreqency.QuadPart;
}
FenceSync::~FenceSync()
......@@ -160,87 +99,17 @@ Error FenceSync::set(GLenum condition)
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);
return mFence->clientWait(flags, timeout, outResult);
}
Error FenceSync::serverWait()
Error FenceSync::serverWait(GLbitfield flags, GLuint64 timeout)
{
// 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);
return mFence->serverWait(flags, timeout);
}
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);
return mFence->getStatus(outResult);
}
}
......@@ -4,7 +4,8 @@
// found in the LICENSE file.
//
// Fence.h: Defines the gl::Fence class, which supports the GL_NV_fence extension.
// Fence.h: Defines the gl::FenceNV and gl::FenceSync classes, which support the GL_NV_fence
// extension and GLES3 sync objects.
#ifndef LIBGLESV2_FENCE_H_
#define LIBGLESV2_FENCE_H_
......@@ -17,7 +18,8 @@
namespace rx
{
class Renderer;
class FenceImpl;
class FenceNVImpl;
class FenceSyncImpl;
}
namespace gl
......@@ -26,14 +28,13 @@ namespace gl
class FenceNV
{
public:
explicit FenceNV(rx::Renderer *renderer);
explicit FenceNV(rx::FenceNVImpl *impl);
virtual ~FenceNV();
GLboolean isFence() const;
Error setFence(GLenum condition);
Error testFence(GLboolean *outResult);
Error finishFence();
Error getFencei(GLenum pname, GLint *params);
GLboolean getStatus() const { return mStatus; }
GLuint getCondition() const { return mCondition; }
......@@ -41,7 +42,7 @@ class FenceNV
private:
DISALLOW_COPY_AND_ASSIGN(FenceNV);
rx::FenceImpl *mFence;
rx::FenceNVImpl *mFence;
bool mIsSet;
......@@ -52,12 +53,12 @@ class FenceNV
class FenceSync : public RefCountObject
{
public:
explicit FenceSync(rx::Renderer *renderer, GLuint id);
explicit FenceSync(rx::FenceSyncImpl *impl, GLuint id);
virtual ~FenceSync();
Error set(GLenum condition);
Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult);
Error serverWait();
Error serverWait(GLbitfield flags, GLuint64 timeout);
Error getStatus(GLint *outResult) const;
GLuint getCondition() const { return mCondition; }
......@@ -65,8 +66,7 @@ class FenceSync : public RefCountObject
private:
DISALLOW_COPY_AND_ASSIGN(FenceSync);
rx::FenceImpl *mFence;
LONGLONG mCounterFrequency;
rx::FenceSyncImpl *mFence;
GLenum mCondition;
};
......
......@@ -146,7 +146,7 @@ GLuint ResourceManager::createFenceSync()
{
GLuint handle = mFenceSyncHandleAllocator.allocate();
FenceSync *fenceSync = new FenceSync(mRenderer, handle);
FenceSync *fenceSync = new FenceSync(mRenderer->createFenceSync(), handle);
fenceSync->addRef();
mFenceSyncMap[handle] = fenceSync;
......
......@@ -2139,19 +2139,35 @@ void GL_APIENTRY glGetFenceivNV(GLuint fence, GLenum pname, GLint *params)
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.
GLboolean status = GL_TRUE;
if (fenceObject->getStatus() != GL_TRUE)
{
gl::Error error = fenceObject->testFence(&status);
if (error.isError())
{
context->recordError(error);
return;
}
}
*params = status;
break;
}
case GL_FENCE_CONDITION_NV:
break;
{
*params = fenceObject->getCondition();
break;
}
default:
context->recordError(gl::Error(GL_INVALID_ENUM));
return;
}
gl::Error error = fenceObject->getFencei(pname, params);
if (error.isError())
{
context->recordError(error);
return;
{
context->recordError(gl::Error(GL_INVALID_ENUM));
return;
}
}
}
}
......@@ -7548,7 +7564,7 @@ void GL_APIENTRY glWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
return;
}
gl::Error error = fenceSync->serverWait();
gl::Error error = fenceSync->serverWait(flags, timeout);
if (error.isError())
{
context->recordError(error);
......
......@@ -4,7 +4,7 @@
// found in the LICENSE file.
//
// FenceImpl.h: Defines the rx::FenceImpl class.
// FenceImpl.h: Defines the rx::FenceNVImpl and rx::FenceSyncImpl classes.
#ifndef LIBGLESV2_RENDERER_FENCEIMPL_H_
#define LIBGLESV2_RENDERER_FENCEIMPL_H_
......@@ -13,20 +13,38 @@
#include "common/angleutils.h"
#include "angle_gl.h"
namespace rx
{
class FenceImpl
class FenceNVImpl
{
public:
FenceImpl() { };
virtual ~FenceImpl() { };
FenceNVImpl() { };
virtual ~FenceNVImpl() { };
virtual gl::Error set() = 0;
virtual gl::Error test(bool flushCommandBuffer, GLboolean *outFinished) = 0;
virtual gl::Error finishFence(GLboolean *outFinished) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(FenceNVImpl);
};
class FenceSyncImpl
{
public:
FenceSyncImpl() { };
virtual ~FenceSyncImpl() { };
virtual gl::Error set() = 0;
virtual gl::Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) = 0;
virtual gl::Error serverWait(GLbitfield flags, GLuint64 timeout) = 0;
virtual gl::Error getStatus(GLint *outResult) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(FenceImpl);
DISALLOW_COPY_AND_ASSIGN(FenceSyncImpl);
};
}
......
......@@ -50,7 +50,8 @@ class TextureStorage;
class VertexBuffer;
class IndexBuffer;
class QueryImpl;
class FenceImpl;
class FenceNVImpl;
class FenceSyncImpl;
class BufferImpl;
class VertexArrayImpl;
class BufferStorage;
......@@ -227,7 +228,8 @@ class Renderer
// Query and Fence creation
virtual QueryImpl *createQuery(GLenum type) = 0;
virtual FenceImpl *createFence() = 0;
virtual FenceNVImpl *createFenceNV() = 0;
virtual FenceSyncImpl *createFenceSync() = 0;
// Transform Feedback creation
virtual TransformFeedbackImpl* createTransformFeedback() = 0;
......
......@@ -4,7 +4,7 @@
// found in the LICENSE file.
//
// Fence11.cpp: Defines the rx::Fence11 class which implements rx::FenceImpl.
// Fence11.cpp: Defines the rx::FenceNV11 and rx::FenceSync11 classes which implement rx::FenceNVImpl and rx::FenceSyncImpl.
#include "libGLESv2/renderer/d3d/d3d11/Fence11.h"
#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h"
......@@ -13,48 +13,43 @@
namespace rx
{
Fence11::Fence11(rx::Renderer11 *renderer)
: mRenderer(renderer),
mQuery(NULL)
{
}
Fence11::~Fence11()
{
SafeRelease(mQuery);
}
//
// Template helpers for set and test operations.
//
gl::Error Fence11::set()
template<class FenceClass>
gl::Error FenceSetHelper(FenceClass *fence)
{
if (!mQuery)
if (!fence->mQuery)
{
D3D11_QUERY_DESC queryDesc;
queryDesc.Query = D3D11_QUERY_EVENT;
queryDesc.MiscFlags = 0;
HRESULT result = mRenderer->getDevice()->CreateQuery(&queryDesc, &mQuery);
HRESULT result = fence->mRenderer->getDevice()->CreateQuery(&queryDesc, &fence->mQuery);
if (FAILED(result))
{
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create event query, result: 0x%X.", result);
}
}
mRenderer->getDeviceContext()->End(mQuery);
fence->mRenderer->getDeviceContext()->End(fence->mQuery);
return gl::Error(GL_NO_ERROR);
}
gl::Error Fence11::test(bool flushCommandBuffer, GLboolean *outFinished)
template <class FenceClass>
gl::Error FenceTestHelper(FenceClass *fence, bool flushCommandBuffer, GLboolean *outFinished)
{
ASSERT(mQuery);
ASSERT(fence->mQuery);
UINT getDataFlags = (flushCommandBuffer ? 0 : D3D11_ASYNC_GETDATA_DONOTFLUSH);
HRESULT result = mRenderer->getDeviceContext()->GetData(mQuery, NULL, 0, getDataFlags);
HRESULT result = fence->mRenderer->getDeviceContext()->GetData(fence->mQuery, NULL, 0, getDataFlags);
if (FAILED(result))
{
return gl::Error(GL_OUT_OF_MEMORY, "Failed to get query data, result: 0x%X.", result);
}
else if (mRenderer->isDeviceLost())
else if (fence->mRenderer->isDeviceLost())
{
return gl::Error(GL_OUT_OF_MEMORY, "Device was lost while querying result of an event query.");
}
......@@ -64,4 +59,172 @@ gl::Error Fence11::test(bool flushCommandBuffer, GLboolean *outFinished)
return gl::Error(GL_NO_ERROR);
}
//
// FenceNV11
//
FenceNV11::FenceNV11(Renderer11 *renderer)
: FenceNVImpl(),
mRenderer(renderer),
mQuery(NULL)
{
}
FenceNV11::~FenceNV11()
{
SafeRelease(mQuery);
}
gl::Error FenceNV11::set()
{
return FenceSetHelper(this);
}
gl::Error FenceNV11::test(bool flushCommandBuffer, GLboolean *outFinished)
{
return FenceTestHelper(this, flushCommandBuffer, outFinished);
}
gl::Error FenceNV11::finishFence(GLboolean *outFinished)
{
ASSERT(outFinished);
while (*outFinished != GL_TRUE)
{
gl::Error error = test(true, outFinished);
if (error.isError())
{
return error;
}
Sleep(0);
}
return gl::Error(GL_NO_ERROR);
}
//
// FenceSync11
//
// 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.
FenceSync11::FenceSync11(Renderer11 *renderer)
: FenceSyncImpl(),
mRenderer(renderer),
mQuery(NULL)
{
LARGE_INTEGER counterFreqency = { 0 };
BOOL success = QueryPerformanceFrequency(&counterFreqency);
UNUSED_ASSERTION_VARIABLE(success);
ASSERT(success);
mCounterFrequency = counterFreqency.QuadPart;
}
FenceSync11::~FenceSync11()
{
SafeRelease(mQuery);
}
gl::Error FenceSync11::set()
{
return FenceSetHelper(this);
}
gl::Error FenceSync11::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult)
{
ASSERT(outResult);
bool flushCommandBuffer = ((flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0);
GLboolean result = GL_FALSE;
gl::Error error = FenceTestHelper(this, flushCommandBuffer, &result);
if (error.isError())
{
*outResult = GL_WAIT_FAILED;
return error;
}
if (result == GL_TRUE)
{
*outResult = GL_ALREADY_SIGNALED;
return gl::Error(GL_NO_ERROR);
}
if (timeout == 0)
{
*outResult = GL_TIMEOUT_EXPIRED;
return gl::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 = FenceTestHelper(this, 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 gl::Error(GL_NO_ERROR);
}
gl::Error FenceSync11::serverWait(GLbitfield flags, GLuint64 timeout)
{
// 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 gl::Error(GL_NO_ERROR);
}
gl::Error FenceSync11::getStatus(GLint *outResult)
{
GLboolean result = GL_FALSE;
gl::Error error = FenceTestHelper(this, 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 gl::Error(GL_NO_ERROR);
}
} // namespace rx
......@@ -4,10 +4,10 @@
// found in the LICENSE file.
//
// Fence11.h: Defines the rx::Fence11 class which implements rx::FenceImpl.
// Fence11.h: Defines the rx::FenceNV11 and rx::FenceSync11 classes which implement rx::FenceNVImpl and rx::FenceSyncImpl.
#ifndef LIBGLESV2_RENDERER_Fence11_H_
#define LIBGLESV2_RENDERER_Fence11_H_
#ifndef LIBGLESV2_RENDERER_FENCE11_H_
#define LIBGLESV2_RENDERER_FENCE11_H_
#include "libGLESv2/renderer/FenceImpl.h"
......@@ -15,20 +15,46 @@ namespace rx
{
class Renderer11;
class Fence11 : public FenceImpl
class FenceNV11 : public FenceNVImpl
{
public:
explicit Fence11(rx::Renderer11 *renderer);
virtual ~Fence11();
explicit FenceNV11(Renderer11 *renderer);
virtual ~FenceNV11();
gl::Error set();
gl::Error test(bool flushCommandBuffer, GLboolean *outFinished);
gl::Error finishFence(GLboolean *outFinished);
private:
DISALLOW_COPY_AND_ASSIGN(Fence11);
DISALLOW_COPY_AND_ASSIGN(FenceNV11);
rx::Renderer11 *mRenderer;
template<class T> friend gl::Error FenceSetHelper(T *fence);
template<class T> friend gl::Error FenceTestHelper(T *fence, bool flushCommandBuffer, GLboolean *outFinished);
Renderer11 *mRenderer;
ID3D11Query *mQuery;
};
class FenceSync11 : public FenceSyncImpl
{
public:
explicit FenceSync11(Renderer11 *renderer);
virtual ~FenceSync11();
gl::Error set();
gl::Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult);
gl::Error serverWait(GLbitfield flags, GLuint64 timeout);
gl::Error getStatus(GLint *outResult);
private:
DISALLOW_COPY_AND_ASSIGN(FenceSync11);
template<class T> friend gl::Error FenceSetHelper(T *fence);
template<class T> friend gl::Error FenceTestHelper(T *fence, bool flushCommandBuffer, GLboolean *outFinished);
Renderer11 *mRenderer;
ID3D11Query *mQuery;
LONGLONG mCounterFrequency;
};
}
......
......@@ -2478,9 +2478,14 @@ QueryImpl *Renderer11::createQuery(GLenum type)
return new Query11(this, type);
}
FenceImpl *Renderer11::createFence()
FenceNVImpl *Renderer11::createFenceNV()
{
return new Fence11(this);
return new FenceNV11(this);
}
FenceSyncImpl *Renderer11::createFenceSync()
{
return new FenceSync11(this);
}
TransformFeedbackImpl* Renderer11::createTransformFeedback()
......
......@@ -172,7 +172,8 @@ class Renderer11 : public Renderer
// Query and Fence creation
virtual QueryImpl *createQuery(GLenum type);
virtual FenceImpl *createFence();
virtual FenceNVImpl *createFenceNV();
virtual FenceSyncImpl *createFenceSync();
// Transform Feedback creation
virtual TransformFeedbackImpl* createTransformFeedback();
......
......@@ -4,7 +4,7 @@
// found in the LICENSE file.
//
// Fence9.cpp: Defines the rx::Fence9 class.
// Fence9.cpp: Defines the rx::FenceNV9 class.
#include "libGLESv2/renderer/d3d/d3d9/Fence9.h"
#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h"
......@@ -14,18 +14,19 @@
namespace rx
{
Fence9::Fence9(rx::Renderer9 *renderer)
: mRenderer(renderer),
FenceNV9::FenceNV9(Renderer9 *renderer)
: FenceNVImpl(),
mRenderer(renderer),
mQuery(NULL)
{
}
Fence9::~Fence9()
FenceNV9::~FenceNV9()
{
SafeRelease(mQuery);
}
gl::Error Fence9::set()
gl::Error FenceNV9::set()
{
if (!mQuery)
{
......@@ -47,7 +48,7 @@ gl::Error Fence9::set()
return gl::Error(GL_NO_ERROR);
}
gl::Error Fence9::test(bool flushCommandBuffer, GLboolean *outFinished)
gl::Error FenceNV9::test(bool flushCommandBuffer, GLboolean *outFinished)
{
ASSERT(mQuery);
......@@ -69,4 +70,22 @@ gl::Error Fence9::test(bool flushCommandBuffer, GLboolean *outFinished)
return gl::Error(GL_NO_ERROR);
}
gl::Error FenceNV9::finishFence(GLboolean *outFinished)
{
ASSERT(outFinished);
while (*outFinished != GL_TRUE)
{
gl::Error error = test(true, outFinished);
if (error.isError())
{
return error;
}
Sleep(0);
}
return gl::Error(GL_NO_ERROR);
}
}
......@@ -4,7 +4,7 @@
// found in the LICENSE file.
//
// Fence9.h: Defines the rx::Fence9 class which implements rx::FenceImpl.
// Fence9.h: Defines the rx::FenceNV9 class which implements rx::FenceNVImpl.
#ifndef LIBGLESV2_RENDERER_FENCE9_H_
#define LIBGLESV2_RENDERER_FENCE9_H_
......@@ -15,19 +15,20 @@ namespace rx
{
class Renderer9;
class Fence9 : public FenceImpl
class FenceNV9 : public FenceNVImpl
{
public:
explicit Fence9(rx::Renderer9 *renderer);
virtual ~Fence9();
explicit FenceNV9(Renderer9 *renderer);
virtual ~FenceNV9();
gl::Error set();
gl::Error test(bool flushCommandBuffer, GLboolean *outFinished);
gl::Error finishFence(GLboolean *outFinished);
private:
DISALLOW_COPY_AND_ASSIGN(Fence9);
DISALLOW_COPY_AND_ASSIGN(FenceNV9);
rx::Renderer9 *mRenderer;
Renderer9 *mRenderer;
IDirect3DQuery9 *mQuery;
};
......
......@@ -637,9 +637,16 @@ QueryImpl *Renderer9::createQuery(GLenum type)
return new Query9(this, type);
}
FenceImpl *Renderer9::createFence()
FenceNVImpl *Renderer9::createFenceNV()
{
return new Fence9(this);
return new FenceNV9(this);
}
FenceSyncImpl *Renderer9::createFenceSync()
{
// Renderer9 doesn't support ES 3.0 and its sync objects.
UNREACHABLE();
return NULL;
}
TransformFeedbackImpl* Renderer9::createTransformFeedback()
......
......@@ -174,7 +174,8 @@ class Renderer9 : public Renderer
// Query and Fence creation
virtual QueryImpl *createQuery(GLenum type);
virtual FenceImpl *createFence();
virtual FenceNVImpl *createFenceNV();
virtual FenceSyncImpl *createFenceSync();
// Transform Feedback creation
virtual TransformFeedbackImpl* createTransformFeedback();
......
//
// Copyright (c) 2014 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.
//
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "libGLESv2/Fence.h"
#include "libGLESv2/renderer/FenceImpl.h"
using ::testing::_;
using ::testing::Return;
using ::testing::SetArgumentPointee;
namespace {
//
// FenceNV tests
//
class MockFenceNVImpl : public rx::FenceNVImpl
{
public:
virtual ~MockFenceNVImpl() { destroy(); }
MOCK_METHOD0(set, gl::Error());
MOCK_METHOD2(test, gl::Error(bool, GLboolean *));
MOCK_METHOD1(finishFence, gl::Error(GLboolean *));
MOCK_METHOD0(destroy, void());
};
class FenceNVTest : public testing::Test
{
protected:
virtual void SetUp()
{
mImpl = new MockFenceNVImpl;
EXPECT_CALL(*mImpl, destroy());
mFence = new gl::FenceNV(mImpl);
}
virtual void TearDown()
{
delete mFence;
}
MockFenceNVImpl *mImpl;
gl::FenceNV* mFence;
};
TEST_F(FenceNVTest, DestructionDeletesImpl)
{
MockFenceNVImpl* impl = new MockFenceNVImpl;
EXPECT_CALL(*impl, destroy()).Times(1).RetiresOnSaturation();
gl::FenceNV* fence = new gl::FenceNV(impl);
delete fence;
// Only needed because the mock is leaked if bugs are present,
// which logs an error, but does not cause the test to fail.
// Ordinarily mocks are verified when destroyed.
testing::Mock::VerifyAndClear(impl);
}
TEST_F(FenceNVTest, SetAndTestBehavior)
{
EXPECT_CALL(*mImpl, set())
.WillOnce(Return(gl::Error(GL_NO_ERROR)))
.RetiresOnSaturation();
EXPECT_EQ(GL_FALSE, mFence->isFence());
mFence->setFence(GL_ALL_COMPLETED_NV);
EXPECT_EQ(GL_TRUE, mFence->isFence());
// Fake the behavior of testing the fence before and after it's passed.
EXPECT_CALL(*mImpl, test(_, _))
.WillOnce(DoAll(SetArgumentPointee<1>(GL_FALSE),
Return(gl::Error(GL_NO_ERROR))))
.WillOnce(DoAll(SetArgumentPointee<1>(GL_TRUE),
Return(gl::Error(GL_NO_ERROR))))
.RetiresOnSaturation();
GLboolean out;
mFence->testFence(&out);
EXPECT_EQ(GL_FALSE, out);
mFence->testFence(&out);
EXPECT_EQ(GL_TRUE, out);
}
//
// FenceSync tests
//
class MockFenceSyncImpl : public rx::FenceSyncImpl
{
public:
virtual ~MockFenceSyncImpl() { destroy(); }
MOCK_METHOD0(set, gl::Error());
MOCK_METHOD3(clientWait, gl::Error(GLbitfield, GLuint64, GLenum *));
MOCK_METHOD2(serverWait, gl::Error(GLbitfield, GLuint64));
MOCK_METHOD1(getStatus, gl::Error(GLint *));
MOCK_METHOD0(destroy, void());
};
class FenceSyncTest : public testing::Test
{
protected:
virtual void SetUp()
{
mImpl = new MockFenceSyncImpl;
EXPECT_CALL(*mImpl, destroy());
mFence = new gl::FenceSync(mImpl, 1);
mFence->addRef();
}
virtual void TearDown()
{
mFence->release();
}
MockFenceSyncImpl *mImpl;
gl::FenceSync* mFence;
};
TEST_F(FenceSyncTest, DestructionDeletesImpl)
{
MockFenceSyncImpl* impl = new MockFenceSyncImpl;
EXPECT_CALL(*impl, destroy()).Times(1).RetiresOnSaturation();
gl::FenceSync* fence = new gl::FenceSync(impl, 1);
fence->addRef();
fence->release();
// Only needed because the mock is leaked if bugs are present,
// which logs an error, but does not cause the test to fail.
// Ordinarily mocks are verified when destroyed.
testing::Mock::VerifyAndClear(impl);
}
TEST_F(FenceSyncTest, SetAndGetStatusBehavior)
{
EXPECT_CALL(*mImpl, set())
.WillOnce(Return(gl::Error(GL_NO_ERROR)))
.RetiresOnSaturation();
mFence->set(GL_SYNC_GPU_COMMANDS_COMPLETE);
EXPECT_EQ(GL_SYNC_GPU_COMMANDS_COMPLETE, mFence->getCondition());
// Fake the behavior of testing the fence before and after it's passed.
EXPECT_CALL(*mImpl, getStatus(_))
.WillOnce(DoAll(SetArgumentPointee<0>(GL_UNSIGNALED),
Return(gl::Error(GL_NO_ERROR))))
.WillOnce(DoAll(SetArgumentPointee<0>(GL_SIGNALED),
Return(gl::Error(GL_NO_ERROR))))
.RetiresOnSaturation();
GLint out;
mFence->getStatus(&out);
EXPECT_EQ(GL_UNSIGNALED, out);
mFence->getStatus(&out);
EXPECT_EQ(GL_SIGNALED, out);
}
} // namespace
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment