diff options
| -rw-r--r-- | include/compute-renderpass.hpp | 10 | ||||
| -rw-r--r-- | include/material.hpp | 2 | ||||
| -rw-r--r-- | include/primitive-renderpass.hpp | 97 | ||||
| -rw-r--r-- | include/renderpass.hpp | 12 | ||||
| -rw-r--r-- | include/vk-api.hpp | 71 | ||||
| -rw-r--r-- | include/vk-renderer.hpp | 65 | ||||
| -rw-r--r-- | src/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/compute-renderpass.cpp | 14 | ||||
| -rw-r--r-- | src/gltf.cpp | 512 | ||||
| -rw-r--r-- | src/main.cpp | 249 | ||||
| -rw-r--r-- | src/primitive-renderpass.cpp | 150 | ||||
| -rw-r--r-- | src/scene.cpp | 14 | ||||
| -rw-r--r-- | src/vk-api.cpp | 406 | ||||
| -rw-r--r-- | src/vk-context.cpp | 7 | ||||
| -rw-r--r-- | src/vk-renderer.cpp | 315 |
15 files changed, 1115 insertions, 810 deletions
diff --git a/include/compute-renderpass.hpp b/include/compute-renderpass.hpp index a581930..641d4b1 100644 --- a/include/compute-renderpass.hpp +++ b/include/compute-renderpass.hpp @@ -14,8 +14,12 @@ class ComputeRenderpass : public Renderpass { : Renderpass(api) {} + ~ComputeRenderpass() { + api.destroy_pipeline(pipeline); + } - void set_pipeline(std::string& shader_name) override final; + + void set_pipeline(std::string& shader_name); void set_dispatch_size(size_t count_x, size_t count_y, size_t count_z); @@ -26,7 +30,7 @@ class ComputeRenderpass : public Renderpass { void set_constant(off_t offset, Buffer* buffer); // TODO: Do not use vulkan api type - void execute(VkCommandBuffer command_buffer) override final; + void execute(vkrenderer& renderer, VkCommandBuffer command_buffer) override final; Texture* output_texture; @@ -39,4 +43,6 @@ class ComputeRenderpass : public Renderpass { size_t group_count_x; size_t group_count_y; size_t group_count_z; + + pipeline pipeline; }; diff --git a/include/material.hpp b/include/material.hpp index 0336fb5..780e68d 100644 --- a/include/material.hpp +++ b/include/material.hpp @@ -13,7 +13,7 @@ struct material { color base_color; texture base_color_texture; texture metallic_roughness_texture; - float metalness = 0.f; + float metalness = 1.f; float roughness = 1.f; }; diff --git a/include/primitive-renderpass.hpp b/include/primitive-renderpass.hpp new file mode 100644 index 0000000..45b43e9 --- /dev/null +++ b/include/primitive-renderpass.hpp @@ -0,0 +1,97 @@ +#pragma once + +#include <stdint.h> +#include <vector> +#include <array> + +#include "vk-renderer.hpp" +#include "renderpass.hpp" + +class Buffer; +class Texture; +class Sampler; +class Primitive; + +class PrimitiveRenderpass : public Renderpass { + public: + + PrimitiveRenderpass(vkapi& api); + + void add_primitive(Primitive* new_primitive); + + void add_color_attachment(VkFormat format); + + void set_depth_stencil(Texture* depth_stencil); + + void set_viewport(float x, float y, float width, float height); + + void set_color_attachment(uint32_t index, Texture* attachment); + + void finalize_render_pass(); + + void execute(vkrenderer& renderer, VkCommandBuffer command_buffer) override final; + + VkRenderPass render_pass = VK_NULL_HANDLE; + + private: + + void create_framebuffers(); + + void recreate_framebuffers(); + + VkViewport viewport = { .minDepth = 0.f, .maxDepth = 1.f }; + + std::vector<Texture*> color_attachments; + std::vector<VkImageView> color_attachments_view; + std::vector<VkFormat> color_attachments_format; + + std::array<framebuffer, vkrenderer::virtual_frames_count> framebuffers; + + std::vector<Primitive*> primitives; +}; + + +class Primitive { + public: + + Primitive(vkapi& api, PrimitiveRenderpass& render_pass) + : api(api), primitive_render_pass(render_pass) + {}; + + void set_pipeline(std::string& shader_name); + + void set_constant_offset(off_t offset); + void set_constant(off_t offset, uint64_t* constant); + void set_constant(off_t offset, Texture* texture); + void set_constant(off_t offset, Buffer* buffer); + void set_constant(off_t offset, Sampler* sampler); + + void set_index_buffer(Buffer* index_buffer); + + void set_scissor(int32_t x, int32_t y, uint32_t width, uint32_t height); + + void set_draw_info(size_t vertex_count, off_t first_vertex, off_t vertex_offset); + + void render(VkCommandBuffer command_buffer); + + +private: + + vkapi& api; + + PrimitiveRenderpass& primitive_render_pass; + + pipeline pipeline; + + Buffer* index_buffer; + + size_t element_count; + off_t first_vertex; + off_t vertex_offset; + + off_t constant_offset; + + VkRect2D scissor = {}; + + std::array<uint8_t, 64> constants; +}; diff --git a/include/renderpass.hpp b/include/renderpass.hpp index 64947b6..a444c64 100644 --- a/include/renderpass.hpp +++ b/include/renderpass.hpp @@ -2,7 +2,7 @@ #include <string> -#include "vk-api.hpp" +#include "vk-renderer.hpp" class Renderpass { public: @@ -11,17 +11,11 @@ class Renderpass { :api(api) {}; - virtual ~Renderpass() { - api.destroy_pipeline(pipeline); - } - - virtual void set_pipeline(std::string& shader_name) = 0; + virtual ~Renderpass() {}; // TODO: Do not use vulkan api type - virtual void execute(VkCommandBuffer command_buffer) = 0; + virtual void execute(vkrenderer& renderer, VkCommandBuffer command_buffer) = 0; protected: vkapi &api; - - pipeline pipeline; }; diff --git a/include/vk-api.hpp b/include/vk-api.hpp index 1b9f51f..0f1431a 100644 --- a/include/vk-api.hpp +++ b/include/vk-api.hpp @@ -1,6 +1,7 @@ #ifndef __VK_API_HPP_ #define __VK_API_HPP_ +#include <stdint.h> #include <vector> #include <map> #include <iostream> @@ -22,6 +23,7 @@ struct pipeline { }; using bindless_index = uint32_t; +using handle = uint32_t; struct image { VkImage handle; @@ -31,6 +33,7 @@ struct image { VkImageSubresourceRange subresource_range; VkFormat format; VkExtent3D size; + VkImageUsageFlags usages; bindless_index bindless_storage_index; bindless_index bindless_sampled_index; @@ -40,13 +43,18 @@ struct image { }; struct swapchain { - size_t image_count; - std::vector<image> images; + uint32_t image_count; + std::vector<handle> images; VkSwapchainKHR handle; VkSurfaceFormatKHR surface_format; VkExtent2D extent; }; +struct framebuffer { + VkFramebuffer handle; + VkExtent2D size; +}; + struct sampler { VkSampler handle; bindless_index bindless_index; @@ -101,16 +109,16 @@ class vkapi { vkapi(); ~vkapi(); - buffer create_buffer(size_t data_size, VkBufferUsageFlags buffer_usage, VmaMemoryUsage mem_usage); - void copy_buffer(VkCommandBuffer cmd_buf, buffer src, buffer dst, size_t size); - void copy_buffer(VkCommandBuffer cmd_buf, buffer src, image dst); - void destroy_buffer(buffer& buffer); + handle create_buffer(size_t data_size, VkBufferUsageFlags buffer_usage, VmaMemoryUsage mem_usage); + void copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst, size_t size); + void copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst); + void destroy_buffer(handle buffer); - image create_image(VkExtent3D size, VkFormat format, VkImageUsageFlags usages); - void destroy_image(image &image); - std::vector<image> create_images(VkExtent3D size, VkFormat format, VkImageUsageFlags usages, size_t image_count); - void destroy_images(std::vector<image> &images); + handle create_image(VkExtent3D size, VkFormat format, VkImageUsageFlags usages); + void destroy_image(handle image); + std::vector<handle> create_images(VkExtent3D size, VkFormat format, VkImageUsageFlags usages, size_t image_count); + void destroy_images(std::vector<handle>& images); VkFence create_fence(); @@ -124,8 +132,8 @@ class vkapi { std::vector<VkSemaphore> create_semaphores(size_t semaphores_count); void destroy_semaphores(std::vector<VkSemaphore> &semaphores); - sampler create_sampler(VkFilter filter, VkSamplerAddressMode address_mode); - void destroy_sampler(sampler sampler); + handle create_sampler(VkFilter filter, VkSamplerAddressMode address_mode); + void destroy_sampler(handle sampler); std::vector<VkCommandBuffer> create_command_buffers(size_t command_buffers_count); @@ -137,10 +145,10 @@ class vkapi { void destroy_render_pass(VkRenderPass render_pass); - VkFramebuffer create_framebuffer(VkRenderPass render_pass, std::vector<image>& images, VkExtent2D size); - std::vector<VkFramebuffer> create_framebuffers(VkRenderPass render_pass, std::vector<image>& images, VkExtent2D size, uint32_t framebuffer_count); - void destroy_framebuffer(VkFramebuffer framebuffer); - void destroy_framebuffers(std::vector<VkFramebuffer>& framebuffers); + framebuffer create_framebuffer(VkRenderPass render_pass, std::vector<VkFormat>& formats, VkExtent2D size); + std::vector<framebuffer> create_framebuffers(VkRenderPass render_pass, std::vector<VkFormat>& formats, VkExtent2D size, uint32_t framebuffer_count); + void destroy_framebuffer(framebuffer framebuffer); + void destroy_framebuffers(std::vector<framebuffer>& framebuffers); pipeline create_compute_pipeline(const char* shader_name); @@ -159,27 +167,27 @@ class vkapi { swapchain create_swapchain(VkSurfaceKHR surface, size_t min_image_count, VkImageUsageFlags usages, VkSwapchainKHR old_swapchain); void destroy_swapchain(swapchain& swapchain); - void update_descriptor_image(image &img, VkDescriptorType type); - void update_descriptor_images(std::vector<image> &images, VkDescriptorType type); - void update_descriptor_sampler(sampler &sampler); - void update_descriptor_samplers(std::vector<sampler> &samplers); + void update_descriptor_image(handle img, VkDescriptorType type); + void update_descriptor_images(std::vector<handle> &images, VkDescriptorType type); + void update_descriptor_sampler(handle sampler); + void update_descriptor_samplers(std::vector<handle> &samplers); void update_constants(VkCommandBuffer command_buffer, VkShaderStageFlagBits shader_stage, off_t offset, size_t size, void* data); void start_record(VkCommandBuffer command_buffer); - void image_barrier(VkCommandBuffer command_buffer, VkImageLayout dst_layout, VkPipelineStageFlagBits dst_stage, VkAccessFlags dst_access, image& image); + void image_barrier(VkCommandBuffer command_buffer, VkImageLayout dst_layout, VkPipelineStageFlagBits dst_stage, VkAccessFlags dst_access, handle image); - void begin_render_pass(VkCommandBuffer command_buffer, VkRenderPass render_pass, VkFramebuffer framebuffer, VkExtent2D size, pipeline& pipeline); + void begin_render_pass(VkCommandBuffer command_buffer, VkRenderPass render_pass, std::vector<VkImageView>& attachments, framebuffer framebuffer, VkExtent2D size); void end_render_pass(VkCommandBuffer command_buffer); void run_compute_pipeline(VkCommandBuffer command_buffer, pipeline& pipeline, size_t group_count_x, size_t group_count_y, size_t group_count_z); void draw(VkCommandBuffer command_buffer, pipeline& pipeline, uint32_t vertex_count, uint32_t vertex_offset); - void draw(VkCommandBuffer command_buffer, pipeline& pipeline, buffer& index_buffer, uint32_t primitive_count, uint32_t indices_offset, uint32_t vertices_offset); + void draw(VkCommandBuffer command_buffer, pipeline& pipeline, handle index_buffer, uint32_t primitive_count, uint32_t indices_offset, uint32_t vertices_offset); - void blit_full(VkCommandBuffer command_buffer, image& src_image, image& dst_image); + void blit_full(VkCommandBuffer command_buffer, handle src_image, handle dst_image); void end_record(VkCommandBuffer command_buffer); @@ -187,6 +195,10 @@ class vkapi { VkResult present(swapchain& swapchain, uint32_t image_index, VkSemaphore wait_semaphore); + const buffer& get_buffer(handle buffer_handle) { return *buffers[buffer_handle]; }; + const image& get_image(handle image_handle) { return *images[image_handle]; }; + const sampler& get_sampler(handle sampler_handle) { return *samplers[sampler_handle]; }; + vkcontext context; private: @@ -195,12 +207,13 @@ class vkapi { const char* shader_stage_extension(VkShaderStageFlags shader_stage); - std::map<VkBuffer, buffer> buffers; - std::map<VkImage, image> images; - std::map<VkSampler, sampler>samplers; + // TODO: Use freelists instead + std::vector<buffer*> buffers; + std::vector<image*> images; + std::vector<sampler*> samplers; - VkCommandPool command_pool; - VkDescriptorPool descriptor_pool; + VkCommandPool command_pool; + VkDescriptorPool descriptor_pool; }; diff --git a/include/vk-renderer.hpp b/include/vk-renderer.hpp index 76dfffc..864bc48 100644 --- a/include/vk-renderer.hpp +++ b/include/vk-renderer.hpp @@ -2,14 +2,16 @@ #define __VK_RENDERER_HPP_ #include <stdint.h> +#include <sys/types.h> #include <vector> #include "vk-api.hpp" -#include "vulkan/vulkan_core.h" class Renderpass; class ComputeRenderpass; +class PrimitiveRenderpass; +class Primitive; class window; class Texture; @@ -24,67 +26,67 @@ class vkrenderer { void begin_frame(); - void ui(); - void compute(uint32_t width, uint32_t height); void finish_frame(); void recreate_swapchain(); - void update_image(Texture* texture, void* data, size_t size); + void update_image(Texture* texture, void* data); + + void update_buffer(Buffer* buffer, void* data, off_t offset, size_t size); Buffer* create_buffer(size_t size, bool isStatic); + Buffer* create_index_buffer(size_t size, bool isStatic); + Texture* create_2d_texture(size_t width, size_t height, VkFormat format); Sampler* create_sampler(VkFilter filter, VkSamplerAddressMode address_mode); ComputeRenderpass* create_compute_renderpass(); + PrimitiveRenderpass* create_primitive_renderpass(); + + Primitive* create_primitive(PrimitiveRenderpass& primitive_render_pass); + void render(); uint32_t frame_index() { return this->virtual_frame_index; } - private: + Texture* back_buffer() { return swapchain_textures[swapchain_image_index]; } - vkapi api; + VkFormat back_buffer_format() { return swapchain.surface_format.format; } - std::vector<Renderpass*> renderpasses; + static constexpr uint32_t virtual_frames_count = 2; + private: void handle_swapchain_result(VkResult function_result); - // vkapi api; + vkapi api; + + std::vector<Renderpass*> renderpasses; uint32_t virtual_frame_index = 0; uint32_t swapchain_image_index = 0; - sampler ui_texture_sampler; - image ui_texture; - std::vector<VkCommandBuffer> command_buffers; - buffer staging_buffer; + handle staging_buffer; pipeline tonemapping_pipeline; - std::vector<buffer> ui_vertex_buffers; - std::vector<buffer> ui_index_buffers; - pipeline ui_pipeline; - VkRenderPass render_pass; - std::vector<VkFramebuffer> framebuffers; - std::vector<VkFence> submission_fences; std::vector<VkSemaphore> execution_semaphores; std::vector<VkSemaphore> acquire_semaphores; VkSurfaceKHR platform_surface; swapchain swapchain; + std::vector<Texture*> swapchain_textures; const uint32_t min_swapchain_image_count = 3; - static constexpr uint32_t virtual_frames_count = 2; }; // TODO: Move those to there own files @@ -93,39 +95,26 @@ class Texture { sampler sampler; - image device_image; + handle device_image; }; class Sampler { public: - sampler device_sampler; + + handle device_sampler; }; class Buffer { public: Buffer(vkrenderer* renderer, size_t size, bool isStatic) - : renderer(renderer), size(size), isStatic(isStatic) {} - - void* ptr() { - size_t offset = isStatic ? 0 : size * renderer->frame_index(); - return (uint8_t*)device_buffer.alloc_info.pMappedData + offset; - } + : size(size), isStatic(isStatic) {} - unsigned long long device_address() { - size_t offset = isStatic ? 0 : size * renderer->frame_index(); - return device_buffer.device_address + offset; - } - - buffer device_buffer; - - private: - - bool isStatic; + handle device_buffer; size_t size; - vkrenderer* renderer; + bool isStatic; }; #endif // !__VK_RENDERER_HPP_ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c91cb83..e8bef7e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,6 +24,7 @@ add_executable( scene.cpp gltf.cpp compute-renderpass.cpp + primitive-renderpass.cpp ) if(UNIX AND NOT APPLE) diff --git a/src/compute-renderpass.cpp b/src/compute-renderpass.cpp index c680bac..7399ae3 100644 --- a/src/compute-renderpass.cpp +++ b/src/compute-renderpass.cpp @@ -11,8 +11,10 @@ void ComputeRenderpass::set_pipeline(std::string& shader_name) { void ComputeRenderpass::set_ouput_texture(Texture* output_texture) { this->output_texture = output_texture; + auto image = api.get_image(output_texture->device_image); + // TODO: Remove hardcoded offset - memcpy(constants.data() + 56, &output_texture->device_image.bindless_storage_index, sizeof(bindless_index)); + memcpy(constants.data() + 56, &image.bindless_storage_index, sizeof(bindless_index)); } void ComputeRenderpass::set_dispatch_size(size_t count_x, size_t count_y, size_t count_z) { @@ -26,17 +28,19 @@ void ComputeRenderpass::set_constant(off_t offset, uint64_t* constant) { } void ComputeRenderpass::set_constant(off_t offset, Texture* texture) { - memcpy(constants.data() + offset, (void*)&texture->device_image.bindless_storage_index, sizeof(bindless_index)); + auto image = api.get_image(texture->device_image); + + memcpy(constants.data() + offset, (void*)&image.bindless_storage_index, sizeof(bindless_index)); input_textures.push_back(texture); } void ComputeRenderpass::set_constant(off_t offset, Buffer* buffer) { - auto address = buffer->device_address(); - memcpy(constants.data() + offset, (void*)&address, sizeof(VkDeviceAddress)); + auto device_buffer = api.get_buffer(buffer->device_buffer); + memcpy(constants.data() + offset, (void*)&device_buffer.device_address, sizeof(VkDeviceAddress)); } -void ComputeRenderpass::execute(VkCommandBuffer command_buffer) { +void ComputeRenderpass::execute(vkrenderer& renderer, VkCommandBuffer command_buffer) { api.update_constants(command_buffer, VK_SHADER_STAGE_COMPUTE_BIT, 0, 64, (void*)&constants); for (auto& texture: input_textures) { diff --git a/src/gltf.cpp b/src/gltf.cpp index b05e71e..2f37a3c 100644 --- a/src/gltf.cpp +++ b/src/gltf.cpp @@ -1,256 +1,256 @@ -#include "gltf.hpp"
-
-#include <fstream>
-#include <cstring>
-
-#define STB_IMAGE_IMPLEMENTATION
-#include "thirdparty/stb_image.h"
-
-#include "utils.hpp"
-
-node gltf::load(std::filesystem::path &path, std::string &filename, vkrenderer &renderer) {
- std::fstream f(path / filename);
- json gltf_json;
-
- f >> gltf_json;
-
- auto &scene = gltf_json["scenes"][0];
-
- auto &buffers = gltf_json["buffers"];
- auto buffer_index = 0;
- auto buffers_content = std::vector<std::vector<uint8_t>>(buffers.size());
- for (auto &buffer: buffers) {
- auto buffer_path = (path / buffer["uri"].get<std::string>()).string();
- buffers_content[buffer_index] = read_file(buffer_path);
- buffer_index++;
- }
-
- auto textures = load_textures(gltf_json, path, renderer);
- auto materials = load_materials(gltf_json, textures);
-
- auto meshes = load_meshes(gltf_json, buffers_content, materials);
-
- node root_node;
- auto &root_children = scene["nodes"];
- uint32_t root_children_count = scene["nodes"].size();
- root_node.children.resize(root_children_count);
-
- for (size_t child_index = 0; child_index < root_children_count; child_index++) {
- load_node(gltf_json, root_children[child_index].get<uint32_t>(), root_node.children[child_index], meshes);
- }
-
- return std::move(root_node);
-}
-
-void gltf::load_node(json &gltf_json, uint32_t index, node &parent, std::vector<mesh> &meshes) {
- auto &gltf_node = gltf_json["nodes"][index];
-
- if (gltf_node.contains("children")) {
- auto &children = gltf_node["children"];
- uint32_t children_count = gltf_node["children"];
- parent.children.resize(children_count);
-
- for (size_t child_index = 0; child_index < children_count; child_index++) {
- load_node(gltf_json, children[child_index].get<uint32_t>(), parent.children[child_index], meshes);
- }
- }
-
- if (gltf_node.contains("mesh")) {
- parent.mesh = std::make_optional(meshes[gltf_node["mesh"].get<uint32_t>()]);
- }
-}
-
-std::vector<mesh> gltf::load_meshes(json &gltf_json, std::vector<std::vector<uint8_t>> &buffers_content, std::vector<material> &materials) {
- auto &gltf_meshes = gltf_json["meshes"];
- auto meshes_count = gltf_meshes.size();
- std::vector<mesh> meshes { meshes_count };
-
- for(size_t mesh_index = 0; mesh_index < meshes_count; mesh_index++) {
- auto &gltf_mesh = gltf_meshes[mesh_index];
- auto &primitives = gltf_mesh["primitives"];
- auto &mesh = meshes[mesh_index];
-
- for (auto& primitive: primitives) {
- auto &&part = load_primitive(gltf_json, primitive, buffers_content, materials);
- mesh.vertices_count += part.vertices_count;
- mesh.triangles_count += part.triangles_count;
- mesh.parts.emplace_back(std::move(part));
- }
- }
-
- return std::move(meshes);
-}
-
-std::vector<texture> gltf::load_textures(json &gltf_json, std::filesystem::path &path, vkrenderer &renderer) {
- auto &gltf_images = gltf_json["images"];
- auto images_count = gltf_images.size();
- std::vector<Texture*> images { images_count };
-
- for (size_t image_index = 0; image_index < images_count; image_index++) {
- auto &gltf_image = gltf_images[image_index];
- int x,y,n;
- auto filepath = (path / gltf_image["uri"].get<std::string>()).string();
- unsigned char *data = stbi_load(filepath.c_str(), &x, &y, &n, 4);
- auto img = renderer.create_2d_texture(static_cast<uint32_t>(x), static_cast<uint32_t>(y), VK_FORMAT_R8G8B8A8_UNORM);
-
- renderer.update_image(img, data, x * y * 4);
-
- stbi_image_free(data);
-
- images[image_index] = std::move(img);
- }
-
- auto &gltf_samplers = gltf_json["samplers"];
- auto samplers_count = gltf_samplers.size();
- std::vector<Sampler*> samplers { samplers_count };
-
- for (size_t sampler_index = 0; sampler_index < samplers_count; sampler_index++) {
- samplers[sampler_index] = renderer.create_sampler(VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT);
- }
-
- auto &gltf_textures = gltf_json["textures"];
- auto textures_count = gltf_textures.size();
- std::vector<texture> textures { textures_count };
-
- for (size_t texture_index = 0; texture_index < textures_count; texture_index++) {
- auto gltf_texture = gltf_textures[texture_index];
-
- auto image_index = gltf_texture["source"].get<uint32_t>();
- auto &image = images[image_index];
-
- uint32_t sampler_id = 0;
- if (gltf_texture.contains("sampler")) {
- auto sampler_index = gltf_texture["sampler"].get<uint32_t>();
- auto &sampler = samplers[sampler_index];
- sampler_id = sampler->device_sampler.bindless_index;
- }
-
- textures[texture_index] = texture {
- .image_id = image->device_image.bindless_sampled_index,
- .sampler_id = sampler_id
- };
- }
-
- return std::move(textures);
-}
-
-std::vector<material> gltf::load_materials(json &gltf_json, std::vector<texture> &textures) {
- auto &gltf_materials = gltf_json["materials"];
- auto materials_count = gltf_materials.size();
- std::vector<material> materials { materials_count };
-
- for(size_t material_index = 0; material_index < materials_count; material_index++) {
- auto& gltf_material = gltf_materials[material_index];
- auto& material = materials[material_index];
-
- if (gltf_material.contains("pbrMetallicRoughness")) {
- auto &pbr_params = gltf_material["pbrMetallicRoughness"];
-
- if (pbr_params.contains("baseColorFactor")) {
- auto &base_color = pbr_params["baseColorFactor"];
- material.base_color.v[0] = base_color[0].get<float>();
- material.base_color.v[1] = base_color[1].get<float>();
- material.base_color.v[2] = base_color[2].get<float>();
- material.base_color.v[3] = base_color[3].get<float>();
- } else
- material.base_color = vec3(1.f);
-
- if (pbr_params.contains("baseColorTexture")) {
- auto base_color_index = pbr_params["baseColorTexture"]["index"].get<uint32_t>();
- material.base_color_texture = textures[base_color_index];
- }
-
- if (pbr_params.contains("metallicFactor"))
- material.metalness = pbr_params["metallicFactor"].get<float>();
- else
- material.metalness = 1.0;
-
- if (pbr_params.contains("roughnessFactor"))
- material.roughness = pbr_params["roughnessFactor"].get<float>();
- else
- material.roughness = 1.0;
-
- if (pbr_params.contains("metallicRoughnessTexture")) {
- auto metallic_roughness_index = pbr_params["metallicRoughnessTexture"]["index"].get<uint32_t>();
- material.metallic_roughness_texture = textures[metallic_roughness_index];
- }
- }
- }
-
- return std::move(materials);
-}
-
-mesh_part gltf::load_primitive(json &gltf_json, json &primitive, std::vector<std::vector<uint8_t>> &buffers_content, std::vector<material> &materials) {
- auto part = mesh_part();
- auto &accessors = gltf_json["accessors"];
-
- {
- auto indices_accessor_index = primitive["indices"].get<uint32_t>();
- auto indices_view_index = accessors[indices_accessor_index]["bufferView"].get<uint32_t>();
- auto &indices_view = gltf_json["bufferViews"][indices_view_index];
-
- auto indices_buffer_index = indices_view["buffer"].get<uint32_t>();
- auto indices_offset = indices_view["byteOffset"].get<size_t>();
- auto indices_length = indices_view["byteLength"].get<size_t>();
-
- auto &indices_buffer = buffers_content[indices_buffer_index];
- uint16_t* indices_start = (uint16_t*)(indices_buffer.data() + indices_offset);
-
- part.indices.resize(indices_length / sizeof(uint16_t));
- std::memcpy(part.indices.data(), indices_start, indices_length);
- }
-
- {
- auto positions_accessor_index = primitive["attributes"]["POSITION"].get<uint32_t>();
- auto positions_view_index = accessors[positions_accessor_index]["bufferView"].get<uint32_t>();
- auto &positions_view = gltf_json["bufferViews"][positions_view_index];
-
- auto positions_buffer_index = positions_view["buffer"].get<uint32_t>();
- auto positions_offset = positions_view["byteOffset"].get<size_t>();
- auto positions_length = positions_view["byteLength"].get<size_t>();
-
- auto &positions_buffer = buffers_content[positions_buffer_index];
- float* positions_start = (float*)(positions_buffer.data() + positions_offset);
-
- part.positions.resize(positions_length / sizeof(float));
- std::memcpy(part.positions.data(), positions_start, positions_length);
- }
-
- {
- auto normals_accessor_index = primitive["attributes"]["NORMAL"].get<uint32_t>();
- auto normals_view_index = accessors[normals_accessor_index]["bufferView"].get<uint32_t>();
- auto &normals_view = gltf_json["bufferViews"][normals_view_index];
-
- auto normals_buffer_index = normals_view["buffer"].get<uint32_t>();
- auto normals_offset = normals_view["byteOffset"].get<size_t>();
- auto normals_length = normals_view["byteLength"].get<size_t>();
-
- auto &normals_buffer = buffers_content[normals_buffer_index];
- float* normals_start = (float*)(normals_buffer.data() + normals_offset);
-
- part.normals.resize(normals_length / sizeof(float));
- std::memcpy(part.normals.data(), normals_start, normals_length);
- }
-
- {
- auto uvs_accessor_index = primitive["attributes"]["TEXCOORD_0"].get<uint32_t>();
- auto uvs_view_index = accessors[uvs_accessor_index]["bufferView"].get<uint32_t>();
- auto &uvs_view = gltf_json["bufferViews"][uvs_view_index];
-
- auto uvs_buffer_index = uvs_view["buffer"].get<uint32_t>();
- auto uvs_offset = uvs_view["byteOffset"].get<size_t>();
- auto uvs_length = uvs_view["byteLength"].get<size_t>();
-
- auto &uvs_buffer = buffers_content[uvs_buffer_index];
- float* uvs_start = (float*)(uvs_buffer.data() + uvs_offset);
-
- part.uvs.resize(uvs_length / sizeof(float));
- std::memcpy(part.uvs.data(), uvs_start, uvs_length);
- }
-
- part.mat = materials[primitive["material"].get<uint32_t>()];
- part.vertices_count = part.positions.size() / 3;
- part.triangles_count = part.indices.size() / 3;
-
- return std::move(part);
-}
+#include "gltf.hpp" + +#include <fstream> +#include <cstring> + +#define STB_IMAGE_IMPLEMENTATION +#include "thirdparty/stb_image.h" + +#include "utils.hpp" + +node gltf::load(std::filesystem::path &path, std::string &filename, vkrenderer &renderer) { + std::fstream f(path / filename); + json gltf_json; + + f >> gltf_json; + + auto &scene = gltf_json["scenes"][0]; + + auto &buffers = gltf_json["buffers"]; + auto buffer_index = 0; + auto buffers_content = std::vector<std::vector<uint8_t>>(buffers.size()); + for (auto &buffer: buffers) { + auto buffer_path = (path / buffer["uri"].get<std::string>()).string(); + buffers_content[buffer_index] = read_file(buffer_path); + buffer_index++; + } + + auto textures = load_textures(gltf_json, path, renderer); + auto materials = load_materials(gltf_json, textures); + + auto meshes = load_meshes(gltf_json, buffers_content, materials); + + node root_node; + auto &root_children = scene["nodes"]; + uint32_t root_children_count = scene["nodes"].size(); + root_node.children.resize(root_children_count); + + for (size_t child_index = 0; child_index < root_children_count; child_index++) { + load_node(gltf_json, root_children[child_index].get<uint32_t>(), root_node.children[child_index], meshes); + } + + return std::move(root_node); +} + +void gltf::load_node(json &gltf_json, uint32_t index, node &parent, std::vector<mesh> &meshes) { + auto &gltf_node = gltf_json["nodes"][index]; + + if (gltf_node.contains("children")) { + auto &children = gltf_node["children"]; + uint32_t children_count = gltf_node["children"]; + parent.children.resize(children_count); + + for (size_t child_index = 0; child_index < children_count; child_index++) { + load_node(gltf_json, children[child_index].get<uint32_t>(), parent.children[child_index], meshes); + } + } + + if (gltf_node.contains("mesh")) { + parent.mesh = std::make_optional(meshes[gltf_node["mesh"].get<uint32_t>()]); + } +} + +std::vector<mesh> gltf::load_meshes(json &gltf_json, std::vector<std::vector<uint8_t>> &buffers_content, std::vector<material> &materials) { + auto &gltf_meshes = gltf_json["meshes"]; + auto meshes_count = gltf_meshes.size(); + std::vector<mesh> meshes { meshes_count }; + + for(size_t mesh_index = 0; mesh_index < meshes_count; mesh_index++) { + auto &gltf_mesh = gltf_meshes[mesh_index]; + auto &primitives = gltf_mesh["primitives"]; + auto &mesh = meshes[mesh_index]; + + for (auto& primitive: primitives) { + auto &&part = load_primitive(gltf_json, primitive, buffers_content, materials); + mesh.vertices_count += part.vertices_count; + mesh.triangles_count += part.triangles_count; + mesh.parts.emplace_back(std::move(part)); + } + } + + return std::move(meshes); +} + +std::vector<texture> gltf::load_textures(json &gltf_json, std::filesystem::path &path, vkrenderer &renderer) { + auto &gltf_images = gltf_json["images"]; + auto images_count = gltf_images.size(); + std::vector<Texture*> images { images_count }; + + for (size_t image_index = 0; image_index < images_count; image_index++) { + auto &gltf_image = gltf_images[image_index]; + int x,y,n; + auto filepath = (path / gltf_image["uri"].get<std::string>()).string(); + unsigned char *data = stbi_load(filepath.c_str(), &x, &y, &n, 4); + auto img = renderer.create_2d_texture(static_cast<uint32_t>(x), static_cast<uint32_t>(y), VK_FORMAT_R8G8B8A8_UNORM); + + renderer.update_image(img, data); + + stbi_image_free(data); + + images[image_index] = std::move(img); + } + + auto &gltf_samplers = gltf_json["samplers"]; + auto samplers_count = gltf_samplers.size(); + std::vector<Sampler*> samplers { samplers_count }; + + for (size_t sampler_index = 0; sampler_index < samplers_count; sampler_index++) { + samplers[sampler_index] = renderer.create_sampler(VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT); + } + + auto &gltf_textures = gltf_json["textures"]; + auto textures_count = gltf_textures.size(); + std::vector<texture> textures { textures_count }; + + for (size_t texture_index = 0; texture_index < textures_count; texture_index++) { + auto gltf_texture = gltf_textures[texture_index]; + + auto image_index = gltf_texture["source"].get<uint32_t>(); + auto &image = images[image_index]; + + uint32_t sampler_id = 0; + // if (gltf_texture.contains("sampler")) { + // auto sampler_index = gltf_texture["sampler"].get<uint32_t>(); + // auto &sampler = samplers[sampler_index]; + // sampler_id = sampler->device_sampler.bindless_index; + // } + + // textures[texture_index] = texture { + // .image_id = image->device_image.bindless_sampled_index, + // .sampler_id = sampler_id + // }; + } + + return std::move(textures); +} + +std::vector<material> gltf::load_materials(json &gltf_json, std::vector<texture> &textures) { + auto &gltf_materials = gltf_json["materials"]; + auto materials_count = gltf_materials.size(); + std::vector<material> materials { materials_count }; + + for(size_t material_index = 0; material_index < materials_count; material_index++) { + auto& gltf_material = gltf_materials[material_index]; + auto& material = materials[material_index]; + + if (gltf_material.contains("pbrMetallicRoughness")) { + auto &pbr_params = gltf_material["pbrMetallicRoughness"]; + + if (pbr_params.contains("baseColorFactor")) { + auto &base_color = pbr_params["baseColorFactor"]; + material.base_color.v[0] = base_color[0].get<float>(); + material.base_color.v[1] = base_color[1].get<float>(); + material.base_color.v[2] = base_color[2].get<float>(); + material.base_color.v[3] = base_color[3].get<float>(); + } else + material.base_color = vec3(1.f); + + if (pbr_params.contains("baseColorTexture")) { + auto base_color_index = pbr_params["baseColorTexture"]["index"].get<uint32_t>(); + material.base_color_texture = textures[base_color_index]; + } + + if (pbr_params.contains("metallicFactor")) + material.metalness = pbr_params["metallicFactor"].get<float>(); + else + material.metalness = 1.0; + + if (pbr_params.contains("roughnessFactor")) + material.roughness = pbr_params["roughnessFactor"].get<float>(); + else + material.roughness = 1.0; + + if (pbr_params.contains("metallicRoughnessTexture")) { + auto metallic_roughness_index = pbr_params["metallicRoughnessTexture"]["index"].get<uint32_t>(); + material.metallic_roughness_texture = textures[metallic_roughness_index]; + } + } + } + + return std::move(materials); +} + +mesh_part gltf::load_primitive(json &gltf_json, json &primitive, std::vector<std::vector<uint8_t>> &buffers_content, std::vector<material> &materials) { + auto part = mesh_part(); + auto &accessors = gltf_json["accessors"]; + + { + auto indices_accessor_index = primitive["indices"].get<uint32_t>(); + auto indices_view_index = accessors[indices_accessor_index]["bufferView"].get<uint32_t>(); + auto &indices_view = gltf_json["bufferViews"][indices_view_index]; + + auto indices_buffer_index = indices_view["buffer"].get<uint32_t>(); + auto indices_offset = indices_view["byteOffset"].get<size_t>(); + auto indices_length = indices_view["byteLength"].get<size_t>(); + + auto &indices_buffer = buffers_content[indices_buffer_index]; + uint16_t* indices_start = (uint16_t*)(indices_buffer.data() + indices_offset); + + part.indices.resize(indices_length / sizeof(uint16_t)); + std::memcpy(part.indices.data(), indices_start, indices_length); + } + + { + auto positions_accessor_index = primitive["attributes"]["POSITION"].get<uint32_t>(); + auto positions_view_index = accessors[positions_accessor_index]["bufferView"].get<uint32_t>(); + auto &positions_view = gltf_json["bufferViews"][positions_view_index]; + + auto positions_buffer_index = positions_view["buffer"].get<uint32_t>(); + auto positions_offset = positions_view["byteOffset"].get<size_t>(); + auto positions_length = positions_view["byteLength"].get<size_t>(); + + auto &positions_buffer = buffers_content[positions_buffer_index]; + float* positions_start = (float*)(positions_buffer.data() + positions_offset); + + part.positions.resize(positions_length / sizeof(float)); + std::memcpy(part.positions.data(), positions_start, positions_length); + } + + { + auto normals_accessor_index = primitive["attributes"]["NORMAL"].get<uint32_t>(); + auto normals_view_index = accessors[normals_accessor_index]["bufferView"].get<uint32_t>(); + auto &normals_view = gltf_json["bufferViews"][normals_view_index]; + + auto normals_buffer_index = normals_view["buffer"].get<uint32_t>(); + auto normals_offset = normals_view["byteOffset"].get<size_t>(); + auto normals_length = normals_view["byteLength"].get<size_t>(); + + auto &normals_buffer = buffers_content[normals_buffer_index]; + float* normals_start = (float*)(normals_buffer.data() + normals_offset); + + part.normals.resize(normals_length / sizeof(float)); + std::memcpy(part.normals.data(), normals_start, normals_length); + } + + { + auto uvs_accessor_index = primitive["attributes"]["TEXCOORD_0"].get<uint32_t>(); + auto uvs_view_index = accessors[uvs_accessor_index]["bufferView"].get<uint32_t>(); + auto &uvs_view = gltf_json["bufferViews"][uvs_view_index]; + + auto uvs_buffer_index = uvs_view["buffer"].get<uint32_t>(); + auto uvs_offset = uvs_view["byteOffset"].get<size_t>(); + auto uvs_length = uvs_view["byteLength"].get<size_t>(); + + auto &uvs_buffer = buffers_content[uvs_buffer_index]; + float* uvs_start = (float*)(uvs_buffer.data() + uvs_offset); + + part.uvs.resize(uvs_length / sizeof(float)); + std::memcpy(part.uvs.data(), uvs_start, uvs_length); + } + + part.mat = materials[primitive["material"].get<uint32_t>()]; + part.vertices_count = part.positions.size() / 3; + part.triangles_count = part.indices.size() / 3; + + return std::move(part); +} diff --git a/src/main.cpp b/src/main.cpp index 45e30a3..6dbfc50 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,45 +1,54 @@ -#include <iostream> +#include <cassert> #include <chrono> -#include <cstring> #include <cstdio> -#include <cassert> +#include <cstring> +#include <iostream> -#include "thirdparty/renderdoc.h" #include "imgui.h" +#include "thirdparty/renderdoc.h" #include "compute-renderpass.hpp" +#include "primitive-renderpass.hpp" +#include "defines.hpp" +#include "scene.hpp" #include "vk-renderer.hpp" #include "window.hpp" -#include "scene.hpp" -#include "defines.hpp" #if defined(LINUX) -#include <unistd.h> #include <dlfcn.h> +#include <unistd.h> #elif defined(WINDOWS) #include <Windows.h> #endif +struct VkVertex { + float x, y; + float u, v; + uint32_t color; + uint32_t padding[3]; +}; + int main() { RENDERDOC_API_1_1_2 *rdoc_api = NULL; #ifdef WINDOWS // At init, on windows - if(HMODULE mod = GetModuleHandleA("renderdoc.dll")) - { - pRENDERDOC_GetAPI RENDERDOC_GetAPI = - (pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI"); - int ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void **)&rdoc_api); - assert(ret == 1); + if (HMODULE mod = GetModuleHandleA("renderdoc.dll")) { + pRENDERDOC_GetAPI RENDERDOC_GetAPI = + (pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI"); + int ret = + RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void **)&rdoc_api); + assert(ret == 1); } #elif defined(LINUX) // At init, on linux/android. // For android replace librenderdoc.so with libVkLayer_GLES_RenderDoc.so - if(void *mod = dlopen("librenderdoc.so", RTLD_NOW | RTLD_NOLOAD)) - { - pRENDERDOC_GetAPI RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)dlsym(mod, "RENDERDOC_GetAPI"); - int ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void **)&rdoc_api); - assert(ret == 1); + if (void *mod = dlopen("librenderdoc.so", RTLD_NOW | RTLD_NOLOAD)) { + pRENDERDOC_GetAPI RENDERDOC_GetAPI = + (pRENDERDOC_GetAPI)dlsym(mod, "RENDERDOC_GetAPI"); + int ret = + RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void **)&rdoc_api); + assert(ret == 1); } #endif @@ -48,21 +57,24 @@ int main() { uint32_t width = 400; uint32_t height = width / aspect_ratio; - window wnd { width , height }; + window wnd{width, height}; float delta_time = 0.f; uint64_t frame_count = 0; auto start = std::chrono::high_resolution_clock::now(); auto end = std::chrono::high_resolution_clock::now(); - point3 position = { 13.0, 2.0, -3.0 }; - point3 target = { 0.0, 0.0, 0.0 }; + point3 position = {13.0, 2.0, -3.0}; + point3 target = {0.0, 0.0, 0.0}; auto v_fov = 90; auto aperture = 0.1; auto focus_distance = 10; auto cam = camera(position, target, v_fov, (float)width / (float)height, aperture, focus_distance); - vkrenderer renderer { wnd }; + vkrenderer renderer{wnd}; + + ImGui::CreateContext(); + auto& io = ImGui::GetIO(); auto main_scene = scene(cam, width, height, renderer); @@ -70,8 +82,8 @@ int main() { auto raytracing_pass = renderer.create_compute_renderpass(); raytracing_pass->set_pipeline(raytracing_shader_name); - auto* accumulation_texture = renderer.create_2d_texture(width, height, VK_FORMAT_R32G32B32A32_SFLOAT); - auto* output_texture = renderer.create_2d_texture(width, height, VK_FORMAT_R32G32B32A32_SFLOAT); + auto *accumulation_texture = renderer.create_2d_texture(width, height, VK_FORMAT_R32G32B32A32_SFLOAT); + auto *output_texture = renderer.create_2d_texture(width, height, VK_FORMAT_R32G32B32A32_SFLOAT); raytracing_pass->set_constant(8, main_scene.bvh_buffer); raytracing_pass->set_constant(16, main_scene.indices_buffer); raytracing_pass->set_constant(24, main_scene.positions_buffer); @@ -79,27 +91,43 @@ int main() { raytracing_pass->set_constant(40, main_scene.uvs_buffer); raytracing_pass->set_constant(48, main_scene.materials_buffer); + uint8_t *pixels = nullptr; + int atlas_width, atlas_height; + io.Fonts->GetTexDataAsRGBA32(&pixels, &atlas_width, &atlas_height); + auto *ui_texture = renderer.create_2d_texture(atlas_width, atlas_height, VK_FORMAT_R8G8B8A8_UNORM); + io.Fonts->SetTexID((void *)&ui_texture); + + renderer.update_image(ui_texture, pixels); + auto ui_texture_sampler = renderer.create_sampler(VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); + + Buffer* ui_vertex_buffer = nullptr; + Buffer* ui_index_buffer = nullptr; + + std::string ui_shader_name = "ui"; + std::vector<Primitive*> ui_primitives; + auto ui_pass = renderer.create_primitive_renderpass(); + ui_pass->set_viewport(0.f, 0.f, (float)width, (float)height); + ui_pass->add_color_attachment(renderer.back_buffer_format()); + ui_pass->finalize_render_pass(); auto can_render = true; - ImGuiIO& io = ImGui::GetIO(); io.DisplaySize.x = (float)width; io.DisplaySize.y = (float)height; - while(wnd.isOpen) { + while (wnd.isOpen) { end = std::chrono::high_resolution_clock::now(); delta_time = std::chrono::duration<float, std::milli>(end - start).count(); start = std::chrono::high_resolution_clock::now(); - ImGuiIO& io = ImGui::GetIO(); io.DeltaTime = delta_time; wnd.poll_events(); - for (auto event: wnd.events) { - switch(event.type) { + for (auto event : wnd.events) { + switch (event.type) { case EVENT_TYPES::RESIZE: { width = event.width; height = event.height; @@ -133,7 +161,7 @@ int main() { move_speed *= 10.f; } - vec3 move_vec {}; + vec3 move_vec{}; switch (event.key) { case KEYS::W: { @@ -201,10 +229,7 @@ int main() { break; } case EVENT_TYPES::MOUSE_MOVE: { - io.MousePos = ImVec2 { - (float)event.x, - (float)event.y - }; + io.MousePos = ImVec2{(float)event.x, (float)event.y}; break; } default: @@ -215,51 +240,150 @@ int main() { wnd.events.clear(); // GUI - ImGui::NewFrame(); + if (can_render) { + ImGui::NewFrame(); - ImGui::SetNextWindowPos({ 0.f, 0.f }); - ImGui::SetNextWindowSize({ 0.f, 0.f }); - ImGui::Begin("Debug", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar); + // ImGui::SetNextWindowPos({0.f, 0.f}); + // ImGui::SetNextWindowSize({0.f, 0.f}); + // ImGui::Begin("Debug", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar); - ImGui::Text("frame per second %u\n", static_cast<uint32_t>(1000.f / delta_time)); - ImGui::Text("frame time %f ms\n", delta_time); - ImGui::Text("frame count %u\n", main_scene.meta.sample_index); + // ImGui::Text("frame per second %u\n", static_cast<uint32_t>(1000.f / delta_time)); + // ImGui::Text("frame time %f ms\n", delta_time); + // ImGui::Text("frame count %u\n", main_scene.meta.sample_index); - if (ImGui::Checkbox("depth of field", (bool*)&main_scene.meta.enable_dof)) { - main_scene.meta.sample_index = 1; - } + // if (ImGui::Checkbox("depth of field", (bool*)&main_scene.meta.enable_dof)) { + // main_scene.meta.sample_index = 1; + // } - ImGui::SliderInt("max bounces", (int32_t*)&main_scene.meta.max_bounce, 1, 250); - ImGui::SliderInt("min bounces", (int32_t*)&main_scene.meta.min_bounce, 1, main_scene.meta.max_bounce); - if (ImGui::SliderInt("downscale factor", (int32_t*)&main_scene.meta.downscale_factor, 1, 32)) { - main_scene.meta.sample_index = 1; - } + // ImGui::SliderInt("max bounces", (int32_t *)&main_scene.meta.max_bounce, 1, 250); + // ImGui::SliderInt("min bounces", (int32_t *)&main_scene.meta.min_bounce, 1, main_scene.meta.max_bounce); + // if (ImGui::SliderInt("downscale factor", (int32_t *)&main_scene.meta.downscale_factor, 1, 32)) { + // main_scene.meta.sample_index = 1; + // } - if (ImGui::Checkbox("debug bvh", (bool*)&main_scene.meta.debug_bvh)) { - main_scene.meta.sample_index = 1; - } + // if (ImGui::Checkbox("debug bvh", (bool *)&main_scene.meta.debug_bvh)) { + // main_scene.meta.sample_index = 1; + // } - ImGui::End(); + // ImGui::End(); + bool open = true; + ImGui:ImGui::ShowDemoWindow(&open); - ImGui::EndFrame(); + ImGui::EndFrame(); - // To start a frame capture, call StartFrameCapture. - // You can specify NULL, NULL for the device to capture on if you have only one device and - // either no windows at all or only one window, and it will capture from that device. - // See the documentation below for a longer explanation - // if(rdoc_api) rdoc_api->StartFrameCapture(NULL, NULL); + ImGui::Render(); - // renderer.ui(); + // To start a frame capture, call StartFrameCapture. + // You can specify NULL, NULL for the device to capture on if you have only + // one device and either no windows at all or only one window, and it will + // capture from that device. See the documentation below for a longer + // explanation if(rdoc_api) rdoc_api->StartFrameCapture(NULL, NULL); - if (can_render) { - std::memcpy(main_scene.scene_buffer->ptr(), &main_scene.meta, sizeof(main_scene.meta)); + renderer.update_buffer(main_scene.scene_buffer, &main_scene.meta, 0, sizeof(main_scene.meta)); raytracing_pass->set_ouput_texture(output_texture); raytracing_pass->set_constant(0, main_scene.scene_buffer); raytracing_pass->set_constant(60, accumulation_texture); + ImDrawData* draw_data = ImGui::GetDrawData(); + + ui_pass->set_viewport(0.f, 0.f, (float)draw_data->DisplaySize.x, (float)draw_data->DisplaySize.y); + + auto previous_size = ui_primitives.size(); + auto commands_count = 0; + + for (uint32_t draw_list_index = 0; draw_list_index < draw_data->CmdListsCount; draw_list_index++) { + commands_count += draw_data->CmdLists[draw_list_index]->CmdBuffer.size(); + } + + if (ui_primitives.size() < commands_count) { + ui_primitives.resize(commands_count); + + for (size_t index = previous_size; index < ui_primitives.size(); index++) { + ui_primitives[index] = renderer.create_primitive(*ui_pass); + ui_primitives[index]->set_pipeline(ui_shader_name); + ui_primitives[index]->set_constant_offset(64); + ui_primitives[index]->set_constant(32, ui_texture); + ui_primitives[index]->set_constant(36, ui_texture_sampler); + } + } + + float scale[] { + 2.f / draw_data->DisplaySize.x, + 2.f / draw_data->DisplaySize.y, + }; + float translate[] { + -1.f - draw_data->DisplayPos.x * (2.f / draw_data->DisplaySize.x), + -1.f - draw_data->DisplayPos.y * (2.f / draw_data->DisplaySize.y), + }; + + if (!ui_vertex_buffer || ui_vertex_buffer->size < draw_data->TotalVtxCount * sizeof(VkVertex)) { + ui_vertex_buffer = renderer.create_buffer(draw_data->TotalVtxCount * sizeof(VkVertex), false); + + for (auto& primitive : ui_primitives) { + primitive->set_constant(0, ui_vertex_buffer); + } + } + + if (!ui_index_buffer || ui_index_buffer->size < draw_data->TotalIdxCount * sizeof(ImDrawIdx)) { + ui_index_buffer = renderer.create_index_buffer(draw_data->TotalIdxCount * sizeof(ImDrawIdx), false); + + for (auto& primitive : ui_primitives) { + primitive->set_index_buffer(ui_index_buffer); + } + } + + off_t vertex_buffer_offset = 0; + off_t index_buffer_offset = 0; + std::vector<VkVertex> vertices; + uint32_t draw_call_index = 0; + for (uint32_t draw_list_index = 0; draw_list_index < draw_data->CmdListsCount; draw_list_index++) { + auto& vertex_buffer = draw_data->CmdLists[draw_list_index]->VtxBuffer; + auto& index_buffer = draw_data->CmdLists[draw_list_index]->IdxBuffer; + vertices.resize(vertex_buffer.size()); + + for (size_t vert_index = 0; vert_index < vertex_buffer.Size; vert_index++) { + vertices[vert_index] = *((VkVertex*)&vertex_buffer[vert_index]); + } + + renderer.update_buffer(ui_vertex_buffer, vertices.data(), vertex_buffer_offset * sizeof(VkVertex), vertices.size() * sizeof(VkVertex)); + renderer.update_buffer(ui_index_buffer, index_buffer.Data, index_buffer_offset * sizeof(ImDrawIdx), index_buffer.size() * sizeof(ImDrawIdx)); + + ImDrawList* draw_list = draw_data->CmdLists[draw_list_index]; + for (auto& draw_cmd: draw_list->CmdBuffer) { + auto& current_primitive = ui_primitives[draw_call_index]; + current_primitive->set_constant(8, (uint64_t*)&scale); + current_primitive->set_constant(16, (uint64_t*)&translate); + + ImVec2 pos = draw_data->DisplayPos; + current_primitive->set_scissor( + (int32_t)draw_cmd.ClipRect.x - pos.x, + (int32_t)draw_cmd.ClipRect.y - pos.y, + (uint32_t)draw_cmd.ClipRect.z - pos.x, + (uint32_t)draw_cmd.ClipRect.w - pos.y + ); + + current_primitive->set_draw_info( + draw_cmd.ElemCount, + index_buffer_offset + draw_cmd.IdxOffset, + vertex_buffer_offset + draw_cmd.VtxOffset + ); + + ui_pass->add_primitive(current_primitive); + draw_call_index++; + } + + vertex_buffer_offset += vertex_buffer.Size; + index_buffer_offset += index_buffer.Size; + } + + renderer.begin_frame(); + + ui_pass->set_color_attachment(0, renderer.back_buffer()); + renderer.render(); + renderer.finish_frame(); main_scene.meta.sample_index++; @@ -282,7 +406,6 @@ int main() { // write_color(std::cout, output_image[index]); // } - std::cerr << "Done !" << std::endl; return 0; diff --git a/src/primitive-renderpass.cpp b/src/primitive-renderpass.cpp new file mode 100644 index 0000000..f8521e3 --- /dev/null +++ b/src/primitive-renderpass.cpp @@ -0,0 +1,150 @@ +#include "primitive-renderpass.hpp" + +#include "vk-renderer.hpp" +#include "vulkan/vulkan_core.h" +#include <stdint.h> + + +void Primitive::set_pipeline(std::string &shader_name) { + std::vector<VkDynamicState> dynamic_states { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR + }; + + pipeline = api.create_graphics_pipeline(shader_name.c_str(), (VkShaderStageFlagBits)(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT), primitive_render_pass.render_pass, dynamic_states); +} + +void Primitive::set_constant_offset(off_t offset) { + constant_offset = offset; +} + +void Primitive::set_constant(off_t offset, uint64_t* constant) { + memcpy(constants.data() + offset, constant, sizeof(uint64_t)); +} + +void Primitive::set_constant(off_t offset, Texture* texture) { + auto image = api.get_image(texture->device_image); + + memcpy(constants.data() + offset, (void*)&image.bindless_storage_index, sizeof(bindless_index)); +} + +void Primitive::set_constant(off_t offset, Buffer* buffer) { + auto device_buffer = api.get_buffer(buffer->device_buffer); + memcpy(constants.data() + offset, (void*)&device_buffer.device_address, sizeof(VkDeviceAddress)); +} + +void Primitive::set_constant(off_t offset, Sampler* sampler) { + auto device_sampler = api.get_sampler(sampler->device_sampler); + memcpy(constants.data() + offset, (void*)&device_sampler.bindless_index, sizeof(bindless_index)); +} + +void Primitive::set_index_buffer(Buffer* index_buffer) { + this->index_buffer = index_buffer; +} + +void Primitive::set_scissor(int32_t x, int32_t y, uint32_t width, uint32_t height) { + scissor.offset.x = x; + scissor.offset.y = y; + scissor.extent.width = width; + scissor.extent.height = height; +} + +void Primitive::set_draw_info(size_t vertex_count, off_t first_vertex, off_t vertex_offset) { + this->element_count = vertex_count; + this->first_vertex = first_vertex; + this->vertex_offset = vertex_offset; +} + +void Primitive::render(VkCommandBuffer command_buffer) { + vkCmdSetScissor(command_buffer, 0, 1, &scissor); + + api.update_constants(command_buffer, VK_SHADER_STAGE_ALL_GRAPHICS, constant_offset, 64, (void*)&constants); + + api.draw( + command_buffer, + pipeline, + index_buffer->device_buffer, + element_count, + first_vertex, + vertex_offset + ); +}; + + +PrimitiveRenderpass::PrimitiveRenderpass(vkapi& api) + : Renderpass(api) { + }; + +void PrimitiveRenderpass::add_primitive(Primitive* new_primitive) { + primitives.push_back(new_primitive); +} + +void PrimitiveRenderpass::add_color_attachment(VkFormat format) { + color_attachments_format.push_back(format); +} + +void PrimitiveRenderpass::set_viewport(float x, float y, float width, float height) { + viewport.x = x; + viewport.y = y; + viewport.width = width; + viewport.height = height; +} + +void PrimitiveRenderpass::set_color_attachment(uint32_t index, Texture* attachment) { + auto device_image = api.get_image(attachment->device_image); + + if (device_image.size.width != framebuffers[0].size.width || + device_image.size.height != framebuffers[0].size.height) { + recreate_framebuffers(); + } + + + color_attachments[index] = attachment; + color_attachments_view[index] = device_image.view; +} + +void PrimitiveRenderpass::finalize_render_pass() { + render_pass = api.create_render_pass(color_attachments_format, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + + create_framebuffers(); + + color_attachments.resize(color_attachments_format.size()); + color_attachments_view.resize(color_attachments_format.size()); +} + +void PrimitiveRenderpass::execute(vkrenderer& renderer, VkCommandBuffer command_buffer) { + VkExtent2D extent = { .width = (uint32_t)viewport.width, .height = (uint32_t)viewport.height }; + + for (auto& attachment : color_attachments) { + api.image_barrier(command_buffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, attachment->device_image); + } + + + api.begin_render_pass(command_buffer, render_pass, color_attachments_view, framebuffers[renderer.frame_index()], extent); + + vkCmdSetViewport(command_buffer, 0, 1, &viewport); + + for (auto primitive : primitives) { + primitive->render(command_buffer); + } + + api.end_render_pass(command_buffer); + + primitives.clear(); +} + +void PrimitiveRenderpass::create_framebuffers() { + VkExtent2D size { .width = (uint32_t) viewport.width, .height = (uint32_t) viewport.height }; + + for(auto& framebuffer : framebuffers) { + framebuffer = api.create_framebuffer(render_pass, color_attachments_format, size); + } +} + +void PrimitiveRenderpass::recreate_framebuffers() { + for (auto& framebuffer: framebuffers) { + api.destroy_framebuffer(framebuffer); + } + + create_framebuffers(); +} diff --git a/src/scene.cpp b/src/scene.cpp index 44c8f8e..871ba68 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -124,23 +124,23 @@ scene::scene(camera cam, uint32_t width, uint32_t height, vkrenderer &renderer) // bvh builder(spheres, packed_nodes);
scene_buffer = renderer.create_buffer(sizeof(meta), false);
- std::memcpy(scene_buffer->ptr(), &meta, sizeof(meta));
+ renderer.update_buffer(scene_buffer, &meta, 0, sizeof(meta));
indices_buffer = renderer.create_buffer(indices.size() * sizeof(indices[0]), true);
- std::memcpy(indices_buffer->ptr(), indices.data(), indices.size() * sizeof(indices[0]));
+ renderer.update_buffer(indices_buffer, indices.data(), 0, indices.size() * sizeof(indices[0]));
positions_buffer = renderer.create_buffer(positions.size() * sizeof(positions[0]), true);
- std::memcpy(positions_buffer->ptr(), positions.data(), positions.size() * sizeof(positions[0]));
+ renderer.update_buffer(positions_buffer, positions.data(), 0, positions.size() * sizeof(positions[0]));
normals_buffer = renderer.create_buffer(normals.size() * sizeof(normals[0]), true);
- std::memcpy(normals_buffer->ptr(), normals.data(), normals.size() * sizeof(normals[0]));
+ renderer.update_buffer(normals_buffer, normals.data(), 0, normals.size() * sizeof(normals[0]));
uvs_buffer = renderer.create_buffer(uvs.size() * sizeof(uvs[0]), true);
- std::memcpy(uvs_buffer->ptr(), uvs.data(), uvs.size() * sizeof(uvs[0]));
+ renderer.update_buffer(uvs_buffer, uvs.data(), 0, uvs.size() * sizeof(uvs[0]));
bvh_buffer = renderer.create_buffer(packed_nodes.size() * sizeof(packed_nodes[0]), true);
- std::memcpy(bvh_buffer->ptr(), packed_nodes.data(), packed_nodes.size() * sizeof(packed_nodes[0]));
+ renderer.update_buffer(bvh_buffer, packed_nodes.data(), 0, packed_nodes.size() * sizeof(packed_nodes[0]));
materials_buffer = renderer.create_buffer(materials.size() * sizeof(materials[0]), true);
- std::memcpy(materials_buffer->ptr(), materials.data(), materials.size() * sizeof(materials[0]));
+ renderer.update_buffer(materials_buffer, materials.data(), 0, materials.size() * sizeof(materials[0]));
}
diff --git a/src/vk-api.cpp b/src/vk-api.cpp index 226314a..1000079 100644 --- a/src/vk-api.cpp +++ b/src/vk-api.cpp @@ -2,6 +2,7 @@ #include <memory> #include "vk-api.hpp" +#include "vulkan-loader.hpp" #include "window.hpp" #include "utils.hpp" @@ -100,15 +101,20 @@ vkapi::vkapi() { .size = 64, }, { - .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + .stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS, .offset = 64, - .size = 32, - }, - { - .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, - .offset = 96, - .size = 32, + .size = 64, }, + // { + // .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + // .offset = 64, + // .size = 32, + // }, + // { + // .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + // .offset = 96, + // .size = 32, + // }, }; VkPipelineLayoutCreateInfo layout_create_info = {}; @@ -135,14 +141,17 @@ vkapi::vkapi() { vkapi::~vkapi() { // Free resources - while (buffers.size()) - destroy_buffer(buffers.begin()->second); + for (handle buffer_handle = 0; buffer_handle < buffers.size(); buffer_handle++) { + destroy_buffer(buffer_handle); + } - while (images.size()) - destroy_image(images.begin()->second); + for (handle image_handle = 0; image_handle < images.size(); image_handle++) { + destroy_image(image_handle); + } - while (samplers.size()) - destroy_sampler(samplers.begin()->second); + for(handle sampler_handle = 0; sampler_handle < samplers.size(); sampler_handle++) { + destroy_sampler(sampler_handle); + } // Free bindless descriptor stuff vkDestroyDescriptorSetLayout(context.device, bindless_descriptor.set_layout, nullptr); @@ -154,8 +163,8 @@ vkapi::~vkapi() { } -buffer vkapi::create_buffer(size_t data_size, VkBufferUsageFlags buffer_usage, VmaMemoryUsage mem_usage) { - buffer buffer = {}; +handle vkapi::create_buffer(size_t data_size, VkBufferUsageFlags buffer_usage, VmaMemoryUsage mem_usage) { + struct buffer* buffer = new struct buffer(); VkBufferCreateInfo buffer_info = {}; buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; @@ -166,34 +175,36 @@ buffer vkapi::create_buffer(size_t data_size, VkBufferUsageFlags buffer_usage, V alloc_create_info.usage = mem_usage; alloc_create_info.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; - VKRESULT(vmaCreateBuffer(context.allocator, &buffer_info, &alloc_create_info, &buffer.handle, &buffer.alloc, &buffer.alloc_info)) + VKRESULT(vmaCreateBuffer(context.allocator, &buffer_info, &alloc_create_info, &buffer->handle, &buffer->alloc, &buffer->alloc_info)) VkBufferDeviceAddressInfo buffer_device_address_info = {}; buffer_device_address_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; buffer_device_address_info.pNext = VK_NULL_HANDLE; - buffer_device_address_info.buffer = buffer.handle; + buffer_device_address_info.buffer = buffer->handle; - buffer.size = data_size; + buffer->size = data_size; - buffer.device_address = vkGetBufferDeviceAddress(context.device, &buffer_device_address_info); + buffer->device_address = vkGetBufferDeviceAddress(context.device, &buffer_device_address_info); - buffers.insert({ buffer.handle, buffer }); + buffers.push_back(buffer); - return std::move(buffer); + return buffers.size() - 1; } -void vkapi::copy_buffer(VkCommandBuffer cmd_buf, buffer src, buffer dst, size_t size) { +void vkapi::copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst, size_t size) { VkBufferCopy buffer_copy = {}; buffer_copy.srcOffset = 0; buffer_copy.dstOffset = 0; buffer_copy.size = size; - vkCmdCopyBuffer(cmd_buf, src.handle, dst.handle, 1, &buffer_copy); + vkCmdCopyBuffer(cmd_buf, buffers[src]->handle, buffers[dst]->handle, 1, &buffer_copy); } -void vkapi::copy_buffer(VkCommandBuffer cmd_buf, buffer src, image dst) { +void vkapi::copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst) { + auto& dst_image = images[dst]; + VkImageSubresourceLayers image_subresource_layers = {}; - image_subresource_layers.aspectMask = dst.subresource_range.aspectMask; + image_subresource_layers.aspectMask = dst_image->subresource_range.aspectMask; image_subresource_layers.mipLevel = 0; image_subresource_layers.baseArrayLayer = 0; image_subresource_layers.layerCount = 1; @@ -204,28 +215,29 @@ void vkapi::copy_buffer(VkCommandBuffer cmd_buf, buffer src, image dst) { buffer_to_image_copy.bufferImageHeight = 0; buffer_to_image_copy.imageSubresource = image_subresource_layers; buffer_to_image_copy.imageOffset = { 0, 0, 0 }; - buffer_to_image_copy.imageExtent = dst.size; + buffer_to_image_copy.imageExtent = dst_image->size; - vkCmdCopyBufferToImage(cmd_buf, src.handle, dst.handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_to_image_copy); + vkCmdCopyBufferToImage(cmd_buf, buffers[src]->handle, dst_image->handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_to_image_copy); } -void vkapi::destroy_buffer(buffer& buffer) { - vmaDestroyBuffer(context.allocator, buffer.handle, buffer.alloc); +void vkapi::destroy_buffer(handle buffer) { + vmaDestroyBuffer(context.allocator, buffers[buffer]->handle, buffers[buffer]->alloc); - buffers.erase(buffer.handle); + // TODO: Free the element once using freelists + // buffers.erase(buffer.handle); } -image vkapi::create_image(VkExtent3D size, VkFormat format, VkImageUsageFlags usages) { - image image; +handle vkapi::create_image(VkExtent3D size, VkFormat format, VkImageUsageFlags usages) { + struct image* image = new struct image(); - image.size = size; + image->size = size; - image.subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - image.subresource_range.baseMipLevel = 0; - image.subresource_range.levelCount = 1; - image.subresource_range.baseArrayLayer = 0; - image.subresource_range.layerCount = 1; + image->subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image->subresource_range.baseMipLevel = 0; + image->subresource_range.levelCount = 1; + image->subresource_range.baseArrayLayer = 0; + image->subresource_range.layerCount = 1; VkImageCreateInfo img_create_info = {}; img_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; @@ -247,13 +259,13 @@ image vkapi::create_image(VkExtent3D size, VkFormat format, VkImageUsageFlags us VmaAllocationCreateInfo alloc_create_info = {}; alloc_create_info.usage = VMA_MEMORY_USAGE_GPU_ONLY; - VKRESULT(vmaCreateImage(context.allocator, &img_create_info, &alloc_create_info, &image.handle, &image.alloc, &image.alloc_info)) + VKRESULT(vmaCreateImage(context.allocator, &img_create_info, &alloc_create_info, &image->handle, &image->alloc, &image->alloc_info)) VkImageViewCreateInfo image_view_create_info = {}; image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; image_view_create_info.pNext = nullptr; image_view_create_info.flags = 0; - image_view_create_info.image = image.handle; + image_view_create_info.image = image->handle; image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; image_view_create_info.format = format; image_view_create_info.components = { @@ -262,41 +274,54 @@ image vkapi::create_image(VkExtent3D size, VkFormat format, VkImageUsageFlags us VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY }; - image_view_create_info.subresourceRange = image.subresource_range; + image_view_create_info.subresourceRange = image->subresource_range; + + VKRESULT(vkCreateImageView(context.device, &image_view_create_info, VK_NULL_HANDLE, &image->view)) + + image->usages = usages; - VKRESULT(vkCreateImageView(context.device, &image_view_create_info, VK_NULL_HANDLE, &image.view)) + images.push_back(image); - image.bindless_storage_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); - image.bindless_sampled_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); + auto image_handle = images.size() - 1; - images.insert({ image.handle, image }); + if (usages & VK_IMAGE_USAGE_STORAGE_BIT) { + image->bindless_storage_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); + update_descriptor_image(image_handle, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); + } + + if (usages & VK_IMAGE_USAGE_SAMPLED_BIT) { + image->bindless_sampled_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); + update_descriptor_image(image_handle, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); + } - return std::move(image); + return image_handle; } -void vkapi::destroy_image(image &image) { - bindless_descriptor.free(image.bindless_storage_index, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); - bindless_descriptor.free(image.bindless_sampled_index, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); +void vkapi::destroy_image(handle image) { + auto current_image = images[image]; + bindless_descriptor.free(current_image->bindless_storage_index, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); + bindless_descriptor.free(current_image->bindless_sampled_index, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); - vmaDestroyImage(context.allocator, image.handle, image.alloc); - vkDestroyImageView(context.device, image.view, nullptr); + vmaDestroyImage(context.allocator, current_image->handle, current_image->alloc); + vkDestroyImageView(context.device, current_image->view, nullptr); - images.erase(image.handle); + // TODO: Free once using freelist + // images.erase(image.handle); } -std::vector<image> vkapi::create_images(VkExtent3D size, VkFormat format, VkImageUsageFlags usages, size_t image_count) { - std::vector<image> images { image_count }; +std::vector<handle> vkapi::create_images(VkExtent3D size, VkFormat format, VkImageUsageFlags usages, size_t image_count) { + std::vector<handle> images_handles(image_count); for (size_t image_index = 0; image_index < image_count; image_index++) { - images[image_index] = create_image(size, format, usages); + images_handles[image_index] = create_image(size, format, usages); } - return std::move(images); + return std::move(images_handles); } -void vkapi::destroy_images(std::vector<image> &images) { - for (auto &image: images) { - destroy_image(image); +void vkapi::destroy_images(std::vector<handle> &images) { + for (auto handle: images) { + destroy_image(handle); } } @@ -367,7 +392,7 @@ void vkapi::destroy_semaphores(std::vector<VkSemaphore> &semaphores) { } -sampler vkapi::create_sampler(VkFilter filter, VkSamplerAddressMode address_mode) { +handle vkapi::create_sampler(VkFilter filter, VkSamplerAddressMode address_mode) { VkSamplerCreateInfo sampler_create_info = {}; sampler_create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; sampler_create_info.pNext = VK_NULL_HANDLE; @@ -387,22 +412,26 @@ sampler vkapi::create_sampler(VkFilter filter, VkSamplerAddressMode address_mode sampler_create_info.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; sampler_create_info.unnormalizedCoordinates = VK_FALSE; - sampler sampler; - VKRESULT(vkCreateSampler(context.device, &sampler_create_info, VK_NULL_HANDLE, &sampler.handle)) + struct sampler* sampler = new struct sampler(); + VKRESULT(vkCreateSampler(context.device, &sampler_create_info, VK_NULL_HANDLE, &sampler->handle)) - sampler.bindless_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_SAMPLER); + sampler->bindless_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_SAMPLER); - samplers.insert({ sampler.handle, sampler }); - return std::move(sampler); + samplers.push_back(sampler); + + update_descriptor_sampler(samplers.size() - 1); + + return samplers.size() - 1; } -void vkapi::destroy_sampler(sampler sampler) { - bindless_descriptor.free(sampler.bindless_index, VK_DESCRIPTOR_TYPE_SAMPLER); +void vkapi::destroy_sampler(handle sampler) { + auto current_sampler = samplers[sampler]; + bindless_descriptor.free(current_sampler->bindless_index, VK_DESCRIPTOR_TYPE_SAMPLER); - vkDestroySampler(context.device, sampler.handle, VK_NULL_HANDLE); + vkDestroySampler(context.device, current_sampler->handle, VK_NULL_HANDLE); - samplers.erase(sampler.handle); + // samplers.erase(sampler.handle); } @@ -436,12 +465,13 @@ VkRenderPass vkapi::create_render_pass(std::vector<VkFormat>& color_attachments_ attachment_description.flags = 0; attachment_description.format = format; attachment_description.samples = VK_SAMPLE_COUNT_1_BIT; - attachment_description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - attachment_description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachment_description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; // TODO: Set based on render pass usage + attachment_description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; // TODO: Set based on render pass usage + attachment_description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachment_description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; attachment_description.initialLayout = initial_layout; - attachment_description.finalLayout = initial_layout; + attachment_description.finalLayout = final_layout; attachments_description.push_back(attachment_description); @@ -462,6 +492,29 @@ VkRenderPass vkapi::create_render_pass(std::vector<VkFormat>& color_attachments_ subpass_description.preserveAttachmentCount = 0; subpass_description.pPreserveAttachments = VK_NULL_HANDLE; + + + VkSubpassDependency subpass_dependency[2] = {}; + subpass_dependency[0].srcSubpass = VK_SUBPASS_EXTERNAL; + subpass_dependency[0].dstSubpass = 1; // First subpass attachment is used in + subpass_dependency[0].srcStageMask = VK_PIPELINE_STAGE_NONE_KHR; + subpass_dependency[0].dstStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + subpass_dependency[0].srcAccessMask = 0; + subpass_dependency[0].dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + subpass_dependency[0].dependencyFlags = 0; + + + subpass_dependency[1].srcSubpass = 1; // Last subpass attachment is used in + subpass_dependency[1].dstSubpass = VK_SUBPASS_EXTERNAL; + subpass_dependency[1].srcStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + subpass_dependency[1].dstStageMask = VK_PIPELINE_STAGE_NONE_KHR; + subpass_dependency[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + subpass_dependency[1].dstAccessMask = 0; + subpass_dependency[1].dependencyFlags = 0; + + VkRenderPass render_pass; VkRenderPassCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; @@ -471,9 +524,8 @@ VkRenderPass vkapi::create_render_pass(std::vector<VkFormat>& color_attachments_ create_info.pAttachments = attachments_description.data(); create_info.subpassCount = 1; create_info.pSubpasses = &subpass_description; - // TODO: Use this to chain renderpasses - create_info.dependencyCount = 0; - create_info.pDependencies = VK_NULL_HANDLE; + // create_info.dependencyCount = sizeof(subpass_dependency) / sizeof(VkSubpassDependency); + // create_info.pDependencies = subpass_dependency; VKRESULT(vkCreateRenderPass(context.device, &create_info, VK_NULL_HANDLE, &render_pass)) @@ -485,46 +537,68 @@ void vkapi::destroy_render_pass(VkRenderPass render_pass) { } -VkFramebuffer vkapi::create_framebuffer(VkRenderPass render_pass, std::vector<image>& images, VkExtent2D size) { - VkFramebuffer framebuffer; - std::vector<VkImageView> attachements; - for (auto& image: images) { - attachements.push_back(image.view); +framebuffer vkapi::create_framebuffer(VkRenderPass render_pass, std::vector<VkFormat>& formats, VkExtent2D size) { + VkFramebuffer framebuffer_handle; + + std::vector<VkFramebufferAttachmentImageInfo> attachments_image_infos(formats.size()); + for (size_t index = 0; index < formats.size(); index++) { + VkFramebufferAttachmentImageInfo attachments_image_info = {}; + attachments_image_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO; + attachments_image_info.pNext = VK_NULL_HANDLE; + attachments_image_info.flags = 0; + attachments_image_info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + attachments_image_info.width = size.width; + attachments_image_info.height = size.height; + attachments_image_info.layerCount = 1; + attachments_image_info.viewFormatCount = 1; + attachments_image_info.pViewFormats = &formats[index]; + + attachments_image_infos[index] = attachments_image_info; } + VkFramebufferAttachmentsCreateInfo attachments_create_info = {}; + attachments_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO; + attachments_create_info.pNext = VK_NULL_HANDLE; + attachments_create_info.attachmentImageInfoCount = attachments_image_infos.size(); + attachments_create_info.pAttachmentImageInfos = attachments_image_infos.data(); + VkFramebufferCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - create_info.pNext = VK_NULL_HANDLE; - create_info.flags = 0; + create_info.pNext = &attachments_create_info; + create_info.flags = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT; create_info.renderPass = render_pass; - create_info.attachmentCount = attachements.size(); - create_info.pAttachments = attachements.data(); + create_info.attachmentCount = formats.size(); + create_info.pAttachments = VK_NULL_HANDLE; create_info.width = size.width; create_info.height = size.height; create_info.layers = 1; - VKRESULT(vkCreateFramebuffer(context.device, &create_info, VK_NULL_HANDLE, &framebuffer)) + VKRESULT(vkCreateFramebuffer(context.device, &create_info, VK_NULL_HANDLE, &framebuffer_handle)) - return framebuffer; + return { .handle = framebuffer_handle, .size = size }; } -std::vector<VkFramebuffer> vkapi::create_framebuffers(VkRenderPass render_pass, std::vector<image>& images, VkExtent2D size, uint32_t framebuffer_count) { - std::vector<VkFramebuffer> framebuffers { framebuffer_count }; +std::vector<framebuffer> vkapi::create_framebuffers(VkRenderPass render_pass, std::vector<VkFormat>& formats, VkExtent2D size, uint32_t framebuffer_count) { + std::vector<framebuffer> framebuffers { framebuffer_count }; for (auto& framebuffer: framebuffers) { - framebuffer = create_framebuffer(render_pass, images, size); + framebuffer = create_framebuffer(render_pass, formats, size); } return std::move(framebuffers); } -void vkapi::destroy_framebuffer(VkFramebuffer framebuffer) { - vkDestroyFramebuffer(context.device, framebuffer, VK_NULL_HANDLE); +void vkapi::destroy_framebuffer(framebuffer framebuffer) { + VKRESULT(vkDeviceWaitIdle(context.device)) + + vkDestroyFramebuffer(context.device, framebuffer.handle, VK_NULL_HANDLE); } -void vkapi::destroy_framebuffers(std::vector<VkFramebuffer>& framebuffers) { +void vkapi::destroy_framebuffers(std::vector<framebuffer>& framebuffers) { + VKRESULT(vkDeviceWaitIdle(context.device)) + for (auto& framebuffer: framebuffers) { - vkDestroyFramebuffer(context.device, framebuffer, VK_NULL_HANDLE); + vkDestroyFramebuffer(context.device, framebuffer.handle, VK_NULL_HANDLE); } } @@ -780,10 +854,11 @@ void vkapi::destroy_surface(VkSurfaceKHR surface) { swapchain vkapi::create_swapchain(VkSurfaceKHR surface, size_t min_image_count, VkImageUsageFlags usages, VkSwapchainKHR old_swapchain) { swapchain swapchain; + VkBool32 queue_support_presentation = VK_FALSE; VKRESULT(vkGetPhysicalDeviceSurfaceSupportKHR(context.physical_device, context.queue_index, surface, &queue_support_presentation)) - assert(queue_support_presentation == true); + assert(queue_support_presentation == VK_TRUE); VkSurfaceCapabilitiesKHR caps; VKRESULT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(context.physical_device, surface, &caps)) @@ -802,18 +877,21 @@ swapchain vkapi::create_swapchain(VkSurfaceKHR surface, size_t min_image_count, swapchain.extent.height = caps.maxImageExtent.height; } + uint32_t supported_formats_count = 0; VKRESULT(vkGetPhysicalDeviceSurfaceFormatsKHR(context.physical_device, surface, &supported_formats_count, VK_NULL_HANDLE)) std::vector<VkSurfaceFormatKHR> supported_formats { supported_formats_count }; VKRESULT(vkGetPhysicalDeviceSurfaceFormatsKHR(context.physical_device, surface, &supported_formats_count, supported_formats.data())) + uint32_t supported_present_modes_count = 0; VKRESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(context.physical_device, surface, &supported_present_modes_count, VK_NULL_HANDLE)) std::vector<VkPresentModeKHR> supported_present_modes { supported_present_modes_count }; VKRESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(context.physical_device, surface, &supported_present_modes_count, supported_present_modes.data())) + swapchain.surface_format = supported_formats[0]; VkSwapchainCreateInfoKHR create_info = {}; @@ -830,22 +908,20 @@ swapchain vkapi::create_swapchain(VkSurfaceKHR surface, size_t min_image_count, create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; create_info.preTransform = caps.currentTransform; create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - create_info.presentMode = VK_PRESENT_MODE_FIFO_KHR; - // create_info.presentMode = VK_PRESENT_MODE_MAILBOX_KHR; + create_info.presentMode = supported_present_modes[0]; create_info.clipped = VK_TRUE; create_info.oldSwapchain = old_swapchain; VKRESULT(vkCreateSwapchainKHR(context.device, &create_info, nullptr, &swapchain.handle)) - uint32_t image_count = 0; - VKRESULT(vkGetSwapchainImagesKHR(context.device, swapchain.handle, &image_count, VK_NULL_HANDLE)) - swapchain.image_count = image_count; - swapchain.images = std::vector<image>{ swapchain.image_count }; - auto images = std::vector<VkImage>{ swapchain.image_count }; - auto views = std::vector<VkImageView>{ swapchain.image_count }; + VKRESULT(vkGetSwapchainImagesKHR(context.device, swapchain.handle, &swapchain.image_count, VK_NULL_HANDLE)) + + swapchain.images = std::vector<handle>(swapchain.image_count); + auto vk_images = std::vector<VkImage>(swapchain.image_count); + + VKRESULT(vkGetSwapchainImagesKHR(context.device, swapchain.handle, &swapchain.image_count, vk_images.data())) - VKRESULT(vkGetSwapchainImagesKHR(context.device, swapchain.handle, (uint32_t*)&swapchain.image_count, images.data())) VkImageSubresourceRange image_subresource_range = {}; image_subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -861,18 +937,19 @@ swapchain vkapi::create_swapchain(VkSurfaceKHR surface, size_t min_image_count, }; for (size_t image_index = 0; image_index < swapchain.image_count; image_index++) { - swapchain.images[image_index].bindless_storage_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); - swapchain.images[image_index].bindless_sampled_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); + struct image* current_image = new struct image(); + + current_image->handle = vk_images[image_index]; + current_image->size = image_size; + current_image->subresource_range = image_subresource_range; + current_image->usages = usages; - swapchain.images[image_index].handle = images[image_index]; - swapchain.images[image_index].size = image_size; - swapchain.images[image_index].subresource_range = image_subresource_range; VkImageViewCreateInfo image_view_create_info = {}; image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; image_view_create_info.pNext = nullptr; image_view_create_info.flags = 0; - image_view_create_info.image = swapchain.images[image_index].handle; + image_view_create_info.image = current_image->handle; image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; image_view_create_info.format = swapchain.surface_format.format; image_view_create_info.components = { @@ -881,38 +958,58 @@ swapchain vkapi::create_swapchain(VkSurfaceKHR surface, size_t min_image_count, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY }; - image_view_create_info.subresourceRange = image_subresource_range; + image_view_create_info.subresourceRange = image_subresource_range; + + VKRESULT(vkCreateImageView(context.device, &image_view_create_info, nullptr, ¤t_image->view)) + + images.push_back(current_image); - VKRESULT(vkCreateImageView(context.device, &image_view_create_info, nullptr, &swapchain.images[image_index].view)) + auto current_image_handle = images.size() - 1; + + if (usages & VK_IMAGE_USAGE_STORAGE_BIT) { + current_image->bindless_storage_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); + update_descriptor_image(current_image_handle, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); + } + + if (usages & VK_IMAGE_USAGE_SAMPLED_BIT) { + current_image->bindless_sampled_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); + update_descriptor_image(current_image_handle, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); + } + + swapchain.images[image_index] = current_image_handle; } - return std::move(swapchain); + return swapchain; } void vkapi::destroy_swapchain(swapchain& swapchain) { + VKRESULT(vkDeviceWaitIdle(context.device)) + for(auto &image: swapchain.images) { - bindless_descriptor.free(image.bindless_storage_index, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); - bindless_descriptor.free(image.bindless_sampled_index, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); + bindless_descriptor.free(images[image]->bindless_storage_index, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); + bindless_descriptor.free(images[image]->bindless_sampled_index, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); - vkDestroyImageView(context.device, image.view, nullptr); + vkDestroyImageView(context.device, images[image]->view, nullptr); } vkDestroySwapchainKHR(context.device, swapchain.handle, nullptr); } -void vkapi::update_descriptor_image(image &img, VkDescriptorType type) { +void vkapi::update_descriptor_image(handle img, VkDescriptorType type) { VkDescriptorImageInfo descriptor_image_info; VkWriteDescriptorSet write_descriptor; + auto current_image = images[img]; + descriptor_image_info.sampler = VK_NULL_HANDLE; - descriptor_image_info.imageView = img.view; + descriptor_image_info.imageView = current_image->view; descriptor_image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; write_descriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; write_descriptor.pNext = nullptr; write_descriptor.dstSet = bindless_descriptor.set; write_descriptor.dstBinding = type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ? 2 : 1; - write_descriptor.dstArrayElement = type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ? img.bindless_storage_index : img.bindless_sampled_index; + write_descriptor.dstArrayElement = type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ? current_image->bindless_storage_index : current_image->bindless_sampled_index; write_descriptor.descriptorCount = 1; write_descriptor.descriptorType = type; write_descriptor.pImageInfo = &descriptor_image_info; @@ -922,21 +1019,21 @@ void vkapi::update_descriptor_image(image &img, VkDescriptorType type) { vkUpdateDescriptorSets(context.device, 1, &write_descriptor, 0, nullptr); } -void vkapi::update_descriptor_images(std::vector<image> &images, VkDescriptorType type) { +void vkapi::update_descriptor_images(std::vector<handle> &handles, VkDescriptorType type) { std::vector<VkDescriptorImageInfo> descriptor_images_info { images.size() }; std::vector<VkWriteDescriptorSet> writes_descriptor { images.size() }; for (size_t image_index = 0; image_index < images.size(); image_index++) { - auto &image = images[image_index]; + auto image = images[handles[image_index]]; descriptor_images_info[image_index].sampler = VK_NULL_HANDLE; - descriptor_images_info[image_index].imageView = image.view; + descriptor_images_info[image_index].imageView = image->view; descriptor_images_info[image_index].imageLayout = VK_IMAGE_LAYOUT_GENERAL; writes_descriptor[image_index].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writes_descriptor[image_index].pNext = nullptr; writes_descriptor[image_index].dstSet = bindless_descriptor.set; writes_descriptor[image_index].dstBinding = type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ? 2 : 1; - writes_descriptor[image_index].dstArrayElement = type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ? image.bindless_storage_index : image.bindless_sampled_index; + writes_descriptor[image_index].dstArrayElement = type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ? image->bindless_storage_index : image->bindless_sampled_index; writes_descriptor[image_index].descriptorCount = 1; writes_descriptor[image_index].descriptorType = type; writes_descriptor[image_index].pImageInfo = &descriptor_images_info[image_index]; @@ -947,11 +1044,12 @@ void vkapi::update_descriptor_images(std::vector<image> &images, VkDescriptorTyp vkUpdateDescriptorSets(context.device, writes_descriptor.size(), writes_descriptor.data(), 0, nullptr); } -void vkapi::update_descriptor_sampler(sampler &sampler) { +void vkapi::update_descriptor_sampler(handle sampler) { VkDescriptorImageInfo descriptor_image_info; VkWriteDescriptorSet write_descriptor; + auto current_sampler = samplers[sampler]; - descriptor_image_info.sampler = sampler.handle; + descriptor_image_info.sampler = current_sampler->handle; descriptor_image_info.imageView = VK_NULL_HANDLE; descriptor_image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; @@ -959,7 +1057,7 @@ void vkapi::update_descriptor_sampler(sampler &sampler) { write_descriptor.pNext = nullptr; write_descriptor.dstSet = bindless_descriptor.set; write_descriptor.dstBinding = 0; - write_descriptor.dstArrayElement = sampler.bindless_index; + write_descriptor.dstArrayElement = current_sampler->bindless_index; write_descriptor.descriptorCount = 1; write_descriptor.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; write_descriptor.pImageInfo = &descriptor_image_info; @@ -969,12 +1067,13 @@ void vkapi::update_descriptor_sampler(sampler &sampler) { vkUpdateDescriptorSets(context.device, 1, &write_descriptor, 0, nullptr); } -void vkapi::update_descriptor_samplers(std::vector<sampler> &samplers) { +void vkapi::update_descriptor_samplers(std::vector<handle> &handles) { std::vector<VkDescriptorImageInfo> descriptor_images_info { samplers.size() }; std::vector<VkWriteDescriptorSet> writes_descriptor { samplers.size() }; for (size_t sampler_index = 0; sampler_index < samplers.size(); sampler_index++) { - descriptor_images_info[sampler_index].sampler = samplers[sampler_index].handle; + auto sampler = samplers[handles[sampler_index]]; + descriptor_images_info[sampler_index].sampler = sampler->handle; descriptor_images_info[sampler_index].imageView = VK_NULL_HANDLE; descriptor_images_info[sampler_index].imageLayout = VK_IMAGE_LAYOUT_GENERAL; @@ -982,7 +1081,7 @@ void vkapi::update_descriptor_samplers(std::vector<sampler> &samplers) { writes_descriptor[sampler_index].pNext = nullptr; writes_descriptor[sampler_index].dstSet = bindless_descriptor.set; writes_descriptor[sampler_index].dstBinding = 0; - writes_descriptor[sampler_index].dstArrayElement = samplers[sampler_index].bindless_index; + writes_descriptor[sampler_index].dstArrayElement = sampler->bindless_index; writes_descriptor[sampler_index].descriptorCount = 1; writes_descriptor[sampler_index].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; writes_descriptor[sampler_index].pImageInfo = &descriptor_images_info[sampler_index]; @@ -1007,22 +1106,24 @@ void vkapi::start_record(VkCommandBuffer command_buffer) { vkBeginCommandBuffer(command_buffer, &cmd_buf_begin_info); } -void vkapi::image_barrier(VkCommandBuffer command_buffer, VkImageLayout dst_layout, VkPipelineStageFlagBits dst_stage, VkAccessFlags dst_access, image& image) { +void vkapi::image_barrier(VkCommandBuffer command_buffer, VkImageLayout dst_layout, VkPipelineStageFlagBits dst_stage, VkAccessFlags dst_access, handle image) { + auto current_image = images[image]; + VkImageMemoryBarrier undefined_to_general_barrier = {}; undefined_to_general_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; undefined_to_general_barrier.pNext = nullptr; - undefined_to_general_barrier.srcAccessMask = image.previous_access; + undefined_to_general_barrier.srcAccessMask = current_image->previous_access; undefined_to_general_barrier.dstAccessMask = dst_access; - undefined_to_general_barrier.oldLayout = image.previous_layout; + undefined_to_general_barrier.oldLayout = current_image->previous_layout; undefined_to_general_barrier.newLayout = dst_layout; undefined_to_general_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; undefined_to_general_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - undefined_to_general_barrier.image = image.handle; - undefined_to_general_barrier.subresourceRange = image.subresource_range; + undefined_to_general_barrier.image = current_image->handle; + undefined_to_general_barrier.subresourceRange = current_image->subresource_range; vkCmdPipelineBarrier( command_buffer, - image.previous_stage, + current_image->previous_stage, dst_stage, 0, 0, @@ -1033,13 +1134,13 @@ void vkapi::image_barrier(VkCommandBuffer command_buffer, VkImageLayout dst_layo &undefined_to_general_barrier ); - image.previous_layout = dst_layout; - image.previous_access = dst_access; - image.previous_stage = dst_stage; + current_image->previous_layout = dst_layout; + current_image->previous_access = dst_access; + current_image->previous_stage = dst_stage; } -void vkapi::begin_render_pass(VkCommandBuffer command_buffer, VkRenderPass render_pass, VkFramebuffer framebuffer, VkExtent2D size, pipeline& pipeline) { +void vkapi::begin_render_pass(VkCommandBuffer command_buffer, VkRenderPass render_pass, std::vector<VkImageView>& attachments, framebuffer framebuffer, VkExtent2D size) { VkRect2D render_area = { { 0, @@ -1048,18 +1149,23 @@ void vkapi::begin_render_pass(VkCommandBuffer command_buffer, VkRenderPass rende size }; + VkRenderPassAttachmentBeginInfo attachment_begin_info = {}; + attachment_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO; + attachment_begin_info.pNext = VK_NULL_HANDLE; + attachment_begin_info.attachmentCount = attachments.size(); + attachment_begin_info.pAttachments = attachments.data(); + VkClearValue clear_value = { 0.f, 0.f, 0.f, 1.f }; VkRenderPassBeginInfo render_pass_begin_info = {}; render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - render_pass_begin_info.pNext = VK_NULL_HANDLE; + render_pass_begin_info.pNext = &attachment_begin_info; render_pass_begin_info.renderPass = render_pass; - render_pass_begin_info.framebuffer = framebuffer; + render_pass_begin_info.framebuffer = framebuffer.handle; render_pass_begin_info.renderArea = render_area; render_pass_begin_info.clearValueCount = 1; render_pass_begin_info.pClearValues = &clear_value; vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); - vkCmdBindPipeline(command_buffer, pipeline.bind_point, pipeline.handle); } void vkapi::end_render_pass(VkCommandBuffer command_buffer) { @@ -1082,14 +1188,18 @@ void vkapi::draw(VkCommandBuffer command_buffer, pipeline& pipeline, uint32_t ve vkCmdDraw(command_buffer, vertex_count, 1, vertex_offset, 0); } -void vkapi::draw(VkCommandBuffer command_buffer, pipeline& pipeline, buffer& index_buffer, uint32_t index_count, uint32_t index_offset, uint32_t vertex_offset) { - vkCmdBindIndexBuffer(command_buffer, index_buffer.handle, 0, VK_INDEX_TYPE_UINT16); +void vkapi::draw(VkCommandBuffer command_buffer, pipeline& pipeline, handle index_buffer, uint32_t index_count, uint32_t index_offset, uint32_t vertex_offset) { + vkCmdBindIndexBuffer(command_buffer, buffers[index_buffer]->handle, 0, VK_INDEX_TYPE_UINT16); vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bindless_descriptor.pipeline_layout, 0, 1, &bindless_descriptor.set, 0, nullptr); + vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.handle); vkCmdDrawIndexed(command_buffer, index_count, 1, index_offset, vertex_offset, 0); } -void vkapi::blit_full(VkCommandBuffer command_buffer, image& src_image, image& dst_image) { +void vkapi::blit_full(VkCommandBuffer command_buffer, handle src, handle dst) { + auto src_image = images[src]; + auto dst_image = images[dst]; + VkImageSubresourceLayers images_subres_layers { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .mipLevel = 0, @@ -1103,9 +1213,9 @@ void vkapi::blit_full(VkCommandBuffer command_buffer, image& src_image, image& d .z = 0, }; VkOffset3D end_offset { - .x = (int32_t)src_image.size.width, - .y = (int32_t)src_image.size.height, - .z = (int32_t)src_image.size.depth, + .x = (int32_t)src_image->size.width, + .y = (int32_t)src_image->size.height, + .z = (int32_t)src_image->size.depth, }; VkImageBlit blit_region { @@ -1115,7 +1225,7 @@ void vkapi::blit_full(VkCommandBuffer command_buffer, image& src_image, image& d .dstOffsets = { start_offset, end_offset }, }; - vkCmdBlitImage(command_buffer, src_image.handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image.handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit_region, VK_FILTER_NEAREST); + vkCmdBlitImage(command_buffer, src_image->handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image->handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit_region, VK_FILTER_NEAREST); } void vkapi::end_record(VkCommandBuffer command_buffer) { diff --git a/src/vk-context.cpp b/src/vk-context.cpp index b539194..53f3e59 100644 --- a/src/vk-context.cpp +++ b/src/vk-context.cpp @@ -3,7 +3,6 @@ #include "vk-context.hpp" #include "vulkan-loader.hpp" -#include "vulkan/vulkan_core.h" #define VMA_IMPLEMENTATION #include "thirdparty/vk_mem_alloc.h" @@ -129,6 +128,7 @@ void vkcontext::create_device() { physical_device_12_features.descriptorBindingPartiallyBound = VK_TRUE; physical_device_12_features.descriptorBindingPartiallyBound = VK_TRUE; physical_device_12_features.descriptorBindingUpdateUnusedWhilePending = VK_TRUE; + physical_device_12_features.imagelessFramebuffer = VK_TRUE; VkPhysicalDeviceFeatures2 device_features = {}; device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; @@ -249,7 +249,7 @@ void vkcontext::check_available_instance_extensions(std::vector<const char*>& av } } - assert(available_needed_extensions_count == needed_extensions.size()); + // assert(available_needed_extensions_count == needed_extensions.size()); } bool vkcontext::support_required_features(VkPhysicalDevice physical_device) { @@ -272,7 +272,8 @@ bool vkcontext::support_required_features(VkPhysicalDevice physical_device) { vulkan_12_features.shaderSampledImageArrayNonUniformIndexing == VK_TRUE && vulkan_12_features.descriptorBindingPartiallyBound == VK_TRUE && vulkan_12_features.descriptorBindingPartiallyBound == VK_TRUE && - vulkan_12_features.descriptorBindingUpdateUnusedWhilePending == VK_TRUE) { + vulkan_12_features.descriptorBindingUpdateUnusedWhilePending == VK_TRUE && + vulkan_12_features.imagelessFramebuffer == VK_TRUE) { std::cerr << "Using physical device " << physical_device_properties.deviceName << std::endl; return true; } else { diff --git a/src/vk-renderer.cpp b/src/vk-renderer.cpp index e2e62ff..2fcd39d 100644 --- a/src/vk-renderer.cpp +++ b/src/vk-renderer.cpp @@ -3,9 +3,8 @@ #include <cassert> #include "compute-renderpass.hpp" -#include "imgui.h" +#include "primitive-renderpass.hpp" #include "vk-renderer.hpp" -#include "thirdparty/vk_mem_alloc.h" #include "defines.hpp" #include "window.hpp" @@ -16,29 +15,23 @@ #define VKRESULT(result) result; #endif -struct VkVertex { - float x, y; - float u, v; - uint32_t color; - uint32_t padding[3]; -}; - -struct UiTransforms { - float scale_x, scale_y; - float translate_x, translate_y; -}; - vkrenderer::vkrenderer(window& wnd) { platform_surface = api.create_surface(wnd); swapchain = api.create_swapchain( platform_surface, min_swapchain_image_count, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_STORAGE_BIT, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, // | + // VK_IMAGE_USAGE_TRANSFER_DST_BIT | + // VK_IMAGE_USAGE_STORAGE_BIT, VK_NULL_HANDLE ); + swapchain_textures.resize(swapchain.image_count); + for (size_t index = 0; index < swapchain.image_count; index++) { + swapchain_textures[index] = new Texture(); + swapchain_textures[index]->device_image = swapchain.images[index]; + } + tonemapping_pipeline = api.create_compute_pipeline("tonemapping"); command_buffers = api.create_command_buffers(virtual_frames_count); @@ -47,83 +40,7 @@ vkrenderer::vkrenderer(window& wnd) { execution_semaphores = api.create_semaphores(virtual_frames_count); acquire_semaphores = api.create_semaphores(virtual_frames_count); - - std::vector<VkFormat> attachments_format { swapchain.surface_format.format }; - render_pass = api.create_render_pass(attachments_format, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); - - for (auto& current_image : swapchain.images) { - std::vector<image> attachments { current_image }; - framebuffers.push_back(api.create_framebuffer(render_pass, attachments, swapchain.extent)); - } - - - std::vector<VkDynamicState> dynamic_states { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR - }; - ui_pipeline = api.create_graphics_pipeline("ui", (VkShaderStageFlagBits)(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT), render_pass, dynamic_states); - - ImGui::CreateContext(); - auto io = ImGui::GetIO(); - - uint8_t* pixels = nullptr; - int atlas_width, atlas_height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &atlas_width, &atlas_height); - - VkExtent3D atlas_size = { - .width = (uint32_t)atlas_width, - .height = (uint32_t)atlas_height, - .depth = 1, - }; staging_buffer = api.create_buffer(4096 * 4096 * 4 * sizeof(uint32_t), VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); - std::memcpy(staging_buffer.alloc_info.pMappedData, pixels, atlas_width * atlas_height * sizeof(uint32_t)); - - // ui_texture = api.create_image(atlas_size, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); - // io.Fonts->SetTexID((void*)&ui_texture); - - // VKRESULT(vkResetFences(api.context.device, 1, &submission_fences[virtual_frame_index])) - - // Initialization frame - // auto cmd_buf = command_buffers[virtual_frame_index]; - // api.start_record(cmd_buf); - - // api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_MEMORY_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, ui_texture); - - // api.copy_buffer(cmd_buf, staging_buffer, ui_texture); - - // api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, 0, ui_texture); - - // api.end_record(cmd_buf); - - - // api.submit(cmd_buf, VK_NULL_HANDLE, VK_NULL_HANDLE, submission_fences[virtual_frame_index]); - - // VKRESULT(vkWaitForFences(api.context.device, 1, &submission_fences[virtual_frame_index], VK_TRUE, UINT64_MAX)) - - std::vector<image> images = { - swapchain.images[0], - swapchain.images[1], - swapchain.images[2] - }; - - api.update_descriptor_images(images, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); - - // std::vector<image> sampled_images = { - // ui_texture - // }; - // api.update_descriptor_images(sampled_images, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); - - // ui_texture_sampler = api.create_sampler(VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); - - // std::vector<sampler> samplers = { - // ui_texture_sampler, - // }; - // api.update_descriptor_samplers(samplers); - - virtual_frame_index++; - - ui_vertex_buffers.resize(virtual_frames_count); - ui_index_buffers.resize(virtual_frames_count); } vkrenderer::~vkrenderer() { @@ -137,124 +54,23 @@ vkrenderer::~vkrenderer() { api.destroy_semaphores(execution_semaphores); api.destroy_semaphores(acquire_semaphores); - api.destroy_render_pass(render_pass); - - // api.destroy_sampler(ui_texture_sampler); - - for (auto& framebuffer: framebuffers) { - api.destroy_framebuffer(framebuffer); - } - api.destroy_command_buffers(command_buffers); api.destroy_pipeline(tonemapping_pipeline); - api.destroy_pipeline(ui_pipeline); api.destroy_swapchain(swapchain); api.destroy_surface(platform_surface); } void vkrenderer::begin_frame() { - ImGui::Render(); - // ImDrawData* draw_data = ImGui::GetDrawData(); - VKRESULT(vkWaitForFences(api.context.device, 1, &submission_fences[virtual_frame_index], VK_TRUE, UINT64_MAX)) VKRESULT(vkResetFences(api.context.device, 1, &submission_fences[virtual_frame_index])) - // if (ui_vertex_buffers[virtual_frame_index].size < draw_data->TotalVtxCount * sizeof(VkVertex)) { - // api.destroy_buffer(ui_vertex_buffers[virtual_frame_index]); - - // ui_vertex_buffers[virtual_frame_index] = api.create_buffer(draw_data->TotalVtxCount * sizeof(VkVertex), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU); - // } - // if (ui_index_buffers[virtual_frame_index].size < draw_data->TotalIdxCount * sizeof(ImDrawIdx)) { - // api.destroy_buffer(ui_index_buffers[virtual_frame_index]); - - // ui_index_buffers[virtual_frame_index] = api.create_buffer(draw_data->TotalIdxCount * sizeof(ImDrawIdx), VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU); - // } - - // off_t vertex_buffer_offset = 0; - // off_t index_buffer_offset = 0; - // for (uint32_t draw_list_index = 0; draw_list_index < draw_data->CmdListsCount; draw_list_index++) { - // auto vertex_buffer = draw_data->CmdLists[draw_list_index]->VtxBuffer; - // auto index_buffer = draw_data->CmdLists[draw_list_index]->IdxBuffer; - // std::vector<VkVertex> vertices; - - // for (auto& imVertex: vertex_buffer) { - // vertices.push_back(*((VkVertex*)&imVertex)); - // } - - // std::memcpy((void*) ((uint64_t)ui_vertex_buffers[virtual_frame_index].alloc_info.pMappedData + (vertex_buffer_offset * sizeof(VkVertex))), vertices.data(), vertex_buffer.Size * sizeof(VkVertex)); - // std::memcpy((void*) ((uint64_t)ui_index_buffers[virtual_frame_index].alloc_info.pMappedData + (index_buffer_offset * sizeof(ImDrawIdx))), index_buffer.Data, index_buffer.Size * sizeof(ImDrawIdx)); - - // vertex_buffer_offset += vertex_buffer.Size; - // index_buffer_offset += index_buffer.Size; - // } - swapchain_image_index = 0; auto acquire_result = vkAcquireNextImageKHR(api.context.device, swapchain.handle, UINT64_MAX, acquire_semaphores[virtual_frame_index], VK_NULL_HANDLE, &swapchain_image_index); handle_swapchain_result(acquire_result); api.start_record(command_buffers[virtual_frame_index]); - -} - -void vkrenderer::ui() { - ImDrawData* draw_data = ImGui::GetDrawData(); - - auto cmd_buf = command_buffers[virtual_frame_index]; - - api.begin_render_pass(cmd_buf, render_pass, framebuffers[swapchain_image_index], swapchain.extent, ui_pipeline); - - VkViewport viewport = {}; - viewport.x = draw_data->DisplayPos.x; - viewport.y = draw_data->DisplayPos.y; - viewport.width = draw_data->DisplaySize.x; - viewport.height = draw_data->DisplaySize.y; - viewport.minDepth = 0.f; - viewport.maxDepth = 1.f; - - vkCmdSetViewport(cmd_buf, 0, 1, &viewport); - - float scale[] { - 2.f / draw_data->DisplaySize.x, - 2.f / draw_data->DisplaySize.y, - }; - float translate[] { - -1.f - draw_data->DisplayPos.x * (2.f / draw_data->DisplaySize.x), - -1.f - draw_data->DisplayPos.y * (2.f / draw_data->DisplaySize.y), - }; - // vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 64, 8, (void*)&ui_vertex_buffers[virtual_frame_index].device_address); - // vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 72, 8, (void*)&scale); - // vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 80, 8, (void*)&translate); - - // vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 96, 4, (void*)&ui_texture.bindless_sampled_index); - // vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 100, 4, (void*)&ui_texture_sampler.bindless_index); - - off_t vertex_buffer_offset = 0; - off_t index_buffer_offset = 0; - for (size_t cmd_index = 0; cmd_index < draw_data->CmdListsCount; cmd_index++) { - ImDrawList* draw_list = draw_data->CmdLists[cmd_index]; - - for (auto& draw_cmd: draw_list->CmdBuffer) { - VkRect2D rect = {}; - rect.offset = { - (int32_t)draw_cmd.ClipRect.x, - (int32_t)draw_cmd.ClipRect.y - }; - rect.extent = { - (uint32_t)draw_cmd.ClipRect.z, - (uint32_t)draw_cmd.ClipRect.w, - }; - vkCmdSetScissor(cmd_buf, 0, 1, &rect); - - api.draw(cmd_buf, ui_pipeline, ui_index_buffers[virtual_frame_index], draw_cmd.ElemCount, index_buffer_offset + draw_cmd.IdxOffset, vertex_buffer_offset + draw_cmd.VtxOffset); - } - - vertex_buffer_offset += draw_list->VtxBuffer.Size; - index_buffer_offset += draw_list->IdxBuffer.Size; - } - - api.end_render_pass(cmd_buf); } void vkrenderer::compute(uint32_t width, uint32_t height) { @@ -268,7 +84,7 @@ void vkrenderer::compute(uint32_t width, uint32_t height) { void vkrenderer::finish_frame() { auto cmd_buf = command_buffers[virtual_frame_index]; - // api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_ACCESS_SHADER_WRITE_BIT, 0, swapchain.images[swapchain_image_index]); + // api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, swapchain.images[swapchain_image_index]); api.end_record(cmd_buf); @@ -281,51 +97,23 @@ void vkrenderer::finish_frame() { } void vkrenderer::recreate_swapchain() { - VKRESULT(vkWaitForFences(api.context.device, submission_fences.size(), submission_fences.data(), VK_TRUE, UINT64_MAX)) + // VKRESULT(vkWaitForFences(api.context.device, submission_fences.size(), submission_fences.data(), VK_TRUE, UINT64_MAX)) + auto swapchain_image_usages = api.get_image(swapchain.images[0]).usages; struct swapchain old_swapchain = swapchain; swapchain = api.create_swapchain( platform_surface, min_swapchain_image_count, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT, + swapchain_image_usages, old_swapchain.handle ); api.destroy_swapchain(old_swapchain); - VkExtent3D image_size = { - .width = swapchain.extent.width, - .height = swapchain.extent.height, - .depth = 1, - }; - - auto cmd_buf = command_buffers[virtual_frame_index]; - api.start_record(cmd_buf); - - api.end_record(cmd_buf); - - VKRESULT(vkResetFences(api.context.device, 1, &submission_fences[0])) - - api.submit(cmd_buf, VK_NULL_HANDLE, VK_NULL_HANDLE, submission_fences[0]); - - VKRESULT(vkWaitForFences(api.context.device, 1, &submission_fences[0], VK_TRUE, UINT64_MAX)) - - std::vector<image> images = { - swapchain.images[0], - swapchain.images[1], - swapchain.images[2] - }; - - api.update_descriptor_images(images, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); - - for (auto& framebuffer: framebuffers) { - api.destroy_framebuffer(framebuffer); - } - framebuffers.clear(); - - for (auto& current_image : swapchain.images) { - std::vector<image> attachments { current_image }; - framebuffers.push_back(api.create_framebuffer(render_pass, attachments, swapchain.extent)); + swapchain_textures.resize(swapchain.image_count); + for (size_t index = 0; index < swapchain.image_count; index++) { + swapchain_textures[index] = new Texture(); + swapchain_textures[index]->device_image = swapchain.images[index]; } } @@ -340,14 +128,17 @@ void vkrenderer::handle_swapchain_result(VkResult function_result) { } } -void vkrenderer::update_image(Texture* texture, void* data, size_t size) { - if (staging_buffer.size < size) { +void vkrenderer::update_image(Texture* texture, void* data) { + auto image = api.get_image(texture->device_image); + auto max_texture_size = image.size.width * image.size.height * 4; + auto buffer = api.get_buffer(staging_buffer); + if (buffer.size < max_texture_size) { api.destroy_buffer(staging_buffer); - staging_buffer = api.create_buffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); + staging_buffer = api.create_buffer(max_texture_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); } - std::memcpy(staging_buffer.alloc_info.pMappedData, data, size); + std::memcpy(buffer.alloc_info.pMappedData, data, max_texture_size); VKRESULT(vkWaitForFences(api.context.device, 1, &submission_fences[virtual_frame_index], VK_TRUE, UINT64_MAX)) VKRESULT(vkResetFences(api.context.device, 1, &submission_fences[virtual_frame_index])) @@ -359,7 +150,7 @@ void vkrenderer::update_image(Texture* texture, void* data, size_t size) { api.copy_buffer(cmd_buf, staging_buffer, texture->device_image); - api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, texture->device_image); + api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, texture->device_image); api.end_record(cmd_buf); @@ -367,9 +158,17 @@ void vkrenderer::update_image(Texture* texture, void* data, size_t size) { api.submit(cmd_buf, VK_NULL_HANDLE, VK_NULL_HANDLE, submission_fences[virtual_frame_index]); VKRESULT(vkWaitForFences(api.context.device, 1, &submission_fences[virtual_frame_index], VK_TRUE, UINT64_MAX)) +} +void vkrenderer::update_buffer(Buffer* buffer, void* data, off_t offset, size_t size) { + auto device_buffer = api.get_buffer(buffer->device_buffer); + + size_t dynamic_offset = buffer->isStatic ? 0 : buffer->size * virtual_frame_index; + + std::memcpy((uint8_t*)device_buffer.alloc_info.pMappedData + dynamic_offset + offset, data, size); } + Buffer* vkrenderer::create_buffer(size_t size, bool isStatic) { auto buffer = new Buffer(this, size, isStatic); @@ -378,6 +177,14 @@ Buffer* vkrenderer::create_buffer(size_t size, bool isStatic) { return buffer; } +Buffer* vkrenderer::create_index_buffer(size_t size, bool isStatic) { + auto buffer = new Buffer(this, size, isStatic); + + buffer->device_buffer = api.create_buffer(isStatic ? size : size * virtual_frames_count, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU); + + return buffer; +} + Texture* vkrenderer::create_2d_texture(size_t width, size_t height, VkFormat format) { auto texture = new Texture(); texture->device_image = api.create_image( @@ -386,9 +193,6 @@ Texture* vkrenderer::create_2d_texture(size_t width, size_t height, VkFormat for VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT ); - api.update_descriptor_image(texture->device_image, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); - api.update_descriptor_image(texture->device_image, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); - return texture; } @@ -398,8 +202,6 @@ Sampler* vkrenderer::create_sampler(VkFilter filter, VkSamplerAddressMode addres sampler->device_sampler = api.create_sampler(filter, address_mode); - api.update_descriptor_sampler(sampler->device_sampler); - return sampler; } @@ -409,22 +211,37 @@ ComputeRenderpass* vkrenderer::create_compute_renderpass() { return (ComputeRenderpass*)renderpasses.back(); } +PrimitiveRenderpass* vkrenderer::create_primitive_renderpass() { + renderpasses.push_back(new PrimitiveRenderpass(api)); + + return (PrimitiveRenderpass*)renderpasses.back(); +} + +Primitive* vkrenderer::create_primitive(PrimitiveRenderpass& primitive_render_pass) { + return new Primitive(api, primitive_render_pass); +} + void vkrenderer::render() { - begin_frame(); + // begin_frame(); auto cmd_buf = command_buffers[virtual_frame_index]; - for (auto& renderpass: renderpasses) { - renderpass->execute(cmd_buf); + // for (auto& renderpass: renderpasses) { + // renderpass->execute(*this, cmd_buf); - api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT, ((ComputeRenderpass*)renderpass)->output_texture->device_image); + // api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT, ((ComputeRenderpass*)renderpass)->output_texture->device_image); - api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, swapchain.images[swapchain_image_index]); + // api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, swapchain.images[swapchain_image_index]); - api.blit_full(cmd_buf, ((ComputeRenderpass*)renderpass)->output_texture->device_image, swapchain.images[swapchain_image_index]); + // api.blit_full(cmd_buf, ((ComputeRenderpass*)renderpass)->output_texture->device_image, swapchain.images[swapchain_image_index]); + // } - api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, swapchain.images[swapchain_image_index]); - } - finish_frame(); + // api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, swapchain.images[swapchain_image_index]); + + renderpasses[1]->execute(*this, cmd_buf); + + api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, swapchain.images[swapchain_image_index]); + + // finish_frame(); } |
