debug_fix_screen_change #2

Merged
xsl merged 35 commits from debug_fix_screen_change into main 2026-04-26 10:58:01 +08:00
8 changed files with 311 additions and 76 deletions
Showing only changes of commit 835f768a4a - Show all commits
+95
View File
@@ -15,6 +15,8 @@ android_app* g_android_app = nullptr;
FaceApp* g_Application = nullptr;
AAssetManager* g_assetManager = nullptr;
jobject g_callback = nullptr;
void handle_cmd(android_app *pApp, int32_t cmd) {
switch (cmd) {
case APP_CMD_INIT_WINDOW:
@@ -168,3 +170,96 @@ JNIEXPORT void JNICALL
Java_com_hmwl_face_1sdk_FaceActivity_StopRunning(JNIEnv *env, jobject thiz) {
g_Application->_running = false;
}
JavaVM* g_jvm = nullptr;
// 添加 JNI_OnLoad 函数
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
g_jvm = vm; // 保存 JavaVM 指针,供其他线程使用
return JNI_VERSION_1_6;
}
void CppCallback(const string& motion_type)
{
JNIEnv* env = nullptr;
bool needDetach = false;
// 获取当前线程的 JNIEnv
JavaVM* vm = g_jvm; // 你需要提前保存 JavaVM* 到全局变量 g_jvm
int status = vm->GetEnv((void**)&env, JNI_VERSION_1_6);
if (status == JNI_EDETACHED) {
// 当前线程未 attach,需 attach
if (vm->AttachCurrentThread(&env, nullptr) != 0) {
return;
}
needDetach = true;
} else if (status != JNI_OK) {
return;
}
if (g_callback == nullptr) {
if (needDetach) vm->DetachCurrentThread();
return;
}
// 1. 获取 CallbackInterface 的 class
jclass callbackClass = env->GetObjectClass(g_callback);
if (callbackClass == nullptr) {
if (needDetach) vm->DetachCurrentThread();
return;
}
// 2. 获取 OnLoadActionFinished 方法 ID(注意方法名大小写必须一致!)
jmethodID methodId = env->GetMethodID(callbackClass, "OnLoadActionFinished", "(Ljava/lang/String;)V");
if (methodId == nullptr) {
env->ExceptionDescribe(); // 打印异常
env->ExceptionClear();
if (needDetach) vm->DetachCurrentThread();
return;
}
// 3. 构造 jstring 参数
jstring jResult = env->NewStringUTF(motion_type.c_str());
// 4. 调用 Java 回调
env->CallVoidMethod(g_callback, methodId, jResult);
// 5. 检查是否抛出异常
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
// 6. 释放局部引用(可选,但推荐)
env->DeleteLocalRef(jResult);
env->DeleteLocalRef(callbackClass);
// 7. 如果是临时 attach 的线程,要 detach
if (needDetach) {
vm->DetachCurrentThread();
}
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_hmwl_face_1sdk_FaceActivity_PreReadAction(JNIEnv *env, jobject thiz, jstring motion,
jobject callback) {
g_callback = env->NewGlobalRef(callback);
const char *nativeString = env->GetStringUTFChars(motion, nullptr);
jsize len = env->GetStringUTFLength(motion);
if(len > ArgLen)
{
aout << "ArgLen to long:" << len << std::endl;
}
if(g_Application->isInited())
{
g_Application->changeMotion(nativeString);
}
// TODO: implement PreReadAction()
std::string ret = g_Application->preReadyMotion(nativeString, CppCallback);
return env->NewStringUTF(ret.c_str());
}
@@ -272,6 +272,15 @@ public class FaceActivity extends GameActivity implements FaceLandmarkerHelper.L
SetCppInitArg(json);
}
public interface CallbackInterface {
void OnLoadActionFinished(String result);
}
protected native String PreReadAction(String motion, CallbackInterface callback);
protected String PreLoadAction(String json, CallbackInterface callback){
return PreReadAction(json, callback);
}
protected native void ChangeStateCpp(String json);
protected void ChangeState(String json){
Log.i("FaceActivity", "ChangeState:" + json);
@@ -4,13 +4,12 @@ import org.json.JSONObject;
public class InitArg {
public int action_fps;
public float zoom;
public Motion motion;
public String toJson() {
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("action_fps", action_fps);
jsonObject.put("zoom", zoom);
jsonObject.put("motion", motion.toJsonObject());
return jsonObject.toString();
} catch (Exception e) {
e.printStackTrace();
@@ -15,28 +15,43 @@ import java.io.BufferedReader
import java.io.InputStreamReader
class MakeupActivity : FaceActivity() {
class MakeupActivity : FaceActivity()
{
private var curIndex = 0
private var pngFilesByFolder: List<FolderInfo>? = null
override fun onCreate(savedInstanceState: Bundle?) {
val motion = Motion().apply {
type = "4"
png_names.add("4.png")
}
FaceInit(this)
val initArg = InitArg().apply {
action_fps = 10
zoom = 1.5f
this.motion = motion
}
SetInitArg(initArg.toJson())
super.onCreate(savedInstanceState)
FaceInit(this)
Toast.makeText(this, "4.png", Toast.LENGTH_LONG).show()
var motion = getMotionByIndex(0);
var jsonString = motion.toJson()
val result = PreLoadAction(jsonString) { motion_type ->
// 在这里处理回调结果
println("OnLoadActionFinished: $motion_type")
ChangeState(motion_type);
}
//Toast.makeText(this, "4.png", Toast.LENGTH_LONG).show()
}
private fun getMotionByIndex(index: Int): Motion {
pngFilesByFolder?.let { folders ->
val motion = Motion().apply {
type = folders[index].folderName
png_names = folders[index].fileList
}
return motion
}
return Motion()
}
private fun getCurMotionState(index: Int): String {
+8 -1
View File
@@ -8,7 +8,6 @@
struct Texture
{
std::string name;
VkSampler sampler;
VkImage image;
VkImageLayout image_layout;
@@ -19,6 +18,14 @@ struct Texture
VkBuffer stagingBuffer = VK_NULL_HANDLE;
VkDeviceMemory stagingBufferMemory = VK_NULL_HANDLE;
VkDevice device;
void reset() {
sampler = VK_NULL_HANDLE;
image = VK_NULL_HANDLE;
device_memory = VK_NULL_HANDLE;
view = VK_NULL_HANDLE;
stagingBuffer = VK_NULL_HANDLE;
stagingBufferMemory = VK_NULL_HANDLE;
}
};
class Application : public AppBase
+119 -46
View File
@@ -567,7 +567,11 @@ void FaceApp::setup_descriptor_set()
alloc_info.pSetLayouts = layouts.data();
alloc_info.descriptorSetCount = m_descriptor_sets.size();
VK_CHECK(vkAllocateDescriptorSets(device, &alloc_info, m_descriptor_sets.data()));
update_descriptor_set(m_texs);
}
void FaceApp::update_descriptor_set(vector<Texture>& texs)
{
for (int i = 0; i < kMaxTexture; ++i)
{
VkDescriptorBufferInfo buffer_descriptor{};
@@ -577,9 +581,9 @@ void FaceApp::setup_descriptor_set()
VkDescriptorImageInfo image_descriptor;
image_descriptor.imageView = m_texs[i].view;
image_descriptor.sampler = m_texs[i].sampler;
image_descriptor.imageLayout = m_texs[i].image_layout;
image_descriptor.imageView = texs[i].view;
image_descriptor.sampler = texs[i].sampler;
image_descriptor.imageLayout = texs[i].image_layout;
VkWriteDescriptorSet write_descriptor_set_uniform{};
write_descriptor_set_uniform.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
@@ -635,17 +639,7 @@ void FaceApp::setup_descriptor_set()
vkUpdateDescriptorSets(device, static_cast<uint32_t>(write_descriptor_sets.size()), write_descriptor_sets.data(), 0, NULL);
}
}
}
void FaceApp::render(VkCommandBuffer commandBuffer, long long frameTime)
@@ -718,6 +712,7 @@ void FaceApp::initVulkan()
createVmaAllocator();
LoadOBJ("face_picture_3dmax.obj", obj_vertices, obj_indices);
m_texs.resize(kMaxTexture);
m_texs_next.resize(kMaxTexture);
if (kThick)
{
m_texs_ex.resize(kMaxTexture);
@@ -731,6 +726,7 @@ void FaceApp::initVulkan()
for (int i = 0; i < kMaxTexture; ++i)
{
loadTexture(image, image.size(), w, h, m_texs[i], true);
loadTexture(image, image.size(), w, h, m_texs_next[i], true);
if (kThick)
{
loadTexture(image, image.size(), w, h, m_texs_ex[i], true);
@@ -753,7 +749,7 @@ void FaceApp::initVulkan()
uploadVertexData();
last_update_time = getCurrentTimeMillis();
changeMotion(_initArg.motion);
//changeMotion(_initArg.motion);
_running = true;
faceAppInited = true;
#if _WIN32
@@ -1153,11 +1149,13 @@ void FaceApp::destroyTexture(VkDevice device, Texture& texture) {
if (texture.stagingBuffer != VK_NULL_HANDLE)
{
vkDestroyBuffer(device, texture.stagingBuffer, nullptr);
texture.stagingBuffer = VK_NULL_HANDLE;
}
if (texture.stagingBufferMemory != VK_NULL_HANDLE)
{
vkFreeMemory(device, texture.stagingBufferMemory, nullptr);
texture.stagingBufferMemory = VK_NULL_HANDLE;
}
}
@@ -1261,6 +1259,11 @@ void FaceApp::cleanup()
destroyTexture(device, m_texs[i]);
}
for (int i = 0; i < this->m_texs_next.size(); ++i)
{
destroyTexture(device, m_texs_next[i]);
}
destroyTexture(device, tex_bg);
vkDestroyCommandPool(device, commandPool, nullptr);
Application::cleanup();
@@ -1284,6 +1287,32 @@ void FaceApp::drawFrame(long long frameTime)
return;
}
if (_motionState == loading_next_motion)
{
int i = _nextMotionIndex;
//for (int i = 0; i < _curMotion.png_names.size(); ++i)
{
#ifdef _WIN32
string path = "pic";
string path_name = path + "/" + _nextMotion.type + "/" + _nextMotion.png_names[i];// +std::to_string(i) + ".png";
loadTextureExample(UTF8ToWideString(path_name), m_texs_next[i], true);
#else
//string path = _curMotion.type + "/" + _curMotion.technique + "/" + _curMotion.step + "/" + _curMotion.show_type;
string path = "pic";
string path_name = path + "/" + _nextMotion.type + "/" + _nextMotion.png_names[i];// +std::to_string(i) + ".png";
loadTexture(path_name, m_texs_next[i], true);
#endif // _WIN32
_nextMotionIndex++;
if (_nextMotionIndex >= _nextMotion.png_names.size())
{
_motionState = load_next_motion_finished;
_callback(_nextMotion.type);
}
}
}
std::unique_lock lock(changeMotionMtx);
static long long game_time = 0;
game_time += frameTime;
@@ -1291,7 +1320,7 @@ void FaceApp::drawFrame(long long frameTime)
if (game_time > actionTime)
{
_curTexIndex++;
if (_curTexIndex >= _curMotion.png_names.size())
if (_curTexIndex >= _curMotion_png_size)
{
_curTexIndex = 0;
}
@@ -1300,44 +1329,88 @@ void FaceApp::drawFrame(long long frameTime)
Application::drawFrame(frameTime);
}
void FaceApp::changeMotion(const char* json)
//void FaceApp::changeMotion(const char* motion_type)
//{
// //Motion motion = json::parse(json);
// changeMotion(motion);
//}
string FaceApp::preReadyMotion(const std::string& json, Callback callback)
{
Motion motion = json::parse(json);
changeMotion(motion);
if (_motionState == loading_next_motion)
{
return "busy on loading:" + _nextMotion.type;
}
else if (_motionState == load_next_motion_finished)
{
return "waitting change next action:" + _nextMotion.type;
}
else if (_motionState == ready)
{
Motion motion = json::parse(json);
_nextMotion = motion;
_motionState = loading_next_motion;
_nextMotionIndex = 0;
_callback = callback;
return "success";
}
return "failure";
}
void FaceApp::changeMotion(Motion& motion)
void FaceApp::changeMotion(const string motion_type)
{
if (_curMotion.getMotionId() == motion.getMotionId())
if (_curMotion_type == motion_type)
{
return;
}
std::unique_lock<std::mutex> lock_changeMotion(changeMotionMtx);
_curMotion = motion;
for (int i = 0; i < _curMotion.png_names.size(); ++i)
if (_motionState != load_next_motion_finished)
{
#ifdef _WIN32
//string path = _curMotion.type + "/" + _curMotion.technique + "/" + _curMotion.step + "/" + _curMotion.show_type;
string path = "pic";
string path_name = path + "/" + _curMotion.type + "/" + _curMotion.png_names[i];// +std::to_string(i) + ".png";
loadTextureExample(UTF8ToWideString(path_name), m_texs[i], true);
if (kThick)
{
string path_name_ex = path + "/" + _curMotion.type + "/" + _curMotion.png_names[i] + std::to_string(i) + "_thick.png";
loadTextureExample(UTF8ToWideString(path_name_ex), m_texs_ex[i], true);
}
#else
//string path = _curMotion.type + "/" + _curMotion.technique + "/" + _curMotion.step + "/" + _curMotion.show_type;
string path = "pic";
string path_name = path + "/" + _curMotion.type + "/" + _curMotion.png_names[i];// +std::to_string(i) + ".png";
loadTexture(path_name, m_texs[i], true);
if (kThick)
{
loadTexture(path_name, m_texs_ex[i], true);
}
#endif // _WIN32
return;
}
std::unique_lock<std::mutex> lock_changeMotion(changeMotionMtx);
for (int i = 0; i < this->m_texs.size(); ++i)
{
destroyTexture(device, m_texs[i]);
}
for (int i = 0; i < m_texs_next.size(); ++i)
{
m_texs[i] = m_texs_next[i];
m_texs_next[i].reset();
}
update_descriptor_set(m_texs);
_curMotion_type = motion_type;
_curMotion_png_size = _nextMotion.png_names.size();
// for (int i = 0; i < _curMotion.png_names.size(); ++i)
// {
//
//#ifdef _WIN32
// //string path = _curMotion.type + "/" + _curMotion.technique + "/" + _curMotion.step + "/" + _curMotion.show_type;
// string path = "pic";
// string path_name = path + "/" + _curMotion.type + "/" + _curMotion.png_names[i];// +std::to_string(i) + ".png";
// loadTextureExample(UTF8ToWideString(path_name), m_texs[i], true);
// if (kThick)
// {
// string path_name_ex = path + "/" + _curMotion.type + "/" + _curMotion.png_names[i] + std::to_string(i) + "_thick.png";
// loadTextureExample(UTF8ToWideString(path_name_ex), m_texs_ex[i], true);
// }
//#else
// //string path = _curMotion.type + "/" + _curMotion.technique + "/" + _curMotion.step + "/" + _curMotion.show_type;
// string path = "pic";
// string path_name = path + "/" + _curMotion.type + "/" + _curMotion.png_names[i];// +std::to_string(i) + ".png";
// loadTexture(path_name, m_texs[i], true);
// if (kThick)
// {
// loadTexture(path_name, m_texs_ex[i], true);
// }
//#endif // _WIN32
//
//
// }
}
+24 -6
View File
@@ -2,6 +2,7 @@
#define __FaceApp_H__
#include "Application.h"
#include <functional>
#include "../third_party/vma/include/vk_mem_alloc.h"
#include <map>
#include <glm/glm.hpp>
@@ -24,8 +25,8 @@ struct InitArg
{
int action_fps;
float zoom;
Motion motion;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(InitArg, action_fps, zoom, motion);
//Motion motion;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(InitArg, action_fps, zoom);
};
@@ -33,7 +34,7 @@ struct PushConstants {
float myValue;
};
using Callback = std::function<void(const std::string&)>;
class FaceApp :public Application
{
@@ -79,6 +80,7 @@ private:
void setup_descriptor_pool();
void setup_descriptor_set_layout();
void setup_descriptor_set();
void update_descriptor_set(vector<Texture>& texs);
const bool kThick = false;
void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size);
@@ -102,6 +104,7 @@ private:
vector<VkDescriptorSet> m_descriptor_sets;
const uint32_t kMaxTexture = 30;
vector<Texture> m_texs;
vector<Texture> m_texs_next;
vector<Texture> m_texs_ex;
@@ -135,10 +138,25 @@ private:
public:
void changeMotion(const char* json);
void changeMotion(Motion& motion);
Callback _callback;
string preReadyMotion(const std::string& json, Callback callback);
void changeMotion(const string motion_type);
//void changeMotion(Motion& motion);
InitArg _initArg;
Motion _curMotion;
//Motion _curMotion;
string _curMotion_type;
int _curMotion_png_size;
Motion _nextMotion;
int _nextMotionIndex;
enum MotionState {
ready,
loading_next_motion,
load_next_motion_finished,
};
MotionState _motionState = ready;
int _curTexIndex = 0;
void SetInitArg(const char* arg);
+32 -13
View File
@@ -39,6 +39,12 @@ std::wstring ReadFileWithChinesePath(const std::wstring& filePath) {
return AppBase::UTF8ToWideString(context);
}
FaceApp* g_app;
void CppCallback(const string& motion_type)
{
g_app->changeMotion(motion_type.c_str());
}
int main() {
@@ -51,23 +57,23 @@ int main() {
Motion motion;
motion.type = "4";
motion.png_names.push_back("4.png");
//for (int i = 0; i < 25; ++i)
//{
// if (i < 10)
// {
// motion.png_names.push_back("00000" + std::to_string(i) + ".png");
// }
// else
// {
// motion.png_names.push_back("0000" + std::to_string(i) + ".png");
for (int i = 0; i < 25; ++i)
{
if (i < 10)
{
motion.png_names.push_back("00000" + std::to_string(i) + ".png");
}
else
{
motion.png_names.push_back("0000" + std::to_string(i) + ".png");
// }
//
//}
}
}
#
init_arg.motion = motion;
//init_arg.motion = motion;
init_arg.action_fps = 10;
@@ -76,9 +82,22 @@ int main() {
string json_str = json(init_arg).dump();
FaceApp app;
g_app = &app;
app.SetInitArg(json_str.c_str());
app.initVulkan();
app._running = true;
auto motion_json = json(motion);
if (!motion_json.is_object()) {
std::cout << "Invalid JSON structure" << std::endl;
}
std::string motion_str = motion_json.dump();
// 添加完整性检查
if (motion_str.empty()) {
std::cout << "Warning: Empty motion string" << std::endl;
}
app.preReadyMotion(motion_str, CppCallback);
app.mainLoop();
//try {
// app.mainLoop();