progress
This commit is contained in:
@@ -5,90 +5,29 @@
|
||||
#include <aidl/com/omixlab/mosis/IMosisService.h>
|
||||
#include <android/binder_ibinder_jni.h>
|
||||
#include <format>
|
||||
#include <glad/gles2.h>
|
||||
#include <glad/egl.h>
|
||||
#include <IUnityGraphics.h>
|
||||
#include <external_texture.h>
|
||||
#include <render_target.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;
|
||||
|
||||
class TextureBlitter
|
||||
{
|
||||
GLuint source_texture = 0;
|
||||
GLuint source_fb = 0;
|
||||
GLuint dest_texture = 0;
|
||||
GLuint dest_fb = 0;
|
||||
GLint width;
|
||||
GLint height;
|
||||
public:
|
||||
bool create(AHardwareBuffer* hardwareBuffer)
|
||||
{
|
||||
AHardwareBuffer_Desc desc{};
|
||||
AHardwareBuffer_describe(hardwareBuffer, &desc);
|
||||
width = desc.width;
|
||||
height = desc.height;
|
||||
EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(hardwareBuffer);
|
||||
EGLImageKHR eglImage = eglCreateImageKHR(eglGetCurrentDisplay(), EGL_NO_CONTEXT,
|
||||
EGL_NATIVE_BUFFER_ANDROID, clientBuffer, nullptr);
|
||||
if (eglImage == EGL_NO_IMAGE_KHR)
|
||||
{
|
||||
Logger::Log("Failed to create EGL image");
|
||||
return false;
|
||||
}
|
||||
glGenTextures(1, &source_texture);
|
||||
glBindTexture(GL_TEXTURE_EXTERNAL_OES, source_texture);
|
||||
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, eglImage);
|
||||
eglDestroyImageKHR(eglGetCurrentDisplay(), eglImage);
|
||||
|
||||
glGenFramebuffers(1, &source_fb);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, source_fb);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_EXTERNAL_OES, source_texture, 0);
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
return false;
|
||||
glGenTextures(1, &dest_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, dest_texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, desc.width, desc.height,
|
||||
0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
|
||||
glGenFramebuffers(1, &dest_fb);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, dest_fb);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, dest_texture, 0);
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
return false;
|
||||
blit();
|
||||
return true;
|
||||
}
|
||||
[[nodiscard]] GLuint dest_texture_id() const
|
||||
{
|
||||
return dest_texture;
|
||||
}
|
||||
void blit()
|
||||
{
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, source_fb);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dest_fb);
|
||||
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
}
|
||||
};
|
||||
|
||||
// Callback function pointers
|
||||
typedef void (*OnMessageCallback)(const char*);
|
||||
typedef void (*OnServiceInitializedCallback)(bool success);
|
||||
typedef void (*OnFrameAvailableCallback)();
|
||||
typedef void (*OnBufferReadyCallback)();
|
||||
typedef void (*OnTextureReadyCallback)(GLuint gl_texture);
|
||||
typedef void (*OnTextureReadyCallback)(void* nativeTexturePtr, int width, int height, bool isVulkan);
|
||||
|
||||
struct NativeCallbacks
|
||||
{
|
||||
OnMessageCallback OnMessage;
|
||||
@@ -102,49 +41,156 @@ NativeCallbacks g_callbacks{};
|
||||
class ServiceContext : public BnMosisListener
|
||||
{
|
||||
AHardwareBuffer* m_hwbuffer = nullptr;
|
||||
std::unique_ptr<TextureBlitter> m_texture;
|
||||
|
||||
public:
|
||||
ndk::ScopedAStatus onServiceInitialized(bool in_success) override
|
||||
{
|
||||
Logger::Log("onServiceInitialized");
|
||||
g_callbacks.OnMessage("onServiceInitialized");
|
||||
g_callbacks.OnServiceInitialized(in_success);
|
||||
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");
|
||||
g_callbacks.OnMessage("onFrameAvailable");
|
||||
g_callbacks.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");
|
||||
g_callbacks.OnMessage("onBufferAvailable");
|
||||
if (g_callbacks.OnMessage)
|
||||
g_callbacks.OnMessage("onBufferAvailable");
|
||||
m_hwbuffer = in_buffer.get();
|
||||
AHardwareBuffer_acquire(m_hwbuffer);
|
||||
g_callbacks.OnBufferReady();
|
||||
if (g_callbacks.OnBufferReady)
|
||||
g_callbacks.OnBufferReady();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
[[nodiscard]] GLuint create_texture()
|
||||
|
||||
bool CreateTexture()
|
||||
{
|
||||
m_texture = std::make_unique<TextureBlitter>();
|
||||
m_texture->create(m_hwbuffer);
|
||||
return m_texture->dest_texture_id();
|
||||
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 update_texture()
|
||||
|
||||
void UpdateTexture()
|
||||
{
|
||||
if (m_texture)
|
||||
m_texture->blit();
|
||||
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 renderers
|
||||
if (g_rendererType == kUnityGfxRendererOpenGLES20 ||
|
||||
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)
|
||||
@@ -153,40 +199,60 @@ extern "C" void SendTouchMove(float x, float y)
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" UnityRenderingEvent InitGLAD()
|
||||
extern "C" void SendTouchUp(float x, float y)
|
||||
{
|
||||
return [](int eventId){
|
||||
gladLoaderLoadEGL(EGL_NO_DISPLAY);
|
||||
int egl_version = gladLoadEGL(eglGetCurrentDisplay(), eglGetProcAddress);
|
||||
if (egl_version == 0)
|
||||
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("Failed to load EGL");
|
||||
Logger::Log("OnInitBackendRenderThread: Failed to initialize GLAD");
|
||||
return;
|
||||
}
|
||||
int gl_version = gladLoaderLoadGLES2();
|
||||
if (gl_version == 0)
|
||||
{
|
||||
Logger::Log("Failed to load GL");
|
||||
return;
|
||||
}
|
||||
if (g_context)
|
||||
{
|
||||
GLuint texture = g_context->create_texture();
|
||||
g_callbacks.OnTextureReady(texture);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
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 [](int eventId){
|
||||
if (g_context)
|
||||
{
|
||||
g_context->update_texture();
|
||||
}
|
||||
};
|
||||
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,
|
||||
@@ -196,6 +262,7 @@ Java_com_omixlab_mosis_unity_MyKotlinPlugin_serviceConnected(JNIEnv *env, jobjec
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user