diff options
Diffstat (limited to 'src/osd/modules/render/bgfx/chainmanager.cpp')
-rw-r--r-- | src/osd/modules/render/bgfx/chainmanager.cpp | 647 |
1 files changed, 501 insertions, 146 deletions
diff --git a/src/osd/modules/render/bgfx/chainmanager.cpp b/src/osd/modules/render/bgfx/chainmanager.cpp index 62df9be9613..a15f2f1e584 100644 --- a/src/osd/modules/render/bgfx/chainmanager.cpp +++ b/src/osd/modules/render/bgfx/chainmanager.cpp @@ -9,13 +9,16 @@ // //============================================================ +#include "chainmanager.h" + #include <bx/readerwriter.h> #include <bx/file.h> -#include "emu.h" +#include "emucore.h" +#include "render.h" #include "../frontend/mame/ui/slider.h" -#include "osdcore.h" +#include "modules/lib/osdobj_common.h" #include "modules/osdwindow.h" #include <rapidjson/document.h> @@ -23,32 +26,67 @@ #include "bgfxutil.h" -#include "chainmanager.h" -#include "chainreader.h" #include "chain.h" - -#include "texture.h" -#include "target.h" +#include "chainreader.h" #include "slider.h" +#include "target.h" +#include "texture.h" #include "sliderdirtynotifier.h" +#include "util/path.h" +#include "util/unicode.h" +#include "util/xmlfile.h" + +#include "osdcore.h" +#include "osdfile.h" + +#include <algorithm> +#include <locale> + + using namespace rapidjson; -const uint32_t chain_manager::CHAIN_NONE = 0; +chain_manager::screen_prim::screen_prim(render_primitive *prim) +{ + m_prim = prim; + m_screen_width = uint16_t(floorf(prim->get_full_quad_width() + 0.5f)); + m_screen_height = uint16_t(floorf(prim->get_full_quad_height() + 0.5f)); + m_quad_width = uint16_t(floorf(prim->get_quad_width() + 0.5f)); + m_quad_height = uint16_t(floorf(prim->get_quad_height() + 0.5f)); + m_tex_width = prim->texture.width; + m_tex_height = prim->texture.height; + m_rowpixels = prim->texture.rowpixels; + m_palette_length = prim->texture.palette_length; + m_flags = prim->flags; +} -chain_manager::chain_manager(running_machine& machine, osd_options& options, texture_manager& textures, target_manager& targets, effect_manager& effects, uint32_t window_index, slider_dirty_notifier& slider_notifier) +chain_manager::chain_manager( + running_machine& machine, + const osd_options& options, + texture_manager& textures, + target_manager& targets, + effect_manager& effects, + uint32_t window_index, + slider_dirty_notifier& slider_notifier, + uint16_t user_prescale, + uint16_t max_prescale_size) : m_machine(machine) , m_options(options) , m_textures(textures) , m_targets(targets) , m_effects(effects) , m_window_index(window_index) + , m_user_prescale(user_prescale) + , m_max_prescale_size(max_prescale_size) , m_slider_notifier(slider_notifier) , m_screen_count(0) + , m_default_chain_index(-1) { + m_converters.clear(); refresh_available_chains(); parse_chain_selections(options.bgfx_screen_chains()); + init_texture_converters(); } chain_manager::~chain_manager() @@ -56,14 +94,65 @@ chain_manager::~chain_manager() destroy_chains(); } +void chain_manager::init_texture_converters() +{ + m_converters.push_back(nullptr); + m_converters.push_back(m_effects.get_or_load_effect(m_options, "misc/texconv_palette16")); + m_converters.push_back(m_effects.get_or_load_effect(m_options, "misc/texconv_rgb32")); + m_converters.push_back(nullptr); + m_converters.push_back(m_effects.get_or_load_effect(m_options, "misc/texconv_yuy16")); + m_adjuster = m_effects.get_or_load_effect(m_options, "misc/bcg_adjust"); +} + +void chain_manager::get_default_chain_info(std::string &out_chain_name, int32_t &out_chain_index) +{ + if (m_default_chain_index == -1) + { + out_chain_index = CHAIN_NONE; + out_chain_name = ""; + return; + } + + out_chain_index = m_default_chain_index; + out_chain_name = "default"; + return; +} + void chain_manager::refresh_available_chains() { m_available_chains.clear(); - m_available_chains.push_back(chain_desc("none", "")); - - std::string chains_path; - osd_subst_env(chains_path, util::string_format("%s" PATH_SEPARATOR "chains", m_options.bgfx_path())); - find_available_chains(chains_path, ""); + m_available_chains.emplace_back("none", ""); + + find_available_chains(util::path_concat(m_options.bgfx_path(), "chains"), ""); + std::collate<wchar_t> const &coll = std::use_facet<std::collate<wchar_t> >(std::locale()); + std::sort( + m_available_chains.begin(), + m_available_chains.end(), + [&coll] (chain_desc const &x, chain_desc const &y) -> bool + { + if (x.m_name == "none") + return y.m_name != "none"; + else if (y.m_name == "none") + return false; + else if (x.m_name == "default") + return y.m_name != "default"; + else if (y.m_name == "default") + return false; + std::wstring const xstr = wstring_from_utf8(x.m_name); + std::wstring const ystr = wstring_from_utf8(y.m_name); + return coll.compare(xstr.data(), xstr.data() + xstr.size(), ystr.data(), ystr.data() + ystr.size()) < 0; + }); + + if (m_default_chain_index == -1) + { + for (size_t i = 0; i < m_available_chains.size(); i++) + { + if (m_available_chains[i].m_name == "default") + { + m_default_chain_index = int32_t(i); + } + } + } destroy_unloaded_chains(); } @@ -73,7 +162,7 @@ void chain_manager::destroy_unloaded_chains() // O(shaders*available_chains), but we don't care because asset reloading happens rarely for (int i = 0; i < m_chain_names.size(); i++) { - std::string name = m_chain_names[i]; + const std::string &name = m_chain_names[i]; if (name.length() > 0) { for (chain_desc desc : m_available_chains) @@ -82,8 +171,7 @@ void chain_manager::destroy_unloaded_chains() { delete m_screen_chains[i]; m_screen_chains[i] = nullptr; - m_chain_names[i] = ""; - m_current_chain[i] = CHAIN_NONE; + get_default_chain_info(m_chain_names[i], m_current_chain[i]); break; } } @@ -91,107 +179,109 @@ void chain_manager::destroy_unloaded_chains() } } -void chain_manager::find_available_chains(std::string root, std::string path) +void chain_manager::find_available_chains(std::string_view root, std::string_view path) { - osd::directory::ptr directory = osd::directory::open(root + path); - if (directory != nullptr) + osd::directory::ptr directory = osd::directory::open(path.empty() ? std::string(root) : util::path_concat(root, path)); + if (directory) { - for (const osd::directory::entry *entry = directory->read(); entry != nullptr; entry = directory->read()) + for (const osd::directory::entry *entry = directory->read(); entry; entry = directory->read()) { if (entry->type == osd::directory::entry::entry_type::FILE) { - std::string name(entry->name); - std::string extension(".json"); + const std::string_view name(entry->name); + const std::string_view extension(".json"); // Does the name has at least one character in addition to ".json"? if (name.length() > extension.length()) { size_t start = name.length() - extension.length(); - std::string test_segment = name.substr(start, extension.length()); + const std::string_view test_segment = name.substr(start, extension.length()); // Does it end in .json? if (test_segment == extension) { - m_available_chains.push_back(chain_desc(name.substr(0, start), path)); + m_available_chains.emplace_back(std::string(name.substr(0, start)), std::string(path)); } } } else if (entry->type == osd::directory::entry::entry_type::DIR) { - std::string name = entry->name; - if (!(name == "." || name == "..")) + const std::string_view name = entry->name; + if ((name != ".") && (name != "..")) { - std::string appended_path = path + "/" + name; - if (path.length() == 0) - { - appended_path = name; - } - find_available_chains(root, path + "/" + name); + if (path.empty()) + find_available_chains(root, name); + else + find_available_chains(root, util::path_concat(path, name)); } } } } } -bgfx_chain* chain_manager::load_chain(std::string name, uint32_t screen_index) +std::unique_ptr<bgfx_chain> chain_manager::load_chain(std::string name, uint32_t screen_index) { if (name.length() < 5 || (name.compare(name.length() - 5, 5, ".json") != 0)) { - name = name + ".json"; + name += ".json"; } - std::string path; - osd_subst_env(path, util::string_format("%s" PATH_SEPARATOR "chains" PATH_SEPARATOR, m_options.bgfx_path())); - path += name; + const std::string path = util::path_concat(m_options.bgfx_path(), "chains", name); bx::FileReader reader; if (!bx::open(&reader, path.c_str())) { - printf("Unable to open chain file %s, falling back to no post processing\n", path.c_str()); + osd_printf_warning("Unable to open chain file %s, falling back to no post processing\n", path); return nullptr; } - int32_t size(bx::getSize(&reader)); + const int32_t size(bx::getSize(&reader)); + + bx::ErrorAssert err; + std::unique_ptr<char []> data(new (std::nothrow) char [size + 1]); + if (!data) + { + osd_printf_error("Out of memory reading chain file %s\n", path); + bx::close(&reader); + return nullptr; + } - char* data = new char[size + 1]; - bx::read(&reader, reinterpret_cast<void*>(data), size); + bx::read(&reader, reinterpret_cast<void*>(data.get()), size, &err); bx::close(&reader); data[size] = 0; Document document; - document.Parse<kParseCommentsFlag>(data); - - delete [] data; + document.Parse<kParseCommentsFlag>(data.get()); + data.reset(); if (document.HasParseError()) { std::string error(GetParseError_En(document.GetParseError())); - printf("Unable to parse chain %s. Errors returned:\n", path.c_str()); - printf("%s\n", error.c_str()); + osd_printf_warning("Unable to parse chain %s. Errors returned:\n%s\n", path, error); return nullptr; } - bgfx_chain* chain = chain_reader::read_from_value(document, name + ": ", *this, screen_index); + std::unique_ptr<bgfx_chain> chain = chain_reader::read_from_value(document, name + ": ", *this, screen_index, m_user_prescale, m_max_prescale_size); - if (chain == nullptr) + if (!chain) { - printf("Unable to load chain %s, falling back to no post processing\n", path.c_str()); + osd_printf_warning("Unable to load chain %s, falling back to no post processing\n", path); return nullptr; } return chain; } -void chain_manager::parse_chain_selections(std::string chain_str) +void chain_manager::parse_chain_selections(std::string_view chain_str) { - std::vector<std::string> chain_names = split_option_string(chain_str); + std::vector<std::string_view> chain_names = split_option_string(chain_str); if (chain_names.empty()) chain_names.push_back("default"); - while (m_current_chain.size() != chain_names.size()) + while (m_current_chain.size() < chain_names.size()) { - m_screen_chains.push_back(nullptr); - m_chain_names.push_back(""); + m_screen_chains.emplace_back(nullptr); + m_chain_names.emplace_back(); m_current_chain.push_back(CHAIN_NONE); } @@ -201,9 +291,7 @@ void chain_manager::parse_chain_selections(std::string chain_str) for (chain_index = 0; chain_index < m_available_chains.size(); chain_index++) { if (m_available_chains[chain_index].m_name == chain_names[index]) - { break; - } } if (chain_index < m_available_chains.size()) @@ -219,24 +307,35 @@ void chain_manager::parse_chain_selections(std::string chain_str) } } -std::vector<std::string> chain_manager::split_option_string(std::string chain_str) const +std::vector<std::string_view> chain_manager::split_option_string(std::string_view chain_str) const { - std::vector<std::string> chain_names; + std::vector<std::string_view> chain_names; - uint32_t length = chain_str.length(); + const uint32_t length = chain_str.length(); uint32_t win = 0; uint32_t last_start = 0; - for (uint32_t i = 0; i < length + 1; i++) + for (uint32_t i = 0; i <= length; i++) { - if (i == length || chain_str[i] == ',' || chain_str[i] == ':') + if (i == length || (chain_str[i] == ',') || (chain_str[i] == ':')) { - if (win == m_window_index) + if ((win == 0) || (win == m_window_index)) { - chain_names.push_back(chain_str.substr(last_start, i - last_start)); + // treat an empty string as equivalent to "default" + if (i > last_start) + chain_names.push_back(chain_str.substr(last_start, i - last_start)); + else + chain_names.push_back("default"); } + last_start = i + 1; - if (chain_str[i] == ':') + if ((i < length) && (chain_str[i] == ':')) { + // no point walking the rest of the string if this was our window + if (win == m_window_index) + break; + + // don't use first for all if more than one window is specified + chain_names.clear(); win++; } } @@ -253,7 +352,7 @@ void chain_manager::load_chains() { chain_desc& desc = m_available_chains[m_current_chain[chain]]; m_chain_names[chain] = desc.m_name; - m_screen_chains[chain] = load_chain(desc.m_path + "/" + desc.m_name, uint32_t(chain)); + m_screen_chains[chain] = load_chain(util::path_concat(desc.m_path, desc.m_name), uint32_t(chain)).release(); } } } @@ -288,19 +387,9 @@ bgfx_chain* chain_manager::screen_chain(uint32_t screen) } } -void chain_manager::process_screen_quad(uint32_t view, uint32_t screen, render_primitive* prim, osd_window &window) +void chain_manager::process_screen_quad(uint32_t view, uint32_t screen, screen_prim &prim, osd_window& window) { - uint16_t tex_width(prim->texture.width); - uint16_t tex_height(prim->texture.height); - - const bgfx::Memory* mem = bgfx_util::mame_texture_data_to_bgfx_texture_data(prim->flags & PRIMFLAG_TEXFORMAT_MASK, - tex_width, tex_height, prim->texture.rowpixels, prim->texture.palette, prim->texture.base); - - std::string full_name = "screen" + std::to_string(screen); - bgfx_texture *texture = new bgfx_texture(full_name, bgfx::TextureFormat::RGBA8, tex_width, tex_height, mem, BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP | BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_MIP_POINT); - m_textures.add_provider(full_name, texture); - - const bool any_targets_rebuilt = m_targets.update_target_sizes(screen, tex_width, tex_height, TARGET_STYLE_GUEST); + const bool any_targets_rebuilt = m_targets.update_target_sizes(screen, prim.m_tex_width, prim.m_tex_height, TARGET_STYLE_GUEST, m_user_prescale, m_max_prescale_size); if (any_targets_rebuilt) { for (bgfx_chain* chain : m_screen_chains) @@ -313,24 +402,26 @@ void chain_manager::process_screen_quad(uint32_t view, uint32_t screen, render_p } bgfx_chain* chain = screen_chain(screen); - chain->process(prim, view, screen, m_textures, window, bgfx_util::get_blend_state(PRIMFLAG_GET_BLENDMODE(prim->flags))); + chain->process(prim, view, screen, m_textures, window); view += chain->applicable_passes(); - - m_textures.add_provider(full_name, nullptr); - delete texture; } -std::vector<render_primitive*> chain_manager::count_screens(render_primitive* prim) +uint32_t chain_manager::count_screens(render_primitive* prim) { - std::vector<render_primitive*> screens; - - int screen_count = 0; + uint32_t screen_count = 0; while (prim != nullptr) { if (PRIMFLAG_GET_SCREENTEX(prim->flags)) { + if (screen_count < m_screen_prims.size()) + { + m_screen_prims[screen_count] = prim; + } + else + { + m_screen_prims.push_back(prim); + } screen_count++; - screens.push_back(prim); } prim = prim->next(); } @@ -338,10 +429,15 @@ std::vector<render_primitive*> chain_manager::count_screens(render_primitive* pr if (screen_count > 0) { update_screen_count(screen_count); - m_targets.update_screen_count(screen_count); + m_targets.update_screen_count(screen_count, m_user_prescale, m_max_prescale_size); } - return screens; + if (screen_count < m_screen_prims.size()) + { + m_screen_prims.resize(screen_count); + } + + return screen_count; } void chain_manager::update_screen_count(uint32_t screen_count) @@ -355,8 +451,12 @@ void chain_manager::update_screen_count(uint32_t screen_count) while (m_screen_chains.size() < m_screen_count) { m_screen_chains.push_back(nullptr); - m_chain_names.push_back(""); - m_current_chain.push_back(CHAIN_NONE); + + int32_t chain_index = CHAIN_NONE; + std::string chain_name; + get_default_chain_info(chain_name, chain_index); + m_chain_names.emplace_back(std::move(chain_name)); + m_current_chain.push_back(chain_index); } // Ensure we have a screen chain selection slider per screen @@ -369,11 +469,20 @@ void chain_manager::update_screen_count(uint32_t screen_count) } } -int32_t chain_manager::slider_changed(running_machine &machine, void *arg, int id, std::string *str, int32_t newval) +void chain_manager::set_current_chain(uint32_t screen, int32_t chain_index) +{ + if (chain_index < m_available_chains.size() && screen < m_current_chain.size() && screen < m_chain_names.size()) + { + m_current_chain[screen] = chain_index; + m_chain_names[screen] = m_available_chains[chain_index].m_name; + } +} + +int32_t chain_manager::slider_changed(int id, std::string *str, int32_t newval) { if (newval != SLIDER_NOCHANGE) { - m_current_chain[id] = newval; + set_current_chain(id, newval); std::vector<std::vector<float>> settings = slider_settings(); reload_chains(); @@ -384,7 +493,7 @@ int32_t chain_manager::slider_changed(running_machine &machine, void *arg, int i if (str != nullptr) { - *str = string_format("%s", m_available_chains[m_current_chain[id]].m_name.c_str()); + *str = m_available_chains[m_current_chain[id]].m_name; } return m_current_chain[id]; @@ -397,42 +506,151 @@ void chain_manager::create_selection_slider(uint32_t screen_index) return; } - std::unique_ptr<slider_state> state = make_unique_clear<slider_state>(); - - state->minval = 0; - state->defval = m_current_chain[screen_index]; - state->maxval = m_available_chains.size() - 1; - state->incval = 1; + int32_t minval = 0; + int32_t defval = m_current_chain[screen_index]; + int32_t maxval = m_available_chains.size() - 1; + int32_t incval = 1; using namespace std::placeholders; - state->update = std::bind(&chain_manager::slider_changed, this, _1, _2, _3, _4, _5); - state->arg = this; - state->id = screen_index; - state->description = "Window " + std::to_string(m_window_index) + ", Screen " + std::to_string(screen_index) + " Effect:"; - - ui::menu_item item; - item.text = state->description; - item.subtext = ""; - item.flags = 0; - item.ref = state.get(); - item.type = ui::menu_item_type::SLIDER; - m_selection_sliders.push_back(item); - m_core_sliders.push_back(std::move(state)); + auto state = std::make_unique<slider_state>( + util::string_format("Window %1$u, Screen %2$u Effect", m_window_index, screen_index), + minval, defval, maxval, incval, + std::bind(&chain_manager::slider_changed, this, screen_index, _1, _2)); + + ui::menu_item item(ui::menu_item_type::SLIDER, state.get()); + item.set_text(state->description); + m_selection_sliders.emplace_back(item); + m_core_sliders.emplace_back(std::move(state)); } -uint32_t chain_manager::handle_screen_chains(uint32_t view, render_primitive *starting_prim, osd_window& window) +uint32_t chain_manager::update_screen_textures(uint32_t view, render_primitive *starting_prim, osd_window& window) { - std::vector<render_primitive*> screens = count_screens(starting_prim); + if (!count_screens(starting_prim)) + return 0; - if (screens.size() == 0) + for (int screen = 0; screen < m_screen_prims.size(); screen++) { - return 0; + screen_prim &prim = m_screen_prims[screen]; + uint16_t tex_width(prim.m_tex_width); + uint16_t tex_height(prim.m_tex_height); + + bgfx_texture* texture = screen < m_screen_textures.size() ? m_screen_textures[screen] : nullptr; + bgfx_texture* palette = screen < m_screen_palettes.size() ? m_screen_palettes[screen] : nullptr; + + const uint32_t src_format = (prim.m_flags & PRIMFLAG_TEXFORMAT_MASK) >> PRIMFLAG_TEXFORMAT_SHIFT; + const bool needs_conversion = m_converters[src_format] != nullptr; + const bool needs_adjust = prim.m_prim->texture.palette != nullptr && src_format != TEXFORMAT_PALETTE16; + const std::string screen_index = std::to_string(screen); + const std::string source_name = "source" + screen_index; + const std::string screen_name = "screen" + screen_index; + const std::string palette_name = "palette" + screen_index; + const std::string &full_name = (needs_conversion || needs_adjust) ? source_name : screen_name; + if (texture && (texture->width() != tex_width || texture->height() != tex_height)) + { + m_textures.remove_provider(full_name); + m_textures.remove_provider(palette_name); + texture = nullptr; + palette = nullptr; + } + + bgfx::TextureFormat::Enum dst_format = bgfx::TextureFormat::BGRA8; + uint16_t pitch = prim.m_rowpixels; + int width_div_factor = 1; + int width_mul_factor = 1; + const bgfx::Memory* mem = bgfx_util::mame_texture_data_to_bgfx_texture_data(dst_format, prim.m_flags & PRIMFLAG_TEXFORMAT_MASK, + prim.m_rowpixels, prim.m_prim->texture.width_margin, tex_height, prim.m_prim->texture.palette, prim.m_prim->texture.base, pitch, width_div_factor, width_mul_factor); + + if (!texture) + { + uint32_t flags = BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_MIP_POINT; + if (!PRIMFLAG_GET_TEXWRAP(prim.m_flags)) + flags |= BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP; + auto newtex = std::make_unique<bgfx_texture>(full_name, dst_format, tex_width, prim.m_prim->texture.width_margin, tex_height, mem, flags, pitch, prim.m_rowpixels, width_div_factor, width_mul_factor); + texture = newtex.get(); + m_textures.add_provider(full_name, std::move(newtex)); + + if (prim.m_prim->texture.palette) + { + uint16_t palette_width = uint16_t(std::min(prim.m_palette_length, 256U)); + uint16_t palette_height = uint16_t(std::max((prim.m_palette_length + 255) / 256, 1U)); + m_palette_temp.resize(palette_width * palette_height * 4); + memcpy(&m_palette_temp[0], prim.m_prim->texture.palette, prim.m_palette_length * 4); + const bgfx::Memory *palmem = bgfx::copy(&m_palette_temp[0], palette_width * palette_height * 4); + auto newpal = std::make_unique<bgfx_texture>(palette_name, bgfx::TextureFormat::BGRA8, palette_width, 0, palette_height, palmem, BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP | BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_MIP_POINT, palette_width * 4); + palette = newpal.get(); + m_textures.add_provider(palette_name, std::move(newpal)); + } + + while (screen >= m_screen_textures.size()) + { + m_screen_textures.emplace_back(nullptr); + } + m_screen_textures[screen] = texture; + + while (screen >= m_screen_palettes.size()) + { + m_screen_palettes.emplace_back(nullptr); + } + if (palette) + { + m_screen_palettes[screen] = palette; + } + } + else + { + texture->update(mem, pitch, prim.m_prim->texture.width_margin); + + if (prim.m_prim->texture.palette) + { + uint16_t palette_width = uint16_t(std::min(prim.m_palette_length, 256U)); + uint16_t palette_height = uint16_t(std::max((prim.m_palette_length + 255) / 256, 1U)); + const uint32_t palette_size = palette_width * palette_height * 4; + m_palette_temp.resize(palette_size); + memcpy(&m_palette_temp[0], prim.m_prim->texture.palette, prim.m_palette_length * 4); + const bgfx::Memory *palmem = bgfx::copy(&m_palette_temp[0], palette_size); + + if (palette) + { + palette->update(palmem); + } + else + { + auto newpal = std::make_unique<bgfx_texture>(palette_name, bgfx::TextureFormat::BGRA8, palette_width, 0, palette_height, palmem, BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP | BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_MIP_POINT, palette_width * 4); + palette = newpal.get(); + m_textures.add_provider(palette_name, std::move(newpal)); + while (screen >= m_screen_palettes.size()) + { + m_screen_palettes.emplace_back(nullptr); + } + m_screen_palettes[screen] = palette; + } + } + } + + const bool has_tint = (prim.m_prim->color.a != 1.0f) || (prim.m_prim->color.r != 1.0f) || (prim.m_prim->color.g != 1.0f) || (prim.m_prim->color.b != 1.0f); + bgfx_chain* chain = screen_chain(screen); + if (chain && needs_adjust && !chain->has_adjuster()) + { + const bool apply_tint = !needs_conversion && has_tint; + chain->insert_effect(chain->has_converter() ? 1 : 0, m_adjuster, apply_tint, "XXadjust", needs_conversion ? "screen" : "source", *this); + chain->set_has_adjuster(true); + } + if (chain && needs_conversion && !chain->has_converter()) + { + chain->insert_effect(0, m_converters[src_format], has_tint, "XXconvert", "source", *this); + chain->set_has_converter(true); + } } + return m_screen_prims.size(); +} + +uint32_t chain_manager::process_screen_chains(uint32_t view, osd_window& window) +{ // Process each screen as necessary uint32_t used_views = 0; uint32_t screen_index = 0; - for (render_primitive* prim : screens) + for (screen_prim &prim : m_screen_prims) { if (m_current_chain[screen_index] == CHAIN_NONE || screen_chain(screen_index) == nullptr) { @@ -440,14 +658,14 @@ uint32_t chain_manager::handle_screen_chains(uint32_t view, render_primitive *st continue; } - uint16_t screen_width(floorf(prim->get_full_quad_width() + 0.5f)); - uint16_t screen_height(floorf(prim->get_full_quad_height() + 0.5f)); + uint16_t screen_width = prim.m_screen_width; + uint16_t screen_height = prim.m_screen_height; if (window.swap_xy()) { std::swap(screen_width, screen_height); } - const bool any_targets_rebuilt = m_targets.update_target_sizes(screen_index, screen_width, screen_height, TARGET_STYLE_NATIVE); + const bool any_targets_rebuilt = m_targets.update_target_sizes(screen_index, screen_width, screen_height, TARGET_STYLE_NATIVE, m_user_prescale, m_max_prescale_size); if (any_targets_rebuilt) { for (bgfx_chain* chain : m_screen_chains) @@ -472,12 +690,12 @@ uint32_t chain_manager::handle_screen_chains(uint32_t view, render_primitive *st bool chain_manager::has_applicable_chain(uint32_t screen) { - return screen < m_screen_count && m_current_chain[screen] != CHAIN_NONE && m_screen_chains[screen] != nullptr; + return (screen < m_screen_count) && (m_current_chain[screen] != CHAIN_NONE) && m_screen_chains[screen]; } bool chain_manager::needs_sliders() { - return m_screen_count > 0 && m_available_chains.size() > 1; + return (m_screen_count > 0) && (m_available_chains.size() > 1); } void chain_manager::restore_slider_settings(int32_t id, std::vector<std::vector<float>>& settings) @@ -500,7 +718,7 @@ void chain_manager::restore_slider_settings(int32_t id, std::vector<std::vector< continue; } - std::vector<bgfx_slider*> chain_sliders = chain->sliders(); + const std::vector<bgfx_slider*> &chain_sliders = chain->sliders(); for (size_t slider = 0; slider < chain_sliders.size(); slider++) { chain_sliders[slider]->import(settings[index][slider]); @@ -508,6 +726,151 @@ void chain_manager::restore_slider_settings(int32_t id, std::vector<std::vector< } } +void chain_manager::load_config(util::xml::data_node const &windownode) +{ + // treat source INI files or more specific as higher priority than CFG + // FIXME: leaky abstraction - this depends on a front-end implementation detail + bool const persist = windownode.get_attribute_int("persist", 1) != 0; + bool const default_chains = (OPTION_PRIORITY_NORMAL + 5) > m_options.get_entry(OSDOPTION_BGFX_SCREEN_CHAINS)->priority(); + bool const explicit_chains = !persist && !default_chains && *m_options.bgfx_screen_chains(); + + // if chains weren't explicitly specified, restore the chains from the config file + if (explicit_chains) + { + osd_printf_verbose( + "BGFX: Ignoring chain selection from window 0 configuration due to explicitly specified chains\n", + m_window_index); + } + else + { + bool changed = false; + util::xml::data_node const *screennode = windownode.get_child("screen"); + while (screennode) + { + auto const index = screennode->get_attribute_int("index", -1); + if ((0 <= index) && (m_screen_count > index)) + { + char const *const chainname = screennode->get_attribute_string("chain", nullptr); + if (chainname) + { + auto const found = std::find_if( + m_available_chains.begin(), + m_available_chains.end(), + [&chainname] (auto const &avail) { return avail.m_name == chainname; }); + if (m_available_chains.end() != found) + { + auto const chainnum = found - m_available_chains.begin(); + if (chainnum != m_current_chain[index]) + { + m_current_chain[index] = chainnum; + changed = true; + } + } + } + } + + screennode = screennode->get_next_sibling("screen"); + } + + if (changed) + reload_chains(); + } + + // now apply slider settings for screens with chains matching config + util::xml::data_node const *screennode = windownode.get_child("screen"); + while (screennode) + { + auto const index = screennode->get_attribute_int("index", -1); + if ((0 <= index) && (m_screen_count > index) && (m_screen_chains.size() > index)) + { + bgfx_chain *const chain = m_screen_chains[index]; + char const *const chainname = screennode->get_attribute_string("chain", nullptr); + if (chain && chainname && (m_available_chains[m_current_chain[index]].m_name == chainname)) + { + auto const &sliders = chain->sliders(); + + util::xml::data_node const *slidernode = screennode->get_child("slider"); + while (slidernode) + { + char const *const slidername = slidernode->get_attribute_string("name", nullptr); + if (slidername) + { + auto const found = std::find_if( + sliders.begin(), + sliders.end(), + [&slidername] (auto const &slider) { return slider->name() == slidername; }); + if (sliders.end() != found) + { + bgfx_slider &slider = **found; + switch (slider.type()) + { + case bgfx_slider::SLIDER_INT_ENUM: + case bgfx_slider::SLIDER_INT: + { + slider_state const &core = *slider.core_slider(); + int32_t const val = slidernode->get_attribute_int("value", core.defval); + slider.update(nullptr, std::clamp(val, core.minval, core.maxval)); + } + break; + default: + { + float const val = slidernode->get_attribute_float("value", slider.default_value()); + slider.import(std::clamp(val, slider.min_value(), slider.max_value())); + } + } + } + } + + slidernode = slidernode->get_next_sibling("slider"); + } + } + } + screennode = screennode->get_next_sibling("screen"); + } +} + +void chain_manager::save_config(util::xml::data_node &parentnode) +{ + if (!needs_sliders()) + return; + + util::xml::data_node *const windownode = parentnode.add_child("window", nullptr); + windownode->set_attribute_int("index", m_window_index); + + for (size_t index = 0; index < m_screen_chains.size() && index < m_screen_count; index++) + { + bgfx_chain *const chain = m_screen_chains[index]; + if (!chain) + continue; + + util::xml::data_node *const screennode = windownode->add_child("screen", nullptr); + screennode->set_attribute_int("index", index); + screennode->set_attribute("chain", m_available_chains[m_current_chain[index]].m_name.c_str()); + + for (bgfx_slider *slider : chain->sliders()) + { + auto const val = slider->update(nullptr, SLIDER_NOCHANGE); + if (val == slider->core_slider()->defval) + continue; + + util::xml::data_node *const slidernode = screennode->add_child("slider", nullptr); + slidernode->set_attribute("name", slider->name().c_str()); + switch (slider->type()) + { + case bgfx_slider::SLIDER_INT_ENUM: + case bgfx_slider::SLIDER_INT: + slidernode->set_attribute_int("value", val); + break; + default: + slidernode->set_attribute_float("value", slider->value()); + } + } + } + + if (!windownode->get_first_child()) + windownode->delete_node(); +} + std::vector<std::vector<float>> chain_manager::slider_settings() { std::vector<std::vector<float>> curr; @@ -527,7 +890,7 @@ std::vector<std::vector<float>> chain_manager::slider_settings() continue; } - std::vector<bgfx_slider*> chain_sliders = chain->sliders(); + const std::vector<bgfx_slider*> &chain_sliders = chain->sliders(); for (bgfx_slider* slider : chain_sliders) { curr[index].push_back(slider->value()); @@ -556,46 +919,38 @@ std::vector<ui::menu_item> chain_manager::get_slider_list() continue; } - std::vector<bgfx_chain_entry*> chain_entries = chain->entries(); + const std::vector<bgfx_chain_entry*> &chain_entries = chain->entries(); for (bgfx_chain_entry* entry : chain_entries) { - std::vector<bgfx_input_pair*> entry_inputs = entry->inputs(); + const std::vector<bgfx_input_pair*> &entry_inputs = entry->inputs(); for (bgfx_input_pair* input : entry_inputs) { std::vector<ui::menu_item> input_sliders = input->get_slider_list(); - for (ui::menu_item slider : input_sliders) + for (ui::menu_item &slider : input_sliders) { - sliders.push_back(slider); + sliders.emplace_back(slider); } } } - std::vector<bgfx_slider*> chain_sliders = chain->sliders(); + const std::vector<bgfx_slider*> &chain_sliders = chain->sliders(); for (bgfx_slider* slider : chain_sliders) { - slider_state* core_slider = slider->core_slider(); + slider_state *const core_slider = slider->core_slider(); - ui::menu_item item; - item.text = core_slider->description; - item.subtext = ""; - item.flags = 0; - item.ref = core_slider; - item.type = ui::menu_item_type::SLIDER; - m_selection_sliders.push_back(item); + ui::menu_item item(ui::menu_item_type::SLIDER, core_slider); + item.set_text(core_slider->description); + m_selection_sliders.emplace_back(item); - sliders.push_back(item); + sliders.emplace_back(std::move(item)); } if (chain_sliders.size() > 0) { - ui::menu_item item; - item.text = MENU_SEPARATOR_ITEM; - item.subtext = ""; - item.flags = 0; - item.ref = nullptr; - item.type = ui::menu_item_type::SEPARATOR; + ui::menu_item item(ui::menu_item_type::SEPARATOR); + item.set_text(MENU_SEPARATOR_ITEM); - sliders.push_back(item); + sliders.emplace_back(std::move(item)); } } |