#include "TextureVk.h" #include "vulkan.h" TextureVk::TextureVk(VkDevice device, VkPhysicalDevice physicalDevice, VkInstance instance, VkQueue* pQueue) : m_data() , m_image() , m_memory() , m_memoryProperties() , m_device(device) , m_pQueue(pQueue) { // Update the texture data m_data.m_pDevice = device; m_data.m_pPhysicalDevice = physicalDevice; m_data.m_pInstance = instance; vkGetPhysicalDeviceMemoryProperties(physicalDevice, &m_memoryProperties); } TextureVk::~TextureVk() { vkFreeMemory(m_device, m_memory, nullptr); vkDestroyImage(m_device, m_image, nullptr); } vr::VRTextureWithPose_t TextureVk::ToVRTexture() { // Update the texture data m_data.m_pQueue = *m_pQueue; // FIXME: We don't know what family the queue is from vr::VRTextureWithPose_t texture = {}; texture.eColorSpace = vr::ColorSpace_Auto; texture.eType = vr::TextureType_Vulkan; texture.handle = &m_data; return texture; } VkFormat TextureVk::TextureFormatToVkFormat(ovrTextureFormat format) { switch (format) { case OVR_FORMAT_UNKNOWN: return VK_FORMAT_UNDEFINED; case OVR_FORMAT_B5G6R5_UNORM: return VK_FORMAT_B5G6R5_UNORM_PACK16; case OVR_FORMAT_B5G5R5A1_UNORM: return VK_FORMAT_B5G5R5A1_UNORM_PACK16; case OVR_FORMAT_B4G4R4A4_UNORM: return VK_FORMAT_B4G4R4A4_UNORM_PACK16; case OVR_FORMAT_R8G8B8A8_UNORM: return VK_FORMAT_R8G8B8A8_UNORM; case OVR_FORMAT_R8G8B8A8_UNORM_SRGB: return VK_FORMAT_R8G8B8A8_SRGB; case OVR_FORMAT_B8G8R8A8_UNORM: return VK_FORMAT_B8G8R8A8_UNORM; case OVR_FORMAT_B8G8R8A8_UNORM_SRGB: return VK_FORMAT_B8G8R8A8_SRGB; case OVR_FORMAT_B8G8R8X8_UNORM: return VK_FORMAT_B8G8R8_UNORM; case OVR_FORMAT_B8G8R8X8_UNORM_SRGB: return VK_FORMAT_B8G8R8_SRGB; case OVR_FORMAT_R16G16B16A16_FLOAT: return VK_FORMAT_R16G16B16A16_SFLOAT; case OVR_FORMAT_R11G11B10_FLOAT: return VK_FORMAT_A2R10G10B10_UINT_PACK32; // TODO: OpenVR doesn't support R11G11B10 // Depth formats case OVR_FORMAT_D16_UNORM: return VK_FORMAT_D16_UNORM; case OVR_FORMAT_D24_UNORM_S8_UINT: return VK_FORMAT_D24_UNORM_S8_UINT; case OVR_FORMAT_D32_FLOAT: return VK_FORMAT_D32_SFLOAT; case OVR_FORMAT_D32_FLOAT_S8X24_UINT: return VK_FORMAT_D32_SFLOAT_S8_UINT; // Added in 1.5 compressed formats can be used for static layers case OVR_FORMAT_BC1_UNORM: return VK_FORMAT_BC1_RGBA_UNORM_BLOCK; case OVR_FORMAT_BC1_UNORM_SRGB: return VK_FORMAT_BC1_RGBA_SRGB_BLOCK; case OVR_FORMAT_BC2_UNORM: return VK_FORMAT_BC2_UNORM_BLOCK; case OVR_FORMAT_BC2_UNORM_SRGB: return VK_FORMAT_BC2_SRGB_BLOCK; case OVR_FORMAT_BC3_UNORM: return VK_FORMAT_BC3_UNORM_BLOCK; case OVR_FORMAT_BC3_UNORM_SRGB: return VK_FORMAT_BC3_SRGB_BLOCK; case OVR_FORMAT_BC6H_UF16: return VK_FORMAT_BC6H_UFLOAT_BLOCK; case OVR_FORMAT_BC6H_SF16: return VK_FORMAT_BC6H_SFLOAT_BLOCK; case OVR_FORMAT_BC7_UNORM: return VK_FORMAT_BC7_UNORM_BLOCK; case OVR_FORMAT_BC7_UNORM_SRGB: return VK_FORMAT_BC7_SRGB_BLOCK; default: return VK_FORMAT_UNDEFINED; } } VkImageUsageFlags TextureVk::BindFlagsToVkImageUsageFlags(unsigned int flags) { VkImageUsageFlags result = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; if (flags & ovrTextureBind_DX_RenderTarget) result |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; if (flags & ovrTextureBind_DX_UnorderedAccess) result |= VK_IMAGE_USAGE_STORAGE_BIT; if (flags & ovrTextureBind_DX_DepthStencil) result |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; return result; } bool TextureVk::GetMemoryType(uint32_t typeBits, VkFlags requirements_mask, uint32_t* typeIndex) { // Search memtypes to find first index with those properties for (uint32_t i = 0; i < m_memoryProperties.memoryTypeCount; i++) { if ((typeBits & 1) == 1) { // Type is available, does it match user properties? if ((m_memoryProperties.memoryTypes[i].propertyFlags & requirements_mask) == requirements_mask) { *typeIndex = i; return true; } } typeBits >>= 1; } // No memory types matched, return failure return false; } bool TextureVk::Init(ovrTextureType type, int Width, int Height, int MipLevels, int ArraySize, ovrTextureFormat Format, unsigned int MiscFlags, unsigned int BindFlags) { VK_DEVICE_FUNCTION(m_device, vkCreateImage) VK_DEVICE_FUNCTION(m_device, vkGetImageMemoryRequirements) VK_DEVICE_FUNCTION(m_device, vkAllocateMemory) VK_DEVICE_FUNCTION(m_device, vkBindImageMemory) VK_DEVICE_FUNCTION(m_device, vkFreeMemory) VK_DEVICE_FUNCTION(m_device, vkDestroyImage) VkImageCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; create_info.imageType = VK_IMAGE_TYPE_2D; create_info.format = TextureFormatToVkFormat(Format); create_info.extent.width = Width; create_info.extent.height = Height; create_info.extent.depth = 1; create_info.mipLevels = MipLevels; create_info.arrayLayers = ArraySize; create_info.samples = VK_SAMPLE_COUNT_1_BIT; create_info.tiling = VK_IMAGE_TILING_OPTIMAL; create_info.usage = BindFlagsToVkImageUsageFlags(BindFlags); create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; if (vkCreateImage(m_device, &create_info, nullptr, &m_image) != VK_SUCCESS) return false; VkMemoryRequirements memReqs = {}; vkGetImageMemoryRequirements(m_device, m_image, &memReqs); VkMemoryAllocateInfo memAlloc = {}; memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; memAlloc.allocationSize = memReqs.size; if (!GetMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAlloc.memoryTypeIndex)) return false; if (vkAllocateMemory(m_device, &memAlloc, nullptr, &m_memory) != VK_SUCCESS) return false; if (vkBindImageMemory(m_device, m_image, m_memory, 0) != VK_SUCCESS) return false; // Update texture data m_data.m_nImage = (uint64_t)m_image; m_data.m_nWidth = create_info.extent.width; m_data.m_nHeight = create_info.extent.height; m_data.m_nFormat = create_info.format; m_data.m_nSampleCount = create_info.samples; return true; }