| // | |
| // Copyright 2022 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. | |
| // | |
| // MultiThreadSteps.cpp: | |
| // Synchronization help for tests that use multiple threads. | |
| #include "MultiThreadSteps.h" | |
| #include "angle_test_platform.h" | |
| #include "gtest/gtest.h" | |
| #include "util/EGLWindow.h" | |
| namespace angle | |
| { | |
| void RunLockStepThreads(EGLWindow *window, size_t threadCount, LockStepThreadFunc threadFuncs[]) | |
| { | |
| EGLDisplay dpy = window->getDisplay(); | |
| EGLConfig config = window->getConfig(); | |
| constexpr EGLint kPBufferSize = 256; | |
| // Initialize the pbuffer and context | |
| EGLint pbufferAttributes[] = { | |
| EGL_WIDTH, kPBufferSize, EGL_HEIGHT, kPBufferSize, EGL_NONE, EGL_NONE, | |
| }; | |
| std::vector<EGLSurface> surfaces(threadCount); | |
| std::vector<EGLContext> contexts(threadCount); | |
| // Create N surfaces and shared contexts, one for each thread | |
| for (size_t threadIndex = 0; threadIndex < threadCount; ++threadIndex) | |
| { | |
| surfaces[threadIndex] = eglCreatePbufferSurface(dpy, config, pbufferAttributes); | |
| EXPECT_EQ(eglGetError(), EGL_SUCCESS); | |
| EGLint extraAttributes[] = {EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE, | |
| static_cast<EGLint>(threadIndex), EGL_NONE}; | |
| if (!IsEGLDisplayExtensionEnabled(dpy, "EGL_ANGLE_context_virtualization")) | |
| { | |
| extraAttributes[0] = EGL_NONE; | |
| } | |
| contexts[threadIndex] = | |
| window->createContext(threadIndex == 0 ? EGL_NO_CONTEXT : contexts[0], extraAttributes); | |
| EXPECT_NE(EGL_NO_CONTEXT, contexts[threadIndex]) << threadIndex; | |
| } | |
| std::vector<std::thread> threads(threadCount); | |
| // Run the threads | |
| for (size_t threadIndex = 0; threadIndex < threadCount; ++threadIndex) | |
| { | |
| threads[threadIndex] = std::thread(std::move(threadFuncs[threadIndex]), dpy, | |
| surfaces[threadIndex], contexts[threadIndex]); | |
| } | |
| // Wait for them to finish | |
| for (size_t threadIndex = 0; threadIndex < threadCount; ++threadIndex) | |
| { | |
| threads[threadIndex].join(); | |
| // Clean up | |
| eglDestroySurface(dpy, surfaces[threadIndex]); | |
| eglDestroyContext(dpy, contexts[threadIndex]); | |
| } | |
| } | |
| } // namespace angle |