1 //========================================================================
2 // Multi-threading test
3 // Copyright (c) Camilla Löwy <elmindreda@glfw.org>
4 //
5 // This software is provided 'as-is', without any express or implied
6 // warranty. In no event will the authors be held liable for any damages
7 // arising from the use of this software.
8 //
9 // Permission is granted to anyone to use this software for any purpose,
10 // including commercial applications, and to alter it and redistribute it
11 // freely, subject to the following restrictions:
12 //
13 // 1. The origin of this software must not be misrepresented; you must not
14 // claim that you wrote the original software. If you use this software
15 // in a product, an acknowledgment in the product documentation would
16 // be appreciated but is not required.
17 //
18 // 2. Altered source versions must be plainly marked as such, and must not
19 // be misrepresented as being the original software.
20 //
21 // 3. This notice may not be removed or altered from any source
22 // distribution.
23 //
24 //========================================================================
25 //
26 // This test is intended to verify whether the OpenGL context part of
27 // the GLFW API is able to be used from multiple threads
28 //
29 //========================================================================
30
31 #include "tinycthread.h"
32
33 #define GLAD_GL_IMPLEMENTATION
34 #include <glad/gl.h>
35 #define GLFW_INCLUDE_NONE
36 #include <GLFW/glfw3.h>
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <math.h>
41
42 typedef struct
43 {
44 GLFWwindow* window;
45 const char* title;
46 float r, g, b;
47 thrd_t id;
48 } Thread;
49
50 static volatile int running = GLFW_TRUE;
51
error_callback(int error, const char* description)52 static void error_callback(int error, const char* description)
53 {
54 fprintf(stderr, "Error: %s\n", description);
55 }
56
key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)57 static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
58 {
59 if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
60 glfwSetWindowShouldClose(window, GLFW_TRUE);
61 }
62
thread_main(void* data)63 static int thread_main(void* data)
64 {
65 const Thread* thread = data;
66
67 glfwMakeContextCurrent(thread->window);
68 glfwSwapInterval(1);
69
70 while (running)
71 {
72 const float v = (float) fabs(sin(glfwGetTime() * 2.f));
73 glClearColor(thread->r * v, thread->g * v, thread->b * v, 0.f);
74
75 glClear(GL_COLOR_BUFFER_BIT);
76 glfwSwapBuffers(thread->window);
77 }
78
79 glfwMakeContextCurrent(NULL);
80 return 0;
81 }
82
main(void)83 int main(void)
84 {
85 int i, result;
86 Thread threads[] =
87 {
88 { NULL, "Red", 1.f, 0.f, 0.f, 0 },
89 { NULL, "Green", 0.f, 1.f, 0.f, 0 },
90 { NULL, "Blue", 0.f, 0.f, 1.f, 0 }
91 };
92 const int count = sizeof(threads) / sizeof(Thread);
93
94 glfwSetErrorCallback(error_callback);
95
96 if (!glfwInit())
97 exit(EXIT_FAILURE);
98
99 for (i = 0; i < count; i++)
100 {
101 glfwWindowHint(GLFW_POSITION_X, 200 + 250 * i);
102 glfwWindowHint(GLFW_POSITION_Y, 200);
103
104 threads[i].window = glfwCreateWindow(200, 200,
105 threads[i].title,
106 NULL, NULL);
107 if (!threads[i].window)
108 {
109 glfwTerminate();
110 exit(EXIT_FAILURE);
111 }
112
113 glfwSetKeyCallback(threads[i].window, key_callback);
114 }
115
116 glfwMakeContextCurrent(threads[0].window);
117 gladLoadGL(glfwGetProcAddress);
118 glfwMakeContextCurrent(NULL);
119
120 for (i = 0; i < count; i++)
121 {
122 if (thrd_create(&threads[i].id, thread_main, threads + i) !=
123 thrd_success)
124 {
125 fprintf(stderr, "Failed to create secondary thread\n");
126
127 glfwTerminate();
128 exit(EXIT_FAILURE);
129 }
130 }
131
132 while (running)
133 {
134 glfwWaitEvents();
135
136 for (i = 0; i < count; i++)
137 {
138 if (glfwWindowShouldClose(threads[i].window))
139 running = GLFW_FALSE;
140 }
141 }
142
143 for (i = 0; i < count; i++)
144 glfwHideWindow(threads[i].window);
145
146 for (i = 0; i < count; i++)
147 thrd_join(threads[i].id, &result);
148
149 exit(EXIT_SUCCESS);
150 }
151
152