You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
798 lines
24 KiB
798 lines
24 KiB
#include <VulkanTutorial.h>
|
|
|
|
#include <utils.h>
|
|
#include <Logger.h>
|
|
|
|
#include <SDL2/SDL_vulkan.h>
|
|
|
|
#include <Eigen/Geometry>
|
|
|
|
#include <cassert>
|
|
#include <stdexcept>
|
|
#include <array>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
|
|
|
|
VkVertexInputBindingDescription Vertex::binding_description() {
|
|
return {
|
|
.binding = 0,
|
|
.stride = sizeof(Vertex),
|
|
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
|
|
};
|
|
}
|
|
|
|
std::array<VkVertexInputAttributeDescription, 2> Vertex::attributes_description() {
|
|
return {
|
|
VkVertexInputAttributeDescription {
|
|
.location = 0,
|
|
.binding = 0,
|
|
.format = VK_FORMAT_R32G32B32_SFLOAT,
|
|
.offset = offsetof(Vertex, position),
|
|
},
|
|
{
|
|
.location = 1,
|
|
.binding = 0,
|
|
.format = VK_FORMAT_R32G32B32_SFLOAT,
|
|
.offset = offsetof(Vertex, color),
|
|
},
|
|
};
|
|
}
|
|
|
|
|
|
const std::vector<Vertex> vertices = {
|
|
{{-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;
|
|
};
|
|
|
|
|
|
VulkanTutorial::VulkanTutorial() {
|
|
m_swapchain.register_creation_callback(
|
|
std::bind(&VulkanTutorial::create_swapchain_objects, this, std::placeholders::_1));
|
|
m_swapchain.register_destruction_callback(
|
|
std::bind(&VulkanTutorial::destroy_swapchain_objects, this));
|
|
}
|
|
|
|
VulkanTutorial::~VulkanTutorial() {
|
|
shutdown();
|
|
}
|
|
|
|
void VulkanTutorial::initialize(SDL_Window* window) {
|
|
auto const context_settings = Vulkan::ContextSettings()
|
|
#if defined(VKEXPE_ENABLE_VALIDATION) || !defined(NDEBUG)
|
|
.with_debug(true)
|
|
#endif
|
|
.with_queue(GRAPHIC_QUEUE, VK_QUEUE_GRAPHICS_BIT)
|
|
.with_window(window);
|
|
m_context.initialize(context_settings);
|
|
|
|
create_command_pool();
|
|
create_descriptor_set_layout();
|
|
create_vertex_buffer();
|
|
create_index_buffer();
|
|
|
|
auto const swapchain_settings = Vulkan::SwapchainSettings(&m_context)
|
|
.with_queue(m_context.queue_family(GRAPHIC_QUEUE));
|
|
m_swapchain.initialize(swapchain_settings);
|
|
}
|
|
|
|
void VulkanTutorial::shutdown() {
|
|
if(!m_context.instance())
|
|
return;
|
|
|
|
vkDeviceWaitIdle(m_context.device());
|
|
|
|
destroy_swapchain_objects();
|
|
|
|
m_context.free_memory(m_vertex_buffer_memory);
|
|
m_context.destroy_command_pool(m_command_pool);
|
|
m_context.free_memory(m_index_buffer_memory);
|
|
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);
|
|
m_render_done.clear();
|
|
|
|
m_swapchain.shutdown();
|
|
m_context.shutdown();
|
|
}
|
|
|
|
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(),
|
|
};
|
|
VkPipelineStageFlags stages[] = {
|
|
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
};
|
|
VkSubmitInfo submit_info {
|
|
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
|
.waitSemaphoreCount = 1,
|
|
.pWaitSemaphores = wait_semaphores,
|
|
.pWaitDstStageMask = stages,
|
|
.commandBufferCount = 1,
|
|
.pCommandBuffers = &m_command_buffers[image_index],
|
|
.signalSemaphoreCount = 1,
|
|
.pSignalSemaphores = &m_render_done[image_index],
|
|
};
|
|
|
|
if(vkQueueSubmit(
|
|
m_context.queue(GRAPHIC_QUEUE),
|
|
1, &submit_info,
|
|
m_swapchain.render_done()
|
|
))
|
|
throw std::runtime_error("failed to submit draw command buffer");
|
|
|
|
m_swapchain.swap_buffers({1, &m_render_done[image_index]});
|
|
}
|
|
|
|
void VulkanTutorial::invalidate_swapchain() {
|
|
m_swapchain.invalidate();
|
|
}
|
|
|
|
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();
|
|
|
|
m_render_done.resize(m_swapchain.image_count());
|
|
|
|
VkSemaphoreCreateInfo semaphore_info {
|
|
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
|
};
|
|
|
|
for(size_t index = 0; index < m_render_done.size(); index += 1) {
|
|
if(vkCreateSemaphore(
|
|
m_context.device(),
|
|
&semaphore_info,
|
|
nullptr,
|
|
&m_render_done[index]
|
|
) != VK_SUCCESS)
|
|
throw std::runtime_error("failed to create semaphore");
|
|
}
|
|
}
|
|
|
|
void VulkanTutorial::destroy_swapchain_objects() {
|
|
if(m_command_pool == VK_NULL_HANDLE)
|
|
return;
|
|
|
|
vkFreeCommandBuffers(
|
|
m_context.device(),
|
|
m_command_pool,
|
|
uint32_t(m_command_buffers.size()),
|
|
m_command_buffers.data()
|
|
);
|
|
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();
|
|
|
|
m_context.destroy_pipeline(m_pipeline);
|
|
m_context.destroy_pipeline_layout(m_pipeline_layout);
|
|
m_context.destroy_render_pass(m_render_pass);
|
|
}
|
|
|
|
void VulkanTutorial::create_render_pass() {
|
|
VkAttachmentDescription color_attachment {
|
|
.format = m_context.surface_format().format,
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
|
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
|
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
|
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
|
.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
|
};
|
|
|
|
VkAttachmentReference color_attachment_ref = {
|
|
.attachment = 0,
|
|
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
|
};
|
|
|
|
VkSubpassDescription subpass {
|
|
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
.colorAttachmentCount = 1,
|
|
.pColorAttachments = &color_attachment_ref,
|
|
};
|
|
|
|
VkSubpassDependency subpass_dep = {
|
|
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
|
.dstSubpass = 0,
|
|
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
.srcAccessMask = 0,
|
|
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
};
|
|
|
|
VkRenderPassCreateInfo render_pass_info {
|
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
|
.attachmentCount = 1,
|
|
.pAttachments = &color_attachment,
|
|
.subpassCount = 1,
|
|
.pSubpasses = &subpass,
|
|
.dependencyCount = 1,
|
|
.pDependencies = &subpass_dep,
|
|
};
|
|
|
|
if(vkCreateRenderPass(
|
|
m_context.device(),
|
|
&render_pass_info,
|
|
nullptr,
|
|
&m_render_pass
|
|
) != VK_SUCCESS)
|
|
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");
|
|
auto const vertex_shader_guard = make_guard([&]{
|
|
vkDestroyShaderModule(m_context.device(), vertex_shader_module, nullptr);
|
|
});
|
|
|
|
auto const fragment_shader_module =
|
|
m_context.create_shader_module_from_file("shaders/shader.frag.spv");
|
|
auto const fragment_shader_guard = make_guard([&]{
|
|
vkDestroyShaderModule(m_context.device(), fragment_shader_module, nullptr);
|
|
});
|
|
|
|
VkPipelineShaderStageCreateInfo shader_stage_infos[] = {
|
|
{
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
|
.module = vertex_shader_module,
|
|
.pName = "main",
|
|
},
|
|
{
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
.module = fragment_shader_module,
|
|
.pName = "main",
|
|
},
|
|
};
|
|
|
|
const VkVertexInputBindingDescription vertex_bindings[] = {
|
|
Vertex::binding_description(),
|
|
};
|
|
const auto vertex_attributes = Vertex::attributes_description();
|
|
|
|
VkPipelineVertexInputStateCreateInfo vertex_info {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
|
.vertexBindingDescriptionCount = 1,
|
|
.pVertexBindingDescriptions = vertex_bindings,
|
|
.vertexAttributeDescriptionCount = uint32_t(vertex_attributes.size()),
|
|
.pVertexAttributeDescriptions = vertex_attributes.data(),
|
|
};
|
|
|
|
VkPipelineInputAssemblyStateCreateInfo assembly_info {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
|
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
|
.primitiveRestartEnable = VK_FALSE,
|
|
};
|
|
|
|
VkViewport viewport {
|
|
.x = 0.0f,
|
|
.y = 0.0f,
|
|
.width = float(m_swapchain.extent().width),
|
|
.height = float(m_swapchain.extent().height),
|
|
.minDepth = 0.0f,
|
|
.maxDepth = 1.0f,
|
|
};
|
|
|
|
VkRect2D scissor = {
|
|
.offset = { 0, 0 },
|
|
.extent = m_swapchain.extent(),
|
|
};
|
|
|
|
VkPipelineViewportStateCreateInfo viewport_info {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
|
.viewportCount = 1,
|
|
.pViewports = &viewport,
|
|
.scissorCount = 1,
|
|
.pScissors = &scissor,
|
|
};
|
|
|
|
VkPipelineRasterizationStateCreateInfo rasterization_info {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
|
.depthClampEnable = VK_FALSE,
|
|
.rasterizerDiscardEnable = VK_FALSE,
|
|
.polygonMode = VK_POLYGON_MODE_FILL,
|
|
.cullMode = VK_CULL_MODE_BACK_BIT,
|
|
.frontFace = VK_FRONT_FACE_CLOCKWISE,
|
|
.depthBiasEnable = VK_FALSE,
|
|
.depthBiasConstantFactor = 0.0f,
|
|
.depthBiasClamp = 0.0f,
|
|
.depthBiasSlopeFactor = 0.0f,
|
|
.lineWidth = 1.0f,
|
|
};
|
|
|
|
VkPipelineMultisampleStateCreateInfo multisample_info {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
|
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
|
|
.sampleShadingEnable = VK_FALSE,
|
|
.minSampleShading = 1.0f,
|
|
.pSampleMask = nullptr,
|
|
.alphaToCoverageEnable = VK_FALSE,
|
|
.alphaToOneEnable = VK_FALSE,
|
|
};
|
|
|
|
VkPipelineColorBlendAttachmentState color_blend_attachment {
|
|
.blendEnable = VK_FALSE,
|
|
.srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
|
|
.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
|
|
.colorBlendOp = VK_BLEND_OP_ADD,
|
|
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
|
|
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
|
|
.alphaBlendOp = VK_BLEND_OP_ADD,
|
|
.colorWriteMask =
|
|
VK_COLOR_COMPONENT_R_BIT |
|
|
VK_COLOR_COMPONENT_G_BIT |
|
|
VK_COLOR_COMPONENT_B_BIT |
|
|
VK_COLOR_COMPONENT_A_BIT,
|
|
};
|
|
|
|
VkPipelineColorBlendStateCreateInfo color_blend_info {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
|
.logicOpEnable = VK_FALSE,
|
|
.logicOp = VK_LOGIC_OP_COPY,
|
|
.attachmentCount = 1,
|
|
.pAttachments = &color_blend_attachment,
|
|
.blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f },
|
|
};
|
|
|
|
VkPipelineLayoutCreateInfo layout_info = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
|
.setLayoutCount = 1,
|
|
.pSetLayouts = &m_descriptor_set_layout,
|
|
.pushConstantRangeCount = 0,
|
|
.pPushConstantRanges = nullptr,
|
|
};
|
|
|
|
if(vkCreatePipelineLayout(
|
|
m_context.device(),
|
|
&layout_info,
|
|
nullptr,
|
|
&m_pipeline_layout
|
|
) != VK_SUCCESS)
|
|
throw std::runtime_error("failed to create pipeline layout");
|
|
|
|
VkGraphicsPipelineCreateInfo pipeline_info {
|
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
|
.stageCount = 2,
|
|
.pStages = shader_stage_infos,
|
|
.pVertexInputState = &vertex_info,
|
|
.pInputAssemblyState = &assembly_info,
|
|
.pViewportState = &viewport_info,
|
|
.pRasterizationState = &rasterization_info,
|
|
.pMultisampleState = &multisample_info,
|
|
.pDepthStencilState = nullptr,
|
|
.pColorBlendState = &color_blend_info,
|
|
.pDynamicState = nullptr,
|
|
.layout = m_pipeline_layout,
|
|
.renderPass = m_render_pass,
|
|
.subpass = 0,
|
|
.basePipelineHandle = VK_NULL_HANDLE,
|
|
.basePipelineIndex = -1,
|
|
};
|
|
|
|
if(vkCreateGraphicsPipelines(
|
|
m_context.device(),
|
|
VK_NULL_HANDLE,
|
|
1, &pipeline_info,
|
|
nullptr,
|
|
&m_pipeline
|
|
) != VK_SUCCESS)
|
|
throw std::runtime_error("failed to create graphic pipeline");
|
|
}
|
|
|
|
void VulkanTutorial::create_framebuffers() {
|
|
m_framebuffers.resize(m_swapchain.image_count());
|
|
|
|
for(size_t index = 0; index < m_framebuffers.size(); index += 1) {
|
|
VkImageView view = m_swapchain.image_view(index);
|
|
|
|
VkFramebufferCreateInfo framebuffer_info {
|
|
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
|
.renderPass = m_render_pass,
|
|
.attachmentCount = 1,
|
|
.pAttachments = &view,
|
|
.width = m_swapchain.extent().width,
|
|
.height = m_swapchain.extent().height,
|
|
.layers = 1,
|
|
};
|
|
|
|
if(vkCreateFramebuffer(
|
|
m_context.device(),
|
|
&framebuffer_info,
|
|
nullptr,
|
|
&m_framebuffers[index]
|
|
) != VK_SUCCESS)
|
|
throw std::runtime_error("failed to create framebuffer");
|
|
}
|
|
}
|
|
|
|
void VulkanTutorial::create_command_pool() {
|
|
if(m_command_pool != VK_NULL_HANDLE)
|
|
return;
|
|
|
|
VkCommandPoolCreateInfo pool_info {
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
|
.flags = 0,
|
|
.queueFamilyIndex = m_context.queue_family(GRAPHIC_QUEUE),
|
|
};
|
|
|
|
if(vkCreateCommandPool(
|
|
m_context.device(),
|
|
&pool_info,
|
|
nullptr,
|
|
&m_command_pool
|
|
) != VK_SUCCESS)
|
|
throw std::runtime_error("failed to create command pool");
|
|
}
|
|
|
|
void VulkanTutorial::create_vertex_buffer() {
|
|
if(m_vertex_buffer != VK_NULL_HANDLE)
|
|
return;
|
|
|
|
VkDeviceSize size = sizeof(vertices[0]) * vertices.size();
|
|
std::tie(m_vertex_buffer, m_vertex_buffer_memory) = m_context.create_buffer(
|
|
size, (char*)vertices.data(),
|
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
|
m_context.queue_family(GRAPHIC_QUEUE)
|
|
);
|
|
}
|
|
|
|
void VulkanTutorial::create_index_buffer() {
|
|
if(m_index_buffer != VK_NULL_HANDLE)
|
|
return;
|
|
|
|
VkDeviceSize size = sizeof(indices[0]) * indices.size();
|
|
std::tie(m_index_buffer, m_index_buffer_memory) = m_context.create_buffer(
|
|
size, (char*)indices.data(),
|
|
VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
|
m_context.queue_family(GRAPHIC_QUEUE)
|
|
);
|
|
}
|
|
|
|
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());
|
|
|
|
VkCommandBufferAllocateInfo allocate_info {
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
|
.commandPool = m_command_pool,
|
|
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
|
.commandBufferCount = uint32_t(m_command_buffers.size()),
|
|
};
|
|
|
|
if(vkAllocateCommandBuffers(
|
|
m_context.device(),
|
|
&allocate_info,
|
|
m_command_buffers.data()
|
|
) != VK_SUCCESS)
|
|
throw std::runtime_error("failed to allocate command buffers");
|
|
|
|
for(size_t index = 0; index < m_command_buffers.size(); index += 1) {
|
|
VkCommandBuffer command_buffer = m_command_buffers[index];
|
|
|
|
VkCommandBufferBeginInfo begin_info {
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
|
.flags = 0,
|
|
.pInheritanceInfo = nullptr,
|
|
};
|
|
|
|
logger.debug() << "record command buffer " << index << " (" << command_buffer << ")";
|
|
|
|
if(vkBeginCommandBuffer(
|
|
command_buffer,
|
|
&begin_info
|
|
) != VK_SUCCESS)
|
|
throw std::runtime_error("failed to begin command buffer");
|
|
|
|
VkClearValue clear_color = {
|
|
.color = {
|
|
.float32 = { 0.0f, 0.0f, 0.0f, 1.0f }
|
|
}
|
|
};
|
|
|
|
VkRenderPassBeginInfo pass_info {
|
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
|
.renderPass = m_render_pass,
|
|
.framebuffer = m_framebuffers[index],
|
|
.renderArea = {
|
|
.offset = { 0, 0 },
|
|
.extent = m_swapchain.extent(),
|
|
},
|
|
.clearValueCount = 1,
|
|
.pClearValues = &clear_color,
|
|
};
|
|
|
|
vkCmdBeginRenderPass(
|
|
command_buffer,
|
|
&pass_info,
|
|
VK_SUBPASS_CONTENTS_INLINE
|
|
);
|
|
|
|
vkCmdBindPipeline(
|
|
command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
m_pipeline
|
|
);
|
|
|
|
VkBuffer vertex_buffers[] = {
|
|
m_vertex_buffer,
|
|
};
|
|
VkDeviceSize offsets[] = {
|
|
0,
|
|
};
|
|
vkCmdBindVertexBuffers(
|
|
command_buffer,
|
|
0,
|
|
1,
|
|
vertex_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,
|
|
0,
|
|
VK_INDEX_TYPE_UINT16
|
|
);
|
|
|
|
vkCmdDrawIndexed(
|
|
command_buffer,
|
|
uint32_t(indices.size()),
|
|
1,
|
|
0,
|
|
0,
|
|
0
|
|
);
|
|
|
|
vkCmdEndRenderPass(command_buffer);
|
|
|
|
if(vkEndCommandBuffer(command_buffer) != VK_SUCCESS)
|
|
throw("failed to record command buffer");
|
|
}
|
|
}
|
|
|