summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2021-09-21 01:02:11 +1000
committer Vas Crabb <vas@vastheman.com>2021-09-21 01:02:11 +1000
commitda1af2b0d6816a5da1544176b882407bd0dad2ee (patch)
tree9a7db16882a0fe937a1b2cbdcb6e78711f33dfa3 /src
parent362d859dc15384f98b97d37cb5e21c7798df3cab (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.cpp8
-rw-r--r--src/emu/rendlay.h16
-rw-r--r--src/frontend/mame/luaengine_render.cpp66
-rw-r--r--src/lib/util/delegate.h127
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