inital vertex buffer
This commit is contained in:
2
Makefile
2
Makefile
@@ -3,7 +3,7 @@ LDFLAGS = -lglfw -lvulkan -ldl -lpthread
|
||||
CFLAGS = -g -pedantic -Wall -Wextra -Wshadow -Wunused-macros
|
||||
|
||||
VulkanApplication: main.c
|
||||
gcc $(CFLAGS) -o VulkanApplication main.c $(LDFLAGS)
|
||||
tcc $(CFLAGS) -o VulkanApplication main.c $(LDFLAGS)
|
||||
|
||||
.PHONY: run clean
|
||||
|
||||
|
||||
324
main.c
324
main.c
@@ -8,9 +8,15 @@
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
enum bool {
|
||||
false = 0,
|
||||
true = 1,
|
||||
};
|
||||
typedef int bool;
|
||||
|
||||
const uint32_t WIDTH = 800;
|
||||
const uint32_t HEIGHT = 600;
|
||||
const int MAX_FRAMES_IN_FLIGHT = 2;
|
||||
#define MAX_FRAMES_IN_FLIGHT 2
|
||||
|
||||
const char* VALIDATION_LAYERS[] = { "VK_LAYER_KHRONOS_validation" };
|
||||
#define VALIDATION_LAYER_COUNT 1
|
||||
@@ -19,11 +25,34 @@ const char* DEVICE_EXTENSIONS[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };
|
||||
#define DEVICE_EXTENSION_COUNT 1
|
||||
|
||||
#ifdef NDEBUG
|
||||
const uint32_t enableValidationLayers = 0;
|
||||
const bool enableValidationLayers = false;
|
||||
#else
|
||||
const uint32_t enableValidationLayers = 1;
|
||||
const bool enableValidationLayers = true;
|
||||
#endif
|
||||
|
||||
typedef struct Vec2 {
|
||||
float x;
|
||||
float y;
|
||||
} Vec2;
|
||||
|
||||
typedef struct Vec3 {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
} Vec3;
|
||||
|
||||
typedef struct Vertex {
|
||||
Vec2 pos;
|
||||
Vec3 color;
|
||||
} Vertex;
|
||||
|
||||
#define VERTEX_COUNT 3
|
||||
const Vertex vertices[VERTEX_COUNT] = {
|
||||
{{0.0f, -0.5f}, {0.0f, 0.0f, 0.0f}},
|
||||
{{0.5f, 0.5f}, {0.0f, 1.0f, 0.0f}},
|
||||
{{-0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}}
|
||||
};
|
||||
|
||||
struct VulkanData {
|
||||
VkInstance instance;
|
||||
VkDebugUtilsMessengerEXT debugMessenger;
|
||||
@@ -43,10 +72,14 @@ struct VulkanData {
|
||||
VkPipeline graphicsPipeline;
|
||||
VkFramebuffer swapChainFramebuffers[4];
|
||||
VkCommandPool commandPool;
|
||||
VkCommandBuffer commandBuffer;
|
||||
VkSemaphore imageAvailableSemaphore;
|
||||
VkSemaphore renderFinishedSemaphore;
|
||||
VkFence inFlightFence;
|
||||
VkCommandBuffer commandBuffers[MAX_FRAMES_IN_FLIGHT];
|
||||
VkSemaphore imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT];
|
||||
VkSemaphore renderFinishedSemaphores[MAX_FRAMES_IN_FLIGHT];
|
||||
VkFence inFlightFences[MAX_FRAMES_IN_FLIGHT];
|
||||
uint32_t currentFrame;
|
||||
bool framebufferResized;
|
||||
VkBuffer vertexBuffer;
|
||||
VkDeviceMemory vertexBufferMemory;
|
||||
};
|
||||
|
||||
struct SwapChainSupportDetails {
|
||||
@@ -65,11 +98,27 @@ struct QueueFamilyIndices {
|
||||
struct Optional presentFamily;
|
||||
};
|
||||
|
||||
GLFWwindow* initWindow() {
|
||||
static VkVertexInputBindingDescription getBindingDescription() {
|
||||
VkVertexInputBindingDescription bindingDescription = {
|
||||
.binding = 0,
|
||||
.stride = sizeof(Vertex),
|
||||
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
|
||||
};
|
||||
return bindingDescription;
|
||||
}
|
||||
|
||||
static void framebufferResizeCallback(GLFWwindow* window, int width, int height) {
|
||||
printf("INFO: resizing from width: %d, height: %d\n", width, height);
|
||||
struct VulkanData* app = (struct VulkanData*) glfwGetWindowUserPointer(window);
|
||||
app->framebufferResized = true;
|
||||
}
|
||||
|
||||
GLFWwindow* initWindow(struct VulkanData* data) {
|
||||
if (!glfwInit()) {
|
||||
fprintf(stderr, "ERROR: Failed to initialize window\n");
|
||||
exit(1);
|
||||
}
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
|
||||
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", NULL, NULL);
|
||||
if (!window) {
|
||||
@@ -79,11 +128,13 @@ GLFWwindow* initWindow() {
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSetWindowUserPointer(window, data);
|
||||
glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
|
||||
return window;
|
||||
}
|
||||
|
||||
// INDIRECTION: main->run->initVulkan->createInstance
|
||||
uint32_t checkValidationLayerSupport() {
|
||||
static bool checkValidationLayerSupport() {
|
||||
uint32_t layerCount;
|
||||
vkEnumerateInstanceLayerProperties(&layerCount, NULL);
|
||||
|
||||
@@ -103,11 +154,11 @@ uint32_t checkValidationLayerSupport() {
|
||||
}
|
||||
|
||||
if (!layerFound) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
// INDIRECTION: main->run->initVulkan->createInstance
|
||||
@@ -125,7 +176,7 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
|
||||
}
|
||||
|
||||
// INDIRECTION: main->run->initVulkan
|
||||
void createInstance(struct VulkanData* data) {
|
||||
static void createInstance(struct VulkanData* data) {
|
||||
if (enableValidationLayers && !checkValidationLayerSupport()) {
|
||||
printf("ERROR: Validation layers requested, but not available\n");
|
||||
exit(1);
|
||||
@@ -211,7 +262,7 @@ VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMes
|
||||
}
|
||||
|
||||
|
||||
void setupDebugMessenger(struct VulkanData* data) {
|
||||
static void setupDebugMessenger(struct VulkanData* data) {
|
||||
if (!enableValidationLayers) return;
|
||||
|
||||
VkDebugUtilsMessengerCreateInfoEXT createInfo = {
|
||||
@@ -227,7 +278,7 @@ void setupDebugMessenger(struct VulkanData* data) {
|
||||
}
|
||||
}
|
||||
|
||||
void createSurface(struct VulkanData* data, GLFWwindow* window) {
|
||||
static void createSurface(struct VulkanData* data, GLFWwindow* window) {
|
||||
VkWaylandSurfaceCreateInfoKHR createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,
|
||||
.display = glfwGetWaylandDisplay(),
|
||||
@@ -243,21 +294,21 @@ void createSurface(struct VulkanData* data, GLFWwindow* window) {
|
||||
}
|
||||
}
|
||||
|
||||
void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator) {
|
||||
static void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator) {
|
||||
PFN_vkDestroyDebugUtilsMessengerEXT func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
|
||||
if (func != NULL) {
|
||||
func(instance, debugMessenger, pAllocator);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t clamp(uint32_t value, uint32_t min, uint32_t max) {
|
||||
static uint32_t clamp(uint32_t value, uint32_t min, uint32_t max) {
|
||||
if (value > max) return max;
|
||||
if (value < min) return min;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
int checkDeviceExtensionSupport(VkPhysicalDevice device) {
|
||||
static int checkDeviceExtensionSupport(VkPhysicalDevice device) {
|
||||
uint32_t extensionCount;
|
||||
vkEnumerateDeviceExtensionProperties(device, NULL, &extensionCount, NULL);
|
||||
|
||||
@@ -278,7 +329,7 @@ int checkDeviceExtensionSupport(VkPhysicalDevice device) {
|
||||
return requiredExtensionsFound == DEVICE_EXTENSION_COUNT;
|
||||
}
|
||||
|
||||
struct SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device, VkSurfaceKHR surface) {
|
||||
static struct SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device, VkSurfaceKHR surface) {
|
||||
struct SwapChainSupportDetails details;
|
||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
|
||||
uint32_t formatCount;
|
||||
@@ -297,7 +348,7 @@ struct SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device, Vk
|
||||
return details;
|
||||
}
|
||||
|
||||
struct QueueFamilyIndices findQueueFamilies(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) {
|
||||
static struct QueueFamilyIndices findQueueFamilies(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) {
|
||||
struct QueueFamilyIndices indices = {
|
||||
.graphicsFamily.v = 0,
|
||||
.graphicsFamily.is_some = 0,
|
||||
@@ -334,7 +385,7 @@ struct QueueFamilyIndices findQueueFamilies(VkPhysicalDevice physicalDevice, VkS
|
||||
return indices;
|
||||
}
|
||||
|
||||
int isDeviceSuitable(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) { // One could pick the device based on a score.
|
||||
static bool isDeviceSuitable(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) { // One could pick the device based on a score.
|
||||
struct QueueFamilyIndices indices = findQueueFamilies(physicalDevice, surface);
|
||||
|
||||
VkPhysicalDeviceProperties deviceProperties;
|
||||
@@ -364,7 +415,7 @@ int isDeviceSuitable(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) { //
|
||||
indices.graphicsFamily.is_some && indices.presentFamily.is_some;
|
||||
}
|
||||
|
||||
void pickPhysicalDevice(struct VulkanData* data) {
|
||||
static void pickPhysicalDevice(struct VulkanData* data) {
|
||||
data->physicalDevice = VK_NULL_HANDLE;
|
||||
uint32_t deviceCount = 0;
|
||||
vkEnumeratePhysicalDevices(data->instance, &deviceCount, NULL);
|
||||
@@ -389,7 +440,7 @@ void pickPhysicalDevice(struct VulkanData* data) {
|
||||
}
|
||||
}
|
||||
|
||||
void createLogicalDevice(struct VulkanData* data) {
|
||||
static void createLogicalDevice(struct VulkanData* data) {
|
||||
struct QueueFamilyIndices indices = findQueueFamilies(data->physicalDevice, data->surface);
|
||||
float queuePriority = 1.0f;
|
||||
|
||||
@@ -461,7 +512,7 @@ void createLogicalDevice(struct VulkanData* data) {
|
||||
vkGetDeviceQueue(data->device, indices.presentFamily.v, 0, &data->presentQueue);
|
||||
}
|
||||
|
||||
VkExtent2D chooseSwapExtent(VkSurfaceCapabilitiesKHR* capabilities, GLFWwindow* window) {
|
||||
static VkExtent2D chooseSwapExtent(VkSurfaceCapabilitiesKHR* capabilities, GLFWwindow* window) {
|
||||
if (capabilities->currentExtent.width != UINT_MAX) {
|
||||
return capabilities->currentExtent;
|
||||
} else {
|
||||
@@ -480,7 +531,7 @@ VkExtent2D chooseSwapExtent(VkSurfaceCapabilitiesKHR* capabilities, GLFWwindow*
|
||||
}
|
||||
}
|
||||
|
||||
VkSurfaceFormatKHR chooseSwapSurfaceFormat(VkSurfaceFormatKHR availableFormats[]) {
|
||||
static VkSurfaceFormatKHR chooseSwapSurfaceFormat(VkSurfaceFormatKHR availableFormats[]) {
|
||||
for(int i = 0; 1; i++) {
|
||||
VkSurfaceFormatKHR availableFormat = availableFormats[i];
|
||||
if (availableFormat.format == VK_FORMAT_UNDEFINED) {
|
||||
@@ -493,7 +544,7 @@ VkSurfaceFormatKHR chooseSwapSurfaceFormat(VkSurfaceFormatKHR availableFormats[]
|
||||
return availableFormats[0];
|
||||
}
|
||||
|
||||
VkPresentModeKHR chooseSwapPresentMode(VkPresentModeKHR availablePresentModes[]) {
|
||||
static VkPresentModeKHR chooseSwapPresentMode(VkPresentModeKHR availablePresentModes[]) {
|
||||
for(int i = 0; 1; i++) {
|
||||
if (availablePresentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
|
||||
return availablePresentModes[i];
|
||||
@@ -502,7 +553,7 @@ VkPresentModeKHR chooseSwapPresentMode(VkPresentModeKHR availablePresentModes[])
|
||||
return VK_PRESENT_MODE_FIFO_KHR;
|
||||
}
|
||||
|
||||
void createSwapChain(struct VulkanData* data, GLFWwindow* window) {
|
||||
static void createSwapChain(struct VulkanData* data, GLFWwindow* window) {
|
||||
struct SwapChainSupportDetails swapChainSupport = querySwapChainSupport(data->physicalDevice, data->surface);
|
||||
VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
|
||||
VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
|
||||
@@ -554,7 +605,7 @@ void createSwapChain(struct VulkanData* data, GLFWwindow* window) {
|
||||
vkGetSwapchainImagesKHR(data->device, data->swapChain, &imageCount, data->swapChainImages);
|
||||
}
|
||||
|
||||
void createImageViews(struct VulkanData* data) {
|
||||
static void createImageViews(struct VulkanData* data) {
|
||||
for (int i = 0; i < data->imageCount; i++) {
|
||||
VkImageViewCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
@@ -577,7 +628,7 @@ void createImageViews(struct VulkanData* data) {
|
||||
}
|
||||
}
|
||||
|
||||
void readFile(const char* fileName, char buffer[], int len) {
|
||||
static void readFile(const char* fileName, char buffer[], int len) {
|
||||
FILE* file = fopen(fileName, "r");
|
||||
if (!file) {
|
||||
printf("ERROR: File \"%s\" can't be opened \n", fileName);
|
||||
@@ -587,7 +638,7 @@ void readFile(const char* fileName, char buffer[], int len) {
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
uint32_t fileSize(const char* fileName) {
|
||||
static uint32_t fileSize(const char* fileName) {
|
||||
FILE* file = fopen(fileName, "r");
|
||||
if (!file) {
|
||||
printf("ERROR: File \"%s\" can't be opened \n", fileName);
|
||||
@@ -601,7 +652,7 @@ uint32_t fileSize(const char* fileName) {
|
||||
return size;
|
||||
}
|
||||
|
||||
VkShaderModule createShaderModule(const char* code, uint32_t size, VkDevice device) {
|
||||
static VkShaderModule createShaderModule(const char* code, uint32_t size, VkDevice device) {
|
||||
VkShaderModuleCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
||||
.codeSize = size,
|
||||
@@ -614,7 +665,7 @@ VkShaderModule createShaderModule(const char* code, uint32_t size, VkDevice devi
|
||||
return shaderModule;
|
||||
}
|
||||
|
||||
void createGraphicsPipeline(struct VulkanData* data) {
|
||||
static void createGraphicsPipeline(struct VulkanData* data) {
|
||||
const char* vertFileName = "shaders/vert.spv";
|
||||
uint32_t vertLen = fileSize(vertFileName);
|
||||
char vertShaderCode[vertLen];
|
||||
@@ -643,7 +694,7 @@ void createGraphicsPipeline(struct VulkanData* data) {
|
||||
.pSpecializationInfo = NULL,
|
||||
};
|
||||
|
||||
VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo};
|
||||
VkPipelineShaderStageCreateInfo shaderStages[2] = {vertShaderStageInfo, fragShaderStageInfo};
|
||||
|
||||
uint32_t dynamicStateCount = 2;
|
||||
VkDynamicState dynamicStates[] = {
|
||||
@@ -657,12 +708,28 @@ void createGraphicsPipeline(struct VulkanData* data) {
|
||||
.pDynamicStates = dynamicStates,
|
||||
};
|
||||
|
||||
VkVertexInputBindingDescription bindingDescription = getBindingDescription();
|
||||
VkVertexInputAttributeDescription attributeDescriptions[2] = {
|
||||
{
|
||||
.binding = 0,
|
||||
.location = 0,
|
||||
.format = VK_FORMAT_R32G32_SFLOAT,
|
||||
.offset = offsetof(Vertex, pos),
|
||||
},
|
||||
{
|
||||
.binding = 0,
|
||||
.location = 1,
|
||||
.format = VK_FORMAT_R32G32B32_SFLOAT,
|
||||
.offset = offsetof(Vertex, color),
|
||||
}
|
||||
};
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.vertexBindingDescriptionCount = 0,
|
||||
.pVertexBindingDescriptions = NULL, // Optional
|
||||
.vertexAttributeDescriptionCount = 0,
|
||||
.pVertexAttributeDescriptions = NULL, // Optional
|
||||
.vertexBindingDescriptionCount = 1,
|
||||
.vertexAttributeDescriptionCount = 2,
|
||||
.pVertexBindingDescriptions = &bindingDescription,
|
||||
.pVertexAttributeDescriptions = attributeDescriptions,
|
||||
};
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssembly = {
|
||||
@@ -781,7 +848,7 @@ void createGraphicsPipeline(struct VulkanData* data) {
|
||||
vkDestroyShaderModule(data->device, vertShaderModule, NULL);
|
||||
}
|
||||
|
||||
void createRenderPass(struct VulkanData* data) {
|
||||
static void createRenderPass(struct VulkanData* data) {
|
||||
VkAttachmentDescription colorAttachment = {
|
||||
.format = data->swapChainImageFormat,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
@@ -829,7 +896,7 @@ void createRenderPass(struct VulkanData* data) {
|
||||
}
|
||||
}
|
||||
|
||||
void createFramebuffers(struct VulkanData* data) {
|
||||
static void createFramebuffers(struct VulkanData* data) {
|
||||
for (int i = 0; i < data->imageCount; i++) {
|
||||
VkImageView attachments[] = {
|
||||
data->swapChainImageViews[i]
|
||||
@@ -852,7 +919,7 @@ void createFramebuffers(struct VulkanData* data) {
|
||||
}
|
||||
}
|
||||
|
||||
void createCommandPool(struct VulkanData* data) {
|
||||
static void createCommandPool(struct VulkanData* data) {
|
||||
struct QueueFamilyIndices queueFamilyIndices = findQueueFamilies(data->physicalDevice, data->surface);
|
||||
|
||||
VkCommandPoolCreateInfo poolInfo = {
|
||||
@@ -867,22 +934,22 @@ void createCommandPool(struct VulkanData* data) {
|
||||
}
|
||||
}
|
||||
|
||||
void createCommandBuffer(struct VulkanData* data) {
|
||||
static void createCommandBuffers(struct VulkanData* data) {
|
||||
VkCommandBufferAllocateInfo allocInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.commandPool = data->commandPool,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandBufferCount = 1,
|
||||
.commandBufferCount = MAX_FRAMES_IN_FLIGHT,
|
||||
};
|
||||
|
||||
if (vkAllocateCommandBuffers(data->device, &allocInfo, &data->commandBuffer) != VK_SUCCESS) {
|
||||
if (vkAllocateCommandBuffers(data->device, &allocInfo, &data->commandBuffers[data->currentFrame]) != VK_SUCCESS) {
|
||||
fprintf(stderr, "ERROR: Failed to allocate command buffers\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex, struct VulkanData* data) {
|
||||
static void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex, struct VulkanData* data) {
|
||||
VkCommandBufferBeginInfo beginInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
.flags = 0,
|
||||
@@ -909,6 +976,10 @@ void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex, str
|
||||
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, data->graphicsPipeline);
|
||||
|
||||
VkBuffer vertexBuffers[] = {data->vertexBuffer};
|
||||
VkDeviceSize offsets[] = {0};
|
||||
vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
|
||||
|
||||
VkViewport viewport = {
|
||||
.x = 0.0f,
|
||||
.y = 0.0f,
|
||||
@@ -924,7 +995,7 @@ void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex, str
|
||||
.extent = data->swapChainExtent,
|
||||
};
|
||||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||
vkCmdDraw(commandBuffer, 3, 1, 0, 0);
|
||||
vkCmdDraw(commandBuffer, VERTEX_COUNT, 1, 0, 0);
|
||||
vkCmdEndRenderPass(commandBuffer);
|
||||
if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) {
|
||||
fprintf(stderr, "ERROR: Failed to record command buffer\n");
|
||||
@@ -932,29 +1003,64 @@ void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex, str
|
||||
}
|
||||
}
|
||||
|
||||
void drawFrame(struct VulkanData* data) {
|
||||
vkWaitForFences(data->device, 1, &data->inFlightFence, VK_TRUE, UINT64_MAX);
|
||||
vkResetFences(data->device, 1, &data->inFlightFence);
|
||||
static void cleanupSwapChain(struct VulkanData* data) {
|
||||
for (int i = 0; i < data->imageCount; i++) {
|
||||
vkDestroyFramebuffer(data->device, data->swapChainFramebuffers[i], NULL);
|
||||
}
|
||||
|
||||
for (int i = 0; i < data->imageCount; i++) {
|
||||
vkDestroyImageView(data->device, data->swapChainImageViews[i], NULL);
|
||||
}
|
||||
|
||||
vkDestroySwapchainKHR(data->device, data->swapChain, NULL);
|
||||
}
|
||||
|
||||
static void recreateSwapChain(struct VulkanData* data, GLFWwindow* window) {
|
||||
int width = 0, height = 0;
|
||||
glfwGetFramebufferSize(window, &width, &height);
|
||||
while (width == 0 || height == 0) {
|
||||
glfwGetFramebufferSize(window, &width, &height);
|
||||
glfwWaitEvents();
|
||||
}
|
||||
vkDeviceWaitIdle(data->device);
|
||||
cleanupSwapChain(data);
|
||||
createSwapChain(data, window);
|
||||
createImageViews(data);
|
||||
createFramebuffers(data);
|
||||
}
|
||||
|
||||
static void drawFrame(struct VulkanData* data, GLFWwindow* window) {
|
||||
vkWaitForFences(data->device, 1, &data->inFlightFences[data->currentFrame], VK_TRUE, UINT64_MAX);
|
||||
|
||||
uint32_t imageIndex;
|
||||
vkAcquireNextImageKHR(data->device, data->swapChain, UINT64_MAX, data->imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
|
||||
vkResetCommandBuffer(data->commandBuffer, 0);
|
||||
recordCommandBuffer(data->commandBuffer, imageIndex, data);
|
||||
VkResult result = vkAcquireNextImageKHR(data->device, data->swapChain, UINT64_MAX, data->imageAvailableSemaphores[data->currentFrame], VK_NULL_HANDLE, &imageIndex);
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||
recreateSwapChain(data, window);
|
||||
return;
|
||||
} else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
|
||||
fprintf(stderr, "ERROR: Failed to acquire swap chain image");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
VkSemaphore waitSemaphores[] = {data->imageAvailableSemaphore};
|
||||
vkResetFences(data->device, 1, &data->inFlightFences[data->currentFrame]);
|
||||
|
||||
vkResetCommandBuffer(data->commandBuffers[data->currentFrame], 0);
|
||||
recordCommandBuffer(data->commandBuffers[data->currentFrame], imageIndex, data);
|
||||
|
||||
VkSemaphore waitSemaphores[] = {data->imageAvailableSemaphores[data->currentFrame]};
|
||||
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
||||
VkSemaphore signalSemaphores[] = {data->renderFinishedSemaphore};
|
||||
VkSemaphore signalSemaphores[] = {data->renderFinishedSemaphores[data->currentFrame]};
|
||||
VkSubmitInfo submitInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = waitSemaphores,
|
||||
.pWaitDstStageMask = waitStages,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &data->commandBuffer,
|
||||
.pCommandBuffers = &data->commandBuffers[data->currentFrame],
|
||||
.signalSemaphoreCount = 1,
|
||||
.pSignalSemaphores = signalSemaphores,
|
||||
};
|
||||
if (vkQueueSubmit(data->graphicsQueue, 1, &submitInfo, data->inFlightFence) != VK_SUCCESS) {
|
||||
if (vkQueueSubmit(data->graphicsQueue, 1, &submitInfo, data->inFlightFences[data->currentFrame]) != VK_SUCCESS) {
|
||||
fprintf(stderr, "ERROR: Failed to submit draw command buffer\n");
|
||||
exit(1);
|
||||
}
|
||||
@@ -970,10 +1076,18 @@ void drawFrame(struct VulkanData* data) {
|
||||
.pResults = NULL,
|
||||
};
|
||||
|
||||
vkQueuePresentKHR(data->presentQueue, &presentInfo);
|
||||
result = vkQueuePresentKHR(data->presentQueue, &presentInfo);
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || data->framebufferResized) {
|
||||
data->framebufferResized = false;
|
||||
recreateSwapChain(data, window);
|
||||
} else if (result != VK_SUCCESS) {
|
||||
fprintf(stderr, "ERROR: Failed to present swap chain image");
|
||||
exit(1);
|
||||
}
|
||||
data->currentFrame = (data->currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
|
||||
}
|
||||
|
||||
void createSyncObjects(struct VulkanData* data) {
|
||||
static void createSyncObjects(struct VulkanData* data) {
|
||||
VkSemaphoreCreateInfo semaphoreInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||
};
|
||||
@@ -981,16 +1095,68 @@ void createSyncObjects(struct VulkanData* data) {
|
||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
||||
.flags = VK_FENCE_CREATE_SIGNALED_BIT,
|
||||
};
|
||||
if (vkCreateSemaphore(data->device, &semaphoreInfo, NULL, &data->imageAvailableSemaphore) != VK_SUCCESS ||
|
||||
vkCreateSemaphore(data->device, &semaphoreInfo, NULL, &data->renderFinishedSemaphore) != VK_SUCCESS ||
|
||||
vkCreateFence(data->device, &fenceInfo, NULL, &data->inFlightFence) != VK_SUCCESS) {
|
||||
fprintf(stderr, "ERROR: Failed to create semaphores\n");
|
||||
exit(1);
|
||||
for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
||||
if (vkCreateSemaphore(data->device, &semaphoreInfo, NULL, &data->imageAvailableSemaphores[i]) != VK_SUCCESS ||
|
||||
vkCreateSemaphore(data->device, &semaphoreInfo, NULL, &data->renderFinishedSemaphores[i]) != VK_SUCCESS ||
|
||||
vkCreateFence(data->device, &fenceInfo, NULL, &data->inFlightFences[i]) != VK_SUCCESS) {
|
||||
fprintf(stderr, "ERROR: Failed to create semaphores\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct VulkanData initVulkan(GLFWwindow* window) {
|
||||
uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties, struct VulkanData* data) {
|
||||
VkPhysicalDeviceMemoryProperties memProperties;
|
||||
vkGetPhysicalDeviceMemoryProperties(data->physicalDevice, &memProperties);
|
||||
|
||||
for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
|
||||
if (typeFilter & (1 << i) && (memProperties.memoryTypes[i].propertyFlags & properties)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "ERROR: Failed to find suitable memory type\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void createVertexBuffer(struct VulkanData* data) {
|
||||
VkBufferCreateInfo bufferInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.size = sizeof(vertices[0]) * VERTEX_COUNT,
|
||||
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
if (vkCreateBuffer(data->device, &bufferInfo, NULL, &data->vertexBuffer) != VK_SUCCESS) {
|
||||
fprintf(stderr, "ERROR: Failed to create vertex buffer\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
VkMemoryRequirements memRequirements;
|
||||
vkGetBufferMemoryRequirements(data->device, data->vertexBuffer, &memRequirements);
|
||||
|
||||
VkMemoryAllocateInfo allocInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.allocationSize = memRequirements.size,
|
||||
.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, data),
|
||||
};
|
||||
|
||||
if (vkAllocateMemory(data->device, &allocInfo, NULL, &data->vertexBufferMemory) != VK_SUCCESS) {
|
||||
fprintf(stderr, "ERROR: Failed to allocate vertex buffer memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
vkBindBufferMemory(data->device, data->vertexBuffer, data->vertexBufferMemory, 0);
|
||||
void* vertexData;
|
||||
vkMapMemory(data->device, data->vertexBufferMemory, 0, bufferInfo.size, 0, &vertexData);
|
||||
memcpy(vertexData, vertices, bufferInfo.size);
|
||||
vkUnmapMemory(data->device, data->vertexBufferMemory);
|
||||
}
|
||||
|
||||
static struct VulkanData initVulkan(GLFWwindow* window) {
|
||||
struct VulkanData data;
|
||||
data.currentFrame = 0;
|
||||
data.framebufferResized = 0;
|
||||
createInstance(&data);
|
||||
setupDebugMessenger(&data);
|
||||
createSurface(&data, window);
|
||||
@@ -1002,16 +1168,17 @@ struct VulkanData initVulkan(GLFWwindow* window) {
|
||||
createGraphicsPipeline(&data);
|
||||
createFramebuffers(&data);
|
||||
createCommandPool(&data);
|
||||
createCommandBuffer(&data);
|
||||
createVertexBuffer(&data);
|
||||
createCommandBuffers(&data);
|
||||
createSyncObjects(&data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void mainLoop(GLFWwindow* window, struct VulkanData* data) {
|
||||
static void mainLoop(GLFWwindow* window, struct VulkanData* data) {
|
||||
while (!glfwWindowShouldClose(window)) {
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
drawFrame(data);
|
||||
drawFrame(data, window);
|
||||
int state = glfwGetKey(window, GLFW_KEY_Q);
|
||||
if (state == GLFW_PRESS) {
|
||||
break;
|
||||
@@ -1021,21 +1188,19 @@ void mainLoop(GLFWwindow* window, struct VulkanData* data) {
|
||||
vkDeviceWaitIdle(data->device);
|
||||
}
|
||||
|
||||
void cleanup(GLFWwindow* window, struct VulkanData* data) {
|
||||
vkDestroySemaphore(data->device, data->imageAvailableSemaphore, NULL);
|
||||
vkDestroySemaphore(data->device, data->renderFinishedSemaphore, NULL);
|
||||
vkDestroyFence(data->device, data->inFlightFence, NULL);
|
||||
vkDestroyCommandPool(data->device, data->commandPool, NULL);
|
||||
for (int i = 0; i < data->imageCount; i++) {
|
||||
vkDestroyFramebuffer(data->device, data->swapChainFramebuffers[i], NULL);
|
||||
}
|
||||
static void cleanup(GLFWwindow* window, struct VulkanData* data) {
|
||||
cleanupSwapChain(data);
|
||||
vkDestroyBuffer(data->device, data->vertexBuffer, NULL);
|
||||
vkFreeMemory(data->device, data->vertexBufferMemory, NULL);
|
||||
vkDestroyPipeline(data->device, data->graphicsPipeline, NULL);
|
||||
vkDestroyPipelineLayout(data->device, data->pipelineLayout, NULL);
|
||||
vkDestroyRenderPass(data->device, data->renderPass, NULL);
|
||||
for (int i = 0; i < data->imageCount; i++) {
|
||||
vkDestroyImageView(data->device, data->swapChainImageViews[i], NULL);
|
||||
for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
||||
vkDestroySemaphore(data->device, data->imageAvailableSemaphores[i], NULL);
|
||||
vkDestroySemaphore(data->device, data->renderFinishedSemaphores[i], NULL);
|
||||
vkDestroyFence(data->device, data->inFlightFences[i], NULL);
|
||||
}
|
||||
vkDestroySwapchainKHR(data->device, data->swapChain, NULL);
|
||||
vkDestroyCommandPool(data->device, data->commandPool, NULL);
|
||||
vkDestroyDevice(data->device, NULL);
|
||||
if (enableValidationLayers) {
|
||||
DestroyDebugUtilsMessengerEXT(data->instance, data->debugMessenger, NULL);
|
||||
@@ -1046,9 +1211,10 @@ void cleanup(GLFWwindow* window, struct VulkanData* data) {
|
||||
glfwTerminate();
|
||||
}
|
||||
|
||||
void run() {
|
||||
GLFWwindow* window = initWindow();
|
||||
struct VulkanData data = initVulkan(window);
|
||||
static void run() {
|
||||
struct VulkanData data;
|
||||
GLFWwindow* window = initWindow(&data);
|
||||
data = initVulkan(window);
|
||||
mainLoop(window, &data);
|
||||
cleanup(window, &data);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
layout(location = 0) in vec3 fragColor;
|
||||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
layout(location = 1) out vec4 outColor;
|
||||
|
||||
void main() {
|
||||
outColor = vec4(fragColor, 1.0);
|
||||
|
||||
@@ -1,20 +1,11 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 inPosition;
|
||||
layout(location = 1) in vec3 inColor;
|
||||
|
||||
layout(location = 0) out vec3 fragColor;
|
||||
|
||||
vec2 positions[3] = vec2[](
|
||||
vec2(0.0, -0.5),
|
||||
vec2(0.5, 0.5),
|
||||
vec2(-0.5, 0.5)
|
||||
);
|
||||
|
||||
vec3 colors[3] = vec3[](
|
||||
vec3(1.0, 0.0, 0.0),
|
||||
vec3(0.0, 1.0, 0.0),
|
||||
vec3(0.0, 0.0, 1.0)
|
||||
);
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
|
||||
fragColor = colors[gl_VertexIndex];
|
||||
gl_Position = vec4(inPosition, 0.0, 1.0);
|
||||
fragColor = inColor;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user