我在Linux上运行的Unity3D应用程序中遇到了一些烦人的崩溃,我正在使用一个本机插件来渲染2D纹理,而问题很可能与此有关。
我试图禁止使用此类插件,但没有发生崩溃。
#include <stdio.h>
#include "PlatformBase.h"
#include "RenderAPI.h"
#include <cstring>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include "GLEW/glew.h"
#include <ctime>
#include <vector>
#include "CallbackManager.h"
#include <iostream>
#include <mutex>
// #include "GLError.h"
#include <sstream>
#include <string>
struct TextureData
{
void* g_TextureHandle = NULL;
void* g_Buffer = NULL;
int g_TextureWidth = 0;
int g_TextureHeight = 0;
int g_BufferLength = 0;
void* g_RgbaBuff = NULL;
FuncCallBack g_Callback = 0;
};
static std::vector<TextureData*> dataList;
static std::mutex dataMutex;
static bool newMode = true;
static int currentIndex = 0;
static FuncPtr log_Callback;
static void LogOut(const char * message)
{
if(log_Callback)
{
std::cout << "Logging to C# " << message << '\n';
log_Callback(message);
}
}
extern "C" int UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API CreateTextureData(void* textureHandle, int w, int h, void* rgbaBuffer)
{
int result = 0;
if(currentIndex > 50)
{
currentIndex = 0;
newMode = false;
}
if (!newMode)
{
try
{
std::lock_guard<std::mutex> lk(dataMutex);
dataList[currentIndex]->g_TextureHandle = textureHandle;
dataList[currentIndex]->g_TextureWidth = w;
dataList[currentIndex]->g_TextureHeight = h;
dataList[currentIndex]->g_RgbaBuff = rgbaBuffer;
result = currentIndex;
currentIndex = currentIndex +1;
}
catch(const std::exception& e)
{
std::cerr << e.what() << "[NativePluginException]\n";
std::stringstream ss;
ss << e.what() << "[NativePluginException]\n";
std::string s = ss.str();
LogOut(s.c_str());
}
}
else
{
TextureData* tData = new TextureData();
tData->g_TextureHandle = textureHandle;
tData->g_TextureWidth = w;
tData->g_TextureHeight = h;
tData->g_RgbaBuff = rgbaBuffer;
std::lock_guard<std::mutex> lk(dataMutex);
dataList.push_back(tData);
currentIndex = currentIndex + 1;
result = dataList.size() - 1;
}
return result;
}
extern "C" int UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UpdateTextureData(int dataId, void* buffer, int bufferLength)
{
try
{
if (dataList.size() > dataId)
{
std::lock_guard<std::mutex> lk(dataMutex);
TextureData *tData = dataList.at(dataId);
tData->g_Buffer = buffer;
tData->g_BufferLength = bufferLength;
return 14;
}
}
catch(const std::exception& e)
{
std::cerr << e.what() << "[NativePluginException]\n";
std::stringstream ss;
ss << e.what() << "[NativePluginException]\n";
std::string s = ss.str();
LogOut(s.c_str());
}
return 15;
}
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API RemoveTextureData(int dataId)
{
}
static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType);
static IUnityInterfaces* s_UnityInterfaces = NULL;
static IUnityGraphics* s_Graphics = NULL;
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces)
{
s_UnityInterfaces = unityInterfaces;
s_Graphics = s_UnityInterfaces->Get<IUnityGraphics>();
s_Graphics->RegisterDeviceEventCallback(OnGraphicsDeviceEvent);
// Run OnGraphicsDeviceEvent(initialize) manually on plugin load
OnGraphicsDeviceEvent(kUnityGfxDeviceEventInitialize);
}
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload()
{
s_Graphics->UnregisterDeviceEventCallback(OnGraphicsDeviceEvent);
}
static RenderAPI* s_CurrentAPI = NULL;
static UnityGfxRenderer s_DeviceType = kUnityGfxRendererNull;
static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType)
{
// Create graphics API implementation upon initialization
if (eventType == kUnityGfxDeviceEventInitialize)
{
assert(s_CurrentAPI == NULL);
s_DeviceType = s_Graphics->GetRenderer();
s_CurrentAPI = CreateRenderAPI(s_DeviceType);
}
// Let the implementation process the device related events
if (s_CurrentAPI)
{
s_CurrentAPI->ProcessDeviceEvent(eventType, s_UnityInterfaces);
}
// Cleanup graphics API implementation upon shutdown
if (eventType == kUnityGfxDeviceEventShutdown)
{
delete s_CurrentAPI;
s_CurrentAPI = NULL;
s_DeviceType = kUnityGfxRendererNull;
}
}
static void ModifyTexturePixelsWithParams(void* textureHandle, int w, int h, void* buffer, int bufferLength, void* rgbaBuffer)
{
int textureRowPitch;
unsigned char * rgba = (unsigned char*)rgbaBuffer;
unsigned char * buf = (unsigned char*)buffer;
if (!buf)
return;
int i = 0;
printf("bufferLength %i width %i height %i \n", bufferLength, w, h);
if (!textureHandle)
{
printf("[NATIVEEXCEPTION]Texture handle was null\n");
std::stringstream ss;
ss << "[NATIVEEXCEPTION]Texture handle was null\n";
std::string s = ss.str();
LogOut(s.c_str());
return;
}
glBindTexture(GL_TEXTURE_2D, (GLuint)(size_t)textureHandle);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buf);
}
static void UNITY_INTERFACE_API OnRenderEventThreadSafe(int eventID)
{
try
{
if(eventID >= dataList.size())
{
printf("EventID bigger than the size of the list %i \n", eventID);
return;
}
std::lock_guard<std::mutex> lk(dataMutex);
TextureData *obj = dataList.at(eventID);
if(obj)
{
if(obj->g_TextureHandle && obj->g_Buffer && obj->g_TextureWidth != 0 && obj->g_TextureWidth != 0 && obj->g_BufferLength != 0 && obj->g_RgbaBuff)
{
ModifyTexturePixelsWithParams(obj->g_TextureHandle, obj->g_TextureWidth, obj->g_TextureHeight, obj->g_Buffer, obj->g_BufferLength, obj->g_RgbaBuff);
}
else
{
printf("Can't modify the texture, null element \n");
std::stringstream ss;
ss << "[NativePluginException] Can't modify the texture, null element\n";
std::string s = ss.str();
LogOut(s.c_str());
}
if (obj->g_Callback != 0 && obj->g_Callback)
{
obj->g_Callback(eventID);
}
else
{
printf("Callback to C# was null for id %i \n", eventID);
}
}
else
{
printf("Received a null pointer, avoiding the call for eventId %i \n", eventID);
}
}
catch(const std::exception& e)
{
std::cerr << e.what() << "[NativePluginException]\n";
std::stringstream ss;
ss << e.what() << "[NativePluginException]\n";
std::string s = ss.str();
LogOut(s.c_str());
}
}
extern "C" UnityRenderingEvent UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API GetRenderEventFuncThreadSafe()
{
return OnRenderEventThreadSafe;
}
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API SetCallback(int dataId, FuncCallBack callback)
{
try
{
if (dataList.size() > dataId)
{
std::lock_guard<std::mutex> lk(dataMutex);
TextureData *tData = dataList.at(dataId);
tData->g_Callback = callback;
}
}
catch(const std::exception& e)
{
std::cerr << e.what() << "[NativePluginException]\n";
std::stringstream ss;
ss << e.what() << "[NativePluginException]\n";
std::string s = ss.str();
LogOut(s.c_str());
}
}
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API SetLogCallback(FuncPtr callback)
{
try
{
log_Callback = callback;
}
catch(const std::exception& e)
{
std::cerr << e.what() << "[NativePluginException]SetLogCallback\n";
std::stringstream ss;
ss << e.what() << "[NativePluginException]\n";
std::string s = ss.str();
LogOut(s.c_str());
}
}
要调用本机插件,我正在在Unity内的纹理GameObject上运行的协程中使用以下代码
while (!exitWhile)
{
yield return new WaitForEndOfFrame;
if (shouldRender && !_fakeTexture)
{
GL.IssuePluginEvent(GetRenderEventFuncThreadSafe(), textureIndex);
bufferPointer = IntPtr.Zero;
if (_doAlphaFading)
DoAlphaFadeIn();
else
color = Color.white;
shouldRender = false;
if (!cycleMode) exitWhile = true;
}
}
纹理创建和更新是在AsyncThread中完成的
textureIndex = CreateTextureData(texturePointer, (int) size.x, (int) size.y, bufferPtr);
[...]
var resp = UpdateTextureData(textureIndex, bufferPtr, buffer.Length);
该插件实际上正在工作,但有时我收到的SIGABRT会使我的应用程序崩溃。 Player.log记录了这样的异常
Receiving unhandled NULL exception
Receiving unhandled NULL exception
#0 0x007f26f55c79c0 in _L_unlock_13
#0 0x007f26e03b59c0 in _L_unlock_13
#1 0x007fff4b896590 in GC_malloc_atomic
#1 0x007f269e00dab0 in mono_threads_detach_coop
#2 0x007f269e00dae0 in mono_threads_detach_coop
#3 0x007f269e00dc30 in mono_threads_detach_coop
#4 0x007f269e00dc90 in mono_threads_detach_coop
#5 0x007f269e00dd90 in mono_threads_set_shutting_down
#6 0x007f269e00de60 in GC_inner_start_routine
#7 0x007f269e00deb0 in GC_call_with_stack_base
#8 0x007f269e00dee0 in start_thread
#2 0x007fff4b8965c0 in mono_gc_register_root
#9 0x007f269e00df80 in clone
#3 0x007fff4b8965e0 in mono_class_vtable
#4 0x007fff4b896600 in mono_string_chars
#5 0x007fff4b896620 in mono_string_new_utf16
#6 0x007fff4b896660 in mono_string_new_len
#7 0x007fff4b8966f0 in operator delete(void*)
#8 0x007fff4b896710 in operator delete(void*)
#9 0x007fff4b896720 in std::vector<std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > >, std::allocator<std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > > >::~vector()
我也设法获得了strace日志,该日志非常大,因此我将其上传到了保管箱文件:https://www.dropbox.com/s/gwfo7alpbkp5c13/strace.log?dl=0
我不是c ++专家,所以我不知道我的本机插件中的某些内容是否会导致类似这种情况。
在此先感谢任何会回答的人!