add first pass vulkan implementation

This commit is contained in:
Nick Fisher
2024-11-04 23:50:52 +08:00
parent bdcbd90ec6
commit b59cadc061
6 changed files with 1025 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
cmake_minimum_required(VERSION 3.14)
set(PROJECT_NAME "thermion_egl")
project(${PROJECT_NAME} LANGUAGES C CXX)
cmake_policy(VERSION 3.14...3.25)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
set(BUILD_SHARED_LIBS TRUE)
set(CMAKE_ENABLE_EXPORTS TRUE)
add_definitions(-DVK_STATIC_DISPATCH)
add_library(${PROJECT_NAME} SHARED
"d3d_texture.cpp"
)
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_20)
include_directories(${PROJECT_NAME} INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/../../include"
)
target_link_libraries(${PROJECT_NAME} PRIVATE
Shlwapi
dxgi
d3d11
)
# Test executable
add_executable(${PROJECT_NAME}_test
"main.cpp"
)
target_include_directories(${PROJECT_NAME}_test PRIVATE
E:\\VulkanSDK\\1.3.296.0\\Include
)
target_link_directories(${PROJECT_NAME}_test PRIVATE
E:\\VulkanSDK\\1.3.296.0\\Lib
)
target_link_libraries(${PROJECT_NAME}_test PRIVATE
${PROJECT_NAME}
vulkan-1
)
# Make sure the test depends on the library
add_dependencies(${PROJECT_NAME}_test ${PROJECT_NAME})

View File

