diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 001fd003d..c01125a26 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,20 @@ 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" ) set(SHADER_HEADERS "") @@ -128,11 +132,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..6d628a3fa --- /dev/null +++ b/app/src/main/cpp/winlator/vk/shaders/cnn_generate.comp @@ -0,0 +1,88 @@ +#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; + + float m0 = pc.mvScale; // signed: midpoint gather = -0.5*flow + float t = pc.t; + float a = 2.0 * t; + float b = 2.0 * (1.0 - t); + + int smR = (pc.flags >> 4) & 7; // bilateral flow-denoise radius (flags bits 4-6) + vec2 flB, flF; + if (smR > 0) { + vec3 cc = texture(backColor, uvc).rgb; // guide on prev color: smooth within objects, keep edges + 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)) / texSize; + 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) * m0; + flF = sF / max(ws, 1e-4) * m0; + } else { + flB = texture(flowB, uvc).xy * m0; + flF = texture(flowF, uvc).xy * m0; + } + if ((pc.flags & 1) != 0) flF = -flF; + if ((pc.flags & 2) != 0) flF *= 0.5; + + vec2 c0 = (numer + flB * a) / texSize; + vec2 c1 = (numer - flB * b) / texSize; + vec2 c2 = (numer + flF * a) / texSize; + vec2 c3 = (numer - flF * b) / 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/interpolate.frag b/app/src/main/cpp/winlator/vk/shaders/interpolate.frag new file mode 100644 index 000000000..f83bc1a77 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/shaders/interpolate.frag @@ -0,0 +1,112 @@ +#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 luma1(vec3 c) { return dot(c, vec3(0.299, 0.587, 0.114)); } + +float valid(vec3 c, highp vec2 p) { + return (dot(c, c) > 1e-4 && !offFrame(p)) ? 1.0 : 0.0; +} + +void main() { + float t = clamp(pc.phase, 0.0, 1.0); + float steadier = clamp(pc.occlusionLo, 0.0, 1.0); + bool cnn = pc.mode >= 3.5; + float imode = cnn ? pc.mode - 4.0 : pc.mode; + + highp vec2 norm = 2.0 / pc.resolution; + vec2 mvB = texture(motionField, vUV).xy; + 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(cWarp, 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; + 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 = norm * 0.5; + 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; + } + + highp vec2 uvA = vUV + t * mvBn; + highp vec2 uvB = vUV - (1.0 - t) * mvBn; + vec3 cA = texture(prevFrame, uvA).rgb; + vec3 cB = texture(currFrame, uvB).rgb; + float tolE = 0.05 * dot(mvB, mvB) + 2.0; + float hiE = 6.0 * tolE + 6.0; + vec2 dA = mvB - texture(motionField, uvA).xy; + vec2 dB = mvB - texture(motionField, uvB).xy; + float occA = 1.0 - smoothstep(tolE, hiE, dot(dA, dA)); + float occB = 1.0 - smoothstep(tolE, hiE, dot(dB, dB)); + float lA = (occA - 1.0) * 16.0 + (valid(cA, uvA) - 1.0) * 24.0; + float lB = (occB - 1.0) * 16.0 + (valid(cB, 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; + float selB = wB / wsum; + vec3 col = (cA * wA + cB * wB) / wsum; + + vec3 repeat = (t < 0.5) ? cPrevFlat : cCurrFlat; + col = mix(repeat, col, uniq * (1.0 - 0.30 * steadier)); + + vec2 tx = norm * 0.5; + vec3 blur = (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; + float kdet = cnn ? (0.30 - 0.15 * steadier) + : (0.55 - 0.30 * steadier) * selB * (1.0 - smoothstep(9.0, 64.0, dot(mvB, mvB))); + col += kdet * clamp(cB - blur, -0.25, 0.25); + + col = mix(col, cCurrFlat, 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..df07f7b7d --- /dev/null +++ b/app/src/main/cpp/winlator/vk/shaders/motion.comp @@ -0,0 +1,158 @@ +#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 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) { + vec3 e = exp2(log2(max(c, vec3(1e-6))) * 0.45454547); + return dot(e, vec3(0.299, 0.587, 0.114)); +} + +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 - FR) : 0; + int tSpan = fine ? (LS + 2 * (FR + 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); + + ivec2 center = ivec2(0); + ivec2 bestD = ivec2(0); + float bestCost = blockCost(l, cCenter, ivec2(0)); + + int minStep = clamp(int(pc.minStep), 1, 8); + int startStep = fine ? 2 : 8; + for (int step = startStep; step >= minStep; step >>= 1) { + 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) > RMAX || abs(d.y) > RMAX) continue; + float cost = blockCost(l, cCenter, d); + if (cost < localBest) { localBest = cost; localBestD = d; } + } + } + if (localBest < bestCost) { bestCost = localBest; bestD = localBestD; center = localBestD; } + } + + float wsum = 0.0; + vec2 disp = vec2(0.0); + for (int sy = -1; sy <= 1; ++sy) { + for (int sx = -1; sx <= 1; ++sx) { + ivec2 dd = bestD + ivec2(sx, sy); + if (abs(dd.x) > RMAX || abs(dd.y) > RMAX) continue; + float c = (sx == 0 && sy == 0) ? bestCost : blockCost(l, cCenter, dd); + float w = exp(-(c - bestCost) * 4.0); + disp += w * vec2(dd); + wsum += w; + } + } + vec2 sub = (fine ? coarseAt(p) : vec2(0.0)) + disp / max(wsum, 1e-6); + + 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); + + const int OFF = 2 * BR + 1; + float second = 3.0e30; + if (bestD.x + OFF <= RMAX) second = min(second, blockCost(l, cCenter, bestD + ivec2( OFF, 0))); + if (bestD.x - OFF >= -RMAX) second = min(second, blockCost(l, cCenter, bestD + ivec2(-OFF, 0))); + if (bestD.y + OFF <= RMAX) second = min(second, blockCost(l, cCenter, bestD + ivec2(0, OFF))); + if (bestD.y - OFF >= -RMAX) second = min(second, blockCost(l, cCenter, bestD + ivec2(0, -OFF))); + float conf = clamp((second - bestCost) / (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..18d750e98 --- /dev/null +++ b/app/src/main/cpp/winlator/vk/shaders/motion_fp32.comp @@ -0,0 +1,152 @@ +#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 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) { + vec3 e = exp2(log2(max(c, vec3(1e-6))) * 0.45454547); + return dot(e, vec3(0.299, 0.587, 0.114)); +} + +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); + + ivec2 center = ivec2(0); + ivec2 bestD = ivec2(0); + float bestCost = blockCost(l, cCenter, ivec2(0)); + + int minStep = clamp(int(pc.minStep), 1, 8); + for (int step = 8; step >= minStep; step >>= 1) { + 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) > RMAX || abs(d.y) > RMAX) continue; + float cost = blockCost(l, cCenter, d); + if (cost < localBest) { localBest = cost; localBestD = d; } + } + } + if (localBest < bestCost) { bestCost = localBest; bestD = localBestD; center = localBestD; } + } + + float wsum = 0.0; + vec2 disp = vec2(0.0); + for (int sy = -1; sy <= 1; ++sy) { + for (int sx = -1; sx <= 1; ++sx) { + ivec2 dd = bestD + ivec2(sx, sy); + if (abs(dd.x) > RMAX || abs(dd.y) > RMAX) continue; + float c = (sx == 0 && sy == 0) ? bestCost : blockCost(l, cCenter, dd); + float w = exp(-(c - bestCost) * 4.0); + disp += w * vec2(dd); + wsum += w; + } + } + vec2 sub = (fine ? coarseAt(p) : vec2(0.0)) + disp / max(wsum, 1e-6); + + 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); + + const int OFF = 2 * BR + 1; + float second = 3.0e30; + if (bestD.x + OFF <= RMAX) second = min(second, blockCost(l, cCenter, bestD + ivec2( OFF, 0))); + if (bestD.x - OFF >= -RMAX) second = min(second, blockCost(l, cCenter, bestD + ivec2(-OFF, 0))); + if (bestD.y + OFF <= RMAX) second = min(second, blockCost(l, cCenter, bestD + ivec2(0, OFF))); + if (bestD.y - OFF >= -RMAX) second = min(second, blockCost(l, cCenter, bestD + ivec2(0, -OFF))); + float conf = clamp((second - bestCost) / (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..77463bd4e --- /dev/null +++ b/app/src/main/cpp/winlator/vk/vk_cnn_fg.c @@ -0,0 +1,893 @@ +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) { + return true; +} + +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; + + float fs = r->fg_flow_scale >= 0.2f ? (r->fg_flow_scale <= 1.0f ? r->fg_flow_scale : 1.0f) : 0.5f; + 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 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, fs=%.2f)", mw, mh, CNN_LEVELS, (double)fs); + 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) : -0.25f; // SIGNED: midpoint gather needs flB=-0.5*flow; +0.25 was wrong-sign (ghosting) + char f2s[16] = {0}; __system_property_get("debug.winnative.fgflow2", f2s); + int flow2 = f2s[0] ? atoi(f2s) : 0; // 1 = feed distinct backward flow to s35 + 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 a698c30d9..93343ce25 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); @@ -148,8 +148,13 @@ bool vkd_load_instance(VkInstance instance) { LOAD(CmdSetViewport); LOAD(CmdSetScissor); LOAD(CmdDraw); + LOAD(CmdDispatch); LOAD(CmdPipelineBarrier); + 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 bf37d977d..9864a1044 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; @@ -125,8 +118,13 @@ typedef struct VkDispatch { PFN_vkCmdSetViewport CmdSetViewport; PFN_vkCmdSetScissor CmdSetScissor; PFN_vkCmdDraw CmdDraw; + PFN_vkCmdDispatch CmdDispatch; PFN_vkCmdPipelineBarrier CmdPipelineBarrier; + PFN_vkCmdBlitImage CmdBlitImage; + PFN_vkCmdCopyImage CmdCopyImage; + PFN_vkCmdClearColorImage CmdClearColorImage; PFN_vkCmdCopyBufferToImage CmdCopyBufferToImage; + PFN_vkCmdCopyImageToBuffer CmdCopyImageToBuffer; // Queue PFN_vkQueueSubmit QueueSubmit; @@ -144,15 +142,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 @@ -211,6 +204,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 @@ -218,6 +212,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 @@ -251,8 +246,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 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 b65be3eb7..9d59c9518 100644 --- a/app/src/main/cpp/winlator/vk/vk_renderer.c +++ b/app/src/main/cpp/winlator/vk/vk_renderer.c @@ -1,30 +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" @@ -44,6 +39,48 @@ #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/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 @@ -54,6 +91,15 @@ 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 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); @@ -65,6 +111,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); @@ -349,11 +411,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; @@ -372,6 +464,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) { @@ -390,7 +527,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; @@ -402,6 +543,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"); @@ -429,8 +602,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; } @@ -447,16 +630,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] = { @@ -472,7 +647,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; @@ -486,7 +660,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 = { @@ -509,8 +682,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"); @@ -562,20 +733,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; @@ -707,8 +914,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; @@ -723,8 +928,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; @@ -739,9 +942,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, @@ -864,12 +1133,16 @@ 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); 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) { return false; } @@ -976,6 +1249,14 @@ 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_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); @@ -995,12 +1276,16 @@ 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); 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_interp_pipeline) { destroy_pipelines(r); return false; } @@ -1033,9 +1318,16 @@ 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_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)); @@ -1121,29 +1413,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) @@ -1181,14 +1477,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; @@ -1222,6 +1518,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) { @@ -1391,9 +1697,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; @@ -1457,11 +1760,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]; @@ -1638,10 +1937,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]; @@ -1837,62 +2133,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; @@ -1910,9 +2161,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; @@ -1926,48 +2174,23 @@ static bool record_and_submit_frame(VkRenderer* r) { destroy_sgsr1_resources(r); } - uint32_t image_index = 0; - VkResult acq = vkAcquireNextImageKHR(r->device, r->swapchain, UINT64_MAX, - f->image_available, VK_NULL_HANDLE, &image_index); - bool recreate_after_present = 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); - 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("vkAcquireNextImageKHR -> %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); - - VkCommandBufferBeginInfo bi = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; - 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 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[0] = 0.0f; - clear.color.float32[1] = 0.0f; - clear.color.float32[2] = 0.0f; clear.color.float32[3] = 1.0f; if (has_effects) { @@ -1975,7 +2198,6 @@ static bool record_and_submit_frame(VkRenderer* r) { ? &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; @@ -1983,34 +2205,32 @@ static bool record_and_submit_frame(VkRenderer* r) { 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); + vkCmdBeginRenderPass(cmd, &rpbi, VK_SUBPASS_CONTENTS_INLINE); + draw_scene_pass(r, cmd, snap, true, scene_target->width, scene_target->height); + vkCmdEndRenderPass(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]; - + 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; + 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(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); + 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; @@ -2018,16 +2238,84 @@ static bool record_and_submit_frame(VkRenderer* r) { } } 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.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(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); + 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); + bool recreate_after_present = 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); + 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("vkAcquireNextImageKHR -> %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); + + VkCommandBufferBeginInfo bi = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + bi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(f->cmd, &bi); + + 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); vkEndCommandBuffer(f->cmd); @@ -2046,8 +2334,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; @@ -2068,6 +2354,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++; pthread_mutex_unlock(&r->queue_mutex); bool present_suboptimal = (pr == VK_SUBOPTIMAL_KHR) && !r->ignore_suboptimal; @@ -2082,86 +2369,1568 @@ 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) - 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; +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_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; } } - - 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}; - nsi.magFilter = VK_FILTER_NEAREST; - nsi.minFilter = VK_FILTER_NEAREST; - nsi.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - nsi.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - nsi.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - nsi.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; - nsi.unnormalizedCoordinates = VK_FALSE; - nsi.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; - if (vkCreateSampler(r->device, &nsi, NULL, &r->shared_sampler_nearest) != VK_SUCCESS) goto fail; + 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)); } - if (r->ext_filter_cubic) { - VkSamplerCreateInfo csi = {VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - csi.magFilter = VK_FILTER_CUBIC_EXT; - csi.minFilter = VK_FILTER_LINEAR; - csi.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - csi.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - csi.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - csi.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; - csi.unnormalizedCoordinates = VK_FALSE; - csi.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; - if (vkCreateSampler(r->device, &csi, NULL, &r->shared_sampler_cubic) != VK_SUCCESS) { - r->shared_sampler_cubic = VK_NULL_HANDLE; - r->ext_filter_cubic = false; - } + 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* 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); } - if (!vkr_staging_pool_init(r)) goto fail; - vkr_suballoc_init(r); + memset(r->fg_motion, 0, sizeof(r->fg_motion)); + 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; +} - r->initialized = true; +// 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; + + 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_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 = 2.0f; + 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; + 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, "480 270 RGBA8 8gen+prev+curr\n"); fclose(fp); } + used = dirs[d]; + } + } + if (used) VK_LOGI("fgdump written: %s/fgdump_NN.raw (00-07 gen, 08 prev, 09 curr)", used); + else VK_LOGE("fgdump write failed (no writable path)"); + r->fg_dump_armed = false; r->fg_dump_count = 0; +} + +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; + { + float fs = r->fg_flow_scale >= 0.2f ? (r->fg_flow_scale <= 1.0f ? r->fg_flow_scale : 1.0f) : 0.5f; + 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 cw = (mw / 2) ? (mw / 2) : 1u, ch = (mh / 2) ? (mh / 2) : 1u; + r->fg_built_flow_scale = fs; + 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_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_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_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); + #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_motion[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.2f && 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, float phase) { + uint64_t now = now_monotonic_ns(); + uint64_t ca = r->fg_curr_arrival_ns, pa = r->fg_prev_arrival_ns; + // disp = the vblank period Java derives slots from, so the snap matches the slot cadence + uint64_t disp = r->fg_display_period_ns ? r->fg_display_period_ns : r->refresh_duration_ns; + uint64_t period = r->fg_present_period_ns ? r->fg_present_period_ns : r->refresh_duration_ns; + uint64_t deadline; + if (ca != 0 && pa != 0 && ca > pa) { + if (phase < 0.0f) phase = 0.0f; + // snap the content period to whole vblanks (same EMA as slots) -> presents on the even grid + uint64_t cp = ca - pa; + uint64_t ema = r->fg_content_period_ns ? r->fg_content_period_ns : cp; + if (disp != 0) { + uint64_t k = (uint64_t)(((double)ema / (double)disp) + 0.5); // == fgEmitOne slots + if (k < 1u) k = 1u; + cp = k * disp; + } + deadline = ca + (uint64_t)((double)phase * (double)cp); + } else if (period != 0) { + deadline = r->fg_present_deadline_ns + period; // pre-lock fallback: even period grid + } else { + r->fg_present_deadline_ns = 0; r->fg_present_target_ns = 0; return 0; + } + if (deadline < now) deadline = now; // never schedule in the past + 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_submit(VkRenderer* r, FgMode mode, float phase) { + 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); + + // Content-dedup step 1: resolve the previous staged frame (deferred promote). + bool promoted = false; + if (r->fg_sig_supported && r->fg_stage_slot >= 0) { + uint32_t sslot = (uint32_t)r->fg_stage_slot; + if (r->fg_slot_fence[sslot] != VK_NULL_HANDLE) + vkWaitForFences(r->device, 1, &r->fg_slot_fence[sslot], VK_TRUE, UINT64_MAX); + double delta = fg_sig_delta(r, sslot, r->fg_history_curr); // = # signature pixels that moved + 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); + if (delta > 0.0 || r->fg_history_count < 2u || backstop) { + 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++; // worker jobs snapshot this to drop a present whose pair was reused + promoted = true; + } else { + r->fg_dup_dropped++; + } + r->fg_stage_slot = -1; + } + + // 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; // pending; promoted on the next HOLD + } else { + r->fg_history_curr = stage; // no dedup: behave as before (advance every HOLD) + 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(); + promoted = true; + } + if (promoted) r->fg_promote_count++; + 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, phase); + 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); + } + } + + 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 acq_timeout = (want_interp && r->active_present_mode != VK_PRESENT_MODE_FIFO_KHR) ? 0u : 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 = do_interp ? job->curr_idx : r->fg_history_curr; + uint32_t prev_idx = do_interp ? job->prev_idx : ((r->fg_history_curr + 2u) % 3u); + 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 { + 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); + if (compute_fwd) { + 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); + } + } + } + + 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++; + } + } + } + + 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) { + 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, phase); + 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) { + bool got_job; + if (pending.valid) { + uint64_t wait_ns = (r->fg_display_period_ns ? r->fg_display_period_ns : 16666667ull) * 2u; + struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += (time_t)(wait_ns / 1000000000ull); + ts.tv_nsec += (long)(wait_ns % 1000000000ull); + if (ts.tv_nsec >= 1000000000L) { ts.tv_nsec -= 1000000000L; ts.tv_sec++; } + got_job = (sem_timedwait(&r->fg_gen_sem, &ts) == 0); + } else { + got_job = (sem_wait(&r->fg_gen_sem) == 0); + } + if (!r->fg_gen_running) break; + + bool need_recreate = false; + FgPending ready = {0}; + if (got_job) { + uint32_t head = r->fg_job_head; + if (head != __atomic_load_n(&r->fg_job_tail, __ATOMIC_ACQUIRE)) { + 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++; + } else { + ready = fg_worker_generate(r, &job); + if (ready.need_recreate) need_recreate = true; + } + } + } + // Present the previously generated frame; the just-generated one's GPU runs during this deadline wait. + if (pending.valid && fg_worker_do_present(r, &pending)) need_recreate = true; + pending = ready; + if (need_recreate) { + fg_worker_recreate(r); + pending.valid = false; // anything acquired before the recreate is now stale + } + } + 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.5f; + 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}; + nsi.magFilter = VK_FILTER_NEAREST; + nsi.minFilter = VK_FILTER_NEAREST; + nsi.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + nsi.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + nsi.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + nsi.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; + nsi.unnormalizedCoordinates = VK_FALSE; + nsi.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + if (vkCreateSampler(r->device, &nsi, NULL, &r->shared_sampler_nearest) != VK_SUCCESS) goto fail; + } + if (r->ext_filter_cubic) { + VkSamplerCreateInfo csi = {VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + csi.magFilter = VK_FILTER_CUBIC_EXT; + csi.minFilter = VK_FILTER_LINEAR; + csi.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + csi.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + csi.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + csi.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; + csi.unnormalizedCoordinates = VK_FALSE; + csi.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + if (vkCreateSampler(r->device, &csi, NULL, &r->shared_sampler_cubic) != VK_SUCCESS) { + r->shared_sampler_cubic = VK_NULL_HANDLE; + r->ext_filter_cubic = false; + } + } + if (!vkr_staging_pool_init(r)) goto fail; + vkr_suballoc_init(r); + + r->initialized = true; return (jlong)(intptr_t)r; fail: @@ -2193,6 +3962,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. @@ -2212,6 +3982,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_sgsr1_resources(r); destroy_offscreen(r); destroy_swapchain(r); @@ -2236,8 +4007,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; } @@ -2249,9 +4019,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); @@ -2264,6 +4032,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) { @@ -2303,9 +4072,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); } @@ -2314,12 +4081,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); @@ -2327,6 +4098,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 void JNICALL JNI_FN(nativeSurfaceDestroyed)(JNIEnv* env, jclass clazz, jlong handle) { @@ -2334,6 +4106,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); @@ -2358,10 +4131,188 @@ 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(nativeRenderHold)(JNIEnv* env, jclass clazz, jlong handle) { + (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) ? 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) { + (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); // O(1) producer; the worker generates+presents + return JNI_TRUE; +} + +JNIEXPORT jboolean JNICALL JNI_FN(nativePresentLast)(JNIEnv* env, jclass clazz, jlong handle, jfloat phase, jlong prevNs, jlong currNs) { + (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); + 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.2f ? 0.2f : (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; +} + +JNIEXPORT jint JNICALL JNI_FN(nativeGetFillHolds)(JNIEnv* env, jclass clazz) { + (void)env; (void)clazz; + char v[PROP_VALUE_MAX] = {0}; + __system_property_get("debug.winnative.fgfill", v); + return v[0] ? (jint)atoi(v) : 1; // default: complete the motion to curr on a late-frame hold +} + // 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 @@ -2392,8 +4343,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)", @@ -2500,14 +4449,9 @@ 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 on the X dispatch thread (XClient.enforceAbsoluteFramerate) and by -// the swapchain present mode + Choreographer-coalesced render requests. The compositor used -// to run its own sleep+busy-spin here too, which duplicated the pacing and burned CPU; this -// entry point is kept as a no-op for Java-side ABI compatibility. +// No-op, kept for Java-side ABI compatibility (FPS pacing is enforced elsewhere). JNIEXPORT void JNICALL JNI_FN(nativeSetFpsLimit)(JNIEnv* env, jclass clazz, jlong handle, jint fps) { (void)env; (void)clazz; (void)handle; (void)fps; } @@ -2527,9 +4471,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; @@ -2549,6 +4491,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); @@ -2565,6 +4509,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); } // ============================================================ @@ -2614,8 +4559,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 74c0a414f..1e8d064e4 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,14 +18,21 @@ #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; #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 { \ @@ -38,16 +43,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; @@ -55,28 +59,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; @@ -117,14 +115,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 { @@ -132,7 +130,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 { @@ -146,14 +144,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; @@ -172,8 +168,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; @@ -186,6 +182,30 @@ 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_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; // ============================================================ @@ -219,27 +239,89 @@ 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; + // ============================================================ // Staging pool for async texture uploads // ============================================================ 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; @@ -258,33 +340,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 @@ -304,7 +377,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; @@ -317,23 +390,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; @@ -367,13 +432,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_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_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 + 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]; + // Quad vertex buffer (window/cursor) 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; @@ -397,8 +525,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; @@ -410,33 +537,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; // ============================================================ @@ -464,10 +642,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, @@ -479,7 +654,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 d4f22571a..67d66f0cc 100644 --- a/app/src/main/feature/settings/other/OtherSettingsFragment.kt +++ b/app/src/main/feature/settings/other/OtherSettingsFragment.kt @@ -149,6 +149,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) @@ -230,6 +234,7 @@ class OtherSettingsFragment : Fragment() { .coerceIn(10, 300), cursorLock = preferences.getBoolean("cursor_lock", false), xinputDisabled = preferences.getBoolean("xinput_toggle", false), + nativeFrameGen = preferences.getBoolean("native_frame_generation", false), enableFileProvider = preferences.getBoolean("enable_file_provider", true), openInBrowser = preferences.getBoolean("open_with_android_browser", false), shareClipboard = preferences.getBoolean("share_android_clipboard", false), diff --git a/app/src/main/feature/settings/other/OtherSettingsScreen.kt b/app/src/main/feature/settings/other/OtherSettingsScreen.kt index bf6249065..1a4361aad 100644 --- a/app/src/main/feature/settings/other/OtherSettingsScreen.kt +++ b/app/src/main/feature/settings/other/OtherSettingsScreen.kt @@ -105,6 +105,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 openInBrowser: Boolean = false, val shareClipboard: Boolean = false, @@ -148,6 +149,7 @@ fun OtherSettingsScreen( onCursorSpeedChanged: (Int) -> Unit, onCursorLockChanged: (Boolean) -> Unit, onXinputDisabledChanged: (Boolean) -> Unit, + onNativeFrameGenChanged: (Boolean) -> Unit, onEnableFileProviderChanged: (Boolean) -> Unit, onOpenInBrowserChanged: (Boolean) -> Unit, onShareClipboardChanged: (Boolean) -> Unit, @@ -281,6 +283,16 @@ fun OtherSettingsScreen( ) } + item(key = "native_frame_gen_card") { + 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, + ) + } + item(key = "integration_section") { SectionLabel(stringResource(R.string.settings_other_section_integration), modifier = Modifier.padding(top = 8.dp)) } diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 61f29a91a..3b0bf06f7 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -1334,6 +1334,15 @@ Installeret sti: Indlæser Workshop-elementer Søg i Workshop-elementer Mislykket + 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 23c44fbde..a6c299f8a 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -1334,6 +1334,15 @@ Installierter Pfad: Workshop-Elemente werden geladen Workshop-Elemente suchen Fehlgeschlagen + 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 010aa4e28..9b9accb69 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -1334,6 +1334,15 @@ Ruta instalada: Cargando elementos de Workshop Buscar elementos de Workshop Fallido + 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 cb552cdfc..677a0b56b 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -1334,6 +1334,15 @@ Chemin installé : Chargement des éléments du Workshop Rechercher des éléments du Workshop Échec + 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 78aa00407..feff61f96 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -1271,6 +1271,15 @@ Workshop आइटम लोड हो रहे हैं Workshop आइटम खोजें विफल + फ्रेम जेन + मल्टीप्लायर + क्वालिटी प्रीसेट + परफॉर्मेंस + बैलेंस्ड + क्वालिटी + स्मूदनेस + नेटिव फ्रेम जनरेशन + मोशन को स्मूद बनाने के लिए कंपोजिटर में इंटरपोलेटेड फ्रेम जोड़ें। यह किसी भी गेम के साथ काम करता है (किसी गेम डेटा की ज़रूरत नहीं) और इनपुट लेटेंसी थोड़ी बढ़ा देता है। नया नाम बदलें जेस्चर प्रोफ़ाइल निर्यात करें diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 8883a0cab..df494e9bf 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -1334,6 +1334,15 @@ Percorso installato: Caricamento elementi Workshop Cerca elementi Workshop Non riuscito + 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 3ec6a6bb7..aa043eea7 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -1335,6 +1335,15 @@ Workshop 항목 로드 중 Workshop 항목 검색 실패 + 프레임 생성 + 배수 + 품질 프리셋 + 성능 + 균형 + 품질 + 부드러움 + 네이티브 프레임 생성 + 컴포지터에서 보간 프레임을 삽입하여 움직임을 부드럽게 만듭니다. 모든 게임에서 작동하며(게임 데이터가 필요 없음) 약간의 입력 지연이 추가됩니다. 새로 만들기 diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 1d723e8b3..173760192 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -1340,6 +1340,15 @@ Zainstalowana ścieżka: Ładowanie elementów Workshop Szukaj elementów Workshop Niepowodzenie + 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 21552c058..474df9524 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -1334,6 +1334,15 @@ Caminho instalado: Carregando itens do Workshop Buscar itens do Workshop Falhou + 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 b578bdaeb..05da9e3b2 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -1334,6 +1334,15 @@ Cale instalata: Se încarcă elementele Workshop Caută elemente Workshop Eșuat + 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 b586219bd..0873e0579 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -1240,6 +1240,15 @@ Загрузка элементов Workshop Поиск элементов Workshop Ошибка + Кадры + Множитель + Пресет качества + Производительность + Сбалансированный + Качество + Плавность + Нативная генерация кадров + Вставка интерполированных кадров в композиторе для плавности движения. Работает с любой игрой (данные игры не нужны) и немного увеличивает задержку ввода. Создать Переименовать diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index ba0f27476..5b74c2573 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -1340,6 +1340,15 @@ Завантаження елементів Workshop Пошук елементів Workshop Помилка + Кадри + Множник + Налаштування якості + Продуктивність + Збалансовано + Якість + Плавність + Нативна генерація кадрів + Вставляє інтерпольовані кадри в композитор для плавнішого руху. Працює з будь-якою грою (дані гри не потрібні) та трохи збільшує затримку вводу. Створити diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 57a39120e..bde1f29b3 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -1334,6 +1334,15 @@ 正在加载 Workshop 项目 搜索 Workshop 项目 失败 + 帧生成 + 倍率 + 质量预设 + 性能 + 均衡 + 质量 + 流畅度 + 原生帧生成 + 在合成器中插入插值帧以使画面运动更流畅。适用于任何游戏(无需游戏数据),并会增加少量输入延迟。 新建 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index dc318de81..2c40eed5f 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -1334,6 +1334,15 @@ 正在載入 Workshop 項目 搜尋 Workshop 項目 失敗 + 生成幀 + 倍率 + 品質預設 + 效能 + 平衡 + 品質 + 流暢度 + 原生畫格生成 + 在合成器中插入內插畫格以使動態更流暢。適用於任何遊戲(無需遊戲資料),並會略微增加輸入延遲。 新增 重新命名 匯出手勢設定檔 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 90fbbddb2..36b079edd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1411,6 +1411,18 @@ Installed path: Loading Workshop items Search Workshop items Failed + 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 d6e9ed01c..8d0ff56a5 100644 --- a/app/src/main/runtime/display/XServerDisplayActivity.java +++ b/app/src/main/runtime/display/XServerDisplayActivity.java @@ -271,6 +271,7 @@ public class XServerDisplayActivity extends FixedFontScaleAppCompatActivity { private boolean effectiveShowFPS = false; 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 Runnable editInputControlsCallback; @@ -372,6 +373,49 @@ public boolean isInputSuspended() { 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 boolean sgsrEnabled = false; private boolean sgsrRuntimeEnabled = false; private int sgsrUpscaleMode = 1; @@ -638,11 +682,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()) { @@ -652,6 +715,34 @@ private void applyPreferredRefreshRate() { } } + // Vote a frame rate on the surface so a VRR/ADFR panel holds the high refresh while FG is active. + 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) {} + } + + // Log the panel's actual physical refresh rate, de-duped so it only prints on change. + 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 the display's refresh rate / supported modes changing while a game * is running (e.g. the user toggles the system refresh rate, or an external @@ -677,6 +768,7 @@ public void onDisplayRemoved(int displayId) { @Override public void onDisplayChanged(int displayId) { + logCurrentRefreshRate("onDisplayChanged"); handleDisplayCapabilitiesChanged(); } }; @@ -3825,6 +3917,8 @@ private void handleNavigationBackPressed() { private void openDrawerMenu() { releasePointerCapture(); + if (xServerView != null && xServerView.getRenderer() != null) + xServerView.getRenderer().fgSetOverlayActive(true); renderDrawerMenu(); if (drawerStateHolder != null) { drawerStateHolder.openDrawer(); @@ -3838,9 +3932,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); @@ -3964,6 +4070,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, screenTouchMode, rtsGesturesEnabled, gestureProfileNames, @@ -4156,6 +4271,104 @@ 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) { + final int[] presetQuality = {0, 1, 1, 2, 1, 2}; + final int[] presetModel = {0, 0, 0, 0, 1, 1}; + final float[] presetFlowScale = {0.2f, 0.4f, 0.6f, 0.8f, 0.6f, 0.8f}; + int idx = Math.max(0, Math.min(preset, presetQuality.length - 1)); + frameGenerationPreset = idx; + frameGenerationQuality = presetQuality[idx]; + frameGenerationModel = presetModel[idx]; + frameGenerationExtrapolate = false; + frameGenerationDeepMode = (idx == 5); // Max engages the bidirectional (deep) flow + 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, presetFlowScale[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 onSGSREnabledChanged(boolean enabled) { boolean wasEnabled = sgsrEnabled; @@ -4640,6 +4853,12 @@ public void onLogsShare() { 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, @@ -5174,6 +5393,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); @@ -6437,11 +6660,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 + "'"); @@ -6450,6 +6674,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); + frameGenerationQuality = fgPrefInt("frame_generation_quality", 1); + frameGenerationSmoothing = fgPrefFloat("frame_generation_smoothing", 0.75f); + frameGenerationDeepMode = fgPrefBool("frame_generation_deep_mode", true); + frameGenerationAdvanced = fgPrefBool("frame_generation_advanced", false); + frameGenerationExtrapolate = fgPrefBool("frame_generation_extrapolate", false); + frameGenerationFramesInFlight = fgPrefInt("frame_generation_fif", 3); + frameGenerationPreset = fgPrefInt("frame_generation_preset", 2); + frameGenerationModel = (frameGenerationPreset == 4 || frameGenerationPreset == 5) ? 1 : 0; + frameGenerationDeepMode = (frameGenerationPreset == 5); // Max uses the bidirectional (deep) flow; others single-flow + final float[] startupPresetFlowScale = {0.2f, 0.4f, 0.6f, 0.8f, 0.6f, 0.8f}; + float startupFlowScale = startupPresetFlowScale[Math.max(0, Math.min(frameGenerationPreset, 5))]; + renderer.setFrameGenerationMultiplier(frameGenerationMultiplier); + renderer.setFrameGenerationPreset(frameGenerationQuality, frameGenerationModel, startupFlowScale); + 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); boolean swapRB = shortcut != null ? shortcut.getExtra("swapRB", "0").equals("1") : (container != null && container.getExtra("swapRB", "0").equals("1")); @@ -6500,6 +6746,10 @@ private void setupUI() { 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.VISIBLE); applyHUDSettings(); updateHUDRenderMode(); @@ -7083,6 +7333,10 @@ 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"; + } + switch (bcnEmulation) { case "auto" -> { if ("compute".equals(bcnEmulationType) && GPUInformation.getVendorID(null, null) != 20803) { diff --git a/app/src/main/runtime/display/XServerDrawerMenu.kt b/app/src/main/runtime/display/XServerDrawerMenu.kt index 1e1f8bb73..9cdd53c32 100644 --- a/app/src/main/runtime/display/XServerDrawerMenu.kt +++ b/app/src/main/runtime/display/XServerDrawerMenu.kt @@ -116,6 +116,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 @@ -162,6 +163,7 @@ import com.winlator.cmod.shared.theme.WinNativeTheme import com.winlator.cmod.shared.ui.dialog.WinNativeDialogButton import com.winlator.cmod.shared.ui.dialog.WinNativeDialogShell import com.winlator.cmod.shared.ui.outlinedSwitchColors +import kotlin.math.abs import kotlin.math.roundToInt // Drawer-local colors. @@ -329,6 +331,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, @@ -390,17 +401,24 @@ class XServerDrawerStateHolder( private var drawerOpen by mutableStateOf(false) internal var openPane by mutableStateOf(null) private var paneVisibilityListener: ((Boolean) -> Unit)? = null + private var drawerOpenListener: ((Boolean) -> Unit)? = null + + fun setDrawerOpenListener(listener: ((Boolean) -> Unit)?) { + drawerOpenListener = listener + } val isDrawerOpen: Boolean get() = drawerOpen fun openDrawer() { drawerOpen = true + drawerOpenListener?.invoke(true) } fun closeDrawer() { drawerOpen = false openPane = null + drawerOpenListener?.invoke(false) } fun isPaneOpen(): Boolean = openPane != null @@ -431,13 +449,6 @@ class XServerDrawerStateHolder( setOpenPaneAndNotify(DrawerPane.LOGS) } - /** - * Append a log line. Safe to call from any thread. When the logs pane is not - * visible, this only stores the line in an off-thread ring buffer — no - * recomposition or main-thread work is scheduled. The buffer is flushed into - * observable state when the pane becomes visible (and live while visible, - * coalesced through a single posted runnable). - */ fun appendLogLine(line: String) { if (logsPausedFlag) return synchronized(logsBuffer) { @@ -536,6 +547,24 @@ interface XServerDrawerActionListener { fun onScreenEffectsCardExpandedChanged(expanded: Boolean) + 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) fun onSGSRSharpnessChanged(sharpness: Int) @@ -697,6 +726,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, screenTouchMode: Int = 0, rtsGesturesEnabled: Boolean = false, gestureProfileNames: List = emptyList(), @@ -848,6 +886,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, @@ -927,11 +974,6 @@ internal fun XServerDrawerContent( onDismiss: () -> Unit, revealCards: Boolean = true, ) { - // The drawer content stays composed even while the sheet is closed (the host - // just translates it off-screen), so opening no longer pays a full - // first-composition cost. Drive the staggered card reveal from the sheet's - // engaged state so it still replays each time the drawer opens, and stays - // stable while switching between panes. val cardsRevealed = remember { mutableStateOf(false) } LaunchedEffect(revealCards) { cardsRevealed.value = revealCards } @@ -1069,6 +1111,7 @@ private fun TopRail( val activeSpecs = RAIL_PANES.filter { spec -> state.items.any { it.itemId == spec.itemId } } val tileBounds = remember { mutableStateMapOf() } + val railScroll = rememberScrollState() val selectedKey = when (openPane) { @@ -1118,10 +1161,12 @@ private fun TopRail( Box( modifier = Modifier - .offset( - x = indicatorX + underlineHorizontalInset, - y = indicatorTileHeight - underlineThickness, - ) + .offset { + IntOffset( + x = (indicatorX + underlineHorizontalInset).roundToPx() - railScroll.value, + y = (indicatorTileHeight - underlineThickness).roundToPx(), + ) + } .width((indicatorWidth - underlineHorizontalInset * 2).coerceAtLeast(0.dp)) .height(underlineThickness) .graphicsLayer { alpha = indicatorAlpha } @@ -1131,7 +1176,7 @@ private fun TopRail( } Row( - modifier = Modifier.horizontalScroll(rememberScrollState()), + modifier = Modifier.horizontalScroll(railScroll), horizontalArrangement = Arrangement.spacedBy(TopRailTileSpacing), verticalAlignment = Alignment.CenterVertically, ) { @@ -2165,11 +2210,6 @@ private fun InputControlsPaneContent( } } -/** - * Compact dropdown shared by the Style and Label Theme rows in the Controls pane. - * Mirrors the styling of [InputControlsProfileSelector] but omits the trailing edit-pencil button - * since these are built-in choices, not user-editable. - */ @Composable private fun InputControlsSimpleDropdown( options: List, @@ -2547,6 +2587,54 @@ private fun ScreenEffectsPaneContent( ) } } + + DrawerBooleanRow( + 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) }, + ) + } + } + } + } } ThinDivider() @@ -4721,10 +4809,6 @@ private fun FPSLimiterCard( val maxFps = maxRefreshRate.coerceAtLeast(FPS_LIMITER_MIN) val steps = (maxFps - FPS_LIMITER_MIN - 1).coerceAtLeast(0) - // Slider position is tracked locally so the readout follows the drag and the - // last value survives an off/on toggle; the limit/refresh-rate commit is - // deferred to release (onValueChangeFinished). Re-seeds when the panel's max - // changes — e.g. a mid-game refresh-rate change that clamps the limit. var sliderValue by remember(maxFps) { mutableStateOf( (if (currentLimit > 0) currentLimit else FPS_LIMITER_DEFAULT) diff --git a/app/src/main/runtime/display/renderer/VulkanRenderer.java b/app/src/main/runtime/display/renderer/VulkanRenderer.java index eb0008a7e..dc5a3a0fc 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; @@ -30,12 +33,7 @@ import java.util.ArrayList; import java.util.concurrent.atomic.AtomicBoolean; -/** - * Native Vulkan compositor. - * - *

