#pragma once #include #include #include #include #include #include #include #include namespace mirrage { namespace ecs { class Entity_manager; } class Meta_system; } // namespace mirrage namespace mirrage::renderer { class Deferred_renderer_factory; class Deferred_renderer; struct Renderer_settings { int shadowmap_resolution = 2048; int shadow_quality = 99; // 0 = lowest bool gi = true; bool gi_highres = true; int gi_diffuse_mip_level = 1; int gi_min_mip_level = 0; int gi_samples = 128; float gi_prioritise_near_samples = 0.8f; int gi_low_quality_mip_levels = 0; float exposure_override = 0.f; bool ssao = true; bool bloom = true; float background_intensity = 1.f; bool dynamic_shadows = false; bool debug_disect = false; int debug_gi_layer = -1; }; #ifdef sf2_structDef sf2_structDef( Renderer_settings, shadowmap_resolution, shadow_quality, gi, dynamic_shadows, debug_gi_layer); #endif struct Global_uniforms { glm::mat4 view_proj_mat; glm::mat4 view_mat; glm::mat4 proj_mat; glm::mat4 inv_view_mat; glm::mat4 inv_proj_mat; glm::vec4 eye_pos; glm::vec4 proj_planes; //< near, far, fov horizontal, fov vertical glm::vec4 time; //< time, sin(time), delta_time glm::vec4 proj_info; }; using Command_buffer_source = std::function; class Pass { public: virtual ~Pass() = default; virtual void update(util::Time dt) = 0; virtual void draw(vk::CommandBuffer&, Command_buffer_source&, vk::DescriptorSet global_uniform_set, std::size_t swapchain_image) = 0; virtual void shrink_to_fit() {} virtual void process_camera(Camera_state&) {} //< allows passes to modify the current camera virtual auto name() const noexcept -> const char* = 0; }; class Pass_factory { public: virtual ~Pass_factory() = default; virtual auto create_pass(Deferred_renderer&, ecs::Entity_manager&, util::maybe, bool& write_first_pp_buffer) -> std::unique_ptr = 0; virtual auto rank_device(vk::PhysicalDevice, util::maybe graphics_queue, int current_score) -> int { return current_score; } virtual void configure_device(vk::PhysicalDevice, util::maybe graphics_queue, graphic::Device_create_info&) {} }; template auto make_pass_factory(Args&&... args) { return std::unique_ptr(new T(std::forward(args)...)); } // shared among all Deferred_renderers in all screens class Deferred_renderer_factory { public: Deferred_renderer_factory(graphic::Context&, graphic::Window& window, std::vector>); auto create_renderer(ecs::Entity_manager&, util::maybe) -> std::unique_ptr; void queue_commands(vk::CommandBuffer); auto queue_temporary_command_buffer() -> vk::CommandBuffer; void finish_frame(); auto settings() const -> auto& { return *_settings; } void settings(const Renderer_settings& s, bool apply = true); void save_settings(); private: friend class Deferred_renderer; using Pass_factories = std::vector>; using Settings_ptr = std::shared_ptr; Settings_ptr _settings; Pass_factories _pass_factories; graphic::Window& _window; graphic::Device_ptr _device; graphic::Swapchain& _swapchain; std::uint32_t _queue_family; vk::Queue _queue; vk::UniqueSemaphore _image_acquired; vk::UniqueSemaphore _image_presented; graphic::Command_buffer_pool _command_buffer_pool; util::maybe _aquired_swapchain_image; std::vector _queued_commands; std::vector _renderer_instances; bool _recreation_pending = false; void _present(); auto _rank_device(vk::PhysicalDevice, util::maybe gqueue) -> int; auto _init_device(vk::PhysicalDevice, util::maybe gqueue) -> graphic::Device_create_info; auto _aquire_next_image() -> std::size_t; }; class Deferred_renderer { public: Deferred_renderer(Deferred_renderer_factory&, std::vector>&, ecs::Entity_manager&, util::maybe); Deferred_renderer(const Deferred_renderer&) = delete; auto operator=(const Deferred_renderer&) -> Deferred_renderer& = delete; ~Deferred_renderer(); void recreate(); template auto find_pass() -> util::tracking_ptr { auto pass = std::find_if( _passes.begin(), _passes.end(), [](auto& p) { return dynamic_cast(&*p) != nullptr; }); return pass != _passes.end() ? util::tracking_ptr(pass->create_ptr()) : util::tracking_ptr{}; } void update(util::Time dt); void draw(); void shrink_to_fit(); auto texture_cache() -> auto& { return *_texture_cache; } auto model_loader() -> auto& { return *_model_loader; } auto gbuffer() noexcept -> auto& { return *_gbuffer; } auto gbuffer() const noexcept -> auto& { return *_gbuffer; } auto global_uniforms() const noexcept -> auto& { return _global_uniforms; } auto global_uniforms_layout() const noexcept { return *_global_uniform_descriptor_set_layout; } auto device() noexcept -> auto& { return *_factory->_device; } auto window() noexcept -> auto& { return _factory->_window; } auto swapchain() noexcept -> auto& { return _factory->_swapchain; } auto queue_family() const noexcept { return _factory->_queue_family; } auto create_descriptor_set(vk::DescriptorSetLayout) -> vk::UniqueDescriptorSet; auto descriptor_pool() noexcept -> auto& { return _descriptor_set_pool; } auto active_camera() noexcept -> util::maybe; auto settings() const -> auto& { return _factory->settings(); } void save_settings() { _factory->save_settings(); } void settings(const Renderer_settings& s, bool apply = true) { _factory->settings(s, apply); } auto profiler() const noexcept -> auto& { return _profiler; } auto profiler() noexcept -> auto& { return _profiler; } private: friend class Deferred_renderer_factory; Deferred_renderer_factory* _factory; ecs::Entity_manager* _entity_manager; util::maybe _meta_system; graphic::Descriptor_pool _descriptor_set_pool; std::unique_ptr _gbuffer; Global_uniforms _global_uniforms; graphic::Profiler _profiler; float _time_acc = 0.f; float _delta_time = 0.f; std::unique_ptr _texture_cache; std::unique_ptr _model_loader; vk::UniqueDescriptorSetLayout _global_uniform_descriptor_set_layout; vk::UniqueDescriptorSet _global_uniform_descriptor_set; graphic::Dynamic_buffer _global_uniform_buffer; std::vector> _passes; Camera_comp::Pool* _cameras; util::maybe _active_camera; void _write_global_uniform_descriptor_set(); void _update_global_uniforms(vk::CommandBuffer, const Camera_state& camera); }; } // namespace mirrage::renderer