Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
bd48ccb
Build standalone, put the OS primitives behind one Linux seam, and ru…
vish-garg Sep 2, 2026
f5abac4
build: keep IDE project state out of the repository
zlatinski Sep 4, 2026
5ed1383
encoder: refuse an input format the encoder cannot take, rather than …
zlatinski Sep 4, 2026
1ccb2f1
codecutils: make image-view creation follow what the image can support
zlatinski Sep 4, 2026
6a2e1e2
codecutils: adopt a caller's Vulkan objects, and give stdio one switch
zlatinski Sep 4, 2026
c792169
codecutils: ask for STORAGE the way a multi-planar format can grant it
zlatinski Sep 4, 2026
75e7e3a
codecutils: refuse a shader module that failed to compile
zlatinski Sep 4, 2026
26cead3
codecutils: make the compute filter's descriptors match its shaders
zlatinski Sep 4, 2026
e5a1218
filter: list VulkanFilterYuvCompute's members in the order they initi…
zlatinski Sep 9, 2026
d48edbe
encoder: add the content probe, keyed by the caller's frame id
zlatinski Sep 4, 2026
c518e58
encoder: config, DPB and GOP corrections
zlatinski Sep 4, 2026
7b87c5b
encoder: refuse a command-line number the parser would silently change
zlatinski Sep 9, 2026
bf89148
encoder-ext: the embeddable interface, and the session it reshapes
zlatinski Sep 4, 2026
1d822eb
AV1: encode capture, parser fixes, and quantizer defaults
vish-garg Sep 2, 2026
cb3c358
tests(shared): judge the filter's output, and prove a cross-device im…
zlatinski Sep 4, 2026
6d31ca1
tests(encoder-ext): cover the interface a host actually drives
zlatinski Sep 4, 2026
c4892e5
Encoder core: the corrections the encode path needed once a host drov…
vish-garg Sep 2, 2026
a03cb71
Colour model, transfer function, and HDR10 static metadata
vish-garg Sep 2, 2026
5373794
Capability advertisement and the input-format taxonomy
zlatinski Sep 4, 2026
da08c7b
Codec parameters are derived from the geometry the bitstream carries
zlatinski Sep 4, 2026
c8399b3
Layout pins as the struct-extension review gate
vish-garg Sep 2, 2026
db9c19d
Reconfigure: apply what it can carry, refuse the rest
vish-garg Sep 2, 2026
0ec9e21
encoder: make the descriptor API an implementation detail
zlatinski Sep 8, 2026
9b68382
build: make the generated dispatch table a prerequisite of every object
zlatinski Sep 4, 2026
96f3882
encoder: an abstract, reference-counted interface for the encoder
zlatinski Sep 5, 2026
b9402b1
tests: cover the encoder interface, and hold its language floor
zlatinski Sep 5, 2026
68f27ef
encoder: let a caller release the process-wide Vulkan instance
zlatinski Sep 10, 2026
215c874
encoder: stop naming the instance twice on an adopted platform
zlatinski Sep 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ run-name: Native build by ${{ github.actor }}
on:
workflow_dispatch:
workflow_call:

# Runs on pushes to the default branch and on pull requests targeting it.
# A topic branch is gated through its pull request, so nothing beyond the
# default branch is enumerated here.
pull_request:
branches:
- main
Expand Down
19 changes: 19 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ run-name: CI by ${{ github.actor }}

on:
workflow_dispatch:

# Runs on pushes to the default branch and on pull requests targeting it.
# A topic branch is gated through its pull request, so nothing beyond the
# default branch is enumerated here.
pull_request:
branches:
- main
Expand Down Expand Up @@ -67,6 +71,21 @@ jobs:
cmake -B BUILD -DCMAKE_BUILD_TYPE=Release
cmake --build BUILD --parallel $BUILD_JOBS --config Release

