nos.sys.vulkan¶
The Vulkan subsystem gives plugins access to GPU resources, command recording, shaders, passes and swapchains.
Describes nos.sys.vulkan 8.0 on Nodos 1.4. Code written against an earlier
version of this subsystem does not compile against it — see
Migrate a plugin to 1.4.
Getting the API¶
#include <nosSysVulkan/nosVulkanSubsystem.h>
#define NOS_DEPENDENCIES \
NOS_DEPENDENCY(NOS_VULKAN)
The global nosVulkan is then available wherever the header is included. See
Use the Vulkan subsystem.
| Header | Contents |
|---|---|
<nosSysVulkan/nosVulkanSubsystem.h> |
The API struct, types and macros. |
<nosSysVulkan/Helpers.hpp> |
C++ helpers in nos::sys::vulkan (aliased nos::vkss). |
<nosSysVulkan/Types_generated.h> |
FlatBuffers types, including Texture and Buffer. |
Prefer the helpers. They fill in the parameter structs and return RAII object references.
C++ helpers¶
Namespace nos::sys::vulkan.
| Helper | Returns |
|---|---|
BeginCmd(nos::Name name, nos::uuid nodeId) |
nosCmd. Records the associated node for profiling. |
EndCmd(nosCmd, nosBool forceSubmit = false, nosGPUEvent* outEvent = nullptr) |
void |
CreateTexture(nosTextureInfo, const char* tag) |
TypedObjectRef<Texture> |
CreateTexture3D(...) |
TypedObjectRef<Texture3D> |
CreateBuffer(nosBufferInfo, ...) |
TypedObjectRef<Buffer> |
CreateResource(nosResourceInfo const&, ...) |
ForeignObjectRef |
ImportExternalResource(nosResourceInfo const&, nosExternalMemoryInfo const&, const char* tag) |
ForeignObjectRef |
GetResourceInfo(TypedObjectRef<T> const&) |
std::optional<...Info> — nullopt when the pin holds no resource. |
GetResourceFieldType(nosResourceObject) |
nosTextureFieldType |
GetTextureSizeInBytes(nosTextureInfo) |
uint64_t |
ShaderDataBinding(nosName, T&) |
nosShaderBinding |
ShaderTextureBinding(nosName, nosTextureObject, nosTextureFilter) |
nosShaderBinding |
ShaderBufferBinding(nosName, nosBufferObject) |
nosShaderBinding |
ShaderTextureArrayBinding(nosName, nosTextureObject*, nosTextureFilter*, uint32_t) |
nosShaderBinding |
ShaderTextureBindingFromPin(nosUUID pinId, ...) |
nosShaderBinding |
IsTextureFieldTypeInterlaced(nosTextureFieldType) |
bool |
FlippedField(nosTextureFieldType) |
nosTextureFieldType |
GetComponentBytesFromTextureFormat(nosFormat) |
unsigned short |
GetNumberOfComponentsFromTextureFormat(nosFormat) |
unsigned short |
Command recording¶
Most calls record into a nosCmd and are not synchronised between CPU and GPU. Nothing executes
until the command buffer is submitted.
Begin¶
typedef struct nosCmdBeginParams
{
nosName Name; // debug label for recorded commands
nosUUID AssociatedNodeId; // node sending the commands, if applicable
nosCmd* OutCmdHandle; // filled with the handle to use for subsequent calls
nosCmdQueueType PreferredQueueType;
} nosCmdBeginParams;
Use vkss::BeginCmd(name, NodeId) rather than filling this in by hand.
End¶
typedef struct nosCmdEndParams
{
nosBool ForceSubmit; // default NOS_FALSE
nosGPUEvent* OutGPUEventHandle; // optional; signalled when the GPU completes
} nosCmdEndParams;
ForceSubmit- Submits the buffer to the GPU. Recorded commands do not execute until submission, and ordinary nodes on a path can leave this false — the engine batches. Submitting has a significant performance cost. Set it true only when the CPU needs the result, or when handing a resource to another graphics API. Command buffers used outside the scheduler thread are submitted regardless.
OutGPUEventHandle- Filled with an event signalled on GPU completion. This does not submit the buffer; waiting
on an event whose buffer was never submitted times out or deadlocks. Every event returned must
eventually reach
WaitGpuEvent, or it leaks.
FlushCommands¶
Resources¶
CreateResource¶
nosResult CreateResource(const nosResourceInfo* resourceInfo,
const nosExternalMemoryHandleType* optExportHandleTypes,
const char* tag,
nosObjectReference* outResource);
tag is a debug label. Prefer vkss::CreateTexture / vkss::CreateBuffer, which return
reference-counted handles with no matching destroy call to remember.
ImportResource¶
nosResult ImportResource(const nosResourceInfo* resourceInfo,
const nosExternalMemoryInfo* importInfo,
const char* tag,
nosObjectReference* outResource);
Brings in memory from another API or process — the basis of cross-process texture sharing.
GetResourceInfo¶
nosResult GetResourceInfo(nosResourceObject handle,
nosResourceInfo* outInfo,
nosExternalMemoryInfo* outExportInfo);
Map¶
CPU pointer to a buffer's memory.
Other resource calls¶
| Function | Purpose |
|---|---|
GetColorTexture(nosVec4 color, nosObjectReference* out) |
A 1×1 texture of a solid colour. |
GetStockTexture(nosObjectReference* out) |
A stock texture. |
IsStockTexture(nosTextureObject, nosStockTexture* outWhich) |
Whether a texture is a stock one. |
IsBlitCompatible(nosFormat src, nosFormat dst) |
Whether Copy supports this format pair. |
SetResourceFieldType(nosResourceObject, nosTextureFieldType) |
Set interlacing field type. |
GetResourceFieldType(nosResourceObject, nosTextureFieldType* out) |
Read it back. |
GetPinTextureFilter(nosUUID pinId, nosTextureFilter* out) |
The filter configured on a pin. |
ResourcePoolGarbageCollect() |
Force-free unused pooled resources. Undoes pool optimisations — call only when genuinely needed. |
Resource types¶
enum nosResourceType
{
NOS_RESOURCE_TYPE_BUFFER = 1,
NOS_RESOURCE_TYPE_TEXTURE = 2,
};
struct nosResourceInfo
{
nosResourceType Type;
union {
nosTextureInfo Texture;
nosBufferInfo Buffer;
};
};
Type must match whichever union member is populated.
Operations¶
Copy¶
typedef struct nosCopyParams
{
nosTextureFilter TextureFilter; // used when blitting between different sizes; LINEAR if params omitted
uint32_t RegionCount;
const nosCopyRegion* Regions;
} nosCopyParams;
Check IsBlitCompatible when the formats differ.
Clear¶
Download¶
nosResult Download(nosCmd, nosTextureObject texture,
nosObjectReference* outBuffer, const char* outBufferTag);
ImageLoad¶
nosResult ImageLoad(nosCmd, const void* buf, nosVec2u extent, nosFormat format,
nosTextureObject dstImg, nosTextureFilter filterIfBlit);
Shaders and passes¶
Compiling and registering¶
A shader is provided to ShaderInfo2.Source as one of: a human-readable HLSL or GLSL source path,
source text, a SPIR-V blob path, or SPIR-V blob data.
nosResult RegisterShaders(size_t count, nosShaderInfo* shaders);
nosResult RegisterPasses(size_t count, nosPassInfo* passInfos);
A pass needs a globally unique PassName — prefix it with your module name. For a render pass,
the fragment shader goes in nosPassInfo.Shader and the optional vertex shader in
nosPassInfo.VertexShader; omitting the vertex shader uses a full-quad default. Compute shaders
form a compute pass.
Running¶
nosResult RunPass(nosCmd, const nosRunPassParams* params);
nosResult RunPass2(nosCmd, const nosRunPass2Params* params);
nosResult RunPass3(nosCmd, const nosRunPass3Params* params);
nosResult RunComputePass(nosCmd, const nosRunComputePassParams* params);
Bind pins to shader parameters with the Shader*Binding helpers.
Shader-only nodes¶
A node with a contents block of type nos.sys.vulkan.GPUNode needs no C++ at all — no binary, no
exported node functions. The shader path is relative to the plugin's manifest; if the extension is
not .spv, the subsystem compiles it with whichever of glslc and dxc succeeds.
"contents": {
"type": "nos.sys.vulkan.GPUNode",
"options": {
"shader": "../Shaders/ColorCorrect.hlsl",
"stage": "FRAGMENT"
}
}
ExecuteGPUNode(void* ctx, nosNodeExecuteParams* params) is the entry point the subsystem uses for
these.
Synchronisation¶
WaitGpuEvent¶
Waits for the GPU to complete work up to the given event, then deletes the event and sets the handle to null.
timeoutNs- Nanoseconds.
UINT64_MAXwaits indefinitely.0deletes the event without waiting, which is the correct way to discard one you no longer need.
Semaphores and events¶
| Function | Purpose |
|---|---|
CreateSemaphore(const nosSemaphoreCreateInfo*, nosObjectReference* out) |
Create a semaphore. |
ExportSemaphore(nosSemaphoreObject, nosSemaphoreExportInfo* out) |
Export for cross-process or cross-API use. |
AddSignalSemaphoreToCmd(nosCmd, nosSemaphoreObject, uint64_t value) |
Signal on completion. |
AddWaitSemaphoreToCmd(nosCmd, nosSemaphoreObject, uint64_t value) |
Wait before executing. |
SignalSemaphore(nosSemaphoreObject, uint64_t value) |
Signal from the CPU. |
CreateGPUEventHolder(nosObjectReference* out) |
Create an event holder object. |
GetGPUEventFromHolder(nosGPUEventHolder, nosGPUEvent** out) |
Extract the event. |
Swapchain and surface¶
For modules presenting to a window directly.
| Function | Purpose |
|---|---|
CreateWindowSurface(void* windowHandle, nosObjectReference* out) |
Surface from a native window handle. |
CreateSwapchain(const nosSwapchainCreateInfo*, nosObjectReference* out, uint32_t* outImgCount) |
Create a swapchain. Access must be externally synchronised. |
SwapchainAcquireNextImage(nosSwapchainObject, uint64_t timeoutNs, uint32_t* outIndex, nosSemaphoreObject toSignal) |
Acquire the next image. May block up to timeoutNs. |
SwapchainPresent(nosSwapchainObject, uint32_t imageIndex, nosSemaphoreObject toWait) |
Present. |
GetSwapchainImages(nosSwapchainObject, nosObjectReference* images) |
Retrieve the images. |
ImageStateToPresent(nosCmd, nosTextureObject) |
Transition an image to present state. |
Note
If SwapchainAcquireNextImage is given a semaphore rather than null, the CPU can run ahead of
the GPU. Wait for the GPU periodically or you will exhaust command resources.