more D3D interop work

This commit is contained in:
Nick Fisher
2023-09-26 15:14:17 +10:00
parent 77eb42ce30
commit c27ca565f9
17 changed files with 2971 additions and 93 deletions

View File

@@ -40,6 +40,8 @@ target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
target_include_directories(${PLUGIN_NAME} INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/include")
add_library(EGL SHARED IMPORTED)
set_property(TARGET EGL PROPERTY IMPORTED_IMPLIB "${CMAKE_CURRENT_SOURCE_DIR}/lib/libEGL.dll.lib")
add_library(bluegl SHARED IMPORTED)
set_property(TARGET bluegl PROPERTY IMPORTED_IMPLIB "${CMAKE_CURRENT_SOURCE_DIR}/lib/bluegl.lib")
add_library(geometry SHARED IMPORTED)
@@ -105,12 +107,6 @@ set_property(TARGET png PROPERTY IMPORTED_IMPLIB "${CMAKE_CURRENT_SOURCE_DIR}/li
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../ios/include)
get_cmake_property(_variableNames VARIABLES)
list (SORT _variableNames)
foreach (_variableName ${_variableNames})
message(STATUS "${_variableName}FOO=BAR${${_variableName}}")
endforeach()
target_link_libraries(${PLUGIN_NAME} PRIVATE
flutter
flutter_wrapper_plugin
@@ -145,11 +141,17 @@ opengl32
png
tinyexr
Shlwapi
EGL
)
# List of absolute paths to libraries that should be bundled with the plugin
set(polyvox_filament_bundled_libraries
""
${CMAKE_CURRENT_SOURCE_DIR}/lib/libEGL.dll
PARENT_SCOPE
windows/lib/*.lib
)
get_cmake_property(_variableNames VARIABLES)
list (SORT _variableNames)
foreach (_variableName ${_variableNames})
message(STATUS "${_variableName}FOO=BAR${${_variableName}}")
endforeach()

View File

@@ -0,0 +1,131 @@
// This file is a part of media_kit
// (https://github.com/media-kit/media-kit).
//
// Copyright © 2021 & onwards, Hitesh Kumar Saini <saini123hitesh@gmail.com>.
// All rights reserved.
// Use of this source code is governed by MIT license that can be found in the
// LICENSE file.
#ifndef ANGLE_SURFACE_MANAGER_H_
#define ANGLE_SURFACE_MANAGER_H_
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <EGL/eglplatform.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <Windows.h>
#include <d3d.h>
#include <d3d11.h>
#include <wrl.h>
#include <cstdint>
#include <functional>
// |ANGLESurfaceManager| provides an abstraction around ANGLE to easily draw
// OpenGL ES 2.0 content & read as D3D 11 texture using shared |HANDLE|.
// * |Draw|: Takes callback where OpenGL ES 2.0 calls can be made for rendering.
// * |Read|: Copies the drawn content to D3D 11 texture & makes it available to
// the shared |handle| for access.
// A large part of implementation is inspired from Flutter.
// https://github.com/flutter/engine/blob/master/shell/platform/windows/angle_surface_manager.h
class ANGLESurfaceManager {
public:
const int32_t width() const { return width_; }
const int32_t height() const { return height_; }
const HANDLE handle() const { return handle_; }
ANGLESurfaceManager(int32_t width, int32_t height);
~ANGLESurfaceManager();
void HandleResize(int32_t width, int32_t height);
void Draw(std::function<void()> callback);
void Read();
void MakeCurrent(bool value);
private:
void SwapBuffers();
void Create();
void CleanUp(bool release_context);
bool CreateD3DTexture();
bool CreateEGLDisplay();
bool CreateAndBindEGLSurface();
IDXGIAdapter* adapter_ = nullptr;
int32_t width_ = 1;
int32_t height_ = 1;
HANDLE internal_handle_ = nullptr;
HANDLE handle_ = nullptr;
// Sync |Draw| & |Read| calls.
HANDLE mutex_ = nullptr;
// D3D 11
ID3D11Device* d3d_11_device_ = nullptr;
ID3D11DeviceContext* d3d_11_device_context_ = nullptr;
Microsoft::WRL::ComPtr<ID3D11Texture2D> internal_d3d_11_texture_2D_;
Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d_11_texture_2D_;
// ANGLE
EGLSurface surface_ = EGL_NO_SURFACE;
EGLDisplay display_ = EGL_NO_DISPLAY;
EGLContext context_ = nullptr;
EGLConfig config_ = nullptr;
static constexpr EGLint kEGLConfigurationAttributes[] = {
EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 8, EGL_STENCIL_SIZE, 8,
EGL_NONE,
};
static constexpr EGLint kEGLContextAttributes[] = {
EGL_CONTEXT_CLIENT_VERSION,
2,
EGL_NONE,
};
static constexpr EGLint kD3D11DisplayAttributes[] = {
EGL_PLATFORM_ANGLE_TYPE_ANGLE,
EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
EGL_TRUE,
EGL_NONE,
};
static constexpr EGLint kD3D11_9_3DisplayAttributes[] = {
EGL_PLATFORM_ANGLE_TYPE_ANGLE,
EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE,
9,
EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE,
3,
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
EGL_TRUE,
EGL_NONE,
};
static constexpr EGLint kD3D9DisplayAttributes[] = {
EGL_PLATFORM_ANGLE_TYPE_ANGLE,
EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE,
EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE,
EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE,
EGL_NONE,
};
static constexpr EGLint kWrapDisplayAttributes[] = {
EGL_PLATFORM_ANGLE_TYPE_ANGLE,
EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
EGL_TRUE,
EGL_NONE,
};
// Number of active instances of ANGLESurfaceManager.
static int32_t instance_count_;
};
#endif // ANGLE_SURFACE_MANAGER_H_

3
windows/lib/libEGL.dll Normal file
View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e6d3c37b5642a0a401a612136305fe645e8805c66a26f92609ea3e1111b631f4
size 475464

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f98edce75b32a5f61ff13e9b1dd2e87a65ee5bb41e618dc099674454c4566855
size 19576

View File

@@ -12,6 +12,7 @@
#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>
@@ -27,15 +28,10 @@
#include <vector>
#include <future>
#include <d3d.h>
#include <d3d11.h>
#include "GL/GL.h"
#include "GL/GLu.h"
#include "GL/wglext.h"
#include <Windows.h>
#include <wrl.h>
#include "PolyvoxFilamentApi.h"
#include "ThreadPool.hpp"
@@ -173,6 +169,11 @@ void PolyvoxFilamentPlugin::Render(
plugin->_textureRegistrar->MarkTextureFrameAvailable(
plugin->_flutterTextureId);
};
_D3D11DeviceContext->CopyResource(_externalD3DTexture2D.Get(),
_internalD3DTexture2D.Get());
_D3D11DeviceContext->Flush();
// render(_viewer, 0, _pixelData.get(), callback, this);
std::packaged_task<void()> lambda([=]() mutable {
render(_viewer, 0, nullptr, nullptr, nullptr);
@@ -200,10 +201,47 @@ void PolyvoxFilamentPlugin::CreateTexture(
const auto width = (uint32_t)round(*(std::get_if<double>(&(args->at(0)))));
const auto height = (uint32_t)round(*(std::get_if<double>(&(args->at(1)))));
IDXGIAdapter* adapter_ = nullptr;
EGLSurface surface_ = EGL_NO_SURFACE;
EGLDisplay display_ = EGL_NO_DISPLAY;
EGLContext context_ = nullptr;
EGLConfig config_ = nullptr;
ID3D11Device* d3d_11_device_ = nullptr;
ID3D11DeviceContext* d3d_11_device_context_ = nullptr;
void* bar = eglGetProcAddress;
void* foo = eglGetProcAddress("eglGetPlatformDisplayEXT");
if (display_ == EGL_NO_DISPLAY) {
auto eglGetPlatformDisplayEXT =
reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(
eglGetProcAddress("eglGetPlatformDisplayEXT"));
if (eglGetPlatformDisplayEXT) {
display_ = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
EGL_DEFAULT_DISPLAY,
kD3D11DisplayAttributes);
if (eglInitialize(display_, 0, 0) == EGL_FALSE) {
display_ = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
EGL_DEFAULT_DISPLAY,
kD3D11_9_3DisplayAttributes);
if (eglInitialize(display_, 0, 0) == EGL_FALSE) {
display_ = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
EGL_DEFAULT_DISPLAY,
kD3D9DisplayAttributes);
if (eglInitialize(display_, 0, 0) == EGL_FALSE) {
display_ = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
EGL_DEFAULT_DISPLAY,
kWrapDisplayAttributes);
if (eglInitialize(display_, 0, 0) == EGL_FALSE) {
result->Error("eglGetPlatformDisplayEXT");
}
}
}
}
} else {
result->Error("eglGetProcAddress");
}
}
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
@@ -239,7 +277,7 @@ void PolyvoxFilamentPlugin::CreateTexture(
auto hr = ::D3D11CreateDevice(
adapter_, D3D_DRIVER_TYPE_UNKNOWN, 0, 0, feature_levels.begin(),
static_cast<UINT>(feature_levels.size()), D3D11_SDK_VERSION,
&d3d_11_device_, 0, &d3d_11_device_context_);
&_D3D11Device, 0, &_D3D11DeviceContext);
if (FAILED(hr)) {
result->Error("ERROR", "Failed to create D3D device", nullptr);
@@ -262,52 +300,48 @@ void PolyvoxFilamentPlugin::CreateTexture(
texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
// create internal texture
HANDLE internal_handle_ = nullptr;
Microsoft::WRL::ComPtr<ID3D11Texture2D> internal_d3d_11_texture_2D_;
hr = d3d_11_device_->CreateTexture2D(&texDesc, nullptr, &internal_d3d_11_texture_2D_);
hr = _D3D11Device->CreateTexture2D(&texDesc, nullptr, &_internalD3DTexture2D);
if FAILED(hr)
{
result->Error("ERROR", "Failed to create D3D texture", nullptr);
return;
}
auto resource = Microsoft::WRL::ComPtr<IDXGIResource>{};
hr = internal_d3d_11_texture_2D_.As(&resource);
hr = _internalD3DTexture2D.As(&resource);
if FAILED(hr) {
result->Error("ERROR", "Failed to create D3D texture", nullptr);
return;
}
hr = resource->GetSharedHandle(&internal_handle_);
hr = resource->GetSharedHandle(&_internalD3DTextureHandle);
if FAILED(hr) {
result->Error("ERROR", "Failed to get shared handle to D3D texture", nullptr);
return;
}
internal_d3d_11_texture_2D_->AddRef();
_internalD3DTexture2D->AddRef();
std::cout << "Created internal D3D texture" << std::endl;
// external
HANDLE handle_ = nullptr;
Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d_11_texture_2D_;
hr = d3d_11_device_->CreateTexture2D(&texDesc, nullptr, &d3d_11_texture_2D_);
hr = _D3D11Device->CreateTexture2D(&texDesc, nullptr, &_externalD3DTexture2D);
if FAILED(hr)
{
result->Error("ERROR", "Failed to create D3D texture", nullptr);
return;
}
resource = Microsoft::WRL::ComPtr<IDXGIResource>{};
hr = d3d_11_texture_2D_.As(&resource);
hr = _externalD3DTexture2D.As(&resource);
if FAILED(hr) {
result->Error("ERROR", "Failed to create D3D texture", nullptr);
return;
}
hr = resource->GetSharedHandle(&handle_);
hr = resource->GetSharedHandle(&_externalD3DTextureHandle);
if FAILED(hr) {
result->Error("ERROR", "Failed to get shared handle to external D3D texture", nullptr);
return;
}
d3d_11_texture_2D_->AddRef();
_externalD3DTexture2D->AddRef();
std::cout << "Created external D3D texture" << std::endl;
@@ -396,8 +430,6 @@ void PolyvoxFilamentPlugin::CreateTexture(
return;
}
_pixelData.reset(new uint8_t[width * height * 4]);
glGenTextures(1, &_glTextureId);
GLenum err = glGetError();
@@ -423,50 +455,65 @@ void PolyvoxFilamentPlugin::CreateTexture(
result->Error("ERROR", "Failed to generate texture, GL error was %d", err);
return;
}
// _pixelData.reset(new uint8_t[width * height * 4]);
// _pixelBuffer = std::make_unique<FlutterDesktopPixelBuffer>();
// _pixelBuffer->buffer = _pixelData.get();
_pixelBuffer = std::make_unique<FlutterDesktopPixelBuffer>();
_pixelBuffer->buffer = _pixelData.get();
// _pixelBuffer->width = size_t(width);
// _pixelBuffer->height = size_t(height);
_pixelBuffer->width = size_t(width);
_pixelBuffer->height = size_t(height);
// _texture =
// std::make_unique<flutter::TextureVariant>(flutter::PixelBufferTexture(
// [=](size_t width,
// size_t height) -> const FlutterDesktopPixelBuffer * {
// if(!_context || !wglMakeCurrent(whdc, _context)) {
// std::cout << "Failed to switch OpenGL context." << std::endl;
// } else {
// uint8_t* data = new uint8_t[width*height*4];
// glBindTexture(GL_TEXTURE_2D, _glTextureId);
// 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;
// }
// }
// _pixelData.reset(data);
// wglMakeCurrent(NULL, NULL);
// }
// _pixelBuffer->buffer = _pixelData.get();
// return _pixelBuffer.get();
// }));
_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::PixelBufferTexture(
[=](size_t width,
size_t height) -> const FlutterDesktopPixelBuffer * {
if(!_context || !wglMakeCurrent(whdc, _context)) {
std::cout << "Failed to switch OpenGL context." << std::endl;
} else {
uint8_t* data = new uint8_t[width*height*4];
glBindTexture(GL_TEXTURE_2D, _glTextureId);
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;
}
}
_pixelData.reset(data);
wglMakeCurrent(NULL, NULL);
}
_pixelBuffer->buffer = _pixelData.get();
return _pixelBuffer.get();
}));
std::make_unique<flutter::TextureVariant>(flutter::GpuSurfaceTexture(
kFlutterDesktopGpuSurfaceTypeDxgiSharedHandle,
[&](auto, auto) { return _textureDescriptor.get(); }));
_flutterTextureId = _textureRegistrar->RegisterTexture(_texture.get());
std::cout << "Registered flutter texture " << _flutterTextureId << std::endl;
std::cout << "Registered Flutter texture ID " << _flutterTextureId << std::endl;
result->Success(flutter::EncodableValue(_flutterTextureId));
}

View File

@@ -7,14 +7,68 @@
#include <chrono>
#include <memory>
#include <Windows.h>
#include <wrl.h>
#include <d3d.h>
#include <d3d11.h>
#include "GL/GL.h"
#include "GL/GLu.h"
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <EGL/eglplatform.h>
#include "PolyvoxFilamentApi.h"
namespace polyvox_filament {
static constexpr EGLint kEGLConfigurationAttributes[] = {
EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 8, EGL_STENCIL_SIZE, 8,
EGL_NONE,
};
static constexpr EGLint kEGLContextAttributes[] = {
EGL_CONTEXT_CLIENT_VERSION,
2,
EGL_NONE,
};
static constexpr EGLint kD3D11DisplayAttributes[] = {
EGL_PLATFORM_ANGLE_TYPE_ANGLE,
EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
EGL_TRUE,
EGL_NONE,
};
static constexpr EGLint kD3D11_9_3DisplayAttributes[] = {
EGL_PLATFORM_ANGLE_TYPE_ANGLE,
EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE,
9,
EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE,
3,
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
EGL_TRUE,
EGL_NONE,
};
static constexpr EGLint kD3D9DisplayAttributes[] = {
EGL_PLATFORM_ANGLE_TYPE_ANGLE,
EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE,
EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE,
EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE,
EGL_NONE,
};
static constexpr EGLint kWrapDisplayAttributes[] = {
EGL_PLATFORM_ANGLE_TYPE_ANGLE,
EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
EGL_TRUE,
EGL_NONE,
};
class PolyvoxFilamentPlugin : public flutter::Plugin {
public:
static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar);
@@ -36,14 +90,32 @@ public:
flutter::TextureRegistrar *_textureRegistrar;
std::unique_ptr<flutter::TextureVariant> _texture = nullptr;
std::unique_ptr<FlutterDesktopPixelBuffer> _pixelBuffer = nullptr;
std::unique_ptr<uint8_t> _pixelData = nullptr;
std::chrono::milliseconds _frameInterval;
// std::unique_ptr<FlutterDesktopPixelBuffer> _pixelBuffer = nullptr;
// std::unique_ptr<uint8_t> _pixelData = nullptr;
std::unique_ptr<FlutterDesktopGpuSurfaceDescriptor> _textureDescriptor = nullptr;
int32_t _frameIntervalInMilliseconds = 1000 / 60;
bool _rendering = false;
int64_t _flutterTextureId;
// OpenGL
// Texture handle
GLuint _glTextureId = 0;
// Shared context
HGLRC _context = NULL;
// D3D
// 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;
void *_viewer = nullptr;
std::map<uint32_t, ResourceBuffer> _resources;