diff --git a/filament/backend/include/backend/platforms/PlatformEGL.h b/filament/backend/include/backend/platforms/PlatformEGL.h index 79400540063..d168fdd9ba8 100644 --- a/filament/backend/include/backend/platforms/PlatformEGL.h +++ b/filament/backend/include/backend/platforms/PlatformEGL.h @@ -42,6 +42,9 @@ class PlatformEGL : public OpenGLPlatform { void createContext(bool shared) override; void releaseContext() noexcept override; + // Return true if we're on an OpenGL platform (as opposed to OpenGL ES). false by default. + virtual bool isOpenGL() const noexcept; + protected: // -------------------------------------------------------------------------------------------- @@ -126,6 +129,7 @@ class PlatformEGL : public OpenGLPlatform { EGLSurface mCurrentDrawSurface = EGL_NO_SURFACE; EGLSurface mCurrentReadSurface = EGL_NO_SURFACE; EGLSurface mEGLDummySurface = EGL_NO_SURFACE; + // mEGLConfig is valid only if ext.egl.KHR_no_config_context is false EGLConfig mEGLConfig = EGL_NO_CONFIG_KHR; Config mContextAttribs; std::vector mAdditionalContexts; @@ -146,8 +150,8 @@ class PlatformEGL : public OpenGLPlatform { void initializeGlExtensions() noexcept; -private: - EGLConfig findSwapChainConfig(uint64_t flags) const; +protected: + EGLConfig findSwapChainConfig(uint64_t flags, bool window, bool pbuffer) const; }; } // namespace filament::backend diff --git a/filament/backend/include/backend/platforms/PlatformEGLHeadless.h b/filament/backend/include/backend/platforms/PlatformEGLHeadless.h index 13d5fa0578e..40d285b9084 100644 --- a/filament/backend/include/backend/platforms/PlatformEGLHeadless.h +++ b/filament/backend/include/backend/platforms/PlatformEGLHeadless.h @@ -30,6 +30,9 @@ class PlatformEGLHeadless : public PlatformEGL { Driver* createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept override; + +protected: + bool isOpenGL() const noexcept override; }; } // namespace filament diff --git a/filament/backend/src/opengl/platforms/PlatformEGL.cpp b/filament/backend/src/opengl/platforms/PlatformEGL.cpp index 9b3e08b20d8..76abd8d5540 100644 --- a/filament/backend/src/opengl/platforms/PlatformEGL.cpp +++ b/filament/backend/src/opengl/platforms/PlatformEGL.cpp @@ -97,13 +97,32 @@ int PlatformEGL::getOSVersion() const noexcept { return 0; } +bool PlatformEGL::isOpenGL() const noexcept { + return false; +} Driver* PlatformEGL::createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept { mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); assert_invariant(mEGLDisplay != EGL_NO_DISPLAY); EGLint major, minor; - EGLBoolean const initialized = eglInitialize(mEGLDisplay, &major, &minor); + EGLBoolean initialized = eglInitialize(mEGLDisplay, &major, &minor); + + if (!initialized) { + EGLDeviceEXT eglDevice; + EGLint numDevices; + PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT = + (PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress("eglQueryDevicesEXT"); + if (eglQueryDevicesEXT != nullptr) { + eglQueryDevicesEXT(1, &eglDevice, &numDevices); + if(auto* getPlatformDisplay = reinterpret_cast( + eglGetProcAddress("eglGetPlatformDisplay"))) { + mEGLDisplay = getPlatformDisplay(EGL_PLATFORM_DEVICE_EXT, eglDevice, 0); + initialized = eglInitialize(mEGLDisplay, &major, &minor); + } + } + } + if (UTILS_UNLIKELY(!initialized)) { slog.e << "eglInitialize failed" << io::endl; return nullptr; @@ -148,10 +167,16 @@ Driver* PlatformEGL::createDriver(void* sharedContext, const Platform::DriverCon constexpr bool requestES2Context = false; #endif - // Request a ES2 context, devices that support ES3 will return an ES3 context - Config contextAttribs = { - { EGL_CONTEXT_CLIENT_VERSION, 2 }, - }; + Config contextAttribs; + + if (isOpenGL()) { + // Request a OpenGL 4.1 context + contextAttribs[EGL_CONTEXT_MAJOR_VERSION] = 4; + contextAttribs[EGL_CONTEXT_MINOR_VERSION] = 1; + } else { + // Request a ES2 context, devices that support ES3 will return an ES3 context + contextAttribs[EGL_CONTEXT_CLIENT_VERSION] = 2; + } // FOR TESTING ONLY, enforce the ES version we're asking for. // FIXME: we should check EGL_ANGLE_create_context_backwards_compatible, however, at least @@ -172,16 +197,17 @@ Driver* PlatformEGL::createDriver(void* sharedContext, const Platform::DriverCon // config use for creating the context EGLConfig eglConfig = EGL_NO_CONFIG_KHR; - // find a config we can use if we don't have "EGL_KHR_no_config_context" and that we can use - // for the dummy pbuffer surface. - mEGLConfig = findSwapChainConfig( - SWAP_CHAIN_CONFIG_TRANSPARENT | - SWAP_CHAIN_HAS_STENCIL_BUFFER ); - if (UTILS_UNLIKELY(mEGLConfig == EGL_NO_CONFIG_KHR)) { - goto error; // error already logged - } if (UTILS_UNLIKELY(!ext.egl.KHR_no_config_context)) { + // find a config we can use if we don't have "EGL_KHR_no_config_context" and that we can use + // for the dummy pbuffer surface. + mEGLConfig = findSwapChainConfig( + SWAP_CHAIN_CONFIG_TRANSPARENT | + SWAP_CHAIN_HAS_STENCIL_BUFFER, + true, true); + if (UTILS_UNLIKELY(mEGLConfig == EGL_NO_CONFIG_KHR)) { + goto error; // error already logged + } // if we don't have the EGL_KHR_no_config_context the context must be created with // the same config as the swapchain, so we have no choice but to create a // transparent config. @@ -335,12 +361,11 @@ void PlatformEGL::terminate() noexcept { eglReleaseThread(); } -EGLConfig PlatformEGL::findSwapChainConfig(uint64_t flags) const { +EGLConfig PlatformEGL::findSwapChainConfig(uint64_t flags, bool window, bool pbuffer) const { // Find config that support ES3. EGLConfig config = EGL_NO_CONFIG_KHR; EGLint configsCount; Config configAttribs = { - { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT }, { EGL_RED_SIZE, 8 }, { EGL_GREEN_SIZE, 8 }, { EGL_BLUE_SIZE, 8 }, @@ -349,9 +374,23 @@ EGLConfig PlatformEGL::findSwapChainConfig(uint64_t flags) const { { EGL_STENCIL_SIZE, (flags & SWAP_CHAIN_HAS_STENCIL_BUFFER) ? 8 : 0 } }; + if (!ext.egl.KHR_no_config_context) { + if (isOpenGL()) { + configAttribs[EGL_RENDERABLE_TYPE] = EGL_OPENGL_BIT; + } else { + configAttribs[EGL_RENDERABLE_TYPE] = EGL_OPENGL_ES2_BIT; + if (ext.egl.KHR_create_context) { + configAttribs[EGL_RENDERABLE_TYPE] |= EGL_OPENGL_ES3_BIT_KHR; + } + } + } - if (ext.egl.KHR_create_context) { - configAttribs[EGL_RENDERABLE_TYPE] |= EGL_OPENGL_ES3_BIT_KHR; + if (window) { + configAttribs[EGL_SURFACE_TYPE] |= EGL_WINDOW_BIT; + } + + if (pbuffer) { + configAttribs[EGL_SURFACE_TYPE] |= EGL_PBUFFER_BIT; } if (ext.egl.ANDROID_recordable) { @@ -394,7 +433,7 @@ Platform::SwapChain* PlatformEGL::createSwapChain( EGLConfig config = EGL_NO_CONFIG_KHR; if (UTILS_LIKELY(ext.egl.KHR_no_config_context)) { - config = findSwapChainConfig(flags); + config = findSwapChainConfig(flags, true, false); } else { config = mEGLConfig; } @@ -430,7 +469,7 @@ Platform::SwapChain* PlatformEGL::createSwapChain( EGLConfig config = EGL_NO_CONFIG_KHR; if (UTILS_LIKELY(ext.egl.KHR_no_config_context)) { - config = findSwapChainConfig(flags); + config = findSwapChainConfig(flags, false, true); } else { config = mEGLConfig; } diff --git a/filament/backend/src/opengl/platforms/PlatformEGLHeadless.cpp b/filament/backend/src/opengl/platforms/PlatformEGLHeadless.cpp index befebaa62da..b3c53716bd4 100644 --- a/filament/backend/src/opengl/platforms/PlatformEGLHeadless.cpp +++ b/filament/backend/src/opengl/platforms/PlatformEGLHeadless.cpp @@ -30,21 +30,14 @@ using namespace utils; namespace filament { using namespace backend; -namespace glext { -UTILS_PRIVATE PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR = {}; -UTILS_PRIVATE PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = {}; -UTILS_PRIVATE PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR = {}; -UTILS_PRIVATE PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = {}; -UTILS_PRIVATE PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = {}; -} -using namespace glext; - -// --------------------------------------------------------------------------------------------- - PlatformEGLHeadless::PlatformEGLHeadless() noexcept : PlatformEGL() { } +bool PlatformEGLHeadless::isOpenGL() const noexcept { + return true; +} + backend::Driver* PlatformEGLHeadless::createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept { EGLBoolean bindAPI = eglBindAPI(EGL_OPENGL_API); @@ -58,166 +51,7 @@ backend::Driver* PlatformEGLHeadless::createDriver(void* sharedContext, return nullptr; } - // Copied from the base class and modified slightly. Should be cleaned up/improved later. - mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - assert_invariant(mEGLDisplay != EGL_NO_DISPLAY); - - EGLint major, minor; - EGLBoolean initialized = eglInitialize(mEGLDisplay, &major, &minor); - - if (!initialized) { - EGLDeviceEXT eglDevice; - EGLint numDevices; - - PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT = - (PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress("eglQueryDevicesEXT"); - if (eglQueryDevicesEXT != NULL) { - eglQueryDevicesEXT(1, &eglDevice, &numDevices); - if(auto* getPlatformDisplay = reinterpret_cast( - eglGetProcAddress("eglGetPlatformDisplay"))) { - mEGLDisplay = getPlatformDisplay(EGL_PLATFORM_DEVICE_EXT, eglDevice, 0); - initialized = eglInitialize(mEGLDisplay, &major, &minor); - } - } - } - - if (UTILS_UNLIKELY(!initialized)) { - slog.e << "eglInitialize failed" << io::endl; - return nullptr; - } - - auto extensions = GLUtils::split(eglQueryString(mEGLDisplay, EGL_EXTENSIONS)); - - eglCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC) eglGetProcAddress("eglCreateSyncKHR"); - eglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC) eglGetProcAddress("eglDestroySyncKHR"); - eglClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC) eglGetProcAddress("eglClientWaitSyncKHR"); - - eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR"); - eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR"); - - EGLint configsCount; - - EGLint configAttribs[] = { - EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, 0, - EGL_DEPTH_SIZE, 32, - EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, - EGL_NONE - }; - - EGLint contextAttribs[] = { - EGL_CONTEXT_CLIENT_VERSION, 3, - EGL_NONE, EGL_NONE, // reserved for EGL_CONTEXT_OPENGL_NO_ERROR_KHR below - EGL_NONE - }; - - EGLint pbufferAttribs[] = { - EGL_WIDTH, 1, - EGL_HEIGHT, 1, - EGL_NONE - }; - -#ifdef NDEBUG - // When we don't have a shared context and we're in release mode, we always activate the - // EGL_KHR_create_context_no_error extension. - if (!sharedContext && extensions.has("EGL_KHR_create_context_no_error")) { - contextAttribs[2] = EGL_CONTEXT_OPENGL_NO_ERROR_KHR; - contextAttribs[3] = EGL_TRUE; - } -#endif - - EGLConfig eglConfig = nullptr; - - // find an opaque config - if (!eglChooseConfig(mEGLDisplay, configAttribs, &mEGLConfig, 1, &configsCount)) { - logEglError("eglChooseConfig"); - goto error; - } - - // fallback to a 24-bit depth buffer - if (configsCount == 0) { - configAttribs[10] = EGL_DEPTH_SIZE; - configAttribs[11] = 24; - - if (!eglChooseConfig(mEGLDisplay, configAttribs, &mEGLConfig, 1, &configsCount)) { - logEglError("eglChooseConfig"); - goto error; - } - } - - // find a transparent config - configAttribs[8] = EGL_ALPHA_SIZE; - configAttribs[9] = 8; - if (!eglChooseConfig(mEGLDisplay, configAttribs, &mEGLTransparentConfig, 1, &configsCount) || - (configAttribs[13] == EGL_DONT_CARE && configsCount == 0)) { - logEglError("eglChooseConfig"); - goto error; - } - - if (!extensions.has("EGL_KHR_no_config_context")) { - // if we have the EGL_KHR_no_config_context, we don't need to worry about the config - // when creating the context, otherwise, we must always pick a transparent config. - eglConfig = mEGLConfig = mEGLTransparentConfig; - } - - // the pbuffer dummy surface is always created with a transparent surface because - // either we have EGL_KHR_no_config_context and it doesn't matter, or we don't and - // we must use a transparent surface - mEGLDummySurface = eglCreatePbufferSurface(mEGLDisplay, mEGLTransparentConfig, pbufferAttribs); - if (mEGLDummySurface == EGL_NO_SURFACE) { - logEglError("eglCreatePbufferSurface"); - goto error; - } - - mEGLContext = eglCreateContext(mEGLDisplay, eglConfig, (EGLContext)sharedContext, contextAttribs); - if (mEGLContext == EGL_NO_CONTEXT && sharedContext && - extensions.has("EGL_KHR_create_context_no_error")) { - // context creation could fail because of EGL_CONTEXT_OPENGL_NO_ERROR_KHR - // not matching the sharedContext. Try with it. - contextAttribs[2] = EGL_CONTEXT_OPENGL_NO_ERROR_KHR; - contextAttribs[3] = EGL_TRUE; - mEGLContext = eglCreateContext(mEGLDisplay, eglConfig, (EGLContext)sharedContext, contextAttribs); - } - if (UTILS_UNLIKELY(mEGLContext == EGL_NO_CONTEXT)) { - // eglCreateContext failed - logEglError("eglCreateContext"); - goto error; - } - - if (!makeCurrent(mEGLDummySurface, mEGLDummySurface)) { - // eglMakeCurrent failed - logEglError("eglMakeCurrent"); - goto error; - } - - initializeGlExtensions(); - - clearGlError(); - - // success!! - return OpenGLPlatform::createDefaultDriver(this, sharedContext, driverConfig); - -error: - // if we're here, we've failed - if (mEGLDummySurface) { - eglDestroySurface(mEGLDisplay, mEGLDummySurface); - } - if (mEGLContext) { - eglDestroyContext(mEGLDisplay, mEGLContext); - } - - mEGLDummySurface = EGL_NO_SURFACE; - mEGLContext = EGL_NO_CONTEXT; - - eglTerminate(mEGLDisplay); - eglReleaseThread(); - - return nullptr; + return PlatformEGL::createDriver(sharedContext, driverConfig); } } // namespace filament - -// ---------------------------------------------------------------------------------------------