91 lines
3.3 KiB
C++
91 lines
3.3 KiB
C++
#pragma once
|
|
#include "../render/Image_View.h"
|
|
#include "../render/Render_Output.h"
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <new>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
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<Storage_Size, Storage_Align>;
|
|
using Output_Fn = Render_Output* (*)(const void*);
|
|
using Destroy_Fn = void (*)(void*);
|
|
using Move_Fn = void (*)(void*, void*);
|
|
|
|
template <typename Handle, typename... Args>
|
|
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<Handle*>(&lease.storage_), std::forward<Args>(args)...);
|
|
lease.output_ = [](const void* storage) -> Render_Output* {
|
|
return reinterpret_cast<const Handle*>(storage)->output();
|
|
};
|
|
lease.destroy_ = [](void* storage) {
|
|
std::destroy_at(reinterpret_cast<Handle*>(storage));
|
|
};
|
|
lease.move_ = [](void* destination, void* source) {
|
|
std::construct_at(reinterpret_cast<Handle*>(destination), std::move(*reinterpret_cast<Handle*>(source)));
|
|
std::destroy_at(reinterpret_cast<Handle*>(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 <typename Handle, typename... Args>
|
|
static Present_Surface_Lease from_handle(bool is_new_frame, bool update_was_pending, Args&&... args) {
|
|
return Present_Surface_Lease::from_handle<Handle>(is_new_frame, update_was_pending, std::forward<Args>(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
|