1 //========================================================================
2 // Multi-threading test
3 // Copyright (c) Camilla Berglund <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 #include <glad/glad.h>
34 #include <GLFW/glfw3.h>
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <math.h>
39
40 typedef struct
41 {
42 GLFWwindow* window;
43 const char* title;
44 float r, g, b;
45 thrd_t id;
46 } Thread;
47
48 static volatile int running = GLFW_TRUE;
49
error_callback(int error,const char * description)50 static void error_callback(int error, const char* description)
51 {
52 fprintf(stderr, "Error: %s\n", description);
53 }
54
thread_main(void * data)55 static int thread_main(void* data)
56 {
57 const Thread* thread = data;
58
59 glfwMakeContextCurrent(thread->window);
60 glfwSwapInterval(1);
61
62 while (running)
63 {
64 const float v = (float) fabs(sin(glfwGetTime() * 2.f));
65 glClearColor(thread->r * v, thread->g * v, thread->b * v, 0.f);
66
67 glClear(GL_COLOR_BUFFER_BIT);
68 glfwSwapBuffers(thread->window);
69 }
70
71 glfwMakeContextCurrent(NULL);
72 return 0;
73 }
74
main(void)75 int main(void)
76 {
77 int i, result;
78 Thread threads[] =
79 {
80 { NULL, "Red", 1.f, 0.f, 0.f, 0 },
81 { NULL, "Green", 0.f, 1.f, 0.f, 0 },
82 { NULL, "Blue", 0.f, 0.f, 1.f, 0 }
83 };
84 const int count = sizeof(threads) / sizeof(Thread);
85
86 glfwSetErrorCallback(error_callback);
87
88 if (!glfwInit())
89 exit(EXIT_FAILURE);
90
91 glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
92
93 for (i = 0; i < count; i++)
94 {
95 threads[i].window = glfwCreateWindow(200, 200,
96 threads[i].title,
97 NULL, NULL);
98 if (!threads[i].window)
99 {
100 glfwTerminate();
101 exit(EXIT_FAILURE);
102 }
103
104 glfwSetWindowPos(threads[i].window, 200 + 250 * i, 200);
105 glfwShowWindow(threads[i].window);
106 }
107
108 glfwMakeContextCurrent(threads[0].window);
109 gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
110 glfwMakeContextCurrent(NULL);
111
112 for (i = 0; i < count; i++)
113 {
114 if (thrd_create(&threads[i].id, thread_main, threads + i) !=
115 thrd_success)
116 {
117 fprintf(stderr, "Failed to create secondary thread\n");
118
119 glfwTerminate();
120 exit(EXIT_FAILURE);
121 }
122 }
123
124 while (running)
125 {
126 glfwWaitEvents();
127
128 for (i = 0; i < count; i++)
129 {
130 if (glfwWindowShouldClose(threads[i].window))
131 running = GLFW_FALSE;
132 }
133 }
134
135 for (i = 0; i < count; i++)
136 glfwHideWindow(threads[i].window);
137
138 for (i = 0; i < count; i++)
139 thrd_join(threads[i].id, &result);
140
141 exit(EXIT_SUCCESS);
142 }
143
144