split D3D/GLES texture creation
This commit is contained in:
@@ -5,7 +5,6 @@ import 'package:thermion_dart/src/viewer/src/shared_types/view.dart' as t;
|
|||||||
import 'package:thermion_flutter/src/widgets/src/resize_observer.dart';
|
import 'package:thermion_flutter/src/widgets/src/resize_observer.dart';
|
||||||
import 'package:thermion_flutter/thermion_flutter.dart';
|
import 'package:thermion_flutter/thermion_flutter.dart';
|
||||||
import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart';
|
import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart';
|
||||||
import 'package:vector_math/vector_math_64.dart' hide Colors;
|
|
||||||
|
|
||||||
class ThermionTextureWidget extends StatefulWidget {
|
class ThermionTextureWidget extends StatefulWidget {
|
||||||
///
|
///
|
||||||
@@ -52,7 +51,10 @@ class _ThermionTextureWidgetState extends State<ThermionTextureWidget> {
|
|||||||
void dispose() {
|
void dispose() {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
_views.remove(widget.view);
|
_views.remove(widget.view);
|
||||||
_texture?.destroy();
|
if(_texture != null) {
|
||||||
|
ThermionFlutterPlatform.instance.destroyTexture(_texture!);
|
||||||
|
}
|
||||||
|
|
||||||
_states.remove(this);
|
_states.remove(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +81,10 @@ class _ThermionTextureWidgetState extends State<ThermionTextureWidget> {
|
|||||||
"Target texture dimensions ${width}x${height} (pixel ratio : $dpr)");
|
"Target texture dimensions ${width}x${height} (pixel ratio : $dpr)");
|
||||||
|
|
||||||
_texture = await ThermionFlutterPlatform.instance
|
_texture = await ThermionFlutterPlatform.instance
|
||||||
.createTexture(widget.view, width, height);
|
.createTexture(width, height);
|
||||||
|
|
||||||
|
await ThermionFlutterPlatform.instance
|
||||||
|
.bind(widget.view, _texture!);
|
||||||
|
|
||||||
_logger.info(
|
_logger.info(
|
||||||
"Actual texture dimensions ${_texture!.width}x${_texture!.height} (pixel ratio : $dpr)");
|
"Actual texture dimensions ${_texture!.width}x${_texture!.height} (pixel ratio : $dpr)");
|
||||||
@@ -109,7 +114,10 @@ class _ThermionTextureWidgetState extends State<ThermionTextureWidget> {
|
|||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
await texture?.destroy();
|
if(texture != null) {
|
||||||
|
ThermionFlutterPlatform.instance.destroyTexture(texture);
|
||||||
|
}
|
||||||
|
|
||||||
_views.clear();
|
_views.clear();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -124,7 +132,7 @@ class _ThermionTextureWidgetState extends State<ThermionTextureWidget> {
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// Each instance of ThermionTextureWidget in the widget hierarchy must
|
/// Each instance of ThermionTextureWidget in the widget hierarchy must
|
||||||
/// call[markFrameAvailable] on every frame to notify Flutter that the content
|
/// call [markFrameAvailable] on every frame to notify Flutter that the content
|
||||||
/// of its backing texture has changed.
|
/// of its backing texture has changed.
|
||||||
///
|
///
|
||||||
/// Calling [requestFrame] on [ThermionViewer], however, will render all
|
/// Calling [requestFrame] on [ThermionViewer], however, will render all
|
||||||
@@ -149,7 +157,9 @@ class _ThermionTextureWidgetState extends State<ThermionTextureWidget> {
|
|||||||
await widget.viewer.requestFrame();
|
await widget.viewer.requestFrame();
|
||||||
lastRender = d.inMilliseconds;
|
lastRender = d.inMilliseconds;
|
||||||
}
|
}
|
||||||
await _texture?.markFrameAvailable();
|
if(_texture != null) {
|
||||||
|
await ThermionFlutterPlatform.instance.markTextureFrameAvailable(_texture!);
|
||||||
|
}
|
||||||
_rendering = false;
|
_rendering = false;
|
||||||
}
|
}
|
||||||
_requestFrame();
|
_requestFrame();
|
||||||
@@ -190,12 +200,7 @@ class _ThermionTextureWidgetState extends State<ThermionTextureWidget> {
|
|||||||
_logger.info(
|
_logger.info(
|
||||||
"Resizing texture to dimensions ${newWidth}x${newHeight} (pixel ratio : $dpr)");
|
"Resizing texture to dimensions ${newWidth}x${newHeight} (pixel ratio : $dpr)");
|
||||||
|
|
||||||
await _texture?.resize(
|
await ThermionFlutterPlatform.instance.resizeTexture(_texture!, newWidth, newHeight);
|
||||||
newWidth,
|
|
||||||
newHeight,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
|
|
||||||
_logger.info(
|
_logger.info(
|
||||||
"Resized texture to dimensions ${_texture!.width}x${_texture!.height} (pixel ratio : $dpr)");
|
"Resized texture to dimensions ${_texture!.width}x${_texture!.height} (pixel ratio : $dpr)");
|
||||||
|
|||||||
@@ -3,4 +3,5 @@ library thermion_flutter;
|
|||||||
export 'src/thermion_flutter_plugin.dart';
|
export 'src/thermion_flutter_plugin.dart';
|
||||||
export 'src/widgets/widgets.dart';
|
export 'src/widgets/widgets.dart';
|
||||||
export 'package:thermion_flutter_platform_interface/thermion_flutter_platform_interface.dart';
|
export 'package:thermion_flutter_platform_interface/thermion_flutter_platform_interface.dart';
|
||||||
|
export 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart';
|
||||||
export 'package:thermion_dart/thermion_dart.dart';
|
export 'package:thermion_dart/thermion_dart.dart';
|
||||||
|
|||||||
@@ -24,6 +24,11 @@ dependencies:
|
|||||||
logging: ^1.2.0
|
logging: ^1.2.0
|
||||||
web: ^1.0.0
|
web: ^1.0.0
|
||||||
|
|
||||||
|
dependency_overrides:
|
||||||
|
thermion_flutter_ffi:
|
||||||
|
path: ../thermion_flutter_ffi
|
||||||
|
thermion_flutter_platform_interface:
|
||||||
|
path: ../thermion_flutter_platform_interface
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|||||||
@@ -4,31 +4,16 @@ project(${PROJECT_NAME} LANGUAGES C CXX)
|
|||||||
|
|
||||||
cmake_policy(VERSION 3.14...3.25)
|
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 "thermion_flutter_plugin")
|
set(PLUGIN_NAME "thermion_flutter_plugin")
|
||||||
|
|
||||||
# Any new source files that you add to the plugin should be added here.
|
|
||||||
list(APPEND PLUGIN_SOURCES
|
list(APPEND PLUGIN_SOURCES
|
||||||
"thermion_flutter_plugin.cpp"
|
"thermion_flutter_plugin.cpp"
|
||||||
"thermion_flutter_plugin.h"
|
"thermion_flutter_plugin.h"
|
||||||
|
"flutter_egl_texture.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
set(THERMION_EGL FALSE)
|
add_subdirectory("rendering/egl")
|
||||||
set(WGL_USE_BACKING_WINDOW FALSE)
|
|
||||||
|
|
||||||
if(THERMION_EGL)
|
|
||||||
add_compile_definitions(THERMION_EGL)
|
|
||||||
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")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Define the plugin library target. Its name must not be changed (see comment
|
|
||||||
# on PLUGIN_NAME above).
|
|
||||||
add_library(${PLUGIN_NAME} SHARED
|
add_library(${PLUGIN_NAME} SHARED
|
||||||
"include/thermion_flutter/thermion_flutter_plugin_c_api.h"
|
"include/thermion_flutter/thermion_flutter_plugin_c_api.h"
|
||||||
"thermion_flutter_plugin_c_api.cpp"
|
"thermion_flutter_plugin_c_api.cpp"
|
||||||
@@ -45,37 +30,12 @@ target_compile_features(${PLUGIN_NAME} PUBLIC cxx_std_20)
|
|||||||
target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
|
target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
|
||||||
target_include_directories(${PLUGIN_NAME} INTERFACE
|
target_include_directories(${PLUGIN_NAME} INTERFACE
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/include"
|
"${CMAKE_CURRENT_SOURCE_DIR}/include"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
)
|
)
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
"${CMAKE_SOURCE_DIR}/../../../../thermion_dart/native/include/filament"
|
"${CMAKE_SOURCE_DIR}/../../../../thermion_dart/native/include/filament"
|
||||||
"${CMAKE_SOURCE_DIR}/../../../../thermion_dart/native/include"
|
"${CMAKE_SOURCE_DIR}/../../../../thermion_dart/native/include"
|
||||||
)
|
|
||||||
|
|
||||||
if(THERMION_EGL)
|
|
||||||
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_SOURCE_DIR}/../../../../thermion_dart/native/lib/windows/x86_64/mdd/libEGL.dll.lib")
|
|
||||||
set_property(TARGET EGL PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_SOURCE_DIR}/../../../../thermion_dart/native/lib/windows/x86_64/mt/angle/libEGL.dll.lib")
|
|
||||||
set_property(TARGET EGL PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_SOURCE_DIR}/../../../../thermion_dart/native/lib/windows/x86_64/mt/angle/libEGL.dll.lib")
|
|
||||||
add_library(GLESv2 SHARED IMPORTED)
|
|
||||||
set_property(TARGET GLESv2 PROPERTY IMPORTED_IMPLIB_DEBUG "${CMAKE_SOURCE_DIR}/../../../../thermion_dart/native/lib/windows/x86_64/mdd/libGLESv2.dll.lib")
|
|
||||||
set_property(TARGET GLESv2 PROPERTY IMPORTED_IMPLIB_PROFILE "${CMAKE_SOURCE_DIR}/../../../../thermion_dart/native/lib/windows/x86_64/mt/angle/libGLESv2.dll.lib")
|
|
||||||
set_property(TARGET GLESv2 PROPERTY IMPORTED_IMPLIB_RELEASE "${CMAKE_SOURCE_DIR}/../../../../thermion_dart/native/lib/windows/x86_64/mt/angle/libGLESv2.dll.lib")
|
|
||||||
else()
|
|
||||||
list(APPEND GL_LIBS
|
|
||||||
opengl32
|
|
||||||
dwmapi
|
|
||||||
comctl32
|
|
||||||
)
|
|
||||||
set(ANGLE_OR_OPENGL_DIR opengl)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include_directories(
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -83,24 +43,19 @@ target_link_libraries(${PLUGIN_NAME} PRIVATE
|
|||||||
flutter
|
flutter
|
||||||
flutter_wrapper_plugin
|
flutter_wrapper_plugin
|
||||||
Shlwapi
|
Shlwapi
|
||||||
${GL_LIBS}
|
thermion_egl
|
||||||
)
|
)
|
||||||
|
|
||||||
# List of absolute paths to libraries that should be bundled with the plugin
|
# Copy thermion_egl library to the Flutter build directory
|
||||||
if(THERMION_EGL)
|
add_custom_command(TARGET ${PLUGIN_NAME} POST_BUILD
|
||||||
set(thermion_flutter_bundled_libraries
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/angle/libEGL.dll
|
$<TARGET_FILE:thermion_egl>
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug/angle/libGLESv2.dll
|
$<TARGET_FILE_DIR:${PLUGIN_NAME}>
|
||||||
${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
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/thermion_dart.dll
|
|
||||||
PARENT_SCOPE
|
|
||||||
)
|
)
|
||||||
else()
|
|
||||||
set(thermion_flutter_bundled_libraries
|
set(thermion_flutter_bundled_libraries
|
||||||
${runner_BINARY_DIR}/../../../native_assets/windows/thermion_dart.dll
|
${runner_BINARY_DIR}/../../../native_assets/windows/thermion_dart.dll
|
||||||
|
$<TARGET_FILE:thermion_egl>
|
||||||
PARENT_SCOPE
|
PARENT_SCOPE
|
||||||
)
|
)
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#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_registrar.h>
|
||||||
|
|
||||||
|
#include "flutter_egl_texture.h"
|
||||||
|
|
||||||
|
namespace thermion::tflutter::windows
|
||||||
|
{
|
||||||
|
|
||||||
|
FlutterEGLTexture::FlutterEGLTexture(HANDLE d3dTexture2DHandle, uint32_t width, uint32_t height) : _width(width), _height(height)
|
||||||
|
{
|
||||||
|
_textureDescriptor = std::make_unique<FlutterDesktopGpuSurfaceDescriptor>();
|
||||||
|
_textureDescriptor->struct_size = sizeof(FlutterDesktopGpuSurfaceDescriptor);
|
||||||
|
_textureDescriptor->handle = d3dTexture2DHandle;
|
||||||
|
_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::GpuSurfaceTexture(
|
||||||
|
kFlutterDesktopGpuSurfaceTypeDxgiSharedHandle,
|
||||||
|
[&](size_t width, size_t height)
|
||||||
|
{
|
||||||
|
if (width != this->_width || height != this->_height)
|
||||||
|
{
|
||||||
|
//this->_onResizeRequested(width, height);
|
||||||
|
}
|
||||||
|
return _textureDescriptor.get();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
::flutter::TextureVariant* FlutterEGLTexture::GetFlutterTexture() {
|
||||||
|
return _texture.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlutterEGLTexture::SetFlutterTextureId(int64_t textureId) {
|
||||||
|
_flutterTextureId = textureId;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t FlutterEGLTexture::GetFlutterTextureId()
|
||||||
|
{
|
||||||
|
return _flutterTextureId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <d3d.h>
|
||||||
|
#include <d3d11.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#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_registrar.h>
|
||||||
|
|
||||||
|
namespace thermion::tflutter::windows {
|
||||||
|
|
||||||
|
class FlutterEGLTexture {
|
||||||
|
public:
|
||||||
|
FlutterEGLTexture(HANDLE d3dTexture2DHandle, uint32_t width, uint32_t height);
|
||||||
|
::flutter::TextureVariant* GetFlutterTexture();
|
||||||
|
int64_t GetFlutterTextureId();
|
||||||
|
void SetFlutterTextureId(int64_t textureId);
|
||||||
|
private:
|
||||||
|
uint32_t _width;
|
||||||
|
uint32_t _height;
|
||||||
|
std::unique_ptr<FlutterDesktopGpuSurfaceDescriptor> _textureDescriptor = nullptr;
|
||||||
|
std::unique_ptr<::flutter::TextureVariant> _texture;
|
||||||
|
int64_t _flutterTextureId = -1;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@@ -4,8 +4,6 @@ project(${PROJECT_NAME} LANGUAGES C CXX)
|
|||||||
|
|
||||||
cmake_policy(VERSION 3.14...3.25)
|
cmake_policy(VERSION 3.14...3.25)
|
||||||
|
|
||||||
add_compile_definitions(THERMION_EGL)
|
|
||||||
|
|
||||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||||
set(BUILD_SHARED_LIBS TRUE)
|
set(BUILD_SHARED_LIBS TRUE)
|
||||||
set(CMAKE_ENABLE_EXPORTS TRUE)
|
set(CMAKE_ENABLE_EXPORTS TRUE)
|
||||||
@@ -41,22 +39,3 @@ target_link_libraries(${PROJECT_NAME} PRIVATE
|
|||||||
d3d11
|
d3d11
|
||||||
)
|
)
|
||||||
|
|
||||||
# Test executable
|
|
||||||
add_executable(${PROJECT_NAME}_test
|
|
||||||
"main.cpp"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Make sure the test depends on the library
|
|
||||||
add_dependencies(${PROJECT_NAME}_test ${PROJECT_NAME})
|
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME}_test PRIVATE
|
|
||||||
${PROJECT_NAME}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Copy ANGLE DLLs to the output directory
|
|
||||||
add_custom_command(TARGET ${PROJECT_NAME}_test POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
|
||||||
"E:/angle/libEGL.dll"
|
|
||||||
"E:/angle/libGLESv2.dll"
|
|
||||||
"$<TARGET_FILE_DIR:${PROJECT_NAME}_test>"
|
|
||||||
)
|
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
namespace thermion::windows::egl {
|
namespace thermion::windows::egl {
|
||||||
|
|
||||||
FlutterEGLContext::FlutterEGLContext() {
|
ThermionEGLContext::ThermionEGLContext() {
|
||||||
|
|
||||||
// D3D starts here
|
// D3D starts here
|
||||||
IDXGIAdapter *adapter_ = nullptr;
|
IDXGIAdapter *adapter_ = nullptr;
|
||||||
@@ -144,7 +144,7 @@ FlutterEGLContext::FlutterEGLContext() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlutterEGLContext::CreateRenderingSurface(
|
EGLTexture* ThermionEGLContext::CreateRenderingSurface(
|
||||||
uint32_t width, uint32_t height,
|
uint32_t width, uint32_t height,
|
||||||
uint32_t left, uint32_t top
|
uint32_t left, uint32_t top
|
||||||
) {
|
) {
|
||||||
@@ -152,17 +152,16 @@ void FlutterEGLContext::CreateRenderingSurface(
|
|||||||
// glext::importGLESExtensionsEntryPoints();
|
// glext::importGLESExtensionsEntryPoints();
|
||||||
|
|
||||||
if(left != 0 || top != 0) {
|
if(left != 0 || top != 0) {
|
||||||
// result->Error("ERROR",
|
std::cout << "ERROR Rendering with EGL uses a Texture render target/Flutter widget and does not need a window offset." << std::endl;
|
||||||
// "Rendering with EGL uses a Texture render target/Flutter widget and does not need a window offset.");
|
return nullptr;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_active.get()) {
|
//if (_active && _active.get()) {
|
||||||
// result->Error("ERROR",
|
// // result->Error("ERROR",
|
||||||
// "Texture already exists. You must call destroyTexture before "
|
// // "Texture already exists. You must call destroyTexture before "
|
||||||
// "attempting to create a new one.");
|
// // "attempting to create a new one.");
|
||||||
return;
|
// return nullptr;
|
||||||
}
|
//}
|
||||||
|
|
||||||
_active = std::make_unique<EGLTexture>(
|
_active = std::make_unique<EGLTexture>(
|
||||||
width, height,
|
width, height,
|
||||||
@@ -176,17 +175,25 @@ void FlutterEGLContext::CreateRenderingSurface(
|
|||||||
// this->_channel->InvokeMethod("resize", std::move(val), nullptr);
|
// this->_channel->InvokeMethod("resize", std::move(val), nullptr);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return _active.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlutterEGLContext::RenderCallback() {
|
void* ThermionEGLContext::GetSharedContext() {
|
||||||
if(_active.get()) {
|
|
||||||
((EGLTexture*)_active.get())->RenderCallback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void* FlutterEGLContext::GetSharedContext() {
|
|
||||||
return (void*)_context;
|
return (void*)_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ThermionEGLContext::ResizeRenderingSurface(uint32_t width, uint32_t height, uint32_t left, uint32_t top) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThermionEGLContext::DestroyRenderingSurface() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLTexture *ThermionEGLContext::GetActiveTexture() {
|
||||||
|
return _active.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,12 +7,15 @@
|
|||||||
|
|
||||||
namespace thermion::windows::egl {
|
namespace thermion::windows::egl {
|
||||||
|
|
||||||
class FlutterEGLContext {
|
class ThermionEGLContext {
|
||||||
public:
|
public:
|
||||||
FlutterEGLContext();
|
ThermionEGLContext();
|
||||||
void* GetSharedContext();
|
void* GetSharedContext();
|
||||||
void RenderCallback();
|
EGLTexture * CreateRenderingSurface(uint32_t width, uint32_t height, uint32_t left, uint32_t top);
|
||||||
void CreateRenderingSurface(uint32_t width, uint32_t height, uint32_t left, uint32_t top);
|
void DestroyRenderingSurface();
|
||||||
|
void ResizeRenderingSurface(uint32_t width, uint32_t height, uint32_t left, uint32_t top);
|
||||||
|
|
||||||
|
EGLTexture * GetActiveTexture();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void* _context = nullptr;
|
void* _context = nullptr;
|
||||||
@@ -20,7 +23,7 @@ private:
|
|||||||
EGLDisplay _eglDisplay = NULL;
|
EGLDisplay _eglDisplay = NULL;
|
||||||
ID3D11Device* _D3D11Device = nullptr;
|
ID3D11Device* _D3D11Device = nullptr;
|
||||||
ID3D11DeviceContext* _D3D11DeviceContext = nullptr;
|
ID3D11DeviceContext* _D3D11DeviceContext = nullptr;
|
||||||
std::unique_ptr<EGLTexture> _active;
|
std::unique_ptr<EGLTexture> _active = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,21 +59,25 @@ static void logEglError(const char *name) noexcept {
|
|||||||
std::cout << name << " failed with " << err << std::endl;
|
std::cout << name << " failed with " << err << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EGLTexture::RenderCallback() {
|
void EGLTexture::Flush() {
|
||||||
glFinish();
|
// glFlush(); // Ensure GL commands are completed
|
||||||
_D3D11DeviceContext->Flush();
|
// _D3D11DeviceContext->Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE EGLTexture::GetTextureHandle() {
|
||||||
|
return _d3dTexture2DHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLTexture::~EGLTexture() {
|
EGLTexture::~EGLTexture() {
|
||||||
if (_eglDisplay != EGL_NO_DISPLAY && _eglSurface != EGL_NO_SURFACE) {
|
// if (_eglDisplay != EGL_NO_DISPLAY && _eglSurface != EGL_NO_SURFACE) {
|
||||||
eglReleaseTexImage(_eglDisplay, _eglSurface, EGL_BACK_BUFFER);
|
// eglReleaseTexImage(_eglDisplay, _eglSurface, EGL_BACK_BUFFER);
|
||||||
}
|
// }
|
||||||
auto success = eglDestroySurface(this->_eglDisplay, this->_eglSurface);
|
// auto success = eglDestroySurface(this->_eglDisplay, this->_eglSurface);
|
||||||
if(success != EGL_TRUE) {
|
// if(success != EGL_TRUE) {
|
||||||
std::cout << "Failed to destroy EGL Surface" << std::endl;
|
// std::cout << "Failed to destroy EGL Surface" << std::endl;
|
||||||
}
|
// }
|
||||||
_d3dTexture2D->Release();
|
_d3dTexture2D->Release();
|
||||||
glDeleteTextures(1, &this->glTextureId);
|
// glDeleteTextures(1, &this->glTextureId);
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLTexture::EGLTexture(
|
EGLTexture::EGLTexture(
|
||||||
@@ -104,7 +108,7 @@ EGLTexture::EGLTexture(
|
|||||||
auto hr = _D3D11Device->CreateTexture2D(&d3d11_texture2D_desc, nullptr,
|
auto hr = _D3D11Device->CreateTexture2D(&d3d11_texture2D_desc, nullptr,
|
||||||
&_d3dTexture2D);
|
&_d3dTexture2D);
|
||||||
if FAILED (hr) {
|
if FAILED (hr) {
|
||||||
// result->Error("ERROR", "Failed to create D3D texture", nullptr);
|
std::cout << "Failed to create D3D texture" << std::endl;
|
||||||
return;
|
return;
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
@@ -112,21 +116,39 @@ EGLTexture::EGLTexture(
|
|||||||
hr = _d3dTexture2D.As(&resource);
|
hr = _d3dTexture2D.As(&resource);
|
||||||
|
|
||||||
if FAILED (hr) {
|
if FAILED (hr) {
|
||||||
// result->Error("ERROR", "Failed to create D3D texture", nullptr);
|
std::cout << "Failed to create D3D texture" << std::endl;
|
||||||
return;
|
return;
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
hr = resource->GetSharedHandle(&_d3dTexture2DHandle);
|
hr = resource->GetSharedHandle(&_d3dTexture2DHandle);
|
||||||
if FAILED (hr) {
|
if FAILED (hr) {
|
||||||
// result->Error("ERROR",
|
std::cout << "Failed to get shared handle to external D3D texture" << std::endl;
|
||||||
// "Failed to get shared handle to external D3D texture",
|
|
||||||
// nullptr);
|
|
||||||
return;
|
return;
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
_d3dTexture2D->AddRef();
|
_d3dTexture2D->AddRef();
|
||||||
|
|
||||||
std::cout << "Created external D3D texture" << std::endl;
|
std::cout << "Created external D3D texture " << width << "x" << height << std::endl;
|
||||||
|
|
||||||
|
// Create render target view of the texture
|
||||||
|
ID3D11RenderTargetView* rtv = nullptr;
|
||||||
|
D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
|
||||||
|
rtvDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||||
|
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
|
||||||
|
rtvDesc.Texture2D.MipSlice = 0;
|
||||||
|
|
||||||
|
hr = _D3D11Device->CreateRenderTargetView(_d3dTexture2D.Get(), &rtvDesc, &rtv);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
std::cout << "Failed to create render target view" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the texture to blue
|
||||||
|
float blueColor[4] = { 0.0f, 0.0f, 1.0f, 1.0f }; // RGBA
|
||||||
|
_D3D11DeviceContext->ClearRenderTargetView(rtv, blueColor);
|
||||||
|
_D3D11DeviceContext->Flush();
|
||||||
|
|
||||||
|
std::cout << "Filled D3D texture blue" << std::endl;
|
||||||
|
|
||||||
EGLint pbufferAttribs[] = {
|
EGLint pbufferAttribs[] = {
|
||||||
EGL_WIDTH, width, EGL_HEIGHT, height,
|
EGL_WIDTH, width, EGL_HEIGHT, height,
|
||||||
@@ -144,25 +166,168 @@ EGLTexture::EGLTexture(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
glGenTextures(1, &glTextureId);
|
/******************
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* THis is working
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
// // Clear to purple
|
||||||
|
// glClearColor(0.5f, 0.0f, 0.5f, 1.0f);
|
||||||
|
// glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
if (glTextureId == 0) {
|
// // Present the surface
|
||||||
std::cout
|
// eglSwapBuffers(_eglDisplay, _eglSurface);
|
||||||
<< "Failed to generate OpenGL texture for ANGLE, OpenGL err was %d",
|
|
||||||
glGetError();
|
// // Synchronize
|
||||||
|
// glFlush();
|
||||||
|
|
||||||
|
|
||||||
|
if (!eglMakeCurrent(_eglDisplay, _eglSurface, _eglSurface, _eglContext)) {
|
||||||
|
logEglError("eglMakeCurrent");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, glTextureId);
|
// Create and setup shaders for rendering the texture
|
||||||
eglBindTexImage(_eglDisplay, _eglSurface, EGL_BACK_BUFFER);
|
const char* vertexShaderSource = R"(#version 300 es
|
||||||
|
precision mediump float;
|
||||||
|
in vec2 position;
|
||||||
|
in vec2 texcoord;
|
||||||
|
out vec2 v_texcoord;
|
||||||
|
void main() {
|
||||||
|
gl_Position = vec4(position, 0.0, 1.0);
|
||||||
|
v_texcoord = texcoord;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
const char* fragmentShaderSource = R"(#version 300 es
|
||||||
|
precision mediump float;
|
||||||
|
in vec2 v_texcoord;
|
||||||
|
uniform sampler2D u_texture;
|
||||||
|
out vec4 fragColor;
|
||||||
|
void main() {
|
||||||
|
fragColor = texture(u_texture, v_texcoord);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
// Create and compile vertex shader
|
||||||
|
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||||
|
glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr);
|
||||||
|
glCompileShader(vertexShader);
|
||||||
|
|
||||||
|
// Check vertex shader compilation
|
||||||
|
GLint success;
|
||||||
|
GLchar infoLog[512];
|
||||||
|
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
|
||||||
|
if (!success) {
|
||||||
|
glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
|
||||||
|
std::cout << "Vertex shader compilation failed:\n" << infoLog << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create and compile fragment shader
|
||||||
|
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
|
glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);
|
||||||
|
glCompileShader(fragmentShader);
|
||||||
|
|
||||||
|
// Check fragment shader compilation
|
||||||
|
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
|
||||||
|
if (!success) {
|
||||||
|
glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog);
|
||||||
|
std::cout << "Fragment shader compilation failed:\n" << infoLog << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create shader program
|
||||||
|
GLuint shaderProgram = glCreateProgram();
|
||||||
|
glAttachShader(shaderProgram, vertexShader);
|
||||||
|
glAttachShader(shaderProgram, fragmentShader);
|
||||||
|
glLinkProgram(shaderProgram);
|
||||||
|
|
||||||
|
// Check program linking
|
||||||
|
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
|
||||||
|
if (!success) {
|
||||||
|
glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);
|
||||||
|
std::cout << "Shader program linking failed:\n" << infoLog << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the source texture
|
||||||
|
GLuint sourceTexture;
|
||||||
|
glGenTextures(1, &sourceTexture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, sourceTexture);
|
||||||
|
|
||||||
|
// Fill texture with purple color
|
||||||
|
uint8_t purplePixels[] = {
|
||||||
|
128, 0, 128, 255 // Single purple pixel (RGBA)
|
||||||
|
};
|
||||||
|
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, purplePixels);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
|
||||||
// clearGlError
|
// Create vertex buffer for fullscreen quad
|
||||||
GLenum const error = glGetError();
|
float vertices[] = {
|
||||||
if (error != GL_NO_ERROR) {
|
// Position // Texcoords
|
||||||
std::cout << "Ignoring pending GL error " << error << std::endl;
|
-1.0f, -1.0f, 0.0f, 0.0f, // Bottom left
|
||||||
|
1.0f, -1.0f, 1.0f, 0.0f, // Bottom right
|
||||||
|
-1.0f, 1.0f, 0.0f, 1.0f, // Top left
|
||||||
|
1.0f, 1.0f, 1.0f, 1.0f // Top right
|
||||||
|
};
|
||||||
|
|
||||||
|
GLuint vbo;
|
||||||
|
glGenBuffers(1, &vbo);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
// Setup vertex attributes
|
||||||
|
glUseProgram(shaderProgram);
|
||||||
|
GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
|
||||||
|
GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
|
||||||
|
|
||||||
|
if (posAttrib < 0 || texAttrib < 0) {
|
||||||
|
std::cout << "Failed to get attribute locations. position: " << posAttrib
|
||||||
|
<< " texcoord: " << texAttrib << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(posAttrib);
|
||||||
|
glEnableVertexAttribArray(texAttrib);
|
||||||
|
|
||||||
|
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
|
||||||
|
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
|
||||||
|
|
||||||
|
// Set texture uniform
|
||||||
|
GLint texUniform = glGetUniformLocation(shaderProgram, "u_texture");
|
||||||
|
glUniform1i(texUniform, 0); // Use texture unit 0
|
||||||
|
|
||||||
|
// Clear and render
|
||||||
|
glViewport(0, 0, width, height);
|
||||||
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
// Draw the fullscreen quad
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
|
||||||
|
// Present the result
|
||||||
|
eglSwapBuffers(_eglDisplay, _eglSurface);
|
||||||
|
|
||||||
|
glFlush();
|
||||||
|
|
||||||
|
// // Cleanup
|
||||||
|
// glDeleteBuffers(1, &vbo);
|
||||||
|
// glDeleteProgram(shaderProgram);
|
||||||
|
// glDeleteShader(vertexShader);
|
||||||
|
// glDeleteShader(fragmentShader);
|
||||||
|
// glDeleteTextures(1, &sourceTexture);
|
||||||
|
|
||||||
|
// Check for errors
|
||||||
|
GLenum error = glGetError();
|
||||||
|
if (error != GL_NO_ERROR) {
|
||||||
|
std::cout << "GL error after rendering: " << error << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "FINISHED TEXTURE CREATION AND RENDERING" << std::endl;
|
||||||
|
|
||||||
|
_D3D11DeviceContext->Flush();
|
||||||
|
|
||||||
char const *version;
|
char const *version;
|
||||||
|
|
||||||
version = (char const *)glGetString(GL_VERSION);
|
version = (char const *)glGetString(GL_VERSION);
|
||||||
@@ -172,27 +337,127 @@ EGLTexture::EGLTexture(
|
|||||||
glGetIntegerv(GL_MAJOR_VERSION, &major);
|
glGetIntegerv(GL_MAJOR_VERSION, &major);
|
||||||
glGetIntegerv(GL_MINOR_VERSION, &minor);
|
glGetIntegerv(GL_MINOR_VERSION, &minor);
|
||||||
|
|
||||||
// _textureDescriptor = std::make_unique<FlutterDesktopGpuSurfaceDescriptor>();
|
std::cout << "FINISHED TEXTURE CREATION" << std::endl;
|
||||||
// _textureDescriptor->struct_size = sizeof(FlutterDesktopGpuSurfaceDescriptor);
|
|
||||||
// _textureDescriptor->handle = _d3dTexture2DHandle;
|
|
||||||
// _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();
|
|
||||||
// }));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EGLTexture::FillBlueAndSaveToBMP(const char* filename) {
|
||||||
|
// Create render target view of the texture
|
||||||
|
ID3D11RenderTargetView* rtv = nullptr;
|
||||||
|
D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
|
||||||
|
rtvDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||||
|
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
|
||||||
|
rtvDesc.Texture2D.MipSlice = 0;
|
||||||
|
|
||||||
|
HRESULT hr = _D3D11Device->CreateRenderTargetView(_d3dTexture2D.Get(), &rtvDesc, &rtv);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
std::cout << "Failed to create render target view" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the texture to blue
|
||||||
|
float blueColor[4] = { 0.0f, 0.0f, 1.0f, 1.0f }; // RGBA
|
||||||
|
_D3D11DeviceContext->ClearRenderTargetView(rtv, blueColor);
|
||||||
|
|
||||||
|
// Create staging texture for CPU read access
|
||||||
|
D3D11_TEXTURE2D_DESC stagingDesc = {};
|
||||||
|
_d3dTexture2D->GetDesc(&stagingDesc);
|
||||||
|
stagingDesc.Usage = D3D11_USAGE_STAGING;
|
||||||
|
stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||||
|
stagingDesc.BindFlags = 0;
|
||||||
|
stagingDesc.MiscFlags = 0;
|
||||||
|
|
||||||
|
ID3D11Texture2D* stagingTexture = nullptr;
|
||||||
|
hr = _D3D11Device->CreateTexture2D(&stagingDesc, nullptr, &stagingTexture);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
rtv->Release();
|
||||||
|
std::cout << "Failed to create staging texture" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy to staging texture
|
||||||
|
_D3D11DeviceContext->CopyResource(stagingTexture, _d3dTexture2D.Get());
|
||||||
|
|
||||||
|
// Save to BMP
|
||||||
|
bool success = SaveTextureAsBMP(stagingTexture, filename);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
stagingTexture->Release();
|
||||||
|
rtv->Release();
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
std::cout << "Successfully saved texture to " << filename << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EGLTexture::SaveTextureAsBMP(ID3D11Texture2D* texture, const char* filename) {
|
||||||
|
D3D11_TEXTURE2D_DESC desc;
|
||||||
|
texture->GetDesc(&desc);
|
||||||
|
|
||||||
|
// Map texture to get pixel data
|
||||||
|
D3D11_MAPPED_SUBRESOURCE mappedResource;
|
||||||
|
HRESULT hr = _D3D11DeviceContext->Map(texture, 0, D3D11_MAP_READ, 0, &mappedResource);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
std::cout << "Failed to map texture" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BMP file header
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct BMPHeader {
|
||||||
|
uint16_t signature;
|
||||||
|
uint32_t fileSize;
|
||||||
|
uint32_t reserved;
|
||||||
|
uint32_t dataOffset;
|
||||||
|
uint32_t headerSize;
|
||||||
|
int32_t width;
|
||||||
|
int32_t height;
|
||||||
|
uint16_t planes;
|
||||||
|
uint16_t bitsPerPixel;
|
||||||
|
uint32_t compression;
|
||||||
|
uint32_t imageSize;
|
||||||
|
int32_t xPixelsPerMeter;
|
||||||
|
int32_t yPixelsPerMeter;
|
||||||
|
uint32_t totalColors;
|
||||||
|
uint32_t importantColors;
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
// Create and fill header
|
||||||
|
BMPHeader header = {};
|
||||||
|
header.signature = 0x4D42; // 'BM'
|
||||||
|
header.fileSize = sizeof(BMPHeader) + desc.Width * desc.Height * 4;
|
||||||
|
header.dataOffset = sizeof(BMPHeader);
|
||||||
|
header.headerSize = 40;
|
||||||
|
header.width = desc.Width;
|
||||||
|
header.height = desc.Height;
|
||||||
|
header.planes = 1;
|
||||||
|
header.bitsPerPixel = 32;
|
||||||
|
header.compression = 0;
|
||||||
|
header.imageSize = desc.Width * desc.Height * 4;
|
||||||
|
header.xPixelsPerMeter = 2835; // 72 DPI
|
||||||
|
header.yPixelsPerMeter = 2835; // 72 DPI
|
||||||
|
|
||||||
|
// Write to file
|
||||||
|
FILE* file = nullptr;
|
||||||
|
fopen_s(&file, filename, "wb");
|
||||||
|
if (!file) {
|
||||||
|
_D3D11DeviceContext->Unmap(texture, 0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite(&header, sizeof(header), 1, file);
|
||||||
|
|
||||||
|
// Write pixel data (need to flip rows as BMP is bottom-up)
|
||||||
|
uint8_t* srcData = reinterpret_cast<uint8_t*>(mappedResource.pData);
|
||||||
|
for (int y = desc.Height - 1; y >= 0; y--) {
|
||||||
|
uint8_t* rowData = srcData + y * mappedResource.RowPitch;
|
||||||
|
fwrite(rowData, desc.Width * 4, 1, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
_D3D11DeviceContext->Unmap(texture, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace thermion_flutter
|
} // namespace thermion_flutter
|
||||||
@@ -34,9 +34,14 @@ class EGLTexture {
|
|||||||
);
|
);
|
||||||
~EGLTexture();
|
~EGLTexture();
|
||||||
|
|
||||||
void RenderCallback();
|
void Flush();
|
||||||
|
HANDLE GetTextureHandle();
|
||||||
|
|
||||||
GLuint glTextureId = 0;
|
GLuint glTextureId = 0;
|
||||||
|
|
||||||
|
void FillBlueAndSaveToBMP(const char* filename);
|
||||||
|
bool SaveTextureAsBMP(ID3D11Texture2D* texture, const char* filename);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _error = false;
|
bool _error = false;
|
||||||
@@ -57,8 +62,6 @@ class EGLTexture {
|
|||||||
EGLConfig _eglConfig = EGL_NO_CONFIG_KHR;
|
EGLConfig _eglConfig = EGL_NO_CONFIG_KHR;
|
||||||
EGLSurface _eglSurface = EGL_NO_SURFACE;
|
EGLSurface _eglSurface = EGL_NO_SURFACE;
|
||||||
|
|
||||||
// std::unique_ptr<FlutterDesktopGpuSurfaceDescriptor> _textureDescriptor = nullptr;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,14 +6,14 @@
|
|||||||
int main() {
|
int main() {
|
||||||
std::cout << "Initializing EGL Context..." << std::endl;
|
std::cout << "Initializing EGL Context..." << std::endl;
|
||||||
|
|
||||||
thermion::windows::egl::FlutterEGLContext context;
|
thermion::windows::egl::ThermionEGLContext context;
|
||||||
|
|
||||||
// Create a rendering surface
|
// Create a rendering surface
|
||||||
const uint32_t width = 800;
|
const uint32_t width = 800;
|
||||||
const uint32_t height = 600;
|
const uint32_t height = 600;
|
||||||
|
|
||||||
std::cout << "Creating rendering surface " << width << "x" << height << std::endl;
|
std::cout << "Creating rendering surface " << width << "x" << height << std::endl;
|
||||||
context.CreateRenderingSurface(width, height, 0, 0);
|
auto *texture = context.CreateRenderingSurface(width, height, 0, 0);
|
||||||
|
|
||||||
void* sharedContext = context.GetSharedContext();
|
void* sharedContext = context.GetSharedContext();
|
||||||
if (sharedContext) {
|
if (sharedContext) {
|
||||||
@@ -23,13 +23,10 @@ int main() {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run a simple render loop
|
// Fill with blue and save
|
||||||
std::cout << "Starting render loop..." << std::endl;
|
texture->FillBlueAndSaveToBMP("output.bmp");
|
||||||
for (int i = 0; i < 10; i++) {
|
|
||||||
context.RenderCallback();
|
std::cout << "Saved blue texture to output.bmp" << std::endl;
|
||||||
std::cout << "Rendered frame " << i + 1 << std::endl;
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "EGL Context demo completed" << std::endl;
|
std::cout << "EGL Context demo completed" << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "flutter_texture_buffer.h"
|
|
||||||
|
|
||||||
namespace thermion_flutter {
|
|
||||||
|
|
||||||
class FlutterRenderContext {
|
|
||||||
public:
|
|
||||||
void CreateRenderingSurface(uint32_t width, uint32_t height, uint32_t left, uint32_t top);
|
|
||||||
void DestroyRenderingSurface();
|
|
||||||
void *GetSharedContext();
|
|
||||||
FlutterTextureBuffer GetActiveTexture() {
|
|
||||||
return _active->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
FlutterRenderContext();
|
|
||||||
std::unique_ptr<FlutterTextureBuffer> _active = nullptr;
|
|
||||||
std::unique_ptr<FlutterTextureBuffer> _inactive = nullptr;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#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 thermion_flutter {
|
|
||||||
|
|
||||||
class FlutterTextureBuffer {
|
|
||||||
public:
|
|
||||||
flutter::TextureVariant GetTexture() {
|
|
||||||
return texture->get();
|
|
||||||
}
|
|
||||||
void RegisterFlutterTextureId(int64_t flutterTextureId);
|
|
||||||
int64_t GetFlutterTextureId();
|
|
||||||
private:
|
|
||||||
int64_t flutterTextureId = -1;
|
|
||||||
std::unique_ptr<flutter::TextureVariant> texture;
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -27,15 +27,10 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "flutter_render_context.h"
|
#include "flutter_egl_texture.h"
|
||||||
|
#include "rendering/egl/egl_context.h"
|
||||||
|
|
||||||
#if THERMION_EGL
|
namespace thermion::tflutter::windows {
|
||||||
#include "egl_context.h"
|
|
||||||
#else
|
|
||||||
#include "wgl_context.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace thermion_flutter {
|
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
@@ -133,10 +128,16 @@ static void _freeResource(ResourceBuffer rbf, void *const plugin) {
|
|||||||
((ThermionFlutterPlugin *)plugin)->freeResource(rbf);
|
((ThermionFlutterPlugin *)plugin)->freeResource(rbf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<FlutterEGLTexture> _texture;
|
||||||
|
|
||||||
void ThermionFlutterPlugin::CreateTexture(
|
void ThermionFlutterPlugin::CreateTexture(
|
||||||
const flutter::MethodCall<flutter::EncodableValue> &methodCall,
|
const flutter::MethodCall<flutter::EncodableValue> &methodCall,
|
||||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
|
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
|
||||||
|
|
||||||
|
if (!_context) {
|
||||||
|
_context = std::make_unique<thermion::windows::egl::ThermionEGLContext>();
|
||||||
|
}
|
||||||
|
|
||||||
const auto *args =
|
const auto *args =
|
||||||
std::get_if<flutter::EncodableList>(methodCall.arguments());
|
std::get_if<flutter::EncodableList>(methodCall.arguments());
|
||||||
|
|
||||||
@@ -146,14 +147,17 @@ void ThermionFlutterPlugin::CreateTexture(
|
|||||||
int dTop = *(std::get_if<int>(&(args->at(3))));
|
int dTop = *(std::get_if<int>(&(args->at(3))));
|
||||||
auto width = (uint32_t)round(dWidth );
|
auto width = (uint32_t)round(dWidth );
|
||||||
auto height = (uint32_t)round(dHeight );
|
auto height = (uint32_t)round(dHeight );
|
||||||
auto left = (uint32_t)round(dLeft );
|
auto left = (uint32_t)round(dLeft);
|
||||||
auto top = (uint32_t)round(dTop );
|
auto top = (uint32_t)round(dTop);
|
||||||
|
|
||||||
_context->CreateRenderingSurface(width, height, std::move(result), left, top);
|
thermion::windows::egl::EGLTexture* eglTexture = _context->CreateRenderingSurface(width, height, left, top);
|
||||||
auto texture = _context->GetActiveTexture();
|
|
||||||
|
|
||||||
auto flutterTextureId = _textureRegistrar->RegisterTexture(texture.GetFlutterTextureId());
|
_texture = std::make_unique<FlutterEGLTexture>(eglTexture->GetTextureHandle(), width, height);
|
||||||
texture.RegisterFlutterTextureId(flutterTextureId);
|
|
||||||
|
auto flutterTextureId = _textureRegistrar->RegisterTexture(_texture->GetFlutterTexture());
|
||||||
|
_texture->SetFlutterTextureId(flutterTextureId);
|
||||||
|
auto glTextureId = 0; // _texture.GetGLTextureId();
|
||||||
|
|
||||||
std::cout << "Registered Flutter texture ID " << flutterTextureId
|
std::cout << "Registered Flutter texture ID " << flutterTextureId
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
||||||
@@ -169,7 +173,8 @@ void ThermionFlutterPlugin::DestroyTexture(
|
|||||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
|
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
|
||||||
|
|
||||||
if (_context) {
|
if (_context) {
|
||||||
_context->DestroyRenderingSurface(std::move(result));
|
_context->DestroyRenderingSurface();
|
||||||
|
result->Success(flutter::EncodableValue((int64_t)nullptr));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result->Error("NO_CONTEXT", "No rendering context is active");
|
result->Error("NO_CONTEXT", "No rendering context is active");
|
||||||
@@ -192,15 +197,11 @@ void ThermionFlutterPlugin::HandleMethodCall(
|
|||||||
result->Success(flutter::EncodableValue((int64_t)wrapper));
|
result->Success(flutter::EncodableValue((int64_t)wrapper));
|
||||||
} else if(methodCall.method_name() == "getSharedContext") {
|
} else if(methodCall.method_name() == "getSharedContext") {
|
||||||
if (!_context) {
|
if (!_context) {
|
||||||
#ifdef THERMION_EGL
|
_context = std::make_unique<thermion::windows::egl::ThermionEGLContext>();
|
||||||
_context = std::make_unique<FlutterEGLContext>(_pluginRegistrar, _textureRegistrar);
|
|
||||||
#else
|
|
||||||
_context = std::make_unique<WGLContext>(_pluginRegistrar, _textureRegistrar);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
result->Success(flutter::EncodableValue((int64_t)_context->GetSharedContext()));
|
result->Success(flutter::EncodableValue((int64_t)_context->GetSharedContext()));
|
||||||
} else if (methodCall.method_name() == "resizeWindow") {
|
} else if (methodCall.method_name() == "resizeWindow") {
|
||||||
#if WGL_USE_BACKING_WINDOW
|
|
||||||
const auto *args =
|
const auto *args =
|
||||||
std::get_if<flutter::EncodableList>(methodCall.arguments());
|
std::get_if<flutter::EncodableList>(methodCall.arguments());
|
||||||
|
|
||||||
@@ -215,9 +216,6 @@ void ThermionFlutterPlugin::HandleMethodCall(
|
|||||||
|
|
||||||
_context->ResizeRenderingSurface(width, height, left, top);
|
_context->ResizeRenderingSurface(width, height, left, top);
|
||||||
result->Success();
|
result->Success();
|
||||||
#else
|
|
||||||
result->Error("ERROR", "resizeWindow is only available when using a backing window");
|
|
||||||
#endif
|
|
||||||
} else if (methodCall.method_name() == "createTexture") {
|
} else if (methodCall.method_name() == "createTexture") {
|
||||||
CreateTexture(methodCall, std::move(result));
|
CreateTexture(methodCall, std::move(result));
|
||||||
} else if (methodCall.method_name() == "createWindow") {
|
} else if (methodCall.method_name() == "createWindow") {
|
||||||
@@ -226,18 +224,17 @@ void ThermionFlutterPlugin::HandleMethodCall(
|
|||||||
DestroyTexture(methodCall, std::move(result));
|
DestroyTexture(methodCall, std::move(result));
|
||||||
} else if (methodCall.method_name() == "markTextureFrameAvailable") {
|
} else if (methodCall.method_name() == "markTextureFrameAvailable") {
|
||||||
if (_context) {
|
if (_context) {
|
||||||
auto texture = context->GetActiveTexture();
|
|
||||||
auto flutterTextureId = texture.GetFlutterTextureId();
|
auto texture = _context->GetActiveTexture();
|
||||||
if(flutterTextureId == -1) {
|
texture->Flush();
|
||||||
|
const auto* flutterTextureId = std::get_if<int64_t>(methodCall.arguments());
|
||||||
|
|
||||||
|
if(!flutterTextureId || *flutterTextureId == -1) {
|
||||||
std::cout << "Bad texture" << std::endl;
|
std::cout << "Bad texture" << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#ifdef THERMION_EGL
|
std::cout << "Marking texture" << flutterTextureId << "available" << std::endl;
|
||||||
_context->RenderCallback();
|
_textureRegistrar->MarkTextureFrameAvailable(*flutterTextureId);
|
||||||
#endif
|
|
||||||
#if !WGL_USE_BACKING_WINDOW
|
|
||||||
_textureRegistrar->MarkTextureFrameAvailable(flutterTextureId);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
result->Success(flutter::EncodableValue((int64_t)nullptr));
|
result->Success(flutter::EncodableValue((int64_t)nullptr));
|
||||||
} else if (methodCall.method_name() == "getDriverPlatform") {
|
} else if (methodCall.method_name() == "getDriverPlatform") {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef FLUTTER_PLUGIN_FLUTTER_FILAMENT_PLUGIN_H_
|
#pragma once
|
||||||
#define FLUTTER_PLUGIN_FLUTTER_FILAMENT_PLUGIN_H_
|
|
||||||
|
|
||||||
#include <flutter/method_channel.h>
|
#include <flutter/method_channel.h>
|
||||||
#include <flutter/plugin_registrar_windows.h>
|
#include <flutter/plugin_registrar_windows.h>
|
||||||
@@ -15,18 +14,13 @@
|
|||||||
#include "GL/GLu.h"
|
#include "GL/GLu.h"
|
||||||
|
|
||||||
#include "ResourceBuffer.h"
|
#include "ResourceBuffer.h"
|
||||||
|
#include "rendering/egl/egl_context.h"
|
||||||
|
|
||||||
#if THERMION_EGL
|
namespace thermion::tflutter::windows {
|
||||||
#include "egl_context.h"
|
|
||||||
#else
|
|
||||||
#include "wgl_context.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace thermion_flutter {
|
class ThermionFlutterPlugin : public ::flutter::Plugin {
|
||||||
|
|
||||||
class ThermionFlutterPlugin : public flutter::Plugin {
|
|
||||||
public:
|
public:
|
||||||
static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar);
|
static void RegisterWithRegistrar(::flutter::PluginRegistrarWindows *registrar);
|
||||||
|
|
||||||
ThermionFlutterPlugin(flutter::TextureRegistrar *textureRegistrar,
|
ThermionFlutterPlugin(flutter::TextureRegistrar *textureRegistrar,
|
||||||
flutter::PluginRegistrarWindows *registrar,
|
flutter::PluginRegistrarWindows *registrar,
|
||||||
@@ -59,13 +53,9 @@ public:
|
|||||||
void freeResource(ResourceBuffer rbuf);
|
void freeResource(ResourceBuffer rbuf);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifdef THERMION_EGL
|
std::unique_ptr<thermion::windows::egl::ThermionEGLContext> _context = nullptr;
|
||||||
std::unique_ptr<FlutterEGLContext> _context = nullptr;
|
|
||||||
#else
|
|
||||||
std::unique_ptr<WGLContext> _context = nullptr;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace thermion_flutter
|
} // namespace thermion_flutter
|
||||||
|
|
||||||
#endif // FLUTTER_PLUGIN_FLUTTER_FILAMENT_PLUGIN_H_
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
void ThermionFlutterPluginCApiRegisterWithRegistrar(
|
void ThermionFlutterPluginCApiRegisterWithRegistrar(
|
||||||
FlutterDesktopPluginRegistrarRef registrar) {
|
FlutterDesktopPluginRegistrarRef registrar) {
|
||||||
thermion_flutter::ThermionFlutterPlugin::RegisterWithRegistrar(
|
thermion::tflutter::windows::ThermionFlutterPlugin::RegisterWithRegistrar(
|
||||||
flutter::PluginRegistrarManager::GetInstance()
|
flutter::PluginRegistrarManager::GetInstance()
|
||||||
->GetRegistrar<flutter::PluginRegistrarWindows>(registrar));
|
->GetRegistrar<flutter::PluginRegistrarWindows>(registrar));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,122 +1,123 @@
|
|||||||
import 'package:logging/logging.dart';
|
// import 'package:logging/logging.dart';
|
||||||
import 'package:thermion_dart/thermion_dart.dart';
|
// import 'package:thermion_dart/thermion_dart.dart';
|
||||||
import 'thermion_flutter_method_channel_interface.dart';
|
// import 'thermion_flutter_method_channel_interface.dart';
|
||||||
|
|
||||||
class FlutterPlatformTexture extends MethodChannelFlutterTexture {
|
// class FlutterPlatformTexture extends ThermionFlutterTexture {
|
||||||
final _logger = Logger("ThermionFlutterTexture");
|
// final _logger = Logger("ThermionFlutterTexture");
|
||||||
|
|
||||||
final ThermionViewer viewer;
|
// final ThermionViewer viewer;
|
||||||
final View view;
|
// final View view;
|
||||||
|
|
||||||
int flutterId = -1;
|
// int flutterId = -1;
|
||||||
int _lastFlutterId = -1;
|
// int _lastFlutterId = -1;
|
||||||
int _lastHardwareId = -1;
|
// int _lastHardwareId = -1;
|
||||||
int hardwareId = -1;
|
// int hardwareId = -1;
|
||||||
int width = -1;
|
// int width = -1;
|
||||||
int height = -1;
|
// int height = -1;
|
||||||
|
|
||||||
SwapChain? swapChain;
|
// SwapChain? swapChain;
|
||||||
|
|
||||||
RenderTarget? _renderTarget;
|
// RenderTarget? _renderTarget;
|
||||||
|
|
||||||
late bool destroySwapChainOnResize;
|
// late bool destroySwapChainOnResize;
|
||||||
|
|
||||||
bool destroyed = false;
|
// bool destroyed = false;
|
||||||
|
|
||||||
FlutterPlatformTexture(
|
// FlutterPlatformTexture(
|
||||||
super.channel, this.viewer, this.view, this.swapChain) {
|
// super.channel, this.viewer, this.view, this.swapChain) {
|
||||||
if (swapChain == null) {
|
// if (swapChain == null) {
|
||||||
destroySwapChainOnResize = true;
|
// destroySwapChainOnResize = true;
|
||||||
} else {
|
// } else {
|
||||||
destroySwapChainOnResize = false;
|
// destroySwapChainOnResize = false;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
Future<void> resize(
|
// Future<void> resize(
|
||||||
int newWidth, int newHeight, int newLeft, int newTop) async {
|
// int newWidth, int newHeight, int newLeft, int newTop) async {
|
||||||
_logger.info(
|
// _logger.info(
|
||||||
"Resizing texture to $newWidth x $newHeight (offset $newLeft, $newTop)");
|
// "Resizing texture to $newWidth x $newHeight (offset $newLeft, $newTop)");
|
||||||
if (newWidth == this.width &&
|
// if (newWidth == this.width &&
|
||||||
newHeight == this.height &&
|
// newHeight == this.height &&
|
||||||
newLeft == 0 &&
|
// newLeft == 0 &&
|
||||||
newTop == 0) {
|
// newTop == 0) {
|
||||||
_logger.info("Existing texture matches requested dimensions");
|
// _logger.info("Existing texture matches requested dimensions");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
this.width = newWidth;
|
// this.width = newWidth;
|
||||||
this.height = newHeight;
|
// this.height = newHeight;
|
||||||
|
|
||||||
var result =
|
// var result =
|
||||||
await channel.invokeMethod("createTexture", [width, height, 0, 0]);
|
// await channel.invokeMethod("createTexture", [width, height, 0, 0]);
|
||||||
if (result == null || (result[0] == -1)) {
|
// if (result == null || (result[0] == -1)) {
|
||||||
throw Exception("Failed to create texture");
|
// throw Exception("Failed to create texture");
|
||||||
}
|
// }
|
||||||
_lastFlutterId = flutterId;
|
// _lastFlutterId = flutterId;
|
||||||
_lastHardwareId = hardwareId;
|
// _lastHardwareId = hardwareId;
|
||||||
flutterId = result[0] as int;
|
// flutterId = result[0] as int;
|
||||||
hardwareId = result[1] as int;
|
// hardwareId = result[1] as int;
|
||||||
|
// var window = result[2] as int; // usually 0 for nullptr
|
||||||
|
|
||||||
_logger.info("Created texture ${flutterId} / ${hardwareId}");
|
// _logger.info("Created texture ${flutterId} / ${hardwareId}");
|
||||||
|
|
||||||
if (destroySwapChainOnResize) {
|
// if (destroySwapChainOnResize) {
|
||||||
if (swapChain != null) {
|
// if (swapChain != null) {
|
||||||
await viewer.destroySwapChain(swapChain!);
|
// await viewer.destroySwapChain(swapChain!);
|
||||||
}
|
// }
|
||||||
swapChain = await viewer.createSwapChain(result[2]);
|
// swapChain = await viewer.createSwapChain(window);
|
||||||
await view.setRenderable(true, swapChain!);
|
// await view.setRenderable(true, swapChain!);
|
||||||
} else if (hardwareId != _lastHardwareId) {
|
// } else if (hardwareId != _lastHardwareId) {
|
||||||
if (_renderTarget != null) {
|
// if (_renderTarget != null) {
|
||||||
await viewer.destroyRenderTarget(_renderTarget!);
|
// await viewer.destroyRenderTarget(_renderTarget!);
|
||||||
}
|
// }
|
||||||
_renderTarget =
|
// _renderTarget =
|
||||||
await viewer.createRenderTarget(width, height, hardwareId);
|
// await viewer.createRenderTarget(width, height, hardwareId);
|
||||||
await view.setRenderTarget(_renderTarget!);
|
// await view.setRenderTarget(_renderTarget!);
|
||||||
await view.setRenderable(true, swapChain!);
|
// await view.setRenderable(true, swapChain!);
|
||||||
if (_lastFlutterId != -1 && _lastHardwareId != -1) {
|
// if (_lastFlutterId != -1 && _lastHardwareId != -1) {
|
||||||
await _destroyTexture(_lastFlutterId, _lastHardwareId);
|
// await _destroyTexture(_lastFlutterId, _lastHardwareId);
|
||||||
_lastFlutterId = -1;
|
// _lastFlutterId = -1;
|
||||||
_lastHardwareId = -1;
|
// _lastHardwareId = -1;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
Future<void> _destroyTexture(
|
// Future<void> _destroyTexture(
|
||||||
int flutterTextureId, int hardwareTextureId) async {
|
// int flutterTextureId, int hardwareTextureId) async {
|
||||||
try {
|
// try {
|
||||||
await channel.invokeMethod(
|
// await channel.invokeMethod(
|
||||||
"destroyTexture", [flutterTextureId, hardwareTextureId]);
|
// "destroyTexture", [flutterTextureId, hardwareTextureId]);
|
||||||
_logger.info("Destroyed texture $flutterTextureId / $hardwareTextureId");
|
// _logger.info("Destroyed texture $flutterTextureId / $hardwareTextureId");
|
||||||
} catch (e) {
|
// } catch (e) {
|
||||||
_logger.severe("Failed to destroy texture: $e");
|
// _logger.severe("Failed to destroy texture: $e");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
bool destroying = false;
|
// bool destroying = false;
|
||||||
Future destroy() async {
|
// Future destroy() async {
|
||||||
if (destroyed || destroying) {
|
// if (destroyed || destroying) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
destroying = true;
|
// destroying = true;
|
||||||
await view.setRenderTarget(null);
|
// await view.setRenderTarget(null);
|
||||||
if (_renderTarget != null) {
|
// if (_renderTarget != null) {
|
||||||
await viewer.destroyRenderTarget(_renderTarget!);
|
// await viewer.destroyRenderTarget(_renderTarget!);
|
||||||
_renderTarget = null;
|
// _renderTarget = null;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (destroySwapChainOnResize && swapChain != null) {
|
// if (destroySwapChainOnResize && swapChain != null) {
|
||||||
await viewer.destroySwapChain(swapChain!);
|
// await viewer.destroySwapChain(swapChain!);
|
||||||
swapChain = null;
|
// swapChain = null;
|
||||||
}
|
// }
|
||||||
await _destroyTexture(flutterId, hardwareId);
|
// await _destroyTexture(flutterId, hardwareId);
|
||||||
flutterId = -1;
|
// flutterId = -1;
|
||||||
hardwareId = -1;
|
// hardwareId = -1;
|
||||||
destroying = false;
|
// destroying = false;
|
||||||
destroyed = true;
|
// destroyed = true;
|
||||||
}
|
// }
|
||||||
|
|
||||||
Future markFrameAvailable() async {
|
// Future markFrameAvailable() async {
|
||||||
await channel.invokeMethod("markTextureFrameAvailable", this.flutterId);
|
// await channel.invokeMethod("markTextureFrameAvailable", this.flutterId);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'dart:ffi';
|
|
||||||
import 'package:thermion_dart/thermion_dart.dart';
|
|
||||||
import 'package:thermion_dart/src/viewer/src/ffi/thermion_viewer_ffi.dart';
|
|
||||||
import 'package:thermion_flutter_platform_interface/thermion_flutter_platform_interface.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
|
||||||
import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart';
|
|
||||||
|
|
||||||
///
|
|
||||||
/// An abstract implementation of [ThermionFlutterPlatform] that uses
|
|
||||||
/// Flutter platform channels to create a rendering context,
|
|
||||||
/// resource loaders, and surface/render target(s).
|
|
||||||
///
|
|
||||||
abstract class ThermionFlutterMethodChannelInterface
|
|
||||||
extends ThermionFlutterPlatform {
|
|
||||||
final channel = const MethodChannel("dev.thermion.flutter/event");
|
|
||||||
final _logger = Logger("ThermionFlutterMethodChannelInterface");
|
|
||||||
|
|
||||||
ThermionViewerFFI? viewer;
|
|
||||||
|
|
||||||
Future<ThermionViewer> createViewer({ThermionFlutterOptions? options}) async {
|
|
||||||
if (viewer != null) {
|
|
||||||
throw Exception(
|
|
||||||
"Only one ThermionViewer can be created at any given time; ensure you have called [dispose] on the previous instance before constructing a new instance.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var resourceLoader = Pointer<Void>.fromAddress(
|
|
||||||
await channel.invokeMethod("getResourceLoaderWrapper"));
|
|
||||||
|
|
||||||
if (resourceLoader == nullptr) {
|
|
||||||
throw Exception("Failed to get resource loader");
|
|
||||||
}
|
|
||||||
|
|
||||||
var driverPlatform = await channel.invokeMethod("getDriverPlatform");
|
|
||||||
var driverPtr = driverPlatform == null
|
|
||||||
? nullptr
|
|
||||||
: Pointer<Void>.fromAddress(driverPlatform);
|
|
||||||
|
|
||||||
var sharedContext = await channel.invokeMethod("getSharedContext");
|
|
||||||
|
|
||||||
var sharedContextPtr = sharedContext == null
|
|
||||||
? nullptr
|
|
||||||
: Pointer<Void>.fromAddress(sharedContext);
|
|
||||||
|
|
||||||
viewer = ThermionViewerFFI(
|
|
||||||
resourceLoader: resourceLoader,
|
|
||||||
driver: driverPtr,
|
|
||||||
sharedContext: sharedContextPtr,
|
|
||||||
uberArchivePath: options?.uberarchivePath);
|
|
||||||
await viewer!.initialized;
|
|
||||||
|
|
||||||
viewer!.onDispose(() async {
|
|
||||||
this.viewer = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
return viewer!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class MethodChannelFlutterTexture extends ThermionFlutterTexture {
|
|
||||||
final MethodChannel channel;
|
|
||||||
|
|
||||||
MethodChannelFlutterTexture(this.channel);
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get flutterId;
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hardwareId;
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get height;
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get width;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:thermion_dart/thermion_dart.dart';
|
||||||
|
import 'package:thermion_dart/thermion_dart.dart' as t;
|
||||||
|
import 'package:thermion_flutter_ffi/src/thermion_flutter_method_channel_platform.dart';
|
||||||
|
import 'package:thermion_flutter_platform_interface/thermion_flutter_platform_interface.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart';
|
||||||
|
import 'package:thermion_flutter_platform_interface/thermion_flutter_window.dart';
|
||||||
|
|
||||||
|
///
|
||||||
|
/// An abstract implementation of [ThermionFlutterPlatform] that uses
|
||||||
|
/// Flutter platform channels to create a rendering context,
|
||||||
|
/// resource loaders, and surface/render target(s).
|
||||||
|
///
|
||||||
|
class ThermionFlutterMethodChannelPlatform
|
||||||
|
extends ThermionFlutterPlatform {
|
||||||
|
|
||||||
|
final channel = const MethodChannel("dev.thermion.flutter/event");
|
||||||
|
final _logger = Logger("ThermionFlutterMethodChannelPlatform");
|
||||||
|
|
||||||
|
|
||||||
|
static SwapChain? _swapChain;
|
||||||
|
|
||||||
|
ThermionFlutterMethodChannelPlatform._();
|
||||||
|
|
||||||
|
static ThermionFlutterMethodChannelPlatform? instance;
|
||||||
|
|
||||||
|
static void registerWith() {
|
||||||
|
instance ??= ThermionFlutterMethodChannelPlatform._();
|
||||||
|
ThermionFlutterPlatform.instance = instance!;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThermionViewerFFI? viewer;
|
||||||
|
|
||||||
|
Future<ThermionViewer> createViewer({ThermionFlutterOptions? options}) async {
|
||||||
|
if (viewer != null) {
|
||||||
|
throw Exception(
|
||||||
|
"Only one ThermionViewer can be created at any given time; ensure you have called [dispose] on the previous instance before constructing a new instance.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var resourceLoader = Pointer<Void>.fromAddress(
|
||||||
|
await channel.invokeMethod("getResourceLoaderWrapper"));
|
||||||
|
|
||||||
|
if (resourceLoader == nullptr) {
|
||||||
|
throw Exception("Failed to get resource loader");
|
||||||
|
}
|
||||||
|
|
||||||
|
var driverPlatform = await channel.invokeMethod("getDriverPlatform");
|
||||||
|
var driverPtr = driverPlatform == null
|
||||||
|
? nullptr
|
||||||
|
: Pointer<Void>.fromAddress(driverPlatform);
|
||||||
|
|
||||||
|
var sharedContext = await channel.invokeMethod("getSharedContext");
|
||||||
|
|
||||||
|
var sharedContextPtr = sharedContext == null
|
||||||
|
? nullptr
|
||||||
|
: Pointer<Void>.fromAddress(sharedContext);
|
||||||
|
|
||||||
|
viewer = ThermionViewerFFI(
|
||||||
|
resourceLoader: resourceLoader,
|
||||||
|
driver: driverPtr,
|
||||||
|
sharedContext: sharedContextPtr,
|
||||||
|
uberArchivePath: options?.uberarchivePath);
|
||||||
|
await viewer!.initialized;
|
||||||
|
|
||||||
|
viewer!.onDispose(() async {
|
||||||
|
_swapChain = null;
|
||||||
|
this.viewer = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (_swapChain != null) {
|
||||||
|
throw Exception("Only a single swapchain can be created");
|
||||||
|
}
|
||||||
|
|
||||||
|
// this implementation renders directly into a texture/render target
|
||||||
|
// we still need to create a (headless) swapchain, but the actual dimensions
|
||||||
|
// don't matter
|
||||||
|
if (Platform.isMacOS || Platform.isIOS || Platform.isWindows) {
|
||||||
|
_swapChain = await viewer!.createHeadlessSwapChain(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return viewer!;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ThermionFlutterTexture?> createTexture(int width, int height) async {
|
||||||
|
var result =
|
||||||
|
await channel.invokeMethod("createTexture", [width, height, 0, 0]);
|
||||||
|
if (result == null || (result[0] == -1)) {
|
||||||
|
throw Exception("Failed to create texture");
|
||||||
|
}
|
||||||
|
final flutterId = result[0] as int;
|
||||||
|
final hardwareId = result[1] as int;
|
||||||
|
var window = result[2] as int; // usually 0 for nullptr
|
||||||
|
|
||||||
|
return ThermionFlutterTexture(flutterId:flutterId, hardwareId:hardwareId, height:height, width:width, window:window);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future bind(view, ThermionFlutterTexture texture) {
|
||||||
|
// TODO: implement bind
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ThermionFlutterWindow> createWindow(int width, int height, int offsetLeft, int offsetTop) {
|
||||||
|
// TODO: implement createWindow
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future destroyTexture(ThermionFlutterTexture texture) {
|
||||||
|
// TODO: implement destroyTexture
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future markTextureFrameAvailable(ThermionFlutterTexture texture) async {
|
||||||
|
await channel.invokeMethod("markTextureFrameAvailable", texture.flutterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ThermionFlutterTexture> resizeTexture(ThermionFlutterTexture texture, int width, int height) async {
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:thermion_dart/thermion_dart.dart';
|
|
||||||
import 'package:thermion_dart/thermion_dart.dart' as t;
|
|
||||||
import 'package:thermion_flutter_ffi/src/thermion_flutter_method_channel_interface.dart';
|
|
||||||
import 'package:thermion_flutter_platform_interface/thermion_flutter_platform_interface.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
|
||||||
import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart';
|
|
||||||
import 'package:thermion_flutter_platform_interface/thermion_flutter_window.dart';
|
|
||||||
|
|
||||||
import 'platform_texture.dart';
|
|
||||||
|
|
||||||
///
|
|
||||||
/// An implementation of [ThermionFlutterPlatform] that uses
|
|
||||||
/// Flutter platform channels to create a rendering context,
|
|
||||||
/// resource loaders, and a texture that will be used as a render target
|
|
||||||
/// for a headless swapchain.
|
|
||||||
///
|
|
||||||
class ThermionFlutterTextureBackedPlatform
|
|
||||||
extends ThermionFlutterMethodChannelInterface {
|
|
||||||
final _logger = Logger("ThermionFlutterTextureBackedPlatform");
|
|
||||||
|
|
||||||
static SwapChain? _swapChain;
|
|
||||||
|
|
||||||
ThermionFlutterTextureBackedPlatform._();
|
|
||||||
|
|
||||||
static ThermionFlutterTextureBackedPlatform? instance;
|
|
||||||
|
|
||||||
static void registerWith() {
|
|
||||||
instance ??= ThermionFlutterTextureBackedPlatform._();
|
|
||||||
ThermionFlutterPlatform.instance = instance!;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<ThermionViewer> createViewer({ThermionFlutterOptions? options}) async {
|
|
||||||
var viewer = await super.createViewer(options: options);
|
|
||||||
if (_swapChain != null) {
|
|
||||||
throw Exception("Only a single swapchain can be created");
|
|
||||||
}
|
|
||||||
|
|
||||||
// this implementation renders directly into a texture/render target
|
|
||||||
// we still need to create a (headless) swapchain, but the actual dimensions
|
|
||||||
// don't matter
|
|
||||||
if (Platform.isMacOS || Platform.isIOS || Platform.isWindows) {
|
|
||||||
_swapChain = await viewer.createHeadlessSwapChain(1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
viewer.onDispose(() async {
|
|
||||||
_swapChain = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
return viewer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// On desktop platforms, textures are always created
|
|
||||||
Future<ThermionFlutterTexture?> createTexture(
|
|
||||||
t.View view, int width, int height) async {
|
|
||||||
var texture = FlutterPlatformTexture(channel, viewer!, view,
|
|
||||||
(Platform.isMacOS || Platform.isIOS || Platform.isWindows) ? _swapChain : null);
|
|
||||||
await texture.resize(width, height, 0, 0);
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<ThermionFlutterWindow> createWindow(
|
|
||||||
int width, int height, int offsetLeft, int offsetTop) {
|
|
||||||
// TODO: implement createWindow
|
|
||||||
throw UnimplementedError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,135 +1,135 @@
|
|||||||
import 'dart:async';
|
// import 'dart:async';
|
||||||
import 'package:flutter/services.dart';
|
// import 'package:flutter/services.dart';
|
||||||
import 'package:thermion_dart/thermion_dart.dart';
|
// import 'package:thermion_dart/thermion_dart.dart';
|
||||||
import 'package:thermion_flutter_ffi/src/thermion_flutter_method_channel_interface.dart';
|
// import 'package:thermion_flutter_ffi/src/thermion_flutter_method_channel_interface.dart';
|
||||||
import 'package:thermion_flutter_platform_interface/thermion_flutter_platform_interface.dart';
|
// import 'package:thermion_flutter_platform_interface/thermion_flutter_platform_interface.dart';
|
||||||
import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart';
|
// import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart';
|
||||||
import 'package:logging/logging.dart';
|
// import 'package:logging/logging.dart';
|
||||||
import 'package:thermion_flutter_platform_interface/thermion_flutter_window.dart';
|
// import 'package:thermion_flutter_platform_interface/thermion_flutter_window.dart';
|
||||||
|
|
||||||
import 'platform_texture.dart';
|
// import 'platform_texture.dart';
|
||||||
|
|
||||||
///
|
// ///
|
||||||
/// A Windows-only implementation of [ThermionFlutterPlatform] that uses
|
// /// A Windows-only implementation of [ThermionFlutterPlatform] that uses
|
||||||
/// a Flutter platform channel to create a rendering context,
|
// /// a Flutter platform channel to create a rendering context,
|
||||||
/// resource loader and a native HWND that will be sit behind the running
|
// /// resource loader and a native HWND that will be sit behind the running
|
||||||
/// Flutter application.
|
// /// Flutter application.
|
||||||
///
|
// ///
|
||||||
class ThermionFlutterWindows
|
// class ThermionFlutterWindows
|
||||||
extends ThermionFlutterMethodChannelInterface {
|
// extends ThermionFlutterMethodChannelPlatform {
|
||||||
|
|
||||||
final _channel = const MethodChannel("dev.thermion.flutter/event");
|
// final _channel = const MethodChannel("dev.thermion.flutter/event");
|
||||||
|
|
||||||
final _logger = Logger("ThermionFlutterWindows");
|
// final _logger = Logger("ThermionFlutterWindows");
|
||||||
|
|
||||||
ThermionViewer? _viewer;
|
// ThermionViewer? _viewer;
|
||||||
|
|
||||||
SwapChain? _swapChain;
|
// SwapChain? _swapChain;
|
||||||
|
|
||||||
ThermionFlutterWindows._() {}
|
// ThermionFlutterWindows._() {}
|
||||||
|
|
||||||
static void registerWith() {
|
// static void registerWith() {
|
||||||
ThermionFlutterPlatform.instance = ThermionFlutterWindows._();
|
// ThermionFlutterPlatform.instance = ThermionFlutterWindows._();
|
||||||
}
|
// }
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
Future<ThermionViewer> createViewer({ThermionFlutterOptions? options}) async {
|
// Future<ThermionViewer> createViewer({ThermionFlutterOptions? options}) async {
|
||||||
if(_viewer != null) {
|
// if(_viewer != null) {
|
||||||
throw Exception("Only one viewer should be instantiated over the life of the app");
|
// throw Exception("Only one viewer should be instantiated over the life of the app");
|
||||||
}
|
// }
|
||||||
_viewer = await super.createViewer(options: options);
|
// _viewer = await super.createViewer(options: options);
|
||||||
_viewer!.onDispose(() async {
|
// _viewer!.onDispose(() async {
|
||||||
_viewer = null;
|
// _viewer = null;
|
||||||
});
|
// });
|
||||||
return _viewer!;
|
// return _viewer!;
|
||||||
}
|
// }
|
||||||
|
|
||||||
///
|
// ///
|
||||||
/// Not supported on Windows. Throws an exception.
|
// /// Not supported on Windows. Throws an exception.
|
||||||
///
|
// ///
|
||||||
@override
|
// @override
|
||||||
Future<ThermionFlutterTexture?> createTexture(View view, int width, int height) async {
|
// Future<ThermionFlutterTexture?> createTexture(View view, int width, int height) async {
|
||||||
var texture = FlutterPlatformTexture(channel, viewer!, view, null);
|
// var texture = FlutterPlatformTexture(channel, viewer!, view, null);
|
||||||
await texture.resize(width, height, 0, 0);
|
// await texture.resize(width, height, 0, 0);
|
||||||
return texture;
|
// return texture;
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
Future<ThermionFlutterWindow> createWindow(int width, int height, int offsetLeft, int offsetTop) async {
|
// Future<ThermionFlutterWindow> createWindow(int width, int height, int offsetLeft, int offsetTop) async {
|
||||||
|
|
||||||
var result = await _channel
|
// var result = await _channel
|
||||||
.invokeMethod("createWindow", [width, height, offsetLeft, offsetLeft]);
|
// .invokeMethod("createWindow", [width, height, offsetLeft, offsetLeft]);
|
||||||
|
|
||||||
if (result == null || result[2] == -1) {
|
// if (result == null || result[2] == -1) {
|
||||||
throw Exception("Failed to create window");
|
// throw Exception("Failed to create window");
|
||||||
}
|
// }
|
||||||
|
|
||||||
var window =
|
// var window =
|
||||||
ThermionFlutterWindowImpl(result[2], _channel, viewer!);
|
// ThermionFlutterWindowImpl(result[2], _channel, viewer!);
|
||||||
await window.resize(width, height, offsetLeft, offsetTop);
|
// await window.resize(width, height, offsetLeft, offsetTop);
|
||||||
var view = await _viewer!.getViewAt(0);
|
// var view = await _viewer!.getViewAt(0);
|
||||||
|
|
||||||
await view.updateViewport(width, height);
|
// await view.updateViewport(width, height);
|
||||||
_swapChain = await _viewer!.createSwapChain(window.handle);
|
// _swapChain = await _viewer!.createSwapChain(window.handle);
|
||||||
await view.setRenderable(true, _swapChain!);
|
// await view.setRenderable(true, _swapChain!);
|
||||||
return window;
|
// return window;
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|
||||||
class ThermionFlutterWindowImpl extends ThermionFlutterWindow {
|
// class ThermionFlutterWindowImpl extends ThermionFlutterWindow {
|
||||||
|
|
||||||
final ThermionViewer viewer;
|
// final ThermionViewer viewer;
|
||||||
final int handle;
|
// final int handle;
|
||||||
int height = 0;
|
// int height = 0;
|
||||||
int width = 0;
|
// int width = 0;
|
||||||
int offsetLeft = 0;
|
// int offsetLeft = 0;
|
||||||
int offsetTop = 0;
|
// int offsetTop = 0;
|
||||||
final MethodChannel _channel;
|
// final MethodChannel _channel;
|
||||||
|
|
||||||
ThermionFlutterWindowImpl(this.handle, this._channel, this.viewer);
|
// ThermionFlutterWindowImpl(this.handle, this._channel, this.viewer);
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
Future destroy() async {
|
// Future destroy() async {
|
||||||
await _channel
|
// await _channel
|
||||||
.invokeMethod("destroyWindow", this.handle);
|
// .invokeMethod("destroyWindow", this.handle);
|
||||||
}
|
// }
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
Future markFrameAvailable() {
|
// Future markFrameAvailable() {
|
||||||
// TODO: implement markFrameAvailable
|
// // TODO: implement markFrameAvailable
|
||||||
throw UnimplementedError();
|
// throw UnimplementedError();
|
||||||
}
|
// }
|
||||||
|
|
||||||
bool _resizing = false;
|
// bool _resizing = false;
|
||||||
|
|
||||||
///
|
// ///
|
||||||
/// Called by [ThermionWidget] to resize the window. Don't call this yourself.
|
// /// Called by [ThermionWidget] to resize the window. Don't call this yourself.
|
||||||
///
|
// ///
|
||||||
@override
|
// @override
|
||||||
Future resize(
|
// Future resize(
|
||||||
int width, int height, int offsetLeft, int offsetTop) async {
|
// int width, int height, int offsetLeft, int offsetTop) async {
|
||||||
if (_resizing) {
|
// if (_resizing) {
|
||||||
throw Exception("Resize underway");
|
// throw Exception("Resize underway");
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (width == this.width && height == this.height && this.offsetLeft == offsetLeft && this.offsetTop == offsetTop) {
|
// if (width == this.width && height == this.height && this.offsetLeft == offsetLeft && this.offsetTop == offsetTop) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
this.width = width;
|
// this.width = width;
|
||||||
this.height = height;
|
// this.height = height;
|
||||||
this.offsetLeft = offsetLeft;
|
// this.offsetLeft = offsetLeft;
|
||||||
this.offsetTop = offsetTop;
|
// this.offsetTop = offsetTop;
|
||||||
|
|
||||||
_resizing = true;
|
// _resizing = true;
|
||||||
|
|
||||||
await _channel
|
// await _channel
|
||||||
.invokeMethod("resizeWindow", [width, height, offsetLeft, offsetTop]);
|
// .invokeMethod("resizeWindow", [width, height, offsetLeft, offsetTop]);
|
||||||
_resizing = false;
|
// _resizing = false;
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
}
|
// }
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
library;
|
library;
|
||||||
export 'src/thermion_flutter_windows.dart';
|
export 'src/thermion_flutter_windows.dart';
|
||||||
export 'src/thermion_flutter_texture_backed_platform.dart';
|
export 'src/thermion_flutter_method_channel_platform.dart';
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ flutter:
|
|||||||
implements: thermion_flutter_platform_interface
|
implements: thermion_flutter_platform_interface
|
||||||
platforms:
|
platforms:
|
||||||
ios:
|
ios:
|
||||||
dartPluginClass: ThermionFlutterTextureBackedPlatform
|
dartPluginClass: ThermionFlutterMethodChannelPlatform
|
||||||
android:
|
android:
|
||||||
dartPluginClass: ThermionFlutterTextureBackedPlatform
|
dartPluginClass: ThermionFlutterMethodChannelPlatform
|
||||||
macos:
|
macos:
|
||||||
dartPluginClass: ThermionFlutterTextureBackedPlatform
|
dartPluginClass: ThermionFlutterMethodChannelPlatform
|
||||||
windows:
|
windows:
|
||||||
dartPluginClass: ThermionFlutterTextureBackedPlatform
|
dartPluginClass: ThermionFlutterMethodChannelPlatform
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
@@ -26,7 +26,9 @@ dependencies:
|
|||||||
thermion_flutter_platform_interface: ^0.2.1-dev.16
|
thermion_flutter_platform_interface: ^0.2.1-dev.16
|
||||||
thermion_dart: ^0.2.1-dev.0.0.16
|
thermion_dart: ^0.2.1-dev.0.0.16
|
||||||
logging: ^1.2.0
|
logging: ^1.2.0
|
||||||
|
dependency_overrides:
|
||||||
|
thermion_flutter_platform_interface:
|
||||||
|
path: ../thermion_flutter_platform_interface
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|||||||
@@ -39,7 +39,34 @@ abstract class ThermionFlutterPlatform extends PlatformInterface {
|
|||||||
/// call this yourself. May not be supported on all platforms.
|
/// call this yourself. May not be supported on all platforms.
|
||||||
///
|
///
|
||||||
Future<ThermionFlutterTexture?> createTexture(
|
Future<ThermionFlutterTexture?> createTexture(
|
||||||
t.View view, int width, int height);
|
int width, int height);
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
Future<ThermionFlutterTexture?> resizeTexture(
|
||||||
|
ThermionFlutterTexture texture,
|
||||||
|
int width, int height);
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
Future destroyTexture(ThermionFlutterTexture texture);
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
Future markTextureFrameAvailable(ThermionFlutterTexture texture);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Binds a rendering surface to the given View.
|
||||||
|
///
|
||||||
|
/// This is internal; unless you are [thermion_*] package developer, don't
|
||||||
|
/// call this yourself. May not be supported on all platforms.
|
||||||
|
///
|
||||||
|
Future bind(
|
||||||
|
t.View view, ThermionFlutterTexture texture);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Create a rendering window.
|
/// Create a rendering window.
|
||||||
|
|||||||
@@ -1,17 +1,13 @@
|
|||||||
abstract class ThermionFlutterTexture {
|
class ThermionFlutterTexture {
|
||||||
|
|
||||||
int get width;
|
final int width;
|
||||||
int get height;
|
final int height;
|
||||||
|
|
||||||
int get flutterId;
|
final int flutterId;
|
||||||
int get hardwareId;
|
final int hardwareId;
|
||||||
|
|
||||||
///
|
final int window;
|
||||||
/// Destroy a texture and clean up the texture cache (if applicable).
|
|
||||||
///
|
|
||||||
Future destroy();
|
|
||||||
|
|
||||||
Future resize(int width, int height, int left, int top);
|
ThermionFlutterTexture({required this.width, required this.height, required this.flutterId, required this.hardwareId, required this.window});
|
||||||
|
|
||||||
Future markFrameAvailable();
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user