|
|
|
|
|
|
|
|
|
|
#include <flutter/fml/logging.h>
|
|
|
|
#include <EGL/egl.h>
|
|
|
|
#include <EGL/eglext.h>
|
|
|
|
#include <GLES2/gl2ext.h>
|
|
|
|
|
|
|
|
#include <vulkan/vulkan.h>
|
|
|
|
#include <vulkan/vulkan_core.h>
|
|
|
|
#include <android/hardware_buffer.h>
|
|
|
|
|
|
|
|
#define UNITY_USED_VULKAN_API_FUNCTIONS(apply) \
|
|
|
|
apply(vkGetDeviceProcAddr); \ |
|
|
|
apply(vkCreateInstance); \ |
|
|
|
apply(vkCmdBeginRenderPass); \ |
|
|
|
apply(vkCreateBuffer); \ |
|
|
|
apply(vkGetPhysicalDeviceMemoryProperties); \ |
|
|
|
apply(vkGetBufferMemoryRequirements); \ |
|
|
|
apply(vkMapMemory); \ |
|
|
|
apply(vkBindBufferMemory); \ |
|
|
|
apply(vkAllocateMemory); \ |
|
|
|
apply(vkDestroyBuffer); \ |
|
|
|
apply(vkFreeMemory); \ |
|
|
|
apply(vkUnmapMemory); \ |
|
|
|
apply(vkQueueWaitIdle); \ |
|
|
|
apply(vkDeviceWaitIdle); \ |
|
|
|
apply(vkCmdCopyBufferToImage); \ |
|
|
|
apply(vkFlushMappedMemoryRanges); \ |
|
|
|
apply(vkCreatePipelineLayout); \ |
|
|
|
apply(vkCreateShaderModule); \ |
|
|
|
apply(vkDestroyShaderModule); \ |
|
|
|
apply(vkCreateGraphicsPipelines); \ |
|
|
|
apply(vkCmdBindPipeline); \ |
|
|
|
apply(vkCmdDraw); \ |
|
|
|
apply(vkCmdPushConstants); \ |
|
|
|
apply(vkCmdBindVertexBuffers); \ |
|
|
|
apply(vkDestroyPipeline); \ |
|
|
|
apply(vkDestroyPipelineLayout); |
|
|
|
|
|
|
|
#define VULKAN_DEFINE_API_FUNCPTR(func) static PFN_##func my_##func
|
|
|
|
VULKAN_DEFINE_API_FUNCPTR(vkGetInstanceProcAddr); |
|
|
|
UNITY_USED_VULKAN_API_FUNCTIONS(VULKAN_DEFINE_API_FUNCPTR); |
|
|
|
#undef VULKAN_DEFINE_API_FUNCPTR
|
|
|
|
|
|
|
|
static void LoadVulkanAPI(PFN_vkGetInstanceProcAddr getInstanceProcAddr, |
|
|
|
VkInstance instance) |
|
|
|
{ |
|
|
|
if (!my_vkGetInstanceProcAddr && getInstanceProcAddr) |
|
|
|
my_vkGetInstanceProcAddr = getInstanceProcAddr; |
|
|
|
|
|
|
|
if (!my_vkCreateInstance) |
|
|
|
my_vkCreateInstance = (PFN_vkCreateInstance)my_vkGetInstanceProcAddr( |
|
|
|
VK_NULL_HANDLE, "vkCreateInstance"); |
|
|
|
|
|
|
|
#define LOAD_VULKAN_FUNC(fn) \
|
|
|
|
if (!my_##fn) \ |
|
|
|
my_##fn = (PFN_##fn)my_vkGetInstanceProcAddr(instance, #fn) |
|
|
|
UNITY_USED_VULKAN_API_FUNCTIONS(LOAD_VULKAN_FUNC); |
|
|
|
#undef LOAD_VULKAN_FUNC
|
|
|
|
} |
|
|
|
|
|
|
|
namespace uiwidgets |
|
|
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GLuint UnitySurfaceManager::CreateRenderSurface(void *native_texture_ptr) |
|
|
|
{ |
|
|
|
GLint old_framebuffer_binding; |
|
|
|
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_framebuffer_binding); |
|
|
|
if (m_UnityVulkan != nullptr) |
|
|
|
{ |
|
|
|
UnityVulkanImage image; |
|
|
|
m_UnityVulkan->AccessTexture( |
|
|
|
native_texture_ptr, UnityVulkanWholeImage, VkImageLayout::VK_IMAGE_LAYOUT_UNDEFINED, 0, |
|
|
|
0, UnityVulkanResourceAccessMode::kUnityVulkanResourceAccess_ObserveOnly, |
|
|
|
&image); |
|
|
|
|
|
|
|
GrVkImageInfo info( |
|
|
|
image.image, GrVkAlloc(image.memory.memory, image.memory.offset, image.memory.size, image.memory.flags), |
|
|
|
image.tiling, |
|
|
|
image.layout, |
|
|
|
image.format, |
|
|
|
image.mipCount); |
|
|
|
glGenFramebuffers(1, &fbo_); |
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo_); |
|
|
|
int width = 100; |
|
|
|
int height = 100; |
|
|
|
GrBackendTexture backendTex(width, height, info); |
|
|
|
GLuint gltex = (GLuint)(size_t)(native_texture_ptr); |
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gltex, 0); |
|
|
|
FML_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); |
|
|
|
m_SkSurface = SkSurface::MakeFromBackendTexture( |
|
|
|
gr_context_.get(), backendTex, kBottomLeft_GrSurfaceOrigin, 1, |
|
|
|
kRGBA_8888_SkColorType, nullptr, nullptr); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
GLint old_framebuffer_binding; |
|
|
|
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_framebuffer_binding); |
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, old_framebuffer_binding); |
|
|
|
glGenFramebuffers(1, &fbo_); |
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo_); |
|
|
|
return fbo_; |
|
|
|
GLuint gltex = (GLuint)(size_t)(native_texture_ptr); |
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gltex, 0); |
|
|
|
FML_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); |
|
|
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, old_framebuffer_binding); |
|
|
|
|
|
|
|
return fbo_; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void UnitySurfaceManager::DestroyRenderSurface() |
|
|
|
|
|
|
|
|
|
|
void UnitySurfaceManager::GetUnityContext() |
|
|
|
{ |
|
|
|
if(egl_unity_context_ != nullptr){ |
|
|
|
if (egl_unity_context_ != nullptr) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
egl_display_ = eglGetCurrentDisplay(); |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
static const int DEV_W = 16, DEV_H = 16; |
|
|
|
FML_CHECK(egl_display_ != EGL_NO_DISPLAY) |
|
|
|
<< "Renderer type is invalid"; |
|
|
|
auto *graphics = unity_interfaces->Get<IUnityGraphics>(); |
|
|
|
UnityGfxRenderer renderer = graphics->GetRenderer(); |
|
|
|
FML_DCHECK(renderer == kUnityGfxRendererOpenGLES30 || |
|
|
|
renderer == kUnityGfxRendererOpenGLES20 || |
|
|
|
renderer == kUnityGfxRendererVulkan); |
|
|
|
// Initialize the display connection.
|
|
|
|
FML_CHECK(eglInitialize(egl_display_, nullptr, nullptr) == EGL_TRUE) |
|
|
|
<< "Renderer type is invalid"; |
|
|
|
if (renderer == kUnityGfxRendererVulkan) |
|
|
|
{ |
|
|
|
auto valid_ = true; |
|
|
|
m_UnityVulkan = unity_interfaces->Get<IUnityGraphicsVulkan>(); |
|
|
|
m_Instance = m_UnityVulkan->Instance(); |
|
|
|
LoadVulkanAPI(m_Instance.getInstanceProcAddr, m_Instance.instance); |
|
|
|
bool success = false; |
|
|
|
// // AHarewareBuffer android api >= 26
|
|
|
|
// AHardwareBuffer* buffer = nullptr;
|
|
|
|
std::tie(success, egl_config_) = ChooseEGLConfiguration(egl_display_); |
|
|
|
FML_CHECK(success) << "Could not choose an EGL configuration."; |
|
|
|
// AHardwareBuffer_Desc hwbDesc;
|
|
|
|
// hwbDesc.width = DEV_W;
|
|
|
|
// hwbDesc.height = DEV_H;
|
|
|
|
// hwbDesc.layers = 1;
|
|
|
|
std::tie(success, egl_context_) = CreateContext(egl_display_, egl_config_, egl_unity_context_); |
|
|
|
// hwbDesc.usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER |
|
|
|
|
// AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
|
|
|
|
// AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
|
|
|
|
// AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT;
|
|
|
|
// hwbDesc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
|
|
|
|
// // The following three are not used in the allocate
|
|
|
|
// hwbDesc.stride = 0;
|
|
|
|
// hwbDesc.rfu0= 0;
|
|
|
|
// hwbDesc.rfu1= 0;
|
|
|
|
|
|
|
|
// if (int error = AHardwareBuffer_allocate(&hwbDesc, &buffer)) {
|
|
|
|
// ERRORF(reporter, "Failed to allocated hardware buffer, error: %d", error);
|
|
|
|
// AHardwareBuffer_release(buffer);
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
|
|
|
|
auto device = m_Instance.device; |
|
|
|
auto physicalDevice = m_Instance.physicalDevice; |
|
|
|
VkImage image = 0; |
|
|
|
// ... // create the image as normal
|
|
|
|
VkMemoryRequirements memReqs; // = device->getImageMemoryRequirements(image);
|
|
|
|
vkGetImageMemoryRequirements(device, image, &memReqs); |
|
|
|
VkMemoryAllocateInfo memAllocInfo; |
|
|
|
const auto handle_type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; |
|
|
|
VkExportMemoryAllocateInfoKHR exportAllocInfo{ |
|
|
|
VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR, nullptr, handle_type}; |
|
|
|
memAllocInfo.pNext = &exportAllocInfo; |
|
|
|
memAllocInfo.allocationSize = memReqs.size; |
|
|
|
|
|
|
|
uint32_t memoryTypeIndex = 0; |
|
|
|
bool foundHeap = false; |
|
|
|
VkPhysicalDeviceMemoryProperties phyDevMemProps; |
|
|
|
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &phyDevMemProps); |
|
|
|
for (uint32_t i = 0; i < phyDevMemProps.memoryTypeCount && !foundHeap; ++i) |
|
|
|
{ |
|
|
|
if (VkMemoryPropertyFlagBits::VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT & (1 << i)) |
|
|
|
{ |
|
|
|
// Map host-visible memory.
|
|
|
|
if (phyDevMemProps.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) |
|
|
|
{ |
|
|
|
memoryTypeIndex = i; |
|
|
|
foundHeap = true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
memAllocInfo.memoryTypeIndex = memoryTypeIndex; |
|
|
|
// physicalDevice->set_memory_type(
|
|
|
|
// memReqs.memoryTypeBits, &memAllocInfo, VkMemoryPropertyFlagBits::VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
|
|
VkDeviceMemory memory; |
|
|
|
vkAllocateMemory(device, &memAllocInfo, NULL, &memory); |
|
|
|
// memory = device->allocateMemory(memAllocInfo);
|
|
|
|
vkBindImageMemory(device, image, memory, 0); |
|
|
|
|
|
|
|
AHardwareBuffer *buffer = nullptr; |
|
|
|
|
|
|
|
VkMemoryGetAndroidHardwareBufferInfoANDROID meminfo; |
|
|
|
meminfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID; |
|
|
|
meminfo.pNext = nullptr; |
|
|
|
meminfo.memory = memory; |
|
|
|
vkGetMemoryAndroidHardwareBufferANDROID(device, &meminfo, &buffer); // android api level 28
|
|
|
|
// HANDLE sharedMemoryHandle = device->getMemoryWin32HandleKHR({
|
|
|
|
// texture.memory, VkExternalMemoryHandleTypeFlags::VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID
|
|
|
|
// });
|
|
|
|
EGLDisplay display = eglGetCurrentDisplay(); |
|
|
|
EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(buffer); |
|
|
|
bool isProtectedContent = true; |
|
|
|
EGLint attribs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, |
|
|
|
isProtectedContent ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE, |
|
|
|
isProtectedContent ? EGL_TRUE : EGL_NONE, |
|
|
|
EGL_NONE}; |
|
|
|
|
|
|
|
EGLImageKHR imagekhr = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attribs); |
|
|
|
|
|
|
|
GLint old_framebuffer_binding; |
|
|
|
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_framebuffer_binding); |
|
|
|
std::tie(success, egl_resource_context_) = CreateContext(egl_display_, egl_config_, egl_context_); |
|
|
|
glGenFramebuffers(1, &fbo_); |
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo_); |
|
|
|
|
|
|
|
GLuint mTexture = 0; |
|
|
|
glGenTextures(1, &mTexture); |
|
|
|
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, imagekhr); |
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0); |
|
|
|
FML_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); |
|
|
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, old_framebuffer_binding); |
|
|
|
|
|
|
|
|
|
|
|
//-------------------
|
|
|
|
|
|
|
|
UnityVulkanPluginEventConfig config_1; |
|
|
|
config_1.graphicsQueueAccess = kUnityVulkanGraphicsQueueAccess_DontCare; |
|
|
|
config_1.renderPassPrecondition = kUnityVulkanRenderPass_EnsureInside; |
|
|
|
config_1.flags = |
|
|
|
kUnityVulkanEventConfigFlag_EnsurePreviousFrameSubmission | |
|
|
|
kUnityVulkanEventConfigFlag_ModifiesCommandBuffersState; |
|
|
|
m_UnityVulkan->ConfigureEvent(1, &config_1); |
|
|
|
|
|
|
|
GrVkBackendContext vk_backend_context; |
|
|
|
vk_backend_context.fInstance = m_Instance.instance; |
|
|
|
vk_backend_context.fPhysicalDevice = m_Instance.physicalDevice; |
|
|
|
vk_backend_context.fDevice = m_Instance.device; |
|
|
|
vk_backend_context.fQueue = m_Instance.graphicsQueue; |
|
|
|
vk_backend_context.fGraphicsQueueIndex = m_Instance.queueFamilyIndex; |
|
|
|
vk_backend_context.fGetProc = |
|
|
|
[getInstanceProc = m_Instance.getInstanceProcAddr, |
|
|
|
getDeviceProc = my_vkGetDeviceProcAddr]( |
|
|
|
const char *proc_name, VkInstance instance, VkDevice device) { |
|
|
|
if (device != VK_NULL_HANDLE) |
|
|
|
{ |
|
|
|
return getDeviceProc(device, proc_name); |
|
|
|
} |
|
|
|
return getInstanceProc(instance, proc_name); |
|
|
|
}; |
|
|
|
gr_context_ = GrContext::MakeVulkan(vk_backend_context); |
|
|
|
|
|
|
|
auto valid_ = true; |
|
|
|
|
|
|
|
bool success = false; |
|
|
|
return success; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// Make sure Vulkan API functions are loaded
|
|
|
|
return success; |
|
|
|
FML_CHECK(egl_display_ != EGL_NO_DISPLAY) |
|
|
|
<< "Renderer type is invalid"; |
|
|
|
|
|
|
|
// Initialize the display connection.
|
|
|
|
FML_CHECK(eglInitialize(egl_display_, nullptr, nullptr) == EGL_TRUE) |
|
|
|
<< "Renderer type is invalid"; |
|
|
|
|
|
|
|
auto valid_ = true; |
|
|
|
|
|
|
|
bool success = false; |
|
|
|
|
|
|
|
std::tie(success, egl_config_) = ChooseEGLConfiguration(egl_display_); |
|
|
|
FML_CHECK(success) << "Could not choose an EGL configuration."; |
|
|
|
|
|
|
|
std::tie(success, egl_context_) = CreateContext(egl_display_, egl_config_, egl_unity_context_); |
|
|
|
|
|
|
|
std::tie(success, egl_resource_context_) = CreateContext(egl_display_, egl_config_, egl_context_); |
|
|
|
return success; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void UnitySurfaceManager::CleanUp() |
|
|
|