├── .github └── FUNDING.yml ├── image_tools ├── external │ ├── stb │ └── bc7enc16 ├── .gitignore ├── include │ ├── image.hpp │ └── block_compression.hpp ├── CMakeLists.txt └── src │ ├── pack.cpp │ ├── unpack.cpp │ └── lib │ ├── image.cpp │ ├── vulkan_tools.cpp │ ├── decompress.cpp │ └── compress.cpp ├── bone_analyzer ├── .gitignore ├── external │ └── json ├── CMakeLists.txt └── src │ └── edge_method.cpp ├── texture_renderer ├── external │ └── stb ├── .gitignore ├── scripts │ ├── solidify.sh │ ├── csv_to_obj.sh │ ├── lib │ │ ├── csv_to_obj.py │ │ └── generate_uvs.py │ ├── run.sh │ ├── prepare.sh │ ├── finish.sh │ └── renderdoc │ │ └── export_pipelines.py ├── CMakeLists.txt └── README.md ├── vulkan_layer ├── external │ ├── stb │ ├── exprtk │ ├── glslang │ ├── image_tools │ ├── SPIRV-Cross │ ├── backward-cpp │ ├── SPIRV-Reflect │ └── Vulkan-ValidationLayers ├── .gitignore ├── test │ ├── rules_fail.txt │ ├── vulkan_test.cpp │ ├── rule_parser.cpp │ ├── rule_parser_multiline.cpp │ ├── custom_structs.cpp │ ├── rules_multiline.txt │ ├── reflection_flags.cpp │ ├── rules_multiline2.txt │ ├── reflection.cpp │ ├── reflection_string.cpp │ ├── enum_reflection.cpp │ ├── struct_tree.cpp │ ├── server_socket.cpp │ ├── rules.txt │ ├── CMakeLists.txt │ └── reflection_array.cpp ├── build32.sh ├── include │ ├── shaders.hpp │ ├── constants.hpp │ ├── utils.hpp │ ├── reflection │ │ ├── reflectionparser.hpp │ │ ├── vkreflection.hpp │ │ └── custom_structs.hpp │ ├── config.hpp │ ├── rules │ │ ├── reader.hpp │ │ ├── ipc.hpp │ │ ├── conditions.hpp │ │ └── execution_env.hpp │ ├── dispatch.hpp │ └── layer.hpp ├── docs │ └── Doxyfile.in ├── CheekyLayerConfig.cmake.in ├── src │ ├── constants.cpp │ ├── dispatch.cpp │ ├── utils.cpp │ ├── rules │ │ ├── data │ │ │ ├── functions.cpp │ │ │ ├── convert.cpp │ │ │ ├── math.cpp │ │ │ ├── variables.cpp │ │ │ ├── map.cpp │ │ │ ├── reduce.cpp │ │ │ └── vulkan.cpp │ │ └── rules.cpp │ ├── config.cpp │ └── descriptors.cpp ├── cheeky_layer_windows.json ├── cheeky_layer_linux.json ├── cheeky_layer32_linux.json ├── generate_reflection.py └── README.md ├── mesh_buffer_tools ├── .gitignore ├── external │ └── json ├── src │ ├── common │ │ ├── buffer.cpp │ │ └── input_assembly.cpp │ ├── pose │ │ └── pose.cpp │ └── extract │ │ └── extract.cpp ├── include │ ├── buffer.hpp │ └── input_assembly.hpp └── CMakeLists.txt ├── tools ├── .stuff │ ├── lib │ │ ├── layer │ │ │ ├── build │ │ │ └── cheeky_layer_linux.json │ │ ├── blender_export_mesh.py │ │ ├── blender_import_mesh.py │ │ ├── blender_pose.py │ │ └── blender_bone_import.py │ └── bin │ │ ├── image_tools │ │ ├── pack │ │ └── unpack │ │ ├── bone_analyzer │ │ ├── mesh_buffer_tools │ │ ├── patch │ │ ├── pose │ │ └── extract │ │ ├── vhtest │ │ ├── vhinstall │ │ ├── vhuninstall │ │ ├── vhenv │ │ ├── vhprepare │ │ ├── vhbonesprepare │ │ ├── vhimageuninstall │ │ ├── vhposeprepare │ │ ├── vhimageprepare │ │ ├── vhmeshuninstall │ │ ├── vhinit │ │ ├── vhmeshprepare │ │ ├── vhimageinstall │ │ ├── vhimagetest │ │ ├── vhmeshinstall │ │ └── vhmeshtest ├── layer │ └── config.txt.template ├── activate └── activate.fish ├── logo.png ├── .woodpecker └── docs.yml ├── LICENSE ├── .gitmodules └── README.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: jcm333 2 | -------------------------------------------------------------------------------- /image_tools/external/stb: -------------------------------------------------------------------------------- 1 | ../../external/stb/ -------------------------------------------------------------------------------- /bone_analyzer/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .cache/ 3 | -------------------------------------------------------------------------------- /bone_analyzer/external/json: -------------------------------------------------------------------------------- 1 | ../../external/json/ -------------------------------------------------------------------------------- /image_tools/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .cache/ 3 | -------------------------------------------------------------------------------- /texture_renderer/external/stb: -------------------------------------------------------------------------------- 1 | ../../external/stb/ -------------------------------------------------------------------------------- /vulkan_layer/external/stb: -------------------------------------------------------------------------------- 1 | ../../external/stb/ -------------------------------------------------------------------------------- /image_tools/external/bc7enc16: -------------------------------------------------------------------------------- 1 | ../../external/bc7enc16/ -------------------------------------------------------------------------------- /mesh_buffer_tools/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .cache/ 3 | -------------------------------------------------------------------------------- /mesh_buffer_tools/external/json: -------------------------------------------------------------------------------- 1 | ../../external/json/ -------------------------------------------------------------------------------- /texture_renderer/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .cache/ 3 | -------------------------------------------------------------------------------- /vulkan_layer/external/exprtk: -------------------------------------------------------------------------------- 1 | ../../external/exprtk/ -------------------------------------------------------------------------------- /vulkan_layer/external/glslang: -------------------------------------------------------------------------------- 1 | ../../external/glslang/ -------------------------------------------------------------------------------- /vulkan_layer/external/image_tools: -------------------------------------------------------------------------------- 1 | ../../image_tools/ -------------------------------------------------------------------------------- /tools/.stuff/lib/layer/build: -------------------------------------------------------------------------------- 1 | ../../../../vulkan_layer/build -------------------------------------------------------------------------------- /vulkan_layer/.gitignore: -------------------------------------------------------------------------------- 1 | .cache/ 2 | build/ 3 | build32/ 4 | -------------------------------------------------------------------------------- /vulkan_layer/external/SPIRV-Cross: -------------------------------------------------------------------------------- 1 | ../../external/SPIRV-Cross/ -------------------------------------------------------------------------------- /vulkan_layer/external/backward-cpp: -------------------------------------------------------------------------------- 1 | ../../external/backward-cpp/ -------------------------------------------------------------------------------- /tools/.stuff/bin/image_tools/pack: -------------------------------------------------------------------------------- 1 | ../../../../image_tools/build/pack -------------------------------------------------------------------------------- /vulkan_layer/external/SPIRV-Reflect: -------------------------------------------------------------------------------- 1 | ../../external/SPIRV-Reflect/ -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JnCrMx/cheeky-imp/HEAD/logo.png -------------------------------------------------------------------------------- /tools/.stuff/bin/bone_analyzer: -------------------------------------------------------------------------------- 1 | ../../../bone_analyzer/build/bone_analyzer -------------------------------------------------------------------------------- /tools/.stuff/bin/image_tools/unpack: -------------------------------------------------------------------------------- 1 | ../../../../image_tools/build/unpack -------------------------------------------------------------------------------- /tools/.stuff/bin/mesh_buffer_tools/patch: -------------------------------------------------------------------------------- 1 | ../../../../mesh_buffer_tools/build/patch -------------------------------------------------------------------------------- /tools/.stuff/bin/mesh_buffer_tools/pose: -------------------------------------------------------------------------------- 1 | ../../../../mesh_buffer_tools/build/pose -------------------------------------------------------------------------------- /tools/.stuff/bin/mesh_buffer_tools/extract: -------------------------------------------------------------------------------- 1 | ../../../../mesh_buffer_tools/build/extract -------------------------------------------------------------------------------- /vulkan_layer/external/Vulkan-ValidationLayers: -------------------------------------------------------------------------------- 1 | ../../external/Vulkan-ValidationLayers/ -------------------------------------------------------------------------------- /tools/.stuff/lib/layer/cheeky_layer_linux.json: -------------------------------------------------------------------------------- 1 | ../../../../vulkan_layer/cheeky_layer_linux.json -------------------------------------------------------------------------------- /tools/.stuff/bin/vhtest: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -f vhimage.txt ]; then 4 | vhimagetest $@ 5 | elif [ -f vhmesh.txt ]; then 6 | vhmeshtest $@ 7 | else 8 | echo "No information file found!" 9 | exit 2 10 | fi 11 | -------------------------------------------------------------------------------- /vulkan_layer/test/rules_fail.txt: -------------------------------------------------------------------------------- 1 | image{} -> log(Lorem ipsum)overflow 2 | image{} -> seq( 3 | image{with(image{})} -> seq() 4 | image{not()} -> seq() 5 | image{compare(math(3x*y\\, x => number(3)), ==, number(3))} -> seq() 6 | -------------------------------------------------------------------------------- /vulkan_layer/build32.sh: -------------------------------------------------------------------------------- 1 | mkdir -p build32 2 | 3 | cmake -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 -DCMAKE_FIND_ROOT_PATH=/usr/lib32 -DVulkan_LIBRARY=/usr/lib32/libvulkan.so -S . -B build32/ 4 | cmake --build build32 --parallel 5 | -------------------------------------------------------------------------------- /tools/.stuff/bin/vhinstall: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -f vhimage.txt ]; then 4 | vhimageinstall $@ 5 | elif [ -f vhmesh.txt ]; then 6 | vhmeshinstall $@ 7 | else 8 | echo "No information file found!" 9 | exit 2 10 | fi 11 | -------------------------------------------------------------------------------- /tools/.stuff/bin/vhuninstall: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -f vhimage.txt ]; then 4 | vhimageuninstall $@ 5 | elif [ -f vhmesh.txt ]; then 6 | vhmeshuninstall $@ 7 | else 8 | echo "No information file found!" 9 | exit 2 10 | fi 11 | -------------------------------------------------------------------------------- /vulkan_layer/include/shaders.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef USE_GLSLANG 4 | #include 5 | extern std::tuple compileShader(EShLanguage stage, std::string glslCode, std::vector& shaderCode); 6 | #endif 7 | -------------------------------------------------------------------------------- /tools/layer/config.txt.template: -------------------------------------------------------------------------------- 1 | dump=true 2 | dumpDirectory=${VH_LAYER_DUMP} 3 | override=true 4 | overrideDirectory=${VH_LAYER_OVERRIDE} 5 | logFile=${VH_LAYER_ROOT}/log.txt 6 | ruleFile=${VH_LAYER_ROOT}/rules.txt 7 | hookDraw=true 8 | pluginDirectory=${VH_LAYER_ROOT}/plugins 9 | -------------------------------------------------------------------------------- /vulkan_layer/include/constants.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace CheekyLayer {namespace Contants 6 | { 7 | extern const std::string LAYER_NAME; 8 | extern const std::string LAYER_DESCRIPTION; 9 | extern const std::string CONFIG_ENV; 10 | extern const std::string GIT_VERSION; 11 | }} -------------------------------------------------------------------------------- /vulkan_layer/docs/Doxyfile.in: -------------------------------------------------------------------------------- 1 | PROJECT_NAME = cheeky-imp 2 | OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@/docs/ 3 | INPUT = @CMAKE_CURRENT_SOURCE_DIR@/include 4 | RECURSIVE = YES 5 | WARN_IF_UNDOCUMENTED = NO 6 | TAGFILES += "@CMAKE_CURRENT_BINARY_DIR@/cppreference-doxygen-web.tag.xml=http://en.cppreference.com/w/" 7 | -------------------------------------------------------------------------------- /tools/.stuff/bin/vhenv: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" == "export" ]; then 4 | export VK_LAYER_PATH="$VH_LIB/layer" 5 | export VK_INSTANCE_LAYERS=VK_LAYER_CHEEKYIMP_CheekyLayer 6 | export CHEEKY_LAYER_CONFIG="$VH_LAYER_ROOT/config.txt" 7 | fi 8 | 9 | echo "VK_LAYER_PATH=\"$VH_LIB/layer\" VK_INSTANCE_LAYERS=VK_LAYER_CHEEKYIMP_CheekyLayer CHEEKY_LAYER_CONFIG=\"$VH_LAYER_ROOT/config.txt\"" 10 | -------------------------------------------------------------------------------- /tools/.stuff/bin/vhprepare: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -f vhimage.txt ]; then 4 | vhimageprepare $@ 5 | elif [ -f vhmesh.txt ]; then 6 | if [ -d texture ]; then 7 | find texture/ -maxdepth 2 -mindepth 2 -name vhimage.txt -printf 'Processing %h\n' -execdir vhprepare \; 8 | fi 9 | vhmeshprepare $@ 10 | if [ -f vhpose.txt ]; then 11 | vhposeprepare $@ 12 | fi 13 | else 14 | echo "No information file found!" 15 | exit 2 16 | fi 17 | -------------------------------------------------------------------------------- /vulkan_layer/CheekyLayerConfig.cmake.in: -------------------------------------------------------------------------------- 1 | include(CMakeFindDependencyMacro) 2 | 3 | find_package(Vulkan REQUIRED) 4 | find_package(OpenSSL REQUIRED) 5 | find_package(Threads REQUIRED) 6 | find_package(spdlog REQUIRED) 7 | find_package(Backward REQUIRED) 8 | 9 | set(CHEEKY_LAYER_GLSLANG @CHEEKY_LAYER_GLSLANG@) 10 | if(CHEEKY_LAYER_GLSLANG) 11 | find_package(glslang REQUIRED) 12 | endif() 13 | 14 | include("${CMAKE_CURRENT_LIST_DIR}/CheekyLayerTargets.cmake") 15 | -------------------------------------------------------------------------------- /tools/.stuff/bin/vhbonesprepare: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -f vhmesh.txt ]; then 4 | echo "No vhmesh.txt file!" 5 | exit 2 6 | fi 7 | if [ ! -f vhpose.txt ]; then 8 | echo "No vhpose.txt file!" 9 | exit 2 10 | fi 11 | 12 | args=$(cat vhmesh.txt | cut -d" " -f1 | sed -E 's/(.*)/\1\nbase_\1.obj\nbase_\1.obj.json\nbones\/\1.json/') 13 | pose=$(cat vhpose.txt | head -n1 | cut -d" " -f1) 14 | 15 | mkdir -p bones 16 | 17 | $VH_BIN/bone_analyzer poses/$pose.json ${args[*]} 18 | -------------------------------------------------------------------------------- /vulkan_layer/src/constants.cpp: -------------------------------------------------------------------------------- 1 | #include "constants.hpp" 2 | #include "git.h" 3 | 4 | namespace CheekyLayer {namespace Contants 5 | { 6 | const std::string LAYER_NAME = "VK_LAYER_CHEEKYIMP_CheekyLayer"; 7 | const std::string LAYER_DESCRIPTION = "Vulkan layer for cheeky-imp - https://github.com/JnCrMx/cheeky-imp"; 8 | const std::string CONFIG_ENV = "CHEEKY_LAYER_CONFIG"; 9 | const std::string GIT_VERSION = std::string{git::Describe()}+(git::AnyUncommittedChanges()?"-dirty":""); 10 | }} 11 | -------------------------------------------------------------------------------- /tools/.stuff/bin/vhimageuninstall: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -f vhimage.txt ]; then 4 | echo "No vhimage.txt file!" 5 | exit 2 6 | fi 7 | 8 | while read line; do 9 | hash=$(echo $line | cut -f1 -d" ") 10 | format=$(echo $line | cut -f2 -d" ") 11 | width=$(echo $line | cut -f3 -d" ") 12 | height=$(echo $line | cut -f3 -d" ") 13 | 14 | echo "Removing image $hash ($format at ${width}x${height}) from overrides ..." 15 | rm $VH_LAYER_OVERRIDE/images/$hash.image 2>/dev/null 16 | done 2 | #include 3 | 4 | int main() { 5 | vk::raii::Context context; 6 | 7 | vk::ApplicationInfo appInfo("CheekyLayer", VK_MAKE_VERSION(0, 0, 1), "CheekyLayer", VK_MAKE_VERSION(0, 0, 1), VK_API_VERSION_1_2); 8 | 9 | vk::raii::Instance instance1(context, vk::InstanceCreateInfo({}, &appInfo, {}, {})); 10 | vk::raii::Instance instance2(context, vk::InstanceCreateInfo({}, &appInfo, {}, {})); 11 | } 12 | -------------------------------------------------------------------------------- /texture_renderer/scripts/solidify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | N=$(nproc) 4 | 5 | if [ -z "$1" ] 6 | then 7 | echo "Usage: $0 WORK-DIR" 8 | exit 1 9 | fi 10 | 11 | dir=$1 12 | 13 | for d in "$dir"/*/; do 14 | event="$(basename ${d%/})" 15 | echo $event 16 | if [ ! -z $FORCE ] || [ ! -f "$dir/$event/texture_solid.png" ]; then 17 | ((i=i%N)); ((i++==0)) && wait 18 | gmic input "$d/texture.png" +solidify 0,0,0 -output[1] "$d/texture_solid.png" & 19 | fi 20 | done 21 | wait 22 | -------------------------------------------------------------------------------- /tools/.stuff/bin/vhposeprepare: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -f vhpose.txt ]; then 4 | echo "No vhpose.txt file!" 5 | exit 2 6 | fi 7 | 8 | 9 | while read line; do 10 | pose=$(echo $line | cut -f1 -d" ") 11 | IFS=' ' read -ra parts <<< "$line" 12 | parts=(${parts[@]:1}) 13 | 14 | echo "Unpacking pose $pose (${parts[@]}) ..." 15 | #java -jar $VH_LIB/mbt.jar pose poses/$pose.bin poses/$pose.json "${parts[@]}" 16 | $VH_BIN/mesh_buffer_tools/pose poses/$pose/ poses/$pose.json ${parts[@]} 17 | done "$obj_dir/$(basename $f .csv).obj" & 25 | done 26 | wait 27 | -------------------------------------------------------------------------------- /tools/.stuff/bin/vhimageprepare: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -f vhimage.txt ]; then 4 | echo "No vhimage.txt file!" 5 | exit 2 6 | fi 7 | 8 | line=$(head -n1 vhimage.txt) 9 | hash=$(echo $line | cut -f1 -d" ") 10 | format=$(echo $line | cut -f2 -d" ") 11 | width=$(echo $line | cut -f3 -d" ") 12 | height=$(echo $line | cut -f4 -d" ") 13 | 14 | echo "Decompressing image $hash ($format at ${width}x${height}) to base.png ..." 15 | $VH_BIN/image_tools/unpack $format $VH_LAYER_DUMP/images/$hash.image base.png $width $height 16 | 17 | cat >.directory < 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | std::string sha256_string(std::span data); 10 | std::string sha256_string(const unsigned char *buf, std::size_t len); 11 | 12 | void replace(std::string& string, const std::string& search, const std::string& replacement); 13 | 14 | uint32_t findMemoryType(VkPhysicalDeviceMemoryProperties memProperties, uint32_t typeFilter, VkMemoryPropertyFlags properties); 15 | 16 | void* find_pnext(const void* pNext, VkStructureType type); 17 | -------------------------------------------------------------------------------- /vulkan_layer/include/reflection/reflectionparser.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace CheekyLayer::reflection { 7 | std::any parse_get(std::string path, const void* p, std::string type); 8 | void parse_set(std::string path, void* p, std::string type, std::any value); 9 | std::string parse_get_type(std::string path, std::string type); 10 | 11 | void parse_assign(std::string expression, void* p, std::string type); 12 | 13 | std::string parse_get_string(std::string path, const void* p, std::string type); 14 | 15 | std::any parse_rvalue(std::string expression, const void* p, std::string dtype); 16 | } 17 | -------------------------------------------------------------------------------- /tools/activate.fish: -------------------------------------------------------------------------------- 1 | #!/use/bin/env fish 2 | 3 | set VH_ROOT $(realpath $PWD) 4 | while [ ! -d "$VH_ROOT/.stuff" ] 5 | set VH_ROOT $(realpath $VH_ROOT/..) 6 | end 7 | 8 | echo "Root directory is $VH_ROOT" 9 | 10 | set -x VH_ROOT "$VH_ROOT" 11 | 12 | set -x VH_BIN "$VH_ROOT/.stuff/bin" 13 | set -x VH_LIB "$VH_ROOT/.stuff/lib" 14 | set -x PATH "$PATH":"$VH_BIN" 15 | 16 | set -x VH_LAYER_ROOT "$VH_ROOT/layer" 17 | set -x VH_LAYER_DUMP "$VH_LAYER_ROOT/dump" 18 | set -x VH_LAYER_OVERRIDE "$VH_LAYER_ROOT/override" 19 | 20 | set -x VH_WORKSPACE "$VH_ROOT/workspace" 21 | 22 | if [ -f "$VH_WORKSPACE/config.fish" ] 23 | source $VH_WORKSPACE/config.fish 24 | end 25 | -------------------------------------------------------------------------------- /mesh_buffer_tools/src/common/buffer.cpp: -------------------------------------------------------------------------------- 1 | #include "buffer.hpp" 2 | 3 | namespace mbt 4 | { 5 | buffer::buffer(std::string path_, int stride_, boost::interprocess::mode_t mode) 6 | { 7 | path = path_; 8 | stride = stride_; 9 | 10 | mapping = file_mapping(path.c_str(), mode); 11 | region = mapped_region(mapping, mode); 12 | 13 | pointer = region.get_address(); 14 | } 15 | 16 | int buffer::count() 17 | { 18 | return region.get_size() / stride; 19 | } 20 | 21 | void* buffer::at(int i) 22 | { 23 | return (void*) ( ((uint8_t*)pointer)+ i*stride ); 24 | } 25 | 26 | size_t buffer::size() 27 | { 28 | return region.get_size(); 29 | } 30 | 31 | void buffer::flush() 32 | { 33 | region.flush(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /vulkan_layer/cheeky_layer_windows.json: -------------------------------------------------------------------------------- 1 | { 2 | "file_format_version" : "1.0.0", 3 | "layer" : { 4 | "name": "VK_LAYER_CHEEKYIMP_CheekyLayer", 5 | "type": "GLOBAL", 6 | "library_path": ".\\cheeky_layer.dll", 7 | "api_version": "1.1.0", 8 | "implementation_version": "1", 9 | "description": "Vulkan layer for cheeky-imp - https://github.com/JnCrMx/cheeky-imp", 10 | "functions": { 11 | "vkGetInstanceProcAddr": "CheekyLayer_GetInstanceProcAddr", 12 | "vkGetDeviceProcAddr": "CheekyLayer_GetDeviceProcAddr" 13 | }, 14 | "enable_environment": { 15 | "ENABLE_CHEEKY_LAYER": "1" 16 | }, 17 | "disable_environment": { 18 | "DISABLE_CHEEKY_LAYER": "1" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /vulkan_layer/cheeky_layer_linux.json: -------------------------------------------------------------------------------- 1 | { 2 | "file_format_version" : "1.0.0", 3 | "layer" : { 4 | "name": "VK_LAYER_CHEEKYIMP_CheekyLayer", 5 | "type": "GLOBAL", 6 | "library_path": "./build/libcheeky_layer.so", 7 | "api_version": "1.1.0", 8 | "implementation_version": "1", 9 | "description": "Vulkan layer for cheeky-imp - https://github.com/JnCrMx/cheeky-imp", 10 | "functions": { 11 | "vkGetInstanceProcAddr": "CheekyLayer_GetInstanceProcAddr", 12 | "vkGetDeviceProcAddr": "CheekyLayer_GetDeviceProcAddr" 13 | }, 14 | "enable_environment": { 15 | "ENABLE_CHEEKY_LAYER": "1" 16 | }, 17 | "disable_environment": { 18 | "DISABLE_CHEEKY_LAYER": "1" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /vulkan_layer/cheeky_layer32_linux.json: -------------------------------------------------------------------------------- 1 | { 2 | "file_format_version" : "1.0.0", 3 | "layer" : { 4 | "name": "VK_LAYER_CHEEKYIMP_CheekyLayer32", 5 | "type": "GLOBAL", 6 | "library_path": "./build32/libcheeky_layer.so", 7 | "api_version": "1.1.0", 8 | "implementation_version": "1", 9 | "description": "Vulkan layer for cheeky-imp - https://github.com/JnCrMx/cheeky-imp", 10 | "functions": { 11 | "vkGetInstanceProcAddr": "CheekyLayer_GetInstanceProcAddr", 12 | "vkGetDeviceProcAddr": "CheekyLayer_GetDeviceProcAddr" 13 | }, 14 | "enable_environment": { 15 | "ENABLE_CHEEKY_LAYER": "1" 16 | }, 17 | "disable_environment": { 18 | "DISABLE_CHEEKY_LAYER": "1" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /mesh_buffer_tools/include/buffer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | using boost::interprocess::file_mapping; 10 | using boost::interprocess::mapped_region; 11 | 12 | namespace mbt 13 | { 14 | class buffer 15 | { 16 | std::string path; 17 | int stride; 18 | file_mapping mapping; 19 | mapped_region region; 20 | void* pointer; 21 | 22 | public: 23 | buffer(std::string path, int stride, boost::interprocess::mode_t mode); 24 | int count(); 25 | size_t size(); 26 | void* at(int i); 27 | void flush(); 28 | 29 | template operator T*() 30 | { 31 | return (T*) pointer; 32 | } 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /tools/.stuff/bin/vhmeshuninstall: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -f vhmesh.txt ]; then 4 | echo "No vhmesh.txt file!" 5 | exit 2 6 | fi 7 | 8 | while read line; do 9 | part=$(echo $line | cut -f1 -d" ") 10 | descriptor=$(echo $line | cut -f2 -d" ") 11 | 12 | indexCount=$(echo $line | cut -f3 -d" ") 13 | firstIndex=$(echo $line | cut -f4 -d" ") 14 | vertexOffset=$(echo $line | cut -f5 -d" ") 15 | 16 | index=$(echo $line | cut -f6 -d" ") 17 | echo "Removing part $part from overrides ..." 18 | 19 | additional=( $(echo $line | cut -f7- -d" ") ) 20 | for i in ${!additional[*]} 21 | do 22 | if ! ((i % 2)); then 23 | rm $VH_LAYER_OVERRIDE/buffers/${additional[$i]}.buf 2>/dev/null 24 | fi 25 | done 26 | 27 | rm $VH_LAYER_OVERRIDE/buffers/$index.buf 2>/dev/null 28 | done 2 | #include 3 | #include 4 | #include 5 | 6 | #include "rules/rules.hpp" 7 | 8 | int main(int argc, char* argv[]) 9 | { 10 | std::string line = argv[1]; 11 | 12 | std::unique_ptr rule = std::make_unique(); 13 | try 14 | { 15 | std::istringstream iss(line); 16 | iss >> *rule; 17 | } 18 | catch(const std::runtime_error ex) 19 | { 20 | std::cerr << "Failed to parse rule \"" << line << "\": " << ex.what() << std::endl; 21 | return 1; 22 | } 23 | 24 | std::ostringstream oss; 25 | rule->print(oss); 26 | 27 | if(oss.str() != line) 28 | { 29 | std::cerr << "Failed to recrated rule \"" << line << "\": output is \"" << oss.str() << "\"" << std::endl; 30 | return 1; 31 | } 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /vulkan_layer/test/rule_parser_multiline.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "rules/rules.hpp" 8 | #include "rules/reader.hpp" 9 | 10 | int main(int argc, char* argv[]) 11 | { 12 | std::string file = argv[1]; 13 | 14 | std::ifstream ifs(file); 15 | CheekyLayer::rules::numbered_streambuf numberer{ifs}; 16 | 17 | std::unique_ptr rule = std::make_unique(); 18 | while(ifs.good()) 19 | { 20 | try 21 | { 22 | ifs >> *rule; 23 | } 24 | catch(const std::runtime_error& ex) 25 | { 26 | std::cout << "Error at " << numberer.line() << ":" << numberer.col() << ":\n\t" << ex.what() << std::endl; 27 | return 2; 28 | } 29 | rule->print(std::cout); 30 | std::cout << std::endl; 31 | } 32 | return 0; 33 | } -------------------------------------------------------------------------------- /vulkan_layer/test/custom_structs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "reflection/reflectionparser.hpp" 6 | #include "reflection/custom_structs.hpp" 7 | 8 | int main() 9 | { 10 | CheekyLayer::reflection::VkCmdDrawIndexed draw = { 11 | .indexCount = 32, 12 | .firstIndex = 1337, 13 | .vertexOffset = 753 14 | }; 15 | 16 | std::any a = CheekyLayer::reflection::parse_get("indexCount", &draw, "VkCmdDrawIndexed"); 17 | assert(std::any_cast(a) == 32); 18 | 19 | std::any b = CheekyLayer::reflection::parse_get("firstIndex", &draw, "VkCmdDrawIndexed"); 20 | assert(std::any_cast(b) == 1337); 21 | 22 | std::any c = CheekyLayer::reflection::parse_get("vertexOffset", &draw, "VkCmdDrawIndexed"); 23 | assert(std::any_cast(c) == 753); 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /tools/.stuff/bin/vhinit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | askdump() { 4 | read -p "Do you want to dump $1? " -r 5 | if [[ $REPLY =~ ^[Yy]$ ]]; then 6 | if [ ! -d "$VH_LAYER_DUMP/$1" ]; then 7 | if [ -d "$VH_LAYER_DUMP/$1_" ]; then 8 | mv "$VH_LAYER_DUMP/$1_" "$VH_LAYER_DUMP/$1" 9 | else 10 | mkdir -p "$VH_LAYER_DUMP/$1" 11 | fi 12 | fi 13 | echo "We will dump $1!" 14 | else 15 | if [ -d "$VH_LAYER_DUMP/$1" ]; then 16 | mv "$VH_LAYER_DUMP/$1" "$VH_LAYER_DUMP/$1_" 17 | fi 18 | echo "We will not dump $1!" 19 | fi 20 | } 21 | 22 | mkdir -p "$VH_LAYER_DUMP" 23 | mkdir -p "$VH_LAYER_OVERRIDE" 24 | 25 | askdump "shaders" 26 | askdump "buffers" 27 | askdump "images" 28 | 29 | mkdir -p "$VH_LAYER_OVERRIDE/shaders" 30 | mkdir -p "$VH_LAYER_OVERRIDE/buffers" 31 | mkdir -p "$VH_LAYER_OVERRIDE/images" 32 | 33 | envsubst < "$VH_LAYER_ROOT/config.txt.template" > "$VH_LAYER_ROOT/config.txt" 34 | -------------------------------------------------------------------------------- /vulkan_layer/test/rules_multiline.txt: -------------------------------------------------------------------------------- 1 | image{} -> logx( 2 | reduce( 3 | map( 4 | unpack(Array, Float, 3, 0, string("1234")), 5 | string, 6 | convert(number, string, current_element()) 7 | ), 8 | string, string(""), 9 | concat(current_reduction(), current_element(), string(" ")) 10 | ) 11 | ) 12 | # comment test! 13 | image{} -> log("1") 14 | 15 | image{} -> log("2") 16 | 17 | # comment test! 18 | # comment test! 19 | # comment test! 20 | # comment test! 21 | image{} -> log("3") 22 | # comment test! 23 | # comment test! 24 | # comment test! 25 | 26 | image{} -> log("4") 27 | 28 | image{} -> logx( 29 | reduce( 30 | map( 31 | unpack(Array, Float, 3, 0, string("1234")), 32 | string, 33 | convert(number, string, current_element()) 34 | ), 35 | # this is a test comment 36 | string, string(""), 37 | concat(current_reduction(), current_element(), string(" ")) 38 | ) 39 | ) 40 | -------------------------------------------------------------------------------- /image_tools/include/image.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace image_tools 8 | { 9 | class image 10 | { 11 | public: 12 | typedef unsigned int color; 13 | image(int width, int height); 14 | image(int w, int h, std::vector&& d); 15 | image(int w, int h, uint8_t* pointer); 16 | 17 | color& at(int x, int y); 18 | glm::vec4 scaled(int x, int y, int w, int h) const; 19 | 20 | operator const uint8_t*(); 21 | 22 | std::vector::iterator begin(); 23 | std::vector::iterator end(); 24 | 25 | std::vector::const_iterator cbegin() const; 26 | std::vector::const_iterator cend() const; 27 | private: 28 | std::vector data; 29 | int width; 30 | int height; 31 | }; 32 | 33 | image::color color(glm::vec4); 34 | glm::vec4 color_to_vec4(image::color); 35 | } 36 | -------------------------------------------------------------------------------- /vulkan_layer/test/reflection_flags.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "reflection/reflectionparser.hpp" 8 | #include "reflection/vkreflection.hpp" 9 | 10 | TEST(reflection, flags) 11 | { 12 | VkDescriptorSetLayoutBinding binding{}; 13 | 14 | CheekyLayer::reflection::parse_assign("stageFlags = VK_SHADER_STAGE_VERTEX_BIT", &binding, "VkDescriptorSetLayoutBinding"); 15 | EXPECT_EQ(binding.stageFlags, VK_SHADER_STAGE_VERTEX_BIT); 16 | 17 | CheekyLayer::reflection::parse_assign("stageFlags = 0", &binding, "VkDescriptorSetLayoutBinding"); 18 | EXPECT_EQ(binding.stageFlags, 0); 19 | 20 | CheekyLayer::reflection::parse_assign("stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT", &binding, "VkDescriptorSetLayoutBinding"); 21 | EXPECT_EQ(binding.stageFlags, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); 22 | } 23 | -------------------------------------------------------------------------------- /mesh_buffer_tools/include/input_assembly.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | namespace mbt 9 | { 10 | class input_attribute 11 | { 12 | public: 13 | input_attribute() {} 14 | input_attribute(int index, std::string name, int location, int binding, std::string format, int offset); 15 | 16 | typedef union { 17 | glm::vec1 vec1; 18 | glm::vec2 vec2; 19 | glm::vec3 vec3; 20 | glm::vec4 vec4; 21 | 22 | glm::u8vec4 u8vec4; 23 | } attribute_value; 24 | 25 | attribute_value read(void* pointer); 26 | void write(attribute_value value, void* pointer); 27 | 28 | int index; 29 | std::string name; 30 | int location; 31 | int binding; 32 | std::string format; 33 | int offset; 34 | 35 | friend std::istream& operator>>(std::istream&, input_attribute&); 36 | }; 37 | std::istream& operator>>(std::istream&, input_attribute&); 38 | } 39 | -------------------------------------------------------------------------------- /vulkan_layer/test/rules_multiline2.txt: -------------------------------------------------------------------------------- 1 | present{ 2 | compare( 3 | unpack(UInt32, 16, datahook:data(mouse)), 4 | ==, 5 | number(1) 6 | ) 7 | } -> seq( 8 | dbus:set( 9 | org.freedesktop.ratbag1, 10 | /org/freedesktop/ratbag1/led/hidraw3/p0/l0, 11 | org.freedesktop.ratbag1.Led, 12 | Color, 13 | ( 14 | math(r*255\, r => unpack(Float, 0, datahook:data(mouse))) 15 | math(g*255\, g => unpack(Float, 4, datahook:data(mouse))) 16 | math(b*255\, b => unpack(Float, 8, datahook:data(mouse))) 17 | ) 18 | ), 19 | dbus:call( 20 | org.freedesktop.ratbag1, 21 | /org/freedesktop/ratbag1/device/hidraw2, 22 | org.freedesktop.ratbag1.Device, 23 | Commit,,), 24 | datahook:set(mouse, 16, pack(UInt32, number(0))) 25 | ) 26 | image{} -> logx(reduce(map(unpack(Array, Float, 3, 0, string("1234")), string, convert(number, string, current_element())), string, string(""), concat(current_reduction(), current_element(), string(" ")))) 27 | -------------------------------------------------------------------------------- /texture_renderer/scripts/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPT="$(realpath "$0")" 4 | SCRIPTPATH="$(dirname "$SCRIPT")" 5 | 6 | N=6 7 | 8 | attachment=1 9 | samples=4 10 | width=2048 11 | height=2048 12 | uvgrow=0.001 13 | 14 | if [ -z "$1" ] 15 | then 16 | echo "Usage: $0 WORK-DIR" 17 | exit 1 18 | fi 19 | 20 | dir="$1" 21 | 22 | for d in "$dir"/*/; do 23 | event="$(basename "${d%/}")" 24 | echo "$event" 25 | if [ ! -z $FORCE ] || [ ! -f "$dir/$event/texture.png" ]; then 26 | ((i=i%N)); ((i++==0)) && wait 27 | "$SCRIPTPATH/../build/texture_renderer" --output "$dir/$event/texture.png" \ 28 | --attachment $attachment --samples $samples --width $width --height $height \ 29 | --shader "$dir/$event/shader.frag" --vertices "$dir/$event/vertices.csv" \ 30 | --pipeline "$dir/$event/pipeline.json" --obj "$dir/$event/model-uv.obj" \ 31 | --uv-grow $uvgrow --auto-size & 32 | fi 33 | done 34 | wait 35 | -------------------------------------------------------------------------------- /vulkan_layer/include/reflection/vkreflection.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace CheekyLayer { namespace reflection { 9 | struct VkReflectInfo 10 | { 11 | std::string name; 12 | std::string type; 13 | bool pointer; 14 | bool array; 15 | std::string arrayLength; 16 | int offset; 17 | }; 18 | 19 | struct VkEnumEntry 20 | { 21 | std::string name; 22 | uint32_t value; 23 | }; 24 | 25 | typedef std::unordered_map inner_reflection_map; 26 | typedef std::unordered_map inner_enum_map; 27 | 28 | struct VkTypeInfo 29 | { 30 | std::string name; 31 | int size; 32 | inner_reflection_map members; 33 | }; 34 | 35 | typedef std::unordered_map reflection_map; 36 | typedef std::unordered_map enum_map; 37 | 38 | extern reflection_map struct_reflection_map; 39 | extern enum_map enum_reflection_map; 40 | }} -------------------------------------------------------------------------------- /.woodpecker/docs.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | download-tag-file: 3 | image: alpine 4 | directory: vulkan_layer 5 | commands: 6 | - apk add --no-cache curl 7 | - mkdir -p build 8 | - curl -L --output build/cppreference-doxygen-web.tag.xml https://upload.cppreference.com/mwiki/images/f/f8/cppreference-doxygen-web.tag.xml 9 | doxygen: 10 | image: greenbone/doxygen 11 | directory: vulkan_layer 12 | commands: 13 | - cd build 14 | - sed -e 's/@CMAKE_CURRENT_BINARY_DIR@/./' -e 's/@CMAKE_CURRENT_SOURCE_DIR@/../' ../docs/Doxyfile.in > Doxyfile 15 | - doxygen 16 | - realpath ./docs 17 | - find ./docs 18 | upload: 19 | image: appleboy/drone-scp 20 | settings: 21 | host: 22 | from_secret: ssh_host 23 | username: 24 | from_secret: ssh_user 25 | key: 26 | from_secret: ssh_key 27 | port: 28 | from_secret: ssh_port 29 | target: /config/data/docs/${CI_REPO}/${CI_COMMIT_BRANCH}/vulkan_layer 30 | source: vulkan_layer/build/docs/html/ 31 | strip_components: 4 32 | -------------------------------------------------------------------------------- /texture_renderer/scripts/lib/generate_uvs.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | import sys 4 | argv = sys.argv 5 | argv = argv[argv.index("--") + 1:] 6 | 7 | bpy.ops.object.delete() 8 | 9 | bpy.ops.wm.obj_import(filepath=argv[0]) 10 | obj = bpy.context.selected_objects[0] 11 | 12 | context = bpy.context 13 | scene = context.scene 14 | vl = context.view_layer 15 | 16 | bpy.ops.object.select_all(action='DESELECT') 17 | 18 | vl.objects.active = obj 19 | obj.select_set(True) 20 | 21 | bpy.ops.object.editmode_toggle() 22 | bpy.ops.mesh.select_all(action='SELECT') 23 | # bpy.ops.uv.unwrap(method='ANGLE_BASED', margin=0.0002) 24 | bpy.ops.uv.lightmap_pack(PREF_CONTEXT='ALL_FACES', PREF_BOX_DIV=64, PREF_MARGIN_DIV=0.1) 25 | bpy.ops.object.editmode_toggle() 26 | 27 | bpy.ops.wm.obj_export(filepath=argv[1], 28 | export_selected_objects=True, export_pbr_extensions=False, export_normals=False, 29 | export_uv=True, export_colors=False, export_materials=False, export_vertex_groups=False, 30 | export_object_groups=False, export_material_groups=False, 31 | export_triangulated_mesh=True 32 | ) 33 | -------------------------------------------------------------------------------- /tools/.stuff/bin/vhmeshprepare: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -f vhmesh.txt ]; then 4 | echo "No vhmesh.txt file!" 5 | exit 2 6 | fi 7 | 8 | 9 | while read line; do 10 | part=$(echo $line | cut -f1 -d" ") 11 | descriptor=$(echo $line | cut -f2 -d" ") 12 | 13 | indexCount=$(echo $line | cut -f3 -d" ") 14 | firstIndex=$(echo $line | cut -f4 -d" ") 15 | vertexOffset=$(echo $line | cut -f5 -d" ") 16 | 17 | index=$(echo $line | cut -f6 -d" ") 18 | 19 | additional=( $(echo $line | cut -f7- -d" ") ) 20 | for i in ${!additional[*]} 21 | do 22 | if ! ((i % 2)); then 23 | additional[$i]="$VH_LAYER_DUMP/buffers/${additional[$i]}.buf" 24 | fi 25 | done 26 | 27 | echo "Unpacking mesh for part $part to base_$part.obj ..." 28 | "$VH_BIN/mesh_buffer_tools/extract" $part "$VH_ROOT/descriptors/$descriptor.txt" base_$part.obj $indexCount $firstIndex $vertexOffset "$VH_LAYER_DUMP/buffers/$index.buf" ${additional[*]} 29 | done /dev/null 2>/dev/null 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 JCM 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /texture_renderer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.28) 2 | 3 | project(texture_renderer) 4 | 5 | set(CMAKE_CXX_STANDARD 20) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | 8 | find_package(Vulkan REQUIRED) 9 | find_package(glm REQUIRED) 10 | 11 | include(FetchContent) 12 | FetchContent_Declare(cxxopts GIT_REPOSITORY https://github.com/jarro2783/cxxopts.git 13 | GIT_TAG v3.3.1) 14 | FetchContent_Declare(glslang GIT_REPOSITORY https://github.com/KhronosGroup/glslang.git 15 | GIT_TAG 15.3.0) 16 | FetchContent_Declare(glaze GIT_REPOSITORY https://github.com/stephenberry/glaze.git 17 | GIT_TAG v5.1.2) 18 | 19 | set(ENABLE_OPT OFF) 20 | FetchContent_MakeAvailable(cxxopts glslang glaze) 21 | 22 | set(SOURCES main.cpp) 23 | 24 | add_executable(texture_renderer ${SOURCES}) 25 | target_link_libraries(texture_renderer PUBLIC 26 | Vulkan::Vulkan Vulkan::Headers 27 | cxxopts::cxxopts glaze::glaze 28 | SPIRV glslang-default-resource-limits 29 | ) 30 | target_include_directories(texture_renderer PRIVATE external/stb) 31 | -------------------------------------------------------------------------------- /tools/.stuff/lib/blender_export_mesh.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import os 3 | import json 4 | 5 | base=os.path.splitext(bpy.path.basename(bpy.data.filepath))[0] 6 | 7 | def export_obj(part): 8 | obj = bpy.data.objects[part] 9 | obj.hide_set(False) 10 | obj.select_set(True) 11 | 12 | bpy.ops.export_scene.obj(filepath=f"{base}_{part}.obj", use_selection=True, use_edges=False, use_normals=True, use_uvs=True, use_materials=False, use_blen_objects=False, use_triangles=True, keep_vertex_order=True) 13 | 14 | groups = {} 15 | for vertex in obj.data.vertices: 16 | for group in vertex.groups: 17 | g = "0" 18 | for group2 in obj.vertex_groups: 19 | if group2.index == group.group: 20 | g = group2.name 21 | break 22 | 23 | if not g in groups: 24 | groups[g] = {} 25 | groups[g][vertex.index] = group.weight 26 | 27 | with open(f"{base}_{part}.obj.json", 'w') as json_file: 28 | json.dump(groups, json_file, sort_keys=True) 29 | 30 | obj.select_set(False) 31 | 32 | f = open("vhmesh.txt", "r") 33 | for x in f: 34 | part=x.split()[0] 35 | export_obj(part) 36 | f.close() 37 | 38 | bpy.ops.wm.quit_blender() 39 | -------------------------------------------------------------------------------- /vulkan_layer/test/reflection.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "reflection/reflectionparser.hpp" 6 | 7 | int main() 8 | { 9 | VkGraphicsPipelineCreateInfo info; 10 | VkPipelineDepthStencilStateCreateInfo depth; 11 | 12 | depth.depthTestEnable = VK_TRUE; 13 | info.pDepthStencilState = &depth; 14 | 15 | std::any a = CheekyLayer::reflection::parse_get("pDepthStencilState->depthTestEnable", &info, "VkGraphicsPipelineCreateInfo"); 16 | assert(std::any_cast(a) == VK_TRUE); 17 | 18 | CheekyLayer::reflection::parse_set("pDepthStencilState->depthTestEnable", &info, "VkGraphicsPipelineCreateInfo", VK_FALSE); 19 | 20 | std::any b = CheekyLayer::reflection::parse_get("pDepthStencilState->depthTestEnable", &info, "VkGraphicsPipelineCreateInfo"); 21 | assert(std::any_cast(b) == VK_FALSE); 22 | 23 | CheekyLayer::reflection::parse_assign("pDepthStencilState->depthTestEnable = VK_TRUE", &info, "VkGraphicsPipelineCreateInfo"); 24 | 25 | std::any c = CheekyLayer::reflection::parse_get("pDepthStencilState->depthTestEnable", &info, "VkGraphicsPipelineCreateInfo"); 26 | assert(std::any_cast(c) == VK_TRUE); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /vulkan_layer/test/reflection_string.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "reflection/reflectionparser.hpp" 6 | 7 | int main() 8 | { 9 | VkGraphicsPipelineCreateInfo info; 10 | VkPipelineDepthStencilStateCreateInfo depth; 11 | 12 | depth.depthCompareOp = VK_COMPARE_OP_ALWAYS; 13 | depth.depthTestEnable = VK_FALSE; 14 | depth.stencilTestEnable = VK_TRUE; 15 | info.pDepthStencilState = &depth; 16 | info.stageCount = 12; 17 | 18 | std::string a = CheekyLayer::reflection::parse_get_string("pDepthStencilState->depthCompareOp", &info, "VkGraphicsPipelineCreateInfo"); 19 | assert(a == "VK_COMPARE_OP_ALWAYS"); 20 | 21 | std::string b = CheekyLayer::reflection::parse_get_string("pDepthStencilState->depthTestEnable", &info, "VkGraphicsPipelineCreateInfo"); 22 | assert(b == "VK_FALSE"); 23 | 24 | std::string c = CheekyLayer::reflection::parse_get_string("pDepthStencilState->stencilTestEnable", &info, "VkGraphicsPipelineCreateInfo"); 25 | assert(c == "VK_TRUE"); 26 | 27 | std::string d = CheekyLayer::reflection::parse_get_string("stageCount", &info, "VkGraphicsPipelineCreateInfo"); 28 | assert(d == "12"); 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/json"] 2 | path = external/json 3 | url = https://github.com/nlohmann/json 4 | shallow = true 5 | [submodule "external/stb"] 6 | path = external/stb 7 | url = https://github.com/nothings/stb 8 | [submodule "external/SPRIV-Cross"] 9 | path = external/SPRIV-Cross 10 | url = https://github.com/KhronosGroup/SPIRV-Cross 11 | [submodule "external/SPIRV-Cross"] 12 | path = external/SPIRV-Cross 13 | url = https://github.com/KhronosGroup/SPIRV-Cross 14 | [submodule "external/glslang"] 15 | path = external/glslang 16 | url = https://github.com/KhronosGroup/glslang 17 | [submodule "external/Vulkan-ValidationLayers"] 18 | path = external/Vulkan-ValidationLayers 19 | url = https://github.com/KhronosGroup/Vulkan-ValidationLayers 20 | [submodule "external/bc7enc16"] 21 | path = external/bc7enc16 22 | url = https://github.com/richgel999/bc7enc16 23 | [submodule "external/exprtk"] 24 | path = external/exprtk 25 | url = https://github.com/ArashPartow/exprtk 26 | [submodule "external/SPIRV-Reflect"] 27 | path = external/SPIRV-Reflect 28 | url = https://github.com/KhronosGroup/SPIRV-Reflect 29 | [submodule "external/backward-cpp"] 30 | path = external/backward-cpp 31 | url = https://github.com/bombela/backward-cpp.git 32 | -------------------------------------------------------------------------------- /vulkan_layer/test/enum_reflection.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "reflection/reflectionparser.hpp" 6 | 7 | int main() 8 | { 9 | VkGraphicsPipelineCreateInfo info; 10 | VkPipelineDepthStencilStateCreateInfo depth; 11 | 12 | depth.depthCompareOp = VK_COMPARE_OP_ALWAYS; 13 | info.pDepthStencilState = &depth; 14 | 15 | std::any a = CheekyLayer::reflection::parse_get("pDepthStencilState->depthCompareOp", &info, "VkGraphicsPipelineCreateInfo"); 16 | assert(std::any_cast(a) == VK_COMPARE_OP_ALWAYS); 17 | 18 | CheekyLayer::reflection::parse_set("pDepthStencilState->depthCompareOp", &info, "VkGraphicsPipelineCreateInfo", (uint32_t)VK_COMPARE_OP_GREATER); 19 | 20 | std::any b = CheekyLayer::reflection::parse_get("pDepthStencilState->depthCompareOp", &info, "VkGraphicsPipelineCreateInfo"); 21 | assert(std::any_cast(b) == VK_COMPARE_OP_GREATER); 22 | 23 | CheekyLayer::reflection::parse_assign("pDepthStencilState->depthCompareOp = VK_COMPARE_OP_NEVER", &info, "VkGraphicsPipelineCreateInfo"); 24 | 25 | std::any c = CheekyLayer::reflection::parse_get("pDepthStencilState->depthCompareOp", &info, "VkGraphicsPipelineCreateInfo"); 26 | assert(std::any_cast(c) == VK_COMPARE_OP_NEVER); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /tools/.stuff/bin/vhimageinstall: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -f vhimage.txt ]; then 4 | echo "No vhimage.txt file!" 5 | exit 2 6 | fi 7 | 8 | if [ $# -lt 1 ]; then 9 | echo "Syntax: vhimageinstall [mip count]" 10 | exit 2 11 | fi 12 | 13 | file=$1 14 | mipCount=$2 15 | if [ ! -f "$file" ]; then 16 | echo "File $file not found!" 17 | exit 2 18 | fi 19 | 20 | if [ -z "${mipCount}" ]; then 21 | mipCount=1000 22 | fi 23 | 24 | 25 | if [ $mipCount -lt 0 ]; then 26 | ((mipCount=-$mipCount)) 27 | reverseMips=1 28 | i=$(wc -l vhimage.txt | cut -f1 -d" ") 29 | else 30 | reverseMips=0 31 | i=1 32 | fi 33 | 34 | while read line; do 35 | hash=$(echo $line | cut -f1 -d" ") 36 | format=$(echo $line | cut -f2 -d" ") 37 | width=$(echo $line | cut -f3 -d" ") 38 | height=$(echo $line | cut -f4 -d" ") 39 | 40 | if [ $i -gt $mipCount ]; then 41 | echo "Removing image $hash ($format at ${width}x${height}) from overrides ..." 42 | rm $VH_LAYER_OVERRIDE/images/$hash.image 2>/dev/null 43 | else 44 | echo "Compressing image $hash ($format at ${width}x${height}) from $file ..." 45 | $VH_BIN/image_tools/pack $format $file $VH_LAYER_OVERRIDE/images/$hash.image $width $height 46 | fi 47 | 48 | if [ $reverseMips == 1 ]; then 49 | ((--i)) 50 | else 51 | ((++i)) 52 | fi 53 | done /dev/null 2>/dev/null 27 | fi 28 | else 29 | echo "No input data found for draw event $event, skipping..." 30 | fi 31 | if [ -f "$workdir/$event/shader.frag.spv" ]; then 32 | spirv-cross -V --version 450 "$workdir/$event/shader.frag.spv" > "$workdir/$event/shader.frag" 33 | else 34 | echo "No shader found for draw event $event, skipping..." 35 | fi 36 | done 37 | -------------------------------------------------------------------------------- /vulkan_layer/include/config.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace CheekyLayer 8 | { 9 | class config 10 | { 11 | public: 12 | const static std::function to_bool; 13 | 14 | config() : config(std::unordered_map{}) {} 15 | config(const std::unordered_map& v); 16 | 17 | bool has(const std::string& key); 18 | 19 | template 20 | T map(const std::string& key, std::function mapper) 21 | { 22 | return mapper((*this)[key]); 23 | } 24 | const std::string& operator[](const std::string& key) const; 25 | 26 | std::filesystem::path log_file; 27 | std::string log_level; 28 | 29 | std::string application; 30 | bool hook_draw_calls; 31 | std::filesystem::path rule_file; 32 | 33 | bool dump; 34 | bool dump_png; 35 | bool dump_png_flipped; 36 | std::filesystem::path dump_directory; 37 | 38 | bool override; 39 | bool override_png_flipped; 40 | std::filesystem::path override_directory; 41 | private: 42 | std::unordered_map values; 43 | 44 | friend std::istream& operator>>(std::istream&, config&); 45 | }; 46 | std::istream& operator>>(std::istream& is, config& config); 47 | 48 | extern const config DEFAULT_CONFIG; 49 | } 50 | -------------------------------------------------------------------------------- /tools/.stuff/bin/vhimagetest: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -f vhimage.txt ]; then 4 | echo "No vhimage.txt file!" 5 | exit 2 6 | fi 7 | 8 | if [ $# -eq 1 ]; then 9 | mode=mod 10 | 11 | file=$1 12 | if [ ! -f "$file" ]; then 13 | echo "File $file not found!" 14 | exit 2 15 | fi 16 | base=${file%.*} 17 | else 18 | mode=base 19 | fi 20 | 21 | tmp=$(mktemp) 22 | 23 | test_dir=test 24 | mkdir -p $test_dir 25 | 26 | while read line; do 27 | hash=$(echo $line | cut -f1 -d" ") 28 | format=$(echo $line | cut -f2 -d" ") 29 | width=$(echo $line | cut -f3 -d" ") 30 | height=$(echo $line | cut -f4 -d" ") 31 | 32 | if [ $mode == "mod" ]; then 33 | out=$test_dir/$base.$width.$height.png 34 | 35 | echo "Compressing and decompressing image ($format at ${width}x${height}) from $file to $out ..." 36 | #java -jar $VH_LIB/bc.jar c $format $file $tmp $width $height 37 | $VH_BIN/image_tools/pack $format $file $tmp $width $height 38 | 39 | #java -jar $VH_LIB/bc.jar d $format $tmp $out $width $height 40 | $VH_BIN/image_tools/unpack $format $tmp $out $width $height 41 | else 42 | out_base=$test_dir/base.$width.$height.png 43 | 44 | echo "Decompressing image $hash ($format at ${width}x${height}) to $out_base ..." 45 | #java -jar $VH_LIB/bc.jar d $format $VH_LAYER_DUMP/images/$hash.image $out_base $width $height 46 | $VH_BIN/image_tools/unpack $format $VH_LAYER_DUMP/images/$hash.image $out_base $width $height 47 | fi 48 | done 2 | 3 | namespace CheekyLayer::rules 4 | { 5 | class numbered_streambuf : public std::streambuf 6 | { 7 | private: 8 | std::streambuf* mySource; 9 | std::istream* myOwner; 10 | 11 | bool myIsAtStartOfLine = true; 12 | int myLineNumber = 0; 13 | int myColumnNumber = 0; 14 | 15 | char myBuffer; 16 | public: 17 | numbered_streambuf(std::streambuf* source) : mySource(source), myOwner(nullptr) {} 18 | numbered_streambuf(std::istream& owner) : mySource(owner.rdbuf()), myOwner(&owner) 19 | { 20 | myOwner->rdbuf(this); 21 | } 22 | ~numbered_streambuf() 23 | { 24 | if(myOwner) 25 | { 26 | myOwner->rdbuf(mySource); 27 | } 28 | } 29 | 30 | int line() const 31 | { 32 | return myLineNumber; 33 | } 34 | 35 | int col() const 36 | { 37 | return myColumnNumber; 38 | } 39 | protected: 40 | int underflow() override 41 | { 42 | int ch = mySource->sbumpc(); 43 | if(ch != EOF) 44 | { 45 | myBuffer = ch; 46 | setg(&myBuffer, &myBuffer, &myBuffer+1); 47 | if(myIsAtStartOfLine) 48 | { 49 | myLineNumber++; 50 | myColumnNumber = 0; 51 | if(ch == '#') 52 | { 53 | while((ch = mySource->sbumpc()) != '\n') { if(ch == EOF) return ch; } 54 | myIsAtStartOfLine = true; 55 | return underflow(); 56 | } 57 | } 58 | else 59 | { 60 | myColumnNumber++; 61 | } 62 | myIsAtStartOfLine = myBuffer == '\n'; 63 | } 64 | return ch; 65 | } 66 | }; 67 | } -------------------------------------------------------------------------------- /image_tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | project(image_tools) 4 | 5 | set(CMAKE_CXX_STANDARD 20) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | 8 | find_package(glm REQUIRED) 9 | 10 | file(GLOB_RECURSE sources_lib src/lib/*.cpp) 11 | file(GLOB_RECURSE sources_pack src/pack.cpp) 12 | file(GLOB_RECURSE sources_unpack src/unpack.cpp) 13 | 14 | option(IMAGE_TOOLS_CLI "Build 'pack' and 'unpack' executables" ON) 15 | option(IMAGE_TOOLS_PIC "Create position independent code" OFF) 16 | option(IMAGE_TOOLS_WITH_VULKAN "Integrate with VkFormat" OFF) 17 | 18 | add_library(image_tools ${sources_lib} external/bc7enc16/bc7decomp.c external/bc7enc16/bc7enc16.c) 19 | target_include_directories(image_tools PUBLIC include/) 20 | target_include_directories(image_tools PRIVATE ${GLM_INCLUDE_DIRS}) 21 | target_include_directories(image_tools PRIVATE external/bc7enc16) 22 | if(IMAGE_TOOLS_PIC) 23 | set_property(TARGET image_tools PROPERTY POSITION_INDEPENDENT_CODE ON) 24 | endif() 25 | if(IMAGE_TOOLS_WITH_VULKAN) 26 | find_package(Vulkan REQUIRED) 27 | 28 | target_include_directories(image_tools PUBLIC ${Vulkan_INCLUDE_DIR}) 29 | target_compile_definitions(image_tools PUBLIC WITH_VULKAN) 30 | endif() 31 | 32 | if(IMAGE_TOOLS_CLI) 33 | add_executable(pack ${sources_pack}) 34 | target_include_directories(pack PRIVATE external/stb) 35 | target_link_libraries(pack PRIVATE image_tools) 36 | 37 | add_executable(unpack ${sources_unpack}) 38 | target_include_directories(unpack PRIVATE external/stb) 39 | target_link_libraries(unpack PRIVATE image_tools) 40 | endif() 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cheeky-imp 2 | 3 | ![cheeky-imp logo](logo.png) 4 | *Logo made by [choco](https://twitter.com/chocographix)* 5 | 6 | A set of tools for hooking into Vulkan games and replacing shaders, textures, and meshes. 7 | 8 | *This README.md is very work-in-progress, so please excuse the shortness and directness.* 9 | 10 | The tools are mainly made for Linux and games that use DXVK (or Vulkan natively). 11 | Some (``mesh_buffer_tools`` and ``image_tools``) should also work on Windows, 12 | but I am not so sure about the ``vulkan_layer``. 13 | 14 | I will try to create a ``README.md`` for each individual project (in the subdirectories), 15 | but that might take quite a while. 16 | 17 | ***Always clone with ``--recurse-submodules`` as this repository uses multiple submodules which are vital for almost all subprojects.*** 18 | 19 | ## Building 20 | 21 | Most subprojects use *CMake*. 22 | Just create a ``build/`` subdirectory, open *bash* in it and do ``cmake ..`` and ``make``. 23 | 24 | ## Tools 25 | 26 | | Tool/Directory | Description | Language | Platform | 27 | | -------------- | ----------- | -------- | -------- | 28 | | [bone_analyzer](bone_analyzer/) | Reconstructs bones for Blender from vertex groups. | C++ | *any* 29 | | [image_tools](image_tools/) | Compresses and decompresses BCx images. | C++ | *any* 30 | | [mesh_buffer_tools](mesh_buffer_tools/) | Extracts and patches meshes for Vulkan games. | C++ | *any* 31 | | [vulkan_layer](vulkan_layer/) | Configurable and programable Vulkan layer for hooking into games, and extracting and modifying shaders, textures and meshes. | C++ | Linux 32 | -------------------------------------------------------------------------------- /image_tools/src/pack.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define STB_IMAGE_IMPLEMENTATION 9 | #include 10 | 11 | #include "block_compression.hpp" 12 | #include "image.hpp" 13 | 14 | #include 15 | 16 | using namespace image_tools; 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | if(argc != 6) 21 | { 22 | std::cerr << "Usage: " << argv[0] << " [format] [input-file] [output-file] [width] [height]" << std::endl; 23 | return 2; 24 | } 25 | 26 | std::string format = argv[1]; 27 | std::string inputPath = argv[2]; 28 | std::string outputPath = argv[3]; 29 | int width = std::atoi(argv[4]); 30 | int height = std::atoi(argv[5]); 31 | 32 | int w, h, comp; 33 | uint8_t* buf = stbi_load(inputPath.c_str(), &w, &h, &comp, STBI_rgb_alpha); 34 | 35 | image image(w, h, buf); 36 | std::vector out; 37 | 38 | if(format=="BC1") 39 | { 40 | compressBC1(image, out, width, height); 41 | } 42 | else if(format=="BC3") 43 | { 44 | compressBC3(image, out, width, height); 45 | } 46 | else if(format=="BC4") 47 | { 48 | compressBC4(image, out, width, height); 49 | } 50 | else if(format=="BC5") 51 | { 52 | compressBC5(image, out, width, height); 53 | } 54 | else if(format=="BC7" || format=="BC7-noalpha") 55 | { 56 | compressBC7(image, out, width, height); 57 | } 58 | 59 | { 60 | std::ofstream outStream(outputPath, std::ios::binary); 61 | outStream.write((char*)out.data(), out.size()); 62 | outStream.flush(); 63 | } 64 | 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /vulkan_layer/src/dispatch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "dispatch.hpp" 11 | #include "layer.hpp" 12 | #include "objects.hpp" 13 | 14 | std::map instance_dispatch; 15 | std::map device_dispatch; 16 | 17 | VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL CheekyLayer_GetDeviceProcAddr(VkDevice device, const char *pName) 18 | { 19 | DeviceHook(DestroyDevice); 20 | 21 | if(!layer_disabled) 22 | { 23 | DeviceHooks(); 24 | } 25 | 26 | { 27 | scoped_lock l(global_lock); 28 | return CheekyLayer::get_device(device).dispatch.GetDeviceProcAddr(device, pName); 29 | } 30 | } 31 | 32 | VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL CheekyLayer_GetInstanceProcAddr(VkInstance instance, const char *pName) 33 | { 34 | InstanceHook(CreateInstance); 35 | InstanceHook(CreateDevice); 36 | InstanceHook(DestroyInstance); 37 | 38 | if(!layer_disabled) 39 | { 40 | InstanceHooks(); 41 | } 42 | 43 | if(instance) { 44 | scoped_lock l(global_lock); 45 | return CheekyLayer::get_instance(instance).dispatch.GetInstanceProcAddr(instance, pName); 46 | } else { 47 | return nullptr; 48 | } 49 | } 50 | 51 | void InitInstanceDispatchTable(VkInstance instance, PFN_vkGetInstanceProcAddr gpa, VkuInstanceDispatchTable& dispatchTable) 52 | { 53 | InitInstanceDispatch(); 54 | } 55 | 56 | void InitDeviceDispatchTable(VkDevice device, PFN_vkGetDeviceProcAddr gdpa, VkuDeviceDispatchTable_& dispatchTable) 57 | { 58 | InitDeviceDispatch(); 59 | } 60 | -------------------------------------------------------------------------------- /vulkan_layer/src/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | std::string sha256_string(const std::span data) 8 | { 9 | unsigned char hash[SHA256_DIGEST_LENGTH]; 10 | SHA256(data.data(), data.size(), hash); 11 | 12 | char outputBuffer[65]; 13 | int i = 0; 14 | for (i = 0; i < SHA256_DIGEST_LENGTH; i++) 15 | { 16 | sprintf(outputBuffer + (i * 2), "%02x", hash[i]); 17 | } 18 | outputBuffer[64] = 0; 19 | 20 | return std::string(outputBuffer); 21 | } 22 | std::string sha256_string(const unsigned char* data, std::size_t len) { 23 | return sha256_string(std::span(data, len)); 24 | } 25 | 26 | void replace(std::string& string, const std::string& search, const std::string& replacement) 27 | { 28 | if(search.empty()) 29 | return; 30 | std::string::size_type pos = 0; 31 | while((pos = string.find(search, pos)) != std::string::npos) 32 | { 33 | string.replace(pos, search.length(), replacement); 34 | pos += replacement.length(); 35 | } 36 | } 37 | 38 | uint32_t findMemoryType(VkPhysicalDeviceMemoryProperties memProperties, uint32_t typeFilter, VkMemoryPropertyFlags properties) 39 | { 40 | for(uint32_t i = 0; i < memProperties.memoryTypeCount; i++) 41 | { 42 | if((typeFilter & (1 << i)) && 43 | (memProperties.memoryTypes[i].propertyFlags & properties) == properties) 44 | { 45 | return i; 46 | } 47 | } 48 | 49 | throw std::runtime_error("failed to find suitable memory type!"); 50 | } 51 | 52 | void* find_pnext(const void* pNext, VkStructureType type) { 53 | while(pNext) { 54 | const VkBaseInStructure* base = static_cast(pNext); 55 | if(base->sType == type) { 56 | return const_cast(pNext); 57 | } 58 | pNext = base->pNext; 59 | } 60 | return nullptr; 61 | } 62 | -------------------------------------------------------------------------------- /tools/.stuff/bin/vhmeshinstall: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -f vhmesh.txt ]; then 4 | echo "No vhmesh.txt file!" 5 | exit 2 6 | fi 7 | 8 | if [ $# -ne 1 ]; then 9 | echo "Syntax: vhmeshinstall " 10 | exit 2 11 | fi 12 | 13 | file=$1 14 | if [ ! -f "$file" ]; then 15 | echo "File $file not found!" 16 | exit 2 17 | fi 18 | 19 | echo "Exporting parts from Blender file $file ..." 20 | blender -b $file --python $VH_LIB/blender_export_mesh.py >/dev/null 2>/dev/null 21 | 22 | name=${file%.*} 23 | 24 | while read line; do 25 | index=$(echo $line | cut -f6 -d" ") 26 | rm $VH_LAYER_OVERRIDE/buffers/$index.buf 27 | 28 | additional=( $(echo $line | cut -f7- -d" ") ) 29 | for i in ${!additional[*]} 30 | do 31 | if ! ((i % 2)); then 32 | rm $VH_LAYER_OVERRIDE/buffers/${additional[$i]}.buf 33 | fi 34 | done 35 | done 3 | #include "image.hpp" 4 | 5 | #ifdef WITH_VULKAN 6 | #include 7 | #include 8 | #endif 9 | 10 | namespace image_tools 11 | { 12 | void compressBC1(const image& in, std::vector& out, int w, int h); 13 | void compressBC2(const image& in, std::vector& out, int w, int h); 14 | void compressBC3(const image& in, std::vector& out, int w, int h); 15 | void compressBC4(const image& in, std::vector& out, int w, int h); 16 | void compressBC5(const image& in, std::vector& out, int w, int h); 17 | void compressBC7(const image& in, std::vector& out, int w, int h); 18 | 19 | void decompressBC1(const uint8_t* in, image& out, int w, int h); 20 | void decompressBC2(const uint8_t* in, image& out, int w, int h); 21 | void decompressBC3(const uint8_t* in, image& out, int w, int h); 22 | void decompressBC4(const uint8_t* in, image& out, int w, int h); 23 | void decompressBC5(const uint8_t* in, image& out, int w, int h); 24 | void decompressBC6(const uint8_t* in, image& out, int w, int h); 25 | void decompressBC7(const uint8_t* in, image& out, int w, int h, bool alpha); 26 | 27 | #ifdef WITH_VULKAN 28 | bool is_compression_supported(VkFormat format); 29 | bool is_compression_supported(vk::Format format); 30 | 31 | void compress(VkFormat format, const image& in, std::vector& out, int w, int h); 32 | void compress(vk::Format format, const image& in, std::vector& out, int w, int h); 33 | 34 | bool is_decompression_supported(VkFormat format); 35 | bool is_decompression_supported(vk::Format format); 36 | 37 | void decompress(VkFormat format, const uint8_t* in, image& out, int w, int h); 38 | void decompress(vk::Format format, const uint8_t* in, image& out, int w, int h); 39 | #endif 40 | } 41 | -------------------------------------------------------------------------------- /tools/.stuff/lib/blender_import_mesh.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from os import path 3 | import os 4 | import json 5 | 6 | def import_obj(part): 7 | bpy.ops.import_scene.obj(filepath=f"base_{part}.obj") 8 | obj = bpy.context.selected_objects[0] 9 | 10 | for subpart in obj.material_slots.keys(): 11 | if(path.exists(f"texture/{subpart}/base.png")): 12 | mat = obj.material_slots[subpart].material 13 | bsdf = mat.node_tree.nodes["Principled BSDF"] 14 | color_input = bsdf.inputs['Base Color'] 15 | 16 | if(os.getenv('BLENDER_SHADER_TYPE') == 'toon'): 17 | mat.node_tree.nodes.remove(bsdf) 18 | bsdf = mat.node_tree.nodes.new("ShaderNodeBsdfToon") 19 | mat.node_tree.links.new(mat.node_tree.nodes["Material Output"].inputs["Surface"], bsdf.outputs["BSDF"]) 20 | color_input = bsdf.inputs['Color'] 21 | 22 | texImage = mat.node_tree.nodes.new('ShaderNodeTexImage') 23 | texImage.image = bpy.data.images.load(f"texture/{subpart}/base.png") 24 | mat.node_tree.links.new(color_input, texImage.outputs['Color']) 25 | 26 | if(path.exists(f"base_{part}.obj.json")): 27 | with open(f"base_{part}.obj.json") as f: 28 | data = json.load(f) 29 | for group, vertices in data.items(): 30 | g = obj.vertex_groups.new(name = part+"_"+group) 31 | for index, weight in vertices.items(): 32 | g.add([int(index)], weight, 'REPLACE') 33 | 34 | obj.name = part 35 | obj.data.use_auto_smooth = True 36 | obj.select_set(False) 37 | 38 | bpy.context.scene.render.engine = 'CYCLES' 39 | bpy.ops.object.delete() 40 | 41 | f = open("vhmesh.txt", "r") 42 | for x in f: 43 | part=x.split()[0] 44 | import_obj(part) 45 | f.close() 46 | 47 | bpy.data.texts.load(os.getenv("VH_LIB")+"/blender_pose.py") 48 | bpy.data.texts.load(os.getenv("VH_LIB")+"/blender_bone_import.py") 49 | 50 | bpy.ops.file.pack_all() 51 | 52 | bpy.ops.wm.save_as_mainfile(filepath=os.getcwd()+"/base.blend") 53 | bpy.ops.wm.quit_blender() 54 | -------------------------------------------------------------------------------- /image_tools/src/unpack.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "block_compression.hpp" 7 | #include "image.hpp" 8 | 9 | #define STB_IMAGE_WRITE_IMPLEMENTATION 10 | #include 11 | 12 | using namespace image_tools; 13 | 14 | int main(int argc, char* argv[]) 15 | { 16 | if(argc != 6) 17 | { 18 | std::cerr << "Usage: " << argv[0] << " [format] [input-file] [output-file] [width] [height]" << std::endl; 19 | return 2; 20 | } 21 | 22 | std::string format = argv[1]; 23 | std::string inputPath = argv[2]; 24 | std::string outputPath = argv[3]; 25 | int width = std::atoi(argv[4]); 26 | int height = std::atoi(argv[5]); 27 | 28 | std::vector data; 29 | 30 | { 31 | std::ifstream in(inputPath, std::ios::binary | std::ios::ate); 32 | if(!in) 33 | { 34 | std::cerr << "Cannot open file: " << inputPath << std::endl; 35 | return 2; 36 | } 37 | 38 | size_t size = in.tellg(); 39 | data.resize(size); 40 | in.seekg(0); 41 | 42 | in.read((char*)data.data(), size); 43 | } 44 | 45 | image image(width, height); 46 | 47 | if(format=="BC1") 48 | { 49 | decompressBC1(data.data(), image, width, height); 50 | } 51 | else if(format=="BC2") 52 | { 53 | decompressBC2(data.data(), image, width, height); 54 | } 55 | else if(format=="BC3") 56 | { 57 | decompressBC3(data.data(), image, width, height); 58 | } 59 | else if(format=="BC4") 60 | { 61 | decompressBC4(data.data(), image, width, height); 62 | } 63 | else if(format=="BC5") 64 | { 65 | decompressBC5(data.data(), image, width, height); 66 | } 67 | else if(format=="BC7") 68 | { 69 | decompressBC7(data.data(), image, width, height, true); 70 | } 71 | else if(format=="BC7-noalpha") 72 | { 73 | decompressBC7(data.data(), image, width, height, false); 74 | } 75 | 76 | stbi_write_png(outputPath.c_str(), width, height, 4, image, width*4); 77 | 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /texture_renderer/scripts/finish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | workdir="$1" 4 | objdir="$2" 5 | out="${3-"./final"}" 6 | mkdir -p "$out" 7 | 8 | if [ -z "$workdir" ] || [ -z "$objdir" ] || [ -z "$out" ] 9 | then 10 | echo "Usage: $0 WORK-DIR OBJ-DIR FINAL-DIR" 11 | exit 1 12 | fi 13 | 14 | for d in "$workdir"/*/; do 15 | event="$(basename "${d%/}")" 16 | echo $event 17 | if [ ! -d "$workdir/$event" ]; then 18 | echo "No data found for draw event $event, skipping..." 19 | continue 20 | fi 21 | if [ ! -f "$workdir/$event/texture.png" ]; then 22 | echo "No texture found for draw event $event, skipping..." 23 | continue 24 | fi 25 | if [ ! -f "$workdir/$event/model-uv.obj" ]; then 26 | echo "No UV model found for draw event $event, skipping..." 27 | continue 28 | fi 29 | 30 | if [ "$(identify -format '%[min] %[max]' "$workdir/$event/texture.png")" = "0 0" ]; then 31 | echo "Texture for draw event $event is empty, skipping..." 32 | continue 33 | fi 34 | 35 | if [ -f "$workdir/$event/texture_solid.png" ]; then 36 | cp "$workdir/$event/texture_solid.png" "$out/$event.png" 37 | else 38 | cp "$workdir/$event/texture.png" "$out/$event.png" 39 | fi 40 | cat > "$out/$event.mtl" < "$out/$filename" <> "$out/$filename" 61 | grep -E '^(vt|f )' --color=never < "$workdir/$event/model-uv.obj" >> "$out/$filename" 62 | done 63 | done 64 | -------------------------------------------------------------------------------- /texture_renderer/README.md: -------------------------------------------------------------------------------- 1 | # texture_renderer 2 | 3 | ## Recommended Directory Structure 4 | ``` 5 | . 6 | ├── csv (exported from RenderDoc) 7 | │ └── 1234-0.csv (output of the vertex shader, from RenderDoc) 8 | ├── final (generated by scripts/finish.sh) 9 | │ ├── 1234-0.obj (OBJ file with UVs and reference to material file) 10 | │ ├── 1234.mtl (material file) 11 | │ └── 1234.png (texture) 12 | ├── obj (generated by scripts/csv_to_obj.sh) 13 | │ └── 1234-0.obj (OBJ file generated from vertex shader output) 14 | └── work (exported from RenderDoc + generated by scripts/prepare.sh + generated by the main tool) 15 | └── 1234 16 | ├── model.obj -> ../../obj/1234-0.obj 17 | ├── model-uv.obj (OBJ file with UVs, generated by Blender) 18 | ├── pipeline.json (Pipeline description, from RenderDoc) 19 | ├── shader.frag (Decompiled fragment shader) 20 | ├── shader.frag.spv (Fragment shader, from RenderDoc) 21 | ├── texture.png (texture) 22 | └── vertices.csv -> ../../csv/1234-0.csv 23 | ``` 24 | 25 | ## Workflow 26 | 1. Make a RenderDoc capture of the environment you want to export. 27 | 2. Open the RenderDoc capture and select the corresponding render pass. 28 | 3. In RenderDoc, use `scripts/renderdoc/export_draws.py` to export the draw events to `csv/` 29 | 4. In RenderDoc, use `scripts/renderdoc/export_pipelines.py` to export the draw events to `work/` 30 | 5. Use `scripts/csv_to_obj.sh` to generate the OBJ files and undo the projection (from `csv/` to `obj/`) 31 | 6. use `scripts/prepare.sh` to decompile the shaders and to generate the UVs (affecting `work/`) 32 | 7. Use `scripts/run.sh` to generate the textures (affecting `work/`) 33 | 8. Export everything as a bunch of OBJs and MTLs (from `work/` to `final/`) 34 | 35 | ### Example Script invocations 36 | 5. `scripts/csv_to_obj.sh ./csv ./obj` 37 | 6. `scripts/prepare.sh ./work ./csv ./obj` 38 | 7. `scripts/run.sh ./work` 39 | 8. `scripts/finish.sh ./work ./obj ./final` 40 | -------------------------------------------------------------------------------- /tools/.stuff/lib/blender_pose.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import mathutils 3 | import json 4 | 5 | def pose_object(name, part, pose, obj): 6 | if not part in pose: 7 | return 8 | 9 | sk = obj.shape_key_add(name=name, from_mix=False) 10 | sk.interpolation = 'KEY_LINEAR' 11 | verts = obj.data.vertices 12 | 13 | for i in range(len(verts)): 14 | vertex = verts[i] 15 | pos = mathutils.Vector() 16 | 17 | sum=0.0 18 | for group in vertex.groups: 19 | sum+=group.weight 20 | for group in vertex.groups: 21 | group.weight /= sum 22 | 23 | for group in vertex.groups: 24 | g = "0" 25 | for group2 in obj.vertex_groups: 26 | if group2.index == group.group: 27 | g = group2.name[len(part)+1:] 28 | break 29 | mat = mathutils.Matrix([pose[part][g][i::4] for i in range(4)]) 30 | pos += (vertex.co @ mat) * group.weight 31 | sk.data[i].co = pos 32 | 33 | 34 | try: 35 | collection = bpy.data.collections["Pose"] 36 | for o in collection.objects: 37 | bpy.data.objects.remove(o) 38 | except: 39 | collection = bpy.data.collections.new("Pose") 40 | bpy.context.scene.collection.children.link(collection) 41 | 42 | with open(bpy.path.abspath("//vhmesh.txt")) as f: 43 | for x in f: 44 | part=x.split()[0] 45 | 46 | oldObj = bpy.data.objects[part] 47 | obj = oldObj.copy() 48 | obj.data = oldObj.data.copy() 49 | collection.objects.link(obj) 50 | 51 | sk_basis = obj.shape_key_add(name='Basis') 52 | sk_basis.interpolation = 'KEY_LINEAR' 53 | obj.data.shape_keys.use_relative = True 54 | 55 | with open(bpy.path.abspath("//vhpose.txt")) as ps: 56 | for y in ps: 57 | poseName=y.split()[0] 58 | with open(bpy.path.abspath(f"//poses/{poseName}.json")) as f: 59 | pose = json.load(f) 60 | pose_object(poseName, part, pose, obj) 61 | -------------------------------------------------------------------------------- /vulkan_layer/test/struct_tree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "reflection/vkreflection.hpp" 9 | 10 | using CheekyLayer::reflection::struct_reflection_map; 11 | using CheekyLayer::reflection::VkReflectInfo; 12 | 13 | void dump_struct(std::ostream& out, std::string name, int level = 0, uint64_t last = 0) 14 | { 15 | if(!struct_reflection_map.contains(name)) 16 | { 17 | for(int j=0; j vec; 32 | for(auto it = a.members.begin(); it != a.members.end(); it++) 33 | { 34 | vec.push_back(it->second); 35 | } 36 | 37 | std::sort(vec.begin(), vec.end(), [](VkReflectInfo a, VkReflectInfo b) { 38 | return a.offset < b.offset; 39 | }); 40 | 41 | for(int i=0; i 7 | 8 | int main() 9 | { 10 | std::ofstream out("/dev/stdout"); 11 | ::logger = new CheekyLayer::logger(out); 12 | 13 | std::string socketRule = R"EOF( 14 | init{} -> seq( 15 | server_socket(socket, TCP, localhost, 1337, Lines) 16 | ) 17 | custom{custom(connect)} -> seq( 18 | write(socket, string("Hello World")), 19 | write(socket, string("Ready to receive your matrices")) 20 | ) 21 | receive{} -> seq( 22 | logx(convert(raw, string, received())), 23 | local=( 24 | raw, 25 | matrix, 26 | reduce( 27 | map( 28 | split( 29 | convert(raw, string, received()), 30 | " " 31 | ), 32 | raw, 33 | pack( 34 | Float, 35 | convert(string, number, current_element()) 36 | ) 37 | ), 38 | raw, 39 | convert(string, raw, string("")), 40 | concat(current_reduction(), current_element()) 41 | ) 42 | ), 43 | write(socket, local(matrix)) 44 | ))EOF"; 45 | 46 | { 47 | std::istringstream rulesIn(socketRule); 48 | CheekyLayer::rules::numbered_streambuf numberer{rulesIn}; 49 | while(rulesIn.good()) 50 | { 51 | try 52 | { 53 | std::unique_ptr rule = std::make_unique(); 54 | rulesIn >> *rule; 55 | 56 | ::rules.push_back(std::move(rule)); 57 | } 58 | catch(const std::exception& ex) 59 | { 60 | *logger << CheekyLayer::logger::begin << "Error at " << numberer.line() << ":" << numberer.col() << ":\n\t" << ex.what() << CheekyLayer::logger::end; 61 | break; 62 | } 63 | } 64 | } 65 | { 66 | CheekyLayer::active_logger log = *logger << CheekyLayer::logger::begin; 67 | CheekyLayer::rules::local_context ctx = { .logger = log }; 68 | CheekyLayer::rules::execute_rules(rules, CheekyLayer::rules::selector_type::Init, VK_NULL_HANDLE, ctx); 69 | log << CheekyLayer::logger::end; 70 | } 71 | { 72 | *logger << CheekyLayer::logger::begin << "Loaded " << rules.size() << " rules:" << CheekyLayer::logger::end; 73 | for(auto& r : rules) 74 | { 75 | CheekyLayer::active_logger log = *logger << CheekyLayer::logger::begin; 76 | log << '\t'; 77 | r->print(log.raw()); 78 | log << CheekyLayer::logger::end; 79 | } 80 | } 81 | for(;;) 82 | { 83 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); 84 | } 85 | } -------------------------------------------------------------------------------- /vulkan_layer/src/rules/data/functions.cpp: -------------------------------------------------------------------------------- 1 | #include "rules/data.hpp" 2 | #include "rules/execution_env.hpp" 3 | #include "rules/rules.hpp" 4 | 5 | namespace CheekyLayer::rules::datas 6 | { 7 | data_register call_function_data::reg("call"); 8 | 9 | void call_function_data::read(std::istream& in) 10 | { 11 | std::getline(in, m_function, ','); 12 | skip_ws(in); 13 | 14 | while(in.peek() != ')') 15 | { 16 | m_args.push_back(read_data(in, m_type)); 17 | 18 | skip_ws(in); 19 | char seperator = in.peek(); 20 | if(seperator != ',') 21 | continue; 22 | in.get(); 23 | skip_ws(in); 24 | } 25 | check_stream(in, ')'); 26 | } 27 | 28 | std::ostream& call_function_data::print(std::ostream& out) 29 | { 30 | out << "call(" << m_function; 31 | for(auto& arg : m_args) 32 | { 33 | out << ", "; 34 | arg->print(out); 35 | } 36 | return out << ")"; 37 | } 38 | 39 | bool call_function_data::supports(selector_type stype, data_type dtype) 40 | { 41 | return true; 42 | } 43 | 44 | data_value call_function_data::get(selector_type stype, data_type dtype, VkHandle handle, global_context& global, local_context& local, rule& rule) 45 | { 46 | if(!global.user_functions.contains(m_function)) 47 | throw RULE_ERROR("function not found: " + m_function); 48 | auto& func = global.user_functions.at(m_function); 49 | if(func.arguments.size() - func.default_arguments.size() > m_args.size()) 50 | throw RULE_ERROR("not enough arguments to call function " + m_function); 51 | 52 | struct restore { 53 | decltype(local)& ctx; 54 | decltype(ctx.local_variables) vars; 55 | 56 | restore(decltype(ctx)& ctx) : ctx(ctx), vars(ctx.local_variables) {} 57 | ~restore() {ctx.local_variables = vars;} 58 | } restore = {local}; 59 | 60 | int args = std::min(func.arguments.size(), m_args.size()); 61 | for(int i=0; iget(stype, func.arguments.at(i), handle, global, local, rule); 65 | local.local_variables[argName] = value; 66 | } 67 | for(int i=args; iget(stype, func.arguments.at(i), handle, global, local, rule); 72 | local.local_variables[argName] = value; 73 | } 74 | return func.data->get(stype, dtype, handle, global, local, rule); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /vulkan_layer/src/config.cpp: -------------------------------------------------------------------------------- 1 | #include "config.hpp" 2 | 3 | #include 4 | 5 | namespace CheekyLayer 6 | { 7 | const std::function config::to_bool = [](std::string s) {return s == "true";}; 8 | 9 | config::config(const std::unordered_map& v) : values(v) 10 | { 11 | log_file = map("logFile", [](std::string s) {return std::filesystem::path(s);}); 12 | log_level = map("logLevel", [](std::string s) {return s;}); 13 | 14 | application = map("application", [](std::string s) {return s;}); 15 | hook_draw_calls = map("hookDraw", to_bool); 16 | rule_file = map("ruleFile", [](std::string s) {return std::filesystem::path(s);}); 17 | 18 | dump = map("dump", to_bool); 19 | dump_png = map("dumpPng", to_bool); 20 | dump_png_flipped = map("dumpPngFlipped", to_bool); 21 | dump_directory = map("dumpDirectory", [](std::string s) {return std::filesystem::path(s);}); 22 | 23 | override = map("override", to_bool); 24 | override_png_flipped = map("overridePngFlipped", to_bool); 25 | override_directory = map("overrideDirectory", [](std::string s) {return std::filesystem::path(s);}); 26 | } 27 | 28 | const std::string& config::operator[](const std::string& key) const 29 | { 30 | return values.contains(key) ? values.at(key) : DEFAULT_CONFIG.values.at(key); 31 | } 32 | 33 | bool config::has(const std::string& key) 34 | { 35 | return values.contains(key); 36 | } 37 | 38 | std::istream& operator>>(std::istream& is, config& config) 39 | { 40 | std::unordered_map values; 41 | 42 | std::string line; 43 | while(std::getline(is, line)) 44 | { 45 | std::istringstream is_line(line); 46 | std::string key; 47 | if(std::getline(is_line, key, '=')) 48 | { 49 | std::string value; 50 | if (key[0] == '#') 51 | continue; 52 | 53 | if(std::getline(is_line, value)) 54 | { 55 | values[key] = value; 56 | } 57 | } 58 | } 59 | config = CheekyLayer::config(values); 60 | 61 | return is; 62 | } 63 | 64 | const config DEFAULT_CONFIG(std::unordered_map({ 65 | {"dump", "false"}, 66 | {"dumpPng", "false"}, 67 | {"dumpPngFlipped", "false"}, 68 | {"dumpDirectory", "/tmp/vulkan_dump"}, 69 | {"override", "true"}, 70 | {"overridePngFlipped", "false"}, 71 | {"overrideDirectory", "./override"}, 72 | {"logFile", "cheeky_layer.txt"}, 73 | {"logLevel", "debug"}, 74 | {"ruleFile", "rules.txt"}, 75 | {"hookDraw", "false"}, 76 | {"application", ""}, 77 | {"pluginDirectory", "./plugins"} 78 | })); 79 | } 80 | -------------------------------------------------------------------------------- /vulkan_layer/src/rules/data/convert.cpp: -------------------------------------------------------------------------------- 1 | #include "rules/data.hpp" 2 | #include "rules/execution_env.hpp" 3 | #include "rules/rules.hpp" 4 | 5 | namespace CheekyLayer::rules::datas 6 | { 7 | data_register convert_data::reg("convert"); 8 | 9 | void convert_data::read(std::istream& in) 10 | { 11 | std::string st; 12 | std::getline(in, st, ','); 13 | skip_ws(in); 14 | srcType = data_type_from_string(st); 15 | 16 | std::string dt; 17 | std::getline(in, dt, ','); 18 | skip_ws(in); 19 | dstType = data_type_from_string(dt); 20 | 21 | m_src = read_data(in, m_type); 22 | check_stream(in, ')'); 23 | 24 | if(!m_src->supports(m_type, srcType)) 25 | throw RULE_ERROR("data does not support source data type "+to_string(srcType)); 26 | } 27 | 28 | data_value convert_data::get(selector_type stype, data_type type, VkHandle handle, global_context& global, local_context& local, rule& rule) 29 | { 30 | if(type != dstType) 31 | throw RULE_ERROR("cannot return data type "+to_string(type)); 32 | 33 | data_value value = m_src->get(stype, srcType, handle, global, local, rule); 34 | if(srcType == dstType) 35 | return value; 36 | 37 | switch(srcType) 38 | { 39 | case data_type::String: { 40 | std::string str = std::get(value); 41 | switch(dstType) 42 | { 43 | case data_type::Raw: 44 | return std::vector(str.begin(), str.end()); 45 | case data_type::Number: 46 | return std::stod(str); 47 | default: 48 | throw RULE_ERROR("no known conversion from "+to_string(srcType)+" to "+to_string(dstType)); 49 | } 50 | } 51 | case data_type::Raw: { 52 | std::vector raw = std::get>(value); 53 | switch(dstType) 54 | { 55 | case data_type::String: 56 | return std::string(raw.begin(), raw.end()); 57 | default: 58 | throw RULE_ERROR("no known conversion from "+to_string(srcType)+" to "+to_string(dstType)); 59 | } 60 | } 61 | case data_type::Number: { 62 | double d = std::get(value); 63 | switch(dstType) 64 | { 65 | case data_type::String: 66 | return std::to_string(d); 67 | default: 68 | throw RULE_ERROR("no known conversion from "+to_string(srcType)+" to "+to_string(dstType)); 69 | } 70 | } 71 | default: 72 | throw RULE_ERROR("no known conversion from "+to_string(srcType)+" to "+to_string(dstType)); 73 | } 74 | } 75 | 76 | bool convert_data::supports(selector_type, data_type type) 77 | { 78 | return type == dstType; 79 | } 80 | 81 | std::ostream& convert_data::print(std::ostream& out) 82 | { 83 | out << "convert(" << to_string(srcType) << ", " << to_string(dstType) << ", "; 84 | m_src->print(out); 85 | out << ")"; 86 | return out; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /vulkan_layer/src/rules/data/math.cpp: -------------------------------------------------------------------------------- 1 | #include "rules/data.hpp" 2 | #include "rules/execution_env.hpp" 3 | #include "rules/rules.hpp" 4 | 5 | #include 6 | #include 7 | 8 | namespace CheekyLayer::rules::datas 9 | { 10 | data_register math_data::reg("math"); 11 | 12 | void math_data::read(std::istream& in) 13 | { 14 | in >> std::quoted(m_expression, '`'); 15 | skip_ws(in); 16 | 17 | while(in.peek() == ',') 18 | { 19 | check_stream(in, ','); 20 | skip_ws(in); 21 | std::string name; 22 | in >> name; 23 | skip_ws(in); 24 | 25 | check_stream(in, '='); 26 | check_stream(in, '>'); 27 | 28 | skip_ws(in); 29 | auto data = read_data(in, m_type); 30 | if(!data->supports(m_type, Number)) 31 | { 32 | std::ostringstream of; 33 | of << "Variable \""; 34 | data->print(of); 35 | of << "\" does not support type Number."; 36 | throw RULE_ERROR(of.str()); 37 | } 38 | m_variables[name] = std::move(data); 39 | } 40 | check_stream(in, ')'); 41 | 42 | exprtk::expression expr; 43 | exprtk::symbol_table table; 44 | 45 | double arg; 46 | for(auto& [name, ptr] : m_variables) 47 | { 48 | table.add_constant(name, arg); 49 | } 50 | table.add_constants(); 51 | 52 | expr.register_symbol_table(table); 53 | 54 | exprtk::parser parser; 55 | if(!parser.compile(m_expression, expr)) 56 | throw RULE_ERROR("Cannot parse expression: "+parser.error()); 57 | } 58 | 59 | data_value math_data::get(selector_type stype, data_type type, VkHandle handle, global_context& global, local_context& local, rule& rule) 60 | { 61 | if(type != data_type::Number) 62 | throw RULE_ERROR("cannot return data type "+to_string(type)); 63 | 64 | exprtk::expression expr; 65 | exprtk::symbol_table table; 66 | 67 | for(auto& [name, ptr] : m_variables) 68 | { 69 | double value = std::get(ptr->get(stype, Number, handle, global, local, rule)); 70 | table.add_constant(name, value); 71 | } 72 | table.add_constants(); 73 | 74 | expr.register_symbol_table(table); 75 | 76 | exprtk::parser parser; 77 | if(!parser.compile(m_expression, expr)) 78 | throw RULE_ERROR("Cannot parse expression: "+parser.error()); 79 | 80 | return expr.value(); 81 | } 82 | 83 | bool math_data::supports(selector_type, data_type type) 84 | { 85 | return type == Number; 86 | } 87 | 88 | std::ostream& math_data::print(std::ostream& out) 89 | { 90 | out << "math(" << std::quoted(m_expression, '`'); 91 | for(auto & [name, ptr] : m_variables) 92 | { 93 | out << ", " << name << " => "; 94 | ptr->print(out); 95 | } 96 | out << ")"; 97 | return out; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /image_tools/src/lib/image.cpp: -------------------------------------------------------------------------------- 1 | #include "image.hpp" 2 | #include 3 | #include 4 | 5 | namespace image_tools 6 | { 7 | image::image(int w, int h) 8 | { 9 | width = w; 10 | height = h; 11 | 12 | data.resize(w*h); 13 | } 14 | 15 | image::image(int w, int h, std::vector&& d) 16 | { 17 | width = w; 18 | height = h; 19 | 20 | data.assign((image::color*)d.data(), ((image::color*)d.data())+w*h); 21 | } 22 | 23 | image::image(int w, int h, uint8_t* pointer) 24 | { 25 | width = w; 26 | height = h; 27 | 28 | data.assign((image::color*)pointer, ((image::color*)pointer)+w*h); 29 | } 30 | 31 | image::color& image::at(int x, int y) 32 | { 33 | return data.at(y*width + x); 34 | } 35 | 36 | constexpr glm::ivec4 color_to_ivec4(image::color c) 37 | { 38 | int r = (c>>(0*8)) & 0xff; 39 | int g = (c>>(1*8)) & 0xff; 40 | int b = (c>>(2*8)) & 0xff; 41 | int a = (c>>(3*8)) & 0xff; 42 | 43 | return glm::ivec4(r, g, b, a); 44 | } 45 | 46 | glm::vec4 image::scaled(int x, int y, int w, int h) const 47 | { 48 | if(w==width && h==height) 49 | return color_to_vec4(data[y*width + x]); 50 | 51 | float factorX = width / ((float)w); 52 | float factorY = height / ((float)h); 53 | 54 | assert(factorX > 1.0); 55 | assert(factorY > 1.0); 56 | 57 | int xx = x * factorX; 58 | int yy = y * factorY; 59 | 60 | int scanX = factorX; 61 | int scanY = factorY; 62 | 63 | glm::ivec4 sum(0.0); 64 | for(int xxx = xx; xxx < xx+scanX; xxx++) 65 | { 66 | for(int yyy = yy; yyy < yy+scanY; yyy++) 67 | { 68 | sum += color_to_ivec4(data[yyy*width + xxx]); 69 | } 70 | } 71 | return glm::vec4(sum) / (float)(scanX * scanY * 255.0f); 72 | } 73 | 74 | image::color color(glm::vec4 rgba) 75 | { 76 | int r = rgba.r * 255.0f; 77 | int g = rgba.g * 255.0f; 78 | int b = rgba.b * 255.0f; 79 | int a = rgba.a * 255.0f; 80 | 81 | return (a<<(3*8)) | (b<<(2*8)) | (g<<(1*8)) | (r<<(0*8)); 82 | } 83 | 84 | glm::vec4 color_to_vec4(image::color c) 85 | { 86 | int r = (c>>(0*8)) & 0xff; 87 | int g = (c>>(1*8)) & 0xff; 88 | int b = (c>>(2*8)) & 0xff; 89 | int a = (c>>(3*8)) & 0xff; 90 | 91 | return glm::vec4(r/255.0f, g/255.0f, b/255.0f, a/255.0f); 92 | } 93 | 94 | image::operator const uint8_t*() 95 | { 96 | return (const uint8_t*) data.data(); 97 | } 98 | 99 | std::vector::iterator image::begin() { return data.begin(); } 100 | std::vector::iterator image::end() { return data.end(); } 101 | 102 | std::vector::const_iterator image::cbegin() const { return data.cbegin(); } 103 | std::vector::const_iterator image::cend() const { return data.cend(); } 104 | } 105 | -------------------------------------------------------------------------------- /vulkan_layer/test/rules.txt: -------------------------------------------------------------------------------- 1 | image{} -> log("Lorem ipsum") 2 | image{} -> seq(log("Lorem ipsum"), log("123")) 3 | image{} -> seq() 4 | image{} -> seq(seq()) 5 | image{} -> seq(seq(), log("Lorem ipsum")) 6 | image{} -> disable() 7 | image{mark(Lorem ipsum)} -> seq() 8 | draw{with(image{})} -> seq() 9 | draw{not(with(image{}))} -> seq() 10 | pipeline{not(with(shader{mark(sky)}))} -> override(pDepthStencilState->depthTestEnable = VK_FALSE) 11 | image{} -> logx(string("Lorem ipsum")) 12 | image{} -> logx(concat(string("Lorem "), string("ipsum"))) 13 | image{} -> logx(concat(string("Lorem"), string(" "), string("ipsum"))) 14 | pipeline{} -> logx(concat(string("Depth:"), vkstruct(pDepthStencilState->depthTestEnable))) 15 | init{} -> socket(socket, TCP, localhost, 1337, Raw) 16 | init{} -> seq(socket(socket, TCP, localhost, 1337, LengthPrefixed), write(socket, string("Hello World"))) 17 | pipeline{} -> write(socket, concat(string("pDepthStencilState->depthTestEnable:"), vkstruct(pDepthStencilState->depthTestEnable), string("\n"))) 18 | image{} -> seq(load_image(local(handle), File, test.png)) 19 | image{} -> seq(load_image(local(handle), FileFromData, string("test.png"))) 20 | receive{} -> log("Test") 21 | receive{} -> write(socket, received()) 22 | receive{} -> write(socket, convert(raw, string, received())) 23 | receive{} -> write(socket, strclean(convert(raw, string, received()))) 24 | image{compare(string("123"), ==, string("123"))} -> seq() 25 | image{} -> seq(preload_image(local(handle), string("test.png"))) 26 | receive{} -> load_image(local(handle), FileFromData, strclean(convert(raw, string, received()))) 27 | device_create{} -> seq() 28 | device_destroy{} -> seq() 29 | draw{with(image{})} -> on(EndRenderPass, seq()) 30 | image{compare(number(123), ==, number(123))} -> seq() 31 | image{compare(number(123.4567), ==, number(123.4567))} -> seq() 32 | image{compare(number(123.456789), ==, number(123.56789))} -> seq() 33 | image{compare(math(`3`), ==, number(3))} -> seq() 34 | image{compare(math(`3x*y`, x => number(3), y => number(3)), ==, number(3))} -> seq() 35 | image{compare(math(`3sin(x)*y`, x => number(3), y => number(3)), ==, number(3))} -> seq() 36 | image{compare(math(`x/y`, x => number(3), y => number(3)), ==, number(3))} -> seq() 37 | image{compare(unpack(Float, 0, string("1234")), ==, number(3))} -> seq() 38 | image{compare(unpack(Float, 0, pack(Float, number(3))), ==, number(3))} -> seq() 39 | image{} -> logx(reduce(unpack(Array, Float, 3, 0, string("1234")), string, string(""), string(""))) 40 | image{} -> logx(reduce(map(unpack(Array, Float, 3, 0, string("1234")), string, convert(number, string, current_element())), string, string(""), concat(current_reduction(), current_element(), string(" ")))) 41 | image{} -> thread(seq(), 10) 42 | image{} -> logx(at(0, unpack(Array, Float, 3, 0, string("1234")))) 43 | image{} -> global=(test, handle()) 44 | -------------------------------------------------------------------------------- /texture_renderer/scripts/renderdoc/export_pipelines.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | 4 | EXPORT_DIR = "#---CHANGE-ME---#" 5 | 6 | def export(controller, draw): 7 | eventId = draw.eventId 8 | print(eventId) 9 | controller.SetFrameEvent(eventId, True) 10 | 11 | pipelineState = controller.GetVulkanPipelineState() 12 | pipeline = pipelineState.graphics 13 | descriptors = pipeline.descriptorSets 14 | 15 | baseDir = f"{EXPORT_DIR}/{eventId}" 16 | os.makedirs(baseDir, exist_ok = True) 17 | 18 | shader = pipelineState.fragmentShader 19 | shaderdata = shader.reflection.rawBytes 20 | with open(f"{baseDir}/shader.frag.spv", "wb") as f: 21 | f.write(shaderdata) 22 | 23 | setLayouts = [] 24 | 25 | for setNum, set in enumerate(descriptors): 26 | bindings = [] 27 | for i, b in enumerate(set.bindings): 28 | if not b.stageFlags & renderdoc.ShaderStageMask.Pixel: 29 | continue 30 | t = b.binds[0].type 31 | if t == renderdoc.BindType.ConstantBuffer or t == renderdoc.BindType.ReadOnlyBuffer: 32 | type = 6 # VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER 33 | if t == renderdoc.BindType.Sampler: 34 | type = 0 # VK_DESCRIPTOR_TYPE_SAMPLER 35 | if t == renderdoc.BindType.ImageSampler: 36 | type = 1 # VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER 37 | if t == renderdoc.BindType.ReadOnlyImage: 38 | type = 2 # VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE 39 | binding = {"binding": i, "count": b.descriptorCount, "type": type} 40 | if type == 6 or type == 1 or type == 2: # VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER or VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER or VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE 41 | data = [] 42 | for j, bb in enumerate(b.binds): 43 | name = f"{setNum}_{i}_{j}" 44 | if type == 6: # VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER 45 | name += ".buf" 46 | bufdata = controller.GetBufferData(bb.resourceResourceId, bb.byteOffset, bb.byteSize) 47 | with open(f"{baseDir}/{name}", "wb") as f: 48 | f.write(bufdata) 49 | else: 50 | name += ".png" 51 | texsave = renderdoc.TextureSave() 52 | texsave.resourceId = bb.resourceResourceId 53 | texsave.mip = 0 54 | texsave.slice.sliceIndex = 0 55 | texsave.alpha = renderdoc.AlphaMapping.Preserve 56 | texsave.destType = renderdoc.FileType.PNG 57 | controller.SaveTexture(texsave, f"{baseDir}/{name}") 58 | data.append(name) 59 | binding["data"] = data 60 | bindings.append(binding) 61 | setLayout = {"bindings": bindings} 62 | setLayouts.append(setLayout) 63 | 64 | with open(f"{baseDir}/pipeline.json", "w") as f: 65 | export = {"pipelineLayout": {"setLayouts": setLayouts}} 66 | json.dump(export, f, ensure_ascii=False, indent=4) 67 | 68 | def exportCurrent(controller): 69 | draw = pyrenderdoc.CurAction() 70 | export(controller, draw) 71 | def exportRenderPass(controller): 72 | action = pyrenderdoc.CurAction() 73 | while not action.flags & renderdoc.ActionFlags.EndPass: 74 | export(controller, action) 75 | action = action.next 76 | 77 | pyrenderdoc.Replay().BlockInvoke(exportRenderPass) 78 | -------------------------------------------------------------------------------- /mesh_buffer_tools/src/pose/pose.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | struct pose_part 19 | { 20 | std::string name; 21 | std::string file; 22 | int offset; 23 | }; 24 | 25 | struct options 26 | { 27 | bool transpose = false; 28 | }; 29 | 30 | int main(int argc, char *argv[]) 31 | { 32 | assert(argc > 3); 33 | 34 | std::string input_path = argv[1]; 35 | std::string output_path = argv[2]; 36 | 37 | options my_options = {}; 38 | int partsOffset; 39 | for(partsOffset = 3; std::string(argv[partsOffset]).starts_with("--"); partsOffset++) 40 | { 41 | std::string option = std::string(argv[partsOffset]).substr(2); 42 | std::cout << "Enabling option " << option << ".\n"; 43 | 44 | if(option == "transpose") 45 | my_options.transpose = true; 46 | else 47 | std::cerr << "Unknown option: --" << option << std::endl; 48 | } 49 | 50 | std::vector parts(argc-partsOffset); 51 | for(int i=0; i>> groupMap; 73 | 74 | for(pose_part part : parts) 75 | { 76 | boost::interprocess::file_mapping map((input_path+"/"+part.file).c_str(), boost::interprocess::read_only); 77 | boost::interprocess::mapped_region region(map, boost::interprocess::read_only); 78 | glm::mat3x4* matrices = (glm::mat3x4*) region.get_address(); 79 | 80 | glm::mat3x4* base = matrices + part.offset; 81 | for(int i = 0; i < 256; i++) 82 | { 83 | glm::mat3x4 mat = base[i]; 84 | glm::mat4 mat2(mat); 85 | 86 | mat2[3][0] = mat2[0][3]; 87 | mat2[3][1] = mat2[1][3]; 88 | mat2[3][2] = mat2[2][3]; 89 | mat2[3][3] = 0.0; 90 | 91 | if(my_options.transpose) 92 | mat2 = glm::transpose(mat2); 93 | 94 | std::array floats; 95 | 96 | const float* source = glm::value_ptr(mat2); 97 | for(int i=0; i<16; i++) 98 | floats[i] = source[i]; 99 | 100 | groupMap[part.name][std::to_string(i)] = floats; 101 | } 102 | } 103 | nlohmann::json j = groupMap; 104 | std::ofstream outJson(output_path); 105 | outJson << std::setw(4) << j; 106 | } 107 | -------------------------------------------------------------------------------- /vulkan_layer/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(FetchContent) 2 | FetchContent_Declare( 3 | googletest 4 | URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip 5 | ) 6 | # For Windows: Prevent overriding the parent project's compiler/linker settings 7 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 8 | FetchContent_MakeAvailable(googletest) 9 | 10 | include(GoogleTest) 11 | 12 | add_executable(test_reflection reflection.cpp) 13 | target_link_libraries(test_reflection PUBLIC cheeky_layer) 14 | add_test(reflection test_reflection) 15 | 16 | add_executable(struct_tree struct_tree.cpp) 17 | target_link_libraries(struct_tree PUBLIC cheeky_layer) 18 | add_test(struct_tree struct_tree VkGraphicsPipelineCreateInfo) 19 | 20 | add_executable(test_enum_reflection enum_reflection.cpp) 21 | target_link_libraries(test_enum_reflection PUBLIC cheeky_layer) 22 | add_test(enum_reflection test_enum_reflection) 23 | 24 | add_executable(test_rule_parser rule_parser.cpp) 25 | target_link_libraries(test_rule_parser PUBLIC cheeky_layer) 26 | add_backward(test_rule_parser) 27 | 28 | file(STRINGS rules.txt RULES) 29 | set(COUNTER 1) 30 | foreach(RULE ${RULES}) 31 | add_test(rule_parser_${COUNTER} test_rule_parser "${RULE}") 32 | MATH(EXPR COUNTER "${COUNTER}+1") 33 | endforeach() 34 | 35 | file(STRINGS rules_fail.txt RULES_FAIL) 36 | set(COUNTER 1) 37 | foreach(RULE ${RULES_FAIL}) 38 | add_test(rule_parser_fail_${COUNTER} test_rule_parser ${RULE}) 39 | set_tests_properties(rule_parser_fail_${COUNTER} PROPERTIES WILL_FAIL TRUE) 40 | MATH(EXPR COUNTER "${COUNTER}+1") 41 | endforeach() 42 | 43 | add_executable(test_custom_structs custom_structs.cpp) 44 | target_link_libraries(test_custom_structs PUBLIC cheeky_layer) 45 | add_test(custom_structs test_custom_structs) 46 | 47 | add_executable(test_reflection_string reflection_string.cpp) 48 | target_link_libraries(test_reflection_string PUBLIC cheeky_layer) 49 | add_test(reflection_string test_reflection_string) 50 | 51 | add_executable(test_reflection_array reflection_array.cpp) 52 | target_link_libraries(test_reflection_array PUBLIC cheeky_layer) 53 | add_test(reflection_array test_reflection_array) 54 | 55 | add_executable(test_reflection_flags reflection_flags.cpp) 56 | target_link_libraries(test_reflection_flags PUBLIC cheeky_layer gtest_main) 57 | gtest_discover_tests(test_reflection_flags) 58 | 59 | add_executable(test_rule_parser_multiline rule_parser_multiline.cpp) 60 | target_link_libraries(test_rule_parser_multiline PUBLIC cheeky_layer) 61 | add_test(rule_parser_multiline1 test_rule_parser_multiline ${CMAKE_CURRENT_SOURCE_DIR}/rules.txt) 62 | add_test(rule_parser_multiline2 test_rule_parser_multiline ${CMAKE_CURRENT_SOURCE_DIR}/rules_multiline.txt) 63 | add_backward(test_rule_parser_multiline) 64 | 65 | #add_executable(test_server_socket server_socket.cpp) 66 | #target_link_libraries(test_server_socket PUBLIC cheeky_layer) 67 | #add_backward(test_server_socket) 68 | 69 | add_executable(test_vulkan vulkan_test.cpp) 70 | target_link_libraries(test_vulkan PUBLIC Vulkan::Vulkan) 71 | -------------------------------------------------------------------------------- /vulkan_layer/test/reflection_array.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "reflection/reflectionparser.hpp" 7 | 8 | int main() 9 | { 10 | VkGraphicsPipelineCreateInfo info; 11 | VkPipelineViewportStateCreateInfo viewport; 12 | VkRect2D scissors[2] = {{.extent = {.width = 1024}}, {.extent = {.width = 1023}}}; 13 | 14 | viewport.scissorCount = 2; 15 | viewport.pScissors = scissors; 16 | 17 | info.pViewportState = &viewport; 18 | 19 | { // test pViewportState->pScissors[0] 20 | std::any a = CheekyLayer::reflection::parse_get("pViewportState->pScissors[0].extent.width", &info, "VkGraphicsPipelineCreateInfo"); 21 | assert(std::any_cast(a) == 1024); 22 | 23 | CheekyLayer::reflection::parse_set("pViewportState->pScissors[0].extent.width", &info, "VkGraphicsPipelineCreateInfo", 512u); 24 | 25 | std::any b = CheekyLayer::reflection::parse_get("pViewportState->pScissors[0].extent.width", &info, "VkGraphicsPipelineCreateInfo"); 26 | assert(std::any_cast(b) == 512); 27 | 28 | CheekyLayer::reflection::parse_assign("pViewportState->pScissors[0].extent.width = 128", &info, "VkGraphicsPipelineCreateInfo"); 29 | 30 | std::any c = CheekyLayer::reflection::parse_get("pViewportState->pScissors[0].extent.width", &info, "VkGraphicsPipelineCreateInfo"); 31 | assert(std::any_cast(c) == 128); 32 | } 33 | 34 | { // test pViewportState->pScissors[1] 35 | std::any a = CheekyLayer::reflection::parse_get("pViewportState->pScissors[1].extent.width", &info, "VkGraphicsPipelineCreateInfo"); 36 | assert(std::any_cast(a) == 1023); 37 | 38 | CheekyLayer::reflection::parse_set("pViewportState->pScissors[1].extent.width", &info, "VkGraphicsPipelineCreateInfo", 511u); 39 | 40 | std::any b = CheekyLayer::reflection::parse_get("pViewportState->pScissors[1].extent.width", &info, "VkGraphicsPipelineCreateInfo"); 41 | assert(std::any_cast(b) == 511); 42 | 43 | CheekyLayer::reflection::parse_assign("pViewportState->pScissors[1].extent.width = 127", &info, "VkGraphicsPipelineCreateInfo"); 44 | 45 | std::any c = CheekyLayer::reflection::parse_get("pViewportState->pScissors[1].extent.width", &info, "VkGraphicsPipelineCreateInfo"); 46 | assert(std::any_cast(c) == 127); 47 | } 48 | 49 | { // test if changing pViewportState->pScissors[1] does not effect pViewportState->pScissors[0] 50 | std::any a = CheekyLayer::reflection::parse_get("pViewportState->pScissors[0].extent.width", &info, "VkGraphicsPipelineCreateInfo"); 51 | assert(std::any_cast(a) == 128); 52 | } 53 | 54 | try // test range check 55 | { 56 | std::any a = CheekyLayer::reflection::parse_get("pViewportState->pScissors[2].extent.width", &info, "VkGraphicsPipelineCreateInfo"); 57 | assert(false); 58 | } 59 | catch(const std::runtime_error& e) 60 | { 61 | assert(std::string(e.what()) == "array index 2 for member \"pScissors\" exceeds its length of 2 which can be found in member \"scissorCount\""); 62 | } 63 | 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /tools/.stuff/lib/blender_bone_import.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import mathutils 3 | import json 4 | 5 | def do_bone(part, bone, edit_bones, parent): 6 | if "head" in bone and "tail" in bone and not bone["head"][0] == None and not bone["tail"][0] == None: 7 | b = edit_bones.new(part+"_"+str(bone["group"])) 8 | head = mathutils.Vector(bone["head"]).xzy 9 | head.y *= -1 10 | tail = mathutils.Vector(bone["tail"]).xzy 11 | tail.y *= -1 12 | b.head = head 13 | b.tail = tail 14 | b.parent = parent 15 | 16 | for child in bone["children"]: 17 | do_bone(part, child, edit_bones, b) 18 | elif "children" in bone: 19 | for child in bone["children"]: 20 | do_bone(part, child, edit_bones, parent) 21 | 22 | def load_bones(part): 23 | with open(bpy.path.abspath(f"//bones/{part}.json")) as f: 24 | bones = json.load(f) 25 | try: 26 | bpy.ops.object.mode_set(mode='OBJECT') 27 | except: 28 | pass 29 | 30 | mesh = bpy.data.objects[part] 31 | bpy.context.view_layer.objects.active = mesh 32 | bpy.ops.object.parent_clear(type='CLEAR') 33 | 34 | name = f"Armature-{part}" 35 | if name in bpy.data.objects: 36 | obj = bpy.data.objects[name] 37 | else: 38 | bpy.ops.object.armature_add() 39 | obj = bpy.context.active_object 40 | obj.name = name 41 | bpy.context.view_layer.objects.active = obj 42 | 43 | obj.data.name = name 44 | 45 | bpy.ops.object.mode_set(mode='EDIT', toggle=False) 46 | 47 | edit_bones = obj.data.edit_bones 48 | for b in edit_bones: 49 | edit_bones.remove(b) 50 | 51 | for tree in bones["trees"]: 52 | do_bone(part, tree, edit_bones, None) 53 | 54 | bpy.ops.object.mode_set(mode='OBJECT') 55 | mesh.select_set(True) 56 | obj.select_set(True) 57 | bpy.context.view_layer.objects.active = obj 58 | bpy.ops.object.parent_set(type='ARMATURE') 59 | bpy.ops.object.select_all(action='DESELECT') 60 | 61 | def load_constraints(part): 62 | with open(bpy.path.abspath(f"//bones/{part}.json")) as f: 63 | bones = json.load(f) 64 | name = f"Armature-{part}" 65 | obj = bpy.data.objects[name] 66 | 67 | for bone in obj.pose.bones: 68 | for c in bone.constraints: 69 | bone.constraints.remove(c) 70 | 71 | for tree in bones["trees"]: 72 | if "parent" in tree: 73 | p = tree["parent"] 74 | pp = p["mesh"] 75 | obj2 = bpy.data.objects[f"Armature-{pp}"] 76 | 77 | bone = obj.pose.bones.get(part+"_"+str(tree["group"])) 78 | if bone is not None: 79 | crc = bone.constraints.new('CHILD_OF') 80 | crc.target = obj2 81 | crc.subtarget = pp+"_"+str(p["bone"]) 82 | 83 | with open(bpy.path.abspath("//vhmesh.txt"), "r") as f: 84 | for x in f: 85 | part=x.split()[0] 86 | load_bones(part) 87 | with open(bpy.path.abspath("//vhmesh.txt"), "r") as f: 88 | for x in f: 89 | part=x.split()[0] 90 | load_constraints(part) 91 | bpy.ops.object.mode_set(mode='OBJECT') 92 | -------------------------------------------------------------------------------- /vulkan_layer/src/rules/data/variables.cpp: -------------------------------------------------------------------------------- 1 | #include "rules/data.hpp" 2 | #include "rules/execution_env.hpp" 3 | #include "rules/rules.hpp" 4 | 5 | #include 6 | #include 7 | 8 | namespace CheekyLayer::rules::datas 9 | { 10 | data_register global_data::reg("global"); 11 | data_register local_data::reg("local"); 12 | 13 | void global_data::read(std::istream& in) 14 | { 15 | std::getline(in, m_name, ')'); 16 | } 17 | 18 | bool global_data::supports(selector_type, data_type) 19 | { 20 | return true; 21 | } 22 | 23 | data_value global_data::get(selector_type, data_type type, VkHandle, global_context& global, local_context&, rule &) 24 | { 25 | if(!global.global_variables.contains(m_name)) 26 | { 27 | auto message = fmt::format("no such global variable: {}, the following are available: {}", m_name, 28 | fmt::join(global.global_variables | std::ranges::views::keys, ", ")); 29 | 30 | throw RULE_ERROR(message); 31 | } 32 | 33 | auto& data = global.global_variables.at(m_name); 34 | 35 | bool okay = true; 36 | switch(type) 37 | { 38 | case String: 39 | okay = std::holds_alternative(data); 40 | break; 41 | case Raw: 42 | okay = std::holds_alternative>(data); 43 | break; 44 | case Handle: 45 | okay = std::holds_alternative(data); 46 | break; 47 | case Number: 48 | okay = std::holds_alternative(data); 49 | break; 50 | case List: 51 | okay = std::holds_alternative(data); 52 | break; 53 | } 54 | if(!okay) 55 | throw RULE_ERROR("requested type "+to_string(type)+" does not match type of current reduction"); 56 | 57 | return data; 58 | } 59 | 60 | std::ostream& global_data::print(std::ostream& out) 61 | { 62 | return out << "global(" << m_name << ")"; 63 | } 64 | 65 | void local_data::read(std::istream& in) 66 | { 67 | std::getline(in, m_name, ')'); 68 | } 69 | 70 | bool local_data::supports(selector_type, data_type) 71 | { 72 | return true; 73 | } 74 | 75 | data_value local_data::get(selector_type, data_type type, VkHandle, global_context&, local_context& local, rule &) 76 | { 77 | if(!local.local_variables.contains(m_name)) 78 | { 79 | auto message = fmt::format("no such local variable: {}, the following are available: {}", m_name, 80 | fmt::join(local.local_variables | std::ranges::views::keys, ", ")); 81 | 82 | throw RULE_ERROR(message); 83 | } 84 | 85 | auto& data = local.local_variables.at(m_name); 86 | 87 | bool okay = true; 88 | switch(type) 89 | { 90 | case String: 91 | okay = std::holds_alternative(data); 92 | break; 93 | case Raw: 94 | okay = std::holds_alternative>(data); 95 | break; 96 | case Handle: 97 | okay = std::holds_alternative(data); 98 | break; 99 | case Number: 100 | okay = std::holds_alternative(data); 101 | break; 102 | case List: 103 | okay = std::holds_alternative(data); 104 | break; 105 | } 106 | if(!okay) 107 | throw RULE_ERROR("requested type "+to_string(type)+" does not match type of current reduction"); 108 | 109 | return data; 110 | } 111 | 112 | std::ostream& local_data::print(std::ostream& out) 113 | { 114 | return out << "local(" << m_name << ")"; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /mesh_buffer_tools/src/common/input_assembly.cpp: -------------------------------------------------------------------------------- 1 | #include "input_assembly.hpp" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace mbt 8 | { 9 | input_attribute::input_attribute(int index_, std::string name_, int location_, int binding_, std::string format_, int offset_) : 10 | index(index_), name(name_), location(location_), binding(binding_), format(format_), offset(offset_) 11 | { 12 | 13 | } 14 | 15 | std::istream& operator>>(std::istream& is, input_attribute& ia) 16 | { 17 | is >> ia.index; 18 | is >> ia.name; 19 | is >> ia.location; 20 | is >> ia.binding; 21 | is >> ia.format; 22 | is >> ia.offset; 23 | return is; 24 | } 25 | 26 | input_attribute::attribute_value input_attribute::read(void* pointer) 27 | { 28 | void* p = ((uint8_t*)pointer) + offset; 29 | 30 | attribute_value val; 31 | if(format=="R32G32B32_FLOAT") 32 | { 33 | val.vec3 = *(glm::vec3*)p; 34 | return val; 35 | } 36 | if(format=="R8G8B8A8_UINT") 37 | { 38 | val.u8vec4 = glm::unpackUint4x8(*(glm::uint32*)p); 39 | return val; 40 | } 41 | if(format=="R8G8B8A8_UNORM") 42 | { 43 | val.vec4 = glm::unpackUnorm4x8(*(uint*)p); 44 | return val; 45 | } 46 | if(format=="R8G8B8A8_SNORM") 47 | { 48 | val.vec4 = glm::unpackSnorm4x8(*(uint*)p); 49 | return val; 50 | } 51 | if(format=="R16G16_FLOAT") 52 | { 53 | val.vec2 = glm::unpackHalf2x16(*(uint*)p); 54 | return val; 55 | } 56 | if(format=="R16G16B16A16_FLOAT") 57 | { 58 | val.vec4 = glm::unpackHalf4x16(*(glm::uint64*)p); 59 | return val; 60 | } 61 | if(format=="R32G32_FLOAT") 62 | { 63 | val.vec2 = *(glm::vec2*)p; 64 | return val; 65 | } 66 | if(format=="R32G32B32A32_FLOAT") 67 | { 68 | val.vec4 = *(glm::vec4*)p; 69 | return val; 70 | } 71 | if(format=="R32G32B32A32_SINT") 72 | { 73 | glm::ivec4 v = *(glm::ivec4*)p; 74 | val.u8vec4.x = v.x; 75 | val.u8vec4.y = v.y; 76 | val.u8vec4.z = v.z; 77 | val.u8vec4.w = v.w; 78 | return val; 79 | } 80 | 81 | throw std::runtime_error("unknown format: "+format); 82 | } 83 | 84 | void input_attribute::write(attribute_value val, void *pointer) 85 | { 86 | void* p = ((uint8_t*)pointer) + offset; 87 | 88 | if(format=="R32G32B32_FLOAT") 89 | { 90 | *(glm::vec3*)p = val.vec3; 91 | return; 92 | } 93 | if(format=="R8G8B8A8_UINT") 94 | { 95 | *(glm::uint32*)p = glm::packUint4x8(val.u8vec4); 96 | return; 97 | } 98 | if(format=="R8G8B8A8_UNORM") 99 | { 100 | *(uint*)p = glm::packUnorm4x8(val.vec4); 101 | return; 102 | } 103 | if(format=="R8G8B8A8_SNORM") 104 | { 105 | *(uint*)p = glm::packSnorm4x8(val.vec4); 106 | return; 107 | } 108 | if(format=="R16G16_FLOAT") 109 | { 110 | *(uint*)p = glm::packHalf2x16(val.vec2); 111 | return; 112 | } 113 | if(format=="R16G16B16A16_FLOAT") 114 | { 115 | *(glm::uint64*)p = glm::packHalf4x16(val.vec4); 116 | return; 117 | } 118 | if(format=="R32G32_FLOAT") 119 | { 120 | *(glm::vec2*)p = val.vec2; 121 | return; 122 | } 123 | if(format=="R32G32B32A32_FLOAT") 124 | { 125 | *(glm::vec4*)p = val.vec4; 126 | return; 127 | } 128 | if(format=="R32G32B32A32_SINT") 129 | { 130 | *(glm::ivec4*)p = {val.u8vec4.x, val.u8vec4.y, val.u8vec4.z, val.u8vec4.w}; 131 | return; 132 | } 133 | 134 | throw std::runtime_error("unknown format: "+format); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /vulkan_layer/generate_reflection.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import reg 4 | 5 | vkreg = reg.Registry() 6 | vkreg.loadFile("/usr/share/vulkan/registry/vk.xml") 7 | 8 | blacklist = [ 9 | "VkPipelineCacheStageValidationIndexEntry", 10 | "VkPipelineCacheSafetyCriticalIndexEntry", 11 | "VkPipelineCacheHeaderVersionSafetyCriticalOne", 12 | "VkPipelineCacheValidationVersion", 13 | "VkPipelineMatchControl", 14 | "VkFaultData", 15 | "VkFaultType", 16 | "VkFaultLevel", 17 | "VkFaultQueryBehavior", 18 | "VkPipelinePoolSize", 19 | "VkCommandPoolMemoryConsumption", 20 | "VkExternalFenceHandleTypeFlagBits", 21 | "VkExternalSemaphoreHandleTypeFlagBits", 22 | "VkExternalMemoryHandleTypeFlagBits", 23 | ] 24 | 25 | print("#include \"reflection/vkreflection.hpp\"") 26 | print("#include \"reflection/custom_structs.hpp\"") 27 | print("namespace CheekyLayer { namespace reflection {") 28 | print("reflection_map struct_reflection_map = {") 29 | for (name, description) in vkreg.typedict.items(): 30 | if name in blacklist: 31 | continue 32 | if not 'category' in description.elem.attrib: 33 | continue 34 | if description.elem.attrib["category"] != "struct": 35 | continue 36 | if 'structextends' in description.elem.attrib: 37 | continue 38 | if name[-1].isupper() and not name[-2].isdigit(): 39 | continue 40 | 41 | print(f"\t{{\n\t\t\"{name}\",\n\t\tVkTypeInfo{{") 42 | print(f"\t\t\t.name = \"{name}\",") 43 | print(f"\t\t\t.size = sizeof({name}),") 44 | print(f"\t\t\t.members = inner_reflection_map{{") 45 | for member in description.getMembers(): 46 | mType=member[0].text 47 | mName=member[1].text 48 | if mName == "sType" or mName == "pNext": 49 | continue 50 | 51 | mPointer = member[0].tail != None and '*' in member[0].tail 52 | if mPointer: 53 | mPointer = "true" 54 | else: 55 | mPointer = "false" 56 | mArray = 'len' in member.attrib; 57 | if mArray: 58 | mArray = "true" 59 | mArrayLen = member.attrib['len'].replace("\\", "\\\\") 60 | mArrayInfo = f", .arrayLength = \"{mArrayLen}\"" 61 | else: 62 | mArray = "false" 63 | mArrayInfo = "" 64 | 65 | print(f"\t\t\t\t{{\"{mName}\", VkReflectInfo{{ .name = \"{mName}\", .type = \"{mType}\", .pointer = {mPointer}, .array = {mArray}{mArrayInfo}, .offset = offsetof({name}, {mName}) }}}},") 66 | 67 | print("\t\t\t}\n\t\t}\n\t},") 68 | print("\tVK_CUSTOM_STRUCTS") 69 | print("};"); 70 | 71 | 72 | print("enum_map enum_reflection_map = {"); 73 | for enum in vkreg.tree.findall("enums"): 74 | name=enum.attrib["name"] 75 | if name in blacklist: 76 | continue 77 | if name == "VkStructureType": 78 | continue 79 | if name == "VkObjectType": 80 | continue 81 | if name == "API Constants": 82 | continue 83 | if name == "VkResult": 84 | continue 85 | if name[-1].isupper(): 86 | continue 87 | 88 | print(f"\t{{\n\t\t\"{name}\",\n\t\tinner_enum_map{{") 89 | for val in enum.findall(".//enum"): 90 | if "protect" in val.attrib: 91 | continue 92 | vName = val.attrib["name"] 93 | if "RESERVED" in vName or "_RESERVE_" in vName: 94 | continue 95 | if vName.endswith("_EXT"): 96 | continue 97 | if vName.endswith("_QCOM") or vName.endswith("_HUAWEI"): 98 | continue 99 | print(f"\t\t\t{{\"{vName}\", VkEnumEntry{{ .name = \"{vName}\", .value = (uint32_t) {vName}}}}},") 100 | print("\t\t}\n\t},") 101 | print("};"); 102 | 103 | print("}}"); 104 | -------------------------------------------------------------------------------- /vulkan_layer/include/reflection/custom_structs.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace CheekyLayer { namespace reflection { 7 | struct VkCommandBufferState { 8 | uint32_t scissorCount; 9 | VkRect2D *pScissors; 10 | 11 | VkBool32 transformFeedback; 12 | }; 13 | 14 | struct VkCmdDrawIndexed { 15 | uint32_t indexCount; 16 | uint32_t instanceCount; 17 | uint32_t firstIndex; 18 | int32_t vertexOffset; 19 | uint32_t firstInstance; 20 | 21 | VkCommandBufferState commandBufferState; 22 | }; 23 | 24 | struct VkCmdDraw { 25 | uint32_t vertexCount; 26 | uint32_t instanceCount; 27 | uint32_t firstVertex; 28 | uint32_t firstInstance; 29 | 30 | VkCommandBufferState commandBufferState; 31 | }; 32 | 33 | #define VK_COMMAND_BUFFER_STATE \ 34 | { \ 35 | "VkCommandBufferState", \ 36 | VkTypeInfo{ \ 37 | .name = "VkCommandBufferState", \ 38 | .size = sizeof(VkCommandBufferState), \ 39 | .members = inner_reflection_map{ \ 40 | {"scissorCount", VkReflectInfo{ .name = "scissorCount", .type = "uint32_t", .pointer = false, .offset = offsetof(VkCommandBufferState, scissorCount) }}, \ 41 | {"pScissors", VkReflectInfo{ .name = "pScissors", .type = "VkRect2D", .pointer = true, .array = true, .arrayLength = "scissorCount", .offset = offsetof(VkCommandBufferState, pScissors) }}, \ 42 | {"transformFeedback", VkReflectInfo{ .name = "transformFeedback", .type = "VkBool32", .pointer = false, .offset = offsetof(VkCommandBufferState, transformFeedback) }}, \ 43 | } \ 44 | } \ 45 | } 46 | 47 | #define VK_CMD_DRAW_INDEXED \ 48 | { \ 49 | "VkCmdDrawIndexed", \ 50 | VkTypeInfo{ \ 51 | .name = "VkCmdDrawIndexed", \ 52 | .size = sizeof(VkCmdDrawIndexed), \ 53 | .members = inner_reflection_map{ \ 54 | {"indexCount", VkReflectInfo{ .name = "indexCount", .type = "uint32_t", .pointer = false, .offset = offsetof(VkCmdDrawIndexed, indexCount) }}, \ 55 | {"instanceCount", VkReflectInfo{ .name = "instanceCount", .type = "uint32_t", .pointer = false, .offset = offsetof(VkCmdDrawIndexed, instanceCount) }}, \ 56 | {"firstIndex", VkReflectInfo{ .name = "firstIndex", .type = "uint32_t", .pointer = false, .offset = offsetof(VkCmdDrawIndexed, firstIndex) }}, \ 57 | {"vertexOffset", VkReflectInfo{ .name = "vertexOffset", .type = "int32_t", .pointer = false, .offset = offsetof(VkCmdDrawIndexed, vertexOffset) }}, \ 58 | {"firstInstance", VkReflectInfo{ .name = "firstInstance", .type = "uint32_t", .pointer = false, .offset = offsetof(VkCmdDrawIndexed, firstInstance) }}, \ 59 | {"commandBufferState", VkReflectInfo{ .name = "commandBufferState", .type = "VkCommandBufferState", .pointer = false, .offset = offsetof(VkCmdDrawIndexed, commandBufferState) }}, \ 60 | } \ 61 | } \ 62 | } 63 | 64 | #define VK_CMD_DRAW \ 65 | { \ 66 | "VkCmdDraw", \ 67 | VkTypeInfo{ \ 68 | .name = "VkCmdDraw", \ 69 | .size = sizeof(VkCmdDraw), \ 70 | .members = inner_reflection_map{ \ 71 | {"vertexCount", VkReflectInfo{ .name = "vertexCount", .type = "uint32_t", .pointer = false, .offset = offsetof(VkCmdDraw, vertexCount) }}, \ 72 | {"instanceCount", VkReflectInfo{ .name = "instanceCount", .type = "uint32_t", .pointer = false, .offset = offsetof(VkCmdDraw, instanceCount) }}, \ 73 | {"firstVertex", VkReflectInfo{ .name = "firstVertex", .type = "uint32_t", .pointer = false, .offset = offsetof(VkCmdDraw, firstVertex) }}, \ 74 | {"firstInstance", VkReflectInfo{ .name = "firstInstance", .type = "uint32_t", .pointer = false, .offset = offsetof(VkCmdDraw, firstInstance) }}, \ 75 | {"commandBufferState", VkReflectInfo{ .name = "commandBufferState", .type = "VkCommandBufferState", .pointer = false, .offset = offsetof(VkCmdDraw, commandBufferState) }}, \ 76 | } \ 77 | } \ 78 | } 79 | 80 | #define VK_CUSTOM_STRUCTS \ 81 | VK_COMMAND_BUFFER_STATE, \ 82 | VK_CMD_DRAW_INDEXED, \ 83 | VK_CMD_DRAW 84 | }} 85 | -------------------------------------------------------------------------------- /tools/.stuff/bin/vhmeshtest: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -f vhmesh.txt ]; then 4 | echo "No vhmesh.txt file!" 5 | exit 2 6 | fi 7 | 8 | if [ $# -ne 1 ]; then 9 | echo "Syntax: vhmeshinstall " 10 | exit 2 11 | fi 12 | 13 | file=$1 14 | if [ ! -f "$file" ]; then 15 | echo "File $file not found!" 16 | exit 2 17 | fi 18 | 19 | echo "Exporting parts from Blender file $file ..." 20 | blender -b $file --python $VH_LIB/blender_export_mesh.py #>/dev/null 2>/dev/null 21 | 22 | name=${file%.*} 23 | 24 | test_dir=test 25 | mkdir -p $test_dir 26 | 27 | 28 | while read line; do 29 | index=$(echo $line | cut -f6 -d" ") 30 | rm $test_dir/$index.buf 31 | 32 | additional=( $(echo $line | cut -f7- -d" ") ) 33 | for i in ${!additional[*]} 34 | do 35 | if ! ((i % 2)); then 36 | rm $test_dir/${additional[$i]}.buf 37 | fi 38 | done 39 | done /dev/null 2>/dev/null 103 | cd .. 104 | 105 | rm $test_dir/vhmesh.txt 106 | if [ "$name" != "base" ]; then 107 | mv $test_dir/base.blend $test_dir/$name.blend 108 | fi 109 | 110 | while read line; do 111 | part=$(echo $line | cut -f1 -d" ") 112 | index=$(echo $line | cut -f2 -d" ") 113 | vertex=$(echo $line | cut -f3 -d" ") 114 | texCoord=$(echo $line | cut -f5 -d" ") 115 | 116 | rm $test_dir/$index.buf 2>/dev/null 117 | rm $test_dir/$vertex.buf 2>/dev/null 118 | rm $test_dir/$texCoord.buf 2>/dev/null 119 | 120 | if [ "$name" != "base" ]; then 121 | rm $test_dir/base_$part.obj 122 | rm $test_dir/base_$part.obj.json 123 | fi 124 | done current_element_data::reg("current_element"); 8 | data_register current_index_data::reg("current_index"); 9 | data_register map_data::reg("map"); 10 | 11 | void current_element_data::read(std::istream& in) 12 | { 13 | check_stream(in, ')'); 14 | } 15 | 16 | data_value current_element_data::get(selector_type, data_type type, VkHandle, global_context&, local_context& local, rule &) 17 | { 18 | if(!local.currentElement) 19 | throw RULE_ERROR("no current element"); 20 | 21 | bool okay = true; 22 | switch(type) 23 | { 24 | case String: 25 | okay = std::holds_alternative(*local.currentElement); 26 | break; 27 | case Raw: 28 | okay = std::holds_alternative>(*local.currentElement); 29 | break; 30 | case Handle: 31 | okay = std::holds_alternative(*local.currentElement); 32 | break; 33 | case Number: 34 | okay = std::holds_alternative(*local.currentElement); 35 | break; 36 | case List: 37 | okay = std::holds_alternative(*local.currentElement); 38 | break; 39 | } 40 | if(!okay) 41 | throw RULE_ERROR("requested type "+to_string(type)+" does not match type of current element"); 42 | 43 | return *local.currentElement; 44 | } 45 | 46 | bool current_element_data::supports(selector_type, data_type) 47 | { 48 | return true; 49 | } 50 | 51 | std::ostream& current_element_data::print(std::ostream& out) 52 | { 53 | return out << "current_element()"; 54 | } 55 | 56 | void current_index_data::read(std::istream& in) 57 | { 58 | check_stream(in, ')'); 59 | } 60 | 61 | data_value current_index_data::get(selector_type, data_type type, VkHandle, global_context&, local_context& local, rule &) 62 | { 63 | return static_cast(local.currentIndex); 64 | } 65 | 66 | bool current_index_data::supports(selector_type, data_type type) 67 | { 68 | return type == data_type::Number; 69 | } 70 | 71 | std::ostream& current_index_data::print(std::ostream& out) 72 | { 73 | return out << "current_index()"; 74 | } 75 | 76 | void map_data::read(std::istream& in) 77 | { 78 | m_src = read_data(in, m_type); 79 | check_stream(in, ','); 80 | skip_ws(in); 81 | if(!m_src->supports(m_type, data_type::List)) 82 | { 83 | std::ostringstream of; 84 | of << "Source \""; 85 | m_src->print(of); 86 | of << "\" does not support type List."; 87 | throw RULE_ERROR(of.str()); 88 | } 89 | 90 | std::string dt; 91 | std::getline(in, dt, ','); 92 | skip_ws(in); 93 | m_elementDstType = data_type_from_string(dt); 94 | 95 | m_mapper = read_data(in, m_type); 96 | check_stream(in, ')'); 97 | if(!m_mapper->supports(m_type, m_elementDstType)) 98 | { 99 | std::ostringstream of; 100 | of << "Mapper \""; 101 | m_src->print(of); 102 | of << "\" does not support requested element type " << to_string(m_elementDstType); 103 | throw RULE_ERROR(of.str()); 104 | } 105 | } 106 | 107 | bool map_data::supports(selector_type, data_type t) 108 | { 109 | return t == data_type::List; 110 | } 111 | 112 | data_value map_data::get(selector_type stype, data_type type, VkHandle handle, global_context& global, local_context& local, rule& rule) 113 | { 114 | data_list src = std::get(m_src->get(stype, data_type::List, handle, global, local, rule)); 115 | 116 | auto saved = local.currentElement; 117 | for(data_value& elem : src.values) 118 | { 119 | local.currentElement = &elem; 120 | elem = m_mapper->get(stype, m_elementDstType, handle, global, local, rule); 121 | } 122 | local.currentElement = saved; 123 | 124 | return src; 125 | } 126 | 127 | std::ostream& map_data::print(std::ostream& out) 128 | { 129 | out << "map("; 130 | m_src->print(out); 131 | out << ", " << to_string(m_elementDstType) << ", "; 132 | m_mapper->print(out); 133 | out << ")"; 134 | return out; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /vulkan_layer/src/rules/data/reduce.cpp: -------------------------------------------------------------------------------- 1 | #include "rules/data.hpp" 2 | #include "rules/execution_env.hpp" 3 | #include "rules/rules.hpp" 4 | 5 | namespace CheekyLayer::rules::datas 6 | { 7 | data_register current_reduction_data::reg("current_reduction"); 8 | data_register reduce_data::reg("reduce"); 9 | 10 | void current_reduction_data::read(std::istream& in) 11 | { 12 | check_stream(in, ')'); 13 | } 14 | 15 | data_value current_reduction_data::get(selector_type, data_type type, VkHandle, global_context&, local_context& local, rule &) 16 | { 17 | if(!local.currentReduction) 18 | throw RULE_ERROR("no current reduction"); 19 | 20 | bool okay = true; 21 | switch(type) 22 | { 23 | case String: 24 | okay = std::holds_alternative(*local.currentReduction); 25 | break; 26 | case Raw: 27 | okay = std::holds_alternative>(*local.currentReduction); 28 | break; 29 | case Handle: 30 | okay = std::holds_alternative(*local.currentReduction); 31 | break; 32 | case Number: 33 | okay = std::holds_alternative(*local.currentReduction); 34 | break; 35 | case List: 36 | okay = std::holds_alternative(*local.currentReduction); 37 | break; 38 | } 39 | if(!okay) 40 | throw RULE_ERROR("requested type "+to_string(type)+" does not match type of current reduction"); 41 | 42 | return *local.currentReduction; 43 | } 44 | 45 | bool current_reduction_data::supports(selector_type, data_type) 46 | { 47 | return true; 48 | } 49 | 50 | std::ostream& current_reduction_data::print(std::ostream& out) 51 | { 52 | return out << "current_reduction()"; 53 | } 54 | 55 | void reduce_data::read(std::istream& in) 56 | { 57 | m_src = read_data(in, m_type); 58 | check_stream(in, ','); 59 | skip_ws(in); 60 | if(!m_src->supports(m_type, data_type::List)) 61 | { 62 | std::ostringstream of; 63 | of << "Source \""; 64 | m_src->print(of); 65 | of << "\" does not support type List."; 66 | throw RULE_ERROR(of.str()); 67 | } 68 | 69 | std::string dt; 70 | std::getline(in, dt, ','); 71 | skip_ws(in); 72 | m_dstType = data_type_from_string(dt); 73 | 74 | m_init = read_data(in, m_type); 75 | check_stream(in, ','); 76 | skip_ws(in); 77 | if(!m_init->supports(m_type, m_dstType)) 78 | { 79 | std::ostringstream of; 80 | of << "Initial value \""; 81 | m_src->print(of); 82 | of << "\" does not support requested element type " << to_string(m_dstType); 83 | throw RULE_ERROR(of.str()); 84 | } 85 | 86 | m_accumulator = read_data(in, m_type); 87 | check_stream(in, ')'); 88 | if(!m_accumulator->supports(m_type, m_dstType)) 89 | { 90 | std::ostringstream of; 91 | of << "Accumulator \""; 92 | m_src->print(of); 93 | of << "\" does not support requested element type " << to_string(m_dstType); 94 | throw RULE_ERROR(of.str()); 95 | } 96 | } 97 | 98 | bool reduce_data::supports(selector_type, data_type t) 99 | { 100 | return t == m_dstType; 101 | } 102 | 103 | data_value reduce_data::get(selector_type stype, data_type type, VkHandle handle, global_context& global, local_context& local, rule& rule) 104 | { 105 | data_list src = std::get(m_src->get(stype, data_type::List, handle, global, local, rule)); 106 | 107 | auto savedElem = local.currentElement; 108 | auto savedRedu = local.currentReduction; 109 | 110 | data_value val = m_init->get(stype, m_dstType, handle, global, local, rule); 111 | local.currentReduction = &val; 112 | for(data_value& elem : src.values) 113 | { 114 | local.currentElement = &elem; 115 | val = m_accumulator->get(stype, m_dstType, handle, global, local, rule); 116 | } 117 | local.currentReduction = savedRedu; 118 | local.currentElement = savedElem; 119 | 120 | return val; 121 | } 122 | 123 | std::ostream& reduce_data::print(std::ostream& out) 124 | { 125 | out << "reduce("; 126 | m_src->print(out); 127 | out << ", " << to_string(m_dstType) << ", "; 128 | m_init->print(out); 129 | out << ", "; 130 | m_accumulator->print(out); 131 | out << ")"; 132 | return out; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /vulkan_layer/include/rules/ipc.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace CheekyLayer 14 | { 15 | struct instance; 16 | struct device; 17 | } 18 | 19 | namespace CheekyLayer::rules::ipc 20 | { 21 | class file_descriptor 22 | { 23 | public: 24 | virtual ~file_descriptor() = default; 25 | 26 | virtual void close() = 0; 27 | virtual size_t write(std::vector&, int arg) = 0; 28 | std::string m_name; 29 | }; 30 | 31 | class local_file : public file_descriptor 32 | { 33 | public: 34 | local_file(std::string filename); 35 | virtual void close(); 36 | virtual size_t write(std::vector&, int arg = 0); 37 | protected: 38 | std::unique_ptr m_stream; 39 | }; 40 | 41 | enum class socket_type 42 | { 43 | TCP, 44 | UDP 45 | }; 46 | 47 | enum class protocol_type 48 | { 49 | Raw, 50 | LengthPrefixed, 51 | Lines 52 | }; 53 | 54 | void listen_helper(std::stop_token& stop, protocol_type protocol, int fd, std::function handler); 55 | 56 | class socket : public file_descriptor 57 | { 58 | public: 59 | socket(socket_type type, std::string hostname, int port, protocol_type protocol, instance* instance) 60 | : socket(type, hostname, port, protocol) { 61 | m_instance = instance; 62 | m_device = nullptr; 63 | } 64 | socket(socket_type type, std::string hostname, int port, protocol_type protocol, device* device) 65 | : socket(type, hostname, port, protocol) { 66 | m_instance = nullptr; 67 | m_device = device; 68 | } 69 | socket(socket_type type, std::string hostname, int port, protocol_type protocol, instance* instance, device* device) 70 | : socket(type, hostname, port, protocol) { 71 | m_instance = instance; 72 | m_device = device; 73 | } 74 | virtual void close(); 75 | virtual size_t write(std::vector&, int arg = 0); 76 | 77 | static socket_type socket_type_from_string(std::string s); 78 | static std::string socket_type_to_string(socket_type e); 79 | static protocol_type protocol_type_from_string(std::string s); 80 | static std::string protocol_type_to_string(protocol_type e); 81 | protected: 82 | socket(socket_type type, std::string hostname, int port, protocol_type protocol); 83 | 84 | instance* m_instance; 85 | device* m_device; 86 | 87 | int m_fd; 88 | socket_type m_type; 89 | protocol_type m_protocol; 90 | std::jthread m_receiveThread; 91 | 92 | size_t writeRaw(void* p, size_t size); 93 | void receiveThread(std::stop_token stop); 94 | }; 95 | 96 | class server_socket : public file_descriptor 97 | { 98 | public: 99 | server_socket(socket_type type, std::string hostname, int port, protocol_type protocol, instance* instance) 100 | : server_socket(type, hostname, port, protocol) { 101 | m_instance = instance; 102 | m_device = nullptr; 103 | } 104 | server_socket(socket_type type, std::string hostname, int port, protocol_type protocol, device* device) 105 | : server_socket(type, hostname, port, protocol) { 106 | m_instance = nullptr; 107 | m_device = device; 108 | } 109 | server_socket(socket_type type, std::string hostname, int port, protocol_type protocol, instance* instance, device* device) 110 | : server_socket(type, hostname, port, protocol) { 111 | m_instance = instance; 112 | m_device = device; 113 | } 114 | virtual void close(); 115 | virtual size_t write(std::vector&, int client); 116 | protected: 117 | server_socket(socket_type type, std::string hostname, int port, protocol_type protocol); 118 | 119 | instance* m_instance; 120 | device* m_device; 121 | 122 | int m_fd; 123 | socket_type m_type; 124 | protocol_type m_protocol; 125 | std::jthread m_listenThread; 126 | std::vector m_clientThreads{}; 127 | 128 | size_t writeRaw(int client, void* p, size_t size); 129 | void receiveThread(std::stop_token stop, int fd, sockaddr_in addr); 130 | }; 131 | } 132 | -------------------------------------------------------------------------------- /vulkan_layer/src/descriptors.cpp: -------------------------------------------------------------------------------- 1 | #include "layer.hpp" 2 | #include "objects.hpp" 3 | #include "rules/rules.hpp" 4 | #include 5 | 6 | bool from_descriptorType(VkDescriptorType type, CheekyLayer::rules::selector_type& outType) 7 | { 8 | switch(type) 9 | { 10 | case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: 11 | case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: 12 | case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: 13 | case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: 14 | outType = CheekyLayer::rules::selector_type::Image; 15 | return true; 16 | case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: 17 | case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: 18 | case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: 19 | case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: 20 | outType = CheekyLayer::rules::selector_type::Buffer; 21 | return true; 22 | default: 23 | return false; 24 | } 25 | } 26 | 27 | namespace CheekyLayer { 28 | 29 | VkResult device::CreateDescriptorUpdateTemplate(const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) 30 | { 31 | VkResult result = dispatch.CreateDescriptorUpdateTemplate(handle, pCreateInfo, pAllocator, pDescriptorUpdateTemplate); 32 | if(result != VK_SUCCESS) 33 | return result; 34 | 35 | logger->debug("CreateDescriptorUpdateTemplate: {} -> {}", pCreateInfo->descriptorUpdateEntryCount, fmt::ptr(pDescriptorUpdateTemplate)); 36 | updateTemplates[*pDescriptorUpdateTemplate] = 37 | std::vector(pCreateInfo->pDescriptorUpdateEntries, pCreateInfo->pDescriptorUpdateEntries+pCreateInfo->descriptorUpdateEntryCount); 38 | 39 | return result; 40 | } 41 | 42 | void device::UpdateDescriptorSetWithTemplate(VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData) 43 | { 44 | dispatch.UpdateDescriptorSetWithTemplate(handle, descriptorSet, descriptorUpdateTemplate, pData); 45 | 46 | descriptor_state& state = descriptorStates[descriptorSet]; 47 | auto& info = updateTemplates[descriptorUpdateTemplate]; 48 | for(int i=0; i(pData)) + entry.offset + j*entry.stride; 65 | switch(type) { 66 | case rules::Buffer: { 67 | const VkDescriptorImageInfo* info = (const VkDescriptorImageInfo*) newPtr; 68 | binding.arrayElements[entry.dstArrayElement + j] = {imageViewToImage[info->imageView], *info}; 69 | break; 70 | } 71 | case rules::Image: { 72 | const VkDescriptorBufferInfo* info = (const VkDescriptorBufferInfo*) newPtr; 73 | binding.arrayElements[entry.dstArrayElement + j] = {info->buffer, *info}; 74 | break; 75 | } 76 | default: 77 | logger->warn("UpdateDescriptorSetWithTemplate: Unknown descriptor type {}", rules::to_string(type)); 78 | break; 79 | } 80 | } 81 | } catch(const std::exception& ex) { 82 | logger->error("UpdateDescriptorSetWithTemplate: {}", ex.what()); 83 | } 84 | } 85 | } 86 | 87 | } 88 | 89 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_CreateDescriptorUpdateTemplate( 90 | VkDevice device, 91 | const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, 92 | const VkAllocationCallbacks* pAllocator, 93 | VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) 94 | { 95 | return CheekyLayer::get_device(device).CreateDescriptorUpdateTemplate(pCreateInfo, pAllocator, pDescriptorUpdateTemplate); 96 | } 97 | 98 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_UpdateDescriptorSetWithTemplate( 99 | VkDevice device, 100 | VkDescriptorSet descriptorSet, 101 | VkDescriptorUpdateTemplate descriptorUpdateTemplate, 102 | const void* pData) 103 | { 104 | return CheekyLayer::get_device(device).UpdateDescriptorSetWithTemplate(descriptorSet, descriptorUpdateTemplate, pData); 105 | } 106 | -------------------------------------------------------------------------------- /vulkan_layer/include/rules/conditions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "rules.hpp" 4 | #include "rules/execution_env.hpp" 5 | #include 6 | #include 7 | 8 | namespace CheekyLayer::rules::conditions 9 | { 10 | class hash_condition : public selector_condition 11 | { 12 | public: 13 | hash_condition(selector_type type) : selector_condition(type) { 14 | if(type != selector_type::Buffer && type != selector_type::Image && type != selector_type::Shader) 15 | throw std::runtime_error("the \"hash\" condition is only supported for buffer, image and shader selectors, but not for "+to_string(type)+" selectors"); 16 | } 17 | virtual void read(std::istream&); 18 | virtual bool test(selector_type, VkHandle, global_context&, local_context&); 19 | virtual std::ostream& print(std::ostream&); 20 | private: 21 | std::string m_hash; 22 | 23 | static condition_register reg; 24 | }; 25 | 26 | class mark_condition : public selector_condition 27 | { 28 | public: 29 | mark_condition(selector_type type) : selector_condition(type) {} 30 | virtual void read(std::istream&); 31 | virtual bool test(selector_type, VkHandle, global_context&, local_context&); 32 | virtual std::ostream& print(std::ostream&); 33 | private: 34 | std::string m_mark; 35 | 36 | static condition_register reg; 37 | }; 38 | 39 | class with_condition : public selector_condition 40 | { 41 | public: 42 | with_condition(selector_type type) : selector_condition(type) { 43 | if(type != selector_type::Draw && type != selector_type::Pipeline) 44 | throw std::runtime_error("the \"with\" condition is only supported for draw and pipeline selectors, but not for "+to_string(type)+" selectors"); 45 | } 46 | virtual void read(std::istream&); 47 | virtual bool test(selector_type, VkHandle, global_context&, local_context&); 48 | virtual std::ostream& print(std::ostream&); 49 | private: 50 | std::unique_ptr m_selector; 51 | 52 | static condition_register reg; 53 | }; 54 | 55 | class not_condition : public selector_condition 56 | { 57 | public: 58 | not_condition(selector_type type) : selector_condition(type) {} 59 | virtual void read(std::istream&); 60 | virtual bool test(selector_type, VkHandle, global_context&, local_context&); 61 | virtual std::ostream& print(std::ostream&); 62 | private: 63 | std::unique_ptr m_condition; 64 | 65 | static condition_register reg; 66 | }; 67 | 68 | class or_condition : public selector_condition 69 | { 70 | public: 71 | or_condition(selector_type type) : selector_condition(type) {} 72 | virtual void read(std::istream&); 73 | virtual bool test(selector_type, VkHandle, global_context&, local_context&); 74 | virtual std::ostream& print(std::ostream&); 75 | private: 76 | std::vector> m_conditions; 77 | 78 | static condition_register reg; 79 | }; 80 | 81 | class compare_condition : public selector_condition 82 | { 83 | enum comparison_operator 84 | { 85 | Equal, 86 | NotEqual, 87 | LessThan, 88 | LessThanOrEqual, 89 | GreaterThan, 90 | GreaterThanOrEqual 91 | }; 92 | 93 | public: 94 | compare_condition(selector_type type) : selector_condition(type) {} 95 | virtual void read(std::istream&); 96 | virtual bool test(selector_type, VkHandle, global_context&, local_context&); 97 | virtual std::ostream& print(std::ostream&); 98 | private: 99 | std::unique_ptr m_left; 100 | comparison_operator m_op; 101 | data_type m_dtype; 102 | std::unique_ptr m_right; 103 | 104 | static std::string op_to_string(comparison_operator op); 105 | static comparison_operator op_from_string(std::string s); 106 | 107 | static condition_register reg; 108 | }; 109 | 110 | class custom_condition : public selector_condition 111 | { 112 | public: 113 | custom_condition(selector_type type) : selector_condition(type) { 114 | if(type != selector_type::Custom) 115 | throw std::runtime_error("the \"custom\" condition is only supported for custom selectors, but not for "+to_string(type)+" selectors"); 116 | } 117 | virtual void read(std::istream&); 118 | virtual bool test(selector_type, VkHandle, global_context&, local_context&); 119 | virtual std::ostream& print(std::ostream&); 120 | private: 121 | std::string m_tag; 122 | 123 | static condition_register reg; 124 | }; 125 | } 126 | -------------------------------------------------------------------------------- /vulkan_layer/include/rules/execution_env.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "rules/ipc.hpp" 18 | #include "reflection/custom_structs.hpp" 19 | 20 | namespace CheekyLayer { 21 | struct instance; 22 | struct device; 23 | struct command_buffer_state; 24 | } 25 | 26 | struct CommandBufferState; 27 | namespace CheekyLayer::rules 28 | { 29 | #if (VK_USE_64_BIT_PTR_DEFINES==1) 30 | typedef void* VkHandle; 31 | #else 32 | typedef uint64_t VkHandle; 33 | #endif 34 | 35 | enum selector_type : int; 36 | struct local_context; 37 | 38 | struct data_list; 39 | using data_value = std::variant, VkHandle, double, data_list>; 40 | 41 | enum data_type : int; 42 | struct user_function 43 | { 44 | class data* data; 45 | std::vector arguments; 46 | std::vector default_arguments; 47 | }; 48 | 49 | class global_context 50 | { 51 | public: 52 | std::map> marks; 53 | std::map hashes; 54 | 55 | std::multimap> on_EndCommandBuffer; 56 | std::multimap> on_QueueSubmit; 57 | std::multimap> on_EndRenderPass; 58 | 59 | void onEndCommandBuffer(VkCommandBuffer commandBuffer, std::function function) 60 | { 61 | on_EndCommandBuffer.emplace(commandBuffer, function); 62 | } 63 | void onQueueSubmit(VkCommandBuffer commandBuffer, std::function function) 64 | { 65 | on_QueueSubmit.emplace(commandBuffer, function); 66 | } 67 | void onEndRenderPass(VkCommandBuffer commandBuffer, std::function function) 68 | { 69 | on_EndRenderPass.emplace(commandBuffer, function); 70 | } 71 | 72 | std::unordered_map> fds; 73 | std::vector threads; 74 | 75 | std::unordered_map global_variables; 76 | std::unordered_map user_functions; 77 | }; 78 | 79 | struct draw_info 80 | { 81 | std::vector& images; 82 | std::vector& shaders; 83 | std::vector& vertexBuffers; 84 | VkBuffer indexBuffer; 85 | 86 | std::variant info; 87 | }; 88 | 89 | struct pipeline_info 90 | { 91 | std::vector& shaderStages; 92 | const VkGraphicsPipelineCreateInfo* info; 93 | }; 94 | 95 | struct receive_info 96 | { 97 | ipc::file_descriptor* socket; 98 | uint8_t* buffer; 99 | size_t size; 100 | int extra = 0; 101 | }; 102 | 103 | struct present_info 104 | { 105 | const VkPresentInfoKHR* info; 106 | }; 107 | 108 | struct swapchain_info 109 | { 110 | const VkSwapchainCreateInfoKHR* info; 111 | }; 112 | 113 | using additional_info = std::variant< 114 | draw_info, 115 | pipeline_info, 116 | receive_info, 117 | present_info, 118 | swapchain_info 119 | >; 120 | 121 | struct calling_context 122 | { 123 | std::function printVerbose; 124 | std::optional info; 125 | 126 | VkCommandBuffer commandBuffer; 127 | command_buffer_state* commandBufferState; 128 | 129 | bool canceled; 130 | std::vector overrides; 131 | std::string customTag; 132 | std::vector> creationCallbacks; 133 | 134 | std::unordered_map local_variables; 135 | 136 | void* customPointer; 137 | }; 138 | 139 | struct local_context 140 | { 141 | spdlog::logger& logger; 142 | std::function printVerbose; 143 | 144 | additional_info* info; 145 | 146 | CheekyLayer::instance* instance; 147 | CheekyLayer::device* device; 148 | 149 | VkCommandBuffer commandBuffer; 150 | command_buffer_state* commandBufferState; 151 | 152 | bool& canceled; 153 | std::vector& overrides; 154 | const std::string& customTag; 155 | std::vector>& creationCallbacks; 156 | 157 | int currentIndex; 158 | data_value* currentElement; 159 | data_value* currentReduction; 160 | 161 | std::unordered_map& local_variables; 162 | 163 | void*& customPointer; 164 | }; 165 | } 166 | -------------------------------------------------------------------------------- /image_tools/src/lib/vulkan_tools.cpp: -------------------------------------------------------------------------------- 1 | #ifdef WITH_VULKAN 2 | 3 | #include 4 | #include 5 | 6 | #include "block_compression.hpp" 7 | 8 | namespace image_tools 9 | { 10 | bool is_compression_supported(VkFormat format) 11 | { 12 | switch(format) 13 | { 14 | case VK_FORMAT_BC1_RGB_SRGB_BLOCK: 15 | case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: 16 | case VK_FORMAT_BC1_RGB_UNORM_BLOCK: 17 | case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: 18 | return true; 19 | case VK_FORMAT_BC3_SRGB_BLOCK: 20 | case VK_FORMAT_BC3_UNORM_BLOCK: 21 | return true; 22 | case VK_FORMAT_BC4_UNORM_BLOCK: 23 | case VK_FORMAT_BC4_SNORM_BLOCK: 24 | return true; 25 | case VK_FORMAT_BC5_UNORM_BLOCK: 26 | case VK_FORMAT_BC5_SNORM_BLOCK: 27 | return true; 28 | case VK_FORMAT_BC7_UNORM_BLOCK: 29 | case VK_FORMAT_BC7_SRGB_BLOCK: 30 | return true; 31 | case VK_FORMAT_R8G8B8A8_UNORM: 32 | case VK_FORMAT_R8G8B8A8_SRGB: 33 | return true; 34 | default: 35 | return false; 36 | } 37 | } 38 | bool is_compression_supported(vk::Format format) 39 | { 40 | return is_compression_supported((VkFormat)format); 41 | } 42 | 43 | bool is_decompression_supported(VkFormat format) 44 | { 45 | switch(format) 46 | { 47 | case VK_FORMAT_BC1_RGB_SRGB_BLOCK: 48 | case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: 49 | case VK_FORMAT_BC1_RGB_UNORM_BLOCK: 50 | case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: 51 | return true; 52 | case VK_FORMAT_BC2_SRGB_BLOCK: 53 | case VK_FORMAT_BC2_UNORM_BLOCK: 54 | return true; 55 | case VK_FORMAT_BC3_SRGB_BLOCK: 56 | case VK_FORMAT_BC3_UNORM_BLOCK: 57 | return true; 58 | case VK_FORMAT_BC4_UNORM_BLOCK: 59 | case VK_FORMAT_BC4_SNORM_BLOCK: 60 | return true; 61 | case VK_FORMAT_BC5_UNORM_BLOCK: 62 | case VK_FORMAT_BC5_SNORM_BLOCK: 63 | return true; 64 | case VK_FORMAT_BC7_UNORM_BLOCK: 65 | case VK_FORMAT_BC7_SRGB_BLOCK: 66 | return true; 67 | default: 68 | return false; 69 | } 70 | } 71 | bool is_decompression_supported(vk::Format format) 72 | { 73 | return is_decompression_supported((VkFormat)format); 74 | } 75 | 76 | void compress(VkFormat format, const image& in, std::vector& out, int w, int h) 77 | { 78 | switch(format) 79 | { 80 | case VK_FORMAT_BC1_RGB_SRGB_BLOCK: 81 | case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: 82 | case VK_FORMAT_BC1_RGB_UNORM_BLOCK: 83 | case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: 84 | compressBC1(in, out, w, h); 85 | break; 86 | case VK_FORMAT_BC3_SRGB_BLOCK: 87 | case VK_FORMAT_BC3_UNORM_BLOCK: 88 | compressBC3(in, out, w, h); 89 | break; 90 | case VK_FORMAT_BC4_UNORM_BLOCK: 91 | case VK_FORMAT_BC4_SNORM_BLOCK: 92 | compressBC4(in, out, w, h); 93 | case VK_FORMAT_BC5_UNORM_BLOCK: 94 | case VK_FORMAT_BC5_SNORM_BLOCK: 95 | compressBC5(in, out, w, h); 96 | break; 97 | case VK_FORMAT_BC7_UNORM_BLOCK: 98 | case VK_FORMAT_BC7_SRGB_BLOCK: 99 | compressBC7(in, out, w, h); 100 | break; 101 | case VK_FORMAT_R8G8B8A8_UNORM: 102 | case VK_FORMAT_R8G8B8A8_SRGB: 103 | { 104 | out.resize(w * h * 4); 105 | for(int x=0; x& out, int w, int h) 123 | { 124 | compress((VkFormat)format, in, out, w, h); 125 | } 126 | 127 | void decompress(VkFormat format, const uint8_t* in, image& out, int w, int h) 128 | { 129 | switch(format) 130 | { 131 | case VK_FORMAT_BC1_RGB_SRGB_BLOCK: 132 | case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: 133 | case VK_FORMAT_BC1_RGB_UNORM_BLOCK: 134 | case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: 135 | decompressBC1(in, out, w, h); 136 | break; 137 | case VK_FORMAT_BC2_SRGB_BLOCK: 138 | case VK_FORMAT_BC2_UNORM_BLOCK: 139 | decompressBC2(in, out, w, h); 140 | break; 141 | case VK_FORMAT_BC3_SRGB_BLOCK: 142 | case VK_FORMAT_BC3_UNORM_BLOCK: 143 | decompressBC3(in, out, w, h); 144 | break; 145 | case VK_FORMAT_BC4_UNORM_BLOCK: 146 | case VK_FORMAT_BC4_SNORM_BLOCK: 147 | decompressBC4(in, out, w, h); 148 | case VK_FORMAT_BC5_UNORM_BLOCK: 149 | case VK_FORMAT_BC5_SNORM_BLOCK: 150 | decompressBC5(in, out, w, h); 151 | break; 152 | case VK_FORMAT_BC7_UNORM_BLOCK: 153 | case VK_FORMAT_BC7_SRGB_BLOCK: 154 | decompressBC7(in, out, w, h, true); 155 | break; 156 | default: 157 | throw std::runtime_error("format not supported: "+vk::to_string(vk::Format(format))); 158 | } 159 | } 160 | void decompress(vk::Format format, const uint8_t *in, image &out, int w, int h) 161 | { 162 | decompress((VkFormat)format, in, out, w, h); 163 | } 164 | } 165 | #endif -------------------------------------------------------------------------------- /vulkan_layer/src/rules/data/vulkan.cpp: -------------------------------------------------------------------------------- 1 | #include "rules/data.hpp" 2 | #include "rules/execution_env.hpp" 3 | #include "rules/rules.hpp" 4 | #include "reflection/reflectionparser.hpp" 5 | #include "objects.hpp" 6 | 7 | namespace CheekyLayer::rules::datas 8 | { 9 | data_register vkstruct_data::reg("vkstruct"); 10 | data_register vkdescriptor_data::reg("vkdescriptor"); 11 | 12 | void vkstruct_data::read(std::istream& in) 13 | { 14 | std::getline(in, m_path, ')'); 15 | 16 | switch(m_type) 17 | { 18 | case selector_type::Pipeline: 19 | reflection::parse_get_type(m_path, "VkGraphicsPipelineCreateInfo"); 20 | break; 21 | case selector_type::Draw: 22 | reflection::parse_get_type(m_path, "VkCmdDrawIndexed"); 23 | break; 24 | default: 25 | throw RULE_ERROR("cannot work with selector type "+to_string(m_type)); 26 | } 27 | } 28 | 29 | data_value vkstruct_data::get(selector_type stype, data_type type, VkHandle handle, global_context& global, local_context& local, rule& rule) 30 | { 31 | const void* structData; 32 | std::string structType; 33 | switch(stype) 34 | { 35 | case selector_type::Pipeline: 36 | structData = std::get(*local.info).info; 37 | structType = "VkGraphicsPipelineCreateInfo"; 38 | break; 39 | case selector_type::Draw: { 40 | auto v = std::get(*local.info).info; 41 | if(std::holds_alternative(v)) 42 | { 43 | structData = std::get(v); 44 | structType = "VkCmdDrawIndexed"; 45 | } 46 | else if(std::holds_alternative(v)) 47 | { 48 | structData = std::get(v); 49 | structType = "VkCmdDraw"; 50 | } 51 | break; 52 | } 53 | default: 54 | throw RULE_ERROR("cannot work with selector type "+to_string(stype)); 55 | } 56 | 57 | switch(type) 58 | { 59 | case data_type::Number: 60 | return (double) std::any_cast(reflection::parse_get(m_path, structData, structType)); 61 | case data_type::String: 62 | return reflection::parse_get_string(m_path, structData, structType); 63 | case data_type::Raw: { 64 | uint32_t r = std::any_cast(reflection::parse_get(m_path, structData, structType)); 65 | std::vector v(sizeof(r)); 66 | std::copy((uint8_t*)&r, (uint8_t*)(&r+1), v.begin()); 67 | return v; } 68 | default: 69 | throw RULE_ERROR("cannot return data type "+to_string(type)); 70 | } 71 | } 72 | 73 | bool vkstruct_data::supports(selector_type, data_type type) 74 | { 75 | return type == data_type::Number || type == data_type::String; 76 | } 77 | 78 | std::ostream& vkstruct_data::print(std::ostream& out) 79 | { 80 | out << "vkstruct(" << m_path << ")"; 81 | return out; 82 | } 83 | 84 | void vkdescriptor_data::read(std::istream& in) 85 | { 86 | in >> m_set; 87 | skip_ws(in); 88 | check_stream(in, ','); 89 | skip_ws(in); 90 | 91 | in >> m_binding; 92 | skip_ws(in); 93 | check_stream(in, ','); 94 | skip_ws(in); 95 | 96 | in >> m_arrayIndex; 97 | skip_ws(in); 98 | check_stream(in, ')'); 99 | } 100 | 101 | data_value vkdescriptor_data::get(selector_type, data_type, VkHandle, global_context& global, local_context& local, rule &) 102 | { 103 | VkDescriptorSet set = local.commandBufferState->descriptorSets.at(m_set); 104 | const descriptor_state& descriptorState = local.device->descriptorStates.at(set); 105 | const descriptor_binding& binding = descriptorState.bindings.at(m_binding); 106 | const descriptor_element& element = binding.arrayElements.at(m_arrayIndex); 107 | 108 | data_value handle = element.handle; 109 | 110 | const auto& info = element.info; 111 | if(std::holds_alternative(info)) 112 | { 113 | const auto& bufferInfo = std::get(info); 114 | data_value offset = static_cast(bufferInfo.offset); 115 | data_value range = static_cast(bufferInfo.range); 116 | 117 | return data_list{handle, offset, range}; 118 | } 119 | else if(std::holds_alternative(info)) 120 | { 121 | const auto& imageInfo = std::get(info); 122 | data_value layout = static_cast(static_cast>(imageInfo.imageLayout)); 123 | data_value view = static_cast(imageInfo.imageView); 124 | data_value sampler = static_cast(imageInfo.sampler); 125 | 126 | return data_list{handle, layout, view, sampler}; 127 | } 128 | 129 | return data_list{handle}; 130 | } 131 | 132 | bool vkdescriptor_data::supports(selector_type stype, data_type dtype) 133 | { 134 | return stype == Draw && dtype == List; 135 | } 136 | 137 | std::ostream& vkdescriptor_data::print(std::ostream& out) 138 | { 139 | out << "vkdescriptor(" << m_set << ", " << m_binding << ", " << m_arrayIndex << ")"; 140 | return out; 141 | } 142 | 143 | void vkhandle_data::read(std::istream& in) 144 | { 145 | check_stream(in, ')'); 146 | } 147 | 148 | data_value vkhandle_data::get(selector_type, data_type, VkHandle handle, global_context&, local_context &, rule &) 149 | { 150 | return handle; 151 | } 152 | 153 | bool vkhandle_data::supports(selector_type stype, data_type dtype) 154 | { 155 | return dtype == Handle; 156 | } 157 | 158 | std::ostream& vkhandle_data::print(std::ostream& out) 159 | { 160 | return out << "vkhandle()"; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /vulkan_layer/README.md: -------------------------------------------------------------------------------- 1 | # Cheeky Layer / ``vulkan_layer`` 2 | 3 | A configurable and programmable Vulkan layer made for hooking into games, and extracting and replacing textures, meshes, shaders and much more! 4 | 5 | ## Features 6 | - Extract textures, meshes (raw buffers) and shaders 7 | - Replace textures, meshes and shaders 8 | - Automatic (but limited) texture compression and decompression for replacing and extracting 9 | - Automatic shader compilation (with ``glslang``) for replacing 10 | - Rule based language for custom behaviour 11 | - Interprocess communication over sockets (``socket`` and ``write`` actions) 12 | - Verbose information about selected draw calls (``verbose`` action) 13 | - On-the-fly replacment of textures and meshes (``overload`` and ``preload`` actions) 14 | - Dump aspects of the framebuffer after selected draw calls (``dumpfb`` action) 15 | - Selection of draw calls (and also other things) by uses textures, meshes and shaders (``draw`` selector and ``with`` condition) 16 | - Modification of pipeline parameters at pipeline creation (``override`` action) 17 | - Runtime reflection into Vulkan structs 18 | - Data procession (kinda experiment) supported for a few conditions and actions (e.g. handling data received via IPC) 19 | - Plugin interface for custom conditions and actions 20 | 21 | ## Usage 22 | 23 | ### Build the layer 24 | This project uses the *CMake* build system. 25 | 26 | **Make sure to *ALWAYS* build it in *Release* (or *RelWithDebInfo*) mode! Building in *Debug* mode will result in incredibly poor performance!** 27 | 28 | You can use the following commands to download and build the Vulkan layer: 29 | ```bash 30 | git clone --recurse-submodules https://git.jcm.re/cheeky-imp/cheeky-imp 31 | cd vulkan_layer 32 | mkdir build 33 | cd build 34 | cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .. 35 | cmake --build . --config RelWithDebInfo --target all -- 36 | ``` 37 | 38 | ### Tell Vulkan where to find the layer 39 | The easiest way to tell Vulkan where to find the layer is to make use of environment variables (see [here](https://vulkan.lunarg.com/doc/view/1.3.204.1/windows/layer_configuration.html) for more information on Vulkan Layer configuration): 40 | 41 | - ``VK_LAYER_PATH`` needs to be pointed to ``/path/to/repository/vulkan_layer``. If you already set this variable, use colons (``:``) to separate multiple paths. 42 | - ``VK_INSTANCE_LAYERS`` needs to contain ``VK_LAYER_CHEEKYIMP_CheekyLayer``, so Vulkan knows to automatically load the layer on instance creation. If you want to use multiple layers, use colons (``:``) to separate them. You might need to play around with the order a bit. 43 | 44 | **Warning: Combining the layer with other layers (in particular RenderDoc) can result in instability and lots of crashes.** 45 | 46 | ### Configuring the layer 47 | Sadly, the layer does not support Vulkan Layer Settings Files yet and uses its own kind of configuration files. 48 | A path to the config needs to be provided with the ``CHEEKY_LAYER_CONFIG`` environment variable. 49 | So, create a file (for example called ``config.txt``) and set ``CHEEKY_LAYER_CONFIG`` to the location of the file. 50 | 51 | This file simply contains options in a ``key=value`` format on each line: 52 | ``` 53 | dump=false|false 54 | dumpDirectory=/absolute/path/to/directory/for/dumping 55 | override=true|false 56 | overrideDirectory=/absolute/path/to/directory/for/overrides 57 | logFile=/absolute/path/to/log/file.txt 58 | ruleFile=/absolute/path/to/rule/file.txt 59 | hookDraw=true|false 60 | pluginDirectory=/absolute/path/to/plugin/directory 61 | application=ApplicationName.exe 62 | ``` 63 | 64 | The following options are available: 65 | | Option | Values | Required | Description | 66 | |---|---|---|---| 67 | |``dump``|``true`` or ``false``| yes | ``true`` if textures, buffers and shaders should be dumped when loaded. | 68 | |``dumpDirectory``|absolute path| yes | Path to the directory to use for dumping, should contain ``images/``, ``buffers/``, ``shaders/`` subdirectories. | 69 | |``override``|``true`` or ``false``| yes | ``true`` if textures, buffers and shaders should be potentially overridden when loaded. | 70 | |``overrideDirectory``|absolute path| yes | Path to the directory to search for the images/buffers/shaders that are to be overridden, should contain ``images/``, ``buffers/``, ``shaders/`` subdirectories. | 71 | 72 | ## Required libraries 73 | | Library | Reason | Inclusion | 74 | | ------- | ------ | --------- | 75 | | [Vulkan](https://www.vulkan.org/) | It is a Vulkan layer after all. | Must be installed manually on the system. | 76 | | [OpenSSL](https://www.openssl.org/) | Hashing data for easier identification. | Must be installed manually on the system. | 77 | | [SPIRV-Cross](https://github.com/KhronosGroup/SPIRV-Cross) | Automatic decompiling of shaders on extraction. | Submodule [``external/``](../external/)``SPIRV-Cross`` | 78 | | [glslang](https://github.com/KhronosGroup/glslang) | Automatic shader compilation for replacing. | Submodule [``external/``](../external/)``glslang`` | 79 | | [stb](https://github.com/nothings/stb) | Image loading and saving. | Submodule [``external/``](../external/)``stb`` | 80 | | [Vulkan-ValidationLayers](https://github.com/KhronosGroup/Vulkan-ValidationLayers) | We need one source file of it for determining the size of images. | Submodule [``external/``](../external/)``Vulkan-ValidationLayers`` | 81 | | [image_tools](../image_tools/) | Automatic (de)compression of images. | Part of *cheeky-imp* | 82 | | [Doxygen](https://www.doxygen.nl) | Generating documentation | Must be installed manually on the system (*optional*). | 83 | | [exprtk](http://www.partow.net/programming/exprtk/) | ``math`` data | Submodule [``external/``](../external/)``exprtk`` | 84 | 85 | ## Adding custom logic with Rules 86 | 87 | This Vulkan layer supports custom logic in the form of "rules". 88 | 89 | The rules are store in the ``ruleFile``; usually ``rules.txt``. 90 | -------------------------------------------------------------------------------- /bone_analyzer/src/edge_method.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | void dfs_util(int v, std::map>& adj, std::map& visited, std::vector& out) 16 | { 17 | visited[v] = true; 18 | out.push_back(v); 19 | 20 | for(int u : adj[v]) 21 | if(!visited[u]) 22 | dfs_util(u, adj, visited, out); 23 | } 24 | 25 | int main(int argc, char* argv[]) 26 | { 27 | std::string mesh_path = argv[1]; 28 | std::string bone_path = argv[2]; 29 | std::string result_path = argv[3]; 30 | 31 | std::ifstream obj(mesh_path); 32 | if(!obj) 33 | throw std::runtime_error("file not found: "+mesh_path); 34 | 35 | std::string line; 36 | std::vector vertices; 37 | std::vector> faces; 38 | while(std::getline(obj, line)) 39 | { 40 | std::istringstream is(line); 41 | std::string type; 42 | is >> type; 43 | if(type=="v") 44 | { 45 | float x, y, z; 46 | is >> x >> y >> z; 47 | vertices.push_back({x, y, z}); 48 | } 49 | if(type=="f") 50 | { 51 | std::array args; 52 | is >> args[0] >> args[1] >> args[2]; 53 | 54 | std::array array; 55 | for(int i=0; i<3; i++) 56 | { 57 | std::stringstream s(args[i]); 58 | int vertex, uv, normal; 59 | 60 | s >> vertex; 61 | s.ignore(1); 62 | s >> uv; 63 | s.ignore(1); 64 | s >> normal; 65 | 66 | array[i] = vertex-1; 67 | } 68 | faces.push_back(array); 69 | } 70 | } 71 | 72 | std::ifstream bones(bone_path); 73 | if(!bones) 74 | throw std::runtime_error("file not foind: "+bone_path); 75 | nlohmann::json json; 76 | bones >> json; 77 | std::map> groupVertexWeight = json; 78 | 79 | nlohmann::json result; 80 | 81 | for(auto it = groupVertexWeight.begin(); it != groupVertexWeight.end(); ++it) 82 | { 83 | std::vector> groupFaces; 84 | std::copy_if(faces.begin(), faces.end(), std::back_inserter(groupFaces), [&it](std::array face){ 85 | for(int i=0; i<3; i++) 86 | { 87 | std::string s = std::to_string(face[i]); 88 | if(!it->second.contains(s)) 89 | return false; 90 | if(it->second[s] < 0.25f) 91 | return false; 92 | } 93 | return true; 94 | }); 95 | for(auto& face : groupFaces) 96 | { 97 | for(int i=0; i<3; i++) 98 | { 99 | glm::vec3 v = vertices[face[i]]; 100 | int first = std::distance(vertices.begin(), std::find(vertices.begin(), vertices.end(), v)); 101 | face[i] = first; 102 | } 103 | } 104 | 105 | std::vector edgeLoopVertices; 106 | 107 | std::vector> edges; 108 | for(auto face : groupFaces) 109 | { 110 | edges.push_back({std::min(face[0], face[1]), std::max(face[0], face[1])}); 111 | edges.push_back({std::min(face[1], face[2]), std::max(face[1], face[2])}); 112 | edges.push_back({std::min(face[0], face[2]), std::max(face[0], face[2])}); 113 | } 114 | for(auto a : edges) 115 | { 116 | int count = std::count(edges.begin(), edges.end(), a); 117 | if(count == 1) 118 | { 119 | edgeLoopVertices.push_back(std::get<0>(a)); 120 | edgeLoopVertices.push_back(std::get<1>(a)); 121 | } 122 | } 123 | std::sort(edgeLoopVertices.begin(), edgeLoopVertices.end()); 124 | edgeLoopVertices.erase(std::unique(edgeLoopVertices.begin(), edgeLoopVertices.end()), edgeLoopVertices.end()); 125 | 126 | std::cout << "Group " << it->first << ": " << 127 | it->second.size() << " vertices and " << 128 | groupFaces.size() << " faces and " << 129 | edges.size() << " edges and " << 130 | edgeLoopVertices.size() << " edge loop vertices." << std::endl; 131 | 132 | if(it->first=="47") 133 | { 134 | std::ofstream o("test.obj"); 135 | for(int v : edgeLoopVertices) 136 | { 137 | glm::vec3 vec = vertices[v]; 138 | o << "v " << vec.x << " " << vec.y << " " << vec.z << std::endl; 139 | } 140 | } 141 | 142 | std::map> adj; 143 | for(int i : edgeLoopVertices) 144 | { 145 | for(int j : edgeLoopVertices) 146 | { 147 | for(auto f : groupFaces) 148 | { 149 | if(std::find(f.begin(), f.end(), i) != f.end() && 150 | std::find(f.begin(), f.end(), j) != f.end()) 151 | { 152 | adj[i].push_back(j); 153 | } 154 | } 155 | } 156 | } 157 | std::map visited; 158 | for(int v : edgeLoopVertices) 159 | visited[v] = false; 160 | 161 | std::vector> edgeLoops; 162 | for(int v : edgeLoopVertices) 163 | { 164 | if(!visited[v]) 165 | { 166 | std::vector out; 167 | dfs_util(v, adj, visited, out); 168 | edgeLoops.push_back(out); 169 | } 170 | } 171 | std::cout << "Found " << edgeLoops.size() << " edge loops." << std::endl; 172 | if(edgeLoops.size() == 2) 173 | { 174 | glm::vec3 head = {0, 0, 0}; 175 | for(int i : edgeLoops[0]) 176 | { 177 | head += vertices[i]; 178 | } 179 | head /= edgeLoops[0].size(); 180 | 181 | glm::vec3 tail = {0, 0, 0}; 182 | for(int i : edgeLoops[1]) 183 | { 184 | tail += vertices[i]; 185 | } 186 | tail /= edgeLoops[1].size(); 187 | 188 | result[it->first]["head"] = {head.x, head.y, head.z}; 189 | result[it->first]["tail"] = {tail.x, tail.y, tail.z}; 190 | } 191 | if(edgeLoops.size() == 1) 192 | { 193 | glm::vec3 head = {0, 0, 0}; 194 | for(int i : edgeLoops[0]) 195 | { 196 | head += vertices[i]; 197 | } 198 | head /= edgeLoops[0].size(); 199 | 200 | glm::vec3 tail = {}; 201 | float maxDist = std::numeric_limits::min(); 202 | for(auto jt = it->second.begin(); jt != it->second.end(); ++jt) 203 | { 204 | int i = std::stoi(jt->first); 205 | glm::vec3 v = vertices[i]; 206 | float dist = glm::distance(head, v); 207 | if(dist > maxDist) 208 | { 209 | maxDist = dist; 210 | tail = v; 211 | } 212 | } 213 | 214 | result[it->first]["head"] = {head.x, head.y, head.z}; 215 | result[it->first]["tail"] = {tail.x, tail.y, tail.z}; 216 | } 217 | } 218 | 219 | { 220 | std::ofstream out(result_path); 221 | out << result; 222 | } 223 | 224 | return 0; 225 | } 226 | -------------------------------------------------------------------------------- /mesh_buffer_tools/src/extract/extract.cpp: -------------------------------------------------------------------------------- 1 | #include "buffer.hpp" 2 | #include "input_assembly.hpp" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | #include 21 | 22 | typedef std::vector vertex; 23 | 24 | int main(int argc, char *argv[]) 25 | { 26 | assert(argc > 7); 27 | std::string object_name = argv[1]; 28 | std::string descriptor_path = argv[2]; 29 | std::string output_path = argv[3]; 30 | 31 | int index_count = std::atoi(argv[4]); 32 | std::string index_offsets = argv[5]; 33 | std::map parts = {{0, object_name}}; 34 | if(index_offsets.find('(') != std::string::npos) 35 | { 36 | int start = index_offsets.find('('); 37 | int end = index_offsets.find(')'); 38 | 39 | std::string part_offsets = index_offsets.substr(start+1, end-start-1); 40 | std::istringstream iss(part_offsets); 41 | 42 | std::string part; 43 | while(std::getline(iss, part, ',')) 44 | { 45 | int sep = part.find('='); 46 | std::string name = part.substr(0, sep); 47 | unsigned long offset = std::stoul(part.substr(sep+1)); 48 | 49 | parts[offset] = name; 50 | } 51 | 52 | index_offsets = index_offsets.substr(0, start); 53 | } 54 | int first_index = std::stoi(index_offsets); 55 | int vertex_offset = std::atoi(argv[6]); 56 | 57 | std::string index_path = argv[7]; 58 | 59 | std::vector attributes; 60 | std::vector attributeBindings; 61 | 62 | std::ifstream descriptor(descriptor_path); 63 | std::string line; 64 | while(std::getline(descriptor, line)) 65 | { 66 | std::istringstream is(line); 67 | 68 | mbt::input_attribute a; 69 | is >> a; 70 | attributes.push_back(a); 71 | 72 | attributeBindings.push_back(a.binding); 73 | } 74 | 75 | std::map mappings; 76 | for(int i=0; i> buffers(bindingCount); 92 | for(int i=0; i(f, std::atoi(argv[8 + 2*i + 1]), boost::interprocess::mode_t::read_only); 101 | } 102 | 103 | int vertexCount = buffers[0]->count(); 104 | std::vector vertices(vertexCount); 105 | 106 | for(int i=0; iat(i); 116 | 117 | vertices[i][j] = attr.read(p); 118 | } 119 | } 120 | 121 | mbt::buffer index_buffer(index_path, 2, boost::interprocess::mode_t::read_only); 122 | unsigned short* indices = index_buffer; 123 | 124 | std::ofstream out(output_path); 125 | std::map vertexPositions; 126 | 127 | std::optional map_position; 128 | std::optional map_normal; 129 | std::optional map_texCoord; 130 | if(mappings.contains("position")) map_position = mappings["position"]; 131 | if(mappings.contains("normal")) map_normal = mappings["normal"]; 132 | if(mappings.contains("texCoord")) map_texCoord = mappings["texCoord"]; 133 | 134 | int face[3]; 135 | int counter = 0; 136 | out << "o " << object_name << std::endl; 137 | for(int i=0; i> adjusted_groups; 184 | for(int i=0; i 0.0) 196 | { 197 | std::string group = std::to_string(groups[j]); 198 | std::string index = std::to_string(vertexPositions[i]); 199 | adjusted_groups[group][index] = weights[j]; 200 | } 201 | } 202 | } 203 | nlohmann::json j = adjusted_groups; 204 | std::ofstream outJson(output_path+".json"); 205 | outJson << j; 206 | } 207 | 208 | return 0; 209 | } 210 | -------------------------------------------------------------------------------- /image_tools/src/lib/decompress.cpp: -------------------------------------------------------------------------------- 1 | #include "block_compression.hpp" 2 | #include "image.hpp" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | namespace image_tools 14 | { 15 | void readColorBlock(const uint8_t* in, float out[4][4]) 16 | { 17 | float colors[8]; 18 | float c0 = in[0]/255.0f; 19 | float c1 = in[1]/255.0f; 20 | 21 | colors[0] = c0; 22 | colors[1] = c1; 23 | 24 | if(c0 > c1) 25 | { 26 | colors[2] = (6.0f * c0 + 1.0f * c1) / 7.0f; 27 | colors[3] = (5.0f * c0 + 2.0f * c1) / 7.0f; 28 | colors[4] = (4.0f * c0 + 3.0f * c1) / 7.0f; 29 | colors[5] = (3.0f * c0 + 4.0f * c1) / 7.0f; 30 | colors[6] = (2.0f * c0 + 5.0f * c1) / 7.0f; 31 | colors[7] = (1.0f * c0 + 6.0f * c1) / 7.0f; 32 | } 33 | else 34 | { 35 | colors[2] = (4.0f * c0 + 1.0f * c1) / 5.0f; 36 | colors[3] = (3.0f * c0 + 2.0f * c1) / 5.0f; 37 | colors[4] = (2.0f * c0 + 3.0f * c1) / 5.0f; 38 | colors[5] = (1.0f * c0 + 4.0f * c1) / 5.0f; 39 | colors[6] = 0.0f; 40 | colors[7] = 1.0f; 41 | } 42 | 43 | uint32_t lookup[2] = { 44 | static_cast(in[4] << 16 | in[3] << 8 | in[2]), 45 | static_cast(in[7] << 16 | in[6] << 8 | in[5]), 46 | }; 47 | for(int i=0; i<16; i++) 48 | { 49 | unsigned int index = (lookup[i/8] >> (3*(i%8))) & 0b111; 50 | 51 | int x = i % 4; 52 | int y = i / 4; 53 | out[x][y] = colors[index]; 54 | } 55 | } 56 | 57 | glm::vec3 color(unsigned short s) 58 | { 59 | float r = ((s>>11)&0b011111)/(31.0f); 60 | float g = ((s>>5)&0b111111)/(63.0f); 61 | float b = ((s)&0b011111)/(31.0f); 62 | 63 | return {r, g, b}; 64 | } 65 | 66 | void decompressBC13(const uint8_t* in, image& out, int w, int h, bool bc3) 67 | { 68 | const uint8_t* buf = in; 69 | for(int y=0; y c1) 92 | { 93 | v2 = (2.0f/3.0f) * v0 + (1.0f/3.0f) * v1; 94 | v3 = (1.0f/3.0f) * v0 + (2.0f/3.0f) * v1; 95 | } 96 | else 97 | { 98 | v2 = (1.0f/2.0f) * v0 + (1.0f/2.0f) * v1; 99 | v3 = glm::vec3(0.0f, 0.0f, 0.0f); 100 | } 101 | glm::vec3 colors[] = {v0, v1, v2, v3}; 102 | 103 | const uint8_t* lookup = buf; buf+=4; 104 | for(int yy=0; yy<4; yy++) 105 | { 106 | uint8_t row = lookup[yy]; 107 | for(int xx=0; xx<4; xx++) 108 | { 109 | int index = (row >> (2*xx)) & 0b11; 110 | out.at(x+xx, y+yy) = color(glm::vec4(colors[index], alpha[xx][yy])); 111 | } 112 | } 113 | } 114 | } 115 | } 116 | 117 | void decompressBC1(const uint8_t* in, image& out, int w, int h) 118 | { 119 | decompressBC13(in, out, w, h, false); 120 | } 121 | 122 | void decompressBC2(const uint8_t *in, image &out, int w, int h) 123 | { 124 | const uint8_t* buf = in; 125 | for(int y=0; y c1) 142 | { 143 | v2 = (2.0f/3.0f) * v0 + (1.0f/3.0f) * v1; 144 | v3 = (1.0f/3.0f) * v0 + (2.0f/3.0f) * v1; 145 | } 146 | else 147 | { 148 | v2 = (1.0f/2.0f) * v0 + (1.0f/2.0f) * v1; 149 | v3 = glm::vec3(0.0f, 0.0f, 0.0f); 150 | } 151 | glm::vec3 colors[] = {v0, v1, v2, v3}; 152 | 153 | const uint8_t* lookup = buf; buf+=4; 154 | for(int yy=0; yy<4; yy++) 155 | { 156 | uint8_t row = lookup[yy]; 157 | for(int xx=0; xx<4; xx++) 158 | { 159 | int index = (row >> (2*xx)) & 0b11; 160 | out.at(x+xx, y+yy) = color(glm::vec4(colors[index], alpha[xx][yy])); 161 | } 162 | } 163 | } 164 | } 165 | } 166 | 167 | void decompressBC3(const uint8_t* in, image& out, int w, int h) 168 | { 169 | decompressBC13(in, out, w, h, true); 170 | } 171 | 172 | void decompressBC4(const uint8_t *in, image &out, int w, int h) 173 | { 174 | const uint8_t* buf = in; 175 | for(int y=0; y 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | template 11 | void* GetKey(DispatchableType inst) 12 | { 13 | return *(void**) inst; 14 | } 15 | 16 | extern std::map instance_dispatch; 17 | extern std::map device_dispatch; 18 | 19 | inline bool layer_disabled = false; 20 | inline bool hook_draw_calls = false; 21 | 22 | void InitInstanceDispatchTable(VkInstance instance, PFN_vkGetInstanceProcAddr gpa, VkuInstanceDispatchTable& dispatchTable); 23 | void InitDeviceDispatchTable(VkDevice device, PFN_vkGetDeviceProcAddr gdpa, VkuDeviceDispatchTable& dispatchTable); 24 | 25 | #define InstanceHook(func) \ 26 | (void)((VkuInstanceDispatchTable*)0)->func; \ 27 | if(!strcmp(pName, "vk" #func)) return (PFN_vkVoidFunction)&CheekyLayer_##func; 28 | #define DeviceHook(func) \ 29 | (void)((VkuDeviceDispatchTable*)0)->func; \ 30 | if(!strcmp(pName, "vk" #func)) return (PFN_vkVoidFunction)&CheekyLayer_##func; 31 | 32 | #define InstanceHooks() \ 33 | InstanceHook(GetInstanceProcAddr) \ 34 | InstanceHook(EnumerateInstanceLayerProperties) \ 35 | InstanceHook(EnumerateInstanceExtensionProperties) \ 36 | InstanceHook(CreateInstance) \ 37 | InstanceHook(DestroyInstance) \ 38 | InstanceHook(EnumerateDeviceLayerProperties) \ 39 | InstanceHook(EnumerateDeviceExtensionProperties) \ 40 | InstanceHook(CreateDevice) \ 41 | InstanceHook(EnumeratePhysicalDevices) \ 42 | InstanceHook(GetPhysicalDeviceQueueFamilyProperties) \ 43 | InstanceHook(GetPhysicalDeviceQueueFamilyProperties2) 44 | 45 | #define DeviceHooks() \ 46 | DeviceHook(GetDeviceProcAddr) \ 47 | DeviceHook(DestroyDevice) \ 48 | \ 49 | DeviceHook(GetDeviceQueue) \ 50 | \ 51 | DeviceHook(CreateImage) \ 52 | DeviceHook(BindImageMemory) \ 53 | DeviceHook(CreateImageView) \ 54 | \ 55 | DeviceHook(CreateBuffer) \ 56 | DeviceHook(BindBufferMemory) \ 57 | DeviceHook(AllocateMemory) \ 58 | DeviceHook(MapMemory) \ 59 | DeviceHook(UnmapMemory) \ 60 | \ 61 | DeviceHook(CmdCopyBufferToImage) \ 62 | DeviceHook(CmdCopyBufferToImage2) \ 63 | /*DeviceHook(CmdCopyBuffer)*/ \ 64 | \ 65 | DeviceHook(CreateShaderModule) \ 66 | DeviceHook(CreateGraphicsPipelines) \ 67 | DeviceHook(CreatePipelineLayout) \ 68 | \ 69 | DeviceHook(CreateFramebuffer) \ 70 | DeviceHook(CreateSwapchainKHR) \ 71 | DeviceHook(GetSwapchainImagesKHR) \ 72 | DeviceHook(QueuePresentKHR) \ 73 | \ 74 | DeviceHook(CmdBindDescriptorSets) \ 75 | DeviceHook(CmdBindPipeline) \ 76 | DeviceHook(CmdBindVertexBuffers) \ 77 | DeviceHook(CmdBindVertexBuffers2EXT) \ 78 | DeviceHook(CmdBindIndexBuffer) \ 79 | DeviceHook(CmdSetScissor) \ 80 | DeviceHook(CmdBeginRenderPass) \ 81 | DeviceHook(CmdEndRenderPass) \ 82 | DeviceHook(CmdDraw) \ 83 | DeviceHook(CmdDrawIndexed) \ 84 | DeviceHook(CmdBeginTransformFeedbackEXT) \ 85 | DeviceHook(CmdBindTransformFeedbackBuffersEXT) \ 86 | DeviceHook(CmdEndTransformFeedbackEXT) \ 87 | \ 88 | DeviceHook(CreateDescriptorUpdateTemplate) \ 89 | DeviceHook(UpdateDescriptorSetWithTemplate) \ 90 | \ 91 | DeviceHook(AllocateCommandBuffers) \ 92 | DeviceHook(FreeCommandBuffers) \ 93 | DeviceHook(EndCommandBuffer) \ 94 | DeviceHook(QueueSubmit) \ 95 | 96 | #define InstanceDispatch(name) \ 97 | dispatchTable.name = (PFN_vk##name)gpa(instance, "vk"#name); 98 | #define DeviceDispatch(name) \ 99 | dispatchTable.name = (PFN_vk##name)gdpa(device, "vk"#name); 100 | 101 | #define InitInstanceDispatch() \ 102 | InstanceDispatch(GetInstanceProcAddr) \ 103 | InstanceDispatch(DestroyInstance) \ 104 | InstanceDispatch(EnumerateDeviceExtensionProperties) \ 105 | InstanceDispatch(GetPhysicalDeviceMemoryProperties) \ 106 | InstanceDispatch(GetPhysicalDeviceProperties) \ 107 | InstanceDispatch(GetPhysicalDeviceQueueFamilyProperties) \ 108 | InstanceDispatch(GetPhysicalDeviceQueueFamilyProperties2) \ 109 | InstanceDispatch(EnumeratePhysicalDevices) \ 110 | \ 111 | InstanceDispatch(DestroySurfaceKHR) \ 112 | InstanceDispatch(GetPhysicalDeviceSurfaceCapabilitiesKHR) \ 113 | InstanceDispatch(GetPhysicalDeviceSurfaceFormatsKHR) \ 114 | InstanceDispatch(GetPhysicalDeviceSurfacePresentModesKHR) 115 | 116 | #define InitDeviceDispatch() \ 117 | DeviceDispatch(GetDeviceProcAddr) \ 118 | DeviceDispatch(DestroyDevice) \ 119 | DeviceDispatch(SetDebugUtilsObjectNameEXT) \ 120 | \ 121 | DeviceDispatch(GetDeviceQueue) \ 122 | DeviceDispatch(CreateCommandPool) \ 123 | DeviceDispatch(DestroyCommandPool) \ 124 | DeviceDispatch(QueueSubmit) \ 125 | DeviceDispatch(QueueWaitIdle) \ 126 | \ 127 | DeviceDispatch(CreateShaderModule) \ 128 | \ 129 | DeviceDispatch(CreateImage) \ 130 | DeviceDispatch(GetImageMemoryRequirements) \ 131 | DeviceDispatch(BindImageMemory) \ 132 | DeviceDispatch(CreateImageView) \ 133 | DeviceDispatch(CreateSampler) \ 134 | \ 135 | DeviceDispatch(CreateBuffer) \ 136 | DeviceDispatch(DestroyBuffer) \ 137 | DeviceDispatch(GetBufferMemoryRequirements) \ 138 | DeviceDispatch(BindBufferMemory) \ 139 | DeviceDispatch(AllocateMemory) \ 140 | DeviceDispatch(FreeMemory) \ 141 | DeviceDispatch(MapMemory) \ 142 | DeviceDispatch(UnmapMemory) \ 143 | DeviceDispatch(FlushMappedMemoryRanges) \ 144 | \ 145 | DeviceDispatch(CreateShaderModule) \ 146 | DeviceDispatch(CreateGraphicsPipelines) \ 147 | DeviceDispatch(CreatePipelineLayout) \ 148 | DeviceDispatch(CreateRenderPass) \ 149 | \ 150 | DeviceDispatch(CreateDescriptorSetLayout) \ 151 | DeviceDispatch(CreateDescriptorPool) \ 152 | DeviceDispatch(AllocateDescriptorSets) \ 153 | \ 154 | DeviceDispatch(CmdCopyBufferToImage) \ 155 | DeviceDispatch(CmdCopyBufferToImage2) \ 156 | DeviceDispatch(CmdCopyBuffer) \ 157 | DeviceDispatch(CmdBindDescriptorSets) \ 158 | DeviceDispatch(CmdBindPipeline) \ 159 | DeviceDispatch(CmdBindVertexBuffers) \ 160 | DeviceDispatch(CmdBindVertexBuffers2EXT) \ 161 | DeviceDispatch(CmdBindIndexBuffer) \ 162 | DeviceDispatch(CmdSetScissor) \ 163 | DeviceDispatch(CmdDrawIndexed) \ 164 | DeviceDispatch(CmdDraw) \ 165 | DeviceDispatch(CmdPipelineBarrier) \ 166 | DeviceDispatch(CmdBeginRenderPass) \ 167 | DeviceDispatch(CmdEndRenderPass) \ 168 | DeviceDispatch(CmdBeginTransformFeedbackEXT) \ 169 | DeviceDispatch(CmdBindTransformFeedbackBuffersEXT) \ 170 | DeviceDispatch(CmdEndTransformFeedbackEXT) \ 171 | DeviceDispatch(CmdPushConstants) \ 172 | \ 173 | DeviceDispatch(CreateDescriptorUpdateTemplate) \ 174 | DeviceDispatch(UpdateDescriptorSetWithTemplate) \ 175 | DeviceDispatch(UpdateDescriptorSets) \ 176 | \ 177 | DeviceDispatch(AllocateCommandBuffers) \ 178 | DeviceDispatch(FreeCommandBuffers) \ 179 | DeviceDispatch(ResetCommandBuffer) \ 180 | DeviceDispatch(BeginCommandBuffer) \ 181 | DeviceDispatch(EndCommandBuffer) \ 182 | \ 183 | DeviceDispatch(CreateSwapchainKHR) \ 184 | DeviceDispatch(QueuePresentKHR) \ 185 | DeviceDispatch(GetSwapchainImagesKHR) \ 186 | DeviceDispatch(CreateSemaphore) \ 187 | \ 188 | DeviceDispatch(CreateFramebuffer) \ 189 | DeviceDispatch(CreateEvent) \ 190 | DeviceDispatch(DestroyEvent) \ 191 | DeviceDispatch(CmdSetEvent) \ 192 | DeviceDispatch(GetEventStatus) \ 193 | DeviceDispatch(CmdCopyImageToBuffer) \ 194 | \ 195 | DeviceDispatch(CreateFence) \ 196 | DeviceDispatch(ResetFences) \ 197 | DeviceDispatch(WaitForFences) 198 | -------------------------------------------------------------------------------- /image_tools/src/lib/compress.cpp: -------------------------------------------------------------------------------- 1 | #include "block_compression.hpp" 2 | #include "image.hpp" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace image_tools 13 | { 14 | unsigned short shortcolor(glm::vec4 rgba) 15 | { 16 | int r = (int)(rgba.r*31.0f) & 31; 17 | int g = (int)(rgba.g*63.0f) & 63; 18 | int b = (int)(rgba.b*31.0f) & 31; 19 | 20 | return (r<<11 | g<<5 | b); 21 | } 22 | 23 | void writeColorBlock(const std::array& in, uint8_t* out) 24 | { 25 | auto [minp, maxp] = std::minmax_element(in.begin(), in.end()); 26 | float min = *minp; 27 | float max = *maxp; 28 | 29 | if(max == min) 30 | { 31 | if(max == 0.0) 32 | max = 0.1; 33 | else 34 | min *= 0.75; 35 | } 36 | 37 | out[0] = max*255.0f; 38 | out[1] = min*255.0f; 39 | 40 | std::array palette = { 41 | max, 42 | min, 43 | (6*max + 1*min)/7, 44 | (5*max + 2*min)/7, 45 | (4*max + 3*min)/7, 46 | (3*max + 4*min)/7, 47 | (2*max + 5*min)/7, 48 | (1*max + 6*min)/7 49 | }; 50 | 51 | uint8_t* lookup = out + 2; 52 | for(int row=0; row<2; row++) 53 | { 54 | uint32_t b = 0; 55 | for(int col=0; col<8; col++) 56 | { 57 | int x = (col%4); 58 | int y = (2*row + col/4); 59 | 60 | float val = in[4*y + x]; 61 | int index = std::distance(palette.begin(), std::min_element(palette.begin(), palette.end(), [val](float a, float b){ 62 | return std::abs(a-val) < std::abs(b-val); 63 | })); 64 | 65 | b |= index << (3*col); 66 | } 67 | lookup[3*row + 2] = (b >> (0*8)) & 0xff; 68 | lookup[3*row + 1] = (b >> (1*8)) & 0xff; 69 | lookup[3*row + 0] = (b >> (3*8)) & 0xff; 70 | } 71 | } 72 | 73 | void compressBC13(const image& in, std::vector& out, int w, int h, bool bc3) 74 | { 75 | out.resize(w * h / (bc3?1:2)); 76 | std::fill(out.begin(), out.end(), 0x00); 77 | 78 | uint8_t* buf = out.data(); 79 | 80 | for(int y=0; y colors; 85 | for(int xx=0; xx<4; xx++) 86 | for(int yy=0; yy<4; yy++) 87 | colors[4*yy+xx] = in.scaled(x+xx, y+yy, w, h); 88 | 89 | if(bc3) 90 | { 91 | std::array alpha; 92 | std::transform(colors.begin(), colors.end(), alpha.begin(), [](glm::vec4 color){ 93 | return color.w; 94 | }); 95 | writeColorBlock(alpha, buf); 96 | buf += 8; 97 | } 98 | 99 | auto [minp, maxp] = std::minmax_element(colors.begin(), colors.end(), [](glm::vec4 a, glm::vec4 b){ 100 | return shortcolor(a) < shortcolor(b); 101 | }); 102 | glm::vec4 max = *maxp; 103 | glm::vec4 min = *minp; 104 | 105 | if(shortcolor(min) == shortcolor(max)) 106 | { 107 | if(glm::length(glm::vec3(max)) < 0.1) 108 | max += glm::vec4(0.25, 0.25, 0.25, 0.0); 109 | else 110 | min *= glm::vec4(0.5, 0.5, 0.5, 1.0); 111 | } 112 | 113 | if(shortcolor(max) <= shortcolor(min)) 114 | std::cout << shortcolor(max) << " " << glm::to_string(max) << " > " << shortcolor(min) << " " << glm::to_string(min) << std::endl; 115 | 116 | ((uint16_t*)buf)[0] = shortcolor(max); 117 | ((uint16_t*)buf)[1] = shortcolor(min); 118 | buf += 2*sizeof(uint16_t); 119 | 120 | glm::vec3 v0 = max; 121 | glm::vec3 v1 = min; 122 | glm::vec3 v2 = (2.0f/3.0f) * v0 + (1.0f/3.0f) * v1; 123 | glm::vec3 v3 = (1.0f/3.0f) * v0 + (2.0f/3.0f) * v1; 124 | std::array palette = {v0, v1, v2, v3}; 125 | 126 | for(int yy=0; yy<4; yy++) 127 | { 128 | unsigned char b = 0; 129 | for(int xx=0; xx<4; xx++) 130 | { 131 | glm::vec3 trueColor = colors[yy*4+xx]; 132 | auto index = std::distance(palette.begin(), std::min_element(palette.begin(), palette.end(), [trueColor](glm::vec3 a, glm::vec3 b){ 133 | float da = glm::distance(a, trueColor); 134 | float db = glm::distance(b, trueColor); 135 | return da < db; 136 | })); 137 | b |= index << xx*2; 138 | } 139 | buf[yy] = b; 140 | } 141 | buf+=4; 142 | } 143 | } 144 | } 145 | 146 | void compressBC1(const image& in, std::vector& out, int w, int h) 147 | { 148 | compressBC13(in, out, w, h, false); 149 | } 150 | 151 | void compressBC3(const image& in, std::vector& out, int w, int h) 152 | { 153 | compressBC13(in, out, w, h, true); 154 | } 155 | 156 | void compressBC4(const image &in, std::vector &out, int w, int h) 157 | { 158 | out.resize(w * h * 0.5); 159 | std::fill(out.begin(), out.end(), 0x00); 160 | 161 | uint8_t* buf = out.data(); 162 | for(int y=0; y colors; 167 | for(int xx=0; xx<4; xx++) 168 | for(int yy=0; yy<4; yy++) 169 | colors[4*yy+xx] = in.scaled(x+xx, y+yy, w, h); 170 | 171 | std::array red; 172 | std::transform(colors.begin(), colors.end(), red.begin(), [](glm::vec4 color){ 173 | return color.r; 174 | }); 175 | writeColorBlock(red, buf); 176 | buf += 8; 177 | } 178 | } 179 | } 180 | 181 | void compressBC5(const image &in, std::vector &out, int w, int h) 182 | { 183 | out.resize(w * h); 184 | std::fill(out.begin(), out.end(), 0x00); 185 | 186 | uint8_t* buf = out.data(); 187 | for(int y=0; y colors; 192 | for(int xx=0; xx<4; xx++) 193 | for(int yy=0; yy<4; yy++) 194 | colors[4*yy+xx] = in.scaled(x+xx, y+yy, w, h); 195 | 196 | std::array red; 197 | std::transform(colors.begin(), colors.end(), red.begin(), [](glm::vec4 color){ 198 | return color.r; 199 | }); 200 | writeColorBlock(red, buf); 201 | buf += 8; 202 | 203 | std::array green; 204 | std::transform(colors.begin(), colors.end(), green.begin(), [](glm::vec4 color){ 205 | return color.g; 206 | }); 207 | writeColorBlock(green, buf); 208 | buf += 8; 209 | } 210 | } 211 | } 212 | 213 | static bool bc7_init = false; 214 | void compressBC7(const image &in, std::vector &out, int w, int h) 215 | { 216 | out.resize(w * h); 217 | std::fill(out.begin(), out.end(), 0x00); 218 | 219 | if(!bc7_init) 220 | { 221 | bc7enc16_compress_block_init(); 222 | bc7_init = true; 223 | } 224 | 225 | bc7enc16_compress_block_params params; 226 | bc7enc16_compress_block_params_init(¶ms); 227 | bc7enc16_compress_block_params_init_perceptual_weights(¶ms); 228 | 229 | for(int y=0; y 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #undef VK_LAYER_EXPORT 11 | #if defined(WIN32) 12 | #define VK_LAYER_EXPORT extern "C" __declspec(dllexport) 13 | #else 14 | #define VK_LAYER_EXPORT extern "C" 15 | #endif 16 | 17 | extern std::mutex global_lock; 18 | extern std::mutex transfer_lock; 19 | using scoped_lock = std::scoped_lock; 20 | 21 | // layer.cpp 22 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_CreateInstance(const VkInstanceCreateInfo*, const VkAllocationCallbacks*, VkInstance*); 23 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_DestroyInstance(VkInstance, const VkAllocationCallbacks*); 24 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_CreateDevice(VkPhysicalDevice, const VkDeviceCreateInfo*, const VkAllocationCallbacks*, VkDevice*); 25 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_GetDeviceQueue(VkDevice, uint32_t, uint32_t, VkQueue*); 26 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_DestroyDevice(VkDevice, const VkAllocationCallbacks*); 27 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_EnumerateInstanceLayerProperties(uint32_t*, VkLayerProperties*); 28 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_EnumerateDeviceLayerProperties(VkPhysicalDevice, uint32_t*, VkLayerProperties*); 29 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_EnumerateInstanceExtensionProperties(const char*, uint32_t*, VkExtensionProperties*); 30 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_EnumerateDeviceExtensionProperties(VkPhysicalDevice, const char*, uint32_t*, VkExtensionProperties*); 31 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_EnumeratePhysicalDevices(VkInstance, uint32_t*, VkPhysicalDevice*); 32 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice, uint32_t*, VkQueueFamilyProperties*); 33 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice, uint32_t*, VkQueueFamilyProperties2*); 34 | 35 | // dispatch.cpp 36 | VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL CheekyLayer_GetDeviceProcAddr(VkDevice, const char*); 37 | VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI_CALL CheekyLayer_GetInstanceProcAddr(VkInstance, const char*); 38 | 39 | // images.cpp 40 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_CreateImage(VkDevice, const VkImageCreateInfo*, const VkAllocationCallbacks*, VkImage*); 41 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_BindImageMemory(VkDevice, VkImage, VkDeviceMemory, VkDeviceSize); 42 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_CreateImageView(VkDevice, const VkImageViewCreateInfo*, const VkAllocationCallbacks*, VkImageView*); 43 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_CmdCopyBufferToImage(VkCommandBuffer, VkBuffer, VkImage, VkImageLayout, uint32_t, const VkBufferImageCopy*); 44 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_CmdCopyBufferToImage2(VkCommandBuffer, const VkCopyBufferToImageInfo2*); 45 | 46 | // buffers.cpp 47 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_CreateBuffer(VkDevice, const VkBufferCreateInfo*, const VkAllocationCallbacks*, VkBuffer*); 48 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_BindBufferMemory(VkDevice, VkBuffer, VkDeviceMemory, VkDeviceSize); 49 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_AllocateMemory(VkDevice, const VkMemoryAllocateInfo*, const VkAllocationCallbacks*, VkDeviceMemory*); 50 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_MapMemory(VkDevice, VkDeviceMemory, VkDeviceSize, VkDeviceSize, VkMemoryMapFlags, void**); 51 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_UnmapMemory(VkDevice, VkDeviceMemory); 52 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_CmdCopyBuffer(VkCommandBuffer, VkBuffer, VkBuffer, uint32_t, const VkBufferCopy*); 53 | 54 | // shaders.cpp 55 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_CreateShaderModule(VkDevice, const VkShaderModuleCreateInfo*, VkAllocationCallbacks*, VkShaderModule*); 56 | 57 | // descriptors.cpp 58 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_CreateDescriptorUpdateTemplate(VkDevice, const VkDescriptorUpdateTemplateCreateInfo*, const VkAllocationCallbacks*, VkDescriptorUpdateTemplate*); 59 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_UpdateDescriptorSetWithTemplate(VkDevice, VkDescriptorSet, VkDescriptorUpdateTemplate, const void*); 60 | 61 | // draw.cpp 62 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_AllocateCommandBuffers(VkDevice, const VkCommandBufferAllocateInfo*, VkCommandBuffer*); 63 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_FreeCommandBuffers(VkDevice, VkCommandPool, uint32_t, const VkCommandBuffer*); 64 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_CreateFramebuffer(VkDevice, const VkFramebufferCreateInfo*, const VkAllocationCallbacks*, VkFramebuffer*); 65 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_CreatePipelineLayout(VkDevice, const VkPipelineLayoutCreateInfo*, const VkAllocationCallbacks*, VkPipelineLayout*); 66 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_CreateGraphicsPipelines(VkDevice, VkPipelineCache, uint32_t, const VkGraphicsPipelineCreateInfo*, const VkAllocationCallbacks*, VkPipeline*); 67 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_CmdBindDescriptorSets(VkCommandBuffer, VkPipelineBindPoint, VkPipelineLayout, uint32_t, uint32_t, const VkDescriptorSet*, uint32_t, const uint32_t*); 68 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_CmdBindPipeline(VkCommandBuffer, VkPipelineBindPoint, VkPipeline); 69 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_CmdBindVertexBuffers(VkCommandBuffer, uint32_t, uint32_t, const VkBuffer*, const VkDeviceSize*); 70 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_CmdBindVertexBuffers2EXT(VkCommandBuffer, uint32_t, uint32_t, const VkBuffer*, const VkDeviceSize*, const VkDeviceSize*, const VkDeviceSize*); 71 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_CmdBindIndexBuffer(VkCommandBuffer, VkBuffer, VkDeviceSize, VkIndexType); 72 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_CmdSetScissor(VkCommandBuffer, uint32_t, uint32_t, const VkRect2D*); 73 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_CmdBeginRenderPass(VkCommandBuffer, const VkRenderPassBeginInfo*, VkSubpassContents); 74 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_CmdEndRenderPass(VkCommandBuffer); 75 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_CmdDrawIndexed(VkCommandBuffer, uint32_t, uint32_t, uint32_t, int32_t, uint32_t); 76 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_CmdDraw(VkCommandBuffer, uint32_t, uint32_t, uint32_t, uint32_t); 77 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_CmdBeginTransformFeedbackEXT(VkCommandBuffer, uint32_t, uint32_t, const VkBuffer*, const VkDeviceSize*); 78 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_CmdBindTransformFeedbackBuffersEXT(VkCommandBuffer, uint32_t, uint32_t, const VkBuffer*, const VkDeviceSize*, const VkDeviceSize*); 79 | VK_LAYER_EXPORT void VKAPI_CALL CheekyLayer_CmdEndTransformFeedbackEXT(VkCommandBuffer, uint32_t, uint32_t, const VkBuffer*, const VkDeviceSize*); 80 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_EndCommandBuffer(VkCommandBuffer); 81 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_CreateSwapchainKHR(VkDevice, const VkSwapchainCreateInfoKHR*, const VkAllocationCallbacks*, VkSwapchainKHR*); 82 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_GetSwapchainImagesKHR(VkDevice, VkSwapchainKHR, uint32_t*, VkImage*); 83 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_QueuePresentKHR(VkQueue, const VkPresentInfoKHR*); 84 | VK_LAYER_EXPORT VkResult VKAPI_CALL CheekyLayer_QueueSubmit(VkQueue, uint32_t, const VkSubmitInfo*, VkFence); 85 | -------------------------------------------------------------------------------- /vulkan_layer/src/rules/rules.cpp: -------------------------------------------------------------------------------- 1 | #include "rules/rules.hpp" 2 | #include "rules/execution_env.hpp" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace CheekyLayer::rules 11 | { 12 | condition_factory::map_type* condition_factory::map = nullptr; 13 | action_factory::map_type* action_factory::map = nullptr; 14 | data_factory::map_type* data_factory::map = nullptr; 15 | 16 | void skip_ws(std::istream& in) 17 | { 18 | while(std::isspace(in.peek())) 19 | (void)in.get(); 20 | } 21 | 22 | void check_stream(std::istream &in, char expected) 23 | { 24 | skip_ws(in); 25 | int c = in.get(); 26 | if(c != expected) 27 | throw std::runtime_error("expected '"+std::string(1, expected)+"' but got '"+std::string(1, static_cast(c))+"' ("+std::to_string(c)+") instead"); 28 | } 29 | 30 | std::unique_ptr read_action(std::istream& in, selector_type type) 31 | { 32 | std::string actionType; 33 | if(!std::getline(in, actionType, '(')) 34 | throw std::runtime_error("cannot read action type"); 35 | skip_ws(in); 36 | std::unique_ptr cptr = action_factory::make_unique_action(actionType, type); 37 | cptr->read(in); 38 | return cptr; 39 | } 40 | 41 | std::istream& operator>>(std::istream& in, rule& rule) 42 | { 43 | skip_ws(in); 44 | rule.m_selector = std::make_unique(); 45 | in >> *rule.m_selector; 46 | skip_ws(in); 47 | 48 | std::string arrow; 49 | in >> arrow; 50 | if(arrow != "->") 51 | throw std::runtime_error("expected '->', but got '"+arrow+"' instead"); 52 | skip_ws(in); 53 | 54 | rule.m_action = read_action(in, rule.m_selector->m_type); 55 | 56 | skip_ws(in); 57 | /*if(in.good()) 58 | throw std::runtime_error("found characters after end of rule");*/ 59 | 60 | return in; 61 | } 62 | 63 | std::unique_ptr read_condition(std::istream& in, selector_type type) 64 | { 65 | std::string conditionType; 66 | if(!std::getline(in, conditionType, '(')) 67 | throw std::runtime_error("cannot read condition type"); 68 | skip_ws(in); 69 | std::unique_ptr cptr = condition_factory::make_unique_condition(conditionType, type); 70 | cptr->read(in); 71 | return cptr; 72 | } 73 | 74 | std::unique_ptr read_data(std::istream& in, selector_type type) 75 | { 76 | std::string dataType; 77 | if(!std::getline(in, dataType, '(')) 78 | throw std::runtime_error("cannot read data type"); 79 | skip_ws(in); 80 | std::unique_ptr cptr = data_factory::make_unique_data(dataType, type); 81 | cptr->read(in); 82 | return cptr; 83 | } 84 | 85 | std::istream& operator>>(std::istream& in, selector& selector) 86 | { 87 | std::string type; 88 | std::getline(in, type, '{'); 89 | 90 | selector.m_type = from_string(type); 91 | 92 | while(in.peek() != '}') 93 | { 94 | skip_ws(in); 95 | selector.m_conditions.push_back(read_condition(in, selector.m_type)); 96 | 97 | skip_ws(in); 98 | int seperator = in.peek(); 99 | if(seperator != ',') 100 | continue; 101 | in.get(); 102 | skip_ws(in); 103 | } 104 | 105 | check_stream(in, '}'); 106 | 107 | return in; 108 | } 109 | 110 | selector_type from_string(const std::string& s) 111 | { 112 | if(s=="image") 113 | return selector_type::Image; 114 | if(s=="buffer") 115 | return selector_type::Buffer; 116 | if(s=="shader") 117 | return selector_type::Shader; 118 | if(s=="draw") 119 | return selector_type::Draw; 120 | if(s=="pipeline") 121 | return selector_type::Pipeline; 122 | if(s=="init") 123 | return selector_type::Init; 124 | if(s=="receive") 125 | return selector_type::Receive; 126 | if(s=="device_create") 127 | return selector_type::DeviceCreate; 128 | if(s=="device_destroy") 129 | return selector_type::DeviceDestroy; 130 | if(s=="present") 131 | return selector_type::Present; 132 | if(s=="swapchain_create") 133 | return selector_type::SwapchainCreate; 134 | if(s=="custom") 135 | return selector_type::Custom; 136 | throw std::runtime_error("unknown selector_type \""+s+"\""); 137 | } 138 | 139 | std::string to_string(selector_type type) 140 | { 141 | switch(type) 142 | { 143 | case selector_type::Image: 144 | return "image"; 145 | case selector_type::Buffer: 146 | return "buffer"; 147 | case selector_type::Shader: 148 | return "shader"; 149 | case selector_type::Draw: 150 | return "draw"; 151 | case selector_type::Pipeline: 152 | return "pipeline"; 153 | case selector_type::Init: 154 | return "init"; 155 | case selector_type::Receive: 156 | return "receive"; 157 | case selector_type::DeviceCreate: 158 | return "device_create"; 159 | case selector_type::DeviceDestroy: 160 | return "device_destroy"; 161 | case selector_type::Present: 162 | return "present"; 163 | case selector_type::SwapchainCreate: 164 | return "swapchain_create"; 165 | case selector_type::Custom: 166 | return "custom"; 167 | default: 168 | return "unknown" + std::to_string((int)type); 169 | } 170 | } 171 | 172 | std::string to_string(data_type type) 173 | { 174 | switch(type) 175 | { 176 | case data_type::String: 177 | return "string"; 178 | case data_type::Raw: 179 | return "raw"; 180 | case data_type::Handle: 181 | return "handle"; 182 | case data_type::Number: 183 | return "number"; 184 | case data_type::List: 185 | return "list"; 186 | default: 187 | return "unknown" + std::to_string((int)type); 188 | } 189 | } 190 | 191 | data_type data_type_from_string(const std::string& s) 192 | { 193 | if(s=="string") 194 | return data_type::String; 195 | if(s=="raw") 196 | return data_type::Raw; 197 | if(s=="handle") 198 | return data_type::Handle; 199 | if(s=="number") 200 | return data_type::Number; 201 | if(s=="list" || s=="vector" || s=="array") 202 | return data_type::List; 203 | throw std::runtime_error("unknown data_type \""+s+"\""); 204 | } 205 | 206 | bool selector::test(selector_type type, VkHandle handle, global_context& global, local_context& local) 207 | { 208 | if(type != m_type) 209 | return false; 210 | for(auto& c : m_conditions) 211 | { 212 | if(!c->test(type, handle, global, local)) 213 | return false; 214 | } 215 | return true; 216 | } 217 | 218 | void rule::execute(selector_type type, VkHandle handle, global_context& global, local_context& local) 219 | { 220 | if(m_disabled) 221 | return; 222 | 223 | if(m_selector->test(type, handle, global, local)) 224 | m_action->execute(type, handle, global, local, *this); 225 | } 226 | 227 | void rule::disable() 228 | { 229 | m_disabled = true; 230 | if(rule_disable_callback != nullptr) 231 | { 232 | rule_disable_callback(this); 233 | } 234 | } 235 | 236 | void execute_rules(std::vector>& rules, selector_type type, VkHandle handle, global_context& global, local_context& local) 237 | { 238 | for(auto& r : rules) 239 | { 240 | try 241 | { 242 | r->execute(type, handle, global, local); 243 | } 244 | catch(const rule_error& ex) 245 | { 246 | std::ostringstream oss; 247 | backward::Printer p; 248 | p.color_mode = backward::ColorMode::never; 249 | p.object = true; 250 | p.address = true; 251 | p.snippet = true; 252 | p.print(ex.stack_trace, oss); 253 | local.logger.error("Failed to execute a rule: {}\n{}", ex.what(), oss.str()); 254 | } 255 | catch(const std::exception& ex) 256 | { 257 | local.logger.error("Failed to execute a rule: {}", ex.what()); 258 | } 259 | } 260 | } 261 | 262 | std::ostream& rule::print(std::ostream &out) 263 | { 264 | m_selector->print(out); 265 | out << " -> "; 266 | m_action->print(out); 267 | return out; 268 | } 269 | 270 | std::ostream& selector::print(std::ostream &out) 271 | { 272 | out << to_string(m_type) << "{"; 273 | for(int i=0; iprint(out); 276 | if(i != m_conditions.size() - 1) 277 | out << ", "; 278 | } 279 | out << "}"; 280 | return out; 281 | } 282 | } 283 | --------------------------------------------------------------------------------