diff options
Diffstat (limited to 'support/hololens/ServoApp/OpenGLES.cpp')
-rw-r--r-- | support/hololens/ServoApp/OpenGLES.cpp | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/support/hololens/ServoApp/OpenGLES.cpp b/support/hololens/ServoApp/OpenGLES.cpp new file mode 100644 index 00000000000..31467a4ed60 --- /dev/null +++ b/support/hololens/ServoApp/OpenGLES.cpp @@ -0,0 +1,270 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "pch.h" +#include "logs.h" +#include "OpenGLES.h" + +using namespace winrt::Windows::UI::Xaml::Controls; +using namespace winrt::Windows::Foundation; +using namespace winrt::Windows::Foundation::Collections; + +OpenGLES::OpenGLES() + : mEglConfig(nullptr), mEglDisplay(EGL_NO_DISPLAY), + mEglContext(EGL_NO_CONTEXT) { + log("OpenGLES::OpenGLES()"); + Initialize(); +} + +OpenGLES::~OpenGLES() { Cleanup(); } + +void OpenGLES::Initialize() { + const EGLint configAttributes[] = {EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, + 8, + EGL_GREEN_SIZE, + 8, + EGL_BLUE_SIZE, + 8, + EGL_ALPHA_SIZE, + 8, + EGL_DEPTH_SIZE, + 24, + EGL_STENCIL_SIZE, + 8, + EGL_NONE}; + + const EGLint contextAttributes[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE}; + + // Based on Angle MS template. + + const EGLint defaultDisplayAttributes[] = { + // These are the default display attributes, used to request ANGLE's D3D11 + // renderer. + // eglInitialize will only succeed with these attributes if the hardware + // supports D3D11 Feature Level 10_0+. + EGL_PLATFORM_ANGLE_TYPE_ANGLE, + EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + + // EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER is an optimization that + // can have large performance benefits on + // mobile devices. Its syntax is subject to change, though. Please update + // your Visual Studio templates if you + // experience compilation issues with it. + EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, + EGL_TRUE, + + // EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that + // enables ANGLE to automatically call + // the IDXGIDevice3::Trim method on behalf of the application when it gets + // suspended. + // Calling IDXGIDevice3::Trim when an application is suspended is a + // Windows Store application certification + // requirement. + EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, + EGL_TRUE, + EGL_NONE, + }; + + const EGLint fl9_3DisplayAttributes[] = { + // These can be used to request ANGLE's D3D11 renderer, with D3D11 Feature + // Level 9_3. + // These attributes are used if the call to eglInitialize fails with the + // default display attributes. + EGL_PLATFORM_ANGLE_TYPE_ANGLE, + EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, + 9, + EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, + 3, + EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, + EGL_TRUE, + EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, + EGL_TRUE, + EGL_NONE, + }; + + const EGLint warpDisplayAttributes[] = { + // These attributes can be used to request D3D11 WARP. + // They are used if eglInitialize fails with both the default display + // attributes and the 9_3 display attributes. + EGL_PLATFORM_ANGLE_TYPE_ANGLE, + EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, + EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE, + EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, + EGL_TRUE, + EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, + EGL_TRUE, + EGL_NONE, + }; + + // eglGetPlatformDisplayEXT is an alternative to eglGetDisplay. + // It allows us to pass in display attributes, used to configure D3D11. + PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = + reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>( + eglGetProcAddress("eglGetPlatformDisplayEXT")); + if (!eglGetPlatformDisplayEXT) { + throw winrt::hresult_error( + E_FAIL, L"Failed to get function eglGetPlatformDisplayEXT"); + } + + // + // To initialize the display, we make three sets of calls to + // eglGetPlatformDisplayEXT and eglInitialize, with varying parameters passed + // to eglGetPlatformDisplayEXT: 1) The first calls uses + // "defaultDisplayAttributes" as a parameter. This corresponds to D3D11 + // Feature Level 10_0+. 2) If eglInitialize fails for step 1 (e.g. because + // 10_0+ isn't supported by the default GPU), then we try again + // using "fl9_3DisplayAttributes". This corresponds to D3D11 Feature Level + // 9_3. + // 3) If eglInitialize fails for step 2 (e.g. because 9_3+ isn't supported by + // the default GPU), then we try again + // using "warpDisplayAttributes". This corresponds to D3D11 Feature Level + // 11_0 on WARP, a D3D11 software rasterizer. + // + + // This tries to initialize EGL to D3D11 Feature Level 10_0+. See above + // comment for details. + mEglDisplay = eglGetPlatformDisplayEXT( + EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes); + if (mEglDisplay == EGL_NO_DISPLAY) { + throw winrt::hresult_error(E_FAIL, L"Failed to get EGL display"); + } + + if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE) { + // This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is + // unavailable (e.g. on some mobile devices). + mEglDisplay = eglGetPlatformDisplayEXT( + EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes); + if (mEglDisplay == EGL_NO_DISPLAY) { + throw winrt::hresult_error(E_FAIL, L"Failed to get EGL display"); + } + + if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE) { + // This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is + // unavailable on the default GPU. + mEglDisplay = eglGetPlatformDisplayEXT( + EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes); + if (mEglDisplay == EGL_NO_DISPLAY) { + throw winrt::hresult_error(E_FAIL, L"Failed to get EGL display"); + } + + if (eglInitialize(mEglDisplay, NULL, NULL) == EGL_FALSE) { + // If all of the calls to eglInitialize returned EGL_FALSE then an error + // has occurred. + throw winrt::hresult_error(E_FAIL, L"Failed to initialize EGL"); + } + } + } + + EGLint numConfigs = 0; + if ((eglChooseConfig(mEglDisplay, configAttributes, &mEglConfig, 1, + &numConfigs) == EGL_FALSE) || + (numConfigs == 0)) { + throw winrt::hresult_error(E_FAIL, L"Failed to choose first EGLConfig"); + } + + mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, + contextAttributes); + if (mEglContext == EGL_NO_CONTEXT) { + throw winrt::hresult_error(E_FAIL, L"Failed to create EGL context"); + } +} + +void OpenGLES::Cleanup() { + if (mEglDisplay != EGL_NO_DISPLAY && mEglContext != EGL_NO_CONTEXT) { + eglDestroyContext(mEglDisplay, mEglContext); + mEglContext = EGL_NO_CONTEXT; + } + + if (mEglDisplay != EGL_NO_DISPLAY) { + eglTerminate(mEglDisplay); + mEglDisplay = EGL_NO_DISPLAY; + } +} + +void OpenGLES::Reset() { + Cleanup(); + Initialize(); +} + +// FIXME: simplify this. Duplicating code with CreateSurface(SwapChainPanel) +EGLSurface +OpenGLES::CreateSurface(winrt::Windows::UI::Core::CoreWindow const &cwin) { + EGLSurface surface = EGL_NO_SURFACE; + + const EGLint surfaceAttributes[] = {EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER, + EGL_TRUE, EGL_NONE}; + + PropertySet surfaceCreationProperties; + + surfaceCreationProperties.Insert(EGLNativeWindowTypeProperty, cwin); + // How to set size and or scale: + // Insert(EGLRenderSurfaceSizeProperty), + // PropertyValue::CreateSize(*renderSurfaceSize)); + // Insert(EGLRenderResolutionScaleProperty), + // PropertyValue::CreateSingle(*resolutionScale)); + + EGLNativeWindowType win = static_cast<EGLNativeWindowType>( + winrt::get_abi(surfaceCreationProperties)); + surface = + eglCreateWindowSurface(mEglDisplay, mEglConfig, win, surfaceAttributes); + + if (surface == EGL_NO_SURFACE) { + throw winrt::hresult_error(E_FAIL, L"Failed to create EGL surface"); + } + + return surface; +} + +EGLSurface OpenGLES::CreateSurface(SwapChainPanel const &panel) { + EGLSurface surface = EGL_NO_SURFACE; + + const EGLint surfaceAttributes[] = {EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER, + EGL_TRUE, EGL_NONE}; + + PropertySet surfaceCreationProperties; + + surfaceCreationProperties.Insert(EGLNativeWindowTypeProperty, panel); + // How to set size and or scale: + // Insert(EGLRenderSurfaceSizeProperty), + // PropertyValue::CreateSize(*renderSurfaceSize)); + // Insert(EGLRenderResolutionScaleProperty), + // PropertyValue::CreateSingle(*resolutionScale)); + + EGLNativeWindowType win = static_cast<EGLNativeWindowType>( + winrt::get_abi(surfaceCreationProperties)); + surface = + eglCreateWindowSurface(mEglDisplay, mEglConfig, win, surfaceAttributes); + + if (surface == EGL_NO_SURFACE) { + throw winrt::hresult_error(E_FAIL, L"Failed to create EGL surface"); + } + + return surface; +} + +void OpenGLES::GetSurfaceDimensions(const EGLSurface surface, EGLint *width, + EGLint *height) { + eglQuerySurface(mEglDisplay, surface, EGL_WIDTH, width); + eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, height); +} + +void OpenGLES::DestroySurface(const EGLSurface surface) { + if (mEglDisplay != EGL_NO_DISPLAY && surface != EGL_NO_SURFACE) { + eglDestroySurface(mEglDisplay, surface); + } +} + +void OpenGLES::MakeCurrent(const EGLSurface surface) { + if (eglMakeCurrent(mEglDisplay, surface, surface, mEglContext) == EGL_FALSE) { + throw winrt::hresult_error(E_FAIL, L"Failed to make EGLSurface current"); + } +} + +EGLBoolean OpenGLES::SwapBuffers(const EGLSurface surface) { + return (eglSwapBuffers(mEglDisplay, surface)); +} |