diff options
| author | 2021-09-21 01:02:11 +1000 | |
|---|---|---|
| committer | 2021-09-21 01:02:11 +1000 | |
| commit | da1af2b0d6816a5da1544176b882407bd0dad2ee (patch) | |
| tree | 9a7db16882a0fe937a1b2cbdcb6e78711f33dfa3 /src | |
| parent | 362d859dc15384f98b97d37cb5e21c7798df3cab (diff) | |
-delegates: Fixed structure return with MSVC C++ ABI.
* Automatically use delegate_mfp_compatible to generate an adaptor for
member functions that return non-scalar, non-reference types
(partially addresses #8597).
* Enabled the MSVC delegate implemenation for MSVC on AArch64.
* Switched back to neater delegate types for layout item bounds and
colour.
-docs: Updated the example layout links to point to 0.235 - this means
there's now an example of embedded SVG.
Diffstat (limited to 'src')
| -rw-r--r-- | src/emu/rendlay.cpp | 8 | ||||
| -rw-r--r-- | src/emu/rendlay.h | 16 | ||||
| -rw-r--r-- | src/frontend/mame/luaengine_render.cpp | 66 | ||||
| -rw-r--r-- | src/lib/util/delegate.h | 127 |
4 files changed, 123 insertions, 94 deletions
diff --git a/src/emu/rendlay.cpp b/src/emu/rendlay.cpp index c3f7a70a2e8..b33c58e8fef 100644 --- a/src/emu/rendlay.cpp +++ b/src/emu/rendlay.cpp @@ -4823,10 +4823,10 @@ int layout_view::item::get_anim_input() const // get_interpolated_bounds - animated bounds //------------------------------------------------- -void layout_view::item::get_interpolated_bounds(render_bounds &result) const +render_bounds layout_view::item::get_interpolated_bounds() const { assert(m_bounds.size() > 1U); - result = interpolate_bounds(m_bounds, m_get_anim_state()); + return interpolate_bounds(m_bounds, m_get_anim_state()); } @@ -4834,10 +4834,10 @@ void layout_view::item::get_interpolated_bounds(render_bounds &result) const // get_interpolated_color - animated color //------------------------------------------------- -void layout_view::item::get_interpolated_color(render_color &result) const +render_color layout_view::item::get_interpolated_color() const { assert(m_color.size() > 1U); - result = interpolate_color(m_color, m_get_anim_state()); + return interpolate_color(m_color, m_get_anim_state()); } diff --git a/src/emu/rendlay.h b/src/emu/rendlay.h index 5555af820ac..5b121d18880 100644 --- a/src/emu/rendlay.h +++ b/src/emu/rendlay.h @@ -25,7 +25,7 @@ namespace emu::render::detail { struct bounds_step { - void get(render_bounds &result) const { result = bounds; } + render_bounds get() const { return bounds; } int state; render_bounds bounds; @@ -35,7 +35,7 @@ using bounds_vector = std::vector<bounds_step>; struct color_step { - void get(render_color &result) const { result = color; } + render_color get() const { return color; } int state; render_color color; @@ -261,8 +261,8 @@ public: public: using state_delegate = delegate<int ()>; - using bounds_delegate = delegate<void (render_bounds &)>; - using color_delegate = delegate<void (render_color &)>; + using bounds_delegate = delegate<render_bounds ()>; + using color_delegate = delegate<render_color ()>; // construction/destruction item( @@ -280,8 +280,8 @@ public: screen_device *screen() const { return m_screen; } bool bounds_animated() const { return m_bounds.size() > 1U; } bool color_animated() const { return m_color.size() > 1U; } - render_bounds bounds() const { render_bounds result; m_get_bounds(result); return result; } - render_color color() const { render_color result; m_get_color(result); return result; } + render_bounds bounds() const { return m_get_bounds(); } + render_color color() const { return m_get_color(); } int blend_mode() const { return m_blend_mode; } u32 visibility_mask() const { return m_visibility_mask; } int orientation() const { return m_orientation; } @@ -323,8 +323,8 @@ public: int get_input_field_conditional() const; int get_anim_output() const; int get_anim_input() const; - void get_interpolated_bounds(render_bounds &result) const; - void get_interpolated_color(render_color &result) const; + render_bounds get_interpolated_bounds() const; + render_color get_interpolated_color() const; static layout_element *find_element(view_environment &env, util::xml::data_node const &itemnode, element_map &elemmap); static bounds_vector make_bounds(view_environment &env, util::xml::data_node const &itemnode, layout_group::transform const &trans); diff --git a/src/frontend/mame/luaengine_render.cpp b/src/frontend/mame/luaengine_render.cpp index eab50d89a90..2cf8cc6878d 100644 --- a/src/frontend/mame/luaengine_render.cpp +++ b/src/frontend/mame/luaengine_render.cpp @@ -291,63 +291,17 @@ void lua_engine::initialize_render(sol::table &emu) "set_animation_state_callback", "animation state"); layout_view_item_type["set_bounds_callback"] = - [this] (layout_view::item &i, sol::object cb) - { - if (cb == sol::lua_nil) - { - i.set_bounds_callback(layout_view::item::bounds_delegate()); - } - else if (cb.is<sol::protected_function>()) - { - i.set_bounds_callback(layout_view::item::bounds_delegate( - [this, cbfunc = cb.as<sol::protected_function>()] (render_bounds &b) - { - auto result(invoke(cbfunc).get<sol::optional<render_bounds> >()); - if (result) - { - b = *result; - } - else - { - osd_printf_error("[LUA ERROR] invalid return from bounds callback\n"); - b = render_bounds{ 0.0, 0.0, 1.0, 1.0 }; - } - })); - } - else - { - osd_printf_error("[LUA ERROR] must call set_bounds_callback with function or nil\n"); - } - }; + make_simple_callback_setter<render_bounds>( + &layout_view::item::set_bounds_callback, + [] () { return render_bounds{ 0.0f, 0.0f, 1.0f, 1.0f }; }, + "set_bounds_callback", + "bounds"); layout_view_item_type["set_color_callback"] = - [this] (layout_view::item &i, sol::object cb) - { - if (cb == sol::lua_nil) - { - i.set_color_callback(layout_view::item::color_delegate()); - } - else if (cb.is<sol::protected_function>()) - { - i.set_color_callback(layout_view::item::color_delegate( - [this, cbfunc = cb.as<sol::protected_function>()] (render_color &c) - { - auto result(invoke(cbfunc).get<sol::optional<render_color> >()); - if (result) - { - c = *result; - } - else - { - osd_printf_error("[LUA ERROR] invalid return from color callback\n"); - c = render_color{ 1.0, 1.0, 1.0, 1.0 }; - } - })); - } - else - { - osd_printf_error("[LUA ERROR] must call set_bounds_callback with function or nil\n"); - } - }; + make_simple_callback_setter<render_color>( + &layout_view::item::set_color_callback, + [] () { return render_color{ 1.0f, 1.0f, 1.0f, 1.0f }; }, + "set_color_callback", + "color"); layout_view_item_type["id"] = sol::property( [] (layout_view::item &i, sol::this_state s) -> sol::object { diff --git a/src/lib/util/delegate.h b/src/lib/util/delegate.h index a92d943bbd4..59e83f82617 100644 --- a/src/lib/util/delegate.h +++ b/src/lib/util/delegate.h @@ -116,6 +116,7 @@ #include <any> #include <cassert> +#include <cstddef> #include <cstdint> #include <cstring> #include <functional> @@ -123,7 +124,7 @@ #include <type_traits> #include <typeinfo> #include <utility> -#include <cstddef> + //************************************************************************** // MACROS @@ -139,7 +140,7 @@ #define MAME_DELEGATE_USE_TYPE MAME_DELEGATE_TYPE_COMPATIBLE #elif defined(__GNUC__) // 32bit MINGW asks for different convention - #if defined(__MINGW32__) && !defined(__x86_64) && defined(__i386__) + #if defined(__MINGW32__) && !defined(__x86_64__) && defined(__i386__) #define MAME_DELEGATE_USE_TYPE MAME_DELEGATE_TYPE_ITANIUM #define MAME_DELEGATE_MEMBER_ABI __thiscall #define MAME_DELEGATE_DIFFERENT_MEMBER_ABI 1 @@ -150,7 +151,7 @@ #define MAME_DELEGATE_MEMBER_ABI #define MAME_DELEGATE_DIFFERENT_MEMBER_ABI 0 #endif -#elif defined(_MSC_VER) && defined(_M_X64) +#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) #define MAME_DELEGATE_MEMBER_ABI #define MAME_DELEGATE_DIFFERENT_MEMBER_ABI 0 #define MAME_DELEGATE_USE_TYPE MAME_DELEGATE_TYPE_MSVC @@ -287,30 +288,15 @@ public: // binding helpers template <typename FunctionType> - void update_after_bind(FunctionType &funcptr, delegate_generic_class *&object) - { - m_realobject = object; - object = reinterpret_cast<delegate_generic_class *>(this); - funcptr = reinterpret_cast<FunctionType>(m_stubfunction); - } + void update_after_bind(FunctionType &funcptr, delegate_generic_class *&object); template <typename FunctionType> - void update_after_copy(FunctionType &funcptr, delegate_generic_class *&object) - { - assert(reinterpret_cast<FunctionType>(m_stubfunction) == funcptr); - object = reinterpret_cast<delegate_generic_class *>(this); - } + void update_after_copy(FunctionType &funcptr, delegate_generic_class *&object); private: // helper stubs for calling encased member function pointers template <class FunctionClass, typename ReturnType, typename... Params> - static ReturnType method_stub(delegate_generic_class *object, Params ... args) - { - using mfptype = ReturnType(FunctionClass::*)(Params...); - delegate_mfp_compatible &_this = *reinterpret_cast<delegate_mfp_compatible *>(object); - mfptype &mfp = *reinterpret_cast<mfptype *>(&_this.m_rawdata); - return (reinterpret_cast<FunctionClass *>(_this.m_realobject)->*mfp)(std::forward<Params>(args)...); - } + static ReturnType method_stub(delegate_generic_class *object, Params ... args); // helper to convert a function of a given type to a generic function, forcing template // instantiation to match the source type @@ -340,6 +326,33 @@ private: }; +template <typename FunctionType> +void delegate_mfp_compatible::update_after_bind(FunctionType &funcptr, delegate_generic_class *&object) +{ + m_realobject = object; + object = reinterpret_cast<delegate_generic_class *>(this); + funcptr = reinterpret_cast<FunctionType>(m_stubfunction); +} + + +template <typename FunctionType> +void delegate_mfp_compatible::update_after_copy(FunctionType &funcptr, delegate_generic_class *&object) +{ + assert(reinterpret_cast<FunctionType>(m_stubfunction) == funcptr); + object = reinterpret_cast<delegate_generic_class *>(this); +} + + +template <class FunctionClass, typename ReturnType, typename... Params> +ReturnType delegate_mfp_compatible::method_stub(delegate_generic_class *object, Params ... args) +{ + using mfptype = ReturnType(FunctionClass::*)(Params...); + delegate_mfp_compatible &_this = *reinterpret_cast<delegate_mfp_compatible *>(object); + mfptype &mfp = *reinterpret_cast<mfptype *>(&_this.m_rawdata); + return (reinterpret_cast<FunctionClass *>(_this.m_realobject)->*mfp)(std::forward<Params>(args)...); +} + + /// \brief Itanium C++ ABI member function pointer wrapper /// @@ -512,19 +525,81 @@ private: int m_vptr_offs = 0; // offset to apply to this pointer to obtain pointer to vptr int m_vt_index = 0; // offset into vtable to additional delta to apply to the 'this' pointer - unsigned m_size = 0; + unsigned m_size = 0; // overall size of the pointer to member function representation }; #if MAME_DELEGATE_USE_TYPE == MAME_DELEGATE_TYPE_COMPATIBLE -using delegate_mfp = delegate_mfp_compatible; + +template <typename ReturnType> +struct delegate_mfp { using type = delegate_mfp_compatible; }; + #elif MAME_DELEGATE_USE_TYPE == MAME_DELEGATE_TYPE_ITANIUM -using delegate_mfp = delegate_mfp_itanium; + +template <typename ReturnType> +struct delegate_mfp { using type = delegate_mfp_itanium; }; + #elif MAME_DELEGATE_USE_TYPE == MAME_DELEGATE_TYPE_MSVC -using delegate_mfp = delegate_mfp_msvc; + +/// \brief Determine whether a type is returned conventionally +/// +/// Under the MSVC C++ ABI with the Microsoft calling convention for +/// x86-64 or AArch64, the calling convention for member functions is +/// not quite the same as a free function with the "this" pointer as the +/// first parameter. +/// +/// Conventionally, structure and union values can be returned in +/// registers if they are small enough and are aggregates (trivially +/// constructible, destructible, copyable and assignable). On x86-64, +/// if the value cannot be returned in registers, the pointer to the +/// area for the return value is conventionally passed in RCX and +/// explicit parameters are shifted by one position. On AArch64, if the +/// value cannot be returned in registers, the pointer to the area for +/// the return value is passed in X8 (explicit parameters do not need to +/// be shifted). +/// +/// For member functions, structure and union types are never returned +/// in registers, and the pointer to the area for the return value is +/// passed differently for structures and unions. When a structure or +/// union is to be returned, a pointer to the area for the return value +/// is effectively passed as a second implicit parameter. On x86-64, +/// the "this" pointer is passed in RCX and the pointer to the area for +/// the return value is passed in RDX; on AArch64, the "this" pointer is +/// passed in X0 and the pointer to the area for the return value is +/// passed in X1. Explicit parameters are shifted an additional +/// position to allow for the second implicit parameter. +/// +/// Note that pointer types are returned conventionally from member +/// functions even when they're too large to return in registers (e.g. a +/// pointer to a function member of a class with unknown inheritance). +/// +/// Because of this, we may need to use the #delegate_mfp_compatible +/// class to generate adaptor thunks depending on the return type. This +/// trait doesn't need to reliably be true for types that are returned +/// conventionally from member functions; it only needs to reliably be +/// false for types that aren't. Incorrectly yielding true will result +/// in incorrect behaviour while incorrectly yielding false will just +/// cause increased overhead (both compile-time and run-time). +template <typename ReturnType> +using delegate_mfp_conventional_return = std::bool_constant< + std::is_void_v<ReturnType> || + std::is_scalar_v<ReturnType> || + std::is_reference_v<ReturnType> >; + +template <typename ReturnType, typename Enable = void> +struct delegate_mfp; + +template <typename ReturnType> +struct delegate_mfp<ReturnType, std::enable_if_t<delegate_mfp_conventional_return<ReturnType>::value> > { using type = delegate_mfp_msvc; }; + +template <typename ReturnType> +struct delegate_mfp<ReturnType, std::enable_if_t<!delegate_mfp_conventional_return<ReturnType>::value> > { using type = delegate_mfp_compatible; }; + #endif +template <typename ReturnType> using delegate_mfp_t = typename delegate_mfp<ReturnType>::type; + /// \brief Helper class for generating late bind functions @@ -705,7 +780,7 @@ protected: delegate_generic_class * m_object = nullptr; // resolved object to the post-cast object delegate_late_bind_helper<LateBindBase> m_latebinder; // late binding helper generic_static_func m_raw_function = nullptr; // raw static function pointer - delegate_mfp m_raw_mfp; // raw member function pointer + delegate_mfp_t<ReturnType> m_raw_mfp; // raw member function pointer }; } // namespace util::detail |
