FindOpenGL: support finding GLES2 and GLES3

This also makes the EGL component not GLVND-specific, so documentation
and tests are updated accordingly.
This commit is contained in:
Jaswant Panchumarti
2023-03-09 13:07:15 -05:00
parent b6ffbffaf2
commit beb0a56c86
5 changed files with 328 additions and 33 deletions

View File

@@ -0,0 +1,5 @@
FindOpenGL-gles
---------------
* The :module:`FindOpenGL` module gained support for components
``GLES2`` and ``GLES3``.

View File

@@ -18,8 +18,26 @@ Optional COMPONENTS
.. versionadded:: 3.10
This module respects several optional COMPONENTS: ``EGL``, ``GLX``, and
``OpenGL``. There are corresponding import targets for each of these flags.
This module respects several optional COMPONENTS:
``EGL``
The EGL interface between OpenGL, OpenGL ES and the underlying windowing system.
``GLX``
An extension to X that interfaces OpenGL, OpenGL ES with X window system.
``OpenGL``
The cross platform API for 3D graphics.
``GLES2``
.. versionadded:: 3.27
A subset of OpenGL API for embedded systems with limited capabilities.
``GLES3``
.. versionadded:: 3.27
A subset of OpenGL API for embedded systems with more capabilities.
IMPORTED Targets
^^^^^^^^^^^^^^^^
@@ -42,6 +60,14 @@ This module defines the :prop_tgt:`IMPORTED` targets:
Defined if the system has OpenGL Extension to the X Window System (GLX).
``OpenGL::EGL``
Defined if the system has EGL.
``OpenGL::GLES2``
.. versionadded:: 3.27
Defined if the system has GLES2.
``OpenGL::GLES3``
.. versionadded:: 3.27
Defined if the system has GLES3.
Result Variables
^^^^^^^^^^^^^^^^
@@ -60,6 +86,10 @@ This module sets the following variables:
True, if the system has GLX.
``OpenGL_EGL_FOUND``
True, if the system has EGL.
``OpenGL::GLES2``
Defined if the system has GLES2.
``OpenGL::GLES3``
Defined if the system has GLES3.
``OPENGL_INCLUDE_DIR``
Path to the OpenGL include directory.
``OPENGL_EGL_INCLUDE_DIRS``
@@ -88,6 +118,14 @@ The following cache variables may also be set:
``OPENGL_gl_LIBRARY``
Path to the OpenGL library. New code should prefer the ``OpenGL::*`` import
targets.
``OPENGL_gles2_LIBRARY``
.. versionadded:: 3.27
Path to the OpenGL GLES2 library.
``OPENGL_gles3_LIBRARY``
.. versionadded:: 3.27
Path to the OpenGL GLES3 library.
.. versionadded:: 3.10
Variables for GLVND-specific libraries ``OpenGL``, ``EGL`` and ``GLX``.
@@ -182,7 +220,10 @@ elseif (APPLE)
OPENGL_glu_LIBRARY
)
else()
if (CMAKE_SYSTEM_NAME MATCHES "HP-UX")
if (CMAKE_ANDROID_NDK)
set(_OPENGL_INCLUDE_PATH ${CMAKE_ANDROID_NDK}/sysroot/usr/include)
set(_OPENGL_LIB_PATH ${CMAKE_ANDROID_NDK}/platforms/android-${CMAKE_SYSTEM_VERSION}/arch-${CMAKE_ANDROID_ARCH}/usr/lib)
elseif (CMAKE_SYSTEM_NAME MATCHES "HP-UX")
# Handle HP-UX cases where we only want to find OpenGL in either hpux64
# or hpux32 depending on if we're doing a 64 bit build.
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
@@ -198,6 +239,13 @@ else()
/boot/develop/lib/x86)
set(_OPENGL_INCLUDE_PATH
/boot/develop/headers/os/opengl)
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
# CMake doesn't support arbitrary globs in search paths.
file(GLOB _OPENGL_LIB_PATH
# The NVidia driver installation tool on Linux installs libraries to a
# `nvidia-<version>` subdirectory.
"/usr/lib/nvidia-*"
"/usr/lib32/nvidia-*")
endif()
# The first line below is to make sure that the proper headers
@@ -215,15 +263,20 @@ else()
)
find_path(OPENGL_GLX_INCLUDE_DIR GL/glx.h ${_OPENGL_INCLUDE_PATH})
find_path(OPENGL_EGL_INCLUDE_DIR EGL/egl.h ${_OPENGL_INCLUDE_PATH})
find_path(OPENGL_GLES2_INCLUDE_DIR GLES2/gl2.h ${_OPENGL_INCLUDE_PATH})
find_path(OPENGL_GLES3_INCLUDE_DIR GLES3/gl3.h ${_OPENGL_INCLUDE_PATH})
find_path(OPENGL_xmesa_INCLUDE_DIR GL/xmesa.h
/usr/share/doc/NVIDIA_GLX-1.0/include
/usr/openwin/share/include
/opt/graphics/OpenGL/include
)
list(APPEND _OpenGL_CACHE_VARS
OPENGL_INCLUDE_DIR
OPENGL_GLX_INCLUDE_DIR
OPENGL_EGL_INCLUDE_DIR
OPENGL_GLES2_INCLUDE_DIR
OPENGL_GLES3_INCLUDE_DIR
OPENGL_xmesa_INCLUDE_DIR
)
@@ -246,6 +299,17 @@ else()
PATH_SUFFIXES libglvnd
)
find_library(OPENGL_gles2_LIBRARY
NAMES GLESv2
PATHS ${_OPENGL_LIB_PATH}
)
find_library(OPENGL_gles3_LIBRARY
NAMES GLESv3
GLESv2 # mesa provides only libGLESv2
PATHS ${_OPENGL_LIB_PATH}
)
find_library(OPENGL_glu_LIBRARY
NAMES GLU MesaGLU
PATHS ${OPENGL_gl_LIBRARY}
@@ -258,6 +322,8 @@ else()
OPENGL_opengl_LIBRARY
OPENGL_glx_LIBRARY
OPENGL_egl_LIBRARY
OPENGL_gles2_LIBRARY
OPENGL_gles3_LIBRARY
OPENGL_glu_LIBRARY
)
@@ -338,12 +404,16 @@ else()
OPENGL_glx_LIBRARY AND
NOT OPENGL_gl_LIBRARY) OR
(NOT OPENGL_USE_EGL AND
NOT OPENGL_USE_GLES3 AND
NOT OPENGL_USE_GLES2 AND
NOT OPENGL_glx_LIBRARY AND
NOT OPENGL_gl_LIBRARY) OR
(NOT OPENGL_USE_EGL AND
OPENGL_opengl_LIBRARY AND
OPENGL_glx_LIBRARY) OR
( OPENGL_USE_EGL))
(NOT OPENGL_USE_GLES3 AND
NOT OPENGL_USE_GLES2 AND
OPENGL_USE_EGL))
list(APPEND _OpenGL_REQUIRED_VARS OPENGL_opengl_LIBRARY)
endif()
@@ -351,13 +421,19 @@ else()
if((NOT OPENGL_USE_OPENGL AND
NOT OPENGL_USE_GLX AND
NOT OPENGL_USE_EGL AND
NOT OPENGL_USE_GLES3 AND
NOT OPENGL_USE_GLES2 AND
NOT OPENGL_glx_LIBRARY AND
NOT OPENGL_gl_LIBRARY) OR
( OPENGL_USE_GLX AND
NOT OPENGL_USE_EGL AND
NOT OPENGL_USE_GLES3 AND
NOT OPENGL_USE_GLES2 AND
NOT OPENGL_glx_LIBRARY AND
NOT OPENGL_gl_LIBRARY) OR
(NOT OPENGL_USE_EGL AND
NOT OPENGL_USE_GLES3 AND
NOT OPENGL_USE_GLES2 AND
OPENGL_opengl_LIBRARY AND
OPENGL_glx_LIBRARY) OR
(OPENGL_USE_GLX AND OPENGL_USE_EGL))
@@ -369,6 +445,16 @@ else()
list(APPEND _OpenGL_REQUIRED_VARS OPENGL_egl_LIBRARY)
endif()
# GLVND GLES2 library.
if(OPENGL_USE_GLES2)
list(APPEND _OpenGL_REQUIRED_VARS OPENGL_gles2_LIBRARY)
endif()
# GLVND GLES3 library.
if(OPENGL_USE_GLES3)
list(APPEND _OpenGL_REQUIRED_VARS OPENGL_gles3_LIBRARY)
endif()
# Old-style "libGL" library: used as a fallback when GLVND isn't available.
if((NOT OPENGL_USE_EGL AND
NOT OPENGL_opengl_LIBRARY AND
@@ -381,7 +467,11 @@ else()
endif()
# We always need the 'gl.h' include dir.
list(APPEND _OpenGL_REQUIRED_VARS OPENGL_INCLUDE_DIR)
if(OPENGL_USE_EGL)
list(APPEND _OpenGL_REQUIRED_VARS OPENGL_EGL_INCLUDE_DIR)
else()
list(APPEND _OpenGL_REQUIRED_VARS OPENGL_INCLUDE_DIR)
endif()
unset(_OPENGL_INCLUDE_PATH)
unset(_OPENGL_LIB_PATH)
@@ -428,6 +518,18 @@ else()
set(OpenGL_EGL_FOUND FALSE)
endif()
if(OPENGL_gles2_LIBRARY AND OPENGL_GLES2_INCLUDE_DIR)
set(OpenGL_GLES2_FOUND TRUE)
else()
set(OpenGL_GLES2_FOUND FALSE)
endif()
if(OPENGL_gles3_LIBRARY AND OPENGL_GLES3_INCLUDE_DIR)
set(OpenGL_GLES3_FOUND TRUE)
else()
set(OpenGL_GLES3_FOUND FALSE)
endif()
# User-visible names should be plural.
if(OPENGL_EGL_INCLUDE_DIR)
set(OPENGL_EGL_INCLUDE_DIRS ${OPENGL_EGL_INCLUDE_DIR})
@@ -461,6 +563,7 @@ if(OPENGL_FOUND)
endif()
set_target_properties(OpenGL::OpenGL PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
"${OPENGL_INCLUDE_DIR}")
set(_OpenGL_EGL_IMPL OpenGL::OpenGL)
endif()
# ::GLX is a GLVND library, and thus Linux-only: we don't bother checking
@@ -481,6 +584,73 @@ if(OPENGL_FOUND)
"${OPENGL_GLX_INCLUDE_DIR}")
endif()
# ::GLES2 is a GLVND library, and thus Linux-only: we don't bother checking
# for a framework version of this library.
if(OpenGL_GLES2_FOUND AND NOT TARGET OpenGL::GLES2)
# Initialize target
if(NOT OPENGL_gles2_LIBRARY)
add_library(OpenGL::GLES2 INTERFACE IMPORTED)
else()
if(IS_ABSOLUTE "${OPENGL_gles2_LIBRARY}")
add_library(OpenGL::GLES2 UNKNOWN IMPORTED)
set_target_properties(OpenGL::GLES2 PROPERTIES
IMPORTED_LOCATION "${OPENGL_gles2_LIBRARY}"
)
else()
add_library(OpenGL::GLES2 INTERFACE IMPORTED)
set_target_properties(OpenGL::GLES2 PROPERTIES
IMPORTED_LIBNAME "${OPENGL_gles2_LIBRARY}"
)
endif()
endif()
# Attach target properties
set_target_properties(OpenGL::GLES2
PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES
"${OPENGL_GLES2_INCLUDE_DIR}"
)
if (OPENGL_USE_GLES2)
set(_OpenGL_EGL_IMPL OpenGL::GLES2)
endif ()
endif()
# ::GLES3 is a GLVND library, and thus Linux-only: we don't bother checking
# for a framework version of this library.
if(OpenGL_GLES3_FOUND AND NOT TARGET OpenGL::GLES3)
# Initialize target
if(NOT OPENGL_gles3_LIBRARY)
add_library(OpenGL::GLES3 INTERFACE IMPORTED)
else()
if(IS_ABSOLUTE "${OPENGL_gles3_LIBRARY}")
add_library(OpenGL::GLES3 UNKNOWN IMPORTED)
set_target_properties(OpenGL::GLES3 PROPERTIES
IMPORTED_LOCATION "${OPENGL_gles3_LIBRARY}"
)
else()
add_library(OpenGL::GLES3 INTERFACE IMPORTED)
set_target_properties(OpenGL::GLES3 PROPERTIES
IMPORTED_LIBNAME "${OPENGL_gles3_LIBRARY}"
)
endif()
endif()
# Attach target properties
set_target_properties(OpenGL::GLES3 PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES
"${OPENGL_GLES3_INCLUDE_DIR}"
)
if (OPENGL_USE_GLES3)
set(_OpenGL_EGL_IMPL OpenGL::GLES3)
endif ()
endif()
if(OPENGL_gl_LIBRARY AND NOT TARGET OpenGL::GL)
# A legacy GL library is available, so use it for the legacy GL target.
if(IS_ABSOLUTE "${OPENGL_gl_LIBRARY}")
@@ -517,10 +687,9 @@ if(OPENGL_FOUND)
# ::EGL is a GLVND library, and thus Linux-only: we don't bother checking
# for a framework version of this library.
# Note we test for OpenGL::OpenGL as a target. When this module is updated to
# support GLES, we would additionally want to check for the hypothetical GLES
# target and enable EGL if either ::GLES or ::OpenGL is created.
if(TARGET OpenGL::OpenGL AND OpenGL_EGL_FOUND AND NOT TARGET OpenGL::EGL)
# Note we test whether _OpenGL_EGL_IMPL is set. Based on the OpenGL implementation,
# _OpenGL_EGL_IMPL will be one of OpenGL::OpenGL, OpenGL::GLES2, OpenGL::GLES3
if(_OpenGL_EGL_IMPL AND OpenGL_EGL_FOUND AND NOT TARGET OpenGL::EGL)
if(IS_ABSOLUTE "${OPENGL_egl_LIBRARY}")
add_library(OpenGL::EGL UNKNOWN IMPORTED)
set_target_properties(OpenGL::EGL PROPERTIES IMPORTED_LOCATION
@@ -531,7 +700,7 @@ if(OPENGL_FOUND)
"${OPENGL_egl_LIBRARY}")
endif()
set_target_properties(OpenGL::EGL PROPERTIES INTERFACE_LINK_LIBRARIES
OpenGL::OpenGL)
"${_OpenGL_EGL_IMPL}")
# Note that EGL's include directory is different from OpenGL/GLX's!
set_target_properties(OpenGL::EGL PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
"${OPENGL_EGL_INCLUDE_DIR}")

