diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 4f006c89e..836b8f1ec 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -6,8 +6,6 @@ include(FetchContent) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 -Wno-unused-function -Wimplicit-function-declaration") -# Zstandard is used by winlator/native_content_io.cpp. Keep this dependency in -# the parent build instead of relying on the Steam client subproject to create it. FetchContent_Declare( zstd GIT_REPOSITORY https://github.com/facebook/zstd.git @@ -46,14 +44,6 @@ add_subdirectory(wn-libsteamclient) find_package(curl REQUIRED CONFIG) -# ---------------------------------------------------------------------------- -# SPIR-V shader compilation -# Each .glsl is compiled by glslc (shipped with the NDK) into a .spv binary, -# then converted to a C uint32_t array via bin2c.cmake. Headers are emitted -# under ${CMAKE_CURRENT_BINARY_DIR}/shaders/*.spv.h and included from vk_renderer.c. -# ---------------------------------------------------------------------------- - -# Locate glslc shipped with the NDK. ANDROID_NDK is provided by the Android Gradle plugin. if(NOT DEFINED ANDROID_NDK) message(FATAL_ERROR "ANDROID_NDK not defined; this project must be built via the Android Gradle plugin") endif() @@ -101,6 +91,21 @@ set(SHADER_LIST "effect_colorblind:frag:effect_colorblind_frag" "effect_pixelate:frag:effect_pixelate_frag" "sgsr1:frag:sgsr1_frag" + "motion:comp:motion_comp" + "motion_fp32:comp:motion_fp32_comp" + "interpolate:frag:interpolate_frag" + "cnn_pyramid:comp:cnn_pyramid_comp" + "cnn_conv:comp:cnn_conv_comp" + "cnn_conv_2pass:comp:cnn_conv_2pass_comp" + "cnn_correlation:comp:cnn_correlation_comp" + "cnn_correlation_cost9:comp:cnn_correlation_cost9_comp" + "cnn_correlation_g09:comp:cnn_correlation_g09_comp" + "cnn_correlation_warpfollow:comp:cnn_correlation_warpfollow_comp" + "cnn_flowreg:comp:cnn_flowreg_comp" + "cnn_occlusion:comp:cnn_occlusion_comp" + "cnn_generate:comp:cnn_generate_comp" + "fg_synthshift:comp:fg_synthshift_comp" + "flowfix:comp:flowfix_comp" ) set(SHADER_HEADERS "") @@ -128,11 +133,27 @@ foreach(entry ${SHADER_LIST}) list(APPEND SHADER_HEADERS "${hdr}") endforeach() -add_custom_target(winlator_shaders DEPENDS ${SHADER_HEADERS}) +set(WEIGHTS_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/winlator/vk/weights_v2") +set(BIN2C_BYTES_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/winlator/vk/bin2c_bytes.cmake") +set(WEIGHTS_LIST 05 06 07 14 20 21 22 24 25 26 27 28 29 36 37 42 45 51) +foreach(id ${WEIGHTS_LIST}) + set(winput "${WEIGHTS_SRC_DIR}/wnfg_${id}.weights.fp16") + set(whdr "${SHADER_OUT_DIR}/wnfg_${id}_weights.h") + add_custom_command( + OUTPUT "${whdr}" + COMMAND "${CMAKE_COMMAND}" + -DINPUT_FILE=${winput} + -DOUTPUT_FILE=${whdr} + -DVAR_NAME=wnfg_${id}_weights + -P "${BIN2C_BYTES_SCRIPT}" + DEPENDS "${winput}" "${BIN2C_BYTES_SCRIPT}" + COMMENT "Embedding weights wnfg_${id}.weights.fp16 -> wnfg_${id}_weights.h" + VERBATIM + ) + list(APPEND SHADER_HEADERS "${whdr}") +endforeach() -# ---------------------------------------------------------------------------- -# Winlator native library (X-server, AHB, Vulkan compositor, helpers) -# ---------------------------------------------------------------------------- +add_custom_target(winlator_shaders DEPENDS ${SHADER_HEADERS}) add_library(winlator SHARED winlator/drawable.c diff --git a/app/src/main/cpp/winlator/vk/bin2c_bytes.cmake b/app/src/main/cpp/winlator/vk/bin2c_bytes.cmake new file mode 100644 index 000000000..e2e1bd585 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/bin2c_bytes.cmake @@ -0,0 +1,36 @@ +if(NOT INPUT_FILE OR NOT OUTPUT_FILE OR NOT VAR_NAME) + message(FATAL_ERROR "bin2c_bytes.cmake requires INPUT_FILE, OUTPUT_FILE, VAR_NAME") +endif() + +file(READ "${INPUT_FILE}" hex_data HEX) +string(LENGTH "${hex_data}" hex_len) + +set(bytes "") +set(line_bytes "") +set(bytes_per_line 0) + +set(i 0) +while(i LESS hex_len) + string(SUBSTRING "${hex_data}" ${i} 2 b) + math(EXPR i "${i} + 2") + string(APPEND line_bytes "0x${b}, ") + math(EXPR bytes_per_line "${bytes_per_line} + 1") + if(bytes_per_line EQUAL 16) + string(APPEND bytes " ${line_bytes}\n") + set(line_bytes "") + set(bytes_per_line 0) + endif() +endwhile() +if(bytes_per_line GREATER 0) + string(APPEND bytes " ${line_bytes}\n") +endif() + +file(WRITE "${OUTPUT_FILE}" +"#pragma once +#include +#include + +static const uint8_t ${VAR_NAME}[] = { +${bytes}}; +static const size_t ${VAR_NAME}_size = sizeof(${VAR_NAME}); +") diff --git a/app/src/main/cpp/winlator/vk/shaders/cnn_conv.comp b/app/src/main/cpp/winlator/vk/shaders/cnn_conv.comp new file mode 100644 index 000000000..059f81913 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/shaders/cnn_conv.comp @@ -0,0 +1,104 @@ +#version 450 +#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require + +layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +layout(set = 0, binding = 0) uniform sampler2DArray uSrc; +layout(set = 0, binding = 1, rgba8) uniform writeonly image2DArray uDst; +layout(set = 0, binding = 3) uniform sampler2D uLuma; + +layout(set = 0, binding = 8, std430) readonly buffer Weights { float16_t W[]; }; + +layout(push_constant) uniform PC { + ivec2 size; + float t; + float mvScale; + uint wBase; + int cinT; + int coutT; + int flags; +} pc; + +const ivec2 TAP[9] = ivec2[]( + ivec2(-1,-1), ivec2(0,-1), ivec2(1,-1), + ivec2(-1, 0), ivec2(0, 0), ivec2(1, 0), + ivec2(-1, 1), ivec2(0, 1), ivec2(1, 1)); + +const int MAX_T = 4; + +mat4 convMat(int k, int ci, int co) { + uint b = pc.wBase + uint((((k * pc.cinT + ci) * pc.coutT + co) * 4) * 4); + mat4 M; + for (int c = 0; c < 4; ++c) { + uint cb = b + uint(c); + M[c] = vec4(float(W[cb + 0u]), + float(W[cb + 4u]), + float(W[cb + 8u]), + float(W[cb + 12u])); + } + return M; +} + +void main() { + ivec2 p = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(p, pc.size))) return; + + bool stem = (pc.flags & 1) != 0; + bool stride2 = (pc.flags & 2) != 0; + bool resid = (pc.flags & 4) != 0; + bool doRelu = (pc.flags & 8) != 0; + bool stem2x = (pc.flags & 16) != 0; + + ivec2 sp = (stride2 || stem2x) ? (p * 2) : p; + + ivec2 hi = stem ? (textureSize(uLuma, 0) - ivec2(1)) + : stride2 ? (textureSize(uSrc, 0).xy - ivec2(1)) + : (pc.size - ivec2(1)); + + vec4 acc[MAX_T]; + for (int co = 0; co < pc.coutT; ++co) acc[co] = vec4(0.0); + + uint affBase = pc.wBase + uint(9 * pc.cinT * pc.coutT * 16); + + for (int k = 0; k < 9; ++k) { + ivec2 q = clamp(sp + TAP[k], ivec2(0), hi); + + if (stem) { + + float luma = texelFetch(uLuma, q, 0).r; + vec4 x = vec4((luma - 0.208008) * 1.496094 + 0.769531, 0.0, 0.0, 0.0); + for (int co = 0; co < pc.coutT; ++co) + acc[co] += convMat(k, 0, co) * x; + } else { + + for (int ci = 0; ci < pc.cinT; ++ci) { + vec4 x = texelFetch(uSrc, ivec3(q, ci), 0); + for (int co = 0; co < pc.coutT; ++co) + acc[co] += convMat(k, ci, co) * x; + } + } + } + + if (resid) { + acc[0] += texelFetch(uSrc, ivec3(p, 0), 0); + } + + for (int co = 0; co < pc.coutT; ++co) { + vec4 bias = vec4(float(W[affBase + uint((0 * pc.coutT + co) * 4 + 0)]), + float(W[affBase + uint((0 * pc.coutT + co) * 4 + 1)]), + float(W[affBase + uint((0 * pc.coutT + co) * 4 + 2)]), + float(W[affBase + uint((0 * pc.coutT + co) * 4 + 3)])); + vec4 scale = vec4(float(W[affBase + uint((1 * pc.coutT + co) * 4 + 0)]), + float(W[affBase + uint((1 * pc.coutT + co) * 4 + 1)]), + float(W[affBase + uint((1 * pc.coutT + co) * 4 + 2)]), + float(W[affBase + uint((1 * pc.coutT + co) * 4 + 3)])); + vec4 offset = vec4(float(W[affBase + uint((2 * pc.coutT + co) * 4 + 0)]), + float(W[affBase + uint((2 * pc.coutT + co) * 4 + 1)]), + float(W[affBase + uint((2 * pc.coutT + co) * 4 + 2)]), + float(W[affBase + uint((2 * pc.coutT + co) * 4 + 3)])); + + vec4 v = (acc[co] - bias) * scale + offset; + if (doRelu) v = max(v, vec4(0.0)); + imageStore(uDst, ivec3(p, co), clamp(v, 0.0, 1.0)); + } +} diff --git a/app/src/main/cpp/winlator/vk/shaders/cnn_conv_2pass.comp b/app/src/main/cpp/winlator/vk/shaders/cnn_conv_2pass.comp new file mode 100644 index 000000000..2342bb765 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/shaders/cnn_conv_2pass.comp @@ -0,0 +1,151 @@ +#version 450 +#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require + +layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +layout(constant_id = 0) const int CIN_T = 2; +layout(constant_id = 1) const int MID_T = 2; +layout(constant_id = 2) const int COUT_T = 2; + +const int TILE = 18; +const int MAX_T = 2; + +layout(set = 0, binding = 32) uniform sampler2D uIn0; +layout(set = 0, binding = 33) uniform sampler2D uIn1; + +layout(set = 0, binding = 48, rgba8) uniform writeonly image2D uOut0; +layout(set = 0, binding = 49, rgba8) uniform writeonly image2D uOut1; + +layout(set = 0, binding = 8, std430) readonly buffer Weights { float16_t W[]; }; + +layout(push_constant) uniform PC { + ivec2 size; + float t; + float mvScale; + uint wBase; + int cinT; + int coutT; + int flags; +} pc; + +const ivec2 TAP_XOUTER[9] = ivec2[]( + ivec2(-1,-1), ivec2(-1, 0), ivec2(-1, 1), + ivec2( 0,-1), ivec2( 0, 0), ivec2( 0, 1), + ivec2( 1,-1), ivec2( 1, 0), ivec2( 1, 1)); + +shared f16vec4 sMid[MAX_T][TILE][TILE]; + +mat4 convMatAt(uint blockBase, int k, int ci, int co, int cinT, int coutT) { + uint b = blockBase + uint((((k * cinT + ci) * coutT + co) * 4) * 4); + mat4 M; + for (int c = 0; c < 4; ++c) { + uint cb = b + uint(c); + M[c] = vec4(float(W[cb + 0u]), float(W[cb + 4u]), + float(W[cb + 8u]), float(W[cb + 12u])); + } + return M; +} + +void affineAt(uint affBase, int co, int coutT, + out vec4 bias, out vec4 scale, out vec4 offset) { + bias = vec4(float(W[affBase + uint((0*coutT + co)*4 + 0)]), + float(W[affBase + uint((0*coutT + co)*4 + 1)]), + float(W[affBase + uint((0*coutT + co)*4 + 2)]), + float(W[affBase + uint((0*coutT + co)*4 + 3)])); + scale = vec4(float(W[affBase + uint((1*coutT + co)*4 + 0)]), + float(W[affBase + uint((1*coutT + co)*4 + 1)]), + float(W[affBase + uint((1*coutT + co)*4 + 2)]), + float(W[affBase + uint((1*coutT + co)*4 + 3)])); + offset = vec4(float(W[affBase + uint((2*coutT + co)*4 + 0)]), + float(W[affBase + uint((2*coutT + co)*4 + 1)]), + float(W[affBase + uint((2*coutT + co)*4 + 2)]), + float(W[affBase + uint((2*coutT + co)*4 + 3)])); +} + +void main() { + bool PASS1_CONV = (pc.flags & 1) != 0; + bool PASS1_CLAMP = (pc.flags & 2) != 0; + + ivec2 base = ivec2(gl_WorkGroupID.xy) * 16 - ivec2(1); + ivec2 lid = ivec2(gl_LocalInvocationID.xy); + ivec2 p = base + ivec2(1) + lid; + ivec2 hi = pc.size - ivec2(1); + + uint p1ConvBase = pc.wBase; + uint p1AffBase = p1ConvBase + uint(9 * CIN_T * MID_T * 16); + + uint p2ConvBase = PASS1_CONV ? (p1AffBase + uint(3 * MID_T * 4)) : pc.wBase; + uint p2AffBase = p2ConvBase + uint(9 * MID_T * COUT_T * 16); + + uint lindex = gl_LocalInvocationIndex; + for (uint idx = lindex; idx < uint(TILE*TILE); idx += 256u) { + int tx = int(idx % uint(TILE)); + int ty = int(idx / uint(TILE)); + ivec2 sp = base + ivec2(tx, ty); + + if (PASS1_CONV) { + + bool centerOOB = any(lessThan(sp, ivec2(0))) || any(greaterThan(sp, hi)); + vec4 acc[MAX_T]; + for (int co = 0; co < MID_T; ++co) acc[co] = vec4(0.0); + if (!centerOOB) { + for (int k = 0; k < 9; ++k) { + ivec2 q = sp + TAP_XOUTER[k]; + bool inb = all(greaterThanEqual(q, ivec2(0))) && all(lessThanEqual(q, hi)); + + vec4 x0 = inb ? texelFetch(uIn0, q, 0) : vec4(0.0); + vec4 x1 = inb ? texelFetch(uIn1, q, 0) : vec4(0.0); + for (int co = 0; co < MID_T; ++co) { + acc[co] += convMatAt(p1ConvBase, k, 0, co, CIN_T, MID_T) * x0; + if (CIN_T > 1) + acc[co] += convMatAt(p1ConvBase, k, 1, co, CIN_T, MID_T) * x1; + } + } + } + for (int co = 0; co < MID_T; ++co) { + vec4 v; + if (centerOOB) { + v = vec4(0.0); + } else { + vec4 bias, scale, offset; + affineAt(p1AffBase, co, MID_T, bias, scale, offset); + v = (acc[co] - bias) * scale + offset; + if (PASS1_CLAMP) v = clamp(v, 0.0, 1.0); + } + sMid[co][tx][ty] = f16vec4(v); + } + } else { + + ivec2 q = clamp(sp, ivec2(0), hi); + sMid[0][tx][ty] = f16vec4(texelFetch(uIn0, q, 0)); + if (MID_T > 1) + sMid[1][tx][ty] = f16vec4(texelFetch(uIn1, q, 0)); + } + } + + barrier(); + + if (any(greaterThanEqual(p, pc.size))) return; + + ivec2 c = lid + ivec2(1); + + vec4 acc[MAX_T]; + for (int co = 0; co < COUT_T; ++co) acc[co] = vec4(0.0); + + for (int k = 0; k < 9; ++k) { + ivec2 li = c + TAP_XOUTER[k]; + for (int ci = 0; ci < MID_T; ++ci) { + vec4 x = vec4(sMid[ci][li.x][li.y]); + for (int co = 0; co < COUT_T; ++co) + acc[co] += convMatAt(p2ConvBase, k, ci, co, MID_T, COUT_T) * x; + } + } + + for (int co = 0; co < COUT_T; ++co) { + vec4 bias, scale, offset; + affineAt(p2AffBase, co, COUT_T, bias, scale, offset); + vec4 v = (acc[co] - bias) * scale + offset; + if (co == 0) imageStore(uOut0, p, v); + else if (co == 1) imageStore(uOut1, p, v); + } +} diff --git a/app/src/main/cpp/winlator/vk/shaders/cnn_correlation.comp b/app/src/main/cpp/winlator/vk/shaders/cnn_correlation.comp new file mode 100644 index 000000000..cd343183c --- /dev/null +++ b/app/src/main/cpp/winlator/vk/shaders/cnn_correlation.comp @@ -0,0 +1,138 @@ +#version 450 +#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require + +layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +layout(set = 0, binding = 0) uniform sampler2DArray uSrc; +layout(set = 0, binding = 2) uniform sampler2DArray uSrc2; +layout(set = 0, binding = 36) uniform sampler2D uFlow; +layout(set = 0, binding = 1, rgba16f) uniform writeonly image2DArray uDst; +layout(set = 0, binding = 8, std430) readonly buffer Weights { float16_t W[]; }; + +layout(push_constant) uniform PC { + ivec2 size; + float t; + float mvScale; + uint wBase; + int cinT; + int coutT; + int flags; +} pc; + +const int V_LOGIT = 0; +const int V_MIX = 1; +int variant() { return (pc.flags >> 8) & 0xF; } +bool useWarp() { return (pc.flags & (1 << 12)) != 0; } + +const ivec2 TAP[9] = ivec2[]( + ivec2(-1,-1), ivec2(0,-1), ivec2(1,-1), + ivec2(-1, 0), ivec2(0, 0), ivec2(1, 0), + ivec2(-1, 1), ivec2(0, 1), ivec2(1, 1)); + +f16vec4 wVec4(uint o) { + return f16vec4(W[o + 0u], W[o + 1u], W[o + 2u], W[o + 3u]); +} +f16mat4 wMat4(uint o) { + return f16mat4(wVec4(o), wVec4(o + 4u), wVec4(o + 8u), wVec4(o + 12u)); +} + +f16vec4 sampleA(int L, vec2 uv) { return f16vec4(textureLod(uSrc, vec3(uv, float(L)), 0.0)); } +f16vec4 sampleBoff(int L, vec2 uv, ivec2 off) { + vec2 texel = 1.0 / vec2(textureSize(uSrc2, 0).xy); + return f16vec4(textureLod(uSrc2, vec3(uv + vec2(off) * texel, float(L)), 0.0)); +} + +void main() { + ivec2 p = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(p, pc.size))) return; + + int cinT = pc.cinT; + vec2 sz = vec2(textureSize(uSrc, 0).xy); + vec2 ctr = vec2(p) + 0.5; + + vec2 uvA = ctr / sz; + vec2 uvB = ctr / sz; + if (useWarp()) { + vec4 flow = texture(uFlow, ctr / sz) * pc.mvScale; + vec2 fwd = flow.xy * pc.t; + vec2 bwd = flow.zw * (1.0 - pc.t); + uvA = (ctr + fwd) / sz; + uvB = (ctr + bwd) / sz; + } + + bool dualRef = (variant() == V_MIX); + + f16vec4 scoreA = f16vec4(0.0hf); + f16vec4 scoreA2 = f16vec4(0.0hf); + float16_t scoreA8 = 0.0hf; + f16vec4 scoreB = f16vec4(0.0hf); + f16vec4 scoreB2 = f16vec4(0.0hf); + float16_t scoreB8 = 0.0hf; + + for (int t = 0; t < 9; t++) { + float16_t sA = 0.0hf; + float16_t sB = 0.0hf; + for (int L = 0; L < cinT; L++) { + f16vec4 a = sampleA(L, uvA); + f16vec4 bt = sampleBoff(L, uvB, TAP[t]); + sA += float16_t(dot(a, bt)); + if (dualRef) { + f16vec4 a2 = sampleA(cinT + L, uvA); + sB += float16_t(dot(a2, bt)); + } + } + if (t < 4) { scoreA[t] = sA; scoreB[t] = sB; } + else if (t < 8) { scoreA2[t - 4] = sA; scoreB2[t - 4] = sB; } + else { scoreA8 = sA; scoreB8 = sB; } + } + + if (variant() == V_LOGIT) { + uint o = pc.wBase; + f16vec4 subA = wVec4(o); f16vec4 mulA = wVec4(o + 4u); f16vec4 addA = wVec4(o + 8u); + f16vec4 subB = wVec4(o + 12u); f16vec4 mulB = wVec4(o + 16u); f16vec4 addB = wVec4(o + 20u); + f16vec4 subC = wVec4(o + 24u); f16vec4 mulC = wVec4(o + 28u); f16vec4 addC = wVec4(o + 32u); + + f16vec4 costA = (scoreA - subA) * mulA + addA; + f16vec4 costB = (scoreA2 - subB) * mulB + addB; + float16_t costC = (scoreA8 - subC.x) * mulC.x + addC.x; + + imageStore(uDst, ivec3(p, 0), vec4(costA)); + imageStore(uDst, ivec3(p, 1), vec4(costB)); + imageStore(uDst, ivec3(p, 2), vec4(costC, 0.0, 0.0, 0.0)); + return; + } + + uint o = pc.wBase; + f16vec4 subA = wVec4(o); f16vec4 mulA = wVec4(o + 4u); f16vec4 addA = wVec4(o + 8u); + f16vec4 subB = wVec4(o + 12u); f16vec4 mulB = wVec4(o + 16u); f16vec4 addB = wVec4(o + 20u); + f16vec4 subAb = wVec4(o + 24u); f16vec4 mulAb = wVec4(o + 28u); f16vec4 addAb = wVec4(o + 32u); + f16vec4 subBb = wVec4(o + 36u); f16vec4 mulBb = wVec4(o + 40u); f16vec4 addBb = wVec4(o + 44u); + f16vec4 subC = wVec4(o + 48u); f16vec4 mulC = wVec4(o + 52u); f16vec4 addC = wVec4(o + 56u); + + f16vec4 nA0 = clamp((scoreA - subA ) * mulA + addA , f16vec4(0.0hf), f16vec4(1.0hf)); + f16vec4 nA1 = clamp((scoreA2 - subB ) * mulB + addB , f16vec4(0.0hf), f16vec4(1.0hf)); + f16vec4 nB0 = clamp((scoreB - subAb) * mulAb + addAb, f16vec4(0.0hf), f16vec4(1.0hf)); + f16vec4 nB1 = clamp((scoreB2 - subBb) * mulBb + addBb, f16vec4(0.0hf), f16vec4(1.0hf)); + float16_t nAC = clamp((scoreA8 - subC.x) * mulC.x + addC.x, 0.0hf, 1.0hf); + float16_t nBC = clamp((scoreB8 - subC.x) * mulC.x + addC.x, 0.0hf, 1.0hf); + + uint h = o + 60u; + for (int head = 0; head < 2; head++) { + f16mat4 M0 = wMat4(h); + f16mat4 M1 = wMat4(h + 16u); + f16mat4 M2 = wMat4(h + 32u); + f16mat4 M3 = wMat4(h + 48u); + f16vec4 V0 = wVec4(h + 64u); + f16vec4 V1 = wVec4(h + 68u); + f16vec4 oSub = wVec4(h + 72u); + f16vec4 oMul = wVec4(h + 76u); + f16vec4 oAdd = wVec4(h + 80u); + + f16vec4 acc = M0 * nA0 + M1 * nA1 + V0 * nAC + + M2 * nB0 + M3 * nB1 + V1 * nBC; + f16vec4 outv = (acc - oSub) * oMul + oAdd; + imageStore(uDst, ivec3(p, head), vec4(outv)); + + h += 84u; + } +} diff --git a/app/src/main/cpp/winlator/vk/shaders/cnn_correlation_cost9.comp b/app/src/main/cpp/winlator/vk/shaders/cnn_correlation_cost9.comp new file mode 100644 index 000000000..4fe865120 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/shaders/cnn_correlation_cost9.comp @@ -0,0 +1,107 @@ +#version 450 +#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require + +layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +layout(set = 0, binding = 32) uniform sampler2D uR0; +layout(set = 0, binding = 33) uniform sampler2D uR1; +layout(set = 0, binding = 34) uniform sampler2D uR2; +layout(set = 0, binding = 35) uniform sampler2D uR3; +layout(set = 0, binding = 36) uniform sampler2D uS0; +layout(set = 0, binding = 37) uniform sampler2D uS1; +layout(set = 0, binding = 38) uniform sampler2D uS2; +layout(set = 0, binding = 39) uniform sampler2D uS3; + +layout(set = 0, binding = 40) uniform sampler2D uFlow; + +layout(set = 0, binding = 48, rgba8) uniform writeonly image2D uOut0; +layout(set = 0, binding = 49, rgba8) uniform writeonly image2D uOut1; +layout(set = 0, binding = 50, rgba8) uniform writeonly image2D uOut2; + +layout(set = 0, binding = 8, std430) readonly buffer Weights { float16_t W[]; }; + +layout(push_constant) uniform PC { + ivec2 size; + float t; + float mvScale; + uint wBase; + int cinT; + int coutT; + int flags; +} pc; + +f16vec4 wVec4(uint o){ return f16vec4(W[o],W[o+1u],W[o+2u],W[o+3u]); } + +f16vec4 refTile(int i, vec2 uv){ + if(i==0) return f16vec4(textureLod(uR0,uv,0.0)); + if(i==1) return f16vec4(textureLod(uR1,uv,0.0)); + if(i==2) return f16vec4(textureLod(uR2,uv,0.0)); + return f16vec4(textureLod(uR3,uv,0.0)); +} + +f16vec4 srchTile(int i, vec2 uv, vec2 texel, ivec2 off){ + vec2 u = uv + vec2(off)*texel; + if(pc.cinT==2){ + + if(i==0) return f16vec4(textureLod(uR2,u,0.0)); + return f16vec4(textureLod(uR3,u,0.0)); + } + + if(i==0) return f16vec4(textureLod(uS0,u,0.0)); + if(i==1) return f16vec4(textureLod(uS1,u,0.0)); + if(i==2) return f16vec4(textureLod(uS2,u,0.0)); + return f16vec4(textureLod(uS3,u,0.0)); +} + +void main(){ + ivec2 p = ivec2(gl_GlobalInvocationID.xy); + if(any(greaterThanEqual(p, pc.size))) return; + + vec2 sz = vec2(textureSize(uR0,0)); + vec2 numer = vec2(p) + 0.5; + vec2 texel = 1.0 / sz; + + vec4 flow = textureLod(uFlow, numer/sz, 0.0); + float m1 = pc.t; + vec2 dispA = flow.xy * m1; + vec2 dispB = flow.zw * (1.0 - m1); + vec2 uvRef = (numer + dispA) / sz; + vec2 uvSrc = (numer + dispB) / sz; + + int refT = pc.cinT; + + f16vec4 R[4]; + for(int i=0;i1)? dot(R[1], srchTile(1,uvSrc,texel,ivec2(ox,oy))):float16_t(0.0hf)) + \ + ((refT>2)? dot(R[2], srchTile(2,uvSrc,texel,ivec2(ox,oy))):float16_t(0.0hf)) + \ + ((refT>3)? dot(R[3], srchTile(3,uvSrc,texel,ivec2(ox,oy))):float16_t(0.0hf)) ) + + float16_t c_mm = COST(-1,-1); + float16_t c_zm = COST( 0,-1); + float16_t c_pm = COST( 1,-1); + float16_t c_mz = COST(-1, 0); + float16_t c_zz = COST( 0, 0); + float16_t c_pz = COST( 1, 0); + float16_t c_mp = COST(-1, 1); + float16_t c_zp = COST( 0, 1); + float16_t c_pp = COST( 1, 1); + + f16vec4 head0 = f16vec4(c_mm, c_zm, c_pm, c_mz); + f16vec4 head1 = f16vec4(c_zz, c_pz, c_mp, c_zp); + float16_t sc = c_pp; + + f16vec4 sub0=wVec4(pc.wBase+0u), mul0=wVec4(pc.wBase+4u), add0=wVec4(pc.wBase+8u); + f16vec4 sub1=wVec4(pc.wBase+12u), mul1=wVec4(pc.wBase+16u), add1=wVec4(pc.wBase+20u); + float16_t subS=W[pc.wBase+24u], mulS=W[pc.wBase+25u], addS=W[pc.wBase+26u]; + + f16vec4 o0 = (head0 - sub0)*mul0 + add0; + f16vec4 o1 = (head1 - sub1)*mul1 + add1; + float16_t oS = (sc - subS)*mulS + addS; + + imageStore(uOut0, p, vec4(o0)); + imageStore(uOut1, p, vec4(o1)); + imageStore(uOut2, p, vec4(float(oS),0.0,0.0,0.0)); +} diff --git a/app/src/main/cpp/winlator/vk/shaders/cnn_correlation_g09.comp b/app/src/main/cpp/winlator/vk/shaders/cnn_correlation_g09.comp new file mode 100644 index 000000000..e50c7013e --- /dev/null +++ b/app/src/main/cpp/winlator/vk/shaders/cnn_correlation_g09.comp @@ -0,0 +1,122 @@ +#version 450 +#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require + +layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +layout(set = 0, binding = 32) uniform sampler2D uA0; +layout(set = 0, binding = 33) uniform sampler2D uA1; +layout(set = 0, binding = 34) uniform sampler2D uB0; +layout(set = 0, binding = 35) uniform sampler2D uB1; +layout(set = 0, binding = 36) uniform sampler2D uC0; +layout(set = 0, binding = 37) uniform sampler2D uC1; + +layout(set = 0, binding = 48, rgba8) uniform writeonly image2D uOut0; +layout(set = 0, binding = 49, rgba8) uniform writeonly image2D uOut1; + +layout(set = 0, binding = 8, std430) readonly buffer Weights { float16_t W[]; }; + +layout(push_constant) uniform PC { + ivec2 size; + float t; + float mvScale; + uint wBase; + int cinT; + int coutT; + int flags; +} pc; + +const float16_t SUB_S = float16_t(2.509765625); +const float16_t MUL_S = float16_t(0.480712890625); +const float16_t ADD_S = float16_t(0.278076171875); +const float16_t F0 = float16_t(0.0); +const float16_t F1 = float16_t(1.0); + +f16vec4 wVec4(uint o) { return f16vec4(W[o], W[o + 1u], W[o + 2u], W[o + 3u]); } + +f16mat4 wMat4(uint o) { return f16mat4(wVec4(o), wVec4(o + 4u), wVec4(o + 8u), wVec4(o + 12u)); } + +void main() { + ivec2 p = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(p, pc.size))) return; + + vec2 sz = vec2(textureSize(uA0, 0)); + vec2 uv = (vec2(p) + 0.5) / sz; + vec2 tpx = 1.0 / sz; + + f16vec4 A0 = f16vec4(textureLod(uA0, uv, 0.0)); + f16vec4 A1 = f16vec4(textureLod(uA1, uv, 0.0)); + f16vec4 B0 = f16vec4(textureLod(uB0, uv, 0.0)); + f16vec4 B1 = f16vec4(textureLod(uB1, uv, 0.0)); + + #define COSTAB(ox, oy, outA, outB) { \ + vec2 _uv = uv + vec2(float(ox), float(oy)) * tpx; \ + f16vec4 _c0 = f16vec4(textureLod(uC0, _uv, 0.0)); \ + f16vec4 _c1 = f16vec4(textureLod(uC1, _uv, 0.0)); \ + outA = dot(A0,_c0); outA += dot(A1,_c1); \ + outB = dot(B0,_c0); outB += dot(B1,_c1); \ + } + + float16_t a_mm, b_mm, a_zm, b_zm, a_pm, b_pm, a_mz, b_mz; + float16_t a_zz, b_zz, a_pz, b_pz, a_mp, b_mp, a_zp, b_zp; + float16_t a_pp, b_pp; + + COSTAB(-1,-1, a_mm, b_mm) + COSTAB( 0,-1, a_zm, b_zm) + COSTAB( 1,-1, a_pm, b_pm) + COSTAB(-1, 0, a_mz, b_mz) + COSTAB( 0, 0, a_zz, b_zz) + COSTAB( 1, 0, a_pz, b_pz) + COSTAB(-1, 1, a_mp, b_mp) + COSTAB( 0, 1, a_zp, b_zp) + COSTAB( 1, 1, a_pp, b_pp) + + f16vec4 cvA1 = f16vec4(a_mm, a_zm, a_pm, a_mz); + f16vec4 cvA2 = f16vec4(a_zz, a_pz, a_mp, a_zp); + f16vec4 cvB1 = f16vec4(b_mm, b_zm, b_pm, b_mz); + f16vec4 cvB2 = f16vec4(b_zz, b_pz, b_mp, b_zp); + float16_t sAv = a_pp; + float16_t sBv = b_pp; + + f16vec4 sub1 = wVec4(pc.wBase + 0u), mul1 = wVec4(pc.wBase + 4u), add1 = wVec4(pc.wBase + 8u); + f16vec4 lo = wVec4(pc.wBase + 12u), hi = wVec4(pc.wBase + 16u); + f16vec4 sub2 = wVec4(pc.wBase + 20u), mul2 = wVec4(pc.wBase + 24u), add2 = wVec4(pc.wBase + 28u); + + f16vec4 qA1 = clamp((cvA1 - sub1) * mul1 + add1, lo, hi); + f16vec4 qB1 = clamp((cvB1 - sub1) * mul1 + add1, lo, hi); + f16vec4 qA2 = clamp((cvA2 - sub2) * mul2 + add2, lo, hi); + f16vec4 qB2 = clamp((cvB2 - sub2) * mul2 + add2, lo, hi); + float16_t qSa = clamp((sAv - SUB_S) * MUL_S + ADD_S, F0, F1); + float16_t qSb = clamp((sBv - SUB_S) * MUL_S + ADD_S, F0, F1); + + { + uint h = pc.wBase + 32u; + f16mat4 M_a = wMat4(h); f16mat4 M_b = wMat4(h + 16u); f16vec4 v_c = wVec4(h + 32u); + f16mat4 M_d = wMat4(h + 36u); f16mat4 M_e = wMat4(h + 52u); f16vec4 v_f = wVec4(h + 68u); + f16vec4 oSub = wVec4(h + 72u), oMul = wVec4(h + 76u), oAdd = wVec4(h + 80u); + + f16vec4 acc = M_a * qA1; + acc += M_b * qA2; + acc += v_c * qSa; + acc += M_d * qB1; + acc += M_e * qB2; + acc += v_f * qSb; + f16vec4 outv = (acc - oSub) * oMul + oAdd; + imageStore(uOut0, p, vec4(outv)); + } + + { + uint h = pc.wBase + 116u; + f16mat4 M_a = wMat4(h); f16mat4 M_b = wMat4(h + 16u); f16vec4 v_c = wVec4(h + 32u); + f16mat4 M_d = wMat4(h + 36u); f16mat4 M_e = wMat4(h + 52u); f16vec4 v_f = wVec4(h + 68u); + f16vec4 oSub = wVec4(h + 72u), oMul = wVec4(h + 76u), oAdd = wVec4(h + 80u); + + f16vec4 acc = M_a * qA1; + acc += M_b * qA2; + acc += v_c * qSa; + acc += M_d * qB1; + acc += M_e * qB2; + acc += v_f * qSb; + f16vec4 outv = (acc - oSub) * oMul + oAdd; + imageStore(uOut1, p, vec4(outv)); + } +} diff --git a/app/src/main/cpp/winlator/vk/shaders/cnn_correlation_warpfollow.comp b/app/src/main/cpp/winlator/vk/shaders/cnn_correlation_warpfollow.comp new file mode 100644 index 000000000..233ee5682 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/shaders/cnn_correlation_warpfollow.comp @@ -0,0 +1,161 @@ +#version 450 +#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require + +layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +layout(set = 0, binding = 32) uniform sampler2D uR0; +layout(set = 0, binding = 33) uniform sampler2D uR1; +layout(set = 0, binding = 34) uniform sampler2D uR2; +layout(set = 0, binding = 35) uniform sampler2D uR3; +layout(set = 0, binding = 36) uniform sampler2D uFlow0; +layout(set = 0, binding = 37) uniform sampler2D uFlow1; + +layout(set = 0, binding = 48, rgba8) uniform writeonly image2D uOut; + +layout(set = 0, binding = 8, std430) readonly buffer Weights { float16_t W[]; }; + +layout(set = 0, binding = 0) uniform UBO { float m0; float m1; float m2; } ubo; + +layout(push_constant) uniform PC { + ivec2 size; + float t; + float mvScale; + uint wBase; + int cinT; + int coutT; + int flags; +} pc; + +f16vec4 wVec4(uint o){ return f16vec4(W[o],W[o+1u],W[o+2u],W[o+3u]); } + +f16vec4 wMatVec(uint o, f16vec4 v){ + return wVec4(o+ 0u)*v.x + wVec4(o+ 4u)*v.y + wVec4(o+ 8u)*v.z + wVec4(o+12u)*v.w; +} + +void main(){ + ivec2 p = ivec2(gl_GlobalInvocationID.xy); + if(any(greaterThanEqual(p, imageSize(uOut)))) return; + + vec2 sz = vec2(textureSize(uR0, 0)); + ivec2 cmax = ivec2(sz) - ivec2(1); + vec2 numer = vec2(p) + 0.5; + vec2 uvCenter = numer / sz; + + float m1 = ubo.m1; + float16_t wFwd = float16_t(1.0 - m1); + float16_t wBwd = float16_t(m1); + + f16vec4 f0 = f16vec4(textureLod(uFlow0, uvCenter, 0.0)); + vec2 uvA0 = (numer + vec2(f0.xy * wFwd)) / sz; + vec2 uvB0 = (numer + vec2(f16vec2(textureLod(uFlow0, uvA0, 0.0).xy))) / sz; + vec2 uvC0 = (numer + vec2(f0.zw * wBwd)) / sz; + vec2 uvD0 = (numer + vec2(f16vec2(textureLod(uFlow0, uvC0, 0.0).zw))) / sz; + + f16vec4 f1 = f16vec4(textureLod(uFlow1, uvCenter, 0.0)); + vec2 uvA1 = (numer + vec2(f1.xy * wFwd)) / sz; + f16vec2 g1fwd = f16vec2(textureLod(uFlow1, uvA1, 0.0).xy); + vec2 uvC1 = (numer + vec2(f1.zw * wBwd)) / sz; + f16vec2 g1bwd = f16vec2(textureLod(uFlow1, uvC1, 0.0).zw); + vec2 uvB1 = (numer + vec2(g1fwd)) / sz; + vec2 uvD1 = (numer + vec2(g1bwd)) / sz; + + f16vec4 rA0_0 = f16vec4(textureLod(uR0, uvB0, 0.0)); + f16vec4 rA0_1 = f16vec4(textureLod(uR1, uvB0, 0.0)); + f16vec4 rA1_0 = f16vec4(textureLod(uR0, uvB1, 0.0)); + f16vec4 rA1_1 = f16vec4(textureLod(uR1, uvB1, 0.0)); + f16vec4 rB0_0 = f16vec4(textureLod(uR2, uvD0, 0.0)); + f16vec4 rB0_1 = f16vec4(textureLod(uR3, uvD0, 0.0)); + f16vec4 rB1_0 = f16vec4(textureLod(uR2, uvD1, 0.0)); + f16vec4 rB1_1 = f16vec4(textureLod(uR3, uvD1, 0.0)); + + ivec2 t_mm = clamp(p+ivec2(-1,-1), ivec2(0), cmax); + ivec2 t_zm = clamp(p+ivec2( 0,-1), ivec2(0), cmax); + ivec2 t_pm = clamp(p+ivec2( 1,-1), ivec2(0), cmax); + ivec2 t_mz = clamp(p+ivec2(-1, 0), ivec2(0), cmax); + ivec2 t_pz = clamp(p+ivec2( 1, 0), ivec2(0), cmax); + ivec2 t_mp = clamp(p+ivec2(-1, 1), ivec2(0), cmax); + ivec2 t_zp = clamp(p+ivec2( 0, 1), ivec2(0), cmax); + ivec2 t_pp = clamp(p+ivec2( 1, 1), ivec2(0), cmax); + + f16vec4 a2_mm=f16vec4(texelFetch(uR2,t_mm,0)), a3_mm=f16vec4(texelFetch(uR3,t_mm,0)); + f16vec4 a2_zm=f16vec4(texelFetch(uR2,t_zm,0)), a3_zm=f16vec4(texelFetch(uR3,t_zm,0)); + f16vec4 a2_pm=f16vec4(texelFetch(uR2,t_pm,0)), a3_pm=f16vec4(texelFetch(uR3,t_pm,0)); + f16vec4 a2_mz=f16vec4(texelFetch(uR2,t_mz,0)), a3_mz=f16vec4(texelFetch(uR3,t_mz,0)); + f16vec4 a2_zz=f16vec4(textureLod(uR2,uvCenter,0.0)), a3_zz=f16vec4(textureLod(uR3,uvCenter,0.0)); + f16vec4 a2_pz=f16vec4(texelFetch(uR2,t_pz,0)), a3_pz=f16vec4(texelFetch(uR3,t_pz,0)); + f16vec4 a2_mp=f16vec4(texelFetch(uR2,t_mp,0)), a3_mp=f16vec4(texelFetch(uR3,t_mp,0)); + f16vec4 a2_zp=f16vec4(texelFetch(uR2,t_zp,0)), a3_zp=f16vec4(texelFetch(uR3,t_zp,0)); + f16vec4 a2_pp=f16vec4(texelFetch(uR2,t_pp,0)), a3_pp=f16vec4(texelFetch(uR3,t_pp,0)); + + f16vec4 b0_mm=f16vec4(texelFetch(uR0,t_mm,0)), b1_mm=f16vec4(texelFetch(uR1,t_mm,0)); + f16vec4 b0_zm=f16vec4(texelFetch(uR0,t_zm,0)), b1_zm=f16vec4(texelFetch(uR1,t_zm,0)); + f16vec4 b0_pm=f16vec4(texelFetch(uR0,t_pm,0)), b1_pm=f16vec4(texelFetch(uR1,t_pm,0)); + f16vec4 b0_mz=f16vec4(texelFetch(uR0,t_mz,0)), b1_mz=f16vec4(texelFetch(uR1,t_mz,0)); + f16vec4 b0_zz=f16vec4(textureLod(uR0,uvCenter,0.0)), b1_zz=f16vec4(textureLod(uR1,uvCenter,0.0)); + f16vec4 b0_pz=f16vec4(texelFetch(uR0,t_pz,0)), b1_pz=f16vec4(texelFetch(uR1,t_pz,0)); + f16vec4 b0_mp=f16vec4(texelFetch(uR0,t_mp,0)), b1_mp=f16vec4(texelFetch(uR1,t_mp,0)); + f16vec4 b0_zp=f16vec4(texelFetch(uR0,t_zp,0)), b1_zp=f16vec4(texelFetch(uR1,t_zp,0)); + f16vec4 b0_pp=f16vec4(texelFetch(uR0,t_pp,0)), b1_pp=f16vec4(texelFetch(uR1,t_pp,0)); + + f16vec4 hA0g1 = f16vec4( + dot(rA0_0,a2_mm)+dot(rA0_1,a3_mm), dot(rA0_0,a2_zm)+dot(rA0_1,a3_zm), + dot(rA0_0,a2_pm)+dot(rA0_1,a3_pm), dot(rA0_0,a2_mz)+dot(rA0_1,a3_mz)); + f16vec4 hA0g2 = f16vec4( + dot(rA0_0,a2_zz)+dot(rA0_1,a3_zz), dot(rA0_0,a2_pz)+dot(rA0_1,a3_pz), + dot(rA0_0,a2_mp)+dot(rA0_1,a3_mp), dot(rA0_0,a2_zp)+dot(rA0_1,a3_zp)); + float16_t sA0 = dot(rA0_0,a2_pp)+dot(rA0_1,a3_pp); + + f16vec4 hA1g1 = f16vec4( + dot(rA1_0,a2_mm)+dot(rA1_1,a3_mm), dot(rA1_0,a2_zm)+dot(rA1_1,a3_zm), + dot(rA1_0,a2_pm)+dot(rA1_1,a3_pm), dot(rA1_0,a2_mz)+dot(rA1_1,a3_mz)); + f16vec4 hA1g2 = f16vec4( + dot(rA1_0,a2_zz)+dot(rA1_1,a3_zz), dot(rA1_0,a2_pz)+dot(rA1_1,a3_pz), + dot(rA1_0,a2_mp)+dot(rA1_1,a3_mp), dot(rA1_0,a2_zp)+dot(rA1_1,a3_zp)); + float16_t sA1 = dot(rA1_0,a2_pp)+dot(rA1_1,a3_pp); + + f16vec4 hB0g1 = f16vec4( + dot(rB0_0,b0_mm)+dot(rB0_1,b1_mm), dot(rB0_0,b0_zm)+dot(rB0_1,b1_zm), + dot(rB0_0,b0_pm)+dot(rB0_1,b1_pm), dot(rB0_0,b0_mz)+dot(rB0_1,b1_mz)); + f16vec4 hB0g2 = f16vec4( + dot(rB0_0,b0_zz)+dot(rB0_1,b1_zz), dot(rB0_0,b0_pz)+dot(rB0_1,b1_pz), + dot(rB0_0,b0_mp)+dot(rB0_1,b1_mp), dot(rB0_0,b0_zp)+dot(rB0_1,b1_zp)); + float16_t sB0 = dot(rB0_0,b0_pp)+dot(rB0_1,b1_pp); + + f16vec4 hB1g1 = f16vec4( + dot(rB1_0,b0_mm)+dot(rB1_1,b1_mm), dot(rB1_0,b0_zm)+dot(rB1_1,b1_zm), + dot(rB1_0,b0_pm)+dot(rB1_1,b1_pm), dot(rB1_0,b0_mz)+dot(rB1_1,b1_mz)); + f16vec4 hB1g2 = f16vec4( + dot(rB1_0,b0_zz)+dot(rB1_1,b1_zz), dot(rB1_0,b0_pz)+dot(rB1_1,b1_pz), + dot(rB1_0,b0_mp)+dot(rB1_1,b1_mp), dot(rB1_0,b0_zp)+dot(rB1_1,b1_zp)); + float16_t sB1 = dot(rB1_0,b0_pp)+dot(rB1_1,b1_pp); + + uint b = pc.wBase; + f16vec4 e0s=wVec4(b+144u), e0m=wVec4(b+148u), e0a=wVec4(b+152u); + f16vec4 e1s=wVec4(b+156u), e1m=wVec4(b+160u), e1a=wVec4(b+164u); + float16_t sSub=W[b+168u], sMul=W[b+169u], sAdd=W[b+170u]; + + f16vec4 ZERO = f16vec4(0.0hf), ONE = f16vec4(1.0hf); + + #define ENC0(v) clamp(((v) - e0s)*e0m + e0a, ZERO, ONE) + #define ENC1(v) clamp(((v) - e1s)*e1m + e1a, ZERO, ONE) + #define ENCS(s) clamp(((s) - sSub)*sMul + sAdd, float16_t(0.0hf), float16_t(1.0hf)) + + f16vec4 acc = f16vec4(0.0hf); + acc += wMatVec(b+ 0u, ENC0(hA0g1)); + acc += wMatVec(b+ 16u, ENC1(hA0g2)); + acc += wVec4(b+128u) * ENCS(sA0); + acc += wMatVec(b+ 32u, ENC0(hB0g1)); + acc += wMatVec(b+ 48u, ENC1(hB0g2)); + acc += wVec4(b+132u) * ENCS(sB0); + acc += wMatVec(b+ 64u, ENC0(hA1g1)); + acc += wMatVec(b+ 80u, ENC1(hA1g2)); + acc += wVec4(b+136u) * ENCS(sA1); + acc += wMatVec(b+ 96u, ENC0(hB1g1)); + acc += wMatVec(b+112u, ENC1(hB1g2)); + acc += wVec4(b+140u) * ENCS(sB1); + + f16vec4 oSub=wVec4(b+171u), oMul=wVec4(b+175u), oAdd=wVec4(b+179u); + f16vec4 outv = (acc - oSub)*oMul + oAdd; + + imageStore(uOut, p, vec4(outv)); +} diff --git a/app/src/main/cpp/winlator/vk/shaders/cnn_flowreg.comp b/app/src/main/cpp/winlator/vk/shaders/cnn_flowreg.comp new file mode 100644 index 000000000..9aab2d54f --- /dev/null +++ b/app/src/main/cpp/winlator/vk/shaders/cnn_flowreg.comp @@ -0,0 +1,87 @@ +#version 450 +#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require + +layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +layout(set = 0, binding = 32) uniform sampler2D uIn0; +layout(set = 0, binding = 33) uniform sampler2D uIn1; +layout(set = 0, binding = 34) uniform sampler2D uIn2; +layout(set = 0, binding = 35) uniform sampler2D uIn3; +layout(set = 0, binding = 36) uniform sampler2D uFlow; +layout(set = 0, binding = 37) uniform sampler2D uOcc; +layout(set = 0, binding = 48, rgba16f) uniform writeonly image2D uDst; + +layout(set = 0, binding = 8, std430) readonly buffer Weights { float16_t W[]; }; + +layout(push_constant) uniform PC { + ivec2 size; + float t; + float mvScale; + uint wBase; + int cinT; + int coutT; + int flags; +} pc; + +const ivec2 TAP[9] = ivec2[]( + ivec2(-1,-1), ivec2(0,-1), ivec2(1,-1), + ivec2(-1, 0), ivec2(0, 0), ivec2(1, 0), + ivec2(-1, 1), ivec2(0, 1), ivec2(1, 1)); + +vec4 sampIn(int ci, vec2 uv) { + if (ci == 0) return textureLod(uIn0, uv, 0.0); + if (ci == 1) return textureLod(uIn1, uv, 0.0); + if (ci == 2) return textureLod(uIn2, uv, 0.0); + return textureLod(uIn3, uv, 0.0); +} + +f16vec4 wRow(int ci, int k, int row) { + uint b = pc.wBase + uint((ci * 9 + k) * 8 + row * 4); + return f16vec4(W[b + 0u], W[b + 1u], W[b + 2u], W[b + 3u]); +} + +void main() { + ivec2 p = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(p, pc.size))) return; + + vec2 fsz = vec2(textureSize(uIn0, 0)); + vec2 numer = vec2(p) + 0.5; + vec2 uv = numer / fsz; + + f16vec2 res = f16vec2(0.0hf); + vec2 texel = vec2(1.0) / fsz; + for (int ci = 0; ci < pc.cinT; ++ci) { + for (int k = 0; k < 9; ++k) { + vec2 tuv = uv + vec2(TAP[k]) * texel; + f16vec4 s = f16vec4(sampIn(ci, tuv)); + f16vec4 r0 = wRow(ci, k, 0); + f16vec4 r1 = wRow(ci, k, 1); + res.x += dot(r0, s); + res.y += dot(r1, s); + } + } + + uint bb = pc.wBase + uint(pc.cinT * 9 * 8); + res += f16vec2(W[bb + 0u], W[bb + 1u]); + + vec2 flow = vec2(res); + + vec4 base = 2.0 * textureLod(uFlow, uv, 0.0); + vec2 fwd = base.xy + flow; + vec2 bwd = base.zw - flow; + + float t = pc.t; + + vec2 uvF = (numer + fwd * (2.0 * t) * 0.25) / fsz; + float occF = textureLod(uOcc, uvF, 0.0).x; + fwd *= (1.0 - occF); + + vec2 uvB = (numer + bwd * (2.0 * (1.0 - t)) * 0.25) / fsz; + float occB = textureLod(uOcc, uvB, 0.0).x; + bwd *= (1.0 - occB); + + float occC = textureLod(uOcc, uv, 0.0).x; + vec4 outv = vec4(fwd.x, fwd.y, bwd.x, bwd.y) * (1.0 - occC); + + imageStore(uDst, p, outv); +} diff --git a/app/src/main/cpp/winlator/vk/shaders/cnn_generate.comp b/app/src/main/cpp/winlator/vk/shaders/cnn_generate.comp new file mode 100644 index 000000000..c186eace6 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/shaders/cnn_generate.comp @@ -0,0 +1,89 @@ +#version 450 + +layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +layout(set = 0, binding = 32) uniform sampler2D backColor; +layout(set = 0, binding = 33) uniform sampler2D fwdColor; +layout(set = 0, binding = 34) uniform sampler2D flowB; +layout(set = 0, binding = 35) uniform sampler2D flowF; +layout(set = 0, binding = 36) uniform sampler2D logits; +layout(set = 0, binding = 48, rgba16f) uniform writeonly image2D uDst; + +layout(push_constant) uniform PC { + ivec2 size; + float t; + float mvScale; + uint wBase; + int cinT; + int coutT; + int flags; +} pc; + +void main() { + ivec2 p = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(p, pc.size))) + return; + + vec2 texSize = vec2(textureSize(backColor, 0)); + vec2 numer = vec2(p) + 0.5; + vec2 uvc = numer / texSize; + + vec2 flowSize = vec2(textureSize(flowB, 0)); + vec2 mvToPixel = texSize / flowSize; + float t = pc.t; + + int smR = (pc.flags >> 4) & 7; + vec2 flB, flF; + if (smR > 0) { + vec3 cc = texture(backColor, uvc).rgb; + vec2 sB = vec2(0.0), sF = vec2(0.0); float ws = 0.0; + for (int dy = -smR; dy <= smR; dy++) + for (int dx = -smR; dx <= smR; dx++) { + vec2 off = vec2(float(dx), float(dy)) / flowSize; + vec3 cn = texture(backColor, uvc + off).rgb; + float dc = dot(cn - cc, cn - cc); + float w = exp(-dc * 30.0) * exp(-float(dx*dx + dy*dy) * 0.25); + sB += texture(flowB, uvc + off).xy * w; + sF += texture(flowF, uvc + off).xy * w; + ws += w; + } + flB = sB / max(ws, 1e-4); + flF = sF / max(ws, 1e-4); + } else { + flB = texture(flowB, uvc).xy; + flF = texture(flowF, uvc).xy; + } + flB *= mvToPixel * pc.mvScale; + flF *= mvToPixel * pc.mvScale; + if ((pc.flags & 1) != 0) flF = -flF; + if ((pc.flags & 2) != 0) flF *= 0.5; + + vec2 c0 = (numer + flB * t) / texSize; + vec2 c1 = (numer - flB * (1.0 - t)) / texSize; + vec2 c2 = (numer - flF * t) / texSize; + vec2 c3 = (numer + flF * (1.0 - t)) / texSize; + + vec3 k0 = texture(backColor, c0).rgb; + vec3 k1 = texture(fwdColor, c1).rgb; + vec3 k2 = texture(backColor, c2).rgb; + vec3 k3 = texture(fwdColor, c3).rgb; + + if ((pc.flags & 8) != 0) { imageStore(uDst, p, vec4(abs(k2 - k3), 1.0)); return; } // debug viz (moved off the sign) + + vec4 L = vec4(texture(logits, c0).x, texture(logits, c1).y, + texture(logits, c2).z, texture(logits, c3).w); + float mx = max(max(L.x, L.y), max(L.z, L.w)); + vec4 e = exp(L - mx); + float w0 = (1.0 - t) * e.x; + float w1 = t * e.y; + float w2 = (1.0 - t) * e.z; + float w3 = t * e.w; + vec3 col = (k0*w0 + k1*w1 + k2*w2 + k3*w3) / (w0 + w1 + w2 + w3 + 1e-6); + + vec3 cPrevFlat = texture(backColor, uvc).rgb; + vec3 cCurrFlat = texture(fwdColor, uvc).rgb; + float staticPix = 1.0 - smoothstep(0.02, 0.06, length(cCurrFlat - cPrevFlat)); + col = mix(col, cCurrFlat, staticPix); + + imageStore(uDst, p, vec4(col, 1.0)); +} diff --git a/app/src/main/cpp/winlator/vk/shaders/cnn_occlusion.comp b/app/src/main/cpp/winlator/vk/shaders/cnn_occlusion.comp new file mode 100644 index 000000000..854db0430 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/shaders/cnn_occlusion.comp @@ -0,0 +1,129 @@ +#version 450 +#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require + +layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +layout(set = 0, binding = 0) uniform sampler2D uSrcA; +layout(set = 0, binding = 2) uniform sampler2D uSrcB; + +layout(set = 0, binding = 1, r8) uniform writeonly image2D uMip0; +layout(set = 0, binding = 3, r8) uniform writeonly image2D uMip1; +layout(set = 0, binding = 4, r8) uniform writeonly image2D uMip2; +layout(set = 0, binding = 5, r8) uniform writeonly image2D uMip3; +layout(set = 0, binding = 6, r8) uniform writeonly image2D uMip4; +layout(set = 0, binding = 7, r8) uniform writeonly image2D uMip5; + +layout(set = 0, binding = 8, std430) readonly buffer Weights { float16_t W[]; }; + +layout(push_constant) uniform PC { + ivec2 size; + float t; + float mvScale; + uint wBase; + int cinT; + int coutT; + int flags; + float occThresh; +} pc; + +const ivec2 OTAP[9] = ivec2[]( + ivec2(-1,-1), ivec2(-1, 0), ivec2(-1, 1), + ivec2( 0,-1), ivec2( 0, 0), ivec2( 0, 1), + ivec2( 1,-1), ivec2( 1, 0), ivec2( 1, 1) +); + +f16vec4 wA(int tap) { + int o = int(pc.wBase) + tap * 4; + return f16vec4(W[o], W[o + 1], W[o + 2], W[o + 3]); +} +f16vec4 wB(int tap) { + int o = int(pc.wBase) + 36 + tap * 4; + return f16vec4(W[o], W[o + 1], W[o + 2], W[o + 3]); +} + +shared float lds[32][32]; + +void main() { + ivec2 wg = ivec2(gl_WorkGroupID.xy); + ivec2 lid = ivec2(gl_LocalInvocationID.xy); + ivec2 sz = pc.size; + ivec2 hi = sz - ivec2(1); + + const float16_t bias = W[int(pc.wBase) + 72]; + const float16_t thr16 = float16_t(pc.occThresh); + const float16_t one16 = float16_t(1.0); + + for (int by = 0; by < 2; ++by) { + for (int bx = 0; bx < 2; ++bx) { + ivec2 p = wg * 32 + lid * 2 + ivec2(bx, by); + + f16vec4 a0 = f16vec4(texelFetch(uSrcA, clamp(p + OTAP[0], ivec2(0), hi), 0)); + float16_t acc = dot(a0, wA(0)); + for (int k = 1; k < 9; ++k) { + f16vec4 a = f16vec4(texelFetch(uSrcA, clamp(p + OTAP[k], ivec2(0), hi), 0)); + acc += dot(a, wA(k)); + } + for (int k = 0; k < 9; ++k) { + f16vec4 b = f16vec4(texelFetch(uSrcB, clamp(p + OTAP[k], ivec2(0), hi), 0)); + acc += dot(b, wB(k)); + } + acc += bias; + + float16_t occ = one16 / (one16 + exp(-acc)); + float16_t mask = step(thr16, occ) * occ; + + if (all(lessThan(p, sz))) + imageStore(uMip0, p, vec4(float(mask))); + + lds[lid.x * 2 + bx][lid.y * 2 + by] = float(mask); + } + } + + barrier(); + + if (lid.x < 16 && lid.y < 16) { + int i = lid.x, j = lid.y; + float avg = 0.25 * (lds[2*i][2*j] + lds[2*i+1][2*j] + + lds[2*i][2*j+1] + lds[2*i+1][2*j+1]); + ivec2 c = wg * 16 + ivec2(i, j); + if (all(lessThan(c, imageSize(uMip1)))) imageStore(uMip1, c, vec4(avg)); + lds[i][j] = avg; + } + barrier(); + + if (lid.x < 8 && lid.y < 8) { + int i = lid.x, j = lid.y; + float avg = 0.25 * (lds[2*i][2*j] + lds[2*i+1][2*j] + + lds[2*i][2*j+1] + lds[2*i+1][2*j+1]); + ivec2 c = wg * 8 + ivec2(i, j); + if (all(lessThan(c, imageSize(uMip2)))) imageStore(uMip2, c, vec4(avg)); + lds[i][j] = avg; + } + barrier(); + + if (lid.x < 4 && lid.y < 4) { + int i = lid.x, j = lid.y; + float avg = 0.25 * (lds[2*i][2*j] + lds[2*i+1][2*j] + + lds[2*i][2*j+1] + lds[2*i+1][2*j+1]); + ivec2 c = wg * 4 + ivec2(i, j); + if (all(lessThan(c, imageSize(uMip3)))) imageStore(uMip3, c, vec4(avg)); + lds[i][j] = avg; + } + barrier(); + + if (lid.x < 2 && lid.y < 2) { + int i = lid.x, j = lid.y; + float avg = 0.25 * (lds[2*i][2*j] + lds[2*i+1][2*j] + + lds[2*i][2*j+1] + lds[2*i+1][2*j+1]); + ivec2 c = wg * 2 + ivec2(i, j); + if (all(lessThan(c, imageSize(uMip4)))) imageStore(uMip4, c, vec4(avg)); + lds[i][j] = avg; + } + barrier(); + + if (lid.x < 1 && lid.y < 1) { + float avg = 0.25 * (lds[0][0] + lds[1][0] + lds[0][1] + lds[1][1]); + ivec2 c = wg; + if (all(lessThan(c, imageSize(uMip5)))) imageStore(uMip5, c, vec4(avg)); + } +} diff --git a/app/src/main/cpp/winlator/vk/shaders/cnn_pyramid.comp b/app/src/main/cpp/winlator/vk/shaders/cnn_pyramid.comp new file mode 100644 index 000000000..24f108e1c --- /dev/null +++ b/app/src/main/cpp/winlator/vk/shaders/cnn_pyramid.comp @@ -0,0 +1,53 @@ +#version 450 +#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require + +layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +layout(set = 0, binding = 0) uniform sampler2D uSrc; + +layout(set = 0, binding = 1, r8) uniform writeonly image2D uDst; + +layout(set = 0, binding = 2) uniform sampler2D uLumaPrev; + +layout(push_constant) uniform PC { + ivec2 size; + float t; + float mvScale; + uint wBase; + int cinT; + int coutT; + int flags; +} pc; + +const vec3 LUMA = vec3(0.298828125, 0.5869140625, 0.11395263671875); + +void main() { + ivec2 p = ivec2(gl_GlobalInvocationID.xy); + + if (any(greaterThanEqual(p, pc.size))) return; + + float luma; + + if ((pc.flags & 1) != 0) { + + ivec2 srcSize = textureSize(uSrc, 0); + vec2 uv = (vec2(p) + 0.5) / vec2(srcSize); + f16vec3 c = f16vec3(textureLod(uSrc, uv, 0.0).rgb); + luma = float(dot(c, f16vec3(LUMA))); + } else { + + ivec2 prevSize = textureSize(uLumaPrev, 0); + ivec2 b = p * 2; + ivec2 i00 = clamp(b, ivec2(0), prevSize - 1); + ivec2 i10 = clamp(b + ivec2(1, 0), ivec2(0), prevSize - 1); + ivec2 i01 = clamp(b + ivec2(0, 1), ivec2(0), prevSize - 1); + ivec2 i11 = clamp(b + ivec2(1, 1), ivec2(0), prevSize - 1); + float16_t l00 = float16_t(texelFetch(uLumaPrev, i00, 0).r); + float16_t l10 = float16_t(texelFetch(uLumaPrev, i10, 0).r); + float16_t l01 = float16_t(texelFetch(uLumaPrev, i01, 0).r); + float16_t l11 = float16_t(texelFetch(uLumaPrev, i11, 0).r); + luma = float((l00 + l10 + l01 + l11) * float16_t(0.25)); + } + + imageStore(uDst, p, vec4(luma)); +} diff --git a/app/src/main/cpp/winlator/vk/shaders/fg_synthshift.comp b/app/src/main/cpp/winlator/vk/shaders/fg_synthshift.comp new file mode 100644 index 000000000..f97143307 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/shaders/fg_synthshift.comp @@ -0,0 +1,27 @@ +#version 450 +// Controlled-motion harness: pattern==0 rigid shift of uSrc; pattern!=0 alias-free value-noise. +layout(local_size_x = 16, local_size_y = 16) in; +layout(set = 0, binding = 0) uniform sampler2D uSrc; +layout(set = 0, binding = 1, rgba8) uniform writeonly image2D uDst; +layout(push_constant) uniform PC { ivec2 size; float shiftX; float pattern; } pc; + +float hash(vec2 c) { return fract(sin(dot(c, vec2(12.9898, 78.233))) * 43758.5453); } +float vnoise(vec2 x) { + vec2 i = floor(x), f = fract(x); f = f * f * (3.0 - 2.0 * f); + float a = hash(i), b = hash(i + vec2(1, 0)), c = hash(i + vec2(0, 1)), d = hash(i + vec2(1, 1)); + return mix(mix(a, b, f.x), mix(c, d, f.x), f.y); +} + +void main() { + ivec2 p = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(p, pc.size))) return; + if (pc.pattern > 0.5) { + vec2 q = (vec2(p) - vec2(pc.shiftX, 0.0)) * 0.018; // ~55px features: larger than test shifts, alias-free + float n0 = vnoise(q) * 0.6 + vnoise(q * 1.9) * 0.4; + float n1 = vnoise(q + 31.7) * 0.6 + vnoise(q * 1.9 + 31.7) * 0.4; + imageStore(uDst, p, vec4(n0, n1, vnoise(q + 91.3), 1.0)); + } else { + vec2 uv = (vec2(p) + 0.5 - vec2(pc.shiftX, 0.0)) / vec2(pc.size); + imageStore(uDst, p, texture(uSrc, clamp(uv, vec2(0.0), vec2(1.0)))); + } +} diff --git a/app/src/main/cpp/winlator/vk/shaders/flowfix.comp b/app/src/main/cpp/winlator/vk/shaders/flowfix.comp new file mode 100644 index 000000000..aeb7cc6c9 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/shaders/flowfix.comp @@ -0,0 +1,63 @@ +#version 450 + +layout(local_size_x = 8, local_size_y = 8) in; + +layout(set = 0, binding = 0) uniform sampler2D prevFrame; +layout(set = 0, binding = 1) uniform sampler2D currFrame; +layout(set = 0, binding = 2) uniform sampler2D motionField; +layout(set = 0, binding = 3, rgba16f) uniform writeonly image2D fixedField; + +layout(push_constant) uniform PC { + ivec2 mvSize; + vec2 invMvSize; + float mvScale; + float minStep; + float upscale; + float phase; +} pc; + +const vec3 LUM = vec3(0.299, 0.587, 0.114); + +const vec2 DIR[8] = vec2[8](vec2(-1.0, 0.0), vec2(1.0, 0.0), vec2(0.0, -1.0), vec2(0.0, 1.0), + vec2(-1.0, -1.0), vec2(1.0, 1.0), vec2(-1.0, 1.0), vec2(1.0, -1.0)); + +float tap(vec2 base, vec2 mv) { + float t = pc.phase; + vec2 a = (base + t * mv) * pc.invMvSize; + vec2 b = (base - (1.0 - t) * mv) * pc.invMvSize; + return abs(dot(textureLod(prevFrame, a, 0.0).rgb - textureLod(currFrame, b, 0.0).rgb, LUM)); +} + +float cost(vec2 base, vec2 mv) { + return tap(base, mv) + + tap(base + vec2(-1.0, 0.0), mv) + + tap(base + vec2( 1.0, 0.0), mv) + + tap(base + vec2( 0.0, -1.0), mv) + + tap(base + vec2( 0.0, 1.0), mv); +} + +void main() { + ivec2 p = ivec2(gl_GlobalInvocationID.xy); + if (p.x >= pc.mvSize.x || p.y >= pc.mvSize.y) return; + + vec4 c0 = texelFetch(motionField, p, 0); + vec2 base = vec2(p) + 0.5; + + vec2 best = c0.xy; + float bestCost = cost(base, best); + + for (int r = 0; r < 2; ++r) { + float rad = (r == 0) ? 2.0 : 5.0; + for (int i = 0; i < 8; ++i) { + ivec2 q = clamp(p + ivec2(DIR[i] * rad), ivec2(0), pc.mvSize - 1); + vec2 cand = texelFetch(motionField, q, 0).xy; + float c = cost(base, cand); + if (c < bestCost) { bestCost = c; best = cand; } + } + } + + float cz = cost(base, vec2(0.0)); + if (cz < bestCost) { best = vec2(0.0); } + + imageStore(fixedField, p, vec4(best, c0.z, c0.w)); +} diff --git a/app/src/main/cpp/winlator/vk/shaders/interpolate.frag b/app/src/main/cpp/winlator/vk/shaders/interpolate.frag new file mode 100644 index 000000000..ffa4feb90 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/shaders/interpolate.frag @@ -0,0 +1,143 @@ +#version 450 + +precision mediump float; +precision highp int; + +layout(location = 0) in highp vec2 vUV; +layout(location = 0) out vec4 outColor; + +layout(set = 0, binding = 0) uniform mediump sampler2D prevFrame; +layout(set = 0, binding = 1) uniform mediump sampler2D currFrame; +layout(set = 0, binding = 2) uniform highp sampler2D motionField; +layout(set = 0, binding = 3) uniform highp sampler2D motionFieldFwd; + +layout(push_constant) uniform PC { + vec2 resolution; + float phase; + float occlusionLo; + float occlusionHi; + float mode; +} pc; + +bool offFrame(highp vec2 uv) { + return uv.x < 0.0 || uv.y < 0.0 || uv.x > 1.0 || uv.y > 1.0; +} + +float valid(highp vec2 p) { + return offFrame(p) ? 0.0 : 1.0; +} + +#define FM_S2(a, b) { vec2 fm_t = min(a, b); b = max(a, b); a = fm_t; } +#define FM_MN3(a, b, c) FM_S2(a, b); FM_S2(a, c); +#define FM_MX3(a, b, c) FM_S2(b, c); FM_S2(a, c); +#define FM_MNMX3(a, b, c) FM_MX3(a, b, c); FM_S2(a, b); +#define FM_MNMX4(a, b, c, d) FM_S2(a, b); FM_S2(c, d); FM_S2(a, c); FM_S2(b, d); +#define FM_MNMX5(a, b, c, d, e) FM_S2(a, b); FM_S2(c, d); FM_MN3(a, c, e); FM_MX3(b, d, e); +#define FM_MNMX6(a, b, c, d, e, f) FM_S2(a, d); FM_S2(b, e); FM_S2(c, f); FM_MN3(a, b, c); FM_MX3(d, e, f); + +vec2 flowMedian(highp vec2 uv, highp vec2 n, out float spread) { + vec2 v0 = texture(motionField, uv + vec2(-n.x, -n.y)).xy; + vec2 v1 = texture(motionField, uv + vec2( 0.0, -n.y)).xy; + vec2 v2 = texture(motionField, uv + vec2( n.x, -n.y)).xy; + vec2 v3 = texture(motionField, uv + vec2(-n.x, 0.0)).xy; + vec2 v4 = texture(motionField, uv).xy; + vec2 v5 = texture(motionField, uv + vec2( n.x, 0.0)).xy; + vec2 v6 = texture(motionField, uv + vec2(-n.x, n.y)).xy; + vec2 v7 = texture(motionField, uv + vec2( 0.0, n.y)).xy; + vec2 v8 = texture(motionField, uv + vec2( n.x, n.y)).xy; + vec2 lo = min(min(min(v0, v1), min(v2, v3)), min(min(v4, v5), min(v6, v7))); + vec2 hi = max(max(max(v0, v1), max(v2, v3)), max(max(v4, v5), max(v6, v7))); + spread = length(max(hi, v8) - min(lo, v8)); + FM_MNMX6(v0, v1, v2, v3, v4, v5); + FM_MNMX5(v1, v2, v3, v4, v6); + FM_MNMX4(v2, v3, v4, v7); + FM_MNMX3(v3, v4, v8); + return v4; +} + +void main() { + float t = clamp(pc.phase, 0.0, 1.0); + float steadier = clamp(pc.occlusionLo, 0.0, 1.0); + float tolScale = clamp(pc.occlusionHi, 0.05, 1.0) / 0.33; + bool cnn = pc.mode >= 3.5; + float imode = cnn ? pc.mode - 4.0 : pc.mode; + + highp vec2 texel = 1.0 / vec2(textureSize(currFrame, 0)); + highp vec2 norm = 1.0 / vec2(textureSize(motionField, 0)); + float flowSpread; + vec2 mvB = flowMedian(vUV, norm, flowSpread); + vec2 mvBn = mvB * norm; + + vec3 cCurrFlat = texture(currFrame, vUV).rgb; + vec3 cPrevFlat = texture(prevFrame, vUV).rgb; + + vec2 maskConf = texture(motionField, vUV).zw; + float staticMask = cnn ? 0.0 : maskConf.x; + float staticPix = max(staticMask, 1.0 - smoothstep(0.02, 0.06, length(cCurrFlat - cPrevFlat))); + float uniq = cnn ? 1.0 : smoothstep(0.08, 0.35, maskConf.y); + + if (imode > 1.5) { + highp vec2 srcPos = vUV + t * mvBn; + vec3 cWarp = texture(currFrame, srcPos).rgb; + float v = valid(srcPos); + cWarp = mix(cCurrFlat, cWarp, v); + + vec2 mvBsrc = texture(motionField, srcPos).xy; + vec2 dv = mvB - mvBsrc; + float tolE = (0.05 * dot(mvB, mvB) + 2.0) * tolScale; + float occ = smoothstep(tolE, 6.0 * tolE + 6.0, dot(dv, dv)); + float relTol = 0.10 * dot(mvB, mvB) + 4.0; + float reliable = (1.0 - smoothstep(relTol, 3.0 * relTol, dot(dv, dv))) * uniq * v; + + vec3 cPred = mix(cCurrFlat, cWarp, reliable); + vec3 col = mix(cWarp, cPred, occ); + + vec2 txE = texel; + vec3 blurE = (texture(currFrame, srcPos + vec2(txE.x, 0.0)).rgb + + texture(currFrame, srcPos - vec2(txE.x, 0.0)).rgb + + texture(currFrame, srcPos + vec2(0.0, txE.y)).rgb + + texture(currFrame, srcPos - vec2(0.0, txE.y)).rgb) * 0.25; + col += 0.55 * v * clamp(cWarp - blurE, -0.25, 0.25); + + float staticHold = staticMask * (1.0 - smoothstep(1.0, 4.0, dot(mvB, mvB))); + col = mix(col, cCurrFlat, staticHold); + outColor = vec4(clamp(col, 0.0, 1.0), 1.0); + return; + } + + bool bidir = imode > 0.5; + vec2 mvF = bidir ? texture(motionFieldFwd, vUV).xy : -mvB; + vec2 mvFn = mvF * norm; + + highp vec2 uvA = bidir ? (vUV - t * mvFn) : (vUV + t * mvBn); + highp vec2 uvB = vUV - (1.0 - t) * mvBn; + vec3 cA = texture(prevFrame, uvA).rgb; + vec3 cB = texture(currFrame, uvB).rgb; + float lA = (valid(uvA) - 1.0) * 24.0; + float lB = (valid(uvB) - 1.0) * 24.0; + float mE = max(lA, lB); + float wA = (1.0 - t) * exp(lA - mE); + float wB = t * exp(lB - mE); + float wsum = wA + wB + 1e-6; + vec3 col = (cA * wA + cB * wB) / wsum; + + vec3 xfade = mix(cPrevFlat, cCurrFlat, t); + float sideAgree = abs(dot(cA - cB, vec3(0.299, 0.587, 0.114))); + col = mix(col, (t < 0.5) ? cA : cB, smoothstep(0.05, 0.22, sideAgree)); + + vec2 tx = texel; + vec3 blurA = (texture(prevFrame, uvA + vec2(tx.x, 0.0)).rgb + + texture(prevFrame, uvA - vec2(tx.x, 0.0)).rgb + + texture(prevFrame, uvA + vec2(0.0, tx.y)).rgb + + texture(prevFrame, uvA - vec2(0.0, tx.y)).rgb) * 0.25; + vec3 blurB = (texture(currFrame, uvB + vec2(tx.x, 0.0)).rgb + + texture(currFrame, uvB - vec2(tx.x, 0.0)).rgb + + texture(currFrame, uvB + vec2(0.0, tx.y)).rgb + + texture(currFrame, uvB - vec2(0.0, tx.y)).rgb) * 0.25; + vec3 detail = ((cA - blurA) * wA + (cB - blurB) * wB) / wsum; + float kdet = 0.95 - 0.30 * steadier; + col += kdet * clamp(detail, -0.25, 0.25); + + col = mix(col, xfade, staticPix); + outColor = vec4(clamp(col, 0.0, 1.0), 1.0); +} diff --git a/app/src/main/cpp/winlator/vk/shaders/motion.comp b/app/src/main/cpp/winlator/vk/shaders/motion.comp new file mode 100644 index 000000000..4c27a8839 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/shaders/motion.comp @@ -0,0 +1,161 @@ +#version 450 + +#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require + +layout(local_size_x = 8, local_size_y = 8) in; + +layout(set = 0, binding = 0) uniform sampler2D prevFrame; +layout(set = 0, binding = 1) uniform sampler2D currFrame; +layout(set = 0, binding = 2) uniform sampler2D coarseFlow; +layout(set = 0, binding = 3, rgba16f) uniform writeonly image2D motionField; + +layout(push_constant) uniform PC { + ivec2 mvSize; + vec2 invMvSize; + float mvScale; + float minStep; + float upscale; + float _pad2; +} pc; + +const int LS = 8; +const int BR = 2; +const int RMAX = 15; +const int FR = 5; +const float WC = 3.0; +const int OFF = 2 * BR + 1; +const int PMAX = FR + OFF; + +const int TILE_P = LS + 2 * (RMAX + BR); // 42 +const int TILE_C = LS + 2 * BR; // 12 + +shared f16vec2 sPrev[TILE_P * TILE_P]; +shared f16vec2 sCurr[TILE_C * TILE_C]; + +float luma(vec3 c) { + return sqrt(max(dot(c, vec3(0.299, 0.587, 0.114)), 0.0)); +} + +float blockCost(ivec2 l, ivec2 cCenter, ivec2 d) { + float cost = 0.0; + for (int by = -BR; by <= BR; ++by) { + for (int bx = -BR; bx <= BR; ++bx) { + ivec2 cc = cCenter + ivec2(bx, by); + ivec2 pp = l + ivec2(RMAX + BR) + d + ivec2(bx, by); + vec2 dv = vec2(sCurr[cc.y * TILE_C + cc.x]) - vec2(sPrev[pp.y * TILE_P + pp.x]); + cost += dv.x * dv.x + WC * dv.y * dv.y; + } + } + return cost; +} + +vec2 coarseAt(ivec2 q) { + return pc.upscale * texture(coarseFlow, (vec2(q) + 0.5) * pc.invMvSize).xy; +} + +vec2 descAt(sampler2D img, vec2 uv, bool aa) { + vec2 ts = pc.invMvSize; + float c; + if (aa) { + vec2 o = 0.25 * ts; + c = 0.25 * (luma(textureLod(img, uv + vec2(-o.x, -o.y), 0.0).rgb) + + luma(textureLod(img, uv + vec2( o.x, -o.y), 0.0).rgb) + + luma(textureLod(img, uv + vec2(-o.x, o.y), 0.0).rgb) + + luma(textureLod(img, uv + vec2( o.x, o.y), 0.0).rgb)); + } else { + c = luma(textureLod(img, uv, 0.0).rgb); + } + float m = 0.25 * (luma(textureLod(img, uv + vec2(ts.x, 0.0), 0.0).rgb) + + luma(textureLod(img, uv - vec2(ts.x, 0.0), 0.0).rgb) + + luma(textureLod(img, uv + vec2(0.0, ts.y), 0.0).rgb) + + luma(textureLod(img, uv - vec2(0.0, ts.y), 0.0).rgb)); + return vec2(c, c - m); +} + +void main() { + ivec2 wgOrigin = ivec2(gl_WorkGroupID.xy) * LS; + ivec2 prevOrigin = wgOrigin - ivec2(RMAX + BR); + ivec2 currOrigin = wgOrigin - ivec2(BR); + + uint li = gl_LocalInvocationIndex; + const uint THREADS = uint(LS * LS); + bool fine = pc.upscale > 0.0; + + int tLo = fine ? (RMAX - PMAX) : 0; + int tSpan = fine ? (LS + 2 * (PMAX + BR)) : TILE_P; + for (uint i = li; i < uint(tSpan * tSpan); i += THREADS) { + int lx = tLo + int(i) % tSpan; + int ly = tLo + int(i) / tSpan; + ivec2 tp = prevOrigin + ivec2(lx, ly); + vec2 w = fine ? coarseAt(tp) : vec2(0.0); + vec2 uv = (vec2(tp) + w + 0.5) * pc.invMvSize; + sPrev[ly * TILE_P + lx] = f16vec2(descAt(prevFrame, uv, !fine)); + } + for (uint i = li; i < uint(TILE_C * TILE_C); i += THREADS) { + int lx = int(i) % TILE_C; + int ly = int(i) / TILE_C; + vec2 uv = (vec2(currOrigin + ivec2(lx, ly)) + 0.5) * pc.invMvSize; + sCurr[i] = f16vec2(descAt(currFrame, uv, !fine)); + } + barrier(); + + ivec2 p = ivec2(gl_GlobalInvocationID.xy); + if (p.x >= pc.mvSize.x || p.y >= pc.mvSize.y) return; + + ivec2 l = ivec2(gl_LocalInvocationID.xy); + ivec2 cCenter = l + ivec2(BR); + + int sdmax = fine ? FR : RMAX; + int pdmax = fine ? PMAX : RMAX; + int it2 = fine ? 2 : clamp(6 - int(pc.minStep), 3, 5); + + ivec2 center = ivec2(0); + float bestCost = blockCost(l, cCenter, center); + for (int step = 2; step >= 1; step >>= 1) { + int iters = (step == 2) ? it2 : 2; + for (int it = 0; it < iters; ++it) { + ivec2 localBestD = center; + float localBest = bestCost; + for (int sy = -1; sy <= 1; ++sy) { + for (int sx = -1; sx <= 1; ++sx) { + if (sx == 0 && sy == 0) continue; + ivec2 d = center + ivec2(sx, sy) * step; + if (abs(d.x) > sdmax || abs(d.y) > sdmax) continue; + float cost = blockCost(l, cCenter, d); + if (cost < localBest) { localBest = cost; localBestD = d; } + } + } + if (localBest >= bestCost * 0.94) break; + bestCost = localBest; + center = localBestD; + } + } + ivec2 bestD = clamp(center, ivec2(-(sdmax - 1)), ivec2(sdmax - 1)); + + float c00 = blockCost(l, cCenter, bestD); + float cxm = blockCost(l, cCenter, bestD + ivec2(-1, 0)); + float cxp = blockCost(l, cCenter, bestD + ivec2( 1, 0)); + float cym = blockCost(l, cCenter, bestD + ivec2( 0, -1)); + float cyp = blockCost(l, cCenter, bestD + ivec2( 0, 1)); + float dx2 = cxm - 2.0 * c00 + cxp; + float dy2 = cym - 2.0 * c00 + cyp; + vec2 frac = vec2(dx2 > 1e-7 ? clamp(0.5 * (cxm - cxp) / dx2, -0.5, 0.5) : 0.0, + dy2 > 1e-7 ? clamp(0.5 * (cym - cyp) / dy2, -0.5, 0.5) : 0.0); + vec2 sub = (fine ? coarseAt(p) : vec2(0.0)) + vec2(bestD) + frac; + + float c0 = float(sCurr[cCenter.y * TILE_C + cCenter.x].x); + float p0 = luma(textureLod(prevFrame, (vec2(p) + 0.5) * pc.invMvSize, 0.0).rgb); + float gx = abs(float(sCurr[cCenter.y * TILE_C + cCenter.x + 1].x) - c0); + float gy = abs(float(sCurr[(cCenter.y + 1) * TILE_C + cCenter.x].x) - c0); + float staticC = (1.0 - smoothstep(0.012, 0.025, abs(c0 - p0))) + * smoothstep(0.05, 0.12, gx + gy); + + float second = 3.0e30; + if (bestD.x + OFF <= pdmax) second = min(second, blockCost(l, cCenter, bestD + ivec2( OFF, 0))); + if (bestD.x - OFF >= -pdmax) second = min(second, blockCost(l, cCenter, bestD + ivec2(-OFF, 0))); + if (bestD.y + OFF <= pdmax) second = min(second, blockCost(l, cCenter, bestD + ivec2(0, OFF))); + if (bestD.y - OFF >= -pdmax) second = min(second, blockCost(l, cCenter, bestD + ivec2(0, -OFF))); + float conf = clamp((second - c00) / (second + 1.0e-3), 0.0, 1.0); + + imageStore(motionField, p, vec4(sub * pc.mvScale, staticC, conf)); +} diff --git a/app/src/main/cpp/winlator/vk/shaders/motion_fp32.comp b/app/src/main/cpp/winlator/vk/shaders/motion_fp32.comp new file mode 100644 index 000000000..699e8822d --- /dev/null +++ b/app/src/main/cpp/winlator/vk/shaders/motion_fp32.comp @@ -0,0 +1,156 @@ +#version 450 + +layout(local_size_x = 8, local_size_y = 8) in; + +layout(set = 0, binding = 0) uniform sampler2D prevFrame; +layout(set = 0, binding = 1) uniform sampler2D currFrame; +layout(set = 0, binding = 2) uniform sampler2D coarseFlow; +layout(set = 0, binding = 3, rgba16f) uniform writeonly image2D motionField; + +layout(push_constant) uniform PC { + ivec2 mvSize; + vec2 invMvSize; + float mvScale; + float minStep; + float upscale; + float _pad2; +} pc; + +const int LS = 8; +const int BR = 2; +const int RMAX = 15; +const float WC = 3.0; +const int FR = 5; +const int OFF = 2 * BR + 1; + +const int TILE_P = LS + 2 * (RMAX + BR); // 42 +const int TILE_C = LS + 2 * BR; // 12 + +shared vec2 sPrev[TILE_P * TILE_P]; +shared vec2 sCurr[TILE_C * TILE_C]; + +float luma(vec3 c) { + return sqrt(max(dot(c, vec3(0.299, 0.587, 0.114)), 0.0)); +} + +float blockCost(ivec2 l, ivec2 cCenter, ivec2 d) { + float cost = 0.0; + for (int by = -BR; by <= BR; ++by) { + for (int bx = -BR; bx <= BR; ++bx) { + ivec2 cc = cCenter + ivec2(bx, by); + ivec2 pp = l + ivec2(RMAX + BR) + d + ivec2(bx, by); + vec2 dv = sCurr[cc.y * TILE_C + cc.x] - sPrev[pp.y * TILE_P + pp.x]; + cost += dv.x * dv.x + WC * dv.y * dv.y; + } + } + return cost; +} + +vec2 coarseAt(ivec2 q) { + return pc.upscale * texture(coarseFlow, (vec2(q) + 0.5) * pc.invMvSize).xy; +} + +vec2 descAt(sampler2D img, vec2 uv, bool aa) { + vec2 ts = pc.invMvSize; + float c; + if (aa) { + vec2 o = 0.25 * ts; + c = 0.25 * (luma(textureLod(img, uv + vec2(-o.x, -o.y), 0.0).rgb) + + luma(textureLod(img, uv + vec2( o.x, -o.y), 0.0).rgb) + + luma(textureLod(img, uv + vec2(-o.x, o.y), 0.0).rgb) + + luma(textureLod(img, uv + vec2( o.x, o.y), 0.0).rgb)); + } else { + c = luma(textureLod(img, uv, 0.0).rgb); + } + float m = 0.25 * (luma(textureLod(img, uv + vec2(ts.x, 0.0), 0.0).rgb) + + luma(textureLod(img, uv - vec2(ts.x, 0.0), 0.0).rgb) + + luma(textureLod(img, uv + vec2(0.0, ts.y), 0.0).rgb) + + luma(textureLod(img, uv - vec2(0.0, ts.y), 0.0).rgb)); + return vec2(c, c - m); +} + +void main() { + ivec2 wgOrigin = ivec2(gl_WorkGroupID.xy) * LS; + ivec2 prevOrigin = wgOrigin - ivec2(RMAX + BR); + ivec2 currOrigin = wgOrigin - ivec2(BR); + + uint li = gl_LocalInvocationIndex; + const uint THREADS = uint(LS * LS); + bool fine = pc.upscale > 0.0; + + for (uint i = li; i < uint(TILE_P * TILE_P); i += THREADS) { + int lx = int(i) % TILE_P; + int ly = int(i) / TILE_P; + ivec2 tp = prevOrigin + ivec2(lx, ly); + vec2 w = fine ? coarseAt(tp) : vec2(0.0); + vec2 uv = (vec2(tp) + w + 0.5) * pc.invMvSize; + sPrev[i] = descAt(prevFrame, uv, !fine); + } + for (uint i = li; i < uint(TILE_C * TILE_C); i += THREADS) { + int lx = int(i) % TILE_C; + int ly = int(i) / TILE_C; + vec2 uv = (vec2(currOrigin + ivec2(lx, ly)) + 0.5) * pc.invMvSize; + sCurr[i] = descAt(currFrame, uv, !fine); + } + barrier(); + + ivec2 p = ivec2(gl_GlobalInvocationID.xy); + if (p.x >= pc.mvSize.x || p.y >= pc.mvSize.y) return; + + ivec2 l = ivec2(gl_LocalInvocationID.xy); + ivec2 cCenter = l + ivec2(BR); + + int sdmax = fine ? FR : RMAX; + int pdmax = RMAX; + int it2 = fine ? 2 : clamp(6 - int(pc.minStep), 3, 5); + + ivec2 center = ivec2(0); + float bestCost = blockCost(l, cCenter, center); + for (int step = 2; step >= 1; step >>= 1) { + int iters = (step == 2) ? it2 : 2; + for (int it = 0; it < iters; ++it) { + ivec2 localBestD = center; + float localBest = bestCost; + for (int sy = -1; sy <= 1; ++sy) { + for (int sx = -1; sx <= 1; ++sx) { + if (sx == 0 && sy == 0) continue; + ivec2 d = center + ivec2(sx, sy) * step; + if (abs(d.x) > sdmax || abs(d.y) > sdmax) continue; + float cost = blockCost(l, cCenter, d); + if (cost < localBest) { localBest = cost; localBestD = d; } + } + } + if (localBest >= bestCost * 0.94) break; + bestCost = localBest; + center = localBestD; + } + } + ivec2 bestD = clamp(center, ivec2(-(sdmax - 1)), ivec2(sdmax - 1)); + + float c00 = blockCost(l, cCenter, bestD); + float cxm = blockCost(l, cCenter, bestD + ivec2(-1, 0)); + float cxp = blockCost(l, cCenter, bestD + ivec2( 1, 0)); + float cym = blockCost(l, cCenter, bestD + ivec2( 0, -1)); + float cyp = blockCost(l, cCenter, bestD + ivec2( 0, 1)); + float dx2 = cxm - 2.0 * c00 + cxp; + float dy2 = cym - 2.0 * c00 + cyp; + vec2 frac = vec2(dx2 > 1e-7 ? clamp(0.5 * (cxm - cxp) / dx2, -0.5, 0.5) : 0.0, + dy2 > 1e-7 ? clamp(0.5 * (cym - cyp) / dy2, -0.5, 0.5) : 0.0); + vec2 sub = (fine ? coarseAt(p) : vec2(0.0)) + vec2(bestD) + frac; + + float c0 = sCurr[cCenter.y * TILE_C + cCenter.x].x; + float p0 = luma(textureLod(prevFrame, (vec2(p) + 0.5) * pc.invMvSize, 0.0).rgb); + float gx = abs(sCurr[cCenter.y * TILE_C + cCenter.x + 1].x - c0); + float gy = abs(sCurr[(cCenter.y + 1) * TILE_C + cCenter.x].x - c0); + float staticC = (1.0 - smoothstep(0.012, 0.025, abs(c0 - p0))) + * smoothstep(0.05, 0.12, gx + gy); + + float second = 3.0e30; + if (bestD.x + OFF <= pdmax) second = min(second, blockCost(l, cCenter, bestD + ivec2( OFF, 0))); + if (bestD.x - OFF >= -pdmax) second = min(second, blockCost(l, cCenter, bestD + ivec2(-OFF, 0))); + if (bestD.y + OFF <= pdmax) second = min(second, blockCost(l, cCenter, bestD + ivec2(0, OFF))); + if (bestD.y - OFF >= -pdmax) second = min(second, blockCost(l, cCenter, bestD + ivec2(0, -OFF))); + float conf = clamp((second - c00) / (second + 1.0e-3), 0.0, 1.0); + + imageStore(motionField, p, vec4(sub * pc.mvScale, staticC, conf)); +} diff --git a/app/src/main/cpp/winlator/vk/vk_cnn_fg.c b/app/src/main/cpp/winlator/vk/vk_cnn_fg.c new file mode 100644 index 000000000..0796c7b57 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/vk_cnn_fg.c @@ -0,0 +1,894 @@ +typedef struct CnnPC { + int32_t sx, sy; + float t; + float mvScale; + uint32_t wBase; + int32_t cinT, coutT, flags; +} CnnPC; + +#define CNN_GRID(w,h) ((uint32_t)(((w)+15u)/16u)), ((uint32_t)(((h)+15u)/16u)), 1u +#define CNN_FLOW_LEVELS 5 + +static bool cnn_wanted(void) { + char v[PROP_VALUE_MAX] = {0}; + __system_property_get("debug.winnative.fgcnn", v); + return v[0] && atoi(v) != 0; +} + +static void cnn_barrier_ml(VkCommandBuffer cmd, VkImage image, uint32_t layers, + VkImageLayout from, VkImageLayout to, + VkPipelineStageFlags src_stage, VkPipelineStageFlags dst_stage, + VkAccessFlags src_access, VkAccessFlags dst_access) { + VkImageMemoryBarrier b = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; + b.oldLayout = from; b.newLayout = to; + b.srcAccessMask = src_access; b.dstAccessMask = dst_access; + b.srcQueueFamilyIndex = b.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + b.image = image; + b.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + b.subresourceRange.levelCount = 1; b.subresourceRange.layerCount = layers; + vkCmdPipelineBarrier(cmd, src_stage, dst_stage, 0, 0, NULL, 0, NULL, 1, &b); +} +static inline void cnn_to_read(VkCommandBuffer cmd, VkImage im, uint32_t layers) { + cnn_barrier_ml(cmd, im, layers, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); +} +static inline void cnn_to_write(VkCommandBuffer cmd, VkImage im, uint32_t layers) { + cnn_barrier_ml(cmd, im, layers, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + 0, VK_ACCESS_SHADER_WRITE_BIT); +} + +typedef struct CnnBind { uint32_t binding; VkDescriptorType type; } CnnBind; + +static VkDescriptorSetLayout cnn_make_dsl(VkRenderer* r, const CnnBind* b, uint32_t n) { + VkDescriptorSetLayoutBinding lb[24]; memset(lb, 0, sizeof(lb)); + for (uint32_t i = 0; i < n; i++) { + lb[i].binding = b[i].binding; + lb[i].descriptorType = b[i].type; + lb[i].descriptorCount = 1; + lb[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + } + VkDescriptorSetLayoutCreateInfo ci = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO}; + ci.bindingCount = n; ci.pBindings = lb; + VkDescriptorSetLayout l = VK_NULL_HANDLE; + if (vkCreateDescriptorSetLayout(r->device, &ci, NULL, &l) != VK_SUCCESS) return VK_NULL_HANDLE; + return l; +} + +static bool cnn_make_pipe(VkRenderer* r, const uint32_t* spv, size_t spvLen, + VkDescriptorSetLayout dsl, VkPipelineLayout* outPL, VkPipeline* outPipe) { + VkPushConstantRange pcr = { VK_SHADER_STAGE_COMPUTE_BIT, 0, 32 }; + VkPipelineLayoutCreateInfo pli = {VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pli.setLayoutCount = 1; pli.pSetLayouts = &dsl; + pli.pushConstantRangeCount = 1; pli.pPushConstantRanges = &pcr; + if (vkCreatePipelineLayout(r->device, &pli, NULL, outPL) != VK_SUCCESS) return false; + VkShaderModule mod = load_shader_module(r, spv, spvLen); + if (!mod) return false; + *outPipe = create_compute_pipeline(r, mod, *outPL); + vkDestroyShaderModule(r->device, mod, NULL); + return *outPipe != VK_NULL_HANDLE; +} + +static bool cnn_make_gh_pipe(VkRenderer* r, const uint32_t* spv, size_t spvLen, + int hasUBO, int nIn, int nOut, + VkDescriptorSetLayout* outDsl, VkPipelineLayout* outPL, VkPipeline* outPipe) { + CnnBind b[24]; uint32_t n = 0; + if (hasUBO) { b[n].binding = 0; b[n].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; n++; } + for (int i = 0; i < nIn; i++) { b[n].binding = 32 + (uint32_t)i; b[n].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; n++; } + for (int o = 0; o < nOut; o++) { b[n].binding = 48 + (uint32_t)o; b[n].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; n++; } + *outDsl = cnn_make_dsl(r, b, n); + if (!*outDsl) return false; + VkPipelineLayoutCreateInfo pli = {VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pli.setLayoutCount = 1; pli.pSetLayouts = outDsl; + if (vkCreatePipelineLayout(r->device, &pli, NULL, outPL) != VK_SUCCESS) return false; + VkShaderModule mod = load_shader_module(r, spv, spvLen); + if (!mod) return false; + *outPipe = create_compute_pipeline(r, mod, *outPL); + vkDestroyShaderModule(r->device, mod, NULL); + return *outPipe != VK_NULL_HANDLE; +} + +static void destroy_cnn_pipelines(VkRenderer* r) { + VkPipelineSet* P = &r->pipelines; + VkPipeline pipes[] = { P->cnn_pyramid_pipe, P->cnn_conv_pipe, P->cnn_cost9_pipe, + P->cnn_flowreg_pipe, P->cnn_warpfollow_pipe, P->cnn_generate_pipe, + P->gh_d5_pipe, P->gh_d6_pipe, P->gh_d7_pipe, P->gh_d8_pipe, P->gh_d9_pipe, P->gh_d10_pipe, + P->gh_occ_pipe, P->gh_gen_pipe, P->fg_synth_pipe }; + VkPipelineLayout pls[] = { P->cnn_pyramid_pl, P->cnn_conv_pl, P->cnn_cost9_pl, + P->cnn_flowreg_pl, P->cnn_warpfollow_pl, P->cnn_generate_pl, + P->gh_d5_pl, P->gh_d6_pl, P->gh_d7_pl, P->gh_d8_pl, P->gh_d9_pl, P->gh_d10_pl, + P->gh_occ_pl, P->gh_gen_pl, P->fg_synth_pl }; + VkDescriptorSetLayout dsls[] = { P->cnn_pyramid_dsl, P->cnn_conv_dsl, P->cnn_cost9_dsl, + P->cnn_flowreg_dsl, P->cnn_warpfollow_dsl, P->cnn_generate_dsl, + P->gh_d5_dsl, P->gh_d6_dsl, P->gh_d7_dsl, P->gh_d8_dsl, P->gh_d9_dsl, P->gh_d10_dsl, + P->gh_occ_dsl, P->gh_gen_dsl, P->fg_synth_dsl }; + for (int i = 0; i < 15; i++) { + if (pipes[i]) vkDestroyPipeline(r->device, pipes[i], NULL); + if (pls[i]) vkDestroyPipelineLayout(r->device, pls[i], NULL); + if (dsls[i]) vkDestroyDescriptorSetLayout(r->device, dsls[i], NULL); + } + P->cnn_pyramid_pipe = P->cnn_conv_pipe = P->cnn_cost9_pipe = + P->cnn_flowreg_pipe = P->cnn_warpfollow_pipe = P->cnn_generate_pipe = VK_NULL_HANDLE; + P->cnn_pyramid_pl = P->cnn_conv_pl = P->cnn_cost9_pl = + P->cnn_flowreg_pl = P->cnn_warpfollow_pl = P->cnn_generate_pl = VK_NULL_HANDLE; + P->cnn_pyramid_dsl = P->cnn_conv_dsl = P->cnn_cost9_dsl = + P->cnn_flowreg_dsl = P->cnn_warpfollow_dsl = P->cnn_generate_dsl = VK_NULL_HANDLE; + P->gh_d5_pipe = P->gh_d6_pipe = P->gh_d7_pipe = P->gh_d8_pipe = P->gh_d9_pipe = P->gh_d10_pipe = VK_NULL_HANDLE; + P->gh_d5_pl = P->gh_d6_pl = P->gh_d7_pl = P->gh_d8_pl = P->gh_d9_pl = P->gh_d10_pl = VK_NULL_HANDLE; + P->gh_d5_dsl = P->gh_d6_dsl = P->gh_d7_dsl = P->gh_d8_dsl = P->gh_d9_dsl = P->gh_d10_dsl = VK_NULL_HANDLE; + P->gh_occ_pipe = P->gh_gen_pipe = VK_NULL_HANDLE; + P->gh_occ_pl = P->gh_gen_pl = VK_NULL_HANDLE; + P->fg_synth_pipe = VK_NULL_HANDLE; P->fg_synth_pl = VK_NULL_HANDLE; P->fg_synth_dsl = VK_NULL_HANDLE; + P->gh_occ_dsl = P->gh_gen_dsl = VK_NULL_HANDLE; +} + +static bool create_cnn_pipelines(VkRenderer* r) { + if (!r->fg_float16_supported) return false; + VkPipelineSet* P = &r->pipelines; + const VkDescriptorType S = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + const VkDescriptorType I = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + const VkDescriptorType B = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + const VkDescriptorType U = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + + const CnnBind pyr[] = { {0,S},{1,I},{2,S} }; + const CnnBind conv[] = { {0,S},{1,I},{3,S},{8,B} }; + const CnnBind cost9[] = { {32,S},{33,S},{34,S},{35,S},{36,S},{37,S},{38,S},{39,S},{40,S}, + {48,I},{49,I},{50,I},{8,B} }; + const CnnBind flowreg[] = { {32,S},{33,S},{34,S},{35,S},{36,S},{37,S},{48,I},{8,B} }; + const CnnBind warpf[] = { {0,U},{32,S},{33,S},{34,S},{35,S},{36,S},{37,S},{48,I},{8,B} }; + const CnnBind gen[] = { {32,S},{33,S},{34,S},{35,S},{36,S},{48,I} }; + + P->cnn_pyramid_dsl = cnn_make_dsl(r, pyr, 3); + P->cnn_conv_dsl = cnn_make_dsl(r, conv, 4); + P->cnn_cost9_dsl = cnn_make_dsl(r, cost9, 13); + P->cnn_flowreg_dsl = cnn_make_dsl(r, flowreg, 8); + P->cnn_warpfollow_dsl = cnn_make_dsl(r, warpf, 9); + P->cnn_generate_dsl = cnn_make_dsl(r, gen, 6); + if (!P->cnn_pyramid_dsl || !P->cnn_conv_dsl || !P->cnn_cost9_dsl || + !P->cnn_flowreg_dsl || !P->cnn_warpfollow_dsl || !P->cnn_generate_dsl) goto cnn_fail; + + if (!cnn_make_pipe(r, cnn_pyramid_comp, cnn_pyramid_comp_size, + P->cnn_pyramid_dsl, &P->cnn_pyramid_pl, &P->cnn_pyramid_pipe)) goto cnn_fail; + if (!cnn_make_pipe(r, cnn_conv_comp, cnn_conv_comp_size, + P->cnn_conv_dsl, &P->cnn_conv_pl, &P->cnn_conv_pipe)) goto cnn_fail; + if (!cnn_make_pipe(r, cnn_correlation_cost9_comp, cnn_correlation_cost9_comp_size, + P->cnn_cost9_dsl, &P->cnn_cost9_pl, &P->cnn_cost9_pipe)) goto cnn_fail; + if (!cnn_make_pipe(r, cnn_flowreg_comp, cnn_flowreg_comp_size, + P->cnn_flowreg_dsl, &P->cnn_flowreg_pl, &P->cnn_flowreg_pipe)) goto cnn_fail; + if (!cnn_make_pipe(r, cnn_correlation_warpfollow_comp, cnn_correlation_warpfollow_comp_size, + P->cnn_warpfollow_dsl, &P->cnn_warpfollow_pl, &P->cnn_warpfollow_pipe)) goto cnn_fail; + if (!cnn_make_pipe(r, cnn_generate_comp, cnn_generate_comp_size, + P->cnn_generate_dsl, &P->cnn_generate_pl, &P->cnn_generate_pipe)) goto cnn_fail; + { const CnnBind synth[] = { {0,S},{1,I} }; + P->fg_synth_dsl = cnn_make_dsl(r, synth, 2); + if (!P->fg_synth_dsl) goto cnn_fail; + if (!cnn_make_pipe(r, fg_synthshift_comp, fg_synthshift_comp_size, + P->fg_synth_dsl, &P->fg_synth_pl, &P->fg_synth_pipe)) goto cnn_fail; } + + if (!cnn_make_gh_pipe(r, wnfg_25_spv, wnfg_25_spv_size, 1, 6, 1, + &P->gh_d5_dsl, &P->gh_d5_pl, &P->gh_d5_pipe)) goto cnn_fail; + if (!cnn_make_gh_pipe(r, wnfg_51_spv, wnfg_51_spv_size, 0, 2, 2, + &P->gh_d6_dsl, &P->gh_d6_pl, &P->gh_d6_pipe)) goto cnn_fail; + if (!cnn_make_gh_pipe(r, wnfg_27_spv, wnfg_27_spv_size, 0, 1, 1, + &P->gh_d7_dsl, &P->gh_d7_pl, &P->gh_d7_pipe)) goto cnn_fail; + if (!cnn_make_gh_pipe(r, wnfg_28_spv, wnfg_28_spv_size, 0, 1, 1, + &P->gh_d8_dsl, &P->gh_d8_pl, &P->gh_d8_pipe)) goto cnn_fail; + if (!cnn_make_gh_pipe(r, wnfg_29_spv, wnfg_29_spv_size, 0, 2, 1, + &P->gh_d9_dsl, &P->gh_d9_pl, &P->gh_d9_pipe)) goto cnn_fail; + if (!cnn_make_gh_pipe(r, wnfg_53_spv, wnfg_53_spv_size, 0, 3, 1, + &P->gh_d10_dsl, &P->gh_d10_pl, &P->gh_d10_pipe)) goto cnn_fail; + + if (!cnn_make_gh_pipe(r, wnfg_13_spv, wnfg_13_spv_size, 1, 2, 6, + &P->gh_occ_dsl, &P->gh_occ_pl, &P->gh_occ_pipe)) goto cnn_fail; + if (!cnn_make_gh_pipe(r, wnfg_04_spv, wnfg_04_spv_size, 1, 5, 1, + &P->gh_gen_dsl, &P->gh_gen_pl, &P->gh_gen_pipe)) goto cnn_fail; + + VK_LOGI("CNN-FG pipelines built"); + return true; +cnn_fail: + VK_LOGW("CNN-FG pipelines unavailable; classical flow only"); + destroy_cnn_pipelines(r); + return false; +} + +static bool cnn_make_ssbo(VkRenderer* r, int id, const void* data, size_t n) { + VkBufferCreateInfo bc = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + bc.size = n; bc.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + bc.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + if (vkCreateBuffer(r->device, &bc, NULL, &r->fg_cnn.w[id]) != VK_SUCCESS) return false; + VkMemoryRequirements mr; vkGetBufferMemoryRequirements(r->device, r->fg_cnn.w[id], &mr); + VkMemoryAllocateInfo ai = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; + ai.allocationSize = mr.size; + ai.memoryTypeIndex = vkr_find_memory_type(r, mr.memoryTypeBits, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + if (ai.memoryTypeIndex == UINT32_MAX) return false; + if (vkAllocateMemory(r->device, &ai, NULL, &r->fg_cnn.wMem[id]) != VK_SUCCESS) return false; + vkBindBufferMemory(r->device, r->fg_cnn.w[id], r->fg_cnn.wMem[id], 0); + void* p = NULL; + if (vkMapMemory(r->device, r->fg_cnn.wMem[id], 0, n, 0, &p) != VK_SUCCESS) return false; + memcpy(p, data, n); + vkUnmapMemory(r->device, r->fg_cnn.wMem[id]); + r->fg_cnn.wLen[id] = n; + return true; +} + +static bool cnn_make_img(VkRenderer* r, VkCnnImg* o, uint32_t w, uint32_t h, + VkFormat fmt, uint32_t layers, bool arrayView) { + if (w < 1) w = 1; if (h < 1) h = 1; if (layers < 1) layers = 1; + memset(o, 0, sizeof(*o)); + o->w = w; o->h = h; o->layers = layers; + VkImageCreateInfo ic = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; + ic.imageType = VK_IMAGE_TYPE_2D; ic.format = fmt; + ic.extent.width = w; ic.extent.height = h; ic.extent.depth = 1; + ic.mipLevels = 1; ic.arrayLayers = layers; + ic.samples = VK_SAMPLE_COUNT_1_BIT; ic.tiling = VK_IMAGE_TILING_OPTIMAL; + ic.usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT + | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + ic.sharingMode = VK_SHARING_MODE_EXCLUSIVE; ic.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + if (vkCreateImage(r->device, &ic, NULL, &o->image) != VK_SUCCESS) return false; + VkMemoryRequirements mr; vkGetImageMemoryRequirements(r->device, o->image, &mr); + VkMemoryAllocateInfo ai = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; + ai.allocationSize = mr.size; + ai.memoryTypeIndex = vkr_find_memory_type(r, mr.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + if (ai.memoryTypeIndex == UINT32_MAX) return false; + if (vkAllocateMemory(r->device, &ai, NULL, &o->memory) != VK_SUCCESS) return false; + vkBindImageMemory(r->device, o->image, o->memory, 0); + + VkImageViewCreateInfo vi = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + vi.image = o->image; vi.format = fmt; + vi.viewType = arrayView ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D; + vi.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + vi.subresourceRange.levelCount = 1; + vi.subresourceRange.baseArrayLayer = 0; + vi.subresourceRange.layerCount = arrayView ? layers : 1; + if (vkCreateImageView(r->device, &vi, NULL, &o->view) != VK_SUCCESS) return false; + + uint32_t nlv = layers < 4 ? layers : 4; + for (uint32_t k = 0; k < nlv; k++) { + VkImageViewCreateInfo lv = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + lv.image = o->image; lv.format = fmt; lv.viewType = VK_IMAGE_VIEW_TYPE_2D; + lv.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + lv.subresourceRange.levelCount = 1; + lv.subresourceRange.baseArrayLayer = k; lv.subresourceRange.layerCount = 1; + if (vkCreateImageView(r->device, &lv, NULL, &o->layerView[k]) != VK_SUCCESS) return false; + } + return true; +} + +static void cnn_free_img(VkRenderer* r, VkCnnImg* o) { + for (int k = 0; k < 4; k++) if (o->layerView[k]) vkDestroyImageView(r->device, o->layerView[k], NULL); + if (o->view) vkDestroyImageView(r->device, o->view, NULL); + if (o->image) vkDestroyImage(r->device, o->image, NULL); + if (o->memory) vkFreeMemory(r->device, o->memory, NULL); + memset(o, 0, sizeof(*o)); +} + +static void fg_destroy_cnn_resources(VkRenderer* r) { + if (!r->device) return; + VkFgCnn* C = &r->fg_cnn; + for (int i = 0; i < 64; i++) { + if (C->w[i]) vkDestroyBuffer(r->device, C->w[i], NULL); + if (C->wMem[i]) vkFreeMemory(r->device, C->wMem[i], NULL); + C->w[i] = VK_NULL_HANDLE; C->wMem[i] = VK_NULL_HANDLE; C->wLen[i] = 0; + } + if (C->ubo) { vkDestroyBuffer(r->device, C->ubo, NULL); C->ubo = VK_NULL_HANDLE; } + if (C->uboMem) { vkFreeMemory(r->device, C->uboMem, NULL); C->uboMem = VK_NULL_HANDLE; } + VkCnnFeatSet* sets[3] = { &C->feat[0], &C->feat[1], &C->feat[2] }; + for (int s = 0; s < 3; s++) + for (int L = 0; L < CNN_LEVELS; L++) { + cnn_free_img(r, &sets[s]->luma[L]); cnn_free_img(r, &sets[s]->feat4a[L]); + cnn_free_img(r, &sets[s]->feat4b[L]); cnn_free_img(r, &sets[s]->feat8[L]); + } + C->featValid[0] = C->featValid[1] = C->featValid[2] = false; + for (int L = 0; L < CNN_LEVELS; L++) { + cnn_free_img(r, &C->feat8_pair[L]); cnn_free_img(r, &C->gPair8[L]); + cnn_free_img(r, &C->gExpIn[L]); cnn_free_img(r, &C->hG23b[L]); cnn_free_img(r, &C->dpair[L]); + cnn_free_img(r, &C->hG0[L]); cnn_free_img(r, &C->hG1[L]); + cnn_free_img(r, &C->hG23[L]); cnn_free_img(r, &C->hG4[L]); + cnn_free_img(r, &C->hD0[L]); cnn_free_img(r, &C->hD1[L]); + cnn_free_img(r, &C->hD2[L]); cnn_free_img(r, &C->hD3[L]); + cnn_free_img(r, &C->hD5[L]); cnn_free_img(r, &C->hD6[L]); + cnn_free_img(r, &C->hD7[L]); cnn_free_img(r, &C->hD8[L]); + cnn_free_img(r, &C->flowMid[L]); cnn_free_img(r, &C->flowRef[L]); cnn_free_img(r, &C->logits[L]); + } + cnn_free_img(r, &C->occ); cnn_free_img(r, &C->seedBlack); cnn_free_img(r, &C->dummy); + for (int s = 0; s < 3; s++) for (int m = 0; m < 6; m++) cnn_free_img(r, &C->occOut[s][m]); + for (int s = 0; s < 3; s++) { + if (C->genUboMem[s]) { vkUnmapMemory(r->device, C->genUboMem[s]); } + if (C->genUbo[s]) { vkDestroyBuffer(r->device, C->genUbo[s], NULL); C->genUbo[s] = VK_NULL_HANDLE; } + if (C->genUboMem[s]) { vkFreeMemory(r->device, C->genUboMem[s], NULL); C->genUboMem[s] = VK_NULL_HANDLE; } + C->genUboMap[s] = NULL; + if (C->genSet[s]) { vkr_free_descriptor_set(r, C->genSet[s]); C->genSet[s] = VK_NULL_HANDLE; } + cnn_free_img(r, &C->gen[s]); + } + C->genReady = false; + for (int pi = 0; pi < CNN_POOLS; pi++) + if (C->pool[pi]) { vkDestroyDescriptorPool(r->device, C->pool[pi], NULL); C->pool[pi] = VK_NULL_HANDLE; } + C->ready = false; +} + +static bool fg_create_cnn_resources(VkRenderer* r, uint32_t w, uint32_t h) { + const VkFormat R8 = VK_FORMAT_R8_UNORM, RGBA8 = VK_FORMAT_R8G8B8A8_UNORM, + F16 = VK_FORMAT_R16G16B16A16_SFLOAT; + VkFgCnn* C = &r->fg_cnn; + + uint32_t mw, mh; + fg_flow_dims(r, w, h, &mw, &mh); + uint32_t lw[CNN_LEVELS], lh[CNN_LEVELS]; + for (int L = 0; L < CNN_LEVELS; L++) { + lw[L] = (L == 0) ? mw : (lw[L-1] > 1 ? lw[L-1] / 2 : 1u); + lh[L] = (L == 0) ? mh : (lh[L-1] > 1 ? lh[L-1] / 2 : 1u); + } + + VkDescriptorPoolSize ps[] = { + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 4096u }, + { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1024u }, + { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 64u }, + { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 512u }, + }; + VkDescriptorPoolCreateInfo dpc = {VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO}; + dpc.maxSets = 1024u; dpc.poolSizeCount = 4; dpc.pPoolSizes = ps; + C->curPool = 0; + for (int pi = 0; pi < CNN_POOLS; pi++) + if (vkCreateDescriptorPool(r->device, &dpc, NULL, &C->pool[pi]) != VK_SUCCESS) return false; + + #define CNN_W(ID) if (!cnn_make_ssbo(r, ID, wnfg_##ID##_weights, (size_t)wnfg_##ID##_weights_size)) return false + CNN_W(05); CNN_W(06); CNN_W(07); CNN_W(14); CNN_W(20); CNN_W(21); CNN_W(22); + CNN_W(24); CNN_W(25); CNN_W(26); CNN_W(27); CNN_W(28); CNN_W(29); + CNN_W(36); CNN_W(37); CNN_W(42); CNN_W(45); CNN_W(51); + #undef CNN_W + + { + float ubo[4] = { 1.0f, 0.5f, 0.5f, 0.0f }; + VkBufferCreateInfo bc = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + bc.size = sizeof(ubo); bc.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + bc.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + if (vkCreateBuffer(r->device, &bc, NULL, &C->ubo) != VK_SUCCESS) return false; + VkMemoryRequirements mr; vkGetBufferMemoryRequirements(r->device, C->ubo, &mr); + VkMemoryAllocateInfo ai = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; + ai.allocationSize = mr.size; + ai.memoryTypeIndex = vkr_find_memory_type(r, mr.memoryTypeBits, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + if (ai.memoryTypeIndex == UINT32_MAX) return false; + if (vkAllocateMemory(r->device, &ai, NULL, &C->uboMem) != VK_SUCCESS) return false; + vkBindBufferMemory(r->device, C->ubo, C->uboMem, 0); + void* p = NULL; + if (vkMapMemory(r->device, C->uboMem, 0, sizeof(ubo), 0, &p) != VK_SUCCESS) return false; + memcpy(p, ubo, sizeof(ubo)); vkUnmapMemory(r->device, C->uboMem); + } + + uint32_t f2w[CNN_LEVELS], f2h[CNN_LEVELS], fw[CNN_LEVELS], fh[CNN_LEVELS]; + for (int L = 0; L < CNN_LEVELS; L++) { + f2w[L] = lw[L] > 1 ? lw[L] / 2 : 1u; f2h[L] = lh[L] > 1 ? lh[L] / 2 : 1u; + fw[L] = f2w[L] > 1 ? f2w[L] / 2 : 1u; fh[L] = f2h[L] > 1 ? f2h[L] / 2 : 1u; + } + + VkCnnFeatSet* fsets[3] = { &C->feat[0], &C->feat[1], &C->feat[2] }; + C->featValid[0] = C->featValid[1] = C->featValid[2] = false; + for (int s = 0; s < 3; s++) + for (int L = 0; L < CNN_LEVELS; L++) { + if (!cnn_make_img(r, &fsets[s]->luma[L], lw[L], lh[L], R8, 1, false)) return false; + if (!cnn_make_img(r, &fsets[s]->feat4a[L], f2w[L], f2h[L], RGBA8, 1, true)) return false; + if (!cnn_make_img(r, &fsets[s]->feat4b[L], f2w[L], f2h[L], RGBA8, 1, true)) return false; + if (!cnn_make_img(r, &fsets[s]->feat8[L], fw[L], fh[L], RGBA8, 2, true)) return false; + } + for (int L = 0; L < CNN_LEVELS; L++) { + if (!cnn_make_img(r, &C->feat8_pair[L], fw[L], fh[L], RGBA8, 4, true)) return false; + if (!cnn_make_img(r, &C->gPair8[L], fw[L], fh[L], RGBA8, 2, true)) return false; + if (!cnn_make_img(r, &C->gExpIn[L], fw[L], fh[L], RGBA8, 3, true)) return false; + if (!cnn_make_img(r, &C->hG23b[L], fw[L], fh[L], RGBA8, 4, true)) return false; + if (!cnn_make_img(r, &C->hG0[L], fw[L], fh[L], RGBA8, 2, true)) return false; + if (!cnn_make_img(r, &C->hG1[L], fw[L], fh[L], RGBA8, 2, true)) return false; + if (!cnn_make_img(r, &C->hG23[L], fw[L], fh[L], RGBA8, 4, true)) return false; + if (!cnn_make_img(r, &C->hG4[L], fw[L], fh[L], RGBA8, 2, true)) return false; + if (!cnn_make_img(r, &C->hD0[L], fw[L], fh[L], RGBA8, 3, true)) return false; + if (!cnn_make_img(r, &C->hD1[L], fw[L], fh[L], RGBA8, 3, true)) return false; + if (!cnn_make_img(r, &C->hD2[L], fw[L], fh[L], RGBA8, 2, true)) return false; + if (!cnn_make_img(r, &C->hD3[L], fw[L], fh[L], RGBA8, 1, true)) return false; + if (!cnn_make_img(r, &C->hD5[L], fw[L], fh[L], RGBA8, 1, true)) return false; + if (!cnn_make_img(r, &C->hD6[L], fw[L], fh[L], RGBA8, 2, true)) return false; + if (!cnn_make_img(r, &C->hD7[L], fw[L], fh[L], RGBA8, 1, true)) return false; + if (!cnn_make_img(r, &C->hD8[L], fw[L], fh[L], RGBA8, 1, true)) return false; + if (!cnn_make_img(r, &C->dpair[L], fw[L], fh[L], RGBA8, 2, true)) return false; + if (!cnn_make_img(r, &C->flowMid[L], fw[L], fh[L], F16, 1, false)) return false; + if (!cnn_make_img(r, &C->flowRef[L], fw[L], fh[L], F16, 1, false)) return false; + if (!cnn_make_img(r, &C->logits[L], fw[L], fh[L], F16, 1, false)) return false; + } + if (!cnn_make_img(r, &C->occ, mw, mh, F16, 1, false)) return false; + if (!cnn_make_img(r, &C->seedBlack, mw, mh, F16, 1, false)) return false; + if (!cnn_make_img(r, &C->dummy, 1, 1, RGBA8, 1, true)) return false; + + for (int s = 0; s < 3; s++) for (int m = 0; m < 6; m++) { + uint32_t ow = mw, oh = mh; + for (int k = 0; k < m; k++) { ow = ow > 1 ? ow / 2 : 1u; oh = oh > 1 ? oh / 2 : 1u; } + if (!cnn_make_img(r, &C->occOut[s][m], ow, oh, R8, 1, false)) return false; + } + for (int s = 0; s < 3; s++) { + if (!cnn_make_img(r, &C->gen[s], w, h, F16, 1, false)) return false; + C->genSet[s] = vkr_alloc_descriptor_set(r); + if (C->genSet[s] == VK_NULL_HANDLE) return false; + VkDescriptorImageInfo dii = { r->fg_sampler, C->gen[s].view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }; + VkWriteDescriptorSet wr = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET}; + wr.dstSet = C->genSet[s]; wr.dstBinding = 0; wr.descriptorCount = 1; + wr.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; wr.pImageInfo = &dii; + vkUpdateDescriptorSets(r->device, 1, &wr, 0, NULL); + + VkBufferCreateInfo bc = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + bc.size = 4 * sizeof(float); bc.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + bc.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + if (vkCreateBuffer(r->device, &bc, NULL, &C->genUbo[s]) != VK_SUCCESS) return false; + VkMemoryRequirements mr; vkGetBufferMemoryRequirements(r->device, C->genUbo[s], &mr); + VkMemoryAllocateInfo ai = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; + ai.allocationSize = mr.size; + ai.memoryTypeIndex = vkr_find_memory_type(r, mr.memoryTypeBits, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + if (ai.memoryTypeIndex == UINT32_MAX) return false; + if (vkAllocateMemory(r->device, &ai, NULL, &C->genUboMem[s]) != VK_SUCCESS) return false; + vkBindBufferMemory(r->device, C->genUbo[s], C->genUboMem[s], 0); + if (vkMapMemory(r->device, C->genUboMem[s], 0, bc.size, 0, &C->genUboMap[s]) != VK_SUCCESS) return false; + } + C->genReady = true; + + C->ready = true; + VK_LOGI("CNN-FG resources allocated (L0 %ux%u, %d levels)", mw, mh, CNN_LEVELS); + return true; +} + +static VkDescriptorSet cnn_alloc(VkRenderer* r, VkDescriptorSetLayout dsl) { + VkDescriptorSetAllocateInfo a = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + a.descriptorPool = r->fg_cnn.pool[r->fg_cnn.curPool]; a.descriptorSetCount = 1; a.pSetLayouts = &dsl; + VkDescriptorSet ds = VK_NULL_HANDLE; + if (vkAllocateDescriptorSets(r->device, &a, &ds) != VK_SUCCESS) return VK_NULL_HANDLE; + return ds; +} +static inline VkWriteDescriptorSet cnn_wimg(VkDescriptorSet ds, uint32_t b, VkDescriptorType t, + const VkDescriptorImageInfo* ii) { + VkWriteDescriptorSet w = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET}; + w.dstSet = ds; w.dstBinding = b; w.descriptorCount = 1; w.descriptorType = t; w.pImageInfo = ii; + return w; +} +static inline VkWriteDescriptorSet cnn_wbuf(VkDescriptorSet ds, uint32_t b, VkDescriptorType t, + const VkDescriptorBufferInfo* bi) { + VkWriteDescriptorSet w = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET}; + w.dstSet = ds; w.dstBinding = b; w.descriptorCount = 1; w.descriptorType = t; w.pBufferInfo = bi; + return w; +} + +static void cnn_conv_dispatch(VkRenderer* r, VkCommandBuffer cmd, + VkImageView srcArr, VkImageView lumaR8, VkImageView dstArr, + int wnfgId, int cinT, int coutT, int flags, uint32_t dW, uint32_t dH) { + VkPipelineSet* P = &r->pipelines; + VkDescriptorSet ds = cnn_alloc(r, P->cnn_conv_dsl); if (!ds) return; + VkDescriptorImageInfo s0 = {r->fg_sampler, srcArr, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; + VkDescriptorImageInfo i1 = {VK_NULL_HANDLE, dstArr, VK_IMAGE_LAYOUT_GENERAL}; + VkDescriptorImageInfo s3 = {r->fg_sampler, lumaR8, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; + VkDescriptorBufferInfo b8 = {r->fg_cnn.w[wnfgId], 0, r->fg_cnn.wLen[wnfgId]}; + VkWriteDescriptorSet w[4] = { + cnn_wimg(ds,0,VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,&s0), + cnn_wimg(ds,1,VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,&i1), + cnn_wimg(ds,3,VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,&s3), + cnn_wbuf(ds,8,VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,&b8), + }; + vkUpdateDescriptorSets(r->device, 4, w, 0, NULL); + CnnPC pc = {0}; pc.sx=(int32_t)dW; pc.sy=(int32_t)dH; pc.t=0.5f; pc.mvScale=1.0f; + pc.cinT=cinT; pc.coutT=coutT; pc.flags=flags; + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, P->cnn_conv_pipe); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, P->cnn_conv_pl, 0, 1, &ds, 0, NULL); + vkCmdPushConstants(cmd, P->cnn_conv_pl, VK_SHADER_STAGE_COMPUTE_BIT, 0, 32, &pc); + vkCmdDispatch(cmd, CNN_GRID(dW, dH)); +} + +static void cnn_pyramid_dispatch(VkRenderer* r, VkCommandBuffer cmd, + VkImageView srcView, VkImageView dstLuma, + bool level0, uint32_t w, uint32_t h) { + VkPipelineSet* P = &r->pipelines; + VkDescriptorSet ds = cnn_alloc(r, P->cnn_pyramid_dsl); if (!ds) return; + VkDescriptorImageInfo s0 = {r->fg_sampler, srcView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; + VkDescriptorImageInfo i1 = {VK_NULL_HANDLE, dstLuma, VK_IMAGE_LAYOUT_GENERAL}; + VkDescriptorImageInfo s2 = {r->fg_sampler, srcView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; + VkWriteDescriptorSet ws[3] = { + cnn_wimg(ds,0,VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,&s0), + cnn_wimg(ds,1,VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,&i1), + cnn_wimg(ds,2,VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,&s2), + }; + vkUpdateDescriptorSets(r->device, 3, ws, 0, NULL); + CnnPC pc = {0}; pc.sx=(int32_t)w; pc.sy=(int32_t)h; pc.flags = level0 ? 1 : 0; + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, P->cnn_pyramid_pipe); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, P->cnn_pyramid_pl, 0, 1, &ds, 0, NULL); + vkCmdPushConstants(cmd, P->cnn_pyramid_pl, VK_SHADER_STAGE_COMPUTE_BIT, 0, 32, &pc); + vkCmdDispatch(cmd, CNN_GRID(w, h)); +} + +static void cnn_cost9_dispatch(VkRenderer* r, VkCommandBuffer cmd, + const VkImageView in5[5], const VkImageView out3[3], + int wnfgId, uint32_t w, uint32_t h) { + VkPipelineSet* P = &r->pipelines; + VkDescriptorSet ds = cnn_alloc(r, P->cnn_cost9_dsl); if (!ds) return; + VkImageView dmy = r->fg_cnn.dummy.layerView[0]; + VkImageView srcmap[9] = { in5[0],in5[1],in5[2],in5[3], dmy, dmy, dmy, dmy, in5[4] }; + VkDescriptorImageInfo si[9]; + for (int i=0;i<9;i++) si[i]=(VkDescriptorImageInfo){r->fg_sampler, srcmap[i], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; + VkDescriptorImageInfo oi[3]; for (int i=0;i<3;i++) oi[i]=(VkDescriptorImageInfo){VK_NULL_HANDLE,out3[i],VK_IMAGE_LAYOUT_GENERAL}; + VkDescriptorBufferInfo b8 = {r->fg_cnn.w[wnfgId], 0, r->fg_cnn.wLen[wnfgId]}; + VkWriteDescriptorSet ws[13]; + for (int i=0;i<9;i++) ws[i]=cnn_wimg(ds,32+i,VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,&si[i]); + for (int i=0;i<3;i++) ws[9+i]=cnn_wimg(ds,48+i,VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,&oi[i]); + ws[12]=cnn_wbuf(ds,8,VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,&b8); + vkUpdateDescriptorSets(r->device, 13, ws, 0, NULL); + CnnPC pc = {0}; pc.sx=(int32_t)w; pc.sy=(int32_t)h; pc.t=0.5f; pc.mvScale=1.0f; pc.cinT=2; + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, P->cnn_cost9_pipe); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, P->cnn_cost9_pl, 0, 1, &ds, 0, NULL); + vkCmdPushConstants(cmd, P->cnn_cost9_pl, VK_SHADER_STAGE_COMPUTE_BIT, 0, 32, &pc); + vkCmdDispatch(cmd, CNN_GRID(w, h)); +} + +static void cnn_flowreg_dispatch(VkRenderer* r, VkCommandBuffer cmd, + VkImageView f0, VkImageView f1, VkImageView flowSeed, + VkImageView occ, VkImageView outFlow16f, uint32_t w, uint32_t h) { + VkPipelineSet* P = &r->pipelines; + VkDescriptorSet ds = cnn_alloc(r, P->cnn_flowreg_dsl); if (!ds) return; + VkImageView dmy = r->fg_cnn.dummy.layerView[0]; + VkDescriptorImageInfo s32={r->fg_sampler,f0,VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; + VkDescriptorImageInfo s33={r->fg_sampler,f1,VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; + VkDescriptorImageInfo s34={r->fg_sampler,dmy,VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; + VkDescriptorImageInfo s35={r->fg_sampler,dmy,VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; + VkDescriptorImageInfo s36={r->fg_sampler,flowSeed,VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; + VkDescriptorImageInfo s37={r->fg_sampler,occ,VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; + VkDescriptorImageInfo oi ={VK_NULL_HANDLE,outFlow16f,VK_IMAGE_LAYOUT_GENERAL}; + VkDescriptorBufferInfo b8={r->fg_cnn.w[24],0,r->fg_cnn.wLen[24]}; + VkWriteDescriptorSet ws[8] = { + cnn_wimg(ds,32,VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,&s32), + cnn_wimg(ds,33,VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,&s33), + cnn_wimg(ds,34,VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,&s34), + cnn_wimg(ds,35,VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,&s35), + cnn_wimg(ds,36,VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,&s36), + cnn_wimg(ds,37,VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,&s37), + cnn_wimg(ds,48,VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,&oi), + cnn_wbuf(ds,8,VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,&b8), + }; + vkUpdateDescriptorSets(r->device, 8, ws, 0, NULL); + CnnPC pc = {0}; pc.sx=(int32_t)w; pc.sy=(int32_t)h; pc.t=0.5f; pc.mvScale=1.0f; pc.cinT=2; + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, P->cnn_flowreg_pipe); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, P->cnn_flowreg_pl, 0, 1, &ds, 0, NULL); + vkCmdPushConstants(cmd, P->cnn_flowreg_pl, VK_SHADER_STAGE_COMPUTE_BIT, 0, 32, &pc); + vkCmdDispatch(cmd, CNN_GRID(w, h)); +} + +static void cnn_gh_dispatch(VkRenderer* r, VkCommandBuffer cmd, + VkPipeline pipe, VkPipelineLayout pl, VkDescriptorSetLayout dsl, + int hasUBO, const VkImageView* inViews, int nIn, + const VkImageView* outViews, int nOut, uint32_t w, uint32_t h) { + VkDescriptorSet ds = cnn_alloc(r, dsl); if (!ds) return; + VkDescriptorImageInfo si[8], oi[4]; VkDescriptorBufferInfo ub; + VkWriteDescriptorSet ws[16]; int nw = 0; + if (hasUBO) { + ub = (VkDescriptorBufferInfo){r->fg_cnn.ubo, 0, VK_WHOLE_SIZE}; + ws[nw++] = cnn_wbuf(ds, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &ub); + } + for (int i = 0; i < nIn; i++) { + si[i] = (VkDescriptorImageInfo){r->fg_sampler, inViews[i], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; + ws[nw++] = cnn_wimg(ds, 32 + (uint32_t)i, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &si[i]); + } + for (int o = 0; o < nOut; o++) { + oi[o] = (VkDescriptorImageInfo){VK_NULL_HANDLE, outViews[o], VK_IMAGE_LAYOUT_GENERAL}; + ws[nw++] = cnn_wimg(ds, 48 + (uint32_t)o, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &oi[o]); + } + vkUpdateDescriptorSets(r->device, (uint32_t)nw, ws, 0, NULL); + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pl, 0, 1, &ds, 0, NULL); + vkCmdDispatch(cmd, CNN_GRID(w, h)); +} + +static void cnn_clear_f16(VkCommandBuffer cmd, VkCnnImg* im) { + cnn_to_write(cmd, im->image, im->layers); + VkClearColorValue cc; memset(&cc, 0, sizeof(cc)); + VkImageSubresourceRange sr = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, im->layers}; + cnn_barrier_ml(cmd, im->image, im->layers, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_WRITE_BIT); + vkCmdClearColorImage(cmd, im->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &cc, 1, &sr); + cnn_barrier_ml(cmd, im->image, im->layers, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); +} + +static void cnn_ingest(VkRenderer* r, VkCommandBuffer cmd, VkImageView frameView, VkCnnFeatSet* FS) { + for (int L=0; Lluma[L].image, 1); + cnn_to_write(cmd, FS->feat4a[L].image, 1); + cnn_to_write(cmd, FS->feat4b[L].image, 1); + cnn_to_write(cmd, FS->feat8[L].image, 2); + } + + for (int L=0; L0) cnn_to_read(cmd, FS->luma[L-1].image, 1); + cnn_pyramid_dispatch(r, cmd, (L==0)?frameView:FS->luma[L-1].view, + FS->luma[L].view, (L==0), FS->luma[L].w, FS->luma[L].h); + } + cnn_to_read(cmd, FS->luma[CNN_FLOW_LEVELS-1].image, 1); + + for (int L=0; Lfg_cnn.dummy.view, FS->luma[L].view, + FS->feat4a[L].view, 5, 1, 1, 1|16, FS->feat4a[L].w, FS->feat4a[L].h); + for (int L=0; Lfeat4a[L].image, 1); + + for (int L=0; Lfeat4a[L].view, FS->luma[L].view, + FS->feat4b[L].view, 6, 1, 1, 0, FS->feat4b[L].w, FS->feat4b[L].h); + for (int L=0; Lfeat4b[L].image, 1); + + for (int L=0; Lfeat4b[L].view, FS->luma[L].view, + FS->feat8[L].view, 7, 1, 2, 2, FS->feat8[L].w, FS->feat8[L].h); + for (int L=0; Lfeat8[L].image, 2); +} + +static void cnn_concat4(VkCommandBuffer cmd, VkCnnImg* lo2, VkCnnImg* hi2, VkCnnImg* dst4) { + cnn_to_write(cmd, dst4->image, 4); + cnn_barrier_ml(cmd, lo2->image, 2, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT); + cnn_barrier_ml(cmd, hi2->image, 2, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT); + cnn_barrier_ml(cmd, dst4->image, 4, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT); + VkImageCopy cp[2]; memset(cp, 0, sizeof(cp)); + cp[0].srcSubresource=(VkImageSubresourceLayers){VK_IMAGE_ASPECT_COLOR_BIT,0,0,2}; + cp[0].dstSubresource=(VkImageSubresourceLayers){VK_IMAGE_ASPECT_COLOR_BIT,0,0,2}; + cp[0].extent=(VkExtent3D){dst4->w, dst4->h, 1}; + cp[1]=cp[0]; cp[1].dstSubresource.baseArrayLayer=2; + vkCmdCopyImage(cmd, lo2->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst4->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cp[0]); + vkCmdCopyImage(cmd, hi2->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst4->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cp[1]); + cnn_barrier_ml(cmd, lo2->image, 2, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT); + cnn_barrier_ml(cmd, hi2->image, 2, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT); + cnn_barrier_ml(cmd, dst4->image, 4, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); +} + +// dst2.layer0 = a.layer0, dst2.layer1 = b.layer0 (prev/curr 4ch each -> 8ch wnfg_36 input). +static void cnn_concat2(VkCommandBuffer cmd, VkCnnImg* a, VkCnnImg* b, VkCnnImg* dst2) { + cnn_to_write(cmd, dst2->image, 2); + cnn_barrier_ml(cmd, a->image, 2, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT); + cnn_barrier_ml(cmd, b->image, 2, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT); + cnn_barrier_ml(cmd, dst2->image, 2, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT); + VkImageCopy cp[2]; memset(cp, 0, sizeof(cp)); + cp[0].srcSubresource=(VkImageSubresourceLayers){VK_IMAGE_ASPECT_COLOR_BIT,0,0,1}; + cp[0].dstSubresource=(VkImageSubresourceLayers){VK_IMAGE_ASPECT_COLOR_BIT,0,0,1}; + cp[0].extent=(VkExtent3D){dst2->w, dst2->h, 1}; + cp[1]=cp[0]; cp[1].dstSubresource.baseArrayLayer=1; // dst layer1 <- b layer0 + vkCmdCopyImage(cmd, a->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst2->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cp[0]); + vkCmdCopyImage(cmd, b->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst2->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cp[1]); + cnn_barrier_ml(cmd, a->image, 2, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT); + cnn_barrier_ml(cmd, b->image, 2, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT); + cnn_barrier_ml(cmd, dst2->image, 2, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); +} + +// dst3(3 layers) = src2.layer0 ++ src2.layer1 ++ 0 (wnfg_45 input; aux b34 group zeroed for now). +static void cnn_pad3z(VkCommandBuffer cmd, VkCnnImg* src2, VkCnnImg* dst3) { + cnn_to_write(cmd, dst3->image, 3); + cnn_barrier_ml(cmd, src2->image, 2, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT); + cnn_barrier_ml(cmd, dst3->image, 3, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT); + VkImageCopy cp; memset(&cp, 0, sizeof(cp)); + cp.srcSubresource=(VkImageSubresourceLayers){VK_IMAGE_ASPECT_COLOR_BIT,0,0,2}; + cp.dstSubresource=(VkImageSubresourceLayers){VK_IMAGE_ASPECT_COLOR_BIT,0,0,2}; + cp.extent=(VkExtent3D){dst3->w, dst3->h, 1}; + vkCmdCopyImage(cmd, src2->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst3->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cp); + VkClearColorValue z; memset(&z, 0, sizeof(z)); + VkImageSubresourceRange rng = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 2, 1}; // layer 2 only + vkCmdClearColorImage(cmd, dst3->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &z, 1, &rng); + cnn_barrier_ml(cmd, src2->image, 2, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT); + cnn_barrier_ml(cmd, dst3->image, 3, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); +} + +// Controlled-motion harness: write a shifted/pattern field into dst via rgba8 storeViews. +static void fg_synth_shift(VkRenderer* r, VkCommandBuffer cmd, VkFgImage* prev, VkFgImage* curr, float shiftX, int pattern) { + VkPipelineSet* P = &r->pipelines; + if (!P->fg_synth_pipe || !prev->storeView || !curr->storeView) return; + VkDescriptorSet ds = cnn_alloc(r, P->fg_synth_dsl); if (!ds) return; + vkr_image_barrier(cmd, curr->image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_SHADER_WRITE_BIT); + VkDescriptorImageInfo s0 = { r->fg_sampler, prev->storeView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }; + VkDescriptorImageInfo i1 = { VK_NULL_HANDLE, curr->storeView, VK_IMAGE_LAYOUT_GENERAL }; + VkWriteDescriptorSet w[2] = { + cnn_wimg(ds, 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &s0), + cnn_wimg(ds, 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &i1) }; + vkUpdateDescriptorSets(r->device, 2, w, 0, NULL); + struct { int32_t sx, sy; float shiftX, pat; } pc = { (int32_t)curr->width, (int32_t)curr->height, shiftX, (float)pattern }; + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, P->fg_synth_pipe); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, P->fg_synth_pl, 0, 1, &ds, 0, NULL); + vkCmdPushConstants(cmd, P->fg_synth_pl, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(pc), &pc); + vkCmdDispatch(cmd, (curr->width + 15u) / 16u, (curr->height + 15u) / 16u, 1u); + vkr_image_barrier(cmd, curr->image, + VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); +} + +static void cnn_flow_pass(VkRenderer* r, VkCommandBuffer cmd, uint32_t parity, + VkFgImage* prevFrame, VkFgImage* currFrame, bool forward, + VkFgImage* outFlow) { + (void)parity; + VkFgCnn* C = &r->fg_cnn; + if (!C->ready) return; + if (!forward) { + C->curPool = (C->curPool + 1u) % (uint32_t)CNN_POOLS; + vkResetDescriptorPool(r->device, C->pool[C->curPool], 0); + cnn_clear_f16(cmd, &C->occ); + cnn_clear_f16(cmd, &C->seedBlack); + cnn_clear_f16(cmd, &C->dummy); + } + + uint32_t prevSlot = (uint32_t)(prevFrame - r->fg_history); if (prevSlot > 2u) prevSlot = 0u; + uint32_t currSlot = (uint32_t)(currFrame - r->fg_history); if (currSlot > 2u) currSlot = 0u; + if (!C->featValid[prevSlot]) { cnn_ingest(r, cmd, prevFrame->view, &C->feat[prevSlot]); C->featValid[prevSlot] = true; } + if (!C->featValid[currSlot]) { cnn_ingest(r, cmd, currFrame->view, &C->feat[currSlot]); C->featValid[currSlot] = true; } + VkCnnFeatSet* fp = &C->feat[prevSlot]; + VkCnnFeatSet* fc = &C->feat[currSlot]; + + VkPipelineSet* P = &r->pipelines; + for (int L = CNN_FLOW_LEVELS - 1; L >= 0; --L) { + uint32_t w = C->hG0[L].w, h = C->hG0[L].h; + bool refine = (L <= 2); + VkImageView seedView = (L == CNN_FLOW_LEVELS - 1) ? C->seedBlack.view + : ((L+1 <= 2) ? C->flowRef[L+1].view : C->flowMid[L+1].view); + + cnn_concat2(cmd, &fp->feat8[L], &fc->feat8[L], &C->gPair8[L]); // prev.L0 ++ curr.L0 = 8ch (wnfg_36 wants cinT=2) + + cnn_to_write(cmd, C->hG0[L].image, 2); + cnn_conv_dispatch(r, cmd, C->gPair8[L].view, fc->luma[L].view, C->hG0[L].view, 36, 2, 2, 0, w, h); + cnn_to_read(cmd, C->hG0[L].image, 2); + cnn_to_write(cmd, C->hG1[L].image, 2); + cnn_conv_dispatch(r, cmd, C->hG0[L].view, fc->luma[L].view, C->hG1[L].view, 37, 2, 2, 0, w, h); + cnn_to_read(cmd, C->hG1[L].image, 2); + // wnfg_45 expansion: hG1 (8ch, +zero aux) -> hG23 (16ch) + cnn_pad3z(cmd, &C->hG1[L], &C->gExpIn[L]); + cnn_to_write(cmd, C->hG23[L].image, 4); + cnn_conv_dispatch(r, cmd, C->gExpIn[L].view, fc->luma[L].view, C->hG23[L].view, 45, 3, 4, 0, w, h); + cnn_to_read(cmd, C->hG23[L].image, 4); + // wnfg_42: hG23 (16ch) -> hG23b (16ch) + cnn_to_write(cmd, C->hG23b[L].image, 4); + cnn_conv_dispatch(r, cmd, C->hG23[L].view, fc->luma[L].view, C->hG23b[L].view, 42, 4, 4, 0, w, h); + cnn_to_read(cmd, C->hG23b[L].image, 4); + cnn_to_write(cmd, C->hG4[L].image, 2); + cnn_conv_dispatch(r, cmd, C->hG23b[L].view, seedView, C->hG4[L].view, 21, 3, 2, 0, w, h); + cnn_to_read(cmd, C->hG4[L].image, 2); + + cnn_to_write(cmd, C->hD0[L].image, 3); + { VkImageView in5[5]={fp->feat8[L].layerView[0],fp->feat8[L].layerView[1],fc->feat8[L].layerView[0],fc->feat8[L].layerView[1],seedView}; // REF=prev, SEARCH=curr (separated frames so the correlation tracks motion) + VkImageView out3[3]={C->hD0[L].layerView[0],C->hD0[L].layerView[1],C->hD0[L].layerView[2]}; + cnn_cost9_dispatch(r, cmd, in5, out3, 14, w, h); } + cnn_to_read(cmd, C->hD0[L].image, 3); + cnn_to_write(cmd, C->hD1[L].image, 3); + { VkImageView in5[5]={C->hD0[L].layerView[0],C->hD0[L].layerView[1],C->hD0[L].layerView[2],C->hG4[L].layerView[0],seedView}; + VkImageView out3[3]={C->hD1[L].layerView[0],C->hD1[L].layerView[1],C->hD1[L].layerView[2]}; + cnn_cost9_dispatch(r, cmd, in5, out3, 20, w, h); } + cnn_to_read(cmd, C->hD1[L].image, 3); + cnn_to_write(cmd, C->hD2[L].image, 2); + cnn_conv_dispatch(r, cmd, C->hD1[L].view, fc->luma[L].view, C->hD2[L].view, 22, 2, 2, 0, w, h); + cnn_to_read(cmd, C->hD2[L].image, 2); + cnn_to_write(cmd, C->hD3[L].image, 1); + cnn_conv_dispatch(r, cmd, C->hD2[L].view, fc->luma[L].view, C->hD3[L].view, 26, 1, 1, 0, w, h); + cnn_to_read(cmd, C->hD3[L].image, 1); + + cnn_to_write(cmd, C->flowMid[L].image, 1); + cnn_flowreg_dispatch(r, cmd, C->hD3[L].layerView[0], C->hD2[L].layerView[0], seedView, + C->occ.view, C->flowMid[L].view, w, h); + cnn_to_read(cmd, C->flowMid[L].image, 1); + + if (!refine) continue; + + cnn_to_write(cmd, C->hD5[L].image, 1); + { VkImageView in[6]={C->hD3[L].layerView[0],C->hD2[L].layerView[0],C->hG4[L].layerView[0],C->hG4[L].layerView[1],C->flowMid[L].view,seedView}; + VkImageView out[1]={C->hD5[L].layerView[0]}; + cnn_gh_dispatch(r, cmd, P->gh_d5_pipe, P->gh_d5_pl, P->gh_d5_dsl, 1, in, 6, out, 1, w, h); } + cnn_to_read(cmd, C->hD5[L].image, 1); + cnn_to_write(cmd, C->hD6[L].image, 2); + { VkImageView in[2]={C->hD5[L].layerView[0],C->hD2[L].layerView[0]}; + VkImageView out[2]={C->hD6[L].layerView[0],C->hD6[L].layerView[1]}; + cnn_gh_dispatch(r, cmd, P->gh_d6_pipe, P->gh_d6_pl, P->gh_d6_dsl, 0, in, 2, out, 2, w, h); } + cnn_to_read(cmd, C->hD6[L].image, 2); + cnn_to_write(cmd, C->hD7[L].image, 1); + { VkImageView in[1]={C->hD6[L].layerView[1]}; + VkImageView out[1]={C->hD7[L].layerView[0]}; + cnn_gh_dispatch(r, cmd, P->gh_d7_pipe, P->gh_d7_pl, P->gh_d7_dsl, 0, in, 1, out, 1, w, h); } + cnn_to_read(cmd, C->hD7[L].image, 1); + cnn_to_write(cmd, C->hD8[L].image, 1); + { VkImageView in[1]={C->hD7[L].layerView[0]}; + VkImageView out[1]={C->hD8[L].layerView[0]}; + cnn_gh_dispatch(r, cmd, P->gh_d8_pipe, P->gh_d8_pl, P->gh_d8_dsl, 0, in, 1, out, 1, w, h); } + cnn_to_read(cmd, C->hD8[L].image, 1); + + if (P->gh_d10_pipe) { + cnn_to_write(cmd, C->logits[L].image, 1); + { VkImageView in[3]={C->hD8[L].layerView[0], C->hD7[L].layerView[0], seedView}; + VkImageView out[1]={C->logits[L].view}; + cnn_gh_dispatch(r, cmd, P->gh_d10_pipe, P->gh_d10_pl, P->gh_d10_dsl, 0, in, 3, out, 1, w, h); } + cnn_to_read(cmd, C->logits[L].image, 1); + } + + VkImageView rdst = (L == 0) ? outFlow->view : C->flowRef[L].view; + VkImage rimg = (L == 0) ? outFlow->image : C->flowRef[L].image; + uint32_t rw = (L == 0) ? outFlow->width : w; + uint32_t rh = (L == 0) ? outFlow->height : h; + cnn_to_write(cmd, rimg, 1); + { VkImageView in[2]={C->hD8[L].layerView[0], seedView}; + VkImageView out[1]={rdst}; + cnn_gh_dispatch(r, cmd, P->gh_d9_pipe, P->gh_d9_pl, P->gh_d9_dsl, 0, in, 2, out, 1, rw, rh); } + if (L != 0) cnn_to_read(cmd, rimg, 1); + } + + vkr_image_barrier(cmd, outFlow->image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); +} + +static void cnn_generate_frame(VkRenderer* r, VkCommandBuffer cmd, uint32_t parity, uint32_t slot, + VkImageView prevView, VkImageView currView, float phase) { + VkFgCnn* C = &r->fg_cnn; + if (!C->ready || !C->genReady) return; + VkPipelineSet* P = &r->pipelines; + uint32_t gw = C->gen[slot].w, gh = C->gen[slot].h; + + vkr_image_barrier(cmd, r->fg_motion[parity].image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + vkr_image_barrier(cmd, r->fg_motion_fwd[parity].image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + vkr_image_barrier(cmd, C->logits[0].image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + + float t = phase < 0.0f ? 0.0f : (phase > 1.0f ? 1.0f : phase); + char m0s[16] = {0}; __system_property_get("debug.winnative.fgm0", m0s); + float m0 = m0s[0] ? (float)atof(m0s) : 1.0f; + char f2s[16] = {0}; __system_property_get("debug.winnative.fgflow2", f2s); + int flow2 = f2s[0] ? atoi(f2s) : 1; + char flgs[16] = {0}; __system_property_get("debug.winnative.fgflags", flgs); + int genflags = flgs[0] ? atoi(flgs) : 16; // default R=1 bilateral flow denoise (bits4-6); bit0 negate flF; bit1 scale flF 0.5 + + cnn_to_write(cmd, C->gen[slot].image, 1); + { + VkDescriptorSet ds = cnn_alloc(r, P->cnn_generate_dsl); if (!ds) return; + VkDescriptorImageInfo s32 = {r->fg_sampler, prevView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; + VkDescriptorImageInfo s33 = {r->fg_sampler, currView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; + VkDescriptorImageInfo s34 = {r->fg_sampler, r->fg_motion[parity].view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; + VkImageView flow2v = (flow2 && r->fg_motion_fwd_valid) ? r->fg_motion_fwd[parity].view : r->fg_motion[parity].view; + VkDescriptorImageInfo s35 = {r->fg_sampler, flow2v, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; + VkDescriptorImageInfo s36 = {r->fg_sampler, C->logits[0].view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; + VkDescriptorImageInfo oi = {VK_NULL_HANDLE, C->gen[slot].view, VK_IMAGE_LAYOUT_GENERAL}; + VkWriteDescriptorSet w[6] = { + cnn_wimg(ds, 32, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &s32), + cnn_wimg(ds, 33, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &s33), + cnn_wimg(ds, 34, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &s34), + cnn_wimg(ds, 35, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &s35), + cnn_wimg(ds, 36, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &s36), + cnn_wimg(ds, 48, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &oi), + }; + vkUpdateDescriptorSets(r->device, 6, w, 0, NULL); + CnnPC pc = {0}; pc.sx = (int32_t)gw; pc.sy = (int32_t)gh; pc.t = t; pc.mvScale = m0; pc.flags = genflags; + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, P->cnn_generate_pipe); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, P->cnn_generate_pl, 0, 1, &ds, 0, NULL); + vkCmdPushConstants(cmd, P->cnn_generate_pl, VK_SHADER_STAGE_COMPUTE_BIT, 0, 32, &pc); + vkCmdDispatch(cmd, (gw + 15u) / 16u, (gh + 15u) / 16u, 1u); + } + vkr_image_barrier(cmd, C->gen[slot].image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); +} diff --git a/app/src/main/cpp/winlator/vk/vk_dispatch.c b/app/src/main/cpp/winlator/vk/vk_dispatch.c index 870c1456c..8f9f780b7 100644 --- a/app/src/main/cpp/winlator/vk/vk_dispatch.c +++ b/app/src/main/cpp/winlator/vk/vk_dispatch.c @@ -39,8 +39,6 @@ bool vkd_init(void* libvulkan_handle) { bool vkd_load_instance(VkInstance instance) { if (!vkd.GetInstanceProcAddr || instance == VK_NULL_HANDLE) return false; - // Device entry points resolve via vkGetInstanceProcAddr too — the loader trampolines. - // See vk_dispatch.h for the rationale. #define LOAD(name) \ vkd.name = (PFN_vk##name)vkd.GetInstanceProcAddr(instance, "vk" #name) @@ -104,6 +102,7 @@ bool vkd_load_instance(VkInstance instance) { LOAD(DestroyDescriptorSetLayout); LOAD(CreateDescriptorPool); LOAD(DestroyDescriptorPool); + LOAD(ResetDescriptorPool); LOAD(AllocateDescriptorSets); LOAD(FreeDescriptorSets); LOAD(UpdateDescriptorSets); @@ -112,6 +111,7 @@ bool vkd_load_instance(VkInstance instance) { LOAD(CreatePipelineLayout); LOAD(DestroyPipelineLayout); LOAD(CreateGraphicsPipelines); + LOAD(CreateComputePipelines); LOAD(DestroyPipeline); LOAD(CreateShaderModule); LOAD(DestroyShaderModule); @@ -127,6 +127,7 @@ bool vkd_load_instance(VkInstance instance) { LOAD(DestroyFence); LOAD(ResetFences); LOAD(WaitForFences); + LOAD(GetFenceStatus); LOAD(CreateSemaphore); LOAD(DestroySemaphore); @@ -148,9 +149,13 @@ bool vkd_load_instance(VkInstance instance) { LOAD(CmdSetViewport); LOAD(CmdSetScissor); LOAD(CmdDraw); + LOAD(CmdDispatch); LOAD(CmdPipelineBarrier); - LOAD(CmdCopyBufferToImage); LOAD(CmdBlitImage); + LOAD(CmdCopyImage); + LOAD(CmdClearColorImage); + LOAD(CmdCopyBufferToImage); + LOAD(CmdCopyImageToBuffer); // Queue LOAD(QueueSubmit); diff --git a/app/src/main/cpp/winlator/vk/vk_dispatch.h b/app/src/main/cpp/winlator/vk/vk_dispatch.h index 812b084b6..2a8d6320f 100644 --- a/app/src/main/cpp/winlator/vk/vk_dispatch.h +++ b/app/src/main/cpp/winlator/vk/vk_dispatch.h @@ -1,11 +1,3 @@ -// Function-pointer dispatch for the compositor's Vulkan calls. -// -// Required because adrenotools-loaded drivers live in an isolated linker namespace and do -// not share global symbols with the system loader — every call must resolve through the -// libvulkan handle chosen at dlopen time. -// -// Init order: vkd_init(handle) -> vkCreateInstance(...) -> vkd_load_instance(instance). - #pragma once #ifndef VK_NO_PROTOTYPES @@ -15,7 +7,6 @@ #include typedef struct VkDispatch { - // Loader-level (resolved via dlsym + vkGetInstanceProcAddr(NULL, ...)) PFN_vkGetInstanceProcAddr GetInstanceProcAddr; PFN_vkCreateInstance CreateInstance; PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties; @@ -81,6 +72,7 @@ typedef struct VkDispatch { PFN_vkDestroyDescriptorSetLayout DestroyDescriptorSetLayout; PFN_vkCreateDescriptorPool CreateDescriptorPool; PFN_vkDestroyDescriptorPool DestroyDescriptorPool; + PFN_vkResetDescriptorPool ResetDescriptorPool; PFN_vkAllocateDescriptorSets AllocateDescriptorSets; PFN_vkFreeDescriptorSets FreeDescriptorSets; PFN_vkUpdateDescriptorSets UpdateDescriptorSets; @@ -89,6 +81,7 @@ typedef struct VkDispatch { PFN_vkCreatePipelineLayout CreatePipelineLayout; PFN_vkDestroyPipelineLayout DestroyPipelineLayout; PFN_vkCreateGraphicsPipelines CreateGraphicsPipelines; + PFN_vkCreateComputePipelines CreateComputePipelines; PFN_vkDestroyPipeline DestroyPipeline; PFN_vkCreateShaderModule CreateShaderModule; PFN_vkDestroyShaderModule DestroyShaderModule; @@ -104,6 +97,7 @@ typedef struct VkDispatch { PFN_vkDestroyFence DestroyFence; PFN_vkResetFences ResetFences; PFN_vkWaitForFences WaitForFences; + PFN_vkGetFenceStatus GetFenceStatus; PFN_vkCreateSemaphore CreateSemaphore; PFN_vkDestroySemaphore DestroySemaphore; @@ -125,9 +119,13 @@ typedef struct VkDispatch { PFN_vkCmdSetViewport CmdSetViewport; PFN_vkCmdSetScissor CmdSetScissor; PFN_vkCmdDraw CmdDraw; + PFN_vkCmdDispatch CmdDispatch; PFN_vkCmdPipelineBarrier CmdPipelineBarrier; - PFN_vkCmdCopyBufferToImage CmdCopyBufferToImage; PFN_vkCmdBlitImage CmdBlitImage; + PFN_vkCmdCopyImage CmdCopyImage; + PFN_vkCmdClearColorImage CmdClearColorImage; + PFN_vkCmdCopyBufferToImage CmdCopyBufferToImage; + PFN_vkCmdCopyImageToBuffer CmdCopyImageToBuffer; // Queue PFN_vkQueueSubmit QueueSubmit; @@ -145,15 +143,10 @@ extern VkDispatch vkd; bool vkd_init(void* libvulkan_handle); -// Loads device-level pointers via vkGetInstanceProcAddr too — the loader trampolines, which -// costs a few ns per call but avoids partitioning instance vs. device scope. bool vkd_load_instance(VkInstance instance); -// Must be called before dlclose so stale-pointer crashes fault on NULL. void vkd_unload(void); -// Redirect bare `vkFoo` names to the dispatch table. - #define vkGetInstanceProcAddr vkd.GetInstanceProcAddr #define vkCreateInstance vkd.CreateInstance #define vkEnumerateInstanceExtensionProperties vkd.EnumerateInstanceExtensionProperties @@ -212,6 +205,7 @@ void vkd_unload(void); #define vkDestroyDescriptorSetLayout vkd.DestroyDescriptorSetLayout #define vkCreateDescriptorPool vkd.CreateDescriptorPool #define vkDestroyDescriptorPool vkd.DestroyDescriptorPool +#define vkResetDescriptorPool vkd.ResetDescriptorPool #define vkAllocateDescriptorSets vkd.AllocateDescriptorSets #define vkFreeDescriptorSets vkd.FreeDescriptorSets #define vkUpdateDescriptorSets vkd.UpdateDescriptorSets @@ -219,6 +213,7 @@ void vkd_unload(void); #define vkCreatePipelineLayout vkd.CreatePipelineLayout #define vkDestroyPipelineLayout vkd.DestroyPipelineLayout #define vkCreateGraphicsPipelines vkd.CreateGraphicsPipelines +#define vkCreateComputePipelines vkd.CreateComputePipelines #define vkDestroyPipeline vkd.DestroyPipeline #define vkCreateShaderModule vkd.CreateShaderModule #define vkDestroyShaderModule vkd.DestroyShaderModule @@ -232,6 +227,7 @@ void vkd_unload(void); #define vkDestroyFence vkd.DestroyFence #define vkResetFences vkd.ResetFences #define vkWaitForFences vkd.WaitForFences +#define vkGetFenceStatus vkd.GetFenceStatus #define vkCreateSemaphore vkd.CreateSemaphore #define vkDestroySemaphore vkd.DestroySemaphore @@ -252,9 +248,13 @@ void vkd_unload(void); #define vkCmdSetViewport vkd.CmdSetViewport #define vkCmdSetScissor vkd.CmdSetScissor #define vkCmdDraw vkd.CmdDraw +#define vkCmdDispatch vkd.CmdDispatch #define vkCmdPipelineBarrier vkd.CmdPipelineBarrier -#define vkCmdCopyBufferToImage vkd.CmdCopyBufferToImage #define vkCmdBlitImage vkd.CmdBlitImage +#define vkCmdCopyImage vkd.CmdCopyImage +#define vkCmdClearColorImage vkd.CmdClearColorImage +#define vkCmdCopyBufferToImage vkd.CmdCopyBufferToImage +#define vkCmdCopyImageToBuffer vkd.CmdCopyImageToBuffer #define vkQueueSubmit vkd.QueueSubmit #define vkQueueWaitIdle vkd.QueueWaitIdle diff --git a/app/src/main/cpp/winlator/vk/vk_image.c b/app/src/main/cpp/winlator/vk/vk_image.c index 83d2d171a..a307babfd 100644 --- a/app/src/main/cpp/winlator/vk/vk_image.c +++ b/app/src/main/cpp/winlator/vk/vk_image.c @@ -1,16 +1,4 @@ // VkTexture allocation, upload, AHB import. -// -// Two creation paths: -// 1. CPU-uploaded: caller hands us BGRA pixel data; we allocate VkImage in DEVICE_LOCAL memory, -// stage the upload through a host-visible buffer, and transition to SHADER_READ_OPTIMAL. -// 2. AHardwareBuffer import: caller hands us an AHB; we allocate dedicated memory backed by the -// AHB (no copy) and bind it to a VkImage. For non-RGB formats (DRI3 vendor formats), we use -// a Ycbcr conversion so the sampler can read them. -// -// Texture lifetimes: -// - Created/updated synchronously on caller's thread (Java/render). -// - Submits go through vkQueueSubmit which is serialized via VkRenderer::queue_mutex. -// - Destruction is deferred via the graveyard so in-flight frames don't see freed handles. #include "vk_state.h" #include @@ -51,15 +39,6 @@ void vkr_image_barrier(VkCommandBuffer cmd, VkImage image, VkImageLayout from, V // ============================================================ // Staging pool — async upload infrastructure // ============================================================ -// -// Each slot owns a VkBuffer, persistently-mapped HOST_VISIBLE memory, a VkCommandPool with -// one VkCommandBuffer, and a VkFence. Round-robin acquisition under a tiny mutex; per-slot -// mutex provides exclusive ownership for the lifetime of an upload (acquire→submit→release). -// -// On a single graphics queue, the upload's terminal pipeline barrier (TRANSFER_WRITE → -// SHADER_READ, dstStage=FRAGMENT_SHADER) extends into all subsequent submits per Vulkan -// spec — so the renderer needs no extra synchronization to safely sample a freshly-updated -// texture as long as the upload was submitted before the render. bool vkr_staging_pool_init(VkRenderer* r) { if (r->staging_pool.initialized) return true; @@ -74,7 +53,7 @@ bool vkr_staging_pool_init(VkRenderer* r) { for (uint32_t i = 0; i < VK_STAGING_POOL_SIZE; i++) { VkStagingSlot* s = &r->staging_pool.slots[i]; pthread_mutex_init(&s->mutex, NULL); - r->staging_pool.valid_slots = i + 1; // mutex is now valid; destroy must clean it up + r->staging_pool.valid_slots = i + 1; VkCommandPoolCreateInfo cpci = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO}; cpci.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; @@ -97,15 +76,13 @@ bool vkr_staging_pool_init(VkRenderer* r) { VK_LOGE("staging pool: vkCreateFence slot %u failed", i); return false; } - // buffer/memory allocated lazily on first use, sized to the actual upload. + // buffer/memory allocated lazily on first use } r->staging_pool.initialized = true; return true; } void vkr_staging_pool_destroy(VkRenderer* r) { - // Tolerates partially-initialized pools — only iterate the slots whose mutexes were - // successfully initialized. for (uint32_t i = 0; i < r->staging_pool.valid_slots; i++) { VkStagingSlot* s = &r->staging_pool.slots[i]; if (s->fence) { @@ -128,14 +105,11 @@ void vkr_staging_pool_destroy(VkRenderer* r) { // Re-allocate a slot's staging buffer to at least `needed` bytes. Caller must own the slot. static bool grow_staging_slot(VkRenderer* r, VkStagingSlot* s, VkDeviceSize needed) { - // Round up to 64 KiB so consecutive size bumps don't trigger reallocs. VkDeviceSize new_size = (needed + 65535ull) & ~(VkDeviceSize)65535ull; if (s->mapped && s->memory) { vkUnmapMemory(r->device, s->memory); s->mapped = NULL; } if (s->buffer) { vkDestroyBuffer(r->device, s->buffer, NULL); s->buffer = VK_NULL_HANDLE; } if (s->memory) { vkFreeMemory(r->device, s->memory, NULL); s->memory = VK_NULL_HANDLE; } - // Reset size now so a later allocation failure leaves the slot in a state where the next - // acquire will retry grow_staging_slot rather than skip it and hand back a NULL buffer. s->size = 0; VkBufferCreateInfo bi = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; @@ -149,12 +123,6 @@ static bool grow_staging_slot(VkRenderer* r, VkStagingSlot* s, VkDeviceSize need VkMemoryAllocateInfo ai = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; ai.allocationSize = mr.size; - // Require HOST_VISIBLE | HOST_COHERENT (typically write-combined on Adreno). Skipping - // HOST_CACHED avoids polluting CPU caches with write-once-then-GPU-read staging, which - // hurts throughput by 5-20% on Adreno. We do not fall back to non-coherent memory: - // vkr_texture_update submits without vkFlushMappedMemoryRanges, so non-coherent staging - // would render undefined data. Vulkan spec §11.6 mandates that every device expose at - // least one HOST_VISIBLE | HOST_COHERENT memory type, so this lookup cannot legally fail. ai.memoryTypeIndex = vkr_find_memory_type(r, mr.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); if (ai.memoryTypeIndex == UINT32_MAX) { @@ -184,15 +152,9 @@ VkStagingSlot* vkr_staging_pool_acquire(VkRenderer* r, VkDeviceSize needed) { VkStagingSlot* s = &r->staging_pool.slots[idx]; - // Per-slot lock guards the slot's resources (buffer/cmd/fence) until release. Round-robin - // means contention only happens once VK_STAGING_POOL_SIZE acquires have wrapped — i.e. - // when the producer is consistently faster than the GPU can drain uploads. pthread_mutex_lock(&s->mutex); - // Wait for the slot's previous submission to retire. With pool_size=8 this almost never - // blocks because the fence signaled long ago. The fence is left signaled here on purpose - // — it gets reset right before vkQueueSubmit, so any no-submit failure path between here - // and submit leaves the fence safely signaled and the slot reusable. + // Wait for the slot's previous submission to retire. vkWaitForFences(r->device, 1, &s->fence, VK_TRUE, UINT64_MAX); vkResetCommandPool(r->device, s->cmd_pool, 0); @@ -247,7 +209,6 @@ void vkr_run_one_shot_cmd(VkRenderer* r, void (*fn)(VkCommandBuffer, void*), voi VkDescriptorSet vkr_alloc_descriptor_set(VkRenderer* r); void vkr_free_descriptor_set(VkRenderer* r, VkDescriptorSet set); -// Image sub-allocator — implemented lower in this file. static bool vkr_suballoc_image(VkRenderer* r, VkImage image, VkSuballoc* out); static void vkr_suballoc_free(VkRenderer* r, VkSuballoc* a); @@ -293,8 +254,7 @@ bool vkr_submit_async_transition(VkRenderer* r, VkImage image, VkImageLayout from, VkImageLayout to, VkPipelineStageFlags src_stage, VkPipelineStageFlags dst_stage, VkAccessFlags src_access, VkAccessFlags dst_access) { - // Reuse the staging pool's per-slot command pool/buffer/fence for this transition. We - // pass needed=0 so the slot's staging buffer isn't grown (we only use the cmd buffer). + // needed=0 reuses the slot's cmd buffer without growing its staging buffer. VkStagingSlot* slot = vkr_staging_pool_acquire(r, 0); if (!slot) { VK_LOGE("vkr_submit_async_transition: staging slot acquire failed"); @@ -324,8 +284,7 @@ bool vkr_submit_async_transition(VkRenderer* r, VkImage image, pthread_mutex_unlock(&r->queue_mutex); if (sr != VK_SUCCESS) { VK_LOGE("vkr_submit_async_transition: vkQueueSubmit -> %d", sr); - // Restore a signaled fence so the slot is reusable. (Same recovery path as - // vkr_texture_update.) + // Restore a signaled fence so the slot is reusable. vkDestroyFence(r->device, slot->fence, NULL); VkFenceCreateInfo rfi = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; rfi.flags = VK_FENCE_CREATE_SIGNALED_BIT; @@ -436,10 +395,6 @@ static VkTexture* pop_live_texture(VkRenderer* r) { // ---------------------------------------------------------------------- // Image sub-allocator // ---------------------------------------------------------------------- -// -// First-fit over a list of large DEVICE_LOCAL blocks, all under image_suballoc.mutex (alloc on -// producer threads, free on the render thread). Region nodes are malloc'd only on new-block -// creation or a non-coalescing free, so steady-state pixmap churn doesn't touch the C heap. void vkr_suballoc_init(VkRenderer* r) { VkImageSuballocator* sa = &r->image_suballoc; @@ -453,9 +408,7 @@ static VkDeviceSize suballoc_align_up(VkDeviceSize v, VkDeviceSize a) { return (v + a - 1) & ~(a - 1); } -// Carve [reg->offset .. bind+size) out of free region `reg` (`prev` = its free-list -// predecessor, or NULL). The leading alignment pad folds into the span so free recovers it -// verbatim. Caller verified the region fits. +// Carve [reg->offset .. bind+size) out of free region `reg`. Caller verified the region fits. static void suballoc_carve(VkMemBlock* block, VkMemRegion* prev, VkMemRegion* reg, VkDeviceSize bind, VkDeviceSize size, VkSuballoc* out) { VkDeviceSize span_offset = reg->offset; @@ -463,10 +416,10 @@ static void suballoc_carve(VkMemBlock* block, VkMemRegion* prev, VkMemRegion* re VkDeviceSize reg_end = reg->offset + reg->size; if (span_end < reg_end) { - reg->offset = span_end; // shrink region to the trailing remainder + reg->offset = span_end; // shrink to the trailing remainder reg->size = reg_end - span_end; } else { - if (prev) prev->next = reg->next; // region fully consumed — unlink + free + if (prev) prev->next = reg->next; // region fully consumed else block->free_list = reg->next; free(reg); } @@ -478,9 +431,8 @@ static void suballoc_carve(VkMemBlock* block, VkMemRegion* prev, VkMemRegion* re out->span_size = span_end - span_offset; } -// Reserve a span sized/aligned for `image` into `out`. Does NOT bind — caller issues the one -// vkBindImageMemory so a bind failure never forces an illegal rebind. False (nothing reserved) -// if no DEVICE_LOCAL type fits or a new block can't be allocated. +// Reserve a span sized/aligned for `image` into `out`. Does NOT bind — caller binds. +// False if no DEVICE_LOCAL type fits or a new block can't be allocated. static bool vkr_suballoc_image(VkRenderer* r, VkImage image, VkSuballoc* out) { VkMemoryRequirements mr; vkGetImageMemoryRequirements(r->device, image, &mr); @@ -583,14 +535,13 @@ static void vkr_suballoc_free(VkRenderer* r, VkSuballoc* a) { if (prev) prev->next = node; else b->free_list = node; } else { - // Node alloc failed (near-impossible): leak the span; the block is reclaimed at - // teardown anyway. + // Node alloc failed: leak the span; the block is reclaimed at teardown. VK_LOGE("suballoc free: region node alloc failed; leaking %llu bytes", (unsigned long long)sz); } } - // Return a fully-drained block so churn doesn't pin memory forever. + // Return a fully-drained block to the device. if (b->free_list && b->free_list->next == NULL && b->free_list->offset == 0 && b->free_list->size == b->size) { VkMemBlock* pb = NULL; @@ -700,7 +651,7 @@ static bool create_image_basic(VkRenderer* r, uint32_t w, uint32_t h, VkFormat f if (vkCreateImage(r->device, &ic, NULL, &t->image) != VK_SUCCESS) return false; - // Preferred path: pooled span (no per-texture vkAllocateMemory). Bind once here. + // Preferred path: pooled span. VkSuballoc sub = {0}; if (vkr_suballoc_image(r, t->image, &sub)) { if (vkBindImageMemory(r->device, t->image, sub.memory, sub.bind_offset) == VK_SUCCESS) { @@ -708,15 +659,13 @@ static bool create_image_basic(VkRenderer* r, uint32_t w, uint32_t h, VkFormat f t->suballocated = true; return true; } - // Bind attempted -> image can't be rebound via the dedicated path; fail (OOM-grade, - // effectively never happens). vkr_suballoc_free(r, &sub); vkDestroyImage(r->device, t->image, NULL); t->image = VK_NULL_HANDLE; return false; } - // Fallback: dedicated allocation (pool OOM / no DEVICE_LOCAL type). No bind attempted yet. + // Fallback: dedicated allocation. VkMemoryRequirements mr; vkGetImageMemoryRequirements(r->device, t->image, &mr); @@ -770,8 +719,7 @@ VkTexture* vkr_texture_create_uploaded(VkRenderer* r, uint32_t width, uint32_t h return NULL; } - // CPU-uploaded textures all want the same sampler config, so use the renderer's shared - // sampler. tex->sampler stays VK_NULL_HANDLE; destroy_texture_resources skips it. + // Use the renderer's shared sampler; tex->sampler stays VK_NULL_HANDLE. if (r->shared_sampler == VK_NULL_HANDLE) { VK_LOGE("vkr_texture_create_uploaded: shared_sampler not initialized"); destroy_texture_resources(r, t); @@ -789,9 +737,7 @@ VkTexture* vkr_texture_create_uploaded(VkRenderer* r, uint32_t width, uint32_t h vkr_texture_update(r, t, width, height, data, data_size, stride_pixels, 0, 0, width, height); } else { - // No initial data — async transition to SHADER_READ so the texture is safe to sample - // as black. Doesn't block the caller; the barrier orders before the next render submit - // on the same queue per Vulkan spec. + // No initial data — async transition to SHADER_READ so the texture samples as black. if (!vkr_submit_async_transition(r, t->image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, @@ -814,13 +760,11 @@ bool vkr_texture_update(VkRenderer* r, VkTexture* tex, uint32_t width, uint32_t uint32_t dirty_w, uint32_t dirty_h) { if (!tex || tex->external || !data || data_size == 0) return false; if (width != tex->width || height != tex->height) { - // Caller is expected to size-match. Reject mismatches to avoid silent corruption. VK_LOGW("vkr_texture_update size mismatch (have %ux%u, got %ux%u)", tex->width, tex->height, width, height); return false; } - // BGRA8 = 4 bytes per pixel. Caller provides stride_pixels (per-row pixel count). if (stride_pixels == 0) stride_pixels = width; if (dirty_w == 0 || dirty_h == 0) { dirty_x = 0; @@ -885,8 +829,7 @@ bool vkr_texture_update(VkRenderer* r, VkTexture* tex, uint32_t width, uint32_t si.commandBufferCount = 1; si.pCommandBuffers = &slot->cmd; - // Reset fence here, not in acquire — guarantees that the only path that leaves a fence - // unsignaled is one where vkQueueSubmit also runs to take ownership of it. + // Reset fence here, not in acquire, so only a path that also submits leaves it unsignaled. vkResetFences(r->device, 1, &slot->fence); pthread_mutex_lock(&r->queue_mutex); @@ -894,9 +837,7 @@ bool vkr_texture_update(VkRenderer* r, VkTexture* tex, uint32_t width, uint32_t pthread_mutex_unlock(&r->queue_mutex); if (sr != VK_SUCCESS) { VK_LOGE("vkr_texture_update: vkQueueSubmit -> %d", sr); - // Submit failed but we already reset the fence, so it's unsignaled and would deadlock - // the next acquire. Replace with a signaled fence. (Submit failures usually mean - // device-lost; the renderer is going to need a restart anyway.) + // Replace with a signaled fence so the next acquire doesn't deadlock. vkDestroyFence(r->device, slot->fence, NULL); VkFenceCreateInfo rfi = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; rfi.flags = VK_FENCE_CREATE_SIGNALED_BIT; @@ -905,9 +846,6 @@ bool vkr_texture_update(VkRenderer* r, VkTexture* tex, uint32_t width, uint32_t return false; } - // The barrier emitted by upload_cmds (TRANSFER_WRITE → SHADER_READ, dstStage= - // FRAGMENT_SHADER) extends into all subsequent submits on the same queue, so the next - // render submit will observe the writes without any additional renderer-side barrier. tex->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; vkr_staging_pool_release(slot); return true; @@ -953,8 +891,7 @@ static void batch_transition_to_shader_read(VkCommandBuffer cmd, VkTexture* tex) VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); } -// Grow-only PreparedBatchUpload[] scratch. Render-thread-only, so unlocked; every element is -// fully overwritten before use, so no zeroing. +// Grow-only PreparedBatchUpload[] scratch (render-thread-only). static PreparedBatchUpload* get_prepared_scratch(VkRenderer* r, uint32_t count) { if (r->batch_prepared_cap < count) { uint32_t new_cap = r->batch_prepared_cap ? r->batch_prepared_cap : 64; @@ -1153,11 +1090,7 @@ VkTexture* vkr_texture_import_ahb(VkRenderer* r, AHardwareBuffer* ahb, bool tran t->ahb = transfer_ownership ? ahb : NULL; if (transfer_ownership) AHardwareBuffer_acquire(ahb); - // External-format AHB sampling requires a YCbCr conversion bound through an immutable - // sampler in the descriptor-set layout. This renderer uses one mutable combined - // image/sampler layout for all regular textures, so accepting external-format AHBs here - // would be Vulkan-invalid on strict drivers. Keep the import path to RGB formats until a - // separate immutable-sampler pipeline/layout path exists. + // External-format AHBs need an immutable-sampler layout this renderer lacks; RGB only. if (format_props.format == VK_FORMAT_UNDEFINED) { VK_LOGW("AHB external-format import unsupported by current descriptor layout"); if (t->ahb) AHardwareBuffer_release(t->ahb); @@ -1178,13 +1111,19 @@ VkTexture* vkr_texture_import_ahb(VkRenderer* r, AHardwareBuffer* ahb, bool tran ic.mipLevels = 1; ic.arrayLayers = 1; ic.samples = VK_SAMPLE_COUNT_1_BIT; - ic.tiling = VK_IMAGE_TILING_OPTIMAL; + // OPTIMAL, falling back to LINEAR only if the driver rejects it. ic.usage = VK_IMAGE_USAGE_SAMPLED_BIT; ic.sharingMode = VK_SHARING_MODE_EXCLUSIVE; ic.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - if (vkCreateImage(r->device, &ic, NULL, &t->image) != VK_SUCCESS) { - VK_LOGW("AHB vkCreateImage failed"); + ic.tiling = VK_IMAGE_TILING_OPTIMAL; + VkResult ahb_cr = vkCreateImage(r->device, &ic, NULL, &t->image); + if (ahb_cr != VK_SUCCESS) { + ic.tiling = VK_IMAGE_TILING_LINEAR; + ahb_cr = vkCreateImage(r->device, &ic, NULL, &t->image); + } + if (ahb_cr != VK_SUCCESS) { + VK_LOGW("AHB vkCreateImage failed (tried OPTIMAL then LINEAR)"); if (t->ahb) AHardwareBuffer_release(t->ahb); free(t); return NULL; @@ -1230,12 +1169,10 @@ VkTexture* vkr_texture_import_ahb(VkRenderer* r, AHardwareBuffer* ahb, bool tran vi.image = t->image; vi.viewType = VK_IMAGE_VIEW_TYPE_2D; vi.format = format_props.format; - // samplerYcbcrConversionComponents is only defined when a Ycbcr conversion is in use; - // some non-Adreno drivers populate non-identity swizzles for RGB AHBs. if (t->ycbcr != VK_NULL_HANDLE) { vi.components = format_props.samplerYcbcrConversionComponents; } else { - // fixes devices that supports vulkan bgra8 format, but doesn't support bgra8 ahb images + // swizzle for devices that support vulkan bgra8 but not bgra8 AHB images bool swizzle_rb = format_props.format == VK_FORMAT_R8G8B8A8_UNORM && r->caps.upload_format == VK_FORMAT_B8G8R8A8_UNORM; vi.components.r = swizzle_rb ? VK_COMPONENT_SWIZZLE_B : VK_COMPONENT_SWIZZLE_IDENTITY; @@ -1257,8 +1194,7 @@ VkTexture* vkr_texture_import_ahb(VkRenderer* r, AHardwareBuffer* ahb, bool tran return NULL; } - // Ycbcr-bound samplers must be created per-texture (driver pairs them with the conversion). - // For plain RGB AHB imports we can reuse the renderer's shared sampler. + // Ycbcr-bound samplers are per-texture; plain RGB imports reuse the shared sampler. VkSampler sampler_for_descriptor; if (t->ycbcr != VK_NULL_HANDLE) { if (!vkr_create_sampler(r, t->ycbcr, &t->sampler)) { @@ -1297,9 +1233,7 @@ VkTexture* vkr_texture_import_ahb(VkRenderer* r, AHardwareBuffer* ahb, bool tran } write_descriptor_set(r, t->descriptor_set, t->view, sampler_for_descriptor); - // Async transition to SHADER_READ. The barrier orders before all subsequent submits on - // the same queue per Vulkan spec, so the next render submit safely samples this image - // without an additional renderer-side wait. + // Async transition to SHADER_READ. if (!vkr_submit_async_transition(r, t->image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, @@ -1347,7 +1281,7 @@ void vkr_texture_schedule_destroy(VkRenderer* r, VkTexture* tex) { } tex->destroy_scheduled = true; - // Defensive: drop any references in the live scene state. + // Drop any references in the live scene state. for (uint32_t i = 0; i < r->scene.window_count; i++) { if (r->scene.windows[i].texture == tex) { r->scene.windows[i].texture = NULL; @@ -1363,7 +1297,7 @@ void vkr_texture_schedule_destroy(VkRenderer* r, VkTexture* tex) { VkTexture** ng = realloc(slot->textures, new_cap * sizeof(VkTexture*)); if (!ng) { pthread_mutex_unlock(&r->scene_mutex); - // As a last resort, leak rather than crash. Better than UAF. + // Leak rather than risk a use-after-free. VK_LOGE("graveyard alloc failed; leaking texture %p", (void*)tex); return; } diff --git a/app/src/main/cpp/winlator/vk/vk_renderer.c b/app/src/main/cpp/winlator/vk/vk_renderer.c index d065ed625..22afc8c1b 100644 --- a/app/src/main/cpp/winlator/vk/vk_renderer.c +++ b/app/src/main/cpp/winlator/vk/vk_renderer.c @@ -1,31 +1,25 @@ // Vulkan compositor for the X-server display path. -// -// Owns the entire native-side rendering state. Java JNI shims push scene snapshots and call -// frame submit; this file handles instance/device/swapchain/pipelines/sync. -// -// All vk* calls below resolve through vk_dispatch.h, which redirects them to the dlopen -// handle (system libvulkan or adrenotools-loaded Turnip) chosen at nativeCreate. -// -// Synchronization model: -// - One graphics queue, serialized externally via VkRenderer::queue_mutex (any thread submits). -// - VK_FRAMES_IN_FLIGHT in-flight frames, each with its own semaphores + fence + cmd buffer. -// - Scene state guarded by VkRenderer::scene_mutex. -// - Texture lifetime: created/uploaded synchronously (blocks ~ms); destroyed via per-frame -// graveyard processed on the render thread, and tracked so renderer teardown can drain -// native texture objects that Java handles have not explicitly destroyed yet. #include "vk_state.h" #include "vk_driver.h" #include #include +#include +#include +#include +#include +#include #include #include +#include #include #include #include +#include +#include +#include -// SPIR-V shader byte arrays generated at build time by glslc + bin2c.cmake. #include "shaders/window_vert.spv.h" #include "shaders/window_frag.spv.h" #include "shaders/cursor_frag.spv.h" @@ -45,6 +39,49 @@ #include "shaders/effect_colorblind_frag.spv.h" #include "shaders/effect_pixelate_frag.spv.h" #include "shaders/sgsr1_frag.spv.h" +#include "shaders/motion_comp.spv.h" +#include "shaders/motion_fp32_comp.spv.h" +#include "shaders/interpolate_frag.spv.h" +#include "shaders/flowfix_comp.spv.h" +#include "shaders/cnn_pyramid_comp.spv.h" +#include "shaders/cnn_conv_comp.spv.h" +#include "shaders/cnn_correlation_cost9_comp.spv.h" +#include "shaders/cnn_correlation_warpfollow_comp.spv.h" +#include "shaders/cnn_flowreg_comp.spv.h" +#include "shaders/cnn_generate_comp.spv.h" +#include "shaders/fg_synthshift_comp.spv.h" +#include "wnfg_spv/wnfg_04_spv.h" +#include "wnfg_spv/wnfg_13_spv.h" +#include "wnfg_spv/wnfg_25_spv.h" +#include "wnfg_spv/wnfg_27_spv.h" +#include "wnfg_spv/wnfg_28_spv.h" +#include "wnfg_spv/wnfg_29_spv.h" +#include "wnfg_spv/wnfg_51_spv.h" +#include "wnfg_spv/wnfg_53_spv.h" +#include "shaders/wnfg_05_weights.h" +#include "shaders/wnfg_06_weights.h" +#include "shaders/wnfg_07_weights.h" +#include "shaders/wnfg_14_weights.h" +#include "shaders/wnfg_20_weights.h" +#include "shaders/wnfg_21_weights.h" +#include "shaders/wnfg_22_weights.h" +#include "shaders/wnfg_24_weights.h" +#include "shaders/wnfg_25_weights.h" +#include "shaders/wnfg_26_weights.h" +#include "shaders/wnfg_27_weights.h" +#include "shaders/wnfg_28_weights.h" +#include "shaders/wnfg_29_weights.h" +#include "shaders/wnfg_36_weights.h" +#include "shaders/wnfg_37_weights.h" +#include "shaders/wnfg_42_weights.h" +#include "shaders/wnfg_45_weights.h" +#include "shaders/wnfg_51_weights.h" + +static uint64_t now_monotonic_ns(void) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t)ts.tv_sec * 1000000000ull + (uint64_t)ts.tv_nsec; +} // ============================================================ // Forward decls @@ -55,6 +92,16 @@ static void destroy_debug_messenger(VkRenderer* r); static bool pick_physical_device(VkRenderer* r); static bool create_device(VkRenderer* r); static void query_device_caps(VkRenderer* r); +static bool cnn_wanted(void); +static void fg_flow_dims(const VkRenderer* r, uint32_t w, uint32_t h, uint32_t* outW, uint32_t* outH); +static bool create_cnn_pipelines(VkRenderer* r); +static void destroy_cnn_pipelines(VkRenderer* r); +static bool fg_create_cnn_resources(VkRenderer* r, uint32_t w, uint32_t h); +static void fg_destroy_cnn_resources(VkRenderer* r); +static void cnn_flow_pass(VkRenderer* r, VkCommandBuffer cmd, uint32_t parity, + VkFgImage* prevFrame, VkFgImage* currFrame, bool forward, VkFgImage* outFlow); +static void cnn_generate_frame(VkRenderer* r, VkCommandBuffer cmd, uint32_t parity, uint32_t slot, + VkImageView prevView, VkImageView currView, float phase); static bool create_command_pool(VkRenderer* r); static bool create_descriptor_pool(VkRenderer* r, uint32_t capacity); static bool create_pipelines(VkRenderer* r); @@ -66,6 +113,22 @@ static bool create_offscreen(VkRenderer* r, uint32_t w, uint32_t h, bool need_se static void destroy_offscreen(VkRenderer* r); static bool create_sgsr1_resources(VkRenderer* r, uint32_t w, uint32_t h); static void destroy_sgsr1_resources(VkRenderer* r); +static void fg_destroy_resources(VkRenderer* r); +static bool fg_ensure_resources(VkRenderer* r); +static void wait_inflight_frames(VkRenderer* r); +static bool fg_worker_create_resources(VkRenderer* r); +static void fg_worker_destroy_resources(VkRenderer* r); +static void fg_worker_start(VkRenderer* r); +static void fg_worker_stop(VkRenderer* r); + +typedef enum { + FG_MODE_HOLD = 0, + FG_MODE_INTERP = 1, + FG_MODE_PRESENT_LAST = 2, + FG_MODE_FLOW = 3, +} FgMode; + +typedef struct { bool has_effects; bool wants_sgsr1; } SceneTargets; static bool create_quad_vbo(VkRenderer* r); static void destroy_quad_vbo(VkRenderer* r); static bool is_plain_rotation_transform(VkSurfaceTransformFlagBitsKHR transform); @@ -350,11 +413,41 @@ static bool create_device(VkRenderer* r) { bool has_ycbcr = has_extension(exts, ext_count, VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); bool has_extmem_caps = has_extension(exts, ext_count, VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME); bool has_queue_fam = has_extension(exts, ext_count, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME); + bool has_f16 = has_extension(exts, ext_count, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME); + bool has_display_timing = has_extension(exts, ext_count, VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME); bool has_cubic = has_extension(exts, ext_count, VK_EXT_FILTER_CUBIC_EXTENSION_NAME); + bool has_optical_flow = has_extension(exts, ext_count, VK_NV_OPTICAL_FLOW_EXTENSION_NAME); + bool has_sync2 = has_extension(exts, ext_count, VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME); + bool has_fmt_feat2 = has_extension(exts, ext_count, VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME); + { uint32_t pdc = 0; vkEnumeratePhysicalDevices(r->instance, &pdc, NULL); + VkPhysicalDevice* pds = calloc(pdc ? pdc : 1, sizeof(VkPhysicalDevice)); + PFN_vkGetPhysicalDeviceProperties2 gpdp2 = + (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(r->instance, "vkGetPhysicalDeviceProperties2"); + if (!gpdp2) gpdp2 = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(r->instance, "vkGetPhysicalDeviceProperties2KHR"); + if (pds && pdc) { vkEnumeratePhysicalDevices(r->instance, &pdc, pds); + for (uint32_t d = 0; d < pdc; d++) { + VkPhysicalDeviceProperties pp; vkGetPhysicalDeviceProperties(pds[d], &pp); + VkPhysicalDeviceDriverProperties drv = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES}; + VkPhysicalDeviceProperties2 p2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, &drv}; + if (gpdp2) gpdp2(pds[d], &p2); + uint32_t ec = 0; vkEnumerateDeviceExtensionProperties(pds[d], NULL, &ec, NULL); + VkExtensionProperties* ep = calloc(ec ? ec : 1, sizeof(VkExtensionProperties)); int ofd = 0; + if (ep && ec) { vkEnumerateDeviceExtensionProperties(pds[d], NULL, &ec, ep); + for (uint32_t e = 0; e < ec; e++) if (!strcmp(ep[e].extensionName, "VK_NV_optical_flow")) ofd = 1; } + free(ep); + VK_LOGI("FG OF probe[%u/%u]: '%s' driverName='%s' driverID=%u apiV=%u.%u extCount=%u of=%d %s", + d, pdc, pp.deviceName, drv.driverName, (unsigned)drv.driverID, + VK_VERSION_MAJOR(pp.apiVersion), VK_VERSION_MINOR(pp.apiVersion), ec, ofd, + pds[d] == r->physical_device ? "<-SELECTED" : ""); + } + } + free(pds); + VK_LOGI("FG OF probe: selected extCount=%u of=%d sync2=%d fmtfeat2=%d", + ext_count, has_optical_flow, has_sync2, has_fmt_feat2); } free(exts); - const char* enable[16]; + const char* enable[24]; uint32_t enable_n = 0; enable[enable_n++] = VK_KHR_SWAPCHAIN_EXTENSION_NAME; @@ -373,6 +466,51 @@ static bool create_device(VkRenderer* r) { r->ext_ahb = ahb_ok; r->ext_ycbcr = has_ycbcr; r->ext_filter_cubic = has_cubic; + + r->fg_float16_supported = false; + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR f16_feat = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR }; + if (has_f16) { + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR f16q = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR }; + VkPhysicalDeviceFeatures2 feats2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 }; + feats2.pNext = &f16q; + PFN_vkGetPhysicalDeviceFeatures2 fnFeat2 = (PFN_vkGetPhysicalDeviceFeatures2) + vkGetInstanceProcAddr(r->instance, "vkGetPhysicalDeviceFeatures2"); + if (!fnFeat2) fnFeat2 = (PFN_vkGetPhysicalDeviceFeatures2) + vkGetInstanceProcAddr(r->instance, "vkGetPhysicalDeviceFeatures2KHR"); + if (fnFeat2) { fnFeat2(r->physical_device, &feats2); r->fg_float16_supported = (f16q.shaderFloat16 == VK_TRUE); } + } + if (r->fg_float16_supported) { + enable[enable_n++] = VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME; + f16_feat.shaderFloat16 = VK_TRUE; + } + if (has_display_timing && enable_n < 24) { + enable[enable_n++] = VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME; + r->ext_display_timing = true; + } + VK_LOGI("Frame generation fp16 support: ext=%d feature=%d", has_f16, r->fg_float16_supported); + + r->fg_optical_flow = false; + VkPhysicalDeviceOpticalFlowFeaturesNV of_feat = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV }; + if (has_optical_flow && has_sync2 && has_fmt_feat2 && enable_n + 3 <= 24) { + VkPhysicalDeviceOpticalFlowFeaturesNV ofq = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV }; + VkPhysicalDeviceFeatures2 feats2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 }; + feats2.pNext = &ofq; + PFN_vkGetPhysicalDeviceFeatures2 fnFeat2 = (PFN_vkGetPhysicalDeviceFeatures2) + vkGetInstanceProcAddr(r->instance, "vkGetPhysicalDeviceFeatures2"); + if (!fnFeat2) fnFeat2 = (PFN_vkGetPhysicalDeviceFeatures2) + vkGetInstanceProcAddr(r->instance, "vkGetPhysicalDeviceFeatures2KHR"); + if (fnFeat2) { fnFeat2(r->physical_device, &feats2); r->fg_optical_flow = (ofq.opticalFlow == VK_TRUE); } + } + if (r->fg_optical_flow) { + enable[enable_n++] = VK_NV_OPTICAL_FLOW_EXTENSION_NAME; + enable[enable_n++] = VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME; + enable[enable_n++] = VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME; + of_feat.opticalFlow = VK_TRUE; + } + VK_LOGI("Frame generation optical flow (VK_NV_optical_flow): ext=%d enabled=%d", has_optical_flow, r->fg_optical_flow); + VK_LOGI("AHB Vulkan device support: android_hardware_buffer=%d external_memory=%d dedicated=%d get_memory_requirements2=%d queue_family_foreign=%d enabled=%d", has_ahb, has_extmem, has_dedicated, has_get_mem_req2, has_queue_fam, r->ext_ahb); if (!r->ext_ahb) { @@ -391,7 +529,11 @@ static bool create_device(VkRenderer* r) { ycbcr_feat.samplerYcbcrConversion = has_ycbcr ? VK_TRUE : VK_FALSE; VkDeviceCreateInfo dci = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO}; - if (has_ycbcr) dci.pNext = &ycbcr_feat; + void* feat_chain = NULL; + if (has_ycbcr) { ycbcr_feat.pNext = feat_chain; feat_chain = &ycbcr_feat; } + if (r->fg_float16_supported) { f16_feat.pNext = feat_chain; feat_chain = &f16_feat; } + if (r->fg_optical_flow) { of_feat.pNext = feat_chain; feat_chain = &of_feat; } + dci.pNext = feat_chain; dci.queueCreateInfoCount = 1; dci.pQueueCreateInfos = &qci; dci.enabledExtensionCount = enable_n; @@ -403,6 +545,38 @@ static bool create_device(VkRenderer* r) { } vkGetDeviceQueue(r->device, r->graphics_queue_family, 0, &r->graphics_queue); + if (r->fg_optical_flow) { + r->fnOFFormats = (PFN_vkGetPhysicalDeviceOpticalFlowImageFormatsNV) + vkGetInstanceProcAddr(r->instance, "vkGetPhysicalDeviceOpticalFlowImageFormatsNV"); + r->fnOFCreate = (PFN_vkCreateOpticalFlowSessionNV) vkGetDeviceProcAddr(r->device, "vkCreateOpticalFlowSessionNV"); + r->fnOFDestroy = (PFN_vkDestroyOpticalFlowSessionNV) vkGetDeviceProcAddr(r->device, "vkDestroyOpticalFlowSessionNV"); + r->fnOFBind = (PFN_vkBindOpticalFlowSessionImageNV) vkGetDeviceProcAddr(r->device, "vkBindOpticalFlowSessionImageNV"); + r->fnOFExecute = (PFN_vkCmdOpticalFlowExecuteNV) vkGetDeviceProcAddr(r->device, "vkCmdOpticalFlowExecuteNV"); + if (!r->fnOFCreate || !r->fnOFDestroy || !r->fnOFBind || !r->fnOFExecute) { + VK_LOGW("optical flow entry points missing; disabling OF flow"); + r->fg_optical_flow = false; + } + } + + if (r->fg_optical_flow && r->fnOFCreate && r->fnOFDestroy) { + VkOpticalFlowSessionCreateInfoNV sci = { VK_STRUCTURE_TYPE_OPTICAL_FLOW_SESSION_CREATE_INFO_NV }; + sci.width = 960; sci.height = 540; + sci.imageFormat = VK_FORMAT_R8G8B8A8_UNORM; + sci.flowVectorFormat = VK_FORMAT_R16G16B16A16_SFLOAT; + sci.outputGridSize = VK_OPTICAL_FLOW_GRID_SIZE_8X8_BIT_NV; + sci.performanceLevel = VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_MEDIUM_NV; + VkOpticalFlowSessionNV sess = VK_NULL_HANDLE; + VkResult sr = r->fnOFCreate(r->device, &sci, NULL, &sess); + VK_LOGI("OF session create probe: result=%d session=%p", (int)sr, (void*)sess); + if (sr == VK_SUCCESS && sess) { + r->fnOFDestroy(r->device, sess, NULL); + VK_LOGI("OF flow path CONFIRMED working"); + } else { + VK_LOGW("OF session create failed (result=%d); disabling OF flow", (int)sr); + r->fg_optical_flow = false; + } + } + if (r->ext_ahb) { r->fnGetAhbProps = (PFN_vkGetAndroidHardwareBufferPropertiesANDROID) vkGetDeviceProcAddr(r->device, "vkGetAndroidHardwareBufferPropertiesANDROID"); @@ -430,8 +604,18 @@ static bool create_device(VkRenderer* r) { r->ext_ycbcr = false; } } + if (r->ext_display_timing) { + r->fnGetRefreshCycleDuration = (PFN_vkGetRefreshCycleDurationGOOGLE) + vkGetDeviceProcAddr(r->device, "vkGetRefreshCycleDurationGOOGLE"); + r->fnGetPastPresentationTiming = (PFN_vkGetPastPresentationTimingGOOGLE) + vkGetDeviceProcAddr(r->device, "vkGetPastPresentationTimingGOOGLE"); + if (!r->fnGetRefreshCycleDuration || !r->fnGetPastPresentationTiming) { + VK_LOGW("VK_GOOGLE_display_timing entry points unavailable; FG present timing disabled"); + r->ext_display_timing = false; + } + } - VK_LOGI("Vulkan device created (AHB=%d, Ycbcr=%d)", r->ext_ahb, r->ext_ycbcr); + VK_LOGI("Vulkan device created (AHB=%d, Ycbcr=%d, displayTiming=%d)", r->ext_ahb, r->ext_ycbcr, r->ext_display_timing); return true; } @@ -448,16 +632,8 @@ static void query_device_caps(VkRenderer* r) { r->caps.is_adreno = (props.vendorID == 0x5143); // Qualcomm r->caps.limits = props.limits; - // Descriptor pool capacity. Vulkan doesn't spec-bound pool size — the only ceiling - // is driver memory, and each combined-image-sampler set is ~100-200 bytes on Adreno, - // so 4096 sets is ~1 MB upfront. Pick a number high enough that an X server with - // hundreds of short-lived pixmaps can't realistically exhaust it. Grow-on-exhaust - // is the proper unbounded answer and remains a separate TODO. r->caps.descriptor_pool_capacity = 4096; - // Offscreen color format. Prefer BGRA8 to match the upload format (no shader swizzle), - // fall back to RGBA8 if the driver doesn't expose BGRA as a sampled color attachment - // in OPTIMAL tiling. RGBA8 is spec-guaranteed for both features. const VkFormatFeatureFlags need = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT; const VkFormat offscreen_candidates[2] = { @@ -473,7 +649,6 @@ static void query_device_caps(VkRenderer* r) { } } - // CPU-uploaded texture format. RGBA8 is spec-guaranteed; BGRA8 is optional. const VkFormatFeatureFlags upload_need = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT; r->caps.upload_format = VK_FORMAT_R8G8B8A8_UNORM; @@ -487,7 +662,6 @@ static void query_device_caps(VkRenderer* r) { } } - // AHB BGRA8 importability — diagnostic only; per-import paths still probe themselves. r->caps.ahb_bgra_supported = false; if (r->ext_ahb) { VkPhysicalDeviceExternalImageFormatInfo ext = { @@ -510,8 +684,6 @@ static void query_device_caps(VkRenderer* r) { VkImageFormatProperties2 out = { VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2 }; out.pNext = &ext_out; - // The 1.1 core entry point isn't statically exported by the Android Vulkan loader on all - // NDK targets; resolve dynamically and fall back to the KHR alias. PFN_vkGetPhysicalDeviceImageFormatProperties2 fnGetIfp2 = (PFN_vkGetPhysicalDeviceImageFormatProperties2) vkGetInstanceProcAddr(r->instance, "vkGetPhysicalDeviceImageFormatProperties2"); @@ -563,20 +735,56 @@ static bool create_command_pool(VkRenderer* r) { return true; } +static void fg_worker_destroy_resources(VkRenderer* r) { + for (uint32_t i = 0; i < 3; i++) { + VkFrame* f = &r->fg_worker_frames[i]; + if (f->image_available) { vkDestroySemaphore(r->device, f->image_available, NULL); f->image_available = VK_NULL_HANDLE; } + if (f->in_flight) { + for (uint32_t s = 0; s < 3; s++) if (r->fg_slot_fence[s] == f->in_flight) r->fg_slot_fence[s] = VK_NULL_HANDLE; + vkDestroyFence(r->device, f->in_flight, NULL); f->in_flight = VK_NULL_HANDLE; + } + f->cmd = VK_NULL_HANDLE; + } + if (r->fg_worker_pool) { vkDestroyCommandPool(r->device, r->fg_worker_pool, NULL); r->fg_worker_pool = VK_NULL_HANDLE; } +} + +static bool fg_worker_create_resources(VkRenderer* r) { + if (r->fg_worker_pool) return true; + VkCommandPoolCreateInfo ci = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO}; + ci.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + ci.queueFamilyIndex = r->graphics_queue_family; + if (vkCreateCommandPool(r->device, &ci, NULL, &r->fg_worker_pool) != VK_SUCCESS) return false; + VkCommandBufferAllocateInfo ai = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO}; + ai.commandPool = r->fg_worker_pool; ai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; ai.commandBufferCount = 1; + VkSemaphoreCreateInfo si = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO}; + VkFenceCreateInfo fi = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; + fi.flags = VK_FENCE_CREATE_SIGNALED_BIT; + for (uint32_t i = 0; i < 3; i++) { + VkFrame* f = &r->fg_worker_frames[i]; + if (vkAllocateCommandBuffers(r->device, &ai, &f->cmd) != VK_SUCCESS) { fg_worker_destroy_resources(r); return false; } + if (vkCreateSemaphore(r->device, &si, NULL, &f->image_available) != VK_SUCCESS) { fg_worker_destroy_resources(r); return false; } + if (vkCreateFence(r->device, &fi, NULL, &f->in_flight) != VK_SUCCESS) { fg_worker_destroy_resources(r); return false; } + } + r->fg_worker_index = 0; + return true; +} + // ============================================================ // Descriptor pool // ============================================================ static bool create_descriptor_pool(VkRenderer* r, uint32_t capacity) { - VkDescriptorPoolSize ps = {0}; - ps.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - ps.descriptorCount = capacity; + VkDescriptorPoolSize ps[2] = {0}; + ps[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + ps[0].descriptorCount = capacity; + ps[1].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + ps[1].descriptorCount = 32; // fine + coarse, backward + forward, 3 parities each VkDescriptorPoolCreateInfo ci = {VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO}; ci.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; ci.maxSets = capacity; - ci.poolSizeCount = 1; - ci.pPoolSizes = &ps; + ci.poolSizeCount = 2; + ci.pPoolSizes = ps; if (vkCreateDescriptorPool(r->device, &ci, NULL, &r->descriptor_pool) != VK_SUCCESS) { VK_LOGE("vkCreateDescriptorPool failed"); return false; @@ -708,8 +916,6 @@ static bool create_pipeline_layouts(VkRenderer* r) { return false; } - // Window/cursor: push constants = float xform[6] + vec2 viewSize + vec4 uvRect - // + int swapRB = 52 bytes VkPushConstantRange pcr_window = {0}; pcr_window.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; pcr_window.offset = 0; @@ -724,8 +930,6 @@ static bool create_pipeline_layouts(VkRenderer* r) { return false; } - // Effect: push constants = vec2 resolution + 4 floats (sat, contrast, sharp, mode) = 24 bytes. - // Other effect shaders only declare the first 16 bytes and ignore the rest. VkPushConstantRange pcr_effect = {0}; pcr_effect.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; pcr_effect.offset = 0; @@ -740,9 +944,75 @@ static bool create_pipeline_layouts(VkRenderer* r) { return false; } + // --- Frame generation layouts --- + // motion.comp set 0: binding0,1,2 = prev,curr,coarseFlow samplers; binding3 = motion storage. All COMPUTE. + VkDescriptorSetLayoutBinding mb[4] = {0}; + mb[0].binding = 0; mb[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + mb[0].descriptorCount = 1; mb[0].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + mb[1] = mb[0]; mb[1].binding = 1; + mb[2] = mb[0]; mb[2].binding = 2; + mb[3].binding = 3; mb[3].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + mb[3].descriptorCount = 1; mb[3].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + VkDescriptorSetLayoutCreateInfo dl_m = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO}; + dl_m.bindingCount = 4; dl_m.pBindings = mb; + if (vkCreateDescriptorSetLayout(r->device, &dl_m, NULL, &r->pipelines.fg_motion_layout) != VK_SUCCESS) { + return false; + } + + // interpolate.frag set 0: prev,curr,mvBwd,mvFwd combined-image-samplers, FRAGMENT. + VkDescriptorSetLayoutBinding ib[4] = {0}; + for (uint32_t i = 0; i < 4; i++) { + ib[i].binding = i; + ib[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + ib[i].descriptorCount = 1; + ib[i].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + } + VkDescriptorSetLayoutCreateInfo dl_i = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO}; + dl_i.bindingCount = 4; dl_i.pBindings = ib; + if (vkCreateDescriptorSetLayout(r->device, &dl_i, NULL, &r->pipelines.fg_interp_layout) != VK_SUCCESS) { + return false; + } + + // motion pipeline layout: motion set + 32B push (ivec2 mvSize, vec2 invMvSize, float mvScale, pad). + VkPushConstantRange mpc = { VK_SHADER_STAGE_COMPUTE_BIT, 0, 32 }; + VkPipelineLayoutCreateInfo mpl = {VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + mpl.setLayoutCount = 1; mpl.pSetLayouts = &r->pipelines.fg_motion_layout; + mpl.pushConstantRangeCount = 1; mpl.pPushConstantRanges = &mpc; + if (vkCreatePipelineLayout(r->device, &mpl, NULL, &r->pipelines.fg_motion_pipe_layout) != VK_SUCCESS) { + return false; + } + + // interp pipeline layout: interp set + 24B fragment push (vec2 resolution, float phase, occLo, occHi, pad). + VkPushConstantRange ipc = { VK_SHADER_STAGE_FRAGMENT_BIT, 0, 24 }; + VkPipelineLayoutCreateInfo ipl = {VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + ipl.setLayoutCount = 1; ipl.pSetLayouts = &r->pipelines.fg_interp_layout; + ipl.pushConstantRangeCount = 1; ipl.pPushConstantRanges = &ipc; + if (vkCreatePipelineLayout(r->device, &ipl, NULL, &r->pipelines.fg_interp_pipe_layout) != VK_SUCCESS) { + return false; + } + return true; } +// Compute pipeline helper for the frame-generation motion pass. +static VkPipeline create_compute_pipeline(VkRenderer* r, VkShaderModule cs, VkPipelineLayout layout) { + VkPipelineShaderStageCreateInfo stage = {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; + stage.module = cs; + stage.pName = "main"; + + VkComputePipelineCreateInfo cpi = {VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; + cpi.stage = stage; + cpi.layout = layout; + + VkPipeline pipe = VK_NULL_HANDLE; + if (vkCreateComputePipelines(r->device, VK_NULL_HANDLE, 1, &cpi, NULL, &pipe) != VK_SUCCESS) { + VK_LOGE("vkCreateComputePipelines failed"); + return VK_NULL_HANDLE; + } + return pipe; +} + static VkPipeline create_graphics_pipeline( VkRenderer* r, VkShaderModule vs, VkShaderModule fs, @@ -865,12 +1135,17 @@ static bool create_pipelines(VkRenderer* r) { VkShaderModule fs_colorblind = load_shader_module(r, effect_colorblind_frag, effect_colorblind_frag_size); VkShaderModule fs_pixelate = load_shader_module(r, effect_pixelate_frag, effect_pixelate_frag_size); VkShaderModule fs_sgsr1 = load_shader_module(r, sgsr1_frag, sgsr1_frag_size); + VkShaderModule cs_motion = r->fg_float16_supported + ? load_shader_module(r, motion_comp, motion_comp_size) + : load_shader_module(r, motion_fp32_comp, motion_fp32_comp_size); + VkShaderModule fs_interp = load_shader_module(r, interpolate_frag, interpolate_frag_size); + VkShaderModule cs_flowfix = load_shader_module(r, flowfix_comp, flowfix_comp_size); if (!vs_window || !fs_window || !fs_cursor || !vs_quad || !fs_blit || !fs_crt || !fs_vivid || !fs_hdr || !fs_natural || !fs_toon || !fs_ntsc || !fs_ntsc2 || !fs_coloradj || !fs_colorgrade || !fs_sharpen || !fs_scanlines || !fs_colorblind || !fs_pixelate - || !fs_sgsr1) { + || !fs_sgsr1 || !cs_motion || !fs_interp || !cs_flowfix) { return false; } @@ -977,6 +1252,16 @@ static bool create_pipelines(VkRenderer* r) { r, vs_quad, fs_pixelate, r->pipelines.effect_layout, r->pipelines.offscreen_pass, false, false, NULL); + r->pipelines.fg_motion_pipeline = create_compute_pipeline( + r, cs_motion, r->pipelines.fg_motion_pipe_layout); + r->pipelines.fg_flowfix_pipeline = create_compute_pipeline( + r, cs_flowfix, r->pipelines.fg_motion_pipe_layout); + r->pipelines.fg_interp_pipeline = create_graphics_pipeline( + r, vs_quad, fs_interp, r->pipelines.fg_interp_pipe_layout, r->pipelines.swapchain_pass, + false, false, NULL); + + r->fg_cnn_capable = cnn_wanted() && create_cnn_pipelines(r); + vkDestroyShaderModule(r->device, vs_window, NULL); vkDestroyShaderModule(r->device, fs_window, NULL); vkDestroyShaderModule(r->device, fs_cursor, NULL); @@ -996,12 +1281,18 @@ static bool create_pipelines(VkRenderer* r) { vkDestroyShaderModule(r->device, fs_colorblind, NULL); vkDestroyShaderModule(r->device, fs_pixelate, NULL); vkDestroyShaderModule(r->device, fs_sgsr1, NULL); + vkDestroyShaderModule(r->device, cs_motion, NULL); + vkDestroyShaderModule(r->device, fs_interp, NULL); + vkDestroyShaderModule(r->device, cs_flowfix, NULL); if (!r->pipelines.window_pipeline || !r->pipelines.cursor_pipeline || !r->pipelines.blit_pipeline || !r->pipelines.offscreen_window_pipeline || !r->pipelines.offscreen_cursor_pipeline - || !r->pipelines.offscreen_blit_pipeline) { + || !r->pipelines.offscreen_blit_pipeline + || !r->pipelines.fg_motion_pipeline + || !r->pipelines.fg_flowfix_pipeline + || !r->pipelines.fg_interp_pipeline) { destroy_pipelines(r); return false; } @@ -1034,9 +1325,17 @@ static void destroy_pipelines(VkRenderer* r) { if (r->pipelines.offscreen_window_pipeline) vkDestroyPipeline(r->device, r->pipelines.offscreen_window_pipeline, NULL); if (r->pipelines.offscreen_cursor_pipeline) vkDestroyPipeline(r->device, r->pipelines.offscreen_cursor_pipeline, NULL); if (r->pipelines.offscreen_blit_pipeline) vkDestroyPipeline(r->device, r->pipelines.offscreen_blit_pipeline, NULL); + if (r->pipelines.fg_motion_pipeline) vkDestroyPipeline(r->device, r->pipelines.fg_motion_pipeline, NULL); + if (r->pipelines.fg_flowfix_pipeline) vkDestroyPipeline(r->device, r->pipelines.fg_flowfix_pipeline, NULL); + if (r->pipelines.fg_interp_pipeline) vkDestroyPipeline(r->device, r->pipelines.fg_interp_pipeline, NULL); + destroy_cnn_pipelines(r); if (r->pipelines.window_layout) vkDestroyPipelineLayout(r->device, r->pipelines.window_layout, NULL); if (r->pipelines.effect_layout) vkDestroyPipelineLayout(r->device, r->pipelines.effect_layout, NULL); + if (r->pipelines.fg_motion_pipe_layout) vkDestroyPipelineLayout(r->device, r->pipelines.fg_motion_pipe_layout, NULL); + if (r->pipelines.fg_interp_pipe_layout) vkDestroyPipelineLayout(r->device, r->pipelines.fg_interp_pipe_layout, NULL); if (r->pipelines.sampler_set_layout) vkDestroyDescriptorSetLayout(r->device, r->pipelines.sampler_set_layout, NULL); + if (r->pipelines.fg_motion_layout) vkDestroyDescriptorSetLayout(r->device, r->pipelines.fg_motion_layout, NULL); + if (r->pipelines.fg_interp_layout) vkDestroyDescriptorSetLayout(r->device, r->pipelines.fg_interp_layout, NULL); if (r->pipelines.swapchain_pass) vkDestroyRenderPass(r->device, r->pipelines.swapchain_pass, NULL); if (r->pipelines.offscreen_pass) vkDestroyRenderPass(r->device, r->pipelines.offscreen_pass, NULL); memset(&r->pipelines, 0, sizeof(r->pipelines)); @@ -1122,29 +1421,33 @@ static bool create_swapchain(VkRenderer* r, uint32_t fallback_width, uint32_t fa free(fmts); r->swapchain_format = chosen.format; - // Honor the Java-requested present mode if the device supports it; otherwise fall back - // to FIFO (always supported per spec). target_present_mode is initialized to FIFO in - // nativeCreate, so a value-equality check is safe (no zero-sentinel ambiguity with - // VK_PRESENT_MODE_IMMEDIATE_KHR which is enum value 0). VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; VkPresentModeKHR want = r->target_present_mode; if (want != VK_PRESENT_MODE_FIFO_KHR) { uint32_t pm_count = 0; vkGetPhysicalDeviceSurfacePresentModesKHR(r->physical_device, r->surface, &pm_count, NULL); + bool have_want = false, have_immediate = false; if (pm_count > 0) { VkPresentModeKHR* pms = calloc(pm_count, sizeof(VkPresentModeKHR)); if (pms) { vkGetPhysicalDeviceSurfacePresentModesKHR(r->physical_device, r->surface, &pm_count, pms); for (uint32_t i = 0; i < pm_count; i++) { - if (pms[i] == want) { present_mode = want; break; } + if (pms[i] == want) have_want = true; + if (pms[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) have_immediate = true; } free(pms); } } - if (present_mode != want) { + if (have_want) { + present_mode = want; + } else if (want == VK_PRESENT_MODE_MAILBOX_KHR && have_immediate) { + present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR; + VK_LOGW("MAILBOX unavailable; using IMMEDIATE for off-vsync present"); + } else { VK_LOGW("Requested present mode %d unavailable; using FIFO", want); } } + r->active_present_mode = present_mode; VkSurfaceTransformFlagBitsKHR pre_transform = caps.currentTransform; if (!is_plain_rotation_transform(pre_transform) @@ -1182,14 +1485,14 @@ static bool create_swapchain(VkRenderer* r, uint32_t fallback_width, uint32_t fa r->surface_extent = surface_extent; r->swapchain_extent = extent; r->swapchain_transform = pre_transform; - // Only possible for unsupported mirrored transforms; avoid an Adreno present loop - // while still letting normal rotation changes recreate the swapchain. r->ignore_suboptimal = r->caps.is_adreno && (pre_transform != caps.currentTransform); - VK_LOGI("Swapchain surface=%ux%u extent=%ux%u currentTransform=0x%x preTransform=0x%x", + VK_LOGI("Swapchain surface=%ux%u extent=%ux%u currentTransform=0x%x preTransform=0x%x mode=%d", surface_extent.width, surface_extent.height, extent.width, extent.height, - caps.currentTransform, pre_transform); + caps.currentTransform, pre_transform, present_mode); uint32_t image_count = caps.minImageCount + 1; + if (image_count < VK_FRAMES_IN_FLIGHT + 1u) image_count = VK_FRAMES_IN_FLIGHT + 1u; + if (present_mode != VK_PRESENT_MODE_FIFO_KHR && image_count < 5) image_count = 5; if (caps.maxImageCount > 0 && image_count > caps.maxImageCount) image_count = caps.maxImageCount; if (image_count > VK_MAX_SWAPCHAIN_IMAGES) image_count = VK_MAX_SWAPCHAIN_IMAGES; @@ -1227,6 +1530,16 @@ static bool create_swapchain(VkRenderer* r, uint32_t fallback_width, uint32_t fa r->swapchain = new_sc; if (old_sc) vkDestroySwapchainKHR(r->device, old_sc, NULL); + r->refresh_duration_ns = 0; + r->fg_present_deadline_ns = 0; + r->fg_present_target_ns = 0; + r->fg_present_id = 0; + if (r->ext_display_timing && r->fnGetRefreshCycleDuration) { + VkRefreshCycleDurationGOOGLE rc = {0}; + if (r->fnGetRefreshCycleDuration(r->device, r->swapchain, &rc) == VK_SUCCESS) + r->refresh_duration_ns = rc.refreshDuration; + } + uint32_t actual_count = 0; if (vkGetSwapchainImagesKHR(r->device, r->swapchain, &actual_count, NULL) != VK_SUCCESS || actual_count == 0) { @@ -1647,9 +1960,6 @@ static void destroy_one_offscreen(VkRenderer* r, VkOffscreen* o) { memset(o, 0, sizeof(*o)); } -// Builds offscreen[0], plus the second ping-pong target (~8 MB RGBA8 + view/sampler/descriptor/ -// framebuffer) only when need_second. At matching dims, a missing second target is added in -// place without disturbing offscreen[0]. static bool create_offscreen(VkRenderer* r, uint32_t w, uint32_t h, bool need_second) { bool dims_ok = r->offscreen_built && r->offscreen[0].width == w && r->offscreen[0].height == h; @@ -1713,11 +2023,7 @@ static void destroy_sgsr1_resources(VkRenderer* r) { // Graveyard processing // ============================================================ -// Detach the slot's pending-destroy list under scene_mutex. The Vulkan destroy calls -// (vkFreeDescriptorSets, vkDestroyImage, vkFreeMemory, AHardwareBuffer_release) can each -// take tens to hundreds of microseconds on Adreno, so doing them under scene_mutex stalls -// every scene producer (X server, input thread) for the full duration. Caller passes the -// detached array to destroy_graveyard_textures() after releasing the lock. +// Detach the slot's pending-destroy list under scene_mutex; caller destroys after unlocking. static void detach_graveyard_slot(VkRenderer* r, uint32_t slot_idx, VkTexture*** out_textures, uint32_t* out_count) { VkGraveSlot* slot = &r->graveyard[slot_idx]; @@ -1894,10 +2200,7 @@ static void push_window_constants(VkCommandBuffer cmd, VkPipelineLayout layout, static void compose_xform_for_window(float out[6], const float scene_xform[6], int wx, int wy, int ww, int wh) { - // Equivalent to GLRenderer.renderDrawable: tmpXForm1 = make(x, y, w, h); tmpXForm1 *= tmpXForm2 - // XForm.set(out, x, y, w, h): [w, 0, 0, h, x, y] float a[6] = { (float)ww, 0.0f, 0.0f, (float)wh, (float)wx, (float)wy }; - // 2x2 + translation multiply: result = a * scene_xform out[0] = a[0]*scene_xform[0] + a[1]*scene_xform[2]; out[1] = a[0]*scene_xform[1] + a[1]*scene_xform[3]; out[2] = a[2]*scene_xform[0] + a[3]*scene_xform[2]; @@ -2093,62 +2396,17 @@ static VkExtent2D compute_sgsr1_source_extent(VkRenderer* r, const VkScene* s) { return source; } -static bool record_and_submit_frame(VkRenderer* r) { - if (!r->surface_ready || !r->swapchain) return false; - - pthread_mutex_lock(&r->render_mutex); - - VkFrame* f = &r->frames[r->frame_index]; - uint32_t grave_slot = r->graveyard_index; - - if (f->in_flight == VK_NULL_HANDLE) { - VkFenceCreateInfo fci = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; - fci.flags = VK_FENCE_CREATE_SIGNALED_BIT; - if (vkCreateFence(r->device, &fci, NULL, &f->in_flight) != VK_SUCCESS) { - f->in_flight = VK_NULL_HANDLE; - VK_LOGE("frame fence unavailable; skipping frame"); - pthread_mutex_unlock(&r->render_mutex); - return false; - } - } - - vkWaitForFences(r->device, 1, &f->in_flight, VK_TRUE, UINT64_MAX); - - // Snapshot the scene under scene_mutex (cheap memcpy of a few KB), then release it so - // scene producers (texture destroys, X server window updates) don't stall behind the - // long acquire/record/submit/present below. render_mutex still serializes us against - // surface lifecycle changes, which keeps the swapchain handles stable for our use. - VkScene snap; - VkTexture** dead = NULL; - uint32_t dead_count = 0; - pthread_mutex_lock(&r->scene_mutex); - if (!r->surface_ready || !r->swapchain || r->swapchain_image_count == 0 - || r->swapchain_extent.width == 0 || r->swapchain_extent.height == 0) { - pthread_mutex_unlock(&r->scene_mutex); - pthread_mutex_unlock(&r->render_mutex); - return false; - } - snap = r->scene; - detach_graveyard_slot(r, grave_slot, &dead, &dead_count); - pthread_mutex_unlock(&r->scene_mutex); - destroy_graveyard_textures(r, dead, dead_count); - - bool wants_sgsr1 = scene_starts_with_sgsr1(&snap); - bool needs_fullres_offscreen = snap.effect_count > 0 - && (!wants_sgsr1 || snap.effect_count > 1); - // offscreen[1] is reached only once the chain writes two distinct offscreen buffers: the - // effect loop's dst_idx starts at 1 for a non-SGSR chain but at 0 for an SGSR1-led one - // (scene goes to the separate SGSR source), so the threshold is >1 normally, >2 for SGSR. +// (Re)build the effect ping-pong / SGSR1 targets for the current scene. Caller holds render_mutex. +static SceneTargets manage_scene_targets(VkRenderer* r, const VkScene* snap) { + bool wants_sgsr1 = scene_starts_with_sgsr1(snap); + bool needs_fullres_offscreen = snap->effect_count > 0 + && (!wants_sgsr1 || snap->effect_count > 1); bool needs_second_offscreen = needs_fullres_offscreen - && snap.effect_count > (wants_sgsr1 ? 2u : 1u); + && snap->effect_count > (wants_sgsr1 ? 2u : 1u); VkExtent2D sgsr1_source_extent = wants_sgsr1 - ? compute_sgsr1_source_extent(r, &snap) + ? compute_sgsr1_source_extent(r, snap) : r->swapchain_extent; - // Full-res ping-pong targets exist only when the chain needs them (SGSR-only writes its - // low-res source straight to the swapchain). offscreen[1] is grown/freed lazily as the - // chain crosses the threshold above; effect counts change on user action, not per frame, - // so this doesn't thrash. Safe under render_mutex (no concurrent swapchain teardown). bool offscreen_dims_stale = !r->offscreen_built || r->offscreen[0].width != r->swapchain_extent.width || r->offscreen[0].height != r->swapchain_extent.height; @@ -2166,9 +2424,6 @@ static bool record_and_submit_frame(VkRenderer* r) { wait_inflight_frames(r); destroy_offscreen(r); } - // Only rebuild SGSR1 source on meaningful dim change. Tiny pixmap-size flicker (off-by- - // one DRI3 jitter, transient resizes) used to thrash this allocation every frame and - // stall the render thread on the full-device wait that preceded it. int sgsr1_dw = (int)r->sgsr1.width - (int)sgsr1_source_extent.width; int sgsr1_dh = (int)r->sgsr1.height - (int)sgsr1_source_extent.height; if (sgsr1_dw < 0) sgsr1_dw = -sgsr1_dw; @@ -2182,6 +2437,117 @@ static bool record_and_submit_frame(VkRenderer* r) { destroy_sgsr1_resources(r); } + bool has_effects = snap->effect_count > 0 && r->offscreen_built; + if (snap->effect_count > 0) { + bool full_ok = !needs_fullres_offscreen + || (r->offscreen_built + && (!needs_second_offscreen || r->offscreen[1].image != VK_NULL_HANDLE)); + has_effects = full_ok && (!wants_sgsr1 || r->sgsr1.built); + } + SceneTargets st = { has_effects, wants_sgsr1 }; + return st; +} + +// Record the composited scene into final_fb; final_offscreen picks the pipeline variant. +static void record_scene_chain(VkRenderer* r, VkCommandBuffer cmd, const VkScene* snap, + bool has_effects, bool wants_sgsr1, + VkRenderPass final_pass, VkFramebuffer final_fb, + uint32_t final_w, uint32_t final_h, bool final_offscreen) { + VkClearValue clear = {0}; + clear.color.float32[3] = 1.0f; + + if (has_effects) { + VkOffscreen* scene_target = (wants_sgsr1 && r->sgsr1.built) + ? &r->sgsr1.source + : &r->offscreen[0]; + + VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + rpbi.renderPass = r->pipelines.offscreen_pass; + rpbi.framebuffer = scene_target->framebuffer; + rpbi.renderArea.extent.width = scene_target->width; + rpbi.renderArea.extent.height = scene_target->height; + rpbi.clearValueCount = 1; + rpbi.pClearValues = &clear; + vkCmdBeginRenderPass(cmd, &rpbi, VK_SUBPASS_CONTENTS_INLINE); + draw_scene_pass(r, cmd, snap, true, scene_target->width, scene_target->height); + vkCmdEndRenderPass(cmd); + + VkOffscreen* src_offscreen = scene_target; + uint32_t dst_idx = (scene_target == &r->offscreen[0]) ? 1u : 0u; + for (uint32_t i = 0; i < snap->effect_count; i++) { + bool last = (i == snap->effect_count - 1); + VkEffectSlot eff = snap->effects[i]; + if (last) { + rpbi.renderPass = final_pass; + rpbi.framebuffer = final_fb; + rpbi.renderArea.extent.width = final_w; + rpbi.renderArea.extent.height = final_h; + } else { + rpbi.renderPass = r->pipelines.offscreen_pass; + rpbi.framebuffer = r->offscreen[dst_idx].framebuffer; + rpbi.renderArea.extent.width = r->offscreen[dst_idx].width; + rpbi.renderArea.extent.height = r->offscreen[dst_idx].height; + } + vkCmdBeginRenderPass(cmd, &rpbi, VK_SUBPASS_CONTENTS_INLINE); + uint32_t target_w = last ? final_w : rpbi.renderArea.extent.width; + uint32_t target_h = last ? final_h : rpbi.renderArea.extent.height; + run_effect(r, cmd, &eff, src_offscreen->descriptor_set, target_w, target_h, + last ? final_offscreen : true); + vkCmdEndRenderPass(cmd); + if (!last) { + src_offscreen = &r->offscreen[dst_idx]; + dst_idx ^= 1u; + } + } + } else { + VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + rpbi.renderPass = final_pass; + rpbi.framebuffer = final_fb; + rpbi.renderArea.extent.width = final_w; + rpbi.renderArea.extent.height = final_h; + rpbi.clearValueCount = 1; + rpbi.pClearValues = &clear; + vkCmdBeginRenderPass(cmd, &rpbi, VK_SUBPASS_CONTENTS_INLINE); + draw_scene_pass(r, cmd, snap, final_offscreen, final_w, final_h); + vkCmdEndRenderPass(cmd); + } +} + +static inline uint32_t vkr_active_fif(VkRenderer* r) { + uint32_t fif = r->fg_target_fif; + if (fif < 1u || fif > VK_FRAMES_IN_FLIGHT) fif = VK_FRAMES_IN_FLIGHT; + return fif; +} + +static bool record_and_submit_frame(VkRenderer* r) { + if (!r->surface_ready || !r->swapchain) return false; + + pthread_mutex_lock(&r->render_mutex); + + if (r->frame_index >= vkr_active_fif(r)) r->frame_index = 0; // live Buffering shrink + VkFrame* f = &r->frames[r->frame_index]; + uint32_t grave_slot = r->graveyard_index; + + vkWaitForFences(r->device, 1, &f->in_flight, VK_TRUE, UINT64_MAX); + + // Snapshot the scene under scene_mutex, then release it before the long acquire/submit/present. + VkScene snap; + VkTexture** dead = NULL; + uint32_t dead_count = 0; + pthread_mutex_lock(&r->scene_mutex); + if (!r->surface_ready || !r->swapchain || r->swapchain_image_count == 0 + || r->swapchain_extent.width == 0 || r->swapchain_extent.height == 0) { + pthread_mutex_unlock(&r->scene_mutex); + pthread_mutex_unlock(&r->render_mutex); + return false; + } + snap = r->scene; + detach_graveyard_slot(r, grave_slot, &dead, &dead_count); + pthread_mutex_unlock(&r->scene_mutex); + destroy_graveyard_textures(r, dead, dead_count); + + SceneTargets st = manage_scene_targets(r, &snap); + uint32_t image_index = 0; VkResult acq = vkAcquireNextImageKHR(r->device, r->swapchain, UINT64_MAX, f->image_available, VK_NULL_HANDLE, &image_index); @@ -2244,80 +2610,9 @@ static bool record_and_submit_frame(VkRenderer* r) { bi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; vkBeginCommandBuffer(f->cmd, &bi); - bool has_effects = snap.effect_count > 0 && r->offscreen_built; - if (snap.effect_count > 0) { - // Don't enter the effect path if a required target's lazy creation failed (else we'd - // record into a null framebuffer). - bool full_ok = !needs_fullres_offscreen - || (r->offscreen_built - && (!needs_second_offscreen || r->offscreen[1].image != VK_NULL_HANDLE)); - has_effects = full_ok && (!wants_sgsr1 || r->sgsr1.built); - } - - VkClearValue clear = {0}; - clear.color.float32[0] = 0.0f; - clear.color.float32[1] = 0.0f; - clear.color.float32[2] = 0.0f; - clear.color.float32[3] = 1.0f; - - if (has_effects) { - VkOffscreen* scene_target = (wants_sgsr1 && r->sgsr1.built) - ? &r->sgsr1.source - : &r->offscreen[0]; - - // Pass 1: render scene to either full-res effect input or SGSR1's low-res source. - VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - rpbi.renderPass = r->pipelines.offscreen_pass; - rpbi.framebuffer = scene_target->framebuffer; - rpbi.renderArea.extent.width = scene_target->width; - rpbi.renderArea.extent.height = scene_target->height; - rpbi.clearValueCount = 1; - rpbi.pClearValues = &clear; - vkCmdBeginRenderPass(f->cmd, &rpbi, VK_SUBPASS_CONTENTS_INLINE); - draw_scene_pass(r, f->cmd, &snap, true, - scene_target->width, scene_target->height); - vkCmdEndRenderPass(f->cmd); - - // Effect chain: source descriptor moves through ping-pong buffers. When SGSR1 is - // first, the first source is low-res and SGSR1 writes full-res output. - VkOffscreen* src_offscreen = scene_target; - uint32_t dst_idx = (scene_target == &r->offscreen[0]) ? 1u : 0u; - for (uint32_t i = 0; i < snap.effect_count; i++) { - bool last = (i == snap.effect_count - 1); - VkEffectSlot* eff = &snap.effects[i]; - - if (last) { - rpbi.renderPass = r->pipelines.swapchain_pass; - rpbi.framebuffer = r->swapchain_framebuffers[image_index]; - rpbi.renderArea.extent = r->swapchain_extent; - } else { - rpbi.renderPass = r->pipelines.offscreen_pass; - rpbi.framebuffer = r->offscreen[dst_idx].framebuffer; - rpbi.renderArea.extent.width = r->offscreen[dst_idx].width; - rpbi.renderArea.extent.height = r->offscreen[dst_idx].height; - } - vkCmdBeginRenderPass(f->cmd, &rpbi, VK_SUBPASS_CONTENTS_INLINE); - uint32_t target_w = last ? r->swapchain_extent.width : rpbi.renderArea.extent.width; - uint32_t target_h = last ? r->swapchain_extent.height : rpbi.renderArea.extent.height; - run_effect(r, f->cmd, eff, src_offscreen->descriptor_set, target_w, target_h, !last); - vkCmdEndRenderPass(f->cmd); - if (!last) { - src_offscreen = &r->offscreen[dst_idx]; - dst_idx ^= 1u; - } - } - } else { - VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - rpbi.renderPass = r->pipelines.swapchain_pass; - rpbi.framebuffer = r->swapchain_framebuffers[image_index]; - rpbi.renderArea.extent = r->swapchain_extent; - rpbi.clearValueCount = 1; - rpbi.pClearValues = &clear; - vkCmdBeginRenderPass(f->cmd, &rpbi, VK_SUBPASS_CONTENTS_INLINE); - draw_scene_pass(r, f->cmd, &snap, false, - r->swapchain_extent.width, r->swapchain_extent.height); - vkCmdEndRenderPass(f->cmd); - } + record_scene_chain(r, f->cmd, &snap, st.has_effects, st.wants_sgsr1, + r->pipelines.swapchain_pass, r->swapchain_framebuffers[image_index], + r->swapchain_extent.width, r->swapchain_extent.height, false); // Blit the final composited image (in PRESENT_SRC after the render pass) into the encoder image. if (rec_this_frame) { @@ -2407,8 +2702,6 @@ static bool record_and_submit_frame(VkRenderer* r) { pthread_mutex_unlock(&r->queue_mutex); if (sr != VK_SUCCESS) { VK_LOGE("vkQueueSubmit -> %d", sr); - // The frame fence was reset before submit. If submit fails, nothing will ever signal - // it, so restore a signaled fence before returning or the next frame can block forever. vkDestroyFence(r->device, f->in_flight, NULL); VkFenceCreateInfo rfi = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; rfi.flags = VK_FENCE_CREATE_SIGNALED_BIT; @@ -2429,6 +2722,7 @@ static bool record_and_submit_frame(VkRenderer* r) { pthread_mutex_lock(&r->queue_mutex); VkResult pr = vkQueuePresentKHR(r->graphics_queue, &pi); + if (pr == VK_SUCCESS || pr == VK_SUBOPTIMAL_KHR) r->fg_present_count++; // Present the mirror separately so its result doesn't disturb the display recreate logic below. if (rec_this_frame) { VkPresentInfoKHR rpi = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR}; @@ -2457,54 +2751,1618 @@ static bool record_and_submit_frame(VkRenderer* r) { pthread_mutex_unlock(&r->render_mutex); - r->frame_index = (r->frame_index + 1) % VK_FRAMES_IN_FLIGHT; + r->frame_index = (r->frame_index + 1) % vkr_active_fif(r); r->graveyard_index = (r->graveyard_index + 1) % (VK_FRAMES_IN_FLIGHT + 1); return true; } // ============================================================ -// JNI entry points +// Frame generation resources + submit // ============================================================ -#define JNI_FN(name) Java_com_winlator_cmod_runtime_display_renderer_VulkanRenderer_##name +static VkDescriptorSet fg_alloc_set(VkRenderer* r, VkDescriptorSetLayout layout) { + VkDescriptorSetAllocateInfo ai = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + ai.descriptorPool = r->descriptor_pool; + ai.descriptorSetCount = 1; + ai.pSetLayouts = &layout; + VkDescriptorSet set = VK_NULL_HANDLE; + pthread_mutex_lock(&r->descriptor_mutex); + VkResult res = vkAllocateDescriptorSets(r->device, &ai, &set); + pthread_mutex_unlock(&r->descriptor_mutex); + if (res != VK_SUCCESS) { VK_LOGE("fg_alloc_set failed: %d", res); return VK_NULL_HANDLE; } + return set; +} -JNIEXPORT jlong JNICALL JNI_FN(nativeCreate)(JNIEnv* env, jclass clazz, - jboolean enableValidationLayers, - jstring driverName, - jobject context) { - (void)clazz; - VkRenderer* r = calloc(1, sizeof(VkRenderer)); - if (!r) return 0; - r->target_present_mode = VK_PRESENT_MODE_FIFO_KHR; - r->validation_enabled = (enableValidationLayers == JNI_TRUE); - pthread_mutex_init(&r->scene_mutex, NULL); - pthread_mutex_init(&r->queue_mutex, NULL); - pthread_mutex_init(&r->texture_mutex, NULL); - pthread_mutex_init(&r->render_mutex, NULL); - pthread_mutex_init(&r->descriptor_mutex, NULL); +static void fg_free_set(VkRenderer* r, VkDescriptorSet set) { + if (set == VK_NULL_HANDLE) return; + pthread_mutex_lock(&r->descriptor_mutex); + vkFreeDescriptorSets(r->device, r->descriptor_pool, 1, &set); + pthread_mutex_unlock(&r->descriptor_mutex); +} - const char* driver_name_c = NULL; - if (driverName != NULL) driver_name_c = (*env)->GetStringUTFChars(env, driverName, NULL); - r->vulkan_handle = winlator_open_vulkan(env, context, driver_name_c); - if (driver_name_c != NULL) (*env)->ReleaseStringUTFChars(env, driverName, driver_name_c); +static void fg_destroy_sig(VkRenderer* r); // content-dedup signature teardown (defined below) +static void fg_destroy_dump(VkRenderer* r); // debug burst-dump teardown (defined below) + +static void fg_destroy_resources(VkRenderer* r) { + if (!r->device) return; + for (uint32_t p = 0; p < 3; p++) { + if (r->fg_motion_set[p]) { fg_free_set(r, r->fg_motion_set[p]); r->fg_motion_set[p] = VK_NULL_HANDLE; } + if (r->fg_motion_set_fwd[p]) { fg_free_set(r, r->fg_motion_set_fwd[p]); r->fg_motion_set_fwd[p] = VK_NULL_HANDLE; } + if (r->fg_fix_set[p]) { fg_free_set(r, r->fg_fix_set[p]); r->fg_fix_set[p] = VK_NULL_HANDLE; } + if (r->fg_interp_set[p]) { fg_free_set(r, r->fg_interp_set[p]); r->fg_interp_set[p] = VK_NULL_HANDLE; } + if (r->fg_interp_set_deep[p]) { fg_free_set(r, r->fg_interp_set_deep[p]); r->fg_interp_set_deep[p] = VK_NULL_HANDLE; } + } + memset(r->fg_slot_fence, 0, sizeof(r->fg_slot_fence)); + for (uint32_t i = 0; i < 3; i++) { + VkFgImage* o = &r->fg_history[i]; + if (o->blit_set) vkr_free_descriptor_set(r, o->blit_set); + if (o->framebuffer) vkDestroyFramebuffer(r->device, o->framebuffer, NULL); + if (o->view) vkDestroyImageView(r->device, o->view, NULL); + if (o->storeView) vkDestroyImageView(r->device, o->storeView, NULL); + if (o->image) vkDestroyImage(r->device, o->image, NULL); + if (o->memory) vkFreeMemory(r->device, o->memory, NULL); + memset(o, 0, sizeof(*o)); + } + fg_destroy_cnn_resources(r); + for (uint32_t mi = 0; mi < 3; mi++) { + VkFgImage* m = &r->fg_motion[mi]; + if (m->view) vkDestroyImageView(r->device, m->view, NULL); + if (m->image) vkDestroyImage(r->device, m->image, NULL); + if (m->memory) vkFreeMemory(r->device, m->memory, NULL); + VkFgImage* mf = &r->fg_motion_fwd[mi]; + if (mf->view) vkDestroyImageView(r->device, mf->view, NULL); + if (mf->image) vkDestroyImage(r->device, mf->image, NULL); + if (mf->memory) vkFreeMemory(r->device, mf->memory, NULL); + VkFgImage* fx = &r->fg_fixed[mi]; + if (fx->view) vkDestroyImageView(r->device, fx->view, NULL); + if (fx->image) vkDestroyImage(r->device, fx->image, NULL); + if (fx->memory) vkFreeMemory(r->device, fx->memory, NULL); + VkFgImage* cb_ = &r->fg_coarse[mi]; + if (cb_->view) vkDestroyImageView(r->device, cb_->view, NULL); + if (cb_->image) vkDestroyImage(r->device, cb_->image, NULL); + if (cb_->memory) vkFreeMemory(r->device, cb_->memory, NULL); + VkFgImage* cf_ = &r->fg_coarse_fwd[mi]; + if (cf_->view) vkDestroyImageView(r->device, cf_->view, NULL); + if (cf_->image) vkDestroyImage(r->device, cf_->image, NULL); + if (cf_->memory) vkFreeMemory(r->device, cf_->memory, NULL); + } + memset(r->fg_motion, 0, sizeof(r->fg_motion)); + memset(r->fg_fixed, 0, sizeof(r->fg_fixed)); + memset(r->fg_motion_fwd, 0, sizeof(r->fg_motion_fwd)); + memset(r->fg_coarse, 0, sizeof(r->fg_coarse)); + memset(r->fg_coarse_fwd, 0, sizeof(r->fg_coarse_fwd)); + if (r->fg_sampler) { vkDestroySampler(r->device, r->fg_sampler, NULL); r->fg_sampler = VK_NULL_HANDLE; } + fg_destroy_sig(r); + fg_destroy_dump(r); + r->fg_built = false; + r->fg_history_count = 0; + r->fg_history_curr = 0; + r->fg_dims.width = 0; + r->fg_dims.height = 0; +} - if (!r->vulkan_handle) { - VK_LOGE("winlator_open_vulkan returned NULL"); - goto fail; - } - if (!vkd_init(r->vulkan_handle)) { - VK_LOGE("vkd_init failed"); - goto fail; - } +// Full-res composited-scene history target: render target (offscreen_pass) + sampled input. +static bool fg_create_color_target(VkRenderer* r, VkFgImage* o, uint32_t w, uint32_t h) { + o->width = w; o->height = h; + VkImageCreateInfo ic = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; + ic.imageType = VK_IMAGE_TYPE_2D; + ic.format = r->caps.offscreen_format; + ic.extent.width = w; ic.extent.height = h; ic.extent.depth = 1; + ic.mipLevels = 1; ic.arrayLayers = 1; + ic.samples = VK_SAMPLE_COUNT_1_BIT; + ic.tiling = VK_IMAGE_TILING_OPTIMAL; + ic.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; // rgba8 storage alias (synth-shift harness) + ic.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_STORAGE_BIT; + ic.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + ic.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + if (vkCreateImage(r->device, &ic, NULL, &o->image) != VK_SUCCESS) return false; - if (!create_instance(r)) goto fail; - if (!pick_physical_device(r)) goto fail; - if (!create_device(r)) goto fail; - query_device_caps(r); - if (!create_command_pool(r)) goto fail; - if (!create_descriptor_pool(r, r->caps.descriptor_pool_capacity)) goto fail; - if (!create_quad_vbo(r)) goto fail; + VkMemoryRequirements mr; vkGetImageMemoryRequirements(r->device, o->image, &mr); + VkMemoryAllocateInfo ai = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; + ai.allocationSize = mr.size; + ai.memoryTypeIndex = vkr_find_memory_type(r, mr.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + if (ai.memoryTypeIndex == UINT32_MAX) return false; + if (vkAllocateMemory(r->device, &ai, NULL, &o->memory) != VK_SUCCESS) return false; + vkBindImageMemory(r->device, o->image, o->memory, 0); + + VkImageViewCreateInfo vi = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + vi.image = o->image; vi.viewType = VK_IMAGE_VIEW_TYPE_2D; vi.format = ic.format; + vi.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + vi.subresourceRange.levelCount = 1; vi.subresourceRange.layerCount = 1; + if (vkCreateImageView(r->device, &vi, NULL, &o->view) != VK_SUCCESS) return false; + + vi.format = VK_FORMAT_R8G8B8A8_UNORM; // rgba8 storage alias for the synth-shift harness + if (vkCreateImageView(r->device, &vi, NULL, &o->storeView) != VK_SUCCESS) return false; + + VkFramebufferCreateInfo fb = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + fb.renderPass = r->pipelines.offscreen_pass; + fb.attachmentCount = 1; fb.pAttachments = &o->view; + fb.width = w; fb.height = h; fb.layers = 1; + if (vkCreateFramebuffer(r->device, &fb, NULL, &o->framebuffer) != VK_SUCCESS) return false; + + // Single-binding set (sampler_set_layout) so PRESENT_LAST can reuse the blit pipeline. + o->blit_set = vkr_alloc_descriptor_set(r); + if (o->blit_set == VK_NULL_HANDLE) return false; + VkDescriptorImageInfo dii = { r->fg_sampler, o->view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }; + VkWriteDescriptorSet wr = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET}; + wr.dstSet = o->blit_set; wr.dstBinding = 0; wr.descriptorCount = 1; + wr.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; wr.pImageInfo = &dii; + vkUpdateDescriptorSets(r->device, 1, &wr, 0, NULL); + return true; +} + +// Half-res rgba16f flow field: storage (motion.comp write) + sampled (interpolate.frag). +static bool fg_create_motion(VkRenderer* r, VkFgImage* o, uint32_t w, uint32_t h) { + o->width = w; o->height = h; o->framebuffer = VK_NULL_HANDLE; + VkImageCreateInfo ic = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; + ic.imageType = VK_IMAGE_TYPE_2D; + ic.format = VK_FORMAT_R16G16B16A16_SFLOAT; // mandatory storage format (no extended-format feature) + ic.extent.width = w; ic.extent.height = h; ic.extent.depth = 1; + ic.mipLevels = 1; ic.arrayLayers = 1; + ic.samples = VK_SAMPLE_COUNT_1_BIT; + ic.tiling = VK_IMAGE_TILING_OPTIMAL; + ic.usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; // TRANSFER_SRC so the flow can be dumped + ic.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + ic.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + if (vkCreateImage(r->device, &ic, NULL, &o->image) != VK_SUCCESS) return false; + + VkMemoryRequirements mr; vkGetImageMemoryRequirements(r->device, o->image, &mr); + VkMemoryAllocateInfo ai = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; + ai.allocationSize = mr.size; + ai.memoryTypeIndex = vkr_find_memory_type(r, mr.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + if (ai.memoryTypeIndex == UINT32_MAX) return false; + if (vkAllocateMemory(r->device, &ai, NULL, &o->memory) != VK_SUCCESS) return false; + vkBindImageMemory(r->device, o->image, o->memory, 0); + + VkImageViewCreateInfo vi = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + vi.image = o->image; vi.viewType = VK_IMAGE_VIEW_TYPE_2D; vi.format = ic.format; + vi.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + vi.subresourceRange.levelCount = 1; vi.subresourceRange.layerCount = 1; + if (vkCreateImageView(r->device, &vi, NULL, &o->view) != VK_SUCCESS) return false; + return true; +} + +static void fg_fix_pass(VkRenderer* r, VkCommandBuffer cmd, uint32_t parity, float phase) { + VkFgImage* dst = &r->fg_fixed[parity]; + struct { int32_t mvW, mvH; float invW, invH, mvScale, minStep, upscale, phase; } fpc; + fpc.mvW = (int32_t)dst->width; fpc.mvH = (int32_t)dst->height; + fpc.invW = 1.0f / (float)dst->width; fpc.invH = 1.0f / (float)dst->height; + fpc.mvScale = 1.0f; fpc.minStep = 0.0f; fpc.upscale = 0.0f; fpc.phase = phase; + vkr_image_barrier(cmd, r->fg_motion[parity].image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + vkr_image_barrier(cmd, dst->image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, VK_ACCESS_SHADER_WRITE_BIT); + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, r->pipelines.fg_flowfix_pipeline); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, r->pipelines.fg_motion_pipe_layout, 0, 1, &r->fg_fix_set[parity], 0, NULL); + vkCmdPushConstants(cmd, r->pipelines.fg_motion_pipe_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(fpc), &fpc); + vkCmdDispatch(cmd, (dst->width + 7u) / 8u, (dst->height + 7u) / 8u, 1); + vkr_image_barrier(cmd, dst->image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); +} + +static void fg_motion_pass(VkRenderer* r, VkCommandBuffer cmd, + VkDescriptorSet coarseSet, VkFgImage* coarseImg, + VkDescriptorSet fineSet, VkFgImage* fineImg, float minStep) { + struct { int32_t mvW, mvH; float invW, invH, mvScale, minStep, upscale, p2; } mpc; + mpc.mvScale = 1.0f; mpc.minStep = minStep; mpc.p2 = 0.0f; + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, r->pipelines.fg_motion_pipeline); + vkr_image_barrier(cmd, coarseImg->image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, VK_ACCESS_SHADER_WRITE_BIT); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, r->pipelines.fg_motion_pipe_layout, 0, 1, &coarseSet, 0, NULL); + mpc.mvW = (int32_t)coarseImg->width; mpc.mvH = (int32_t)coarseImg->height; + mpc.invW = 1.0f / (float)coarseImg->width; mpc.invH = 1.0f / (float)coarseImg->height; mpc.upscale = 0.0f; + vkCmdPushConstants(cmd, r->pipelines.fg_motion_pipe_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(mpc), &mpc); + vkCmdDispatch(cmd, (coarseImg->width + 7u) / 8u, (coarseImg->height + 7u) / 8u, 1); + vkr_image_barrier(cmd, coarseImg->image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + vkr_image_barrier(cmd, fineImg->image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, VK_ACCESS_SHADER_WRITE_BIT); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, r->pipelines.fg_motion_pipe_layout, 0, 1, &fineSet, 0, NULL); + mpc.mvW = (int32_t)fineImg->width; mpc.mvH = (int32_t)fineImg->height; + mpc.invW = 1.0f / (float)fineImg->width; mpc.invH = 1.0f / (float)fineImg->height; + mpc.upscale = (float)fineImg->width / (float)coarseImg->width; + vkCmdPushConstants(cmd, r->pipelines.fg_motion_pipe_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(mpc), &mpc); + vkCmdDispatch(cmd, (fineImg->width + 7u) / 8u, (fineImg->height + 7u) / 8u, 1); + vkr_image_barrier(cmd, fineImg->image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); +} + +#include "vk_cnn_fg.c" + +// Content-signature resources for duplicate detection: a tiny blit target + per-slot host buffers. +#define FG_SIG_W 64u +#define FG_SIG_H 36u +static bool fg_create_sig(VkRenderer* r) { + r->fg_sig_supported = false; + r->fg_stage_slot = -1; + VkImageCreateInfo ic = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; + ic.imageType = VK_IMAGE_TYPE_2D; ic.format = VK_FORMAT_R8G8B8A8_UNORM; + ic.extent.width = FG_SIG_W; ic.extent.height = FG_SIG_H; ic.extent.depth = 1; + ic.mipLevels = 1; ic.arrayLayers = 1; ic.samples = VK_SAMPLE_COUNT_1_BIT; + ic.tiling = VK_IMAGE_TILING_OPTIMAL; + ic.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + ic.sharingMode = VK_SHARING_MODE_EXCLUSIVE; ic.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + if (vkCreateImage(r->device, &ic, NULL, &r->fg_sig_img) != VK_SUCCESS) return false; + VkMemoryRequirements mr; vkGetImageMemoryRequirements(r->device, r->fg_sig_img, &mr); + VkMemoryAllocateInfo ai = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; ai.allocationSize = mr.size; + ai.memoryTypeIndex = vkr_find_memory_type(r, mr.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + if (ai.memoryTypeIndex == UINT32_MAX) return false; + if (vkAllocateMemory(r->device, &ai, NULL, &r->fg_sig_img_mem) != VK_SUCCESS) return false; + vkBindImageMemory(r->device, r->fg_sig_img, r->fg_sig_img_mem, 0); + for (uint32_t i = 0; i < 3; i++) { + VkBufferCreateInfo bc = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + bc.size = (VkDeviceSize)FG_SIG_W * FG_SIG_H * 4; bc.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; + bc.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + if (vkCreateBuffer(r->device, &bc, NULL, &r->fg_sig_buf[i]) != VK_SUCCESS) return false; + VkMemoryRequirements br; vkGetBufferMemoryRequirements(r->device, r->fg_sig_buf[i], &br); + VkMemoryAllocateInfo bai = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; bai.allocationSize = br.size; + bai.memoryTypeIndex = vkr_find_memory_type(r, br.memoryTypeBits, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + if (bai.memoryTypeIndex == UINT32_MAX) return false; + if (vkAllocateMemory(r->device, &bai, NULL, &r->fg_sig_buf_mem[i]) != VK_SUCCESS) return false; + vkBindBufferMemory(r->device, r->fg_sig_buf[i], r->fg_sig_buf_mem[i], 0); + if (vkMapMemory(r->device, r->fg_sig_buf_mem[i], 0, VK_WHOLE_SIZE, 0, &r->fg_sig_ptr[i]) != VK_SUCCESS) return false; + memset(r->fg_sig_ptr[i], 0, (size_t)FG_SIG_W * FG_SIG_H * 4); + } + r->fg_sig_supported = true; + return true; +} + +static void fg_destroy_sig(VkRenderer* r) { + if (r->fg_sig_img) { vkDestroyImage(r->device, r->fg_sig_img, NULL); r->fg_sig_img = VK_NULL_HANDLE; } + if (r->fg_sig_img_mem) { vkFreeMemory(r->device, r->fg_sig_img_mem, NULL); r->fg_sig_img_mem = VK_NULL_HANDLE; } + for (uint32_t i = 0; i < 3; i++) { + if (r->fg_sig_buf[i]) { vkDestroyBuffer(r->device, r->fg_sig_buf[i], NULL); r->fg_sig_buf[i] = VK_NULL_HANDLE; } + if (r->fg_sig_buf_mem[i]) { vkFreeMemory(r->device, r->fg_sig_buf_mem[i], NULL); r->fg_sig_buf_mem[i] = VK_NULL_HANDLE; } + r->fg_sig_ptr[i] = NULL; + } + r->fg_sig_supported = false; + r->fg_stage_slot = -1; +} + +static void fg_record_sig(VkRenderer* r, VkCommandBuffer cmd, uint32_t slot) { + if (!r->fg_sig_supported) return; + vkr_image_barrier(cmd, r->fg_history[slot].image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); + vkr_image_barrier(cmd, r->fg_sig_img, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, VK_ACCESS_TRANSFER_WRITE_BIT); + VkImageBlit blit = {0}; + blit.srcSubresource = (VkImageSubresourceLayers){VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; + blit.srcOffsets[1] = (VkOffset3D){(int32_t)r->fg_history[slot].width, (int32_t)r->fg_history[slot].height, 1}; + blit.dstSubresource = (VkImageSubresourceLayers){VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; + blit.dstOffsets[1] = (VkOffset3D){(int32_t)FG_SIG_W, (int32_t)FG_SIG_H, 1}; + vkCmdBlitImage(cmd, r->fg_history[slot].image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + r->fg_sig_img, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR); + vkr_image_barrier(cmd, r->fg_sig_img, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); + VkBufferImageCopy cp = {0}; + cp.imageSubresource = (VkImageSubresourceLayers){VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; + cp.imageExtent = (VkExtent3D){FG_SIG_W, FG_SIG_H, 1}; + vkCmdCopyImageToBuffer(cmd, r->fg_sig_img, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + r->fg_sig_buf[slot], 1, &cp); + vkr_image_barrier(cmd, r->fg_history[slot].image, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT); +} + +// Count of signature pixels whose colour moved beyond the noise floor (a duplicate scores 0). +static double fg_sig_delta(VkRenderer* r, uint32_t a, uint32_t b) { + const uint8_t* pa = (const uint8_t*)r->fg_sig_ptr[a]; + const uint8_t* pb = (const uint8_t*)r->fg_sig_ptr[b]; + if (!pa || !pb) return 1e9; + uint32_t n = FG_SIG_W * FG_SIG_H, changed = 0; + for (uint32_t i = 0; i < n; i++) { + int dr = abs((int)pa[i*4+0] - (int)pb[i*4+0]); + int dg = abs((int)pa[i*4+1] - (int)pb[i*4+1]); + int db = abs((int)pa[i*4+2] - (int)pb[i*4+2]); + int m = dr > dg ? dr : dg; if (db > m) m = db; + if (m > 2) changed++; + } + return (double)changed; +} + +// --- Debug burst dump ----------------------------------------------------------------------------- +#define FG_DUMP_W 636u +#define FG_DUMP_H 1386u +#define FG_DUMP_N 10u +#define FG_DUMP_BUFS 10u +static uint32_t s_fgseq_last_curr = 0xFFFFFFFFu; + +static bool fg_create_dump(VkRenderer* r) { + r->fg_dump_supported = false; + r->fg_dump_armed = false; r->fg_dump_count = 0; r->fg_dump_seen_zero = false; + VkImageCreateInfo ic = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; + ic.imageType = VK_IMAGE_TYPE_2D; ic.format = VK_FORMAT_R8G8B8A8_UNORM; + ic.extent.width = FG_DUMP_W; ic.extent.height = FG_DUMP_H; ic.extent.depth = 1; + ic.mipLevels = 1; ic.arrayLayers = 1; ic.samples = VK_SAMPLE_COUNT_1_BIT; + ic.tiling = VK_IMAGE_TILING_OPTIMAL; + ic.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + ic.sharingMode = VK_SHARING_MODE_EXCLUSIVE; ic.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + if (vkCreateImage(r->device, &ic, NULL, &r->fg_dump_img) != VK_SUCCESS) return false; + VkMemoryRequirements mr; vkGetImageMemoryRequirements(r->device, r->fg_dump_img, &mr); + VkMemoryAllocateInfo ai = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; ai.allocationSize = mr.size; + ai.memoryTypeIndex = vkr_find_memory_type(r, mr.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + if (ai.memoryTypeIndex == UINT32_MAX) return false; + if (vkAllocateMemory(r->device, &ai, NULL, &r->fg_dump_img_mem) != VK_SUCCESS) return false; + vkBindImageMemory(r->device, r->fg_dump_img, r->fg_dump_img_mem, 0); + for (uint32_t i = 0; i < FG_DUMP_BUFS; i++) { + VkBufferCreateInfo bc = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + bc.size = (VkDeviceSize)FG_DUMP_W * FG_DUMP_H * 4; bc.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; + bc.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + if (vkCreateBuffer(r->device, &bc, NULL, &r->fg_dump_buf[i]) != VK_SUCCESS) return false; + VkMemoryRequirements br; vkGetBufferMemoryRequirements(r->device, r->fg_dump_buf[i], &br); + VkMemoryAllocateInfo bai = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; bai.allocationSize = br.size; + bai.memoryTypeIndex = vkr_find_memory_type(r, br.memoryTypeBits, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + if (bai.memoryTypeIndex == UINT32_MAX) return false; + if (vkAllocateMemory(r->device, &bai, NULL, &r->fg_dump_buf_mem[i]) != VK_SUCCESS) return false; + vkBindBufferMemory(r->device, r->fg_dump_buf[i], r->fg_dump_buf_mem[i], 0); + if (vkMapMemory(r->device, r->fg_dump_buf_mem[i], 0, VK_WHOLE_SIZE, 0, &r->fg_dump_ptr[i]) != VK_SUCCESS) return false; + memset(r->fg_dump_ptr[i], 0, (size_t)FG_DUMP_W * FG_DUMP_H * 4); + } + r->fg_dump_supported = true; + return true; +} + +static void fg_destroy_dump(VkRenderer* r) { + if (r->fg_dump_img) { vkDestroyImage(r->device, r->fg_dump_img, NULL); r->fg_dump_img = VK_NULL_HANDLE; } + if (r->fg_dump_img_mem) { vkFreeMemory(r->device, r->fg_dump_img_mem, NULL); r->fg_dump_img_mem = VK_NULL_HANDLE; } + for (uint32_t i = 0; i < FG_DUMP_BUFS; i++) { + if (r->fg_dump_buf[i]) { vkDestroyBuffer(r->device, r->fg_dump_buf[i], NULL); r->fg_dump_buf[i] = VK_NULL_HANDLE; } + if (r->fg_dump_buf_mem[i]) { vkFreeMemory(r->device, r->fg_dump_buf_mem[i], NULL); r->fg_dump_buf_mem[i] = VK_NULL_HANDLE; } + r->fg_dump_ptr[i] = NULL; + } + r->fg_dump_supported = false; + r->fg_dump_armed = false; r->fg_dump_count = 0; +} + +// Blit srcImg (full res, given layout) -> fg_dump_img (480x270) -> fg_dump_buf[bufIdx]. Restores srcImg. +static void fg_record_dump(VkRenderer* r, VkCommandBuffer cmd, VkImage srcImg, VkImageLayout srcLayout, uint32_t srcW, uint32_t srcH, uint32_t bufIdx, int rawF16) { + if (!r->fg_dump_supported || bufIdx >= FG_DUMP_BUFS) return; + r->fg_dump_w[bufIdx] = srcW; r->fg_dump_h[bufIdx] = srcH; + vkr_image_barrier(cmd, srcImg, + srcLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); + if (rawF16) { + uint32_t cw = srcW < 512u ? srcW : 512u, chh = srcH < 512u ? srcH : 512u; + VkBufferImageCopy rcp = {0}; + rcp.imageSubresource = (VkImageSubresourceLayers){VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; + rcp.imageExtent = (VkExtent3D){cw, chh, 1}; + vkCmdCopyImageToBuffer(cmd, srcImg, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, r->fg_dump_buf[bufIdx], 1, &rcp); + vkr_image_barrier(cmd, srcImg, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, srcLayout, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT); + return; + } + vkr_image_barrier(cmd, r->fg_dump_img, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, VK_ACCESS_TRANSFER_WRITE_BIT); + VkImageBlit blit = {0}; + blit.srcSubresource = (VkImageSubresourceLayers){VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; + blit.srcOffsets[1] = (VkOffset3D){(int32_t)srcW, (int32_t)srcH, 1}; + blit.dstSubresource = (VkImageSubresourceLayers){VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; + blit.dstOffsets[1] = (VkOffset3D){(int32_t)FG_DUMP_W, (int32_t)FG_DUMP_H, 1}; + vkCmdBlitImage(cmd, srcImg, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + r->fg_dump_img, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR); + vkr_image_barrier(cmd, r->fg_dump_img, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT); + VkBufferImageCopy cp = {0}; + cp.imageSubresource = (VkImageSubresourceLayers){VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; + cp.imageExtent = (VkExtent3D){FG_DUMP_W, FG_DUMP_H, 1}; + vkCmdCopyImageToBuffer(cmd, r->fg_dump_img, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + r->fg_dump_buf[bufIdx], 1, &cp); + vkr_image_barrier(cmd, srcImg, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, srcLayout, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT); +} + +// Edge-trigger: arm one burst on each 0->1 transition of debug.winnative.fgdump. +static void fg_dump_poll(VkRenderer* r) { + char val[8] = {0}; + __system_property_get("debug.winnative.fgdump", val); + if (val[0] == '0') r->fg_dump_seen_zero = true; + if (val[0] == '1' && r->fg_dump_seen_zero && !r->fg_dump_armed && r->fg_dump_count == 0) { + r->fg_dump_armed = true; r->fg_dump_seen_zero = false; + VK_LOGI("fgdump armed"); + } +} + +// Write the 10 host buffers to disk (raw RGBA8). Drain the queue first (one-shot debug path). +static void fg_dump_flush(VkRenderer* r) { + pthread_mutex_lock(&r->queue_mutex); + vkQueueWaitIdle(r->graphics_queue); + pthread_mutex_unlock(&r->queue_mutex); + static const char* dirs[2] = { + "/sdcard/Android/data/com.winnative.cmod/files", + "/data/data/com.winnative.cmod/files" + }; + const size_t sz = (size_t)FG_DUMP_W * FG_DUMP_H * 4; + const char* used = NULL; + for (uint32_t d = 0; d < 2 && !used; d++) { + char path[256]; + bool ok = true; + for (uint32_t i = 0; i < FG_DUMP_BUFS && ok; i++) { + snprintf(path, sizeof(path), "%s/fgdump_%02u.raw", dirs[d], i); + FILE* fp = fopen(path, "wb"); + if (!fp) { ok = false; break; } + ok = (fwrite(r->fg_dump_ptr[i], 1, sz, fp) == sz); + fclose(fp); + } + if (ok) { + snprintf(path, sizeof(path), "%s/fgdump_info.txt", dirs[d]); + FILE* fp = fopen(path, "w"); + if (fp) { + fprintf(fp, "blit %u %u RGBA8\n", FG_DUMP_W, FG_DUMP_H); + for (uint32_t i = 0; i < FG_DUMP_BUFS; i++) { + const char* k = r->fg_dump_kind[i] == 1 ? "prev" + : r->fg_dump_kind[i] == 2 ? "curr" + : r->fg_dump_kind[i] == 3 ? "flow" : "unused"; + fprintf(fp, "%02u %s %u %u %.4f\n", i, k, + r->fg_dump_w[i], r->fg_dump_h[i], (double)r->fg_dump_phase_of[i]); + } + fclose(fp); + } + used = dirs[d]; + } + } + if (used) VK_LOGI("fgdump written: %s/fgdump_NN.raw + fgdump_info.txt", used); + else VK_LOGE("fgdump write failed (no writable path)"); + r->fg_dump_armed = false; r->fg_dump_count = 0; +} + +#define FG_FLOW_MAX_EDGE 640u + +static void fg_flow_dims(const VkRenderer* r, uint32_t w, uint32_t h, uint32_t* outW, uint32_t* outH) { + float fs = r->fg_flow_scale >= 0.05f ? (r->fg_flow_scale <= 1.0f ? r->fg_flow_scale : 1.0f) : 0.25f; + uint32_t mw = (uint32_t)((float)w * fs); if (mw < 1u) mw = 1u; + uint32_t mh = (uint32_t)((float)h * fs); if (mh < 1u) mh = 1u; + uint32_t edge = mw > mh ? mw : mh; + if (edge > FG_FLOW_MAX_EDGE) { + float k = (float)FG_FLOW_MAX_EDGE / (float)edge; + mw = (uint32_t)((float)mw * k); if (mw < 1u) mw = 1u; + mh = (uint32_t)((float)mh * k); if (mh < 1u) mh = 1u; + } + *outW = mw; *outH = mh; +} + +static bool fg_create_resources(VkRenderer* r, uint32_t w, uint32_t h) { + VkSamplerCreateInfo si = {VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + si.magFilter = VK_FILTER_LINEAR; si.minFilter = VK_FILTER_LINEAR; + si.addressModeU = si.addressModeV = si.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + if (vkCreateSampler(r->device, &si, NULL, &r->fg_sampler) != VK_SUCCESS) goto fail; + + if (!fg_create_color_target(r, &r->fg_history[0], w, h)) goto fail; + if (!fg_create_color_target(r, &r->fg_history[1], w, h)) goto fail; + if (!fg_create_color_target(r, &r->fg_history[2], w, h)) goto fail; + { + uint32_t mw, mh; + fg_flow_dims(r, w, h, &mw, &mh); + uint32_t cw = (mw / 2) ? (mw / 2) : 1u, ch = (mh / 2) ? (mh / 2) : 1u; + r->fg_built_flow_scale = r->fg_flow_scale; + VK_LOGI("FG flow field %ux%u (scale %.2f, search range +-%d px)", + mw, mh, (double)r->fg_flow_scale, (int)(30.0f * (float)w / (float)mw)); + for (uint32_t mi = 0; mi < 3; mi++) { + if (!fg_create_motion(r, &r->fg_motion[mi], mw, mh)) goto fail; + if (!fg_create_motion(r, &r->fg_motion_fwd[mi], mw, mh)) goto fail; + if (!fg_create_motion(r, &r->fg_fixed[mi], mw, mh)) goto fail; + if (!fg_create_motion(r, &r->fg_coarse[mi], cw, ch)) goto fail; + if (!fg_create_motion(r, &r->fg_coarse_fwd[mi], cw, ch)) goto fail; + } + } + + if (r->fg_cnn_capable) { + if (!fg_create_cnn_resources(r, w, h)) { + VK_LOGW("CNN-FG resources unavailable; classical flow only"); + fg_destroy_cnn_resources(r); + r->fg_cnn_capable = false; + } + } + + memset(r->fg_slot_fence, 0, sizeof(r->fg_slot_fence)); + + for (uint32_t p = 0; p < 3; p++) { + r->fg_motion_set[p] = fg_alloc_set(r, r->pipelines.fg_motion_layout); + r->fg_motion_set_fwd[p] = fg_alloc_set(r, r->pipelines.fg_motion_layout); + r->fg_coarse_set[p] = fg_alloc_set(r, r->pipelines.fg_motion_layout); + r->fg_coarse_set_fwd[p] = fg_alloc_set(r, r->pipelines.fg_motion_layout); + r->fg_fix_set[p] = fg_alloc_set(r, r->pipelines.fg_motion_layout); + r->fg_interp_set[p] = fg_alloc_set(r, r->pipelines.fg_interp_layout); + r->fg_interp_set_deep[p] = fg_alloc_set(r, r->pipelines.fg_interp_layout); + if (!r->fg_motion_set[p] || !r->fg_motion_set_fwd[p] || !r->fg_coarse_set[p] || !r->fg_coarse_set_fwd[p] || !r->fg_fix_set[p] || !r->fg_interp_set[p] || !r->fg_interp_set_deep[p]) goto fail; + + VkImageView prevV = r->fg_history[(p + 2u) % 3u].view; + VkImageView currV = r->fg_history[p].view; + + VkDescriptorImageInfo sPrev = { r->fg_sampler, prevV, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }; + VkDescriptorImageInfo sCurr = { r->fg_sampler, currV, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }; + #define FG_MOTION_WRITE(SET, B0, B1, B2VIEW, B2LAYOUT, B3VIEW) do { \ + VkDescriptorImageInfo i0 = { r->fg_sampler, (B0), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }; \ + VkDescriptorImageInfo i1 = { r->fg_sampler, (B1), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }; \ + VkDescriptorImageInfo i2 = { r->fg_sampler, (B2VIEW), (B2LAYOUT) }; \ + VkDescriptorImageInfo i3 = { VK_NULL_HANDLE, (B3VIEW), VK_IMAGE_LAYOUT_GENERAL }; \ + VkWriteDescriptorSet w_[4] = {0}; \ + for (int b = 0; b < 4; b++) { w_[b].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; w_[b].dstSet = (SET); w_[b].dstBinding = (uint32_t)b; w_[b].descriptorCount = 1; } \ + w_[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; w_[0].pImageInfo = &i0; \ + w_[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; w_[1].pImageInfo = &i1; \ + w_[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; w_[2].pImageInfo = &i2; \ + w_[3].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; w_[3].pImageInfo = &i3; \ + vkUpdateDescriptorSets(r->device, 4, w_, 0, NULL); \ + } while (0) + // backward: coarse (prev,curr -> fg_coarse), fine (prev,curr,fg_coarse -> fg_motion) + FG_MOTION_WRITE(r->fg_coarse_set[p], prevV, currV, prevV, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, r->fg_coarse[p].view); + FG_MOTION_WRITE(r->fg_motion_set[p], prevV, currV, r->fg_coarse[p].view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, r->fg_motion[p].view); + // forward: prev/curr swapped, into fg_coarse_fwd / fg_motion_fwd + FG_MOTION_WRITE(r->fg_coarse_set_fwd[p], currV, prevV, currV, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, r->fg_coarse_fwd[p].view); + FG_MOTION_WRITE(r->fg_motion_set_fwd[p], currV, prevV, r->fg_coarse_fwd[p].view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, r->fg_motion_fwd[p].view); + FG_MOTION_WRITE(r->fg_fix_set[p], prevV, currV, r->fg_motion[p].view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, r->fg_fixed[p].view); + #undef FG_MOTION_WRITE + (void)sPrev; (void)sCurr; + + VkDescriptorImageInfo iPrev = { r->fg_sampler, prevV, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }; + VkDescriptorImageInfo iCurr = { r->fg_sampler, currV, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }; + VkDescriptorImageInfo iMv = { r->fg_sampler, r->fg_fixed[p].view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }; + VkDescriptorImageInfo iMvFwd = { r->fg_sampler, r->fg_motion_fwd[p].view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }; + VkWriteDescriptorSet iw_[4] = {0}; + for (int b = 0; b < 4; b++) { iw_[b].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; iw_[b].dstSet = r->fg_interp_set[p]; iw_[b].dstBinding = (uint32_t)b; iw_[b].descriptorCount = 1; iw_[b].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; } + iw_[0].pImageInfo = &iPrev; iw_[1].pImageInfo = &iCurr; iw_[2].pImageInfo = &iMv; iw_[3].pImageInfo = &iMv; + vkUpdateDescriptorSets(r->device, 4, iw_, 0, NULL); + + VkDescriptorImageInfo dPrev = { r->fg_sampler, prevV, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }; + VkDescriptorImageInfo dCurr = { r->fg_sampler, currV, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }; + VkWriteDescriptorSet dw_[4] = {0}; + for (int b = 0; b < 4; b++) { dw_[b].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; dw_[b].dstSet = r->fg_interp_set_deep[p]; dw_[b].dstBinding = (uint32_t)b; dw_[b].descriptorCount = 1; dw_[b].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; } + dw_[0].pImageInfo = &dPrev; dw_[1].pImageInfo = &dCurr; dw_[2].pImageInfo = &iMv; dw_[3].pImageInfo = &iMvFwd; + vkUpdateDescriptorSets(r->device, 4, dw_, 0, NULL); + } + + // Content-dedup signature resources (best-effort; if it fails, dedup just stays disabled). + if (!fg_create_sig(r)) { fg_destroy_sig(r); VK_LOGW("FG content-dedup unavailable; running without it"); } + // Debug burst-dump resources (best-effort; if it fails, dump stays disabled). + if (!fg_create_dump(r)) { fg_destroy_dump(r); VK_LOGW("FG debug dump unavailable"); } + r->fg_stage_slot = -1; + r->fg_last_promote_ns = 0; + + r->fg_dims.width = w; r->fg_dims.height = h; + r->fg_history_curr = 0; + r->fg_history_count = 0; + r->fg_motion_valid = false; // freshly created motion image — force a recompute before reuse + r->fg_motion_fwd_valid = false; + r->fg_built = true; + return true; + +fail: + VK_LOGE("fg_create_resources failed (%ux%u)", w, h); + fg_destroy_resources(r); + return false; +} + +// Build/rebuild FG images for the current swapchain extent. Caller holds render_mutex. +static bool fg_ensure_resources(VkRenderer* r) { + if (r->swapchain_extent.width == 0 || r->swapchain_extent.height == 0) return false; + if (!r->pipelines_built) return false; + { char fss[16] = {0}; __system_property_get("debug.winnative.fgflowscale", fss); + if (fss[0]) { float v = (float)atof(fss); if (v >= 0.05f && v <= 1.0f) r->fg_flow_scale = v; } } + if (r->fg_built + && r->fg_dims.width == r->swapchain_extent.width + && r->fg_dims.height == r->swapchain_extent.height + && fabsf(r->fg_built_flow_scale - r->fg_flow_scale) < 1e-4f) { + return true; + } + wait_inflight_frames(r); + if (r->fg_gen_started) { pthread_mutex_lock(&r->queue_mutex); vkQueueWaitIdle(r->graphics_queue); pthread_mutex_unlock(&r->queue_mutex); } + fg_destroy_resources(r); + return fg_create_resources(r, r->swapchain_extent.width, r->swapchain_extent.height); +} + +static void fg_restore_fence(VkRenderer* r, VkFrame* f) { + for (uint32_t i = 0; i < 3; i++) if (r->fg_slot_fence[i] == f->in_flight) r->fg_slot_fence[i] = VK_NULL_HANDLE; + vkDestroyFence(r->device, f->in_flight, NULL); + VkFenceCreateInfo rfi = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; + rfi.flags = VK_FENCE_CREATE_SIGNALED_BIT; + if (vkCreateFence(r->device, &rfi, NULL, &f->in_flight) != VK_SUCCESS) { + f->in_flight = VK_NULL_HANDLE; + VK_LOGE("Failed to recreate frame fence after FG submit failure"); + } +} + +// Diagnostic cadence counters (render-thread only). +static uint64_t g_fg_holds = 0; +static uint64_t g_fg_interp = 0; +static uint64_t g_fg_plast = 0; +static uint64_t g_fg_dropped = 0; + +#define FG_PRESENT_LEAD_NS 150000ull + +static uint64_t fg_compute_deadline(VkRenderer* r, uint64_t target) { + uint64_t now = now_monotonic_ns(); + uint64_t period = r->fg_present_period_ns ? r->fg_present_period_ns : r->refresh_duration_ns; + uint64_t deadline = target; + if (deadline == 0) { + if (period == 0) { r->fg_present_deadline_ns = 0; r->fg_present_target_ns = 0; return 0; } + deadline = r->fg_present_deadline_ns + period; + } + if (deadline < now) deadline = now; + if (period != 0 && deadline > now + 4u * period) deadline = now + period; + r->fg_present_deadline_ns = deadline; + r->fg_present_target_ns = deadline; + return deadline; +} + +static void fg_sleep_to_deadline(VkRenderer* r) { + if (r->active_present_mode == VK_PRESENT_MODE_FIFO_KHR) return; // FIFO already vsync-paces + uint64_t deadline = r->fg_present_target_ns ? r->fg_present_target_ns : r->fg_present_deadline_ns; + if (deadline == 0) return; + uint64_t target = deadline > FG_PRESENT_LEAD_NS ? deadline - FG_PRESENT_LEAD_NS : deadline; + struct timespec ts; + ts.tv_sec = (time_t)(target / 1000000000ull); + ts.tv_nsec = (long)(target % 1000000000ull); + while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL) == EINTR) {} +} + +// Drain past-present timing records and accumulate the real scan-out interval stats. +static void fg_collect_present_timing(VkRenderer* r) { + if (!r->ext_display_timing || !r->fnGetPastPresentationTiming) return; + VkPastPresentationTimingGOOGLE pt[16]; + uint32_t n = 16; + VkResult tr = r->fnGetPastPresentationTiming(r->device, r->swapchain, &n, pt); + if (tr != VK_SUCCESS && tr != VK_INCOMPLETE) return; + for (uint32_t i = 0; i < n; i++) { + uint64_t a = pt[i].actualPresentTime; + if (r->fg_t_last_ns != 0 && a > r->fg_t_last_ns) { + double ms = (double)(a - r->fg_t_last_ns) / 1.0e6; + if (ms > 0.5 && ms < 100.0) { + if (r->fg_t_count == 0 || ms < r->fg_t_min_ms) r->fg_t_min_ms = ms; + if (r->fg_t_count == 0 || ms > r->fg_t_max_ms) r->fg_t_max_ms = ms; + r->fg_t_sum_ms += ms; r->fg_t_sumsq_ms += ms * ms; r->fg_t_count++; + } + } + r->fg_t_last_ns = a; + } +} + +static bool fg_resolve_stage(VkRenderer* r, bool blocking) { + if (!r->fg_sig_supported || r->fg_stage_slot < 0) return false; + uint32_t sslot = (uint32_t)r->fg_stage_slot; + VkFence fence = r->fg_slot_fence[sslot]; + if (fence != VK_NULL_HANDLE) { + if (blocking) vkWaitForFences(r->device, 1, &fence, VK_TRUE, UINT64_MAX); + else if (vkGetFenceStatus(r->device, fence) != VK_SUCCESS) return false; + } + double delta = fg_sig_delta(r, sslot, r->fg_history_curr); + r->fg_last_sig_delta = delta; + uint64_t nowp = now_monotonic_ns(); + bool backstop = (r->fg_last_promote_ns != 0) && (nowp - r->fg_last_promote_ns > 100000000ull); + bool promote = delta > 0.0 || r->fg_history_count < 2u || backstop || r->fg_stage_force; + r->fg_stage_slot = -1; + r->fg_stage_force = false; + if (!promote) { r->fg_dup_dropped++; return false; } + r->fg_history_curr = sslot; + if (r->fg_history_count < 3) r->fg_history_count++; + r->fg_motion_valid = false; r->fg_motion_fwd_valid = false; + r->fg_last_promote_ns = nowp; + r->fg_promote_ns = nowp; + r->fg_distinct++; + r->fg_promote_seq++; + r->fg_promote_count++; + return true; +} + +static bool fg_submit(VkRenderer* r, FgMode mode, float phase, uint64_t target_ns, bool force_promote) { + if (!r->surface_ready || !r->swapchain) return false; + pthread_mutex_lock(&r->render_mutex); + if (!r->surface_ready || !r->swapchain || r->swapchain_image_count == 0 + || r->swapchain_extent.width == 0 || r->swapchain_extent.height == 0 + || !r->pipelines_built) { + pthread_mutex_unlock(&r->render_mutex); + return false; + } + + if (r->frame_index >= vkr_active_fif(r)) r->frame_index = 0; // live Buffering shrink + VkFrame* f = &r->frames[r->frame_index]; + uint64_t fw0 = now_monotonic_ns(); + vkWaitForFences(r->device, 1, &f->in_flight, VK_TRUE, UINT64_MAX); + { double fw = (double)(now_monotonic_ns() - fw0) / 1.0e6; + r->fg_fw_sum_ms += fw; if (fw > r->fg_fw_max_ms) r->fg_fw_max_ms = fw; r->fg_fw_n++; } + + if (!fg_ensure_resources(r)) { pthread_mutex_unlock(&r->render_mutex); return false; } + + VkCommandBufferBeginInfo bi = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + bi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + // -------- HOLD: render composited scene into history[curr'] (no present) -------- + if (mode == FG_MODE_HOLD) { + VkScene snap; + VkTexture** dead = NULL; uint32_t dead_count = 0; + pthread_mutex_lock(&r->scene_mutex); + snap = r->scene; + detach_graveyard_slot(r, r->graveyard_index, &dead, &dead_count); + pthread_mutex_unlock(&r->scene_mutex); + destroy_graveyard_textures(r, dead, dead_count); + + SceneTargets st = manage_scene_targets(r, &snap); + + bool promoted = fg_resolve_stage(r, true); + + // Step 2: composite the incoming frame into a staging slot (neither curr nor prev). + uint32_t stage = (r->fg_history_curr + 1u) % 3u; + VkFgImage* hist = &r->fg_history[stage]; + r->fg_cnn.featValid[stage] = false; + if (r->fg_slot_fence[stage] != VK_NULL_HANDLE) + vkWaitForFences(r->device, 1, &r->fg_slot_fence[stage], VK_TRUE, UINT64_MAX); + vkResetFences(r->device, 1, &f->in_flight); + vkBeginCommandBuffer(f->cmd, &bi); + record_scene_chain(r, f->cmd, &snap, st.has_effects, st.wants_sgsr1, + r->pipelines.offscreen_pass, hist->framebuffer, + hist->width, hist->height, true); + fg_record_sig(r, f->cmd, stage); + vkEndCommandBuffer(f->cmd); + + VkSubmitInfo si = {VK_STRUCTURE_TYPE_SUBMIT_INFO}; + si.commandBufferCount = 1; si.pCommandBuffers = &f->cmd; + pthread_mutex_lock(&r->queue_mutex); + VkResult sr = vkQueueSubmit(r->graphics_queue, 1, &si, f->in_flight); + pthread_mutex_unlock(&r->queue_mutex); + if (sr != VK_SUCCESS) { + VK_LOGE("fg HOLD submit -> %d", sr); + fg_restore_fence(r, f); + pthread_mutex_unlock(&r->render_mutex); + return false; + } + r->fg_slot_fence[stage] = f->in_flight; + if (r->fg_sig_supported) { + r->fg_stage_slot = (int32_t)stage; + r->fg_stage_force = force_promote; + } else { + r->fg_history_curr = stage; + if (r->fg_history_count < 3) r->fg_history_count++; + r->fg_motion_valid = false; r->fg_motion_fwd_valid = false; + r->fg_promote_ns = now_monotonic_ns(); + r->fg_promote_seq++; + r->fg_promote_count++; + } + (void)promoted; + g_fg_holds++; + pthread_mutex_unlock(&r->render_mutex); + r->frame_index = (r->frame_index + 1) % vkr_active_fif(r); + r->graveyard_index = (r->graveyard_index + 1) % (VK_FRAMES_IN_FLIGHT + 1); + return true; + } + + // -------- INTERP / PRESENT_LAST: acquire swapchain image, present -------- + bool deep = r->fg_deep_mode && (r->fg_history_count >= 2u); + bool do_interp = (mode == FG_MODE_INTERP) && (r->fg_history_count >= 2u); + + uint64_t acq_timeout = (do_interp && r->active_present_mode != VK_PRESENT_MODE_FIFO_KHR) + ? 0u : UINT64_MAX; + uint32_t image_index = 0; + VkResult acq = vkAcquireNextImageKHR(r->device, r->swapchain, acq_timeout, + f->image_available, VK_NULL_HANDLE, &image_index); + bool recreate_after_present = false; + if (acq == VK_NOT_READY || acq == VK_TIMEOUT) { + // No free image right now — drop this interpolated frame (not an error). + g_fg_dropped++; + pthread_mutex_unlock(&r->render_mutex); + return false; + } + if (acq == VK_ERROR_OUT_OF_DATE_KHR) { + r->surface_ready = false; + pthread_mutex_lock(&r->queue_mutex); vkQueueWaitIdle(r->graphics_queue); pthread_mutex_unlock(&r->queue_mutex); + fg_destroy_resources(r); + destroy_swapchain_resources(r); + r->surface_ready = create_swapchain(r, r->surface_extent.width, r->surface_extent.height); + pthread_mutex_unlock(&r->render_mutex); + return false; + } else if (acq == VK_SUBOPTIMAL_KHR) { + if (!r->ignore_suboptimal) recreate_after_present = true; + } else if (acq != VK_SUCCESS) { + VK_LOGE("fg acquire -> %d", acq); + pthread_mutex_unlock(&r->render_mutex); + return false; + } + VkSemaphore render_finished = r->swapchain_render_finished[image_index]; + vkResetFences(r->device, 1, &f->in_flight); + + uint32_t parity = r->fg_history_curr; + uint32_t curr_idx = parity; + uint32_t prev_idx = (parity + 2u) % 3u; + VkFgImage* curr = &r->fg_history[curr_idx]; + + // Advance the present deadline for the pacer (fg_sleep_to_deadline). + fg_compute_deadline(r, target_ns); + if (do_interp) { + if (r->fg_curr_arrival_ns != r->fg_dbg_last_curr) { + r->fg_dbg_done_n = r->fg_dbg_n; + for (uint32_t i = 0; i < r->fg_dbg_n && i < 8u; i++) r->fg_dbg_done[i] = r->fg_dbg_phase[i]; + r->fg_dbg_n = 0; + r->fg_dbg_last_curr = r->fg_curr_arrival_ns; + } + if (r->fg_dbg_n < 8u) r->fg_dbg_phase[r->fg_dbg_n++] = phase; + } + + vkBeginCommandBuffer(f->cmd, &bi); + + if (do_interp) { + VkFgImage* prev = &r->fg_history[prev_idx]; + // First interp of each pair recomputes the flow in-path (lazy); later interps reuse it. + bool compute_bwd = !r->fg_motion_valid; + bool compute_fwd = deep && !r->fg_extrapolate && !r->fg_motion_fwd_valid; + bool any_compute = compute_bwd || compute_fwd; + VkPipelineStageFlags hist_dst = any_compute + ? VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + vkr_image_barrier(f->cmd, prev->image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, hist_dst, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + vkr_image_barrier(f->cmd, curr->image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, hist_dst, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + if (compute_bwd) { + if (r->fg_use_cnn && r->fg_cnn_capable && r->fg_cnn.ready) { + cnn_flow_pass(r, f->cmd, parity, prev, curr, false, &r->fg_motion[parity]); + } else { + fg_motion_pass(r, f->cmd, r->fg_coarse_set[parity], &r->fg_coarse[parity], + r->fg_motion_set[parity], &r->fg_motion[parity], (float)r->fg_min_step); + } + r->fg_motion_valid = true; + } else { + vkr_image_barrier(f->cmd, r->fg_motion[parity].image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + } + if (compute_fwd) { + if (r->fg_use_cnn && r->fg_cnn_capable && r->fg_cnn.ready) { + cnn_flow_pass(r, f->cmd, parity, curr, prev, true, &r->fg_motion_fwd[parity]); + } else { + fg_motion_pass(r, f->cmd, r->fg_coarse_set_fwd[parity], &r->fg_coarse_fwd[parity], + r->fg_motion_set_fwd[parity], &r->fg_motion_fwd[parity], (float)r->fg_min_step); + } + r->fg_motion_fwd_valid = true; + } else if (deep && r->fg_motion_fwd_valid) { + // Forward flow reused. Re-establish its compute-write -> fragment-read dep. + vkr_image_barrier(f->cmd, r->fg_motion_fwd[parity].image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + } + } + + if (do_interp) fg_fix_pass(r, f->cmd, parity, phase); + + VkClearValue clear = {0}; + clear.color.float32[3] = 1.0f; + VkRenderPassBeginInfo rp = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + rp.renderPass = r->pipelines.swapchain_pass; + rp.framebuffer = r->swapchain_framebuffers[image_index]; + rp.renderArea.extent = r->swapchain_extent; + rp.clearValueCount = 1; rp.pClearValues = &clear; + vkCmdBeginRenderPass(f->cmd, &rp, VK_SUBPASS_CONTENTS_INLINE); + + VkViewport vp = {0, 0, (float)r->swapchain_extent.width, (float)r->swapchain_extent.height, 0.0f, 1.0f}; + VkRect2D scis = {{0, 0}, r->swapchain_extent}; + vkCmdSetViewport(f->cmd, 0, 1, &vp); + vkCmdSetScissor(f->cmd, 0, 1, &scis); + + if (do_interp) { + vkCmdBindPipeline(f->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, r->pipelines.fg_interp_pipeline); + bool use_fwd = deep && r->fg_motion_fwd_valid && !r->fg_extrapolate; + vkCmdBindDescriptorSets(f->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + r->pipelines.fg_interp_pipe_layout, 0, 1, + use_fwd ? &r->fg_interp_set_deep[parity] : &r->fg_interp_set[parity], 0, NULL); + struct { float resW, resH, phase, occLo, occHi, mode; } ipc; + ipc.resW = 2.0f * (float)r->fg_motion[parity].width; + ipc.resH = 2.0f * (float)r->fg_motion[parity].height; + ipc.phase = phase; ipc.occLo = r->fg_occ_lo; ipc.occHi = r->fg_occ_hi; + ipc.mode = (r->fg_extrapolate ? 2.0f : (use_fwd ? 1.0f : 0.0f)) + ((r->fg_use_cnn && r->fg_cnn_capable) ? 4.0f : 0.0f); + vkCmdPushConstants(f->cmd, r->pipelines.fg_interp_pipe_layout, VK_SHADER_STAGE_FRAGMENT_BIT, + 0, sizeof(ipc), &ipc); + vkCmdDraw(f->cmd, 3, 1, 0, 0); + } else { + // PRESENT_LAST or interp-not-ready fallback: blit the latest real frame. + vkCmdBindPipeline(f->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, r->pipelines.blit_pipeline); + vkCmdBindDescriptorSets(f->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + r->pipelines.effect_layout, 0, 1, &curr->blit_set, 0, NULL); + vkCmdDraw(f->cmd, 3, 1, 0, 0); + } + vkCmdEndRenderPass(f->cmd); + vkEndCommandBuffer(f->cmd); + + VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkSubmitInfo si = {VK_STRUCTURE_TYPE_SUBMIT_INFO}; + si.waitSemaphoreCount = 1; si.pWaitSemaphores = &f->image_available; + si.pWaitDstStageMask = &wait_stage; + si.commandBufferCount = 1; si.pCommandBuffers = &f->cmd; + si.signalSemaphoreCount = 1; si.pSignalSemaphores = &render_finished; + pthread_mutex_lock(&r->queue_mutex); + VkResult sr = vkQueueSubmit(r->graphics_queue, 1, &si, f->in_flight); + pthread_mutex_unlock(&r->queue_mutex); + if (sr != VK_SUCCESS) { + VK_LOGE("fg present submit -> %d", sr); + fg_restore_fence(r, f); + pthread_mutex_unlock(&r->render_mutex); + return false; + } + r->fg_slot_fence[curr_idx] = f->in_flight; + if (do_interp) r->fg_slot_fence[prev_idx] = f->in_flight; + + VkPresentInfoKHR pinfo = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR}; + pinfo.waitSemaphoreCount = 1; pinfo.pWaitSemaphores = &render_finished; + pinfo.swapchainCount = 1; pinfo.pSwapchains = &r->swapchain; pinfo.pImageIndices = &image_index; + VkPresentTimeGOOGLE ptg; + VkPresentTimesInfoGOOGLE pti; + if (r->ext_display_timing) { + ptg.presentID = ++r->fg_present_id; + ptg.desiredPresentTime = 0; + pti.sType = VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE; + pti.pNext = NULL; pti.swapchainCount = 1; pti.pTimes = &ptg; + pinfo.pNext = &pti; + } + fg_sleep_to_deadline(r); + pthread_mutex_lock(&r->queue_mutex); + VkResult pr = vkQueuePresentKHR(r->graphics_queue, &pinfo); + if (pr == VK_SUCCESS || pr == VK_SUBOPTIMAL_KHR) { + r->fg_present_count++; + if (do_interp) g_fg_interp++; else g_fg_plast++; + fg_collect_present_timing(r); + if (((g_fg_interp + g_fg_plast) % 120u) == 0u) { + double mean = r->fg_t_count ? r->fg_t_sum_ms / r->fg_t_count : 0.0; + double var = r->fg_t_count ? r->fg_t_sumsq_ms / r->fg_t_count - mean * mean : 0.0; + double sd = var > 0.0 ? sqrt(var) : 0.0; + VK_LOGI("FG cadence: holds=%llu interp=%llu presentLast=%llu dropped=%llu presents=%llu", + (unsigned long long)g_fg_holds, (unsigned long long)g_fg_interp, + (unsigned long long)g_fg_plast, (unsigned long long)g_fg_dropped, + (unsigned long long)r->fg_present_count); + VK_LOGI("FG timing: n=%u mean=%.2fms cov=%.0f%% min=%.2f max=%.2f [%s]", + r->fg_t_count, mean, mean > 0.0 ? 100.0 * sd / mean : 0.0, + r->fg_t_count ? r->fg_t_min_ms : 0.0, r->fg_t_count ? r->fg_t_max_ms : 0.0, + r->fg_deep_mode ? "quality" : "standard"); + VK_LOGI("FG fence-wait: n=%u mean=%.3fms max=%.3fms (GL-thread block on in_flight before present)", + r->fg_fw_n, r->fg_fw_n ? r->fg_fw_sum_ms / r->fg_fw_n : 0.0, r->fg_fw_max_ms); + r->fg_fw_sum_ms = 0.0; r->fg_fw_max_ms = 0.0; r->fg_fw_n = 0; + char pbuf[64]; int poff = 0; + for (uint32_t i = 0; i < r->fg_dbg_done_n && i < 8u; i++) + poff += snprintf(pbuf + poff, sizeof(pbuf) - (size_t)poff, "%.2f ", r->fg_dbg_done[i]); + if (poff == 0) pbuf[0] = '\0'; + VK_LOGI("FG phases[n=%u]: %s", r->fg_dbg_done_n, pbuf); + r->fg_t_count = 0; r->fg_t_sum_ms = 0.0; r->fg_t_sumsq_ms = 0.0; + } + } + pthread_mutex_unlock(&r->queue_mutex); + + bool present_suboptimal = (pr == VK_SUBOPTIMAL_KHR) && !r->ignore_suboptimal; + if (recreate_after_present || pr == VK_ERROR_OUT_OF_DATE_KHR || present_suboptimal) { + r->surface_ready = false; + pthread_mutex_lock(&r->queue_mutex); vkQueueWaitIdle(r->graphics_queue); pthread_mutex_unlock(&r->queue_mutex); + fg_destroy_resources(r); + destroy_swapchain_resources(r); + r->surface_ready = create_swapchain(r, r->surface_extent.width, r->surface_extent.height); + } + pthread_mutex_unlock(&r->render_mutex); + r->frame_index = (r->frame_index + 1) % vkr_active_fif(r); + return true; +} + +// ============================================================ +// FG generation worker (consumer): owns the swapchain present path while FG is on +// ============================================================ + +// Pace to a specific job deadline (no-op under FIFO, where the blocking acquire already vsync-paces). +static void fg_sleep_to(VkRenderer* r, uint64_t deadline) { + (void)r; + if (deadline == 0) return; + uint64_t target = deadline > FG_PRESENT_LEAD_NS ? deadline - FG_PRESENT_LEAD_NS : deadline; + struct timespec ts; + ts.tv_sec = (time_t)(target / 1000000000ull); + ts.tv_nsec = (long)(target % 1000000000ull); + while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL) == EINTR) {} +} + +static void fg_worker_recreate(VkRenderer* r) { + pthread_mutex_lock(&r->render_mutex); + r->surface_ready = false; + pthread_mutex_lock(&r->queue_mutex); vkQueueWaitIdle(r->graphics_queue); pthread_mutex_unlock(&r->queue_mutex); + fg_destroy_resources(r); + destroy_swapchain_resources(r); + r->surface_ready = create_swapchain(r, r->surface_extent.width, r->surface_extent.height); + r->fg_swapchain_gen++; + pthread_mutex_unlock(&r->render_mutex); +} + +typedef struct FgPending { + bool valid; + bool need_recreate; + uint32_t image_index; + VkSemaphore render_finished; + VkSwapchainKHR swapchain; + uint64_t deadline_ns; + bool recreate_after; + bool do_interp; +} FgPending; + +static FgPending fg_worker_generate(VkRenderer* r, const FgJob* job) { + FgPending p = {0}; + if (!r->surface_ready || !r->swapchain || r->swapchain_image_count == 0 + || r->swapchain_extent.width == 0u || !r->pipelines_built) { g_fg_dropped++; return p; } + + if (job->mode == FG_MODE_FLOW) { + if (!(r->fg_use_cnn && r->fg_cnn_capable && r->fg_cnn.ready)) return p; + VkFrame* ff = &r->fg_worker_frames[r->fg_worker_index]; + r->fg_worker_index = (r->fg_worker_index + 1u) % 3u; + if (ff->in_flight) vkWaitForFences(r->device, 1, &ff->in_flight, VK_TRUE, UINT64_MAX); + VkCommandBufferBeginInfo fbi = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + fbi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + pthread_mutex_lock(&r->render_mutex); + if (!r->fg_built || r->fg_history_count < 2u || r->fg_motion_valid + || (uint32_t)(r->fg_promote_seq - job->seq) >= 2u) { + pthread_mutex_unlock(&r->render_mutex); return p; + } + uint32_t fcurr = job->curr_idx, fprev = job->prev_idx; + VkFgImage* fc = &r->fg_history[fcurr]; + VkFgImage* fp = &r->fg_history[fprev]; + bool fdeep = job->deep && !r->fg_extrapolate; + vkResetFences(r->device, 1, &ff->in_flight); + vkBeginCommandBuffer(ff->cmd, &fbi); + vkr_image_barrier(ff->cmd, fp->image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + vkr_image_barrier(ff->cmd, fc->image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + cnn_flow_pass(r, ff->cmd, fcurr, fp, fc, false, &r->fg_motion[fcurr]); + r->fg_motion_valid = true; + if (fdeep) { + cnn_flow_pass(r, ff->cmd, fcurr, fc, fp, true, &r->fg_motion_fwd[fcurr]); + r->fg_motion_fwd_valid = true; + } + vkEndCommandBuffer(ff->cmd); + VkSubmitInfo fsi = {VK_STRUCTURE_TYPE_SUBMIT_INFO}; + fsi.commandBufferCount = 1; fsi.pCommandBuffers = &ff->cmd; + pthread_mutex_lock(&r->queue_mutex); + VkResult fsr = vkQueueSubmit(r->graphics_queue, 1, &fsi, ff->in_flight); + pthread_mutex_unlock(&r->queue_mutex); + if (fsr != VK_SUCCESS) { + vkDestroyFence(r->device, ff->in_flight, NULL); + VkFenceCreateInfo rfi = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; rfi.flags = VK_FENCE_CREATE_SIGNALED_BIT; + vkCreateFence(r->device, &rfi, NULL, &ff->in_flight); + r->fg_motion_valid = false; r->fg_motion_fwd_valid = false; + } else { + r->fg_slot_fence[fcurr] = ff->in_flight; + r->fg_slot_fence[fprev] = ff->in_flight; + } + pthread_mutex_unlock(&r->render_mutex); + return p; + } + + // Debug burst-dump: a completed burst (all submits fenced by now) gets written out and disarmed. + if (r->fg_dump_supported && r->fg_dump_armed && r->fg_dump_count >= FG_DUMP_N) fg_dump_flush(r); + + uint32_t genslot = r->fg_worker_index; + VkFrame* f = &r->fg_worker_frames[r->fg_worker_index]; + r->fg_worker_index = (r->fg_worker_index + 1u) % 3u; + if (f->in_flight) vkWaitForFences(r->device, 1, &f->in_flight, VK_TRUE, UINT64_MAX); + + bool want_interp = (job->mode == FG_MODE_INTERP); + uint64_t disp_ns = r->fg_display_period_ns ? r->fg_display_period_ns : 16666667ull; + uint64_t acq_timeout = (want_interp && r->active_present_mode != VK_PRESENT_MODE_FIFO_KHR) + ? 2u * disp_ns : 100000000ull; + uint32_t image_index = 0; + VkResult acq = vkAcquireNextImageKHR(r->device, r->swapchain, acq_timeout, + f->image_available, VK_NULL_HANDLE, &image_index); + if (acq == VK_NOT_READY || acq == VK_TIMEOUT) { g_fg_dropped++; return p; } + if (acq == VK_ERROR_OUT_OF_DATE_KHR) { p.need_recreate = true; return p; } + bool recreate_after_present = (acq == VK_SUBOPTIMAL_KHR) && !r->ignore_suboptimal; + if (acq != VK_SUCCESS && acq != VK_SUBOPTIMAL_KHR) { VK_LOGE("fg-gen acquire -> %d", acq); g_fg_dropped++; return p; } + + VkSemaphore render_finished = r->swapchain_render_finished[image_index]; + VkCommandBufferBeginInfo bi = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + bi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + pthread_mutex_lock(&r->render_mutex); + if (!r->fg_built) { pthread_mutex_unlock(&r->render_mutex); g_fg_dropped++; return p; } + bool stale = (uint32_t)(r->fg_promote_seq - job->seq) >= 2u; + bool do_interp = want_interp && !stale && r->fg_history_count >= 2u; + uint32_t curr_idx = stale ? r->fg_history_curr : job->curr_idx; + uint32_t prev_idx = stale ? ((r->fg_history_curr + 2u) % 3u) : job->prev_idx; + bool deep = job->deep && do_interp; + uint32_t parity = curr_idx; + VkFgImage* curr = &r->fg_history[curr_idx]; + + vkResetFences(r->device, 1, &f->in_flight); + vkBeginCommandBuffer(f->cmd, &bi); + + if (do_interp) { + VkFgImage* prev = &r->fg_history[prev_idx]; + bool compute_fwd = deep && !r->fg_extrapolate; // worker recomputes flow each generated frame + VkPipelineStageFlags hist_dst = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + vkr_image_barrier(f->cmd, prev->image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, hist_dst, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + vkr_image_barrier(f->cmd, curr->image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, hist_dst, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + { char syn[16] = {0}; __system_property_get("debug.winnative.fgsynth", syn); // controlled-motion harness + int synN = syn[0] ? atoi(syn) : 0; + if (synN != 0 && prev->storeView && curr->storeView) { + char patS[8] = {0}; __system_property_get("debug.winnative.fgpat", patS); + int pat = patS[0] ? atoi(patS) : 0; + if (pat) { + fg_synth_shift(r, f->cmd, curr, prev, 0.0f, 1); // prev = noise pattern + fg_synth_shift(r, f->cmd, prev, curr, (float)synN, 1); // curr = pattern shifted right by N + } else { + fg_synth_shift(r, f->cmd, prev, curr, (float)synN, 0); // curr = real prev shifted by N + } + r->fg_cnn.featValid[curr_idx] = false; + r->fg_cnn.featValid[prev_idx] = false; + r->fg_motion_valid = false; r->fg_motion_fwd_valid = false; // recompute flow on the shifted input + } } + if (r->fg_use_cnn && r->fg_cnn_capable && r->fg_cnn.ready) { + if (!r->fg_motion_valid) { + cnn_flow_pass(r, f->cmd, parity, prev, curr, false, &r->fg_motion[parity]); + r->fg_motion_valid = true; + } else { + vkr_image_barrier(f->cmd, r->fg_motion[parity].image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + } + if (compute_fwd) { + if (!r->fg_motion_fwd_valid) { + cnn_flow_pass(r, f->cmd, parity, curr, prev, true, &r->fg_motion_fwd[parity]); + r->fg_motion_fwd_valid = true; + } else { + vkr_image_barrier(f->cmd, r->fg_motion_fwd[parity].image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + } + } + } else { + if (!r->fg_motion_valid) { + fg_motion_pass(r, f->cmd, r->fg_coarse_set[parity], &r->fg_coarse[parity], + r->fg_motion_set[parity], &r->fg_motion[parity], (float)r->fg_min_step); + r->fg_motion_valid = true; + } else { + vkr_image_barrier(f->cmd, r->fg_motion[parity].image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + } + if (compute_fwd) { + if (!r->fg_motion_fwd_valid) { + fg_motion_pass(r, f->cmd, r->fg_coarse_set_fwd[parity], &r->fg_coarse_fwd[parity], + r->fg_motion_set_fwd[parity], &r->fg_motion_fwd[parity], (float)r->fg_min_step); + r->fg_motion_fwd_valid = true; + } else { + vkr_image_barrier(f->cmd, r->fg_motion_fwd[parity].image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT); + } + } + } + } + + if (do_interp) { + fg_dump_poll(r); + if (r->fg_dump_supported && r->fg_dump_armed && r->fg_dump_count + 3u <= FG_DUMP_N + && curr_idx != s_fgseq_last_curr) { + s_fgseq_last_curr = curr_idx; + uint32_t b0 = r->fg_dump_count; + r->fg_dump_kind[b0] = 1; r->fg_dump_phase_of[b0] = 0.0f; + fg_record_dump(r, f->cmd, r->fg_history[prev_idx].image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + r->fg_dims.width, r->fg_dims.height, b0, 0); + r->fg_dump_kind[b0+1] = 2; r->fg_dump_phase_of[b0+1] = 1.0f; + fg_record_dump(r, f->cmd, curr->image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + r->fg_dims.width, r->fg_dims.height, b0+1, 0); + r->fg_dump_kind[b0+2] = 3; r->fg_dump_phase_of[b0+2] = job->phase; + fg_record_dump(r, f->cmd, r->fg_motion[parity].image, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + r->fg_motion[parity].width, r->fg_motion[parity].height, b0+2, 1); + VK_LOGI("fgseq[%u..%u] prev/curr/flow (phase=%.3f flow=%ux%u prev=%u curr=%u)", + b0, b0+2, (double)job->phase, + r->fg_motion[parity].width, r->fg_motion[parity].height, prev_idx, curr_idx); + r->fg_dump_count += 3u; + } + } + + bool gen_present = false; + if (do_interp && r->fg_use_cnn && r->fg_cnn_capable && r->fg_cnn.genReady && r->fg_cnn_gen + && deep && !r->fg_extrapolate && r->fg_motion_fwd_valid) { + cnn_generate_frame(r, f->cmd, parity, genslot, + r->fg_history[prev_idx].view, curr->view, job->phase); + gen_present = true; + + fg_dump_poll(r); + float fg_dump_prevph = r->fg_dump_last_phase; + r->fg_dump_last_phase = job->phase; + int synDump = 0; { char s2[16] = {0}; __system_property_get("debug.winnative.fgsynth", s2); synDump = s2[0] ? atoi(s2) : 0; } + int rawm = synDump ? 1 : 0; // full-res 1:1 crop under the harness (no downscale confound) + if (r->fg_dump_supported && r->fg_dump_armed && r->fg_dump_count < FG_DUMP_N + && !(r->fg_dump_count == 0 && job->phase > fg_dump_prevph + 0.01f)) { + if (r->fg_dump_count == 0) s_fgseq_last_curr = 0xFFFFFFFFu; + if (curr_idx != s_fgseq_last_curr && r->fg_dump_count < FG_DUMP_N) { + fg_record_dump(r, f->cmd, r->fg_history[prev_idx].image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, r->fg_dims.width, r->fg_dims.height, r->fg_dump_count, rawm); + VK_LOGI("fgseq[%u] REAL (prev=%u curr=%u)", r->fg_dump_count, prev_idx, curr_idx); + r->fg_dump_count++; + s_fgseq_last_curr = curr_idx; + } + if (r->fg_dump_count < FG_DUMP_N) { + fg_record_dump(r, f->cmd, r->fg_cnn.gen[genslot].image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, r->fg_dims.width, r->fg_dims.height, r->fg_dump_count, rawm); + VK_LOGI("fgseq[%u] GENERATED (phase=%.3f prev=%u curr=%u)", r->fg_dump_count, job->phase, prev_idx, curr_idx); + r->fg_dump_count++; + } + if (synDump && r->fg_dump_count < FG_DUMP_N) { // harness: raw F16 flow field + fg_record_dump(r, f->cmd, r->fg_motion[parity].image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, r->fg_motion[parity].width, r->fg_motion[parity].height, r->fg_dump_count, 1); + VK_LOGI("fgseq[%u] FLOW (flowres=%ux%u)", r->fg_dump_count, r->fg_motion[parity].width, r->fg_motion[parity].height); + r->fg_dump_count++; + } + } + } + + if (do_interp && !gen_present) fg_fix_pass(r, f->cmd, parity, job->phase); + + VkClearValue clear = {0}; + clear.color.float32[3] = 1.0f; + VkRenderPassBeginInfo rp = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; + rp.renderPass = r->pipelines.swapchain_pass; + rp.framebuffer = r->swapchain_framebuffers[image_index]; + rp.renderArea.extent = r->swapchain_extent; + rp.clearValueCount = 1; rp.pClearValues = &clear; + vkCmdBeginRenderPass(f->cmd, &rp, VK_SUBPASS_CONTENTS_INLINE); + VkViewport vp = {0, 0, (float)r->swapchain_extent.width, (float)r->swapchain_extent.height, 0.0f, 1.0f}; + VkRect2D scis = {{0, 0}, r->swapchain_extent}; + vkCmdSetViewport(f->cmd, 0, 1, &vp); + vkCmdSetScissor(f->cmd, 0, 1, &scis); + if (gen_present) { + // CNN SELECT result: present gen[genslot] via the blit pipeline (mirror PRESENT_LAST). + vkCmdBindPipeline(f->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, r->pipelines.blit_pipeline); + vkCmdBindDescriptorSets(f->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + r->pipelines.effect_layout, 0, 1, &r->fg_cnn.genSet[genslot], 0, NULL); + vkCmdDraw(f->cmd, 3, 1, 0, 0); + } else if (do_interp) { + vkCmdBindPipeline(f->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, r->pipelines.fg_interp_pipeline); + bool use_fwd = deep && !r->fg_extrapolate; + vkCmdBindDescriptorSets(f->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + r->pipelines.fg_interp_pipe_layout, 0, 1, + use_fwd ? &r->fg_interp_set_deep[parity] : &r->fg_interp_set[parity], 0, NULL); + struct { float resW, resH, phase, occLo, occHi, mode; } ipc; + ipc.resW = 2.0f * (float)r->fg_motion[parity].width; + ipc.resH = 2.0f * (float)r->fg_motion[parity].height; + ipc.phase = job->phase; ipc.occLo = r->fg_occ_lo; ipc.occHi = r->fg_occ_hi; + ipc.mode = (r->fg_extrapolate ? 2.0f : (use_fwd ? 1.0f : 0.0f)) + ((r->fg_use_cnn && r->fg_cnn_capable) ? 4.0f : 0.0f); + vkCmdPushConstants(f->cmd, r->pipelines.fg_interp_pipe_layout, VK_SHADER_STAGE_FRAGMENT_BIT, + 0, sizeof(ipc), &ipc); + vkCmdDraw(f->cmd, 3, 1, 0, 0); + } else { + vkCmdBindPipeline(f->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, r->pipelines.blit_pipeline); + vkCmdBindDescriptorSets(f->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + r->pipelines.effect_layout, 0, 1, &curr->blit_set, 0, NULL); + vkCmdDraw(f->cmd, 3, 1, 0, 0); + } + vkCmdEndRenderPass(f->cmd); + vkEndCommandBuffer(f->cmd); + + VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkSubmitInfo si = {VK_STRUCTURE_TYPE_SUBMIT_INFO}; + si.waitSemaphoreCount = 1; si.pWaitSemaphores = &f->image_available; + si.pWaitDstStageMask = &wait_stage; + si.commandBufferCount = 1; si.pCommandBuffers = &f->cmd; + si.signalSemaphoreCount = 1; si.pSignalSemaphores = &render_finished; + pthread_mutex_lock(&r->queue_mutex); + VkResult sr = vkQueueSubmit(r->graphics_queue, 1, &si, f->in_flight); + pthread_mutex_unlock(&r->queue_mutex); + if (sr != VK_SUCCESS) { + VK_LOGE("fg-gen submit -> %d", sr); + vkDestroyFence(r->device, f->in_flight, NULL); // submit didn't signal; re-arm signaled + VkFenceCreateInfo rfi = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; rfi.flags = VK_FENCE_CREATE_SIGNALED_BIT; + vkCreateFence(r->device, &rfi, NULL, &f->in_flight); + pthread_mutex_unlock(&r->render_mutex); + return p; + } + r->fg_slot_fence[curr_idx] = f->in_flight; + if (do_interp) r->fg_slot_fence[prev_idx] = f->in_flight; + VkSwapchainKHR swapchain = r->swapchain; + pthread_mutex_unlock(&r->render_mutex); + + p.valid = true; + p.image_index = image_index; + p.render_finished = render_finished; + p.swapchain = swapchain; + p.deadline_ns = job->deadline_ns; + p.recreate_after = recreate_after_present; + p.do_interp = do_interp; + return p; +} + +// Pace to the deadline and present a generated frame. Returns true when the swapchain needs recreating. +static bool fg_worker_do_present(VkRenderer* r, const FgPending* p) { + fg_sleep_to(r, p->deadline_ns); + + VkPresentInfoKHR pinfo = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR}; + pinfo.waitSemaphoreCount = 1; pinfo.pWaitSemaphores = &p->render_finished; + pinfo.swapchainCount = 1; pinfo.pSwapchains = &p->swapchain; pinfo.pImageIndices = &p->image_index; + VkPresentTimeGOOGLE ptg; VkPresentTimesInfoGOOGLE pti; + if (r->ext_display_timing) { + // Request the computed present instant so a panel that honours display-timing places it (CLOCK_MONOTONIC ns). + ptg.presentID = ++r->fg_present_id; ptg.desiredPresentTime = p->deadline_ns; + pti.sType = VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE; + pti.pNext = NULL; pti.swapchainCount = 1; pti.pTimes = &ptg; + pinfo.pNext = &pti; + } + pthread_mutex_lock(&r->queue_mutex); + VkResult pr = vkQueuePresentKHR(r->graphics_queue, &pinfo); + if (pr == VK_SUCCESS || pr == VK_SUBOPTIMAL_KHR) { + r->fg_present_count++; + if (p->do_interp) g_fg_interp++; else g_fg_plast++; + fg_collect_present_timing(r); + if (((g_fg_interp + g_fg_plast) % 120u) == 0u) { + double mean = r->fg_t_count ? r->fg_t_sum_ms / r->fg_t_count : 0.0; + double var = r->fg_t_count ? r->fg_t_sumsq_ms / r->fg_t_count - mean * mean : 0.0; + double sd = var > 0.0 ? sqrt(var) : 0.0; + VK_LOGI("FG cadence: holds=%llu interp=%llu presentLast=%llu dropped=%llu presents=%llu", + (unsigned long long)g_fg_holds, (unsigned long long)g_fg_interp, + (unsigned long long)g_fg_plast, (unsigned long long)g_fg_dropped, + (unsigned long long)r->fg_present_count); + VK_LOGI("FG timing: n=%u mean=%.2fms cov=%.0f%% min=%.2f max=%.2f [%s]", + r->fg_t_count, mean, mean > 0.0 ? 100.0 * sd / mean : 0.0, + r->fg_t_count ? r->fg_t_min_ms : 0.0, r->fg_t_count ? r->fg_t_max_ms : 0.0, + r->fg_deep_mode ? "quality" : "standard"); + VK_LOGI("FG fence-wait: n=%u mean=%.3fms max=%.3fms (GL-thread block on in_flight before present)", + r->fg_fw_n, r->fg_fw_n ? r->fg_fw_sum_ms / r->fg_fw_n : 0.0, r->fg_fw_max_ms); + r->fg_fw_sum_ms = 0.0; r->fg_fw_max_ms = 0.0; r->fg_fw_n = 0; + r->fg_t_count = 0; r->fg_t_sum_ms = 0.0; r->fg_t_sumsq_ms = 0.0; + } + } + pthread_mutex_unlock(&r->queue_mutex); + + return p->recreate_after || pr == VK_ERROR_OUT_OF_DATE_KHR + || (pr == VK_SUBOPTIMAL_KHR && !r->ignore_suboptimal); +} + +// Producer (GL thread): snapshot the cadence decision into a job + enqueue + wake the worker. O(1). +static void fg_enqueue(VkRenderer* r, uint8_t mode, float phase, uint64_t target_ns) { + pthread_mutex_lock(&r->render_mutex); + if (!r->fg_gen_started) { pthread_mutex_unlock(&r->render_mutex); return; } // re-check UNDER the lock: stop sets it false here too, so no sem_post races sem_destroy + uint32_t curr = r->fg_history_curr; + FgJob job; + job.mode = mode; + // CNN generate needs the forward field -> force deep on the CNN path. + job.deep = ((r->fg_deep_mode || (r->fg_use_cnn && r->fg_cnn_capable)) && r->fg_history_count >= 2u) ? 1u : 0u; + job.phase = phase; + job.curr_idx = curr; + job.prev_idx = (curr + 2u) % 3u; + job.seq = r->fg_promote_seq; + fg_compute_deadline(r, target_ns); + job.deadline_ns = r->fg_present_target_ns ? r->fg_present_target_ns : r->fg_present_deadline_ns; + + if (mode == FG_MODE_INTERP && r->fg_use_cnn && r->fg_cnn_capable + && r->fg_history_count >= 2u && r->fg_promote_seq != r->fg_cnn_flow_seq) { + uint32_t ftail = r->fg_job_tail; + uint32_t fnext = (ftail + 1u) % FG_JOB_RING; + if (fnext != r->fg_job_head) { + r->fg_cnn_flow_seq = r->fg_promote_seq; + FgJob fj = job; + fj.mode = (uint8_t)FG_MODE_FLOW; + fj.deadline_ns = 0u; + r->fg_job_ring[ftail] = fj; + __atomic_store_n(&r->fg_job_tail, fnext, __ATOMIC_RELEASE); + sem_post(&r->fg_gen_sem); + } + } + + uint32_t tail = r->fg_job_tail; + uint32_t next = (tail + 1u) % FG_JOB_RING; + if (next == r->fg_job_head) { + pthread_mutex_unlock(&r->render_mutex); + g_fg_dropped++; + return; + } + r->fg_job_ring[tail] = job; + __atomic_store_n(&r->fg_job_tail, next, __ATOMIC_RELEASE); + sem_post(&r->fg_gen_sem); + pthread_mutex_unlock(&r->render_mutex); +} + +static void* fg_gen_loop(void* arg) { + VkRenderer* r = (VkRenderer*)arg; + prctl(PR_SET_NAME, "fg-gen", 0, 0, 0); + setpriority(PRIO_PROCESS, 0, -8); + FgPending pending = {0}; + while (r->fg_gen_running) { + if (pending.valid) { + bool recreate = fg_worker_do_present(r, &pending); + pending.valid = false; + if (recreate) fg_worker_recreate(r); + } + if (!r->fg_gen_running) break; + if (sem_wait(&r->fg_gen_sem) != 0) continue; + if (!r->fg_gen_running) break; + + uint32_t head = r->fg_job_head; + if (head == __atomic_load_n(&r->fg_job_tail, __ATOMIC_ACQUIRE)) continue; + FgJob job = r->fg_job_ring[head]; + __atomic_store_n(&r->fg_job_head, (head + 1u) % FG_JOB_RING, __ATOMIC_RELEASE); + // drop-late: skip an INTERP whose deadline already passed by >1 vsync; never drop a PRESENT_LAST. + uint64_t period = r->fg_display_period_ns ? r->fg_display_period_ns : 16666667ull; + if (job.mode == FG_MODE_INTERP && job.deadline_ns != 0u + && now_monotonic_ns() > job.deadline_ns + period) { + g_fg_dropped++; + continue; + } + pending = fg_worker_generate(r, &job); + if (pending.need_recreate) { + fg_worker_recreate(r); + pending.valid = false; + } + } + if (pending.valid) fg_worker_do_present(r, &pending); // flush the trailing frame on stop + return NULL; +} + +static void fg_worker_start(VkRenderer* r) { + if (r->fg_gen_started) return; + if (!fg_worker_create_resources(r)) { VK_LOGE("fg-gen worker resource create failed"); return; } + sem_init(&r->fg_gen_sem, 0, 0); + r->fg_job_head = r->fg_job_tail = 0; + r->fg_gen_running = 1; + if (pthread_create(&r->fg_gen_thread, NULL, fg_gen_loop, r) != 0) { + r->fg_gen_running = 0; sem_destroy(&r->fg_gen_sem); + fg_worker_destroy_resources(r); + VK_LOGE("fg-gen pthread_create failed"); + return; + } + r->fg_gen_started = true; + VK_LOGI("fg-gen worker started"); +} + +static void fg_worker_stop(VkRenderer* r) { + if (!r->fg_gen_started) return; + pthread_mutex_lock(&r->render_mutex); // serialize with fg_enqueue + r->fg_gen_started = false; + r->fg_gen_running = 0; + pthread_mutex_unlock(&r->render_mutex); + sem_post(&r->fg_gen_sem); + pthread_join(r->fg_gen_thread, NULL); + sem_destroy(&r->fg_gen_sem); + pthread_mutex_lock(&r->queue_mutex); vkQueueWaitIdle(r->graphics_queue); pthread_mutex_unlock(&r->queue_mutex); + fg_worker_destroy_resources(r); + VK_LOGI("fg-gen worker stopped"); +} + +// ============================================================ +// JNI entry points +// ============================================================ + +#define JNI_FN(name) Java_com_winlator_cmod_runtime_display_renderer_VulkanRenderer_##name + +static JavaVM* g_pump_jvm = NULL; +static jobject g_pump_renderer = NULL; +static jmethodID g_pump_tick = NULL; +static pthread_t g_pump_thread; +static volatile int g_pump_running = 0; +static AChoreographer* g_pump_chor = NULL; + +static void fg_pump_frame(long frameTimeNanos, void* data) { + (void)data; + if (!g_pump_running) return; + JNIEnv* env = NULL; + if ((*g_pump_jvm)->GetEnv(g_pump_jvm, (void**)&env, JNI_VERSION_1_6) == JNI_OK + && env && g_pump_renderer && g_pump_tick) { + (*env)->CallVoidMethod(env, g_pump_renderer, g_pump_tick, (jlong)frameTimeNanos); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + } + if (g_pump_running && g_pump_chor) + AChoreographer_postFrameCallback(g_pump_chor, fg_pump_frame, NULL); +} + +static void* fg_pump_loop(void* arg) { + (void)arg; + prctl(PR_SET_NAME, "fg-pump", 0, 0, 0); + setpriority(PRIO_PROCESS, 0, -8); + JNIEnv* env = NULL; + (*g_pump_jvm)->AttachCurrentThread(g_pump_jvm, &env, NULL); + ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); + g_pump_chor = AChoreographer_getInstance(); + if (g_pump_chor) AChoreographer_postFrameCallback(g_pump_chor, fg_pump_frame, NULL); + else VK_LOGE("AChoreographer_getInstance returned NULL"); + while (g_pump_running) ALooper_pollOnce(100, NULL, NULL, NULL); + g_pump_chor = NULL; + (*g_pump_jvm)->DetachCurrentThread(g_pump_jvm); + return NULL; +} + +JNIEXPORT void JNICALL JNI_FN(nativeFgPumpStart)(JNIEnv* env, jclass clazz, jobject renderer) { + (void)clazz; + if (g_pump_running) return; + (*env)->GetJavaVM(env, &g_pump_jvm); + g_pump_renderer = (*env)->NewGlobalRef(env, renderer); + jclass rc = (*env)->GetObjectClass(env, renderer); + g_pump_tick = (*env)->GetMethodID(env, rc, "fgPumpTickFromNative", "(J)V"); + if (!g_pump_tick) { VK_LOGE("fgPumpTickFromNative(J)V not found"); return; } + g_pump_running = 1; + if (pthread_create(&g_pump_thread, NULL, fg_pump_loop, NULL) != 0) { + g_pump_running = 0; VK_LOGE("native fg-pump pthread_create failed"); return; + } + VK_LOGI("native fg-pump started (AChoreographer pthread)"); +} + +JNIEXPORT void JNICALL JNI_FN(nativeFgPumpStop)(JNIEnv* env, jclass clazz) { + (void)clazz; + if (!g_pump_running) return; + g_pump_running = 0; + pthread_join(g_pump_thread, NULL); + if (g_pump_renderer) { (*env)->DeleteGlobalRef(env, g_pump_renderer); g_pump_renderer = NULL; } + g_pump_tick = NULL; + VK_LOGI("native fg-pump stopped"); +} + +JNIEXPORT jlong JNICALL JNI_FN(nativeCreate)(JNIEnv* env, jclass clazz, + jboolean enableValidationLayers, + jstring driverName, + jobject context) { + (void)clazz; + VkRenderer* r = calloc(1, sizeof(VkRenderer)); + if (!r) return 0; + r->target_present_mode = VK_PRESENT_MODE_MAILBOX_KHR; + r->active_present_mode = VK_PRESENT_MODE_FIFO_KHR; + r->fg_occ_lo = 0.06f; + r->fg_occ_hi = 0.25f; + r->fg_min_step = 1; + r->fg_flow_scale = 0.25f; + r->fg_use_cnn = cnn_wanted(); + r->fg_cnn_gen = true; + r->validation_enabled = (enableValidationLayers == JNI_TRUE); + pthread_mutex_init(&r->scene_mutex, NULL); + pthread_mutex_init(&r->queue_mutex, NULL); + pthread_mutex_init(&r->texture_mutex, NULL); + pthread_mutex_init(&r->render_mutex, NULL); + pthread_mutex_init(&r->descriptor_mutex, NULL); + + const char* driver_name_c = NULL; + if (driverName != NULL) driver_name_c = (*env)->GetStringUTFChars(env, driverName, NULL); + r->vulkan_handle = winlator_open_vulkan(env, context, driver_name_c); + if (driver_name_c != NULL) (*env)->ReleaseStringUTFChars(env, driverName, driver_name_c); + + if (!r->vulkan_handle) { + VK_LOGE("winlator_open_vulkan returned NULL"); + goto fail; + } + if (!vkd_init(r->vulkan_handle)) { + VK_LOGE("vkd_init failed"); + goto fail; + } + + if (!create_instance(r)) goto fail; + if (!pick_physical_device(r)) goto fail; + if (!create_device(r)) goto fail; + query_device_caps(r); + if (!create_command_pool(r)) goto fail; + if (!create_descriptor_pool(r, r->caps.descriptor_pool_capacity)) goto fail; + if (!create_quad_vbo(r)) goto fail; if (!vkr_create_sampler(r, VK_NULL_HANDLE, &r->shared_sampler)) goto fail; { VkSamplerCreateInfo nsi = {VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; @@ -2568,6 +4426,7 @@ JNIEXPORT void JNICALL JNI_FN(nativeDestroy)(JNIEnv* env, jclass clazz, jlong ha VkRenderer* r = (VkRenderer*)(intptr_t)handle; if (!r) return; + fg_worker_stop(r); // join the worker before any device/swapchain teardown if (r->device) vkDeviceWaitIdle(r->device); // Drain any in-flight uploads and tear down the staging pool before destroying images. @@ -2587,6 +4446,7 @@ JNIEXPORT void JNICALL JNI_FN(nativeDestroy)(JNIEnv* env, jclass clazz, jlong ha free(r->batch_entry_scratch); free(r->batch_prepared_scratch); + fg_destroy_resources(r); destroy_record_swapchain(r); destroy_sgsr1_resources(r); destroy_offscreen(r); @@ -2612,8 +4472,7 @@ JNIEXPORT void JNICALL JNI_FN(nativeDestroy)(JNIEnv* env, jclass clazz, jlong ha destroy_debug_messenger(r); if (r->instance)vkDestroyInstance(r->instance, NULL); - // Clear dispatch BEFORE dlclose so a stray call from another thread faults on NULL - // rather than jumping into freed library memory. + // Clear dispatch BEFORE dlclose so a stray call faults on NULL, not freed memory. vkd_unload(); if (r->vulkan_handle) { dlclose(r->vulkan_handle); r->vulkan_handle = NULL; } @@ -2625,9 +4484,7 @@ JNIEXPORT void JNICALL JNI_FN(nativeDestroy)(JNIEnv* env, jclass clazz, jlong ha free(r); } -// Lifecycle helper: take render_mutex (waits for any in-flight render to finish), then -// briefly take scene_mutex to clear surface_ready so producers see a consistent state. -// Returns with only render_mutex held; caller must release it. +// Take render_mutex, then briefly scene_mutex to clear surface_ready. Returns holding render_mutex. static void lifecycle_begin(VkRenderer* r) { pthread_mutex_lock(&r->render_mutex); pthread_mutex_lock(&r->scene_mutex); @@ -2640,6 +4497,7 @@ JNIEXPORT void JNICALL JNI_FN(nativeSurfaceCreated)(JNIEnv* env, jclass clazz, j VkRenderer* r = (VkRenderer*)(intptr_t)handle; if (!r) return; + fg_worker_stop(r); // worker restarts on the next nativeSurfaceChanged if FG is on lifecycle_begin(r); if (r->surface) { @@ -2679,9 +4537,7 @@ JNIEXPORT void JNICALL JNI_FN(nativeSurfaceCreated)(JNIEnv* env, jclass clazz, j VK_LOGE("Selected queue family does not support presentation"); } - // Wait for SurfaceHolder.surfaceChanged() before creating the swapchain. On Android - // the surface can be created while the activity is still completing a rotation, so - // creating it here can lock in stale portrait dimensions for a landscape launch. + // Wait for SurfaceHolder.surfaceChanged() before creating the swapchain (rotation may be mid-flight). pthread_mutex_unlock(&r->render_mutex); } @@ -2690,12 +4546,16 @@ JNIEXPORT void JNICALL JNI_FN(nativeSurfaceChanged)(JNIEnv* env, jclass clazz, j VkRenderer* r = (VkRenderer*)(intptr_t)handle; if (!r || !r->surface) return; + bool fg_was = r->fg_enabled; + fg_worker_stop(r); // worker owns the swapchain while FG is on — stop it BEFORE touching it (no render_mutex held) + lifecycle_begin(r); vkDeviceWaitIdle(r->device); destroy_sgsr1_resources(r); destroy_offscreen(r); destroy_swapchain(r); - if (!create_swapchain(r, (uint32_t)w, (uint32_t)h)) { + bool ok = create_swapchain(r, (uint32_t)w, (uint32_t)h); + if (!ok) { VK_LOGE("Swapchain re-create failed in nativeSurfaceChanged"); } else { pthread_mutex_lock(&r->scene_mutex); @@ -2703,6 +4563,7 @@ JNIEXPORT void JNICALL JNI_FN(nativeSurfaceChanged)(JNIEnv* env, jclass clazz, j pthread_mutex_unlock(&r->scene_mutex); } pthread_mutex_unlock(&r->render_mutex); + if (fg_was && ok) fg_worker_start(r); } JNIEXPORT jboolean JNICALL JNI_FN(nativeStartRecording)(JNIEnv* env, jclass clazz, jlong handle, jobject surface, jint fps, jboolean recordUI) { @@ -2854,6 +4715,7 @@ JNIEXPORT void JNICALL JNI_FN(nativeSurfaceDestroyed)(JNIEnv* env, jclass clazz, VkRenderer* r = (VkRenderer*)(intptr_t)handle; if (!r) return; + fg_worker_stop(r); // stop before the swapchain it owns is destroyed lifecycle_begin(r); if (r->device) vkDeviceWaitIdle(r->device); @@ -2878,10 +4740,191 @@ JNIEXPORT jboolean JNICALL JNI_FN(nativeRenderFrame)(JNIEnv* env, jclass clazz, return record_and_submit_frame(r) ? JNI_TRUE : JNI_FALSE; } +// ---- Frame generation JNI ---- + +JNIEXPORT void JNICALL JNI_FN(nativeSetFrameGeneration)(JNIEnv* env, jclass clazz, jlong handle, jboolean enabled) { + (void)env; (void)clazz; + VkRenderer* r = (VkRenderer*)(intptr_t)handle; + if (!r) return; + bool was = r->fg_enabled; + bool now = (enabled == JNI_TRUE); + if (now == was) return; + r->fg_enabled = now; + if (now) fg_worker_start(r); + else fg_worker_stop(r); + VK_LOGI("Frame generation %s (fp16=%d)", now ? "ENABLED" : "disabled", r->fg_float16_supported); +} + +// Present mode actually in use (Java convention: 0 FIFO, 1 MAILBOX, 2 IMMEDIATE). +JNIEXPORT jint JNICALL JNI_FN(nativeGetActivePresentMode)(JNIEnv* env, jclass clazz, jlong handle) { + (void)env; (void)clazz; + VkRenderer* r = (VkRenderer*)(intptr_t)handle; + if (!r) return 0; + switch (r->active_present_mode) { + case VK_PRESENT_MODE_MAILBOX_KHR: return 1; + case VK_PRESENT_MODE_IMMEDIATE_KHR: return 2; + default: return 0; + } +} + +JNIEXPORT jboolean JNICALL JNI_FN(nativeFrameGenerationSupported)(JNIEnv* env, jclass clazz, jlong handle) { + (void)env; (void)clazz; + VkRenderer* r = (VkRenderer*)(intptr_t)handle; + return (r != NULL) ? JNI_TRUE : JNI_FALSE; +} + +// Monotonic count of actual vkQueuePresentKHR calls (real + interpolated). +JNIEXPORT jlong JNICALL JNI_FN(nativeGetDisplayFrameCount)(JNIEnv* env, jclass clazz, jlong handle) { + (void)env; (void)clazz; + VkRenderer* r = (VkRenderer*)(intptr_t)handle; + if (!r) return 0; + pthread_mutex_lock(&r->queue_mutex); + uint64_t c = r->fg_present_count; + pthread_mutex_unlock(&r->queue_mutex); + return (jlong)c; +} + +JNIEXPORT jboolean JNICALL JNI_FN(nativeFgResolveStage)(JNIEnv* env, jclass clazz, jlong handle) { + (void)env; (void)clazz; + VkRenderer* r = (VkRenderer*)(intptr_t)handle; + if (!r || !r->surface_ready) return JNI_FALSE; + pthread_mutex_lock(&r->render_mutex); + bool p = fg_resolve_stage(r, false); + pthread_mutex_unlock(&r->render_mutex); + return p ? JNI_TRUE : JNI_FALSE; +} + +JNIEXPORT jboolean JNICALL JNI_FN(nativeRenderHold)(JNIEnv* env, jclass clazz, jlong handle, jboolean forcePromote) { + (void)env; (void)clazz; + VkRenderer* r = (VkRenderer*)(intptr_t)handle; + if (!r || !r->surface_ready) return JNI_FALSE; + return fg_submit(r, FG_MODE_HOLD, 0.5f, 0u, forcePromote == JNI_TRUE) ? JNI_TRUE : JNI_FALSE; +} + +// out[0]=promote count, out[1]=last promote time (ns), out[2]=duplicates dropped, out[3]=distinct total. +JNIEXPORT void JNICALL JNI_FN(nativeFgPromoteInfo)(JNIEnv* env, jclass clazz, jlong handle, jlongArray out) { + (void)clazz; + VkRenderer* r = (VkRenderer*)(intptr_t)handle; + if (!r || !out) return; + jlong vals[4]; + pthread_mutex_lock(&r->render_mutex); + vals[0] = (jlong)r->fg_promote_count; + vals[1] = (jlong)r->fg_promote_ns; + vals[2] = (jlong)r->fg_dup_dropped; + vals[3] = (jlong)r->fg_distinct; + pthread_mutex_unlock(&r->render_mutex); + (*env)->SetLongArrayRegion(env, out, 0, 4, vals); +} + +JNIEXPORT jboolean JNICALL JNI_FN(nativeRenderInterp)(JNIEnv* env, jclass clazz, jlong handle, jfloat phase, jlong prevNs, jlong currNs, jlong targetNs) { + (void)env; (void)clazz; + VkRenderer* r = (VkRenderer*)(intptr_t)handle; + if (!r || !r->surface_ready) return JNI_FALSE; + r->fg_prev_arrival_ns = prevNs > 0 ? (uint64_t)prevNs : 0; + r->fg_curr_arrival_ns = currNs > 0 ? (uint64_t)currNs : 0; + fg_enqueue(r, FG_MODE_INTERP, (float)phase, targetNs > 0 ? (uint64_t)targetNs : 0u); + return JNI_TRUE; +} + +JNIEXPORT jboolean JNICALL JNI_FN(nativePresentLast)(JNIEnv* env, jclass clazz, jlong handle, jfloat phase, jlong prevNs, jlong currNs, jlong targetNs) { + (void)env; (void)clazz; + VkRenderer* r = (VkRenderer*)(intptr_t)handle; + if (!r || !r->surface_ready) return JNI_FALSE; + r->fg_prev_arrival_ns = prevNs > 0 ? (uint64_t)prevNs : 0; + r->fg_curr_arrival_ns = currNs > 0 ? (uint64_t)currNs : 0; + fg_enqueue(r, FG_MODE_PRESENT_LAST, phase, targetNs > 0 ? (uint64_t)targetNs : 0u); + return JNI_TRUE; +} + +// Live FG knobs: occLo/occHi = interp consistency window (smoothness), minStep = motion search floor. +JNIEXPORT void JNICALL JNI_FN(nativeSetFrameGenParams)(JNIEnv* env, jclass clazz, jlong handle, + jfloat occLo, jfloat occHi, jint minStep) { + (void)env; (void)clazz; + VkRenderer* r = (VkRenderer*)(intptr_t)handle; + if (!r) return; + // occLo now carries the preset's model flag (0 standard, 1 steadier) through to interpolate.frag. + float lo = occLo < 0.0f ? 0.0f : (occLo > 1.0f ? 1.0f : occLo); + float hi = occHi > lo ? occHi : (lo + 0.1f); + r->fg_occ_lo = lo; + r->fg_occ_hi = hi; + r->fg_min_step = minStep < 1 ? 1 : (minStep > 8 ? 8 : minStep); + VK_LOGI("FG params set: model(occLo)=%.2f minStep(quality)=%d", lo, r->fg_min_step); +} + +// Preset flow-resolution dial [0.2,1.0]; the render thread rebuilds the motion fields when it changes. +JNIEXPORT void JNICALL JNI_FN(nativeSetFrameGenFlowScale)(JNIEnv* env, jclass clazz, jlong handle, jfloat flowScale) { + (void)env; (void)clazz; + VkRenderer* r = (VkRenderer*)(intptr_t)handle; + if (!r) return; + float fs = flowScale < 0.05f ? 0.05f : (flowScale > 1.0f ? 1.0f : flowScale); + r->fg_flow_scale = fs; + VK_LOGI("FG flowScale set: %.2f (motion-field rebuild pending)", fs); +} + +JNIEXPORT void JNICALL JNI_FN(nativeSetFrameGenDeepMode)(JNIEnv* env, jclass clazz, jlong handle, jboolean deep) { + (void)env; (void)clazz; + VkRenderer* r = (VkRenderer*)(intptr_t)handle; + if (!r) return; + bool want = deep ? true : false; + if (want == r->fg_deep_mode) return; + pthread_mutex_lock(&r->render_mutex); + r->fg_deep_mode = want; + // Restart the cadence cleanly so the new mode warms up from scratch (a brief re-prime). + r->fg_history_count = 0; + r->fg_motion_valid = false; + r->fg_motion_fwd_valid = false; + pthread_mutex_unlock(&r->render_mutex); +} + +JNIEXPORT void JNICALL JNI_FN(nativeSetFrameGenUseCnn)(JNIEnv* env, jclass clazz, jlong handle, jboolean useCnn) { + (void)env; (void)clazz; + VkRenderer* r = (VkRenderer*)(intptr_t)handle; + if (!r) return; + bool want = useCnn ? true : false; + if (want == r->fg_use_cnn) return; + pthread_mutex_lock(&r->render_mutex); + r->fg_use_cnn = want; + r->fg_history_count = 0; + r->fg_motion_valid = false; + r->fg_motion_fwd_valid = false; + pthread_mutex_unlock(&r->render_mutex); +} + +// Generation method: false = interpolation, true = extrapolation. +JNIEXPORT void JNICALL JNI_FN(nativeSetFrameGenExtrapolate)(JNIEnv* env, jclass clazz, jlong handle, jboolean extrapolate) { + (void)env; (void)clazz; + VkRenderer* r = (VkRenderer*)(intptr_t)handle; + if (!r) return; + bool want = extrapolate ? true : false; + if (want == r->fg_extrapolate) return; + pthread_mutex_lock(&r->render_mutex); + r->fg_extrapolate = want; + r->fg_history_count = 0; + r->fg_motion_valid = false; + r->fg_motion_fwd_valid = false; + pthread_mutex_unlock(&r->render_mutex); +} + +// Requested compositor frames-in-flight (1..3); applied live via the frame-slot rotation depth. +JNIEXPORT void JNICALL JNI_FN(nativeSetFrameGenFramesInFlight)(JNIEnv* env, jclass clazz, jlong handle, jint framesInFlight) { + (void)env; (void)clazz; + VkRenderer* r = (VkRenderer*)(intptr_t)handle; + if (!r) return; + uint32_t fif = framesInFlight < 1 ? 1u : (framesInFlight > 3 ? 3u : (uint32_t)framesInFlight); + r->fg_target_fif = fif; +} + +JNIEXPORT void JNICALL JNI_FN(nativeSetVsyncTiming)(JNIEnv* env, jclass clazz, jlong handle, jlong periodNs, jlong displayPeriodNs, jlong contentPeriodNs, jlong vsyncNs) { + (void)env; (void)clazz; + VkRenderer* r = (VkRenderer*)(intptr_t)handle; + if (!r) return; + r->fg_present_period_ns = periodNs > 0 ? (uint64_t)periodNs : 0; + r->fg_display_period_ns = displayPeriodNs > 0 ? (uint64_t)displayPeriodNs : 0; + r->fg_content_period_ns = contentPeriodNs > 0 ? (uint64_t)contentPeriodNs : 0; + r->fg_vsync_anchor_ns = vsyncNs > 0 ? (uint64_t)vsyncNs : 0; +} + // Scene byte buffer layout (must mirror VulkanRenderer.java offsets). Native-endian, packed. -// Using a single direct ByteBuffer instead of 6 separate jarray params avoids per-frame JNI -// critical regions (each ~3-8µs on ART) and the temporary array shadow allocations they -// trigger. #define SCENE_OFF_CURSOR_HANDLE 0 #define SCENE_OFF_WINDOW_HANDLES 8 /* int64 × VK_MAX_RENDERABLE_WINDOWS */ #define SCENE_OFF_WINDOW_COUNT 520 @@ -2912,8 +4955,6 @@ JNIEXPORT void JNICALL JNI_FN(nativeSetScene)(JNIEnv* env, jclass clazz, jlong h const uint8_t* base = (const uint8_t*)(*env)->GetDirectBufferAddress(env, sceneBuf); if (!base) return; - // Defensive: a future Java-side layout change with a stale SCENE_BUF_SIZE would silently - // read past the buffer here. GetDirectBufferCapacity is one JNI call; cheap insurance. jlong cap = (*env)->GetDirectBufferCapacity(env, sceneBuf); if (cap < SCENE_BUF_SIZE) { VK_LOGE("nativeSetScene: scene buffer too small (%lld < %d)", @@ -3020,8 +5061,6 @@ JNIEXPORT void JNICALL JNI_FN(nativeSetScene)(JNIEnv* env, jclass clazz, jlong h } pthread_mutex_unlock(&r->scene_mutex); - // Offscreen rebuild is handled in record_and_submit_frame under render_mutex; nothing - // here needs to touch swapchain-tied resources. } // FPS pacing is enforced by delaying PresentIdleNotify (buffer-release back-pressure) on the @@ -3048,9 +5087,7 @@ JNIEXPORT void JNICALL JNI_FN(nativeSetScaleFilter)(JNIEnv* env, jclass clazz, j pthread_mutex_unlock(&r->render_mutex); } -// Set the compositor present mode. Java passes 0=FIFO, 1=MAILBOX, 2=IMMEDIATE; anything else -// is treated as FIFO. Triggers a swapchain rebuild if a surface is currently active so the -// change takes effect on the next frame. +// Set the compositor present mode (0=FIFO, 1=MAILBOX, 2=IMMEDIATE). Rebuilds the swapchain if active. JNIEXPORT void JNICALL JNI_FN(nativeSetPresentMode)(JNIEnv* env, jclass clazz, jlong handle, jint mode) { (void)env; (void)clazz; VkRenderer* r = (VkRenderer*)(intptr_t)handle; @@ -3070,6 +5107,8 @@ JNIEXPORT void JNICALL JNI_FN(nativeSetPresentMode)(JNIEnv* env, jclass clazz, j pthread_mutex_unlock(&r->render_mutex); return; } + bool restart_worker = r->fg_gen_started; + fg_worker_stop(r); lifecycle_begin(r); r->target_present_mode = vk_mode; if (r->device) vkDeviceWaitIdle(r->device); @@ -3086,6 +5125,7 @@ JNIEXPORT void JNICALL JNI_FN(nativeSetPresentMode)(JNIEnv* env, jclass clazz, j pthread_mutex_unlock(&r->scene_mutex); } pthread_mutex_unlock(&r->render_mutex); + if (restart_worker && r->fg_enabled) fg_worker_start(r); } // ============================================================ @@ -3135,8 +5175,6 @@ JNIEXPORT jboolean JNICALL TEX_FN(nativeUpdate)(JNIEnv* env, jclass clazz, jlong ? JNI_TRUE : JNI_FALSE; } -// Grow-only scratch for parsed batch entries. Render-thread-only, so unlocked; every element -// is fully populated before use, so no zeroing. (Mirrors get_prepared_scratch in vk_image.c.) static VkTextureBatchUpload* get_entry_scratch(VkRenderer* r, uint32_t count) { if (r->batch_entry_cap < count) { uint32_t new_cap = r->batch_entry_cap ? r->batch_entry_cap : 64; diff --git a/app/src/main/cpp/winlator/vk/vk_state.h b/app/src/main/cpp/winlator/vk/vk_state.h index 0eae82af5..e3df8d5fb 100644 --- a/app/src/main/cpp/winlator/vk/vk_state.h +++ b/app/src/main/cpp/winlator/vk/vk_state.h @@ -1,5 +1,4 @@ // Master state header for the Vulkan compositor. -// Internal use only — JNI entry points expose a long handle that wraps VkRenderer*. #pragma once @@ -7,12 +6,11 @@ #include #include #include +#include #include #include #include -// All vk* calls route through the dispatch table — vk_dispatch.h is the Vulkan header for -// this translation unit (do not include directly). #include "vk_dispatch.h" #define VK_LOG_TAG "VkRenderer" @@ -20,16 +18,23 @@ #define VK_LOGW(...) __android_log_print(ANDROID_LOG_WARN, VK_LOG_TAG, __VA_ARGS__) #define VK_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, VK_LOG_TAG, __VA_ARGS__) -#define VK_FRAMES_IN_FLIGHT 2 +#define VK_FRAMES_IN_FLIGHT 3 #define VK_MAX_SWAPCHAIN_IMAGES 8 +#define FG_JOB_RING 6u + +typedef struct FgJob { + uint8_t mode; // 1 = INTERP, 2 = PRESENT_LAST + uint8_t deep; + float phase; + uint32_t curr_idx; + uint32_t prev_idx; + uint64_t deadline_ns; + uint32_t seq; +} FgJob; // Encoder input-surface swapchains can expose many more images than a display swapchain. #define VK_MAX_RECORD_IMAGES 32 #define VK_MAX_EFFECTS 8 #define VK_MAX_RENDERABLE_WINDOWS 64 -// Number of in-flight upload slots. Each slot owns a persistently-mapped staging buffer, -// fence, and command pool. An upload only blocks when this many uploads are still pending -// on the GPU — with 8 slots and ~100µs GPU upload time, we can sustain ~80k uploads/sec -// without ever waiting. #define VK_STAGING_POOL_SIZE 8 #define VK_CHECK(expr) do { \ @@ -40,16 +45,15 @@ } while (0) // ============================================================ -// Texture (drives both regular CPU-uploaded images and AHB imports) +// Texture // ============================================================ -// A CPU-uploaded texture's slice of an image sub-allocator block (defined below). struct VkMemBlock; typedef struct VkSuballoc { struct VkMemBlock* block; // owning block (NULL => not sub-allocated) - VkDeviceMemory memory; // == block->memory, cached for vkBindImageMemory - VkDeviceSize bind_offset; // aligned offset the image is bound at - VkDeviceSize span_offset; // reserved span start/length, returned on free + VkDeviceMemory memory; + VkDeviceSize bind_offset; + VkDeviceSize span_offset; VkDeviceSize span_size; } VkSuballoc; @@ -57,28 +61,22 @@ typedef struct VkTexture { VkImage image; VkImageView view; VkDeviceMemory memory; - VkSampler sampler; // owned per-texture (simple); could be cached + VkSampler sampler; // owned per-texture VkSamplerYcbcrConversion ycbcr; // VK_NULL_HANDLE if unused - VkDescriptorSet descriptor_set; // one per texture, lives until destruction + VkDescriptorSet descriptor_set; uint32_t width; uint32_t height; VkFormat format; VkImageLayout layout; - // Lifetime: when set, owned by texture and freed on destroy. AHardwareBuffer* ahb; - // Track readiness: true once image+view+sampler are valid. bool ready; - // True if this texture should never be uploaded to (e.g. AHB scanout). - bool external; - // Prevent duplicate deferred frees if Java schedules destruction more than once. + bool external; // never uploaded to (e.g. AHB scanout) bool destroy_scheduled; - // suballocated: backing comes from the shared sub-allocator (suballoc) and `memory` is - // unused. AHB imports and the dedicated fallback leave this false. - bool suballocated; + bool suballocated; // backing from the shared sub-allocator; `memory` unused VkSuballoc suballoc; } VkTexture; @@ -119,14 +117,14 @@ typedef enum VkEffectType { typedef struct VkEffectSlot { VkEffectType type; - int mode; // effect-specific mode - float param0; // generic + int mode; + float param0; float param1; - float param2; // generic + float param2; } VkEffectSlot; // ============================================================ -// Scene snapshot (mutex-protected, written from Java threads, read on render thread) +// Scene snapshot // ============================================================ typedef struct VkRenderableWindow { @@ -134,7 +132,7 @@ typedef struct VkRenderableWindow { int x, y; uint32_t width, height; float u0, v0, u1, v1; - bool direct_scanout; // hint, currently unused + bool direct_scanout; // unused } VkRenderableWindow; typedef struct VkScene { @@ -148,14 +146,12 @@ typedef struct VkScene { uint32_t cursor_height; bool cursor_visible; - // Transform parameters - tmpXForm2 of GLRenderer applied to all windows. float xform[6]; bool scissor_enabled; int scissor_x, scissor_y, scissor_w, scissor_h; int viewport_x, viewport_y, viewport_w, viewport_h; bool viewport_set; - // Render dims (logical screen size). uint32_t screen_width; uint32_t screen_height; uint32_t source_width; @@ -174,8 +170,8 @@ typedef struct VkScene { typedef struct VkPipelineSet { VkDescriptorSetLayout sampler_set_layout; - VkPipelineLayout window_layout; // push constants: xform[6] + viewSize - VkPipelineLayout effect_layout; // push constants: resolution + effect params + VkPipelineLayout window_layout; // push: xform[6] + viewSize + VkPipelineLayout effect_layout; // push: resolution + effect params VkPipeline window_pipeline; VkPipeline cursor_pipeline; VkPipeline blit_pipeline; @@ -188,6 +184,31 @@ typedef struct VkPipelineSet { // Render passes VkRenderPass swapchain_pass; // load=clear, store=store, final=present VkRenderPass offscreen_pass; // load=clear, store=store, final=shader-read + + // --- Frame generation --- + VkDescriptorSetLayout fg_motion_layout; // set0: sampler(prev,curr) + STORAGE_IMAGE(mv), COMPUTE + VkDescriptorSetLayout fg_interp_layout; // set0: 4x COMBINED_IMAGE_SAMPLER, FRAGMENT + VkPipelineLayout fg_motion_pipe_layout; // motion set + 32B compute push range + VkPipelineLayout fg_interp_pipe_layout; // interp set + 24B fragment push range + VkPipeline fg_motion_pipeline; // compute + VkPipeline fg_flowfix_pipeline; + VkPipeline fg_interp_pipeline; // graphics (swapchain_pass) + + VkDescriptorSetLayout cnn_pyramid_dsl, cnn_conv_dsl, cnn_cost9_dsl, + cnn_flowreg_dsl, cnn_warpfollow_dsl, cnn_generate_dsl; + VkPipelineLayout cnn_pyramid_pl, cnn_conv_pl, cnn_cost9_pl, + cnn_flowreg_pl, cnn_warpfollow_pl, cnn_generate_pl; + VkPipeline cnn_pyramid_pipe, cnn_conv_pipe, cnn_cost9_pipe, + cnn_flowreg_pipe, cnn_warpfollow_pipe, cnn_generate_pipe; + + VkDescriptorSetLayout gh_d5_dsl, gh_d6_dsl, gh_d7_dsl, gh_d8_dsl, gh_d9_dsl, gh_d10_dsl; + VkPipelineLayout gh_d5_pl, gh_d6_pl, gh_d7_pl, gh_d8_pl, gh_d9_pl, gh_d10_pl; + VkPipeline gh_d5_pipe, gh_d6_pipe, gh_d7_pipe, gh_d8_pipe, gh_d9_pipe, gh_d10_pipe; + VkDescriptorSetLayout fg_synth_dsl; VkPipelineLayout fg_synth_pl; VkPipeline fg_synth_pipe; + + VkDescriptorSetLayout gh_occ_dsl, gh_gen_dsl; // wnfg_13 occlusion, wnfg_04 generate + VkPipelineLayout gh_occ_pl, gh_gen_pl; + VkPipeline gh_occ_pipe, gh_gen_pipe; } VkPipelineSet; // ============================================================ @@ -221,6 +242,67 @@ typedef struct VkSgsr1State { uint32_t height; } VkSgsr1State; +typedef struct VkFgImage { + VkImage image; + VkImageView view; + VkImageView storeView; // rgba8 mutable view for the synth-shift harness (history only) + VkDeviceMemory memory; + VkFramebuffer framebuffer; // history targets only; VK_NULL_HANDLE for the motion field + VkDescriptorSet blit_set; // history only + uint32_t width, height; +} VkFgImage; + +// ============================================================ +#define CNN_LEVELS 7 +typedef struct VkCnnImg { + VkImage image; + VkImageView view; + VkImageView layerView[4]; + VkDeviceMemory memory; + uint32_t w, h, layers; +} VkCnnImg; +typedef struct VkCnnFeatSet { + VkCnnImg luma [CNN_LEVELS]; + VkCnnImg feat4a[CNN_LEVELS]; + VkCnnImg feat4b[CNN_LEVELS]; + VkCnnImg feat8 [CNN_LEVELS]; +} VkCnnFeatSet; +#define CNN_POOLS 8 + +typedef struct VkFgCnn { + bool ready; + VkDescriptorPool pool[CNN_POOLS]; + uint32_t curPool; + VkCnnFeatSet feat[3]; + bool featValid[3]; + VkCnnImg feat8_pair[CNN_LEVELS]; + VkCnnImg gPair8[CNN_LEVELS]; // wnfg_36 input: prev.feat8 L0 ++ curr.feat8 L0 (8ch, cinT=2) + VkCnnImg gExpIn[CNN_LEVELS]; // wnfg_45 input: hG1.L0 ++ hG1.L1 ++ 0 (3-layer, cinT=3) + VkCnnImg hG23b[CNN_LEVELS]; // wnfg_42 output (16ch) when wnfg_45 expansion is present + VkCnnImg hG0[CNN_LEVELS], hG1[CNN_LEVELS], hG23[CNN_LEVELS], hG4[CNN_LEVELS]; + VkCnnImg hD0[CNN_LEVELS], hD1[CNN_LEVELS], hD2[CNN_LEVELS], hD3[CNN_LEVELS]; + VkCnnImg hD5[CNN_LEVELS], hD6[CNN_LEVELS], hD7[CNN_LEVELS], hD8[CNN_LEVELS]; + VkCnnImg dpair[CNN_LEVELS]; + VkCnnImg flowMid[CNN_LEVELS]; + VkCnnImg flowRef[CNN_LEVELS]; + VkCnnImg logits[CNN_LEVELS]; + VkCnnImg occ; + VkCnnImg seedBlack; + VkCnnImg dummy; + VkBuffer ubo; VkDeviceMemory uboMem; + VkBuffer w[64]; + VkDeviceMemory wMem[64]; + VkDeviceSize wLen[64]; + + // wnfg_13 occlusion + wnfg_04 generate + VkCnnImg occOut[3][6]; + VkCnnImg gen[3]; // RGBA16F generated frame ring, full swapchain res + VkDescriptorSet genSet[3]; // binding0 = gen[i].view (present blit) + VkBuffer genUbo[3]; // per-frame {mvScale, t, _} for wnfg_04 + VkDeviceMemory genUboMem[3]; + void* genUboMap[3]; + bool genReady; +} VkFgCnn; // Recording mirror: a second swapchain on a MediaCodec input surface; each frame is blitted from // the display swapchain into it and co-presented. Gated on rec.active. typedef struct VkRecordSwap { @@ -256,21 +338,21 @@ typedef struct VkRecordSwap { typedef struct VkStagingSlot { pthread_mutex_t mutex; // held by current owner from acquire to release - VkCommandPool cmd_pool; // exclusive to this slot, no global cmd pool sync needed + VkCommandPool cmd_pool; // exclusive to this slot VkCommandBuffer cmd; VkBuffer buffer; VkDeviceMemory memory; void* mapped; // persistently mapped HOST_VISIBLE memory - VkDeviceSize size; // current allocation; grows on demand - VkFence fence; // signaled when this slot's last submission completes + VkDeviceSize size; // grows on demand + VkFence fence; } VkStagingSlot; typedef struct VkStagingPool { VkStagingSlot slots[VK_STAGING_POOL_SIZE]; - uint32_t valid_slots; // count of slots whose per-slot mutex is initialized + uint32_t valid_slots; // slots whose per-slot mutex is initialized uint64_t next; // round-robin counter pthread_mutex_t mutex; // protects `next` only - bool mutex_init; // pool-mutex initialization flag (for safe destroy) + bool mutex_init; bool initialized; } VkStagingPool; @@ -289,33 +371,24 @@ typedef struct VkGraveSlot { // ============================================================ typedef struct VkDeviceCaps { - // Identity uint32_t vendor_id; uint32_t device_id; uint32_t driver_version; bool is_adreno; // vendor_id == 0x5143 (Qualcomm) - // Limits / sizing VkPhysicalDeviceLimits limits; uint32_t descriptor_pool_capacity; - // Format choices resolved against driver feature support VkFormat offscreen_format; // BGRA preferred, RGBA fallback VkFormat upload_format; // BGRA preferred; RGBA fallback uses CPU-side swizzle bool upload_needs_bgra_swizzle; - // Diagnostic bool ahb_bgra_supported; // VK_FORMAT_B8G8R8A8_UNORM importable from AHB } VkDeviceCaps; // ============================================================ // Image sub-allocator // ============================================================ -// -// CPU-uploaded textures share large DEVICE_LOCAL blocks instead of each taking a dedicated -// vkAllocateMemory — avoids per-pixmap allocator latency and hitting maxMemoryAllocationCount -// (~4096 on Adreno) under X-server pixmap churn. Each block has a first-fit free list (offset- -// sorted, coalesced on free); fully-drained blocks are returned. AHB imports stay dedicated. #define VK_SUBALLOC_BLOCK_SIZE (32u * 1024u * 1024u) // 32 MiB default block @@ -335,7 +408,7 @@ typedef struct VkMemBlock { typedef struct VkImageSuballocator { VkMemBlock* blocks; - VkDeviceSize block_size; // size used when carving a new block + VkDeviceSize block_size; pthread_mutex_t mutex; // alloc (producer threads) vs free (render thread) bool mutex_init; } VkImageSuballocator; @@ -348,23 +421,15 @@ typedef struct VkRenderer { // Lifecycle bool initialized; bool surface_ready; - // True when we deliberately create a fallback swapchain with a preTransform that differs - // from caps.currentTransform (Adreno reports SUBOPTIMAL on every present in that case). bool ignore_suboptimal; - pthread_mutex_t scene_mutex; // guards r->scene + graveyard slots; held briefly by all + pthread_mutex_t scene_mutex; // guards r->scene + graveyard slots pthread_mutex_t queue_mutex; // serializes vkQueueSubmit across threads pthread_mutex_t texture_mutex; // guards live_textures pthread_mutex_t descriptor_mutex;// external sync for descriptor_pool alloc/free - pthread_mutex_t render_mutex; // serializes lifecycle vs render; held by render thread for - // the full acquire+record+submit+present, and by lifecycle - // ops (surface create/change/destroy) before they touch the - // swapchain. Scene producers do NOT take this — they only - // touch scene_mutex, so they never stall behind a frame. + pthread_mutex_t render_mutex; // serializes lifecycle vs render // Instance + physical/logical device - // dlopen handle for the libvulkan we resolved through. dlclose'd in nativeDestroy AFTER - // vkd_unload() to avoid stale dispatch pointers calling into freed memory. - void* vulkan_handle; + void* vulkan_handle; // dlopen handle for libvulkan VkInstance instance; bool validation_enabled; bool debug_utils_enabled; @@ -398,6 +463,76 @@ typedef struct VkRenderer { bool offscreen_built; VkSgsr1State sgsr1; + // --- Frame generation --- + bool fg_enabled; + bool fg_float16_supported; // shaderFloat16 available (selects the fp16 motion shader) + bool fg_built; // history + motion images allocated at fg_dims + VkExtent2D fg_dims; + VkFgImage fg_history[3]; // composited-scene ring; fg_history_curr = newest + VkFgImage fg_motion[3]; // half-res backward-flow ring + VkFgImage fg_motion_fwd[3]; // half-res forward-flow ring + VkFgImage fg_fixed[3]; + VkFgImage fg_coarse[3]; // quarter-res backward coarse-flow + VkFgImage fg_coarse_fwd[3]; // quarter-res forward coarse-flow + VkSampler fg_sampler; // linear, clamp + VkDescriptorSet fg_motion_set[3]; // prev,curr,coarse samplers + motion storage + VkDescriptorSet fg_motion_set_fwd[3]; + VkDescriptorSet fg_fix_set[3]; + VkDescriptorSet fg_coarse_set[3]; + VkDescriptorSet fg_coarse_set_fwd[3]; + VkDescriptorSet fg_interp_set[3]; // prev,curr,mvBwd,mvFwd samplers + VkDescriptorSet fg_interp_set_deep[3]; + VkFence fg_slot_fence[3]; // last submit that used each history slot + uint32_t fg_history_curr; // index of the most-recent composited frame + uint32_t fg_history_count; // valid history frames + uint64_t fg_present_count; // vkQueuePresentKHR calls; guarded by queue_mutex + bool fg_motion_valid; + bool fg_motion_fwd_valid; + bool fg_deep_mode; // bidirectional warp + bool fg_extrapolate; // false=interpolate, true=extrapolate forward + uint32_t fg_target_fif; // requested compositor frames-in-flight 1..3 + float fg_occ_lo; // consistency lower bound + float fg_occ_hi; // consistency upper bound + int32_t fg_min_step; // lowest TSS step (1 = full search) + float fg_flow_scale; // flow-field resolution scale [0.2,1.0] + float fg_built_flow_scale; // flow_scale baked into the current motion resources + + bool fg_use_cnn; + bool fg_cnn_capable; + bool fg_cnn_gen; + uint32_t fg_cnn_flow_seq; + VkFgCnn fg_cnn; + + // --- Content-duplicate detection --- + VkImage fg_sig_img; // tiny blit target, reused each HOLD + VkDeviceMemory fg_sig_img_mem; + VkBuffer fg_sig_buf[3]; // per-slot host-visible downsample + VkDeviceMemory fg_sig_buf_mem[3]; + void* fg_sig_ptr[3]; + bool fg_sig_supported; // blit+readback path created OK (else dedup disabled) + int32_t fg_stage_slot; // history slot holding the pending frame, -1 = none + bool fg_stage_force; + uint32_t fg_dump_w[10], fg_dump_h[10]; + uint8_t fg_dump_kind[10]; + float fg_dump_phase_of[10]; + VkFence fg_stage_fence; + uint64_t fg_last_promote_ns; + double fg_last_sig_delta; + uint64_t fg_dup_dropped, fg_distinct; + uint64_t fg_promote_count; + uint64_t fg_promote_ns; // CLOCK_MONOTONIC of the most recent promotion + + // --- Debug burst dump (debug.winnative.fgdump 1) --- + bool fg_dump_supported; + bool fg_dump_armed; + bool fg_dump_seen_zero; + uint32_t fg_dump_count; + float fg_dump_last_phase; + VkImage fg_dump_img; // 480x270 RGBA8 blit target + VkDeviceMemory fg_dump_img_mem; + VkBuffer fg_dump_buf[10]; // 8 gen + prev + curr, host-visible + VkDeviceMemory fg_dump_buf_mem[10]; + void* fg_dump_ptr[10]; // record_blit_src adds TRANSFER_SRC usage to the display swapchain (toggled by start/stop recording). bool record_blit_src; VkRecordSwap rec; @@ -406,9 +541,7 @@ typedef struct VkRenderer { VkBuffer quad_vbo; VkDeviceMemory quad_vbo_memory; - // Shared sampler for all CPU-uploaded textures and AHB textures that don't need a Ycbcr - // conversion. Created once at init; vkCreateSampler costs ~50-200µs on Adreno, so giving - // every texture its own sampler is a non-trivial CPU+GPU tax during pixmap churn. + // Shared sampler for CPU-uploaded and non-Ycbcr AHB textures. VkSampler shared_sampler; VkSampler shared_sampler_nearest; VkSampler shared_sampler_cubic; @@ -432,8 +565,7 @@ typedef struct VkRenderer { VkGraveSlot graveyard[VK_FRAMES_IN_FLIGHT + 1]; uint32_t graveyard_index; - // Live native textures owned by this renderer/device. Java Texture objects can outlive a - // renderer teardown, so nativeDestroy drains this list before the device is destroyed. + // Live native textures owned by this renderer/device; drained on nativeDestroy. VkTexture** live_textures; uint32_t live_texture_count; uint32_t live_texture_capacity; @@ -445,33 +577,84 @@ typedef struct VkRenderer { // Cached device capabilities populated by query_device_caps(). VkDeviceCaps caps; - // Function pointers loaded via vkGetDeviceProcAddr (not all are statically exported by - // the Android Vulkan loader, even in Vulkan 1.1). + // Function pointers loaded via vkGetDeviceProcAddr. PFN_vkGetAndroidHardwareBufferPropertiesANDROID fnGetAhbProps; PFN_vkCreateSamplerYcbcrConversion fnCreateYcbcr; PFN_vkDestroySamplerYcbcrConversion fnDestroyYcbcr; PFN_vkCreateDebugUtilsMessengerEXT fnCreateDebugUtilsMessenger; PFN_vkDestroyDebugUtilsMessengerEXT fnDestroyDebugUtilsMessenger; + // VK_GOOGLE_display_timing — present-pacing hint + telemetry (no-op when absent). + bool ext_display_timing; + uint64_t refresh_duration_ns; // panel vsync period from the swapchain (fallback) + uint64_t fg_present_period_ns; // target inter-present interval (ns) fed from Java + uint64_t fg_present_deadline_ns; // unsnapped deadline accumulator + uint64_t fg_present_target_ns; // present target for the next present + uint64_t fg_display_period_ns; // live panel vsync period fed from Java + uint64_t fg_content_period_ns; // EMA content interval fed from Java (matches slots) + uint64_t fg_vsync_anchor_ns; // latest Choreographer vsync timestamp + uint64_t fg_prev_arrival_ns; // real-frame arrival times + uint64_t fg_curr_arrival_ns; + uint64_t fg_t_last_ns; // present-interval telemetry accumulators + uint32_t fg_t_count; + double fg_t_sum_ms; + double fg_t_sumsq_ms; + double fg_t_min_ms; + double fg_t_max_ms; + double fg_fw_sum_ms; // in_flight fence-wait telemetry + double fg_fw_max_ms; + uint32_t fg_fw_n; + float fg_dbg_phase[8]; + float fg_dbg_done[8]; + uint32_t fg_dbg_n; + uint32_t fg_dbg_done_n; + uint64_t fg_dbg_last_curr; + uint32_t fg_present_id; + + // FG generation worker: GL thread enqueues; this pthread runs flow+generate+pace+present. + FgJob fg_job_ring[FG_JOB_RING]; // SPSC: GL produces (tail), worker consumes (head) + volatile uint32_t fg_job_head; + volatile uint32_t fg_job_tail; + sem_t fg_gen_sem; + pthread_t fg_gen_thread; + volatile int fg_gen_running; + bool fg_gen_started; + VkCommandPool fg_worker_pool; // worker-owned + VkFrame fg_worker_frames[3]; // worker-owned cmd + fence + image_available + uint32_t fg_worker_index; + volatile uint32_t fg_promote_seq; // ++ on each HOLD promote; jobs snapshot it + volatile uint32_t fg_swapchain_gen; // ++ on swapchain recreate + + PFN_vkGetRefreshCycleDurationGOOGLE fnGetRefreshCycleDuration; + PFN_vkGetPastPresentationTimingGOOGLE fnGetPastPresentationTiming; + + // VK_NV_optical_flow: driver-accelerated motion estimation. + bool fg_optical_flow; // extension available + feature enabled + PFN_vkGetPhysicalDeviceOpticalFlowImageFormatsNV fnOFFormats; + PFN_vkCreateOpticalFlowSessionNV fnOFCreate; + PFN_vkDestroyOpticalFlowSessionNV fnOFDestroy; + PFN_vkBindOpticalFlowSessionImageNV fnOFBind; + PFN_vkCmdOpticalFlowExecuteNV fnOFExecute; + // Async upload pool (created in nativeCreate after device). VkStagingPool staging_pool; // Image sub-allocator for CPU-uploaded textures (created in nativeCreate after device). VkImageSuballocator image_suballoc; - // Grow-only scratch for the batch upload path (render-thread-only, so unlocked; zero - // steady-state heap traffic). - VkTextureBatchUpload* batch_entry_scratch; // nativeBatchUpdate: parsed JNI entries + // Grow-only scratch for the batch upload path (render-thread-only). + VkTextureBatchUpload* batch_entry_scratch; // parsed JNI entries uint32_t batch_entry_cap; - void* batch_prepared_scratch; // vkr_texture_batch_update: PreparedBatchUpload[] + void* batch_prepared_scratch; // PreparedBatchUpload[] uint32_t batch_prepared_cap; // Scene state VkScene scene; - // Compositor present mode requested by Java (default FIFO). Validated against - // device-supported modes in create_swapchain; falls back to FIFO if unavailable. + // Present mode requested by Java; falls back to FIFO if unavailable. VkPresentModeKHR target_present_mode; + // Present mode actually selected by the last create_swapchain. + VkPresentModeKHR active_present_mode; } VkRenderer; // ============================================================ @@ -499,10 +682,7 @@ void vkr_image_barrier(VkCommandBuffer cmd, VkImage image, VkImageLayout f VkAccessFlags src_access, VkAccessFlags dst_access); bool vkr_create_sampler(VkRenderer* r, VkSamplerYcbcrConversion ycbcr, VkSampler* out); void vkr_retarget_shared_sampler(VkRenderer* r); -// Async layout transition through the staging pool. Submits a tiny command buffer that runs -// the requested barrier, but does NOT wait for the GPU. The barrier is ordered before all -// subsequent submits on the same queue per Vulkan spec, so callers can sample the image as -// soon as the next render submit happens. Returns false on submit failure. +// Async layout transition through the staging pool; returns false on submit failure. bool vkr_submit_async_transition(VkRenderer* r, VkImage image, VkImageLayout from, VkImageLayout to, VkPipelineStageFlags src_stage, VkPipelineStageFlags dst_stage, @@ -514,7 +694,6 @@ void vkr_staging_pool_destroy(VkRenderer* r); VkStagingSlot* vkr_staging_pool_acquire(VkRenderer* r, VkDeviceSize needed); void vkr_staging_pool_release(VkStagingSlot* slot); -// Image sub-allocator lifecycle (alloc/free are static in vk_image.c). Destroy after all -// textures are released. +// Image sub-allocator lifecycle (alloc/free are static in vk_image.c). void vkr_suballoc_init(VkRenderer* r); void vkr_suballoc_destroy(VkRenderer* r); diff --git a/app/src/main/cpp/winlator/vk/weights_v2/wnfg_05.weights.fp16 b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_05.weights.fp16 new file mode 100644 index 000000000..b4af922f1 Binary files /dev/null and b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_05.weights.fp16 differ diff --git a/app/src/main/cpp/winlator/vk/weights_v2/wnfg_06.weights.fp16 b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_06.weights.fp16 new file mode 100644 index 000000000..57f9ff40f --- /dev/null +++ b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_06.weights.fp16 @@ -0,0 +1,2 @@ +4i$X6@ E,2Ҟ+1b$a)/8p˶$,'P/'.t-z+n%-5TD+ l1 1mz-%/)*wh#ਗ8* ,F5G$2N'+Q,|%Ǩ^,a'B.117w2"(0u+s&Y ["T54p8;5A #4)ӫcХW4w5!L11+p +|'  (6*57" 1G/*41&..(:4s0&D5%97dy1W$mX1&z.DBH-E@.c4j5 \ No newline at end of file diff --git a/app/src/main/cpp/winlator/vk/weights_v2/wnfg_07.weights.fp16 b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_07.weights.fp16 new file mode 100644 index 000000000..e1f6c5cd2 Binary files /dev/null and b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_07.weights.fp16 differ diff --git a/app/src/main/cpp/winlator/vk/weights_v2/wnfg_14.weights.fp16 b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_14.weights.fp16 new file mode 100644 index 000000000..e91510017 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_14.weights.fp16 @@ -0,0 +1 @@ +KAqAMA{A|:;o:-;\2u5Y14AAIAnA::};);5414MA/;2 \ No newline at end of file diff --git a/app/src/main/cpp/winlator/vk/weights_v2/wnfg_20.weights.fp16 b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_20.weights.fp16 new file mode 100644 index 000000000..e91510017 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_20.weights.fp16 @@ -0,0 +1 @@ +KAqAMA{A|:;o:-;\2u5Y14AAIAnA::};);5414MA/;2 \ No newline at end of file diff --git a/app/src/main/cpp/winlator/vk/weights_v2/wnfg_21.weights.fp16 b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_21.weights.fp16 new file mode 100644 index 000000000..2d2803f43 Binary files /dev/null and b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_21.weights.fp16 differ diff --git a/app/src/main/cpp/winlator/vk/weights_v2/wnfg_22.weights.fp16 b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_22.weights.fp16 new file mode 100644 index 000000000..7f171f042 Binary files /dev/null and b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_22.weights.fp16 differ diff --git a/app/src/main/cpp/winlator/vk/weights_v2/wnfg_24.weights.fp16 b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_24.weights.fp16 new file mode 100644 index 000000000..485de28cc Binary files /dev/null and b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_24.weights.fp16 differ diff --git a/app/src/main/cpp/winlator/vk/weights_v2/wnfg_25.weights.fp16 b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_25.weights.fp16 new file mode 100644 index 000000000..cdd0e49ef Binary files /dev/null and b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_25.weights.fp16 differ diff --git a/app/src/main/cpp/winlator/vk/weights_v2/wnfg_26.weights.fp16 b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_26.weights.fp16 new file mode 100644 index 000000000..cd246d709 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_26.weights.fp16 @@ -0,0 +1,3 @@ +)$ +--뷒9U8̶16j+(w(,1Ƕ7 hW#,+á޻u6^7h18x:](S'0%0g,̰*7[쯶368/38)Y*l0}0R.053o1 83E8+a2AE6)1.#00q5AS4#vw.M(0¶1180455>)50*45l5 +,Z,1㥳>4+1ͷ 8ٶ7*40뼍3շ0'<8:I5'5886z86=گ \ No newline at end of file diff --git a/app/src/main/cpp/winlator/vk/weights_v2/wnfg_27.weights.fp16 b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_27.weights.fp16 new file mode 100644 index 000000000..b4325dbf0 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_27.weights.fp16 @@ -0,0 +1,2 @@ +T*87:ذ/470?5a׵4153+- +6/1̪ʰ$=ٴ +5.F,M:39l8mmIF^60. z-].h4M 2#21v5"жܶJ+u&0/8I0*3Q11Pƴ㻀4W_78oLQ9pf 4_շ(30L/|6V\#жз828M)E<8e Bq?_77{8.07̴j9 \ No newline at end of file diff --git a/app/src/main/cpp/winlator/vk/weights_v2/wnfg_28.weights.fp16 b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_28.weights.fp16 new file mode 100644 index 000000000..78540887b --- /dev/null +++ b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_28.weights.fp16 @@ -0,0 +1,3 @@ +a:+ʶTTuM Q4|,V805)v0+%5A9c4+5V41,,%19߶-Wۺ[68 Og8E2T.3K^3F4N31/^4޵k16"==.51/kܸӲ6+-;425B5q5-016s0:EIP'2H4_: +1]6 +;n4l`5''183 5/02F8\.|!+,Һ8"'j8J=϶9s8a9924:ܴ \ No newline at end of file diff --git a/app/src/main/cpp/winlator/vk/weights_v2/wnfg_29.weights.fp16 b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_29.weights.fp16 new file mode 100644 index 000000000..0a402285d Binary files /dev/null and b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_29.weights.fp16 differ diff --git a/app/src/main/cpp/winlator/vk/weights_v2/wnfg_36.weights.fp16 b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_36.weights.fp16 new file mode 100644 index 000000000..ae7fc52ed Binary files /dev/null and b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_36.weights.fp16 differ diff --git a/app/src/main/cpp/winlator/vk/weights_v2/wnfg_37.weights.fp16 b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_37.weights.fp16 new file mode 100644 index 000000000..5b40842e2 Binary files /dev/null and b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_37.weights.fp16 differ diff --git a/app/src/main/cpp/winlator/vk/weights_v2/wnfg_42.weights.fp16 b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_42.weights.fp16 new file mode 100644 index 000000000..bc15a8023 Binary files /dev/null and b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_42.weights.fp16 differ diff --git a/app/src/main/cpp/winlator/vk/weights_v2/wnfg_45.weights.fp16 b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_45.weights.fp16 new file mode 100644 index 000000000..a7052c1e6 Binary files /dev/null and b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_45.weights.fp16 differ diff --git a/app/src/main/cpp/winlator/vk/weights_v2/wnfg_51.weights.fp16 b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_51.weights.fp16 new file mode 100644 index 000000000..07be37715 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/weights_v2/wnfg_51.weights.fp16 @@ -0,0 +1,2 @@ +l8F,%3.23g40 d,I-˸(-O$[,.T%4ٰY.]/4<44 4(25`+m32,0*'ص"(*?.x/1?N42--33쭕C`S+g񲕬0h*u03ԥAt4U$0-s301N344x/5O1ٳv1³B!++ ǥ泍/0K 198S2b5&4_4"WT00.)Ͳbv4R2x3,[(520]0 4h685{4~- 4k4x4ήq+ԵX-k+6321w+*2I4ձ)Zn,<-&-t2F114&XV,R$:$2vϳ)`o:E2*4/-A.11u)/1Y0.R.-3.ұ/7>/>1.?c5ȯɲ,1120*/^2ͭ{,J'*.C/{"8- +,4-0K*-!ܧ1390k1Ͱ51,ͬTxG#10J.s1;43)'z,0.731f &0R*Ȯ~,0**$X!#!1*)101t101C3!,FD.R1ߧ0HةaJ+4u02/(m04z1I5-׬44{^-m1Ʈr´A -32*A,3 F5/3.(/u0,8~'=B+23el(0/v1e4*0!,24,Z0.3q5'{O[ޮ8П(Ѱ3|-6,/ +ӧuI f1A03-X2y4W, /+"E0/:2$Ք"D0q1=,~/438-LK5x6{(-B)).5J#u33i3.`44$6+55@6/&Fi.C,63/߮](c23Se@:Jй8806p8388!9F:ϧ$://Rj1 \ No newline at end of file diff --git a/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_04_spv.h b/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_04_spv.h new file mode 100644 index 000000000..d254a372f --- /dev/null +++ b/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_04_spv.h @@ -0,0 +1,115 @@ +#pragma once +#include +#include + +static const uint32_t wnfg_04_spv[] = { + 0x07230203, 0x00010000, 0x000d000b, 0x0000009a, 0x00000000, 0x00020011, 0x00000001, 0x00020011, + 0x00000032, 0x00020011, 0x00000038, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, + 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0006000f, 0x00000005, 0x00000002, 0x6e69616d, + 0x00000000, 0x00000003, 0x00060010, 0x00000002, 0x00000011, 0x00000010, 0x00000010, 0x00000001, + 0x00040047, 0x00000003, 0x0000000b, 0x0000001c, 0x00030047, 0x00000004, 0x00000019, 0x00040047, + 0x00000004, 0x00000021, 0x00000030, 0x00040047, 0x00000004, 0x00000022, 0x00000000, 0x00040047, + 0x00000005, 0x00000021, 0x00000020, 0x00040047, 0x00000005, 0x00000022, 0x00000000, 0x00040047, + 0x00000006, 0x00000021, 0x00000022, 0x00040047, 0x00000006, 0x00000022, 0x00000000, 0x00030047, + 0x00000007, 0x00000002, 0x00050048, 0x00000007, 0x00000000, 0x00000023, 0x00000000, 0x00050048, + 0x00000007, 0x00000001, 0x00000023, 0x00000004, 0x00050048, 0x00000007, 0x00000002, 0x00000023, + 0x00000008, 0x00040047, 0x00000008, 0x00000021, 0x00000000, 0x00040047, 0x00000008, 0x00000022, + 0x00000000, 0x00040047, 0x00000009, 0x00000021, 0x00000023, 0x00040047, 0x00000009, 0x00000022, + 0x00000000, 0x00040047, 0x0000000a, 0x00000021, 0x00000024, 0x00040047, 0x0000000a, 0x00000022, + 0x00000000, 0x00040047, 0x0000000b, 0x00000021, 0x00000021, 0x00040047, 0x0000000b, 0x00000022, + 0x00000000, 0x00040047, 0x0000000c, 0x0000000b, 0x00000019, 0x00020013, 0x0000000d, 0x00030021, + 0x0000000e, 0x0000000d, 0x00040015, 0x0000000f, 0x00000020, 0x00000001, 0x00040017, 0x00000010, + 0x0000000f, 0x00000002, 0x00040015, 0x00000011, 0x00000020, 0x00000000, 0x00040017, 0x00000012, + 0x00000011, 0x00000003, 0x00040020, 0x00000013, 0x00000001, 0x00000012, 0x0004003b, 0x00000013, + 0x00000003, 0x00000001, 0x00040017, 0x00000014, 0x00000011, 0x00000002, 0x00030016, 0x00000015, + 0x00000020, 0x00090019, 0x00000016, 0x00000015, 0x00000001, 0x00000000, 0x00000000, 0x00000000, + 0x00000002, 0x00000000, 0x00040020, 0x00000017, 0x00000000, 0x00000016, 0x0004003b, 0x00000017, + 0x00000004, 0x00000000, 0x00020014, 0x00000018, 0x00040017, 0x00000019, 0x00000018, 0x00000002, + 0x00090019, 0x0000001a, 0x00000015, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, + 0x00000000, 0x0003001b, 0x0000001b, 0x0000001a, 0x00040020, 0x0000001c, 0x00000000, 0x0000001b, + 0x0004003b, 0x0000001c, 0x00000005, 0x00000000, 0x0004002b, 0x0000000f, 0x0000001d, 0x00000000, + 0x00040017, 0x0000001e, 0x00000015, 0x00000002, 0x0004002b, 0x00000011, 0x0000001f, 0x00000000, + 0x0004002b, 0x00000011, 0x00000020, 0x00000001, 0x0004002b, 0x00000015, 0x00000021, 0x3f000000, + 0x0005002c, 0x0000001e, 0x00000022, 0x00000021, 0x00000021, 0x00040017, 0x00000023, 0x00000015, + 0x00000004, 0x0004003b, 0x0000001c, 0x00000006, 0x00000000, 0x0004002b, 0x00000015, 0x00000024, + 0x00000000, 0x0005001e, 0x00000007, 0x00000015, 0x00000015, 0x00000015, 0x00040020, 0x00000025, + 0x00000002, 0x00000007, 0x0004003b, 0x00000025, 0x00000008, 0x00000002, 0x00040020, 0x00000026, + 0x00000002, 0x00000015, 0x0004002b, 0x00000015, 0x00000027, 0x40000000, 0x0004002b, 0x0000000f, + 0x00000028, 0x00000001, 0x0004002b, 0x00000015, 0x00000029, 0x3f800000, 0x0004003b, 0x0000001c, + 0x00000009, 0x00000000, 0x0004003b, 0x0000001c, 0x0000000a, 0x00000000, 0x0004003b, 0x0000001c, + 0x0000000b, 0x00000000, 0x0004002b, 0x00000015, 0x0000002a, 0x322bcc77, 0x0004002b, 0x00000011, + 0x0000002b, 0x00000010, 0x0006002c, 0x00000012, 0x0000000c, 0x0000002b, 0x0000002b, 0x00000020, + 0x00050036, 0x0000000d, 0x00000002, 0x00000000, 0x0000000e, 0x000200f8, 0x0000002c, 0x000300f7, + 0x0000002d, 0x00000000, 0x000300fb, 0x0000001f, 0x0000002e, 0x000200f8, 0x0000002e, 0x0004003d, + 0x00000012, 0x0000002f, 0x00000003, 0x0007004f, 0x00000014, 0x00000030, 0x0000002f, 0x0000002f, + 0x00000000, 0x00000001, 0x0004007c, 0x00000010, 0x00000031, 0x00000030, 0x0004003d, 0x00000016, + 0x00000032, 0x00000004, 0x00040068, 0x00000010, 0x00000033, 0x00000032, 0x000500af, 0x00000019, + 0x00000034, 0x00000031, 0x00000033, 0x0004009a, 0x00000018, 0x00000035, 0x00000034, 0x000300f7, + 0x00000036, 0x00000000, 0x000400fa, 0x00000035, 0x00000037, 0x00000036, 0x000200f8, 0x00000037, + 0x000200f9, 0x0000002d, 0x000200f8, 0x00000036, 0x0004003d, 0x0000001b, 0x00000038, 0x00000005, + 0x00040064, 0x0000001a, 0x00000039, 0x00000038, 0x00050067, 0x00000010, 0x0000003a, 0x00000039, + 0x0000001d, 0x0004007c, 0x00000014, 0x0000003b, 0x0000003a, 0x00050051, 0x00000011, 0x0000003c, + 0x0000003b, 0x00000000, 0x00040070, 0x00000015, 0x0000003d, 0x0000003c, 0x00050051, 0x00000011, + 0x0000003e, 0x0000003b, 0x00000001, 0x00040070, 0x00000015, 0x0000003f, 0x0000003e, 0x00050050, + 0x0000001e, 0x00000040, 0x0000003d, 0x0000003f, 0x00040070, 0x0000001e, 0x00000041, 0x00000030, + 0x00050081, 0x0000001e, 0x00000042, 0x00000041, 0x00000022, 0x00050088, 0x0000001e, 0x00000043, + 0x00000042, 0x00000040, 0x0004003d, 0x0000001b, 0x00000044, 0x00000006, 0x00070058, 0x00000023, + 0x00000045, 0x00000044, 0x00000043, 0x00000002, 0x00000024, 0x00050041, 0x00000026, 0x00000046, + 0x00000008, 0x0000001d, 0x0004003d, 0x00000015, 0x00000047, 0x00000046, 0x0005008e, 0x00000023, + 0x00000048, 0x00000045, 0x00000047, 0x00050041, 0x00000026, 0x00000049, 0x00000008, 0x00000028, + 0x0004003d, 0x00000015, 0x0000004a, 0x00000049, 0x00050085, 0x00000015, 0x0000004b, 0x00000027, + 0x0000004a, 0x00050083, 0x00000015, 0x0000004c, 0x00000029, 0x0000004a, 0x00050085, 0x00000015, + 0x0000004d, 0x00000027, 0x0000004c, 0x0004003d, 0x0000001b, 0x0000004e, 0x00000009, 0x00070058, + 0x00000023, 0x0000004f, 0x0000004e, 0x00000043, 0x00000002, 0x00000024, 0x0005008e, 0x00000023, + 0x00000050, 0x0000004f, 0x00000047, 0x0007004f, 0x0000001e, 0x00000051, 0x00000048, 0x00000048, + 0x00000000, 0x00000001, 0x0005008e, 0x0000001e, 0x00000052, 0x00000051, 0x0000004b, 0x00050081, + 0x0000001e, 0x00000053, 0x00000042, 0x00000052, 0x00050088, 0x0000001e, 0x00000054, 0x00000053, + 0x00000040, 0x0007004f, 0x0000001e, 0x00000055, 0x00000048, 0x00000048, 0x00000002, 0x00000003, + 0x0005008e, 0x0000001e, 0x00000056, 0x00000055, 0x0000004d, 0x00050081, 0x0000001e, 0x00000057, + 0x00000042, 0x00000056, 0x00050088, 0x0000001e, 0x00000058, 0x00000057, 0x00000040, 0x0007004f, + 0x0000001e, 0x00000059, 0x00000050, 0x00000050, 0x00000000, 0x00000001, 0x0005008e, 0x0000001e, + 0x0000005a, 0x00000059, 0x0000004b, 0x00050081, 0x0000001e, 0x0000005b, 0x00000042, 0x0000005a, + 0x00050088, 0x0000001e, 0x0000005c, 0x0000005b, 0x00000040, 0x0007004f, 0x0000001e, 0x0000005d, + 0x00000050, 0x00000050, 0x00000002, 0x00000003, 0x0005008e, 0x0000001e, 0x0000005e, 0x0000005d, + 0x0000004d, 0x00050081, 0x0000001e, 0x0000005f, 0x00000042, 0x0000005e, 0x00050088, 0x0000001e, + 0x00000060, 0x0000005f, 0x00000040, 0x0004003d, 0x0000001b, 0x00000061, 0x0000000a, 0x00070058, + 0x00000023, 0x00000062, 0x00000061, 0x00000054, 0x00000002, 0x00000024, 0x00050051, 0x00000015, + 0x00000063, 0x00000062, 0x00000000, 0x0004003d, 0x0000001b, 0x00000064, 0x0000000a, 0x00070058, + 0x00000023, 0x00000065, 0x00000064, 0x00000058, 0x00000002, 0x00000024, 0x00050051, 0x00000015, + 0x00000066, 0x00000065, 0x00000001, 0x0004003d, 0x0000001b, 0x00000067, 0x0000000a, 0x00070058, + 0x00000023, 0x00000068, 0x00000067, 0x0000005c, 0x00000002, 0x00000024, 0x00050051, 0x00000015, + 0x00000069, 0x00000068, 0x00000002, 0x0004003d, 0x0000001b, 0x0000006a, 0x0000000a, 0x00070058, + 0x00000023, 0x0000006b, 0x0000006a, 0x00000060, 0x00000002, 0x00000024, 0x00050051, 0x00000015, + 0x0000006c, 0x0000006b, 0x00000003, 0x00070050, 0x00000023, 0x0000006d, 0x00000063, 0x00000066, + 0x00000069, 0x0000006c, 0x0006000c, 0x00000023, 0x0000006e, 0x00000001, 0x0000001b, 0x0000006d, + 0x00050051, 0x00000015, 0x0000006f, 0x0000006e, 0x00000000, 0x00050051, 0x00000015, 0x00000070, + 0x0000006e, 0x00000001, 0x00050081, 0x00000015, 0x00000071, 0x0000006f, 0x00000070, 0x00050051, + 0x00000015, 0x00000072, 0x0000006e, 0x00000002, 0x00050081, 0x00000015, 0x00000073, 0x00000071, + 0x00000072, 0x00050051, 0x00000015, 0x00000074, 0x0000006e, 0x00000003, 0x00050081, 0x00000015, + 0x00000075, 0x00000073, 0x00000074, 0x00070050, 0x00000023, 0x00000076, 0x00000075, 0x00000075, + 0x00000075, 0x00000075, 0x00050088, 0x00000023, 0x00000077, 0x0000006e, 0x00000076, 0x00050051, + 0x00000015, 0x00000078, 0x00000077, 0x00000000, 0x00050051, 0x00000015, 0x00000079, 0x00000077, + 0x00000001, 0x00050051, 0x00000015, 0x0000007a, 0x00000077, 0x00000002, 0x00050051, 0x00000015, + 0x0000007b, 0x00000077, 0x00000003, 0x0004003d, 0x00000016, 0x0000007c, 0x00000004, 0x0004003d, + 0x0000001b, 0x0000007d, 0x00000005, 0x00070058, 0x00000023, 0x0000007e, 0x0000007d, 0x00000054, + 0x00000002, 0x00000024, 0x0005008e, 0x00000023, 0x0000007f, 0x0000007e, 0x0000004c, 0x0005008e, + 0x00000023, 0x00000080, 0x0000007f, 0x00000078, 0x0004003d, 0x0000001b, 0x00000081, 0x0000000b, + 0x00070058, 0x00000023, 0x00000082, 0x00000081, 0x00000058, 0x00000002, 0x00000024, 0x0005008e, + 0x00000023, 0x00000083, 0x00000082, 0x0000004a, 0x0005008e, 0x00000023, 0x00000084, 0x00000083, + 0x00000079, 0x00050081, 0x00000023, 0x00000085, 0x00000080, 0x00000084, 0x0004003d, 0x0000001b, + 0x00000086, 0x00000005, 0x00070058, 0x00000023, 0x00000087, 0x00000086, 0x0000005c, 0x00000002, + 0x00000024, 0x0005008e, 0x00000023, 0x00000088, 0x00000087, 0x0000004c, 0x0005008e, 0x00000023, + 0x00000089, 0x00000088, 0x0000007a, 0x00050081, 0x00000023, 0x0000008a, 0x00000085, 0x00000089, + 0x0004003d, 0x0000001b, 0x0000008b, 0x0000000b, 0x00070058, 0x00000023, 0x0000008c, 0x0000008b, + 0x00000060, 0x00000002, 0x00000024, 0x0005008e, 0x00000023, 0x0000008d, 0x0000008c, 0x0000004a, + 0x0005008e, 0x00000023, 0x0000008e, 0x0000008d, 0x0000007b, 0x00050081, 0x00000023, 0x0000008f, + 0x0000008a, 0x0000008e, 0x00050085, 0x00000015, 0x00000090, 0x0000004c, 0x00000078, 0x00050085, + 0x00000015, 0x00000091, 0x0000004a, 0x00000079, 0x00050081, 0x00000015, 0x00000092, 0x00000090, + 0x00000091, 0x00050085, 0x00000015, 0x00000093, 0x0000004c, 0x0000007a, 0x00050081, 0x00000015, + 0x00000094, 0x00000092, 0x00000093, 0x00050085, 0x00000015, 0x00000095, 0x0000004a, 0x0000007b, + 0x00050081, 0x00000015, 0x00000096, 0x00000094, 0x00000095, 0x00050081, 0x00000015, 0x00000097, + 0x00000096, 0x0000002a, 0x00070050, 0x00000023, 0x00000098, 0x00000097, 0x00000097, 0x00000097, + 0x00000097, 0x00050088, 0x00000023, 0x00000099, 0x0000008f, 0x00000098, 0x00040063, 0x0000007c, + 0x00000031, 0x00000099, 0x000200f9, 0x0000002d, 0x000200f8, 0x0000002d, 0x000100fd, 0x00010038, +}; +static const size_t wnfg_04_spv_size = sizeof(wnfg_04_spv); diff --git a/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_13_spv.h b/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_13_spv.h new file mode 100644 index 000000000..24e8381ec --- /dev/null +++ b/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_13_spv.h @@ -0,0 +1,371 @@ +#pragma once +#include +#include + +static const uint32_t wnfg_13_spv[] = { + 0x07230203, 0x00010000, 0x000d000b, 0x00000225, 0x00000000, 0x00020011, 0x00000001, 0x00020011, + 0x00000009, 0x00020011, 0x00000031, 0x00020011, 0x00000032, 0x0006000b, 0x00000001, 0x4c534c47, + 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0007000f, 0x00000005, + 0x00000002, 0x6e69616d, 0x00000000, 0x00000003, 0x00000004, 0x00060010, 0x00000002, 0x00000011, + 0x00000010, 0x00000010, 0x00000001, 0x00040047, 0x00000005, 0x00000021, 0x00000020, 0x00040047, + 0x00000005, 0x00000022, 0x00000000, 0x00040047, 0x00000006, 0x00000021, 0x00000021, 0x00040047, + 0x00000006, 0x00000022, 0x00000000, 0x00030047, 0x00000007, 0x00000002, 0x00050048, 0x00000007, + 0x00000000, 0x00000023, 0x00000000, 0x00050048, 0x00000007, 0x00000001, 0x00000023, 0x00000004, + 0x00050048, 0x00000007, 0x00000002, 0x00000023, 0x00000008, 0x00040047, 0x00000008, 0x00000021, + 0x00000000, 0x00040047, 0x00000008, 0x00000022, 0x00000000, 0x00040047, 0x00000003, 0x0000000b, + 0x0000001a, 0x00040047, 0x00000004, 0x0000000b, 0x0000001b, 0x00030047, 0x00000009, 0x00000019, + 0x00040047, 0x00000009, 0x00000021, 0x00000030, 0x00040047, 0x00000009, 0x00000022, 0x00000000, + 0x00030047, 0x0000000a, 0x00000019, 0x00040047, 0x0000000a, 0x00000021, 0x00000031, 0x00040047, + 0x0000000a, 0x00000022, 0x00000000, 0x00030047, 0x0000000b, 0x00000019, 0x00040047, 0x0000000b, + 0x00000021, 0x00000032, 0x00040047, 0x0000000b, 0x00000022, 0x00000000, 0x00030047, 0x0000000c, + 0x00000019, 0x00040047, 0x0000000c, 0x00000021, 0x00000033, 0x00040047, 0x0000000c, 0x00000022, + 0x00000000, 0x00030047, 0x0000000d, 0x00000019, 0x00040047, 0x0000000d, 0x00000021, 0x00000034, + 0x00040047, 0x0000000d, 0x00000022, 0x00000000, 0x00030047, 0x0000000e, 0x00000019, 0x00040047, + 0x0000000e, 0x00000021, 0x00000035, 0x00040047, 0x0000000e, 0x00000022, 0x00000000, 0x00040047, + 0x0000000f, 0x0000000b, 0x00000019, 0x00020013, 0x00000010, 0x00030021, 0x00000011, 0x00000010, + 0x00040015, 0x00000012, 0x00000020, 0x00000000, 0x00040017, 0x00000013, 0x00000012, 0x00000002, + 0x00030016, 0x00000014, 0x00000020, 0x00040017, 0x00000015, 0x00000014, 0x00000002, 0x00030016, + 0x00000016, 0x00000010, 0x00040015, 0x00000017, 0x00000020, 0x00000001, 0x00040017, 0x00000018, + 0x00000017, 0x00000002, 0x0004002b, 0x00000017, 0x00000019, 0x00000001, 0x0005002c, 0x00000018, + 0x0000001a, 0x00000019, 0x00000019, 0x00090019, 0x0000001b, 0x00000014, 0x00000001, 0x00000000, + 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x0003001b, 0x0000001c, 0x0000001b, 0x00040020, + 0x0000001d, 0x00000000, 0x0000001c, 0x0004003b, 0x0000001d, 0x00000005, 0x00000000, 0x0004002b, + 0x00000017, 0x0000001e, 0xffffffff, 0x0005002c, 0x00000018, 0x0000001f, 0x0000001e, 0x0000001e, + 0x0004002b, 0x00000017, 0x00000020, 0x00000000, 0x0005002c, 0x00000018, 0x00000021, 0x00000020, + 0x00000020, 0x00040017, 0x00000022, 0x00000014, 0x00000004, 0x00040017, 0x00000023, 0x00000016, + 0x00000004, 0x0004002b, 0x00000016, 0x00000024, 0x000039ad, 0x0004002b, 0x00000016, 0x00000025, + 0x0000b695, 0x0004002b, 0x00000016, 0x00000026, 0x0000b6f7, 0x0004002b, 0x00000016, 0x00000027, + 0x0000b8a8, 0x0007002c, 0x00000023, 0x00000028, 0x00000024, 0x00000025, 0x00000026, 0x00000027, + 0x0005002c, 0x00000018, 0x00000029, 0x0000001e, 0x00000020, 0x0004002b, 0x00000016, 0x0000002a, + 0x00003965, 0x0004002b, 0x00000016, 0x0000002b, 0x0000b4c2, 0x0004002b, 0x00000016, 0x0000002c, + 0x0000b7c5, 0x0004002b, 0x00000016, 0x0000002d, 0x0000bc55, 0x0007002c, 0x00000023, 0x0000002e, + 0x0000002a, 0x0000002b, 0x0000002c, 0x0000002d, 0x0005002c, 0x00000018, 0x0000002f, 0x0000001e, + 0x00000019, 0x0004002b, 0x00000016, 0x00000030, 0x00003c71, 0x0004002b, 0x00000016, 0x00000031, + 0x0000b8b0, 0x0004002b, 0x00000016, 0x00000032, 0x0000b918, 0x0004002b, 0x00000016, 0x00000033, + 0x0000bcac, 0x0007002c, 0x00000023, 0x00000034, 0x00000030, 0x00000031, 0x00000032, 0x00000033, + 0x0005002c, 0x00000018, 0x00000035, 0x00000020, 0x0000001e, 0x0004002b, 0x00000016, 0x00000036, + 0x0000350e, 0x0004002b, 0x00000016, 0x00000037, 0x0000b748, 0x0004002b, 0x00000016, 0x00000038, + 0x0000b899, 0x0004002b, 0x00000016, 0x00000039, 0x0000bb11, 0x0007002c, 0x00000023, 0x0000003a, + 0x00000036, 0x00000037, 0x00000038, 0x00000039, 0x0004002b, 0x00000016, 0x0000003b, 0x0000336e, + 0x0004002b, 0x00000016, 0x0000003c, 0x0000b2fa, 0x0004002b, 0x00000016, 0x0000003d, 0x0000b81f, + 0x0004002b, 0x00000016, 0x0000003e, 0x0000be73, 0x0007002c, 0x00000023, 0x0000003f, 0x0000003b, + 0x0000003c, 0x0000003d, 0x0000003e, 0x0005002c, 0x00000018, 0x00000040, 0x00000020, 0x00000019, + 0x0004002b, 0x00000016, 0x00000041, 0x000039ab, 0x0004002b, 0x00000016, 0x00000042, 0x0000b806, + 0x0004002b, 0x00000016, 0x00000043, 0x0000b910, 0x0004002b, 0x00000016, 0x00000044, 0x0000be84, + 0x0007002c, 0x00000023, 0x00000045, 0x00000041, 0x00000042, 0x00000043, 0x00000044, 0x0005002c, + 0x00000018, 0x00000046, 0x00000019, 0x0000001e, 0x0004002b, 0x00000016, 0x00000047, 0x00003ace, + 0x0004002b, 0x00000016, 0x00000048, 0x0000b984, 0x0004002b, 0x00000016, 0x00000049, 0x0000bb07, + 0x0004002b, 0x00000016, 0x0000004a, 0x0000b9c1, 0x0007002c, 0x00000023, 0x0000004b, 0x00000047, + 0x00000048, 0x00000049, 0x0000004a, 0x0005002c, 0x00000018, 0x0000004c, 0x00000019, 0x00000020, + 0x0004002b, 0x00000016, 0x0000004d, 0x000039b4, 0x0004002b, 0x00000016, 0x0000004e, 0x0000b843, + 0x0004002b, 0x00000016, 0x0000004f, 0x0000ba1f, 0x0004002b, 0x00000016, 0x00000050, 0x0000bb31, + 0x0007002c, 0x00000023, 0x00000051, 0x0000004d, 0x0000004e, 0x0000004f, 0x00000050, 0x0004002b, + 0x00000016, 0x00000052, 0x00003c74, 0x0004002b, 0x00000016, 0x00000053, 0x0000ba1c, 0x0004002b, + 0x00000016, 0x00000054, 0x0000bb03, 0x0004002b, 0x00000016, 0x00000055, 0x0000bcaa, 0x0007002c, + 0x00000023, 0x00000056, 0x00000052, 0x00000053, 0x00000054, 0x00000055, 0x0004003b, 0x0000001d, + 0x00000006, 0x00000000, 0x0004002b, 0x00000016, 0x00000057, 0x0000ba22, 0x0004002b, 0x00000016, + 0x00000058, 0x00003aea, 0x0004002b, 0x00000016, 0x00000059, 0x0000b853, 0x0004002b, 0x00000016, + 0x0000005a, 0x00003828, 0x0007002c, 0x00000023, 0x0000005b, 0x00000057, 0x00000058, 0x00000059, + 0x0000005a, 0x0004002b, 0x00000016, 0x0000005c, 0x0000bbb1, 0x0004002b, 0x00000016, 0x0000005d, + 0x000039df, 0x0004002b, 0x00000016, 0x0000005e, 0x0000b8f6, 0x0004002b, 0x00000016, 0x0000005f, + 0x000038c0, 0x0007002c, 0x00000023, 0x00000060, 0x0000005c, 0x0000005d, 0x0000005e, 0x0000005f, + 0x0004002b, 0x00000016, 0x00000061, 0x0000bd85, 0x0004002b, 0x00000016, 0x00000062, 0x00003b69, + 0x0004002b, 0x00000016, 0x00000063, 0x0000ba37, 0x0004002b, 0x00000016, 0x00000064, 0x000039d5, + 0x0007002c, 0x00000023, 0x00000065, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x0004002b, + 0x00000016, 0x00000066, 0x0000b8e7, 0x0004002b, 0x00000016, 0x00000067, 0x00003952, 0x0004002b, + 0x00000016, 0x00000068, 0x0000b8de, 0x0004002b, 0x00000016, 0x00000069, 0x00003913, 0x0007002c, + 0x00000023, 0x0000006a, 0x00000066, 0x00000067, 0x00000068, 0x00000069, 0x0004002b, 0x00000016, + 0x0000006b, 0x0000b7a8, 0x0004002b, 0x00000016, 0x0000006c, 0x000036eb, 0x0004002b, 0x00000016, + 0x0000006d, 0x0000b919, 0x0004002b, 0x00000016, 0x0000006e, 0x000038ea, 0x0007002c, 0x00000023, + 0x0000006f, 0x0000006b, 0x0000006c, 0x0000006d, 0x0000006e, 0x0004002b, 0x00000016, 0x00000070, + 0x0000ba7c, 0x0004002b, 0x00000016, 0x00000071, 0x000038b8, 0x0004002b, 0x00000016, 0x00000072, + 0x0000b99f, 0x0004002b, 0x00000016, 0x00000073, 0x000039f8, 0x0007002c, 0x00000023, 0x00000074, + 0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x0004002b, 0x00000016, 0x00000075, 0x0000bca0, + 0x0004002b, 0x00000016, 0x00000076, 0x00003aa3, 0x0004002b, 0x00000016, 0x00000077, 0x0000ba8e, + 0x0004002b, 0x00000016, 0x00000078, 0x00003ab6, 0x0007002c, 0x00000023, 0x00000079, 0x00000075, + 0x00000076, 0x00000077, 0x00000078, 0x0004002b, 0x00000016, 0x0000007a, 0x0000bbcf, 0x0004002b, + 0x00000016, 0x0000007b, 0x00003963, 0x0004002b, 0x00000016, 0x0000007c, 0x0000ba64, 0x0004002b, + 0x00000016, 0x0000007d, 0x00003a9e, 0x0007002c, 0x00000023, 0x0000007e, 0x0000007a, 0x0000007b, + 0x0000007c, 0x0000007d, 0x0004002b, 0x00000016, 0x0000007f, 0x0000bd30, 0x0004002b, 0x00000016, + 0x00000080, 0x0000ba5a, 0x0004002b, 0x00000016, 0x00000081, 0x00003bb8, 0x0007002c, 0x00000023, + 0x00000082, 0x0000007f, 0x00000078, 0x00000080, 0x00000081, 0x0004002b, 0x00000016, 0x00000083, + 0x00003c00, 0x0004002b, 0x00000016, 0x00000084, 0x000032e4, 0x0005001e, 0x00000007, 0x00000014, + 0x00000014, 0x00000014, 0x00040020, 0x00000085, 0x00000002, 0x00000007, 0x0004003b, 0x00000085, + 0x00000008, 0x00000002, 0x0004002b, 0x00000017, 0x00000086, 0x00000002, 0x00040020, 0x00000087, + 0x00000002, 0x00000014, 0x0004002b, 0x00000012, 0x00000088, 0x00000000, 0x0004002b, 0x00000012, + 0x00000089, 0x00000001, 0x00040017, 0x0000008a, 0x00000012, 0x00000003, 0x00040020, 0x0000008b, + 0x00000001, 0x0000008a, 0x0004003b, 0x0000008b, 0x00000003, 0x00000001, 0x0004002b, 0x00000012, + 0x0000008c, 0x00000020, 0x0005002c, 0x00000013, 0x0000008d, 0x0000008c, 0x0000008c, 0x0004003b, + 0x0000008b, 0x00000004, 0x00000001, 0x0004002b, 0x00000012, 0x0000008e, 0x00000002, 0x0005002c, + 0x00000013, 0x0000008f, 0x0000008e, 0x0000008e, 0x00020014, 0x00000090, 0x00090019, 0x00000091, + 0x00000014, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0x0000000f, 0x00040020, + 0x00000092, 0x00000000, 0x00000091, 0x0004003b, 0x00000092, 0x00000009, 0x00000000, 0x00040017, + 0x00000093, 0x00000090, 0x00000002, 0x0004001c, 0x00000094, 0x00000016, 0x0000008c, 0x0004001c, + 0x00000095, 0x00000094, 0x0000008c, 0x00040020, 0x00000096, 0x00000004, 0x00000095, 0x0004003b, + 0x00000096, 0x00000097, 0x00000004, 0x00040020, 0x00000098, 0x00000004, 0x00000016, 0x0004002b, + 0x00000012, 0x00000099, 0x00000108, 0x00040020, 0x0000009a, 0x00000001, 0x00000012, 0x0004002b, + 0x00000012, 0x0000009b, 0x00000010, 0x0004002b, 0x00000016, 0x0000009c, 0x00003400, 0x0005002c, + 0x00000013, 0x0000009d, 0x0000009b, 0x0000009b, 0x0004003b, 0x00000092, 0x0000000a, 0x00000000, + 0x0004002b, 0x00000012, 0x0000009e, 0x00000008, 0x0005002c, 0x00000013, 0x0000009f, 0x0000009e, + 0x0000009e, 0x0004003b, 0x00000092, 0x0000000b, 0x00000000, 0x0004002b, 0x00000012, 0x000000a0, + 0x00000004, 0x0005002c, 0x00000013, 0x000000a1, 0x000000a0, 0x000000a0, 0x0004003b, 0x00000092, + 0x0000000c, 0x00000000, 0x0004003b, 0x00000092, 0x0000000d, 0x00000000, 0x0004003b, 0x00000092, + 0x0000000e, 0x00000000, 0x0006002c, 0x0000008a, 0x0000000f, 0x0000009b, 0x0000009b, 0x00000089, + 0x00030029, 0x00000090, 0x000000a2, 0x0005002c, 0x00000013, 0x000000a3, 0x00000088, 0x00000088, + 0x00050036, 0x00000010, 0x00000002, 0x00000000, 0x00000011, 0x000200f8, 0x000000a4, 0x0004003d, + 0x0000001c, 0x000000a5, 0x00000005, 0x00040064, 0x0000001b, 0x000000a6, 0x000000a5, 0x00050067, + 0x00000018, 0x000000a7, 0x000000a6, 0x00000020, 0x0004007c, 0x00000013, 0x000000a8, 0x000000a7, + 0x00050051, 0x00000012, 0x000000a9, 0x000000a8, 0x00000000, 0x00040070, 0x00000014, 0x000000aa, + 0x000000a9, 0x00050051, 0x00000012, 0x000000ab, 0x000000a8, 0x00000001, 0x00040070, 0x00000014, + 0x000000ac, 0x000000ab, 0x00050050, 0x00000015, 0x000000ad, 0x000000aa, 0x000000ac, 0x0004003d, + 0x0000008a, 0x000000ae, 0x00000003, 0x0007004f, 0x00000013, 0x000000af, 0x000000ae, 0x000000ae, + 0x00000000, 0x00000001, 0x00050084, 0x00000013, 0x000000b0, 0x000000af, 0x0000008d, 0x0004003d, + 0x0000008a, 0x000000b1, 0x00000004, 0x0007004f, 0x00000013, 0x000000b2, 0x000000b1, 0x000000b1, + 0x00000000, 0x00000001, 0x00050084, 0x00000013, 0x000000b3, 0x000000b2, 0x0000008f, 0x000200f9, + 0x000000b4, 0x000200f8, 0x000000b4, 0x000700f5, 0x00000012, 0x000000b5, 0x00000088, 0x000000a4, + 0x000000b6, 0x000000b7, 0x000500b0, 0x00000090, 0x000000b8, 0x000000b5, 0x0000008e, 0x000400f6, + 0x000000b9, 0x000000b7, 0x00000000, 0x000400fa, 0x000000b8, 0x000000ba, 0x000000b9, 0x000200f8, + 0x000000ba, 0x000200f9, 0x000000bb, 0x000200f8, 0x000000bb, 0x000700f5, 0x00000012, 0x000000bc, + 0x00000088, 0x000000ba, 0x000000bd, 0x000000be, 0x000500b0, 0x00000090, 0x000000bf, 0x000000bc, + 0x0000008e, 0x000400f6, 0x000000c0, 0x000000be, 0x00000000, 0x000400fa, 0x000000bf, 0x000000c1, + 0x000000c0, 0x000200f8, 0x000000c1, 0x00050080, 0x00000013, 0x000000c2, 0x000000b0, 0x000000b3, + 0x00050050, 0x00000013, 0x000000c3, 0x000000bc, 0x000000b5, 0x00050080, 0x00000013, 0x000000c4, + 0x000000c2, 0x000000c3, 0x0004007c, 0x00000018, 0x000000c5, 0x000000c4, 0x0004006e, 0x00000018, + 0x000000c6, 0x000000ad, 0x00050082, 0x00000018, 0x000000c7, 0x000000c6, 0x0000001a, 0x0004003d, + 0x0000001c, 0x000000c8, 0x00000005, 0x00050080, 0x00000018, 0x000000c9, 0x000000c5, 0x0000001f, + 0x0008000c, 0x00000018, 0x000000ca, 0x00000001, 0x0000002d, 0x000000c9, 0x00000021, 0x000000c7, + 0x00040064, 0x0000001b, 0x000000cb, 0x000000c8, 0x0007005f, 0x00000022, 0x000000cc, 0x000000cb, + 0x000000ca, 0x00000002, 0x00000020, 0x00040073, 0x00000023, 0x000000cd, 0x000000cc, 0x00050094, + 0x00000016, 0x000000ce, 0x000000cd, 0x00000028, 0x0004003d, 0x0000001c, 0x000000cf, 0x00000005, + 0x00050080, 0x00000018, 0x000000d0, 0x000000c5, 0x00000029, 0x0008000c, 0x00000018, 0x000000d1, + 0x00000001, 0x0000002d, 0x000000d0, 0x00000021, 0x000000c7, 0x00040064, 0x0000001b, 0x000000d2, + 0x000000cf, 0x0007005f, 0x00000022, 0x000000d3, 0x000000d2, 0x000000d1, 0x00000002, 0x00000020, + 0x00040073, 0x00000023, 0x000000d4, 0x000000d3, 0x00050094, 0x00000016, 0x000000d5, 0x000000d4, + 0x0000002e, 0x00050081, 0x00000016, 0x000000d6, 0x000000ce, 0x000000d5, 0x0004003d, 0x0000001c, + 0x000000d7, 0x00000005, 0x00050080, 0x00000018, 0x000000d8, 0x000000c5, 0x0000002f, 0x0008000c, + 0x00000018, 0x000000d9, 0x00000001, 0x0000002d, 0x000000d8, 0x00000021, 0x000000c7, 0x00040064, + 0x0000001b, 0x000000da, 0x000000d7, 0x0007005f, 0x00000022, 0x000000db, 0x000000da, 0x000000d9, + 0x00000002, 0x00000020, 0x00040073, 0x00000023, 0x000000dc, 0x000000db, 0x00050094, 0x00000016, + 0x000000dd, 0x000000dc, 0x00000034, 0x00050081, 0x00000016, 0x000000de, 0x000000d6, 0x000000dd, + 0x0004003d, 0x0000001c, 0x000000df, 0x00000005, 0x00050080, 0x00000018, 0x000000e0, 0x000000c5, + 0x00000035, 0x0008000c, 0x00000018, 0x000000e1, 0x00000001, 0x0000002d, 0x000000e0, 0x00000021, + 0x000000c7, 0x00040064, 0x0000001b, 0x000000e2, 0x000000df, 0x0007005f, 0x00000022, 0x000000e3, + 0x000000e2, 0x000000e1, 0x00000002, 0x00000020, 0x00040073, 0x00000023, 0x000000e4, 0x000000e3, + 0x00050094, 0x00000016, 0x000000e5, 0x000000e4, 0x0000003a, 0x00050081, 0x00000016, 0x000000e6, + 0x000000de, 0x000000e5, 0x0004003d, 0x0000001c, 0x000000e7, 0x00000005, 0x0008000c, 0x00000018, + 0x000000e8, 0x00000001, 0x0000002d, 0x000000c5, 0x00000021, 0x000000c7, 0x00040064, 0x0000001b, + 0x000000e9, 0x000000e7, 0x0007005f, 0x00000022, 0x000000ea, 0x000000e9, 0x000000e8, 0x00000002, + 0x00000020, 0x00040073, 0x00000023, 0x000000eb, 0x000000ea, 0x00050094, 0x00000016, 0x000000ec, + 0x000000eb, 0x0000003f, 0x00050081, 0x00000016, 0x000000ed, 0x000000e6, 0x000000ec, 0x0004003d, + 0x0000001c, 0x000000ee, 0x00000005, 0x00050080, 0x00000018, 0x000000ef, 0x000000c5, 0x00000040, + 0x0008000c, 0x00000018, 0x000000f0, 0x00000001, 0x0000002d, 0x000000ef, 0x00000021, 0x000000c7, + 0x00040064, 0x0000001b, 0x000000f1, 0x000000ee, 0x0007005f, 0x00000022, 0x000000f2, 0x000000f1, + 0x000000f0, 0x00000002, 0x00000020, 0x00040073, 0x00000023, 0x000000f3, 0x000000f2, 0x00050094, + 0x00000016, 0x000000f4, 0x000000f3, 0x00000045, 0x00050081, 0x00000016, 0x000000f5, 0x000000ed, + 0x000000f4, 0x0004003d, 0x0000001c, 0x000000f6, 0x00000005, 0x00050080, 0x00000018, 0x000000f7, + 0x000000c5, 0x00000046, 0x0008000c, 0x00000018, 0x000000f8, 0x00000001, 0x0000002d, 0x000000f7, + 0x00000021, 0x000000c7, 0x00040064, 0x0000001b, 0x000000f9, 0x000000f6, 0x0007005f, 0x00000022, + 0x000000fa, 0x000000f9, 0x000000f8, 0x00000002, 0x00000020, 0x00040073, 0x00000023, 0x000000fb, + 0x000000fa, 0x00050094, 0x00000016, 0x000000fc, 0x000000fb, 0x0000004b, 0x00050081, 0x00000016, + 0x000000fd, 0x000000f5, 0x000000fc, 0x0004003d, 0x0000001c, 0x000000fe, 0x00000005, 0x00050080, + 0x00000018, 0x000000ff, 0x000000c5, 0x0000004c, 0x0008000c, 0x00000018, 0x00000100, 0x00000001, + 0x0000002d, 0x000000ff, 0x00000021, 0x000000c7, 0x00040064, 0x0000001b, 0x00000101, 0x000000fe, + 0x0007005f, 0x00000022, 0x00000102, 0x00000101, 0x00000100, 0x00000002, 0x00000020, 0x00040073, + 0x00000023, 0x00000103, 0x00000102, 0x00050094, 0x00000016, 0x00000104, 0x00000103, 0x00000051, + 0x00050081, 0x00000016, 0x00000105, 0x000000fd, 0x00000104, 0x0004003d, 0x0000001c, 0x00000106, + 0x00000005, 0x00050080, 0x00000018, 0x00000107, 0x000000c5, 0x0000001a, 0x0008000c, 0x00000018, + 0x00000108, 0x00000001, 0x0000002d, 0x00000107, 0x00000021, 0x000000c7, 0x00040064, 0x0000001b, + 0x00000109, 0x00000106, 0x0007005f, 0x00000022, 0x0000010a, 0x00000109, 0x00000108, 0x00000002, + 0x00000020, 0x00040073, 0x00000023, 0x0000010b, 0x0000010a, 0x00050094, 0x00000016, 0x0000010c, + 0x0000010b, 0x00000056, 0x00050081, 0x00000016, 0x0000010d, 0x00000105, 0x0000010c, 0x0004003d, + 0x0000001c, 0x0000010e, 0x00000006, 0x00040064, 0x0000001b, 0x0000010f, 0x0000010e, 0x0007005f, + 0x00000022, 0x00000110, 0x0000010f, 0x000000ca, 0x00000002, 0x00000020, 0x00040073, 0x00000023, + 0x00000111, 0x00000110, 0x00050094, 0x00000016, 0x00000112, 0x00000111, 0x0000005b, 0x00050081, + 0x00000016, 0x00000113, 0x0000010d, 0x00000112, 0x0004003d, 0x0000001c, 0x00000114, 0x00000006, + 0x00040064, 0x0000001b, 0x00000115, 0x00000114, 0x0007005f, 0x00000022, 0x00000116, 0x00000115, + 0x000000d1, 0x00000002, 0x00000020, 0x00040073, 0x00000023, 0x00000117, 0x00000116, 0x00050094, + 0x00000016, 0x00000118, 0x00000117, 0x00000060, 0x00050081, 0x00000016, 0x00000119, 0x00000113, + 0x00000118, 0x0004003d, 0x0000001c, 0x0000011a, 0x00000006, 0x00040064, 0x0000001b, 0x0000011b, + 0x0000011a, 0x0007005f, 0x00000022, 0x0000011c, 0x0000011b, 0x000000d9, 0x00000002, 0x00000020, + 0x00040073, 0x00000023, 0x0000011d, 0x0000011c, 0x00050094, 0x00000016, 0x0000011e, 0x0000011d, + 0x00000065, 0x00050081, 0x00000016, 0x0000011f, 0x00000119, 0x0000011e, 0x0004003d, 0x0000001c, + 0x00000120, 0x00000006, 0x00040064, 0x0000001b, 0x00000121, 0x00000120, 0x0007005f, 0x00000022, + 0x00000122, 0x00000121, 0x000000e1, 0x00000002, 0x00000020, 0x00040073, 0x00000023, 0x00000123, + 0x00000122, 0x00050094, 0x00000016, 0x00000124, 0x00000123, 0x0000006a, 0x00050081, 0x00000016, + 0x00000125, 0x0000011f, 0x00000124, 0x0004003d, 0x0000001c, 0x00000126, 0x00000006, 0x00040064, + 0x0000001b, 0x00000127, 0x00000126, 0x0007005f, 0x00000022, 0x00000128, 0x00000127, 0x000000e8, + 0x00000002, 0x00000020, 0x00040073, 0x00000023, 0x00000129, 0x00000128, 0x00050094, 0x00000016, + 0x0000012a, 0x00000129, 0x0000006f, 0x00050081, 0x00000016, 0x0000012b, 0x00000125, 0x0000012a, + 0x0004003d, 0x0000001c, 0x0000012c, 0x00000006, 0x00040064, 0x0000001b, 0x0000012d, 0x0000012c, + 0x0007005f, 0x00000022, 0x0000012e, 0x0000012d, 0x000000f0, 0x00000002, 0x00000020, 0x00040073, + 0x00000023, 0x0000012f, 0x0000012e, 0x00050094, 0x00000016, 0x00000130, 0x0000012f, 0x00000074, + 0x00050081, 0x00000016, 0x00000131, 0x0000012b, 0x00000130, 0x0004003d, 0x0000001c, 0x00000132, + 0x00000006, 0x00040064, 0x0000001b, 0x00000133, 0x00000132, 0x0007005f, 0x00000022, 0x00000134, + 0x00000133, 0x000000f8, 0x00000002, 0x00000020, 0x00040073, 0x00000023, 0x00000135, 0x00000134, + 0x00050094, 0x00000016, 0x00000136, 0x00000135, 0x00000079, 0x00050081, 0x00000016, 0x00000137, + 0x00000131, 0x00000136, 0x0004003d, 0x0000001c, 0x00000138, 0x00000006, 0x00040064, 0x0000001b, + 0x00000139, 0x00000138, 0x0007005f, 0x00000022, 0x0000013a, 0x00000139, 0x00000100, 0x00000002, + 0x00000020, 0x00040073, 0x00000023, 0x0000013b, 0x0000013a, 0x00050094, 0x00000016, 0x0000013c, + 0x0000013b, 0x0000007e, 0x00050081, 0x00000016, 0x0000013d, 0x00000137, 0x0000013c, 0x0004003d, + 0x0000001c, 0x0000013e, 0x00000006, 0x00040064, 0x0000001b, 0x0000013f, 0x0000013e, 0x0007005f, + 0x00000022, 0x00000140, 0x0000013f, 0x00000108, 0x00000002, 0x00000020, 0x00040073, 0x00000023, + 0x00000141, 0x00000140, 0x00050094, 0x00000016, 0x00000142, 0x00000141, 0x00000082, 0x00050081, + 0x00000016, 0x00000143, 0x0000013d, 0x00000142, 0x00050081, 0x00000016, 0x00000144, 0x00000143, + 0x00000084, 0x0004007f, 0x00000016, 0x00000145, 0x00000144, 0x0006000c, 0x00000016, 0x00000146, + 0x00000001, 0x0000001b, 0x00000145, 0x00050081, 0x00000016, 0x00000147, 0x00000083, 0x00000146, + 0x00050088, 0x00000016, 0x00000148, 0x00000083, 0x00000147, 0x00050041, 0x00000087, 0x00000149, + 0x00000008, 0x00000086, 0x0004003d, 0x00000014, 0x0000014a, 0x00000149, 0x00040073, 0x00000016, + 0x0000014b, 0x0000014a, 0x0007000c, 0x00000016, 0x0000014c, 0x00000001, 0x00000030, 0x0000014b, + 0x00000148, 0x00050085, 0x00000016, 0x0000014d, 0x0000014c, 0x00000148, 0x0004003d, 0x00000091, + 0x0000014e, 0x00000009, 0x00040068, 0x00000018, 0x0000014f, 0x0000014e, 0x000500b1, 0x00000093, + 0x00000150, 0x000000c5, 0x0000014f, 0x0004009b, 0x00000090, 0x00000151, 0x00000150, 0x000300f7, + 0x00000152, 0x00000000, 0x000400fa, 0x00000151, 0x00000153, 0x00000152, 0x000200f8, 0x00000153, + 0x0004003d, 0x00000091, 0x00000154, 0x00000009, 0x00040073, 0x00000014, 0x00000155, 0x0000014d, + 0x00070050, 0x00000022, 0x00000156, 0x00000155, 0x00000155, 0x00000155, 0x00000155, 0x00040063, + 0x00000154, 0x000000c5, 0x00000156, 0x000200f9, 0x00000152, 0x000200f8, 0x00000152, 0x00050051, + 0x00000012, 0x00000157, 0x000000b3, 0x00000000, 0x00050080, 0x00000012, 0x00000158, 0x00000157, + 0x000000bc, 0x00050051, 0x00000012, 0x00000159, 0x000000b3, 0x00000001, 0x00050080, 0x00000012, + 0x0000015a, 0x00000159, 0x000000b5, 0x00060041, 0x00000098, 0x0000015b, 0x00000097, 0x00000158, + 0x0000015a, 0x0003003e, 0x0000015b, 0x0000014d, 0x000200f9, 0x000000be, 0x000200f8, 0x000000be, + 0x00050080, 0x00000012, 0x000000bd, 0x000000bc, 0x00000019, 0x000200f9, 0x000000bb, 0x000200f8, + 0x000000c0, 0x000200f9, 0x000000b7, 0x000200f8, 0x000000b7, 0x00050080, 0x00000012, 0x000000b6, + 0x000000b5, 0x00000019, 0x000200f9, 0x000000b4, 0x000200f8, 0x000000b9, 0x000400e0, 0x0000008e, + 0x0000008e, 0x00000099, 0x00050041, 0x0000009a, 0x0000015c, 0x00000004, 0x00000088, 0x0004003d, + 0x00000012, 0x0000015d, 0x0000015c, 0x000500b0, 0x00000090, 0x0000015e, 0x0000015d, 0x0000009b, + 0x000300f7, 0x0000015f, 0x00000000, 0x000400fa, 0x0000015e, 0x00000160, 0x0000015f, 0x000200f8, + 0x00000160, 0x00050041, 0x0000009a, 0x00000161, 0x00000004, 0x00000089, 0x0004003d, 0x00000012, + 0x00000162, 0x00000161, 0x000500b0, 0x00000090, 0x00000163, 0x00000162, 0x0000009b, 0x000200f9, + 0x0000015f, 0x000200f8, 0x0000015f, 0x000700f5, 0x00000090, 0x00000164, 0x0000015e, 0x000000b9, + 0x00000163, 0x00000160, 0x000300f7, 0x00000165, 0x00000000, 0x000400fa, 0x00000164, 0x00000166, + 0x00000165, 0x000200f8, 0x00000166, 0x000500c4, 0x00000012, 0x00000167, 0x0000015d, 0x00000089, + 0x00050041, 0x0000009a, 0x00000168, 0x00000004, 0x00000089, 0x0004003d, 0x00000012, 0x00000169, + 0x00000168, 0x000500c4, 0x00000012, 0x0000016a, 0x00000169, 0x00000089, 0x00060041, 0x00000098, + 0x0000016b, 0x00000097, 0x00000167, 0x0000016a, 0x0004003d, 0x00000016, 0x0000016c, 0x0000016b, + 0x00050080, 0x00000012, 0x0000016d, 0x00000167, 0x00000089, 0x00060041, 0x00000098, 0x0000016e, + 0x00000097, 0x0000016d, 0x0000016a, 0x0004003d, 0x00000016, 0x0000016f, 0x0000016e, 0x00050081, + 0x00000016, 0x00000170, 0x0000016c, 0x0000016f, 0x00050080, 0x00000012, 0x00000171, 0x0000016a, + 0x00000089, 0x00060041, 0x00000098, 0x00000172, 0x00000097, 0x00000167, 0x00000171, 0x0004003d, + 0x00000016, 0x00000173, 0x00000172, 0x00050081, 0x00000016, 0x00000174, 0x00000170, 0x00000173, + 0x00060041, 0x00000098, 0x00000175, 0x00000097, 0x0000016d, 0x00000171, 0x0004003d, 0x00000016, + 0x00000176, 0x00000175, 0x00050081, 0x00000016, 0x00000177, 0x00000174, 0x00000176, 0x00050085, + 0x00000016, 0x00000178, 0x0000009c, 0x00000177, 0x00050084, 0x00000013, 0x00000179, 0x000000af, + 0x0000009d, 0x00050080, 0x00000013, 0x0000017a, 0x00000179, 0x000000b2, 0x0004007c, 0x00000018, + 0x0000017b, 0x0000017a, 0x0004003d, 0x00000091, 0x0000017c, 0x0000000a, 0x00040068, 0x00000018, + 0x0000017d, 0x0000017c, 0x000500b1, 0x00000093, 0x0000017e, 0x0000017b, 0x0000017d, 0x0004009b, + 0x00000090, 0x0000017f, 0x0000017e, 0x000300f7, 0x00000180, 0x00000000, 0x000400fa, 0x0000017f, + 0x00000181, 0x00000180, 0x000200f8, 0x00000181, 0x0004003d, 0x00000091, 0x00000182, 0x0000000a, + 0x00040073, 0x00000014, 0x00000183, 0x00000178, 0x00070050, 0x00000022, 0x00000184, 0x00000183, + 0x00000183, 0x00000183, 0x00000183, 0x00040063, 0x00000182, 0x0000017b, 0x00000184, 0x000200f9, + 0x00000180, 0x000200f8, 0x00000180, 0x00060041, 0x00000098, 0x00000185, 0x00000097, 0x0000015d, + 0x00000169, 0x0003003e, 0x00000185, 0x00000178, 0x000200f9, 0x00000165, 0x000200f8, 0x00000165, + 0x000400e0, 0x0000008e, 0x0000008e, 0x00000099, 0x000500b0, 0x00000090, 0x00000186, 0x0000015d, + 0x0000009e, 0x000300f7, 0x00000187, 0x00000000, 0x000400fa, 0x00000186, 0x00000188, 0x00000187, + 0x000200f8, 0x00000188, 0x00050041, 0x0000009a, 0x00000189, 0x00000004, 0x00000089, 0x0004003d, + 0x00000012, 0x0000018a, 0x00000189, 0x000500b0, 0x00000090, 0x0000018b, 0x0000018a, 0x0000009e, + 0x000200f9, 0x00000187, 0x000200f8, 0x00000187, 0x000700f5, 0x00000090, 0x0000018c, 0x00000186, + 0x00000165, 0x0000018b, 0x00000188, 0x000300f7, 0x0000018d, 0x00000000, 0x000400fa, 0x0000018c, + 0x0000018e, 0x0000018d, 0x000200f8, 0x0000018e, 0x000500c4, 0x00000012, 0x0000018f, 0x0000015d, + 0x00000089, 0x00050041, 0x0000009a, 0x00000190, 0x00000004, 0x00000089, 0x0004003d, 0x00000012, + 0x00000191, 0x00000190, 0x000500c4, 0x00000012, 0x00000192, 0x00000191, 0x00000089, 0x00060041, + 0x00000098, 0x00000193, 0x00000097, 0x0000018f, 0x00000192, 0x0004003d, 0x00000016, 0x00000194, + 0x00000193, 0x00050080, 0x00000012, 0x00000195, 0x0000018f, 0x00000089, 0x00060041, 0x00000098, + 0x00000196, 0x00000097, 0x00000195, 0x00000192, 0x0004003d, 0x00000016, 0x00000197, 0x00000196, + 0x00050081, 0x00000016, 0x00000198, 0x00000194, 0x00000197, 0x00050080, 0x00000012, 0x00000199, + 0x00000192, 0x00000089, 0x00060041, 0x00000098, 0x0000019a, 0x00000097, 0x0000018f, 0x00000199, + 0x0004003d, 0x00000016, 0x0000019b, 0x0000019a, 0x00050081, 0x00000016, 0x0000019c, 0x00000198, + 0x0000019b, 0x00060041, 0x00000098, 0x0000019d, 0x00000097, 0x00000195, 0x00000199, 0x0004003d, + 0x00000016, 0x0000019e, 0x0000019d, 0x00050081, 0x00000016, 0x0000019f, 0x0000019c, 0x0000019e, + 0x00050085, 0x00000016, 0x000001a0, 0x0000009c, 0x0000019f, 0x00050084, 0x00000013, 0x000001a1, + 0x000000af, 0x0000009f, 0x00050080, 0x00000013, 0x000001a2, 0x000001a1, 0x000000b2, 0x0004007c, + 0x00000018, 0x000001a3, 0x000001a2, 0x0004003d, 0x00000091, 0x000001a4, 0x0000000b, 0x00040068, + 0x00000018, 0x000001a5, 0x000001a4, 0x000500b1, 0x00000093, 0x000001a6, 0x000001a3, 0x000001a5, + 0x0004009b, 0x00000090, 0x000001a7, 0x000001a6, 0x000300f7, 0x000001a8, 0x00000000, 0x000400fa, + 0x000001a7, 0x000001a9, 0x000001a8, 0x000200f8, 0x000001a9, 0x0004003d, 0x00000091, 0x000001aa, + 0x0000000b, 0x00040073, 0x00000014, 0x000001ab, 0x000001a0, 0x00070050, 0x00000022, 0x000001ac, + 0x000001ab, 0x000001ab, 0x000001ab, 0x000001ab, 0x00040063, 0x000001aa, 0x000001a3, 0x000001ac, + 0x000200f9, 0x000001a8, 0x000200f8, 0x000001a8, 0x00060041, 0x00000098, 0x000001ad, 0x00000097, + 0x0000015d, 0x00000191, 0x0003003e, 0x000001ad, 0x000001a0, 0x000200f9, 0x0000018d, 0x000200f8, + 0x0000018d, 0x000400e0, 0x0000008e, 0x0000008e, 0x00000099, 0x000500b0, 0x00000090, 0x000001ae, + 0x0000015d, 0x000000a0, 0x000300f7, 0x000001af, 0x00000000, 0x000400fa, 0x000001ae, 0x000001b0, + 0x000001af, 0x000200f8, 0x000001b0, 0x00050041, 0x0000009a, 0x000001b1, 0x00000004, 0x00000089, + 0x0004003d, 0x00000012, 0x000001b2, 0x000001b1, 0x000500b0, 0x00000090, 0x000001b3, 0x000001b2, + 0x000000a0, 0x000200f9, 0x000001af, 0x000200f8, 0x000001af, 0x000700f5, 0x00000090, 0x000001b4, + 0x000001ae, 0x0000018d, 0x000001b3, 0x000001b0, 0x000300f7, 0x000001b5, 0x00000000, 0x000400fa, + 0x000001b4, 0x000001b6, 0x000001b5, 0x000200f8, 0x000001b6, 0x000500c4, 0x00000012, 0x000001b7, + 0x0000015d, 0x00000089, 0x00050041, 0x0000009a, 0x000001b8, 0x00000004, 0x00000089, 0x0004003d, + 0x00000012, 0x000001b9, 0x000001b8, 0x000500c4, 0x00000012, 0x000001ba, 0x000001b9, 0x00000089, + 0x00060041, 0x00000098, 0x000001bb, 0x00000097, 0x000001b7, 0x000001ba, 0x0004003d, 0x00000016, + 0x000001bc, 0x000001bb, 0x00050080, 0x00000012, 0x000001bd, 0x000001b7, 0x00000089, 0x00060041, + 0x00000098, 0x000001be, 0x00000097, 0x000001bd, 0x000001ba, 0x0004003d, 0x00000016, 0x000001bf, + 0x000001be, 0x00050081, 0x00000016, 0x000001c0, 0x000001bc, 0x000001bf, 0x00050080, 0x00000012, + 0x000001c1, 0x000001ba, 0x00000089, 0x00060041, 0x00000098, 0x000001c2, 0x00000097, 0x000001b7, + 0x000001c1, 0x0004003d, 0x00000016, 0x000001c3, 0x000001c2, 0x00050081, 0x00000016, 0x000001c4, + 0x000001c0, 0x000001c3, 0x00060041, 0x00000098, 0x000001c5, 0x00000097, 0x000001bd, 0x000001c1, + 0x0004003d, 0x00000016, 0x000001c6, 0x000001c5, 0x00050081, 0x00000016, 0x000001c7, 0x000001c4, + 0x000001c6, 0x00050085, 0x00000016, 0x000001c8, 0x0000009c, 0x000001c7, 0x00050084, 0x00000013, + 0x000001c9, 0x000000af, 0x000000a1, 0x00050080, 0x00000013, 0x000001ca, 0x000001c9, 0x000000b2, + 0x0004007c, 0x00000018, 0x000001cb, 0x000001ca, 0x0004003d, 0x00000091, 0x000001cc, 0x0000000c, + 0x00040068, 0x00000018, 0x000001cd, 0x000001cc, 0x000500b1, 0x00000093, 0x000001ce, 0x000001cb, + 0x000001cd, 0x0004009b, 0x00000090, 0x000001cf, 0x000001ce, 0x000300f7, 0x000001d0, 0x00000000, + 0x000400fa, 0x000001cf, 0x000001d1, 0x000001d0, 0x000200f8, 0x000001d1, 0x0004003d, 0x00000091, + 0x000001d2, 0x0000000c, 0x00040073, 0x00000014, 0x000001d3, 0x000001c8, 0x00070050, 0x00000022, + 0x000001d4, 0x000001d3, 0x000001d3, 0x000001d3, 0x000001d3, 0x00040063, 0x000001d2, 0x000001cb, + 0x000001d4, 0x000200f9, 0x000001d0, 0x000200f8, 0x000001d0, 0x00060041, 0x00000098, 0x000001d5, + 0x00000097, 0x0000015d, 0x000001b9, 0x0003003e, 0x000001d5, 0x000001c8, 0x000200f9, 0x000001b5, + 0x000200f8, 0x000001b5, 0x000400e0, 0x0000008e, 0x0000008e, 0x00000099, 0x000500b0, 0x00000090, + 0x000001d6, 0x0000015d, 0x0000008e, 0x000300f7, 0x000001d7, 0x00000000, 0x000400fa, 0x000001d6, + 0x000001d8, 0x000001d7, 0x000200f8, 0x000001d8, 0x00050041, 0x0000009a, 0x000001d9, 0x00000004, + 0x00000089, 0x0004003d, 0x00000012, 0x000001da, 0x000001d9, 0x000500b0, 0x00000090, 0x000001db, + 0x000001da, 0x0000008e, 0x000200f9, 0x000001d7, 0x000200f8, 0x000001d7, 0x000700f5, 0x00000090, + 0x000001dc, 0x000001d6, 0x000001b5, 0x000001db, 0x000001d8, 0x000300f7, 0x000001dd, 0x00000000, + 0x000400fa, 0x000001dc, 0x000001de, 0x000001dd, 0x000200f8, 0x000001de, 0x000500c4, 0x00000012, + 0x000001df, 0x0000015d, 0x00000089, 0x00050041, 0x0000009a, 0x000001e0, 0x00000004, 0x00000089, + 0x0004003d, 0x00000012, 0x000001e1, 0x000001e0, 0x000500c4, 0x00000012, 0x000001e2, 0x000001e1, + 0x00000089, 0x00060041, 0x00000098, 0x000001e3, 0x00000097, 0x000001df, 0x000001e2, 0x0004003d, + 0x00000016, 0x000001e4, 0x000001e3, 0x00050080, 0x00000012, 0x000001e5, 0x000001df, 0x00000089, + 0x00060041, 0x00000098, 0x000001e6, 0x00000097, 0x000001e5, 0x000001e2, 0x0004003d, 0x00000016, + 0x000001e7, 0x000001e6, 0x00050081, 0x00000016, 0x000001e8, 0x000001e4, 0x000001e7, 0x00050080, + 0x00000012, 0x000001e9, 0x000001e2, 0x00000089, 0x00060041, 0x00000098, 0x000001ea, 0x00000097, + 0x000001df, 0x000001e9, 0x0004003d, 0x00000016, 0x000001eb, 0x000001ea, 0x00050081, 0x00000016, + 0x000001ec, 0x000001e8, 0x000001eb, 0x00060041, 0x00000098, 0x000001ed, 0x00000097, 0x000001e5, + 0x000001e9, 0x0004003d, 0x00000016, 0x000001ee, 0x000001ed, 0x00050081, 0x00000016, 0x000001ef, + 0x000001ec, 0x000001ee, 0x00050085, 0x00000016, 0x000001f0, 0x0000009c, 0x000001ef, 0x00050084, + 0x00000013, 0x000001f1, 0x000000af, 0x0000008f, 0x00050080, 0x00000013, 0x000001f2, 0x000001f1, + 0x000000b2, 0x0004007c, 0x00000018, 0x000001f3, 0x000001f2, 0x0004003d, 0x00000091, 0x000001f4, + 0x0000000d, 0x00040068, 0x00000018, 0x000001f5, 0x000001f4, 0x000500b1, 0x00000093, 0x000001f6, + 0x000001f3, 0x000001f5, 0x0004009b, 0x00000090, 0x000001f7, 0x000001f6, 0x000300f7, 0x000001f8, + 0x00000000, 0x000400fa, 0x000001f7, 0x000001f9, 0x000001f8, 0x000200f8, 0x000001f9, 0x0004003d, + 0x00000091, 0x000001fa, 0x0000000d, 0x00040073, 0x00000014, 0x000001fb, 0x000001f0, 0x00070050, + 0x00000022, 0x000001fc, 0x000001fb, 0x000001fb, 0x000001fb, 0x000001fb, 0x00040063, 0x000001fa, + 0x000001f3, 0x000001fc, 0x000200f9, 0x000001f8, 0x000200f8, 0x000001f8, 0x00060041, 0x00000098, + 0x000001fd, 0x00000097, 0x0000015d, 0x000001e1, 0x0003003e, 0x000001fd, 0x000001f0, 0x000200f9, + 0x000001dd, 0x000200f8, 0x000001dd, 0x000400e0, 0x0000008e, 0x0000008e, 0x00000099, 0x000500b0, + 0x00000090, 0x000001fe, 0x0000015d, 0x00000089, 0x000300f7, 0x000001ff, 0x00000000, 0x000400fa, + 0x000001fe, 0x00000200, 0x000001ff, 0x000200f8, 0x00000200, 0x00050041, 0x0000009a, 0x00000201, + 0x00000004, 0x00000089, 0x0004003d, 0x00000012, 0x00000202, 0x00000201, 0x000500b0, 0x00000090, + 0x00000203, 0x00000202, 0x00000089, 0x000200f9, 0x000001ff, 0x000200f8, 0x000001ff, 0x000700f5, + 0x00000090, 0x00000204, 0x000001fe, 0x000001dd, 0x00000203, 0x00000200, 0x000300f7, 0x00000205, + 0x00000000, 0x000400fa, 0x00000204, 0x00000206, 0x00000205, 0x000200f8, 0x00000206, 0x000500c4, + 0x00000012, 0x00000207, 0x0000015d, 0x00000089, 0x00050041, 0x0000009a, 0x00000208, 0x00000004, + 0x00000089, 0x0004003d, 0x00000012, 0x00000209, 0x00000208, 0x000500c4, 0x00000012, 0x0000020a, + 0x00000209, 0x00000089, 0x00060041, 0x00000098, 0x0000020b, 0x00000097, 0x00000207, 0x0000020a, + 0x0004003d, 0x00000016, 0x0000020c, 0x0000020b, 0x00050080, 0x00000012, 0x0000020d, 0x00000207, + 0x00000089, 0x00060041, 0x00000098, 0x0000020e, 0x00000097, 0x0000020d, 0x0000020a, 0x0004003d, + 0x00000016, 0x0000020f, 0x0000020e, 0x00050081, 0x00000016, 0x00000210, 0x0000020c, 0x0000020f, + 0x00050080, 0x00000012, 0x00000211, 0x0000020a, 0x00000089, 0x00060041, 0x00000098, 0x00000212, + 0x00000097, 0x00000207, 0x00000211, 0x0004003d, 0x00000016, 0x00000213, 0x00000212, 0x00050081, + 0x00000016, 0x00000214, 0x00000210, 0x00000213, 0x00060041, 0x00000098, 0x00000215, 0x00000097, + 0x0000020d, 0x00000211, 0x0004003d, 0x00000016, 0x00000216, 0x00000215, 0x00050081, 0x00000016, + 0x00000217, 0x00000214, 0x00000216, 0x00050085, 0x00000016, 0x00000218, 0x0000009c, 0x00000217, + 0x00050080, 0x00000013, 0x00000219, 0x000000af, 0x000000b2, 0x0004007c, 0x00000018, 0x0000021a, + 0x00000219, 0x0004003d, 0x00000091, 0x0000021b, 0x0000000e, 0x00040068, 0x00000018, 0x0000021c, + 0x0000021b, 0x000500b1, 0x00000093, 0x0000021d, 0x0000021a, 0x0000021c, 0x0004009b, 0x00000090, + 0x0000021e, 0x0000021d, 0x000300f7, 0x0000021f, 0x00000000, 0x000400fa, 0x0000021e, 0x00000220, + 0x0000021f, 0x000200f8, 0x00000220, 0x0004003d, 0x00000091, 0x00000221, 0x0000000e, 0x00040073, + 0x00000014, 0x00000222, 0x00000218, 0x00070050, 0x00000022, 0x00000223, 0x00000222, 0x00000222, + 0x00000222, 0x00000222, 0x00040063, 0x00000221, 0x0000021a, 0x00000223, 0x000200f9, 0x0000021f, + 0x000200f8, 0x0000021f, 0x00060041, 0x00000098, 0x00000224, 0x00000097, 0x0000015d, 0x00000209, + 0x0003003e, 0x00000224, 0x00000218, 0x000200f9, 0x00000205, 0x000200f8, 0x00000205, 0x000100fd, + 0x00010038, +}; +static const size_t wnfg_13_spv_size = sizeof(wnfg_13_spv); diff --git a/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_25_spv.h b/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_25_spv.h new file mode 100644 index 000000000..6bb9e8bc8 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_25_spv.h @@ -0,0 +1,493 @@ +#pragma once +#include +#include + +static const uint32_t wnfg_25_spv[] = { + 0x07230203, 0x00010000, 0x000d000b, 0x000002fc, 0x00000000, 0x00020011, 0x00000001, 0x00020011, + 0x00000009, 0x00020011, 0x00000032, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, + 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0006000f, 0x00000005, 0x00000002, 0x6e69616d, + 0x00000000, 0x00000003, 0x00060010, 0x00000002, 0x00000011, 0x00000010, 0x00000010, 0x00000001, + 0x00040047, 0x00000003, 0x0000000b, 0x0000001c, 0x00030047, 0x00000004, 0x00000019, 0x00040047, + 0x00000004, 0x00000021, 0x00000030, 0x00040047, 0x00000004, 0x00000022, 0x00000000, 0x00040047, + 0x00000005, 0x00000021, 0x00000020, 0x00040047, 0x00000005, 0x00000022, 0x00000000, 0x00030047, + 0x00000006, 0x00000002, 0x00050048, 0x00000006, 0x00000000, 0x00000023, 0x00000000, 0x00050048, + 0x00000006, 0x00000001, 0x00000023, 0x00000004, 0x00050048, 0x00000006, 0x00000002, 0x00000023, + 0x00000008, 0x00040047, 0x00000007, 0x00000021, 0x00000000, 0x00040047, 0x00000007, 0x00000022, + 0x00000000, 0x00040047, 0x00000008, 0x00000021, 0x00000024, 0x00040047, 0x00000008, 0x00000022, + 0x00000000, 0x00040047, 0x00000009, 0x00000021, 0x00000025, 0x00040047, 0x00000009, 0x00000022, + 0x00000000, 0x00040047, 0x0000000a, 0x00000021, 0x00000021, 0x00040047, 0x0000000a, 0x00000022, + 0x00000000, 0x00040047, 0x0000000b, 0x00000021, 0x00000022, 0x00040047, 0x0000000b, 0x00000022, + 0x00000000, 0x00040047, 0x0000000c, 0x00000021, 0x00000023, 0x00040047, 0x0000000c, 0x00000022, + 0x00000000, 0x00040047, 0x0000000d, 0x0000000b, 0x00000019, 0x00020013, 0x0000000e, 0x00030021, + 0x0000000f, 0x0000000e, 0x00040015, 0x00000010, 0x00000020, 0x00000001, 0x00040017, 0x00000011, + 0x00000010, 0x00000002, 0x00040015, 0x00000012, 0x00000020, 0x00000000, 0x00040017, 0x00000013, + 0x00000012, 0x00000003, 0x00040020, 0x00000014, 0x00000001, 0x00000013, 0x0004003b, 0x00000014, + 0x00000003, 0x00000001, 0x00040017, 0x00000015, 0x00000012, 0x00000002, 0x00030016, 0x00000016, + 0x00000020, 0x00090019, 0x00000017, 0x00000016, 0x00000001, 0x00000000, 0x00000000, 0x00000000, + 0x00000002, 0x00000004, 0x00040020, 0x00000018, 0x00000000, 0x00000017, 0x0004003b, 0x00000018, + 0x00000004, 0x00000000, 0x00020014, 0x00000019, 0x00040017, 0x0000001a, 0x00000019, 0x00000002, + 0x00090019, 0x0000001b, 0x00000016, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, + 0x00000000, 0x0003001b, 0x0000001c, 0x0000001b, 0x00040020, 0x0000001d, 0x00000000, 0x0000001c, + 0x0004003b, 0x0000001d, 0x00000005, 0x00000000, 0x0004002b, 0x00000010, 0x0000001e, 0x00000000, + 0x00040017, 0x0000001f, 0x00000016, 0x00000002, 0x0004002b, 0x00000012, 0x00000020, 0x00000000, + 0x0004002b, 0x00000012, 0x00000021, 0x00000001, 0x0004002b, 0x00000016, 0x00000022, 0x3f000000, + 0x0005002c, 0x0000001f, 0x00000023, 0x00000022, 0x00000022, 0x0004002b, 0x00000010, 0x00000024, + 0x00000001, 0x0005002c, 0x00000011, 0x00000025, 0x00000024, 0x00000024, 0x00030016, 0x00000026, + 0x00000010, 0x0004002b, 0x00000016, 0x00000027, 0x3f800000, 0x0005001e, 0x00000006, 0x00000016, + 0x00000016, 0x00000016, 0x00040020, 0x00000028, 0x00000002, 0x00000006, 0x0004003b, 0x00000028, + 0x00000007, 0x00000002, 0x00040020, 0x00000029, 0x00000002, 0x00000016, 0x00040017, 0x0000002a, + 0x00000026, 0x00000004, 0x0004003b, 0x0000001d, 0x00000008, 0x00000000, 0x0004002b, 0x00000016, + 0x0000002b, 0x00000000, 0x00040017, 0x0000002c, 0x00000016, 0x00000004, 0x00040017, 0x0000002d, + 0x00000026, 0x00000002, 0x0004003b, 0x0000001d, 0x00000009, 0x00000000, 0x0004002b, 0x00000026, + 0x0000002e, 0x00000000, 0x0007002c, 0x0000002a, 0x0000002f, 0x0000002e, 0x0000002e, 0x0000002e, + 0x0000002e, 0x0004003b, 0x0000001d, 0x0000000a, 0x00000000, 0x0004003b, 0x0000001d, 0x0000000b, + 0x00000000, 0x0004002b, 0x00000010, 0x00000030, 0xffffffff, 0x0005002c, 0x00000011, 0x00000031, + 0x00000030, 0x00000030, 0x0005002c, 0x00000011, 0x00000032, 0x0000001e, 0x0000001e, 0x0004003b, + 0x0000001d, 0x0000000c, 0x00000000, 0x0005002c, 0x00000011, 0x00000033, 0x0000001e, 0x00000030, + 0x0005002c, 0x00000011, 0x00000034, 0x00000024, 0x00000030, 0x0005002c, 0x00000011, 0x00000035, + 0x00000030, 0x0000001e, 0x0005002c, 0x00000011, 0x00000036, 0x00000024, 0x0000001e, 0x0005002c, + 0x00000011, 0x00000037, 0x00000030, 0x00000024, 0x0005002c, 0x00000011, 0x00000038, 0x0000001e, + 0x00000024, 0x00040018, 0x00000039, 0x0000002a, 0x00000004, 0x0004002b, 0x00000026, 0x0000003a, + 0x00003734, 0x0004002b, 0x00000026, 0x0000003b, 0x000037e6, 0x0004002b, 0x00000026, 0x0000003c, + 0x000031b8, 0x0004002b, 0x00000026, 0x0000003d, 0x000037c4, 0x0007002c, 0x0000002a, 0x0000003e, + 0x0000003a, 0x0000003b, 0x0000003c, 0x0000003d, 0x0004002b, 0x00000026, 0x0000003f, 0x0000ac3f, + 0x0004002b, 0x00000026, 0x00000040, 0x000038f7, 0x0004002b, 0x00000026, 0x00000041, 0x0000ae43, + 0x0004002b, 0x00000026, 0x00000042, 0x000037e7, 0x0007002c, 0x0000002a, 0x00000043, 0x0000003f, + 0x00000040, 0x00000041, 0x00000042, 0x0004002b, 0x00000026, 0x00000044, 0x00003576, 0x0004002b, + 0x00000026, 0x00000045, 0x00003729, 0x0004002b, 0x00000026, 0x00000046, 0x000034b1, 0x0004002b, + 0x00000026, 0x00000047, 0x000036a3, 0x0007002c, 0x0000002a, 0x00000048, 0x00000044, 0x00000045, + 0x00000046, 0x00000047, 0x0004002b, 0x00000026, 0x00000049, 0x0000ae0a, 0x0004002b, 0x00000026, + 0x0000004a, 0x000038a4, 0x0004002b, 0x00000026, 0x0000004b, 0x0000b129, 0x0004002b, 0x00000026, + 0x0000004c, 0x0000352b, 0x0007002c, 0x0000002a, 0x0000004d, 0x00000049, 0x0000004a, 0x0000004b, + 0x0000004c, 0x0007002c, 0x00000039, 0x0000004e, 0x0000003e, 0x00000043, 0x00000048, 0x0000004d, + 0x0004002b, 0x00000026, 0x0000004f, 0x00004138, 0x0004002b, 0x00000026, 0x00000050, 0x0000415f, + 0x0004002b, 0x00000026, 0x00000051, 0x00004137, 0x0004002b, 0x00000026, 0x00000052, 0x0000416e, + 0x0007002c, 0x0000002a, 0x00000053, 0x0000004f, 0x00000050, 0x00000051, 0x00000052, 0x0004002b, + 0x00000026, 0x00000054, 0x00003d97, 0x0004002b, 0x00000026, 0x00000055, 0x00003c7f, 0x0004002b, + 0x00000026, 0x00000056, 0x00003d5a, 0x0004002b, 0x00000026, 0x00000057, 0x00003c79, 0x0007002c, + 0x0000002a, 0x00000058, 0x00000054, 0x00000055, 0x00000056, 0x00000057, 0x0004002b, 0x00000026, + 0x00000059, 0x0000b713, 0x0004002b, 0x00000026, 0x0000005a, 0x00002d4c, 0x0004002b, 0x00000026, + 0x0000005b, 0x0000b88b, 0x0004002b, 0x00000026, 0x0000005c, 0x00002e34, 0x0007002c, 0x0000002a, + 0x0000005d, 0x00000059, 0x0000005a, 0x0000005b, 0x0000005c, 0x0004002b, 0x00000026, 0x0000005e, + 0x00003c00, 0x0007002c, 0x0000002a, 0x0000005f, 0x0000005e, 0x0000005e, 0x0000005e, 0x0000005e, + 0x0004002b, 0x00000026, 0x00000060, 0x0000b5b5, 0x0004002b, 0x00000026, 0x00000061, 0x0000380a, + 0x0004002b, 0x00000026, 0x00000062, 0x0000ad6a, 0x0004002b, 0x00000026, 0x00000063, 0x000036ce, + 0x0007002c, 0x0000002a, 0x00000064, 0x00000060, 0x00000061, 0x00000062, 0x00000063, 0x0004002b, + 0x00000026, 0x00000065, 0x0000af23, 0x0004002b, 0x00000026, 0x00000066, 0x00003a02, 0x0004002b, + 0x00000026, 0x00000067, 0x0000acea, 0x0004002b, 0x00000026, 0x00000068, 0x00003360, 0x0007002c, + 0x0000002a, 0x00000069, 0x00000065, 0x00000066, 0x00000067, 0x00000068, 0x0004002b, 0x00000026, + 0x0000006a, 0x00003413, 0x0004002b, 0x00000026, 0x0000006b, 0x00002f0e, 0x0004002b, 0x00000026, + 0x0000006c, 0x000028ac, 0x0004002b, 0x00000026, 0x0000006d, 0x000035b3, 0x0007002c, 0x0000002a, + 0x0000006e, 0x0000006a, 0x0000006b, 0x0000006c, 0x0000006d, 0x0004002b, 0x00000026, 0x0000006f, + 0x00001325, 0x0004002b, 0x00000026, 0x00000070, 0x0000393e, 0x0004002b, 0x00000026, 0x00000071, + 0x0000adef, 0x0004002b, 0x00000026, 0x00000072, 0x0000359b, 0x0007002c, 0x0000002a, 0x00000073, + 0x0000006f, 0x00000070, 0x00000071, 0x00000072, 0x0007002c, 0x00000039, 0x00000074, 0x00000064, + 0x00000069, 0x0000006e, 0x00000073, 0x0004002b, 0x00000026, 0x00000075, 0x000041cb, 0x0004002b, + 0x00000026, 0x00000076, 0x00004161, 0x0007002c, 0x0000002a, 0x00000077, 0x00000075, 0x00000052, + 0x0000004f, 0x00000076, 0x0004002b, 0x00000026, 0x00000078, 0x00003bf1, 0x0004002b, 0x00000026, + 0x00000079, 0x00003aae, 0x0004002b, 0x00000026, 0x0000007a, 0x00003bc2, 0x0004002b, 0x00000026, + 0x0000007b, 0x00003a44, 0x0007002c, 0x0000002a, 0x0000007c, 0x00000078, 0x00000079, 0x0000007a, + 0x0000007b, 0x0004002b, 0x00000026, 0x0000007d, 0x00003574, 0x0004002b, 0x00000026, 0x0000007e, + 0x000033bc, 0x0004002b, 0x00000026, 0x0000007f, 0x0000ac76, 0x0004002b, 0x00000026, 0x00000080, + 0x00003242, 0x0007002c, 0x0000002a, 0x00000081, 0x0000007d, 0x0000007e, 0x0000007f, 0x00000080, + 0x0004002b, 0x00000026, 0x00000082, 0x000035a5, 0x0004002b, 0x00000026, 0x00000083, 0x00002e5e, + 0x0004002b, 0x00000026, 0x00000084, 0x00002000, 0x0007002c, 0x0000002a, 0x00000085, 0x00000082, + 0x00000083, 0x00000084, 0x00000044, 0x0004002b, 0x00000026, 0x00000086, 0x00004139, 0x0004002b, + 0x00000026, 0x00000087, 0x00003c31, 0x0004002b, 0x00000026, 0x00000088, 0x0000aa02, 0x0004002b, + 0x00000026, 0x00000089, 0x0000b842, 0x0004002b, 0x00000026, 0x0000008a, 0x0000aef0, 0x0004002b, + 0x00000026, 0x0000008b, 0x0000b92d, 0x0004002b, 0x00000026, 0x0000008c, 0x0000b460, 0x0007002c, + 0x0000002a, 0x0000008d, 0x00000089, 0x0000008a, 0x0000008b, 0x0000008c, 0x0004002b, 0x00000026, + 0x0000008e, 0x0000b61e, 0x0004002b, 0x00000026, 0x0000008f, 0x00002ca5, 0x0004002b, 0x00000026, + 0x00000090, 0x0000b870, 0x0004002b, 0x00000026, 0x00000091, 0x0000ace3, 0x0007002c, 0x0000002a, + 0x00000092, 0x0000008e, 0x0000008f, 0x00000090, 0x00000091, 0x0004002b, 0x00000026, 0x00000093, + 0x0000b98b, 0x0004002b, 0x00000026, 0x00000094, 0x0000ad67, 0x0004002b, 0x00000026, 0x00000095, + 0x0000b864, 0x0004002b, 0x00000026, 0x00000096, 0x0000b553, 0x0007002c, 0x0000002a, 0x00000097, + 0x00000093, 0x00000094, 0x00000095, 0x00000096, 0x0004002b, 0x00000026, 0x00000098, 0x0000b81f, + 0x0004002b, 0x00000026, 0x00000099, 0x00002e95, 0x0004002b, 0x00000026, 0x0000009a, 0x0000b7a3, + 0x0004002b, 0x00000026, 0x0000009b, 0x0000adb9, 0x0007002c, 0x0000002a, 0x0000009c, 0x00000098, + 0x00000099, 0x0000009a, 0x0000009b, 0x0007002c, 0x00000039, 0x0000009d, 0x0000008d, 0x00000092, + 0x00000097, 0x0000009c, 0x0004002b, 0x00000026, 0x0000009e, 0x0000bc31, 0x0004002b, 0x00000026, + 0x0000009f, 0x0000abc9, 0x0004002b, 0x00000026, 0x000000a0, 0x0000b688, 0x0004002b, 0x00000026, + 0x000000a1, 0x000030ad, 0x0007002c, 0x0000002a, 0x000000a2, 0x0000009e, 0x0000009f, 0x000000a0, + 0x000000a1, 0x0004002b, 0x00000026, 0x000000a3, 0x0000b832, 0x0004002b, 0x00000026, 0x000000a4, + 0x00003207, 0x0004002b, 0x00000026, 0x000000a5, 0x0000b78f, 0x0004002b, 0x00000026, 0x000000a6, + 0x0000b21a, 0x0007002c, 0x0000002a, 0x000000a7, 0x000000a3, 0x000000a4, 0x000000a5, 0x000000a6, + 0x0004002b, 0x00000026, 0x000000a8, 0x0000256a, 0x0004002b, 0x00000026, 0x000000a9, 0x0000b039, + 0x0004002b, 0x00000026, 0x000000aa, 0x0000b8c3, 0x0004002b, 0x00000026, 0x000000ab, 0x0000b555, + 0x0007002c, 0x0000002a, 0x000000ac, 0x000000a8, 0x000000a9, 0x000000aa, 0x000000ab, 0x0004002b, + 0x00000026, 0x000000ad, 0x0000b3a2, 0x0004002b, 0x00000026, 0x000000ae, 0x0000324a, 0x0004002b, + 0x00000026, 0x000000af, 0x0000b80b, 0x0004002b, 0x00000026, 0x000000b0, 0x0000b0f2, 0x0007002c, + 0x0000002a, 0x000000b1, 0x000000ad, 0x000000ae, 0x000000af, 0x000000b0, 0x0007002c, 0x00000039, + 0x000000b2, 0x000000a2, 0x000000a7, 0x000000ac, 0x000000b1, 0x0004002b, 0x00000026, 0x000000b3, + 0x0000a70c, 0x0004002b, 0x00000026, 0x000000b4, 0x0000b196, 0x0004002b, 0x00000026, 0x000000b5, + 0x0000b8bd, 0x0004002b, 0x00000026, 0x000000b6, 0x0000b5aa, 0x0007002c, 0x0000002a, 0x000000b7, + 0x000000b3, 0x000000b4, 0x000000b5, 0x000000b6, 0x0004002b, 0x00000026, 0x000000b8, 0x00002ec2, + 0x0004002b, 0x00000026, 0x000000b9, 0x0000a9ce, 0x0004002b, 0x00000026, 0x000000ba, 0x00002eb1, + 0x0004002b, 0x00000026, 0x000000bb, 0x0000aa70, 0x0007002c, 0x0000002a, 0x000000bc, 0x000000b8, + 0x000000b9, 0x000000ba, 0x000000bb, 0x0004002b, 0x00000026, 0x000000bd, 0x00003443, 0x0004002b, + 0x00000026, 0x000000be, 0x0000b2a2, 0x0004002b, 0x00000026, 0x000000bf, 0x0000353b, 0x0004002b, + 0x00000026, 0x000000c0, 0x0000b26e, 0x0007002c, 0x0000002a, 0x000000c1, 0x000000bd, 0x000000be, + 0x000000bf, 0x000000c0, 0x0004002b, 0x00000026, 0x000000c2, 0x0000aa5d, 0x0004002b, 0x00000026, + 0x000000c3, 0x0000a9d8, 0x0004002b, 0x00000026, 0x000000c4, 0x00003196, 0x0004002b, 0x00000026, + 0x000000c5, 0x00003049, 0x0007002c, 0x0000002a, 0x000000c6, 0x000000c2, 0x000000c3, 0x000000c4, + 0x000000c5, 0x0004002b, 0x00000026, 0x000000c7, 0x000034de, 0x0004002b, 0x00000026, 0x000000c8, + 0x0000b1cc, 0x0004002b, 0x00000026, 0x000000c9, 0x00003493, 0x0004002b, 0x00000026, 0x000000ca, + 0x0000b40b, 0x0007002c, 0x0000002a, 0x000000cb, 0x000000c7, 0x000000c8, 0x000000c9, 0x000000ca, + 0x0007002c, 0x00000039, 0x000000cc, 0x000000bc, 0x000000c1, 0x000000c6, 0x000000cb, 0x0004002b, + 0x00000026, 0x000000cd, 0x0000b8e7, 0x0004002b, 0x00000026, 0x000000ce, 0x0000b75b, 0x0004002b, + 0x00000026, 0x000000cf, 0x000037de, 0x0004002b, 0x00000026, 0x000000d0, 0x0000bac0, 0x0007002c, + 0x0000002a, 0x000000d1, 0x000000cd, 0x000000ce, 0x000000cf, 0x000000d0, 0x0004002b, 0x00000026, + 0x000000d2, 0x000031ef, 0x0004002b, 0x00000026, 0x000000d3, 0x0000aba0, 0x0004002b, 0x00000026, + 0x000000d4, 0x00003487, 0x0004002b, 0x00000026, 0x000000d5, 0x0000b40e, 0x0007002c, 0x0000002a, + 0x000000d6, 0x000000d2, 0x000000d3, 0x000000d4, 0x000000d5, 0x0004002b, 0x00000026, 0x000000d7, + 0x00003164, 0x0004002b, 0x00000026, 0x000000d8, 0x0000b328, 0x0004002b, 0x00000026, 0x000000d9, + 0x00003134, 0x0004002b, 0x00000026, 0x000000da, 0x00009f77, 0x0007002c, 0x0000002a, 0x000000db, + 0x000000d7, 0x000000d8, 0x000000d9, 0x000000da, 0x0004002b, 0x00000026, 0x000000dc, 0x0000250c, + 0x0004002b, 0x00000026, 0x000000dd, 0x00002321, 0x0004002b, 0x00000026, 0x000000de, 0x0000347a, + 0x0004002b, 0x00000026, 0x000000df, 0x0000b2f0, 0x0007002c, 0x0000002a, 0x000000e0, 0x000000dc, + 0x000000dd, 0x000000de, 0x000000df, 0x0007002c, 0x00000039, 0x000000e1, 0x000000d1, 0x000000d6, + 0x000000db, 0x000000e0, 0x0004002b, 0x00000026, 0x000000e2, 0x00003464, 0x0004002b, 0x00000026, + 0x000000e3, 0x0000b187, 0x0004002b, 0x00000026, 0x000000e4, 0x00002c5b, 0x0004002b, 0x00000026, + 0x000000e5, 0x00002bd8, 0x0007002c, 0x0000002a, 0x000000e6, 0x000000e2, 0x000000e3, 0x000000e4, + 0x000000e5, 0x0004002b, 0x00000026, 0x000000e7, 0x00002e24, 0x0004002b, 0x00000026, 0x000000e8, + 0x000098c3, 0x0004002b, 0x00000026, 0x000000e9, 0x000031da, 0x0004002b, 0x00000026, 0x000000ea, + 0x00002085, 0x0007002c, 0x0000002a, 0x000000eb, 0x000000e7, 0x000000e8, 0x000000e9, 0x000000ea, + 0x0004002b, 0x00000026, 0x000000ec, 0x0000339d, 0x0004002b, 0x00000026, 0x000000ed, 0x0000b069, + 0x0004002b, 0x00000026, 0x000000ee, 0x00003459, 0x0004002b, 0x00000026, 0x000000ef, 0x0000b1e2, + 0x0007002c, 0x0000002a, 0x000000f0, 0x000000ec, 0x000000ed, 0x000000ee, 0x000000ef, 0x0004002b, + 0x00000026, 0x000000f1, 0x00002c46, 0x0004002b, 0x00000026, 0x000000f2, 0x0000290d, 0x0004002b, + 0x00000026, 0x000000f3, 0x000030b5, 0x0004002b, 0x00000026, 0x000000f4, 0x00002799, 0x0007002c, + 0x0000002a, 0x000000f5, 0x000000f1, 0x000000f2, 0x000000f3, 0x000000f4, 0x0004002b, 0x00000026, + 0x000000f6, 0x00003578, 0x0004002b, 0x00000026, 0x000000f7, 0x0000b05d, 0x0004002b, 0x00000026, + 0x000000f8, 0x0000b076, 0x0007002c, 0x0000002a, 0x000000f9, 0x000000f6, 0x000000f7, 0x000000e2, + 0x000000f8, 0x0007002c, 0x00000039, 0x000000fa, 0x000000eb, 0x000000f0, 0x000000f5, 0x000000f9, + 0x0004002b, 0x00000026, 0x000000fb, 0x0000b989, 0x0004002b, 0x00000026, 0x000000fc, 0x0000b575, + 0x0004002b, 0x00000026, 0x000000fd, 0x000037dd, 0x0004002b, 0x00000026, 0x000000fe, 0x0000b9ca, + 0x0007002c, 0x0000002a, 0x000000ff, 0x000000fb, 0x000000fc, 0x000000fd, 0x000000fe, 0x0004002b, + 0x00000026, 0x00000100, 0x00003276, 0x0004002b, 0x00000026, 0x00000101, 0x0000a466, 0x0004002b, + 0x00000026, 0x00000102, 0x00003563, 0x0004002b, 0x00000026, 0x00000103, 0x0000ada5, 0x0007002c, + 0x0000002a, 0x00000104, 0x00000100, 0x00000101, 0x00000102, 0x00000103, 0x0004002b, 0x00000026, + 0x00000105, 0x000035ea, 0x0004002b, 0x00000026, 0x00000106, 0x0000b247, 0x0004002b, 0x00000026, + 0x00000107, 0x00003203, 0x0004002b, 0x00000026, 0x00000108, 0x00002891, 0x0007002c, 0x0000002a, + 0x00000109, 0x00000105, 0x00000106, 0x00000107, 0x00000108, 0x0004002b, 0x00000026, 0x0000010a, + 0x00002583, 0x0004002b, 0x00000026, 0x0000010b, 0x000026fb, 0x0004002b, 0x00000026, 0x0000010c, + 0x00003495, 0x0004002b, 0x00000026, 0x0000010d, 0x0000ae7f, 0x0007002c, 0x0000002a, 0x0000010e, + 0x0000010a, 0x0000010b, 0x0000010c, 0x0000010d, 0x0007002c, 0x00000039, 0x0000010f, 0x000000ff, + 0x00000104, 0x00000109, 0x0000010e, 0x0004002b, 0x00000026, 0x00000110, 0x00003552, 0x0004002b, + 0x00000026, 0x00000111, 0x0000a2a7, 0x0004002b, 0x00000026, 0x00000112, 0x0000315b, 0x0004002b, + 0x00000026, 0x00000113, 0x00002e09, 0x0007002c, 0x0000002a, 0x00000114, 0x00000110, 0x00000111, + 0x00000112, 0x00000113, 0x0004002b, 0x00000026, 0x00000115, 0x0000ba6a, 0x0004002b, 0x00000026, + 0x00000116, 0x00003596, 0x0004002b, 0x00000026, 0x00000117, 0x0000332d, 0x0007002c, 0x0000002a, + 0x00000118, 0x00000115, 0x00000116, 0x00000117, 0x00000098, 0x0004002b, 0x00000026, 0x00000119, + 0x00003c55, 0x0004002b, 0x00000026, 0x0000011a, 0x00003faa, 0x0004002b, 0x00000026, 0x0000011b, + 0x00003cfa, 0x0004002b, 0x00000026, 0x0000011c, 0x00003dd8, 0x0007002c, 0x0000002a, 0x0000011d, + 0x00000119, 0x0000011a, 0x0000011b, 0x0000011c, 0x0004002b, 0x00000026, 0x0000011e, 0x0000b245, + 0x0004002b, 0x00000026, 0x0000011f, 0x00003a82, 0x0004002b, 0x00000026, 0x00000120, 0x000035ad, + 0x0004002b, 0x00000026, 0x00000121, 0x00003be2, 0x0007002c, 0x0000002a, 0x00000122, 0x0000011e, + 0x0000011f, 0x00000120, 0x00000121, 0x0004002b, 0x00000012, 0x00000123, 0x00000010, 0x0006002c, + 0x00000013, 0x0000000d, 0x00000123, 0x00000123, 0x00000021, 0x00050036, 0x0000000e, 0x00000002, + 0x00000000, 0x0000000f, 0x000200f8, 0x00000124, 0x000300f7, 0x00000125, 0x00000000, 0x000300fb, + 0x00000020, 0x00000126, 0x000200f8, 0x00000126, 0x0004003d, 0x00000013, 0x00000127, 0x00000003, + 0x0007004f, 0x00000015, 0x00000128, 0x00000127, 0x00000127, 0x00000000, 0x00000001, 0x0004007c, + 0x00000011, 0x00000129, 0x00000128, 0x0004003d, 0x00000017, 0x0000012a, 0x00000004, 0x00040068, + 0x00000011, 0x0000012b, 0x0000012a, 0x000500af, 0x0000001a, 0x0000012c, 0x00000129, 0x0000012b, + 0x0004009a, 0x00000019, 0x0000012d, 0x0000012c, 0x000300f7, 0x0000012e, 0x00000000, 0x000400fa, + 0x0000012d, 0x0000012f, 0x0000012e, 0x000200f8, 0x0000012f, 0x000200f9, 0x00000125, 0x000200f8, + 0x0000012e, 0x0004003d, 0x0000001c, 0x00000130, 0x00000005, 0x00040064, 0x0000001b, 0x00000131, + 0x00000130, 0x00050067, 0x00000011, 0x00000132, 0x00000131, 0x0000001e, 0x0004007c, 0x00000015, + 0x00000133, 0x00000132, 0x00050051, 0x00000012, 0x00000134, 0x00000133, 0x00000000, 0x00040070, + 0x00000016, 0x00000135, 0x00000134, 0x00050051, 0x00000012, 0x00000136, 0x00000133, 0x00000001, + 0x00040070, 0x00000016, 0x00000137, 0x00000136, 0x00050050, 0x0000001f, 0x00000138, 0x00000135, + 0x00000137, 0x00040070, 0x0000001f, 0x00000139, 0x00000128, 0x00050081, 0x0000001f, 0x0000013a, + 0x00000139, 0x00000023, 0x00050088, 0x0000001f, 0x0000013b, 0x0000013a, 0x00000138, 0x0004007c, + 0x00000011, 0x0000013c, 0x00000133, 0x00050082, 0x00000011, 0x0000013d, 0x0000013c, 0x00000025, + 0x00050041, 0x00000029, 0x0000013e, 0x00000007, 0x00000024, 0x0004003d, 0x00000016, 0x0000013f, + 0x0000013e, 0x00050083, 0x00000016, 0x00000140, 0x00000027, 0x0000013f, 0x00040073, 0x00000026, + 0x00000141, 0x00000140, 0x00040073, 0x00000026, 0x00000142, 0x0000013f, 0x0004003d, 0x0000001c, + 0x00000143, 0x00000008, 0x00070058, 0x0000002c, 0x00000144, 0x00000143, 0x0000013b, 0x00000002, + 0x0000002b, 0x00040073, 0x0000002a, 0x00000145, 0x00000144, 0x0004003d, 0x0000001c, 0x00000146, + 0x00000008, 0x0007004f, 0x0000002d, 0x00000147, 0x00000145, 0x00000145, 0x00000000, 0x00000001, + 0x0005008e, 0x0000002d, 0x00000148, 0x00000147, 0x00000141, 0x00040073, 0x0000001f, 0x00000149, + 0x00000148, 0x00050081, 0x0000001f, 0x0000014a, 0x0000013a, 0x00000149, 0x00050088, 0x0000001f, + 0x0000014b, 0x0000014a, 0x00000138, 0x00070058, 0x0000002c, 0x0000014c, 0x00000146, 0x0000014b, + 0x00000002, 0x0000002b, 0x0007004f, 0x0000001f, 0x0000014d, 0x0000014c, 0x0000014c, 0x00000000, + 0x00000001, 0x00040073, 0x0000002d, 0x0000014e, 0x0000014d, 0x00040073, 0x0000001f, 0x0000014f, + 0x0000014e, 0x00050081, 0x0000001f, 0x00000150, 0x0000013a, 0x0000014f, 0x00050088, 0x0000001f, + 0x00000151, 0x00000150, 0x00000138, 0x0004003d, 0x0000001c, 0x00000152, 0x00000008, 0x0007004f, + 0x0000002d, 0x00000153, 0x00000145, 0x00000145, 0x00000002, 0x00000003, 0x0005008e, 0x0000002d, + 0x00000154, 0x00000153, 0x00000142, 0x00040073, 0x0000001f, 0x00000155, 0x00000154, 0x00050081, + 0x0000001f, 0x00000156, 0x0000013a, 0x00000155, 0x00050088, 0x0000001f, 0x00000157, 0x00000156, + 0x00000138, 0x00070058, 0x0000002c, 0x00000158, 0x00000152, 0x00000157, 0x00000002, 0x0000002b, + 0x0007004f, 0x0000001f, 0x00000159, 0x00000158, 0x00000158, 0x00000002, 0x00000003, 0x00040073, + 0x0000002d, 0x0000015a, 0x00000159, 0x00040073, 0x0000001f, 0x0000015b, 0x0000015a, 0x00050081, + 0x0000001f, 0x0000015c, 0x0000013a, 0x0000015b, 0x00050088, 0x0000001f, 0x0000015d, 0x0000015c, + 0x00000138, 0x0004003d, 0x0000001c, 0x0000015e, 0x00000009, 0x00070058, 0x0000002c, 0x0000015f, + 0x0000015e, 0x0000013b, 0x00000002, 0x0000002b, 0x00040073, 0x0000002a, 0x00000160, 0x0000015f, + 0x0004003d, 0x0000001c, 0x00000161, 0x00000009, 0x0007004f, 0x0000002d, 0x00000162, 0x00000160, + 0x00000160, 0x00000000, 0x00000001, 0x0005008e, 0x0000002d, 0x00000163, 0x00000162, 0x00000141, + 0x00040073, 0x0000001f, 0x00000164, 0x00000163, 0x00050081, 0x0000001f, 0x00000165, 0x0000013a, + 0x00000164, 0x00050088, 0x0000001f, 0x00000166, 0x00000165, 0x00000138, 0x00070058, 0x0000002c, + 0x00000167, 0x00000161, 0x00000166, 0x00000002, 0x0000002b, 0x0007004f, 0x0000001f, 0x00000168, + 0x00000167, 0x00000167, 0x00000000, 0x00000001, 0x00040073, 0x0000002d, 0x00000169, 0x00000168, + 0x0004003d, 0x0000001c, 0x0000016a, 0x00000009, 0x0007004f, 0x0000002d, 0x0000016b, 0x00000160, + 0x00000160, 0x00000002, 0x00000003, 0x0005008e, 0x0000002d, 0x0000016c, 0x0000016b, 0x00000142, + 0x00040073, 0x0000001f, 0x0000016d, 0x0000016c, 0x00050081, 0x0000001f, 0x0000016e, 0x0000013a, + 0x0000016d, 0x00050088, 0x0000001f, 0x0000016f, 0x0000016e, 0x00000138, 0x00070058, 0x0000002c, + 0x00000170, 0x0000016a, 0x0000016f, 0x00000002, 0x0000002b, 0x0007004f, 0x0000001f, 0x00000171, + 0x00000170, 0x00000170, 0x00000002, 0x00000003, 0x00040073, 0x0000002d, 0x00000172, 0x00000171, + 0x00050051, 0x00000026, 0x00000173, 0x00000169, 0x00000000, 0x00050051, 0x00000026, 0x00000174, + 0x00000169, 0x00000001, 0x00050051, 0x00000026, 0x00000175, 0x00000172, 0x00000000, 0x00050051, + 0x00000026, 0x00000176, 0x00000172, 0x00000001, 0x00070050, 0x0000002a, 0x00000177, 0x00000173, + 0x00000174, 0x00000175, 0x00000176, 0x0007004f, 0x0000002d, 0x00000178, 0x00000177, 0x00000177, + 0x00000000, 0x00000001, 0x00040073, 0x0000001f, 0x00000179, 0x00000178, 0x00050081, 0x0000001f, + 0x0000017a, 0x0000013a, 0x00000179, 0x00050088, 0x0000001f, 0x0000017b, 0x0000017a, 0x00000138, + 0x0007004f, 0x0000002d, 0x0000017c, 0x00000177, 0x00000177, 0x00000002, 0x00000003, 0x00040073, + 0x0000001f, 0x0000017d, 0x0000017c, 0x00050081, 0x0000001f, 0x0000017e, 0x0000013a, 0x0000017d, + 0x00050088, 0x0000001f, 0x0000017f, 0x0000017e, 0x00000138, 0x0004003d, 0x0000001c, 0x00000180, + 0x00000005, 0x00070058, 0x0000002c, 0x00000181, 0x00000180, 0x00000151, 0x00000002, 0x0000002b, + 0x00040073, 0x0000002a, 0x00000182, 0x00000181, 0x0004003d, 0x0000001c, 0x00000183, 0x0000000a, + 0x00070058, 0x0000002c, 0x00000184, 0x00000183, 0x00000151, 0x00000002, 0x0000002b, 0x00040073, + 0x0000002a, 0x00000185, 0x00000184, 0x0004003d, 0x0000001c, 0x00000186, 0x00000005, 0x00070058, + 0x0000002c, 0x00000187, 0x00000186, 0x0000017b, 0x00000002, 0x0000002b, 0x00040073, 0x0000002a, + 0x00000188, 0x00000187, 0x0004003d, 0x0000001c, 0x00000189, 0x0000000a, 0x00070058, 0x0000002c, + 0x0000018a, 0x00000189, 0x0000017b, 0x00000002, 0x0000002b, 0x00040073, 0x0000002a, 0x0000018b, + 0x0000018a, 0x0004003d, 0x0000001c, 0x0000018c, 0x0000000b, 0x00050080, 0x00000011, 0x0000018d, + 0x00000129, 0x00000031, 0x0008000c, 0x00000011, 0x0000018e, 0x00000001, 0x0000002d, 0x0000018d, + 0x00000032, 0x0000013d, 0x00040064, 0x0000001b, 0x0000018f, 0x0000018c, 0x0007005f, 0x0000002c, + 0x00000190, 0x0000018f, 0x0000018e, 0x00000002, 0x0000001e, 0x00040073, 0x0000002a, 0x00000191, + 0x00000190, 0x0004003d, 0x0000001c, 0x00000192, 0x0000000c, 0x00040064, 0x0000001b, 0x00000193, + 0x00000192, 0x0007005f, 0x0000002c, 0x00000194, 0x00000193, 0x0000018e, 0x00000002, 0x0000001e, + 0x00040073, 0x0000002a, 0x00000195, 0x00000194, 0x0004003d, 0x0000001c, 0x00000196, 0x0000000b, + 0x00050080, 0x00000011, 0x00000197, 0x00000129, 0x00000033, 0x0008000c, 0x00000011, 0x00000198, + 0x00000001, 0x0000002d, 0x00000197, 0x00000032, 0x0000013d, 0x00040064, 0x0000001b, 0x00000199, + 0x00000196, 0x0007005f, 0x0000002c, 0x0000019a, 0x00000199, 0x00000198, 0x00000002, 0x0000001e, + 0x00040073, 0x0000002a, 0x0000019b, 0x0000019a, 0x0004003d, 0x0000001c, 0x0000019c, 0x0000000c, + 0x00040064, 0x0000001b, 0x0000019d, 0x0000019c, 0x0007005f, 0x0000002c, 0x0000019e, 0x0000019d, + 0x00000198, 0x00000002, 0x0000001e, 0x00040073, 0x0000002a, 0x0000019f, 0x0000019e, 0x0004003d, + 0x0000001c, 0x000001a0, 0x0000000b, 0x00050080, 0x00000011, 0x000001a1, 0x00000129, 0x00000034, + 0x0008000c, 0x00000011, 0x000001a2, 0x00000001, 0x0000002d, 0x000001a1, 0x00000032, 0x0000013d, + 0x00040064, 0x0000001b, 0x000001a3, 0x000001a0, 0x0007005f, 0x0000002c, 0x000001a4, 0x000001a3, + 0x000001a2, 0x00000002, 0x0000001e, 0x00040073, 0x0000002a, 0x000001a5, 0x000001a4, 0x0004003d, + 0x0000001c, 0x000001a6, 0x0000000c, 0x00040064, 0x0000001b, 0x000001a7, 0x000001a6, 0x0007005f, + 0x0000002c, 0x000001a8, 0x000001a7, 0x000001a2, 0x00000002, 0x0000001e, 0x00040073, 0x0000002a, + 0x000001a9, 0x000001a8, 0x0004003d, 0x0000001c, 0x000001aa, 0x0000000b, 0x00050080, 0x00000011, + 0x000001ab, 0x00000129, 0x00000035, 0x0008000c, 0x00000011, 0x000001ac, 0x00000001, 0x0000002d, + 0x000001ab, 0x00000032, 0x0000013d, 0x00040064, 0x0000001b, 0x000001ad, 0x000001aa, 0x0007005f, + 0x0000002c, 0x000001ae, 0x000001ad, 0x000001ac, 0x00000002, 0x0000001e, 0x00040073, 0x0000002a, + 0x000001af, 0x000001ae, 0x00050094, 0x00000026, 0x000001b0, 0x00000182, 0x000001af, 0x00050094, + 0x00000026, 0x000001b1, 0x00000182, 0x00000191, 0x00050094, 0x00000026, 0x000001b2, 0x00000185, + 0x00000195, 0x00050081, 0x00000026, 0x000001b3, 0x000001b1, 0x000001b2, 0x00050094, 0x00000026, + 0x000001b4, 0x00000182, 0x0000019b, 0x00050094, 0x00000026, 0x000001b5, 0x00000185, 0x0000019f, + 0x00050081, 0x00000026, 0x000001b6, 0x000001b4, 0x000001b5, 0x00050094, 0x00000026, 0x000001b7, + 0x00000182, 0x000001a5, 0x00050094, 0x00000026, 0x000001b8, 0x00000185, 0x000001a9, 0x00050081, + 0x00000026, 0x000001b9, 0x000001b7, 0x000001b8, 0x00070050, 0x0000002a, 0x000001ba, 0x000001b3, + 0x000001b6, 0x000001b9, 0x000001b0, 0x00050094, 0x00000026, 0x000001bb, 0x00000188, 0x000001af, + 0x00050094, 0x00000026, 0x000001bc, 0x00000188, 0x00000191, 0x00050094, 0x00000026, 0x000001bd, + 0x0000018b, 0x00000195, 0x00050081, 0x00000026, 0x000001be, 0x000001bc, 0x000001bd, 0x00050094, + 0x00000026, 0x000001bf, 0x00000188, 0x0000019b, 0x00050094, 0x00000026, 0x000001c0, 0x0000018b, + 0x0000019f, 0x00050081, 0x00000026, 0x000001c1, 0x000001bf, 0x000001c0, 0x00050094, 0x00000026, + 0x000001c2, 0x00000188, 0x000001a5, 0x00050094, 0x00000026, 0x000001c3, 0x0000018b, 0x000001a9, + 0x00050081, 0x00000026, 0x000001c4, 0x000001c2, 0x000001c3, 0x00070050, 0x0000002a, 0x000001c5, + 0x000001be, 0x000001c1, 0x000001c4, 0x000001bb, 0x0004003d, 0x0000001c, 0x000001c6, 0x0000000c, + 0x00040064, 0x0000001b, 0x000001c7, 0x000001c6, 0x0007005f, 0x0000002c, 0x000001c8, 0x000001c7, + 0x000001ac, 0x00000002, 0x0000001e, 0x00040073, 0x0000002a, 0x000001c9, 0x000001c8, 0x00050094, + 0x00000026, 0x000001ca, 0x00000185, 0x000001c9, 0x00050081, 0x00000026, 0x000001cb, 0x000001b0, + 0x000001ca, 0x00060052, 0x0000002a, 0x000001cc, 0x000001cb, 0x000001ba, 0x00000003, 0x00050094, + 0x00000026, 0x000001cd, 0x0000018b, 0x000001c9, 0x00050081, 0x00000026, 0x000001ce, 0x000001bb, + 0x000001cd, 0x00060052, 0x0000002a, 0x000001cf, 0x000001ce, 0x000001c5, 0x00000003, 0x0004003d, + 0x0000001c, 0x000001d0, 0x0000000b, 0x00070058, 0x0000002c, 0x000001d1, 0x000001d0, 0x0000013b, + 0x00000002, 0x0000002b, 0x00040073, 0x0000002a, 0x000001d2, 0x000001d1, 0x0004003d, 0x0000001c, + 0x000001d3, 0x0000000c, 0x00070058, 0x0000002c, 0x000001d4, 0x000001d3, 0x0000013b, 0x00000002, + 0x0000002b, 0x00040073, 0x0000002a, 0x000001d5, 0x000001d4, 0x0004003d, 0x0000001c, 0x000001d6, + 0x0000000b, 0x00050080, 0x00000011, 0x000001d7, 0x00000129, 0x00000036, 0x0008000c, 0x00000011, + 0x000001d8, 0x00000001, 0x0000002d, 0x000001d7, 0x00000032, 0x0000013d, 0x00040064, 0x0000001b, + 0x000001d9, 0x000001d6, 0x0007005f, 0x0000002c, 0x000001da, 0x000001d9, 0x000001d8, 0x00000002, + 0x0000001e, 0x00040073, 0x0000002a, 0x000001db, 0x000001da, 0x0004003d, 0x0000001c, 0x000001dc, + 0x0000000c, 0x00040064, 0x0000001b, 0x000001dd, 0x000001dc, 0x0007005f, 0x0000002c, 0x000001de, + 0x000001dd, 0x000001d8, 0x00000002, 0x0000001e, 0x00040073, 0x0000002a, 0x000001df, 0x000001de, + 0x0004003d, 0x0000001c, 0x000001e0, 0x0000000b, 0x00050080, 0x00000011, 0x000001e1, 0x00000129, + 0x00000037, 0x0008000c, 0x00000011, 0x000001e2, 0x00000001, 0x0000002d, 0x000001e1, 0x00000032, + 0x0000013d, 0x00040064, 0x0000001b, 0x000001e3, 0x000001e0, 0x0007005f, 0x0000002c, 0x000001e4, + 0x000001e3, 0x000001e2, 0x00000002, 0x0000001e, 0x00040073, 0x0000002a, 0x000001e5, 0x000001e4, + 0x0004003d, 0x0000001c, 0x000001e6, 0x0000000c, 0x00040064, 0x0000001b, 0x000001e7, 0x000001e6, + 0x0007005f, 0x0000002c, 0x000001e8, 0x000001e7, 0x000001e2, 0x00000002, 0x0000001e, 0x00040073, + 0x0000002a, 0x000001e9, 0x000001e8, 0x0004003d, 0x0000001c, 0x000001ea, 0x0000000b, 0x00050080, + 0x00000011, 0x000001eb, 0x00000129, 0x00000038, 0x0008000c, 0x00000011, 0x000001ec, 0x00000001, + 0x0000002d, 0x000001eb, 0x00000032, 0x0000013d, 0x00040064, 0x0000001b, 0x000001ed, 0x000001ea, + 0x0007005f, 0x0000002c, 0x000001ee, 0x000001ed, 0x000001ec, 0x00000002, 0x0000001e, 0x00040073, + 0x0000002a, 0x000001ef, 0x000001ee, 0x00050094, 0x00000026, 0x000001f0, 0x00000182, 0x000001ef, + 0x00050094, 0x00000026, 0x000001f1, 0x00000182, 0x000001d2, 0x00050094, 0x00000026, 0x000001f2, + 0x00000185, 0x000001d5, 0x00050081, 0x00000026, 0x000001f3, 0x000001f1, 0x000001f2, 0x00050094, + 0x00000026, 0x000001f4, 0x00000182, 0x000001db, 0x00050094, 0x00000026, 0x000001f5, 0x00000185, + 0x000001df, 0x00050081, 0x00000026, 0x000001f6, 0x000001f4, 0x000001f5, 0x00050094, 0x00000026, + 0x000001f7, 0x00000182, 0x000001e5, 0x00050094, 0x00000026, 0x000001f8, 0x00000185, 0x000001e9, + 0x00050081, 0x00000026, 0x000001f9, 0x000001f7, 0x000001f8, 0x00070050, 0x0000002a, 0x000001fa, + 0x000001f3, 0x000001f6, 0x000001f9, 0x000001f0, 0x00050094, 0x00000026, 0x000001fb, 0x00000188, + 0x000001ef, 0x00050094, 0x00000026, 0x000001fc, 0x00000188, 0x000001d2, 0x00050094, 0x00000026, + 0x000001fd, 0x0000018b, 0x000001d5, 0x00050081, 0x00000026, 0x000001fe, 0x000001fc, 0x000001fd, + 0x00050094, 0x00000026, 0x000001ff, 0x00000188, 0x000001db, 0x00050094, 0x00000026, 0x00000200, + 0x0000018b, 0x000001df, 0x00050081, 0x00000026, 0x00000201, 0x000001ff, 0x00000200, 0x00050094, + 0x00000026, 0x00000202, 0x00000188, 0x000001e5, 0x00050094, 0x00000026, 0x00000203, 0x0000018b, + 0x000001e9, 0x00050081, 0x00000026, 0x00000204, 0x00000202, 0x00000203, 0x00070050, 0x0000002a, + 0x00000205, 0x000001fe, 0x00000201, 0x00000204, 0x000001fb, 0x0004003d, 0x0000001c, 0x00000206, + 0x0000000c, 0x00040064, 0x0000001b, 0x00000207, 0x00000206, 0x0007005f, 0x0000002c, 0x00000208, + 0x00000207, 0x000001ec, 0x00000002, 0x0000001e, 0x00040073, 0x0000002a, 0x00000209, 0x00000208, + 0x00050094, 0x00000026, 0x0000020a, 0x00000185, 0x00000209, 0x00050081, 0x00000026, 0x0000020b, + 0x000001f0, 0x0000020a, 0x00060052, 0x0000002a, 0x0000020c, 0x0000020b, 0x000001fa, 0x00000003, + 0x00050094, 0x00000026, 0x0000020d, 0x0000018b, 0x00000209, 0x00050081, 0x00000026, 0x0000020e, + 0x000001fb, 0x0000020d, 0x00060052, 0x0000002a, 0x0000020f, 0x0000020e, 0x00000205, 0x00000003, + 0x0004003d, 0x0000001c, 0x00000210, 0x0000000b, 0x00050080, 0x00000011, 0x00000211, 0x00000129, + 0x00000025, 0x0008000c, 0x00000011, 0x00000212, 0x00000001, 0x0000002d, 0x00000211, 0x00000032, + 0x0000013d, 0x00040064, 0x0000001b, 0x00000213, 0x00000210, 0x0007005f, 0x0000002c, 0x00000214, + 0x00000213, 0x00000212, 0x00000002, 0x0000001e, 0x00040073, 0x0000002a, 0x00000215, 0x00000214, + 0x0004003d, 0x0000001c, 0x00000216, 0x0000000c, 0x00040064, 0x0000001b, 0x00000217, 0x00000216, + 0x0007005f, 0x0000002c, 0x00000218, 0x00000217, 0x00000212, 0x00000002, 0x0000001e, 0x00040073, + 0x0000002a, 0x00000219, 0x00000218, 0x0004003d, 0x0000001c, 0x0000021a, 0x0000000b, 0x00070058, + 0x0000002c, 0x0000021b, 0x0000021a, 0x0000015d, 0x00000002, 0x0000002b, 0x00040073, 0x0000002a, + 0x0000021c, 0x0000021b, 0x0004003d, 0x0000001c, 0x0000021d, 0x0000000c, 0x00070058, 0x0000002c, + 0x0000021e, 0x0000021d, 0x0000015d, 0x00000002, 0x0000002b, 0x00040073, 0x0000002a, 0x0000021f, + 0x0000021e, 0x0004003d, 0x0000001c, 0x00000220, 0x0000000b, 0x00070058, 0x0000002c, 0x00000221, + 0x00000220, 0x0000017f, 0x00000002, 0x0000002b, 0x00040073, 0x0000002a, 0x00000222, 0x00000221, + 0x0004003d, 0x0000001c, 0x00000223, 0x0000000c, 0x00070058, 0x0000002c, 0x00000224, 0x00000223, + 0x0000017f, 0x00000002, 0x0000002b, 0x00040073, 0x0000002a, 0x00000225, 0x00000224, 0x0004003d, + 0x0000001c, 0x00000226, 0x00000005, 0x00040064, 0x0000001b, 0x00000227, 0x00000226, 0x0007005f, + 0x0000002c, 0x00000228, 0x00000227, 0x0000018e, 0x00000002, 0x0000001e, 0x00040073, 0x0000002a, + 0x00000229, 0x00000228, 0x0004003d, 0x0000001c, 0x0000022a, 0x0000000a, 0x00040064, 0x0000001b, + 0x0000022b, 0x0000022a, 0x0007005f, 0x0000002c, 0x0000022c, 0x0000022b, 0x0000018e, 0x00000002, + 0x0000001e, 0x00040073, 0x0000002a, 0x0000022d, 0x0000022c, 0x0004003d, 0x0000001c, 0x0000022e, + 0x00000005, 0x00040064, 0x0000001b, 0x0000022f, 0x0000022e, 0x0007005f, 0x0000002c, 0x00000230, + 0x0000022f, 0x00000198, 0x00000002, 0x0000001e, 0x00040073, 0x0000002a, 0x00000231, 0x00000230, + 0x0004003d, 0x0000001c, 0x00000232, 0x0000000a, 0x00040064, 0x0000001b, 0x00000233, 0x00000232, + 0x0007005f, 0x0000002c, 0x00000234, 0x00000233, 0x00000198, 0x00000002, 0x0000001e, 0x00040073, + 0x0000002a, 0x00000235, 0x00000234, 0x0004003d, 0x0000001c, 0x00000236, 0x00000005, 0x00040064, + 0x0000001b, 0x00000237, 0x00000236, 0x0007005f, 0x0000002c, 0x00000238, 0x00000237, 0x000001a2, + 0x00000002, 0x0000001e, 0x00040073, 0x0000002a, 0x00000239, 0x00000238, 0x0004003d, 0x0000001c, + 0x0000023a, 0x0000000a, 0x00040064, 0x0000001b, 0x0000023b, 0x0000023a, 0x0007005f, 0x0000002c, + 0x0000023c, 0x0000023b, 0x000001a2, 0x00000002, 0x0000001e, 0x00040073, 0x0000002a, 0x0000023d, + 0x0000023c, 0x0004003d, 0x0000001c, 0x0000023e, 0x00000005, 0x00040064, 0x0000001b, 0x0000023f, + 0x0000023e, 0x0007005f, 0x0000002c, 0x00000240, 0x0000023f, 0x000001ac, 0x00000002, 0x0000001e, + 0x00040073, 0x0000002a, 0x00000241, 0x00000240, 0x00050094, 0x00000026, 0x00000242, 0x0000021c, + 0x00000241, 0x00050094, 0x00000026, 0x00000243, 0x0000021c, 0x00000229, 0x00050094, 0x00000026, + 0x00000244, 0x0000021f, 0x0000022d, 0x00050081, 0x00000026, 0x00000245, 0x00000243, 0x00000244, + 0x00050094, 0x00000026, 0x00000246, 0x0000021c, 0x00000231, 0x00050094, 0x00000026, 0x00000247, + 0x0000021f, 0x00000235, 0x00050081, 0x00000026, 0x00000248, 0x00000246, 0x00000247, 0x00050094, + 0x00000026, 0x00000249, 0x0000021c, 0x00000239, 0x00050094, 0x00000026, 0x0000024a, 0x0000021f, + 0x0000023d, 0x00050081, 0x00000026, 0x0000024b, 0x00000249, 0x0000024a, 0x00070050, 0x0000002a, + 0x0000024c, 0x00000245, 0x00000248, 0x0000024b, 0x00000242, 0x00050094, 0x00000026, 0x0000024d, + 0x00000222, 0x00000241, 0x00050094, 0x00000026, 0x0000024e, 0x00000222, 0x00000229, 0x00050094, + 0x00000026, 0x0000024f, 0x00000225, 0x0000022d, 0x00050081, 0x00000026, 0x00000250, 0x0000024e, + 0x0000024f, 0x00050094, 0x00000026, 0x00000251, 0x00000222, 0x00000231, 0x00050094, 0x00000026, + 0x00000252, 0x00000225, 0x00000235, 0x00050081, 0x00000026, 0x00000253, 0x00000251, 0x00000252, + 0x00050094, 0x00000026, 0x00000254, 0x00000222, 0x00000239, 0x00050094, 0x00000026, 0x00000255, + 0x00000225, 0x0000023d, 0x00050081, 0x00000026, 0x00000256, 0x00000254, 0x00000255, 0x00070050, + 0x0000002a, 0x00000257, 0x00000250, 0x00000253, 0x00000256, 0x0000024d, 0x0004003d, 0x0000001c, + 0x00000258, 0x0000000a, 0x00040064, 0x0000001b, 0x00000259, 0x00000258, 0x0007005f, 0x0000002c, + 0x0000025a, 0x00000259, 0x000001ac, 0x00000002, 0x0000001e, 0x00040073, 0x0000002a, 0x0000025b, + 0x0000025a, 0x00050094, 0x00000026, 0x0000025c, 0x0000021f, 0x0000025b, 0x00050081, 0x00000026, + 0x0000025d, 0x00000242, 0x0000025c, 0x00060052, 0x0000002a, 0x0000025e, 0x0000025d, 0x0000024c, + 0x00000003, 0x00050094, 0x00000026, 0x0000025f, 0x00000225, 0x0000025b, 0x00050081, 0x00000026, + 0x00000260, 0x0000024d, 0x0000025f, 0x00060052, 0x0000002a, 0x00000261, 0x00000260, 0x00000257, + 0x00000003, 0x0004003d, 0x0000001c, 0x00000262, 0x00000005, 0x00070058, 0x0000002c, 0x00000263, + 0x00000262, 0x0000013b, 0x00000002, 0x0000002b, 0x00040073, 0x0000002a, 0x00000264, 0x00000263, + 0x0004003d, 0x0000001c, 0x00000265, 0x0000000a, 0x00070058, 0x0000002c, 0x00000266, 0x00000265, + 0x0000013b, 0x00000002, 0x0000002b, 0x00040073, 0x0000002a, 0x00000267, 0x00000266, 0x0004003d, + 0x0000001c, 0x00000268, 0x00000005, 0x00040064, 0x0000001b, 0x00000269, 0x00000268, 0x0007005f, + 0x0000002c, 0x0000026a, 0x00000269, 0x000001d8, 0x00000002, 0x0000001e, 0x00040073, 0x0000002a, + 0x0000026b, 0x0000026a, 0x0004003d, 0x0000001c, 0x0000026c, 0x0000000a, 0x00040064, 0x0000001b, + 0x0000026d, 0x0000026c, 0x0007005f, 0x0000002c, 0x0000026e, 0x0000026d, 0x000001d8, 0x00000002, + 0x0000001e, 0x00040073, 0x0000002a, 0x0000026f, 0x0000026e, 0x0004003d, 0x0000001c, 0x00000270, + 0x00000005, 0x00040064, 0x0000001b, 0x00000271, 0x00000270, 0x0007005f, 0x0000002c, 0x00000272, + 0x00000271, 0x000001e2, 0x00000002, 0x0000001e, 0x00040073, 0x0000002a, 0x00000273, 0x00000272, + 0x0004003d, 0x0000001c, 0x00000274, 0x0000000a, 0x00040064, 0x0000001b, 0x00000275, 0x00000274, + 0x0007005f, 0x0000002c, 0x00000276, 0x00000275, 0x000001e2, 0x00000002, 0x0000001e, 0x00040073, + 0x0000002a, 0x00000277, 0x00000276, 0x0004003d, 0x0000001c, 0x00000278, 0x00000005, 0x00040064, + 0x0000001b, 0x00000279, 0x00000278, 0x0007005f, 0x0000002c, 0x0000027a, 0x00000279, 0x000001ec, + 0x00000002, 0x0000001e, 0x00040073, 0x0000002a, 0x0000027b, 0x0000027a, 0x00050094, 0x00000026, + 0x0000027c, 0x0000021c, 0x0000027b, 0x00050094, 0x00000026, 0x0000027d, 0x0000021c, 0x00000264, + 0x00050094, 0x00000026, 0x0000027e, 0x0000021f, 0x00000267, 0x00050081, 0x00000026, 0x0000027f, + 0x0000027d, 0x0000027e, 0x00050094, 0x00000026, 0x00000280, 0x0000021c, 0x0000026b, 0x00050094, + 0x00000026, 0x00000281, 0x0000021f, 0x0000026f, 0x00050081, 0x00000026, 0x00000282, 0x00000280, + 0x00000281, 0x00050094, 0x00000026, 0x00000283, 0x0000021c, 0x00000273, 0x00050094, 0x00000026, + 0x00000284, 0x0000021f, 0x00000277, 0x00050081, 0x00000026, 0x00000285, 0x00000283, 0x00000284, + 0x00070050, 0x0000002a, 0x00000286, 0x0000027f, 0x00000282, 0x00000285, 0x0000027c, 0x00050094, + 0x00000026, 0x00000287, 0x00000222, 0x0000027b, 0x00050094, 0x00000026, 0x00000288, 0x00000222, + 0x00000264, 0x00050094, 0x00000026, 0x00000289, 0x00000225, 0x00000267, 0x00050081, 0x00000026, + 0x0000028a, 0x00000288, 0x00000289, 0x00050094, 0x00000026, 0x0000028b, 0x00000222, 0x0000026b, + 0x00050094, 0x00000026, 0x0000028c, 0x00000225, 0x0000026f, 0x00050081, 0x00000026, 0x0000028d, + 0x0000028b, 0x0000028c, 0x00050094, 0x00000026, 0x0000028e, 0x00000222, 0x00000273, 0x00050094, + 0x00000026, 0x0000028f, 0x00000225, 0x00000277, 0x00050081, 0x00000026, 0x00000290, 0x0000028e, + 0x0000028f, 0x00070050, 0x0000002a, 0x00000291, 0x0000028a, 0x0000028d, 0x00000290, 0x00000287, + 0x0004003d, 0x0000001c, 0x00000292, 0x0000000a, 0x00040064, 0x0000001b, 0x00000293, 0x00000292, + 0x0007005f, 0x0000002c, 0x00000294, 0x00000293, 0x000001ec, 0x00000002, 0x0000001e, 0x00040073, + 0x0000002a, 0x00000295, 0x00000294, 0x00050094, 0x00000026, 0x00000296, 0x0000021f, 0x00000295, + 0x00050081, 0x00000026, 0x00000297, 0x0000027c, 0x00000296, 0x00060052, 0x0000002a, 0x00000298, + 0x00000297, 0x00000286, 0x00000003, 0x00050094, 0x00000026, 0x00000299, 0x00000225, 0x00000295, + 0x00050081, 0x00000026, 0x0000029a, 0x00000287, 0x00000299, 0x00060052, 0x0000002a, 0x0000029b, + 0x0000029a, 0x00000291, 0x00000003, 0x0004003d, 0x0000001c, 0x0000029c, 0x00000005, 0x00040064, + 0x0000001b, 0x0000029d, 0x0000029c, 0x0007005f, 0x0000002c, 0x0000029e, 0x0000029d, 0x00000212, + 0x00000002, 0x0000001e, 0x00040073, 0x0000002a, 0x0000029f, 0x0000029e, 0x0004003d, 0x0000001c, + 0x000002a0, 0x0000000a, 0x00040064, 0x0000001b, 0x000002a1, 0x000002a0, 0x0007005f, 0x0000002c, + 0x000002a2, 0x000002a1, 0x00000212, 0x00000002, 0x0000001e, 0x00040073, 0x0000002a, 0x000002a3, + 0x000002a2, 0x00050083, 0x0000002a, 0x000002a4, 0x000001cc, 0x00000053, 0x00050085, 0x0000002a, + 0x000002a5, 0x000002a4, 0x00000058, 0x00050081, 0x0000002a, 0x000002a6, 0x000002a5, 0x0000005d, + 0x0008000c, 0x0000002a, 0x000002a7, 0x00000001, 0x0000002b, 0x000002a6, 0x0000002f, 0x0000005f, + 0x00050091, 0x0000002a, 0x000002a8, 0x0000004e, 0x000002a7, 0x00050083, 0x0000002a, 0x000002a9, + 0x0000020c, 0x00000077, 0x00050085, 0x0000002a, 0x000002aa, 0x000002a9, 0x0000007c, 0x00050081, + 0x0000002a, 0x000002ab, 0x000002aa, 0x00000081, 0x0008000c, 0x0000002a, 0x000002ac, 0x00000001, + 0x0000002b, 0x000002ab, 0x0000002f, 0x0000005f, 0x00050091, 0x0000002a, 0x000002ad, 0x00000074, + 0x000002ac, 0x00050081, 0x0000002a, 0x000002ae, 0x000002a8, 0x000002ad, 0x00050094, 0x00000026, + 0x000002af, 0x00000182, 0x00000215, 0x00050094, 0x00000026, 0x000002b0, 0x00000185, 0x00000219, + 0x00050081, 0x00000026, 0x000002b1, 0x000002af, 0x000002b0, 0x00050083, 0x00000026, 0x000002b2, + 0x000002b1, 0x00000086, 0x00050085, 0x00000026, 0x000002b3, 0x000002b2, 0x00000087, 0x00050081, + 0x00000026, 0x000002b4, 0x000002b3, 0x00000088, 0x0008000c, 0x00000026, 0x000002b5, 0x00000001, + 0x0000002b, 0x000002b4, 0x0000002e, 0x0000005e, 0x0005008e, 0x0000002a, 0x000002b6, 0x00000085, + 0x000002b5, 0x00050081, 0x0000002a, 0x000002b7, 0x000002ae, 0x000002b6, 0x00050083, 0x0000002a, + 0x000002b8, 0x0000025e, 0x00000053, 0x00050085, 0x0000002a, 0x000002b9, 0x000002b8, 0x00000058, + 0x00050081, 0x0000002a, 0x000002ba, 0x000002b9, 0x0000005d, 0x0008000c, 0x0000002a, 0x000002bb, + 0x00000001, 0x0000002b, 0x000002ba, 0x0000002f, 0x0000005f, 0x00050091, 0x0000002a, 0x000002bc, + 0x0000009d, 0x000002bb, 0x00050081, 0x0000002a, 0x000002bd, 0x000002b7, 0x000002bc, 0x00050083, + 0x0000002a, 0x000002be, 0x00000298, 0x00000077, 0x00050085, 0x0000002a, 0x000002bf, 0x000002be, + 0x0000007c, 0x00050081, 0x0000002a, 0x000002c0, 0x000002bf, 0x00000081, 0x0008000c, 0x0000002a, + 0x000002c1, 0x00000001, 0x0000002b, 0x000002c0, 0x0000002f, 0x0000005f, 0x00050091, 0x0000002a, + 0x000002c2, 0x000000b2, 0x000002c1, 0x00050081, 0x0000002a, 0x000002c3, 0x000002bd, 0x000002c2, + 0x00050094, 0x00000026, 0x000002c4, 0x0000021c, 0x0000029f, 0x00050094, 0x00000026, 0x000002c5, + 0x0000021f, 0x000002a3, 0x00050081, 0x00000026, 0x000002c6, 0x000002c4, 0x000002c5, 0x00050083, + 0x00000026, 0x000002c7, 0x000002c6, 0x00000086, 0x00050085, 0x00000026, 0x000002c8, 0x000002c7, + 0x00000087, 0x00050081, 0x00000026, 0x000002c9, 0x000002c8, 0x00000088, 0x0008000c, 0x00000026, + 0x000002ca, 0x00000001, 0x0000002b, 0x000002c9, 0x0000002e, 0x0000005e, 0x0005008e, 0x0000002a, + 0x000002cb, 0x000000b7, 0x000002ca, 0x00050081, 0x0000002a, 0x000002cc, 0x000002c3, 0x000002cb, + 0x00050083, 0x0000002a, 0x000002cd, 0x000001cf, 0x00000053, 0x00050085, 0x0000002a, 0x000002ce, + 0x000002cd, 0x00000058, 0x00050081, 0x0000002a, 0x000002cf, 0x000002ce, 0x0000005d, 0x0008000c, + 0x0000002a, 0x000002d0, 0x00000001, 0x0000002b, 0x000002cf, 0x0000002f, 0x0000005f, 0x00050091, + 0x0000002a, 0x000002d1, 0x000000cc, 0x000002d0, 0x00050081, 0x0000002a, 0x000002d2, 0x000002cc, + 0x000002d1, 0x00050083, 0x0000002a, 0x000002d3, 0x0000020f, 0x00000077, 0x00050085, 0x0000002a, + 0x000002d4, 0x000002d3, 0x0000007c, 0x00050081, 0x0000002a, 0x000002d5, 0x000002d4, 0x00000081, + 0x0008000c, 0x0000002a, 0x000002d6, 0x00000001, 0x0000002b, 0x000002d5, 0x0000002f, 0x0000005f, + 0x00050091, 0x0000002a, 0x000002d7, 0x000000e1, 0x000002d6, 0x00050081, 0x0000002a, 0x000002d8, + 0x000002d2, 0x000002d7, 0x00050094, 0x00000026, 0x000002d9, 0x00000188, 0x00000215, 0x00050094, + 0x00000026, 0x000002da, 0x0000018b, 0x00000219, 0x00050081, 0x00000026, 0x000002db, 0x000002d9, + 0x000002da, 0x00050083, 0x00000026, 0x000002dc, 0x000002db, 0x00000086, 0x00050085, 0x00000026, + 0x000002dd, 0x000002dc, 0x00000087, 0x00050081, 0x00000026, 0x000002de, 0x000002dd, 0x00000088, + 0x0008000c, 0x00000026, 0x000002df, 0x00000001, 0x0000002b, 0x000002de, 0x0000002e, 0x0000005e, + 0x0005008e, 0x0000002a, 0x000002e0, 0x000000e6, 0x000002df, 0x00050081, 0x0000002a, 0x000002e1, + 0x000002d8, 0x000002e0, 0x0004003d, 0x00000017, 0x000002e2, 0x00000004, 0x00050083, 0x0000002a, + 0x000002e3, 0x00000261, 0x00000053, 0x00050085, 0x0000002a, 0x000002e4, 0x000002e3, 0x00000058, + 0x00050081, 0x0000002a, 0x000002e5, 0x000002e4, 0x0000005d, 0x0008000c, 0x0000002a, 0x000002e6, + 0x00000001, 0x0000002b, 0x000002e5, 0x0000002f, 0x0000005f, 0x00050091, 0x0000002a, 0x000002e7, + 0x000000fa, 0x000002e6, 0x00050081, 0x0000002a, 0x000002e8, 0x000002e1, 0x000002e7, 0x00050083, + 0x0000002a, 0x000002e9, 0x0000029b, 0x00000077, 0x00050085, 0x0000002a, 0x000002ea, 0x000002e9, + 0x0000007c, 0x00050081, 0x0000002a, 0x000002eb, 0x000002ea, 0x00000081, 0x0008000c, 0x0000002a, + 0x000002ec, 0x00000001, 0x0000002b, 0x000002eb, 0x0000002f, 0x0000005f, 0x00050091, 0x0000002a, + 0x000002ed, 0x0000010f, 0x000002ec, 0x00050081, 0x0000002a, 0x000002ee, 0x000002e8, 0x000002ed, + 0x00050094, 0x00000026, 0x000002ef, 0x00000222, 0x0000029f, 0x00050094, 0x00000026, 0x000002f0, + 0x00000225, 0x000002a3, 0x00050081, 0x00000026, 0x000002f1, 0x000002ef, 0x000002f0, 0x00050083, + 0x00000026, 0x000002f2, 0x000002f1, 0x00000086, 0x00050085, 0x00000026, 0x000002f3, 0x000002f2, + 0x00000087, 0x00050081, 0x00000026, 0x000002f4, 0x000002f3, 0x00000088, 0x0008000c, 0x00000026, + 0x000002f5, 0x00000001, 0x0000002b, 0x000002f4, 0x0000002e, 0x0000005e, 0x0005008e, 0x0000002a, + 0x000002f6, 0x00000114, 0x000002f5, 0x00050081, 0x0000002a, 0x000002f7, 0x000002ee, 0x000002f6, + 0x00050083, 0x0000002a, 0x000002f8, 0x000002f7, 0x00000118, 0x00050085, 0x0000002a, 0x000002f9, + 0x000002f8, 0x0000011d, 0x00050081, 0x0000002a, 0x000002fa, 0x000002f9, 0x00000122, 0x00040073, + 0x0000002c, 0x000002fb, 0x000002fa, 0x00040063, 0x000002e2, 0x00000129, 0x000002fb, 0x000200f9, + 0x00000125, 0x000200f8, 0x00000125, 0x000100fd, 0x00010038, +}; +static const size_t wnfg_25_spv_size = sizeof(wnfg_25_spv); diff --git a/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_27_spv.h b/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_27_spv.h new file mode 100644 index 000000000..1b1976b69 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_27_spv.h @@ -0,0 +1,280 @@ +#pragma once +#include +#include + +static const uint32_t wnfg_27_spv[] = { + 0x07230203, 0x00010000, 0x000d000b, 0x000001b4, 0x00000000, 0x00020011, 0x00000001, 0x00020011, + 0x00000009, 0x00020011, 0x00000032, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, + 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0006000f, 0x00000005, 0x00000002, 0x6e69616d, + 0x00000000, 0x00000003, 0x00060010, 0x00000002, 0x00000011, 0x00000010, 0x00000010, 0x00000001, + 0x00040047, 0x00000003, 0x0000000b, 0x0000001c, 0x00030047, 0x00000004, 0x00000019, 0x00040047, + 0x00000004, 0x00000021, 0x00000030, 0x00040047, 0x00000004, 0x00000022, 0x00000000, 0x00040047, + 0x00000005, 0x00000021, 0x00000020, 0x00040047, 0x00000005, 0x00000022, 0x00000000, 0x00040047, + 0x00000006, 0x0000000b, 0x00000019, 0x00020013, 0x00000007, 0x00030021, 0x00000008, 0x00000007, + 0x00040015, 0x00000009, 0x00000020, 0x00000001, 0x00040017, 0x0000000a, 0x00000009, 0x00000002, + 0x00040015, 0x0000000b, 0x00000020, 0x00000000, 0x00040017, 0x0000000c, 0x0000000b, 0x00000003, + 0x00040020, 0x0000000d, 0x00000001, 0x0000000c, 0x0004003b, 0x0000000d, 0x00000003, 0x00000001, + 0x00040017, 0x0000000e, 0x0000000b, 0x00000002, 0x00030016, 0x0000000f, 0x00000020, 0x00090019, + 0x00000010, 0x0000000f, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0x00000004, + 0x00040020, 0x00000011, 0x00000000, 0x00000010, 0x0004003b, 0x00000011, 0x00000004, 0x00000000, + 0x00020014, 0x00000012, 0x00040017, 0x00000013, 0x00000012, 0x00000002, 0x00090019, 0x00000014, + 0x0000000f, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x0003001b, + 0x00000015, 0x00000014, 0x00040020, 0x00000016, 0x00000000, 0x00000015, 0x0004003b, 0x00000016, + 0x00000005, 0x00000000, 0x0004002b, 0x00000009, 0x00000017, 0x00000000, 0x0004002b, 0x0000000b, + 0x00000018, 0x00000000, 0x0004002b, 0x0000000b, 0x00000019, 0x00000001, 0x00030016, 0x0000001a, + 0x00000010, 0x00040017, 0x0000001b, 0x0000001a, 0x00000004, 0x00040018, 0x0000001c, 0x0000001b, + 0x00000004, 0x0004002b, 0x0000001a, 0x0000001d, 0x0000b454, 0x0004002b, 0x0000001a, 0x0000001e, + 0x0000b0d8, 0x0004002b, 0x0000001a, 0x0000001f, 0x0000af37, 0x0004002b, 0x0000001a, 0x00000020, + 0x00003506, 0x0007002c, 0x0000001b, 0x00000021, 0x0000001d, 0x0000001e, 0x0000001f, 0x00000020, + 0x0004002b, 0x0000001a, 0x00000022, 0x0000382a, 0x0004002b, 0x0000001a, 0x00000023, 0x0000a1f4, + 0x0004002b, 0x0000001a, 0x00000024, 0x00003004, 0x0004002b, 0x0000001a, 0x00000025, 0x0000b48b, + 0x0007002c, 0x0000001b, 0x00000026, 0x00000022, 0x00000023, 0x00000024, 0x00000025, 0x0004002b, + 0x0000001a, 0x00000027, 0x000037d8, 0x0004002b, 0x0000001a, 0x00000028, 0x00002fcb, 0x0004002b, + 0x0000001a, 0x00000029, 0x0000b03f, 0x0004002b, 0x0000001a, 0x0000002a, 0x0000b661, 0x0007002c, + 0x0000001b, 0x0000002b, 0x00000027, 0x00000028, 0x00000029, 0x0000002a, 0x0004002b, 0x0000001a, + 0x0000002c, 0x00003aaa, 0x0004002b, 0x0000001a, 0x0000002d, 0x0000349c, 0x0004002b, 0x0000001a, + 0x0000002e, 0x0000b81a, 0x0004002b, 0x0000001a, 0x0000002f, 0x0000b5d7, 0x0007002c, 0x0000001b, + 0x00000030, 0x0000002c, 0x0000002d, 0x0000002e, 0x0000002f, 0x0007002c, 0x0000001c, 0x00000031, + 0x00000021, 0x00000026, 0x0000002b, 0x00000030, 0x0004002b, 0x00000009, 0x00000032, 0xffffffff, + 0x0005002c, 0x0000000a, 0x00000033, 0x00000032, 0x00000032, 0x0005002c, 0x0000000a, 0x00000034, + 0x00000017, 0x00000017, 0x00040017, 0x00000035, 0x0000000f, 0x00000004, 0x0004002b, 0x0000000f, + 0x00000036, 0x00000000, 0x0007002c, 0x00000035, 0x00000037, 0x00000036, 0x00000036, 0x00000036, + 0x00000036, 0x0004002b, 0x0000001a, 0x00000038, 0x0000b69c, 0x0004002b, 0x0000001a, 0x00000039, + 0x0000b60c, 0x0004002b, 0x0000001a, 0x0000003a, 0x0000a9ed, 0x0004002b, 0x0000001a, 0x0000003b, + 0x000034a0, 0x0007002c, 0x0000001b, 0x0000003c, 0x00000038, 0x00000039, 0x0000003a, 0x0000003b, + 0x0004002b, 0x0000001a, 0x0000003d, 0x0000369a, 0x0004002b, 0x0000001a, 0x0000003e, 0x0000ac7a, + 0x0004002b, 0x0000001a, 0x0000003f, 0x00002e5d, 0x0004002b, 0x0000001a, 0x00000040, 0x0000b697, + 0x0007002c, 0x0000001b, 0x00000041, 0x0000003d, 0x0000003e, 0x0000003f, 0x00000040, 0x0004002b, + 0x0000001a, 0x00000042, 0x000030ad, 0x0004002b, 0x0000001a, 0x00000043, 0x00009b14, 0x0004002b, + 0x0000001a, 0x00000044, 0x0000b168, 0x0004002b, 0x0000001a, 0x00000045, 0x0000b74d, 0x0007002c, + 0x0000001b, 0x00000046, 0x00000042, 0x00000043, 0x00000044, 0x00000045, 0x0004002b, 0x0000001a, + 0x00000047, 0x00002e8c, 0x0004002b, 0x0000001a, 0x00000048, 0x00002d8c, 0x0004002b, 0x0000001a, + 0x00000049, 0x0000b8ab, 0x0004002b, 0x0000001a, 0x0000004a, 0x0000b694, 0x0007002c, 0x0000001b, + 0x0000004b, 0x00000047, 0x00000048, 0x00000049, 0x0000004a, 0x0007002c, 0x0000001c, 0x0000004c, + 0x0000003c, 0x00000041, 0x00000046, 0x0000004b, 0x0005002c, 0x0000000a, 0x0000004d, 0x00000032, + 0x00000017, 0x0004002b, 0x0000001a, 0x0000004e, 0x0000b197, 0x0004002b, 0x0000001a, 0x0000004f, + 0x0000bbe3, 0x0004002b, 0x0000001a, 0x00000050, 0x000038a7, 0x0004002b, 0x0000001a, 0x00000051, + 0x00003951, 0x0007002c, 0x0000001b, 0x00000052, 0x0000004e, 0x0000004f, 0x00000050, 0x00000051, + 0x0004002b, 0x0000001a, 0x00000053, 0x0000a4ed, 0x0004002b, 0x0000001a, 0x00000054, 0x00003480, + 0x0004002b, 0x0000001a, 0x00000055, 0x0000ba6f, 0x0004002b, 0x0000001a, 0x00000056, 0x0000ba8d, + 0x0007002c, 0x0000001b, 0x00000057, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x0004002b, + 0x0000001a, 0x00000058, 0x0000b550, 0x0004002b, 0x0000001a, 0x00000059, 0x00001d57, 0x0004002b, + 0x0000001a, 0x0000005a, 0x0000b7f6, 0x0004002b, 0x0000001a, 0x0000005b, 0x0000b870, 0x0007002c, + 0x0000001b, 0x0000005c, 0x00000058, 0x00000059, 0x0000005a, 0x0000005b, 0x0004002b, 0x0000001a, + 0x0000005d, 0x0000b4c6, 0x0004002b, 0x0000001a, 0x0000005e, 0x0000375f, 0x0004002b, 0x0000001a, + 0x0000005f, 0x0000bb4c, 0x0004002b, 0x0000001a, 0x00000060, 0x0000ba66, 0x0007002c, 0x0000001b, + 0x00000061, 0x0000005d, 0x0000005e, 0x0000005f, 0x00000060, 0x0007002c, 0x0000001c, 0x00000062, + 0x00000052, 0x00000057, 0x0000005c, 0x00000061, 0x0004002b, 0x00000009, 0x00000063, 0x00000001, + 0x0005002c, 0x0000000a, 0x00000064, 0x00000032, 0x00000063, 0x0004002b, 0x0000001a, 0x00000065, + 0x00003134, 0x0004002b, 0x0000001a, 0x00000066, 0x00002dca, 0x0004002b, 0x0000001a, 0x00000067, + 0x000031c1, 0x0004002b, 0x0000001a, 0x00000068, 0x0000b13d, 0x0007002c, 0x0000001b, 0x00000069, + 0x00000065, 0x00000066, 0x00000067, 0x00000068, 0x0004002b, 0x0000001a, 0x0000006a, 0x000035be, + 0x0004002b, 0x0000001a, 0x0000006b, 0x00002b20, 0x0004002b, 0x0000001a, 0x0000006c, 0x0000aacc, + 0x0004002b, 0x0000001a, 0x0000006d, 0x0000b603, 0x0007002c, 0x0000001b, 0x0000006e, 0x0000006a, + 0x0000006b, 0x0000006c, 0x0000006d, 0x0004002b, 0x0000001a, 0x0000006f, 0x00003311, 0x0004002b, + 0x0000001a, 0x00000070, 0x000036bf, 0x0004002b, 0x0000001a, 0x00000071, 0x0000b0ca, 0x0004002b, + 0x0000001a, 0x00000072, 0x0000ae8e, 0x0007002c, 0x0000001b, 0x00000073, 0x0000006f, 0x00000070, + 0x00000071, 0x00000072, 0x0004002b, 0x0000001a, 0x00000074, 0x00002b9b, 0x0004002b, 0x0000001a, + 0x00000075, 0x00002f95, 0x0004002b, 0x0000001a, 0x00000076, 0x0000bb24, 0x0004002b, 0x0000001a, + 0x00000077, 0x0000b4d9, 0x0007002c, 0x0000001b, 0x00000078, 0x00000074, 0x00000075, 0x00000076, + 0x00000077, 0x0007002c, 0x0000001c, 0x00000079, 0x00000069, 0x0000006e, 0x00000073, 0x00000078, + 0x0005002c, 0x0000000a, 0x0000007a, 0x00000017, 0x00000032, 0x0004002b, 0x0000001a, 0x0000007b, + 0x000020d1, 0x0004002b, 0x0000001a, 0x0000007c, 0x00003223, 0x0004002b, 0x0000001a, 0x0000007d, + 0x0000b48d, 0x0004002b, 0x0000001a, 0x0000007e, 0x0000aa9f, 0x0007002c, 0x0000001b, 0x0000007f, + 0x0000007b, 0x0000007c, 0x0000007d, 0x0000007e, 0x0004002b, 0x0000001a, 0x00000080, 0x00003282, + 0x0004002b, 0x0000001a, 0x00000081, 0x000031c4, 0x0004002b, 0x0000001a, 0x00000082, 0x0000a311, + 0x0004002b, 0x0000001a, 0x00000083, 0x0000b6d0, 0x0007002c, 0x0000001b, 0x00000084, 0x00000080, + 0x00000081, 0x00000082, 0x00000083, 0x0004002b, 0x0000001a, 0x00000085, 0x0000a0ef, 0x0004002b, + 0x0000001a, 0x00000086, 0x00003576, 0x0004002b, 0x0000001a, 0x00000087, 0x0000b487, 0x0004002b, + 0x0000001a, 0x00000088, 0x0000aebc, 0x0007002c, 0x0000001b, 0x00000089, 0x00000085, 0x00000086, + 0x00000087, 0x00000088, 0x0004002b, 0x0000001a, 0x0000008a, 0x0000a8f5, 0x0004002b, 0x0000001a, + 0x0000008b, 0x0000a422, 0x0004002b, 0x0000001a, 0x0000008c, 0x0000b586, 0x0004002b, 0x0000001a, + 0x0000008d, 0x0000b6dc, 0x0007002c, 0x0000001b, 0x0000008e, 0x0000008a, 0x0000008b, 0x0000008c, + 0x0000008d, 0x0007002c, 0x0000001c, 0x0000008f, 0x0000007f, 0x00000084, 0x00000089, 0x0000008e, + 0x0004002b, 0x0000001a, 0x00000090, 0x0000340b, 0x0004002b, 0x0000001a, 0x00000091, 0x0000b928, + 0x0004002b, 0x0000001a, 0x00000092, 0x0000367c, 0x0004002b, 0x0000001a, 0x00000093, 0x0000b35c, + 0x0007002c, 0x0000001b, 0x00000094, 0x00000090, 0x00000091, 0x00000092, 0x00000093, 0x0004002b, + 0x0000001a, 0x00000095, 0x0000b55f, 0x0004002b, 0x0000001a, 0x00000096, 0x00003033, 0x0004002b, + 0x0000001a, 0x00000097, 0x0000b391, 0x0004002b, 0x0000001a, 0x00000098, 0x0000b4ee, 0x0007002c, + 0x0000001b, 0x00000099, 0x00000095, 0x00000096, 0x00000097, 0x00000098, 0x0004002b, 0x0000001a, + 0x0000009a, 0x0000b4fb, 0x0004002b, 0x0000001a, 0x0000009b, 0x00001af0, 0x0004002b, 0x0000001a, + 0x0000009c, 0x0000b356, 0x0004002b, 0x0000001a, 0x0000009d, 0x0000b012, 0x0007002c, 0x0000001b, + 0x0000009e, 0x0000009a, 0x0000009b, 0x0000009c, 0x0000009d, 0x0004002b, 0x0000001a, 0x0000009f, + 0x0000b7d5, 0x0004002b, 0x0000001a, 0x000000a0, 0x00002f4c, 0x0004002b, 0x0000001a, 0x000000a1, + 0x0000b99a, 0x0004002b, 0x0000001a, 0x000000a2, 0x000023e2, 0x0007002c, 0x0000001b, 0x000000a3, + 0x0000009f, 0x000000a0, 0x000000a1, 0x000000a2, 0x0007002c, 0x0000001c, 0x000000a4, 0x00000094, + 0x00000099, 0x0000009e, 0x000000a3, 0x0005002c, 0x0000000a, 0x000000a5, 0x00000017, 0x00000063, + 0x0004002b, 0x0000001a, 0x000000a6, 0x0000350a, 0x0004002b, 0x0000001a, 0x000000a7, 0x00003a4d, + 0x0004002b, 0x0000001a, 0x000000a8, 0x0000bc6d, 0x0004002b, 0x0000001a, 0x000000a9, 0x0000b2a7, + 0x0007002c, 0x0000001b, 0x000000aa, 0x000000a6, 0x000000a7, 0x000000a8, 0x000000a9, 0x0004002b, + 0x0000001a, 0x000000ab, 0x00002ee7, 0x0004002b, 0x0000001a, 0x000000ac, 0x000033a7, 0x0004002b, + 0x0000001a, 0x000000ad, 0x0000b11a, 0x0004002b, 0x0000001a, 0x000000ae, 0x0000b5ef, 0x0007002c, + 0x0000001b, 0x000000af, 0x000000ab, 0x000000ac, 0x000000ad, 0x000000ae, 0x0004002b, 0x0000001a, + 0x000000b0, 0x0000a546, 0x0004002b, 0x0000001a, 0x000000b1, 0x000039b3, 0x0004002b, 0x0000001a, + 0x000000b2, 0x0000b06d, 0x0004002b, 0x0000001a, 0x000000b3, 0x0000b046, 0x0007002c, 0x0000001b, + 0x000000b4, 0x000000b0, 0x000000b1, 0x000000b2, 0x000000b3, 0x0004002b, 0x0000001a, 0x000000b5, + 0x00002c93, 0x0004002b, 0x0000001a, 0x000000b6, 0x0000386c, 0x0004002b, 0x0000001a, 0x000000b7, + 0x0000b849, 0x0004002b, 0x0000001a, 0x000000b8, 0x0000b85e, 0x0007002c, 0x0000001b, 0x000000b9, + 0x000000b5, 0x000000b6, 0x000000b7, 0x000000b8, 0x0007002c, 0x0000001c, 0x000000ba, 0x000000aa, + 0x000000af, 0x000000b4, 0x000000b9, 0x0005002c, 0x0000000a, 0x000000bb, 0x00000063, 0x00000032, + 0x0004002b, 0x0000001a, 0x000000bc, 0x0000b1ec, 0x0004002b, 0x0000001a, 0x000000bd, 0x000026b8, + 0x0004002b, 0x0000001a, 0x000000be, 0x0000b62a, 0x0004002b, 0x0000001a, 0x000000bf, 0x00009d10, + 0x0007002c, 0x0000001b, 0x000000c0, 0x000000bc, 0x000000bd, 0x000000be, 0x000000bf, 0x0004002b, + 0x0000001a, 0x000000c1, 0x00002b4a, 0x0004002b, 0x0000001a, 0x000000c2, 0x00002f30, 0x0004002b, + 0x0000001a, 0x000000c3, 0x00003390, 0x0004002b, 0x0000001a, 0x000000c4, 0x0000b731, 0x0007002c, + 0x0000001b, 0x000000c5, 0x000000c1, 0x000000c2, 0x000000c3, 0x000000c4, 0x0004002b, 0x0000001a, + 0x000000c6, 0x0000a5e6, 0x0004002b, 0x0000001a, 0x000000c7, 0x000038b3, 0x0004002b, 0x0000001a, + 0x000000c8, 0x00003151, 0x0004002b, 0x0000001a, 0x000000c9, 0x0000b1ae, 0x0007002c, 0x0000001b, + 0x000000ca, 0x000000c6, 0x000000c7, 0x000000c8, 0x000000c9, 0x0004002b, 0x0000001a, 0x000000cb, + 0x0000a975, 0x0004002b, 0x0000001a, 0x000000cc, 0x00003049, 0x0004002b, 0x0000001a, 0x000000cd, + 0x0000af1f, 0x0004002b, 0x0000001a, 0x000000ce, 0x0000b518, 0x0007002c, 0x0000001b, 0x000000cf, + 0x000000cb, 0x000000cc, 0x000000cd, 0x000000ce, 0x0007002c, 0x0000001c, 0x000000d0, 0x000000c0, + 0x000000c5, 0x000000ca, 0x000000cf, 0x0005002c, 0x0000000a, 0x000000d1, 0x00000063, 0x00000017, + 0x0004002b, 0x0000001a, 0x000000d2, 0x0000bac1, 0x0004002b, 0x0000001a, 0x000000d3, 0x0000b7d0, + 0x0004002b, 0x0000001a, 0x000000d4, 0x0000b80f, 0x0004002b, 0x0000001a, 0x000000d5, 0x0000383c, + 0x0007002c, 0x0000001b, 0x000000d6, 0x000000d2, 0x000000d3, 0x000000d4, 0x000000d5, 0x0004002b, + 0x0000001a, 0x000000d7, 0x000038b9, 0x0004002b, 0x0000001a, 0x000000d8, 0x0000b7f2, 0x0004002b, + 0x0000001a, 0x000000d9, 0x0000ab65, 0x0007002c, 0x0000001b, 0x000000da, 0x00000083, 0x000000d7, + 0x000000d8, 0x000000d9, 0x0004002b, 0x0000001a, 0x000000db, 0x0000b699, 0x0004002b, 0x0000001a, + 0x000000dc, 0x00003207, 0x0004002b, 0x0000001a, 0x000000dd, 0x0000294d, 0x0004002b, 0x0000001a, + 0x000000de, 0x0000a782, 0x0007002c, 0x0000001b, 0x000000df, 0x000000db, 0x000000dc, 0x000000dd, + 0x000000de, 0x0004002b, 0x0000001a, 0x000000e0, 0x0000ba05, 0x0004002b, 0x0000001a, 0x000000e1, + 0x0000388c, 0x0004002b, 0x0000001a, 0x000000e2, 0x0000b745, 0x0004002b, 0x0000001a, 0x000000e3, + 0x0000a909, 0x0007002c, 0x0000001b, 0x000000e4, 0x000000e0, 0x000000e1, 0x000000e2, 0x000000e3, + 0x0007002c, 0x0000001c, 0x000000e5, 0x000000d6, 0x000000da, 0x000000df, 0x000000e4, 0x0005002c, + 0x0000000a, 0x000000e6, 0x00000063, 0x00000063, 0x0004002b, 0x0000001a, 0x000000e7, 0x0000b842, + 0x0004002b, 0x0000001a, 0x000000e8, 0x00003f71, 0x0004002b, 0x0000001a, 0x000000e9, 0x0000c1eb, + 0x0004002b, 0x0000001a, 0x000000ea, 0x0000c1a0, 0x0007002c, 0x0000001b, 0x000000eb, 0x000000e7, + 0x000000e8, 0x000000e9, 0x000000ea, 0x0004002b, 0x0000001a, 0x000000ec, 0x00003701, 0x0004002b, + 0x0000001a, 0x000000ed, 0x0000387b, 0x0004002b, 0x0000001a, 0x000000ee, 0x0000302e, 0x0007002c, + 0x0000001b, 0x000000ef, 0x0000005e, 0x000000ec, 0x000000ed, 0x000000ee, 0x0004002b, 0x0000001a, + 0x000000f0, 0x00003719, 0x0004002b, 0x0000001a, 0x000000f1, 0x0000b09c, 0x0004002b, 0x0000001a, + 0x000000f2, 0x0000b4cc, 0x0004002b, 0x0000001a, 0x000000f3, 0x0000396a, 0x0007002c, 0x0000001b, + 0x000000f4, 0x000000f0, 0x000000f1, 0x000000f2, 0x000000f3, 0x0004002b, 0x0000000b, 0x000000f5, + 0x00000010, 0x0006002c, 0x0000000c, 0x00000006, 0x000000f5, 0x000000f5, 0x00000019, 0x00050036, + 0x00000007, 0x00000002, 0x00000000, 0x00000008, 0x000200f8, 0x000000f6, 0x000300f7, 0x000000f7, + 0x00000000, 0x000300fb, 0x00000018, 0x000000f8, 0x000200f8, 0x000000f8, 0x0004003d, 0x0000000c, + 0x000000f9, 0x00000003, 0x0007004f, 0x0000000e, 0x000000fa, 0x000000f9, 0x000000f9, 0x00000000, + 0x00000001, 0x0004007c, 0x0000000a, 0x000000fb, 0x000000fa, 0x0004003d, 0x00000010, 0x000000fc, + 0x00000004, 0x00040068, 0x0000000a, 0x000000fd, 0x000000fc, 0x000500af, 0x00000013, 0x000000fe, + 0x000000fb, 0x000000fd, 0x0004009a, 0x00000012, 0x000000ff, 0x000000fe, 0x000300f7, 0x00000100, + 0x00000000, 0x000400fa, 0x000000ff, 0x00000101, 0x00000100, 0x000200f8, 0x00000101, 0x000200f9, + 0x000000f7, 0x000200f8, 0x00000100, 0x0004003d, 0x00000010, 0x00000102, 0x00000004, 0x00050080, + 0x0000000a, 0x00000103, 0x000000fb, 0x00000033, 0x000500af, 0x00000013, 0x00000104, 0x00000103, + 0x00000034, 0x0004009b, 0x00000012, 0x00000105, 0x00000104, 0x000300f7, 0x00000106, 0x00000000, + 0x000400fa, 0x00000105, 0x00000107, 0x00000106, 0x000200f8, 0x00000107, 0x0004003d, 0x00000015, + 0x00000108, 0x00000005, 0x00040064, 0x00000014, 0x00000109, 0x00000108, 0x00050067, 0x0000000a, + 0x0000010a, 0x00000109, 0x00000017, 0x000500b1, 0x00000013, 0x0000010b, 0x00000103, 0x0000010a, + 0x0004009b, 0x00000012, 0x0000010c, 0x0000010b, 0x000200f9, 0x00000106, 0x000200f8, 0x00000106, + 0x000700f5, 0x00000012, 0x0000010d, 0x00000105, 0x00000100, 0x0000010c, 0x00000107, 0x000300f7, + 0x0000010e, 0x00000000, 0x000400fa, 0x0000010d, 0x0000010f, 0x00000110, 0x000200f8, 0x0000010f, + 0x0004003d, 0x00000015, 0x00000111, 0x00000005, 0x00040064, 0x00000014, 0x00000112, 0x00000111, + 0x0007005f, 0x00000035, 0x00000113, 0x00000112, 0x00000103, 0x00000002, 0x00000017, 0x000200f9, + 0x0000010e, 0x000200f8, 0x00000110, 0x000200f9, 0x0000010e, 0x000200f8, 0x0000010e, 0x000700f5, + 0x00000035, 0x00000114, 0x00000113, 0x0000010f, 0x00000037, 0x00000110, 0x00040073, 0x0000001b, + 0x00000115, 0x00000114, 0x00050091, 0x0000001b, 0x00000116, 0x00000031, 0x00000115, 0x00050080, + 0x0000000a, 0x00000117, 0x000000fb, 0x0000004d, 0x000500af, 0x00000013, 0x00000118, 0x00000117, + 0x00000034, 0x0004009b, 0x00000012, 0x00000119, 0x00000118, 0x000300f7, 0x0000011a, 0x00000000, + 0x000400fa, 0x00000119, 0x0000011b, 0x0000011a, 0x000200f8, 0x0000011b, 0x0004003d, 0x00000015, + 0x0000011c, 0x00000005, 0x00040064, 0x00000014, 0x0000011d, 0x0000011c, 0x00050067, 0x0000000a, + 0x0000011e, 0x0000011d, 0x00000017, 0x000500b1, 0x00000013, 0x0000011f, 0x00000117, 0x0000011e, + 0x0004009b, 0x00000012, 0x00000120, 0x0000011f, 0x000200f9, 0x0000011a, 0x000200f8, 0x0000011a, + 0x000700f5, 0x00000012, 0x00000121, 0x00000119, 0x0000010e, 0x00000120, 0x0000011b, 0x000300f7, + 0x00000122, 0x00000000, 0x000400fa, 0x00000121, 0x00000123, 0x00000124, 0x000200f8, 0x00000123, + 0x0004003d, 0x00000015, 0x00000125, 0x00000005, 0x00040064, 0x00000014, 0x00000126, 0x00000125, + 0x0007005f, 0x00000035, 0x00000127, 0x00000126, 0x00000117, 0x00000002, 0x00000017, 0x000200f9, + 0x00000122, 0x000200f8, 0x00000124, 0x000200f9, 0x00000122, 0x000200f8, 0x00000122, 0x000700f5, + 0x00000035, 0x00000128, 0x00000127, 0x00000123, 0x00000037, 0x00000124, 0x00040073, 0x0000001b, + 0x00000129, 0x00000128, 0x00050091, 0x0000001b, 0x0000012a, 0x0000004c, 0x00000129, 0x00050081, + 0x0000001b, 0x0000012b, 0x00000116, 0x0000012a, 0x00050080, 0x0000000a, 0x0000012c, 0x000000fb, + 0x00000064, 0x000500af, 0x00000013, 0x0000012d, 0x0000012c, 0x00000034, 0x0004009b, 0x00000012, + 0x0000012e, 0x0000012d, 0x000300f7, 0x0000012f, 0x00000000, 0x000400fa, 0x0000012e, 0x00000130, + 0x0000012f, 0x000200f8, 0x00000130, 0x0004003d, 0x00000015, 0x00000131, 0x00000005, 0x00040064, + 0x00000014, 0x00000132, 0x00000131, 0x00050067, 0x0000000a, 0x00000133, 0x00000132, 0x00000017, + 0x000500b1, 0x00000013, 0x00000134, 0x0000012c, 0x00000133, 0x0004009b, 0x00000012, 0x00000135, + 0x00000134, 0x000200f9, 0x0000012f, 0x000200f8, 0x0000012f, 0x000700f5, 0x00000012, 0x00000136, + 0x0000012e, 0x00000122, 0x00000135, 0x00000130, 0x000300f7, 0x00000137, 0x00000000, 0x000400fa, + 0x00000136, 0x00000138, 0x00000139, 0x000200f8, 0x00000138, 0x0004003d, 0x00000015, 0x0000013a, + 0x00000005, 0x00040064, 0x00000014, 0x0000013b, 0x0000013a, 0x0007005f, 0x00000035, 0x0000013c, + 0x0000013b, 0x0000012c, 0x00000002, 0x00000017, 0x000200f9, 0x00000137, 0x000200f8, 0x00000139, + 0x000200f9, 0x00000137, 0x000200f8, 0x00000137, 0x000700f5, 0x00000035, 0x0000013d, 0x0000013c, + 0x00000138, 0x00000037, 0x00000139, 0x00040073, 0x0000001b, 0x0000013e, 0x0000013d, 0x00050091, + 0x0000001b, 0x0000013f, 0x00000062, 0x0000013e, 0x00050081, 0x0000001b, 0x00000140, 0x0000012b, + 0x0000013f, 0x00050080, 0x0000000a, 0x00000141, 0x000000fb, 0x0000007a, 0x000500af, 0x00000013, + 0x00000142, 0x00000141, 0x00000034, 0x0004009b, 0x00000012, 0x00000143, 0x00000142, 0x000300f7, + 0x00000144, 0x00000000, 0x000400fa, 0x00000143, 0x00000145, 0x00000144, 0x000200f8, 0x00000145, + 0x0004003d, 0x00000015, 0x00000146, 0x00000005, 0x00040064, 0x00000014, 0x00000147, 0x00000146, + 0x00050067, 0x0000000a, 0x00000148, 0x00000147, 0x00000017, 0x000500b1, 0x00000013, 0x00000149, + 0x00000141, 0x00000148, 0x0004009b, 0x00000012, 0x0000014a, 0x00000149, 0x000200f9, 0x00000144, + 0x000200f8, 0x00000144, 0x000700f5, 0x00000012, 0x0000014b, 0x00000143, 0x00000137, 0x0000014a, + 0x00000145, 0x000300f7, 0x0000014c, 0x00000000, 0x000400fa, 0x0000014b, 0x0000014d, 0x0000014e, + 0x000200f8, 0x0000014d, 0x0004003d, 0x00000015, 0x0000014f, 0x00000005, 0x00040064, 0x00000014, + 0x00000150, 0x0000014f, 0x0007005f, 0x00000035, 0x00000151, 0x00000150, 0x00000141, 0x00000002, + 0x00000017, 0x000200f9, 0x0000014c, 0x000200f8, 0x0000014e, 0x000200f9, 0x0000014c, 0x000200f8, + 0x0000014c, 0x000700f5, 0x00000035, 0x00000152, 0x00000151, 0x0000014d, 0x00000037, 0x0000014e, + 0x00040073, 0x0000001b, 0x00000153, 0x00000152, 0x00050091, 0x0000001b, 0x00000154, 0x00000079, + 0x00000153, 0x00050081, 0x0000001b, 0x00000155, 0x00000140, 0x00000154, 0x0004003d, 0x00000015, + 0x00000156, 0x00000005, 0x00040064, 0x00000014, 0x00000157, 0x00000156, 0x0007005f, 0x00000035, + 0x00000158, 0x00000157, 0x000000fb, 0x00000002, 0x00000017, 0x00040073, 0x0000001b, 0x00000159, + 0x00000158, 0x00050091, 0x0000001b, 0x0000015a, 0x0000008f, 0x00000159, 0x00050081, 0x0000001b, + 0x0000015b, 0x00000155, 0x0000015a, 0x00050080, 0x0000000a, 0x0000015c, 0x000000fb, 0x000000a5, + 0x000500af, 0x00000013, 0x0000015d, 0x0000015c, 0x00000034, 0x0004009b, 0x00000012, 0x0000015e, + 0x0000015d, 0x000300f7, 0x0000015f, 0x00000000, 0x000400fa, 0x0000015e, 0x00000160, 0x0000015f, + 0x000200f8, 0x00000160, 0x0004003d, 0x00000015, 0x00000161, 0x00000005, 0x00040064, 0x00000014, + 0x00000162, 0x00000161, 0x00050067, 0x0000000a, 0x00000163, 0x00000162, 0x00000017, 0x000500b1, + 0x00000013, 0x00000164, 0x0000015c, 0x00000163, 0x0004009b, 0x00000012, 0x00000165, 0x00000164, + 0x000200f9, 0x0000015f, 0x000200f8, 0x0000015f, 0x000700f5, 0x00000012, 0x00000166, 0x0000015e, + 0x0000014c, 0x00000165, 0x00000160, 0x000300f7, 0x00000167, 0x00000000, 0x000400fa, 0x00000166, + 0x00000168, 0x00000169, 0x000200f8, 0x00000168, 0x0004003d, 0x00000015, 0x0000016a, 0x00000005, + 0x00040064, 0x00000014, 0x0000016b, 0x0000016a, 0x0007005f, 0x00000035, 0x0000016c, 0x0000016b, + 0x0000015c, 0x00000002, 0x00000017, 0x000200f9, 0x00000167, 0x000200f8, 0x00000169, 0x000200f9, + 0x00000167, 0x000200f8, 0x00000167, 0x000700f5, 0x00000035, 0x0000016d, 0x0000016c, 0x00000168, + 0x00000037, 0x00000169, 0x00040073, 0x0000001b, 0x0000016e, 0x0000016d, 0x00050091, 0x0000001b, + 0x0000016f, 0x000000a4, 0x0000016e, 0x00050081, 0x0000001b, 0x00000170, 0x0000015b, 0x0000016f, + 0x00050080, 0x0000000a, 0x00000171, 0x000000fb, 0x000000bb, 0x000500af, 0x00000013, 0x00000172, + 0x00000171, 0x00000034, 0x0004009b, 0x00000012, 0x00000173, 0x00000172, 0x000300f7, 0x00000174, + 0x00000000, 0x000400fa, 0x00000173, 0x00000175, 0x00000174, 0x000200f8, 0x00000175, 0x0004003d, + 0x00000015, 0x00000176, 0x00000005, 0x00040064, 0x00000014, 0x00000177, 0x00000176, 0x00050067, + 0x0000000a, 0x00000178, 0x00000177, 0x00000017, 0x000500b1, 0x00000013, 0x00000179, 0x00000171, + 0x00000178, 0x0004009b, 0x00000012, 0x0000017a, 0x00000179, 0x000200f9, 0x00000174, 0x000200f8, + 0x00000174, 0x000700f5, 0x00000012, 0x0000017b, 0x00000173, 0x00000167, 0x0000017a, 0x00000175, + 0x000300f7, 0x0000017c, 0x00000000, 0x000400fa, 0x0000017b, 0x0000017d, 0x0000017e, 0x000200f8, + 0x0000017d, 0x0004003d, 0x00000015, 0x0000017f, 0x00000005, 0x00040064, 0x00000014, 0x00000180, + 0x0000017f, 0x0007005f, 0x00000035, 0x00000181, 0x00000180, 0x00000171, 0x00000002, 0x00000017, + 0x000200f9, 0x0000017c, 0x000200f8, 0x0000017e, 0x000200f9, 0x0000017c, 0x000200f8, 0x0000017c, + 0x000700f5, 0x00000035, 0x00000182, 0x00000181, 0x0000017d, 0x00000037, 0x0000017e, 0x00040073, + 0x0000001b, 0x00000183, 0x00000182, 0x00050091, 0x0000001b, 0x00000184, 0x000000ba, 0x00000183, + 0x00050081, 0x0000001b, 0x00000185, 0x00000170, 0x00000184, 0x00050080, 0x0000000a, 0x00000186, + 0x000000fb, 0x000000d1, 0x000500af, 0x00000013, 0x00000187, 0x00000186, 0x00000034, 0x0004009b, + 0x00000012, 0x00000188, 0x00000187, 0x000300f7, 0x00000189, 0x00000000, 0x000400fa, 0x00000188, + 0x0000018a, 0x00000189, 0x000200f8, 0x0000018a, 0x0004003d, 0x00000015, 0x0000018b, 0x00000005, + 0x00040064, 0x00000014, 0x0000018c, 0x0000018b, 0x00050067, 0x0000000a, 0x0000018d, 0x0000018c, + 0x00000017, 0x000500b1, 0x00000013, 0x0000018e, 0x00000186, 0x0000018d, 0x0004009b, 0x00000012, + 0x0000018f, 0x0000018e, 0x000200f9, 0x00000189, 0x000200f8, 0x00000189, 0x000700f5, 0x00000012, + 0x00000190, 0x00000188, 0x0000017c, 0x0000018f, 0x0000018a, 0x000300f7, 0x00000191, 0x00000000, + 0x000400fa, 0x00000190, 0x00000192, 0x00000193, 0x000200f8, 0x00000192, 0x0004003d, 0x00000015, + 0x00000194, 0x00000005, 0x00040064, 0x00000014, 0x00000195, 0x00000194, 0x0007005f, 0x00000035, + 0x00000196, 0x00000195, 0x00000186, 0x00000002, 0x00000017, 0x000200f9, 0x00000191, 0x000200f8, + 0x00000193, 0x000200f9, 0x00000191, 0x000200f8, 0x00000191, 0x000700f5, 0x00000035, 0x00000197, + 0x00000196, 0x00000192, 0x00000037, 0x00000193, 0x00040073, 0x0000001b, 0x00000198, 0x00000197, + 0x00050091, 0x0000001b, 0x00000199, 0x000000d0, 0x00000198, 0x00050081, 0x0000001b, 0x0000019a, + 0x00000185, 0x00000199, 0x00050080, 0x0000000a, 0x0000019b, 0x000000fb, 0x000000e6, 0x000500af, + 0x00000013, 0x0000019c, 0x0000019b, 0x00000034, 0x0004009b, 0x00000012, 0x0000019d, 0x0000019c, + 0x000300f7, 0x0000019e, 0x00000000, 0x000400fa, 0x0000019d, 0x0000019f, 0x0000019e, 0x000200f8, + 0x0000019f, 0x0004003d, 0x00000015, 0x000001a0, 0x00000005, 0x00040064, 0x00000014, 0x000001a1, + 0x000001a0, 0x00050067, 0x0000000a, 0x000001a2, 0x000001a1, 0x00000017, 0x000500b1, 0x00000013, + 0x000001a3, 0x0000019b, 0x000001a2, 0x0004009b, 0x00000012, 0x000001a4, 0x000001a3, 0x000200f9, + 0x0000019e, 0x000200f8, 0x0000019e, 0x000700f5, 0x00000012, 0x000001a5, 0x0000019d, 0x00000191, + 0x000001a4, 0x0000019f, 0x000300f7, 0x000001a6, 0x00000000, 0x000400fa, 0x000001a5, 0x000001a7, + 0x000001a8, 0x000200f8, 0x000001a7, 0x0004003d, 0x00000015, 0x000001a9, 0x00000005, 0x00040064, + 0x00000014, 0x000001aa, 0x000001a9, 0x0007005f, 0x00000035, 0x000001ab, 0x000001aa, 0x0000019b, + 0x00000002, 0x00000017, 0x000200f9, 0x000001a6, 0x000200f8, 0x000001a8, 0x000200f9, 0x000001a6, + 0x000200f8, 0x000001a6, 0x000700f5, 0x00000035, 0x000001ac, 0x000001ab, 0x000001a7, 0x00000037, + 0x000001a8, 0x00040073, 0x0000001b, 0x000001ad, 0x000001ac, 0x00050091, 0x0000001b, 0x000001ae, + 0x000000e5, 0x000001ad, 0x00050081, 0x0000001b, 0x000001af, 0x0000019a, 0x000001ae, 0x00050083, + 0x0000001b, 0x000001b0, 0x000001af, 0x000000eb, 0x00050085, 0x0000001b, 0x000001b1, 0x000001b0, + 0x000000ef, 0x00050081, 0x0000001b, 0x000001b2, 0x000001b1, 0x000000f4, 0x00040073, 0x00000035, + 0x000001b3, 0x000001b2, 0x00040063, 0x00000102, 0x000000fb, 0x000001b3, 0x000200f9, 0x000000f7, + 0x000200f8, 0x000000f7, 0x000100fd, 0x00010038, +}; +static const size_t wnfg_27_spv_size = sizeof(wnfg_27_spv); diff --git a/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_28_spv.h b/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_28_spv.h new file mode 100644 index 000000000..c2b1c281a --- /dev/null +++ b/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_28_spv.h @@ -0,0 +1,281 @@ +#pragma once +#include +#include + +static const uint32_t wnfg_28_spv[] = { + 0x07230203, 0x00010000, 0x000d000b, 0x000001b6, 0x00000000, 0x00020011, 0x00000001, 0x00020011, + 0x00000009, 0x00020011, 0x00000032, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, + 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0006000f, 0x00000005, 0x00000002, 0x6e69616d, + 0x00000000, 0x00000003, 0x00060010, 0x00000002, 0x00000011, 0x00000010, 0x00000010, 0x00000001, + 0x00040047, 0x00000003, 0x0000000b, 0x0000001c, 0x00030047, 0x00000004, 0x00000019, 0x00040047, + 0x00000004, 0x00000021, 0x00000030, 0x00040047, 0x00000004, 0x00000022, 0x00000000, 0x00040047, + 0x00000005, 0x00000021, 0x00000020, 0x00040047, 0x00000005, 0x00000022, 0x00000000, 0x00040047, + 0x00000006, 0x0000000b, 0x00000019, 0x00020013, 0x00000007, 0x00030021, 0x00000008, 0x00000007, + 0x00040015, 0x00000009, 0x00000020, 0x00000001, 0x00040017, 0x0000000a, 0x00000009, 0x00000002, + 0x00040015, 0x0000000b, 0x00000020, 0x00000000, 0x00040017, 0x0000000c, 0x0000000b, 0x00000003, + 0x00040020, 0x0000000d, 0x00000001, 0x0000000c, 0x0004003b, 0x0000000d, 0x00000003, 0x00000001, + 0x00040017, 0x0000000e, 0x0000000b, 0x00000002, 0x00030016, 0x0000000f, 0x00000020, 0x00090019, + 0x00000010, 0x0000000f, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0x00000004, + 0x00040020, 0x00000011, 0x00000000, 0x00000010, 0x0004003b, 0x00000011, 0x00000004, 0x00000000, + 0x00020014, 0x00000012, 0x00040017, 0x00000013, 0x00000012, 0x00000002, 0x00090019, 0x00000014, + 0x0000000f, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x0003001b, + 0x00000015, 0x00000014, 0x00040020, 0x00000016, 0x00000000, 0x00000015, 0x0004003b, 0x00000016, + 0x00000005, 0x00000000, 0x0004002b, 0x00000009, 0x00000017, 0x00000000, 0x0004002b, 0x0000000b, + 0x00000018, 0x00000000, 0x0004002b, 0x0000000b, 0x00000019, 0x00000001, 0x00030016, 0x0000001a, + 0x00000010, 0x00040017, 0x0000001b, 0x0000001a, 0x00000004, 0x00040018, 0x0000001c, 0x0000001b, + 0x00000004, 0x0004002b, 0x0000001a, 0x0000001d, 0x00003a61, 0x0004002b, 0x0000001a, 0x0000001e, + 0x0000b6ca, 0x0004002b, 0x0000001a, 0x0000001f, 0x0000bb4d, 0x0004002b, 0x0000001a, 0x00000020, + 0x0000b97c, 0x0007002c, 0x0000001b, 0x00000021, 0x0000001d, 0x0000001e, 0x0000001f, 0x00000020, + 0x0004002b, 0x0000001a, 0x00000022, 0x00001e9c, 0x0004002b, 0x0000001a, 0x00000023, 0x0000ae54, + 0x0004002b, 0x0000001a, 0x00000024, 0x0000af8f, 0x0004002b, 0x0000001a, 0x00000025, 0x0000b4bd, + 0x0007002c, 0x0000001b, 0x00000026, 0x00000022, 0x00000023, 0x00000024, 0x00000025, 0x0004002b, + 0x0000001a, 0x00000027, 0x00002b97, 0x0004002b, 0x0000001a, 0x00000028, 0x0000b054, 0x0004002b, + 0x0000001a, 0x00000029, 0x0000ae0c, 0x0004002b, 0x0000001a, 0x0000002a, 0x00002c19, 0x0007002c, + 0x0000001b, 0x0000002b, 0x00000027, 0x00000028, 0x00000029, 0x0000002a, 0x0004002b, 0x0000001a, + 0x0000002c, 0x0000ae9d, 0x0004002b, 0x0000001a, 0x0000002d, 0x0000ba75, 0x0004002b, 0x0000001a, + 0x0000002e, 0x00003451, 0x0004002b, 0x0000001a, 0x0000002f, 0x00003856, 0x0007002c, 0x0000001b, + 0x00000030, 0x0000002c, 0x0000002d, 0x0000002e, 0x0000002f, 0x0007002c, 0x0000001c, 0x00000031, + 0x00000021, 0x00000026, 0x0000002b, 0x00000030, 0x0004002b, 0x00000009, 0x00000032, 0xffffffff, + 0x0005002c, 0x0000000a, 0x00000033, 0x00000032, 0x00000032, 0x0005002c, 0x0000000a, 0x00000034, + 0x00000017, 0x00000017, 0x00040017, 0x00000035, 0x0000000f, 0x00000004, 0x0004002b, 0x0000000f, + 0x00000036, 0x00000000, 0x0007002c, 0x00000035, 0x00000037, 0x00000036, 0x00000036, 0x00000036, + 0x00000036, 0x0004002b, 0x0000001a, 0x00000038, 0x00002e54, 0x0004002b, 0x0000001a, 0x00000039, + 0x0000aef1, 0x0004002b, 0x0000001a, 0x0000003a, 0x0000ae4e, 0x0004002b, 0x0000001a, 0x0000003b, + 0x00002f16, 0x0007002c, 0x0000001b, 0x0000003c, 0x00000038, 0x00000039, 0x0000003a, 0x0000003b, + 0x0004002b, 0x0000001a, 0x0000003d, 0x000033de, 0x0004002b, 0x0000001a, 0x0000003e, 0x0000aff2, + 0x0004002b, 0x0000001a, 0x0000003f, 0x0000b4b6, 0x0004002b, 0x0000001a, 0x00000040, 0x0000b85e, + 0x0007002c, 0x0000001b, 0x00000041, 0x0000003d, 0x0000003e, 0x0000003f, 0x00000040, 0x0004002b, + 0x0000001a, 0x00000042, 0x0000b1fd, 0x0004002b, 0x0000001a, 0x00000043, 0x0000335e, 0x0004002b, + 0x0000001a, 0x00000044, 0x000033c1, 0x0004002b, 0x0000001a, 0x00000045, 0x000034c2, 0x0007002c, + 0x0000001b, 0x00000046, 0x00000042, 0x00000043, 0x00000044, 0x00000045, 0x0004002b, 0x0000001a, + 0x00000047, 0x0000b04b, 0x0004002b, 0x0000001a, 0x00000048, 0x00003446, 0x0004002b, 0x0000001a, + 0x00000049, 0x000031e1, 0x0004002b, 0x0000001a, 0x0000004a, 0x0000b5de, 0x0007002c, 0x0000001b, + 0x0000004b, 0x00000047, 0x00000048, 0x00000049, 0x0000004a, 0x0007002c, 0x0000001c, 0x0000004c, + 0x0000003c, 0x00000041, 0x00000046, 0x0000004b, 0x0005002c, 0x0000000a, 0x0000004d, 0x00000032, + 0x00000017, 0x0004002b, 0x0000001a, 0x0000004e, 0x00003073, 0x0004002b, 0x0000001a, 0x0000004f, + 0x0000b449, 0x0004002b, 0x0000001a, 0x00000050, 0x0000ac19, 0x0004002b, 0x0000001a, 0x00000051, + 0x0000310a, 0x0007002c, 0x0000001b, 0x00000052, 0x0000004e, 0x0000004f, 0x00000050, 0x00000051, + 0x0004002b, 0x0000001a, 0x00000053, 0x00003ac9, 0x0004002b, 0x0000001a, 0x00000054, 0x0000ba50, + 0x0004002b, 0x0000001a, 0x00000055, 0x0000ba48, 0x0004002b, 0x0000001a, 0x00000056, 0x0000ba5d, + 0x0007002c, 0x0000001b, 0x00000057, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x0004002b, + 0x0000001a, 0x00000058, 0x0000b5ac, 0x0004002b, 0x0000001a, 0x00000059, 0x00003227, 0x0004002b, + 0x0000001a, 0x0000005a, 0x000034d0, 0x0004002b, 0x0000001a, 0x0000005b, 0x0000361a, 0x0007002c, + 0x0000001b, 0x0000005c, 0x00000058, 0x00000059, 0x0000005a, 0x0000005b, 0x0004002b, 0x0000001a, + 0x0000005d, 0x0000b945, 0x0004002b, 0x0000001a, 0x0000005e, 0x0000b599, 0x0004002b, 0x0000001a, + 0x0000005f, 0x00003a5f, 0x0004002b, 0x0000001a, 0x00000060, 0x00003b0a, 0x0007002c, 0x0000001b, + 0x00000061, 0x0000005d, 0x0000005e, 0x0000005f, 0x00000060, 0x0007002c, 0x0000001c, 0x00000062, + 0x00000052, 0x00000057, 0x0000005c, 0x00000061, 0x0004002b, 0x00000009, 0x00000063, 0x00000001, + 0x0005002c, 0x0000000a, 0x00000064, 0x00000032, 0x00000063, 0x0004002b, 0x0000001a, 0x00000065, + 0x000030fd, 0x0004002b, 0x0000001a, 0x00000066, 0x00003076, 0x0004002b, 0x0000001a, 0x00000067, + 0x0000b441, 0x0004002b, 0x0000001a, 0x00000068, 0x00003456, 0x0007002c, 0x0000001b, 0x00000069, + 0x00000065, 0x00000066, 0x00000067, 0x00000068, 0x0004002b, 0x0000001a, 0x0000006a, 0x00002935, + 0x0004002b, 0x0000001a, 0x0000006b, 0x00002b05, 0x0004002b, 0x0000001a, 0x0000006c, 0x0000b239, + 0x0004002b, 0x0000001a, 0x0000006d, 0x0000ac31, 0x0007002c, 0x0000001b, 0x0000006e, 0x0000006a, + 0x0000006b, 0x0000006c, 0x0000006d, 0x0004002b, 0x0000001a, 0x0000006f, 0x0000aa9f, 0x0004002b, + 0x0000001a, 0x00000070, 0x00002502, 0x0004002b, 0x0000001a, 0x00000071, 0x00003463, 0x0004002b, + 0x0000001a, 0x00000072, 0x00002c2c, 0x0007002c, 0x0000001b, 0x00000073, 0x0000006f, 0x00000070, + 0x00000071, 0x00000072, 0x0004002b, 0x0000001a, 0x00000074, 0x0000b318, 0x0004002b, 0x0000001a, + 0x00000075, 0x000035ed, 0x0004002b, 0x0000001a, 0x00000076, 0x0000352b, 0x0004002b, 0x0000001a, + 0x00000077, 0x000025bb, 0x0007002c, 0x0000001b, 0x00000078, 0x00000074, 0x00000075, 0x00000076, + 0x00000077, 0x0007002c, 0x0000001c, 0x00000079, 0x00000069, 0x0000006e, 0x00000073, 0x00000078, + 0x0005002c, 0x0000000a, 0x0000007a, 0x00000017, 0x00000032, 0x0004002b, 0x0000001a, 0x0000007b, + 0x0000ac6b, 0x0004002b, 0x0000001a, 0x0000007c, 0x000031cb, 0x0004002b, 0x0000001a, 0x0000007d, + 0x00002edb, 0x0004002b, 0x0000001a, 0x0000007e, 0x0000b22f, 0x0007002c, 0x0000001b, 0x0000007f, + 0x0000007b, 0x0000007c, 0x0000007d, 0x0000007e, 0x0004002b, 0x0000001a, 0x00000080, 0x0000a6af, + 0x0004002b, 0x0000001a, 0x00000081, 0x00003695, 0x0004002b, 0x0000001a, 0x00000082, 0x00009735, + 0x0004002b, 0x0000001a, 0x00000083, 0x0000b56b, 0x0007002c, 0x0000001b, 0x00000084, 0x00000080, + 0x00000081, 0x00000082, 0x00000083, 0x0004002b, 0x0000001a, 0x00000085, 0x0000a905, 0x0004002b, + 0x0000001a, 0x00000086, 0x0000b122, 0x0004002b, 0x0000001a, 0x00000087, 0x00003198, 0x0004002b, + 0x0000001a, 0x00000088, 0x0000af9a, 0x0007002c, 0x0000001b, 0x00000089, 0x00000085, 0x00000086, + 0x00000087, 0x00000088, 0x0004002b, 0x0000001a, 0x0000008a, 0x0000aeaa, 0x0004002b, 0x0000001a, + 0x0000008b, 0x00003d3d, 0x0004002b, 0x0000001a, 0x0000008c, 0x0000ac8b, 0x0004002b, 0x0000001a, + 0x0000008d, 0x0000b8dc, 0x0007002c, 0x0000001b, 0x0000008e, 0x0000008a, 0x0000008b, 0x0000008c, + 0x0000008d, 0x0007002c, 0x0000001c, 0x0000008f, 0x0000007f, 0x00000084, 0x00000089, 0x0000008e, + 0x0004002b, 0x0000001a, 0x00000090, 0x0000b16e, 0x0004002b, 0x0000001a, 0x00000091, 0x00003560, + 0x0004002b, 0x0000001a, 0x00000092, 0x00003338, 0x0004002b, 0x0000001a, 0x00000093, 0x000030a4, + 0x0007002c, 0x0000001b, 0x00000094, 0x00000090, 0x00000091, 0x00000092, 0x00000093, 0x0004002b, + 0x0000001a, 0x00000095, 0x00003495, 0x0004002b, 0x0000001a, 0x00000096, 0x0000ad27, 0x0004002b, + 0x0000001a, 0x00000097, 0x0000b3a1, 0x0004002b, 0x0000001a, 0x00000098, 0x0000b6f3, 0x0007002c, + 0x0000001b, 0x00000099, 0x00000095, 0x00000096, 0x00000097, 0x00000098, 0x0004002b, 0x0000001a, + 0x0000009a, 0x0000b16c, 0x0004002b, 0x0000001a, 0x0000009b, 0x0000a527, 0x0004002b, 0x0000001a, + 0x0000009c, 0x0000350d, 0x0004002b, 0x0000001a, 0x0000009d, 0x0000ae32, 0x0007002c, 0x0000001b, + 0x0000009e, 0x0000009a, 0x0000009b, 0x0000009c, 0x0000009d, 0x0004002b, 0x0000001a, 0x0000009f, + 0x0000af1b, 0x0004002b, 0x0000001a, 0x000000a0, 0x000031cc, 0x0004002b, 0x0000001a, 0x000000a1, + 0x00002fce, 0x0004002b, 0x0000001a, 0x000000a2, 0x0000b346, 0x0007002c, 0x0000001b, 0x000000a3, + 0x0000009f, 0x000000a0, 0x000000a1, 0x000000a2, 0x0007002c, 0x0000001c, 0x000000a4, 0x00000094, + 0x00000099, 0x0000009e, 0x000000a3, 0x0005002c, 0x0000000a, 0x000000a5, 0x00000017, 0x00000063, + 0x0004002b, 0x0000001a, 0x000000a6, 0x000031a0, 0x0004002b, 0x0000001a, 0x000000a7, 0x0000b583, + 0x0004002b, 0x0000001a, 0x000000a8, 0x0000a957, 0x0004002b, 0x0000001a, 0x000000a9, 0x0000b10c, + 0x0007002c, 0x0000001b, 0x000000aa, 0x000000a6, 0x000000a7, 0x000000a8, 0x000000a9, 0x0004002b, + 0x0000001a, 0x000000ab, 0x000039ca, 0x0004002b, 0x0000001a, 0x000000ac, 0x0000b695, 0x0004002b, + 0x0000001a, 0x000000ad, 0x0000badb, 0x0004002b, 0x0000001a, 0x000000ae, 0x0000b94f, 0x0007002c, + 0x0000001b, 0x000000af, 0x000000ab, 0x000000ac, 0x000000ad, 0x000000ae, 0x0004002b, 0x0000001a, + 0x000000b0, 0x0000b6df, 0x0004002b, 0x0000001a, 0x000000b1, 0x00002dae, 0x0004002b, 0x0000001a, + 0x000000b2, 0x0000365b, 0x0004002b, 0x0000001a, 0x000000b3, 0x00003867, 0x0007002c, 0x0000001b, + 0x000000b4, 0x000000b0, 0x000000b1, 0x000000b2, 0x000000b3, 0x0004002b, 0x0000001a, 0x000000b5, + 0x0000b9ad, 0x0004002b, 0x0000001a, 0x000000b6, 0x0000b78c, 0x0004002b, 0x0000001a, 0x000000b7, + 0x000038f6, 0x0004002b, 0x0000001a, 0x000000b8, 0x00003245, 0x0007002c, 0x0000001b, 0x000000b9, + 0x000000b5, 0x000000b6, 0x000000b7, 0x000000b8, 0x0007002c, 0x0000001c, 0x000000ba, 0x000000aa, + 0x000000af, 0x000000b4, 0x000000b9, 0x0005002c, 0x0000000a, 0x000000bb, 0x00000063, 0x00000032, + 0x0004002b, 0x0000001a, 0x000000bc, 0x0000b2d3, 0x0004002b, 0x0000001a, 0x000000bd, 0x00002d03, + 0x0004002b, 0x0000001a, 0x000000be, 0x00003542, 0x0004002b, 0x0000001a, 0x000000bf, 0x00003112, + 0x0007002c, 0x0000001b, 0x000000c0, 0x000000bc, 0x000000bd, 0x000000be, 0x000000bf, 0x0004002b, + 0x0000001a, 0x000000c1, 0x000036ad, 0x0004002b, 0x0000001a, 0x000000c2, 0x0000b43b, 0x0004002b, + 0x0000001a, 0x000000c3, 0x0000b571, 0x0004002b, 0x0000001a, 0x000000c4, 0x0000b904, 0x0007002c, + 0x0000001b, 0x000000c5, 0x000000c1, 0x000000c2, 0x000000c3, 0x000000c4, 0x0004002b, 0x0000001a, + 0x000000c6, 0x0000b51f, 0x0004002b, 0x0000001a, 0x000000c7, 0x000034d1, 0x0004002b, 0x0000001a, + 0x000000c8, 0x000035b8, 0x0004002b, 0x0000001a, 0x000000c9, 0x0000368c, 0x0007002c, 0x0000001b, + 0x000000ca, 0x000000c6, 0x000000c7, 0x000000c8, 0x000000c9, 0x0004002b, 0x0000001a, 0x000000cb, + 0x00002bb0, 0x0004002b, 0x0000001a, 0x000000cc, 0x00003532, 0x0004002b, 0x0000001a, 0x000000cd, + 0x0000302d, 0x0004002b, 0x0000001a, 0x000000ce, 0x0000b89f, 0x0007002c, 0x0000001b, 0x000000cf, + 0x000000cb, 0x000000cc, 0x000000cd, 0x000000ce, 0x0007002c, 0x0000001c, 0x000000d0, 0x000000c0, + 0x000000c5, 0x000000ca, 0x000000cf, 0x0005002c, 0x0000000a, 0x000000d1, 0x00000063, 0x00000017, + 0x0004002b, 0x0000001a, 0x000000d2, 0x0000b88d, 0x0004002b, 0x0000001a, 0x000000d3, 0x0000217c, + 0x0004002b, 0x0000001a, 0x000000d4, 0x000038d6, 0x0004002b, 0x0000001a, 0x000000d5, 0x00003889, + 0x0007002c, 0x0000001b, 0x000000d6, 0x000000d2, 0x000000d3, 0x000000d4, 0x000000d5, 0x0004002b, + 0x0000001a, 0x000000d7, 0x000038d5, 0x0004002b, 0x0000001a, 0x000000d8, 0x0000ba2b, 0x0004002b, + 0x0000001a, 0x000000d9, 0x0000b722, 0x0004002b, 0x0000001a, 0x000000da, 0x0000b903, 0x0007002c, + 0x0000001b, 0x000000db, 0x000000d7, 0x000000d8, 0x000000d9, 0x000000da, 0x0004002b, 0x0000001a, + 0x000000dc, 0x0000b1a7, 0x0004002b, 0x0000001a, 0x000000dd, 0x00002cab, 0x0004002b, 0x0000001a, + 0x000000de, 0x00002787, 0x0004002b, 0x0000001a, 0x000000df, 0x0000a8f1, 0x0007002c, 0x0000001b, + 0x000000e0, 0x000000dc, 0x000000dd, 0x000000de, 0x000000df, 0x0004002b, 0x0000001a, 0x000000e1, + 0x00002e5c, 0x0004002b, 0x0000001a, 0x000000e2, 0x0000bad2, 0x0004002b, 0x0000001a, 0x000000e3, + 0x0000b36a, 0x0004002b, 0x0000001a, 0x000000e4, 0x0000b6e2, 0x0007002c, 0x0000001b, 0x000000e5, + 0x000000e1, 0x000000e2, 0x000000e3, 0x000000e4, 0x0007002c, 0x0000001c, 0x000000e6, 0x000000d6, + 0x000000db, 0x000000e0, 0x000000e5, 0x0005002c, 0x0000000a, 0x000000e7, 0x00000063, 0x00000063, + 0x0004002b, 0x0000001a, 0x000000e8, 0x0000bc4a, 0x0004002b, 0x0000001a, 0x000000e9, 0x0000b49b, + 0x0004002b, 0x0000001a, 0x000000ea, 0x00003d94, 0x0004002b, 0x0000001a, 0x000000eb, 0x0000b6cf, + 0x0007002c, 0x0000001b, 0x000000ec, 0x000000e8, 0x000000e9, 0x000000ea, 0x000000eb, 0x0004002b, + 0x0000001a, 0x000000ed, 0x000039a9, 0x0004002b, 0x0000001a, 0x000000ee, 0x00003873, 0x0004002b, + 0x0000001a, 0x000000ef, 0x00003961, 0x0004002b, 0x0000001a, 0x000000f0, 0x00003916, 0x0007002c, + 0x0000001b, 0x000000f1, 0x000000ed, 0x000000ee, 0x000000ef, 0x000000f0, 0x0004002b, 0x0000001a, + 0x000000f2, 0x00003203, 0x0004002b, 0x0000001a, 0x000000f3, 0x00003418, 0x0004002b, 0x0000001a, + 0x000000f4, 0x00003aee, 0x0004002b, 0x0000001a, 0x000000f5, 0x0000b4dc, 0x0007002c, 0x0000001b, + 0x000000f6, 0x000000f2, 0x000000f3, 0x000000f4, 0x000000f5, 0x0004002b, 0x0000000b, 0x000000f7, + 0x00000010, 0x0006002c, 0x0000000c, 0x00000006, 0x000000f7, 0x000000f7, 0x00000019, 0x00050036, + 0x00000007, 0x00000002, 0x00000000, 0x00000008, 0x000200f8, 0x000000f8, 0x000300f7, 0x000000f9, + 0x00000000, 0x000300fb, 0x00000018, 0x000000fa, 0x000200f8, 0x000000fa, 0x0004003d, 0x0000000c, + 0x000000fb, 0x00000003, 0x0007004f, 0x0000000e, 0x000000fc, 0x000000fb, 0x000000fb, 0x00000000, + 0x00000001, 0x0004007c, 0x0000000a, 0x000000fd, 0x000000fc, 0x0004003d, 0x00000010, 0x000000fe, + 0x00000004, 0x00040068, 0x0000000a, 0x000000ff, 0x000000fe, 0x000500af, 0x00000013, 0x00000100, + 0x000000fd, 0x000000ff, 0x0004009a, 0x00000012, 0x00000101, 0x00000100, 0x000300f7, 0x00000102, + 0x00000000, 0x000400fa, 0x00000101, 0x00000103, 0x00000102, 0x000200f8, 0x00000103, 0x000200f9, + 0x000000f9, 0x000200f8, 0x00000102, 0x0004003d, 0x00000010, 0x00000104, 0x00000004, 0x00050080, + 0x0000000a, 0x00000105, 0x000000fd, 0x00000033, 0x000500af, 0x00000013, 0x00000106, 0x00000105, + 0x00000034, 0x0004009b, 0x00000012, 0x00000107, 0x00000106, 0x000300f7, 0x00000108, 0x00000000, + 0x000400fa, 0x00000107, 0x00000109, 0x00000108, 0x000200f8, 0x00000109, 0x0004003d, 0x00000015, + 0x0000010a, 0x00000005, 0x00040064, 0x00000014, 0x0000010b, 0x0000010a, 0x00050067, 0x0000000a, + 0x0000010c, 0x0000010b, 0x00000017, 0x000500b1, 0x00000013, 0x0000010d, 0x00000105, 0x0000010c, + 0x0004009b, 0x00000012, 0x0000010e, 0x0000010d, 0x000200f9, 0x00000108, 0x000200f8, 0x00000108, + 0x000700f5, 0x00000012, 0x0000010f, 0x00000107, 0x00000102, 0x0000010e, 0x00000109, 0x000300f7, + 0x00000110, 0x00000000, 0x000400fa, 0x0000010f, 0x00000111, 0x00000112, 0x000200f8, 0x00000111, + 0x0004003d, 0x00000015, 0x00000113, 0x00000005, 0x00040064, 0x00000014, 0x00000114, 0x00000113, + 0x0007005f, 0x00000035, 0x00000115, 0x00000114, 0x00000105, 0x00000002, 0x00000017, 0x000200f9, + 0x00000110, 0x000200f8, 0x00000112, 0x000200f9, 0x00000110, 0x000200f8, 0x00000110, 0x000700f5, + 0x00000035, 0x00000116, 0x00000115, 0x00000111, 0x00000037, 0x00000112, 0x00040073, 0x0000001b, + 0x00000117, 0x00000116, 0x00050091, 0x0000001b, 0x00000118, 0x00000031, 0x00000117, 0x00050080, + 0x0000000a, 0x00000119, 0x000000fd, 0x0000004d, 0x000500af, 0x00000013, 0x0000011a, 0x00000119, + 0x00000034, 0x0004009b, 0x00000012, 0x0000011b, 0x0000011a, 0x000300f7, 0x0000011c, 0x00000000, + 0x000400fa, 0x0000011b, 0x0000011d, 0x0000011c, 0x000200f8, 0x0000011d, 0x0004003d, 0x00000015, + 0x0000011e, 0x00000005, 0x00040064, 0x00000014, 0x0000011f, 0x0000011e, 0x00050067, 0x0000000a, + 0x00000120, 0x0000011f, 0x00000017, 0x000500b1, 0x00000013, 0x00000121, 0x00000119, 0x00000120, + 0x0004009b, 0x00000012, 0x00000122, 0x00000121, 0x000200f9, 0x0000011c, 0x000200f8, 0x0000011c, + 0x000700f5, 0x00000012, 0x00000123, 0x0000011b, 0x00000110, 0x00000122, 0x0000011d, 0x000300f7, + 0x00000124, 0x00000000, 0x000400fa, 0x00000123, 0x00000125, 0x00000126, 0x000200f8, 0x00000125, + 0x0004003d, 0x00000015, 0x00000127, 0x00000005, 0x00040064, 0x00000014, 0x00000128, 0x00000127, + 0x0007005f, 0x00000035, 0x00000129, 0x00000128, 0x00000119, 0x00000002, 0x00000017, 0x000200f9, + 0x00000124, 0x000200f8, 0x00000126, 0x000200f9, 0x00000124, 0x000200f8, 0x00000124, 0x000700f5, + 0x00000035, 0x0000012a, 0x00000129, 0x00000125, 0x00000037, 0x00000126, 0x00040073, 0x0000001b, + 0x0000012b, 0x0000012a, 0x00050091, 0x0000001b, 0x0000012c, 0x0000004c, 0x0000012b, 0x00050081, + 0x0000001b, 0x0000012d, 0x00000118, 0x0000012c, 0x00050080, 0x0000000a, 0x0000012e, 0x000000fd, + 0x00000064, 0x000500af, 0x00000013, 0x0000012f, 0x0000012e, 0x00000034, 0x0004009b, 0x00000012, + 0x00000130, 0x0000012f, 0x000300f7, 0x00000131, 0x00000000, 0x000400fa, 0x00000130, 0x00000132, + 0x00000131, 0x000200f8, 0x00000132, 0x0004003d, 0x00000015, 0x00000133, 0x00000005, 0x00040064, + 0x00000014, 0x00000134, 0x00000133, 0x00050067, 0x0000000a, 0x00000135, 0x00000134, 0x00000017, + 0x000500b1, 0x00000013, 0x00000136, 0x0000012e, 0x00000135, 0x0004009b, 0x00000012, 0x00000137, + 0x00000136, 0x000200f9, 0x00000131, 0x000200f8, 0x00000131, 0x000700f5, 0x00000012, 0x00000138, + 0x00000130, 0x00000124, 0x00000137, 0x00000132, 0x000300f7, 0x00000139, 0x00000000, 0x000400fa, + 0x00000138, 0x0000013a, 0x0000013b, 0x000200f8, 0x0000013a, 0x0004003d, 0x00000015, 0x0000013c, + 0x00000005, 0x00040064, 0x00000014, 0x0000013d, 0x0000013c, 0x0007005f, 0x00000035, 0x0000013e, + 0x0000013d, 0x0000012e, 0x00000002, 0x00000017, 0x000200f9, 0x00000139, 0x000200f8, 0x0000013b, + 0x000200f9, 0x00000139, 0x000200f8, 0x00000139, 0x000700f5, 0x00000035, 0x0000013f, 0x0000013e, + 0x0000013a, 0x00000037, 0x0000013b, 0x00040073, 0x0000001b, 0x00000140, 0x0000013f, 0x00050091, + 0x0000001b, 0x00000141, 0x00000062, 0x00000140, 0x00050081, 0x0000001b, 0x00000142, 0x0000012d, + 0x00000141, 0x00050080, 0x0000000a, 0x00000143, 0x000000fd, 0x0000007a, 0x000500af, 0x00000013, + 0x00000144, 0x00000143, 0x00000034, 0x0004009b, 0x00000012, 0x00000145, 0x00000144, 0x000300f7, + 0x00000146, 0x00000000, 0x000400fa, 0x00000145, 0x00000147, 0x00000146, 0x000200f8, 0x00000147, + 0x0004003d, 0x00000015, 0x00000148, 0x00000005, 0x00040064, 0x00000014, 0x00000149, 0x00000148, + 0x00050067, 0x0000000a, 0x0000014a, 0x00000149, 0x00000017, 0x000500b1, 0x00000013, 0x0000014b, + 0x00000143, 0x0000014a, 0x0004009b, 0x00000012, 0x0000014c, 0x0000014b, 0x000200f9, 0x00000146, + 0x000200f8, 0x00000146, 0x000700f5, 0x00000012, 0x0000014d, 0x00000145, 0x00000139, 0x0000014c, + 0x00000147, 0x000300f7, 0x0000014e, 0x00000000, 0x000400fa, 0x0000014d, 0x0000014f, 0x00000150, + 0x000200f8, 0x0000014f, 0x0004003d, 0x00000015, 0x00000151, 0x00000005, 0x00040064, 0x00000014, + 0x00000152, 0x00000151, 0x0007005f, 0x00000035, 0x00000153, 0x00000152, 0x00000143, 0x00000002, + 0x00000017, 0x000200f9, 0x0000014e, 0x000200f8, 0x00000150, 0x000200f9, 0x0000014e, 0x000200f8, + 0x0000014e, 0x000700f5, 0x00000035, 0x00000154, 0x00000153, 0x0000014f, 0x00000037, 0x00000150, + 0x00040073, 0x0000001b, 0x00000155, 0x00000154, 0x00050091, 0x0000001b, 0x00000156, 0x00000079, + 0x00000155, 0x00050081, 0x0000001b, 0x00000157, 0x00000142, 0x00000156, 0x0004003d, 0x00000015, + 0x00000158, 0x00000005, 0x00040064, 0x00000014, 0x00000159, 0x00000158, 0x0007005f, 0x00000035, + 0x0000015a, 0x00000159, 0x000000fd, 0x00000002, 0x00000017, 0x00040073, 0x0000001b, 0x0000015b, + 0x0000015a, 0x00050091, 0x0000001b, 0x0000015c, 0x0000008f, 0x0000015b, 0x00050081, 0x0000001b, + 0x0000015d, 0x00000157, 0x0000015c, 0x00050080, 0x0000000a, 0x0000015e, 0x000000fd, 0x000000a5, + 0x000500af, 0x00000013, 0x0000015f, 0x0000015e, 0x00000034, 0x0004009b, 0x00000012, 0x00000160, + 0x0000015f, 0x000300f7, 0x00000161, 0x00000000, 0x000400fa, 0x00000160, 0x00000162, 0x00000161, + 0x000200f8, 0x00000162, 0x0004003d, 0x00000015, 0x00000163, 0x00000005, 0x00040064, 0x00000014, + 0x00000164, 0x00000163, 0x00050067, 0x0000000a, 0x00000165, 0x00000164, 0x00000017, 0x000500b1, + 0x00000013, 0x00000166, 0x0000015e, 0x00000165, 0x0004009b, 0x00000012, 0x00000167, 0x00000166, + 0x000200f9, 0x00000161, 0x000200f8, 0x00000161, 0x000700f5, 0x00000012, 0x00000168, 0x00000160, + 0x0000014e, 0x00000167, 0x00000162, 0x000300f7, 0x00000169, 0x00000000, 0x000400fa, 0x00000168, + 0x0000016a, 0x0000016b, 0x000200f8, 0x0000016a, 0x0004003d, 0x00000015, 0x0000016c, 0x00000005, + 0x00040064, 0x00000014, 0x0000016d, 0x0000016c, 0x0007005f, 0x00000035, 0x0000016e, 0x0000016d, + 0x0000015e, 0x00000002, 0x00000017, 0x000200f9, 0x00000169, 0x000200f8, 0x0000016b, 0x000200f9, + 0x00000169, 0x000200f8, 0x00000169, 0x000700f5, 0x00000035, 0x0000016f, 0x0000016e, 0x0000016a, + 0x00000037, 0x0000016b, 0x00040073, 0x0000001b, 0x00000170, 0x0000016f, 0x00050091, 0x0000001b, + 0x00000171, 0x000000a4, 0x00000170, 0x00050081, 0x0000001b, 0x00000172, 0x0000015d, 0x00000171, + 0x00050080, 0x0000000a, 0x00000173, 0x000000fd, 0x000000bb, 0x000500af, 0x00000013, 0x00000174, + 0x00000173, 0x00000034, 0x0004009b, 0x00000012, 0x00000175, 0x00000174, 0x000300f7, 0x00000176, + 0x00000000, 0x000400fa, 0x00000175, 0x00000177, 0x00000176, 0x000200f8, 0x00000177, 0x0004003d, + 0x00000015, 0x00000178, 0x00000005, 0x00040064, 0x00000014, 0x00000179, 0x00000178, 0x00050067, + 0x0000000a, 0x0000017a, 0x00000179, 0x00000017, 0x000500b1, 0x00000013, 0x0000017b, 0x00000173, + 0x0000017a, 0x0004009b, 0x00000012, 0x0000017c, 0x0000017b, 0x000200f9, 0x00000176, 0x000200f8, + 0x00000176, 0x000700f5, 0x00000012, 0x0000017d, 0x00000175, 0x00000169, 0x0000017c, 0x00000177, + 0x000300f7, 0x0000017e, 0x00000000, 0x000400fa, 0x0000017d, 0x0000017f, 0x00000180, 0x000200f8, + 0x0000017f, 0x0004003d, 0x00000015, 0x00000181, 0x00000005, 0x00040064, 0x00000014, 0x00000182, + 0x00000181, 0x0007005f, 0x00000035, 0x00000183, 0x00000182, 0x00000173, 0x00000002, 0x00000017, + 0x000200f9, 0x0000017e, 0x000200f8, 0x00000180, 0x000200f9, 0x0000017e, 0x000200f8, 0x0000017e, + 0x000700f5, 0x00000035, 0x00000184, 0x00000183, 0x0000017f, 0x00000037, 0x00000180, 0x00040073, + 0x0000001b, 0x00000185, 0x00000184, 0x00050091, 0x0000001b, 0x00000186, 0x000000ba, 0x00000185, + 0x00050081, 0x0000001b, 0x00000187, 0x00000172, 0x00000186, 0x00050080, 0x0000000a, 0x00000188, + 0x000000fd, 0x000000d1, 0x000500af, 0x00000013, 0x00000189, 0x00000188, 0x00000034, 0x0004009b, + 0x00000012, 0x0000018a, 0x00000189, 0x000300f7, 0x0000018b, 0x00000000, 0x000400fa, 0x0000018a, + 0x0000018c, 0x0000018b, 0x000200f8, 0x0000018c, 0x0004003d, 0x00000015, 0x0000018d, 0x00000005, + 0x00040064, 0x00000014, 0x0000018e, 0x0000018d, 0x00050067, 0x0000000a, 0x0000018f, 0x0000018e, + 0x00000017, 0x000500b1, 0x00000013, 0x00000190, 0x00000188, 0x0000018f, 0x0004009b, 0x00000012, + 0x00000191, 0x00000190, 0x000200f9, 0x0000018b, 0x000200f8, 0x0000018b, 0x000700f5, 0x00000012, + 0x00000192, 0x0000018a, 0x0000017e, 0x00000191, 0x0000018c, 0x000300f7, 0x00000193, 0x00000000, + 0x000400fa, 0x00000192, 0x00000194, 0x00000195, 0x000200f8, 0x00000194, 0x0004003d, 0x00000015, + 0x00000196, 0x00000005, 0x00040064, 0x00000014, 0x00000197, 0x00000196, 0x0007005f, 0x00000035, + 0x00000198, 0x00000197, 0x00000188, 0x00000002, 0x00000017, 0x000200f9, 0x00000193, 0x000200f8, + 0x00000195, 0x000200f9, 0x00000193, 0x000200f8, 0x00000193, 0x000700f5, 0x00000035, 0x00000199, + 0x00000198, 0x00000194, 0x00000037, 0x00000195, 0x00040073, 0x0000001b, 0x0000019a, 0x00000199, + 0x00050091, 0x0000001b, 0x0000019b, 0x000000d0, 0x0000019a, 0x00050081, 0x0000001b, 0x0000019c, + 0x00000187, 0x0000019b, 0x00050080, 0x0000000a, 0x0000019d, 0x000000fd, 0x000000e7, 0x000500af, + 0x00000013, 0x0000019e, 0x0000019d, 0x00000034, 0x0004009b, 0x00000012, 0x0000019f, 0x0000019e, + 0x000300f7, 0x000001a0, 0x00000000, 0x000400fa, 0x0000019f, 0x000001a1, 0x000001a0, 0x000200f8, + 0x000001a1, 0x0004003d, 0x00000015, 0x000001a2, 0x00000005, 0x00040064, 0x00000014, 0x000001a3, + 0x000001a2, 0x00050067, 0x0000000a, 0x000001a4, 0x000001a3, 0x00000017, 0x000500b1, 0x00000013, + 0x000001a5, 0x0000019d, 0x000001a4, 0x0004009b, 0x00000012, 0x000001a6, 0x000001a5, 0x000200f9, + 0x000001a0, 0x000200f8, 0x000001a0, 0x000700f5, 0x00000012, 0x000001a7, 0x0000019f, 0x00000193, + 0x000001a6, 0x000001a1, 0x000300f7, 0x000001a8, 0x00000000, 0x000400fa, 0x000001a7, 0x000001a9, + 0x000001aa, 0x000200f8, 0x000001a9, 0x0004003d, 0x00000015, 0x000001ab, 0x00000005, 0x00040064, + 0x00000014, 0x000001ac, 0x000001ab, 0x0007005f, 0x00000035, 0x000001ad, 0x000001ac, 0x0000019d, + 0x00000002, 0x00000017, 0x000200f9, 0x000001a8, 0x000200f8, 0x000001aa, 0x000200f9, 0x000001a8, + 0x000200f8, 0x000001a8, 0x000700f5, 0x00000035, 0x000001ae, 0x000001ad, 0x000001a9, 0x00000037, + 0x000001aa, 0x00040073, 0x0000001b, 0x000001af, 0x000001ae, 0x00050091, 0x0000001b, 0x000001b0, + 0x000000e6, 0x000001af, 0x00050081, 0x0000001b, 0x000001b1, 0x0000019c, 0x000001b0, 0x00050083, + 0x0000001b, 0x000001b2, 0x000001b1, 0x000000ec, 0x00050085, 0x0000001b, 0x000001b3, 0x000001b2, + 0x000000f1, 0x00050081, 0x0000001b, 0x000001b4, 0x000001b3, 0x000000f6, 0x00040073, 0x00000035, + 0x000001b5, 0x000001b4, 0x00040063, 0x00000104, 0x000000fd, 0x000001b5, 0x000200f9, 0x000000f9, + 0x000200f8, 0x000000f9, 0x000100fd, 0x00010038, +}; +static const size_t wnfg_28_spv_size = sizeof(wnfg_28_spv); diff --git a/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_29_spv.h b/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_29_spv.h new file mode 100644 index 000000000..89f1dee43 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_29_spv.h @@ -0,0 +1,200 @@ +#pragma once +#include +#include + +static const uint32_t wnfg_29_spv[] = { + 0x07230203, 0x00010000, 0x000d000b, 0x00000139, 0x00000000, 0x00020011, 0x00000001, 0x00020011, + 0x00000009, 0x00020011, 0x00000032, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, + 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0006000f, 0x00000005, 0x00000002, 0x6e69616d, + 0x00000000, 0x00000003, 0x00060010, 0x00000002, 0x00000011, 0x00000010, 0x00000010, 0x00000001, + 0x00040047, 0x00000003, 0x0000000b, 0x0000001c, 0x00030047, 0x00000004, 0x00000019, 0x00040047, + 0x00000004, 0x00000021, 0x00000030, 0x00040047, 0x00000004, 0x00000022, 0x00000000, 0x00040047, + 0x00000005, 0x00000021, 0x00000020, 0x00040047, 0x00000005, 0x00000022, 0x00000000, 0x00040047, + 0x00000006, 0x00000021, 0x00000021, 0x00040047, 0x00000006, 0x00000022, 0x00000000, 0x00040047, + 0x00000007, 0x0000000b, 0x00000019, 0x00020013, 0x00000008, 0x00030021, 0x00000009, 0x00000008, + 0x00040015, 0x0000000a, 0x00000020, 0x00000001, 0x00040017, 0x0000000b, 0x0000000a, 0x00000002, + 0x00040015, 0x0000000c, 0x00000020, 0x00000000, 0x00040017, 0x0000000d, 0x0000000c, 0x00000003, + 0x00040020, 0x0000000e, 0x00000001, 0x0000000d, 0x0004003b, 0x0000000e, 0x00000003, 0x00000001, + 0x00040017, 0x0000000f, 0x0000000c, 0x00000002, 0x00030016, 0x00000010, 0x00000020, 0x00090019, + 0x00000011, 0x00000010, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0x00000002, + 0x00040020, 0x00000012, 0x00000000, 0x00000011, 0x0004003b, 0x00000012, 0x00000004, 0x00000000, + 0x00020014, 0x00000013, 0x00040017, 0x00000014, 0x00000013, 0x00000002, 0x00090019, 0x00000015, + 0x00000010, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x0003001b, + 0x00000016, 0x00000015, 0x00040020, 0x00000017, 0x00000000, 0x00000016, 0x0004003b, 0x00000017, + 0x00000005, 0x00000000, 0x0004002b, 0x0000000a, 0x00000018, 0x00000000, 0x00040017, 0x00000019, + 0x00000010, 0x00000002, 0x0004002b, 0x00000010, 0x0000001a, 0x3f000000, 0x0005002c, 0x00000019, + 0x0000001b, 0x0000001a, 0x0000001a, 0x0004002b, 0x0000000c, 0x0000001c, 0x00000000, 0x0004002b, + 0x0000000c, 0x0000001d, 0x00000001, 0x00030016, 0x0000001e, 0x00000010, 0x00040017, 0x0000001f, + 0x0000001e, 0x00000004, 0x00040018, 0x00000020, 0x0000001f, 0x00000004, 0x0004002b, 0x0000001e, + 0x00000021, 0x000034c4, 0x0004002b, 0x0000001e, 0x00000022, 0x00003476, 0x0004002b, 0x0000001e, + 0x00000023, 0x0000b9f4, 0x0004002b, 0x0000001e, 0x00000024, 0x0000b99b, 0x0007002c, 0x0000001f, + 0x00000025, 0x00000021, 0x00000022, 0x00000023, 0x00000024, 0x0004002b, 0x0000001e, 0x00000026, + 0x00003093, 0x0004002b, 0x0000001e, 0x00000027, 0x00002fc1, 0x0004002b, 0x0000001e, 0x00000028, + 0x00002f2b, 0x0004002b, 0x0000001e, 0x00000029, 0x00003052, 0x0007002c, 0x0000001f, 0x0000002a, + 0x00000026, 0x00000027, 0x00000028, 0x00000029, 0x0004002b, 0x0000001e, 0x0000002b, 0x0000327c, + 0x0004002b, 0x0000001e, 0x0000002c, 0x0000327f, 0x0004002b, 0x0000001e, 0x0000002d, 0x00003636, + 0x0004002b, 0x0000001e, 0x0000002e, 0x00003644, 0x0007002c, 0x0000001f, 0x0000002f, 0x0000002b, + 0x0000002c, 0x0000002d, 0x0000002e, 0x0004002b, 0x0000001e, 0x00000030, 0x0000b996, 0x0004002b, + 0x0000001e, 0x00000031, 0x0000b995, 0x0004002b, 0x0000001e, 0x00000032, 0x00003539, 0x0004002b, + 0x0000001e, 0x00000033, 0x0000352e, 0x0007002c, 0x0000001f, 0x00000034, 0x00000030, 0x00000031, + 0x00000032, 0x00000033, 0x0007002c, 0x00000020, 0x00000035, 0x00000025, 0x0000002a, 0x0000002f, + 0x00000034, 0x0004002b, 0x00000010, 0x00000036, 0x00000000, 0x0004002b, 0x0000000a, 0x00000037, + 0xffffffff, 0x0005002c, 0x0000000b, 0x00000038, 0x00000037, 0x00000037, 0x00040017, 0x00000039, + 0x00000010, 0x00000004, 0x0004002b, 0x0000001e, 0x0000003a, 0x000038e2, 0x0004002b, 0x0000001e, + 0x0000003b, 0x000038c9, 0x0004002b, 0x0000001e, 0x0000003c, 0x0000acc5, 0x0004002b, 0x0000001e, + 0x0000003d, 0x0000adfa, 0x0007002c, 0x0000001f, 0x0000003e, 0x0000003a, 0x0000003b, 0x0000003c, + 0x0000003d, 0x0004002b, 0x0000001e, 0x0000003f, 0x000037aa, 0x0004002b, 0x0000001e, 0x00000040, + 0x00003786, 0x0004002b, 0x0000001e, 0x00000041, 0x00003554, 0x0004002b, 0x0000001e, 0x00000042, + 0x000035de, 0x0007002c, 0x0000001f, 0x00000043, 0x0000003f, 0x00000040, 0x00000041, 0x00000042, + 0x0004002b, 0x0000001e, 0x00000044, 0x00003665, 0x0004002b, 0x0000001e, 0x00000045, 0x00003653, + 0x0004002b, 0x0000001e, 0x00000046, 0x00003708, 0x0004002b, 0x0000001e, 0x00000047, 0x00003706, + 0x0007002c, 0x0000001f, 0x00000048, 0x00000044, 0x00000045, 0x00000046, 0x00000047, 0x0004002b, + 0x0000001e, 0x00000049, 0x0000b948, 0x0004002b, 0x0000001e, 0x0000004a, 0x0000b912, 0x0004002b, + 0x0000001e, 0x0000004b, 0x00003119, 0x0004002b, 0x0000001e, 0x0000004c, 0x000030c5, 0x0007002c, + 0x0000001f, 0x0000004d, 0x00000049, 0x0000004a, 0x0000004b, 0x0000004c, 0x0007002c, 0x00000020, + 0x0000004e, 0x0000003e, 0x00000043, 0x00000048, 0x0000004d, 0x0005002c, 0x0000000b, 0x0000004f, + 0x00000037, 0x00000018, 0x0004002b, 0x0000001e, 0x00000050, 0x00003515, 0x0004002b, 0x0000001e, + 0x00000051, 0x000034b9, 0x0004002b, 0x0000001e, 0x00000052, 0x0000ba6a, 0x0004002b, 0x0000001e, + 0x00000053, 0x0000ba18, 0x0007002c, 0x0000001f, 0x00000054, 0x00000050, 0x00000051, 0x00000052, + 0x00000053, 0x0004002b, 0x0000001e, 0x00000055, 0x00002e5c, 0x0004002b, 0x0000001e, 0x00000056, + 0x00002ce5, 0x0004002b, 0x0000001e, 0x00000057, 0x000032d0, 0x0004002b, 0x0000001e, 0x00000058, + 0x00003318, 0x0007002c, 0x0000001f, 0x00000059, 0x00000055, 0x00000056, 0x00000057, 0x00000058, + 0x0004002b, 0x0000001e, 0x0000005a, 0x00003467, 0x0004002b, 0x0000001e, 0x0000005b, 0x00003446, + 0x0004002b, 0x0000001e, 0x0000005c, 0x00003477, 0x0004002b, 0x0000001e, 0x0000005d, 0x000034e7, + 0x0007002c, 0x0000001f, 0x0000005e, 0x0000005a, 0x0000005b, 0x0000005c, 0x0000005d, 0x0004002b, + 0x0000001e, 0x0000005f, 0x0000b999, 0x0004002b, 0x0000001e, 0x00000060, 0x0000b956, 0x0004002b, + 0x0000001e, 0x00000061, 0x00003508, 0x0004002b, 0x0000001e, 0x00000062, 0x0000351f, 0x0007002c, + 0x0000001f, 0x00000063, 0x0000005f, 0x00000060, 0x00000061, 0x00000062, 0x0007002c, 0x00000020, + 0x00000064, 0x00000054, 0x00000059, 0x0000005e, 0x00000063, 0x0004002b, 0x0000000a, 0x00000065, + 0x00000001, 0x0005002c, 0x0000000b, 0x00000066, 0x00000037, 0x00000065, 0x0004002b, 0x0000001e, + 0x00000067, 0x00003888, 0x0004002b, 0x0000001e, 0x00000068, 0x0000389c, 0x0004002b, 0x0000001e, + 0x00000069, 0x00002c10, 0x0004002b, 0x0000001e, 0x0000006a, 0x00002c76, 0x0007002c, 0x0000001f, + 0x0000006b, 0x00000067, 0x00000068, 0x00000069, 0x0000006a, 0x0004002b, 0x0000001e, 0x0000006c, + 0x00003790, 0x0004002b, 0x0000001e, 0x0000006d, 0x0000377d, 0x0004002b, 0x0000001e, 0x0000006e, + 0x0000367b, 0x0004002b, 0x0000001e, 0x0000006f, 0x000036aa, 0x0007002c, 0x0000001f, 0x00000070, + 0x0000006c, 0x0000006d, 0x0000006e, 0x0000006f, 0x0004002b, 0x0000001e, 0x00000071, 0x000035fa, + 0x0004002b, 0x0000001e, 0x00000072, 0x000035d6, 0x0004002b, 0x0000001e, 0x00000073, 0x00003854, + 0x0004002b, 0x0000001e, 0x00000074, 0x00003874, 0x0007002c, 0x0000001f, 0x00000075, 0x00000071, + 0x00000072, 0x00000073, 0x00000074, 0x0004002b, 0x0000001e, 0x00000076, 0x0000b900, 0x0004002b, + 0x0000001e, 0x00000077, 0x0000b94e, 0x0004002b, 0x0000001e, 0x00000078, 0x000032e8, 0x0004002b, + 0x0000001e, 0x00000079, 0x000032b4, 0x0007002c, 0x0000001f, 0x0000007a, 0x00000076, 0x00000077, + 0x00000078, 0x00000079, 0x0007002c, 0x00000020, 0x0000007b, 0x0000006b, 0x00000070, 0x00000075, + 0x0000007a, 0x0005002c, 0x0000000b, 0x0000007c, 0x00000018, 0x00000037, 0x0004002b, 0x0000001e, + 0x0000007d, 0x00003add, 0x0004002b, 0x0000001e, 0x0000007e, 0x00003aaa, 0x0004002b, 0x0000001e, + 0x0000007f, 0x00003902, 0x0004002b, 0x0000001e, 0x00000080, 0x000038bc, 0x0007002c, 0x0000001f, + 0x00000081, 0x0000007d, 0x0000007e, 0x0000007f, 0x00000080, 0x0004002b, 0x0000001e, 0x00000082, + 0x00003a9c, 0x0004002b, 0x0000001e, 0x00000083, 0x00003a3e, 0x0004002b, 0x0000001e, 0x00000084, + 0x00003946, 0x0004002b, 0x0000001e, 0x00000085, 0x00003948, 0x0007002c, 0x0000001f, 0x00000086, + 0x00000082, 0x00000083, 0x00000084, 0x00000085, 0x0004002b, 0x0000001e, 0x00000087, 0x0000388a, + 0x0004002b, 0x0000001e, 0x00000088, 0x00003856, 0x0004002b, 0x0000001e, 0x00000089, 0x000038ef, + 0x0004002b, 0x0000001e, 0x0000008a, 0x000038f0, 0x0007002c, 0x0000001f, 0x0000008b, 0x00000087, + 0x00000088, 0x00000089, 0x0000008a, 0x0004002b, 0x0000001e, 0x0000008c, 0x0000b86b, 0x0004002b, + 0x0000001e, 0x0000008d, 0x0000b86e, 0x0004002b, 0x0000001e, 0x0000008e, 0x0000299c, 0x0004002b, + 0x0000001e, 0x0000008f, 0x00002ad4, 0x0007002c, 0x0000001f, 0x00000090, 0x0000008c, 0x0000008d, + 0x0000008e, 0x0000008f, 0x0007002c, 0x00000020, 0x00000091, 0x00000081, 0x00000086, 0x0000008b, + 0x00000090, 0x0004002b, 0x0000001e, 0x00000092, 0x000038b9, 0x0004002b, 0x0000001e, 0x00000093, + 0x0000aec6, 0x0004002b, 0x0000001e, 0x00000094, 0x0000b020, 0x0007002c, 0x0000001f, 0x00000095, + 0x00000092, 0x00000087, 0x00000093, 0x00000094, 0x0004002b, 0x0000001e, 0x00000096, 0x00003707, + 0x0004002b, 0x0000001e, 0x00000097, 0x000036b7, 0x0004002b, 0x0000001e, 0x00000098, 0x0000383a, + 0x0004002b, 0x0000001e, 0x00000099, 0x0000384d, 0x0007002c, 0x0000001f, 0x0000009a, 0x00000096, + 0x00000097, 0x00000098, 0x00000099, 0x0004002b, 0x0000001e, 0x0000009b, 0x0000376a, 0x0004002b, + 0x0000001e, 0x0000009c, 0x0000372e, 0x0004002b, 0x0000001e, 0x0000009d, 0x0000379a, 0x0004002b, + 0x0000001e, 0x0000009e, 0x000037b6, 0x0007002c, 0x0000001f, 0x0000009f, 0x0000009b, 0x0000009c, + 0x0000009d, 0x0000009e, 0x0004002b, 0x0000001e, 0x000000a0, 0x0000b967, 0x0004002b, 0x0000001e, + 0x000000a1, 0x0000b950, 0x0004002b, 0x0000001e, 0x000000a2, 0x00003381, 0x0004002b, 0x0000001e, + 0x000000a3, 0x00003371, 0x0007002c, 0x0000001f, 0x000000a4, 0x000000a0, 0x000000a1, 0x000000a2, + 0x000000a3, 0x0007002c, 0x00000020, 0x000000a5, 0x00000095, 0x0000009a, 0x0000009f, 0x000000a4, + 0x0005002c, 0x0000000b, 0x000000a6, 0x00000018, 0x00000065, 0x0004002b, 0x0000001e, 0x000000a7, + 0x000034ef, 0x0004002b, 0x0000001e, 0x000000a8, 0x0000b8c9, 0x0004002b, 0x0000001e, 0x000000a9, + 0x0000b859, 0x0007002c, 0x0000001f, 0x000000aa, 0x00000033, 0x000000a7, 0x000000a8, 0x000000a9, + 0x0004002b, 0x0000001e, 0x000000ab, 0x0000300f, 0x0004002b, 0x0000001e, 0x000000ac, 0x00002f7f, + 0x0004002b, 0x0000001e, 0x000000ad, 0x0000325b, 0x0004002b, 0x0000001e, 0x000000ae, 0x00003271, + 0x0007002c, 0x0000001f, 0x000000af, 0x000000ab, 0x000000ac, 0x000000ad, 0x000000ae, 0x0004002b, + 0x0000001e, 0x000000b0, 0x00003410, 0x0004002b, 0x0000001e, 0x000000b1, 0x00003414, 0x0004002b, + 0x0000001e, 0x000000b2, 0x00003680, 0x0004002b, 0x0000001e, 0x000000b3, 0x00003673, 0x0007002c, + 0x0000001f, 0x000000b4, 0x000000b0, 0x000000b1, 0x000000b2, 0x000000b3, 0x0004002b, 0x0000001e, + 0x000000b5, 0x0000b959, 0x0004002b, 0x0000001e, 0x000000b6, 0x0000b97a, 0x0004002b, 0x0000001e, + 0x000000b7, 0x000034a7, 0x0004002b, 0x0000001e, 0x000000b8, 0x000034a3, 0x0007002c, 0x0000001f, + 0x000000b9, 0x000000b5, 0x000000b6, 0x000000b7, 0x000000b8, 0x0007002c, 0x00000020, 0x000000ba, + 0x000000aa, 0x000000af, 0x000000b4, 0x000000b9, 0x0005002c, 0x0000000b, 0x000000bb, 0x00000065, + 0x00000037, 0x0004002b, 0x0000001e, 0x000000bc, 0x000038b0, 0x0004002b, 0x0000001e, 0x000000bd, + 0x000038c4, 0x0004002b, 0x0000001e, 0x000000be, 0x0000a5bd, 0x0004002b, 0x0000001e, 0x000000bf, + 0x0000a8b4, 0x0007002c, 0x0000001f, 0x000000c0, 0x000000bc, 0x000000bd, 0x000000be, 0x000000bf, + 0x0004002b, 0x0000001e, 0x000000c1, 0x00003703, 0x0004002b, 0x0000001e, 0x000000c2, 0x00003741, + 0x0004002b, 0x0000001e, 0x000000c3, 0x00003736, 0x0004002b, 0x0000001e, 0x000000c4, 0x0000374b, + 0x0007002c, 0x0000001f, 0x000000c5, 0x000000c1, 0x000000c2, 0x000000c3, 0x000000c4, 0x0004002b, + 0x0000001e, 0x000000c6, 0x0000371b, 0x0004002b, 0x0000001e, 0x000000c7, 0x00003727, 0x0004002b, + 0x0000001e, 0x000000c8, 0x0000379b, 0x0004002b, 0x0000001e, 0x000000c9, 0x0000378e, 0x0007002c, + 0x0000001f, 0x000000ca, 0x000000c6, 0x000000c7, 0x000000c8, 0x000000c9, 0x0004002b, 0x0000001e, + 0x000000cb, 0x0000b931, 0x0004002b, 0x0000001e, 0x000000cc, 0x0000b93a, 0x0004002b, 0x0000001e, + 0x000000cd, 0x00003055, 0x0004002b, 0x0000001e, 0x000000ce, 0x0000306f, 0x0007002c, 0x0000001f, + 0x000000cf, 0x000000cb, 0x000000cc, 0x000000cd, 0x000000ce, 0x0007002c, 0x00000020, 0x000000d0, + 0x000000c0, 0x000000c5, 0x000000ca, 0x000000cf, 0x0005002c, 0x0000000b, 0x000000d1, 0x00000065, + 0x00000018, 0x0004002b, 0x0000001e, 0x000000d2, 0x00003511, 0x0004002b, 0x0000001e, 0x000000d3, + 0x00003537, 0x0004002b, 0x0000001e, 0x000000d4, 0x0000ba83, 0x0004002b, 0x0000001e, 0x000000d5, + 0x0000ba64, 0x0007002c, 0x0000001f, 0x000000d6, 0x000000d2, 0x000000d3, 0x000000d4, 0x000000d5, + 0x0004002b, 0x0000001e, 0x000000d7, 0x00002c05, 0x0004002b, 0x0000001e, 0x000000d8, 0x00002c8d, + 0x0004002b, 0x0000001e, 0x000000d9, 0x00003577, 0x0004002b, 0x0000001e, 0x000000da, 0x00003564, + 0x0007002c, 0x0000001f, 0x000000db, 0x000000d7, 0x000000d8, 0x000000d9, 0x000000da, 0x0004002b, + 0x0000001e, 0x000000dc, 0x000034ea, 0x0004002b, 0x0000001e, 0x000000dd, 0x000034f4, 0x0004002b, + 0x0000001e, 0x000000de, 0x00003569, 0x0004002b, 0x0000001e, 0x000000df, 0x00003524, 0x0007002c, + 0x0000001f, 0x000000e0, 0x000000dc, 0x000000dd, 0x000000de, 0x000000df, 0x0004002b, 0x0000001e, + 0x000000e1, 0x0000b9b5, 0x0004002b, 0x0000001e, 0x000000e2, 0x0000b98e, 0x0004002b, 0x0000001e, + 0x000000e3, 0x000034a9, 0x0004002b, 0x0000001e, 0x000000e4, 0x000034d0, 0x0007002c, 0x0000001f, + 0x000000e5, 0x000000e1, 0x000000e2, 0x000000e3, 0x000000e4, 0x0007002c, 0x00000020, 0x000000e6, + 0x000000d6, 0x000000db, 0x000000e0, 0x000000e5, 0x0005002c, 0x0000000b, 0x000000e7, 0x00000065, + 0x00000065, 0x0004002b, 0x0000001e, 0x000000e8, 0x000039f2, 0x0004002b, 0x0000001e, 0x000000e9, + 0x00003aa4, 0x0004002b, 0x0000001e, 0x000000ea, 0x000036f5, 0x0004002b, 0x0000001e, 0x000000eb, + 0x000035f1, 0x0007002c, 0x0000001f, 0x000000ec, 0x000000e8, 0x000000e9, 0x000000ea, 0x000000eb, + 0x0004003b, 0x00000017, 0x00000006, 0x00000000, 0x0004002b, 0x0000000c, 0x000000ed, 0x00000010, + 0x0006002c, 0x0000000d, 0x00000007, 0x000000ed, 0x000000ed, 0x0000001d, 0x00050036, 0x00000008, + 0x00000002, 0x00000000, 0x00000009, 0x000200f8, 0x000000ee, 0x000300f7, 0x000000ef, 0x00000000, + 0x000300fb, 0x0000001c, 0x000000f0, 0x000200f8, 0x000000f0, 0x0004003d, 0x0000000d, 0x000000f1, + 0x00000003, 0x0007004f, 0x0000000f, 0x000000f2, 0x000000f1, 0x000000f1, 0x00000000, 0x00000001, + 0x0004007c, 0x0000000b, 0x000000f3, 0x000000f2, 0x0004003d, 0x00000011, 0x000000f4, 0x00000004, + 0x00040068, 0x0000000b, 0x000000f5, 0x000000f4, 0x000500af, 0x00000014, 0x000000f6, 0x000000f3, + 0x000000f5, 0x0004009a, 0x00000013, 0x000000f7, 0x000000f6, 0x000300f7, 0x000000f8, 0x00000000, + 0x000400fa, 0x000000f7, 0x000000f9, 0x000000f8, 0x000200f8, 0x000000f9, 0x000200f9, 0x000000ef, + 0x000200f8, 0x000000f8, 0x0004003d, 0x00000016, 0x000000fa, 0x00000005, 0x00040064, 0x00000015, + 0x000000fb, 0x000000fa, 0x00050067, 0x0000000b, 0x000000fc, 0x000000fb, 0x00000018, 0x0004007c, + 0x0000000f, 0x000000fd, 0x000000fc, 0x00040070, 0x00000019, 0x000000fe, 0x000000f2, 0x00050081, + 0x00000019, 0x000000ff, 0x000000fe, 0x0000001b, 0x00050051, 0x0000000c, 0x00000100, 0x000000fd, + 0x00000000, 0x00040070, 0x00000010, 0x00000101, 0x00000100, 0x00050051, 0x0000000c, 0x00000102, + 0x000000fd, 0x00000001, 0x00040070, 0x00000010, 0x00000103, 0x00000102, 0x00050050, 0x00000019, + 0x00000104, 0x00000101, 0x00000103, 0x00050088, 0x00000019, 0x00000105, 0x000000ff, 0x00000104, + 0x0004003d, 0x00000016, 0x00000106, 0x00000005, 0x00080058, 0x00000039, 0x00000107, 0x00000106, + 0x00000105, 0x0000000a, 0x00000036, 0x00000038, 0x00040073, 0x0000001f, 0x00000108, 0x00000107, + 0x00050091, 0x0000001f, 0x00000109, 0x00000035, 0x00000108, 0x0004003d, 0x00000016, 0x0000010a, + 0x00000005, 0x00080058, 0x00000039, 0x0000010b, 0x0000010a, 0x00000105, 0x0000000a, 0x00000036, + 0x0000004f, 0x00040073, 0x0000001f, 0x0000010c, 0x0000010b, 0x00050091, 0x0000001f, 0x0000010d, + 0x0000004e, 0x0000010c, 0x00050081, 0x0000001f, 0x0000010e, 0x00000109, 0x0000010d, 0x0004003d, + 0x00000016, 0x0000010f, 0x00000005, 0x00080058, 0x00000039, 0x00000110, 0x0000010f, 0x00000105, + 0x0000000a, 0x00000036, 0x00000066, 0x00040073, 0x0000001f, 0x00000111, 0x00000110, 0x00050091, + 0x0000001f, 0x00000112, 0x00000064, 0x00000111, 0x00050081, 0x0000001f, 0x00000113, 0x0000010e, + 0x00000112, 0x0004003d, 0x00000016, 0x00000114, 0x00000005, 0x00080058, 0x00000039, 0x00000115, + 0x00000114, 0x00000105, 0x0000000a, 0x00000036, 0x0000007c, 0x00040073, 0x0000001f, 0x00000116, + 0x00000115, 0x00050091, 0x0000001f, 0x00000117, 0x0000007b, 0x00000116, 0x00050081, 0x0000001f, + 0x00000118, 0x00000113, 0x00000117, 0x0004003d, 0x00000016, 0x00000119, 0x00000005, 0x00070058, + 0x00000039, 0x0000011a, 0x00000119, 0x00000105, 0x00000002, 0x00000036, 0x00040073, 0x0000001f, + 0x0000011b, 0x0000011a, 0x00050091, 0x0000001f, 0x0000011c, 0x00000091, 0x0000011b, 0x00050081, + 0x0000001f, 0x0000011d, 0x00000118, 0x0000011c, 0x0004003d, 0x00000016, 0x0000011e, 0x00000005, + 0x00080058, 0x00000039, 0x0000011f, 0x0000011e, 0x00000105, 0x0000000a, 0x00000036, 0x000000a6, + 0x00040073, 0x0000001f, 0x00000120, 0x0000011f, 0x00050091, 0x0000001f, 0x00000121, 0x000000a5, + 0x00000120, 0x00050081, 0x0000001f, 0x00000122, 0x0000011d, 0x00000121, 0x0004003d, 0x00000016, + 0x00000123, 0x00000005, 0x00080058, 0x00000039, 0x00000124, 0x00000123, 0x00000105, 0x0000000a, + 0x00000036, 0x000000bb, 0x00040073, 0x0000001f, 0x00000125, 0x00000124, 0x00050091, 0x0000001f, + 0x00000126, 0x000000ba, 0x00000125, 0x00050081, 0x0000001f, 0x00000127, 0x00000122, 0x00000126, + 0x0004003d, 0x00000016, 0x00000128, 0x00000005, 0x00080058, 0x00000039, 0x00000129, 0x00000128, + 0x00000105, 0x0000000a, 0x00000036, 0x000000d1, 0x00040073, 0x0000001f, 0x0000012a, 0x00000129, + 0x00050091, 0x0000001f, 0x0000012b, 0x000000d0, 0x0000012a, 0x00050081, 0x0000001f, 0x0000012c, + 0x00000127, 0x0000012b, 0x0004003d, 0x00000016, 0x0000012d, 0x00000005, 0x00080058, 0x00000039, + 0x0000012e, 0x0000012d, 0x00000105, 0x0000000a, 0x00000036, 0x000000e7, 0x00040073, 0x0000001f, + 0x0000012f, 0x0000012e, 0x00050091, 0x0000001f, 0x00000130, 0x000000e6, 0x0000012f, 0x00050081, + 0x0000001f, 0x00000131, 0x0000012c, 0x00000130, 0x00050081, 0x0000001f, 0x00000132, 0x00000131, + 0x000000ec, 0x0004003d, 0x00000016, 0x00000133, 0x00000006, 0x00070058, 0x00000039, 0x00000134, + 0x00000133, 0x00000105, 0x00000002, 0x00000036, 0x00040073, 0x0000001f, 0x00000135, 0x00000134, + 0x00050081, 0x0000001f, 0x00000136, 0x00000132, 0x00000135, 0x0004003d, 0x00000011, 0x00000137, + 0x00000004, 0x00040073, 0x00000039, 0x00000138, 0x00000136, 0x00040063, 0x00000137, 0x000000f3, + 0x00000138, 0x000200f9, 0x000000ef, 0x000200f8, 0x000000ef, 0x000100fd, 0x00010038, +}; +static const size_t wnfg_29_spv_size = sizeof(wnfg_29_spv); diff --git a/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_51_spv.h b/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_51_spv.h new file mode 100644 index 000000000..a9233acbb --- /dev/null +++ b/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_51_spv.h @@ -0,0 +1,743 @@ +#pragma once +#include +#include + +static const uint32_t wnfg_51_spv[] = { + 0x07230203, 0x00010000, 0x000d000b, 0x000004ad, 0x00000000, 0x00020011, 0x00000001, 0x00020011, + 0x00000009, 0x00020011, 0x00000032, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, + 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0006000f, 0x00000005, 0x00000002, 0x6e69616d, + 0x00000000, 0x00000003, 0x00060010, 0x00000002, 0x00000011, 0x00000010, 0x00000010, 0x00000001, + 0x00040047, 0x00000003, 0x0000000b, 0x0000001c, 0x00030047, 0x00000004, 0x00000019, 0x00040047, + 0x00000004, 0x00000021, 0x00000030, 0x00040047, 0x00000004, 0x00000022, 0x00000000, 0x00040047, + 0x00000005, 0x00000021, 0x00000020, 0x00040047, 0x00000005, 0x00000022, 0x00000000, 0x00040047, + 0x00000006, 0x00000021, 0x00000021, 0x00040047, 0x00000006, 0x00000022, 0x00000000, 0x00030047, + 0x00000007, 0x00000019, 0x00040047, 0x00000007, 0x00000021, 0x00000031, 0x00040047, 0x00000007, + 0x00000022, 0x00000000, 0x00040047, 0x00000008, 0x0000000b, 0x00000019, 0x00020013, 0x00000009, + 0x00030021, 0x0000000a, 0x00000009, 0x00040015, 0x0000000b, 0x00000020, 0x00000001, 0x00040017, + 0x0000000c, 0x0000000b, 0x00000002, 0x00040015, 0x0000000d, 0x00000020, 0x00000000, 0x00040017, + 0x0000000e, 0x0000000d, 0x00000003, 0x00040020, 0x0000000f, 0x00000001, 0x0000000e, 0x0004003b, + 0x0000000f, 0x00000003, 0x00000001, 0x00040017, 0x00000010, 0x0000000d, 0x00000002, 0x00030016, + 0x00000011, 0x00000020, 0x00090019, 0x00000012, 0x00000011, 0x00000001, 0x00000000, 0x00000000, + 0x00000000, 0x00000002, 0x00000004, 0x00040020, 0x00000013, 0x00000000, 0x00000012, 0x0004003b, + 0x00000013, 0x00000004, 0x00000000, 0x00020014, 0x00000014, 0x00040017, 0x00000015, 0x00000014, + 0x00000002, 0x00090019, 0x00000016, 0x00000011, 0x00000001, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000000, 0x0003001b, 0x00000017, 0x00000016, 0x00040020, 0x00000018, 0x00000000, + 0x00000017, 0x0004003b, 0x00000018, 0x00000005, 0x00000000, 0x0004002b, 0x0000000b, 0x00000019, + 0x00000000, 0x0004002b, 0x0000000d, 0x0000001a, 0x00000000, 0x0004002b, 0x0000000d, 0x0000001b, + 0x00000001, 0x00030016, 0x0000001c, 0x00000010, 0x00040017, 0x0000001d, 0x0000001c, 0x00000004, + 0x0004002b, 0x0000000b, 0x0000001e, 0xffffffff, 0x0005002c, 0x0000000c, 0x0000001f, 0x0000001e, + 0x0000001e, 0x0005002c, 0x0000000c, 0x00000020, 0x00000019, 0x00000019, 0x00040017, 0x00000021, + 0x00000011, 0x00000004, 0x0004002b, 0x00000011, 0x00000022, 0x00000000, 0x0007002c, 0x00000021, + 0x00000023, 0x00000022, 0x00000022, 0x00000022, 0x00000022, 0x0005002c, 0x0000000c, 0x00000024, + 0x0000001e, 0x00000019, 0x0004002b, 0x0000000b, 0x00000025, 0x00000001, 0x0005002c, 0x0000000c, + 0x00000026, 0x0000001e, 0x00000025, 0x0005002c, 0x0000000c, 0x00000027, 0x00000019, 0x0000001e, + 0x0005002c, 0x0000000c, 0x00000028, 0x00000019, 0x00000025, 0x0005002c, 0x0000000c, 0x00000029, + 0x00000025, 0x0000001e, 0x0005002c, 0x0000000c, 0x0000002a, 0x00000025, 0x00000019, 0x0005002c, + 0x0000000c, 0x0000002b, 0x00000025, 0x00000025, 0x0004003b, 0x00000018, 0x00000006, 0x00000000, + 0x00040018, 0x0000002c, 0x0000001d, 0x00000004, 0x0004002b, 0x0000001c, 0x0000002d, 0x0000386c, + 0x0004002b, 0x0000001c, 0x0000002e, 0x000032a5, 0x0004002b, 0x0000001c, 0x0000002f, 0x0000b2fd, + 0x0004002b, 0x0000001c, 0x00000030, 0x00002cab, 0x0007002c, 0x0000001d, 0x00000031, 0x0000002d, + 0x0000002e, 0x0000002f, 0x00000030, 0x0004002b, 0x0000001c, 0x00000032, 0x00002c46, 0x0004002b, + 0x0000001c, 0x00000033, 0x000033f2, 0x0004002b, 0x0000001c, 0x00000034, 0x0000b40c, 0x0004002b, + 0x0000001c, 0x00000035, 0x0000abb6, 0x0007002c, 0x0000001d, 0x00000036, 0x00000032, 0x00000033, + 0x00000034, 0x00000035, 0x0004002b, 0x0000001c, 0x00000037, 0x00003325, 0x0004002b, 0x0000001c, + 0x00000038, 0x00003467, 0x0004002b, 0x0000001c, 0x00000039, 0x0000b164, 0x0004002b, 0x0000001c, + 0x0000003a, 0x00009c49, 0x0007002c, 0x0000001d, 0x0000003b, 0x00000037, 0x00000038, 0x00000039, + 0x0000003a, 0x0004002b, 0x0000001c, 0x0000003c, 0x00002ef4, 0x0004002b, 0x0000001c, 0x0000003d, + 0x000030b9, 0x0004002b, 0x0000001c, 0x0000003e, 0x0000abb0, 0x0004002b, 0x0000001c, 0x0000003f, + 0x00002d9d, 0x0007002c, 0x0000001d, 0x00000040, 0x0000003c, 0x0000003d, 0x0000003e, 0x0000003f, + 0x0007002c, 0x0000002c, 0x00000041, 0x00000031, 0x00000036, 0x0000003b, 0x00000040, 0x0004002b, + 0x0000001c, 0x00000042, 0x00002d3c, 0x0004002b, 0x0000001c, 0x00000043, 0x00001974, 0x0004002b, + 0x0000001c, 0x00000044, 0x000026ad, 0x0004002b, 0x0000001c, 0x00000045, 0x0000ace8, 0x0007002c, + 0x0000001d, 0x00000046, 0x00000042, 0x00000043, 0x00000044, 0x00000045, 0x0004002b, 0x0000001c, + 0x00000047, 0x0000a7ff, 0x0004002b, 0x0000001c, 0x00000048, 0x000032a4, 0x0004002b, 0x0000001c, + 0x00000049, 0x0000b158, 0x0004002b, 0x0000001c, 0x0000004a, 0x00002419, 0x0007002c, 0x0000001d, + 0x0000004b, 0x00000047, 0x00000048, 0x00000049, 0x0000004a, 0x0004002b, 0x0000001c, 0x0000004c, + 0x0000268b, 0x0004002b, 0x0000001c, 0x0000004d, 0x00003146, 0x0004002b, 0x0000001c, 0x0000004e, + 0x00002c56, 0x0004002b, 0x0000001c, 0x0000004f, 0x0000ae3a, 0x0007002c, 0x0000001d, 0x00000050, + 0x0000004c, 0x0000004d, 0x0000004e, 0x0000004f, 0x0004002b, 0x0000001c, 0x00000051, 0x00002dc5, + 0x0004002b, 0x0000001c, 0x00000052, 0x00003431, 0x0004002b, 0x0000001c, 0x00000053, 0x0000a152, + 0x0004002b, 0x0000001c, 0x00000054, 0x00003224, 0x0007002c, 0x0000001d, 0x00000055, 0x00000051, + 0x00000052, 0x00000053, 0x00000054, 0x0007002c, 0x0000002c, 0x00000056, 0x00000046, 0x0000004b, + 0x00000050, 0x00000055, 0x0004002b, 0x0000001c, 0x00000057, 0x000034ab, 0x0004002b, 0x0000001c, + 0x00000058, 0x0000acd7, 0x0004002b, 0x0000001c, 0x00000059, 0x0000ab01, 0x0004002b, 0x0000001c, + 0x0000005a, 0x0000ae5e, 0x0007002c, 0x0000001d, 0x0000005b, 0x00000057, 0x00000058, 0x00000059, + 0x0000005a, 0x0004002b, 0x0000001c, 0x0000005c, 0x0000317a, 0x0004002b, 0x0000001c, 0x0000005d, + 0x000034af, 0x0004002b, 0x0000001c, 0x0000005e, 0x0000b48c, 0x0004002b, 0x0000001c, 0x0000005f, + 0x00002dc7, 0x0007002c, 0x0000001d, 0x00000060, 0x0000005c, 0x0000005d, 0x0000005e, 0x0000005f, + 0x0004002b, 0x0000001c, 0x00000061, 0x00003549, 0x0004002b, 0x0000001c, 0x00000062, 0x000034dd, + 0x0004002b, 0x0000001c, 0x00000063, 0x0000aaa8, 0x0004002b, 0x0000001c, 0x00000064, 0x0000a8b7, + 0x0007002c, 0x0000001d, 0x00000065, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x0004002b, + 0x0000001c, 0x00000066, 0x00002dae, 0x0004002b, 0x0000001c, 0x00000067, 0x0000aeb9, 0x0004002b, + 0x0000001c, 0x00000068, 0x0000187b, 0x0004002b, 0x0000001c, 0x00000069, 0x0000316d, 0x0007002c, + 0x0000001d, 0x0000006a, 0x00000066, 0x00000067, 0x00000068, 0x00000069, 0x0007002c, 0x0000002c, + 0x0000006b, 0x0000005b, 0x00000060, 0x00000065, 0x0000006a, 0x0004002b, 0x0000001c, 0x0000006c, + 0x0000329f, 0x0004002b, 0x0000001c, 0x0000006d, 0x00002de8, 0x0004002b, 0x0000001c, 0x0000006e, + 0x0000adec, 0x0004002b, 0x0000001c, 0x0000006f, 0x00002b53, 0x0007002c, 0x0000001d, 0x00000070, + 0x0000006c, 0x0000006d, 0x0000006e, 0x0000006f, 0x0004002b, 0x0000001c, 0x00000071, 0x0000a7eb, + 0x0004002b, 0x0000001c, 0x00000072, 0x000033c9, 0x0004002b, 0x0000001c, 0x00000073, 0x0000ae95, + 0x0004002b, 0x0000001c, 0x00000074, 0x0000b1a3, 0x0007002c, 0x0000001d, 0x00000075, 0x00000071, + 0x00000072, 0x00000073, 0x00000074, 0x0004002b, 0x0000001c, 0x00000076, 0x0000a91f, 0x0004002b, + 0x0000001c, 0x00000077, 0x000033a0, 0x0004002b, 0x0000001c, 0x00000078, 0x0000af43, 0x0004002b, + 0x0000001c, 0x00000079, 0x0000ab8c, 0x0007002c, 0x0000001d, 0x0000007a, 0x00000076, 0x00000077, + 0x00000078, 0x00000079, 0x0004002b, 0x0000001c, 0x0000007b, 0x00002d89, 0x0004002b, 0x0000001c, + 0x0000007c, 0x0000aa9f, 0x0004002b, 0x0000001c, 0x0000007d, 0x0000ac60, 0x0004002b, 0x0000001c, + 0x0000007e, 0x0000b3be, 0x0007002c, 0x0000001d, 0x0000007f, 0x0000007b, 0x0000007c, 0x0000007d, + 0x0000007e, 0x0007002c, 0x0000002c, 0x00000080, 0x00000070, 0x00000075, 0x0000007a, 0x0000007f, + 0x0004002b, 0x0000001c, 0x00000081, 0x0000b3b2, 0x0004002b, 0x0000001c, 0x00000082, 0x0000ad87, + 0x0004002b, 0x0000001c, 0x00000083, 0x0000301d, 0x0004002b, 0x0000001c, 0x00000084, 0x0000a8f4, + 0x0007002c, 0x0000001d, 0x00000085, 0x00000081, 0x00000082, 0x00000083, 0x00000084, 0x0004002b, + 0x0000001c, 0x00000086, 0x0000afc8, 0x0004002b, 0x0000001c, 0x00000087, 0x0000311a, 0x0004002b, + 0x0000001c, 0x00000088, 0x00002aca, 0x0004002b, 0x0000001c, 0x00000089, 0x000032db, 0x0007002c, + 0x0000001d, 0x0000008a, 0x00000086, 0x00000087, 0x00000088, 0x00000089, 0x0004002b, 0x0000001c, + 0x0000008b, 0x0000b2c9, 0x0004002b, 0x0000001c, 0x0000008c, 0x0000311b, 0x0004002b, 0x0000001c, + 0x0000008d, 0x00002ffc, 0x0004002b, 0x0000001c, 0x0000008e, 0x0000adcd, 0x0007002c, 0x0000001d, + 0x0000008f, 0x0000008b, 0x0000008c, 0x0000008d, 0x0000008e, 0x0004002b, 0x0000001c, 0x00000090, + 0x00002cee, 0x0004002b, 0x0000001c, 0x00000091, 0x000032d3, 0x0004002b, 0x0000001c, 0x00000092, + 0x0000b15e, 0x0004002b, 0x0000001c, 0x00000093, 0x0000ad1b, 0x0007002c, 0x0000001d, 0x00000094, + 0x00000090, 0x00000091, 0x00000092, 0x00000093, 0x0007002c, 0x0000002c, 0x00000095, 0x00000085, + 0x0000008a, 0x0000008f, 0x00000094, 0x0004002b, 0x0000001c, 0x00000096, 0x0000a432, 0x0004002b, + 0x0000001c, 0x00000097, 0x0000b09c, 0x0004002b, 0x0000001c, 0x00000098, 0x0000278b, 0x0004002b, + 0x0000001c, 0x00000099, 0x0000aede, 0x0007002c, 0x0000001d, 0x0000009a, 0x00000096, 0x00000097, + 0x00000098, 0x00000099, 0x0004002b, 0x0000001c, 0x0000009b, 0x00002c34, 0x0004002b, 0x0000001c, + 0x0000009c, 0x00003396, 0x0004002b, 0x0000001c, 0x0000009d, 0x0000ad7b, 0x0004002b, 0x0000001c, + 0x0000009e, 0x0000ace7, 0x0007002c, 0x0000001d, 0x0000009f, 0x0000009b, 0x0000009c, 0x0000009d, + 0x0000009e, 0x0004002b, 0x0000001c, 0x000000a0, 0x0000305a, 0x0004002b, 0x0000001c, 0x000000a1, + 0x00003571, 0x0004002b, 0x0000001c, 0x000000a2, 0x0000ad4f, 0x0004002b, 0x0000001c, 0x000000a3, + 0x0000a938, 0x0007002c, 0x0000001d, 0x000000a4, 0x000000a0, 0x000000a1, 0x000000a2, 0x000000a3, + 0x0004002b, 0x0000001c, 0x000000a5, 0x00002ec9, 0x0004002b, 0x0000001c, 0x000000a6, 0x0000ab98, + 0x0004002b, 0x0000001c, 0x000000a7, 0x0000b25b, 0x0004002b, 0x0000001c, 0x000000a8, 0x0000ada2, + 0x0007002c, 0x0000001d, 0x000000a9, 0x000000a5, 0x000000a6, 0x000000a7, 0x000000a8, 0x0007002c, + 0x0000002c, 0x000000aa, 0x0000009a, 0x0000009f, 0x000000a4, 0x000000a9, 0x0004002b, 0x0000001c, + 0x000000ab, 0x00003839, 0x0004002b, 0x0000001c, 0x000000ac, 0x0000269b, 0x0004002b, 0x0000001c, + 0x000000ad, 0x0000b922, 0x0004002b, 0x0000001c, 0x000000ae, 0x000030aa, 0x0007002c, 0x0000001d, + 0x000000af, 0x000000ab, 0x000000ac, 0x000000ad, 0x000000ae, 0x0004002b, 0x0000001c, 0x000000b0, + 0x00003253, 0x0004002b, 0x0000001c, 0x000000b1, 0x000034fe, 0x0004002b, 0x0000001c, 0x000000b2, + 0x0000b5a5, 0x0004002b, 0x0000001c, 0x000000b3, 0x00002e80, 0x0007002c, 0x0000001d, 0x000000b4, + 0x000000b0, 0x000000b1, 0x000000b2, 0x000000b3, 0x0004002b, 0x0000001c, 0x000000b5, 0x00003562, + 0x0004002b, 0x0000001c, 0x000000b6, 0x0000345f, 0x0004002b, 0x0000001c, 0x000000b7, 0x0000b857, + 0x0004002b, 0x0000001c, 0x000000b8, 0x000029c9, 0x0007002c, 0x0000001d, 0x000000b9, 0x000000b5, + 0x000000b6, 0x000000b7, 0x000000b8, 0x0004002b, 0x0000001c, 0x000000ba, 0x00001ffc, 0x0004002b, + 0x0000001c, 0x000000bb, 0x0000b8ea, 0x0004002b, 0x0000001c, 0x000000bc, 0x00003054, 0x0004002b, + 0x0000001c, 0x000000bd, 0x0000a906, 0x0007002c, 0x0000001d, 0x000000be, 0x000000ba, 0x000000bb, + 0x000000bc, 0x000000bd, 0x0007002c, 0x0000002c, 0x000000bf, 0x000000af, 0x000000b4, 0x000000b9, + 0x000000be, 0x0004002b, 0x0000001c, 0x000000c0, 0x00002729, 0x0004002b, 0x0000001c, 0x000000c1, + 0x0000b0bb, 0x0004002b, 0x0000001c, 0x000000c2, 0x0000b6b6, 0x0004002b, 0x0000001c, 0x000000c3, + 0x0000a420, 0x0007002c, 0x0000001d, 0x000000c4, 0x000000c0, 0x000000c1, 0x000000c2, 0x000000c3, + 0x0004002b, 0x0000001c, 0x000000c5, 0x00002c7a, 0x0004002b, 0x0000001c, 0x000000c6, 0x00003337, + 0x0004002b, 0x0000001c, 0x000000c7, 0x0000b11c, 0x0004002b, 0x0000001c, 0x000000c8, 0x00003026, + 0x0007002c, 0x0000001d, 0x000000c9, 0x000000c5, 0x000000c6, 0x000000c7, 0x000000c8, 0x0004002b, + 0x0000001c, 0x000000ca, 0x00003008, 0x0004002b, 0x0000001c, 0x000000cb, 0x000031ab, 0x0004002b, + 0x0000001c, 0x000000cc, 0x0000b397, 0x0004002b, 0x0000001c, 0x000000cd, 0x0000ac52, 0x0007002c, + 0x0000001d, 0x000000ce, 0x000000ca, 0x000000cb, 0x000000cc, 0x000000cd, 0x0004002b, 0x0000001c, + 0x000000cf, 0x00002e1a, 0x0004002b, 0x0000001c, 0x000000d0, 0x0000ac66, 0x0004002b, 0x0000001c, + 0x000000d1, 0x0000a5ad, 0x0004002b, 0x0000001c, 0x000000d2, 0x0000ac92, 0x0007002c, 0x0000001d, + 0x000000d3, 0x000000cf, 0x000000d0, 0x000000d1, 0x000000d2, 0x0007002c, 0x0000002c, 0x000000d4, + 0x000000c4, 0x000000c9, 0x000000ce, 0x000000d3, 0x0004002b, 0x0000001c, 0x000000d5, 0x0000340f, + 0x0004002b, 0x0000001c, 0x000000d6, 0x0000b14c, 0x0004002b, 0x0000001c, 0x000000d7, 0x0000b7bb, + 0x0004002b, 0x0000001c, 0x000000d8, 0x0000ad8e, 0x0007002c, 0x0000001d, 0x000000d9, 0x000000d5, + 0x000000d6, 0x000000d7, 0x000000d8, 0x0004002b, 0x0000001c, 0x000000da, 0x000033f0, 0x0004002b, + 0x0000001c, 0x000000db, 0x0000354b, 0x0004002b, 0x0000001c, 0x000000dc, 0x0000b67b, 0x0004002b, + 0x0000001c, 0x000000dd, 0x00002dbe, 0x0007002c, 0x0000001d, 0x000000de, 0x000000da, 0x000000db, + 0x000000dc, 0x000000dd, 0x0004002b, 0x0000001c, 0x000000df, 0x00003808, 0x0004002b, 0x0000001c, + 0x000000e0, 0x00003678, 0x0004002b, 0x0000001c, 0x000000e1, 0x0000b828, 0x0004002b, 0x0000001c, + 0x000000e2, 0x00002942, 0x0007002c, 0x0000001d, 0x000000e3, 0x000000df, 0x000000e0, 0x000000e1, + 0x000000e2, 0x0004002b, 0x0000001c, 0x000000e4, 0x00002d8a, 0x0004002b, 0x0000001c, 0x000000e5, + 0x0000b581, 0x0004002b, 0x0000001c, 0x000000e6, 0x00009e9e, 0x0004002b, 0x0000001c, 0x000000e7, + 0x000029ad, 0x0007002c, 0x0000001d, 0x000000e8, 0x000000e4, 0x000000e5, 0x000000e6, 0x000000e7, + 0x0007002c, 0x0000002c, 0x000000e9, 0x000000d9, 0x000000de, 0x000000e3, 0x000000e8, 0x0004002b, + 0x0000001c, 0x000000ea, 0x000034ec, 0x0004002b, 0x0000001c, 0x000000eb, 0x0000348f, 0x0004002b, + 0x0000001c, 0x000000ec, 0x00002bd6, 0x0004002b, 0x0000001c, 0x000000ed, 0x0000b794, 0x0007002c, + 0x0000001d, 0x000000ee, 0x000000ea, 0x000000eb, 0x000000ec, 0x000000ed, 0x0004002b, 0x0000001c, + 0x000000ef, 0x0000343c, 0x0004002b, 0x0000001c, 0x000000f0, 0x00003228, 0x0004002b, 0x0000001c, + 0x000000f1, 0x0000b16d, 0x0004002b, 0x0000001c, 0x000000f2, 0x0000302c, 0x0007002c, 0x0000001d, + 0x000000f3, 0x000000ef, 0x000000f0, 0x000000f1, 0x000000f2, 0x0004002b, 0x0000001c, 0x000000f4, + 0x000034f8, 0x0004002b, 0x0000001c, 0x000000f5, 0x0000350e, 0x0004002b, 0x0000001c, 0x000000f6, + 0x0000b105, 0x0004002b, 0x0000001c, 0x000000f7, 0x00002abd, 0x0007002c, 0x0000001d, 0x000000f8, + 0x000000f4, 0x000000f5, 0x000000f6, 0x000000f7, 0x0004002b, 0x0000001c, 0x000000f9, 0x0000b20d, + 0x0004002b, 0x0000001c, 0x000000fa, 0x0000b860, 0x0004002b, 0x0000001c, 0x000000fb, 0x00003233, + 0x0004002b, 0x0000001c, 0x000000fc, 0x0000a927, 0x0007002c, 0x0000001d, 0x000000fd, 0x000000f9, + 0x000000fa, 0x000000fb, 0x000000fc, 0x0007002c, 0x0000002c, 0x000000fe, 0x000000ee, 0x000000f3, + 0x000000f8, 0x000000fd, 0x0004002b, 0x0000001c, 0x000000ff, 0x00002e41, 0x0004002b, 0x0000001c, + 0x00000100, 0x000029b1, 0x0004002b, 0x0000001c, 0x00000101, 0x000030c7, 0x0004002b, 0x0000001c, + 0x00000102, 0x0000b5a7, 0x0007002c, 0x0000001d, 0x00000103, 0x000000ff, 0x00000100, 0x00000101, + 0x00000102, 0x0004002b, 0x0000001c, 0x00000104, 0x000031e0, 0x0004002b, 0x0000001c, 0x00000105, + 0x00002f88, 0x0004002b, 0x0000001c, 0x00000106, 0x0000b290, 0x0004002b, 0x0000001c, 0x00000107, + 0x00002e52, 0x0007002c, 0x0000001d, 0x00000108, 0x00000104, 0x00000105, 0x00000106, 0x00000107, + 0x0004002b, 0x0000001c, 0x00000109, 0x000031b3, 0x0004002b, 0x0000001c, 0x0000010a, 0x00003191, + 0x0004002b, 0x0000001c, 0x0000010b, 0x0000aeaa, 0x0004002b, 0x0000001c, 0x0000010c, 0x0000a8b0, + 0x0007002c, 0x0000001d, 0x0000010d, 0x00000109, 0x0000010a, 0x0000010b, 0x0000010c, 0x0004002b, + 0x0000001c, 0x0000010e, 0x0000ab75, 0x0004002b, 0x0000001c, 0x0000010f, 0x0000b659, 0x0004002b, + 0x0000001c, 0x00000110, 0x00002e83, 0x0004002b, 0x0000001c, 0x00000111, 0x0000b02d, 0x0007002c, + 0x0000001d, 0x00000112, 0x0000010e, 0x0000010f, 0x00000110, 0x00000111, 0x0007002c, 0x0000002c, + 0x00000113, 0x00000103, 0x00000108, 0x0000010d, 0x00000112, 0x0004002b, 0x0000001c, 0x00000114, + 0x000020dc, 0x0004002b, 0x0000001c, 0x00000115, 0x00002881, 0x0004002b, 0x0000001c, 0x00000116, + 0x00002cf7, 0x0004002b, 0x0000001c, 0x00000117, 0x0000b842, 0x0007002c, 0x0000001d, 0x00000118, + 0x00000114, 0x00000115, 0x00000116, 0x00000117, 0x0004002b, 0x0000001c, 0x00000119, 0x00003546, + 0x0004002b, 0x0000001c, 0x0000011a, 0x00002ff4, 0x0004002b, 0x0000001c, 0x0000011b, 0x0000a538, + 0x0004002b, 0x0000001c, 0x0000011c, 0x00002bf3, 0x0007002c, 0x0000001d, 0x0000011d, 0x00000119, + 0x0000011a, 0x0000011b, 0x0000011c, 0x0004002b, 0x0000001c, 0x0000011e, 0x0000332f, 0x0004002b, + 0x0000001c, 0x0000011f, 0x00003075, 0x0004002b, 0x0000001c, 0x00000120, 0x0000277e, 0x0004002b, + 0x0000001c, 0x00000121, 0x000032e9, 0x0007002c, 0x0000001d, 0x00000122, 0x0000011e, 0x0000011f, + 0x00000120, 0x00000121, 0x0004002b, 0x0000001c, 0x00000123, 0x00002ef7, 0x0004002b, 0x0000001c, + 0x00000124, 0x0000b201, 0x0004002b, 0x0000001c, 0x00000125, 0x0000953d, 0x0004002b, 0x0000001c, + 0x00000126, 0x000033d2, 0x0007002c, 0x0000001d, 0x00000127, 0x00000123, 0x00000124, 0x00000125, + 0x00000126, 0x0007002c, 0x0000002c, 0x00000128, 0x00000118, 0x0000011d, 0x00000122, 0x00000127, + 0x0004002b, 0x0000001c, 0x00000129, 0x00003373, 0x0004002b, 0x0000001c, 0x0000012a, 0x0000334e, + 0x0004002b, 0x0000001c, 0x0000012b, 0x00002f82, 0x0004002b, 0x0000001c, 0x0000012c, 0x0000b3d9, + 0x0007002c, 0x0000001d, 0x0000012d, 0x00000129, 0x0000012a, 0x0000012b, 0x0000012c, 0x0004002b, + 0x0000001c, 0x0000012e, 0x000030d1, 0x0004002b, 0x0000001c, 0x0000012f, 0x00003407, 0x0004002b, + 0x0000001c, 0x00000130, 0x0000b293, 0x0004002b, 0x0000001c, 0x00000131, 0x0000a486, 0x0007002c, + 0x0000001d, 0x00000132, 0x0000012e, 0x0000012f, 0x00000130, 0x00000131, 0x0004002b, 0x0000001c, + 0x00000133, 0x000031d5, 0x0004002b, 0x0000001c, 0x00000134, 0x00003493, 0x0004002b, 0x0000001c, + 0x00000135, 0x0000b535, 0x0004002b, 0x0000001c, 0x00000136, 0x00003176, 0x0007002c, 0x0000001d, + 0x00000137, 0x00000133, 0x00000134, 0x00000135, 0x00000136, 0x0004002b, 0x0000001c, 0x00000138, + 0x0000a718, 0x0004002b, 0x0000001c, 0x00000139, 0x0000b478, 0x0004002b, 0x0000001c, 0x0000013a, + 0x0000314f, 0x0004002b, 0x0000001c, 0x0000013b, 0x0000b31d, 0x0007002c, 0x0000001d, 0x0000013c, + 0x00000138, 0x00000139, 0x0000013a, 0x0000013b, 0x0007002c, 0x0000002c, 0x0000013d, 0x0000012d, + 0x00000132, 0x00000137, 0x0000013c, 0x0004002b, 0x0000001c, 0x0000013e, 0x0000a4a0, 0x0004002b, + 0x0000001c, 0x0000013f, 0x0000a7dc, 0x0004002b, 0x0000001c, 0x00000140, 0x00003039, 0x0004002b, + 0x0000001c, 0x00000141, 0x0000b0cd, 0x0007002c, 0x0000001d, 0x00000142, 0x0000013e, 0x0000013f, + 0x00000140, 0x00000141, 0x0004002b, 0x0000001c, 0x00000143, 0x00002aa1, 0x0004002b, 0x0000001c, + 0x00000144, 0x000031f8, 0x0004002b, 0x0000001c, 0x00000145, 0x0000b46b, 0x0004002b, 0x0000001c, + 0x00000146, 0x000035e8, 0x0007002c, 0x0000001d, 0x00000147, 0x00000143, 0x00000144, 0x00000145, + 0x00000146, 0x0004002b, 0x0000001c, 0x00000148, 0x000033c1, 0x0004002b, 0x0000001c, 0x00000149, + 0x0000b4e8, 0x0004002b, 0x0000001c, 0x0000014a, 0x00003197, 0x0007002c, 0x0000001d, 0x0000014b, + 0x000000e4, 0x00000148, 0x00000149, 0x0000014a, 0x0004002b, 0x0000001c, 0x0000014c, 0x000021dc, + 0x0004002b, 0x0000001c, 0x0000014d, 0x0000b21f, 0x0004002b, 0x0000001c, 0x0000014e, 0x000031de, + 0x0004002b, 0x0000001c, 0x0000014f, 0x0000b9fa, 0x0007002c, 0x0000001d, 0x00000150, 0x0000014c, + 0x0000014d, 0x0000014e, 0x0000014f, 0x0007002c, 0x0000002c, 0x00000151, 0x00000142, 0x00000147, + 0x0000014b, 0x00000150, 0x0004002b, 0x0000001c, 0x00000152, 0x00002049, 0x0004002b, 0x0000001c, + 0x00000153, 0x0000a92d, 0x0004002b, 0x0000001c, 0x00000154, 0x00002f20, 0x0004002b, 0x0000001c, + 0x00000155, 0x0000b3a3, 0x0007002c, 0x0000001d, 0x00000156, 0x00000152, 0x00000153, 0x00000154, + 0x00000155, 0x0004002b, 0x0000001c, 0x00000157, 0x00003166, 0x0004002b, 0x0000001c, 0x00000158, + 0x00003258, 0x0004002b, 0x0000001c, 0x00000159, 0x0000b02b, 0x0004002b, 0x0000001c, 0x0000015a, + 0x00003045, 0x0007002c, 0x0000001d, 0x0000015b, 0x00000157, 0x00000158, 0x00000159, 0x0000015a, + 0x0004002b, 0x0000001c, 0x0000015c, 0x00003041, 0x0004002b, 0x0000001c, 0x0000015d, 0x00003479, + 0x0004002b, 0x0000001c, 0x0000015e, 0x0000b2a7, 0x0004002b, 0x0000001c, 0x0000015f, 0x00002fdf, + 0x0007002c, 0x0000001d, 0x00000160, 0x0000015c, 0x0000015d, 0x0000015e, 0x0000015f, 0x0004002b, + 0x0000001c, 0x00000161, 0x0000331b, 0x0004002b, 0x0000001c, 0x00000162, 0x00002c57, 0x0004002b, + 0x0000001c, 0x00000163, 0x00002281, 0x0004002b, 0x0000001c, 0x00000164, 0x0000323a, 0x0007002c, + 0x0000001d, 0x00000165, 0x00000161, 0x00000162, 0x00000163, 0x00000164, 0x0007002c, 0x0000002c, + 0x00000166, 0x00000156, 0x0000015b, 0x00000160, 0x00000165, 0x0004002b, 0x0000001c, 0x00000167, + 0x00003668, 0x0004002b, 0x0000001c, 0x00000168, 0x0000340d, 0x0004002b, 0x0000001c, 0x00000169, + 0x00002b71, 0x0004002b, 0x0000001c, 0x0000016a, 0x0000b86b, 0x0007002c, 0x0000001d, 0x0000016b, + 0x00000167, 0x00000168, 0x00000169, 0x0000016a, 0x0004002b, 0x0000001c, 0x0000016c, 0x00003538, + 0x0004002b, 0x0000001c, 0x0000016d, 0x0000346b, 0x0004002b, 0x0000001c, 0x0000016e, 0x0000b292, + 0x0004002b, 0x0000001c, 0x0000016f, 0x00002b7f, 0x0007002c, 0x0000001d, 0x00000170, 0x0000016c, + 0x0000016d, 0x0000016e, 0x0000016f, 0x0004002b, 0x0000001c, 0x00000171, 0x0000347b, 0x0004002b, + 0x0000001c, 0x00000172, 0x00003478, 0x0004002b, 0x0000001c, 0x00000173, 0x0000b5d4, 0x0004002b, + 0x0000001c, 0x00000174, 0x000036bd, 0x0007002c, 0x0000001d, 0x00000175, 0x00000171, 0x00000172, + 0x00000173, 0x00000174, 0x0004002b, 0x0000001c, 0x00000176, 0x00002d7e, 0x0004002b, 0x0000001c, + 0x00000177, 0x0000aece, 0x0004002b, 0x0000001c, 0x00000178, 0x00002d58, 0x0004002b, 0x0000001c, + 0x00000179, 0x0000b604, 0x0007002c, 0x0000001d, 0x0000017a, 0x00000176, 0x00000177, 0x00000178, + 0x00000179, 0x0007002c, 0x0000002c, 0x0000017b, 0x0000016b, 0x00000170, 0x00000175, 0x0000017a, + 0x0004002b, 0x0000001c, 0x0000017c, 0x000030c6, 0x0004002b, 0x0000001c, 0x0000017d, 0x0000a6e5, + 0x0004002b, 0x0000001c, 0x0000017e, 0x00002cfd, 0x0004002b, 0x0000001c, 0x0000017f, 0x0000b544, + 0x0007002c, 0x0000001d, 0x00000180, 0x0000017c, 0x0000017d, 0x0000017e, 0x0000017f, 0x0004002b, + 0x0000001c, 0x00000181, 0x000031b8, 0x0004002b, 0x0000001c, 0x00000182, 0x000031c2, 0x0004002b, + 0x0000001c, 0x00000183, 0x0000b446, 0x0004002b, 0x0000001c, 0x00000184, 0x00002e1e, 0x0007002c, + 0x0000001d, 0x00000185, 0x00000181, 0x00000182, 0x00000183, 0x00000184, 0x0004002b, 0x0000001c, + 0x00000186, 0x00003174, 0x0004002b, 0x0000001c, 0x00000187, 0x00003343, 0x0004002b, 0x0000001c, + 0x00000188, 0x0000b5bc, 0x0004002b, 0x0000001c, 0x00000189, 0x00003152, 0x0007002c, 0x0000001d, + 0x0000018a, 0x00000186, 0x00000187, 0x00000188, 0x00000189, 0x0004002b, 0x0000001c, 0x0000018b, + 0x000030db, 0x0004002b, 0x0000001c, 0x0000018c, 0x00002114, 0x0004002b, 0x0000001c, 0x0000018d, + 0x00009f84, 0x0004002b, 0x0000001c, 0x0000018e, 0x0000a7df, 0x0007002c, 0x0000001d, 0x0000018f, + 0x0000018b, 0x0000018c, 0x0000018d, 0x0000018e, 0x0007002c, 0x0000002c, 0x00000190, 0x00000180, + 0x00000185, 0x0000018a, 0x0000018f, 0x0004002b, 0x0000001c, 0x00000191, 0x00002eb3, 0x0004002b, + 0x0000001c, 0x00000192, 0x00002ba8, 0x0004002b, 0x0000001c, 0x00000193, 0x00002f08, 0x0004002b, + 0x0000001c, 0x00000194, 0x0000b62e, 0x0007002c, 0x0000001d, 0x00000195, 0x00000191, 0x00000192, + 0x00000193, 0x00000194, 0x0004002b, 0x0000001c, 0x00000196, 0x00003460, 0x0004002b, 0x0000001c, + 0x00000197, 0x00003503, 0x0004002b, 0x0000001c, 0x00000198, 0x0000b126, 0x0004002b, 0x0000001c, + 0x00000199, 0x00002c43, 0x0007002c, 0x0000001d, 0x0000019a, 0x00000196, 0x00000197, 0x00000198, + 0x00000199, 0x0004002b, 0x0000001c, 0x0000019b, 0x00003419, 0x0004002b, 0x0000001c, 0x0000019c, + 0x000035fc, 0x0004002b, 0x0000001c, 0x0000019d, 0x0000b546, 0x0004002b, 0x0000001c, 0x0000019e, + 0x00003336, 0x0007002c, 0x0000001d, 0x0000019f, 0x0000019b, 0x0000019c, 0x0000019d, 0x0000019e, + 0x0004002b, 0x0000001c, 0x000001a0, 0x00003624, 0x0004002b, 0x0000001c, 0x000001a1, 0x00003640, + 0x0004002b, 0x0000001c, 0x000001a2, 0x0000b469, 0x0004002b, 0x0000001c, 0x000001a3, 0x00002fe7, + 0x0007002c, 0x0000001d, 0x000001a4, 0x000001a0, 0x000001a1, 0x000001a2, 0x000001a3, 0x0007002c, + 0x0000002c, 0x000001a5, 0x00000195, 0x0000019a, 0x0000019f, 0x000001a4, 0x0004002b, 0x0000001c, + 0x000001a6, 0x00004003, 0x0004002b, 0x0000001c, 0x000001a7, 0x00003acf, 0x0004002b, 0x0000001c, + 0x000001a8, 0x0000ba9a, 0x0004002b, 0x0000001c, 0x000001a9, 0x0000bce8, 0x0007002c, 0x0000001d, + 0x000001aa, 0x000001a6, 0x000001a7, 0x000001a8, 0x000001a9, 0x0004002b, 0x0000001c, 0x000001ab, + 0x000030df, 0x0004002b, 0x0000001c, 0x000001ac, 0x000036a4, 0x0004002b, 0x0000001c, 0x000001ad, + 0x00003870, 0x0007002c, 0x0000001d, 0x000001ae, 0x000000df, 0x000001ab, 0x000001ac, 0x000001ad, + 0x0004002b, 0x0000001c, 0x000001af, 0x0000b997, 0x0004002b, 0x0000001c, 0x000001b0, 0x00003a46, + 0x0004002b, 0x0000001c, 0x000001b1, 0x0000a7cf, 0x0004002b, 0x0000001c, 0x000001b2, 0x0000b824, + 0x0007002c, 0x0000001d, 0x000001b3, 0x000001af, 0x000001b0, 0x000001b1, 0x000001b2, 0x0004003b, + 0x00000013, 0x00000007, 0x00000000, 0x0004002b, 0x0000001c, 0x000001b4, 0x0000ba16, 0x0004002b, + 0x0000001c, 0x000001b5, 0x0000b2a0, 0x0004002b, 0x0000001c, 0x000001b6, 0x0000244f, 0x0004002b, + 0x0000001c, 0x000001b7, 0x00003408, 0x0007002c, 0x0000001d, 0x000001b8, 0x000001b4, 0x000001b5, + 0x000001b6, 0x000001b7, 0x0004002b, 0x0000001c, 0x000001b9, 0x0000b6bc, 0x0004002b, 0x0000001c, + 0x000001ba, 0x0000ae28, 0x0004002b, 0x0000001c, 0x000001bb, 0x00002c5b, 0x0004002b, 0x0000001c, + 0x000001bc, 0x0000b0d9, 0x0007002c, 0x0000001d, 0x000001bd, 0x000001b9, 0x000001ba, 0x000001bb, + 0x000001bc, 0x0004002b, 0x0000001c, 0x000001be, 0x0000b8cb, 0x0004002b, 0x0000001c, 0x000001bf, + 0x0000a8e7, 0x0004002b, 0x0000001c, 0x000001c0, 0x00002ea4, 0x0004002b, 0x0000001c, 0x000001c1, + 0x00002e59, 0x0007002c, 0x0000001d, 0x000001c2, 0x000001be, 0x000001bf, 0x000001c0, 0x000001c1, + 0x0004002b, 0x0000001c, 0x000001c3, 0x0000b489, 0x0004002b, 0x0000001c, 0x000001c4, 0x00002de2, + 0x0004002b, 0x0000001c, 0x000001c5, 0x00002554, 0x0004002b, 0x0000001c, 0x000001c6, 0x00002f5d, + 0x0007002c, 0x0000001d, 0x000001c7, 0x000001c3, 0x000001c4, 0x000001c5, 0x000001c6, 0x0007002c, + 0x0000002c, 0x000001c8, 0x000001b8, 0x000001bd, 0x000001c2, 0x000001c7, 0x0004002b, 0x0000001c, + 0x000001c9, 0x0000b01c, 0x0004002b, 0x0000001c, 0x000001ca, 0x0000b1e7, 0x0004002b, 0x0000001c, + 0x000001cb, 0x00001e45, 0x0004002b, 0x0000001c, 0x000001cc, 0x0000342a, 0x0007002c, 0x0000001d, + 0x000001cd, 0x000001c9, 0x000001ca, 0x000001cb, 0x000001cc, 0x0004002b, 0x0000001c, 0x000001ce, + 0x0000af76, 0x0004002b, 0x0000001c, 0x000001cf, 0x0000b060, 0x0004002b, 0x0000001c, 0x000001d0, + 0x0000a9a7, 0x0004002b, 0x0000001c, 0x000001d1, 0x0000b0b2, 0x0007002c, 0x0000001d, 0x000001d2, + 0x000001ce, 0x000001cf, 0x000001d0, 0x000001d1, 0x0004002b, 0x0000001c, 0x000001d3, 0x0000b3cf, + 0x0004002b, 0x0000001c, 0x000001d4, 0x0000ad6f, 0x0004002b, 0x0000001c, 0x000001d5, 0x0000a7a4, + 0x0004002b, 0x0000001c, 0x000001d6, 0x00002fbc, 0x0007002c, 0x0000001d, 0x000001d7, 0x000001d3, + 0x000001d4, 0x000001d5, 0x000001d6, 0x0004002b, 0x0000001c, 0x000001d8, 0x0000a429, 0x0004002b, + 0x0000001c, 0x000001d9, 0x0000ac3a, 0x0004002b, 0x0000001c, 0x000001da, 0x00003280, 0x0004002b, + 0x0000001c, 0x000001db, 0x00002d8b, 0x0007002c, 0x0000001d, 0x000001dc, 0x000001d8, 0x000001d9, + 0x000001da, 0x000001db, 0x0007002c, 0x0000002c, 0x000001dd, 0x000001cd, 0x000001d2, 0x000001d7, + 0x000001dc, 0x0004002b, 0x0000001c, 0x000001de, 0x0000aec6, 0x0004002b, 0x0000001c, 0x000001df, + 0x0000b8a2, 0x0004002b, 0x0000001c, 0x000001e0, 0x00002d09, 0x0004002b, 0x0000001c, 0x000001e1, + 0x00002c41, 0x0007002c, 0x0000001d, 0x000001e2, 0x000001de, 0x000001df, 0x000001e0, 0x000001e1, + 0x0004002b, 0x0000001c, 0x000001e3, 0x0000ad72, 0x0004002b, 0x0000001c, 0x000001e4, 0x0000b4c2, + 0x0004002b, 0x0000001c, 0x000001e5, 0x000033a2, 0x0004002b, 0x0000001c, 0x000001e6, 0x0000b4ef, + 0x0007002c, 0x0000001d, 0x000001e7, 0x000001e3, 0x000001e4, 0x000001e5, 0x000001e6, 0x0004002b, + 0x0000001c, 0x000001e8, 0x0000b30f, 0x0004002b, 0x0000001c, 0x000001e9, 0x0000b80e, 0x0004002b, + 0x0000001c, 0x000001ea, 0x000032d7, 0x0004002b, 0x0000001c, 0x000001eb, 0x0000adff, 0x0007002c, + 0x0000001d, 0x000001ec, 0x000001e8, 0x000001e9, 0x000001ea, 0x000001eb, 0x0004002b, 0x0000001c, + 0x000001ed, 0x0000ac93, 0x0004002b, 0x0000001c, 0x000001ee, 0x0000b141, 0x0004002b, 0x0000001c, + 0x000001ef, 0x00002a1b, 0x0004002b, 0x0000001c, 0x000001f0, 0x00003301, 0x0007002c, 0x0000001d, + 0x000001f1, 0x000001ed, 0x000001ee, 0x000001ef, 0x000001f0, 0x0007002c, 0x0000002c, 0x000001f2, + 0x000001e2, 0x000001e7, 0x000001ec, 0x000001f1, 0x0004002b, 0x0000001c, 0x000001f3, 0x0000b667, + 0x0004002b, 0x0000001c, 0x000001f4, 0x000030af, 0x0004002b, 0x0000001c, 0x000001f5, 0x0000a5d4, + 0x0004002b, 0x0000001c, 0x000001f6, 0x00003488, 0x0007002c, 0x0000001d, 0x000001f7, 0x000001f3, + 0x000001f4, 0x000001f5, 0x000001f6, 0x0004002b, 0x0000001c, 0x000001f8, 0x0000af1a, 0x0004002b, + 0x0000001c, 0x000001f9, 0x00002a68, 0x0004002b, 0x0000001c, 0x000001fa, 0x0000acc1, 0x0004002b, + 0x0000001c, 0x000001fb, 0x00002455, 0x0007002c, 0x0000001d, 0x000001fc, 0x000001f8, 0x000001f9, + 0x000001fa, 0x000001fb, 0x0004002b, 0x0000001c, 0x000001fd, 0x0000b2f1, 0x0004002b, 0x0000001c, + 0x000001fe, 0x0000a941, 0x0004002b, 0x0000001c, 0x000001ff, 0x000030fe, 0x0007002c, 0x0000001d, + 0x00000200, 0x000001fd, 0x0000011f, 0x000001fe, 0x000001ff, 0x0004002b, 0x0000001c, 0x00000201, + 0x0000ac95, 0x0004002b, 0x0000001c, 0x00000202, 0x000033ab, 0x0004002b, 0x0000001c, 0x00000203, + 0x0000ac74, 0x0004002b, 0x0000001c, 0x00000204, 0x00002d82, 0x0007002c, 0x0000001d, 0x00000205, + 0x00000201, 0x00000202, 0x00000203, 0x00000204, 0x0007002c, 0x0000002c, 0x00000206, 0x000001f7, + 0x000001fc, 0x00000200, 0x00000205, 0x0004002b, 0x0000001c, 0x00000207, 0x00002c7b, 0x0004002b, + 0x0000001c, 0x00000208, 0x00002f43, 0x0004002b, 0x0000001c, 0x00000209, 0x0000ad1e, 0x0004002b, + 0x0000001c, 0x0000020a, 0x000034c4, 0x0007002c, 0x0000001d, 0x0000020b, 0x00000207, 0x00000208, + 0x00000209, 0x0000020a, 0x0004002b, 0x0000001c, 0x0000020c, 0x0000274a, 0x0004002b, 0x0000001c, + 0x0000020d, 0x0000227b, 0x0004002b, 0x0000001c, 0x0000020e, 0x0000adfe, 0x0004002b, 0x0000001c, + 0x0000020f, 0x00002d16, 0x0007002c, 0x0000001d, 0x00000210, 0x0000020c, 0x0000020d, 0x0000020e, + 0x0000020f, 0x0004002b, 0x0000001c, 0x00000211, 0x00002ad3, 0x0004002b, 0x0000001c, 0x00000212, + 0x00002d38, 0x0004002b, 0x0000001c, 0x00000213, 0x0000b0fe, 0x0004002b, 0x0000001c, 0x00000214, + 0x000030d9, 0x0007002c, 0x0000001d, 0x00000215, 0x00000211, 0x00000212, 0x00000213, 0x00000214, + 0x0004002b, 0x0000001c, 0x00000216, 0x00002edf, 0x0004002b, 0x0000001c, 0x00000217, 0x00002b09, + 0x0004002b, 0x0000001c, 0x00000218, 0x00002c83, 0x0004002b, 0x0000001c, 0x00000219, 0x0000af4b, + 0x0007002c, 0x0000001d, 0x0000021a, 0x00000216, 0x00000217, 0x00000218, 0x00000219, 0x0007002c, + 0x0000002c, 0x0000021b, 0x0000020b, 0x00000210, 0x00000215, 0x0000021a, 0x0004002b, 0x0000001c, + 0x0000021c, 0x00009bc1, 0x0004002b, 0x0000001c, 0x0000021d, 0x0000b0d1, 0x0004002b, 0x0000001c, + 0x0000021e, 0x0000aaa0, 0x0004002b, 0x0000001c, 0x0000021f, 0x00002f1c, 0x0007002c, 0x0000001d, + 0x00000220, 0x0000021c, 0x0000021d, 0x0000021e, 0x0000021f, 0x0004002b, 0x0000001c, 0x00000221, + 0x0000a4e9, 0x0004002b, 0x0000001c, 0x00000222, 0x0000b033, 0x0004002b, 0x0000001c, 0x00000223, + 0x0000a836, 0x0004002b, 0x0000001c, 0x00000224, 0x0000a80a, 0x0007002c, 0x0000001d, 0x00000225, + 0x00000221, 0x00000222, 0x00000223, 0x00000224, 0x0004002b, 0x0000001c, 0x00000226, 0x00009fd0, + 0x0004002b, 0x0000001c, 0x00000227, 0x0000b0fa, 0x0004002b, 0x0000001c, 0x00000228, 0x0000a7d3, + 0x0007002c, 0x0000001d, 0x00000229, 0x00000226, 0x00000227, 0x00000090, 0x00000228, 0x0004002b, + 0x0000001c, 0x0000022a, 0x00009d28, 0x0004002b, 0x0000001c, 0x0000022b, 0x00002d7c, 0x0004002b, + 0x0000001c, 0x0000022c, 0x0000ad88, 0x0004002b, 0x0000001c, 0x0000022d, 0x00001d75, 0x0007002c, + 0x0000001d, 0x0000022e, 0x0000022a, 0x0000022b, 0x0000022c, 0x0000022d, 0x0007002c, 0x0000002c, + 0x0000022f, 0x00000220, 0x00000225, 0x00000229, 0x0000022e, 0x0004002b, 0x0000001c, 0x00000230, + 0x0000b7b1, 0x0004002b, 0x0000001c, 0x00000231, 0x00003476, 0x0004002b, 0x0000001c, 0x00000232, + 0x0000285b, 0x0004002b, 0x0000001c, 0x00000233, 0x00003013, 0x0007002c, 0x0000001d, 0x00000234, + 0x00000230, 0x00000231, 0x00000232, 0x00000233, 0x0004002b, 0x0000001c, 0x00000235, 0x0000b2cd, + 0x0004002b, 0x0000001c, 0x00000236, 0x00003252, 0x0004002b, 0x0000001c, 0x00000237, 0x00003235, + 0x0004002b, 0x0000001c, 0x00000238, 0x0000b28c, 0x0007002c, 0x0000001d, 0x00000239, 0x00000235, + 0x00000236, 0x00000237, 0x00000238, 0x0004002b, 0x0000001c, 0x0000023a, 0x0000b662, 0x0004002b, + 0x0000001c, 0x0000023b, 0x00003378, 0x0004002b, 0x0000001c, 0x0000023c, 0x000030a3, 0x0004002b, + 0x0000001c, 0x0000023d, 0x000020a5, 0x0007002c, 0x0000001d, 0x0000023e, 0x0000023a, 0x0000023b, + 0x0000023c, 0x0000023d, 0x0004002b, 0x0000001c, 0x0000023f, 0x0000ae94, 0x0004002b, 0x0000001c, + 0x00000240, 0x00002cde, 0x0004002b, 0x0000001c, 0x00000241, 0x0000b25d, 0x0004002b, 0x0000001c, + 0x00000242, 0x000034cf, 0x0007002c, 0x0000001d, 0x00000243, 0x0000023f, 0x00000240, 0x00000241, + 0x00000242, 0x0007002c, 0x0000002c, 0x00000244, 0x00000234, 0x00000239, 0x0000023e, 0x00000243, + 0x0004002b, 0x0000001c, 0x00000245, 0x00002a11, 0x0004002b, 0x0000001c, 0x00000246, 0x00003093, + 0x0004002b, 0x0000001c, 0x00000247, 0x0000aa58, 0x0004002b, 0x0000001c, 0x00000248, 0x00003199, + 0x0007002c, 0x0000001d, 0x00000249, 0x00000245, 0x00000246, 0x00000247, 0x00000248, 0x0004002b, + 0x0000001c, 0x0000024a, 0x0000aec8, 0x0004002b, 0x0000001c, 0x0000024b, 0x00002a9a, 0x0004002b, + 0x0000001c, 0x0000024c, 0x000021d2, 0x0004002b, 0x0000001c, 0x0000024d, 0x0000af2a, 0x0007002c, + 0x0000001d, 0x0000024e, 0x0000024a, 0x0000024b, 0x0000024c, 0x0000024d, 0x0004002b, 0x0000001c, + 0x0000024f, 0x0000a67e, 0x0004002b, 0x0000001c, 0x00000250, 0x00002aec, 0x0004002b, 0x0000001c, + 0x00000251, 0x00002123, 0x0004002b, 0x0000001c, 0x00000252, 0x0000290f, 0x0007002c, 0x0000001d, + 0x00000253, 0x0000024f, 0x00000250, 0x00000251, 0x00000252, 0x0004002b, 0x0000001c, 0x00000254, + 0x00002c13, 0x0004002b, 0x0000001c, 0x00000255, 0x0000b024, 0x0004002b, 0x0000001c, 0x00000256, + 0x0000ae04, 0x0004002b, 0x0000001c, 0x00000257, 0x00003102, 0x0007002c, 0x0000001d, 0x00000258, + 0x00000254, 0x00000255, 0x00000256, 0x00000257, 0x0007002c, 0x0000002c, 0x00000259, 0x00000249, + 0x0000024e, 0x00000253, 0x00000258, 0x0004002b, 0x0000001c, 0x0000025a, 0x00002eb7, 0x0004002b, + 0x0000001c, 0x0000025b, 0x0000af91, 0x0004002b, 0x0000001c, 0x0000025c, 0x0000aa75, 0x0004002b, + 0x0000001c, 0x0000025d, 0x0000a469, 0x0007002c, 0x0000001d, 0x0000025e, 0x0000025a, 0x0000025b, + 0x0000025c, 0x0000025d, 0x0004002b, 0x0000001c, 0x0000025f, 0x0000a535, 0x0004002b, 0x0000001c, + 0x00000260, 0x0000ac4a, 0x0004002b, 0x0000001c, 0x00000261, 0x0000337f, 0x0004002b, 0x0000001c, + 0x00000262, 0x0000b104, 0x0007002c, 0x0000001d, 0x00000263, 0x0000025f, 0x00000260, 0x00000261, + 0x00000262, 0x0004002b, 0x0000001c, 0x00000264, 0x00001fce, 0x0004002b, 0x0000001c, 0x00000265, + 0x0000b2f4, 0x0004002b, 0x0000001c, 0x00000266, 0x00003383, 0x0004002b, 0x0000001c, 0x00000267, + 0x0000b1e4, 0x0007002c, 0x0000001d, 0x00000268, 0x00000264, 0x00000265, 0x00000266, 0x00000267, + 0x0004002b, 0x0000001c, 0x00000269, 0x0000a907, 0x0004002b, 0x0000001c, 0x0000026a, 0x000023c4, + 0x0004002b, 0x0000001c, 0x0000026b, 0x0000b302, 0x0004002b, 0x0000001c, 0x0000026c, 0x000033cf, + 0x0007002c, 0x0000001d, 0x0000026d, 0x00000269, 0x0000026a, 0x0000026b, 0x0000026c, 0x0007002c, + 0x0000002c, 0x0000026e, 0x0000025e, 0x00000263, 0x00000268, 0x0000026d, 0x0004002b, 0x0000001c, + 0x0000026f, 0x0000ac98, 0x0004002b, 0x0000001c, 0x00000270, 0x000028c9, 0x0004002b, 0x0000001c, + 0x00000271, 0x0000b578, 0x0004002b, 0x0000001c, 0x00000272, 0x0000a8bc, 0x0007002c, 0x0000001d, + 0x00000273, 0x0000026f, 0x00000270, 0x00000271, 0x00000272, 0x0004002b, 0x0000001c, 0x00000274, + 0x0000b5d8, 0x0004002b, 0x0000001c, 0x00000275, 0x0000aaf8, 0x0004002b, 0x0000001c, 0x00000276, + 0x00002f9f, 0x0004002b, 0x0000001c, 0x00000277, 0x0000b43f, 0x0007002c, 0x0000001d, 0x00000278, + 0x00000274, 0x00000275, 0x00000276, 0x00000277, 0x0004002b, 0x0000001c, 0x00000279, 0x0000b698, + 0x0004002b, 0x0000001c, 0x0000027a, 0x00003113, 0x0004002b, 0x0000001c, 0x0000027b, 0x0000b4b0, + 0x0007002c, 0x0000001d, 0x0000027c, 0x00000279, 0x0000024d, 0x0000027a, 0x0000027b, 0x0004002b, + 0x0000001c, 0x0000027d, 0x0000221f, 0x0004002b, 0x0000001c, 0x0000027e, 0x00002e3f, 0x0004002b, + 0x0000001c, 0x0000027f, 0x0000b19e, 0x0004002b, 0x0000001c, 0x00000280, 0x0000344e, 0x0007002c, + 0x0000001d, 0x00000281, 0x0000027d, 0x0000027e, 0x0000027f, 0x00000280, 0x0007002c, 0x0000002c, + 0x00000282, 0x00000273, 0x00000278, 0x0000027c, 0x00000281, 0x0004002b, 0x0000001c, 0x00000283, + 0x00002e33, 0x0004002b, 0x0000001c, 0x00000284, 0x0000aa02, 0x0004002b, 0x0000001c, 0x00000285, + 0x0000b037, 0x0004002b, 0x0000001c, 0x00000286, 0x00002e10, 0x0007002c, 0x0000001d, 0x00000287, + 0x00000283, 0x00000284, 0x00000285, 0x00000286, 0x0004002b, 0x0000001c, 0x00000288, 0x0000ad9a, + 0x0004002b, 0x0000001c, 0x00000289, 0x0000b1d2, 0x0004002b, 0x0000001c, 0x0000028a, 0x00002f3e, + 0x0004002b, 0x0000001c, 0x0000028b, 0x00001611, 0x0007002c, 0x0000001d, 0x0000028c, 0x00000288, + 0x00000289, 0x0000028a, 0x0000028b, 0x0004002b, 0x0000001c, 0x0000028d, 0x0000afef, 0x0004002b, + 0x0000001c, 0x0000028e, 0x0000b08b, 0x0004002b, 0x0000001c, 0x0000028f, 0x0000313e, 0x0004002b, + 0x0000001c, 0x00000290, 0x0000a23f, 0x0007002c, 0x0000001d, 0x00000291, 0x0000028d, 0x0000028e, + 0x0000028f, 0x00000290, 0x0004002b, 0x0000001c, 0x00000292, 0x00009de3, 0x0004002b, 0x0000001c, + 0x00000293, 0x00002fe0, 0x0004002b, 0x0000001c, 0x00000294, 0x0000b0b9, 0x0004002b, 0x0000001c, + 0x00000295, 0x00003563, 0x0007002c, 0x0000001d, 0x00000296, 0x00000292, 0x00000293, 0x00000294, + 0x00000295, 0x0007002c, 0x0000002c, 0x00000297, 0x00000287, 0x0000028c, 0x00000291, 0x00000296, + 0x0004002b, 0x0000001c, 0x00000298, 0x0000ac65, 0x0004002b, 0x0000001c, 0x00000299, 0x00003028, + 0x0004002b, 0x0000001c, 0x0000029a, 0x0000b6f7, 0x0004002b, 0x0000001c, 0x0000029b, 0x000030e0, + 0x0007002c, 0x0000001d, 0x0000029c, 0x00000298, 0x00000299, 0x0000029a, 0x0000029b, 0x0004002b, + 0x0000001c, 0x0000029d, 0x0000ad6c, 0x0004002b, 0x0000001c, 0x0000029e, 0x0000b5ff, 0x0004002b, + 0x0000001c, 0x0000029f, 0x0000b483, 0x0007002c, 0x0000001d, 0x000002a0, 0x0000029d, 0x0000029e, + 0x00000136, 0x0000029f, 0x0004002b, 0x0000001c, 0x000002a1, 0x0000ac1f, 0x0004002b, 0x0000001c, + 0x000002a2, 0x0000b801, 0x0004002b, 0x0000001c, 0x000002a3, 0x00003465, 0x0004002b, 0x0000001c, + 0x000002a4, 0x0000b521, 0x0007002c, 0x0000001d, 0x000002a5, 0x000002a1, 0x000002a2, 0x000002a3, + 0x000002a4, 0x0004002b, 0x0000001c, 0x000002a6, 0x0000b41d, 0x0004002b, 0x0000001c, 0x000002a7, + 0x0000b32a, 0x0004002b, 0x0000001c, 0x000002a8, 0x00002c1a, 0x0007002c, 0x0000001d, 0x000002a9, + 0x000002a6, 0x00000105, 0x000002a7, 0x000002a8, 0x0007002c, 0x0000002c, 0x000002aa, 0x0000029c, + 0x000002a0, 0x000002a5, 0x000002a9, 0x0004002b, 0x0000001c, 0x000002ab, 0x0000aab0, 0x0004002b, + 0x0000001c, 0x000002ac, 0x00002b18, 0x0004002b, 0x0000001c, 0x000002ad, 0x0000b3e6, 0x0004002b, + 0x0000001c, 0x000002ae, 0x0000124b, 0x0007002c, 0x0000001d, 0x000002af, 0x000002ab, 0x000002ac, + 0x000002ad, 0x000002ae, 0x0004002b, 0x0000001c, 0x000002b0, 0x0000b3c2, 0x0004002b, 0x0000001c, + 0x000002b1, 0x00002b08, 0x0004002b, 0x0000001c, 0x000002b2, 0x00002f8d, 0x0004002b, 0x0000001c, + 0x000002b3, 0x0000afbf, 0x0007002c, 0x0000001d, 0x000002b4, 0x000002b0, 0x000002b1, 0x000002b2, + 0x000002b3, 0x0004002b, 0x0000001c, 0x000002b5, 0x0000b442, 0x0004002b, 0x0000001c, 0x000002b6, + 0x000020e2, 0x0004002b, 0x0000001c, 0x000002b7, 0x000030bf, 0x0004002b, 0x0000001c, 0x000002b8, + 0x0000ab09, 0x0007002c, 0x0000001d, 0x000002b9, 0x000002b5, 0x000002b6, 0x000002b7, 0x000002b8, + 0x0004002b, 0x0000001c, 0x000002ba, 0x0000af21, 0x0004002b, 0x0000001c, 0x000002bb, 0x0000a5c7, + 0x0004002b, 0x0000001c, 0x000002bc, 0x000031b4, 0x0007002c, 0x0000001d, 0x000002bd, 0x000002ba, + 0x000002bb, 0x000001d1, 0x000002bc, 0x0007002c, 0x0000002c, 0x000002be, 0x000002af, 0x000002b4, + 0x000002b9, 0x000002bd, 0x0004002b, 0x0000001c, 0x000002bf, 0x00002ce3, 0x0004002b, 0x0000001c, + 0x000002c0, 0x0000af78, 0x0004002b, 0x0000001c, 0x000002c1, 0x0000abb2, 0x0004002b, 0x0000001c, + 0x000002c2, 0x00002e05, 0x0007002c, 0x0000001d, 0x000002c3, 0x000002bf, 0x000002c0, 0x000002c1, + 0x000002c2, 0x0004002b, 0x0000001c, 0x000002c4, 0x0000a9f2, 0x0004002b, 0x0000001c, 0x000002c5, + 0x0000ac07, 0x0004002b, 0x0000001c, 0x000002c6, 0x00003173, 0x0007002c, 0x0000001d, 0x000002c7, + 0x000002c4, 0x000002c5, 0x00000144, 0x000002c6, 0x0004002b, 0x0000001c, 0x000002c8, 0x0000accd, + 0x0004002b, 0x0000001c, 0x000002c9, 0x00002347, 0x0004002b, 0x0000001c, 0x000002ca, 0x0000343b, + 0x0007002c, 0x0000001d, 0x000002cb, 0x000002c8, 0x000002c9, 0x000001ff, 0x000002ca, 0x0004002b, + 0x0000001c, 0x000002cc, 0x0000a954, 0x0004002b, 0x0000001c, 0x000002cd, 0x0000adaa, 0x0004002b, + 0x0000001c, 0x000002ce, 0x0000ae4a, 0x0007002c, 0x0000001d, 0x000002cf, 0x000002cc, 0x000002cd, + 0x000002ce, 0x0000026c, 0x0007002c, 0x0000002c, 0x000002d0, 0x000002c3, 0x000002c7, 0x000002cb, + 0x000002cf, 0x0004002b, 0x0000001c, 0x000002d1, 0x00002495, 0x0004002b, 0x0000001c, 0x000002d2, + 0x00001a44, 0x0004002b, 0x0000001c, 0x000002d3, 0x0000b4a2, 0x0004002b, 0x0000001c, 0x000002d4, + 0x00002c9d, 0x0007002c, 0x0000001d, 0x000002d5, 0x000002d1, 0x000002d2, 0x000002d3, 0x000002d4, + 0x0004002b, 0x0000001c, 0x000002d6, 0x000094d5, 0x0004002b, 0x0000001c, 0x000002d7, 0x0000b21c, + 0x0004002b, 0x0000001c, 0x000002d8, 0x00003080, 0x0004002b, 0x0000001c, 0x000002d9, 0x0000b0aa, + 0x0007002c, 0x0000001d, 0x000002da, 0x000002d6, 0x000002d7, 0x000002d8, 0x000002d9, 0x0004002b, + 0x0000001c, 0x000002db, 0x00002205, 0x0004002b, 0x0000001c, 0x000002dc, 0x0000b391, 0x0004002b, + 0x0000001c, 0x000002dd, 0x00003171, 0x0004002b, 0x0000001c, 0x000002de, 0x0000af7e, 0x0007002c, + 0x0000001d, 0x000002df, 0x000002db, 0x000002dc, 0x000002dd, 0x000002de, 0x0004002b, 0x0000001c, + 0x000002e0, 0x0000b0bc, 0x0004002b, 0x0000001c, 0x000002e1, 0x0000a9ff, 0x0004002b, 0x0000001c, + 0x000002e2, 0x0000af3d, 0x0007002c, 0x0000001d, 0x000002e3, 0x000002e0, 0x000002e1, 0x000002e2, + 0x000001d6, 0x0007002c, 0x0000002c, 0x000002e4, 0x000002d5, 0x000002da, 0x000002df, 0x000002e3, + 0x0004002b, 0x0000001c, 0x000002e5, 0x0000ae85, 0x0004002b, 0x0000001c, 0x000002e6, 0x000033aa, + 0x0004002b, 0x0000001c, 0x000002e7, 0x0000b5b4, 0x0004002b, 0x0000001c, 0x000002e8, 0x0000ac29, + 0x0007002c, 0x0000001d, 0x000002e9, 0x000002e5, 0x000002e6, 0x000002e7, 0x000002e8, 0x0004002b, + 0x0000001c, 0x000002ea, 0x0000b4b3, 0x0004002b, 0x0000001c, 0x000002eb, 0x000032fc, 0x0004002b, + 0x0000001c, 0x000002ec, 0x0000322a, 0x0004002b, 0x0000001c, 0x000002ed, 0x0000b5a1, 0x0007002c, + 0x0000001d, 0x000002ee, 0x000002ea, 0x000002eb, 0x000002ec, 0x000002ed, 0x0004002b, 0x0000001c, + 0x000002ef, 0x000031d0, 0x0004002b, 0x0000001c, 0x000002f0, 0x00003449, 0x0004002b, 0x0000001c, + 0x000002f1, 0x0000b55a, 0x0007002c, 0x0000001d, 0x000002f2, 0x0000029e, 0x000002ef, 0x000002f0, + 0x000002f1, 0x0004002b, 0x0000001c, 0x000002f3, 0x0000b3b6, 0x0004002b, 0x0000001c, 0x000002f4, + 0x00002b77, 0x0004002b, 0x0000001c, 0x000002f5, 0x0000b1d5, 0x0004002b, 0x0000001c, 0x000002f6, + 0x00002c6e, 0x0007002c, 0x0000001d, 0x000002f7, 0x000002f3, 0x000002f4, 0x000002f5, 0x000002f6, + 0x0007002c, 0x0000002c, 0x000002f8, 0x000002e9, 0x000002ee, 0x000002f2, 0x000002f7, 0x0004002b, + 0x0000001c, 0x000002f9, 0x0000ad19, 0x0004002b, 0x0000001c, 0x000002fa, 0x0000ae17, 0x0004002b, + 0x0000001c, 0x000002fb, 0x000028fd, 0x0007002c, 0x0000001d, 0x000002fc, 0x000000ca, 0x000002f9, + 0x000002fa, 0x000002fb, 0x0004002b, 0x0000001c, 0x000002fd, 0x0000af9a, 0x0004002b, 0x0000001c, + 0x000002fe, 0x00001961, 0x0004002b, 0x0000001c, 0x000002ff, 0x0000af6d, 0x0007002c, 0x0000001d, + 0x00000300, 0x000002fd, 0x000002fe, 0x0000011f, 0x000002ff, 0x0004002b, 0x0000001c, 0x00000301, + 0x0000b048, 0x0004002b, 0x0000001c, 0x00000302, 0x00002b4a, 0x0004002b, 0x0000001c, 0x00000303, + 0x000032bd, 0x0004002b, 0x0000001c, 0x00000304, 0x0000af02, 0x0007002c, 0x0000001d, 0x00000305, + 0x00000301, 0x00000302, 0x00000303, 0x00000304, 0x0004002b, 0x0000001c, 0x00000306, 0x0000a9d8, + 0x0004002b, 0x0000001c, 0x00000307, 0x0000ad34, 0x0004002b, 0x0000001c, 0x00000308, 0x00002f84, + 0x0004002b, 0x0000001c, 0x00000309, 0x000030e2, 0x0007002c, 0x0000001d, 0x0000030a, 0x00000306, + 0x00000307, 0x00000308, 0x00000309, 0x0007002c, 0x0000002c, 0x0000030b, 0x000002fc, 0x00000300, + 0x00000305, 0x0000030a, 0x0004002b, 0x0000001c, 0x0000030c, 0x0000a4ec, 0x0004002b, 0x0000001c, + 0x0000030d, 0x0000285d, 0x0004002b, 0x0000001c, 0x0000030e, 0x0000b563, 0x0004002b, 0x0000001c, + 0x0000030f, 0x0000a153, 0x0007002c, 0x0000001d, 0x00000310, 0x0000030c, 0x0000030d, 0x0000030e, + 0x0000030f, 0x0004002b, 0x0000001c, 0x00000311, 0x0000aedf, 0x0004002b, 0x0000001c, 0x00000312, + 0x0000aead, 0x0004002b, 0x0000001c, 0x00000313, 0x0000320e, 0x0004002b, 0x0000001c, 0x00000314, + 0x0000b6e5, 0x0007002c, 0x0000001d, 0x00000315, 0x00000311, 0x00000312, 0x00000313, 0x00000314, + 0x0004002b, 0x0000001c, 0x00000316, 0x0000ab9e, 0x0004002b, 0x0000001c, 0x00000317, 0x0000b2c0, + 0x0004002b, 0x0000001c, 0x00000318, 0x00003395, 0x0004002b, 0x0000001c, 0x00000319, 0x0000b765, + 0x0007002c, 0x0000001d, 0x0000031a, 0x00000316, 0x00000317, 0x00000318, 0x00000319, 0x0004002b, + 0x0000001c, 0x0000031b, 0x0000b014, 0x0004002b, 0x0000001c, 0x0000031c, 0x0000afb1, 0x0004002b, + 0x0000001c, 0x0000031d, 0x0000a8fe, 0x0004002b, 0x0000001c, 0x0000031e, 0x0000aebc, 0x0007002c, + 0x0000001d, 0x0000031f, 0x0000031b, 0x0000031c, 0x0000031d, 0x0000031e, 0x0007002c, 0x0000002c, + 0x00000320, 0x00000310, 0x00000315, 0x0000031a, 0x0000031f, 0x0004002b, 0x0000001c, 0x00000321, + 0x0000bdee, 0x0004002b, 0x0000001c, 0x00000322, 0x0000b44a, 0x0004002b, 0x0000001c, 0x00000323, + 0x0000b9d0, 0x0004002b, 0x0000001c, 0x00000324, 0x00003896, 0x0007002c, 0x0000001d, 0x00000325, + 0x00000321, 0x00000322, 0x00000323, 0x00000324, 0x0004002b, 0x0000001c, 0x00000326, 0x000033a8, + 0x0004002b, 0x0000001c, 0x00000327, 0x00003893, 0x0004002b, 0x0000001c, 0x00000328, 0x00003813, + 0x0004002b, 0x0000001c, 0x00000329, 0x00003921, 0x0007002c, 0x0000001d, 0x0000032a, 0x00000326, + 0x00000327, 0x00000328, 0x00000329, 0x0004002b, 0x0000001c, 0x0000032b, 0x00003a99, 0x0004002b, + 0x0000001c, 0x0000032c, 0x00002f2f, 0x0004002b, 0x0000001c, 0x0000032d, 0x0000b952, 0x0004002b, + 0x0000001c, 0x0000032e, 0x0000316a, 0x0007002c, 0x0000001d, 0x0000032f, 0x0000032b, 0x0000032c, + 0x0000032d, 0x0000032e, 0x0004002b, 0x0000000d, 0x00000330, 0x00000010, 0x0006002c, 0x0000000e, + 0x00000008, 0x00000330, 0x00000330, 0x0000001b, 0x00050036, 0x00000009, 0x00000002, 0x00000000, + 0x0000000a, 0x000200f8, 0x00000331, 0x000300f7, 0x00000332, 0x00000000, 0x000300fb, 0x0000001a, + 0x00000333, 0x000200f8, 0x00000333, 0x0004003d, 0x0000000e, 0x00000334, 0x00000003, 0x0007004f, + 0x00000010, 0x00000335, 0x00000334, 0x00000334, 0x00000000, 0x00000001, 0x0004007c, 0x0000000c, + 0x00000336, 0x00000335, 0x0004003d, 0x00000012, 0x00000337, 0x00000004, 0x00040068, 0x0000000c, + 0x00000338, 0x00000337, 0x000500af, 0x00000015, 0x00000339, 0x00000336, 0x00000338, 0x0004009a, + 0x00000014, 0x0000033a, 0x00000339, 0x000300f7, 0x0000033b, 0x00000000, 0x000400fa, 0x0000033a, + 0x0000033c, 0x0000033b, 0x000200f8, 0x0000033c, 0x000200f9, 0x00000332, 0x000200f8, 0x0000033b, + 0x00050080, 0x0000000c, 0x0000033d, 0x00000336, 0x0000001f, 0x000500af, 0x00000015, 0x0000033e, + 0x0000033d, 0x00000020, 0x0004009b, 0x00000014, 0x0000033f, 0x0000033e, 0x000300f7, 0x00000340, + 0x00000000, 0x000400fa, 0x0000033f, 0x00000341, 0x00000340, 0x000200f8, 0x00000341, 0x0004003d, + 0x00000017, 0x00000342, 0x00000005, 0x00040064, 0x00000016, 0x00000343, 0x00000342, 0x00050067, + 0x0000000c, 0x00000344, 0x00000343, 0x00000019, 0x000500b1, 0x00000015, 0x00000345, 0x0000033d, + 0x00000344, 0x0004009b, 0x00000014, 0x00000346, 0x00000345, 0x000200f9, 0x00000340, 0x000200f8, + 0x00000340, 0x000700f5, 0x00000014, 0x00000347, 0x0000033f, 0x0000033b, 0x00000346, 0x00000341, + 0x000300f7, 0x00000348, 0x00000000, 0x000400fa, 0x00000347, 0x00000349, 0x0000034a, 0x000200f8, + 0x00000349, 0x0004003d, 0x00000017, 0x0000034b, 0x00000005, 0x00040064, 0x00000016, 0x0000034c, + 0x0000034b, 0x0007005f, 0x00000021, 0x0000034d, 0x0000034c, 0x0000033d, 0x00000002, 0x00000019, + 0x000200f9, 0x00000348, 0x000200f8, 0x0000034a, 0x000200f9, 0x00000348, 0x000200f8, 0x00000348, + 0x000700f5, 0x00000021, 0x0000034e, 0x0000034d, 0x00000349, 0x00000023, 0x0000034a, 0x00040073, + 0x0000001d, 0x0000034f, 0x0000034e, 0x00050080, 0x0000000c, 0x00000350, 0x00000336, 0x00000024, + 0x000500af, 0x00000015, 0x00000351, 0x00000350, 0x00000020, 0x0004009b, 0x00000014, 0x00000352, + 0x00000351, 0x000300f7, 0x00000353, 0x00000000, 0x000400fa, 0x00000352, 0x00000354, 0x00000353, + 0x000200f8, 0x00000354, 0x0004003d, 0x00000017, 0x00000355, 0x00000005, 0x00040064, 0x00000016, + 0x00000356, 0x00000355, 0x00050067, 0x0000000c, 0x00000357, 0x00000356, 0x00000019, 0x000500b1, + 0x00000015, 0x00000358, 0x00000350, 0x00000357, 0x0004009b, 0x00000014, 0x00000359, 0x00000358, + 0x000200f9, 0x00000353, 0x000200f8, 0x00000353, 0x000700f5, 0x00000014, 0x0000035a, 0x00000352, + 0x00000348, 0x00000359, 0x00000354, 0x000300f7, 0x0000035b, 0x00000000, 0x000400fa, 0x0000035a, + 0x0000035c, 0x0000035d, 0x000200f8, 0x0000035c, 0x0004003d, 0x00000017, 0x0000035e, 0x00000005, + 0x00040064, 0x00000016, 0x0000035f, 0x0000035e, 0x0007005f, 0x00000021, 0x00000360, 0x0000035f, + 0x00000350, 0x00000002, 0x00000019, 0x000200f9, 0x0000035b, 0x000200f8, 0x0000035d, 0x000200f9, + 0x0000035b, 0x000200f8, 0x0000035b, 0x000700f5, 0x00000021, 0x00000361, 0x00000360, 0x0000035c, + 0x00000023, 0x0000035d, 0x00040073, 0x0000001d, 0x00000362, 0x00000361, 0x00050080, 0x0000000c, + 0x00000363, 0x00000336, 0x00000026, 0x000500af, 0x00000015, 0x00000364, 0x00000363, 0x00000020, + 0x0004009b, 0x00000014, 0x00000365, 0x00000364, 0x000300f7, 0x00000366, 0x00000000, 0x000400fa, + 0x00000365, 0x00000367, 0x00000366, 0x000200f8, 0x00000367, 0x0004003d, 0x00000017, 0x00000368, + 0x00000005, 0x00040064, 0x00000016, 0x00000369, 0x00000368, 0x00050067, 0x0000000c, 0x0000036a, + 0x00000369, 0x00000019, 0x000500b1, 0x00000015, 0x0000036b, 0x00000363, 0x0000036a, 0x0004009b, + 0x00000014, 0x0000036c, 0x0000036b, 0x000200f9, 0x00000366, 0x000200f8, 0x00000366, 0x000700f5, + 0x00000014, 0x0000036d, 0x00000365, 0x0000035b, 0x0000036c, 0x00000367, 0x000300f7, 0x0000036e, + 0x00000000, 0x000400fa, 0x0000036d, 0x0000036f, 0x00000370, 0x000200f8, 0x0000036f, 0x0004003d, + 0x00000017, 0x00000371, 0x00000005, 0x00040064, 0x00000016, 0x00000372, 0x00000371, 0x0007005f, + 0x00000021, 0x00000373, 0x00000372, 0x00000363, 0x00000002, 0x00000019, 0x000200f9, 0x0000036e, + 0x000200f8, 0x00000370, 0x000200f9, 0x0000036e, 0x000200f8, 0x0000036e, 0x000700f5, 0x00000021, + 0x00000374, 0x00000373, 0x0000036f, 0x00000023, 0x00000370, 0x00040073, 0x0000001d, 0x00000375, + 0x00000374, 0x00050080, 0x0000000c, 0x00000376, 0x00000336, 0x00000027, 0x000500af, 0x00000015, + 0x00000377, 0x00000376, 0x00000020, 0x0004009b, 0x00000014, 0x00000378, 0x00000377, 0x000300f7, + 0x00000379, 0x00000000, 0x000400fa, 0x00000378, 0x0000037a, 0x00000379, 0x000200f8, 0x0000037a, + 0x0004003d, 0x00000017, 0x0000037b, 0x00000005, 0x00040064, 0x00000016, 0x0000037c, 0x0000037b, + 0x00050067, 0x0000000c, 0x0000037d, 0x0000037c, 0x00000019, 0x000500b1, 0x00000015, 0x0000037e, + 0x00000376, 0x0000037d, 0x0004009b, 0x00000014, 0x0000037f, 0x0000037e, 0x000200f9, 0x00000379, + 0x000200f8, 0x00000379, 0x000700f5, 0x00000014, 0x00000380, 0x00000378, 0x0000036e, 0x0000037f, + 0x0000037a, 0x000300f7, 0x00000381, 0x00000000, 0x000400fa, 0x00000380, 0x00000382, 0x00000383, + 0x000200f8, 0x00000382, 0x0004003d, 0x00000017, 0x00000384, 0x00000005, 0x00040064, 0x00000016, + 0x00000385, 0x00000384, 0x0007005f, 0x00000021, 0x00000386, 0x00000385, 0x00000376, 0x00000002, + 0x00000019, 0x000200f9, 0x00000381, 0x000200f8, 0x00000383, 0x000200f9, 0x00000381, 0x000200f8, + 0x00000381, 0x000700f5, 0x00000021, 0x00000387, 0x00000386, 0x00000382, 0x00000023, 0x00000383, + 0x00040073, 0x0000001d, 0x00000388, 0x00000387, 0x0004003d, 0x00000017, 0x00000389, 0x00000005, + 0x00040064, 0x00000016, 0x0000038a, 0x00000389, 0x0007005f, 0x00000021, 0x0000038b, 0x0000038a, + 0x00000336, 0x00000002, 0x00000019, 0x00040073, 0x0000001d, 0x0000038c, 0x0000038b, 0x00050080, + 0x0000000c, 0x0000038d, 0x00000336, 0x00000028, 0x000500af, 0x00000015, 0x0000038e, 0x0000038d, + 0x00000020, 0x0004009b, 0x00000014, 0x0000038f, 0x0000038e, 0x000300f7, 0x00000390, 0x00000000, + 0x000400fa, 0x0000038f, 0x00000391, 0x00000390, 0x000200f8, 0x00000391, 0x0004003d, 0x00000017, + 0x00000392, 0x00000005, 0x00040064, 0x00000016, 0x00000393, 0x00000392, 0x00050067, 0x0000000c, + 0x00000394, 0x00000393, 0x00000019, 0x000500b1, 0x00000015, 0x00000395, 0x0000038d, 0x00000394, + 0x0004009b, 0x00000014, 0x00000396, 0x00000395, 0x000200f9, 0x00000390, 0x000200f8, 0x00000390, + 0x000700f5, 0x00000014, 0x00000397, 0x0000038f, 0x00000381, 0x00000396, 0x00000391, 0x000300f7, + 0x00000398, 0x00000000, 0x000400fa, 0x00000397, 0x00000399, 0x0000039a, 0x000200f8, 0x00000399, + 0x0004003d, 0x00000017, 0x0000039b, 0x00000005, 0x00040064, 0x00000016, 0x0000039c, 0x0000039b, + 0x0007005f, 0x00000021, 0x0000039d, 0x0000039c, 0x0000038d, 0x00000002, 0x00000019, 0x000200f9, + 0x00000398, 0x000200f8, 0x0000039a, 0x000200f9, 0x00000398, 0x000200f8, 0x00000398, 0x000700f5, + 0x00000021, 0x0000039e, 0x0000039d, 0x00000399, 0x00000023, 0x0000039a, 0x00040073, 0x0000001d, + 0x0000039f, 0x0000039e, 0x00050080, 0x0000000c, 0x000003a0, 0x00000336, 0x00000029, 0x000500af, + 0x00000015, 0x000003a1, 0x000003a0, 0x00000020, 0x0004009b, 0x00000014, 0x000003a2, 0x000003a1, + 0x000300f7, 0x000003a3, 0x00000000, 0x000400fa, 0x000003a2, 0x000003a4, 0x000003a3, 0x000200f8, + 0x000003a4, 0x0004003d, 0x00000017, 0x000003a5, 0x00000005, 0x00040064, 0x00000016, 0x000003a6, + 0x000003a5, 0x00050067, 0x0000000c, 0x000003a7, 0x000003a6, 0x00000019, 0x000500b1, 0x00000015, + 0x000003a8, 0x000003a0, 0x000003a7, 0x0004009b, 0x00000014, 0x000003a9, 0x000003a8, 0x000200f9, + 0x000003a3, 0x000200f8, 0x000003a3, 0x000700f5, 0x00000014, 0x000003aa, 0x000003a2, 0x00000398, + 0x000003a9, 0x000003a4, 0x000300f7, 0x000003ab, 0x00000000, 0x000400fa, 0x000003aa, 0x000003ac, + 0x000003ad, 0x000200f8, 0x000003ac, 0x0004003d, 0x00000017, 0x000003ae, 0x00000005, 0x00040064, + 0x00000016, 0x000003af, 0x000003ae, 0x0007005f, 0x00000021, 0x000003b0, 0x000003af, 0x000003a0, + 0x00000002, 0x00000019, 0x000200f9, 0x000003ab, 0x000200f8, 0x000003ad, 0x000200f9, 0x000003ab, + 0x000200f8, 0x000003ab, 0x000700f5, 0x00000021, 0x000003b1, 0x000003b0, 0x000003ac, 0x00000023, + 0x000003ad, 0x00040073, 0x0000001d, 0x000003b2, 0x000003b1, 0x00050080, 0x0000000c, 0x000003b3, + 0x00000336, 0x0000002a, 0x000500af, 0x00000015, 0x000003b4, 0x000003b3, 0x00000020, 0x0004009b, + 0x00000014, 0x000003b5, 0x000003b4, 0x000300f7, 0x000003b6, 0x00000000, 0x000400fa, 0x000003b5, + 0x000003b7, 0x000003b6, 0x000200f8, 0x000003b7, 0x0004003d, 0x00000017, 0x000003b8, 0x00000005, + 0x00040064, 0x00000016, 0x000003b9, 0x000003b8, 0x00050067, 0x0000000c, 0x000003ba, 0x000003b9, + 0x00000019, 0x000500b1, 0x00000015, 0x000003bb, 0x000003b3, 0x000003ba, 0x0004009b, 0x00000014, + 0x000003bc, 0x000003bb, 0x000200f9, 0x000003b6, 0x000200f8, 0x000003b6, 0x000700f5, 0x00000014, + 0x000003bd, 0x000003b5, 0x000003ab, 0x000003bc, 0x000003b7, 0x000300f7, 0x000003be, 0x00000000, + 0x000400fa, 0x000003bd, 0x000003bf, 0x000003c0, 0x000200f8, 0x000003bf, 0x0004003d, 0x00000017, + 0x000003c1, 0x00000005, 0x00040064, 0x00000016, 0x000003c2, 0x000003c1, 0x0007005f, 0x00000021, + 0x000003c3, 0x000003c2, 0x000003b3, 0x00000002, 0x00000019, 0x000200f9, 0x000003be, 0x000200f8, + 0x000003c0, 0x000200f9, 0x000003be, 0x000200f8, 0x000003be, 0x000700f5, 0x00000021, 0x000003c4, + 0x000003c3, 0x000003bf, 0x00000023, 0x000003c0, 0x00040073, 0x0000001d, 0x000003c5, 0x000003c4, + 0x00050080, 0x0000000c, 0x000003c6, 0x00000336, 0x0000002b, 0x000500af, 0x00000015, 0x000003c7, + 0x000003c6, 0x00000020, 0x0004009b, 0x00000014, 0x000003c8, 0x000003c7, 0x000300f7, 0x000003c9, + 0x00000000, 0x000400fa, 0x000003c8, 0x000003ca, 0x000003c9, 0x000200f8, 0x000003ca, 0x0004003d, + 0x00000017, 0x000003cb, 0x00000005, 0x00040064, 0x00000016, 0x000003cc, 0x000003cb, 0x00050067, + 0x0000000c, 0x000003cd, 0x000003cc, 0x00000019, 0x000500b1, 0x00000015, 0x000003ce, 0x000003c6, + 0x000003cd, 0x0004009b, 0x00000014, 0x000003cf, 0x000003ce, 0x000200f9, 0x000003c9, 0x000200f8, + 0x000003c9, 0x000700f5, 0x00000014, 0x000003d0, 0x000003c8, 0x000003be, 0x000003cf, 0x000003ca, + 0x000300f7, 0x000003d1, 0x00000000, 0x000400fa, 0x000003d0, 0x000003d2, 0x000003d3, 0x000200f8, + 0x000003d2, 0x0004003d, 0x00000017, 0x000003d4, 0x00000005, 0x00040064, 0x00000016, 0x000003d5, + 0x000003d4, 0x0007005f, 0x00000021, 0x000003d6, 0x000003d5, 0x000003c6, 0x00000002, 0x00000019, + 0x000200f9, 0x000003d1, 0x000200f8, 0x000003d3, 0x000200f9, 0x000003d1, 0x000200f8, 0x000003d1, + 0x000700f5, 0x00000021, 0x000003d7, 0x000003d6, 0x000003d2, 0x00000023, 0x000003d3, 0x00040073, + 0x0000001d, 0x000003d8, 0x000003d7, 0x000300f7, 0x000003d9, 0x00000000, 0x000400fa, 0x0000033f, + 0x000003da, 0x000003d9, 0x000200f8, 0x000003da, 0x0004003d, 0x00000017, 0x000003db, 0x00000006, + 0x00040064, 0x00000016, 0x000003dc, 0x000003db, 0x00050067, 0x0000000c, 0x000003dd, 0x000003dc, + 0x00000019, 0x000500b1, 0x00000015, 0x000003de, 0x0000033d, 0x000003dd, 0x0004009b, 0x00000014, + 0x000003df, 0x000003de, 0x000200f9, 0x000003d9, 0x000200f8, 0x000003d9, 0x000700f5, 0x00000014, + 0x000003e0, 0x0000033f, 0x000003d1, 0x000003df, 0x000003da, 0x000300f7, 0x000003e1, 0x00000000, + 0x000400fa, 0x000003e0, 0x000003e2, 0x000003e3, 0x000200f8, 0x000003e2, 0x0004003d, 0x00000017, + 0x000003e4, 0x00000006, 0x00040064, 0x00000016, 0x000003e5, 0x000003e4, 0x0007005f, 0x00000021, + 0x000003e6, 0x000003e5, 0x0000033d, 0x00000002, 0x00000019, 0x000200f9, 0x000003e1, 0x000200f8, + 0x000003e3, 0x000200f9, 0x000003e1, 0x000200f8, 0x000003e1, 0x000700f5, 0x00000021, 0x000003e7, + 0x000003e6, 0x000003e2, 0x00000023, 0x000003e3, 0x00040073, 0x0000001d, 0x000003e8, 0x000003e7, + 0x000300f7, 0x000003e9, 0x00000000, 0x000400fa, 0x00000352, 0x000003ea, 0x000003e9, 0x000200f8, + 0x000003ea, 0x0004003d, 0x00000017, 0x000003eb, 0x00000006, 0x00040064, 0x00000016, 0x000003ec, + 0x000003eb, 0x00050067, 0x0000000c, 0x000003ed, 0x000003ec, 0x00000019, 0x000500b1, 0x00000015, + 0x000003ee, 0x00000350, 0x000003ed, 0x0004009b, 0x00000014, 0x000003ef, 0x000003ee, 0x000200f9, + 0x000003e9, 0x000200f8, 0x000003e9, 0x000700f5, 0x00000014, 0x000003f0, 0x00000352, 0x000003e1, + 0x000003ef, 0x000003ea, 0x000300f7, 0x000003f1, 0x00000000, 0x000400fa, 0x000003f0, 0x000003f2, + 0x000003f3, 0x000200f8, 0x000003f2, 0x0004003d, 0x00000017, 0x000003f4, 0x00000006, 0x00040064, + 0x00000016, 0x000003f5, 0x000003f4, 0x0007005f, 0x00000021, 0x000003f6, 0x000003f5, 0x00000350, + 0x00000002, 0x00000019, 0x000200f9, 0x000003f1, 0x000200f8, 0x000003f3, 0x000200f9, 0x000003f1, + 0x000200f8, 0x000003f1, 0x000700f5, 0x00000021, 0x000003f7, 0x000003f6, 0x000003f2, 0x00000023, + 0x000003f3, 0x00040073, 0x0000001d, 0x000003f8, 0x000003f7, 0x000300f7, 0x000003f9, 0x00000000, + 0x000400fa, 0x00000365, 0x000003fa, 0x000003f9, 0x000200f8, 0x000003fa, 0x0004003d, 0x00000017, + 0x000003fb, 0x00000006, 0x00040064, 0x00000016, 0x000003fc, 0x000003fb, 0x00050067, 0x0000000c, + 0x000003fd, 0x000003fc, 0x00000019, 0x000500b1, 0x00000015, 0x000003fe, 0x00000363, 0x000003fd, + 0x0004009b, 0x00000014, 0x000003ff, 0x000003fe, 0x000200f9, 0x000003f9, 0x000200f8, 0x000003f9, + 0x000700f5, 0x00000014, 0x00000400, 0x00000365, 0x000003f1, 0x000003ff, 0x000003fa, 0x000300f7, + 0x00000401, 0x00000000, 0x000400fa, 0x00000400, 0x00000402, 0x00000403, 0x000200f8, 0x00000402, + 0x0004003d, 0x00000017, 0x00000404, 0x00000006, 0x00040064, 0x00000016, 0x00000405, 0x00000404, + 0x0007005f, 0x00000021, 0x00000406, 0x00000405, 0x00000363, 0x00000002, 0x00000019, 0x000200f9, + 0x00000401, 0x000200f8, 0x00000403, 0x000200f9, 0x00000401, 0x000200f8, 0x00000401, 0x000700f5, + 0x00000021, 0x00000407, 0x00000406, 0x00000402, 0x00000023, 0x00000403, 0x00040073, 0x0000001d, + 0x00000408, 0x00000407, 0x000300f7, 0x00000409, 0x00000000, 0x000400fa, 0x00000378, 0x0000040a, + 0x00000409, 0x000200f8, 0x0000040a, 0x0004003d, 0x00000017, 0x0000040b, 0x00000006, 0x00040064, + 0x00000016, 0x0000040c, 0x0000040b, 0x00050067, 0x0000000c, 0x0000040d, 0x0000040c, 0x00000019, + 0x000500b1, 0x00000015, 0x0000040e, 0x00000376, 0x0000040d, 0x0004009b, 0x00000014, 0x0000040f, + 0x0000040e, 0x000200f9, 0x00000409, 0x000200f8, 0x00000409, 0x000700f5, 0x00000014, 0x00000410, + 0x00000378, 0x00000401, 0x0000040f, 0x0000040a, 0x000300f7, 0x00000411, 0x00000000, 0x000400fa, + 0x00000410, 0x00000412, 0x00000413, 0x000200f8, 0x00000412, 0x0004003d, 0x00000017, 0x00000414, + 0x00000006, 0x00040064, 0x00000016, 0x00000415, 0x00000414, 0x0007005f, 0x00000021, 0x00000416, + 0x00000415, 0x00000376, 0x00000002, 0x00000019, 0x000200f9, 0x00000411, 0x000200f8, 0x00000413, + 0x000200f9, 0x00000411, 0x000200f8, 0x00000411, 0x000700f5, 0x00000021, 0x00000417, 0x00000416, + 0x00000412, 0x00000023, 0x00000413, 0x00040073, 0x0000001d, 0x00000418, 0x00000417, 0x0004003d, + 0x00000017, 0x00000419, 0x00000006, 0x00040064, 0x00000016, 0x0000041a, 0x00000419, 0x0007005f, + 0x00000021, 0x0000041b, 0x0000041a, 0x00000336, 0x00000002, 0x00000019, 0x00040073, 0x0000001d, + 0x0000041c, 0x0000041b, 0x000300f7, 0x0000041d, 0x00000000, 0x000400fa, 0x0000038f, 0x0000041e, + 0x0000041d, 0x000200f8, 0x0000041e, 0x0004003d, 0x00000017, 0x0000041f, 0x00000006, 0x00040064, + 0x00000016, 0x00000420, 0x0000041f, 0x00050067, 0x0000000c, 0x00000421, 0x00000420, 0x00000019, + 0x000500b1, 0x00000015, 0x00000422, 0x0000038d, 0x00000421, 0x0004009b, 0x00000014, 0x00000423, + 0x00000422, 0x000200f9, 0x0000041d, 0x000200f8, 0x0000041d, 0x000700f5, 0x00000014, 0x00000424, + 0x0000038f, 0x00000411, 0x00000423, 0x0000041e, 0x000300f7, 0x00000425, 0x00000000, 0x000400fa, + 0x00000424, 0x00000426, 0x00000427, 0x000200f8, 0x00000426, 0x0004003d, 0x00000017, 0x00000428, + 0x00000006, 0x00040064, 0x00000016, 0x00000429, 0x00000428, 0x0007005f, 0x00000021, 0x0000042a, + 0x00000429, 0x0000038d, 0x00000002, 0x00000019, 0x000200f9, 0x00000425, 0x000200f8, 0x00000427, + 0x000200f9, 0x00000425, 0x000200f8, 0x00000425, 0x000700f5, 0x00000021, 0x0000042b, 0x0000042a, + 0x00000426, 0x00000023, 0x00000427, 0x00040073, 0x0000001d, 0x0000042c, 0x0000042b, 0x000300f7, + 0x0000042d, 0x00000000, 0x000400fa, 0x000003a2, 0x0000042e, 0x0000042d, 0x000200f8, 0x0000042e, + 0x0004003d, 0x00000017, 0x0000042f, 0x00000006, 0x00040064, 0x00000016, 0x00000430, 0x0000042f, + 0x00050067, 0x0000000c, 0x00000431, 0x00000430, 0x00000019, 0x000500b1, 0x00000015, 0x00000432, + 0x000003a0, 0x00000431, 0x0004009b, 0x00000014, 0x00000433, 0x00000432, 0x000200f9, 0x0000042d, + 0x000200f8, 0x0000042d, 0x000700f5, 0x00000014, 0x00000434, 0x000003a2, 0x00000425, 0x00000433, + 0x0000042e, 0x000300f7, 0x00000435, 0x00000000, 0x000400fa, 0x00000434, 0x00000436, 0x00000437, + 0x000200f8, 0x00000436, 0x0004003d, 0x00000017, 0x00000438, 0x00000006, 0x00040064, 0x00000016, + 0x00000439, 0x00000438, 0x0007005f, 0x00000021, 0x0000043a, 0x00000439, 0x000003a0, 0x00000002, + 0x00000019, 0x000200f9, 0x00000435, 0x000200f8, 0x00000437, 0x000200f9, 0x00000435, 0x000200f8, + 0x00000435, 0x000700f5, 0x00000021, 0x0000043b, 0x0000043a, 0x00000436, 0x00000023, 0x00000437, + 0x00040073, 0x0000001d, 0x0000043c, 0x0000043b, 0x000300f7, 0x0000043d, 0x00000000, 0x000400fa, + 0x000003b5, 0x0000043e, 0x0000043d, 0x000200f8, 0x0000043e, 0x0004003d, 0x00000017, 0x0000043f, + 0x00000006, 0x00040064, 0x00000016, 0x00000440, 0x0000043f, 0x00050067, 0x0000000c, 0x00000441, + 0x00000440, 0x00000019, 0x000500b1, 0x00000015, 0x00000442, 0x000003b3, 0x00000441, 0x0004009b, + 0x00000014, 0x00000443, 0x00000442, 0x000200f9, 0x0000043d, 0x000200f8, 0x0000043d, 0x000700f5, + 0x00000014, 0x00000444, 0x000003b5, 0x00000435, 0x00000443, 0x0000043e, 0x000300f7, 0x00000445, + 0x00000000, 0x000400fa, 0x00000444, 0x00000446, 0x00000447, 0x000200f8, 0x00000446, 0x0004003d, + 0x00000017, 0x00000448, 0x00000006, 0x00040064, 0x00000016, 0x00000449, 0x00000448, 0x0007005f, + 0x00000021, 0x0000044a, 0x00000449, 0x000003b3, 0x00000002, 0x00000019, 0x000200f9, 0x00000445, + 0x000200f8, 0x00000447, 0x000200f9, 0x00000445, 0x000200f8, 0x00000445, 0x000700f5, 0x00000021, + 0x0000044b, 0x0000044a, 0x00000446, 0x00000023, 0x00000447, 0x00040073, 0x0000001d, 0x0000044c, + 0x0000044b, 0x000300f7, 0x0000044d, 0x00000000, 0x000400fa, 0x000003c8, 0x0000044e, 0x0000044d, + 0x000200f8, 0x0000044e, 0x0004003d, 0x00000017, 0x0000044f, 0x00000006, 0x00040064, 0x00000016, + 0x00000450, 0x0000044f, 0x00050067, 0x0000000c, 0x00000451, 0x00000450, 0x00000019, 0x000500b1, + 0x00000015, 0x00000452, 0x000003c6, 0x00000451, 0x0004009b, 0x00000014, 0x00000453, 0x00000452, + 0x000200f9, 0x0000044d, 0x000200f8, 0x0000044d, 0x000700f5, 0x00000014, 0x00000454, 0x000003c8, + 0x00000445, 0x00000453, 0x0000044e, 0x000300f7, 0x00000455, 0x00000000, 0x000400fa, 0x00000454, + 0x00000456, 0x00000457, 0x000200f8, 0x00000456, 0x0004003d, 0x00000017, 0x00000458, 0x00000006, + 0x00040064, 0x00000016, 0x00000459, 0x00000458, 0x0007005f, 0x00000021, 0x0000045a, 0x00000459, + 0x000003c6, 0x00000002, 0x00000019, 0x000200f9, 0x00000455, 0x000200f8, 0x00000457, 0x000200f9, + 0x00000455, 0x000200f8, 0x00000455, 0x000700f5, 0x00000021, 0x0000045b, 0x0000045a, 0x00000456, + 0x00000023, 0x00000457, 0x00040073, 0x0000001d, 0x0000045c, 0x0000045b, 0x0004003d, 0x00000012, + 0x0000045d, 0x00000004, 0x00050091, 0x0000001d, 0x0000045e, 0x00000041, 0x0000034f, 0x00050091, + 0x0000001d, 0x0000045f, 0x00000056, 0x00000362, 0x00050081, 0x0000001d, 0x00000460, 0x0000045e, + 0x0000045f, 0x00050091, 0x0000001d, 0x00000461, 0x0000006b, 0x00000375, 0x00050081, 0x0000001d, + 0x00000462, 0x00000460, 0x00000461, 0x00050091, 0x0000001d, 0x00000463, 0x00000080, 0x00000388, + 0x00050081, 0x0000001d, 0x00000464, 0x00000462, 0x00000463, 0x00050091, 0x0000001d, 0x00000465, + 0x00000095, 0x0000038c, 0x00050081, 0x0000001d, 0x00000466, 0x00000464, 0x00000465, 0x00050091, + 0x0000001d, 0x00000467, 0x000000aa, 0x0000039f, 0x00050081, 0x0000001d, 0x00000468, 0x00000466, + 0x00000467, 0x00050091, 0x0000001d, 0x00000469, 0x000000bf, 0x000003b2, 0x00050081, 0x0000001d, + 0x0000046a, 0x00000468, 0x00000469, 0x00050091, 0x0000001d, 0x0000046b, 0x000000d4, 0x000003c5, + 0x00050081, 0x0000001d, 0x0000046c, 0x0000046a, 0x0000046b, 0x00050091, 0x0000001d, 0x0000046d, + 0x000000e9, 0x000003d8, 0x00050081, 0x0000001d, 0x0000046e, 0x0000046c, 0x0000046d, 0x00050091, + 0x0000001d, 0x0000046f, 0x000000fe, 0x000003e8, 0x00050081, 0x0000001d, 0x00000470, 0x0000046e, + 0x0000046f, 0x00050091, 0x0000001d, 0x00000471, 0x00000113, 0x000003f8, 0x00050081, 0x0000001d, + 0x00000472, 0x00000470, 0x00000471, 0x00050091, 0x0000001d, 0x00000473, 0x00000128, 0x00000408, + 0x00050081, 0x0000001d, 0x00000474, 0x00000472, 0x00000473, 0x00050091, 0x0000001d, 0x00000475, + 0x0000013d, 0x00000418, 0x00050081, 0x0000001d, 0x00000476, 0x00000474, 0x00000475, 0x00050091, + 0x0000001d, 0x00000477, 0x00000151, 0x0000041c, 0x00050081, 0x0000001d, 0x00000478, 0x00000476, + 0x00000477, 0x00050091, 0x0000001d, 0x00000479, 0x00000166, 0x0000042c, 0x00050081, 0x0000001d, + 0x0000047a, 0x00000478, 0x00000479, 0x00050091, 0x0000001d, 0x0000047b, 0x0000017b, 0x0000043c, + 0x00050081, 0x0000001d, 0x0000047c, 0x0000047a, 0x0000047b, 0x00050091, 0x0000001d, 0x0000047d, + 0x00000190, 0x0000044c, 0x00050081, 0x0000001d, 0x0000047e, 0x0000047c, 0x0000047d, 0x00050091, + 0x0000001d, 0x0000047f, 0x000001a5, 0x0000045c, 0x00050081, 0x0000001d, 0x00000480, 0x0000047e, + 0x0000047f, 0x00050083, 0x0000001d, 0x00000481, 0x00000480, 0x000001aa, 0x00050085, 0x0000001d, + 0x00000482, 0x00000481, 0x000001ae, 0x00050081, 0x0000001d, 0x00000483, 0x00000482, 0x000001b3, + 0x00040073, 0x00000021, 0x00000484, 0x00000483, 0x00040063, 0x0000045d, 0x00000336, 0x00000484, + 0x0004003d, 0x00000012, 0x00000485, 0x00000007, 0x00050091, 0x0000001d, 0x00000486, 0x000001c8, + 0x0000034f, 0x00050091, 0x0000001d, 0x00000487, 0x000001dd, 0x00000362, 0x00050081, 0x0000001d, + 0x00000488, 0x00000486, 0x00000487, 0x00050091, 0x0000001d, 0x00000489, 0x000001f2, 0x00000375, + 0x00050081, 0x0000001d, 0x0000048a, 0x00000488, 0x00000489, 0x00050091, 0x0000001d, 0x0000048b, + 0x00000206, 0x00000388, 0x00050081, 0x0000001d, 0x0000048c, 0x0000048a, 0x0000048b, 0x00050091, + 0x0000001d, 0x0000048d, 0x0000021b, 0x0000038c, 0x00050081, 0x0000001d, 0x0000048e, 0x0000048c, + 0x0000048d, 0x00050091, 0x0000001d, 0x0000048f, 0x0000022f, 0x0000039f, 0x00050081, 0x0000001d, + 0x00000490, 0x0000048e, 0x0000048f, 0x00050091, 0x0000001d, 0x00000491, 0x00000244, 0x000003b2, + 0x00050081, 0x0000001d, 0x00000492, 0x00000490, 0x00000491, 0x00050091, 0x0000001d, 0x00000493, + 0x00000259, 0x000003c5, 0x00050081, 0x0000001d, 0x00000494, 0x00000492, 0x00000493, 0x00050091, + 0x0000001d, 0x00000495, 0x0000026e, 0x000003d8, 0x00050081, 0x0000001d, 0x00000496, 0x00000494, + 0x00000495, 0x00050091, 0x0000001d, 0x00000497, 0x00000282, 0x000003e8, 0x00050081, 0x0000001d, + 0x00000498, 0x00000496, 0x00000497, 0x00050091, 0x0000001d, 0x00000499, 0x00000297, 0x000003f8, + 0x00050081, 0x0000001d, 0x0000049a, 0x00000498, 0x00000499, 0x00050091, 0x0000001d, 0x0000049b, + 0x000002aa, 0x00000408, 0x00050081, 0x0000001d, 0x0000049c, 0x0000049a, 0x0000049b, 0x00050091, + 0x0000001d, 0x0000049d, 0x000002be, 0x00000418, 0x00050081, 0x0000001d, 0x0000049e, 0x0000049c, + 0x0000049d, 0x00050091, 0x0000001d, 0x0000049f, 0x000002d0, 0x0000041c, 0x00050081, 0x0000001d, + 0x000004a0, 0x0000049e, 0x0000049f, 0x00050091, 0x0000001d, 0x000004a1, 0x000002e4, 0x0000042c, + 0x00050081, 0x0000001d, 0x000004a2, 0x000004a0, 0x000004a1, 0x00050091, 0x0000001d, 0x000004a3, + 0x000002f8, 0x0000043c, 0x00050081, 0x0000001d, 0x000004a4, 0x000004a2, 0x000004a3, 0x00050091, + 0x0000001d, 0x000004a5, 0x0000030b, 0x0000044c, 0x00050081, 0x0000001d, 0x000004a6, 0x000004a4, + 0x000004a5, 0x00050091, 0x0000001d, 0x000004a7, 0x00000320, 0x0000045c, 0x00050081, 0x0000001d, + 0x000004a8, 0x000004a6, 0x000004a7, 0x00050083, 0x0000001d, 0x000004a9, 0x000004a8, 0x00000325, + 0x00050085, 0x0000001d, 0x000004aa, 0x000004a9, 0x0000032a, 0x00050081, 0x0000001d, 0x000004ab, + 0x000004aa, 0x0000032f, 0x00040073, 0x00000021, 0x000004ac, 0x000004ab, 0x00040063, 0x00000485, + 0x00000336, 0x000004ac, 0x000200f9, 0x00000332, 0x000200f8, 0x00000332, 0x000100fd, 0x00010038, +}; +static const size_t wnfg_51_spv_size = sizeof(wnfg_51_spv); diff --git a/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_53_spv.h b/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_53_spv.h new file mode 100644 index 000000000..c13eb1ad8 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/wnfg_spv/wnfg_53_spv.h @@ -0,0 +1,340 @@ +#pragma once +#include +#include + +static const uint32_t wnfg_53_spv[] = { + 0x07230203, 0x00010000, 0x000d000b, 0x0000021f, 0x00000000, 0x00020011, 0x00000001, 0x00020011, + 0x00000009, 0x00020011, 0x00000032, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, + 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0006000f, 0x00000005, 0x00000002, 0x6e69616d, + 0x00000000, 0x00000003, 0x00060010, 0x00000002, 0x00000011, 0x00000010, 0x00000010, 0x00000001, + 0x00040047, 0x00000003, 0x0000000b, 0x0000001c, 0x00030047, 0x00000004, 0x00000019, 0x00040047, + 0x00000004, 0x00000021, 0x00000030, 0x00040047, 0x00000004, 0x00000022, 0x00000000, 0x00040047, + 0x00000005, 0x00000021, 0x00000020, 0x00040047, 0x00000005, 0x00000022, 0x00000000, 0x00040047, + 0x00000006, 0x00000021, 0x00000021, 0x00040047, 0x00000006, 0x00000022, 0x00000000, 0x00040047, + 0x00000007, 0x00000021, 0x00000022, 0x00040047, 0x00000007, 0x00000022, 0x00000000, 0x00040047, + 0x00000008, 0x0000000b, 0x00000019, 0x00020013, 0x00000009, 0x00030021, 0x0000000a, 0x00000009, + 0x00040015, 0x0000000b, 0x00000020, 0x00000001, 0x00040017, 0x0000000c, 0x0000000b, 0x00000002, + 0x00040015, 0x0000000d, 0x00000020, 0x00000000, 0x00040017, 0x0000000e, 0x0000000d, 0x00000003, + 0x00040020, 0x0000000f, 0x00000001, 0x0000000e, 0x0004003b, 0x0000000f, 0x00000003, 0x00000001, + 0x00040017, 0x00000010, 0x0000000d, 0x00000002, 0x00030016, 0x00000011, 0x00000020, 0x00090019, + 0x00000012, 0x00000011, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0x00000002, + 0x00040020, 0x00000013, 0x00000000, 0x00000012, 0x0004003b, 0x00000013, 0x00000004, 0x00000000, + 0x00020014, 0x00000014, 0x00040017, 0x00000015, 0x00000014, 0x00000002, 0x00090019, 0x00000016, + 0x00000011, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x0003001b, + 0x00000017, 0x00000016, 0x00040020, 0x00000018, 0x00000000, 0x00000017, 0x0004003b, 0x00000018, + 0x00000005, 0x00000000, 0x0004002b, 0x0000000b, 0x00000019, 0x00000000, 0x00040017, 0x0000001a, + 0x00000011, 0x00000002, 0x0004002b, 0x00000011, 0x0000001b, 0x3f000000, 0x0005002c, 0x0000001a, + 0x0000001c, 0x0000001b, 0x0000001b, 0x0004002b, 0x0000000d, 0x0000001d, 0x00000000, 0x0004002b, + 0x0000000d, 0x0000001e, 0x00000001, 0x00030016, 0x0000001f, 0x00000010, 0x00040017, 0x00000020, + 0x0000001f, 0x00000004, 0x00040018, 0x00000021, 0x00000020, 0x00000004, 0x0004002b, 0x0000001f, + 0x00000022, 0x0000aa20, 0x0004002b, 0x0000001f, 0x00000023, 0x0000a8fd, 0x0004002b, 0x0000001f, + 0x00000024, 0x000021c9, 0x0004002b, 0x0000001f, 0x00000025, 0x000025f6, 0x0007002c, 0x00000020, + 0x00000026, 0x00000022, 0x00000023, 0x00000024, 0x00000025, 0x0004002b, 0x0000001f, 0x00000027, + 0x00002dee, 0x0004002b, 0x0000001f, 0x00000028, 0x00002eef, 0x0004002b, 0x0000001f, 0x00000029, + 0x000031bf, 0x0004002b, 0x0000001f, 0x0000002a, 0x0000315a, 0x0007002c, 0x00000020, 0x0000002b, + 0x00000027, 0x00000028, 0x00000029, 0x0000002a, 0x0004002b, 0x0000001f, 0x0000002c, 0x0000af5d, + 0x0004002b, 0x0000001f, 0x0000002d, 0x0000af00, 0x0004002b, 0x0000001f, 0x0000002e, 0x00002f01, + 0x0004002b, 0x0000001f, 0x0000002f, 0x00003023, 0x0007002c, 0x00000020, 0x00000030, 0x0000002c, + 0x0000002d, 0x0000002e, 0x0000002f, 0x0004002b, 0x0000001f, 0x00000031, 0x0000ae7e, 0x0004002b, + 0x0000001f, 0x00000032, 0x0000ae16, 0x0004002b, 0x0000001f, 0x00000033, 0x00002e6b, 0x0004002b, + 0x0000001f, 0x00000034, 0x00002e52, 0x0007002c, 0x00000020, 0x00000035, 0x00000031, 0x00000032, + 0x00000033, 0x00000034, 0x0007002c, 0x00000021, 0x00000036, 0x00000026, 0x0000002b, 0x00000030, + 0x00000035, 0x0004002b, 0x00000011, 0x00000037, 0x00000000, 0x0004002b, 0x0000000b, 0x00000038, + 0xffffffff, 0x0005002c, 0x0000000c, 0x00000039, 0x00000038, 0x00000038, 0x00040017, 0x0000003a, + 0x00000011, 0x00000004, 0x0004002b, 0x0000001f, 0x0000003b, 0x000028f4, 0x0004002b, 0x0000001f, + 0x0000003c, 0x0000268b, 0x0004002b, 0x0000001f, 0x0000003d, 0x0000343c, 0x0004002b, 0x0000001f, + 0x0000003e, 0x00003415, 0x0007002c, 0x00000020, 0x0000003f, 0x0000003b, 0x0000003c, 0x0000003d, + 0x0000003e, 0x0004002b, 0x0000001f, 0x00000040, 0x00003292, 0x0004002b, 0x0000001f, 0x00000041, + 0x00003256, 0x0004002b, 0x0000001f, 0x00000042, 0x00003435, 0x0004002b, 0x0000001f, 0x00000043, + 0x00003404, 0x0007002c, 0x00000020, 0x00000044, 0x00000040, 0x00000041, 0x00000042, 0x00000043, + 0x0004002b, 0x0000001f, 0x00000045, 0x00001f89, 0x0004002b, 0x0000001f, 0x00000046, 0x00009edd, + 0x0004002b, 0x0000001f, 0x00000047, 0x000033ac, 0x0004002b, 0x0000001f, 0x00000048, 0x00003351, + 0x0007002c, 0x00000020, 0x00000049, 0x00000045, 0x00000046, 0x00000047, 0x00000048, 0x0004002b, + 0x0000001f, 0x0000004a, 0x000032a7, 0x0004002b, 0x0000001f, 0x0000004b, 0x00003231, 0x0004002b, + 0x0000001f, 0x0000004c, 0x000031ee, 0x0004002b, 0x0000001f, 0x0000004d, 0x0000321c, 0x0007002c, + 0x00000020, 0x0000004e, 0x0000004a, 0x0000004b, 0x0000004c, 0x0000004d, 0x0007002c, 0x00000021, + 0x0000004f, 0x0000003f, 0x00000044, 0x00000049, 0x0000004e, 0x0005002c, 0x0000000c, 0x00000050, + 0x00000038, 0x00000019, 0x0004002b, 0x0000001f, 0x00000051, 0x0000ad6d, 0x0004002b, 0x0000001f, + 0x00000052, 0x0000ad8c, 0x0004002b, 0x0000001f, 0x00000053, 0x00002dbe, 0x0004002b, 0x0000001f, + 0x00000054, 0x00002cbb, 0x0007002c, 0x00000020, 0x00000055, 0x00000051, 0x00000052, 0x00000053, + 0x00000054, 0x0004002b, 0x0000001f, 0x00000056, 0x0000302c, 0x0004002b, 0x0000001f, 0x00000057, + 0x00003065, 0x0004002b, 0x0000001f, 0x00000058, 0x0000317f, 0x0004002b, 0x0000001f, 0x00000059, + 0x000031bd, 0x0007002c, 0x00000020, 0x0000005a, 0x00000056, 0x00000057, 0x00000058, 0x00000059, + 0x0004002b, 0x0000001f, 0x0000005b, 0x0000b06c, 0x0004002b, 0x0000001f, 0x0000005c, 0x0000b05d, + 0x0004002b, 0x0000001f, 0x0000005d, 0x000030bd, 0x0004002b, 0x0000001f, 0x0000005e, 0x000030a1, + 0x0007002c, 0x00000020, 0x0000005f, 0x0000005b, 0x0000005c, 0x0000005d, 0x0000005e, 0x0004002b, + 0x0000001f, 0x00000060, 0x0000a81a, 0x0004002b, 0x0000001f, 0x00000061, 0x0000a531, 0x0004002b, + 0x0000001f, 0x00000062, 0x00002bd6, 0x0004002b, 0x0000001f, 0x00000063, 0x00002b98, 0x0007002c, + 0x00000020, 0x00000064, 0x00000060, 0x00000061, 0x00000062, 0x00000063, 0x0007002c, 0x00000021, + 0x00000065, 0x00000055, 0x0000005a, 0x0000005f, 0x00000064, 0x0004002b, 0x0000000b, 0x00000066, + 0x00000001, 0x0005002c, 0x0000000c, 0x00000067, 0x00000038, 0x00000066, 0x0004002b, 0x0000001f, + 0x00000068, 0x00002e3c, 0x0004002b, 0x0000001f, 0x00000069, 0x00002eb2, 0x0004002b, 0x0000001f, + 0x0000006a, 0x000032fb, 0x0004002b, 0x0000001f, 0x0000006b, 0x000032ad, 0x0007002c, 0x00000020, + 0x0000006c, 0x00000068, 0x00000069, 0x0000006a, 0x0000006b, 0x0004002b, 0x0000001f, 0x0000006d, + 0x0000323c, 0x0004002b, 0x0000001f, 0x0000006e, 0x000031da, 0x0004002b, 0x0000001f, 0x0000006f, + 0x00003410, 0x0004002b, 0x0000001f, 0x00000070, 0x0000343e, 0x0007002c, 0x00000020, 0x00000071, + 0x0000006d, 0x0000006e, 0x0000006f, 0x00000070, 0x0004002b, 0x0000001f, 0x00000072, 0x00002d90, + 0x0004002b, 0x0000001f, 0x00000073, 0x00002d8a, 0x0004002b, 0x0000001f, 0x00000074, 0x00003320, + 0x0004002b, 0x0000001f, 0x00000075, 0x00003274, 0x0007002c, 0x00000020, 0x00000076, 0x00000072, + 0x00000073, 0x00000074, 0x00000075, 0x0004002b, 0x0000001f, 0x00000077, 0x00002d6a, 0x0004002b, + 0x0000001f, 0x00000078, 0x00002b8f, 0x0004002b, 0x0000001f, 0x00000079, 0x0000345d, 0x0004002b, + 0x0000001f, 0x0000007a, 0x00003462, 0x0007002c, 0x00000020, 0x0000007b, 0x00000077, 0x00000078, + 0x00000079, 0x0000007a, 0x0007002c, 0x00000021, 0x0000007c, 0x0000006c, 0x00000071, 0x00000076, + 0x0000007b, 0x0005002c, 0x0000000c, 0x0000007d, 0x00000019, 0x00000038, 0x0004002b, 0x0000001f, + 0x0000007e, 0x00002ef0, 0x0004002b, 0x0000001f, 0x0000007f, 0x00002f76, 0x0004002b, 0x0000001f, + 0x00000080, 0x00003747, 0x0004002b, 0x0000001f, 0x00000081, 0x00003773, 0x0007002c, 0x00000020, + 0x00000082, 0x0000007e, 0x0000007f, 0x00000080, 0x00000081, 0x0004002b, 0x0000001f, 0x00000083, + 0x00003483, 0x0004002b, 0x0000001f, 0x00000084, 0x000034c7, 0x0004002b, 0x0000001f, 0x00000085, + 0x000035a9, 0x0004002b, 0x0000001f, 0x00000086, 0x00003565, 0x0007002c, 0x00000020, 0x00000087, + 0x00000083, 0x00000084, 0x00000085, 0x00000086, 0x0004002b, 0x0000001f, 0x00000088, 0x00003140, + 0x0004002b, 0x0000001f, 0x00000089, 0x00002fa9, 0x0004002b, 0x0000001f, 0x0000008a, 0x00003532, + 0x0004002b, 0x0000001f, 0x0000008b, 0x00003543, 0x0007002c, 0x00000020, 0x0000008c, 0x00000088, + 0x00000089, 0x0000008a, 0x0000008b, 0x0004002b, 0x0000001f, 0x0000008d, 0x000035de, 0x0004002b, + 0x0000001f, 0x0000008e, 0x00003542, 0x0004002b, 0x0000001f, 0x0000008f, 0x0000361b, 0x0004002b, + 0x0000001f, 0x00000090, 0x000035d8, 0x0007002c, 0x00000020, 0x00000091, 0x0000008d, 0x0000008e, + 0x0000008f, 0x00000090, 0x0007002c, 0x00000021, 0x00000092, 0x00000082, 0x00000087, 0x0000008c, + 0x00000091, 0x0004002b, 0x0000001f, 0x00000093, 0x00002c64, 0x0004002b, 0x0000001f, 0x00000094, + 0x00002d03, 0x0004002b, 0x0000001f, 0x00000095, 0x00003479, 0x0004002b, 0x0000001f, 0x00000096, + 0x00003461, 0x0007002c, 0x00000020, 0x00000097, 0x00000093, 0x00000094, 0x00000095, 0x00000096, + 0x0004002b, 0x0000001f, 0x00000098, 0x00003447, 0x0004002b, 0x0000001f, 0x00000099, 0x000033e3, + 0x0004002b, 0x0000001f, 0x0000009a, 0x00003441, 0x0004002b, 0x0000001f, 0x0000009b, 0x00003437, + 0x0007002c, 0x00000020, 0x0000009c, 0x00000098, 0x00000099, 0x0000009a, 0x0000009b, 0x0004002b, + 0x0000001f, 0x0000009d, 0x00002b06, 0x0004002b, 0x0000001f, 0x0000009e, 0x0000285a, 0x0004002b, + 0x0000001f, 0x0000009f, 0x0000328a, 0x0004002b, 0x0000001f, 0x000000a0, 0x00003296, 0x0007002c, + 0x00000020, 0x000000a1, 0x0000009d, 0x0000009e, 0x0000009f, 0x000000a0, 0x0004002b, 0x0000001f, + 0x000000a2, 0x00003105, 0x0004002b, 0x0000001f, 0x000000a3, 0x0000306f, 0x0004002b, 0x0000001f, + 0x000000a4, 0x0000335a, 0x0004002b, 0x0000001f, 0x000000a5, 0x0000339c, 0x0007002c, 0x00000020, + 0x000000a6, 0x000000a2, 0x000000a3, 0x000000a4, 0x000000a5, 0x0007002c, 0x00000021, 0x000000a7, + 0x00000097, 0x0000009c, 0x000000a1, 0x000000a6, 0x0005002c, 0x0000000c, 0x000000a8, 0x00000019, + 0x00000066, 0x0004002b, 0x0000001f, 0x000000a9, 0x00008c5c, 0x0004002b, 0x0000001f, 0x000000aa, + 0x00001c08, 0x0004002b, 0x0000001f, 0x000000ab, 0x00002841, 0x0004002b, 0x0000001f, 0x000000ac, + 0x000027fc, 0x0007002c, 0x00000020, 0x000000ad, 0x000000a9, 0x000000aa, 0x000000ab, 0x000000ac, + 0x0004002b, 0x0000001f, 0x000000ae, 0x0000300e, 0x0004002b, 0x0000001f, 0x000000af, 0x00002f71, + 0x0004002b, 0x0000001f, 0x000000b0, 0x000031e0, 0x0004002b, 0x0000001f, 0x000000b1, 0x0000318c, + 0x0007002c, 0x00000020, 0x000000b2, 0x000000ae, 0x000000af, 0x000000b0, 0x000000b1, 0x0004002b, + 0x0000001f, 0x000000b3, 0x0000a3a4, 0x0004002b, 0x0000001f, 0x000000b4, 0x0000a0b8, 0x0004002b, + 0x0000001f, 0x000000b5, 0x00002f0b, 0x0004002b, 0x0000001f, 0x000000b6, 0x00002f8b, 0x0007002c, + 0x00000020, 0x000000b7, 0x000000b3, 0x000000b4, 0x000000b5, 0x000000b6, 0x0004002b, 0x0000001f, + 0x000000b8, 0x0000b325, 0x0004002b, 0x0000001f, 0x000000b9, 0x0000b268, 0x0004002b, 0x0000001f, + 0x000000ba, 0x00003213, 0x0004002b, 0x0000001f, 0x000000bb, 0x000031cb, 0x0007002c, 0x00000020, + 0x000000bc, 0x000000b8, 0x000000b9, 0x000000ba, 0x000000bb, 0x0007002c, 0x00000021, 0x000000bd, + 0x000000ad, 0x000000b2, 0x000000b7, 0x000000bc, 0x0005002c, 0x0000000c, 0x000000be, 0x00000066, + 0x00000038, 0x0004002b, 0x0000001f, 0x000000bf, 0x00002ac2, 0x0004002b, 0x0000001f, 0x000000c0, + 0x00002c35, 0x0004002b, 0x0000001f, 0x000000c1, 0x0000344e, 0x0004002b, 0x0000001f, 0x000000c2, + 0x00003427, 0x0007002c, 0x00000020, 0x000000c3, 0x000000bf, 0x000000c0, 0x000000c1, 0x000000c2, + 0x0004002b, 0x0000001f, 0x000000c4, 0x0000334b, 0x0004002b, 0x0000001f, 0x000000c5, 0x00003393, + 0x0004002b, 0x0000001f, 0x000000c6, 0x0000340e, 0x0007002c, 0x00000020, 0x000000c7, 0x000000c4, + 0x000000c5, 0x000000c6, 0x00000098, 0x0004002b, 0x0000001f, 0x000000c8, 0x00002e54, 0x0004002b, + 0x0000001f, 0x000000c9, 0x00002ee1, 0x0004002b, 0x0000001f, 0x000000ca, 0x000032e7, 0x0004002b, + 0x0000001f, 0x000000cb, 0x000032d9, 0x0007002c, 0x00000020, 0x000000cc, 0x000000c8, 0x000000c9, + 0x000000ca, 0x000000cb, 0x0004002b, 0x0000001f, 0x000000cd, 0x00002cb8, 0x0004002b, 0x0000001f, + 0x000000ce, 0x00002cd3, 0x0004002b, 0x0000001f, 0x000000cf, 0x0000345c, 0x0004002b, 0x0000001f, + 0x000000d0, 0x0000347c, 0x0007002c, 0x00000020, 0x000000d1, 0x000000cd, 0x000000ce, 0x000000cf, + 0x000000d0, 0x0007002c, 0x00000021, 0x000000d2, 0x000000c3, 0x000000c7, 0x000000cc, 0x000000d1, + 0x0005002c, 0x0000000c, 0x000000d3, 0x00000066, 0x00000019, 0x0004002b, 0x0000001f, 0x000000d4, + 0x0000aab3, 0x0004002b, 0x0000001f, 0x000000d5, 0x0000aa47, 0x0004002b, 0x0000001f, 0x000000d6, + 0x00002d72, 0x0004002b, 0x0000001f, 0x000000d7, 0x00002ddf, 0x0007002c, 0x00000020, 0x000000d8, + 0x000000d4, 0x000000d5, 0x000000d6, 0x000000d7, 0x0004002b, 0x0000001f, 0x000000d9, 0x0000319f, + 0x0004002b, 0x0000001f, 0x000000da, 0x0000317b, 0x0004002b, 0x0000001f, 0x000000db, 0x00003167, + 0x0004002b, 0x0000001f, 0x000000dc, 0x00003159, 0x0007002c, 0x00000020, 0x000000dd, 0x000000d9, + 0x000000da, 0x000000db, 0x000000dc, 0x0004002b, 0x0000001f, 0x000000de, 0x0000ab52, 0x0004002b, + 0x0000001f, 0x000000df, 0x0000a9f9, 0x0004002b, 0x0000001f, 0x000000e0, 0x00002fd9, 0x0004002b, + 0x0000001f, 0x000000e1, 0x0000301d, 0x0007002c, 0x00000020, 0x000000e2, 0x000000de, 0x000000df, + 0x000000e0, 0x000000e1, 0x0004002b, 0x0000001f, 0x000000e3, 0x0000b15b, 0x0004002b, 0x0000001f, + 0x000000e4, 0x0000b0c9, 0x0004002b, 0x0000001f, 0x000000e5, 0x000030a3, 0x0004002b, 0x0000001f, + 0x000000e6, 0x0000305d, 0x0007002c, 0x00000020, 0x000000e7, 0x000000e3, 0x000000e4, 0x000000e5, + 0x000000e6, 0x0007002c, 0x00000021, 0x000000e8, 0x000000d8, 0x000000dd, 0x000000e2, 0x000000e7, + 0x0005002c, 0x0000000c, 0x000000e9, 0x00000066, 0x00000066, 0x0004002b, 0x0000001f, 0x000000ea, + 0x0000333c, 0x0004002b, 0x0000001f, 0x000000eb, 0x000033a9, 0x0004002b, 0x0000001f, 0x000000ec, + 0x0000b4a5, 0x0004002b, 0x0000001f, 0x000000ed, 0x0000b477, 0x0007002c, 0x00000020, 0x000000ee, + 0x000000ea, 0x000000eb, 0x000000ec, 0x000000ed, 0x0004002b, 0x0000001f, 0x000000ef, 0x0000b48a, + 0x0004002b, 0x0000001f, 0x000000f0, 0x0000b634, 0x0004002b, 0x0000001f, 0x000000f1, 0x000030db, + 0x0004002b, 0x0000001f, 0x000000f2, 0x000030b8, 0x0007002c, 0x00000020, 0x000000f3, 0x000000ef, + 0x000000f0, 0x000000f1, 0x000000f2, 0x0004002b, 0x0000001f, 0x000000f4, 0x00002ca7, 0x0004002b, + 0x0000001f, 0x000000f5, 0x00002d55, 0x0004002b, 0x0000001f, 0x000000f6, 0x000033f8, 0x0004002b, + 0x0000001f, 0x000000f7, 0x00003414, 0x0007002c, 0x00000020, 0x000000f8, 0x000000f4, 0x000000f5, + 0x000000f6, 0x000000f7, 0x0004002b, 0x0000001f, 0x000000f9, 0x00003401, 0x0004002b, 0x0000001f, + 0x000000fa, 0x00003443, 0x0004002b, 0x0000001f, 0x000000fb, 0x0000aeb8, 0x0004002b, 0x0000001f, + 0x000000fc, 0x0000b03b, 0x0007002c, 0x00000020, 0x000000fd, 0x000000f9, 0x000000fa, 0x000000fb, + 0x000000fc, 0x0007002c, 0x00000021, 0x000000fe, 0x000000ee, 0x000000f3, 0x000000f8, 0x000000fd, + 0x0004003b, 0x00000018, 0x00000006, 0x00000000, 0x0004002b, 0x0000001f, 0x000000ff, 0x000034d6, + 0x0004002b, 0x0000001f, 0x00000100, 0x0000354d, 0x0004002b, 0x0000001f, 0x00000101, 0x0000b0de, + 0x0004002b, 0x0000001f, 0x00000102, 0x0000b0af, 0x0007002c, 0x00000020, 0x00000103, 0x000000ff, + 0x00000100, 0x00000101, 0x00000102, 0x0004002b, 0x0000001f, 0x00000104, 0x0000b8cc, 0x0004002b, + 0x0000001f, 0x00000105, 0x0000b83e, 0x0004002b, 0x0000001f, 0x00000106, 0x0000334e, 0x0004002b, + 0x0000001f, 0x00000107, 0x00003377, 0x0007002c, 0x00000020, 0x00000108, 0x00000104, 0x00000105, + 0x00000106, 0x00000107, 0x0004002b, 0x0000001f, 0x00000109, 0x0000344c, 0x0004002b, 0x0000001f, + 0x0000010a, 0x000034f3, 0x0004002b, 0x0000001f, 0x0000010b, 0x00003508, 0x0007002c, 0x00000020, + 0x0000010c, 0x00000042, 0x00000109, 0x0000010a, 0x0000010b, 0x0004002b, 0x0000001f, 0x0000010d, + 0x000035f4, 0x0004002b, 0x0000001f, 0x0000010e, 0x00003597, 0x0004002b, 0x0000001f, 0x0000010f, + 0x00002e95, 0x0004002b, 0x0000001f, 0x00000110, 0x00002f23, 0x0007002c, 0x00000020, 0x00000111, + 0x0000010d, 0x0000010e, 0x0000010f, 0x00000110, 0x0007002c, 0x00000021, 0x00000112, 0x00000103, + 0x00000108, 0x0000010c, 0x00000111, 0x0004002b, 0x0000001f, 0x00000113, 0x000033b3, 0x0004002b, + 0x0000001f, 0x00000114, 0x00003314, 0x0004002b, 0x0000001f, 0x00000115, 0x0000b4ba, 0x0004002b, + 0x0000001f, 0x00000116, 0x0000b4d3, 0x0007002c, 0x00000020, 0x00000117, 0x00000113, 0x00000114, + 0x00000115, 0x00000116, 0x0004002b, 0x0000001f, 0x00000118, 0x0000b54a, 0x0004002b, 0x0000001f, + 0x00000119, 0x0000b64c, 0x0004002b, 0x0000001f, 0x0000011a, 0x000030a8, 0x0004002b, 0x0000001f, + 0x0000011b, 0x000030c3, 0x0007002c, 0x00000020, 0x0000011c, 0x00000118, 0x00000119, 0x0000011a, + 0x0000011b, 0x0004002b, 0x0000001f, 0x0000011d, 0x00002edf, 0x0004002b, 0x0000001f, 0x0000011e, + 0x00002ec9, 0x0004002b, 0x0000001f, 0x0000011f, 0x0000331d, 0x0004002b, 0x0000001f, 0x00000120, + 0x000032fc, 0x0007002c, 0x00000020, 0x00000121, 0x0000011d, 0x0000011e, 0x0000011f, 0x00000120, + 0x0004002b, 0x0000001f, 0x00000122, 0x00003425, 0x0004002b, 0x0000001f, 0x00000123, 0x00003450, + 0x0004002b, 0x0000001f, 0x00000124, 0x0000b0f4, 0x0004002b, 0x0000001f, 0x00000125, 0x0000b0ad, + 0x0007002c, 0x00000020, 0x00000126, 0x00000122, 0x00000123, 0x00000124, 0x00000125, 0x0007002c, + 0x00000021, 0x00000127, 0x00000117, 0x0000011c, 0x00000121, 0x00000126, 0x0004002b, 0x0000001f, + 0x00000128, 0x00003517, 0x0004002b, 0x0000001f, 0x00000129, 0x000034d2, 0x0004002b, 0x0000001f, + 0x0000012a, 0x0000b0da, 0x0004002b, 0x0000001f, 0x0000012b, 0x0000b123, 0x0007002c, 0x00000020, + 0x0000012c, 0x00000128, 0x00000129, 0x0000012a, 0x0000012b, 0x0004002b, 0x0000001f, 0x0000012d, + 0x0000b6d7, 0x0004002b, 0x0000001f, 0x0000012e, 0x0000b72a, 0x0004002b, 0x0000001f, 0x0000012f, + 0x000033b8, 0x0004002b, 0x0000001f, 0x00000130, 0x0000337c, 0x0007002c, 0x00000020, 0x00000131, + 0x0000012d, 0x0000012e, 0x0000012f, 0x00000130, 0x0004002b, 0x0000001f, 0x00000132, 0x00003237, + 0x0004002b, 0x0000001f, 0x00000133, 0x00003203, 0x0004002b, 0x0000001f, 0x00000134, 0x00003501, + 0x0004002b, 0x0000001f, 0x00000135, 0x000034e7, 0x0007002c, 0x00000020, 0x00000136, 0x00000132, + 0x00000133, 0x00000134, 0x00000135, 0x0004002b, 0x0000001f, 0x00000137, 0x0000360f, 0x0004002b, + 0x0000001f, 0x00000138, 0x0000359f, 0x0004002b, 0x0000001f, 0x00000139, 0x00002b9f, 0x0004002b, + 0x0000001f, 0x0000013a, 0x00002c06, 0x0007002c, 0x00000020, 0x0000013b, 0x00000137, 0x00000138, + 0x00000139, 0x0000013a, 0x0007002c, 0x00000021, 0x0000013c, 0x0000012c, 0x00000131, 0x00000136, + 0x0000013b, 0x0004002b, 0x0000001f, 0x0000013d, 0x0000366b, 0x0004002b, 0x0000001f, 0x0000013e, + 0x00003678, 0x0004002b, 0x0000001f, 0x0000013f, 0x00009b7c, 0x0004002b, 0x0000001f, 0x00000140, + 0x0000a57b, 0x0007002c, 0x00000020, 0x00000141, 0x0000013d, 0x0000013e, 0x0000013f, 0x00000140, + 0x0004002b, 0x0000001f, 0x00000142, 0x0000ba51, 0x0004002b, 0x0000001f, 0x00000143, 0x0000b954, + 0x0004002b, 0x0000001f, 0x00000144, 0x000034c5, 0x0004002b, 0x0000001f, 0x00000145, 0x0000349f, + 0x0007002c, 0x00000020, 0x00000146, 0x00000142, 0x00000143, 0x00000144, 0x00000145, 0x0004002b, + 0x0000001f, 0x00000147, 0x000035a4, 0x0004002b, 0x0000001f, 0x00000148, 0x0000357d, 0x0004002b, + 0x0000001f, 0x00000149, 0x000035f3, 0x0004002b, 0x0000001f, 0x0000014a, 0x0000358a, 0x0007002c, + 0x00000020, 0x0000014b, 0x00000147, 0x00000148, 0x00000149, 0x0000014a, 0x0004002b, 0x0000001f, + 0x0000014c, 0x00003741, 0x0004002b, 0x0000001f, 0x0000014d, 0x0000373b, 0x0004002b, 0x0000001f, + 0x0000014e, 0x00003551, 0x0007002c, 0x00000020, 0x0000014f, 0x0000014c, 0x0000014d, 0x0000008b, + 0x0000014e, 0x0007002c, 0x00000021, 0x00000150, 0x00000141, 0x00000146, 0x0000014b, 0x0000014f, + 0x0004002b, 0x0000001f, 0x00000151, 0x00003506, 0x0004002b, 0x0000001f, 0x00000152, 0x00003522, + 0x0004002b, 0x0000001f, 0x00000153, 0x0000b0d8, 0x0004002b, 0x0000001f, 0x00000154, 0x0000b0ee, + 0x0007002c, 0x00000020, 0x00000155, 0x00000151, 0x00000152, 0x00000153, 0x00000154, 0x0004002b, + 0x0000001f, 0x00000156, 0x0000b76a, 0x0004002b, 0x0000001f, 0x00000157, 0x0000b736, 0x0004002b, + 0x0000001f, 0x00000158, 0x00003334, 0x0004002b, 0x0000001f, 0x00000159, 0x00003329, 0x0007002c, + 0x00000020, 0x0000015a, 0x00000156, 0x00000157, 0x00000158, 0x00000159, 0x0004002b, 0x0000001f, + 0x0000015b, 0x00003357, 0x0004002b, 0x0000001f, 0x0000015c, 0x000032e4, 0x0004002b, 0x0000001f, + 0x0000015d, 0x0000347f, 0x0004002b, 0x0000001f, 0x0000015e, 0x0000349a, 0x0007002c, 0x00000020, + 0x0000015f, 0x0000015b, 0x0000015c, 0x0000015d, 0x0000015e, 0x0004002b, 0x0000001f, 0x00000160, + 0x000035c7, 0x0004002b, 0x0000001f, 0x00000161, 0x0000351e, 0x0004002b, 0x0000001f, 0x00000162, + 0x00002a4e, 0x0004002b, 0x0000001f, 0x00000163, 0x00002aee, 0x0007002c, 0x00000020, 0x00000164, + 0x00000160, 0x00000161, 0x00000162, 0x00000163, 0x0007002c, 0x00000021, 0x00000165, 0x00000155, + 0x0000015a, 0x0000015f, 0x00000164, 0x0004002b, 0x0000001f, 0x00000166, 0x000032f7, 0x0004002b, + 0x0000001f, 0x00000167, 0x0000333f, 0x0004002b, 0x0000001f, 0x00000168, 0x0000b454, 0x0004002b, + 0x0000001f, 0x00000169, 0x0000b432, 0x0007002c, 0x00000020, 0x0000016a, 0x00000166, 0x00000167, + 0x00000168, 0x00000169, 0x0004002b, 0x0000001f, 0x0000016b, 0x0000b5ec, 0x0004002b, 0x0000001f, + 0x0000016c, 0x0000b779, 0x0004002b, 0x0000001f, 0x0000016d, 0x0000311a, 0x0004002b, 0x0000001f, + 0x0000016e, 0x00003166, 0x0007002c, 0x00000020, 0x0000016f, 0x0000016b, 0x0000016c, 0x0000016d, + 0x0000016e, 0x0004002b, 0x0000001f, 0x00000170, 0x00002bfe, 0x0004002b, 0x0000001f, 0x00000171, + 0x00002cbf, 0x0004002b, 0x0000001f, 0x00000172, 0x0000340f, 0x0004002b, 0x0000001f, 0x00000173, + 0x00003426, 0x0007002c, 0x00000020, 0x00000174, 0x00000170, 0x00000171, 0x00000172, 0x00000173, + 0x0004002b, 0x0000001f, 0x00000175, 0x0000347d, 0x0004002b, 0x0000001f, 0x00000176, 0x00003454, + 0x0004002b, 0x0000001f, 0x00000177, 0x0000b2c2, 0x0004002b, 0x0000001f, 0x00000178, 0x0000b329, + 0x0007002c, 0x00000020, 0x00000179, 0x00000175, 0x00000176, 0x00000177, 0x00000178, 0x0007002c, + 0x00000021, 0x0000017a, 0x0000016a, 0x0000016f, 0x00000174, 0x00000179, 0x0004002b, 0x0000001f, + 0x0000017b, 0x0000348c, 0x0004002b, 0x0000001f, 0x0000017c, 0x0000b024, 0x0004002b, 0x0000001f, + 0x0000017d, 0x0000b048, 0x0007002c, 0x00000020, 0x0000017e, 0x00000144, 0x0000017b, 0x0000017c, + 0x0000017d, 0x0004002b, 0x0000001f, 0x0000017f, 0x0000b987, 0x0004002b, 0x0000001f, 0x00000180, + 0x0000b8f3, 0x0004002b, 0x0000001f, 0x00000181, 0x0000339e, 0x0004002b, 0x0000001f, 0x00000182, + 0x0000336a, 0x0007002c, 0x00000020, 0x00000183, 0x0000017f, 0x00000180, 0x00000181, 0x00000182, + 0x0004002b, 0x0000001f, 0x00000184, 0x00003430, 0x0004002b, 0x0000001f, 0x00000185, 0x00003460, + 0x0004002b, 0x0000001f, 0x00000186, 0x000034b2, 0x0004002b, 0x0000001f, 0x00000187, 0x000034b1, + 0x0007002c, 0x00000020, 0x00000188, 0x00000184, 0x00000185, 0x00000186, 0x00000187, 0x0004002b, + 0x0000001f, 0x00000189, 0x0000358f, 0x0004002b, 0x0000001f, 0x0000018a, 0x00003591, 0x0004002b, + 0x0000001f, 0x0000018b, 0x00002961, 0x0004002b, 0x0000001f, 0x0000018c, 0x00002a36, 0x0007002c, + 0x00000020, 0x0000018d, 0x00000189, 0x0000018a, 0x0000018b, 0x0000018c, 0x0007002c, 0x00000021, + 0x0000018e, 0x0000017e, 0x00000183, 0x00000188, 0x0000018d, 0x0004002b, 0x0000001f, 0x0000018f, + 0x00003264, 0x0004002b, 0x0000001f, 0x00000190, 0x0000b340, 0x0004002b, 0x0000001f, 0x00000191, + 0x0000b374, 0x0007002c, 0x00000020, 0x00000192, 0x00000041, 0x0000018f, 0x00000190, 0x00000191, + 0x0004002b, 0x0000001f, 0x00000193, 0x0000b5d3, 0x0004002b, 0x0000001f, 0x00000194, 0x0000b6c4, + 0x0004002b, 0x0000001f, 0x00000195, 0x0000310a, 0x0004002b, 0x0000001f, 0x00000196, 0x00003109, + 0x0007002c, 0x00000020, 0x00000197, 0x00000193, 0x00000194, 0x00000195, 0x00000196, 0x0004002b, + 0x0000001f, 0x00000198, 0x00002f05, 0x0004002b, 0x0000001f, 0x00000199, 0x00002e14, 0x0004002b, + 0x0000001f, 0x0000019a, 0x00003355, 0x0007002c, 0x00000020, 0x0000019b, 0x00000198, 0x00000199, + 0x00000130, 0x0000019a, 0x0004002b, 0x0000001f, 0x0000019c, 0x00003440, 0x0004002b, 0x0000001f, + 0x0000019d, 0x00003421, 0x0004002b, 0x0000001f, 0x0000019e, 0x0000b20c, 0x0007002c, 0x00000020, + 0x0000019f, 0x0000019c, 0x0000019d, 0x0000019e, 0x0000019e, 0x0007002c, 0x00000021, 0x000001a0, + 0x00000192, 0x00000197, 0x0000019b, 0x0000019f, 0x0004002b, 0x0000001f, 0x000001a1, 0x000035cb, + 0x0004002b, 0x0000001f, 0x000001a2, 0x00003733, 0x0004002b, 0x0000001f, 0x000001a3, 0x0000316e, + 0x0004002b, 0x0000001f, 0x000001a4, 0x000032f6, 0x0007002c, 0x00000020, 0x000001a5, 0x000001a1, + 0x000001a2, 0x000001a3, 0x000001a4, 0x0004003b, 0x00000018, 0x00000007, 0x00000000, 0x0004002b, + 0x0000000d, 0x000001a6, 0x00000010, 0x0006002c, 0x0000000e, 0x00000008, 0x000001a6, 0x000001a6, + 0x0000001e, 0x00050036, 0x00000009, 0x00000002, 0x00000000, 0x0000000a, 0x000200f8, 0x000001a7, + 0x000300f7, 0x000001a8, 0x00000000, 0x000300fb, 0x0000001d, 0x000001a9, 0x000200f8, 0x000001a9, + 0x0004003d, 0x0000000e, 0x000001aa, 0x00000003, 0x0007004f, 0x00000010, 0x000001ab, 0x000001aa, + 0x000001aa, 0x00000000, 0x00000001, 0x0004007c, 0x0000000c, 0x000001ac, 0x000001ab, 0x0004003d, + 0x00000012, 0x000001ad, 0x00000004, 0x00040068, 0x0000000c, 0x000001ae, 0x000001ad, 0x000500af, + 0x00000015, 0x000001af, 0x000001ac, 0x000001ae, 0x0004009a, 0x00000014, 0x000001b0, 0x000001af, + 0x000300f7, 0x000001b1, 0x00000000, 0x000400fa, 0x000001b0, 0x000001b2, 0x000001b1, 0x000200f8, + 0x000001b2, 0x000200f9, 0x000001a8, 0x000200f8, 0x000001b1, 0x0004003d, 0x00000017, 0x000001b3, + 0x00000005, 0x00040064, 0x00000016, 0x000001b4, 0x000001b3, 0x00050067, 0x0000000c, 0x000001b5, + 0x000001b4, 0x00000019, 0x0004007c, 0x00000010, 0x000001b6, 0x000001b5, 0x00040070, 0x0000001a, + 0x000001b7, 0x000001ab, 0x00050081, 0x0000001a, 0x000001b8, 0x000001b7, 0x0000001c, 0x00050051, + 0x0000000d, 0x000001b9, 0x000001b6, 0x00000000, 0x00040070, 0x00000011, 0x000001ba, 0x000001b9, + 0x00050051, 0x0000000d, 0x000001bb, 0x000001b6, 0x00000001, 0x00040070, 0x00000011, 0x000001bc, + 0x000001bb, 0x00050050, 0x0000001a, 0x000001bd, 0x000001ba, 0x000001bc, 0x00050088, 0x0000001a, + 0x000001be, 0x000001b8, 0x000001bd, 0x0004003d, 0x00000017, 0x000001bf, 0x00000005, 0x00080058, + 0x0000003a, 0x000001c0, 0x000001bf, 0x000001be, 0x0000000a, 0x00000037, 0x00000039, 0x00040073, + 0x00000020, 0x000001c1, 0x000001c0, 0x00050091, 0x00000020, 0x000001c2, 0x00000036, 0x000001c1, + 0x0004003d, 0x00000017, 0x000001c3, 0x00000005, 0x00080058, 0x0000003a, 0x000001c4, 0x000001c3, + 0x000001be, 0x0000000a, 0x00000037, 0x00000050, 0x00040073, 0x00000020, 0x000001c5, 0x000001c4, + 0x00050091, 0x00000020, 0x000001c6, 0x0000004f, 0x000001c5, 0x00050081, 0x00000020, 0x000001c7, + 0x000001c2, 0x000001c6, 0x0004003d, 0x00000017, 0x000001c8, 0x00000005, 0x00080058, 0x0000003a, + 0x000001c9, 0x000001c8, 0x000001be, 0x0000000a, 0x00000037, 0x00000067, 0x00040073, 0x00000020, + 0x000001ca, 0x000001c9, 0x00050091, 0x00000020, 0x000001cb, 0x00000065, 0x000001ca, 0x00050081, + 0x00000020, 0x000001cc, 0x000001c7, 0x000001cb, 0x0004003d, 0x00000017, 0x000001cd, 0x00000005, + 0x00080058, 0x0000003a, 0x000001ce, 0x000001cd, 0x000001be, 0x0000000a, 0x00000037, 0x0000007d, + 0x00040073, 0x00000020, 0x000001cf, 0x000001ce, 0x00050091, 0x00000020, 0x000001d0, 0x0000007c, + 0x000001cf, 0x00050081, 0x00000020, 0x000001d1, 0x000001cc, 0x000001d0, 0x0004003d, 0x00000017, + 0x000001d2, 0x00000005, 0x00070058, 0x0000003a, 0x000001d3, 0x000001d2, 0x000001be, 0x00000002, + 0x00000037, 0x00040073, 0x00000020, 0x000001d4, 0x000001d3, 0x00050091, 0x00000020, 0x000001d5, + 0x00000092, 0x000001d4, 0x00050081, 0x00000020, 0x000001d6, 0x000001d1, 0x000001d5, 0x0004003d, + 0x00000017, 0x000001d7, 0x00000005, 0x00080058, 0x0000003a, 0x000001d8, 0x000001d7, 0x000001be, + 0x0000000a, 0x00000037, 0x000000a8, 0x00040073, 0x00000020, 0x000001d9, 0x000001d8, 0x00050091, + 0x00000020, 0x000001da, 0x000000a7, 0x000001d9, 0x00050081, 0x00000020, 0x000001db, 0x000001d6, + 0x000001da, 0x0004003d, 0x00000017, 0x000001dc, 0x00000005, 0x00080058, 0x0000003a, 0x000001dd, + 0x000001dc, 0x000001be, 0x0000000a, 0x00000037, 0x000000be, 0x00040073, 0x00000020, 0x000001de, + 0x000001dd, 0x00050091, 0x00000020, 0x000001df, 0x000000bd, 0x000001de, 0x00050081, 0x00000020, + 0x000001e0, 0x000001db, 0x000001df, 0x0004003d, 0x00000017, 0x000001e1, 0x00000005, 0x00080058, + 0x0000003a, 0x000001e2, 0x000001e1, 0x000001be, 0x0000000a, 0x00000037, 0x000000d3, 0x00040073, + 0x00000020, 0x000001e3, 0x000001e2, 0x00050091, 0x00000020, 0x000001e4, 0x000000d2, 0x000001e3, + 0x00050081, 0x00000020, 0x000001e5, 0x000001e0, 0x000001e4, 0x0004003d, 0x00000017, 0x000001e6, + 0x00000005, 0x00080058, 0x0000003a, 0x000001e7, 0x000001e6, 0x000001be, 0x0000000a, 0x00000037, + 0x000000e9, 0x00040073, 0x00000020, 0x000001e8, 0x000001e7, 0x00050091, 0x00000020, 0x000001e9, + 0x000000e8, 0x000001e8, 0x00050081, 0x00000020, 0x000001ea, 0x000001e5, 0x000001e9, 0x0004003d, + 0x00000017, 0x000001eb, 0x00000006, 0x00080058, 0x0000003a, 0x000001ec, 0x000001eb, 0x000001be, + 0x0000000a, 0x00000037, 0x00000039, 0x00040073, 0x00000020, 0x000001ed, 0x000001ec, 0x00050091, + 0x00000020, 0x000001ee, 0x000000fe, 0x000001ed, 0x00050081, 0x00000020, 0x000001ef, 0x000001ea, + 0x000001ee, 0x0004003d, 0x00000017, 0x000001f0, 0x00000006, 0x00080058, 0x0000003a, 0x000001f1, + 0x000001f0, 0x000001be, 0x0000000a, 0x00000037, 0x00000050, 0x00040073, 0x00000020, 0x000001f2, + 0x000001f1, 0x00050091, 0x00000020, 0x000001f3, 0x00000112, 0x000001f2, 0x00050081, 0x00000020, + 0x000001f4, 0x000001ef, 0x000001f3, 0x0004003d, 0x00000017, 0x000001f5, 0x00000006, 0x00080058, + 0x0000003a, 0x000001f6, 0x000001f5, 0x000001be, 0x0000000a, 0x00000037, 0x00000067, 0x00040073, + 0x00000020, 0x000001f7, 0x000001f6, 0x00050091, 0x00000020, 0x000001f8, 0x00000127, 0x000001f7, + 0x00050081, 0x00000020, 0x000001f9, 0x000001f4, 0x000001f8, 0x0004003d, 0x00000017, 0x000001fa, + 0x00000006, 0x00080058, 0x0000003a, 0x000001fb, 0x000001fa, 0x000001be, 0x0000000a, 0x00000037, + 0x0000007d, 0x00040073, 0x00000020, 0x000001fc, 0x000001fb, 0x00050091, 0x00000020, 0x000001fd, + 0x0000013c, 0x000001fc, 0x00050081, 0x00000020, 0x000001fe, 0x000001f9, 0x000001fd, 0x0004003d, + 0x00000017, 0x000001ff, 0x00000006, 0x00070058, 0x0000003a, 0x00000200, 0x000001ff, 0x000001be, + 0x00000002, 0x00000037, 0x00040073, 0x00000020, 0x00000201, 0x00000200, 0x00050091, 0x00000020, + 0x00000202, 0x00000150, 0x00000201, 0x00050081, 0x00000020, 0x00000203, 0x000001fe, 0x00000202, + 0x0004003d, 0x00000017, 0x00000204, 0x00000006, 0x00080058, 0x0000003a, 0x00000205, 0x00000204, + 0x000001be, 0x0000000a, 0x00000037, 0x000000a8, 0x00040073, 0x00000020, 0x00000206, 0x00000205, + 0x00050091, 0x00000020, 0x00000207, 0x00000165, 0x00000206, 0x00050081, 0x00000020, 0x00000208, + 0x00000203, 0x00000207, 0x0004003d, 0x00000017, 0x00000209, 0x00000006, 0x00080058, 0x0000003a, + 0x0000020a, 0x00000209, 0x000001be, 0x0000000a, 0x00000037, 0x000000be, 0x00040073, 0x00000020, + 0x0000020b, 0x0000020a, 0x00050091, 0x00000020, 0x0000020c, 0x0000017a, 0x0000020b, 0x00050081, + 0x00000020, 0x0000020d, 0x00000208, 0x0000020c, 0x0004003d, 0x00000017, 0x0000020e, 0x00000006, + 0x00080058, 0x0000003a, 0x0000020f, 0x0000020e, 0x000001be, 0x0000000a, 0x00000037, 0x000000d3, + 0x00040073, 0x00000020, 0x00000210, 0x0000020f, 0x00050091, 0x00000020, 0x00000211, 0x0000018e, + 0x00000210, 0x00050081, 0x00000020, 0x00000212, 0x0000020d, 0x00000211, 0x0004003d, 0x00000017, + 0x00000213, 0x00000006, 0x00080058, 0x0000003a, 0x00000214, 0x00000213, 0x000001be, 0x0000000a, + 0x00000037, 0x000000e9, 0x00040073, 0x00000020, 0x00000215, 0x00000214, 0x00050091, 0x00000020, + 0x00000216, 0x000001a0, 0x00000215, 0x00050081, 0x00000020, 0x00000217, 0x00000212, 0x00000216, + 0x00050081, 0x00000020, 0x00000218, 0x00000217, 0x000001a5, 0x0004003d, 0x00000017, 0x00000219, + 0x00000007, 0x00070058, 0x0000003a, 0x0000021a, 0x00000219, 0x000001be, 0x00000002, 0x00000037, + 0x00040073, 0x00000020, 0x0000021b, 0x0000021a, 0x00050081, 0x00000020, 0x0000021c, 0x00000218, + 0x0000021b, 0x0004003d, 0x00000012, 0x0000021d, 0x00000004, 0x00040073, 0x0000003a, 0x0000021e, + 0x0000021c, 0x00040063, 0x0000021d, 0x000001ac, 0x0000021e, 0x000200f9, 0x000001a8, 0x000200f8, + 0x000001a8, 0x000100fd, 0x00010038, +}; +static const size_t wnfg_53_spv_size = sizeof(wnfg_53_spv); diff --git a/app/src/main/feature/settings/other/OtherSettingsFragment.kt b/app/src/main/feature/settings/other/OtherSettingsFragment.kt index 79fa30188..e902b911d 100644 --- a/app/src/main/feature/settings/other/OtherSettingsFragment.kt +++ b/app/src/main/feature/settings/other/OtherSettingsFragment.kt @@ -151,6 +151,10 @@ class OtherSettingsFragment : Fragment() { preferences.edit { putBoolean("xinput_toggle", checked) } refresh() }, + onNativeFrameGenChanged = { checked -> + preferences.edit { putBoolean("native_frame_generation", checked) } + refresh() + }, onEnableFileProviderChanged = { checked -> preferences.edit { putBoolean("enable_file_provider", checked) } WinToast.show(ctx, R.string.settings_general_take_effect_next_startup) @@ -238,6 +242,7 @@ class OtherSettingsFragment : Fragment() { cursorLock = preferences.getBoolean("cursor_lock", false), xinputDisabled = preferences.getBoolean("xinput_toggle", false), + nativeFrameGen = preferences.getBoolean("native_frame_generation", false), enableAutoScraping = preferences.getBoolean("enable_auto_scraping", false), enableFileProvider = preferences.getBoolean("enable_file_provider", true), openInBrowser = preferences.getBoolean("open_with_android_browser", false), diff --git a/app/src/main/feature/settings/other/OtherSettingsScreen.kt b/app/src/main/feature/settings/other/OtherSettingsScreen.kt index a98a38274..9a3060ac6 100644 --- a/app/src/main/feature/settings/other/OtherSettingsScreen.kt +++ b/app/src/main/feature/settings/other/OtherSettingsScreen.kt @@ -106,6 +106,7 @@ data class OtherSettingsState( val cursorSpeedPercent: Int = 100, val cursorLock: Boolean = false, val xinputDisabled: Boolean = false, + val nativeFrameGen: Boolean = false, val enableFileProvider: Boolean = true, val enableAutoScraping: Boolean = false, val openInBrowser: Boolean = false, @@ -150,6 +151,7 @@ fun OtherSettingsScreen( onCursorSpeedChanged: (Int) -> Unit, onCursorLockChanged: (Boolean) -> Unit, onXinputDisabledChanged: (Boolean) -> Unit, + onNativeFrameGenChanged: (Boolean) -> Unit, onEnableFileProviderChanged: (Boolean) -> Unit, onAutoScrapingChanged: (Boolean) -> Unit, onOpenInBrowserChanged: (Boolean) -> Unit, @@ -270,6 +272,14 @@ fun OtherSettingsScreen( onCheckedChange = onExternalDisplayOutputChanged, ) + SettingsToggleCard( + title = stringResource(R.string.settings_other_frame_gen_title), + subtitle = stringResource(R.string.settings_other_frame_gen_summary), + icon = Icons.Outlined.Speed, + checked = state.nativeFrameGen, + onCheckedChange = onNativeFrameGenChanged, + ) + SectionLabel(stringResource(R.string.settings_other_section_integration), modifier = Modifier.padding(top = 8.dp)) SettingsToggleCard( diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 7c2bc7ae8..8d381490c 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -1492,6 +1492,15 @@ Installeret sti: Solfilter Lydstyrke Sendes direkte til dine Viture-briller via USB. + Frame Gen + Multiplikator + Kvalitetsforudindstilling + Ydelse + Balanceret + Kvalitet + Jævnhed + Native Frame Generation + Indsæt interpolerede frames i compositoren for at gøre bevægelser mere flydende. Virker med alle spil (ingen spildata nødvendig) og tilføjer en smule input-latens. Ny diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 303dbfa8e..044c280e0 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -1492,6 +1492,15 @@ Installierter Pfad: Sonnenschutz Lautstärke Direkt per USB an deine Viture-Brille gesendet. + Frame Gen + Multiplikator + Qualitätsvoreinstellung + Leistung + Ausgewogen + Qualität + Glättung + Native Frame Generation + Fügt im Compositor interpolierte Zwischenbilder ein, um Bewegungen flüssiger darzustellen. Funktioniert mit jedem Spiel (keine Spieldaten erforderlich) und erhöht die Eingabelatenz geringfügig. Neu diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 5cc622090..0a7076bbe 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -1492,6 +1492,15 @@ Ruta instalada: Filtro solar Volumen Se envía directamente a tus gafas Viture por USB. + Frame Gen + Multiplicador + Perfil de calidad + Rendimiento + Equilibrado + Calidad + Suavidad + Generación de fotogramas nativa + Inserta fotogramas interpolados en el compositor para suavizar el movimiento. Funciona con cualquier juego (sin necesidad de datos del juego) y añade una pequeña cantidad de latencia de entrada. Nuevo diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index e8865ddbc..09981240e 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -1492,6 +1492,15 @@ Chemin installé : Filtre solaire Volume Envoyé directement à vos lunettes Viture via USB. + Frame Gen + Multiplicateur + Préréglage de qualité + Performance + Équilibré + Qualité + Fluidité + Génération d\'images native + Insère des images interpolées dans le compositeur pour fluidifier les mouvements. Compatible avec tous les jeux (aucune donnée de jeu requise) et ajoute une légère latence d\'entrée. Nouveau diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 63edff4cd..291b7c38d 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -1430,6 +1430,15 @@ वॉल्यूम USB के माध्यम से सीधे आपके Viture ग्लासेस पर भेजा गया। + फ्रेम जेन + मल्टीप्लायर + क्वालिटी प्रीसेट + परफॉर्मेंस + बैलेंस्ड + क्वालिटी + स्मूदनेस + नेटिव फ्रेम जनरेशन + मोशन को स्मूद बनाने के लिए कंपोजिटर में इंटरपोलेटेड फ्रेम जोड़ें। यह किसी भी गेम के साथ काम करता है (किसी गेम डेटा की ज़रूरत नहीं) और इनपुट लेटेंसी थोड़ी बढ़ा देता है। नया नाम बदलें जेस्चर प्रोफ़ाइल निर्यात करें diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 99e2cf56c..919a8aabc 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -1492,6 +1492,15 @@ Percorso installato: Filtro solare Volume Inviato direttamente ai tuoi occhiali Viture via USB. + Frame Gen + Moltiplicatore + Preset qualità + Prestazioni + Bilanciato + Qualità + Fluidità + Frame Generation nativa + Inserisce frame interpolati nel compositor per rendere il movimento più fluido. Funziona con qualsiasi gioco (senza bisogno dei dati del gioco) e aggiunge una piccola quantità di latenza di input. Nuovo diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 3d9dd0d1c..1e98e2f71 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -1493,6 +1493,15 @@ 햇빛 차단 볼륨 USB로 Viture 글래스에 직접 전송됩니다. + 프레임 생성 + 배수 + 품질 프리셋 + 성능 + 균형 + 품질 + 부드러움 + 네이티브 프레임 생성 + 컴포지터에서 보간 프레임을 삽입하여 움직임을 부드럽게 만듭니다. 모든 게임에서 작동하며(게임 데이터가 필요 없음) 약간의 입력 지연이 추가됩니다. 새로 만들기 diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 33f7e49df..9a04b216b 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -1498,6 +1498,15 @@ Zainstalowana ścieżka: Filtr słoneczny Głośność Wysyłane bezpośrednio do okularów Viture przez USB. + Gen. klatek + Mnożnik + Ustawienie jakości + Wydajność + Zrównoważone + Jakość + Płynność + Natywne generowanie klatek (Frame Generation) + Wstawia interpolowane klatki w kompozytorze, aby wygładzić ruch. Działa z każdą grą (nie wymaga danych gry) i nieznacznie zwiększa opóźnienie sterowania. Nowy diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 144328d65..e0cf92d15 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -1492,6 +1492,15 @@ Caminho instalado: Bloqueio solar Volume Enviado diretamente para seus óculos Viture via USB. + Geração de Quadros + Multiplicador + Predefinição de qualidade + Desempenho + Equilibrado + Qualidade + Suavidade + Geração de Quadros Nativa + Insere quadros interpolados no compositor para suavizar o movimento. Funciona com qualquer jogo (não precisa de dados do jogo) e adiciona uma pequena quantidade de latência de entrada. Novo diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 2577a0474..502da2697 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -1493,6 +1493,15 @@ Cale instalata: Volum Trimis direct la ochelarii Viture prin USB. + Gen. cadre + Multiplicator + Presetare de calitate + Performanță + Echilibrat + Calitate + Fluiditate + Generare nativă de cadre (Frame Generation) + Inserează cadre interpolate în compozitor pentru a fluidiza mișcarea. Funcționează cu orice joc (nu necesită date despre joc) și adaugă o cantitate mică de latență a comenzilor. Nou Redenumește Exportă profilul de gesturi diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index d63098f20..6c7883989 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -1399,6 +1399,15 @@ Громкость Отправляется напрямую на очки Viture по USB. + Кадры + Множитель + Пресет качества + Производительность + Сбалансированный + Качество + Плавность + Нативная генерация кадров + Вставка интерполированных кадров в композиторе для плавности движения. Работает с любой игрой (данные игры не нужны) и немного увеличивает задержку ввода. Создать Переименовать diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index aa2251751..845b48854 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -1498,6 +1498,15 @@ Світлофільтр Гучність Надсилається напряму на окуляри Viture через USB. + Кадри + Множник + Налаштування якості + Продуктивність + Збалансовано + Якість + Плавність + Нативна генерація кадрів + Вставляє інтерпольовані кадри в композитор для плавнішого руху. Працює з будь-якою грою (дані гри не потрібні) та трохи збільшує затримку вводу. Створити diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index fb359c30b..d2019eac2 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -1492,6 +1492,15 @@ 遮光 音量 通过 USB 直接发送到你的 Viture 眼镜。 + 帧生成 + 倍率 + 质量预设 + 性能 + 均衡 + 质量 + 流畅度 + 原生帧生成 + 在合成器中插入插值帧以使画面运动更流畅。适用于任何游戏(无需游戏数据),并会增加少量输入延迟。 新建 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 6312633aa..b5e31861a 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -1493,6 +1493,15 @@ 音量 透過 USB 直接傳送到你的 Viture 眼鏡。 + 生成幀 + 倍率 + 品質預設 + 效能 + 平衡 + 品質 + 流暢度 + 原生畫格生成 + 在合成器中插入內插畫格以使動態更流暢。適用於任何遊戲(無需遊戲資料),並會略微增加輸入延遲。 新增 重新命名 匯出手勢設定檔 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 364f9c208..4e511dfb0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1624,6 +1624,18 @@ Installed path: Auto-Hide Fade the chat head after 10s of inactivity Friends + Frame Gen + Multiplier + Quality preset + Performance + Balanced + Quality + Smoothness + Recommended + Smooth + Low Latency + Native Frame Generation + Insert interpolated frames in the compositor to smooth motion. Works with any game (no game data needed) and adds a small amount of input latency. Files Copy diff --git a/app/src/main/runtime/display/XServerDisplayActivity.java b/app/src/main/runtime/display/XServerDisplayActivity.java index 2cb2caa38..6b6f207e5 100644 --- a/app/src/main/runtime/display/XServerDisplayActivity.java +++ b/app/src/main/runtime/display/XServerDisplayActivity.java @@ -283,6 +283,7 @@ public class XServerDisplayActivity extends FixedFontScaleAppCompatActivity { private android.hardware.input.InputManager.InputDeviceListener hudControllerListener; private boolean isTapToClickEnabled = true; private int runtimeFpsLimit = 0; + private float lastLoggedRefreshHz = 0f; // de-dupes the periodic physical-refresh self-log private String lastRendererName = "Vulkan"; private String lastGpuName = null; private boolean gameWindowSeen; @@ -443,6 +444,53 @@ private boolean isAnyControllerConnected() { private boolean frametimeNumericMode = false; private boolean hudCardExpanded = false; private boolean screenEffectsCardExpanded = false; + private boolean frameGenerationEnabled = false; + // Frame generation settings persist per game (shortcut), not globally. + private String fgGameId() { + if (shortcut != null) { + String uuid = shortcut.getExtra("uuid", ""); + if (!uuid.isEmpty()) return "s:" + uuid; + String path = getIntent().getStringExtra("shortcut_path"); + if (path != null && !path.isEmpty()) return "p:" + Integer.toHexString(path.hashCode()); + } + return container != null ? "c:" + container.id : "g"; + } + + private String fgKey(String base) { + return base + ":" + fgGameId(); + } + + private boolean fgPrefBool(String base, boolean def) { + String k = fgKey(base); + if (preferences.contains(k)) return preferences.getBoolean(k, def); + return preferences.getBoolean(base, def); + } + + private int fgPrefInt(String base, int def) { + String k = fgKey(base); + if (preferences.contains(k)) return preferences.getInt(k, def); + return preferences.getInt(base, def); + } + + private float fgPrefFloat(String base, float def) { + String k = fgKey(base); + if (preferences.contains(k)) return preferences.getFloat(k, def); + return preferences.getFloat(base, def); + } + + private int frameGenerationMultiplier = 2; + private int frameGenerationQuality = 1; + private float frameGenerationSmoothing = 0.75f; + private boolean frameGenerationDeepMode = true; + private boolean frameGenerationAdvanced = false; + private boolean frameGenerationExtrapolate = false; + private int frameGenerationFramesInFlight = 3; + private int frameGenerationPreset = 2; // Eco/Flow/Bal/Boost/Clear/Max + private int frameGenerationModel = 0; // 0 = standard, 1 = steadier + private static final int[] FG_PRESET_QUALITY = {0, 1, 1, 2, 1, 2}; + private static final int[] FG_PRESET_MODEL = {0, 0, 0, 0, 1, 1}; + private static final float[] FG_PRESET_FLOW_SCALE = {0.20f, 0.22f, 0.25f, 0.28f, 0.25f, 0.30f}; + private static final boolean[] FG_PRESET_DEEP = {false, false, false, false, false, true}; private boolean sgsrEnabled = false; private boolean sgsrRuntimeEnabled = false; private int sgsrUpscaleMode = 1; @@ -900,11 +948,30 @@ private String getShortcutWineVersionOverride() { return shortcut.getExtra("wineVersion"); } + // Debounce FG target changes into a single panel re-pin once the rate settles. + private final Runnable fgRepinRunnable = this::applyPreferredRefreshRate; + + private void scheduleFgRefreshRepin() { + Handler h = handler; + if (h == null) { applyPreferredRefreshRate(); return; } + h.removeCallbacks(fgRepinRunnable); + h.postDelayed(fgRepinRunnable, 600L); + } + private void applyPreferredRefreshRate() { Runnable applyRefresh = () -> { if (isFinishing() || isDestroyed()) return; - RefreshRateUtils.applyPreferredRefreshRate(this, getRefreshRateOverride(), runtimeFpsLimit); + VulkanRenderer renderer = xServerView != null ? xServerView.getRenderer() : null; + if (renderer != null && renderer.isFrameGenerationEnabled()) { + int panelMax = RefreshRateUtils.getMaxSupportedRefreshRate(this); + renderer.setFrameGenDisplayCap(panelMax); + RefreshRateUtils.applyPreferredRefreshRate(this, panelMax, panelMax); + requestSurfaceFrameRate((float) panelMax); + lastLoggedRefreshHz = 0f; + } else { + RefreshRateUtils.applyPreferredRefreshRate(this, getRefreshRateOverride(), runtimeFpsLimit); + } }; if (Looper.myLooper() == Looper.getMainLooper()) { @@ -914,6 +981,32 @@ private void applyPreferredRefreshRate() { } } + private void requestSurfaceFrameRate(float hz) { + if (hz <= 0f || Build.VERSION.SDK_INT < Build.VERSION_CODES.R || xServerView == null) return; + try { + android.view.Surface s = xServerView.getHolder().getSurface(); + if (s == null || !s.isValid()) return; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + s.setFrameRate(hz, android.view.Surface.FRAME_RATE_COMPATIBILITY_DEFAULT, + android.view.Surface.CHANGE_FRAME_RATE_ALWAYS); + } else { + s.setFrameRate(hz, android.view.Surface.FRAME_RATE_COMPATIBILITY_DEFAULT); + } + } catch (Exception ignore) {} + } + + private void logCurrentRefreshRate(String from) { + try { + android.view.Display d = getWindow().getDecorView().getDisplay(); + if (d == null) return; + float hz = d.getMode().getRefreshRate(); + if (Math.abs(hz - lastLoggedRefreshHz) < 0.5f) return; + lastLoggedRefreshHz = hz; + Log.i("XServerDisplayActivity", "Physical display refresh now " + Math.round(hz) + + "Hz (modeId=" + d.getMode().getModeId() + ", " + from + ")"); + } catch (Exception ignore) {} + } + /** Watch for display refresh-rate / mode changes while a game runs so the FPS-limiter ceiling and chosen limit aren't stranded above what the panel can present. */ private void registerDisplayChangeListener() { if (displayListener != null) return; @@ -933,6 +1026,7 @@ public void onDisplayRemoved(int displayId) { @Override public void onDisplayChanged(int displayId) { + logCurrentRefreshRate("onDisplayChanged"); handleDisplayCapabilitiesChanged(); } }; @@ -4095,6 +4189,8 @@ private void handleNavigationBackPressed() { private void openDrawerMenu() { releasePointerCapture(); + if (xServerView != null && xServerView.getRenderer() != null) + xServerView.getRenderer().fgSetOverlayActive(true); renderDrawerMenu(); if (drawerStateHolder != null) { drawerStateHolder.openDrawer(); @@ -4108,9 +4204,21 @@ private void closeDrawerMenu() { if (drawerStateHolder != null) { drawerStateHolder.closeDrawer(); } + if (xServerView != null && xServerView.getRenderer() != null) + xServerView.getRenderer().fgSetOverlayActive(false); tryCapturePointer(); } + // Safety net for the drawer-open listener: resumes FG if a close path missed it. Idempotent. + @Override + public void onUserInteraction() { + super.onUserInteraction(); + if (drawerStateHolder == null || !drawerStateHolder.isDrawerOpen()) { + VulkanRenderer r = xServerView != null ? xServerView.getRenderer() : null; + if (r != null) r.fgClearOverlayIfActive(); + } + } + private String currentGyroActivatorLabel() { String[] names = getResources().getStringArray(R.array.button_options); int[] keycodes = getResources().getIntArray(R.array.button_keycodes); @@ -4244,6 +4352,15 @@ private void renderDrawerMenu() { xServerView != null && xServerView.getRenderer() != null && xServerView.getRenderer().isFullscreen(), RefreshRateUtils.getMaxSupportedRefreshRate(this), isRefactorSizeEnabled, + frameGenerationEnabled, + frameGenerationMultiplier, + frameGenerationQuality, + frameGenerationSmoothing, + frameGenerationDeepMode, + frameGenerationAdvanced, + frameGenerationExtrapolate, + frameGenerationFramesInFlight, + frameGenerationPreset, screenRecorder != null && screenRecorder.isRecording(), buildRecordConfig(), screenTouchMode, @@ -4543,6 +4660,101 @@ public void onScreenEffectsCardExpandedChanged(boolean expanded) { renderDrawerMenu(); } + @Override + public void onFrameGenerationEnabledChanged(boolean enabled) { + frameGenerationEnabled = enabled; + preferences.edit().putBoolean(fgKey("native_frame_generation"), enabled).apply(); + VulkanRenderer r = xServerView != null ? xServerView.getRenderer() : null; + if (r != null) r.setFrameGeneration(enabled); + applyPreferredRefreshRate(); + renderDrawerMenu(); + } + + @Override + public void onFrameGenerationMultiplierSelected(int multiplier) { + frameGenerationMultiplier = multiplier; + preferences.edit().putInt(fgKey("frame_generation_multiplier"), multiplier).apply(); + VulkanRenderer r = xServerView != null ? xServerView.getRenderer() : null; + if (r != null) r.setFrameGenerationMultiplier(multiplier); + applyPreferredRefreshRate(); + renderDrawerMenu(); + } + + @Override + public void onFrameGenerationPresetSelected(int preset) { + int idx = Math.max(0, Math.min(preset, FG_PRESET_QUALITY.length - 1)); + frameGenerationPreset = idx; + frameGenerationQuality = FG_PRESET_QUALITY[idx]; + frameGenerationModel = FG_PRESET_MODEL[idx]; + frameGenerationExtrapolate = false; + frameGenerationDeepMode = FG_PRESET_DEEP[idx]; + preferences.edit() + .putInt(fgKey("frame_generation_preset"), idx) + .putInt(fgKey("frame_generation_quality"), frameGenerationQuality) + .putBoolean(fgKey("frame_generation_extrapolate"), false) + .putBoolean(fgKey("frame_generation_deep_mode"), frameGenerationDeepMode) + .apply(); + VulkanRenderer r = xServerView != null ? xServerView.getRenderer() : null; + if (r != null) { + r.setFrameGenerationPreset(frameGenerationQuality, frameGenerationModel, FG_PRESET_FLOW_SCALE[idx]); + r.setFrameGenerationExtrapolate(false); + r.setFrameGenerationDeepMode(frameGenerationDeepMode); + } + renderDrawerMenu(); + } + + @Override + public void onFrameGenerationQualitySelected(int quality) { + frameGenerationQuality = quality; + preferences.edit().putInt(fgKey("frame_generation_quality"), quality).apply(); + VulkanRenderer r = xServerView != null ? xServerView.getRenderer() : null; + if (r != null) r.setFrameGenerationQuality(quality); + renderDrawerMenu(); + } + + @Override + public void onFrameGenerationSmoothingChanged(float smoothing) { + frameGenerationSmoothing = smoothing; + preferences.edit().putFloat(fgKey("frame_generation_smoothing"), smoothing).apply(); + VulkanRenderer r = xServerView != null ? xServerView.getRenderer() : null; + if (r != null) r.setFrameGenerationSmoothness(smoothing); + renderDrawerMenu(); + } + + @Override + public void onFrameGenerationDeepModeChanged(boolean deep) { + frameGenerationDeepMode = deep; + preferences.edit().putBoolean(fgKey("frame_generation_deep_mode"), deep).apply(); + VulkanRenderer r = xServerView != null ? xServerView.getRenderer() : null; + if (r != null) r.setFrameGenerationDeepMode(deep); + renderDrawerMenu(); + } + + @Override + public void onFrameGenerationAdvancedChanged(boolean advanced) { + frameGenerationAdvanced = advanced; + preferences.edit().putBoolean(fgKey("frame_generation_advanced"), advanced).apply(); + renderDrawerMenu(); // UI-only: reveals the advanced controls + } + + @Override + public void onFrameGenerationExtrapolateChanged(boolean extrapolate) { + frameGenerationExtrapolate = extrapolate; + preferences.edit().putBoolean(fgKey("frame_generation_extrapolate"), extrapolate).apply(); + VulkanRenderer r = xServerView != null ? xServerView.getRenderer() : null; + if (r != null) r.setFrameGenerationExtrapolate(extrapolate); + renderDrawerMenu(); + } + + @Override + public void onFrameGenerationFramesInFlightChanged(int framesInFlight) { + frameGenerationFramesInFlight = framesInFlight; + preferences.edit().putInt(fgKey("frame_generation_fif"), framesInFlight).apply(); + VulkanRenderer r = xServerView != null ? xServerView.getRenderer() : null; + if (r != null) r.setFrameGenerationFramesInFlight(framesInFlight); + renderDrawerMenu(); + } + @Override public void onOutputResolutionSelected(int index) { if (externalDisplayController != null) { @@ -5150,6 +5362,12 @@ public void onRecordStart(int fpsIndex, int resolutionIndex, int quality, boolea if (drawerStateHolder == null) { drawerStateHolder = new XServerDrawerStateHolder(state); + // Pause/resume FG on every drawer open/close, including scrim/swipe closes. + drawerStateHolder.setDrawerOpenListener(open -> { + VulkanRenderer r = xServerView != null ? xServerView.getRenderer() : null; + if (r != null) r.fgSetOverlayActive(open); + return kotlin.Unit.INSTANCE; + }); XServerDisplayHostKt.setupXServerDisplayHost( displayHostComposeView, xServerDisplayFrame, @@ -5678,6 +5896,10 @@ private boolean handleDrawerAction(int itemId) { frameRating = new FrameRating(this, graphicsDriverConfig); frameRating.setRenderer(lastRendererName); if (lastGpuName != null) frameRating.setGpuName(lastGpuName); + frameRating.setDisplayFrameCounter(() -> { + VulkanRenderer fgr = xServerView != null ? xServerView.getRenderer() : null; + return (fgr != null && fgr.isFrameGenerationEnabled()) ? fgr.getDisplayFrameCount() : 0L; + }); frameRating.setVisibility(View.GONE); applyHUDSettings(); rootView.addView(frameRating); @@ -7357,11 +7579,12 @@ private void setupUI() { FrameLayout rootView = xServerDisplayFrame; xServerView = new XServerSurfaceView(this, xServer); final VulkanRenderer renderer = xServerView.getRenderer(); - // Match guest libvulkan so imported AHB tiling matches the producer. - String compositorGraphicsDriver = - graphicsDriverConfig != null ? graphicsDriverConfig.get("version") : null; - if (compositorGraphicsDriver == null || compositorGraphicsDriver.isEmpty()) { - compositorGraphicsDriver = "System"; + boolean fgWantsCompositorDriver = fgPrefBool("native_frame_generation", false); + String compositorGraphicsDriver = "System"; + if (fgWantsCompositorDriver) { + String cfgVer = graphicsDriverConfig != null ? graphicsDriverConfig.get("version") : null; + compositorGraphicsDriver = (cfgVer != null && !cfgVer.isEmpty()) ? cfgVer + : (graphicsDriver != null && !graphicsDriver.isEmpty() ? graphicsDriver : "System"); } Log.i("XServerDisplayActivity", "Compositor graphics driver='" + compositorGraphicsDriver + "' from graphicsDriver='" + graphicsDriver + "'"); @@ -7370,6 +7593,28 @@ private void setupUI() { renderer.setNativeMode(isNativeRenderingEnabled); renderer.setPresentMode(VulkanRenderer.parsePresentMode( graphicsDriverConfig != null ? graphicsDriverConfig.get("compositorPresentMode") : null)); + frameGenerationEnabled = fgPrefBool("native_frame_generation", false); + frameGenerationMultiplier = fgPrefInt("frame_generation_multiplier", 2); + frameGenerationSmoothing = fgPrefFloat("frame_generation_smoothing", 0.75f); + frameGenerationAdvanced = fgPrefBool("frame_generation_advanced", false); + frameGenerationExtrapolate = fgPrefBool("frame_generation_extrapolate", false); + frameGenerationFramesInFlight = fgPrefInt("frame_generation_fif", 3); + frameGenerationPreset = Math.max(0, Math.min(fgPrefInt("frame_generation_preset", 2), + FG_PRESET_QUALITY.length - 1)); + frameGenerationQuality = FG_PRESET_QUALITY[frameGenerationPreset]; + frameGenerationModel = FG_PRESET_MODEL[frameGenerationPreset]; + frameGenerationDeepMode = FG_PRESET_DEEP[frameGenerationPreset]; + renderer.setFrameGenerationMultiplier(frameGenerationMultiplier); + renderer.setFrameGenerationPreset(frameGenerationQuality, frameGenerationModel, + FG_PRESET_FLOW_SCALE[frameGenerationPreset]); + renderer.setFrameGenerationSmoothness(frameGenerationSmoothing); + renderer.setFrameGenerationDeepMode(frameGenerationDeepMode); + renderer.setFrameGenerationExtrapolate(frameGenerationExtrapolate); + renderer.setFrameGenerationFramesInFlight(frameGenerationFramesInFlight); + // Re-pin the window's preferred display mode whenever the measured FG target moves. + renderer.setFrameGenRateChangedListener(this::scheduleFgRefreshRepin); + renderer.setFrameGeneration(frameGenerationEnabled); + if (frameGenerationEnabled) applyPreferredRefreshRate(); String containerSwapRB = container != null ? container.getExtra("swapRB", "0") : "0"; renderer.setSwapRB("1".equals(getShortcutSetting("swapRB", containerSwapRB))); @@ -7416,10 +7661,13 @@ private void setupUI() { effectiveShowFPS = preferences.getBoolean("fps_monitor_enabled", false); - // Always create FrameRating so it feeds the phone gauge HUD; its on-screen overlay shows only when the FPS monitor is enabled. frameRating = new FrameRating(this, graphicsDriverConfig); frameRating.setRenderer(lastRendererName); if (lastGpuName != null) frameRating.setGpuName(lastGpuName); + frameRating.setDisplayFrameCounter(() -> { + VulkanRenderer fgr = xServerView != null ? xServerView.getRenderer() : null; + return (fgr != null && fgr.isFrameGenerationEnabled()) ? fgr.getDisplayFrameCount() : 0L; + }); frameRating.setVisibility(effectiveShowFPS ? View.VISIBLE : View.GONE); applyHUDSettings(); updateHUDRenderMode(); @@ -8184,8 +8432,11 @@ private void extractGraphicsDriverFiles() { String bcnEmulation = graphicsDriverConfig.get("bcnEmulation"); String bcnEmulationType = graphicsDriverConfig.get("bcnEmulationType"); + if (bcnEmulation == null || com.winlator.cmod.runtime.system.GPUInformation.isAdrenoGPU(this)) { + bcnEmulation = "none"; + } + int gpuVendorId = GPUInformation.getVendorID(null, null); - // BCn compute shaders are unsupported on Adreno and crash on Xclipse with this wrapper boolean excludeBcnCompute = gpuVendorId == 20803 || (wantGamenative && gpuVendorId == 0x144D); switch (bcnEmulation) { diff --git a/app/src/main/runtime/display/XServerDrawerEffectsPane.kt b/app/src/main/runtime/display/XServerDrawerEffectsPane.kt index fda9ebd6a..e906d462d 100644 --- a/app/src/main/runtime/display/XServerDrawerEffectsPane.kt +++ b/app/src/main/runtime/display/XServerDrawerEffectsPane.kt @@ -238,6 +238,69 @@ internal fun ScreenEffectsPaneContent( ThinDivider() + Column(verticalArrangement = Arrangement.spacedBy((8f * paneScale).dp)) { + PaneSectionLabel(stringResource(R.string.session_drawer_rail_label_frame_generation)) + NavBooleanRow( + title = stringResource(R.string.session_drawer_rail_label_frame_generation), + checked = state.frameGenerationEnabled, + onCheckedChange = listener::onFrameGenerationEnabledChanged, + ) + + AnimatedVisibility( + visible = state.frameGenerationEnabled, + enter = + expandVertically( + animationSpec = tween(durationMillis = 220, easing = FastOutSlowInEasing), + expandFrom = Alignment.Top, + ) + fadeIn(animationSpec = tween(durationMillis = 160, easing = FastOutSlowInEasing)), + exit = + shrinkVertically( + animationSpec = tween(durationMillis = 180, easing = FastOutSlowInEasing), + shrinkTowards = Alignment.Top, + ) + fadeOut(animationSpec = tween(durationMillis = 120, easing = FastOutSlowInEasing)), + ) { + Column(verticalArrangement = Arrangement.spacedBy((8f * paneScale).dp)) { + PaneSectionLabel(stringResource(R.string.session_drawer_frame_generation_multiplier)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy((8f * paneScale).dp), + ) { + listOf(2, 3, 4).forEach { multiplier -> + HUDToggleChip( + label = "${multiplier}×", + checked = state.frameGenerationMultiplier == multiplier, + onClick = { listener.onFrameGenerationMultiplierSelected(multiplier) }, + modifier = Modifier.weight(1f), + ) + } + } + PaneSectionLabel(stringResource(R.string.session_drawer_frame_generation_quality)) + val fgPresetLabels = listOf("Eco", "Flow", "Bal", "Boost", "Clear", "Max") + ChipFlow { + fgPresetLabels.forEachIndexed { index, label -> + HUDToggleChip( + label = label, + checked = state.frameGenerationPreset == index, + onClick = { listener.onFrameGenerationPresetSelected(index) }, + ) + } + } + NavSliderRow( + label = stringResource(R.string.session_drawer_frame_generation_smoothness), + valueText = "${(state.frameGenerationSmoothing * 100).roundToInt()}%", + value = state.frameGenerationSmoothing, + valueRange = 0f..1f, + steps = 19, + onValueChange = { + listener.onFrameGenerationSmoothingChanged(it.coerceIn(0f, 1f)) + }, + ) + } + } + } + + ThinDivider() + Column(verticalArrangement = Arrangement.spacedBy((8f * paneScale).dp)) { PaneSectionLabel(stringResource(R.string.session_drawer_color_profile)) diff --git a/app/src/main/runtime/display/XServerDrawerMenu.kt b/app/src/main/runtime/display/XServerDrawerMenu.kt index 0351a402d..50d78aed4 100644 --- a/app/src/main/runtime/display/XServerDrawerMenu.kt +++ b/app/src/main/runtime/display/XServerDrawerMenu.kt @@ -124,6 +124,7 @@ import androidx.compose.runtime.setValue import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester @@ -618,6 +619,15 @@ data class XServerDrawerState( val fpsLimit: Int = 0, val maxRefreshRate: Int = 60, val screenEffectsCardExpanded: Boolean = false, + val frameGenerationEnabled: Boolean = false, + val frameGenerationMultiplier: Int = 2, + val frameGenerationQuality: Int = 1, + val frameGenerationSmoothing: Float = 0.5f, + val frameGenerationDeepMode: Boolean = false, + val frameGenerationAdvanced: Boolean = false, + val frameGenerationExtrapolate: Boolean = false, + val frameGenerationFramesInFlight: Int = 3, + val frameGenerationPreset: Int = 2, val sgsrEnabled: Boolean = false, val sgsrSharpness: Int = 100, val vividEnabled: Boolean = false, @@ -736,6 +746,11 @@ class XServerDrawerStateHolder( var controllerConnected by mutableStateOf(false) private set private var paneVisibilityListener: ((Boolean) -> Unit)? = null + private var drawerOpenListener: ((Boolean) -> Unit)? = null + + fun setDrawerOpenListener(listener: ((Boolean) -> Unit)?) { + drawerOpenListener = listener + } // Bumped on swap-back so the host re-requests a layout pass on the Compose-hosted display frame. var phoneRelayoutTick by mutableStateOf(0) @@ -750,6 +765,7 @@ class XServerDrawerStateHolder( fun openDrawer() { drawerOpen = true + drawerOpenListener?.invoke(true) } private fun regionSize(r: Int) = when (r) { @@ -879,6 +895,7 @@ class XServerDrawerStateHolder( fun closeDrawer() { drawerOpen = false openPane = null + drawerOpenListener?.invoke(false) } fun isPaneOpen(): Boolean = openPane != null @@ -1045,6 +1062,23 @@ interface XServerDrawerActionListener { fun onOutputSwapToDisplay() fun onOutputCastClick() + fun onFrameGenerationEnabledChanged(enabled: Boolean) + + fun onFrameGenerationMultiplierSelected(multiplier: Int) + + fun onFrameGenerationPresetSelected(preset: Int) + + fun onFrameGenerationQualitySelected(quality: Int) + + fun onFrameGenerationSmoothingChanged(smoothing: Float) + + fun onFrameGenerationDeepModeChanged(deep: Boolean) + + fun onFrameGenerationAdvancedChanged(advanced: Boolean) + + fun onFrameGenerationExtrapolateChanged(extrapolate: Boolean) + + fun onFrameGenerationFramesInFlightChanged(framesInFlight: Int) fun onSGSREnabledChanged(enabled: Boolean) @@ -1225,6 +1259,15 @@ fun buildXServerDrawerState( fullscreenEnabled: Boolean = false, maxRefreshRate: Int = 60, refactorSizeEnabled: Boolean = false, + frameGenerationEnabled: Boolean = false, + frameGenerationMultiplier: Int = 2, + frameGenerationQuality: Int = 1, + frameGenerationSmoothing: Float = 0.5f, + frameGenerationDeepMode: Boolean = false, + frameGenerationAdvanced: Boolean = false, + frameGenerationExtrapolate: Boolean = false, + frameGenerationFramesInFlight: Int = 3, + frameGenerationPreset: Int = 2, recordingActive: Boolean = false, recordConfig: RecordUiConfig = RecordUiConfig(), screenTouchMode: Int = 0, @@ -1394,6 +1437,15 @@ fun buildXServerDrawerState( fpsLimit = fpsLimit, maxRefreshRate = maxRefreshRate, screenEffectsCardExpanded = screenEffectsCardExpanded, + frameGenerationEnabled = frameGenerationEnabled, + frameGenerationMultiplier = frameGenerationMultiplier, + frameGenerationQuality = frameGenerationQuality, + frameGenerationSmoothing = frameGenerationSmoothing, + frameGenerationDeepMode = frameGenerationDeepMode, + frameGenerationAdvanced = frameGenerationAdvanced, + frameGenerationExtrapolate = frameGenerationExtrapolate, + frameGenerationFramesInFlight = frameGenerationFramesInFlight, + frameGenerationPreset = frameGenerationPreset, sgsrEnabled = sgsrEnabled, sgsrSharpness = sgsrSharpness, vividEnabled = vividEnabled, diff --git a/app/src/main/runtime/display/renderer/VulkanRenderer.java b/app/src/main/runtime/display/renderer/VulkanRenderer.java index a804fe339..7d3744848 100644 --- a/app/src/main/runtime/display/renderer/VulkanRenderer.java +++ b/app/src/main/runtime/display/renderer/VulkanRenderer.java @@ -3,8 +3,11 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.os.Build; import android.os.Handler; +import android.os.HandlerThread; import android.os.Looper; +import android.os.Process; import android.util.Log; import android.view.Choreographer; import android.view.Surface; @@ -50,9 +53,52 @@ public class VulkanRenderer private long nativeHandle = 0; private boolean supportProbed = false; private boolean loggedAhbSceneUse = false; - // Must be set before attachSurface — nativeCreate reads it once at instance creation. + // Must be set before attachSurface. private volatile String graphicsDriverName = null; + // ---- Frame generation ---- + private volatile boolean frameGenEnabled = false; + private volatile int fgMultiplier = 2; // target display:engine ratio (2, 3, 4) — the user ceiling + private volatile int fgEffectiveMultiplier = 2; // adaptive working multiplier (2..ceiling) + private volatile int fgBoundSecs = 0; + private volatile int fgRecoverSecs = 0; // consecutive healthy seconds -> step the multiplier back up + private final AtomicBoolean fgNewScene = new AtomicBoolean(false); + private final AtomicBoolean fgSceneDirty = new AtomicBoolean(false); + private final AtomicBoolean fgPumpScheduled = new AtomicBoolean(false); + private long fgEngineFrames = 0; + private volatile long fgDisplayPeriodNs = 0; + private volatile double fgLockedGameHz = 0.0; + private long fgLastPumpNs = 0; + private volatile long fgLastGameNs = 0; + private volatile long fgPrevGameNs = 0; + private volatile long fgCurrentVsyncNs = 0; + private long fgLastEmitVsyncNs = 0; + private long fgPromoteVsyncNs = 0; + private int fgSlotsLocked = 0; + private boolean fgForcePromote = false; + private Drawable fgLastScanoutSrc = null; + private Drawable fgFirstScanoutSrc = null; + private boolean fgMultiBuffer = false; + private long fgLastAcceptNs = 0L; + private static final long FG_DEDUP_FREEZE_NS = 100_000_000L; + private boolean fgEmitWasHold = false; + private long fgInstHoldN, fgInstInterpN, fgInstLongN, fgInstTotalN; + private double fgInstHoldSum, fgInstInterpSum, fgInstHoldMax, fgInstInterpMax; + private boolean fgRenderPrioritySet = false; + private volatile int fgActivePresentMode = PRESENT_MODE_FIFO; + private volatile int fgDisplayCapHz = 0; // panel-max ceiling for the target post rate; 0 = uncapped + private volatile int fgQuality = 1; // 0 performance, 1 balanced, 2 quality + private volatile float fgSmoothness = 0.75f; + private volatile boolean fgDeepMode = false; + private volatile boolean fgExtrapolate = false; // false = interpolate, true = extrapolate + private volatile int fgModel = 0; // 0 = standard, 1 = steadier + private volatile float fgFlowScale = 0.25f; + private volatile int fgFramesInFlight = 3; // compositor buffering depth (1..3) + private volatile Surface fgSurface; + private float fgFrameRateHint = -1f; + private long fgFrameRateHintNs = 0L; + private volatile Runnable fgRateChangedListener; + private final EffectComposer effectComposer; public final ViewTransformation viewTransformation = new ViewTransformation(); @@ -116,11 +162,11 @@ public void setSwapRB(boolean v) { private final ByteBuffer sceneBuf = ByteBuffer.allocateDirect(SCENE_BUF_SIZE).order(ByteOrder.nativeOrder()); private final Handler mainHandler = new Handler(Looper.getMainLooper()); + private volatile boolean fgPumpStarted = false; private final AtomicBoolean renderRequested = new AtomicBoolean(false); // Reusable scratch — sized once, refilled per frame. private final float[] sceneXform = XForm.getInstance(); - // Effect.writeParams writes into a float[]; we copy into the ByteBuffer afterwards. private final float[] effectParamsScratch = new float[MAX_EFFECTS * 4]; private final AtomicBoolean destroyed = new AtomicBoolean(false); @@ -141,6 +187,7 @@ public void destroy() { // Unregister from the persistent XServer to avoid leaking listeners. xServer.windowManager.removeOnWindowModificationListener(this); xServer.pointer.removeOnPointerMotionListener(this); + stopFgPumpThread(); if (nativeHandle != 0) { // On the UI thread, run nativeDestroy off-thread — it may block on vkDeviceWaitIdle. @@ -171,6 +218,11 @@ public void destroy() { private final Choreographer.FrameCallback coalescedRenderCallback; public void requestRenderCoalesced() { + if (frameGenEnabled) { + fgSceneDirty.set(true); + scheduleFgPump(); + return; + } if (renderRequested.compareAndSet(false, true)) { // Post directly (thread-safe): a handler hop arms past the next doFrame and halves the visible cursor rate. Choreographer choreographer = mainChoreographer; @@ -185,6 +237,451 @@ public void requestRenderCoalesced() { } } + // ---- Frame generation driver ------------------------------------------- + + /** Toggle native frame generation. Safe to call from any thread. */ + public void setFrameGeneration(boolean enabled) { + frameGenEnabled = enabled; + synchronized (this) { + if (nativeHandle != 0) { + nativeSetFrameGeneration(nativeHandle, enabled); + nativeSetPresentMode(nativeHandle, enabled ? PRESENT_MODE_MAILBOX : requestedPresentMode); + fgActivePresentMode = nativeGetActivePresentMode(nativeHandle); + } + } + if (enabled) { + pushFrameGenParams(); + synchronized (this) { + if (nativeHandle != 0) nativeSetFrameGenDeepMode(nativeHandle, fgDeepMode); + } + fgEngineFrames = 0; + fgCurrentVsyncNs = 0; + fgLastScanoutSrc = null; + fgFirstScanoutSrc = null; + fgMultiBuffer = false; + fgLastAcceptNs = 0L; + fgRenderPrioritySet = false; + fgLockedGameHz = 0.0; + fgNewScene.set(true); + startFgPumpThread(); + scheduleFgPump(); + } + if (!enabled) { fgLockedGameHz = 0.0; fgApplyFrameRateHint(0.0, System.nanoTime()); stopFgPumpThread(); } + } + + public boolean isFrameGenerationEnabled() { return frameGenEnabled; } + + /** Target display:engine ratio (2, 3, 4). Snapped to a supported value. Live; safe from any thread. */ + public void setFrameGenerationMultiplier(int multiplier) { + fgMultiplier = multiplier <= 2 ? 2 : (multiplier >= 4 ? 4 : 3); + fgEffectiveMultiplier = fgMultiplier; + fgBoundSecs = 0; + } + + public int getFrameGenMultiplier() { return fgMultiplier; } + + /** Panel-max refresh (Hz) — the scheduler won't target a post rate above this. 0 = uncapped. */ + public void setFrameGenDisplayCap(int hz) { fgDisplayCapHz = Math.max(0, hz); } + + /** Quality preset: 0 performance, 1 balanced, 2 quality. Live; safe from any thread. */ + public void setFrameGenerationQuality(int quality) { + fgQuality = quality < 0 ? 0 : (quality > 2 ? 2 : quality); + pushFrameGenParams(); + } + + public int getFrameGenerationQuality() { return fgQuality; } + + /** Apply a preset's flow quality + model + flowScale. Live. */ + public void setFrameGenerationPreset(int quality, int model, float flowScale) { + fgQuality = quality < 0 ? 0 : (quality > 2 ? 2 : quality); + fgModel = model <= 0 ? 0 : 1; + float fs = flowScale < 0.05f ? 0.05f : (flowScale > 1.0f ? 1.0f : flowScale); + boolean flowChanged = Math.abs(fs - fgFlowScale) > 1e-4f; + fgFlowScale = fs; + pushFrameGenParams(); + if (flowChanged) { + synchronized (this) { + if (nativeHandle != 0) nativeSetFrameGenFlowScale(nativeHandle, fs); + } + } + } + + /** Interpolation smoothness in [0,1]. Live. */ + public void setFrameGenerationSmoothness(float smoothness) { + fgSmoothness = smoothness < 0f ? 0f : (smoothness > 1f ? 1f : smoothness); + pushFrameGenParams(); + } + + public float getFrameGenerationSmoothness() { return fgSmoothness; } + + /** Pipeline mode. false = standard (single backward flow). true = quality (bidirectional warp). Live. */ + public void setFrameGenerationDeepMode(boolean deep) { + fgDeepMode = deep; + synchronized (this) { + if (nativeHandle != 0) nativeSetFrameGenDeepMode(nativeHandle, deep); + } + } + + public boolean isFrameGenerationDeepMode() { return fgDeepMode; } + + /** Generation method. false = interpolation (+1 frame latency). true = extrapolation (no added latency). Live. */ + public void setFrameGenerationExtrapolate(boolean extrapolate) { + fgExtrapolate = extrapolate; + synchronized (this) { + if (nativeHandle != 0) nativeSetFrameGenExtrapolate(nativeHandle, extrapolate); + } + } + + public boolean isFrameGenerationExtrapolate() { return fgExtrapolate; } + + /** Compositor frames-in-flight (1..3): the latency/smoothness dial. Live. */ + public void setFrameGenerationFramesInFlight(int framesInFlight) { + fgFramesInFlight = framesInFlight < 1 ? 1 : (framesInFlight > 3 ? 3 : framesInFlight); + synchronized (this) { + if (nativeHandle != 0) nativeSetFrameGenFramesInFlight(nativeHandle, fgFramesInFlight); + } + } + + public int getFrameGenerationFramesInFlight() { return fgFramesInFlight; } + + private void pushFrameGenParams() { + float occHi = 0.12f + 0.28f * fgSmoothness; + float occLo = (float) fgModel; // 0 standard, 1 steadier + int minStep = fgQuality == 0 ? 4 : (fgQuality == 2 ? 1 : 2); + synchronized (this) { + if (nativeHandle != 0) nativeSetFrameGenParams(nativeHandle, occLo, occHi, minStep); + } + } + + /** Actual vkQueuePresentKHR count (real + interpolated). HUD derives Display FPS from this. */ + public long getDisplayFrameCount() { + synchronized (this) { + return nativeHandle != 0 ? nativeGetDisplayFrameCount(nativeHandle) : 0L; + } + } + + private synchronized void startFgPumpThread() { + if (fgPumpStarted) return; + nativeFgPumpStart(this); + fgPumpStarted = true; + } + + private synchronized void stopFgPumpThread() { + if (!fgPumpStarted) return; + fgPumpStarted = false; + fgLastPumpNs = 0L; + nativeFgPumpStop(); + } + + private void scheduleFgPump() { + if (frameGenEnabled && !fgPumpStarted) startFgPumpThread(); + } + + // Invoked from the native pump thread once per vsync (frameTimeNanos = the vsync time). + private void fgPumpTickFromNative(long frameTimeNanos) { + if (!frameGenEnabled || nativeHandle == 0) return; + if (fgActivePresentMode == PRESENT_MODE_FIFO) { + fgActivePresentMode = nativeGetActivePresentMode(nativeHandle); + } + if (fgLastPumpNs != 0L) { + long d = frameTimeNanos - fgLastPumpNs; + if (d > 0L && d < 100_000_000L) { // ignore stalls / outliers + fgDisplayPeriodNs = fgDisplayPeriodNs == 0L ? d : fgDisplayPeriodNs + (d - fgDisplayPeriodNs) / 8L; + if (nativeHandle != 0) { + double th = fgTargetHz(); + nativeSetVsyncTiming(nativeHandle, th > 0.0 ? (long) (1.0e9 / th) : fgDisplayPeriodNs, + fgDisplayPeriodNs, fgContentPeriodNs, frameTimeNanos); + fgApplyFrameRateHint(th, frameTimeNanos); + } + } else if (d >= 100_000_000L) { + fgResyncPending = true; + } + } + fgLastPumpNs = frameTimeNanos; + fgCurrentVsyncNs = frameTimeNanos; + xServerView.requestRender(); + } + + private void fgDrawFrame() { + if (!fgRenderPrioritySet) { + try { android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY); } + catch (Throwable t) { /* best-effort */ } + fgRenderPrioritySet = true; + } + int perTick = fgComputePerTick(); + for (int i = 0; i < perTick; i++) { + long t0 = System.nanoTime(); + int kind = fgEmitOne(); + if (kind == 1) fgDiagInterp++; + else if (kind == 2) fgDiagReal++; + else fgDiagNone++; + if (kind != 0) fgInstrument((System.nanoTime() - t0) / 1000L, fgEmitWasHold); + } + fgCadenceDiag(); + } + + private long fgDiagInterp, fgDiagReal, fgDiagNone, fgDiagLastNs; + private void fgCadenceDiag() { + long now = System.nanoTime(); + if (fgDiagLastNs == 0L) { fgDiagLastNs = now; return; } + if (now - fgDiagLastNs < 1_000_000_000L) return; + long game = fgContentPeriodNs, disp = fgDisplayPeriodNs; + double gameHz = game > 0 ? 1e9 / game : 0, dispHz = disp > 0 ? 1e9 / disp : 0; + double ratio = disp > 0 ? (double) game / disp : 0; + long dupDrop = 0, distinct = 0; + if (nativeHandle != 0) { nativeFgPromoteInfo(nativeHandle, fgPromoteInfo); dupDrop = fgPromoteInfo[2]; distinct = fgPromoteInfo[3]; } + long dDup = dupDrop - fgDiagPrevDup, dDist = distinct - fgDiagPrevDist; + fgDiagPrevDup = dupDrop; fgDiagPrevDist = distinct; + double secs = (double) (now - fgDiagLastNs) / 1e9; + if (fgLockedGameHz > 0.0 && secs > 0.0 && secs <= 1.5) { + double deliveredHz = (double) (fgDiagInterp + fgDiagReal) / secs; + double targetEff = Math.max(1, fgCadenceM) * fgLockedGameHz; + if (fgDisplayCapHz > 0) targetEff = Math.min(targetEff, (double) fgDisplayCapHz); + if (deliveredHz > 0.0 && deliveredHz < 0.85 * targetEff && !fgOverlayActive) { + fgRecoverSecs = 0; + if (++fgBoundSecs >= 4 && fgEffectiveMultiplier > 2) { fgEffectiveMultiplier--; fgBoundSecs = 0; } + } else if (deliveredHz >= 0.95 * targetEff && fgEffectiveMultiplier < fgMultiplier && !fgOverlayActive) { + fgBoundSecs = 0; + if (++fgRecoverSecs >= 3) { fgEffectiveMultiplier++; fgRecoverSecs = 0; } + } else { + fgBoundSecs = 0; + fgRecoverSecs = 0; + } + } + Log.i(TAG, String.format(java.util.Locale.US, + "FG diag: content=%.0fHz (locked=%.0f) panel=%.0fHz slots=%d mult=%dx(eff=%dx cad=%dx) | present interp=%d real=%d none=%d | " + + "content-dedup distinct=%d/s dup-dropped=%d/s | id-dedup-dropped=%d accepted=%d", + gameHz, fgLockedGameHz, dispHz, (int) Math.round(ratio), fgMultiplier, fgEffectiveMultiplier, fgCadenceM, + fgDiagInterp, fgDiagReal, fgDiagNone, dDist, dDup, fgDiagDedupDropped, fgDiagAccepted)); + fgDiagInterp = fgDiagReal = fgDiagNone = fgDiagDedupDropped = fgDiagAccepted = 0; + fgDiagLastNs = now; + } + private long fgDiagDedupDropped, fgDiagAccepted, fgDiagPrevDup, fgDiagPrevDist; + + private void fgInstrument(long usCpu, boolean wasHold) { + double ms = usCpu / 1000.0; + if (wasHold) { fgInstHoldN++; fgInstHoldSum += ms; if (ms > fgInstHoldMax) fgInstHoldMax = ms; } + else { fgInstInterpN++; fgInstInterpSum += ms; if (ms > fgInstInterpMax) fgInstInterpMax = ms; } + if (ms > 8.31) fgInstLongN++; + if (++fgInstTotalN >= 240) { + android.util.Log.i(TAG, String.format(java.util.Locale.US, + "FG cpu/present: composite n=%d mean=%.2f max=%.2f | interp n=%d mean=%.2f max=%.2f | over-budget=%d/%d", + fgInstHoldN, fgInstHoldN > 0 ? fgInstHoldSum / fgInstHoldN : 0.0, fgInstHoldMax, + fgInstInterpN, fgInstInterpN > 0 ? fgInstInterpSum / fgInstInterpN : 0.0, fgInstInterpMax, + fgInstLongN, fgInstTotalN)); + fgInstHoldN = fgInstInterpN = fgInstLongN = fgInstTotalN = 0; + fgInstHoldSum = fgInstInterpSum = fgInstHoldMax = fgInstInterpMax = 0.0; + } + } + + private final long[] fgPromoteInfo = new long[4]; + private long fgPromoteSeen = 0; + private long fgLastPromoteNs = 0, fgPrevPromoteNs = 0; // times of the last two distinct content frames + private long fgContentPeriodNs = 0; // EMA of the interval between distinct content frames + private int fgVblankSincePromote = 0; // vblanks since the last real frame — drives the steady output gate + private volatile int fgCadenceM = 2; // divisor-snapped multiplier actually used by the cadence + private volatile boolean fgResyncPending = false; + private volatile boolean fgOverlayActive = false; + + // Re-anchor the FG content clock + working multiplier after a pause/overlay/focus gap. + private void doFgResync() { + fgLockedGameHz = 0.0; + fgContentPeriodNs = 0L; + fgPrevPromoteNs = 0L; + fgLastPromoteNs = 0L; + fgEngineFrames = 0; + fgVblankSincePromote = 0; + fgLastEmitVsyncNs = 0; + fgPromoteVsyncNs = 0; + fgSlotsLocked = 0; + fgEffectiveMultiplier = fgMultiplier; + fgBoundSecs = 0; + fgNewScene.set(true); + } + + /** Mark a UI overlay (drawer) active; clearing it re-anchors the FG clock fresh. Thread-safe. */ + public void fgSetOverlayActive(boolean active) { + if (fgOverlayActive == active) return; + fgOverlayActive = active; + if (!active) fgResyncPending = true; + } + + /** Idempotently resume FG if it is in overlay-pause. Does nothing when not paused. */ + public void fgClearOverlayIfActive() { + if (fgOverlayActive) { fgOverlayActive = false; fgResyncPending = true; } + } + + private int fgEmitOne() { + if (fgResyncPending) { fgResyncPending = false; doFgResync(); } + boolean newGame = fgNewScene.getAndSet(false); + boolean dirty = fgSceneDirty.getAndSet(false); + + long vsync = fgCurrentVsyncNs; + boolean tick = vsync == 0L || vsync != fgLastEmitVsyncNs; + if (tick) fgLastEmitVsyncNs = vsync; + + int eff = Math.max(2, fgEffectiveMultiplier); + long disp = fgDisplayPeriodNs; + long period = fgContentPeriodNs; + int slots = fgSlotsLocked; + if (disp > 0L && period > 0L) { + double ratio = (double) period / (double) disp; + if (slots < 1 || Math.abs(ratio - slots) > 0.65) { + slots = Math.max(1, (int) Math.round(ratio)); + } + fgSlotsLocked = slots; + } + if (slots < 1) slots = eff; + int emits = Math.max(1, Math.min(eff, slots)); + fgCadenceM = emits; + int lastSlot = fgSlotVblank(emits - 1, slots, emits); + + boolean staticContent = period <= 0L || fgLastPromoteNs == 0L + || (System.nanoTime() - fgLastPromoteNs) > 2L * period; + boolean uiHold = dirty && !newGame && staticContent; + if (dirty && !newGame && !staticContent) fgSceneDirty.set(true); + boolean hold = newGame || uiHold; + fgEmitWasHold = hold; + + boolean promoted = false, uiPromote = false; + if (nativeHandle != 0) { + if (hold) fgBuildAndStage(uiHold); + else nativeFgResolveStage(nativeHandle); + nativeFgPromoteInfo(nativeHandle, fgPromoteInfo); + if (fgPromoteInfo[0] != fgPromoteSeen) { + fgPromoteSeen = fgPromoteInfo[0]; + long pNs = fgLastGameNs != 0L ? fgLastGameNs + : (fgPromoteInfo[1] != 0L ? fgPromoteInfo[1] : System.nanoTime()); + if (pNs != fgLastPromoteNs) { + promoted = true; + if (fgLastPromoteNs != 0L) { + long d = pNs - fgLastPromoteNs; + if (d > 0L && d < 500_000_000L) { + fgContentPeriodNs = fgContentPeriodNs == 0L ? d + : fgContentPeriodNs + (d - fgContentPeriodNs) / 8L; + double inst = 1.0e9 / (double) fgContentPeriodNs; + fgLockedGameHz = fgLockedGameHz <= 0.0 ? inst + : fgLockedGameHz + (inst - fgLockedGameHz) * 0.25; + } + } + fgPrevPromoteNs = fgLastPromoteNs; + fgLastPromoteNs = pNs; + fgEngineFrames++; + fgVblankSincePromote = 0; + fgPromoteVsyncNs = vsync; + } else { + uiPromote = true; + } + } + } + if (!promoted) { + if (vsync > 0L && disp > 0L && fgPromoteVsyncNs > 0L) { + long d = vsync - fgPromoteVsyncNs; + fgVblankSincePromote = d <= 0L ? 0 : (int) ((d + disp / 2L) / disp); + } else if (tick) { + fgVblankSincePromote++; + } + } + + long target = fgPresentTargetNs(); + boolean canInterp = fgMultiplier > 1 && fgEngineFrames >= 2 && period > 0L + && fgLastPromoteNs != 0L && fgPrevPromoteNs != 0L; + if (!canInterp) { + if (hold || uiPromote) { + nativePresentLast(nativeHandle, 0f, fgPrevPromoteNs, fgLastPromoteNs, target); + return 2; + } + return 0; + } + + int vi = fgVblankSincePromote; + if (vi > lastSlot) { + if (uiPromote) { + nativePresentLast(nativeHandle, 0f, fgPrevPromoteNs, fgLastPromoteNs, target); + return 2; + } + return 0; + } + if (!tick && !promoted) return 0; + + int k = -1; + for (int i = 0; i < emits; i++) { + if (fgSlotVblank(i, slots, emits) == vi) { k = i; break; } + } + if (k < 0) return 0; + + int realSlot = fgExtrapolate ? 0 : emits - 1; + if (k == realSlot) { + nativePresentLast(nativeHandle, 0f, fgPrevPromoteNs, fgLastPromoteNs, target); + return 2; + } + int v = fgSlotVblank(k, slots, emits); + double phase = fgExtrapolate + ? (double) v / (double) slots + : 1.0 - (double) (lastSlot - v) / (double) slots; + nativeRenderInterp(nativeHandle, (float) phase, fgPrevPromoteNs, fgLastPromoteNs, target); + return 1; + } + + private static int fgSlotVblank(int k, int slots, int emits) { + return (int) (((long) k * (long) slots + (long) (emits / 2)) / (long) emits); + } + + private long fgPresentTargetNs() { + long v = fgCurrentVsyncNs, d = fgDisplayPeriodNs; + return (v > 0L && d > 0L) ? v + d : 0L; + } + + // Target FG post rate (Hz): multiplier × locked game rate, capped to the panel max. 0 if not measured. + private double fgTargetHz() { + double g = fgLockedGameHz; + if (g <= 0.0) return 0.0; + double target = Math.max(1, fgCadenceM) * g; + if (fgDisplayCapHz > 0) target = Math.min(target, (double) fgDisplayCapHz); + return target; + } + + private int fgComputePerTick() { + return 1; + } + + private void fgApplyFrameRateHint(double targetHz, long nowNs) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return; + float rate = frameGenEnabled && targetHz > 0.0 ? (float) Math.round(targetHz) : 0f; + if (rate == fgFrameRateHint) return; + if (rate != 0f && fgFrameRateHint > 0f && Math.abs(rate - fgFrameRateHint) <= 5f) return; // EMA jitter + if (rate != 0f && nowNs - fgFrameRateHintNs < 500_000_000L) return; + // DEFAULT (exact-or-multiple), not FIXED_SOURCE (video pulldown semantics). + Surface s = fgSurface; + if (s != null && s.isValid()) { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + s.setFrameRate(rate, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT, + Surface.CHANGE_FRAME_RATE_ALWAYS); + } else { + s.setFrameRate(rate, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT); + } + } catch (IllegalStateException | IllegalArgumentException ignored) {} + } + fgFrameRateHint = rate; + fgFrameRateHintNs = nowNs; + Log.i(TAG, "FG target display rate: " + (int) rate + "Hz (game=" + Math.round(fgLockedGameHz) + + " x" + fgMultiplier + (fgDeepMode ? " quality" : " standard") + ")"); + Runnable l = fgRateChangedListener; + if (l != null) l.run(); + } + + /** Live FG display target (multiplier × measured game fps, rounded), or 0 if unknown/off. */ + public int getFrameGenTargetHz() { + float rate = fgFrameRateHint; + return rate > 0f ? Math.round(rate) : 0; + } + + /** Invoked (any thread) whenever the FG display target changes; 0-target means FG off. */ + public void setFrameGenRateChangedListener(Runnable listener) { + fgRateChangedListener = listener; + } + private Drawable createRootCursorDrawable() { Context context = xServerView.getContext(); BitmapFactory.Options options = new BitmapFactory.Options(); @@ -200,6 +697,8 @@ public void setGraphicsDriver(String driverName) { } public void attachSurface(Surface surface) { + fgSurface = surface; + fgFrameRateHint = -1f; // Serialize with detachSurface()/destroy() so a re-attach can't overlap a native teardown. synchronized (this) { if (nativeHandle == 0) { @@ -221,15 +720,29 @@ public void attachSurface(Surface surface) { xServer.windowManager.addOnWindowModificationListener(this); xServer.pointer.addOnPointerMotionListener(this); } + if (frameGenEnabled) { + nativeSetFrameGeneration(nativeHandle, true); + nativeSetPresentMode(nativeHandle, PRESENT_MODE_MAILBOX); + fgActivePresentMode = nativeGetActivePresentMode(nativeHandle); + pushFrameGenParams(); + nativeSetFrameGenDeepMode(nativeHandle, fgDeepMode); + fgEngineFrames = 0; + fgNewScene.set(true); + startFgPumpThread(); + scheduleFgPump(); + } nativeSurfaceCreated(nativeHandle, surface); } } private boolean shouldEnableValidationLayers() { + // Force validation layers off and clear any stale pref (the UI toggle is disabled). Context context = xServerView.getContext(); - return BuildConfig.DEBUG - && PreferenceManager.getDefaultSharedPreferences(context) - .getBoolean(PREF_VULKAN_VALIDATION_LAYERS, false); + android.content.SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + if (prefs.getBoolean(PREF_VULKAN_VALIDATION_LAYERS, false)) { + prefs.edit().putBoolean(PREF_VULKAN_VALIDATION_LAYERS, false).apply(); + } + return false; } public void notifySurfaceChanged(int w, int h) { @@ -312,7 +825,11 @@ public void onSurfaceDestroyed() { @Override public void onDrawFrame() { if (nativeHandle == 0) return; - buildAndSubmitFrame(); + if (frameGenEnabled) { + fgDrawFrame(); + } else { + buildAndSubmitFrame(); + } } // ----- Scene assembly ---------------------------------------------------- @@ -566,8 +1083,21 @@ private void buildAndSubmitFrame() { } nativeSetScene(nativeHandle, buf); - // nativeSetFpsLimit is a native no-op (pacing is done elsewhere); not called per frame. - nativeRenderFrame(nativeHandle); + if (frameGenEnabled) { + // FG: render into the history ring without presenting; presents are issued by fgEmitOne(). + nativeRenderHold(nativeHandle, fgForcePromote); + } else { + nativeRenderFrame(nativeHandle); + } + } + + private void fgBuildAndStage(boolean uiOnly) { + fgForcePromote = uiOnly; + try { + buildAndSubmitFrame(); + } finally { + fgForcePromote = false; + } } // ----- WindowManager / Pointer listeners -------------------------------- @@ -613,6 +1143,11 @@ public void onUpdateWindowAttributes(Window window, Bitmask mask) { public void requestCursorRender() { cursorActiveUntilNs = System.nanoTime() + CURSOR_ACTIVE_NS; + if (frameGenEnabled) { + fgSceneDirty.set(true); + scheduleFgPump(); + return; + } xServerView.requestTransientRender(100); } @@ -627,8 +1162,28 @@ public void onPointerMove(short x, short y) { @Override public void onFramePresented(Window window, WindowManager.FrameSource source, int serial) { - // DRI3_BUFFER fires at pixmap allocation, not a visible change; the real present already wakes us. Skip it. if (source == WindowManager.FrameSource.DRI3_BUFFER) return; + if (frameGenEnabled) { + Drawable scanoutNow = (window != null && window.getContent() != null) + ? window.getContent().getScanoutSource() : null; + if (scanoutNow != null) { + if (fgFirstScanoutSrc == null) fgFirstScanoutSrc = scanoutNow; + else if (scanoutNow != fgFirstScanoutSrc) fgMultiBuffer = true; + } + long now = System.nanoTime(); + if (fgMultiBuffer && scanoutNow != null && scanoutNow == fgLastScanoutSrc + && (now - fgLastAcceptNs) < FG_DEDUP_FREEZE_NS) { + fgDiagDedupDropped++; + return; // duplicate buffer — ignore for the FG cadence + } + fgDiagAccepted++; + fgLastScanoutSrc = scanoutNow; + fgLastAcceptNs = now; + fgLastGameNs = now; + fgNewScene.set(true); + scheduleFgPump(); + return; + } requestRenderCoalesced(); } @@ -937,4 +1492,23 @@ private static native long nativeCreate(boolean enableValidationLayers, private static native void nativeSetFpsLimit(long handle, int fps); private static native void nativeSetPresentMode(long handle, int mode); private static native void nativeSetScaleFilter(long handle, int mode); + + // ---- Frame generation ---- + private static native void nativeSetFrameGeneration(long handle, boolean enabled); + private static native boolean nativeFrameGenerationSupported(long handle); + private static native long nativeGetDisplayFrameCount(long handle); + private static native boolean nativeRenderHold(long handle, boolean forcePromote); + private static native boolean nativeFgResolveStage(long handle); + private static native boolean nativeRenderInterp(long handle, float phase, long prevNs, long currNs, long targetNs); + private static native void nativeFgPromoteInfo(long handle, long[] out); + private static native boolean nativePresentLast(long handle, float phase, long prevNs, long currNs, long targetNs); + private static native void nativeSetFrameGenParams(long handle, float occLo, float occHi, int minStep); + private static native void nativeSetFrameGenFlowScale(long handle, float flowScale); + private static native void nativeSetFrameGenDeepMode(long handle, boolean deep); + private static native void nativeSetFrameGenExtrapolate(long handle, boolean extrapolate); + private static native void nativeSetFrameGenFramesInFlight(long handle, int framesInFlight); + private static native int nativeGetActivePresentMode(long handle); + private static native void nativeSetVsyncTiming(long handle, long periodNs, long displayPeriodNs, long contentPeriodNs, long vsyncNs); + private static native void nativeFgPumpStart(Object renderer); + private static native void nativeFgPumpStop(); } diff --git a/app/src/main/runtime/display/ui/FrameRating.java b/app/src/main/runtime/display/ui/FrameRating.java index 91591fb59..5c262b13a 100644 --- a/app/src/main/runtime/display/ui/FrameRating.java +++ b/app/src/main/runtime/display/ui/FrameRating.java @@ -131,6 +131,12 @@ public void setFrameObserver(FrameObserver observer) { // When values are mirrored to the Compose overlay the on-screen view is GONE, but we must still compute FPS/frametime so the mirrored gauges stay live. private volatile boolean hudMirrorActive; private volatile float lastFPS; + // Frame generation: when set, supplies the cumulative display present count (real + generated). + // 0 means FG is off, in which case the HUD shows the single engine FPS. + private java.util.function.LongSupplier displayFrameCounter; + private long lastDisplayCount = -1L; + private long lastDisplayNano; + private volatile float displayFps; private volatile long lastFrameNano; private long lastPrimaryFrameNano; private long lastGraphRedraw; @@ -877,6 +883,12 @@ private void applyDisplayMode() { requestLayout(); } + /** Supplies the cumulative display present count (real + generated) so the HUD can show the output + * rate while frame generation is on; supply 0 (or null) when FG is off to fall back to engine FPS. */ + public void setDisplayFrameCounter(java.util.function.LongSupplier supplier) { + this.displayFrameCounter = supplier; + } + public void setRenderer(String renderer) { if (renderer == null) { return; @@ -1544,8 +1556,26 @@ this.lastFPS, this.currentMs, this.gpuLoad, this.cpuPercent, ramPercentValue(), this.tvTemp.setVisibility(View.GONE); } + // Frame generation: derive the output rate (real + generated) from the present counter so the + // HUD reflects what is actually displayed, not just the engine rate. + if (this.displayFrameCounter != null) { + long c = this.displayFrameCounter.getAsLong(); + if (c <= 0L) { + this.displayFps = 0.0f; + this.lastDisplayCount = -1L; + } else { + if (this.lastDisplayCount >= 0L && nowNano > this.lastDisplayNano) { + this.displayFps = + (float) ((c - this.lastDisplayCount) * 1000000000.0 / (nowNano - this.lastDisplayNano)); + } + this.lastDisplayCount = c; + this.lastDisplayNano = nowNano; + } + } + if (this.enableFps && this.tvFpsBig != null) { - this.tvFpsBig.setText(String.format(Locale.US, "%.0f", this.lastFPS)); + float shownFps = this.displayFps > 0.0f ? this.displayFps : this.lastFPS; + this.tvFpsBig.setText(String.format(Locale.US, "%.0f", shownFps)); this.tvFpsBig.setTextColor(this.C_FPS_OK); this.tvFpsBig.setVisibility(View.VISIBLE); } else if (this.tvFpsBig != null) this.tvFpsBig.setVisibility(View.GONE); diff --git a/app/src/main/runtime/display/xserver/XServer.java b/app/src/main/runtime/display/xserver/XServer.java index 580de3dbf..8a6bba1a2 100644 --- a/app/src/main/runtime/display/xserver/XServer.java +++ b/app/src/main/runtime/display/xserver/XServer.java @@ -15,6 +15,7 @@ import com.winlator.cmod.runtime.display.xserver.extensions.XInput2Extension; import com.winlator.cmod.shared.android.CursorLocker; import java.nio.charset.Charset; +import java.util.Arrays; import java.util.EnumMap; import java.util.concurrent.locks.ReentrantLock; @@ -183,8 +184,9 @@ private class MultiXLock implements XLock { private final Lockable[] lockables; private MultiXLock(Lockable[] lockables) { - this.lockables = lockables; - for (Lockable lockable : lockables) locks.get(lockable).lock(); + this.lockables = lockables.clone(); + Arrays.sort(this.lockables); + for (Lockable lockable : this.lockables) locks.get(lockable).lock(); } @Override diff --git a/app/src/main/shared/android/RefreshRateUtils.java b/app/src/main/shared/android/RefreshRateUtils.java index 6f25edb8f..db05d2098 100644 --- a/app/src/main/shared/android/RefreshRateUtils.java +++ b/app/src/main/shared/android/RefreshRateUtils.java @@ -134,54 +134,32 @@ public static int resolvePreferredDisplayModeId(Activity activity, int requested } Display.Mode currentMode = display.getMode(); - Display.Mode[] modes = display.getSupportedModes(); - Display.Mode bestMode = null; - float bestModeRate = 0f; - boolean bestIsExact = false; - float closestDelta = Float.MAX_VALUE; + Display.Mode exact = null, closest = null; + float exactRate = 0f, closestDelta = Float.MAX_VALUE, closestRate = 0f; - for (Display.Mode mode : modes) { + for (Display.Mode mode : display.getSupportedModes()) { if (!isSameModeGroup(currentMode, mode)) continue; - float refreshRate = mode.getRefreshRate(); if (refreshRate <= 0f) continue; if (requestedHz <= 0) { - if (bestMode == null || refreshRate > bestModeRate) { - bestMode = mode; - bestModeRate = refreshRate; - } + if (exact == null || refreshRate > exactRate) { exact = mode; exactRate = refreshRate; } continue; } - if (Math.round(refreshRate) == requestedHz) { - // Any exact match beats a non-exact one; among exact matches keep the highest rate. - if (!bestIsExact || refreshRate > bestModeRate) { - bestMode = mode; - bestModeRate = refreshRate; - bestIsExact = true; - closestDelta = 0f; - } + if (exact == null || refreshRate > exactRate) { exact = mode; exactRate = refreshRate; } continue; } - - // Never let a non-exact mode override an exact match found elsewhere in the list. - if (bestIsExact) continue; - float delta = Math.abs(refreshRate - requestedHz); - if (bestMode == null - || delta < closestDelta - || (delta == closestDelta && refreshRate > bestModeRate)) { - bestMode = mode; - bestModeRate = refreshRate; - closestDelta = delta; + if (closest == null || delta < closestDelta + || (delta == closestDelta && refreshRate > closestRate)) { + closest = mode; closestDelta = delta; closestRate = refreshRate; } } - if (bestMode != null) { - return bestMode.getModeId(); - } + if (exact != null) return exact.getModeId(); + if (closest != null) return closest.getModeId(); return requestedHz <= 0 ? currentMode.getModeId() : 0; } @@ -310,6 +288,12 @@ public static void applyPreferredRefreshRate(Activity activity, int requestedHz, WindowManager.LayoutParams params = activity.getWindow().getAttributes(); int modeId = resolvePreferredDisplayModeId(activity, effectiveRequestedHz); float refreshRate = resolvePreferredRefreshRate(activity, effectiveRequestedHz); + // Skip redundant window updates: the FG target fluctuates (e.g. 114-122) but resolves to the + // same mode, so without this guard setAttributes would fire several times a second. + if (params.preferredDisplayModeId == modeId + && Math.abs(params.preferredRefreshRate - refreshRate) < 0.5f) { + return; + } params.preferredDisplayModeId = modeId; // Must be 0 when a modeId is set. params.preferredRefreshRate = modeId != 0 ? 0f : refreshRate; diff --git a/tools/frame-gen-tester/Frame-Gen-Tester.exe b/tools/frame-gen-tester/Frame-Gen-Tester.exe new file mode 100755 index 000000000..43b8a4cfc Binary files /dev/null and b/tools/frame-gen-tester/Frame-Gen-Tester.exe differ diff --git a/tools/frame-gen-tester/README.md b/tools/frame-gen-tester/README.md new file mode 100644 index 000000000..e429ef9b4 --- /dev/null +++ b/tools/frame-gen-tester/README.md @@ -0,0 +1,47 @@ +# Frame-Gen-Tester + +A 30 FPS Win64 scene for exercising Frame Generation: a character walks for 30 s, +turns, walks 30 s back, turns, and repeats — a 64 s loop — with wind moving through the +trees behind. The camera follows, so the walk phases give sustained global motion and +the spin phases give a static background with independent local motion: the two cases +that break interpolation in different ways. The forest repeats spatially, so the walk +never runs out of scenery. + +Every element is a pure function of time, so rendering at `t = n + 0.5` produces the +exact frame a perfect interpolator would generate between frames `n` and `n+1`. That +makes generated frames measurable against ground truth rather than eyeballed. + +A ticker along the top advances exactly one cell per frame and a yellow bar sweeps +linearly, so a duplicated, dropped, or out-of-order frame is visible directly. + +## Build + + ./build.sh + +`Frame-Gen-Tester.exe` is the tester. `fgtester ` is the +native build; it writes `real_NNN.ppm`, `mid_NNN.ppm` (the true midpoint) and +`q1/q2/q3_NNN.ppm` (the true 0.25/0.5/0.75 phases). + +## Use + +Add `Frame-Gen-Tester.exe` as a custom game in WinNative and run it with Frame +Generation on. It targets 30 FPS, so on a 120 Hz panel there are four vblanks per +content frame and 2x/3x/4x all have room. + +Holding 30 FPS is the whole point — the compositor is being tested against that content +rate — so at startup it benchmarks itself and picks the largest of 1280x720, 1024x576, +854x480, 640x360 or 480x270 that renders inside the frame budget. The title bar shows +the chosen size, the measured rate and the late-frame count, and a block in the top +right corner is green while 30 FPS is being held and red when it is not. Pass a size on +the command line (`Frame-Gen-Tester.exe 854 480`) to override the choice. + +Check the ticker first: it must advance one cell per real frame with no repeats or +reversals. Then watch the tree canopies (independent motion), the trunks (thin +structures) and the ground (large motion) for artifacts. + +To capture what the compositor actually produced: + + adb shell setprop debug.winnative.fgdump 0 + adb shell setprop debug.winnative.fgdump 1 + adb pull /sdcard/Android/data/com.winnative.cmod/files/ fgdump/ + python3 ../fgdump_view.py fgdump/ diff --git a/tools/frame-gen-tester/build.sh b/tools/frame-gen-tester/build.sh new file mode 100755 index 000000000..a456c0819 --- /dev/null +++ b/tools/frame-gen-tester/build.sh @@ -0,0 +1,8 @@ +#!/bin/sh +# Windows build (the tester itself) and a native build that writes frames plus the +# exact midpoints a perfect interpolator would produce. +set -e +cd "$(dirname "$0")" +x86_64-w64-mingw32-gcc -O2 -municode -mwindows fgtester.c -o Frame-Gen-Tester.exe -lgdi32 +gcc -O2 -DFGT_HEADLESS fgtester.c -o fgtester -lm +echo "built Frame-Gen-Tester.exe and fgtester" diff --git a/tools/frame-gen-tester/fgtester b/tools/frame-gen-tester/fgtester new file mode 100755 index 000000000..509c1cc1d Binary files /dev/null and b/tools/frame-gen-tester/fgtester differ diff --git a/tools/frame-gen-tester/fgtester.c b/tools/frame-gen-tester/fgtester.c new file mode 100644 index 000000000..6b9316f56 --- /dev/null +++ b/tools/frame-gen-tester/fgtester.c @@ -0,0 +1,569 @@ +// Frame Gen test scene. Everything is a pure function of time, so rendering at +// t = n + 0.5 gives the exact frame a perfect interpolator would produce. +// +// x86_64-w64-mingw32-gcc -O2 -municode -mwindows fgtester.c -o Frame-Gen-Tester.exe -lgdi32 +// gcc -O2 -DFGT_HEADLESS fgtester.c -o fgtester -lm (writes PPM frames + midpoints) + +#include +#include +#include +#include + +#define MAXW 1600 +#define MAXH 900 +#define FPS 30.0 + +static int RW = 1280, RH = 720; +static float HORIZ, FOCAL = 620.0f; +#define EYE_H 1.65f + +static unsigned char fb[MAXH * MAXW * 4]; /* BGRA, matches a Win32 DIB */ +#define PIX(x, y) (fb + (((y) * RW + (x)) << 2)) + +static float clampf(float v, float a, float b) { return v < a ? a : (v > b ? b : v); } +static float smoothstepf(float a, float b, float x) { + float t = clampf((x - a) / (b - a), 0.f, 1.f); + return t * t * (3.f - 2.f * t); +} +static float fract(float x) { return x - floorf(x); } +static float hash1(float n) { return fract(sinf(n * 12.9898f) * 43758.5453f); } +/* fast floor for the ranges this scene uses; avoids a libm call per pixel */ +static int ffloor(float v) { return (int)(v + 1048576.0f) - 1048576; } + +static void px(int x, int y, float r, float g, float b, float a) { + if (x < 0 || y < 0 || x >= RW || y >= RH || a <= 0.f) return; + unsigned char *p = PIX(x, y); + if (a >= 0.996f) { + p[2] = (unsigned char)(clampf(r, 0, 1) * 255.f); + p[1] = (unsigned char)(clampf(g, 0, 1) * 255.f); + p[0] = (unsigned char)(clampf(b, 0, 1) * 255.f); + p[3] = 255; + return; + } + float ia = 1.f - a; + p[2] = (unsigned char)(clampf(p[2] * (1.f / 255.f) * ia + r * a, 0, 1) * 255.f); + p[1] = (unsigned char)(clampf(p[1] * (1.f / 255.f) * ia + g * a, 0, 1) * 255.f); + p[0] = (unsigned char)(clampf(p[0] * (1.f / 255.f) * ia + b * a, 0, 1) * 255.f); + p[3] = 255; +} + +/* ---- precomputed tables --------------------------------------------------- + The scene needs noise, but evaluating it per pixel costs a sin per sample. + Both users of it are periodic, so they are baked once at startup. */ +#define CLW 256 +#define CLH 96 +#define CLMASK (CLW - 1) +static float cloud[CLH][CLW]; +#define NTILE 64 +static float tilecol[NTILE][3]; +#define DET 128 +#define DETMASK (DET - 1) +static float detail[DET][DET]; + +static float vnoise(const float *g, int gw, int gh, float x, float y) { + int x0 = ffloor(x), y0 = ffloor(y); + float fx = x - x0, fy = y - y0; + fx = fx * fx * (3.f - 2.f * fx); fy = fy * fy * (3.f - 2.f * fy); + int xa = ((x0 % gw) + gw) % gw, xb = (xa + 1) % gw; + int ya = ((y0 % gh) + gh) % gh, yb = (ya + 1) % gh; + float a = g[ya * gw + xa], b = g[ya * gw + xb]; + float c = g[yb * gw + xa], d = g[yb * gw + xb]; + return (a * (1 - fx) + b * fx) * (1 - fy) + (c * (1 - fx) + d * fx) * fy; +} + +static void build_tables(void) { + /* fBm from a few small periodic lattices: smooth, wraps, and costs nothing + at run time because the result is baked into a table */ + static float g1[16 * 6], g2[32 * 12], g3[64 * 24]; + for (int i = 0; i < 16 * 6; i++) g1[i] = hash1(i * 1.31f + 0.7f); + for (int i = 0; i < 32 * 12; i++) g2[i] = hash1(i * 2.17f + 3.1f); + for (int i = 0; i < 64 * 24; i++) g3[i] = hash1(i * 4.53f + 9.4f); + float lo = 1e9f, hi = -1e9f; + for (int y = 0; y < CLH; y++) + for (int x = 0; x < CLW; x++) { + float u = (float)x / CLW, v = (float)y / CLH; + float n = vnoise(g1, 16, 6, u * 16.f, v * 6.f) * 0.55f + + vnoise(g2, 32, 12, u * 32.f, v * 12.f) * 0.30f + + vnoise(g3, 64, 24, u * 64.f, v * 24.f) * 0.15f; + cloud[y][x] = n; + if (n < lo) lo = n; if (n > hi) hi = n; + } + for (int y = 0; y < CLH; y++) + for (int x = 0; x < CLW; x++) + cloud[y][x] = smoothstepf(0.45f, 0.88f, (cloud[y][x] - lo) / (hi - lo + 1e-6f)); + /* fine surface detail: real high-frequency texture, which flat shading cannot + provide and which is the first thing a misaligned blend destroys */ + for (int y = 0; y < DET; y++) + for (int x = 0; x < DET; x++) { + float a = hash1((float)(y * DET + x) * 0.917f + 4.1f); + float b = hash1((float)(((y >> 1) << 7) + (x >> 1)) * 1.703f + 8.3f); + float c = hash1((float)(((y >> 2) << 7) + (x >> 2)) * 2.311f + 2.7f); + detail[y][x] = (a - 0.5f) * 0.60f + (b - 0.5f) * 0.28f + (c - 0.5f) * 0.16f; + } + for (int i = 0; i < NTILE; i++) { + float h = hash1(i * 3.17f + 0.5f), h2 = hash1(i * 8.11f), h3 = hash1(i * 5.03f); + tilecol[i][0] = 0.16f + h * 0.10f; + tilecol[i][1] = 0.26f + h2 * 0.16f; + tilecol[i][2] = 0.12f + h3 * 0.08f; + } +} + +/* ---- motion script ------------------------------------------------------- + 30 s out, turn, 30 s back, turn, repeat. */ +#define WALK_T 30.0f +#define SPIN_T 2.0f +#define LOOP_T (2 * WALK_T + 2 * SPIN_T) +#define WALK_SPEED 3.6f + +static void character_state(float t, float *wx, float *phase, float *spin) { + float u = fmodf(t, LOOP_T); + if (u < 0) u += LOOP_T; + float x, sp = 0.f; + if (u < WALK_T) { + x = u * WALK_SPEED; + } else if (u < WALK_T + SPIN_T) { + x = WALK_T * WALK_SPEED; sp = (u - WALK_T) / SPIN_T * 6.2831853f; + } else if (u < 2 * WALK_T + SPIN_T) { + x = WALK_T * WALK_SPEED - (u - WALK_T - SPIN_T) * WALK_SPEED; + } else { + x = 0.f; sp = (u - 2 * WALK_T - SPIN_T) / SPIN_T * 6.2831853f; + } + *wx = x; + *spin = sp; + *phase = x * 1.9f; /* stride tied to distance so feet never slide */ +} + +/* ---- world ---------------------------------------------------------------- */ +#define CELL 1.5f +#define INVCELL (1.0f / CELL) + +static void draw_world(float t, float camx) { + int hy = (int)HORIZ; + float cscroll = t * 3.5f; + for (int y = 0; y < hy && y < RH; y++) { + float sky = (float)y / HORIZ; + float r0 = 0.35f + 0.42f * sky, g0 = 0.55f + 0.32f * sky, b0 = 0.86f - 0.06f * sky; + float amt = smoothstepf(0.0f, 0.55f, sky) * 0.34f; + int row = (int)(sky * (CLH - 1)); + const float *cr = cloud[row < 0 ? 0 : (row >= CLH ? CLH - 1 : row)]; + float u = cscroll; + float du = (float)CLW / (float)RW * 1.6f; + unsigned char *p = PIX(0, y); + for (int x = 0; x < RW; x++, p += 4) { + int ui = (int)u; float uf = u - (float)ui; + float c = cr[ui & CLMASK] * (1.f - uf) + cr[(ui + 1) & CLMASK] * uf; + c *= amt; + p[2] = (unsigned char)(clampf(r0 + c, 0, 1) * 255.f); + p[1] = (unsigned char)(clampf(g0 + c * 0.9f, 0, 1) * 255.f); + p[0] = (unsigned char)(clampf(b0 + c * 0.5f, 0, 1) * 255.f); + p[3] = 255; + u += du; + } + } + for (int y = hy < 0 ? 0 : hy; y < RH; y++) { + float dy = (float)y - HORIZ; + float z = (EYE_H * FOCAL) / (dy + 0.5f); + float fade = smoothstepf(90.f, 12.f, z); + float haze = 1.f - fade; + float hr = 0.62f * haze, hg = 0.72f * haze, hb = 0.80f * haze; + float dwx = z / FOCAL; + float wx = (0.5f - RW * 0.5f) * dwx + camx; + int iz = ffloor(z * INVCELL); + float detfade = 0.55f * smoothstepf(26.f, 5.f, z); + unsigned char *p = PIX(0, y); + for (int x = 0; x < RW; x++, p += 4) { + int ix = ffloor(wx * INVCELL); + unsigned h = (unsigned)(ix * 73856093) ^ (unsigned)(iz * 19349663); + const float *tc = tilecol[(h >> 7) & (NTILE - 1)]; + float k = ((ix + iz) & 1) ? 1.22f : 0.86f; + /* detail fades out with distance, as a mip chain would, so it does not alias */ + float dv = detail[ffloor(z * 22.f) & DETMASK][ffloor(wx * 22.f) & DETMASK] + * detfade; + k += dv; + p[2] = (unsigned char)(clampf(tc[0] * k * fade + hr, 0, 1) * 255.f); + p[1] = (unsigned char)(clampf(tc[1] * k * fade + hg, 0, 1) * 255.f); + p[0] = (unsigned char)(clampf(tc[2] * k * fade + hb, 0, 1) * 255.f); + p[3] = 255; + wx += dwx; + } + } +} + +static void project(float wx, float wz, float camx, float *sx, float *sy, float *scale) { + float z = wz < 0.35f ? 0.35f : wz; + *scale = FOCAL / z; + *sx = RW * 0.5f + (wx - camx) * (*scale); + *sy = HORIZ + EYE_H * (*scale); +} + +static void disc(float cx, float cy, float rx, float ry, float r, float g, float b) { + if (rx < 0.4f) rx = 0.4f; + if (ry < 0.4f) ry = 0.4f; + int x0 = (int)(cx - rx) - 1, x1 = (int)(cx + rx) + 1; + int y0 = (int)(cy - ry) - 1, y1 = (int)(cy + ry) + 1; + if (x1 < 0 || y1 < 0 || x0 >= RW || y0 >= RH) return; + if (x0 < 0) x0 = 0; if (y0 < 0) y0 = 0; + if (x1 >= RW) x1 = RW - 1; if (y1 >= RH) y1 = RH - 1; + float irx = 1.f / rx, iry = 1.f / ry; + for (int y = y0; y <= y1; y++) { + float v = (y + 0.5f - cy) * iry, v2 = v * v; + for (int x = x0; x <= x1; x++) { + float u = (x + 0.5f - cx) * irx; + float d = u * u + v2; + if (d >= 1.15f) continue; + px(x, y, r, g, b, d <= 0.80f ? 1.f : smoothstepf(1.15f, 0.80f, d)); + } + } +} + +/* rotated bar, used for limbs and trunks; sqrt only in the antialiased band */ +static void bar(float x0, float y0, float x1, float y1, float w, float r, float g, float b) { + float dx = x1 - x0, dy = y1 - y0; + float len = sqrtf(dx * dx + dy * dy); + if (len < 0.001f) return; + dx /= len; dy /= len; + int bx0 = (int)fminf(x0, x1) - (int)w - 2, bx1 = (int)fmaxf(x0, x1) + (int)w + 2; + int by0 = (int)fminf(y0, y1) - (int)w - 2, by1 = (int)fmaxf(y0, y1) + (int)w + 2; + if (bx1 < 0 || by1 < 0 || bx0 >= RW || by0 >= RH) return; + if (bx0 < 0) bx0 = 0; if (by0 < 0) by0 = 0; + if (bx1 >= RW) bx1 = RW - 1; if (by1 >= RH) by1 = RH - 1; + float wi = w - 1.2f; if (wi < 0.f) wi = 0.f; + float wo2 = w * w, wi2 = wi * wi; + for (int y = by0; y <= by1; y++) + for (int x = bx0; x <= bx1; x++) { + float pxx = x + 0.5f - x0, pyy = y + 0.5f - y0; + float tp = pxx * dx + pyy * dy; + if (tp < 0.f) tp = 0.f; else if (tp > len) tp = len; + float ox = pxx - dx * tp, oy = pyy - dy * tp; + float d2 = ox * ox + oy * oy; + if (d2 >= wo2) continue; + float dv = detail[(y * 3) & DETMASK][(x * 3) & DETMASK] * 0.5f; + px(x, y, r + dv, g + dv, b + dv, d2 <= wi2 ? 1.f : smoothstepf(w, wi, sqrtf(d2))); + } +} + +typedef struct { float wx, wz, h, phase, lean; int kind; } Tree; +#define NTREES 64 +#define TREE_PERIOD 140.0f /* the forest repeats, so the walk never runs out of it */ +static Tree trees[NTREES]; + +static void init_trees(void) { + build_tables(); + for (int i = 0; i < NTREES; i++) { + float a = hash1(i * 1.7f + 0.3f), b = hash1(i * 4.1f + 1.9f), c = hash1(i * 9.3f); + trees[i].wx = a * TREE_PERIOD; + trees[i].wz = 9.f + b * 46.f; + trees[i].h = 3.4f + c * 3.4f; + trees[i].phase = hash1(i * 2.3f) * 6.2831853f; + trees[i].lean = (hash1(i * 5.5f) - 0.5f) * 0.25f; + trees[i].kind = (int)(hash1(i * 8.8f) * 3.f); + } +} + +/* Gusty wind: two slow envelopes so sway is not a single clean sinusoid. */ +static float wind(float t, float phase) { + float gust = 0.55f + 0.45f * sinf(t * 0.37f + phase * 0.2f) * sinf(t * 0.11f + 1.3f); + return gust * (sinf(t * 1.9f + phase) + 0.45f * sinf(t * 3.7f + phase * 1.7f)); +} + +static void draw_trees(float t, float camx) { + for (int i = 0; i < NTREES; i++) { + Tree *tr = &trees[i]; + float wx = tr->wx + TREE_PERIOD * floorf((camx - tr->wx) / TREE_PERIOD + 0.5f); + float sx, sy, sc; + project(wx, tr->wz, camx, &sx, &sy, &sc); + float trunkH = tr->h * sc; + if (sx < -trunkH || sx > RW + trunkH) continue; + float sway = wind(t, tr->phase) * (0.055f + 0.02f * tr->kind); + float topx = sx + (sway + tr->lean) * trunkH * 0.55f; + float topy = sy - trunkH; + float fade = smoothstepf(90.f, 14.f, tr->wz); + float tw = clampf(trunkH * 0.045f, 1.2f, 22.f); + bar(sx, sy, topx, topy, tw, 0.26f * fade + 0.55f * (1 - fade), + 0.19f * fade + 0.66f * (1 - fade), 0.13f * fade + 0.76f * (1 - fade)); + int nb = 5 + tr->kind; + for (int k = 0; k < nb; k++) { + float f = (float)k / nb; + float lag = wind(t - 0.10f - f * 0.06f, tr->phase + k * 0.9f); + float bx = topx + lag * trunkH * 0.10f + (hash1(i * 3.f + k) - 0.5f) * trunkH * 0.42f; + float by = topy + (hash1(i * 6.f + k * 2.f) - 0.35f) * trunkH * 0.34f; + float rr = trunkH * (0.20f + 0.10f * hash1(i + k * 5.f)); + float g0 = 0.34f + 0.20f * hash1(i * 2.f + k); + disc(bx, by, rr * 1.25f, rr, 0.10f * fade + 0.6f * (1 - fade), + g0 * fade + 0.70f * (1 - fade), 0.12f * fade + 0.78f * (1 - fade)); + } + } +} + +static void draw_character(float t, float camx) { + float wx, phase, spin; + character_state(t, &wx, &phase, &spin); + float sx, sy, sc; + project(wx, 5.0f, camx, &sx, &sy, &sc); + float hgt = 1.75f * sc; + float cs = cosf(spin); + float xs = fabsf(cs) * 0.72f + 0.28f; + float step = sinf(phase), step2 = sinf(phase + 3.14159f); + float bob = fabsf(sinf(phase)) * hgt * 0.018f; + float hipY = sy - hgt * 0.48f - bob; + float shoY = sy - hgt * 0.82f - bob; + float headY = sy - hgt * 0.93f - bob; + float lw = hgt * 0.055f; + #define SXP(o) (sx + (o) * xs) + bar(SXP(0), hipY, SXP(step * hgt * 0.17f), sy - fabsf(step) * hgt * 0.06f, lw, .18f, .20f, .30f); + bar(SXP(0), hipY, SXP(step2 * hgt * 0.17f), sy - fabsf(step2) * hgt * 0.06f, lw, .14f, .16f, .26f); + bar(SXP(0), hipY, SXP(0), shoY, hgt * 0.075f, .72f, .26f, .22f); + bar(SXP(0), shoY, SXP(step2 * hgt * 0.15f), shoY + hgt * 0.24f, lw * 0.85f, .80f, .62f, .48f); + bar(SXP(0), shoY, SXP(step * hgt * 0.15f), shoY + hgt * 0.24f, lw * 0.85f, .70f, .54f, .42f); + disc(SXP(0), headY, hgt * 0.062f * xs + hgt * 0.02f, hgt * 0.072f, .90f, .74f, .60f); + if (cs > 0.f) + disc(SXP(hgt * 0.05f * (spin > 3.14159f ? -1.f : 1.f)), headY + hgt * 0.008f, + hgt * 0.018f, hgt * 0.016f, .80f, .58f, .46f); + #undef SXP +} + +/* A marker that advances exactly one cell per frame: any duplicated, dropped or + out-of-order frame is immediately visible, and it is trivial to read off a dump. */ +static void draw_tick(float t, int health) { + int n = (int)floorf(t * FPS + 0.5f); + int cells = 30, cw = RW / cells; + for (int i = 0; i < cells; i++) { + float on = (i == (n % cells)) ? 1.f : 0.12f; + for (int y = 8; y < 26; y++) + for (int x = i * cw + 3; x < (i + 1) * cw - 3; x++) px(x, y, on, on, on * 0.6f, 1.f); + } + /* smooth sub-frame sweep: position is linear in t, so a correctly paced + generated frame lands exactly between its neighbours */ + float u = fmodf(t * 0.25f, 1.f); + int bx = (int)(u * (RW - 60)); + for (int y = 32; y < 46; y++) + for (int x = bx; x < bx + 60; x++) px(x, y, 1.f, 0.85f, 0.1f, 1.f); + /* green while the tester is holding 30 FPS, red when it is not */ + for (int y = 8; y < 46; y++) + for (int x = RW - 30; x < RW - 8; x++) + px(x, y, health ? 0.1f : 0.95f, health ? 0.9f : 0.15f, 0.1f, 1.f); +} + +static void render(float t, int health) { + float wx, phase, spin; + character_state(t, &wx, &phase, &spin); + float camx = wx; + draw_world(t, camx); + draw_trees(t, camx); + draw_character(t, camx); + draw_tick(t, health); +} + +#ifdef FGT_HEADLESS +static void write_ppm(const char *path) { + FILE *f = fopen(path, "wb"); + if (!f) { fprintf(stderr, "cannot write %s\n", path); return; } + fprintf(f, "P6\n%d %d\n255\n", RW, RH); + for (int y = 0; y < RH; y++) + for (int x = 0; x < RW; x++) { + unsigned char *p = PIX(x, y); + fputc(p[2], f); fputc(p[1], f); fputc(p[0], f); + } + fclose(f); +} +int main(int argc, char **argv) { + const char *dir = argc > 1 ? argv[1] : "."; + int n0 = argc > 2 ? atoi(argv[2]) : 0; + int nframes = argc > 3 ? atoi(argv[3]) : 8; + int step = argc > 4 ? atoi(argv[4]) : 1; /* 1 = 30 FPS, 3 = 10 FPS, 15 = 2 FPS */ + if (argc > 6) { RW = atoi(argv[5]); RH = atoi(argv[6]); } + if (step < 1) step = 1; + HORIZ = RH * 0.52f; FOCAL = RW * 0.484f; + init_trees(); + char path[512]; + for (int i = 0; i < nframes; i++) { + float t = (n0 + (float)i * step) / FPS; + float d = step / FPS; /* interval between presented frames */ + render(t, 1); + snprintf(path, sizeof(path), "%s/real_%03d.ppm", dir, i); write_ppm(path); + render(t + 0.5f * d, 1); + snprintf(path, sizeof(path), "%s/mid_%03d.ppm", dir, i); write_ppm(path); + for (int q = 1; q <= 3; q++) { + render(t + q * 0.25f * d, 1); + snprintf(path, sizeof(path), "%s/q%d_%03d.ppm", dir, q, i); write_ppm(path); + } + } + printf("wrote %d frames at step %d (%.0f FPS) to %s (%dx%d)\n", + nframes, step, FPS / step, dir, RW, RH); + return 0; +} +#else +#include + +static double now_s(LARGE_INTEGER freq) { + LARGE_INTEGER c; QueryPerformanceCounter(&c); + return (double)c.QuadPart / (double)freq.QuadPart; +} + +/* Presentation rate. The animation clock always runs in real time, so dropping the + rate skips the frames in between rather than slowing the scene down: the character + jumps to where it would have been. That is the point of the lower rates - it gives + frame generation a much larger gap to bridge. */ +static const int RATES[3] = {30, 10, 2}; +static int g_rate_idx = 0; +#define RATE_STEP (30 / RATES[g_rate_idx]) + +#define BTN_W 76 +#define BTN_H 32 +#define BTN_Y 52 +#define BTN_X0 12 +#define BTN_GAP 8 +static void btn_rect(int i, RECT *r) { + r->left = BTN_X0 + i * (BTN_W + BTN_GAP); + r->top = BTN_Y; r->right = r->left + BTN_W; r->bottom = BTN_Y + BTN_H; +} + +static LRESULT CALLBACK wndproc(HWND h, UINT m, WPARAM w, LPARAM l) { + switch (m) { + case WM_DESTROY: PostQuitMessage(0); return 0; + case WM_LBUTTONDOWN: { + int mx = (short)LOWORD(l), my = (short)HIWORD(l); + for (int i = 0; i < 3; i++) { + RECT r; btn_rect(i, &r); + if (mx >= r.left && mx < r.right && my >= r.top && my < r.bottom) { + g_rate_idx = i; break; + } + } + return 0; + } + case WM_KEYDOWN: + if (w == VK_ESCAPE) PostQuitMessage(0); + else if (w == '1') g_rate_idx = 0; + else if (w == '2') g_rate_idx = 1; + else if (w == '3') g_rate_idx = 2; + return 0; + case WM_ERASEBKGND: return 1; + } + return DefWindowProcW(h, m, w, l); +} + +static void draw_buttons(HDC dc, HFONT font) { + HFONT old = (HFONT)SelectObject(dc, font); + SetBkMode(dc, TRANSPARENT); + for (int i = 0; i < 3; i++) { + RECT r; btn_rect(i, &r); + int on = (i == g_rate_idx); + HBRUSH bg = CreateSolidBrush(on ? RGB(240, 200, 40) : RGB(30, 34, 44)); + FillRect(dc, &r, bg); + DeleteObject(bg); + HBRUSH fr = CreateSolidBrush(on ? RGB(255, 255, 255) : RGB(120, 130, 150)); + FrameRect(dc, &r, fr); + DeleteObject(fr); + wchar_t lab[16]; + swprintf(lab, 16, L"%d FPS", RATES[i]); + SetTextColor(dc, on ? RGB(20, 20, 20) : RGB(215, 220, 230)); + DrawTextW(dc, lab, -1, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + } + SelectObject(dc, old); +} + +/* Pick the largest of a few sizes that renders inside the frame budget. The + content rate is what the compositor is being tested against, so holding 30 FPS + matters more than resolution. */ +static void pick_resolution(void) { + static const int cand[][2] = {{1280,720},{1024,576},{854,480},{640,360},{480,270}}; + LARGE_INTEGER freq; QueryPerformanceFrequency(&freq); + for (int i = 0; i < 5; i++) { + RW = cand[i][0]; RH = cand[i][1]; + HORIZ = RH * 0.52f; FOCAL = RW * 0.484f; + render(0.f, 1); /* warm caches */ + double a = now_s(freq); + for (int k = 0; k < 3; k++) render(k * 0.033f, 1); + double ms = (now_s(freq) - a) * 1000.0 / 3.0; + if (ms <= 16.0 || i == 4) return; + } +} + +int WINAPI wWinMain(HINSTANCE hi, HINSTANCE hp, PWSTR cmd, int show) { + (void)hp; + init_trees(); + int forced = 0; + if (cmd && *cmd) { + int w = 0, h = 0; + if (swscanf(cmd, L"%d %d", &w, &h) == 2 && w >= 320 && h >= 180 && w <= MAXW && h <= MAXH) { + RW = w; RH = h; forced = 1; + HORIZ = RH * 0.52f; FOCAL = RW * 0.484f; + } + } + if (!forced) pick_resolution(); + + WNDCLASSW wc = {0}; + wc.lpfnWndProc = wndproc; wc.hInstance = hi; wc.lpszClassName = L"FGTester"; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + RegisterClassW(&wc); + RECT r = {0, 0, RW, RH}; + AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, FALSE); + HWND hwnd = CreateWindowW(L"FGTester", L"Frame-Gen-Tester", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, r.right - r.left, r.bottom - r.top, + NULL, NULL, hi, NULL); + ShowWindow(hwnd, show); + HDC dc = GetDC(hwnd); + BITMAPINFO bi = {0}; + bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bi.bmiHeader.biWidth = RW; bi.bmiHeader.biHeight = -RH; + bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 32; bi.bmiHeader.biCompression = BI_RGB; + void *bits = NULL; + HBITMAP dib = CreateDIBSection(dc, &bi, DIB_RGB_COLORS, &bits, NULL, 0); + HDC memdc = CreateCompatibleDC(dc); + SelectObject(memdc, dib); + + HFONT font = CreateFontW(-16, 0, 0, 0, FW_BOLD, 0, 0, 0, DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, + DEFAULT_PITCH | FF_SWISS, L"Segoe UI"); + + LARGE_INTEGER freq; QueryPerformanceFrequency(&freq); + /* n counts in 30 FPS units regardless of the presentation rate, so the animation + clock stays real-time and a lower rate simply skips the frames between presents */ + double t0 = now_s(freq), tick = 1.0 / FPS; + long long n = 0, win_late = 0, win_n = 0; + double win_t0 = t0; + int health = 1; + MSG msg; + for (;;) { + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) { + if (msg.message == WM_QUIT) goto done; + TranslateMessage(&msg); DispatchMessageW(&msg); + } + int step = RATE_STEP; + double target = n * tick; + render((float)target, health); + memcpy(bits, fb, (size_t)RW * RH * 4); + draw_buttons(memdc, font); + BitBlt(dc, 0, 0, RW, RH, memdc, 0, 0, SRCCOPY); + n += step; win_n++; + double after = now_s(freq) - t0; + if (after > target + step * tick) win_late++; + if (now_s(freq) - win_t0 >= 1.0) { + double secs = now_s(freq) - win_t0; + double fps = win_n / secs; + int want = RATES[g_rate_idx]; + health = (win_late * 20 <= win_n); /* under 5% late frames */ + wchar_t title[224]; + swprintf(title, 224, + L"Frame-Gen-Tester %dx%d %.1f FPS (target %d, skipping %d of every %d)" + L" late %lld/%lld %s", + RW, RH, fps, want, step - 1, step, win_late, win_n, + health ? L"OK" : L"TOO SLOW"); + SetWindowTextW(hwnd, title); + win_t0 = now_s(freq); win_n = 0; win_late = 0; + } + for (;;) { + double e = now_s(freq) - t0, tg = n * tick; + if (e >= tg) break; + double rem = tg - e; + if (rem > 0.002) Sleep((DWORD)((rem - 0.001) * 1000)); + } + /* never try to catch up by racing: a stalled frame just shifts the phase */ + if (now_s(freq) - t0 > (n + 2 * step) * tick) t0 = now_s(freq) - n * tick; + } +done: + DeleteObject(font); + DeleteDC(memdc); DeleteObject(dib); ReleaseDC(hwnd, dc); + return 0; +} +#endif diff --git a/tools/frame-gen-tester/prof.c b/tools/frame-gen-tester/prof.c new file mode 100644 index 000000000..9510c0fd3 --- /dev/null +++ b/tools/frame-gen-tester/prof.c @@ -0,0 +1,2 @@ +#define FGT_HEADLESS +#include "fgtester.c"