2
0
Эх сурвалжийг харах

Merge pull request #1169 from floooh/simgui-image-handles

sokol_imgui.h: simplify ImTextureID handling.
Andre Weissflog 9 сар өмнө
parent
commit
789d97071d

+ 17 - 0
CHANGELOG.md

@@ -1,5 +1,22 @@
 ## Updates
 
+### 17-Dec-2024
+
+- sokol_imgui.h (breaking change): user-provided images and samplers are now
+  stashed directly in a Dear ImGui ImTextureID handle instead of in a separate backing
+  object (this is possible now because ImTextureID is now guaranteed to be 64 bits,
+  so it can directly hold two 32-bit sokol-gfx handles). This change drastically
+  simplifies the sokol_imgui.h implementatation, but requires some breaking API
+  changes (please read the updated doc section `ON USER-PROVIDED IMAGES AND SAMPLERS`
+  in sokol_imgui.h)
+- sokol_gfx.h: a couple of new functions to get granular buffer and image properties
+  called `sg_query_buffer_[property]()` and `sg_query_image_[property]()`. Those are
+  cheaper than the similar `sg_query_buffer_desc()` and `sg_query_image_desc()`
+  functions if you only need to get one or few properties.
+- sokol_gfx_imgui.h: internal non-breaking fixes for the sokol_imgui.h API update.
+
+Associated PR: https://github.com/floooh/sokol/pull/1169
+
 ### 14-Dec-2024
 
 - sokol_app.h win32: merged PR https://github.com/floooh/sokol/pull/1167, this

+ 112 - 0
sokol_gfx.h

@@ -4249,6 +4249,18 @@ SOKOL_GFX_API_DECL sg_sampler_desc sg_query_sampler_defaults(const sg_sampler_de
 SOKOL_GFX_API_DECL sg_shader_desc sg_query_shader_defaults(const sg_shader_desc* desc);
 SOKOL_GFX_API_DECL sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_desc* desc);
 SOKOL_GFX_API_DECL sg_attachments_desc sg_query_attachments_defaults(const sg_attachments_desc* desc);
+// assorted query functions
+SOKOL_GFX_API_DECL size_t sg_query_buffer_size(sg_buffer buf);
+SOKOL_GFX_API_DECL sg_buffer_type sg_query_buffer_type(sg_buffer buf);
+SOKOL_GFX_API_DECL sg_usage sg_query_buffer_usage(sg_buffer buf);
+SOKOL_GFX_API_DECL sg_image_type sg_query_image_type(sg_image img);
+SOKOL_GFX_API_DECL int sg_query_image_width(sg_image img);
+SOKOL_GFX_API_DECL int sg_query_image_height(sg_image img);
+SOKOL_GFX_API_DECL int sg_query_image_num_slices(sg_image img);
+SOKOL_GFX_API_DECL int sg_query_image_num_mipmaps(sg_image img);
+SOKOL_GFX_API_DECL sg_pixel_format sg_query_image_pixelformat(sg_image img);
+SOKOL_GFX_API_DECL sg_usage sg_query_image_usage(sg_image img);
+SOKOL_GFX_API_DECL int sg_query_image_sample_count(sg_image img);
 
 // separate resource allocation and initialization (for async setup)
 SOKOL_GFX_API_DECL sg_buffer sg_alloc_buffer(void);
@@ -19228,6 +19240,33 @@ SOKOL_API_IMPL sg_buffer_desc sg_query_buffer_desc(sg_buffer buf_id) {
     return desc;
 }
 
