#pragma once //STL includes required by EU07 includes #include #include #include #include #include // OpenGL includes required by EU07 includes #include // for GLuint, GLint // Div. includes required by EU07 includes #include #include #include #include #include #include #include // EU07 includes #include #include #include "nvrenderer_enums.h" #include "quadtree.h" #include "rendering/renderer.h" #include "resource_registry.h" #include "environment/sky.h" namespace Rt { struct IRtModel; } template struct MaRendererConstants { static constexpr size_t NumMaterialPasses() noexcept { return static_cast(Renderer::RenderPassType::Num); } static constexpr size_t NumDrawTypes() noexcept { return static_cast(Renderer::DrawType::Num); } static constexpr size_t NumShadowPipelines() noexcept { return NumDrawTypes() << 1; } static constexpr size_t NumMaterialPipelines() noexcept { return NumDrawTypes() * NumMaterialPasses(); } static constexpr size_t GetPipelineIndex( typename Renderer::RenderPassType pass_type, typename Renderer::DrawType draw_type) { return static_cast(draw_type) * NumMaterialPasses() + static_cast(pass_type); } static constexpr size_t GetDefaultShadowPipelineIndex( typename Renderer::DrawType type, const bool masked) { return static_cast(type) << 1 | !!masked & 1; } }; class NvRenderer : public gfx_renderer, public MaResourceRegistry { public: enum class Api { D3D11, D3D12, Vulkan }; using RenderPassType = RendererEnums::RenderPassType; using DrawType = RendererEnums::DrawType; public: using Constants = MaRendererConstants; // SZ renderer interface implementation virtual ~NvRenderer() override {} virtual bool Init(GLFWwindow *Window) override; virtual bool AddViewport( const global_settings::extraviewport_config &conf) override; virtual void Shutdown() override; virtual bool Render() override; virtual void SwapBuffers() override; virtual float Framerate() override; virtual gfx::geometrybank_handle Create_Bank() override; virtual gfx::geometry_handle Insert(gfx::index_array &Indices, gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometrybank_handle const &Geometry, int const Type) override; virtual gfx::geometry_handle Insert(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometrybank_handle const &Geometry, int const Type) override; virtual bool Replace(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type, std::size_t const Offset = 0) override; virtual bool Append(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type) override; virtual gfx::index_array const &Indices( gfx::geometry_handle const &Geometry) const override; virtual gfx::vertex_array const &Vertices( gfx::geometry_handle const &Geometry) const override; const gfx::userdata_array &UserData( const gfx::geometry_handle &Geometry) const override; virtual material_handle Fetch_Material(std::string const &Filename, bool const Loadnow = true) override; virtual void Bind_Material(material_handle const Material, TSubModel const *sm = nullptr, lighting_data const *lighting = nullptr) override; virtual IMaterial const *Material( material_handle const Material) const override; virtual std::shared_ptr Fetch_Shader( std::string const &name) override; virtual texture_handle Fetch_Texture( std::string const &Filename, bool const Loadnow = true, GLint format_hint = GL_SRGB_ALPHA) override; virtual void Bind_Texture(texture_handle const Texture) override; virtual void Bind_Texture(std::size_t const Unit, texture_handle const Texture) override; virtual ITexture &Texture(texture_handle const Texture) override; virtual ITexture const &Texture(texture_handle const Texture) const override; virtual void Pick_Control_Callback( std::function Callback) override; virtual void Pick_Node_Callback( std::function Callback) override; virtual TSubModel const *Pick_Control() const override; virtual scene::basic_node const *Pick_Node() const override; virtual glm::dvec3 Mouse_Position() const override; virtual void Update(double const Deltatime) override; virtual void Update_Pick_Control() override; virtual void Update_Pick_Node() override; virtual glm::dvec3 Update_Mouse_Position() override; virtual bool Debug_Ui_State(std::optional) override; virtual std::string const &info_times() const override; virtual std::string const &info_stats() const override; virtual imgui_renderer *GetImguiRenderer() override; virtual void MakeScreenshot() override; NvRenderer(Api api) : m_api(api), MaResourceRegistry(nullptr) {} static bool d3d11_renderer_register; static bool d3d12_renderer_register; static bool vk_renderer_register; static bool renderer_register; struct IFrustumTester { virtual bool IntersectSphere(const glm::dvec3 &origin, double radius) const = 0; virtual bool IntersectBox(const glm::dvec3 &origin, const glm::dvec3 &extent) const = 0; virtual bool IntersectBox(const glm::dmat4x3 &transform, const glm::dvec3 &origin, const glm::dvec3 &extent) const = 0; }; class NvRendererBackend *GetBackend() const { return m_backend.get(); } // private: friend class NvRendererBackend; friend class NvRendererMessageCallback; friend class NvImguiRenderer; friend class NvTextureManager; friend struct NvGbuffer; friend struct NvSsao; friend struct FullScreenPass; friend struct NvTAA; friend struct NvFSR; friend struct MaEnvironment; friend struct MaShadowMap; Api m_api; std::shared_ptr m_backend; std::shared_ptr m_message_callback; std::shared_ptr m_imgui_renderer; std::shared_ptr m_gbuffer; std::shared_ptr m_gbuffer_cube; std::shared_ptr m_gbuffer_shadow; std::shared_ptr m_gbuffer_lighting; std::shared_ptr m_gbuffer_blit; std::shared_ptr m_ssao; std::shared_ptr m_motion_cache; std::shared_ptr m_instance_cache; std::shared_ptr m_taa; std::shared_ptr m_tonemap; std::shared_ptr m_fsr; std::shared_ptr m_environment; std::shared_ptr m_shadow_map; std::shared_ptr m_contact_shadows; std::shared_ptr m_bloom; std::shared_ptr m_sky; std::shared_ptr m_auto_exposure; std::shared_ptr m_windshield_rain; std::unordered_map> rt_models; std::shared_ptr GetRtModel(TModel3d const *); std::shared_ptr m_config; struct MaConfig *GetConfig() const { return m_config.get(); } static struct MaConfig *Config(); struct GeometryBounds { glm::dvec3 m_origin; glm::dvec3 m_extent; }; GeometryBounds GetGeometryBounds(gfx::geometry_handle const &handle) const; size_t GetCurrentFrame() const; void DebugUi(); glm::dmat4 m_previous_view_proj; glm::dmat4 m_previous_view; bool m_debug_ui_active; nvrhi::CommandListHandle m_command_list; nvrhi::EventQueryHandle m_upload_event_query; std::mutex m_mtx_context_lock; glm::dvec3 m_previous_env_position; uint64_t m_previous_env_frame; glm::dvec3 m_mouse_ro; glm::dvec3 m_mouse_rd; TSubModel const *m_picked_submodel = nullptr; using section_sequence = std::vector; using distancecell_pair = std::pair; using cell_sequence = std::vector; struct RenderPass { RenderPassType m_type; double m_draw_range; uint64_t m_frame_index; bool m_draw_shapes = true; bool m_draw_lines = true; bool m_draw_tanimobj = true; bool m_draw_dynamic = true; bool m_draw_track = true; bool m_draw_instances = true; bool m_sort_batches = true; bool m_sort_transparents = true; nvrhi::CommandListHandle m_command_list_draw; nvrhi::CommandListHandle m_command_list_preparation; nvrhi::FramebufferHandle m_framebuffer; nvrhi::ViewportState m_viewport_state; glm::dmat4 m_projection; glm::dvec3 m_origin; glm::dmat3 m_transform; glm::dmat3 m_history_transform; double ScreenRadius(const glm::dvec3 &origin, double radius) const { glm::dvec4 ndc = m_projection * glm::dvec4(0., radius, -glm::length(origin - m_origin), 1.); return glm::abs(ndc.y / ndc.w); } double ScreenRadius(double sqr_distance, double radius) const { glm::dvec4 ndc = m_projection * glm::dvec4(0., radius, -glm::sqrt(sqr_distance), 1.); return glm::abs(ndc.y / ndc.w); } bool NeedsHistory() const { return m_type == RenderPassType::Deferred; } bool SphereVisible(const glm::dvec3 &origin, double radius) const { return !m_frustum_tester || m_frustum_tester->IntersectSphere(origin - m_origin, radius); } bool BoxVisible(const glm::dvec3 &origin, const glm::dvec3 &extent) const { return !m_frustum_tester || m_frustum_tester->IntersectBox(origin - m_origin, extent); } bool BoxVisible(glm::dmat4x3 transform, const glm::dvec3 &origin, const glm::dvec3 &extent) const { transform[3] -= m_origin; return !m_frustum_tester || m_frustum_tester->IntersectBox(transform, origin, extent); } bool Visible(scene::bounding_area const &area) const { return SphereVisible(area.center, area.radius); } bool Visible(TDynamicObject *dynamic) const { return SphereVisible(dynamic->GetPosition(), dynamic->radius() * 1.25); } const IFrustumTester *m_frustum_tester; }; struct GeometryChunk { std::vector m_vertices; std::vector m_indices; size_t m_vertex_offset; size_t m_index_offset; size_t m_vertex_count; size_t m_index_count; bool m_indexed; bool m_is_uptodate = false; uint64_t m_last_frame_requested = static_cast(-1); uint64_t m_last_frame_updated = static_cast(-1); uint64_t m_last_frame_uploaded = static_cast(-1); nvrhi::BufferHandle m_index_buffer; nvrhi::BufferHandle m_vertex_buffer; nvrhi::EventQueryHandle m_chunk_ready_handle; std::future m_chunk_upload; glm::vec3 m_origin; glm::vec3 m_extent; glm::dvec3 m_last_position_requested; std::function m_replace_impl; void UpdateBounds(); }; struct GeometryBank { nvrhi::BufferHandle m_index_buffer; nvrhi::BufferHandle m_vertex_buffer; size_t m_vertex_count; size_t m_index_count; std::vector m_chunks; bool m_is_uptodate = false; nvrhi::EventQueryHandle m_uploaded_query; uint64_t m_last_frame_requested = static_cast(-1); }; std::vector m_geometry_banks; nvrhi::BufferHandle m_culling_view_data; struct GeometryBatch { struct CullingViewData { glm::vec4 m_frustum_planes[6]; glm::mat4 m_projection; }; struct CullingPushConstants { glm::vec3 m_origin; float m_instance_radius; float m_min_radius; float m_max_radius; uint32_t m_num_instances; }; struct CullingCommandBuffer { uint32_t m_index_count_per_instance; uint32_t m_instance_count; uint32_t m_start_index_location; int32_t m_base_vertex_location; uint32_t m_start_instance_location; }; gfx::geometry_handle m_geometry; material_handle m_material; std::vector m_transforms; glm::vec3 m_diffuse; glm::dvec3 m_origin; glm::dvec3 m_extent; glm::dvec3 m_instance_origin; nvrhi::BufferHandle m_static_instance_buffer; nvrhi::BufferHandle m_instance_buffer; nvrhi::BufferHandle m_static_command_buffer; nvrhi::BufferHandle m_command_buffer; nvrhi::BindingSetHandle m_culling_binding_set; double m_sqr_distance_max; double m_sqr_distance_min; double m_instance_radius; std::string m_name; }; std::vector m_geometry_batches; QuadTree m_batch_quadtree; struct TrackBatch { std::string m_name; glm::dvec3 m_origin; glm::dvec3 m_extent; glm::dvec3 m_geometry_origin; glm::vec3 m_diffuse; std::vector m_draw_commands; gfx::geometry_handle m_geometry; material_handle m_material; nvrhi::BufferHandle m_command_buffer; struct BufferRegion { size_t m_start_vertex; size_t m_vertex_count; size_t m_start_index; size_t m_index_count; }; std::vector m_regions; std::vector m_regions_need_update; }; bool TrackBatchPartialUpdate(size_t batch_index, size_t track_index, gfx::vertex_array &vertices); std::vector m_track_batches; QuadTree m_track_quadtree; struct Shape { std::string m_name; glm::dvec3 m_origin; glm::dvec3 m_extent; glm::dvec3 m_geometry_origin; gfx::geometry_handle m_geometry; bool m_draw_in_opaque; bool m_draw_in_transparent; material_handle m_material; glm::vec3 m_diffuse; }; std::vector m_shapes; QuadTree m_shape_quadtree; struct Line { std::string m_name; glm::dvec3 m_origin; glm::dvec3 m_extent; glm::dvec3 m_geometry_origin; gfx::geometry_handle m_geometry; float m_line_width; glm::vec3 m_color; float m_metalness; float m_roughness; }; std::vector m_lines; QuadTree m_line_quadtree; struct Renderable { struct RenderableItem { bool m_render_in_forward = false; glm::dmat4x3 m_transform; glm::dmat4x3 m_history_transform; gfx::geometry_handle m_geometry; material_handle m_material; double m_sqr_distance_max; double m_sqr_distance_min; float m_opacity; float m_selfillum; glm::vec3 m_diffuse; std::string_view m_name = ""; }; struct SpotLight { glm::vec3 m_color; glm::dvec3 m_origin; glm::vec3 m_direction; float m_radius; float m_cos_inner_cone; float m_cos_outer_cone; }; std::vector m_items; std::vector m_spotlights; bool m_render_in_deferred = false; bool m_render_in_forward = false; void Reset() { m_items.clear(); m_spotlights.clear(); m_render_in_deferred = false; m_render_in_forward = false; } }; struct AnimObj { std::string m_name; glm::dvec3 m_origin; glm::dvec3 m_extent; bool m_render_in_deferred; bool m_render_in_forward; bool m_animatable; bool m_was_once_animated = false; double m_sqr_distance_max; double m_sqr_distance_min; double m_distance; TAnimModel *m_model; Renderable m_renderable; }; std::vector m_animateds; QuadTree m_animated_quadtree; struct DynObj { TDynamicObject *m_dynamic; glm::dvec3 m_location; double m_radius; double m_distance; Renderable m_renderable; Renderable m_renderable_kabina; }; uint32_t m_dynamic_with_kabina; std::vector m_dynamics; std::vector m_renderable_dynamics; std::vector m_renderable_spotlights; struct Cell { scene::basic_cell *m_cell; glm::dvec3 m_origin; glm::dvec3 m_extent; }; std::vector m_cells; QuadTree m_cell_quadtree; void GatherSpotLights(const RenderPass &pass); void UpdateGeometry(gfx::geometry_handle handle, const RenderPass &pass, bool *p_is_uploading = nullptr); section_sequence m_sectionqueue; cell_sequence m_cellqueue; struct MaterialCache; struct MaterialTemplate : public MaResourceRegistry { struct TextureBinding { std::string m_name; std::string m_sampler_name; int m_hint; bool disable_anisotropy = false; bool disable_filter = false; bool disable_mip_bias = false; texture_handle m_default_texture; }; bool m_enable_refraction = false; nvrhi::static_vector m_texture_bindings; std::array m_pipelines; std::array m_resource_mappings; std::string m_name; std::string m_masked_shadow_texture; nvrhi::BindingLayoutHandle m_binding_layout; virtual bool CreateBindingSet(size_t pipeline_index, MaterialCache &cache); [[nodiscard]] nvrhi::IGraphicsPipeline *GetPipeline( RenderPassType pass_type, DrawType draw_type, bool alpha_masked) const; virtual void Init(const YAML::Node &conf); MaterialTemplate(const std::string &name, NvRenderer *renderer) : m_name(name), MaResourceRegistry(renderer), m_renderer(renderer) {} NvRenderer *m_renderer; }; struct MaterialCache : public IMaterial, public MaResourceRegistry { explicit MaterialCache(MaterialTemplate *my_template) : MaResourceRegistry(my_template), m_template(my_template) {} void Init() { InitResourceRegistry(); } std::array m_last_texture_updates{}; std::string m_name; std::array m_pipelines; std::array m_binding_sets; std::array m_texture_handles; nvrhi::BindingSetHandle m_binding_set; nvrhi::BindingSetHandle m_binding_set_cubemap; nvrhi::BindingSetHandle m_binding_set_shadow; glm::dvec3 m_last_position_requested; MaterialTemplate *m_template; bool m_masked_shadow; int m_shadow_rank; uint64_t m_last_frame_requested = 0; std::optional m_opacity; glm::dvec2 m_size; [[nodiscard]] bool ShouldRenderInPass(const RenderPass &pass) const; void finalize(bool Loadnow) override {} bool update() override { return false; } [[nodiscard]] float get_or_guess_opacity() const override { if (m_opacity.has_value()) return *m_opacity; if (m_masked_shadow) return 0.0f; else return 0.5f; } bool is_translucent() const override { return m_masked_shadow; } glm::vec2 GetSize() const override { return m_size; } std::string GetName() const override { return m_name; } std::optional GetSelfillum() const override { return std::nullopt; } texture_handle GetTexture(int slot) const override { return m_texture_handles[slot]; }; int GetShadowRank() const override { return m_shadow_rank; } }; std::unordered_map m_material_map; std::vector m_material_cache; bool m_scene_initialized = false; bool m_envir_can_filter = false; std::array(DrawType::Num)> m_input_layouts; nvrhi::InputLayoutHandle GetInputLayout(DrawType draw_type); struct DrawConstants { glm::mat4 m_jittered_projection; glm::mat4 m_projection; glm::mat4 m_projection_history; }; struct CubeDrawConstants { glm::mat4 m_face_projection; }; struct PushConstantsDraw { glm::mat3x4 m_modelview; glm::mat3x4 m_modelview_history; glm::vec3 m_diffuse; float m_alpha_threshold; float m_alpha_mult; float m_selfillum; }; typedef PushConstantsDraw PushConstantsCubemap; struct PushConstantsLine { glm::mat3x4 m_modelview; glm::mat3x4 m_modelview_history; glm::vec3 m_color; float m_line_weight; float m_metalness; float m_roughness; }; struct PushConstantsShadow { glm::mat4 m_modelviewprojection; float m_alpha_threshold; }; bool InitMaterials(); std::unordered_map> m_material_templates; nvrhi::FramebufferHandle m_framebuffer_forward; nvrhi::BindingLayoutHandle m_binding_layout_drawconstants; nvrhi::BindingLayoutHandle m_binding_layout_cubedrawconstants; nvrhi::BindingLayoutHandle m_binding_layout_shadowdrawconstants; nvrhi::BindingLayoutHandle m_binding_layout_forward; nvrhi::BindingSetHandle m_binding_set_drawconstants; nvrhi::BindingSetHandle m_binding_set_cubedrawconstants; nvrhi::BindingSetHandle m_binding_set_shadowdrawconstants; nvrhi::BindingSetHandle m_binding_set_line; std::array m_binding_set_forward; nvrhi::BufferHandle m_cubedrawconstant_buffer; nvrhi::BufferHandle m_drawconstant_buffer; std::array m_vertex_shader; std::array m_vertex_shader_prepass; std::array m_vertex_shader_cubemap; std::array m_vertex_shader_shadow; nvrhi::BindingLayoutHandle m_binding_layout_shadow_masked; nvrhi::BindingLayoutHandle m_binding_layout_prepass; nvrhi::ShaderHandle m_pixel_shader_shadow_masked; nvrhi::ShaderHandle m_pixel_shader_prepass_masked; std::array m_input_layout; std::array m_pso_shadow; std::array m_pso_prepass; nvrhi::GraphicsPipelineHandle m_pso_line; std::condition_variable m_cv_next_frame; glm::mat4 m_previous_projection; struct DrawCallStat { void Reset() { m_drawcalls = 0; m_triangles = 0; } int m_drawcalls = 0; int m_triangles = 0; void Draw(nvrhi::DrawArguments const &args) { ++m_drawcalls; m_triangles += args.vertexCount * args.instanceCount / 3; } }; DrawCallStat m_drawcalls_shape{}; DrawCallStat m_drawcalls_line{}; DrawCallStat m_drawcalls_tanimobj{}; DrawCallStat m_drawcalls_dynamic{}; DrawCallStat m_drawcalls_track{}; DrawCallStat m_drawcalls_instances{}; DrawCallStat *m_drawcall_counter = nullptr; bool m_draw_shapes = true; bool m_draw_lines = true; bool m_draw_tanimobj = true; bool m_draw_dynamic = true; bool m_draw_track = true; bool m_draw_instances = true; bool m_sort_batches = true; bool m_sort_transparents = true; bool m_pause_animations = false; std::unordered_set m_batched_instances; static const void *CombinePointers(const void *a, const void *b) { union { struct { uint32_t a; uint32_t b; }; const void *c; } val{}; val.a = static_cast(reinterpret_cast(a)); val.b = static_cast(reinterpret_cast(b)); return val.c; } static double SqrDistToScreenSize(double sqr_dist, double radius) { double dist = glm::sqrt(sqr_dist); glm::dmat4 std_projection = glm::perspectiveRH_ZO(glm::radians(45.), 1., .1, 2e5); glm::dvec4 ndc = std_projection * glm::dvec4(0., radius, -dist, 1.); return glm::abs(ndc.y / ndc.w); }; void UpdateDrawData(const RenderPass &pass, const glm::dmat4 &transform, const glm::dmat4 &history_transform, float opacity_threshold, float opacity_mult, float selfillum, const glm::vec3& diffuse); void UpdateDrawDataLine(const RenderPass &pass, const glm::dmat4 &transform, const glm::dmat4 &history_transform, const Line &line); void BindConstants(const RenderPass &pass, nvrhi::GraphicsState &gfx_state); bool BindMaterial(material_handle handle, DrawType draw_type, const RenderPass &pass, nvrhi::GraphicsState &gfx_state, float &alpha_threshold, bool *out_is_refractive = nullptr); bool BindLineMaterial(DrawType draw_type, const RenderPass &pass, nvrhi::GraphicsState &gfx_state); bool BindGeometry(gfx::geometry_handle handle, const RenderPass &pass, nvrhi::GraphicsState &gfx_state, nvrhi::DrawArguments &args, bool &indexed); void GatherModelsForBatching(); void GatherTracksForBatching(); void GatherShapesForBatching(); void GatherAnimatedsForBatching(); void GatherCellsForAnimation(); void GatherDynamics(); void RenderBatches(const RenderPass &pass); void RenderTracks(const RenderPass &pass); void RenderShapes(const RenderPass &pass); void RenderLines(const RenderPass &pass); void RenderAnimateds(const RenderPass &pass); void RenderKabina(const RenderPass &pass); void Render(const Renderable &renderable, const RenderPass &pass, const glm::dvec3 &history_origin, const double distance); void Animate(const glm::dvec3 &origin, double radius, uint64_t frame); void Render(TAnimModel *Instance, const RenderPass &pass); bool Render(TDynamicObject *Dynamic, const RenderPass &pass); bool Render(TModel3d *Model, material_data const *Material, float const Squaredistance, const RenderPass &pass); void Render(TSubModel *Submodel, const RenderPass &pass); bool Render_cab(TDynamicObject const *Dynamic, const RenderPass &pass); void Animate(AnimObj &instance, const glm::dvec3 &origin, uint64_t frame); void Animate(DynObj &instance, const glm::dvec3 &origin, uint64_t frame); void Animate(Renderable &renderable, TModel3d *Model, const material_data *material, double distance, const glm::dvec3 &position, const glm::vec3 &angle, uint64_t frame); void Animate(Renderable &renderable, TModel3d *Model, const material_data *material, double distance, const glm::dmat4 &transform, uint64_t frame); void Animate(Renderable &renderable, TSubModel *Submodel, const material_data *material, double distance, const glm::dmat4 &transform, uint64_t frame); #if LIBMANUL_WITH_D3D12 bool InitForD3D12(GLFWwindow *Window); #endif #if LIBMANUL_WITH_VULKAN bool InitForVulkan(GLFWwindow *Window); #endif };