Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/angle
Path: blob/main_old/src/tests/egl_tests/EGLMultiContextTest.cpp
1693 views
1
//
2
// Copyright 2021 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
// EGLMultiContextTest.cpp:
7
// Tests relating to multiple non-shared Contexts.
8
9
#include <gtest/gtest.h>
10
11
#include "test_utils/ANGLETest.h"
12
#include "test_utils/MultiThreadSteps.h"
13
#include "test_utils/angle_test_configs.h"
14
#include "test_utils/gl_raii.h"
15
#include "util/EGLWindow.h"
16
17
using namespace angle;
18
19
namespace
20
{
21
22
EGLBoolean SafeDestroyContext(EGLDisplay display, EGLContext &context)
23
{
24
EGLBoolean result = EGL_TRUE;
25
if (context != EGL_NO_CONTEXT)
26
{
27
result = eglDestroyContext(display, context);
28
context = EGL_NO_CONTEXT;
29
}
30
return result;
31
}
32
33
class EGLMultiContextTest : public ANGLETest
34
{
35
public:
36
EGLMultiContextTest() : mContexts{EGL_NO_CONTEXT, EGL_NO_CONTEXT}, mTexture(0) {}
37
38
void testTearDown() override
39
{
40
glDeleteTextures(1, &mTexture);
41
42
EGLDisplay display = getEGLWindow()->getDisplay();
43
44
if (display != EGL_NO_DISPLAY)
45
{
46
for (auto &context : mContexts)
47
{
48
SafeDestroyContext(display, context);
49
}
50
}
51
52
// Set default test state to not give an error on shutdown.
53
getEGLWindow()->makeCurrent();
54
}
55
56
EGLContext mContexts[2];
57
GLuint mTexture;
58
};
59
60
// Test that calling eglDeleteContext on a context that is not current succeeds.
61
TEST_P(EGLMultiContextTest, TestContextDestroySimple)
62
{
63
EGLWindow *window = getEGLWindow();
64
EGLDisplay dpy = window->getDisplay();
65
66
EGLContext context1 = window->createContext(EGL_NO_CONTEXT);
67
EGLContext context2 = window->createContext(EGL_NO_CONTEXT);
68
69
EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, context1));
70
EXPECT_EGL_TRUE(eglDestroyContext(dpy, context2));
71
EXPECT_EGL_SUCCESS();
72
73
// Cleanup
74
EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
75
EXPECT_EGL_TRUE(eglDestroyContext(dpy, context1));
76
EXPECT_EGL_SUCCESS();
77
}
78
79
// Test that a compute shader running in one thread will still work when rendering is happening in
80
// another thread (with non-shared contexts). The non-shared context will still share a Vulkan
81
// command buffer.
82
TEST_P(EGLMultiContextTest, ComputeShaderOkayWithRendering)
83
{
84
ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
85
ANGLE_SKIP_TEST_IF(!isVulkanRenderer());
86
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 || getClientMinorVersion() < 1);
87
88
// Initialize contexts
89
EGLWindow *window = getEGLWindow();
90
EGLDisplay dpy = window->getDisplay();
91
EGLConfig config = window->getConfig();
92
93
constexpr size_t kThreadCount = 2;
94
EGLSurface surface[kThreadCount] = {EGL_NO_SURFACE, EGL_NO_SURFACE};
95
EGLContext ctx[kThreadCount] = {EGL_NO_CONTEXT, EGL_NO_CONTEXT};
96
97
EGLint pbufferAttributes[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE};
98
99
for (size_t t = 0; t < kThreadCount; ++t)
100
{
101
surface[t] = eglCreatePbufferSurface(dpy, config, pbufferAttributes);
102
EXPECT_EGL_SUCCESS();
103
104
ctx[t] = window->createContext(EGL_NO_CONTEXT);
105
EXPECT_NE(EGL_NO_CONTEXT, ctx[t]);
106
}
107
108
// Synchronization tools to ensure the two threads are interleaved as designed by this test.
109
std::mutex mutex;
110
std::condition_variable condVar;
111
112
enum class Step
113
{
114
Thread0Start,
115
Thread0DispatchedCompute,
116
Thread1Drew,
117
Thread0DispatchedComputeAgain,
118
Finish,
119
Abort,
120
};
121
Step currentStep = Step::Thread0Start;
122
123
// This first thread dispatches a compute shader. It immediately starts.
124
std::thread deletingThread = std::thread([&]() {
125
ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
126
127
EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface[0], surface[0], ctx[0]));
128
EXPECT_EGL_SUCCESS();
129
130
// Potentially wait to be signalled to start.
131
ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0Start));
132
133
// Wake up and do next step: Create, detach, and dispatch a compute shader program.
134
constexpr char kCS[] = R"(#version 310 es
135
layout(local_size_x=1) in;
136
void main()
137
{
138
})";
139
GLuint computeProgram = glCreateProgram();
140
GLuint cs = CompileShader(GL_COMPUTE_SHADER, kCS);
141
EXPECT_NE(0u, cs);
142
143
glAttachShader(computeProgram, cs);
144
glDeleteShader(cs);
145
glLinkProgram(computeProgram);
146
GLint linkStatus;
147
glGetProgramiv(computeProgram, GL_LINK_STATUS, &linkStatus);
148
EXPECT_GL_TRUE(linkStatus);
149
glDetachShader(computeProgram, cs);
150
EXPECT_GL_NO_ERROR();
151
glUseProgram(computeProgram);
152
153
glDispatchCompute(8, 4, 2);
154
EXPECT_GL_NO_ERROR();
155
156
// Signal the second thread and wait for it to draw and flush.
157
threadSynchronization.nextStep(Step::Thread0DispatchedCompute);
158
ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1Drew));
159
160
// Wake up and do next step: Dispatch the same compute shader again.
161
glDispatchCompute(8, 4, 2);
162
163
// Signal the second thread and wait for it to draw and flush again.
164
threadSynchronization.nextStep(Step::Thread0DispatchedComputeAgain);
165
ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
166
167
// Wake up and do next step: Dispatch the same compute shader again, and force flush the
168
// underlying command buffer.
169
glDispatchCompute(8, 4, 2);
170
glFinish();
171
172
// Clean-up and exit this thread.
173
EXPECT_GL_NO_ERROR();
174
EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
175
EXPECT_EGL_SUCCESS();
176
});
177
178
// This second thread renders. It starts once the other thread does its first nextStep()
179
std::thread continuingThread = std::thread([&]() {
180
ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
181
182
EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface[1], surface[1], ctx[1]));
183
EXPECT_EGL_SUCCESS();
184
185
// Wait for first thread to create and dispatch a compute shader.
186
ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0DispatchedCompute));
187
188
// Wake up and do next step: Create graphics resources, draw, and force flush the
189
// underlying command buffer.
190
GLTexture texture;
191
glBindTexture(GL_TEXTURE_2D, texture);
192
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
193
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
194
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
195
196
GLRenderbuffer renderbuffer;
197
GLFramebuffer fbo;
198
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
199
constexpr int kRenderbufferSize = 4;
200
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kRenderbufferSize, kRenderbufferSize);
201
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
202
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
203
renderbuffer);
204
glBindTexture(GL_TEXTURE_2D, texture);
205
206
GLProgram graphicsProgram;
207
graphicsProgram.makeRaster(essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
208
ASSERT_TRUE(graphicsProgram.valid());
209
210
drawQuad(graphicsProgram.get(), essl1_shaders::PositionAttrib(), 0.5f);
211
glFinish();
212
213
// Signal the first thread and wait for it to dispatch a compute shader again.
214
threadSynchronization.nextStep(Step::Thread1Drew);
215
ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0DispatchedComputeAgain));
216
217
// Wake up and do next step: Draw and force flush the underlying command buffer again.
218
drawQuad(graphicsProgram.get(), essl1_shaders::PositionAttrib(), 0.5f);
219
glFinish();
220
221
// Signal the first thread and wait exit this thread.
222
threadSynchronization.nextStep(Step::Finish);
223
224
EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
225
EXPECT_EGL_SUCCESS();
226
});
227
228
deletingThread.join();
229
continuingThread.join();
230
231
ASSERT_NE(currentStep, Step::Abort);
232
233
// Clean up
234
EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
235
for (size_t t = 0; t < kThreadCount; ++t)
236
{
237
eglDestroySurface(dpy, surface[t]);
238
eglDestroyContext(dpy, ctx[t]);
239
}
240
}
241
} // anonymous namespace
242
243
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EGLMultiContextTest);
244
ANGLE_INSTANTIATE_TEST_ES31(EGLMultiContextTest);
245
246