@@ -0,0 +1,272 @@
#include "d3d_texture.h"
#include <functional>
#include <iostream>
#include <memory>
#include <thread>
namespace thermion::windows::d3d {
void D3DTexture::Flush() {
// glFlush(); // Ensure GL commands are completed
_D3D11DeviceContext->Flush();
}
HANDLE D3DTexture::GetTextureHandle() {
return _d3dTexture2DHandle;
}
D3DTexture::~D3DTexture() {
_d3dTexture2D->Release();
}
bool IsNTHandleSupported(ID3D11Device* device) {
Microsoft::WRL::ComPtr<ID3D11Device5> device5;
return SUCCEEDED(device->QueryInterface(IID_PPV_ARGS(&device5)));
}
D3DTexture::D3DTexture(
uint32_t width, uint32_t height,
std::function<void(size_t, size_t)> onResizeRequested
)
: _width(width), _height(height), _onResizeRequested(onResizeRequested) {
IDXGIAdapter *adapter_ = nullptr;
auto feature_levels = {
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,
};
IDXGIFactory1 *dxgi = nullptr;
HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void **)&dxgi);
if (FAILED(hr)) {
std::cout << "Failed to create DXGI 1.1 factory" << std::endl;
return;
}
dxgi->EnumAdapters(0, &adapter_);
dxgi->Release();
if (!adapter_) {
std::cout << "Failed to locate default D3D adapter" << std::endl;
return;
}
Microsoft::WRL::ComPtr<IDXGIFactory2> factory2;
if (SUCCEEDED(dxgi->QueryInterface(IID_PPV_ARGS(&factory2)))) {
std::cout << "DXGI 1.2 or higher supported" << std::endl;
}
DXGI_ADAPTER_DESC adapter_desc_;
adapter_->GetDesc(&adapter_desc_);
std::wcout << L"D3D adapter description: " << adapter_desc_.Description
<< std::endl;
hr = ::D3D11CreateDevice(
adapter_, D3D_DRIVER_TYPE_UNKNOWN, 0, D3D11_CREATE_DEVICE_BGRA_SUPPORT, feature_levels.begin(),
static_cast<UINT>(feature_levels.size()), D3D11_SDK_VERSION,
&_D3D11Device, 0, &_D3D11DeviceContext);
if (FAILED(hr)) {
std::cout << "Failed to create D3D device" << std::endl;
return;
}
Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device = nullptr;
auto dxgi_device_success = _D3D11Device->QueryInterface(
__uuidof(IDXGIDevice), (void **)&dxgi_device);
if (SUCCEEDED(dxgi_device_success) && dxgi_device != nullptr) {
dxgi_device->SetGPUThreadPriority(5); // Must be in interval [-7, 7].
}
if(IsNTHandleSupported(_D3D11Device)) {
std::cout << "NT HANDLE SUPPORT" << std::endl;
} else {
std::cout << "NT HANDLE NOT SUPPORT" << std::endl;
}
auto level = _D3D11Device->GetFeatureLevel();
std::cout << "Direct3D Feature Level: "
<< (((unsigned)level) >> 12) << "_"
<< ((((unsigned)level) >> 8) & 0xf) << std::endl;
// Create texture
auto d3d11_texture2D_desc = D3D11_TEXTURE2D_DESC{0};
d3d11_texture2D_desc.Width = width;
d3d11_texture2D_desc.Height = height;
d3d11_texture2D_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
d3d11_texture2D_desc.MipLevels = 1;
d3d11_texture2D_desc.ArraySize = 1;
d3d11_texture2D_desc.SampleDesc.Count = 1;
d3d11_texture2D_desc.SampleDesc.Quality = 0;
d3d11_texture2D_desc.Usage = D3D11_USAGE_DEFAULT;
d3d11_texture2D_desc.BindFlags =
D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
d3d11_texture2D_desc.CPUAccessFlags = 0;
d3d11_texture2D_desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
hr = _D3D11Device->CreateTexture2D(&d3d11_texture2D_desc, nullptr, &_d3dTexture2D);
if FAILED (hr) {
std::cout << "Failed to create D3D texture (" << hr << ")" << std::endl;
return;
}
auto resource = Microsoft::WRL::ComPtr<IDXGIResource1>{};
hr = _d3dTexture2D.As(&resource);
if FAILED (hr) {
std::cout << "Failed to create D3D texture" << std::endl;
return;
;
}
hr = resource->GetSharedHandle(&_d3dTexture2DHandle);
if FAILED (hr) {
std::cout << "Failed to get shared handle to external D3D texture" << std::endl;
return;
;
}
_d3dTexture2D->AddRef();
std::cout << "Created external D3D texture " << width << "x" << height << std::endl;
// Create render target view of the texture
ID3D11RenderTargetView* rtv = nullptr;
D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
rtvDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
rtvDesc.Texture2D.MipSlice = 0;
hr = _D3D11Device->CreateRenderTargetView(_d3dTexture2D.Get(), &rtvDesc, &rtv);
if (FAILED(hr)) {
std::cout << "Failed to create render target view" << std::endl;
return;
}
// Clear the texture to blue
float blueColor[4] = { 0.0f, 0.0f, 1.0f, 1.0f }; // RGBA
_D3D11DeviceContext->ClearRenderTargetView(rtv, blueColor);
_D3D11DeviceContext->Flush();
}
void D3DTexture::FillBlueAndSaveToBMP(const char* filename) {
// Create render target view of the texture
ID3D11RenderTargetView* rtv = nullptr;
D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
rtvDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
rtvDesc.Texture2D.MipSlice = 0;
HRESULT hr = _D3D11Device->CreateRenderTargetView(_d3dTexture2D.Get(), &rtvDesc, &rtv);
if (FAILED(hr)) {
std::cout << "Failed to create render target view" << std::endl;
return;
}
// Clear the texture to blue
float blueColor[4] = { 0.0f, 0.0f, 1.0f, 1.0f }; // RGBA
_D3D11DeviceContext->ClearRenderTargetView(rtv, blueColor);
// Create staging texture for CPU read access
D3D11_TEXTURE2D_DESC stagingDesc = {};
_d3dTexture2D->GetDesc(&stagingDesc);
stagingDesc.Usage = D3D11_USAGE_STAGING;
stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
stagingDesc.BindFlags = 0;
stagingDesc.MiscFlags = 0;
ID3D11Texture2D* stagingTexture = nullptr;
hr = _D3D11Device->CreateTexture2D(&stagingDesc, nullptr, &stagingTexture);
if (FAILED(hr)) {
rtv->Release();
std::cout << "Failed to create staging texture" << std::endl;
return;
}
// Copy to staging texture
_D3D11DeviceContext->CopyResource(stagingTexture, _d3dTexture2D.Get());
// Save to BMP
bool success = SaveTextureAsBMP(stagingTexture, filename);
// Cleanup
stagingTexture->Release();
rtv->Release();
if (success) {
std::cout << "Successfully saved texture to " << filename << std::endl;
}
}
bool D3DTexture::SaveTextureAsBMP(ID3D11Texture2D* texture, const char* filename) {
D3D11_TEXTURE2D_DESC desc;
texture->GetDesc(&desc);
// Map texture to get pixel data
D3D11_MAPPED_SUBRESOURCE mappedResource;
HRESULT hr = _D3D11DeviceContext->Map(texture, 0, D3D11_MAP_READ, 0, &mappedResource);
if (FAILED(hr)) {
std::cout << "Failed to map texture" << std::endl;
return false;
}
// BMP file header
#pragma pack(push, 1)
struct BMPHeader {
uint16_t signature;
uint32_t fileSize;
uint32_t reserved;
uint32_t dataOffset;
uint32_t headerSize;
int32_t width;
int32_t height;
uint16_t planes;
uint16_t bitsPerPixel;
uint32_t compression;
uint32_t imageSize;
int32_t xPixelsPerMeter;
int32_t yPixelsPerMeter;
uint32_t totalColors;
uint32_t importantColors;
};
#pragma pack(pop)
// Create and fill header
BMPHeader header = {};
header.signature = 0x4D42; // 'BM'
header.fileSize = sizeof(BMPHeader) + desc.Width * desc.Height * 4;
header.dataOffset = sizeof(BMPHeader);
header.headerSize = 40;
header.width = desc.Width;
header.height = desc.Height;
header.planes = 1;
header.bitsPerPixel = 32;
header.compression = 0;
header.imageSize = desc.Width * desc.Height * 4;
header.xPixelsPerMeter = 2835; // 72 DPI
header.yPixelsPerMeter = 2835; // 72 DPI
// Write to file
FILE* file = nullptr;
fopen_s(&file, filename, "wb");
if (!file) {
_D3D11DeviceContext->Unmap(texture, 0);
return false;
}
fwrite(&header, sizeof(header), 1, file);
// Write pixel data (need to flip rows as BMP is bottom-up)
uint8_t* srcData = reinterpret_cast<uint8_t*>(mappedResource.pData);
for (int y = desc.Height - 1; y >= 0; y--) {
uint8_t* rowData = srcData + y * mappedResource.RowPitch;
fwrite(rowData, desc.Width * 4, 1, file);
}
fclose(file);
_D3D11DeviceContext->Unmap(texture, 0);
return true;
}
} // namespace thermion_flutter

