Skip to content

C API Reference

iderex edited this page Jul 19, 2026 · 2 revisions

C API reference

The public surface is a single C header, include/cudec.h. This page is a browsable summary of it; the header is the authoritative contract — the exact argument validation, the async/sync semantics of each call, and the fixed struct layouts live there and win on any discrepancy with this page.

Everything below is extern "C": C-compatible, needs no CUDA headers, never throws across the boundary, and never reports output it did not fully validate. cudec decodes LZ4 only today — block, frame, and streaming. Snappy, GDeflate, and Zstd are planned (see Home) and have no entry points yet.

Versioning

int cudec_version(void);

Returns the runtime library version as major * 10000 + minor * 100 + patch, for an ABI sanity check against the compile-time macros CUDEC_VERSION_MAJOR, CUDEC_VERSION_MINOR, and CUDEC_VERSION_PATCH.

Status codes

Every decode entry point returns a cudec_status. The values are fixed so a caller's switch stays stable across versions.

Status Meaning
CUDEC_OK success
CUDEC_ERR_INVALID_ARGUMENT a NULL/misaligned argument, empty batch, or over-limit batch — rejected, no launch
CUDEC_ERR_CORRUPT_INPUT the bitstream failed validation
CUDEC_ERR_OUTPUT_TOO_SMALL the destination capacity is too small for the decoded output
CUDEC_ERR_CUDA a device or host resource failure
CUDEC_ERR_NOT_IMPLEMENTED reserved; defined in the ABI, not currently returned by any entry point
CUDEC_ERR_UNSUPPORTED a valid frame using a feature outside cudec's supported subset

