Skip to content

Commit

Permalink
layer: Add a Vulkan layer required for Reflex support
Browse files Browse the repository at this point in the history
  • Loading branch information
Saancreed committed Dec 18, 2024
1 parent 2252eab commit ded553e
Show file tree
Hide file tree
Showing 4 changed files with 1,031 additions and 0 deletions.
29 changes: 29 additions & 0 deletions layer/VkLayer_DXVK_NVAPI_reflex.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"file_format_version": "1.2.1",
"layer": {
"name": "VK_LAYER_DXVK_NVAPI_reflex",
"type": "GLOBAL",
"api_version": "1.3.295",
"library_path": "libdxvk_nvapi_vkreflex_layer.so",
"library_arch": "64",
"implementation_version": "1",
"description": "DXVK-NVAPI Vulkan Reflex compatibility layer",
"functions": {
"vkNegotiateLoaderLayerInterfaceVersion": "vkNegotiateLoaderLayerInterfaceVersion"
},
"instance_extensions": [],
"device_extensions": [
{
"name": "VK_NV_low_latency",
"spec_version": "1",
"entrypoints": []
}
],
"enable_environment": {
"DXVK_NVAPI_VKREFLEX": "1"
},
"disable_environment": {
"DISABLE_DXVK_NVAPI_VKREFLEX": "1"
}
}
}
142 changes: 142 additions & 0 deletions layer/log.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#pragma once

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#if defined(_WIN32)

#include <libloaderapi.h>
#include <processthreadsapi.h>
#include <profileapi.h>
#define GetProcessId GetCurrentProcessId
#define GetThreadId GetCurrentThreadId
#define PID_FORMAT "%04x"

static LARGE_INTEGER freq;

#else

#if !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
#include <time.h>
#include <unistd.h>
#define GetProcessId getpid
#define GetThreadId gettid
#define PID_FORMAT "%08x"

#endif

#if !defined(LOG_CHANNEL)
#warning LOG_CHANNEL is not defined
#define LOG_CHANNEL "unknown"
#endif

#if !defined(LOG_LEVEL_ENV)
#warning LOG_LEVEL_ENV is not defined
#define LOG_LEVEL_ENV ""
#endif

enum LogLevel {
LogLevel_None = 0,
LogLevel_Error = 1,
LogLevel_Warn = 2,
LogLevel_Info = 3,
LogLevel_Trace = 4,
LogLevel_Debug = 5,
};

static LogLevel logLevel = LogLevel_None;
static void (*wineDbgLog)(char const*) = nullptr;

static thread_local char wineDbgLogMessageBuffer[1024];

static inline char const* LogLevelString(LogLevel level) {
switch (level) {
case LogLevel_Debug:
return "debug";
case LogLevel_Trace:
return "trace";
case LogLevel_Info:
return "info";
case LogLevel_Warn:
return "warn";
case LogLevel_Error:
return "err";
case LogLevel_None:
return "none";
default:
return "?";
}
}

struct LogTimestamp {
int32_t seconds;
int32_t milliseconds;
};

static inline struct LogTimestamp GetTimestamp(void) {
#ifdef _WIN32
LARGE_INTEGER count;
QueryPerformanceCounter(&count);
return {
.seconds = (int32_t)(count.QuadPart / freq.QuadPart),
.milliseconds = (int32_t)(((count.QuadPart % freq.QuadPart) * 1000) / freq.QuadPart),
};
#else
struct timespec timespec;
clock_gettime(CLOCK_MONOTONIC_RAW, &timespec);
return {
.seconds = (int32_t)timespec.tv_sec,
.milliseconds = (int32_t)(timespec.tv_nsec / 1000000),
};
#endif
}

#define LOG(level, fmt, ...) \
do { \
if (logLevel >= level) { \
struct LogTimestamp time = GetTimestamp(); \
if (wineDbgLog) { \
snprintf( \
wineDbgLogMessageBuffer, sizeof(wineDbgLogMessageBuffer), \
"%3u.%03u:" PID_FORMAT ":" PID_FORMAT ":%s:" LOG_CHANNEL ":%s " fmt "\n", \
(int)time.seconds, (int)time.milliseconds, \
(unsigned int)GetProcessId(), (unsigned int)GetThreadId(), \
LogLevelString(level), \
__func__ __VA_OPT__(, ) __VA_ARGS__); \
wineDbgLog(wineDbgLogMessageBuffer); \
} else { \
fprintf( \
stderr, \
"%3u.%03u:" PID_FORMAT ":" PID_FORMAT ":%s:" LOG_CHANNEL ":%s " fmt "\n", \
(int)time.seconds, (int)time.milliseconds, \
(unsigned int)GetProcessId(), (unsigned int)GetThreadId(), \
LogLevelString(level), \
__func__ __VA_OPT__(, ) __VA_ARGS__); \
} \
} \
} while (0)

#define ERR(fmt, ...) LOG(LogLevel_Error, fmt, __VA_ARGS__)
#define WARN(fmt, ...) LOG(LogLevel_Warn, fmt, __VA_ARGS__)
#define INFO(fmt, ...) LOG(LogLevel_Info, fmt, __VA_ARGS__)
#define TRACE(fmt, ...) LOG(LogLevel_Trace, fmt, __VA_ARGS__)
#define DBG(fmt, ...) LOG(LogLevel_Debug, fmt, __VA_ARGS__)

static void InitLogger(void) {
char const* logLevelEnv = getenv(LOG_LEVEL_ENV);

if (logLevelEnv)
logLevel = (LogLevel)(atoi(logLevelEnv));

#if defined(_WIN32)
QueryPerformanceFrequency(&freq);

HMODULE ntdll = GetModuleHandleA("ntdll.dll");

if (ntdll)
*(void**)(&wineDbgLog) = (void*)GetProcAddress(ntdll, "__wine_dbg_output");
#endif
}
19 changes: 19 additions & 0 deletions layer/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
project('dxvk-nvapi-vkreflex-layer', ['cpp'], default_options: ['cpp_std=c++20'])

vk_headers = include_directories('../external/Vulkan-Headers/include')
vkroots = include_directories('../external/vkroots')

shared_library(
'dxvk_nvapi_vkreflex_layer',
sources: ['vulkan_reflex_layer.cpp'],
include_directories: [vk_headers, vkroots],
install: true,
)

configure_file(
copy: true,
input: 'VkLayer_DXVK_NVAPI_reflex.json',
install: true,
install_dir: 'share/vulkan/implicit_layer.d',
output: 'VkLayer_DXVK_NVAPI_reflex.json',
)
Loading

0 comments on commit ded553e

Please sign in to comment.