View File

@@ -0,0 +1,51 @@
#pragma once
#include <functional>
#include <mutex>
#include <d3d.h>
#include <d3d11.h>
#include <dxgi1_2.h> // Add this line
#include <d3d11_4.h>
#include <Windows.h>
#include <wrl.h>
typedef uint32_t GLuint;
namespace thermion::windows::d3d {
class D3DTexture {
public:
D3DTexture(
uint32_t width,
uint32_t height,
std::function<void(size_t, size_t)> onResizeRequested
);
~D3DTexture();
void Flush();
HANDLE GetTextureHandle();
GLuint glTextureId = 0;
void FillBlueAndSaveToBMP(const char* filename);
bool SaveTextureAsBMP(ID3D11Texture2D* texture, const char* filename);
// Device
ID3D11Device* _D3D11Device = nullptr;
private:
bool _error = false;
uint32_t _width = 0;
uint32_t _height = 0;
bool logged = false;
std::function<void(size_t, size_t)> _onResizeRequested;
ID3D11DeviceContext* _D3D11DeviceContext = nullptr;
// Texture objects/shared handles
Microsoft::WRL::ComPtr<ID3D11Texture2D> _d3dTexture2D;
HANDLE _d3dTexture2DHandle = nullptr;
};
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include <memory>
#include <Windows.h>
#include "egl_texture.h"
namespace thermion::windows::egl {
class ThermionEGLContext {
public:
ThermionEGLContext();
void* GetSharedContext();
EGLTexture * CreateRenderingSurface(uint32_t width, uint32_t height, uint32_t left, uint32_t top);
void DestroyRenderingSurface();
void ResizeRenderingSurface(uint32_t width, uint32_t height, uint32_t left, uint32_t top);
EGLTexture * GetActiveTexture();
private:
void* _context = nullptr;
EGLConfig _eglConfig = NULL;
EGLDisplay _eglDisplay = NULL;
ID3D11Device* _D3D11Device = nullptr;
ID3D11DeviceContext* _D3D11DeviceContext = nullptr;
std::unique_ptr<EGLTexture> _active = nullptr;
};
}

View File

@@ -0,0 +1,484 @@
#include "d3d_texture.h"
#include <iostream>
#include <thread>
#include <chrono>
#include <vulkan/vulkan.h>
#include <vulkan/vulkan_win32.h>
#include <vector>
#include <string>
#include "d3d_texture.h"
#include <functional>
#include <iostream>
#include <memory>
#include <thread>
// Helper function to convert VkResult to string for error reporting
const char *VkResultToString(VkResult result)
{
switch (result)
{
case VK_SUCCESS:
return "VK_SUCCESS";
case VK_ERROR_OUT_OF_HOST_MEMORY:
return "VK_ERROR_OUT_OF_HOST_MEMORY";
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
return "VK_ERROR_OUT_OF_DEVICE_MEMORY";
case VK_ERROR_INITIALIZATION_FAILED:
return "VK_ERROR_INITIALIZATION_FAILED";
case VK_ERROR_LAYER_NOT_PRESENT:
return "VK_ERROR_LAYER_NOT_PRESENT";
case VK_ERROR_EXTENSION_NOT_PRESENT:
return "VK_ERROR_EXTENSION_NOT_PRESENT";
default:
return "UNKNOWN_ERROR";
}
}
// Modified memory type selection function with more detailed requirements checking
uint32_t findOptimalMemoryType(VkPhysicalDevice physicalDevice,
uint32_t typeFilter,
VkMemoryPropertyFlags requiredProperties,
VkMemoryPropertyFlags preferredProperties = 0) {
VkPhysicalDeviceMemoryProperties memProperties;
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
// First try to find memory type with all preferred properties
if (preferredProperties != 0) {
for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
if ((typeFilter & (1 << i)) &&
(memProperties.memoryTypes[i].propertyFlags & (requiredProperties | preferredProperties)) ==
(requiredProperties | preferredProperties)) {
return i;
}
}
}
// Fall back to just required properties
for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
if ((typeFilter & (1 << i)) &&
(memProperties.memoryTypes[i].propertyFlags & requiredProperties) == requiredProperties) {
return i;
}
}
return UINT32_MAX;
}
// Consolidated function for creating Vulkan instance
VkResult createVulkanInstance(VkInstance *instance)
{
std::vector<const char *> instanceExtensions = {
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME};
VkApplicationInfo appInfo = {};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "Vulkan-D3D11 Interop";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "No Engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_1;
VkInstanceCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo;
createInfo.enabledExtensionCount = static_cast<uint32_t>(instanceExtensions.size());
createInfo.ppEnabledExtensionNames = instanceExtensions.data();
return vkCreateInstance(&createInfo, nullptr, instance);
}
// Consolidated function for creating logical device
VkResult createLogicalDevice(VkInstance instance, VkPhysicalDevice *physicalDevice, VkDevice *device)
{
uint32_t deviceCount = 0;
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
std::vector<VkPhysicalDevice> physicalDevices(deviceCount);
vkEnumeratePhysicalDevices(instance, &deviceCount, physicalDevices.data());
if (deviceCount == 0)
{
return VK_ERROR_INITIALIZATION_FAILED;
}
*physicalDevice = physicalDevices[0];
std::vector<const char *> deviceExtensions = {
VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME};
float queuePriority = 1.0f;
VkDeviceQueueCreateInfo queueCreateInfo = {};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = 0;
queueCreateInfo.queueCount = 1;
queueCreateInfo.pQueuePriorities = &queuePriority;
VkDeviceCreateInfo deviceCreateInfo = {};
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
deviceCreateInfo.queueCreateInfoCount = 1;
deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo;
deviceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.data();
return vkCreateDevice(*physicalDevice, &deviceCreateInfo, nullptr, device);
}
bool checkD3D11VulkanInterop(VkPhysicalDevice physicalDevice, ID3D11Device *d3dDevice)
{
std::cout << "\n=== Checking D3D11-Vulkan Interop Support in QEMU ===" << std::endl;
// Check Vulkan external memory capabilities
VkPhysicalDeviceExternalImageFormatInfo externFormatInfo = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT};
VkPhysicalDeviceImageFormatInfo2 formatInfo = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
.pNext = &externFormatInfo,
.format = VK_FORMAT_R8G8B8A8_UNORM,
.type = VK_IMAGE_TYPE_2D,
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
.flags = 0};
VkExternalImageFormatProperties externFormatProps = {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES};
VkImageFormatProperties2 formatProps = {
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
.pNext = &externFormatProps};
// Check device properties
VkPhysicalDeviceProperties deviceProps;
vkGetPhysicalDeviceProperties(physicalDevice, &deviceProps);
std::cout << "Vulkan Device: " << deviceProps.deviceName << std::endl;
std::cout << "Driver Version: " << deviceProps.driverVersion << std::endl;
std::cout << "API Version: " << VK_VERSION_MAJOR(deviceProps.apiVersion) << "." << VK_VERSION_MINOR(deviceProps.apiVersion) << "." << VK_VERSION_PATCH(deviceProps.apiVersion) << std::endl;
// Check D3D11 device capabilities
D3D11_FEATURE_DATA_D3D11_OPTIONS3 featureData = {};
HRESULT hr = d3dDevice->CheckFeatureSupport(
D3D11_FEATURE_D3D11_OPTIONS3,
&featureData,
sizeof(featureData));
std::cout << "\nChecking D3D11 Device:" << std::endl;
// Get D3D11 device information
IDXGIDevice *dxgiDevice = nullptr;
hr = d3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void **)&dxgiDevice);
if (SUCCEEDED(hr))
{
IDXGIAdapter *adapter = nullptr;
hr = dxgiDevice->GetAdapter(&adapter);
if (SUCCEEDED(hr))
{
DXGI_ADAPTER_DESC desc;
adapter->GetDesc(&desc);
std::wcout << L"D3D11 Adapter: " << desc.Description << std::endl;
adapter->Release();
}
dxgiDevice->Release();
}
// Check for external memory support
VkResult result = vkGetPhysicalDeviceImageFormatProperties2(
physicalDevice,
&formatInfo,
&formatProps);
std::cout << "\nInterop Support Details:" << std::endl;
// Check external memory extension
uint32_t extensionCount = 0;
vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> extensions(extensionCount);
vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, extensions.data());
bool hasExternalMemoryExt = false;
bool hasWin32Ext = false;
for (const auto &ext : extensions)
{
if (strcmp(ext.extensionName, VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME) == 0)
{
hasExternalMemoryExt = true;
}
if (strcmp(ext.extensionName, VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME) == 0)
{
hasWin32Ext = true;
}
}
std::cout << "External Memory Extension: " << (hasExternalMemoryExt ? "Yes" : "No") << std::endl;
std::cout << "Win32 External Memory Extension: " << (hasWin32Ext ? "Yes" : "No") << std::endl;
std::cout << "Format Properties Check: " << (result == VK_SUCCESS ? "Passed" : "Failed") << std::endl;
// Check memory properties
VkPhysicalDeviceMemoryProperties memProps;
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProps);
std::cout << "\nMemory Types Available:" << std::endl;
for (uint32_t i = 0; i < memProps.memoryTypeCount; i++)
{
VkMemoryPropertyFlags flags = memProps.memoryTypes[i].propertyFlags;
std::cout << "Type " << i << ": ";
if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
std::cout << "Device Local ";
if (flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
std::cout << "Host Visible ";
if (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
std::cout << "Host Coherent ";
if (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT)
std::cout << "Host Cached ";
std::cout << std::endl;
}
// Check if all required features are available
bool supportsInterop =
hasExternalMemoryExt &&
hasWin32Ext &&
result == VK_SUCCESS;
std::cout << "\nFinal Result: " << (supportsInterop ? "Interop Supported" : "Interop Not Supported") << std::endl;
std::cout << "================================================" << std::endl;
return supportsInterop;
}
int main()
{
VkInstance instance = VK_NULL_HANDLE;
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
VkDevice device = VK_NULL_HANDLE;
VkImage image = VK_NULL_HANDLE;
HANDLE sharedHandle = nullptr;
uint32_t height = 100;
uint32_t width = 100;
std::cout << "[Step 1] Initializing D3D texture..." << std::endl;
thermion::windows::d3d::D3DTexture texture(width, height, [=](size_t width, size_t height) {});
sharedHandle = texture.GetTextureHandle();
if (!sharedHandle)
{
std::cout << "[ERROR] Failed to get shared texture handle!" << std::endl;
return 1;
}
texture.FillBlueAndSaveToBMP("output.bmp");
std::cout << "[Info] Filled texture with blue and saved to output.bmp" << std::endl;
// Create Vulkan instance
VkResult result = createVulkanInstance(&instance);
if (result != VK_SUCCESS)
{
std::cout << "[ERROR] Failed to create Vulkan instance! Error: " << VkResultToString(result) << std::endl;
return 1;
}
// Create logical device
result = createLogicalDevice(instance, &physicalDevice, &device);
if (result != VK_SUCCESS)
{
std::cout << "[ERROR] Failed to create logical device! Error: " << VkResultToString(result) << std::endl;
vkDestroyInstance(instance, nullptr);
return 1;
}
// In main(), after creating both D3D11 and Vulkan devices:
texture.FillBlueAndSaveToBMP("output.bmp");
if (!checkD3D11VulkanInterop(physicalDevice, texture._D3D11Device))
{
std::cout << "D3D11-Vulkan interop is not supported in this QEMU environment" << std::endl;
// Consider falling back to a different approach
return 1;
}
VkPhysicalDeviceExternalImageFormatInfo externFormatInfo = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
.pNext = nullptr,
.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT};
VkPhysicalDeviceImageFormatInfo2 formatInfo = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
.pNext = &externFormatInfo,
.format = VK_FORMAT_R8G8B8A8_UNORM,
.type = VK_IMAGE_TYPE_2D,
.tiling = VK_IMAGE_TILING_OPTIMAL, // Changed to LINEAR for VM compatibility
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, // Simplified usage flags
.flags = 0};
VkExternalImageFormatProperties externFormatProps = {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES};
VkImageFormatProperties2 formatProps = {
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
.pNext = &externFormatProps};
// Query supported features
result = vkGetPhysicalDeviceImageFormatProperties2(
physicalDevice,
&formatInfo,
&formatProps);
if (result != VK_SUCCESS)
{
std::cout << "VM environment may not support required external memory features" << std::endl;
return 1;
}
std::cout << "VM environment supports required external memory features" << std::endl;
// Create image with external memory support
VkExternalMemoryImageCreateInfo extImageInfo = {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT};
VkImageCreateInfo imageInfo = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = &extImageInfo,
.flags = 0,
.imageType = VK_IMAGE_TYPE_2D,
.format = VK_FORMAT_R8G8B8A8_UNORM,
.extent = {width, height, 1},
.mipLevels = 1,
.arrayLayers = 1,
.samples = VK_SAMPLE_COUNT_1_BIT,
.tiling = VK_IMAGE_TILING_OPTIMAL, // Changed to LINEAR for VM
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, // Simplified usage
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED};
result = vkCreateImage(device, &imageInfo, nullptr, &image);
if (result != VK_SUCCESS)
{
std::cout << "Failed to create iamge " << std::endl;
}
else
{
std::cout << "Successfully created image " << std::endl;
}
VkMemoryDedicatedRequirements MemoryDedicatedRequirements{
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
.pNext = nullptr};
VkMemoryRequirements2 MemoryRequirements2{
.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
.pNext = &MemoryDedicatedRequirements};
const VkImageMemoryRequirementsInfo2 ImageMemoryRequirementsInfo2{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
.pNext = nullptr,
.image = image};
// WARN: Memory access violation unless validation instance layer is enabled, otherwise success but...
vkGetImageMemoryRequirements2(device, &ImageMemoryRequirementsInfo2, &MemoryRequirements2);
// ... if we happen to be here, MemoryRequirements2 is empty
VkMemoryRequirements &MemoryRequirements = MemoryRequirements2.memoryRequirements;
const VkMemoryDedicatedAllocateInfo MemoryDedicatedAllocateInfo{
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
.pNext = nullptr,
.image = image,
.buffer = VK_NULL_HANDLE};
const VkImportMemoryWin32HandleInfoKHR ImportMemoryWin32HandleInfo{
.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR,
.pNext = &MemoryDedicatedAllocateInfo,
.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT,
.handle = sharedHandle,
.name = nullptr};
VkDeviceMemory ImageMemory = VK_NULL_HANDLE;
// Find suitable memory type
uint32_t memoryTypeIndex = findOptimalMemoryType(
physicalDevice,
MemoryRequirements.memoryTypeBits,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT // You might need to adjust these flags
);
VkMemoryAllocateInfo allocInfo{
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.pNext = &ImportMemoryWin32HandleInfo,
.allocationSize = MemoryRequirements.size,
.memoryTypeIndex = memoryTypeIndex // Assuming 'properties' is your memory type index
};
VkResult allocResult = vkAllocateMemory(device, &allocInfo, nullptr, &ImageMemory);
if (allocResult != VK_SUCCESS || ImageMemory == VK_NULL_HANDLE)
{
std::cout << "IMAGE MEMORY ALLOCATION FAILED:" << std::endl;
std::cout << " Allocation size: " << MemoryRequirements.size << " bytes" << std::endl;
std::cout << " Memory type index: " << allocInfo.memoryTypeIndex << std::endl;
std::cout << " Error code: " << allocResult << std::endl;
// Get more detailed error message based on VkResult
const char *errorMsg;
switch (allocResult)
{
case VK_ERROR_OUT_OF_HOST_MEMORY:
errorMsg = "VK_ERROR_OUT_OF_HOST_MEMORY: Out of host memory";
break;
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
errorMsg = "VK_ERROR_OUT_OF_DEVICE_MEMORY: Out of device memory";
break;
case VK_ERROR_INVALID_EXTERNAL_HANDLE:
errorMsg = "VK_ERROR_INVALID_EXTERNAL_HANDLE: The external handle is invalid";
break;
case VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS:
errorMsg = "VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS: The requested address is not available";
break;
default:
errorMsg = "Unknown error";
}
std::cout << " Error message: " << errorMsg << std::endl;
// Print shared handle info
std::cout << " Shared handle value: " << sharedHandle << std::endl;
// Print memory requirements
std::cout << " Memory requirements:" << std::endl;
std::cout << " Size: " << MemoryRequirements.size << std::endl;
std::cout << " Alignment: " << MemoryRequirements.alignment << std::endl;
std::cout << " Memory type bits: 0x" << std::hex << MemoryRequirements.memoryTypeBits << std::dec << std::endl;
return 1;
}
// memAllocator->Allocate(MemoryRequirements, &ImageMemory, properties, &ImportMemoryWin32HandleInfo);
// if(ImageMemory == VK_NULL_HANDLE) {
// std::cout << "IMAGE MEMORY ALLOCATION FAILED" << std::endl;
// return;
// }
const VkBindImageMemoryInfo bindImageMemoryInfo{
.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
.pNext = nullptr,
.image = image,
.memory = ImageMemory,
.memoryOffset = 0};
result = vkBindImageMemory2(device, 1, &bindImageMemoryInfo);
if (result != VK_SUCCESS)
{
std::cout << "bindimagememory2 failed" << std::endl;
}
std::cout << "FIISHED" << std::endl;
// Cleanup
std::cout << "\n[Step 6] Cleaning up resources..." << std::endl;
vkDestroyImage(device, image, nullptr);
// vkFreeMemory(device, memory, nullptr);
vkDestroyDevice(device, nullptr);
vkDestroyInstance(instance, nullptr);
std::cout << "[Complete] All resources cleaned up successfully" << std::endl;
return 0;
}

