xref: /aosp_15_r20/external/angle/src/tests/test_utils/MultiThreadSteps.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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