Owns the C-side renderer handle and pushes a scene snapshot every frame. Replaces the - * previous GLES2 {@code GLRenderer}; preserves the same public API so callers do not change. - */ +/** Native Vulkan compositor. Owns the C-side renderer handle and pushes a scene snapshot every frame. */ public class VulkanRenderer implements RenderCallback, WindowManager.OnWindowModificationListener, @@ -55,9 +53,54 @@ 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 boolean fgPendingReal = false; + private int fgPendingInterps = 0; + private int fgInterpTotal = 0; + private int fgSlotIdx = 0; + private long fgEngineFrames = 0; + private volatile long fgDisplayPeriodNs = 0; + private volatile long fgGamePeriodNs = 0; + private volatile double fgLockedGameHz = 0.0; + private int fgGameDriftFrames = 0; + private long fgLastPumpNs = 0; + private volatile long fgLastGameNs = 0; + private volatile long fgPrevGameNs = 0; + private volatile long fgCurrentVsyncNs = 0; + 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.5f; // flow-field resolution scale [0.2,1.0] + 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(); @@ -120,11 +163,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 +184,7 @@ public void destroy() { // LEAK FIX: Unregister from the persistent XServer to prevent "zombie" listeners xServer.windowManager.removeOnWindowModificationListener(this); xServer.pointer.removeOnPointerMotionListener(this); + stopFgPumpThread(); if (nativeHandle != 0) { // If we are on the UI thread, nativeDestroy (which might block on vkDeviceWaitIdle) @@ -169,6 +213,11 @@ public void destroy() { } public void requestRenderCoalesced() { + if (frameGenEnabled) { + fgSceneDirty.set(true); + scheduleFgPump(); + return; + } if (renderRequested.compareAndSet(false, true)) { mainHandler.post(() -> Choreographer.getInstance().postFrameCallback(frameTimeNanos -> { @@ -178,6 +227,429 @@ 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); + } + fgPendingReal = false; + fgPendingInterps = 0; + fgInterpTotal = 0; + fgEngineFrames = 0; + fgCurrentVsyncNs = 0; + fgLastScanoutSrc = null; + fgFirstScanoutSrc = null; + fgMultiBuffer = false; + fgLastAcceptNs = 0L; + fgRenderPrioritySet = false; + fgLockedGameHz = 0.0; + fgGameDriftFrames = 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.2f ? 0.2f : (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 fgFillHolds = 1; // debug.winnative.fgfill: complete motion to curr on late holds (0=off) + private int fgFillCtr = 0; + private int fgPromoteSlotIdx = 0; // display ticks since the last promote + 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; + fgGamePeriodNs = 0L; + fgGameDriftFrames = 0; + fgPrevPromoteNs = 0L; + fgLastPromoteNs = 0L; + fgEngineFrames = 0; + fgPromoteSlotIdx = 0; + fgVblankSincePromote = 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(); } + if ((fgFillCtr++ & 63) == 0) fgFillHolds = nativeGetFillHolds(); + boolean newGame = fgNewScene.getAndSet(false); + boolean dirty = fgSceneDirty.getAndSet(false); + fgEmitWasHold = newGame || dirty; + boolean promoted = false; + if (newGame || dirty) { + buildAndSubmitFrame(); // HOLD: stage incoming; native promotes only distinct content + if (nativeHandle != 0) { + nativeFgPromoteInfo(nativeHandle, fgPromoteInfo); + if (fgPromoteInfo[0] != fgPromoteSeen) { + fgPromoteSeen = fgPromoteInfo[0]; + promoted = true; + long pNs = fgLastGameNs != 0L ? fgLastGameNs + : (fgPromoteInfo[1] != 0L ? fgPromoteInfo[1] : System.nanoTime()); + if (fgLastPromoteNs != 0L) { + long d = pNs - fgLastPromoteNs; // interval between distinct frames = content period + 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; + fgGameDriftFrames = 0; + fgGamePeriodNs = fgContentPeriodNs; + } + } + fgPrevPromoteNs = fgLastPromoteNs; + fgLastPromoteNs = pNs; + fgEngineFrames++; + fgPromoteSlotIdx = 0; + fgVblankSincePromote = 0; // new content interval — restart the output gate at the real frame + } + } + } + if (!promoted) fgPromoteSlotIdx++; + + long period = fgContentPeriodNs; + boolean canInterp = fgMultiplier > 1 && fgEngineFrames >= 2 && period > 0L + && fgLastPromoteNs != 0L && fgPrevPromoteNs != 0L; + if (!canInterp) { + if (newGame || dirty) { nativePresentLast(nativeHandle, 0f, fgPrevPromoteNs, fgLastPromoteNs); return 2; } + return 0; + } + + if (promoted) { + nativePresentLast(nativeHandle, 0f, fgPrevPromoteNs, fgLastPromoteNs); + return 2; + } + if (period <= 0L) return 0; + int eff = Math.max(2, fgEffectiveMultiplier); + long disp = fgDisplayPeriodNs; + int slots = eff; + if (disp > 0L) { + int s = (int) Math.round((double) period / (double) disp); + if (s >= 2) slots = s; + } + int emits = Math.min(eff, slots); // can't show more unique frames than panel refreshes per interval + fgCadenceM = emits; + fgVblankSincePromote++; + int vi = fgVblankSincePromote; // vblanks since the real frame (1..slots-1) + if (vi >= slots) { // interval fully spanned (content static) + // Now a UI-only recomposite (cursor) warrants a sharp redraw; otherwise hold. + if (dirty && !newGame) { nativePresentLast(nativeHandle, 0f, fgPrevPromoteNs, fgLastPromoteNs); return 2; } + if (fgFillHolds > 0 && vi < slots + fgFillHolds) { // next real frame late: carry the motion + double phase = (double) vi / (double) slots; // >=1.0 -> reach curr then extrapolate forward + nativeRenderInterp(nativeHandle, (float) phase, fgPrevPromoteNs, fgLastPromoteNs); + return 1; + } + return 0; // hold for the next promote + } + boolean emit = (int) ((long) vi * emits / slots) != (int) ((long) (vi - 1) * emits / slots); + if (!emit) return 0; // between gates — hold the current frame + double phase = (double) vi / (double) slots; // deterministic slot phase, jitter-free + nativeRenderInterp(nativeHandle, (float) phase, fgPrevPromoteNs, fgLastPromoteNs); + return 1; + } + + // 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 fgComputeInterps() { + int maxInterps = Math.max(1, fgEffectiveMultiplier) - 1; + long disp = fgDisplayPeriodNs, game = fgGamePeriodNs; + if (disp <= 0L || game <= 0L) return 0; + if (fgActivePresentMode == PRESENT_MODE_FIFO) { + int slots = (int) Math.floor((double) game / (double) disp + 1e-3); + return Math.max(0, Math.min(maxInterps, slots - 1)); + } + double gameHz = fgLockedGameHz > 0.0 ? fgLockedGameHz : 1.0e9 / (double) game; + int interps = (int) Math.round(fgTargetHz() / gameHz) - 1; + return Math.max(0, Math.min(maxInterps, interps)); + } + + 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(); @@ -193,6 +665,8 @@ public void setGraphicsDriver(String driverName) { } public void attachSurface(Surface surface) { + fgSurface = surface; + fgFrameRateHint = -1f; // fresh surface carries no frame-rate preference; re-apply if (nativeHandle == 0) { nativeHandle = nativeCreate(shouldEnableValidationLayers(), graphicsDriverName, xServerView.getContext().getApplicationContext()); @@ -202,10 +676,23 @@ public void attachSurface(Surface surface) { } Texture.setRendererHandle(nativeHandle); // Apply the cached present-mode request now that the native renderer exists. - // No-op if the requested mode equals the native default (FIFO). if (requestedPresentMode != PRESENT_MODE_FIFO) { nativeSetPresentMode(nativeHandle, requestedPresentMode); } + if (frameGenEnabled) { + nativeSetFrameGeneration(nativeHandle, true); + nativeSetPresentMode(nativeHandle, PRESENT_MODE_MAILBOX); + fgActivePresentMode = nativeGetActivePresentMode(nativeHandle); + pushFrameGenParams(); + nativeSetFrameGenDeepMode(nativeHandle, fgDeepMode); + fgPendingReal = false; + fgPendingInterps = 0; + fgInterpTotal = 0; + fgEngineFrames = 0; + fgNewScene.set(true); + startFgPumpThread(); + scheduleFgPump(); + } if (requestedScaleFilter != SCALE_FILTER_OFF) { nativeSetScaleFilter(nativeHandle, requestedScaleFilter); } @@ -217,10 +704,13 @@ public void attachSurface(Surface 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) { @@ -258,7 +748,11 @@ public void onSurfaceDestroyed() { @Override public void onDrawFrame() { if (nativeHandle == 0) return; - buildAndSubmitFrame(); + if (frameGenEnabled) { + fgDrawFrame(); + } else { + buildAndSubmitFrame(); + } } // ----- Scene assembly ---------------------------------------------------- @@ -496,8 +990,12 @@ 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); + } else { + nativeRenderFrame(nativeHandle); + } } // ----- WindowManager / Pointer listeners -------------------------------- @@ -543,6 +1041,7 @@ public void onUpdateWindowAttributes(Window window, Bitmask mask) { public void requestCursorRender() { cursorActiveUntilNs = System.nanoTime() + CURSOR_ACTIVE_NS; + if (frameGenEnabled) fgSceneDirty.set(true); xServerView.requestTransientRender(100); } @@ -557,8 +1056,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(); } @@ -767,9 +1286,6 @@ public void setFpsLimit(int fps) { public static final int PRESENT_MODE_MAILBOX = 1; public static final int PRESENT_MODE_IMMEDIATE = 2; - // Cached so callers can set a mode before the native renderer exists. Applied during - // attachSurface() right after nativeCreate. Updates after init forward straight to the - // native side and trigger a swapchain rebuild. private int requestedPresentMode = PRESENT_MODE_FIFO; public void setPresentMode(int mode) { @@ -807,8 +1323,6 @@ public void setUnviewableWMClasses(String... names) { } public void enforceFpsLimit() { - // FPS limiting is now performed in native (after queue submit/present), so this - // method is a no-op kept for source compatibility with any external callers. } // ---- JNI --------------------------------------------------------------- @@ -825,4 +1339,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); + private static native boolean nativeRenderInterp(long handle, float phase, long prevNs, long currNs); + private static native void nativeFgPromoteInfo(long handle, long[] out); + private static native boolean nativePresentLast(long handle, float phase, long prevNs, long currNs); + 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 int nativeGetFillHolds(); + 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 58471d5e6..f66bc7e9d 100644 --- a/app/src/main/runtime/display/ui/FrameRating.java +++ b/app/src/main/runtime/display/ui/FrameRating.java @@ -132,6 +132,12 @@ public void setFrameObserver(FrameObserver observer) { private boolean isStatsRunning; private volatile boolean isCharging; 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; @@ -876,6 +882,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; @@ -1487,8 +1499,26 @@ public void run() { 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 4d9f8878f..a2e0f9bce 100644 --- a/app/src/main/shared/android/RefreshRateUtils.java +++ b/app/src/main/shared/android/RefreshRateUtils.java @@ -134,50 +134,35 @@ 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; - float closestDelta = Float.MAX_VALUE; + // Two independent passes (order-independent): an exact round-Hz match always wins over a + // closest match. The single-pass version mis-selected when a higher-rate mode preceded the + // exact match in enumeration order (e.g. requestedHz=60 picked the 90Hz mode). + 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) { - if (bestMode == null || refreshRate > bestModeRate) { - bestMode = mode; - bestModeRate = refreshRate; - closestDelta = 0f; - } + if (exact == null || refreshRate > exactRate) { exact = mode; exactRate = refreshRate; } continue; } - - if (bestMode != null && closestDelta == 0f) 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; } @@ -300,6 +285,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; params.preferredRefreshRate = refreshRate; activity.getWindow().setAttributes(params);