mirror of
https://github.com/ZDoom/ZDRay.git
synced 2024-11-10 14:51:40 +00:00
Upgrade to latest version of zvulkan and hook up minAccelerationStructureScratchOffsetAlignment
This commit is contained in:
parent
b44e54743b
commit
c142f11248
16 changed files with 13053 additions and 12660 deletions
|
@ -80,9 +80,16 @@ GPURaytracer::GPURaytracer()
|
||||||
if(!rdoc_api)
|
if(!rdoc_api)
|
||||||
LoadRenderDoc();
|
LoadRenderDoc();
|
||||||
|
|
||||||
auto instance = std::make_shared<VulkanInstance>(VKDebug);
|
auto instance = VulkanInstanceBuilder()
|
||||||
device = std::make_unique<VulkanDevice>(instance, nullptr, VulkanCompatibleDevice::SelectDevice(instance, nullptr, 0));
|
.DebugLayer(VKDebug)
|
||||||
|
.Create();
|
||||||
|
|
||||||
|
device = VulkanDeviceBuilder()
|
||||||
|
.OptionalRayQuery()
|
||||||
|
.Create(instance);
|
||||||
|
|
||||||
useRayQuery = !NoRtx && device->PhysicalDevice.Features.RayQuery.rayQuery;
|
useRayQuery = !NoRtx && device->PhysicalDevice.Features.RayQuery.rayQuery;
|
||||||
|
|
||||||
PrintVulkanInfo();
|
PrintVulkanInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -609,6 +616,7 @@ void GPURaytracer::CreateBottomLevelAccelerationStructure()
|
||||||
blScratchBuffer = BufferBuilder()
|
blScratchBuffer = BufferBuilder()
|
||||||
.Usage(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
|
.Usage(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
|
||||||
.Size(sizeInfo.buildScratchSize)
|
.Size(sizeInfo.buildScratchSize)
|
||||||
|
.MinAlignment(device->PhysicalDevice.Properties.AccelerationStructure.minAccelerationStructureScratchOffsetAlignment)
|
||||||
.DebugName("blScratchBuffer")
|
.DebugName("blScratchBuffer")
|
||||||
.Create(device.get());
|
.Create(device.get());
|
||||||
|
|
||||||
|
@ -691,6 +699,7 @@ void GPURaytracer::CreateTopLevelAccelerationStructure()
|
||||||
tlScratchBuffer = BufferBuilder()
|
tlScratchBuffer = BufferBuilder()
|
||||||
.Usage(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
|
.Usage(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
|
||||||
.Size(sizeInfo.buildScratchSize)
|
.Size(sizeInfo.buildScratchSize)
|
||||||
|
.MinAlignment(device->PhysicalDevice.Properties.AccelerationStructure.minAccelerationStructureScratchOffsetAlignment)
|
||||||
.DebugName("tlScratchBuffer")
|
.DebugName("tlScratchBuffer")
|
||||||
.Create(device.get());
|
.Create(device.get());
|
||||||
|
|
||||||
|
@ -717,17 +726,20 @@ void GPURaytracer::CreateShaders()
|
||||||
traceprefix += "#line 1\r\n";
|
traceprefix += "#line 1\r\n";
|
||||||
|
|
||||||
vertShader = ShaderBuilder()
|
vertShader = ShaderBuilder()
|
||||||
.VertexShader(prefix + glsl_vert)
|
.Type(ShaderType::Vertex)
|
||||||
|
.AddSource("vert.glsl", prefix + glsl_vert)
|
||||||
.DebugName("vertShader")
|
.DebugName("vertShader")
|
||||||
.Create("vertShader", device.get());
|
.Create("vertShader", device.get());
|
||||||
|
|
||||||
fragShader = ShaderBuilder()
|
fragShader = ShaderBuilder()
|
||||||
.FragmentShader(traceprefix + glsl_frag)
|
.Type(ShaderType::Fragment)
|
||||||
|
.AddSource("frag.glsl", traceprefix + glsl_frag)
|
||||||
.DebugName("fragShader")
|
.DebugName("fragShader")
|
||||||
.Create("fragShader", device.get());
|
.Create("fragShader", device.get());
|
||||||
|
|
||||||
fragResolveShader = ShaderBuilder()
|
fragResolveShader = ShaderBuilder()
|
||||||
.FragmentShader(prefix + glsl_frag_resolve)
|
.Type(ShaderType::Fragment)
|
||||||
|
.AddSource("frag_resolve.glsl", prefix + glsl_frag_resolve)
|
||||||
.DebugName("fragResolveShader")
|
.DebugName("fragResolveShader")
|
||||||
.Create("fragResolveShader", device.get());
|
.Create("fragResolveShader", device.get());
|
||||||
}
|
}
|
||||||
|
@ -964,7 +976,7 @@ LightmapImage GPURaytracer::CreateImage(int width, int height)
|
||||||
|
|
||||||
void GPURaytracer::CreateUniformBuffer()
|
void GPURaytracer::CreateUniformBuffer()
|
||||||
{
|
{
|
||||||
VkDeviceSize align = device->PhysicalDevice.Properties.limits.minUniformBufferOffsetAlignment;
|
VkDeviceSize align = device->PhysicalDevice.Properties.Properties.limits.minUniformBufferOffsetAlignment;
|
||||||
uniformStructStride = (sizeof(Uniforms) + align - 1) / align * align;
|
uniformStructStride = (sizeof(Uniforms) + align - 1) / align * align;
|
||||||
|
|
||||||
uniformBuffer = BufferBuilder()
|
uniformBuffer = BufferBuilder()
|
||||||
|
@ -1047,7 +1059,7 @@ std::vector<CollisionNode> GPURaytracer::CreateCollisionNodes()
|
||||||
|
|
||||||
void GPURaytracer::PrintVulkanInfo()
|
void GPURaytracer::PrintVulkanInfo()
|
||||||
{
|
{
|
||||||
const auto& props = device->PhysicalDevice.Properties;
|
const auto& props = device->PhysicalDevice.Properties.Properties;
|
||||||
|
|
||||||
std::string deviceType;
|
std::string deviceType;
|
||||||
switch (props.deviceType)
|
switch (props.deviceType)
|
||||||
|
|
|
@ -154,7 +154,7 @@ private:
|
||||||
int uniformStructs = 256;
|
int uniformStructs = 256;
|
||||||
VkDeviceSize uniformStructStride = sizeof(Uniforms);
|
VkDeviceSize uniformStructStride = sizeof(Uniforms);
|
||||||
|
|
||||||
std::unique_ptr<VulkanDevice> device;
|
std::shared_ptr<VulkanDevice> device;
|
||||||
|
|
||||||
bool useRayQuery = true;
|
bool useRayQuery = true;
|
||||||
|
|
||||||
|
|
3
thirdparty/ZVulkan/CMakeLists.txt
vendored
3
thirdparty/ZVulkan/CMakeLists.txt
vendored
|
@ -3,7 +3,6 @@ project(zvulkan)
|
||||||
|
|
||||||
set(ZVULKAN_SOURCES
|
set(ZVULKAN_SOURCES
|
||||||
src/vulkanbuilders.cpp
|
src/vulkanbuilders.cpp
|
||||||
src/vulkancompatibledevice.cpp
|
|
||||||
src/vulkandevice.cpp
|
src/vulkandevice.cpp
|
||||||
src/vulkaninstance.cpp
|
src/vulkaninstance.cpp
|
||||||
src/vulkansurface.cpp
|
src/vulkansurface.cpp
|
||||||
|
@ -171,8 +170,6 @@ source_group("include" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/z
|
||||||
source_group("include\\vk_mem_alloc" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zvulkan/vk_mem_alloc/.+")
|
source_group("include\\vk_mem_alloc" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zvulkan/vk_mem_alloc/.+")
|
||||||
source_group("include\\volk" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zvulkan/volk/.+")
|
source_group("include\\volk" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/include/zvulkan/volk/.+")
|
||||||
|
|
||||||
source_group("example" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/example/.+")
|
|
||||||
|
|
||||||
include_directories(include include/zvulkan src)
|
include_directories(include include/zvulkan src)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
168
thirdparty/ZVulkan/include/zvulkan/vulkanbuilders.h
vendored
168
thirdparty/ZVulkan/include/zvulkan/vulkanbuilders.h
vendored
|
@ -2,6 +2,117 @@
|
||||||
|
|
||||||
#include "vulkanobjects.h"
|
#include "vulkanobjects.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
class VulkanCompatibleDevice;
|
||||||
|
|
||||||
|
class VulkanInstanceBuilder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VulkanInstanceBuilder();
|
||||||
|
|
||||||
|
VulkanInstanceBuilder& ApiVersionsToTry(const std::vector<uint32_t>& versions);
|
||||||
|
VulkanInstanceBuilder& RequireExtension(const std::string& extensionName);
|
||||||
|
VulkanInstanceBuilder& RequireSurfaceExtensions(bool enable = true);
|
||||||
|
VulkanInstanceBuilder& OptionalExtension(const std::string& extensionName);
|
||||||
|
VulkanInstanceBuilder& DebugLayer(bool enable = true);
|
||||||
|
|
||||||
|
std::shared_ptr<VulkanInstance> Create();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<uint32_t> apiVersionsToTry;
|
||||||
|
std::set<std::string> requiredExtensions;
|
||||||
|
std::set<std::string> optionalExtensions;
|
||||||
|
bool debugLayer = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||||
|
|
||||||
|
class VulkanSurfaceBuilder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VulkanSurfaceBuilder();
|
||||||
|
|
||||||
|
VulkanSurfaceBuilder& Win32Window(HWND handle);
|
||||||
|
|
||||||
|
std::shared_ptr<VulkanSurface> Create(std::shared_ptr<VulkanInstance> instance);
|
||||||
|
|
||||||
|
private:
|
||||||
|
HWND hwnd = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class VulkanDeviceBuilder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VulkanDeviceBuilder();
|
||||||
|
|
||||||
|
VulkanDeviceBuilder& RequireExtension(const std::string& extensionName);
|
||||||
|
VulkanDeviceBuilder& OptionalExtension(const std::string& extensionName);
|
||||||
|
VulkanDeviceBuilder& OptionalRayQuery();
|
||||||
|
VulkanDeviceBuilder& OptionalDescriptorIndexing();
|
||||||
|
VulkanDeviceBuilder& Surface(std::shared_ptr<VulkanSurface> surface);
|
||||||
|
VulkanDeviceBuilder& SelectDevice(int index);
|
||||||
|
|
||||||
|
std::vector<VulkanCompatibleDevice> FindDevices(const std::shared_ptr<VulkanInstance>& instance);
|
||||||
|
std::shared_ptr<VulkanDevice> Create(std::shared_ptr<VulkanInstance> instance);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::set<std::string> requiredDeviceExtensions;
|
||||||
|
std::set<std::string> optionalDeviceExtensions;
|
||||||
|
std::shared_ptr<VulkanSurface> surface;
|
||||||
|
int deviceIndex = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VulkanSwapChainBuilder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VulkanSwapChainBuilder();
|
||||||
|
|
||||||
|
std::shared_ptr<VulkanSwapChain> Create(VulkanDevice* device);
|
||||||
|
};
|
||||||
|
|
||||||
|
class CommandPoolBuilder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CommandPoolBuilder();
|
||||||
|
|
||||||
|
CommandPoolBuilder& QueueFamily(int index);
|
||||||
|
CommandPoolBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
||||||
|
|
||||||
|
std::unique_ptr<VulkanCommandPool> Create(VulkanDevice* device);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* debugName = nullptr;
|
||||||
|
int queueFamilyIndex = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SemaphoreBuilder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SemaphoreBuilder();
|
||||||
|
|
||||||
|
SemaphoreBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
||||||
|
|
||||||
|
std::unique_ptr<VulkanSemaphore> Create(VulkanDevice* device);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* debugName = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FenceBuilder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FenceBuilder();
|
||||||
|
|
||||||
|
FenceBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
||||||
|
|
||||||
|
std::unique_ptr<VulkanFence> Create(VulkanDevice* device);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* debugName = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
class ImageBuilder
|
class ImageBuilder
|
||||||
{
|
{
|
||||||
|
@ -73,6 +184,7 @@ public:
|
||||||
BufferBuilder& Size(size_t size);
|
BufferBuilder& Size(size_t size);
|
||||||
BufferBuilder& Usage(VkBufferUsageFlags bufferUsage, VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_GPU_ONLY, VmaAllocationCreateFlags allocFlags = 0);
|
BufferBuilder& Usage(VkBufferUsageFlags bufferUsage, VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_GPU_ONLY, VmaAllocationCreateFlags allocFlags = 0);
|
||||||
BufferBuilder& MemoryType(VkMemoryPropertyFlags requiredFlags, VkMemoryPropertyFlags preferredFlags, uint32_t memoryTypeBits = 0);
|
BufferBuilder& MemoryType(VkMemoryPropertyFlags requiredFlags, VkMemoryPropertyFlags preferredFlags, uint32_t memoryTypeBits = 0);
|
||||||
|
BufferBuilder& MinAlignment(VkDeviceSize memoryAlignment);
|
||||||
BufferBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
BufferBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
||||||
|
|
||||||
std::unique_ptr<VulkanBuffer> Create(VulkanDevice *device);
|
std::unique_ptr<VulkanBuffer> Create(VulkanDevice *device);
|
||||||
|
@ -81,6 +193,27 @@ private:
|
||||||
VkBufferCreateInfo bufferInfo = {};
|
VkBufferCreateInfo bufferInfo = {};
|
||||||
VmaAllocationCreateInfo allocInfo = {};
|
VmaAllocationCreateInfo allocInfo = {};
|
||||||
const char* debugName = nullptr;
|
const char* debugName = nullptr;
|
||||||
|
VkDeviceSize minAlignment = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ShaderType
|
||||||
|
{
|
||||||
|
Vertex,
|
||||||
|
TessControl,
|
||||||
|
TessEvaluation,
|
||||||
|
Geometry,
|
||||||
|
Fragment,
|
||||||
|
Compute
|
||||||
|
};
|
||||||
|
|
||||||
|
class ShaderIncludeResult
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ShaderIncludeResult(std::string name, std::string text) : name(std::move(name)), text(std::move(text)) { }
|
||||||
|
ShaderIncludeResult(std::string error) : text(std::move(error)) { }
|
||||||
|
|
||||||
|
std::string name; // fully resolved name of the included header file
|
||||||
|
std::string text; // the file contents - or include error message if name is empty
|
||||||
};
|
};
|
||||||
|
|
||||||
class ShaderBuilder
|
class ShaderBuilder
|
||||||
|
@ -91,16 +224,23 @@ public:
|
||||||
static void Init();
|
static void Init();
|
||||||
static void Deinit();
|
static void Deinit();
|
||||||
|
|
||||||
ShaderBuilder& VertexShader(const std::string &code);
|
ShaderBuilder& Type(ShaderType type);
|
||||||
ShaderBuilder& FragmentShader(const std::string&code);
|
ShaderBuilder& AddSource(const std::string& name, const std::string& code);
|
||||||
|
|
||||||
|
ShaderBuilder& OnIncludeSystem(std::function<ShaderIncludeResult(std::string headerName, std::string includerName, size_t inclusionDepth)> onIncludeSystem);
|
||||||
|
ShaderBuilder& OnIncludeLocal(std::function<ShaderIncludeResult(std::string headerName, std::string includerName, size_t inclusionDepth)> onIncludeLocal);
|
||||||
|
|
||||||
ShaderBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
ShaderBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
||||||
|
|
||||||
std::unique_ptr<VulkanShader> Create(const char *shadername, VulkanDevice *device);
|
std::unique_ptr<VulkanShader> Create(const char *shadername, VulkanDevice *device);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string code;
|
std::vector<std::pair<std::string, std::string>> sources;
|
||||||
|
std::function<ShaderIncludeResult(std::string headerName, std::string includerName, size_t inclusionDepth)> onIncludeSystem;
|
||||||
|
std::function<ShaderIncludeResult(std::string headerName, std::string includerName, size_t inclusionDepth)> onIncludeLocal;
|
||||||
int stage = 0;
|
int stage = 0;
|
||||||
const char* debugName = nullptr;
|
const char* debugName = nullptr;
|
||||||
|
friend class ShaderBuilderIncluderImpl;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AccelerationStructureBuilder
|
class AccelerationStructureBuilder
|
||||||
|
@ -125,6 +265,7 @@ class ComputePipelineBuilder
|
||||||
public:
|
public:
|
||||||
ComputePipelineBuilder();
|
ComputePipelineBuilder();
|
||||||
|
|
||||||
|
ComputePipelineBuilder& Cache(VulkanPipelineCache* cache);
|
||||||
ComputePipelineBuilder& Layout(VulkanPipelineLayout *layout);
|
ComputePipelineBuilder& Layout(VulkanPipelineLayout *layout);
|
||||||
ComputePipelineBuilder& ComputeShader(VulkanShader *shader);
|
ComputePipelineBuilder& ComputeShader(VulkanShader *shader);
|
||||||
ComputePipelineBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
ComputePipelineBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
||||||
|
@ -134,6 +275,7 @@ public:
|
||||||
private:
|
private:
|
||||||
VkComputePipelineCreateInfo pipelineInfo = {};
|
VkComputePipelineCreateInfo pipelineInfo = {};
|
||||||
VkPipelineShaderStageCreateInfo stageInfo = {};
|
VkPipelineShaderStageCreateInfo stageInfo = {};
|
||||||
|
VulkanPipelineCache* cache = nullptr;
|
||||||
const char* debugName = nullptr;
|
const char* debugName = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -213,6 +355,7 @@ class GraphicsPipelineBuilder
|
||||||
public:
|
public:
|
||||||
GraphicsPipelineBuilder();
|
GraphicsPipelineBuilder();
|
||||||
|
|
||||||
|
GraphicsPipelineBuilder& Cache(VulkanPipelineCache* cache);
|
||||||
GraphicsPipelineBuilder& Subpass(int subpass);
|
GraphicsPipelineBuilder& Subpass(int subpass);
|
||||||
GraphicsPipelineBuilder& Layout(VulkanPipelineLayout *layout);
|
GraphicsPipelineBuilder& Layout(VulkanPipelineLayout *layout);
|
||||||
GraphicsPipelineBuilder& RenderPass(VulkanRenderPass *renderPass);
|
GraphicsPipelineBuilder& RenderPass(VulkanRenderPass *renderPass);
|
||||||
|
@ -266,6 +409,7 @@ private:
|
||||||
std::vector<VkVertexInputAttributeDescription> vertexInputAttributes;
|
std::vector<VkVertexInputAttributeDescription> vertexInputAttributes;
|
||||||
std::vector<VkDynamicState> dynamicStates;
|
std::vector<VkDynamicState> dynamicStates;
|
||||||
|
|
||||||
|
VulkanPipelineCache* cache = nullptr;
|
||||||
const char* debugName = nullptr;
|
const char* debugName = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -288,6 +432,24 @@ private:
|
||||||
const char* debugName = nullptr;
|
const char* debugName = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PipelineCacheBuilder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PipelineCacheBuilder();
|
||||||
|
|
||||||
|
PipelineCacheBuilder& InitialData(const void* data, size_t size);
|
||||||
|
PipelineCacheBuilder& Flags(VkPipelineCacheCreateFlags flags);
|
||||||
|
|
||||||
|
PipelineCacheBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
||||||
|
|
||||||
|
std::unique_ptr<VulkanPipelineCache> Create(VulkanDevice* device);
|
||||||
|
|
||||||
|
private:
|
||||||
|
VkPipelineCacheCreateInfo pipelineCacheInfo = {};
|
||||||
|
std::vector<uint8_t> initData;
|
||||||
|
const char* debugName = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
class RenderPassBuilder
|
class RenderPassBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -14,9 +14,6 @@ public:
|
||||||
|
|
||||||
bool GraphicsTimeQueries = false;
|
bool GraphicsTimeQueries = false;
|
||||||
|
|
||||||
std::vector<std::string> EnabledDeviceExtensions;
|
std::set<std::string> EnabledDeviceExtensions;
|
||||||
VulkanDeviceFeatures EnabledFeatures;
|
VulkanDeviceFeatures EnabledFeatures;
|
||||||
|
|
||||||
static std::vector<VulkanCompatibleDevice> FindDevices(const std::shared_ptr<VulkanInstance>& instance, const std::shared_ptr<VulkanSurface>& surface);
|
|
||||||
static VulkanCompatibleDevice SelectDevice(const std::shared_ptr<VulkanInstance>& instance, const std::shared_ptr<VulkanSurface>& surface, int vk_device);
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,7 +21,7 @@ public:
|
||||||
VulkanDevice(std::shared_ptr<VulkanInstance> instance, std::shared_ptr<VulkanSurface> surface, const VulkanCompatibleDevice& selectedDevice);
|
VulkanDevice(std::shared_ptr<VulkanInstance> instance, std::shared_ptr<VulkanSurface> surface, const VulkanCompatibleDevice& selectedDevice);
|
||||||
~VulkanDevice();
|
~VulkanDevice();
|
||||||
|
|
||||||
std::vector<std::string> EnabledDeviceExtensions;
|
std::set<std::string> EnabledDeviceExtensions;
|
||||||
VulkanDeviceFeatures EnabledFeatures;
|
VulkanDeviceFeatures EnabledFeatures;
|
||||||
|
|
||||||
VulkanPhysicalDevice PhysicalDevice;
|
VulkanPhysicalDevice PhysicalDevice;
|
||||||
|
@ -39,7 +39,7 @@ public:
|
||||||
int PresentFamily = -1;
|
int PresentFamily = -1;
|
||||||
bool GraphicsTimeQueries = false;
|
bool GraphicsTimeQueries = false;
|
||||||
|
|
||||||
bool SupportsDeviceExtension(const char* ext) const;
|
bool SupportsExtension(const char* ext) const;
|
||||||
|
|
||||||
void SetObjectName(const char* name, uint64_t handle, VkObjectType type);
|
void SetObjectName(const char* name, uint64_t handle, VkObjectType type);
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,6 @@
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
#define VK_USE_PLATFORM_MACOS_MVK
|
#define VK_USE_PLATFORM_MACOS_MVK
|
||||||
#define VK_USE_PLATFORM_METAL_EXT
|
#define VK_USE_PLATFORM_METAL_EXT
|
||||||
#else
|
|
||||||
#define VK_USE_PLATFORM_XLIB_KHR
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "volk/volk.h"
|
#include "volk/volk.h"
|
||||||
|
@ -21,6 +19,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
class VulkanDeviceFeatures
|
class VulkanDeviceFeatures
|
||||||
{
|
{
|
||||||
|
@ -32,47 +31,41 @@ public:
|
||||||
VkPhysicalDeviceDescriptorIndexingFeatures DescriptorIndexing = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT };
|
VkPhysicalDeviceDescriptorIndexingFeatures DescriptorIndexing = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class VulkanDeviceProperties
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VkPhysicalDeviceProperties Properties = {};
|
||||||
|
VkPhysicalDeviceMemoryProperties Memory = {};
|
||||||
|
VkPhysicalDeviceAccelerationStructurePropertiesKHR AccelerationStructure = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR };
|
||||||
|
VkPhysicalDeviceDescriptorIndexingProperties DescriptorIndexing = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT };
|
||||||
|
};
|
||||||
|
|
||||||
class VulkanPhysicalDevice
|
class VulkanPhysicalDevice
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VkPhysicalDevice Device = VK_NULL_HANDLE;
|
VkPhysicalDevice Device = VK_NULL_HANDLE;
|
||||||
std::vector<VkExtensionProperties> Extensions;
|
std::vector<VkExtensionProperties> Extensions;
|
||||||
std::vector<VkQueueFamilyProperties> QueueFamilies;
|
std::vector<VkQueueFamilyProperties> QueueFamilies;
|
||||||
VkPhysicalDeviceProperties Properties = {};
|
VulkanDeviceProperties Properties;
|
||||||
VkPhysicalDeviceMemoryProperties MemoryProperties = {};
|
|
||||||
VulkanDeviceFeatures Features;
|
VulkanDeviceFeatures Features;
|
||||||
};
|
};
|
||||||
|
|
||||||
class VulkanInstance
|
class VulkanInstance
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VulkanInstance(bool wantDebugLayer);
|
VulkanInstance(std::vector<uint32_t> apiVersionsToTry, std::set<std::string> requiredExtensions, std::set<std::string> optionalExtensions, bool wantDebugLayer);
|
||||||
~VulkanInstance();
|
~VulkanInstance();
|
||||||
|
|
||||||
std::vector<const char*> RequiredExtensions =
|
std::vector<uint32_t> ApiVersionsToTry;
|
||||||
{
|
|
||||||
VK_KHR_SURFACE_EXTENSION_NAME,
|
std::set<std::string> RequiredExtensions;
|
||||||
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
std::set<std::string> OptionalExtensions;
|
||||||
VK_KHR_WIN32_SURFACE_EXTENSION_NAME
|
|
||||||
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
|
||||||
VK_MVK_MACOS_SURFACE_EXTENSION_NAME
|
|
||||||
#elif defined(VK_USE_PLATFORM_XLIB_KHR)
|
|
||||||
VK_KHR_XLIB_SURFACE_EXTENSION_NAME
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
std::vector<const char*> OptionalExtensions =
|
|
||||||
{
|
|
||||||
VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME,
|
|
||||||
VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME,
|
|
||||||
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME
|
|
||||||
};
|
|
||||||
std::vector<uint32_t> ApiVersionsToTry = { VK_API_VERSION_1_2, VK_API_VERSION_1_1, VK_API_VERSION_1_0 };
|
|
||||||
|
|
||||||
std::vector<VkLayerProperties> AvailableLayers;
|
std::vector<VkLayerProperties> AvailableLayers;
|
||||||
std::vector<VkExtensionProperties> AvailableExtensions;
|
std::vector<VkExtensionProperties> AvailableExtensions;
|
||||||
|
|
||||||
std::vector<const char*> EnabledValidationLayers;
|
std::set<std::string> EnabledValidationLayers;
|
||||||
std::vector<const char*> EnabledExtensions;
|
std::set<std::string> EnabledExtensions;
|
||||||
|
|
||||||
std::vector<VulkanPhysicalDevice> PhysicalDevices;
|
std::vector<VulkanPhysicalDevice> PhysicalDevices;
|
||||||
|
|
||||||
|
|
|
@ -305,6 +305,24 @@ private:
|
||||||
VulkanPipelineLayout &operator=(const VulkanPipelineLayout &) = delete;
|
VulkanPipelineLayout &operator=(const VulkanPipelineLayout &) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class VulkanPipelineCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VulkanPipelineCache(VulkanDevice* device, VkPipelineCache cache);
|
||||||
|
~VulkanPipelineCache();
|
||||||
|
|
||||||
|
void SetDebugName(const char* name) { device->SetObjectName(name, (uint64_t)cache, VK_OBJECT_TYPE_PIPELINE_CACHE); }
|
||||||
|
|
||||||
|
std::vector<uint8_t> GetCacheData();
|
||||||
|
|
||||||
|
VulkanDevice* device;
|
||||||
|
VkPipelineCache cache;
|
||||||
|
|
||||||
|
private:
|
||||||
|
VulkanPipelineCache(const VulkanPipelineCache&) = delete;
|
||||||
|
VulkanPipelineCache& operator=(const VulkanPipelineCache&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
class VulkanRenderPass
|
class VulkanRenderPass
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -1105,7 +1123,8 @@ inline VulkanImage::VulkanImage(VulkanDevice *device, VkImage image, VmaAllocati
|
||||||
|
|
||||||
inline VulkanImage::~VulkanImage()
|
inline VulkanImage::~VulkanImage()
|
||||||
{
|
{
|
||||||
vmaDestroyImage(device->allocator, image, allocation);
|
if (allocation)
|
||||||
|
vmaDestroyImage(device->allocator, image, allocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void *VulkanImage::Map(size_t offset, size_t size)
|
inline void *VulkanImage::Map(size_t offset, size_t size)
|
||||||
|
@ -1178,6 +1197,33 @@ inline VulkanPipelineLayout::~VulkanPipelineLayout()
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline VulkanPipelineCache::VulkanPipelineCache(VulkanDevice* device, VkPipelineCache cache) : device(device), cache(cache)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VulkanPipelineCache::~VulkanPipelineCache()
|
||||||
|
{
|
||||||
|
vkDestroyPipelineCache(device->device, cache, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::vector<uint8_t> VulkanPipelineCache::GetCacheData()
|
||||||
|
{
|
||||||
|
size_t dataSize = 0;
|
||||||
|
VkResult result = vkGetPipelineCacheData(device->device, cache, &dataSize, nullptr);
|
||||||
|
CheckVulkanError(result, "Could not get cache data size");
|
||||||
|
|
||||||
|
std::vector<uint8_t> buffer;
|
||||||
|
buffer.resize(dataSize);
|
||||||
|
result = vkGetPipelineCacheData(device->device, cache, &dataSize, buffer.data());
|
||||||
|
if (result == VK_INCOMPLETE)
|
||||||
|
VulkanError("Could not get cache data (incomplete)");
|
||||||
|
CheckVulkanError(result, "Could not get cache data");
|
||||||
|
buffer.resize(dataSize);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
inline VulkanRenderPass::VulkanRenderPass(VulkanDevice *device, VkRenderPass renderPass) : device(device), renderPass(renderPass)
|
inline VulkanRenderPass::VulkanRenderPass(VulkanDevice *device, VkRenderPass renderPass) : device(device), renderPass(renderPass)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,45 +2,19 @@
|
||||||
|
|
||||||
#include "vulkaninstance.h"
|
#include "vulkaninstance.h"
|
||||||
|
|
||||||
|
class VulkanSurface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VulkanSurface(std::shared_ptr<VulkanInstance> instance, VkSurfaceKHR surface);
|
||||||
|
~VulkanSurface();
|
||||||
|
|
||||||
|
std::shared_ptr<VulkanInstance> Instance;
|
||||||
|
VkSurfaceKHR Surface = VK_NULL_HANDLE;
|
||||||
|
|
||||||
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||||
|
|
||||||
class VulkanSurface
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VulkanSurface(std::shared_ptr<VulkanInstance> instance, HWND window);
|
VulkanSurface(std::shared_ptr<VulkanInstance> instance, HWND window);
|
||||||
~VulkanSurface();
|
|
||||||
|
|
||||||
std::shared_ptr<VulkanInstance> Instance;
|
|
||||||
VkSurfaceKHR Surface = VK_NULL_HANDLE;
|
|
||||||
HWND Window = 0;
|
HWND Window = 0;
|
||||||
};
|
|
||||||
|
|
||||||
#elif defined(VK_USE_PLATFORM_XLIB_KHR)
|
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
|
|
||||||
class VulkanSurface
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VulkanSurface(std::shared_ptr<VulkanInstance> instance, Display* disp, Window wind);
|
|
||||||
~VulkanSurface();
|
|
||||||
|
|
||||||
std::shared_ptr<VulkanInstance> Instance;
|
|
||||||
VkSurfaceKHR Surface = VK_NULL_HANDLE;
|
|
||||||
Display* disp = nullptr;
|
|
||||||
Window wind;
|
|
||||||
};
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
class VulkanSurface
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VulkanSurface(std::shared_ptr<VulkanInstance> instance);
|
|
||||||
~VulkanSurface();
|
|
||||||
|
|
||||||
std::shared_ptr<VulkanInstance> Instance;
|
|
||||||
VkSurfaceKHR Surface = VK_NULL_HANDLE;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
};
|
||||||
|
|
|
@ -1,50 +1,61 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "vulkandevice.h"
|
#include "vulkandevice.h"
|
||||||
|
#include "vulkanobjects.h"
|
||||||
|
|
||||||
class VulkanSemaphore;
|
class VulkanSemaphore;
|
||||||
class VulkanFence;
|
class VulkanFence;
|
||||||
|
|
||||||
|
class VulkanSurfaceCapabilities
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VkSurfaceCapabilitiesKHR Capabilites = { };
|
||||||
|
#ifdef WIN32
|
||||||
|
VkSurfaceCapabilitiesFullScreenExclusiveEXT FullScreenExclusive = { VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT };
|
||||||
|
#else
|
||||||
|
struct { void* pNext = nullptr; VkBool32 fullScreenExclusiveSupported = 0; } FullScreenExclusive;
|
||||||
|
#endif
|
||||||
|
std::vector<VkPresentModeKHR> PresentModes;
|
||||||
|
std::vector<VkSurfaceFormatKHR> Formats;
|
||||||
|
};
|
||||||
|
|
||||||
class VulkanSwapChain
|
class VulkanSwapChain
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VulkanSwapChain(VulkanDevice *device, bool vsync);
|
VulkanSwapChain(VulkanDevice* device);
|
||||||
~VulkanSwapChain();
|
~VulkanSwapChain();
|
||||||
|
|
||||||
uint32_t acquireImage(int width, int height, bool exclusivefullscreen, VulkanSemaphore *semaphore = nullptr, VulkanFence *fence = nullptr);
|
void Create(int width, int height, int imageCount, bool vsync, bool hdr, bool exclusivefullscreen);
|
||||||
void queuePresent(uint32_t imageIndex, VulkanSemaphore *semaphore = nullptr);
|
bool Lost() const { return lost; }
|
||||||
|
|
||||||
bool vsync;
|
int Width() const { return actualExtent.width; }
|
||||||
VkSwapchainKHR swapChain = VK_NULL_HANDLE;
|
int Height() const { return actualExtent.height; }
|
||||||
VkSurfaceFormatKHR swapChainFormat;
|
VkSurfaceFormatKHR Format() const { return format; }
|
||||||
VkPresentModeKHR swapChainPresentMode;
|
|
||||||
|
|
||||||
std::vector<VkImage> swapChainImages;
|
int ImageCount() const { return (int)images.size(); }
|
||||||
std::vector<VkImageView> swapChainImageViews;
|
VulkanImage* GetImage(int index) { return images[index].get(); }
|
||||||
|
VulkanImageView* GetImageView(int index) { return views[index].get(); }
|
||||||
|
|
||||||
VkExtent2D actualExtent;
|
int AcquireImage(VulkanSemaphore* semaphore = nullptr, VulkanFence* fence = nullptr);
|
||||||
|
void QueuePresent(int imageIndex, VulkanSemaphore* semaphore = nullptr);
|
||||||
bool newSwapChain = true;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void selectFormat();
|
void SelectFormat(const VulkanSurfaceCapabilities& caps, bool hdr);
|
||||||
void selectPresentMode(bool fullscreen);
|
|
||||||
bool createSwapChain(int width, int height, bool fullscreen, VkSwapchainKHR oldSwapChain = VK_NULL_HANDLE);
|
|
||||||
void createViews();
|
|
||||||
void getImages();
|
|
||||||
void releaseResources();
|
|
||||||
void releaseViews();
|
|
||||||
void recreate(int width, int height, bool fullscreen);
|
|
||||||
|
|
||||||
std::vector<VkSurfaceFormatKHR> getSurfaceFormats();
|
bool CreateSwapchain(int width, int height, int imageCount, bool vsync, bool hdr, bool exclusivefullscreen);
|
||||||
std::vector<VkPresentModeKHR> getPresentModes(bool exclusivefullscreen);
|
|
||||||
|
|
||||||
VulkanDevice *device = nullptr;
|
VulkanSurfaceCapabilities GetSurfaceCapabilities(bool exclusivefullscreen);
|
||||||
|
|
||||||
int lastSwapWidth = 0;
|
VulkanDevice* device = nullptr;
|
||||||
int lastSwapHeight = 0;
|
bool lost = true;
|
||||||
bool lastFullscreen = false;
|
|
||||||
|
|
||||||
VulkanSwapChain(const VulkanSwapChain &) = delete;
|
VkExtent2D actualExtent = {};
|
||||||
VulkanSwapChain &operator=(const VulkanSwapChain &) = delete;
|
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
|
||||||
|
VkSurfaceFormatKHR format = {};
|
||||||
|
VkPresentModeKHR presentMode;
|
||||||
|
std::vector<std::unique_ptr<VulkanImage>> images;
|
||||||
|
std::vector<std::unique_ptr<VulkanImageView>> views;
|
||||||
|
|
||||||
|
VulkanSwapChain(const VulkanSwapChain&) = delete;
|
||||||
|
VulkanSwapChain& operator=(const VulkanSwapChain&) = delete;
|
||||||
};
|
};
|
||||||
|
|
541
thirdparty/ZVulkan/src/vulkanbuilders.cpp
vendored
541
thirdparty/ZVulkan/src/vulkanbuilders.cpp
vendored
|
@ -1,5 +1,8 @@
|
||||||
|
|
||||||
#include "vulkanbuilders.h"
|
#include "vulkanbuilders.h"
|
||||||
|
#include "vulkansurface.h"
|
||||||
|
#include "vulkancompatibledevice.h"
|
||||||
|
#include "vulkanswapchain.h"
|
||||||
#include "glslang/glslang/Public/ShaderLang.h"
|
#include "glslang/glslang/Public/ShaderLang.h"
|
||||||
#include "glslang/spirv/GlslangToSpv.h"
|
#include "glslang/spirv/GlslangToSpv.h"
|
||||||
|
|
||||||
|
@ -125,29 +128,143 @@ ShaderBuilder::ShaderBuilder()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderBuilder& ShaderBuilder::VertexShader(const std::string& c)
|
ShaderBuilder& ShaderBuilder::Type(ShaderType type)
|
||||||
{
|
{
|
||||||
code = c;
|
switch (type)
|
||||||
stage = EShLanguage::EShLangVertex;
|
{
|
||||||
|
case ShaderType::Vertex: stage = EShLanguage::EShLangVertex; break;
|
||||||
|
case ShaderType::TessControl: stage = EShLanguage::EShLangTessControl; break;
|
||||||
|
case ShaderType::TessEvaluation: stage = EShLanguage::EShLangTessEvaluation; break;
|
||||||
|
case ShaderType::Geometry: stage = EShLanguage::EShLangGeometry; break;
|
||||||
|
case ShaderType::Fragment: stage = EShLanguage::EShLangFragment; break;
|
||||||
|
case ShaderType::Compute: stage = EShLanguage::EShLangCompute; break;
|
||||||
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderBuilder& ShaderBuilder::FragmentShader(const std::string& c)
|
ShaderBuilder& ShaderBuilder::AddSource(const std::string& name, const std::string& code)
|
||||||
{
|
{
|
||||||
code = c;
|
sources.push_back({ name, code });
|
||||||
stage = EShLanguage::EShLangFragment;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShaderBuilder& ShaderBuilder::OnIncludeSystem(std::function<ShaderIncludeResult(std::string headerName, std::string includerName, size_t inclusionDepth)> onIncludeSystem)
|
||||||
|
{
|
||||||
|
this->onIncludeSystem = std::move(onIncludeSystem);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderBuilder& ShaderBuilder::OnIncludeLocal(std::function<ShaderIncludeResult(std::string headerName, std::string includerName, size_t inclusionDepth)> onIncludeLocal)
|
||||||
|
{
|
||||||
|
this->onIncludeLocal = std::move(onIncludeLocal);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ShaderBuilderIncluderImpl : public glslang::TShader::Includer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ShaderBuilderIncluderImpl(ShaderBuilder* shaderBuilder) : shaderBuilder(shaderBuilder)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
IncludeResult* includeSystem(const char* headerName, const char* includerName, size_t inclusionDepth) override
|
||||||
|
{
|
||||||
|
if (!shaderBuilder->onIncludeSystem)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::unique_ptr<ShaderIncludeResult> result;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = std::make_unique<ShaderIncludeResult>(shaderBuilder->onIncludeSystem(headerName, includerName, inclusionDepth));
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
result = std::make_unique<ShaderIncludeResult>(e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result || (result->name.empty() && result->text.empty()))
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
IncludeResult* outer = new IncludeResult(result->name, result->text.data(), result->text.size(), result.get());
|
||||||
|
result.release();
|
||||||
|
return outer;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IncludeResult* includeLocal(const char* headerName, const char* includerName, size_t inclusionDepth) override
|
||||||
|
{
|
||||||
|
if (!shaderBuilder->onIncludeLocal)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::unique_ptr<ShaderIncludeResult> result;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = std::make_unique<ShaderIncludeResult>(shaderBuilder->onIncludeLocal(headerName, includerName, inclusionDepth));
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
result = std::make_unique<ShaderIncludeResult>(e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result || (result->name.empty() && result->text.empty()))
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
IncludeResult* outer = new IncludeResult(result->name, result->text.data(), result->text.size(), result.get());
|
||||||
|
result.release();
|
||||||
|
return outer;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void releaseInclude(IncludeResult* result) override
|
||||||
|
{
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
delete (ShaderIncludeResult*)result->userData;
|
||||||
|
delete result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ShaderBuilder* shaderBuilder = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
std::unique_ptr<VulkanShader> ShaderBuilder::Create(const char *shadername, VulkanDevice *device)
|
std::unique_ptr<VulkanShader> ShaderBuilder::Create(const char *shadername, VulkanDevice *device)
|
||||||
{
|
{
|
||||||
EShLanguage stage = (EShLanguage)this->stage;
|
EShLanguage stage = (EShLanguage)this->stage;
|
||||||
const char *sources[] = { code.c_str() };
|
|
||||||
|
std::vector<const char*> namesC, sourcesC;
|
||||||
|
std::vector<int> lengthsC;
|
||||||
|
for (const auto& s : sources)
|
||||||
|
{
|
||||||
|
namesC.push_back(s.first.c_str());
|
||||||
|
sourcesC.push_back(s.second.c_str());
|
||||||
|
lengthsC.push_back((int)s.second.size());
|
||||||
|
}
|
||||||
|
|
||||||
TBuiltInResource resources = DefaultTBuiltInResource;
|
TBuiltInResource resources = DefaultTBuiltInResource;
|
||||||
|
|
||||||
glslang::TShader shader(stage);
|
glslang::TShader shader(stage);
|
||||||
shader.setStrings(sources, 1);
|
shader.setStringsWithLengthsAndNames(sourcesC.data(), lengthsC.data(), namesC.data(), (int)sources.size());
|
||||||
shader.setEnvInput(glslang::EShSourceGlsl, stage, glslang::EShClientVulkan, 100);
|
shader.setEnvInput(glslang::EShSourceGlsl, stage, glslang::EShClientVulkan, 100);
|
||||||
if (device->Instance->ApiVersion >= VK_API_VERSION_1_2)
|
if (device->Instance->ApiVersion >= VK_API_VERSION_1_2)
|
||||||
{
|
{
|
||||||
|
@ -159,7 +276,9 @@ std::unique_ptr<VulkanShader> ShaderBuilder::Create(const char *shadername, Vulk
|
||||||
shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_0);
|
shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_0);
|
||||||
shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_0);
|
shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_0);
|
||||||
}
|
}
|
||||||
bool compileSuccess = shader.parse(&resources, 110, false, EShMsgVulkanRules);
|
|
||||||
|
ShaderBuilderIncluderImpl includer(this);
|
||||||
|
bool compileSuccess = shader.parse(&resources, 110, false, EShMsgVulkanRules, includer);
|
||||||
if (!compileSuccess)
|
if (!compileSuccess)
|
||||||
{
|
{
|
||||||
throw std::runtime_error(std::string("Shader compile failed: ") + shader.getInfoLog());
|
throw std::runtime_error(std::string("Shader compile failed: ") + shader.getInfoLog());
|
||||||
|
@ -206,6 +325,54 @@ std::unique_ptr<VulkanShader> ShaderBuilder::Create(const char *shadername, Vulk
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
CommandPoolBuilder::CommandPoolBuilder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandPoolBuilder& CommandPoolBuilder::QueueFamily(int index)
|
||||||
|
{
|
||||||
|
queueFamilyIndex = index;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<VulkanCommandPool> CommandPoolBuilder::Create(VulkanDevice* device)
|
||||||
|
{
|
||||||
|
auto obj = std::make_unique<VulkanCommandPool>(device, queueFamilyIndex != -1 ? queueFamilyIndex : device->GraphicsFamily);
|
||||||
|
if (debugName)
|
||||||
|
obj->SetDebugName(debugName);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
SemaphoreBuilder::SemaphoreBuilder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<VulkanSemaphore> SemaphoreBuilder::Create(VulkanDevice* device)
|
||||||
|
{
|
||||||
|
auto obj = std::make_unique<VulkanSemaphore>(device);
|
||||||
|
if (debugName)
|
||||||
|
obj->SetDebugName(debugName);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
FenceBuilder::FenceBuilder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<VulkanFence> FenceBuilder::Create(VulkanDevice* device)
|
||||||
|
{
|
||||||
|
auto obj = std::make_unique<VulkanFence>(device);
|
||||||
|
if (debugName)
|
||||||
|
obj->SetDebugName(debugName);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ImageBuilder::ImageBuilder()
|
ImageBuilder::ImageBuilder()
|
||||||
{
|
{
|
||||||
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||||
|
@ -476,13 +643,27 @@ BufferBuilder& BufferBuilder::MemoryType(VkMemoryPropertyFlags requiredFlags, Vk
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BufferBuilder& BufferBuilder::MinAlignment(VkDeviceSize memoryAlignment)
|
||||||
|
{
|
||||||
|
minAlignment = memoryAlignment;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<VulkanBuffer> BufferBuilder::Create(VulkanDevice* device)
|
std::unique_ptr<VulkanBuffer> BufferBuilder::Create(VulkanDevice* device)
|
||||||
{
|
{
|
||||||
VkBuffer buffer;
|
VkBuffer buffer;
|
||||||
VmaAllocation allocation;
|
VmaAllocation allocation;
|
||||||
|
|
||||||
VkResult result = vmaCreateBuffer(device->allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr);
|
if (minAlignment == 0)
|
||||||
CheckVulkanError(result, "Could not allocate memory for vulkan buffer");
|
{
|
||||||
|
VkResult result = vmaCreateBuffer(device->allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr);
|
||||||
|
CheckVulkanError(result, "Could not allocate memory for vulkan buffer");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VkResult result = vmaCreateBufferWithAlignment(device->allocator, &bufferInfo, &allocInfo, minAlignment, &buffer, &allocation, nullptr);
|
||||||
|
CheckVulkanError(result, "Could not allocate memory for vulkan buffer");
|
||||||
|
}
|
||||||
|
|
||||||
auto obj = std::make_unique<VulkanBuffer>(device, buffer, allocation, bufferInfo.size);
|
auto obj = std::make_unique<VulkanBuffer>(device, buffer, allocation, bufferInfo.size);
|
||||||
if (debugName)
|
if (debugName)
|
||||||
|
@ -538,6 +719,12 @@ ComputePipelineBuilder::ComputePipelineBuilder()
|
||||||
stageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
stageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ComputePipelineBuilder& ComputePipelineBuilder::Cache(VulkanPipelineCache* cache)
|
||||||
|
{
|
||||||
|
this->cache = cache;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
ComputePipelineBuilder& ComputePipelineBuilder::Layout(VulkanPipelineLayout* layout)
|
ComputePipelineBuilder& ComputePipelineBuilder::Layout(VulkanPipelineLayout* layout)
|
||||||
{
|
{
|
||||||
pipelineInfo.layout = layout->layout;
|
pipelineInfo.layout = layout->layout;
|
||||||
|
@ -557,7 +744,7 @@ ComputePipelineBuilder& ComputePipelineBuilder::ComputeShader(VulkanShader* shad
|
||||||
std::unique_ptr<VulkanPipeline> ComputePipelineBuilder::Create(VulkanDevice* device)
|
std::unique_ptr<VulkanPipeline> ComputePipelineBuilder::Create(VulkanDevice* device)
|
||||||
{
|
{
|
||||||
VkPipeline pipeline;
|
VkPipeline pipeline;
|
||||||
vkCreateComputePipelines(device->device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline);
|
vkCreateComputePipelines(device->device, cache ? cache->cache : VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline);
|
||||||
auto obj = std::make_unique<VulkanPipeline>(device, pipeline);
|
auto obj = std::make_unique<VulkanPipeline>(device, pipeline);
|
||||||
if (debugName)
|
if (debugName)
|
||||||
obj->SetDebugName(debugName);
|
obj->SetDebugName(debugName);
|
||||||
|
@ -758,6 +945,10 @@ GraphicsPipelineBuilder::GraphicsPipelineBuilder()
|
||||||
inputAssembly.primitiveRestartEnable = VK_FALSE;
|
inputAssembly.primitiveRestartEnable = VK_FALSE;
|
||||||
|
|
||||||
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||||
|
viewportState.viewportCount = 1;
|
||||||
|
viewportState.pViewports = &viewport;
|
||||||
|
viewportState.scissorCount = 1;
|
||||||
|
viewportState.pScissors = &scissor;
|
||||||
|
|
||||||
depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||||
depthStencil.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
|
depthStencil.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
|
||||||
|
@ -816,6 +1007,12 @@ GraphicsPipelineBuilder& GraphicsPipelineBuilder::RasterizationSamples(VkSampleC
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GraphicsPipelineBuilder& GraphicsPipelineBuilder::Cache(VulkanPipelineCache* cache)
|
||||||
|
{
|
||||||
|
this->cache = cache;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
GraphicsPipelineBuilder& GraphicsPipelineBuilder::Subpass(int subpass)
|
GraphicsPipelineBuilder& GraphicsPipelineBuilder::Subpass(int subpass)
|
||||||
{
|
{
|
||||||
pipelineInfo.subpass = subpass;
|
pipelineInfo.subpass = subpass;
|
||||||
|
@ -848,9 +1045,6 @@ GraphicsPipelineBuilder& GraphicsPipelineBuilder::Viewport(float x, float y, flo
|
||||||
viewport.height = height;
|
viewport.height = height;
|
||||||
viewport.minDepth = minDepth;
|
viewport.minDepth = minDepth;
|
||||||
viewport.maxDepth = maxDepth;
|
viewport.maxDepth = maxDepth;
|
||||||
|
|
||||||
viewportState.viewportCount = 1;
|
|
||||||
viewportState.pViewports = &viewport;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -860,9 +1054,6 @@ GraphicsPipelineBuilder& GraphicsPipelineBuilder::Scissor(int x, int y, int widt
|
||||||
scissor.offset.y = y;
|
scissor.offset.y = y;
|
||||||
scissor.extent.width = width;
|
scissor.extent.width = width;
|
||||||
scissor.extent.height = height;
|
scissor.extent.height = height;
|
||||||
|
|
||||||
viewportState.scissorCount = 1;
|
|
||||||
viewportState.pScissors = &scissor;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1038,7 +1229,7 @@ GraphicsPipelineBuilder& GraphicsPipelineBuilder::AddDynamicState(VkDynamicState
|
||||||
std::unique_ptr<VulkanPipeline> GraphicsPipelineBuilder::Create(VulkanDevice* device)
|
std::unique_ptr<VulkanPipeline> GraphicsPipelineBuilder::Create(VulkanDevice* device)
|
||||||
{
|
{
|
||||||
VkPipeline pipeline = 0;
|
VkPipeline pipeline = 0;
|
||||||
VkResult result = vkCreateGraphicsPipelines(device->device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline);
|
VkResult result = vkCreateGraphicsPipelines(device->device, cache ? cache->cache : VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline);
|
||||||
CheckVulkanError(result, "Could not create graphics pipeline");
|
CheckVulkanError(result, "Could not create graphics pipeline");
|
||||||
auto obj = std::make_unique<VulkanPipeline>(device, pipeline);
|
auto obj = std::make_unique<VulkanPipeline>(device, pipeline);
|
||||||
if (debugName)
|
if (debugName)
|
||||||
|
@ -1086,6 +1277,54 @@ std::unique_ptr<VulkanPipelineLayout> PipelineLayoutBuilder::Create(VulkanDevice
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
PipelineCacheBuilder::PipelineCacheBuilder()
|
||||||
|
{
|
||||||
|
pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
|
||||||
|
}
|
||||||
|
|
||||||
|
PipelineCacheBuilder& PipelineCacheBuilder::InitialData(const void* data, size_t size)
|
||||||
|
{
|
||||||
|
initData.resize(size);
|
||||||
|
memcpy(initData.data(), data, size);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PipelineCacheBuilder& PipelineCacheBuilder::Flags(VkPipelineCacheCreateFlags flags)
|
||||||
|
{
|
||||||
|
pipelineCacheInfo.flags = flags;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<VulkanPipelineCache> PipelineCacheBuilder::Create(VulkanDevice* device)
|
||||||
|
{
|
||||||
|
pipelineCacheInfo.pInitialData = nullptr;
|
||||||
|
pipelineCacheInfo.initialDataSize = 0;
|
||||||
|
|
||||||
|
// Check if the saved cache data is compatible with our device:
|
||||||
|
if (initData.size() >= sizeof(VkPipelineCacheHeaderVersionOne))
|
||||||
|
{
|
||||||
|
VkPipelineCacheHeaderVersionOne* header = (VkPipelineCacheHeaderVersionOne*)initData.data();
|
||||||
|
if (header->headerVersion == VK_PIPELINE_CACHE_HEADER_VERSION_ONE &&
|
||||||
|
header->vendorID == device->PhysicalDevice.Properties.Properties.vendorID &&
|
||||||
|
header->deviceID == device->PhysicalDevice.Properties.Properties.deviceID &&
|
||||||
|
memcmp(header->pipelineCacheUUID, device->PhysicalDevice.Properties.Properties.pipelineCacheUUID, VK_UUID_SIZE) == 0)
|
||||||
|
{
|
||||||
|
pipelineCacheInfo.pInitialData = initData.data();
|
||||||
|
pipelineCacheInfo.initialDataSize = initData.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipelineCache pipelineCache;
|
||||||
|
VkResult result = vkCreatePipelineCache(device->device, &pipelineCacheInfo, nullptr, &pipelineCache);
|
||||||
|
CheckVulkanError(result, "Could not create pipeline cache");
|
||||||
|
auto obj = std::make_unique<VulkanPipelineCache>(device, pipelineCache);
|
||||||
|
if (debugName)
|
||||||
|
obj->SetDebugName(debugName);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
RenderPassBuilder::RenderPassBuilder()
|
RenderPassBuilder::RenderPassBuilder()
|
||||||
{
|
{
|
||||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||||
|
@ -1433,3 +1672,267 @@ void WriteDescriptors::Execute(VulkanDevice* device)
|
||||||
if (!writes.empty())
|
if (!writes.empty())
|
||||||
vkUpdateDescriptorSets(device->device, (uint32_t)writes.size(), writes.data(), 0, nullptr);
|
vkUpdateDescriptorSets(device->device, (uint32_t)writes.size(), writes.data(), 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
VulkanInstanceBuilder::VulkanInstanceBuilder()
|
||||||
|
{
|
||||||
|
apiVersionsToTry = { VK_API_VERSION_1_2, VK_API_VERSION_1_1, VK_API_VERSION_1_0 };
|
||||||
|
|
||||||
|
OptionalExtension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME);
|
||||||
|
OptionalExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanInstanceBuilder& VulkanInstanceBuilder::ApiVersionsToTry(const std::vector<uint32_t>& versions)
|
||||||
|
{
|
||||||
|
apiVersionsToTry = versions;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanInstanceBuilder& VulkanInstanceBuilder::RequireExtension(const std::string& extensionName)
|
||||||
|
{
|
||||||
|
requiredExtensions.insert(extensionName);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanInstanceBuilder& VulkanInstanceBuilder::RequireSurfaceExtensions(bool enable)
|
||||||
|
{
|
||||||
|
if (enable)
|
||||||
|
{
|
||||||
|
RequireExtension(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
|
|
||||||
|
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
||||||
|
RequireExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
|
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
||||||
|
RequireExtension(VK_MVK_MACOS_SURFACE_EXTENSION_NAME);
|
||||||
|
#elif defined(VK_USE_PLATFORM_XLIB_KHR)
|
||||||
|
RequireExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
OptionalExtension(VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME); // For HDR support
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanInstanceBuilder& VulkanInstanceBuilder::OptionalExtension(const std::string& extensionName)
|
||||||
|
{
|
||||||
|
optionalExtensions.insert(extensionName);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanInstanceBuilder& VulkanInstanceBuilder::DebugLayer(bool enable)
|
||||||
|
{
|
||||||
|
debugLayer = enable;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<VulkanInstance> VulkanInstanceBuilder::Create()
|
||||||
|
{
|
||||||
|
return std::make_shared<VulkanInstance>(apiVersionsToTry, requiredExtensions, optionalExtensions, debugLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||||
|
|
||||||
|
VulkanSurfaceBuilder::VulkanSurfaceBuilder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanSurfaceBuilder& VulkanSurfaceBuilder::Win32Window(HWND hwnd)
|
||||||
|
{
|
||||||
|
this->hwnd = hwnd;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<VulkanSurface> VulkanSurfaceBuilder::Create(std::shared_ptr<VulkanInstance> instance)
|
||||||
|
{
|
||||||
|
return std::make_shared<VulkanSurface>(std::move(instance), hwnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
VulkanDeviceBuilder::VulkanDeviceBuilder()
|
||||||
|
{
|
||||||
|
OptionalExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
|
||||||
|
OptionalExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanDeviceBuilder& VulkanDeviceBuilder::RequireExtension(const std::string& extensionName)
|
||||||
|
{
|
||||||
|
requiredDeviceExtensions.insert(extensionName);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanDeviceBuilder& VulkanDeviceBuilder::OptionalExtension(const std::string& extensionName)
|
||||||
|
{
|
||||||
|
optionalDeviceExtensions.insert(extensionName);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanDeviceBuilder& VulkanDeviceBuilder::OptionalRayQuery()
|
||||||
|
{
|
||||||
|
OptionalExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
|
||||||
|
OptionalExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
|
||||||
|
OptionalExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||||
|
OptionalExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanDeviceBuilder& VulkanDeviceBuilder::OptionalDescriptorIndexing()
|
||||||
|
{
|
||||||
|
OptionalExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanDeviceBuilder& VulkanDeviceBuilder::Surface(std::shared_ptr<VulkanSurface> surface)
|
||||||
|
{
|
||||||
|
if (surface)
|
||||||
|
{
|
||||||
|
RequireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||||
|
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
||||||
|
OptionalExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
this->surface = std::move(surface);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanDeviceBuilder& VulkanDeviceBuilder::SelectDevice(int index)
|
||||||
|
{
|
||||||
|
deviceIndex = index;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<VulkanCompatibleDevice> VulkanDeviceBuilder::FindDevices(const std::shared_ptr<VulkanInstance>& instance)
|
||||||
|
{
|
||||||
|
std::vector<VulkanCompatibleDevice> supportedDevices;
|
||||||
|
|
||||||
|
for (size_t idx = 0; idx < instance->PhysicalDevices.size(); idx++)
|
||||||
|
{
|
||||||
|
const auto& info = instance->PhysicalDevices[idx];
|
||||||
|
|
||||||
|
// Check if all required extensions are there
|
||||||
|
std::set<std::string> requiredExtensionSearch = requiredDeviceExtensions;
|
||||||
|
for (const auto& ext : info.Extensions)
|
||||||
|
requiredExtensionSearch.erase(ext.extensionName);
|
||||||
|
if (!requiredExtensionSearch.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Check if all required features are there
|
||||||
|
if (info.Features.Features.samplerAnisotropy != VK_TRUE ||
|
||||||
|
info.Features.Features.fragmentStoresAndAtomics != VK_TRUE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
VulkanCompatibleDevice dev;
|
||||||
|
dev.Device = &instance->PhysicalDevices[idx];
|
||||||
|
dev.EnabledDeviceExtensions = requiredDeviceExtensions;
|
||||||
|
|
||||||
|
// Enable optional extensions we are interested in, if they are available on this device
|
||||||
|
for (const auto& ext : dev.Device->Extensions)
|
||||||
|
{
|
||||||
|
if (optionalDeviceExtensions.find(ext.extensionName) != optionalDeviceExtensions.end())
|
||||||
|
{
|
||||||
|
dev.EnabledDeviceExtensions.insert(ext.extensionName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable optional features we are interested in, if they are available on this device
|
||||||
|
auto& enabledFeatures = dev.EnabledFeatures;
|
||||||
|
auto& deviceFeatures = dev.Device->Features;
|
||||||
|
enabledFeatures.Features.samplerAnisotropy = deviceFeatures.Features.samplerAnisotropy;
|
||||||
|
enabledFeatures.Features.fragmentStoresAndAtomics = deviceFeatures.Features.fragmentStoresAndAtomics;
|
||||||
|
enabledFeatures.Features.depthClamp = deviceFeatures.Features.depthClamp;
|
||||||
|
enabledFeatures.Features.shaderClipDistance = deviceFeatures.Features.shaderClipDistance;
|
||||||
|
enabledFeatures.BufferDeviceAddress.bufferDeviceAddress = deviceFeatures.BufferDeviceAddress.bufferDeviceAddress;
|
||||||
|
enabledFeatures.AccelerationStructure.accelerationStructure = deviceFeatures.AccelerationStructure.accelerationStructure;
|
||||||
|
enabledFeatures.RayQuery.rayQuery = deviceFeatures.RayQuery.rayQuery;
|
||||||
|
enabledFeatures.DescriptorIndexing.runtimeDescriptorArray = deviceFeatures.DescriptorIndexing.runtimeDescriptorArray;
|
||||||
|
enabledFeatures.DescriptorIndexing.descriptorBindingPartiallyBound = deviceFeatures.DescriptorIndexing.descriptorBindingPartiallyBound;
|
||||||
|
enabledFeatures.DescriptorIndexing.descriptorBindingSampledImageUpdateAfterBind = deviceFeatures.DescriptorIndexing.descriptorBindingSampledImageUpdateAfterBind;
|
||||||
|
enabledFeatures.DescriptorIndexing.descriptorBindingVariableDescriptorCount = deviceFeatures.DescriptorIndexing.descriptorBindingVariableDescriptorCount;
|
||||||
|
|
||||||
|
// Figure out which queue can present
|
||||||
|
if (surface)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < (int)info.QueueFamilies.size(); i++)
|
||||||
|
{
|
||||||
|
VkBool32 presentSupport = false;
|
||||||
|
VkResult result = vkGetPhysicalDeviceSurfaceSupportKHR(info.Device, i, surface->Surface, &presentSupport);
|
||||||
|
if (result == VK_SUCCESS && info.QueueFamilies[i].queueCount > 0 && presentSupport)
|
||||||
|
{
|
||||||
|
dev.PresentFamily = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The vulkan spec states that graphics and compute queues can always do transfer.
|
||||||
|
// Furthermore the spec states that graphics queues always can do compute.
|
||||||
|
// Last, the spec makes it OPTIONAL whether the VK_QUEUE_TRANSFER_BIT is set for such queues, but they MUST support transfer.
|
||||||
|
//
|
||||||
|
// In short: pick the first graphics queue family for everything.
|
||||||
|
for (int i = 0; i < (int)info.QueueFamilies.size(); i++)
|
||||||
|
{
|
||||||
|
const auto& queueFamily = info.QueueFamilies[i];
|
||||||
|
if (queueFamily.queueCount > 0 && (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT))
|
||||||
|
{
|
||||||
|
dev.GraphicsFamily = i;
|
||||||
|
dev.GraphicsTimeQueries = queueFamily.timestampValidBits != 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only use device if we found the required graphics and present queues
|
||||||
|
if (dev.GraphicsFamily != -1 && (!surface || dev.PresentFamily != -1))
|
||||||
|
{
|
||||||
|
supportedDevices.push_back(dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The device order returned by Vulkan can be anything. Prefer discrete > integrated > virtual gpu > cpu > other
|
||||||
|
auto sortFunc = [&](const auto& a, const auto b)
|
||||||
|
{
|
||||||
|
// Sort by GPU type first. This will ensure the "best" device is most likely to map to vk_device 0
|
||||||
|
static const int typeSort[] = { 4, 1, 0, 2, 3 };
|
||||||
|
int sortA = a.Device->Properties.Properties.deviceType < 5 ? typeSort[a.Device->Properties.Properties.deviceType] : (int)a.Device->Properties.Properties.deviceType;
|
||||||
|
int sortB = b.Device->Properties.Properties.deviceType < 5 ? typeSort[b.Device->Properties.Properties.deviceType] : (int)b.Device->Properties.Properties.deviceType;
|
||||||
|
if (sortA != sortB)
|
||||||
|
return sortA < sortB;
|
||||||
|
|
||||||
|
// Then sort by the device's unique ID so that vk_device uses a consistent order
|
||||||
|
int sortUUID = memcmp(a.Device->Properties.Properties.pipelineCacheUUID, b.Device->Properties.Properties.pipelineCacheUUID, VK_UUID_SIZE);
|
||||||
|
return sortUUID < 0;
|
||||||
|
};
|
||||||
|
std::stable_sort(supportedDevices.begin(), supportedDevices.end(), sortFunc);
|
||||||
|
|
||||||
|
return supportedDevices;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<VulkanDevice> VulkanDeviceBuilder::Create(std::shared_ptr<VulkanInstance> instance)
|
||||||
|
{
|
||||||
|
if (instance->PhysicalDevices.empty())
|
||||||
|
VulkanError("No Vulkan devices found. The graphics card may have no vulkan support or the driver may be too old.");
|
||||||
|
|
||||||
|
std::vector<VulkanCompatibleDevice> supportedDevices = FindDevices(instance);
|
||||||
|
if (supportedDevices.empty())
|
||||||
|
VulkanError("No Vulkan device found supports the minimum requirements of this application");
|
||||||
|
|
||||||
|
size_t selected = deviceIndex;
|
||||||
|
if (selected >= supportedDevices.size())
|
||||||
|
selected = 0;
|
||||||
|
return std::make_shared<VulkanDevice>(instance, surface, supportedDevices[selected]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
VulkanSwapChainBuilder::VulkanSwapChainBuilder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<VulkanSwapChain> VulkanSwapChainBuilder::Create(VulkanDevice* device)
|
||||||
|
{
|
||||||
|
return std::make_shared<VulkanSwapChain>(device);
|
||||||
|
}
|
||||||
|
|
20
thirdparty/ZVulkan/src/vulkandevice.cpp
vendored
20
thirdparty/ZVulkan/src/vulkandevice.cpp
vendored
|
@ -33,18 +33,20 @@ VulkanDevice::~VulkanDevice()
|
||||||
ReleaseResources();
|
ReleaseResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VulkanDevice::SupportsDeviceExtension(const char* ext) const
|
bool VulkanDevice::SupportsExtension(const char* ext) const
|
||||||
{
|
{
|
||||||
return std::find(EnabledDeviceExtensions.begin(), EnabledDeviceExtensions.end(), ext) != EnabledDeviceExtensions.end();
|
return
|
||||||
|
EnabledDeviceExtensions.find(ext) != EnabledDeviceExtensions.end() ||
|
||||||
|
Instance->EnabledExtensions.find(ext) != Instance->EnabledExtensions.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDevice::CreateAllocator()
|
void VulkanDevice::CreateAllocator()
|
||||||
{
|
{
|
||||||
VmaAllocatorCreateInfo allocinfo = {};
|
VmaAllocatorCreateInfo allocinfo = {};
|
||||||
allocinfo.vulkanApiVersion = Instance->ApiVersion;
|
allocinfo.vulkanApiVersion = Instance->ApiVersion;
|
||||||
if (SupportsDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) && SupportsDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME))
|
if (SupportsExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) && SupportsExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME))
|
||||||
allocinfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
|
allocinfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
|
||||||
if (SupportsDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME))
|
if (SupportsExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME))
|
||||||
allocinfo.flags |= VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
|
allocinfo.flags |= VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
|
||||||
allocinfo.physicalDevice = PhysicalDevice.Device;
|
allocinfo.physicalDevice = PhysicalDevice.Device;
|
||||||
allocinfo.device = device;
|
allocinfo.device = device;
|
||||||
|
@ -91,7 +93,7 @@ void VulkanDevice::CreateDevice()
|
||||||
deviceFeatures2.features = EnabledFeatures.Features;
|
deviceFeatures2.features = EnabledFeatures.Features;
|
||||||
|
|
||||||
void** next = const_cast<void**>(&deviceCreateInfo.pNext);
|
void** next = const_cast<void**>(&deviceCreateInfo.pNext);
|
||||||
if (SupportsDeviceExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME))
|
if (SupportsExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME))
|
||||||
{
|
{
|
||||||
*next = &deviceFeatures2;
|
*next = &deviceFeatures2;
|
||||||
next = &deviceFeatures2.pNext;
|
next = &deviceFeatures2.pNext;
|
||||||
|
@ -101,22 +103,22 @@ void VulkanDevice::CreateDevice()
|
||||||
deviceCreateInfo.pEnabledFeatures = &deviceFeatures2.features;
|
deviceCreateInfo.pEnabledFeatures = &deviceFeatures2.features;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SupportsDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME))
|
if (SupportsExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME))
|
||||||
{
|
{
|
||||||
*next = &EnabledFeatures.BufferDeviceAddress;
|
*next = &EnabledFeatures.BufferDeviceAddress;
|
||||||
next = &EnabledFeatures.BufferDeviceAddress.pNext;
|
next = &EnabledFeatures.BufferDeviceAddress.pNext;
|
||||||
}
|
}
|
||||||
if (SupportsDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME))
|
if (SupportsExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME))
|
||||||
{
|
{
|
||||||
*next = &EnabledFeatures.AccelerationStructure;
|
*next = &EnabledFeatures.AccelerationStructure;
|
||||||
next = &EnabledFeatures.AccelerationStructure.pNext;
|
next = &EnabledFeatures.AccelerationStructure.pNext;
|
||||||
}
|
}
|
||||||
if (SupportsDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME))
|
if (SupportsExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME))
|
||||||
{
|
{
|
||||||
*next = &EnabledFeatures.RayQuery;
|
*next = &EnabledFeatures.RayQuery;
|
||||||
next = &EnabledFeatures.RayQuery.pNext;
|
next = &EnabledFeatures.RayQuery.pNext;
|
||||||
}
|
}
|
||||||
if (SupportsDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME))
|
if (SupportsExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME))
|
||||||
{
|
{
|
||||||
*next = &EnabledFeatures.DescriptorIndexing;
|
*next = &EnabledFeatures.DescriptorIndexing;
|
||||||
next = &EnabledFeatures.DescriptorIndexing.pNext;
|
next = &EnabledFeatures.DescriptorIndexing.pNext;
|
||||||
|
|
55
thirdparty/ZVulkan/src/vulkaninstance.cpp
vendored
55
thirdparty/ZVulkan/src/vulkaninstance.cpp
vendored
|
@ -6,7 +6,8 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
VulkanInstance::VulkanInstance(bool wantDebugLayer) : WantDebugLayer(wantDebugLayer)
|
VulkanInstance::VulkanInstance(std::vector<uint32_t> apiVersionsToTry, std::set<std::string> requiredExtensions, std::set<std::string> optionalExtensions, bool wantDebugLayer)
|
||||||
|
: ApiVersionsToTry(std::move(apiVersionsToTry)), RequiredExtensions(std::move(requiredExtensions)), OptionalExtensions(std::move(optionalExtensions)), WantDebugLayer(wantDebugLayer)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -64,8 +65,8 @@ void VulkanInstance::CreateInstance()
|
||||||
{
|
{
|
||||||
if (layer.layerName == debugLayer)
|
if (layer.layerName == debugLayer)
|
||||||
{
|
{
|
||||||
EnabledValidationLayers.push_back(layer.layerName);
|
EnabledValidationLayers.insert(layer.layerName);
|
||||||
EnabledExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
EnabledExtensions.insert(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
debugLayerFound = true;
|
debugLayerFound = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -75,15 +76,20 @@ void VulkanInstance::CreateInstance()
|
||||||
// Enable optional instance extensions we are interested in
|
// Enable optional instance extensions we are interested in
|
||||||
for (const auto& ext : AvailableExtensions)
|
for (const auto& ext : AvailableExtensions)
|
||||||
{
|
{
|
||||||
for (const auto& opt : OptionalExtensions)
|
if (OptionalExtensions.find(ext.extensionName) != OptionalExtensions.end())
|
||||||
{
|
{
|
||||||
if (strcmp(ext.extensionName, opt) == 0)
|
EnabledExtensions.insert(ext.extensionName);
|
||||||
{
|
|
||||||
EnabledExtensions.push_back(opt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<const char*> enabledValidationLayersCStr;
|
||||||
|
for (const std::string& layer : EnabledValidationLayers)
|
||||||
|
enabledValidationLayersCStr.push_back(layer.c_str());
|
||||||
|
|
||||||
|
std::vector<const char*> enabledExtensionsCStr;
|
||||||
|
for (const std::string& ext : EnabledExtensions)
|
||||||
|
enabledExtensionsCStr.push_back(ext.c_str());
|
||||||
|
|
||||||
// Try get the highest vulkan version we can get
|
// Try get the highest vulkan version we can get
|
||||||
VkResult result = VK_ERROR_INITIALIZATION_FAILED;
|
VkResult result = VK_ERROR_INITIALIZATION_FAILED;
|
||||||
for (uint32_t apiVersion : ApiVersionsToTry)
|
for (uint32_t apiVersion : ApiVersionsToTry)
|
||||||
|
@ -100,9 +106,9 @@ void VulkanInstance::CreateInstance()
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||||
createInfo.pApplicationInfo = &appInfo;
|
createInfo.pApplicationInfo = &appInfo;
|
||||||
createInfo.enabledExtensionCount = (uint32_t)EnabledExtensions.size();
|
createInfo.enabledExtensionCount = (uint32_t)EnabledExtensions.size();
|
||||||
createInfo.enabledLayerCount = (uint32_t)EnabledValidationLayers.size();
|
createInfo.enabledLayerCount = (uint32_t)enabledValidationLayersCStr.size();
|
||||||
createInfo.ppEnabledLayerNames = EnabledValidationLayers.data();
|
createInfo.ppEnabledLayerNames = enabledValidationLayersCStr.data();
|
||||||
createInfo.ppEnabledExtensionNames = EnabledExtensions.data();
|
createInfo.ppEnabledExtensionNames = enabledExtensionsCStr.data();
|
||||||
|
|
||||||
result = vkCreateInstance(&createInfo, nullptr, &Instance);
|
result = vkCreateInstance(&createInfo, nullptr, &Instance);
|
||||||
if (result >= VK_SUCCESS)
|
if (result >= VK_SUCCESS)
|
||||||
|
@ -157,9 +163,6 @@ std::vector<VulkanPhysicalDevice> VulkanInstance::GetPhysicalDevices(VkInstance
|
||||||
auto& dev = devinfo[i];
|
auto& dev = devinfo[i];
|
||||||
dev.Device = devices[i];
|
dev.Device = devices[i];
|
||||||
|
|
||||||
vkGetPhysicalDeviceMemoryProperties(dev.Device, &dev.MemoryProperties);
|
|
||||||
vkGetPhysicalDeviceProperties(dev.Device, &dev.Properties);
|
|
||||||
|
|
||||||
uint32_t queueFamilyCount = 0;
|
uint32_t queueFamilyCount = 0;
|
||||||
vkGetPhysicalDeviceQueueFamilyProperties(dev.Device, &queueFamilyCount, nullptr);
|
vkGetPhysicalDeviceQueueFamilyProperties(dev.Device, &queueFamilyCount, nullptr);
|
||||||
dev.QueueFamilies.resize(queueFamilyCount);
|
dev.QueueFamilies.resize(queueFamilyCount);
|
||||||
|
@ -180,11 +183,32 @@ std::vector<VulkanPhysicalDevice> VulkanInstance::GetPhysicalDevices(VkInstance
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
vkGetPhysicalDeviceMemoryProperties(dev.Device, &dev.Properties.Memory);
|
||||||
|
|
||||||
if (apiVersion != VK_API_VERSION_1_0)
|
if (apiVersion != VK_API_VERSION_1_0)
|
||||||
{
|
{
|
||||||
|
VkPhysicalDeviceProperties2 deviceProperties2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 };
|
||||||
|
|
||||||
|
void** next = const_cast<void**>(&deviceProperties2.pNext);
|
||||||
|
if (checkForExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME))
|
||||||
|
{
|
||||||
|
*next = &dev.Properties.AccelerationStructure;
|
||||||
|
next = &dev.Properties.AccelerationStructure.pNext;
|
||||||
|
}
|
||||||
|
if (checkForExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME))
|
||||||
|
{
|
||||||
|
*next = &dev.Properties.DescriptorIndexing;
|
||||||
|
next = &dev.Properties.DescriptorIndexing.pNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
vkGetPhysicalDeviceProperties2(dev.Device, &deviceProperties2);
|
||||||
|
dev.Properties.Properties = deviceProperties2.properties;
|
||||||
|
dev.Properties.AccelerationStructure.pNext = nullptr;
|
||||||
|
dev.Properties.DescriptorIndexing.pNext = nullptr;
|
||||||
|
|
||||||
VkPhysicalDeviceFeatures2 deviceFeatures2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
|
VkPhysicalDeviceFeatures2 deviceFeatures2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
|
||||||
|
|
||||||
void** next = const_cast<void**>(&deviceFeatures2.pNext);
|
next = const_cast<void**>(&deviceFeatures2.pNext);
|
||||||
if (checkForExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME))
|
if (checkForExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME))
|
||||||
{
|
{
|
||||||
*next = &dev.Features.BufferDeviceAddress;
|
*next = &dev.Features.BufferDeviceAddress;
|
||||||
|
@ -215,6 +239,7 @@ std::vector<VulkanPhysicalDevice> VulkanInstance::GetPhysicalDevices(VkInstance
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
vkGetPhysicalDeviceProperties(dev.Device, &dev.Properties.Properties);
|
||||||
vkGetPhysicalDeviceFeatures(dev.Device, &dev.Features.Features);
|
vkGetPhysicalDeviceFeatures(dev.Device, &dev.Features.Features);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
44
thirdparty/ZVulkan/src/vulkansurface.cpp
vendored
44
thirdparty/ZVulkan/src/vulkansurface.cpp
vendored
|
@ -2,6 +2,15 @@
|
||||||
#include "vulkansurface.h"
|
#include "vulkansurface.h"
|
||||||
#include "vulkaninstance.h"
|
#include "vulkaninstance.h"
|
||||||
|
|
||||||
|
VulkanSurface::VulkanSurface(std::shared_ptr<VulkanInstance> instance, VkSurfaceKHR surface) : Instance(std::move(instance)), Surface(surface)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanSurface::~VulkanSurface()
|
||||||
|
{
|
||||||
|
vkDestroySurfaceKHR(Instance->Instance, Surface, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||||
|
|
||||||
VulkanSurface::VulkanSurface(std::shared_ptr<VulkanInstance> instance, HWND window) : Instance(std::move(instance)), Window(window)
|
VulkanSurface::VulkanSurface(std::shared_ptr<VulkanInstance> instance, HWND window) : Instance(std::move(instance)), Window(window)
|
||||||
|
@ -15,39 +24,4 @@ VulkanSurface::VulkanSurface(std::shared_ptr<VulkanInstance> instance, HWND wind
|
||||||
VulkanError("Could not create vulkan surface");
|
VulkanError("Could not create vulkan surface");
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanSurface::~VulkanSurface()
|
|
||||||
{
|
|
||||||
vkDestroySurfaceKHR(Instance->Instance, Surface, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(VK_USE_PLATFORM_XLIB_KHR)
|
|
||||||
|
|
||||||
VulkanSurface::VulkanSurface(std::shared_ptr<VulkanInstance> instance, Display* disp, Window wind) : Instance(std::move(instance)), disp(disp), wind(wind)
|
|
||||||
{
|
|
||||||
VkXlibSurfaceCreateInfoKHR createInfo = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR };
|
|
||||||
createInfo.dpy = disp;
|
|
||||||
createInfo.window = wind;
|
|
||||||
|
|
||||||
VkResult result = vkCreateXlibSurfaceKHR(Instance->Instance, &createInfo, nullptr, &Surface);
|
|
||||||
if (result != VK_SUCCESS)
|
|
||||||
VulkanError("Could not create vulkan surface");
|
|
||||||
}
|
|
||||||
|
|
||||||
VulkanSurface::~VulkanSurface()
|
|
||||||
{
|
|
||||||
vkDestroySurfaceKHR(Instance->Instance, Surface, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
VulkanSurface::VulkanSurface(std::shared_ptr<VulkanInstance> instance) : Instance(std::move(instance))
|
|
||||||
{
|
|
||||||
VulkanError("VulkanSurface not implemented on this platform");
|
|
||||||
}
|
|
||||||
|
|
||||||
VulkanSurface::~VulkanSurface()
|
|
||||||
{
|
|
||||||
vkDestroySurfaceKHR(Instance->Instance, Surface, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
605
thirdparty/ZVulkan/src/vulkanswapchain.cpp
vendored
605
thirdparty/ZVulkan/src/vulkanswapchain.cpp
vendored
|
@ -2,205 +2,163 @@
|
||||||
#include "vulkanswapchain.h"
|
#include "vulkanswapchain.h"
|
||||||
#include "vulkanobjects.h"
|
#include "vulkanobjects.h"
|
||||||
#include "vulkansurface.h"
|
#include "vulkansurface.h"
|
||||||
|
#include "vulkanbuilders.h"
|
||||||
|
|
||||||
VulkanSwapChain::VulkanSwapChain(VulkanDevice *device, bool vsync) : vsync(vsync), device(device)
|
VulkanSwapChain::VulkanSwapChain(VulkanDevice* device) : device(device)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanSwapChain::~VulkanSwapChain()
|
VulkanSwapChain::~VulkanSwapChain()
|
||||||
{
|
{
|
||||||
releaseResources();
|
views.clear();
|
||||||
|
images.clear();
|
||||||
|
if (swapchain)
|
||||||
|
vkDestroySwapchainKHR(device->device, swapchain, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t VulkanSwapChain::acquireImage(int width, int height, bool fullscreen, VulkanSemaphore *semaphore, VulkanFence *fence)
|
void VulkanSwapChain::Create(int width, int height, int imageCount, bool vsync, bool hdr, bool exclusivefullscreen)
|
||||||
{
|
{
|
||||||
if (width <= 0 || height <= 0)
|
views.clear();
|
||||||
return 0xffffffff;
|
images.clear();
|
||||||
|
|
||||||
if (lastSwapWidth != width || lastSwapHeight != height || !swapChain || lastFullscreen != fullscreen)
|
CreateSwapchain(width, height, imageCount, vsync, hdr, exclusivefullscreen);
|
||||||
|
|
||||||
|
if (exclusivefullscreen && lost)
|
||||||
{
|
{
|
||||||
recreate(width, height, fullscreen);
|
// We could not acquire exclusive fullscreen. Fall back to normal fullsceen instead.
|
||||||
lastSwapWidth = width;
|
CreateSwapchain(width, height, imageCount, vsync, hdr, false);
|
||||||
lastSwapHeight = height;
|
|
||||||
lastFullscreen = fullscreen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t imageIndex;
|
if (swapchain)
|
||||||
while (true)
|
|
||||||
{
|
{
|
||||||
if (!swapChain)
|
uint32_t imageCount;
|
||||||
{
|
VkResult result = vkGetSwapchainImagesKHR(device->device, swapchain, &imageCount, nullptr);
|
||||||
imageIndex = 0xffffffff;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkResult result = vkAcquireNextImageKHR(device->device, swapChain, 1'000'000'000, semaphore ? semaphore->semaphore : VK_NULL_HANDLE, fence ? fence->fence : VK_NULL_HANDLE, &imageIndex);
|
|
||||||
if (result == VK_SUCCESS)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (result == VK_SUBOPTIMAL_KHR)
|
|
||||||
{
|
|
||||||
lastSwapWidth = 0;
|
|
||||||
lastSwapHeight = 0;
|
|
||||||
lastFullscreen = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (result == VK_ERROR_OUT_OF_DATE_KHR)
|
|
||||||
{
|
|
||||||
recreate(width, height, fullscreen);
|
|
||||||
}
|
|
||||||
else if (result == VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT)
|
|
||||||
{
|
|
||||||
#ifdef WIN32
|
|
||||||
if (GetForegroundWindow() == device->Surface->Window)
|
|
||||||
{
|
|
||||||
vkAcquireFullScreenExclusiveModeEXT(device->device, swapChain);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
imageIndex = 0xffffffff;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (result == VK_NOT_READY || result == VK_TIMEOUT)
|
|
||||||
{
|
|
||||||
imageIndex = 0xffffffff;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw std::runtime_error("Failed to acquire next image!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return imageIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanSwapChain::queuePresent(uint32_t imageIndex, VulkanSemaphore *semaphore)
|
|
||||||
{
|
|
||||||
VkPresentInfoKHR presentInfo = {};
|
|
||||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
|
||||||
presentInfo.waitSemaphoreCount = semaphore ? 1 : 0;
|
|
||||||
presentInfo.pWaitSemaphores = semaphore ? &semaphore->semaphore : VK_NULL_HANDLE;
|
|
||||||
presentInfo.swapchainCount = 1;
|
|
||||||
presentInfo.pSwapchains = &swapChain;
|
|
||||||
presentInfo.pImageIndices = &imageIndex;
|
|
||||||
presentInfo.pResults = nullptr;
|
|
||||||
VkResult result = vkQueuePresentKHR(device->PresentQueue, &presentInfo);
|
|
||||||
if (result == VK_SUBOPTIMAL_KHR || result == VK_ERROR_OUT_OF_DATE_KHR)
|
|
||||||
{
|
|
||||||
lastSwapWidth = 0;
|
|
||||||
lastSwapHeight = 0;
|
|
||||||
lastFullscreen = false;
|
|
||||||
}
|
|
||||||
else if (result == VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT)
|
|
||||||
{
|
|
||||||
#ifdef WIN32
|
|
||||||
if (GetForegroundWindow() == device->Surface->Window)
|
|
||||||
{
|
|
||||||
vkAcquireFullScreenExclusiveModeEXT(device->device, swapChain);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else if (result == VK_ERROR_OUT_OF_HOST_MEMORY || result == VK_ERROR_OUT_OF_DEVICE_MEMORY)
|
|
||||||
{
|
|
||||||
// The spec says we can recover from this.
|
|
||||||
// However, if we are out of memory it is better to crash now than in some other weird place further away from the source of the problem.
|
|
||||||
|
|
||||||
throw std::runtime_error("vkQueuePresentKHR failed: out of memory");
|
|
||||||
}
|
|
||||||
else if (result == VK_ERROR_DEVICE_LOST)
|
|
||||||
{
|
|
||||||
throw std::runtime_error("vkQueuePresentKHR failed: device lost");
|
|
||||||
}
|
|
||||||
else if (result == VK_ERROR_SURFACE_LOST_KHR)
|
|
||||||
{
|
|
||||||
throw std::runtime_error("vkQueuePresentKHR failed: surface lost");
|
|
||||||
}
|
|
||||||
else if (result != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
throw std::runtime_error("vkQueuePresentKHR failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanSwapChain::recreate(int width, int height, bool fullscreen)
|
|
||||||
{
|
|
||||||
newSwapChain = true;
|
|
||||||
|
|
||||||
releaseViews();
|
|
||||||
swapChainImages.clear();
|
|
||||||
|
|
||||||
selectFormat();
|
|
||||||
selectPresentMode(fullscreen);
|
|
||||||
|
|
||||||
VkSwapchainKHR oldSwapChain = swapChain;
|
|
||||||
createSwapChain(width, height, fullscreen, oldSwapChain);
|
|
||||||
if (oldSwapChain)
|
|
||||||
vkDestroySwapchainKHR(device->device, oldSwapChain, nullptr);
|
|
||||||
|
|
||||||
if (swapChain)
|
|
||||||
{
|
|
||||||
getImages();
|
|
||||||
createViews();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VulkanSwapChain::createSwapChain(int width, int height, bool fullscreen, VkSwapchainKHR oldSwapChain)
|
|
||||||
{
|
|
||||||
VkSurfaceCapabilitiesKHR surfaceCapabilities;
|
|
||||||
#ifdef WIN32
|
|
||||||
bool exclusivefullscreen = false;
|
|
||||||
if (fullscreen && device->SupportsDeviceExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME))
|
|
||||||
{
|
|
||||||
VkPhysicalDeviceSurfaceInfo2KHR info = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR };
|
|
||||||
VkSurfaceFullScreenExclusiveInfoEXT exclusiveInfo = { VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT };
|
|
||||||
VkSurfaceFullScreenExclusiveWin32InfoEXT exclusiveWin32Info = { VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT };
|
|
||||||
info.surface = device->Surface->Surface;
|
|
||||||
info.pNext = &exclusiveInfo;
|
|
||||||
exclusiveInfo.fullScreenExclusive = VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT;
|
|
||||||
exclusiveInfo.pNext = &exclusiveWin32Info;
|
|
||||||
exclusiveWin32Info.hmonitor = MonitorFromWindow(device->Surface->Window, MONITOR_DEFAULTTONEAREST);
|
|
||||||
|
|
||||||
VkSurfaceCapabilities2KHR capabilites = { VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR };
|
|
||||||
VkSurfaceCapabilitiesFullScreenExclusiveEXT exclusiveCapabilities = { VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT };
|
|
||||||
capabilites.pNext = &exclusiveCapabilities;
|
|
||||||
|
|
||||||
VkResult result = vkGetPhysicalDeviceSurfaceCapabilities2KHR(device->PhysicalDevice.Device, &info, &capabilites);
|
|
||||||
if (result != VK_SUCCESS)
|
if (result != VK_SUCCESS)
|
||||||
throw std::runtime_error("vkGetPhysicalDeviceSurfaceCapabilities2EXT failed");
|
throw std::runtime_error("vkGetSwapchainImagesKHR failed");
|
||||||
|
|
||||||
surfaceCapabilities = capabilites.surfaceCapabilities;
|
std::vector<VkImage> swapchainImages;
|
||||||
exclusivefullscreen = exclusiveCapabilities.fullScreenExclusiveSupported == VK_TRUE;
|
swapchainImages.resize(imageCount);
|
||||||
|
result = vkGetSwapchainImagesKHR(device->device, swapchain, &imageCount, swapchainImages.data());
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("vkGetSwapchainImagesKHR failed (2)");
|
||||||
|
|
||||||
exclusivefullscreen = false; // Force it off for now since it doesn't work when vsync is false for some reason
|
for (VkImage vkimage : swapchainImages)
|
||||||
|
{
|
||||||
|
auto image = std::make_unique<VulkanImage>(device, vkimage, nullptr, actualExtent.width, actualExtent.height, 1, 1);
|
||||||
|
auto view = ImageViewBuilder()
|
||||||
|
.Type(VK_IMAGE_VIEW_TYPE_2D)
|
||||||
|
.Image(image.get(), format.format)
|
||||||
|
.DebugName("SwapchainImageView")
|
||||||
|
.Create(device);
|
||||||
|
images.push_back(std::move(image));
|
||||||
|
views.push_back(std::move(view));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanSwapChain::SelectFormat(const VulkanSurfaceCapabilities& caps, bool hdr)
|
||||||
|
{
|
||||||
|
if (caps.Formats.size() == 1 && caps.Formats.front().format == VK_FORMAT_UNDEFINED)
|
||||||
|
{
|
||||||
|
format.format = VK_FORMAT_B8G8R8A8_UNORM;
|
||||||
|
format.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr)
|
||||||
|
{
|
||||||
|
for (const auto& f : caps.Formats)
|
||||||
|
{
|
||||||
|
if (f.format == VK_FORMAT_R16G16B16A16_SFLOAT && f.colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT)
|
||||||
|
{
|
||||||
|
format = f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& f : caps.Formats)
|
||||||
|
{
|
||||||
|
if (f.format == VK_FORMAT_B8G8R8A8_UNORM && f.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||||
|
{
|
||||||
|
format = f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
format = caps.Formats.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VulkanSwapChain::CreateSwapchain(int width, int height, int imageCount, bool vsync, bool hdr, bool exclusivefullscreen)
|
||||||
|
{
|
||||||
|
lost = false;
|
||||||
|
|
||||||
|
VulkanSurfaceCapabilities caps = GetSurfaceCapabilities(exclusivefullscreen);
|
||||||
|
|
||||||
|
if (exclusivefullscreen && (caps.PresentModes.empty() || !caps.FullScreenExclusive.fullScreenExclusiveSupported))
|
||||||
|
{
|
||||||
|
// Try again without exclusive full screen.
|
||||||
|
exclusivefullscreen = false;
|
||||||
|
caps = GetSurfaceCapabilities(exclusivefullscreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (caps.PresentModes.empty())
|
||||||
|
throw std::runtime_error("No surface present modes supported");
|
||||||
|
|
||||||
|
bool supportsFifoRelaxed = std::find(caps.PresentModes.begin(), caps.PresentModes.end(), VK_PRESENT_MODE_FIFO_RELAXED_KHR) != caps.PresentModes.end();
|
||||||
|
bool supportsMailbox = std::find(caps.PresentModes.begin(), caps.PresentModes.end(), VK_PRESENT_MODE_MAILBOX_KHR) != caps.PresentModes.end();
|
||||||
|
bool supportsImmediate = std::find(caps.PresentModes.begin(), caps.PresentModes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR) != caps.PresentModes.end();
|
||||||
|
|
||||||
|
presentMode = VK_PRESENT_MODE_FIFO_KHR;
|
||||||
|
if (vsync)
|
||||||
|
{
|
||||||
|
if (supportsFifoRelaxed)
|
||||||
|
presentMode = VK_PRESENT_MODE_FIFO_RELAXED_KHR;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device->PhysicalDevice.Device, device->Surface->Surface, &surfaceCapabilities);
|
if (exclusivefullscreen) // Exclusive full screen doesn't seem to support mailbox for some reason, even if it is advertised
|
||||||
if (result != VK_SUCCESS)
|
{
|
||||||
throw std::runtime_error("vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed");
|
if (supportsImmediate)
|
||||||
fullscreen = false;
|
presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||||
|
else if (supportsMailbox)
|
||||||
|
presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (supportsMailbox)
|
||||||
|
presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
|
||||||
|
else if (supportsImmediate)
|
||||||
|
presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
SelectFormat(caps, hdr);
|
||||||
|
|
||||||
actualExtent = { static_cast<uint32_t>(width), static_cast<uint32_t>(height) };
|
actualExtent = { static_cast<uint32_t>(width), static_cast<uint32_t>(height) };
|
||||||
actualExtent.width = std::max(surfaceCapabilities.minImageExtent.width, std::min(surfaceCapabilities.maxImageExtent.width, actualExtent.width));
|
actualExtent.width = std::max(caps.Capabilites.minImageExtent.width, std::min(caps.Capabilites.maxImageExtent.width, actualExtent.width));
|
||||||
actualExtent.height = std::max(surfaceCapabilities.minImageExtent.height, std::min(surfaceCapabilities.maxImageExtent.height, actualExtent.height));
|
actualExtent.height = std::max(caps.Capabilites.minImageExtent.height, std::min(caps.Capabilites.maxImageExtent.height, actualExtent.height));
|
||||||
if (actualExtent.width == 0 || actualExtent.height == 0)
|
if (actualExtent.width == 0 || actualExtent.height == 0)
|
||||||
{
|
{
|
||||||
swapChain = VK_NULL_HANDLE;
|
swapchain = VK_NULL_HANDLE;
|
||||||
|
lost = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t imageCount = surfaceCapabilities.minImageCount + 1;
|
if (caps.Capabilites.maxImageCount != 0)
|
||||||
if (surfaceCapabilities.maxImageCount > 0 && imageCount > surfaceCapabilities.maxImageCount)
|
imageCount = std::min(caps.Capabilites.maxImageCount, (uint32_t)imageCount);
|
||||||
imageCount = surfaceCapabilities.maxImageCount;
|
imageCount = std::max(caps.Capabilites.minImageCount, (uint32_t)imageCount);
|
||||||
|
|
||||||
imageCount = std::min(imageCount, (uint32_t)2); // Only use two buffers (triple buffering sucks! good for benchmarks, bad for mouse input)
|
|
||||||
|
|
||||||
VkSwapchainCreateInfoKHR swapChainCreateInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
|
VkSwapchainCreateInfoKHR swapChainCreateInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
|
||||||
|
#ifdef WIN32
|
||||||
|
VkSurfaceFullScreenExclusiveInfoEXT exclusiveInfo = { VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT };
|
||||||
|
VkSurfaceFullScreenExclusiveWin32InfoEXT exclusiveWin32Info = { VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT };
|
||||||
|
#endif
|
||||||
|
|
||||||
swapChainCreateInfo.surface = device->Surface->Surface;
|
swapChainCreateInfo.surface = device->Surface->Surface;
|
||||||
swapChainCreateInfo.minImageCount = imageCount;
|
swapChainCreateInfo.minImageCount = imageCount;
|
||||||
swapChainCreateInfo.imageFormat = swapChainFormat.format;
|
swapChainCreateInfo.imageFormat = format.format;
|
||||||
swapChainCreateInfo.imageColorSpace = swapChainFormat.colorSpace;
|
swapChainCreateInfo.imageColorSpace = format.colorSpace;
|
||||||
swapChainCreateInfo.imageExtent = actualExtent;
|
swapChainCreateInfo.imageExtent = actualExtent;
|
||||||
swapChainCreateInfo.imageArrayLayers = 1;
|
swapChainCreateInfo.imageArrayLayers = 1;
|
||||||
swapChainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
swapChainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||||
|
@ -219,188 +177,189 @@ bool VulkanSwapChain::createSwapChain(int width, int height, bool fullscreen, Vk
|
||||||
swapChainCreateInfo.pQueueFamilyIndices = nullptr;
|
swapChainCreateInfo.pQueueFamilyIndices = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
swapChainCreateInfo.preTransform = surfaceCapabilities.currentTransform;
|
swapChainCreateInfo.preTransform = caps.Capabilites.currentTransform;
|
||||||
swapChainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; // If alpha channel is passed on to the DWM or not
|
swapChainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; // If alpha channel is passed on to the DWM or not
|
||||||
swapChainCreateInfo.presentMode = swapChainPresentMode;
|
swapChainCreateInfo.presentMode = presentMode;
|
||||||
swapChainCreateInfo.clipped = VK_FALSE;// VK_TRUE;
|
swapChainCreateInfo.clipped = VK_TRUE; // Applications SHOULD set this value to VK_TRUE if they do not expect to read back the content of presentable images before presenting them or after reacquiring them, and if their fragment shaders do not have any side effects that require them to run for all pixels in the presentable image
|
||||||
swapChainCreateInfo.oldSwapchain = oldSwapChain;
|
swapChainCreateInfo.oldSwapchain = swapchain;
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
VkSurfaceFullScreenExclusiveInfoEXT exclusiveInfo = { VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT };
|
if (exclusivefullscreen)
|
||||||
VkSurfaceFullScreenExclusiveWin32InfoEXT exclusiveWin32Info = { VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT };
|
|
||||||
if (exclusivefullscreen && device->SupportsDeviceExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME))
|
|
||||||
{
|
{
|
||||||
swapChainCreateInfo.pNext = &exclusiveInfo;
|
swapChainCreateInfo.pNext = &exclusiveInfo;
|
||||||
exclusiveInfo.fullScreenExclusive = VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT;
|
|
||||||
exclusiveInfo.pNext = &exclusiveWin32Info;
|
exclusiveInfo.pNext = &exclusiveWin32Info;
|
||||||
|
exclusiveInfo.fullScreenExclusive = VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT;
|
||||||
exclusiveWin32Info.hmonitor = MonitorFromWindow(device->Surface->Window, MONITOR_DEFAULTTONEAREST);
|
exclusiveWin32Info.hmonitor = MonitorFromWindow(device->Surface->Window, MONITOR_DEFAULTTONEAREST);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VkResult result = vkCreateSwapchainKHR(device->device, &swapChainCreateInfo, nullptr, &swapChain);
|
VkResult result = vkCreateSwapchainKHR(device->device, &swapChainCreateInfo, nullptr, &swapchain);
|
||||||
|
|
||||||
|
if (swapChainCreateInfo.oldSwapchain)
|
||||||
|
vkDestroySwapchainKHR(device->device, swapChainCreateInfo.oldSwapchain, nullptr);
|
||||||
|
|
||||||
if (result != VK_SUCCESS)
|
if (result != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
swapChain = VK_NULL_HANDLE;
|
swapchain = VK_NULL_HANDLE;
|
||||||
|
lost = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
if (exclusivefullscreen && device->SupportsDeviceExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME))
|
if (exclusivefullscreen)
|
||||||
{
|
{
|
||||||
vkAcquireFullScreenExclusiveModeEXT(device->device, swapChain);
|
result = vkAcquireFullScreenExclusiveModeEXT(device->device, swapchain);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
lost = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanSwapChain::createViews()
|
int VulkanSwapChain::AcquireImage(VulkanSemaphore* semaphore, VulkanFence* fence)
|
||||||
{
|
{
|
||||||
swapChainImageViews.reserve(swapChainImages.size());
|
if (lost)
|
||||||
for (size_t i = 0; i < swapChainImages.size(); i++)
|
return -1;
|
||||||
|
|
||||||
|
uint32_t imageIndex;
|
||||||
|
VkResult result = vkAcquireNextImageKHR(device->device, swapchain, 1'000'000'000, semaphore ? semaphore->semaphore : VK_NULL_HANDLE, fence ? fence->fence : VK_NULL_HANDLE, &imageIndex);
|
||||||
|
if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR)
|
||||||
{
|
{
|
||||||
device->SetObjectName("SwapChainImage", (uint64_t)swapChainImages[i], VK_OBJECT_TYPE_IMAGE);
|
return imageIndex;
|
||||||
|
|
||||||
VkImageViewCreateInfo createInfo = {};
|
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
||||||
createInfo.image = swapChainImages[i];
|
|
||||||
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
||||||
createInfo.format = swapChainFormat.format;
|
|
||||||
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
createInfo.subresourceRange.baseMipLevel = 0;
|
|
||||||
createInfo.subresourceRange.levelCount = 1;
|
|
||||||
createInfo.subresourceRange.baseArrayLayer = 0;
|
|
||||||
createInfo.subresourceRange.layerCount = 1;
|
|
||||||
|
|
||||||
VkImageView view;
|
|
||||||
VkResult result = vkCreateImageView(device->device, &createInfo, nullptr, &view);
|
|
||||||
if (result != VK_SUCCESS)
|
|
||||||
throw std::runtime_error("Could not create image view for swapchain image");
|
|
||||||
|
|
||||||
device->SetObjectName("SwapChainImageView", (uint64_t)view, VK_OBJECT_TYPE_IMAGE_VIEW);
|
|
||||||
|
|
||||||
swapChainImageViews.push_back(view);
|
|
||||||
}
|
}
|
||||||
}
|
else if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT)
|
||||||
|
|
||||||
void VulkanSwapChain::selectFormat()
|
|
||||||
{
|
|
||||||
std::vector<VkSurfaceFormatKHR> surfaceFormats = getSurfaceFormats();
|
|
||||||
if (surfaceFormats.empty())
|
|
||||||
throw std::runtime_error("No surface formats supported");
|
|
||||||
|
|
||||||
if (surfaceFormats.size() == 1 && surfaceFormats.front().format == VK_FORMAT_UNDEFINED)
|
|
||||||
{
|
{
|
||||||
swapChainFormat.format = VK_FORMAT_B8G8R8A8_UNORM;
|
lost = true;
|
||||||
swapChainFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
return -1;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else if (result == VK_NOT_READY || result == VK_TIMEOUT)
|
||||||
for (const auto &format : surfaceFormats)
|
|
||||||
{
|
{
|
||||||
if (format.format == VK_FORMAT_B8G8R8A8_UNORM && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
return -1;
|
||||||
{
|
|
||||||
swapChainFormat = format;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
swapChainFormat = surfaceFormats.front();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanSwapChain::selectPresentMode(bool fullscreen)
|
|
||||||
{
|
|
||||||
std::vector<VkPresentModeKHR> presentModes = getPresentModes(fullscreen);
|
|
||||||
|
|
||||||
if (presentModes.empty())
|
|
||||||
throw std::runtime_error("No surface present modes supported");
|
|
||||||
|
|
||||||
swapChainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
|
|
||||||
if (vsync)
|
|
||||||
{
|
|
||||||
bool supportsFifoRelaxed = std::find(presentModes.begin(), presentModes.end(), VK_PRESENT_MODE_FIFO_RELAXED_KHR) != presentModes.end();
|
|
||||||
if (supportsFifoRelaxed)
|
|
||||||
swapChainPresentMode = VK_PRESENT_MODE_FIFO_RELAXED_KHR;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool supportsMailbox = std::find(presentModes.begin(), presentModes.end(), VK_PRESENT_MODE_MAILBOX_KHR) != presentModes.end();
|
throw std::runtime_error("Failed to acquire next image!");
|
||||||
bool supportsImmediate = std::find(presentModes.begin(), presentModes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR) != presentModes.end();
|
|
||||||
if (supportsMailbox)
|
|
||||||
swapChainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
|
|
||||||
else if (supportsImmediate)
|
|
||||||
swapChainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanSwapChain::getImages()
|
void VulkanSwapChain::QueuePresent(int imageIndex, VulkanSemaphore* semaphore)
|
||||||
{
|
{
|
||||||
uint32_t imageCount;
|
uint32_t index = imageIndex;
|
||||||
VkResult result = vkGetSwapchainImagesKHR(device->device, swapChain, &imageCount, nullptr);
|
VkPresentInfoKHR presentInfo = {};
|
||||||
if (result != VK_SUCCESS)
|
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||||
throw std::runtime_error("vkGetSwapchainImagesKHR failed");
|
presentInfo.waitSemaphoreCount = semaphore ? 1 : 0;
|
||||||
|
presentInfo.pWaitSemaphores = semaphore ? &semaphore->semaphore : VK_NULL_HANDLE;
|
||||||
swapChainImages.resize(imageCount);
|
presentInfo.swapchainCount = 1;
|
||||||
result = vkGetSwapchainImagesKHR(device->device, swapChain, &imageCount, swapChainImages.data());
|
presentInfo.pSwapchains = &swapchain;
|
||||||
if (result != VK_SUCCESS)
|
presentInfo.pImageIndices = &index;
|
||||||
throw std::runtime_error("vkGetSwapchainImagesKHR failed (2)");
|
presentInfo.pResults = nullptr;
|
||||||
}
|
VkResult result = vkQueuePresentKHR(device->PresentQueue, &presentInfo);
|
||||||
|
if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR)
|
||||||
void VulkanSwapChain::releaseViews()
|
|
||||||
{
|
|
||||||
for (auto &view : swapChainImageViews)
|
|
||||||
{
|
{
|
||||||
vkDestroyImageView(device->device, view, nullptr);
|
return;
|
||||||
|
}
|
||||||
|
else if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_ERROR_SURFACE_LOST_KHR || result == VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT)
|
||||||
|
{
|
||||||
|
lost = true;
|
||||||
|
}
|
||||||
|
else if (result == VK_ERROR_OUT_OF_HOST_MEMORY || result == VK_ERROR_OUT_OF_DEVICE_MEMORY)
|
||||||
|
{
|
||||||
|
// The spec says we can recover from this.
|
||||||
|
// However, if we are out of memory it is better to crash now than in some other weird place further away from the source of the problem.
|
||||||
|
|
||||||
|
throw std::runtime_error("vkQueuePresentKHR failed: out of memory");
|
||||||
|
}
|
||||||
|
else if (result == VK_ERROR_DEVICE_LOST)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("vkQueuePresentKHR failed: device lost");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("vkQueuePresentKHR failed");
|
||||||
}
|
}
|
||||||
swapChainImageViews.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanSwapChain::releaseResources()
|
VulkanSurfaceCapabilities VulkanSwapChain::GetSurfaceCapabilities(bool exclusivefullscreen)
|
||||||
{
|
{
|
||||||
releaseViews();
|
// They sure made it easy to query something that isn't even time critical. Good job guys!
|
||||||
if (swapChain)
|
|
||||||
vkDestroySwapchainKHR(device->device, swapChain, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<VkSurfaceFormatKHR> VulkanSwapChain::getSurfaceFormats()
|
VulkanSurfaceCapabilities caps;
|
||||||
{
|
|
||||||
uint32_t surfaceFormatCount = 0;
|
|
||||||
VkResult result = vkGetPhysicalDeviceSurfaceFormatsKHR(device->PhysicalDevice.Device, device->Surface->Surface, &surfaceFormatCount, nullptr);
|
|
||||||
if (result != VK_SUCCESS)
|
|
||||||
throw std::runtime_error("vkGetPhysicalDeviceSurfaceFormatsKHR failed");
|
|
||||||
else if (surfaceFormatCount == 0)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
std::vector<VkSurfaceFormatKHR> surfaceFormats(surfaceFormatCount);
|
VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR };
|
||||||
result = vkGetPhysicalDeviceSurfaceFormatsKHR(device->PhysicalDevice.Device, device->Surface->Surface, &surfaceFormatCount, surfaceFormats.data());
|
|
||||||
if (result != VK_SUCCESS)
|
|
||||||
throw std::runtime_error("vkGetPhysicalDeviceSurfaceFormatsKHR failed");
|
|
||||||
return surfaceFormats;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<VkPresentModeKHR> VulkanSwapChain::getPresentModes(bool exclusivefullscreen)
|
|
||||||
{
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
if (exclusivefullscreen && device->SupportsDeviceExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME))
|
VkSurfaceFullScreenExclusiveInfoEXT exclusiveInfo = { VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT };
|
||||||
|
VkSurfaceFullScreenExclusiveWin32InfoEXT exclusiveWin32Info = { VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
if (exclusivefullscreen)
|
||||||
{
|
{
|
||||||
VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR };
|
|
||||||
VkSurfaceFullScreenExclusiveInfoEXT exclusiveInfo = { VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT };
|
|
||||||
surfaceInfo.surface = device->Surface->Surface;
|
|
||||||
surfaceInfo.pNext = &exclusiveInfo;
|
|
||||||
exclusiveInfo.fullScreenExclusive = VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT;
|
exclusiveInfo.fullScreenExclusive = VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT;
|
||||||
|
exclusiveWin32Info.hmonitor = MonitorFromWindow(device->Surface->Window, MONITOR_DEFAULTTONEAREST);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
surfaceInfo.surface = device->Surface->Surface;
|
||||||
|
|
||||||
|
if (device->SupportsExtension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME))
|
||||||
|
{
|
||||||
|
const void** next = &surfaceInfo.pNext;
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
if (exclusivefullscreen && device->SupportsExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME))
|
||||||
|
{
|
||||||
|
*next = &exclusiveInfo;
|
||||||
|
next = const_cast<const void**>(&exclusiveInfo.pNext);
|
||||||
|
|
||||||
|
*next = &exclusiveWin32Info;
|
||||||
|
next = &exclusiveWin32Info.pNext;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
VkSurfaceCapabilities2KHR caps2 = { VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR };
|
||||||
|
next = const_cast<const void**>(&caps2.pNext);
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
if (exclusivefullscreen && device->SupportsExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME))
|
||||||
|
{
|
||||||
|
*next = &caps.FullScreenExclusive;
|
||||||
|
next = const_cast<const void**>(&caps.FullScreenExclusive.pNext);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
VkResult result = vkGetPhysicalDeviceSurfaceCapabilities2KHR(device->PhysicalDevice.Device, &surfaceInfo, &caps2);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("vkGetPhysicalDeviceSurfaceCapabilities2KHR failed");
|
||||||
|
|
||||||
|
caps.Capabilites = caps2.surfaceCapabilities;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device->PhysicalDevice.Device, device->Surface->Surface, &caps.Capabilites);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
if (exclusivefullscreen && device->SupportsExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME))
|
||||||
|
{
|
||||||
|
const void** next = &surfaceInfo.pNext;
|
||||||
|
|
||||||
uint32_t presentModeCount = 0;
|
uint32_t presentModeCount = 0;
|
||||||
VkResult result = vkGetPhysicalDeviceSurfacePresentModes2EXT(device->PhysicalDevice.Device, &surfaceInfo, &presentModeCount, nullptr);
|
VkResult result = vkGetPhysicalDeviceSurfacePresentModes2EXT(device->PhysicalDevice.Device, &surfaceInfo, &presentModeCount, nullptr);
|
||||||
if (result != VK_SUCCESS)
|
if (result != VK_SUCCESS)
|
||||||
throw std::runtime_error("vkGetPhysicalDeviceSurfacePresentModes2EXT failed");
|
throw std::runtime_error("vkGetPhysicalDeviceSurfacePresentModes2EXT failed");
|
||||||
else if (presentModeCount == 0)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
std::vector<VkPresentModeKHR> presentModes(presentModeCount);
|
if (presentModeCount > 0)
|
||||||
result = vkGetPhysicalDeviceSurfacePresentModes2EXT(device->PhysicalDevice.Device, &surfaceInfo, &presentModeCount, presentModes.data());
|
{
|
||||||
if (result != VK_SUCCESS)
|
caps.PresentModes.resize(presentModeCount);
|
||||||
throw std::runtime_error("vkGetPhysicalDeviceSurfacePresentModes2EXT failed");
|
result = vkGetPhysicalDeviceSurfacePresentModes2EXT(device->PhysicalDevice.Device, &surfaceInfo, &presentModeCount, caps.PresentModes.data());
|
||||||
return presentModes;
|
if (result != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("vkGetPhysicalDeviceSurfacePresentModes2EXT failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
|
@ -409,13 +368,51 @@ std::vector<VkPresentModeKHR> VulkanSwapChain::getPresentModes(bool exclusiveful
|
||||||
VkResult result = vkGetPhysicalDeviceSurfacePresentModesKHR(device->PhysicalDevice.Device, device->Surface->Surface, &presentModeCount, nullptr);
|
VkResult result = vkGetPhysicalDeviceSurfacePresentModesKHR(device->PhysicalDevice.Device, device->Surface->Surface, &presentModeCount, nullptr);
|
||||||
if (result != VK_SUCCESS)
|
if (result != VK_SUCCESS)
|
||||||
throw std::runtime_error("vkGetPhysicalDeviceSurfacePresentModesKHR failed");
|
throw std::runtime_error("vkGetPhysicalDeviceSurfacePresentModesKHR failed");
|
||||||
else if (presentModeCount == 0)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
std::vector<VkPresentModeKHR> presentModes(presentModeCount);
|
if (presentModeCount > 0)
|
||||||
result = vkGetPhysicalDeviceSurfacePresentModesKHR(device->PhysicalDevice.Device, device->Surface->Surface, &presentModeCount, presentModes.data());
|
{
|
||||||
if (result != VK_SUCCESS)
|
caps.PresentModes.resize(presentModeCount);
|
||||||
throw std::runtime_error("vkGetPhysicalDeviceSurfacePresentModesKHR failed");
|
result = vkGetPhysicalDeviceSurfacePresentModesKHR(device->PhysicalDevice.Device, device->Surface->Surface, &presentModeCount, caps.PresentModes.data());
|
||||||
return presentModes;
|
if (result != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("vkGetPhysicalDeviceSurfacePresentModesKHR failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (device->SupportsExtension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME))
|
||||||
|
{
|
||||||
|
uint32_t surfaceFormatCount = 0;
|
||||||
|
VkResult result = vkGetPhysicalDeviceSurfaceFormats2KHR(device->PhysicalDevice.Device, &surfaceInfo, &surfaceFormatCount, nullptr);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("vkGetPhysicalDeviceSurfaceFormats2KHR failed");
|
||||||
|
|
||||||
|
if (surfaceFormatCount > 0)
|
||||||
|
{
|
||||||
|
std::vector<VkSurfaceFormat2KHR> formats(surfaceFormatCount, { VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR });
|
||||||
|
result = vkGetPhysicalDeviceSurfaceFormats2KHR(device->PhysicalDevice.Device, &surfaceInfo, &surfaceFormatCount, formats.data());
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("vkGetPhysicalDeviceSurfaceFormats2KHR failed");
|
||||||
|
|
||||||
|
for (VkSurfaceFormat2KHR& fmt : formats)
|
||||||
|
caps.Formats.push_back(fmt.surfaceFormat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint32_t surfaceFormatCount = 0;
|
||||||
|
VkResult result = vkGetPhysicalDeviceSurfaceFormatsKHR(device->PhysicalDevice.Device, device->Surface->Surface, &surfaceFormatCount, nullptr);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("vkGetPhysicalDeviceSurfaceFormatsKHR failed");
|
||||||
|
|
||||||
|
if (surfaceFormatCount > 0)
|
||||||
|
{
|
||||||
|
caps.Formats.resize(surfaceFormatCount);
|
||||||
|
result = vkGetPhysicalDeviceSurfaceFormatsKHR(device->PhysicalDevice.Device, device->Surface->Surface, &surfaceFormatCount, caps.Formats.data());
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("vkGetPhysicalDeviceSurfaceFormatsKHR failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
caps.FullScreenExclusive.pNext = nullptr;
|
||||||
|
|
||||||
|
return caps;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue