{"id":21703543,"url":"https://github.com/jolifantobambla/vk","last_synced_at":"2026-01-05T11:02:14.184Z","repository":{"id":53124272,"uuid":"344886814","full_name":"JolifantoBambla/vk","owner":"JolifantoBambla","description":"Common Lisp/CFFI bindings for the Vulkan API.","archived":false,"fork":false,"pushed_at":"2023-01-23T11:46:53.000Z","size":6785,"stargazers_count":49,"open_issues_count":2,"forks_count":5,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-20T16:49:13.517Z","etag":null,"topics":["cffi","vulkan"],"latest_commit_sha":null,"homepage":"https://jolifantobambla.github.io/vk/","language":"Common Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JolifantoBambla.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-03-05T17:36:38.000Z","updated_at":"2024-12-08T13:49:46.000Z","dependencies_parsed_at":"2023-02-05T00:02:12.810Z","dependency_job_id":null,"html_url":"https://github.com/JolifantoBambla/vk","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/JolifantoBambla/vk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JolifantoBambla%2Fvk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JolifantoBambla%2Fvk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JolifantoBambla%2Fvk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JolifantoBambla%2Fvk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JolifantoBambla","download_url":"https://codeload.github.com/JolifantoBambla/vk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JolifantoBambla%2Fvk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28216332,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2026-01-05T02:00:06.358Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cffi","vulkan"],"created_at":"2024-11-25T21:33:19.605Z","updated_at":"2026-01-05T11:02:14.150Z","avatar_url":"https://github.com/JolifantoBambla.png","language":"Common Lisp","funding_links":[],"categories":[],"sub_categories":[],"readme":"# vk\n[Autogenerated](https://github.com/JolifantoBambla/vk-generator) Common Lisp/CFFI bindings for the Vulkan API.\n\n\n## Motivation\nThe goal of this project is to make Vulkan feel lispy without bringing in too much abstraction.\nIt provides a layer of CLOS wrappers and functions atop CFFI-bindings to the Vulkan shared library that gets rid\nof redundant struct members and output parameters of functions as much as possible.\n\nE.g. where you would have to write the following in C++ (without VulkanHpp) to get all GPUs on a computer:\n\n```cpp\nstd::vector\u003cVkPhysicalDevice\u003e devices;\nuint32_t count = 0;\n\n// first get the number of available devices\nVkResult res = vkEnumeratePhysicalDevices(instance, \u0026count, nullptr);\n\n// then get the devices\ndevices.resize(count);\nres = vkEnumeratePhysicalDevices(instance, \u0026count, devices.data());\n```\n\nYou can just write the following with `vk`:\n\n```cl\n(let ((devices (vk:enumerate-physical-devices instance)))\n  ;; do something with your devices\n  )\n```\n\n\n## Requirements\n\n### Supported CL implementations\n`vk` has been mostly tested on SBCL.\n\nMinimal tests (loading the system and running a dummy test) suggest that `vk` works on:\n\n* ABCL\n* Clozure CL\n* ECL\n* SBCL\n\nCheck out the results of the latest [test actions](https://github.com/JolifantoBambla/vk/actions).\n\nUnfortunately CLISP fails to install using Roswell (at least via GitHub Actions), so it remains untested.\n\nAllegro is installed in a 32 bit version by Roswell (at least via GitHub Actions) which does not support `:long-long`. 64 bit versions are untested.\n\nCMUCL fails to find `libvulkan.so` in the test action.\n\n### Supported operating systems\n`vk` has currently only been tested on linux (Ubuntu 20.04) and Windows (SBCL).\n\nMacOS might also work if [MoltenVK](https://github.com/KhronosGroup/MoltenVK) is set up correctly.\n\n### Supported Vulkan API versions\n**The current version of `vk` is based on version `v1.2.198`.**\n\n`vk` targets Vulkan 1.2, so all versions support the core API of version 1.2.x.\nThe main branch is always generated from the most recent version of the [Vulkan API XML registry](https://github.com/KhronosGroup/Vulkan-Docs)\nsupported by [vk-generator](https://github.com/JolifantoBambla/vk-generator) which also made it to a Vulkan SDK release.\nOther versions are available on other branches named after the version (e.g. `v1.2.153`).\nFor more information about supported versions see the documentation of [vk-generator](https://github.com/JolifantoBambla/vk-generator).\n\n#### Versioning of `vk`\n`vk` uses the following versioning scheme: `major.minor.patch-\u003cVulkan API verion\u003e`.\n\nSince there are a lot of different Vulkan API versions, when there's a bug fix for the current version older versions might not\nreceive bug fixes right away.\nIf you absolutely have to work with a specific version and it seems like a bug fix just won't come for that version, feel free to\nopen an issue in the GitHub repository.\n\n\n#### Migrating from 2.x.x-v1.2.x to 3.x.x-vx.x.x\nHandle types are wrapped in version 3.0.0-v1.2.198 and above.\nShould you have used raw handles returned by `vk` functions with functions from other packages (e.g. for window surface creation), you have to unwrap them by calling `vk:raw-handle`.\n\nFunctions that query a device and return a struct (class) instance that has a `pNext` member (`next` slot) have an additional optional argument of that struct (class) type to allow querying extension-specific information via this `pNext` member.\nIn some cases these new optional arguments might not have been added to the end of a function's lambda list from previous versions.\n\n### CL dependencies\n* `alexandria`\n* `cffi`\n\n#### Test dependencies\n* `rove`\n\n### Other dependencies\n* The `vulkan` shared library. The easiest way of getting it is by installing the [Vulkan SDK](https://vulkan.lunarg.com/sdk/home).\n\n#### MacOS only\n* [MoltenVK](https://github.com/KhronosGroup/MoltenVK)\n\n\n## Installation\nAs of the may 2021 dist update `vk` is available on Quicklisp.\nJust make sure to have Vulkan installed (see [Vulkan SDK](https://vulkan.lunarg.com/sdk/home)), and then run \n\n```cl\n(ql:quickload :vk)\n```\n\n\n## Packages\n\n### vk\nThe main package of this system is `vk`.\nIt provides class and function wrappers over the lower level bindings in the `vulkan` package.\n\nNote that there is no validation done by `vk` whatsoever, so you still need to enable validation layers in the driver yourself when creating a `vk:instance` (i.e. a `VkInstance`) just as you would have to in every other language.\n\n#### Shadowed Symbols\nIt is **not meant do be `:use`d** by packages directly, since **it shadows symbols from `cl`** that clash with function and/or slot names from the Vulkan API:\n\n* `format`\n* `set`\n* `stream`\n* `type`\n* `values`\n\n#### Naming conventions\nIn `vk` all names in the Vulkan API have been stripped of their prefixes (i.e. `Vk` for types and `vk` for commands) and lispified (e.g. `VkInstanceCreateInfo` is `vk:instance-create-info`).\n\nStruct and union member names as well as command arguments designating pointers in the C API by being prefixes with either `p` or `pp` have also been stripped of those (e.g. `pNext` is just `next`). \n\nEnum and bitmask value names have been stripped of any redundant prefixes denoting the enum or bitmask they belong to and are represented as keywords in `vk` (e.g. `VK_FORMAT_R4G4_UNORM_PACK8` is just `:r4g4-unorm-pack8`).\n\n##### Exceptions\nThere are a few name clashes in the C API which break the naming conventions.\nCurrently, they all are between functions and slot accessors of the same name.\nAs a general rule, function names take precedence over slot accessors.\nSlots and their `:initarg`s still have the same name, but the accessors use the lispified names of their corresponding struct members in the C API.\n\n* The accessors to all slots named `wait-semaphores` are named `p-wait-semaphores` because they clash with the name of the function `vk:wait-semaphores`.\n* Types from external headers (e.g. OS specific types) are not modified.\n* Slots and accessors with the name `function` or `pFunction` in the C API are called `function-handle`. \n\n### vulkan (%vk)\n`vulkan` (or `%vk`) contains the lower level `cffi` bindings to the C API.\n\nThe naming conventions are the same as in `vk` except for struct/union member names and command arguments.\n\n### vk-error\n`VkResult` values are automatically translated in both `vk` and `vulkan`.\nEach negative result value is represented as an error type.\nAll error types are exposed via `vk-error` (as well as `vk` and `vulkan`).\n\n### vk-alloc\nContains utilities for allocating resources and translating classes/structs to/from foreign memory.\n\n#### Multithreading\nWhen translating class instances the pointers to all translated struct members which are non-primitive types (e.g of `vk:instance-create-info` if it is bound to an instance of `vk:debug-utils-messenger-create-info-ext`) are stored in the hash table `vk-alloc:*allocated-foreign-objects*` and are freed before the pointer to the translated class instance is freed.\nSince hash tables are not thread-safe and there should be no case where type translation needs to span multiple threads, each thread can and should have its own `vk-alloc:*allocated-foreign-objects*` that is independent of those of other threads.\n\nNote that the wrapper functions in `vk` overwrite `vk-alloc:*allocated-foreign-objects*` in their own scope, so if a thread doesn't explicitly translate class instances, you should be fine.\n\n### vk-utils\nContains utils for `vk`.\n\n`vk-utils` contains `with`-style wrapper macros for most handles in the Vulkan API, e.g. `with-instance`:\n\n```cl\n;; the instance is created using the given create-info and is destroyed\n;; at the end of the implicit progn of this macro:\n(vk-utils:with-instance (instance instance-create-info)\n  (format t \"Found ~a devices!~%\"\n            (length (vk:enumerate-physical-devices instance))))\n```\n\nAll available wrappers are listed in the [API reference](https://jolifantobambla.github.io/vk).\n\nAside from utilities for `vk`, this package also contains the function `memcpy`.\n\n\n## Samples and Usage\nCheck out the [API reference](https://jolifantobambla.github.io/vk).\n\nCheck out the project [vk-samples](https://github.com/JolifantoBambla/vk-samples) for sample usage of `vk` as well as `vk-utils`.\n\n### Structs\nThe Vulkan C API contains loads of structs and unions which each have a corresponding CLOS class in `vk`.\nAll these classes come with `cffi` translators, which automatically translate instances to and from foreign memory whenever they are needed.\nThis also goes for nested structs, so whenever a struct has a pointer to another struct as a member, you can just bind the slot to an instance of the corresponding class.\n\nE.g. the `pInputAssemblyState` member of a `VkGraphicsPipelineCreateInfo` could be set like this in `vk`:\n\n```cl\n(vk:make-graphics-pipeline-create-info\n ...\n :input-assembly-state (vk:make-pipeline-input-assembly-state-create-info\n                        :topology :triangle-list\n                        :primitive-restart-enable nil)\n ...\n )\n```\n\nNote that in some places where a class instance is used (as a slot value or a function argument), you can also use a `cffi:foreign-pointer` as well, which might save you computation time, if you store translated objects yourself somewhere (e.g. `vk:allocation-callbacks`).\n\n`vk` exposes each class directly as well as a `make`-style constructor for every class.\n\nIn the C API structs and unions often contain members which specify the length of another member (e.g. of a `const char*`).\nSince those are redundant they are not included in the class wrappers and are set automatically during translation.\n\nE.g. during translation, the `queueCreateInfoCount` member of a `VkDeviceCreateInfo` is automatically set to the length of the `queue-create-info` slot of the corresponding `vk:device-create-info` instance:\n\n```cl\n(vk:make-device-create-info\n :queue-create-infos (list (vk:make-device-queue-create-info\n                            ...\n                            )))\n```\n\nThe exception to this are `void` pointers to arbitrary data, for which the size can not be determined without any knowledge about the type and number of elements in the array/buffer the pointer points to (e.g. the slot `initial-data` of the class `vk:pipeline-cache-create-info` which wraps `VkPipelineCacheCreateInfo`).\n\nAnother exception are cases where a slot specifies the length of an optional array (which can be null) but is not optional itself (e.g. `descriptor-count` in `vk:descriptor-set-layout-binding` and `swapchain-count` in `vk:present-regions-khr` or `vk:present-times-info-google`).\n\n#### Unions\nA class representing a union in the C API has one slot for each possible member of the union.\nIn order for translation to work properly only one slot should be bound for an instance of a class representing a union.\nIf more than one slot is bound, the first one (w.r.t. the order in which slots were specified in the class definition) will be used during translation.\n`make`-style constructors for such classes allow only exactly one slot to be set.\n\n#### Extending Structs: pNext\nMany structs in the Vulkan API can be extended by one or more other structs using their `pNext` member (a `void` pointer).\nIn `vk` you can bind the `next` slot of such an instance to an instance of the class you'd like to extend it with.\nLike all other slots the data bound to a `next` slot will be automatically translated to foreign memory along with the class instance when it is used as an argument for a function.\nNote however, that there is no validation for bound `next` slots on the `vk` side.\nE.g. to register a debug messenger to a `vk:instance` during creation, you can write:\n\n```cl\n(vk:make-instance-create-info\n :next (vk:make-debug-utils-messenger-create-info-ext\n        :message-type '(:validation)\n        :message-severity '(:info :warning :error)\n        :pfn-user-callback ... ;; some CFFI callback\n        :user-data ...) ;; whatever user data you want to pass\n :application-info ...) ;; whatever you want to enable for your Vulkan instance\n```\n\n### Handles\nLike structs, handle types are wrapped in `vk` with in order to allow type checks when calling `vk` functions.\nThe rationale here is that not having to restart an interactive programming session because a segmentation fault that could have been prevented by a simple type check crashed the Lisp image is more important than the cost of wrapping and unwrapping handles.\nHandle wrappers are structs with a single member `handle` and have the lispified name of their C counterparts (e.g. `instance` instead of `VkInstance`).\nTo access the raw foreign pointer within a handle wrapper, call `vk:raw-handle`.\nTo make a handle wrapper from a raw foreign pointer call `vk:make-\u003chandle-name\u003e-wrapper`.\n\n### Enums \u0026 Bitmasks\nEnums and bitmasks are represented by keywords, just as with all other `cffi` bindings.\n\n### Functions\nAlmost all functions in the C API return a `VkResult` which indicates if its execution was successful or not.\nSo when a function should initialize a handle, it will take a pointer to the handle as an argument and by checking the `VkResult` you would be sure if the handle is valid or not.\nSince this doesn't feel very lispy, `vk` wraps all functions omitting these output parameters from the lamda lists of the wrapper functions and instead returns them as `cl:values` together with the `VkResult`.\nIn the `cl:values`, the output parameters are in order of their appearence in the lambda list of the wrapped function followed by its return value (e.g. a wrapped/translated `VkResult`) if it returns a value (e.g. `vk:create-instance` returns `(cl:values \u003cthe created instance\u003e \u003ca translated VkResult value\u003e)`).\n\nAs with classes, `vk` also omits arguments which specify the length of another argument from the wrapper functions lambda list.\nThe same goes for return values.\nE.g. where `vkEnumeratePhysicalDevices` has two output parameters (`pPhysicalDeviceCount` and `pPhysicalDevices`), `vk:enumerate-physical-devices` only returns the found `physical-device` handles (and the result code, i.e. `:success`):\n\n```cl\n(let ((devices (vk:enumerate-physical-devices instance)))\n  ;; do something with your devices\n  )\n```\n\nThe exception to this are again `void` pointers (e.g. the parameter `data` in `vk:get-query-pool-results` which wraps `vkGetQueryPoolResults` in the C API) which would require some knowledge about the exact type, etc.\n\n#### VkResult\n`VkResult` is an enum with positive and negative values, where negative values encode errors, zero encodes the success of a function and positive values encode the (partial) success of a function.\nIf a function returns a negative `VkResult` `vk` signals a `vk-error` with the error code as a keyword.\n\n#### VkAllocationCallbacks\nAll functions that allocate resources and initialize handles take an intance of `vk:allocation-callbacks` (i.e. `VkAllocationCallbacks`) as an optional argument.\nSince most of the time, this will be the same instance, `vk` provides the parameter `vk:*default-allocator*` which is used as the default value wherever an instance of `vk:allocation-callbacks` is used.\nIt defaults to a `cffi:null-pointer`.\n\n### Using Extensions\nThe Vulkan API offers loads of extensions.\nTo use them, you need to enable them when creating your `vk:instance` or `vk:device` (depending on the type of the extension) by passing their names via the `enabled-extension-names` slot of their respective `*-create-info`s.\nFor this purpose `vk` provides the names of all extensions as constants with the following naming scheme `+-*-extension-name+`.\n\nE.g. the name of the `VK_EXT_debug_utils` extension is `vk:+ext-debug-utils-extension-name+`:\n\n```cl\n(vk:make-instance-create-info\n :application-info ...\n ;; we need to enable the debug utils extension during instance creation\n :enabled-extension-names (list vk:+ext-debug-utils-extension-name+))\n```\n\nApart from being enabled, functions belonging to an extension also need to be loaded for the `vk:instance` or `vk:device` which used them.\nFor this purpose every extension function has an additional optional argument at the very end of its lambda list: `extension-loader`.\nThis always defaults to the parameter `vk:*default-extension-loader*` and must be an instance of the struct `extension-loader`.\n\nIn order for the an `extension-loader` to work, it needs to be supplied with a `vk:instance` and/or a `vk:device`.\nE.g. via creation:\n\n```cl\n(setf vk:*default-extension-loader* (vk:make-extension-loader\n                                     :instance instance\n                                     :device device))\n```\n\nOr by setting them using the readers `(extension-loader-instance vk:*default-extension-loader*)` and `(extension-loader-device vk:*default-extension-loader*)`.\n\nWhen calling an extension function the passed `extension-loader` is searched for the function pointer of the extension function.\nIf it is the first call of the function using this `extension-loader` instance, the function pointer is fetched using `vk:get-instance-proc-addr` or `vk:get-device-proc-addr` and stored in an internal hash map of the `extension-loader` instance.\nThen and in every subsequent call of the extension function this function pointer is used to call the function.\n\nNote that setting the `device` or `instance` of an `extension-loader` via the exposed accessors in `vk` require the given handles to be wrapped, whereas the `vulkan` counterparts require raw foreign pointers.\n\nSo after having initialized the `vk:*default-extension-loader*` you can call extension functions like every other function in `vk`:\n\n```cl\n(vk:create-debug-utils-messenger-ext instance\n                                     create-info)\n```\n\nNote that function pointers fetched for a `vk:device` are favored over `vk:instance` function pointers, so if an `extension-loader` has a `vk:device` and a `vk:instance` and has already loaded the function pointer on a `vk:instance` level, it will fetch and use the `vk:device` level function pointers instead.\nThe reason for this is that `vk:device` level function pointers avoid the overhead of possible dispatch mechanisms in the driver because the exact `vk:device` is already known.\n(This is also true for all other functions in the Vulkan API, so if you really care for performance then you might want to fetch function pointers for all functions via `vk:get-device-proc-addr` and use only those.)\n\n\n## Caveats\n### Validation Errors \u0026 Slime\nValidation errors produced by `VK_LAYER_KHRONOS_validation` are not logged via a debug utils messengers, but directly to `stdout`.\nThis means that for slime users validation errors will be logged to `*inferior-lisp*` by default.\nSee [this stackoverflow answer](https://stackoverflow.com/a/40180199) for more information.\n\n### pNext-member of VkBaseOutStructure\nDue to how foreign structs with `pNext` members are translated from foreign memory, a translated `vk:base-out-structure` will always have a foreign pointer or `nil` bound to its `next`-slot.\nThis should not be a problem however, since there is almost no use for instances of `vk:base-out-structure` aside from determining the actual type of the instance by reading its `s-type`-slot.\n\n### VkShaderModuleCreateInfo\nThe `VkShaderModuleCreateInfo` struct has a member called `codeSize` which is the number of bytes in its `code` member.\nYou might be tempted to read your shaders byte by byte, but `VkShaderModuleCreateInfo` actually expects an array of `uint32_t`.\nAs with other `*Count`-members in the Vulkan API, `vk` determines the value to set for `codeSize` automatically.\nFor this to work properly, the `code` slot of a `vk:shader-module` also needs to be a sequence of 32-bit integers.\n\n`vk-utils:read-shader-source` exists exactly for this purpose: it reads a SPIR-V binary and spits out a vector of 32-bit integers.\n\nAnother option is to use the package [shaderc](https://github.com/JolifantoBambla/shadercl) to compile shaders into a vector of 32-bit integers directly from your REPL.\n\n### Lambda list order\nMany `vk` wrapper functions make use of optional arguments if their C counterparts don't require an argument to be set.\nIn some cases, the order of the wrapper function's lambda list therefore differs from the order of the corresponding C function's argument list.\nE.g. `vk:cmd-pipeline-barrier`, where `src-stage-mask` and `dst-stage-mask` are the last two arguments instead of the second and third one.\n\n### Default values of slots\nSome slots of `vk`'s wrapper classes have default values (mostly number - `0.0` or `0` - and string slots - `\"\"`).\nThe choice for these default values are determined automatically by the generator from the member's type in the C API.\nIn some cases, these defaults don't make much sense (e.g. `vk:viewport`'s `max-depth` slot is `0.0` by default).\n\n\n## Contributing\nFound a bug? Please open a bug report in the GitHub repository.\n\n\n## Acknowledgements\nThe whole project is autogenerated by [vk-generator](https://github.com/JolifantoBambla/vk-generator) which has been forked from [cl-vulkan](https://github.com/3b/cl-vulkan) and is partially ported from [Vulkan-Hpp](https://github.com/KhronosGroup/Vulkan-Hpp).\n\nThe documentation is autogenerated using [staple](https://github.com/Shinmera/staple).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjolifantobambla%2Fvk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjolifantobambla%2Fvk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjolifantobambla%2Fvk/lists"}