-
Notifications
You must be signed in to change notification settings - Fork 24
/
helloworld_mt.cpp
185 lines (175 loc) · 6.11 KB
/
helloworld_mt.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*
* Copyright 2011-2019 Branimir Karadzic. All rights reserved.
* License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
*/
#include <stdio.h>
#include <bx/bx.h>
#include <bx/spscqueue.h>
#include <bx/thread.h>
#include <bgfx/bgfx.h>
#include <bgfx/platform.h>
#include <GLFW/glfw3.h>
#if BX_PLATFORM_LINUX
#define GLFW_EXPOSE_NATIVE_X11
#elif BX_PLATFORM_WINDOWS
#define GLFW_EXPOSE_NATIVE_WIN32
#elif BX_PLATFORM_OSX
#define GLFW_EXPOSE_NATIVE_COCOA
#endif
#include <GLFW/glfw3native.h>
#include "logo.h"
static bx::DefaultAllocator s_allocator;
static bx::SpScUnboundedQueue s_apiThreadEvents(&s_allocator);
enum class EventType
{
Exit,
Key,
Resize
};
struct ExitEvent
{
EventType type = EventType::Exit;
};
struct KeyEvent
{
EventType type = EventType::Key;
int key;
int action;
};
struct ResizeEvent
{
EventType type = EventType::Resize;
uint32_t width;
uint32_t height;
};
static void glfw_errorCallback(int error, const char *description)
{
fprintf(stderr, "GLFW error %d: %s\n", error, description);
}
static void glfw_keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
{
auto keyEvent = new KeyEvent;
keyEvent->key = key;
keyEvent->action = action;
s_apiThreadEvents.push(keyEvent);
}
struct ApiThreadArgs
{
bgfx::PlatformData platformData;
uint32_t width;
uint32_t height;
};
static int32_t runApiThread(bx::Thread *self, void *userData)
{
auto args = (ApiThreadArgs *)userData;
// Initialize bgfx using the native window handle and window resolution.
bgfx::Init init;
init.platformData = args->platformData;
init.resolution.width = args->width;
init.resolution.height = args->height;
init.resolution.reset = BGFX_RESET_VSYNC;
if (!bgfx::init(init))
return 1;
// Set view 0 to the same dimensions as the window and to clear the color buffer.
const bgfx::ViewId kClearView = 0;
bgfx::setViewClear(kClearView, BGFX_CLEAR_COLOR);
bgfx::setViewRect(kClearView, 0, 0, bgfx::BackbufferRatio::Equal);
uint32_t width = args->width;
uint32_t height = args->height;
bool showStats = false;
bool exit = false;
while (!exit) {
// Handle events from the main thread.
while (auto ev = (EventType *)s_apiThreadEvents.pop()) {
if (*ev == EventType::Key) {
auto keyEvent = (KeyEvent *)ev;
if (keyEvent->key == GLFW_KEY_F1 && keyEvent->action == GLFW_RELEASE)
showStats = !showStats;
}
else if (*ev == EventType::Resize) {
auto resizeEvent = (ResizeEvent *)ev;
bgfx::reset(resizeEvent->width, resizeEvent->height, BGFX_RESET_VSYNC);
bgfx::setViewRect(kClearView, 0, 0, bgfx::BackbufferRatio::Equal);
width = resizeEvent->width;
height = resizeEvent->height;
} else if (*ev == EventType::Exit) {
exit = true;
}
delete ev;
}
// This dummy draw call is here to make sure that view 0 is cleared if no other draw calls are submitted to view 0.
bgfx::touch(kClearView);
// Use debug font to print information about this example.
bgfx::dbgTextClear();
bgfx::dbgTextImage(bx::max<uint16_t>(uint16_t(width / 2 / 8), 20) - 20, bx::max<uint16_t>(uint16_t(height / 2 / 16), 6) - 6, 40, 12, s_logo, 160);
bgfx::dbgTextPrintf(0, 0, 0x0f, "Press F1 to toggle stats.");
bgfx::dbgTextPrintf(0, 1, 0x0f, "Color can be changed with ANSI \x1b[9;me\x1b[10;ms\x1b[11;mc\x1b[12;ma\x1b[13;mp\x1b[14;me\x1b[0m code too.");
bgfx::dbgTextPrintf(80, 1, 0x0f, "\x1b[;0m \x1b[;1m \x1b[; 2m \x1b[; 3m \x1b[; 4m \x1b[; 5m \x1b[; 6m \x1b[; 7m \x1b[0m");
bgfx::dbgTextPrintf(80, 2, 0x0f, "\x1b[;8m \x1b[;9m \x1b[;10m \x1b[;11m \x1b[;12m \x1b[;13m \x1b[;14m \x1b[;15m \x1b[0m");
const bgfx::Stats* stats = bgfx::getStats();
bgfx::dbgTextPrintf(0, 2, 0x0f, "Backbuffer %dW x %dH in pixels, debug text %dW x %dH in characters.", stats->width, stats->height, stats->textWidth, stats->textHeight);
// Enable stats or debug text.
bgfx::setDebug(showStats ? BGFX_DEBUG_STATS : BGFX_DEBUG_TEXT);
// Advance to next frame. Main thread will be kicked to process submitted rendering primitives.
bgfx::frame();
}
bgfx::shutdown();
return 0;
}
int main(int argc, char **argv)
{
// Create a GLFW window without an OpenGL context.
glfwSetErrorCallback(glfw_errorCallback);
if (!glfwInit())
return 1;
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow *window = glfwCreateWindow(1024, 768, "helloworld multithreaded", nullptr, nullptr);
if (!window)
return 1;
glfwSetKeyCallback(window, glfw_keyCallback);
// Call bgfx::renderFrame before bgfx::init to signal to bgfx not to create a render thread.
// Most graphics APIs must be used on the same thread that created the window.
bgfx::renderFrame();
// Create a thread to call the bgfx API from (except bgfx::renderFrame).
ApiThreadArgs apiThreadArgs;
#if BX_PLATFORM_LINUX || BX_PLATFORM_BSD
apiThreadArgs.platformData.ndt = glfwGetX11Display();
apiThreadArgs.platformData.nwh = (void*)(uintptr_t)glfwGetX11Window(window);
#elif BX_PLATFORM_OSX
apiThreadArgs.platformData.nwh = glfwGetCocoaWindow(window);
#elif BX_PLATFORM_WINDOWS
apiThreadArgs.platformData.nwh = glfwGetWin32Window(window);
#endif
int width, height;
glfwGetWindowSize(window, &width, &height);
apiThreadArgs.width = (uint32_t)width;
apiThreadArgs.height = (uint32_t)height;
bx::Thread apiThread;
apiThread.init(runApiThread, &apiThreadArgs);
// Run GLFW message pump.
bool exit = false;
while (!exit) {
glfwPollEvents();
// Send window close event to the API thread.
if (glfwWindowShouldClose(window)) {
s_apiThreadEvents.push(new ExitEvent);
exit = true;
}
// Send window resize event to the API thread.
int oldWidth = width, oldHeight = height;
glfwGetWindowSize(window, &width, &height);
if (width != oldWidth || height != oldHeight) {
auto resize = new ResizeEvent;
resize->width = (uint32_t)width;
resize->height = (uint32_t)height;
s_apiThreadEvents.push(resize);
}
// Wait for the API thread to call bgfx::frame, then process submitted rendering primitives.
bgfx::renderFrame();
}
// Wait for the API thread to finish before shutting down.
while (bgfx::RenderFrame::NoContext != bgfx::renderFrame()) {}
apiThread.shutdown();
glfwTerminate();
return apiThread.getExitCode();
}