From bde8c8bd073abeb314748d66d6402f951ecb2902 Mon Sep 17 00:00:00 2001 From: Frederico Linhares Date: Wed, 9 Nov 2022 16:11:15 -0300 Subject: feat create method Rectangle#draw --- glsl/shader_2d_wired.frag.glsl | 30 +++ glsl/shader_2d_wired.vert.glsl | 30 +++ src/core.cpp | 69 ++++-- src/core.hpp | 12 +- src/rectangle.cpp | 122 +++++----- src/rectangle.hpp | 6 +- src/sprite.cpp | 21 ++ src/view_2d.cpp | 30 ++- src/view_2d.hpp | 6 + src/view_3d.cpp | 17 -- src/vk/destination_buffer.cpp | 70 +++--- src/vk/destination_buffer.hpp | 3 + src/vk/device.cpp | 7 + src/vk/device.hpp | 2 + src/vk/graphics_pipeline_2d.cpp | 332 -------------------------- src/vk/graphics_pipeline_2d.hpp | 47 ---- src/vk/graphics_pipeline_2d_layout.cpp | 231 ------------------- src/vk/graphics_pipeline_2d_layout.hpp | 48 ---- src/vk/graphics_pipeline_2d_solid.cpp | 333 +++++++++++++++++++++++++++ src/vk/graphics_pipeline_2d_solid.hpp | 47 ++++ src/vk/graphics_pipeline_2d_solid_layout.cpp | 231 +++++++++++++++++++ src/vk/graphics_pipeline_2d_solid_layout.hpp | 48 ++++ src/vk/graphics_pipeline_2d_wired.cpp | 324 ++++++++++++++++++++++++++ src/vk/graphics_pipeline_2d_wired.hpp | 46 ++++ src/vk/graphics_pipeline_2d_wired_layout.cpp | 225 ++++++++++++++++++ src/vk/graphics_pipeline_2d_wired_layout.hpp | 43 ++++ src/vk/rectangle.cpp | 245 ++++++++++++++++++++ src/vk/rectangle.hpp | 66 ++++++ src/vk/renderer.cpp | 51 +++- src/vk/source_buffer.cpp | 13 +- src/vk/source_buffer.hpp | 4 +- src/vk/sprite.cpp | 2 +- src/vk/view_2d.cpp | 3 +- src/vk/view_2d.hpp | 2 + test/src/main.rb | 6 +- 35 files changed, 1948 insertions(+), 824 deletions(-) create mode 100644 glsl/shader_2d_wired.frag.glsl create mode 100644 glsl/shader_2d_wired.vert.glsl delete mode 100644 src/vk/graphics_pipeline_2d.cpp delete mode 100644 src/vk/graphics_pipeline_2d.hpp delete mode 100644 src/vk/graphics_pipeline_2d_layout.cpp delete mode 100644 src/vk/graphics_pipeline_2d_layout.hpp create mode 100644 src/vk/graphics_pipeline_2d_solid.cpp create mode 100644 src/vk/graphics_pipeline_2d_solid.hpp create mode 100644 src/vk/graphics_pipeline_2d_solid_layout.cpp create mode 100644 src/vk/graphics_pipeline_2d_solid_layout.hpp create mode 100644 src/vk/graphics_pipeline_2d_wired.cpp create mode 100644 src/vk/graphics_pipeline_2d_wired.hpp create mode 100644 src/vk/graphics_pipeline_2d_wired_layout.cpp create mode 100644 src/vk/graphics_pipeline_2d_wired_layout.hpp create mode 100644 src/vk/rectangle.cpp create mode 100644 src/vk/rectangle.hpp diff --git a/glsl/shader_2d_wired.frag.glsl b/glsl/shader_2d_wired.frag.glsl new file mode 100644 index 0000000..0671223 --- /dev/null +++ b/glsl/shader_2d_wired.frag.glsl @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#version 450 + +layout(location = 0) out vec4 out_color; + +layout(set = 1, binding = 0) uniform UBOModel2D +{ + vec3 color; +} ubo_model_2d; + +void +main() +{ + out_color = vec4(ubo_model_2d.color, 1.0); +} diff --git a/glsl/shader_2d_wired.vert.glsl b/glsl/shader_2d_wired.vert.glsl new file mode 100644 index 0000000..97330dc --- /dev/null +++ b/glsl/shader_2d_wired.vert.glsl @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#version 450 + +layout(location = 0) in vec2 in_position; + +layout(set = 0, binding = 0) uniform UBOView2D +{ + mat4 proj; +} ubo_view; + +void +main() +{ + gl_Position = ubo_view.proj * vec4(in_position, 0.0, 1.0); +} diff --git a/src/core.cpp b/src/core.cpp index f3f0e14..ae8db70 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -540,12 +540,12 @@ unload_vk_graphics_pipeline_3d_layout(void *obj) } void -load_vk_graphics_pipeline_2d_layout(void *obj) +load_vk_graphics_pipeline_2d_solid_layout(void *obj) { try { - cg_core.vk_graphics_pipeline_2d_layout = - new VK::GraphicsPipeline2DLayout(); + cg_core.vk_graphics_pipeline_2d_solid_layout = + new VK::GraphicsPipeline2DSolidLayout(); } catch(const CommandError &e) { @@ -554,9 +554,29 @@ load_vk_graphics_pipeline_2d_layout(void *obj) } void -unload_vk_graphics_pipeline_2d_layout(void *obj) +unload_vk_graphics_pipeline_2d_solid_layout(void *obj) { - delete cg_core.vk_graphics_pipeline_2d_layout; + delete cg_core.vk_graphics_pipeline_2d_solid_layout; +} + +void +load_vk_graphics_pipeline_2d_wired_layout(void *obj) +{ + try + { + cg_core.vk_graphics_pipeline_2d_wired_layout = + new VK::GraphicsPipeline2DWiredLayout(); + } + catch(const CommandError &e) + { + throw CommandError{"Failed to create 2d graphics pipeline."}; + } +} + +void +unload_vk_graphics_pipeline_2d_wired_layout(void *obj) +{ + delete cg_core.vk_graphics_pipeline_2d_wired_layout; } void @@ -580,12 +600,32 @@ unload_vk_graphics_pipeline_3d(void *obj) } void -load_vk_graphics_pipeline_2d(void *obj) +load_vk_graphics_pipeline_2d_solid(void *obj) +{ + try + { + cg_core.vk_graphics_pipeline_2d_solid = + std::make_unique(); + } + catch(const CommandError &e) + { + throw CommandError{"Failed to create 2d graphics pipeline."}; + } +} + +void +unload_vk_graphics_pipeline_2d_solid(void *obj) +{ + cg_core.vk_graphics_pipeline_2d_solid = nullptr; +} + +void +load_vk_graphics_pipeline_2d_wired(void *obj) { try { - cg_core.vk_graphics_pipeline_2d = - std::make_unique(); + cg_core.vk_graphics_pipeline_2d_wired = + std::make_unique(); } catch(const CommandError &e) { @@ -594,9 +634,9 @@ load_vk_graphics_pipeline_2d(void *obj) } void -unload_vk_graphics_pipeline_2d(void *obj) +unload_vk_graphics_pipeline_2d_wired(void *obj) { - cg_core.vk_graphics_pipeline_2d = nullptr; + cg_core.vk_graphics_pipeline_2d_wired = nullptr; } void @@ -672,10 +712,13 @@ const CommandChain cg_sCore::loader{ {&load_vk_graphics_pipeline_3d_layout, &unload_vk_graphics_pipeline_3d_layout}, - {&load_vk_graphics_pipeline_2d_layout, - &unload_vk_graphics_pipeline_2d_layout}, + {&load_vk_graphics_pipeline_2d_solid_layout, + &unload_vk_graphics_pipeline_2d_solid_layout}, + {&load_vk_graphics_pipeline_2d_wired_layout, + &unload_vk_graphics_pipeline_2d_wired_layout}, {&load_vk_graphics_pipeline_3d, &unload_vk_graphics_pipeline_3d}, - {&load_vk_graphics_pipeline_2d, &unload_vk_graphics_pipeline_2d}, + {&load_vk_graphics_pipeline_2d_solid, &unload_vk_graphics_pipeline_2d_solid}, + {&load_vk_graphics_pipeline_2d_wired, &unload_vk_graphics_pipeline_2d_wired}, {&load_vk_renderer, &unload_vk_renderer}, {&load_mruby_interface, nullptr} diff --git a/src/core.hpp b/src/core.hpp index 0830a49..5d92cfa 100644 --- a/src/core.hpp +++ b/src/core.hpp @@ -46,10 +46,12 @@ #include "worker.hpp" #include "vk/device.hpp" +#include "vk/graphics_pipeline_2d_solid_layout.hpp" +#include "vk/graphics_pipeline_2d_wired_layout.hpp" +#include "vk/graphics_pipeline_2d_solid.hpp" +#include "vk/graphics_pipeline_2d_wired.hpp" #include "vk/graphics_pipeline_3d_layout.hpp" -#include "vk/graphics_pipeline_2d_layout.hpp" #include "vk/graphics_pipeline_3d.hpp" -#include "vk/graphics_pipeline_2d.hpp" #include "vk/renderer.hpp" #include "vk/swapchain.hpp" @@ -110,9 +112,11 @@ struct cg_sCore VK::Swapchain *vk_swapchain; VK::GraphicsPipeline3DLayout *vk_graphics_pipeline_3d_layout; - VK::GraphicsPipeline2DLayout *vk_graphics_pipeline_2d_layout; + VK::GraphicsPipeline2DSolidLayout *vk_graphics_pipeline_2d_solid_layout; + VK::GraphicsPipeline2DWiredLayout *vk_graphics_pipeline_2d_wired_layout; std::unique_ptr vk_graphics_pipeline_3d; - std::unique_ptr vk_graphics_pipeline_2d; + std::unique_ptr vk_graphics_pipeline_2d_solid; + std::unique_ptr vk_graphics_pipeline_2d_wired; VK::Renderer *vk_renderer; diff --git a/src/rectangle.cpp b/src/rectangle.cpp index 3bc0a84..18c86a4 100644 --- a/src/rectangle.cpp +++ b/src/rectangle.cpp @@ -16,28 +16,16 @@ #include "rectangle.hpp" -namespace -{ - -constexpr bool -align_vertically(float a_x, float a_width, float b_x, float b_width) -{ - return a_x <= b_x + b_width && a_x + a_width >= b_x; -} - -constexpr bool -align_horizontally(float a_y, float a_height, float b_y, float b_height) -{ - return a_y <= b_y + b_height && a_y + a_height >= b_y; -} - -} +#include "vector_3d.hpp" +#include "view_2d.hpp" +#include "view_3d.hpp" void cg_free_rectangle(mrb_state *mrb, void* obj) { - auto ptr = static_cast(obj); + auto ptr = static_cast*>(obj); + ptr->~shared_ptr(); mrb_free(mrb, ptr); } @@ -48,17 +36,16 @@ static mrb_value cg_cRectangle_initialize(mrb_state *mrb, mrb_value self) { mrb_float x, y, width, height; - struct cg_rectangle *ptr; + std::shared_ptr *ptr; mrb_get_args(mrb, "ffff", &x, &y, &width, &height); - ptr = (cg_rectangle *)DATA_PTR(self); + ptr = (std::shared_ptr*)DATA_PTR(self); if(ptr) mrb_free(mrb, ptr); - ptr = (cg_rectangle *)mrb_malloc(mrb, sizeof(cg_rectangle)); + ptr = (std::shared_ptr*)mrb_malloc( + mrb, sizeof(std::shared_ptr)); - ptr->x = x; - ptr->y = y; - ptr->width = width; - ptr->height = height; + new(ptr)std::shared_ptr( + std::make_shared(x, y, width, height)); mrb_data_init(self, ptr, &cg_rectangle_type); return self; @@ -67,122 +54,141 @@ cg_cRectangle_initialize(mrb_state *mrb, mrb_value self) static mrb_value cg_cRectangle_get_x(mrb_state *mrb, mrb_value self) { - auto ptr = (cg_rectangle *)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); - return mrb_float_value(mrb, ptr->x); + return mrb_float_value(mrb, (*ptr)->x); } static mrb_value cg_cRectangle_set_x(mrb_state *mrb, mrb_value self) { mrb_float x; - auto ptr = (cg_rectangle *)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); mrb_get_args(mrb, "f", &x); - ptr->x = x; + (*ptr)->x = x; - return mrb_float_value(mrb, ptr->x); + return mrb_float_value(mrb, (*ptr)->x); } static mrb_value cg_cRectangle_get_y(mrb_state *mrb, mrb_value self) { - auto ptr = (cg_rectangle *)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); - return mrb_float_value(mrb, ptr->y); + return mrb_float_value(mrb, (*ptr)->y); } static mrb_value cg_cRectangle_set_y(mrb_state *mrb, mrb_value self) { mrb_float y; - auto *ptr = (cg_rectangle *)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); mrb_get_args(mrb, "f", &y); - ptr->y = y; + (*ptr)->y = y; - return mrb_float_value(mrb, ptr->y); + return mrb_float_value(mrb, (*ptr)->y); } static mrb_value cg_cRectangle_get_width(mrb_state *mrb, mrb_value self) { - auto *ptr = (cg_rectangle *)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); - return mrb_float_value(mrb, ptr->width); + return mrb_float_value(mrb, (*ptr)->width); } static mrb_value cg_cRectangle_set_width(mrb_state *mrb, mrb_value self) { mrb_float width; - auto *ptr = (struct cg_rectangle *)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); mrb_get_args(mrb, "f", &width); - ptr->width = width; + (*ptr)->width = width; - return mrb_float_value(mrb, ptr->width); + return mrb_float_value(mrb, (*ptr)->width); } static mrb_value cg_cRectangle_get_height(mrb_state *mrb, mrb_value self) { - auto *ptr = (struct cg_rectangle *)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); - return mrb_float_value(mrb, ptr->height); + return mrb_float_value(mrb, (*ptr)->height); } static mrb_value cg_cRectangle_set_height(mrb_state *mrb, mrb_value self) { mrb_float height; - auto *ptr = (cg_rectangle *)DATA_PTR(self); + auto ptr = (std::shared_ptr*)DATA_PTR(self); mrb_get_args(mrb, "f", &height); - ptr->height = height; + (*ptr)->height = height; - return mrb_float_value(mrb, ptr->height); + return mrb_float_value(mrb, (*ptr)->height); } static mrb_value cg_cRectangle_align_vertically(mrb_state *mrb, mrb_value self) { - cg_rectangle *ptr, *that; + std::shared_ptr *ptr, *that; mrb_get_args(mrb, "d", &that, &cg_rectangle_type); - ptr = (cg_rectangle *)DATA_PTR(self); + ptr = (std::shared_ptr*)DATA_PTR(self); - return mrb_bool_value( - align_vertically(ptr->x, ptr->width, that->x, that->width)); + return mrb_bool_value((*ptr)->align_vertically(**that)); } static mrb_value cg_cRectangle_align_horizontally(mrb_state *mrb, mrb_value self) { - cg_rectangle *ptr, *that; + std::shared_ptr *ptr, *that; mrb_get_args(mrb, "d", &that, &cg_rectangle_type); - ptr = (cg_rectangle *)DATA_PTR(self); + ptr = (std::shared_ptr*)DATA_PTR(self); - return mrb_bool_value( - align_horizontally(ptr->y, ptr->height, that->y, that->height)); + return mrb_bool_value((*ptr)->align_horizontally(**that)); } static mrb_value cg_cRectangle_collide(mrb_state *mrb, mrb_value self) { - cg_rectangle *ptr, *that; + std::shared_ptr *ptr, *that; mrb_get_args(mrb, "d", &that, &cg_rectangle_type); - ptr = (cg_rectangle *)DATA_PTR(self); + ptr = (std::shared_ptr*)DATA_PTR(self); - return mrb_bool_value( - align_vertically(ptr->x, ptr->width, that->x, that->width) && - align_horizontally(ptr->y, ptr->height, that->y, that->height)); + return mrb_bool_value((*ptr)->collide(**that)); +} + +static mrb_value +cg_cRectangle_draw(mrb_state *mrb, mrb_value self) +{ + mrb_value view_value; + VK::View2D *view_2d; + std::shared_ptr *color; + auto ptr = (std::shared_ptr*)DATA_PTR(self); + + mrb_get_args(mrb, "od", &view_value, &color, &cg_vector_3d_type); + + view_2d = cg_cView_to_view_2d(mrb, view_value); + + VK::UBOModel2D model; + model.color = **color; + (*ptr)->ub_rectangle[cg_core.vk_swapchain->current_frame].copy_data(&model); + (*ptr)->update_vertex_buffer(); + auto &rectangles = view_2d->rectangles_to_draw[ + cg_core.vk_swapchain->current_frame]; + rectangles.push_back(*ptr); + + return self; } void @@ -221,4 +227,6 @@ cg_rectangle_init(mrb_state *mrb) cg_cRectangle_align_horizontally, MRB_ARGS_REQ(1)); mrb_define_method( mrb, cg_cRectangle, "collide?", cg_cRectangle_collide, MRB_ARGS_REQ(1)); + mrb_define_method( + mrb, cg_cRectangle, "draw", cg_cRectangle_draw, MRB_ARGS_REQ(2)); } diff --git a/src/rectangle.hpp b/src/rectangle.hpp index e89b6ba..8ed1748 100644 --- a/src/rectangle.hpp +++ b/src/rectangle.hpp @@ -18,11 +18,7 @@ #define CANDY_GEAR_RECTANGLE_H 1 #include "core.hpp" - -struct cg_rectangle -{ - float x, y, width, height; -}; +#include "vk/rectangle.hpp" extern const struct mrb_data_type cg_rectangle_type; diff --git a/src/sprite.cpp b/src/sprite.cpp index 5f815f6..fa5e22f 100644 --- a/src/sprite.cpp +++ b/src/sprite.cpp @@ -18,6 +18,7 @@ #include "texture.hpp" #include "vector_4d.hpp" +#include "view_2d.hpp" #include "vk/sprite.hpp" void @@ -52,6 +53,25 @@ cg_cSprite_initialize(mrb_state *mrb, mrb_value self) return self; } +static mrb_value +cg_cSprite_draw(mrb_state *mrb, mrb_value self) +{ + mrb_value view_value; + VK::View2D *view_2d; + std::shared_ptr *position; + auto ptr = (std::shared_ptr*)DATA_PTR(self); + + mrb_get_args(mrb, "od", &view_value, &position, &cg_vector_4d_type); + + view_2d = cg_cView_to_view_2d(mrb, view_value); + + auto &positions = view_2d->sprites_to_draw[ + cg_core.vk_swapchain->current_frame][*ptr]; + positions.push_back(*position->get()); + + return self; +} + void cg_sprite_init(mrb_state *mrb) { @@ -62,4 +82,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(2)); } diff --git a/src/view_2d.cpp b/src/view_2d.cpp index c84cbee..3f4325d 100644 --- a/src/view_2d.cpp +++ b/src/view_2d.cpp @@ -18,6 +18,7 @@ #include "sprite.hpp" #include "vector_4d.hpp" +#include "view_3d.hpp" #include "vk/sprite.hpp" #include "vk/view_2d.hpp" @@ -51,20 +52,26 @@ cg_cView2D_initialize(mrb_state *mrb, mrb_value self) return self; } -static mrb_value -cg_cView2D_draw(mrb_state *mrb, mrb_value self) +VK::View2D* +cg_cView_to_view_2d(mrb_state *mrb, mrb_value view_value) { - std::shared_ptr *sprite; - std::shared_ptr *position; - auto *ptr = (std::shared_ptr*)DATA_PTR(self); + VK::View2D* view_2d; + const mrb_data_type *type = DATA_TYPE(view_value); - mrb_get_args(mrb, "dd", &sprite, &cg_sprite_type, - &position, &cg_vector_4d_type); - auto &positions = (*ptr)->sprites_to_draw[ - cg_core.vk_swapchain->current_frame][*sprite]; - positions.push_back(*position->get()); + if(type == &cg_view_2d_type) + view_2d = static_cast*>( + DATA_PTR(view_value))->get(); + else if (type == &cg_view_3d_type) + view_2d = static_cast( + static_cast*>( + DATA_PTR(view_value))->get()); + else + mrb_raisef( + mrb, E_TYPE_ERROR, "wrong argument type %s (expected %s or %s)", + type->struct_name, cg_view_2d_type.struct_name, + cg_view_3d_type.struct_name); - return self; + return view_2d; } void @@ -77,5 +84,4 @@ cg_view_2d_init(mrb_state *mrb) MRB_SET_INSTANCE_TT(cg_cView2D, MRB_TT_DATA); mrb_define_method( mrb, cg_cView2D, "initialize", cg_cView2D_initialize, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, cg_cView2D, "draw", cg_cView2D_draw, MRB_ARGS_REQ(2)); } diff --git a/src/view_2d.hpp b/src/view_2d.hpp index 0b33380..c2b1701 100644 --- a/src/view_2d.hpp +++ b/src/view_2d.hpp @@ -21,6 +21,12 @@ extern const struct mrb_data_type cg_view_2d_type; +// Receives a mrb_value that points to a View2D or a View3D and returns a +// pointer to View2D. If the mrb_value points to a View3D, the view will be +// cast to a VK::View2D. +VK::View2D* +cg_cView_to_view_2d(mrb_state *mrb, mrb_value view_value); + void cg_view_2d_init(mrb_state *mrb); diff --git a/src/view_3d.cpp b/src/view_3d.cpp index 4e8b254..1b733b8 100644 --- a/src/view_3d.cpp +++ b/src/view_3d.cpp @@ -77,22 +77,6 @@ cg_cView3D_set_camera_rotation(mrb_state *mrb, mrb_value self) return self; } -static mrb_value -cg_cView3D_draw(mrb_state *mrb, mrb_value self) -{ - std::shared_ptr *sprite; - std::shared_ptr *position; - auto *ptr = (std::shared_ptr*)DATA_PTR(self); - - mrb_get_args(mrb, "dd", &sprite, &cg_sprite_type, - &position, &cg_vector_4d_type); - auto &positions = (*ptr)->sprites_to_draw[ - cg_core.vk_swapchain->current_frame][*sprite]; - positions.push_back(*position->get()); - - return self; -} - void cg_view_3d_init(mrb_state *mrb) { @@ -109,5 +93,4 @@ cg_view_3d_init(mrb_state *mrb) mrb_define_method( mrb, cg_cView3D, "camera_rotation=", cg_cView3D_set_camera_rotation, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, cg_cView3D, "draw", cg_cView3D_draw, MRB_ARGS_REQ(2)); } diff --git a/src/vk/destination_buffer.cpp b/src/vk/destination_buffer.cpp index 872f8a8..5c55fd2 100644 --- a/src/vk/destination_buffer.cpp +++ b/src/vk/destination_buffer.cpp @@ -34,39 +34,7 @@ DestinationBuffer::DestinationBuffer( BaseBuffer::loader.execute(dynamic_cast(this)); - // Load command - { - CommandPool command_pool(this->queue_family, 1); - Queue transfer_queue{this->queue_family->get_queue()}; - - this->vk_command_buffer = command_pool.command_buffers[0]; - - VkCommandBufferBeginInfo begin_info = {}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - - VkBufferCopy copy_region = {}; - copy_region.srcOffset = 0; - copy_region.dstOffset = 0; - copy_region.size = this->device_size; - - vkBeginCommandBuffer(this->vk_command_buffer, &begin_info); - - vkCmdCopyBuffer( - this->vk_command_buffer, this->source_buffer->buffer, this->buffer, 1, - ©_region); - - vkEndCommandBuffer(this->vk_command_buffer); - - VkSubmitInfo submit_info = {}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &this->vk_command_buffer; - - vkQueueSubmit(transfer_queue.queue, 1, &submit_info, VK_NULL_HANDLE); - - vkQueueWaitIdle(transfer_queue.queue); - } + this->copy_data(); } DestinationBuffer::DestinationBuffer( @@ -102,4 +70,40 @@ DestinationBuffer::~DestinationBuffer() BaseBuffer::loader.revert(dynamic_cast(this)); } +void +DestinationBuffer::copy_data() +{ + CommandPool command_pool(this->queue_family, 1); + Queue transfer_queue{this->queue_family->get_queue()}; + this->device_size = source_buffer->device_size; + + this->vk_command_buffer = command_pool.command_buffers[0]; + + VkCommandBufferBeginInfo begin_info = {}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + VkBufferCopy copy_region = {}; + copy_region.srcOffset = 0; + copy_region.dstOffset = 0; + copy_region.size = this->device_size; + + vkBeginCommandBuffer(this->vk_command_buffer, &begin_info); + + vkCmdCopyBuffer( + this->vk_command_buffer, this->source_buffer->buffer, this->buffer, 1, + ©_region); + + vkEndCommandBuffer(this->vk_command_buffer); + + VkSubmitInfo submit_info = {}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &this->vk_command_buffer; + + vkQueueSubmit(transfer_queue.queue, 1, &submit_info, VK_NULL_HANDLE); + + vkQueueWaitIdle(transfer_queue.queue); +} + } diff --git a/src/vk/destination_buffer.hpp b/src/vk/destination_buffer.hpp index e856f4d..9b42af3 100644 --- a/src/vk/destination_buffer.hpp +++ b/src/vk/destination_buffer.hpp @@ -44,6 +44,9 @@ struct DestinationBuffer: public BaseBuffer operator=(DestinationBuffer &&that); ~DestinationBuffer(); + + void + copy_data(); }; } diff --git a/src/vk/device.cpp b/src/vk/device.cpp index 74727f9..957ae6d 100644 --- a/src/vk/device.cpp +++ b/src/vk/device.cpp @@ -126,6 +126,7 @@ Device::Device(VkPhysicalDevice vk_physical_device, bool with_swapchain) VkPhysicalDeviceFeatures required_features = {}; required_features.multiDrawIndirect = supported_features.multiDrawIndirect; + required_features.fillModeNonSolid = VK_TRUE; required_features.geometryShader = VK_TRUE; required_features.tessellationShader = VK_TRUE; required_features.samplerAnisotropy = VK_TRUE; @@ -165,6 +166,10 @@ Device::Device(VkPhysicalDevice vk_physical_device, bool with_swapchain) this->device, DATA_DIR "/glsl/shader_2d.vert.spv"); this->frag2d_shader_module = create_shader_module( this->device, DATA_DIR "/glsl/shader_2d.frag.spv"); + this->vert2d_wired_shader_module = create_shader_module( + this->device, DATA_DIR "/glsl/shader_2d_wired.vert.spv"); + this->frag2d_wired_shader_module = create_shader_module( + this->device, DATA_DIR "/glsl/shader_2d_wired.frag.spv"); } this->queue_families = static_cast( @@ -202,6 +207,8 @@ Device::~Device() vkDestroyShaderModule(this->device, this->frag3d_shader_module, nullptr); vkDestroyShaderModule(this->device, this->vert2d_shader_module, nullptr); vkDestroyShaderModule(this->device, this->frag2d_shader_module, nullptr); + vkDestroyShaderModule(this->device, this->vert2d_wired_shader_module, nullptr); + vkDestroyShaderModule(this->device, this->frag2d_wired_shader_module, nullptr); vkDeviceWaitIdle(this->device); vkDestroyDevice(this->device, nullptr); diff --git a/src/vk/device.hpp b/src/vk/device.hpp index cc5df82..9f5a776 100644 --- a/src/vk/device.hpp +++ b/src/vk/device.hpp @@ -41,6 +41,8 @@ public: VkShaderModule frag3d_shader_module; VkShaderModule vert2d_shader_module; VkShaderModule frag2d_shader_module; + VkShaderModule vert2d_wired_shader_module; + VkShaderModule frag2d_wired_shader_module; bool with_swapchain; diff --git a/src/vk/graphics_pipeline_2d.cpp b/src/vk/graphics_pipeline_2d.cpp deleted file mode 100644 index 734a509..0000000 --- a/src/vk/graphics_pipeline_2d.cpp +++ /dev/null @@ -1,332 +0,0 @@ -/* - * 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 "graphics_pipeline_2d.hpp" - -#include - -#include "../core.hpp" -#include "sprite.hpp" - -namespace -{ - -void -load_framebuffer(void *obj) -{ - auto self = static_cast(obj); - - self->swapchain_framebuffers.resize(cg_core.vk_swapchain->images_count); - for (auto i{0}; i < cg_core.vk_swapchain->images_count; i++) - { - std::array attachments = { - cg_core.vk_swapchain->image_views[i] - }; - - VkFramebufferCreateInfo framebuffer_info{}; - framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebuffer_info.renderPass = - cg_core.vk_graphics_pipeline_2d_layout->render_pass; - framebuffer_info.attachmentCount = attachments.size(); - framebuffer_info.pAttachments = attachments.data(); - framebuffer_info.width = cg_core.display_width; - framebuffer_info.height = cg_core.display_height; - framebuffer_info.layers = 1; - - if(vkCreateFramebuffer( - cg_core.vk_device_with_swapchain->device, &framebuffer_info, nullptr, - &self->swapchain_framebuffers[i]) - != VK_SUCCESS) - throw CommandError{"Failed to create Vulkan Framebuffer."}; - } -} - -void -unload_framebuffer(void *obj) -{ - auto self = static_cast(obj); - - for(auto framebuffer: self->swapchain_framebuffers) - vkDestroyFramebuffer( - cg_core.vk_device_with_swapchain->device, framebuffer, nullptr); -} - -void -load_pipeline(void *obj) -{ - auto self = static_cast(obj); - - VkPipelineShaderStageCreateInfo vert_shader_stage_info{}; - vert_shader_stage_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - vert_shader_stage_info.pNext = nullptr; - vert_shader_stage_info.flags = 0; - vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; - vert_shader_stage_info.module = - cg_core.vk_device_with_swapchain->vert2d_shader_module; - vert_shader_stage_info.pName = "main"; - vert_shader_stage_info.pSpecializationInfo = nullptr; - - VkPipelineShaderStageCreateInfo frag_shader_stage_info{}; - frag_shader_stage_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - frag_shader_stage_info.pNext = nullptr; - frag_shader_stage_info.flags = 0; - frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; - frag_shader_stage_info.module = - cg_core.vk_device_with_swapchain->frag2d_shader_module; - frag_shader_stage_info.pName = "main"; - frag_shader_stage_info.pSpecializationInfo = nullptr; - - VkPipelineShaderStageCreateInfo shader_stages[] = { - vert_shader_stage_info, - frag_shader_stage_info - }; - - VkVertexInputBindingDescription vertex_input_binding{}; - vertex_input_binding.binding = 0; - vertex_input_binding.stride = sizeof(glm::vec2); - vertex_input_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - - std::array vertex_attribute{}; - // Texture coordinate. - vertex_attribute[0].location = 0; - vertex_attribute[0].binding = 0; - vertex_attribute[0].format = VK_FORMAT_R32G32_SFLOAT; - vertex_attribute[0].offset = 0; - - VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; - vertex_input_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertex_input_info.pNext = nullptr; - vertex_input_info.flags = 0; - vertex_input_info.vertexBindingDescriptionCount = 1; - vertex_input_info.pVertexBindingDescriptions = &vertex_input_binding; - vertex_input_info.vertexAttributeDescriptionCount = - static_cast(vertex_attribute.size()); - vertex_input_info.pVertexAttributeDescriptions = vertex_attribute.data(); - - VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; - input_assembly.sType = - VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - input_assembly.pNext = nullptr; - input_assembly.flags = 0; - input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; - input_assembly.primitiveRestartEnable = VK_FALSE; - - VkViewport viewport = {}; - viewport.x = 0; - viewport.y = 0; - viewport.width = cg_core.display_width; - viewport.height = cg_core.display_height; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - - VkRect2D scissor = {}; - scissor.offset = {0, 0}; - scissor.extent = {cg_core.display_width, cg_core.display_height}; - - VkPipelineViewportStateCreateInfo viewport_state = {}; - viewport_state.sType = - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewport_state.pNext = nullptr; - viewport_state.flags = 0; - viewport_state.viewportCount = 1; - viewport_state.pViewports = &viewport; - viewport_state.scissorCount = 1; - viewport_state.pScissors = &scissor; - - VkPipelineRasterizationStateCreateInfo rasterizer = {}; - rasterizer.sType = - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizer.pNext = nullptr; - rasterizer.flags = 0; - rasterizer.depthClampEnable = VK_FALSE; - rasterizer.rasterizerDiscardEnable = VK_FALSE; - rasterizer.polygonMode = VK_POLYGON_MODE_FILL; - rasterizer.cullMode = VK_CULL_MODE_NONE; - rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - rasterizer.depthBiasEnable = VK_FALSE; - rasterizer.depthBiasConstantFactor = 0.0f; - rasterizer.depthBiasClamp = 0.0f; - rasterizer.depthBiasSlopeFactor = 0.0f; - rasterizer.lineWidth = 1.0f; - - VkPipelineMultisampleStateCreateInfo multisampling = {}; - multisampling.sType = - VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - multisampling.sampleShadingEnable = VK_FALSE; - multisampling.minSampleShading = 1.0f; - multisampling.pSampleMask = nullptr; - multisampling.alphaToCoverageEnable = VK_FALSE; - multisampling.alphaToOneEnable = VK_FALSE; - - VkPipelineColorBlendAttachmentState color_blend_attachment = {}; - color_blend_attachment.blendEnable = VK_FALSE; - color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; - color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; - color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment.colorWriteMask = - VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | - VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - - VkPipelineColorBlendStateCreateInfo color_blending = {}; - color_blending.sType = - VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - color_blending.pNext = nullptr; - color_blending.flags = 0; - color_blending.logicOpEnable = VK_FALSE; - color_blending.logicOp = VK_LOGIC_OP_COPY; - color_blending.attachmentCount = 1; - color_blending.pAttachments = &color_blend_attachment; - color_blending.blendConstants[0] = 0.0f; - color_blending.blendConstants[1] = 0.0f; - color_blending.blendConstants[2] = 0.0f; - color_blending.blendConstants[3] = 0.0f; - - VkDynamicState dynamic_states[] = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_LINE_WIDTH - }; - - VkPipelineDynamicStateCreateInfo dynamic_state_info = {}; - dynamic_state_info.sType = - VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamic_state_info.dynamicStateCount = 2; - dynamic_state_info.pDynamicStates = dynamic_states; - - VkGraphicsPipelineCreateInfo pipeline_info{}; - pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipeline_info.pNext = nullptr; - pipeline_info.flags = 0; - pipeline_info.stageCount = 2; - pipeline_info.pStages = shader_stages; - pipeline_info.pVertexInputState = &vertex_input_info; - pipeline_info.pInputAssemblyState = &input_assembly; - pipeline_info.pTessellationState = nullptr; - pipeline_info.pViewportState = &viewport_state; - pipeline_info.pRasterizationState = &rasterizer; - pipeline_info.pMultisampleState = &multisampling; - pipeline_info.pDepthStencilState = nullptr; - pipeline_info.pColorBlendState = &color_blending; - pipeline_info.pDynamicState = &dynamic_state_info; - pipeline_info.layout = cg_core.vk_graphics_pipeline_2d_layout->pipeline; - pipeline_info.renderPass = - cg_core.vk_graphics_pipeline_2d_layout->render_pass; - pipeline_info.subpass = 0; - pipeline_info.basePipelineHandle = VK_NULL_HANDLE; - pipeline_info.basePipelineIndex = -1; - - if(vkCreateGraphicsPipelines( - cg_core.vk_device_with_swapchain->device, VK_NULL_HANDLE, 1, - &pipeline_info, nullptr, &self->graphic_pipeline) - != VK_SUCCESS) - throw CommandError{"Failed to create graphics pipeline."}; -} - -void -unload_pipeline(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyPipeline( - cg_core.vk_device_with_swapchain->device, self->graphic_pipeline, nullptr); -} - -const CommandChain loader{ - {&load_framebuffer, &unload_framebuffer}, - {&load_pipeline, &unload_pipeline} -}; - -} - -namespace VK -{ - -GraphicsPipeline2D::GraphicsPipeline2D() -{ - loader.execute(this); -} - -GraphicsPipeline2D::~GraphicsPipeline2D() -{ - loader.revert(this); -} - -void -GraphicsPipeline2D::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) -{ - // Set viewport - { - VkViewport vk_viewport{}; - 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.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]: view->sprites_to_draw[current_frame]) - { - // Commands - { - 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); - } - - // Prepare for the next frame. - view->sprites_to_draw[next_frame].clear(); -} - -} diff --git a/src/vk/graphics_pipeline_2d.hpp b/src/vk/graphics_pipeline_2d.hpp deleted file mode 100644 index ffa373a..0000000 --- a/src/vk/graphics_pipeline_2d.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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_GRAPHICS_PIPELINE_2D_H -#define CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_H 1 - -#include -#include -#include - -#include "core.hpp" -#include "sprite.hpp" -#include "view_2d.hpp" - -namespace VK -{ - -struct GraphicsPipeline2D -{ - std::vector swapchain_framebuffers; - VkPipeline graphic_pipeline; - - GraphicsPipeline2D(); - ~GraphicsPipeline2D(); - - void - 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); -}; - -} - -#endif /* CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_H */ diff --git a/src/vk/graphics_pipeline_2d_layout.cpp b/src/vk/graphics_pipeline_2d_layout.cpp deleted file mode 100644 index 6840f2c..0000000 --- a/src/vk/graphics_pipeline_2d_layout.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* - * 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 "graphics_pipeline_2d_layout.hpp" - -#include - -#include "../core.hpp" - -namespace -{ - -void -load_descriptor_set_view(void *obj) -{ - auto self = static_cast(obj); - - std::array layout_bindings{}; - - layout_bindings[0].binding = 0; - layout_bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - layout_bindings[0].descriptorCount = 1; - layout_bindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - layout_bindings[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 = static_cast(layout_bindings.size()); - layout_info.pBindings = layout_bindings.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 projection."}; -} - -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_sprite(void *obj) -{ - auto self = static_cast(obj); - - std::array layout_bindings{}; - - layout_bindings[0].binding = 0; - layout_bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - layout_bindings[0].descriptorCount = 1; - layout_bindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - layout_bindings[0].pImmutableSamplers = nullptr; - - layout_bindings[1].binding = 1; - layout_bindings[1].descriptorType = - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - layout_bindings[1].descriptorCount = 1; - layout_bindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - layout_bindings[1].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 = static_cast(layout_bindings.size()); - layout_info.pBindings = layout_bindings.data(); - - if(vkCreateDescriptorSetLayout( - cg_core.vk_device_with_swapchain->device, &layout_info, nullptr, - &self->descriptor_set_sprite) != VK_SUCCESS) - throw CommandError{ - "Failed to create Vulkan descriptor set layout for sprites."}; -} - -void -unload_descriptor_set_sprite(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyDescriptorSetLayout( - cg_core.vk_device_with_swapchain->device, self->descriptor_set_sprite, - nullptr); -} - -void -load_pipeline(void *obj) -{ - auto self = static_cast(obj); - - std::array set_layouts{ - self->descriptor_set_view, self->descriptor_set_sprite - }; - - VkPipelineLayoutCreateInfo pipeline_layout_info{}; - pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipeline_layout_info.setLayoutCount = set_layouts.size(); - pipeline_layout_info.pSetLayouts = set_layouts.data(); - pipeline_layout_info.pushConstantRangeCount = 0; - pipeline_layout_info.pPushConstantRanges = nullptr; - - if(vkCreatePipelineLayout( - cg_core.vk_device_with_swapchain->device, &pipeline_layout_info, - nullptr, &self->pipeline) != VK_SUCCESS) - throw CommandError{"Failed to create Vulkan pipeline layout."}; -} - -void -unload_pipeline(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyPipelineLayout( - cg_core.vk_device_with_swapchain->device, self->pipeline, nullptr); -} - -void -load_render_pass(void *obj) -{ - auto self = static_cast(obj); - - std::array attachments{}; - // Color attachment. - attachments[0].flags = 0; - attachments[0].format = cg_core.vk_swapchain->image_format; - attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; - attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - - VkAttachmentReference color_attachment_ref{}; - color_attachment_ref.attachment = 0; - color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkSubpassDescription subpass{}; - subpass.flags = 0; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.inputAttachmentCount = 0; - subpass.pInputAttachments = nullptr; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &color_attachment_ref; - subpass.pResolveAttachments = nullptr; - subpass.pDepthStencilAttachment = nullptr; - subpass.preserveAttachmentCount = 0; - subpass.pPreserveAttachments = nullptr; - - VkSubpassDependency dependency{}; - dependency.srcSubpass = VK_SUBPASS_EXTERNAL; - dependency.dstSubpass = 0; - dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; - dependency.srcAccessMask = 0; - dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; - dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - - VkRenderPassCreateInfo render_pass_info{}; - render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - render_pass_info.pNext = nullptr; - render_pass_info.flags = 0; - render_pass_info.attachmentCount = attachments.size(); - render_pass_info.pAttachments = attachments.data(); - render_pass_info.subpassCount = 1; - render_pass_info.pSubpasses = &subpass; - render_pass_info.dependencyCount = 1; - render_pass_info.pDependencies = &dependency; - - if(vkCreateRenderPass( - cg_core.vk_device_with_swapchain->device, &render_pass_info, - nullptr, &self->render_pass) != VK_SUCCESS) - throw CommandError{"Failed to create Vulkan Render Pass 2D."}; -} - -static void -unload_render_pass(void *obj) -{ - auto self = static_cast(obj); - - vkDestroyRenderPass( - cg_core.vk_device_with_swapchain->device, self->render_pass, nullptr); -} - -const CommandChain loader{ - {&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} -}; - -} - -namespace VK -{ - -GraphicsPipeline2DLayout::GraphicsPipeline2DLayout() -{ - loader.execute(this); -} - -GraphicsPipeline2DLayout::~GraphicsPipeline2DLayout() -{ - loader.revert(this); -} - -} diff --git a/src/vk/graphics_pipeline_2d_layout.hpp b/src/vk/graphics_pipeline_2d_layout.hpp deleted file mode 100644 index 1e0a794..0000000 --- a/src/vk/graphics_pipeline_2d_layout.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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_GRAPHICS_PIPELINE_2D_LAYOUT_H -#define CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_LAYOUT_H 1 - -#include "core.hpp" - -namespace VK -{ - -struct UBOView2D -{ - glm::mat4 proj; -}; - -struct UBOSpritePositions -{ - glm::vec4 positions[128]; -}; - -struct GraphicsPipeline2DLayout -{ - VkDescriptorSetLayout descriptor_set_view; - VkDescriptorSetLayout descriptor_set_sprite; - VkPipelineLayout pipeline; - VkRenderPass render_pass; - - GraphicsPipeline2DLayout(); - ~GraphicsPipeline2DLayout(); -}; - -} - -#endif /* CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_LAYOUT_H */ diff --git a/src/vk/graphics_pipeline_2d_solid.cpp b/src/vk/graphics_pipeline_2d_solid.cpp new file mode 100644 index 0000000..3906cc7 --- /dev/null +++ b/src/vk/graphics_pipeline_2d_solid.cpp @@ -0,0 +1,333 @@ +/* + * 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 "graphics_pipeline_2d_solid.hpp" + +#include + +#include "../core.hpp" +#include "sprite.hpp" + +namespace +{ + +void +load_framebuffer(void *obj) +{ + auto self = static_cast(obj); + + self->swapchain_framebuffers.resize(cg_core.vk_swapchain->images_count); + for (auto i{0}; i < cg_core.vk_swapchain->images_count; i++) + { + std::array attachments = { + cg_core.vk_swapchain->image_views[i] + }; + + VkFramebufferCreateInfo framebuffer_info{}; + framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebuffer_info.renderPass = + cg_core.vk_graphics_pipeline_2d_solid_layout->render_pass; + framebuffer_info.attachmentCount = attachments.size(); + framebuffer_info.pAttachments = attachments.data(); + framebuffer_info.width = cg_core.display_width; + framebuffer_info.height = cg_core.display_height; + framebuffer_info.layers = 1; + + if(vkCreateFramebuffer( + cg_core.vk_device_with_swapchain->device, &framebuffer_info, nullptr, + &self->swapchain_framebuffers[i]) + != VK_SUCCESS) + throw CommandError{"Failed to create Vulkan Framebuffer."}; + } +} + +void +unload_framebuffer(void *obj) +{ + auto self = static_cast(obj); + + for(auto framebuffer: self->swapchain_framebuffers) + vkDestroyFramebuffer( + cg_core.vk_device_with_swapchain->device, framebuffer, nullptr); +} + +void +load_pipeline(void *obj) +{ + auto self = static_cast(obj); + + VkPipelineShaderStageCreateInfo vert_shader_stage_info{}; + vert_shader_stage_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vert_shader_stage_info.pNext = nullptr; + vert_shader_stage_info.flags = 0; + vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; + vert_shader_stage_info.module = + cg_core.vk_device_with_swapchain->vert2d_shader_module; + vert_shader_stage_info.pName = "main"; + vert_shader_stage_info.pSpecializationInfo = nullptr; + + VkPipelineShaderStageCreateInfo frag_shader_stage_info{}; + frag_shader_stage_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + frag_shader_stage_info.pNext = nullptr; + frag_shader_stage_info.flags = 0; + frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + frag_shader_stage_info.module = + cg_core.vk_device_with_swapchain->frag2d_shader_module; + frag_shader_stage_info.pName = "main"; + frag_shader_stage_info.pSpecializationInfo = nullptr; + + VkPipelineShaderStageCreateInfo shader_stages[] = { + vert_shader_stage_info, + frag_shader_stage_info + }; + + VkVertexInputBindingDescription vertex_input_binding{}; + vertex_input_binding.binding = 0; + vertex_input_binding.stride = sizeof(glm::vec2); + vertex_input_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + std::array vertex_attribute{}; + // Texture coordinate. + vertex_attribute[0].location = 0; + vertex_attribute[0].binding = 0; + vertex_attribute[0].format = VK_FORMAT_R32G32_SFLOAT; + vertex_attribute[0].offset = 0; + + VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; + vertex_input_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertex_input_info.pNext = nullptr; + vertex_input_info.flags = 0; + vertex_input_info.vertexBindingDescriptionCount = 1; + vertex_input_info.pVertexBindingDescriptions = &vertex_input_binding; + vertex_input_info.vertexAttributeDescriptionCount = + static_cast(vertex_attribute.size()); + vertex_input_info.pVertexAttributeDescriptions = vertex_attribute.data(); + + VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; + input_assembly.sType = + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + input_assembly.pNext = nullptr; + input_assembly.flags = 0; + input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + input_assembly.primitiveRestartEnable = VK_FALSE; + + VkViewport viewport = {}; + viewport.x = 0; + viewport.y = 0; + viewport.width = cg_core.display_width; + viewport.height = cg_core.display_height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor = {}; + scissor.offset = {0, 0}; + scissor.extent = {cg_core.display_width, cg_core.display_height}; + + VkPipelineViewportStateCreateInfo viewport_state = {}; + viewport_state.sType = + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewport_state.pNext = nullptr; + viewport_state.flags = 0; + viewport_state.viewportCount = 1; + viewport_state.pViewports = &viewport; + viewport_state.scissorCount = 1; + viewport_state.pScissors = &scissor; + + VkPipelineRasterizationStateCreateInfo rasterizer = {}; + rasterizer.sType = + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.pNext = nullptr; + rasterizer.flags = 0; + rasterizer.depthClampEnable = VK_FALSE; + rasterizer.rasterizerDiscardEnable = VK_FALSE; + rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + rasterizer.cullMode = VK_CULL_MODE_NONE; + rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizer.depthBiasEnable = VK_FALSE; + rasterizer.depthBiasConstantFactor = 0.0f; + rasterizer.depthBiasClamp = 0.0f; + rasterizer.depthBiasSlopeFactor = 0.0f; + rasterizer.lineWidth = 1.0f; + + VkPipelineMultisampleStateCreateInfo multisampling = {}; + multisampling.sType = + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisampling.sampleShadingEnable = VK_FALSE; + multisampling.minSampleShading = 1.0f; + multisampling.pSampleMask = nullptr; + multisampling.alphaToCoverageEnable = VK_FALSE; + multisampling.alphaToOneEnable = VK_FALSE; + + VkPipelineColorBlendAttachmentState color_blend_attachment = {}; + color_blend_attachment.blendEnable = VK_FALSE; + color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; + color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment.colorWriteMask = + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + VkPipelineColorBlendStateCreateInfo color_blending = {}; + color_blending.sType = + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + color_blending.pNext = nullptr; + color_blending.flags = 0; + color_blending.logicOpEnable = VK_FALSE; + color_blending.logicOp = VK_LOGIC_OP_COPY; + color_blending.attachmentCount = 1; + color_blending.pAttachments = &color_blend_attachment; + color_blending.blendConstants[0] = 0.0f; + color_blending.blendConstants[1] = 0.0f; + color_blending.blendConstants[2] = 0.0f; + color_blending.blendConstants[3] = 0.0f; + + VkDynamicState dynamic_states[] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_LINE_WIDTH + }; + + VkPipelineDynamicStateCreateInfo dynamic_state_info = {}; + dynamic_state_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic_state_info.dynamicStateCount = 2; + dynamic_state_info.pDynamicStates = dynamic_states; + + VkGraphicsPipelineCreateInfo pipeline_info{}; + pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipeline_info.pNext = nullptr; + pipeline_info.flags = 0; + pipeline_info.stageCount = 2; + pipeline_info.pStages = shader_stages; + pipeline_info.pVertexInputState = &vertex_input_info; + pipeline_info.pInputAssemblyState = &input_assembly; + pipeline_info.pTessellationState = nullptr; + pipeline_info.pViewportState = &viewport_state; + pipeline_info.pRasterizationState = &rasterizer; + pipeline_info.pMultisampleState = &multisampling; + pipeline_info.pDepthStencilState = nullptr; + pipeline_info.pColorBlendState = &color_blending; + pipeline_info.pDynamicState = &dynamic_state_info; + pipeline_info.layout = + cg_core.vk_graphics_pipeline_2d_solid_layout->pipeline; + pipeline_info.renderPass = + cg_core.vk_graphics_pipeline_2d_solid_layout->render_pass; + pipeline_info.subpass = 0; + pipeline_info.basePipelineHandle = VK_NULL_HANDLE; + pipeline_info.basePipelineIndex = -1; + + if(vkCreateGraphicsPipelines( + cg_core.vk_device_with_swapchain->device, VK_NULL_HANDLE, 1, + &pipeline_info, nullptr, &self->graphic_pipeline) + != VK_SUCCESS) + throw CommandError{"Failed to create graphics pipeline."}; +} + +void +unload_pipeline(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyPipeline( + cg_core.vk_device_with_swapchain->device, self->graphic_pipeline, nullptr); +} + +const CommandChain loader{ + {&load_framebuffer, &unload_framebuffer}, + {&load_pipeline, &unload_pipeline} +}; + +} + +namespace VK +{ + +GraphicsPipeline2DSolid::GraphicsPipeline2DSolid() +{ + loader.execute(this); +} + +GraphicsPipeline2DSolid::~GraphicsPipeline2DSolid() +{ + loader.revert(this); +} + +void +GraphicsPipeline2DSolid::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) +{ + // Set viewport + { + VkViewport vk_viewport{}; + 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.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]: view->sprites_to_draw[current_frame]) + { + // Commands + { + 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_solid_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); + } + + // Prepare for the next frame. + view->sprites_to_draw[next_frame].clear(); +} + +} diff --git a/src/vk/graphics_pipeline_2d_solid.hpp b/src/vk/graphics_pipeline_2d_solid.hpp new file mode 100644 index 0000000..ec3c744 --- /dev/null +++ b/src/vk/graphics_pipeline_2d_solid.hpp @@ -0,0 +1,47 @@ +/* + * 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_GRAPHICS_PIPELINE_2D_SOLID_H +#define CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_SOLID_H 1 + +#include +#include +#include + +#include "core.hpp" +#include "sprite.hpp" +#include "view_2d.hpp" + +namespace VK +{ + +struct GraphicsPipeline2DSolid +{ + std::vector swapchain_framebuffers; + VkPipeline graphic_pipeline; + + GraphicsPipeline2DSolid(); + ~GraphicsPipeline2DSolid(); + + void + 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); +}; + +} + +#endif /* CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_SOLID_H */ diff --git a/src/vk/graphics_pipeline_2d_solid_layout.cpp b/src/vk/graphics_pipeline_2d_solid_layout.cpp new file mode 100644 index 0000000..6f0da0e --- /dev/null +++ b/src/vk/graphics_pipeline_2d_solid_layout.cpp @@ -0,0 +1,231 @@ +/* + * 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 "graphics_pipeline_2d_solid_layout.hpp" + +#include + +#include "../core.hpp" + +namespace +{ + +void +load_descriptor_set_view(void *obj) +{ + auto self = static_cast(obj); + + std::array layout_bindings{}; + + layout_bindings[0].binding = 0; + layout_bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + layout_bindings[0].descriptorCount = 1; + layout_bindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + layout_bindings[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 = static_cast(layout_bindings.size()); + layout_info.pBindings = layout_bindings.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 projection."}; +} + +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_sprite(void *obj) +{ + auto self = static_cast(obj); + + std::array layout_bindings{}; + + layout_bindings[0].binding = 0; + layout_bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + layout_bindings[0].descriptorCount = 1; + layout_bindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + layout_bindings[0].pImmutableSamplers = nullptr; + + layout_bindings[1].binding = 1; + layout_bindings[1].descriptorType = + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + layout_bindings[1].descriptorCount = 1; + layout_bindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + layout_bindings[1].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 = static_cast(layout_bindings.size()); + layout_info.pBindings = layout_bindings.data(); + + if(vkCreateDescriptorSetLayout( + cg_core.vk_device_with_swapchain->device, &layout_info, nullptr, + &self->descriptor_set_sprite) != VK_SUCCESS) + throw CommandError{ + "Failed to create Vulkan descriptor set layout for sprites."}; +} + +void +unload_descriptor_set_sprite(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyDescriptorSetLayout( + cg_core.vk_device_with_swapchain->device, self->descriptor_set_sprite, + nullptr); +} + +void +load_pipeline(void *obj) +{ + auto self = static_cast(obj); + + std::array set_layouts{ + self->descriptor_set_view, self->descriptor_set_sprite + }; + + VkPipelineLayoutCreateInfo pipeline_layout_info{}; + pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipeline_layout_info.setLayoutCount = set_layouts.size(); + pipeline_layout_info.pSetLayouts = set_layouts.data(); + pipeline_layout_info.pushConstantRangeCount = 0; + pipeline_layout_info.pPushConstantRanges = nullptr; + + if(vkCreatePipelineLayout( + cg_core.vk_device_with_swapchain->device, &pipeline_layout_info, + nullptr, &self->pipeline) != VK_SUCCESS) + throw CommandError{"Failed to create Vulkan pipeline layout."}; +} + +void +unload_pipeline(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyPipelineLayout( + cg_core.vk_device_with_swapchain->device, self->pipeline, nullptr); +} + +void +load_render_pass(void *obj) +{ + auto self = static_cast(obj); + + std::array attachments{}; + // Color attachment. + attachments[0].flags = 0; + attachments[0].format = cg_core.vk_swapchain->image_format; + attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; + attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkAttachmentReference color_attachment_ref{}; + color_attachment_ref.attachment = 0; + color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass{}; + subpass.flags = 0; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.inputAttachmentCount = 0; + subpass.pInputAttachments = nullptr; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &color_attachment_ref; + subpass.pResolveAttachments = nullptr; + subpass.pDepthStencilAttachment = nullptr; + subpass.preserveAttachmentCount = 0; + subpass.pPreserveAttachments = nullptr; + + VkSubpassDependency dependency{}; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependency.srcAccessMask = 0; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + + VkRenderPassCreateInfo render_pass_info{}; + render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + render_pass_info.pNext = nullptr; + render_pass_info.flags = 0; + render_pass_info.attachmentCount = attachments.size(); + render_pass_info.pAttachments = attachments.data(); + render_pass_info.subpassCount = 1; + render_pass_info.pSubpasses = &subpass; + render_pass_info.dependencyCount = 1; + render_pass_info.pDependencies = &dependency; + + if(vkCreateRenderPass( + cg_core.vk_device_with_swapchain->device, &render_pass_info, + nullptr, &self->render_pass) != VK_SUCCESS) + throw CommandError{"Failed to create Vulkan Render Pass 2D."}; +} + +static void +unload_render_pass(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyRenderPass( + cg_core.vk_device_with_swapchain->device, self->render_pass, nullptr); +} + +const CommandChain loader{ + {&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} +}; + +} + +namespace VK +{ + +GraphicsPipeline2DSolidLayout::GraphicsPipeline2DSolidLayout() +{ + loader.execute(this); +} + +GraphicsPipeline2DSolidLayout::~GraphicsPipeline2DSolidLayout() +{ + loader.revert(this); +} + +} diff --git a/src/vk/graphics_pipeline_2d_solid_layout.hpp b/src/vk/graphics_pipeline_2d_solid_layout.hpp new file mode 100644 index 0000000..121ddaa --- /dev/null +++ b/src/vk/graphics_pipeline_2d_solid_layout.hpp @@ -0,0 +1,48 @@ +/* + * 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_GRAPHICS_PIPELINE_2D_LAYOUT_H +#define CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_LAYOUT_H 1 + +#include "core.hpp" + +namespace VK +{ + +struct UBOView2D +{ + glm::mat4 proj; +}; + +struct UBOSpritePositions +{ + glm::vec4 positions[128]; +}; + +struct GraphicsPipeline2DSolidLayout +{ + VkDescriptorSetLayout descriptor_set_view; + VkDescriptorSetLayout descriptor_set_sprite; + VkPipelineLayout pipeline; + VkRenderPass render_pass; + + GraphicsPipeline2DSolidLayout(); + ~GraphicsPipeline2DSolidLayout(); +}; + +} + +#endif /* CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_LAYOUT_H */ diff --git a/src/vk/graphics_pipeline_2d_wired.cpp b/src/vk/graphics_pipeline_2d_wired.cpp new file mode 100644 index 0000000..2b416c2 --- /dev/null +++ b/src/vk/graphics_pipeline_2d_wired.cpp @@ -0,0 +1,324 @@ +/* + * 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 "graphics_pipeline_2d_wired.hpp" + +#include + +#include "../core.hpp" +#include "rectangle.hpp" +#include "sprite.hpp" + +namespace +{ + +void +load_framebuffer(void *obj) +{ + auto self = static_cast(obj); + + self->swapchain_framebuffers.resize( + cg_core.vk_swapchain->images_count); + for (auto i{0}; i < cg_core.vk_swapchain->images_count; i++) + { + std::array attachments = { + cg_core.vk_swapchain->image_views[i] + }; + + VkFramebufferCreateInfo framebuffer_info{}; + framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebuffer_info.renderPass = + cg_core.vk_graphics_pipeline_2d_wired_layout->render_pass; + framebuffer_info.attachmentCount = attachments.size(); + framebuffer_info.pAttachments = attachments.data(); + framebuffer_info.width = cg_core.display_width; + framebuffer_info.height = cg_core.display_height; + framebuffer_info.layers = 1; + + if(vkCreateFramebuffer( + cg_core.vk_device_with_swapchain->device, &framebuffer_info, nullptr, + &self->swapchain_framebuffers[i]) != VK_SUCCESS) + throw CommandError{"Failed to create Vulkan Framebuffer."}; + } +} + +void +unload_framebuffer(void *obj) +{ + auto self = static_cast(obj); + + for(auto framebuffer: self->swapchain_framebuffers) + vkDestroyFramebuffer( + cg_core.vk_device_with_swapchain->device, framebuffer, nullptr); +} + +void +load_pipeline(void *obj) +{ + auto self = static_cast(obj); + + VkPipelineShaderStageCreateInfo vert_shader_stage_info{}; + vert_shader_stage_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vert_shader_stage_info.pNext = nullptr; + vert_shader_stage_info.flags = 0; + vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; + vert_shader_stage_info.module = + cg_core.vk_device_with_swapchain->vert2d_wired_shader_module; + vert_shader_stage_info.pName = "main"; + vert_shader_stage_info.pSpecializationInfo = nullptr; + + VkPipelineShaderStageCreateInfo frag_shader_stage_info{}; + frag_shader_stage_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + frag_shader_stage_info.pNext = nullptr; + frag_shader_stage_info.flags = 0; + frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + frag_shader_stage_info.module = + cg_core.vk_device_with_swapchain->frag2d_wired_shader_module; + frag_shader_stage_info.pName = "main"; + frag_shader_stage_info.pSpecializationInfo = nullptr; + + VkPipelineShaderStageCreateInfo shader_stages[] = { + vert_shader_stage_info, + frag_shader_stage_info + }; + + VkVertexInputBindingDescription vertex_input_binding{}; + vertex_input_binding.binding = 0; + vertex_input_binding.stride = sizeof(glm::vec2); + vertex_input_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + std::array vertex_attribute{}; + vertex_attribute[0].location = 0; + vertex_attribute[0].binding = 0; + vertex_attribute[0].format = VK_FORMAT_R32G32_SFLOAT; + vertex_attribute[0].offset = 0; + + VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; + vertex_input_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertex_input_info.pNext = nullptr; + vertex_input_info.flags = 0; + vertex_input_info.vertexBindingDescriptionCount = 1; + vertex_input_info.pVertexBindingDescriptions = &vertex_input_binding; + vertex_input_info.vertexAttributeDescriptionCount = + static_cast(vertex_attribute.size()); + vertex_input_info.pVertexAttributeDescriptions = vertex_attribute.data(); + + VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; + input_assembly.sType = + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + input_assembly.pNext = nullptr; + input_assembly.flags = 0; + input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + input_assembly.primitiveRestartEnable = VK_FALSE; + + VkViewport viewport = {}; + viewport.x = 0; + viewport.y = 0; + viewport.width = cg_core.display_width; + viewport.height = cg_core.display_height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor = {}; + scissor.offset = {0, 0}; + scissor.extent = {cg_core.display_width, cg_core.display_height}; + + VkPipelineViewportStateCreateInfo viewport_state = {}; + viewport_state.sType = + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewport_state.pNext = nullptr; + viewport_state.flags = 0; + viewport_state.viewportCount = 1; + viewport_state.pViewports = &viewport; + viewport_state.scissorCount = 1; + viewport_state.pScissors = &scissor; + + VkPipelineRasterizationStateCreateInfo rasterizer = {}; + rasterizer.sType = + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.pNext = nullptr; + rasterizer.flags = 0; + rasterizer.depthClampEnable = VK_FALSE; + rasterizer.rasterizerDiscardEnable = VK_FALSE; + rasterizer.polygonMode = VK_POLYGON_MODE_LINE; + rasterizer.cullMode = VK_CULL_MODE_NONE; + rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizer.depthBiasEnable = VK_FALSE; + rasterizer.depthBiasConstantFactor = 0.0f; + rasterizer.depthBiasClamp = 0.0f; + rasterizer.depthBiasSlopeFactor = 0.0f; + rasterizer.lineWidth = 1.0f; + + VkPipelineMultisampleStateCreateInfo multisampling = {}; + multisampling.sType = + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisampling.sampleShadingEnable = VK_FALSE; + multisampling.minSampleShading = 1.0f; + multisampling.pSampleMask = nullptr; + multisampling.alphaToCoverageEnable = VK_FALSE; + multisampling.alphaToOneEnable = VK_FALSE; + + VkPipelineColorBlendAttachmentState color_blend_attachment = {}; + color_blend_attachment.blendEnable = VK_FALSE; + color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; + color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment.colorWriteMask = + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + VkPipelineColorBlendStateCreateInfo color_blending = {}; + color_blending.sType = + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + color_blending.pNext = nullptr; + color_blending.flags = 0; + color_blending.logicOpEnable = VK_FALSE; + color_blending.logicOp = VK_LOGIC_OP_COPY; + color_blending.attachmentCount = 1; + color_blending.pAttachments = &color_blend_attachment; + color_blending.blendConstants[0] = 0.0f; + color_blending.blendConstants[1] = 0.0f; + color_blending.blendConstants[2] = 0.0f; + color_blending.blendConstants[3] = 0.0f; + + VkDynamicState dynamic_states[] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_LINE_WIDTH + }; + + VkPipelineDynamicStateCreateInfo dynamic_state_info = {}; + dynamic_state_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic_state_info.dynamicStateCount = 2; + dynamic_state_info.pDynamicStates = dynamic_states; + + VkGraphicsPipelineCreateInfo pipeline_info{}; + pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipeline_info.pNext = nullptr; + pipeline_info.flags = 0; + pipeline_info.stageCount = 2; + pipeline_info.pStages = shader_stages; + pipeline_info.pVertexInputState = &vertex_input_info; + pipeline_info.pInputAssemblyState = &input_assembly; + pipeline_info.pTessellationState = nullptr; + pipeline_info.pViewportState = &viewport_state; + pipeline_info.pRasterizationState = &rasterizer; + pipeline_info.pMultisampleState = &multisampling; + pipeline_info.pDepthStencilState = nullptr; + pipeline_info.pColorBlendState = &color_blending; + pipeline_info.pDynamicState = &dynamic_state_info; + pipeline_info.layout = + cg_core.vk_graphics_pipeline_2d_wired_layout->pipeline; + pipeline_info.renderPass = + cg_core.vk_graphics_pipeline_2d_wired_layout->render_pass; + pipeline_info.subpass = 0; + pipeline_info.basePipelineHandle = VK_NULL_HANDLE; + pipeline_info.basePipelineIndex = -1; + + if(vkCreateGraphicsPipelines( + cg_core.vk_device_with_swapchain->device, VK_NULL_HANDLE, 1, + &pipeline_info, nullptr, &self->graphic_pipeline) != VK_SUCCESS) + throw CommandError{"Failed to create graphics pipeline."}; +} + +void +unload_pipeline(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyPipeline( + cg_core.vk_device_with_swapchain->device, self->graphic_pipeline, nullptr); +} + +const CommandChain loader{ + {&load_framebuffer, &unload_framebuffer}, + {&load_pipeline, &unload_pipeline} +}; + +} + +namespace VK +{ + +GraphicsPipeline2DWired::GraphicsPipeline2DWired() +{ + loader.execute(this); +} + +GraphicsPipeline2DWired::~GraphicsPipeline2DWired() +{ + loader.revert(this); +} + +void +GraphicsPipeline2DWired::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) +{ + // Set viewport + { + VkViewport vk_viewport{}; + 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.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 rectangles + for(auto& rectangle: view->rectangles_to_draw[current_frame]) + { + std::array vk_descriptor_sets{ + view->descriptor_sets_2d[image_index], + rectangle->descriptor_sets[image_index]}; + VkDeviceSize offsets[]{0}; + + vkCmdBindDescriptorSets( + draw_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + cg_core.vk_graphics_pipeline_2d_wired_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, + &rectangle->vertex_buffers[image_index].buffer, offsets); + vkCmdDraw( + draw_command_buffer, Rectangle::vertex_count, 1, 0, 0); + } + + // Prepare for the next frame. + view->rectangles_to_draw[next_frame].clear(); +} + +} diff --git a/src/vk/graphics_pipeline_2d_wired.hpp b/src/vk/graphics_pipeline_2d_wired.hpp new file mode 100644 index 0000000..e6c40de --- /dev/null +++ b/src/vk/graphics_pipeline_2d_wired.hpp @@ -0,0 +1,46 @@ +/* + * 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_GRAPHICS_PIPELINE_2D_WIRED_H +#define CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_WIRED_H 1 + +#include +#include +#include + +#include "core.hpp" +#include "view_2d.hpp" + +namespace VK +{ + +struct GraphicsPipeline2DWired +{ + std::vector swapchain_framebuffers; + VkPipeline graphic_pipeline; + + GraphicsPipeline2DWired(); + ~GraphicsPipeline2DWired(); + + void + 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); +}; + +} + +#endif /* CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_WIRED_H */ diff --git a/src/vk/graphics_pipeline_2d_wired_layout.cpp b/src/vk/graphics_pipeline_2d_wired_layout.cpp new file mode 100644 index 0000000..c523bc7 --- /dev/null +++ b/src/vk/graphics_pipeline_2d_wired_layout.cpp @@ -0,0 +1,225 @@ +/* + * 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 "graphics_pipeline_2d_wired_layout.hpp" + +#include + +#include "../core.hpp" +#include "graphics_pipeline_2d_solid_layout.hpp" + +namespace +{ + +void +load_descriptor_set_view(void *obj) +{ + auto self = static_cast(obj); + + std::array layout_bindings{}; + + layout_bindings[0].binding = 0; + layout_bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + layout_bindings[0].descriptorCount = 1; + layout_bindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + layout_bindings[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 = static_cast(layout_bindings.size()); + layout_info.pBindings = layout_bindings.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 projection."}; +} + +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_instance(void *obj) +{ + auto self = static_cast(obj); + + std::array layout_bindings{}; + + layout_bindings[0].binding = 0; + layout_bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + layout_bindings[0].descriptorCount = 1; + layout_bindings[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + layout_bindings[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 = static_cast(layout_bindings.size()); + layout_info.pBindings = layout_bindings.data(); + + if(vkCreateDescriptorSetLayout( + cg_core.vk_device_with_swapchain->device, &layout_info, nullptr, + &self->descriptor_set_instance) != VK_SUCCESS) + throw CommandError{ + "Failed to create Vulkan descriptor set layout for rectangles."}; +} + +void +unload_descriptor_set_instance(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyDescriptorSetLayout( + cg_core.vk_device_with_swapchain->device, self->descriptor_set_instance, + nullptr); +} + +void +load_pipeline(void *obj) +{ + auto self = static_cast(obj); + + std::array set_layouts{ + self->descriptor_set_view, self->descriptor_set_instance + }; + + VkPipelineLayoutCreateInfo pipeline_layout_info{}; + pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipeline_layout_info.setLayoutCount = set_layouts.size(); + pipeline_layout_info.pSetLayouts = set_layouts.data(); + pipeline_layout_info.pushConstantRangeCount = 0; + pipeline_layout_info.pPushConstantRanges = nullptr; + + if(vkCreatePipelineLayout( + cg_core.vk_device_with_swapchain->device, &pipeline_layout_info, + nullptr, &self->pipeline) != VK_SUCCESS) + throw CommandError{"Failed to create Vulkan pipeline layout."}; +} + +void +unload_pipeline(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyPipelineLayout( + cg_core.vk_device_with_swapchain->device, self->pipeline, nullptr); +} + +void +load_render_pass(void *obj) +{ + auto self = static_cast(obj); + + std::array attachments{}; + // Color attachment. + attachments[0].flags = 0; + attachments[0].format = cg_core.vk_swapchain->image_format; + attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; + attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + VkAttachmentReference color_attachment_ref{}; + color_attachment_ref.attachment = 0; + color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass{}; + subpass.flags = 0; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.inputAttachmentCount = 0; + subpass.pInputAttachments = nullptr; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &color_attachment_ref; + subpass.pResolveAttachments = nullptr; + subpass.pDepthStencilAttachment = nullptr; + subpass.preserveAttachmentCount = 0; + subpass.pPreserveAttachments = nullptr; + + VkSubpassDependency dependency{}; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependency.srcAccessMask = 0; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + + VkRenderPassCreateInfo render_pass_info{}; + render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + render_pass_info.pNext = nullptr; + render_pass_info.flags = 0; + render_pass_info.attachmentCount = attachments.size(); + render_pass_info.pAttachments = attachments.data(); + render_pass_info.subpassCount = 1; + render_pass_info.pSubpasses = &subpass; + render_pass_info.dependencyCount = 1; + render_pass_info.pDependencies = &dependency; + + if(vkCreateRenderPass( + cg_core.vk_device_with_swapchain->device, &render_pass_info, + nullptr, &self->render_pass) != VK_SUCCESS) + throw CommandError{"Failed to create Vulkan Render Pass 2D."}; +} + +static void +unload_render_pass(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyRenderPass( + cg_core.vk_device_with_swapchain->device, self->render_pass, nullptr); +} + +const CommandChain loader{ + {&load_descriptor_set_view, &unload_descriptor_set_view}, + {&load_descriptor_set_instance, &unload_descriptor_set_instance}, + {&load_pipeline, &unload_pipeline}, + {&load_render_pass, &unload_render_pass} +}; + +} + +namespace VK +{ + +GraphicsPipeline2DWiredLayout::GraphicsPipeline2DWiredLayout() +{ + loader.execute(this); +} + +GraphicsPipeline2DWiredLayout::~GraphicsPipeline2DWiredLayout() +{ + loader.revert(this); +} + +} diff --git a/src/vk/graphics_pipeline_2d_wired_layout.hpp b/src/vk/graphics_pipeline_2d_wired_layout.hpp new file mode 100644 index 0000000..3d0268e --- /dev/null +++ b/src/vk/graphics_pipeline_2d_wired_layout.hpp @@ -0,0 +1,43 @@ +/* + * 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_GRAPHICS_PIPELINE_2D_WIRED_LAYOUT_H +#define CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_WIRED_LAYOUT_H 1 + +#include "core.hpp" + +namespace VK +{ + +struct UBOModel2D +{ + glm::vec3 color; +}; + +struct GraphicsPipeline2DWiredLayout +{ + VkDescriptorSetLayout descriptor_set_view; + VkDescriptorSetLayout descriptor_set_instance; + VkPipelineLayout pipeline; + VkRenderPass render_pass; + + GraphicsPipeline2DWiredLayout(); + ~GraphicsPipeline2DWiredLayout(); +}; + +} + +#endif /* CANDY_GEAR_VK_GRAPHICS_PIPELINE_2D_LAYOUT_H */ diff --git a/src/vk/rectangle.cpp b/src/vk/rectangle.cpp new file mode 100644 index 0000000..b0925f1 --- /dev/null +++ b/src/vk/rectangle.cpp @@ -0,0 +1,245 @@ +/* + * 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 "rectangle.hpp" + +#include + +#include "../core.hpp" +#include "graphics_pipeline_2d_wired_layout.hpp" + +namespace +{ + +void +load_mesh(void *obj) +{ + auto self = static_cast(obj); + + self->queue_family = + cg_core.vk_device_with_swapchain->get_queue_family_with_graphics(); + + glm::vec2 rect[4]{ + glm::vec2{self->x, self->y}, + glm::vec2{self->x, self->y + self->height}, + glm::vec2{self->x + self->width, self->y}, + glm::vec2{self->x + self->width, self->y + self->height} + }; + + void *vertexes_data{&rect}; + static const size_t vertexes_size = + sizeof(glm::vec2) * VK::Rectangle::vertex_count; + self->source_buffers.reserve(cg_core.vk_swapchain->images_count); + self->vertex_buffers.reserve(cg_core.vk_swapchain->images_count); + for(int i{0}; i < cg_core.vk_swapchain->images_count; i++) + { + self->source_buffers.emplace_back( + self->queue_family->device, vertexes_data, vertexes_size); + self->vertex_buffers.emplace_back( + self->queue_family, &self->source_buffers[i], + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + } +} + +void +unload_mesh(void *obj) +{ + auto self = static_cast(obj); + + self->vertex_buffers.clear(); + self->source_buffers.clear(); +} + +void +load_uniform_buffer(void *obj) +{ + auto self = static_cast(obj); + + self->ub_rectangle.reserve(cg_core.vk_swapchain->images_count); + for(auto i{0}; i < cg_core.vk_swapchain->images_count; i++) + self->ub_rectangle.emplace_back( + cg_core.vk_device_with_swapchain, sizeof(VK::UBOModel2D)); +} + +void +unload_uniform_buffer(void *obj) +{ + auto self = static_cast(obj); + + self->ub_rectangle.clear(); +} + +void +load_descriptor_set_pool(void *obj) +{ + auto self = static_cast(obj); + + std::array descriptor_pool_sizes{}; + descriptor_pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptor_pool_sizes[0].descriptorCount = self->ub_rectangle.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_rectangle.size(); + pool_info.poolSizeCount = descriptor_pool_sizes.size(); + pool_info.pPoolSizes = descriptor_pool_sizes.data(); + + if(vkCreateDescriptorPool( + self->queue_family->device->device, &pool_info, nullptr, + &self->descriptor_pool) != VK_SUCCESS) + throw CommandError{"Failed to create a Vulkan descriptor pool."}; +} + +void +unload_descriptor_set_pool(void *obj) +{ + auto self = static_cast(obj); + + vkDestroyDescriptorPool( + self->queue_family->device->device, self->descriptor_pool, nullptr); +} + +void +load_descriptor_sets(void *obj) +{ + auto self = static_cast(obj); + + std::vector layouts( + cg_core.vk_swapchain->images_count, + cg_core.vk_graphics_pipeline_2d_wired_layout->descriptor_set_instance); + + 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.resize(layouts.size()); + if(vkAllocateDescriptorSets( + self->queue_family->device->device, &alloc_info, + self->descriptor_sets.data()) != VK_SUCCESS) + CommandError{"Failed to create Vulkan descriptor set."}; +} + +void +load_data_to_descriptor_sets(void *obj) +{ + auto self = static_cast(obj); + + for(auto i{0}; i < self->ub_rectangle.size(); i++) + { + VkDescriptorBufferInfo buffer_info{}; + buffer_info.buffer = self->ub_rectangle[i].buffer; + buffer_info.offset = 0; + buffer_info.range = sizeof(VK::UBOModel2D); + + std::array write_descriptors{}; + write_descriptors[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptors[0].dstSet = self->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 = &buffer_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); + } +} + +static const CommandChain loader{ + {&load_mesh, &unload_mesh}, + {&load_uniform_buffer, &unload_uniform_buffer}, + {&load_descriptor_set_pool, &unload_descriptor_set_pool}, + {&load_descriptor_sets, nullptr}, + {&load_data_to_descriptor_sets, nullptr}, +}; + +constexpr bool +_align_vertically(const float a_x, const float a_width, + const float b_x, const float b_width) +{ + return a_x <= b_x + b_width && a_x + a_width >= b_x; +} + +constexpr bool +_align_horizontally(const float a_y, const float a_height, + const float b_y, const float b_height) +{ + return a_y <= b_y + b_height && a_y + a_height >= b_y; +} + +} + +namespace VK +{ + +Rectangle::Rectangle(float x, float y, float width, float height): + x{x}, + y{y}, + width{width}, + height{height} +{ + loader.execute(this); +} + +Rectangle::~Rectangle() +{ + loader.revert(this); +} + +bool +Rectangle::align_vertically(const Rectangle &that) const +{ + return _align_vertically(this->x, this->width, that.x, that.width); +} + +bool +Rectangle::align_horizontally(const Rectangle &that) const +{ + return _align_horizontally(this->y, this->height, that.y, that.height); +} + +bool +Rectangle::collide(const Rectangle &that) const +{ + return + _align_vertically(this->x, this->width, that.x, that.width) && + _align_horizontally(this->y, this->height, that.y, that.height); +} + +void +Rectangle::update_vertex_buffer() +{ + glm::vec2 rect[4]{ + glm::vec2{this->x, this->y}, + glm::vec2{this->x, this->y + this->height}, + glm::vec2{this->x + this->width, this->y}, + glm::vec2{this->x + this->width, this->y + this->height} + }; + + void *vertexes_data{&rect}; + this->source_buffers[cg_core.vk_swapchain->current_frame].copy_data( + vertexes_data); + this->vertex_buffers[cg_core.vk_swapchain->current_frame].copy_data(); +} + +} diff --git a/src/vk/rectangle.hpp b/src/vk/rectangle.hpp new file mode 100644 index 0000000..fc21135 --- /dev/null +++ b/src/vk/rectangle.hpp @@ -0,0 +1,66 @@ +/* + * 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_RECTANGLE_H +#define CANDY_GEAR_VK_RECTANGLE_H 1 + +#include + +#include "core.hpp" +#include "destination_buffer.hpp" +#include "queue_family.hpp" +#include "uniform_buffer.hpp" + +namespace VK +{ + +struct Rectangle +{ + static const uint32_t vertex_count{4}; + + float x{0}; + float y{0}; + float width{1}; + float height{1}; + + QueueFamily *queue_family; + + std::vector source_buffers; + std::vector vertex_buffers; + + std::vector ub_rectangle; + + VkDescriptorPool descriptor_pool; + std::vector descriptor_sets; + + Rectangle() = default; + Rectangle(float x, float y, float width, float height); + ~Rectangle(); + + bool + align_vertically(const Rectangle &that) const; + bool + align_horizontally(const Rectangle &that) const; + bool + collide(const Rectangle &that) const; + + void + update_vertex_buffer(); +}; + +} + +#endif /* CANDY_GEAR_VK_RECTANGLE_H */ diff --git a/src/vk/renderer.cpp b/src/vk/renderer.cpp index 8d82b00..a7e5f35 100644 --- a/src/vk/renderer.cpp +++ b/src/vk/renderer.cpp @@ -231,15 +231,16 @@ Renderer::draw() vkCmdEndRenderPass(draw_command_buffer); } - // 2D drawing + // 2D solid 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; + cg_core.vk_graphics_pipeline_2d_solid_layout->render_pass; render_pass_begin.framebuffer = - cg_core.vk_graphics_pipeline_2d->swapchain_framebuffers[image_index]; + cg_core.vk_graphics_pipeline_2d_solid->swapchain_framebuffers[ + image_index]; render_pass_begin.renderArea.offset = {0, 0}; render_pass_begin.renderArea.extent = { static_cast(cg_core.display_width), @@ -251,12 +252,45 @@ Renderer::draw() draw_command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); for(auto &view: this->views_2d) - cg_core.vk_graphics_pipeline_2d->draw( + cg_core.vk_graphics_pipeline_2d_solid->draw( view, draw_command_buffer, cg_core.vk_swapchain->current_frame, next_frame, image_index); for(auto &view: this->views_3d) - cg_core.vk_graphics_pipeline_2d->draw( + cg_core.vk_graphics_pipeline_2d_solid->draw( + view, draw_command_buffer, cg_core.vk_swapchain->current_frame, + next_frame, image_index); + + vkCmdEndRenderPass(draw_command_buffer); + } + + // 2D wired 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_wired_layout->render_pass; + render_pass_begin.framebuffer = + cg_core.vk_graphics_pipeline_2d_wired->swapchain_framebuffers[ + image_index]; + render_pass_begin.renderArea.offset = {0, 0}; + render_pass_begin.renderArea.extent = { + static_cast(cg_core.display_width), + static_cast(cg_core.display_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_2d) + cg_core.vk_graphics_pipeline_2d_wired->draw( + view, draw_command_buffer, cg_core.vk_swapchain->current_frame, + next_frame, image_index); + + for(auto &view: this->views_3d) + cg_core.vk_graphics_pipeline_2d_wired->draw( view, draw_command_buffer, cg_core.vk_swapchain->current_frame, next_frame, image_index); @@ -313,11 +347,8 @@ Renderer::draw() // Prepare for the next frame. { - this->models_to_draw[next_frame].clear(); - for(auto &view: this->views_2d) view->sprites_to_draw[next_frame].clear(); - for(auto &view: this->views_3d) view->sprites_to_draw[next_frame].clear(); - - cg_core.vk_swapchain->current_frame = next_frame; + this->models_to_draw[next_frame].clear(); + cg_core.vk_swapchain->current_frame = next_frame; } } else diff --git a/src/vk/source_buffer.cpp b/src/vk/source_buffer.cpp index 7e6c570..f8f1aee 100644 --- a/src/vk/source_buffer.cpp +++ b/src/vk/source_buffer.cpp @@ -21,8 +21,7 @@ namespace VK { -SourceBuffer::SourceBuffer(Device *device, void *data, size_t data_size): - data{data} +SourceBuffer::SourceBuffer(Device *device, void *data, size_t data_size) { this->device = device; this->device_size = data_size; @@ -40,7 +39,7 @@ SourceBuffer::SourceBuffer(Device *device, void *data, size_t data_size): error += command_error.what(); throw std::runtime_error{error}; } - this->copy_data(); + this->copy_data(data); } SourceBuffer::SourceBuffer(SourceBuffer &&that) @@ -50,11 +49,9 @@ SourceBuffer::SourceBuffer(SourceBuffer &&that) this->device_size = that.device_size; this->buffer_usage = that.buffer_usage; this->memory_properties = that.memory_properties; - this->data = that.data; that.buffer = VK_NULL_HANDLE; that.device_memory = VK_NULL_HANDLE; - that.data = nullptr; } SourceBuffer& @@ -65,11 +62,9 @@ SourceBuffer::operator=(SourceBuffer &&that) this->device_size = that.device_size; this->buffer_usage = that.buffer_usage; this->memory_properties = that.memory_properties; - this->data = that.data; that.buffer = VK_NULL_HANDLE; that.device_memory = VK_NULL_HANDLE; - that.data = nullptr; return *this; } @@ -80,12 +75,12 @@ SourceBuffer::~SourceBuffer() } void -SourceBuffer::copy_data() +SourceBuffer::copy_data(void *src_data) { void *dst_data; vkMapMemory(this->device->device, this->device_memory, 0, this->device_size, 0, &dst_data); - memcpy(dst_data, this->data, static_cast(this->device_size)); + memcpy(dst_data, src_data, static_cast(this->device_size)); vkUnmapMemory(this->device->device, this->device_memory); } diff --git a/src/vk/source_buffer.hpp b/src/vk/source_buffer.hpp index 713d708..440e561 100644 --- a/src/vk/source_buffer.hpp +++ b/src/vk/source_buffer.hpp @@ -28,8 +28,6 @@ struct SourceBuffer: public BaseBuffer SourceBuffer& operator=(const SourceBuffer &t) = delete; - void *data; - SourceBuffer(Device *device, void *data, size_t data_size); SourceBuffer(SourceBuffer &&that); @@ -39,7 +37,7 @@ struct SourceBuffer: public BaseBuffer ~SourceBuffer(); void - copy_data(); + copy_data(void *src_data); }; } diff --git a/src/vk/sprite.cpp b/src/vk/sprite.cpp index 9a718d7..a7b802a 100644 --- a/src/vk/sprite.cpp +++ b/src/vk/sprite.cpp @@ -137,7 +137,7 @@ load_descriptor_sets(void *obj) std::vector layouts( cg_core.vk_swapchain->images_count, - cg_core.vk_graphics_pipeline_2d_layout->descriptor_set_sprite); + cg_core.vk_graphics_pipeline_2d_solid_layout->descriptor_set_sprite); VkDescriptorSetAllocateInfo alloc_info{}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; diff --git a/src/vk/view_2d.cpp b/src/vk/view_2d.cpp index 623aa63..011fb1a 100644 --- a/src/vk/view_2d.cpp +++ b/src/vk/view_2d.cpp @@ -56,7 +56,7 @@ load_descriptor_sets_2d(void *obj) std::vector layouts( cg_core.vk_swapchain->images_count, - cg_core.vk_graphics_pipeline_2d_layout->descriptor_set_view); + cg_core.vk_graphics_pipeline_2d_solid_layout->descriptor_set_view); VkDescriptorSetAllocateInfo alloc_info{}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; @@ -124,6 +124,7 @@ const CommandChain View2D::descriptor_sets_loader{ View2D::View2D(glm::vec4 region): region{region}, descriptor_pool{VK_NULL_HANDLE}, + rectangles_to_draw{cg_core.vk_swapchain->images_count}, sprites_to_draw{cg_core.vk_swapchain->images_count} { loader.execute(this); diff --git a/src/vk/view_2d.hpp b/src/vk/view_2d.hpp index f6741cc..ec7225f 100644 --- a/src/vk/view_2d.hpp +++ b/src/vk/view_2d.hpp @@ -23,6 +23,7 @@ #include "core.hpp" #include "sprite.hpp" +#include "rectangle.hpp" namespace VK { @@ -37,6 +38,7 @@ struct View2D VkDescriptorPool descriptor_pool; std::vector descriptor_sets_2d; + std::vector>> rectangles_to_draw; std::vector< std::unordered_map, std::vector>> sprites_to_draw; diff --git a/test/src/main.rb b/test/src/main.rb index be0ae0b..b7bbe85 100644 --- a/test/src/main.rb +++ b/test/src/main.rb @@ -25,9 +25,12 @@ end def init() texture = CandyGear::Texture.from_image("textures/color_texture.png"); mesh = CandyGear::Mesh.new("meshes/cube.cgmesh"); + + $color = CandyGear::Vector3D.new(0.8, 0.2, 0.2); $model = CandyGear::Model.new(mesh, texture); $sprite = CandyGear::Sprite.new( texture, CandyGear::Vector4D.new(0, 0, 1.0, 1.0)); + $rectangle = CandyGear::Rectangle.new(102.0, 1.0, 101.0, 101.0) $sprite_position = CandyGear::Vector4D.new(1.0, 1.0, 101.0, 101.0); $instances = [ @@ -83,8 +86,9 @@ end def quit() = CandyGear.quit(); def tick() - $view1.draw($sprite, $sprite_position); + $sprite.draw($view1, $sprite_position); $instances_rotation.rotate(0.0, BOX_ROTATION_SPEED); + $rectangle.draw($view1, $color); $instances.each do |i| $model.draw(i, $instances_rotation); end -- cgit v1.2.3