Files
renderdoc/util/test/demos/vk/vk_test.h
T
baldurk 856c838def Update copyright years to 2026 and fix copyright ranges
* In a previous update in 2021 many copyright ranges were truncated
  accidentally, and some files have been copy-pasted with wrong years. These
  dates have been fixed based on git history and original copyright messages.
2026-01-05 14:17:28 +00:00

350 lines
12 KiB
C++

/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2018-2026 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#pragma once
#include <functional>
#include <mutex>
#include <set>
#include <vector>
#include "../test_common.h"
#include "vk_headers.h"
#include "vk_helpers.h"
#include "vk_test.h"
struct VulkanGraphicsTest;
struct AllocatedBuffer
{
VulkanGraphicsTest *test = NULL;
VmaAllocator allocator = NULL;
VkBuffer buffer = VK_NULL_HANDLE;
VmaAllocation alloc = {};
VkDeviceAddress address = 0;
AllocatedBuffer() {}
AllocatedBuffer(VulkanGraphicsTest *test, const VkBufferCreateInfo &bufInfo,
const VmaAllocationCreateInfo &allocInfo, uint32_t alignment = 1);
void free();
template <typename T, size_t N>
void upload(const T (&data)[N])
{
upload(data, sizeof(T) * N);
}
void upload(const void *data, size_t size)
{
byte *ptr = map();
if(ptr)
memcpy(ptr, data, size);
unmap();
}
byte *map()
{
byte *ret = NULL;
VkResult vkr = vmaMapMemory(allocator, alloc, (void **)&ret);
if(vkr != VK_SUCCESS)
return NULL;
return ret;
}
void unmap() { vmaUnmapMemory(allocator, alloc); }
};
struct AllocatedImage
{
VulkanGraphicsTest *test = NULL;
VmaAllocator allocator = NULL;
VkImage image = VK_NULL_HANDLE;
VmaAllocation alloc = {};
VkImageCreateInfo createInfo;
AllocatedImage() {}
AllocatedImage(VulkanGraphicsTest *test, const VkImageCreateInfo &imgInfo,
const VmaAllocationCreateInfo &allocInfo);
void free();
};
#define CHECK_VKR(cmd) \
do \
{ \
VkResult _vkr = cmd; \
if(_vkr != VK_SUCCESS) \
{ \
fprintf(stdout, "%s:%d Vulkan Error: %s executing:\n%s\n", __FILE__, __LINE__, \
vkh::result_str(_vkr), #cmd); \
fflush(stdout); \
DEBUG_BREAK(); \
exit(1); \
} \
} while(0);
struct VulkanGraphicsTest;
struct VulkanCommands
{
public:
VulkanCommands(VulkanGraphicsTest *test);
~VulkanCommands();
VkCommandBuffer GetCommandBuffer(VkCommandBufferLevel level);
void Submit(const std::vector<VkCommandBuffer> &cmds, const std::vector<VkCommandBuffer> &seccmds,
VkQueue q, VkSemaphore wait, VkSemaphore signal);
void ProcessCompletions();
private:
VulkanGraphicsTest *m_Test;
VkCommandPool cmdPool;
std::set<VkFence> fences;
std::vector<VkCommandBuffer> freeCommandBuffers[2];
std::vector<std::pair<VkCommandBuffer, VkFence>> pendingCommandBuffers[2];
};
struct VulkanWindow : public GraphicsWindow, public VulkanCommands
{
VkFormat format;
uint32_t imgIndex = 0;
VkRenderPass rp = VK_NULL_HANDLE;
VkViewport viewport;
VkRect2D scissor;
VulkanWindow(VulkanGraphicsTest *test, GraphicsWindow *win);
virtual ~VulkanWindow();
void Shutdown();
vkh::RenderPassBeginInfo beginRP() { return vkh::RenderPassBeginInfo(rp, GetFB(), scissor); }
void setViewScissor(VkCommandBuffer cmd);
size_t GetCount() { return imgs.size(); }
VkImage GetImage(size_t idx = ~0U)
{
if(idx == ~0U)
idx = imgIndex;
return imgs[idx];
}
VkImageView GetView(size_t idx = ~0U)
{
if(idx == ~0U)
idx = imgIndex;
return imgviews[idx];
}
VkFramebuffer GetFB(size_t idx = ~0U)
{
if(idx == ~0U)
idx = imgIndex;
return fbs[idx];
}
bool Initialised() { return swap != VK_NULL_HANDLE; }
void Submit(int index, int totalSubmits, const std::vector<VkCommandBuffer> &cmds,
const std::vector<VkCommandBuffer> &seccmds, VkQueue q);
static void MultiPresent(VkQueue queue, std::vector<VulkanWindow *> windows);
void Present(VkQueue q);
// forward GraphicsWindow functions to internal window
void Resize(int width, int height) { m_Win->Resize(width, height); }
bool Update() { return m_Win->Update(); }
private:
bool CreateSwapchain();
void DestroySwapchain();
void Acquire();
void PostPresent(VkResult vkr);
VkSurfaceKHR surface = VK_NULL_HANDLE;
VkSwapchainKHR swap = VK_NULL_HANDLE;
std::vector<VkImage> imgs;
std::vector<VkImageView> imgviews;
uint32_t semIdx = 0;
std::vector<VkSemaphore> renderStartSemaphore;
std::vector<VkSemaphore> renderEndSemaphore;
std::vector<VkFence> imageFences;
std::vector<VkFramebuffer> fbs;
GraphicsWindow *m_Win;
VulkanGraphicsTest *m_Test;
};
struct VulkanGraphicsTest : public GraphicsTest
{
static const TestAPI API = TestAPI::Vulkan;
VulkanGraphicsTest();
void Prepare(int argc, char **argv);
bool Init();
void Shutdown();
VulkanWindow *MakeWindow(int width, int height, const char *title);
bool Running();
VkImage StartUsingBackbuffer(VkCommandBuffer cmd,
VkAccessFlags nextUse = VK_ACCESS_TRANSFER_WRITE_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VkImageLayout layout = VK_IMAGE_LAYOUT_GENERAL,
VulkanWindow *window = NULL);
void FinishUsingBackbuffer(VkCommandBuffer cmd,
VkAccessFlags prevUse = VK_ACCESS_TRANSFER_WRITE_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VkImageLayout layout = VK_IMAGE_LAYOUT_GENERAL,
VulkanWindow *window = NULL);
void Submit(int index, int totalSubmits, const std::vector<VkCommandBuffer> &cmds,
const std::vector<VkCommandBuffer> &seccmds = {});
void SubmitAndPresent(const std::vector<VkCommandBuffer> &cmds);
void Present();
VkPipelineShaderStageCreateInfo LoadShaderModule(const std::string &filename, ShaderStage stage,
const char *entry_point = "main");
VkPipelineShaderStageCreateInfo CompileShaderModule(
const std::string &source_text, ShaderLang lang, ShaderStage stage,
const char *entry_point = "main", const std::map<std::string, std::string> &macros = {},
SPIRVTarget target = SPIRVTarget::vulkan);
VkCommandBuffer GetCommandBuffer(VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
VulkanWindow *window = NULL);
void setName(VkObjectType objType, uint64_t obj, const std::string &name);
void pushMarker(VkCommandBuffer cmd, const std::string &name);
void setMarker(VkCommandBuffer cmd, const std::string &name);
void popMarker(VkCommandBuffer cmd);
void pushMarker(VkQueue queue, const std::string &name);
void setMarker(VkQueue queue, const std::string &name);
void popMarker(VkQueue queue);
void blitToSwap(VkCommandBuffer cmd, VkImage src, VkImageLayout srcLayout, VkImage dst,
VkImageLayout dstLayout);
void uploadBufferToImage(VkImage destImage, VkExtent3D destExtent, VkBuffer srcBuffer,
VkImageLayout finalLayout);
template <typename T>
void setName(T obj, const std::string &name);
VkDescriptorSet allocateDescriptorSet(VkDescriptorSetLayout setLayout);
VkPipeline createGraphicsPipeline(const VkGraphicsPipelineCreateInfo *info);
VkPipeline createComputePipeline(const VkComputePipelineCreateInfo *info);
VkFramebuffer createFramebuffer(const VkFramebufferCreateInfo *info);
VkRenderPass createRenderPass(const VkRenderPassCreateInfo *info);
VkImageView createImageView(const VkImageViewCreateInfo *info);
VkBufferView createBufferView(const VkBufferViewCreateInfo *info);
VkPipelineLayout createPipelineLayout(const VkPipelineLayoutCreateInfo *info);
VkDescriptorSetLayout createDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo *info);
VkSampler createSampler(const VkSamplerCreateInfo *info);
void getPhysFeatures2(void *nextStruct);
void getPhysProperties2(void *nextStruct);
std::mutex mutex;
// instance version
uint32_t instVersion;
// device version
uint32_t devVersion;
// a custom struct to pass to vkInstanceCreateInfo::pNext
const void *instInfoNext = NULL;
// requested features
VkPhysicalDeviceFeatures features = {};
VkPhysicalDeviceFeatures optFeatures = {};
// enabled instance extensions
std::vector<const char *> instExts;
std::vector<const char *> instLayers;
// required extensions before Init(), enabled extensions after Init()
std::vector<const char *> devExts;
// optional extensions, will be added to devExts if supported (allows fallback paths)
std::vector<const char *> optDevExts;
VkQueueFlags queueFlagsRequired = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
VkQueueFlags queueFlagsBanned = 0;
bool forceGraphicsQueue = false;
bool forceComputeQueue = false;
bool forceTransferQueue = false;
uint32_t graphicsQueueFamilyIndex = ~0U;
uint32_t computeQueueFamilyIndex = ~0U;
uint32_t transferQueueFamilyIndex = ~0U;
bool hasExt(const char *ext);
// a custom struct to pass to vkDeviceCreateInfo::pNext
const void *devInfoNext = NULL;
// core objects
VkInstance instance;
VkPhysicalDevice phys;
VkDevice device;
uint32_t queueFamilyIndex = ~0U;
uint32_t queueCount;
VkQueue queue;
VkPhysicalDeviceProperties physProperties;
// utilities
VkDebugUtilsMessengerEXT debugUtilsMessenger;
// tracking object lifetimes
std::vector<VkShaderModule> shaders;
std::vector<VkDescriptorPool> descPools;
std::vector<VkPipeline> pipes;
std::vector<VkFramebuffer> framebuffers;
std::vector<VkRenderPass> renderpasses;
std::vector<VkImageView> imageviews;
std::vector<VkBufferView> bufferviews;
std::vector<VkPipelineLayout> pipelayouts;
std::vector<VkDescriptorSetLayout> setlayouts;
std::vector<VkSampler> samplers;
std::map<VkImage, VmaAllocation> imageAllocs;
std::map<VkBuffer, VmaAllocation> bufferAllocs;
VulkanWindow *mainWindow = NULL;
VulkanCommands *headlessCmds = NULL;
VkPipeline DefaultTriPipe;
AllocatedBuffer DefaultTriVB;
// VMA
bool vmaDedicated = false;
bool vmaBDA = false;
VmaAllocator allocator = VK_NULL_HANDLE;
private:
static bool prepared_vk;
GraphicsWindow *MakePlatformWindow(int width, int height, const char *title);
};
extern std::string VKFullscreenQuadVertex;
extern std::string VKDefaultVertex;
extern std::string VKDefaultPixel;