aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndre Weissflog <floooh@gmail.com>2021-04-17 14:08:24 +0200
committerAndre Weissflog <floooh@gmail.com>2021-04-17 14:08:24 +0200
commit660b4050ca6104a57c7a95f5f3781f3d046ecc3f (patch)
tree849ba842d5aa4ee244cd2f1413aa8e2141b44150
parentf3f1661f69f180d50bf108811914de7ea5425a20 (diff)
sokol_app.h: window pool code, and some better platform-specific code structure
-rw-r--r--sokol_app.h316
1 files changed, 298 insertions, 18 deletions
diff --git a/sokol_app.h b/sokol_app.h
index a041ff86..d198d251 100644
--- a/sokol_app.h
+++ b/sokol_app.h
@@ -1015,6 +1015,7 @@ extern "C" {
/* misc constants */
enum {
+ SAPP_INVALID_ID = 0,
SAPP_MAX_TOUCHPOINTS = 8,
SAPP_MAX_MOUSEBUTTONS = 3,
SAPP_MAX_KEYCODES = 512,
@@ -1382,6 +1383,7 @@ typedef struct sapp_ios_desc {
} sapp_ios_desc;
typedef struct sapp_desc {
+ int window_pool_size;
sapp_window_desc window;
sapp_icon_desc icon; // FIXME: per-window icons?
sapp_gl_desc gl;
@@ -2245,6 +2247,14 @@ typedef struct {
#define _SAPP_PIXELFORMAT_DEPTH (41)
#define _SAPP_PIXELFORMAT_DEPTH_STENCIL (42)
+/* this MUST be 0 */
+#define _SAPP_INVALID_SLOT_INDEX (0)
+
+#define _SAPP_SLOT_SHIFT (16)
+#define _SAPP_SLOT_MASK ((1<<_SAPP_SLOT_SHIFT)-1)
+#define _SAPP_MAX_POOL_SIZE (1<<_SAPP_SLOT_SHIFT)
+#define _SAPP_DEFAULT_POOL_SIZE (128)
+
#if defined(_SAPP_MACOS) || defined(_SAPP_IOS)
// this is ARC compatible
#if defined(__cplusplus)
@@ -2257,6 +2267,17 @@ typedef struct {
#endif
typedef struct {
+ int size;
+ int queue_top;
+ uint32_t* gen_ctrs;
+ int* free_queue;
+} _sapp_pool_t;
+
+typedef struct {
+ uint32_t id;
+} _sapp_slot_t;
+
+typedef struct {
bool enabled;
int buf_size;
char* buffer;
@@ -2280,10 +2301,6 @@ typedef struct {
} _sapp_mouse_t;
typedef struct {
- uint32_t id;
-} _sapp_slot_t;
-
-typedef struct {
_sapp_slot_t slot;
sapp_window_desc desc;
int window_width;
@@ -2327,7 +2344,13 @@ typedef struct {
} _sapp_window_t;
typedef struct {
+ _sapp_pool_t pool;
+ _sapp_window_t* windows;
+} _sapp_window_pool_t;
+
+typedef struct {
sapp_desc desc;
+ _sapp_window_pool_t window_pool;
_sapp_window_t window;
bool valid;
bool gles2_fallback;
@@ -2366,7 +2389,210 @@ typedef struct {
} _sapp_t;
static _sapp_t _sapp;
-/*=== PRIVATE HELPER FUNCTIONS ===============================================*/
+// forward-declared platform-specific functions
+#if defined(_SAPP_MACOS)
+_SOKOL_PRIVATE void _sapp_macos_init_backend(void);
+_SOKOL_PRIVATE void _sapp_macos_discard_backend(void);
+_SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win, const sapp_window_desc* desc);
+_SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* win);
+#elif defined(_SAPP_IOS)
+_SOKOL_PRIVATE void _sapp_ios_init_backend(void);
+_SOKOL_PRIVATE void _sapp_ios_discard_backend(void);
+_SOKOL_PRIVATE bool _sapp_ios_create_window(_sapp_window_t* win, const sapp_window_desc* desc);
+_SOKOL_PRIVATE void _sapp_ios_destroy_window(_sapp_window_t* win);
+#elif defined(_SAPP_EMSCRIPTEN)
+_SOKOL_PRIVATE void _sapp_emsc_init_backend(void);
+_SOKOL_PRIVATE void _sapp_emsc_discard_backend(void);
+_SOKOL_PRIVATE bool _sapp_emsc_create_window(_sapp_window_t* win, const sapp_window_desc* desc);
+_SOKOL_PRIVATE void _sapp_emsc_destroy_window(_sapp_window_t* win);
+#elif defined(_SAPP_WIN32)
+_SOKOL_PRIVATE void _sapp_win32_init_backend(void);
+_SOKOL_PRIVATE void _sapp_win32_discard_backend(void);
+_SOKOL_PRIVATE bool _sapp_win32_create_window(_sapp_window_t* win, const sapp_window_desc* desc);
+_SOKOL_PRIVATE void _sapp_win32_destroy_window(_sapp_window_t* win);
+#elif defined(_SAPP_UWP)
+_SOKOL_PRIVATE void _sapp_uwp_init_backend(void);
+_SOKOL_PRIVATE void _sapp_uwp_discard_backend(void);
+_SOKOL_PRIVATE bool _sapp_uwp_create_window(_sapp_window_t* win, const sapp_window_desc* desc);
+_SOKOL_PRIVATE void _sapp_uwp_destroy_window(_sapp_window_t* win);
+#elif defined(_SAPP_ANDROID)
+_SOKOL_PRIVATE void _sapp_android_init_backend(void);
+_SOKOL_PRIVATE void _sapp_android_discard_backend(void);
+_SOKOL_PRIVATE bool _sapp_android_create_window(_sapp_window_t* win, const sapp_window_desc* desc);
+_SOKOL_PRIVATE void _sapp_android_destroy_window(_sapp_window_t* win);
+#elif defined(_SAPP_LINUX)
+_SOKOL_PRIVATE void _sapp_x11_init_backend(void);
+_SOKOL_PRIVATE void _sapp_x11_discard_backend(void);
+_SOKOL_PRIVATE bool _sapp_x11_create_window(_sapp_window_t* win, const sapp_window_desc* desc);
+_SOKOL_PRIVATE void _sapp_x11_destroy_window(_sapp_window_t* win);
+#endif
+
+/*=== POOL IMPLEMENTATION ====================================================*/
+_SOKOL_PRIVATE void _sapp_init_pool(_sapp_pool_t* pool, int num) {
+ SOKOL_ASSERT(pool && (num >= 1));
+ /* slot 0 is reserved for the 'invalid id', so bump the pool size by 1 */
+ pool->size = num + 1;
+ pool->queue_top = 0;
+ /* generation counters indexable by pool slot index, slot 0 is reserved */
+ pool->gen_ctrs = (uint32_t*) SOKOL_CALLOC((size_t)pool->size, sizeof(uint32_t));
+ SOKOL_ASSERT(pool->gen_ctrs);
+ /* it's not a bug to only reserve 'num' here */
+ pool->free_queue = (int*) SOKOL_CALLOC((size_t)num, sizeof(int));
+ SOKOL_ASSERT(pool->free_queue);
+ /* never allocate the zero-th pool item since the invalid id is 0 */
+ for (int i = pool->size-1; i >= 1; i--) {
+ pool->free_queue[pool->queue_top++] = i;
+ }
+}
+
+_SOKOL_PRIVATE void _sapp_discard_pool(_sapp_pool_t* pool) {
+ SOKOL_ASSERT(pool);
+ SOKOL_ASSERT(pool->free_queue);
+ SOKOL_FREE(pool->free_queue);
+ pool->free_queue = 0;
+ SOKOL_ASSERT(pool->gen_ctrs);
+ SOKOL_FREE(pool->gen_ctrs);
+ pool->gen_ctrs = 0;
+ pool->size = 0;
+ pool->queue_top = 0;
+}
+
+_SOKOL_PRIVATE int _sapp_pool_alloc_index(_sapp_pool_t* pool) {
+ SOKOL_ASSERT(pool);
+ SOKOL_ASSERT(pool->free_queue);
+ if (pool->queue_top > 0) {
+ int slot_index = pool->free_queue[--pool->queue_top];
+ SOKOL_ASSERT((slot_index > 0) && (slot_index < pool->size));
+ return slot_index;
+ }
+ else {
+ /* pool exhausted */
+ return _SAPP_INVALID_SLOT_INDEX;
+ }
+}
+
+_SOKOL_PRIVATE void _sapp_pool_free_index(_sapp_pool_t* pool, int slot_index) {
+ SOKOL_ASSERT((slot_index > _SAPP_INVALID_SLOT_INDEX) && (slot_index < pool->size));
+ SOKOL_ASSERT(pool);
+ SOKOL_ASSERT(pool->free_queue);
+ SOKOL_ASSERT(pool->queue_top < pool->size);
+ #ifdef SOKOL_DEBUG
+ /* debug check against double-free */
+ for (int i = 0; i < pool->queue_top; i++) {
+ SOKOL_ASSERT(pool->free_queue[i] != slot_index);
+ }
+ #endif
+ pool->free_queue[pool->queue_top++] = slot_index;
+ SOKOL_ASSERT(pool->queue_top <= (pool->size-1));
+}
+
+_SOKOL_PRIVATE void _sapp_reset_slot(_sapp_slot_t* slot) {
+ SOKOL_ASSERT(slot);
+ memset(slot, 0, sizeof(_sapp_slot_t));
+}
+
+/* allocate the slot at slot_index:
+ - bump the slot's generation counter
+ - create a resource id from the generation counter and slot index
+ - set the slot's id to this id
+ - set the slot's state to ALLOC
+ - return the resource id
+*/
+_SOKOL_PRIVATE uint32_t _sapp_slot_alloc(_sapp_pool_t* pool, _sapp_slot_t* slot, int slot_index) {
+ SOKOL_ASSERT(pool && pool->gen_ctrs);
+ SOKOL_ASSERT((slot_index > _SAPP_INVALID_SLOT_INDEX) && (slot_index < pool->size));
+ SOKOL_ASSERT(slot->id == SAPP_INVALID_ID);
+ uint32_t ctr = ++pool->gen_ctrs[slot_index];
+ slot->id = (ctr<<_SAPP_SLOT_SHIFT)|(slot_index & _SAPP_SLOT_MASK);
+ return slot->id;
+}
+
+_SOKOL_PRIVATE int _sapp_slot_index(uint32_t id) {
+ int slot_index = (int) (id & _SAPP_SLOT_MASK);
+ SOKOL_ASSERT(_SAPP_INVALID_SLOT_INDEX != slot_index);
+ return slot_index;
+}
+
+_SOKOL_PRIVATE void _sapp_setup_window_pool(_sapp_window_pool_t* window_pool, const sapp_desc* desc) {
+ SOKOL_ASSERT(window_pool);
+ SOKOL_ASSERT((desc->window_pool_size > 0) && (desc->window_pool_size < _SAPP_MAX_POOL_SIZE));
+ _sapp_init_pool(&window_pool->pool, desc->window_pool_size);
+ window_pool->windows = (_sapp_window_t*) SOKOL_CALLOC((size_t)window_pool->pool.size, sizeof(_sapp_window_t));
+ SOKOL_ASSERT(window_pool->windows);
+}
+
+_SOKOL_PRIVATE void _sapp_discard_window_pool(_sapp_window_pool_t* window_pool) {
+ SOKOL_ASSERT(window_pool);
+ SOKOL_ASSERT(window_pool->windows);
+ SOKOL_FREE(window_pool->windows); window_pool->windows = 0;
+ _sapp_discard_pool(&window_pool->pool);
+}
+
+/* returns pointer to window by id without matching id check */
+_SOKOL_PRIVATE _sapp_window_t* _sapp_window_at(const _sapp_window_pool_t* win_pool, uint32_t win_id) {
+ SOKOL_ASSERT(win_pool && (SAPP_INVALID_ID != win_id));
+ int slot_index = _sapp_slot_index(win_id);
+ SOKOL_ASSERT((slot_index > _SAPP_INVALID_SLOT_INDEX) && (slot_index < win_pool->pool.size));
+ return &win_pool->windows[slot_index];
+}
+
+/* returns pointer to window with matching id check, may return 0 */
+_SOKOL_PRIVATE _sapp_window_t* _sapp_lookup_window(const _sapp_window_pool_t* win_pool, uint32_t win_id) {
+ if (SAPP_INVALID_ID != win_id) {
+ _sapp_window_t* win = _sapp_window_at(win_pool, win_id);
+ if (win->slot.id == win_id) {
+ return win;
+ }
+ }
+ return 0;
+}
+
+_SOKOL_PRIVATE bool _sapp_create_window(_sapp_window_t* win, const sapp_window_desc* desc) {
+ #if defined(_SAPP_MACOS)
+ return _sapp_macos_create_window(win, desc);
+ #elif defined(_SAPP_IOS)
+ return _sapp_ios_create_window(win, desc);
+ #elif defined(_SAPP_EMSCRIPTEN)
+ return _sapp_emsc_create_window(win, desc);
+ #elif defined(_SAPP_WIN32)
+ return _sapp_win32_create_window(win, desc);
+ #elif defined(_SAPP_UWP)
+ return _sapp_uwp_create_window(win, desc);
+ #elif defined(_SAPP_ANDROID)
+ return _sapp_android_create_window(win, desc);
+ #elif defined(_SAPP_LINUX)
+ return _sapp_x11_create_window(win, desc);
+ #endif
+}
+
+_SOKOL_PRIVATE void _sapp_destroy_window(_sapp_window_t* win) {
+ #if defined(_SAPP_MACOS)
+ _sapp_macos_destroy_window(win);
+ #elif defined(_SAPP_IOS)
+ _sapp_ios_destroy_window(win);
+ #elif defined(_SAPP_EMSCRIPTEN)
+ _sapp_emsc_destroy_window(win);
+ #elif defined(_SAPP_WIN32)
+ _sapp_win32_destroy_window(win);
+ #elif defined(_SAPP_UWP)
+ _sapp_uwp_destroy_window(win);
+ #elif defined(_SAPP_ANDROID)
+ _sapp_android_destroy_window(win);
+ #elif defined(_SAPP_LINUX)
+ _sapp_x11_destroy_window(win);
+ #endif
+}
+
+_SOKOL_PRIVATE void _sapp_destroy_all_windows(_sapp_window_pool_t* win_pool) {
+ SOKOL_ASSERT(win_pool);
+ for (int i = 0; i < win_pool->pool.size; i++) {
+ uint32_t win_id = win_pool->windows[i].slot.id;
+ if (SAPP_INVALID_ID != win_id) {
+ _sapp_destroy_window(&win_pool->windows[i]);
+ }
+ }
+}
+
_SOKOL_PRIVATE void _sapp_fail(const char* msg) {
if (_sapp.desc.fail_cb) {
_sapp.desc.fail_cb(msg);
@@ -2482,8 +2708,45 @@ _SOKOL_PRIVATE sapp_window_desc _sapp_window_defaults(const sapp_window_desc* in
return desc;
}
+_SOKOL_PRIVATE void _sapp_init_backend(void) {
+ #if defined(_SAPP_MACOS)
+ _sapp_macos_init_backend();
+ #elif defined(_SAPP_IOS)
+ _sapp_ios_init_backend();
+ #elif defined(_SAPP_EMSCRIPTEN)
+ _sapp_emsc_init_backend();
+ #elif defined(_SAPP_WIN32)
+ _sapp_win32_init_backend();
+ #elif defined(_SAPP_UWP)
+ _sapp_uwp_init_backend();
+ #elif defined(_SAPP_ANDROID)
+ _sapp_android_init_backend();
+ #elif defined(_SAPP_LINUX)
+ _sapp_x11_init_backend();
+ #endif
+}
+
+_SOKOL_PRIVATE void _sapp_discard_backend(void) {
+ #if defined(_SAPP_MACOS)
+ _sapp_macos_discard_backend();
+ #elif defined(_SAPP_IOS)
+ _sapp_ios_discard_backend();
+ #elif defined(_SAPP_EMSCRIPTEN)
+ _sapp_emsc_discard_backend();
+ #elif defined(_SAPP_WIN32)
+ _sapp_win32_discard_backend();
+ #elif defined(_SAPP_UWP)
+ _sapp_uwp_discard_backend();
+ #elif defined(_SAPP_ANDROID)
+ _sapp_android_discard_backend();
+ #elif defined(_SAPP_LINUX)
+ _sapp_x11_discard_backend();
+ #endif
+}
+
_SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* in_desc) {
sapp_desc desc = *in_desc;
+ desc.window_pool_size = _sapp_def(desc.window_pool_size, _SAPP_DEFAULT_POOL_SIZE);
desc.window = _sapp_window_defaults(&desc.window);
desc.html5.canvas_name = _sapp_def(desc.html5.canvas_name, "canvas");
return desc;
@@ -2515,9 +2778,13 @@ _SOKOL_PRIVATE void _sapp_init_state(const sapp_desc* desc) {
_sapp.window.dpi_scale = 1.0f;
_sapp.window.fullscreen = _sapp.desc.window.fullscreen;
_sapp.window.mouse.shown = true;
+ _sapp_setup_window_pool(&_sapp.window_pool, desc);
+ _sapp_init_backend();
}
_SOKOL_PRIVATE void _sapp_discard_state(void) {
+ _sapp_destroy_all_windows(&_sapp.window_pool);
+ _sapp_discard_window_pool(&_sapp.window_pool);
if (_sapp.window.clipboard.enabled) {
SOKOL_ASSERT(_sapp.window.clipboard.buffer);
SOKOL_FREE((void*)_sapp.window.clipboard.buffer);
@@ -2529,6 +2796,7 @@ _SOKOL_PRIVATE void _sapp_discard_state(void) {
if (_sapp.default_icon_pixels) {
SOKOL_FREE((void*)_sapp.default_icon_pixels);
}
+ _sapp_discard_backend();
_SAPP_CLEAR(_sapp_t, _sapp);
}
@@ -2866,7 +3134,21 @@ _SOKOL_PRIVATE void _sapp_macos_init_keytable(void) {
_sapp.keycodes[0x4E] = SAPP_KEYCODE_KP_SUBTRACT;
}
-_SOKOL_PRIVATE void _sapp_macos_discard_state(void) {
+/* called from _sapp_init_state() */
+_SOKOL_PRIVATE void _sapp_macos_init_backend(void) {
+ _sapp_macos_init_keytable();
+ [NSApplication sharedApplication];
+ // set the application dock icon as early as possible, otherwise
+ // the dummy icon will be visible for a short time
+ sapp_set_icon(&_sapp.desc.icon);
+ NSApp.activationPolicy = NSApplicationActivationPolicyRegular;
+ _sapp.macos.app_delegate = [[_sapp_macos_app_delegate alloc] init];
+ NSApp.delegate = _sapp.macos.app_delegate;
+ [NSApp activateIgnoringOtherApps:YES];
+}
+
+/* called from _sapp_discard_state() */
+_SOKOL_PRIVATE void _sapp_macos_discard_backend(void) {
// NOTE: it's safe to call [release] on a nil object
_SAPP_OBJC_RELEASE(_sapp.macos.win.tracking_area);
_SAPP_OBJC_RELEASE(_sapp.macos.win.delegate);
@@ -2880,18 +3162,17 @@ _SOKOL_PRIVATE void _sapp_macos_discard_state(void) {
_SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) {
_sapp_init_state(desc);
- _sapp_macos_init_keytable();
- [NSApplication sharedApplication];
- // set the application dock icon as early as possible, otherwise
- // the dummy icon will be visible for a short time
- sapp_set_icon(&_sapp.desc.icon);
- NSApp.activationPolicy = NSApplicationActivationPolicyRegular;
- _sapp.macos.app_delegate = [[_sapp_macos_app_delegate alloc] init];
- NSApp.delegate = _sapp.macos.app_delegate;
- [NSApp activateIgnoringOtherApps:YES];
[NSApp run];
- // NOTE: [NSApp run] never returns, instead cleanup code
- // must be put into applicationWillTerminate
+ // NOTE: [NSApp run] never returns, cleanup code is in applicationWillTerminate instead
+}
+
+_SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win, const sapp_window_desc* desc) {
+ // FIXME
+ return false;
+}
+
+_SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* win) {
+ // FIXME
}
/* MacOS entry function */
@@ -3251,7 +3532,6 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) {
- (void)applicationWillTerminate:(NSNotification*)notification {
_SOKOL_UNUSED(notification);
_sapp_call_cleanup();
- _sapp_macos_discard_state();
_sapp_discard_state();
}
@end