achirkin / vulkan Goto Github PK
View Code? Open in Web Editor NEWLow-level low-overhead haskell bindings to vulkan API
License: BSD 3-Clause "New" or "Revised" License
Low-level low-overhead haskell bindings to vulkan API
License: BSD 3-Clause "New" or "Revised" License
I was asking something in the freenode #haskell channel, and linked this: https://github.com/achirkin/vulkan/blob/master/vulkan-api/vulkan-api.cabal. Someone spoke up and pointed out that it's "Not Okay" for flags to affect the publicly visible API. In particular, you have a bunch of flags that toggle the visibility of certain modules.
I asked for an alternative solution, and the suggestions were to do one of the following:
Also, I haven't checked if it's being done anywhere, but I imagine using flags to enable CPP options that, in-turn, cause parts of the public API to be toggled on and off would also be a bad thing for the same reason.
As I understand it, the main reason for this is that you don't want whether a flag is enabled to impact the code of a dependent package, because you can't make a cabal package depend on a specific flag configuration of another project. On the other hand, flags that improve performance (such as useNativeFFI-*) are fine, because they don't impact the implementation of dependent packages.
I would like to volunteer to design a logo for use in the readme file. What do you think?
It occurred to me that, without getVec
from easytensor, I don't see how you can index something like the memoryTypes of VkPhysicalDeviceMemoryProperties using an index obtained at runtime. It supports something like getFieldArray @"memoryTypes" @5 pdmp
, but how would you index given an Int value?
In the meantime, I'm just using getVec
, but it doesn't make sense to require an external library for this.
vulkan/genvulkan/src/VkXml/Sections/Types.hs
Lines 210 to 214 in 84a01f4
Make len
and altlen
parsing more correct and robust w.r.t. spec 10.2.2 "attributes of member
tags".
Have you considered, or do you see any problem with, the idea of making a generalization of VkStruct, one that's not Vulkan specific? It just seems to me that the ability to read/write a byte array as a struct with named and typed fields would be useful elsewhere. Particularly in C-library bindings.
Disclaimer: I've only been figuring out Vulkan for two days flat, so I've just barely passed creating logical devices in the API reference, but I do have experience porting quite a few C libraries into Haskell.
So far the library works fine, except for one tiny issue: the compilation times are abysmal.
To confirm that this isn't just me being dumb with the code on my end I created a test that looks like
wrap :: forall (a :: Type) (fname :: Symbol). CanWriteField fname a => IO ()
wrap = writeField @fname @a nullPtr undefined
throwaway :: IO ()
throwaway
| () == () = return ()
| otherwise = do
wrap @VkApplicationInfo @"sType"
wrap @VkApplicationInfo @"pNext"
wrap @VkApplicationInfo @"pApplicationName"
...
The wrap
s go on for 220 more lines to include every field in VkApplicationInfo
, VkInstanceCreateInfo
, VkPhysicalDeviceLimits
, VkPhysicalDeviceSparseProperties
, VkPhysicalDeviceProperties
, VkPhysicalDeviceFeatures
and VkDeviceCreateInfo
. The compilation time of this file at -O1 -Wall
is 30 seconds on my machine.
The code in this library depends on a lot of typing and type families are incredibly slow on recursion (#8095), my question therefore is:
Is all the type-level fluff actually needed or can this be removed?
So far I've been interacting with the library solely through writeField
/readField
(fieldOffset
) and raw Ptr
s. In my experience this set of features is all that is needed to operate C binding libraries, anything beyond that is overdesigning. The programmer will have to define multiple modules of wrappers anyway, so limiting them in any capacity at best yields neglible benefits to those who fully agree on your API design and at worst renders the library unusable.
The rewrite as I see it would be:
VkStruct
and all the complex type code. Use GHC.Records.HasField for field name definition and a custom class for offsets (I use storable-offset for this). This is the important change, every other one below is simply my preference and is most probably inconsequential;String
s and/or CString
s;CApiFFI
. VK_MAKE_API_VERSION
and the like should definitely be parts of this library;Show
, Eq
, Ord
, Read
and Enum
serve little purpose; Enum
and Show
in particular are not total for enumerations ever;forall a. (Num a, Eq a) => a
. The typing doesn't help much here.I am not in the mood to create a third Vulkan bindings library, however I also recognize that removing all the overtyping of this library is an immediate bump to v2.0.0.0
with all the rewrite baggage for the end users.
um sry im a little bit new to haskell, mosty us c and rust, but i was wandering what all the '@' operators were or is it a custom operator, and if there were any docs for this library.
I tested that the library compiles on arm, but I did not manage to run it due to lack of arm devices with vulkan support.
Thanks to hsc2hs
, everything should work in theory; so I am curious to see if the library can run on mobile or other 32 bit platforms in reality.
The simplest way to test the minimal functionality is to try ve-01-CreateInstance
from vulkan-examples
folder.
Admittedly I don't know very much about haskell, so I apologize if the solution is obvious, but I can't seem to figure out how to read from an array which has a variable length.
The best I could come up with is this (for reading the memoryTypes from the "vkGetPhysicalDeviceMemoryProperties" function)
memTypes <- case memTypeIndex of
0 -> Just <$> readFieldArray @"memoryTypes" @0 memPropPtr
1 -> Just <$> readFieldArray @"memoryTypes" @1 memPropPtr
2 -> Just <$> readFieldArray @"memoryTypes" @2 memPropPtr
3 -> Just <$> readFieldArray @"memoryTypes" @3 memPropPtr
4 -> Just <$> readFieldArray @"memoryTypes" @4 memPropPtr
5 -> Just <$> readFieldArray @"memoryTypes" @5 memPropPtr
6 -> Just <$> readFieldArray @"memoryTypes" @6 memPropPtr
7 -> Just <$> readFieldArray @"memoryTypes" @7 memPropPtr
...
I can't find any example or code anywhere that uses readFieldArray with a variable length, so with my limited knowledge of Haskell, I'm not sure if there is a better way.
Would it be possible to describe how this is done in some documentation somewhere or in an example?
Hi,
I'm trying to run the examples. 01 works, with others I get same error as with 02:
`
stack exec ve-01-CreateInstance
Success! 0x0000000000abffd0
VK_SUCCESS
stack exec ve-02-GLFWWindow
GLFW version: 3.3.2 Win32 WGL EGL OSMesa MinGW
Initialized GLFW window.
Closed GLFW window.
Terminated GLFW.
ve-02-GLFWWindow.EXE: VulkanException {vkeCode = Just VK_ERROR_LAYER_NOT_PRESENT, vkeMessage = "vkCreateInstance: Failed to create vkInstance."}`
System: Windows 8.1
Vuklan SDK installed, the examples are running.
I have built the examples with "stack build", also no modifications were made, except adding the extra dependencies for GLFW as suggested by stack.
I assume this could be the problem with my setup, so I'll be greateful if you could push me in the right direction...
P.S.
When trying to build triangles, I get the following error: (I can't see how they would be connected, so just in case)
E:\temp\vulkan\vulkan-triangles\src\Lib\Vulkan\Vertex.hs:59:22: error:
Not in scope: type constructor or class `KnownDimType'
|
59 | atLeastThree :: (All KnownDimType ns, BoundedDims ns)
| ^^^^^^^^^^^^
Completed 50 action(s).
I've been working with Vulkan 1.0 this whole time, but I decided to import Core_1_1 to make use of VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT
. However, I get a type error when attempting to combine it with VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT
from 1.0.
Looking at the source, it appears their types are different, and I suspect this is a mistake.
VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT :: VkImageCreateBitmask a
vs
VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT :: VkImageCreateFlagBits
I'm not really clear on the intended distinction between these, but I have a function like this that won't typecheck:
getMaxUsableSampleCount :: MonadIO io => VkPhysicalDevice -> io VkSampleCountFlagBits
getMaxUsableSampleCount physicalDevice = do
limits <- getField @"limits" <$> getPhysicalDeviceProperties physicalDevice
let sampleCounts = min (getField @"framebufferColorSampleCounts" limits) (getField @"framebufferDepthSampleCounts" limits)
return $
fromMaybe VK_SAMPLE_COUNT_1_BIT .
find ((0 /=) . (sampleCounts .&.)) $
[
VK_SAMPLE_COUNT_64_BIT,
VK_SAMPLE_COUNT_32_BIT,
VK_SAMPLE_COUNT_16_BIT,
VK_SAMPLE_COUNT_8_BIT,
VK_SAMPLE_COUNT_4_BIT,
VK_SAMPLE_COUNT_2_BIT
]
The type works if I replace the return type with VkSampleCountFlags
. However, I need FlagBits because that's what's consumed later by the samples
field of the VkImageCreateInfo
structure. Only way I can see to work around this is something like:
getMaxUsableSampleCount :: MonadIO io => VkPhysicalDevice -> io VkSampleCountFlagBits
getMaxUsableSampleCount physicalDevice = do
limits <- getField @"limits" <$> getPhysicalDeviceProperties physicalDevice
let sampleCounts = min (getField @"framebufferColorSampleCounts" limits) (getField @"framebufferDepthSampleCounts" limits)
return $
fromMaybe VK_SAMPLE_COUNT_1_BIT .
fmap snd .
find ((0 /=) . (sampleCounts .&.) . fst) $
[
(VK_SAMPLE_COUNT_64_BIT, VK_SAMPLE_COUNT_64_BIT),
(VK_SAMPLE_COUNT_32_BIT, VK_SAMPLE_COUNT_32_BIT),
(VK_SAMPLE_COUNT_16_BIT, VK_SAMPLE_COUNT_16_BIT),
(VK_SAMPLE_COUNT_8_BIT, VK_SAMPLE_COUNT_8_BIT),
(VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_4_BIT),
(VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_2_BIT)
]
What's the reason for removing this instance? I can work around it by explicitly wrapping/unwrapping a number with VkFormat, but it would be convenient if VkFormat itself were a number.
Hi, I'm getting these errors on the GLFW examples running on nixos
lc@icecrown ~/v/vulkan-examples> stack --nix exec -- ve-02-GLFWWindow
No protocol specified
ve-02-GLFWWindow: VulkanException {vkeCode = Nothing, vkeMessage = "Failed to initialize GLFW."}
Instead of always using getField
and set
, I believe some non-opaque struct types could benefit from using explicitly bidirectional pattern synonyms. For instance:
{-# COMPLETE VkSurfaceFormatKHR #-}
pattern VkSurfaceFormatKHR :: VkFormat -> VkColorSpaceKHR -> VkSurfaceFormatKHR
pattern VkSurfaceFormatKHR fmt spc
<- ( getField @"format" &&& getField @"colorSpace"-> (fmt, spc) )
where VkSurfaceFormatKHR fmt spc
= createVk ( set @"format" fmt &* set @"colorSpace" spc )
The Vulkan 1.1 spec was released recently. How much work is it to support that with the bindings?
If you write this:
enumFromTo @VkSampleCountFlags VK_SAMPLE_COUNT_1_BIT VK_SAMPLE_COUNT_64_BIT
I would expect it to produce a list like:
[VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT, VK_SAMPLE_COUNT_16_BIT, VK_SAMPLE_COUNT_32_BIT, VK_SAMPLE_COUNT_64_BIT]
But instead it produces this list:
[VK_SAMPLE_COUNT_1_BIT,VK_SAMPLE_COUNT_2_BIT,VkSampleCountBitmask 3,VK_SAMPLE_COUNT_4_BIT,VkSampleCountBitmask 5,VkSampleCountBitmask 6,VkSampleCountBitmask 7,VK_SAMPLE_COUNT_8_BIT,VkSampleCountBitmask 9,VkSampleCountBitmask 10,VkSampleCountBitmask 11,VkSampleCountBitmask 12,VkSampleCountBitmask 13,VkSampleCountBitmask 14,VkSampleCountBitmask 15,VK_SAMPLE_COUNT_16_BIT,VkSampleCountBitmask 17,VkSampleCountBitmask 18,VkSampleCountBitmask 19,VkSampleCountBitmask 20,VkSampleCountBitmask 21,VkSampleCountBitmask 22,VkSampleCountBitmask 23,VkSampleCountBitmask 24,VkSampleCountBitmask 25,VkSampleCountBitmask 26,VkSampleCountBitmask 27,VkSampleCountBitmask 28,VkSampleCountBitmask 29,VkSampleCountBitmask 30,VkSampleCountBitmask 31,VK_SAMPLE_COUNT_32_BIT,VkSampleCountBitmask 33,VkSampleCountBitmask 34,VkSampleCountBitmask 35,VkSampleCountBitmask 36,VkSampleCountBitmask 37,VkSampleCountBitmask 38,VkSampleCountBitmask 39,VkSampleCountBitmask 40,VkSampleCountBitmask 41,VkSampleCountBitmask 42,VkSampleCountBitmask 43,VkSampleCountBitmask 44,VkSampleCountBitmask 45,VkSampleCountBitmask 46,VkSampleCountBitmask 47,VkSampleCountBitmask 48,VkSampleCountBitmask 49,VkSampleCountBitmask 50,VkSampleCountBitmask 51,VkSampleCountBitmask 52,VkSampleCountBitmask 53,VkSampleCountBitmask 54,VkSampleCountBitmask 55,VkSampleCountBitmask 56,VkSampleCountBitmask 57,VkSampleCountBitmask 58,VkSampleCountBitmask 59,VkSampleCountBitmask 60,VkSampleCountBitmask 61,VkSampleCountBitmask 62,VkSampleCountBitmask 63,VK_SAMPLE_COUNT_64_BIT]
Is this a mistake, or are my expectations wrong?
The resolver in vulkan-examples
can be updated to lts-12.11
, in my testing on Windows all the examples work fine except 5, which fails with this error:
VUID-VkPipelineVertexInputStateCreateInfo-pVertexAttributeDescriptions-parameter(ERROR / SPEC): msgNum: 279077889 - vkCreateGraphicsPipelines: required parameter pCreateInfos[0].pVertexInputState->pVertexAttributeDescriptions specified as NULL. The spec valid usage text states 'If vertexAttributeDescriptionCount is not 0, pVertexAttributeDescriptions must be a valid pointer to an array of vertexAttributeDescriptionCount valid VkVertexInputAttributeDescription structures' (https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-VkPipelineVertexInputStateCreateInfo-pVertexAttributeDescriptions-parameter)
Objects: 1
[0] 0x0, type: 0, name: (null)
Validation(ERROR): msg_code: 279077889: [ VUID-VkPipelineVertexInputStateCreateInfo-pVertexAttributeDescriptions-parameter ] [ VUID-VkPipelineVertexInputStateCreateInfo-pVertexAttributeDescriptions-parameter ] Object: VK_NULL_HANDLE (Type = 0) | vkCreateGraphicsPipelines: required parameter pCreateInfos[0].pVertexInputState->pVertexAttributeDescriptions specified as NULL. The spec valid usage text states 'If vertexAttributeDescriptionCount is not 0, pVertexAttributeDescriptions must be a valid pointer to an array of vertexAttributeDescriptionCount valid VkVertexInputAttributeDescription structures' (https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-VkPipelineVertexInputStateCreateInfo-pVertexAttributeDescriptions-parameter)
VUID-VkPipelineVertexInputStateCreateInfo-vertexAttributeDescriptionCount-00614(ERROR / SPEC): msgNum: 278922444 - vkCreateGraphicsPipelines: pararameter pCreateInfo[0].pVertexInputState->vertexAttributeDescriptionCount (0) is greater than VkPhysicalDeviceLimits::maxVertexInputAttributes (16). The spec valid usage text states 'vertexAttributeDescriptionCount must be less than or equal to VkPhysicalDeviceLimits::maxVertexInputAttributes' (https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-VkPipelineVertexInputStateCreateInfo-vertexAttributeDescriptionCount-00614)
Objects: 1
[0] 0x0, type: 0, name: (null)
Validation(ERROR): msg_code: 278922444: [ VUID-VkPipelineVertexInputStateCreateInfo-vertexAttributeDescriptionCount-00614 ] [ VUID-VkPipelineVertexInputStateCreateInfo-vertexAttributeDescriptionCount-00614 ] Object: VK_NULL_HANDLE (Type = 0) | vkCreateGraphicsPipelines: pararameter pCreateInfo[0].pVertexInputState->vertexAttributeDescriptionCount (0) is greater than VkPhysicalDeviceLimits::maxVertexInputAttributes (16). The spec valid usage text states 'vertexAttributeDescriptionCount must be less than or equal to VkPhysicalDeviceLimits::maxVertexInputAttributes' (https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-VkPipelineVertexInputStateCreateInfo-vertexAttributeDescriptionCount-00614)
With the old resolver, I could not get vulkan-examples
to compile.
I can't get vulkan-triangles
to work with the resolver it had (nightly-2018-04-12
) or with lts-12.11
. In both cases I get the following error:
vulkan-api-1.1.3.0: configure (lib)
Progress 1/3
-- While building custom Setup.hs for package vulkan-api-1.1.3.0 using:
C:\sr\setup-exe-cache\x86_64-windows\Cabal-simple_Z6RU0evB_2.2.0.1_ghc-8.4.3.exe --builddir=.stack-work\dist\7d103d30 configure --with-ghc=C:\Users\hyper\AppData\Local\Programs\stack\x86_64-windows\ghc-8.4.3\bin\ghc.EXE --with-ghc-pkg=C:\Users\hyper\AppData\Local\Programs\stack\x86_64-windows\ghc-8.4.3\bin\ghc-pkg.EXE --user --package-db=clear --package-db=global --package-db=C:\sr\snapshots\bbeb756e\pkgdb --package-db=C:\Users\hyper\Desktop\vulkan-master\vulkan-triangles\.stack-work\install\96fd7a97\pkgdb --libdir=C:\Users\hyper\Desktop\vulkan-master\vulkan-triangles\.stack-work\install\96fd7a97\lib --bindir=C:\Users\hyper\Desktop\vulkan-master\vulkan-triangles\.stack-work\install\96fd7a97\bin --datadir=C:\Users\hyper\Desktop\vulkan-master\vulkan-triangles\.stack-work\install\96fd7a97\share --libexecdir=C:\Users\hyper\Desktop\vulkan-master\vulkan-triangles\.stack-work\install\96fd7a97\libexec --sysconfdir=C:\Users\hyper\Desktop\vulkan-master\vulkan-triangles\.stack-work\install\96fd7a97\etc --docdir=C:\Users\hyper\Desktop\vulkan-master\vulkan-triangles\.stack-work\install\96fd7a97\doc\vulkan-api-1.1.3.0 --htmldir=C:\Users\hyper\Desktop\vulkan-master\vulkan-triangles\.stack-work\install\96fd7a97\doc\vulkan-api-1.1.3.0 --haddockdir=C:\Users\hyper\Desktop\vulkan-master\vulkan-triangles\.stack-work\install\96fd7a97\doc\vulkan-api-1.1.3.0 --dependency=base=base-4.11.1.0 -fuseNativeFFI-1-0 -f-useNativeFFI-1-1 -fuseUnsafeFFIDefault --ghc-options -O2 --extra-include-dirs=C:\Users\hyper\AppData\Local\Programs\stack\x86_64-windows\msys2-20180531\mingw64\include --extra-lib-dirs=C:\Users\hyper\AppData\Local\Programs\stack\x86_64-windows\msys2-20180531\mingw64\bin --extra-lib-dirs=C:\Users\hyper\AppData\Local\Programs\stack\x86_64-windows\msys2-20180531\mingw64\lib --enable-tests --enable-benchmarks
Process exited with code: ExitFailure 1
Logs have been written to: C:\Users\hyper\Desktop\vulkan-master\vulkan-triangles\.stack-work\logs\vulkan-api-1.1.3.0.log
Configuring vulkan-api-1.1.3.0...
Cabal-simple_Z6RU0evB_2.2.0.1_ghc-8.4.3.exe: Missing dependency on a foreign
library:
* Missing (or bad) C library: vulkan-1
This problem can usually be solved by installing the system package that
provides this library (you may need the "-dev" version). If the library is
already installed but in a non-standard location then you can use the flags
--extra-include-dirs= and --extra-lib-dirs= to specify where it is.If the
library file does exist, it may contain errors that are caught by the C
compiler at the preprocessing stage. In this case you can re-run configure
with the verbosity flag -v3 to see the error messages.
What's the state (fate?) of the Program
code in vulkan-triangles
? With the exception of a few of the hard-coded device / chain / instance queries, it looks to be a good foundation for a general api. How would you feel about moving it to a dedicated module in vulkan-api
or a standalone library one-step in abstraction above vulkan-api
?
environment
windows 10
vulkan sdk 1.1.92.1
I got an error below.
D:\Work\vulkan\genvulkan>stack exec genvulkan
Parsing file "D:\Work\vulkan\vulkan-docs\xml\vk.xml";
Output folder is "D:\Work\vulkan\vulkan-api\src-gen\";
Warning: ignoring tag.
Done parsing, start generating...
genvulkan.EXE: Write.Types.Define.genDefine: unknown define!
Please, add a new guard to the function. Data: VkTypeSimple {name = VkTypeName {unVkTypeName = "VK_MAKE_VERSION"}, attributes = VkTypeAttrs {name = Nothing, alias = Nothing, category = VkTypeCatDefine, requires = Nothing, parent = [], returnedonly = False, comment = "", structextends = []}, typeData = VkTypeData {name = Just (VkTypeName {unVkTypeName = "VK_MAKE_VERSION"},[]), retType = Nothing, reference = [], comment = Nothing, code = "#define VK_MAKE_VERSION(major, minor, patch) \\r\n (((major) << 22) | ((minor) << 12) | (patch))"}}
CallStack (from HasCallStack):
error, called at src\Write\Types\Define.hs:155:17 in genvulkan-1.1.3.0-BkKDr8oYUStImjbP53zqC6:Write.Types.Define
So, I fixed the code ""#define VK_MAKE_VERSION(major, minor, patch) \\\n" ==> "#define VK_MAKE_VERSION(major, minor, patch) \\\r\n"
inert the "\r".
Slowly making my way through the vulkan tutorial, I've encountered a lot of creation functions that fit this pattern:
newVkInstance :: VkInstanceCreateInfo -> Acquire VkInstance
newVkInstance createInfo =
(
withPtr createInfo $ \createInfoPtr ->
alloca $ \vulkanInstancePtr -> do
vkCreateInstance createInfoPtr VK_NULL vulkanInstancePtr &
onVkFailureThrow "vkCreateInstance failed."
peek vulkanInstancePtr
)
`mkAcquire`
\vulkanInstance -> vkDestroyInstance vulkanInstance VK_NULL
newVkDevice :: VkPhysicalDevice -> VkDeviceCreateInfo -> Acquire VkDevice
newVkDevice physicalDevice createInfo =
(
withPtr createInfo $ \createInfoPtr ->
alloca $ \devicePtr -> do
vkCreateDevice physicalDevice createInfoPtr VK_NULL devicePtr &
onVkFailureThrow "vkCreateDevice failed."
peek devicePtr
)
`mkAcquire`
\device -> vkDestroyDevice device VK_NULL
newVkSwapchain :: VkDevice -> VkSwapchainCreateInfoKHR -> Acquire VkSwapchainKHR
newVkSwapchain device createInfo =
(
withPtr createInfo $ \createInfoPtr ->
alloca $ \swapchainPtr -> do
vkCreateSwapchainKHR device createInfoPtr VK_NULL swapchainPtr &
onVkFailureThrow "vkCreateSwapchainKHR failed."
peek swapchainPtr
)
`mkAcquire`
\swapchain -> vkDestroySwapchainKHR device swapchain VK_NULL
But now I've encountered vkCreateGraphicsPipelines
, which has an unusual signature. Instead of taking a pointer to one CreateInfo data structure, it takes a pointer to an array of them. I can follow the above pattern to use it for creating just one pipeline like this:
newGraphicsPipeline :: VkDevice -> VkGraphicsPipelineCreateInfo -> Acquire VkPipeline
newGraphicsPipeline device createInfo =
(
withPtr createInfo $ \createInfoPtr ->
alloca $ \pipelinePtr -> do
vkCreateGraphicsPipelines device VK_NULL_HANDLE 1 createInfoPtr VK_NULL pipelinePtr &
onVkFailureThrow "vkCreateGraphicsPipelines failed."
peek pipelinePtr
)
`mkAcquire`
\pipeline -> vkDestroyPipeline device pipeline VK_NULL
But if I wanted to make this:
newGraphicsPipelines :: VkDevice -> [VkGraphicsPipelineCreateInfo] -> Acquire [VkPipeline]
I don't see a way to get a pointer to an array of those CreateInfos. Am I missing something, or should we add a withArrayPtr
or withListPtr
or something?
The readme states that vulkan-api
was tested on MoltenVK. How was GLFW linked to vulkan? It looks like GLFW-b
packages a version of glfw the potentially predates MoltenVK support. I'm abled to install glfw (via source) and am told that I finds the vulkan libraries. However, it looks like stack build
in vulkan-examples links the wrong glfw
:
stack exec ve-06-Drawing
GLFW version: 3.2.1 Cocoa NSGL chdir menubar retina
Terminated GLFW.
ve-06-Drawing: VulkanException {vkeCode = Nothing, vkeMessage = "GLFW reports that vulkan is not supported!"}
The readme says "Windowing is done via GLFW, so you may need to have it on your system, version 3.2 or newer."
I'm not sure what exactly is meant by "have it on your system". I'm on Windows and new to Haskell. I suspect I need to download the precompiled binaries (.ddls and .libs) and deposit them somewhere on my system, but I'm not sure where.
Also, in the Lib
folder in the examples, Graphics.UI.GLFW
is imported. Is this inside the vulkan-api package, or do I need to import this elsewhere?
Currently HEAD works for me with GHC 8.10.4, but the version from Hackage doesn't. The following errors occur with the Hackage version:
src/Graphics/Vulkan/Marshal/Internal.hs:186:17: error:
• errMsg
• In the expression:
error
"VulkanFields.withField: unreachable code (no such field guarded by type family)."
In an equation for ‘withField’:
withField
= error
"VulkanFields.withField: unreachable code (no such field guarded by type family)."
In the instance declaration for ‘VulkanFields '[]’
|
186 | withField = error "VulkanFields.withField: unreachable code (no such field guarded by type family)."
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/Graphics/Vulkan/Marshal/Internal.hs:201:28: error:
• Cannot apply expression of type ‘Proxy# _0’
to a visible type argument ‘m’
• In the first argument of ‘k’, namely ‘(proxy# @_ @m)’
In the first argument of ‘(.)’, namely ‘k (proxy# @_ @m)’
In the expression: k (proxy# @_ @m) . enumerateFields @ms k
|
201 | enumerateFields k = k (proxy# @_ @m) . enumerateFields @ms k
| ^^^^^^^^^^^^
Hi,
I recently started a library to load assets from the gltf spec (here) with the aim of being able to efficiently get assets and animations to the vulkan api (using this c++ project as a reference).
I wondered if you could provide some advice: If I have a buffer or raw binary vertex data (ie, a Mesh
) parsed as a little endian ByteString
, some accessor
s telling me what components this buffer represents, the number of bytes per component, the stride, etc, what's the best way to get that geometry into a form that I can get to vkVertexBuffer
efficiently?
I've looked at the DataFrame
PrimBytes
instance but I'm not exactly sure where to start as the easytensor
vulkan-api
design goals are not totally clear to me.
Thanks!
I have tried a lot of things trying to get vulkan-examples (executable ve-06-Drawing) to work with MoltenVK on macOS, but always get the error "ve-06-Drawing: VulkanException {vkeCode = Nothing, vkeMessage = "GLFW reports that vulkan is not supported!"}". It would be awesome if the README had instructions on how to pull that off. I'm assuming this is possible because the README claims that vulkan-api is tested with MoltenVK.
System: macOS 10.14.3
cabal-install and Cabal version: 2.4.1.0
ghc: 8.6.4
Things I tried:
I think that static linking to the frameworks doesn't work because the C code is built without cmake which would define _GLFW_VULKAN_STATIC. This define is queried in vulkan.c. Interestingly this file only mentions .dll and .so files as parameters to dlopen, not .dylib. But I'm probably missing something.
vulkan-api has a lot of modules.
The modules build up into a really long command line passed to GHC, which causes Windows build to crash with createProcess: does not exist (No such file or directory)
error message.
To workaround this problem, I need to either split the build command into several, or group some modules.
I Just recommend to fix your code like this.
Define.hs 53 line
&& (c == "#define VK_MAKE_VERSION(major, minor, patch) \\n (((major) << 22) | ((minor) << 12) | (patch))" || c == "#define VK_MAKE_VERSION(major, minor, patch) \\r\n (((major) << 22) | ((minor) << 12) | (patch))")
It works on any os.
ATM, all FFI by default is unsafe, which makes writing haskell debug callback troublesome.
The proposal is to add another copy for all exported FFI functions, so that the a vulkan call vkXxx
would be translated to three haskell functions:
foreign import ccall safe "vkXxx" vkXxxSafe :: ...
...
foreign import ccall unsafe "vkXxx" vkXxxUnsafe :: ...
...
#ifdef SAFE_FFI_DEFAULT
vkXxx = vkXxxSafe
#else
vkXxx = vkXxxUnsafe
#endif
The same for vk[Get|Lookup][Instance|Device|]Proc
.
Another approach would be to add one boolean type parameter to each vkXxx
function to define whether to call it safe or unsafe. Though, this would require another type class to allow writing two versions of each function (to keep the choice zero-cost at runtime via specialization-inlining).
I have a branch here that allows the examples to compile on nixos, but I get a VK_ERROR_INCOMPATIBLE_DRIVER when trying to run it. vulkaninfo
by itself works fine and doesn't report a driver error, so raising this as an issue in case someone knows what's going on.
I managed to shoot myself in the foot by reading back an array that was set via setListCountAndRef
by extracting the Ptr
near the end of the lifetime of a struct, followed by reading the array with peekArray
. Because the array lifetime is coupled to the struct lifetime, this caused the array to be overwritten sometimes before peekArray
was finished.
While that's entirely my fault, it would be nice to have more field accessor functions. I already have some in Program.Foreign: withUnsafeField
, getListCountAndRef
. (Besides, the function withArrayLen
from this module should probably be in Graphics.Vulkan.Marshal
). Not making a pull request because I don't know where to put them, and I guess they can be done without IO
somehow.
Not sure if this is working as intended or some bug so i post it here.
This one line takes about a minute to compile:
deviceFeaturesStruct = createVk @VkPhysicalDeviceFeatures @'[] $ pure ()
LTS-15.15 stack,
extra-deps:
I've noticed a lot of structures in which you have to set a count field and a pointer field, and it often ends up looking like this:
set @"enabledExtensionCount" (lengthNum extensions) &*
setListRef @"ppEnabledExtensionNames" extensions
where:
lengthNum :: (Foldable t, Num n) => t a -> n
lengthNum = fromIntegral . length
{-# INLINE lengthNum #-}
I'm now imagining a helper for this pattern, something that looks like this:
setCountAndListRef @"enabledExtensionCount" @"ppEnabledExtensionNames" extensions
Best I can come up with to implement it is this:
setCountAndListRef ::
forall countFname arrayFname x c s.
(
CanWriteField countFname x,
CanWriteField arrayFname x,
FieldType countFname x ~ c,
FieldType arrayFname x ~ Ptr s,
Storable s,
Num c
) =>
[s] -> CreateVkStruct x '[countFname, arrayFname] ()
setCountAndListRef ss =
set @countFname (lengthNum ss) &*
setListRef @arrayFname ss
But it doesn't type-check, and I'm unsure how to resolve it. It complains that it can't deduce Graphics.Vulkan.Marshal.Create.Union x '[countFname] '[arrayFname] ~ '[countFname, arrayFname]
.
Edit: Maybe a better name would be setListCountAndRef
.
I'm working through https://vulkan-tutorial.com/, and translating the example code to Haskell as I go. My source is here: https://github.com/rotaerk/vulkanTest.
I got as far as adding validation layers, with everything building and running as expected, but when I added the debug callback (https://github.com/Rotaerk/vulkanTest/blob/master/src/Main.hs#L184), I got the following link error:
Linking dist/build/vulkanTest/vulkanTest ...
dist/build/vulkanTest/vulkanTest-tmp/Main.p_o: In functionsGDa_info': /tmp/nix-build-vulkanTest-0.1.0.0.drv-0/ghc15641_0/ghc_9.p_o:(.text.sGDa_info+0x87): undefined reference to
vkDestroyDebugReportCallbackEXT'
dist/build/vulkanTest/vulkanTest-tmp/Main.p_o: In functioncIyh_info': /tmp/nix-build-vulkanTest-0.1.0.0.drv-0/ghc15641_0/ghc_9.p_o:(.text.sGCM_info+0x2cf): undefined reference to
vkCreateDebugReportCallbackEXT'
collect2: error: ld returned 1 exit status
cc' failed in phase
Linker'. (Exit code: 1)
I'm not sure whether there's a problem with what I'm doing, so this may not be an issue with your bindings. However, I ran across this stackoverflow post indicating that for functions from Vulkan extensions, you're supposed to use vkGetInstanceProcAddr to dynamically load them. I was told that this is true for all extensions.
Your bindings don't do that; instead they do a foreign import of them just like with the core Vulkan functions. I do see that you have some examples using extensions, and I'm not sure how those would work if the above is true ...
Do you have any idea where the problem lies, here?
I'm trying to create some helper functions to eliminate some of the monotony of creating structures, for instance:
applicationInfo ::
CreateVkStruct VkApplicationInfo
'[
"pApplicationName",
"applicationVersion",
"pEngineName",
"engineVersion",
"apiVersion"
] () ->
VkApplicationInfo
applicationInfo rest =
createVk $
set @"sType" VK_STRUCTURE_TYPE_APPLICATION_INFO &*
set @"pNext" VK_NULL &*
rest
However, with this implementation, I have to supply the fields in the order specified in the type signature. Is there some way to resolve this? Would exposing the Union type family help?
Also, it seems like it might be more flexible in this context if there were a way to specify "a CreateVkStruct that has all the fields set except these", and then have the type signature list sType and pNext rather than the ones that the caller must provide.
With last few versions of vulkan-api
I've got some trouble: the generated haddock documentation was above 50MB and hackage rejected it for uploading.
This led me to thing that the source code size (not only haddock) is a bit too much. I open this issue as a request to check what things are not used and can be dropped. This is especially a question to @cjay , @o1lo01ol1o , and @Rotaerk .
For starters, I am thinking about reducing the deriving clause for generated enums: remove Num
, Bounded
, Data
, and Generic
instances. None of these seem to be useful, and Bounded
actually is misleading (e.g. max bound it that of Int32
and does not correspond to the actual enum range). Shall I do that?
For Bits and Bitmasks I would remove Bounded
, Data
, and Generic
, and I am not sure about Real
, Num
, and Integral
. Am I missing anything?
With structs it is a bit more complicated. I think it is possible to restructure a few things in VulkanMarshal
such that Eq
, Show
, Ord
, Storable
can be expressed once in terms of it, and all Field
-related classes can completely go away. The problem is that it probably won't be possible to define VulkanMarshal
instance for user types. Is that a problem?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.