# The C++ suite. This is the only `ctest` invocation under
# .github/workflows/, so it is what makes the tree's add_test()
# registrations gate anything.
#
# This runner (ubuntu-24.04, GitHub-hosted) has NO NVIDIA GPU, so the
# tests are split by label: the device-free set must be green here and
# is the real gate, and the gpu set reports SKIPPED rather than FAILED
# when there is no device -- so it is green here too, and becomes a
# genuine gate the day this job moves to a GPU runner. The script also
# fails if any registered test carries neither label, and fails if a
# label selects zero tests, so the gate cannot quietly become a no-op.
- name: Run CTest suite
run: |
./scripts/run_ctest_ci.sh BUILD

- name: Set up Python
uses: actions/setup-python@v5
with:
Expand Down
20 changes: 20 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,26 @@ BUILD*
tests/resources/
tests/results/

# Encoder bitstream output. A run that supplies no output path gets the
# encoder's default name -- out.264, out.265 or out.ivf by codec -- in the
# directory it was run from, so a binary invoked by hand from the tree root
# leaves one here. Test binaries run under CTest do not: each runs in its own
# directory inside the build tree, which BUILD* above already covers.
#
# The three default names, anchored to the root, and NOT the extensions: an
# elementary stream in these formats is also the shape a reference or golden
# bitstream takes, and one added under docs/ or tests/ is content the
# repository is meant to carry rather than an artifact of a build.
/out.264
/out.265
/out.ivf

# Generated into the build tree by cmake/VulkanDispatchTable.cmake
common/libs/VkCodecUtils/HelpersDispatchTable.h
common/libs/VkCodecUtils/HelpersDispatchTable.cpp

# IDE / editor project state. Machine-local and not part of the source.
.settings/
.vscode/
.idea/
*.code-workspace
416 changes: 410 additions & 6 deletions CMakeLists.txt

Large diffs are not rendered by default.

27 changes: 19 additions & 8 deletions cmake/VulkanShaderCompilerBackend.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,23 @@ if(VK_VIDEO_SAMPLES_SHADER_BACKEND STREQUAL "glslang")
find_library(GLSLANG_LIBRARY_DEBUG NAMES glslangd HINTS ${GLSLANG_SDK_LIB_HINTS})
find_library(GLSLANG_RESOURCE_LIMITS_LIBRARY_DEBUG NAMES glslang-default-resource-limitsd
HINTS ${GLSLANG_SDK_LIB_HINTS})

# The SDK's glslang is a static library built with ENABLE_OPT=ON, so
# it carries unresolved SPIRV-Tools references (spvContextCreate,
# spvValidatorOptions*) that the linker must satisfy even though we
# never enable the optimizer. The Linux shared library resolves them
# internally and needs none of this.
find_library(SPIRV_TOOLS_LIBRARY NAMES SPIRV-Tools HINTS ${GLSLANG_SDK_LIB_HINTS})
find_library(SPIRV_TOOLS_OPT_LIBRARY NAMES SPIRV-Tools-opt HINTS ${GLSLANG_SDK_LIB_HINTS})
find_library(SPIRV_TOOLS_LIBRARY_DEBUG NAMES SPIRV-Toolsd HINTS ${GLSLANG_SDK_LIB_HINTS})
find_library(SPIRV_TOOLS_OPT_LIBRARY_DEBUG NAMES SPIRV-Tools-optd HINTS ${GLSLANG_SDK_LIB_HINTS})
endif()

# A glslang built with ENABLE_OPT=ON carries unresolved SPIRV-Tools
# references (spvContextCreate, spvValidatorOptions*, and the
# spvtools::Create*Pass factories) that the linker must satisfy even
# though we never enable the optimizer. This is NOT MSVC-specific: it
# applies whenever the glslang we found is a static archive, which is
# what Debian/Ubuntu's libglslang-dev ships. Leaving them unresolved
# still links a shared library, but dlopen() of it then fails with
# undefined symbol: _ZN8spvtools29CreateLocalMultiStoreElimPassEv
# so the search has to run on every platform. Where glslang is a shared
# library that resolves them internally, these archives contribute
# nothing and are simply not pulled in.
find_library(SPIRV_TOOLS_LIBRARY NAMES SPIRV-Tools HINTS ${GLSLANG_SDK_LIB_HINTS})
find_library(SPIRV_TOOLS_OPT_LIBRARY NAMES SPIRV-Tools-opt HINTS ${GLSLANG_SDK_LIB_HINTS})
endif()

