|
|
|
@ -1,4 +1,5 @@
@@ -1,4 +1,5 @@
|
|
|
|
|
#define GLFW_INCLUDE_VULKAN |
|
|
|
|
#define GLM_FORCE_DEPTH_ZERO_TO_ONE |
|
|
|
|
#include <GLFW/glfw3.h> |
|
|
|
|
#include <vulkan/vulkan.h> |
|
|
|
|
|
|
|
|
@ -95,6 +96,10 @@ typedef struct ApplicationState {
@@ -95,6 +96,10 @@ typedef struct ApplicationState {
|
|
|
|
|
VkDeviceMemory texture_image_memory; |
|
|
|
|
VkImageView texture_image_view; |
|
|
|
|
VkSampler texture_sampler; |
|
|
|
|
|
|
|
|
|
VkImage depth_image; |
|
|
|
|
VkDeviceMemory depth_image_memory; |
|
|
|
|
VkImageView depth_image_view; |
|
|
|
|
} ApplicationState; |
|
|
|
|
|
|
|
|
|
typedef struct QueueFamilyIndices { |
|
|
|
@ -105,20 +110,27 @@ typedef struct QueueFamilyIndices {
@@ -105,20 +110,27 @@ typedef struct QueueFamilyIndices {
|
|
|
|
|
} QueueFamilyIndices; |
|
|
|
|
|
|
|
|
|
typedef struct Vertex { |
|
|
|
|
vec2 position; |
|
|
|
|
vec3 position; |
|
|
|
|
vec3 color; |
|
|
|
|
vec2 tex_coord; |
|
|
|
|
} Vertex; |
|
|
|
|
|
|
|
|
|
const Vertex vertices[] = { |
|
|
|
|
{{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f}}, |
|
|
|
|
{{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f}}, |
|
|
|
|
{{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}, {0.0f, 1.0f}}, |
|
|
|
|
{{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}} |
|
|
|
|
{{-0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}}, |
|
|
|
|
{{0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}}, |
|
|
|
|
{{0.5f, 0.5f, 0.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}}, |
|
|
|
|
{{-0.5f, 0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}}, |
|
|
|
|
|
|
|
|
|
{{-0.5f, -0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}}, |
|
|
|
|
{{0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}}, |
|
|
|
|
{{0.5f, 0.5f, -0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}}, |
|
|
|
|
{{-0.5f, 0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const uint16_t indices[] = { |
|
|
|
|
0, 1, 2, 2, 3, 0 |
|
|
|
|
0, 1, 2, 2, 3, 0, |
|
|
|
|
4, 5, 6, 6, 7, 4 |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
typedef struct UBO { |
|
|
|
@ -643,6 +655,16 @@ void create_render_pass(ApplicationState* state) {
@@ -643,6 +655,16 @@ void create_render_pass(ApplicationState* state) {
|
|
|
|
|
//images to be presented
|
|
|
|
|
color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; |
|
|
|
|
|
|
|
|
|
VkAttachmentDescription depth_attachment = {0}; |
|
|
|
|
depth_attachment.format = VK_FORMAT_D32_SFLOAT; |
|
|
|
|
depth_attachment.samples = VK_SAMPLE_COUNT_1_BIT; |
|
|
|
|
depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; |
|
|
|
|
depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; |
|
|
|
|
depth_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
|
|
|
|
depth_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; |
|
|
|
|
depth_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
|
|
|
|
depth_attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; |
|
|
|
|
|
|
|
|
|
//there may be multiple subpasses, subpasses depend on the previous framebuffer contents
|
|
|
|
|
//they can be used for things sych as postprocessing
|
|
|
|
|
//every subpass references one or more attachment
|
|
|
|
@ -650,18 +672,24 @@ void create_render_pass(ApplicationState* state) {
@@ -650,18 +672,24 @@ void create_render_pass(ApplicationState* state) {
|
|
|
|
|
color_attachment_reference.attachment = 0; |
|
|
|
|
color_attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
|
|
|
|
|
|
|
|
|
VkAttachmentReference depth_attachment_reference = {0}; |
|
|
|
|
depth_attachment_reference.attachment = 1; |
|
|
|
|
depth_attachment_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; |
|
|
|
|
|
|
|
|
|
//now we create the subpass
|
|
|
|
|
//layout(location = 0) out vec4 outColor;
|
|
|
|
|
VkSubpassDescription subpass = {0}; |
|
|
|
|
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; |
|
|
|
|
subpass.colorAttachmentCount = 1; |
|
|
|
|
subpass.pColorAttachments = &color_attachment_reference; |
|
|
|
|
subpass.pDepthStencilAttachment = &depth_attachment_reference; |
|
|
|
|
|
|
|
|
|
VkAttachmentDescription attachments[2] = {color_attachment, depth_attachment}; |
|
|
|
|
//let's create the render pass
|
|
|
|
|
VkRenderPassCreateInfo render_pass_info = {0}; |
|
|
|
|
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; |
|
|
|
|
render_pass_info.attachmentCount = 1; |
|
|
|
|
render_pass_info.pAttachments = &color_attachment; |
|
|
|
|
render_pass_info.attachmentCount = ARRSIZE(attachments); |
|
|
|
|
render_pass_info.pAttachments = attachments; |
|
|
|
|
render_pass_info.subpassCount = 1; |
|
|
|
|
render_pass_info.pSubpasses = &subpass; |
|
|
|
|
|
|
|
|
@ -680,11 +708,11 @@ void create_render_pass(ApplicationState* state) {
@@ -680,11 +708,11 @@ void create_render_pass(ApplicationState* state) {
|
|
|
|
|
dependency.srcSubpass = VK_SUBPASS_EXTERNAL; |
|
|
|
|
dependency.dstSubpass = 0; |
|
|
|
|
//wait on the color attachment
|
|
|
|
|
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; |
|
|
|
|
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; |
|
|
|
|
dependency.srcAccessMask = 0; |
|
|
|
|
//the part of the subpass when the attachment is written has to wait
|
|
|
|
|
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; |
|
|
|
|
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; |
|
|
|
|
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; |
|
|
|
|
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; |
|
|
|
|
|
|
|
|
|
render_pass_info.dependencyCount = 1; |
|
|
|
|
render_pass_info.pDependencies = &dependency; |
|
|
|
@ -786,7 +814,7 @@ void create_graphics_pipeline(ApplicationState* state) {
@@ -786,7 +814,7 @@ void create_graphics_pipeline(ApplicationState* state) {
|
|
|
|
|
|
|
|
|
|
//We have position and color, so we need two descriptions
|
|
|
|
|
VkVertexInputAttributeDescription attribute_description[3] = { |
|
|
|
|
{.binding = 0, .location = 0, .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(Vertex, position)}, |
|
|
|
|
{.binding = 0, .location = 0, .format = VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(Vertex, position)}, |
|
|
|
|
{.binding = 0, .location = 1, .format = VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(Vertex, color)}, |
|
|
|
|
{.binding = 0, .location = 2, .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(Vertex, tex_coord)}, |
|
|
|
|
}; |
|
|
|
@ -891,6 +919,16 @@ void create_graphics_pipeline(ApplicationState* state) {
@@ -891,6 +919,16 @@ void create_graphics_pipeline(ApplicationState* state) {
|
|
|
|
|
|
|
|
|
|
printf("created pipeline layout\n"); |
|
|
|
|
|
|
|
|
|
VkPipelineDepthStencilStateCreateInfo depth_stencil = {0}; |
|
|
|
|
depth_stencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; |
|
|
|
|
depth_stencil.depthTestEnable = VK_TRUE; |
|
|
|
|
depth_stencil.depthWriteEnable = VK_TRUE; |
|
|
|
|
depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS; |
|
|
|
|
depth_stencil.depthBoundsTestEnable = VK_FALSE; |
|
|
|
|
depth_stencil.minDepthBounds = 0.0f; // Optional
|
|
|
|
|
depth_stencil.maxDepthBounds = 1.0f; // Optional
|
|
|
|
|
depth_stencil.stencilTestEnable = VK_FALSE; |
|
|
|
|
|
|
|
|
|
VkGraphicsPipelineCreateInfo pipeline_info = {0}; |
|
|
|
|
pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; |
|
|
|
|
//shaders
|
|
|
|
@ -905,6 +943,7 @@ void create_graphics_pipeline(ApplicationState* state) {
@@ -905,6 +943,7 @@ void create_graphics_pipeline(ApplicationState* state) {
|
|
|
|
|
pipeline_info.pDepthStencilState = NULL; // Optional
|
|
|
|
|
pipeline_info.pColorBlendState = &color_blending; |
|
|
|
|
pipeline_info.pDynamicState = &dynamic_state; |
|
|
|
|
pipeline_info.pDepthStencilState = &depth_stencil; |
|
|
|
|
|
|
|
|
|
pipeline_info.layout = state->pipeline_layout; |
|
|
|
|
pipeline_info.renderPass = state->render_pass; |
|
|
|
@ -931,13 +970,14 @@ void create_framebuffers(ApplicationState* state) {
@@ -931,13 +970,14 @@ void create_framebuffers(ApplicationState* state) {
|
|
|
|
|
for (int i = 0; i < state->swapchain_image_count; i++) { |
|
|
|
|
printf("creating framebuffer %x\n", i); |
|
|
|
|
VkImageView attachments[] = { |
|
|
|
|
state->swapchain_image_views[i] |
|
|
|
|
state->swapchain_image_views[i], |
|
|
|
|
state->depth_image_view |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
VkFramebufferCreateInfo framebuffer_info = {0}; |
|
|
|
|
framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; |
|
|
|
|
framebuffer_info.renderPass = state->render_pass; |
|
|
|
|
framebuffer_info.attachmentCount = 1; |
|
|
|
|
framebuffer_info.attachmentCount = ARRSIZE(attachments); |
|
|
|
|
framebuffer_info.pAttachments = attachments; |
|
|
|
|
framebuffer_info.width = state->swapchain_extent.width; |
|
|
|
|
framebuffer_info.height = state->swapchain_extent.height; |
|
|
|
@ -1136,7 +1176,7 @@ void create_image(ApplicationState* state, uint32_t width, uint32_t height, VkFo
@@ -1136,7 +1176,7 @@ void create_image(ApplicationState* state, uint32_t width, uint32_t height, VkFo
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
VkMemoryRequirements mem_req; |
|
|
|
|
vkGetImageMemoryRequirements(state->device, state->texture_image, &mem_req); |
|
|
|
|
vkGetImageMemoryRequirements(state->device, *image, &mem_req); |
|
|
|
|
|
|
|
|
|
VkMemoryAllocateInfo alloc_info = {0}; |
|
|
|
|
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
|
|
|
@ -1224,6 +1264,27 @@ void copy_buffer_to_image(ApplicationState* state, VkBuffer to_copy, VkImage ima
@@ -1224,6 +1264,27 @@ void copy_buffer_to_image(ApplicationState* state, VkBuffer to_copy, VkImage ima
|
|
|
|
|
end_single_time_commands(state, buffer); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void create_depth_resources(ApplicationState* state) { |
|
|
|
|
create_image(state, state->swapchain_extent.width, state->swapchain_extent.height, VK_FORMAT_D32_SFLOAT, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, |
|
|
|
|
&state->depth_image, &state->depth_image_memory); |
|
|
|
|
|
|
|
|
|
VkImageViewCreateInfo view_info = {0}; |
|
|
|
|
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; |
|
|
|
|
view_info.image = state->depth_image; |
|
|
|
|
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; |
|
|
|
|
view_info.format = VK_FORMAT_D32_SFLOAT; |
|
|
|
|
view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; |
|
|
|
|
view_info.subresourceRange.baseMipLevel = 0; |
|
|
|
|
view_info.subresourceRange.levelCount = 1; |
|
|
|
|
view_info.subresourceRange.baseArrayLayer = 0; |
|
|
|
|
view_info.subresourceRange.layerCount = 1; |
|
|
|
|
|
|
|
|
|
if (vkCreateImageView(state->device, &view_info, NULL, &state->depth_image_view) != VK_SUCCESS) { |
|
|
|
|
printf("failed to create texture image view\n"); |
|
|
|
|
exit(1); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void create_texture_image(ApplicationState* state) { |
|
|
|
|
int width, height, channels; |
|
|
|
|
stbi_uc* pixels = stbi_load("../src/res/texture.jpg", &width, &height, &channels, STBI_rgb_alpha); |
|
|
|
@ -1420,9 +1481,17 @@ void record_command_buffer(ApplicationState* state, VkCommandBuffer command_buff
@@ -1420,9 +1481,17 @@ void record_command_buffer(ApplicationState* state, VkCommandBuffer command_buff
|
|
|
|
|
render_pass_info.renderArea.offset.y = 0; |
|
|
|
|
render_pass_info.renderArea.extent = state->swapchain_extent; |
|
|
|
|
|
|
|
|
|
VkClearValue clearColor = {0}; |
|
|
|
|
render_pass_info.clearValueCount = 1; |
|
|
|
|
render_pass_info.pClearValues = &clearColor; |
|
|
|
|
VkClearValue clear_color = {0}; |
|
|
|
|
VkClearValue stencil_clear; |
|
|
|
|
stencil_clear.depthStencil.depth = 1.0f; |
|
|
|
|
stencil_clear.depthStencil.stencil = 0; |
|
|
|
|
|
|
|
|
|
VkClearValue clear_values[2]; |
|
|
|
|
clear_values[0] = clear_color; |
|
|
|
|
clear_values[1] = stencil_clear; |
|
|
|
|
|
|
|
|
|
render_pass_info.clearValueCount = ARRSIZE(clear_values); |
|
|
|
|
render_pass_info.pClearValues = clear_values; |
|
|
|
|
|
|
|
|
|
//can also be VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS to execute command stored in secondary buffers
|
|
|
|
|
vkCmdBeginRenderPass(command_buffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); |
|
|
|
@ -1496,8 +1565,9 @@ void init_vulkan(ApplicationState* state) {
@@ -1496,8 +1565,9 @@ void init_vulkan(ApplicationState* state) {
|
|
|
|
|
create_render_pass(state); |
|
|
|
|
create_descriptor_set_layout(state); |
|
|
|
|
create_graphics_pipeline(state); |
|
|
|
|
create_framebuffers(state); |
|
|
|
|
create_command_pool(state); |
|
|
|
|
create_depth_resources(state); |
|
|
|
|
create_framebuffers(state); |
|
|
|
|
create_texture_image(state); |
|
|
|
|
create_texture_image_view(state); |
|
|
|
|
create_texture_image_sampler(state); |
|
|
|
@ -1512,6 +1582,7 @@ void init_vulkan(ApplicationState* state) {
@@ -1512,6 +1582,7 @@ void init_vulkan(ApplicationState* state) {
|
|
|
|
|
|
|
|
|
|
void update_uniform_buffer(ApplicationState* state, uint32_t current_frame) { |
|
|
|
|
uint64_t time = clock() / (CLOCKS_PER_SEC / 1000); |
|
|
|
|
time = 0; |
|
|
|
|
|
|
|
|
|
UBO ubo = {0}; |
|
|
|
|
glm_mat4_identity(ubo.model); |
|
|
|
@ -1626,6 +1697,9 @@ void terminate(ApplicationState* state) {
@@ -1626,6 +1697,9 @@ void terminate(ApplicationState* state) {
|
|
|
|
|
vkDestroyImageView(state->device, state->texture_image_view, NULL); |
|
|
|
|
vkDestroyImage(state->device, state->texture_image, NULL); |
|
|
|
|
vkFreeMemory(state->device, state->texture_image_memory, NULL); |
|
|
|
|
vkDestroyImageView(state->device, state->depth_image_view, NULL); |
|
|
|
|
vkDestroyImage(state->device, state->depth_image, NULL); |
|
|
|
|
vkFreeMemory(state->device, state->depth_image_memory, NULL); |
|
|
|
|
|
|
|
|
|
vkDestroySwapchainKHR(state->device, state->swapchain, NULL); |
|
|
|
|
vkDestroyDevice(state->device, NULL); |
|
|
|
|