From 604482d55cbaab9602e3c9f2ceb367f1f97db13a Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sun, 18 May 2025 20:51:58 +0800 Subject: [PATCH] [Feat]: Making DiligentCore EGL init work --- CMakeLists.txt | 11 +- MG/Includes.h | 10 + MG/Init.cpp | 2 + .../EGL/Diligent/GLES/EGL_impl.cpp | 335 ++++++++++++++++++ .../EGL/Diligent/GLES/EGL_impl.h | 62 ++++ MG/MG_GL/Implementations/EGL/GLES/EGL_WRAP.h | 2 + .../Implementations/GL/Getter/BackendInfo.cpp | 6 + MG/MG_RHI/GLES/Test/TestDrawing.cpp | 6 + 8 files changed, 429 insertions(+), 5 deletions(-) create mode 100644 MG/MG_GL/Implementations/EGL/Diligent/GLES/EGL_impl.cpp create mode 100644 MG/MG_GL/Implementations/EGL/Diligent/GLES/EGL_impl.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fe8f2366..52bda6f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,9 @@ add_library(${CMAKE_PROJECT_NAME} SHARED MG/MG_GL/Implementations/EGL/VK/EGL_EMU.cpp MG/MG_GL/Implementations/EGL/GLES/EGL_WRAP.cpp - + + MG/MG_GL/Implementations/EGL/Diligent/GLES/EGL_impl.cpp + # MG_GL/State MG/MG_GL/State/Core/GLState.cpp @@ -107,17 +109,16 @@ target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE vulkan ) +add_subdirectory(3rdparty/DiligentCore) + target_include_directories(MobileGL PUBLIC ${CMAKE_SOURCE_DIR}/include - ${CMAKE_SOURCE_DIR}/3rdparty/DiligentCore ) -add_subdirectory(3rdparty/DiligentCore) - target_link_libraries(MobileGL PRIVATE Diligent-Common - Diligent-GraphicsEngineOpenGL-static + Diligent-GraphicsEngineOpenGL-shared ) if (PROFILING) diff --git a/MG/Includes.h b/MG/Includes.h index 8df9ab35..3519ac28 100644 --- a/MG/Includes.h +++ b/MG/Includes.h @@ -134,3 +134,13 @@ #include #include #include + +#if BACKEND_TYPE == BACKEND_DILIGENT +#include "EngineFactory.h" +#include "EngineFactoryOpenGL.h" +#include "RefCntAutoPtr.hpp" + +#include "PipelineState.h" +#include "GraphicsTypes.h" +#include "DeviceContext.h" +#endif diff --git a/MG/Init.cpp b/MG/Init.cpp index 27bc3a36..2c21f76f 100644 --- a/MG/Init.cpp +++ b/MG/Init.cpp @@ -8,7 +8,9 @@ __attribute__((constructor)) void MG_Initialize() { MG_Util::Debug::LogInit(); MG_Util::Debug::LogI("MobileGL Initializing..."); MG_State::Init(); +#if BACKEND_TYPE == BACKEND_GLES MG_GL::BackendLoader::Init(); +#endif } __attribute__((destructor)) void MG_Destroy() { diff --git a/MG/MG_GL/Implementations/EGL/Diligent/GLES/EGL_impl.cpp b/MG/MG_GL/Implementations/EGL/Diligent/GLES/EGL_impl.cpp new file mode 100644 index 00000000..dac1bcbe --- /dev/null +++ b/MG/MG_GL/Implementations/EGL/Diligent/GLES/EGL_impl.cpp @@ -0,0 +1,335 @@ +// +// Created by Swung 0x48 on 2025-05-18. +// + +#include "EGL_impl.h" + +typedef Diligent::IEngineFactoryOpenGL* (*Diligent_GetEngineFactoryOpenGL_t)(); + +using namespace Diligent; + +namespace MG_EGL::Diligent { + static const char *VSSource = R"( +struct PSInput +{ + float4 Pos : SV_POSITION; + float3 Color : COLOR; +}; + +void main(in uint VertId : SV_VertexID, + out PSInput PSIn) +{ + float4 Pos[3]; + Pos[0] = float4(-0.5, -0.5, 0.0, 1.0); + Pos[1] = float4( 0.0, +0.5, 0.0, 1.0); + Pos[2] = float4(+0.5, -0.5, 0.0, 1.0); + + float3 Col[3]; + Col[0] = float3(1.0, 0.0, 0.0); // red + Col[1] = float3(0.0, 1.0, 0.0); // green + Col[2] = float3(0.0, 0.0, 1.0); // blue + + PSIn.Pos = Pos[VertId]; + PSIn.Color = Col[VertId]; +} +)"; + +// Pixel shader simply outputs interpolated vertex color + static const char *PSSource = R"( +struct PSInput +{ + float4 Pos : SV_POSITION; + float3 Color : COLOR; +}; + +struct PSOutput +{ + float4 Color : SV_TARGET; +}; + +void main(in PSInput PSIn, + out PSOutput PSOut) +{ + PSOut.Color = float4(PSIn.Color.rgb, 1.0); +} +)"; + + EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window, + const EGLint *attrib_list) { + void *handle = dlopen("libGraphicsEngineOpenGL.so", RTLD_LAZY); + auto Diligent_GetEngineFactoryOpenGL = + (Diligent_GetEngineFactoryOpenGL_t) dlsym(handle, + "Diligent_GetEngineFactoryOpenGL"); + + auto *pFactoryOpenGL = Diligent_GetEngineFactoryOpenGL(); + ::Diligent::EngineGLCreateInfo EngineCI; + auto *nativeWindow = static_cast(window); + EngineCI.Window.pAWindow = nativeWindow; + + ::Diligent::SwapChainDesc SCDesc; + + auto &ctx = MG_EGL::Diligent::DeviceContext::GetInstance(); + + pFactoryOpenGL->CreateDeviceAndSwapChainGL( + EngineCI, &ctx.pDevice, &ctx.pContext, SCDesc, &ctx.pSwapChain); + + // Pipeline state object encompasses configuration of all GPU stages + + GraphicsPipelineStateCreateInfo PSOCreateInfo; + + // Pipeline state name is used by the engine to report issues. + // It is always a good idea to give objects descriptive names. + PSOCreateInfo.PSODesc.Name = "Simple triangle PSO"; + + // This is a graphics pipeline + PSOCreateInfo.PSODesc.PipelineType = PIPELINE_TYPE_GRAPHICS; + + // clang-format off + // This tutorial will render to a single render target + PSOCreateInfo.GraphicsPipeline.NumRenderTargets = 1; + // Set render target format which is the format of the swap chain's color buffer + PSOCreateInfo.GraphicsPipeline.RTVFormats[0] = ctx.pSwapChain->GetDesc().ColorBufferFormat; + // Use the depth buffer format from the swap chain + PSOCreateInfo.GraphicsPipeline.DSVFormat = ctx.pSwapChain->GetDesc().DepthBufferFormat; + // Primitive topology defines what kind of primitives will be rendered by this pipeline state + PSOCreateInfo.GraphicsPipeline.PrimitiveTopology = PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + // No back face culling for this tutorial + PSOCreateInfo.GraphicsPipeline.RasterizerDesc.CullMode = CULL_MODE_NONE; + // Disable depth testing + PSOCreateInfo.GraphicsPipeline.DepthStencilDesc.DepthEnable = False; + // clang-format on + + ShaderCreateInfo ShaderCI; + // Tell the system that the shader source code is in HLSL. + // For OpenGL, the engine will convert this into GLSL under the hood. + ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL; + // OpenGL backend requires emulated combined HLSL texture samplers (g_Texture + g_Texture_sampler combination) + ShaderCI.Desc.UseCombinedTextureSamplers = true; + // Create a vertex shader + RefCntAutoPtr pVS; + { + ShaderCI.Desc.ShaderType = SHADER_TYPE_VERTEX; + ShaderCI.EntryPoint = "main"; + ShaderCI.Desc.Name = "Triangle vertex shader"; + ShaderCI.Source = VSSource; + ctx.pDevice->CreateShader(ShaderCI, &pVS); + } + + // Create a pixel shader + RefCntAutoPtr pPS; + { + ShaderCI.Desc.ShaderType = SHADER_TYPE_PIXEL; + ShaderCI.EntryPoint = "main"; + ShaderCI.Desc.Name = "Triangle pixel shader"; + ShaderCI.Source = PSSource; + ctx.pDevice->CreateShader(ShaderCI, &pPS); + } + + // Finally, create the pipeline state + PSOCreateInfo.pVS = pVS; + PSOCreateInfo.pPS = pPS; + ctx.pDevice->CreateGraphicsPipelineState(PSOCreateInfo, &ctx.pPSO); + + return (EGLSurface) 1; + } + + EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, + EGLint config_size, EGLint *num_config) { + *num_config = 1; + return EGL_TRUE; + } + + EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext shareCtx, + const EGLint *attrib_list) { + return (EGLContext) 1; + } + + EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) { + return EGL_TRUE; + } + + EGLDisplay eglGetDisplay(NativeDisplayType display) { + return (EGLDisplay) 1; + } + + EGLint eglGetError() { + return EGL_SUCCESS; + } + + EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) { + return EGL_TRUE; + } + + EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) { + return EGL_TRUE; + } + + EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) { + return EGL_TRUE; + } + + EGLBoolean eglTerminate(EGLDisplay dpy) { + return EGL_TRUE; + } + + EGLBoolean eglReleaseThread(void) { + return EGL_TRUE; + } + + EGLContext eglGetCurrentContext(void) { + return (EGLContext) 1; + } + + EGLBoolean + eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) { + if (attribute == EGL_NATIVE_VISUAL_ID) + *value = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; + return EGL_TRUE; + } + + EGLBoolean eglBindAPI(EGLenum api) { + return EGL_TRUE; + } + + EGLSurface eglGetCurrentSurface(EGLint readdraw) { + return (EGLSurface) 1; + } + + EGLBoolean + eglQuerySurface(EGLDisplay display, EGLSurface surface, EGLint attribute, EGLint *value) { + return EGL_TRUE; + } + + EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) { + return EGL_TRUE; + } + + EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) { + auto &ctx = MG_EGL::Diligent::DeviceContext::GetInstance(); + + // Clear the back buffer + const float ClearColor[] = {0.350f, 0.350f, 0.350f, 1.0f}; + // Let the engine perform required state transitions + ITextureView *pRTV = ctx.pSwapChain->GetCurrentBackBufferRTV(); + ITextureView *pDSV = ctx.pSwapChain->GetDepthBufferDSV(); + ctx.pContext->ClearRenderTarget(pRTV, ClearColor, + RESOURCE_STATE_TRANSITION_MODE_TRANSITION); + ctx.pContext->ClearDepthStencil(pDSV, CLEAR_DEPTH_FLAG, 1.f, 0, + RESOURCE_STATE_TRANSITION_MODE_TRANSITION); + + // Set the pipeline state in the immediate context + ctx.pContext->SetPipelineState(ctx.pPSO); + + // Typically we should now call CommitShaderResources(), however shaders in this example don't + // use any resources. + + DrawAttribs drawAttrs; + drawAttrs.NumVertices = 3; // We will render 3 vertices + ctx.pContext->Draw(drawAttrs); + + ctx.pSwapChain->Present(); + + return EGL_TRUE; + } + + EGLSurface + eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) { + return (EGLSurface) 1; + } + +} + +void *libGLES = nullptr, *libEGL = nullptr; + +static const char *LibPathPrefixes[] = { + "", + "/opt/vc/lib/", + "/usr/local/lib/", + "/usr/lib/", + nullptr +}; + +static const char *LibExts[] = { + "so", + "so.1", + "so.2", + "dylib", + "dll", + nullptr +}; + +static const char *GLES3Libs[] = { + "libGLESv3_CM", + "libGLESv3", + nullptr +}; + +static const char *EGLLibs[] = { + "libEGL", + nullptr +}; + +void *OpenLib(const char **names, const char *override) { + void *lib = nullptr; + + char path_name[PATH_MAX + 1]; + int flags = RTLD_LOCAL | RTLD_NOW; + if (override) { + if ((lib = dlopen(override, flags))) { + strncpy(path_name, override, PATH_MAX); + return lib; + } else { + MG_Util::Debug::LogE("LIBGL_GLES override failed: %s\n", dlerror()); + } + } + for (int p = 0; LibPathPrefixes[p]; p++) { + for (int i = 0; names[i]; i++) { + for (int e = 0; LibExts[e]; e++) { + snprintf(path_name, PATH_MAX, "%s%s.%s", LibPathPrefixes[p], names[i], LibExts[e]); + if ((lib = dlopen(path_name, flags))) { + return lib; + } + } + } + } + return lib; +} + +typedef __eglMustCastToProperFunctionPointerType (* eglGetProcAddress_t)(const char *procname); +eglGetProcAddress_t real_eglGetProcAddress = nullptr; + +__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) { + if (strncmp(procname, "eglGetProcAddress", strlen("eglGetProcAddress")) == 0) { + return (__eglMustCastToProperFunctionPointerType)(&eglGetProcAddress); + } + + MG_EGL_PROC_EXPORT(eglCreateWindowSurface); + MG_EGL_PROC_EXPORT(eglChooseConfig); + MG_EGL_PROC_EXPORT(eglCreateContext); + MG_EGL_PROC_EXPORT(eglInitialize); + MG_EGL_PROC_EXPORT(eglGetDisplay); + MG_EGL_PROC_EXPORT(eglGetError); + MG_EGL_PROC_EXPORT(eglMakeCurrent); + MG_EGL_PROC_EXPORT(eglDestroyContext); + MG_EGL_PROC_EXPORT(eglDestroySurface); + MG_EGL_PROC_EXPORT(eglTerminate); + MG_EGL_PROC_EXPORT(eglReleaseThread); + MG_EGL_PROC_EXPORT(eglGetCurrentContext); + MG_EGL_PROC_EXPORT(eglGetConfigAttrib); + MG_EGL_PROC_EXPORT(eglBindAPI); + MG_EGL_PROC_EXPORT(eglGetCurrentSurface); + MG_EGL_PROC_EXPORT(eglQuerySurface); + MG_EGL_PROC_EXPORT(eglSwapInterval); + MG_EGL_PROC_EXPORT(eglSwapBuffers); + MG_EGL_PROC_EXPORT(eglCreatePbufferSurface); + + /* TODO: Call real eglGetProcAddress() to get the rest (should be real native GLES functions) */ + if (!libEGL) { + libEGL = OpenLib(EGLLibs, nullptr); + real_eglGetProcAddress = (eglGetProcAddress_t)dlsym(libEGL, "eglGetProcAddress"); + } + if (real_eglGetProcAddress) + return real_eglGetProcAddress(procname); + + return nullptr; +} diff --git a/MG/MG_GL/Implementations/EGL/Diligent/GLES/EGL_impl.h b/MG/MG_GL/Implementations/EGL/Diligent/GLES/EGL_impl.h new file mode 100644 index 00000000..c80908ca --- /dev/null +++ b/MG/MG_GL/Implementations/EGL/Diligent/GLES/EGL_impl.h @@ -0,0 +1,62 @@ +// +// Created by Swung 0x48 on 2025-05-18. +// + +#ifndef MOBILEGLUES_EGL_IMPL_H +#define MOBILEGLUES_EGL_IMPL_H + + +#include "../../../../../Includes.h" + +#if BACKEND_TYPE == BACKEND_DILIGENT + +namespace MG_EGL::Diligent { + struct DeviceContext { + public: + static inline DeviceContext& GetInstance() { + static DeviceContext devctx; + return devctx; + } + + ::Diligent::RefCntAutoPtr<::Diligent::IRenderDevice> pDevice; + ::Diligent::RefCntAutoPtr<::Diligent::IDeviceContext> pContext; + ::Diligent::RefCntAutoPtr<::Diligent::ISwapChain> pSwapChain; + ::Diligent::RefCntAutoPtr<::Diligent::IPipelineState> pPSO; + bool initialized = false; + int majorVer = 1; + int minorVer = 5; + + }; + + EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint* attrib_list); + EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs, EGLint config_size, EGLint* num_config); + EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext shareCtx, const EGLint* attrib_list); + EGLBoolean eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor); + EGLDisplay eglGetDisplay(NativeDisplayType display); + EGLint eglGetError(); + EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); + EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx); + EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface); + EGLBoolean eglTerminate(EGLDisplay dpy); + EGLBoolean eglReleaseThread(void); + EGLContext eglGetCurrentContext(void); + EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value); + EGLBoolean eglBindAPI(EGLenum api); + EGLSurface eglGetCurrentSurface(EGLint readdraw); + EGLBoolean eglQuerySurface(EGLDisplay display, EGLSurface surface, EGLint attribute, EGLint *value); + EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval); + EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw); + EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list); +} + +#define MG_EGL_PROC_EXPORT(name) \ + if (strncmp(procname, #name, strlen(#name)) == 0) { \ + return (__eglMustCastToProperFunctionPointerType)(&MG_EGL::Diligent::name); \ + } + +MG_EXPORT __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname); + +#endif + + +#endif //MOBILEGLUES_EGL_IMPL_H diff --git a/MG/MG_GL/Implementations/EGL/GLES/EGL_WRAP.h b/MG/MG_GL/Implementations/EGL/GLES/EGL_WRAP.h index 86387480..1407ad19 100644 --- a/MG/MG_GL/Implementations/EGL/GLES/EGL_WRAP.h +++ b/MG/MG_GL/Implementations/EGL/GLES/EGL_WRAP.h @@ -9,6 +9,8 @@ #if BACKEND_TYPE == BACKEND_GLES + + #endif #endif //MOBILEGL_EGL_GLES_EGL_WRAP_H diff --git a/MG/MG_GL/Implementations/GL/Getter/BackendInfo.cpp b/MG/MG_GL/Implementations/GL/Getter/BackendInfo.cpp index 13ad681b..1b8ca3ba 100644 --- a/MG/MG_GL/Implementations/GL/Getter/BackendInfo.cpp +++ b/MG/MG_GL/Implementations/GL/Getter/BackendInfo.cpp @@ -12,6 +12,8 @@ namespace MG_GL::Getter { return "Metal"; #elif BACKEND_TYPE == BACKEND_GLES return "OpenGL ES"; +#elif BACKEND_TYPE == BACKEND_DILIGENT + return "Diligent"; #else return ""; #endif @@ -24,6 +26,8 @@ namespace MG_GL::Getter { return "MobileGlumtl"; #elif BACKEND_TYPE == BACKEND_GLES return "MobileGlues"; +#elif BACKEND_TYPE == BACKEND_DILIGENT + return "MobileGluDiligent"; #else return ""; #endif @@ -79,6 +83,8 @@ namespace MG_GL::Getter { std::to_string(minor)+"." + std::to_string(patch); #elif BACKEND_TYPE == BACKEND_GLES backendVersion = std::string((const char*)::GLES::glGetString(GL_VERSION)); +#elif BACKEND_TYPE == BACKEND_DILIGENT + backendVersion = "Diligent"; #else backendVersion = ""; #endif diff --git a/MG/MG_RHI/GLES/Test/TestDrawing.cpp b/MG/MG_RHI/GLES/Test/TestDrawing.cpp index 93348cb6..b37c0f28 100644 --- a/MG/MG_RHI/GLES/Test/TestDrawing.cpp +++ b/MG/MG_RHI/GLES/Test/TestDrawing.cpp @@ -14,6 +14,7 @@ namespace MG_RHI::GLES::Test { } bool CheckShaderCompileStatus(GLuint shader, const char* type) { +#if BACKEND_TYPE == BACKEND_GLES GLint success; ::GLES::glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if (!success) { @@ -22,10 +23,12 @@ namespace MG_RHI::GLES::Test { MG_Util::Debug::LogE("Shader compilation error (%s): %s", type, infoLog); return false; } +#endif return true; } bool CheckProgramLinkStatus(GLuint program) { +#if BACKEND_TYPE == BACKEND_GLES GLint success; ::GLES::glGetProgramiv(program, GL_LINK_STATUS, &success); if (!success) { @@ -34,11 +37,13 @@ namespace MG_RHI::GLES::Test { MG_Util::Debug::LogE("Program link error: %s", infoLog); return false; } +#endif return true; } // TODO: Use the textures state from MG_RHI(another state?) rather than directly from MG_State void DrawAllTextures() { +#if BACKEND_TYPE == BACKEND_GLES ::GLES::glClearColor(1,1,1,1); ::GLES::glClear(GL_COLOR_BUFFER_BIT); @@ -230,5 +235,6 @@ namespace MG_RHI::GLES::Test { ::GLES::glUseProgram(origProgram); ::GLES::glViewport(origViewport[0], origViewport[1], origViewport[2], origViewport[3]); +#endif } } \ No newline at end of file