仍然闪烁
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
#include "Explicit_Renderable_Runtime.h"
|
||||
#include "../../architecture/Renderable.h"
|
||||
#include "../../base/Memory.h"
|
||||
#include <mutex>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
|
||||
namespace renderive {
|
||||
|
||||
namespace {
|
||||
|
||||
struct Explicit_Input_Slot {
|
||||
Input_Data* data{};
|
||||
std::uint64_t version = 0;
|
||||
bool pending = false;
|
||||
std::shared_ptr<Update_State> completion_state;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
struct Explicit_Renderable_Runtime_Data {
|
||||
Renderable* owner{};
|
||||
mutable std::mutex state_mutex;
|
||||
mutable std::mutex input_mutex;
|
||||
Render_Object_Owner state_owner;
|
||||
Render_State* state{};
|
||||
Render_Object_Owner input_owner;
|
||||
Explicit_Input_Slot input;
|
||||
std::uint64_t input_version = 0;
|
||||
std::pmr::vector<std::shared_ptr<Update_State>> committed_update_states{memory_resource(Memory_Domain::Update_Completion)};
|
||||
|
||||
void initialize(Renderable& renderable) {
|
||||
clear();
|
||||
state_owner = renderable.create_render_state();
|
||||
state = state_owner.get<Render_State>();
|
||||
if (state)
|
||||
state->version = 1;
|
||||
input_owner = renderable.create_input_data();
|
||||
input.data = input_owner.get<Input_Data>();
|
||||
input.version = 0;
|
||||
input.pending = false;
|
||||
input.completion_state.reset();
|
||||
}
|
||||
|
||||
void cancel_pending_completions() {
|
||||
std::lock_guard<std::mutex> lock(input_mutex);
|
||||
if (input.completion_state) {
|
||||
input.completion_state->complete_all(std::make_error_code(std::errc::operation_canceled), Update_Outcome::Cancelled);
|
||||
input.completion_state.reset();
|
||||
}
|
||||
cancel_update_states(committed_update_states);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
{
|
||||
std::lock_guard<std::mutex> input_lock(input_mutex);
|
||||
if (input.completion_state) {
|
||||
input.completion_state->complete_all(std::make_error_code(std::errc::operation_canceled), Update_Outcome::Cancelled);
|
||||
input.completion_state.reset();
|
||||
}
|
||||
input.data = nullptr;
|
||||
input.version = 0;
|
||||
input.pending = false;
|
||||
input_owner.reset();
|
||||
input_version = 0;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> state_lock(state_mutex);
|
||||
state = nullptr;
|
||||
state_owner.reset();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
struct Explicit_State_Read_Handle final : Render_State_Read_Handle {
|
||||
explicit Explicit_State_Read_Handle(std::unique_lock<std::mutex> lock)
|
||||
: lock(std::move(lock)) {}
|
||||
std::unique_lock<std::mutex> lock;
|
||||
};
|
||||
|
||||
struct Explicit_Input_Frame_Handle final : Render_Input_Frame_Handle {
|
||||
Explicit_Input_Frame_Handle(Explicit_Renderable_Runtime_Data* runtime, std::unique_lock<std::mutex> lock)
|
||||
: runtime(runtime), lock(std::move(lock)) {}
|
||||
void consume_input(Input_Data* input) override {
|
||||
if (consumed || !runtime)
|
||||
return;
|
||||
consumed = true;
|
||||
if (runtime->input.completion_state) {
|
||||
runtime->input.completion_state->complete_until(Update_Stage::Committed);
|
||||
runtime->committed_update_states.push_back(std::move(runtime->input.completion_state));
|
||||
}
|
||||
if (input)
|
||||
input->clear();
|
||||
runtime->input.pending = false;
|
||||
}
|
||||
Explicit_Renderable_Runtime_Data* runtime{};
|
||||
std::unique_lock<std::mutex> lock;
|
||||
bool consumed = false;
|
||||
};
|
||||
|
||||
struct Explicit_State_Write_Handle final : Render_State_Write_Handle {
|
||||
Explicit_State_Write_Handle(Explicit_Renderable_Runtime_Data* runtime, std::unique_lock<std::mutex> lock)
|
||||
: runtime(runtime), lock(std::move(lock)) {}
|
||||
~Explicit_State_Write_Handle() override {
|
||||
if (!runtime || !runtime->state)
|
||||
return;
|
||||
++runtime->state->version;
|
||||
lock.unlock();
|
||||
if (runtime->owner)
|
||||
runtime->owner->mark_render_dirty(Dirty_Reason::Config);
|
||||
}
|
||||
Explicit_Renderable_Runtime_Data* runtime{};
|
||||
std::unique_lock<std::mutex> lock;
|
||||
};
|
||||
|
||||
struct Explicit_Input_Write_Handle final : Render_Input_Write_Handle {
|
||||
Explicit_Input_Write_Handle(Explicit_Renderable_Runtime_Data* runtime, std::unique_lock<std::mutex> lock, bool notify_render)
|
||||
: runtime(runtime), lock(std::move(lock)), notify_render(notify_render) {}
|
||||
~Explicit_Input_Write_Handle() override {
|
||||
if (!runtime)
|
||||
return;
|
||||
runtime->input.version = ++runtime->input_version;
|
||||
runtime->input.pending = true;
|
||||
lock.unlock();
|
||||
if (notify_render && runtime->owner)
|
||||
runtime->owner->mark_render_dirty();
|
||||
}
|
||||
void set_completion(std::shared_ptr<Update_State> state) override {
|
||||
if (!runtime)
|
||||
return;
|
||||
if (runtime->input.completion_state && runtime->input.completion_state != state)
|
||||
runtime->input.completion_state->complete_all(std::make_error_code(std::errc::operation_canceled), Update_Outcome::Cancelled);
|
||||
runtime->input.completion_state = std::move(state);
|
||||
}
|
||||
Explicit_Renderable_Runtime_Data* runtime{};
|
||||
std::unique_lock<std::mutex> lock;
|
||||
bool notify_render{};
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
Explicit_Renderable_Runtime::Explicit_Renderable_Runtime(Renderable& owner)
|
||||
: d(std::make_unique<Explicit_Renderable_Runtime_Data>()) {
|
||||
d->owner = &owner;
|
||||
d->initialize(owner);
|
||||
}
|
||||
|
||||
Explicit_Renderable_Runtime::~Explicit_Renderable_Runtime() {
|
||||
d->clear();
|
||||
}
|
||||
|
||||
void Explicit_Renderable_Runtime::set_render_state_copier(Copy_Render_State_Function) {}
|
||||
|
||||
void Explicit_Renderable_Runtime::cancel_pending_completions() {
|
||||
d->cancel_pending_completions();
|
||||
}
|
||||
|
||||
void Explicit_Renderable_Runtime::drain_committed_update_states(std::pmr::vector<std::shared_ptr<Update_State>>& output) {
|
||||
for (auto& state : d->committed_update_states)
|
||||
output.push_back(std::move(state));
|
||||
d->committed_update_states.clear();
|
||||
}
|
||||
|
||||
Render_State_Read_Guard Explicit_Renderable_Runtime::acquire_state_read(Renderable_State_Role) {
|
||||
return acquire_render_state_read();
|
||||
}
|
||||
|
||||
Render_State_Read_Guard Explicit_Renderable_Runtime::acquire_render_state_read() {
|
||||
std::unique_lock<std::mutex> lock(d->state_mutex);
|
||||
if (!d->state)
|
||||
return {};
|
||||
return Render_State_Read_Guard(d->state, std::make_unique<Explicit_State_Read_Handle>(std::move(lock)));
|
||||
}
|
||||
|
||||
Render_State_Read_Guard Explicit_Renderable_Runtime::acquire_edit_state_read() {
|
||||
return acquire_render_state_read();
|
||||
}
|
||||
|
||||
Render_State_Write_Guard Explicit_Renderable_Runtime::acquire_edit_state() {
|
||||
std::unique_lock<std::mutex> lock(d->state_mutex);
|
||||
if (!d->state)
|
||||
return {};
|
||||
return Render_State_Write_Guard(d->state, std::make_unique<Explicit_State_Write_Handle>(d.get(), std::move(lock)));
|
||||
}
|
||||
|
||||
Render_Input_Write_Guard Explicit_Renderable_Runtime::acquire_edit_input(bool notify_render) {
|
||||
std::unique_lock<std::mutex> lock(d->input_mutex);
|
||||
if (!d->input.data)
|
||||
return {};
|
||||
return Render_Input_Write_Guard(d->input.data, std::make_unique<Explicit_Input_Write_Handle>(d.get(), std::move(lock), notify_render));
|
||||
}
|
||||
|
||||
Renderable_Frame_View Explicit_Renderable_Runtime::capture_frame_view() {
|
||||
std::unique_lock<std::mutex> state_lock(d->state_mutex);
|
||||
if (!d->state)
|
||||
return {};
|
||||
auto state_guard = Render_State_Read_Guard(
|
||||
d->state,
|
||||
std::make_unique<Explicit_State_Read_Handle>(std::move(state_lock)));
|
||||
|
||||
Render_Input_Frame_Guard input_guard;
|
||||
std::unique_lock<std::mutex> input_lock(d->input_mutex);
|
||||
if (d->input.data) {
|
||||
input_guard = Render_Input_Frame_Guard(
|
||||
d->input.data,
|
||||
std::make_unique<Explicit_Input_Frame_Handle>(d.get(), std::move(input_lock)));
|
||||
}
|
||||
return Renderable_Frame_View(std::move(state_guard), std::move(input_guard));
|
||||
}
|
||||
|
||||
Render_State* Explicit_Renderable_Runtime::state(Renderable_State_Role) {
|
||||
return d->state;
|
||||
}
|
||||
|
||||
Input_Data* Explicit_Renderable_Runtime::input_data(Renderable_Input_Role) {
|
||||
return d->input.data;
|
||||
}
|
||||
|
||||
void Explicit_Renderable_Runtime::clear_render_input() {
|
||||
std::lock_guard<std::mutex> lock(d->input_mutex);
|
||||
if (d->input.completion_state) {
|
||||
d->input.completion_state->complete_until(Update_Stage::Committed);
|
||||
d->committed_update_states.push_back(std::move(d->input.completion_state));
|
||||
}
|
||||
if (d->input.data)
|
||||
d->input.data->clear();
|
||||
d->input.pending = false;
|
||||
}
|
||||
|
||||
std::unique_ptr<Renderable_Runtime> make_explicit_renderable_runtime(Renderable& owner) {
|
||||
return std::make_unique<Explicit_Renderable_Runtime>(owner);
|
||||
}
|
||||
|
||||
} // namespace renderive
|
||||
Reference in New Issue
Block a user