Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sokol_gfx: Issue creating render target #936

Closed
leiradel opened this issue Nov 4, 2023 · 17 comments
Closed

sokol_gfx: Issue creating render target #936

leiradel opened this issue Nov 4, 2023 · 17 comments

Comments

@leiradel
Copy link

leiradel commented Nov 4, 2023

I'm having trouble creating a render target on Windows with the D3D11 backend.

I had code working fine on Android using the GLES3 backend, but it refused to create the render target on Windows:

SokolRenderTarget(long const width, long const height) : rm::RenderTarget(width, height) {
    sg_desc sgdesc = sg_query_desc();

    {
        sg_image_desc desc = {};
        desc.render_target = true;
        desc.width = width;
        desc.height = height;
        desc.pixel_format = SG_PIXELFORMAT_RGBA8;
        desc.sample_count = sgdesc.context.sample_count;
        _target = sg_make_image(&desc);

        if (sg_query_image_state(_target) != SG_RESOURCESTATE_VALID) {
            RM_FATAL("Failed to create frame buffer image");
            return;
        }

        RM_INFO("Created color attachment");

        desc.pixel_format = sgdesc.context.depth_format;
        desc.sample_count = sgdesc.context.sample_count;
        _depth = sg_make_image(&desc);

        if (sg_query_image_state(_depth) != SG_RESOURCESTATE_VALID) {
            RM_FATAL("Failed to create frame buffer depth image");
            return;
        }

        RM_INFO("Created depth buffer");
    }

    {
        sg_pass_desc desc = {};
        desc.color_attachments[0].image = _target;
        desc.depth_stencil_attachment.image = _depth;
        _pass = sg_make_pass(&desc);

        if (sg_query_pass_state(_pass) != SG_RESOURCESTATE_VALID) {
            RM_FATAL("Failed to create frame buffer pass");
            return;
        }
    }
}

There's a validation error when creating the depth buffer:

[ERROR] sokol_gfx.h:14771: VALIDATE_IMAGEDESC_RT_PIXELFORMAT: invalid pixel format for render-target image
[FATAL] sokol_gfx.h:14683: VALIDATION_FAILED: validation layer checks failed

The best I could come up with is this:

#if defined(_WIN32)
                desc.pixel_format = SG_PIXELFORMAT_DEPTH;
#else
                desc.pixel_format = sgdesc.context.depth_format;
#endif

It's a red flag for me, the fact that I'm testing the platform there tells me that I'd doing something wrong, but that got me past the render target creation. However, I then I get this error when rendering:

[ERROR] sokol_gfx.h:15318: VALIDATE_ABND_FS_IMAGE_MSAA: sg_apply_bindings: cannot bind image with sample_count>1 to fragment stage
[FATAL] sokol_gfx.h:14683: VALIDATION_FAILED: validation layer checks failed

I'm using sokol_gp to render the game since it's 2D. I recon that the issue may be in it, but I'd appreciate some assurance that I'm correctly creating the render target.

Thanks in advance!

@leiradel
Copy link
Author

leiradel commented Nov 4, 2023

Oh, I think I should say that I tried many different combinations of values in pixel_format for both the color attachment and the depth buffer, after looking at the sokol examples. Unfortunately, nothing worked.

@floooh
Copy link
Owner

floooh commented Nov 5, 2023

