mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-12 19:41:10 +00:00
Merge commit 'e1a7d527fd412b6bd78833e01fe80f515e324971' into merge/main-into-non-adreno-all
# Conflicts: # .github/workflows/build.yml # app/build.gradle # app/src/main/java/com/droiddeck/launcher/core/DeviceReport.kt # app/src/main/java/com/droiddeck/launcher/gpu/DriverPairs.kt # app/src/main/java/com/droiddeck/launcher/gpu/GpuInfo.kt # app/src/main/java/com/droiddeck/launcher/gpu/TurnipDriver.java # app/src/main/java/com/droiddeck/launcher/gpu/TurnipReleases.kt # app/src/main/java/com/droiddeck/launcher/runtime/LinuxRuntime.java # app/src/main/java/com/droiddeck/launcher/session/SessionFiles.kt # app/src/main/java/com/droiddeck/launcher/session/SessionService.kt # app/src/main/res/values/strings.xml # app/src/test/java/com/droiddeck/launcher/ui/ComponentsPageProfileTest.kt # tools/build_local.sh # tools/gamescope/PATCHES.md # tools/gamescope/release.env # tools/linuxfs/overlay/usr/local/bin/droiddeck-game-env # tools/linuxfs/preload/netif.c # tools/linuxfs/preload/opens.c # tools/release/runtime_inputs.py
This commit is contained in:
commit
e7b523d653
574 files changed
+41749
-2616
No files matched your search
@@ -11,23 +11,23 @@ add_subdirectory(adrenotools)
|
||||
# DXVK's DXBC->SPIR-V translator is zlib licensed (vendored under thirdparty/dxbc).
|
||||
add_subdirectory(thirdparty/dxbc)
|
||||
|
||||
set(WINFG_UPSTREAM "v0.3.0")
|
||||
set(WINFG_CHAIN_SRC
|
||||
framegen/winfg/framegen.cpp
|
||||
framegen/winfg/framegen.hpp
|
||||
framegen/winfg/record_impl.inc
|
||||
framegen/winfg/config.hpp
|
||||
framegen/winfg/embedded_shaders.hpp
|
||||
framegen/winfg/winfg_engine.cpp
|
||||
set(DDFG_UPSTREAM "v0.3.0")
|
||||
set(DDFG_CHAIN_SRC
|
||||
framegen/ddfg/framegen.cpp
|
||||
framegen/ddfg/framegen.hpp
|
||||
framegen/ddfg/record_impl.inc
|
||||
framegen/ddfg/config.hpp
|
||||
framegen/ddfg/embedded_shaders.hpp
|
||||
framegen/ddfg/ddfg_engine.cpp
|
||||
)
|
||||
set(WINFG_HASH_INPUT "")
|
||||
foreach(f ${WINFG_CHAIN_SRC})
|
||||
set(DDFG_HASH_INPUT "")
|
||||
foreach(f ${DDFG_CHAIN_SRC})
|
||||
file(SHA256 "${CMAKE_CURRENT_SOURCE_DIR}/${f}" _h)
|
||||
string(APPEND WINFG_HASH_INPUT "${_h}")
|
||||
string(APPEND DDFG_HASH_INPUT "${_h}")
|
||||
endforeach()
|
||||
string(SHA256 WINFG_CHAIN_HASH_FULL "${WINFG_HASH_INPUT}")
|
||||
string(SUBSTRING "${WINFG_CHAIN_HASH_FULL}" 0 12 WINFG_CHAIN_HASH)
|
||||
message(STATUS "win-fg chain: ${WINFG_UPSTREAM} (src ${WINFG_CHAIN_HASH})")
|
||||
string(SHA256 DDFG_CHAIN_HASH_FULL "${DDFG_HASH_INPUT}")
|
||||
string(SUBSTRING "${DDFG_CHAIN_HASH_FULL}" 0 12 DDFG_CHAIN_HASH)
|
||||
message(STATUS "dd-fg chain: win-fg ${DDFG_UPSTREAM} (src ${DDFG_CHAIN_HASH})")
|
||||
|
||||
add_subdirectory(waylandcomp)
|
||||
add_subdirectory(questxr)
|
||||
@@ -39,6 +39,10 @@ target_link_libraries(deviceinfo dl)
|
||||
|
||||
add_library(termux SHARED termux/termux.c)
|
||||
|
||||
add_library(ddvenc SHARED venc/venc_server.cpp)
|
||||
target_compile_features(ddvenc PRIVATE cxx_std_17)
|
||||
target_link_libraries(ddvenc mediandk log)
|
||||
|
||||
# The optional proprietary SDK is supplied locally; its headers/libraries are not vendored.
|
||||
if(DROIDDECK_VITURE_SDK_DIR)
|
||||
add_library(droiddeck_viture SHARED viture/sdk_bridge.cpp)
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
#ifdef __GLIBC__
|
||||
#include <gnu/lib-names.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/joystick.h>
|
||||
@@ -1181,8 +1184,9 @@ struct TritonSharedData {
|
||||
uint32_t input_length;
|
||||
uint8_t input[64];
|
||||
uint64_t output_seq;
|
||||
uint32_t output_feature;
|
||||
uint32_t output_length;
|
||||
uint16_t output_feature;
|
||||
uint16_t output_length;
|
||||
uint32_t output_ack;
|
||||
uint8_t output[64];
|
||||
uint64_t get_request;
|
||||
uint64_t get_reply;
|
||||
@@ -1199,6 +1203,8 @@ static_assert(offsetof(TritonSharedData, report_id) == 16, "Triton report ID off
|
||||
static_assert(offsetof(TritonSharedData, input) == 24, "Triton input offset");
|
||||
static_assert(offsetof(TritonSharedData, output_seq) == 88, "Triton output sequence offset");
|
||||
static_assert(offsetof(TritonSharedData, output_feature) == 96, "Triton output feature offset");
|
||||
static_assert(offsetof(TritonSharedData, output_length) == 98, "Triton output length offset");
|
||||
static_assert(offsetof(TritonSharedData, output_ack) == 100, "Triton output ack offset");
|
||||
static_assert(offsetof(TritonSharedData, output) == 104, "Triton output offset");
|
||||
static_assert(offsetof(TritonSharedData, get_request) == 168, "Triton feature request offset");
|
||||
static_assert(offsetof(TritonSharedData, get_reply) == 176, "Triton feature reply offset");
|
||||
@@ -1216,6 +1222,8 @@ static constexpr int TRITON_REPORT_ID_BYTES = 1;
|
||||
static constexpr int TRITON_STATE_BYTES = 45;
|
||||
static constexpr int TRITON_REPORT_INTERVAL_US = 4000;
|
||||
static constexpr int TRITON_FEATURE_TIMEOUT_MS = 500;
|
||||
// The app clears output_length once it has taken a report; a writer waits this long for that before overwriting.
|
||||
static constexpr int TRITON_OUTPUT_TIMEOUT_MS = 50;
|
||||
static constexpr const char *TRITON_NAME = "Steam Controller";
|
||||
static constexpr const char *TRITON_SERIAL = "DROIDDECKSC01";
|
||||
static const uint8_t kTritonReportDescriptor[] = {
|
||||
@@ -2571,11 +2579,21 @@ __attribute__((visibility("hidden"))) static void triton_queue_output(DeckHidraw
|
||||
if (!data || !size || size > 64 || triton.mapping_size < TRITON_SHARED_OFFSET + TRITON_SHARED_BLOCK_SIZE) return;
|
||||
auto *shared = reinterpret_cast<TritonSharedData *>(reinterpret_cast<uint8_t *>(triton.ring) + TRITON_SHARED_OFFSET);
|
||||
if (__atomic_load_n(&shared->magic, __ATOMIC_ACQUIRE) != TRITON_SHARED_MAGIC) return;
|
||||
static std::mutex one_at_a_time;
|
||||
std::lock_guard<std::mutex> guard(one_at_a_time);
|
||||
for (int waited = 0;
|
||||
static_cast<uint32_t>(__atomic_load_n(&shared->output_seq, __ATOMIC_ACQUIRE)) !=
|
||||
__atomic_load_n(&shared->output_ack, __ATOMIC_ACQUIRE) &&
|
||||
__atomic_load_n(&shared->connected, __ATOMIC_ACQUIRE) != 0 && waited < TRITON_OUTPUT_TIMEOUT_MS * 4;
|
||||
waited++) {
|
||||
struct timespec interval = {0, 250 * 1000L};
|
||||
nanosleep(&interval, nullptr);
|
||||
}
|
||||
uint64_t seq = __atomic_load_n(&shared->output_seq, __ATOMIC_RELAXED);
|
||||
if (seq & 1) seq++;
|
||||
__atomic_store_n(&shared->output_seq, seq + 1, __ATOMIC_RELEASE);
|
||||
shared->output_feature = feature ? 1 : 0;
|
||||
shared->output_length = static_cast<uint32_t>(size);
|
||||
shared->output_length = static_cast<uint16_t>(size);
|
||||
memcpy(shared->output, data, size);
|
||||
if (size < sizeof(shared->output)) memset(shared->output + size, 0, sizeof(shared->output) - size);
|
||||
__atomic_thread_fence(__ATOMIC_RELEASE);
|
||||
@@ -2632,6 +2650,38 @@ __attribute__((visibility("hidden"))) static int triton_get_feature(DeckHidraw &
|
||||
static constexpr uint32_t TRITON_HWID = 72;
|
||||
static constexpr uint32_t TRITON_FW_TIMESTAMP = 0x6AC686B3;
|
||||
|
||||
// Steam compares the controller's firmware with TRITON_FW_TS in its bundled hardwareupdater.cfg (and blocks
|
||||
// with a required update below MUST_UPDATE_TRITON_FW_TS), so the emulated pad reports at least the build
|
||||
// Steam ships.
|
||||
static uint32_t triton_fw_timestamp() {
|
||||
static const uint32_t timestamp = [] {
|
||||
std::vector<std::string> roots;
|
||||
char exe[PATH_MAX];
|
||||
ssize_t n = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
|
||||
if (n > 0) {
|
||||
std::string path(exe, static_cast<size_t>(n));
|
||||
size_t bin = path.rfind('/');
|
||||
size_t root = bin == std::string::npos || bin == 0 ? std::string::npos : path.rfind('/', bin - 1);
|
||||
if (bin != std::string::npos && bin > 0) roots.push_back(path.substr(0, bin));
|
||||
if (root != std::string::npos) roots.push_back(path.substr(0, root));
|
||||
}
|
||||
if (const char *home = getenv("HOME")) roots.push_back(std::string(home) + "/.local/share/Steam");
|
||||
uint32_t newest = TRITON_FW_TIMESTAMP;
|
||||
for (const std::string &root : roots) {
|
||||
std::ifstream cfg(root + "/bin/hardwareupdater/hardwareupdater.cfg");
|
||||
std::string line;
|
||||
while (std::getline(cfg, line)) {
|
||||
if (line.rfind("TRITON_FW_TS:", 0) != 0) continue;
|
||||
uint32_t shipped = static_cast<uint32_t>(strtoul(line.c_str() + 13, nullptr, 16));
|
||||
if (shipped > newest) newest = shipped;
|
||||
}
|
||||
}
|
||||
if (newest != TRITON_FW_TIMESTAMP) Logger::log("triton: reporting firmware %08x, the build Steam ships\n", newest);
|
||||
return newest;
|
||||
}();
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
__attribute__((visibility("hidden"))) static int triton_pad_feature(DeckHidraw &triton, uint8_t *buf, size_t size, bool set) {
|
||||
if (!buf || size < 2) {
|
||||
errno = EINVAL;
|
||||
@@ -2652,7 +2702,7 @@ __attribute__((visibility("hidden"))) static int triton_pad_feature(DeckHidraw &
|
||||
switch (triton.pending_feature) {
|
||||
case DECK_GET_ATTRIBUTES_VALUES: {
|
||||
static const uint8_t kIds[] = {0x01, 0x02, 0x04, 0x09, 0x0a, 0x0b};
|
||||
const uint32_t values[] = {static_cast<uint32_t>(TRITON_WIRED_PRODUCT), 0, TRITON_FW_TIMESTAMP, TRITON_HWID, 0, 4000};
|
||||
const uint32_t values[] = {static_cast<uint32_t>(TRITON_WIRED_PRODUCT), 0, triton_fw_timestamp(), TRITON_HWID, 0, 4000};
|
||||
reply[2] = sizeof(kIds) * 5;
|
||||
for (size_t i = 0; i < sizeof(kIds); i++) {
|
||||
reply[3 + i * 5] = kIds[i];
|
||||
@@ -3577,7 +3627,21 @@ EXPORT int close(int fd) {
|
||||
static constexpr int kMaxRingWaitMs = 2;
|
||||
static constexpr int kLowLatencyRingWaitUs = 250;
|
||||
|
||||
EXPORT ssize_t read(int fd, void *buf, size_t count) {
|
||||
static ssize_t copy_input_events(void *buf, const struct input_event *events, size_t count) {
|
||||
size_t bytes = count * sizeof(struct input_event);
|
||||
struct iovec local = {const_cast<struct input_event *>(events), bytes};
|
||||
struct iovec remote = {buf, bytes};
|
||||
ssize_t copied = syscall(SYS_process_vm_writev, getpid(), &local, 1, &remote, 1, 0);
|
||||
if (copied < 0) return -1;
|
||||
if (copied != static_cast<ssize_t>(bytes)) {
|
||||
errno = EFAULT;
|
||||
copied -= copied % sizeof(struct input_event);
|
||||
if (!copied) return -1;
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
|
||||
static ssize_t read_input(int fd, void *buf, size_t count) {
|
||||
if (!watched(fd)) return syscall(SYS_read, fd, buf, count);
|
||||
std::unique_lock<std::recursive_mutex> guard(controller_mutex());
|
||||
auto controller = controller_map().find(fd);
|
||||
@@ -3622,42 +3686,44 @@ EXPORT ssize_t read(int fd, void *buf, size_t count) {
|
||||
if (events == 0) break;
|
||||
const uint8_t *ring_events = reinterpret_cast<const uint8_t *>(fake.ring) +
|
||||
FAKE_INPUT_RING_HEADER_SIZE;
|
||||
std::vector<struct input_event> input_events(events);
|
||||
for (size_t i = 0; i < events; ++i) {
|
||||
size_t index = (fake.read_seq + i) % FAKE_INPUT_RING_CAPACITY;
|
||||
RingEvent stored;
|
||||
memcpy(&stored, ring_events + index * FAKE_INPUT_EVENT_SIZE, FAKE_INPUT_EVENT_SIZE);
|
||||
struct input_event ev = {};
|
||||
struct input_event &ev = input_events[i];
|
||||
ev.time.tv_sec = stored.sec;
|
||||
ev.time.tv_usec = stored.usec;
|
||||
ev.type = stored.type;
|
||||
ev.code = stored.code;
|
||||
ev.value = stored.value;
|
||||
if (ev.type == EV_ABS) ev.code = presented_abs_code(fake, ev.code);
|
||||
memcpy(static_cast<uint8_t *>(buf) + i * sizeof(ev), &ev, sizeof(ev));
|
||||
}
|
||||
__atomic_thread_fence(__ATOMIC_ACQUIRE);
|
||||
if (snap.sequence != __atomic_load_n(&fake.ring->snapshot_seq, __ATOMIC_RELAXED))
|
||||
continue;
|
||||
fake.read_seq += events;
|
||||
return static_cast<ssize_t>(events * sizeof(struct input_event));
|
||||
ssize_t copied = copy_input_events(buf, input_events.data(), events);
|
||||
if (copied > 0) fake.read_seq += copied / sizeof(struct input_event);
|
||||
return copied;
|
||||
}
|
||||
}
|
||||
|
||||
size_t events = std::min(requested, fake.keyframe_remaining);
|
||||
struct input_event input_events[kNeutralEventCount] = {};
|
||||
struct timeval now = {};
|
||||
gettimeofday(&now, nullptr);
|
||||
for (size_t i = 0; i < events; ++i) {
|
||||
size_t index = kNeutralEventCount - fake.keyframe_remaining;
|
||||
struct input_event ev = {};
|
||||
size_t index = kNeutralEventCount - fake.keyframe_remaining + i;
|
||||
struct input_event &ev = input_events[i];
|
||||
ev.time = now;
|
||||
ev.type = kNeutralEvents[index].type;
|
||||
ev.code = kNeutralEvents[index].code;
|
||||
ev.value = keyframe_value(fake, ev.type, ev.code);
|
||||
if (ev.type == EV_ABS) ev.code = presented_abs_code(fake, ev.code);
|
||||
memcpy(static_cast<uint8_t *>(buf) + i * sizeof(ev), &ev, sizeof(ev));
|
||||
--fake.keyframe_remaining;
|
||||
}
|
||||
return static_cast<ssize_t>(events * sizeof(struct input_event));
|
||||
ssize_t copied = copy_input_events(buf, input_events, events);
|
||||
if (copied > 0) fake.keyframe_remaining -= copied / sizeof(struct input_event);
|
||||
return copied;
|
||||
}
|
||||
if (nonblock) {
|
||||
errno = EAGAIN;
|
||||
@@ -3673,6 +3739,52 @@ EXPORT ssize_t read(int fd, void *buf, size_t count) {
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT ssize_t read(int fd, void *buf, size_t count) {
|
||||
return read_input(fd, buf, count);
|
||||
}
|
||||
|
||||
EXPORT ssize_t readv(int fd, const struct iovec *iov, int iovcnt) {
|
||||
if (!is_fake_input_fd(fd)) return syscall(SYS_readv, fd, iov, iovcnt);
|
||||
if (iovcnt < 0 || iovcnt > IOV_MAX) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (iovcnt && !iov) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
std::vector<struct iovec> copied_iov(static_cast<size_t>(iovcnt));
|
||||
if (iovcnt) {
|
||||
size_t bytes = copied_iov.size() * sizeof(struct iovec);
|
||||
struct iovec local = {copied_iov.data(), bytes};
|
||||
struct iovec remote = {const_cast<struct iovec *>(iov), bytes};
|
||||
ssize_t copied = syscall(SYS_process_vm_readv, getpid(), &local, 1, &remote, 1, 0);
|
||||
if (copied != static_cast<ssize_t>(bytes)) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
iov = copied_iov.data();
|
||||
size_t size = 0;
|
||||
for (int i = 0; i < iovcnt; ++i) {
|
||||
if (iov[i].iov_len > static_cast<size_t>(SSIZE_MAX) - size) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
size += iov[i].iov_len;
|
||||
}
|
||||
|
||||
ssize_t total = 0;
|
||||
for (int i = 0; i < iovcnt; ++i) {
|
||||
if (!iov[i].iov_len) continue;
|
||||
ssize_t got = read_input(fd, iov[i].iov_base, iov[i].iov_len);
|
||||
if (got < 0) return total ? total : -1;
|
||||
total += got;
|
||||
if (static_cast<size_t>(got) != iov[i].iov_len) break;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
EXPORT ssize_t write(int fd, const void *buf, size_t count) {
|
||||
static auto my_write = reinterpret_cast<decltype(&::write)>(dlsym(RTLD_NEXT, "write"));
|
||||
|
||||
@@ -4103,4 +4215,92 @@ EXPORT int __fxstat64(int version, int fd, struct stat64 *buf) {
|
||||
if (!real) return fstat64(fd, buf);
|
||||
return fake_stat_fd(fd, buf, [version](int f, struct stat64 *b) { return real(version, f, b); });
|
||||
}
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
using dlsym_fn = void *(*)(void *, const char *);
|
||||
|
||||
static const char *const interposed_names[] = {
|
||||
"open", "open64", "openat", "openat64", "close", "read", "readv", "write", "writev", "ioctl",
|
||||
"poll", "ppoll", "select", "stat", "stat64", "fstat", "fstat64", "__xstat", "__xstat64",
|
||||
"__fxstat", "__fxstat64", "statx", "statfs", "statfs64", "fstatfs", "fstatfs64", "access",
|
||||
"faccessat", "opendir", "scandir", "inotify_add_watch",
|
||||
};
|
||||
|
||||
static dlsym_fn next_dlsym() {
|
||||
static const dlsym_fn fn = [] {
|
||||
#ifdef __x86_64__
|
||||
const char *base = "GLIBC_2.2.5";
|
||||
#else
|
||||
const char *base = "GLIBC_2.0";
|
||||
#endif
|
||||
for (const char *version : {base, "GLIBC_2.34"}) {
|
||||
if (auto found = reinterpret_cast<dlsym_fn>(dlvsym(RTLD_NEXT, "dlsym", version))) return found;
|
||||
}
|
||||
return dlsym_fn{};
|
||||
}();
|
||||
return fn;
|
||||
}
|
||||
|
||||
static void *global_dlsym(void *, const char *name) { return next_dlsym()(RTLD_DEFAULT, name); }
|
||||
|
||||
static void *missing_dlsym(void *, const char *) { return nullptr; }
|
||||
|
||||
static bool interposed(const char *name) {
|
||||
for (const char *interposed_name : interposed_names) {
|
||||
if (strcmp(interposed_name, name) == 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" __attribute__((visibility("hidden"), used)) void *fakeinput_dlsym_target(void *handle, const char *name) {
|
||||
dlsym_fn next = next_dlsym();
|
||||
if (!next) return reinterpret_cast<void *>(missing_dlsym);
|
||||
if (handle == RTLD_DEFAULT || handle == RTLD_NEXT || name == nullptr) return reinterpret_cast<void *>(next);
|
||||
static void *const libc = dlopen(LIBC_SO, RTLD_LAZY | RTLD_NOLOAD);
|
||||
if (handle != libc || !interposed(name)) return reinterpret_cast<void *>(next);
|
||||
return reinterpret_cast<void *>(global_dlsym);
|
||||
}
|
||||
|
||||
#ifdef __x86_64__
|
||||
__asm__(".text\n"
|
||||
".globl dlsym\n"
|
||||
".type dlsym, @function\n"
|
||||
"dlsym:\n"
|
||||
".cfi_startproc\n"
|
||||
"pushq %rdi\n"
|
||||
".cfi_adjust_cfa_offset 8\n"
|
||||
"pushq %rsi\n"
|
||||
".cfi_adjust_cfa_offset 8\n"
|
||||
"subq $8, %rsp\n"
|
||||
".cfi_adjust_cfa_offset 8\n"
|
||||
"call fakeinput_dlsym_target\n"
|
||||
"addq $8, %rsp\n"
|
||||
".cfi_adjust_cfa_offset -8\n"
|
||||
"popq %rsi\n"
|
||||
".cfi_adjust_cfa_offset -8\n"
|
||||
"popq %rdi\n"
|
||||
".cfi_adjust_cfa_offset -8\n"
|
||||
"jmp *%rax\n"
|
||||
".cfi_endproc\n"
|
||||
".size dlsym, .-dlsym\n");
|
||||
#else
|
||||
__asm__(".text\n"
|
||||
".globl dlsym\n"
|
||||
".type dlsym, @function\n"
|
||||
"dlsym:\n"
|
||||
".cfi_startproc\n"
|
||||
"subl $12, %esp\n"
|
||||
".cfi_adjust_cfa_offset 12\n"
|
||||
"movl 20(%esp), %eax\n"
|
||||
"movl %eax, 4(%esp)\n"
|
||||
"movl 16(%esp), %eax\n"
|
||||
"movl %eax, (%esp)\n"
|
||||
"call fakeinput_dlsym_target\n"
|
||||
"addl $12, %esp\n"
|
||||
".cfi_adjust_cfa_offset -12\n"
|
||||
"jmp *%eax\n"
|
||||
".cfi_endproc\n"
|
||||
".size dlsym, .-dlsym\n");
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
@@ -131,7 +131,7 @@ struct VkTable {
|
||||
#include <string>
|
||||
|
||||
namespace lsfg { class Engine; }
|
||||
namespace winfg { class Engine; }
|
||||
namespace ddfg { class Engine; }
|
||||
|
||||
static constexpr uint32_t MAX_FRAMES_IN_FLIGHT = 2;
|
||||
|
||||
@@ -280,7 +280,7 @@ public:
|
||||
static constexpr int32_t kFgCaptureGame = -1;
|
||||
void setFrameGenTuning(float flowScale, float refreshHz, int32_t captureHeight = 0);
|
||||
void setFrameGenEngine(int kind);
|
||||
void setWinFgTuning(int model, int perfPreset);
|
||||
void setDdFgTuning(int model, int perfPreset);
|
||||
|
||||
private:
|
||||
struct WinTex {
|
||||
@@ -468,12 +468,12 @@ private:
|
||||
uint64_t fgSourceFrames_ = 0;
|
||||
std::string lsfgCachePath_;
|
||||
bool lsfgEngineTried_ = false;
|
||||
std::unique_ptr<winfg::Engine> winfgEngine_;
|
||||
bool winfgEngineTried_ = false;
|
||||
std::unique_ptr<ddfg::Engine> ddfgEngine_;
|
||||
bool ddfgEngineTried_ = false;
|
||||
std::atomic<int> fgEngineKind_{0};
|
||||
std::atomic<int> fgModel_{4};
|
||||
std::atomic<int> fgPerfPreset_{1};
|
||||
bool ensureWinFgEngine();
|
||||
bool ensureDdFgEngine();
|
||||
bool fgCapsOk() const;
|
||||
|
||||
uint32_t syncSlot(uint32_t k) const { return currentFrame * kMaxPresentsPerFrame + k; }
|
||||
|
||||
File renamed without changes.
File renamed without changes.
+36
-36
@@ -6,7 +6,7 @@
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
namespace winfg {
|
||||
namespace ddfg {
|
||||
|
||||
struct Config {
|
||||
bool enabled = false;
|
||||
@@ -213,48 +213,48 @@ static inline void apply_toml(Config& c, const std::string& path) {
|
||||
}
|
||||
|
||||
static inline std::string conf_path() {
|
||||
if (const char* p = std::getenv("WIN_FG_CONF")) return p;
|
||||
if (const char* p = std::getenv("DD_FG_CONF")) return p;
|
||||
const char* home = std::getenv("HOME");
|
||||
return home ? std::string(home) + "/.config/win-fg/conf.toml" : std::string();
|
||||
return home ? std::string(home) + "/.config/dd-fg/conf.toml" : std::string();
|
||||
}
|
||||
|
||||
static inline std::string capture_root(const Config& c) {
|
||||
if (!c.capDir.empty()) return c.capDir;
|
||||
if (const char* home = std::getenv("HOME")) return std::string(home) + "/.cache/winfg-capture";
|
||||
return std::string("/tmp/winfg-capture");
|
||||
if (const char* home = std::getenv("HOME")) return std::string(home) + "/.cache/ddfg-capture";
|
||||
return std::string("/tmp/ddfg-capture");
|
||||
}
|
||||
|
||||
static inline Config load_config() {
|
||||
Config c;
|
||||
c.enabled = envi("WIN_FG_ENABLE", 0) != 0;
|
||||
if (const char* d = std::getenv("WIN_FG_DEBUG")) c.debug = parse_bool(d, c.debug);
|
||||
if (const char* pc = std::getenv("WIN_FG_PACING")) c.pacing = parse_bool(pc, c.pacing);
|
||||
c.model = envi("WIN_FG_MODEL", c.model);
|
||||
c.multiplier = envi("WIN_FG_MULT", c.multiplier);
|
||||
c.extraImages = envi("WIN_FG_EXTRA_IMAGES", c.extraImages);
|
||||
c.perfPreset = envi("WIN_FG_PERF_PRESET", c.perfPreset);
|
||||
if (const char* g = std::getenv("WIN_FG_GM")) c.gmMode = parse_tristate(g, c.gmMode);
|
||||
if (const char* r = std::getenv("WIN_FG_FLOWREG")) c.frMode = parse_tristate(r, c.frMode);
|
||||
c.frIters = envi("WIN_FG_FR_ITERS", c.frIters);
|
||||
c.frLambda = envf("WIN_FG_FR_LAMBDA", c.frLambda);
|
||||
c.frDt = envf("WIN_FG_FR_DT", c.frDt);
|
||||
c.frEdge = envf("WIN_FG_FR_EDGE", c.frEdge);
|
||||
c.frEps = envf("WIN_FG_FR_EPS", c.frEps);
|
||||
c.flowScale = envf("WIN_FG_FLOWSCALE", c.flowScale);
|
||||
c.beta = envf("WIN_FG_BETA", c.beta);
|
||||
c.lambda = envf("WIN_FG_LAMBDA", c.lambda);
|
||||
c.epsilon = envf("WIN_FG_EPSILON", c.epsilon);
|
||||
c.photoScale = envf("WIN_FG_PHOTOSCALE", c.photoScale);
|
||||
if (const char* cc = std::getenv("WIN_FG_CAPTURE")) c.capture = parse_bool(cc, c.capture);
|
||||
c.captureW = envi("WIN_FG_CAPTURE_W", c.captureW);
|
||||
c.captureH = envi("WIN_FG_CAPTURE_H", c.captureH);
|
||||
if (const char* cm = std::getenv("WIN_FG_CAPTURE_MODE")) c.capMode = parse_capmode(cm, c.capMode);
|
||||
c.capPatches = envi("WIN_FG_CAPTURE_PATCHES", c.capPatches);
|
||||
c.capPatchSize = envi("WIN_FG_CAPTURE_PATCH", c.capPatchSize);
|
||||
c.capMotion = envf("WIN_FG_CAPTURE_MOTION", c.capMotion);
|
||||
c.capShardMB = envi("WIN_FG_CAPTURE_SHARD_MB", c.capShardMB);
|
||||
if (const char* cd = std::getenv("WIN_FG_CAPTURE_DIR")) c.capDir = cd;
|
||||
if (const char* h = std::getenv("WIN_FG_HUD_RECT")) {
|
||||
c.enabled = envi("DD_FG_ENABLE", 0) != 0;
|
||||
if (const char* d = std::getenv("DD_FG_DEBUG")) c.debug = parse_bool(d, c.debug);
|
||||
if (const char* pc = std::getenv("DD_FG_PACING")) c.pacing = parse_bool(pc, c.pacing);
|
||||
c.model = envi("DD_FG_MODEL", c.model);
|
||||
c.multiplier = envi("DD_FG_MULT", c.multiplier);
|
||||
c.extraImages = envi("DD_FG_EXTRA_IMAGES", c.extraImages);
|
||||
c.perfPreset = envi("DD_FG_PERF_PRESET", c.perfPreset);
|
||||
if (const char* g = std::getenv("DD_FG_GM")) c.gmMode = parse_tristate(g, c.gmMode);
|
||||
if (const char* r = std::getenv("DD_FG_FLOWREG")) c.frMode = parse_tristate(r, c.frMode);
|
||||
c.frIters = envi("DD_FG_FR_ITERS", c.frIters);
|
||||
c.frLambda = envf("DD_FG_FR_LAMBDA", c.frLambda);
|
||||
c.frDt = envf("DD_FG_FR_DT", c.frDt);
|
||||
c.frEdge = envf("DD_FG_FR_EDGE", c.frEdge);
|
||||
c.frEps = envf("DD_FG_FR_EPS", c.frEps);
|
||||
c.flowScale = envf("DD_FG_FLOWSCALE", c.flowScale);
|
||||
c.beta = envf("DD_FG_BETA", c.beta);
|
||||
c.lambda = envf("DD_FG_LAMBDA", c.lambda);
|
||||
c.epsilon = envf("DD_FG_EPSILON", c.epsilon);
|
||||
c.photoScale = envf("DD_FG_PHOTOSCALE", c.photoScale);
|
||||
if (const char* cc = std::getenv("DD_FG_CAPTURE")) c.capture = parse_bool(cc, c.capture);
|
||||
c.captureW = envi("DD_FG_CAPTURE_W", c.captureW);
|
||||
c.captureH = envi("DD_FG_CAPTURE_H", c.captureH);
|
||||
if (const char* cm = std::getenv("DD_FG_CAPTURE_MODE")) c.capMode = parse_capmode(cm, c.capMode);
|
||||
c.capPatches = envi("DD_FG_CAPTURE_PATCHES", c.capPatches);
|
||||
c.capPatchSize = envi("DD_FG_CAPTURE_PATCH", c.capPatchSize);
|
||||
c.capMotion = envf("DD_FG_CAPTURE_MOTION", c.capMotion);
|
||||
c.capShardMB = envi("DD_FG_CAPTURE_SHARD_MB", c.capShardMB);
|
||||
if (const char* cd = std::getenv("DD_FG_CAPTURE_DIR")) c.capDir = cd;
|
||||
if (const char* h = std::getenv("DD_FG_HUD_RECT")) {
|
||||
float r[4] = {0,0,0,0}; int n = 0;
|
||||
std::string s = h; size_t start = 0;
|
||||
for (; n < 4; ++n) {
|
||||
@@ -266,8 +266,8 @@ static inline Config load_config() {
|
||||
c.hudX0 = r[0]; c.hudY0 = r[1]; c.hudX1 = r[2]; c.hudY1 = r[3];
|
||||
}
|
||||
const char* home = std::getenv("HOME");
|
||||
if (home) apply_toml(c, std::string(home) + "/.config/win-fg/conf.toml");
|
||||
if (const char* p = std::getenv("WIN_FG_CONF")) apply_toml(c, p);
|
||||
if (home) apply_toml(c, std::string(home) + "/.config/dd-fg/conf.toml");
|
||||
if (const char* p = std::getenv("DD_FG_CONF")) apply_toml(c, p);
|
||||
c.sanitize();
|
||||
return c;
|
||||
}
|
||||
+13
-10
@@ -1,10 +1,10 @@
|
||||
#include "winfg_engine.h"
|
||||
#include "winfg_vkd.h"
|
||||
#include "ddfg_engine.h"
|
||||
#include "ddfg_vkd.h"
|
||||
#include "log.hpp"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
namespace winfg {
|
||||
namespace ddfg {
|
||||
namespace {
|
||||
|
||||
float alphaFor(uint32_t k, uint32_t n) {
|
||||
@@ -31,18 +31,18 @@ Engine::~Engine() { destroyRing(); fg_.destroy(); }
|
||||
|
||||
bool Engine::init(const VkTable& table, VkPhysicalDevice phys, VkDevice dev,
|
||||
uint32_t queueFamily, VkQueue queue) {
|
||||
if (!winfgVkdInit(table, dd_, id_)) {
|
||||
WFG_LOGE("native: dispatch incomplete; frame generation unavailable");
|
||||
if (!ddfgVkdInit(table, dd_, id_)) {
|
||||
DDFG_LOGE("native: dispatch incomplete; frame generation unavailable");
|
||||
return false;
|
||||
}
|
||||
phys_ = phys; dev_ = dev; qf_ = queueFamily; queue_ = queue;
|
||||
id_.GetPhysicalDeviceMemoryProperties(phys_, &memProps_);
|
||||
if (!fg_.init(&dd_, &id_, phys_, dev_, qf_, queue_)) {
|
||||
WFG_LOGE("native: FrameGen::init failed");
|
||||
DDFG_LOGE("native: FrameGen::init failed");
|
||||
unavailable_ = true;
|
||||
return false;
|
||||
}
|
||||
WFG_LOGI("native: chain ready (10 pipelines, embedded shaders)");
|
||||
DDFG_LOGI("native: chain ready (10 pipelines, embedded shaders)");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ bool Engine::prepare(uint32_t w, uint32_t h, VkFormat fmt) {
|
||||
|
||||
|
||||
if (!fg_.onResize(VkExtent2D{w, h}, fmt, false)) {
|
||||
WFG_LOGE("native: onResize %ux%u failed; frame generation unavailable", w, h);
|
||||
DDFG_LOGE("native: onResize %ux%u failed; frame generation unavailable", w, h);
|
||||
unavailable_ = true;
|
||||
return false;
|
||||
}
|
||||
@@ -71,11 +71,13 @@ bool Engine::prepare(uint32_t w, uint32_t h, VkFormat fmt) {
|
||||
}
|
||||
builtW_ = w; builtH_ = h; builtFmt_ = fmt;
|
||||
history_ = 0; curr_ = 0; frames_ = 0;
|
||||
WFG_LOGI("native: built %ux%u fmt=%d model=%d preset=%d flow=%.2f",
|
||||
DDFG_LOGI("native: built %ux%u fmt=%d model=%d preset=%d flow=%.2f",
|
||||
w, h, (int)fmt, cfg_.model, cfg_.perfPreset, (double)cfg_.flowScale);
|
||||
return true;
|
||||
}
|
||||
|
||||
static_assert(kMaxGenerations <= (uint32_t)FrameGen::kSynthSlots, "each generation needs its own synth slot");
|
||||
|
||||
uint32_t Engine::plan(uint32_t capacity) const {
|
||||
if (!valid() || history_ < 2) return 0;
|
||||
const uint32_t want = (uint32_t)std::max(cfg_.multiplier - 1, 0);
|
||||
@@ -131,7 +133,8 @@ void Engine::generateInto(VkCommandBuffer cmd, uint32_t generation, uint32_t cou
|
||||
dd_.CmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &toWrite);
|
||||
|
||||
fg_.record(cmd, prev.view, curr.view, targetView, alphaFor(generation, count), gmSlot_);
|
||||
fg_.record(cmd, prev.view, curr.view, targetView, alphaFor(generation, count), gmSlot_,
|
||||
generation, generation > 0);
|
||||
if (generation + 1 == count) gmSlot_ = (gmSlot_ + 1) % (uint32_t)FrameGen::kGmSlots;
|
||||
|
||||
(void)w; (void)h;
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
struct VkTable;
|
||||
|
||||
namespace winfg {
|
||||
namespace ddfg {
|
||||
|
||||
constexpr uint32_t kMaxGenerations = 3;
|
||||
|
||||
+3
-3
@@ -1,14 +1,14 @@
|
||||
#include "winfg_vkd.h"
|
||||
#include "ddfg_vkd.h"
|
||||
#include "../VulkanRendererContext.h"
|
||||
#include <android/log.h>
|
||||
|
||||
bool winfgVkdInit(const VkTable& table, winfg::DeviceDispatch& dd, winfg::InstanceDispatch& id) {
|
||||
bool ddfgVkdInit(const VkTable& table, ddfg::DeviceDispatch& dd, ddfg::InstanceDispatch& id) {
|
||||
bool ok = true;
|
||||
#define COPY(dst, fn) \
|
||||
do { \
|
||||
dst.fn = table.fn; \
|
||||
if (!dst.fn) { \
|
||||
__android_log_print(ANDROID_LOG_ERROR, "WinFgVkd", \
|
||||
__android_log_print(ANDROID_LOG_ERROR, "DdFgVkd", \
|
||||
"entry point vk" #fn " did not resolve"); \
|
||||
ok = false; \
|
||||
} \
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include "vk_dispatch.hpp"
|
||||
struct VkTable;
|
||||
bool ddfgVkdInit(const VkTable& table, ddfg::DeviceDispatch& dd, ddfg::InstanceDispatch& id);
|
||||
+5
-5
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
namespace winfg { namespace embedded {
|
||||
namespace ddfg { namespace embedded {
|
||||
static const uint32_t OF3_LUMA_SPV[] = {0x07230203u,0x00010300u,0x0008000bu,0x00000054u,0x00000000u,0x00020011u,0x00000001u,0x00020011u,0x00000032u,0x0006000bu,0x00000001u,0x4c534c47u,0x6474732eu,0x3035342eu,0x00000000u,0x0003000eu,0x00000000u,0x00000001u,0x0006000fu,0x00000005u,0x00000004u,0x6e69616du,0x00000000u,0x0000000du,0x00060010u,0x00000004u,0x00000011u,0x00000010u,0x00000010u,0x00000001u,0x00030003u,0x00000002u,0x000001c2u,0x00040005u,0x00000004u,0x6e69616du,0x00000000u,0x00030005u,0x00000009u,0x00646967u,0x00080005u,0x0000000du,0x475f6c67u,0x61626f6cu,0x766e496cu,0x7461636fu,0x496e6f69u,0x00000044u,0x00030005u,0x00000012u,0x006d6964u,0x00040005u,0x00000016u,0x74734475u,0x00000000u,0x00030005u,0x00000030u,0x00007675u,0x00030005u,0x0000003bu,0x00626772u,0x00040005u,0x0000003fu,0x63725375u,0x00000000u,0x00030005u,0x00000047u,0x00005966u,0x00040047u,0x0000000du,0x0000000bu,0x0000001cu,0x00030047u,0x00000016u,0x00000019u,0x00040047u,0x00000016u,0x00000021u,0x00000030u,0x00040047u,0x00000016u,0x00000022u,0x00000000u,0x00040047u,0x0000003fu,0x00000021u,0x00000020u,0x00040047u,0x0000003fu,0x00000022u,0x00000000u,0x00040047u,0x00000053u,0x0000000bu,0x00000019u,0x00020013u,0x00000002u,0x00030021u,0x00000003u,0x00000002u,0x00040015u,0x00000006u,0x00000020u,0x00000001u,0x00040017u,0x00000007u,0x00000006u,0x00000002u,0x00040020u,0x00000008u,0x00000007u,0x00000007u,0x00040015u,0x0000000au,0x00000020u,0x00000000u,0x00040017u,0x0000000bu,0x0000000au,0x00000003u,0x00040020u,0x0000000cu,0x00000001u,0x0000000bu,0x0004003bu,0x0000000cu,0x0000000du,0x00000001u,0x00040017u,0x0000000eu,0x0000000au,0x00000002u,0x00030016u,0x00000013u,0x00000020u,0x00090019u,0x00000014u,0x00000013u,0x00000001u,0x00000000u,0x00000000u,0x00000000u,0x00000002u,0x00000003u,0x00040020u,0x00000015u,0x00000000u,0x00000014u,0x0004003bu,0x00000015u,0x00000016u,0x00000000u,0x00020014u,0x00000019u,0x0004002bu,0x0000000au,0x0000001au,0x00000000u,0x00040020u,0x0000001bu,0x00000007u,0x00000006u,0x0004002bu,0x0000000au,0x00000024u,0x00000001u,0x00040017u,0x0000002eu,0x00000013u,0x00000002u,0x00040020u,0x0000002fu,0x00000007u,0x0000002eu,0x0004002bu,0x00000013u,0x00000033u,0x3f000000u,0x00040017u,0x00000039u,0x00000013u,0x00000003u,0x00040020u,0x0000003au,0x00000007u,0x00000039u,0x00090019u,0x0000003cu,0x00000013u,0x00000001u,0x00000000u,0x00000000u,0x00000000u,0x00000001u,0x00000000u,0x0003001bu,0x0000003du,0x0000003cu,0x00040020u,0x0000003eu,0x00000000u,0x0000003du,0x0004003bu,0x0000003eu,0x0000003fu,0x00000000u,0x0004002bu,0x00000013u,0x00000042u,0x00000000u,0x00040017u,0x00000043u,0x00000013u,0x00000004u,0x00040020u,0x00000046u,0x00000007u,0x00000013u,0x0004002bu,0x00000013u,0x00000049u,0x3e59b3d0u,0x0004002bu,0x00000013u,0x0000004au,0x3f371759u,0x0004002bu,0x00000013u,0x0000004bu,0x3d93dd98u,0x0006002cu,0x00000039u,0x0000004cu,0x00000049u,0x0000004au,0x0000004bu,0x0004002bu,0x0000000au,0x00000052u,0x00000010u,0x0006002cu,0x0000000bu,0x00000053u,0x00000052u,0x00000052u,0x00000024u,0x00050036u,0x00000002u,0x00000004u,0x00000000u,0x00000003u,0x000200f8u,0x00000005u,0x0004003bu,0x00000008u,0x00000009u,0x00000007u,0x0004003bu,0x00000008u,0x00000012u,0x00000007u,0x0004003bu,0x0000002fu,0x00000030u,0x00000007u,0x0004003bu,0x0000003au,0x0000003bu,0x00000007u,0x0004003bu,0x00000046u,0x00000047u,0x00000007u,0x0004003du,0x0000000bu,0x0000000fu,0x0000000du,0x0007004fu,0x0000000eu,0x00000010u,0x0000000fu,0x0000000fu,0x00000000u,0x00000001u,0x0004007cu,0x00000007u,0x00000011u,0x00000010u,0x0003003eu,0x00000009u,0x00000011u,0x0004003du,0x00000014u,0x00000017u,0x00000016u,0x00040068u,0x00000007u,0x00000018u,0x00000017u,0x0003003eu,0x00000012u,0x00000018u,0x00050041u,0x0000001bu,0x0000001cu,0x00000009u,0x0000001au,0x0004003du,0x00000006u,0x0000001du,0x0000001cu,0x00050041u,0x0000001bu,0x0000001eu,0x00000012u,0x0000001au,0x0004003du,0x00000006u,0x0000001fu,0x0000001eu,0x000500afu,0x00000019u,0x00000020u,0x0000001du,0x0000001fu,0x000400a8u,0x00000019u,0x00000021u,0x00000020u,0x000300f7u,0x00000023u,0x00000000u,0x000400fau,0x00000021u,0x00000022u,0x00000023u,0x000200f8u,0x00000022u,0x00050041u,0x0000001bu,0x00000025u,0x00000009u,0x00000024u,0x0004003du,0x00000006u,0x00000026u,0x00000025u,0x00050041u,0x0000001bu,0x00000027u,0x00000012u,0x00000024u,0x0004003du,0x00000006u,0x00000028u,0x00000027u,0x000500afu,0x00000019u,0x00000029u,0x00000026u,0x00000028u,0x000200f9u,0x00000023u,0x000200f8u,0x00000023u,0x000700f5u,0x00000019u,0x0000002au,0x00000020u,0x00000005u,0x00000029u,0x00000022u,0x000300f7u,0x0000002cu,0x00000000u,0x000400fau,0x0000002au,0x0000002bu,0x0000002cu,0x000200f8u,0x0000002bu,0x000100fdu,0x000200f8u,0x0000002cu,0x0004003du,0x00000007u,0x00000031u,0x00000009u,0x0004006fu,0x0000002eu,0x00000032u,0x00000031u,0x00050050u,0x0000002eu,0x00000034u,0x00000033u,0x00000033u,0x00050081u,0x0000002eu,0x00000035u,0x00000032u,0x00000034u,0x0004003du,0x00000007u,0x00000036u,0x00000012u,0x0004006fu,0x0000002eu,0x00000037u,0x00000036u,0x00050088u,0x0000002eu,0x00000038u,0x0Line truncated
|
||||
static const size_t OF3_LUMA_LEN = 481;
|
||||
static const uint32_t OF3_DOWNSAMPLE_SPV[] = {0x07230203u,0x00010300u,0x0008000bu,0x0000008au,0x00000000u,0x00020011u,0x00000001u,0x00020011u,0x00000032u,0x0006000bu,0x00000001u,0x4c534c47u,0x6474732eu,0x3035342eu,0x00000000u,0x0003000eu,0x00000000u,0x00000001u,0x0006000fu,0x00000005u,0x00000004u,0x6e69616du,0x00000000u,0x0000000du,0x00060010u,0x00000004u,0x00000011u,0x00000010u,0x00000010u,0x00000001u,0x00030003u,0x00000002u,0x000001c2u,0x00040005u,0x00000004u,0x6e69616du,0x00000000u,0x00030005u,0x00000009u,0x00646967u,0x00080005u,0x0000000du,0x475f6c67u,0x61626f6cu,0x766e496cu,0x7461636fu,0x496e6f69u,0x00000044u,0x00030005u,0x00000012u,0x006d6964u,0x00040005u,0x00000016u,0x74734475u,0x00000000u,0x00040005u,0x00000030u,0x44637273u,0x00006d69u,0x00040005u,0x00000034u,0x63725375u,0x00000000u,0x00040005u,0x0000003au,0x65736162u,0x00000000u,0x00030005u,0x00000044u,0x00000068u,0x00030005u,0x0000004au,0x00000061u,0x00030005u,0x00000059u,0x00000062u,0x00030005u,0x00000065u,0x00000063u,0x00030005u,0x00000071u,0x00000064u,0x00040047u,0x0000000du,0x0000000bu,0x0000001cu,0x00030047u,0x00000016u,0x00000019u,0x00040047u,0x00000016u,0x00000021u,0x00000030u,0x00040047u,0x00000016u,0x00000022u,0x00000000u,0x00040047u,0x00000034u,0x00000021u,0x00000020u,0x00040047u,0x00000034u,0x00000022u,0x00000000u,0x00040047u,0x00000089u,0x0000000bu,0x00000019u,0x00020013u,0x00000002u,0x00030021u,0x00000003u,0x00000002u,0x00040015u,0x00000006u,0x00000020u,0x00000001u,0x00040017u,0x00000007u,0x00000006u,0x00000002u,0x00040020u,0x00000008u,0x00000007u,0x00000007u,0x00040015u,0x0000000au,0x00000020u,0x00000000u,0x00040017u,0x0000000bu,0x0000000au,0x00000003u,0x00040020u,0x0000000cu,0x00000001u,0x0000000bu,0x0004003bu,0x0000000cu,0x0000000du,0x00000001u,0x00040017u,0x0000000eu,0x0000000au,0x00000002u,0x00030016u,0x00000013u,0x00000020u,0x00090019u,0x00000014u,0x00000013u,0x00000001u,0x00000000u,0x00000000u,0x00000000u,0x00000002u,0x00000003u,0x00040020u,0x00000015u,0x00000000u,0x00000014u,0x0004003bu,0x00000015u,0x00000016u,0x00000000u,0x00020014u,0x00000019u,0x0004002bu,0x0000000au,0x0000001au,0x00000000u,0x00040020u,0x0000001bu,0x00000007u,0x00000006u,0x0004002bu,0x0000000au,0x00000024u,0x00000001u,0x00040017u,0x0000002eu,0x00000013u,0x00000002u,0x00040020u,0x0000002fu,0x00000007u,0x0000002eu,0x00090019u,0x00000031u,0x00000013u,0x00000001u,0x00000000u,0x00000000u,0x00000000u,0x00000001u,0x00000000u,0x0003001bu,0x00000032u,0x00000031u,0x00040020u,0x00000033u,0x00000000u,0x00000032u,0x0004003bu,0x00000033u,0x00000034u,0x00000000u,0x0004002bu,0x00000006u,0x00000036u,0x00000000u,0x0004002bu,0x00000013u,0x0000003du,0x40000000u,0x0004002bu,0x00000013u,0x0000003fu,0x3f800000u,0x0004002bu,0x00000013u,0x00000045u,0x3f000000u,0x00040020u,0x00000049u,0x00000007u,0x00000013u,0x0004002bu,0x00000013u,0x00000055u,0x00000000u,0x00040017u,0x00000056u,0x00000013u,0x00000004u,0x0004002bu,0x00000013u,0x00000085u,0x3e800000u,0x0004002bu,0x0000000au,0x00000088u,0x00000010u,0x0006002cu,0x0000000bu,0x00000089u,0x00000088u,0x00000088u,0x00000024u,0x00050036u,0x00000002u,0x00000004u,0x00000000u,0x00000003u,0x000200f8u,0x00000005u,0x0004003bu,0x00000008u,0x00000009u,0x00000007u,0x0004003bu,0x00000008u,0x00000012u,0x00000007u,0x0004003bu,0x0000002fu,0x00000030u,0x00000007u,0x0004003bu,0x0000002fu,0x0000003au,0x00000007u,0x0004003bu,0x0000002fu,0x00000044u,0x00000007u,0x0004003bu,0x00000049u,0x0000004au,0x00000007u,0x0004003bu,0x00000049u,0x00000059u,0x00000007u,0x0004003bu,0x00000049u,0x00000065u,0x00000007u,0x0004003bu,0x00000049u,0x00000071u,0x00000007u,0x0004003du,0x0000000bu,0x0000000fu,0x0000000du,0x0007004fu,0x0000000eu,0x00000010u,0x0000000fu,0x0000000fu,0x00000000u,0x00000001u,0x0004007cu,0x00000007u,0x00000011u,0x00000010u,0x0003003eu,0x00000009u,0x00000011u,0x0004003du,0x00000014u,0x00000017u,0x00000016u,0x00040068u,0x00000007u,0x00000018u,0x00000017u,0x0003003eu,0x00000012u,0x00000018u,0x00050041u,0x0000001bu,0x0000001cu,0x00000009u,0x0000001au,0x0004003du,0x00000006u,0x0000001du,0x0000001cu,0x00050041u,0x0000001bu,0x0000001eu,0x00000012u,0x0000001au,0x0004003du,0x00000006u,0x0000001fu,0x0000001eu,0x000500afu,0x00000019u,0x00000020u,0x0000001du,0x0000001fu,0x000400a8u,0x00000019u,0x00000021u,0x00000020u,0x000300f7u,0x00000023u,0x00000000u,0x000400fau,0x00000021u,0x00000022u,0x00000023u,0x000200f8u,0x00000022u,0x00050041u,0x0000001bu,0x00000025u,0x00000009u,0x00000024u,0x0004003du,0x00000006u,0x00000026u,0x00000025u,0x00050041u,0x0000001bu,0x00000027u,0x00000012u,0x00000024u,0x0004003du,0x00000006u,0x00000028u,0x00000027u,0x000500afu,0x00000019u,0x00000029u,0x00000026u,0x00000028u,0x000200f9u,0x00000023u,0x000200f8u,0x00000023u,0x000700f5u,0x00000019u,0x0000002au,0x00000020u,0x00000005u,0x00000029u,0x00000022u,0x000300f7u,0x0000002cu,0x00000000u,0x000400fau,0x0000002au,0x0000002bu,0x0000002cu,0x000200f8u,0x0000002bu,0x000100fdu,0x000200f8u,0x0000002cu,0x0004003du,0x00000032u,0x00000035u,0x00000034u,0x00040064u,0x00000031u,0x00000037u,0x00000035u,0x0005006Line truncated
|
||||
@@ -20,10 +20,10 @@ static const uint32_t OF3_GM_PREWARP_SPV[] = {0x07230203u,0x00010300u,0x0008000b
|
||||
static const size_t OF3_GM_PREWARP_LEN = 706;
|
||||
static const uint32_t OF3_FLOWREG_SPV[] = {0x07230203u,0x00010300u,0x0008000bu,0x00000144u,0x00000000u,0x00020011u,0x00000001u,0x00020011u,0x00000032u,0x0006000bu,0x00000001u,0x4c534c47u,0x6474732eu,0x3035342eu,0x00000000u,0x0003000eu,0x00000000u,0x00000001u,0x0006000fu,0x00000005u,0x00000004u,0x6e69616du,0x00000000u,0x00000037u,0x00060010u,0x00000004u,0x00000011u,0x00000010u,0x00000010u,0x00000001u,0x00030003u,0x00000002u,0x000001c2u,0x00040005u,0x00000004u,0x6e69616du,0x00000000u,0x00060005u,0x0000000eu,0x63746566u,0x76285568u,0x763b3269u,0x003b3269u,0x00030005u,0x0000000cu,0x00000070u,0x00030005u,0x0000000du,0x006d6964u,0x00060005u,0x00000013u,0x63746566u,0x76284c68u,0x763b3269u,0x003b3269u,0x00030005u,0x00000011u,0x00000070u,0x00030005u,0x00000012u,0x006d6964u,0x00040005u,0x00000018u,0x6f6c4675u,0x006e4977u,0x00040005u,0x00000026u,0x6d754c75u,0x00000061u,0x00030005u,0x00000034u,0x00646967u,0x00080005u,0x00000037u,0x475f6c67u,0x61626f6cu,0x766e496cu,0x7461636fu,0x496e6f69u,0x00000044u,0x00030005u,0x0000003cu,0x006d6964u,0x00030005u,0x00000055u,0x00007464u,0x00030005u,0x00000056u,0x00000055u,0x00050006u,0x00000056u,0x00000000u,0x61726170u,0x0000736du,0x00030005u,0x00000058u,0x00000000u,0x00040005u,0x0000005cu,0x626d616cu,0x00006164u,0x00050005u,0x0000005fu,0x65676465u,0x68706c41u,0x00000061u,0x00040005u,0x00000063u,0x54737065u,0x00000056u,0x00030005u,0x00000068u,0x00004375u,0x00040005u,0x00000069u,0x61726170u,0x0000006du,0x00040005u,0x0000006bu,0x61726170u,0x0000006du,0x00030005u,0x0000006eu,0x00004c75u,0x00040005u,0x00000073u,0x61726170u,0x0000006du,0x00040005u,0x00000074u,0x61726170u,0x0000006du,0x00030005u,0x00000077u,0x00005275u,0x00040005u,0x0000007bu,0x61726170u,0x0000006du,0x00040005u,0x0000007cu,0x61726170u,0x0000006du,0x00030005u,0x0000007fu,0x00005575u,0x00040005u,0x00000083u,0x61726170u,0x0000006du,0x00040005u,0x00000084u,0x61726170u,0x0000006du,0x00030005u,0x00000087u,0x00004475u,0x00040005u,0x0000008bu,0x61726170u,0x0000006du,0x00040005u,0x0000008cu,0x61726170u,0x0000006du,0x00040005u,0x0000008fu,0x6d69646cu,0x00000000u,0x00030005u,0x00000093u,0x00004c6cu,0x00040005u,0x00000096u,0x61726170u,0x0000006du,0x00040005u,0x00000097u,0x61726170u,0x0000006du,0x00030005u,0x0000009au,0x0000526cu,0x00040005u,0x0000009du,0x61726170u,0x0000006du,0x00040005u,0x0000009eu,0x61726170u,0x0000006du,0x00030005u,0x000000a1u,0x0000556cu,0x00040005u,0x000000a4u,0x61726170u,0x0000006du,0x00040005u,0x000000a5u,0x61726170u,0x0000006du,0x00030005u,0x000000a8u,0x0000446cu,0x00040005u,0x000000abu,0x61726170u,0x0000006du,0x00040005u,0x000000acu,0x61726170u,0x0000006du,0x00040005u,0x000000afu,0x67616d67u,0x00000000u,0x00030005u,0x000000bbu,0x00000067u,0x00030005u,0x000000c4u,0x00004c64u,0x00030005u,0x000000c8u,0x00005264u,0x00030005u,0x000000ccu,0x00005564u,0x00030005u,0x000000d0u,0x00004464u,0x00030005u,0x000000d4u,0x00003265u,0x00030005u,0x000000d8u,0x00004c77u,0x00030005u,0x000000e1u,0x00005277u,0x00030005u,0x000000eau,0x00005577u,0x00030005u,0x000000f3u,0x00004477u,0x00040005u,0x000000fcu,0x576d7573u,0x00000000u,0x00040005u,0x00000104u,0x576d7573u,0x00000055u,0x00040005u,0x00000114u,0x66694475u,0x00000066u,0x00030005u,0x00000120u,0x00003066u,0x00050005u,0x00000121u,0x6f6c4675u,0x73624f77u,0x00000000u,0x00040005u,0x0000012au,0x74656874u,0x00000061u,0x00030005u,0x0000012eu,0x00000072u,0x00040005u,0x00000132u,0x77654e75u,0x00000000u,0x00050005u,0x0000013eu,0x6f6c4675u,0x74754f77u,0x00000000u,0x00040047u,0x00000018u,0x00000021u,0x00000020u,0x00040047u,0x00000018u,0x00000022u,0x00000000u,0x00040047u,0x00000026u,0x00000021u,0x00000022u,0x00040047u,0x00000026u,0x00000022u,0x00000000u,0x00040047u,0x00000037u,0x0000000bu,0x0000001cu,0x00030047u,0x00000056u,0x00000002u,0x00050048u,0x00000056u,0x00000000u,0x00000023u,0x00000000u,0x00040047u,0x00000058u,0x00000021u,0x00000000u,0x00040047u,0x00000058u,0x00000022u,0x00000000u,0x00040047u,0x00000121u,0x00000021u,0x00000021u,0x00040047u,0x00000121u,0x00000022u,0x00000000u,0x00030047u,0x0000013eu,0x00000019u,0x00040047u,0x0000013eu,0x00000021u,0x00000030u,0x00040047u,0x0000013eu,0x00000022u,0x00000000u,0x00040047u,0x00000143u,0x0000000bu,0x00000019u,0x00020013u,0x00000002u,0x00030021u,0x00000003u,0x00000002u,0x00040015u,0x00000006u,0x00000020u,0x00000001u,0x00040017u,0x00000007u,0x00000006u,0x00000002u,0x00040020u,0x00000008u,0x00000007u,0x00000007u,0x00030016u,0x00000009u,0x00000020u,0x00040017u,0x0000000au,0x00000009u,0x00000004u,0x00050021u,0x0000000bu,0x0000000au,0x00000008u,0x00000008u,0x00050021u,0x00000010u,0x00000009u,0x00000008u,0x00000008u,0x00090019u,0x00000015u,0x00000009u,0x00000001u,0x00000000u,0x00000000u,0x00000000u,0x00000001u,0x00000000u,0x0003001bu,0x00000016u,0x00000015u,0x00040020u,0x00000017u,0x00000000u,0x00000016u,0x0004003bu,0x00000017u,0x00000018u,0x00000000u,0x0004002bu,0x00000006u,0x0000001bu,0x00000000u,0x0005002cu,0x00000007u,0x0000001cu,0x0000001bu,0x0000001bu,0x0004002bu,0x00000006u,0x0000001eu,0x00000001u,0x0004003bu,0x00000017u,0x00000026u,0x00000000u,Line truncated
|
||||
static const size_t OF3_FLOWREG_LEN = 1936;
|
||||
static const uint32_t WFG_SYNTH_SPV[] = {0x07230203u,0x00010300u,0x0008000bu,0x00000208u,0x00000000u,0x00020011u,0x00000001u,0x00020011u,0x00000032u,0x0006000bu,0x00000001u,0x4c534c47u,0x6474732eu,0x3035342eu,0x00000000u,0x0003000eu,0x00000000u,0x00000001u,0x0006000fu,0x00000005u,0x00000004u,0x6e69616du,0x00000000u,0x0000001cu,0x00060010u,0x00000004u,0x00000011u,0x00000010u,0x00000010u,0x00000001u,0x00030003u,0x00000002u,0x000001c2u,0x00040005u,0x00000004u,0x6e69616du,0x00000000u,0x00050005u,0x0000000bu,0x616d756cu,0x33667628u,0x0000003bu,0x00030005u,0x0000000au,0x00000063u,0x00030005u,0x00000018u,0x00646967u,0x00080005u,0x0000001cu,0x475f6c67u,0x61626f6cu,0x766e496cu,0x7461636fu,0x496e6f69u,0x00000044u,0x00030005u,0x00000021u,0x006d6964u,0x00040005u,0x00000024u,0x74754f75u,0x00000000u,0x00040005u,0x0000003eu,0x44766e69u,0x00006d69u,0x00030005u,0x00000044u,0x00007675u,0x00030005u,0x0000004du,0x00000055u,0x00060006u,0x0000004du,0x00000000u,0x776f6c66u,0x6c616353u,0x00000065u,0x00050006u,0x0000004du,0x00000001u,0x68706c61u,0x00000061u,0x00050006u,0x0000004du,0x00000002u,0x61746562u,0x00000000u,0x00050006u,0x0000004du,0x00000003u,0x626d616cu,0x00006164u,0x00050006u,0x0000004du,0x00000004u,0x69737065u,0x006e6f6cu,0x00060006u,0x0000004du,0x00000005u,0x746f6870u,0x6163536fu,0x0000656cu,0x00050006u,0x0000004du,0x00000006u,0x30646170u,0x00000000u,0x00050006u,0x0000004du,0x00000007u,0x31646170u,0x00000000u,0x00050006u,0x0000004du,0x00000008u,0x52647568u,0x00746365u,0x00030005u,0x0000004fu,0x00000000u,0x00040005u,0x0000008cu,0x72754375u,0x00000072u,0x00030005u,0x00000098u,0x00676264u,0x00030005u,0x0000009fu,0x00007366u,0x00040005u,0x000000a9u,0x64774273u,0x00000000u,0x00050005u,0x000000aau,0x6f6c4675u,0x64774277u,0x00000000u,0x00040005u,0x000000aeu,0x64774673u,0x00000000u,0x00050005u,0x000000afu,0x6f6c4675u,0x64774677u,0x00000000u,0x00030005u,0x000000b3u,0x00313046u,0x00030005u,0x000000bau,0x00303146u,0x00040005u,0x000000c1u,0x31306663u,0x00000000u,0x00040005u,0x000000c5u,0x30316663u,0x00000000u,0x00030005u,0x000000c9u,0x0031306du,0x00030005u,0x000000d5u,0x0030316du,0x00030005u,0x000000e0u,0x00004170u,0x00030005u,0x000000e8u,0x00004270u,0x00030005u,0x000000f0u,0x00003043u,0x00040005u,0x000000f1u,0x65725075u,0x00000076u,0x00030005u,0x000000f6u,0x00003143u,0x00030005u,0x000000fbu,0x00004165u,0x00040005u,0x000000fcu,0x61726170u,0x0000006du,0x00040005u,0x0000010cu,0x61726170u,0x0000006du,0x00030005u,0x00000111u,0x00004265u,0x00040005u,0x00000112u,0x61726170u,0x0000006du,0x00040005u,0x00000122u,0x61726170u,0x0000006du,0x00040005u,0x00000127u,0x76556266u,0x00000000u,0x00040005u,0x0000012bu,0x65526266u,0x00646973u,0x00040005u,0x00000138u,0x736e6f63u,0x00747369u,0x00030005u,0x00000149u,0x0000305au,0x00030005u,0x00000157u,0x0000315au,0x00040005u,0x00000163u,0x30756174u,0x00000000u,0x00040005u,0x00000167u,0x31756174u,0x00000000u,0x00040005u,0x0000016au,0x78616d7au,0x00000000u,0x00030005u,0x0000016eu,0x00003057u,0x00030005u,0x00000179u,0x00003157u,0x00040005u,0x00000183u,0x6d757357u,0x00000000u,0x00040005u,0x00000187u,0x70726177u,0x00006465u,0x00050005u,0x000001a0u,0x736f7263u,0x64616673u,0x00000065u,0x00050005u,0x000001adu,0x746f6870u,0x7272456fu,0x00000000u,0x00050005u,0x000001b1u,0x746f6870u,0x7572546fu,0x00007473u,0x00040005u,0x000001b7u,0x73757274u,0x00000074u,0x00040005u,0x000001c3u,0x76657270u,0x00000043u,0x00040005u,0x000001c8u,0x72727563u,0x00000043u,0x00050005u,0x000001cdu,0x746e6f63u,0x44746e65u,0x00666669u,0x00050005u,0x000001d2u,0x72746e75u,0x65747375u,0x00000064u,0x00040005u,0x000001d7u,0x44676962u,0x00666669u,0x00050005u,0x000001dcu,0x70616e73u,0x75436f54u,0x00007272u,0x00040005u,0x000001e5u,0x6374756fu,0x00000000u,0x00030005u,0x000001eeu,0x0067616du,0x00030005u,0x000001f2u,0x0000006eu,0x00030005u,0x000001f6u,0x00746173u,0x00040047u,0x0000001cu,0x0000000bu,0x0000001cu,0x00030047u,0x00000024u,0x00000019u,0x00040047u,0x00000024u,0x00000021u,0x00000030u,0x00040047u,0x00000024u,0x00000022u,0x00000000u,0x00030047u,0x0000004du,0x00000002u,0x00050048u,0x0000004du,0x00000000u,0x00000023u,0x00000000u,0x00050048u,0x0000004du,0x00000001u,0x00000023u,0x00000004u,0x00050048u,0x0000004du,0x00000002u,0x00000023u,0x00000008u,0x00050048u,0x0000004du,0x00000003u,0x00000023u,0x0000000cu,0x00050048u,0x0000004du,0x00000004u,0x00000023u,0x00000010u,0x00050048u,0x0000004du,0x00000005u,0x00000023u,0x00000014u,0x00050048u,0x0000004du,0x00000006u,0x00000023u,0x00000018u,0x00050048u,0x0000004du,0x00000007u,0x00000023u,0x0000001cu,0x00050048u,0x0000004du,0x00000008u,0x00000023u,0x00000020u,0x00040047u,0x0000004fu,0x00000021u,0x00000000u,0x00040047u,0x0000004fu,0x00000022u,0x00000000u,0x00040047u,0x0000008cu,0x00000021u,0x00000021u,0x00040047u,0x0000008cu,0x00000022u,0x00000000u,0x00040047u,0x000000aau,0x00000021u,0x00000023u,0x00040047u,0x000000aau,0x00000022u,0x00000000u,0x00040047u,0x000000afu,0x00000021u,0x00000022u,0x00040047u,0x000000afu,0x00000022u,0x00000000u,0x00040047u,0x000000f1u,0x00000021u,0x00000020u,0x00040047u,0x000000f1u,0xLine truncated
|
||||
static const size_t WFG_SYNTH_LEN = 3082;
|
||||
static const uint32_t DDFG_SYNTH_SPV[] = {0x07230203u,0x00010300u,0x0008000bu,0x00000208u,0x00000000u,0x00020011u,0x00000001u,0x00020011u,0x00000032u,0x0006000bu,0x00000001u,0x4c534c47u,0x6474732eu,0x3035342eu,0x00000000u,0x0003000eu,0x00000000u,0x00000001u,0x0006000fu,0x00000005u,0x00000004u,0x6e69616du,0x00000000u,0x0000001cu,0x00060010u,0x00000004u,0x00000011u,0x00000010u,0x00000010u,0x00000001u,0x00030003u,0x00000002u,0x000001c2u,0x00040005u,0x00000004u,0x6e69616du,0x00000000u,0x00050005u,0x0000000bu,0x616d756cu,0x33667628u,0x0000003bu,0x00030005u,0x0000000au,0x00000063u,0x00030005u,0x00000018u,0x00646967u,0x00080005u,0x0000001cu,0x475f6c67u,0x61626f6cu,0x766e496cu,0x7461636fu,0x496e6f69u,0x00000044u,0x00030005u,0x00000021u,0x006d6964u,0x00040005u,0x00000024u,0x74754f75u,0x00000000u,0x00040005u,0x0000003eu,0x44766e69u,0x00006d69u,0x00030005u,0x00000044u,0x00007675u,0x00030005u,0x0000004du,0x00000055u,0x00060006u,0x0000004du,0x00000000u,0x776f6c66u,0x6c616353u,0x00000065u,0x00050006u,0x0000004du,0x00000001u,0x68706c61u,0x00000061u,0x00050006u,0x0000004du,0x00000002u,0x61746562u,0x00000000u,0x00050006u,0x0000004du,0x00000003u,0x626d616cu,0x00006164u,0x00050006u,0x0000004du,0x00000004u,0x69737065u,0x006e6f6cu,0x00060006u,0x0000004du,0x00000005u,0x746f6870u,0x6163536fu,0x0000656cu,0x00050006u,0x0000004du,0x00000006u,0x30646170u,0x00000000u,0x00050006u,0x0000004du,0x00000007u,0x31646170u,0x00000000u,0x00050006u,0x0000004du,0x00000008u,0x52647568u,0x00746365u,0x00030005u,0x0000004fu,0x00000000u,0x00040005u,0x0000008cu,0x72754375u,0x00000072u,0x00030005u,0x00000098u,0x00676264u,0x00030005u,0x0000009fu,0x00007366u,0x00040005u,0x000000a9u,0x64774273u,0x00000000u,0x00050005u,0x000000aau,0x6f6c4675u,0x64774277u,0x00000000u,0x00040005u,0x000000aeu,0x64774673u,0x00000000u,0x00050005u,0x000000afu,0x6f6c4675u,0x64774677u,0x00000000u,0x00030005u,0x000000b3u,0x00313046u,0x00030005u,0x000000bau,0x00303146u,0x00040005u,0x000000c1u,0x31306663u,0x00000000u,0x00040005u,0x000000c5u,0x30316663u,0x00000000u,0x00030005u,0x000000c9u,0x0031306du,0x00030005u,0x000000d5u,0x0030316du,0x00030005u,0x000000e0u,0x00004170u,0x00030005u,0x000000e8u,0x00004270u,0x00030005u,0x000000f0u,0x00003043u,0x00040005u,0x000000f1u,0x65725075u,0x00000076u,0x00030005u,0x000000f6u,0x00003143u,0x00030005u,0x000000fbu,0x00004165u,0x00040005u,0x000000fcu,0x61726170u,0x0000006du,0x00040005u,0x0000010cu,0x61726170u,0x0000006du,0x00030005u,0x00000111u,0x00004265u,0x00040005u,0x00000112u,0x61726170u,0x0000006du,0x00040005u,0x00000122u,0x61726170u,0x0000006du,0x00040005u,0x00000127u,0x76556266u,0x00000000u,0x00040005u,0x0000012bu,0x65526266u,0x00646973u,0x00040005u,0x00000138u,0x736e6f63u,0x00747369u,0x00030005u,0x00000149u,0x0000305au,0x00030005u,0x00000157u,0x0000315au,0x00040005u,0x00000163u,0x30756174u,0x00000000u,0x00040005u,0x00000167u,0x31756174u,0x00000000u,0x00040005u,0x0000016au,0x78616d7au,0x00000000u,0x00030005u,0x0000016eu,0x00003057u,0x00030005u,0x00000179u,0x00003157u,0x00040005u,0x00000183u,0x6d757357u,0x00000000u,0x00040005u,0x00000187u,0x70726177u,0x00006465u,0x00050005u,0x000001a0u,0x736f7263u,0x64616673u,0x00000065u,0x00050005u,0x000001adu,0x746f6870u,0x7272456fu,0x00000000u,0x00050005u,0x000001b1u,0x746f6870u,0x7572546fu,0x00007473u,0x00040005u,0x000001b7u,0x73757274u,0x00000074u,0x00040005u,0x000001c3u,0x76657270u,0x00000043u,0x00040005u,0x000001c8u,0x72727563u,0x00000043u,0x00050005u,0x000001cdu,0x746e6f63u,0x44746e65u,0x00666669u,0x00050005u,0x000001d2u,0x72746e75u,0x65747375u,0x00000064u,0x00040005u,0x000001d7u,0x44676962u,0x00666669u,0x00050005u,0x000001dcu,0x70616e73u,0x75436f54u,0x00007272u,0x00040005u,0x000001e5u,0x6374756fu,0x00000000u,0x00030005u,0x000001eeu,0x0067616du,0x00030005u,0x000001f2u,0x0000006eu,0x00030005u,0x000001f6u,0x00746173u,0x00040047u,0x0000001cu,0x0000000bu,0x0000001cu,0x00030047u,0x00000024u,0x00000019u,0x00040047u,0x00000024u,0x00000021u,0x00000030u,0x00040047u,0x00000024u,0x00000022u,0x00000000u,0x00030047u,0x0000004du,0x00000002u,0x00050048u,0x0000004du,0x00000000u,0x00000023u,0x00000000u,0x00050048u,0x0000004du,0x00000001u,0x00000023u,0x00000004u,0x00050048u,0x0000004du,0x00000002u,0x00000023u,0x00000008u,0x00050048u,0x0000004du,0x00000003u,0x00000023u,0x0000000cu,0x00050048u,0x0000004du,0x00000004u,0x00000023u,0x00000010u,0x00050048u,0x0000004du,0x00000005u,0x00000023u,0x00000014u,0x00050048u,0x0000004du,0x00000006u,0x00000023u,0x00000018u,0x00050048u,0x0000004du,0x00000007u,0x00000023u,0x0000001cu,0x00050048u,0x0000004du,0x00000008u,0x00000023u,0x00000020u,0x00040047u,0x0000004fu,0x00000021u,0x00000000u,0x00040047u,0x0000004fu,0x00000022u,0x00000000u,0x00040047u,0x0000008cu,0x00000021u,0x00000021u,0x00040047u,0x0000008cu,0x00000022u,0x00000000u,0x00040047u,0x000000aau,0x00000021u,0x00000023u,0x00040047u,0x000000aau,0x00000022u,0x00000000u,0x00040047u,0x000000afu,0x00000021u,0x00000022u,0x00040047u,0x000000afu,0x00000022u,0x00000000u,0x00040047u,0x000000f1u,0x00000021u,0x00000020u,0x00040047u,0x000000f1u,0Line truncated
|
||||
static const size_t DDFG_SYNTH_LEN = 3082;
|
||||
struct Blob { const uint32_t* code; size_t words; };
|
||||
enum Shader { OF3_LUMA, OF3_DOWNSAMPLE, OF3_FLOW, OF3_EXPAND, OF3_FLOW_M4, OF3_EXPAND_M4, OF3_GM_REDUCE, OF3_GM_PREWARP, OF3_FLOWREG, WFG_SYNTH, SHADER_COUNT };
|
||||
enum Shader { OF3_LUMA, OF3_DOWNSAMPLE, OF3_FLOW, OF3_EXPAND, OF3_FLOW_M4, OF3_EXPAND_M4, OF3_GM_REDUCE, OF3_GM_PREWARP, OF3_FLOWREG, DDFG_SYNTH, SHADER_COUNT };
|
||||
static inline Blob blob(Shader s) {
|
||||
switch (s) {
|
||||
case OF3_LUMA: return { OF3_LUMA_SPV, OF3_LUMA_LEN };
|
||||
@@ -35,7 +35,7 @@ static inline Blob blob(Shader s) {
|
||||
case OF3_GM_REDUCE: return { OF3_GM_REDUCE_SPV, OF3_GM_REDUCE_LEN };
|
||||
case OF3_GM_PREWARP: return { OF3_GM_PREWARP_SPV, OF3_GM_PREWARP_LEN };
|
||||
case OF3_FLOWREG: return { OF3_FLOWREG_SPV, OF3_FLOWREG_LEN };
|
||||
case WFG_SYNTH: return { WFG_SYNTH_SPV, WFG_SYNTH_LEN };
|
||||
case DDFG_SYNTH: return { DDFG_SYNTH_SPV, DDFG_SYNTH_LEN };
|
||||
default: return { nullptr, 0 };
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -4,9 +4,9 @@
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
|
||||
namespace winfg {
|
||||
namespace ddfg {
|
||||
|
||||
#define VKOK(x) do { if ((x) != VK_SUCCESS) { WFG_LOGE("vk fail: %s", #x); return false; } } while (0)
|
||||
#define VKOK(x) do { if ((x) != VK_SUCCESS) { DDFG_LOGE("vk fail: %s", #x); return false; } } while (0)
|
||||
|
||||
uint32_t FrameGen::findMemType(uint32_t bits, VkMemoryPropertyFlags props) const {
|
||||
for (uint32_t i = 0; i < memProps_.memoryTypeCount; ++i)
|
||||
@@ -153,9 +153,9 @@ bool FrameGen::init(const DeviceDispatch* dd, const InstanceDispatch* id,
|
||||
if (!makePipe(pGmReduce_, embedded::OF3_GM_REDUCE, unused)) return false;
|
||||
if (!makePipe(pGmPrewarp_, embedded::OF3_GM_PREWARP, unused)) return false;
|
||||
if (!makePipe(pFlowReg_, embedded::OF3_FLOWREG, unused)) return false;
|
||||
if (!makePipe(pSynth_, embedded::WFG_SYNTH, unused)) return false;
|
||||
if (!makeGmBuffers()) { WFG_LOGE("framegen: GM SSBO alloc failed - C1 disabled"); }
|
||||
WFG_LOGI("framegen init ok (queueFamily=%u, 10 pipelines, model=%d, C1 gm=%d, C2 flow_reg=%d iters=%d)",
|
||||
if (!makePipe(pSynth_, embedded::DDFG_SYNTH, unused)) return false;
|
||||
if (!makeGmBuffers()) { DDFG_LOGE("framegen: GM SSBO alloc failed - C1 disabled"); }
|
||||
DDFG_LOGI("framegen init ok (queueFamily=%u, 10 pipelines, model=%d, C1 gm=%d, C2 flow_reg=%d iters=%d)",
|
||||
queueFamily_, cfg_.model, cfg_.gmMode, cfg_.frMode, cfg_.frIters);
|
||||
return true;
|
||||
}
|
||||
@@ -194,7 +194,7 @@ bool FrameGen::onResize(VkExtent2D extent, VkFormat , bool force) {
|
||||
if (!makeImage(flowRegA_, levelExtent(extent, flowFinest_), VK_FORMAT_R16G16B16A16_SFLOAT, regUsage)) return false;
|
||||
if (!makeImage(flowRegB_, levelExtent(extent, flowFinest_), VK_FORMAT_R16G16B16A16_SFLOAT, regUsage)) return false;
|
||||
ready_ = true;
|
||||
WFG_LOGI("framegen resized to %ux%u (%d pyramid levels, kFlowFinest=%d perf_preset=%d)",
|
||||
DDFG_LOGI("framegen resized to %ux%u (%d pyramid levels, kFlowFinest=%d perf_preset=%d)",
|
||||
extent.width, extent.height, kLevels, flowFinest_, cfg_.perfPreset);
|
||||
return true;
|
||||
}
|
||||
+4
-2
@@ -3,7 +3,7 @@
|
||||
#include "config.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace winfg {
|
||||
namespace ddfg {
|
||||
|
||||
class FrameGen {
|
||||
public:
|
||||
@@ -12,7 +12,8 @@ public:
|
||||
void configure(const Config& c);
|
||||
bool onResize(VkExtent2D extent, VkFormat colorFormat, bool force = false);
|
||||
void record(VkCommandBuffer cmd, VkImageView prevView, VkImageView currView,
|
||||
VkImageView outView, float alpha, uint32_t gmSlot = 0);
|
||||
VkImageView outView, float alpha, uint32_t gmSlot = 0,
|
||||
uint32_t synthSlot = 0, bool reuseFlow = false);
|
||||
void destroy();
|
||||
bool valid() const { return device_ != VK_NULL_HANDLE && ready_; }
|
||||
const Config& config() const { return cfg_; }
|
||||
@@ -25,6 +26,7 @@ public:
|
||||
|
||||
|
||||
static constexpr int kGmSlots = 3;
|
||||
static constexpr int kSynthSlots = 3;
|
||||
static constexpr int kGmLevel = 3;
|
||||
static constexpr int kGmThreads = 512;
|
||||
static constexpr int kGmStride = 32;
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#if defined(__ANDROID__)
|
||||
#include <android/log.h>
|
||||
#define DDFG_LOGI(...) __android_log_print(ANDROID_LOG_INFO, "dd-fg", __VA_ARGS__)
|
||||
#define DDFG_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "dd-fg", __VA_ARGS__)
|
||||
#else
|
||||
#include <cstdio>
|
||||
#define DDFG_LOGI(...) do { std::fprintf(stderr, "[dd-fg] " __VA_ARGS__); std::fprintf(stderr, "\n"); } while(0)
|
||||
#define DDFG_LOGE(...) do { std::fprintf(stderr, "[dd-fg][E] " __VA_ARGS__); std::fprintf(stderr, "\n"); } while(0)
|
||||
#endif
|
||||
|
||||
#define DDFG_LOGD(cond, ...) do { if (cond) DDFG_LOGI(__VA_ARGS__); } while(0)
|
||||
+159
-142
@@ -1,31 +1,34 @@
|
||||
|
||||
namespace {
|
||||
struct ScratchState {
|
||||
VkBuffer synthUbo = VK_NULL_HANDLE; VkDeviceMemory synthUboMem = VK_NULL_HANDLE; void* synthUboPtr = nullptr;
|
||||
VkBuffer synthUbo[ddfg::FrameGen::kSynthSlots]{};
|
||||
VkDeviceMemory synthUboMem[ddfg::FrameGen::kSynthSlots]{};
|
||||
void* synthUboPtr[ddfg::FrameGen::kSynthSlots]{};
|
||||
std::vector<VkBuffer> flowUbo; std::vector<VkDeviceMemory> flowUboMem; std::vector<void*> flowUboPtr;
|
||||
VkBuffer expandUbo = VK_NULL_HANDLE; VkDeviceMemory expandUboMem = VK_NULL_HANDLE; void* expandUboPtr = nullptr;
|
||||
VkBuffer flowRegUbo = VK_NULL_HANDLE; VkDeviceMemory flowRegUboMem = VK_NULL_HANDLE; void* flowRegUboPtr = nullptr;
|
||||
VkBuffer gmUbo[winfg::FrameGen::kGmSlots]{};
|
||||
VkDeviceMemory gmUboMem[winfg::FrameGen::kGmSlots]{};
|
||||
void* gmUboPtr[winfg::FrameGen::kGmSlots]{};
|
||||
VkBuffer gmUbo[ddfg::FrameGen::kGmSlots]{};
|
||||
VkDeviceMemory gmUboMem[ddfg::FrameGen::kGmSlots]{};
|
||||
void* gmUboPtr[ddfg::FrameGen::kGmSlots]{};
|
||||
VkDescriptorSet sLumaCurr = VK_NULL_HANDLE, sLumaPrev = VK_NULL_HANDLE;
|
||||
std::vector<VkDescriptorSet> sDownA, sDownB, sFlow;
|
||||
VkDescriptorSet sExpand[winfg::FrameGen::kGmSlots]{};
|
||||
VkDescriptorSet sExpand[ddfg::FrameGen::kGmSlots]{};
|
||||
|
||||
|
||||
|
||||
VkDescriptorSet sFlowReg0 = VK_NULL_HANDLE, sFlowRegAB = VK_NULL_HANDLE, sFlowRegBA = VK_NULL_HANDLE;
|
||||
VkDescriptorSet sSynth = VK_NULL_HANDLE;
|
||||
VkDescriptorSet sGmReduce[winfg::FrameGen::kGmSlots]{};
|
||||
std::vector<VkDescriptorSet> sGmPrewarp[winfg::FrameGen::kGmSlots];
|
||||
VkDescriptorSet sSynth[ddfg::FrameGen::kSynthSlots]{};
|
||||
VkDescriptorSet sGmReduce[ddfg::FrameGen::kGmSlots]{};
|
||||
std::vector<VkDescriptorSet> sGmPrewarp[ddfg::FrameGen::kGmSlots];
|
||||
VkExtent2D builtFor{0,0};
|
||||
bool built = false;
|
||||
bool flowInited = false;
|
||||
bool flowReady = false;
|
||||
};
|
||||
ScratchState g_scratch;
|
||||
}
|
||||
|
||||
static bool makeUbo(const winfg::DeviceDispatch* dd, VkDevice dev,
|
||||
static bool makeUbo(const ddfg::DeviceDispatch* dd, VkDevice dev,
|
||||
const VkPhysicalDeviceMemoryProperties& mp,
|
||||
VkDeviceSize size, VkBuffer& buf, VkDeviceMemory& mem, void*& ptr) {
|
||||
VkBufferCreateInfo bi{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO};
|
||||
@@ -41,21 +44,21 @@ static bool makeUbo(const winfg::DeviceDispatch* dd, VkDevice dev,
|
||||
return dd->MapMemory(dev, mem, 0, size, 0, &ptr) == VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkDescriptorSet allocSet(const winfg::DeviceDispatch* dd, VkDevice dev,
|
||||
static VkDescriptorSet allocSet(const ddfg::DeviceDispatch* dd, VkDevice dev,
|
||||
VkDescriptorPool pool, VkDescriptorSetLayout layout) {
|
||||
VkDescriptorSetAllocateInfo ai{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO};
|
||||
ai.descriptorPool = pool; ai.descriptorSetCount = 1; ai.pSetLayouts = &layout;
|
||||
VkDescriptorSet s = VK_NULL_HANDLE; dd->AllocateDescriptorSets(dev, &ai, &s); return s;
|
||||
}
|
||||
|
||||
static void wImg(const winfg::DeviceDispatch* dd, VkDevice dev, VkDescriptorSet set, uint32_t binding,
|
||||
static void wImg(const ddfg::DeviceDispatch* dd, VkDevice dev, VkDescriptorSet set, uint32_t binding,
|
||||
VkDescriptorType type, VkImageView view, VkSampler samp, VkImageLayout layout) {
|
||||
VkDescriptorImageInfo ii{}; ii.imageView = view; ii.sampler = samp; ii.imageLayout = layout;
|
||||
VkWriteDescriptorSet w{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET};
|
||||
w.dstSet = set; w.dstBinding = binding; w.descriptorCount = 1; w.descriptorType = type; w.pImageInfo = ⅈ
|
||||
dd->UpdateDescriptorSets(dev, 1, &w, 0, nullptr);
|
||||
}
|
||||
static void wUbo(const winfg::DeviceDispatch* dd, VkDevice dev, VkDescriptorSet set, uint32_t binding,
|
||||
static void wUbo(const ddfg::DeviceDispatch* dd, VkDevice dev, VkDescriptorSet set, uint32_t binding,
|
||||
VkBuffer buf, VkDeviceSize range) {
|
||||
VkDescriptorBufferInfo bi{}; bi.buffer = buf; bi.range = range;
|
||||
VkWriteDescriptorSet w{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET};
|
||||
@@ -63,7 +66,7 @@ static void wUbo(const winfg::DeviceDispatch* dd, VkDevice dev, VkDescriptorSet
|
||||
w.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; w.pBufferInfo = &bi;
|
||||
dd->UpdateDescriptorSets(dev, 1, &w, 0, nullptr);
|
||||
}
|
||||
static void wSsbo(const winfg::DeviceDispatch* dd, VkDevice dev, VkDescriptorSet set, uint32_t binding,
|
||||
static void wSsbo(const ddfg::DeviceDispatch* dd, VkDevice dev, VkDescriptorSet set, uint32_t binding,
|
||||
VkBuffer buf, VkDeviceSize range) {
|
||||
VkDescriptorBufferInfo bi{}; bi.buffer = buf; bi.range = range;
|
||||
VkWriteDescriptorSet w{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET};
|
||||
@@ -117,7 +120,7 @@ static void mulAff(const double A[3][3], const double B[3][3], double out[3][3])
|
||||
out[2][0]=0.0; out[2][1]=0.0; out[2][2]=1.0;
|
||||
}
|
||||
|
||||
namespace winfg {
|
||||
namespace ddfg {
|
||||
|
||||
static bool ensureScratch(FrameGen* fg, const DeviceDispatch* dd, VkDevice dev,
|
||||
const VkPhysicalDeviceMemoryProperties& mp, VkDescriptorPool pool,
|
||||
@@ -140,7 +143,7 @@ static void destroyScratch(const DeviceDispatch* dd, VkDevice dev, VkDescriptorP
|
||||
b = VK_NULL_HANDLE; m = VK_NULL_HANDLE; p = nullptr;
|
||||
};
|
||||
auto& S = g_scratch;
|
||||
freeUbo(S.synthUbo, S.synthUboMem, S.synthUboPtr);
|
||||
for (int s = 0; s < FrameGen::kSynthSlots; ++s) freeUbo(S.synthUbo[s], S.synthUboMem[s], S.synthUboPtr[s]);
|
||||
freeUbo(S.expandUbo, S.expandUboMem, S.expandUboPtr);
|
||||
freeUbo(S.flowRegUbo, S.flowRegUboMem, S.flowRegUboPtr);
|
||||
for (size_t i = 0; i < S.flowUbo.size(); ++i) freeUbo(S.flowUbo[i], S.flowUboMem[i], S.flowUboPtr[i]);
|
||||
@@ -154,7 +157,7 @@ void FrameGen::configure(const Config& c) {
|
||||
int want = flowFinestForPreset(cfg_.perfPreset);
|
||||
const int maxFinest = kLevels - 2;
|
||||
if (want > maxFinest) {
|
||||
WFG_LOGE("perf-preset=%d wants kFlowFinest=%d but only %d pyramid levels exist "
|
||||
DDFG_LOGE("perf-preset=%d wants kFlowFinest=%d but only %d pyramid levels exist "
|
||||
"(need >=2 solved) - clamping to %d", cfg_.perfPreset, want, kLevels, maxFinest);
|
||||
want = maxFinest;
|
||||
}
|
||||
@@ -163,7 +166,7 @@ void FrameGen::configure(const Config& c) {
|
||||
const int prevFinest = flowFinest_;
|
||||
flowFinest_ = want;
|
||||
const bool live = (flowFinest_ != prevFinest) && ready_;
|
||||
WFG_LOGI("perf-preset=%d -> kFlowFinest=%d (was %d) live-rebuild=%d ready=%d",
|
||||
DDFG_LOGI("perf-preset=%d -> kFlowFinest=%d (was %d) live-rebuild=%d ready=%d",
|
||||
cfg_.perfPreset, flowFinest_, prevFinest, live ? 1 : 0, ready_ ? 1 : 0);
|
||||
|
||||
if (!live) return;
|
||||
@@ -174,12 +177,12 @@ void FrameGen::configure(const Config& c) {
|
||||
dd_->DeviceWaitIdle(device_);
|
||||
destroyScratch(dd_, device_, descPool_);
|
||||
if (!onResize(extent_, VK_FORMAT_UNDEFINED, true))
|
||||
WFG_LOGE("perf-preset live rebuild: onResize FAILED at %ux%u - FG disabled until next resize",
|
||||
DDFG_LOGE("perf-preset live rebuild: onResize FAILED at %ux%u - FG disabled until next resize",
|
||||
extent_.width, extent_.height);
|
||||
for (int i = 0; i < 6; ++i) gmRun_[i] = 0.0;
|
||||
for (int s = 0; s < kGmSlots; ++s) { gmSlotValid_[s] = false; for (int i = 0; i < 6; ++i) gmLinAt_[s][i] = 0.0; }
|
||||
gmHaveEst_ = false; gmEngaged_ = false; gmStableCount_ = 0; gmLastTransPx_ = 0.0f;
|
||||
WFG_LOGI("perf-preset live rebuild DONE (kFlowFinest=%d, flow predictor reset)", flowFinest_);
|
||||
DDFG_LOGI("perf-preset live rebuild DONE (kFlowFinest=%d, flow predictor reset)", flowFinest_);
|
||||
}
|
||||
|
||||
bool FrameGen::updateGlobalMotion(uint32_t gmSlot, VkExtent2D fullExtent) {
|
||||
@@ -249,9 +252,10 @@ bool FrameGen::updateGlobalMotion(uint32_t gmSlot, VkExtent2D fullExtent) {
|
||||
}
|
||||
|
||||
void FrameGen::record(VkCommandBuffer cmd, VkImageView prevView, VkImageView currView,
|
||||
VkImageView outView, float alpha, uint32_t gmSlot) {
|
||||
VkImageView outView, float alpha, uint32_t gmSlot, uint32_t synthSlot, bool reuseFlow) {
|
||||
if (!valid()) return;
|
||||
if (gmSlot >= (uint32_t)kGmSlots) gmSlot = 0;
|
||||
if (synthSlot >= (uint32_t)kSynthSlots) synthSlot = 0;
|
||||
const bool m4 = (cfg_.model == 4);
|
||||
const Pipe& flowP = m4 ? pFlowM4_ : pFlow_;
|
||||
const Pipe& expandP = m4 ? pExpandM4_ : pExpand_;
|
||||
@@ -263,35 +267,42 @@ void FrameGen::record(VkCommandBuffer cmd, VkImageView prevView, VkImageView cur
|
||||
pFlowReg_, flowRegA_, flowRegB_, gmSsbo_, kLevels, cfg_);
|
||||
}
|
||||
|
||||
bool gmEngaged = updateGlobalMotion(gmSlot, extent_);
|
||||
if (g_scratch.gmUboPtr[gmSlot]) {
|
||||
GMUBO g{};
|
||||
g.lin[0]=(float)gmRun_[0]; g.lin[1]=(float)gmRun_[1]; g.lin[2]=(float)gmRun_[2]; g.lin[3]=(float)gmRun_[3];
|
||||
g.linT[0]=(float)gmRun_[4]; g.linT[1]=(float)gmRun_[5]; g.linT[2]=gmEngaged?1.0f:0.0f; g.linT[3]=0.0f;
|
||||
if (gmEngaged) {
|
||||
g.app[0]=(float)gmRun_[0]; g.app[1]=(float)gmRun_[1]; g.app[2]=(float)gmRun_[2]; g.app[3]=(float)gmRun_[3];
|
||||
g.appT[0]=(float)gmRun_[4]; g.appT[1]=(float)gmRun_[5];
|
||||
// Every generation of one real frame is recorded into the same command buffer, so the flow
|
||||
// between prev and curr is computed once and each generation gets its own synth UBO and set.
|
||||
if (reuseFlow && !g_scratch.flowReady) return;
|
||||
if (!reuseFlow) {
|
||||
bool gmEngaged = updateGlobalMotion(gmSlot, extent_);
|
||||
if (g_scratch.gmUboPtr[gmSlot]) {
|
||||
GMUBO g{};
|
||||
g.lin[0]=(float)gmRun_[0]; g.lin[1]=(float)gmRun_[1]; g.lin[2]=(float)gmRun_[2]; g.lin[3]=(float)gmRun_[3];
|
||||
g.linT[0]=(float)gmRun_[4]; g.linT[1]=(float)gmRun_[5]; g.linT[2]=gmEngaged?1.0f:0.0f; g.linT[3]=0.0f;
|
||||
if (gmEngaged) {
|
||||
g.app[0]=(float)gmRun_[0]; g.app[1]=(float)gmRun_[1]; g.app[2]=(float)gmRun_[2]; g.app[3]=(float)gmRun_[3];
|
||||
g.appT[0]=(float)gmRun_[4]; g.appT[1]=(float)gmRun_[5];
|
||||
}
|
||||
std::memcpy(g_scratch.gmUboPtr[gmSlot], &g, sizeof(g));
|
||||
}
|
||||
std::memcpy(g_scratch.gmUboPtr[gmSlot], &g, sizeof(g));
|
||||
}
|
||||
{
|
||||
static int lastEng = -1;
|
||||
if (gmEngaged != (lastEng == 1) || (gmFrames_ % 300ull) == 0) {
|
||||
WFG_LOGI("C1 global-motion: engaged=%d mode=%d stable=%d transPx=%.1f (model=%d)",
|
||||
gmEngaged ? 1 : 0, cfg_.gmMode, gmStableCount_, gmLastTransPx_, cfg_.model);
|
||||
lastEng = gmEngaged ? 1 : 0;
|
||||
{
|
||||
static int lastEng = -1;
|
||||
if (gmEngaged != (lastEng == 1) || (gmFrames_ % 300ull) == 0) {
|
||||
DDFG_LOGI("C1 global-motion: engaged=%d mode=%d stable=%d transPx=%.1f (model=%d)",
|
||||
gmEngaged ? 1 : 0, cfg_.gmMode, gmStableCount_, gmLastTransPx_, cfg_.model);
|
||||
lastEng = gmEngaged ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
wImg(dd_, device_, g_scratch.sLumaCurr, 32, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, currView, linear_, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
wImg(dd_, device_, g_scratch.sLumaPrev, 32, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, prevView, linear_, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
}
|
||||
|
||||
SynthUBO su{cfg_.flowScale, alpha, cfg_.beta, cfg_.lambda, cfg_.epsilon, cfg_.photoScale, 0, 0,
|
||||
cfg_.hudX0, cfg_.hudY0, cfg_.hudX1, cfg_.hudY1};
|
||||
if (g_scratch.synthUboPtr) std::memcpy(g_scratch.synthUboPtr, &su, sizeof(su));
|
||||
if (g_scratch.synthUboPtr[synthSlot]) std::memcpy(g_scratch.synthUboPtr[synthSlot], &su, sizeof(su));
|
||||
|
||||
wImg(dd_, device_, g_scratch.sLumaCurr, 32, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, currView, linear_, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
wImg(dd_, device_, g_scratch.sLumaPrev, 32, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, prevView, linear_, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
wImg(dd_, device_, g_scratch.sSynth, 32, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, prevView, linear_, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
wImg(dd_, device_, g_scratch.sSynth, 33, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, currView, linear_, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
wImg(dd_, device_, g_scratch.sSynth, 48, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, outView, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_GENERAL);
|
||||
const VkDescriptorSet synthSet = g_scratch.sSynth[synthSlot];
|
||||
wImg(dd_, device_, synthSet, 32, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, prevView, linear_, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
wImg(dd_, device_, synthSet, 33, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, currView, linear_, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
wImg(dd_, device_, synthSet, 48, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, outView, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_GENERAL);
|
||||
|
||||
auto disp = [&](const Pipe& p, VkDescriptorSet set, VkExtent2D e) {
|
||||
dd_->CmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, p.pipeline);
|
||||
@@ -300,106 +311,109 @@ void FrameGen::record(VkCommandBuffer cmd, VkImageView prevView, VkImageView cur
|
||||
};
|
||||
auto bar = [&](FrameGen::Img& i){ barrier(cmd, i.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); };
|
||||
|
||||
for (auto& i : pyrA_) barrier(cmd, i.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
for (auto& i : pyrB_) barrier(cmd, i.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
for (int l = flowFinest_; l < kLevels; ++l) barrier(cmd, pyrAs_[l].image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
barrier(cmd, flowExpA_.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
barrier(cmd, flowExpB_.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
barrier(cmd, flowRegA_.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
barrier(cmd, flowRegB_.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
{
|
||||
VkClearColorValue zero{};
|
||||
VkImageSubresourceRange rng{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||
if (!reuseFlow) {
|
||||
for (auto& i : pyrA_) barrier(cmd, i.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
for (auto& i : pyrB_) barrier(cmd, i.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
for (int l = flowFinest_; l < kLevels; ++l) barrier(cmd, pyrAs_[l].image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
barrier(cmd, flowExpA_.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
barrier(cmd, flowExpB_.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
barrier(cmd, flowRegA_.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
barrier(cmd, flowRegB_.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||
{
|
||||
VkClearColorValue zero{};
|
||||
VkImageSubresourceRange rng{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||
for (int l = flowFinest_; l < kLevels; ++l) {
|
||||
VkImageMemoryBarrier b{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
|
||||
b.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; b.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
b.srcAccessMask = 0; b.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
b.image = flowLvl_[l].image; b.subresourceRange = rng;
|
||||
b.srcQueueFamilyIndex = b.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
dd_->CmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &b);
|
||||
dd_->CmdClearColorImage(cmd, flowLvl_[l].image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &zero, 1, &rng);
|
||||
b.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; b.newLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
b.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; b.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
||||
dd_->CmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &b);
|
||||
}
|
||||
}
|
||||
|
||||
disp(pLuma_, g_scratch.sLumaCurr, levelExtent(extent_, 0));
|
||||
disp(pLuma_, g_scratch.sLumaPrev, levelExtent(extent_, 0));
|
||||
bar(pyrA_[0]); bar(pyrB_[0]);
|
||||
for (int l = 1; l < kLevels; ++l) {
|
||||
disp(pDown_, g_scratch.sDownA[l - 1], levelExtent(extent_, l));
|
||||
disp(pDown_, g_scratch.sDownB[l - 1], levelExtent(extent_, l));
|
||||
bar(pyrA_[l]); bar(pyrB_[l]);
|
||||
}
|
||||
if (gmBuffersReady_ && g_scratch.sGmReduce[gmSlot]) {
|
||||
dd_->CmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pGmReduce_.pipeline);
|
||||
dd_->CmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pGmReduce_.layout, 0, 1, &g_scratch.sGmReduce[gmSlot], 0, nullptr);
|
||||
dd_->CmdDispatch(cmd, (uint32_t)(kGmThreads / 64), 1, 1);
|
||||
VkMemoryBarrier mb{VK_STRUCTURE_TYPE_MEMORY_BARRIER};
|
||||
mb.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; mb.dstAccessMask = VK_ACCESS_HOST_READ_BIT;
|
||||
dd_->CmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
|
||||
0, 1, &mb, 0, nullptr, 0, nullptr);
|
||||
}
|
||||
for (int l = flowFinest_; l < kLevels; ++l) {
|
||||
VkImageMemoryBarrier b{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
|
||||
b.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; b.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
b.srcAccessMask = 0; b.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
b.image = flowLvl_[l].image; b.subresourceRange = rng;
|
||||
b.srcQueueFamilyIndex = b.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
dd_->CmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &b);
|
||||
dd_->CmdClearColorImage(cmd, flowLvl_[l].image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &zero, 1, &rng);
|
||||
b.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; b.newLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
b.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; b.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
||||
dd_->CmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &b);
|
||||
disp(pGmPrewarp_, g_scratch.sGmPrewarp[gmSlot][l], levelExtent(extent_, l));
|
||||
bar(pyrAs_[l]);
|
||||
}
|
||||
for (int l = kLevels - 1; l >= flowFinest_; --l) {
|
||||
disp(flowP, g_scratch.sFlow[l], levelExtent(extent_, l));
|
||||
bar(flowLvl_[l]);
|
||||
}
|
||||
}
|
||||
|
||||
disp(pLuma_, g_scratch.sLumaCurr, levelExtent(extent_, 0));
|
||||
disp(pLuma_, g_scratch.sLumaPrev, levelExtent(extent_, 0));
|
||||
bar(pyrA_[0]); bar(pyrB_[0]);
|
||||
for (int l = 1; l < kLevels; ++l) {
|
||||
disp(pDown_, g_scratch.sDownA[l - 1], levelExtent(extent_, l));
|
||||
disp(pDown_, g_scratch.sDownB[l - 1], levelExtent(extent_, l));
|
||||
bar(pyrA_[l]); bar(pyrB_[l]);
|
||||
}
|
||||
if (gmBuffersReady_ && g_scratch.sGmReduce[gmSlot]) {
|
||||
dd_->CmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pGmReduce_.pipeline);
|
||||
dd_->CmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pGmReduce_.layout, 0, 1, &g_scratch.sGmReduce[gmSlot], 0, nullptr);
|
||||
dd_->CmdDispatch(cmd, (uint32_t)(kGmThreads / 64), 1, 1);
|
||||
VkMemoryBarrier mb{VK_STRUCTURE_TYPE_MEMORY_BARRIER};
|
||||
mb.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; mb.dstAccessMask = VK_ACCESS_HOST_READ_BIT;
|
||||
dd_->CmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
|
||||
0, 1, &mb, 0, nullptr, 0, nullptr);
|
||||
}
|
||||
for (int l = flowFinest_; l < kLevels; ++l) {
|
||||
disp(pGmPrewarp_, g_scratch.sGmPrewarp[gmSlot][l], levelExtent(extent_, l));
|
||||
bar(pyrAs_[l]);
|
||||
}
|
||||
for (int l = kLevels - 1; l >= flowFinest_; --l) {
|
||||
disp(flowP, g_scratch.sFlow[l], levelExtent(extent_, l));
|
||||
bar(flowLvl_[l]);
|
||||
}
|
||||
const bool frEngaged = (cfg_.frMode != 2) && (cfg_.frIters > 0);
|
||||
if (frEngaged) {
|
||||
const int F = flowFinest_;
|
||||
const VkExtent2D fe = levelExtent(extent_, F);
|
||||
if (g_scratch.flowRegUboPtr) {
|
||||
FlowRegUBO fu{cfg_.frDt, cfg_.frLambda, cfg_.frEdge, cfg_.frEps};
|
||||
std::memcpy(g_scratch.flowRegUboPtr, &fu, sizeof(fu));
|
||||
}
|
||||
FrameGen::Img* last = nullptr;
|
||||
for (int it = 0; it < cfg_.frIters; ++it) {
|
||||
VkDescriptorSet set; FrameGen::Img* outImg;
|
||||
if (it == 0) { set = g_scratch.sFlowReg0; outImg = &flowRegA_; }
|
||||
else if (it % 2 == 1) { set = g_scratch.sFlowRegAB; outImg = &flowRegB_; }
|
||||
else { set = g_scratch.sFlowRegBA; outImg = &flowRegA_; }
|
||||
dd_->CmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pFlowReg_.pipeline);
|
||||
dd_->CmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pFlowReg_.layout, 0, 1, &set, 0, nullptr);
|
||||
dd_->CmdDispatch(cmd, (fe.width + 15) / 16, (fe.height + 15) / 16, 1);
|
||||
bar(*outImg);
|
||||
last = outImg;
|
||||
}
|
||||
VkMemoryBarrier mb{VK_STRUCTURE_TYPE_MEMORY_BARRIER};
|
||||
mb.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
||||
mb.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
dd_->CmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, 1, &mb, 0, nullptr, 0, nullptr);
|
||||
VkImageCopy region{};
|
||||
region.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
|
||||
region.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
|
||||
region.extent = {fe.width, fe.height, 1};
|
||||
dd_->CmdCopyImage(cmd, last->image, VK_IMAGE_LAYOUT_GENERAL,
|
||||
flowLvl_[F].image, VK_IMAGE_LAYOUT_GENERAL, 1, ®ion);
|
||||
VkMemoryBarrier mb2{VK_STRUCTURE_TYPE_MEMORY_BARRIER};
|
||||
mb2.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
mb2.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
dd_->CmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
0, 1, &mb2, 0, nullptr, 0, nullptr);
|
||||
}
|
||||
{
|
||||
static int lastFr = -1;
|
||||
int fe = frEngaged ? 1 : 0;
|
||||
if (fe != lastFr || (gmFrames_ % 300ull) == 0) {
|
||||
DDFG_LOGI("C2 flow-reg: engaged=%d mode=%d iters=%d lambda=%.2f dt=%.2f edge=%.1f eps=%.3f (model=%d)",
|
||||
fe, cfg_.frMode, cfg_.frIters, cfg_.frLambda, cfg_.frDt, cfg_.frEdge, cfg_.frEps, cfg_.model);
|
||||
lastFr = fe;
|
||||
}
|
||||
}
|
||||
|
||||
const bool frEngaged = (cfg_.frMode != 2) && (cfg_.frIters > 0);
|
||||
if (frEngaged) {
|
||||
const int F = flowFinest_;
|
||||
const VkExtent2D fe = levelExtent(extent_, F);
|
||||
if (g_scratch.flowRegUboPtr) {
|
||||
FlowRegUBO fu{cfg_.frDt, cfg_.frLambda, cfg_.frEdge, cfg_.frEps};
|
||||
std::memcpy(g_scratch.flowRegUboPtr, &fu, sizeof(fu));
|
||||
}
|
||||
FrameGen::Img* last = nullptr;
|
||||
for (int it = 0; it < cfg_.frIters; ++it) {
|
||||
VkDescriptorSet set; FrameGen::Img* outImg;
|
||||
if (it == 0) { set = g_scratch.sFlowReg0; outImg = &flowRegA_; }
|
||||
else if (it % 2 == 1) { set = g_scratch.sFlowRegAB; outImg = &flowRegB_; }
|
||||
else { set = g_scratch.sFlowRegBA; outImg = &flowRegA_; }
|
||||
dd_->CmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pFlowReg_.pipeline);
|
||||
dd_->CmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pFlowReg_.layout, 0, 1, &set, 0, nullptr);
|
||||
dd_->CmdDispatch(cmd, (fe.width + 15) / 16, (fe.height + 15) / 16, 1);
|
||||
bar(*outImg);
|
||||
last = outImg;
|
||||
}
|
||||
VkMemoryBarrier mb{VK_STRUCTURE_TYPE_MEMORY_BARRIER};
|
||||
mb.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
||||
mb.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
dd_->CmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, 1, &mb, 0, nullptr, 0, nullptr);
|
||||
VkImageCopy region{};
|
||||
region.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
|
||||
region.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
|
||||
region.extent = {fe.width, fe.height, 1};
|
||||
dd_->CmdCopyImage(cmd, last->image, VK_IMAGE_LAYOUT_GENERAL,
|
||||
flowLvl_[F].image, VK_IMAGE_LAYOUT_GENERAL, 1, ®ion);
|
||||
VkMemoryBarrier mb2{VK_STRUCTURE_TYPE_MEMORY_BARRIER};
|
||||
mb2.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
mb2.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
dd_->CmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
0, 1, &mb2, 0, nullptr, 0, nullptr);
|
||||
disp(expandP, g_scratch.sExpand[gmSlot], levelExtent(extent_, 0));
|
||||
bar(flowExpA_); bar(flowExpB_);
|
||||
g_scratch.flowReady = true;
|
||||
}
|
||||
{
|
||||
static int lastFr = -1;
|
||||
int fe = frEngaged ? 1 : 0;
|
||||
if (fe != lastFr || (gmFrames_ % 300ull) == 0) {
|
||||
WFG_LOGI("C2 flow-reg: engaged=%d mode=%d iters=%d lambda=%.2f dt=%.2f edge=%.1f eps=%.3f (model=%d)",
|
||||
fe, cfg_.frMode, cfg_.frIters, cfg_.frLambda, cfg_.frDt, cfg_.frEdge, cfg_.frEps, cfg_.model);
|
||||
lastFr = fe;
|
||||
}
|
||||
}
|
||||
|
||||
disp(expandP, g_scratch.sExpand[gmSlot], levelExtent(extent_, 0));
|
||||
bar(flowExpA_); bar(flowExpB_);
|
||||
disp(pSynth_, g_scratch.sSynth, levelExtent(extent_, 0));
|
||||
disp(pSynth_, synthSet, levelExtent(extent_, 0));
|
||||
}
|
||||
|
||||
static bool ensureScratch(FrameGen* fg, const DeviceDispatch* dd, VkDevice dev,
|
||||
@@ -418,7 +432,8 @@ static bool ensureScratch(FrameGen* fg, const DeviceDispatch* dd, VkDevice dev,
|
||||
S = ScratchState{};
|
||||
const auto GEN = VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
makeUbo(dd, dev, mp, sizeof(SynthUBO), S.synthUbo, S.synthUboMem, S.synthUboPtr);
|
||||
for (int s = 0; s < FrameGen::kSynthSlots; ++s)
|
||||
makeUbo(dd, dev, mp, sizeof(SynthUBO), S.synthUbo[s], S.synthUboMem[s], S.synthUboPtr[s]);
|
||||
makeUbo(dd, dev, mp, sizeof(FlowUBO), S.expandUbo, S.expandUboMem, S.expandUboPtr);
|
||||
if (S.expandUboPtr) { FlowUBO u{cfg.flowScale, 0, 0.6f, 1.6f}; std::memcpy(S.expandUboPtr, &u, sizeof(u)); }
|
||||
makeUbo(dd, dev, mp, sizeof(FlowRegUBO), S.flowRegUbo, S.flowRegUboMem, S.flowRegUboPtr);
|
||||
@@ -509,10 +524,12 @@ static bool ensureScratch(FrameGen* fg, const DeviceDispatch* dd, VkDevice dev,
|
||||
wImg(dd, dev, S.sFlowRegBA, 48, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, flowRegA.view, VK_NULL_HANDLE, GEN);
|
||||
}
|
||||
|
||||
S.sSynth = allocSet(dd, dev, pool, pSynth.setLayout);
|
||||
wUbo(dd, dev, S.sSynth, 0, S.synthUbo, sizeof(SynthUBO));
|
||||
wImg(dd, dev, S.sSynth, 34, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, expA.view, samp, GEN);
|
||||
wImg(dd, dev, S.sSynth, 35, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, expB.view, samp, GEN);
|
||||
for (int s = 0; s < FrameGen::kSynthSlots; ++s) {
|
||||
S.sSynth[s] = allocSet(dd, dev, pool, pSynth.setLayout);
|
||||
wUbo(dd, dev, S.sSynth[s], 0, S.synthUbo[s], sizeof(SynthUBO));
|
||||
wImg(dd, dev, S.sSynth[s], 34, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, expA.view, samp, GEN);
|
||||
wImg(dd, dev, S.sSynth[s], 35, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, expB.view, samp, GEN);
|
||||
}
|
||||
|
||||
S.builtFor = ext; S.built = true;
|
||||
return true;
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
#include <vulkan/vk_layer.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace winfg {
|
||||
namespace ddfg {
|
||||
|
||||
static inline void* dispatch_key(void* handle) { return *reinterpret_cast<void**>(handle); }
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
#if defined(__ANDROID__)
|
||||
#include <android/log.h>
|
||||
#define WFG_LOGI(...) __android_log_print(ANDROID_LOG_INFO, "win-fg", __VA_ARGS__)
|
||||
#define WFG_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "win-fg", __VA_ARGS__)
|
||||
#else
|
||||
#include <cstdio>
|
||||
#define WFG_LOGI(...) do { std::fprintf(stderr, "[win-fg] " __VA_ARGS__); std::fprintf(stderr, "\n"); } while(0)
|
||||
#define WFG_LOGE(...) do { std::fprintf(stderr, "[win-fg][E] " __VA_ARGS__); std::fprintf(stderr, "\n"); } while(0)
|
||||
#endif
|
||||
|
||||
#define WFG_LOGD(cond, ...) do { if (cond) WFG_LOGI(__VA_ARGS__); } while(0)
|
||||
@@ -1,4 +0,0 @@
|
||||
#pragma once
|
||||
#include "vk_dispatch.hpp"
|
||||
struct VkTable;
|
||||
bool winfgVkdInit(const VkTable& table, winfg::DeviceDispatch& dd, winfg::InstanceDispatch& id);
|
||||
@@ -1,5 +1,8 @@
|
||||
#include <errno.h>
|
||||
#include <jni.h>
|
||||
#include <stdatomic.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_droiddeck_launcher_input_FakeInputWriter_nativeStoreFence(JNIEnv *env, jclass clazz) {
|
||||
@@ -7,3 +10,10 @@ Java_com_droiddeck_launcher_input_FakeInputWriter_nativeStoreFence(JNIEnv *env,
|
||||
(void)clazz;
|
||||
atomic_thread_fence(memory_order_release);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_droiddeck_launcher_session_ThreadSignals_tgkill(JNIEnv *env, jclass clazz, jint tgid, jint tid, jint signal) {
|
||||
(void)env;
|
||||
(void)clazz;
|
||||
return syscall(SYS_tgkill, tgid, tid, signal) == 0 ? 0 : errno;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#ifndef DROIDDECK_VENC_PROTO_H
|
||||
#define DROIDDECK_VENC_PROTO_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* SOCK_SEQPACKET between the guest's Remote Play hooks and the app: the emulated /dev/video-enc0 and
|
||||
* MediaCodec encoder, and remote touches. A config carries the buffer memfds (inputs first) as SCM_RIGHTS;
|
||||
* every frame gets one reply, touches get none. */
|
||||
|
||||
#define VENC_MAX_BUFFERS 16
|
||||
|
||||
enum venc_msg { VENC_CONFIG = 1, VENC_FRAME = 2, VENC_DONE = 3, VENC_BITRATE = 4, VENC_TOUCH = 5 };
|
||||
enum venc_touch_action { VENC_TOUCH_DOWN = 0, VENC_TOUCH_MOVE = 1, VENC_TOUCH_UP = 2 };
|
||||
enum venc_codec { VENC_H264 = 0, VENC_HEVC = 1 };
|
||||
|
||||
struct venc_config {
|
||||
uint32_t type;
|
||||
uint32_t codec;
|
||||
uint32_t width, height, stride, rows;
|
||||
uint32_t fps_num, fps_den;
|
||||
uint32_t bitrate, peak_bitrate, vbr;
|
||||
uint32_t gop;
|
||||
int32_t profile, level;
|
||||
uint32_t inputs, outputs;
|
||||
uint32_t input_size, output_size;
|
||||
};
|
||||
|
||||
struct venc_frame {
|
||||
uint32_t type;
|
||||
uint32_t input, output;
|
||||
uint32_t bytes;
|
||||
uint32_t keyframe;
|
||||
int64_t pts_us;
|
||||
};
|
||||
|
||||
struct venc_done {
|
||||
uint32_t type;
|
||||
int32_t status;
|
||||
uint32_t bytes;
|
||||
uint32_t keyframe;
|
||||
};
|
||||
|
||||
struct venc_bitrate {
|
||||
uint32_t type;
|
||||
uint32_t bitrate;
|
||||
};
|
||||
|
||||
/* Remote Play's touch-as-mouse turned back into a touch; x and y are fractions of the screen in 1/65535. */
|
||||
struct venc_touch {
|
||||
uint32_t type;
|
||||
uint32_t action;
|
||||
uint32_t x, y;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,346 @@
|
||||
#include <android/log.h>
|
||||
#include <dlfcn.h>
|
||||
#include <jni.h>
|
||||
#include <media/NdkMediaCodec.h>
|
||||
#include <media/NdkMediaFormat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "venc_proto.h"
|
||||
|
||||
#define LOG(...) __android_log_print(ANDROID_LOG_INFO, "DroidDeckVenc", __VA_ARGS__)
|
||||
|
||||
namespace {
|
||||
|
||||
struct Mapping {
|
||||
uint8_t *data = nullptr;
|
||||
size_t size = 0;
|
||||
};
|
||||
|
||||
constexpr int32_t kColorFormatYuv420SemiPlanar = 21;
|
||||
constexpr uint32_t kBufferFlagKeyFrame = 1;
|
||||
constexpr uint32_t kBufferFlagCodecConfig = 2;
|
||||
constexpr int kTouchWidth = 1920, kTouchHeight = 1080; // InputSpace.kt
|
||||
constexpr int kRemoteTouchId = 31; // the compositor's last touch slot (MAX_TOUCH_POINTS 32)
|
||||
|
||||
int32_t avc_profile(int32_t v4l2) {
|
||||
switch (v4l2) {
|
||||
case 0: return 1;
|
||||
case 1: return 0x10000;
|
||||
case 2: return 2;
|
||||
case 3: return 4;
|
||||
case 4: return 8;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class Session {
|
||||
public:
|
||||
explicit Session(int fd) : fd_(fd) {}
|
||||
~Session() {
|
||||
release();
|
||||
close(fd_);
|
||||
}
|
||||
|
||||
void run() {
|
||||
for (;;) {
|
||||
uint8_t buf[256];
|
||||
int fds[VENC_MAX_BUFFERS * 2];
|
||||
int nfds = 0;
|
||||
ssize_t n = receive(buf, sizeof buf, fds, &nfds);
|
||||
if (n <= 0) return;
|
||||
uint32_t type;
|
||||
memcpy(&type, buf, sizeof type);
|
||||
if (type == VENC_CONFIG && n == (ssize_t)sizeof(venc_config)) {
|
||||
venc_config c;
|
||||
memcpy(&c, buf, sizeof c);
|
||||
bool ok = configure(c, fds, nfds);
|
||||
for (int i = 0; i < nfds; i++) close(fds[i]);
|
||||
reply(ok ? 0 : -1, 0, false);
|
||||
} else if (type == VENC_FRAME && n == (ssize_t)sizeof(venc_frame)) {
|
||||
venc_frame f;
|
||||
memcpy(&f, buf, sizeof f);
|
||||
uint32_t bytes = 0;
|
||||
bool key = false;
|
||||
bool ok = encode(f, &bytes, &key);
|
||||
reply(ok ? 0 : -1, bytes, key);
|
||||
} else if (type == VENC_TOUCH && n == (ssize_t)sizeof(venc_touch)) {
|
||||
venc_touch t;
|
||||
memcpy(&t, buf, sizeof t);
|
||||
touch(t);
|
||||
for (int i = 0; i < nfds; i++) close(fds[i]);
|
||||
} else if (type == VENC_BITRATE && n == (ssize_t)sizeof(venc_bitrate)) {
|
||||
venc_bitrate b;
|
||||
memcpy(&b, buf, sizeof b);
|
||||
set_bitrate(b.bitrate);
|
||||
for (int i = 0; i < nfds; i++) close(fds[i]);
|
||||
} else {
|
||||
LOG("unexpected message %u of %zd bytes; closing", type, n);
|
||||
for (int i = 0; i < nfds; i++) close(fds[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ssize_t receive(uint8_t *buf, size_t len, int *fds, int *nfds) {
|
||||
char control[CMSG_SPACE(sizeof(int) * VENC_MAX_BUFFERS * 2)];
|
||||
iovec iov = {buf, len};
|
||||
msghdr m = {};
|
||||
m.msg_iov = &iov;
|
||||
m.msg_iovlen = 1;
|
||||
m.msg_control = control;
|
||||
m.msg_controllen = sizeof control;
|
||||
ssize_t n = recvmsg(fd_, &m, MSG_CMSG_CLOEXEC);
|
||||
for (cmsghdr *c = CMSG_FIRSTHDR(&m); n > 0 && c; c = CMSG_NXTHDR(&m, c)) {
|
||||
if (c->cmsg_level != SOL_SOCKET || c->cmsg_type != SCM_RIGHTS) continue;
|
||||
int count = (int)((c->cmsg_len - CMSG_LEN(0)) / sizeof(int));
|
||||
memcpy(fds, CMSG_DATA(c), sizeof(int) * std::min(count, VENC_MAX_BUFFERS * 2));
|
||||
*nfds = std::min(count, VENC_MAX_BUFFERS * 2);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void reply(int32_t status, uint32_t bytes, bool key) {
|
||||
venc_done d = {VENC_DONE, status, bytes, key ? 1u : 0u};
|
||||
send(fd_, &d, sizeof d, MSG_NOSIGNAL);
|
||||
}
|
||||
|
||||
void release() {
|
||||
if (codec_) {
|
||||
AMediaCodec_stop(codec_);
|
||||
AMediaCodec_delete(codec_);
|
||||
codec_ = nullptr;
|
||||
}
|
||||
for (auto &m : inputs_) munmap(m.data, m.size);
|
||||
for (auto &m : outputs_) munmap(m.data, m.size);
|
||||
inputs_.clear();
|
||||
outputs_.clear();
|
||||
header_.clear();
|
||||
}
|
||||
|
||||
AMediaCodec *create(const venc_config &c, bool with_profile) {
|
||||
const char *mime = c.codec == VENC_HEVC ? "video/hevc" : "video/avc";
|
||||
AMediaCodec *codec = AMediaCodec_createEncoderByType(mime);
|
||||
if (!codec) return nullptr;
|
||||
float fps = c.fps_num ? (float)c.fps_den / (float)c.fps_num : 60.0f;
|
||||
AMediaFormat *f = AMediaFormat_new();
|
||||
AMediaFormat_setString(f, AMEDIAFORMAT_KEY_MIME, mime);
|
||||
AMediaFormat_setInt32(f, AMEDIAFORMAT_KEY_WIDTH, (int32_t)c.width);
|
||||
AMediaFormat_setInt32(f, AMEDIAFORMAT_KEY_HEIGHT, (int32_t)c.height);
|
||||
AMediaFormat_setInt32(f, AMEDIAFORMAT_KEY_COLOR_FORMAT, kColorFormatYuv420SemiPlanar);
|
||||
AMediaFormat_setInt32(f, AMEDIAFORMAT_KEY_BIT_RATE, (int32_t)std::max(c.bitrate, 500000u));
|
||||
AMediaFormat_setInt32(f, "bitrate-mode", c.vbr ? 1 : 2);
|
||||
AMediaFormat_setFloat(f, AMEDIAFORMAT_KEY_FRAME_RATE, fps);
|
||||
AMediaFormat_setFloat(f, "operating-rate", fps);
|
||||
AMediaFormat_setInt32(f, "priority", 0);
|
||||
AMediaFormat_setInt32(f, "latency", 1);
|
||||
AMediaFormat_setInt32(f, "max-bframes", 0);
|
||||
AMediaFormat_setInt32(f, "prepend-sps-pps-to-idr-frames", 1);
|
||||
float gop_seconds = c.gop && c.gop < 0xffff ? (float)c.gop / fps : 3600.0f;
|
||||
AMediaFormat_setFloat(f, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, std::max(gop_seconds, 0.1f));
|
||||
if (with_profile) {
|
||||
int32_t profile = c.codec == VENC_HEVC ? (c.profile == 2 ? 2 : 1) : avc_profile(c.profile);
|
||||
if (profile) AMediaFormat_setInt32(f, "profile", profile);
|
||||
}
|
||||
media_status_t s = AMediaCodec_configure(codec, f, nullptr, nullptr, AMEDIACODEC_CONFIGURE_FLAG_ENCODE);
|
||||
AMediaFormat_delete(f);
|
||||
if (s == AMEDIA_OK) s = AMediaCodec_start(codec);
|
||||
if (s != AMEDIA_OK) {
|
||||
AMediaCodec_delete(codec);
|
||||
return nullptr;
|
||||
}
|
||||
return codec;
|
||||
}
|
||||
|
||||
bool configure(const venc_config &c, const int *fds, int nfds) {
|
||||
release();
|
||||
if (c.inputs + c.outputs != (uint32_t)nfds || c.width < 64 || c.height < 64 || c.stride < c.width ||
|
||||
c.rows < c.height || (uint64_t)c.stride * c.rows * 3 / 2 > c.input_size) {
|
||||
LOG("bad config: %u+%u buffers for %d fds, %ux%u stride %u", c.inputs, c.outputs, nfds, c.width, c.height,
|
||||
c.stride);
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < nfds; i++) {
|
||||
bool input = (uint32_t)i < c.inputs;
|
||||
size_t size = input ? c.input_size : c.output_size;
|
||||
void *p = mmap(nullptr, size, input ? PROT_READ : PROT_READ | PROT_WRITE, MAP_SHARED, fds[i], 0);
|
||||
if (p == MAP_FAILED) {
|
||||
LOG("could not map buffer %d: %s", i, strerror(errno));
|
||||
release();
|
||||
return false;
|
||||
}
|
||||
(input ? inputs_ : outputs_).push_back({(uint8_t *)p, size});
|
||||
}
|
||||
codec_ = create(c, true);
|
||||
if (!codec_) codec_ = create(c, false);
|
||||
if (!codec_) {
|
||||
LOG("no %s encoder for %ux%u", c.codec == VENC_HEVC ? "HEVC" : "H.264", c.width, c.height);
|
||||
release();
|
||||
return false;
|
||||
}
|
||||
config_ = c;
|
||||
dst_stride_ = (int32_t)c.width;
|
||||
dst_rows_ = (int32_t)c.height;
|
||||
using InputFormat = AMediaFormat *(*)(AMediaCodec *);
|
||||
static auto input_format = (InputFormat)dlsym(RTLD_DEFAULT, "AMediaCodec_getInputFormat");
|
||||
if (AMediaFormat *in = input_format ? input_format(codec_) : nullptr) {
|
||||
int32_t v;
|
||||
if (AMediaFormat_getInt32(in, "stride", &v) && v >= (int32_t)c.width) dst_stride_ = v;
|
||||
if (AMediaFormat_getInt32(in, "slice-height", &v) && v >= (int32_t)c.height) dst_rows_ = v;
|
||||
AMediaFormat_delete(in);
|
||||
}
|
||||
LOG("%s %ux%u at %.2f fps, %u kbit/s %s, input stride %d rows %d", c.codec == VENC_HEVC ? "HEVC" : "H.264",
|
||||
c.width, c.height, c.fps_num ? (double)c.fps_den / c.fps_num : 0.0, c.bitrate / 1000,
|
||||
c.vbr ? "VBR" : "CBR", dst_stride_, dst_rows_);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void touch(const venc_touch &t) {
|
||||
using SendTouch = void (*)(int, int, int, int);
|
||||
static SendTouch send_touch = [] {
|
||||
void *wayland = dlopen("libdroiddeckwayland.so", RTLD_NOW | RTLD_NOLOAD);
|
||||
auto fn = wayland ? (SendTouch)dlsym(wayland, "droiddeck_wayland_send_touch") : nullptr;
|
||||
if (!fn) LOG("remote touch unavailable: %s", dlerror());
|
||||
return fn;
|
||||
}();
|
||||
if (!send_touch || t.action > VENC_TOUCH_UP) return;
|
||||
int x = (int)((uint64_t)std::min(t.x, 65535u) * (kTouchWidth - 1) / 65535);
|
||||
int y = (int)((uint64_t)std::min(t.y, 65535u) * (kTouchHeight - 1) / 65535);
|
||||
send_touch((int)t.action, kRemoteTouchId, x, y);
|
||||
}
|
||||
|
||||
void set_bitrate(uint32_t bitrate) {
|
||||
if (!codec_) return;
|
||||
AMediaFormat *p = AMediaFormat_new();
|
||||
AMediaFormat_setInt32(p, "video-bitrate", (int32_t)std::max(bitrate, 500000u));
|
||||
AMediaCodec_setParameters(codec_, p);
|
||||
AMediaFormat_delete(p);
|
||||
}
|
||||
|
||||
bool encode(const venc_frame &f, uint32_t *bytes, bool *key) {
|
||||
if (!codec_ || f.input >= inputs_.size() || f.output >= outputs_.size()) return false;
|
||||
if (f.keyframe) {
|
||||
AMediaFormat *p = AMediaFormat_new();
|
||||
AMediaFormat_setInt32(p, "request-sync", 0);
|
||||
AMediaCodec_setParameters(codec_, p);
|
||||
AMediaFormat_delete(p);
|
||||
}
|
||||
ssize_t in = AMediaCodec_dequeueInputBuffer(codec_, 100000);
|
||||
if (in < 0) return false;
|
||||
size_t capacity = 0;
|
||||
uint8_t *dst = AMediaCodec_getInputBuffer(codec_, (size_t)in, &capacity);
|
||||
size_t need = (size_t)dst_stride_ * dst_rows_ + (size_t)dst_stride_ * ((config_.height + 1) / 2);
|
||||
if (!dst || capacity < need) return false;
|
||||
const uint8_t *src = inputs_[f.input].data;
|
||||
for (uint32_t y = 0; y < config_.height; y++)
|
||||
memcpy(dst + (size_t)y * dst_stride_, src + (size_t)y * config_.stride, config_.width);
|
||||
const uint8_t *src_uv = src + (size_t)config_.stride * config_.rows;
|
||||
uint8_t *dst_uv = dst + (size_t)dst_stride_ * dst_rows_;
|
||||
for (uint32_t y = 0; y < (config_.height + 1) / 2; y++)
|
||||
memcpy(dst_uv + (size_t)y * dst_stride_, src_uv + (size_t)y * config_.stride, config_.width);
|
||||
if (AMediaCodec_queueInputBuffer(codec_, (size_t)in, 0, need, (uint64_t)std::max<int64_t>(f.pts_us, 0), 0) !=
|
||||
AMEDIA_OK)
|
||||
return false;
|
||||
Mapping &out = outputs_[f.output];
|
||||
for (int tries = 0; tries < 20; tries++) {
|
||||
AMediaCodecBufferInfo info;
|
||||
ssize_t o = AMediaCodec_dequeueOutputBuffer(codec_, &info, 20000);
|
||||
if (o == AMEDIACODEC_INFO_TRY_AGAIN_LATER || o == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED ||
|
||||
o == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED)
|
||||
continue;
|
||||
if (o < 0) return false;
|
||||
size_t size = 0;
|
||||
uint8_t *data = AMediaCodec_getOutputBuffer(codec_, (size_t)o, &size);
|
||||
const uint8_t *payload = data ? data + info.offset : nullptr;
|
||||
size_t length = data ? (size_t)info.size : 0;
|
||||
if (info.flags & kBufferFlagCodecConfig) {
|
||||
header_.assign(payload, payload + length);
|
||||
AMediaCodec_releaseOutputBuffer(codec_, (size_t)o, false);
|
||||
continue;
|
||||
}
|
||||
*key = (info.flags & kBufferFlagKeyFrame) != 0;
|
||||
bool prepend = *key && !header_.empty() &&
|
||||
(length < header_.size() || memcmp(payload, header_.data(), header_.size()) != 0);
|
||||
size_t total = length + (prepend ? header_.size() : 0);
|
||||
bool fits = payload && total <= out.size;
|
||||
if (fits) {
|
||||
if (prepend) memcpy(out.data, header_.data(), header_.size());
|
||||
memcpy(out.data + (prepend ? header_.size() : 0), payload, length);
|
||||
*bytes = (uint32_t)total;
|
||||
}
|
||||
AMediaCodec_releaseOutputBuffer(codec_, (size_t)o, false);
|
||||
return fits;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int fd_;
|
||||
AMediaCodec *codec_ = nullptr;
|
||||
venc_config config_ = {};
|
||||
int32_t dst_stride_ = 0, dst_rows_ = 0;
|
||||
std::vector<Mapping> inputs_, outputs_;
|
||||
std::vector<uint8_t> header_;
|
||||
};
|
||||
|
||||
std::atomic<int> g_listener{-1};
|
||||
|
||||
void serve(int listener) {
|
||||
for (;;) {
|
||||
int fd = accept4(listener, nullptr, nullptr, SOCK_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
return;
|
||||
}
|
||||
std::thread([fd] {
|
||||
Session s(fd);
|
||||
s.run();
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL
|
||||
Java_com_droiddeck_launcher_session_VideoEncodeBridge_nativeStart(JNIEnv *env, jobject, jstring jpath) {
|
||||
if (g_listener.load() >= 0) return JNI_TRUE;
|
||||
const char *path = env->GetStringUTFChars(jpath, nullptr);
|
||||
sockaddr_un addr = {};
|
||||
addr.sun_family = AF_UNIX;
|
||||
bool fits = strlen(path) < sizeof addr.sun_path;
|
||||
if (fits) strcpy(addr.sun_path, path);
|
||||
int fd = fits ? socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0) : -1;
|
||||
if (fd >= 0) {
|
||||
unlink(path);
|
||||
if (bind(fd, (sockaddr *)&addr, sizeof addr) != 0 || listen(fd, 4) != 0) {
|
||||
LOG("could not listen on %s: %s", path, strerror(errno));
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
env->ReleaseStringUTFChars(jpath, path);
|
||||
if (fd < 0) return JNI_FALSE;
|
||||
g_listener.store(fd);
|
||||
std::thread(serve, fd).detach();
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_droiddeck_launcher_session_VideoEncodeBridge_nativeStop(JNIEnv *, jobject) {
|
||||
int fd = g_listener.exchange(-1);
|
||||
if (fd >= 0) {
|
||||
shutdown(fd, SHUT_RDWR);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
@@ -45,10 +45,10 @@ target_include_directories(droiddeckwayland PRIVATE
|
||||
)
|
||||
|
||||
set(DROIDDECK_FRAMEGEN_LSFG_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../framegen/lsfg)
|
||||
set(DROIDDECK_FRAMEGEN_WINFG_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../framegen/winfg)
|
||||
set(DROIDDECK_FRAMEGEN_DDFG_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../framegen/ddfg)
|
||||
if (TARGET dxbc AND EXISTS ${DROIDDECK_FRAMEGEN_LSFG_DIR}/lsfg_engine.cpp
|
||||
AND EXISTS ${DROIDDECK_FRAMEGEN_WINFG_DIR}/winfg_engine.cpp)
|
||||
message(STATUS "droiddeckwayland: frame-generation engines built in (LSFG Native, Win-FG Native)")
|
||||
AND EXISTS ${DROIDDECK_FRAMEGEN_DDFG_DIR}/ddfg_engine.cpp)
|
||||
message(STATUS "droiddeckwayland: frame-generation engines built in (LSFG Native, DD-FG Native)")
|
||||
target_sources(droiddeckwayland PRIVATE
|
||||
src/framegen_engine.cpp
|
||||
${DROIDDECK_FRAMEGEN_LSFG_DIR}/lsfg_probe.cpp
|
||||
@@ -68,9 +68,9 @@ if (TARGET dxbc AND EXISTS ${DROIDDECK_FRAMEGEN_LSFG_DIR}/lsfg_engine.cpp
|
||||
${DROIDDECK_FRAMEGEN_LSFG_DIR}/lsfg_engine.cpp
|
||||
${DROIDDECK_FRAMEGEN_LSFG_DIR}/lsfg_governor.cpp
|
||||
${DROIDDECK_FRAMEGEN_LSFG_DIR}/lsfg_jni.cpp
|
||||
${DROIDDECK_FRAMEGEN_WINFG_DIR}/framegen.cpp
|
||||
${DROIDDECK_FRAMEGEN_WINFG_DIR}/winfg_vkd.cpp
|
||||
${DROIDDECK_FRAMEGEN_WINFG_DIR}/winfg_engine.cpp
|
||||
${DROIDDECK_FRAMEGEN_DDFG_DIR}/framegen.cpp
|
||||
${DROIDDECK_FRAMEGEN_DDFG_DIR}/ddfg_vkd.cpp
|
||||
${DROIDDECK_FRAMEGEN_DDFG_DIR}/ddfg_engine.cpp
|
||||
)
|
||||
target_include_directories(droiddeckwayland PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/..
|
||||
@@ -79,8 +79,8 @@ if (TARGET dxbc AND EXISTS ${DROIDDECK_FRAMEGEN_LSFG_DIR}/lsfg_engine.cpp
|
||||
target_compile_options(droiddeckwayland PRIVATE
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-std=c++17 -fvisibility=hidden>)
|
||||
target_compile_definitions(droiddeckwayland PRIVATE
|
||||
WINFG_UPSTREAM="${WINFG_UPSTREAM}"
|
||||
WINFG_CHAIN_HASH="${WINFG_CHAIN_HASH}"
|
||||
DDFG_UPSTREAM="${DDFG_UPSTREAM}"
|
||||
DDFG_CHAIN_HASH="${DDFG_CHAIN_HASH}"
|
||||
)
|
||||
target_link_libraries(droiddeckwayland dxbc atomic)
|
||||
else()
|
||||
|
||||
@@ -228,6 +228,8 @@ struct surface {
|
||||
enum surface_role role;
|
||||
struct wl_resource *idle_buffer;
|
||||
struct wl_listener idle_buffer_destroy;
|
||||
uint32_t *idle_px;
|
||||
int idle_w, idle_h;
|
||||
struct wl_resource *xdg_surface, *xdg_toplevel;
|
||||
struct wl_resource *viewport;
|
||||
|
||||
@@ -979,8 +981,30 @@ static void cursor_publish_buffer(struct surface *s, struct wl_resource *buffer)
|
||||
g_cursor_shown = s;
|
||||
}
|
||||
|
||||
static void surface_forget_idle_px(struct surface *s) {
|
||||
free(s->idle_px);
|
||||
s->idle_px = NULL;
|
||||
s->idle_w = s->idle_h = 0;
|
||||
}
|
||||
|
||||
static void on_idle_buffer_destroyed(struct wl_listener *l, void *data) {
|
||||
struct surface *s = wl_container_of(l, s, idle_buffer_destroy);
|
||||
struct wl_shm_buffer *shm = wl_shm_buffer_get(s->idle_buffer);
|
||||
if (shm) {
|
||||
int32_t w = wl_shm_buffer_get_width(shm), h = wl_shm_buffer_get_height(shm);
|
||||
int32_t stride = wl_shm_buffer_get_stride(shm);
|
||||
uint32_t *px = w > 0 && h > 0 && (int64_t)w * h <= CURSOR_MAX_PX && (int64_t)stride >= (int64_t)w * 4
|
||||
? realloc(s->idle_px, (size_t)w * h * 4) : NULL;
|
||||
if (px) {
|
||||
wl_shm_buffer_begin_access(shm);
|
||||
const uint8_t *src = wl_shm_buffer_get_data(shm);
|
||||
for (int y = 0; y < h; y++) memcpy(&px[(size_t)y * w], src + (size_t)y * stride, (size_t)w * 4);
|
||||
wl_shm_buffer_end_access(shm);
|
||||
s->idle_px = px;
|
||||
s->idle_w = w;
|
||||
s->idle_h = h;
|
||||
}
|
||||
}
|
||||
wl_list_remove(&s->idle_buffer_destroy.link);
|
||||
wl_list_init(&s->idle_buffer_destroy.link);
|
||||
s->idle_buffer = NULL;
|
||||
@@ -1007,6 +1031,7 @@ static struct wl_resource *surface_take_idle(struct surface *s) {
|
||||
}
|
||||
|
||||
static void surface_drop_idle(struct surface *s) {
|
||||
surface_forget_idle_px(s);
|
||||
struct wl_resource *buffer = surface_take_idle(s);
|
||||
if (buffer) send_buffer_release(buffer);
|
||||
}
|
||||
@@ -1136,6 +1161,7 @@ static void surface_resource_destroy(struct wl_resource *r) {
|
||||
if (g_cursor_surface == s) { g_cursor_surface = NULL; cursor_publish_hidden(); }
|
||||
if (g_cursor_shown == s) g_cursor_shown = NULL;
|
||||
surface_take_idle(s);
|
||||
surface_forget_idle_px(s);
|
||||
if (g_grab == s) g_grab = NULL;
|
||||
if (g_key_target == s) g_key_target = NULL;
|
||||
if (g_ime_click == s) g_ime_click = NULL;
|
||||
@@ -2123,6 +2149,9 @@ static void pointer_set_cursor(struct wl_client *c, struct wl_resource *r, uint3
|
||||
send_buffer_release(buffer);
|
||||
} else if (g_cursor_shown == s) {
|
||||
cursor_publish_shown();
|
||||
} else if (s->idle_px) {
|
||||
cursor_publish_pixels((const uint8_t *)s->idle_px, s->idle_w, s->idle_h, (size_t)s->idle_w * 4, hx, hy);
|
||||
g_cursor_shown = s;
|
||||
}
|
||||
}
|
||||
static void pointer_release(struct wl_client *c, struct wl_resource *r) { wl_resource_destroy(r); }
|
||||
@@ -2674,7 +2703,11 @@ static void pointer_input(double x, double y, int relative, uint32_t button, int
|
||||
uint32_t t = now_ms();
|
||||
|
||||
pointer_focus(target->resource, fx, fy);
|
||||
if (!(k && k->is_lock))
|
||||
// A button-only input must not replay a cached absolute position. A game
|
||||
// may have warped its cursor since the last motion (before taking lock,
|
||||
// or while releasing it), so that replay can become an unintended pan.
|
||||
// Absolute touch events still carry their position, including on clicks.
|
||||
if (!(k && k->is_lock) && (!relative || dx != 0 || dy != 0))
|
||||
for_each_pointer_of(client, sp) wl_pointer_send_motion(sp->ptr, t, fx, fy);
|
||||
send_relative_motion(client, dx, dy);
|
||||
for_each_pointer_of(client, sp) {
|
||||
|
||||
@@ -86,7 +86,7 @@ static int64_t now_ns(void) {
|
||||
|
||||
|
||||
void vkp_framegen_set_engine(int kind) {
|
||||
if (kind != VKP_FG_ENGINE_LSFG && kind != VKP_FG_ENGINE_WINFG) kind = VKP_FG_ENGINE_LSFG;
|
||||
if (kind != VKP_FG_ENGINE_LSFG && kind != VKP_FG_ENGINE_DDFG) kind = VKP_FG_ENGINE_LSFG;
|
||||
atomic_store(&g_kind, kind);
|
||||
atomic_store(&g_failed_kind, -1);
|
||||
atomic_store(&g_cfg_dirty, 1);
|
||||
@@ -125,7 +125,7 @@ void vkp_framegen_set_tuning(float flow_scale, float refresh_hz) {
|
||||
atomic_store(&g_cfg_dirty, 1);
|
||||
}
|
||||
|
||||
void vkp_framegen_set_winfg_tuning(int model, int perf_preset) {
|
||||
void vkp_framegen_set_ddfg_tuning(int model, int perf_preset) {
|
||||
atomic_store(&g_model, model == 3 ? 3 : 4);
|
||||
atomic_store(&g_preset, perf_preset < 0 ? 0 : perf_preset > 2 ? 2 : perf_preset);
|
||||
atomic_store(&g_cfg_dirty, 1);
|
||||
@@ -180,9 +180,9 @@ void vkp_framegen_device_ready(VkDevice dev, VkQueue queue, uint32_t qfam, int f
|
||||
g_vk.GetPhysicalDeviceMemoryProperties(g_pd, &g_memprops);
|
||||
fge_device_ready(g_gipa, g_inst, g_pd, dev, queue, qfam, features_enabled);
|
||||
g_dev_ready = vk.CreateImage && vk.CreateImageView && vk.CmdPipelineBarrier;
|
||||
FGLOG("engines ready on the compositor's device: LSFG Native %s (%s), Win-FG Native %s",
|
||||
FGLOG("engines ready on the compositor's device: LSFG Native %s (%s), DD-FG Native %s",
|
||||
fge_caps_ok(VKP_FG_ENGINE_LSFG) ? "available" : "unavailable", fge_caps_reason(),
|
||||
fge_caps_ok(VKP_FG_ENGINE_WINFG) ? "available" : "unavailable");
|
||||
fge_caps_ok(VKP_FG_ENGINE_DDFG) ? "available" : "unavailable");
|
||||
}
|
||||
|
||||
void vkp_framegen_device_lost(void) { g_dev_lost = 1; }
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
#endif
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
enum { VKP_FG_ENGINE_LSFG = 0, VKP_FG_ENGINE_WINFG = 1 };
|
||||
enum { VKP_FG_ENGINE_LSFG = 0, VKP_FG_ENGINE_DDFG = 1 };
|
||||
#define VKP_FG_MAX_GENERATIONS 3
|
||||
|
||||
void vkp_framegen_set_engine(int kind);
|
||||
void vkp_framegen_set_armed(int armed, int multiplier, int target_fps);
|
||||
void vkp_framegen_set_lsfg_cache_path(const char *path);
|
||||
void vkp_framegen_set_tuning(float flow_scale, float refresh_hz);
|
||||
void vkp_framegen_set_winfg_tuning(int model, int perf_preset);
|
||||
void vkp_framegen_set_ddfg_tuning(int model, int perf_preset);
|
||||
int vkp_framegen_problem(void);
|
||||
const char *vkp_framegen_caps_reason(void);
|
||||
void vkp_framegen_stats(float out[6]);
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "lsfg/lsfg_engine.h"
|
||||
#include "lsfg/lsfg_probe.h"
|
||||
#include "lsfg/lsfg_vkd.h"
|
||||
#include "winfg/winfg_engine.h"
|
||||
#include "ddfg/ddfg_engine.h"
|
||||
|
||||
#define ELOG(...) __android_log_print(ANDROID_LOG_INFO, "DroidDeckWayland", "framegen: " __VA_ARGS__)
|
||||
#define ELOGE(...) __android_log_print(ANDROID_LOG_ERROR, "DroidDeckWayland", "framegen: " __VA_ARGS__)
|
||||
@@ -30,7 +30,7 @@ uint32_t g_qfam = 0;
|
||||
bool g_probed = false, g_ready = false;
|
||||
|
||||
std::unique_ptr<lsfg::Engine> g_lsfg;
|
||||
std::unique_ptr<winfg::Engine> g_winfg;
|
||||
std::unique_ptr<ddfg::Engine> g_ddfg;
|
||||
int g_kind = -1;
|
||||
char g_build[96] = "";
|
||||
|
||||
@@ -143,15 +143,15 @@ int fge_start(int kind, const char *cache_path) {
|
||||
fge_stop();
|
||||
if (!g_ready) return -1;
|
||||
if (kind == 1) {
|
||||
auto e = std::make_unique<winfg::Engine>();
|
||||
auto e = std::make_unique<ddfg::Engine>();
|
||||
if (!e->init(g_table, g_pd, g_dev, g_qfam, g_queue)) {
|
||||
ELOGE("winfg-native: engine init failed");
|
||||
ELOGE("ddfg-native: engine init failed");
|
||||
return -1;
|
||||
}
|
||||
g_winfg = std::move(e);
|
||||
g_ddfg = std::move(e);
|
||||
g_kind = 1;
|
||||
#if defined(WINFG_UPSTREAM) && defined(WINFG_CHAIN_HASH)
|
||||
std::snprintf(g_build, sizeof(g_build), "chain %s, src %s", WINFG_UPSTREAM, WINFG_CHAIN_HASH);
|
||||
#if defined(DDFG_UPSTREAM) && defined(DDFG_CHAIN_HASH)
|
||||
std::snprintf(g_build, sizeof(g_build), "chain %s, src %s", DDFG_UPSTREAM, DDFG_CHAIN_HASH);
|
||||
#else
|
||||
std::snprintf(g_build, sizeof(g_build), "embedded chain");
|
||||
#endif
|
||||
@@ -176,46 +176,46 @@ int fge_start(int kind, const char *cache_path) {
|
||||
}
|
||||
|
||||
void fge_stop(void) {
|
||||
if ((g_lsfg || g_winfg) && g_table.DeviceWaitIdle && g_dev) g_table.DeviceWaitIdle(g_dev);
|
||||
if ((g_lsfg || g_ddfg) && g_table.DeviceWaitIdle && g_dev) g_table.DeviceWaitIdle(g_dev);
|
||||
g_lsfg.reset();
|
||||
g_winfg.reset();
|
||||
g_ddfg.reset();
|
||||
g_kind = -1;
|
||||
}
|
||||
|
||||
int fge_unavailable(void) {
|
||||
if (g_kind == 1) return g_winfg && g_winfg->unavailable() ? 1 : 0;
|
||||
if (g_kind == 1) return g_ddfg && g_ddfg->unavailable() ? 1 : 0;
|
||||
return g_lsfg && g_lsfg->unavailable() ? 1 : 0;
|
||||
}
|
||||
|
||||
void fge_configure(uint32_t multiplier, uint32_t target_fps, float flow_scale, float refresh_hz,
|
||||
int model, int perf_preset) {
|
||||
if (multiplier < 2) multiplier = 2;
|
||||
if (g_kind == 1 && g_winfg) g_winfg->configure(multiplier, model, perf_preset, flow_scale);
|
||||
if (g_kind == 1 && g_ddfg) g_ddfg->configure(multiplier, model, perf_preset, flow_scale);
|
||||
else if (g_lsfg) g_lsfg->configure(multiplier, target_fps, flow_scale, refresh_hz);
|
||||
}
|
||||
|
||||
int fge_prepare(uint32_t w, uint32_t h, VkFormat fmt) {
|
||||
if (g_kind == 1) return g_winfg && g_winfg->prepare(w, h, fmt) ? 1 : 0;
|
||||
if (g_kind == 1) return g_ddfg && g_ddfg->prepare(w, h, fmt) ? 1 : 0;
|
||||
if (!g_lsfg) return 0;
|
||||
g_lsfg->setGuestExtent(w, h);
|
||||
return g_lsfg->prepare(w, h, fmt) ? 1 : 0;
|
||||
}
|
||||
|
||||
uint32_t fge_plan(uint32_t capacity, uint64_t source_frames, float presented_rate) {
|
||||
if (g_kind == 1) return g_winfg ? g_winfg->plan(capacity) : 0;
|
||||
if (g_kind == 1) return g_ddfg ? g_ddfg->plan(capacity) : 0;
|
||||
if (!g_lsfg) return 0;
|
||||
g_lsfg->setPresentedRate(presented_rate);
|
||||
return g_lsfg->plan(capacity, source_frames);
|
||||
}
|
||||
|
||||
void fge_process(VkCommandBuffer cmd, VkImage source, uint32_t w, uint32_t h, uint32_t gens) {
|
||||
if (g_kind == 1) { if (g_winfg) g_winfg->process(cmd, source, w, h, gens); return; }
|
||||
if (g_kind == 1) { if (g_ddfg) g_ddfg->process(cmd, source, w, h, gens); return; }
|
||||
if (g_lsfg) g_lsfg->process(cmd, source, w, h, gens);
|
||||
}
|
||||
|
||||
void fge_generate(VkCommandBuffer cmd, uint32_t g, uint32_t count, VkImage img, VkImageView view,
|
||||
uint32_t w, uint32_t h) {
|
||||
if (g_kind == 1) { if (g_winfg) g_winfg->generateInto(cmd, g, count, img, view, w, h); return; }
|
||||
if (g_kind == 1) { if (g_ddfg) g_ddfg->generateInto(cmd, g, count, img, view, w, h); return; }
|
||||
if (g_lsfg) g_lsfg->generateInto(cmd, g, g, img, view, w, h);
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ void fge_telemetry(float *accepted, float *source_rate, float *thermal) {
|
||||
}
|
||||
}
|
||||
|
||||
const char *fge_engine_name(int kind) { return kind == 1 ? "Win-FG Native" : "LSFG Native"; }
|
||||
const char *fge_engine_name(int kind) { return kind == 1 ? "DD-FG Native" : "LSFG Native"; }
|
||||
const char *fge_build_info(void) { return g_build; }
|
||||
|
||||
}
|
||||
@@ -34,5 +34,5 @@ void fge_forget_targets(void) {}
|
||||
void fge_telemetry(float *accepted, float *source_rate, float *thermal) {
|
||||
*accepted = 0.0f; *source_rate = 0.0f; *thermal = -1.0f;
|
||||
}
|
||||
const char *fge_engine_name(int kind) { return kind == 1 ? "Win-FG Native" : "LSFG Native"; }
|
||||
const char *fge_engine_name(int kind) { return kind == 1 ? "DD-FG Native" : "LSFG Native"; }
|
||||
const char *fge_build_info(void) { return "stub"; }
|
||||
@@ -31,10 +31,10 @@ Java_com_droiddeck_launcher_wayland_WaylandCompositor_nativeSetFrameGenTuning(JN
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_droiddeck_launcher_wayland_WaylandCompositor_nativeSetWinFgTuning(JNIEnv *env, jclass clazz,
|
||||
Java_com_droiddeck_launcher_wayland_WaylandCompositor_nativeSetDdFgTuning(JNIEnv *env, jclass clazz,
|
||||
jint model, jint perfPreset) {
|
||||
(void)env; (void)clazz;
|
||||
vkp_framegen_set_winfg_tuning((int)model, (int)perfPreset);
|
||||
vkp_framegen_set_ddfg_tuning((int)model, (int)perfPreset);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
|
||||
Reference in new issue
Block a user