Implement FenceNVGL.

BUG=angleproject:888

Change-Id: Iea6993fe5459cf829f4bd23b0df5e223f22903f5
Reviewed-on: https://chromium-review.googlesource.com/264989
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Tested-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/Fence.cpp b/src/libANGLE/Fence.cpp
index 2337364..aa76791 100644
--- a/src/libANGLE/Fence.cpp
+++ b/src/libANGLE/Fence.cpp
@@ -32,16 +32,9 @@
     SafeDelete(mFence);
 }
 
-GLboolean FenceNV::isFence() const
+Error FenceNV::set(GLenum condition)
 {
-    // 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();
+    Error error = mFence->set(condition);
     if (error.isError())
     {
         return error;
@@ -54,10 +47,10 @@
     return Error(GL_NO_ERROR);
 }
 
-Error FenceNV::testFence(GLboolean *outResult)
+Error FenceNV::test(GLboolean *outResult)
 {
     // Flush the command buffer by default
-    Error error = mFence->test(true, &mStatus);
+    Error error = mFence->test(&mStatus);
     if (error.isError())
     {
         return error;
@@ -67,11 +60,19 @@
     return Error(GL_NO_ERROR);
 }
 
-Error FenceNV::finishFence()
+Error FenceNV::finish()
 {
     ASSERT(mIsSet);
 
-    return mFence->finishFence(&mStatus);
+    gl::Error error = mFence->finish();
+    if (error.isError())
+    {
+        return error;
+    }
+
+    mStatus = GL_TRUE;
+
+    return Error(GL_NO_ERROR);
 }
 
 FenceSync::FenceSync(rx::FenceSyncImpl *impl, GLuint id)
diff --git a/src/libANGLE/Fence.h b/src/libANGLE/Fence.h
index 2d8beee..74dad05 100644
--- a/src/libANGLE/Fence.h
+++ b/src/libANGLE/Fence.h
@@ -30,11 +30,11 @@
     explicit FenceNV(rx::FenceNVImpl *impl);
     virtual ~FenceNV();
 
-    GLboolean isFence() const;
-    Error setFence(GLenum condition);
-    Error testFence(GLboolean *outResult);
-    Error finishFence();
+    Error set(GLenum condition);
+    Error test(GLboolean *outResult);
+    Error finish();
 
+    bool isSet() const { return mIsSet; }
     GLboolean getStatus() const { return mStatus; }
     GLenum getCondition() const { return mCondition; }
 
diff --git a/src/libANGLE/Fence_unittest.cpp b/src/libANGLE/Fence_unittest.cpp
index 50a56bb..37b3e6f 100644
--- a/src/libANGLE/Fence_unittest.cpp
+++ b/src/libANGLE/Fence_unittest.cpp
@@ -25,9 +25,9 @@
   public:
     virtual ~MockFenceNVImpl() { destroy(); }
 
-    MOCK_METHOD0(set, gl::Error());
-    MOCK_METHOD2(test, gl::Error(bool, GLboolean *));
-    MOCK_METHOD1(finishFence, gl::Error(GLboolean *));
+    MOCK_METHOD1(set, gl::Error(GLenum));
+    MOCK_METHOD1(test, gl::Error(GLboolean *));
+    MOCK_METHOD0(finish, gl::Error());
 
     MOCK_METHOD0(destroy, void());
 };
@@ -67,23 +67,23 @@
 
 TEST_F(FenceNVTest, SetAndTestBehavior)
 {
-    EXPECT_CALL(*mImpl, set())
+    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());
+    EXPECT_FALSE(mFence->isSet());
+    mFence->set(GL_ALL_COMPLETED_NV);
+    EXPECT_TRUE(mFence->isSet());
     // Fake the behavior of testing the fence before and after it's passed.
-    EXPECT_CALL(*mImpl, test(_, _))
-        .WillOnce(DoAll(SetArgumentPointee<1>(GL_FALSE),
+    EXPECT_CALL(*mImpl, test(_))
+        .WillOnce(DoAll(SetArgumentPointee<0>(GL_FALSE),
                         Return(gl::Error(GL_NO_ERROR))))
-        .WillOnce(DoAll(SetArgumentPointee<1>(GL_TRUE),
+        .WillOnce(DoAll(SetArgumentPointee<0>(GL_TRUE),
                         Return(gl::Error(GL_NO_ERROR))))
         .RetiresOnSaturation();
     GLboolean out;
-    mFence->testFence(&out);
+    mFence->test(&out);
     EXPECT_EQ(GL_FALSE, out);
-    mFence->testFence(&out);
+    mFence->test(&out);
     EXPECT_EQ(GL_TRUE, out);
 }
 
diff --git a/src/libANGLE/renderer/FenceNVImpl.h b/src/libANGLE/renderer/FenceNVImpl.h
index 3463921..a534914 100644
--- a/src/libANGLE/renderer/FenceNVImpl.h
+++ b/src/libANGLE/renderer/FenceNVImpl.h
@@ -24,9 +24,9 @@
     FenceNVImpl() { };
     virtual ~FenceNVImpl() { };
 
-    virtual gl::Error set() = 0;
-    virtual gl::Error test(bool flushCommandBuffer, GLboolean *outFinished) = 0;
-    virtual gl::Error finishFence(GLboolean *outFinished) = 0;
+    virtual gl::Error set(GLenum condition) = 0;
+    virtual gl::Error test(GLboolean *outFinished) = 0;
+    virtual gl::Error finish() = 0;
 };
 
 }
diff --git a/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp b/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp
index ec006b5..e1bfdef 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp
@@ -76,23 +76,22 @@
     SafeRelease(mQuery);
 }
 
-gl::Error FenceNV11::set()
+gl::Error FenceNV11::set(GLenum condition)
 {
     return FenceSetHelper(this);
 }
 
-gl::Error FenceNV11::test(bool flushCommandBuffer, GLboolean *outFinished)
+gl::Error FenceNV11::test(GLboolean *outFinished)
 {
-    return FenceTestHelper(this, flushCommandBuffer, outFinished);
+    return FenceTestHelper(this, true, outFinished);
 }
 
-gl::Error FenceNV11::finishFence(GLboolean *outFinished)
+gl::Error FenceNV11::finish()
 {
-    ASSERT(outFinished);
-
-    while (*outFinished != GL_TRUE)
+    GLboolean finished = GL_FALSE;
+    while (finished != GL_TRUE)
     {
-        gl::Error error = test(true, outFinished);
+        gl::Error error = FenceTestHelper(this, true, &finished);
         if (error.isError())
         {
             return error;
diff --git a/src/libANGLE/renderer/d3d/d3d11/Fence11.h b/src/libANGLE/renderer/d3d/d3d11/Fence11.h
index 74e9763..5959788 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Fence11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/Fence11.h
@@ -20,11 +20,11 @@
 {
   public:
     explicit FenceNV11(Renderer11 *renderer);
-    virtual ~FenceNV11();
+    ~FenceNV11() override;
 
-    gl::Error set();
-    gl::Error test(bool flushCommandBuffer, GLboolean *outFinished);
-    gl::Error finishFence(GLboolean *outFinished);
+    gl::Error set(GLenum condition) override;
+    gl::Error test(GLboolean *outFinished) override;
+    gl::Error finish() override;
 
   private:
     template<class T> friend gl::Error FenceSetHelper(T *fence);
diff --git a/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp b/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp
index 27c265e..3300681 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp
+++ b/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp
@@ -25,7 +25,7 @@
     SafeRelease(mQuery);
 }
 
-gl::Error FenceNV9::set()
+gl::Error FenceNV9::set(GLenum condition)
 {
     if (!mQuery)
     {
@@ -47,7 +47,29 @@
     return gl::Error(GL_NO_ERROR);
 }
 
-gl::Error FenceNV9::test(bool flushCommandBuffer, GLboolean *outFinished)
+gl::Error FenceNV9::test(GLboolean *outFinished)
+{
+    return testHelper(true, outFinished);
+}
+
+gl::Error FenceNV9::finish()
+{
+    GLboolean finished = GL_FALSE;
+    while (finished != GL_TRUE)
+    {
+        gl::Error error = testHelper(true, &finished);
+        if (error.isError())
+        {
+            return error;
+        }
+
+        Sleep(0);
+    }
+
+    return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error FenceNV9::testHelper(bool flushCommandBuffer, GLboolean *outFinished)
 {
     ASSERT(mQuery);
 
@@ -69,22 +91,4 @@
     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/libANGLE/renderer/d3d/d3d9/Fence9.h b/src/libANGLE/renderer/d3d/d3d9/Fence9.h
index 4b86747..200ac68 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Fence9.h
+++ b/src/libANGLE/renderer/d3d/d3d9/Fence9.h
@@ -20,13 +20,15 @@
 {
   public:
     explicit FenceNV9(Renderer9 *renderer);
-    virtual ~FenceNV9();
+    ~FenceNV9() override;
 
-    gl::Error set();
-    gl::Error test(bool flushCommandBuffer, GLboolean *outFinished);
-    gl::Error finishFence(GLboolean *outFinished);
+    gl::Error set(GLenum condition) override;
+    gl::Error test(GLboolean *outFinished) override;
+    gl::Error finish() override;
 
   private:
+    gl::Error testHelper(bool flushCommandBuffer, GLboolean *outFinished);
+
     Renderer9 *mRenderer;
     IDirect3DQuery9 *mQuery;
 };
diff --git a/src/libANGLE/renderer/gl/FenceNVGL.cpp b/src/libANGLE/renderer/gl/FenceNVGL.cpp
index 6e4dd40..b463054 100644
--- a/src/libANGLE/renderer/gl/FenceNVGL.cpp
+++ b/src/libANGLE/renderer/gl/FenceNVGL.cpp
@@ -9,33 +9,43 @@
 #include "libANGLE/renderer/gl/FenceNVGL.h"
 
 #include "common/debug.h"
+#include "libANGLE/renderer/gl/FunctionsGL.h"
+
 
 namespace rx
 {
 
-FenceNVGL::FenceNVGL()
-    : FenceNVImpl()
-{}
+FenceNVGL::FenceNVGL(const FunctionsGL *functions)
+    : FenceNVImpl(),
+      mFunctions(functions)
+{
+    mFunctions->genFencesNV(1, &mFence);
+}
 
 FenceNVGL::~FenceNVGL()
-{}
-
-gl::Error FenceNVGL::set()
 {
-    UNIMPLEMENTED();
-    return gl::Error(GL_INVALID_OPERATION);
+    mFunctions->deleteFencesNV(1, &mFence);
+    mFence = 0;
 }
 
-gl::Error FenceNVGL::test(bool flushCommandBuffer, GLboolean *outFinished)
+gl::Error FenceNVGL::set(GLenum condition)
 {
-    UNIMPLEMENTED();
-    return gl::Error(GL_INVALID_OPERATION);
+    ASSERT(condition == GL_ALL_COMPLETED_NV);
+    mFunctions->setFenceNV(mFence, condition);
+    return gl::Error(GL_NO_ERROR);
 }
 
-gl::Error FenceNVGL::finishFence(GLboolean *outFinished)
+gl::Error FenceNVGL::test(GLboolean *outFinished)
 {
-    UNIMPLEMENTED();
-    return gl::Error(GL_INVALID_OPERATION);
+    ASSERT(outFinished);
+    *outFinished = mFunctions->testFenceNV(mFence);
+    return gl::Error(GL_NO_ERROR);
+}
+
+gl::Error FenceNVGL::finish()
+{
+    mFunctions->finishFenceNV(mFence);
+    return gl::Error(GL_NO_ERROR);
 }
 
 }
diff --git a/src/libANGLE/renderer/gl/FenceNVGL.h b/src/libANGLE/renderer/gl/FenceNVGL.h
index 84d549f..ffeca85 100644
--- a/src/libANGLE/renderer/gl/FenceNVGL.h
+++ b/src/libANGLE/renderer/gl/FenceNVGL.h
@@ -13,16 +13,22 @@
 
 namespace rx
 {
+class FunctionsGL;
 
 class FenceNVGL : public FenceNVImpl
 {
   public:
-    FenceNVGL();
+    explicit FenceNVGL(const FunctionsGL *functions);
     ~FenceNVGL() override;
 
-    gl::Error set() override;
-    gl::Error test(bool flushCommandBuffer, GLboolean *outFinished) override;
-    gl::Error finishFence(GLboolean *outFinished) override;
+    gl::Error set(GLenum condition) override;
+    gl::Error test(GLboolean *outFinished) override;
+    gl::Error finish() override;
+
+  private:
+    GLuint mFence;
+
+    const FunctionsGL *mFunctions;
 };
 
 }
diff --git a/src/libANGLE/renderer/gl/FunctionsGL.cpp b/src/libANGLE/renderer/gl/FunctionsGL.cpp
index e20249f..926209b 100644
--- a/src/libANGLE/renderer/gl/FunctionsGL.cpp
+++ b/src/libANGLE/renderer/gl/FunctionsGL.cpp
@@ -159,6 +159,14 @@
       texImage3D(nullptr),
       texSubImage3D(nullptr),
 
+      deleteFencesNV(nullptr),
+      genFencesNV(nullptr),
+      isFenceNV(nullptr),
+      testFenceNV(nullptr),
+      getFenceivNV(nullptr),
+      finishFenceNV(nullptr),
+      setFenceNV(nullptr),
+
       activeTexture(nullptr),
       compressedTexImage1D(nullptr),
       compressedTexImage2D(nullptr),
@@ -863,6 +871,15 @@
         AssignGLEntryPoint(loadProcAddress("glDrawRangeElements"), &drawRangeElements);
         AssignGLEntryPoint(loadProcAddress("glTexImage3D"), &texImage3D);
         AssignGLEntryPoint(loadProcAddress("glTexSubImage3D"), &texSubImage3D);
+
+        // Extensions
+        AssignGLExtensionEntryPoint(extensions, "GL_NV_fence", loadProcAddress("glDeleteFencesNV"), &deleteFencesNV);
+        AssignGLExtensionEntryPoint(extensions, "GL_NV_fence", loadProcAddress("glGenFencesNV"), &genFencesNV);
+        AssignGLExtensionEntryPoint(extensions, "GL_NV_fence", loadProcAddress("glIsFenceNV"), &isFenceNV);
+        AssignGLExtensionEntryPoint(extensions, "GL_NV_fence", loadProcAddress("glTestFenceNV"), &testFenceNV);
+        AssignGLExtensionEntryPoint(extensions, "GL_NV_fence", loadProcAddress("glGetFenceivNV"), &getFenceivNV);
+        AssignGLExtensionEntryPoint(extensions, "GL_NV_fence", loadProcAddress("glFinishFenceNV"), &finishFenceNV);
+        AssignGLExtensionEntryPoint(extensions, "GL_NV_fence", loadProcAddress("glSetFenceNV"), &setFenceNV);
     }
 
     // 1.3
diff --git a/src/libANGLE/renderer/gl/FunctionsGL.h b/src/libANGLE/renderer/gl/FunctionsGL.h
index f479086..bf6c2bf 100644
--- a/src/libANGLE/renderer/gl/FunctionsGL.h
+++ b/src/libANGLE/renderer/gl/FunctionsGL.h
@@ -106,6 +106,15 @@
     PFNGLTEXIMAGE3DPROC texImage3D;
     PFNGLTEXSUBIMAGE3DPROC texSubImage3D;
 
+    // 1.2 Extensions
+    PFNGLDELETEFENCESNVPROC deleteFencesNV;
+    PFNGLGENFENCESNVPROC genFencesNV;
+    PFNGLISFENCENVPROC isFenceNV;
+    PFNGLTESTFENCENVPROC testFenceNV;
+    PFNGLGETFENCEIVNVPROC getFenceivNV;
+    PFNGLFINISHFENCENVPROC finishFenceNV;
+    PFNGLSETFENCENVPROC setFenceNV;
+
     // 1.3
     PFNGLACTIVETEXTUREPROC activeTexture;
     PFNGLCOMPRESSEDTEXIMAGE1DPROC compressedTexImage1D;
diff --git a/src/libANGLE/renderer/gl/RendererGL.cpp b/src/libANGLE/renderer/gl/RendererGL.cpp
index 53f2e89..7e1b0b0 100644
--- a/src/libANGLE/renderer/gl/RendererGL.cpp
+++ b/src/libANGLE/renderer/gl/RendererGL.cpp
@@ -144,7 +144,7 @@
 
 FenceNVImpl *RendererGL::createFenceNV()
 {
-    return new FenceNVGL();
+    return new FenceNVGL(mFunctions);
 }
 
 FenceSyncImpl *RendererGL::createFenceSync()
diff --git a/src/libANGLE/renderer/gl/functionsgl_enums.h b/src/libANGLE/renderer/gl/functionsgl_enums.h
index 8e27af9..42e5f38 100644
--- a/src/libANGLE/renderer/gl/functionsgl_enums.h
+++ b/src/libANGLE/renderer/gl/functionsgl_enums.h
@@ -250,6 +250,11 @@
 #define GL_UNSIGNED_SHORT_5_6_5 0x8363
 #define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364
 
+// 1.2 Extensions
+#define GL_ALL_COMPLETED_NV 0x84F2
+#define GL_FENCE_STATUS_NV 0x84F3
+#define GL_FENCE_CONDITION_NV 0x84F4
+
 // 1.3
 #define GL_ACTIVE_TEXTURE 0x84E0
 #define GL_CLAMP_TO_BORDER 0x812D
diff --git a/src/libANGLE/renderer/gl/functionsgl_typedefs.h b/src/libANGLE/renderer/gl/functionsgl_typedefs.h
index 713a35a..82fb5d8 100644
--- a/src/libANGLE/renderer/gl/functionsgl_typedefs.h
+++ b/src/libANGLE/renderer/gl/functionsgl_typedefs.h
@@ -125,6 +125,15 @@
 typedef void (INTERNAL_GL_APIENTRY *PFNGLTEXIMAGE3DPROC)(GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
 typedef void (INTERNAL_GL_APIENTRY *PFNGLTEXSUBIMAGE3DPROC)(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
 
+// 1.2 Extensions
+typedef void (INTERNAL_GL_APIENTRY *PFNGLDELETEFENCESNVPROC)(GLsizei, const GLuint *);
+typedef void (INTERNAL_GL_APIENTRY *PFNGLGENFENCESNVPROC)(GLsizei, GLuint *);
+typedef GLboolean (INTERNAL_GL_APIENTRY *PFNGLISFENCENVPROC)(GLuint);
+typedef GLboolean (INTERNAL_GL_APIENTRY *PFNGLTESTFENCENVPROC)(GLuint);
+typedef void (INTERNAL_GL_APIENTRY *PFNGLGETFENCEIVNVPROC)(GLuint, GLenum, GLint *);
+typedef void (INTERNAL_GL_APIENTRY *PFNGLFINISHFENCENVPROC)(GLuint);
+typedef void (INTERNAL_GL_APIENTRY *PFNGLSETFENCENVPROC)(GLuint, GLenum);
+
 // 1.3
 typedef void (INTERNAL_GL_APIENTRY *PFNGLACTIVETEXTUREPROC)(GLenum);
 typedef void (INTERNAL_GL_APIENTRY *PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *);
diff --git a/src/libANGLE/renderer/gl/renderergl_utils.cpp b/src/libANGLE/renderer/gl/renderergl_utils.cpp
index 433aee2..f395ff4 100644
--- a/src/libANGLE/renderer/gl/renderergl_utils.cpp
+++ b/src/libANGLE/renderer/gl/renderergl_utils.cpp
@@ -155,6 +155,7 @@
     extensions->textureStorage = true;
     extensions->fboRenderMipmap = true;
     extensions->framebufferMultisample = caps->maxSamples > 0;
+    extensions->fence = std::find(functions->extensions.begin(), functions->extensions.end(), "GL_NV_fence") != functions->extensions.end();
 }
 
 }
diff --git a/src/libGLESv2/entry_points_gles_2_0_ext.cpp b/src/libGLESv2/entry_points_gles_2_0_ext.cpp
index 6f85b2f..1756618 100644
--- a/src/libGLESv2/entry_points_gles_2_0_ext.cpp
+++ b/src/libGLESv2/entry_points_gles_2_0_ext.cpp
@@ -168,13 +168,13 @@
             return;
         }
 
-        if (fenceObject->isFence() != GL_TRUE)
+        if (fenceObject->isSet() != GL_TRUE)
         {
             context->recordError(Error(GL_INVALID_OPERATION));
             return;
         }
 
-        fenceObject->finishFence();
+        fenceObject->finish();
     }
 }
 
@@ -233,7 +233,7 @@
             return;
         }
 
-        if (fenceObject->isFence() != GL_TRUE)
+        if (fenceObject->isSet() != GL_TRUE)
         {
             context->recordError(Error(GL_INVALID_OPERATION));
             return;
@@ -249,7 +249,7 @@
                 GLboolean status = GL_TRUE;
                 if (fenceObject->getStatus() != GL_TRUE)
                 {
-                    Error error = fenceObject->testFence(&status);
+                    Error error = fenceObject->test(&status);
                     if (error.isError())
                     {
                         context->recordError(error);
@@ -448,7 +448,9 @@
             return GL_FALSE;
         }
 
-        return fenceObject->isFence();
+        // GL_NV_fence spec:
+        // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an existing fence.
+        return fenceObject->isSet();
     }
 
     return GL_FALSE;
@@ -548,7 +550,7 @@
             return;
         }
 
-        Error error = fenceObject->setFence(condition);
+        Error error = fenceObject->set(condition);
         if (error.isError())
         {
             context->recordError(error);
@@ -572,14 +574,14 @@
             return GL_TRUE;
         }
 
-        if (fenceObject->isFence() != GL_TRUE)
+        if (fenceObject->isSet() != GL_TRUE)
         {
             context->recordError(Error(GL_INVALID_OPERATION));
             return GL_TRUE;
         }
 
         GLboolean result;
-        Error error = fenceObject->testFence(&result);
+        Error error = fenceObject->test(&result);
         if (error.isError())
         {
             context->recordError(error);