Closed amerkoleci closed 5 years ago
A C-interface would be useful, but I'd prefer if this was contributed by someone else (e.g. you). @rossy made something like this, not sure how complete it is.
I have something WIP here (https://github.com/amerkoleci/SPIRVCrossSharp), will do PR
Yeah, I made a (very limited) C interface for SPIRV-Cross so I could use it in mpv: https://github.com/rossy/crossc
The API is documented here: https://github.com/rossy/crossc/blob/master/crossc.h
Currently it can only compile to HLSL and it only has interfaces for the options I needed in mpv (shader_model, flip_vert_y,) though it also has features that I think are important for a cross-platform C library, like shared library support (with SONAMEs,) and I tried to build it in a way that encourages ABI stability by using accessor functions to set properties, rather than setting them in public structures.
I was meaning to propose it to upstream and hopefully get it (or something like it) integrated as the official C interface for SPIRV-Cross, but I guess I got lazy, since I haven't done that yet.
I do something similar in order to generate internal Rust bindings to map them to a Rust API. The biggest issues I had were handling exception messages and classes.
Maybe this wrapper has some useful ideas, although it tends to be slightly conservative and copies most return values from SPIRV-Cross (I don't try to assume the lifetime of return values): https://github.com/grovesNL/spirv_cross/blob/master/spirv_cross/src/wrapper.hpp https://github.com/grovesNL/spirv_cross/blob/master/spirv_cross/src/wrapper.cpp
It sounds like many people have looked into similar things, so we should make sure the C wrapper is comprehensive enough to cover the cases for everyone who has been involved in this.
As for exceptions, a C wrapper can easily catch all exception and translate that. Generally, exceptions in SPIRV-Cross are "fatal" exceptions. Usually, exceptions can be directly translated to an abort().
The most important things for me is:
and you should be careful of allocations, making sure that each side of the api boundary will free what was allocated by them and not the other.
Ye, that's another consideration. Where allocations and frees happen.
@HansKristian-ARM Those requirements sound good to me. Also thanks for keeping mpv's use case in mind.
As for exceptions, a C wrapper can easily catch all exception and translate that. Generally, exceptions in SPIRV-Cross are "fatal" exceptions. Usually, exceptions can be directly translated to an abort().
Hopefully the abort() won't be done by the C wrapper itself. A fatal exception in SPIRV-Cross might not be fatal for the calling application. For example, mpv lets the user interactively enable and disable shaders, so if a shader can't be translated, the user can just disable it again. Also, mpv logs the full shader source on error to help with debugging, which it wouldn't be able to do if the process aborted immediately.
Currently, mpv calls crossc_strerror in crossc to get the exception message (e.what()) thrown by SPIRV-Cross, which is also helpful for debugging.
Yes, the wrapper shouldn't actually call abort(), just meant that the errors tend to be fatal in nature, so translating the exception handlers into some generic error code + error string is fine.
I'm mentally marking this is as the biggest ticket feature I will try to get done.
The error code + error string would be great to avoid e.what()
. I have a build of my SPIRV-Cross C wrapper that I compiled to WebAssembly with Emscripten, but exceptions aren't supported in that environment, so I use -fno-exceptions
and -DSPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS=1
at the moment.
Hm. I had not seen this issue before.
For embedding in Chromium, my team wanted a path into SPIRV-Cross which (1) always runs SPIR-V validatio first and (2) never uses exceptions (aborts instead). We ended up writing a library to do this, as a component in Shaderc, and are now making "libshaderc_spvc".
And in Shaderc we always make a C API as the baseline thing, so we have https://github.com/google/shaderc/blob/master/libshaderc_spvc/include/shaderc/spvc.h It might not be complete, but we intend to keep it stable. Then we build a headers-only C++ wrapper around that.
Note: your uses might want to deliberately bypass SPIR-V validation, so you might not want to use codepath.
(whoops. Accidentally closed the issue!) Also, thanks to @HansKristian-Work for adding the abort-instead-of-exceptions mode and making an interface we could use to bypass the exception-heavy initial binary parsing.
@dneto0 I see. From what I can tell, that interface is more tailored to the needs of simple cases of cross compilation. I guess the main user of this interface right now is WebGPU?
On top of that, I intend to add the full reflection support, querying type information and all other options and helper functions for special use cases. I don't think this interface is going to supplant whatever is in shaderc though. I don't intent on exposing the ParsedIR integration interface to C for example.
One thing that might be possible to add is a wrapper to export a C++ generated ParsedIR to a C version of that. That might enable shaderc to reuse the C wrapper for the advanced use cases.
Not really an issue, would be nice to have C interface for SPIRV-Cross so we can call from external, for example C#.
Maybe I can send PR tho.