| // |
| // Copyright 2019 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. |
| // |
| // EGLSyncTest.cpp: |
| // Tests of EGL_KHR_fence_sync and EGL_KHR_wait_sync extensions. |
| |
| #include <gtest/gtest.h> |
| |
| #include "test_utils/ANGLETest.h" |
| #include "test_utils/angle_test_configs.h" |
| #include "util/EGLWindow.h" |
| |
| using namespace angle; |
| |
| class EGLSyncTest : public ANGLETest |
| { |
| protected: |
| bool hasFenceSyncExtension() const |
| { |
| return IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), "EGL_KHR_fence_sync"); |
| } |
| bool hasWaitSyncExtension() const |
| { |
| return hasFenceSyncExtension() && |
| IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), "EGL_KHR_wait_sync"); |
| } |
| bool hasGLSyncExtension() const { return IsGLExtensionEnabled("GL_OES_EGL_sync"); } |
| |
| bool hasAndroidNativeFenceSyncExtension() const |
| { |
| return IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), |
| "EGL_ANDROID_native_fence_sync"); |
| } |
| }; |
| |
| // Test error cases for all EGL_KHR_fence_sync functions |
| TEST_P(EGLSyncTest, FenceSyncErrors) |
| { |
| ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension()); |
| |
| EGLDisplay display = getEGLWindow()->getDisplay(); |
| |
| // If the client API doesn't have the necessary extension, test that sync creation fails and |
| // ignore the rest of the tests. |
| if (!hasGLSyncExtension()) |
| { |
| EXPECT_EQ(EGL_NO_SYNC_KHR, eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr)); |
| EXPECT_EGL_ERROR(EGL_BAD_MATCH); |
| } |
| |
| ANGLE_SKIP_TEST_IF(!hasGLSyncExtension()); |
| |
| EGLContext context = eglGetCurrentContext(); |
| EGLSurface drawSurface = eglGetCurrentSurface(EGL_DRAW); |
| EGLSurface readSurface = eglGetCurrentSurface(EGL_READ); |
| |
| EXPECT_NE(context, EGL_NO_CONTEXT); |
| EXPECT_NE(drawSurface, EGL_NO_SURFACE); |
| EXPECT_NE(readSurface, EGL_NO_SURFACE); |
| |
| // CreateSync with no attribute shouldn't cause an error |
| EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr); |
| EXPECT_NE(sync, EGL_NO_SYNC_KHR); |
| |
| EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync)); |
| |
| // CreateSync with empty attribute shouldn't cause an error |
| const EGLint emptyAttributes[] = {EGL_NONE}; |
| sync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, emptyAttributes); |
| EXPECT_NE(sync, EGL_NO_SYNC_KHR); |
| |
| // DestroySync generates BAD_PARAMETER if the sync is not valid |
| EXPECT_EGL_FALSE(eglDestroySyncKHR(display, reinterpret_cast<EGLSyncKHR>(20))); |
| EXPECT_EGL_ERROR(EGL_BAD_PARAMETER); |
| |
| // CreateSync generates BAD_DISPLAY if display is not valid |
| EXPECT_EQ(EGL_NO_SYNC_KHR, eglCreateSyncKHR(EGL_NO_DISPLAY, EGL_SYNC_FENCE_KHR, nullptr)); |
| EXPECT_EGL_ERROR(EGL_BAD_DISPLAY); |
| |
| // CreateSync generates BAD_ATTRIBUTE if attribute is neither nullptr nor empty. |
| const EGLint nonEmptyAttributes[] = { |
| EGL_CL_EVENT_HANDLE, |
| 0, |
| EGL_NONE, |
| }; |
| EXPECT_EQ(EGL_NO_SYNC_KHR, eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nonEmptyAttributes)); |
| EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE); |
| |
| // CreateSync generates BAD_ATTRIBUTE if type is not valid |
| EXPECT_EQ(EGL_NO_SYNC_KHR, eglCreateSyncKHR(display, 0, nullptr)); |
| EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE); |
| |
| // CreateSync generates BAD_MATCH if no context is current |
| eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); |
| EXPECT_EQ(EGL_NO_SYNC_KHR, eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr)); |
| EXPECT_EGL_ERROR(EGL_BAD_MATCH); |
| eglMakeCurrent(display, drawSurface, readSurface, context); |
| |
| // ClientWaitSync generates EGL_BAD_PARAMETER if the sync object is not valid |
| EXPECT_EGL_FALSE(eglClientWaitSyncKHR(display, reinterpret_cast<EGLSyncKHR>(30), 0, 0)); |
| EXPECT_EGL_ERROR(EGL_BAD_PARAMETER); |
| |
| // GetSyncAttrib generates EGL_BAD_PARAMETER if the sync object is not valid, and value is not |
| // modified |
| constexpr EGLint kSentinelAttribValue = 123456789; |
| EGLint attribValue = kSentinelAttribValue; |
| EXPECT_EGL_FALSE(eglGetSyncAttribKHR(display, reinterpret_cast<EGLSyncKHR>(40), |
| EGL_SYNC_TYPE_KHR, &attribValue)); |
| EXPECT_EGL_ERROR(EGL_BAD_PARAMETER); |
| EXPECT_EQ(attribValue, kSentinelAttribValue); |
| |
| // GetSyncAttrib generates EGL_BAD_ATTRIBUTE if the attribute is not valid, and value is not |
| // modified |
| EXPECT_EGL_FALSE(eglGetSyncAttribKHR(display, sync, EGL_CL_EVENT_HANDLE, &attribValue)); |
| EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE); |
| EXPECT_EQ(attribValue, kSentinelAttribValue); |
| |
| // GetSyncAttrib generates EGL_BAD_MATCH if the attribute is valid for sync, but not the |
| // particular sync type. We don't have such a case at the moment. |
| |
| EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync)); |
| } |
| |
| // Test error cases for all EGL_KHR_wait_sync functions |
| TEST_P(EGLSyncTest, WaitSyncErrors) |
| { |
| // The client API that shows support for eglWaitSyncKHR is the same as the one required for |
| // eglCreateSyncKHR. As such, there is no way to create a sync and not be able to wait on it. |
| // This would have created an EGL_BAD_MATCH error. |
| ANGLE_SKIP_TEST_IF(!hasWaitSyncExtension() || !hasGLSyncExtension()); |
| |
| EGLDisplay display = getEGLWindow()->getDisplay(); |
| EGLContext context = eglGetCurrentContext(); |
| EGLSurface drawSurface = eglGetCurrentSurface(EGL_DRAW); |
| EGLSurface readSurface = eglGetCurrentSurface(EGL_READ); |
| |
| EXPECT_NE(context, EGL_NO_CONTEXT); |
| EXPECT_NE(drawSurface, EGL_NO_SURFACE); |
| EXPECT_NE(readSurface, EGL_NO_SURFACE); |
| |
| EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr); |
| EXPECT_NE(sync, EGL_NO_SYNC_KHR); |
| |
| // WaitSync generates BAD_MATCH if no context is current |
| eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); |
| EXPECT_EGL_FALSE(eglWaitSyncKHR(display, sync, 0)); |
| EXPECT_EGL_ERROR(EGL_BAD_MATCH); |
| eglMakeCurrent(display, drawSurface, readSurface, context); |
| |
| // WaitSync generates BAD_PARAMETER if the sync is not valid |
| EXPECT_EGL_FALSE(eglWaitSyncKHR(display, reinterpret_cast<EGLSyncKHR>(20), 0)); |
| EXPECT_EGL_ERROR(EGL_BAD_PARAMETER); |
| |
| // WaitSync generates BAD_PARAMETER if flags is non-zero |
| EXPECT_EGL_FALSE(eglWaitSyncKHR(display, sync, 1)); |
| EXPECT_EGL_ERROR(EGL_BAD_PARAMETER); |
| |
| EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync)); |
| } |
| |
| // Test usage of eglGetSyncAttribKHR |
| TEST_P(EGLSyncTest, GetSyncAttrib) |
| { |
| ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension()); |
| |
| EGLDisplay display = getEGLWindow()->getDisplay(); |
| |
| EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr); |
| EXPECT_NE(sync, EGL_NO_SYNC_KHR); |
| |
| // Fence sync attributes are: |
| // |
| // EGL_SYNC_TYPE_KHR: EGL_SYNC_FENCE_KHR |
| // EGL_SYNC_STATUS_KHR: EGL_UNSIGNALED_KHR or EGL_SIGNALED_KHR |
| // EGL_SYNC_CONDITION_KHR: EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR |
| |
| constexpr EGLint kSentinelAttribValue = 123456789; |
| EGLint attribValue = kSentinelAttribValue; |
| EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_TYPE_KHR, &attribValue)); |
| EXPECT_EQ(attribValue, EGL_SYNC_FENCE_KHR); |
| |
| attribValue = kSentinelAttribValue; |
| EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_CONDITION_KHR, &attribValue)); |
| EXPECT_EQ(attribValue, EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR); |
| |
| attribValue = kSentinelAttribValue; |
| EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_STATUS_KHR, &attribValue)); |
| |
| // Hack around EXPECT_* not having an "either this or that" variant: |
| if (attribValue != EGL_SIGNALED_KHR) |
| { |
| EXPECT_EQ(attribValue, EGL_UNSIGNALED_KHR); |
| } |
| |
| EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync)); |
| } |
| |
| // Test that basic usage works and doesn't generate errors or crash |
| TEST_P(EGLSyncTest, BasicOperations) |
| { |
| ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension()); |
| |
| EGLDisplay display = getEGLWindow()->getDisplay(); |
| |
| EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr); |
| EXPECT_NE(sync, EGL_NO_SYNC_KHR); |
| |
| glClearColor(1.0f, 0.0f, 1.0f, 1.0f); |
| |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_EGL_TRUE(eglWaitSyncKHR(display, sync, 0)); |
| |
| glFlush(); |
| |
| EGLint value = 0; |
| unsigned int loopCount = 0; |
| |
| // Use 'loopCount' to make sure the test doesn't get stuck in an infinite loop |
| while (value != EGL_SIGNALED_KHR && loopCount <= 1000000) |
| { |
| loopCount++; |
| EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_STATUS_KHR, &value)); |
| } |
| |
| ASSERT_EQ(value, EGL_SIGNALED_KHR); |
| |
| for (size_t i = 0; i < 20; i++) |
| { |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_EQ( |
| EGL_CONDITION_SATISFIED_KHR, |
| eglClientWaitSyncKHR(display, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR)); |
| EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, sync, EGL_SYNC_STATUS_KHR, &value)); |
| EXPECT_EQ(value, EGL_SIGNALED_KHR); |
| } |
| |
| EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync)); |
| } |
| |
| // Test eglWaitNative api |
| TEST_P(EGLSyncTest, WaitNative) |
| { |
| // Clear to red color |
| glClearColor(1.0f, 0.0f, 0.0f, 1.0f); |
| |
| glClear(GL_COLOR_BUFFER_BIT); |
| EXPECT_EGL_TRUE(eglWaitNative(EGL_CORE_NATIVE_ENGINE)); |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::red); |
| } |
| |
| // Verify eglDupNativeFence for EGL_ANDROID_native_fence_sync |
| TEST_P(EGLSyncTest, AndroidNativeFence_DupNativeFenceFD) |
| { |
| ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension()); |
| ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension()); |
| ANGLE_SKIP_TEST_IF(!hasAndroidNativeFenceSyncExtension()); |
| |
| EGLDisplay display = getEGLWindow()->getDisplay(); |
| |
| // We can ClientWait on this |
| EGLSyncKHR syncWithGeneratedFD = |
| eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); |
| EXPECT_NE(syncWithGeneratedFD, EGL_NO_SYNC_KHR); |
| |
| int fd = eglDupNativeFenceFDANDROID(display, syncWithGeneratedFD); |
| EXPECT_EGL_SUCCESS(); |
| |
| // Clean up created objects. |
| if (fd != EGL_NO_NATIVE_FENCE_FD_ANDROID) |
| { |
| close(fd); |
| } |
| |
| EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncWithGeneratedFD)); |
| } |
| |
| // Verify CreateSync and ClientWait for EGL_ANDROID_native_fence_sync |
| TEST_P(EGLSyncTest, AndroidNativeFence_ClientWait) |
| { |
| ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension()); |
| ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension()); |
| ANGLE_SKIP_TEST_IF(!hasAndroidNativeFenceSyncExtension()); |
| |
| EGLint value = 0; |
| EGLDisplay display = getEGLWindow()->getDisplay(); |
| |
| // We can ClientWait on this |
| EGLSyncKHR syncWithGeneratedFD = |
| eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); |
| EXPECT_NE(syncWithGeneratedFD, EGL_NO_SYNC_KHR); |
| |
| // Create work to do |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| glFinish(); |
| |
| // Wait for draw to complete |
| EXPECT_EQ(EGL_CONDITION_SATISFIED, |
| eglClientWaitSyncKHR(display, syncWithGeneratedFD, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, |
| 1000000000)); |
| EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, syncWithGeneratedFD, EGL_SYNC_STATUS_KHR, &value)); |
| EXPECT_EQ(value, EGL_SIGNALED_KHR); |
| |
| // Clean up created objects. |
| EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncWithGeneratedFD)); |
| } |
| |
| // Verify WaitSync with EGL_ANDROID_native_fence_sync |
| // Simulate passing FDs across processes by passing across Contexts. |
| TEST_P(EGLSyncTest, AndroidNativeFence_WaitSync) |
| { |
| ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension()); |
| ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension()); |
| ANGLE_SKIP_TEST_IF(!hasAndroidNativeFenceSyncExtension()); |
| |
| EGLint value = 0; |
| EGLDisplay display = getEGLWindow()->getDisplay(); |
| EGLSurface surface = getEGLWindow()->getSurface(); |
| |
| /*- First Context ------------------------*/ |
| |
| // We can ClientWait on this |
| EGLSyncKHR syncWithGeneratedFD = |
| eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); |
| EXPECT_NE(syncWithGeneratedFD, EGL_NO_SYNC_KHR); |
| |
| int fd = eglDupNativeFenceFDANDROID(display, syncWithGeneratedFD); |
| EXPECT_EGL_SUCCESS(); // Can return -1 (when signaled) or valid FD. |
| |
| // Create work to do |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| glFinish(); |
| |
| /*- Second Context ------------------------*/ |
| if (fd > EGL_NO_NATIVE_FENCE_FD_ANDROID) |
| { |
| EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); |
| |
| EGLContext context2 = getEGLWindow()->createContext(EGL_NO_CONTEXT); |
| EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, context2)); |
| |
| // We can eglWaitSync on this - import FD from first sync. |
| EGLint syncAttribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, (EGLint)fd, EGL_NONE}; |
| EGLSyncKHR syncWithDupFD = |
| eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, syncAttribs); |
| EXPECT_NE(syncWithDupFD, EGL_NO_SYNC_KHR); |
| |
| // Second draw waits for first to complete. May already be signaled - ignore error. |
| if (eglWaitSyncKHR(display, syncWithDupFD, 0) == EGL_TRUE) |
| { |
| // Create work to do |
| glClearColor(1.0f, 0.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| glFinish(); |
| } |
| |
| // Wait for second draw to complete |
| EXPECT_EQ(EGL_CONDITION_SATISFIED, |
| eglClientWaitSyncKHR(display, syncWithDupFD, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, |
| 1000000000)); |
| EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, syncWithDupFD, EGL_SYNC_STATUS_KHR, &value)); |
| EXPECT_EQ(value, EGL_SIGNALED_KHR); |
| |
| // Reset to default context and surface. |
| EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); |
| EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, getEGLWindow()->getContext())); |
| |
| // Clean up created objects. |
| EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncWithDupFD)); |
| EXPECT_EGL_TRUE(eglDestroyContext(display, context2)); |
| } |
| |
| // Wait for first draw to complete |
| EXPECT_EQ(EGL_CONDITION_SATISFIED, |
| eglClientWaitSyncKHR(display, syncWithGeneratedFD, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, |
| 1000000000)); |
| EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, syncWithGeneratedFD, EGL_SYNC_STATUS_KHR, &value)); |
| EXPECT_EQ(value, EGL_SIGNALED_KHR); |
| |
| // Clean up created objects. |
| EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncWithGeneratedFD)); |
| } |
| |
| // Verify EGL_ANDROID_native_fence_sync |
| // Simulate passing FDs across processes by passing across Contexts. |
| TEST_P(EGLSyncTest, AndroidNativeFence_withFences) |
| { |
| ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension()); |
| ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension()); |
| ANGLE_SKIP_TEST_IF(!hasAndroidNativeFenceSyncExtension()); |
| |
| EGLint value = 0; |
| EGLDisplay display = getEGLWindow()->getDisplay(); |
| EGLSurface surface = getEGLWindow()->getSurface(); |
| |
| /*- First Context ------------------------*/ |
| |
| // Extra fence syncs to ensure that Fence and Android Native fences work together |
| EGLSyncKHR syncFence1 = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr); |
| EXPECT_NE(syncFence1, EGL_NO_SYNC_KHR); |
| |
| // We can ClientWait on this |
| EGLSyncKHR syncWithGeneratedFD = |
| eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); |
| EXPECT_NE(syncWithGeneratedFD, EGL_NO_SYNC_KHR); |
| |
| int fd = eglDupNativeFenceFDANDROID(display, syncWithGeneratedFD); |
| EXPECT_EGL_SUCCESS(); // Can return -1 (when signaled) or valid FD. |
| |
| EGLSyncKHR syncFence2 = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr); |
| EXPECT_NE(syncFence2, EGL_NO_SYNC_KHR); |
| |
| // Create work to do |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| glFlush(); |
| |
| /*- Second Context ------------------------*/ |
| if (fd > EGL_NO_NATIVE_FENCE_FD_ANDROID) |
| { |
| EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); |
| |
| EGLContext context2 = getEGLWindow()->createContext(EGL_NO_CONTEXT); |
| EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, context2)); |
| |
| // check that Fence and Android fences work together |
| EGLSyncKHR syncFence3 = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr); |
| EXPECT_NE(syncFence3, EGL_NO_SYNC_KHR); |
| |
| // We can eglWaitSync on this |
| EGLint syncAttribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, (EGLint)fd, EGL_NONE}; |
| EGLSyncKHR syncWithDupFD = |
| eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, syncAttribs); |
| EXPECT_NE(syncWithDupFD, EGL_NO_SYNC_KHR); |
| |
| EGLSyncKHR syncFence4 = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr); |
| EXPECT_NE(syncFence4, EGL_NO_SYNC_KHR); |
| |
| // Second draw waits for first to complete. May already be signaled - ignore error. |
| if (eglWaitSyncKHR(display, syncWithDupFD, 0) == EGL_TRUE) |
| { |
| // Create work to do |
| glClearColor(1.0f, 0.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| glFlush(); |
| } |
| |
| // Wait for second draw to complete |
| EXPECT_EQ(EGL_CONDITION_SATISFIED, |
| eglClientWaitSyncKHR(display, syncWithDupFD, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, |
| 1000000000)); |
| EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, syncWithDupFD, EGL_SYNC_STATUS_KHR, &value)); |
| EXPECT_EQ(value, EGL_SIGNALED_KHR); |
| |
| // Reset to default context and surface. |
| EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); |
| EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, getEGLWindow()->getContext())); |
| |
| // Clean up created objects. |
| EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncFence3)); |
| EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncFence4)); |
| EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncWithDupFD)); |
| EXPECT_EGL_TRUE(eglDestroyContext(display, context2)); |
| } |
| |
| // Wait for first draw to complete |
| EXPECT_EQ(EGL_CONDITION_SATISFIED, |
| eglClientWaitSyncKHR(display, syncWithGeneratedFD, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, |
| 1000000000)); |
| EXPECT_EGL_TRUE(eglGetSyncAttribKHR(display, syncWithGeneratedFD, EGL_SYNC_STATUS_KHR, &value)); |
| EXPECT_EQ(value, EGL_SIGNALED_KHR); |
| |
| // Clean up created objects. |
| EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncFence1)); |
| EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncFence2)); |
| EXPECT_EGL_TRUE(eglDestroySyncKHR(display, syncWithGeneratedFD)); |
| } |
| |
| ANGLE_INSTANTIATE_TEST(EGLSyncTest, |
| ES2_D3D9(), |
| ES2_D3D11(), |
| ES3_D3D11(), |
| ES2_OPENGL(), |
| ES3_OPENGL(), |
| ES2_OPENGLES(), |
| ES3_OPENGLES(), |
| ES2_VULKAN(), |
| ES3_VULKAN()); |