I think these are several issues. The first one I need to investigate (e.g. why does creating a rendering target with pixel format sgdesc.context.depth_format fail, which is most likely SG_PIXELFORMAT_DEPTH_STENCIL, this is definitely weird.

The second problem regarding VALIDATE_ABND_FS_IMAGE_MSAA was a breaking change from May 2023:

https://github.com/floooh/sokol/blob/master/CHANGELOG.md#19-may-2023

(an MSAA render target now needs to be explicitly resolved into a non-MSAA render target, and this resolved image needs to be used as texture).

@floooh
Copy link
Owner

floooh commented Nov 5, 2023

As for the first error, can you check these two things:

if (sg_query_pixelformat(SG_PIXELFORMAT_DEPTH_STENCIL).render) {
    printf("depth stencil is renderable\n");
} else {
    printf("depth stencil is not renderable!\n");
}

...if this already ends up in the else branch, then there's something weird about your D3D11 driver, because in this case the D3D11 driver says that SG_PIXELFORMAT_DEPTH_STENCIL isn't renderable (this check happens here:

sokol/sokol_gfx.h

Line 9816 in bd7fa93

info->render = 0 != (rtv_dxgi_fmt_caps & D3D11_FORMAT_SUPPORT_RENDER_TARGET);
)

...second can you check that the pixel format in sgdesc.context.depth_format is indeed SG_PIXELFORMAT_DEPTH_STENCIL (numeric value 43)?

@floooh
Copy link
Owner

floooh commented Nov 5, 2023

PS: the closest sokol sample for your use case is this:

https://github.com/floooh/sokol-samples/blob/master/sapp/offscreen-msaa-sapp.c

...specifically this part where the pass object is created:

https://github.com/floooh/sokol-samples/blob/3e746d86cd87f634f4f7793c2e8d0ef71a2067ca/sapp/offscreen-msaa-sapp.c#L70-L113

Note how there's now 3 image objects required instead of two:

  • a MSAA render target image as color attachment
  • a non-MSAA render target image as "resolve attachment" (this is new since last May)
  • a depth-buffer image (note though that I'm using the SG_PIXELFORMAT_DEPTH here, there's no need that this should be the same as the default frame buffer's depth-buffer pixel format, which is SG_PIXELFORMAT_DEPTH_STENCIL (if sokol_app.h is used at least - still weird that this would produce an error on your side thoguh)

...to access the render target as texture in a pixel shader you would need the resolve-image now

@leiradel
Copy link
Author

leiradel commented Nov 5, 2023

As for the first error, can you check these two things:

if (sg_query_pixelformat(SG_PIXELFORMAT_DEPTH_STENCIL).render) {
    printf("depth stencil is renderable\n");
} else {
    printf("depth stencil is not renderable!\n");
}

...if this already ends up in the else branch, then there's something weird about your D3D11 driver, because in this case the D3D11 driver says that SG_PIXELFORMAT_DEPTH_STENCIL isn't renderable (this check happens here:

sokol/sokol_gfx.h

Line 9816 in bd7fa93

info->render = 0 != (rtv_dxgi_fmt_caps & D3D11_FORMAT_SUPPORT_RENDER_TARGET);

)

It ends up in the else branch:

[INFO ] Initializing platform services
[INFO ] Initializing GDI+
[INFO ] Initializing time
[INFO ] Initializing renderer
[INFO ] depth stencil is not renderable!

@leiradel
Copy link
Author

leiradel commented Nov 5, 2023

...second can you check that the pixel format in sgdesc.context.depth_format is indeed SG_PIXELFORMAT_DEPTH_STENCIL (numeric value 43)?

Thread 1 hit Breakpoint 1, (anonymous namespace)::SokolRenderTarget::SokolRenderTarget (this=0x1484c3189f0, width=1280, height=888) at Platform/Sokol/Renderer.cpp:117
117                     desc.sample_count = sgdesc.context.sample_count;
(gdb) p sgdesc.context.depth_format
$2 = SG_PIXELFORMAT_DEPTH_STENCIL
(gdb) p (int)SG_PIXELFORMAT_DEPTH_STENCIL
$4 = 43

This is when creating the render target.

@leiradel
Copy link
Author

leiradel commented Nov 5, 2023

PS: the closest sokol sample for your use case is this:

https://github.com/floooh/sokol-samples/blob/master/sapp/offscreen-msaa-sapp.c

I'm not using MSAA, maybe it's something from sokol_gp? Also, I'm using sokol_app on Windows, but not on Android.

@floooh
Copy link
Owner

floooh commented Nov 6, 2023

[INFO ] depth stencil is not renderable!

Wait, it's the same here on my laptop! I need to investigate this. In the meantime, please use SG_PIXELFORMAT_DEPTH as workaround for offscreen render targets (unless stencil is needed, in that case you'd need to wait for a fix).

I'm not using MSAA

Hmm, the error VALIDATE_ABND_FS_IMAGE_MSAA happens when trying to bind a render target image with .sample_count > 1 to a shader stage, and since in your code a render target image is initialized like this:

        sg_image_desc desc = {};
        desc.render_target = true;
        desc.width = width;
        desc.height = height;
        desc.pixel_format = SG_PIXELFORMAT_RGBA8;
        desc.sample_count = sgdesc.context.sample_count;  <===================
        _target = sg_make_image(&desc);

...I was assuming that sgdesc.context.sample_count is set to a value > 1. If no MSAA is intended for offscreen rendering, it's better to set desc.sample_count explicitly to 1 (also in the pipeline objects used for offscreen rendering!)

I'll check what's up with the non-renderable SG_PIXELFORMAT_DEPTH_STENCIL next.

@floooh
Copy link
Owner

floooh commented Nov 6, 2023

I'm preparing a fix for the non-renderable SG_PIXELFORMAT_DEPTH_STENCIL images in this PR:

#937

...the problem was that all depth pixel formats should also be reported as renderable (which didn't happen in the d3d11 backend). I also cleaned up the texture vs resource-view pixel formats for SG_PIXELFORMAT_DEPTH_STENCIL in the D3D11 backend (similar how it was already done for SG_PIXELFORMAT_DEPTH). I tested in the offscreen-sapp.c sample by switching all occurances of SG_PIXELFORMAT_DEPTH to SG_PIXELFORMAT_DEPTH_STENCIL.

The multisample validation error is something else though (please check that your rendertarget image really isn't created with a sample_count > 1.

@floooh
Copy link
Owner

floooh commented Nov 6, 2023

Ok, PR #937 has been merged, which should fix the first part of the problem (not being able to create a depth-stencil render-target image.

Let me know if this works, and let's look into the multisample validation error next :)

@leiradel
Copy link
Author

leiradel commented Nov 7, 2023

Ok, I've updated sokol_gfx, and changed sokol_gp at one place to replace SG_SAMPLERTYPE_SAMPLE with SG_SAMPLERTYPE_FILTERING. My code to create a render target now looks like this:

SokolRenderTarget(long const width, long const height) : rm::RenderTarget(width, height) {
    sg_desc sgdesc = sg_query_desc();

    {
        sg_image_desc desc = {};
        desc.render_target = true;
        desc.width = width;
        desc.height = height;
        desc.pixel_format = SG_PIXELFORMAT_RGBA8;
        desc.sample_count = 1;
        _target = sg_make_image(&desc);

        if (sg_query_image_state(_target) != SG_RESOURCESTATE_VALID) {
            RM_FATAL("Failed to create frame buffer image");
            return;
        }

        RM_INFO("Created color attachment");

        desc.pixel_format = SG_PIXELFORMAT_DEPTH;
        desc.sample_count = 1;
        _depth = sg_make_image(&desc);

        if (sg_query_image_state(_depth) != SG_RESOURCESTATE_VALID) {
            RM_FATAL("Failed to create frame buffer depth image");
            return;
        }

        RM_INFO("Created depth buffer");
    }

    {
        sg_pass_desc desc = {};
        desc.color_attachments[0].image = _target;
        desc.depth_stencil_attachment.image = _depth;
        _pass = sg_make_pass(&desc);

        if (sg_query_pass_state(_pass) != SG_RESOURCESTATE_VALID) {
            RM_FATAL("Failed to create frame buffer pass");
            return;
        }
    }
}

The render target is created but now I get an error when trying to render into it:

[ERROR] sokol_gfx.h:16131: VALIDATE_APIP_COLOR_FORMAT: sg_apply_pipeline: pipeline color attachment pixel format doesn't match pass color attachment pixel format
[ERROR] sokol_gfx.h:16132: VALIDATE_APIP_SAMPLE_COUNT: sg_apply_pipeline: pipeline MSAA sample count doesn't match render pass attachment sample count
[ERROR] sokol_gfx.h:16136: VALIDATE_APIP_DEPTH_FORMAT: sg_apply_pipeline: pipeline depth pixel_format doesn't match pass depth attachment pixel format
[FATAL] sokol_gfx.h:15603: VALIDATION_FAILED: validation layer checks failed

On Android, with the same code, I'm also getting a validation failure when trying to render into the render target:

sokol_gfx.h:16136: VALIDATE_APIP_DEPTH_FORMAT: sg_apply_pipeline: pipeline depth pixel_format doesn't match pass depth attachment pixel format
sokol_gfx.h:15603: VALIDATION_FAILED: validation layer checks failed

Thanks for the time you're putting into this issue, and please let me know if you need any other tests.

@floooh
Copy link
Owner

floooh commented Nov 7, 2023

Ah ok, now it's clashing with sokol_gp.h pipeline creation code.

It looks like sokol_gp.h expects the depth-pixel-format to be identical with the default framebuffer, and doesn't have enough options to inject a completely custom pipeline object (e.g. this is all you can change: https://github.com/edubart/sokol_gp/blob/f3a4ec845c782157c4182c39e5a13c49f4858a60/sokol_gp.h#L530-L535).

On the other hand you can inject "any" pipeline here as long as it is compatible with what sokol_gp.h expects (e.g. you don't have to use sgp_make_pipeline():

https://github.com/edubart/sokol_gp/blob/f3a4ec845c782157c4182c39e5a13c49f4858a60/sokol_gp.h#L2075-L2088

There are two options now, either make your render pass compatible, with the default framebuffer, and switch off multisampling in the default framebuffer:

  • the pixel formats in _target and _depth need to be changed back to be identical with the default framebuffer
  • initialize sokol_app.h with a sample count of 1

...or you create your own pipeline object with sg_make_pipeline() (NOT sgp_make_pipeline()) which is compatible with your render pass and a duplicate of the sokol_gp.h shader.

The third option is to ask the sokol_gp.h author (or to patch this in your own copy) to add more configuration options to sgp_make_pipeline(), at least the depth pixel format and sample count.

@leiradel
Copy link
Author

leiradel commented Nov 7, 2023

I can now create a render target and use it without any issues on Android using this:

SokolRenderTarget(long const width, long const height) : rm::RenderTarget(width, height) {
    sg_desc sgdesc = sg_query_desc();

    {
        sg_image_desc desc = {};
        desc.render_target = true;
        desc.width = width;
        desc.height = height;
        desc.pixel_format = sgdesc.context.color_format;
        desc.sample_count = sgdesc.context.sample_count;
        _target = sg_make_image(&desc);

        if (sg_query_image_state(_target) != SG_RESOURCESTATE_VALID) {
            RM_FATAL("Failed to create frame buffer image");
            return;
        }

        RM_INFO("Created color attachment");

        desc.pixel_format = sgdesc.context.depth_format;
        _depth = sg_make_image(&desc);

        if (sg_query_image_state(_depth) != SG_RESOURCESTATE_VALID) {
            RM_FATAL("Failed to create frame buffer depth image");
            return;
        }

        RM_INFO("Created depth buffer");
    }

    {
        sg_pass_desc desc = {};
        desc.color_attachments[0].image = _target;
        desc.depth_stencil_attachment.image = _depth;
        _pass = sg_make_pass(&desc);

        if (sg_query_pass_state(_pass) != SG_RESOURCESTATE_VALID) {
            RM_FATAL("Failed to create frame buffer pass");
            return;
        }
    }
}

On Windows, the render target is correctly created, but all I get is a gray screen. This is on me though, since I can't even render a colored quad. I'm probably doing something wrong.

Thanks for all the help!

@edubart
Copy link
Contributor

edubart commented Nov 16, 2023

The third option is to ask the sokol_gp.h author (or to patch this in your own copy) to add more configuration options to sgp_make_pipeline(), at least the depth pixel format and sample count.

sokol_gp.h author here, I will probably expose both later to help with this issue.

But about the depth pixel format, the library is intended for 2D, so it does no care about depth-stencil format, that's why I created the issue #632 in the past. Ideally he should be not be using depth stencil for 2D stuff, maybe Sokol could have a "dont care" pixel format for depth-stencil, and then I advise users of Sokol GP to use that everywhere.

@edubart
Copy link
Contributor

edubart commented Jan 7, 2024

I updated sokol_gp.h to be able to specify depth_format and sample_count in its pipelines, and also on context creation. So I think this issue can be closed.

@floooh
Copy link
Owner

floooh commented Jan 8, 2024

Thanks!

@floooh floooh closed this as completed Jan 8, 2024
@leiradel
Copy link
Author

leiradel commented Apr 3, 2024

I forgot to thank you guys for solving this, so thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants