일단 완성
This commit is contained in:
@@ -6,8 +6,6 @@ find_package(Vulkan REQUIRED)
|
|||||||
include(cmake/Shaders.cmake)
|
include(cmake/Shaders.cmake)
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
|
|
||||||
set(FMT_HEADER_ONLY ON)
|
|
||||||
|
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
glm
|
glm
|
||||||
GIT_REPOSITORY "https://github.com/g-truc/glm.git"
|
GIT_REPOSITORY "https://github.com/g-truc/glm.git"
|
||||||
@@ -65,3 +63,5 @@ file(GLOB_RECURSE ShaderSources CONFIGURE_DEPENDS
|
|||||||
|
|
||||||
add_shaders(VulkanEngineShaders ${ShaderSources})
|
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")
|
||||||
15
CMakeSettings.json
Normal file
15
CMakeSettings.json
Normal 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
BIN
assets/paving-stones.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 MiB |
8422
include/stb/stb_image.h
Normal file
8422
include/stb/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
12
include/vulkan/buffer_handle.h
Normal file
12
include/vulkan/buffer_handle.h
Normal 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
|
||||||
@@ -1,15 +1,33 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
#include "buffer_handle.h"
|
||||||
#include "glfw/glfw_window.h"
|
#include "glfw/glfw_window.h"
|
||||||
#include "precomp.h"
|
#include "precomp.h"
|
||||||
|
#include "texture_handle.h"
|
||||||
|
#include "vertex.h"
|
||||||
|
|
||||||
namespace veng {
|
namespace veng {
|
||||||
class Graphics final {
|
class Graphics final {
|
||||||
public:
|
public:
|
||||||
Graphics(gsl::not_null<Window *> window);
|
Graphics(gsl::not_null<Window*> window);
|
||||||
~Graphics();
|
~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:
|
private:
|
||||||
struct QueueFamilyIndices {
|
struct QueueFamilyIndices {
|
||||||
std::optional<std::uint32_t> graphics_family = std::nullopt;
|
std::optional<std::uint32_t> graphics_family = std::nullopt;
|
||||||
@@ -28,6 +46,8 @@ class Graphics final {
|
|||||||
bool IsValid() const { return !formats.empty() && !present_modes.empty(); }
|
bool IsValid() const { return !formats.empty() && !present_modes.empty(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 초기화
|
||||||
|
|
||||||
void InitializeVulkan();
|
void InitializeVulkan();
|
||||||
void CreateInstance();
|
void CreateInstance();
|
||||||
void SetupDebugMessenger();
|
void SetupDebugMessenger();
|
||||||
@@ -38,6 +58,22 @@ class Graphics final {
|
|||||||
void CreateImageViews();
|
void CreateImageViews();
|
||||||
void CreateRenderPass();
|
void CreateRenderPass();
|
||||||
void CreateGraphicsPipeline();
|
void CreateGraphicsPipeline();
|
||||||
|
void CreateFramebuffers();
|
||||||
|
void CreateCommandPool();
|
||||||
|
void CreateCommandBuffer();
|
||||||
|
void CreateSignals();
|
||||||
|
void CreateDescriptorSetLayouts();
|
||||||
|
void CreateDescriptorPools();
|
||||||
|
void CreateDescriptorSets();
|
||||||
|
void CreateTextureSampler();
|
||||||
|
|
||||||
|
void RecreateSwapChain();
|
||||||
|
void CleanupSwapChain();
|
||||||
|
|
||||||
|
// 랜더링
|
||||||
|
|
||||||
|
void BeginCommands();
|
||||||
|
void EndCommands();
|
||||||
|
|
||||||
std::vector<gsl::czstring> GetRequiredInstanceExtentions();
|
std::vector<gsl::czstring> GetRequiredInstanceExtentions();
|
||||||
|
|
||||||
@@ -61,10 +97,29 @@ class Graphics final {
|
|||||||
VkPresentModeKHR ChooseSwapPresentMode(
|
VkPresentModeKHR ChooseSwapPresentMode(
|
||||||
gsl::span<VkPresentModeKHR> present_modes);
|
gsl::span<VkPresentModeKHR> present_modes);
|
||||||
VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities);
|
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);
|
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, 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);
|
||||||
|
|
||||||
|
VkViewport GetViewport();
|
||||||
|
VkRect2D GetScissor();
|
||||||
|
|
||||||
std::array<gsl::czstring, 1> required_device_extentions_ = {
|
std::array<gsl::czstring, 1> required_device_extentions_ = {
|
||||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME};
|
VK_KHR_SWAPCHAIN_EXTENSION_NAME};
|
||||||
|
|
||||||
@@ -81,14 +136,36 @@ class Graphics final {
|
|||||||
VkSurfaceFormatKHR surface_format_;
|
VkSurfaceFormatKHR surface_format_;
|
||||||
VkPresentModeKHR present_mode_;
|
VkPresentModeKHR present_mode_;
|
||||||
VkExtent2D extent_;
|
VkExtent2D extent_;
|
||||||
|
|
||||||
std::vector<VkImage> swap_chain_images_;
|
std::vector<VkImage> swap_chain_images_;
|
||||||
std::vector<VkImageView> swap_chain_image_views_;
|
std::vector<VkImageView> swap_chain_image_views_;
|
||||||
|
std::vector<VkFramebuffer> swap_chain_framebuffers_;
|
||||||
|
|
||||||
VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE;
|
VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE;
|
||||||
VkRenderPass render_pass_ = VK_NULL_HANDLE;
|
VkRenderPass render_pass_ = VK_NULL_HANDLE;
|
||||||
VkPipeline pipeline_ = VK_NULL_HANDLE;
|
VkPipeline pipeline_ = VK_NULL_HANDLE;
|
||||||
|
VkDescriptorSetLayout descriptor_set_layout_ = VK_NULL_HANDLE;
|
||||||
|
|
||||||
gsl::not_null<Window *> window_;
|
VkCommandPool command_pool_ = VK_NULL_HANDLE;
|
||||||
|
VkCommandBuffer command_buffer_ = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
VkSemaphore image_available_signal_ = VK_NULL_HANDLE;
|
||||||
|
VkSemaphore render_finished_signal_ = VK_NULL_HANDLE;
|
||||||
|
VkFence still_rendering_fence_ = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
std::uint32_t current_image_index_ = 0;
|
||||||
|
|
||||||
|
VkDescriptorSetLayout uniform_set_layout_ = VK_NULL_HANDLE;
|
||||||
|
VkDescriptorPool uniform_pool_ = VK_NULL_HANDLE;
|
||||||
|
VkDescriptorSet uniform_set_ = VK_NULL_HANDLE;
|
||||||
|
BufferHandle uniform_buffer_;
|
||||||
|
void* uniform_buffer_location_;
|
||||||
|
|
||||||
|
VkDescriptorSetLayout texture_set_layout_ = VK_NULL_HANDLE;
|
||||||
|
VkDescriptorPool texture_pool_ = VK_NULL_HANDLE;
|
||||||
|
VkSampler texture_sampler_ = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
gsl::not_null<Window*> window_;
|
||||||
bool validation_enabled_ = false;
|
bool validation_enabled_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
14
include/vulkan/texture_handle.h
Normal file
14
include/vulkan/texture_handle.h
Normal 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
|
||||||
8
include/vulkan/uniform_transformations.h
Normal file
8
include/vulkan/uniform_transformations.h
Normal 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
38
include/vulkan/vertex.h
Normal 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
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
#version 450
|
#version 450
|
||||||
|
#include "common.glsl"
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vertex_uv;
|
||||||
layout(location = 0) out vec4 out_color;
|
layout(location = 0) out vec4 out_color;
|
||||||
|
|
||||||
|
layout(set = 1, binding = 0) uniform sampler2D texture_sampler;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
out_color = vec4(1.0, 0.0, 0.5, 1.0);
|
out_color = texture(texture_sampler, vertex_uv);
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,16 @@
|
|||||||
#version 450
|
#version 450
|
||||||
#include "common.glsl"
|
#include "common.glsl"
|
||||||
|
|
||||||
vec2 hardcoded_positions[3] = vec2[](
|
layout(location = 0) in vec3 input_position;
|
||||||
vec2(0.0, -0.5),
|
layout(location = 1) in vec2 input_uv;
|
||||||
vec2(0.5, 0.5),
|
|
||||||
vec2(-0.5, 0.5)
|
layout(location = 0) out vec2 vertex_uv;
|
||||||
);
|
|
||||||
|
layout(push_constant) uniform Model {
|
||||||
|
mat4 transformation;
|
||||||
|
} model;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 current_Position = hardcoded_positions[gl_VertexIndex];
|
gl_Position = camera.projection * camera.view * model.transformation * vec4(input_position, 1.0);
|
||||||
gl_Position = vec4(current_Position, 0.0, 1.0);
|
vertex_uv = input_uv;
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
namespace veng {
|
namespace veng {
|
||||||
|
|
||||||
Window::Window(gsl::czstring name, glm::ivec2 size) {
|
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);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
|
||||||
window_ = glfwCreateWindow(size.x, size.y, name, nullptr, nullptr);
|
window_ = glfwCreateWindow(size.x, size.y, name, nullptr, nullptr);
|
||||||
|
|||||||
47
src/main.cpp
47
src/main.cpp
@@ -1,10 +1,15 @@
|
|||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
#include "glfw/glfw_initialization.h"
|
#include "glfw/glfw_initialization.h"
|
||||||
#include "glfw/glfw_monitor.h"
|
#include "glfw/glfw_monitor.h"
|
||||||
#include "glfw/glfw_window.h"
|
#include "glfw/glfw_window.h"
|
||||||
|
#include "precomp.h"
|
||||||
#include "vulkan/graphics.h"
|
#include "vulkan/graphics.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
std::int32_t main(std::int32_t argc, gsl::zstring* argv) {
|
std::int32_t main(std::int32_t argc, gsl::zstring* argv) {
|
||||||
const veng::GlfwInitialization _glfw;
|
const veng::GlfwInitialization _glfw;
|
||||||
|
|
||||||
@@ -13,9 +18,51 @@ std::int32_t main(std::int32_t argc, gsl::zstring* argv) {
|
|||||||
|
|
||||||
veng::Graphics graphics(&window);
|
veng::Graphics graphics(&window);
|
||||||
|
|
||||||
|
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 view = glm::translate(glm::mat4(1.f), glm::vec3(0.f, 0.f, -2.f));
|
||||||
|
glm::mat4 projection =
|
||||||
|
glm::perspective(glm::radians(60.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();
|
||||||
|
|
||||||
while (!window.ShouldClose()) {
|
while (!window.ShouldClose()) {
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
|
|
||||||
|
if (graphics.BeginFrame()) {
|
||||||
|
double current_time = glfwGetTime();
|
||||||
|
float delta_time = static_cast<float>(current_time - last_time);
|
||||||
|
last_time = current_time;
|
||||||
|
|
||||||
|
std::cout << 1.f / delta_time << std::endl;
|
||||||
|
|
||||||
|
graphics.SetTexture(texture);
|
||||||
|
graphics.RenderIndexedBuffer(buffer, index_buffer, indices.size());
|
||||||
|
rotation = glm::rotate(rotation, delta_time * glm::radians(3600.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;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
2
src/stb/stb_image.cpp
Normal file
2
src/stb/stb_image.cpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "stb/stb_image.h"
|
||||||
314
src/vulkan/buffers.cpp
Normal file
314
src/vulkan/buffers.cpp
Normal file
@@ -0,0 +1,314 @@
|
|||||||
|
#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, ©_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, ©_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) {
|
||||||
|
vkCmdPushConstants(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};
|
||||||
|
std::memcpy(uniform_buffer_location_, &transformations,
|
||||||
|
sizeof(UniformTransformations));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Graphics::RenderBuffer(BufferHandle handle, std::uint32_t vertex_count) {
|
||||||
|
VkDeviceSize offset = 0;
|
||||||
|
vkCmdBindDescriptorSets(command_buffer_, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
|
pipeline_layout_, 0, 1, &uniform_set_, 0, nullptr);
|
||||||
|
vkCmdBindVertexBuffers(command_buffer_, 0, 1, &handle.buffer, &offset);
|
||||||
|
vkCmdDraw(command_buffer_, vertex_count, 1, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Graphics::RenderIndexedBuffer(BufferHandle vertex_buffer,
|
||||||
|
BufferHandle index_buffer,
|
||||||
|
std::uint32_t count) {
|
||||||
|
VkDeviceSize offset = 0;
|
||||||
|
vkCmdBindDescriptorSets(command_buffer_, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
|
pipeline_layout_, 0, 1, &uniform_set_, 0, nullptr);
|
||||||
|
vkCmdBindVertexBuffers(command_buffer_, 0, 1, &vertex_buffer.buffer, &offset);
|
||||||
|
vkCmdBindIndexBuffer(command_buffer_, index_buffer.buffer, 0,
|
||||||
|
VK_INDEX_TYPE_UINT32);
|
||||||
|
vkCmdDrawIndexed(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);
|
||||||
|
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_, uniform_buffer_.memory, 0, buffer_size, 0,
|
||||||
|
&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 = 1;
|
||||||
|
|
||||||
|
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 = 1;
|
||||||
|
|
||||||
|
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() {
|
||||||
|
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, &uniform_set_);
|
||||||
|
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
|
||||||
|
|
||||||
|
VkDescriptorBufferInfo buffer_info = {};
|
||||||
|
buffer_info.buffer = 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 = 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
|
||||||
94
src/vulkan/class.cpp
Normal file
94
src/vulkan/class.cpp
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
#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();
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
DestroyBuffer(uniform_buffer_);
|
||||||
|
|
||||||
|
if (uniform_set_layout_ != VK_NULL_HANDLE)
|
||||||
|
vkDestroyDescriptorSetLayout(logical_device_, uniform_set_layout_,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
if (image_available_signal_ != VK_NULL_HANDLE)
|
||||||
|
vkDestroySemaphore(logical_device_, image_available_signal_, nullptr);
|
||||||
|
|
||||||
|
if (render_finished_signal_ != VK_NULL_HANDLE)
|
||||||
|
vkDestroySemaphore(logical_device_, render_finished_signal_, nullptr);
|
||||||
|
|
||||||
|
if (still_rendering_fence_ != VK_NULL_HANDLE)
|
||||||
|
vkDestroyFence(logical_device_, still_rendering_fence_, 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();
|
||||||
|
CreateFramebuffers();
|
||||||
|
CreateCommandPool();
|
||||||
|
CreateCommandBuffer();
|
||||||
|
CreateSignals();
|
||||||
|
CreateUniformBuffers();
|
||||||
|
CreateDescriptorPools();
|
||||||
|
CreateDescriptorSets();
|
||||||
|
CreateTextureSampler();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace veng
|
||||||
169
src/vulkan/drawing.cpp
Normal file
169
src/vulkan/drawing.cpp
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
#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++) {
|
||||||
|
VkFramebufferCreateInfo info = {};
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||||
|
info.renderPass = render_pass_;
|
||||||
|
info.attachmentCount = 1;
|
||||||
|
info.pAttachments = &swap_chain_image_views_[i];
|
||||||
|
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;
|
||||||
|
|
||||||
|
VkResult result =
|
||||||
|
vkAllocateCommandBuffers(logical_device_, &info, &command_buffer_);
|
||||||
|
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Graphics::BeginCommands() {
|
||||||
|
vkResetCommandBuffer(command_buffer_, 0);
|
||||||
|
|
||||||
|
VkCommandBufferBeginInfo begin_info = {};
|
||||||
|
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
|
|
||||||
|
VkResult result = vkBeginCommandBuffer(command_buffer_, &begin_info);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("Failed to begin command buffer!");
|
||||||
|
|
||||||
|
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_;
|
||||||
|
|
||||||
|
VkClearValue clear_color = {{{0.f, 0.f, 0.f, 1.f}}};
|
||||||
|
render_pass_begin_info.clearValueCount = 1;
|
||||||
|
render_pass_begin_info.pClearValues = &clear_color;
|
||||||
|
|
||||||
|
vkCmdBeginRenderPass(command_buffer_, &render_pass_begin_info,
|
||||||
|
VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
vkCmdBindPipeline(command_buffer_, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
|
pipeline_);
|
||||||
|
VkViewport viewport = GetViewport();
|
||||||
|
VkRect2D scissor = GetScissor();
|
||||||
|
|
||||||
|
vkCmdSetViewport(command_buffer_, 0, 1, &viewport);
|
||||||
|
vkCmdSetScissor(command_buffer_, 0, 1, &scissor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Graphics::EndCommands() {
|
||||||
|
vkCmdEndRenderPass(command_buffer_);
|
||||||
|
VkResult result = vkEndCommandBuffer(command_buffer_);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("Failed to record command buffer!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Graphics::CreateSignals() {
|
||||||
|
VkSemaphoreCreateInfo semafore_info = {};
|
||||||
|
semafore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||||
|
|
||||||
|
if (vkCreateSemaphore(logical_device_, &semafore_info, nullptr,
|
||||||
|
&image_available_signal_) != VK_SUCCESS)
|
||||||
|
std::exit(EXIT_FAILURE);
|
||||||
|
if (vkCreateSemaphore(logical_device_, &semafore_info, nullptr,
|
||||||
|
&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,
|
||||||
|
&still_rendering_fence_) != VK_SUCCESS)
|
||||||
|
std::exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Graphics::BeginFrame() {
|
||||||
|
vkWaitForFences(logical_device_, 1, &still_rendering_fence_, VK_TRUE,
|
||||||
|
UINT64_MAX);
|
||||||
|
VkResult image_acquire_result = vkAcquireNextImageKHR(
|
||||||
|
logical_device_, swap_chain_, UINT64_MAX, image_available_signal_,
|
||||||
|
VK_NULL_HANDLE, ¤t_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, &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 = &image_available_signal_;
|
||||||
|
submit_info.pWaitDstStageMask = &wait_stage;
|
||||||
|
submit_info.commandBufferCount = 1;
|
||||||
|
submit_info.pCommandBuffers = &command_buffer_;
|
||||||
|
submit_info.signalSemaphoreCount = 1;
|
||||||
|
submit_info.pSignalSemaphores = &render_finished_signal_;
|
||||||
|
|
||||||
|
VkResult submit_result =
|
||||||
|
vkQueueSubmit(graphics_queue_, 1, &submit_info, 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 = &render_finished_signal_;
|
||||||
|
present_info.swapchainCount = 1;
|
||||||
|
present_info.pSwapchains = &swap_chain_;
|
||||||
|
present_info.pImageIndices = ¤t_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!");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace veng
|
||||||
@@ -8,52 +8,4 @@
|
|||||||
|
|
||||||
namespace veng {
|
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) {
|
|
||||||
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);
|
|
||||||
|
|
||||||
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();
|
|
||||||
CreateRenderPass();
|
|
||||||
CreateGraphicsPipeline();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace veng
|
} // namespace veng
|
||||||
|
|||||||
@@ -21,6 +21,26 @@ VkShaderModule Graphics::CreateShaderModule(gsl::span<std::uint8_t> buffer) {
|
|||||||
return shader_module;
|
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() {
|
void Graphics::CreateGraphicsPipeline() {
|
||||||
std::vector<std::uint8_t> basic_vertex_data = ReadFile("./basic.vert.spv");
|
std::vector<std::uint8_t> basic_vertex_data = ReadFile("./basic.vert.spv");
|
||||||
VkShaderModule vertex_shader = CreateShaderModule(basic_vertex_data);
|
VkShaderModule vertex_shader = CreateShaderModule(basic_vertex_data);
|
||||||
@@ -62,17 +82,9 @@ void Graphics::CreateGraphicsPipeline() {
|
|||||||
dynamic_state_info.dynamicStateCount = dynamic_states.size();
|
dynamic_state_info.dynamicStateCount = dynamic_states.size();
|
||||||
dynamic_state_info.pDynamicStates = dynamic_states.data();
|
dynamic_state_info.pDynamicStates = dynamic_states.data();
|
||||||
|
|
||||||
VkViewport viewport = {};
|
VkViewport viewport = GetViewport();
|
||||||
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;
|
|
||||||
|
|
||||||
VkRect2D scissor = {};
|
VkRect2D scissor = GetScissor();
|
||||||
scissor.offset = {0, 0};
|
|
||||||
scissor.extent = extent_;
|
|
||||||
|
|
||||||
VkPipelineViewportStateCreateInfo viewport_info = {};
|
VkPipelineViewportStateCreateInfo viewport_info = {};
|
||||||
viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||||
@@ -81,11 +93,18 @@ void Graphics::CreateGraphicsPipeline() {
|
|||||||
viewport_info.scissorCount = 1;
|
viewport_info.scissorCount = 1;
|
||||||
viewport_info.pScissors = &scissor;
|
viewport_info.pScissors = &scissor;
|
||||||
|
|
||||||
|
auto vertex_binding_description = Vertex::GetBindingDescription();
|
||||||
|
auto vertex_attribute_descriptions = Vertex::GetAttributeDescriptions();
|
||||||
|
|
||||||
VkPipelineVertexInputStateCreateInfo vertex_input_info = {};
|
VkPipelineVertexInputStateCreateInfo vertex_input_info = {};
|
||||||
vertex_input_info.sType =
|
vertex_input_info.sType =
|
||||||
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||||
vertex_input_info.vertexBindingDescriptionCount = 0;
|
vertex_input_info.vertexBindingDescriptionCount = 1;
|
||||||
vertex_input_info.vertexAttributeDescriptionCount = 0;
|
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 = {};
|
VkPipelineInputAssemblyStateCreateInfo input_assembly_info = {};
|
||||||
input_assembly_info.sType =
|
input_assembly_info.sType =
|
||||||
@@ -111,10 +130,17 @@ void Graphics::CreateGraphicsPipeline() {
|
|||||||
multisampling_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
multisampling_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
|
||||||
VkPipelineColorBlendAttachmentState color_blend_attachment = {};
|
VkPipelineColorBlendAttachmentState color_blend_attachment = {};
|
||||||
color_blend_attachment.blendEnable = VK_FALSE;
|
|
||||||
color_blend_attachment.colorWriteMask =
|
color_blend_attachment.colorWriteMask =
|
||||||
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_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 = {};
|
VkPipelineColorBlendStateCreateInfo color_blending_info = {};
|
||||||
color_blending_info.sType =
|
color_blending_info.sType =
|
||||||
@@ -123,8 +149,20 @@ void Graphics::CreateGraphicsPipeline() {
|
|||||||
color_blending_info.attachmentCount = 1;
|
color_blending_info.attachmentCount = 1;
|
||||||
color_blending_info.pAttachments = &color_blend_attachment;
|
color_blending_info.pAttachments = &color_blend_attachment;
|
||||||
|
|
||||||
|
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 = {};
|
VkPipelineLayoutCreateInfo layout_info = {};
|
||||||
layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_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,
|
VkResult layout_result = vkCreatePipelineLayout(logical_device_, &layout_info,
|
||||||
nullptr, &pipeline_layout_);
|
nullptr, &pipeline_layout_);
|
||||||
@@ -183,4 +221,33 @@ void Graphics::CreateRenderPass() {
|
|||||||
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
|
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();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace veng
|
} // namespace veng
|
||||||
|
|||||||
@@ -140,29 +140,35 @@ void Graphics::CreateSwapChain() {
|
|||||||
swap_chain_images_.data());
|
swap_chain_images_.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkImageView Graphics::CreateImageView(VkImage image, VkFormat format) {
|
||||||
|
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 = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
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() {
|
void Graphics::CreateImageViews() {
|
||||||
swap_chain_image_views_.resize(swap_chain_images_.size());
|
swap_chain_image_views_.resize(swap_chain_images_.size());
|
||||||
|
|
||||||
auto image_view_it = swap_chain_image_views_.begin();
|
auto image_view_it = swap_chain_image_views_.begin();
|
||||||
for (VkImage image : swap_chain_images_) {
|
for (VkImage image : swap_chain_images_) {
|
||||||
VkImageViewCreateInfo info = {};
|
*image_view_it = CreateImageView(image, surface_format_.format);
|
||||||
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::advance(image_view_it, 1);
|
std::advance(image_view_it, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
219
src/vulkan/texture.cpp
Normal file
219
src/vulkan/texture.cpp
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
#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_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);
|
||||||
|
|
||||||
|
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_);
|
||||||
|
vkFreeDescriptorSets(logical_device_, texture_pool_, 1, &handle.set);
|
||||||
|
vkDestroyImageView(logical_device_, handle.image_view, nullptr);
|
||||||
|
vkDestroyImage(logical_device_, handle.image, nullptr);
|
||||||
|
vkFreeMemory(logical_device_, handle.memory, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Graphics::SetTexture(TextureHandle handle) {
|
||||||
|
vkCmdBindDescriptorSets(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.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, ®ion);
|
||||||
|
|
||||||
|
EndTransientCommandBuffer(local_command_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureHandle Graphics::CreateImage(glm::ivec2 size, 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 = VK_FORMAT_R8G8B8A8_SRGB;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace veng
|
||||||
Reference in New Issue
Block a user