4c3b11445c
Phase 0 of design/pyrowave-codec-plan.md — the opt-in wired-LAN ultra-low- latency codec. Vendored at upstream 509e4f88 (API 0.4.0, Granite 44362775, volk + vulkan-headers pins in PUNKTFUNK-VENDOR.txt), pruned to the 6.6 MB the standalone no-renderer build needs; scripts/vendor-pyrowave.sh reproduces the tree (a pin bump is protocol-affecting, plan §4.2). build.rs drives the wrapper CMakeLists (static archives incl. a static C-API lib upstream only ships shared) + bindgen over pyrowave.h; Linux and Windows only, empty stub elsewhere (Apple gets a native Metal port, §4.7). Offline-safe by construction: no network, no system lib, vendored Vulkan headers — same model as the opus dep (flatpak builder has no network). Phase-0 validation on .21 (RTX 5070 Ti, driver 610.43.03): - upstream pyrowave-c-test + interop test (incl. dmabuf/DRM-modifier Vulkan<->Vulkan) pass, from the pristine AND the pruned tree - GPU kernel times at ~1.6 bpp noise: encode/decode 0.090/0.042 ms @800p, 0.146/0.067 @1080p, 0.226/0.103 @1440p, 0.477/0.201 @4K — order of magnitude under NVENC's 1-2 ms retrieve, CBR lands within ~100 B of target - cargo test -p pyrowave-sys green (static link + API-version pin check) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
547 lines
24 KiB
C
547 lines
24 KiB
C
// Copyright (c) 2026 Hans-Kristian Arntzen
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#ifndef PYROWAVE_H_
|
|
#define PYROWAVE_H_
|
|
|
|
#if !defined(VULKAN_CORE_H_)
|
|
#error "Must include vulkan headers before including pyrowave.h"
|
|
#endif
|
|
|
|
#include <stddef.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#else
|
|
#include <stdbool.h>
|
|
#endif
|
|
|
|
// API and ABI is not considered stable until MAJOR version hits 1!
|
|
|
|
#define PYROWAVE_API_VERSION_MAJOR 0
|
|
#define PYROWAVE_API_VERSION_MINOR 4
|
|
#define PYROWAVE_API_VERSION_PATCH 0
|
|
|
|
#if !defined(PYROWAVE_PUBLIC_API)
|
|
#if defined(PYROWAVE_EXPORT_SYMBOLS)
|
|
#if defined(__GNUC__)
|
|
#define PYROWAVE_PUBLIC_API __attribute__((visibility("default")))
|
|
#elif defined(_MSC_VER)
|
|
#define PYROWAVE_PUBLIC_API __declspec(dllexport)
|
|
#else
|
|
#define PYROWAVE_PUBLIC_API
|
|
#endif
|
|
#else
|
|
#define PYROWAVE_PUBLIC_API
|
|
#endif
|
|
#else
|
|
#define PYROWAVE_PUBLIC_API
|
|
#endif
|
|
|
|
typedef void (*pyrowave_message_cb)(void *userdata, const char *msg);
|
|
|
|
typedef enum pyrowave_result
|
|
{
|
|
PYROWAVE_SUCCESS = 0,
|
|
PYROWAVE_TIMEOUT = 1,
|
|
PYROWAVE_ERROR_GENERIC = -1,
|
|
PYROWAVE_ERROR_INVALID_ARGUMENT = -2,
|
|
PYROWAVE_ERROR_OUT_OF_HOST_MEMORY = -3,
|
|
PYROWAVE_ERROR_OUT_OF_DEVICE_MEMORY = -4,
|
|
PYROWAVE_ERROR_NO_VULKAN = -5,
|
|
PYROWAVE_ERROR_NOT_IMPLEMENTED = -6,
|
|
PYROWAVE_ERROR_UNSUPPORTED_EXTERNAL_HANDLE = -7,
|
|
PYROWAVE_ERROR_FAILED_EXTERNAL_HANDLE = -8,
|
|
PYROWAVE_ERROR_INT_MAX = 0x7fffffff
|
|
} pyrowave_result;
|
|
|
|
typedef enum pyrowave_chroma_subsampling
|
|
{
|
|
PYROWAVE_CHROMA_SUBSAMPLING_420 = 0,
|
|
PYROWAVE_CHROMA_SUBSAMPLING_444 = 1,
|
|
PYROWAVE_CHROMA_SUBSAMPLING_INT_MAX = 0x7fffffff
|
|
} pyrowave_chroma_subsampling;
|
|
|
|
typedef struct pyrowave_encoder_opaque *pyrowave_encoder;
|
|
typedef struct pyrowave_decoder_opaque *pyrowave_decoder;
|
|
typedef struct pyrowave_device_opaque *pyrowave_device;
|
|
typedef struct pyrowave_sync_object_opaque *pyrowave_sync_object;
|
|
typedef struct pyrowave_image_opaque *pyrowave_image;
|
|
|
|
// Used to dynamically detect any API/ABI incompatibility.
|
|
// This entry point is stable.
|
|
PYROWAVE_PUBLIC_API void pyrowave_get_api_version(uint32_t *major, uint32_t *minor, uint32_t *patch);
|
|
|
|
// Device API.
|
|
PYROWAVE_PUBLIC_API pyrowave_result pyrowave_create_default_device(pyrowave_device *device);
|
|
|
|
typedef struct pyrowave_device_create_queue_info
|
|
{
|
|
VkQueue queue;
|
|
uint32_t familyIndex;
|
|
uint32_t index;
|
|
} pyrowave_device_create_queue_info;
|
|
|
|
// Locks and unlocks submissions to all VkQueues on the VkDevice which the pyrowave_device as access to
|
|
// (either via vkGetDeviceQueue or queue_info structs).
|
|
typedef void (*pyrowave_queue_lock_cb)(void *userdata);
|
|
|
|
typedef struct pyrowave_device_create_info
|
|
{
|
|
// The vkGetInstanceProcAddr entry point for a valid Vulkan loader.
|
|
PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
|
|
|
|
// The Vulkan handles used to create the device.
|
|
VkInstance instance;
|
|
VkPhysicalDevice physical_device;
|
|
VkDevice device;
|
|
|
|
// The CreateInfos used to create instance and device.
|
|
// The pointers and all contents inside them must remain valid for the lifetime of the pyrowave_device.
|
|
// device_create_info needs to supply valid queue create infos as well as
|
|
// extensions and pNext needs to contain PDF2 struct.
|
|
// Instance create infos needs valid extensions as well as a compatible pApplicationInfo w.r.t apiVersion.
|
|
// apiVersion should be at least Vulkan 1.3.
|
|
// At least one graphics capable queue must be present.
|
|
const VkInstanceCreateInfo *instance_create_info;
|
|
const VkDeviceCreateInfo *device_create_info;
|
|
|
|
// Rather than calling vkGetDeviceQueue to get queues,
|
|
// implementation will look for a valid queue here first.
|
|
// This allows passing only graphics queue #2 for example.
|
|
// These queues should only be used for spurious uploads as needed.
|
|
pyrowave_device_create_queue_info *queue_info;
|
|
uint32_t queue_info_count;
|
|
|
|
// Misc callbacks. Can be NULL. If device was created with VK_KHR_implicitly_synchronized_queued, locking
|
|
// callbacks are not needed.
|
|
// pyrowave device will only submit queue commands inside pyrowave device API calls,
|
|
// so that is another way to ensure synchronization.
|
|
pyrowave_queue_lock_cb queue_lock_callback;
|
|
pyrowave_queue_lock_cb queue_unlock_callback;
|
|
|
|
// Userdata provided to callbacks.
|
|
void *userdata;
|
|
} pyrowave_device_create_info;
|
|
|
|
typedef struct pyrowave_uuid
|
|
{
|
|
uint8_t uuid[VK_UUID_SIZE];
|
|
} pyrowave_uuid;
|
|
|
|
typedef struct pyrowave_luid
|
|
{
|
|
uint8_t luid[VK_LUID_SIZE];
|
|
} pyrowave_luid;
|
|
|
|
// Direct API that shares a VkDevice. Avoids needing to use external memory to encode and decode.
|
|
// Encoder expects features:
|
|
// - Basic subgroup support. ARITHMETIC, SHUFFLE, SHUFFLE_RELATIVE, VOTE, BALLOT, CLUSTERED, BASIC (Vulkan 1.1 core).
|
|
// - Subgroup size control (Vulkan 1.3 core).
|
|
// - Subgroup size control enough to force wave16, wave32 or wave64.
|
|
// - shaderInt16
|
|
// - storageBuffer8BitAccess
|
|
// This covers all desktop GPUs and most mobile GPUs.
|
|
// Optional:
|
|
// - shaderFloat16
|
|
// Decoder expects features:
|
|
// - Basic subgroup support. ARITHMETIC, SHUFFLE, SHUFFLE_RELATIVE, VOTE, BALLOT, BASIC (Vulkan 1.1 core).
|
|
// - Subgroup size control (Vulkan 1.3 core).
|
|
// - Anything from wave4 to wave128 goes as long as it supports subgroup size control.
|
|
// Should cover anything remotely relevant.
|
|
PYROWAVE_PUBLIC_API pyrowave_result
|
|
pyrowave_create_device(const pyrowave_device_create_info *info, pyrowave_device *device);
|
|
|
|
// On Windows, LUID is generally used, but other OS-es may need device_uuid/driver_uuid.
|
|
PYROWAVE_PUBLIC_API pyrowave_result pyrowave_create_device_by_compat(
|
|
// If non-zero, needs to match VkPhysicalDeviceProperties::vendorID/deviceID.
|
|
// Risks picking the wrong device if there are multiple ICDs for the same GPU.
|
|
uint32_t vid, uint32_t pid,
|
|
const pyrowave_uuid *device_uuid, // If non-NULL, needs to match VkPhysicalDeviceIDProperties::deviceUUID
|
|
const pyrowave_uuid *driver_uuid, // If non-NULL, needs to match VkPhysicalDeviceIDProperties::driverUUID
|
|
const pyrowave_luid *device_luid, // If non-NULL, needs to match VkPhysicalDeviceIDProperties::deviceLUID
|
|
pyrowave_device *device);
|
|
|
|
// For performance debugging, reports GPU timestamps.
|
|
PYROWAVE_PUBLIC_API void
|
|
pyrowave_device_report_performance_stats(pyrowave_device device, pyrowave_message_cb cb, void *userdata, bool reset);
|
|
|
|
// Out pointers can be NULL, in which case nothing is written to them.
|
|
PYROWAVE_PUBLIC_API void pyrowave_device_get_vk_device_handles(
|
|
pyrowave_device device,
|
|
VkInstance *vk_instance, VkPhysicalDevice *vk_physical_device,
|
|
VkDevice *vk_device);
|
|
|
|
// If a command buffer is set on the device, any encoder or decoder commands which record Vulkan commands
|
|
// will record to cmd instead.
|
|
// pyrowave_device will not submit or close the command buffer.
|
|
// Any state on the command buffer is assumed to be clobbered.
|
|
// When recording is complete, set cmd to VK_NULL_HANDLE.
|
|
// pyrowave_device will only record commands directly inside an API entry point.
|
|
// The command buffer must be created for a an appropriate queue family based on how its used.
|
|
// Encoder: VK_QUEUE_COMPUTE_BIT.
|
|
// Decoder: VK_QUEUE_COMPUTE_BIT (if using normal path), VK_QUEUE_GRAPHICS_BIT (if using fragment path).
|
|
PYROWAVE_PUBLIC_API void
|
|
pyrowave_device_set_command_buffer(pyrowave_device device, VkCommandBuffer cmd);
|
|
|
|
// When an explicit command buffer is not used, controls which queue family is preferred for encode or decode operations.
|
|
// This is typically used to select between graphics or async compute encoding.
|
|
// These methods have tradeoffs, but for cross-process encoding, it makes more sense to use async compute encode,
|
|
// since the graphics queue may become busy.
|
|
// If encoding in-process on QueuePresent or similar, graphics queue might make more sense, since it guarantees lowest possible encoding latency.
|
|
// For decoding, graphics queue is natural since the result will immediately be consumed there.
|
|
// Valid values for queue_flags are VK_QUEUE_GRAPHICS_BIT or VK_QUEUE_COMPUTE_BIT.
|
|
// For borrowed devices, pyrowave must have been provided an async compute queue, or it will fallback to graphics.
|
|
// If there are no async compute queues on the device, graphics queue will be used instead.
|
|
// When explicit command buffers are used, queue_flags denotes which queue type the command buffer belongs to.
|
|
PYROWAVE_PUBLIC_API pyrowave_result
|
|
pyrowave_device_set_queue_type(pyrowave_device device, VkQueueFlagBits queue_flags);
|
|
|
|
PYROWAVE_PUBLIC_API bool
|
|
pyrowave_device_confirm_interop_support(pyrowave_device device);
|
|
|
|
// All encoders and decoders must have been destroyed before destroying the device.
|
|
PYROWAVE_PUBLIC_API void pyrowave_device_destroy(pyrowave_device device);
|
|
////
|
|
|
|
// External sync API
|
|
// On Windows, this is a HANDLE reinterpreted as uintptr_t.
|
|
// On POSIX, it's a file descriptor int casted to uintptr_t.
|
|
typedef uintptr_t pyrowave_os_handle;
|
|
|
|
typedef struct pyrowave_sync_object_create_info
|
|
{
|
|
pyrowave_device device;
|
|
|
|
// If this is an invalid handle according to the OS (NULL HANDLE, negative fd),
|
|
// the sync object is created as an exportable handle.
|
|
// If a handle is imported successfully, pyrowave_sync_object takes ownership of the OS handle.
|
|
pyrowave_os_handle external_handle;
|
|
|
|
// Must be one of the supported handle types by the device.
|
|
// The implementation will fail the call with an appropriate error if not supported.
|
|
// Recognized types:
|
|
// - OPAQUE_FD
|
|
// - SYNC_FD_BIT
|
|
// - OPAQUE_WIN32_BIT
|
|
// - OPAQUE_WIN32_KMT_BIT
|
|
// - D3D12_FENCE_BIT (D3D11_FENCE_BIT is alias of D3D12_FENCE_BIT)
|
|
// NOTE: When importing NT handles, the implementation will take ownership and close the HANDLE on import.
|
|
// The semaphore holds a reference to the underlying object.
|
|
// It may be a good idea to call DuplicateHandle() and hand that over to the implementation instead.
|
|
// This has been known to workaround some weird bugs in the wild, but the root cause is unknown.
|
|
VkExternalSemaphoreHandleTypeFlagBits handle_type;
|
|
|
|
// Binary or Timeline. For D3D11/D3D12 fence import, this must be TIMELINE.
|
|
VkSemaphoreType semaphore_type;
|
|
|
|
// Only relevant for importing.
|
|
// For binary semaphores, this must be TEMPORARY for now.
|
|
// This makes the sync object fire and forget and can only be used once.
|
|
// TEMPORARY must not be used for timeline semaphores.
|
|
VkSemaphoreImportFlags import_flags;
|
|
} pyrowave_sync_object_create_info;
|
|
|
|
PYROWAVE_PUBLIC_API pyrowave_result
|
|
pyrowave_sync_object_create(const pyrowave_sync_object_create_info *info, pyrowave_sync_object *sync);
|
|
|
|
PYROWAVE_PUBLIC_API VkSemaphore
|
|
pyrowave_sync_object_get_semaphore(pyrowave_sync_object sync);
|
|
|
|
// Called after signaling a semaphore, the sync payload can be exported to a handle.
|
|
// For timeline semaphores this can be called at any time if was created exportable.
|
|
// The common use case on Windows is to import a D3D12 fence timeline, never export, since
|
|
// not all implementations support exporting a timeline semaphore on that platform,
|
|
// but all support importing.
|
|
PYROWAVE_PUBLIC_API pyrowave_result
|
|
pyrowave_sync_object_export_handle(pyrowave_sync_object sync, pyrowave_os_handle *handle);
|
|
|
|
// Timeout interpreted as Vulkan API.
|
|
PYROWAVE_PUBLIC_API pyrowave_result
|
|
pyrowave_sync_object_cpu_wait(pyrowave_sync_object sync, uint64_t value, uint64_t timeout);
|
|
|
|
PYROWAVE_PUBLIC_API pyrowave_result
|
|
pyrowave_sync_object_cpu_signal(pyrowave_sync_object sync, uint64_t value);
|
|
|
|
PYROWAVE_PUBLIC_API void pyrowave_sync_object_destroy(pyrowave_sync_object sync);
|
|
////
|
|
|
|
// External resource API
|
|
typedef struct pyrowave_image_view
|
|
{
|
|
VkImage image;
|
|
// Extent of mip0. Must be consistent with width/height used to create the encoder.
|
|
// If the view is taking chroma of a planar image,
|
|
// the width/height is for the luma plane, i.e. the base image.
|
|
uint32_t width;
|
|
uint32_t height;
|
|
// Base format used to create the image.
|
|
VkFormat image_format;
|
|
|
|
// Must be UNORM in some way and be supported for sampling and storage.
|
|
// For planar image_format, the image must have been created with
|
|
// VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT to be able to take plane views.
|
|
VkFormat view_format;
|
|
uint32_t mip_level;
|
|
uint32_t layer;
|
|
// If using a planar image format, needs to be e.g. VK_IMAGE_ASPECT_PLANE_*_BIT.
|
|
VkImageAspectFlagBits aspect;
|
|
// For decode path, must be IDENTITY or R.
|
|
VkComponentSwizzle swizzle;
|
|
// Must be VK_IMAGE_LAYOUT_(SHADER_)READ_ONLY_OPTIMAL (encode only) or VK_IMAGE_LAYOUT_GENERAL.
|
|
// For fragment decode path, must be (COLOR_)ATTACHMENT_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL.
|
|
// Pyrowave will not perform any image layout transitions on its own in the GPU buffer paths.
|
|
VkImageLayout layout;
|
|
} pyrowave_image_view;
|
|
|
|
typedef struct pyrowave_image_create_info
|
|
{
|
|
pyrowave_device device;
|
|
|
|
// Must be a valid external handle.
|
|
// NOTE: When importing NT handles, the implementation will take ownership and close the HANDLE on import.
|
|
// The image holds a reference to the underlying object.
|
|
// It may be a good idea to call DuplicateHandle() and hand that over to the implementation instead.
|
|
// This has been known to workaround some weird bugs in the wild, but the root cause is unknown.
|
|
pyrowave_os_handle external_handle;
|
|
VkExternalMemoryHandleTypeFlagBits handle_type;
|
|
|
|
// For OPAQUE handles, the create info must be conformant to spec requirements where the create infos
|
|
// have to match between creator and consumer.
|
|
// (In practice, this can be awkward especially when sharing between e.g. GL and Vulkan,
|
|
// spec calls for enabling "all" flags).
|
|
// For other types, image_create_info has to be compatible enough to make the sharing work.
|
|
//
|
|
// - Tiling must be OPTIMAL or DRM_FORMAT_MODIFIER_EXT.
|
|
// - Sharing mode must be EXCLUSIVE.
|
|
// - If a planar format like NV12 is used, the image must have MUTABLE_BIT image creation set.
|
|
const VkImageCreateInfo *image_create_info;
|
|
|
|
// DRM format modifier usage:
|
|
// - Set image_create_info->tiling to VK_IMAGE_TILING_DRM_FORMAT_MODIFIER.
|
|
// - handle_type must be VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT.
|
|
// - VkImageDrmFormatModifierExplicitCreateInfoEXT must be chained into the pNext of image_create_info.
|
|
|
|
// External images are always assumed to be in GENERAL layout.
|
|
} pyrowave_image_create_info;
|
|
|
|
// Only intended to be used with external memory. For pyrowave_create_device() path
|
|
// application should create its own images and set the image view struct without going through this API.
|
|
PYROWAVE_PUBLIC_API pyrowave_result
|
|
pyrowave_image_create(const pyrowave_image_create_info *info, pyrowave_image *image);
|
|
|
|
PYROWAVE_PUBLIC_API VkImage
|
|
pyrowave_image_get_handle(pyrowave_image image);
|
|
|
|
// Generates an image view from an (imported) image automatically for convenience.
|
|
// - Aspect must be VK_IMAGE_ASPECT_PLANE_0_BIT, PLANE_1_BIT or PLANE_2_BIT.
|
|
// - For 2-plane YCbCr image formats or two component image formats, image view swizzles are used to synthesize 3 planes.
|
|
// - For single component image formats, the aspect is ignored (the image is the plane itself).
|
|
// - For 3-component image formats, the aspect selects the component index through image swizzle.
|
|
//
|
|
// Some validation rules:
|
|
// - For 2-plane YCbCr image formats, usage must not be STORAGE_BIT.
|
|
// - For non-YCbCr image formats with more than 1 component, usage must not be STORAGE_BIT.
|
|
// - Usage must be VK_IMAGE_USAGE_STORAGE_BIT (for decode) or VK_IMAGE_USAGE_SAMPLED_BIT (for encode).
|
|
// - The format of the image must be recognized. Highly unusual formats may be rejected.
|
|
PYROWAVE_PUBLIC_API pyrowave_result
|
|
pyrowave_image_get_image_view(pyrowave_image image, VkImageAspectFlagBits aspect,
|
|
VkImageUsageFlagBits usage, pyrowave_image_view *view);
|
|
|
|
PYROWAVE_PUBLIC_API void pyrowave_image_destroy(pyrowave_image image);
|
|
////
|
|
|
|
// Encoder API
|
|
typedef struct pyrowave_encoder_create_info
|
|
{
|
|
pyrowave_device device;
|
|
// For 420 subsampling, must be even.
|
|
int width;
|
|
int height;
|
|
pyrowave_chroma_subsampling chroma;
|
|
} pyrowave_encoder_create_info;
|
|
|
|
typedef struct pyrowave_packet
|
|
{
|
|
size_t offset;
|
|
size_t size;
|
|
} pyrowave_packet;
|
|
|
|
typedef struct pyrowave_sync_point
|
|
{
|
|
// Can be VK_NULL_HANDLE, in which case it means "no sync".
|
|
VkSemaphore semaphore;
|
|
|
|
// If semaphore is a binary semaphore, value must be 0.
|
|
// NOTE: While waiting for a timeline semaphore value of 0 is valid Vulkan,
|
|
// it's a noop and can be replaced with that.
|
|
uint64_t value;
|
|
} pyrowave_sync_point;
|
|
|
|
typedef struct pyrowave_gpu_external_reference
|
|
{
|
|
pyrowave_image image;
|
|
// VK_QUEUE_FAMILY_EXTERNAL, _FOREIGN, _IGNORED or a normal queue family index.
|
|
uint32_t queue_family_index;
|
|
} pyrowave_gpu_external_reference;
|
|
|
|
typedef struct pyrowave_gpu_buffers
|
|
{
|
|
// All 3 planes must be provided. For NV12 images, pass in the same plane for Cb and Cr, but use swizzle
|
|
// to select R and G planes to fake a YUV420P image.
|
|
// Very slightly less efficient, but should barely be measurable.
|
|
// pyrowave_image_get_image_view() can be used as a helper to fill these in.
|
|
pyrowave_image_view planes[3];
|
|
} pyrowave_gpu_buffers;
|
|
|
|
typedef struct pyrowave_gpu_sync_operation
|
|
{
|
|
// If interacting with external images, it's expected that implementation needs to acquire and release the image.
|
|
// Decode only:
|
|
// If acquiring from QUEUE_FAMILY_IGNORED,
|
|
// the image will be transitioned away from VK_IMAGE_LAYOUT_UNDEFINED instead rather than taking ownership.
|
|
// In Vulkan, if content does not have to be preserved (i.e. decoding), it can just be discarded with UNDEFINED.
|
|
const pyrowave_gpu_external_reference *images;
|
|
size_t num_images;
|
|
pyrowave_sync_point sync;
|
|
} pyrowave_gpu_sync_operation;
|
|
|
|
// TODO: Add support for importing external memory as GPU buffers.
|
|
|
|
// The CPU path is mostly for bringup testing.
|
|
typedef enum pyrowave_cpu_buffer_format
|
|
{
|
|
PYROWAVE_CPU_BUFFER_FORMAT_NV12 = 0, // 2 planes. Y packed in 8bpp, then CbCr packed in 16bpp. Only supported for encoding.
|
|
PYROWAVE_CPU_BUFFER_FORMAT_YUV420P = 1, // 3 planes. Y, Cb, Cr packed into separate planes. Native format for pyrowave.
|
|
PYROWAVE_CPU_BUFFER_FORMAT_YUV444P = 2, // 3 planes. Y, Cb, Cr packed into separate planes. Native format for pyrowave.
|
|
PYROWAVE_CPU_BUFFER_FORMAT_INT_MAX = 0x7fffffff
|
|
} pyrowave_cpu_buffer_format;
|
|
|
|
typedef struct pyrowave_cpu_buffer
|
|
{
|
|
// Written in decoder, read-only in encoder.
|
|
void *data[3];
|
|
// Must be at least width for plane times texel size of the plane.
|
|
size_t row_stride_in_bytes[3];
|
|
// Must be at least row_stride times height of plane.
|
|
size_t plane_size_in_bytes[3];
|
|
// Size of the luma plane. Size of chroma is implied by format.
|
|
// Must be same extent as decoder.
|
|
int width;
|
|
int height;
|
|
pyrowave_cpu_buffer_format format;
|
|
} pyrowave_cpu_buffer;
|
|
|
|
typedef struct pyrowave_rate_control
|
|
{
|
|
// Very basic, target bitstream for an image must not exceed this size.
|
|
size_t maximum_bitstream_size;
|
|
} pyrowave_rate_control;
|
|
|
|
// The entry points for encoder are not thread safe. Application must ensure synchronization.
|
|
PYROWAVE_PUBLIC_API pyrowave_result
|
|
pyrowave_encoder_create(const pyrowave_encoder_create_info *info, pyrowave_encoder *encoder);
|
|
|
|
// Synchronous encode API. For low-latency use cases, overlapping frames in encode is meaningless
|
|
// due to latency and the encoder is so fast anyway. This function will not block, but subsequent functions will.
|
|
// Calling an encode operation with synchronous API clobbers any previous encoded frame.
|
|
// The encoded stream will contain a small sequence counter that tracks frame ordering.
|
|
// acquire and release can be NULL if no sync is required.
|
|
// If command buffer is set on pyrowave_device, acquire and release must both be NULL.
|
|
// If command buffer is set on pyrowave_device, applications is responsible for submitting that work to GPU
|
|
// and waiting for it before calling pyrowave_encoder_compute_num_packets or pyrowave_encoder_packetize.
|
|
// If command buffer is set, application must ensure synchronization as:
|
|
// - Before, the layouts in buffers must be correct.
|
|
// Memory must be visible to COMPUTE_SHADER / SHADER_SAMPLED_READ.
|
|
// - After: Application must add execution barrier on COMPUTE_SHADER stage before writing to images.
|
|
PYROWAVE_PUBLIC_API pyrowave_result
|
|
pyrowave_encoder_encode_gpu_synchronous(pyrowave_encoder encoder,
|
|
const pyrowave_gpu_sync_operation *acquire,
|
|
const pyrowave_gpu_sync_operation *release,
|
|
const pyrowave_gpu_buffers *buffers,
|
|
const pyrowave_rate_control *rate_control);
|
|
|
|
// A command buffer must not be set on pyrowave_device.
|
|
PYROWAVE_PUBLIC_API pyrowave_result
|
|
pyrowave_encoder_encode_cpu_synchronous(pyrowave_encoder encoder, const pyrowave_cpu_buffer *buffers,
|
|
const pyrowave_rate_control *rate_control);
|
|
|
|
// Can only be called after a successful encoding operation and result is only valid for that particular frame.
|
|
// Computes the number of network packets required if each packet can consume a provided number of bytes.
|
|
PYROWAVE_PUBLIC_API pyrowave_result
|
|
pyrowave_encoder_compute_num_packets(pyrowave_encoder encoder, size_t packet_boundary, size_t *num_packets);
|
|
|
|
// Number of packets is implied to be greater-than-equal to num_packets as returned earlier.
|
|
PYROWAVE_PUBLIC_API pyrowave_result
|
|
pyrowave_encoder_packetize(pyrowave_encoder encoder, pyrowave_packet *packets, size_t packet_boundary,
|
|
size_t *out_packets, void *bitstream, size_t size);
|
|
|
|
// Implementation ensures GPU is idle before destroying objects.
|
|
PYROWAVE_PUBLIC_API void
|
|
pyrowave_encoder_destroy(pyrowave_encoder encoder);
|
|
//////
|
|
|
|
// Decoder
|
|
typedef struct pyrowave_decoder_create_info
|
|
{
|
|
pyrowave_device device;
|
|
// For 420 subsampling, must be even.
|
|
int width;
|
|
int height;
|
|
pyrowave_chroma_subsampling chroma;
|
|
bool fragment_path;
|
|
} pyrowave_decoder_create_info;
|
|
|
|
// Fragment path is optimized for typical mobile GPUs which have weak compute support.
|
|
// iDWT is instead computed entirely in traditional render passes and fragment shaders.
|
|
// This path is *not* recommended for desktop-class chips.
|
|
PYROWAVE_PUBLIC_API bool
|
|
pyrowave_decoder_device_prefers_fragment_path(pyrowave_device device);
|
|
|
|
PYROWAVE_PUBLIC_API pyrowave_result
|
|
pyrowave_decoder_create(const pyrowave_decoder_create_info *info, pyrowave_decoder *decoder);
|
|
|
|
// Throws away all queued packets.
|
|
PYROWAVE_PUBLIC_API void pyrowave_decoder_clear(pyrowave_decoder decoder);
|
|
|
|
// A frame is potentially split into multiple packets.
|
|
// If a packet is pushed for a frame that is deemed to arrive earlier, it is dropped.
|
|
// A packet that is pushed for a frame with a higher frame sequence will clear out the old queued frame and start a new frame.
|
|
// Packets are pushed into the decoder until decode_is_ready says it's ready.
|
|
PYROWAVE_PUBLIC_API pyrowave_result
|
|
pyrowave_decoder_push_packet(pyrowave_decoder decoder, const void *data, size_t size);
|
|
|
|
// For error correction purposes, it may be okay to decode a frame which dropped some packets.
|
|
PYROWAVE_PUBLIC_API bool
|
|
pyrowave_decoder_decode_is_ready(pyrowave_decoder decoder, bool allow_partial_frame);
|
|
|
|
// Decoding can be done at any time, leading to potentially corrupt/incomplete results if packets are missing.
|
|
// Missing wavelet weights are assumed to be 0 which can lead to extra blurring.
|
|
// See pyrowave_decoder_decode_is_ready() to determine if the final result is known to be complete.
|
|
// acquire and release can be NULL if no sync is required.
|
|
// If command buffer is set on pyrowave_device, acquire and release must both be NULL.
|
|
// If command buffer is set, application must ensure synchronization as:
|
|
// - Before, the layouts in buffers must be correct.
|
|
// If fragment path, memory must be visible to COLOR_ATTACHMENT_OUTPUT / COLOR_ATTACHMENT_WRITE.
|
|
// If compute path, memory must be visible to COMPUTE_SHADER / SHADER_STORAGE_WRITE.
|
|
// - After: Application must synchronize against the stages above before it can read or transition away.
|
|
PYROWAVE_PUBLIC_API pyrowave_result
|
|
pyrowave_decoder_decode_gpu_buffer(pyrowave_decoder decoder,
|
|
const pyrowave_gpu_sync_operation *acquire,
|
|
const pyrowave_gpu_sync_operation *release,
|
|
const pyrowave_gpu_buffers *buffers);
|
|
|
|
// A command buffer must not be set on pyrowave_device.
|
|
PYROWAVE_PUBLIC_API pyrowave_result
|
|
pyrowave_decoder_decode_cpu_buffer_synchronous(pyrowave_decoder decoder, const pyrowave_cpu_buffer *buffers);
|
|
|
|
// Implementation ensures GPU is idle before destroying objects.
|
|
PYROWAVE_PUBLIC_API void pyrowave_decoder_destroy(pyrowave_decoder decoder);
|
|
//////
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|