if(GLSLANG_LIBRARY AND GLSLANG_RESOURCE_LIMITS_LIBRARY AND GLSLANG_INCLUDE_DIR)
Expand All @@ -108,6 +114,11 @@ if(VK_VIDEO_SAMPLES_SHADER_BACKEND STREQUAL "glslang")
message(STATUS "Found glslang: ${GLSLANG_LIBRARY} (debug: ${GLSLANG_LIBRARY_DEBUG})")
else()
set(VK_SHADER_COMPILER_LIBS ${GLSLANG_LIBRARY} ${GLSLANG_RESOURCE_LIMITS_LIBRARY})
if(SPIRV_TOOLS_LIBRARY AND SPIRV_TOOLS_OPT_LIBRARY)
list(APPEND VK_SHADER_COMPILER_LIBS
${SPIRV_TOOLS_OPT_LIBRARY} ${SPIRV_TOOLS_LIBRARY})
message(STATUS "Found SPIRV-Tools for static glslang: ${SPIRV_TOOLS_LIBRARY}")
endif()
message(STATUS "Found glslang: ${GLSLANG_LIBRARY}")
endif()
# Both the include root and its glslang/ subdirectory: the sources spell
Expand Down
110 changes: 110 additions & 0 deletions cmake/VvsValidationGate.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Register a CTest entry whose validation-layer output is gating.
#
# THE NAME IS DELIBERATE. Two encoder test directories carry their own gate
# script and define a function of their own, vvs_add_gated_test(). A CMake
# function is global from the point it is defined, so a shared definition
# sharing that name would be replaced by whichever directory the configure
# reached last and every directory after it would silently get the other
# implementation. The two names are distinct so that neither can shadow the
# other.
#
# A test added with add_test() alone reports only its exit code, so a run that
# emitted validation errors and still exited 0 is recorded as PASSED and the
# errors are visible to nobody. vvs_add_validation_gated_test() runs the same
# binary through cmake/validation_gate.cmake, which reads the exit code and
# the layer output together and fails the test that produced a message.
#
# vvs_add_validation_gated_test(<test-name>
# TARGET <executable-target>
# [ARGS <arg>...]
# [EXPECT <VUID>=<count>...])
#
# EXPECT declares a CEILING per VUID, and it is the only way a message is
# tolerated. A VUID that is not named has a ceiling of zero, so a message the
# tree has never seen fails on its first occurrence; a VUID that is named
# fails on the first occurrence past its count. Both facts are printed on
# every run and appended to validation_gate_summary.txt in the build root, so
# an allowance is never silent. An EXPECT entry records a defect that the tree
# already carries and that the entry does not excuse -- name the defect where
# the entry is written.
#
# WHAT PINS WHAT. VK_LAYER_SETTINGS_PATH controls HOW MANY messages print;
# the layer path controls WHETHER ANY DO. VVS_VALIDATION_LAYER_PATH is empty
# by default, and while it is empty the ambient environment decides which
# layer the loader finds -- so set it to make a build self-contained, and set
# VVS_REQUIRE_VALIDATION_LAYER so that a host without a layer reports a
# failure rather than an ungated run.
#
# A GATED TEST STILL RUNS WHERE NO LAYER IS PRESENT, and its own exit code
# still decides its verdict; what a missing layer removes is the validation
# check and nothing else. That is what makes gating a test never weaker than
# leaving it on a plain add_test(): this adds a way to fail and takes none
# away.

