| // Copyright 2022 The Dawn & Tint Authors |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are met: |
| // |
| // 1. Redistributions of source code must retain the above copyright notice, this |
| // list of conditions and the following disclaimer. |
| // |
| // 2. Redistributions in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // |
| // 3. Neither the name of the copyright holder nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #include "dawn/native/opengl/EGLFunctions.h" |
| |
| #include <string> |
| #include <tuple> |
| |
| #include "absl/container/flat_hash_set.h" |
| #include "absl/strings/str_split.h" |
| #include "dawn/native/opengl/UtilsEGL.h" |
| |
| namespace dawn::native::opengl { |
| |
| namespace { |
| |
| using VersionPromoted = std::tuple<uint32_t, uint32_t>; |
| constexpr VersionPromoted EGL1_5 = {1, 5}; |
| constexpr VersionPromoted NeverPromoted = {100000, 0}; |
| |
| // EGL_EXT_client_extensions which was promoted to 1.5 adds the concept of client extensions that |
| // can be queried with eglGetString(EGL_NO_DISPLAY, EGL_EXTENSIONS). These can be loaded during |
| // LoadClientProcs instead of LoadDisplayProcs. |
| enum class ExtType { |
| Display, |
| Client, |
| }; |
| |
| struct ExtensionInfo { |
| EGLExt index; |
| const char* name; |
| VersionPromoted versionPromoted; |
| ExtType type; |
| }; |
| |
| static constexpr size_t kExtensionCount = static_cast<size_t>(EGLExt::EnumCount); |
| static constexpr std::array<ExtensionInfo, kExtensionCount> kExtensionInfos{{ |
| // |
| {EGLExt::ClientExtensions, "EGL_EXT_client_extensions", EGL1_5, ExtType::Client}, |
| {EGLExt::PlatformBase, "EGL_EXT_platform_base", EGL1_5, ExtType::Client}, |
| // TODO(344606402): Mark as promoted again when ANGLE supports EGL_SYNC_FENCE in EGL 1.5 |
| {EGLExt::FenceSync, "EGL_KHR_fence_sync", NeverPromoted, ExtType::Display}, |
| {EGLExt::CLEvent2, "EGL_KHR_cl_event2", EGL1_5, ExtType::Display}, |
| {EGLExt::WaitSync, "EGL_KHR_wait_sync", EGL1_5, ExtType::Display}, |
| {EGLExt::ImageBase, "EGL_KHR_image_base", EGL1_5, ExtType::Display}, |
| {EGLExt::GLTexture2DImage, "EGL_KHR_gl_texture_2D_image", EGL1_5, ExtType::Display}, |
| {EGLExt::GLTexture3DImage, "EGL_KHR_gl_texture_3D_image", EGL1_5, ExtType::Display}, |
| {EGLExt::GLTextureCubemapImage, "EGL_KHR_gl_texture_cubemap_image", EGL1_5, ExtType::Display}, |
| {EGLExt::GLRenderBufferImage, "EGL_KHR_gl_renderbuffer_image", EGL1_5, ExtType::Display}, |
| {EGLExt::CreateContext, "EGL_KHR_create_context", EGL1_5, ExtType::Display}, |
| {EGLExt::CreateContextRobustness, "EGL_EXT_create_context_robustness", EGL1_5, |
| ExtType::Display}, |
| {EGLExt::GetAllProcAddresses, "EGL_KHR_get_all_proc_addresses", EGL1_5, ExtType::Display}, |
| {EGLExt::ClientGetAllProcAddresses, "EGL_KHR_client_get_all_proc_addresses", EGL1_5, |
| ExtType::Client}, |
| {EGLExt::GLColorSpace, "EGL_KHR_gl_colorspace", EGL1_5, ExtType::Display}, |
| {EGLExt::SurfacelessContext, "EGL_KHR_surfaceless_context", EGL1_5, ExtType::Display}, |
| |
| {EGLExt::DisplayTextureShareGroup, "EGL_ANGLE_display_texture_share_group", NeverPromoted, |
| ExtType::Display}, |
| {EGLExt::ReusableSync, "EGL_KHR_reusable_sync", NeverPromoted, ExtType::Display}, |
| {EGLExt::NoConfigContext, "EGL_KHR_no_config_context", NeverPromoted, ExtType::Display}, |
| {EGLExt::PixelFormatFloat, "EGL_EXT_pixel_format_float", NeverPromoted, ExtType::Display}, |
| {EGLExt::GLColorspace, "EGL_KHR_gl_colorspace", NeverPromoted, ExtType::Display}, |
| // |
| }}; |
| |
| } // anonymous namespace |
| |
| #define GET_PROC_WITH_NAME(member, name) \ |
| do { \ |
| member = reinterpret_cast<decltype(member)>(GetProcAddress(name)); \ |
| if (member == nullptr) { \ |
| return DAWN_INTERNAL_ERROR(std::string("Couldn't get proc ") + name); \ |
| } \ |
| } while (0) |
| |
| #define GET_PROC(name) GET_PROC_WITH_NAME(name, "egl" #name) |
| |
| MaybeError EGLFunctions::LoadClientProcs(EGLGetProcProc getProc) { |
| // Load EGL 1.0 |
| GetProcAddress = getProc; |
| |
| GET_PROC(ChooseConfig); |
| GET_PROC(CopyBuffers); |
| GET_PROC(CreateContext); |
| GET_PROC(CreatePbufferSurface); |
| GET_PROC(CreatePixmapSurface); |
| GET_PROC(CreateWindowSurface); |
| GET_PROC(DestroyContext); |
| GET_PROC(DestroySurface); |
| GET_PROC(GetConfigAttrib); |
| GET_PROC(GetConfigs); |
| GET_PROC(GetCurrentDisplay); |
| GET_PROC(GetCurrentSurface); |
| GET_PROC(GetDisplay); |
| GET_PROC(GetError); |
| GET_PROC(Initialize); |
| GET_PROC(MakeCurrent); |
| GET_PROC(QueryContext); |
| GET_PROC(QueryString); |
| GET_PROC(QuerySurface); |
| GET_PROC(SwapBuffers); |
| GET_PROC(Terminate); |
| GET_PROC(WaitGL); |
| GET_PROC(WaitNative); |
| |
| // Get the EGL client extensions, if they are supported. |
| const char* rawExtensions = QueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); |
| if (rawExtensions == nullptr) { |
| return {}; |
| } |
| absl::flat_hash_set<std::string_view> extensions = absl::StrSplit(rawExtensions, " "); |
| |
| for (const ExtensionInfo& ext : kExtensionInfos) { |
| if (extensions.contains(ext.name) && ext.type == ExtType::Client) { |
| mExtensions.set(ext.index); |
| } |
| } |
| |
| return LoadClientExtensions(); |
| } |
| |
| MaybeError EGLFunctions::LoadDisplayProcs(EGLDisplay display) { |
| DAWN_ASSERT(GetProcAddress != nullptr); |
| |
| // Get the EGL version and extensions. |
| { |
| EGLint major, minor; |
| DAWN_TRY(CheckEGL(*this, Initialize(display, &major, &minor), "eglInitialize")); |
| DAWN_INVALID_IF(major != 1, "EGL version (%u) is not 1.", major); |
| mMajorVersion = major; |
| mMinorVersion = minor; |
| } |
| { |
| const char* rawExtensions = QueryString(display, EGL_EXTENSIONS); |
| absl::flat_hash_set<std::string_view> extensions = absl::StrSplit(rawExtensions, " "); |
| |
| for (const ExtensionInfo& ext : kExtensionInfos) { |
| if (std::tie(mMajorVersion, mMinorVersion) >= ext.versionPromoted || |
| extensions.contains(ext.name)) { |
| mExtensions.set(ext.index); |
| } |
| } |
| } |
| |
| // EGL 1.1 |
| if (mMinorVersion >= 1) { |
| GET_PROC(BindTexImage); |
| GET_PROC(ReleaseTexImage); |
| GET_PROC(SurfaceAttrib); |
| GET_PROC(SwapInterval); |
| } |
| |
| // EGL 1.2 |
| if (mMinorVersion >= 2) { |
| GET_PROC(BindAPI); |
| GET_PROC(QueryAPI); |
| GET_PROC(CreatePbufferFromClientBuffer); |
| GET_PROC(ReleaseThread); |
| GET_PROC(WaitClient); |
| } |
| |
| // EGL 1.3 (no new procs) |
| |
| // EGL 1.4 |
| if (mMinorVersion >= 4) { |
| GET_PROC(GetCurrentContext); |
| } |
| |
| // EGL 1.5 |
| if (mMinorVersion >= 5) { |
| GET_PROC(CreateSync); |
| GET_PROC(DestroySync); |
| GET_PROC(ClientWaitSync); |
| GET_PROC(GetSyncAttrib); |
| GET_PROC(CreateImage); |
| GET_PROC(DestroyImage); |
| GET_PROC(GetPlatformDisplay); |
| GET_PROC(CreatePlatformWindowSurface); |
| GET_PROC(CreatePlatformPixmapSurface); |
| GET_PROC(WaitSync); |
| } else { |
| // Load display extensions that would otherwise be promoted to EGL 1.5. |
| |
| if (HasExt(EGLExt::FenceSync)) { |
| GET_PROC_WITH_NAME(ClientWaitSync, "eglClientWaitSyncKHR"); |
| GET_PROC_WITH_NAME(CreateSync, "eglCreateSyncKHR"); |
| GET_PROC_WITH_NAME(DestroySync, "eglDestroySyncKHR"); |
| GET_PROC_WITH_NAME(ClientWaitSync, "eglClientWaitSyncKHR"); |
| } |
| |
| if (HasExt(EGLExt::ImageBase)) { |
| GET_PROC_WITH_NAME(CreateImage, "eglCreateImageKHR"); |
| GET_PROC_WITH_NAME(DestroyImage, "eglDestroyImageKHR"); |
| } |
| |
| if (HasExt(EGLExt::WaitSync)) { |
| GET_PROC_WITH_NAME(WaitSync, "eglWaitSyncKHR"); |
| } |
| } |
| |
| // Load client extensions if they haven't been already. |
| if (!HasExt(EGLExt::ClientExtensions)) { |
| DAWN_TRY(LoadClientExtensions()); |
| } |
| |
| // Other extensions |
| |
| if (HasExt(EGLExt::ReusableSync)) { |
| GET_PROC_WITH_NAME(SignalSync, "eglSignalSyncKHR"); |
| } |
| |
| return {}; |
| } |
| |
| uint32_t EGLFunctions::GetMajorVersion() const { |
| return mMajorVersion; |
| } |
| |
| uint32_t EGLFunctions::GetMinorVersion() const { |
| return mMinorVersion; |
| } |
| |
| bool EGLFunctions::HasExt(EGLExt extension) const { |
| return mExtensions[extension]; |
| } |
| |
| MaybeError EGLFunctions::LoadClientExtensions() { |
| if (HasExt(EGLExt::PlatformBase) && mMinorVersion < 5) { |
| GET_PROC_WITH_NAME(GetPlatformDisplay, "eglGetPlatformDisplayEXT"); |
| GET_PROC_WITH_NAME(CreatePlatformWindowSurface, "eglCreatePlatformWindowSurfaceEXT"); |
| GET_PROC_WITH_NAME(CreatePlatformPixmapSurface, "eglCreatePlatformPixmapSurfaceEXT"); |
| } |
| |
| return {}; |
| } |
| |
| } // namespace dawn::native::opengl |