From 7880de4d3252e1b6cae07363d8d5f0f8d8a8c2cb Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Sun, 17 Nov 2019 04:01:22 +1100 Subject: UI cleanup: * Make input mapping menus more efficient - most of the properties of a field won't change * Get rid of the pool allocator in base menu class - it was encouraging bad design --- src/frontend/mame/ui/inputmap.cpp | 261 +++++++++++++++++++------------------- src/frontend/mame/ui/inputmap.h | 31 +++-- src/frontend/mame/ui/menu.cpp | 53 +------- src/frontend/mame/ui/menu.h | 12 -- 4 files changed, 146 insertions(+), 211 deletions(-) (limited to 'src/frontend') diff --git a/src/frontend/mame/ui/inputmap.cpp b/src/frontend/mame/ui/inputmap.cpp index 182a2201d83..6d7c1b138a1 100644 --- a/src/frontend/mame/ui/inputmap.cpp +++ b/src/frontend/mame/ui/inputmap.cpp @@ -66,63 +66,57 @@ void menu_input_groups::handle() input menu -------------------------------------------------*/ -menu_input_general::menu_input_general(mame_ui_manager &mui, render_container &container, int _group) : menu_input(mui, container) +menu_input_general::menu_input_general(mame_ui_manager &mui, render_container &container, int _group) + : menu_input(mui, container) + , group(_group) { - group = _group; } void menu_input_general::populate(float &customtop, float &custombottom) { - input_item_data *itemlist = nullptr; - - /* iterate over the input ports and add menu items */ - for (input_type_entry &entry : machine().ioport().types()) + if (data.empty()) + { + assert(!pollingitem); - /* add if we match the group and we have a valid name */ - if (entry.group() == group && entry.name() != nullptr && entry.name()[0] != 0) + // iterate over the input ports and add menu items + for (input_type_entry &entry : machine().ioport().types()) { - input_seq_type seqtype; - - /* loop over all sequence types */ - for (seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; ++seqtype) + // add if we match the group and we have a valid name + if ((entry.group() == group) && entry.name() && entry.name()[0]) { - /* build an entry for the standard sequence */ - input_item_data *item = (input_item_data *)m_pool_alloc(sizeof(*item)); - memset(item, 0, sizeof(*item)); - item->ref = &entry; - if(pollingitem && pollingref == &entry && pollingseq == seqtype) - pollingitem = item; - item->seqtype = seqtype; - item->seq = machine().ioport().type_seq(entry.type(), entry.player(), seqtype); - item->defseq = &entry.defseq(seqtype); - item->group = entry.group(); - item->type = ioport_manager::type_is_analog(entry.type()) ? (INPUT_TYPE_ANALOG + seqtype) : INPUT_TYPE_DIGITAL; - item->is_optional = false; - item->name = entry.name(); - item->owner_name = nullptr; - item->next = itemlist; - itemlist = item; - - /* stop after one, unless we're analog */ - if (item->type == INPUT_TYPE_DIGITAL) - break; + // loop over all sequence types + for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; ++seqtype) + { + // build an entry for the standard sequence + input_item_data &item(*data.emplace(data.end())); + item.ref = &entry; + item.seqtype = seqtype; + item.seq = machine().ioport().type_seq(entry.type(), entry.player(), seqtype); + item.defseq = &entry.defseq(seqtype); + item.group = entry.group(); + item.type = ioport_manager::type_is_analog(entry.type()) ? (INPUT_TYPE_ANALOG + seqtype) : INPUT_TYPE_DIGITAL; + item.is_optional = false; + item.name = entry.name(); + item.owner_name = nullptr; + + // stop after one, unless we're analog + if (item.type == INPUT_TYPE_DIGITAL) + break; + } } } - - - // first count the number of items - int numitems = 0; - for (input_item_data const *item = itemlist; item != nullptr; item = item->next) - numitems++; - - // now allocate an array of items and fill it up - std::vector itemarray(numitems); - int curitem = numitems; - for (input_item_data *item = itemlist; item != nullptr; item = item->next) - itemarray[--curitem] = item; + } + else + { + for (input_item_data &item : data) + { + const input_type_entry &entry(*reinterpret_cast(item.ref)); + item.seq = machine().ioport().type_seq(entry.type(), entry.player(), item.seqtype); + } + } // populate the menu in a standard fashion - populate_sorted(std::move(itemarray)); + populate_sorted(); } menu_input_general::~menu_input_general() @@ -140,90 +134,89 @@ menu_input_specific::menu_input_specific(mame_ui_manager &mui, render_container void menu_input_specific::populate(float &customtop, float &custombottom) { - input_item_data *itemlist = nullptr; - - /* iterate over the input ports and add menu items */ - for (auto &port : machine().ioport().ports()) + if (data.empty()) { - for (ioport_field &field : port.second->fields()) - { - ioport_type_class type_class = field.type_class(); + assert(!pollingitem); - /* add if we match the group and we have a valid name */ - if (field.enabled() && (type_class == INPUT_CLASS_CONTROLLER || type_class == INPUT_CLASS_MISC || type_class == INPUT_CLASS_KEYBOARD)) + // iterate over the input ports and add menu items + for (auto &port : machine().ioport().ports()) + { + for (ioport_field &field : port.second->fields()) { - /* loop over all sequence types */ - for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; ++seqtype) + const ioport_type_class type_class = field.type_class(); + + // add if it's enabled and it's a system-specific class + if (field.enabled() && (type_class == INPUT_CLASS_CONTROLLER || type_class == INPUT_CLASS_MISC || type_class == INPUT_CLASS_KEYBOARD)) { - /* build an entry for the standard sequence */ - input_item_data *item = (input_item_data *)m_pool_alloc(sizeof(*item)); - memset(item, 0, sizeof(*item)); - item->ref = &field; - item->seqtype = seqtype; - if(pollingitem && pollingref == item->ref && pollingseq == seqtype) - pollingitem = item; - item->seq = field.seq(seqtype); - item->defseq = &field.defseq(seqtype); - item->group = machine().ioport().type_group(field.type(), field.player()); - item->type = field.is_analog() ? (INPUT_TYPE_ANALOG + seqtype) : INPUT_TYPE_DIGITAL; - item->is_optional = field.optional(); - item->name = field.name(); - item->owner_name = field.device().tag(); - item->next = itemlist; - itemlist = item; - - /* stop after one, unless we're analog */ - if (item->type == INPUT_TYPE_DIGITAL) - break; + // loop over all sequence types + for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; ++seqtype) + { + // build an entry for the standard sequence + input_item_data &item(*data.emplace(data.end())); + item.ref = &field; + item.seqtype = seqtype; + item.seq = field.seq(seqtype); + item.defseq = &field.defseq(seqtype); + item.group = machine().ioport().type_group(field.type(), field.player()); + item.type = field.is_analog() ? (INPUT_TYPE_ANALOG + seqtype) : INPUT_TYPE_DIGITAL; + item.is_optional = field.optional(); + item.name = field.name(); + item.owner_name = field.device().tag(); + + // stop after one, unless we're analog + if (item.type == INPUT_TYPE_DIGITAL) + break; + } } } } - } - // first count the number of items - int numitems = 0; - for (input_item_data const *item = itemlist; item != nullptr; item = item->next) - numitems++; - - // now allocate an array of items and fill it up - std::vector itemarray(numitems); - int curitem = 0; - for (input_item_data *item = itemlist; item != nullptr; item = item->next) - itemarray[curitem++] = item; - - // sort it - std::sort(itemarray.begin(), itemarray.end(), [](const input_item_data *i1, const input_item_data *i2) { - int cmp = strcmp(i1->owner_name, i2->owner_name); - if (cmp < 0) - return true; - if (cmp > 0) - return false; - if (i1->group < i2->group) - return true; - if (i1->group > i2->group) - return false; - const ioport_field &field1 = *reinterpret_cast(i1->ref); - const ioport_field &field2 = *reinterpret_cast(i2->ref); - if (field1.type() < field2.type()) - return true; - if (field1.type() > field2.type()) - return false; - std::vector codes1 = field1.keyboard_codes(0); - std::vector codes2 = field2.keyboard_codes(0); - if (!codes1.empty() && (codes2.empty() || codes1[0] < codes2[0])) - return true; - if (!codes2.empty() && (codes1.empty() || codes1[0] > codes2[0])) - return false; - cmp = strcmp(i1->name, i2->name); - if (cmp < 0) - return true; - if (cmp > 0) - return false; - return i1->type < i2->type; - }); + // sort it + std::sort( + data.begin(), + data.end(), + [] (const input_item_data &i1, const input_item_data &i2) + { + int cmp = strcmp(i1.owner_name, i2.owner_name); + if (cmp < 0) + return true; + if (cmp > 0) + return false; + if (i1.group < i2.group) + return true; + if (i1.group > i2.group) + return false; + const ioport_field &field1 = *reinterpret_cast(i1.ref); + const ioport_field &field2 = *reinterpret_cast(i2.ref); + if (field1.type() < field2.type()) + return true; + if (field1.type() > field2.type()) + return false; + std::vector codes1 = field1.keyboard_codes(0); + std::vector codes2 = field2.keyboard_codes(0); + if (!codes1.empty() && (codes2.empty() || codes1[0] < codes2[0])) + return true; + if (!codes2.empty() && (codes1.empty() || codes1[0] > codes2[0])) + return false; + cmp = strcmp(i1.name, i2.name); + if (cmp < 0) + return true; + if (cmp > 0) + return false; + return i1.type < i2.type; + }); + } + else + { + for (input_item_data &item : data) + { + const ioport_field &field(*reinterpret_cast(item.ref)); + item.seq = field.seq(item.seqtype); + } + } // populate the menu in a standard fashion - populate_sorted(std::move(itemarray)); + populate_sorted(); } menu_input_specific::~menu_input_specific() @@ -367,43 +360,43 @@ void menu_input_specific::update_input(struct input_item_data *seqchangeditem) // menu from them //------------------------------------------------- -void menu_input::populate_sorted(std::vector &&itemarray) +void menu_input::populate_sorted() { const char *nameformat[INPUT_TYPE_TOTAL] = { nullptr }; std::string subtext; std::string prev_owner; bool first_entry = true; - /* create a mini lookup table for name format based on type */ + // create a mini lookup table for name format based on type nameformat[INPUT_TYPE_DIGITAL] = "%s"; nameformat[INPUT_TYPE_ANALOG] = "%s Analog"; nameformat[INPUT_TYPE_ANALOG_INC] = "%s Analog Inc"; nameformat[INPUT_TYPE_ANALOG_DEC] = "%s Analog Dec"; - /* build the menu */ - for (input_item_data *item : itemarray) + // build the menu + for (input_item_data &item : data) { uint32_t flags = 0; - /* generate the name of the item itself, based off the base name and the type */ - assert(nameformat[item->type] != nullptr); + // generate the name of the item itself, based off the base name and the type + assert(nameformat[item.type] != nullptr); - if (item->owner_name && strcmp(item->owner_name, prev_owner.c_str()) != 0) + if (item.owner_name && strcmp(item.owner_name, prev_owner.c_str()) != 0) { if (first_entry) first_entry = false; else item_append(menu_item_type::SEPARATOR); - item_append(string_format("[root%s]", item->owner_name), "", 0, nullptr); - prev_owner.assign(item->owner_name); + item_append(string_format("[root%s]", item.owner_name), "", 0, nullptr); + prev_owner.assign(item.owner_name); } - std::string text = string_format(nameformat[item->type], item->name); - if (item->is_optional) + std::string text = string_format(nameformat[item.type], item.name); + if (item.is_optional) text = "(" + text + ")"; /* if we're polling this item, use some spaces with left/right arrows */ - if (pollingref == item->ref && pollingseq == item->seqtype) + if (pollingref == item.ref && pollingseq == item.seqtype) { subtext.assign(" "); flags |= FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW; @@ -412,12 +405,12 @@ void menu_input::populate_sorted(std::vector &&itemarray) /* otherwise, generate the sequence name and invert it if different from the default */ else { - subtext = machine().input().seq_name(item->seq); - flags |= (item->seq != *item->defseq) ? FLAG_INVERT : 0; + subtext = machine().input().seq_name(item.seq); + flags |= (item.seq != *item.defseq) ? FLAG_INVERT : 0; } /* add the item */ - item_append(text, subtext, flags, item); + item_append(text, subtext, flags, &item); } } diff --git a/src/frontend/mame/ui/inputmap.h b/src/frontend/mame/ui/inputmap.h index bfb6dbcec17..d790ef73d40 100644 --- a/src/frontend/mame/ui/inputmap.h +++ b/src/frontend/mame/ui/inputmap.h @@ -14,6 +14,8 @@ #include "ui/menu.h" +#include + namespace ui { @@ -31,7 +33,6 @@ private: class menu_input : public menu { public: - menu_input(mame_ui_manager &mui, render_container &container); virtual ~menu_input() override; protected: @@ -43,24 +44,26 @@ protected: INPUT_TYPE_TOTAL = INPUT_TYPE_ANALOG + SEQ_TYPE_TOTAL }; - /* internal input menu item data */ + // internal input menu item data struct input_item_data { - input_item_data * next; /* pointer to next item in the list */ - const void * ref; /* reference to type description for global inputs or field for game inputs */ - input_seq_type seqtype; /* sequence type */ - input_seq seq; /* copy of the live sequence */ - const input_seq * defseq; /* pointer to the default sequence */ - const char * name; /* pointer to the base name of the item */ - const char * owner_name; /* pointer to the name of the owner of the item */ - ioport_group group; /* group type */ - uint8_t type; /* type of port */ - bool is_optional; /* true if this input is considered optional */ + const void * ref = nullptr; // reference to type description for global inputs or field for game inputs + input_seq_type seqtype = SEQ_TYPE_INVALID; // sequence type + input_seq seq; // copy of the live sequence + const input_seq * defseq = nullptr; // pointer to the default sequence + const char * name = nullptr; // pointer to the base name of the item + const char * owner_name = nullptr; // pointer to the name of the owner of the item + ioport_group group = IPG_INVALID; // group type + uint8_t type = 0U; // type of port + bool is_optional = false; // true if this input is considered optional }; + using data_vector = std::vector; - void populate_sorted(std::vector &&itemarray); + menu_input(mame_ui_manager &mui, render_container &container); + void populate_sorted(); void toggle_none_default(input_seq &selected_seq, input_seq &original_seq, const input_seq &selected_defseq); + data_vector data; const void * pollingref; input_seq_type pollingseq; input_item_data * pollingitem; @@ -84,7 +87,7 @@ private: virtual void populate(float &customtop, float &custombottom) override; virtual void update_input(struct input_item_data *seqchangeditem) override; - int group; + const int group; }; class menu_input_specific : public menu_input diff --git a/src/frontend/mame/ui/menu.cpp b/src/frontend/mame/ui/menu.cpp index bb56497f32a..bc920cd8d0b 100644 --- a/src/frontend/mame/ui/menu.cpp +++ b/src/frontend/mame/ui/menu.cpp @@ -32,12 +32,6 @@ namespace ui { -/*************************************************************************** - CONSTANTS -***************************************************************************/ - -#define UI_MENU_POOL_SIZE 65536 - /*************************************************************************** GLOBAL VARIABLES ***************************************************************************/ @@ -242,7 +236,6 @@ menu::menu(mame_ui_manager &mui, render_container &container) , m_container(container) , m_parent() , m_event() - , m_pool(nullptr) , m_customtop(0.0f) , m_custombottom(0.0f) , m_resetpos(0) @@ -266,19 +259,11 @@ menu::menu(mame_ui_manager &mui, render_container &container) menu::~menu() { - // free the pools - while (m_pool) - { - pool *const ppool = m_pool; - m_pool = m_pool->next; - global_free_array(ppool); - } } //------------------------------------------------- -// reset - free all items in the menu, -// and all memory allocated from the memory pool +// reset - free all items in the menu //------------------------------------------------- void menu::reset(reset_options options) @@ -291,9 +276,7 @@ void menu::reset(reset_options options) else if (options == reset_options::REMEMBER_REF) m_resetref = get_selection_ref(); - // reset all the pools and the item count back to 0 - for (pool *ppool = m_pool; ppool != nullptr; ppool = ppool->next) - ppool->top = (uint8_t *)(ppool + 1); + // reset the item count back to 0 m_items.clear(); m_visible_items = 0; m_selected = 0; @@ -485,38 +468,6 @@ const menu::event *menu::process(uint32_t flags, float x0, float y0) } -//------------------------------------------------- -// m_pool_alloc - allocate temporary memory -// from the menu's memory pool -//------------------------------------------------- - -void *menu::m_pool_alloc(size_t size) -{ - assert(size < UI_MENU_POOL_SIZE); - - // find a pool with enough room - for (pool *ppool = m_pool; ppool != nullptr; ppool = ppool->next) - { - if (ppool->end - ppool->top >= size) - { - void *result = ppool->top; - ppool->top += size; - return result; - } - } - - // allocate a new pool - pool *ppool = (pool *)global_alloc_array_clear(sizeof(*ppool) + UI_MENU_POOL_SIZE); - - // wire it up - ppool->next = m_pool; - m_pool = ppool; - ppool->top = (uint8_t *)(ppool + 1); - ppool->end = ppool->top + UI_MENU_POOL_SIZE; - return m_pool_alloc(size); -} - - //------------------------------------------------- // set_selection - changes the index // of the currently selected menu item diff --git a/src/frontend/mame/ui/menu.h b/src/frontend/mame/ui/menu.h index 16d50f7227b..c57fcb96f50 100644 --- a/src/frontend/mame/ui/menu.h +++ b/src/frontend/mame/ui/menu.h @@ -7,7 +7,6 @@ Internal MAME menus for the user interface. ***************************************************************************/ - #ifndef MAME_FRONTEND_UI_MENU_H #define MAME_FRONTEND_UI_MENU_H @@ -136,9 +135,6 @@ protected: running_machine &machine() const { return m_ui.machine(); } render_container &container() const { return m_container; } - // allocate temporary memory from the menu's memory pool - void *m_pool_alloc(size_t size); - void reset(reset_options options); void reset_parent(reset_options options) { m_parent->reset(options); } @@ -334,13 +330,6 @@ private: using global_state_ptr = std::shared_ptr; using global_state_map = std::map; - struct pool - { - pool *next; // chain to next one - uint8_t *top; // top of the pool - uint8_t *end; // end of the pool - }; - // request the specific handling of the game selection main menu bool is_special_main_menu() const; void set_special_main_menu(bool disable); @@ -381,7 +370,6 @@ private: render_container &m_container; // render_container we render to std::unique_ptr m_parent; // pointer to parent menu event m_event; // the UI event that occurred - pool *m_pool; // list of memory pools float m_customtop; // amount of extra height to add at the top float m_custombottom; // amount of extra height to add at the bottom -- cgit v1.2.3