Uniform buffers.
This commit is contained in:
@@ -537,6 +537,14 @@ void Context::destroy_command_pool(VkCommandPool& command_pool) {
|
||||
command_pool = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void Context::destroy_descriptor_pool(VkDescriptorPool& descriptor_pool) {
|
||||
if(descriptor_pool == VK_NULL_HANDLE)
|
||||
return;
|
||||
|
||||
vkDestroyDescriptorPool(m_device, descriptor_pool, nullptr);
|
||||
descriptor_pool = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void Context::destroy_render_pass(VkRenderPass& render_pass) {
|
||||
if(render_pass == VK_NULL_HANDLE)
|
||||
return;
|
||||
@@ -545,6 +553,14 @@ void Context::destroy_render_pass(VkRenderPass& render_pass) {
|
||||
render_pass = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void Context::destroy_descriptor_set_layout(VkDescriptorSetLayout& descriptor_set_layout) {
|
||||
if(descriptor_set_layout == VK_NULL_HANDLE)
|
||||
return;
|
||||
|
||||
vkDestroyDescriptorSetLayout(m_device, descriptor_set_layout, nullptr);
|
||||
descriptor_set_layout = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void Context::destroy_pipeline_layout(VkPipelineLayout& pipeline_layout) {
|
||||
if(pipeline_layout == VK_NULL_HANDLE)
|
||||
return;
|
||||
|
||||
@@ -128,8 +128,10 @@ public:
|
||||
void destroy_buffer(VkBuffer& buffer);
|
||||
|
||||
void destroy_command_pool(VkCommandPool& command_pool);
|
||||
void destroy_descriptor_pool(VkDescriptorPool& descriptor_pool);
|
||||
|
||||
void destroy_render_pass(VkRenderPass& render_pass);
|
||||
void destroy_descriptor_set_layout(VkDescriptorSetLayout& descriptor_set_layout);
|
||||
void destroy_pipeline_layout(VkPipelineLayout& pipeline_layout);
|
||||
void destroy_pipeline(VkPipeline& pipeline);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <Eigen/Dense>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
|
||||
|
||||
struct Vertex {
|
||||
Eigen::Vector2f position;
|
||||
Eigen::Vector3f position;
|
||||
Eigen::Vector3f color;
|
||||
|
||||
static VkVertexInputBindingDescription binding_description();
|
||||
@@ -24,6 +25,11 @@ public:
|
||||
GRAPHIC_QUEUE,
|
||||
};
|
||||
|
||||
using Clock = std::chrono::high_resolution_clock;
|
||||
using TimePoint = Clock::time_point;
|
||||
using Duration = Clock::duration;
|
||||
using SecondsD = std::chrono::duration<double>;
|
||||
|
||||
public:
|
||||
VulkanTutorial();
|
||||
VulkanTutorial(const VulkanTutorial&) = delete;
|
||||
@@ -42,11 +48,15 @@ private:
|
||||
void destroy_swapchain_objects();
|
||||
|
||||
void create_render_pass();
|
||||
void create_descriptor_set_layout();
|
||||
void create_graphic_pipeline();
|
||||
void create_framebuffers();
|
||||
void create_command_pool();
|
||||
void create_vertex_buffer();
|
||||
void create_index_buffer();
|
||||
void create_uniform_buffer();
|
||||
void create_descriptor_pool();
|
||||
void create_descriptor_sets();
|
||||
void create_command_buffers();
|
||||
|
||||
private:
|
||||
@@ -56,6 +66,7 @@ private:
|
||||
VkQueue m_presentation_queue = nullptr;
|
||||
|
||||
VkRenderPass m_render_pass = VK_NULL_HANDLE;
|
||||
VkDescriptorSetLayout m_descriptor_set_layout = VK_NULL_HANDLE;
|
||||
VkPipelineLayout m_pipeline_layout = VK_NULL_HANDLE;
|
||||
VkPipeline m_pipeline = VK_NULL_HANDLE;
|
||||
std::vector<VkFramebuffer> m_framebuffers;
|
||||
@@ -64,6 +75,14 @@ private:
|
||||
VkDeviceMemory m_vertex_buffer_memory = VK_NULL_HANDLE;
|
||||
VkBuffer m_index_buffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory m_index_buffer_memory = VK_NULL_HANDLE;
|
||||
std::vector<VkBuffer> m_uniform_buffers;
|
||||
std::vector<VkDeviceSize> m_uniform_buffer_offsets;
|
||||
VkDeviceMemory m_uniform_buffer_memory = VK_NULL_HANDLE;
|
||||
VkDescriptorPool m_descriptor_pool = VK_NULL_HANDLE;
|
||||
std::vector<VkDescriptorSet> m_descriptor_sets;
|
||||
std::vector<VkCommandBuffer> m_command_buffers;
|
||||
std::vector<VkSemaphore> m_render_done;
|
||||
|
||||
TimePoint m_last_frame_time;
|
||||
Duration m_time = Duration(0);
|
||||
};
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#include <Logger.h>
|
||||
#include <VkExpe.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
VkExpe vk_expe(argc, argv);
|
||||
|
||||
@@ -23,3 +23,39 @@ std::vector<char> read_binary_file(const char* path) {
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
Eigen::Matrix4f projection_matrix(float x_min, float x_max, float y_min, float y_max, float z_min, float z_max) {
|
||||
auto const cx = x_max + x_min;
|
||||
auto const cy = y_max + y_min;
|
||||
auto const cz = z_max + z_min;
|
||||
|
||||
auto const dx = x_max - x_min;
|
||||
auto const dy = y_max - y_min;
|
||||
auto const dz = z_max - z_min;
|
||||
|
||||
auto const pz = z_max * z_min;
|
||||
|
||||
return (Eigen::Matrix4f() <<
|
||||
2.0f * z_min / dx, 0.0f, -cx / dx, 0.0f,
|
||||
0.0f, 2.0f * z_min / dy, -cy / dy, 0.0f,
|
||||
0.0f, 0.0f, cz / dz, -2.0f * pz / dz,
|
||||
0.0f, 0.0f, 1.0f, 0.0f
|
||||
).finished();
|
||||
}
|
||||
|
||||
Eigen::Matrix4f look_at_matrix(
|
||||
const Eigen::Vector3f& cam_pos,
|
||||
const Eigen::Vector3f& look_at,
|
||||
const Eigen::Vector3f& up
|
||||
) {
|
||||
const Eigen::Vector3f z = (look_at - cam_pos).normalized();
|
||||
const Eigen::Vector3f x = z.cross(up).normalized();
|
||||
const Eigen::Vector3f y = z.cross(x).normalized();
|
||||
|
||||
const auto view_linear = (Eigen::Matrix3f() << x, y, z).finished().transpose();
|
||||
return (Eigen::Matrix4f() <<
|
||||
view_linear,
|
||||
view_linear * (-cam_pos),
|
||||
Eigen::Vector4f::UnitW().transpose()
|
||||
).finished();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Eigen/Dense>
|
||||
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
@@ -74,3 +76,10 @@ private:
|
||||
size_t m_size = 0;
|
||||
T* m_data = nullptr;
|
||||
};
|
||||
|
||||
Eigen::Matrix4f projection_matrix(float x_min, float x_max, float y_min, float y_max, float z_min, float z_max);
|
||||
Eigen::Matrix4f look_at_matrix(
|
||||
const Eigen::Vector3f& cam_pos,
|
||||
const Eigen::Vector3f& look_at,
|
||||
const Eigen::Vector3f& up
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user