228 lines
8.0 KiB
C++
228 lines
8.0 KiB
C++
#ifndef UTIL_H
|
|
#define UTIL_H
|
|
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <filesystem>
|
|
#include <optional>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <cassert>
|
|
|
|
#include <vulkan/vulkan.h>
|
|
|
|
#include "glm/vec4.hpp"
|
|
|
|
|
|
inline void checkVkResult(VkResult result, const char* expression, const char* file, int line)
|
|
{
|
|
if (result == VK_SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
throw std::runtime_error(
|
|
std::string{"Vulkan call failed: "} + expression +
|
|
" returned " + std::to_string(static_cast<int>(result)) +
|
|
" at " + file + ":" + std::to_string(line));
|
|
}
|
|
|
|
#define VK_CHECK(call) \
|
|
do { \
|
|
const VkResult result_ = (call); \
|
|
checkVkResult(result_, #call, __FILE__, __LINE__); \
|
|
} while (0)
|
|
|
|
namespace vkutil {
|
|
struct CreateImageInfo {
|
|
VkFormat format;
|
|
VkImageUsageFlags usage;
|
|
VkImageCreateFlags flags;
|
|
VkExtent3D extent{};
|
|
std::uint32_t numLayers{1};
|
|
VkSampleCountFlagBits samples{VK_SAMPLE_COUNT_1_BIT};
|
|
VkImageTiling tiling{VK_IMAGE_TILING_OPTIMAL};
|
|
bool mipMap{false};
|
|
bool isCubemap{false};
|
|
};
|
|
|
|
void transitionImage(
|
|
VkCommandBuffer cmd,
|
|
VkImage image,
|
|
VkImageLayout currentLayout,
|
|
VkImageLayout newLayout);
|
|
|
|
void transitionImage(
|
|
VkCommandBuffer cmd,
|
|
VkImage image,
|
|
VkImageLayout currentLayout,
|
|
VkImageLayout newLayout,
|
|
const VkImageSubresourceRange& subresourceRange);
|
|
|
|
void copyImageToImage(
|
|
VkCommandBuffer cmd,
|
|
VkImage source,
|
|
VkImage destination,
|
|
VkExtent2D srcSize,
|
|
VkExtent2D dstSize,
|
|
VkFilter filter);
|
|
|
|
void copyImageToImage(
|
|
VkCommandBuffer cmd,
|
|
VkImage source,
|
|
VkImage destination,
|
|
VkExtent2D srcSize,
|
|
int destX,
|
|
int destY,
|
|
int destW,
|
|
int destH,
|
|
VkFilter filter);
|
|
|
|
void bufferHostWriteToShaderReadBarrier(
|
|
VkCommandBuffer cmd,
|
|
VkBuffer buffer,
|
|
VkDeviceSize offset = 0,
|
|
VkDeviceSize size = VK_WHOLE_SIZE);
|
|
|
|
void bufferHostWriteToTransferReadBarrier(
|
|
VkCommandBuffer cmd,
|
|
VkBuffer buffer,
|
|
VkDeviceSize offset = 0,
|
|
VkDeviceSize size = VK_WHOLE_SIZE);
|
|
|
|
// Object names (VK_EXT_debug_utils), shown in RenderDoc, Nsight and validation messages.
|
|
// All of these are no-ops when the extension isn't loaded.
|
|
void addDebugLabel(VkDevice device, VkObjectType objectType, std::uint64_t objectHandle, const char* label);
|
|
void addDebugLabel(VkDevice device, VkImage image, const char* label);
|
|
void addDebugLabel(VkDevice device, VkImageView imageView, const char* label);
|
|
void addDebugLabel(VkDevice device, VkShaderModule shaderModule, const char* label);
|
|
void addDebugLabel(VkDevice device, VkPipeline pipeline, const char* label);
|
|
void addDebugLabel(VkDevice device, VkPipelineLayout layout, const char* label);
|
|
void addDebugLabel(VkDevice device, VkBuffer buffer, const char* label);
|
|
void addDebugLabel(VkDevice device, VkSampler sampler, const char* label);
|
|
void addDebugLabel(VkDevice device, VkDescriptorPool descriptorPool, const char* label);
|
|
void addDebugLabel(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const char* label);
|
|
void addDebugLabel(VkDevice device, VkDescriptorSet descriptorSet, const char* label);
|
|
void addDebugLabel(VkDevice device, VkCommandPool commandPool, const char* label);
|
|
void addDebugLabel(VkDevice device, VkCommandBuffer commandBuffer, const char* label);
|
|
void addDebugLabel(VkDevice device, VkFence fence, const char* label);
|
|
void addDebugLabel(VkDevice device, VkSemaphore semaphore, const char* label);
|
|
void addDebugLabel(VkDevice device, VkQueue queue, const char* label);
|
|
|
|
// Command buffer regions, they nest like a stack: every begin needs a matching end
|
|
// in the same command buffer.
|
|
[[nodiscard]] bool debugLabelsEnabled();
|
|
void cmdBeginLabel(VkCommandBuffer cmd, const char* label, const glm::vec4& color = glm::vec4{1.0f});
|
|
void cmdEndLabel(VkCommandBuffer cmd);
|
|
void cmdInsertLabel(VkCommandBuffer cmd, const char* label, const glm::vec4& color = glm::vec4{1.0f});
|
|
|
|
// printf style, only formats when labels are actually recorded (cheap enough for per draw labels)
|
|
template <typename... Args>
|
|
void cmdBeginLabelFormatted(VkCommandBuffer cmd, const glm::vec4& color, const char* format, Args... args)
|
|
{
|
|
if (!debugLabelsEnabled()) {
|
|
return;
|
|
}
|
|
|
|
char label[256];
|
|
std::snprintf(label, sizeof(label), format, args...);
|
|
cmdBeginLabel(cmd, label, color);
|
|
}
|
|
|
|
class ScopedCmdLabel {
|
|
public:
|
|
ScopedCmdLabel(VkCommandBuffer cmd, const char* label, const glm::vec4& color = glm::vec4{1.0f});
|
|
~ScopedCmdLabel();
|
|
|
|
ScopedCmdLabel(const ScopedCmdLabel& other) = delete;
|
|
ScopedCmdLabel(ScopedCmdLabel&& other) noexcept = delete;
|
|
ScopedCmdLabel& operator=(const ScopedCmdLabel& other) = delete;
|
|
ScopedCmdLabel& operator=(ScopedCmdLabel&& other) noexcept = delete;
|
|
|
|
private:
|
|
VkCommandBuffer cmd{VK_NULL_HANDLE};
|
|
};
|
|
|
|
// Colors used for the renderer's labels, so passes are easy to tell apart in a capture
|
|
namespace labelColors {
|
|
inline const glm::vec4 frame{0.8f, 0.8f, 0.8f, 1.0f};
|
|
inline const glm::vec4 compute{0.9f, 0.5f, 0.1f, 1.0f};
|
|
inline const glm::vec4 shadow{0.3f, 0.3f, 0.6f, 1.0f};
|
|
inline const glm::vec4 depth{0.4f, 0.4f, 0.4f, 1.0f};
|
|
inline const glm::vec4 opaque{0.2f, 0.7f, 0.3f, 1.0f};
|
|
inline const glm::vec4 sky{0.3f, 0.6f, 0.9f, 1.0f};
|
|
inline const glm::vec4 debug{0.9f, 0.2f, 0.6f, 1.0f};
|
|
inline const glm::vec4 ui{0.9f, 0.9f, 0.2f, 1.0f};
|
|
inline const glm::vec4 transfer{0.6f, 0.4f, 0.2f, 1.0f};
|
|
inline const glm::vec4 draw{0.5f, 0.8f, 0.5f, 1.0f};
|
|
}
|
|
|
|
struct RenderingInfoParams {
|
|
VkExtent2D renderExtent;
|
|
VkImageView colorImageView{VK_NULL_HANDLE};
|
|
std::optional<glm::vec4> colorImageClearValue;
|
|
VkImageView depthImageView{VK_NULL_HANDLE};
|
|
std::optional<float> depthImageClearValue;
|
|
};
|
|
|
|
struct RenderInfo {
|
|
VkRenderingAttachmentInfo colorAttachment{};
|
|
VkRenderingAttachmentInfo depthAttachment{};
|
|
VkRenderingInfo renderingInfo{};
|
|
|
|
RenderInfo() = default;
|
|
|
|
RenderInfo(const RenderInfo& other)
|
|
: colorAttachment(other.colorAttachment),
|
|
depthAttachment(other.depthAttachment),
|
|
renderingInfo(other.renderingInfo)
|
|
{
|
|
rebind();
|
|
}
|
|
|
|
RenderInfo& operator=(const RenderInfo& other)
|
|
{
|
|
if (this != &other) {
|
|
colorAttachment = other.colorAttachment;
|
|
depthAttachment = other.depthAttachment;
|
|
renderingInfo = other.renderingInfo;
|
|
rebind();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
RenderInfo(RenderInfo&& other) noexcept
|
|
: colorAttachment(other.colorAttachment),
|
|
depthAttachment(other.depthAttachment),
|
|
renderingInfo(other.renderingInfo)
|
|
{
|
|
rebind();
|
|
}
|
|
|
|
RenderInfo& operator=(RenderInfo&& other) noexcept
|
|
{
|
|
if (this != &other) {
|
|
colorAttachment = other.colorAttachment;
|
|
depthAttachment = other.depthAttachment;
|
|
renderingInfo = other.renderingInfo;
|
|
rebind();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
void rebind()
|
|
{
|
|
renderingInfo.pColorAttachments = renderingInfo.colorAttachmentCount != 0
|
|
? &colorAttachment
|
|
: nullptr;
|
|
renderingInfo.pDepthAttachment = renderingInfo.pDepthAttachment != nullptr
|
|
? &depthAttachment
|
|
: nullptr;
|
|
}
|
|
};
|
|
|
|
RenderInfo createRenderingInfo(const RenderingInfoParams& params);
|
|
|
|
VkShaderModule loadShaderModule(const std::filesystem::path& path, VkDevice device);
|
|
}
|
|
#endif //UTIL_H
|