move flutter_filament plugin to federated structure
This commit is contained in:
17
flutter_filament_federated/flutter_filament/windows/.gitignore
vendored
Normal file
17
flutter_filament_federated/flutter_filament/windows/.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
flutter/
|
||||
|
||||
# Visual Studio user-specific files.
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# Visual Studio build-related files.
|
||||
x64/
|
||||
x86/
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
@@ -0,0 +1,283 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
set(PROJECT_NAME "flutter_filament")
|
||||
project(${PROJECT_NAME} LANGUAGES C CXX)
|
||||
|
||||
cmake_policy(VERSION 3.14...3.25)
|
||||
|
||||
# This value is used when generating builds using this plugin, so it must
|
||||
# not be changed
|
||||
set(PLUGIN_NAME "flutter_filament_plugin")
|
||||
|
||||
# Any new source files that you add to the plugin should be added here.
|
||||
list(APPEND PLUGIN_SOURCES
|
||||
"flutter_filament_plugin.cpp"
|
||||
"flutter_filament_plugin.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../ios/src/SceneManager.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../ios/src/FilamentViewer.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../ios/src/FlutterFilamentApi.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../ios/src/FlutterFilamentFFIApi.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../ios/src/StreamBufferAdapter.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../ios/src/TimeIt.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../ios/src/camutils/Manipulator.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../ios/src/camutils/Bookmark.cpp"
|
||||
)
|
||||
|
||||
set(USE_ANGLE FALSE)
|
||||
set(WGL_USE_BACKING_WINDOW TRUE)
|
||||
|
||||
if(USE_ANGLE)
|
||||
add_compile_definitions(USE_ANGLE)
|
||||
list(APPEND PLUGIN_SOURCES "flutter_angle_texture.cpp" "egl_context.cpp" )
|
||||
else()
|
||||
if(WGL_USE_BACKING_WINDOW)
|
||||
add_compile_definitions(WGL_USE_BACKING_WINDOW)
|
||||
endif()
|
||||
list(APPEND PLUGIN_SOURCES "wgl_context.cpp" "opengl_texture_buffer.cpp" "backing_window.cpp")
|
||||
# if(WGL_USE_BACKING_WINDOW)
|
||||
# list(APPEND PLUGIN_SOURCES )
|
||||
# else()
|
||||
# list(APPEND PLUGIN_SOURCES )
|
||||
# endif()
|
||||
endif()
|
||||
|
||||
# Define the plugin library target. Its name must not be changed (see comment
|
||||
# on PLUGIN_NAME above).
|
||||
add_library(${PLUGIN_NAME} SHARED
|
||||
"include/flutter_filament/flutter_filament_plugin_c_api.h"
|
||||
"flutter_filament_plugin_c_api.cpp"
|
||||
${PLUGIN_SOURCES}
|
||||
"include/material/image.c"
|
||||
)
|
||||
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
|
||||
apply_standard_settings(${PLUGIN_NAME})
|
||||
|
||||
set_target_properties(${PLUGIN_NAME} PROPERTIES
|
||||
CXX_VISIBILITY_PRESET hidden)
|
||||
target_compile_features(${PLUGIN_NAME} PUBLIC cxx_std_20)
|
||||
target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
|
||||
target_include_directories(${PLUGIN_NAME} INTERFACE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include"
|
||||
)
|
||||
|
||||
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include/filament")
|
||||
|
||||
if(USE_ANGLE)
|
||||
list(APPEND GL_LIBS
|
||||
EGL
|
||||
GLESv2
|
||||
)
|
||||
set(ANGLE_OR_OPENGL_DIR angle)
|
||||
add_library(EGL SHARED IMPORTED)
|
||||
set_property(TARGET EGL PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/angle/libEGL.dll.lib")
|
||||
set_property(TARGET EGL PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/angle/libEGL.dll.lib")
|
||||
set_property(TARGET EGL PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/angle/libEGL.dll.lib")
|
||||
add_library(GLESv2 SHARED IMPORTED)
|
||||
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")
|
||||
else()
|
||||
list(APPEND GL_LIBS
|
||||
bluegl
|
||||
opengl32
|
||||
dwmapi
|
||||
comctl32
|
||||
)
|
||||
set(ANGLE_OR_OPENGL_DIR opengl)
|
||||
add_library(bluegl SHARED IMPORTED)
|
||||
set_property(TARGET bluegl PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/opengl/bluegl.lib")
|
||||
set_property(TARGET bluegl PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/opengl/bluegl.lib")
|
||||
set_property(TARGET bluegl PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/opengl/bluegl.lib")
|
||||
endif()
|
||||
|
||||
add_library(backend SHARED IMPORTED)
|
||||
set_property(TARGET backend PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/${ANGLE_OR_OPENGL_DIR}/backend.lib")
|
||||
set_property(TARGET backend PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/${ANGLE_OR_OPENGL_DIR}/backend.lib")
|
||||
set_property(TARGET backend PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/${ANGLE_OR_OPENGL_DIR}/backend.lib")
|
||||
|
||||
add_library(geometry SHARED IMPORTED)
|
||||
set_property(TARGET geometry PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/geometry.lib")
|
||||
set_property(TARGET geometry PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/geometry.lib")
|
||||
set_property(TARGET geometry PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/geometry.lib")
|
||||
|
||||
add_library(filament SHARED IMPORTED)
|
||||
set_property(TARGET filament PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/${ANGLE_OR_OPENGL_DIR}/filament.lib")
|
||||
set_property(TARGET filament PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/${ANGLE_OR_OPENGL_DIR}/filament.lib")
|
||||
set_property(TARGET filament PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/${ANGLE_OR_OPENGL_DIR}/filament.lib")
|
||||
|
||||
add_library(filameshio SHARED IMPORTED)
|
||||
set_property(TARGET filameshio PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/filameshio.lib")
|
||||
set_property(TARGET filameshio PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/filameshio.lib")
|
||||
set_property(TARGET filameshio PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/filameshio.lib")
|
||||
|
||||
add_library(filamat SHARED IMPORTED)
|
||||
set_property(TARGET filamat PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/filamat.lib")
|
||||
set_property(TARGET filamat PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/filamat.lib")
|
||||
set_property(TARGET filamat PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/filamat.lib")
|
||||
|
||||
add_library(utils SHARED IMPORTED)
|
||||
set_property(TARGET utils PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/utils.lib")
|
||||
set_property(TARGET utils PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/utils.lib")
|
||||
set_property(TARGET utils PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/utils.lib")
|
||||
|
||||
add_library(filabridge SHARED IMPORTED)
|
||||
set_property(TARGET filabridge PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/filabridge.lib")
|
||||
set_property(TARGET filabridge PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/filabridge.lib")
|
||||
set_property(TARGET filabridge PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/filabridge.lib")
|
||||
|
||||
add_library(gltfio SHARED IMPORTED)
|
||||
set_property(TARGET gltfio PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/gltfio.lib")
|
||||
set_property(TARGET gltfio PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/gltfio.lib")
|
||||
set_property(TARGET gltfio PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/gltfio.lib")
|
||||
|
||||
add_library(gltfio_core SHARED IMPORTED)
|
||||
set_property(TARGET gltfio_core PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/gltfio_core.lib")
|
||||
set_property(TARGET gltfio_core PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/gltfio_core.lib")
|
||||
set_property(TARGET gltfio_core PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/gltfio_core.lib")
|
||||
|
||||
add_library(image SHARED IMPORTED)
|
||||
set_property(TARGET image PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/image.lib")
|
||||
set_property(TARGET image PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/image.lib")
|
||||
set_property(TARGET image PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/image.lib")
|
||||
|
||||
add_library(imageio STATIC IMPORTED)
|
||||
set_property(TARGET imageio PROPERTY IMPORTED_LOCATION_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/imageio.lib")
|
||||
set_property(TARGET imageio PROPERTY IMPORTED_LOCATION_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/imageio.lib")
|
||||
set_property(TARGET imageio PROPERTY IMPORTED_LOCATION_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/imageio.lib")
|
||||
|
||||
add_library(tinyexr STATIC IMPORTED)
|
||||
set_property(TARGET tinyexr PROPERTY IMPORTED_LOCATION_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/tinyexr.lib")
|
||||
set_property(TARGET tinyexr PROPERTY IMPORTED_LOCATION_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/tinyexr.lib")
|
||||
set_property(TARGET tinyexr PROPERTY IMPORTED_LOCATION_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/tinyexr.lib")
|
||||
|
||||
add_library(camutils SHARED IMPORTED)
|
||||
set_property(TARGET camutils PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/camutils.lib")
|
||||
set_property(TARGET camutils PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/camutils.lib")
|
||||
set_property(TARGET camutils PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/camutils.lib")
|
||||
|
||||
add_library(filaflat SHARED IMPORTED)
|
||||
set_property(TARGET filaflat PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/filaflat.lib")
|
||||
set_property(TARGET filaflat PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/filaflat.lib")
|
||||
set_property(TARGET filaflat PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/filaflat.lib")
|
||||
|
||||
add_library(dracodec SHARED IMPORTED)
|
||||
set_property(TARGET dracodec PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/dracodec.lib")
|
||||
set_property(TARGET dracodec PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/dracodec.lib")
|
||||
set_property(TARGET dracodec PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/dracodec.lib")
|
||||
|
||||
add_library(ibl SHARED IMPORTED)
|
||||
set_property(TARGET ibl PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/ibl.lib")
|
||||
set_property(TARGET ibl PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/ibl.lib")
|
||||
set_property(TARGET ibl PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/ibl.lib")
|
||||
|
||||
add_library(ktxreader SHARED IMPORTED)
|
||||
set_property(TARGET ktxreader PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/ktxreader.lib")
|
||||
set_property(TARGET ktxreader PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/ktxreader.lib")
|
||||
set_property(TARGET ktxreader PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/ktxreader.lib")
|
||||
|
||||
add_library(stb SHARED IMPORTED)
|
||||
set_property(TARGET stb PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/stb.lib")
|
||||
set_property(TARGET stb PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/stb.lib")
|
||||
set_property(TARGET stb PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/stb.lib")
|
||||
|
||||
add_library(bluevk SHARED IMPORTED)
|
||||
set_property(TARGET bluevk PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/bluevk.lib")
|
||||
set_property(TARGET bluevk PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/bluevk.lib")
|
||||
set_property(TARGET bluevk PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/bluevk.lib")
|
||||
|
||||
add_library(vkshaders SHARED IMPORTED)
|
||||
set_property(TARGET vkshaders PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/vkshaders.lib")
|
||||
set_property(TARGET vkshaders PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/vkshaders.lib")
|
||||
set_property(TARGET vkshaders PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/vkshaders.lib")
|
||||
|
||||
add_library(uberzlib SHARED IMPORTED)
|
||||
set_property(TARGET uberzlib PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/uberzlib.lib")
|
||||
set_property(TARGET uberzlib PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/uberzlib.lib")
|
||||
set_property(TARGET uberzlib PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/uberzlib.lib")
|
||||
|
||||
add_library(smol-v SHARED IMPORTED)
|
||||
set_property(TARGET smol-v PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/smol-v.lib")
|
||||
set_property(TARGET smol-v PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/smol-v.lib")
|
||||
set_property(TARGET smol-v PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/smol-v.lib")
|
||||
|
||||
add_library(uberarchive SHARED IMPORTED)
|
||||
set_property(TARGET uberarchive PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/${ANGLE_OR_OPENGL_DIR}/uberarchive.lib")
|
||||
set_property(TARGET uberarchive PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/${ANGLE_OR_OPENGL_DIR}/uberarchive.lib")
|
||||
set_property(TARGET uberarchive PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/${ANGLE_OR_OPENGL_DIR}/uberarchive.lib")
|
||||
|
||||
add_library(meshoptimizer SHARED IMPORTED)
|
||||
set_property(TARGET meshoptimizer PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/meshoptimizer.lib")
|
||||
set_property(TARGET meshoptimizer PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/meshoptimizer.lib")
|
||||
set_property(TARGET meshoptimizer PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/meshoptimizer.lib")
|
||||
|
||||
add_library(basis_transcoder SHARED IMPORTED)
|
||||
set_property(TARGET basis_transcoder PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/basis_transcoder.lib")
|
||||
set_property(TARGET basis_transcoder PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/basis_transcoder.lib")
|
||||
set_property(TARGET basis_transcoder PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/basis_transcoder.lib")
|
||||
|
||||
add_library(z SHARED IMPORTED)
|
||||
set_property(TARGET z PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/z.lib")
|
||||
set_property(TARGET z PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/z.lib")
|
||||
set_property(TARGET z PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/z.lib")
|
||||
|
||||
add_library(zstd SHARED IMPORTED)
|
||||
set_property(TARGET zstd PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/zstd.lib")
|
||||
set_property(TARGET zstd PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/zstd.lib")
|
||||
set_property(TARGET zstd PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/zstd.lib")
|
||||
|
||||
add_library(png SHARED IMPORTED)
|
||||
set_property(TARGET png PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/png.lib")
|
||||
set_property(TARGET png PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/png.lib")
|
||||
set_property(TARGET png PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib/Release/png.lib")
|
||||
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../ios/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
target_link_libraries(${PLUGIN_NAME} PRIVATE
|
||||
flutter
|
||||
flutter_wrapper_plugin
|
||||
gltfio
|
||||
gltfio_core
|
||||
filament
|
||||
backend
|
||||
geometry
|
||||
filamat
|
||||
filabridge
|
||||
camutils
|
||||
filaflat
|
||||
dracodec
|
||||
ibl
|
||||
ktxreader
|
||||
image
|
||||
imageio
|
||||
utils
|
||||
stb
|
||||
uberzlib
|
||||
smol-v
|
||||
uberarchive
|
||||
meshoptimizer
|
||||
geometry
|
||||
basis_transcoder
|
||||
z
|
||||
zstd
|
||||
png
|
||||
tinyexr
|
||||
Shlwapi
|
||||
${GL_LIBS}
|
||||
)
|
||||
|
||||
# List of absolute paths to libraries that should be bundled with the plugin
|
||||
if(USE_ANGLE)
|
||||
set(flutter_filament_bundled_libraries
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/angle/libEGL.dll
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/angle/libGLESv2.dll
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/libc++.dll
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/third_party_abseil-cpp_absl.dll
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/third_party_zlib.dll
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,357 @@
|
||||
#include "backing_window.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include <Windows.h>
|
||||
#include <dwmapi.h>
|
||||
#include <ShObjIdl.h>
|
||||
|
||||
#pragma comment(lib, "dwmapi.lib")
|
||||
#pragma comment(lib, "comctl32.lib")
|
||||
|
||||
namespace flutter_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;
|
||||
|
||||
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) {
|
||||
if (!g_set_window_composition_attribute_initialized) {
|
||||
auto user32 = ::GetModuleHandleA("user32.dll");
|
||||
if (user32) {
|
||||
g_set_window_composition_attribute =
|
||||
reinterpret_cast<_SetWindowCompositionAttribute>(
|
||||
::GetProcAddress(user32, "SetWindowCompositionAttribute"));
|
||||
if (g_set_window_composition_attribute) {
|
||||
g_set_window_composition_attribute_initialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
ACCENT_POLICY accent = {static_cast<ACCENT_STATE>(accent_state), 2,
|
||||
static_cast<DWORD>(gradient_color), 0};
|
||||
WINDOWCOMPOSITIONATTRIBDATA data;
|
||||
data.Attrib = WCA_ACCENT_POLICY;
|
||||
data.pvData = &accent;
|
||||
data.cbData = sizeof(accent);
|
||||
g_set_window_composition_attribute(window, &data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LRESULT CALLBACK FilamentWindowProc(HWND const window, UINT const message,
|
||||
WPARAM const wparam,
|
||||
LPARAM const lparam) noexcept {
|
||||
switch (message) {
|
||||
case WM_MOUSEMOVE: {
|
||||
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) {
|
||||
HWND flutterRootWindow = reinterpret_cast<HWND>(user_data);
|
||||
::SetForegroundWindow(flutterRootWindow);
|
||||
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: {
|
||||
// Prevent erasing of |window| when it is unfocused and minimized or
|
||||
// moved out of screen etc.
|
||||
break;
|
||||
}
|
||||
case WM_SIZE:
|
||||
break;
|
||||
case WM_MOVE:
|
||||
case WM_MOVING:
|
||||
case WM_ACTIVATE:
|
||||
case WM_WINDOWPOSCHANGED: {
|
||||
// NativeViewCore::GetInstance()->SetHitTestBehavior(0);
|
||||
auto user_data = ::GetWindowLongPtr(window, GWLP_USERDATA);
|
||||
if (user_data) {
|
||||
HWND flutterRootWindow = reinterpret_cast<HWND>(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);
|
||||
}
|
||||
|
||||
BackingWindow::BackingWindow(flutter::PluginRegistrarWindows *pluginRegistrar,
|
||||
int width,
|
||||
int height,
|
||||
int left,
|
||||
int top) : _width(width), _height(height), _left(left), _top(top) {
|
||||
// a Flutter application actually has two windows - the innner window contains the FlutterView.
|
||||
// although we will use the outer window for various events, we always position things relative to the inner window.
|
||||
_flutterViewWindow = pluginRegistrar->GetView()->GetNativeWindow();
|
||||
_flutterRootWindow = ::GetAncestor(_flutterViewWindow, GA_ROOT);
|
||||
|
||||
RECT flutterChildRect;
|
||||
::GetWindowRect(_flutterViewWindow, &flutterChildRect);
|
||||
|
||||
// set composition to allow transparency
|
||||
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_MOUSEMOVE: {
|
||||
break;
|
||||
}
|
||||
case WM_ACTIVATE: {
|
||||
RECT rootWindowRect;
|
||||
::GetWindowRect(_flutterViewWindow, &rootWindowRect);
|
||||
// Position |native_view| such that it's z order is behind |window_| &
|
||||
// redraw aswell.
|
||||
::SetWindowPos(_windowHandle, _flutterRootWindow, rootWindowRect.left + _left,
|
||||
rootWindowRect.top + _top, _width,
|
||||
_height, SWP_NOACTIVATE);
|
||||
break;
|
||||
}
|
||||
case WM_SIZE: {
|
||||
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::milliseconds>(
|
||||
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);
|
||||
}
|
||||
|
||||
RECT flutterViewRect;
|
||||
::GetWindowRect(_flutterViewWindow, &flutterViewRect);
|
||||
::SetWindowPos(_windowHandle, _flutterRootWindow, flutterViewRect.left + _left,
|
||||
flutterViewRect.top + _top, _width, _height,
|
||||
SWP_NOACTIVATE);
|
||||
},
|
||||
last_thread_time_)
|
||||
.detach();
|
||||
}
|
||||
last_wm_size_wparam_ = wparam;
|
||||
break;
|
||||
}
|
||||
case WM_MOVE:
|
||||
case WM_MOVING:
|
||||
case WM_WINDOWPOSCHANGED: {
|
||||
RECT rootWindowRect;
|
||||
::GetWindowRect(_flutterViewWindow, &rootWindowRect);
|
||||
if (rootWindowRect.right - rootWindowRect.left > 0 &&
|
||||
rootWindowRect.bottom - rootWindowRect.top > 0) {
|
||||
::SetWindowPos(_windowHandle, _flutterRootWindow, rootWindowRect.left + _left,
|
||||
rootWindowRect.top + _top, _width,
|
||||
_height, SWP_NOACTIVATE);
|
||||
// |window_| is minimized.
|
||||
if (rootWindowRect.left < 0 && rootWindowRect.top < 0 &&
|
||||
rootWindowRect.right < 0 && rootWindowRect.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 std::nullopt;
|
||||
});
|
||||
|
||||
// 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(0);
|
||||
::RegisterClassExW(&window_class);
|
||||
_windowHandle = ::CreateWindow(kClassName, kWindowName, WS_OVERLAPPEDWINDOW,
|
||||
0, 0, _width, _height, 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));
|
||||
|
||||
auto style = ::GetWindowLong(_windowHandle, GWL_STYLE);
|
||||
style &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX |
|
||||
WS_EX_APPWINDOW);
|
||||
::SetWindowLong(_windowHandle, GWL_STYLE, style);
|
||||
|
||||
::SetWindowLongPtr(_windowHandle, GWLP_USERDATA,
|
||||
reinterpret_cast<LONG>(_flutterRootWindow));
|
||||
|
||||
RECT flutterViewRect;
|
||||
::GetWindowRect(_flutterViewWindow, &flutterViewRect);
|
||||
|
||||
::SetWindowPos(_windowHandle, _flutterRootWindow, flutterViewRect.left + _left,
|
||||
flutterViewRect.top + _top, _width, _height,
|
||||
SWP_NOACTIVATE);
|
||||
|
||||
// remove taskbar entry for the window we created
|
||||
ITaskbarList3* taskbar = nullptr;
|
||||
::CoCreateInstance(CLSID_TaskbarList, 0, CLSCTX_INPROC_SERVER,
|
||||
IID_PPV_ARGS(&taskbar));
|
||||
taskbar->DeleteTab(_windowHandle);
|
||||
taskbar->Release();
|
||||
|
||||
::ShowWindow(_windowHandle, SW_SHOW);
|
||||
::ShowWindow(_flutterViewWindow, SW_SHOW);
|
||||
::SetForegroundWindow(_flutterViewWindow);
|
||||
::SetFocus(_flutterViewWindow);
|
||||
LONG ex_style = ::GetWindowLong(_flutterRootWindow, GWL_EXSTYLE);
|
||||
ex_style &= ~(WS_EX_TRANSPARENT | WS_EX_LAYERED);
|
||||
::SetWindowLong(_flutterRootWindow, GWL_EXSTYLE, ex_style);
|
||||
}
|
||||
|
||||
void BackingWindow::Resize(int width, int height, int left, int top) {
|
||||
_width = width;
|
||||
_height = height;
|
||||
_left = left;
|
||||
_top = top;
|
||||
RECT flutterViewRect;
|
||||
::GetWindowRect(_flutterViewWindow, &flutterViewRect);
|
||||
std::cout << "Resizing to " << _width << " x " << _height << " with LT" << _left << " " << _top << " flutter view rect" << flutterViewRect.left << " " << flutterViewRect.top << " " << flutterViewRect.right << " " << flutterViewRect.bottom << std::endl;
|
||||
|
||||
::SetWindowPos(_windowHandle, _flutterRootWindow, flutterViewRect.left + _left,
|
||||
flutterViewRect.top + _top, _width, _height,
|
||||
SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
HWND BackingWindow::GetHandle() { return _windowHandle; }
|
||||
} // namespace flutter_filament
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef _BACKING_WINDOW_H
|
||||
#define _BACKING_WINDOW_H
|
||||
|
||||
#include <flutter/method_channel.h>
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
#include <flutter/standard_method_codec.h>
|
||||
|
||||
namespace flutter_filament {
|
||||
|
||||
class BackingWindow {
|
||||
public:
|
||||
BackingWindow(
|
||||
flutter::PluginRegistrarWindows *pluginRegistrar,
|
||||
int width,
|
||||
int height,
|
||||
int left,
|
||||
int top);
|
||||
HWND GetHandle();
|
||||
void Resize(int width, int height, int left, int top);
|
||||
private:
|
||||
HWND _windowHandle;
|
||||
HWND _flutterRootWindow;
|
||||
HWND _flutterViewWindow;
|
||||
uint32_t _width = 0;
|
||||
uint32_t _height = 0;
|
||||
uint32_t _left = 0;
|
||||
uint32_t _top = 0;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,200 @@
|
||||
|
||||
#include "egl_context.h"
|
||||
|
||||
#define FILAMENT_USE_EXTERNAL_GLES3
|
||||
#include <gl_headers.h>
|
||||
|
||||
#pragma comment(lib, "dwmapi.lib")
|
||||
#pragma comment(lib, "comctl32.lib")
|
||||
|
||||
namespace flutter_filament {
|
||||
|
||||
FlutterEGLContext::FlutterEGLContext(
|
||||
flutter::PluginRegistrarWindows* pluginRegistrar,
|
||||
flutter::TextureRegistrar* textureRegistrar) : FlutterRenderContext(pluginRegistrar, 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;
|
||||
}
|
||||
|
||||
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<UINT>(feature_levels.size()), D3D11_SDK_VERSION,
|
||||
&_D3D11Device, 0, &_D3D11DeviceContext);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
std::cout << "Failed to create D3D device" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
Microsoft::WRL::ComPtr<IDXGIDevice> 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;
|
||||
}
|
||||
|
||||
_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<PFNEGLGETPLATFORMDISPLAYEXTPROC>(
|
||||
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;
|
||||
}
|
||||
|
||||
glext::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)) {
|
||||
std::cout << "Failed to find EGL config" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
auto ctx = eglCreateContext(_eglDisplay, _eglConfig, EGL_NO_CONTEXT,contextAttribs);
|
||||
_context = (void*)ctx;
|
||||
|
||||
if (UTILS_UNLIKELY(_context == EGL_NO_CONTEXT)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void FlutterEGLContext::CreateRenderingSurface(
|
||||
uint32_t width, uint32_t height,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result,
|
||||
uint32_t left, uint32_t top
|
||||
) {
|
||||
|
||||
glext::importGLESExtensionsEntryPoints();
|
||||
|
||||
if(left != 0 || top != 0) {
|
||||
result->Error("ERROR",
|
||||
"Rendering with EGL uses a Texture render target/Flutter widget and does not need a window offset.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_active.get()) {
|
||||
result->Error("ERROR",
|
||||
"Texture already exists. You must call destroyTexture before "
|
||||
"attempting to create a new one.");
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<FlutterTextureBuffer> active = std::make_unique<FlutterAngleTexture>(
|
||||
_pluginRegistrar, _textureRegistrar, std::move(result), width, height,
|
||||
_D3D11Device, _D3D11DeviceContext, _eglConfig, _eglDisplay, _context,
|
||||
[=](size_t width, size_t height) {
|
||||
std::cout << "RESIZE" << std::endl;
|
||||
std::vector<int64_t> list;
|
||||
list.push_back((int64_t)width);
|
||||
list.push_back((int64_t)height);
|
||||
// auto val = std::make_unique<flutter::EncodableValue>(list);
|
||||
// this->_channel->InvokeMethod("resize", std::move(val), nullptr);
|
||||
});
|
||||
_active = std::move(active);
|
||||
|
||||
}
|
||||
|
||||
void FlutterEGLContext::RenderCallback() {
|
||||
if(_active.get()) {
|
||||
((FlutterAngleTexture*)_active.get())->RenderCallback();
|
||||
}
|
||||
}
|
||||
|
||||
void* FlutterEGLContext::GetSharedContext() {
|
||||
return (void*)_context;
|
||||
}
|
||||
|
||||
void* FlutterEGLContext::GetPlatform() {
|
||||
return (void*)_platform;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef _EGL_CONTEXT_H
|
||||
#define _EGL_CONTEXT_H
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <flutter/method_channel.h>
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
#include <flutter/standard_method_codec.h>
|
||||
#include <flutter/texture_registrar.h>
|
||||
|
||||
#include "flutter_angle_texture.h"
|
||||
#include "backend/platforms/PlatformEGL.h"
|
||||
#include "flutter_render_context.h"
|
||||
|
||||
namespace flutter_filament {
|
||||
|
||||
class FlutterEGLContext : public FlutterRenderContext {
|
||||
public:
|
||||
FlutterEGLContext(flutter::PluginRegistrarWindows* pluginRegistrar, flutter::TextureRegistrar* textureRegistrar);
|
||||
void* GetSharedContext();
|
||||
void RenderCallback();
|
||||
void* GetPlatform();
|
||||
void CreateRenderingSurface(uint32_t width, uint32_t height, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result, uint32_t left, uint32_t top );
|
||||
|
||||
private:
|
||||
void* _context = nullptr;
|
||||
EGLConfig _eglConfig = NULL;
|
||||
EGLDisplay _eglDisplay = NULL;
|
||||
ID3D11Device* _D3D11Device = nullptr;
|
||||
ID3D11DeviceContext* _D3D11DeviceContext = nullptr;
|
||||
filament::backend::Platform* _platform = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,243 @@
|
||||
#include "flutter_angle_texture.h"
|
||||
|
||||
#include <flutter/method_channel.h>
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
#include <flutter/standard_method_codec.h>
|
||||
#include <flutter/texture_registrar.h>
|
||||
|
||||
#include <thread>
|
||||
|
||||
namespace flutter_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() {
|
||||
glFinish();
|
||||
_D3D11DeviceContext->CopyResource(_externalD3DTexture2D.Get(),
|
||||
_internalD3DTexture2D.Get());
|
||||
_D3D11DeviceContext->Flush();
|
||||
}
|
||||
|
||||
FlutterAngleTexture::~FlutterAngleTexture() {
|
||||
if (_eglDisplay != EGL_NO_DISPLAY && _eglSurface != EGL_NO_SURFACE) {
|
||||
eglReleaseTexImage(_eglDisplay, _eglSurface, EGL_BACK_BUFFER);
|
||||
}
|
||||
auto success = eglDestroySurface(this->_eglDisplay, this->_eglSurface);
|
||||
if(success != EGL_TRUE) {
|
||||
std::cout << "Failed to destroy EGL Surface" << std::endl;
|
||||
}
|
||||
_internalD3DTexture2D->Release();
|
||||
_externalD3DTexture2D->Release();
|
||||
glDeleteTextures(1, &this->glTextureId);
|
||||
}
|
||||
|
||||
FlutterAngleTexture::FlutterAngleTexture(
|
||||
flutter::PluginRegistrarWindows *pluginRegistrar,
|
||||
flutter::TextureRegistrar *textureRegistrar,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result,
|
||||
uint32_t width, uint32_t height, ID3D11Device *D3D11Device,
|
||||
ID3D11DeviceContext *D3D11DeviceContext, EGLConfig eglConfig,
|
||||
EGLDisplay eglDisplay, EGLContext eglContext,
|
||||
std::function<void(size_t, size_t)> onResizeRequested
|
||||
)
|
||||
: _pluginRegistrar(pluginRegistrar), _textureRegistrar(textureRegistrar),
|
||||
_width(width), _height(height), _D3D11Device(D3D11Device),
|
||||
_D3D11DeviceContext(D3D11DeviceContext), _eglConfig(eglConfig),
|
||||
_eglDisplay(eglDisplay), _eglContext(eglContext), _onResizeRequested(onResizeRequested) {
|
||||
|
||||
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<IDXGIResource>{};
|
||||
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,
|
||||
};
|
||||
|
||||
_eglSurface = eglCreatePbufferFromClientBuffer(
|
||||
_eglDisplay, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
|
||||
_internalD3DTextureHandle, _eglConfig, pbufferAttribs);
|
||||
|
||||
if (!eglMakeCurrent(_eglDisplay, _eglSurface, _eglSurface, _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, _eglSurface, 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);
|
||||
|
||||
_textureDescriptor = std::make_unique<FlutterDesktopGpuSurfaceDescriptor>();
|
||||
_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::TextureVariant>(flutter::GpuSurfaceTexture(
|
||||
kFlutterDesktopGpuSurfaceTypeDxgiSharedHandle,
|
||||
[&](size_t width, size_t height) {
|
||||
if(width != this->_width || height != this->_height) {
|
||||
this->_onResizeRequested(width, height);
|
||||
}
|
||||
return _textureDescriptor.get();
|
||||
}));
|
||||
|
||||
flutterTextureId = _textureRegistrar->RegisterTexture(texture.get());
|
||||
std::cout << "Registered Flutter texture ID " << flutterTextureId
|
||||
<< std::endl;
|
||||
|
||||
std::vector<flutter::EncodableValue> resultList;
|
||||
resultList.push_back(flutter::EncodableValue(flutterTextureId));
|
||||
resultList.push_back(flutter::EncodableValue((int64_t) nullptr));
|
||||
resultList.push_back(flutter::EncodableValue(glTextureId));
|
||||
resultList.push_back(flutter::EncodableValue((int64_t) eglContext));
|
||||
result->Success(resultList);
|
||||
}
|
||||
|
||||
} // namespace flutter_filament
|
||||
@@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef _FLUTTER_ANGLE_TEXTURE_H
|
||||
#define _FLUTTER_ANGLE_TEXTURE_H
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <flutter/texture_registrar.h>
|
||||
#include <flutter/method_channel.h>
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
|
||||
#include <d3d.h>
|
||||
#include <d3d11.h>
|
||||
|
||||
#include "EGL/egl.h"
|
||||
#include "EGL/eglext.h"
|
||||
#include "EGL/eglplatform.h"
|
||||
#include "GLES2/gl2.h"
|
||||
#include "GLES2/gl2ext.h"
|
||||
#include <GLES3/gl31.h>
|
||||
|
||||
#include <Windows.h>
|
||||
#include <wrl.h>
|
||||
|
||||
#include "flutter_texture_buffer.h"
|
||||
|
||||
typedef uint32_t GLuint;
|
||||
|
||||
namespace flutter_filament {
|
||||
|
||||
class FlutterAngleTexture : public FlutterTextureBuffer {
|
||||
public:
|
||||
FlutterAngleTexture(
|
||||
flutter::PluginRegistrarWindows* pluginRegistrar,
|
||||
flutter::TextureRegistrar* textureRegistrar,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
ID3D11Device* D3D11Device,
|
||||
ID3D11DeviceContext* D3D11DeviceContext,
|
||||
EGLConfig eglConfig,
|
||||
EGLDisplay eglDisplay,
|
||||
EGLContext eglContext,
|
||||
std::function<void(size_t, size_t)> onResizeRequested
|
||||
);
|
||||
~FlutterAngleTexture();
|
||||
|
||||
void RenderCallback();
|
||||
|
||||
GLuint glTextureId = 0;
|
||||
std::unique_ptr<flutter::TextureVariant> texture;
|
||||
|
||||
private:
|
||||
flutter::PluginRegistrarWindows* _pluginRegistrar;
|
||||
flutter::TextureRegistrar* _textureRegistrar;
|
||||
uint32_t _width = 0;
|
||||
uint32_t _height = 0;
|
||||
bool logged = false;
|
||||
std::function<void(size_t, size_t)> _onResizeRequested;
|
||||
|
||||
// Device
|
||||
ID3D11Device* _D3D11Device = nullptr;
|
||||
ID3D11DeviceContext* _D3D11DeviceContext = nullptr;
|
||||
// Texture objects/shared handles
|
||||
Microsoft::WRL::ComPtr<ID3D11Texture2D> _externalD3DTexture2D;
|
||||
Microsoft::WRL::ComPtr<ID3D11Texture2D> _internalD3DTexture2D;
|
||||
HANDLE _externalD3DTextureHandle = nullptr;
|
||||
HANDLE _internalD3DTextureHandle = nullptr;
|
||||
|
||||
EGLDisplay _eglDisplay = EGL_NO_DISPLAY;
|
||||
EGLContext _eglContext = EGL_NO_CONTEXT;
|
||||
EGLConfig _eglConfig = EGL_NO_CONFIG_KHR;
|
||||
EGLSurface _eglSurface = EGL_NO_SURFACE;
|
||||
|
||||
std::unique_ptr<FlutterDesktopGpuSurfaceDescriptor> _textureDescriptor = nullptr;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
#endif // _FLUTTER_ANGLE_TEXTURE
|
||||
@@ -0,0 +1,270 @@
|
||||
#pragma comment(lib, "dxgi.lib")
|
||||
#pragma comment(lib, "d3d11.lib")
|
||||
|
||||
#include "flutter_filament_plugin.h"
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <flutter/method_channel.h>
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
#include <flutter/standard_method_codec.h>
|
||||
#include <flutter/texture_registrar.h>
|
||||
|
||||
#include <codecvt>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
#include <iostream>
|
||||
#include <locale>
|
||||
#include <map>
|
||||
#include <math.h>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
|
||||
#include "FlutterFilamentApi.h"
|
||||
|
||||
#include "flutter_render_context.h"
|
||||
|
||||
#if USE_ANGLE
|
||||
#include "egl_context.h"
|
||||
#else
|
||||
#include "wgl_context.h"
|
||||
#endif
|
||||
|
||||
namespace flutter_filament {
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
|
||||
void FlutterFilamentPlugin::RegisterWithRegistrar(
|
||||
flutter::PluginRegistrarWindows *registrar) {
|
||||
auto channel =
|
||||
std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
|
||||
registrar->messenger(), "app.polyvox.filament/event",
|
||||
&flutter::StandardMethodCodec::GetInstance());
|
||||
|
||||
auto plugin = std::make_unique<FlutterFilamentPlugin>(
|
||||
registrar->texture_registrar(), registrar, channel);
|
||||
|
||||
registrar->AddPlugin(std::move(plugin));
|
||||
}
|
||||
|
||||
FlutterFilamentPlugin::FlutterFilamentPlugin(
|
||||
flutter::TextureRegistrar *textureRegistrar,
|
||||
flutter::PluginRegistrarWindows *pluginRegistrar,
|
||||
std::unique_ptr<flutter::MethodChannel<flutter::EncodableValue>> &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));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
FlutterFilamentPlugin::~FlutterFilamentPlugin() {}
|
||||
|
||||
ResourceBuffer FlutterFilamentPlugin::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 {
|
||||
|
||||
if (name_str.rfind("asset://", 0) == 0) {
|
||||
name_str = name_str.substr(8);
|
||||
}
|
||||
|
||||
TCHAR pBuf[512];
|
||||
size_t len = sizeof(pBuf);
|
||||
int bytes = GetModuleFileName(NULL, pBuf, len);
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
std::wstring assetPath = converter.from_bytes(name_str.c_str());
|
||||
|
||||
std::wstring exePathBuf(pBuf);
|
||||
std::filesystem::path exePath(exePathBuf);
|
||||
auto exeDir = exePath.remove_filename();
|
||||
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;
|
||||
return ResourceBuffer(nullptr, 0, -1);
|
||||
}
|
||||
is.seekg(0, std::ios::end);
|
||||
length = is.tellg();
|
||||
|
||||
char *buffer;
|
||||
buffer = new char[length];
|
||||
is.seekg(0, std::ios::beg);
|
||||
is.read(buffer, length);
|
||||
is.close();
|
||||
auto id = _resources.size();
|
||||
auto rb = ResourceBuffer(buffer, length, id);
|
||||
_resources.emplace(id, rb);
|
||||
|
||||
std::wcout << "Loaded resource of length " << length << " from path "
|
||||
<< targetFilePath << std::endl;
|
||||
|
||||
return rb;
|
||||
}
|
||||
|
||||
void FlutterFilamentPlugin::freeResource(ResourceBuffer rbuf) {
|
||||
free((void *)rbuf.data);
|
||||
}
|
||||
|
||||
static ResourceBuffer _loadResource(const char *path, void *const plugin) {
|
||||
return ((FlutterFilamentPlugin *)plugin)->loadResource(path);
|
||||
}
|
||||
|
||||
static void _freeResource(ResourceBuffer rbf, void *const plugin) {
|
||||
((FlutterFilamentPlugin *)plugin)->freeResource(rbf);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
((FlutterFilamentPlugin *)owner)->RenderCallback();
|
||||
}
|
||||
|
||||
// this is the method on FlutterFilamentPlugin that will copy between D3D
|
||||
// textures
|
||||
void FlutterFilamentPlugin::RenderCallback() {
|
||||
if (_context) {
|
||||
auto flutterTextureId = _context->GetFlutterTextureId();
|
||||
if(flutterTextureId == -1) {
|
||||
std::cout << "Bad texture" << std::endl;
|
||||
return;
|
||||
}
|
||||
#ifdef USE_ANGLE
|
||||
_context->RenderCallback();
|
||||
#endif
|
||||
#if !WGL_USE_BACKING_WINDOW
|
||||
_textureRegistrar->MarkTextureFrameAvailable(flutterTextureId);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void FlutterFilamentPlugin::CreateTexture(
|
||||
const flutter::MethodCall<flutter::EncodableValue> &methodCall,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
|
||||
|
||||
const auto *args =
|
||||
std::get_if<flutter::EncodableList>(methodCall.arguments());
|
||||
|
||||
double dWidth = *(std::get_if<double>(&(args->at(0))));
|
||||
double dHeight = *(std::get_if<double>(&(args->at(1))));
|
||||
double dLeft = *(std::get_if<double>(&(args->at(2))));
|
||||
double dTop = *(std::get_if<double>(&(args->at(3))));
|
||||
auto width = (uint32_t)round(dWidth );
|
||||
auto height = (uint32_t)round(dHeight );
|
||||
auto left = (uint32_t)round(dLeft );
|
||||
auto top = (uint32_t)round(dTop );
|
||||
|
||||
std::cout << "Using " << width << "x" << height << std::endl;
|
||||
|
||||
// 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
|
||||
_context = std::make_unique<FlutterEGLContext>(_pluginRegistrar, _textureRegistrar);
|
||||
#else
|
||||
_context = std::make_unique<WGLContext>(_pluginRegistrar, _textureRegistrar);
|
||||
#endif
|
||||
}
|
||||
_context->CreateRenderingSurface(width, height, std::move(result), left, top);
|
||||
}
|
||||
|
||||
void FlutterFilamentPlugin::DestroyTexture(
|
||||
const flutter::MethodCall<flutter::EncodableValue> &methodCall,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
|
||||
|
||||
const auto *flutterTextureId = std::get_if<int64_t>(methodCall.arguments());
|
||||
|
||||
if (!flutterTextureId) {
|
||||
result->Error("NOT_IMPLEMENTED", "Flutter texture ID must be provided");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_context) {
|
||||
_context->DestroyTexture(std::move(result));
|
||||
}
|
||||
else {
|
||||
result->Error("NO_CONTEXT", "No rendering context is active");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FlutterFilamentPlugin::HandleMethodCall(
|
||||
const flutter::MethodCall<flutter::EncodableValue> &methodCall,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
|
||||
|
||||
if (methodCall.method_name() == "usesBackingWindow") {
|
||||
result->Success(flutter::EncodableValue(
|
||||
#ifdef WGL_USE_BACKING_WINDOW
|
||||
true
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
));
|
||||
} else if (methodCall.method_name() == "getResourceLoaderWrapper") {
|
||||
const ResourceLoaderWrapper *const resourceLoader =
|
||||
new ResourceLoaderWrapper(_loadResource, _freeResource, this);
|
||||
result->Success(flutter::EncodableValue((int64_t)resourceLoader));
|
||||
} else if (methodCall.method_name() == "resizeWindow") {
|
||||
#if WGL_USE_BACKING_WINDOW
|
||||
const auto *args =
|
||||
std::get_if<flutter::EncodableList>(methodCall.arguments());
|
||||
double dWidth = *(std::get_if<double>(&(args->at(0))));
|
||||
double dHeight = *(std::get_if<double>(&(args->at(1))));
|
||||
double dLeft = *(std::get_if<double>(&(args->at(2))));
|
||||
double dTop = *(std::get_if<double>(&(args->at(3))));
|
||||
auto width = (uint32_t)round(dWidth );
|
||||
auto height = (uint32_t)round(dHeight );
|
||||
auto left = (uint32_t)round(dLeft );
|
||||
auto top = (uint32_t)round(dTop );
|
||||
_context->ResizeRenderingSurface(width, height, left, top);
|
||||
result->Success();
|
||||
#else
|
||||
result->Error("ERROR", "resizeWindow is only available when using a backing window");
|
||||
#endif
|
||||
} 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;
|
||||
#if !ANGLE && WGL_USE_BACKING_WINDOW
|
||||
resultList.push_back(flutter::EncodableValue((int64_t)nullptr));
|
||||
resultList.push_back(flutter::EncodableValue((int64_t)nullptr));
|
||||
#else
|
||||
resultList.push_back(flutter::EncodableValue((int64_t)&render_callback));
|
||||
resultList.push_back(flutter::EncodableValue((int64_t)this));
|
||||
#endif
|
||||
result->Success(resultList);
|
||||
} else if (methodCall.method_name() == "getDriverPlatform") {
|
||||
#ifdef USE_ANGLE
|
||||
result->Success(flutter::EncodableValue((int64_t)_context->GetPlatform()));
|
||||
#else
|
||||
result->Success(flutter::EncodableValue((int64_t) nullptr));
|
||||
#endif
|
||||
} else {
|
||||
result->Error("NOT_IMPLEMENTED", "Method is not implemented %s",
|
||||
methodCall.method_name());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace flutter_filament
|
||||
@@ -0,0 +1,71 @@
|
||||
#ifndef FLUTTER_PLUGIN_FLUTTER_FILAMENT_PLUGIN_H_
|
||||
#define FLUTTER_PLUGIN_FLUTTER_FILAMENT_PLUGIN_H_
|
||||
|
||||
#include <flutter/method_channel.h>
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include <Windows.h>
|
||||
#include <wrl.h>
|
||||
|
||||
#include "GL/GL.h"
|
||||
#include "GL/GLu.h"
|
||||
|
||||
#include "FlutterFilamentApi.h"
|
||||
|
||||
#if USE_ANGLE
|
||||
#include "egl_context.h"
|
||||
#else
|
||||
#include "wgl_context.h"
|
||||
#endif
|
||||
|
||||
namespace flutter_filament {
|
||||
|
||||
class FlutterFilamentPlugin : public flutter::Plugin {
|
||||
public:
|
||||
static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar);
|
||||
|
||||
FlutterFilamentPlugin(flutter::TextureRegistrar *textureRegistrar,
|
||||
flutter::PluginRegistrarWindows *registrar,
|
||||
std::unique_ptr<flutter::MethodChannel<flutter::EncodableValue>>& channel);
|
||||
virtual ~FlutterFilamentPlugin();
|
||||
|
||||
// Disallow copy and assign.
|
||||
FlutterFilamentPlugin(const FlutterFilamentPlugin &) = delete;
|
||||
FlutterFilamentPlugin &operator=(const FlutterFilamentPlugin &) = delete;
|
||||
|
||||
// Called when a method is called on this plugin's channel from Dart.
|
||||
void HandleMethodCall(
|
||||
const flutter::MethodCall<flutter::EncodableValue> &method_call,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
|
||||
|
||||
flutter::PluginRegistrarWindows *_pluginRegistrar;
|
||||
flutter::TextureRegistrar *_textureRegistrar;
|
||||
std::unique_ptr<flutter::MethodChannel<flutter::EncodableValue>> _channel;
|
||||
std::map<uint32_t, ResourceBuffer> _resources;
|
||||
|
||||
void CreateTexture(
|
||||
const flutter::MethodCall<flutter::EncodableValue> &methodCall,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
|
||||
void DestroyTexture(
|
||||
const flutter::MethodCall<flutter::EncodableValue> &methodCall,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
|
||||
void RenderCallback();
|
||||
|
||||
ResourceBuffer loadResource(const char *path);
|
||||
void freeResource(ResourceBuffer rbuf);
|
||||
|
||||
private:
|
||||
#ifdef USE_ANGLE
|
||||
std::unique_ptr<FlutterEGLContext> _context = nullptr;
|
||||
#else
|
||||
std::unique_ptr<WGLContext> _context = nullptr;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace flutter_filament
|
||||
|
||||
#endif // FLUTTER_PLUGIN_FLUTTER_FILAMENT_PLUGIN_H_
|
||||
@@ -0,0 +1,12 @@
|
||||
#include "include/flutter_filament/flutter_filament_plugin_c_api.h"
|
||||
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
|
||||
#include "flutter_filament_plugin.h"
|
||||
|
||||
void FlutterFilamentPluginCApiRegisterWithRegistrar(
|
||||
FlutterDesktopPluginRegistrarRef registrar) {
|
||||
flutter_filament::FlutterFilamentPlugin::RegisterWithRegistrar(
|
||||
flutter::PluginRegistrarManager::GetInstance()
|
||||
->GetRegistrar<flutter::PluginRegistrarWindows>(registrar));
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef _FLUTTER_RENDER_CONTEXT_H
|
||||
#define _FLUTTER_RENDER_CONTEXT_H
|
||||
|
||||
#include <flutter/method_channel.h>
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
#include <flutter/standard_method_codec.h>
|
||||
#include <flutter/texture_registrar.h>
|
||||
|
||||
#include "flutter_texture_buffer.h"
|
||||
|
||||
namespace flutter_filament {
|
||||
|
||||
class FlutterRenderContext {
|
||||
public:
|
||||
|
||||
void CreateRenderingSurface(uint32_t width, uint32_t height, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result, uint32_t left, uint32_t top );
|
||||
|
||||
void DestroyTexture(std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
|
||||
if (!_active) {
|
||||
result->Success("Texture has already been detroyed, ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
auto sh = std::make_shared<
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>>>(
|
||||
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() {
|
||||
if(!_active) {
|
||||
return -1;
|
||||
}
|
||||
return _active->flutterTextureId;
|
||||
}
|
||||
|
||||
protected:
|
||||
FlutterRenderContext( flutter::PluginRegistrarWindows* pluginRegistrar, flutter::TextureRegistrar* textureRegistrar) : _pluginRegistrar(pluginRegistrar), _textureRegistrar(textureRegistrar) {};
|
||||
|
||||
flutter::PluginRegistrarWindows* _pluginRegistrar;
|
||||
flutter::TextureRegistrar* _textureRegistrar;
|
||||
std::unique_ptr<FlutterTextureBuffer> _active = nullptr;
|
||||
std::unique_ptr<FlutterTextureBuffer> _inactive = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef _FLUTTER_TEXTURE_BUFFER_H
|
||||
#define _FLUTTER_TEXTURE_BUFFER_H
|
||||
|
||||
#include <flutter/method_channel.h>
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
#include <flutter/standard_method_codec.h>
|
||||
#include <flutter/texture_registrar.h>
|
||||
|
||||
|
||||
namespace flutter_filament {
|
||||
|
||||
class FlutterTextureBuffer {
|
||||
public:
|
||||
int64_t flutterTextureId = -1;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,144 @@
|
||||
#include "opengl_texture_buffer.h"
|
||||
|
||||
#include <flutter/method_channel.h>
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
#include <flutter/standard_method_codec.h>
|
||||
#include <flutter/texture_registrar.h>
|
||||
|
||||
#include <thread>
|
||||
|
||||
namespace flutter_filament {
|
||||
|
||||
void _release_callback(void *releaseContext) {
|
||||
// ((OpenGLTextureBuffer*)releaseContext)->unlock();
|
||||
}
|
||||
|
||||
OpenGLTextureBuffer::OpenGLTextureBuffer(
|
||||
flutter::PluginRegistrarWindows *pluginRegistrar,
|
||||
flutter::TextureRegistrar *textureRegistrar,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result,
|
||||
uint32_t width, uint32_t height, HGLRC context)
|
||||
: _pluginRegistrar(pluginRegistrar), _textureRegistrar(textureRegistrar),
|
||||
_width(width), _height(height), _context(context) {
|
||||
|
||||
HWND hwnd = _pluginRegistrar->GetView()->GetNativeWindow();
|
||||
|
||||
HDC whdc = GetDC(hwnd);
|
||||
|
||||
if (!_context || !wglMakeCurrent(whdc, _context)) {
|
||||
result->Error("ERROR", "Failed to switch OpenGL context in constructor.");
|
||||
return;
|
||||
}
|
||||
|
||||
glGenTextures(1, &glTextureId);
|
||||
|
||||
if (glTextureId == 0) {
|
||||
result->Error("ERROR", "Failed to generate texture, OpenGL err was %d",
|
||||
glGetError());
|
||||
return;
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, glTextureId);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, _width, _height, 0, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, 0);
|
||||
|
||||
GLenum err = glGetError();
|
||||
|
||||
if (err != GL_NO_ERROR) {
|
||||
result->Error("ERROR", "Failed to generate texture, GL error was %d", err);
|
||||
return;
|
||||
}
|
||||
wglMakeCurrent(NULL, NULL);
|
||||
|
||||
pixelBuffer = std::make_unique<FlutterDesktopPixelBuffer>();
|
||||
pixelData.reset(new uint8_t[_width * _height * 4]);
|
||||
|
||||
pixelBuffer->buffer = pixelData.get();
|
||||
pixelBuffer->width = size_t(_width);
|
||||
pixelBuffer->height = size_t(_height);
|
||||
pixelBuffer->release_callback = _release_callback;
|
||||
pixelBuffer->release_context = this;
|
||||
|
||||
std::cout << "Created initial pixel data/buffer of size " << _width << "x"
|
||||
<< _height << std::endl;
|
||||
|
||||
texture =
|
||||
std::make_unique<flutter::TextureVariant>(flutter::PixelBufferTexture(
|
||||
[=](size_t width,
|
||||
size_t height) -> const FlutterDesktopPixelBuffer * {
|
||||
|
||||
if (width != this->_width || height != this->_height) {
|
||||
if(!this->logged) {
|
||||
std::cout << "Front-end widget expects " << width << "x" << height << " but this is " << this->_width << "x" << this->_height
|
||||
<< std::endl;
|
||||
this->logged = true;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
uint8_t *data = (uint8_t *)pixelData.get();
|
||||
|
||||
if (!_context || !wglMakeCurrent(whdc, _context)) {
|
||||
std::cout << "Failed to switch OpenGL context in callback."
|
||||
<< std::endl;
|
||||
} else {
|
||||
// It seems there's at least 1 frame delay between resizing a
|
||||
// front-end widget and the layout operation being performed on
|
||||
// Windows. I haven't found a way to guarantee that we can resize
|
||||
// the OpenGL texture before the pixel buffer callback here. (If
|
||||
// you can find/suggest a way, please let me know). This means we
|
||||
// need to manually check that the requested size matches the
|
||||
// current size of our GL texture, and return an empty pixel
|
||||
// buffer if not.
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
|
||||
GLenum err = glGetError();
|
||||
|
||||
if (err != GL_NO_ERROR) {
|
||||
if (err == GL_INVALID_OPERATION) {
|
||||
std::cout << "Invalid op" << std::endl;
|
||||
} else if (err == GL_INVALID_VALUE) {
|
||||
std::cout << "Invalid value" << std::endl;
|
||||
} else if (err == GL_OUT_OF_MEMORY) {
|
||||
std::cout << "Out of mem" << std::endl;
|
||||
} else if (err == GL_INVALID_ENUM) {
|
||||
std::cout << "Invalid enum" << std::endl;
|
||||
} else {
|
||||
std::cout << "Unknown error" << std::endl;
|
||||
}
|
||||
}
|
||||
wglMakeCurrent(NULL, NULL);
|
||||
}
|
||||
pixelBuffer->buffer = pixelData.get();
|
||||
return pixelBuffer.get();
|
||||
}));
|
||||
|
||||
flutterTextureId = textureRegistrar->RegisterTexture(texture.get());
|
||||
std::cout << "Registered Flutter texture ID " << flutterTextureId
|
||||
<< std::endl;
|
||||
|
||||
if (flutterTextureId != -1) {
|
||||
std::vector<flutter::EncodableValue> resultList;
|
||||
resultList.push_back(flutter::EncodableValue(flutterTextureId));
|
||||
resultList.push_back(flutter::EncodableValue((int64_t) nullptr));
|
||||
resultList.push_back(flutter::EncodableValue(glTextureId));
|
||||
resultList.push_back(flutter::EncodableValue((int64_t)_context));
|
||||
result->Success(resultList);
|
||||
}
|
||||
}
|
||||
|
||||
OpenGLTextureBuffer::~OpenGLTextureBuffer() {
|
||||
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;
|
||||
}
|
||||
glDeleteTextures(1, &this->glTextureId);
|
||||
wglMakeCurrent(NULL, NULL);
|
||||
}
|
||||
|
||||
} // namespace flutter_filament
|
||||
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef _OPENGL_TEXTURE_BUFFER_H
|
||||
#define _OPENGL_TEXTURE_BUFFER_H
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <flutter/texture_registrar.h>
|
||||
#include <flutter/method_channel.h>
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
|
||||
#include "GL/GL.h"
|
||||
#include "GL/GLu.h"
|
||||
#include "GL/wglext.h"
|
||||
|
||||
#include <Windows.h>
|
||||
#include <wrl.h>
|
||||
|
||||
#include "flutter_texture_buffer.h"
|
||||
|
||||
typedef uint32_t GLuint;
|
||||
|
||||
namespace flutter_filament {
|
||||
|
||||
class OpenGLTextureBuffer : public FlutterTextureBuffer {
|
||||
public:
|
||||
OpenGLTextureBuffer(
|
||||
flutter::PluginRegistrarWindows* pluginRegistrar,
|
||||
flutter::TextureRegistrar* textureRegistrar,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
HGLRC context);
|
||||
|
||||
~OpenGLTextureBuffer();
|
||||
GLuint glTextureId = 0;
|
||||
std::unique_ptr<FlutterDesktopPixelBuffer> pixelBuffer;
|
||||
std::unique_ptr<uint8_t> pixelData;
|
||||
std::unique_ptr<flutter::TextureVariant> texture;
|
||||
|
||||
private:
|
||||
flutter::PluginRegistrarWindows* _pluginRegistrar;
|
||||
flutter::TextureRegistrar* _textureRegistrar;
|
||||
uint32_t _width = 0;
|
||||
uint32_t _height = 0;
|
||||
HGLRC _context = NULL;
|
||||
bool logged = false;
|
||||
};
|
||||
|
||||
}
|
||||
#endif // _OPENGL_TEXTURE_BUFFER_H
|
||||
@@ -0,0 +1,43 @@
|
||||
#include <flutter/method_call.h>
|
||||
#include <flutter/method_result_functions.h>
|
||||
#include <flutter/standard_method_codec.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#include "flutter_filament_plugin.h"
|
||||
|
||||
namespace flutter_filament {
|
||||
namespace test {
|
||||
|
||||
namespace {
|
||||
|
||||
using flutter::EncodableMap;
|
||||
using flutter::EncodableValue;
|
||||
using flutter::MethodCall;
|
||||
using flutter::MethodResultFunctions;
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(FlutterFilamentPlugin, GetPlatformVersion) {
|
||||
FlutterFilamentPlugin plugin;
|
||||
// Save the reply value from the success callback.
|
||||
std::string result_string;
|
||||
plugin.HandleMethodCall(
|
||||
MethodCall("getPlatformVersion", std::make_unique<EncodableValue>()),
|
||||
std::make_unique<MethodResultFunctions<>>(
|
||||
[&result_string](const EncodableValue* result) {
|
||||
result_string = std::get<std::string>(*result);
|
||||
},
|
||||
nullptr, nullptr));
|
||||
|
||||
// Since the exact string varies by host, just ensure that it's a string
|
||||
// with the expected format.
|
||||
EXPECT_TRUE(result_string.rfind("Windows ", 0) == 0);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace flutter_filament
|
||||
@@ -0,0 +1,147 @@
|
||||
#include "wgl_context.h"
|
||||
|
||||
#ifdef WGL_USE_BACKING_WINDOW
|
||||
#include "backing_window.h"
|
||||
#endif
|
||||
|
||||
#include "flutter_texture_buffer.h"
|
||||
|
||||
namespace flutter_filament {
|
||||
|
||||
WGLContext::WGLContext(flutter::PluginRegistrarWindows *pluginRegistrar,
|
||||
flutter::TextureRegistrar *textureRegistrar)
|
||||
: FlutterRenderContext(pluginRegistrar, textureRegistrar) {
|
||||
|
||||
#if WGL_USE_BACKING_WINDOW
|
||||
return;
|
||||
#endif
|
||||
|
||||
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_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, // Flags
|
||||
PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette.
|
||||
24, // Colordepth of the framebuffer.
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
16, // 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<int> 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::ResizeRenderingSurface(uint32_t width, uint32_t height, uint32_t left, uint32_t top) {
|
||||
#if WGL_USE_BACKING_WINDOW
|
||||
_backingWindow->Resize(width, height, left, top);
|
||||
#endif
|
||||
}
|
||||
|
||||
void WGLContext::CreateRenderingSurface(
|
||||
uint32_t width, uint32_t height,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result, uint32_t left, uint32_t top) {
|
||||
|
||||
#if WGL_USE_BACKING_WINDOW
|
||||
if(!_backingWindow) {
|
||||
_backingWindow = std::make_unique<BackingWindow>(
|
||||
_pluginRegistrar, static_cast<int>(width), static_cast<int>(height), static_cast<int>(left), static_cast<int>(top));
|
||||
} else {
|
||||
ResizeRenderingSurface(width, height, left, top);
|
||||
}
|
||||
std::vector<flutter::EncodableValue> 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));
|
||||
resultList.push_back(flutter::EncodableValue((int64_t)_context));
|
||||
result->Success(resultList);
|
||||
#else
|
||||
if(left != 0 || top != 0) {
|
||||
result->Error("ERROR",
|
||||
"When WGL_USE_BACKING_WINDOW is false, rendering with WGL uses a Texture render target/Flutter widget and does not need a window offset.");
|
||||
} else if (_active.get()) {
|
||||
result->Error("ERROR",
|
||||
"Texture already exists. You must call destroyTexture before "
|
||||
"attempting to create a new one.");
|
||||
|
||||
} else {
|
||||
auto active = std::make_unique<OpenGLTextureBuffer>(
|
||||
_pluginRegistrar, _textureRegistrar, std::move(result), width, height,
|
||||
_context);
|
||||
_active = std::move(active);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void *WGLContext::GetSharedContext() { return (void *)_context; }
|
||||
|
||||
} // namespace flutter_filament
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef _WGL_CONTEXT_H
|
||||
#define _WGL_CONTEXT_H
|
||||
|
||||
#include <Windows.h>
|
||||
#include "opengl_texture_buffer.h"
|
||||
#include "flutter_render_context.h"
|
||||
#if WGL_USE_BACKING_WINDOW
|
||||
#include "backing_window.h"
|
||||
#endif
|
||||
namespace flutter_filament {
|
||||
|
||||
class WGLContext : public FlutterRenderContext {
|
||||
public:
|
||||
WGLContext(flutter::PluginRegistrarWindows* pluginRegistrar, flutter::TextureRegistrar* textureRegistrar);
|
||||
void* GetSharedContext();
|
||||
void CreateRenderingSurface(
|
||||
uint32_t width, uint32_t height,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result, uint32_t left, uint32_t top);
|
||||
void ResizeRenderingSurface(
|
||||
uint32_t width, uint32_t height, uint32_t left, uint32_t top
|
||||
);
|
||||
private:
|
||||
HGLRC _context = NULL;
|
||||
#if WGL_USE_BACKING_WINDOW
|
||||
std::unique_ptr<BackingWindow> _backingWindow = nullptr;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user