On this page:
4.1 ravk show:   Review key information
4.1.1 ravk show spec:   Specification review
4.2 ravk generate:   Generate Code to use Vulkan
4.2.1 Using Built-in Generators
4.2.2 Example:   Your First Code Generator
4.2.3 Generator Configuration Space
4.2.3.1 Switches
7.7

4 ravk: Vulkan Ecosystem Controls

ravk (pronounced "Ravick") is a command-line interface that reports useful facts about a Vulkan integration in terms of a vk.xml specification.

You can use ravk to generate modules that operate independently from this collection, generate Racket code fragments for auditing purposes, and to review information about the Vulkan specification itself.

Many commands operate on a copy of vk.xml, and you can specify which to use.

    $ ravk ...           # Use local mirror of vk.xml

    $ ravk --latest ...  # (or -l) Use latest vk.xml from the Khronos Group.

4.1 ravk show: Review key information

Use ravk show to view helpful data about the code that will run on the host system in an integration.

4.1.1 ravk show spec: Specification review

It’s critically important that all concerned parties keep an eye on the Vulkan specification. You will need information about the spec to know if you should upgrade this collection or use a different version of vk.xml to generate code.

    $ ravk show spec           # prints local mirror of vk.xml for offline use.

    $ ravk show spec --xexpr   # (or -x) prints vk.xml as an X-expression. Ignored if -v is set.

    $ ravk show spec --version # (or -v) Show specification version.

    $ ravk -l show spec -x     # X-expression of latest vk.xml

4.2 ravk generate: Generate Code to use Vulkan

    $ ravk generate heading.rkt body.rkt footer.rkt ...

The generate command prints code to STDOUT. The output may be a full Racket module body complete with a #lang line, or a parseable fragment that follows certain assumptions.

Use this command to inspect the Vulkan registry with custom views, or to prepare code with an adjustable level of overhead.

The arguments are paths to Racket modules that must provide a procedure called in-fragment. It returns a sequence of Racket code given a Vulkan specification and a shared configuration.

(require racket/generator)
 
(define (in-fragment registry [config #hash()])
  (in-generator
    (yield "#lang racket/base")
    (yield '(define something 1))))

If the first element of the sequence is a string, it will be printed in display mode. This is to support #lang lines. In this case, a trailing newline character is optional. In all other cases, each element of the sequence is a datum that, when printed in write mode, will appear in a file as a valid Racket expression.

config is populated by the ravk generate command such that the long form name of each option is a key in the dictionary (e.g. --enable-auto-check-vkresult has the key 'enable-auto-check-vkresult. Keys might not be present, and the value of each key depends on the option. See Generator Configuration Space.

The output of each module appears follows the order declared in the command line. There is no guarentee that the output will be a valid program, so you have to know what you are asking for.

4.2.1 Using Built-in Generators

Besides paths to Racket modules, you can symbolically refer to built-in generators. In addition, the output of ravk generate unsafe in particular is the content of vulkan/unsafe.

This effectively locks down a copy of Racket code against a Vulkan spec version, and makes it possible for some packages to operate without a dependency on this collection, and with minimal overhead.

    $ ravk generate unsafe > unsafe.rkt

Here are the currently supported built-in generators:

unsafe

FFI bindings for Vulkan across all platforms and extensions for the given specification.

4.2.2 Example: Your First Code Generator

A code generator module lazily produces Racket code in terms of a Vulkan specification. To write one, you need to know the Vulkan Registry.

It so happens that code generator modules are easy to write with Racket Generators. Be careful not to confuse the two.

In this example, we generate a Racket module that prints platform-specific type names when instantiated. registry-xexpr is bound to an X-expression form of the <registry> (root) element of a Vulkan specification.

"gen-platform-type-printer.rkt"

#lang racket/base
 
(provide in-fragment)
(require racket/generator
         racket/string
         txexpr)
 
(define (in-fragment registry-xexpr [config #hash()])
  (in-generator
    (yield "#lang racket/base")
    (define platform-type-elements
      (findf*-txexpr registry-xexpr
                     (λ (x)
                       (and (list? x)
                            (string-suffix? (attr-ref x 'requires "")
                                            ".h"))))
      (for ([element platform-type-elements])
        (yield `(displayln ,(attr-ref element 'name)))))))

For Vulkan 1.1.126, this session holds:

    $ ravk generate gen-platform-type-printer.rkt > print-platform-types.rkt

    $ racket print-platform-types.rkt

    Display

    VisualID

    Window

    RROutput

    wl_display

    wl_surface

    HINSTANCE

    HWND

    HMONITOR

    HANDLE

    SECURITY_ATTRIBUTES

    DWORD

    LPCWSTR

    xcb_connection_t

    xcb_visualid_t

    xcb_window_t

    zx_handle_t

    GgpStreamDescriptor

    GgpFrameToken

Code generators can also generate documentation or report data. The possibilities are exciting, but some words of warning:

4.2.3 Generator Configuration Space

The built-in code generators share configuration that controls their output. You can control this configuration using command-line flags.

4.2.3.1 Switches

The following values are booleans for in-fragment’s purposes. If the flag is not set, the key will not be set in the dictionary passed to in-fragment.