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

use spirv-cross for generate some shader related vkCreateInfo in Vulkan.Util? #260

Open
ukari opened this issue Feb 12, 2021 · 15 comments
Open

Comments

@ukari
Copy link
Contributor

ukari commented Feb 12, 2021

I write a example https://gist.github.com/ukari/6b9d94b04c3c26ff63ffd4663914c7da

and inlined some examples which could easily run by excute test2(for makeShaderInfo), test3(for makeDescriptorInfo), test4(for makeInputInfo)

module SpirV
  ( reflection
  , makeShaderInfo
  , makeDescriptorInfo
  , makeInputInfo
  ) where

import Vulkan.Core10.Shader (ShaderModule)

data Shader = Shader
  { stage :: ShaderStage
  , code :: B.ByteString
  } deriving (Show)

data Reflection = Reflection
  { entryPoints :: Vector EntryPoint
  , inputs :: Maybe (Vector Input)
  , textures :: Maybe (Vector Texture)
  , ubos :: Maybe (Vector Ubo)
  } deriving (Show, Generic, FromJSON, ToJSON)

data ShaderInfo = ShaderInfo
  { shaderModuleCreateInfo:: ShaderModuleCreateInfo '[]
  , pipelineShaderStageCreateInfos :: ShaderModule -> Vector (PipelineShaderStageCreateInfo '[])
  }

reflection :: MonadIO m => ShaderStage -> "code" ::: String -> m (Shader, Reflection)

makeShaderInfo :: (Shader, Reflection) -> ShaderInfo

makeDescriptorInfo :: Vector (Shader, Reflection) -> Vector (DescriptorSetLayoutCreateInfo '[])

makeInputInfo :: Vector (Shader, Reflection) -> Maybe (PipelineVertexInputStateCreateInfo '[])

now this only support single binding for input vertex, which let all input vertex attribute have a default binding = 0.

maybe can provide a binding map parameter to specify individual binding by name, like foo [(1, ["inPos", "inColor"]) (2, ["texCoord"])] speficies that (binding = 1) inPos, (binding = 1) inColor, (binding = 2) texCoord

here is some related references:

SaschaWillems - Multiple Vulkan buffer binding points

island pipeline

@sheaf
Copy link
Collaborator

sheaf commented Feb 12, 2021

It's definitely worth investigating what information can be extracted from a shader or shader pipeline which would allow for automation of Vulkan operations (such as creation of a graphics pipeline and binding of appropriate resources).

Given that Vulkan is based on SPIR-V, I think it makes the most sense to have something that handles SPIR-V directly and extracts relevant information. Yet it still seems quite difficult as there are a lot of features one needs to take into account: descriptor sets, binding numbers, arrayed descriptors, visibility of descriptors in different stages, different storage classes (uniform buffers, storage buffers, push constants, acceleration structures,...), and so on. I doubt it's really possible to come up with a comprehensive solution that would avoid having to manually handle resource management on the Vulkan side in general. That's what I keep finding with the Vulkan API: you try to come up with some abstractions to simplify your tasks, but then when your requirements change ever so slightly you realise you needed access to some part or other. So at some level I believe there's no bypassing the low-level nature of Vulkan unless you start strongly restricting functionality.

You might be interested in the approach I took here for handling descriptor sets. You specify a bunch of different descriptors and it will go ahead and figure out everything it needs to handle

  • creation of descriptor set layouts,
  • allocation of descriptor sets,
  • initialisation of resources (e.g. writing data to buffers),
  • binding of resources (descriptor sets, vertex buffers, etc).

See for instance this example in which I declare the kind of descriptor sets I want, and then later on the shader stage flags and the data to use for initialisation. The functions from Vulkan.Resource then allocate everything, returning the descriptor set layouts, descriptor sets, and functions that allow you to update the underlying data that the descriptors point to (e.g. to move the camera).

@ukari
Copy link
Contributor Author

ukari commented Feb 15, 2021

@sheaf
Hi, I read a bit of your example. I have some questions but don't know it is suitable to open a issue under FIR so I ask here.

FIR seems directly generate spirv code from AST, why there is a example/CreateDirs which helps to compile shader to a spv file. This weird me a bit. I thought it could use a temporary directory for storage spv file or directly pass spv code to vulkan api. Or maybe this is just for better generated spirv debug experience?

Thy way FIR use to write shader is a eDSL -> spv approach. It would be more nice if there could be a vulkan glsl -> eDSL or spv -> eDSL because people mostly teach shader in glsl or hlsl. Write spriv with eDSL is a little difficult.

@sheaf
Copy link
Collaborator

sheaf commented Feb 15, 2021

The data directory thing is just a way of writing the shader files to disk in a portable way. I'm using it to implement live shader reloading (by watching the files change on disk), and it's also useful to have the SPIR-V on disk so that you can run the various SPIR-V tools on it. However it's also possible to directly pass the SPIR-V data to Vulkan without writing to disk (personally I find it more convenient to have them on disk).

I wrote the FIR library specifically to avoid having to write GLSL (and in fact I started the project when I realised I could bypass GLSL entirely by compiling directly to SPIR-V), but I understand that it's not for everyone.

@expipiplus1
Copy link
Owner

Thanks!

In general this kind of stuff seems like a really good fit for vulkan-utils.

with the Vulkan API: you try to come up with some abstractions to simplify your tasks, but then when your requirements change ever so slightly you realise you needed access to some part or other

This is certainly true, but as long as there's some "escape hatch" then covering the simple cases is very handy.

Whatever ends up in utils would have to have some good documentation and an example due to the trickyness of this in vulkan.

@dpwiz
Copy link
Collaborator

dpwiz commented Mar 1, 2021

There can be a package that has only the base types for SPIR-V derived data (and maybe code generation build-tools).

Shader-producing packages (vulkan-utils, FIR, shader libraries) then can provide types and values to shader-consuming packages (vulkan examples, frameworks and projects) with compile-time compatibility checks. There is jQuery on hackage, why not bloom postprocessing code?

Same energy: https://github.com/embarkstudios/rust-gpu#why-embark

@ukari
Copy link
Contributor Author

ukari commented Mar 2, 2021

@dpwiz What is a SPIR-V derived data? Does it means types for the json of spirv-cross reflection?

@dpwiz
Copy link
Collaborator

dpwiz commented Mar 4, 2021

@dpwiz What is a SPIR-V derived data? Does it means types for the json of spirv-cross reflection?

Yes, the reflection data.

@ukari
Copy link
Contributor Author

ukari commented Mar 12, 2021

Is anyone works on this? I am not sure how to contribute it due to the example I wrote only support the few part of reflection data now.

Should I put the WIP stuff into Vulkan.Utils module though the feature is still weak? Or just put it into the examples?

@dpwiz
Copy link
Collaborator

dpwiz commented Mar 13, 2021

I'd suggest sending a PR with the code packaged as vulkan-reflect. Maybe there can be a part that works without even depending on the big vulkan package.

@ukari
Copy link
Contributor Author

ukari commented Mar 14, 2021

note

The api in current example

makeDescriptorInfo :: Vector (Shader, Reflection) -> Vector (DescriptorSetLayoutCreateInfo '[])
--                            ^ not rely `vulkan`            ^ rely on `vulkan`
--                                    ^ not rely `vulkan`

And in this reflect package(in imagination), the api could be like

data DescriptorSetLayout = ...
--   ^ not rely `vulkan`
makeDescriptorInfo :: Vector (Shader, Reflection) -> (DescriptorSetLayout -> a) -> Vector a
--                            ^ not rely `vulkan`
--                                    ^ not rely `vulkan`

@ukari
Copy link
Contributor Author

ukari commented Mar 14, 2021

@dpwiz I noticed that FIR examples also use stuffs like PipelineShaderStageCreateInfo from vulkan package. Is it worth to abstract a part which not rely on vulkan? There seems no more active projects(except fir and vulkan) about vulkan in haskell

@dpwiz
Copy link
Collaborator

dpwiz commented Mar 15, 2021

I imagine some CLI or web tool that can be used to inspect shader binaries and maybe generate code. They may not need to actually instantiate Vulkan data or use any libvulkan code.

But things like "just give me an appropriate CreateInfo" can be a great addition to vulkan-utils.

@ukari
Copy link
Contributor Author

ukari commented Mar 17, 2021

I make a vulkan-reflect branch locally https://github.com/ukari/vulkan/tree/vulkan-reflect

some stuffs might need to be done

  • error process
  • reformat
  • haddock
  • some api might need to be removed or redesigned, like reflect', reflection'
  • some function name could be changed to have a more precise name
  • makePipelineVertexInputStateCreateInfo only support single binding for input vertex, there could be a new helper function to support multiple binding with signature MultipleBinding -> PipelineVertexInputStateCreateInfo '[] -> PipelineVertexInputStateCreateInfo '[]
  • support more feature, like Sampler2D -> DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
  • support both GLSL and HLSL

@dpwiz
Copy link
Collaborator

dpwiz commented Mar 18, 2021

You can start a PR so we can post comments attached to actual code.

I may be wrong, but it seems you decode from Aeson's Text into String type to fields only to use fromString function via type class. You can add FromJSON instances directly to types like ShaderStage and use Aeson.withText wrappers to decode its values right away.

data EntryPoint = EntryPoint
  { name :: Text
  , mode :: ShaderStage
  } deriving (Show, Generic, FromJSON, ToJSON)

@dpwiz
Copy link
Collaborator

dpwiz commented Jul 7, 2022

BTW, there are now 2 packages to query spirv-reflect instead of spirv-cross

I haven't tried to generate haskell types, but it contains a bit more information about types and their layouts.

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

4 participants