diff options
| author | Andre Weissflog <floooh@gmail.com> | 2022-10-22 14:23:00 +0200 |
|---|---|---|
| committer | Andre Weissflog <floooh@gmail.com> | 2022-10-22 14:23:00 +0200 |
| commit | e4b2aad7f27929b6ca58777c4f6884a23b1b0fbb (patch) | |
| tree | 8717a18f409c9bdcc46a9b4d14a51d223143f472 | |
| parent | 2057da7e15367ba9cf1deee82f8660a19aefe154 (diff) | |
| parent | 3797da8c7f140f1406671a8ddcac1f7a2d4fc354 (diff) | |
Merge branch 'log-callback' of github.com:Manuzor/sokol into Manuzor-log-callback
| -rw-r--r-- | sokol_app.h | 206 | ||||
| -rw-r--r-- | sokol_args.h | 12 | ||||
| -rw-r--r-- | sokol_audio.h | 126 | ||||
| -rw-r--r-- | sokol_fetch.h | 99 | ||||
| -rw-r--r-- | sokol_gfx.h | 194 | ||||
| -rw-r--r-- | util/sokol_debugtext.h | 78 | ||||
| -rw-r--r-- | util/sokol_fontstash.h | 9 | ||||
| -rw-r--r-- | util/sokol_gl.h | 83 |
8 files changed, 585 insertions, 222 deletions
diff --git a/sokol_app.h b/sokol_app.h index 03c15be2..2759898c 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -28,7 +28,6 @@ Optionally provide the following defines with your own implementations: SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_LOG(msg) - your own logging function (default: puts(msg)) SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) SOKOL_ABORT() - called after an unrecoverable error (default: abort()) SOKOL_WIN32_FORCE_MAIN - define this on Win32 to use a main() entry point instead of WinMain @@ -204,7 +203,7 @@ The fail callback is called when a fatal error is encountered during start which doesn't allow the program to continue. Providing a callback here gives you a chance to show an error message - to the user. The default behaviour is SOKOL_LOG(msg) + to the user. The default behaviour is SAPP_LOG(msg) As you can see, those 'standard callbacks' don't have a user_data argument, so any data that needs to be preserved between callbacks @@ -1029,7 +1028,7 @@ .allocator = { .alloc = my_alloc, .free = my_free, - .user_data = ...; + .user_data = ..., } }; } @@ -1039,6 +1038,29 @@ This only affects memory allocation calls done by sokol_app.h itself though, not any allocations in OS libraries. + + LOG FUNCTION OVERRIDE + ===================== + You can override the log function at initialization time like this: + + void my_log(const char* message, void* user_data) { + printf("sapp says: \s\n", message); + } + + sapp_desc sokol_main(int argc, char* argv[]) { + return (sapp_desc){ + // ... + .logger = { + .log_cb = my_log, + .user_data = ..., + } + }; + } + + If no overrides are provided, puts will be used on most platforms. + On Android, __android_log_write will be used instead. + + TEMP NOTE DUMP ============== - onscreen keyboard support on Android requires Java :(, should we even bother? @@ -1442,6 +1464,17 @@ typedef struct sapp_allocator { void* user_data; } sapp_allocator; +/* + sapp_logger + + Used in sapp_desc to provide custom log callbacks to sokol_app.h. + Default behavior is SAPP_LOG_DEFAULT(message). +*/ +typedef struct sapp_logger { + void (*log_cb)(const char* message, void* user_data); + void* user_data; +} sapp_logger; + typedef struct sapp_desc { void (*init_cb)(void); // these are the user-provided callbacks without user data void (*frame_cb)(void); @@ -1471,6 +1504,7 @@ typedef struct sapp_desc { int max_dropped_file_path_length; // max length in bytes of a dropped UTF-8 file path (default: 2048) sapp_icon_desc icon; // the initial window icon to set sapp_allocator allocator; // optional memory allocation overrides (default: malloc/free) + sapp_logger logger; // optional log callback overrides (default: SAPP_LOG(message)) /* backend-specific options */ bool gl_force_gles2; // if true, setup GLES2/WebGL even if GLES3/WebGL2 is available @@ -1775,19 +1809,35 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #ifndef SOKOL_UNREACHABLE #define SOKOL_UNREACHABLE SOKOL_ASSERT(false) #endif -#ifndef SOKOL_LOG + +#if defined(SOKOL_LOG) +#error "SOKOL_LOG macro is no longer supported, please use sg_desc.logger to override log functions" +#endif +#ifndef SOKOL_NO_LOG #ifdef SOKOL_DEBUG + #define SOKOL_NO_LOG 0 + #else + #define SOKOL_NO_LOG 1 + #endif +#endif +#if !SOKOL_NO_LOG + #define SAPP_LOG(s) { SOKOL_ASSERT(s); _sapp_log(s); } + #ifndef SAPP_LOG_DEFAULT #if defined(__ANDROID__) #include <android/log.h> - #define SOKOL_LOG(s) { SOKOL_ASSERT(s); __android_log_write(ANDROID_LOG_INFO, "SOKOL_APP", s); } + #define SAPP_LOG_DEFAULT(s) __android_log_write(ANDROID_LOG_INFO, "SOKOL_APP", s) #else #include <stdio.h> - #define SOKOL_LOG(s) { SOKOL_ASSERT(s); puts(s); } + #define SAPP_LOG_DEFAULT(s) puts(s) #endif - #else - #define SOKOL_LOG(s) #endif +#else + #define SAPP_LOG(s) #endif +#ifndef SAPP_LOG_DEFAULT + #define SAPP_LOG_DEFAULT(s) +#endif + #ifndef SOKOL_ABORT #define SOKOL_ABORT() abort() #endif @@ -2737,6 +2787,18 @@ _SOKOL_PRIVATE void _sapp_free(void* ptr) { } } +#if !SOKOL_NO_LOG +_SOKOL_PRIVATE void _sapp_log(const char* msg) { + SOKOL_ASSERT(msg); + if (_sapp.desc.logger.log_cb) { + _sapp.desc.logger.log_cb(msg, _sapp.desc.logger.user_data); + } + else { + SAPP_LOG_DEFAULT(msg); + } +} +#endif + _SOKOL_PRIVATE void _sapp_fail(const char* msg) { if (_sapp.desc.fail_cb) { _sapp.desc.fail_cb(msg); @@ -2745,7 +2807,7 @@ _SOKOL_PRIVATE void _sapp_fail(const char* msg) { _sapp.desc.fail_userdata_cb(msg, _sapp.desc.user_data); } else { - SOKOL_LOG(msg); + SAPP_LOG(msg); } SOKOL_ABORT(); } @@ -2970,7 +3032,7 @@ _SOKOL_PRIVATE bool _sapp_image_validate(const sapp_image_desc* desc) { SOKOL_ASSERT(desc->pixels.size > 0); const size_t wh_size = (size_t)(desc->width * desc->height) * sizeof(uint32_t); if (wh_size != desc->pixels.size) { - SOKOL_LOG("Image data size mismatch (must be width*height*4 bytes)\n"); + SAPP_LOG("Image data size mismatch (must be width*height*4 bytes)\n"); return false; } return true; @@ -3795,7 +3857,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { for (int i = 0; i < _sapp.drop.num_files; i++) { NSURL *fileUrl = [NSURL fileURLWithPath:[pboard.pasteboardItems[(NSUInteger)i] stringForType:NSPasteboardTypeFileURL]]; if (!_sapp_strcpy(fileUrl.standardizedURL.path.UTF8String, _sapp_dropped_file_path_ptr(i), _sapp.drop.max_path_length)) { - SOKOL_LOG("sokol_app.h: dropped file path too long (sapp_desc.max_dropped_file_path_length)\n"); + SAPP_LOG("sokol_app.h: dropped file path too long (sapp_desc.max_dropped_file_path_length)\n"); drop_failed = true; break; } @@ -4494,7 +4556,7 @@ EMSCRIPTEN_KEEPALIVE void _sapp_emsc_drop(int i, const char* name) { return; } if (!_sapp_strcpy(name, _sapp_dropped_file_path_ptr(i), _sapp.drop.max_path_length)) { - SOKOL_LOG("sokol_app.h: dropped file path too long!\n"); + SAPP_LOG("sokol_app.h: dropped file path too long!\n"); _sapp.drop.num_files = 0; } } @@ -6104,7 +6166,7 @@ _SOKOL_PRIVATE void _sapp_d3d11_create_device_and_swapchain(void) { // === // // ...just retry with the DEBUG flag switched off - SOKOL_LOG("sokol_app.h: D3D11CreateDeviceAndSwapChain() with D3D11_CREATE_DEVICE_DEBUG failed, retrying without debug flag.\n"); + SAPP_LOG("sokol_app.h: D3D11CreateDeviceAndSwapChain() with D3D11_CREATE_DEVICE_DEBUG failed, retrying without debug flag.\n"); create_flags &= ~D3D11_CREATE_DEVICE_DEBUG; hr = D3D11CreateDeviceAndSwapChain( NULL, /* pAdapter (use default) */ @@ -6137,16 +6199,16 @@ _SOKOL_PRIVATE void _sapp_d3d11_create_device_and_swapchain(void) { _SAPP_SAFE_RELEASE(dxgi_factory); } else { - SOKOL_LOG("sokol_app.h: could not obtain IDXGIFactory object.\n"); + SAPP_LOG("sokol_app.h: could not obtain IDXGIFactory object.\n"); } _SAPP_SAFE_RELEASE(dxgi_adapter); } else { - SOKOL_LOG("sokol_app.h: could not obtain IDXGIAdapter object.\n"); + SAPP_LOG("sokol_app.h: could not obtain IDXGIAdapter object.\n"); } } else { - SOKOL_LOG("sokol_app.h: could not obtain IDXGIDevice1 interface\n"); + SAPP_LOG("sokol_app.h: could not obtain IDXGIDevice1 interface\n"); } } @@ -6695,7 +6757,7 @@ _SOKOL_PRIVATE void _sapp_win32_lock_mouse(bool lock) { _sapp.win32.hwnd // hwndTarget }; if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) { - SOKOL_LOG("RegisterRawInputDevices() failed (on mouse lock).\n"); + SAPP_LOG("RegisterRawInputDevices() failed (on mouse lock).\n"); } /* in case the raw mouse device only supports absolute position reporting, we need to skip the dx/dy compution for the first WM_INPUT event @@ -6706,7 +6768,7 @@ _SOKOL_PRIVATE void _sapp_win32_lock_mouse(bool lock) { /* disable raw input for mouse */ const RAWINPUTDEVICE rid = { 0x01, 0x02, RIDEV_REMOVE, NULL }; if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) { - SOKOL_LOG("RegisterRawInputDevices() failed (on mouse unlock).\n"); + SAPP_LOG("RegisterRawInputDevices() failed (on mouse unlock).\n"); } /* let the mouse roam freely again */ @@ -6846,7 +6908,7 @@ _SOKOL_PRIVATE void _sapp_win32_files_dropped(HDROP hdrop) { WCHAR* buffer = (WCHAR*) _sapp_malloc_clear(num_chars * sizeof(WCHAR)); DragQueryFileW(hdrop, i, buffer, num_chars); if (!_sapp_win32_wide_to_utf8(buffer, _sapp_dropped_file_path_ptr((int)i), _sapp.drop.max_path_length)) { - SOKOL_LOG("sokol_app.h: dropped file path too long (sapp_desc.max_dropped_file_path_length)\n"); + SAPP_LOG("sokol_app.h: dropped file path too long (sapp_desc.max_dropped_file_path_length)\n"); drop_failed = true; } _sapp_free(buffer); @@ -7022,7 +7084,7 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM UINT size = sizeof(_sapp.win32.raw_input_data); // see: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getrawinputdata if ((UINT)-1 == GetRawInputData(ri, RID_INPUT, &_sapp.win32.raw_input_data, &size, sizeof(RAWINPUTHEADER))) { - SOKOL_LOG("GetRawInputData() failed\n"); + SAPP_LOG("GetRawInputData() failed\n"); break; } const RAWINPUT* raw_mouse_data = (const RAWINPUT*) &_sapp.win32.raw_input_data; @@ -7373,7 +7435,7 @@ _SOKOL_PRIVATE const char* _sapp_win32_get_clipboard_string(void) { return _sapp.clipboard.buffer; } if (!_sapp_win32_wide_to_utf8(wchar_buf, _sapp.clipboard.buffer, _sapp.clipboard.buf_size)) { - SOKOL_LOG("sokol_app.h: clipboard string didn't fit into clipboard buffer\n"); + SAPP_LOG("sokol_app.h: clipboard string didn't fit into clipboard buffer\n"); } GlobalUnlock(object); CloseClipboard(); @@ -8726,16 +8788,16 @@ _SOKOL_PRIVATE void _sapp_android_cleanup_egl(void) { if (_sapp.android.display != EGL_NO_DISPLAY) { eglMakeCurrent(_sapp.android.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (_sapp.android.surface != EGL_NO_SURFACE) { - SOKOL_LOG("Destroying egl surface"); + SAPP_LOG("Destroying egl surface"); eglDestroySurface(_sapp.android.display, _sapp.android.surface); _sapp.android.surface = EGL_NO_SURFACE; } if (_sapp.android.context != EGL_NO_CONTEXT) { - SOKOL_LOG("Destroying egl context"); + SAPP_LOG("Destroying egl context"); eglDestroyContext(_sapp.android.display, _sapp.android.context); _sapp.android.context = EGL_NO_CONTEXT; } - SOKOL_LOG("Terminating egl display"); + SAPP_LOG("Terminating egl display"); eglTerminate(_sapp.android.display); _sapp.android.display = EGL_NO_DISPLAY; } @@ -8776,7 +8838,7 @@ _SOKOL_PRIVATE void _sapp_android_cleanup_egl_surface(void) { _SOKOL_PRIVATE void _sapp_android_app_event(sapp_event_type type) { if (_sapp_events_enabled()) { _sapp_init_event(type); - SOKOL_LOG("event_cb()"); + SAPP_LOG("event_cb()"); _sapp_call_event(&_sapp.event); } } @@ -8822,18 +8884,18 @@ _SOKOL_PRIVATE void _sapp_android_update_dimensions(ANativeWindow* window, bool _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float)_sapp.window_width; if (win_changed || fb_changed || force_update) { if (!_sapp.first_frame) { - SOKOL_LOG("SAPP_EVENTTYPE_RESIZED"); + SAPP_LOG("SAPP_EVENTTYPE_RESIZED"); _sapp_android_app_event(SAPP_EVENTTYPE_RESIZED); } } } _SOKOL_PRIVATE void _sapp_android_cleanup(void) { - SOKOL_LOG("Cleaning up"); + SAPP_LOG("Cleaning up"); if (_sapp.android.surface != EGL_NO_SURFACE) { /* egl context is bound, cleanup gracefully */ if (_sapp.init_called && !_sapp.cleanup_called) { - SOKOL_LOG("cleanup_cb()"); + SAPP_LOG("cleanup_cb()"); _sapp_call_cleanup(); } } @@ -8870,22 +8932,22 @@ _SOKOL_PRIVATE bool _sapp_android_touch_event(const AInputEvent* e) { sapp_event_type type = SAPP_EVENTTYPE_INVALID; switch (action) { case AMOTION_EVENT_ACTION_DOWN: - SOKOL_LOG("Touch: down"); + SAPP_LOG("Touch: down"); case AMOTION_EVENT_ACTION_POINTER_DOWN: - SOKOL_LOG("Touch: ptr down"); + SAPP_LOG("Touch: ptr down"); type = SAPP_EVENTTYPE_TOUCHES_BEGAN; break; case AMOTION_EVENT_ACTION_MOVE: type = SAPP_EVENTTYPE_TOUCHES_MOVED; break; case AMOTION_EVENT_ACTION_UP: - SOKOL_LOG("Touch: up"); + SAPP_LOG("Touch: up"); case AMOTION_EVENT_ACTION_POINTER_UP: - SOKOL_LOG("Touch: ptr up"); + SAPP_LOG("Touch: ptr up"); type = SAPP_EVENTTYPE_TOUCHES_ENDED; break; case AMOTION_EVENT_ACTION_CANCEL: - SOKOL_LOG("Touch: cancel"); + SAPP_LOG("Touch: cancel"); type = SAPP_EVENTTYPE_TOUCHES_CANCELLED; break; default: @@ -8936,7 +8998,7 @@ _SOKOL_PRIVATE int _sapp_android_input_cb(int fd, int events, void* data) { _SOKOL_UNUSED(fd); _SOKOL_UNUSED(data); if ((events & ALOOPER_EVENT_INPUT) == 0) { - SOKOL_LOG("_sapp_android_input_cb() encountered unsupported event"); + SAPP_LOG("_sapp_android_input_cb() encountered unsupported event"); return 1; } SOKOL_ASSERT(_sapp.android.current.input); @@ -8957,13 +9019,13 @@ _SOKOL_PRIVATE int _sapp_android_input_cb(int fd, int events, void* data) { _SOKOL_PRIVATE int _sapp_android_main_cb(int fd, int events, void* data) { _SOKOL_UNUSED(data); if ((events & ALOOPER_EVENT_INPUT) == 0) { - SOKOL_LOG("_sapp_android_main_cb() encountered unsupported event"); + SAPP_LOG("_sapp_android_main_cb() encountered unsupported event"); return 1; } _sapp_android_msg_t msg; if (read(fd, &msg, sizeof(msg)) != sizeof(msg)) { - SOKOL_LOG("Could not write to read_from_main_fd"); + SAPP_LOG("Could not write to read_from_main_fd"); return 1; } @@ -8971,7 +9033,7 @@ _SOKOL_PRIVATE int _sapp_android_main_cb(int fd, int events, void* data) { switch (msg) { case _SOKOL_ANDROID_MSG_CREATE: { - SOKOL_LOG("MSG_CREATE"); + SAPP_LOG("MSG_CREATE"); SOKOL_ASSERT(!_sapp.valid); bool result = _sapp_android_init_egl(); SOKOL_ASSERT(result); _SOKOL_UNUSED(result); @@ -8980,36 +9042,36 @@ _SOKOL_PRIVATE int _sapp_android_main_cb(int fd, int events, void* data) { } break; case _SOKOL_ANDROID_MSG_RESUME: - SOKOL_LOG("MSG_RESUME"); + SAPP_LOG("MSG_RESUME"); _sapp.android.has_resumed = true; _sapp_android_app_event(SAPP_EVENTTYPE_RESUMED); break; case _SOKOL_ANDROID_MSG_PAUSE: - SOKOL_LOG("MSG_PAUSE"); + SAPP_LOG("MSG_PAUSE"); _sapp.android.has_resumed = false; _sapp_android_app_event(SAPP_EVENTTYPE_SUSPENDED); break; case _SOKOL_ANDROID_MSG_FOCUS: - SOKOL_LOG("MSG_FOCUS"); + SAPP_LOG("MSG_FOCUS"); _sapp.android.has_focus = true; break; case _SOKOL_ANDROID_MSG_NO_FOCUS: - SOKOL_LOG("MSG_NO_FOCUS"); + SAPP_LOG("MSG_NO_FOCUS"); _sapp.android.has_focus = false; break; case _SOKOL_ANDROID_MSG_SET_NATIVE_WINDOW: - SOKOL_LOG("MSG_SET_NATIVE_WINDOW"); + SAPP_LOG("MSG_SET_NATIVE_WINDOW"); if (_sapp.android.current.window != _sapp.android.pending.window) { if (_sapp.android.current.window != NULL) { _sapp_android_cleanup_egl_surface(); } if (_sapp.android.pending.window != NULL) { - SOKOL_LOG("Creating egl surface ..."); + SAPP_LOG("Creating egl surface ..."); if (_sapp_android_init_egl_surface(_sapp.android.pending.window)) { - SOKOL_LOG("... ok!"); + SAPP_LOG("... ok!"); _sapp_android_update_dimensions(_sapp.android.pending.window, true); } else { - SOKOL_LOG("... failed!"); + SAPP_LOG("... failed!"); _sapp_android_shutdown(); } } @@ -9017,7 +9079,7 @@ _SOKOL_PRIVATE int _sapp_android_main_cb(int fd, int events, void* data) { _sapp.android.current.window = _sapp.android.pending.window; break; case _SOKOL_ANDROID_MSG_SET_INPUT_QUEUE: - SOKOL_LOG("MSG_SET_INPUT_QUEUE"); + SAPP_LOG("MSG_SET_INPUT_QUEUE"); if (_sapp.android.current.input != _sapp.android.pending.input) { if (_sapp.android.current.input != NULL) { AInputQueue_detachLooper(_sapp.android.current.input); @@ -9034,13 +9096,13 @@ _SOKOL_PRIVATE int _sapp_android_main_cb(int fd, int events, void* data) { _sapp.android.current.input = _sapp.android.pending.input; break; case _SOKOL_ANDROID_MSG_DESTROY: - SOKOL_LOG("MSG_DESTROY"); + SAPP_LOG("MSG_DESTROY"); _sapp_android_cleanup(); _sapp.valid = false; _sapp.android.is_thread_stopping = true; break; default: - SOKOL_LOG("Unknown msg type received"); + SAPP_LOG("Unknown msg type received"); break; } pthread_cond_broadcast(&_sapp.android.pt.cond); /* signal "received" */ @@ -9058,17 +9120,17 @@ _SOKOL_PRIVATE void _sapp_android_show_keyboard(bool shown) { SOKOL_ASSERT(_sapp.valid); /* This seems to be broken in the NDK, but there is (a very cumbersome) workaround... */ if (shown) { - SOKOL_LOG("Showing keyboard"); + SAPP_LOG("Showing keyboard"); ANativeActivity_showSoftInput(_sapp.android.activity, ANATIVEACTIVITY_SHOW_SOFT_INPUT_FORCED); } else { - SOKOL_LOG("Hiding keyboard"); + SAPP_LOG("Hiding keyboard"); ANativeActivity_hideSoftInput(_sapp.android.activity, ANATIVEACTIVITY_HIDE_SOFT_INPUT_NOT_ALWAYS); } } _SOKOL_PRIVATE void* _sapp_android_loop(void* arg) { _SOKOL_UNUSED(arg); - SOKOL_LOG("Loop thread started"); + SAPP_LOG("Loop thread started"); _sapp.android.looper = ALooper_prepare(0 /* or ALOOPER_PREPARE_ALLOW_NON_CALLBACKS*/); ALooper_addFd(_sapp.android.looper, @@ -9113,38 +9175,38 @@ _SOKOL_PRIVATE void* _sapp_android_loop(void* arg) { _sapp.android.is_thread_stopped = true; pthread_cond_broadcast(&_sapp.android.pt.cond); pthread_mutex_unlock(&_sapp.android.pt.mutex); - SOKOL_LOG("Loop thread done"); + SAPP_LOG("Loop thread done"); return NULL; } /* android main/ui thread */ _SOKOL_PRIVATE void _sapp_android_msg(_sapp_android_msg_t msg) { if (write(_sapp.android.pt.write_from_main_fd, &msg, sizeof(msg)) != sizeof(msg)) { - SOKOL_LOG("Could not write to write_from_main_fd"); + SAPP_LOG("Could not write to write_from_main_fd"); } } _SOKOL_PRIVATE void _sapp_android_on_start(ANativeActivity* activity) { _SOKOL_UNUSED(activity); - SOKOL_LOG("NativeActivity onStart()"); + SAPP_LOG("NativeActivity onStart()"); } _SOKOL_PRIVATE void _sapp_android_on_resume(ANativeActivity* activity) { _SOKOL_UNUSED(activity); - SOKOL_LOG("NativeActivity onResume()"); + SAPP_LOG("NativeActivity onResume()"); _sapp_android_msg(_SOKOL_ANDROID_MSG_RESUME); } _SOKOL_PRIVATE void* _sapp_android_on_save_instance_state(ANativeActivity* activity, size_t* out_size) { _SOKOL_UNUSED(activity); - SOKOL_LOG("NativeActivity onSaveInstanceState()"); + SAPP_LOG("NativeActivity onSaveInstanceState()"); *out_size = 0; return NULL; } _SOKOL_PRIVATE void _sapp_android_on_window_focus_changed(ANativeActivity* activity, int has_focus) { _SOKOL_UNUSED(activity); - SOKOL_LOG("NativeActivity onWindowFocusChanged()"); + SAPP_LOG("NativeActivity onWindowFocusChanged()"); if (has_focus) { _sapp_android_msg(_SOKOL_ANDROID_MSG_FOCUS); } else { @@ -9154,13 +9216,13 @@ _SOKOL_PRIVATE void _sapp_android_on_window_focus_changed(ANativeActivity* activ _SOKOL_PRIVATE void _sapp_android_on_pause(ANativeActivity* activity) { _SOKOL_UNUSED(activity); - SOKOL_LOG("NativeActivity onPause()"); + SAPP_LOG("NativeActivity onPause()"); _sapp_android_msg(_SOKOL_ANDROID_MSG_PAUSE); } _SOKOL_PRIVATE void _sapp_android_on_stop(ANativeActivity* activity) { _SOKOL_UNUSED(activity); - SOKOL_LOG("NativeActivity onStop()"); + SAPP_LOG("NativeActivity onStop()"); } _SOKOL_PRIVATE void _sapp_android_msg_set_native_window(ANativeWindow* window) { @@ -9175,14 +9237,14 @@ _SOKOL_PRIVATE void _sapp_android_msg_set_native_window(ANativeWindow* window) { _SOKOL_PRIVATE void _sapp_android_on_native_window_created(ANativeActivity* activity, ANativeWindow* window) { _SOKOL_UNUSED(activity); - SOKOL_LOG("NativeActivity onNativeWindowCreated()"); + SAPP_LOG("NativeActivity onNativeWindowCreated()"); _sapp_android_msg_set_native_window(window); } _SOKOL_PRIVATE void _sapp_android_on_native_window_destroyed(ANativeActivity* activity, ANativeWindow* window) { _SOKOL_UNUSED(activity); _SOKOL_UNUSED(window); - SOKOL_LOG("NativeActivity onNativeWindowDestroyed()"); + SAPP_LOG("NativeActivity onNativeWindowDestroyed()"); _sapp_android_msg_set_native_window(NULL); } @@ -9198,26 +9260,26 @@ _SOKOL_PRIVATE void _sapp_android_msg_set_input_queue(AInputQueue* input) { _SOKOL_PRIVATE void _sapp_android_on_input_queue_created(ANativeActivity* activity, AInputQueue* queue) { _SOKOL_UNUSED(activity); - SOKOL_LOG("NativeActivity onInputQueueCreated()"); + SAPP_LOG("NativeActivity onInputQueueCreated()"); _sapp_android_msg_set_input_queue(queue); } _SOKOL_PRIVATE void _sapp_android_on_input_queue_destroyed(ANativeActivity* activity, AInputQueue* queue) { _SOKOL_UNUSED(activity); _SOKOL_UNUSED(queue); - SOKOL_LOG("NativeActivity onInputQueueDestroyed()"); + SAPP_LOG("NativeActivity onInputQueueDestroyed()"); _sapp_android_msg_set_input_queue(NULL); } _SOKOL_PRIVATE void _sapp_android_on_config_changed(ANativeActivity* activity) { _SOKOL_UNUSED(activity); - SOKOL_LOG("NativeActivity onConfigurationChanged()"); + SAPP_LOG("NativeActivity onConfigurationChanged()"); /* see android:configChanges in manifest */ } _SOKOL_PRIVATE void _sapp_android_on_low_memory(ANativeActivity* activity) { _SOKOL_UNUSED(activity); - SOKOL_LOG("NativeActivity onLowMemory()"); + SAPP_LOG("NativeActivity onLowMemory()"); } _SOKOL_PRIVATE void _sapp_android_on_destroy(ANativeActivity* activity) { @@ -9230,7 +9292,7 @@ _SOKOL_PRIVATE void _sapp_android_on_destroy(ANativeActivity* activity) { * _sapp_android_on_stop(), the crash disappears. Is this a bug in NativeActivity? */ _SOKOL_UNUSED(activity); - SOKOL_LOG("NativeActivity onDestroy()"); + SAPP_LOG("NativeActivity onDestroy()"); /* send destroy msg */ pthread_mutex_lock(&_sapp.android.pt.mutex); @@ -9247,7 +9309,7 @@ _SOKOL_PRIVATE void _sapp_android_on_destroy(ANativeActivity* activity) { close(_sapp.android.pt.read_from_main_fd); close(_sapp.android.pt.write_from_main_fd); - SOKOL_LOG("NativeActivity done"); + SAPP_LOG("NativeActivity done"); /* this is a bit naughty, but causes a clean restart of the app (static globals are reset) */ exit(0); @@ -9257,7 +9319,7 @@ JNIEXPORT void ANativeActivity_onCreate(ANativeActivity* activity, void* saved_state, size_t saved_state_size) { _SOKOL_UNUSED(saved_state); _SOKOL_UNUSED(saved_state_size); - SOKOL_LOG("NativeActivity onCreate()"); + SAPP_LOG("NativeActivity onCreate()"); // the NativeActity pointer needs to be available inside sokol_main() // (see https://github.com/floooh/sokol/issues/708), however _sapp_init_state() @@ -9271,7 +9333,7 @@ void ANativeActivity_onCreate(ANativeActivity* activity, void* saved_state, size int pipe_fd[2]; if (pipe(pipe_fd) != 0) { - SOKOL_LOG("Could not create thread pipe"); + SAPP_LOG("Could not create thread pipe"); return; } _sapp.android.pt.read_from_main_fd = pipe_fd[0]; @@ -9319,7 +9381,7 @@ void ANativeActivity_onCreate(ANativeActivity* activity, void* saved_state, size activity->callbacks->onConfigurationChanged = _sapp_android_on_config_changed; activity->callbacks->onLowMemory = _sapp_android_on_low_memory; - SOKOL_LOG("NativeActivity successfully created"); + SAPP_LOG("NativeActivity successfully created"); /* NOT A BUG: do NOT call sapp_discard_state() */ } @@ -11187,7 +11249,7 @@ _SOKOL_PRIVATE bool _sapp_x11_parse_dropped_files_list(const char* src) { ((src_count == 6) && (src_chr != '/')) || ((src_count == 7) && (src_chr != '/'))) { - SOKOL_LOG("sokol_app.h: dropped file URI doesn't start with file://"); + SAPP_LOG("sokol_app.h: dropped file URI doesn't start with file://"); err = true; break; } @@ -11220,7 +11282,7 @@ _SOKOL_PRIVATE bool _sapp_x11_parse_dropped_files_list(const char* src) { *dst_ptr++ = dst_chr; } else { - SOKOL_LOG("sokol_app.h: dropped file path too long (sapp_desc.max_dropped_file_path_length)"); + SAPP_LOG("sokol_app.h: dropped file path too long (sapp_desc.max_dropped_file_path_length)"); err = true; break; } diff --git a/sokol_args.h b/sokol_args.h index 352b4897..e6bfc983 100644 --- a/sokol_args.h +++ b/sokol_args.h @@ -16,7 +16,6 @@ Optionally provide the following defines with your own implementations: SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_LOG(msg) - your own logging functions (default: puts(msg)) SOKOL_ARGS_API_DECL - public function declaration prefix (default: extern) SOKOL_API_DECL - same as SOKOL_ARGS_API_DECL SOKOL_API_IMPL - public function implementation prefix (default: -) @@ -236,7 +235,7 @@ .allocator = { .alloc = my_alloc, .free = my_free, - .user_data = ...; + .user_data = ..., } }); ... @@ -246,7 +245,6 @@ This only affects memory allocation calls done by sokol_args.h itself though, not any allocations in OS libraries. - TODO ==== - parsing errors? @@ -382,14 +380,6 @@ inline void sargs_setup(const sargs_desc& desc) { return sargs_setup(&desc); } #include <assert.h> #define SOKOL_ASSERT(c) assert(c) #endif -#ifndef SOKOL_LOG - #ifdef SOKOL_DEBUG - #include <stdio.h> - #define SOKOL_LOG(s) { SOKOL_ASSERT(s); puts(s); } - #else - #define SOKOL_LOG(s) - #endif -#endif #ifndef _SOKOL_PRIVATE #if defined(__GNUC__) || defined(__clang__) diff --git a/sokol_audio.h b/sokol_audio.h index 4686425a..eed1e311 100644 --- a/sokol_audio.h +++ b/sokol_audio.h @@ -17,7 +17,6 @@ SOKOL_DUMMY_BACKEND - use a dummy backend SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_LOG(msg) - your own logging function (default: puts(msg)) SOKOL_AUDIO_API_DECL- public function declaration prefix (default: extern) SOKOL_API_DECL - same as SOKOL_AUDIO_API_DECL SOKOL_API_IMPL - public function implementation prefix (default: -) @@ -383,7 +382,7 @@ .allocator = { .alloc = my_alloc, .free = my_free, - .user_data = ...; + .user_data = ..., } }); ... @@ -397,6 +396,28 @@ was called, so you don't need to worry about thread-safety. + LOG FUNCTION OVERRIDE + ===================== + You can override the log function at initialization time like this: + + void my_log(const char* message, void* user_data) { + printf("saudio says: \s\n", message); + } + + ... + saudio_setup(&(saudio_desc){ + // ... + .logger = { + .log_cb = my_log, + .user_data = ..., + } + }); + ... + + If no overrides are provided, puts will be used on most platforms. + On Android, __android_log_write will be used instead. + + LICENSE ======= @@ -459,6 +480,17 @@ typedef struct saudio_allocator { void* user_data; } saudio_allocator; +/* + saudio_logger + + Used in saudio_desc to provide custom log callbacks to sokol_audio.h. + Default behavior is SAUDIO_LOG_DEFAULT(message). +*/ +typedef struct saudio_logger { + void (*log_cb)(const char* message, void* user_data); + void* user_data; +} saudio_logger; + typedef struct saudio_desc { int sample_rate; // requested sample rate int num_channels; // number of channels, default: 1 (mono) @@ -469,6 +501,7 @@ typedef struct saudio_desc { void (*stream_userdata_cb)(float* buffer, int num_frames, int num_channels, void* user_data); //... and with user data void* user_data; // optional user data argument for stream_userdata_cb saudio_allocator allocator; // optional allocation override functions + saudio_logger logger; // optional log override functions } saudio_desc; /* setup sokol-audio */ @@ -527,14 +560,34 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc); #include <assert.h> #define SOKOL_ASSERT(c) assert(c) #endif -#ifndef SOKOL_LOG + +#if defined(SOKOL_LOG) +#error "SOKOL_LOG macro is no longer supported, please use saudio_desc.logger to override log functions" +#endif +#ifndef SOKOL_NO_LOG #ifdef SOKOL_DEBUG - #include <stdio.h> - #define SOKOL_LOG(s) { SOKOL_ASSERT(s); puts(s); } + #define SOKOL_NO_LOG 0 #else - #define SOKOL_LOG(s) + #define SOKOL_NO_LOG 1 #endif #endif +#if !SOKOL_NO_LOG + #define SAUDIO_LOG(s) { SOKOL_ASSERT(s); _saudio_log(s); } + #ifndef SAUDIO_LOG_DEFAULT + #if defined(__ANDROID__) + #include <android/log.h> + #define SAUDIO_LOG_DEFAULT(s) __android_log_write(ANDROID_LOG_INFO, "SOKOL_AUDIO", s) + #else + #include <stdio.h> + #define SAUDIO_LOG_DEFAULT(s) puts(s) + #endif + #endif +#else + #define SAUDIO_LOG(s) +#endif +#ifndef SAUDIO_LOG_DEFAULT + #define SAUDIO_LOG_DEFAULT(s) +#endif #ifndef _SOKOL_PRIVATE #if defined(__GNUC__) || defined(__clang__) @@ -984,6 +1037,17 @@ _SOKOL_PRIVATE void _saudio_free(void* ptr) { } } +#if !SOKOL_NO_LOG +_SOKOL_PRIVATE void _saudio_log(const char* msg) { + SOKOL_ASSERT(msg); + if (_saudio.desc.logger.log_cb) { + _saudio.desc.logger.log_cb(msg, _saudio.desc.logger.user_data); + } else { + SAUDIO_LOG_DEFAULT(msg); + } +} +#endif + /*=== MUTEX IMPLEMENTATION ===================================================*/ #if defined(_SAUDIO_NOTHREADS) @@ -1386,7 +1450,7 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) { int dir; uint32_t rate; int rc = snd_pcm_open(&_saudio.backend.device, "default", SND_PCM_STREAM_PLAYBACK, 0); if (rc < 0) { - SOKOL_LOG("sokol_audio.h: snd_pcm_open() failed"); + SAUDIO_LOG("sokol_audio.h: snd_pcm_open() failed"); return false; } @@ -1399,26 +1463,26 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) { snd_pcm_hw_params_any(_saudio.backend.device, params); snd_pcm_hw_params_set_access(_saudio.backend.device, params, SND_PCM_ACCESS_RW_INTERLEAVED); if (0 > snd_pcm_hw_params_set_format(_saudio.backend.device, params, SND_PCM_FORMAT_FLOAT_LE)) { - SOKOL_LOG("sokol_audio.h: float samples not supported"); + SAUDIO_LOG("sokol_audio.h: float samples not supported"); goto error; } if (0 > snd_pcm_hw_params_set_buffer_size(_saudio.backend.device, params, (snd_pcm_uframes_t)_saudio.buffer_frames)) { - SOKOL_LOG("sokol_audio.h: requested buffer size not supported"); + SAUDIO_LOG("sokol_audio.h: requested buffer size not supported"); goto error; } if (0 > snd_pcm_hw_params_set_channels(_saudio.backend.device, params, (uint32_t)_saudio.num_channels)) { - SOKOL_LOG("sokol_audio.h: requested channel count not supported"); + SAUDIO_LOG("sokol_audio.h: requested channel count not supported"); goto error; } /* let ALSA pick a nearby sampling rate */ rate = (uint32_t) _saudio.sample_rate; dir = 0; if (0 > snd_pcm_hw_params_set_rate_near(_saudio.backend.device, params, &rate, &dir)) { - SOKOL_LOG("sokol_audio.h: snd_pcm_hw_params_set_rate_near() failed"); + SAUDIO_LOG("sokol_audio.h: snd_pcm_hw_params_set_rate_near() failed"); goto error; } if (0 > snd_pcm_hw_params(_saudio.backend.device, params)) { - SOKOL_LOG("sokol_audio.h: snd_pcm_hw_params() failed"); + SAUDIO_LOG("sokol_audio.h: snd_pcm_hw_params() failed"); goto error; } @@ -1433,7 +1497,7 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) { /* create the buffer-streaming start thread */ if (0 != pthread_create(&_saudio.backend.thread, 0, _saudio_alsa_cb, 0)) { - SOKOL_LOG("sokol_audio.h: pthread_create() failed"); + SAUDIO_LOG("sokol_audio.h: pthread_create() failed"); goto error; } @@ -1626,17 +1690,17 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) { #endif _saudio.backend.thread.buffer_end_event = CreateEvent(0, FALSE, FALSE, 0); if (0 == _saudio.backend.thread.buffer_end_event) { - SOKOL_LOG("sokol_audio wasapi: failed to create buffer_end_event"); + SAUDIO_LOG("sokol_audio wasapi: failed to create buffer_end_event"); goto error; } #if defined(_SAUDIO_UWP) _saudio.backend.interface_activation_mutex = CreateMutexA(NULL, FALSE, "interface_activation_mutex"); if (_saudio.backend.interface_activation_mutex == NULL) { - SOKOL_LOG("sokol_audio wasapi: failed to create interface activation mutex"); + SAUDIO_LOG("sokol_audio wasapi: failed to create interface activation mutex"); goto error; } if (FAILED(StringFromIID(_SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_Devinterface_Audio_Render), &_saudio.backend.interface_activation_audio_interface_uid_string))) { - SOKOL_LOG("sokol_audio wasapi: failed to get default audio device ID string"); + SAUDIO_LOG("sokol_audio wasapi: failed to get default audio device ID string"); goto error; } @@ -1650,7 +1714,7 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) { static IActivateAudioInterfaceCompletionHandler completion_handler_interface = { &completion_handler_interface_vtable }; if (FAILED(ActivateAudioInterfaceAsync(_saudio.backend.interface_activation_audio_interface_uid_string, _SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IAudioClient), NULL, &completion_handler_interface, &_saudio.backend.interface_activation_operation))) { - SOKOL_LOG("sokol_audio wasapi: failed to get default audio device ID string"); + SAUDIO_LOG("sokol_audio wasapi: failed to get default audio device ID string"); goto error; } while (!(_saudio.backend.audio_client)) { @@ -1660,7 +1724,7 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) { } if (!(_saudio.backend.interface_activation_success)) { - SOKOL_LOG("sokol_audio wasapi: interface activation failed. Unable to get audio client"); + SAUDIO_LOG("sokol_audio wasapi: interface activation failed. Unable to get audio client"); goto error; } @@ -1670,14 +1734,14 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) { _SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IMMDeviceEnumerator), (void**)&_saudio.backend.device_enumerator))) { - SOKOL_LOG("sokol_audio wasapi: failed to create device enumerator"); + SAUDIO_LOG("sokol_audio wasapi: failed to create device enumerator"); goto error; } if (FAILED(IMMDeviceEnumerator_GetDefaultAudioEndpoint(_saudio.backend.device_enumerator, eRender, eConsole, &_saudio.backend.device))) { - SOKOL_LOG("sokol_audio wasapi: GetDefaultAudioEndPoint failed"); + SAUDIO_LOG("sokol_audio wasapi: GetDefaultAudioEndPoint failed"); goto error; } if (FAILED(IMMDevice_Activate(_saudio.backend.device, @@ -1685,7 +1749,7 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) { CLSCTX_ALL, 0, (void**)&_saudio.backend.audio_client))) { - SOKOL_LOG("sokol_audio wasapi: device activate failed"); + SAUDIO_LOG("sokol_audio wasapi: device activate failed"); goto error; } #endif @@ -1714,22 +1778,22 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) { AUDCLNT_STREAMFLAGS_EVENTCALLBACK|AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM|AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY, dur, 0, (WAVEFORMATEX*)&fmtex, 0))) { - SOKOL_LOG("sokol_audio wasapi: audio client initialize failed"); + SAUDIO_LOG("sokol_audio wasapi: audio client initialize failed"); goto error; } if (FAILED(IAudioClient_GetBufferSize(_saudio.backend.audio_client, &_saudio.backend.thread.dst_buffer_frames))) { - SOKOL_LOG("sokol_audio wasapi: audio client get buffer size failed"); + SAUDIO_LOG("sokol_audio wasapi: audio client get buffer size failed"); goto error; } if (FAILED(IAudioClient_GetService(_saudio.backend.audio_client, _SOKOL_AUDIO_WIN32COM_ID(_saudio_IID_IAudioRenderClient), (void**)&_saudio.backend.render_client))) { - SOKOL_LOG("sokol_audio wasapi: audio client GetService failed"); + SAUDIO_LOG("sokol_audio wasapi: audio client GetService failed"); goto error; } if (FAILED(IAudioClient_SetEventHandle(_saudio.backend.audio_client, _saudio.backend.thread.buffer_end_event))) { - SOKOL_LOG("sokol_audio wasapi: audio client SetEventHandle failed"); + SAUDIO_LOG("sokol_audio wasapi: audio client SetEventHandle failed"); goto error; } _saudio.bytes_per_frame = _saudio.num_channels * (int)sizeof(float); @@ -1742,7 +1806,7 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) { /* create streaming thread */ _saudio.backend.thread.thread_handle = CreateThread(NULL, 0, _saudio_wasapi_thread_fn, 0, 0, 0); if (0 == _saudio.backend.thread.thread_handle) { - SOKOL_LOG("sokol_audio wasapi: CreateThread failed"); + SAUDIO_LOG("sokol_audio wasapi: CreateThread failed"); goto error; } return true; @@ -2065,14 +2129,14 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) { /* Create engine */ const SLEngineOption opts[] = { { SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE } }; if (slCreateEngine(&_saudio.backend.engine_obj, 1, opts, 0, NULL, NULL ) != SL_RESULT_SUCCESS) { - SOKOL_LOG("sokol_audio opensles: slCreateEngine failed"); + SAUDIO_LOG("sokol_audio opensles: slCreateEngine failed"); _saudio_backend_shutdown(); return false; } (*_saudio.backend.engine_obj)->Realize(_saudio.backend.engine_obj, SL_BOOLEAN_FALSE); if ((*_saudio.backend.engine_obj)->GetInterface(_saudio.backend.engine_obj, SL_IID_ENGINE, &_saudio.backend.engine) != SL_RESULT_SUCCESS) { - SOKOL_LOG("sokol_audio opensles: GetInterface->Engine failed"); + SAUDIO_LOG("sokol_audio opensles: GetInterface->Engine failed"); _saudio_backend_shutdown(); return false; } @@ -2084,14 +2148,14 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) { if( (*_saudio.backend.engine)->CreateOutputMix(_saudio.backend.engine, &_saudio.backend.output_mix_obj, 1, ids, req) != SL_RESULT_SUCCESS) { - SOKOL_LOG("sokol_audio opensles: CreateOutputMix failed"); + SAUDIO_LOG("sokol_audio opensles: CreateOutputMix failed"); _saudio_backend_shutdown(); return false; } (*_saudio.backend.output_mix_obj)->Realize(_saudio.backend.output_mix_obj, SL_BOOLEAN_FALSE); if((*_saudio.backend.output_mix_obj)->GetInterface(_saudio.backend.output_mix_obj, SL_IID_VOLUME, &_saudio.backend.output_mix_vol) != SL_RESULT_SUCCESS) { - SOKOL_LOG("sokol_audio opensles: GetInterface->OutputMixVol failed"); + SAUDIO_LOG("sokol_audio opensles: GetInterface->OutputMixVol failed"); } } @@ -2190,7 +2254,7 @@ SOKOL_API_IMPL void saudio_setup(const saudio_desc* desc) { the requested packet size */ if (0 != (_saudio.buffer_frames % _saudio.packet_frames)) { - SOKOL_LOG("sokol_audio.h: actual backend buffer size isn't multiple of requested packet size"); + SAUDIO_LOG("sokol_audio.h: actual backend buffer size isn't multiple of requested packet size"); _saudio_backend_shutdown(); return; } diff --git a/sokol_fetch.h b/sokol_fetch.h index 07af0c27..0c2e12e6 100644 --- a/sokol_fetch.h +++ b/sokol_fetch.h @@ -16,7 +16,6 @@ Optionally provide the following defines with your own implementations: SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_LOG(msg) - your own logging function (default: puts(msg)) SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) SOKOL_FETCH_API_DECL - public function declaration prefix (default: extern) SOKOL_API_DECL - same as SOKOL_FETCH_API_DECL @@ -810,7 +809,7 @@ .allocator = { .alloc = my_alloc, .free = my_free, - .user_data = ...; + .user_data = ..., } }); ... @@ -824,6 +823,28 @@ was called, so you don't need to worry about thread-safety. + LOG FUNCTION OVERRIDE + ===================== + You can override the log function at initialization time like this: + + void my_log(const char* message, void* user_data) { + printf("sfetch says: \s\n", message); + } + + ... + sfetch_setup(&(sfetch_desc_t){ + // ... + .logger = { + .log_cb = my_log, + .user_data = ..., + } + }); + ... + + If no overrides are provided, puts will be used on most platforms. + On Android, __android_log_write will be used instead. + + FUTURE PLANS / V2.0 IDEA DUMP ============================= - An optional polling API (as alternative to callback API) @@ -903,6 +924,16 @@ typedef struct sfetch_allocator_t { void* user_data; } sfetch_allocator_t; +/* + sfetch_logger_t + + Used in sfetch_desc_t to provide custom log callbacks to sokol_fetch.h. + Default behavior is SFETCH_LOG_DEFAULT(message). +*/ +typedef struct sfetch_logger_t { + void (*log_cb)(const char* message, void* user_data); + void* user_data; +} sfetch_logger_t; /* configuration values for sfetch_setup() */ typedef struct sfetch_desc_t { @@ -910,6 +941,7 @@ typedef struct sfetch_desc_t { uint32_t num_channels; /* number of channels to fetch requests in parallel (default: 1) */ uint32_t num_lanes; /* max number of requests active on the same channel (default: 1) */ sfetch_allocator_t allocator; /* optional memory allocation overrides (default: malloc/free) */ + sfetch_logger_t logger; /* optional log function overrides (default: SFETCH_LOG_DEFAULT(message)) */ } sfetch_desc_t; /* a request handle to identify an active fetch request, returned by sfetch_send() */ @@ -1035,13 +1067,33 @@ inline sfetch_handle_t sfetch_send(const sfetch_request_t& request) { return sfe #include <assert.h> #define SOKOL_ASSERT(c) assert(c) #endif -#ifndef SOKOL_LOG + +#if defined(SOKOL_LOG) +#error "SOKOL_LOG macro is no longer supported, please use sfetch_desc.logger to override log functions" +#endif +#ifndef SOKOL_NO_LOG #ifdef SOKOL_DEBUG - #include <stdio.h> - #define SOKOL_LOG(s) { SOKOL_ASSERT(s); puts(s); } + #define SOKOL_NO_LOG 0 #else - #define SOKOL_LOG(s) + #define SOKOL_NO_LOG 1 + #endif +#endif +#if !SOKOL_NO_LOG + #define SFETCH_LOG(s) { SOKOL_ASSERT(s); _sfetch_log(s); } + #ifndef SFETCH_LOG_DEFAULT + #if defined(__ANDROID__) + #include <android/log.h> + #define SFETCH_LOG_DEFAULT(s) __android_log_write(ANDROID_LOG_INFO, "SOKOL_FETCH", s) + #else + #include <stdio.h> + #define SFETCH_LOG_DEFAULT(s) puts(s) + #endif #endif +#else + #define SFETCH_LOG(s) +#endif +#ifndef SFETCH_LOG_DEFAULT + #define SFETCH_LOG_DEFAULT(s) #endif #ifndef _SOKOL_PRIVATE @@ -1288,6 +1340,17 @@ _SOKOL_PRIVATE void _sfetch_free(void* ptr) { } } +#if !SOKOL_NO_LOG +_SOKOL_PRIVATE void _sfetch_log(const char* msg) { + if (_sfetch->desc.logger.log_cb) { + _sfetch->desc.logger.log_cb(msg, _sfetch->desc.logger.user_data); + } + else { + SFETCH_LOG_DEFAULT(msg); + } +} +#endif + _SOKOL_PRIVATE _sfetch_t* _sfetch_ctx(void) { return _sfetch; } @@ -1716,7 +1779,7 @@ _SOKOL_PRIVATE bool _sfetch_win32_utf8_to_wide(const char* src, wchar_t* dst, in _SOKOL_PRIVATE _sfetch_file_handle_t _sfetch_file_open(const _sfetch_path_t* path) { wchar_t w_path[SFETCH_MAX_PATH]; if (!_sfetch_win32_utf8_to_wide(path->buf, w_path, sizeof(w_path))) { - SOKOL_LOG("_sfetch_file_open: error converting UTF-8 path to wide string"); + SFETCH_LOG("_sfetch_file_open: error converting UTF-8 path to wide string"); return 0; } _sfetch_file_handle_t h = CreateFileW( @@ -2234,7 +2297,7 @@ _SOKOL_PRIVATE bool _sfetch_channel_send(_sfetch_channel_t* chn, uint32_t slot_i return true; } else { - SOKOL_LOG("sfetch_send: user_sent queue is full)"); + SFETCH_LOG("sfetch_send: user_sent queue is full)"); return false; } } @@ -2379,35 +2442,35 @@ _SOKOL_PRIVATE void _sfetch_channel_dowork(_sfetch_channel_t* chn, _sfetch_pool_ _SOKOL_PRIVATE bool _sfetch_validate_request(_sfetch_t* ctx, const sfetch_request_t* req) { #if defined(SOKOL_DEBUG) if (req->channel >= ctx->desc.num_channels) { - SOKOL_LOG("_sfetch_validate_request: request.channel too big!"); + SFETCH_LOG("_sfetch_validate_request: request.channel too big!"); return false; } if (!req->path) { - SOKOL_LOG("_sfetch_validate_request: request.path is null!"); + SFETCH_LOG("_sfetch_validate_request: request.path is null!"); return false; } if (strlen(req->path) >= (SFETCH_MAX_PATH-1)) { - SOKOL_LOG("_sfetch_validate_request: request.path is too long (must be < SFETCH_MAX_PATH-1)"); + SFETCH_LOG("_sfetch_validate_request: request.path is too long (must be < SFETCH_MAX_PATH-1)"); return false; } if (!req->callback) { - SOKOL_LOG("_sfetch_validate_request: request.callback missing"); + SFETCH_LOG("_sfetch_validate_request: request.callback missing"); return false; } if (req->chunk_size > req->buffer_size) { - SOKOL_LOG("_sfetch_validate_request: request.chunk_size is greater request.buffer_size)"); + SFETCH_LOG("_sfetch_validate_request: request.chunk_size is greater request.buffer_size)"); return false; } if (req->user_data_ptr && (req->user_data_size == 0)) { - SOKOL_LOG("_sfetch_validate_request: request.user_data_ptr is set, but request.user_data_size is null"); + SFETCH_LOG("_sfetch_validate_request: request.user_data_ptr is set, but request.user_data_size is null"); return false; } if (!req->user_data_ptr && (req->user_data_size > 0)) { - SOKOL_LOG("_sfetch_validate_request: request.user_data_ptr is null, but request.user_data_size is not"); + SFETCH_LOG("_sfetch_validate_request: request.user_data_ptr is null, but request.user_data_size is not"); return false; } if (req->user_data_size > SFETCH_MAX_USERDATA_UINT64 * sizeof(uint64_t)) { - SOKOL_LOG("_sfetch_validate_request: request.user_data_size is too big (see SFETCH_MAX_USERDATA_UINT64"); + SFETCH_LOG("_sfetch_validate_request: request.user_data_size is too big (see SFETCH_MAX_USERDATA_UINT64"); return false; } #else @@ -2443,7 +2506,7 @@ SOKOL_API_IMPL void sfetch_setup(const sfetch_desc_t* desc_) { /* replace zero-init items with default values */ if (ctx->desc.num_channels > SFETCH_MAX_CHANNELS) { ctx->desc.num_channels = SFETCH_MAX_CHANNELS; - SOKOL_LOG("sfetch_setup: clamping num_channels to SFETCH_MAX_CHANNELS"); + SFETCH_LOG("sfetch_setup: clamping num_channels to SFETCH_MAX_CHANNELS"); } /* setup the global request item pool */ @@ -2515,7 +2578,7 @@ SOKOL_API_IMPL sfetch_handle_t sfetch_send(const sfetch_request_t* request) { uint32_t slot_id = _sfetch_pool_item_alloc(&ctx->pool, request); if (0 == slot_id) { - SOKOL_LOG("sfetch_send: request pool exhausted (too many active requests)"); + SFETCH_LOG("sfetch_send: request pool exhausted (too many active requests)"); return invalid_handle; } if (!_sfetch_channel_send(&ctx->chn[request->channel], slot_id)) { diff --git a/sokol_gfx.h b/sokol_gfx.h index be756663..f3bd048b 100644 --- a/sokol_gfx.h +++ b/sokol_gfx.h @@ -40,7 +40,6 @@ Optionally provide the following defines with your own implementations: SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) - SOKOL_LOG(msg) - your own logging function (default: puts(msg)) SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) SOKOL_GFX_API_DECL - public function declaration prefix (default: extern) SOKOL_API_DECL - same as SOKOL_GFX_API_DECL @@ -679,7 +678,7 @@ .allocator = { .alloc = my_alloc, .free = my_free, - .user_data = ...; + .user_data = ..., } }); ... @@ -690,6 +689,27 @@ itself though, not any allocations in OS libraries. + LOG FUNCTION OVERRIDE + ===================== + You can override the log function at initialization time like this: + + void my_log(const char* message, void* user_data) { + printf("sg says: \s\n", message); + } + + ... + sg_setup(&(sg_desc){ + // ... + .logger = { + .log_cb = my_log, + .user_data = ..., + } + }); + ... + + If no overrides are provided, puts will be used on most platforms. + On Android, __android_log_write will be used instead. + TODO: ==== - talk about asynchronous resource creation @@ -2454,6 +2474,17 @@ typedef struct sg_allocator { void* user_data; } sg_allocator; +/* + sg_logger + + Used in sg_desc to provide custom log callbacks to sokol_gfx.h. + Default behavior is SG_LOG_DEFAULT(message). +*/ +typedef struct sg_logger { + void (*log_cb)(const char* message, void* user_data); + void* user_data; +} sg_logger; + typedef struct sg_desc { uint32_t _start_canary; int buffer_pool_size; @@ -2466,6 +2497,7 @@ typedef struct sg_desc { int staging_buffer_size; int sampler_cache_size; sg_allocator allocator; + sg_logger logger; // optional log function override sg_context_desc context; uint32_t _end_canary; } sg_desc; @@ -2658,13 +2690,38 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_ #ifndef SOKOL_UNREACHABLE #define SOKOL_UNREACHABLE SOKOL_ASSERT(false) #endif -#ifndef SOKOL_LOG + +#if defined(SOKOL_LOG) +#error "SOKOL_LOG macro is no longer supported, please use sg_desc.logger to override log functions" +#endif +#ifndef SOKOL_NO_LOG #ifdef SOKOL_DEBUG - #include <stdio.h> - #define SOKOL_LOG(s) { SOKOL_ASSERT(s); puts(s); } + #define SOKOL_NO_LOG 0 + #else + #define SOKOL_NO_LOG 1 + #endif +#endif +#if !SOKOL_NO_LOG + #if defined(__ANDROID__) + #include <android/log.h> // __android_log_write #else - #define SOKOL_LOG(s) + #include <stdio.h> // puts + #endif + #define SG_LOG(s) { SOKOL_ASSERT(s); _sg_log(s); } + #ifndef SG_LOG_DEFAULT + #if defined(__ANDROID__) + #include <android/log.h> + #define SG_LOG_DEFAULT(s) __android_log_write(ANDROID_LOG_INFO, "SOKOL_GFX", s) + #else + #include <stdio.h> + #define SG_LOG_DEFAULT(s) puts(s) + #endif #endif +#else + #define SG_LOG(s) +#endif +#ifndef SG_LOG_DEFAULT + #define SG_LOG_DEFAULT(s) #endif #ifndef _SOKOL_PRIVATE @@ -4323,6 +4380,17 @@ _SOKOL_PRIVATE void _sg_free(void* ptr) { } } +#if !SOKOL_NO_LOG +_SOKOL_PRIVATE void _sg_log(const char* msg) { + SOKOL_ASSERT(msg); + if (_sg.desc.logger.log_cb) { + _sg.desc.logger.log_cb(msg, _sg.desc.logger.user_data); + } else { + SG_LOG_DEFAULT(msg); + } +} +#endif + _SOKOL_PRIVATE bool _sg_strempty(const _sg_str_t* str) { return 0 == str->buf[0]; } @@ -6570,16 +6638,16 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_image(_sg_image_t* img, const sg_ /* check if texture format is support */ if (!_sg_gl_supported_texture_format(img->cmn.pixel_format)) { - SOKOL_LOG("texture format not supported by GL context\n"); + SG_LOG("texture format not supported by GL context\n"); return SG_RESOURCESTATE_FAILED; } /* check for optional texture types */ if ((img->cmn.type == SG_IMAGETYPE_3D) && !_sg.features.imagetype_3d) { - SOKOL_LOG("3D textures not supported by GL context\n"); + SG_LOG("3D textures not supported by GL context\n"); return SG_RESOURCESTATE_FAILED; } if ((img->cmn.type == SG_IMAGETYPE_ARRAY) && !_sg.features.imagetype_array) { - SOKOL_LOG("array textures not supported by GL context\n"); + SG_LOG("array textures not supported by GL context\n"); return SG_RESOURCESTATE_FAILED; } @@ -6783,7 +6851,7 @@ _SOKOL_PRIVATE GLuint _sg_gl_compile_shader(sg_shader_stage stage, const char* s if (log_len > 0) { GLchar* log_buf = (GLchar*) _sg_malloc((size_t)log_len); glGetShaderInfoLog(gl_shd, log_len, &log_len, log_buf); - SOKOL_LOG(log_buf); + SG_LOG(log_buf); _sg_free(log_buf); } glDeleteShader(gl_shd); @@ -6826,7 +6894,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_shader(_sg_shader_t* shd, const s if (log_len > 0) { GLchar* log_buf = (GLchar*) _sg_malloc((size_t)log_len); glGetProgramInfoLog(gl_prog, log_len, &log_len, log_buf); - SOKOL_LOG(log_buf); + SG_LOG(log_buf); _sg_free(log_buf); } glDeleteProgram(gl_prog); @@ -6974,8 +7042,8 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_pipeline(_sg_pipeline_t* pip, _sg pip->cmn.vertex_layout_valid[a_desc->buffer_index] = true; } else { - SOKOL_LOG("Vertex attribute not found in shader: "); - SOKOL_LOG(_sg_strptr(&shd->gl.attrs[attr_index].name)); + SG_LOG("Vertex attribute not found in shader: "); + SG_LOG(_sg_strptr(&shd->gl.attrs[attr_index].name)); } } return SG_RESOURCESTATE_VALID; @@ -7080,7 +7148,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_pass(_sg_pass_t* pass, _sg_image_ /* check if framebuffer is complete */ if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - SOKOL_LOG("Framebuffer completeness check failed!\n"); + SG_LOG("Framebuffer completeness check failed!\n"); return SG_RESOURCESTATE_FAILED; } @@ -7127,7 +7195,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_pass(_sg_pass_t* pass, _sg_image_ } /* check if framebuffer is complete */ if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - SOKOL_LOG("Framebuffer completeness check failed (msaa resolve buffer)!\n"); + SG_LOG("Framebuffer completeness check failed (msaa resolve buffer)!\n"); return SG_RESOURCESTATE_FAILED; } /* setup color attachments for the framebuffer */ @@ -8637,7 +8705,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_buffer(_sg_buffer_t* buf, cons } HRESULT hr = _sg_d3d11_CreateBuffer(_sg.d3d11.dev, &d3d11_desc, init_data_ptr, &buf->d3d11.buf); if (!(SUCCEEDED(hr) && buf->d3d11.buf)) { - SOKOL_LOG("failed to create D3D11 buffer\n"); + SG_LOG("failed to create D3D11 buffer\n"); return SG_RESOURCESTATE_FAILED; } } @@ -8696,7 +8764,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const /* create only a depth-texture */ SOKOL_ASSERT(!injected); if (img->d3d11.format == DXGI_FORMAT_UNKNOWN) { - SOKOL_LOG("trying to create a D3D11 depth-texture with unsupported pixel format\n"); + SG_LOG("trying to create a D3D11 depth-texture with unsupported pixel format\n"); return SG_RESOURCESTATE_FAILED; } D3D11_TEXTURE2D_DESC d3d11_desc; @@ -8712,7 +8780,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const d3d11_desc.SampleDesc.Quality = (UINT) (msaa ? D3D11_STANDARD_MULTISAMPLE_PATTERN : 0); hr = _sg_d3d11_CreateTexture2D(_sg.d3d11.dev, &d3d11_desc, NULL, &img->d3d11.texds); if (!(SUCCEEDED(hr) && img->d3d11.texds)) { - SOKOL_LOG("failed to create D3D11 texture 2D\n"); + SG_LOG("failed to create D3D11 texture 2D\n"); return SG_RESOURCESTATE_FAILED; } } @@ -8776,7 +8844,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const } if (img->d3d11.format == DXGI_FORMAT_UNKNOWN) { /* trying to create a texture format that's not supported by D3D */ - SOKOL_LOG("trying to create a D3D11 texture with unsupported pixel format\n"); + SG_LOG("trying to create a D3D11 texture with unsupported pixel format\n"); return SG_RESOURCESTATE_FAILED; } d3d11_tex_desc.SampleDesc.Count = 1; @@ -8785,7 +8853,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const hr = _sg_d3d11_CreateTexture2D(_sg.d3d11.dev, &d3d11_tex_desc, init_data, &img->d3d11.tex2d); if (!(SUCCEEDED(hr) && img->d3d11.tex2d)) { - SOKOL_LOG("failed to create D3D11 texture 2D\n"); + SG_LOG("failed to create D3D11 texture 2D\n"); return SG_RESOURCESTATE_FAILED; } } @@ -8814,7 +8882,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const } hr = _sg_d3d11_CreateShaderResourceView(_sg.d3d11.dev, (ID3D11Resource*)img->d3d11.tex2d, &d3d11_srv_desc, &img->d3d11.srv); if (!(SUCCEEDED(hr) && img->d3d11.srv)) { - SOKOL_LOG("failed to create D3D11 resource view\n"); + SG_LOG("failed to create D3D11 resource view\n"); return SG_RESOURCESTATE_FAILED; } } @@ -8859,12 +8927,12 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const } if (img->d3d11.format == DXGI_FORMAT_UNKNOWN) { /* trying to create a texture format that's not supported by D3D */ - SOKOL_LOG("trying to create a D3D11 texture with unsupported pixel format\n"); + SG_LOG("trying to create a D3D11 texture with unsupported pixel format\n"); return SG_RESOURCESTATE_FAILED; } hr = _sg_d3d11_CreateTexture3D(_sg.d3d11.dev, &d3d11_tex_desc, init_data, &img->d3d11.tex3d); if (!(SUCCEEDED(hr) && img->d3d11.tex3d)) { - SOKOL_LOG("failed to create D3D11 texture 3D\n"); + SG_LOG("failed to create D3D11 texture 3D\n"); return SG_RESOURCESTATE_FAILED; } } @@ -8877,7 +8945,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const d3d11_srv_desc.Texture3D.MipLevels = (UINT)img->cmn.num_mipmaps; hr = _sg_d3d11_CreateShaderResourceView(_sg.d3d11.dev, (ID3D11Resource*)img->d3d11.tex3d, &d3d11_srv_desc, &img->d3d11.srv); if (!(SUCCEEDED(hr) && img->d3d11.srv)) { - SOKOL_LOG("failed to create D3D11 resource view\n"); + SG_LOG("failed to create D3D11 resource view\n"); return SG_RESOURCESTATE_FAILED; } } @@ -8899,7 +8967,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const d3d11_tex_desc.SampleDesc.Quality = (UINT)D3D11_STANDARD_MULTISAMPLE_PATTERN; hr = _sg_d3d11_CreateTexture2D(_sg.d3d11.dev, &d3d11_tex_desc, NULL, &img->d3d11.texmsaa); if (!(SUCCEEDED(hr) && img->d3d11.texmsaa)) { - SOKOL_LOG("failed to create D3D11 texture 2D\n"); + SG_LOG("failed to create D3D11 texture 2D\n"); return SG_RESOURCESTATE_FAILED; } } @@ -8931,7 +8999,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const d3d11_smp_desc.MaxLOD = desc->max_lod; hr = _sg_d3d11_CreateSamplerState(_sg.d3d11.dev, &d3d11_smp_desc, &img->d3d11.smp); if (!(SUCCEEDED(hr) && img->d3d11.smp)) { - SOKOL_LOG("failed to create D3D11 sampler state\n"); + SG_LOG("failed to create D3D11 sampler state\n"); return SG_RESOURCESTATE_FAILED; } } @@ -8970,7 +9038,7 @@ _SOKOL_PRIVATE bool _sg_d3d11_load_d3dcompiler_dll(void) { _sg.d3d11.d3dcompiler_dll = LoadLibraryA("d3dcompiler_47.dll"); if (0 == _sg.d3d11.d3dcompiler_dll) { /* don't attempt to load missing DLL in the future */ - SOKOL_LOG("failed to load d3dcompiler_47.dll!\n"); + SG_LOG("failed to load d3dcompiler_47.dll!\n"); _sg.d3d11.d3dcompiler_dll_load_failed = true; return false; } @@ -9008,7 +9076,7 @@ _SOKOL_PRIVATE ID3DBlob* _sg_d3d11_compile_shader(const sg_shader_stage_desc* st &output, /* ppCode */ &errors_or_warnings); /* ppErrorMsgs */ if (errors_or_warnings) { - SOKOL_LOG((LPCSTR)_sg_d3d11_GetBufferPointer(errors_or_warnings)); + SG_LOG((LPCSTR)_sg_d3d11_GetBufferPointer(errors_or_warnings)); _sg_d3d11_Release(errors_or_warnings); errors_or_warnings = NULL; } if (FAILED(hr)) { @@ -9050,7 +9118,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_shader(_sg_shader_t* shd, cons cb_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; hr = _sg_d3d11_CreateBuffer(_sg.d3d11.dev, &cb_desc, NULL, &d3d11_stage->cbufs[ub_index]); if (!(SUCCEEDED(hr) && d3d11_stage->cbufs[ub_index])) { - SOKOL_LOG("failed to create D3D11 buffer\n"); + SG_LOG("failed to create D3D11 buffer\n"); return SG_RESOURCESTATE_FAILED; } } @@ -9182,7 +9250,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip, shd->d3d11.vs_blob_length, /* BytecodeLength */ &pip->d3d11.il); if (!(SUCCEEDED(hr) && pip->d3d11.il)) { - SOKOL_LOG("failed to create D3D11 input layout\n"); + SG_LOG("failed to create D3D11 input layout\n"); return SG_RESOURCESTATE_FAILED; } @@ -9201,7 +9269,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip, rs_desc.AntialiasedLineEnable = FALSE; hr = _sg_d3d11_CreateRasterizerState(_sg.d3d11.dev, &rs_desc, &pip->d3d11.rs); if (!(SUCCEEDED(hr) && pip->d3d11.rs)) { - SOKOL_LOG("failed to create D3D11 rasterizer state\n"); + SG_LOG("failed to create D3D11 rasterizer state\n"); return SG_RESOURCESTATE_FAILED; } @@ -9226,7 +9294,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip, dss_desc.BackFace.StencilFunc = _sg_d3d11_compare_func(sb->compare); hr = _sg_d3d11_CreateDepthStencilState(_sg.d3d11.dev, &dss_desc, &pip->d3d11.dss); if (!(SUCCEEDED(hr) && pip->d3d11.dss)) { - SOKOL_LOG("failed to create D3D11 depth stencil state\n"); + SG_LOG("failed to create D3D11 depth stencil state\n"); return SG_RESOURCESTATE_FAILED; } @@ -9260,7 +9328,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip, } hr = _sg_d3d11_CreateBlendState(_sg.d3d11.dev, &bs_desc, &pip->d3d11.bs); if (!(SUCCEEDED(hr) && pip->d3d11.bs)) { - SOKOL_LOG("failed to create D3D11 blend state\n"); + SG_LOG("failed to create D3D11 blend state\n"); return SG_RESOURCESTATE_FAILED; } @@ -9341,7 +9409,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pass(_sg_pass_t* pass, _sg_ima SOKOL_ASSERT(d3d11_res); HRESULT hr = _sg_d3d11_CreateRenderTargetView(_sg.d3d11.dev, d3d11_res, &d3d11_rtv_desc, &pass->d3d11.color_atts[i].rtv); if (!(SUCCEEDED(hr) && pass->d3d11.color_atts[i].rtv)) { - SOKOL_LOG("failed to create D3D11 render target view\n"); + SG_LOG("failed to create D3D11 render target view\n"); return SG_RESOURCESTATE_FAILED; } } @@ -9374,7 +9442,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pass(_sg_pass_t* pass, _sg_ima SOKOL_ASSERT(d3d11_res); HRESULT hr = _sg_d3d11_CreateDepthStencilView(_sg.d3d11.dev, d3d11_res, &d3d11_dsv_desc, &pass->d3d11.ds_att.dsv); if (!(SUCCEEDED(hr) && pass->d3d11.ds_att.dsv)) { - SOKOL_LOG("failed to create D3D11 depth stencil view\n"); + SG_LOG("failed to create D3D11 depth stencil view\n"); return SG_RESOURCESTATE_FAILED; } } @@ -9674,7 +9742,7 @@ _SOKOL_PRIVATE void _sg_d3d11_update_buffer(_sg_buffer_t* buf, const sg_range* d memcpy(d3d11_msr.pData, data->ptr, data->size); _sg_d3d11_Unmap(_sg.d3d11.ctx, (ID3D11Resource*)buf->d3d11.buf, 0); } else { - SOKOL_LOG("failed to map buffer while updating!\n"); + SG_LOG("failed to map buffer while updating!\n"); } } @@ -9690,7 +9758,7 @@ _SOKOL_PRIVATE int _sg_d3d11_append_buffer(_sg_buffer_t* buf, const sg_range* da memcpy(dst_ptr, data->ptr, data->size); _sg_d3d11_Unmap(_sg.d3d11.ctx, (ID3D11Resource*)buf->d3d11.buf, 0); } else { - SOKOL_LOG("failed to map buffer while appending!\n"); + SG_LOG("failed to map buffer while appending!\n"); } /* NOTE: this alignment is a requirement from WebGPU, but we want identical behaviour across all backend */ return _sg_roundup((int)data->size, 4); @@ -9742,7 +9810,7 @@ _SOKOL_PRIVATE void _sg_d3d11_update_image(_sg_image_t* img, const sg_image_data } _sg_d3d11_Unmap(_sg.d3d11.ctx, d3d11_res, subres_index); } else { - SOKOL_LOG("failed to map texture!\n"); + SG_LOG("failed to map texture!\n"); } } } @@ -10618,7 +10686,7 @@ _SOKOL_PRIVATE bool _sg_mtl_init_texdesc_common(MTLTextureDescriptor* mtl_desc, mtl_desc.textureType = _sg_mtl_texture_type(img->cmn.type); mtl_desc.pixelFormat = _sg_mtl_pixel_format(img->cmn.pixel_format); if (MTLPixelFormatInvalid == mtl_desc.pixelFormat) { - SOKOL_LOG("Unsupported texture pixel format!\n"); + SG_LOG("Unsupported texture pixel format!\n"); return false; } mtl_desc.width = (NSUInteger)img->cmn.width; @@ -10780,7 +10848,7 @@ _SOKOL_PRIVATE id<MTLLibrary> _sg_mtl_compile_library(const char* src) { error:&err ]; if (err) { - SOKOL_LOG([err.localizedDescription UTF8String]); + SG_LOG([err.localizedDescription UTF8String]); } return lib; } @@ -10790,7 +10858,7 @@ _SOKOL_PRIVATE id<MTLLibrary> _sg_mtl_library_from_bytecode(const void* ptr, siz dispatch_data_t lib_data = dispatch_data_create(ptr, num_bytes, NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT); id<MTLLibrary> lib = [_sg.mtl.device newLibraryWithData:lib_data error:&err]; if (err) { - SOKOL_LOG([err.localizedDescription UTF8String]); + SG_LOG([err.localizedDescription UTF8String]); } _SG_OBJC_RELEASE(lib_data); return lib; @@ -10832,11 +10900,11 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_shader(_sg_shader_t* shd, const goto failed; } if (nil == vs_func) { - SOKOL_LOG("vertex shader entry function not found\n"); + SG_LOG("vertex shader entry function not found\n"); goto failed; } if (nil == fs_func) { - SOKOL_LOG("fragment shader entry function not found\n"); + SG_LOG("fragment shader entry function not found\n"); goto failed; } /* it is legal to call _sg_mtl_add_resource with a nil value, this will return a special 0xFFFFFFFF index */ @@ -10960,7 +11028,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_pipeline(_sg_pipeline_t* pip, _s _SG_OBJC_RELEASE(rp_desc); if (nil == mtl_rps) { SOKOL_ASSERT(err); - SOKOL_LOG([err.localizedDescription UTF8String]); + SG_LOG([err.localizedDescription UTF8String]); return SG_RESOURCESTATE_FAILED; } @@ -11956,7 +12024,7 @@ _SOKOL_PRIVATE void _sg_wgpu_ubpool_mapped_callback(WGPUBufferMapAsyncStatus sta } /* FIXME: better handling for this */ if (WGPUBufferMapAsyncStatus_Success != status) { - SOKOL_LOG("Mapping uniform buffer failed!\n"); + SG_LOG("Mapping uniform buffer failed!\n"); SOKOL_ASSERT(false); } SOKOL_ASSERT(data && (data_len == _sg.wgpu.ub.num_bytes)); @@ -12215,7 +12283,7 @@ _SOKOL_PRIVATE uint32_t _sg_wgpu_staging_copy_to_buffer(WGPUBuffer dst_buf, uint SOKOL_ASSERT(data_num_bytes > 0); uint32_t copy_num_bytes = _sg_roundup(data_num_bytes, 4); if ((_sg.wgpu.staging.offset + copy_num_bytes) >= _sg.wgpu.staging.num_bytes) { - SOKOL_LOG("WGPU: Per frame staging buffer full (in _sg_wgpu_staging_copy_to_buffer())!\n"); + SG_LOG("WGPU: Per frame staging buffer full (in _sg_wgpu_staging_copy_to_buffer())!\n"); return false; } const int cur = _sg.wgpu.staging.cur; @@ -12234,7 +12302,7 @@ _SOKOL_PRIVATE bool _sg_wgpu_staging_copy_to_texture(_sg_image_t* img, const sg_ SOKOL_ASSERT(_sg.wgpu.staging_cmd_enc); uint32_t num_bytes = _sg_wgpu_image_data_buffer_size(img); if ((_sg.wgpu.staging.offset + num_bytes) >= _sg.wgpu.staging.num_bytes) { - SOKOL_LOG("WGPU: Per frame staging buffer full (in _sg_wgpu_staging_copy_to_texture)!\n"); + SG_LOG("WGPU: Per frame staging buffer full (in _sg_wgpu_staging_copy_to_texture)!\n"); return false; } const int cur = _sg.wgpu.staging.cur; @@ -12372,7 +12440,7 @@ _SOKOL_PRIVATE void _sg_wgpu_discard_backend(void) { } _SOKOL_PRIVATE void _sg_wgpu_reset_state_cache(void) { - SOKOL_LOG("_sg_wgpu_reset_state_cache: FIXME\n"); + SG_LOG("_sg_wgpu_reset_state_cache: FIXME\n"); } _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_context(_sg_context_t* ctx) { @@ -12388,7 +12456,7 @@ _SOKOL_PRIVATE void _sg_wgpu_destroy_context(_sg_context_t* ctx) { _SOKOL_PRIVATE void _sg_wgpu_activate_context(_sg_context_t* ctx) { (void)ctx; - SOKOL_LOG("_sg_wgpu_activate_context: FIXME\n"); + SG_LOG("_sg_wgpu_activate_context: FIXME\n"); } _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) { @@ -14167,14 +14235,14 @@ _SOKOL_PRIVATE void _sg_validate_begin(void) { _SOKOL_PRIVATE void _sg_validate(bool cond, _sg_validate_error_t err) { if (!cond) { _sg.validate_error = err; - SOKOL_LOG(_sg_validate_string(err)); + SG_LOG(_sg_validate_string(err)); } } _SOKOL_PRIVATE bool _sg_validate_end(void) { if (_sg.validate_error != _SG_VALIDATE_SUCCESS) { #if !defined(SOKOL_VALIDATE_NON_FATAL) - SOKOL_LOG("^^^^ SOKOL-GFX VALIDATION FAILED, TERMINATING ^^^^"); + SG_LOG("^^^^ SOKOL-GFX VALIDATION FAILED, TERMINATING ^^^^"); SOKOL_ASSERT(false); #endif return false; @@ -15151,7 +15219,7 @@ _SOKOL_PRIVATE bool _sg_uninit_buffer(sg_buffer buf_id) { return true; } else { - SOKOL_LOG("_sg_uninit_buffer: active context mismatch (must be same as for creation)"); + SG_LOG("_sg_uninit_buffer: active context mismatch (must be same as for creation)"); _SG_TRACE_NOARGS(err_context_mismatch); } } @@ -15167,7 +15235,7 @@ _SOKOL_PRIVATE bool _sg_uninit_image(sg_image img_id) { return true; } else { - SOKOL_LOG("_sg_uninit_image: active context mismatch (must be same as for creation)"); + SG_LOG("_sg_uninit_image: active context mismatch (must be same as for creation)"); _SG_TRACE_NOARGS(err_context_mismatch); } } @@ -15183,7 +15251,7 @@ _SOKOL_PRIVATE bool _sg_uninit_shader(sg_shader shd_id) { return true; } else { - SOKOL_LOG("_sg_uninit_shader: active context mismatch (must be same as for creation)"); + SG_LOG("_sg_uninit_shader: active context mismatch (must be same as for creation)"); _SG_TRACE_NOARGS(err_context_mismatch); } } @@ -15199,7 +15267,7 @@ _SOKOL_PRIVATE bool _sg_uninit_pipeline(sg_pipeline pip_id) { return true; } else { - SOKOL_LOG("_sg_uninit_pipeline: active context mismatch (must be same as for creation)"); + SG_LOG("_sg_uninit_pipeline: active context mismatch (must be same as for creation)"); _SG_TRACE_NOARGS(err_context_mismatch); } } @@ -15215,7 +15283,7 @@ _SOKOL_PRIVATE bool _sg_uninit_pass(sg_pass pass_id) { return true; } else { - SOKOL_LOG("_sg_uninit_pass: active context mismatch (must be same as for creation)"); + SG_LOG("_sg_uninit_pass: active context mismatch (must be same as for creation)"); _SG_TRACE_NOARGS(err_context_mismatch); } } @@ -15362,7 +15430,7 @@ SOKOL_API_IMPL sg_trace_hooks sg_install_trace_hooks(const sg_trace_hooks* trace _sg.hooks = *trace_hooks; #else static sg_trace_hooks old_hooks; - SOKOL_LOG("sg_install_trace_hooks() called, but SG_TRACE_HOOKS is not defined!"); + SG_LOG("sg_install_trace_hooks() called, but SG_TRACE_HOOKS is not defined!"); #endif return old_hooks; } @@ -15599,7 +15667,7 @@ SOKOL_API_IMPL sg_buffer sg_make_buffer(const sg_buffer_desc* desc) { _sg_init_buffer(buf_id, &desc_def); } else { - SOKOL_LOG("buffer pool exhausted!"); + SG_LOG("buffer pool exhausted!"); _SG_TRACE_NOARGS(err_buffer_pool_exhausted); } _SG_TRACE_ARGS(make_buffer, &desc_def, buf_id); @@ -15615,7 +15683,7 @@ SOKOL_API_IMPL sg_image sg_make_image(const sg_image_desc* desc) { _sg_init_image(img_id, &desc_def); } else { - SOKOL_LOG("image pool exhausted!"); + SG_LOG("image pool exhausted!"); _SG_TRACE_NOARGS(err_image_pool_exhausted); } _SG_TRACE_ARGS(make_image, &desc_def, img_id); @@ -15631,7 +15699,7 @@ SOKOL_API_IMPL sg_shader sg_make_shader(const sg_shader_desc* desc) { _sg_init_shader(shd_id, &desc_def); } else { - SOKOL_LOG("shader pool exhausted!"); + SG_LOG("shader pool exhausted!"); _SG_TRACE_NOARGS(err_shader_pool_exhausted); } _SG_TRACE_ARGS(make_shader, &desc_def, shd_id); @@ -15647,7 +15715,7 @@ SOKOL_API_IMPL sg_pipeline sg_make_pipeline(const sg_pipeline_desc* desc) { _sg_init_pipeline(pip_id, &desc_def); } else { - SOKOL_LOG("pipeline pool exhausted!"); + SG_LOG("pipeline pool exhausted!"); _SG_TRACE_NOARGS(err_pipeline_pool_exhausted); } _SG_TRACE_ARGS(make_pipeline, &desc_def, pip_id); @@ -15663,7 +15731,7 @@ SOKOL_API_IMPL sg_pass sg_make_pass(const sg_pass_desc* desc) { _sg_init_pass(pass_id, &desc_def); } else { - SOKOL_LOG("pass pool exhausted!"); + SG_LOG("pass pool exhausted!"); _SG_TRACE_NOARGS(err_pass_pool_exhausted); } _SG_TRACE_ARGS(make_pass, &desc_def, pass_id); @@ -15900,7 +15968,7 @@ SOKOL_API_IMPL void sg_draw(int base_element, int num_elements, int num_instance SOKOL_ASSERT(num_instances >= 0); #if defined(SOKOL_DEBUG) if (!_sg.bindings_valid) { - SOKOL_LOG("attempting to draw without resource bindings"); + SG_LOG("attempting to draw without resource bindings"); } #endif if (!_sg.pass_valid) { diff --git a/util/sokol_debugtext.h b/util/sokol_debugtext.h index ae69904d..3201d9e3 100644 --- a/util/sokol_debugtext.h +++ b/util/sokol_debugtext.h @@ -31,7 +31,6 @@ SOKOL_DEBUGTEXT_API_DECL - public function declaration prefix (default: extern) SOKOL_API_DECL - same as SOKOL_DEBUGTEXT_API_DECL SOKOL_API_IMPL - public function implementation prefix (default: -) - SOKOL_LOG(msg) - your own logging function (default: puts(msg)) SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) If sokol_debugtext.h is compiled as a DLL, define the following before @@ -396,6 +395,27 @@ If no overrides are provided, malloc and free will be used. + LOG FUNCTION OVERRIDE + ===================== + You can override the log function at initialization time like this: + + void my_log(const char* message, void* user_data) { + printf("sdtx says: \s\n", message); + } + + ... + sdtx_setup(&(sdtx_desc_t){ + // ... + .logger = { + .log_cb = my_log, + .user_data = ..., + } + }); + ... + + If no overrides are provided, puts will be used on most platforms. + On Android, __android_log_write will be used instead. + LICENSE ======= zlib/libpng license @@ -544,6 +564,17 @@ typedef struct sdtx_allocator_t { } sdtx_allocator_t; /* + sdtx_logger_t + + Used in sdtx_desc_t to provide custom log callbacks to sokol_debugtext.h. + Default behavior is SDTX_LOG_DEFAULT(message). +*/ +typedef struct sdtx_logger_t { + void (*log_cb)(const char* message, void* user_data); + void* user_data; +} sdtx_logger_t; + +/* sdtx_desc_t Describes the sokol-debugtext API initialization parameters. Passed @@ -565,6 +596,7 @@ typedef struct sdtx_desc_t { sdtx_font_desc_t fonts[SDTX_MAX_FONTS]; // up to 8 fonts descriptions sdtx_context_desc_t context; // the default context creation parameters sdtx_allocator_t allocator; // optional memory allocation overrides (default: malloc/free) + sdtx_logger_t logger; // optional log override functions (default: SDTX_LOG_DEFAULT(message)) } sdtx_desc_t; /* initialization/shutdown */ @@ -655,14 +687,35 @@ inline sdtx_context sdtx_make_context(const sdtx_context_desc_t& desc) { return #include <assert.h> #define SOKOL_ASSERT(c) assert(c) #endif -#ifndef SOKOL_LOG + +#if defined(SOKOL_LOG) +#error "SOKOL_LOG macro is no longer supported, please use sg_desc.logger to override log functions" +#endif +#ifndef SOKOL_NO_LOG #ifdef SOKOL_DEBUG - #include <stdio.h> - #define SOKOL_LOG(s) { SOKOL_ASSERT(s); puts(s); } + #define SOKOL_NO_LOG 0 #else - #define SOKOL_LOG(s) + #define SOKOL_NO_LOG 1 + #endif +#endif +#if !SOKOL_NO_LOG + #define SDTX_LOG(s) { SOKOL_ASSERT(s); _sdtx_log(s); } + #ifndef SDTX_LOG_DEFAULT + #if defined(__ANDROID__) + #include <android/log.h> + #define SDTX_LOG_DEFAULT(s) __android_log_write(ANDROID_LOG_INFO, "SOKOL_DEBUGTEXT", s) + #else + #include <stdio.h> + #define SDTX_LOG_DEFAULT(s) puts(s) + #endif #endif +#else + #define SDTX_LOG(s) +#endif +#ifndef SDTX_LOG_DEFAULT + #define SDTX_LOG_DEFAULT(s) #endif + #ifndef SOKOL_UNREACHABLE #define SOKOL_UNREACHABLE SOKOL_ASSERT(false) #endif @@ -3510,6 +3563,17 @@ static void _sdtx_free(void* ptr) { } } +#if !SOKOL_NO_LOG +static void _sdtx_log(const char* msg) { + SOKOL_ASSERT(msg); + if (_sdtx.desc.logger.log_cb) { + _sdtx.desc.logger.log_cb(msg, _sdtx.desc.logger.user_data); + } else { + SDTX_LOG_DEFAULT(msg); + } +} +#endif + /*=== CONTEXT POOL ===========================================================*/ static void _sdtx_init_pool(_sdtx_pool_t* pool, int num) { SOKOL_ASSERT(pool && (num >= 1)); @@ -4017,7 +4081,7 @@ SOKOL_API_IMPL sdtx_context sdtx_make_context(const sdtx_context_desc_t* desc) { _sdtx_init_context(ctx_id, desc); } else { - SOKOL_LOG("sokol_debugtext.h: context pool exhausted!"); + SDTX_LOG("sokol_debugtext.h: context pool exhausted!"); } return ctx_id; } @@ -4025,7 +4089,7 @@ SOKOL_API_IMPL sdtx_context sdtx_make_context(const sdtx_context_desc_t* desc) { SOKOL_API_IMPL void sdtx_destroy_context(sdtx_context ctx_id) { SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); if (_sdtx_is_default_context(ctx_id)) { - SOKOL_LOG("sokol_debugtext.h: cannot destroy default context"); + SDTX_LOG("sokol_debugtext.h: cannot destroy default context"); return; } _sdtx_destroy_context(ctx_id); diff --git a/util/sokol_fontstash.h b/util/sokol_fontstash.h index af9f18c1..16d288ab 100644 --- a/util/sokol_fontstash.h +++ b/util/sokol_fontstash.h @@ -31,7 +31,6 @@ SOKOL_FONTSTASH_API_DECL - public function declaration prefix (default: extern) SOKOL_API_DECL - same as SOKOL_FONTSTASH_API_DECL SOKOL_API_IMPL - public function implementation prefix (default: -) - SOKOL_LOG(msg) - your own logging function (default: puts(msg)) SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) Include the following headers before including sokol_fontstash.h: @@ -273,14 +272,6 @@ SOKOL_FONTSTASH_API_DECL uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, ui #include <assert.h> #define SOKOL_ASSERT(c) assert(c) #endif -#ifndef SOKOL_LOG - #ifdef SOKOL_DEBUG - #include <stdio.h> - #define SOKOL_LOG(s) { SOKOL_ASSERT(s); puts(s); } - #else - #define SOKOL_LOG(s) - #endif -#endif #ifndef SOKOL_UNREACHABLE #define SOKOL_UNREACHABLE SOKOL_ASSERT(false) #endif diff --git a/util/sokol_gl.h b/util/sokol_gl.h index 5f8e565c..1f4f4d05 100644 --- a/util/sokol_gl.h +++ b/util/sokol_gl.h @@ -30,7 +30,6 @@ SOKOL_GL_API_DECL - public function declaration prefix (default: extern) SOKOL_API_DECL - same as SOKOL_GL_API_DECL SOKOL_API_IMPL - public function implementation prefix (default: -) - SOKOL_LOG(msg) - your own logging function (default: puts(msg)) SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) If sokol_gl.h is compiled as a DLL, define the following before @@ -573,6 +572,28 @@ If no overrides are provided, malloc and free will be used. + LOG FUNCTION OVERRIDE + ===================== + You can override the log function at initialization time like this: + + void my_log(const char* message, void* user_data) { + printf("sgl says: \s\n", message); + } + + ... + sgl_setup(&(sgl_desc_t){ + // ... + .logger = { + .log_cb = my_log, + .user_data = ..., + } + }); + ... + + If no overrides are provided, puts will be used on most platforms. + On Android, __android_log_write will be used instead. + + LICENSE ======= zlib/libpng license @@ -675,6 +696,17 @@ typedef struct sgl_allocator_t { void* user_data; } sgl_allocator_t; +/* + sgl_logger_t + + Used in sgl_desc_t to provide custom log callbacks to sokol_gl.h. + Default behavior is SGL_LOG_DEFAULT(message). +*/ +typedef struct sgl_logger_t { + void (*log_cb)(const char* message, void* user_data); + void* user_data; +} sgl_logger_t; + typedef struct sgl_desc_t { int max_vertices; // default: 64k int max_commands; // default: 16k @@ -685,6 +717,7 @@ typedef struct sgl_desc_t { int sample_count; sg_face_winding face_winding; // default: SG_FACEWINDING_CCW sgl_allocator_t allocator; // optional memory allocation overrides (default: malloc/free) + sgl_logger_t logger; // optional memory allocation overrides (default: SGL_LOG_DEFAULT(message)) } sgl_desc_t; /* the default context handle */ @@ -830,16 +863,33 @@ inline sgl_pipeline sgl_context_make_pipeline(sgl_context ctx, const sg_pipeline #include <assert.h> #define SOKOL_ASSERT(c) assert(c) #endif -#ifndef SOKOL_LOG + +#if defined(SOKOL_LOG) +#error "SOKOL_LOG macro is no longer supported, please use sgl_desc_t.logger to override log functions" +#endif +#ifndef SOKOL_NO_LOG #ifdef SOKOL_DEBUG - #include <stdio.h> - #define SOKOL_LOG(s) { SOKOL_ASSERT(s); puts(s); } + #define SOKOL_NO_LOG 0 #else - #define SOKOL_LOG(s) + #define SOKOL_NO_LOG 1 #endif #endif -#ifndef SOKOL_UNREACHABLE - #define SOKOL_UNREACHABLE SOKOL_ASSERT(false) +#if !SOKOL_NO_LOG + #define SGL_LOG(s) { SOKOL_ASSERT(s); _sgl_log(s); } + #ifndef SGL_LOG_DEFAULT + #if defined(__ANDROID__) + #include <android/log.h> + #define SGL_LOG_DEFAULT(s) __android_log_write(ANDROID_LOG_INFO, "SOKOL_GL", s) + #else + #include <stdio.h> + #define SGL_LOG_DEFAULT(s) puts(s) + #endif + #endif +#else + #define SGL_LOG(s) +#endif +#ifndef SGL_LOG_DEFAULT + #define SGL_LOG_DEFAULT(s) #endif #define _sgl_def(val, def) (((val) == 0) ? (def) : (val)) @@ -2340,6 +2390,17 @@ static void _sgl_free(void* ptr) { } } +#if !SOKOL_NO_LOG +static void _sgl_log(const char* msg) { + SOKOL_ASSERT(msg); + if (_sgl.desc.logger.log_cb) { + _sgl.desc.logger.log_cb(msg, _sgl.desc.logger.user_data); + } else { + SGL_LOG_DEFAULT(msg); + } +} +#endif + static void _sgl_init_pool(_sgl_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 */ @@ -2576,7 +2637,7 @@ static void _sgl_init_pipeline(sgl_pipeline pip_id, const sg_pipeline_desc* in_d else { pip->pip[i] = sg_make_pipeline(&desc); if (pip->pip[i].id == SG_INVALID_ID) { - SOKOL_LOG("sokol_gl.h: failed to create pipeline object"); + SGL_LOG("sokol_gl.h: failed to create pipeline object"); pip->slot.state = SG_RESOURCESTATE_FAILED; } } @@ -2590,7 +2651,7 @@ static sgl_pipeline _sgl_make_pipeline(const sg_pipeline_desc* desc, const sgl_c _sgl_init_pipeline(pip_id, desc, ctx_desc); } else { - SOKOL_LOG("sokol_gl.h: pipeline pool exhausted!"); + SGL_LOG("sokol_gl.h: pipeline pool exhausted!"); } return pip_id; } @@ -2717,7 +2778,7 @@ static sgl_context _sgl_make_context(const sgl_context_desc_t* desc) { _sgl_init_context(ctx_id, desc); } else { - SOKOL_LOG("sokol_gl.h: context pool exhausted!"); + SGL_LOG("sokol_gl.h: context pool exhausted!"); } return ctx_id; } @@ -3298,7 +3359,7 @@ SOKOL_API_IMPL sgl_context sgl_make_context(const sgl_context_desc_t* desc) { SOKOL_API_IMPL void sgl_destroy_context(sgl_context ctx_id) { SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); if (_sgl_is_default_context(ctx_id)) { - SOKOL_LOG("sokol_gl.h: cannot destroy default context"); + SGL_LOG("sokol_gl.h: cannot destroy default context"); return; } _sgl_destroy_context(ctx_id); |