From 3d6ca447a7104c499e92fc954affdaf4bf011388 Mon Sep 17 00:00:00 2001 From: Frederico Linhares Date: Fri, 16 Sep 2022 12:03:04 -0300 Subject: feat Create View --- glsl/shader_2d.vert.glsl | 6 +- glsl/shader_3d.frag.glsl | 15 +- glsl/shader_3d.vert.glsl | 18 ++- src/candy_gear.cpp | 58 ++++--- src/core.cpp | 27 ++-- src/core.hpp | 12 +- src/main.cpp | 2 + src/model.cpp | 4 +- src/sprite.cpp | 15 +- src/view.cpp | 94 +++++++++++ src/view.hpp | 27 ++++ src/vk/graphics_pipeline_2d.cpp | 226 ++++++-------------------- src/vk/graphics_pipeline_2d.hpp | 18 +-- src/vk/graphics_pipeline_2d_layout.cpp | 29 ++-- src/vk/graphics_pipeline_2d_layout.hpp | 12 +- src/vk/graphics_pipeline_3d.cpp | 281 +++++++++++++++------------------ src/vk/graphics_pipeline_3d.hpp | 17 +- src/vk/graphics_pipeline_3d_layout.cpp | 69 ++++++-- src/vk/graphics_pipeline_3d_layout.hpp | 25 ++- src/vk/renderer.cpp | 169 +++++++++++--------- src/vk/renderer.hpp | 17 +- src/vk/swapchain.cpp | 58 ++++++- src/vk/swapchain.hpp | 6 + src/vk/uniform_buffer.hpp | 28 ---- src/vk/view.cpp | 259 ++++++++++++++++++++++++++++++ src/vk/view.hpp | 55 +++++++ test/config/init.yaml | 3 - test/src/main.rb | 12 +- 28 files changed, 979 insertions(+), 583 deletions(-) create mode 100644 src/view.cpp create mode 100644 src/view.hpp create mode 100644 src/vk/view.cpp create mode 100644 src/vk/view.hpp diff --git a/glsl/shader_2d.vert.glsl b/glsl/shader_2d.vert.glsl index b053fec..5c5a243 100644 --- a/glsl/shader_2d.vert.glsl +++ b/glsl/shader_2d.vert.glsl @@ -21,10 +21,10 @@ layout(location = 0) in vec2 in_texture_coord; layout(location = 0) out vec2 out_texture_coord; -layout(set = 0, binding = 0) uniform UBOProjection +layout(set = 0, binding = 0) uniform UBOView2D { mat4 proj; -} ubo_projection; +} ubo_view; layout(set = 1, binding = 0) uniform UBOSpritePositions { @@ -54,5 +54,5 @@ main() coordinate = vec2(position.z, position.w); break; } - gl_Position = ubo_projection.proj * vec4(coordinate, 0.0, 1.0); + gl_Position = ubo_view.proj * vec4(coordinate, 0.0, 1.0); } diff --git a/glsl/shader_3d.frag.glsl b/glsl/shader_3d.frag.glsl index 5c4b857..302f7d4 100644 --- a/glsl/shader_3d.frag.glsl +++ b/glsl/shader_3d.frag.glsl @@ -28,24 +28,25 @@ layout(location = 0) in DataTransferObject in_dto; layout(location = 0) out vec4 out_color; -layout(set = 0, binding = 1) uniform UBODirectionalLight +layout(set = 0, binding = 1) uniform UBOWorld { - vec3 direction; - vec4 color; -} ubo_directional_light; + vec3 directional_light_direction; + vec4 directional_light_color; +} ubo_world; -layout(set = 1, binding = 1) uniform sampler2D texture_sampler; +layout(set = 2, binding = 1) uniform sampler2D texture_sampler; void main() { float diffuse_factor = - max(dot(in_dto.normal, -ubo_directional_light.direction), 0.0); + max(dot(in_dto.normal, -ubo_world.directional_light_direction), 0.0); vec4 diff_samp = texture(texture_sampler, in_dto.frag_texture_coord); vec4 ambient = vec4(vec3(in_dto.frag_color), diff_samp.a); vec4 diffuse = - vec4(vec3(ubo_directional_light.color * diffuse_factor), diff_samp.a); + vec4(vec3(ubo_world.directional_light_color * diffuse_factor), + diff_samp.a); diffuse *= diff_samp; ambient *= diff_samp; diff --git a/glsl/shader_3d.vert.glsl b/glsl/shader_3d.vert.glsl index 387ad00..29beea9 100644 --- a/glsl/shader_3d.vert.glsl +++ b/glsl/shader_3d.vert.glsl @@ -29,14 +29,18 @@ layout(location = 0) out DataTransferObject vec3 normal; } out_dto; -layout(set = 0, binding = 0) uniform UBOViewProjection +layout(set = 0, binding = 0) uniform UBOWorld +{ + vec4 ambient_light_color; +} ubo_world; + +layout(set = 1, binding = 0) uniform UBOView { mat4 view; mat4 proj; - vec4 ambient_color; -} ubo_view_projection; +} ubo_view; -layout(set = 1, binding = 0) uniform UBOModelInstance +layout(set = 2, binding = 0) uniform UBOModelInstance { mat4 instances[128]; } ubo_model_instance; @@ -45,9 +49,9 @@ void main() { gl_Position = - ubo_view_projection.proj * ubo_view_projection.view * - ubo_model_instance.instances[gl_InstanceIndex] * vec4(in_position, 1.0); - out_dto.frag_color = ubo_view_projection.ambient_color; + ubo_view.proj * ubo_view.view * + ubo_model_instance.instances[gl_InstanceIndex] * vec4(in_position, 1.0); + out_dto.frag_color = ubo_world.ambient_light_color; out_dto.frag_texture_coord = in_texture_coord; out_dto.normal = mat3(ubo_model_instance.instances[gl_InstanceIndex]) * in_normal; diff --git a/src/candy_gear.cpp b/src/candy_gear.cpp index 9460b51..8ba87cc 100644 --- a/src/candy_gear.cpp +++ b/src/candy_gear.cpp @@ -24,6 +24,7 @@ #include "rotation_3d.hpp" #include "vector_3d.hpp" +#include "view.hpp" static mrb_value parse_node(mrb_state *mrb, const YAML::Node &node) @@ -60,37 +61,47 @@ parse_node(mrb_state *mrb, const YAML::Node &node) } static mrb_value -cg_mCandyGear_set_camera_position(mrb_state *mrb, mrb_value self) +cg_mCandyGear_load_yaml(mrb_state *mrb, mrb_value self) { - std::shared_ptr *camera_position; + const char *file_path; - mrb_get_args(mrb, "d", &camera_position, &cg_vector_3d_type); - cg_core.vk_graphics_pipeline_3d->camera_position = (*camera_position); + mrb_get_args(mrb, "z", &file_path); - return self; + YAML::Node root = YAML::LoadFile(file_path); + + return parse_node(mrb, root); } static mrb_value -cg_mCandyGear_set_camera_rotation(mrb_state *mrb, mrb_value self) +cg_mCandyGear_set_views(mrb_state *mrb, mrb_value self) { - std::shared_ptr *camera_rotation; + struct RClass *cg_m, *cg_cView; + mrb_value *array; + mrb_int array_len; - mrb_get_args(mrb, "d", &camera_rotation, &cg_rotation_3d_type); - cg_core.vk_graphics_pipeline_3d->camera_rotation = (*camera_rotation); + std::vector> views; - return self; -} - -static mrb_value -cg_mCandyGear_load_yaml(mrb_state *mrb, mrb_value self) -{ - const char *file_path; + cg_m = mrb_module_get(mrb, "CandyGear"); + cg_cView = mrb_class_get_under(mrb, cg_m, "View"); - mrb_get_args(mrb, "z", &file_path); + mrb_get_args(mrb, "a", &array, &array_len); + for(mrb_int i{0}; i < array_len; i++) + { + if(mrb_obj_is_kind_of(mrb, array[i], cg_cView)) + { + auto v = (std::shared_ptr*)DATA_PTR(array[i]); + views.push_back(*v); + } + } - YAML::Node root = YAML::LoadFile(file_path); + // A Renderer need at least one view to work. + if(views.size() > 0) + { + delete cg_core.vk_renderer; + cg_core.vk_renderer = new VK::Renderer({views}); + } - return parse_node(mrb, root); + return self; } static mrb_value @@ -135,15 +146,10 @@ cg_candy_gear_init(mrb_state *mrb) cg_m = mrb_module_get(mrb, "CandyGear"); - mrb_define_class_method( - mrb, cg_m, "camera_position=", cg_mCandyGear_set_camera_position, - MRB_ARGS_REQ(1)); - mrb_define_class_method( - mrb, cg_m, "camera_rotation=", cg_mCandyGear_set_camera_rotation, - MRB_ARGS_REQ(1)); - mrb_define_class_method( mrb, cg_m, "load_yaml", cg_mCandyGear_load_yaml, MRB_ARGS_REQ(1)); + mrb_define_class_method( + mrb, cg_m, "views=", cg_mCandyGear_set_views, MRB_ARGS_REQ(1)); mrb_define_class_method( mrb, cg_m, "log", cg_mCandyGear_log, MRB_ARGS_REQ(2)); mrb_define_class_method( diff --git a/src/core.cpp b/src/core.cpp index 46fb6eb..5827ef6 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -62,8 +62,6 @@ load_variables(void *obj) cg_core.game_name = new char[game_name.size() + 1]; strcpy(cg_core.game_name, game_name.c_str()); - cg_core.game_width = root["game"]["width"].as(); - cg_core.game_height = root["game"]["height"].as(); cg_core.screen_width = root["screen"]["width"].as(); cg_core.screen_height = root["screen"]["height"].as(); @@ -491,12 +489,13 @@ unload_vk_graphics_pipeline_2d_layout(void *obj) delete cg_core.vk_graphics_pipeline_2d_layout; } -static void +void load_vk_graphics_pipeline_3d(void *obj) { try { - cg_core.vk_graphics_pipeline_3d = new VK::GraphicsPipeline3D(); + cg_core.vk_graphics_pipeline_3d = + std::make_unique(); } catch(const CommandError &e) { @@ -504,18 +503,19 @@ load_vk_graphics_pipeline_3d(void *obj) } } -static void +void unload_vk_graphics_pipeline_3d(void *obj) { - delete cg_core.vk_graphics_pipeline_3d; + cg_core.vk_graphics_pipeline_3d = nullptr; } -static void +void load_vk_graphics_pipeline_2d(void *obj) { try { - cg_core.vk_graphics_pipeline_2d = new VK::GraphicsPipeline2D(); + cg_core.vk_graphics_pipeline_2d = + std::make_unique(); } catch(const CommandError &e) { @@ -523,10 +523,10 @@ load_vk_graphics_pipeline_2d(void *obj) } } -static void +void unload_vk_graphics_pipeline_2d(void *obj) { - delete cg_core.vk_graphics_pipeline_2d; + cg_core.vk_graphics_pipeline_2d = nullptr; } static void @@ -534,7 +534,12 @@ load_vk_renderer(void *obj) { try { - cg_core.vk_renderer = new VK::Renderer(); + glm::vec4 region( + 0.f, 0.f, + static_cast(cg_core.screen_width), + static_cast(cg_core.screen_height)); + cg_core.vk_renderer = new VK::Renderer( + {std::make_shared(region)}); } catch(const CommandError &e) { diff --git a/src/core.hpp b/src/core.hpp index c7dbceb..c4e9a6c 100644 --- a/src/core.hpp +++ b/src/core.hpp @@ -73,14 +73,6 @@ struct cg_sCore /// Text displayed in the game window. char *game_name; - /** - * @{ - * This is the amount of pixel the games use to render a buffer. The image in - * this buffer is then rendered to the screen. - */ - uint32_t game_width, game_height; - /// @} - /** * @{ * This is the ammount of pixel that the games uses when rendering to the @@ -110,8 +102,8 @@ struct cg_sCore VK::GraphicsPipeline3DLayout *vk_graphics_pipeline_3d_layout; VK::GraphicsPipeline2DLayout *vk_graphics_pipeline_2d_layout; - VK::GraphicsPipeline3D *vk_graphics_pipeline_3d; - VK::GraphicsPipeline2D *vk_graphics_pipeline_2d; + std::unique_ptr vk_graphics_pipeline_3d; + std::unique_ptr vk_graphics_pipeline_2d; VK::Renderer *vk_renderer; diff --git a/src/main.cpp b/src/main.cpp index 590ea89..21e2c29 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,6 +27,7 @@ #include "texture.hpp" #include "vector_3d.hpp" #include "vector_4d.hpp" +#include "view.hpp" cg_sCore cg_core; @@ -69,6 +70,7 @@ int main(int argc, char *argv[]) cg_texture_init(cg_core.mrb); cg_vector_3d_init(cg_core.mrb); cg_vector_4d_init(cg_core.mrb); + cg_view_init(cg_core.mrb); main_obj = mrb_obj_iv_inspect(cg_core.mrb, cg_core.mrb->top_self); sym_init = mrb_intern_cstr(cg_core.mrb, "init"); diff --git a/src/model.cpp b/src/model.cpp index 45744f6..6a6e470 100644 --- a/src/model.cpp +++ b/src/model.cpp @@ -70,8 +70,8 @@ cg_cModel_draw(mrb_state *mrb, mrb_value self) instance.position = **position; instance.rotation = **rotation; - auto &instances = cg_core.vk_graphics_pipeline_3d->models_to_draw[ - cg_core.vk_renderer->current_frame][*ptr]; + auto &instances = cg_core.vk_renderer->models_to_draw[ + cg_core.vk_swapchain->current_frame][*ptr]; instances.push_back(instance); return self; diff --git a/src/sprite.cpp b/src/sprite.cpp index 7c1f109..96a702a 100644 --- a/src/sprite.cpp +++ b/src/sprite.cpp @@ -17,8 +17,9 @@ #include "sprite.hpp" #include "texture.hpp" -#include "vk/sprite.hpp" #include "vector_4d.hpp" +#include "view.hpp" +#include "vk/sprite.hpp" void cg_free_sprite(mrb_state *mrb, void* obj) @@ -55,13 +56,13 @@ cg_cSprite_initialize(mrb_state *mrb, mrb_value self) static mrb_value cg_cSprite_draw(mrb_state *mrb, mrb_value self) { - auto *ptr = (std::shared_ptr*)DATA_PTR(self); - + std::shared_ptr *view; std::shared_ptr *position; + auto *ptr = (std::shared_ptr*)DATA_PTR(self); - mrb_get_args(mrb, "d", &position, &cg_vector_4d_type); - auto &positions = cg_core.vk_graphics_pipeline_2d->sprites_to_draw[ - cg_core.vk_renderer->current_frame][*ptr]; + mrb_get_args(mrb, "dd", &view, &cg_view_type, &position, &cg_vector_4d_type); + auto &positions = (*view)->sprites_to_draw[ + cg_core.vk_swapchain->current_frame][*ptr]; positions.push_back(*position->get()); return self; @@ -77,5 +78,5 @@ cg_sprite_init(mrb_state *mrb) MRB_SET_INSTANCE_TT(cg_cSprite, MRB_TT_DATA); mrb_define_method( mrb, cg_cSprite, "initialize", cg_cSprite_initialize, MRB_ARGS_REQ(2)); - mrb_define_method(mrb, cg_cSprite, "draw", cg_cSprite_draw, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, cg_cSprite, "draw", cg_cSprite_draw, MRB_ARGS_REQ(2)); } diff --git a/src/view.cpp b/src/view.cpp new file mode 100644 index 0000000..745c4bc --- /dev/null +++ b/src/view.cpp @@ -0,0 +1,94 @@ +/* + * 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 "rotation_3d.hpp" +#include "vector_3d.hpp" +#include "vector_4d.hpp" +#include "vk/view.hpp" + +void +cg_free_view(mrb_state *mrb, void* obj) +{ + auto ptr = static_cast*>(obj); + + ptr->~shared_ptr(); + mrb_free(mrb, ptr); +} + +const struct mrb_data_type cg_view_type = { "CG_View", cg_free_view }; + +static mrb_value +cg_cView_initialize(mrb_state *mrb, mrb_value self) +{ + std::shared_ptr *region; + std::shared_ptr *ptr; + + mrb_get_args(mrb, "d", ®ion, &cg_vector_4d_type); + ptr = (std::shared_ptr*)DATA_PTR(self); + if(ptr) mrb_free(mrb, ptr); + ptr = (std::shared_ptr*)mrb_malloc( + mrb, sizeof(std::shared_ptr)); + + new(ptr)std::shared_ptr( + std::make_shared(*region->get())); + + mrb_data_init(self, ptr, &cg_view_type); + return self; +} + +static mrb_value +cg_cView_set_camera_position(mrb_state *mrb, mrb_value self) +{ + std::shared_ptr *camera_position; + auto ptr = (std::shared_ptr*)DATA_PTR(self); + + mrb_get_args(mrb, "d", &camera_position, &cg_vector_3d_type); + (*ptr)->camera_position = (*camera_position); + + return self; +} + +static mrb_value +cg_cView_set_camera_rotation(mrb_state *mrb, mrb_value self) +{ + std::shared_ptr *camera_rotation; + auto ptr = (std::shared_ptr*)DATA_PTR(self); + + mrb_get_args(mrb, "d", &camera_rotation, &cg_rotation_3d_type); + (*ptr)->camera_rotation = (*camera_rotation); + + return self; +} + +void +cg_view_init(mrb_state *mrb) +{ + struct RClass *cg_m, *cg_cView; + + cg_m = mrb_module_get(mrb, "CandyGear"); + cg_cView = mrb_define_class_under(mrb, cg_m, "View", mrb->object_class); + MRB_SET_INSTANCE_TT(cg_cView, MRB_TT_DATA); + mrb_define_method( + mrb, cg_cView, "initialize", cg_cView_initialize, MRB_ARGS_REQ(1)); + mrb_define_method( + mrb, cg_cView, "camera_position=", cg_cView_set_camera_position, + MRB_ARGS_REQ(1)); + mrb_define_method( + mrb, cg_cView, "camera_rotation=", cg_cView_set_camera_rotation, + MRB_ARGS_REQ(1)); +} diff --git a/src/view.hpp b/src/view.hpp new file mode 100644 index 0000000..ae22b59 --- /dev/null +++ b/src/view.hpp @@ -0,0 +1,27 @@ +/* + * 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_VIEW_H +#define CANDY_GEAR_VIEW_H 1 + +#include "core.hpp" + +extern const struct mrb_data_type cg_view_type; + +void +cg_view_init(mrb_state *mrb); + +#endif /* CANDY_GEAR_VIEW_H */ 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 @@ -24,123 +24,6 @@ namespace { -void -load_projection_uniform_buffer(void *obj) -{ - auto self = static_cast(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(obj); - - self->ub_projection.clear(); -} - -void -load_descriptor_pool(void *obj) -{ - auto self = static_cast(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(obj); - - vkDestroyDescriptorPool( - cg_core.vk_device_with_swapchain->device, self->descriptor_pool, - nullptr); -} - -void -load_projection_descriptor_sets(void *obj) -{ - auto self = static_cast(obj); - - std::vector 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(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 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(cg_core.game_width), - 0.0f, static_cast(cg_core.game_height), - 0.0f, 100.0f); - self->ub_projection[i].copy_data(&ubo_projection); - } -} - void load_framebuffer(void *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(cg_core.screen_width); - viewport.height = static_cast(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, 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(cg_core.screen_width); - vk_viewport.height = static_cast(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(view->region.x); + vk_scissor.offset.y = static_cast(view->region.y); + vk_scissor.extent.width = static_cast(view->region.z); + vk_scissor.extent.height = static_cast(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 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 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 +#include #include #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 ub_projection; - - VkDescriptorPool descriptor_pool; - std::vector projection_descriptor_sets; - VkRenderPass render_pass; std::vector swapchain_framebuffers; VkPipeline graphic_pipeline; - std::vector< - std::unordered_map, std::vector>> - 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, 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(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(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(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(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(obj); std::array 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(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(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(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(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(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(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(obj); std::vector 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(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 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(cg_core.screen_width); - viewport.height = static_cast(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(0.0f, 0.0f, 0.0f)}, - camera_rotation{std::make_shared(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, const VkCommandBuffer draw_command_buffer, + const size_t current_frame, const uint32_t image_index) { - // Load command. + // Set viewport { - // Dark gray blue. - std::array 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(cg_core.screen_width); - vk_viewport.height = static_cast(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(view->region.x); + vk_scissor.offset.y = static_cast(view->region.y); + vk_scissor.extent.width = static_cast(view->region.z); + vk_scissor.extent.height = static_cast(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 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 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(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 ub_view_projection; - std::vector ub_directional_light; + std::vector ub_world_vert; + std::vector ub_world_frag; VkDescriptorPool descriptor_pool; - std::vector world_view_descriptor_sets; + std::vector descriptor_sets_world; std::vector swapchain_framebuffers; VkPipeline graphic_pipeline; - std::shared_ptr camera_position; - std::shared_ptr camera_rotation; - std::vector, std::vector>> - 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, 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(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(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(obj); + + std::array 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(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(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(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(obj); - std::array set_layouts{ - self->descriptor_set_world_view, + std::array 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(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,63 +16,13 @@ #include "renderer.hpp" +#include + #include "../core.hpp" namespace { -void -load_frame_sync(void *obj) -{ - auto self = static_cast(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(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) { @@ -103,9 +53,10 @@ unload_command_pool(void *obj) { auto self = static_cast(obj); - vkWaitForFences(cg_core.vk_device_with_swapchain->device, 2, - self->in_flight_fences.data(), VK_TRUE, - std::numeric_limits::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::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> views): + models_to_draw{cg_core.vk_swapchain->images_count}, + views{views} { loader.execute(this); } +Renderer::Renderer(std::initializer_list> views): + Renderer{std::vector>(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::max()); + &cg_core.vk_swapchain->in_flight_fences[ + cg_core.vk_swapchain->current_frame], VK_TRUE, + std::numeric_limits::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::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::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 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(cg_core.screen_width), + static_cast(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(cg_core.screen_width), + static_cast(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 +#include #include #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 image_available_semaphores; - std::vector render_finished_semaphores; - std::vector in_flight_fences; + std::vector, std::vector>> + models_to_draw; + std::vector> views; QueueFamily *queue_family; VkCommandPool command_pool; std::vector draw_command_buffers; - Renderer(); + Renderer(std::vector> views); + Renderer(std::initializer_list> 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(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(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 image_available_semaphores; + std::vector render_finished_semaphores; + std::vector 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 + +#include "../core.hpp" + +namespace +{ + +void +load_3d_uniform_buffer(void *obj) +{ + auto self = static_cast(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(obj); + + self->ub_3d.clear(); +} + +void +load_2d_uniform_buffer(void *obj) +{ + auto self = static_cast(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(obj); + + self->ub_2d.clear(); +} + +void +load_descriptor_pool(void *obj) +{ + auto self = static_cast(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(obj); + + vkDestroyDescriptorPool( + cg_core.vk_device_with_swapchain->device, self->descriptor_pool, + nullptr); +} + +void +load_descriptor_sets_3d(void *obj) +{ + auto self = static_cast(obj); + + std::vector 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(obj); + + std::vector 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(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 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(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 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(0.0f, 0.0f, 0.0f)}, + camera_rotation{std::make_shared(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 +#include +#include + +#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 ub_3d; + std::vector ub_2d; + + VkDescriptorPool descriptor_pool; + std::vector descriptor_sets_3d; + std::vector descriptor_sets_2d; + + std::shared_ptr camera_position; + std::shared_ptr camera_rotation; + + std::vector< + std::unordered_map, std::vector>> + sprites_to_draw; + + View(glm::vec4 region); + ~View(); +}; + +} + +#endif /* CANDY_GEAR_VK_VIEW_H */ diff --git a/test/config/init.yaml b/test/config/init.yaml index 2139b75..0a7fdcf 100644 --- a/test/config/init.yaml +++ b/test/config/init.yaml @@ -1,7 +1,4 @@ name: "Candy Gear Test" -game: - width: 640 - height: 360 screen: width: 1280 height: 720 diff --git a/test/src/main.rb b/test/src/main.rb index f5c0676..67ef80c 100644 --- a/test/src/main.rb +++ b/test/src/main.rb @@ -35,8 +35,14 @@ def init() $camera_position = CandyGear::Vector3D.new(0.0, 0.0, 0.0); $camera_rotation = CandyGear::Rotation3D.new(0.0, 0.0, 0.0); - CandyGear.camera_position = $camera_position; - CandyGear.camera_rotation = $camera_rotation; + + color = CandyGear::Vector3D.new(0.12, 0.12, 0.18); + $view1 = CandyGear::View.new(CandyGear::Vector4D.new(0, 0, 1280, 360)); + $view2 = CandyGear::View.new(CandyGear::Vector4D.new(0, 360, 1280, 360)); + CandyGear.views = [$view1, $view2]; + + $view1.camera_position = $camera_position; + $view1.camera_rotation = $camera_rotation; end def key_down(key) @@ -70,7 +76,7 @@ end def quit() = CandyGear.quit(); def tick() - $sprite.draw($sprite_position); + $sprite.draw($view2, $sprite_position); $instances_rotation.rotate(0.0, BOX_ROTATION_SPEED); $instances.each do |i| $model.draw(i, $instances_rotation); -- cgit v1.2.3