270 lines
7.0 KiB
C++
270 lines
7.0 KiB
C++
#include <jni.h>
|
|
#include <aidl/com/omixlab/mosis/IMosisListener.h>
|
|
#include <aidl/com/omixlab/mosis/BnMosisListener.h>
|
|
#include <logger.h>
|
|
#include <aidl/com/omixlab/mosis/IMosisService.h>
|
|
#include <android/binder_ibinder_jni.h>
|
|
#include <format>
|
|
#include <IUnityGraphics.h>
|
|
|
|
#include "texture_backend.h"
|
|
#include "opengl_backend.h"
|
|
#include "vulkan_backend.h"
|
|
|
|
using namespace aidl::com::omixlab::mosis;
|
|
using namespace aidl::android::hardware;
|
|
|
|
// Global state
|
|
std::shared_ptr<IMosisService> g_service;
|
|
std::shared_ptr<class ServiceContext> g_context;
|
|
std::unique_ptr<ITextureBackend> g_backend;
|
|
IUnityInterfaces* g_unityInterfaces = nullptr;
|
|
UnityGfxRenderer g_rendererType = kUnityGfxRendererNull;
|
|
|
|
// Callback function pointers
|
|
typedef void (*OnMessageCallback)(const char*);
|
|
typedef void (*OnServiceInitializedCallback)(bool success);
|
|
typedef void (*OnFrameAvailableCallback)();
|
|
typedef void (*OnBufferReadyCallback)();
|
|
typedef void (*OnTextureReadyCallback)(void* nativeTexturePtr, int width, int height, bool isVulkan);
|
|
|
|
struct NativeCallbacks
|
|
{
|
|
OnMessageCallback OnMessage;
|
|
OnServiceInitializedCallback OnServiceInitialized;
|
|
OnFrameAvailableCallback OnFrameAvailable;
|
|
OnBufferReadyCallback OnBufferReady;
|
|
OnTextureReadyCallback OnTextureReady;
|
|
};
|
|
NativeCallbacks g_callbacks{};
|
|
|
|
class ServiceContext : public BnMosisListener
|
|
{
|
|
AHardwareBuffer* m_hwbuffer = nullptr;
|
|
|
|
public:
|
|
ndk::ScopedAStatus onServiceInitialized(bool in_success) override
|
|
{
|
|
Logger::Log("onServiceInitialized");
|
|
if (g_callbacks.OnMessage)
|
|
g_callbacks.OnMessage("onServiceInitialized");
|
|
if (g_callbacks.OnServiceInitialized)
|
|
g_callbacks.OnServiceInitialized(in_success);
|
|
return ndk::ScopedAStatus::ok();
|
|
}
|
|
|
|
ndk::ScopedAStatus onFrameAvailable() override
|
|
{
|
|
Logger::Log("onFrameAvailable");
|
|
if (g_callbacks.OnMessage)
|
|
g_callbacks.OnMessage("onFrameAvailable");
|
|
if (g_callbacks.OnFrameAvailable)
|
|
g_callbacks.OnFrameAvailable();
|
|
return ndk::ScopedAStatus::ok();
|
|
}
|
|
|
|
ndk::ScopedAStatus onBufferAvailable(const HardwareBuffer &in_buffer) override
|
|
{
|
|
Logger::Log("onBufferAvailable");
|
|
if (g_callbacks.OnMessage)
|
|
g_callbacks.OnMessage("onBufferAvailable");
|
|
m_hwbuffer = in_buffer.get();
|
|
AHardwareBuffer_acquire(m_hwbuffer);
|
|
if (g_callbacks.OnBufferReady)
|
|
g_callbacks.OnBufferReady();
|
|
return ndk::ScopedAStatus::ok();
|
|
}
|
|
|
|
bool CreateTexture()
|
|
{
|
|
if (!m_hwbuffer)
|
|
{
|
|
Logger::Log("CreateTexture: No hardware buffer available");
|
|
return false;
|
|
}
|
|
|
|
if (!g_backend)
|
|
{
|
|
Logger::Log("CreateTexture: No backend available");
|
|
return false;
|
|
}
|
|
|
|
if (!g_backend->Create(m_hwbuffer))
|
|
{
|
|
Logger::Log("CreateTexture: Backend Create failed");
|
|
return false;
|
|
}
|
|
|
|
// Notify C# with texture info
|
|
if (g_callbacks.OnTextureReady)
|
|
{
|
|
g_callbacks.OnTextureReady(
|
|
g_backend->GetNativeTexturePtr(),
|
|
g_backend->GetWidth(),
|
|
g_backend->GetHeight(),
|
|
g_backend->IsVulkan()
|
|
);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void UpdateTexture()
|
|
{
|
|
if (g_backend)
|
|
{
|
|
g_backend->Update();
|
|
}
|
|
}
|
|
};
|
|
|
|
// Unity Plugin Interface
|
|
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API
|
|
UnityPluginLoad(IUnityInterfaces* unityInterfaces)
|
|
{
|
|
g_unityInterfaces = unityInterfaces;
|
|
|
|
IUnityGraphics* graphics = unityInterfaces->Get<IUnityGraphics>();
|
|
if (!graphics)
|
|
{
|
|
Logger::Log("UnityPluginLoad: IUnityGraphics not available");
|
|
return;
|
|
}
|
|
|
|
g_rendererType = graphics->GetRenderer();
|
|
Logger::Log(std::format("UnityPluginLoad: Renderer type = {}", static_cast<int>(g_rendererType)));
|
|
|
|
// Try to create Vulkan backend first
|
|
if (g_rendererType == kUnityGfxRendererVulkan)
|
|
{
|
|
auto vulkanBackend = std::make_unique<VulkanTextureBackend>();
|
|
if (vulkanBackend->Initialize(unityInterfaces))
|
|
{
|
|
g_backend = std::move(vulkanBackend);
|
|
Logger::Log("UnityPluginLoad: Using Vulkan backend");
|
|
return;
|
|
}
|
|
Logger::Log("UnityPluginLoad: Vulkan initialization failed, falling back to OpenGL");
|
|
}
|
|
|
|
// Fall back to OpenGL for GLES renderer (Unity 6+ only supports GLES 3.0+)
|
|
if (g_rendererType == kUnityGfxRendererOpenGLES30)
|
|
{
|
|
g_backend = std::make_unique<OpenGLTextureBackend>();
|
|
Logger::Log("UnityPluginLoad: Using OpenGL backend");
|
|
}
|
|
else
|
|
{
|
|
Logger::Log(std::format("UnityPluginLoad: Unsupported renderer type {}", static_cast<int>(g_rendererType)));
|
|
}
|
|
}
|
|
|
|
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API
|
|
UnityPluginUnload()
|
|
{
|
|
Logger::Log("UnityPluginUnload");
|
|
|
|
// Clean up backend
|
|
if (g_backend)
|
|
{
|
|
g_backend->Destroy();
|
|
g_backend.reset();
|
|
}
|
|
|
|
g_unityInterfaces = nullptr;
|
|
g_rendererType = kUnityGfxRendererNull;
|
|
}
|
|
|
|
// Native callback setters
|
|
extern "C" void SetNativeCallbacks(const NativeCallbacks& ptr)
|
|
{
|
|
g_callbacks = ptr;
|
|
}
|
|
|
|
// Touch input forwarding
|
|
extern "C" void SendTouchDown(float x, float y)
|
|
{
|
|
if (g_service)
|
|
{
|
|
g_service->onTouchDown(x, y);
|
|
}
|
|
}
|
|
|
|
extern "C" void SendTouchMove(float x, float y)
|
|
{
|
|
if (g_service)
|
|
{
|
|
g_service->onTouchMove(x, y);
|
|
}
|
|
}
|
|
|
|
extern "C" void SendTouchUp(float x, float y)
|
|
{
|
|
if (g_service)
|
|
{
|
|
g_service->onTouchUp(x, y);
|
|
}
|
|
}
|
|
|
|
// Unity render thread callbacks
|
|
static void UNITY_INTERFACE_API OnInitBackendRenderThread(int eventId)
|
|
{
|
|
Logger::Log("OnInitBackendRenderThread");
|
|
|
|
// For OpenGL, we need to initialize GLAD on the render thread
|
|
if (!g_backend->IsVulkan())
|
|
{
|
|
if (!OpenGLTextureBackend::InitializeGLAD())
|
|
{
|
|
Logger::Log("OnInitBackendRenderThread: Failed to initialize GLAD");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (g_context)
|
|
{
|
|
g_context->CreateTexture();
|
|
}
|
|
}
|
|
|
|
static void UNITY_INTERFACE_API OnUpdateTextureRenderThread(int eventId)
|
|
{
|
|
if (g_context)
|
|
{
|
|
g_context->UpdateTexture();
|
|
}
|
|
}
|
|
|
|
extern "C" UnityRenderingEvent InitBackend()
|
|
{
|
|
return OnInitBackendRenderThread;
|
|
}
|
|
|
|
extern "C" UnityRenderingEvent UpdateTexture()
|
|
{
|
|
return OnUpdateTextureRenderThread;
|
|
}
|
|
|
|
// Legacy compatibility - redirect to new names
|
|
extern "C" UnityRenderingEvent InitGLAD()
|
|
{
|
|
return InitBackend();
|
|
}
|
|
|
|
// JNI entry point from Kotlin
|
|
extern "C"
|
|
JNIEXPORT void JNICALL
|
|
Java_com_omixlab_mosis_unity_MyKotlinPlugin_serviceConnected(JNIEnv *env, jobject thiz,
|
|
jobject binder)
|
|
{
|
|
AIBinder* pBinder = AIBinder_fromJavaBinder(env, binder);
|
|
const ndk::SpAIBinder spBinder(pBinder);
|
|
g_service = IMosisService::fromBinder(spBinder);
|
|
Logger::Log("Service Connected");
|
|
|
|
g_context = ndk::SharedRefBase::make<ServiceContext>();
|
|
bool result{};
|
|
g_service->initOS(g_context, &result);
|
|
Logger::Log(std::format("InitOS returned {}", result));
|
|
}
|