1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2021 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 // Demonstrates GLES usage with two contexts, one uploading texture data.
7*8975f5c5SAndroid Build Coastguard Worker
8*8975f5c5SAndroid Build Coastguard Worker #include "SampleApplication.h"
9*8975f5c5SAndroid Build Coastguard Worker #include "util/random_utils.h"
10*8975f5c5SAndroid Build Coastguard Worker #include "util/shader_utils.h"
11*8975f5c5SAndroid Build Coastguard Worker #include "util/test_utils.h"
12*8975f5c5SAndroid Build Coastguard Worker
13*8975f5c5SAndroid Build Coastguard Worker #include <array>
14*8975f5c5SAndroid Build Coastguard Worker #include <mutex>
15*8975f5c5SAndroid Build Coastguard Worker #include <queue>
16*8975f5c5SAndroid Build Coastguard Worker #include <thread>
17*8975f5c5SAndroid Build Coastguard Worker
18*8975f5c5SAndroid Build Coastguard Worker struct TextureAndFence
19*8975f5c5SAndroid Build Coastguard Worker {
20*8975f5c5SAndroid Build Coastguard Worker GLuint textureID;
21*8975f5c5SAndroid Build Coastguard Worker GLsync fenceSync;
22*8975f5c5SAndroid Build Coastguard Worker };
23*8975f5c5SAndroid Build Coastguard Worker
24*8975f5c5SAndroid Build Coastguard Worker constexpr GLuint64 kTimeout = 10000000;
25*8975f5c5SAndroid Build Coastguard Worker static constexpr GLint kTextureSize = 2;
26*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kWindowWidth = 400;
27*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kWindowHeight = 300;
28*8975f5c5SAndroid Build Coastguard Worker
UpdateThreadLoop(EGLDisplay display,EGLConfig config,EGLContext shareContext,std::mutex * updateThreadMutex,std::queue<TextureAndFence> * updateThreadQueue,std::mutex * mainThreadMutex,std::queue<TextureAndFence> * mainThreadQueue)29*8975f5c5SAndroid Build Coastguard Worker void UpdateThreadLoop(EGLDisplay display,
30*8975f5c5SAndroid Build Coastguard Worker EGLConfig config,
31*8975f5c5SAndroid Build Coastguard Worker EGLContext shareContext,
32*8975f5c5SAndroid Build Coastguard Worker std::mutex *updateThreadMutex,
33*8975f5c5SAndroid Build Coastguard Worker std::queue<TextureAndFence> *updateThreadQueue,
34*8975f5c5SAndroid Build Coastguard Worker std::mutex *mainThreadMutex,
35*8975f5c5SAndroid Build Coastguard Worker std::queue<TextureAndFence> *mainThreadQueue)
36*8975f5c5SAndroid Build Coastguard Worker {
37*8975f5c5SAndroid Build Coastguard Worker angle::RNG rng;
38*8975f5c5SAndroid Build Coastguard Worker
39*8975f5c5SAndroid Build Coastguard Worker EGLint contextAttribs[] = {EGL_CONTEXT_MAJOR_VERSION, 3, EGL_NONE};
40*8975f5c5SAndroid Build Coastguard Worker EGLContext context = eglCreateContext(display, config, shareContext, contextAttribs);
41*8975f5c5SAndroid Build Coastguard Worker
42*8975f5c5SAndroid Build Coastguard Worker EGLint surfaceAttribs[] = {EGL_NONE};
43*8975f5c5SAndroid Build Coastguard Worker EGLSurface surface = eglCreatePbufferSurface(display, config, surfaceAttribs);
44*8975f5c5SAndroid Build Coastguard Worker
45*8975f5c5SAndroid Build Coastguard Worker eglMakeCurrent(display, surface, surface, context);
46*8975f5c5SAndroid Build Coastguard Worker
47*8975f5c5SAndroid Build Coastguard Worker for (;;)
48*8975f5c5SAndroid Build Coastguard Worker {
49*8975f5c5SAndroid Build Coastguard Worker bool hasUpdate = false;
50*8975f5c5SAndroid Build Coastguard Worker TextureAndFence textureAndFence;
51*8975f5c5SAndroid Build Coastguard Worker
52*8975f5c5SAndroid Build Coastguard Worker {
53*8975f5c5SAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(*updateThreadMutex);
54*8975f5c5SAndroid Build Coastguard Worker if (!updateThreadQueue->empty())
55*8975f5c5SAndroid Build Coastguard Worker {
56*8975f5c5SAndroid Build Coastguard Worker textureAndFence = updateThreadQueue->back();
57*8975f5c5SAndroid Build Coastguard Worker hasUpdate = true;
58*8975f5c5SAndroid Build Coastguard Worker updateThreadQueue->pop();
59*8975f5c5SAndroid Build Coastguard Worker }
60*8975f5c5SAndroid Build Coastguard Worker }
61*8975f5c5SAndroid Build Coastguard Worker
62*8975f5c5SAndroid Build Coastguard Worker if (hasUpdate)
63*8975f5c5SAndroid Build Coastguard Worker {
64*8975f5c5SAndroid Build Coastguard Worker if (textureAndFence.textureID == 0)
65*8975f5c5SAndroid Build Coastguard Worker {
66*8975f5c5SAndroid Build Coastguard Worker // Signal from the main thread to stop execution.
67*8975f5c5SAndroid Build Coastguard Worker break;
68*8975f5c5SAndroid Build Coastguard Worker }
69*8975f5c5SAndroid Build Coastguard Worker
70*8975f5c5SAndroid Build Coastguard Worker glClientWaitSync(textureAndFence.fenceSync, 0, kTimeout);
71*8975f5c5SAndroid Build Coastguard Worker glDeleteSync(textureAndFence.fenceSync);
72*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, textureAndFence.textureID);
73*8975f5c5SAndroid Build Coastguard Worker
74*8975f5c5SAndroid Build Coastguard Worker std::vector<uint8_t> bytes(3, 0);
75*8975f5c5SAndroid Build Coastguard Worker FillVectorWithRandomUBytes(&rng, &bytes);
76*8975f5c5SAndroid Build Coastguard Worker bytes.push_back(255);
77*8975f5c5SAndroid Build Coastguard Worker
78*8975f5c5SAndroid Build Coastguard Worker std::vector<uint8_t> textureData;
79*8975f5c5SAndroid Build Coastguard Worker for (GLint x = 0; x < kTextureSize; ++x)
80*8975f5c5SAndroid Build Coastguard Worker {
81*8975f5c5SAndroid Build Coastguard Worker for (GLint y = 0; y < kTextureSize; ++y)
82*8975f5c5SAndroid Build Coastguard Worker {
83*8975f5c5SAndroid Build Coastguard Worker textureData.insert(textureData.end(), bytes.begin(), bytes.end());
84*8975f5c5SAndroid Build Coastguard Worker }
85*8975f5c5SAndroid Build Coastguard Worker }
86*8975f5c5SAndroid Build Coastguard Worker
87*8975f5c5SAndroid Build Coastguard Worker glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextureSize, kTextureSize, GL_RGBA,
88*8975f5c5SAndroid Build Coastguard Worker GL_UNSIGNED_BYTE, textureData.data());
89*8975f5c5SAndroid Build Coastguard Worker
90*8975f5c5SAndroid Build Coastguard Worker GLsync mainThreadSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
91*8975f5c5SAndroid Build Coastguard Worker
92*8975f5c5SAndroid Build Coastguard Worker {
93*8975f5c5SAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(*mainThreadMutex);
94*8975f5c5SAndroid Build Coastguard Worker mainThreadQueue->push({textureAndFence.textureID, mainThreadSync});
95*8975f5c5SAndroid Build Coastguard Worker }
96*8975f5c5SAndroid Build Coastguard Worker }
97*8975f5c5SAndroid Build Coastguard Worker
98*8975f5c5SAndroid Build Coastguard Worker angle::Sleep(200);
99*8975f5c5SAndroid Build Coastguard Worker }
100*8975f5c5SAndroid Build Coastguard Worker
101*8975f5c5SAndroid Build Coastguard Worker eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
102*8975f5c5SAndroid Build Coastguard Worker eglDestroySurface(display, surface);
103*8975f5c5SAndroid Build Coastguard Worker eglDestroyContext(display, context);
104*8975f5c5SAndroid Build Coastguard Worker }
105*8975f5c5SAndroid Build Coastguard Worker
106*8975f5c5SAndroid Build Coastguard Worker class MultipleContextsSample : public SampleApplication
107*8975f5c5SAndroid Build Coastguard Worker {
108*8975f5c5SAndroid Build Coastguard Worker public:
MultipleContextsSample(int argc,char ** argv)109*8975f5c5SAndroid Build Coastguard Worker MultipleContextsSample(int argc, char **argv)
110*8975f5c5SAndroid Build Coastguard Worker : SampleApplication("MultipleContexts",
111*8975f5c5SAndroid Build Coastguard Worker argc,
112*8975f5c5SAndroid Build Coastguard Worker argv,
113*8975f5c5SAndroid Build Coastguard Worker ClientType::ES3_0,
114*8975f5c5SAndroid Build Coastguard Worker kWindowWidth,
115*8975f5c5SAndroid Build Coastguard Worker kWindowHeight)
116*8975f5c5SAndroid Build Coastguard Worker {}
117*8975f5c5SAndroid Build Coastguard Worker
initialize()118*8975f5c5SAndroid Build Coastguard Worker bool initialize() override
119*8975f5c5SAndroid Build Coastguard Worker {
120*8975f5c5SAndroid Build Coastguard Worker // Initialize some textures and send them to the update thread.
121*8975f5c5SAndroid Build Coastguard Worker glGenTextures(kNumTextures, mTextures.data());
122*8975f5c5SAndroid Build Coastguard Worker
123*8975f5c5SAndroid Build Coastguard Worker for (GLuint texture : mTextures)
124*8975f5c5SAndroid Build Coastguard Worker {
125*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, texture);
126*8975f5c5SAndroid Build Coastguard Worker glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureSize, kTextureSize, 0, GL_RGBA,
127*8975f5c5SAndroid Build Coastguard Worker GL_UNSIGNED_BYTE, nullptr);
128*8975f5c5SAndroid Build Coastguard Worker glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
129*8975f5c5SAndroid Build Coastguard Worker glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
130*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, 0);
131*8975f5c5SAndroid Build Coastguard Worker GLsync fenceSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
132*8975f5c5SAndroid Build Coastguard Worker
133*8975f5c5SAndroid Build Coastguard Worker mUpdateThreadQueue.push({texture, fenceSync});
134*8975f5c5SAndroid Build Coastguard Worker }
135*8975f5c5SAndroid Build Coastguard Worker
136*8975f5c5SAndroid Build Coastguard Worker mUpdateThread.reset(new std::thread(UpdateThreadLoop, getDisplay(), getConfig(),
137*8975f5c5SAndroid Build Coastguard Worker getContext(), &mUpdateThreadMutex, &mUpdateThreadQueue,
138*8975f5c5SAndroid Build Coastguard Worker &mMainThreadMutex, &mMainThreadQueue));
139*8975f5c5SAndroid Build Coastguard Worker
140*8975f5c5SAndroid Build Coastguard Worker mProgram = CompileProgram(angle::essl1_shaders::vs::Texture2D(),
141*8975f5c5SAndroid Build Coastguard Worker angle::essl1_shaders::fs::Texture2D());
142*8975f5c5SAndroid Build Coastguard Worker glUseProgram(mProgram);
143*8975f5c5SAndroid Build Coastguard Worker glEnableVertexAttribArray(0);
144*8975f5c5SAndroid Build Coastguard Worker
145*8975f5c5SAndroid Build Coastguard Worker glGenBuffers(1, &mVertexBuffer);
146*8975f5c5SAndroid Build Coastguard Worker glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
147*8975f5c5SAndroid Build Coastguard Worker glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 2 * 6, nullptr, GL_DYNAMIC_DRAW);
148*8975f5c5SAndroid Build Coastguard Worker
149*8975f5c5SAndroid Build Coastguard Worker glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
150*8975f5c5SAndroid Build Coastguard Worker
151*8975f5c5SAndroid Build Coastguard Worker return true;
152*8975f5c5SAndroid Build Coastguard Worker }
153*8975f5c5SAndroid Build Coastguard Worker
destroy()154*8975f5c5SAndroid Build Coastguard Worker void destroy() override
155*8975f5c5SAndroid Build Coastguard Worker {
156*8975f5c5SAndroid Build Coastguard Worker {
157*8975f5c5SAndroid Build Coastguard Worker // Signal the worker thread to stop execution.
158*8975f5c5SAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(mUpdateThreadMutex);
159*8975f5c5SAndroid Build Coastguard Worker mUpdateThreadQueue.push({0, 0});
160*8975f5c5SAndroid Build Coastguard Worker }
161*8975f5c5SAndroid Build Coastguard Worker
162*8975f5c5SAndroid Build Coastguard Worker for (;;)
163*8975f5c5SAndroid Build Coastguard Worker {
164*8975f5c5SAndroid Build Coastguard Worker {
165*8975f5c5SAndroid Build Coastguard Worker std::lock_guard<std::mutex> mainLock(mMainThreadMutex);
166*8975f5c5SAndroid Build Coastguard Worker if (mMainThreadQueue.empty())
167*8975f5c5SAndroid Build Coastguard Worker {
168*8975f5c5SAndroid Build Coastguard Worker std::lock_guard<std::mutex> updateLock(mUpdateThreadMutex);
169*8975f5c5SAndroid Build Coastguard Worker if (mUpdateThreadQueue.empty())
170*8975f5c5SAndroid Build Coastguard Worker {
171*8975f5c5SAndroid Build Coastguard Worker break;
172*8975f5c5SAndroid Build Coastguard Worker }
173*8975f5c5SAndroid Build Coastguard Worker }
174*8975f5c5SAndroid Build Coastguard Worker else
175*8975f5c5SAndroid Build Coastguard Worker {
176*8975f5c5SAndroid Build Coastguard Worker TextureAndFence textureAndFence = mMainThreadQueue.back();
177*8975f5c5SAndroid Build Coastguard Worker mMainThreadQueue.pop();
178*8975f5c5SAndroid Build Coastguard Worker glClientWaitSync(textureAndFence.fenceSync, 0, kTimeout);
179*8975f5c5SAndroid Build Coastguard Worker glDeleteSync(textureAndFence.fenceSync);
180*8975f5c5SAndroid Build Coastguard Worker }
181*8975f5c5SAndroid Build Coastguard Worker }
182*8975f5c5SAndroid Build Coastguard Worker }
183*8975f5c5SAndroid Build Coastguard Worker
184*8975f5c5SAndroid Build Coastguard Worker glDeleteTextures(kNumTextures, mTextures.data());
185*8975f5c5SAndroid Build Coastguard Worker glDeleteProgram(mProgram);
186*8975f5c5SAndroid Build Coastguard Worker glDeleteBuffers(1, &mVertexBuffer);
187*8975f5c5SAndroid Build Coastguard Worker }
188*8975f5c5SAndroid Build Coastguard Worker
draw()189*8975f5c5SAndroid Build Coastguard Worker void draw() override
190*8975f5c5SAndroid Build Coastguard Worker {
191*8975f5c5SAndroid Build Coastguard Worker bool hasUpdate = false;
192*8975f5c5SAndroid Build Coastguard Worker TextureAndFence textureAndFence;
193*8975f5c5SAndroid Build Coastguard Worker while (!hasUpdate)
194*8975f5c5SAndroid Build Coastguard Worker {
195*8975f5c5SAndroid Build Coastguard Worker {
196*8975f5c5SAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(mMainThreadMutex);
197*8975f5c5SAndroid Build Coastguard Worker if (!mMainThreadQueue.empty())
198*8975f5c5SAndroid Build Coastguard Worker {
199*8975f5c5SAndroid Build Coastguard Worker hasUpdate = true;
200*8975f5c5SAndroid Build Coastguard Worker textureAndFence = mMainThreadQueue.back();
201*8975f5c5SAndroid Build Coastguard Worker mMainThreadQueue.pop();
202*8975f5c5SAndroid Build Coastguard Worker }
203*8975f5c5SAndroid Build Coastguard Worker }
204*8975f5c5SAndroid Build Coastguard Worker }
205*8975f5c5SAndroid Build Coastguard Worker
206*8975f5c5SAndroid Build Coastguard Worker glClientWaitSync(textureAndFence.fenceSync, 0, kTimeout);
207*8975f5c5SAndroid Build Coastguard Worker glDeleteSync(textureAndFence.fenceSync);
208*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, textureAndFence.textureID);
209*8975f5c5SAndroid Build Coastguard Worker
210*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kNumRows = 3;
211*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kNumCols = 4;
212*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kTileHeight = kWindowHeight / kNumRows;
213*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kTileWidth = kWindowWidth / kNumCols;
214*8975f5c5SAndroid Build Coastguard Worker
215*8975f5c5SAndroid Build Coastguard Worker size_t tileX = mDrawCount % kNumCols;
216*8975f5c5SAndroid Build Coastguard Worker size_t tileY = (mDrawCount / kNumCols) % kNumRows;
217*8975f5c5SAndroid Build Coastguard Worker
218*8975f5c5SAndroid Build Coastguard Worker mDrawCount++;
219*8975f5c5SAndroid Build Coastguard Worker
220*8975f5c5SAndroid Build Coastguard Worker GLfloat tileX0 = static_cast<float>(tileX) / static_cast<float>(kNumCols);
221*8975f5c5SAndroid Build Coastguard Worker GLfloat tileY0 = static_cast<float>(tileY) / static_cast<float>(kNumRows);
222*8975f5c5SAndroid Build Coastguard Worker GLfloat tileX1 = tileX0 + static_cast<float>(kTileWidth) / static_cast<float>(kWindowWidth);
223*8975f5c5SAndroid Build Coastguard Worker GLfloat tileY1 =
224*8975f5c5SAndroid Build Coastguard Worker tileY0 + static_cast<float>(kTileHeight) / static_cast<float>(kWindowHeight);
225*8975f5c5SAndroid Build Coastguard Worker
226*8975f5c5SAndroid Build Coastguard Worker tileX0 = tileX0 * 2.0f - 1.0f;
227*8975f5c5SAndroid Build Coastguard Worker tileX1 = tileX1 * 2.0f - 1.0f;
228*8975f5c5SAndroid Build Coastguard Worker tileY0 = tileY0 * 2.0f - 1.0f;
229*8975f5c5SAndroid Build Coastguard Worker tileY1 = tileY1 * 2.0f - 1.0f;
230*8975f5c5SAndroid Build Coastguard Worker
231*8975f5c5SAndroid Build Coastguard Worker std::vector<GLfloat> vertices = {tileX0, tileY0, tileX0, tileY1, tileX1, tileY0,
232*8975f5c5SAndroid Build Coastguard Worker tileX1, tileY0, tileX1, tileY1, tileX0, tileY1};
233*8975f5c5SAndroid Build Coastguard Worker
234*8975f5c5SAndroid Build Coastguard Worker glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices[0]) * vertices.size(), vertices.data());
235*8975f5c5SAndroid Build Coastguard Worker
236*8975f5c5SAndroid Build Coastguard Worker glClear(GL_COLOR_BUFFER_BIT);
237*8975f5c5SAndroid Build Coastguard Worker glDrawArrays(GL_TRIANGLES, 0, 6);
238*8975f5c5SAndroid Build Coastguard Worker
239*8975f5c5SAndroid Build Coastguard Worker GLsync drawSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
240*8975f5c5SAndroid Build Coastguard Worker {
241*8975f5c5SAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(mUpdateThreadMutex);
242*8975f5c5SAndroid Build Coastguard Worker mUpdateThreadQueue.push({textureAndFence.textureID, drawSync});
243*8975f5c5SAndroid Build Coastguard Worker }
244*8975f5c5SAndroid Build Coastguard Worker }
245*8975f5c5SAndroid Build Coastguard Worker
246*8975f5c5SAndroid Build Coastguard Worker private:
247*8975f5c5SAndroid Build Coastguard Worker std::unique_ptr<std::thread> mUpdateThread;
248*8975f5c5SAndroid Build Coastguard Worker
249*8975f5c5SAndroid Build Coastguard Worker static constexpr GLuint kNumTextures = 4;
250*8975f5c5SAndroid Build Coastguard Worker std::array<GLuint, kNumTextures> mTextures;
251*8975f5c5SAndroid Build Coastguard Worker
252*8975f5c5SAndroid Build Coastguard Worker GLuint mProgram = 0;
253*8975f5c5SAndroid Build Coastguard Worker GLuint mVertexBuffer = 0;
254*8975f5c5SAndroid Build Coastguard Worker
255*8975f5c5SAndroid Build Coastguard Worker std::mutex mUpdateThreadMutex;
256*8975f5c5SAndroid Build Coastguard Worker std::queue<TextureAndFence> mUpdateThreadQueue;
257*8975f5c5SAndroid Build Coastguard Worker std::mutex mMainThreadMutex;
258*8975f5c5SAndroid Build Coastguard Worker std::queue<TextureAndFence> mMainThreadQueue;
259*8975f5c5SAndroid Build Coastguard Worker size_t mDrawCount = 0;
260*8975f5c5SAndroid Build Coastguard Worker };
261*8975f5c5SAndroid Build Coastguard Worker
main(int argc,char ** argv)262*8975f5c5SAndroid Build Coastguard Worker int main(int argc, char **argv)
263*8975f5c5SAndroid Build Coastguard Worker {
264*8975f5c5SAndroid Build Coastguard Worker MultipleContextsSample app(argc, argv);
265*8975f5c5SAndroid Build Coastguard Worker return app.run();
266*8975f5c5SAndroid Build Coastguard Worker }
267