1 //
2 // Copyright 2022 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // MultiThreadSteps.cpp:
7 // Synchronization help for tests that use multiple threads.
8
9 #include "MultiThreadSteps.h"
10
11 #include "angle_test_platform.h"
12 #include "gtest/gtest.h"
13 #include "util/EGLWindow.h"
14
15 namespace angle
16 {
17
RunLockStepThreads(EGLWindow * window,size_t threadCount,LockStepThreadFunc threadFuncs[])18 void RunLockStepThreads(EGLWindow *window, size_t threadCount, LockStepThreadFunc threadFuncs[])
19 {
20 constexpr EGLint kPBufferSize = 256;
21 RunLockStepThreadsWithSize(window, kPBufferSize, kPBufferSize, threadCount, threadFuncs);
22 }
23
RunLockStepThreadsWithSize(EGLWindow * window,EGLint width,EGLint height,size_t threadCount,LockStepThreadFunc threadFuncs[])24 void RunLockStepThreadsWithSize(EGLWindow *window,
25 EGLint width,
26 EGLint height,
27 size_t threadCount,
28 LockStepThreadFunc threadFuncs[])
29 {
30 EGLDisplay dpy = window->getDisplay();
31 EGLConfig config = window->getConfig();
32
33 // Initialize the pbuffer and context
34 EGLint pbufferAttributes[] = {
35 EGL_WIDTH, width, EGL_HEIGHT, height, EGL_NONE, EGL_NONE,
36 };
37
38 std::vector<EGLSurface> surfaces(threadCount);
39 std::vector<EGLContext> contexts(threadCount);
40
41 // Create N surfaces and shared contexts, one for each thread
42 for (size_t threadIndex = 0; threadIndex < threadCount; ++threadIndex)
43 {
44 surfaces[threadIndex] = eglCreatePbufferSurface(dpy, config, pbufferAttributes);
45 EXPECT_EQ(eglGetError(), EGL_SUCCESS);
46 EGLint extraAttributes[] = {EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE,
47 static_cast<EGLint>(threadIndex), EGL_NONE};
48 if (!IsEGLDisplayExtensionEnabled(dpy, "EGL_ANGLE_context_virtualization"))
49 {
50 extraAttributes[0] = EGL_NONE;
51 }
52 contexts[threadIndex] =
53 window->createContext(threadIndex == 0 ? EGL_NO_CONTEXT : contexts[0], extraAttributes);
54 EXPECT_NE(EGL_NO_CONTEXT, contexts[threadIndex]) << threadIndex;
55 }
56
57 std::vector<std::thread> threads(threadCount);
58
59 // Run the threads
60 for (size_t threadIndex = 0; threadIndex < threadCount; ++threadIndex)
61 {
62 threads[threadIndex] = std::thread(std::move(threadFuncs[threadIndex]), dpy,
63 surfaces[threadIndex], contexts[threadIndex]);
64 }
65
66 // Wait for them to finish
67 for (size_t threadIndex = 0; threadIndex < threadCount; ++threadIndex)
68 {
69 threads[threadIndex].join();
70
71 // Clean up
72 eglDestroySurface(dpy, surfaces[threadIndex]);
73 eglDestroyContext(dpy, contexts[threadIndex]);
74 }
75 }
76 } // namespace angle
77