From 70ab7deec5a92c465e86b46925d2209acafeabbe Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Wed, 21 Aug 2024 19:44:49 +0200 Subject: [PATCH 01/12] gh actions: switch actions/checkout version to main --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d314b1d..76a581c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,7 +11,7 @@ jobs: # NOTE: odin macos and ubuntu releases are zipped twice, so this is bit of a hack. # The examples folder also conflicts with the sokol examples, so we just remove it. steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@main - uses: ilammy/msvc-dev-cmd@v1 - if: runner.os == 'Linux' name: prepare-linux From 11dcdf02277b1aa4cb28f4e39038d792b2a9723b Mon Sep 17 00:00:00 2001 From: GH Action Date: Mon, 26 Aug 2024 12:56:38 +0000 Subject: [PATCH 02/12] updated (https://github.com/floooh/sokol/commit/501acaf3f9c4cf1516d2dcf84d195e5f898b18e0) --- sokol/c/sokol_gl.h | 140 +++++++++++++++++++++++++++++++++------------ sokol/gl/gl.odin | 18 +++--- 2 files changed, 115 insertions(+), 43 deletions(-) diff --git a/sokol/c/sokol_gl.h b/sokol/c/sokol_gl.h index 15b3880..654cb0f 100644 --- a/sokol/c/sokol_gl.h +++ b/sokol/c/sokol_gl.h @@ -372,8 +372,8 @@ the last call to sgl_draw() through sokol-gfx, and will 'rewind' the internal vertex-, uniform- and command-buffers. - --- each sokol-gl context tracks an internal error code, to query the - current error code for the currently active context call: + --- each sokol-gl context tracks internal error states which can + be obtains via: sgl_error_t sgl_error() @@ -381,18 +381,28 @@ sgl_error_t sgl_context_error(ctx); - ...which can return the following error codes: + ...this returns a struct with the following booleans: - SGL_NO_ERROR - all OK, no error occurred since last sgl_draw() - SGL_ERROR_VERTICES_FULL - internal vertex buffer is full (checked in sgl_end()) - SGL_ERROR_UNIFORMS_FULL - the internal uniforms buffer is full (checked in sgl_end()) - SGL_ERROR_COMMANDS_FULL - the internal command buffer is full (checked in sgl_end()) - SGL_ERROR_STACK_OVERFLOW - matrix- or pipeline-stack overflow - SGL_ERROR_STACK_UNDERFLOW - matrix- or pipeline-stack underflow - SGL_ERROR_NO_CONTEXT - the active context no longer exists + .any - true if any of the below errors is true + .vertices_full - internal vertex buffer is full (checked in sgl_end()) + .uniforms_full - the internal uniforms buffer is full (checked in sgl_end()) + .commands_full - the internal command buffer is full (checked in sgl_end()) + .stack_overflow - matrix- or pipeline-stack overflow + .stack_underflow - matrix- or pipeline-stack underflow + .no_context - the active context no longer exists - ...if sokol-gl is in an error-state, sgl_draw() will skip any rendering, - and reset the error code to SGL_NO_ERROR. + ...depending on the above error state, sgl_draw() may skip rendering + completely, or only draw partial geometry + + --- you can get the number of recorded vertices and draw commands in the current + frame and active sokol-gl context via: + + int sgl_num_vertices() + int sgl_num_commands() + + ...this allows you to check whether the vertex or command pools are running + full before the overflow actually happens (in this case you could also + check the error booleans in the result of sgl_error()). RENDER LAYERS ============= @@ -762,14 +772,14 @@ typedef struct sgl_context { uint32_t id; } sgl_context; Errors are reset each frame after calling sgl_draw(), get the last error code with sgl_error() */ -typedef enum sgl_error_t { - SGL_NO_ERROR = 0, - SGL_ERROR_VERTICES_FULL, - SGL_ERROR_UNIFORMS_FULL, - SGL_ERROR_COMMANDS_FULL, - SGL_ERROR_STACK_OVERFLOW, - SGL_ERROR_STACK_UNDERFLOW, - SGL_ERROR_NO_CONTEXT, +typedef struct sgl_error_t { + bool any; + bool vertices_full; + bool uniforms_full; + bool commands_full; + bool stack_overflow; + bool stack_underflow; + bool no_context; } sgl_error_t; /* @@ -832,6 +842,10 @@ SOKOL_GL_API_DECL void sgl_set_context(sgl_context ctx); SOKOL_GL_API_DECL sgl_context sgl_get_context(void); SOKOL_GL_API_DECL sgl_context sgl_default_context(void); +/* get information about recorded vertices and commands in current context */ +SOKOL_GL_API_DECL int sgl_num_vertices(void); +SOKOL_GL_API_DECL int sgl_num_commands(void); + /* draw recorded commands (call inside a sokol-gfx render pass) */ SOKOL_GL_API_DECL void sgl_draw(void); SOKOL_GL_API_DECL void sgl_context_draw(sgl_context ctx); @@ -2342,7 +2356,7 @@ typedef struct { /* state tracking */ int base_vertex; - int vtx_count; /* number of times vtx function has been called, used for non-triangle primitives */ + int quad_vtx_count; /* number of times vtx function has been called, used for non-triangle primitives */ sgl_error_t error; bool in_begin; int layer_id; @@ -2903,10 +2917,24 @@ static void _sgl_destroy_context(sgl_context ctx_id) { // ██ ██ ██ ███████ ██████ // // >>misc + +static sgl_error_t _sgl_error_defaults(void) { + sgl_error_t defaults = {0}; + return defaults; +} + +static int _sgl_num_vertices(_sgl_context_t* ctx) { + return ctx->vertices.next; +} + +static int _sgl_num_commands(_sgl_context_t* ctx) { + return ctx->commands.next; +} + static void _sgl_begin(_sgl_context_t* ctx, _sgl_primitive_type_t mode) { ctx->in_begin = true; ctx->base_vertex = ctx->vertices.next; - ctx->vtx_count = 0; + ctx->quad_vtx_count = 0; ctx->cur_prim_type = mode; } @@ -2916,7 +2944,7 @@ static void _sgl_rewind(_sgl_context_t* ctx) { ctx->uniforms.next = 0; ctx->commands.next = 0; ctx->base_vertex = 0; - ctx->error = SGL_NO_ERROR; + ctx->error = _sgl_error_defaults(); ctx->layer_id = 0; ctx->matrix_dirty = true; } @@ -2938,7 +2966,8 @@ static _sgl_vertex_t* _sgl_next_vertex(_sgl_context_t* ctx) { if (ctx->vertices.next < ctx->vertices.cap) { return &ctx->vertices.ptr[ctx->vertices.next++]; } else { - ctx->error = SGL_ERROR_VERTICES_FULL; + ctx->error.vertices_full = true; + ctx->error.any = true; return 0; } } @@ -2947,7 +2976,8 @@ static _sgl_uniform_t* _sgl_next_uniform(_sgl_context_t* ctx) { if (ctx->uniforms.next < ctx->uniforms.cap) { return &ctx->uniforms.ptr[ctx->uniforms.next++]; } else { - ctx->error = SGL_ERROR_UNIFORMS_FULL; + ctx->error.uniforms_full = true; + ctx->error.any = true; return 0; } } @@ -2964,7 +2994,8 @@ static _sgl_command_t* _sgl_next_command(_sgl_context_t* ctx) { if (ctx->commands.next < ctx->commands.cap) { return &ctx->commands.ptr[ctx->commands.next++]; } else { - ctx->error = SGL_ERROR_COMMANDS_FULL; + ctx->error.commands_full = true; + ctx->error.any = true; return 0; } } @@ -2991,7 +3022,7 @@ static void _sgl_vtx(_sgl_context_t* ctx, float x, float y, float z, float u, fl SOKOL_ASSERT(ctx->in_begin); _sgl_vertex_t* vtx; /* handle non-native primitive types */ - if ((ctx->cur_prim_type == SGL_PRIMITIVETYPE_QUADS) && ((ctx->vtx_count & 3) == 3)) { + if ((ctx->cur_prim_type == SGL_PRIMITIVETYPE_QUADS) && ((ctx->quad_vtx_count & 3) == 3)) { /* for quads, before writing the last quad vertex, reuse the first and third vertex to start the second triangle in the quad */ @@ -3007,7 +3038,7 @@ static void _sgl_vtx(_sgl_context_t* ctx, float x, float y, float z, float u, fl vtx->rgba = rgba; vtx->psize = ctx->point_size; } - ctx->vtx_count++; + ctx->quad_vtx_count++; } static void _sgl_identity(_sgl_matrix_t* m) { @@ -3342,7 +3373,7 @@ static bool _sgl_is_default_context(sgl_context ctx_id) { static void _sgl_draw(_sgl_context_t* ctx, int layer_id) { SOKOL_ASSERT(ctx); - if ((ctx->error == SGL_NO_ERROR) && (ctx->vertices.next > 0) && (ctx->commands.next > 0)) { + if ((ctx->vertices.next > 0) && (ctx->commands.next > 0)) { sg_push_debug_group("sokol-gl"); uint32_t cur_pip_id = SG_INVALID_ID; @@ -3356,6 +3387,8 @@ static void _sgl_draw(_sgl_context_t* ctx, int layer_id) { sg_update_buffer(ctx->vbuf, &range); } + // render all successfully recorded commands (this may be less than the + // issued commands if we're in an error state) for (int i = 0; i < ctx->commands.next; i++) { const _sgl_command_t* cmd = &ctx->commands.ptr[i]; if (cmd->layer_id != layer_id) { @@ -3463,7 +3496,10 @@ SOKOL_API_IMPL sgl_error_t sgl_error(void) { if (ctx) { return ctx->error; } else { - return SGL_ERROR_NO_CONTEXT; + sgl_error_t err = _sgl_error_defaults(); + err.no_context = true; + err.any = true; + return err; } } @@ -3472,7 +3508,10 @@ SOKOL_API_IMPL sgl_error_t sgl_context_error(sgl_context ctx_id) { if (ctx) { return ctx->error; } else { - return SGL_ERROR_NO_CONTEXT; + sgl_error_t err = _sgl_error_defaults(); + err.no_context = true; + err.any = true; + return err; } } @@ -3521,6 +3560,26 @@ SOKOL_API_IMPL sgl_context sgl_default_context(void) { return SGL_DEFAULT_CONTEXT; } +SOKOL_API_IMPL int sgl_num_vertices(void) { + SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); + _sgl_context_t* ctx = _sgl.cur_ctx; + if (ctx) { + return _sgl_num_vertices(ctx); + } else { + return 0; + } +} + +SOKOL_API_IMPL int sgl_num_commands(void) { + SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); + _sgl_context_t* ctx = _sgl.cur_ctx; + if (ctx) { + return _sgl_num_commands(ctx); + } else { + return 0; + } +} + SOKOL_API_IMPL sgl_pipeline sgl_make_pipeline(const sg_pipeline_desc* desc) { SOKOL_ASSERT(_SGL_INIT_COOKIE == _sgl.init_cookie); _sgl_context_t* ctx = _sgl.cur_ctx; @@ -3576,7 +3635,8 @@ SOKOL_API_IMPL void sgl_push_pipeline(void) { ctx->pip_tos++; ctx->pip_stack[ctx->pip_tos] = ctx->pip_stack[ctx->pip_tos-1]; } else { - ctx->error = SGL_ERROR_STACK_OVERFLOW; + ctx->error.stack_overflow = true; + ctx->error.any = true; } } @@ -3589,7 +3649,8 @@ SOKOL_API_IMPL void sgl_pop_pipeline(void) { if (ctx->pip_tos > 0) { ctx->pip_tos--; } else { - ctx->error = SGL_ERROR_STACK_UNDERFLOW; + ctx->error.stack_underflow = true; + ctx->error.any = true; } } @@ -3778,6 +3839,7 @@ SOKOL_API_IMPL void sgl_end(void) { SOKOL_ASSERT(ctx->in_begin); SOKOL_ASSERT(ctx->vertices.next >= ctx->base_vertex); ctx->in_begin = false; + bool matrix_dirty = ctx->matrix_dirty; if (matrix_dirty) { ctx->matrix_dirty = false; @@ -3787,6 +3849,12 @@ SOKOL_API_IMPL void sgl_end(void) { uni->tm = *_sgl_matrix_texture(ctx); } } + + // don't record any new commands when we're in an error state + if (ctx->error.any) { + return; + } + // check if command can be merged with current command sg_pipeline pip = _sgl_get_pipeline(ctx->pip_stack[ctx->pip_tos], ctx->cur_prim_type); sg_image img = ctx->texturing_enabled ? ctx->cur_img : _sgl.def_img; @@ -4205,7 +4273,8 @@ SOKOL_GL_API_DECL void sgl_push_matrix(void) { _sgl_matrix_t* dst = _sgl_matrix(ctx); *dst = *src; } else { - ctx->error = SGL_ERROR_STACK_OVERFLOW; + ctx->error.stack_overflow = true; + ctx->error.any = true; } } @@ -4220,7 +4289,8 @@ SOKOL_GL_API_DECL void sgl_pop_matrix(void) { if (ctx->matrix_tos[ctx->cur_matrix_mode] > 0) { ctx->matrix_tos[ctx->cur_matrix_mode]--; } else { - ctx->error = SGL_ERROR_STACK_UNDERFLOW; + ctx->error.stack_underflow = true; + ctx->error.any = true; } } diff --git a/sokol/gl/gl.odin b/sokol/gl/gl.odin index f0eada6..88143a5 100644 --- a/sokol/gl/gl.odin +++ b/sokol/gl/gl.odin @@ -78,6 +78,8 @@ foreign sokol_gl_clib { set_context :: proc(ctx: Context) --- get_context :: proc() -> Context --- default_context :: proc() -> Context --- + num_vertices :: proc() -> c.int --- + num_commands :: proc() -> c.int --- draw :: proc() --- context_draw :: proc(ctx: Context) --- draw_layer :: proc(#any_int layer_id: c.int) --- @@ -178,14 +180,14 @@ Context :: struct { id : u32, } -Error :: enum i32 { - NO_ERROR = 0, - VERTICES_FULL, - UNIFORMS_FULL, - COMMANDS_FULL, - STACK_OVERFLOW, - STACK_UNDERFLOW, - NO_CONTEXT, +Error :: struct { + any : bool, + vertices_full : bool, + uniforms_full : bool, + commands_full : bool, + stack_overflow : bool, + stack_underflow : bool, + no_context : bool, } Context_Desc :: struct { From eb025a82d3e6b9cdfe7ef4ca9a9f98bab7e5b28d Mon Sep 17 00:00:00 2001 From: GH Action Date: Sat, 31 Aug 2024 13:11:33 +0000 Subject: [PATCH 03/12] updated (https://github.com/floooh/sokol/commit/eacb44750081c1194ba1baac369dc48b4c94e81e) --- sokol/c/sokol_gfx.h | 108 +++++++++++++++++++++++++++++++++++--------- sokol/gfx/gfx.odin | 1 + 2 files changed, 87 insertions(+), 22 deletions(-) diff --git a/sokol/c/sokol_gfx.h b/sokol/c/sokol_gfx.h index 9e1321f..9e57392 100644 --- a/sokol/c/sokol_gfx.h +++ b/sokol/c/sokol_gfx.h @@ -1496,6 +1496,7 @@ .wgpu.num_bindgroup_cache_hits .wgpu.num_bindgroup_cache_misses .wgpu.num_bindgroup_cache_collisions + .wgpu_num_bindgroup_cache_invalidates .wgpu.num_bindgroup_cache_vs_hash_key_mismatch The value to pay attention to is `.wgpu.num_bindgroup_cache_collisions`, @@ -3482,6 +3483,7 @@ typedef struct sg_frame_stats_wgpu_bindings { uint32_t num_bindgroup_cache_hits; uint32_t num_bindgroup_cache_misses; uint32_t num_bindgroup_cache_collisions; + uint32_t num_bindgroup_cache_invalidates; uint32_t num_bindgroup_cache_hash_vs_key_mismatch; } sg_frame_stats_wgpu_bindings; @@ -5783,10 +5785,20 @@ typedef struct { uint32_t id; } _sg_wgpu_bindgroup_handle_t; -#define _SG_WGPU_BINDGROUPSCACHE_NUM_ITEMS (1 + _SG_WGPU_MAX_BINDGROUP_ENTRIES) +typedef enum { + _SG_WGPU_BINDGROUPSCACHEITEMTYPE_NONE = 0, + _SG_WGPU_BINDGROUPSCACHEITEMTYPE_IMAGE = 0x1111111111111111, + _SG_WGPU_BINDGROUPSCACHEITEMTYPE_SAMPLER = 0x2222222222222222, + _SG_WGPU_BINDGROUPSCACHEITEMTYPE_STORAGEBUFFER = 0x3333333333333333, + _SG_WGPU_BINDGROUPSCACHEITEMTYPE_PIPELINE = 0x4444444444444444, +} _sg_wgpu_bindgroups_cache_item_type_t; + +#define _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS (1 + _SG_WGPU_MAX_BINDGROUP_ENTRIES) typedef struct { uint64_t hash; - uint32_t items[_SG_WGPU_BINDGROUPSCACHE_NUM_ITEMS]; + // the format of cache key items is (_sg_wgpu_bindgroups_cache_item_type_t << 32) | handle.id, + // where the item type is a per-resource-type bit pattern + uint64_t items[_SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS]; } _sg_wgpu_bindgroups_cache_key_t; typedef struct { @@ -14034,6 +14046,26 @@ _SOKOL_PRIVATE uint64_t _sg_wgpu_hash(const void* key, int len, uint64_t seed) { return h; } +_SOKOL_PRIVATE uint64_t _sg_wgpu_bindgroups_cache_item(_sg_wgpu_bindgroups_cache_item_type_t type, uint32_t id) { + return (((uint64_t)type) << 32) | id; +} + +_SOKOL_PRIVATE uint64_t _sg_wgpu_bindgroups_cache_pip_item(uint32_t id) { + return _sg_wgpu_bindgroups_cache_item(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_PIPELINE, id); +} + +_SOKOL_PRIVATE uint64_t _sg_wgpu_bindgroups_cache_image_item(uint32_t id) { + return _sg_wgpu_bindgroups_cache_item(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_IMAGE, id); +} + +_SOKOL_PRIVATE uint64_t _sg_wgpu_bindgroups_cache_sampler_item(uint32_t id) { + return _sg_wgpu_bindgroups_cache_item(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_SAMPLER, id); +} + +_SOKOL_PRIVATE uint64_t _sg_wgpu_bindgroups_cache_sbuf_item(uint32_t id) { + return _sg_wgpu_bindgroups_cache_item(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_STORAGEBUFFER, id); +} + _SOKOL_PRIVATE void _sg_wgpu_init_bindgroups_cache_key(_sg_wgpu_bindgroups_cache_key_t* key, const _sg_bindings_t* bnd) { SOKOL_ASSERT(bnd); SOKOL_ASSERT(bnd->pip); @@ -14045,38 +14077,39 @@ _SOKOL_PRIVATE void _sg_wgpu_init_bindgroups_cache_key(_sg_wgpu_bindgroups_cache SOKOL_ASSERT(bnd->num_fs_sbufs <= SG_MAX_SHADERSTAGE_STORAGEBUFFERS); _sg_clear(key->items, sizeof(key->items)); - key->items[0] = bnd->pip->slot.id; - const int vs_imgs_offset = 1; - const int vs_smps_offset = vs_imgs_offset + SG_MAX_SHADERSTAGE_IMAGES; - const int vs_sbufs_offset = vs_smps_offset + SG_MAX_SHADERSTAGE_SAMPLERS; - const int fs_imgs_offset = vs_sbufs_offset + SG_MAX_SHADERSTAGE_STORAGEBUFFERS; - const int fs_smps_offset = fs_imgs_offset + SG_MAX_SHADERSTAGE_IMAGES; - const int fs_sbufs_offset = fs_smps_offset + SG_MAX_SHADERSTAGE_SAMPLERS; - SOKOL_ASSERT((fs_sbufs_offset + SG_MAX_SHADERSTAGE_STORAGEBUFFERS) == _SG_WGPU_BINDGROUPSCACHE_NUM_ITEMS); + int item_idx = 0; + key->items[item_idx++] = _sg_wgpu_bindgroups_cache_pip_item(bnd->pip->slot.id); for (int i = 0; i < bnd->num_vs_imgs; i++) { SOKOL_ASSERT(bnd->vs_imgs[i]); - key->items[vs_imgs_offset + i] = bnd->vs_imgs[i]->slot.id; + SOKOL_ASSERT(item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS); + key->items[item_idx++] = _sg_wgpu_bindgroups_cache_image_item(bnd->vs_imgs[i]->slot.id); } for (int i = 0; i < bnd->num_vs_smps; i++) { SOKOL_ASSERT(bnd->vs_smps[i]); - key->items[vs_smps_offset + i] = bnd->vs_smps[i]->slot.id; + SOKOL_ASSERT(item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS); + key->items[item_idx++] = _sg_wgpu_bindgroups_cache_sampler_item(bnd->vs_smps[i]->slot.id); } for (int i = 0; i < bnd->num_vs_sbufs; i++) { SOKOL_ASSERT(bnd->vs_sbufs[i]); - key->items[vs_sbufs_offset + i] = bnd->vs_sbufs[i]->slot.id; + SOKOL_ASSERT(item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS); + key->items[item_idx++] = _sg_wgpu_bindgroups_cache_sbuf_item(bnd->vs_sbufs[i]->slot.id); } for (int i = 0; i < bnd->num_fs_imgs; i++) { SOKOL_ASSERT(bnd->fs_imgs[i]); - key->items[fs_imgs_offset + i] = bnd->fs_imgs[i]->slot.id; + SOKOL_ASSERT(item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS); + key->items[item_idx++] = _sg_wgpu_bindgroups_cache_image_item(bnd->fs_imgs[i]->slot.id); } for (int i = 0; i < bnd->num_fs_smps; i++) { SOKOL_ASSERT(bnd->fs_smps[i]); - key->items[fs_smps_offset + i] = bnd->fs_smps[i]->slot.id; + SOKOL_ASSERT(item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS); + key->items[item_idx++] = _sg_wgpu_bindgroups_cache_sampler_item(bnd->fs_smps[i]->slot.id); } for (int i = 0; i < bnd->num_fs_sbufs; i++) { SOKOL_ASSERT(bnd->fs_sbufs[i]); - key->items[fs_sbufs_offset + i] = bnd->fs_sbufs[i]->slot.id; + SOKOL_ASSERT(item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS); + key->items[item_idx++] = _sg_wgpu_bindgroups_cache_sbuf_item(bnd->fs_sbufs[i]->slot.id); } + SOKOL_ASSERT(item_idx == (1 + bnd->num_vs_imgs + bnd->num_vs_smps + bnd->num_vs_sbufs + bnd->num_fs_imgs + bnd->num_fs_smps + bnd->num_fs_sbufs)); key->hash = _sg_wgpu_hash(&key->items, (int)sizeof(key->items), 0x1234567887654321); } @@ -14228,6 +14261,33 @@ _SOKOL_PRIVATE uint32_t _sg_wgpu_bindgroups_cache_get(uint64_t hash) { return _sg.wgpu.bindgroups_cache.items[index].id; } +// called from wgpu resource destroy functions to also invalidate any +// bindgroups cache slot and bindgroup referencing that resource +_SOKOL_PRIVATE void _sg_wgpu_bindgroups_cache_invalidate(_sg_wgpu_bindgroups_cache_item_type_t type, uint32_t id) { + const uint64_t key_item = _sg_wgpu_bindgroups_cache_item(type, id); + SOKOL_ASSERT(_sg.wgpu.bindgroups_cache.items); + for (uint32_t cache_item_idx = 0; cache_item_idx < _sg.wgpu.bindgroups_cache.num; cache_item_idx++) { + const uint32_t bg_id = _sg.wgpu.bindgroups_cache.items[cache_item_idx].id; + if (bg_id != SG_INVALID_ID) { + _sg_wgpu_bindgroup_t* bg = _sg_wgpu_lookup_bindgroup(bg_id); + SOKOL_ASSERT(bg && (bg->slot.state == SG_RESOURCESTATE_VALID)); + // check if resource is in bindgroup, if yes discard bindgroup and invalidate cache slot + bool invalidate_cache_item = false; + for (int key_item_idx = 0; key_item_idx < _SG_WGPU_BINDGROUPSCACHEKEY_NUM_ITEMS; key_item_idx++) { + if (bg->key.items[key_item_idx] == key_item) { + invalidate_cache_item = true; + break; + } + } + if (invalidate_cache_item) { + _sg_wgpu_discard_bindgroup(bg); bg = 0; + _sg_wgpu_bindgroups_cache_set(cache_item_idx, SG_INVALID_ID); + _sg_stats_add(wgpu.bindings.num_bindgroup_cache_invalidates, 1); + } + } + } +} + _SOKOL_PRIVATE void _sg_wgpu_bindings_cache_clear(void) { memset(&_sg.wgpu.bindings_cache, 0, sizeof(_sg.wgpu.bindings_cache)); } @@ -14288,7 +14348,7 @@ _SOKOL_PRIVATE void _sg_wgpu_bindings_cache_bg_update(const _sg_wgpu_bindgroup_t } } -_SOKOL_PRIVATE void _sg_wgpu_set_bindings_bindgroup(_sg_wgpu_bindgroup_t* bg) { +_SOKOL_PRIVATE void _sg_wgpu_set_bindgroup(_sg_wgpu_bindgroup_t* bg) { if (_sg_wgpu_bindings_cache_bg_dirty(bg)) { _sg_wgpu_bindings_cache_bg_update(bg); _sg_stats_add(wgpu.bindings.num_set_bindgroup, 1); @@ -14334,7 +14394,7 @@ _SOKOL_PRIVATE bool _sg_wgpu_apply_bindgroup(_sg_bindings_t* bnd) { _sg_wgpu_bindgroups_cache_set(key.hash, bg->slot.id); } if (bg && bg->slot.state == SG_RESOURCESTATE_VALID) { - _sg_wgpu_set_bindings_bindgroup(bg); + _sg_wgpu_set_bindgroup(bg); } else { return false; } @@ -14343,7 +14403,7 @@ _SOKOL_PRIVATE bool _sg_wgpu_apply_bindgroup(_sg_bindings_t* bnd) { _sg_wgpu_bindgroup_t* bg = _sg_wgpu_create_bindgroup(bnd); if (bg) { if (bg->slot.state == SG_RESOURCESTATE_VALID) { - _sg_wgpu_set_bindings_bindgroup(bg); + _sg_wgpu_set_bindgroup(bg); } _sg_wgpu_discard_bindgroup(bg); } else { @@ -14351,7 +14411,7 @@ _SOKOL_PRIVATE bool _sg_wgpu_apply_bindgroup(_sg_bindings_t* bnd) { } } } else { - _sg_wgpu_set_bindings_bindgroup(0); + _sg_wgpu_set_bindgroup(0); } return true; } @@ -14484,8 +14544,10 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_buffer(_sg_buffer_t* buf, const _SOKOL_PRIVATE void _sg_wgpu_discard_buffer(_sg_buffer_t* buf) { SOKOL_ASSERT(buf); + if (buf->cmn.type == SG_BUFFERTYPE_STORAGEBUFFER) { + _sg_wgpu_bindgroups_cache_invalidate(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_STORAGEBUFFER, buf->slot.id); + } if (buf->wgpu.buf) { - wgpuBufferDestroy(buf->wgpu.buf); wgpuBufferRelease(buf->wgpu.buf); } } @@ -14621,12 +14683,12 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_image(_sg_image_t* img, const s _SOKOL_PRIVATE void _sg_wgpu_discard_image(_sg_image_t* img) { SOKOL_ASSERT(img); + _sg_wgpu_bindgroups_cache_invalidate(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_IMAGE, img->slot.id); if (img->wgpu.view) { wgpuTextureViewRelease(img->wgpu.view); img->wgpu.view = 0; } if (img->wgpu.tex) { - wgpuTextureDestroy(img->wgpu.tex); wgpuTextureRelease(img->wgpu.tex); img->wgpu.tex = 0; } @@ -14667,6 +14729,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_sampler(_sg_sampler_t* smp, con _SOKOL_PRIVATE void _sg_wgpu_discard_sampler(_sg_sampler_t* smp) { SOKOL_ASSERT(smp); + _sg_wgpu_bindgroups_cache_invalidate(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_SAMPLER, smp->slot.id); if (smp->wgpu.smp) { wgpuSamplerRelease(smp->wgpu.smp); smp->wgpu.smp = 0; @@ -14904,6 +14967,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_pipeline(_sg_pipeline_t* pip, _ _SOKOL_PRIVATE void _sg_wgpu_discard_pipeline(_sg_pipeline_t* pip) { SOKOL_ASSERT(pip); + _sg_wgpu_bindgroups_cache_invalidate(_SG_WGPU_BINDGROUPSCACHEITEMTYPE_PIPELINE, pip->slot.id); if (pip == _sg.wgpu.cur_pipeline) { _sg.wgpu.cur_pipeline = 0; _sg.wgpu.cur_pipeline_id.id = SG_INVALID_ID; diff --git a/sokol/gfx/gfx.odin b/sokol/gfx/gfx.odin index 3cff0d9..ede2917 100644 --- a/sokol/gfx/gfx.odin +++ b/sokol/gfx/gfx.odin @@ -1062,6 +1062,7 @@ Frame_Stats_Wgpu_Bindings :: struct { num_bindgroup_cache_hits : u32, num_bindgroup_cache_misses : u32, num_bindgroup_cache_collisions : u32, + num_bindgroup_cache_invalidates : u32, num_bindgroup_cache_hash_vs_key_mismatch : u32, } From 962174dba0e5809988f166403c169fc9bcea32d7 Mon Sep 17 00:00:00 2001 From: Beau McCartney Date: Sat, 31 Aug 2024 23:24:29 -0600 Subject: [PATCH 04/12] fix -DSOKOL_GLCORE33 (to -DSOKOL_GLCORE) in macos dynlib build script --- sokol/build_clibs_macos_dylib.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sokol/build_clibs_macos_dylib.sh b/sokol/build_clibs_macos_dylib.sh index 6e0abc2..af5321b 100755 --- a/sokol/build_clibs_macos_dylib.sh +++ b/sokol/build_clibs_macos_dylib.sh @@ -42,9 +42,9 @@ build_lib_release sokol dylib/sokol_dylib_macos_arm64_metal_release SOKOL_METAL build_lib_debug sokol dylib/sokol_dylib_macos_arm64_metal_debug SOKOL_METAL arm64 build_lib_release sokol dylib/sokol_dylib_macos_x64_metal_release SOKOL_METAL x86_64 build_lib_debug sokol dylib/sokol_dylib_macos_x64_metal_debug SOKOL_METAL x86_64 -build_lib_release sokol dylib/sokol_dylib_macos_arm64_gl_release SOKOL_GLCORE33 arm64 -build_lib_debug sokol dylib/sokol_dylib_macos_arm64_gl_debug SOKOL_GLCORE33 arm64 -build_lib_release sokol dylib/sokol_dylib_macos_x64_gl_release SOKOL_GLCORE33 x86_64 -build_lib_debug sokol dylib/sokol_dylib_macos_x64_gl_debug SOKOL_GLCORE33 x86_64 +build_lib_release sokol dylib/sokol_dylib_macos_arm64_gl_release SOKOL_GLCORE arm64 +build_lib_debug sokol dylib/sokol_dylib_macos_arm64_gl_debug SOKOL_GLCORE arm64 +build_lib_release sokol dylib/sokol_dylib_macos_x64_gl_release SOKOL_GLCORE x86_64 +build_lib_debug sokol dylib/sokol_dylib_macos_x64_gl_debug SOKOL_GLCORE x86_64 rm *.o From 535cc827a5bb471a246954bccda98b988bb40b04 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Sun, 1 Sep 2024 14:28:43 +0200 Subject: [PATCH 05/12] gh actions: also run build_clibs_macos_dylib.sh --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 76a581c..413ae64 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -44,6 +44,7 @@ jobs: cd sokol chmod a+x ./build_clibs_macos.sh ./build_clibs_macos.sh + ./build_clibs_macos_dylib.sh cd .. - if: runner.os == 'Windows' name: prepare-windows From df19460c36f705e7c9f960d9fea9ff66a77472ff Mon Sep 17 00:00:00 2001 From: GH Action Date: Sun, 1 Sep 2024 13:54:40 +0000 Subject: [PATCH 06/12] updated (https://github.com/floooh/sokol/commit/189843bf4f86969ca4cc4b6d94e793a37c5128a7) --- sokol/c/sokol_gfx.h | 15 ++++++++++++++- sokol/gfx/gfx.odin | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/sokol/c/sokol_gfx.h b/sokol/c/sokol_gfx.h index 9e57392..7e94f9d 100644 --- a/sokol/c/sokol_gfx.h +++ b/sokol/c/sokol_gfx.h @@ -3889,6 +3889,12 @@ typedef enum sg_log_item { before sg_setup() is called .environment.d3d11.device_context a pointer to the ID3D11DeviceContext object + .d3d11_shader_debugging + set this to true to compile shaders which are provided as HLSL source + code with debug information and without optimization, this allows + shader debugging in tools like RenderDoc, to output source code + instead of byte code from sokol-shdc, omit the `--binary` cmdline + option WebGPU specific: .wgpu_disable_bindgroups_cache @@ -4001,6 +4007,7 @@ typedef struct sg_desc { int uniform_buffer_size; int max_commit_listeners; bool disable_validation; // disable validation layer even in debug mode, useful for tests + bool d3d11_shader_debugging; // if true, HLSL shaders are compiled with D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION bool mtl_force_managed_storage_mode; // for debugging: use Metal managed storage mode for resources even with UMA bool mtl_use_command_buffer_with_retained_references; // Metal: use a managed MTLCommandBuffer which ref-counts used resources bool wgpu_disable_bindgroups_cache; // set to true to disable the WebGPU backend BindGroup cache @@ -10712,6 +10719,12 @@ _SOKOL_PRIVATE ID3DBlob* _sg_d3d11_compile_shader(const sg_shader_stage_desc* st return NULL; } SOKOL_ASSERT(stage_desc->d3d11_target); + UINT flags1 = D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR; + if (_sg.desc.d3d11_shader_debugging) { + flags1 |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; + } else { + flags1 |= D3DCOMPILE_OPTIMIZATION_LEVEL3; + } ID3DBlob* output = NULL; ID3DBlob* errors_or_warnings = NULL; HRESULT hr = _sg.d3d11.D3DCompile_func( @@ -10722,7 +10735,7 @@ _SOKOL_PRIVATE ID3DBlob* _sg_d3d11_compile_shader(const sg_shader_stage_desc* st NULL, // pInclude stage_desc->entry ? stage_desc->entry : "main", // pEntryPoint stage_desc->d3d11_target, // pTarget - D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR | D3DCOMPILE_OPTIMIZATION_LEVEL3, // Flags1 + flags1, // Flags1 0, // Flags2 &output, // ppCode &errors_or_warnings); // ppErrorMsgs diff --git a/sokol/gfx/gfx.odin b/sokol/gfx/gfx.odin index ede2917..e9a6b06 100644 --- a/sokol/gfx/gfx.odin +++ b/sokol/gfx/gfx.odin @@ -1448,6 +1448,7 @@ Desc :: struct { uniform_buffer_size : c.int, max_commit_listeners : c.int, disable_validation : bool, + d3d11_shader_debugging : bool, mtl_force_managed_storage_mode : bool, mtl_use_command_buffer_with_retained_references : bool, wgpu_disable_bindgroups_cache : bool, From 953a205b9bae422d4e3afbb5b9fa9e51e59fc55f Mon Sep 17 00:00:00 2001 From: GH Action Date: Mon, 2 Sep 2024 11:09:17 +0000 Subject: [PATCH 07/12] updated (https://github.com/floooh/sokol/commit/ec18cd9eacde0cf641f3403eaaeac123e6155ff8) --- sokol/c/sokol_gfx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sokol/c/sokol_gfx.h b/sokol/c/sokol_gfx.h index 7e94f9d..57c24a7 100644 --- a/sokol/c/sokol_gfx.h +++ b/sokol/c/sokol_gfx.h @@ -963,7 +963,7 @@ ON STORAGE BUFFERS ================== Storage buffers can be used to pass large amounts of random access structured - data fromt the CPU side to the shaders. They are similar to data textures, but are + data from the CPU side to the shaders. They are similar to data textures, but are more convenient to use both on the CPU and shader side since they can be accessed in shaders as as a 1-dimensional array of struct items. From 09304654798814cbe0aa26382ef24a18eb246adb Mon Sep 17 00:00:00 2001 From: GH Action Date: Mon, 2 Sep 2024 12:45:56 +0000 Subject: [PATCH 08/12] updated (https://github.com/floooh/sokol/commit/c28138a2103b09a6545868d4bd271277170a1165) --- sokol/c/sokol_gfx.h | 18 +++--------------- sokol/gfx/gfx.odin | 3 --- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/sokol/c/sokol_gfx.h b/sokol/c/sokol_gfx.h index 57c24a7..9cf317a 100644 --- a/sokol/c/sokol_gfx.h +++ b/sokol/c/sokol_gfx.h @@ -2098,13 +2098,10 @@ typedef enum sg_primitive_type { used in the sg_sampler_desc.min_filter, sg_sampler_desc.mag_filter and sg_sampler_desc.mipmap_filter members when creating a sampler object. - For min_filter and mag_filter the default is SG_FILTER_NEAREST. - - For mipmap_filter the default is SG_FILTER_NONE. + For the default is SG_FILTER_NEAREST. */ typedef enum sg_filter { _SG_FILTER_DEFAULT, // value 0 reserved for default-init - SG_FILTER_NONE, // FIXME: deprecated SG_FILTER_NEAREST, SG_FILTER_LINEAR, _SG_FILTER_NUM, @@ -2893,7 +2890,7 @@ typedef struct sg_image_desc { .min_filter: SG_FILTER_NEAREST .mag_filter: SG_FILTER_NEAREST - .mipmap_filter SG_FILTER_NONE + .mipmap_filter SG_FILTER_NEAREST .wrap_u: SG_WRAP_REPEAT .wrap_v: SG_WRAP_REPEAT .wrap_w: SG_WRAP_REPEAT (only SG_IMAGETYPE_3D) @@ -3652,8 +3649,6 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_DYNAMIC_NO_DATA, "dynamic/stream images cannot be initialized with data") \ _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_COMPRESSED_IMMUTABLE, "compressed images must be immutable") \ _SG_LOGITEM_XMACRO(VALIDATE_SAMPLERDESC_CANARY, "sg_sampler_desc not initialized") \ - _SG_LOGITEM_XMACRO(VALIDATE_SAMPLERDESC_MINFILTER_NONE, "sg_sampler_desc.min_filter cannot be SG_FILTER_NONE") \ - _SG_LOGITEM_XMACRO(VALIDATE_SAMPLERDESC_MAGFILTER_NONE, "sg_sampler_desc.mag_filter cannot be SG_FILTER_NONE") \ _SG_LOGITEM_XMACRO(VALIDATE_SAMPLERDESC_ANISTROPIC_REQUIRES_LINEAR_FILTERING, "sg_sampler_desc.max_anisotropy > 1 requires min/mag/mipmap_filter to be SG_FILTER_LINEAR") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_CANARY, "sg_shader_desc not initialized") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_SOURCE, "shader source code required") \ @@ -7161,14 +7156,12 @@ _SOKOL_PRIVATE GLenum _sg_gl_blend_op(sg_blend_op op) { _SOKOL_PRIVATE GLenum _sg_gl_min_filter(sg_filter min_f, sg_filter mipmap_f) { if (min_f == SG_FILTER_NEAREST) { switch (mipmap_f) { - case SG_FILTER_NONE: return GL_NEAREST; case SG_FILTER_NEAREST: return GL_NEAREST_MIPMAP_NEAREST; case SG_FILTER_LINEAR: return GL_NEAREST_MIPMAP_LINEAR; default: SOKOL_UNREACHABLE; return (GLenum)0; } } else if (min_f == SG_FILTER_LINEAR) { switch (mipmap_f) { - case SG_FILTER_NONE: return GL_LINEAR; case SG_FILTER_NEAREST: return GL_LINEAR_MIPMAP_NEAREST; case SG_FILTER_LINEAR: return GL_LINEAR_MIPMAP_LINEAR; default: SOKOL_UNREACHABLE; return (GLenum)0; @@ -11907,8 +11900,6 @@ _SOKOL_PRIVATE MTLSamplerMinMagFilter _sg_mtl_minmag_filter(sg_filter f) { _SOKOL_PRIVATE MTLSamplerMipFilter _sg_mtl_mipmap_filter(sg_filter f) { switch (f) { - case SG_FILTER_NONE: - return MTLSamplerMipFilterNotMipmapped; case SG_FILTER_NEAREST: return MTLSamplerMipFilterNearest; case SG_FILTER_LINEAR: @@ -13464,7 +13455,6 @@ _SOKOL_PRIVATE WGPUFilterMode _sg_wgpu_sampler_minmag_filter(sg_filter f) { _SOKOL_PRIVATE WGPUMipmapFilterMode _sg_wgpu_sampler_mipmap_filter(sg_filter f) { switch (f) { - case SG_FILTER_NONE: case SG_FILTER_NEAREST: return WGPUMipmapFilterMode_Nearest; case SG_FILTER_LINEAR: @@ -16325,8 +16315,6 @@ _SOKOL_PRIVATE bool _sg_validate_sampler_desc(const sg_sampler_desc* desc) { _sg_validate_begin(); _SG_VALIDATE(desc->_start_canary == 0, VALIDATE_SAMPLERDESC_CANARY); _SG_VALIDATE(desc->_end_canary == 0, VALIDATE_SAMPLERDESC_CANARY); - _SG_VALIDATE(desc->min_filter != SG_FILTER_NONE, VALIDATE_SAMPLERDESC_MINFILTER_NONE); - _SG_VALIDATE(desc->mag_filter != SG_FILTER_NONE, VALIDATE_SAMPLERDESC_MAGFILTER_NONE); // restriction from WebGPU: when anisotropy > 1, all filters must be linear if (desc->max_anisotropy > 1) { _SG_VALIDATE((desc->min_filter == SG_FILTER_LINEAR) @@ -17146,7 +17134,7 @@ _SOKOL_PRIVATE sg_sampler_desc _sg_sampler_desc_defaults(const sg_sampler_desc* sg_sampler_desc def = *desc; def.min_filter = _sg_def(def.min_filter, SG_FILTER_NEAREST); def.mag_filter = _sg_def(def.mag_filter, SG_FILTER_NEAREST); - def.mipmap_filter = _sg_def(def.mipmap_filter, SG_FILTER_NONE); + def.mipmap_filter = _sg_def(def.mipmap_filter, SG_FILTER_NEAREST); def.wrap_u = _sg_def(def.wrap_u, SG_WRAP_REPEAT); def.wrap_v = _sg_def(def.wrap_v, SG_WRAP_REPEAT); def.wrap_w = _sg_def(def.wrap_w, SG_WRAP_REPEAT); diff --git a/sokol/gfx/gfx.odin b/sokol/gfx/gfx.odin index e9a6b06..dd1740e 100644 --- a/sokol/gfx/gfx.odin +++ b/sokol/gfx/gfx.odin @@ -444,7 +444,6 @@ Primitive_Type :: enum i32 { Filter :: enum i32 { DEFAULT, - NONE, NEAREST, LINEAR, } @@ -1222,8 +1221,6 @@ Log_Item :: enum i32 { VALIDATE_IMAGEDESC_DYNAMIC_NO_DATA, VALIDATE_IMAGEDESC_COMPRESSED_IMMUTABLE, VALIDATE_SAMPLERDESC_CANARY, - VALIDATE_SAMPLERDESC_MINFILTER_NONE, - VALIDATE_SAMPLERDESC_MAGFILTER_NONE, VALIDATE_SAMPLERDESC_ANISTROPIC_REQUIRES_LINEAR_FILTERING, VALIDATE_SHADERDESC_CANARY, VALIDATE_SHADERDESC_SOURCE, From d362055fd56dfe4b55a5a5d8ef8dec2c04e90997 Mon Sep 17 00:00:00 2001 From: GH Action Date: Tue, 10 Sep 2024 07:48:10 +0000 Subject: [PATCH 09/12] updated (https://github.com/floooh/sokol/commit/90186789884646f5fe640edea1d8441feb02f590) --- sokol/c/sokol_app.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sokol/c/sokol_app.h b/sokol/c/sokol_app.h index 790e9de..7cd29bf 100644 --- a/sokol/c/sokol_app.h +++ b/sokol/c/sokol_app.h @@ -8015,7 +8015,7 @@ _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) { #if defined(SOKOL_D3D11) _sapp_d3d11_destroy_default_render_target(); _sapp_d3d11_destroy_device_and_swapchain(); - #else + #elif defined(SOKOL_GLCORE) _sapp_wgl_destroy_context(); _sapp_wgl_shutdown(); #endif From baeac83382cdae9f41ecba21074a2326328ffa4a Mon Sep 17 00:00:00 2001 From: GH Action Date: Sun, 15 Sep 2024 16:21:47 +0000 Subject: [PATCH 10/12] updated (https://github.com/floooh/sokol/commit/f62817137961a1eedc3eac03f62012795d2c79c4) --- sokol/c/sokol_audio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sokol/c/sokol_audio.h b/sokol/c/sokol_audio.h index aca4942..960c42d 100644 --- a/sokol/c/sokol_audio.h +++ b/sokol/c/sokol_audio.h @@ -2473,7 +2473,7 @@ void _saudio_backend_shutdown(void) { #elif defined(SAUDIO_ANDROID_SLES) _saudio_sles_backend_shutdown(); #elif defined(_SAUDIO_APPLE) - return _saudio_coreaudio_backend_shutdown(); + _saudio_coreaudio_backend_shutdown(); #else #error "unknown platform" #endif From b499b4fe78a9f68be352e09f926f5716a9c40135 Mon Sep 17 00:00:00 2001 From: GH Action Date: Tue, 17 Sep 2024 17:16:51 +0000 Subject: [PATCH 11/12] updated (https://github.com/floooh/sokol/commit/15412a3c03a6a799d267599c5378a7422b14ab58) --- sokol/app/app.odin | 1 + sokol/c/sokol_app.h | 126 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 126 insertions(+), 1 deletion(-) diff --git a/sokol/app/app.odin b/sokol/app/app.odin index c6fc270..5ae9fe4 100644 --- a/sokol/app/app.odin +++ b/sokol/app/app.odin @@ -411,6 +411,7 @@ Log_Item :: enum i32 { LINUX_X11_OPEN_DISPLAY_FAILED, LINUX_X11_QUERY_SYSTEM_DPI_FAILED, LINUX_X11_DROPPED_FILE_URI_WRONG_SCHEME, + LINUX_X11_FAILED_TO_BECOME_OWNER_OF_CLIPBOARD, ANDROID_UNSUPPORTED_INPUT_EVENT_INPUT_CB, ANDROID_UNSUPPORTED_INPUT_EVENT_MAIN_CB, ANDROID_READ_MSG_FAILED, diff --git a/sokol/c/sokol_app.h b/sokol/c/sokol_app.h index 7cd29bf..97f72ab 100644 --- a/sokol/c/sokol_app.h +++ b/sokol/c/sokol_app.h @@ -130,7 +130,7 @@ screen keyboard | --- | --- | --- | YES | TODO | YES swap interval | YES | YES | YES | YES | TODO | YES high-dpi | YES | YES | TODO | YES | YES | YES - clipboard | YES | YES | TODO | --- | --- | YES + clipboard | YES | YES | YES | --- | --- | YES MSAA | YES | YES | YES | YES | YES | YES drag'n'drop | YES | YES | YES | --- | --- | YES window icon | YES | YES(1)| YES | --- | --- | YES @@ -1603,6 +1603,7 @@ typedef struct sapp_allocator { _SAPP_LOGITEM_XMACRO(LINUX_X11_OPEN_DISPLAY_FAILED, "XOpenDisplay() failed") \ _SAPP_LOGITEM_XMACRO(LINUX_X11_QUERY_SYSTEM_DPI_FAILED, "failed to query system dpi value, assuming default 96.0") \ _SAPP_LOGITEM_XMACRO(LINUX_X11_DROPPED_FILE_URI_WRONG_SCHEME, "dropped file URL doesn't start with 'file://'") \ + _SAPP_LOGITEM_XMACRO(LINUX_X11_FAILED_TO_BECOME_OWNER_OF_CLIPBOARD, "X11: Failed to become owner of clipboard selection") \ _SAPP_LOGITEM_XMACRO(ANDROID_UNSUPPORTED_INPUT_EVENT_INPUT_CB, "unsupported input event encountered in _sapp_android_input_cb()") \ _SAPP_LOGITEM_XMACRO(ANDROID_UNSUPPORTED_INPUT_EVENT_MAIN_CB, "unsupported input event encountered in _sapp_android_main_cb()") \ _SAPP_LOGITEM_XMACRO(ANDROID_READ_MSG_FAILED, "failed to read message in _sapp_android_main_cb()") \ @@ -2162,6 +2163,7 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #include /* LONG_MAX */ #include /* only used a linker-guard, search for _sapp_linux_run() and see first comment */ #include + #include #endif #if defined(_SAPP_APPLE) @@ -2752,6 +2754,8 @@ typedef struct { float dpi; unsigned char error_code; Atom UTF8_STRING; + Atom CLIPBOARD; + Atom TARGETS; Atom WM_PROTOCOLS; Atom WM_DELETE_WINDOW; Atom WM_STATE; @@ -9618,6 +9622,8 @@ _SOKOL_PRIVATE void _sapp_x11_init_extensions(void) { _sapp.x11.NET_WM_ICON = XInternAtom(_sapp.x11.display, "_NET_WM_ICON", False); _sapp.x11.NET_WM_STATE = XInternAtom(_sapp.x11.display, "_NET_WM_STATE", False); _sapp.x11.NET_WM_STATE_FULLSCREEN = XInternAtom(_sapp.x11.display, "_NET_WM_STATE_FULLSCREEN", False); + _sapp.x11.CLIPBOARD = XInternAtom(_sapp.x11.display, "CLIPBOARD", False); + _sapp.x11.TARGETS = XInternAtom(_sapp.x11.display, "TARGETS", False); if (_sapp.drop.enabled) { _sapp.x11.xdnd.XdndAware = XInternAtom(_sapp.x11.display, "XdndAware", False); _sapp.x11.xdnd.XdndEnter = XInternAtom(_sapp.x11.display, "XdndEnter", False); @@ -10463,6 +10469,75 @@ _SOKOL_PRIVATE void _sapp_x11_lock_mouse(bool lock) { XFlush(_sapp.x11.display); } +_SOKOL_PRIVATE void _sapp_x11_set_clipboard_string(const char* str) { + SOKOL_ASSERT(_sapp.clipboard.enabled && _sapp.clipboard.buffer); + if (strlen(str) >= (size_t)_sapp.clipboard.buf_size) { + _SAPP_ERROR(CLIPBOARD_STRING_TOO_BIG); + } + XSetSelectionOwner(_sapp.x11.display, _sapp.x11.CLIPBOARD, _sapp.x11.window, CurrentTime); + if (XGetSelectionOwner(_sapp.x11.display, _sapp.x11.CLIPBOARD) != _sapp.x11.window) { + _SAPP_ERROR(LINUX_X11_FAILED_TO_BECOME_OWNER_OF_CLIPBOARD); + } +} + +_SOKOL_PRIVATE const char* _sapp_x11_get_clipboard_string(void) { + SOKOL_ASSERT(_sapp.clipboard.enabled && _sapp.clipboard.buffer); + Atom none = XInternAtom(_sapp.x11.display, "SAPP_SELECTION", False); + Atom incremental = XInternAtom(_sapp.x11.display, "INCR", False); + if (XGetSelectionOwner(_sapp.x11.display, _sapp.x11.CLIPBOARD) == _sapp.x11.window) { + // Instead of doing a large number of X round-trips just to put this + // string into a window property and then read it back, just return it + return _sapp.clipboard.buffer; + } + XConvertSelection(_sapp.x11.display, + _sapp.x11.CLIPBOARD, + _sapp.x11.UTF8_STRING, + none, + _sapp.x11.window, + CurrentTime); + XEvent event; + while (!XCheckTypedWindowEvent(_sapp.x11.display, _sapp.x11.window, SelectionNotify, &event)) { + // Wait for event data to arrive on the X11 display socket + struct pollfd fd = { ConnectionNumber(_sapp.x11.display), POLLIN }; + while (!XPending(_sapp.x11.display)) { + poll(&fd, 1, -1); + } + } + if (event.xselection.property == None) { + return NULL; + } + char* data = NULL; + Atom actualType; + int actualFormat; + unsigned long itemCount, bytesAfter; + const bool ret = XGetWindowProperty(_sapp.x11.display, + event.xselection.requestor, + event.xselection.property, + 0, + LONG_MAX, + True, + _sapp.x11.UTF8_STRING, + &actualType, + &actualFormat, + &itemCount, + &bytesAfter, + (unsigned char**) &data); + if (ret != Success || data == NULL) { + if (data != NULL) { + XFree(data); + } + return NULL; + } + if ((actualType == incremental) || (itemCount >= (size_t)_sapp.clipboard.buf_size)) { + _SAPP_ERROR(CLIPBOARD_STRING_TOO_BIG); + XFree(data); + return NULL; + } + _sapp_strcpy(data, _sapp.clipboard.buffer, _sapp.clipboard.buf_size); + XFree(data); + return _sapp.clipboard.buffer; +} + _SOKOL_PRIVATE void _sapp_x11_update_window_title(void) { Xutf8SetWMProperties(_sapp.x11.display, _sapp.x11.window, @@ -11202,6 +11277,48 @@ _SOKOL_PRIVATE void _sapp_x11_on_clientmessage(XEvent* event) { } } +_SOKOL_PRIVATE void _sapp_x11_on_selectionrequest(XEvent* event) { + XSelectionRequestEvent* req = &event->xselectionrequest; + if (req->selection != _sapp.x11.CLIPBOARD) { + return; + } + if (!_sapp.clipboard.enabled) { + return; + } + SOKOL_ASSERT(_sapp.clipboard.buffer); + XSelectionEvent reply; + _sapp_clear(&reply, sizeof(reply)); + reply.type = SelectionNotify; + reply.display = req->display; + reply.requestor = req->requestor; + reply.selection = req->selection; + reply.target = req->target; + reply.property = req->property; + reply.time = req->time; + if (req->target == _sapp.x11.UTF8_STRING) { + XChangeProperty(_sapp.x11.display, + req->requestor, + req->property, + _sapp.x11.UTF8_STRING, + 8, + PropModeReplace, + (unsigned char*) _sapp.clipboard.buffer, + strlen(_sapp.clipboard.buffer)); + } else if (req->target == _sapp.x11.TARGETS) { + XChangeProperty(_sapp.x11.display, + req->requestor, + req->property, + XA_ATOM, + 32, + PropModeReplace, + (unsigned char*) &_sapp.x11.UTF8_STRING, + 1); + } else { + reply.property = None; + } + XSendEvent(_sapp.x11.display, req->requestor, False, 0, (XEvent*) &reply); +} + _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { switch (event->type) { case GenericEvent: @@ -11243,6 +11360,9 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { case SelectionNotify: _sapp_x11_on_selectionnotify(event); break; + case SelectionRequest: + _sapp_x11_on_selectionrequest(event); + break; case DestroyNotify: // not a bug break; @@ -11723,6 +11843,8 @@ SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) { _sapp_emsc_set_clipboard_string(str); #elif defined(_SAPP_WIN32) _sapp_win32_set_clipboard_string(str); + #elif defined(_SAPP_LINUX) + _sapp_x11_set_clipboard_string(str); #else /* not implemented */ #endif @@ -11739,6 +11861,8 @@ SOKOL_API_IMPL const char* sapp_get_clipboard_string(void) { return _sapp.clipboard.buffer; #elif defined(_SAPP_WIN32) return _sapp_win32_get_clipboard_string(); + #elif defined(_SAPP_LINUX) + return _sapp_x11_get_clipboard_string(); #else /* not implemented */ return _sapp.clipboard.buffer; From a459fd5b2b1b50382ce8845d896fe5194b8fc898 Mon Sep 17 00:00:00 2001 From: GH Action Date: Fri, 20 Sep 2024 16:08:28 +0000 Subject: [PATCH 12/12] updated (https://github.com/floooh/sokol/commit/689c8268792e77be70b54e311d89eb87045966e7) --- sokol/c/sokol_gl.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sokol/c/sokol_gl.h b/sokol/c/sokol_gl.h index 654cb0f..f2b3262 100644 --- a/sokol/c/sokol_gl.h +++ b/sokol/c/sokol_gl.h @@ -2919,7 +2919,8 @@ static void _sgl_destroy_context(sgl_context ctx_id) { // >>misc static sgl_error_t _sgl_error_defaults(void) { - sgl_error_t defaults = {0}; + sgl_error_t defaults; + _sgl_clear(&defaults, sizeof(defaults)); return defaults; }