Types

  • cudec_stream_t — binary-compatible with cudaStream_t without pulling in the CUDA headers (both are pointers to the driver's CUstream_st). Pass a cudaStream_t directly; NULL means the legacy default stream.
  • cudec_chunk_result — the per-chunk outcome, a fixed 16-byte layout on both sides of the ABI: int32_t status (a cudec_status value), uint32_t reserved (written as zero), uint64_t bytes_written (valid output bytes when status is CUDEC_OK). The header pins the layout with a static assertion so a compiler mismatch fails the build rather than corrupting results.
  • cudec_mem_space — where the streaming decoder's per-chunk destinations live: CUDEC_MEM_HOST (host pointers; output is copied device-to-host) or CUDEC_MEM_DEVICE (device pointers; output stays in VRAM).
  • cudec_stream_ctx — an opaque, reusable streaming-decode context (see Streaming decode).

Batch block decode

cudec_status cudec_lz4_decompress_batch(
    const void* const* d_src_ptrs, const size_t* d_src_sizes,
    void* const* d_dst_ptrs, const size_t* d_dst_capacities,
    size_t chunk_count, cudec_chunk_result* d_results,
    cudec_stream_t stream);

Decodes chunk_count independent LZ4 blocks already resident on the GPU. Every array argument is device memory of chunk_count entries, and the pointers those arrays hold are device pointers; d_results must be 16-byte aligned (any cudaMalloc allocation is).

The call is asynchronous on stream: the synchronous return value covers argument validation and launch submission only; the per-chunk outcomes land in d_results and are valid once the stream reaches the end of this launch. On a successful chunk the destination holds exactly bytes_written decoded bytes; a malformed chunk reports a defined error (CUDEC_ERR_CORRUPT_INPUT / CUDEC_ERR_OUTPUT_TOO_SMALL) with bytes_written == 0 and its destination contents are unspecified but never presented as a valid decode.

Validation rejects the whole call synchronously with CUDEC_ERR_INVALID_ARGUMENT and launches nothing on any NULL array argument, a misaligned d_results, an empty batch (chunk_count == 0), or a batch beyond the implementation's launch limit (rejected, never truncated).

Frame decode

cudec_status cudec_lz4f_decompress(
    const void* frame, size_t frame_size,
    void* dst, size_t dst_capacity, size_t* bytes_written);

Decodes a single .lz4 frame (magic, frame descriptor, data blocks, end mark, optional checksums) from host memory into host memory, using the GPU batch decoder internally. Synchronous.

Supported subset: block-independent frames (compressed with LZ4F_blockIndependent). The header, block, and content checksums and the optional declared content size are verified fail-closed when present. Returns:

  • CUDEC_ERR_UNSUPPORTED — a valid frame cudec does not decode (block-linked mode, which is liblz4's frame-compressor default, or a dictionary id);
  • CUDEC_ERR_CORRUPT_INPUT — a malformed frame, a checksum mismatch, or a declared content size that does not match the decoded size;
  • CUDEC_ERR_OUTPUT_TOO_SMALLdst_capacity is too small;
  • CUDEC_ERR_CUDA — a device or host resource failure;
  • CUDEC_ERR_INVALID_ARGUMENT — a NULL frame or bytes_written, or a NULL dst with a non-zero dst_capacity.

On any error *bytes_written is 0 and no partial output is presented as a valid decode.

Streaming decode (reusable context)

The streaming path decodes host-resident compressed chunks, staging them to the GPU through the context's own pinned buffer, and writes the output to either host or device memory. Create a context once and reuse it across decodes so the staging allocation is paid once, not per call; the staging grows on demand to the largest batch seen and is reused for same-or-smaller batches. A context is not thread-safe — use one per thread.

cudec_status cudec_stream_ctx_create(cudec_stream_ctx** out_ctx);

cudec_status cudec_lz4_decompress_stream_ctx(
    cudec_stream_ctx* ctx, const void* const* h_src_ptrs,
    const size_t* h_src_sizes, void* const* dst_ptrs, const size_t* dst_caps,
    size_t chunk_count, cudec_mem_space dst_space,
    cudec_chunk_result* h_results);

void cudec_stream_ctx_destroy(cudec_stream_ctx* ctx);
  • cudec_stream_ctx_create allocates only the CUDA stream and a small event up front; the staging is allocated lazily on the first decode. Returns CUDEC_ERR_INVALID_ARGUMENT if out_ctx is NULL, CUDEC_ERR_CUDA on a stream/event/host allocation failure; on any error *out_ctx is set to NULL.
  • cudec_lz4_decompress_stream_ctx is synchronous: all work is drained before it returns, so every dst[k] and h_results[k] is valid on a CUDEC_OK return. All array arguments are host arrays of chunk_count entries. The decoded output is bit-identical whether the context is fresh or reused (including after the staging has grown) and matches a single-stream reference decode. The aggregate return is CUDEC_OK iff every chunk decoded OK; otherwise a resource failure (CUDEC_ERR_CUDA) takes precedence, then the first non-OK chunk's status in index order.
    • Fail-closed: a NULL ctx, a NULL array, a NULL h_src_ptrs[k] with a non-zero h_src_sizes[k], a NULL dst[k] with a non-zero dst_caps[k], an unknown dst_space, chunk_count == 0, or an over-limit batch returns CUDEC_ERR_INVALID_ARGUMENT, decodes nothing, and does not poison the context.
    • Poison-on-fault: a CUDA fault during a decode poisons the context — it returns CUDEC_ERR_CUDA, every later decode on it returns CUDEC_ERR_CUDA without touching the device, and only cudec_stream_ctx_destroy is valid on it thereafter.
  • cudec_stream_ctx_destroy frees everything the context owns. It is NULL-safe and valid on a poisoned context; after it returns the pointer is dangling.

One-shot streaming

cudec_status cudec_lz4_decompress_stream(
    const void* const* h_src_ptrs, const size_t* h_src_sizes,
    void* const* dst_ptrs, const size_t* dst_caps,
    size_t chunk_count, cudec_mem_space dst_space,
    cudec_chunk_result* h_results);

Equivalent to a cudec_stream_ctx_create, one cudec_lz4_decompress_stream_ctx, and a cudec_stream_ctx_destroy. It pays the full staging allocation on every call; a caller decoding repeatedly should hold a context and call the _ctx entry instead. Same arguments, contract, and fail-closed behavior as the reusable-context decode.

See also

  • Home — overview, the implemented-vs-planned format table, build, and security model.
  • Benchmarks — the measured LZ4 baselines, with methodology.
  • include/cudec.h — the authoritative header.
  • MASTERPLAN — the design record and the architecture pillars behind this ABI.