#pragma once #include "../render/Image_View.h" #include "../render/Render_Output.h" #include #include #include #include #include #include namespace renderive { struct Present_Surface_Lease_Access; class Present_Surface_Lease { public: Present_Surface_Lease(); Present_Surface_Lease(Present_Surface_Lease&& other) noexcept; Present_Surface_Lease& operator=(Present_Surface_Lease&& other) noexcept; ~Present_Surface_Lease(); [[nodiscard]] explicit operator bool() const; [[nodiscard]] bool new_frame() const; [[nodiscard]] bool request_was_pending() const; [[nodiscard]] Image_View image() const; private: friend struct Present_Surface_Lease_Access; static constexpr std::size_t Storage_Size = 96; static constexpr std::size_t Storage_Align = alignof(std::max_align_t); using Storage = std::aligned_storage_t; using Output_Fn = Render_Output* (*)(const void*); using Destroy_Fn = void (*)(void*); using Move_Fn = void (*)(void*, void*); template static Present_Surface_Lease from_handle(bool is_new_frame, bool update_was_pending, Args&&... args) { static_assert(sizeof(Handle) <= Storage_Size, "Present surface handle exceeds inline lease storage"); static_assert(alignof(Handle) <= Storage_Align, "Present surface handle exceeds inline lease alignment"); Present_Surface_Lease lease; std::construct_at(reinterpret_cast(&lease.storage_), std::forward(args)...); lease.output_ = [](const void* storage) -> Render_Output* { return reinterpret_cast(storage)->output(); }; lease.destroy_ = [](void* storage) { std::destroy_at(reinterpret_cast(storage)); }; lease.move_ = [](void* destination, void* source) { std::construct_at(reinterpret_cast(destination), std::move(*reinterpret_cast(source))); std::destroy_at(reinterpret_cast(source)); }; lease.is_new_frame = is_new_frame; lease.update_was_pending = update_was_pending; return lease; } static Present_Surface_Lease empty(bool is_new_frame, bool update_was_pending); [[nodiscard]] Render_Output* output() const; void reset(); void move_from(Present_Surface_Lease&& other) noexcept; Storage storage_{}; Output_Fn output_{}; Destroy_Fn destroy_{}; Move_Fn move_{}; bool is_new_frame{}; bool update_was_pending{}; }; struct Present_Surface_Lease_Access { template static Present_Surface_Lease from_handle(bool is_new_frame, bool update_was_pending, Args&&... args) { return Present_Surface_Lease::from_handle(is_new_frame, update_was_pending, std::forward(args)...); } static Present_Surface_Lease empty(bool is_new_frame, bool update_was_pending) { return Present_Surface_Lease::empty(is_new_frame, update_was_pending); } static Render_Output* output(const Present_Surface_Lease& lease) { return lease.output(); } static void reset(Present_Surface_Lease& lease) { lease.reset(); } }; } // namespace renderive