mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-08-09 13:22:24 +03:00
317 lines
12 KiB
C++
317 lines
12 KiB
C++
// Copyright (c) 2019 OPEN CASCADE SAS
|
|
//
|
|
// This file is part of Open CASCADE Technology software library.
|
|
//
|
|
// This library is free software; you can redistribute it and/or modify it under
|
|
// the terms of the GNU Lesser General Public License version 2.1 as published
|
|
// by the Free Software Foundation, with special exception defined in the file
|
|
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
|
// distribution for complete text of the license and disclaimer of any warranty.
|
|
//
|
|
// Alternatively, this file may be used under the terms of Open CASCADE
|
|
// commercial license or contractual agreement.
|
|
|
|
#if defined(_WIN32)
|
|
#include <windows.h>
|
|
|
|
#define VK_USE_PLATFORM_WIN32_KHR 1
|
|
#endif
|
|
|
|
#include <Vulkan_Surface.hxx>
|
|
|
|
#include <Aspect_Window.hxx>
|
|
#include <Message.hxx>
|
|
#include <Message_Messenger.hxx>
|
|
#include <Vulkan_Device.hxx>
|
|
#include <Vulkan_Fence.hxx>
|
|
|
|
#include <vulkan/vulkan.h>
|
|
|
|
IMPLEMENT_STANDARD_RTTIEXT(Vulkan_Surface, Standard_Transient)
|
|
|
|
// =======================================================================
|
|
// function : Vulkan_Surface
|
|
// purpose :
|
|
// =======================================================================
|
|
Vulkan_Surface::Vulkan_Surface()
|
|
: mySwapFence (new Vulkan_Fence()),
|
|
myVkSurface (NULL),
|
|
myVkSwapChain (NULL),
|
|
myVkFormat (new VkSurfaceFormatKHR())
|
|
{
|
|
//
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : ~Vulkan_Surface
|
|
// purpose :
|
|
// =======================================================================
|
|
Vulkan_Surface::~Vulkan_Surface()
|
|
{
|
|
Release (Handle(Vulkan_Device)());
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : Release
|
|
// purpose :
|
|
// =======================================================================
|
|
void Vulkan_Surface::Release (const Handle(Vulkan_Device)& theDevice)
|
|
{
|
|
mySwapFence->Release (theDevice);
|
|
for (size_t anImgIter = 0; anImgIter < myVkImageViews.size(); ++anImgIter)
|
|
{
|
|
VkImageView& aVkImageView = myVkImageViews[anImgIter];
|
|
if (aVkImageView != NULL)
|
|
{
|
|
Standard_ASSERT_RETURN (!theDevice.IsNull(), "Vulkan_Surface destroyed without Vulkan context",);
|
|
vkDestroyImageView (theDevice->Device(), aVkImageView, theDevice->HostAllocator());
|
|
aVkImageView = NULL;
|
|
}
|
|
}
|
|
myVkImages.clear();
|
|
myVkImageViews.clear();
|
|
if (myVkSwapChain != NULL)
|
|
{
|
|
Standard_ASSERT_RETURN (!theDevice.IsNull(), "Vulkan_Surface destroyed without Vulkan context",);
|
|
vkDestroySwapchainKHR (theDevice->Device(), myVkSwapChain, theDevice->HostAllocator());
|
|
myVkSwapChain = NULL;
|
|
}
|
|
if (myVkSurface != NULL)
|
|
{
|
|
Standard_ASSERT_RETURN (!theDevice.IsNull(), "Vulkan_Surface destroyed without Vulkan context",);
|
|
vkDestroySurfaceKHR (theDevice->Instance(), myVkSurface, theDevice->HostAllocator());
|
|
myVkSurface = NULL;
|
|
}
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : Init
|
|
// purpose :
|
|
// =======================================================================
|
|
bool Vulkan_Surface::Init (const Handle(Vulkan_Device)& theDevice,
|
|
const Handle(Aspect_Window)& theWindow)
|
|
{
|
|
Release (theDevice);
|
|
if (theDevice.IsNull()
|
|
|| theDevice->Device() == NULL
|
|
|| theWindow.IsNull())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!mySwapFence->Create (theDevice))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
#if defined(_WIN32)
|
|
VkWin32SurfaceCreateInfoKHR aVkWin32SurfInfo;
|
|
aVkWin32SurfInfo.sType = VkStructureType::VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
|
|
aVkWin32SurfInfo.pNext = NULL;
|
|
aVkWin32SurfInfo.flags = 0;
|
|
aVkWin32SurfInfo.hinstance = GetModuleHandleW (NULL);
|
|
aVkWin32SurfInfo.hwnd = (HWND )theWindow->NativeHandle();
|
|
|
|
VkResult aRes = vkCreateWin32SurfaceKHR (theDevice->Instance(), &aVkWin32SurfInfo, theDevice->HostAllocator(), &myVkSurface);
|
|
if (aRes != VkResult::VK_SUCCESS)
|
|
{
|
|
Message::DefaultMessenger()->Send (TCollection_AsciiString ("Vulkan_Surface, unable to create surface: ") + Vulkan_Device::FormatVkError (aRes));
|
|
Release (theDevice);
|
|
return false;
|
|
}
|
|
#else
|
|
int NOT_IMPLEMENTED = 0;
|
|
return false;
|
|
#endif
|
|
|
|
VkBool32 isSupported = VK_FALSE;
|
|
aRes = vkGetPhysicalDeviceSurfaceSupportKHR (theDevice->PhysicalDevice(), 0, myVkSurface, &isSupported);
|
|
if (aRes != VkResult::VK_SUCCESS || isSupported == VK_FALSE)
|
|
{
|
|
if (aRes != VkResult::VK_SUCCESS)
|
|
{
|
|
Message::DefaultMessenger()->Send (TCollection_AsciiString ("Vulkan_Surface, surface not supported: ") + Vulkan_Device::FormatVkError (aRes));
|
|
}
|
|
else
|
|
{
|
|
Message::DefaultMessenger()->Send (TCollection_AsciiString ("Vulkan_Surface, surface not supported"));
|
|
}
|
|
Release (theDevice);
|
|
return false;
|
|
}
|
|
|
|
VkSurfaceCapabilitiesKHR aVkSurfCaps;
|
|
aRes = vkGetPhysicalDeviceSurfaceCapabilitiesKHR (theDevice->PhysicalDevice(), myVkSurface, &aVkSurfCaps);
|
|
if (aRes != VkResult::VK_SUCCESS)
|
|
{
|
|
Message::DefaultMessenger()->Send (TCollection_AsciiString ("Vulkan_Surface, failed to get surface capabilities: ") + Vulkan_Device::FormatVkError (aRes));
|
|
Release (theDevice);
|
|
return false;
|
|
}
|
|
|
|
if (!findFormat (theDevice, *myVkFormat))
|
|
{
|
|
Release (theDevice);
|
|
return false;
|
|
}
|
|
|
|
{
|
|
VkSwapchainCreateInfoKHR aSwapChainInfo;
|
|
aSwapChainInfo.sType = VkStructureType::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
|
aSwapChainInfo.pNext = NULL;
|
|
aSwapChainInfo.flags = 0;
|
|
aSwapChainInfo.surface = myVkSurface;
|
|
aSwapChainInfo.minImageCount = 2;
|
|
aSwapChainInfo.imageFormat = myVkFormat->format;
|
|
aSwapChainInfo.imageColorSpace = myVkFormat->colorSpace;
|
|
aSwapChainInfo.imageExtent = VkExtent2D { aVkSurfCaps.currentExtent.width, aVkSurfCaps.currentExtent.height };
|
|
aSwapChainInfo.imageArrayLayers = 1;
|
|
aSwapChainInfo.imageUsage = VkImageUsageFlagBits::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
|
aSwapChainInfo.imageSharingMode = VkSharingMode::VK_SHARING_MODE_EXCLUSIVE;
|
|
aSwapChainInfo.queueFamilyIndexCount = 0;
|
|
aSwapChainInfo.pQueueFamilyIndices = NULL;
|
|
aSwapChainInfo.preTransform = VkSurfaceTransformFlagBitsKHR::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
|
aSwapChainInfo.compositeAlpha = VkCompositeAlphaFlagBitsKHR::VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
|
aSwapChainInfo.presentMode = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_KHR;
|
|
aSwapChainInfo.clipped = VK_TRUE;
|
|
aSwapChainInfo.oldSwapchain = VK_NULL_HANDLE;
|
|
|
|
aRes = vkCreateSwapchainKHR (theDevice->Device(), &aSwapChainInfo, theDevice->HostAllocator(), &myVkSwapChain);
|
|
if (aRes != VkResult::VK_SUCCESS)
|
|
{
|
|
Message::DefaultMessenger()->Send (TCollection_AsciiString ("Vulkan_Surface, failed to create swapchain: ") + Vulkan_Device::FormatVkError (aRes));
|
|
Release (theDevice);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
{
|
|
uint32_t aNbSwapChainImages = 0;
|
|
aRes = vkGetSwapchainImagesKHR (theDevice->Device(), myVkSwapChain, &aNbSwapChainImages, NULL);
|
|
if (aRes != VkResult::VK_SUCCESS)
|
|
{
|
|
Message::DefaultMessenger()->Send (TCollection_AsciiString ("Vulkan_Surface, failed to get swapchain images count: ") + Vulkan_Device::FormatVkError (aRes));
|
|
return false;
|
|
}
|
|
|
|
myVkImages.resize (aNbSwapChainImages, NULL);
|
|
aRes = vkGetSwapchainImagesKHR (theDevice->Device(), myVkSwapChain, &aNbSwapChainImages, myVkImages.data());
|
|
if (aRes != VkResult::VK_SUCCESS)
|
|
{
|
|
Message::DefaultMessenger()->Send (TCollection_AsciiString ("Vulkan_Surface, failed to get swapchain images: ") + Vulkan_Device::FormatVkError (aRes));
|
|
Release (theDevice);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
myVkImageViews.resize (myVkImages.size(), NULL);
|
|
for (uint32_t anImgIter = 0; anImgIter < myVkImages.size(); ++anImgIter)
|
|
{
|
|
VkImageView& aVkImageView = myVkImageViews[anImgIter];
|
|
|
|
VkImageViewCreateInfo aVkImgViewInfo;
|
|
aVkImgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
aVkImgViewInfo.pNext = NULL;
|
|
aVkImgViewInfo.flags = 0;
|
|
aVkImgViewInfo.image = myVkImages[anImgIter];
|
|
aVkImgViewInfo.viewType = VkImageViewType::VK_IMAGE_VIEW_TYPE_2D;
|
|
aVkImgViewInfo.format = myVkFormat->format;
|
|
aVkImgViewInfo.components =
|
|
{
|
|
VkComponentSwizzle::VK_COMPONENT_SWIZZLE_R,
|
|
VkComponentSwizzle::VK_COMPONENT_SWIZZLE_G,
|
|
VkComponentSwizzle::VK_COMPONENT_SWIZZLE_B,
|
|
VkComponentSwizzle::VK_COMPONENT_SWIZZLE_A
|
|
};
|
|
aVkImgViewInfo.subresourceRange.aspectMask = VkImageAspectFlagBits::VK_IMAGE_ASPECT_COLOR_BIT;
|
|
aVkImgViewInfo.subresourceRange.baseMipLevel = 0;
|
|
aVkImgViewInfo.subresourceRange.levelCount = 1;
|
|
aVkImgViewInfo.subresourceRange.baseArrayLayer = 0;
|
|
aVkImgViewInfo.subresourceRange.layerCount = 1;
|
|
|
|
aRes = vkCreateImageView (theDevice->Device(), &aVkImgViewInfo, theDevice->HostAllocator(), &aVkImageView);
|
|
if (aRes != VkResult::VK_SUCCESS)
|
|
{
|
|
Message::DefaultMessenger()->Send (TCollection_AsciiString ("Vulkan_Surface, failed to create image view: ") + Vulkan_Device::FormatVkError (aRes));
|
|
Release (theDevice);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : findFormat
|
|
// purpose :
|
|
// =======================================================================
|
|
bool Vulkan_Surface::findFormat (const Handle(Vulkan_Device)& theDevice,
|
|
VkSurfaceFormatKHR& theFormat)
|
|
{
|
|
if (myVkSurface == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
uint32_t aNbSurfFormats = 0;
|
|
VkResult aRes = vkGetPhysicalDeviceSurfaceFormatsKHR (theDevice->PhysicalDevice(), myVkSurface, &aNbSurfFormats, NULL);
|
|
if (aRes != VkResult::VK_SUCCESS
|
|
|| aNbSurfFormats == 0)
|
|
{
|
|
Message::DefaultMessenger()->Send (TCollection_AsciiString ("Vulkan_Surface, failed to get surface formats count: ") + Vulkan_Device::FormatVkError (aRes));
|
|
return false;
|
|
}
|
|
|
|
std::vector<VkSurfaceFormatKHR> aVkSurfFormats (aNbSurfFormats);
|
|
aRes = vkGetPhysicalDeviceSurfaceFormatsKHR (theDevice->PhysicalDevice(), myVkSurface, &aNbSurfFormats, aVkSurfFormats.data());
|
|
if (aRes != VkResult::VK_SUCCESS)
|
|
{
|
|
Message::DefaultMessenger()->Send (TCollection_AsciiString ("Vulkan_Surface, failed to get surface formats: ") + Vulkan_Device::FormatVkError (aRes));
|
|
return false;
|
|
}
|
|
|
|
theFormat = aVkSurfFormats[0];
|
|
return true;
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : CurrentSize
|
|
// purpose :
|
|
// =======================================================================
|
|
Graphic3d_Vec2u Vulkan_Surface::CurrentSize (const Handle(Vulkan_Device)& theDevice)
|
|
{
|
|
if (myVkSurface == NULL)
|
|
{
|
|
return Graphic3d_Vec2u (0, 0);
|
|
}
|
|
|
|
VkSurfaceCapabilitiesKHR aVkSurfCaps;
|
|
VkResult aRes = vkGetPhysicalDeviceSurfaceCapabilitiesKHR (theDevice->PhysicalDevice(), myVkSurface, &aVkSurfCaps);
|
|
if (aRes != VkResult::VK_SUCCESS)
|
|
{
|
|
Message::DefaultMessenger()->Send (TCollection_AsciiString ("Vulkan_Window, failed to get surface capabilities: ") + Vulkan_Device::FormatVkError (aRes));
|
|
return Graphic3d_Vec2u (0, 0);
|
|
}
|
|
|
|
return Graphic3d_Vec2u (aVkSurfCaps.currentExtent.width, aVkSurfCaps.currentExtent.height);
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : AcquireNextImage
|
|
// purpose :
|
|
// =======================================================================
|
|
bool Vulkan_Surface::AcquireNextImage (const Handle(Vulkan_Device)& theDevice,
|
|
uint32_t& theSwapChainIndex)
|
|
{
|
|
theSwapChainIndex = 0;
|
|
VkResult aRes = vkAcquireNextImageKHR (theDevice->Device(), myVkSwapChain, UINT64_MAX, VK_NULL_HANDLE, mySwapFence->Fence(), &theSwapChainIndex);
|
|
if (aRes != VkResult::VK_SUCCESS)
|
|
{
|
|
Message::DefaultMessenger()->Send (TCollection_AsciiString ("Vulkan_Surface, failed to get next swapchain image: ") + Vulkan_Device::FormatVkError (aRes));
|
|
return false;
|
|
}
|
|
|
|
return mySwapFence->Wait (theDevice)
|
|
&& mySwapFence->Reset(theDevice);
|
|
}
|