From 8cea106b30b65bef5876a3c37f76c6f16a3aad77 Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Wed, 25 Oct 2023 13:11:58 +1100 Subject: [PATCH] refactor Windows classes to separate EGL/WGL/Backing Window --- windows/CMakeLists.txt | 22 +- windows/PlatformANGLE.cpp | 481 ---------------------------- windows/PlatformANGLE.h | 116 ------- windows/backing_window.cpp | 250 +++++++++++++++ windows/backing_window.h | 23 ++ windows/egl_context.cpp | 170 ++++++++++ windows/egl_context.h | 28 ++ windows/flutter_angle_texture.h | 6 +- windows/flutter_render_context.h | 51 +++ windows/flutter_texture_buffer.h | 18 ++ windows/opengl_texture_buffer.cpp | 8 +- windows/opengl_texture_buffer.h | 10 +- windows/polyvox_filament_plugin.cpp | 439 +++++-------------------- windows/polyvox_filament_plugin.h | 32 +- windows/utils.cc | 130 ++++++++ windows/utils.h | 20 ++ windows/wgl_context.cpp | 139 ++++++++ windows/wgl_context.h | 25 ++ 18 files changed, 972 insertions(+), 996 deletions(-) delete mode 100644 windows/PlatformANGLE.cpp delete mode 100644 windows/PlatformANGLE.h create mode 100644 windows/backing_window.cpp create mode 100644 windows/backing_window.h create mode 100644 windows/egl_context.cpp create mode 100644 windows/egl_context.h create mode 100644 windows/flutter_render_context.h create mode 100644 windows/flutter_texture_buffer.h create mode 100644 windows/utils.cc create mode 100644 windows/utils.h create mode 100644 windows/wgl_context.cpp create mode 100644 windows/wgl_context.h diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt index 9fff27a6..64c81fbe 100644 --- a/windows/CMakeLists.txt +++ b/windows/CMakeLists.txt @@ -22,16 +22,22 @@ list(APPEND PLUGIN_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/../ios/src/camutils/Bookmark.cpp" ) -set(USE_ANGLE TRUE) +set(USE_ANGLE FALSE) + +if(!USE_ANGLE) +set(WGL_USE_BACKING_WINDOW TRUE) +endif() if(USE_ANGLE) add_compile_definitions(USE_ANGLE) - list(APPEND PLUGIN_SOURCES - # "PlatformAngle.cpp" - "flutter_angle_texture.cpp" - ) + list(APPEND PLUGIN_SOURCES "flutter_angle_texture.cpp" "egl_context.cpp" ) else() - list(APPEND PLUGIN_SOURCES "opengl_texture_buffer.cpp") + list(APPEND PLUGIN_SOURCES "wgl_context.cpp") + if(WGL_USE_BACKING_WINDOW) + list(APPEND PLUGIN_SOURCES "utils.cc" "backing_window.cpp") + else() + list(APPEND PLUGIN_SOURCES "opengl_texture_buffer.cpp") + endif() endif() # Define the plugin library target. Its name must not be changed (see comment @@ -74,9 +80,9 @@ if(USE_ANGLE) else() list(APPEND GL_LIBS bluegl - # bluevk - # vkshaders opengl32 + dwmapi + comctl32 ) set(ANGLE_OR_OPENGL_DIR opengl) add_library(bluegl SHARED IMPORTED) diff --git a/windows/PlatformANGLE.cpp b/windows/PlatformANGLE.cpp deleted file mode 100644 index 128b3761..00000000 --- a/windows/PlatformANGLE.cpp +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Copyright (C) 2022 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. - */ - -#pragma comment(lib, "dxgi.lib") -#pragma comment(lib, "d3d11.lib") - -#include "PlatformANGLE.h" - -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include - -using namespace utils; - -// PROC wglGetProcAddress(LPCSTR name) { -// // PANIC -// return nullptr; -// } - -namespace filament::backend::GLUtils { - class unordered_string_set : public std::unordered_set { - public: - bool has(std::string_view str) const noexcept; - }; - - unordered_string_set split(const char* extensions) noexcept; -} - -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; - - -void PlatformANGLE::logEglError(const char* name) noexcept { - const char* err; - switch (eglGetError()) { - case EGL_NOT_INITIALIZED: err = "EGL_NOT_INITIALIZED"; break; - case EGL_BAD_ACCESS: err = "EGL_BAD_ACCESS"; break; - case EGL_BAD_ALLOC: err = "EGL_BAD_ALLOC"; break; - case EGL_BAD_ATTRIBUTE: err = "EGL_BAD_ATTRIBUTE"; break; - case EGL_BAD_CONTEXT: err = "EGL_BAD_CONTEXT"; break; - case EGL_BAD_CONFIG: err = "EGL_BAD_CONFIG"; break; - case EGL_BAD_CURRENT_SURFACE: err = "EGL_BAD_CURRENT_SURFACE";break; - case EGL_BAD_DISPLAY: err = "EGL_BAD_DISPLAY"; break; - case EGL_BAD_SURFACE: err = "EGL_BAD_SURFACE"; break; - case EGL_BAD_MATCH: err = "EGL_BAD_MATCH"; break; - case EGL_BAD_PARAMETER: err = "EGL_BAD_PARAMETER"; break; - case EGL_BAD_NATIVE_PIXMAP: err = "EGL_BAD_NATIVE_PIXMAP"; break; - case EGL_BAD_NATIVE_WINDOW: err = "EGL_BAD_NATIVE_WINDOW"; break; - case EGL_CONTEXT_LOST: err = "EGL_CONTEXT_LOST"; break; - default: err = "unknown"; break; - } - slog.e << name << " failed with " << err << io::endl; -} - -void PlatformANGLE::clearGlError() noexcept { - // clear GL error that may have been set by previous calls - GLenum const error = glGetError(); - if (error != GL_NO_ERROR) { - slog.w << "Ignoring pending GL error " << io::hex << error << io::endl; - } -} - - -int PlatformANGLE::getOSVersion() const noexcept { - return 0; -} - -// --------------------------------------------------------------------------------------------- - -PlatformANGLE::PlatformANGLE( - HANDLE d3dTextureHandle, - uint32_t width, - uint32_t height -) noexcept : mD3DTextureHandle(d3dTextureHandle), mWidth(width), mHeight(height), OpenGLPlatform() { - -} - -PlatformANGLE::~PlatformANGLE() { - -} - -backend::Driver* PlatformANGLE::createDriver(void* sharedContext, - const Platform::DriverConfig& driverConfig) noexcept { - - if (UTILS_UNLIKELY(sharedContext)) { - slog.e << "Cannot provide shared context with PlatformANGLE" << io::endl; - return nullptr; - } - - EGLBoolean bindAPI = eglBindAPI(EGL_OPENGL_ES_API); - if (UTILS_UNLIKELY(!bindAPI)) { - slog.e << "eglBindAPI EGL_OPENGL_ES_API failed" << io::endl; - 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 = false; // = eglInitialize(mEGLDisplay, &major, &minor); - - // if (!initialized) { - EGLDeviceEXT eglDevice; - EGLint numDevices; - - if(auto* getPlatformDisplay = reinterpret_cast( - eglGetProcAddress("eglGetPlatformDisplayEXT"))) { - - EGLint kD3D11DisplayAttributes[] = { - EGL_PLATFORM_ANGLE_TYPE_ANGLE, - EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, - EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, - EGL_TRUE, - EGL_NONE, - }; - mEGLDisplay = getPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, kD3D11DisplayAttributes); - initialized = eglInitialize(mEGLDisplay, &major, &minor); - } - - std::cout << "Got major " << major << " and minor " << minor << std::endl; - - if (UTILS_UNLIKELY(!initialized)) { - slog.e << "eglInitialize failed" << io::endl; - return nullptr; - } - - importGLESExtensionsEntryPoints(); - - 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 configAttribs[] = { - EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 8, EGL_STENCIL_SIZE, 8, - 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, mWidth, EGL_HEIGHT, mHeight, - EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, - EGL_NONE, - }; - - EGLConfig eglConfig = nullptr; - EGLConfig mEGLTransparentConfig = nullptr; - - char const* version; - - // 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; - } - - mEGLContext = eglCreateContext(mEGLDisplay, eglConfig, EGL_NO_CONTEXT, contextAttribs); - - if (UTILS_UNLIKELY(mEGLContext == EGL_NO_CONTEXT)) { - // eglCreateContext failed - logEglError("eglCreateContext"); - goto error; - } - - mCurrentDrawSurface = mCurrentReadSurface = eglCreatePbufferFromClientBuffer( - mEGLDisplay, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, mD3DTextureHandle, - mEGLTransparentConfig, pbufferAttribs); - - if (mCurrentDrawSurface == EGL_NO_SURFACE) { - logEglError("eglCreatePbufferSurface"); - goto error; - } - - if (!eglMakeCurrent(mEGLDisplay, mCurrentDrawSurface, mCurrentDrawSurface, mEGLContext)) { - // eglMakeCurrent failed - logEglError("eglMakeCurrent"); - goto error; - } - - glGenTextures(1, &glTextureId); - - if (glTextureId == 0) { - std::cout << "Failed to generate OpenGL texture for ANGLE, OpenGL err was %d", - glGetError(); - return nullptr; - } - - glBindTexture(GL_TEXTURE_2D, glTextureId); - eglBindTexImage(mEGLDisplay, mCurrentReadSurface, EGL_BACK_BUFFER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - initializeGlExtensions(); - - clearGlError(); - - version = (char const*)glGetString(GL_VERSION); - std::cout << "Got version " << version << std::endl; - glGetIntegerv(GL_MAJOR_VERSION, &major); - glGetIntegerv(GL_MINOR_VERSION, &minor); - - // success!! - return OpenGLPlatform::createDefaultDriver(this, sharedContext, driverConfig); - -error: - // if we're here, we've failed - if (mCurrentDrawSurface) { - eglDestroySurface(mEGLDisplay, mCurrentDrawSurface); - } - if (mEGLContext) { - eglDestroyContext(mEGLDisplay, mEGLContext); - } - - mCurrentDrawSurface = mCurrentReadSurface = EGL_NO_SURFACE; - mEGLContext = EGL_NO_CONTEXT; - - eglTerminate(mEGLDisplay); - eglReleaseThread(); - - return nullptr; -} - - -EGLBoolean PlatformANGLE::makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) noexcept { - // if (UTILS_UNLIKELY((drawSurface != mCurrentDrawSurface || readSurface != mCurrentReadSurface))) { - mCurrentDrawSurface = drawSurface; - mCurrentReadSurface = readSurface; - return eglMakeCurrent(mEGLDisplay, drawSurface, readSurface, mEGLContext); - // } - return EGL_TRUE; -} - -void PlatformANGLE::terminate() noexcept { - eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglDestroyContext(mEGLDisplay, mEGLContext); - eglTerminate(mEGLDisplay); - eglReleaseThread(); -} - -EGLConfig PlatformANGLE::findSwapChainConfig(uint64_t flags) const { - EGLConfig config = EGL_NO_CONFIG_KHR; - EGLint configsCount; - EGLint configAttribs[] = { - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, (flags & SWAP_CHAIN_CONFIG_TRANSPARENT) ? 8 : 0, - EGL_DEPTH_SIZE, 24, - EGL_RECORDABLE_ANDROID, 1, - EGL_NONE - }; - - if (UTILS_UNLIKELY( - !eglChooseConfig(mEGLDisplay, configAttribs, &config, 1, &configsCount))) { - logEglError("eglChooseConfig"); - return EGL_NO_CONFIG_KHR; - } - - if (UTILS_UNLIKELY(configsCount == 0)) { - // warn and retry without EGL_RECORDABLE_ANDROID - logEglError( - "eglChooseConfig(..., EGL_RECORDABLE_ANDROID) failed. Continuing without it."); - configAttribs[12] = EGL_RECORDABLE_ANDROID; - configAttribs[13] = EGL_DONT_CARE; - if (UTILS_UNLIKELY( - !eglChooseConfig(mEGLDisplay, configAttribs, &config, 1, &configsCount) || - configsCount == 0)) { - logEglError("eglChooseConfig"); - return EGL_NO_CONFIG_KHR; - } - } - return config; -} - -bool PlatformANGLE::isSRGBSwapChainSupported() const noexcept { - return ext.egl.KHR_gl_colorspace; -} - -void PlatformANGLE::destroySwapChain(Platform::SwapChain* swapChain) noexcept { - EGLSurface sur = (EGLSurface) swapChain; - if (sur != EGL_NO_SURFACE) { - makeCurrent(EGL_NO_SURFACE, EGL_NO_SURFACE); - eglDestroySurface(mEGLDisplay, sur); - } -} - -void PlatformANGLE::makeCurrent(Platform::SwapChain* drawSwapChain, - Platform::SwapChain* readSwapChain) noexcept { - EGLSurface drawSur = (EGLSurface) drawSwapChain; - EGLSurface readSur = (EGLSurface) readSwapChain; - if (drawSur != EGL_NO_SURFACE || readSur != EGL_NO_SURFACE) { - makeCurrent(drawSur, readSur); - } -} - using namespace std::chrono_literals; - -void PlatformANGLE::commit(Platform::SwapChain* swapChain) noexcept { - EGLSurface sur = (EGLSurface) swapChain; - if (sur != EGL_NO_SURFACE) { - eglSwapBuffers(mEGLDisplay, sur); - } -} - -bool PlatformANGLE::canCreateFence() noexcept { - return true; -} - -Platform::Fence* PlatformANGLE::createFence() noexcept { - Fence* f = nullptr; -#ifdef EGL_KHR_reusable_sync - f = (Fence*) eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr); -#endif - return f; -} - -void PlatformANGLE::destroyFence(Platform::Fence* fence) noexcept { -#ifdef EGL_KHR_reusable_sync - EGLSyncKHR sync = (EGLSyncKHR) fence; - if (sync != EGL_NO_SYNC_KHR) { - eglDestroySyncKHR(mEGLDisplay, sync); - } -#endif -} - -FenceStatus PlatformANGLE::waitFence( - Platform::Fence* fence, uint64_t timeout) noexcept { -#ifdef EGL_KHR_reusable_sync - EGLSyncKHR sync = (EGLSyncKHR) fence; - if (sync != EGL_NO_SYNC_KHR) { - EGLint status = eglClientWaitSyncKHR(mEGLDisplay, sync, 0, (EGLTimeKHR)timeout); - if (status == EGL_CONDITION_SATISFIED_KHR) { - return FenceStatus::CONDITION_SATISFIED; - } - if (status == EGL_TIMEOUT_EXPIRED_KHR) { - return FenceStatus::TIMEOUT_EXPIRED; - } - } -#endif - return FenceStatus::ERROR; -} - -#define GL_TEXTURE_EXTERNAL_OES 0x8D65 - -OpenGLPlatform::ExternalTexture* PlatformANGLE::createExternalImageTexture() noexcept { - ExternalTexture* outTexture = new ExternalTexture{}; - // glGenTextures(1, &outTexture->id); - // if (UTILS_LIKELY(ext.gl.OES_EGL_image_external_essl3)) { - // outTexture->target = GL_TEXTURE_EXTERNAL_OES; - // } else { - // // if texture external is not supported, revert to texture 2d - // outTexture->target = GL_TEXTURE_2D; - // } - return outTexture; -} - -void PlatformANGLE::destroyExternalImage(ExternalTexture* texture) noexcept { - // glDeleteTextures(1, &texture->id); - delete texture; -} - -bool PlatformANGLE::setExternalImage(void* externalImage, - UTILS_UNUSED_IN_RELEASE ExternalTexture* texture) noexcept { - if (UTILS_LIKELY(ext.gl.OES_EGL_image_external_essl3)) { - assert_invariant(texture->target == GL_TEXTURE_EXTERNAL_OES); - // the texture is guaranteed to be bound here. -// #ifdef GL_OES_EGL_image -// glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, -// static_cast(externalImage)); -// #endif - } - return true; -} - -void PlatformANGLE::initializeGlExtensions() noexcept { - GLUtils::unordered_string_set glExtensions; - GLint n; - glGetIntegerv(GL_NUM_EXTENSIONS, &n); - for (GLint i = 0; i < n; ++i) { - const char* const extension = (const char*)glGetStringi(GL_EXTENSIONS, (GLuint)i); - glExtensions.insert(extension); - } - ext.gl.OES_EGL_image_external_essl3 = glExtensions.has("GL_OES_EGL_image_external_essl3"); -} - -Platform::SwapChain* PlatformANGLE::createSwapChain(void* nativewindow, uint64_t flags) noexcept { - return (Platform::SwapChain*) mCurrentDrawSurface; -} - -Platform::SwapChain* PlatformANGLE::createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept { - return (Platform::SwapChain*) mCurrentDrawSurface; -} - - - -} // namespace filament - -// --------------------------------------------------------------------------------------------- diff --git a/windows/PlatformANGLE.h b/windows/PlatformANGLE.h deleted file mode 100644 index dc6a4f61..00000000 --- a/windows/PlatformANGLE.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef _POLYVOX_FILAMENT_PLATFORM_ANGLE_H -#define _POLYVOX_FILAMENT_PLATFORM_ANGLE_H - -#include -#include - -#include -#include - - -#include -#include -#include - -#include "backend/DriverEnums.h" -#include "backend/platforms/OpenGLPlatform.h" -#include "backend/Platform.h" - -#define FILAMENT_USE_EXTERNAL_GLES3 - -#include "gl_headers.h" - -namespace filament::backend { - -/** - * A concrete implementation of OpenGLPlatform that supports EGL with a headless swapchain and external D3D texture support. - */ -class PlatformANGLE : public OpenGLPlatform { -public: - PlatformANGLE(HANDLE d3dTextureHandle, uint32_t width, uint32_t height) noexcept; - ~PlatformANGLE(); - - Driver* createDriver(void* sharedContext, - const Platform::DriverConfig& driverConfig) noexcept override; - - Platform::SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override; - - Platform::SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override; - - GLuint glTextureId = 0; - EGLSurface mCurrentDrawSurface = EGL_NO_SURFACE; - EGLSurface mCurrentReadSurface = EGL_NO_SURFACE; - EGLDisplay mEGLDisplay = EGL_NO_DISPLAY; - EGLContext mEGLContext = EGL_NO_CONTEXT; - EGLConfig mEGLConfig = EGL_NO_CONFIG_KHR; -private: - /** - * This returns zero. This method can be overridden to return something more useful. - * @return zero - */ - int getOSVersion() const noexcept override; - - // -------------------------------------------------------------------------------------------- - // OpenGLPlatform Interface - - void terminate() noexcept override; - - bool isSRGBSwapChainSupported() const noexcept override; - void destroySwapChain(SwapChain* swapChain) noexcept override; - void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override; - void commit(SwapChain* swapChain) noexcept override; - - bool canCreateFence() noexcept override; - Fence* createFence() noexcept override; - void destroyFence(Fence* fence) noexcept override; - FenceStatus waitFence(Fence* fence, uint64_t timeout) noexcept override; - - OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override; - void destroyExternalImage(ExternalTexture* texture) noexcept override; - bool setExternalImage(void* externalImage, ExternalTexture* texture) noexcept override; - - /** - * Logs glGetError() to slog.e - * @param name a string giving some context on the error. Typically __func__. - */ - static void logEglError(const char* name) noexcept; - - /** - * Calls glGetError() to clear the current error flags. logs a warning to log.w if - * an error was pending. - */ - static void clearGlError() noexcept; - - /** - * Always use this instead of eglMakeCurrent(). - */ - EGLBoolean makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) noexcept; - - // TODO: this should probably use getters instead. - - EGLSurface mEGLDummySurface = EGL_NO_SURFACE; - - HANDLE mD3DTextureHandle = nullptr; - uint32_t mWidth = 0; - uint32_t mHeight = 0; - - // supported extensions detected at runtime - struct { - struct { - bool OES_EGL_image_external_essl3 = false; - } gl; - struct { - bool KHR_no_config_context = false; - bool KHR_gl_colorspace = false; - } egl; - } ext; - -private: - void initializeGlExtensions() noexcept; - EGLConfig findSwapChainConfig(uint64_t flags) const; - -}; - -} // namespace filament - -#endif // _POLYVOX_FILAMENT_PLATFORM_ANGLE_H diff --git a/windows/backing_window.cpp b/windows/backing_window.cpp new file mode 100644 index 00000000..f630b3cb --- /dev/null +++ b/windows/backing_window.cpp @@ -0,0 +1,250 @@ +#include "backing_window.h" + +namespace polyvox_filament { + +static constexpr auto kClassName = L"FLUTTER_FILAMENT_WINDOW"; +static constexpr auto kWindowName = L"flutter_filament_window"; +static bool was_window_hidden_due_to_minimize_ = false; +static WPARAM last_wm_size_wparam_ = SIZE_RESTORED; +uint64_t last_thread_time_ = 0; +static constexpr auto kNativeViewPositionAndShowDelay = 300; + +LRESULT NativeViewSubclassProc(HWND window, UINT message, WPARAM wparam, + LPARAM lparam, UINT_PTR subclass_id, + DWORD_PTR ref_data) noexcept { + switch (message) { + case WM_ERASEBKGND: { + // Prevent erasing of |window| when it is unfocused and minimized or + // moved out of screen etc. + return 1; + } + case WM_SIZE: { + // Prevent unnecessary maxmize, minimize or restore messages for |window|. + // Since it is |SetParent|'ed into native view container. + return 1; + } + default: + break; + } + return ::DefSubclassProc(window, message, wparam, lparam); +} + +LRESULT CALLBACK FilamentWindowProc(HWND const window, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_MOUSEMOVE: { + std::cout << "FILAMENT MOUSE MOVE" << std::endl; + TRACKMOUSEEVENT event; + event.cbSize = sizeof(event); + event.hwndTrack = window; + event.dwFlags = TME_HOVER; + event.dwHoverTime = 200; + auto user_data = ::GetWindowLongPtr(window, GWLP_USERDATA); + if (user_data) { + std::cout << "setting foreground in filamentwindwoproc" << std::endl; + HWND flutterRootWindow = reinterpret_cast(user_data); + ::SetForegroundWindow(flutterRootWindow); + // NativeViewCore::GetInstance()->SetHitTestBehavior(0); + LONG ex_style = ::GetWindowLong(flutterRootWindow, GWL_EXSTYLE); + ex_style &= ~(WS_EX_TRANSPARENT | WS_EX_LAYERED); + ::SetWindowLong(flutterRootWindow, GWL_EXSTYLE, ex_style); + } + break; + } + case WM_ERASEBKGND: { + std::cout << "FILAMENT ERASE BKGND" << std::endl; + // Prevent erasing of |window| when it is unfocused and minimized or + // moved out of screen etc. + return 1; + } + case WM_SIZE: + case WM_MOVE: + case WM_MOVING: + case WM_ACTIVATE: + case WM_WINDOWPOSCHANGED: { + std::cout << "FILAMENT POS CHANGED" << std::endl; + // NativeViewCore::GetInstance()->SetHitTestBehavior(0); + auto user_data = ::GetWindowLongPtr(window, GWLP_USERDATA); + if (user_data) { + std::cout << "setting foreground in filamentwindwoproc" << std::endl; + HWND flutterRootWindow = reinterpret_cast(user_data); + ::SetForegroundWindow(flutterRootWindow); + // NativeViewCore::GetInstance()->SetHitTestBehavior(0); + LONG ex_style = ::GetWindowLong(flutterRootWindow, GWL_EXSTYLE); + ex_style &= ~(WS_EX_TRANSPARENT | WS_EX_LAYERED); + ::SetWindowLong(flutterRootWindow, GWL_EXSTYLE, ex_style); + } + break; + } + default: + break; + } + return ::DefWindowProc(window, message, wparam, lparam); +} + + +class BackingWindow { + + BackingWindow::BackingWindow( + flutter::PluginRegistrarWindows *pluginRegistrar, + int initialWidth, + int initialHeight) { + // get the root Flutter window + HWND flutterWindow = pluginRegistrar->GetView()->GetNativeWindow(); + _flutterRootWindow = ::GetAncestor(flutterWindow, GA_ROOT); + + // set composition to allow transparency + flutternativeview::SetWindowComposition(_flutterRootWindow, 6, 0); + + // register a top-level WindowProcDelegate to handle window events + pluginRegistrar->RegisterTopLevelWindowProcDelegate([=](HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam) { + switch (message) { + case WM_ACTIVATE: { + std::cout << "WM_ACTIVATE" << std::endl; + RECT window_rect; + ::GetWindowRect(_flutterRootWindow, &window_rect); + // Position |native_view| such that it's z order is behind |window_| & + // redraw aswell. + ::SetWindowPos(_windowHandle, _flutterRootWindow, window_rect.left, + window_rect.top, window_rect.right - window_rect.left, + window_rect.bottom - window_rect.top, SWP_NOACTIVATE); + break; + } + case WM_SIZE: { + std::cout << "WM_SIZE" << std::endl; + + // Handle Windows's minimize & maximize animations properly. + // Since |SetWindowPos| & other Win32 APIs on |native_view_container_| + // do not re-produce the same DWM animations like actual user + // interractions on the |window_| do (though both windows are overlapped + // tightly but maximize and minimze animations can't be mimiced for the + // both of them at the same time), the best solution is to make the + // |window_| opaque & hide |native_view_container_| & alter it's position. + // After that, finally make |native_view_container_| visible again & + // |window_| transparent again. This approach is not perfect, but it's the + // best we can do. The minimize & maximize animations on the |window_| + // look good with just a slight glitch on the visible native views. In + // future, maybe replacing the |NativeView| widget (Flutter-side) with + // equivalent window screenshot will result in a totally seamless + // experience. + if (wparam != SIZE_RESTORED || last_wm_size_wparam_ == SIZE_MINIMIZED || + last_wm_size_wparam_ == SIZE_MAXIMIZED || + was_window_hidden_due_to_minimize_) { + was_window_hidden_due_to_minimize_ = false; + // Minimize condition is handled separately inside |WM_WINDOWPOSCHANGED| + // case, since we don't want to cause unnecessary redraws (& show/hide) + // when user is resizing the window by dragging the window border. + SetWindowComposition(_flutterRootWindow, 0, 0); + ::ShowWindow(_windowHandle, SW_HIDE); + last_thread_time_ = + std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); + std::thread( + [=](uint64_t time) { + if (time < last_thread_time_) { + return; + } + std::this_thread::sleep_for( + std::chrono::milliseconds(kNativeViewPositionAndShowDelay)); + SetWindowComposition(_flutterRootWindow, 6, 0); + // Handling SIZE_MINIMIZED separately. + if (wparam != SIZE_MINIMIZED) { + ::ShowWindow(_windowHandle, SW_SHOWNOACTIVATE); + } + }, + last_thread_time_) + .detach(); + } + last_wm_size_wparam_ = wparam; + break; + } + // Keep |native_view_container_| behind the |window_|. + case WM_MOVE: + case WM_MOVING: + case WM_WINDOWPOSCHANGED: { + std::cout << "FLUTTER WINDOWPOSCHANGED"<< std::endl; + RECT window_rect; + ::GetWindowRect(_flutterRootWindow, &window_rect); + if (window_rect.right - window_rect.left > 0 && + window_rect.bottom - window_rect.top > 0) { + ::SetWindowPos(_windowHandle, _flutterRootWindow, window_rect.left, + window_rect.top, window_rect.right - window_rect.left, + window_rect.bottom - window_rect.top, SWP_NOACTIVATE); + // |window_| is minimized. + if (window_rect.left < 0 && window_rect.top < 0 && + window_rect.right < 0 && window_rect.bottom < 0) { + // Hide |native_view_container_| to prevent showing + // |native_view_container_| before |window_| placement + // i.e when restoring window after clicking the taskbar icon. + SetWindowComposition(_flutterRootWindow, 0, 0); + ::ShowWindow(_windowHandle, SW_HIDE); + was_window_hidden_due_to_minimize_ = true; + } + } + break; + } + case WM_CLOSE: { + // close + break; + } + default: + break; + } + return NULL; + }); + + // create the HWND for Filament + auto window_class = WNDCLASSEX{}; + ::SecureZeroMemory(&window_class, sizeof(window_class)); + window_class.cbSize = sizeof(window_class); + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.lpfnWndProc = FilamentWindowProc; + window_class.hInstance = 0; + window_class.lpszClassName = kClassName; + window_class.hCursor = ::LoadCursorW(nullptr, IDC_ARROW); + window_class.hbrBackground = ::CreateSolidBrush(RGB(0, 255, 0)); + ::RegisterClassExW(&window_class); + _windowHandle = + ::CreateWindow(kClassName, kWindowName, WS_OVERLAPPEDWINDOW, 0, 0, initialWidth, initialHeight, + nullptr, nullptr, GetModuleHandle(nullptr), nullptr); + + // Disable DWM animations + auto disable_window_transitions = TRUE; + DwmSetWindowAttribute(_windowHandle, DWMWA_TRANSITIONS_FORCEDISABLED, + &disable_window_transitions, + sizeof(disable_window_transitions)); + + ::SetWindowSubclass(_windowHandle, NativeViewSubclassProc, 69420, + NULL); // what does this do? + + auto style = ::GetWindowLongPtr(_windowHandle, GWL_STYLE); + style &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | + WS_EX_APPWINDOW); + ::SetWindowLongPtr(_windowHandle, GWL_STYLE, style); + + RECT flutterWindowRect; + ::GetClientRect(_flutterRootWindow, &flutterWindowRect); + + ::SetWindowLongPtr(_windowHandle, GWLP_USERDATA, + reinterpret_cast(_flutterRootWindow)); + + ::SetWindowPos(_windowHandle, _flutterRootWindow, flutterWindowRect.left, + flutterWindowRect.top, initialWidth, initialHeight, SWP_SHOWWINDOW); + // flutterWindowRect.right - flutterWindowRect.left, + // flutterWindowRect.bottom - flutterWindowRect.top, SWP_SHOWWINDOW); + ::ShowWindow(_windowHandle, SW_SHOW); + ::ShowWindow(_flutterRootWindow, SW_SHOW); + ::SetFocus(_flutterRootWindow); + } + } + + BackingWindow::GetHandle() { + return _windowHandle; + } + +} diff --git a/windows/backing_window.h b/windows/backing_window.h new file mode 100644 index 00000000..bb7a7bef --- /dev/null +++ b/windows/backing_window.h @@ -0,0 +1,23 @@ +#ifndef _BACKING_WINDOW_H +#define _BACKING_WINDOW_H + +#include +#include +#include + +namespace polyvox_filament { + +class BackingWindow { + public: + BackingWindow( + flutter::PluginRegistrarWindows *pluginRegistrar, + int initialWidth, + int initialHeight); + HWND GetHandle(); + private: + HWND _windowHandle; + HWND _flutterRootWindow; +} + +} +#endif \ No newline at end of file diff --git a/windows/egl_context.cpp b/windows/egl_context.cpp new file mode 100644 index 00000000..e9f2eba7 --- /dev/null +++ b/windows/egl_context.cpp @@ -0,0 +1,170 @@ +#include "egl_context.h" + +namespace polyvox_filament { + +EGLContext::EGLContext(flutter::PluginRegistrarWindows* pluginRegistrar, flutter::TextureRegistrar* textureRegistrar); { + + _platform = new filament::backend::PlatformEGL(); + + // D3D starts here + IDXGIAdapter *adapter_ = nullptr; + + // first, we need to initialize the D3D device and create the backing texture + // this has been taken from + // https://github.com/alexmercerind/flutter-windows-ANGLE-OpenGL-ES/blob/master/windows/angle_surface_manager.cc + auto feature_levels = { + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3, + }; + // NOTE: Not enabling DirectX 12. + // |D3D11CreateDevice| crashes directly on Windows 7. + // D3D_FEATURE_LEVEL_12_2, D3D_FEATURE_LEVEL_12_1, D3D_FEATURE_LEVEL_12_0, + // D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, + // D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3, + IDXGIFactory *dxgi = nullptr; + ::CreateDXGIFactory(__uuidof(IDXGIFactory), (void **)&dxgi); + // Manually selecting adapter. As far as my experience goes, this is the + // safest approach. Passing NULL (so-called default) seems to cause issues + // on Windows 7 or maybe some older graphics drivers. + // First adapter is the default. + // |D3D_DRIVER_TYPE_UNKNOWN| must be passed with manual adapter selection. + dxgi->EnumAdapters(0, &adapter_); + dxgi->Release(); + if (!adapter_) { + std::cout << "Failed to locate default D3D adapter" << std::endl; + return false; + } + + DXGI_ADAPTER_DESC adapter_desc_; + adapter_->GetDesc(&adapter_desc_); + std::wcout << L"D3D adapter description: " << adapter_desc_.Description + << std::endl; + + auto hr = ::D3D11CreateDevice( + adapter_, D3D_DRIVER_TYPE_UNKNOWN, 0, 0, feature_levels.begin(), + static_cast(feature_levels.size()), D3D11_SDK_VERSION, + &_D3D11Device, 0, &_D3D11DeviceContext); + + if (FAILED(hr)) { + std::cout << "Failed to create D3D device" << std::endl; + return false; + } + + Microsoft::WRL::ComPtr dxgi_device = nullptr; + auto dxgi_device_success = _D3D11Device->QueryInterface( + __uuidof(IDXGIDevice), (void **)&dxgi_device); + if (SUCCEEDED(dxgi_device_success) && dxgi_device != nullptr) { + dxgi_device->SetGPUThreadPriority(5); // Must be in interval [-7, 7]. + } + auto level = _D3D11Device->GetFeatureLevel(); + std::cout << "media_kit: ANGLESurfaceManager: Direct3D Feature Level: " + << (((unsigned)level) >> 12) << "_" + << ((((unsigned)level) >> 8) & 0xf) << std::endl; + + // ******************* + // * * + // * * + // * EGL starts here * + // * * + // * * + // * * + // ******************* + EGLBoolean bindAPI = eglBindAPI(EGL_OPENGL_ES_API); + if (UTILS_UNLIKELY(!bindAPI)) { + std::cout << "eglBindAPI EGL_OPENGL_ES_API failed" << std::endl; + return false; + } + + _eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + assert_invariant(_eglDisplay != EGL_NO_DISPLAY); + + EGLint major, minor; + EGLBoolean initialized = false; + + EGLDeviceEXT eglDevice; + EGLint numDevices; + + if (auto *getPlatformDisplay = + reinterpret_cast( + eglGetProcAddress("eglGetPlatformDisplayEXT"))) { + + EGLint kD3D11DisplayAttributes[] = { + EGL_PLATFORM_ANGLE_TYPE_ANGLE, + EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, + EGL_TRUE, + EGL_NONE, + }; + _eglDisplay = getPlatformDisplay( + EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, kD3D11DisplayAttributes); + initialized = eglInitialize(_eglDisplay, &major, &minor); + } + + std::cout << "Got major " << major << " and minor " << minor << std::endl; + + if (UTILS_UNLIKELY(!initialized)) { + std::cout << "eglInitialize failed" << std::endl; + return false; + } + + importGLESExtensionsEntryPoints(); + + EGLint configsCount; + + EGLint configAttribs[] = {EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, EGL_DEPTH_SIZE, 24, + EGL_STENCIL_SIZE, 8, EGL_ALPHA_SIZE, 8, + EGL_NONE}; + + EGLint contextAttribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE, + EGL_NONE, // reserved for EGL_CONTEXT_OPENGL_NO_ERROR_KHR below + EGL_NONE}; + + // find an opaque config + if (!eglChooseConfig(_eglDisplay, configAttribs, &_eglConfig, 1, + &configsCount)) { + return false; + } + + _context = (void *)eglCreateContext(_eglDisplay, _eglConfig, EGL_NO_CONTEXT, + contextAttribs); + + if (UTILS_UNLIKELY(_context == EGL_NO_CONTEXT)) { + return false; + } +} + +EGLContext::CreateTexture( + uint32_t width, uint32_t height, + std::unique_ptr> result) { + importGLESExtensionsEntryPoints(); + + if (_active.get()) { + result->Error("ERROR", + "Texture already exists. You must call destroyTexture before " + "attempting to create a new one."); + return false; + } + + _active = std::make_unique( + _pluginRegistrar, _textureRegistrar, std::move(result), width, height, + _D3D11Device, _D3D11DeviceContext, _eglConfig, _eglDisplay, _context, + [=](size_t width, size_t height) { + std::vector list; + list.push_back((int64_t)width); + list.push_back((int64_t)height); + auto val = std::make_unique(list); + this->_channel->InvokeMethod("resize", std::move(val), nullptr); + }); + + return _active->flutterTextureId != -1; +} + +EGLContext::GetSharedContext() { + return (void*)_eglContext; +} + +} \ No newline at end of file diff --git a/windows/egl_context.h b/windows/egl_context.h new file mode 100644 index 00000000..4ef550c0 --- /dev/null +++ b/windows/egl_context.h @@ -0,0 +1,28 @@ +#ifndef _EGL_CONTEXT_H +#define _EGL_CONTEXT_H + +#include "flutter_angle_texture.h" +#include "backend/platforms/PlatformEGL.h" + +namespace polyvox_filament { + +class EGLContext : public FlutterRenderingContext { +public: + EGLContext(flutter::PluginRegistrarWindows* pluginRegistrar, flutter::TextureRegistrar* textureRegistrar); + void CreateTexture( + uint32_t width, uint32_t height, + std::unique_ptr> result); +private: + EGLContext _context = NULL; + EGLConfig _eglConfig = NULL; + EGLDisplay _eglDisplay = NULL; + std::unique_ptr _active = nullptr; + std::unique_ptr _inactive = nullptr; + ID3D11Device* _D3D11Device = nullptr; + ID3D11DeviceContext* _D3D11DeviceContext = nullptr; + filament::backend::Platform* _platform = nullptr; +} + +} + +#endif \ No newline at end of file diff --git a/windows/flutter_angle_texture.h b/windows/flutter_angle_texture.h index c1e63523..37e75733 100644 --- a/windows/flutter_angle_texture.h +++ b/windows/flutter_angle_texture.h @@ -22,11 +22,13 @@ #include #include +#include "flutter_texture_buffer.h" + typedef uint32_t GLuint; namespace polyvox_filament { -class FlutterAngleTexture { +class FlutterAngleTexture : FlutterTextureBuffer { public: FlutterAngleTexture( flutter::PluginRegistrarWindows* pluginRegistrar, @@ -45,7 +47,6 @@ class FlutterAngleTexture { void RenderCallback(); - int64_t flutterTextureId = 0; GLuint glTextureId = 0; std::unique_ptr texture; @@ -55,7 +56,6 @@ class FlutterAngleTexture { uint32_t _width = 0; uint32_t _height = 0; bool logged = false; - std::shared_ptr _renderMutex; std::function _onResizeRequested; // Device diff --git a/windows/flutter_render_context.h b/windows/flutter_render_context.h new file mode 100644 index 00000000..b6487bf6 --- /dev/null +++ b/windows/flutter_render_context.h @@ -0,0 +1,51 @@ +#ifndef _FLUTTER_RENDER_CONTEXT_H +#define _FLUTTER_RENDER_CONTEXT_H + +#include +#include +#include +#include + +#include "flutter_texture_buffer.h" + +namespace polyvox_filament { + + class FlutterRenderContext { + public: + void DestroyTexture(std::unique_ptr> result) { + if (!_active) { + result->Success("Texture has already been detroyed, ignoring"); + return; + } + + // if (_active->flutterTextureId != *flutterTextureId) { + // result->Error("TEXTURE_MISMATCH", "Specified texture ID is not active"); + // return; + // } + + auto sh = std::make_shared< + std::unique_ptr>>( + std::move(result)); + + _textureRegistrar->UnregisterTexture( + _active->flutterTextureId, [=, sharedResult = std::move(sh)]() { + this->_inactive = std::move(this->_active); + auto unique = std::move(*(sharedResult.get())); + unique->Success(flutter::EncodableValue(true)); + std::cout << "Unregistered/destroyed texture." << std::endl; + }); + } + int64_t GetFlutterTextureId() { + return _active->flutterTextureId; + } + void* sharedContext = nullptr; + + protected: + flutter::PluginRegistrarWindows* _pluginRegistrar; + flutter::TextureRegistrar* _textureRegistrar; + std::unique_ptr _active = nullptr; + std::unique_ptr _inactive = nullptr; + }; +} + +#endif \ No newline at end of file diff --git a/windows/flutter_texture_buffer.h b/windows/flutter_texture_buffer.h new file mode 100644 index 00000000..efd741bc --- /dev/null +++ b/windows/flutter_texture_buffer.h @@ -0,0 +1,18 @@ +#ifndef _FLUTTER_TEXTURE_BUFFER_H +#define _FLUTTER_TEXTURE_BUFFER_H + +#include +#include +#include +#include + + +namespace polyvox_filament { + + class FlutterTextureBuffer { + public: + int64_t flutterTextureId = 0; + }; +} + +#endif \ No newline at end of file diff --git a/windows/opengl_texture_buffer.cpp b/windows/opengl_texture_buffer.cpp index dfb53e7c..5d46dcb2 100644 --- a/windows/opengl_texture_buffer.cpp +++ b/windows/opengl_texture_buffer.cpp @@ -17,11 +17,9 @@ OpenGLTextureBuffer::OpenGLTextureBuffer( flutter::PluginRegistrarWindows *pluginRegistrar, flutter::TextureRegistrar *textureRegistrar, std::unique_ptr> result, - uint32_t width, uint32_t height, HGLRC context, - std::shared_ptr renderMutex) + uint32_t width, uint32_t height, HGLRC context) : _pluginRegistrar(pluginRegistrar), _textureRegistrar(textureRegistrar), - _width(width), _height(height), _context(context), - _renderMutex(renderMutex) { + _width(width), _height(height), _context(context) { HWND hwnd = _pluginRegistrar->GetView()->GetNativeWindow(); @@ -135,7 +133,7 @@ OpenGLTextureBuffer::~OpenGLTextureBuffer() { // result->Error("CONTEXT", "Failed to switch OpenGL context.", nullptr); return; } - glDeleteTextures(1, &this->_inactive->glTextureId); + glDeleteTextures(1, &this->glTextureId); wglMakeCurrent(NULL, NULL); } diff --git a/windows/opengl_texture_buffer.h b/windows/opengl_texture_buffer.h index 44e58c97..543da660 100644 --- a/windows/opengl_texture_buffer.h +++ b/windows/opengl_texture_buffer.h @@ -16,25 +16,24 @@ #include #include +#include "flutter_texture_buffer.h" + typedef uint32_t GLuint; namespace polyvox_filament { -class OpenGLTextureBuffer { +class OpenGLTextureBuffer : public FlutterTextureBuffer { public: - OpenGLTextureBuffer( flutter::PluginRegistrarWindows* pluginRegistrar, flutter::TextureRegistrar* textureRegistrar, std::unique_ptr> result, uint32_t width, uint32_t height, - HGLRC context, - std::shared_ptr renderMutex); + HGLRC context); ~OpenGLTextureBuffer(); GLuint glTextureId = 0; - int64_t flutterTextureId = 0; std::unique_ptr pixelBuffer; std::unique_ptr pixelData; std::unique_ptr texture; @@ -46,7 +45,6 @@ class OpenGLTextureBuffer { uint32_t _height = 0; HGLRC _context = NULL; bool logged = false; - std::shared_ptr _renderMutex; }; } diff --git a/windows/polyvox_filament_plugin.cpp b/windows/polyvox_filament_plugin.cpp index dfe1a0bb..c3fab1b2 100644 --- a/windows/polyvox_filament_plugin.cpp +++ b/windows/polyvox_filament_plugin.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -26,21 +27,29 @@ #include #include #include -#include +#include #include "PolyvoxFilamentApi.h" -#ifdef USE_ANGLE -#include "PlatformANGLE.h" -#endif +#include #include +#include #include +#include "utils.h" + +#include "flutter_render_context.h" + +#if USE_ANGLE +#include "egl_context.h" +#else +#include "wgl_context.h" +#endif + using namespace std::chrono_literals; namespace polyvox_filament { -// static void PolyvoxFilamentPlugin::RegisterWithRegistrar( flutter::PluginRegistrarWindows *registrar) { auto channel = @@ -57,21 +66,25 @@ void PolyvoxFilamentPlugin::RegisterWithRegistrar( PolyvoxFilamentPlugin::PolyvoxFilamentPlugin( flutter::TextureRegistrar *textureRegistrar, flutter::PluginRegistrarWindows *pluginRegistrar, - std::unique_ptr>& channel) - : _textureRegistrar(textureRegistrar), _pluginRegistrar(pluginRegistrar), _channel(std::move(channel)) { - _channel->SetMethodCallHandler( - [=](const auto &call, auto result) { - this->HandleMethodCall(call, std::move(result)); - }); - } + std::unique_ptr> &channel) + : _textureRegistrar(textureRegistrar), _pluginRegistrar(pluginRegistrar), + _channel(std::move(channel)) { + + // attach the method call handler for incoming messages + _channel->SetMethodCallHandler([=](const auto &call, auto result) { + std::cout << call.method_name() << std::endl; + this->HandleMethodCall(call, std::move(result)); + }); +} + PolyvoxFilamentPlugin::~PolyvoxFilamentPlugin() {} ResourceBuffer PolyvoxFilamentPlugin::loadResource(const char *name) { - + std::string name_str(name); std::filesystem::path targetFilePath; - + if (name_str.rfind("file://", 0) == 0) { targetFilePath = name_str.substr(7); } else { @@ -89,14 +102,14 @@ ResourceBuffer PolyvoxFilamentPlugin::loadResource(const char *name) { std::wstring exePathBuf(pBuf); std::filesystem::path exePath(exePathBuf); auto exeDir = exePath.remove_filename(); - targetFilePath = exeDir.wstring() + L"data/flutter_assets/" + - assetPath; + targetFilePath = exeDir.wstring() + L"data/flutter_assets/" + assetPath; } std::streampos length; - + std::ifstream is(targetFilePath.c_str(), std::ios::binary); if (!is) { - std::cout << "Failed to find resource at file path " << targetFilePath << std::endl; + std::cout << "Failed to find resource at file path " << targetFilePath + << std::endl; return ResourceBuffer(nullptr, 0, -1); } is.seekg(0, std::ios::end); @@ -111,7 +124,8 @@ ResourceBuffer PolyvoxFilamentPlugin::loadResource(const char *name) { auto rb = ResourceBuffer(buffer, length, id); _resources.emplace(id, rb); - std::wcout << "Loaded resource of length " << length << " from path " << targetFilePath << std::endl; + std::wcout << "Loaded resource of length " << length << " from path " + << targetFilePath << std::endl; return rb; } @@ -130,301 +144,28 @@ static void _freeResource(ResourceBuffer rbf, void *const plugin) { // this is the C-style function that will be returned via getRenderCallback // called on every frame by the FFI API -// this is just a convenient wrapper to call RenderCallback on the actual plugin instance -void render_callback(void* owner) { - ((PolyvoxFilamentPlugin*)owner)->RenderCallback(); +// this is just a convenient wrapper to call RenderCallback on the actual plugin +// instance +void render_callback(void *owner) { + ((PolyvoxFilamentPlugin *)owner)->RenderCallback(); } -// this is the method on PolyvoxFilamentPlugin that will copy between D3D textures +// this is the method on PolyvoxFilamentPlugin that will copy between D3D +// textures void PolyvoxFilamentPlugin::RenderCallback() { - - // std::lock_guard guard(*(_renderMutex.get())); - if (_active) { - #ifdef USE_ANGLE - _active->RenderCallback(); - #endif - _textureRegistrar->MarkTextureFrameAvailable(_active->flutterTextureId); - } -} - + if (_context) { + auto flutterTextureId = _context->GetFlutterTextureId(); #ifdef USE_ANGLE -bool PolyvoxFilamentPlugin::CreateSharedEGLContext() { - - //platform = new filament::backend::PlatformANGLE(_internalD3DTextureHandle, - // width, height); - _platform = new filament::backend::PlatformEGL(); - - // D3D starts here - IDXGIAdapter* adapter_ = nullptr; - - // first, we need to initialize the D3D device and create the backing texture - // this has been taken from https://github.com/alexmercerind/flutter-windows-ANGLE-OpenGL-ES/blob/master/windows/angle_surface_manager.cc - auto feature_levels = { - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_1, - D3D_FEATURE_LEVEL_10_0, - D3D_FEATURE_LEVEL_9_3, - }; - // NOTE: Not enabling DirectX 12. - // |D3D11CreateDevice| crashes directly on Windows 7. - // D3D_FEATURE_LEVEL_12_2, D3D_FEATURE_LEVEL_12_1, D3D_FEATURE_LEVEL_12_0, - // D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, - // D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3, - IDXGIFactory* dxgi = nullptr; - ::CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&dxgi); - // Manually selecting adapter. As far as my experience goes, this is the - // safest approach. Passing NULL (so-called default) seems to cause issues - // on Windows 7 or maybe some older graphics drivers. - // First adapter is the default. - // |D3D_DRIVER_TYPE_UNKNOWN| must be passed with manual adapter selection. - dxgi->EnumAdapters(0, &adapter_); - dxgi->Release(); - if (!adapter_) { - std::cout << "Failed to locate default D3D adapter"<< std::endl; - return false; - } - - DXGI_ADAPTER_DESC adapter_desc_; - adapter_->GetDesc(&adapter_desc_); - std::wcout << L"D3D adapter description: " << adapter_desc_.Description << std::endl; - - auto hr = ::D3D11CreateDevice( - adapter_, D3D_DRIVER_TYPE_UNKNOWN, 0, 0, feature_levels.begin(), - static_cast(feature_levels.size()), D3D11_SDK_VERSION, - &_D3D11Device, 0, &_D3D11DeviceContext); - - if (FAILED(hr)) { - std::cout << "Failed to create D3D device"<< std::endl; - return false; - } - - Microsoft::WRL::ComPtr dxgi_device = nullptr; - auto dxgi_device_success = _D3D11Device->QueryInterface( - __uuidof(IDXGIDevice), (void**)&dxgi_device); - if (SUCCEEDED(dxgi_device_success) && dxgi_device != nullptr) { - dxgi_device->SetGPUThreadPriority(5); // Must be in interval [-7, 7]. - } - auto level = _D3D11Device->GetFeatureLevel(); - std::cout << "media_kit: ANGLESurfaceManager: Direct3D Feature Level: " - << (((unsigned)level) >> 12) << "_" - << ((((unsigned)level) >> 8) & 0xf) << std::endl; - - - // ******************* - // * * - // * * - // * EGL starts here * - // * * - // * * - // * * - // ******************* - EGLBoolean bindAPI = eglBindAPI(EGL_OPENGL_ES_API); - if (UTILS_UNLIKELY(!bindAPI)) { - std::cout << "eglBindAPI EGL_OPENGL_ES_API failed" << std::endl; - return false; - } - - _eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - assert_invariant(_eglDisplay != EGL_NO_DISPLAY); - - EGLint major, minor; - EGLBoolean initialized = false; - - EGLDeviceEXT eglDevice; - EGLint numDevices; - - if(auto* getPlatformDisplay = reinterpret_cast( - eglGetProcAddress("eglGetPlatformDisplayEXT"))) { - - EGLint kD3D11DisplayAttributes[] = { - EGL_PLATFORM_ANGLE_TYPE_ANGLE, - EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, - EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, - EGL_TRUE, - EGL_NONE, - }; - _eglDisplay = getPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, kD3D11DisplayAttributes); - initialized = eglInitialize(_eglDisplay, &major, &minor); - } - - std::cout << "Got major " << major << " and minor " << minor << std::endl; - - if (UTILS_UNLIKELY(!initialized)) { - std::cout << "eglInitialize failed" << std::endl; - return false; - } - - importGLESExtensionsEntryPoints(); - - EGLint configsCount; - - EGLint configAttribs[] = { - EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, - EGL_DEPTH_SIZE, 24, EGL_STENCIL_SIZE, 8, EGL_ALPHA_SIZE, 8, - EGL_NONE - }; - - EGLint contextAttribs[] = { - EGL_CONTEXT_CLIENT_VERSION, 3, - EGL_NONE, EGL_NONE, // reserved for EGL_CONTEXT_OPENGL_NO_ERROR_KHR below - EGL_NONE - }; - - // find an opaque config - if (!eglChooseConfig(_eglDisplay, configAttribs, &_eglConfig, 1, &configsCount)) { - return false; - } - - _context = (void*)eglCreateContext(_eglDisplay, _eglConfig, EGL_NO_CONTEXT, contextAttribs); - - if (UTILS_UNLIKELY(_context == EGL_NO_CONTEXT)) { - return false; - } -} - -bool PolyvoxFilamentPlugin::MakeD3DTexture(uint32_t width, uint32_t height,std::unique_ptr> result) { - importGLESExtensionsEntryPoints(); - - if(_active.get()) { - result->Error("ERROR", "Texture already exists. You must call destroyTexture before attempting to create a new one."); - return false; - } - - _active = std::make_unique( - _pluginRegistrar, - _textureRegistrar, - std::move(result), - width, - height, - _D3D11Device, - _D3D11DeviceContext, - _eglConfig, - _eglDisplay, - _context, [=](size_t width, size_t height) { - std::vector list; - list.push_back((int64_t)width); - list.push_back((int64_t)height); - auto val = std::make_unique(list); - this->_channel->InvokeMethod("resize", std::move(val), nullptr); - }); - - return _active->flutterTextureId != -1; -} -#else -bool PolyvoxFilamentPlugin::CreateSharedWGLContext() { - - HWND hwnd = _pluginRegistrar->GetView() - ->GetNativeWindow(); - - HDC whdc = GetDC(hwnd); - if (whdc == NULL) { - std::cout << "No device context for temporary window" << std::endl; - return false; - } - - std::cout << "No GL context exists, creating" << std::endl; - - PIXELFORMATDESCRIPTOR pfd = { - sizeof(PIXELFORMATDESCRIPTOR), - 1, - PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, // Flags - PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette. - 32, // Colordepth of the framebuffer. - 0, 0, 0, 0, 0, 0, - 0, - 0, - 0, - 0, 0, 0, 0, - 32, // Number of bits for the depthbuffer - 0, // Number of bits for the stencilbuffer - 0, // Number of Aux buffers in the framebuffer. - PFD_MAIN_PLANE, - 0, - 0, 0, 0 - }; - - int pixelFormat = ChoosePixelFormat(whdc, &pfd); - SetPixelFormat(whdc, pixelFormat, &pfd); - - // We need a tmp context to retrieve and call wglCreateContextAttribsARB. - HGLRC tempContext = wglCreateContext(whdc); - if (!wglMakeCurrent(whdc, tempContext)) { - std::cout <<"Failed to acquire temporary context" << std::endl; - return false; - } - - GLenum err = glGetError(); - - if(err != GL_NO_ERROR) { - std::cout <<"GL Error @ 455 %d" << std::endl; - return false; - } - - PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs = nullptr; - - wglCreateContextAttribs = - (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress( - "wglCreateContextAttribsARB"); - - if (!wglCreateContextAttribs) { - std::cout <<"Failed to resolve wglCreateContextAttribsARB" << std::endl; - return false; - } - - for (int minor = 5; minor >= 1; minor--) { - std::vector mAttribs = {WGL_CONTEXT_MAJOR_VERSION_ARB, 4, - WGL_CONTEXT_MINOR_VERSION_ARB, minor, 0}; - _context = wglCreateContextAttribs(whdc, nullptr, mAttribs.data()); - if (_context) { - break; - } - } - - wglMakeCurrent(NULL, NULL); - wglDeleteContext(tempContext); - - if (!_context || !wglMakeCurrent(whdc, _context)) { - std::cout << "Failed to create OpenGL context." << std::endl; - return false; - } - - -} - -bool PolyvoxFilamentPlugin::MakeOpenGLTexture(uint32_t width, uint32_t height,std::unique_ptr> result) { - - if(_active.get()) { - result->Error("ERROR", "Texture already exists. You must call destroyTexture before attempting to create a new one."); - return false; - } - - _active = std::make_unique( - _pluginRegistrar, - _textureRegistrar, - std::move(result), - width, - height, - _context, - _renderMutex - ); - - return _active->flutterTextureId != -1; - -} + _active->RenderCallback(); #endif - + _textureRegistrar->MarkTextureFrameAvailable(flutterTextureId); + } +} void PolyvoxFilamentPlugin::CreateTexture( const flutter::MethodCall &methodCall, std::unique_ptr> result) { - - if(!_renderMutex.get()) { - _renderMutex = std::make_shared(); - } - - std::lock_guard guard(*(_renderMutex.get())); - const auto *args = std::get_if(methodCall.arguments()); @@ -433,86 +174,78 @@ void PolyvoxFilamentPlugin::CreateTexture( // create a single shared context for the life of the application // this will be used to create a backing texture and passed to Filament - if(!_context) { - #ifdef USE_ANGLE - CreateSharedEGLContext(); - #else - CreateSharedWGLContext(); - #endif + if (!_context) { +#ifdef USE_ANGLE + _context = std::make_unique(_pluginRegistrar); +#else + _context = std::make_unique(_pluginRegistrar, _textureRegistrar); +#endif } - - #ifdef USE_ANGLE - bool success = MakeD3DTexture(width, height, std::move(result)); - #else - bool success = MakeOpenGLTexture(width, height, std::move(result)); - #endif + //_context->CreateTexture(width, height, std::move(result)); } void PolyvoxFilamentPlugin::DestroyTexture( const flutter::MethodCall &methodCall, std::unique_ptr> result) { - const auto *flutterTextureId = - std::get_if(methodCall.arguments()); - if(!flutterTextureId) { + const auto *flutterTextureId = std::get_if(methodCall.arguments()); + + if (!flutterTextureId) { result->Error("NOT_IMPLEMENTED", "Flutter texture ID must be provided"); return; } - - if(!_active) { - result->Success("Texture has already been detroyed, ignoring"); - return; + + if (_context) { + _context->DestroyTexture(std::move(result)); } - - if(_active->flutterTextureId != *flutterTextureId) { - result->Error("TEXTURE_MISMATCH", "Specified texture ID is not active"); - return; + else { + result->Error("NO_CONTEXT", "No rendering context is active"); } - auto sh = std::make_shared>>(std::move(result)); - - _textureRegistrar->UnregisterTexture(_active->flutterTextureId, [=, - sharedResult=std::move(sh) - ]() { - this->_inactive = std::move(this->_active); - auto unique = std::move(*(sharedResult.get())); - unique->Success(flutter::EncodableValue(true)); - std::cout << "Unregistered/destroyed texture." << std::endl; - }); - - } void PolyvoxFilamentPlugin::HandleMethodCall( const flutter::MethodCall &methodCall, std::unique_ptr> result) { - if (methodCall.method_name() == "getSharedContext") { - result->Success(flutter::EncodableValue((int64_t)_context)); + if (methodCall.method_name() == "useBackingWindow") { + result->Success(flutter::EncodableValue( + #ifdef WGL_USE_BACKING_WINDOW + true + #else + false + #endif + )); + } else if (methodCall.method_name() == "getSharedContext") { + result->Success(flutter::EncodableValue((int64_t)_context->sharedContext)); } else if (methodCall.method_name() == "getResourceLoaderWrapper") { const ResourceLoaderWrapper *const resourceLoader = - new ResourceLoaderWrapper(_loadResource, _freeResource, this); + new ResourceLoaderWrapper(_loadResource, _freeResource, this); result->Success(flutter::EncodableValue((int64_t)resourceLoader)); } else if (methodCall.method_name() == "createTexture") { CreateTexture(methodCall, std::move(result)); } else if (methodCall.method_name() == "destroyTexture") { DestroyTexture(methodCall, std::move(result)); - } else if(methodCall.method_name() == "getRenderCallback") { - flutter::EncodableList resultList; - resultList.push_back(flutter::EncodableValue((int64_t)&render_callback)); - resultList.push_back(flutter::EncodableValue((int64_t)this)); - result->Success(resultList); - } else if(methodCall.method_name() == "getDriverPlatform") { - #ifdef USE_ANGLE - result->Success(flutter::EncodableValue((int64_t)_platform)); + } else if (methodCall.method_name() == "getRenderCallback") { + #if !ANGLE && WGL_USE_BACKING_WINDOW + result->Success(nullptr); #else - result->Success(flutter::EncodableValue((int64_t)nullptr)); + flutter::EncodableList resultList; + resultList.push_back(flutter::EncodableValue((int64_t)&render_callback)); + resultList.push_back(flutter::EncodableValue((int64_t)this)); + result->Success(resultList); #endif + } else if (methodCall.method_name() == "getDriverPlatform") { +#ifdef USE_ANGLE + result->Success(flutter::EncodableValue((int64_t)_platform)); +#else + result->Success(flutter::EncodableValue((int64_t) nullptr)); +#endif } else { - result->Error("NOT_IMPLEMENTED", "Method is not implemented %s", methodCall.method_name()); + result->Error("NOT_IMPLEMENTED", "Method is not implemented %s", + methodCall.method_name()); } } } // namespace polyvox_filament - diff --git a/windows/polyvox_filament_plugin.h b/windows/polyvox_filament_plugin.h index 84ff9c71..74ffdeef 100644 --- a/windows/polyvox_filament_plugin.h +++ b/windows/polyvox_filament_plugin.h @@ -14,15 +14,14 @@ #include "GL/GL.h" #include "GL/GLu.h" -#ifdef USE_ANGLE -#include "flutter_angle_texture.h" -#include "backend/platforms/PlatformEGL.h" -#else -#include "opengl_texture_buffer.h" -#endif - #include "PolyvoxFilamentApi.h" +#if ANGLE +#include "egl_context.h" +#else +#include "wgl_context.h" +#endif + namespace polyvox_filament { class PolyvoxFilamentPlugin : public flutter::Plugin { @@ -47,7 +46,6 @@ public: flutter::TextureRegistrar *_textureRegistrar; std::unique_ptr> _channel; std::map _resources; - std::shared_ptr _renderMutex; void CreateTexture( const flutter::MethodCall &methodCall, @@ -62,23 +60,9 @@ public: private: #ifdef USE_ANGLE - bool CreateSharedEGLContext(); - bool MakeD3DTexture(uint32_t width, uint32_t height, std::unique_ptr> result); - EGLContext _context = NULL; - EGLConfig _eglConfig = NULL; - EGLDisplay _eglDisplay = NULL; - std::unique_ptr _active = nullptr; - std::unique_ptr _inactive = nullptr; - ID3D11Device* _D3D11Device = nullptr; - ID3D11DeviceContext* _D3D11DeviceContext = nullptr; - filament::backend::Platform* _platform = nullptr; + std::unique_ptr _context = nullptr; #else - std::unique_ptr _active = nullptr; - std::unique_ptr _inactive = nullptr; - // shared OpenGLContext - HGLRC _context = NULL; - bool CreateSharedWGLContext(); - bool MakeOpenGLTexture(uint32_t width, uint32_t height, std::unique_ptr> result); + std::unique_ptr _context = nullptr; #endif }; diff --git a/windows/utils.cc b/windows/utils.cc new file mode 100644 index 00000000..16f7aab2 --- /dev/null +++ b/windows/utils.cc @@ -0,0 +1,130 @@ +// This file is a part of flutter_native_view +// (https://github.com/alexmercerind/flutter_native_view). +// +// Copyright (c) 2022, Hitesh Kumar Saini . +// All rights reserved. +// Use of this source code is governed by MIT license that can be found in the +// LICENSE file. + +#include "utils.h" +#include + +#pragma comment(lib, "dwmapi.lib") +#pragma comment(lib, "comctl32.lib") + +namespace flutternativeview { + +typedef enum _WINDOWCOMPOSITIONATTRIB { + WCA_UNDEFINED = 0, + WCA_NCRENDERING_ENABLED = 1, + WCA_NCRENDERING_POLICY = 2, + WCA_TRANSITIONS_FORCEDISABLED = 3, + WCA_ALLOW_NCPAINT = 4, + WCA_CAPTION_BUTTON_BOUNDS = 5, + WCA_NONCLIENT_RTL_LAYOUT = 6, + WCA_FORCE_ICONIC_REPRESENTATION = 7, + WCA_EXTENDED_FRAME_BOUNDS = 8, + WCA_HAS_ICONIC_BITMAP = 9, + WCA_THEME_ATTRIBUTES = 10, + WCA_NCRENDERING_EXILED = 11, + WCA_NCADORNMENTINFO = 12, + WCA_EXCLUDED_FROM_LIVEPREVIEW = 13, + WCA_VIDEO_OVERLAY_ACTIVE = 14, + WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15, + WCA_DISALLOW_PEEK = 16, + WCA_CLOAK = 17, + WCA_CLOAKED = 18, + WCA_ACCENT_POLICY = 19, + WCA_FREEZE_REPRESENTATION = 20, + WCA_EVER_UNCLOAKED = 21, + WCA_VISUAL_OWNER = 22, + WCA_HOLOGRAPHIC = 23, + WCA_EXCLUDED_FROM_DDA = 24, + WCA_PASSIVEUPDATEMODE = 25, + WCA_USEDARKMODECOLORS = 26, + WCA_LAST = 27 +} WINDOWCOMPOSITIONATTRIB; + +typedef struct _WINDOWCOMPOSITIONATTRIBDATA { + WINDOWCOMPOSITIONATTRIB Attrib; + PVOID pvData; + SIZE_T cbData; +} WINDOWCOMPOSITIONATTRIBDATA; + +typedef enum _ACCENT_STATE { + ACCENT_DISABLED = 0, + ACCENT_ENABLE_GRADIENT = 1, + ACCENT_ENABLE_TRANSPARENTGRADIENT = 2, + ACCENT_ENABLE_BLURBEHIND = 3, + ACCENT_ENABLE_ACRYLICBLURBEHIND = 4, + ACCENT_ENABLE_HOSTBACKDROP = 5, + ACCENT_INVALID_STATE = 6 +} ACCENT_STATE; + +typedef struct _ACCENT_POLICY { + ACCENT_STATE AccentState; + DWORD AccentFlags; + DWORD GradientColor; + DWORD AnimationId; +} ACCENT_POLICY; + +typedef BOOL(WINAPI* _GetWindowCompositionAttribute)( + HWND, WINDOWCOMPOSITIONATTRIBDATA*); +typedef BOOL(WINAPI* _SetWindowCompositionAttribute)( + HWND, WINDOWCOMPOSITIONATTRIBDATA*); + +static _SetWindowCompositionAttribute g_set_window_composition_attribute = NULL; +static bool g_set_window_composition_attribute_initialized = false; + +typedef LONG NTSTATUS, *PNTSTATUS; +#define STATUS_SUCCESS (0x00000000) + +typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); + +RTL_OSVERSIONINFOW GetWindowsVersion() { + HMODULE hmodule = ::GetModuleHandleW(L"ntdll.dll"); + if (hmodule) { + RtlGetVersionPtr rtl_get_version_ptr = + (RtlGetVersionPtr)::GetProcAddress(hmodule, "RtlGetVersion"); + if (rtl_get_version_ptr != nullptr) { + RTL_OSVERSIONINFOW rovi = {0}; + rovi.dwOSVersionInfoSize = sizeof(rovi); + if (STATUS_SUCCESS == rtl_get_version_ptr(&rovi)) { + return rovi; + } + } + } + RTL_OSVERSIONINFOW rovi = {0}; + return rovi; +} + +void SetWindowComposition(HWND window, int32_t accent_state, + int32_t gradient_color) { + // TODO: Look for a better available API. + if (GetWindowsVersion().dwBuildNumber >= 18362) { + std::cout << "got win ver" << std::endl; + if (!g_set_window_composition_attribute_initialized) { + std::cout << "not init" << std::endl; + auto user32 = ::GetModuleHandleA("user32.dll"); + if (user32) { + std::cout << "user32" << std::endl; + g_set_window_composition_attribute = + reinterpret_cast<_SetWindowCompositionAttribute>( + ::GetProcAddress(user32, "SetWindowCompositionAttribute")); + if (g_set_window_composition_attribute) { + std::cout << "set" << std::endl; + g_set_window_composition_attribute_initialized = true; + } + } + } + ACCENT_POLICY accent = {static_cast(accent_state), 2, + static_cast(gradient_color), 0}; + WINDOWCOMPOSITIONATTRIBDATA data; + data.Attrib = WCA_ACCENT_POLICY; + data.pvData = &accent; + data.cbData = sizeof(accent); + g_set_window_composition_attribute(window, &data); + } +} + +} // namespace flutternativeview diff --git a/windows/utils.h b/windows/utils.h new file mode 100644 index 00000000..36fb05d9 --- /dev/null +++ b/windows/utils.h @@ -0,0 +1,20 @@ +// This file is a part of flutter_native_view +// (https://github.com/alexmercerind/flutter_native_view). +// +// Copyright (c) 2022, Hitesh Kumar Saini . +// All rights reserved. +// Use of this source code is governed by MIT license that can be found in the +// LICENSE file. + +#include + +#include + +namespace flutternativeview { + +RTL_OSVERSIONINFOW GetWindowsVersion(); + +void SetWindowComposition(HWND window, int32_t accent_state, + int32_t gradient_color); + +} // namespace flutternativeview diff --git a/windows/wgl_context.cpp b/windows/wgl_context.cpp new file mode 100644 index 00000000..e6394c34 --- /dev/null +++ b/windows/wgl_context.cpp @@ -0,0 +1,139 @@ +#include "wgl_context.h" + +#ifdef WGL_USE_BACKING_WINDOW +#include "backing_window.h" +#endif + +#include "flutter_texture_buffer.h" + +namespace polyvox_filament { + +WGLContext::WGLContext(flutter::PluginRegistrarWindows *pluginRegistrar, + flutter::TextureRegistrar *textureRegistrar) { + + auto hwnd = pluginRegistrar->GetView()->GetNativeWindow(); + + HDC whdc = GetDC(hwnd); + if (whdc == NULL) { + std::cout << "No device context for temporary window" << std::endl; + return; + } + + std::cout << "No GL context exists, creating" << std::endl; + + PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), + 1, + PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, // Flags + PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette. + 32, // Colordepth of the framebuffer. + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 32, // Number of bits for the depthbuffer + 0, // Number of bits for the stencilbuffer + 0, // Number of Aux buffers in the framebuffer. + PFD_MAIN_PLANE, + 0, + 0, + 0, + 0}; + + int pixelFormat = ChoosePixelFormat(whdc, &pfd); + SetPixelFormat(whdc, pixelFormat, &pfd); + + // We need a tmp context to retrieve and call wglCreateContextAttribsARB. + HGLRC tempContext = wglCreateContext(whdc); + if (!wglMakeCurrent(whdc, tempContext)) { + std::cout << "Failed to acquire temporary context" << std::endl; + return; + } + + GLenum err = glGetError(); + + if (err != GL_NO_ERROR) { + std::cout << "GL Error @ 455 %d" << std::endl; + return; + } + + PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs = nullptr; + + wglCreateContextAttribs = + (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress( + "wglCreateContextAttribsARB"); + + if (!wglCreateContextAttribs) { + std::cout << "Failed to resolve wglCreateContextAttribsARB" << std::endl; + return; + } + + for (int minor = 5; minor >= 1; minor--) { + std::vector mAttribs = {WGL_CONTEXT_MAJOR_VERSION_ARB, 4, + WGL_CONTEXT_MINOR_VERSION_ARB, minor, 0}; + _context = wglCreateContextAttribs(whdc, nullptr, mAttribs.data()); + if (_context) { + break; + } + } + + wglMakeCurrent(NULL, NULL); + wglDeleteContext(tempContext); + + if (!_context || !wglMakeCurrent(whdc, _context)) { + std::cout << "Failed to create OpenGL context." << std::endl; + return; + } +} + +void WGLContext::CreateTexture( + uint32_t width, uint32_t height, + std::unique_ptr> result) { + +#ifdef WGL_USE_BACKING_WINDOW + _backingWindow = std::make_unique() + : std::vector resultList; + resultList.push_back(flutter::EncodableValue((int64_t) nullptr)); + resultList.push_back( + flutter::EncodableValue((int64_t)_backingWindow->GetHandle())); + resultList.push_back(flutter::EncodableValue((int64_t) nullptr)); + result->Success(resultList); +} +else { + result->Error("FOO", "ERROR", nullptr); +} +#else + if (_active.get()) { + result->Error("ERROR", + "Texture already exists. You must call destroyTexture before " + "attempting to create a new one."); + } else { + _active = std::make_unique(_pluginRegistrar, _textureRegistrar, + std::move(result), width, height, + _context); + + if (_active->flutterTextureId != -1) { + std::vector resultList; + resultList.push_back(flutter::EncodableValue((int64_t) nullptr)); + resultList.push_back(flutter::EncodableValue((int64_t) nullptr)); + resultList.push_back(flutter::EncodableValue((int64_t) nullptr)); + result->Success(resultList); + } else { + result->Error("FOO", "ERROR", nullptr); + } + } +#endif +} + +void *WGLContext::GetSharedContext() { return (void *)_context; } + +} // namespace polyvox_filament diff --git a/windows/wgl_context.h b/windows/wgl_context.h new file mode 100644 index 00000000..5d676ec0 --- /dev/null +++ b/windows/wgl_context.h @@ -0,0 +1,25 @@ +#ifndef _WGL_CONTEXT_H +#define _WGL_CONTEXT_H + +#include +#include "opengl_texture_buffer.h" +#include "flutter_render_context.h" +#if WGL_USE_BACKING_WINDOW +#include "backing_window.h" +#endif +namespace polyvox_filament { + + class WGLContext : public FlutterRenderContext { + public: + WGLContext(flutter::PluginRegistrarWindows* pluginRegistrar, flutter::TextureRegistrar* textureRegistrar); + void CreateTexture(uint32_t width, uint32_t height, std::unique_ptr> result); + void* GetSharedContext(); + private: + HGLRC _context = NULL; + #if WGL_USE_BACKING_WINDOW + std::unique_ptr _backingWindow = nullptr; + #endif + }; + +} +#endif \ No newline at end of file