SnowflakePowered / librashader

RetroArch Shaders for All
Mozilla Public License 2.0
77 stars 7 forks source link

Provide C++ examples for using librashader_ld.h #1

Closed star69rem closed 1 year ago

star69rem commented 1 year ago

librashader-capi-tests doesn't even compile because it has hardcoded include paths to someone's D drive, and there only seems to be a Vulkan example. I just wanted to test out a D3D11 sample to see whether it was worth torpedoing one of my projects for.

star69rem commented 1 year ago

Yeah even if I manually add the Vulkan includes it doesn't compile.

Severity Code Description Project File Line Suppression State Error (active) E0020 identifier "PFN_libra_preset_get_runtime_params" is undefined librashader-capi-tests E:\librashader-master\include\librashader_ld.h 295

chyyran commented 1 year ago

Hi! Sorry about that, I mostly focused on Rust examples when developing because that's what I'm familiar the most with

There was an issue with one of the type names regarding libra_preset_param_list_t that failed to get updated, I've since fixed that in https://github.com/SnowflakePowered/librashader/commit/e1eb0ccb22981612162698ba97c3bd2873efd21b. That should hopefully fix the PFN_libra_preset_get_runtime_params error, but if it doesn't make sure librashader.h is also included. Another issue with the frame options naming for D3D11 was fixed in https://github.com/SnowflakePowered/librashader/commit/c20104703b73c00c0db4b33dd271b208dde253cd. Please bear with me while these issues get sorted out.

As for the hardcoded "D:" drive includes, you'll have to fix those yourself in Visual Studio image

Unfortunately I don't have a proper CMake setup for the C++ test project because I was mostly concerned with testing whether the bindings were sound or not rather than usage of the API which I had the Rust examples for. Here is a short snippet you can plug in to an existing D3D11 render loop with the latest commit.

libra_d3d11_filter_chain_t create_d3d11_filter_chain(libra_instance_t& instance, const char* path, ID3D11Device* device) {
    libra_shader_preset_t preset;
    libra_error_t error;

    error = instance.preset_create(path, &preset);
    if (error != NULL) {
        instance.error_print(error);
        instance.error_free(&error);
        return NULL;
    }

    libra_d3d11_filter_chain_t filter_chain;
    error = instance.d3d11_filter_chain_create(&preset, NULL, device,
                                               &filter_chain);
    if (error != NULL) {
        instance.error_print(error);
        instance.error_free(&error);
        return NULL;
    }

    return filter_chain;
}

void apply_d3d11_filter_chain_to_frame(
    libra_instance_t& instance, libra_d3d11_filter_chain_t& filter_chain, size_t frame_count, const ID3D11ShaderResourceView* srv, 
        const ID3D11RenderTargetView *rtv, uint32_t height, uint32_t width, float_t x, float_t y) {
    libra_source_image_d3d11_t input = { srv, height, width };
    libra_viewport_t vp = {x, y, height, width};

    // can check for error if you want 
    instance.d3d11_filter_chain_frame(&filter_chain, frame_count, input, vp,
                                      rtv, NULL, NULL);

}

Note that at this point in time, while in beta, I recommend you build your own copy of librashader.dll with the instructions in the README. There's quite a lot of churn since the last release but pushing a new release is blocking on some downstream dependencies to update.

star69rem commented 1 year ago

Thanks for looking into this. I'll try it out.

star69rem commented 1 year ago

No luck. Cannot get this thing to work as a static lib.

Severity Code Description Project File Line Suppression State Error LNK2038 mismatch detected for 'RuntimeLibrary': value 'MD_DynamicRelease' doesn't match value 'MT_StaticRelease' in librashader_capi.lib(wrapper.o) 1

The header doesn't work out of the box, either. It includes Vulkan stuff even if you're specifying D3D11.

star69rem commented 1 year ago

Seeing this when adding this to .cargo/config.toml: [build] rustflags = ["-C", "target-feature=+crt-static"]

