2019-11-29 18:28:22 +00:00
|
|
|
/*
|
|
|
|
Created on: Nov 29, 2019
|
|
|
|
|
|
|
|
Copyright 2019 flyinghead
|
|
|
|
|
|
|
|
This file is part of Flycast.
|
|
|
|
|
|
|
|
Flycast is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Flycast is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
#pragma once
|
2021-01-23 14:59:57 +00:00
|
|
|
|
2020-05-09 10:07:49 +00:00
|
|
|
#ifdef USE_VULKAN
|
2021-01-09 17:16:39 +00:00
|
|
|
#include <stdexcept>
|
2019-11-29 18:28:22 +00:00
|
|
|
|
2021-07-08 10:47:00 +00:00
|
|
|
class InvalidVulkanContext : public std::runtime_error {
|
|
|
|
public:
|
|
|
|
InvalidVulkanContext() : std::runtime_error("Invalid Vulkan context") {}
|
|
|
|
};
|
2021-04-08 08:38:26 +00:00
|
|
|
|
2021-07-08 10:47:00 +00:00
|
|
|
#ifdef LIBRETRO
|
|
|
|
#include "vk_context_lr.h"
|
|
|
|
#else
|
|
|
|
|
|
|
|
#include "vulkan.h"
|
|
|
|
#include "vmallocator.h"
|
|
|
|
#include "quad.h"
|
|
|
|
#include "rend/TexCache.h"
|
|
|
|
#include "overlay.h"
|
2021-11-10 19:35:30 +00:00
|
|
|
#include "wsi/context.h"
|
2021-07-08 10:47:00 +00:00
|
|
|
|
|
|
|
struct ImDrawData;
|
2022-03-07 08:22:49 +00:00
|
|
|
class TextureCache;
|
2021-07-08 10:47:00 +00:00
|
|
|
|
2021-11-10 19:35:30 +00:00
|
|
|
class VulkanContext : public GraphicsContext
|
2019-11-29 18:28:22 +00:00
|
|
|
{
|
|
|
|
public:
|
2021-12-16 20:26:55 +00:00
|
|
|
VulkanContext();
|
|
|
|
~VulkanContext();
|
2019-11-29 18:28:22 +00:00
|
|
|
|
2021-11-10 19:35:30 +00:00
|
|
|
bool init();
|
|
|
|
void term() override;
|
2019-11-29 18:28:22 +00:00
|
|
|
|
|
|
|
VkInstance GetInstance() const { return static_cast<VkInstance>(instance.get()); }
|
|
|
|
u32 GetGraphicsQueueFamilyIndex() const { return graphicsQueueIndex; }
|
2021-11-10 19:35:30 +00:00
|
|
|
void resize() override { resized = true; }
|
2021-01-09 17:16:39 +00:00
|
|
|
bool IsValid() { return width != 0 && height != 0; }
|
2019-11-29 18:28:22 +00:00
|
|
|
void NewFrame();
|
|
|
|
void BeginRenderPass();
|
2021-04-08 08:38:26 +00:00
|
|
|
void EndFrame(vk::CommandBuffer cmdBuffer = vk::CommandBuffer());
|
2021-01-09 17:16:39 +00:00
|
|
|
void Present() noexcept;
|
2023-10-11 12:12:29 +00:00
|
|
|
void PresentFrame(vk::Image image, vk::ImageView imageView, const vk::Extent2D& extent, float aspectRatio) noexcept;
|
2019-11-30 11:14:36 +00:00
|
|
|
void PresentLastFrame();
|
2023-06-26 09:56:56 +00:00
|
|
|
void initVideoRouting() override;
|
2019-11-29 18:28:22 +00:00
|
|
|
|
|
|
|
vk::PhysicalDevice GetPhysicalDevice() const { return physicalDevice; }
|
|
|
|
vk::Device GetDevice() const { return *device; }
|
|
|
|
vk::PipelineCache GetPipelineCache() const { return *pipelineCache; }
|
|
|
|
vk::RenderPass GetRenderPass() const { return *renderPass; }
|
|
|
|
vk::CommandBuffer GetCurrentCommandBuffer() const { return *commandBuffers[GetCurrentImageIndex()]; }
|
|
|
|
vk::DescriptorPool GetDescriptorPool() const { return *descriptorPool; }
|
2021-09-27 18:29:23 +00:00
|
|
|
vk::Extent2D GetViewPort() const { return { (u32)settings.display.width, (u32)settings.display.height }; }
|
2023-06-26 09:56:56 +00:00
|
|
|
vk::SwapchainKHR GetSwapChain() const { return *swapChain; }
|
2021-12-15 16:58:58 +00:00
|
|
|
u32 GetSwapChainSize() const { return (u32)imageViews.size(); }
|
2019-11-29 18:28:22 +00:00
|
|
|
int GetCurrentImageIndex() const { return currentImage; }
|
2021-01-09 17:16:39 +00:00
|
|
|
void WaitIdle() const;
|
2019-11-29 18:28:22 +00:00
|
|
|
bool IsRendering() const { return rendering; }
|
|
|
|
vk::DeviceSize GetUniformBufferAlignment() const { return uniformBufferAlignment; }
|
|
|
|
vk::DeviceSize GetStorageBufferAlignment() const { return storageBufferAlignment; }
|
|
|
|
bool IsFormatSupported(TextureType textureType)
|
|
|
|
{
|
|
|
|
switch (textureType)
|
|
|
|
{
|
|
|
|
case TextureType::_4444:
|
|
|
|
return optimalTilingSupported4444;
|
|
|
|
case TextureType::_565:
|
|
|
|
return optimalTilingSupported565;
|
|
|
|
case TextureType::_5551:
|
|
|
|
return optimalTilingSupported1555;
|
|
|
|
default:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2022-12-21 15:49:08 +00:00
|
|
|
std::string getDriverName() override {
|
|
|
|
return driverName;
|
|
|
|
}
|
|
|
|
std::string getDriverVersion() override {
|
|
|
|
return driverVersion;
|
|
|
|
}
|
2019-11-29 18:28:22 +00:00
|
|
|
vk::Format GetDepthFormat() const { return depthFormat; }
|
|
|
|
static VulkanContext *Instance() { return contextInstance; }
|
|
|
|
bool SupportsSamplerAnisotropy() const { return samplerAnisotropy; }
|
2021-07-06 14:19:12 +00:00
|
|
|
float GetMaxSamplerAnisotropy() const { return samplerAnisotropy ? maxSamplerAnisotropy : 1.f; }
|
2019-11-29 18:28:22 +00:00
|
|
|
bool SupportsDedicatedAllocation() const { return dedicatedAllocationSupported; }
|
|
|
|
const VMAllocator& GetAllocator() const { return allocator; }
|
2019-12-07 21:12:14 +00:00
|
|
|
vk::DeviceSize GetMaxMemoryAllocationSize() const { return maxMemoryAllocationSize; }
|
2019-12-22 16:48:24 +00:00
|
|
|
u32 GetVendorID() const { return vendorID; }
|
2021-04-08 08:38:26 +00:00
|
|
|
vk::CommandBuffer PrepareOverlay(bool vmu, bool crosshair);
|
2021-01-23 14:59:57 +00:00
|
|
|
void DrawOverlay(float scaling, bool vmu, bool crosshair);
|
2022-10-06 16:02:01 +00:00
|
|
|
void SubmitCommandBuffers(const std::vector<vk::CommandBuffer> &buffers, vk::Fence fence) {
|
2021-07-08 10:47:00 +00:00
|
|
|
graphicsQueue.submit(
|
2022-10-06 16:02:01 +00:00
|
|
|
vk::SubmitInfo(nullptr, nullptr, buffers), fence);
|
2021-07-08 10:47:00 +00:00
|
|
|
}
|
2021-11-10 19:35:30 +00:00
|
|
|
bool hasPerPixel() override { return fragmentStoresAndAtomics; }
|
2022-06-17 14:17:58 +00:00
|
|
|
bool recreateSwapChainIfNeeded();
|
2019-11-29 18:28:22 +00:00
|
|
|
|
2021-01-09 17:16:39 +00:00
|
|
|
#ifdef VK_DEBUG
|
|
|
|
void setObjectName(u64 object, VkDebugReportObjectTypeEXT objectType, const std::string& name)
|
|
|
|
{
|
|
|
|
VkDebugMarkerObjectNameInfoEXT nameInfo = {};
|
|
|
|
nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT;
|
|
|
|
nameInfo.objectType = objectType;
|
|
|
|
nameInfo.object = object;
|
|
|
|
nameInfo.pObjectName = name.c_str();
|
2023-02-01 16:55:24 +00:00
|
|
|
VULKAN_HPP_DEFAULT_DISPATCHER.vkDebugMarkerSetObjectNameEXT((VkDevice)*device, &nameInfo);
|
2021-01-09 17:16:39 +00:00
|
|
|
}
|
|
|
|
#endif
|
2021-12-13 20:02:44 +00:00
|
|
|
constexpr static int VENDOR_AMD = 0x1022;
|
|
|
|
// AMD GPU products use the ATI vendor Id
|
|
|
|
constexpr static int VENDOR_ATI = 0x1002;
|
|
|
|
constexpr static int VENDOR_ARM = 0x13B5;
|
|
|
|
constexpr static int VENDOR_INTEL = 0x8086;
|
|
|
|
constexpr static int VENDOR_NVIDIA = 0x10DE;
|
|
|
|
constexpr static int VENDOR_QUALCOMM = 0x5143;
|
|
|
|
constexpr static int VENDOR_MESA = 0x10005;
|
2021-01-09 17:16:39 +00:00
|
|
|
|
2019-11-29 18:28:22 +00:00
|
|
|
private:
|
2021-01-09 17:16:39 +00:00
|
|
|
void CreateSwapChain();
|
|
|
|
bool InitDevice();
|
|
|
|
bool InitInstance(const char** extensions, uint32_t extensions_count);
|
2019-11-29 18:28:22 +00:00
|
|
|
void InitImgui();
|
|
|
|
void DoSwapAutomation();
|
2022-10-25 13:00:04 +00:00
|
|
|
void DrawFrame(vk::ImageView imageView, const vk::Extent2D& extent, float aspectRatio);
|
2021-01-09 17:16:39 +00:00
|
|
|
vk::SurfaceKHR GetSurface() const { return *surface; }
|
2019-11-29 18:28:22 +00:00
|
|
|
|
2021-01-09 17:16:39 +00:00
|
|
|
bool HasSurfaceDimensionChanged() const;
|
|
|
|
void SetWindowSize(u32 width, u32 height);
|
2019-11-29 18:28:22 +00:00
|
|
|
|
|
|
|
VMAllocator allocator;
|
|
|
|
bool rendering = false;
|
|
|
|
bool renderDone = false;
|
|
|
|
u32 width = 0;
|
|
|
|
u32 height = 0;
|
2021-01-09 17:16:39 +00:00
|
|
|
bool resized = false;
|
2021-04-20 08:56:49 +00:00
|
|
|
bool swapOnVSync = true;
|
2019-11-29 18:28:22 +00:00
|
|
|
vk::UniqueInstance instance;
|
|
|
|
vk::PhysicalDevice physicalDevice;
|
|
|
|
|
|
|
|
u32 graphicsQueueIndex = 0;
|
|
|
|
u32 presentQueueIndex = 0;
|
|
|
|
vk::DeviceSize uniformBufferAlignment = 0;
|
|
|
|
vk::DeviceSize storageBufferAlignment = 0;
|
2019-12-14 16:53:01 +00:00
|
|
|
vk::DeviceSize maxMemoryAllocationSize = 0xFFFFFFFFu;
|
2019-11-29 18:28:22 +00:00
|
|
|
bool optimalTilingSupported565 = false;
|
|
|
|
bool optimalTilingSupported1555 = false;
|
|
|
|
bool optimalTilingSupported4444 = false;
|
|
|
|
bool fragmentStoresAndAtomics = false;
|
|
|
|
bool samplerAnisotropy = false;
|
2021-07-06 14:19:12 +00:00
|
|
|
float maxSamplerAnisotropy = 0.f;
|
2019-11-29 18:28:22 +00:00
|
|
|
bool dedicatedAllocationSupported = false;
|
2019-12-22 16:48:24 +00:00
|
|
|
u32 vendorID = 0;
|
2021-11-10 19:35:30 +00:00
|
|
|
int swapInterval = 1;
|
2019-11-29 18:28:22 +00:00
|
|
|
vk::UniqueDevice device;
|
|
|
|
|
|
|
|
vk::UniqueSurfaceKHR surface;
|
|
|
|
|
|
|
|
vk::UniqueSwapchainKHR swapChain;
|
|
|
|
std::vector<vk::UniqueImageView> imageViews;
|
|
|
|
u32 currentImage = 0;
|
|
|
|
vk::Format colorFormat = vk::Format::eUndefined;
|
|
|
|
|
|
|
|
vk::Queue graphicsQueue;
|
|
|
|
vk::Queue presentQueue;
|
|
|
|
|
|
|
|
vk::UniqueDescriptorPool descriptorPool;
|
|
|
|
vk::UniqueRenderPass renderPass;
|
|
|
|
|
|
|
|
vk::Format depthFormat = vk::Format::eUndefined;
|
|
|
|
|
|
|
|
std::vector<vk::UniqueCommandPool> commandPools;
|
|
|
|
std::vector<vk::UniqueCommandBuffer> commandBuffers;
|
|
|
|
|
|
|
|
std::vector<vk::UniqueFramebuffer> framebuffers;
|
|
|
|
|
|
|
|
std::vector<vk::UniqueFence> drawFences;
|
|
|
|
std::vector<vk::UniqueSemaphore> renderCompleteSemaphores;
|
|
|
|
std::vector<vk::UniqueSemaphore> imageAcquiredSemaphores;
|
|
|
|
u32 currentSemaphore = 0;
|
|
|
|
|
|
|
|
vk::UniquePipelineCache pipelineCache;
|
|
|
|
|
2021-11-01 12:05:22 +00:00
|
|
|
std::unique_ptr<QuadPipeline> quadPipelineWithAlpha;
|
2019-11-29 18:28:22 +00:00
|
|
|
std::unique_ptr<QuadPipeline> quadPipeline;
|
2021-03-19 18:31:01 +00:00
|
|
|
std::unique_ptr<QuadPipeline> quadRotatePipeline;
|
2019-12-25 12:09:54 +00:00
|
|
|
std::unique_ptr<QuadDrawer> quadDrawer;
|
2021-03-19 18:31:01 +00:00
|
|
|
std::unique_ptr<QuadDrawer> quadRotateDrawer;
|
2019-11-29 18:28:22 +00:00
|
|
|
std::unique_ptr<ShaderManager> shaderManager;
|
|
|
|
|
2019-11-30 11:14:36 +00:00
|
|
|
vk::ImageView lastFrameView;
|
2021-01-09 17:16:39 +00:00
|
|
|
vk::Extent2D lastFrameExtent;
|
2022-10-25 13:00:04 +00:00
|
|
|
float lastFrameAR = 0.f;
|
2019-11-30 11:14:36 +00:00
|
|
|
|
2021-01-23 14:59:57 +00:00
|
|
|
std::unique_ptr<VulkanOverlay> overlay;
|
2021-12-16 20:26:55 +00:00
|
|
|
// only used to delay the destruction of overlay textures
|
|
|
|
std::unique_ptr<TextureCache> textureCache;
|
2019-12-25 12:09:54 +00:00
|
|
|
|
2022-12-21 15:49:08 +00:00
|
|
|
std::string driverName;
|
|
|
|
std::string driverVersion;
|
|
|
|
|
2019-11-29 18:28:22 +00:00
|
|
|
#ifdef VK_DEBUG
|
|
|
|
#ifndef __ANDROID__
|
|
|
|
vk::UniqueDebugUtilsMessengerEXT debugUtilsMessenger;
|
|
|
|
#else
|
|
|
|
vk::UniqueDebugReportCallbackEXT debugReportCallback;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
static VulkanContext *contextInstance;
|
|
|
|
};
|
2021-07-08 10:47:00 +00:00
|
|
|
#endif // !LIBRETRO
|
2020-05-09 10:07:49 +00:00
|
|
|
|
2021-07-08 10:47:00 +00:00
|
|
|
static inline vk::Format findDepthFormat(vk::PhysicalDevice physicalDevice)
|
|
|
|
{
|
|
|
|
const vk::Format depthFormats[] = { vk::Format::eD32SfloatS8Uint, vk::Format::eD24UnormS8Uint, vk::Format::eD16UnormS8Uint };
|
|
|
|
vk::ImageTiling tiling;
|
|
|
|
vk::Format depthFormat = vk::Format::eUndefined;
|
2023-02-18 12:24:34 +00:00
|
|
|
for (size_t i = 0; i < std::size(depthFormats); i++)
|
2021-07-08 10:47:00 +00:00
|
|
|
{
|
|
|
|
vk::FormatProperties formatProperties = physicalDevice.getFormatProperties(depthFormats[i]);
|
|
|
|
|
|
|
|
if (formatProperties.optimalTilingFeatures & vk::FormatFeatureFlagBits::eDepthStencilAttachment)
|
|
|
|
{
|
|
|
|
tiling = vk::ImageTiling::eOptimal;
|
|
|
|
depthFormat = depthFormats[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (depthFormat == vk::Format::eUndefined)
|
|
|
|
{
|
|
|
|
// Try to find a linear format
|
2023-02-18 12:24:34 +00:00
|
|
|
for (size_t i = 0; i < std::size(depthFormats); i++)
|
2021-07-08 10:47:00 +00:00
|
|
|
{
|
|
|
|
vk::FormatProperties formatProperties = physicalDevice.getFormatProperties(depthFormats[i]);
|
|
|
|
|
|
|
|
if (formatProperties.linearTilingFeatures & vk::FormatFeatureFlagBits::eDepthStencilAttachment)
|
|
|
|
{
|
|
|
|
tiling = vk::ImageTiling::eLinear;
|
|
|
|
depthFormat = depthFormats[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (depthFormat == vk::Format::eUndefined)
|
|
|
|
die("No supported depth/stencil format found");
|
|
|
|
}
|
|
|
|
NOTICE_LOG(RENDERER, "Using depth format %s tiling %s", vk::to_string(depthFormat).c_str(), vk::to_string(tiling).c_str());
|
|
|
|
|
|
|
|
return depthFormat;
|
|
|
|
}
|
2021-01-09 17:16:39 +00:00
|
|
|
|
2020-05-09 10:07:49 +00:00
|
|
|
#endif // USE_VULKAN
|