summaryrefslogtreecommitdiff
path: root/src/contrib/SDL-3.2.20/test/testgles2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/contrib/SDL-3.2.20/test/testgles2.c')
-rw-r--r--src/contrib/SDL-3.2.20/test/testgles2.c956
1 files changed, 956 insertions, 0 deletions
diff --git a/src/contrib/SDL-3.2.20/test/testgles2.c b/src/contrib/SDL-3.2.20/test/testgles2.c
new file mode 100644
index 0000000..1184eab
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/test/testgles2.c
@@ -0,0 +1,956 @@
1/*
2 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely.
11*/
12
13#include <SDL3/SDL_test_common.h>
14#include <SDL3/SDL_main.h>
15
16#ifdef SDL_PLATFORM_EMSCRIPTEN
17#include <emscripten/emscripten.h>
18#endif
19
20#include <stdlib.h>
21
22#if defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_ANDROID) || defined(SDL_PLATFORM_EMSCRIPTEN) || defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_LINUX)
23#define HAVE_OPENGLES2
24#endif
25
26#ifdef HAVE_OPENGLES2
27
28#include <SDL3/SDL_opengles2.h>
29
30typedef struct GLES2_Context
31{
32#define SDL_PROC(ret, func, params) ret (APIENTRY *func) params;
33#include "../src/render/opengles2/SDL_gles2funcs.h"
34#undef SDL_PROC
35} GLES2_Context;
36
37typedef struct shader_data
38{
39 GLuint shader_program, shader_frag, shader_vert;
40
41 GLint attr_position;
42 GLint attr_color, attr_mvp;
43
44 int angle_x, angle_y, angle_z;
45
46 GLuint position_buffer;
47 GLuint color_buffer;
48} shader_data;
49
50typedef enum wait_state
51{
52 WAIT_STATE_GO = 0,
53 WAIT_STATE_ENTER_SEM,
54 WAIT_STATE_WAITING_ON_SEM,
55} wait_state;
56
57typedef struct thread_data
58{
59 SDL_Thread *thread;
60 SDL_Semaphore *suspend_sem;
61 SDL_AtomicInt suspended;
62 int done;
63 int index;
64} thread_data;
65
66static SDLTest_CommonState *state;
67static SDL_GLContext *context = NULL;
68static int depth = 16;
69static bool suspend_when_occluded;
70static GLES2_Context ctx;
71static shader_data *datas;
72
73static bool LoadContext(GLES2_Context *data)
74{
75#ifdef SDL_VIDEO_DRIVER_UIKIT
76#define __SDL_NOGETPROCADDR__
77#elif defined(SDL_VIDEO_DRIVER_ANDROID)
78#define __SDL_NOGETPROCADDR__
79#endif
80
81#if defined __SDL_NOGETPROCADDR__
82#define SDL_PROC(ret, func, params) data->func = func;
83#else
84#define SDL_PROC(ret, func, params) \
85 do { \
86 data->func = (ret (APIENTRY *) params)SDL_GL_GetProcAddress(#func); \
87 if (!data->func) { \
88 return SDL_SetError("Couldn't load GLES2 function %s: %s", #func, SDL_GetError()); \
89 } \
90 } while (0);
91#endif /* __SDL_NOGETPROCADDR__ */
92
93#include "../src/render/opengles2/SDL_gles2funcs.h"
94#undef SDL_PROC
95 return true;
96}
97
98/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
99static void
100quit(int rc)
101{
102 int i;
103
104 SDL_free(datas);
105 if (context) {
106 for (i = 0; i < state->num_windows; i++) {
107 if (context[i]) {
108 SDL_GL_DestroyContext(context[i]);
109 }
110 }
111
112 SDL_free(context);
113 }
114
115 SDLTest_CommonQuit(state);
116 /* Let 'main()' return normally */
117 if (rc != 0) {
118 exit(rc);
119 }
120}
121
122#define GL_CHECK(x) \
123 x; \
124 { \
125 GLenum glError = ctx.glGetError(); \
126 if (glError != GL_NO_ERROR) { \
127 SDL_Log("glGetError() = %i (0x%.8x) at line %i", glError, glError, __LINE__); \
128 quit(1); \
129 } \
130 }
131
132/**
133 * Simulates desktop's glRotatef. The matrix is returned in column-major
134 * order.
135 */
136static void
137rotate_matrix(float angle, float x, float y, float z, float *r)
138{
139 float radians, c, s, c1, u[3], length;
140 int i, j;
141
142 radians = (angle * SDL_PI_F) / 180.0f;
143
144 c = SDL_cosf(radians);
145 s = SDL_sinf(radians);
146
147 c1 = 1.0f - SDL_cosf(radians);
148
149 length = (float)SDL_sqrt(x * x + y * y + z * z);
150
151 u[0] = x / length;
152 u[1] = y / length;
153 u[2] = z / length;
154
155 for (i = 0; i < 16; i++) {
156 r[i] = 0.0;
157 }
158
159 r[15] = 1.0;
160
161 for (i = 0; i < 3; i++) {
162 r[i * 4 + (i + 1) % 3] = u[(i + 2) % 3] * s;
163 r[i * 4 + (i + 2) % 3] = -u[(i + 1) % 3] * s;
164 }
165
166 for (i = 0; i < 3; i++) {
167 for (j = 0; j < 3; j++) {
168 r[i * 4 + j] += c1 * u[i] * u[j] + (i == j ? c : 0.0f);
169 }
170 }
171}
172
173/**
174 * Simulates gluPerspectiveMatrix
175 */
176static void
177perspective_matrix(float fovy, float aspect, float znear, float zfar, float *r)
178{
179 int i;
180 float f;
181
182 f = 1.0f / SDL_tanf(fovy * 0.5f);
183
184 for (i = 0; i < 16; i++) {
185 r[i] = 0.0;
186 }
187
188 r[0] = f / aspect;
189 r[5] = f;
190 r[10] = (znear + zfar) / (znear - zfar);
191 r[11] = -1.0f;
192 r[14] = (2.0f * znear * zfar) / (znear - zfar);
193 r[15] = 0.0f;
194}
195
196/**
197 * Multiplies lhs by rhs and writes out to r. All matrices are 4x4 and column
198 * major. In-place multiplication is supported.
199 */
200static void
201multiply_matrix(const float *lhs, const float *rhs, float *r)
202{
203 int i, j, k;
204 float tmp[16];
205
206 for (i = 0; i < 4; i++) {
207 for (j = 0; j < 4; j++) {
208 tmp[j * 4 + i] = 0.0;
209
210 for (k = 0; k < 4; k++) {
211 tmp[j * 4 + i] += lhs[k * 4 + i] * rhs[j * 4 + k];
212 }
213 }
214 }
215
216 for (i = 0; i < 16; i++) {
217 r[i] = tmp[i];
218 }
219}
220
221/**
222 * Create shader, load in source, compile, dump debug as necessary.
223 *
224 * shader: Pointer to return created shader ID.
225 * source: Passed-in shader source code.
226 * shader_type: Passed to GL, e.g. GL_VERTEX_SHADER.
227 */
228static void
229process_shader(GLuint *shader, const char *source, GLint shader_type)
230{
231 GLint status = GL_FALSE;
232 const char *shaders[1] = { NULL };
233 char buffer[1024];
234 GLsizei length = 0;
235
236 /* Create shader and load into GL. */
237 *shader = GL_CHECK(ctx.glCreateShader(shader_type));
238
239 shaders[0] = source;
240
241 GL_CHECK(ctx.glShaderSource(*shader, 1, shaders, NULL));
242
243 /* Clean up shader source. */
244 shaders[0] = NULL;
245
246 /* Try compiling the shader. */
247 GL_CHECK(ctx.glCompileShader(*shader));
248 GL_CHECK(ctx.glGetShaderiv(*shader, GL_COMPILE_STATUS, &status));
249
250 /* Dump debug info (source and log) if compilation failed. */
251 if (status != GL_TRUE) {
252 ctx.glGetShaderInfoLog(*shader, sizeof(buffer), &length, &buffer[0]);
253 buffer[length] = '\0';
254 SDL_Log("Shader compilation failed: %s", buffer);
255 quit(-1);
256 }
257}
258
259static void
260link_program(struct shader_data *data)
261{
262 GLint status = GL_FALSE;
263 char buffer[1024];
264 GLsizei length = 0;
265
266 GL_CHECK(ctx.glAttachShader(data->shader_program, data->shader_vert));
267 GL_CHECK(ctx.glAttachShader(data->shader_program, data->shader_frag));
268 GL_CHECK(ctx.glLinkProgram(data->shader_program));
269 GL_CHECK(ctx.glGetProgramiv(data->shader_program, GL_LINK_STATUS, &status));
270
271 if (status != GL_TRUE) {
272 ctx.glGetProgramInfoLog(data->shader_program, sizeof(buffer), &length, &buffer[0]);
273 buffer[length] = '\0';
274 SDL_Log("Program linking failed: %s", buffer);
275 quit(-1);
276 }
277}
278
279/* 3D data. Vertex range -0.5..0.5 in all axes.
280 * Z -0.5 is near, 0.5 is far. */
281static const float g_vertices[] = {
282 /* Front face. */
283 /* Bottom left */
284 -0.5,
285 0.5,
286 -0.5,
287 0.5,
288 -0.5,
289 -0.5,
290 -0.5,
291 -0.5,
292 -0.5,
293 /* Top right */
294 -0.5,
295 0.5,
296 -0.5,
297 0.5,
298 0.5,
299 -0.5,
300 0.5,
301 -0.5,
302 -0.5,
303 /* Left face */
304 /* Bottom left */
305 -0.5,
306 0.5,
307 0.5,
308 -0.5,
309 -0.5,
310 -0.5,
311 -0.5,
312 -0.5,
313 0.5,
314 /* Top right */
315 -0.5,
316 0.5,
317 0.5,
318 -0.5,
319 0.5,
320 -0.5,
321 -0.5,
322 -0.5,
323 -0.5,
324 /* Top face */
325 /* Bottom left */
326 -0.5,
327 0.5,
328 0.5,
329 0.5,
330 0.5,
331 -0.5,
332 -0.5,
333 0.5,
334 -0.5,
335 /* Top right */
336 -0.5,
337 0.5,
338 0.5,
339 0.5,
340 0.5,
341 0.5,
342 0.5,
343 0.5,
344 -0.5,
345 /* Right face */
346 /* Bottom left */
347 0.5,
348 0.5,
349 -0.5,
350 0.5,
351 -0.5,
352 0.5,
353 0.5,
354 -0.5,
355 -0.5,
356 /* Top right */
357 0.5,
358 0.5,
359 -0.5,
360 0.5,
361 0.5,
362 0.5,
363 0.5,
364 -0.5,
365 0.5,
366 /* Back face */
367 /* Bottom left */
368 0.5,
369 0.5,
370 0.5,
371 -0.5,
372 -0.5,
373 0.5,
374 0.5,
375 -0.5,
376 0.5,
377 /* Top right */
378 0.5,
379 0.5,
380 0.5,
381 -0.5,
382 0.5,
383 0.5,
384 -0.5,
385 -0.5,
386 0.5,
387 /* Bottom face */
388 /* Bottom left */
389 -0.5,
390 -0.5,
391 -0.5,
392 0.5,
393 -0.5,
394 0.5,
395 -0.5,
396 -0.5,
397 0.5,
398 /* Top right */
399 -0.5,
400 -0.5,
401 -0.5,
402 0.5,
403 -0.5,
404 -0.5,
405 0.5,
406 -0.5,
407 0.5,
408};
409
410static const float g_colors[] = {
411 /* Front face */
412 /* Bottom left */
413 1.0, 0.0, 0.0, /* red */
414 0.0, 0.0, 1.0, /* blue */
415 0.0, 1.0, 0.0, /* green */
416 /* Top right */
417 1.0, 0.0, 0.0, /* red */
418 1.0, 1.0, 0.0, /* yellow */
419 0.0, 0.0, 1.0, /* blue */
420 /* Left face */
421 /* Bottom left */
422 1.0, 1.0, 1.0, /* white */
423 0.0, 1.0, 0.0, /* green */
424 0.0, 1.0, 1.0, /* cyan */
425 /* Top right */
426 1.0, 1.0, 1.0, /* white */
427 1.0, 0.0, 0.0, /* red */
428 0.0, 1.0, 0.0, /* green */
429 /* Top face */
430 /* Bottom left */
431 1.0, 1.0, 1.0, /* white */
432 1.0, 1.0, 0.0, /* yellow */
433 1.0, 0.0, 0.0, /* red */
434 /* Top right */
435 1.0, 1.0, 1.0, /* white */
436 0.0, 0.0, 0.0, /* black */
437 1.0, 1.0, 0.0, /* yellow */
438 /* Right face */
439 /* Bottom left */
440 1.0, 1.0, 0.0, /* yellow */
441 1.0, 0.0, 1.0, /* magenta */
442 0.0, 0.0, 1.0, /* blue */
443 /* Top right */
444 1.0, 1.0, 0.0, /* yellow */
445 0.0, 0.0, 0.0, /* black */
446 1.0, 0.0, 1.0, /* magenta */
447 /* Back face */
448 /* Bottom left */
449 0.0, 0.0, 0.0, /* black */
450 0.0, 1.0, 1.0, /* cyan */
451 1.0, 0.0, 1.0, /* magenta */
452 /* Top right */
453 0.0, 0.0, 0.0, /* black */
454 1.0, 1.0, 1.0, /* white */
455 0.0, 1.0, 1.0, /* cyan */
456 /* Bottom face */
457 /* Bottom left */
458 0.0, 1.0, 0.0, /* green */
459 1.0, 0.0, 1.0, /* magenta */
460 0.0, 1.0, 1.0, /* cyan */
461 /* Top right */
462 0.0, 1.0, 0.0, /* green */
463 0.0, 0.0, 1.0, /* blue */
464 1.0, 0.0, 1.0, /* magenta */
465};
466
467static const char *g_shader_vert_src =
468 " attribute vec4 av4position; "
469 " attribute vec3 av3color; "
470 " uniform mat4 mvp; "
471 " varying vec3 vv3color; "
472 " void main() { "
473 " vv3color = av3color; "
474 " gl_Position = mvp * av4position; "
475 " } ";
476
477static const char *g_shader_frag_src =
478 " precision lowp float; "
479 " varying vec3 vv3color; "
480 " void main() { "
481 " gl_FragColor = vec4(vv3color, 1.0); "
482 " } ";
483
484static void
485Render(unsigned int width, unsigned int height, shader_data *data)
486{
487 float matrix_rotate[16], matrix_modelview[16], matrix_perspective[16], matrix_mvp[16];
488
489 /*
490 * Do some rotation with Euler angles. It is not a fixed axis as
491 * quaterions would be, but the effect is cool.
492 */
493 rotate_matrix((float)data->angle_x, 1.0f, 0.0f, 0.0f, matrix_modelview);
494 rotate_matrix((float)data->angle_y, 0.0f, 1.0f, 0.0f, matrix_rotate);
495
496 multiply_matrix(matrix_rotate, matrix_modelview, matrix_modelview);
497
498 rotate_matrix((float)data->angle_z, 0.0f, 1.0f, 0.0f, matrix_rotate);
499
500 multiply_matrix(matrix_rotate, matrix_modelview, matrix_modelview);
501
502 /* Pull the camera back from the cube */
503 matrix_modelview[14] -= 2.5f;
504
505 perspective_matrix(45.0f, (float)width / height, 0.01f, 100.0f, matrix_perspective);
506 multiply_matrix(matrix_perspective, matrix_modelview, matrix_mvp);
507
508 GL_CHECK(ctx.glUniformMatrix4fv(data->attr_mvp, 1, GL_FALSE, matrix_mvp));
509
510 data->angle_x += 3;
511 data->angle_y += 2;
512 data->angle_z += 1;
513
514 if (data->angle_x >= 360) {
515 data->angle_x -= 360;
516 }
517 if (data->angle_x < 0) {
518 data->angle_x += 360;
519 }
520 if (data->angle_y >= 360) {
521 data->angle_y -= 360;
522 }
523 if (data->angle_y < 0) {
524 data->angle_y += 360;
525 }
526 if (data->angle_z >= 360) {
527 data->angle_z -= 360;
528 }
529 if (data->angle_z < 0) {
530 data->angle_z += 360;
531 }
532
533 GL_CHECK(ctx.glViewport(0, 0, width, height));
534 GL_CHECK(ctx.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT));
535 GL_CHECK(ctx.glDrawArrays(GL_TRIANGLES, 0, 36));
536}
537
538static int done;
539static Uint32 frames;
540#ifndef SDL_PLATFORM_EMSCRIPTEN
541static thread_data *threads;
542#endif
543
544static void
545render_window(int index)
546{
547 int w, h;
548
549 if (!state->windows[index]) {
550 return;
551 }
552
553 if (!SDL_GL_MakeCurrent(state->windows[index], context[index])) {
554 SDL_Log("SDL_GL_MakeCurrent(): %s", SDL_GetError());
555 return;
556 }
557
558 SDL_GetWindowSizeInPixels(state->windows[index], &w, &h);
559 Render(w, h, &datas[index]);
560 SDL_GL_SwapWindow(state->windows[index]);
561 ++frames;
562}
563
564#ifndef SDL_PLATFORM_EMSCRIPTEN
565static int SDLCALL
566render_thread_fn(void *render_ctx)
567{
568 thread_data *thread = render_ctx;
569
570 while (!done && !thread->done && state->windows[thread->index]) {
571 if (SDL_CompareAndSwapAtomicInt(&thread->suspended, WAIT_STATE_ENTER_SEM, WAIT_STATE_WAITING_ON_SEM)) {
572 SDL_WaitSemaphore(thread->suspend_sem);
573 }
574 render_window(thread->index);
575 }
576
577 SDL_GL_MakeCurrent(state->windows[thread->index], NULL);
578 return 0;
579}
580
581static thread_data *GetThreadDataForWindow(SDL_WindowID id)
582{
583 int i;
584 SDL_Window *window = SDL_GetWindowFromID(id);
585 if (window) {
586 for (i = 0; i < state->num_windows; ++i) {
587 if (window == state->windows[i]) {
588 return &threads[i];
589 }
590 }
591 }
592 return NULL;
593}
594
595static void
596loop_threaded(void)
597{
598 SDL_Event event;
599 thread_data *tdata;
600
601 /* Wait for events */
602 while (SDL_WaitEvent(&event) && !done) {
603 if (suspend_when_occluded && event.type == SDL_EVENT_WINDOW_OCCLUDED) {
604 tdata = GetThreadDataForWindow(event.window.windowID);
605 if (tdata) {
606 SDL_CompareAndSwapAtomicInt(&tdata->suspended, WAIT_STATE_GO, WAIT_STATE_ENTER_SEM);
607 }
608 } else if (suspend_when_occluded && event.type == SDL_EVENT_WINDOW_EXPOSED) {
609 tdata = GetThreadDataForWindow(event.window.windowID);
610 if (tdata) {
611 if (SDL_SetAtomicInt(&tdata->suspended, WAIT_STATE_GO) == WAIT_STATE_WAITING_ON_SEM) {
612 SDL_SignalSemaphore(tdata->suspend_sem);
613 }
614 }
615 } else if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) {
616 tdata = GetThreadDataForWindow(event.window.windowID);
617 if (tdata) {
618 /* Stop the render thread when the window is closed */
619 tdata->done = 1;
620 if (tdata->thread) {
621 SDL_SetAtomicInt(&tdata->suspended, WAIT_STATE_GO);
622 SDL_SignalSemaphore(tdata->suspend_sem);
623 SDL_WaitThread(tdata->thread, NULL);
624 tdata->thread = NULL;
625 SDL_DestroySemaphore(tdata->suspend_sem);
626 }
627 break;
628 }
629 }
630 SDLTest_CommonEvent(state, &event, &done);
631 }
632}
633#endif
634
635static void
636loop(void)
637{
638 SDL_Event event;
639 int i;
640 int active_windows = 0;
641
642 /* Check for events */
643 while (SDL_PollEvent(&event) && !done) {
644 SDLTest_CommonEvent(state, &event, &done);
645 }
646 if (!done) {
647 for (i = 0; i < state->num_windows; ++i) {
648 if (state->windows[i] == NULL ||
649 (suspend_when_occluded && (SDL_GetWindowFlags(state->windows[i]) & SDL_WINDOW_OCCLUDED))) {
650 continue;
651 }
652 ++active_windows;
653 render_window(i);
654 }
655 }
656#ifdef SDL_PLATFORM_EMSCRIPTEN
657 else {
658 emscripten_cancel_main_loop();
659 }
660#endif
661
662 /* If all windows are occluded, throttle event polling to 15hz. */
663 if (!done && !active_windows) {
664 SDL_DelayNS(SDL_NS_PER_SECOND / 15);
665 }
666}
667
668int main(int argc, char *argv[])
669{
670 int fsaa, accel, threaded;
671 int value;
672 int i;
673 const SDL_DisplayMode *mode;
674 Uint64 then, now;
675 shader_data *data;
676
677 /* Initialize parameters */
678 fsaa = 0;
679 accel = 0;
680 threaded = 0;
681
682 /* Initialize test framework */
683 state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
684 if (!state) {
685 return 1;
686 }
687 for (i = 1; i < argc;) {
688 int consumed;
689
690 consumed = SDLTest_CommonArg(state, i);
691 if (consumed == 0) {
692 if (SDL_strcasecmp(argv[i], "--fsaa") == 0) {
693 ++fsaa;
694 consumed = 1;
695 } else if (SDL_strcasecmp(argv[i], "--accel") == 0) {
696 ++accel;
697 consumed = 1;
698 } else if (SDL_strcasecmp(argv[i], "--threaded") == 0) {
699 ++threaded;
700 consumed = 1;
701 } else if(SDL_strcasecmp(argv[i], "--suspend-when-occluded") == 0) {
702 suspend_when_occluded = true;
703 consumed = 1;
704 } else if (SDL_strcasecmp(argv[i], "--zdepth") == 0) {
705 i++;
706 if (!argv[i]) {
707 consumed = -1;
708 } else {
709 char *endptr = NULL;
710 depth = (int)SDL_strtol(argv[i], &endptr, 0);
711 if (endptr != argv[i] && *endptr == '\0') {
712 consumed = 1;
713 } else {
714 consumed = -1;
715 }
716 }
717 } else {
718 consumed = -1;
719 }
720 }
721 if (consumed < 0) {
722 static const char *options[] = { "[--fsaa]", "[--accel]", "[--zdepth %d]", "[--threaded]", "[--suspend-when-occluded]",NULL };
723 SDLTest_CommonLogUsage(state, argv[0], options);
724 quit(1);
725 }
726 i += consumed;
727 }
728
729 /* Set OpenGL parameters */
730 state->window_flags |= SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE;
731 state->gl_red_size = 5;
732 state->gl_green_size = 5;
733 state->gl_blue_size = 5;
734 state->gl_depth_size = depth;
735 state->gl_major_version = 2;
736 state->gl_minor_version = 0;
737 state->gl_profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
738
739 if (fsaa) {
740 state->gl_multisamplebuffers = 1;
741 state->gl_multisamplesamples = fsaa;
742 }
743 if (accel) {
744 state->gl_accelerated = 1;
745 }
746 if (!SDLTest_CommonInit(state)) {
747 quit(2);
748 return 0;
749 }
750
751 context = (SDL_GLContext *)SDL_calloc(state->num_windows, sizeof(*context));
752 if (!context) {
753 SDL_Log("Out of memory!");
754 quit(2);
755 }
756
757 /* Create OpenGL ES contexts */
758 for (i = 0; i < state->num_windows; i++) {
759 context[i] = SDL_GL_CreateContext(state->windows[i]);
760 if (!context[i]) {
761 SDL_Log("SDL_GL_CreateContext(): %s", SDL_GetError());
762 quit(2);
763 }
764 }
765
766 /* Important: call this *after* creating the context */
767 if (!LoadContext(&ctx)) {
768 SDL_Log("Could not load GLES2 functions");
769 quit(2);
770 return 0;
771 }
772
773 SDL_GL_SetSwapInterval(state->render_vsync);
774
775 mode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay());
776 SDL_Log("Threaded : %s", threaded ? "yes" : "no");
777 if (mode) {
778 SDL_Log("Screen bpp: %d", SDL_BITSPERPIXEL(mode->format));
779 SDL_Log("%s", "");
780 }
781 SDL_Log("Vendor : %s", ctx.glGetString(GL_VENDOR));
782 SDL_Log("Renderer : %s", ctx.glGetString(GL_RENDERER));
783 SDL_Log("Version : %s", ctx.glGetString(GL_VERSION));
784 SDL_Log("Extensions : %s", ctx.glGetString(GL_EXTENSIONS));
785 SDL_Log("%s", "");
786
787 if (SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &value)) {
788 SDL_Log("SDL_GL_RED_SIZE: requested %d, got %d", 5, value);
789 } else {
790 SDL_Log("Failed to get SDL_GL_RED_SIZE: %s",
791 SDL_GetError());
792 }
793 if (SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &value)) {
794 SDL_Log("SDL_GL_GREEN_SIZE: requested %d, got %d", 5, value);
795 } else {
796 SDL_Log("Failed to get SDL_GL_GREEN_SIZE: %s",
797 SDL_GetError());
798 }
799 if (SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &value)) {
800 SDL_Log("SDL_GL_BLUE_SIZE: requested %d, got %d", 5, value);
801 } else {
802 SDL_Log("Failed to get SDL_GL_BLUE_SIZE: %s",
803 SDL_GetError());
804 }
805 if (SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &value)) {
806 SDL_Log("SDL_GL_DEPTH_SIZE: requested %d, got %d", depth, value);
807 } else {
808 SDL_Log("Failed to get SDL_GL_DEPTH_SIZE: %s",
809 SDL_GetError());
810 }
811 if (fsaa) {
812 if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &value)) {
813 SDL_Log("SDL_GL_MULTISAMPLEBUFFERS: requested 1, got %d", value);
814 } else {
815 SDL_Log("Failed to get SDL_GL_MULTISAMPLEBUFFERS: %s",
816 SDL_GetError());
817 }
818 if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &value)) {
819 SDL_Log("SDL_GL_MULTISAMPLESAMPLES: requested %d, got %d", fsaa,
820 value);
821 } else {
822 SDL_Log("Failed to get SDL_GL_MULTISAMPLESAMPLES: %s",
823 SDL_GetError());
824 }
825 }
826 if (accel) {
827 if (SDL_GL_GetAttribute(SDL_GL_ACCELERATED_VISUAL, &value)) {
828 SDL_Log("SDL_GL_ACCELERATED_VISUAL: requested 1, got %d", value);
829 } else {
830 SDL_Log("Failed to get SDL_GL_ACCELERATED_VISUAL: %s",
831 SDL_GetError());
832 }
833 }
834
835 datas = (shader_data *)SDL_calloc(state->num_windows, sizeof(shader_data));
836
837 /* Set rendering settings for each context */
838 for (i = 0; i < state->num_windows; ++i) {
839
840 int w, h;
841 if (!SDL_GL_MakeCurrent(state->windows[i], context[i])) {
842 SDL_Log("SDL_GL_MakeCurrent(): %s", SDL_GetError());
843
844 /* Continue for next window */
845 continue;
846 }
847 SDL_GetWindowSizeInPixels(state->windows[i], &w, &h);
848 ctx.glViewport(0, 0, w, h);
849
850 data = &datas[i];
851 data->angle_x = 0;
852 data->angle_y = 0;
853 data->angle_z = 0;
854
855 /* Shader Initialization */
856 process_shader(&data->shader_vert, g_shader_vert_src, GL_VERTEX_SHADER);
857 process_shader(&data->shader_frag, g_shader_frag_src, GL_FRAGMENT_SHADER);
858
859 /* Create shader_program (ready to attach shaders) */
860 data->shader_program = GL_CHECK(ctx.glCreateProgram());
861
862 /* Attach shaders and link shader_program */
863 link_program(data);
864
865 /* Get attribute locations of non-fixed attributes like color and texture coordinates. */
866 data->attr_position = GL_CHECK(ctx.glGetAttribLocation(data->shader_program, "av4position"));
867 data->attr_color = GL_CHECK(ctx.glGetAttribLocation(data->shader_program, "av3color"));
868
869 /* Get uniform locations */
870 data->attr_mvp = GL_CHECK(ctx.glGetUniformLocation(data->shader_program, "mvp"));
871
872 GL_CHECK(ctx.glUseProgram(data->shader_program));
873
874 /* Enable attributes for position, color and texture coordinates etc. */
875 GL_CHECK(ctx.glEnableVertexAttribArray(data->attr_position));
876 GL_CHECK(ctx.glEnableVertexAttribArray(data->attr_color));
877
878 /* Populate attributes for position, color and texture coordinates etc. */
879
880 GL_CHECK(ctx.glGenBuffers(1, &data->position_buffer));
881 GL_CHECK(ctx.glBindBuffer(GL_ARRAY_BUFFER, data->position_buffer));
882 GL_CHECK(ctx.glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertices), g_vertices, GL_STATIC_DRAW));
883 GL_CHECK(ctx.glVertexAttribPointer(data->attr_position, 3, GL_FLOAT, GL_FALSE, 0, 0));
884 GL_CHECK(ctx.glBindBuffer(GL_ARRAY_BUFFER, 0));
885
886 GL_CHECK(ctx.glGenBuffers(1, &data->color_buffer));
887 GL_CHECK(ctx.glBindBuffer(GL_ARRAY_BUFFER, data->color_buffer));
888 GL_CHECK(ctx.glBufferData(GL_ARRAY_BUFFER, sizeof(g_colors), g_colors, GL_STATIC_DRAW));
889 GL_CHECK(ctx.glVertexAttribPointer(data->attr_color, 3, GL_FLOAT, GL_FALSE, 0, 0));
890 GL_CHECK(ctx.glBindBuffer(GL_ARRAY_BUFFER, 0));
891
892 GL_CHECK(ctx.glEnable(GL_CULL_FACE));
893 GL_CHECK(ctx.glEnable(GL_DEPTH_TEST));
894
895 SDL_GL_MakeCurrent(state->windows[i], NULL);
896 }
897
898 /* Main render loop */
899 frames = 0;
900 then = SDL_GetTicks();
901 done = 0;
902
903#ifdef SDL_PLATFORM_EMSCRIPTEN
904 emscripten_set_main_loop(loop, 0, 1);
905#else
906 if (threaded) {
907 threads = (thread_data *)SDL_calloc(state->num_windows, sizeof(thread_data));
908
909 /* Start a render thread for each window */
910 for (i = 0; i < state->num_windows; ++i) {
911 threads[i].index = i;
912 SDL_SetAtomicInt(&threads[i].suspended, 0);
913 threads[i].suspend_sem = SDL_CreateSemaphore(0);
914 threads[i].thread = SDL_CreateThread(render_thread_fn, "RenderThread", &threads[i]);
915 }
916
917 while (!done) {
918 loop_threaded();
919 }
920
921 /* Join the remaining render threads (if any) */
922 for (i = 0; i < state->num_windows; ++i) {
923 threads[i].done = 1;
924 if (threads[i].thread) {
925 SDL_WaitThread(threads[i].thread, NULL);
926 }
927 }
928 SDL_free(threads);
929 } else {
930 while (!done) {
931 loop();
932 }
933 }
934#endif
935
936 /* Print out some timing information */
937 now = SDL_GetTicks();
938 if (now > then) {
939 SDL_Log("%2.2f frames per second",
940 ((double)frames * 1000) / (now - then));
941 }
942#ifndef SDL_PLATFORM_ANDROID
943 quit(0);
944#endif
945 return 0;
946}
947
948#else /* HAVE_OPENGLES2 */
949
950int main(int argc, char *argv[])
951{
952 SDL_Log("No OpenGL ES support on this system");
953 return 1;
954}
955
956#endif /* HAVE_OPENGLES2 */