diff --git a/filament/backend/CMakeLists.txt b/filament/backend/CMakeLists.txt index 0a07c82836d..9a70983d794 100644 --- a/filament/backend/CMakeLists.txt +++ b/filament/backend/CMakeLists.txt @@ -378,10 +378,6 @@ set(LINUX_LINKER_OPTIMIZATION_FLAGS if (LINUX AND FILAMENT_SUPPORTS_OSMESA) set(OSMESA_COMPILE_FLAGS -I${FILAMENT_OSMESA_PATH}/include/GL) - set(OSMESA_LINKER_FLAGS - -Wl,-L${FILAMENT_OSMESA_PATH}/lib/x86_64-linux-gnu/ - -lOSMesa - ) endif() if (MSVC) diff --git a/filament/backend/include/backend/platforms/PlatformOSMesa.h b/filament/backend/include/backend/platforms/PlatformOSMesa.h index bcb82195a4c..a1a72fc6f77 100644 --- a/filament/backend/include/backend/platforms/PlatformOSMesa.h +++ b/filament/backend/include/backend/platforms/PlatformOSMesa.h @@ -21,7 +21,7 @@ #include "bluegl/BlueGL.h" -#include "osmesa.h" +#include #include #include @@ -56,6 +56,7 @@ class PlatformOSMesa : public OpenGLPlatform { private: OSMesaContext mContext; + void* mOsMesaApi = nullptr; }; } // namespace filament::backend diff --git a/filament/backend/src/opengl/platforms/PlatformOSMesa.cpp b/filament/backend/src/opengl/platforms/PlatformOSMesa.cpp index 9a34577dc1c..fdeccfe110f 100644 --- a/filament/backend/src/opengl/platforms/PlatformOSMesa.cpp +++ b/filament/backend/src/opengl/platforms/PlatformOSMesa.cpp @@ -19,6 +19,7 @@ #include #include +#include #include namespace filament::backend { @@ -41,13 +42,56 @@ struct OSMesaSwapchain { std::unique_ptr buffer; }; -} // anonymous namespace +struct OSMesaAPI { +private: + using CreateContextFunc = OSMesaContext (*)(GLenum format, OSMesaContext); + using DestroyContextFunc = GLboolean (*)(OSMesaContext); + using MakeCurrentFunc = GLboolean (*)(OSMesaContext ctx, void* buffer, GLenum type, + GLsizei width, GLsizei height); + using GetProcAddressFunc = OSMESAproc (*)(const char* funcName); + +public: + CreateContextFunc OSMesaCreateContext; + DestroyContextFunc OSMesaDestroyContext; + MakeCurrentFunc OSMesaMakeCurrent; + GetProcAddressFunc OSMesaGetProcAddress; + + OSMesaAPI() { + constexpr char const* libraryNames[] = {"libOSMesa.so", "libosmesa.so"}; + for (char const* libName: libraryNames) { + mLib = dlopen(libName, RTLD_GLOBAL | RTLD_NOW); + if (mLib) { + break; + } + } + FILAMENT_CHECK_PRECONDITION(mLib) + << "Unable to dlopen libOSMesa to create a software GL context"; + + OSMesaGetProcAddress = (GetProcAddressFunc) dlsym(mLib, "OSMesaGetProcAddress"); + + OSMesaCreateContext = (CreateContextFunc) OSMesaGetProcAddress("OSMesaCreateContext"); + OSMesaDestroyContext = + (DestroyContextFunc) OSMesaGetProcAddress("OSMesaDestroyContext"); + OSMesaMakeCurrent = (MakeCurrentFunc) OSMesaGetProcAddress("OSMesaMakeCurrent"); + } + + ~OSMesaAPI() { + dlclose(mLib); + } +private: + void* mLib = nullptr; +}; + +}// anonymous namespace Driver* PlatformOSMesa::createDriver(void* const sharedGLContext, const DriverConfig& driverConfig) noexcept { + OSMesaAPI* api = new OSMesaAPI(); + mOsMesaApi = api; + FILAMENT_CHECK_PRECONDITION(sharedGLContext == nullptr) << "shared GL context is not supported with PlatformOSMesa"; - mContext = OSMesaCreateContext(GL_RGBA, NULL); + mContext = api->OSMesaCreateContext(GL_RGBA, NULL); // We need to do a no-op makecurrent here so that the context will be in a correct state before // any GL calls. @@ -62,7 +106,11 @@ Driver* PlatformOSMesa::createDriver(void* const sharedGLContext, } void PlatformOSMesa::terminate() noexcept { - OSMesaDestroyContext(mContext); + OSMesaAPI* api = (OSMesaAPI*) mOsMesaApi; + api->OSMesaDestroyContext(mContext); + delete api; + mOsMesaApi = nullptr; + bluegl::unbind(); } @@ -84,11 +132,12 @@ void PlatformOSMesa::destroySwapChain(Platform::SwapChain* swapChain) noexcept { bool PlatformOSMesa::makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept { + OSMesaAPI* api = (OSMesaAPI*) mOsMesaApi; OSMesaSwapchain* impl = (OSMesaSwapchain*) drawSwapChain; - auto result = OSMesaMakeCurrent(mContext, (BackingType*) impl->buffer.get(), BACKING_GL_TYPE, - impl->width, impl->height); - FILAMENT_CHECK_POSTCONDITION(result) << "OSMesaMakeCurrent failed!"; + auto result = api->OSMesaMakeCurrent(mContext, (BackingType*) impl->buffer.get(), + BACKING_GL_TYPE, impl->width, impl->height); + FILAMENT_CHECK_POSTCONDITION(result == GL_TRUE) << "OSMesaMakeCurrent failed!"; return true; } diff --git a/libs/bluegl/CMakeLists.txt b/libs/bluegl/CMakeLists.txt index 9ce75c177dd..704432cd15a 100644 --- a/libs/bluegl/CMakeLists.txt +++ b/libs/bluegl/CMakeLists.txt @@ -36,6 +36,8 @@ elseif (APPLE AND NOT IOS) elseif(LINUX) if(FILAMENT_SUPPORTS_EGL_ON_LINUX) set(SRCS ${SRCS} src/BlueGLLinuxEGL.cpp) + elseif(FILAMENT_SUPPORTS_OSMESA) + set(SRCS ${SRCS} src/BlueGLLinuxOSMesa.cpp) else() set(SRCS ${SRCS} src/BlueGLLinux.cpp) endif() diff --git a/libs/bluegl/src/BlueGLLinuxOSMesa.cpp b/libs/bluegl/src/BlueGLLinuxOSMesa.cpp new file mode 100644 index 00000000000..182f5b2a528 --- /dev/null +++ b/libs/bluegl/src/BlueGLLinuxOSMesa.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace bluegl { + +namespace { +using ProcAddressFunc = void*(*)(char const* funcName); +} + +struct Driver { + ProcAddressFunc OSMesaGetProcAddress; + void* library; +} g_driver = {nullptr, nullptr}; + +bool initBinder() { + constexpr char const* libraryNames[] = {"libOSMesa.so", "libosmesa.so"}; + for (char const* name : libraryNames) { + g_driver.library = dlopen(name, RTLD_GLOBAL | RTLD_NOW); + if (g_driver.library) { + break; + } + } + if (!g_driver.library) { + return false; + } + + g_driver.OSMesaGetProcAddress = (ProcAddressFunc) + dlsym(g_driver.library, "OSMesaGetProcAddress"); + + return g_driver.OSMesaGetProcAddress; +} + +void* loadFunction(const char* name) { + return (void*) g_driver.OSMesaGetProcAddress(name); +} + +void shutdownBinder() { + dlclose(g_driver.library); + memset(&g_driver, 0, sizeof(g_driver)); +} + +} // namespace bluegl