summaryrefslogtreecommitdiffstats
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
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.
-rw-r--r--docs/source/techspecs/layout_files.rst19
-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
5 files changed, 133 insertions, 103 deletions
diff --git a/docs/source/techspecs/layout_files.rst b/docs/source/techspecs/layout_files.rst
index 0a8d39c4bba..be4965a9e95 100644
--- a/docs/source/techspecs/layout_files.rst
+++ b/docs/source/techspecs/layout_files.rst
@@ -1447,32 +1447,33 @@ Example layout files
These layout files demonstrate various artwork system features. They are all
internal layouts included in MAME.
-`sstrangr.lay <https://git.redump.net/mame/tree/src/mame/layout/sstrangr.lay?h=mame0226>`_
+`sstrangr.lay <https://git.redump.net/mame/tree/src/mame/layout/sstrangr.lay?h=mame0235>`_
A simple case of using translucent colour overlays to visually separate and
highlight elements on a black and white screen.
-`seawolf.lay <https://git.redump.net/mame/tree/src/mame/layout/seawolf.lay?h=mame0226>`_
+`seawolf.lay <https://git.redump.net/mame/tree/src/mame/layout/seawolf.lay?h=mame0235>`_
This system uses lamps for key gameplay elements. Blending modes are used
for the translucent colour overlay placed over the monitor, and the lamps
reflected in front of the monitor. Also uses collections to allow parts of
- the layout to be disabled selectively.
-`armora.lay <https://git.redump.net/mame/tree/src/mame/layout/armora.lay?h=mame0226>`_
+ the layout to be disabled selectively. The shapes on the overlay are drawn
+ using embedded SVG images.
+`armora.lay <https://git.redump.net/mame/tree/src/mame/layout/armora.lay?h=mame0235>`_
This game’s monitor is viewed directly through a translucent colour overlay
rather than being reflected from inside the cabinet. This means the overlay
reflects ambient light as well as affecting the colour of the video image.
-`tranz330.lay <https://git.redump.net/mame/tree/src/mame/layout/tranz330.lay?h=mame0226>`_
+`tranz330.lay <https://git.redump.net/mame/tree/src/mame/layout/tranz330.lay?h=mame0235>`_
A multi-segment alphanumeric display and keypad. The keys are clickable,
and provide visual feedback when pressed.
-`esq2by16.lay <https://git.redump.net/mame/tree/src/mame/layout/esq2by16.lay?h=mame0226>`_
+`esq2by16.lay <https://git.redump.net/mame/tree/src/mame/layout/esq2by16.lay?h=mame0235>`_
Builds up a multi-line dot matrix character display. Repeats are used to
avoid repetition for the rows in a character, characters in a line, and
lines in a page. Group colors allow a single element to be used for all
four display colours.
-`cgang.lay <https://git.redump.net/mame/tree/src/mame/layout/cgang.lay?h=mame0226>`_
+`cgang.lay <https://git.redump.net/mame/tree/src/mame/layout/cgang.lay?h=mame0235>`_
Animates the position of element items to simulate an electromechanical
shooting gallery game. Also demonstrates effective use of components to
build up complex graphics.
-`unkeinv.lay <https://git.redump.net/mame/tree/src/mame/layout/unkeinv.lay?h=mame0226>`_
+`unkeinv.lay <https://git.redump.net/mame/tree/src/mame/layout/unkeinv.lay?h=mame0235>`_
Shows the position of a slider control with LEDs on it.
-`md6802.lay <https://git.redump.net/mame/tree/src/mame/layout/md6802.lay?h=mame0226>`_
+`md6802.lay <https://git.redump.net/mame/tree/src/mame/layout/md6802.lay?h=mame0235>`_
Effectively using groups as a procedural programming language to build up an
image of a trainer board.
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