#include "opengl_backend.h" #include bool OpenGLTextureBackend::InitializeGLAD() { gladLoaderLoadEGL(EGL_NO_DISPLAY); int egl_version = gladLoadEGL(eglGetCurrentDisplay(), eglGetProcAddress); if (egl_version == 0) { Logger::Log("OpenGLTextureBackend: Failed to load EGL"); return false; } int gl_version = gladLoaderLoadGLES2(); if (gl_version == 0) { Logger::Log("OpenGLTextureBackend: Failed to load GLES2"); return false; } Logger::Log("OpenGLTextureBackend: GLAD initialized successfully"); return true; } bool OpenGLTextureBackend::Create(AHardwareBuffer* buffer) { if (m_Created) { Destroy(); } // Get buffer dimensions AHardwareBuffer_Desc desc{}; AHardwareBuffer_describe(buffer, &desc); m_Width = static_cast(desc.width); m_Height = static_cast(desc.height); // Create EGL image from hardware buffer EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(buffer); EGLImageKHR eglImage = eglCreateImageKHR( eglGetCurrentDisplay(), EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer, nullptr ); if (eglImage == EGL_NO_IMAGE_KHR) { Logger::Log("OpenGLTextureBackend: Failed to create EGL image"); return false; } // Create source texture (external OES format from hardware buffer) glGenTextures(1, &m_SourceTexture); glBindTexture(GL_TEXTURE_EXTERNAL_OES, m_SourceTexture); 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); // Create source framebuffer glGenFramebuffers(1, &m_SourceFramebuffer); glBindFramebuffer(GL_FRAMEBUFFER, m_SourceFramebuffer); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_EXTERNAL_OES, m_SourceTexture, 0 ); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { Logger::Log("OpenGLTextureBackend: Source framebuffer incomplete"); Destroy(); return false; } // Create destination texture (standard 2D texture for Unity) glGenTextures(1, &m_DestTexture); glBindTexture(GL_TEXTURE_2D, m_DestTexture); 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, m_Width, m_Height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr ); // Create destination framebuffer glGenFramebuffers(1, &m_DestFramebuffer); glBindFramebuffer(GL_FRAMEBUFFER, m_DestFramebuffer); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_DestTexture, 0 ); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { Logger::Log("OpenGLTextureBackend: Dest framebuffer incomplete"); Destroy(); return false; } m_Created = true; // Initial blit Blit(); Logger::Log("OpenGLTextureBackend: Created successfully"); return true; } void OpenGLTextureBackend::Update() { if (m_Created) { Blit(); } } void OpenGLTextureBackend::Blit() { glBindFramebuffer(GL_READ_FRAMEBUFFER, m_SourceFramebuffer); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_DestFramebuffer); glBlitFramebuffer( 0, 0, m_Width, m_Height, 0, 0, m_Width, m_Height, GL_COLOR_BUFFER_BIT, GL_NEAREST ); } void OpenGLTextureBackend::Destroy() { if (m_DestFramebuffer) { glDeleteFramebuffers(1, &m_DestFramebuffer); m_DestFramebuffer = 0; } if (m_SourceFramebuffer) { glDeleteFramebuffers(1, &m_SourceFramebuffer); m_SourceFramebuffer = 0; } if (m_DestTexture) { glDeleteTextures(1, &m_DestTexture); m_DestTexture = 0; } if (m_SourceTexture) { glDeleteTextures(1, &m_SourceTexture); m_SourceTexture = 0; } m_Width = 0; m_Height = 0; m_Created = false; } void* OpenGLTextureBackend::GetNativeTexturePtr() { return reinterpret_cast(static_cast(m_DestTexture)); }