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/222954
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Tested-by: Kenneth Russell <kbr@chromium.org>
diff --git a/src/libGLESv2/Context.cpp b/src/libGLESv2/Context.cpp
index eab2dad..752212a 100644
--- a/src/libGLESv2/Context.cpp
+++ b/src/libGLESv2/Context.cpp
@@ -287,7 +287,7 @@
 {
     GLuint handle = mFenceNVHandleAllocator.allocate();
 
-    mFenceNVMap[handle] = new FenceNV(mRenderer);
+    mFenceNVMap[handle] = new FenceNV(mRenderer->createFenceNV());
 
     return handle;
 }
diff --git a/src/libGLESv2/Fence.cpp b/src/libGLESv2/Fence.cpp
index c0bef12..0aacb9d 100644
--- a/src/libGLESv2/Fence.cpp
+++ b/src/libGLESv2/Fence.cpp
@@ -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 @@
 {
     ASSERT(mIsSet);
 
-    while (mStatus != GL_TRUE)
-    {
-        Error error = mFence->test(true, &mStatus);
-        if (error.isError())
-        {
-            return error;
-        }
-
-        Sleep(0);
-    }
-
-    return Error(GL_NO_ERROR);
+    return mFence->finishFence(&mStatus);
 }
 
-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)
+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::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);
 }
 
 }
diff --git a/src/libGLESv2/Fence.h b/src/libGLESv2/Fence.h
index 0c4919d..411fa2c 100644
--- a/src/libGLESv2/Fence.h
+++ b/src/libGLESv2/Fence.h
@@ -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 @@
 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 @@
   private:
     DISALLOW_COPY_AND_ASSIGN(FenceNV);
 
-    rx::FenceImpl *mFence;
+    rx::FenceNVImpl *mFence;
 
     bool mIsSet;
 
@@ -52,12 +53,12 @@
 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 @@
   private:
     DISALLOW_COPY_AND_ASSIGN(FenceSync);
 
-    rx::FenceImpl *mFence;
-    LONGLONG mCounterFrequency;
+    rx::FenceSyncImpl *mFence;
 
     GLenum mCondition;
 };
diff --git a/src/libGLESv2/ResourceManager.cpp b/src/libGLESv2/ResourceManager.cpp
index 9121de1..04fa841 100644
--- a/src/libGLESv2/ResourceManager.cpp
+++ b/src/libGLESv2/ResourceManager.cpp
@@ -146,7 +146,7 @@
 {
     GLuint handle = mFenceSyncHandleAllocator.allocate();
 
-    FenceSync *fenceSync = new FenceSync(mRenderer, handle);
+    FenceSync *fenceSync = new FenceSync(mRenderer->createFenceSync(), handle);
     fenceSync->addRef();
     mFenceSyncMap[handle] = fenceSync;
 
diff --git a/src/libGLESv2/libGLESv2.cpp b/src/libGLESv2/libGLESv2.cpp
index f528222..054e310 100644
--- a/src/libGLESv2/libGLESv2.cpp
+++ b/src/libGLESv2/libGLESv2.cpp
@@ -2139,19 +2139,35 @@
         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 @@
             return;
         }
 
-        gl::Error error = fenceSync->serverWait();
+        gl::Error error = fenceSync->serverWait(flags, timeout);
         if (error.isError())
         {
             context->recordError(error);
diff --git a/src/libGLESv2/renderer/FenceImpl.h b/src/libGLESv2/renderer/FenceImpl.h
index 8d56851..1dd4678 100644
--- a/src/libGLESv2/renderer/FenceImpl.h
+++ b/src/libGLESv2/renderer/FenceImpl.h
@@ -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(FenceImpl);
+    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(FenceSyncImpl);
 };
 
 }
diff --git a/src/libGLESv2/renderer/Renderer.h b/src/libGLESv2/renderer/Renderer.h
index 43c2dac..1730725 100644
--- a/src/libGLESv2/renderer/Renderer.h
+++ b/src/libGLESv2/renderer/Renderer.h
@@ -50,7 +50,8 @@
 class VertexBuffer;
 class IndexBuffer;
 class QueryImpl;
-class FenceImpl;
+class FenceNVImpl;
+class FenceSyncImpl;
 class BufferImpl;
 class VertexArrayImpl;
 class BufferStorage;
@@ -227,7 +228,8 @@
 
     // 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;
diff --git a/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp b/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp
index c0f462a..e96c515 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp
@@ -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)
-{
-}
+//
+// Template helpers for set and test operations.
+//
 
-Fence11::~Fence11()
+template<class FenceClass>
+gl::Error FenceSetHelper(FenceClass *fence)
 {
-    SafeRelease(mQuery);
-}
-
-gl::Error Fence11::set()
-{
-    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 @@
     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
diff --git a/src/libGLESv2/renderer/d3d/d3d11/Fence11.h b/src/libGLESv2/renderer/d3d/d3d11/Fence11.h
index 9347197..1223a53 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/Fence11.h
+++ b/src/libGLESv2/renderer/d3d/d3d11/Fence11.h
@@ -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,22 +15,48 @@
 {
 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;
+};
+
 }
 
 #endif // LIBGLESV2_RENDERER_FENCE11_H_
diff --git a/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp b/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
index e58076d..3f92cd4 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
@@ -2478,9 +2478,14 @@
     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()
diff --git a/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h b/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h
index b36c316..86935bc 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h
+++ b/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h
@@ -172,7 +172,8 @@
 
     // Query and Fence creation
     virtual QueryImpl *createQuery(GLenum type);
-    virtual FenceImpl *createFence();
+    virtual FenceNVImpl *createFenceNV();
+    virtual FenceSyncImpl *createFenceSync();
 
     // Transform Feedback creation
     virtual TransformFeedbackImpl* createTransformFeedback();
diff --git a/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp b/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp
index 5140e96..66263fe 100644
--- a/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp
@@ -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 @@
     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 @@
     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);
+}
+
 }
diff --git a/src/libGLESv2/renderer/d3d/d3d9/Fence9.h b/src/libGLESv2/renderer/d3d/d3d9/Fence9.h
index 3bf9d08..d7873d5 100644
--- a/src/libGLESv2/renderer/d3d/d3d9/Fence9.h
+++ b/src/libGLESv2/renderer/d3d/d3d9/Fence9.h
@@ -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 @@
 {
 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;
 };
 
diff --git a/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp b/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
index 6e2bc6d..e0afaa2 100644
--- a/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
@@ -637,9 +637,16 @@
     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()
diff --git a/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h b/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h
index 7d4c73c..3bd8902 100644
--- a/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h
+++ b/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h
@@ -174,7 +174,8 @@
 
     // Query and Fence creation
     virtual QueryImpl *createQuery(GLenum type);
-    virtual FenceImpl *createFence();
+    virtual FenceNVImpl *createFenceNV();
+    virtual FenceSyncImpl *createFenceSync();
 
     // Transform Feedback creation
     virtual TransformFeedbackImpl* createTransformFeedback();
diff --git a/tests/angle_implementation_unit_tests/Fence_unittest.cpp b/tests/angle_implementation_unit_tests/Fence_unittest.cpp
new file mode 100644
index 0000000..27596a0
--- /dev/null
+++ b/tests/angle_implementation_unit_tests/Fence_unittest.cpp
@@ -0,0 +1,162 @@
+//
+// 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