#pragma once #include "renderer_api/renderer_api.h" #include #include namespace pp::renderer { enum class RecordedRenderCommandKind : std::uint8_t { begin_render_pass, set_viewport, set_scissor, set_blend_state, set_depth_state, bind_shader, set_shader_uniform, bind_texture, bind_sampler, bind_mesh, draw, upload_texture, generate_mipmaps, transition_texture, copy_texture, read_texture, capture_frame, blit_render_target, end_render_pass, trace_marker, trace_begin_scope, trace_end_scope, }; struct RecordedRenderCommand { RecordedRenderCommandKind kind = RecordedRenderCommandKind::draw; TextureDesc target_desc {}; bool clear_color_enabled = false; ClearColor clear_color {}; bool clear_depth_enabled = false; float clear_depth = 1.0F; bool clear_stencil_enabled = false; std::uint8_t clear_stencil = 0; Viewport viewport {}; ScissorRect scissor {}; BlendState blend_state {}; DepthState depth_state {}; MeshDesc mesh_desc {}; DrawDesc draw_desc {}; TextureDesc texture_desc {}; std::uint32_t texture_slot = 0; SamplerDesc sampler_desc {}; std::uint32_t sampler_slot = 0; TextureDesc source_desc {}; TextureDesc destination_desc {}; TextureState before_state = TextureState::undefined; TextureState after_state = TextureState::undefined; ReadbackRegion readback_region {}; ReadbackRegion source_region {}; ReadbackRegion destination_region {}; BlitFilter blit_filter = BlitFilter::nearest; std::uint64_t upload_bytes = 0; std::uint32_t generated_mip_levels = 0; std::uint64_t generated_mip_bytes = 0; std::uint64_t copy_source_bytes = 0; std::uint64_t copy_destination_bytes = 0; std::uint64_t readback_bytes = 0; std::uint64_t capture_bytes = 0; std::uint64_t blit_source_bytes = 0; std::uint64_t blit_destination_bytes = 0; std::uint64_t uniform_bytes = 0; const char* component = ""; const char* name = ""; }; class RecordingTexture2D final : public ITexture2D { public: explicit RecordingTexture2D(TextureDesc desc) noexcept; [[nodiscard]] TextureDesc desc() const noexcept override; private: TextureDesc desc_ {}; }; class RecordingRenderTarget final : public IRenderTarget { public: explicit RecordingRenderTarget(TextureDesc color_desc) noexcept; [[nodiscard]] TextureDesc color_desc() const noexcept override; private: TextureDesc color_desc_ {}; }; class RecordingShaderProgram final : public IShaderProgram { public: explicit RecordingShaderProgram(const char* debug_name) noexcept; [[nodiscard]] const char* debug_name() const noexcept override; private: const char* debug_name_ = ""; }; class RecordingMesh final : public IMesh { public: explicit RecordingMesh(MeshDesc desc) noexcept; [[nodiscard]] MeshDesc desc() const noexcept override; private: MeshDesc desc_ {}; }; class RecordingReadbackBuffer final : public IReadbackBuffer { public: explicit RecordingReadbackBuffer(std::uint64_t size_bytes) noexcept; [[nodiscard]] std::uint64_t size_bytes() const noexcept override; private: std::uint64_t size_bytes_ = 0; }; class RecordingCommandContext final : public ICommandContext { public: explicit RecordingCommandContext(std::vector& commands) noexcept; [[nodiscard]] pp::foundation::Status begin_render_pass( IRenderTarget& target, RenderPassDesc desc) noexcept override; [[nodiscard]] pp::foundation::Status set_viewport(Viewport viewport) noexcept override; [[nodiscard]] pp::foundation::Status set_scissor(ScissorRect scissor) noexcept override; [[nodiscard]] pp::foundation::Status set_blend_state(BlendState state) noexcept override; [[nodiscard]] pp::foundation::Status set_depth_state(DepthState state) noexcept override; [[nodiscard]] pp::foundation::Status bind_shader(IShaderProgram& shader) noexcept override; [[nodiscard]] pp::foundation::Status set_shader_uniform( const char* name, std::span bytes) noexcept override; [[nodiscard]] pp::foundation::Status bind_texture( std::uint32_t slot, ITexture2D& texture) noexcept override; [[nodiscard]] pp::foundation::Status bind_sampler( std::uint32_t slot, SamplerDesc sampler) noexcept override; [[nodiscard]] pp::foundation::Status bind_mesh(IMesh& mesh) noexcept override; [[nodiscard]] pp::foundation::Status draw(DrawDesc desc) noexcept override; [[nodiscard]] pp::foundation::Status read_texture( ITexture2D& texture, ReadbackRegion region, IReadbackBuffer& destination) noexcept override; [[nodiscard]] pp::foundation::Status upload_texture( ITexture2D& texture, ReadbackRegion region, std::span rgba_or_channel_bytes) noexcept override; [[nodiscard]] pp::foundation::Status generate_mipmaps( ITexture2D& texture) noexcept override; [[nodiscard]] pp::foundation::Status transition_texture( ITexture2D& texture, TextureState before, TextureState after) noexcept override; [[nodiscard]] pp::foundation::Status copy_texture( ITexture2D& source, ReadbackRegion source_region, ITexture2D& destination, ReadbackRegion destination_region) noexcept override; [[nodiscard]] pp::foundation::Status capture_frame( IRenderTarget& target, IReadbackBuffer& destination) noexcept override; [[nodiscard]] pp::foundation::Status blit_render_target( IRenderTarget& source, ReadbackRegion source_region, IRenderTarget& destination, ReadbackRegion destination_region, BlitFilter filter) noexcept override; void end_render_pass() noexcept override; [[nodiscard]] bool in_render_pass() const noexcept; void reset() noexcept; private: std::vector* commands_ = nullptr; TextureDesc active_target_ {}; MeshDesc active_mesh_ {}; bool in_render_pass_ = false; bool shader_bound_ = false; bool mesh_bound_ = false; }; class RecordingRenderTrace final : public IRenderTrace { public: explicit RecordingRenderTrace(std::vector& commands) noexcept; [[nodiscard]] pp::foundation::Status marker(const char* component, const char* name) noexcept override; [[nodiscard]] pp::foundation::Status begin_scope(const char* component, const char* name) noexcept override; [[nodiscard]] pp::foundation::Status end_scope() noexcept override; void reset() noexcept; private: std::vector* commands_ = nullptr; std::uint32_t scope_depth_ = 0; }; class RecordingRenderDevice final : public IRenderDevice { public: RecordingRenderDevice() noexcept; [[nodiscard]] const char* backend_name() const noexcept override; [[nodiscard]] RenderDeviceFeatures features() const noexcept override; [[nodiscard]] pp::foundation::Result> create_texture( TextureDesc desc) noexcept override; [[nodiscard]] pp::foundation::Result> create_render_target( TextureDesc color_desc) noexcept override; [[nodiscard]] pp::foundation::Result> create_shader_program( ShaderProgramDesc desc) noexcept override; [[nodiscard]] pp::foundation::Result> create_mesh( MeshDesc desc) noexcept override; [[nodiscard]] pp::foundation::Result> create_readback_buffer( std::uint64_t size_bytes) noexcept override; [[nodiscard]] ICommandContext& immediate_context() noexcept override; [[nodiscard]] IRenderTrace* trace() noexcept override; [[nodiscard]] std::span commands() const noexcept; void clear() noexcept; private: std::vector commands_; RecordingCommandContext context_; RecordingRenderTrace trace_; }; [[nodiscard]] const char* recorded_render_command_kind_name(RecordedRenderCommandKind kind) noexcept; }