|
|
|
@ -5,6 +5,8 @@ |
|
|
|
|
|
|
|
#include <SDL2/SDL_vulkan.h> |
|
|
|
|
|
|
|
#include <Eigen/Geometry> |
|
|
|
|
|
|
|
#include <cassert> |
|
|
|
#include <stdexcept> |
|
|
|
#include <array> |
|
|
|
@ -26,7 +28,7 @@ std::array<VkVertexInputAttributeDescription, 2> Vertex::attributes_description( |
|
|
|
VkVertexInputAttributeDescription { |
|
|
|
.location = 0, |
|
|
|
.binding = 0, |
|
|
|
.format = VK_FORMAT_R32G32_SFLOAT, |
|
|
|
.format = VK_FORMAT_R32G32B32_SFLOAT, |
|
|
|
.offset = offsetof(Vertex, position), |
|
|
|
}, |
|
|
|
{ |
|
|
|
@ -40,15 +42,40 @@ std::array<VkVertexInputAttributeDescription, 2> Vertex::attributes_description( |
|
|
|
|
|
|
|
|
|
|
|
const std::vector<Vertex> vertices = { |
|
|
|
{{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}}, |
|
|
|
{{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}}, |
|
|
|
{{-0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}}, |
|
|
|
{{0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}}, |
|
|
|
{{-0.5f, -0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}}, |
|
|
|
{{0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}}, |
|
|
|
{{-0.5f, 0.5f, -0.5f}, {0.0f, 0.0f, 1.0f}}, |
|
|
|
{{0.5f, 0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}}, |
|
|
|
|
|
|
|
{{-0.5f, -0.5f, 0.5f}, {0.0f, 1.0f, 1.0f}}, |
|
|
|
{{0.5f, -0.5f, 0.5f}, {1.0f, 0.0f, 1.0f}}, |
|
|
|
{{-0.5f, 0.5f, 0.5f}, {1.0f, 1.0f, 0.0f}}, |
|
|
|
{{0.5f, 0.5f, 0.5f}, {0.2f, 0.2f, 0.2f}}, |
|
|
|
}; |
|
|
|
|
|
|
|
const std::vector<uint16_t> indices = { |
|
|
|
0, 1, 2, |
|
|
|
2, 1, 3, |
|
|
|
|
|
|
|
1, 5, 3, |
|
|
|
3, 5, 7, |
|
|
|
|
|
|
|
5, 4, 7, |
|
|
|
7, 4, 6, |
|
|
|
|
|
|
|
4, 0, 6, |
|
|
|
6, 0, 2, |
|
|
|
|
|
|
|
0, 4, 1, |
|
|
|
1, 4, 5, |
|
|
|
|
|
|
|
2, 3, 6, |
|
|
|
6, 3, 7, |
|
|
|
}; |
|
|
|
|
|
|
|
struct Uniforms { |
|
|
|
alignas(16) Eigen::Matrix4f scene_from_model; |
|
|
|
alignas(16) Eigen::Matrix4f projection_from_scene; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
@ -73,6 +100,7 @@ void VulkanTutorial::initialize(SDL_Window* window) { |
|
|
|
m_context.initialize(context_settings); |
|
|
|
|
|
|
|
create_command_pool(); |
|
|
|
create_descriptor_set_layout(); |
|
|
|
create_vertex_buffer(); |
|
|
|
create_index_buffer(); |
|
|
|
|
|
|
|
@ -95,6 +123,7 @@ void VulkanTutorial::shutdown() { |
|
|
|
m_context.destroy_buffer(m_index_buffer); |
|
|
|
m_context.free_memory(m_vertex_buffer_memory); |
|
|
|
m_context.destroy_buffer(m_vertex_buffer); |
|
|
|
m_context.destroy_descriptor_set_layout(m_descriptor_set_layout); |
|
|
|
|
|
|
|
for(VkSemaphore semaphore: m_render_done) |
|
|
|
m_context.destroy_semaphore(semaphore); |
|
|
|
@ -108,6 +137,57 @@ void VulkanTutorial::draw_frame() { |
|
|
|
m_swapchain.begin_frame(); |
|
|
|
auto const image_index = m_swapchain.current_image_index(); |
|
|
|
|
|
|
|
const auto now = Clock::now(); |
|
|
|
if(m_last_frame_time.time_since_epoch() != Duration(0)) { |
|
|
|
m_time += now - m_last_frame_time; |
|
|
|
} |
|
|
|
m_last_frame_time = now; |
|
|
|
|
|
|
|
const float alpha = SecondsD(m_time).count() * (2.0 * M_PI) / 3.0; |
|
|
|
const float dist = 2.0f; |
|
|
|
const Eigen::Matrix4f view = look_at_matrix( |
|
|
|
// Eigen::Vector3f(0.0f, 0.0f, -dist),
|
|
|
|
Eigen::Vector3f(0.0f, -dist, -dist), |
|
|
|
// dist * Eigen::Vector3f(std::cos(alpha), std::sin(alpha), -1.0),
|
|
|
|
Eigen::Vector3f::Zero(), |
|
|
|
-Eigen::Vector3f::UnitY() |
|
|
|
); |
|
|
|
|
|
|
|
const float fov = M_PI / 3.0f; |
|
|
|
const float near = 0.1f; |
|
|
|
const float far = 10.0f; |
|
|
|
const float hx = near * std::tan(fov / 2.0f); |
|
|
|
const float hy = hx * m_swapchain.extent().height / m_swapchain.extent().width; |
|
|
|
const Eigen::Matrix4f proj = projection_matrix( |
|
|
|
-hx, hx, |
|
|
|
-hy, hy, |
|
|
|
near, far |
|
|
|
); |
|
|
|
|
|
|
|
using Transform = Eigen::Transform<float, 3, Eigen::Affine>; |
|
|
|
Transform model = Transform::Identity(); |
|
|
|
model.rotate(Eigen::AngleAxisf( |
|
|
|
alpha, |
|
|
|
Eigen::Vector3f::UnitY() |
|
|
|
)); |
|
|
|
|
|
|
|
const Uniforms uniforms = { |
|
|
|
.scene_from_model = model.matrix(), |
|
|
|
.projection_from_scene = proj * view, |
|
|
|
}; |
|
|
|
|
|
|
|
void* uniform_buffer; |
|
|
|
vkMapMemory( |
|
|
|
m_context.device(), |
|
|
|
m_uniform_buffer_memory, |
|
|
|
m_uniform_buffer_offsets[image_index], |
|
|
|
sizeof(Uniforms), |
|
|
|
0, |
|
|
|
&uniform_buffer |
|
|
|
); |
|
|
|
std::memcpy(uniform_buffer, &uniforms, sizeof(Uniforms)); |
|
|
|
vkUnmapMemory(m_context.device(), m_uniform_buffer_memory); |
|
|
|
|
|
|
|
VkSemaphore wait_semaphores[] = { |
|
|
|
m_swapchain.ready_to_render(), |
|
|
|
}; |
|
|
|
@ -142,6 +222,9 @@ void VulkanTutorial::invalidate_swapchain() { |
|
|
|
void VulkanTutorial::create_swapchain_objects(uint32_t image_count) { |
|
|
|
create_render_pass(); |
|
|
|
create_framebuffers(); |
|
|
|
create_uniform_buffer(); |
|
|
|
create_descriptor_pool(); |
|
|
|
create_descriptor_sets(); |
|
|
|
create_graphic_pipeline(); |
|
|
|
create_command_buffers(); |
|
|
|
|
|
|
|
@ -174,6 +257,13 @@ void VulkanTutorial::destroy_swapchain_objects() { |
|
|
|
); |
|
|
|
m_command_buffers.clear(); |
|
|
|
|
|
|
|
for(VkBuffer buffer: m_uniform_buffers) |
|
|
|
m_context.destroy_buffer(buffer); |
|
|
|
m_uniform_buffers.clear(); |
|
|
|
m_context.free_memory(m_uniform_buffer_memory); |
|
|
|
|
|
|
|
m_context.destroy_descriptor_pool(m_descriptor_pool); |
|
|
|
|
|
|
|
for(VkFramebuffer framebuffer: m_framebuffers) |
|
|
|
m_context.destroy_framebuffer(framebuffer); |
|
|
|
m_framebuffers.clear(); |
|
|
|
@ -234,6 +324,28 @@ void VulkanTutorial::create_render_pass() { |
|
|
|
throw std::runtime_error("failed to create render pass"); |
|
|
|
} |
|
|
|
|
|
|
|
void VulkanTutorial::create_descriptor_set_layout() { |
|
|
|
VkDescriptorSetLayoutBinding binding { |
|
|
|
.binding = 0, |
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, |
|
|
|
.descriptorCount = 1, |
|
|
|
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT, |
|
|
|
}; |
|
|
|
|
|
|
|
VkDescriptorSetLayoutCreateInfo layout_info { |
|
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, |
|
|
|
.bindingCount = 1, |
|
|
|
.pBindings = &binding, |
|
|
|
}; |
|
|
|
if(vkCreateDescriptorSetLayout( |
|
|
|
m_context.device(), |
|
|
|
&layout_info, |
|
|
|
nullptr, |
|
|
|
&m_descriptor_set_layout |
|
|
|
) != VK_SUCCESS) |
|
|
|
throw std::runtime_error("failed to create descriptor set layout"); |
|
|
|
} |
|
|
|
|
|
|
|
void VulkanTutorial::create_graphic_pipeline() { |
|
|
|
auto const vertex_shader_module = |
|
|
|
m_context.create_shader_module_from_file("shaders/shader.vert.spv"); |
|
|
|
@ -353,8 +465,8 @@ void VulkanTutorial::create_graphic_pipeline() { |
|
|
|
|
|
|
|
VkPipelineLayoutCreateInfo layout_info = { |
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, |
|
|
|
.setLayoutCount = 0, |
|
|
|
.pSetLayouts = nullptr, |
|
|
|
.setLayoutCount = 1, |
|
|
|
.pSetLayouts = &m_descriptor_set_layout, |
|
|
|
.pushConstantRangeCount = 0, |
|
|
|
.pPushConstantRanges = nullptr, |
|
|
|
}; |
|
|
|
@ -467,6 +579,115 @@ void VulkanTutorial::create_index_buffer() { |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
void VulkanTutorial::create_uniform_buffer() { |
|
|
|
m_uniform_buffers.assign(m_swapchain.image_count(), VK_NULL_HANDLE); |
|
|
|
for(size_t index = 0; index < m_uniform_buffers.size(); index += 1) { |
|
|
|
VkBufferCreateInfo buffer_info { |
|
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
|
|
|
.size = sizeof(Uniforms), |
|
|
|
.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, |
|
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
|
|
|
}; |
|
|
|
|
|
|
|
if(vkCreateBuffer( |
|
|
|
m_context.device(), |
|
|
|
&buffer_info, |
|
|
|
nullptr, |
|
|
|
&m_uniform_buffers[index] |
|
|
|
) != VK_SUCCESS) |
|
|
|
throw std::runtime_error("failed to create buffer"); |
|
|
|
} |
|
|
|
|
|
|
|
VkMemoryRequirements memory_requirements; |
|
|
|
vkGetBufferMemoryRequirements( |
|
|
|
m_context.device(), |
|
|
|
m_uniform_buffers[0], |
|
|
|
&memory_requirements |
|
|
|
); |
|
|
|
|
|
|
|
m_uniform_buffer_memory = m_context.allocate_memory( |
|
|
|
memory_requirements.size * m_swapchain.image_count(), |
|
|
|
memory_requirements.memoryTypeBits, |
|
|
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
|
|
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
|
|
|
); |
|
|
|
|
|
|
|
m_uniform_buffer_offsets.resize(m_uniform_buffers.size()); |
|
|
|
for(size_t index = 0; index < m_uniform_buffers.size(); index += 1) { |
|
|
|
m_uniform_buffer_offsets[index] = index * memory_requirements.size; |
|
|
|
vkBindBufferMemory( |
|
|
|
m_context.device(), |
|
|
|
m_uniform_buffers[index], |
|
|
|
m_uniform_buffer_memory, |
|
|
|
m_uniform_buffer_offsets[index] |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void VulkanTutorial::create_descriptor_pool() { |
|
|
|
VkDescriptorPoolSize pool_size { |
|
|
|
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, |
|
|
|
.descriptorCount = uint32_t(m_swapchain.image_count()), |
|
|
|
}; |
|
|
|
|
|
|
|
VkDescriptorPoolCreateInfo pool_info { |
|
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, |
|
|
|
.maxSets = uint32_t(m_swapchain.image_count()), |
|
|
|
.poolSizeCount = 1, |
|
|
|
.pPoolSizes = &pool_size, |
|
|
|
}; |
|
|
|
if(vkCreateDescriptorPool( |
|
|
|
m_context.device(), |
|
|
|
&pool_info, |
|
|
|
nullptr, |
|
|
|
&m_descriptor_pool |
|
|
|
) != VK_SUCCESS) |
|
|
|
throw std::runtime_error("failed to create descriptor pool"); |
|
|
|
} |
|
|
|
|
|
|
|
void VulkanTutorial::create_descriptor_sets() { |
|
|
|
const std::vector<VkDescriptorSetLayout> layouts( |
|
|
|
m_swapchain.image_count(), m_descriptor_set_layout); |
|
|
|
|
|
|
|
VkDescriptorSetAllocateInfo alloc_info { |
|
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, |
|
|
|
.descriptorPool = m_descriptor_pool, |
|
|
|
.descriptorSetCount = uint32_t(layouts.size()), |
|
|
|
.pSetLayouts = layouts.data(), |
|
|
|
}; |
|
|
|
|
|
|
|
m_descriptor_sets.resize(m_swapchain.image_count()); |
|
|
|
if(vkAllocateDescriptorSets( |
|
|
|
m_context.device(), |
|
|
|
&alloc_info, |
|
|
|
m_descriptor_sets.data() |
|
|
|
) != VK_SUCCESS) |
|
|
|
throw std::runtime_error("failed to allocate descriptor sets"); |
|
|
|
|
|
|
|
for(size_t index = 0; index < m_swapchain.image_count(); index += 1) { |
|
|
|
VkDescriptorBufferInfo buffer_info { |
|
|
|
.buffer = m_uniform_buffers[index], |
|
|
|
.offset = 0, |
|
|
|
.range = sizeof(Uniforms), |
|
|
|
}; |
|
|
|
|
|
|
|
VkWriteDescriptorSet write { |
|
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, |
|
|
|
.dstSet = m_descriptor_sets[index], |
|
|
|
.dstBinding = 0, |
|
|
|
.dstArrayElement = 0, |
|
|
|
.descriptorCount = 1, |
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, |
|
|
|
.pBufferInfo = &buffer_info, |
|
|
|
}; |
|
|
|
vkUpdateDescriptorSets( |
|
|
|
m_context.device(), |
|
|
|
1, &write, |
|
|
|
0, nullptr |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void VulkanTutorial::create_command_buffers() { |
|
|
|
m_command_buffers.resize(m_framebuffers.size()); |
|
|
|
|
|
|
|
@ -545,6 +766,14 @@ void VulkanTutorial::create_command_buffers() { |
|
|
|
offsets |
|
|
|
); |
|
|
|
|
|
|
|
vkCmdBindDescriptorSets( |
|
|
|
command_buffer, |
|
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS, |
|
|
|
m_pipeline_layout, |
|
|
|
0, 1, &m_descriptor_sets[index], |
|
|
|
0, nullptr |
|
|
|
); |
|
|
|
|
|
|
|
vkCmdBindIndexBuffer( |
|
|
|
command_buffer, |
|
|
|
m_index_buffer, |
|
|
|
|