View File

@@ -0,0 +1,144 @@
#include <functional>
#include <iostream>
#include <vector>
#include "egl_context.h"
namespace thermion::windows::vulkan {
ThermionEGLContext::ThermionEGLContext() {
// *******************
// * *
// * *
// * EGL starts here *
// * *
// * *
// * *
// *******************
EGLBoolean bindAPI = eglBindAPI(EGL_OPENGL_ES_API);
if (!bindAPI) {
std::cout << "eglBindAPI EGL_OPENGL_ES_API failed" << std::endl;
return;
}
_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (_eglDisplay == EGL_NO_DISPLAY) {
std::cout << "eglBindAPI EGL_OPENGL_ES_API failed" << std::endl;
return;
}
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 (!initialized) {
std::cout << "eglInitialize failed" << std::endl;
return;
}
// glext::importGLESExtensionsEntryPoints();
EGLint configsCount;
EGLint configAttribs[] = {EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8, EGL_DEPTH_SIZE, 24,
EGL_STENCIL_SIZE, 8, EGL_ALPHA_SIZE, 8,
EGL_NONE};
EGLint contextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE,
EGL_NONE, // reserved for EGL_CONTEXT_OPENGL_NO_ERROR_KHR below
EGL_NONE};
// find an opaque config
if (!eglChooseConfig(_eglDisplay, configAttribs, &_eglConfig, 1,
&configsCount)) {
std::cout << "Failed to find EGL config" << std::endl;
return;
}
auto ctx = eglCreateContext(_eglDisplay, _eglConfig, EGL_NO_CONTEXT,contextAttribs);
_context = (void*)ctx;
if (_context == EGL_NO_CONTEXT) {
return;
}
}
EGLTexture* ThermionEGLContext::CreateRenderingSurface(
uint32_t width, uint32_t height,
uint32_t left, uint32_t top
) {
// glext::importGLESExtensionsEntryPoints();
if(left != 0 || top != 0) {
std::cout << "ERROR Rendering with EGL uses a Texture render target/Flutter widget and does not need a window offset." << std::endl;
return nullptr;
}
//if (_active && _active.get()) {
// // result->Error("ERROR",
// // "Texture already exists. You must call destroyTexture before "
// // "attempting to create a new one.");
// return nullptr;
//}
_active = std::make_unique<EGLTexture>(
width, height,
_D3D11Device, _D3D11DeviceContext, _eglConfig, _eglDisplay, _context,
[=](size_t width, size_t height) {
std::cout << "RESIZE" << std::endl;
std::vector<int64_t> list;
list.push_back((int64_t)width);
list.push_back((int64_t)height);
// auto val = std::make_unique<flutter::EncodableValue>(list);
// this->_channel->InvokeMethod("resize", std::move(val), nullptr);
});
return _active.get();
}
void* ThermionEGLContext::GetSharedContext() {
return (void*)_context;
}
void ThermionEGLContext::ResizeRenderingSurface(uint32_t width, uint32_t height, uint32_t left, uint32_t top) {
}
void ThermionEGLContext::DestroyRenderingSurface() {
}
EGLTexture *ThermionEGLContext::GetActiveTexture() {
return _active.get();
}
}