summaryrefslogtreecommitdiff
path: root/src/vk
diff options
context:
space:
mode:
Diffstat (limited to 'src/vk')
-rw-r--r--src/vk/graphics_pipeline_2d.cpp226
-rw-r--r--src/vk/graphics_pipeline_2d.hpp18
-rw-r--r--src/vk/graphics_pipeline_2d_layout.cpp29
-rw-r--r--src/vk/graphics_pipeline_2d_layout.hpp12
-rw-r--r--src/vk/graphics_pipeline_3d.cpp281
-rw-r--r--src/vk/graphics_pipeline_3d.hpp17
-rw-r--r--src/vk/graphics_pipeline_3d_layout.cpp69
-rw-r--r--src/vk/graphics_pipeline_3d_layout.hpp25
-rw-r--r--src/vk/renderer.cpp169
-rw-r--r--src/vk/renderer.hpp17
-rw-r--r--src/vk/swapchain.cpp58
-rw-r--r--src/vk/swapchain.hpp6
-rw-r--r--src/vk/uniform_buffer.hpp28
-rw-r--r--src/vk/view.cpp259
-rw-r--r--src/vk/view.hpp55
15 files changed, 765 insertions, 504 deletions
diff --git a/src/vk/graphics_pipeline_2d.cpp b/src/vk/graphics_pipeline_2d.cpp
index 61cfe3f..08bdb6e 100644
--- a/src/vk/graphics_pipeline_2d.cpp
+++ b/src/vk/graphics_pipeline_2d.cpp
@@ -25,123 +25,6 @@ namespace
{
void
-load_projection_uniform_buffer(void *obj)
-{
- auto self = static_cast<VK::GraphicsPipeline2D*>(obj);
-
- try
- {
- self->ub_projection.reserve(cg_core.vk_swapchain->images_count);
- for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++)
- self->ub_projection.emplace_back(
- cg_core.vk_device_with_swapchain, sizeof(VK::UBOProjection));
- }
- catch(const std::exception& e)
- {
- throw CommandError{e.what()};
- }
-}
-
-void
-unload_projection_uniform_buffer(void *obj)
-{
- auto self = static_cast<VK::GraphicsPipeline2D*>(obj);
-
- self->ub_projection.clear();
-}
-
-void
-load_descriptor_pool(void *obj)
-{
- auto self = static_cast<VK::GraphicsPipeline2D*>(obj);
-
- VkDescriptorPoolSize descriptor_pool_size{};
- descriptor_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- descriptor_pool_size.descriptorCount = self->ub_projection.size();
-
- VkDescriptorPoolCreateInfo pool_info{};
- pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
- pool_info.pNext = nullptr;
- pool_info.flags = 0;
- pool_info.maxSets = self->ub_projection.size();
- pool_info.poolSizeCount = 1;
- pool_info.pPoolSizes = &descriptor_pool_size;
-
- if(vkCreateDescriptorPool(
- cg_core.vk_device_with_swapchain->device, &pool_info, nullptr,
- &self->descriptor_pool) != VK_SUCCESS)
- throw CommandError{"Failed to create a Vulkan descriptor pool."};
-}
-
-void
-unload_descriptor_pool(void *obj)
-{
- auto self = static_cast<VK::GraphicsPipeline2D*>(obj);
-
- vkDestroyDescriptorPool(
- cg_core.vk_device_with_swapchain->device, self->descriptor_pool,
- nullptr);
-}
-
-void
-load_projection_descriptor_sets(void *obj)
-{
- auto self = static_cast<VK::GraphicsPipeline2D*>(obj);
-
- std::vector<VkDescriptorSetLayout> layouts(
- self->ub_projection.size(),
- cg_core.vk_graphics_pipeline_2d_layout->descriptor_set_projection);
-
- VkDescriptorSetAllocateInfo alloc_info{};
- alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
- alloc_info.descriptorPool = self->descriptor_pool;
- alloc_info.descriptorSetCount = layouts.size();
- alloc_info.pSetLayouts = layouts.data();
-
- self->projection_descriptor_sets.resize(layouts.size());
- if(vkAllocateDescriptorSets(
- cg_core.vk_device_with_swapchain->device, &alloc_info,
- self->projection_descriptor_sets.data()) != VK_SUCCESS)
- throw CommandError{"Failed to create Vulkan projection descriptor sets."};
-}
-
-void
-load_resources_to_descriptor_sets(void *obj)
-{
- auto self = static_cast<VK::GraphicsPipeline2D*>(obj);
-
- for(auto i{0}; i < self->ub_projection.size(); i++)
- {
- VkDescriptorBufferInfo projection_info{};
- projection_info.buffer = self->ub_projection[i].buffer;
- projection_info.offset = 0;
- projection_info.range = sizeof(VK::UBOProjection);
-
- std::array<VkWriteDescriptorSet, 1> write_descriptors{};
- write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- write_descriptors[0].dstSet = self->projection_descriptor_sets[i];
- write_descriptors[0].dstBinding = 0;
- write_descriptors[0].dstArrayElement = 0;
- write_descriptors[0].descriptorCount = 1;
- write_descriptors[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- write_descriptors[0].pBufferInfo = &projection_info;
- write_descriptors[0].pImageInfo = nullptr;
- write_descriptors[0].pTexelBufferView = nullptr;
-
- vkUpdateDescriptorSets(
- cg_core.vk_device_with_swapchain->device, write_descriptors.size(),
- write_descriptors.data(), 0, nullptr);
-
- VK::UBOProjection ubo_projection;
- ubo_projection.proj = glm::ortho(
- 0.0f, static_cast<float>(cg_core.game_width),
- 0.0f, static_cast<float>(cg_core.game_height),
- 0.0f, 100.0f);
- self->ub_projection[i].copy_data(&ubo_projection);
- }
-}
-
-void
load_framebuffer(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline2D*>(obj);
@@ -245,10 +128,10 @@ load_pipeline(void *obj)
input_assembly.primitiveRestartEnable = VK_FALSE;
VkViewport viewport = {};
- viewport.x = 0.0f;
- viewport.y = 0.0f;
- viewport.width = static_cast<float>(cg_core.screen_width);
- viewport.height = static_cast<float>(cg_core.screen_height);
+ viewport.x = 0;
+ viewport.y = 0;
+ viewport.width = cg_core.screen_width;
+ viewport.height = cg_core.screen_height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
@@ -368,11 +251,6 @@ unload_pipeline(void *obj)
}
const CommandChain loader{
- {&load_projection_uniform_buffer, &unload_projection_uniform_buffer},
- {&load_descriptor_pool, &unload_descriptor_pool},
- // By destroying the pool the sets are also destroyed.
- {&load_projection_descriptor_sets, nullptr},
- {&load_resources_to_descriptor_sets, nullptr},
{&load_framebuffer, &unload_framebuffer},
{&load_pipeline, &unload_pipeline}
};
@@ -382,8 +260,7 @@ const CommandChain loader{
namespace VK
{
-GraphicsPipeline2D::GraphicsPipeline2D():
- sprites_to_draw{cg_core.vk_swapchain->images_count}
+GraphicsPipeline2D::GraphicsPipeline2D()
{
loader.execute(this);
}
@@ -395,74 +272,61 @@ GraphicsPipeline2D::~GraphicsPipeline2D()
void
GraphicsPipeline2D::draw(
- const VkCommandBuffer draw_command_buffer, const size_t current_frame,
- const size_t next_frame, const uint32_t image_index)
+ std::shared_ptr<View> view, const VkCommandBuffer draw_command_buffer,
+ const size_t current_frame, const size_t next_frame,
+ const uint32_t image_index)
{
- // Load command
+ // Set viewport
{
- VkRenderPassBeginInfo render_pass_begin{};
- render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
- render_pass_begin.pNext = nullptr;
- render_pass_begin.renderPass =
- cg_core.vk_graphics_pipeline_2d_layout->render_pass;
- render_pass_begin.framebuffer = this->swapchain_framebuffers[image_index];
- render_pass_begin.renderArea.offset = {0, 0};
- render_pass_begin.renderArea.extent = {
- cg_core.screen_width, cg_core.screen_height};
- render_pass_begin.clearValueCount = 0;
- render_pass_begin.pClearValues = nullptr;
-
- vkCmdBeginRenderPass(
- draw_command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE);
-
VkViewport vk_viewport{};
- vk_viewport.width = static_cast<float>(cg_core.screen_width);
- vk_viewport.height = static_cast<float>(cg_core.screen_height);
+ vk_viewport.x = view->region.x;
+ vk_viewport.y = view->region.y;
+ vk_viewport.width = view->region.z;
+ vk_viewport.height = view->region.w;
vk_viewport.minDepth = 0.0f;
vk_viewport.maxDepth = 1.0f;
vkCmdSetViewport(draw_command_buffer, 0, 1, &vk_viewport);
VkRect2D vk_scissor{};
- vk_scissor.extent.width = cg_core.screen_width;
- vk_scissor.extent.height = cg_core.screen_height;
- vk_scissor.offset.x = 0;
- vk_scissor.offset.y = 0;
+ vk_scissor.offset.x = static_cast<int32_t>(view->region.x);
+ vk_scissor.offset.y = static_cast<int32_t>(view->region.y);
+ vk_scissor.extent.width = static_cast<uint32_t>(view->region.z);
+ vk_scissor.extent.height = static_cast<uint32_t>(view->region.w);
vkCmdSetScissor(draw_command_buffer, 0, 1, &vk_scissor);
+ }
- // Draw sprites
- for(auto& [sprite, positions]: this->sprites_to_draw[current_frame])
+ // Draw sprites
+ for(auto& [sprite, positions]: view->sprites_to_draw[current_frame])
+ {
+ // Commands
{
- // Commands
- {
- std::array<VkDescriptorSet, 2> vk_descriptor_sets{
- this->projection_descriptor_sets[image_index],
- sprite->descriptor_sets[image_index]};
- VkDeviceSize offsets[]{0};
-
- vkCmdBindDescriptorSets(
- draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
- cg_core.vk_graphics_pipeline_2d_layout->pipeline, 0,
- vk_descriptor_sets.size(), vk_descriptor_sets.data(), 0, nullptr);
- vkCmdBindPipeline(
- draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
- this->graphic_pipeline);
- vkCmdBindVertexBuffers(
- draw_command_buffer, 0, 1, &sprite->vertex_buffer->buffer, offsets);
- vkCmdDraw(
- draw_command_buffer, Sprite::vertex_count, positions.size(), 0, 0);
- }
-
- VK::UBOSpritePositions ubo_sprite_positions;
- for(auto i{0}; i < positions.size(); i++)
- ubo_sprite_positions.positions[i] = positions[i];
- sprite->ub_sprite_positions[image_index].copy_data(
- &ubo_sprite_positions);
+ std::array<VkDescriptorSet, 2> vk_descriptor_sets{
+ view->descriptor_sets_2d[image_index],
+ sprite->descriptor_sets[image_index]};
+ VkDeviceSize offsets[]{0};
+
+ vkCmdBindDescriptorSets(
+ draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+ cg_core.vk_graphics_pipeline_2d_layout->pipeline, 0,
+ vk_descriptor_sets.size(), vk_descriptor_sets.data(), 0, nullptr);
+ vkCmdBindPipeline(
+ draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+ this->graphic_pipeline);
+ vkCmdBindVertexBuffers(
+ draw_command_buffer, 0, 1, &sprite->vertex_buffer->buffer, offsets);
+ vkCmdDraw(
+ draw_command_buffer, Sprite::vertex_count, positions.size(), 0, 0);
}
+
+ VK::UBOSpritePositions ubo_sprite_positions;
+ for(auto i{0}; i < positions.size(); i++)
+ ubo_sprite_positions.positions[i] = positions[i];
+ sprite->ub_sprite_positions[image_index].copy_data(
+ &ubo_sprite_positions);
}
- vkCmdEndRenderPass(draw_command_buffer);
// Prepare for the next frame.
- this->sprites_to_draw[next_frame].clear();
+ view->sprites_to_draw[next_frame].clear();
}
}
diff --git a/src/vk/graphics_pipeline_2d.hpp b/src/vk/graphics_pipeline_2d.hpp
index 193c06d..dd4bb29 100644
--- a/src/vk/graphics_pipeline_2d.hpp
+++ b/src/vk/graphics_pipeline_2d.hpp
@@ -17,36 +17,30 @@
#ifndef CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_H
#define CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_H 1
+#include <memory>
+#include <unordered_map>
#include <vector>
#include "core.hpp"
#include "sprite.hpp"
+#include "view.hpp"
namespace VK
{
struct GraphicsPipeline2D
{
- // FIXME: if this vector get resized, it will cause a segmentation fault!
- std::vector<UniformBuffer> ub_projection;
-
- VkDescriptorPool descriptor_pool;
- std::vector<VkDescriptorSet> projection_descriptor_sets;
-
VkRenderPass render_pass;
std::vector<VkFramebuffer> swapchain_framebuffers;
VkPipeline graphic_pipeline;
- std::vector<
- std::unordered_map<std::shared_ptr<Sprite>, std::vector<glm::vec4>>>
- sprites_to_draw;
-
GraphicsPipeline2D();
~GraphicsPipeline2D();
void
- draw(const VkCommandBuffer draw_command_buffer, const size_t current_frame,
- const size_t next_frame, const uint32_t image_index);
+ draw(std::shared_ptr<View> view, const VkCommandBuffer draw_command_buffer,
+ const size_t current_frame, const size_t next_frame,
+ const uint32_t image_index);
};
}
diff --git a/src/vk/graphics_pipeline_2d_layout.cpp b/src/vk/graphics_pipeline_2d_layout.cpp
index f8822b9..6840f2c 100644
--- a/src/vk/graphics_pipeline_2d_layout.cpp
+++ b/src/vk/graphics_pipeline_2d_layout.cpp
@@ -24,7 +24,7 @@ namespace
{
void
-load_descriptor_set_layout_projection(void *obj)
+load_descriptor_set_view(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline2DLayout*>(obj);
@@ -45,23 +45,23 @@ load_descriptor_set_layout_projection(void *obj)
if(vkCreateDescriptorSetLayout(
cg_core.vk_device_with_swapchain->device, &layout_info, nullptr,
- &self->descriptor_set_projection) != VK_SUCCESS)
+ &self->descriptor_set_view) != VK_SUCCESS)
throw CommandError{
"Failed to create Vulkan descriptor set layout for projection."};
}
void
-unload_descriptor_set_layout_projection(void *obj)
+unload_descriptor_set_view(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline2DLayout*>(obj);
vkDestroyDescriptorSetLayout(
- cg_core.vk_device_with_swapchain->device, self->descriptor_set_projection,
+ cg_core.vk_device_with_swapchain->device, self->descriptor_set_view,
nullptr);
}
void
-load_descriptor_set_layout_sprite(void *obj)
+load_descriptor_set_sprite(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline2DLayout*>(obj);
@@ -95,22 +95,22 @@ load_descriptor_set_layout_sprite(void *obj)
}
void
-unload_descriptor_set_layout_sprite(void *obj)
+unload_descriptor_set_sprite(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline2DLayout*>(obj);
vkDestroyDescriptorSetLayout(
- cg_core.vk_device_with_swapchain->device,
- self->descriptor_set_sprite, nullptr);
+ cg_core.vk_device_with_swapchain->device, self->descriptor_set_sprite,
+ nullptr);
}
void
-load_pipeline_layout(void *obj)
+load_pipeline(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline2DLayout*>(obj);
std::array<VkDescriptorSetLayout, 2> set_layouts{
- self->descriptor_set_projection, self->descriptor_set_sprite
+ self->descriptor_set_view, self->descriptor_set_sprite
};
VkPipelineLayoutCreateInfo pipeline_layout_info{};
@@ -127,7 +127,7 @@ load_pipeline_layout(void *obj)
}
void
-unload_pipeline_layout(void *obj)
+unload_pipeline(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline2DLayout*>(obj);
@@ -207,10 +207,9 @@ unload_render_pass(void *obj)
}
const CommandChain loader{
- {&load_descriptor_set_layout_projection,
- &unload_descriptor_set_layout_projection},
- {&load_descriptor_set_layout_sprite, &unload_descriptor_set_layout_sprite},
- {&load_pipeline_layout, &unload_pipeline_layout},
+ {&load_descriptor_set_view, &unload_descriptor_set_view},
+ {&load_descriptor_set_sprite, &unload_descriptor_set_sprite},
+ {&load_pipeline, &unload_pipeline},
{&load_render_pass, &unload_render_pass}
};
diff --git a/src/vk/graphics_pipeline_2d_layout.hpp b/src/vk/graphics_pipeline_2d_layout.hpp
index 520bbc1..1e0a794 100644
--- a/src/vk/graphics_pipeline_2d_layout.hpp
+++ b/src/vk/graphics_pipeline_2d_layout.hpp
@@ -22,9 +22,19 @@
namespace VK
{
+struct UBOView2D
+{
+ glm::mat4 proj;
+};
+
+struct UBOSpritePositions
+{
+ glm::vec4 positions[128];
+};
+
struct GraphicsPipeline2DLayout
{
- VkDescriptorSetLayout descriptor_set_projection;
+ VkDescriptorSetLayout descriptor_set_view;
VkDescriptorSetLayout descriptor_set_sprite;
VkPipelineLayout pipeline;
VkRenderPass render_pass;
diff --git a/src/vk/graphics_pipeline_3d.cpp b/src/vk/graphics_pipeline_3d.cpp
index 31e9365..02fbfd9 100644
--- a/src/vk/graphics_pipeline_3d.cpp
+++ b/src/vk/graphics_pipeline_3d.cpp
@@ -28,16 +28,16 @@ namespace
{
void
-load_view_projection_uniform_buffer(void *obj)
+load_world_vert_uniform_buffer(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3D*>(obj);
try
{
- self->ub_view_projection.reserve(cg_core.vk_swapchain->images_count);
+ self->ub_world_vert.reserve(cg_core.vk_swapchain->images_count);
for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++)
- self->ub_view_projection.emplace_back(
- cg_core.vk_device_with_swapchain, sizeof(VK::UBOViewProjection));
+ self->ub_world_vert.emplace_back(
+ cg_core.vk_device_with_swapchain, sizeof(VK::UBOWorld3D_Vert));
}
catch(const std::exception& e)
{
@@ -46,24 +46,24 @@ load_view_projection_uniform_buffer(void *obj)
}
void
-unload_view_projection_uniform_buffer(void *obj)
+unload_world_vert_uniform_buffer(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3D*>(obj);
- self->ub_view_projection.clear();
+ self->ub_world_vert.clear();
}
void
-load_directional_light_uniform_buffer(void *obj)
+load_world_frag_uniform_buffer(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3D*>(obj);
try
{
- self->ub_view_projection.reserve(cg_core.vk_swapchain->images_count);
+ self->ub_world_frag.reserve(cg_core.vk_swapchain->images_count);
for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++)
- self->ub_directional_light.emplace_back(
- cg_core.vk_device_with_swapchain, sizeof(VK::UBODirectionalLight));
+ self->ub_world_frag.emplace_back(
+ cg_core.vk_device_with_swapchain, sizeof(VK::UBOWorld3D_Frag));
}
catch(const std::exception& e)
{
@@ -72,11 +72,11 @@ load_directional_light_uniform_buffer(void *obj)
}
void
-unload_directional_light_uniform_buffer(void *obj)
+unload_world_frag_uniform_buffer(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3D*>(obj);
- self->ub_directional_light.clear();
+ self->ub_world_frag.clear();
}
void
@@ -84,17 +84,18 @@ load_descriptor_pool(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3D*>(obj);
+ uint32_t uniform_buffers_count =
+ self->ub_world_vert.size() + self->ub_world_vert.size();
+
VkDescriptorPoolSize descriptor_pool_size{};
descriptor_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- descriptor_pool_size.descriptorCount =
- self->ub_view_projection.size() + self->ub_directional_light.size();
+ descriptor_pool_size.descriptorCount = uniform_buffers_count;
VkDescriptorPoolCreateInfo pool_info{};
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
pool_info.pNext = nullptr;
pool_info.flags = 0;
- pool_info.maxSets = self->ub_view_projection.size() +
- self->ub_directional_light.size();
+ pool_info.maxSets = uniform_buffers_count;
pool_info.poolSizeCount = 1;
pool_info.pPoolSizes = &descriptor_pool_size;
@@ -115,26 +116,25 @@ unload_descriptor_pool(void *obj)
}
void
-load_world_view_descriptor_sets(void *obj)
+load_descriptor_sets_world(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3D*>(obj);
std::vector<VkDescriptorSetLayout> layouts(
cg_core.vk_swapchain->images_count,
- cg_core.vk_graphics_pipeline_3d_layout->descriptor_set_world_view);
+ cg_core.vk_graphics_pipeline_3d_layout->descriptor_set_world);
VkDescriptorSetAllocateInfo alloc_info{};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = self->descriptor_pool;
- alloc_info.descriptorSetCount = self->ub_view_projection.size();
+ alloc_info.descriptorSetCount = layouts.size();
alloc_info.pSetLayouts = layouts.data();
- self->world_view_descriptor_sets.resize(
- cg_core.vk_swapchain->images_count);
+ self->descriptor_sets_world.resize(layouts.size());
if(vkAllocateDescriptorSets(
cg_core.vk_device_with_swapchain->device, &alloc_info,
- self->world_view_descriptor_sets.data()) != VK_SUCCESS)
- throw CommandError{"Failed to create Vulkan world view descriptor set."};
+ self->descriptor_sets_world.data()) != VK_SUCCESS)
+ throw CommandError{"Failed to create Vulkan world descriptor set."};
}
void
@@ -142,36 +142,36 @@ load_resources_to_descriptor_sets(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3D*>(obj);
- for(auto i{0}; i < self->ub_view_projection.size(); i++)
+ for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++)
{
- VkDescriptorBufferInfo view_projection_info{};
- view_projection_info.buffer = self->ub_view_projection[i].buffer;
- view_projection_info.offset = 0;
- view_projection_info.range = sizeof(VK::UBOViewProjection);
+ VkDescriptorBufferInfo world_vert_info{};
+ world_vert_info.buffer = self->ub_world_vert[i].buffer;
+ world_vert_info.offset = 0;
+ world_vert_info.range = sizeof(VK::UBOWorld3D_Vert);
- VkDescriptorBufferInfo directional_light_info{};
- directional_light_info.buffer = self->ub_directional_light[i].buffer;
- directional_light_info.offset = 0;
- directional_light_info.range = sizeof(VK::UBODirectionalLight);
+ VkDescriptorBufferInfo world_frag_info{};
+ world_frag_info.buffer = self->ub_world_frag[i].buffer;
+ world_frag_info.offset = 0;
+ world_frag_info.range = sizeof(VK::UBOWorld3D_Frag);
std::array<VkWriteDescriptorSet, 2> write_descriptors{};
write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- write_descriptors[0].dstSet = self->world_view_descriptor_sets[i];
+ write_descriptors[0].dstSet = self->descriptor_sets_world[i];
write_descriptors[0].dstBinding = 0;
write_descriptors[0].dstArrayElement = 0;
write_descriptors[0].descriptorCount = 1;
write_descriptors[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- write_descriptors[0].pBufferInfo = &view_projection_info;
+ write_descriptors[0].pBufferInfo = &world_vert_info;
write_descriptors[0].pImageInfo = nullptr;
write_descriptors[0].pTexelBufferView = nullptr;
write_descriptors[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- write_descriptors[1].dstSet = self->world_view_descriptor_sets[i];
+ write_descriptors[1].dstSet = self->descriptor_sets_world[i];
write_descriptors[1].dstBinding = 1;
write_descriptors[1].dstArrayElement = 0;
write_descriptors[1].descriptorCount = 1;
write_descriptors[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- write_descriptors[1].pBufferInfo = &directional_light_info;
+ write_descriptors[1].pBufferInfo = &world_frag_info;
write_descriptors[1].pImageInfo = nullptr;
write_descriptors[1].pTexelBufferView = nullptr;
@@ -369,10 +369,10 @@ load_pipeline(void *obj)
input_assembly.primitiveRestartEnable = VK_FALSE;
VkViewport viewport = {};
- viewport.x = 0.0f;
- viewport.y = 0.0f;
- viewport.width = static_cast<float>(cg_core.screen_width);
- viewport.height = static_cast<float>(cg_core.screen_height);
+ viewport.x = 0;
+ viewport.y = 0;
+ viewport.width = cg_core.screen_width;
+ viewport.height = cg_core.screen_height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
@@ -505,13 +505,11 @@ unload_pipeline(void *obj)
}
const CommandChain loader{
- {&load_view_projection_uniform_buffer,
- &unload_view_projection_uniform_buffer},
- {&load_directional_light_uniform_buffer,
- &unload_directional_light_uniform_buffer},
+ {&load_world_vert_uniform_buffer, &unload_world_vert_uniform_buffer},
+ {&load_world_frag_uniform_buffer, &unload_world_frag_uniform_buffer},
{&load_descriptor_pool, &unload_descriptor_pool},
// By destroying the pool the sets are also destroyed.
- {&load_world_view_descriptor_sets, nullptr},
+ {&load_descriptor_sets_world, nullptr},
{&load_resources_to_descriptor_sets, nullptr},
{&load_depth_image, &unload_depth_image},
{&load_depth_image_view, &unload_depth_image_view},
@@ -524,10 +522,7 @@ const CommandChain loader{
namespace VK
{
-GraphicsPipeline3D::GraphicsPipeline3D():
- camera_position{std::make_shared<glm::vec3>(0.0f, 0.0f, 0.0f)},
- camera_rotation{std::make_shared<glm::vec3>(0.0f, 0.0f, 0.0f)},
- models_to_draw{cg_core.vk_swapchain->images_count}
+GraphicsPipeline3D::GraphicsPipeline3D()
{
loader.execute(this);
}
@@ -539,138 +534,116 @@ GraphicsPipeline3D::~GraphicsPipeline3D()
void
GraphicsPipeline3D::draw(
- const VkCommandBuffer draw_command_buffer, const size_t current_frame,
- const size_t next_frame, const uint32_t image_index)
+ std::shared_ptr<View> view, const VkCommandBuffer draw_command_buffer,
+ const size_t current_frame, const uint32_t image_index)
{
- // Load command.
+ // Set viewport
{
- // Dark gray blue.
- std::array<VkClearValue, 2> clear_values{};
- clear_values[0].color = {0.12f, 0.12f, 0.18f, 1.0f};
- clear_values[1].depthStencil = {1.0f, 0};
-
- VkRenderPassBeginInfo render_pass_begin{};
- render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
- render_pass_begin.pNext = nullptr;
- render_pass_begin.renderPass =
- cg_core.vk_graphics_pipeline_3d_layout->render_pass;
- render_pass_begin.framebuffer = this->swapchain_framebuffers[image_index];
- render_pass_begin.renderArea.offset = {0, 0};
- render_pass_begin.renderArea.extent = {
- cg_core.screen_width, cg_core.screen_height};
- render_pass_begin.clearValueCount = clear_values.size();
- render_pass_begin.pClearValues = clear_values.data();
-
- vkCmdBeginRenderPass(
- draw_command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE);
-
VkViewport vk_viewport{};
- vk_viewport.width = static_cast<float>(cg_core.screen_width);
- vk_viewport.height = static_cast<float>(cg_core.screen_height);
+ vk_viewport.x = view->region.x;
+ vk_viewport.y = view->region.y;
+ vk_viewport.width = view->region.z;
+ vk_viewport.height = view->region.w;
vk_viewport.minDepth = 0.0f;
vk_viewport.maxDepth = 1.0f;
vkCmdSetViewport(draw_command_buffer, 0, 1, &vk_viewport);
VkRect2D vk_scissor{};
- vk_scissor.extent.width = cg_core.screen_width;
- vk_scissor.extent.height = cg_core.screen_height;
- vk_scissor.offset.x = 0;
- vk_scissor.offset.y = 0;
+ vk_scissor.offset.x = static_cast<int32_t>(view->region.x);
+ vk_scissor.offset.y = static_cast<int32_t>(view->region.y);
+ vk_scissor.extent.width = static_cast<uint32_t>(view->region.z);
+ vk_scissor.extent.height = static_cast<uint32_t>(view->region.w);
vkCmdSetScissor(draw_command_buffer, 0, 1, &vk_scissor);
+ }
- // Draw models
- for(auto& [model, instances] : this->models_to_draw[current_frame])
+ // Draw models
+ for(auto& [model, instances]:
+ cg_core.vk_renderer->models_to_draw[current_frame])
+ {
+ // Commands
{
- // Commands
- {
- std::array<VkDescriptorSet, 2> vk_descriptor_sets{
- this->world_view_descriptor_sets[image_index],
- model->descriptor_sets[image_index]};
- VkBuffer vertex_buffers[]{model->vertex_buffer->buffer};
- VkDeviceSize offsets[]{0};
-
- vkCmdBindDescriptorSets(
- draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
- cg_core.vk_graphics_pipeline_3d_layout->pipeline, 0,
- vk_descriptor_sets.size(), vk_descriptor_sets.data(), 0, nullptr);
- vkCmdBindPipeline(
- draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
- this->graphic_pipeline);
- vkCmdBindVertexBuffers(
- draw_command_buffer, 0, 1, vertex_buffers, offsets);
- vkCmdBindIndexBuffer(
- draw_command_buffer, model->index_buffer->buffer, 0,
- VK_INDEX_TYPE_UINT32);
- vkCmdDrawIndexed(
- draw_command_buffer, model->index_count, instances.size(), 0, 0, 0);
- }
-
- VK::UBOModelInstance ubo_model_instance;
-
- for(int i{0}; i < instances.size(); i++)
- {
- // Object matrix.
- glm::mat4 instance_matrix{1.0f};
- instance_matrix = glm::translate(
- instance_matrix, instances[i].position);
- instance_matrix = glm::rotate(
- instance_matrix, instances[i].rotation.x, glm::vec3{1.0, 0.0, 0.0});
- instance_matrix = glm::rotate(
- instance_matrix, instances[i].rotation.y, glm::vec3{0.0, 1.0, 0.0});
- instance_matrix = glm::rotate(
- instance_matrix, instances[i].rotation.z, glm::vec3{0.0, 0.0, 1.0});
-
- ubo_model_instance.instances[i] = instance_matrix;
- }
-
- model->ub_model_instance[image_index].copy_data(&ubo_model_instance);
+ std::array<VkDescriptorSet, 3> vk_descriptor_sets{
+ this->descriptor_sets_world[image_index],
+ view->descriptor_sets_3d[image_index],
+ model->descriptor_sets[image_index]};
+ VkBuffer vertex_buffers[]{model->vertex_buffer->buffer};
+ VkDeviceSize offsets[]{0};
+
+ vkCmdBindDescriptorSets(
+ draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+ cg_core.vk_graphics_pipeline_3d_layout->pipeline, 0,
+ vk_descriptor_sets.size(), vk_descriptor_sets.data(), 0, nullptr);
+ vkCmdBindPipeline(
+ draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+ this->graphic_pipeline);
+ vkCmdBindVertexBuffers(
+ draw_command_buffer, 0, 1, vertex_buffers, offsets);
+ vkCmdBindIndexBuffer(
+ draw_command_buffer, model->index_buffer->buffer, 0,
+ VK_INDEX_TYPE_UINT32);
+ vkCmdDrawIndexed(
+ draw_command_buffer, model->index_count, instances.size(), 0, 0, 0);
}
- vkCmdEndRenderPass(draw_command_buffer);
+ VK::UBOModelInstance ubo_model_instance;
+
+ for(int i{0}; i < instances.size(); i++)
+ {
+ // Object matrix.
+ glm::mat4 instance_matrix{1.0f};
+ instance_matrix = glm::translate(
+ instance_matrix, instances[i].position);
+ instance_matrix = glm::rotate(
+ instance_matrix, instances[i].rotation.x, glm::vec3{1.0, 0.0, 0.0});
+ instance_matrix = glm::rotate(
+ instance_matrix, instances[i].rotation.y, glm::vec3{0.0, 1.0, 0.0});
+ instance_matrix = glm::rotate(
+ instance_matrix, instances[i].rotation.z, glm::vec3{0.0, 0.0, 1.0});
+
+ ubo_model_instance.instances[i] = instance_matrix;
+ }
+
+ model->ub_model_instance[image_index].copy_data(&ubo_model_instance);
}
- // Update view projection uniform buffers
+ // Update view uniform buffers
{
- VK::UBOViewProjection ubo_view_projection{};
+ VK::UBOView3D ubo_view_3d{};
// View matrix.
- ubo_view_projection.view = glm::mat4{1.0f};
- ubo_view_projection.view = glm::translate(
- ubo_view_projection.view, *this->camera_position);
- ubo_view_projection.view = glm::rotate(
- ubo_view_projection.view, this->camera_rotation->y,
- glm::vec3{0.0, 1.0, 0.0});
- ubo_view_projection.view = glm::rotate(
- ubo_view_projection.view, this->camera_rotation->x,
- glm::vec3{1.0, 0.0, 0.0});
- ubo_view_projection.view = glm::rotate(
- ubo_view_projection.view, this->camera_rotation->z,
- glm::vec3{0.0, 0.0, 1.0});
- ubo_view_projection.view = glm::inverse(ubo_view_projection.view);
+ ubo_view_3d.view = glm::mat4{1.0f};
+ ubo_view_3d.view = glm::translate(
+ ubo_view_3d.view, *view->camera_position);
+ ubo_view_3d.view = glm::rotate(
+ ubo_view_3d.view, view->camera_rotation->y, glm::vec3{0.0, 1.0, 0.0});
+ ubo_view_3d.view = glm::rotate(
+ ubo_view_3d.view, view->camera_rotation->x, glm::vec3{1.0, 0.0, 0.0});
+ ubo_view_3d.view = glm::rotate(
+ ubo_view_3d.view, view->camera_rotation->z, glm::vec3{0.0, 0.0, 1.0});
+ ubo_view_3d.view = glm::inverse(ubo_view_3d.view);
// Projection matrix.
- ubo_view_projection.proj = glm::perspective(
+ ubo_view_3d.proj = glm::perspective(
glm::radians(45.0f),
- cg_core.screen_width / static_cast<float>(cg_core.screen_height),
+ view->region.z / view->region.w,
0.1f, 100.0f);
- ubo_view_projection.proj[1][1] *= -1;
+ ubo_view_3d.proj[1][1] *= -1;
- ubo_view_projection.ambient_color = glm::vec4{0.25, 0.25, 0.25, 1.0};
-
- this->ub_view_projection[image_index].copy_data(&ubo_view_projection);
+ view->ub_3d[image_index].copy_data(&ubo_view_3d);
}
- // Update directional light uniform buffers
+ // Update world uniform buffer
{
- UBODirectionalLight ubo_directional_light{};
- ubo_directional_light.direction = glm::vec3{-0.57735, -0.57735, -0.57735};
- ubo_directional_light.color = glm::vec4{0.8, 0.8, 0.8, 1.0};
-
- this->ub_directional_light[image_index].copy_data(&ubo_directional_light);
+ UBOWorld3D_Vert ubo_world_3d_vert{};
+ ubo_world_3d_vert.ambient_light_color = glm::vec4{0.25, 0.25, 0.25, 1.0};
+ this->ub_world_vert[image_index].copy_data(&ubo_world_3d_vert);
+
+ UBOWorld3D_Frag ubo_world_3d_frag{};
+ ubo_world_3d_frag.directional_light_direction =
+ glm::vec3{-0.57735, -0.57735, -0.57735};
+ ubo_world_3d_frag.directional_light_color = glm::vec4{0.8, 0.8, 0.8, 1.0};
+ this->ub_world_frag[image_index].copy_data(&ubo_world_3d_frag);
}
-
- // Prepare for the next frame.
- this->models_to_draw[next_frame].clear();
}
}
diff --git a/src/vk/graphics_pipeline_3d.hpp b/src/vk/graphics_pipeline_3d.hpp
index 97ca63c..a7cf117 100644
--- a/src/vk/graphics_pipeline_3d.hpp
+++ b/src/vk/graphics_pipeline_3d.hpp
@@ -26,6 +26,7 @@
#include "model.hpp"
#include "model_instance.hpp"
#include "uniform_buffer.hpp"
+#include "view.hpp"
namespace VK
{
@@ -38,27 +39,21 @@ struct GraphicsPipeline3D
VkImageView depth_image_view;
// FIXME: if this vector get resized, it will cause a segmentation fault!
- std::vector<UniformBuffer> ub_view_projection;
- std::vector<UniformBuffer> ub_directional_light;
+ std::vector<UniformBuffer> ub_world_vert;
+ std::vector<UniformBuffer> ub_world_frag;
VkDescriptorPool descriptor_pool;
- std::vector<VkDescriptorSet> world_view_descriptor_sets;
+ std::vector<VkDescriptorSet> descriptor_sets_world;
std::vector<VkFramebuffer> swapchain_framebuffers;
VkPipeline graphic_pipeline;
- std::shared_ptr<glm::vec3> camera_position;
- std::shared_ptr<glm::vec3> camera_rotation;
- std::vector<std::unordered_map<
- std::shared_ptr<Model>, std::vector<ModelInstance>>>
- models_to_draw;
-
GraphicsPipeline3D();
~GraphicsPipeline3D();
void
- draw(const VkCommandBuffer draw_command_buffer, const size_t current_frame,
- const size_t next_frame, const uint32_t image_index);
+ draw(std::shared_ptr<View> view, const VkCommandBuffer draw_command_buffer,
+ const size_t current_frame, const uint32_t image_index);
};
}
diff --git a/src/vk/graphics_pipeline_3d_layout.cpp b/src/vk/graphics_pipeline_3d_layout.cpp
index 62c894c..4374ab9 100644
--- a/src/vk/graphics_pipeline_3d_layout.cpp
+++ b/src/vk/graphics_pipeline_3d_layout.cpp
@@ -22,8 +22,9 @@
namespace
{
+
void
-load_descriptor_set_layout_world_view(void *obj)
+load_descriptor_set_world(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3DLayout*>(obj);
@@ -49,23 +50,59 @@ load_descriptor_set_layout_world_view(void *obj)
if(vkCreateDescriptorSetLayout(
cg_core.vk_device_with_swapchain->device, &layout_info, nullptr,
- &self->descriptor_set_world_view) != VK_SUCCESS)
+ &self->descriptor_set_world) != VK_SUCCESS)
throw CommandError{
"Failed to create Vulkan descriptor set layout for world view."};
}
void
-unload_descriptor_set_layout_world_view(void *obj)
+unload_descriptor_set_world(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3DLayout*>(obj);
vkDestroyDescriptorSetLayout(
- cg_core.vk_device_with_swapchain->device,
- self->descriptor_set_world_view, nullptr);
+ cg_core.vk_device_with_swapchain->device, self->descriptor_set_world,
+ nullptr);
+}
+
+void
+load_descriptor_set_view(void *obj)
+{
+ auto self = static_cast<VK::GraphicsPipeline3DLayout*>(obj);
+
+ std::array<VkDescriptorSetLayoutBinding, 1> set_layouts{};
+ set_layouts[0].binding = 0;
+ set_layouts[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ set_layouts[0].descriptorCount = 1;
+ set_layouts[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
+ set_layouts[0].pImmutableSamplers = nullptr;
+
+ VkDescriptorSetLayoutCreateInfo layout_info{};
+ layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ layout_info.pNext = nullptr;
+ layout_info.flags = 0;
+ layout_info.bindingCount = set_layouts.size();
+ layout_info.pBindings = set_layouts.data();
+
+ if(vkCreateDescriptorSetLayout(
+ cg_core.vk_device_with_swapchain->device, &layout_info, nullptr,
+ &self->descriptor_set_view) != VK_SUCCESS)
+ throw CommandError{
+ "Failed to create Vulkan descriptor set layout for world view."};
+}
+
+void
+unload_descriptor_set_view(void *obj)
+{
+ auto self = static_cast<VK::GraphicsPipeline3DLayout*>(obj);
+
+ vkDestroyDescriptorSetLayout(
+ cg_core.vk_device_with_swapchain->device, self->descriptor_set_view,
+ nullptr);
}
void
-load_descriptor_set_layout_model_instance(void *obj)
+load_descriptor_set_model_instance(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3DLayout*>(obj);
@@ -99,7 +136,7 @@ load_descriptor_set_layout_model_instance(void *obj)
}
void
-unload_descriptor_set_layout_model_instance(void *obj)
+unload_descriptor_set_model_instance(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3DLayout*>(obj);
@@ -109,12 +146,13 @@ unload_descriptor_set_layout_model_instance(void *obj)
}
void
-load_pipeline_layout(void *obj)
+load_pipeline(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3DLayout*>(obj);
- std::array<VkDescriptorSetLayout, 2> set_layouts{
- self->descriptor_set_world_view,
+ std::array<VkDescriptorSetLayout, 3> set_layouts{
+ self->descriptor_set_world,
+ self->descriptor_set_view,
self->descriptor_set_model_instance};
VkPipelineLayoutCreateInfo pipeline_layout_info{};
@@ -131,7 +169,7 @@ load_pipeline_layout(void *obj)
}
void
-unload_pipeline_layout(void *obj)
+unload_pipeline(void *obj)
{
auto self = static_cast<VK::GraphicsPipeline3DLayout*>(obj);
@@ -226,11 +264,10 @@ unload_render_pass(void *obj)
}
const CommandChain loader{
- {&load_descriptor_set_layout_world_view,
- &unload_descriptor_set_layout_world_view},
- {&load_descriptor_set_layout_model_instance,
- &unload_descriptor_set_layout_model_instance},
- {&load_pipeline_layout, &unload_pipeline_layout},
+ {&load_descriptor_set_world, &unload_descriptor_set_world},
+ {&load_descriptor_set_view, &unload_descriptor_set_view},
+ {&load_descriptor_set_model_instance, &unload_descriptor_set_model_instance},
+ {&load_pipeline, &unload_pipeline},
{&load_render_pass, &unload_render_pass}
};
diff --git a/src/vk/graphics_pipeline_3d_layout.hpp b/src/vk/graphics_pipeline_3d_layout.hpp
index 296bdb2..d45a778 100644
--- a/src/vk/graphics_pipeline_3d_layout.hpp
+++ b/src/vk/graphics_pipeline_3d_layout.hpp
@@ -22,9 +22,32 @@
namespace VK
{
+struct UBOWorld3D_Vert
+{
+ glm::vec4 ambient_light_color;
+};
+
+struct UBOWorld3D_Frag
+{
+ glm::vec3 directional_light_direction;
+ glm::vec4 directional_light_color;
+};
+
+struct UBOView3D
+{
+ glm::mat4 view;
+ glm::mat4 proj;
+};
+
+struct UBOModelInstance
+{
+ glm::mat4 instances[128];
+};
+
struct GraphicsPipeline3DLayout
{
- VkDescriptorSetLayout descriptor_set_world_view;
+ VkDescriptorSetLayout descriptor_set_world;
+ VkDescriptorSetLayout descriptor_set_view;
VkDescriptorSetLayout descriptor_set_model_instance;
VkPipelineLayout pipeline;
VkRenderPass render_pass;
diff --git a/src/vk/renderer.cpp b/src/vk/renderer.cpp
index 33a4bf7..e806716 100644
--- a/src/vk/renderer.cpp
+++ b/src/vk/renderer.cpp
@@ -16,64 +16,14 @@
#include "renderer.hpp"
+#include <array>
+
#include "../core.hpp"
namespace
{
void
-load_frame_sync(void *obj)
-{
- auto self = static_cast<VK::Renderer*>(obj);
-
- self->image_available_semaphores.resize(self->max_frames_in_flight);
- self->render_finished_semaphores.resize(self->max_frames_in_flight);
- self->in_flight_fences.resize(self->max_frames_in_flight);
-
- VkSemaphoreCreateInfo semaphore_info = {};
- semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- semaphore_info.pNext = nullptr;
- semaphore_info.flags = 0;
-
- VkFenceCreateInfo fence_info = {};
- fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
- fence_info.pNext = nullptr;
- fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
-
- // FIXME: if this loop fails, it will not destroy the semaphores.
- for(auto i{0}; i < self->max_frames_in_flight; i++)
- {
- if(vkCreateSemaphore(
- cg_core.vk_device_with_swapchain->device, &semaphore_info,
- nullptr, &self->image_available_semaphores[i]) != VK_SUCCESS ||
- vkCreateSemaphore(
- cg_core.vk_device_with_swapchain->device, &semaphore_info,
- nullptr, &self->render_finished_semaphores[i]) != VK_SUCCESS ||
- vkCreateFence(cg_core.vk_device_with_swapchain->device, &fence_info,
- nullptr, &self->in_flight_fences[i]) != VK_SUCCESS)
- throw CommandError{"Failed to create semaphores."};
- }
-}
-
-void
-unload_frame_sync(void *obj)
-{
- auto self = static_cast<VK::Renderer*>(obj);
-
- vkDeviceWaitIdle(cg_core.vk_device_with_swapchain->device);
-
- for(auto i{0}; i < self->max_frames_in_flight; i++)
- {
- vkDestroySemaphore(cg_core.vk_device_with_swapchain->device,
- self->render_finished_semaphores[i], nullptr);
- vkDestroySemaphore(cg_core.vk_device_with_swapchain->device,
- self->image_available_semaphores[i], nullptr);
- vkDestroyFence(cg_core.vk_device_with_swapchain->device,
- self->in_flight_fences[i], nullptr);
- }
-}
-
-void
load_queue_family(void *obj)
{
auto self = static_cast<VK::Renderer*>(obj);
@@ -103,9 +53,10 @@ unload_command_pool(void *obj)
{
auto self = static_cast<VK::Renderer*>(obj);
- vkWaitForFences(cg_core.vk_device_with_swapchain->device, 2,
- self->in_flight_fences.data(), VK_TRUE,
- std::numeric_limits<uint64_t>::max());
+ vkWaitForFences(cg_core.vk_device_with_swapchain->device,
+ VK::Swapchain::max_frames_in_flight,
+ cg_core.vk_swapchain->in_flight_fences.data(), VK_TRUE,
+ std::numeric_limits<uint64_t>::max());
vkDestroyCommandPool(
self->queue_family->device->device, self->command_pool, nullptr);
}
@@ -132,7 +83,6 @@ load_draw_command_buffer(void *obj)
}
const CommandChain loader{
- {&load_frame_sync, &unload_frame_sync},
{&load_queue_family, nullptr},
{&load_command_pool, &unload_command_pool},
{&load_draw_command_buffer, nullptr}
@@ -143,12 +93,18 @@ const CommandChain loader{
namespace VK
{
-Renderer::Renderer():
- current_frame{0}
+Renderer::Renderer(std::vector<std::shared_ptr<View>> views):
+ models_to_draw{cg_core.vk_swapchain->images_count},
+ views{views}
{
loader.execute(this);
}
+Renderer::Renderer(std::initializer_list<std::shared_ptr<View>> views):
+ Renderer{std::vector<std::shared_ptr<View>>(views)}
+{
+}
+
Renderer::~Renderer()
{
loader.revert(this);
@@ -158,24 +114,26 @@ void
Renderer::draw()
{
vkWaitForFences(cg_core.vk_device_with_swapchain->device, 1,
- &this->in_flight_fences[this->current_frame], VK_TRUE,
- std::numeric_limits<uint64_t>::max());
+ &cg_core.vk_swapchain->in_flight_fences[
+ cg_core.vk_swapchain->current_frame], VK_TRUE,
+ std::numeric_limits<uint64_t>::max());
vkResetFences(cg_core.vk_device_with_swapchain->device, 1,
- &this->in_flight_fences[this->current_frame]);
+ &cg_core.vk_swapchain->in_flight_fences[
+ cg_core.vk_swapchain->current_frame]);
uint32_t image_index;
vkAcquireNextImageKHR(
- cg_core.vk_device_with_swapchain->device, cg_core.vk_swapchain->swapchain,
- std::numeric_limits<uint64_t>::max(),
- this->image_available_semaphores[this->current_frame],
- VK_NULL_HANDLE, &image_index);
+ cg_core.vk_device_with_swapchain->device,
+ cg_core.vk_swapchain->swapchain, std::numeric_limits<uint64_t>::max(),
+ cg_core.vk_swapchain->image_available_semaphores[
+ cg_core.vk_swapchain->current_frame], VK_NULL_HANDLE, &image_index);
VkCommandBuffer draw_command_buffer =
- this->draw_command_buffers[this->current_frame];
+ this->draw_command_buffers[cg_core.vk_swapchain->current_frame];
vkResetCommandBuffer(draw_command_buffer, 0);
- auto next_frame = this->current_frame + 1;
- if(next_frame == this->max_frames_in_flight) next_frame = 0;
+ auto next_frame = cg_core.vk_swapchain->current_frame + 1;
+ if(next_frame == Swapchain::max_frames_in_flight) next_frame = 0;
// Begin command buffer.
{
@@ -187,10 +145,64 @@ Renderer::draw()
throw std::runtime_error{"Failed to beggin draw command buffer."};
}
- cg_core.vk_graphics_pipeline_3d->draw(
- draw_command_buffer, current_frame, next_frame, image_index);
- cg_core.vk_graphics_pipeline_2d->draw(
- draw_command_buffer, current_frame, next_frame, image_index);
+ // 3D drawing.
+ {
+ // Dark gray blue.
+ std::array<VkClearValue, 2> clear_values{};
+ clear_values[0].color = {0.12f, 0.12f, 0.18f, 1.0f};
+ clear_values[1].depthStencil = {1.0f, 0};
+
+ VkRenderPassBeginInfo render_pass_begin{};
+ render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ render_pass_begin.pNext = nullptr;
+ render_pass_begin.renderPass =
+ cg_core.vk_graphics_pipeline_3d_layout->render_pass;
+ render_pass_begin.framebuffer =
+ cg_core.vk_graphics_pipeline_3d->swapchain_framebuffers[image_index];
+ render_pass_begin.renderArea.offset = {0, 0};
+ render_pass_begin.renderArea.extent = {
+ static_cast<uint32_t>(cg_core.screen_width),
+ static_cast<uint32_t>(cg_core.screen_height)};
+ render_pass_begin.clearValueCount = clear_values.size();
+ render_pass_begin.pClearValues = clear_values.data();
+
+ vkCmdBeginRenderPass(
+ draw_command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE);
+
+ for(auto &view: this->views)
+ cg_core.vk_graphics_pipeline_3d->draw(
+ view, draw_command_buffer, cg_core.vk_swapchain->current_frame,
+ image_index);
+
+ vkCmdEndRenderPass(draw_command_buffer);
+ }
+
+ // 2D drawing
+ {
+ VkRenderPassBeginInfo render_pass_begin{};
+ render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ render_pass_begin.pNext = nullptr;
+ render_pass_begin.renderPass =
+ cg_core.vk_graphics_pipeline_2d_layout->render_pass;
+ render_pass_begin.framebuffer =
+ cg_core.vk_graphics_pipeline_2d->swapchain_framebuffers[image_index];
+ render_pass_begin.renderArea.offset = {0, 0};
+ render_pass_begin.renderArea.extent = {
+ static_cast<uint32_t>(cg_core.screen_width),
+ static_cast<uint32_t>(cg_core.screen_height)};
+ render_pass_begin.clearValueCount = 0;
+ render_pass_begin.pClearValues = nullptr;
+
+ vkCmdBeginRenderPass(
+ draw_command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE);
+
+ for(auto &view: this->views)
+ cg_core.vk_graphics_pipeline_2d->draw(
+ view, draw_command_buffer, cg_core.vk_swapchain->current_frame,
+ next_frame, image_index);
+
+ vkCmdEndRenderPass(draw_command_buffer);
+ }
// End command buffer.
if(vkEndCommandBuffer(draw_command_buffer) != VK_SUCCESS)
@@ -201,11 +213,13 @@ Renderer::draw()
auto queue{this->queue_family->get_queue()};
VkSemaphore wait_semaphores[]{
- this->image_available_semaphores[this->current_frame]};
+ cg_core.vk_swapchain->image_available_semaphores[
+ cg_core.vk_swapchain->current_frame]};
VkPipelineStageFlags wait_stages[] =
{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
VkSemaphore signal_semaphores[]{
- this->render_finished_semaphores[this->current_frame]};
+ cg_core.vk_swapchain->render_finished_semaphores[
+ cg_core.vk_swapchain->current_frame]};
VkSubmitInfo submit_info{};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
@@ -219,8 +233,8 @@ Renderer::draw()
submit_info.pSignalSemaphores = signal_semaphores;
if(vkQueueSubmit(
- queue.queue, 1, &submit_info,
- this->in_flight_fences[this->current_frame]) != VK_SUCCESS)
+ queue.queue, 1, &submit_info, cg_core.vk_swapchain->in_flight_fences[
+ cg_core.vk_swapchain->current_frame]) != VK_SUCCESS)
throw std::runtime_error{"Failed to submit draw command buffer."};
VkSwapchainKHR swap_chains[]{cg_core.vk_swapchain->swapchain};
@@ -239,7 +253,8 @@ Renderer::draw()
}
// Prepare for the next frame.
- this->current_frame = next_frame;
+ this->models_to_draw[next_frame].clear();
+ cg_core.vk_swapchain->current_frame = next_frame;
}
}
diff --git a/src/vk/renderer.hpp b/src/vk/renderer.hpp
index 4b6c91d..4cd7739 100644
--- a/src/vk/renderer.hpp
+++ b/src/vk/renderer.hpp
@@ -17,27 +17,32 @@
#ifndef CANDY_GEAR_VK_RENDERER_H
#define CANDY_GEAR_VK_RENDERER_H 1
+#include <initializer_list>
+#include <memory>
#include <vector>
#include "core.hpp"
+#include "model.hpp"
+#include "model_instance.hpp"
#include "queue_family.hpp"
+#include "view.hpp"
namespace VK
{
struct Renderer
{
- static const int max_frames_in_flight{2};
- size_t current_frame;
- std::vector<VkSemaphore> image_available_semaphores;
- std::vector<VkSemaphore> render_finished_semaphores;
- std::vector<VkFence> in_flight_fences;
+ std::vector<std::unordered_map<
+ std::shared_ptr<Model>, std::vector<ModelInstance>>>
+ models_to_draw;
+ std::vector<std::shared_ptr<View>> views;
QueueFamily *queue_family;
VkCommandPool command_pool;
std::vector<VkCommandBuffer> draw_command_buffers;
- Renderer();
+ Renderer(std::vector<std::shared_ptr<View>> views);
+ Renderer(std::initializer_list<std::shared_ptr<View>> views);
~Renderer();
void
diff --git a/src/vk/swapchain.cpp b/src/vk/swapchain.cpp
index 678279e..1dd19d9 100644
--- a/src/vk/swapchain.cpp
+++ b/src/vk/swapchain.cpp
@@ -127,9 +127,62 @@ unload_image_view(void *obj)
cg_core.vk_device_with_swapchain->device, self->image_views[i], nullptr);
}
+void
+load_frame_sync(void *obj)
+{
+ auto self = static_cast<VK::Swapchain*>(obj);
+
+ self->image_available_semaphores.resize(self->max_frames_in_flight);
+ self->render_finished_semaphores.resize(self->max_frames_in_flight);
+ self->in_flight_fences.resize(self->max_frames_in_flight);
+
+ VkSemaphoreCreateInfo semaphore_info = {};
+ semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+ semaphore_info.pNext = nullptr;
+ semaphore_info.flags = 0;
+
+ VkFenceCreateInfo fence_info = {};
+ fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+ fence_info.pNext = nullptr;
+ fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
+
+ // FIXME: if this loop fails, it will not destroy the semaphores.
+ for(auto i{0}; i < self->max_frames_in_flight; i++)
+ {
+ if(vkCreateSemaphore(
+ cg_core.vk_device_with_swapchain->device, &semaphore_info,
+ nullptr, &self->image_available_semaphores[i]) != VK_SUCCESS ||
+ vkCreateSemaphore(
+ cg_core.vk_device_with_swapchain->device, &semaphore_info,
+ nullptr, &self->render_finished_semaphores[i]) != VK_SUCCESS ||
+ vkCreateFence(cg_core.vk_device_with_swapchain->device, &fence_info,
+ nullptr, &self->in_flight_fences[i]) != VK_SUCCESS)
+ throw CommandError{"Failed to create semaphores."};
+ }
+}
+
+void
+unload_frame_sync(void *obj)
+{
+ auto self = static_cast<VK::Swapchain*>(obj);
+
+ vkDeviceWaitIdle(cg_core.vk_device_with_swapchain->device);
+
+ for(auto i{0}; i < self->max_frames_in_flight; i++)
+ {
+ vkDestroySemaphore(cg_core.vk_device_with_swapchain->device,
+ self->render_finished_semaphores[i], nullptr);
+ vkDestroySemaphore(cg_core.vk_device_with_swapchain->device,
+ self->image_available_semaphores[i], nullptr);
+ vkDestroyFence(cg_core.vk_device_with_swapchain->device,
+ self->in_flight_fences[i], nullptr);
+ }
+}
+
const CommandChain loader{
{&load_swapchain, &unload_swapchain},
- {&load_image_view, &unload_image_view}
+ {&load_image_view, &unload_image_view},
+ {&load_frame_sync, &unload_frame_sync}
};
}
@@ -137,7 +190,8 @@ const CommandChain loader{
namespace VK
{
-Swapchain::Swapchain()
+Swapchain::Swapchain():
+ current_frame{0}
{
loader.execute(this);
}
diff --git a/src/vk/swapchain.hpp b/src/vk/swapchain.hpp
index 64df208..a5ade81 100644
--- a/src/vk/swapchain.hpp
+++ b/src/vk/swapchain.hpp
@@ -32,6 +32,12 @@ struct Swapchain
VkImage *images;
VkImageView *image_views;
+ static const int max_frames_in_flight{2};
+ size_t current_frame;
+ std::vector<VkSemaphore> image_available_semaphores;
+ std::vector<VkSemaphore> render_finished_semaphores;
+ std::vector<VkFence> in_flight_fences;
+
Swapchain();
~Swapchain();
};
diff --git a/src/vk/uniform_buffer.hpp b/src/vk/uniform_buffer.hpp
index 2cee9ff..e978894 100644
--- a/src/vk/uniform_buffer.hpp
+++ b/src/vk/uniform_buffer.hpp
@@ -26,34 +26,6 @@
namespace VK
{
-struct UBOSpritePositions
-{
- glm::vec4 positions[128];
-};
-
-struct UBOProjection
-{
- glm::mat4 proj;
-};
-
-struct UBOModelInstance
-{
- glm::mat4 instances[128];
-};
-
-struct UBOViewProjection
-{
- glm::mat4 view;
- glm::mat4 proj;
- glm::vec4 ambient_color;
-};
-
-struct UBODirectionalLight
-{
- glm::vec3 direction;
- glm::vec4 color;
-};
-
// FIXME: this class need to delete or create custom copy constructors!
class UniformBuffer: public BaseBuffer
{
diff --git a/src/vk/view.cpp b/src/vk/view.cpp
new file mode 100644
index 0000000..16ee60c
--- /dev/null
+++ b/src/vk/view.cpp
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2022 Frederico de Oliveira Linhares
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "view.hpp"
+
+#include <array>
+
+#include "../core.hpp"
+
+namespace
+{
+
+void
+load_3d_uniform_buffer(void *obj)
+{
+ auto self = static_cast<VK::View*>(obj);
+
+ try
+ {
+ self->ub_3d.reserve(cg_core.vk_swapchain->images_count);
+ for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++)
+ self->ub_3d.emplace_back(
+ cg_core.vk_device_with_swapchain, sizeof(VK::UBOView3D));
+ }
+ catch(const std::exception& e)
+ {
+ throw CommandError{e.what()};
+ }
+}
+
+void
+unload_3d_uniform_buffer(void *obj)
+{
+ auto self = static_cast<VK::View*>(obj);
+
+ self->ub_3d.clear();
+}
+
+void
+load_2d_uniform_buffer(void *obj)
+{
+ auto self = static_cast<VK::View*>(obj);
+
+ try
+ {
+ self->ub_2d.reserve(cg_core.vk_swapchain->images_count);
+ for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++)
+ self->ub_2d.emplace_back(
+ cg_core.vk_device_with_swapchain, sizeof(VK::UBOView2D));
+ }
+ catch(const std::exception& e)
+ {
+ throw CommandError{e.what()};
+ }
+}
+
+void
+unload_2d_uniform_buffer(void *obj)
+{
+ auto self = static_cast<VK::View*>(obj);
+
+ self->ub_2d.clear();
+}
+
+void
+load_descriptor_pool(void *obj)
+{
+ auto self = static_cast<VK::View*>(obj);
+
+ uint32_t uniform_buffer_count = self->ub_3d.size() + self->ub_2d.size();
+
+ VkDescriptorPoolSize descriptor_pool_size{};
+ descriptor_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ descriptor_pool_size.descriptorCount = uniform_buffer_count;
+
+ VkDescriptorPoolCreateInfo pool_info{};
+ pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+ pool_info.pNext = nullptr;
+ pool_info.flags = 0;
+ pool_info.maxSets = uniform_buffer_count;
+ pool_info.poolSizeCount = 1;
+ pool_info.pPoolSizes = &descriptor_pool_size;
+
+ if(vkCreateDescriptorPool(
+ cg_core.vk_device_with_swapchain->device, &pool_info, nullptr,
+ &self->descriptor_pool) != VK_SUCCESS)
+ throw CommandError{"Failed to create a Vulkan descriptor pool."};
+}
+
+void
+unload_descriptor_pool(void *obj)
+{
+ auto self = static_cast<VK::View*>(obj);
+
+ vkDestroyDescriptorPool(
+ cg_core.vk_device_with_swapchain->device, self->descriptor_pool,
+ nullptr);
+}
+
+void
+load_descriptor_sets_3d(void *obj)
+{
+ auto self = static_cast<VK::View*>(obj);
+
+ std::vector<VkDescriptorSetLayout> layouts(
+ cg_core.vk_swapchain->images_count,
+ cg_core.vk_graphics_pipeline_3d_layout->descriptor_set_view);
+
+ VkDescriptorSetAllocateInfo alloc_info{};
+ alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+ alloc_info.descriptorPool = self->descriptor_pool;
+ alloc_info.descriptorSetCount = layouts.size();
+ alloc_info.pSetLayouts = layouts.data();
+
+ self->descriptor_sets_3d.resize(layouts.size());
+ if(vkAllocateDescriptorSets(
+ cg_core.vk_device_with_swapchain->device, &alloc_info,
+ self->descriptor_sets_3d.data()) != VK_SUCCESS)
+ throw CommandError{"Failed to create Vulkan descriptor sets for view."};
+}
+
+void
+load_descriptor_sets_2d(void *obj)
+{
+ auto self = static_cast<VK::View*>(obj);
+
+ std::vector<VkDescriptorSetLayout> layouts(
+ cg_core.vk_swapchain->images_count,
+ cg_core.vk_graphics_pipeline_2d_layout->descriptor_set_view);
+
+ VkDescriptorSetAllocateInfo alloc_info{};
+ alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+ alloc_info.descriptorPool = self->descriptor_pool;
+ alloc_info.descriptorSetCount = layouts.size();
+ alloc_info.pSetLayouts = layouts.data();
+
+ self->descriptor_sets_2d.resize(layouts.size());
+ if(vkAllocateDescriptorSets(
+ cg_core.vk_device_with_swapchain->device, &alloc_info,
+ self->descriptor_sets_2d.data()) != VK_SUCCESS)
+ throw CommandError{"Failed to create Vulkan descriptor sets for view."};
+}
+
+void
+load_resources_to_descriptor_sets_3d(void *obj)
+{
+ auto self = static_cast<VK::View*>(obj);
+
+ for(auto i{0}; i < self->ub_3d.size(); i++)
+ {
+ VkDescriptorBufferInfo view_3d_info{};
+ view_3d_info.buffer = self->ub_3d[i].buffer;
+ view_3d_info.offset = 0;
+ view_3d_info.range = sizeof(VK::UBOView3D);
+
+ std::array<VkWriteDescriptorSet, 1> write_descriptors{};
+ write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ write_descriptors[0].dstSet = self->descriptor_sets_3d[i];
+ write_descriptors[0].dstBinding = 0;
+ write_descriptors[0].dstArrayElement = 0;
+ write_descriptors[0].descriptorCount = 1;
+ write_descriptors[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ write_descriptors[0].pBufferInfo = &view_3d_info;
+ write_descriptors[0].pImageInfo = nullptr;
+ write_descriptors[0].pTexelBufferView = nullptr;
+
+ vkUpdateDescriptorSets(
+ cg_core.vk_device_with_swapchain->device, write_descriptors.size(),
+ write_descriptors.data(), 0, nullptr);
+
+ VK::UBOView3D ubo_view_3d;
+ ubo_view_3d.proj = glm::ortho(
+ 0.0f, self->region.z,
+ 0.0f, self->region.w,
+ 0.0f, 100.0f);
+ self->ub_3d[i].copy_data(&ubo_view_3d);
+ }
+}
+
+void
+load_resources_to_descriptor_sets_2d(void *obj)
+{
+ auto self = static_cast<VK::View*>(obj);
+
+ for(auto i{0}; i < self->ub_2d.size(); i++)
+ {
+ VkDescriptorBufferInfo view_2d_info{};
+ view_2d_info.buffer = self->ub_2d[i].buffer;
+ view_2d_info.offset = 0;
+ view_2d_info.range = sizeof(VK::UBOView2D);
+
+ std::array<VkWriteDescriptorSet, 1> write_descriptors{};
+ write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ write_descriptors[0].dstSet = self->descriptor_sets_2d[i];
+ write_descriptors[0].dstBinding = 0;
+ write_descriptors[0].dstArrayElement = 0;
+ write_descriptors[0].descriptorCount = 1;
+ write_descriptors[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ write_descriptors[0].pBufferInfo = &view_2d_info;
+ write_descriptors[0].pImageInfo = nullptr;
+ write_descriptors[0].pTexelBufferView = nullptr;
+
+ vkUpdateDescriptorSets(
+ cg_core.vk_device_with_swapchain->device, write_descriptors.size(),
+ write_descriptors.data(), 0, nullptr);
+
+ VK::UBOView2D ubo_view_2d;
+ ubo_view_2d.proj = glm::ortho(
+ 0.0f, self->region.z,
+ 0.0f, self->region.w,
+ 0.0f, 100.0f);
+ self->ub_2d[i].copy_data(&ubo_view_2d);
+ }
+}
+
+const CommandChain loader{
+ {&load_3d_uniform_buffer, &unload_3d_uniform_buffer},
+ {&load_2d_uniform_buffer, &unload_2d_uniform_buffer},
+ {&load_descriptor_pool, &unload_descriptor_pool},
+ // By destroying the pool the sets are also destroyed.
+ {&load_descriptor_sets_3d, nullptr},
+ {&load_descriptor_sets_2d, nullptr},
+ {&load_resources_to_descriptor_sets_3d, nullptr},
+ {&load_resources_to_descriptor_sets_2d, nullptr}
+};
+
+}
+
+namespace VK
+{
+
+View::View(glm::vec4 region):
+ region{region},
+ camera_position{std::make_shared<glm::vec3>(0.0f, 0.0f, 0.0f)},
+ camera_rotation{std::make_shared<glm::vec3>(0.0f, 0.0f, 0.0f)},
+ sprites_to_draw{cg_core.vk_swapchain->images_count}
+{
+ loader.execute(this);
+}
+
+View::~View()
+{
+ loader.revert(this);
+}
+
+}
diff --git a/src/vk/view.hpp b/src/vk/view.hpp
new file mode 100644
index 0000000..3936413
--- /dev/null
+++ b/src/vk/view.hpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2022 Frederico de Oliveira Linhares
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CANDY_GEAR_VK_VIEW_H
+#define CANDY_GEAR_VK_VIEW_H 1
+
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include "core.hpp"
+#include "sprite.hpp"
+
+namespace VK
+{
+
+struct View
+{
+ glm::vec4 region;
+
+ // FIXME: if these vectors get resized, they can cause a segmentation fault!
+ std::vector<UniformBuffer> ub_3d;
+ std::vector<UniformBuffer> ub_2d;
+
+ VkDescriptorPool descriptor_pool;
+ std::vector<VkDescriptorSet> descriptor_sets_3d;
+ std::vector<VkDescriptorSet> descriptor_sets_2d;
+
+ std::shared_ptr<glm::vec3> camera_position;
+ std::shared_ptr<glm::vec3> camera_rotation;
+
+ std::vector<
+ std::unordered_map<std::shared_ptr<Sprite>, std::vector<glm::vec4>>>
+ sprites_to_draw;
+
+ View(glm::vec4 region);
+ ~View();
+};
+
+}
+
+#endif /* CANDY_GEAR_VK_VIEW_H */