Files
cup_edit/thermion_dart/native/src/windows/vulkan/vulkan_texture.cpp
Nick Fisher 436873a455 successfully creating D3D texture with D3D11_RESOURCE_MISC_SHARED_NTHANDLE;
successfully allocating with VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT

working copying vulkan texture

successfully passing D3D texture back to Flutter

chore: Dart/Windows sample project: remove unnnecessary InvalidateRect from update()

chore: Dart/Windows sample project: add generated bindings

successfully blitting from Vulkan swapchain to D3D texture

working Vulkan texture integration with Flutter

refactor to allow disposal of resources in destructors

handle destroyTexture correctly

correctly implement surface resizing/destruction

move Windows engine to Vulkan backend and flush after creating swapchain

add vulkan + vkshaders to Windows libs

update materials with Vulkan

move Vulkan implementation to thermion_Dart

remove extras folder

thermion_flutter plugin updates

update build hook to copy .lib file to output directory and use -vulkan lib zip file

thermion_flutter cleanup

reinstate stereoscopic on Windows

add dxgi and d3d11.lib to windows header pragma

update cli_windows sample project

copy filament/vulkan headers to output directory. This was originally added to facilitate linking on Windows (where thermion_flutter_plugin.cpp needs the Vulkan-related headers), but this doesn't actually solve the problem because there's no way that I've found to get the directory structure correct in the Dart native_assets build directory unless you explicitly address each inidivual file. The current approach is therefore to just keep a permanent copy of the headers in the thermion_filament directory (meaning these will need to be updated manually if the Filament version changes). However, I decided to keep the changes to build.dart because it doesn't have much negative impact and may be helpful in future.

disable stereoscopic on Windows and disable handle use after free checks

use filament headers for thermion_flutter

throw Exception for MSAA on Windows (note that passing msaa:true for setAntiAliasing doesn't actually set MSAA on other platforms, but at least it won't cause the engine to crash)

change header include path for Windows/Vulkan

change header include path for Windows/Vulkan

add filament/vulkan headers for flutter (Windows)

ensure destroyTexture platform methods accept an integer rather than a list

handle Android/Windows swapchain creation separately
2024-11-11 12:49:40 +08:00

158 lines
6.8 KiB
C++

#include "vulkan_texture.h"
#include "bluevk/BlueVK.h"
#include "utils.h"
#include <iostream>
namespace thermion::windows::vulkan
{
VulkanTexture::VulkanTexture(VkImage image, VkDevice device, VkDeviceMemory imageMemory, uint32_t width, uint32_t height, HANDLE d3dTextureHandle) : _image(image), _device(device), _imageMemory(imageMemory), _width(width), _height(height), _d3dTextureHandle(d3dTextureHandle) {};
VulkanTexture::~VulkanTexture() {
bluevk::vkDeviceWaitIdle(_device);
if(_image != VK_NULL_HANDLE) {
bluevk::vkDestroyImage(_device, _image, nullptr);
} else {
std::cout << "Warning : no vkImage found" << std::endl;
}
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkImportMemoryWin32HandleInfoKHR.html
// imageMemory has been imported from D3D without transferring ownership
// therefore we don't need to release
}
std::unique_ptr<VulkanTexture> VulkanTexture::create(VkDevice device, VkPhysicalDevice physicalDevice, uint32_t width, uint32_t height, HANDLE d3dTextureHandle)
{
// 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_B8G8R8A8_UNORM,
.extent = {width, height, 1},
.mipLevels = 1,
.arrayLayers = 1,
.samples = VK_SAMPLE_COUNT_1_BIT,
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED};
VkImage image;
VkResult result = bluevk::vkCreateImage(device, &imageInfo, nullptr, &image);
if (result != VK_SUCCESS)
{
std::cout << "Failed to create iamge " << std::endl;
return nullptr;
}
std::cout << "Created vkImage " << (int64_t)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...
bluevk::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 = d3dTextureHandle,
.name = nullptr};
// Find suitable memory type
uint32_t memoryTypeIndex = findOptimalMemoryType(
physicalDevice,
MemoryRequirements.memoryTypeBits,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
);
VkMemoryAllocateInfo allocInfo{
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.pNext = &ImportMemoryWin32HandleInfo,
.allocationSize = MemoryRequirements.size,
.memoryTypeIndex = memoryTypeIndex
};
VkDeviceMemory imageMemory = VK_NULL_HANDLE;
VkResult allocResult = bluevk::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 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 nullptr;
}
const VkBindImageMemoryInfo bindImageMemoryInfo{
.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
.pNext = nullptr,
.image = image,
.memory = imageMemory,
.memoryOffset = 0};
result = bluevk::vkBindImageMemory2(device, 1, &bindImageMemoryInfo);
if (result != VK_SUCCESS)
{
std::cout << "vkBindImageMemory2 failed" << std::endl;
return nullptr;
}
return std::make_unique<VulkanTexture>(image, device, imageMemory, width, height, d3dTextureHandle);
}
}