libshaderc_sys-d34cdc21cb8ef69a.rlib(compiler.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MD_DynamicRelease' doesn't match value 'MT_StaticRelease' in liblibrashader_spirv_cross-f96f5a6da73edc39.rlib(wrapper.o)

star69rem commented 1 year ago

And it doesn't work if you use librashader_ld.h, either, because that gets you:

Severity Code Description Project File Line Suppression State Error (active) E0144 a value of type "libra_error_t ()(libra_d3d11_filter_chain_t chain, size_t frame_count, libra_source_image_d3d11_t image, libra_viewport_t viewport, const ID3D11RenderTargetView out, const float mvp, const frame_vk_opt_t *opt)" cannot be used to initialize an entity of type "PFN_libra_d3d11_filter_chain_frame" \librashader\librashader_ld.h 636

star69rem commented 1 year ago

Okay just for the heck of it, I tried letting it load the DLL. Surprise surprise, doesn't work either.

libra_instance_t librashader = librashader_load_instance();

libra_shader_preset_t preset;
libra_error_t error = librashader.preset_create("D:\\slang-shaders-master\\crt\\crt-royale.slangp", &preset);
if (error != NULL) {
    std::cout << "Could not load preset\n";

}

filter_chain_d3d11_opt_t shaderOptions = {};
shaderOptions.use_deferred_context = true;
shaderOptions.force_no_mipmaps = false;

libra_d3d11_filter_chain_t chain;
if (librashader.d3d11_filter_chain_create(&preset, &shaderOptions, m_d3dDevice.Get(), &chain)) {
    std::cout << "Could not create OpenGL filter chain\n";
}

Bombs out when falling chain_create.

Exception thrown at 0x00007FFA438ECB0E (librashader.dll) in .exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.

chyyran commented 1 year ago

And it doesn't work if you use librashader_ld.h, either, because that gets you:

Severity Code Description Project File Line Suppression State Error (active) E0144 a value of type "libra_error_t ()(libra_d3d11_filter_chain_t chain, size_t frame_count, libra_source_image_d3d11_t image, libra_viewport_t viewport, const ID3D11RenderTargetView out, const float mvp, const frame_vk_opt_t *opt)" cannot be used to initialize an entity of type "PFN_libra_d3d11_filter_chain_frame" \librashader\librashader_ld.h 636

Should be fixed in https://github.com/SnowflakePowered/librashader/commit/62b0d590adde33aa45449dd82b9bd4434a712a28. Forgot to apply type renaming fixes to the loader header, since that one is manually written and not generated.

To link as a static lib, you shouldn't need to add rustflags = ["-C", "target-feature=+crt-static"]. Instead you link against librashader.lib, and you'll have to add that yourself in Visual Studio. This will pull in a bunch of system linkages that you'll need to resolve as well depending on your project.

librashader_ld.h will enable support for all supported runtimes by default. You should remove the LIBRA_RUNTIME_VULKAN define to disable Vulkan support.

chyyran commented 1 year ago

Bombs out when falling chain_create.

Exception thrown at 0x00007FFA438ECB0E (librashader.dll) in .exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.

Are you using the fixed header in https://github.com/SnowflakePowered/librashader/commit/62b0d590adde33aa45449dd82b9bd4434a712a28 for this? Can you try passing in NULL for the shader options. I'll take a look later today if neither of those work out.

star69rem commented 1 year ago

error is 0x000001d8a1958750 when I do it with NULL, but it isn't outright crashing anymore.

libra_error_t error = librashader.d3d11_filter_chain_create(&preset, NULL, g_game->m_d3dDevice1.Get(), &chain);

star69rem commented 1 year ago

And libra_d3d11_filter_chain_t chain is 0xcccccccccccccccc.

star69rem commented 1 year ago

To link as a static lib, you shouldn't need to add rustflags = ["-C", "target-feature=+crt-static"]. Instead you link against librashader.lib, and you'll have to add that yourself in Visual Studio. This will pull in a bunch of system linkages that you'll need to resolve as well depending on your project.

That's what I did, and I get the mismatch errors.

error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MD_DynamicRelease' doesn't match value 'MT_StaticRelease'

My project is statically linked, but that .lib is not regardless of whether I mess with the rust flags.

chyyran commented 1 year ago

Thanks, I can look more into this after work.

On Thu, Jan 26, 2023 at 10:31 AM star69rem @.***> wrote:

To link as a static lib, you shouldn't need to add rustflags = ["-C", "target-feature=+crt-static"]. Instead you link against librashader.lib, and you'll have to add that yourself in Visual Studio. This will pull in a bunch of system linkages that you'll need to resolve as well depending on your project.

That's what I did, and I get the mismatch errors.

error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MD_DynamicRelease' doesn't match value 'MT_StaticRelease'

My project is statically linked, but that .lib is not regardless of whether I mess with the rust flags.

— Reply to this email directly, view it on GitHub https://github.com/SnowflakePowered/librashader/issues/1#issuecomment-1405186729, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAHUIN3HBLDBI7A433J5TIDWUKKGBANCNFSM6AAAAAAUCAO7TQ . You are receiving this because you commented.Message ID: @.***>

star69rem commented 1 year ago

I just checked, and the only reason it didn't crash with the access violation was when it was called before the d3d device was created. Also note that this is a ComPtr, and I'm getting the pointer with ComPtr Get() if that matters.

chyyran commented 1 year ago

I suspect that it has to do with the library expecting a pointer to the ComPtr. I’ll have to fix the generated headers to account for that.

On Thu, Jan 26, 2023 at 11:07 AM star69rem @.***> wrote:

I just checked, and the only reason it didn't crash with the access violation was when it was called before the d3d device was created. Also note that this is a ComPtr, and I'm getting the pointer with ComPtr Get() if that matters.

— Reply to this email directly, view it on GitHub https://github.com/SnowflakePowered/librashader/issues/1#issuecomment-1405239047, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAHUINZ5MERGYQCVY7KIVBTWUKOMDANCNFSM6AAAAAAUCAO7TQ . You are receiving this because you commented.Message ID: @.***>

star69rem commented 1 year ago

Also, my program uses Direct3D 11.1. I tried changing the include in librashader to d3d11_1.h, but it didn't work.

star69rem commented 1 year ago

Ugh, the other thing probably screwing it up is that because I'm on 11.1 I have a ID3D11Device1 not ID3D11Device. I really think you should just do 11.1. For anyone running a shader, that will probably be what they're on anyway.

chyyran commented 1 year ago

You can QueryInterface to get a ID3D11Device from an ID3D11Device1. librashader doesn’t need feature level 11_1 so there’s no reason to go with ID3D11Device1.

On Thu, Jan 26, 2023 at 11:25 AM star69rem @.***> wrote:

Ugh, the other thing probably screwing it up is that because I'm on 11.1 I have a ID3D11Device1 not ID3D11Device. I really think you should just do 11.1. For anyone running a shader, that will probably be what they're on anyway.

— Reply to this email directly, view it on GitHub https://github.com/SnowflakePowered/librashader/issues/1#issuecomment-1405264961, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAHUINYXVXMCQNILRKEB2NTWUKQPTANCNFSM6AAAAAAUCAO7TQ . You are receiving this because you commented.Message ID: @.***>

chyyran commented 1 year ago

8e67c637a5f78b99401327769856d2f0cda5be6d should fix the generated bindings. As I suspected the issue was that the real type expected by librashader was ID3D11Device** but you provide an ID3D11Device* leading to the access violation. I changed the function to expect a raw ID3D11Device* now.

chyyran commented 1 year ago

After looking into static linking a bit more, I've clarified that we don't do anything special to support it. I suggest using corrosion to set up build dependencies properly if you want to statically link librashader.

star69rem commented 1 year ago

Thanks. Trying it now. I'm stumbling and bumbling because I haven't really worked with Rust or Cargo before.

star69rem commented 1 year ago

I can call d3d11_filter_chain_create now, but if I call d3d11_filter_chain_frame more than once I get unhandled exceptions. It would be so helpful to actually have a working example.

star69rem commented 1 year ago

Does librashader need its own dedicated context, or can I pass an existing one in? Once I call librashader's frame function , I can't call:

g_game->m_d3dContext1->OMSetRenderTargets(1, g_game->m_renderTargetView.GetAddressOf(), nullptr);

without getting an error.

star69rem commented 1 year ago

So the problem seems to be that I can't call this more than once:

libra_error_t shaderError = librashader.d3d11_filter_chain_frame(&chain, shaderFrame, input, vp, g_game->m_LibraShaderRenderTargetView.Get(), NULL, NULL);

On the second frame it always throws an access violation.

chyyran commented 1 year ago

It's because the way the windows crate wraps COM pointers is more akin to a ComPtr than a raw pointer. Manually calling AddRef should fix it.

I have a working C++ example up that I'll push in a few minutes with a fix to prevent Rust-side from decrementing the refcount because of RAII when passing the pointer over.

star69rem commented 1 year ago

I added this and it lasts more than one frame, but it's incredibly slow and just pegs my GPU and crashes in around 10 seconds.

g_game->tempSrv->AddRef(); g_game->m_renderTargetView->AddRef();

chyyran commented 1 year ago

https://github.com/SnowflakePowered/librashader/commit/cdf94cee1f96e34d0fb2986e0c6852cb04bf7e0b should fix the access violation caused by dropping the COM pointer.

I've added a C++ example (which is mostly just some Hello Triangle tutorial with the librashader parts being a 1:1 port from the Rust example) here: https://github.com/SnowflakePowered/librashader/blob/master/test/capi-tests/librashader-capi-tests/dx11-example/main.cpp#L365

What you basically need to do is copy the texture resource, make an SRV from that and use that as an input. Using a release build also has a big difference on both shader compile times and FPS. Using the default context should be fine. If you're using the immediate context, all render targets will be unbound at the end of d3d11_filter_chain_frame so if you need to do any additional rendering you'll need to rebind your targets.

star69rem commented 1 year ago

It looks like it's sort of working! Thanks a lot! The only problem now is that I need to figure out how to pass my program's native low resolution parameters to the shader. Not sure what the syntax for that is (the shader looks kind of crappy).

star69rem commented 1 year ago

Performance seems to be a problem too. I have a 3090 and it's incredibly slow.

chyyran commented 1 year ago

Yeah, that example creates and releases a Texture2D every frame so it'll be extremely slow. I made another example with a persistent Texture2D here: https://github.com/SnowflakePowered/librashader/blob/master/test/capi-tests/librashader-capi-tests/dx11-example-2/code.cpp#L474 with much better performance.

star69rem commented 1 year ago

My program has a persistent Texture2D.

star69rem commented 1 year ago

And for some reason crt-lottes.slangp crashes where as crt-royale.slangp doesn't.

chyyran commented 1 year ago

crt-lottes.slangp works fine for me with good performance. I would check the error returned if the error is in filter chain creation.

The extremely poor performance of crt-royale I would chalk up to the shader just not playing nice with D3D11. There's space for optimization in the runtime implementation, but crt-royale was never known for great performance on D3D11 even in RetroArch.

image