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