xref: /aosp_15_r20/external/angle/src/tests/egl_tests/EGLContextASANTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2020 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker // EGLContextASANTest.cpp:
7*8975f5c5SAndroid Build Coastguard Worker //   Tests relating to ASAN errors regarding context.
8*8975f5c5SAndroid Build Coastguard Worker 
9*8975f5c5SAndroid Build Coastguard Worker #include <gtest/gtest.h>
10*8975f5c5SAndroid Build Coastguard Worker 
11*8975f5c5SAndroid Build Coastguard Worker #include "test_utils/ANGLETest.h"
12*8975f5c5SAndroid Build Coastguard Worker #include "test_utils/angle_test_configs.h"
13*8975f5c5SAndroid Build Coastguard Worker #include "test_utils/gl_raii.h"
14*8975f5c5SAndroid Build Coastguard Worker #include "util/EGLWindow.h"
15*8975f5c5SAndroid Build Coastguard Worker 
16*8975f5c5SAndroid Build Coastguard Worker #include <condition_variable>
17*8975f5c5SAndroid Build Coastguard Worker #include <mutex>
18*8975f5c5SAndroid Build Coastguard Worker #include <thread>
19*8975f5c5SAndroid Build Coastguard Worker 
20*8975f5c5SAndroid Build Coastguard Worker using namespace angle;
21*8975f5c5SAndroid Build Coastguard Worker 
22*8975f5c5SAndroid Build Coastguard Worker namespace
23*8975f5c5SAndroid Build Coastguard Worker {
24*8975f5c5SAndroid Build Coastguard Worker 
SafeDestroyContext(EGLDisplay display,EGLContext & context)25*8975f5c5SAndroid Build Coastguard Worker EGLBoolean SafeDestroyContext(EGLDisplay display, EGLContext &context)
26*8975f5c5SAndroid Build Coastguard Worker {
27*8975f5c5SAndroid Build Coastguard Worker     EGLBoolean result = EGL_TRUE;
28*8975f5c5SAndroid Build Coastguard Worker     if (context != EGL_NO_CONTEXT)
29*8975f5c5SAndroid Build Coastguard Worker     {
30*8975f5c5SAndroid Build Coastguard Worker         result  = eglDestroyContext(display, context);
31*8975f5c5SAndroid Build Coastguard Worker         context = EGL_NO_CONTEXT;
32*8975f5c5SAndroid Build Coastguard Worker     }
33*8975f5c5SAndroid Build Coastguard Worker     return result;
34*8975f5c5SAndroid Build Coastguard Worker }
35*8975f5c5SAndroid Build Coastguard Worker 
36*8975f5c5SAndroid Build Coastguard Worker class EGLContextASANTest : public ANGLETest<>
37*8975f5c5SAndroid Build Coastguard Worker {
38*8975f5c5SAndroid Build Coastguard Worker   public:
EGLContextASANTest()39*8975f5c5SAndroid Build Coastguard Worker     EGLContextASANTest() {}
40*8975f5c5SAndroid Build Coastguard Worker };
41*8975f5c5SAndroid Build Coastguard Worker 
42*8975f5c5SAndroid Build Coastguard Worker // Tests that creating resources works after freeing the share context.
TEST_P(EGLContextASANTest,DestroyContextInUse)43*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLContextASANTest, DestroyContextInUse)
44*8975f5c5SAndroid Build Coastguard Worker {
45*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
46*8975f5c5SAndroid Build Coastguard Worker 
47*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay display = getEGLWindow()->getDisplay();
48*8975f5c5SAndroid Build Coastguard Worker     EGLConfig config   = getEGLWindow()->getConfig();
49*8975f5c5SAndroid Build Coastguard Worker     EGLSurface surface = getEGLWindow()->getSurface();
50*8975f5c5SAndroid Build Coastguard Worker 
51*8975f5c5SAndroid Build Coastguard Worker     const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION,
52*8975f5c5SAndroid Build Coastguard Worker                                      getEGLWindow()->getClientMajorVersion(), EGL_NONE};
53*8975f5c5SAndroid Build Coastguard Worker 
54*8975f5c5SAndroid Build Coastguard Worker     EGLContext context = eglCreateContext(display, config, nullptr, contextAttribs);
55*8975f5c5SAndroid Build Coastguard Worker     ASSERT_EGL_SUCCESS();
56*8975f5c5SAndroid Build Coastguard Worker     ASSERT_TRUE(context != EGL_NO_CONTEXT);
57*8975f5c5SAndroid Build Coastguard Worker 
58*8975f5c5SAndroid Build Coastguard Worker     // Synchronization tools to ensure the two threads are interleaved as designed by this test.
59*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
60*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
61*8975f5c5SAndroid Build Coastguard Worker 
62*8975f5c5SAndroid Build Coastguard Worker     enum class Step
63*8975f5c5SAndroid Build Coastguard Worker     {
64*8975f5c5SAndroid Build Coastguard Worker         Start,
65*8975f5c5SAndroid Build Coastguard Worker         Thread1Draw,
66*8975f5c5SAndroid Build Coastguard Worker         Thread0Delete,
67*8975f5c5SAndroid Build Coastguard Worker         Thread1Draw2,
68*8975f5c5SAndroid Build Coastguard Worker         Finish,
69*8975f5c5SAndroid Build Coastguard Worker         Abort,
70*8975f5c5SAndroid Build Coastguard Worker     };
71*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
72*8975f5c5SAndroid Build Coastguard Worker 
73*8975f5c5SAndroid Build Coastguard Worker     // Helper functions to synchronize the threads so that the operations are executed in the
74*8975f5c5SAndroid Build Coastguard Worker     // specific order the test is written for.
75*8975f5c5SAndroid Build Coastguard Worker     auto waitForStep = [&](Step waitStep) -> bool {
76*8975f5c5SAndroid Build Coastguard Worker         std::unique_lock<std::mutex> lock(mutex);
77*8975f5c5SAndroid Build Coastguard Worker         while (currentStep != waitStep)
78*8975f5c5SAndroid Build Coastguard Worker         {
79*8975f5c5SAndroid Build Coastguard Worker             // If necessary, abort execution as the other thread has encountered a GL error.
80*8975f5c5SAndroid Build Coastguard Worker             if (currentStep == Step::Abort)
81*8975f5c5SAndroid Build Coastguard Worker             {
82*8975f5c5SAndroid Build Coastguard Worker                 return false;
83*8975f5c5SAndroid Build Coastguard Worker             }
84*8975f5c5SAndroid Build Coastguard Worker             condVar.wait(lock);
85*8975f5c5SAndroid Build Coastguard Worker         }
86*8975f5c5SAndroid Build Coastguard Worker 
87*8975f5c5SAndroid Build Coastguard Worker         return true;
88*8975f5c5SAndroid Build Coastguard Worker     };
89*8975f5c5SAndroid Build Coastguard Worker     auto nextStep = [&](Step newStep) {
90*8975f5c5SAndroid Build Coastguard Worker         {
91*8975f5c5SAndroid Build Coastguard Worker             std::unique_lock<std::mutex> lock(mutex);
92*8975f5c5SAndroid Build Coastguard Worker             currentStep = newStep;
93*8975f5c5SAndroid Build Coastguard Worker         }
94*8975f5c5SAndroid Build Coastguard Worker         condVar.notify_one();
95*8975f5c5SAndroid Build Coastguard Worker     };
96*8975f5c5SAndroid Build Coastguard Worker 
97*8975f5c5SAndroid Build Coastguard Worker     class AbortOnFailure
98*8975f5c5SAndroid Build Coastguard Worker     {
99*8975f5c5SAndroid Build Coastguard Worker       public:
100*8975f5c5SAndroid Build Coastguard Worker         AbortOnFailure(Step *currentStep, std::mutex *mutex, std::condition_variable *condVar)
101*8975f5c5SAndroid Build Coastguard Worker             : mCurrentStep(currentStep), mMutex(mutex), mCondVar(condVar)
102*8975f5c5SAndroid Build Coastguard Worker         {}
103*8975f5c5SAndroid Build Coastguard Worker 
104*8975f5c5SAndroid Build Coastguard Worker         ~AbortOnFailure()
105*8975f5c5SAndroid Build Coastguard Worker         {
106*8975f5c5SAndroid Build Coastguard Worker             bool isAborting = false;
107*8975f5c5SAndroid Build Coastguard Worker             {
108*8975f5c5SAndroid Build Coastguard Worker                 std::unique_lock<std::mutex> lock(*mMutex);
109*8975f5c5SAndroid Build Coastguard Worker                 isAborting = *mCurrentStep != Step::Finish;
110*8975f5c5SAndroid Build Coastguard Worker 
111*8975f5c5SAndroid Build Coastguard Worker                 if (isAborting)
112*8975f5c5SAndroid Build Coastguard Worker                 {
113*8975f5c5SAndroid Build Coastguard Worker                     *mCurrentStep = Step::Abort;
114*8975f5c5SAndroid Build Coastguard Worker                 }
115*8975f5c5SAndroid Build Coastguard Worker             }
116*8975f5c5SAndroid Build Coastguard Worker             mCondVar->notify_all();
117*8975f5c5SAndroid Build Coastguard Worker         }
118*8975f5c5SAndroid Build Coastguard Worker 
119*8975f5c5SAndroid Build Coastguard Worker       private:
120*8975f5c5SAndroid Build Coastguard Worker         Step *mCurrentStep;
121*8975f5c5SAndroid Build Coastguard Worker         std::mutex *mMutex;
122*8975f5c5SAndroid Build Coastguard Worker         std::condition_variable *mCondVar;
123*8975f5c5SAndroid Build Coastguard Worker     };
124*8975f5c5SAndroid Build Coastguard Worker 
125*8975f5c5SAndroid Build Coastguard Worker     // Unmake current to release the "surface".
126*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
127*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
128*8975f5c5SAndroid Build Coastguard Worker 
129*8975f5c5SAndroid Build Coastguard Worker     std::thread deletingThread = std::thread([&]() {
130*8975f5c5SAndroid Build Coastguard Worker         AbortOnFailure abortOnFailure(&currentStep, &mutex, &condVar);
131*8975f5c5SAndroid Build Coastguard Worker 
132*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
133*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
134*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_NO_ERROR();
135*8975f5c5SAndroid Build Coastguard Worker 
136*8975f5c5SAndroid Build Coastguard Worker         // Wait for other thread to draw
137*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(waitForStep(Step::Thread1Draw));
138*8975f5c5SAndroid Build Coastguard Worker 
139*8975f5c5SAndroid Build Coastguard Worker         // Delete the context, if implemented properly this is a no-op because the context is
140*8975f5c5SAndroid Build Coastguard Worker         // current in another thread.
141*8975f5c5SAndroid Build Coastguard Worker         SafeDestroyContext(display, context);
142*8975f5c5SAndroid Build Coastguard Worker 
143*8975f5c5SAndroid Build Coastguard Worker         // Wait for the other thread to use context again
144*8975f5c5SAndroid Build Coastguard Worker         nextStep(Step::Thread0Delete);
145*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(waitForStep(Step::Finish));
146*8975f5c5SAndroid Build Coastguard Worker     });
147*8975f5c5SAndroid Build Coastguard Worker 
148*8975f5c5SAndroid Build Coastguard Worker     std::thread continuingThread = std::thread([&]() {
149*8975f5c5SAndroid Build Coastguard Worker         EGLContext localContext = context;
150*8975f5c5SAndroid Build Coastguard Worker         AbortOnFailure abortOnFailure(&currentStep, &mutex, &condVar);
151*8975f5c5SAndroid Build Coastguard Worker 
152*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, localContext));
153*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
154*8975f5c5SAndroid Build Coastguard Worker 
155*8975f5c5SAndroid Build Coastguard Worker         constexpr GLsizei kTexSize = 1;
156*8975f5c5SAndroid Build Coastguard Worker         const GLColor kTexData     = GLColor::red;
157*8975f5c5SAndroid Build Coastguard Worker 
158*8975f5c5SAndroid Build Coastguard Worker         GLTexture tex;
159*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, tex);
160*8975f5c5SAndroid Build Coastguard Worker         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
161*8975f5c5SAndroid Build Coastguard Worker                      &kTexData);
162*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
163*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
164*8975f5c5SAndroid Build Coastguard Worker 
165*8975f5c5SAndroid Build Coastguard Worker         GLProgram program;
166*8975f5c5SAndroid Build Coastguard Worker         program.makeRaster(essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
167*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(program.valid());
168*8975f5c5SAndroid Build Coastguard Worker 
169*8975f5c5SAndroid Build Coastguard Worker         // Draw using the texture.
170*8975f5c5SAndroid Build Coastguard Worker         drawQuad(program.get(), essl1_shaders::PositionAttrib(), 0.5f);
171*8975f5c5SAndroid Build Coastguard Worker 
172*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, localContext));
173*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
174*8975f5c5SAndroid Build Coastguard Worker 
175*8975f5c5SAndroid Build Coastguard Worker         // Wait for the other thread to delete the context.
176*8975f5c5SAndroid Build Coastguard Worker         nextStep(Step::Thread1Draw);
177*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(waitForStep(Step::Thread0Delete));
178*8975f5c5SAndroid Build Coastguard Worker 
179*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, localContext));
180*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
181*8975f5c5SAndroid Build Coastguard Worker 
182*8975f5c5SAndroid Build Coastguard Worker         // Draw again. If the context has been inappropriately deleted in thread0 this will cause a
183*8975f5c5SAndroid Build Coastguard Worker         // use-after-free error.
184*8975f5c5SAndroid Build Coastguard Worker         drawQuad(program.get(), essl1_shaders::PositionAttrib(), 0.5f);
185*8975f5c5SAndroid Build Coastguard Worker 
186*8975f5c5SAndroid Build Coastguard Worker         nextStep(Step::Finish);
187*8975f5c5SAndroid Build Coastguard Worker 
188*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
189*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
190*8975f5c5SAndroid Build Coastguard Worker     });
191*8975f5c5SAndroid Build Coastguard Worker 
192*8975f5c5SAndroid Build Coastguard Worker     deletingThread.join();
193*8975f5c5SAndroid Build Coastguard Worker     continuingThread.join();
194*8975f5c5SAndroid Build Coastguard Worker 
195*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
196*8975f5c5SAndroid Build Coastguard Worker 
197*8975f5c5SAndroid Build Coastguard Worker     // Make default context and surface current again.
198*8975f5c5SAndroid Build Coastguard Worker     EXPECT_TRUE(getEGLWindow()->makeCurrent());
199*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
200*8975f5c5SAndroid Build Coastguard Worker 
201*8975f5c5SAndroid Build Coastguard Worker     // cleanup
202*8975f5c5SAndroid Build Coastguard Worker     ASSERT_GL_NO_ERROR();
203*8975f5c5SAndroid Build Coastguard Worker }
204*8975f5c5SAndroid Build Coastguard Worker }  // anonymous namespace
205*8975f5c5SAndroid Build Coastguard Worker 
206*8975f5c5SAndroid Build Coastguard Worker GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EGLContextASANTest);
207*8975f5c5SAndroid Build Coastguard Worker ANGLE_INSTANTIATE_TEST(EGLContextASANTest,
208*8975f5c5SAndroid Build Coastguard Worker                        ES2_D3D9(),
209*8975f5c5SAndroid Build Coastguard Worker                        ES2_D3D11(),
210*8975f5c5SAndroid Build Coastguard Worker                        ES3_D3D11(),
211*8975f5c5SAndroid Build Coastguard Worker                        ES2_OPENGL(),
212*8975f5c5SAndroid Build Coastguard Worker                        ES3_OPENGL(),
213*8975f5c5SAndroid Build Coastguard Worker                        ES2_VULKAN(),
214*8975f5c5SAndroid Build Coastguard Worker                        ES3_VULKAN());
215