// SPDX-FileCopyrightText: 2026 Alex Bates // // SPDX-License-Identifier: AGPL-3.0-or-later /// C bridge for parallel-rdp's Granite Vulkan context and RDP command processor. /// /// Provides a headless Vulkan context (no WSI/window) suitable for sharing the /// VkDevice with wgpu, plus per-editor RDP renderers that submit display list /// commands and produce scanout images. #pragma once #include #ifdef __cplusplus extern "C" { #endif // -- Logging -- /// Log level constants for `rdp_set_log_callback`. #define RDP_LOG_LEVEL_ERROR 0 #define RDP_LOG_LEVEL_WARN 1 #define RDP_LOG_LEVEL_INFO 2 /// Set a callback to receive log messages from parallel-rdp's Granite backend. /// /// Must be called before `rdp_context_create` on the thread that will call /// the bridge functions. The callback receives a log level and a /// null-terminated message string. /// /// Pass NULL to disable the callback and fall back to stderr. void rdp_set_log_callback(void (*callback)(uint32_t level, const char *msg)); // -- Vulkan context (Granite-owned headless device) -- /// Create a headless Vulkan context via Granite. /// /// The caller may request additional instance/device extensions (e.g. those /// required by wgpu) which Granite will enable alongside its own requirements. /// /// Returns an opaque pointer, or NULL on failure. void *rdp_context_create( const char *const *instance_ext, uint32_t num_instance_ext, const char *const *device_ext, uint32_t num_device_ext); /// Destroy a Vulkan context created by `rdp_context_create`. void rdp_context_destroy(void *ctx); /// Get the VkInstance handle from the context. void *rdp_context_get_instance(void *ctx); /// Get the VkPhysicalDevice handle from the context. void *rdp_context_get_physical_device(void *ctx); /// Get the VkDevice handle from the context. void *rdp_context_get_device(void *ctx); /// Get a graphics/compute queue and its family index. void *rdp_context_get_queue(void *ctx, uint32_t *family_index); // -- Renderer (one per editor, owns CommandProcessor + RDRAM) -- /// Create an RDP renderer. /// /// Each renderer has its own CommandProcessor and RDRAM allocation, so /// multiple editors can render independently. /// /// `rdram_size` is typically 4 or 8 MiB. /// `flags` is a bitmask of `RDP::CommandProcessorFlagBits`. void *rdp_renderer_create(void *ctx, uint32_t rdram_size, uint32_t flags); /// Destroy an RDP renderer. void rdp_renderer_destroy(void *renderer); /// Get a mutable pointer to the renderer's RDRAM. uint8_t *rdp_renderer_get_rdram(void *renderer); /// Get the RDRAM size in bytes. uint32_t rdp_renderer_get_rdram_size(void *renderer); /// Begin a new frame context. /// /// Flushes pending work, drains the command ring, and advances Granite's /// per-frame resource tracking. Must be called once per frame before /// enqueuing commands. void rdp_renderer_begin_frame(void *renderer); /// Enqueue RDP commands for processing. /// /// `words` points to an array of 32-bit words (big-endian command data). /// `num_words` is the total number of words. void rdp_renderer_enqueue(void *renderer, const uint32_t *words, uint32_t num_words); /// Set a VI (Video Interface) register. /// /// `reg` is the VIRegister index (0 = Control, 1 = Origin, etc.) void rdp_renderer_set_vi_register(void *renderer, uint32_t reg, uint32_t value); /// Perform scanout: read the framebuffer via the Video Interface and produce /// an output image. /// /// Returns the VkImage handle for the scanout result. The image format is /// R8G8B8A8_UNORM (or SRGB depending on Granite configuration). /// `width` and `height` are set to the scanout dimensions. /// /// Returns NULL if scanout produced no valid image. void *rdp_renderer_scanout(void *renderer, uint32_t *width, uint32_t *height); /// Perform scanout and copy the result to a CPU buffer as RGBA8 pixels. /// /// `buffer` must point to at least `width * height * 4` bytes. /// `width` and `height` are outputs set to the scanout dimensions. /// Returns 1 on success, 0 if scanout produced no valid image. int rdp_renderer_scanout_sync( void *renderer, uint8_t *buffer, uint32_t buffer_size, uint32_t *width, uint32_t *height); /// Signal the renderer's timeline and wait for all previous work to complete. void rdp_renderer_flush(void *renderer); /// Signal the renderer's timeline and return the timeline value (non-blocking). /// /// Call `rdp_renderer_wait_for_timeline` with the returned value to wait /// for all work submitted before this signal to complete. uint64_t rdp_renderer_signal_timeline(void *renderer); /// Wait for the renderer's timeline to reach `value`. void rdp_renderer_wait_for_timeline(void *renderer, uint64_t value); #ifdef __cplusplus } #endif