set(VVS_VALIDATION_ALLOW_VUIDS "unknown VkStructureType" CACHE STRING
"Regex matched against a validation message BODY; matches are tolerated")
option(VVS_REQUIRE_VALIDATION_LAYER
"Fail, rather than skip, a gated test when no validation layer is installed"
OFF)
set(VVS_VALIDATION_LAYER_PATH "" CACHE PATH
"Directory holding a validation-layer manifest; becomes the tests VK_LAYER_PATH")
set(VVS_VALIDATION_LAYER_LIBDIR "" CACHE PATH
"Directory added to the tests LD_LIBRARY_PATH. A Vulkan SDK layer manifest names a bare soname, so without this the layer loads only if its library is already on the default search path")

set(VVS_VALIDATION_GATE_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/validation_gate.cmake")
set(VVS_VALIDATION_LAYER_SETTINGS "${CMAKE_CURRENT_LIST_DIR}/vk_layer_settings.txt")

function(vvs_add_validation_gated_test _name)
cmake_parse_arguments(_g "" "TARGET" "ARGS;EXPECT" ${ARGN})
if(NOT _g_TARGET)
message(FATAL_ERROR "vvs_add_validation_gated_test(${_name}): TARGET is required")
endif()

# SPACE-separated. validation_gate.cmake documents TEST_ARGS as one argument
# or a space-separated string and splits it on whitespace; a CMake list
# interpolates semicolon-separated, which would reach the binary as a single
# unrecognised argument and make it print its usage and exit non-zero.
string(JOIN " " _gated_args ${_g_ARGS})
# Comma-separated for the same reason, and VUID names carry no commas.
string(JOIN "," _gated_expect ${_g_EXPECT})

set(_env
"VK_LAYER_SETTINGS_PATH=${VVS_VALIDATION_LAYER_SETTINGS}"
# Forced through the loader rather than left to the binary: a binary
# that enables the layer only under a verbose flag would otherwise be
# gated by a layer that never loaded.
"VK_LOADER_LAYERS_ENABLE=VK_LAYER_KHRONOS_validation"
# Makes the loader name the layers it inserts. The gate requires that
# line before it reads a count, so a run with no layer is reported as
# such instead of as a clean one.
"VK_LOADER_DEBUG=layer")
if(VVS_VALIDATION_LAYER_PATH)
list(APPEND _env "VK_LAYER_PATH=${VVS_VALIDATION_LAYER_PATH}")
endif()
if(VVS_VALIDATION_LAYER_LIBDIR)
# Replaces rather than prepends. Deliberate, and opt-in: a test whose
# loader path half-comes from the ambient shell is not reproducible.
list(APPEND _env "LD_LIBRARY_PATH=${VVS_VALIDATION_LAYER_LIBDIR}")
endif()

add_test(NAME ${_name}
COMMAND ${CMAKE_COMMAND}
-DTEST_EXE=$<TARGET_FILE:${_g_TARGET}>
"-DTEST_ARGS=${_gated_args}"
-DREQUIRE_LAYER=${VVS_REQUIRE_VALIDATION_LAYER}
"-DALLOW_VUIDS=${VVS_VALIDATION_ALLOW_VUIDS}"
"-DEXPECT_VUIDS=${_gated_expect}"
"-DGATE_SUMMARY=${CMAKE_BINARY_DIR}/validation_gate_summary.txt"
-P "${VVS_VALIDATION_GATE_SCRIPT}")
# SKIP_REGULAR_EXPRESSION, not SKIP_RETURN_CODE: SKIP_RETURN_CODE outranks
# every other verdict in CTest, so a run that emitted validation errors on
# its way to a skip exit would be recorded as Skipped. The gate emits the
# token below only on a path that has already established there were none,
# and only for the test's own exit 77 -- the same condition SKIP_RETURN_CODE
# 77 named on these tests before they were gated. SKIP_RETURN_CODE cannot be
# carried alongside it in any case: the registered command is the cmake -P
# wrapper, whose exit code is 0 or 1 and never 77.
set_tests_properties(${_name} PROPERTIES
SKIP_REGULAR_EXPRESSION "VALIDATION_GATE_RESULT=SKIP"
ENVIRONMENT "${_env}")
endfunction()
Loading
Loading