Compare commits

...

3 Commits

Author SHA1 Message Date
45ee4f0056 화면크기변경 로직 추가 2025-05-17 20:13:34 +09:00
bba916f29e 일단 완성 2025-05-17 12:34:03 +09:00
6ec8ce37d0 그래픽 파이프라인까지 완료 2025-04-10 22:01:07 +09:00
25 changed files with 9868 additions and 68 deletions

View File

@@ -38,6 +38,14 @@ FetchContent_Declare(
)
FetchContent_MakeAvailable(GSL)
FetchContent_Declare(
ASSIMP
GIT_REPOSITORY "https://github.com/assimp/assimp.git"
GIT_TAG "v5.4.3"
GIT_SHALLOW ON
)
FetchContent_MakeAvailable(ASSIMP)
file(GLOB_RECURSE VulkanEngineSources CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/glfw/*.cpp"
@@ -50,6 +58,7 @@ target_link_libraries(VulkanEngine PRIVATE glm)
target_link_libraries(VulkanEngine PRIVATE glfw)
target_link_libraries(VulkanEngine PRIVATE Microsoft.GSL::GSL)
target_link_libraries(VulkanEngine PRIVATE spdlog)
target_link_libraries(VulkanEngine PRIVATE assimp::assimp)
target_include_directories(VulkanEngine PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_compile_features(VulkanEngine PRIVATE cxx_std_20)
@@ -62,4 +71,7 @@ file(GLOB_RECURSE ShaderSources CONFIGURE_DEPENDS
)
add_shaders(VulkanEngineShaders ${ShaderSources})
add_dependencies(VulkanEngine VulkanEngineShaders)
add_dependencies(VulkanEngine VulkanEngineShaders)
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/assets/paving-stones.jpg" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/assets")
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/assets/player.fbx" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/assets")

15
CMakeSettings.json Normal file
View File

@@ -0,0 +1,15 @@
{
"configurations": [
{
"name": "x64-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": ""
}
]
}

BIN
assets/paving-stones.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

BIN
assets/player.fbx Normal file

Binary file not shown.

View File

@@ -12,3 +12,5 @@
#include "spdlog/spdlog.h"
#include "utilities.h"
#define MAX_BUFFERED_FRAMES (2)

8422
include/stb/stb_image.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
#pragma once
#include <vulkan/vulkan.h>
namespace veng {
struct BufferHandle {
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE;
};
} // namespace veng

View File

@@ -1,15 +1,46 @@
#pragma once
#include <vulkan/vulkan.h>
#include "buffer_handle.h"
#include "glfw/glfw_window.h"
#include "precomp.h"
#include "texture_handle.h"
#include "vertex.h"
namespace veng {
struct Frame {
VkSemaphore image_available_signal = VK_NULL_HANDLE;
VkSemaphore render_finished_signal = VK_NULL_HANDLE;
VkFence still_rendering_fence = VK_NULL_HANDLE;
VkCommandBuffer command_buffer = VK_NULL_HANDLE;
VkDescriptorSet uniform_set = VK_NULL_HANDLE;
BufferHandle uniform_buffer;
void* uniform_buffer_location;
};
class Graphics final {
public:
Graphics(gsl::not_null<Window *> window);
Graphics(gsl::not_null<Window*> window);
~Graphics();
bool BeginFrame();
void SetModelMatrix(glm::mat4 model);
void SetViewProjection(glm::mat4 view, glm::mat4 projection);
void SetTexture(TextureHandle handle);
void RenderBuffer(BufferHandle handle, std::uint32_t vertex_count);
void RenderIndexedBuffer(BufferHandle vertex_buffer,
BufferHandle index_buffer, std::uint32_t count);
void EndFrame();
BufferHandle CreateVertexBuffer(gsl::span<Vertex> vertices);
BufferHandle CreateIndexBuffer(gsl::span<std::uint32_t> indices);
void DestroyBuffer(BufferHandle handle);
TextureHandle CreateTexture(gsl::czstring path);
void DestroyTexture(TextureHandle handle);
private:
struct QueueFamilyIndices {
std::optional<std::uint32_t> graphics_family = std::nullopt;
@@ -21,13 +52,15 @@ class Graphics final {
};
struct SwapChainProperties {
VkSurfaceCapabilitiesKHR capabilities;
VkSurfaceCapabilitiesKHR capabilities = {};
std::vector<VkSurfaceFormatKHR> formats;
std::vector<VkPresentModeKHR> present_modes;
bool IsValid() const { return !formats.empty() && !present_modes.empty(); }
};
// 초기화
void InitializeVulkan();
void CreateInstance();
void SetupDebugMessenger();
@@ -36,7 +69,25 @@ class Graphics final {
void CreateSurface();
void CreateSwapChain();
void CreateImageViews();
void CreateRenderPass();
void CreateGraphicsPipeline();
void CreateFramebuffers();
void CreateCommandPool();
void CreateCommandBuffer();
void CreateSignals();
void CreateDescriptorSetLayouts();
void CreateDescriptorPools();
void CreateDescriptorSets();
void CreateTextureSampler();
void CreateDepthResources();
void RecreateSwapChain();
void CleanupSwapChain();
// 랜더링
void BeginCommands();
void EndCommands();
std::vector<gsl::czstring> GetRequiredInstanceExtentions();
@@ -60,10 +111,32 @@ class Graphics final {
VkPresentModeKHR ChooseSwapPresentMode(
gsl::span<VkPresentModeKHR> present_modes);
VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities);
std::uint32_t ChooseSwapImageCount(const VkSurfaceCapabilitiesKHR& capabilities);
std::uint32_t ChooseSwapImageCount(
const VkSurfaceCapabilitiesKHR& capabilities);
VkShaderModule CreateShaderModule(gsl::span<std::uint8_t> buffer);
std::uint32_t FindMemoryType(std::uint32_t type_bits_filter,
VkMemoryPropertyFlags required_properties);
BufferHandle CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
VkMemoryPropertyFlags properties);
VkCommandBuffer BeginTransientCommandBuffer();
void EndTransientCommandBuffer(VkCommandBuffer command_buffer);
void CreateUniformBuffers();
TextureHandle CreateImage(glm::ivec2 size, VkFormat image_format,
VkBufferUsageFlags usage,
VkMemoryPropertyFlags properties);
void TransitionImageLayout(VkImage image, VkImageLayout old_layout,
VkImageLayout new_layout);
void CopyBufferToImage(VkBuffer buffer, VkImage image, glm::ivec2 image_size);
VkImageView CreateImageView(VkImage image, VkFormat format,
VkImageAspectFlags aspect_flag);
VkViewport GetViewport();
VkRect2D GetScissor();
std::array<gsl::czstring, 1> required_device_extentions_ = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME};
@@ -80,10 +153,33 @@ class Graphics final {
VkSurfaceFormatKHR surface_format_;
VkPresentModeKHR present_mode_;
VkExtent2D extent_;
std::vector<VkImage> swap_chain_images_;
std::vector<VkImageView> swap_chain_image_views_;
std::vector<VkFramebuffer> swap_chain_framebuffers_;
gsl::not_null<Window *> window_;
VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE;
VkRenderPass render_pass_ = VK_NULL_HANDLE;
VkPipeline pipeline_ = VK_NULL_HANDLE;
VkDescriptorSetLayout descriptor_set_layout_ = VK_NULL_HANDLE;
VkCommandPool command_pool_ = VK_NULL_HANDLE;
std::uint32_t current_image_index_ = 0;
VkDescriptorSetLayout uniform_set_layout_ = VK_NULL_HANDLE;
VkDescriptorPool uniform_pool_ = VK_NULL_HANDLE;
VkDescriptorSetLayout texture_set_layout_ = VK_NULL_HANDLE;
VkDescriptorPool texture_pool_ = VK_NULL_HANDLE;
VkSampler texture_sampler_ = VK_NULL_HANDLE;
TextureHandle depth_texture_;
std::array<Frame, MAX_BUFFERED_FRAMES> frames_;
std::int32_t current_frame_ = 0;
gsl::not_null<Window*> window_;
bool validation_enabled_ = false;
};

View File

@@ -0,0 +1,14 @@
#pragma once
#include <vulkan/vulkan.h>
namespace veng {
struct TextureHandle {
VkImage image = VK_NULL_HANDLE;
VkImageView image_view = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE;
VkDescriptorSet set = VK_NULL_HANDLE;
};
} // namespace veng

View File

@@ -0,0 +1,8 @@
#pragma once
namespace veng {
struct UniformTransformations {
glm::mat4 view;
glm::mat4 projection;
};
} // namespace veng

38
include/vulkan/vertex.h Normal file
View File

@@ -0,0 +1,38 @@
#pragma once
#include <vulkan/vulkan.h>
namespace veng {
struct Vertex {
Vertex() : position(glm::vec3(0.f)), uv(glm::vec2(0.f)) {}
Vertex(glm::vec3 _position, glm::vec2 _uv) : position(_position), uv(_uv) {}
glm::vec3 position;
glm::vec2 uv;
static VkVertexInputBindingDescription GetBindingDescription() {
VkVertexInputBindingDescription description = {};
description.binding = 0;
description.stride = sizeof(Vertex);
description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
return description;
}
static std::array<VkVertexInputAttributeDescription, 2> GetAttributeDescriptions() {
std::array<VkVertexInputAttributeDescription, 2> descriptions = {};
descriptions[0].binding = 0;
descriptions[0].location = 0;
descriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
descriptions[0].offset = offsetof(Vertex, position);
descriptions[1].binding = 0;
descriptions[1].location = 1;
descriptions[1].format = VK_FORMAT_R32G32_SFLOAT;
descriptions[1].offset = offsetof(Vertex, uv);
return descriptions;
}
};
} // namespace veng

View File

@@ -1,8 +1,11 @@
#version 450
#include "common.glsl"
layout(location = 0) in vec2 vertex_uv;
layout(location = 0) out vec4 out_color;
layout(set = 1, binding = 0) uniform sampler2D texture_sampler;
void main() {
out_color = vec4(1.0, 0.0, 0.5, 1.0);
out_color = texture(texture_sampler, vertex_uv);
}

View File

@@ -1,13 +1,16 @@
#version 450
#include "common.glsl"
vec2 hardcoded_positions[3] = vec2[](
vec2(0.0, -0.5),
vec2(0.5, 0.5),
vec2(-0.5, 0.5)
);
layout(location = 0) in vec3 input_position;
layout(location = 1) in vec2 input_uv;
layout(location = 0) out vec2 vertex_uv;
layout(push_constant) uniform Model {
mat4 transformation;
} model;
void main() {
vec2 current_Position = hardcoded_positions[gl_VertexIndex];
gl_Position = vec4(current_Position, 0.0, 1.0);
gl_Position = camera.projection * camera.view * model.transformation * vec4(input_position, 1.0);
vertex_uv = input_uv;
}

View File

@@ -1 +1,7 @@
#extension GL_KHR_vulkan_glsl : enable
#extension GL_KHR_vulkan_glsl : enable
layout(set = 0, binding = 0) uniform UniformTransformations {
mat4 view;
mat4 projection;
}
camera;

View File

@@ -7,7 +7,7 @@
namespace veng {
Window::Window(gsl::czstring name, glm::ivec2 size) {
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
// glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
window_ = glfwCreateWindow(size.x, size.y, name, nullptr, nullptr);

View File

@@ -1,8 +1,14 @@
#include <GLFW/glfw3.h>
#include <glm/gtc/matrix_transform.hpp>
#include <iostream>
#include "assimp/Importer.hpp"
#include "assimp/postprocess.h"
#include "glfw/glfw_initialization.h"
#include "glfw/glfw_monitor.h"
#include "glfw/glfw_window.h"
#include "precomp.h"
#include "vulkan/graphics.h"
std::int32_t main(std::int32_t argc, gsl::zstring* argv) {
@@ -13,9 +19,79 @@ std::int32_t main(std::int32_t argc, gsl::zstring* argv) {
veng::Graphics graphics(&window);
Assimp::Importer assetImporter;
const struct aiScene* scene = assetImporter.ReadFile(
"assets/player.fbx", aiProcess_CalcTangentSpace | aiProcess_Triangulate |
aiProcess_JoinIdenticalVertices | aiProcess_SortByPType);
if (nullptr == scene) {
spdlog::error(assetImporter.GetErrorString());
return false;
}
std::array<veng::Vertex, 4> vertices = {
veng::Vertex{{-.5f, -.5f, 0.f}, {0.f, 1.f}},
veng::Vertex{{.5f, -.5f, 0.f}, {1.f, 1.f}},
veng::Vertex{{-.5f, .5f, 0.f}, {0.f, 0.f}},
veng::Vertex{{.5f, .5f, 0.f}, {1.f, 0.f}}};
veng::BufferHandle buffer = graphics.CreateVertexBuffer(vertices);
std::array<std::uint32_t, 6> indices = {0, 3, 2, 0, 1, 3};
veng::BufferHandle index_buffer = graphics.CreateIndexBuffer(indices);
glm::mat4 rotation = glm::rotate(glm::mat4(1.0f), glm::radians(45.f),
glm::vec3(0.f, 1.f, 0.f));
glm::mat4 rotation2 =
glm::rotate(glm::mat4(1.0f), glm::radians(0.f), glm::vec3(0.f, 0.f, 1.f));
glm::mat4 view = glm::translate(glm::mat4(1.f), glm::vec3(0.f, 0.f, -2.f));
glm::mat4 projection =
glm::perspective(glm::radians(150.f), 800.f / 600.f, 0.1f, 100.f);
graphics.SetViewProjection(view, projection);
veng::TextureHandle texture =
graphics.CreateTexture("assets/paving-stones.jpg");
double last_time = glfwGetTime();
glm::ivec2 window_size;
while (!window.ShouldClose()) {
glfwPollEvents();
glm::ivec2 current_window_size = window.GetFramebufferSize();
if (current_window_size != window_size && current_window_size.x != 0 && current_window_size.y != 0) {
window_size = current_window_size;
projection = glm::perspective(
glm::radians(90.f),
(float)current_window_size.x / (float)current_window_size.y, 0.1f,
100.f);
graphics.SetViewProjection(view, projection);
}
if (graphics.BeginFrame()) {
double current_time = glfwGetTime();
float delta_time = static_cast<float>(current_time - last_time);
last_time = current_time;
graphics.SetTexture(texture);
rotation2 = glm::rotate(rotation2, delta_time * glm::radians(-360.f),
glm::vec3(0.f, 0.f, 1.f));
graphics.SetModelMatrix(rotation2);
graphics.RenderIndexedBuffer(buffer, index_buffer, indices.size());
rotation = glm::rotate(rotation, delta_time * glm::radians(360.f),
glm::vec3(0.f, 0.f, 1.f));
graphics.SetModelMatrix(rotation);
graphics.RenderIndexedBuffer(buffer, index_buffer, indices.size());
graphics.EndFrame();
}
}
graphics.DestroyTexture(texture);
graphics.DestroyBuffer(buffer);
graphics.DestroyBuffer(index_buffer);
return EXIT_SUCCESS;
}

2
src/stb/stb_image.cpp Normal file
View File

@@ -0,0 +1,2 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb/stb_image.h"

324
src/vulkan/buffers.cpp Normal file
View File

@@ -0,0 +1,324 @@
#include <vulkan/vulkan.h>
#include "precomp.h"
#include "vulkan/graphics.h"
#include "vulkan/uniform_transformations.h"
namespace veng {
std::uint32_t Graphics::FindMemoryType(
std::uint32_t type_bits_filter, VkMemoryPropertyFlags required_properties) {
VkPhysicalDeviceMemoryProperties memory_properties;
vkGetPhysicalDeviceMemoryProperties(physical_device_, &memory_properties);
gsl::span<VkMemoryType> memory_types(memory_properties.memoryTypes,
memory_properties.memoryTypeCount);
for (std::uint32_t i = 0; i < memory_types.size(); i++) {
bool passes_filter = type_bits_filter & (1 << i);
bool has_property_flags =
memory_types[i].propertyFlags & required_properties;
if (passes_filter && has_property_flags) return i;
}
throw std::runtime_error("Cannot find memory type!");
}
BufferHandle Graphics::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
VkMemoryPropertyFlags properties) {
BufferHandle handle = {};
VkBufferCreateInfo buffer_info = {};
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
buffer_info.size = size;
buffer_info.usage = usage;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VkResult result =
vkCreateBuffer(logical_device_, &buffer_info, nullptr, &handle.buffer);
if (result != VK_SUCCESS)
throw std::runtime_error("Failed to create vertex buffer!");
VkMemoryRequirements memory_requirements;
vkGetBufferMemoryRequirements(logical_device_, handle.buffer,
&memory_requirements);
std::uint32_t chosen_memory_type =
FindMemoryType(memory_requirements.memoryTypeBits, properties);
VkMemoryAllocateInfo allocation_info = {};
allocation_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocation_info.allocationSize = memory_requirements.size;
allocation_info.memoryTypeIndex = chosen_memory_type;
VkResult allocation_result = vkAllocateMemory(
logical_device_, &allocation_info, nullptr, &handle.memory);
if (allocation_result != VK_SUCCESS)
throw std::runtime_error("Failed to allocate buffer memory!");
vkBindBufferMemory(logical_device_, handle.buffer, handle.memory, 0);
return handle;
}
BufferHandle Graphics::CreateVertexBuffer(gsl::span<Vertex> vertices) {
VkDeviceSize size = sizeof(Vertex) * vertices.size();
BufferHandle staging_handle = CreateBuffer(
size,
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
void* data;
vkMapMemory(logical_device_, staging_handle.memory, 0, size, 0, &data);
std::memcpy(data, vertices.data(), size);
vkUnmapMemory(logical_device_, staging_handle.memory);
BufferHandle gpu_handle = CreateBuffer(
size,
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VkCommandBuffer transient_commands = BeginTransientCommandBuffer();
VkBufferCopy copy_info = {};
copy_info.srcOffset = 0;
copy_info.dstOffset = 0;
copy_info.size = size;
vkCmdCopyBuffer(transient_commands, staging_handle.buffer, gpu_handle.buffer,
1, &copy_info);
EndTransientCommandBuffer(transient_commands);
DestroyBuffer(staging_handle);
return gpu_handle;
}
BufferHandle Graphics::CreateIndexBuffer(gsl::span<std::uint32_t> indices) {
VkDeviceSize size = sizeof(std::uint32_t) * indices.size();
BufferHandle staging_handle =
CreateBuffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
void* data;
vkMapMemory(logical_device_, staging_handle.memory, 0, size, 0, &data);
std::memcpy(data, indices.data(), size);
vkUnmapMemory(logical_device_, staging_handle.memory);
BufferHandle gpu_handle = CreateBuffer(
size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VkCommandBuffer transient_commands = BeginTransientCommandBuffer();
VkBufferCopy copy_info = {};
copy_info.srcOffset = 0;
copy_info.dstOffset = 0;
copy_info.size = size;
vkCmdCopyBuffer(transient_commands, staging_handle.buffer, gpu_handle.buffer,
1, &copy_info);
EndTransientCommandBuffer(transient_commands);
DestroyBuffer(staging_handle);
return gpu_handle;
}
void Graphics::DestroyBuffer(BufferHandle handle) {
vkDeviceWaitIdle(logical_device_);
vkDestroyBuffer(logical_device_, handle.buffer, nullptr);
vkFreeMemory(logical_device_, handle.memory, nullptr);
}
void Graphics::SetModelMatrix(glm::mat4 model) {
// for (Frame& frame : frames_)
vkCmdPushConstants(frames_[current_frame_].command_buffer, pipeline_layout_,
VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &model);
}
void Graphics::SetViewProjection(glm::mat4 view, glm::mat4 projection) {
UniformTransformations transformations{view, projection};
for (Frame& frame : frames_)
std::memcpy(frame.uniform_buffer_location,
&transformations, sizeof(UniformTransformations));
}
void Graphics::RenderBuffer(BufferHandle handle, std::uint32_t vertex_count) {
VkDeviceSize offset = 0;
vkCmdBindDescriptorSets(frames_[current_frame_].command_buffer,
VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_, 0,
1, &frames_[current_frame_].uniform_set, 0, nullptr);
vkCmdBindVertexBuffers(frames_[current_frame_].command_buffer, 0, 1,
&handle.buffer, &offset);
vkCmdDraw(frames_[current_frame_].command_buffer, vertex_count, 1, 0, 0);
}
void Graphics::RenderIndexedBuffer(BufferHandle vertex_buffer,
BufferHandle index_buffer,
std::uint32_t count) {
VkDeviceSize offset = 0;
vkCmdBindDescriptorSets(frames_[current_frame_].command_buffer,
VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_, 0,
1, &frames_[current_frame_].uniform_set, 0, nullptr);
vkCmdBindVertexBuffers(frames_[current_frame_].command_buffer, 0, 1,
&vertex_buffer.buffer, &offset);
vkCmdBindIndexBuffer(frames_[current_frame_].command_buffer,
index_buffer.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(frames_[current_frame_].command_buffer, count, 1, 0, 0, 0);
SetModelMatrix(glm::mat4(1.f));
}
VkCommandBuffer Graphics::BeginTransientCommandBuffer() {
VkCommandBufferAllocateInfo allocation_info = {};
allocation_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocation_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocation_info.commandPool = command_pool_;
allocation_info.commandBufferCount = 1;
VkCommandBuffer buffer;
vkAllocateCommandBuffers(logical_device_, &allocation_info, &buffer);
VkCommandBufferBeginInfo begin_info = {};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(buffer, &begin_info);
return buffer;
}
void Graphics::EndTransientCommandBuffer(VkCommandBuffer command_buffer) {
vkEndCommandBuffer(command_buffer);
VkSubmitInfo submit_info = {};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &command_buffer;
vkQueueSubmit(graphics_queue_, 1, &submit_info, VK_NULL_HANDLE);
vkQueueWaitIdle(graphics_queue_);
vkFreeCommandBuffers(logical_device_, command_pool_, 1, &command_buffer);
}
void Graphics::CreateUniformBuffers() {
VkDeviceSize buffer_size = sizeof(UniformTransformations);
for (Frame& frame : frames_) {
frame.uniform_buffer =
CreateBuffer(buffer_size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
vkMapMemory(logical_device_, frame.uniform_buffer.memory, 0, buffer_size, 0,
&frame.uniform_buffer_location);
}
}
void Graphics::CreateDescriptorSetLayouts() {
VkDescriptorSetLayoutBinding uniform_layout_binding = {};
uniform_layout_binding.binding = 0;
uniform_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
uniform_layout_binding.descriptorCount = 1;
uniform_layout_binding.stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS;
VkDescriptorSetLayoutCreateInfo uniform_layout_info = {};
uniform_layout_info.sType =
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
uniform_layout_info.bindingCount = 1;
uniform_layout_info.pBindings = &uniform_layout_binding;
if (vkCreateDescriptorSetLayout(logical_device_, &uniform_layout_info,
nullptr,
&uniform_set_layout_) != VK_SUCCESS) {
std::exit(EXIT_FAILURE);
}
VkDescriptorSetLayoutBinding texture_layout_binding = {};
texture_layout_binding.binding = 0;
texture_layout_binding.descriptorType =
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
texture_layout_binding.descriptorCount = 1;
texture_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
VkDescriptorSetLayoutCreateInfo texture_layout_info = {};
texture_layout_info.sType =
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
texture_layout_info.bindingCount = 1;
texture_layout_info.pBindings = &texture_layout_binding;
if (vkCreateDescriptorSetLayout(logical_device_, &texture_layout_info,
nullptr,
&texture_set_layout_) != VK_SUCCESS) {
std::exit(EXIT_FAILURE);
}
}
void Graphics::CreateDescriptorPools() {
VkDescriptorPoolSize uniform_pool_size = {};
uniform_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
uniform_pool_size.descriptorCount = MAX_BUFFERED_FRAMES;
VkDescriptorPoolCreateInfo uniform_create_info = {};
uniform_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
uniform_create_info.poolSizeCount = 1;
uniform_create_info.pPoolSizes = &uniform_pool_size;
uniform_create_info.maxSets = MAX_BUFFERED_FRAMES;
if (vkCreateDescriptorPool(logical_device_, &uniform_create_info, nullptr,
&uniform_pool_) != VK_SUCCESS) {
std::exit(EXIT_FAILURE);
}
VkPhysicalDeviceProperties properties = {};
vkGetPhysicalDeviceProperties(physical_device_, &properties);
VkDescriptorPoolSize texture_pool_size = {};
texture_pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
texture_pool_size.descriptorCount =
properties.limits.maxSamplerAllocationCount;
VkDescriptorPoolCreateInfo texture_create_info = {};
texture_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
texture_create_info.poolSizeCount = 1;
texture_create_info.pPoolSizes = &texture_pool_size;
texture_create_info.maxSets = properties.limits.maxSamplerAllocationCount;
texture_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
if (vkCreateDescriptorPool(logical_device_, &texture_create_info, nullptr,
&texture_pool_) != VK_SUCCESS) {
std::exit(EXIT_FAILURE);
}
}
void Graphics::CreateDescriptorSets() {
for (Frame& frame : frames_) {
VkDescriptorSetAllocateInfo set_info = {};
set_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
set_info.descriptorPool = uniform_pool_;
set_info.descriptorSetCount = 1;
set_info.pSetLayouts = &uniform_set_layout_;
VkResult result = vkAllocateDescriptorSets(logical_device_, &set_info,
&frame.uniform_set);
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
VkDescriptorBufferInfo buffer_info = {};
buffer_info.buffer = frame.uniform_buffer.buffer;
buffer_info.offset = 0;
buffer_info.range = sizeof(UniformTransformations);
VkWriteDescriptorSet descriptor_write = {};
descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptor_write.dstSet = frame.uniform_set;
descriptor_write.dstBinding = 0;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write.descriptorCount = 1;
descriptor_write.pBufferInfo = &buffer_info;
vkUpdateDescriptorSets(logical_device_, 1, &descriptor_write, 0, nullptr);
}
}
} // namespace veng

102
src/vulkan/class.cpp Normal file
View File

@@ -0,0 +1,102 @@
#include <GLFW/glfw3.h>
#include "precomp.h"
#include "vulkan/graphics.h"
namespace veng {
Graphics::Graphics(gsl::not_null<Window*> window) : window_(window) {
#if !defined(NDEBUG)
validation_enabled_ = true;
#endif
InitializeVulkan();
}
Graphics::~Graphics() {
if (logical_device_ != VK_NULL_HANDLE) {
vkDeviceWaitIdle(logical_device_);
CleanupSwapChain();
DestroyTexture(depth_texture_);
if (texture_pool_ != VK_NULL_HANDLE)
vkDestroyDescriptorPool(logical_device_, texture_pool_, nullptr);
if (texture_set_layout_ != VK_NULL_HANDLE)
vkDestroyDescriptorSetLayout(logical_device_, texture_set_layout_,
nullptr);
if (texture_sampler_ != VK_NULL_HANDLE)
vkDestroySampler(logical_device_, texture_sampler_, nullptr);
if (uniform_pool_ != VK_NULL_HANDLE)
vkDestroyDescriptorPool(logical_device_, uniform_pool_, nullptr);
for (Frame& frame : frames_) {
DestroyBuffer(frame.uniform_buffer);
if (frame.image_available_signal != VK_NULL_HANDLE)
vkDestroySemaphore(logical_device_, frame.image_available_signal,
nullptr);
if (frame.render_finished_signal != VK_NULL_HANDLE)
vkDestroySemaphore(logical_device_, frame.render_finished_signal,
nullptr);
if (frame.still_rendering_fence != VK_NULL_HANDLE)
vkDestroyFence(logical_device_, frame.still_rendering_fence, nullptr);
}
if (uniform_set_layout_ != VK_NULL_HANDLE)
vkDestroyDescriptorSetLayout(logical_device_, uniform_set_layout_,
nullptr);
if (command_pool_ != VK_NULL_HANDLE)
vkDestroyCommandPool(logical_device_, command_pool_, nullptr);
if (logical_device_ != VK_NULL_HANDLE)
vkDestroyPipeline(logical_device_, pipeline_, nullptr);
if (pipeline_layout_ != VK_NULL_HANDLE)
vkDestroyPipelineLayout(logical_device_, pipeline_layout_, nullptr);
if (render_pass_ != VK_NULL_HANDLE)
vkDestroyRenderPass(logical_device_, render_pass_, nullptr);
vkDestroyDevice(logical_device_, nullptr);
}
if (instance_ != VK_NULL_HANDLE) {
if (surface_ != VK_NULL_HANDLE)
vkDestroySurfaceKHR(instance_, surface_, nullptr);
if (debug_messenger_ != VK_NULL_HANDLE)
vkDestroyDebugUtilsMessengerEXT(instance_, debug_messenger_, nullptr);
vkDestroyInstance(instance_, nullptr);
}
}
void Graphics::InitializeVulkan() {
CreateInstance();
SetupDebugMessenger();
CreateSurface();
PickPhysicalDevice();
CreateLogicalDeviceAndQueues();
CreateSwapChain();
CreateImageViews();
CreateRenderPass();
CreateDescriptorSetLayouts();
CreateGraphicsPipeline();
CreateDepthResources();
CreateFramebuffers();
CreateCommandPool();
CreateCommandBuffer();
CreateSignals();
CreateUniformBuffers();
CreateDescriptorPools();
CreateDescriptorSets();
CreateTextureSampler();
TransitionImageLayout(depth_texture_.image, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
}
} // namespace veng

View File

@@ -140,6 +140,8 @@ void Graphics::CreateLogicalDeviceAndQueues() {
}
VkPhysicalDeviceFeatures required_features = {};
required_features.depthBounds = true;
required_features.depthClamp = true;
VkDeviceCreateInfo device_info = {};
device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;

191
src/vulkan/drawing.cpp Normal file
View File

@@ -0,0 +1,191 @@
#include <GLFW/glfw3.h>
#include "precomp.h"
#include "vulkan/graphics.h"
namespace veng {
void Graphics::CreateFramebuffers() {
swap_chain_framebuffers_.resize(swap_chain_image_views_.size());
for (std::uint32_t i = 0; i < swap_chain_image_views_.size(); i++) {
std::array<VkImageView, 2> attachments = {swap_chain_image_views_[i],
depth_texture_.image_view};
VkFramebufferCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
info.renderPass = render_pass_;
info.attachmentCount = attachments.size();
info.pAttachments = attachments.data();
info.width = extent_.width;
info.height = extent_.height;
info.layers = 1;
VkResult result = vkCreateFramebuffer(logical_device_, &info, nullptr,
&swap_chain_framebuffers_[i]);
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
}
}
void Graphics::CreateCommandPool() {
QueueFamilyIndices indices = FindQueueFamilies(physical_device_);
VkCommandPoolCreateInfo pool_info = {};
pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
pool_info.queueFamilyIndex = indices.graphics_family.value();
VkResult result =
vkCreateCommandPool(logical_device_, &pool_info, nullptr, &command_pool_);
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
}
void Graphics::CreateCommandBuffer() {
VkCommandBufferAllocateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
info.commandPool = command_pool_;
info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
info.commandBufferCount = 1;
for (Frame& frame : frames_) {
VkResult result =
vkAllocateCommandBuffers(logical_device_, &info, &frame.command_buffer);
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
}
}
void Graphics::BeginCommands() {
vkResetCommandBuffer(frames_[current_frame_].command_buffer, 0);
VkCommandBufferBeginInfo begin_info = {};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
VkResult result = vkBeginCommandBuffer(
frames_[current_frame_].command_buffer, &begin_info);
if (result != VK_SUCCESS)
throw std::runtime_error("Failed to begin command buffer!");
std::array<VkClearValue, 2> clear_values;
clear_values[0].color = {{0.f, 0.f, 0.f, 1.f}};
clear_values[1].depthStencil = {1.f, 0};
VkRenderPassBeginInfo render_pass_begin_info = {};
render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
render_pass_begin_info.renderPass = render_pass_;
render_pass_begin_info.framebuffer =
swap_chain_framebuffers_[current_image_index_];
render_pass_begin_info.renderArea.offset = {0, 0};
render_pass_begin_info.renderArea.extent = extent_;
render_pass_begin_info.clearValueCount = clear_values.size();
render_pass_begin_info.pClearValues = clear_values.data();
vkCmdBeginRenderPass(frames_[current_frame_].command_buffer,
&render_pass_begin_info,
VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(frames_[current_frame_].command_buffer,
VK_PIPELINE_BIND_POINT_GRAPHICS,
pipeline_);
VkViewport viewport = GetViewport();
VkRect2D scissor = GetScissor();
vkCmdSetViewport(frames_[current_frame_].command_buffer, 0, 1, &viewport);
vkCmdSetScissor(frames_[current_frame_].command_buffer, 0, 1, &scissor);
}
void Graphics::EndCommands() {
vkCmdEndRenderPass(frames_[current_frame_].command_buffer);
VkResult result = vkEndCommandBuffer(frames_[current_frame_].command_buffer);
if (result != VK_SUCCESS)
throw std::runtime_error("Failed to record command buffer!");
}
void Graphics::CreateSignals() {
for (Frame& frame : frames_) {
VkSemaphoreCreateInfo semafore_info = {};
semafore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
if (vkCreateSemaphore(logical_device_, &semafore_info, nullptr,
&frame.image_available_signal) !=
VK_SUCCESS)
std::exit(EXIT_FAILURE);
if (vkCreateSemaphore(logical_device_, &semafore_info, nullptr,
&frame.render_finished_signal) !=
VK_SUCCESS)
std::exit(EXIT_FAILURE);
VkFenceCreateInfo fence_info = {};
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
if (vkCreateFence(logical_device_, &fence_info, nullptr,
&frame.still_rendering_fence) !=
VK_SUCCESS)
std::exit(EXIT_FAILURE);
}
}
bool Graphics::BeginFrame() {
vkWaitForFences(logical_device_, 1,
&frames_[current_frame_].still_rendering_fence, VK_TRUE,
UINT64_MAX);
VkResult image_acquire_result = vkAcquireNextImageKHR(logical_device_, swap_chain_, UINT64_MAX,
frames_[current_frame_].image_available_signal,
VK_NULL_HANDLE, &current_image_index_);
if (image_acquire_result == VK_ERROR_OUT_OF_DATE_KHR) {
RecreateSwapChain();
return false;
}
if (image_acquire_result != VK_SUCCESS &&
image_acquire_result != VK_SUBOPTIMAL_KHR)
throw std::runtime_error("Couldn't acquire render image!");
vkResetFences(logical_device_, 1,
&frames_[current_frame_].still_rendering_fence);
BeginCommands();
SetModelMatrix(glm::mat4(1.f));
return true;
}
void veng::Graphics::EndFrame() {
EndCommands();
VkSubmitInfo submit_info = {};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &frames_[current_frame_].image_available_signal;
submit_info.pWaitDstStageMask = &wait_stage;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &frames_[current_frame_].command_buffer;
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores =
&frames_[current_frame_].render_finished_signal;
VkResult submit_result =
vkQueueSubmit(graphics_queue_, 1, &submit_info,
frames_[current_frame_].still_rendering_fence);
if (submit_result != VK_SUCCESS)
throw std::runtime_error("failed to submit draw commands!");
VkPresentInfoKHR present_info = {};
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
present_info.waitSemaphoreCount = 1;
present_info.pWaitSemaphores =
&frames_[current_frame_].render_finished_signal;
present_info.swapchainCount = 1;
present_info.pSwapchains = &swap_chain_;
present_info.pImageIndices = &current_image_index_;
VkResult result = vkQueuePresentKHR(present_queue_, &present_info);
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
RecreateSwapChain();
else if (result != VK_SUCCESS)
throw std::runtime_error("Failed to present swap chain image!");
current_frame_ = (current_frame_++) % MAX_BUFFERED_FRAMES;
}
} // namespace veng

View File

@@ -8,38 +8,4 @@
namespace veng {
Graphics::Graphics(gsl::not_null<Window*> window) : window_(window) {
#if !defined(NDEBUG)
validation_enabled_ = true;
#endif
InitializeVulkan();
}
Graphics::~Graphics() {
if (logical_device_ != VK_NULL_HANDLE) {
for (VkImageView image_view : swap_chain_image_views_)
vkDestroyImageView(logical_device_, image_view, nullptr);
if (swap_chain_ != VK_NULL_HANDLE)
vkDestroySwapchainKHR(logical_device_, swap_chain_, nullptr);
vkDestroyDevice(logical_device_, nullptr);
}
if (instance_ != VK_NULL_HANDLE) {
if (surface_ != VK_NULL_HANDLE)
vkDestroySurfaceKHR(instance_, surface_, nullptr);
if (debug_messenger_ != VK_NULL_HANDLE)
vkDestroyDebugUtilsMessengerEXT(instance_, debug_messenger_, nullptr);
vkDestroyInstance(instance_, nullptr);
}
}
void Graphics::InitializeVulkan() {
CreateInstance();
SetupDebugMessenger();
CreateSurface();
PickPhysicalDevice();
CreateLogicalDeviceAndQueues();
CreateSwapChain();
CreateGraphicsPipeline();
}
} // namespace veng

View File

@@ -21,6 +21,26 @@ VkShaderModule Graphics::CreateShaderModule(gsl::span<std::uint8_t> buffer) {
return shader_module;
}
VkViewport Graphics::GetViewport() {
VkViewport viewport = {};
viewport.x = 0.f;
viewport.y = 0.f;
viewport.width = static_cast<std::float_t>(extent_.width);
viewport.height = static_cast<std::float_t>(extent_.height);
viewport.minDepth = 0.f;
viewport.maxDepth = 1.f;
return viewport;
}
VkRect2D Graphics::GetScissor() {
VkRect2D scissor = {};
scissor.offset = {0, 0};
scissor.extent = extent_;
return scissor;
}
void Graphics::CreateGraphicsPipeline() {
std::vector<std::uint8_t> basic_vertex_data = ReadFile("./basic.vert.spv");
VkShaderModule vertex_shader = CreateShaderModule(basic_vertex_data);
@@ -52,5 +72,235 @@ void Graphics::CreateGraphicsPipeline() {
std::array<VkPipelineShaderStageCreateInfo, 2> stage_infos = {
vertex_stage_info, fragment_stage_info};
std::array<VkDynamicState, 2> dynamic_states = {VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR};
VkPipelineDynamicStateCreateInfo dynamic_state_info = {};
dynamic_state_info.sType =
VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamic_state_info.dynamicStateCount = dynamic_states.size();
dynamic_state_info.pDynamicStates = dynamic_states.data();
VkViewport viewport = GetViewport();
VkRect2D scissor = GetScissor();
VkPipelineViewportStateCreateInfo viewport_info = {};
viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewport_info.viewportCount = 1;
viewport_info.pViewports = &viewport;
viewport_info.scissorCount = 1;
viewport_info.pScissors = &scissor;
auto vertex_binding_description = Vertex::GetBindingDescription();
auto vertex_attribute_descriptions = Vertex::GetAttributeDescriptions();
VkPipelineVertexInputStateCreateInfo vertex_input_info = {};
vertex_input_info.sType =
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertex_input_info.vertexBindingDescriptionCount = 1;
vertex_input_info.pVertexBindingDescriptions = &vertex_binding_description;
vertex_input_info.vertexAttributeDescriptionCount =
vertex_attribute_descriptions.size();
vertex_input_info.pVertexAttributeDescriptions =
vertex_attribute_descriptions.data();
VkPipelineInputAssemblyStateCreateInfo input_assembly_info = {};
input_assembly_info.sType =
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
input_assembly_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
input_assembly_info.primitiveRestartEnable = VK_FALSE;
VkPipelineRasterizationStateCreateInfo rasterization_state_info = {};
rasterization_state_info.sType =
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterization_state_info.depthClampEnable = VK_FALSE;
rasterization_state_info.rasterizerDiscardEnable = VK_FALSE;
rasterization_state_info.polygonMode = VK_POLYGON_MODE_FILL;
rasterization_state_info.lineWidth = 1.f;
rasterization_state_info.cullMode = VK_CULL_MODE_NONE;
rasterization_state_info.frontFace = VK_FRONT_FACE_CLOCKWISE;
rasterization_state_info.depthBiasEnable = VK_FALSE;
VkPipelineMultisampleStateCreateInfo multisampling_info = {};
multisampling_info.sType =
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling_info.sampleShadingEnable = VK_FALSE;
multisampling_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkPipelineColorBlendAttachmentState color_blend_attachment = {};
color_blend_attachment.colorWriteMask =
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
color_blend_attachment.blendEnable = VK_TRUE;
color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
color_blend_attachment.dstColorBlendFactor =
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD;
color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD;
VkPipelineColorBlendStateCreateInfo color_blending_info = {};
color_blending_info.sType =
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
color_blending_info.logicOpEnable = VK_FALSE;
color_blending_info.attachmentCount = 1;
color_blending_info.pAttachments = &color_blend_attachment;
VkPipelineDepthStencilStateCreateInfo depth_stencil_info = {};
depth_stencil_info.sType =
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depth_stencil_info.depthTestEnable = VK_TRUE;
depth_stencil_info.depthWriteEnable = VK_TRUE;
depth_stencil_info.depthCompareOp = VK_COMPARE_OP_LESS;
depth_stencil_info.depthBoundsTestEnable = VK_TRUE;
depth_stencil_info.minDepthBounds = 0.f;
depth_stencil_info.maxDepthBounds = 1.f;
depth_stencil_info.stencilTestEnable = VK_FALSE;
VkPushConstantRange model_matrix_range = {};
model_matrix_range.offset = 0;
model_matrix_range.size = sizeof(glm::mat4);
model_matrix_range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
std::array<VkDescriptorSetLayout, 2> set_layouts = {uniform_set_layout_,
texture_set_layout_};
VkPipelineLayoutCreateInfo layout_info = {};
layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
layout_info.pushConstantRangeCount = 1;
layout_info.pPushConstantRanges = &model_matrix_range;
layout_info.setLayoutCount = set_layouts.size();
layout_info.pSetLayouts = set_layouts.data();
VkResult layout_result = vkCreatePipelineLayout(logical_device_, &layout_info,
nullptr, &pipeline_layout_);
if (layout_result != VK_SUCCESS) std::exit(EXIT_FAILURE);
VkGraphicsPipelineCreateInfo pipeline_info = {};
pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipeline_info.stageCount = stage_infos.size();
pipeline_info.pStages = stage_infos.data();
pipeline_info.pVertexInputState = &vertex_input_info;
pipeline_info.pInputAssemblyState = &input_assembly_info;
pipeline_info.pViewportState = &viewport_info;
pipeline_info.pRasterizationState = &rasterization_state_info;
pipeline_info.pMultisampleState = &multisampling_info;
pipeline_info.pDepthStencilState = &depth_stencil_info;
pipeline_info.pColorBlendState = &color_blending_info;
pipeline_info.pDynamicState = &dynamic_state_info;
pipeline_info.layout = pipeline_layout_;
pipeline_info.renderPass = render_pass_;
pipeline_info.subpass = 0;
VkResult pipline_result = vkCreateGraphicsPipelines(
logical_device_, VK_NULL_HANDLE, 1, &pipeline_info, nullptr, &pipeline_);
if (pipline_result != VK_SUCCESS) std::exit(EXIT_FAILURE);
}
void Graphics::CreateRenderPass() {
VkAttachmentDescription color_attachment = {};
color_attachment.format = surface_format_.format;
color_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentReference color_attachment_ref = {};
color_attachment_ref.attachment = 0;
color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentDescription depth_attachment = {};
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;
VkAttachmentReference depth_attachment_ref = {};
depth_attachment_ref.attachment = 1;
depth_attachment_ref.layout =
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkSubpassDescription main_subpass = {};
main_subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
main_subpass.colorAttachmentCount = 1;
main_subpass.pColorAttachments = &color_attachment_ref;
main_subpass.pDepthStencilAttachment = &depth_attachment_ref;
VkSubpassDependency dependency = {};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
dependency.srcAccessMask = 0;
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;
std::array<VkAttachmentDescription, 2> attachments = {color_attachment,
depth_attachment};
VkRenderPassCreateInfo render_pass_info = {};
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
render_pass_info.attachmentCount = attachments.size();
render_pass_info.pAttachments = attachments.data();
render_pass_info.subpassCount = 1;
render_pass_info.pSubpasses = &main_subpass;
render_pass_info.dependencyCount = 1;
render_pass_info.pDependencies = &dependency;
VkResult result = vkCreateRenderPass(logical_device_, &render_pass_info,
nullptr, &render_pass_);
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
}
void veng::Graphics::RecreateSwapChain() {
glm::ivec2 size = window_->GetFramebufferSize();
while (size.x == 0 || size.y == 0) {
size = window_->GetFramebufferSize();
// glfwWaitEvents();
return;
}
vkDeviceWaitIdle(logical_device_);
CleanupSwapChain();
CreateSwapChain();
CreateImageViews();
CreateDepthResources();
CreateFramebuffers();
}
void veng::Graphics::CleanupSwapChain() {
if (logical_device_ == VK_NULL_HANDLE) return;
for (VkFramebuffer framebuffer : swap_chain_framebuffers_)
vkDestroyFramebuffer(logical_device_, framebuffer, nullptr);
for (VkImageView image_view : swap_chain_image_views_)
vkDestroyImageView(logical_device_, image_view, nullptr);
if (swap_chain_ != VK_NULL_HANDLE)
vkDestroySwapchainKHR(logical_device_, swap_chain_, nullptr);
vkDeviceWaitIdle(logical_device_);
vkDestroyImageView(logical_device_, depth_texture_.image_view, nullptr);
depth_texture_.image_view = VK_NULL_HANDLE;
vkDestroyImage(logical_device_, depth_texture_.image, nullptr);
depth_texture_.image = VK_NULL_HANDLE;
vkFreeMemory(logical_device_, depth_texture_.memory, nullptr);
depth_texture_.memory = VK_NULL_HANDLE;
}
} // namespace veng

View File

@@ -140,30 +140,36 @@ void Graphics::CreateSwapChain() {
swap_chain_images_.data());
}
VkImageView Graphics::CreateImageView(VkImage image, VkFormat format, VkImageAspectFlags aspect_flag) {
VkImageViewCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
info.image = image;
info.viewType = VK_IMAGE_VIEW_TYPE_2D;
info.format = format;
info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
info.subresourceRange.aspectMask = aspect_flag;
info.subresourceRange.baseMipLevel = 0;
info.subresourceRange.levelCount = 1;
info.subresourceRange.baseArrayLayer = 0;
info.subresourceRange.layerCount = 1;
VkImageView view;
VkResult result = vkCreateImageView(logical_device_, &info, nullptr, &view);
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
return view;
}
void Graphics::CreateImageViews() {
swap_chain_image_views_.resize(swap_chain_images_.size());
auto image_view_it = swap_chain_image_views_.begin();
for (VkImage image : swap_chain_images_) {
VkImageViewCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
info.image = image;
info.viewType = VK_IMAGE_VIEW_TYPE_2D;
info.format = surface_format_.format;
info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
info.subresourceRange.baseMipLevel = 0;
info.subresourceRange.layerCount = 1;
info.subresourceRange.baseArrayLayer = 0;
info.subresourceRange.layerCount = 1;
VkResult result =
vkCreateImageView(logical_device_, &info, nullptr, &*image_view_it);
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
std::next(image_view_it);
*image_view_it = CreateImageView(image, surface_format_.format, VK_IMAGE_ASPECT_COLOR_BIT);
std::advance(image_view_it, 1);
}
}

250
src/vulkan/texture.cpp Normal file
View File

@@ -0,0 +1,250 @@
#include <vulkan/vulkan.h>
#include "stb/stb_image.h"
#include "vulkan/graphics.h"
namespace veng {
void Graphics::CreateTextureSampler() {
VkSamplerCreateInfo sampler_info = {};
sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
sampler_info.magFilter = VK_FILTER_LINEAR;
sampler_info.minFilter = VK_FILTER_LINEAR;
sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
sampler_info.anisotropyEnable = VK_FALSE;
sampler_info.maxAnisotropy = 1.f;
sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
sampler_info.unnormalizedCoordinates = VK_FALSE;
sampler_info.compareEnable = VK_FALSE;
sampler_info.compareOp = VK_COMPARE_OP_ALWAYS;
sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
sampler_info.mipLodBias = 0.f;
sampler_info.minLod = 0.f;
sampler_info.maxLod = 0.f;
if (vkCreateSampler(logical_device_, &sampler_info, nullptr,
&texture_sampler_) != VK_SUCCESS) {
std::exit(EXIT_FAILURE);
}
}
TextureHandle Graphics::CreateTexture(gsl::czstring path) {
glm::ivec2 image_extents;
std::int32_t channels;
std::vector<std::uint8_t> image_file_data = ReadFile(path);
stbi_uc* pixel_data = stbi_load_from_memory(
image_file_data.data(), image_file_data.size(), &image_extents.x,
&image_extents.y, &channels, STBI_rgb_alpha);
VkDeviceSize buffer_size = image_extents.x * image_extents.y * 4;
BufferHandle staging =
CreateBuffer(buffer_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
void* data_location;
vkMapMemory(logical_device_, staging.memory, 0, buffer_size, 0,
&data_location);
std::memcpy(data_location, pixel_data, buffer_size);
vkUnmapMemory(logical_device_, staging.memory);
stbi_image_free(pixel_data);
TextureHandle handle =
CreateImage(image_extents, VK_FORMAT_R8G8B8A8_SRGB,
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
TransitionImageLayout(handle.image, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
CopyBufferToImage(staging.buffer, handle.image, image_extents);
TransitionImageLayout(handle.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
handle.image_view = CreateImageView(handle.image, VK_FORMAT_R8G8B8A8_SRGB,
VK_IMAGE_ASPECT_COLOR_BIT);
VkDescriptorSetAllocateInfo set_info = {};
set_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
set_info.descriptorPool = texture_pool_;
set_info.descriptorSetCount = 1;
set_info.pSetLayouts = &texture_set_layout_;
VkResult result =
vkAllocateDescriptorSets(logical_device_, &set_info, &handle.set);
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
VkDescriptorImageInfo image_info = {};
image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
image_info.imageView = handle.image_view;
image_info.sampler = texture_sampler_;
VkWriteDescriptorSet descriptor_write = {};
descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptor_write.dstSet = handle.set;
descriptor_write.dstBinding = 0;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptor_write.descriptorCount = 1;
descriptor_write.pImageInfo = &image_info;
vkUpdateDescriptorSets(logical_device_, 1, &descriptor_write, 0, nullptr);
DestroyBuffer(staging);
return handle;
}
void Graphics::DestroyTexture(TextureHandle handle) {
vkDeviceWaitIdle(logical_device_);
if (handle.set != VK_NULL_HANDLE)
vkFreeDescriptorSets(logical_device_, texture_pool_, 1, &handle.set);
if (handle.image_view != VK_NULL_HANDLE)
vkDestroyImageView(logical_device_, handle.image_view, nullptr);
if (handle.image != VK_NULL_HANDLE)
vkDestroyImage(logical_device_, handle.image, nullptr);
if (handle.memory != VK_NULL_HANDLE)
vkFreeMemory(logical_device_, handle.memory, nullptr);
}
void Graphics::SetTexture(TextureHandle handle) {
vkCmdBindDescriptorSets(frames_[current_frame_].command_buffer,
VK_PIPELINE_BIND_POINT_GRAPHICS,
pipeline_layout_, 1, 1, &handle.set, 0, nullptr);
}
void Graphics::TransitionImageLayout(VkImage image, VkImageLayout old_layout,
VkImageLayout new_layout) {
VkCommandBuffer local_command_buffer = BeginTransientCommandBuffer();
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = old_layout;
barrier.newLayout = new_layout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.layerCount = 1;
VkPipelineStageFlags source_stage = {};
VkPipelineStageFlags destination_stage = {};
if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED &&
new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
destination_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
} else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL &&
new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
source_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
destination_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
} else if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED &&
new_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
destination_stage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
}
if (new_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
else
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
vkCmdPipelineBarrier(local_command_buffer, source_stage, destination_stage, 0,
0, nullptr, 0, nullptr, 1, &barrier);
EndTransientCommandBuffer(local_command_buffer);
}
void Graphics::CopyBufferToImage(VkBuffer buffer, VkImage image,
glm::ivec2 image_size) {
VkCommandBuffer local_command_buffer = BeginTransientCommandBuffer();
VkBufferImageCopy region = {};
region.bufferOffset = 0;
region.bufferRowLength = 0;
region.bufferImageHeight = 0;
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.mipLevel = 0;
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.layerCount = 1;
region.imageOffset = {0, 0, 0};
region.imageExtent = {static_cast<std::uint32_t>(image_size.x),
static_cast<std::uint32_t>(image_size.y), 1};
vkCmdCopyBufferToImage(local_command_buffer, buffer, image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
EndTransientCommandBuffer(local_command_buffer);
}
TextureHandle Graphics::CreateImage(glm::ivec2 size, VkFormat image_format,
VkBufferUsageFlags usage,
VkMemoryPropertyFlags properties) {
TextureHandle handle = {};
VkImageCreateInfo image_info = {};
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image_info.usage = usage;
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
image_info.imageType = VK_IMAGE_TYPE_2D;
image_info.extent.width = size.x;
image_info.extent.height = size.y;
image_info.extent.depth = 1;
image_info.mipLevels = 1;
image_info.arrayLayers = 1;
image_info.format = image_format;
image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_info.flags = 0;
VkResult result =
vkCreateImage(logical_device_, &image_info, nullptr, &handle.image);
if (result != VK_SUCCESS)
throw std::runtime_error("Failed to create vertex buffer!");
VkMemoryRequirements memory_requirements;
vkGetImageMemoryRequirements(logical_device_, handle.image,
&memory_requirements);
std::uint32_t chosen_memory_type =
FindMemoryType(memory_requirements.memoryTypeBits, properties);
VkMemoryAllocateInfo allocation_info = {};
allocation_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocation_info.allocationSize = memory_requirements.size;
allocation_info.memoryTypeIndex = chosen_memory_type;
VkResult allocation_result = vkAllocateMemory(
logical_device_, &allocation_info, nullptr, &handle.memory);
if (allocation_result != VK_SUCCESS)
throw std::runtime_error("Failed to allocate image memory!");
vkBindImageMemory(logical_device_, handle.image, handle.memory, 0);
return handle;
}
void Graphics::CreateDepthResources() {
VkFormat kDepthFormat = VK_FORMAT_D32_SFLOAT;
depth_texture_ = CreateImage({extent_.width, extent_.height}, kDepthFormat,
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
depth_texture_.image_view = CreateImageView(
depth_texture_.image, kDepthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
}
} // namespace veng