+SOKOL_API_IMPL size_t sg_query_buffer_size(sg_buffer buf_id) {
+    SOKOL_ASSERT(_sg.valid);
+    const _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id);
+    if (buf) {
+        return (size_t)buf->cmn.size;
+    }
+    return 0;
+}
+
+SOKOL_API_IMPL sg_buffer_type sg_query_buffer_type(sg_buffer buf_id) {
+    SOKOL_ASSERT(_sg.valid);
+    const _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id);
+    if (buf) {
+        return buf->cmn.type;
+    }
+    return _SG_BUFFERTYPE_DEFAULT;
+}
+
+SOKOL_API_IMPL sg_usage sg_query_buffer_usage(sg_buffer buf_id) {
+    SOKOL_ASSERT(_sg.valid);
+    const _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id);
+    if (buf) {
+        return buf->cmn.usage;
+    }
+    return _SG_USAGE_DEFAULT;
+}
+
 SOKOL_API_IMPL sg_image_desc sg_query_image_desc(sg_image img_id) {
     SOKOL_ASSERT(_sg.valid);
     sg_image_desc desc;
@@ -19247,6 +19286,79 @@ SOKOL_API_IMPL sg_image_desc sg_query_image_desc(sg_image img_id) {
     return desc;
 }
 
+SOKOL_API_IMPL sg_image_type sg_query_image_type(sg_image img_id) {
+    SOKOL_ASSERT(_sg.valid);
+    const _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id);
+    if (img) {
+        return img->cmn.type;
+    }
+    return _SG_IMAGETYPE_DEFAULT;
+}
+
+SOKOL_API_IMPL int sg_query_image_width(sg_image img_id) {
+    SOKOL_ASSERT(_sg.valid);
+    const _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id);
+    if (img) {
+        return img->cmn.width;
+    }
+    return 0;
+}
+
+SOKOL_API_IMPL int sg_query_image_height(sg_image img_id) {
+    SOKOL_ASSERT(_sg.valid);
+    const _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id);
+    if (img) {
+        return img->cmn.height;
+    }
+    return 0;
+}
+
+SOKOL_API_IMPL int sg_query_image_num_slices(sg_image img_id) {
+    SOKOL_ASSERT(_sg.valid);
+    const _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id);
+    if (img) {
+        return img->cmn.num_slices;
+    }
+    return 0;
+}
+
+SOKOL_API_IMPL int sg_query_image_num_mipmaps(sg_image img_id) {
+    SOKOL_ASSERT(_sg.valid);
+    const _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id);
+    if (img) {
+        return img->cmn.num_mipmaps;
+    }
+    return 0;
+}
+
+SOKOL_API_IMPL sg_pixel_format sg_query_image_pixelformat(sg_image img_id) {
+    SOKOL_ASSERT(_sg.valid);
+    const _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id);
+    if (img) {
+        return img->cmn.pixel_format;
+    }
+    return _SG_PIXELFORMAT_DEFAULT;
+}
+
+SOKOL_API_IMPL sg_usage sg_query_image_usage(sg_image img_id) {
+    SOKOL_ASSERT(_sg.valid);
+    const _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id);
+    if (img) {
+        return img->cmn.usage;
+    }
+    return _SG_USAGE_DEFAULT;
+}
+
+SOKOL_API_IMPL int sg_query_image_sample_count(sg_image img_id) {
+    SOKOL_ASSERT(_sg.valid);
+    SOKOL_ASSERT(_sg.valid);
+    const _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id);
+    if (img) {
+        return img->cmn.sample_count;
+    }
+    return 0;
+}
+
 SOKOL_API_IMPL sg_sampler_desc sg_query_sampler_desc(sg_sampler smp_id) {
     SOKOL_ASSERT(_sg.valid);
     sg_sampler_desc desc;

+ 26 - 0
tests/functional/sokol_gfx_test.c

@@ -918,6 +918,9 @@ UTEST(sokol_gfx, query_buffer_desc) {
     T(b0_desc.mtl_buffers[0] == 0);
     T(b0_desc.d3d11_buffer == 0);
     T(b0_desc.wgpu_buffer == 0);
+    T(sg_query_buffer_size(b0) == 32);
+    T(sg_query_buffer_type(b0) == SG_BUFFERTYPE_VERTEXBUFFER);
+    T(sg_query_buffer_usage(b0) == SG_USAGE_STREAM);
 
     float vtx_data[16];
     sg_buffer b1 = sg_make_buffer(&(sg_buffer_desc){
@@ -929,6 +932,9 @@ UTEST(sokol_gfx, query_buffer_desc) {
     T(b1_desc.usage == SG_USAGE_IMMUTABLE);
     T(b1_desc.data.ptr == 0);
     T(b1_desc.data.size == 0);
+    T(sg_query_buffer_size(b1) == sizeof(vtx_data));
+    T(sg_query_buffer_type(b1) == SG_BUFFERTYPE_VERTEXBUFFER);
+    T(sg_query_buffer_usage(b1) == SG_USAGE_IMMUTABLE);
 
     uint16_t idx_data[8];
     sg_buffer b2 = sg_make_buffer(&(sg_buffer_desc){
@@ -941,6 +947,9 @@ UTEST(sokol_gfx, query_buffer_desc) {
     T(b2_desc.usage == SG_USAGE_IMMUTABLE);
     T(b2_desc.data.ptr == 0);
     T(b2_desc.data.size == 0);
+    T(sg_query_buffer_size(b2) == sizeof(idx_data));
+    T(sg_query_buffer_type(b2) == SG_BUFFERTYPE_INDEXBUFFER);
+    T(sg_query_buffer_usage(b2) == SG_USAGE_IMMUTABLE);
 
     // invalid buffer (returns zeroed desc)
     sg_buffer b3 = sg_make_buffer(&(sg_buffer_desc){
@@ -953,6 +962,9 @@ UTEST(sokol_gfx, query_buffer_desc) {
     T(b3_desc.size == 0);
     T(b3_desc.type == 0);
     T(b3_desc.usage == 0);
+    T(sg_query_buffer_size(b3) == 0);
+    T(sg_query_buffer_type(b3) == _SG_BUFFERTYPE_DEFAULT);
+    T(sg_query_buffer_usage(b3) == _SG_USAGE_DEFAULT);
 
     sg_shutdown();
 }
@@ -984,6 +996,13 @@ UTEST(sokol_gfx, query_image_desc) {
     T(i0_desc.d3d11_texture == 0);
     T(i0_desc.d3d11_shader_resource_view == 0);
     T(i0_desc.wgpu_texture == 0);
+    T(sg_query_image_type(i0) == SG_IMAGETYPE_2D);
+    T(sg_query_image_width(i0) == 256);
+    T(sg_query_image_height(i0) == 512);
+    T(sg_query_image_num_slices(i0) == 1);
+    T(sg_query_image_num_mipmaps(i0) == 1);
+    T(sg_query_image_pixelformat(i0) == SG_PIXELFORMAT_R8);
+    T(sg_query_image_sample_count(i0) == 1);
 
     sg_destroy_image(i0);
     const sg_image_desc i0_desc_x = sg_query_image_desc(i0);
@@ -996,6 +1015,13 @@ UTEST(sokol_gfx, query_image_desc) {
     T(i0_desc_x.usage == 0);
     T(i0_desc_x.pixel_format == 0);
     T(i0_desc_x.sample_count == 0);
+    T(sg_query_image_type(i0) == _SG_IMAGETYPE_DEFAULT);
+    T(sg_query_image_width(i0) == 0);
+    T(sg_query_image_height(i0) == 0);
+    T(sg_query_image_num_slices(i0) == 0);
+    T(sg_query_image_num_mipmaps(i0) == 0);
+    T(sg_query_image_pixelformat(i0) == _SG_PIXELFORMAT_DEFAULT);
+    T(sg_query_image_sample_count(i0) == 0);
 
     sg_shutdown();
 }

+ 1 - 8
util/sokol_gfx_imgui.h

@@ -260,7 +260,6 @@ typedef struct sgimgui_image_t {
     float ui_scale;
     sgimgui_str_t label;
     sg_image_desc desc;
-    simgui_image_t simgui_img;
 } sgimgui_image_t;
 
 typedef struct sgimgui_sampler_t {
@@ -1577,18 +1576,12 @@ _SOKOL_PRIVATE void _sgimgui_image_created(sgimgui_t* ctx, sg_image res_id, int
     img->desc = *desc;
     img->ui_scale = 1.0f;
     img->label = _sgimgui_make_str(desc->label);
-    simgui_image_desc_t simgui_img_desc;
-    _sgimgui_clear(&simgui_img_desc, sizeof(simgui_img_desc));
-    simgui_img_desc.image = res_id;
-    // keep sampler at default, which will use sokol_imgui.h's default nearest-filtering sampler
-    img->simgui_img = simgui_make_image(&simgui_img_desc);
 }
 
 _SOKOL_PRIVATE void _sgimgui_image_destroyed(sgimgui_t* ctx, int slot_index) {
     SOKOL_ASSERT((slot_index > 0) && (slot_index < ctx->image_window.num_slots));
     sgimgui_image_t* img = &ctx->image_window.slots[slot_index];
     img->res_id.id = SG_INVALID_ID;
-    simgui_destroy_image(img->simgui_img);
 }
 
 _SOKOL_PRIVATE void _sgimgui_sampler_created(sgimgui_t* ctx, sg_sampler res_id, int slot_index, const sg_sampler_desc* desc) {
@@ -3362,7 +3355,7 @@ _SOKOL_PRIVATE void _sgimgui_draw_embedded_image(sgimgui_t* ctx, sg_image img, f
             igSliderFloatEx("Scale", scale, 0.125f, 8.0f, "%.3f", ImGuiSliderFlags_Logarithmic);
             float w = (float)img_ui->desc.width * (*scale);
             float h = (float)img_ui->desc.height * (*scale);
-            igImage(simgui_imtextureid(img_ui->simgui_img), IMVEC2(w, h));
+            igImage(simgui_imtextureid(img_ui->res_id), IMVEC2(w, h));
             igPopID();
         } else {
             igText("Image not renderable.");

+ 47 - 390
util/sokol_imgui.h

@@ -112,13 +112,9 @@
                 sokol-imgui will use this to compute the size of the vertex-
                 and index-buffers allocated via sokol_gfx.h
 
-            int image_pool_size
-                Number of simgui_image_t objects which can be alive at the same time.
-                The default is 256.
-
             sg_pixel_format color_format
                 The color pixel format of the render pass where the UI
-                will be rendered. The default (0) matches sokoL_gfx.h's
+                will be rendered. The default (0) matches sokol_gfx.h's
                 default pass.
 
             sg_pixel_format depth_format
@@ -236,49 +232,37 @@
 
     ON USER-PROVIDED IMAGES AND SAMPLERS
     ====================================
-    To render your own images via ImGui::Image(), first create an simgui_image_t
-    object from a sokol-gfx image and sampler object.
-
-        // create a sokol-imgui image object which associates an sg_image with an sg_sampler
-        simgui_image_t simgui_img = simgui_make_image(&(simgui_image_desc_t){
-            .image = sg_make_image(...),
-            .sampler = sg_make_sampler(...),
-        });
-
-        // convert the returned image handle into a ImTextureID handle
-        ImTextureID tex_id = simgui_imtextureid(simgui_img);
-
-        // use the ImTextureID handle in Dear ImGui calls:
-        ImGui::Image(tex_id, ...);
-
-    simgui_image_t objects are small and cheap (literally just the image and sampler
-    handle).
+    To render your own images via ImGui::Image() you need to create a Dear ImGui
+    compatible texture handle (ImTextureID) from a sokol-gfx image handle
+    or optionally an image handle and a compatible sampler handle.
 
-    You can omit the sampler handle in the simgui_make_image() call, in this case a
-    default sampler will be used with nearest-filtering and clamp-to-edge.
+    To create a ImTextureID from a sokol-gfx image handle, call:
 
-    Trying to render with an invalid simgui_image_t handle will render a small 8x8
-    white default texture instead.
+        sg_image img= ...;
+        ImTextureID imtex_id = simgui_imtextureid(img);
 
-    To destroy a sokol-imgui image object, call
+    Since no sampler is provided, such a texture handle will use a default
+    sampler with nearest filtering and clamp-to-edge.
 
-        simgui_destroy_image(simgui_img);
+    If you need to render with a different sampler, do this instead:
 
-    But please be aware that the image object needs to be around until simgui_render() is called
-    in a frame (if this turns out to be too much of a hassle we could introduce some sort
-    of garbage collection where destroyed simgui_image_t objects are kept around until
-    the simgui_render() call).
+        sg_image img = ...;
+        sg_sampler smp = ...;
+        ImTextureID imtex_id = simgui_imtextureid_with_sampler(img, smp);
 
-    You can call:
+    You don't need to 'release' the ImTextureID handle, the ImTextureID
+    bits is simply a combination of the sg_image and sg_sampler bits.
 
-        simgui_image_desc_t desc = simgui_query_image_desc(img)
+    Once you have constructed an ImTextureID handle via simgui_imtextureid()
+    or simgui_imtextureid_with_sampler(), it used in the ImGui::Image()
+    call like this:
 
-    ...to get the original desc struct, useful if you need to get the sokol-gfx image
-    and sampler handle of the simgui_image_t object.
+        ImGui::Image(imtex_id, ...);
 
-    You can convert an ImTextureID back into an simgui_image_t handle:
+    To extract the sg_image and sg_sampler handle from an ImTextureID:
 
-        simgui_image_t img = simgui_image_from_imtextureid(tex_id);
+        sg_image img = simgui_image_from_imtextureid(imtex_id);
+        sg_sampler smp = simgui_sampler_from_imtextureid(imtex_id);
 
 
     MEMORY ALLOCATION OVERRIDE
@@ -426,33 +410,6 @@
 extern "C" {
 #endif
 
-enum {
-    SIMGUI_INVALID_ID = 0,
-};
-
-/*
-    simgui_image_t
-
-    A combined image-sampler pair used to inject custom images and samplers into Dear ImGui.
-
-    Create with simgui_make_image(), and convert to an ImTextureID handle via
-    simgui_imtextureid().
-*/
-typedef struct simgui_image_t { uint32_t id; } simgui_image_t;
-
-/*
-    simgui_image_desc_t
-
-    Descriptor struct for simgui_make_image(). You must provide
-    at least an sg_image handle. Keeping the sg_sampler handle
-    zero-initialized will select the builtin default sampler
-    which uses linear filtering.
-*/
-typedef struct simgui_image_desc_t {
-    sg_image image;
-    sg_sampler sampler;
-} simgui_image_desc_t;
-
 /*
     simgui_log_item
 
@@ -462,7 +419,6 @@ typedef struct simgui_image_desc_t {
 #define _SIMGUI_LOG_ITEMS \
     _SIMGUI_LOGITEM_XMACRO(OK, "Ok") \
     _SIMGUI_LOGITEM_XMACRO(MALLOC_FAILED, "memory allocation failed") \
-    _SIMGUI_LOGITEM_XMACRO(IMAGE_POOL_EXHAUSTED, "image pool exhausted") \
 
 #define _SIMGUI_LOGITEM_XMACRO(item,msg) SIMGUI_LOGITEM_##item,
 typedef enum simgui_log_item_t {
@@ -508,7 +464,6 @@ typedef struct simgui_logger_t {
 
 typedef struct simgui_desc_t {
     int max_vertices;               // default: 65536
-    int image_pool_size;            // default: 256
     sg_pixel_format color_format;
     sg_pixel_format depth_format;
     int sample_count;
@@ -537,11 +492,10 @@ typedef struct simgui_font_tex_desc_t {
 SOKOL_IMGUI_API_DECL void simgui_setup(const simgui_desc_t* desc);
 SOKOL_IMGUI_API_DECL void simgui_new_frame(const simgui_frame_desc_t* desc);
 SOKOL_IMGUI_API_DECL void simgui_render(void);
-SOKOL_IMGUI_API_DECL simgui_image_t simgui_make_image(const simgui_image_desc_t* desc);
-SOKOL_IMGUI_API_DECL void simgui_destroy_image(simgui_image_t img);
-SOKOL_IMGUI_API_DECL simgui_image_desc_t simgui_query_image_desc(simgui_image_t img);
-SOKOL_IMGUI_API_DECL uint64_t simgui_imtextureid(simgui_image_t img);
-SOKOL_IMGUI_API_DECL simgui_image_t simgui_image_from_imtextureid(uint64_t im_texture_id);
+SOKOL_IMGUI_API_DECL uint64_t simgui_imtextureid(sg_image img);
+SOKOL_IMGUI_API_DECL uint64_t simgui_imtextureid_with_sampler(sg_image img, sg_sampler smp);
+SOKOL_IMGUI_API_DECL sg_image simgui_image_from_imtextureid(uint64_t imtex_id);
+SOKOL_IMGUI_API_DECL sg_sampler simgui_sampler_from_imtextureid(uint64_t imtex_id);
 SOKOL_IMGUI_API_DECL void simgui_add_focus_event(bool focus);
 SOKOL_IMGUI_API_DECL void simgui_add_mouse_pos_event(float x, float y);
 SOKOL_IMGUI_API_DECL void simgui_add_touch_pos_event(float x, float y);
@@ -564,7 +518,6 @@ SOKOL_IMGUI_API_DECL void simgui_destroy_fonts_texture(void);
 
 // reference-based equivalents for C++
 inline void simgui_setup(const simgui_desc_t& desc) { return simgui_setup(&desc); }
-inline simgui_image_t simgui_make_image(const simgui_image_desc_t& desc) { return simgui_make_image(&desc); }
 inline void simgui_new_frame(const simgui_frame_desc_t& desc) { return simgui_new_frame(&desc); }
 inline void simgui_create_fonts_texture(const simgui_font_tex_desc_t& desc) { return simgui_create_fonts_texture(&desc); }
 
@@ -624,58 +577,15 @@ inline void simgui_create_fonts_texture(const simgui_font_tex_desc_t& desc) { re
 #endif
 
 #define _SIMGUI_INIT_COOKIE (0xBABEBABE)
-#define _SIMGUI_INVALID_SLOT_INDEX (0)
-#define _SIMGUI_SLOT_SHIFT (16)
-#define _SIMGUI_MAX_POOL_SIZE (1<<_SIMGUI_SLOT_SHIFT)
-#define _SIMGUI_SLOT_MASK (_SIMGUI_MAX_POOL_SIZE-1)
 
 // helper macros and constants
 #define _simgui_def(val, def) (((val) == 0) ? (def) : (val))
 
-// workaround for missing ImDrawCallback_ResetRenderState in cimgui.h
-// see: https://github.com/cimgui/cimgui/issues/261
-#ifndef ImDrawCallback_ResetRenderState
-#define ImDrawCallback_ResetRenderState (ImDrawCallback)(-8)
-#endif
-
 typedef struct {
     ImVec2 disp_size;
     uint8_t _pad_8[8];
 } _simgui_vs_params_t;
 
-typedef enum {
-    _SIMGUI_RESOURCESTATE_INITIAL,
-    _SIMGUI_RESOURCESTATE_ALLOC,
-    _SIMGUI_RESOURCESTATE_VALID,
-    _SIMGUI_RESOURCESTATE_FAILED,
-    _SIMGUI_RESOURCESTATE_INVALID,
-    _SIMGUI_RESOURCESTATE_FORCE_U32 = 0x7FFFFFFF
-} _simgui_resource_state;
-
-typedef struct {
-    uint32_t id;
-    _simgui_resource_state state;
-} _simgui_slot_t;
-
-typedef struct {
-    int size;
-    int queue_top;
-    uint32_t* gen_ctrs;
-    int* free_queue;
-} _simgui_pool_t;
-
-typedef struct {
-    _simgui_slot_t slot;
-    sg_image image;
-    sg_sampler sampler;
-    sg_pipeline pip;    // this will either be _simgui.def_pip or _simgui.pip_unfilterable
-} _simgui_image_t;
-
-typedef struct {
-    _simgui_pool_t pool;
-    _simgui_image_t* items;
-} _simgui_image_pool_t;
-
 typedef struct {
     uint32_t init_cookie;
     simgui_desc_t desc;
@@ -684,7 +594,6 @@ typedef struct {
     sg_buffer ibuf;
     sg_image font_img;
     sg_sampler font_smp;
-    simgui_image_t default_font;
     sg_image def_img;       // used as default image for user images
     sg_sampler def_smp;     // used as default sampler for user images
     sg_shader def_shd;
@@ -695,7 +604,6 @@ typedef struct {
     sg_range vertices;
     sg_range indices;
     bool is_osx;
-    _simgui_image_pool_t image_pool;
 } _simgui_state_t;
 static _simgui_state_t _simgui;
 
@@ -2393,12 +2301,6 @@ static void* _simgui_malloc(size_t size) {
     return ptr;
 }
 
-static void* _simgui_malloc_clear(size_t size) {
-    void* ptr = _simgui_malloc(size);
-    _simgui_clear(ptr, size);
-    return ptr;
-}
-
 static void _simgui_free(void* ptr) {
     if (_simgui.desc.allocator.free_fn) {
         _simgui.desc.allocator.free_fn(ptr, _simgui.desc.allocator.user_data);
@@ -2407,208 +2309,6 @@ static void _simgui_free(void* ptr) {
     }
 }
 
-// ██████   ██████   ██████  ██
-// ██   ██ ██    ██ ██    ██ ██
-// ██████  ██    ██ ██    ██ ██
-// ██      ██    ██ ██    ██ ██
-// ██       ██████   ██████  ███████
-//
-// >>pool
-static void _simgui_init_pool(_simgui_pool_t* pool, int num) {
-    SOKOL_ASSERT(pool && (num >= 1));
-    // slot 0 is reserved for the 'invalid id', so bump the pool size by 1
-    pool->size = num + 1;
-    pool->queue_top = 0;
-    // generation counters indexable by pool slot index, slot 0 is reserved
-    size_t gen_ctrs_size = sizeof(uint32_t) * (size_t)pool->size;
-    pool->gen_ctrs = (uint32_t*) _simgui_malloc_clear(gen_ctrs_size);
-    // it's not a bug to only reserve 'num' here
-    pool->free_queue = (int*) _simgui_malloc_clear(sizeof(int) * (size_t)num);
-    // never allocate the zero-th pool item since the invalid id is 0
-    for (int i = pool->size-1; i >= 1; i--) {
-        pool->free_queue[pool->queue_top++] = i;
-    }
-}
-
-static void _simgui_discard_pool(_simgui_pool_t* pool) {
-    SOKOL_ASSERT(pool);
-    SOKOL_ASSERT(pool->free_queue);
-    _simgui_free(pool->free_queue);
-    pool->free_queue = 0;
-    SOKOL_ASSERT(pool->gen_ctrs);
-    _simgui_free(pool->gen_ctrs);
-    pool->gen_ctrs = 0;
-    pool->size = 0;
-    pool->queue_top = 0;
-}
-
-static int _simgui_pool_alloc_index(_simgui_pool_t* pool) {
-    SOKOL_ASSERT(pool);
-    SOKOL_ASSERT(pool->free_queue);
-    if (pool->queue_top > 0) {
-        int slot_index = pool->free_queue[--pool->queue_top];
-        SOKOL_ASSERT((slot_index > 0) && (slot_index < pool->size));
-        return slot_index;
-    } else {
-        // pool exhausted
-        return _SIMGUI_INVALID_SLOT_INDEX;
-    }
-}
-
-static void _simgui_pool_free_index(_simgui_pool_t* pool, int slot_index) {
-    SOKOL_ASSERT((slot_index > _SIMGUI_INVALID_SLOT_INDEX) && (slot_index < pool->size));
-    SOKOL_ASSERT(pool);
-    SOKOL_ASSERT(pool->free_queue);
-    SOKOL_ASSERT(pool->queue_top < pool->size);
-    #ifdef SOKOL_DEBUG
-    // debug check against double-free
-    for (int i = 0; i < pool->queue_top; i++) {
-        SOKOL_ASSERT(pool->free_queue[i] != slot_index);
-    }
-    #endif
-    pool->free_queue[pool->queue_top++] = slot_index;
-    SOKOL_ASSERT(pool->queue_top <= (pool->size-1));
-}
-
-/* initialize a pool slot:
-    - bump the slot's generation counter
-    - create a resource id from the generation counter and slot index
-    - set the slot's id to this id
-    - set the slot's state to ALLOC
-    - return the handle id
-*/
-static uint32_t _simgui_slot_init(_simgui_pool_t* pool, _simgui_slot_t* slot, int slot_index) {
-    /* FIXME: add handling for an overflowing generation counter,
-       for now, just overflow (another option is to disable
-       the slot)
-    */
-    SOKOL_ASSERT(pool && pool->gen_ctrs);
-    SOKOL_ASSERT((slot_index > _SIMGUI_INVALID_SLOT_INDEX) && (slot_index < pool->size));
-    SOKOL_ASSERT((slot->state == _SIMGUI_RESOURCESTATE_INITIAL) && (slot->id == SIMGUI_INVALID_ID));
-    uint32_t ctr = ++pool->gen_ctrs[slot_index];
-    slot->id = (ctr<<_SIMGUI_SLOT_SHIFT)|(slot_index & _SIMGUI_SLOT_MASK);
-    slot->state = _SIMGUI_RESOURCESTATE_ALLOC;
-    return slot->id;
-}
-
-// extract slot index from id
-static int _simgui_slot_index(uint32_t id) {
-    int slot_index = (int) (id & _SIMGUI_SLOT_MASK);
-    SOKOL_ASSERT(_SIMGUI_INVALID_SLOT_INDEX != slot_index);
-    return slot_index;
-}
-
-static void _simgui_init_item_pool(_simgui_pool_t* pool, int pool_size, void** items_ptr, size_t item_size_bytes) {
-    // NOTE: the pools will have an additional item, since slot 0 is reserved
-    SOKOL_ASSERT(pool && (pool->size == 0));
-    SOKOL_ASSERT((pool_size > 0) && (pool_size < _SIMGUI_MAX_POOL_SIZE));
-    SOKOL_ASSERT(items_ptr && (*items_ptr == 0));
-    SOKOL_ASSERT(item_size_bytes > 0);
-    _simgui_init_pool(pool, pool_size);
-    const size_t pool_size_bytes = item_size_bytes * (size_t)pool->size;
-    *items_ptr = _simgui_malloc_clear(pool_size_bytes);
-}
-
-static void _simgui_discard_item_pool(_simgui_pool_t* pool, void** items_ptr) {
-    SOKOL_ASSERT(pool && (pool->size != 0));
-    SOKOL_ASSERT(items_ptr && (*items_ptr != 0));
-    _simgui_free(*items_ptr); *items_ptr = 0;
-    _simgui_discard_pool(pool);
-}
-
-static void _simgui_setup_image_pool(int pool_size) {
-    _simgui_image_pool_t* p = &_simgui.image_pool;
-    _simgui_init_item_pool(&p->pool, pool_size, (void**)&p->items, sizeof(_simgui_image_t));
-}
-
-static void _simgui_discard_image_pool(void) {
-    _simgui_image_pool_t* p = &_simgui.image_pool;
-    _simgui_discard_item_pool(&p->pool, (void**)&p->items);
-}
-
-static simgui_image_t _simgui_make_image_handle(uint32_t id) {
-    simgui_image_t handle = { id };
-    return handle;
-}
-
-static _simgui_image_t* _simgui_image_at(uint32_t id) {
-    SOKOL_ASSERT(SIMGUI_INVALID_ID != id);
-    const _simgui_image_pool_t* p = &_simgui.image_pool;
-    int slot_index = _simgui_slot_index(id);
-    SOKOL_ASSERT((slot_index > _SIMGUI_INVALID_SLOT_INDEX) && (slot_index < p->pool.size));
-    return &p->items[slot_index];
-}
-
-static _simgui_image_t* _simgui_lookup_image(uint32_t id) {
-    if (SIMGUI_INVALID_ID != id) {
-        _simgui_image_t* img = _simgui_image_at(id);
-        if (img->slot.id == id) {
-            return img;
-        }
-    }
-    return 0;
-}
-
-static simgui_image_t _simgui_alloc_image(void) {
-    _simgui_image_pool_t* p = &_simgui.image_pool;
-    int slot_index = _simgui_pool_alloc_index(&p->pool);
-    if (_SIMGUI_INVALID_SLOT_INDEX != slot_index) {
-        uint32_t id = _simgui_slot_init(&p->pool, &p->items[slot_index].slot, slot_index);
-        return _simgui_make_image_handle(id);
-    } else {
-        // pool exhausted
-        return _simgui_make_image_handle(SIMGUI_INVALID_ID);
-    }
-}
-
-static _simgui_resource_state _simgui_init_image(_simgui_image_t* img, const simgui_image_desc_t* desc) {
-    SOKOL_ASSERT(img && (img->slot.state == _SIMGUI_RESOURCESTATE_ALLOC));
-    SOKOL_ASSERT(desc);
-    SOKOL_ASSERT(_simgui.def_pip.id != SIMGUI_INVALID_ID);
-    SOKOL_ASSERT(_simgui.pip_unfilterable.id != SIMGUI_INVALID_ID);
-    img->image = desc->image;
-    img->sampler = desc->sampler;
-    if (sg_query_pixelformat(sg_query_image_desc(desc->image).pixel_format).filter) {
-        img->pip = _simgui.def_pip;
-    } else {
-        img->pip = _simgui.pip_unfilterable;
-    }
-    return _SIMGUI_RESOURCESTATE_VALID;
-}
-
-static void _simgui_deinit_image(_simgui_image_t* img) {
-    SOKOL_ASSERT(img);
-    img->image.id = SIMGUI_INVALID_ID;
-    img->sampler.id = SIMGUI_INVALID_ID;
-    img->pip.id = SIMGUI_INVALID_ID;
-}
-
-static void _simgui_destroy_image(simgui_image_t img_id) {
-    _simgui_image_t* img = _simgui_lookup_image(img_id.id);
-    if (img) {
-        _simgui_deinit_image(img);
-        _simgui_image_pool_t* p = &_simgui.image_pool;
-        _simgui_clear(img, sizeof(_simgui_image_t));
-        _simgui_pool_free_index(&p->pool, _simgui_slot_index(img_id.id));
-    }
-}
-
-static void _simgui_destroy_all_images(void) {
-    _simgui_image_pool_t* p = &_simgui.image_pool;
-    for (int i = 0; i < p->pool.size; i++) {
-        _simgui_image_t* img = &p->items[i];
-        _simgui_destroy_image(_simgui_make_image_handle(img->slot.id));
-    }
-}
-
-static simgui_image_desc_t _simgui_image_desc_defaults(const simgui_image_desc_t* desc) {
-    SOKOL_ASSERT(desc);
-    simgui_image_desc_t res = *desc;
-    res.image.id = _simgui_def(res.image.id, _simgui.def_img.id);
-    res.sampler.id = _simgui_def(res.sampler.id, _simgui.def_smp.id);
-    return res;
-}
-
 static bool _simgui_is_osx(void) {
     #if defined(SOKOL_DUMMY_BACKEND)
         return false;
@@ -2625,7 +2325,6 @@ static simgui_desc_t _simgui_desc_defaults(const simgui_desc_t* desc) {
     SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn));
     simgui_desc_t res = *desc;
     res.max_vertices = _simgui_def(res.max_vertices, 65536);
-    res.image_pool_size = _simgui_def(res.image_pool_size, 256);
     return res;
 }
 
@@ -2648,9 +2347,6 @@ SOKOL_API_IMPL void simgui_setup(const simgui_desc_t* desc) {
     // can keep color_format, depth_format and sample_count as is,
     // since sokol_gfx.h will do its own default-value handling
 
-    // setup image pool
-    _simgui_setup_image_pool(_simgui.desc.image_pool_size);
-
     // allocate an intermediate vertex- and index-buffer
     SOKOL_ASSERT(_simgui.desc.max_vertices > 0);
     _simgui.vertices.size = (size_t)_simgui.desc.max_vertices * sizeof(ImDrawVert);
@@ -2862,7 +2558,6 @@ SOKOL_API_IMPL void simgui_create_fonts_texture(const simgui_font_tex_desc_t* de
     SOKOL_ASSERT(desc);
     SOKOL_ASSERT(SG_INVALID_ID == _simgui.font_smp.id);
     SOKOL_ASSERT(SG_INVALID_ID == _simgui.font_img.id);
-    SOKOL_ASSERT(SIMGUI_INVALID_ID == _simgui.default_font.id);
 
     #if defined(__cplusplus)
         ImGuiIO* io = &ImGui::GetIO();
@@ -2898,22 +2593,15 @@ SOKOL_API_IMPL void simgui_create_fonts_texture(const simgui_font_tex_desc_t* de
     font_img_desc.label = "sokol-imgui-font-image";
     _simgui.font_img = sg_make_image(&font_img_desc);
 
-    simgui_image_desc_t img_desc;
-    _simgui_clear(&img_desc, sizeof(img_desc));
-    img_desc.image = _simgui.font_img;
-    img_desc.sampler = _simgui.font_smp;
-    _simgui.default_font = simgui_make_image(&img_desc);
-    io->Fonts->TexID = simgui_imtextureid(_simgui.default_font);
+    io->Fonts->TexID = simgui_imtextureid_with_sampler(_simgui.font_img, _simgui.font_smp);
 }
 
 SOKOL_API_IMPL void simgui_destroy_fonts_texture(void) {
     // NOTE: it's valid to call the destroy funcs with SG_INVALID_ID
     sg_destroy_sampler(_simgui.font_smp);
     sg_destroy_image(_simgui.font_img);
-    simgui_destroy_image(_simgui.default_font);
     _simgui.font_smp.id = SG_INVALID_ID;
     _simgui.font_img.id = SG_INVALID_ID;
-    _simgui.default_font.id = SIMGUI_INVALID_ID;
 }
 
 SOKOL_API_IMPL void simgui_shutdown(void) {
@@ -2936,8 +2624,6 @@ SOKOL_API_IMPL void simgui_shutdown(void) {
     sg_destroy_buffer(_simgui.vbuf);
     sg_pop_debug_group();
     sg_push_debug_group("sokol-imgui");
-    _simgui_destroy_all_images();
-    _simgui_discard_image_pool();
     SOKOL_ASSERT(_simgui.vertices.ptr);
     _simgui_free((void*)_simgui.vertices.ptr);
     SOKOL_ASSERT(_simgui.indices.ptr);
@@ -2945,47 +2631,24 @@ SOKOL_API_IMPL void simgui_shutdown(void) {
     _simgui.init_cookie = 0;
 }
 
-SOKOL_API_IMPL simgui_image_t simgui_make_image(const simgui_image_desc_t* desc) {
-    SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie);
-    SOKOL_ASSERT(desc);
-    const simgui_image_desc_t desc_def = _simgui_image_desc_defaults(desc);
-    simgui_image_t img_id = _simgui_alloc_image();
-    _simgui_image_t* img = _simgui_lookup_image(img_id.id);
-    if (img) {
-        img->slot.state = _simgui_init_image(img, &desc_def);
-        SOKOL_ASSERT((img->slot.state == _SIMGUI_RESOURCESTATE_VALID) || (img->slot.state == _SIMGUI_RESOURCESTATE_FAILED));
-    } else {
-        _SIMGUI_ERROR(IMAGE_POOL_EXHAUSTED);
-    }
-    return img_id;
-}
-
-SOKOL_API_IMPL void simgui_destroy_image(simgui_image_t img_id) {
-    SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie);
-    _simgui_destroy_image(img_id);
+SOKOL_API_IMPL uint64_t simgui_imtextureid_with_sampler(sg_image img, sg_sampler smp) {
+    uint32_t img_id = img.id;
+    uint32_t smp_id = smp.id;
+    return (((uint64_t)smp_id)<<32) | img_id;
 }
 
-SOKOL_API_IMPL simgui_image_desc_t simgui_query_image_desc(simgui_image_t img_id) {
-    SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie);
-    _simgui_image_t* img = _simgui_lookup_image(img_id.id);
-    simgui_image_desc_t desc;
-    _simgui_clear(&desc, sizeof(desc));
-    if (img) {
-        desc.image = img->image;
-        desc.sampler = img->sampler;
-    }
-    return desc;
+SOKOL_API_IMPL uint64_t simgui_imtextureid(sg_image img) {
+    return simgui_imtextureid_with_sampler(img, _simgui.def_smp);
 }
 
-SOKOL_API_IMPL uint64_t simgui_imtextureid(simgui_image_t img) {
-    SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie);
-    return (uint64_t)(uintptr_t)img.id;
+SOKOL_API_IMPL sg_image simgui_image_from_imtextureid(uint64_t imtex_id) {
+    sg_image img = { (uint32_t)imtex_id };
+    return img;
 }
 
-SOKOL_API_IMPL simgui_image_t simgui_image_from_imtextureid(uint64_t im_texture_id) {
-    SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie);
-    simgui_image_t img = { (uint32_t)im_texture_id };
-    return img;
+SOKOL_API_IMPL sg_sampler simgui_sampler_from_imtextureid(uint64_t imtex_id) {
+    sg_sampler smp = { (uint32_t)(imtex_id >> 32) };
+    return smp;
 }
 
 SOKOL_API_IMPL void simgui_new_frame(const simgui_frame_desc_t* desc) {
@@ -3044,16 +2707,14 @@ SOKOL_API_IMPL void simgui_new_frame(const simgui_frame_desc_t* desc) {
     #endif
 }
 
-static const _simgui_image_t* _simgui_bind_image_sampler(sg_bindings* bindings, ImTextureID tex_id) {
-    const _simgui_image_t* img = _simgui_lookup_image((uint32_t)(uintptr_t)tex_id);
-    if (img) {
-        bindings->images[0] = img->image;
-        bindings->samplers[0] = img->sampler;
+static sg_pipeline _simgui_bind_image_sampler(sg_bindings* bindings, ImTextureID imtex_id) {
+    bindings->images[0] = simgui_image_from_imtextureid(imtex_id);
+    bindings->samplers[0] = simgui_sampler_from_imtextureid(imtex_id);
+    if (sg_query_pixelformat(sg_query_image_pixelformat(bindings->images[0])).filter) {
+        return _simgui.def_pip;
     } else {
-        bindings->images[0] = _simgui.def_img;
-        bindings->samplers[0] = _simgui.def_smp;
+        return _simgui.pip_unfilterable;
     }
-    return img;
 }
 
 static ImDrawList* _simgui_imdrawlist_at(ImDrawData* draw_data, int cl_index) {
@@ -3185,12 +2846,8 @@ SOKOL_API_IMPL void simgui_render(void) {
                 if ((tex_id != pcmd->TextureId) || (vtx_offset != pcmd->VtxOffset)) {
                     tex_id = pcmd->TextureId;
                     vtx_offset = pcmd->VtxOffset;
-                    const _simgui_image_t* img = _simgui_bind_image_sampler(&bind, tex_id);
-                    if (img) {
-                        sg_apply_pipeline(img->pip);
-                    } else {
-                        sg_apply_pipeline(_simgui.def_pip);
-                    }
+                    sg_pipeline pip = _simgui_bind_image_sampler(&bind, tex_id);
+                    sg_apply_pipeline(pip);
                     sg_apply_uniforms(0, SG_RANGE_REF(vs_params));
                     bind.vertex_buffer_offsets[0] = vb_offset + (int)(pcmd->VtxOffset * sizeof(ImDrawVert));
                     sg_apply_bindings(&bind);