520 lines
22 KiB
C++
520 lines
22 KiB
C++
#include "../../architecture/Strategy_Render_Data.h"
|
|
#include "../../architecture/Renderable.h"
|
|
#include "../../base/Memory.h"
|
|
#include "Low_Latency_Roles.h"
|
|
#include "Triple_Buffer.h"
|
|
#include <array>
|
|
#include <mutex>
|
|
#include <ostream>
|
|
#include <system_error>
|
|
#include <utility>
|
|
|
|
namespace renderive {
|
|
|
|
std::ostream& operator<<(std::ostream& stream, const Range& range) {
|
|
stream << "Range(" << range.origin << ", " << range.target << ")";
|
|
return stream;
|
|
}
|
|
|
|
namespace {
|
|
|
|
struct Input_Buffer_Slot {
|
|
Input_Data* data{};
|
|
std::uint64_t version = 0;
|
|
bool pending = false;
|
|
std::shared_ptr<Update_State> completion_state;
|
|
};
|
|
|
|
std::uint8_t state_role_index(Renderable_State_Role role) {
|
|
switch (role) {
|
|
case Renderable_State_Role::Edit:
|
|
return State_Edit;
|
|
case Renderable_State_Role::Ready:
|
|
return State_Ready;
|
|
case Renderable_State_Role::Render:
|
|
return State_Render;
|
|
}
|
|
return State_Render;
|
|
}
|
|
|
|
std::uint8_t input_role_index(Renderable_Input_Role role) {
|
|
switch (role) {
|
|
case Renderable_Input_Role::Edit:
|
|
return Input_Edit;
|
|
case Renderable_Input_Role::Ready:
|
|
return Input_Ready;
|
|
case Renderable_Input_Role::Render:
|
|
return Input_Render;
|
|
}
|
|
return Input_Render;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
struct Strategy_Render_Data_Private {
|
|
Renderable_Runtime_Strategy runtime_strategy_value = Renderable_Runtime_Strategy::Low_Latency;
|
|
Triple_Role_Buffer_Control state_control;
|
|
std::array<Render_State*, 3> state_buffers{};
|
|
std::array<Render_Object_Owner, 3> state_buffer_owners{};
|
|
Triple_Role_Buffer_Control input_control;
|
|
std::array<Input_Buffer_Slot, 3> input_buffers{};
|
|
std::array<Render_Object_Owner, 3> input_buffer_owners{};
|
|
std::pmr::vector<std::shared_ptr<Update_State>> committed_update_states{memory_resource(Memory_Domain::Update_Completion)};
|
|
std::uint64_t input_version = 0;
|
|
mutable std::mutex explicit_state_mutex;
|
|
mutable std::mutex explicit_input_mutex;
|
|
Render_Object_Owner explicit_state_owner;
|
|
Render_State* explicit_state{};
|
|
Render_Object_Owner explicit_input_owner;
|
|
Input_Buffer_Slot explicit_input;
|
|
std::uint64_t explicit_input_version = 0;
|
|
|
|
Render_State* state_by_index(std::uint8_t index) const {
|
|
return index < state_buffers.size() ? state_buffers[index] : nullptr;
|
|
}
|
|
Render_State* state(std::uint8_t role) const {
|
|
if (runtime_strategy_value == Renderable_Runtime_Strategy::Explicit)
|
|
return explicit_state;
|
|
return state_by_index(state_control.read_view()[role]);
|
|
}
|
|
Input_Data* input_data_by_index(std::uint8_t index) const {
|
|
return index < input_buffers.size() ? input_buffers[index].data : nullptr;
|
|
}
|
|
Input_Buffer_Slot& input_slot_by_index(std::uint8_t index) {
|
|
return input_buffers[index];
|
|
}
|
|
const Input_Buffer_Slot& input_slot_by_index(std::uint8_t index) const {
|
|
return input_buffers[index];
|
|
}
|
|
Input_Buffer_Slot& input_slot(std::uint8_t role) {
|
|
return input_slot_by_index(input_control.read_view()[role]);
|
|
}
|
|
const Input_Buffer_Slot& input_slot(std::uint8_t role) const {
|
|
return input_slot_by_index(input_control.read_view()[role]);
|
|
}
|
|
Input_Data* input_data(std::uint8_t role) const {
|
|
if (runtime_strategy_value == Renderable_Runtime_Strategy::Explicit)
|
|
return explicit_input.data;
|
|
return input_slot(role).data;
|
|
}
|
|
Triple_Buffer_Lease try_mark_state_role(std::uint8_t role) {
|
|
auto record = state_control.try_acquire_role(role);
|
|
return record.result == Triple_Buffer_Result::Success ? record.lease : Triple_Buffer_Lease{};
|
|
}
|
|
Triple_Buffer_Lease mark_state_role(std::uint8_t role) {
|
|
auto record = state_control.acquire_role(role);
|
|
return record.result == Triple_Buffer_Result::Success ? record.lease : Triple_Buffer_Lease{};
|
|
}
|
|
void mark_input_dirty(Triple_Buffer_Lease lease) {
|
|
Input_Buffer_Slot& slot = input_slot_by_index(lease.index);
|
|
slot.version = ++input_version;
|
|
slot.pending = true;
|
|
}
|
|
void set_input_completion(Triple_Buffer_Lease lease, std::shared_ptr<Update_State> state) {
|
|
Input_Buffer_Slot& slot = input_slot_by_index(lease.index);
|
|
if (slot.completion_state && slot.completion_state != state)
|
|
slot.completion_state->complete_all({}, Update_Outcome::Superseded);
|
|
slot.completion_state = std::move(state);
|
|
}
|
|
void cancel_pending_completions() {
|
|
for (Input_Buffer_Slot& slot : input_buffers) {
|
|
if (!slot.completion_state)
|
|
continue;
|
|
slot.completion_state->complete_all(std::make_error_code(std::errc::operation_canceled), Update_Outcome::Cancelled);
|
|
slot.completion_state.reset();
|
|
}
|
|
{
|
|
std::lock_guard<std::mutex> lock(explicit_input_mutex);
|
|
if (explicit_input.completion_state) {
|
|
explicit_input.completion_state->complete_all(std::make_error_code(std::errc::operation_canceled), Update_Outcome::Cancelled);
|
|
explicit_input.completion_state.reset();
|
|
}
|
|
}
|
|
cancel_update_states(committed_update_states);
|
|
}
|
|
void clear_state_buffers() {
|
|
state_control.close_and_wait();
|
|
for (std::size_t i = 0; i < state_buffers.size(); ++i) {
|
|
state_buffer_owners[i].reset();
|
|
state_buffers[i] = nullptr;
|
|
}
|
|
state_control.reset();
|
|
}
|
|
void clear_input_buffers() {
|
|
input_control.close_and_wait();
|
|
cancel_pending_completions();
|
|
for (std::size_t i = 0; i < input_buffers.size(); ++i) {
|
|
input_buffer_owners[i].reset();
|
|
input_buffers[i].data = nullptr;
|
|
input_buffers[i].version = 0;
|
|
input_buffers[i].pending = false;
|
|
input_buffers[i].completion_state.reset();
|
|
}
|
|
input_version = 0;
|
|
input_control.reset();
|
|
}
|
|
void clear_explicit_runtime() {
|
|
{
|
|
std::lock_guard<std::mutex> input_lock(explicit_input_mutex);
|
|
if (explicit_input.completion_state) {
|
|
explicit_input.completion_state->complete_all(std::make_error_code(std::errc::operation_canceled), Update_Outcome::Cancelled);
|
|
explicit_input.completion_state.reset();
|
|
}
|
|
explicit_input.data = nullptr;
|
|
explicit_input.version = 0;
|
|
explicit_input.pending = false;
|
|
explicit_input_owner.reset();
|
|
explicit_input_version = 0;
|
|
}
|
|
{
|
|
std::lock_guard<std::mutex> state_lock(explicit_state_mutex);
|
|
explicit_state = nullptr;
|
|
explicit_state_owner.reset();
|
|
}
|
|
}
|
|
void initialize_low_latency_runtime_buffers(
|
|
Render_Object_Owner edit_state,
|
|
Render_Object_Owner ready_state,
|
|
Render_Object_Owner render_state,
|
|
Render_Object_Owner edit_input,
|
|
Render_Object_Owner ready_input,
|
|
Render_Object_Owner render_input) {
|
|
clear_state_buffers();
|
|
clear_input_buffers();
|
|
clear_explicit_runtime();
|
|
state_buffer_owners[State_Edit] = std::move(edit_state);
|
|
state_buffer_owners[State_Ready] = std::move(ready_state);
|
|
state_buffer_owners[State_Render] = std::move(render_state);
|
|
state_buffers[State_Edit] = state_buffer_owners[State_Edit].get<Render_State>();
|
|
state_buffers[State_Ready] = state_buffer_owners[State_Ready].get<Render_State>();
|
|
state_buffers[State_Render] = state_buffer_owners[State_Render].get<Render_State>();
|
|
input_buffer_owners[Input_Edit] = std::move(edit_input);
|
|
input_buffer_owners[Input_Ready] = std::move(ready_input);
|
|
input_buffer_owners[Input_Render] = std::move(render_input);
|
|
if (input_buffer_owners[Input_Edit])
|
|
input_buffers[Input_Edit].data = input_buffer_owners[Input_Edit].get<Input_Data>();
|
|
if (input_buffer_owners[Input_Ready])
|
|
input_buffers[Input_Ready].data = input_buffer_owners[Input_Ready].get<Input_Data>();
|
|
if (input_buffer_owners[Input_Render])
|
|
input_buffers[Input_Render].data = input_buffer_owners[Input_Render].get<Input_Data>();
|
|
if (state_buffers[State_Edit])
|
|
state_buffers[State_Edit]->version = 1;
|
|
}
|
|
void initialize_explicit_runtime_buffers(Render_Object_Owner state, Render_Object_Owner input) {
|
|
clear_state_buffers();
|
|
clear_input_buffers();
|
|
clear_explicit_runtime();
|
|
explicit_state_owner = std::move(state);
|
|
explicit_state = explicit_state_owner.get<Render_State>();
|
|
if (explicit_state)
|
|
explicit_state->version = 1;
|
|
explicit_input_owner = std::move(input);
|
|
explicit_input.data = explicit_input_owner.get<Input_Data>();
|
|
explicit_input.version = 0;
|
|
explicit_input.pending = false;
|
|
explicit_input.completion_state.reset();
|
|
}
|
|
void clear_input_role(Renderable_Input_Role role) {
|
|
if (runtime_strategy_value == Renderable_Runtime_Strategy::Explicit) {
|
|
std::lock_guard<std::mutex> lock(explicit_input_mutex);
|
|
if (explicit_input.completion_state) {
|
|
if (role == Renderable_Input_Role::Render) {
|
|
explicit_input.completion_state->complete_until(Update_Stage::Committed);
|
|
committed_update_states.push_back(std::move(explicit_input.completion_state));
|
|
}
|
|
else {
|
|
explicit_input.completion_state->complete_all({}, Update_Outcome::Superseded);
|
|
explicit_input.completion_state.reset();
|
|
}
|
|
}
|
|
if (explicit_input.data)
|
|
explicit_input.data->clear();
|
|
explicit_input.pending = false;
|
|
return;
|
|
}
|
|
Input_Buffer_Slot& slot = input_slot(input_role_index(role));
|
|
if (slot.completion_state) {
|
|
if (role == Renderable_Input_Role::Render) {
|
|
slot.completion_state->complete_until(Update_Stage::Committed);
|
|
committed_update_states.push_back(std::move(slot.completion_state));
|
|
}
|
|
else {
|
|
slot.completion_state->complete_all({}, Update_Outcome::Superseded);
|
|
slot.completion_state.reset();
|
|
}
|
|
}
|
|
if (slot.data)
|
|
slot.data->clear();
|
|
slot.pending = false;
|
|
}
|
|
};
|
|
|
|
namespace {
|
|
|
|
struct Low_Latency_State_Read_Handle final : Render_State_Read_Handle {
|
|
Low_Latency_State_Read_Handle(Strategy_Render_Data_Private* runtime, Triple_Buffer_Lease lease)
|
|
: runtime(runtime), lease(lease) {}
|
|
~Low_Latency_State_Read_Handle() override {
|
|
if (runtime && lease)
|
|
runtime->state_control.unmark_use(lease);
|
|
}
|
|
Strategy_Render_Data_Private* runtime{};
|
|
Triple_Buffer_Lease lease{};
|
|
};
|
|
|
|
struct Low_Latency_State_Edit_Handle final : Render_State_Edit_Handle {
|
|
Low_Latency_State_Edit_Handle(Strategy_Render_Data_Private* runtime, Renderable* owner, Triple_Buffer_Lease lease)
|
|
: runtime(runtime), owner(owner), lease(lease) {}
|
|
~Low_Latency_State_Edit_Handle() override {
|
|
if (!runtime || !lease)
|
|
return;
|
|
if (auto* state = runtime->state_by_index(lease.index))
|
|
++state->version;
|
|
runtime->state_control.unmark_use(lease);
|
|
if (owner)
|
|
owner->mark_render_dirty(Dirty_Reason::Config);
|
|
}
|
|
Strategy_Render_Data_Private* runtime{};
|
|
Renderable* owner{};
|
|
Triple_Buffer_Lease lease{};
|
|
};
|
|
|
|
struct Low_Latency_Input_Edit_Handle final : Render_Input_Edit_Handle {
|
|
Low_Latency_Input_Edit_Handle(Strategy_Render_Data_Private* runtime, Renderable* owner, Triple_Buffer_Lease lease, bool notify_render)
|
|
: runtime(runtime), owner(owner), lease(lease), notify_render(notify_render) {}
|
|
~Low_Latency_Input_Edit_Handle() override {
|
|
if (!runtime || !lease)
|
|
return;
|
|
runtime->mark_input_dirty(lease);
|
|
runtime->input_control.unmark_use(lease);
|
|
if (notify_render && owner)
|
|
owner->mark_render_dirty();
|
|
}
|
|
void set_completion(std::shared_ptr<Update_State> state) override {
|
|
if (runtime && lease)
|
|
runtime->set_input_completion(lease, std::move(state));
|
|
}
|
|
Strategy_Render_Data_Private* runtime{};
|
|
Renderable* owner{};
|
|
Triple_Buffer_Lease lease{};
|
|
bool notify_render{};
|
|
};
|
|
|
|
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_State_Edit_Handle final : Render_State_Edit_Handle {
|
|
Explicit_State_Edit_Handle(Strategy_Render_Data_Private* runtime, Renderable* owner, std::unique_lock<std::mutex> lock)
|
|
: runtime(runtime), owner(owner), lock(std::move(lock)) {}
|
|
~Explicit_State_Edit_Handle() override {
|
|
if (!runtime || !runtime->explicit_state)
|
|
return;
|
|
++runtime->explicit_state->version;
|
|
lock.unlock();
|
|
if (owner)
|
|
owner->mark_render_dirty(Dirty_Reason::Config);
|
|
}
|
|
Strategy_Render_Data_Private* runtime{};
|
|
Renderable* owner{};
|
|
std::unique_lock<std::mutex> lock;
|
|
};
|
|
|
|
struct Explicit_Input_Edit_Handle final : Render_Input_Edit_Handle {
|
|
Explicit_Input_Edit_Handle(Strategy_Render_Data_Private* runtime, Renderable* owner, std::unique_lock<std::mutex> lock, bool notify_render)
|
|
: runtime(runtime), owner(owner), lock(std::move(lock)), notify_render(notify_render) {}
|
|
~Explicit_Input_Edit_Handle() override {
|
|
if (!runtime)
|
|
return;
|
|
runtime->explicit_input.version = ++runtime->explicit_input_version;
|
|
runtime->explicit_input.pending = true;
|
|
lock.unlock();
|
|
if (notify_render && owner)
|
|
owner->mark_render_dirty();
|
|
}
|
|
void set_completion(std::shared_ptr<Update_State> state) override {
|
|
if (!runtime)
|
|
return;
|
|
if (runtime->explicit_input.completion_state && runtime->explicit_input.completion_state != state)
|
|
runtime->explicit_input.completion_state->complete_all({}, Update_Outcome::Superseded);
|
|
runtime->explicit_input.completion_state = std::move(state);
|
|
}
|
|
Strategy_Render_Data_Private* runtime{};
|
|
Renderable* owner{};
|
|
std::unique_lock<std::mutex> lock;
|
|
bool notify_render{};
|
|
};
|
|
|
|
} // namespace
|
|
|
|
Strategy_Render_Data::Strategy_Render_Data()
|
|
: runtime(std::make_unique<Strategy_Render_Data_Private>()) {}
|
|
|
|
Strategy_Render_Data::~Strategy_Render_Data() {
|
|
runtime->clear_state_buffers();
|
|
runtime->clear_input_buffers();
|
|
runtime->clear_explicit_runtime();
|
|
}
|
|
|
|
void Strategy_Render_Data::initialize_runtime(Renderable& owner, Renderable_Runtime_Strategy strategy) {
|
|
runtime->runtime_strategy_value = strategy;
|
|
if (strategy == Renderable_Runtime_Strategy::Explicit) {
|
|
runtime->initialize_explicit_runtime_buffers(owner.create_render_state(), owner.create_input_data());
|
|
return;
|
|
}
|
|
runtime->initialize_low_latency_runtime_buffers(
|
|
owner.create_render_state(),
|
|
owner.create_render_state(),
|
|
owner.create_render_state(),
|
|
owner.create_input_data(),
|
|
owner.create_input_data(),
|
|
owner.create_input_data());
|
|
}
|
|
|
|
Renderable_Runtime_Strategy Strategy_Render_Data::runtime_strategy() const {
|
|
return runtime->runtime_strategy_value;
|
|
}
|
|
|
|
void Strategy_Render_Data::cancel_pending_completions() {
|
|
runtime->cancel_pending_completions();
|
|
}
|
|
|
|
void Strategy_Render_Data::drain_committed_update_states(std::pmr::vector<std::shared_ptr<Update_State>>& output) {
|
|
for (auto& state : runtime->committed_update_states)
|
|
output.push_back(std::move(state));
|
|
runtime->committed_update_states.clear();
|
|
}
|
|
|
|
Render_State_Read_Guard Strategy_Render_Data::acquire_state_read(Renderable_State_Role role) {
|
|
if (runtime->runtime_strategy_value == Renderable_Runtime_Strategy::Explicit) {
|
|
std::unique_lock<std::mutex> lock(runtime->explicit_state_mutex);
|
|
if (!runtime->explicit_state)
|
|
return {};
|
|
return Render_State_Read_Guard(runtime->explicit_state, std::make_unique<Explicit_State_Read_Handle>(std::move(lock)));
|
|
}
|
|
Triple_Buffer_Lease lease = runtime->mark_state_role(state_role_index(role));
|
|
if (!lease)
|
|
return {};
|
|
return Render_State_Read_Guard(runtime->state_by_index(lease.index), std::make_unique<Low_Latency_State_Read_Handle>(runtime.get(), lease));
|
|
}
|
|
|
|
Render_State_Read_Guard Strategy_Render_Data::acquire_render_state_read() {
|
|
if (runtime->runtime_strategy_value == Renderable_Runtime_Strategy::Explicit) {
|
|
std::unique_lock<std::mutex> lock(runtime->explicit_state_mutex);
|
|
if (!runtime->explicit_state)
|
|
return {};
|
|
return Render_State_Read_Guard(runtime->explicit_state, std::make_unique<Explicit_State_Read_Handle>(std::move(lock)));
|
|
}
|
|
Triple_Buffer_Lease lease = runtime->try_mark_state_role(State_Render);
|
|
if (!lease)
|
|
return {};
|
|
return Render_State_Read_Guard(runtime->state_by_index(lease.index), std::make_unique<Low_Latency_State_Read_Handle>(runtime.get(), lease));
|
|
}
|
|
|
|
Render_State_Read_Guard Strategy_Render_Data::acquire_edit_state_read() {
|
|
if (runtime->runtime_strategy_value == Renderable_Runtime_Strategy::Explicit) {
|
|
std::unique_lock<std::mutex> lock(runtime->explicit_state_mutex);
|
|
if (!runtime->explicit_state)
|
|
return {};
|
|
return Render_State_Read_Guard(runtime->explicit_state, std::make_unique<Explicit_State_Read_Handle>(std::move(lock)));
|
|
}
|
|
Triple_Buffer_Lease lease = runtime->mark_state_role(State_Edit);
|
|
if (!lease)
|
|
return {};
|
|
return Render_State_Read_Guard(runtime->state_by_index(lease.index), std::make_unique<Low_Latency_State_Read_Handle>(runtime.get(), lease));
|
|
}
|
|
|
|
Render_State_Read_Guard Strategy_Render_Data::acquire_prepare_state_read() {
|
|
if (runtime->runtime_strategy_value != Renderable_Runtime_Strategy::Explicit)
|
|
return {};
|
|
std::unique_lock<std::mutex> lock(runtime->explicit_state_mutex);
|
|
if (!runtime->explicit_state)
|
|
return {};
|
|
return Render_State_Read_Guard(runtime->explicit_state, std::make_unique<Explicit_State_Read_Handle>(std::move(lock)));
|
|
}
|
|
|
|
Render_State_Edit_Guard Strategy_Render_Data::acquire_edit_state() {
|
|
if (runtime->runtime_strategy_value == Renderable_Runtime_Strategy::Explicit) {
|
|
std::unique_lock<std::mutex> lock(runtime->explicit_state_mutex);
|
|
if (!runtime->explicit_state)
|
|
return {};
|
|
return Render_State_Edit_Guard(runtime->explicit_state, std::make_unique<Explicit_State_Edit_Handle>(runtime.get(), q_ptr, std::move(lock)));
|
|
}
|
|
Triple_Buffer_Lease lease = runtime->mark_state_role(State_Edit);
|
|
if (!lease)
|
|
return {};
|
|
return Render_State_Edit_Guard(runtime->state_by_index(lease.index), std::make_unique<Low_Latency_State_Edit_Handle>(runtime.get(), q_ptr, lease));
|
|
}
|
|
|
|
Render_Input_Edit_Guard Strategy_Render_Data::acquire_edit_input(bool notify_render) {
|
|
if (runtime->runtime_strategy_value == Renderable_Runtime_Strategy::Explicit) {
|
|
std::unique_lock<std::mutex> lock(runtime->explicit_input_mutex);
|
|
if (!runtime->explicit_input.data)
|
|
return {};
|
|
return Render_Input_Edit_Guard(runtime->explicit_input.data, std::make_unique<Explicit_Input_Edit_Handle>(runtime.get(), q_ptr, std::move(lock), notify_render));
|
|
}
|
|
auto record = runtime->input_control.acquire_role(Input_Edit);
|
|
if (record.result != Triple_Buffer_Result::Success)
|
|
return {};
|
|
Input_Data* input = runtime->input_data_by_index(record.lease.index);
|
|
if (!input) {
|
|
runtime->input_control.unmark_use(record.lease);
|
|
return {};
|
|
}
|
|
return Render_Input_Edit_Guard(input, std::make_unique<Low_Latency_Input_Edit_Handle>(runtime.get(), q_ptr, record.lease, notify_render));
|
|
}
|
|
|
|
void Strategy_Render_Data::sync_state_pipeline() {
|
|
if (runtime->runtime_strategy_value == Renderable_Runtime_Strategy::Explicit)
|
|
return;
|
|
auto edit_record = runtime->state_control.try_acquire_role(State_Edit);
|
|
if (edit_record.result != Triple_Buffer_Result::Success)
|
|
return;
|
|
auto ready_record = runtime->state_control.try_acquire_role(State_Ready);
|
|
if (ready_record.result != Triple_Buffer_Result::Success) {
|
|
runtime->state_control.unmark_use(edit_record.lease);
|
|
return;
|
|
}
|
|
Render_State* ready = runtime->state_by_index(ready_record.lease.index);
|
|
Render_State* edit = runtime->state_by_index(edit_record.lease.index);
|
|
if (ready && edit && buffer_version_newer(edit->version, ready->version))
|
|
copy_render_state_object(*ready, *edit);
|
|
runtime->state_control.unmark_use(ready_record.lease);
|
|
runtime->state_control.unmark_use(edit_record.lease);
|
|
runtime->state_control.try_swap_role(State_Ready, State_Render, [this](const Triple_Buffer_View& view) {
|
|
auto* ready = runtime->state_by_index(view[State_Ready]);
|
|
auto* render = runtime->state_by_index(view[State_Render]);
|
|
return ready && render && buffer_version_newer(ready->version, render->version);
|
|
});
|
|
runtime->input_control.try_swap_role(Input_Edit, Input_Ready, [this](const Triple_Buffer_View& view) {
|
|
const Input_Buffer_Slot& edit = runtime->input_slot_by_index(view[Input_Edit]);
|
|
const Input_Buffer_Slot& ready = runtime->input_slot_by_index(view[Input_Ready]);
|
|
return edit.pending && buffer_version_newer(edit.version, ready.version);
|
|
});
|
|
runtime->input_control.try_swap_role(Input_Ready, Input_Render, [this](const Triple_Buffer_View& view) {
|
|
const Input_Buffer_Slot& ready = runtime->input_slot_by_index(view[Input_Ready]);
|
|
const Input_Buffer_Slot& render = runtime->input_slot_by_index(view[Input_Render]);
|
|
return ready.pending && buffer_version_newer(ready.version, render.version);
|
|
});
|
|
}
|
|
|
|
Render_State* Strategy_Render_Data::state(Renderable_State_Role role) {
|
|
return runtime->runtime_strategy_value == Renderable_Runtime_Strategy::Explicit
|
|
? runtime->explicit_state
|
|
: runtime->state(state_role_index(role));
|
|
}
|
|
|
|
Input_Data* Strategy_Render_Data::input_data(Renderable_Input_Role role) {
|
|
return runtime->runtime_strategy_value == Renderable_Runtime_Strategy::Explicit
|
|
? runtime->explicit_input.data
|
|
: runtime->input_data(input_role_index(role));
|
|
}
|
|
|
|
void Strategy_Render_Data::clear_render_input() {
|
|
runtime->clear_input_role(Renderable_Input_Role::Render);
|
|
}
|
|
|
|
} // namespace renderive
|