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