mirror of
https://github.com/coah80/LegacyVulkEdition.git
synced 2026-06-08 02:13:08 +00:00
324 lines
10 KiB
C++
324 lines
10 KiB
C++
#pragma once
|
|
|
|
#undef min
|
|
#undef max
|
|
|
|
#include <vulkan/vulkan.h>
|
|
#define GLFW_INCLUDE_NONE
|
|
#include <GLFW/glfw3.h>
|
|
|
|
#include <array>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <mutex>
|
|
#include <optional>
|
|
#include <vector>
|
|
|
|
#ifndef VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR
|
|
#define VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR 0x00000001
|
|
#endif
|
|
|
|
class VulkanBootstrapApp
|
|
{
|
|
public:
|
|
enum class ShaderVariant : uint32_t
|
|
{
|
|
ColorOnly = 0,
|
|
Textured,
|
|
TexturedAlphaTest,
|
|
TexturedFog,
|
|
TexturedFogAlphaTest,
|
|
Count
|
|
};
|
|
|
|
enum class BlendMode : uint32_t
|
|
{
|
|
Opaque = 0,
|
|
Alpha,
|
|
Additive,
|
|
PreserveDestination,
|
|
Count
|
|
};
|
|
|
|
struct Vertex
|
|
{
|
|
float position[3];
|
|
float texCoord[2];
|
|
float color[4];
|
|
};
|
|
|
|
struct RenderState
|
|
{
|
|
BlendMode blendMode = BlendMode::Opaque;
|
|
bool depthTestEnabled = true;
|
|
bool depthWriteEnabled = true;
|
|
bool cullEnabled = false;
|
|
bool cullClockwise = true;
|
|
int textureIndex = -1;
|
|
};
|
|
|
|
struct TextureSlot
|
|
{
|
|
VkImage image = VK_NULL_HANDLE;
|
|
VkDeviceMemory memory = VK_NULL_HANDLE;
|
|
VkImageView imageView = VK_NULL_HANDLE;
|
|
VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
|
|
uint32_t width = 0;
|
|
uint32_t height = 0;
|
|
bool allocated = false;
|
|
bool linearFiltering = false;
|
|
bool clampAddress = false;
|
|
};
|
|
|
|
static constexpr uint32_t kMaxTextures = 256;
|
|
|
|
static void initialiseGlfw();
|
|
static void terminateGlfw();
|
|
static GLFWwindow *createWindow(const char *title, uint32_t width = 1280, uint32_t height = 720);
|
|
|
|
void run();
|
|
void attachToWindow(GLFWwindow *window);
|
|
void beginFrame();
|
|
void submitVertices(
|
|
VkPrimitiveTopology topology,
|
|
const Vertex *vertices,
|
|
size_t count,
|
|
ShaderVariant variant,
|
|
const float mvp[16],
|
|
const RenderState &state,
|
|
const float *colorModulation = nullptr);
|
|
void requestClear(uint32_t flags);
|
|
void tickFrame();
|
|
void shutdownRenderer();
|
|
|
|
struct FrameStats
|
|
{
|
|
double drawFrameMs = 0.0;
|
|
double fenceWaitMs = 0.0;
|
|
uint32_t vertexCount = 0;
|
|
uint32_t batchCount = 0;
|
|
uint32_t textureCount = 0;
|
|
uint32_t swapchainImageCount = 0;
|
|
const char *presentModeName = "unknown";
|
|
char gpuName[256] = {};
|
|
uint32_t swapchainWidth = 0;
|
|
uint32_t swapchainHeight = 0;
|
|
};
|
|
FrameStats getFrameStats() const;
|
|
void setClearColour(const float colourRGBA[4]);
|
|
void setViewportRect(int x, int y, uint32_t width, uint32_t height);
|
|
int allocateTextureSlot();
|
|
void freeTextureSlot(int index);
|
|
void setCurrentTexture(int index);
|
|
int getCurrentTexture() const;
|
|
void setTextureLinearFiltering(int index, bool enabled);
|
|
void setTextureClampAddress(int index, bool enabled);
|
|
void uploadTextureData(int slotIndex, uint32_t width, uint32_t height, const void *pixelData);
|
|
void updateTextureData(
|
|
int slotIndex,
|
|
int xOffset,
|
|
int yOffset,
|
|
uint32_t width,
|
|
uint32_t height,
|
|
const void *pixelData);
|
|
|
|
std::function<void(VkCommandBuffer, uint32_t)> overlayCallback;
|
|
std::function<void()> swapchainRecreatedCallback;
|
|
|
|
VkDevice getDevice() const { return device_; }
|
|
VkPhysicalDevice getPhysicalDevice() const { return physicalDevice_; }
|
|
VkQueue getGraphicsQueue() const { return graphicsQueue_; }
|
|
uint32_t getGraphicsQueueFamily() const;
|
|
VkImageView *getSwapchainImageViews() { return swapchainImageViews_.data(); }
|
|
uint32_t getSwapchainImageCount() const { return (uint32_t)swapchainImageViews_.size(); }
|
|
VkFormat getSwapchainFormat() const { return swapchainImageFormat_; }
|
|
GLFWwindow *getWindow() const { return window_; }
|
|
uint32_t getCurrentImageIndex() const { return currentImageIndex_; }
|
|
VkSemaphore getImageAvailableSemaphore() const { return imageAvailableSemaphore_; }
|
|
|
|
private:
|
|
uint32_t currentImageIndex_ = 0;
|
|
struct DrawBatch
|
|
{
|
|
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
|
uint32_t firstVertex = 0;
|
|
uint32_t vertexCount = 0;
|
|
uint32_t clearFlags = 0;
|
|
ShaderVariant shaderVariant = ShaderVariant::ColorOnly;
|
|
RenderState renderState {};
|
|
std::array<float, 16> mvp {};
|
|
int viewportX = 0;
|
|
int viewportY = 0;
|
|
uint32_t viewportWidth = 0;
|
|
uint32_t viewportHeight = 0;
|
|
};
|
|
|
|
struct QueueFamilyIndices
|
|
{
|
|
std::optional<uint32_t> graphicsFamily;
|
|
std::optional<uint32_t> presentFamily;
|
|
|
|
bool isComplete() const;
|
|
};
|
|
|
|
struct SwapchainSupportDetails
|
|
{
|
|
VkSurfaceCapabilitiesKHR capabilities {};
|
|
std::vector<VkSurfaceFormatKHR> formats;
|
|
std::vector<VkPresentModeKHR> presentModes;
|
|
};
|
|
|
|
void initWindow();
|
|
void initVulkan();
|
|
void mainLoop();
|
|
void cleanup();
|
|
void recreateSwapchain();
|
|
void cleanupSwapchain();
|
|
|
|
void createInstance();
|
|
void createSurface();
|
|
void pickPhysicalDevice();
|
|
void createLogicalDevice();
|
|
void createCommandPool();
|
|
void createSwapchain();
|
|
void createImageViews();
|
|
void createDepthResources();
|
|
void createRenderPass();
|
|
void createGraphicsPipeline();
|
|
void createFramebuffers();
|
|
void createVertexBuffer(size_t vertexCapacity);
|
|
void ensureVertexBufferCapacity(size_t requiredVertices);
|
|
void createCommandBuffers();
|
|
void createSyncObjects();
|
|
void createTextureResources();
|
|
void createDescriptorPool();
|
|
void createDescriptorSetLayout();
|
|
void createSamplers();
|
|
void createFallbackTexture();
|
|
void drawFrame();
|
|
void recordCommandBuffer(
|
|
VkCommandBuffer commandBuffer,
|
|
uint32_t imageIndex,
|
|
const std::vector<DrawBatch> &batches);
|
|
uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) const;
|
|
void createBuffer(
|
|
VkDeviceSize size,
|
|
VkBufferUsageFlags usage,
|
|
VkMemoryPropertyFlags properties,
|
|
VkBuffer &buffer,
|
|
VkDeviceMemory &bufferMemory);
|
|
void copyBuffer(VkBuffer sourceBuffer, VkBuffer destinationBuffer, VkDeviceSize size);
|
|
VkCommandBuffer beginOneTimeCommands();
|
|
void endOneTimeCommands(VkCommandBuffer commandBuffer);
|
|
void transitionImageLayout(
|
|
VkCommandBuffer commandBuffer,
|
|
VkImage image,
|
|
VkImageLayout oldLayout,
|
|
VkImageLayout newLayout);
|
|
void ensureStagingBuffer(VkDeviceSize requiredSize);
|
|
void destroyTextureResources();
|
|
void destroyTextureSlotResources(int index, bool freeDescriptorSet);
|
|
void updateTextureDescriptor(int index);
|
|
VkSampler getSamplerForSlot(const TextureSlot &slot) const;
|
|
VkPipeline getPipelineForBatch(const DrawBatch &batch) const;
|
|
uint32_t getPipelineIndex(
|
|
ShaderVariant variant,
|
|
BlendMode blendMode,
|
|
bool depthTestEnabled,
|
|
bool depthWriteEnabled,
|
|
bool cullEnabled,
|
|
bool cullClockwise) const;
|
|
void logSelectedDevice() const;
|
|
void logSwapchainSelection(
|
|
VkSurfaceFormatKHR surfaceFormat,
|
|
VkPresentModeKHR presentMode,
|
|
VkExtent2D extent) const;
|
|
|
|
bool isDeviceSuitable(VkPhysicalDevice device) const;
|
|
bool checkDeviceExtensionSupport(VkPhysicalDevice device) const;
|
|
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) const;
|
|
SwapchainSupportDetails querySwapchainSupport(VkPhysicalDevice device) const;
|
|
|
|
VkSurfaceFormatKHR chooseSwapSurfaceFormat(
|
|
const std::vector<VkSurfaceFormatKHR> &availableFormats) const;
|
|
VkPresentModeKHR chooseSwapPresentMode(
|
|
const std::vector<VkPresentModeKHR> &availablePresentModes) const;
|
|
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR &capabilities) const;
|
|
|
|
std::vector<const char *> getRequiredInstanceExtensions() const;
|
|
std::vector<const char *> getRequiredDeviceExtensions() const;
|
|
|
|
static void framebufferResizeCallback(GLFWwindow *window, int width, int height);
|
|
|
|
static constexpr uint32_t kWindowWidth = 1280;
|
|
static constexpr uint32_t kWindowHeight = 720;
|
|
|
|
GLFWwindow *window_ = nullptr;
|
|
|
|
VkInstance instance_ = VK_NULL_HANDLE;
|
|
VkSurfaceKHR surface_ = VK_NULL_HANDLE;
|
|
VkPhysicalDevice physicalDevice_ = VK_NULL_HANDLE;
|
|
VkDevice device_ = VK_NULL_HANDLE;
|
|
VkQueue graphicsQueue_ = VK_NULL_HANDLE;
|
|
VkQueue presentQueue_ = VK_NULL_HANDLE;
|
|
VkCommandPool commandPool_ = VK_NULL_HANDLE;
|
|
|
|
VkSwapchainKHR swapchain_ = VK_NULL_HANDLE;
|
|
std::vector<VkImage> swapchainImages_;
|
|
std::vector<VkImageView> swapchainImageViews_;
|
|
std::vector<VkFramebuffer> swapchainFramebuffers_;
|
|
VkFormat swapchainImageFormat_ = VK_FORMAT_UNDEFINED;
|
|
VkExtent2D swapchainExtent_ {};
|
|
VkImage depthImage_ = VK_NULL_HANDLE;
|
|
VkDeviceMemory depthImageMemory_ = VK_NULL_HANDLE;
|
|
VkImageView depthImageView_ = VK_NULL_HANDLE;
|
|
VkRenderPass renderPass_ = VK_NULL_HANDLE;
|
|
VkPipelineLayout pipelineLayout_ = VK_NULL_HANDLE;
|
|
std::array<
|
|
VkPipeline,
|
|
static_cast<size_t>(ShaderVariant::Count) *
|
|
static_cast<size_t>(BlendMode::Count) *
|
|
16u>
|
|
pipelines_ {};
|
|
std::vector<VkCommandBuffer> commandBuffers_;
|
|
|
|
VkBuffer vertexBuffer_ = VK_NULL_HANDLE;
|
|
VkDeviceMemory vertexBufferMemory_ = VK_NULL_HANDLE;
|
|
void *vertexBufferMapped_ = nullptr;
|
|
size_t vertexBufferCapacity_ = 0;
|
|
std::mutex frameDataMutex_;
|
|
int currentViewportX_ = 0;
|
|
int currentViewportY_ = 0;
|
|
uint32_t currentViewportWidth_ = 0;
|
|
uint32_t currentViewportHeight_ = 0;
|
|
std::vector<Vertex> frameVertices_;
|
|
std::vector<DrawBatch> frameBatches_;
|
|
|
|
VkSemaphore imageAvailableSemaphore_ = VK_NULL_HANDLE;
|
|
VkSemaphore renderFinishedSemaphore_ = VK_NULL_HANDLE;
|
|
VkFence inFlightFence_ = VK_NULL_HANDLE;
|
|
|
|
TextureSlot textureSlots_[kMaxTextures] {};
|
|
VkDescriptorPool descriptorPool_ = VK_NULL_HANDLE;
|
|
VkDescriptorSetLayout textureSetLayout_ = VK_NULL_HANDLE;
|
|
VkSampler nearestRepeatSampler_ = VK_NULL_HANDLE;
|
|
VkSampler nearestClampSampler_ = VK_NULL_HANDLE;
|
|
VkSampler linearRepeatSampler_ = VK_NULL_HANDLE;
|
|
VkSampler linearClampSampler_ = VK_NULL_HANDLE;
|
|
VkBuffer stagingBuffer_ = VK_NULL_HANDLE;
|
|
VkDeviceMemory stagingBufferMemory_ = VK_NULL_HANDLE;
|
|
VkDeviceSize stagingBufferSize_ = 0;
|
|
int boundTextureIndex_ = -1;
|
|
int fallbackTextureIndex_ = -1;
|
|
|
|
bool framebufferResized_ = false;
|
|
bool startupInfoLogged_ = false;
|
|
float clearColour_[4] = {0.05f, 0.06f, 0.09f, 1.0f};
|
|
size_t prevFrameVertexCount_ = 0;
|
|
size_t prevFrameBatchCount_ = 0;
|
|
|
|
FrameStats frameStats_ {};
|
|
VkPresentModeKHR activePresentMode_ = VK_PRESENT_MODE_FIFO_KHR;
|
|
};
|