floooh / sokol

minimal cross-platform standalone C headers
https://floooh.github.io/sokol-html5
zlib License
6.55k stars 469 forks source link

Questions about Textures and Samplers used with imgui #968

Closed voidware closed 5 months ago

voidware commented 5 months ago

Version changelog 7 Jan, 24;

I've just updated to this (latest version). Today, i've been battling with the the texture and sampler separation in the shaders.

I have it working, but can you verify/explain a few things for me...

Q1 Font Atlas

I make my own font atlas texture now like this:

        sg_image_desc img_desc = { };
        img_desc.width = font_width;
        img_desc.height = font_height;
        img_desc.pixel_format = SG_PIXELFORMAT_RGBA8;
        img_desc.data.subimage[0][0].ptr = font_pixels;
        img_desc.data.subimage[0][0].size = font_width * font_height * 4;
        sg_image sgi = sg_make_image(&img_desc);

        sg_sampler_desc sampd = {};
        sampd.min_filter = SG_FILTER_LINEAR;
        sampd.mag_filter = SG_FILTER_LINEAR;
        sampd.wrap_u = SG_WRAP_CLAMP_TO_EDGE;
        sampd.wrap_v = SG_WRAP_CLAMP_TO_EDGE;
        sg_sampler ss = sg_make_sampler(&sampd);

        simgui_image_desc_t foo{ sgi, ss };
        simgui_image_t si = simgui_make_image(&foo); 
        io.Fonts->TexID = simgui_imtextureid(si);

So create a sampler. If i don't, the fonts look terrible. Perhaps default sampler is not LINEAR. Anyway, my question is, will sokol know to destroy the image and sampler when i clear the font for another one. when i do this:

        io.Fonts->ClearTexData();

Or do i manually need to do it? I think it used to delete the texture.

Q2 Using Textures

I have a custom control that draws images. I Create them like this:

        sg_image_desc sgid = {};
        sgid.width = it._w;
        sgid.height = it._h;
        sgid.pixel_format = SG_PIXELFORMAT_RGBA8;
        auto& si = sgid.data.subimage[0][0];
        si.ptr = r._dstate->_pix;
        si.size = it._imageSize; 
        sg_image sgi = sg_make_image(&sgid);

        res = sgi.id != 0;
        if (res)
        {
            sg_image_info ifo;
            ifo = sg_query_image_info(sgi);
            res = ifo.slot.state == SG_RESOURCESTATE_VALID;
        }

        if (res)
        {
            // drop data, decoder and pix but not TID
            sg_sampler_desc sampd = {};
            sampd.min_filter = SG_FILTER_LINEAR;
            sampd.mag_filter = SG_FILTER_LINEAR;
            sampd.wrap_u = SG_WRAP_CLAMP_TO_EDGE;
            sampd.wrap_v = SG_WRAP_CLAMP_TO_EDGE;
            sg_sampler ss = sg_make_sampler(&sampd);

            simgui_image_desc_t foo{ sgi, ss };
            simgui_image_t si = simgui_make_image(&foo);
            it._tid = simgui_imtextureid(si);
            r.purgeData();
            r._state = rec_finished;
        }
        else
        {
            sg_destroy_image(sgi);
        }

This code is made more complex by the need to check the resource pool, but my question relates to the addition of the sampler above

because:

When i destroy the texture, do i do this;

            simgui_image_t si = simgui_image_from_imtextureid(_tid);
            simgui_image_desc_t sid = simgui_query_image_desc(si);
            sg_destroy_image(sid.image);
            sg_destroy_sampler(sid.sampler); // ok if blank?
            simgui_destroy_image(si);

My question is whether i am supposed to separately destroy the image and the sampler as well as the simgui_image or does simgui_destroy_image to that as wll for me?

Q3 Samplers in general

In the examples above i created separate samplers for each texture image im using. Could i have used the same sampler, held globally somewhere? or would that cause a problem if two textures renders in the same scene?

Thanks for your help. much appreciated.

floooh commented 5 months ago

For Q1: check out how it's done in the imgui-highdpi-sapp sample:

https://github.com/floooh/sokol-samples/blob/59d548eea08b34a4c157098221375997594414e1/sapp/imgui-highdpi-sapp.cc#L45-L67

If you switch to a different font you need to clean up everything yourself, e.g. call simgui_destroy_image(), sg_destroy_image()... you can re-use the sampler object for the next call to simgui_make_image() though. It might also work to just switch out the texture without invaliding the simgui_image_t handle, e.g. just call sg_uninit_image() and sg_init_image() without calling simgui_destroy_image() and simgui_make_image(), this "switcheroo" is untested though.

My question is whether i am supposed to separately destroy the image and the sampler as well as the simgui_image or does simgui_destroy_image to that as wll for me?

Nope, simgui_destroy_image() will not destroy the underlying sg_image and sg_sampler it will only 'destroy' the simgui_image_t handle, e.g. see:

https://github.com/floooh/sokol/blob/5cd323a5f0fb040d942a8d11cc5a8d4bc055cc61/util/sokol_imgui.h#L2100-L2115

Could i have used the same sampler, held globally somewhere?

Yes, you can share the same sampler object between multiple textures, and also use the same texture with different samplers (e.g. have one texture, but two samplers, one with linear and one with nearest filtering, and create two simgui_image_t handles to render the same texture with linear or nearest filtering). This ability to freely combine texture and sampler object was the main reason why 3D APIs other than OpenGL have separate texture and sampler objects.

It also makes a lot of sense to only create a handful of sampler objects with all the sampler state combinations you need, and re-use them for everything throughout the lifetime of your application. Samplers are 'cheap and small' though, so if it makes more sense in your code to have many of them (e.g. one per texture) that's not a problem either.

voidware commented 5 months ago

Thanks a lot for the clarification and answers. Looks like i was doing mostly the right thing, except for clearing the font texture when changing. Setup was ok.

Also, I'll probably now create one shared sampler, so things will be simpler anyhow. Good to know that will work.

floooh commented 5 months ago

Closing the ticket if that's ok.

voidware commented 5 months ago

Yes thanks, everything good. I fixed my leak when destroying the font atlas, everything else ok. Also use of shared samplers works fine.