The open source OpenXR runtime
1// Copyright 2020-2022, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief C++ program part for the SDL test.
6 * @author Jakob Bornecrantz <jakob@collabora.com>
7 * @ingroup sdl_test
8 */
9
10#include "ogl/ogl_api.h"
11
12#include "util/u_misc.h"
13
14#include "sdl_internal.hpp"
15
16#include <cstdio>
17
18void
19sdl_create_window(struct sdl_program *sp)
20{
21 if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
22 assert(false);
23 }
24
25 char title[1024];
26 snprintf(title, sizeof(title), "Monado! ☃");
27
28 int x = SDL_WINDOWPOS_UNDEFINED;
29 int y = SDL_WINDOWPOS_UNDEFINED;
30 int w = 1920;
31 int h = 1080;
32
33 SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
34 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
35 SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
36 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
37 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
38 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
39 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
40 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
41
42 int window_flags = 0;
43 window_flags |= SDL_WINDOW_SHOWN;
44 window_flags |= SDL_WINDOW_OPENGL;
45 window_flags |= SDL_WINDOW_RESIZABLE;
46 window_flags |= SDL_WINDOW_ALLOW_HIGHDPI;
47#if 0
48 window_flags |= SDL_WINDOW_MAXIMIZED;
49#endif
50
51
52 sp->win = SDL_CreateWindow(title, x, y, w, h, window_flags);
53
54 if (sp->win == NULL) {
55 assert(false);
56 }
57
58 sp->ctx = SDL_GL_CreateContext(sp->win);
59 if (sp->ctx == NULL) {
60 assert(false);
61 }
62
63 // Make the context current in this thread for loading OpenGL.
64 sdl_make_current(sp);
65 SDL_GL_SetSwapInterval(1); // Enable vsync
66
67 // Setup OpenGL bindings.
68 bool err = gladLoadGL((GLADloadfunc)SDL_GL_GetProcAddress) == 0;
69 if (err) {
70 assert(false);
71 }
72
73 // We are going to render on a different thread, make sure to unbind it.
74 sdl_make_uncurrent(sp);
75}
76
77extern "C" struct sdl_program *
78sdl_program_plus_create()
79{
80 sdl_program_plus &spp = *new sdl_program_plus();
81 spp.spp = &spp;
82
83 os_mutex_init(&spp.current_mutex);
84
85 // Initial state.
86 spp.log_level = U_LOGGING_INFO;
87 spp.state.head.pose = XRT_POSE_IDENTITY;
88
89 // Create the window, init before sub components.
90 sdl_create_window(&spp);
91
92 // Init sub components.
93 sdl_instance_init(&spp);
94 sdl_system_init(&spp);
95 sdl_device_init(&spp);
96 sdl_system_devices_init(&spp);
97 sdl_compositor_init(&spp); // Needs the window.
98
99 return &spp;
100}
101
102extern "C" void
103sdl_program_plus_render(struct sdl_program_plus *spp_ptr)
104{
105 auto &spp = *spp_ptr;
106
107 // Make context current
108 sdl_make_current(&spp);
109
110 // Flush the events.
111 SDL_Event e = {0};
112 while (SDL_PollEvent(&e)) {
113 // Nothing for now.
114 }
115
116 if (spp.c.base.layer_accum.layer_count == 0) {
117 glClearColor(0.2f, 0.2f, 0.2f, 0.0f);
118 glClear(GL_COLOR_BUFFER_BIT);
119 } else if (spp.c.base.layer_accum.layers[0].data.type == XRT_LAYER_PROJECTION ||
120 spp.c.base.layer_accum.layers[0].data.type == XRT_LAYER_PROJECTION_DEPTH) {
121
122 auto &l = spp.c.base.layer_accum.layers[0];
123 auto &ssc = *(sdl_swapchain *)l.sc_array[0];
124 GLuint tex = ssc.textures[l.data.proj.v[0].sub.image_index];
125
126 glClearColor(0.2f, 0.0f, 0.0f, 0.0f);
127 glClear(GL_COLOR_BUFFER_BIT);
128
129 GLuint fbo = 0;
130 glGenFramebuffers(1, &fbo);
131 glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
132 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
133 CHECK_GL();
134
135 glFramebufferTexture2D( //
136 GL_READ_FRAMEBUFFER, // GLenum target
137 GL_COLOR_ATTACHMENT0, // GLenum attachment
138 GL_TEXTURE_2D, // GLenum textarget
139 tex, // GLuint texture
140 0); // GLint level
141 CHECK_GL();
142
143 int w, h;
144 SDL_GetWindowSize(spp.win, &w, &h);
145 glBlitFramebuffer( //
146 0, // GLint srcX0
147 0, // GLint srcY0
148 ssc.w, // GLint srcX1
149 ssc.h, // GLint srcY1
150 0, // GLint dstX0
151 0, // GLint dstY0
152 w, // GLint dstX1
153 h, // GLint dstY1
154 GL_COLOR_BUFFER_BIT, // GLbitfield mask
155 GL_NEAREST); // GLenum filter
156 CHECK_GL();
157
158 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
159 CHECK_GL();
160
161 glDeleteFramebuffers(1, &fbo);
162 } else {
163 glClearColor(1.0f, 0.0f, 1.0f, 0.0f);
164 glClear(GL_COLOR_BUFFER_BIT);
165 }
166
167 // Display what we rendered.
168 SDL_GL_SwapWindow(spp.win);
169
170 // Will be used when creating swapchains, unbind it.
171 sdl_make_uncurrent(&spp);
172}
173
174extern "C" void
175sdl_program_plus_destroy(struct sdl_program_plus *spp)
176{
177 os_mutex_destroy(&spp->current_mutex);
178
179 delete spp;
180}