From 2b9ddef5e73f43843afd4a6cd7ae02a53c79029b Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Sun, 22 Oct 2023 17:45:09 +1100 Subject: [PATCH] use shared EGLContext for ANGLE on Windows --- windows/CMakeLists.txt | 16 +- windows/PlatformANGLE.cpp | 26 +- windows/PlatformANGLE.h | 1 + windows/flutter_angle_texture.cpp | 230 +++++++++++++ windows/flutter_angle_texture.h | 81 +++++ windows/lib/Debug/angle/backend.lib | 4 +- windows/polyvox_filament_plugin.cpp | 510 ++++++++++++++-------------- windows/polyvox_filament_plugin.h | 57 ++-- 8 files changed, 630 insertions(+), 295 deletions(-) create mode 100644 windows/flutter_angle_texture.cpp create mode 100644 windows/flutter_angle_texture.h diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt index 1a41aa20..fb881556 100644 --- a/windows/CMakeLists.txt +++ b/windows/CMakeLists.txt @@ -12,7 +12,6 @@ set(PLUGIN_NAME "polyvox_filament_plugin") list(APPEND PLUGIN_SOURCES "polyvox_filament_plugin.cpp" "polyvox_filament_plugin.h" - "opengl_texture_buffer.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../ios/src/AssetManager.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../ios/src/FilamentViewer.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../ios/src/PolyvoxFilamentApi.cpp" @@ -23,11 +22,16 @@ list(APPEND PLUGIN_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/../ios/src/camutils/Bookmark.cpp" ) -set(USE_ANGLE FALSE) +set(USE_ANGLE TRUE) if(USE_ANGLE) add_compile_definitions(USE_ANGLE) - list(APPEND PLUGIN_SOURCES "PlatformAngle.cpp") + list(APPEND PLUGIN_SOURCES + # "PlatformAngle.cpp" + "flutter_angle_texture.cpp" + ) +else() + list(APPEND PLUGIN_SOURCES "opengl_texture_buffer.cpp") endif() # Define the plugin library target. Its name must not be changed (see comment @@ -57,6 +61,8 @@ if(USE_ANGLE) list(APPEND GL_LIBS EGL GLESv2 + #bluegl + #opengl32 ) set(ANGLE_OR_OPENGL_DIR angle) add_library(EGL SHARED IMPORTED) @@ -67,6 +73,10 @@ if(USE_ANGLE) set_property(TARGET GLESv2 PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/angle/libGLESv2.dll.lib") set_property(TARGET GLESv2 PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/angle/libGLESv2.dll.lib") set_property(TARGET GLESv2 PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/angle/libGLESv2.dll.lib") + add_library(bluegl SHARED IMPORTED) + set_property(TARGET bluegl PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/angle/bluegl.lib") + set_property(TARGET bluegl PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/angle/bluegl.lib") + set_property(TARGET bluegl PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/angle/bluegl.lib") else() list(APPEND GL_LIBS bluegl diff --git a/windows/PlatformANGLE.cpp b/windows/PlatformANGLE.cpp index 1b9dba8f..128b3761 100644 --- a/windows/PlatformANGLE.cpp +++ b/windows/PlatformANGLE.cpp @@ -35,10 +35,10 @@ using namespace utils; -PROC wglGetProcAddress(LPCSTR name) { - // PANIC - return nullptr; -} +// PROC wglGetProcAddress(LPCSTR name) { +// // PANIC +// return nullptr; +// } namespace filament::backend::GLUtils { class unordered_string_set : public std::unordered_set { @@ -108,6 +108,9 @@ PlatformANGLE::PlatformANGLE( } +PlatformANGLE::~PlatformANGLE() { + +} backend::Driver* PlatformANGLE::createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept { @@ -258,6 +261,13 @@ backend::Driver* PlatformANGLE::createDriver(void* sharedContext, } 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); @@ -437,10 +447,10 @@ bool PlatformANGLE::setExternalImage(void* externalImage, 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 +// #ifdef GL_OES_EGL_image +// glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, +// static_cast(externalImage)); +// #endif } return true; } diff --git a/windows/PlatformANGLE.h b/windows/PlatformANGLE.h index 9de57c55..dc6a4f61 100644 --- a/windows/PlatformANGLE.h +++ b/windows/PlatformANGLE.h @@ -28,6 +28,7 @@ namespace filament::backend { 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; diff --git a/windows/flutter_angle_texture.cpp b/windows/flutter_angle_texture.cpp new file mode 100644 index 00000000..ed7ebc43 --- /dev/null +++ b/windows/flutter_angle_texture.cpp @@ -0,0 +1,230 @@ +#include "flutter_angle_texture.h" + +#include +#include +#include +#include + +#include "backend/platforms/PlatformEGL.h" + +#include + +namespace polyvox_filament { + +static void 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; + } + std::cout << name << " failed with " << err << std::endl; +} + +void FlutterAngleTexture::RenderCallback() { + _D3D11DeviceContext->CopyResource(_externalD3DTexture2D.Get(), + _internalD3DTexture2D.Get()); + _D3D11DeviceContext->Flush(); +} + +FlutterAngleTexture::FlutterAngleTexture( + flutter::PluginRegistrarWindows *pluginRegistrar, + flutter::TextureRegistrar *textureRegistrar, + std::unique_ptr> result, + uint32_t width, uint32_t height, ID3D11Device *D3D11Device, + ID3D11DeviceContext *D3D11DeviceContext, EGLConfig eglConfig, + EGLDisplay eglDisplay, EGLContext eglContext) + : _pluginRegistrar(pluginRegistrar), _textureRegistrar(textureRegistrar), + _width(width), _height(height), _D3D11Device(D3D11Device), + _D3D11DeviceContext(D3D11DeviceContext), _eglConfig(eglConfig), + _eglDisplay(eglDisplay), _eglContext(eglContext) { + + auto d3d11_texture2D_desc = D3D11_TEXTURE2D_DESC{0}; + d3d11_texture2D_desc.Width = width; + d3d11_texture2D_desc.Height = height; + d3d11_texture2D_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + d3d11_texture2D_desc.MipLevels = 1; + d3d11_texture2D_desc.ArraySize = 1; + d3d11_texture2D_desc.SampleDesc.Count = 1; + d3d11_texture2D_desc.SampleDesc.Quality = 0; + d3d11_texture2D_desc.Usage = D3D11_USAGE_DEFAULT; + d3d11_texture2D_desc.BindFlags = + D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; + d3d11_texture2D_desc.CPUAccessFlags = 0; + d3d11_texture2D_desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED; + + // create internal texture + auto hr = _D3D11Device->CreateTexture2D(&d3d11_texture2D_desc, nullptr, + &_internalD3DTexture2D); + if FAILED (hr) { + result->Error("ERROR", "Failed to create D3D texture", nullptr); + return; + ; + } + auto resource = Microsoft::WRL::ComPtr{}; + hr = _internalD3DTexture2D.As(&resource); + + if FAILED (hr) { + result->Error("ERROR", "Failed to create D3D texture", nullptr); + return; + ; + } + hr = resource->GetSharedHandle(&_internalD3DTextureHandle); + if FAILED (hr) { + result->Error("ERROR", "Failed to get shared handle to D3D texture", + nullptr); + return; + ; + } + _internalD3DTexture2D->AddRef(); + + std::cout << "Created internal D3D texture" << std::endl; + + // external + hr = _D3D11Device->CreateTexture2D(&d3d11_texture2D_desc, nullptr, + &_externalD3DTexture2D); + if FAILED (hr) { + result->Error("ERROR", "Failed to create D3D texture", nullptr); + return; + ; + } + hr = _externalD3DTexture2D.As(&resource); + + if FAILED (hr) { + result->Error("ERROR", "Failed to create D3D texture", nullptr); + return; + ; + } + hr = resource->GetSharedHandle(&_externalD3DTextureHandle); + if FAILED (hr) { + result->Error("ERROR", + "Failed to get shared handle to external D3D texture", + nullptr); + return; + ; + } + _externalD3DTexture2D->AddRef(); + + std::cout << "Created external D3D texture" << std::endl; + + EGLint pbufferAttribs[] = { + EGL_WIDTH, width, EGL_HEIGHT, height, + EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, + EGL_NONE, + }; + + auto surface = eglCreatePbufferFromClientBuffer( + _eglDisplay, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, + _internalD3DTextureHandle, _eglConfig, pbufferAttribs); + + if (!eglMakeCurrent(_eglDisplay, surface, surface, _eglContext)) { + // eglMakeCurrent failed + logEglError("eglMakeCurrent"); + return; + } + + glGenTextures(1, &glTextureId); + + if (glTextureId == 0) { + std::cout + << "Failed to generate OpenGL texture for ANGLE, OpenGL err was %d", + glGetError(); + return; + } + + glBindTexture(GL_TEXTURE_2D, glTextureId); + eglBindTexImage(_eglDisplay, surface, EGL_BACK_BUFFER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + // clearGlError + GLenum const error = glGetError(); + if (error != GL_NO_ERROR) { + std::cout << "Ignoring pending GL error " << error << std::endl; + } + char const *version; + + version = (char const *)glGetString(GL_VERSION); + std::cout << "Got version " << version << std::endl; + + EGLint major, minor; + glGetIntegerv(GL_MAJOR_VERSION, &major); + glGetIntegerv(GL_MINOR_VERSION, &minor); + + // platform = new filament::backend::PlatformANGLE(_internalD3DTextureHandle, + // width, height); + platform = new filament::backend::PlatformEGL(); //_internalD3DTextureHandle, + //width, height); + + _textureDescriptor = std::make_unique(); + _textureDescriptor->struct_size = sizeof(FlutterDesktopGpuSurfaceDescriptor); + _textureDescriptor->handle = _externalD3DTextureHandle; + _textureDescriptor->width = _textureDescriptor->visible_width = width; + _textureDescriptor->height = _textureDescriptor->visible_height = height; + _textureDescriptor->release_context = nullptr; + _textureDescriptor->release_callback = [](void *release_context) { + + }; + _textureDescriptor->format = kFlutterDesktopPixelFormatBGRA8888; + + texture = + std::make_unique(flutter::GpuSurfaceTexture( + kFlutterDesktopGpuSurfaceTypeDxgiSharedHandle, + [&](auto, auto) { return _textureDescriptor.get(); })); + + flutterTextureId = _textureRegistrar->RegisterTexture(texture.get()); + std::cout << "Registered Flutter texture ID " << flutterTextureId + << std::endl; + + std::vector resultList; + resultList.push_back(flutter::EncodableValue(flutterTextureId)); + resultList.push_back(flutter::EncodableValue((int64_t) nullptr)); + resultList.push_back(flutter::EncodableValue(glTextureId)); + result->Success(resultList); +} + +FlutterAngleTexture::~FlutterAngleTexture() {} + +} // namespace polyvox_filament \ No newline at end of file diff --git a/windows/flutter_angle_texture.h b/windows/flutter_angle_texture.h new file mode 100644 index 00000000..9698aee1 --- /dev/null +++ b/windows/flutter_angle_texture.h @@ -0,0 +1,81 @@ +#pragma once + +#ifndef _FLUTTER_ANGLE_TEXTURE_H +#define _FLUTTER_ANGLE_TEXTURE_H + +#include + +#include +#include +#include + +#include +#include + +#include "EGL/egl.h" +#include "EGL/eglext.h" +#include "EGL/eglplatform.h" +#include "GLES2/gl2.h" +#include "GLES2/gl2ext.h" +#include + +#include "PlatformANGLE.h" + +#include +#include + +typedef uint32_t GLuint; + +namespace polyvox_filament { + +class FlutterAngleTexture { + public: + FlutterAngleTexture( + flutter::PluginRegistrarWindows* pluginRegistrar, + flutter::TextureRegistrar* textureRegistrar, + std::unique_ptr> result, + uint32_t width, + uint32_t height, + ID3D11Device* D3D11Device, + ID3D11DeviceContext* D3D11DeviceContext, + EGLConfig eglConfig, + EGLDisplay eglDisplay, + EGLContext eglContext + ); + ~FlutterAngleTexture(); + + void RenderCallback(); + + int64_t flutterTextureId = 0; + GLuint glTextureId = 0; + std::unique_ptr texture; + filament::backend::Platform* platform = nullptr; + + + private: + flutter::PluginRegistrarWindows* _pluginRegistrar; + flutter::TextureRegistrar* _textureRegistrar; + uint32_t _width = 0; + uint32_t _height = 0; + bool logged = false; + std::shared_ptr _renderMutex; + + // Device + ID3D11Device* _D3D11Device = nullptr; + ID3D11DeviceContext* _D3D11DeviceContext = nullptr; + // Texture objects/shared handles + Microsoft::WRL::ComPtr _externalD3DTexture2D; + Microsoft::WRL::ComPtr _internalD3DTexture2D; + HANDLE _externalD3DTextureHandle = nullptr; + HANDLE _internalD3DTextureHandle = nullptr; + + EGLDisplay _eglDisplay = EGL_NO_DISPLAY; + EGLContext _eglContext = EGL_NO_CONTEXT; + EGLConfig _eglConfig = EGL_NO_CONFIG_KHR; + + std::unique_ptr _textureDescriptor = nullptr; + +}; + +} +#endif // _FLUTTER_ANGLE_TEXTURE \ No newline at end of file diff --git a/windows/lib/Debug/angle/backend.lib b/windows/lib/Debug/angle/backend.lib index a4f38683..f31b12a1 100644 --- a/windows/lib/Debug/angle/backend.lib +++ b/windows/lib/Debug/angle/backend.lib @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bf1bd7a89d00fa74f04c446aaeb9742793e02b42d53c0cf1375951f5948cd2ef -size 20108820 +oid sha256:1fcbbe01dc1cc92264b2bcf56a386c34c79fb2c90b5ab5f95e8aa37db3542788 +size 20903930 diff --git a/windows/polyvox_filament_plugin.cpp b/windows/polyvox_filament_plugin.cpp index c02ef6af..f201eb75 100644 --- a/windows/polyvox_filament_plugin.cpp +++ b/windows/polyvox_filament_plugin.cpp @@ -136,249 +136,253 @@ void render_callback(void* owner) { // this is the method on PolyvoxFilamentPlugin that will copy between D3D textures void PolyvoxFilamentPlugin::RenderCallback() { - #ifdef USE_ANGLE - _D3D11DeviceContext->CopyResource(_externalD3DTexture2D.Get(), - _internalD3DTexture2D.Get()); - _D3D11DeviceContext->Flush(); - #endif + std::lock_guard guard(*(_renderMutex.get())); if (_active) { + #ifdef USE_ANGLE + _active->RenderCallback(); + #endif _textureRegistrar->MarkTextureFrameAvailable(_active->flutterTextureId); } } #ifdef USE_ANGLE -bool PolyvoxFilamentPlugin::MakeD3DTexture(uint32_t width, uint32_t height,std::unique_ptr> result) { +bool PolyvoxFilamentPlugin::CreateSharedEGLContext() { + // D3D starts here + IDXGIAdapter* adapter_ = nullptr; - // 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); - // 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, + 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; // = eglInitialize(_eglDisplay, &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, + }; + _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_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 24, EGL_STENCIL_SIZE, 8, EGL_ALPHA_SIZE, 8, + EGL_NONE }; - // 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_) { - result->Error("ERROR", "Failed to locate default D3D adapter", nullptr); + + 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 + ); - 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)) { - result->Error("ERROR", "Failed to create D3D device", nullptr); - 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; - auto d3d11_texture2D_desc = D3D11_TEXTURE2D_DESC{0}; - d3d11_texture2D_desc.Width = width; - d3d11_texture2D_desc.Height = height; - d3d11_texture2D_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - d3d11_texture2D_desc.MipLevels = 1; - d3d11_texture2D_desc.ArraySize = 1; - d3d11_texture2D_desc.SampleDesc.Count = 1; - d3d11_texture2D_desc.SampleDesc.Quality = 0; - d3d11_texture2D_desc.Usage = D3D11_USAGE_DEFAULT; - d3d11_texture2D_desc.BindFlags = - D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; - d3d11_texture2D_desc.CPUAccessFlags = 0; - d3d11_texture2D_desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED; - - // create internal texture - hr = _D3D11Device->CreateTexture2D(&d3d11_texture2D_desc, nullptr, &_internalD3DTexture2D); - if FAILED(hr) - { - result->Error("ERROR", "Failed to create D3D texture", nullptr); - return false; - } - auto resource = Microsoft::WRL::ComPtr{}; - hr = _internalD3DTexture2D.As(&resource); - - if FAILED(hr) { - result->Error("ERROR", "Failed to create D3D texture", nullptr); - return false; - } - hr = resource->GetSharedHandle(&_internalD3DTextureHandle); - if FAILED(hr) { - result->Error("ERROR", "Failed to get shared handle to D3D texture", nullptr); - return false; - } - _internalD3DTexture2D->AddRef(); - - std::cout << "Created internal D3D texture" << std::endl; - - // external - hr = _D3D11Device->CreateTexture2D(&d3d11_texture2D_desc, nullptr, &_externalD3DTexture2D); - if FAILED(hr) - { - result->Error("ERROR", "Failed to create D3D texture", nullptr); - return false; - } - hr = _externalD3DTexture2D.As(&resource); - - if FAILED(hr) { - result->Error("ERROR", "Failed to create D3D texture", nullptr); - return false; - } - hr = resource->GetSharedHandle(&_externalD3DTextureHandle); - if FAILED(hr) { - result->Error("ERROR", "Failed to get shared handle to external D3D texture", nullptr); - return false; - } - _externalD3DTexture2D->AddRef(); - - std::cout << "Created external D3D texture" << std::endl; - - _platform = new filament::backend::PlatformANGLE(_internalD3DTextureHandle, width, height); - - _textureDescriptor = std::make_unique(); - _textureDescriptor->struct_size = sizeof(FlutterDesktopGpuSurfaceDescriptor); - _textureDescriptor->handle = _externalD3DTextureHandle; - _textureDescriptor->width = _textureDescriptor->visible_width = width; - _textureDescriptor->height = _textureDescriptor->visible_height = height; - _textureDescriptor->release_context = nullptr; - _textureDescriptor->release_callback = [](void* release_context) {}; - _textureDescriptor->format = kFlutterDesktopPixelFormatBGRA8888; - - _texture = - std::make_unique(flutter::GpuSurfaceTexture( - kFlutterDesktopGpuSurfaceTypeDxgiSharedHandle, - [&](auto, auto) { return _textureDescriptor.get(); })); - - _flutterTextureId = _textureRegistrar->RegisterTexture(_texture.get()); - std::cout << "Registered Flutter texture ID " << _flutterTextureId << std::endl; - - std::vector resultList; - resultList.push_back(flutter::EncodableValue(_flutterTextureId)); - resultList.push_back(flutter::EncodableValue((int64_t)nullptr)); - resultList.push_back(flutter::EncodableValue(_platform->glTextureId)); - result->Success(resultList); - return true; + return _active->flutterTextureId != -1; } -#else -bool PolyvoxFilamentPlugin::MakeOpenGLTexture(uint32_t width, uint32_t height,std::unique_ptr> result) { +#else +bool PolyvoxFilamentPlugin::CreateSharedWGLContext() { HWND hwnd = _pluginRegistrar->GetView() ->GetNativeWindow(); HDC whdc = GetDC(hwnd); if (whdc == NULL) { - result->Error("ERROR", "No device context for temporary window", nullptr); + std::cout << "No device context for temporary window" << std::endl; return false; } - - if(!_renderMutex.get()) { - _renderMutex = std::make_shared(); - } - - - // we need a single context (since this will be passed to the renderer) - // if this is the first time we are attempting to create a texture, let's create the context - if(_context == NULL) { - std::cout << "No GL context exists, creating" << std::endl; + 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 - }; + 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); + 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)) { - result->Error("ERROR", "Failed to acquire temporary context", nullptr); + // 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; } + } - GLenum err = glGetError(); + wglMakeCurrent(NULL, NULL); + wglDeleteContext(tempContext); - if(err != GL_NO_ERROR) { - result->Error("ERROR", "GL Error @ 455 %d", err); - return false; - } + if (!_context || !wglMakeCurrent(whdc, _context)) { + std::cout << "Failed to create OpenGL context." << std::endl; + return false; + } - PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs = nullptr; - wglCreateContextAttribs = - (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress( - "wglCreateContextAttribsARB"); +} - if (!wglCreateContextAttribs) { - result->Error("ERROR", "Failed to resolve wglCreateContextAttribsARB", - nullptr); - return false; - } +bool PolyvoxFilamentPlugin::MakeOpenGLTexture(uint32_t width, uint32_t height,std::unique_ptr> result) { - 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)) { - result->Error("ERROR", "Failed to create OpenGL context."); - return false; - } - - } - if(_active.get()) { result->Error("ERROR", "Texture already exists. You must call destroyTexture before attempting to create a new one."); return false; @@ -397,18 +401,36 @@ bool PolyvoxFilamentPlugin::MakeOpenGLTexture(uint32_t width, uint32_t height,st return _active->flutterTextureId != -1; } -#endif +#endif + 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()); const auto width = (uint32_t)round(*(std::get_if(&(args->at(0))))); const auto height = (uint32_t)round(*(std::get_if(&(args->at(1))))); + // 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 + } + #ifdef USE_ANGLE bool success = MakeD3DTexture(width, height, std::move(result)); #else @@ -428,59 +450,55 @@ void PolyvoxFilamentPlugin::DestroyTexture( return; } - #ifdef USE_ANGLE - // TODO - result->Error("NOT_IMPLEMENTED", "Method is not implemented %s", methodCall.method_name()); - #else - auto sh = std::make_shared>>(std::move(result)); + + if(!_active) { + result->Success("Texture has already been detroyed, ignoring"); + return; + } - 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; + } - if(_active->flutterTextureId != *flutterTextureId) { - result->Error("TEXTURE_MISMATCH", "Specified texture ID is not active"); - return; - } + auto sh = std::make_shared>>(std::move(result)); + + // result->Error("NOT_IMPLEMENTED", "Method is not implemented %s", methodCall.method_name()); _textureRegistrar->UnregisterTexture(_active->flutterTextureId, [=, sharedResult=std::move(sh) ]() { + #ifdef USE_ANGLE + this->_active = nullptr; + #else + if(this->_inactive) { + HWND hwnd = _pluginRegistrar->GetView()->GetNativeWindow(); + HDC whdc = GetDC(hwnd); - if(this->_inactive) { - - HWND hwnd = _pluginRegistrar->GetView()->GetNativeWindow(); - - HDC whdc = GetDC(hwnd); - - if (!wglMakeCurrent(whdc, _context)) { - std::cout << "Failed to switch OpenGL context in destructor." << std::endl; - // result->Error("CONTEXT", "Failed to switch OpenGL context.", nullptr); - return; + if (!wglMakeCurrent(whdc, _context)) { + std::cout << "Failed to switch OpenGL context in destructor." << std::endl; + // result->Error("CONTEXT", "Failed to switch OpenGL context.", nullptr); + return; + } + glDeleteTextures(1, &this->_inactive->glTextureId); + wglMakeCurrent(NULL, NULL); } - glDeleteTextures(1, &this->_inactive->glTextureId); - wglMakeCurrent(NULL, NULL); - } - this->_inactive = std::move(this->_active); + this->_inactive = std::move(this->_active); + #endif auto unique = std::move(*(sharedResult.get())); unique->Success(flutter::EncodableValue(true)); - std::cout << "Destroyed OpenGLTextureBuffer." << std::endl; + std::cout << "Unregistered/destroyed texture." << std::endl; }); - #endif + + } void PolyvoxFilamentPlugin::HandleMethodCall( const flutter::MethodCall &methodCall, std::unique_ptr> result) { - // std::cout << methodCall.method_name() << std::endl; if (methodCall.method_name() == "getSharedContext") { - #ifdef USE_ANGLE - result->Success(flutter::EncodableValue((int64_t)nullptr)); - #else result->Success(flutter::EncodableValue((int64_t)_context)); - #endif } else if (methodCall.method_name() == "getResourceLoaderWrapper") { const ResourceLoaderWrapper *const resourceLoader = new ResourceLoaderWrapper(_loadResource, _freeResource, this); @@ -496,7 +514,7 @@ void PolyvoxFilamentPlugin::HandleMethodCall( result->Success(resultList); } else if(methodCall.method_name() == "getDriverPlatform") { #ifdef USE_ANGLE - result->Success(flutter::EncodableValue((int64_t)_platform)); + result->Success(flutter::EncodableValue((int64_t)_active->platform)); #else result->Success(flutter::EncodableValue((int64_t)nullptr)); #endif diff --git a/windows/polyvox_filament_plugin.h b/windows/polyvox_filament_plugin.h index 8b80519e..50ec325f 100644 --- a/windows/polyvox_filament_plugin.h +++ b/windows/polyvox_filament_plugin.h @@ -11,21 +11,11 @@ #include #include -#ifdef USE_ANGLE -#include -#include -#endif - #include "GL/GL.h" #include "GL/GLu.h" #ifdef USE_ANGLE -#include "EGL/egl.h" -#include "EGL/eglext.h" -#include "EGL/eglplatform.h" -#include "GLES2/gl2.h" -#include "GLES2/gl2ext.h" -#include "PlatformAngle.h" +#include "flutter_angle_texture.h" #else #include "opengl_texture_buffer.h" #endif @@ -53,33 +43,9 @@ public: flutter::PluginRegistrarWindows *_pluginRegistrar; flutter::TextureRegistrar *_textureRegistrar; - std::map _resources; - - std::unique_ptr _textureDescriptor = nullptr; - - #ifdef USE_ANGLE - // Device - ID3D11Device* _D3D11Device = nullptr; - ID3D11DeviceContext* _D3D11DeviceContext = nullptr; - // Texture objects/shared handles - Microsoft::WRL::ComPtr _externalD3DTexture2D; - Microsoft::WRL::ComPtr _internalD3DTexture2D; - HANDLE _externalD3DTextureHandle = nullptr; - HANDLE _internalD3DTextureHandle = nullptr; - filament::backend::PlatformANGLE* _platform = nullptr; - - bool MakeD3DTexture(uint32_t width, uint32_t height, std::unique_ptr> result); - #else std::shared_ptr _renderMutex; - std::unique_ptr _active = nullptr; - std::unique_ptr _inactive = nullptr; - - // shared OpenGLContext - HGLRC _context = NULL; - bool MakeOpenGLTexture(uint32_t width, uint32_t height, std::unique_ptr> result); - #endif - + void CreateTexture( const flutter::MethodCall &methodCall, std::unique_ptr> result); @@ -90,6 +56,25 @@ public: ResourceBuffer loadResource(const char *path); void freeResource(ResourceBuffer rbuf); + + private: + #ifdef USE_ANGLE + EGLContext _context = NULL; + EGLConfig _eglConfig = NULL; + EGLDisplay _eglDisplay = NULL; + std::unique_ptr _active = nullptr; + ID3D11Device* _D3D11Device = nullptr; + ID3D11DeviceContext* _D3D11DeviceContext = nullptr; + bool CreateSharedEGLContext(); + bool MakeD3DTexture(uint32_t width, uint32_t height, std::unique_ptr> result); + #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); + #endif }; } // namespace polyvox_filament