View File

@@ -44,28 +44,115 @@ else()
add_test(NAME test_comp_glx_novnd COMMAND test_comp_glx_novnd)
endif()
# EGL is only available on Linux+GLVND at present.
if(OpenGL_TEST_VND)
find_package(OpenGL COMPONENTS OpenGL EGL)
if(OpenGL_EGL_FOUND)
add_executable(test_comp_egl main.c)
target_link_libraries(test_comp_egl PRIVATE OpenGL::OpenGL OpenGL::EGL)
add_test(NAME test_comp_egl COMMAND test_comp_egl)
# EGL-only code should not link to GLX.
execute_process(COMMAND ldd test_comp_egl
OUTPUT_VARIABLE LDD_OUT
ERROR_VARIABLE LDD_ERR)
if("${LDD_OUT}" MATCHES "GLX")
message(FATAL_ERROR "EGL-only code links to GLX!")
endif()
endif()
# all three COMPONENTS together.
find_package(OpenGL COMPONENTS OpenGL EGL GLX)
if(OpenGL_EGL_FOUND AND OpenGL_GLX_FOUND)
add_executable(test_comp_both main.c)
target_link_libraries(test_comp_both PRIVATE OpenGL::OpenGL OpenGL::EGL
OpenGL::GLX)
add_test(NAME test_comp_both COMMAND test_comp_both)
find_package(OpenGL COMPONENTS OpenGL EGL)
if(OpenGL_EGL_FOUND)
add_executable(test_comp_egl main.c)
target_link_libraries(test_comp_egl PRIVATE OpenGL::OpenGL OpenGL::EGL)
add_test(NAME test_comp_egl COMMAND test_comp_egl)
# EGL-only code should not link to GLX.
get_target_property(iface_libs OpenGL::EGL INTERFACE_LINK_LIBRARIES)
if(iface_libs MATCHES "GLX")
message(FATAL_ERROR "EGL-only code links to GLX!")
endif()
endif()
# all three COMPONENTS together.
find_package(OpenGL COMPONENTS OpenGL EGL GLX)
if(OpenGL_EGL_FOUND AND OpenGL_GLX_FOUND)
add_executable(test_comp_both main.c)
target_link_libraries(test_comp_both PRIVATE OpenGL::OpenGL OpenGL::EGL
OpenGL::GLX)
add_test(NAME test_comp_both COMMAND test_comp_both)
endif()
find_package(OpenGL COMPONENTS GLES2)
if(OpenGL_GLES2_FOUND)
add_executable(test_comp_gles2 main_gles2.c)
target_link_libraries(test_comp_gles2 PRIVATE OpenGL::GLES2)
add_test(NAME test_comp_gles2 COMMAND test_comp_gles2)
# GLES2-only code should not link to OpenGL
get_target_property(iface_libs test_comp_gles2 LINK_LIBRARIES)
if(iface_libs MATCHES "OpenGL::OpenGL")
message(FATAL_ERROR "GLES2-only code links to OpenGL!")
endif()
endif()
# GLES2 and EGL together.
find_package(OpenGL COMPONENTS GLES2 EGL)
if(OpenGL_GLES2_FOUND AND OpenGL_EGL_FOUND)
add_executable(test_comp_gles2_egl main_gles2.c)
target_link_libraries(test_comp_gles2_egl PRIVATE OpenGL::GLES2
OpenGL::EGL)
add_test(NAME test_comp_gles2_egl COMMAND test_comp_gles2_egl)
# GLES2-EGL-only code should not link to OpenGL or GLX
get_target_property(iface_libs test_comp_gles2_egl LINK_LIBRARIES)
if(iface_libs MATCHES "OpenGL::OpenGL")
message(FATAL_ERROR "GLES2-only code links to OpenGL!")
endif()
if(iface_libs MATCHES "GLX")
message(FATAL_ERROR "GLES2-EGL-only code links to GLX!")
endif()
endif()
# GLES2 and GLX together.
find_package(OpenGL COMPONENTS GLES2 GLX)
if(OpenGL_GLES2_FOUND AND OpenGL_GLX_FOUND)
add_executable(test_comp_gles2_glx main_gles2.c)
target_link_libraries(test_comp_gles2_glx PRIVATE OpenGL::GLES2
OpenGL::GLX)
add_test(NAME test_comp_gles2_glx COMMAND test_comp_gles2_glx)
# GLES2-GLX-only code should not link to OpenGL or EGL
get_target_property(iface_libs test_comp_gles2_glx LINK_LIBRARIES)
if(iface_libs MATCHES "OpenGL::OpenGL")
message(FATAL_ERROR "GLES2-only code links to OpenGL!")
endif()
if(iface_libs MATCHES "EGL")
message(FATAL_ERROR "GLES2-GLX-only code links to EGL!")
endif()
endif()
find_package(OpenGL COMPONENTS GLES3)
if(OpenGL_GLES3_FOUND)
add_executable(test_comp_gles3 main_gles3.c)
target_link_libraries(test_comp_gles3 PRIVATE OpenGL::GLES3)
add_test(NAME test_comp_gles3 COMMAND test_comp_gles3)
# GLES3-only code should not link to OpenGL.
get_target_property(iface_libs test_comp_gles3 LINK_LIBRARIES)
if(iface_libs MATCHES "OpenGL::OpenGL")
message(FATAL_ERROR "GLES3-only code links to OpenGL!")
endif()
endif()
# GLES3 and EGL together.
find_package(OpenGL COMPONENTS GLES3 EGL)
if(OpenGL_GLES3_FOUND AND OpenGL_EGL_FOUND)
add_executable(test_comp_gles3_egl main_gles3.c)
target_link_libraries(test_comp_gles3_egl PRIVATE OpenGL::GLES3
OpenGL::EGL)
add_test(NAME test_comp_gles3_egl COMMAND test_comp_gles3_egl)
# GLES3-EGL-only code should not link to OpenGL or GLX
get_target_property(iface_libs test_comp_gles3_egl LINK_LIBRARIES)
if(iface_libs MATCHES "OpenGL::OpenGL")
message(FATAL_ERROR "GLES3-only code links to OpenGL!")
endif()
if(iface_libs MATCHES "GLX")
message(FATAL_ERROR "GLES3-EGL-only code links to GLX!")
endif()
endif()
# GLES3 and GLX together.
find_package(OpenGL COMPONENTS GLES3 GLX)
if(OpenGL_GLES3_FOUND AND OpenGL_GLX_FOUND)
add_executable(test_comp_gles3_glx main_gles3.c)
target_link_libraries(test_comp_gles3_glx PRIVATE OpenGL::GLES3
OpenGL::GLX)
add_test(NAME test_comp_gles3_glx COMMAND test_comp_gles3_glx)
# GLESr-GLX-only code should not link to OpenGL or EGL
get_target_property(iface_libs test_comp_gles3_glx LINK_LIBRARIES)
if(iface_libs MATCHES "OpenGL::OpenGL")
message(FATAL_ERROR "GLES3-only code links to OpenGL!")
endif()
if(iface_libs MATCHES "EGL")
message(FATAL_ERROR "GLES3-GLX-only code links to EGL!")
endif()
endif()

View File

@@ -0,0 +1,17 @@
#ifdef _WIN32
# error "GLES2 cannot be tested on WIN32 platforms."
#endif
#ifdef __APPLE__
# error "GLES2 cannot be tested on macOS platform."
#else
# include <GLES2/gl2.h>
#endif
#include <stdio.h>
int main()
{
/* Reference a GL symbol without requiring a context at runtime. */
printf("&glGetString = %p\n", &glGetString);
return 0;
}

View File

@@ -0,0 +1,17 @@
#ifdef _WIN32
# error "GLES3 cannot be tested on WIN32 platforms."
#endif
#ifdef __APPLE__
# error "GLES3 cannot be tested on macOS platform."
#else
# include <GLES3/gl3.h>
#endif
#include <stdio.h>
int main()
{
/* Reference a GL symbol without requiring a context at runtime. */
printf("&glGetString = %p\n", &glGetString);
return 0;
}