diff options
Diffstat (limited to 'src/osd/modules/render/drawbgfx.cpp')
-rw-r--r-- | src/osd/modules/render/drawbgfx.cpp | 1147 |
1 files changed, 783 insertions, 364 deletions
diff --git a/src/osd/modules/render/drawbgfx.cpp b/src/osd/modules/render/drawbgfx.cpp index 3c15bc3cf96..ef90478e59e 100644 --- a/src/osd/modules/render/drawbgfx.cpp +++ b/src/osd/modules/render/drawbgfx.cpp @@ -5,10 +5,44 @@ // drawbgfx.cpp - BGFX renderer // //============================================================ + +#include "drawbgfx.h" + +// render/bgfx +#include "bgfx/effect.h" +#include "bgfx/effectmanager.h" +#include "bgfx/shadermanager.h" +#include "bgfx/slider.h" +#include "bgfx/target.h" +#include "bgfx/target.h" +#include "bgfx/targetmanager.h" +#include "bgfx/texture.h" +#include "bgfx/texturemanager.h" +#include "bgfx/uniform.h" +#include "bgfx/view.h" + +// render +#include "aviwrite.h" +#include "bgfxutil.h" +#include "render_module.h" + +// emu +#include "emu.h" +#include "config.h" +#include "render.h" +#include "rendutil.h" + +// util +#include "util/xmlfile.h" + +// OSD +#include "modules/lib/osdobj_common.h" +#include "window.h" + #include <bx/math.h> #include <bx/readerwriter.h> -#if defined(SDLMAME_WIN32) || defined(OSD_WINDOWS) || defined(OSD_UWP) +#if defined(SDLMAME_WIN32) || defined(OSD_WINDOWS) // standard windows headers #include <windows.h> #if defined(SDLMAME_WIN32) @@ -22,38 +56,415 @@ extern void *GetOSWindow(void *wincontroller); #endif #endif -// MAMEOS headers -#include "emu.h" -#include "window.h" -#include "rendutil.h" -#include "aviwrite.h" - #include <bgfx/bgfx.h> #include <bgfx/platform.h> + +#include "imgui/imgui.h" + #include <algorithm> -#include "drawbgfx.h" -#include "bgfxutil.h" -#include "bgfx/texturemanager.h" -#include "bgfx/targetmanager.h" -#include "bgfx/shadermanager.h" -#include "bgfx/effectmanager.h" -#include "bgfx/chainmanager.h" -#include "bgfx/effect.h" -#include "bgfx/texture.h" -#include "bgfx/target.h" -#include "bgfx/chain.h" -#include "bgfx/vertex.h" -#include "bgfx/uniform.h" -#include "bgfx/slider.h" -#include "bgfx/target.h" -#include "bgfx/view.h" -#include "imgui/imgui.h" +//============================================================ +// Renderer interface to parent module +//============================================================ + +class renderer_bgfx::parent_module +{ +public: + util::xml::data_node &persistent_settings() { return *m_persistent_settings; } + osd_options const &options() const { return *m_options; } + uint32_t max_texture_size() const { return m_max_texture_size; } + + template <typename T> + util::notifier_subscription subscribe_load(void (T::*func)(util::xml::data_node const &), T *obj) + { + return m_load_notifier.subscribe(delegate<void (util::xml::data_node const &)>(func, obj)); + } + + template <typename T> + util::notifier_subscription subscribe_save(void (T::*func)(util::xml::data_node &), T *obj) + { + return m_save_notifier.subscribe(delegate<void (util::xml::data_node &)>(func, obj)); + } + +protected: + parent_module() + : m_options(nullptr) + , m_max_texture_size(0) + , m_renderer_count(0) + { + } + virtual ~parent_module() + { + assert(!m_renderer_count); + } + + bool has_active_renderers() const + { + return 0 < m_renderer_count; + } + + util::notifier<util::xml::data_node const &> m_load_notifier; + util::notifier<util::xml::data_node &> m_save_notifier; + util::xml::file::ptr m_persistent_settings; + osd_options const *m_options; + uint32_t m_max_texture_size; + +private: + friend class parent_module_holder; + + virtual void last_renderer_destroyed() = 0; + + void renderer_created() + { + ++m_renderer_count; + } + + void renderer_destroyed() + { + assert(m_renderer_count); + if (!--m_renderer_count) + last_renderer_destroyed(); + } + + unsigned m_renderer_count; +}; + + +inline renderer_bgfx::parent_module_holder::parent_module_holder(parent_module &parent) + : m_parent(parent) +{ + m_parent.renderer_created(); +} + + +inline renderer_bgfx::parent_module_holder::~parent_module_holder() +{ + m_parent.renderer_destroyed(); +} + + + +//============================================================ +// OSD MODULE +//============================================================ + +namespace osd { + +namespace { + +class video_bgfx : public osd_module, public render_module, protected renderer_bgfx::parent_module +{ +public: + video_bgfx() + : osd_module(OSD_RENDERER_PROVIDER, "bgfx") + , m_bgfx_library_initialized(false) + { + } + ~video_bgfx() { exit(); } + + virtual int init(osd_interface &osd, osd_options const &options) override; + virtual void exit() override; + + virtual std::unique_ptr<osd_renderer> create(osd_window &window) override; + +protected: + virtual unsigned flags() const override { return FLAG_INTERACTIVE; } + +private: + virtual void last_renderer_destroyed() override; + + void load_config(config_type cfg_type, config_level cfg_level, util::xml::data_node const *parentnode); + void save_config(config_type cfg_type, util::xml::data_node *parentnode); + + bool init_bgfx_library(osd_window &window); + + static bool set_platform_data(bgfx::PlatformData &platform_data, osd_window const &window); + + bool m_bgfx_library_initialized; +}; + + +//============================================================ +// video_bgfx::init +//============================================================ + +int video_bgfx::init(osd_interface &osd, osd_options const &options) +{ + m_options = &options; + m_persistent_settings = util::xml::file::create(); + + // Check that BGFX directory exists + char const *const bgfx_path = options.bgfx_path(); + osd::directory::ptr directory = osd::directory::open(bgfx_path); + if (!directory) + { + osd_printf_error("Unable to find the BGFX path %s, please install it or fix the bgfx_path setting to use the BGFX renderer.\n", bgfx_path); + return -1; + } + directory.reset(); + + // Verify baseline shaders + const bool gui_opaque_valid = effect_manager::validate_effect(options, "gui_opaque"); + const bool gui_blend_valid = effect_manager::validate_effect(options, "gui_blend"); + const bool gui_multiply_valid = effect_manager::validate_effect(options, "gui_multiply"); + const bool gui_add_valid = effect_manager::validate_effect(options, "gui_add"); + const bool all_gui_valid = gui_opaque_valid && gui_blend_valid && gui_multiply_valid && gui_add_valid; + + const bool screen_opaque_valid = effect_manager::validate_effect(options, "screen_opaque"); + const bool screen_blend_valid = effect_manager::validate_effect(options, "screen_blend"); + const bool screen_multiply_valid = effect_manager::validate_effect(options, "screen_multiply"); + const bool screen_add_valid = effect_manager::validate_effect(options, "screen_add"); + const bool all_screen_valid = screen_opaque_valid && screen_blend_valid && screen_multiply_valid && screen_add_valid; + + if (!all_gui_valid || !all_screen_valid) + { + osd_printf_error("BGFX: Unable to load required shaders. Please update the %s folder or adjust your bgfx_path setting.\n", options.bgfx_path()); + return -1; + } + + m_max_texture_size = 16384; // Relatively safe default on modern GPUs + + // Register configuration handlers - do this last because it can't be undone + downcast<osd_common_t &>(osd).machine().configuration().config_register( + "bgfx", + configuration_manager::load_delegate(&video_bgfx::load_config, this), + configuration_manager::save_delegate(&video_bgfx::save_config, this)); + + return 0; +} + + +//============================================================ +// video_bgfx::exit +//============================================================ + +void video_bgfx::exit() +{ + assert(!has_active_renderers()); + + if (m_bgfx_library_initialized) + { + osd_printf_verbose("Shutting down BGFX library\n"); + imguiDestroy(); + bgfx::shutdown(); + m_bgfx_library_initialized = false; + } + m_max_texture_size = 0; + m_persistent_settings.reset(); + m_options = nullptr; +} + + +//============================================================ +// video_bgfx::create +//============================================================ + +std::unique_ptr<osd_renderer> video_bgfx::create(osd_window &window) +{ + // start BGFX if this is the first window + if (!m_bgfx_library_initialized) + { + assert(window.index() == 0); // bad things will happen otherwise + assert(!has_active_renderers()); + + osd_printf_verbose("Initializing BGFX library\n"); + if (!init_bgfx_library(window)) + { + osd_printf_error("BGFX library initialization failed\n"); + return nullptr; + } + m_bgfx_library_initialized = true; + } + + return std::make_unique<renderer_bgfx>(window, static_cast<renderer_bgfx::parent_module &>(*this)); +} + + +//============================================================ +// video_bgfx::last_renderer_destroyed +//============================================================ + +void video_bgfx::last_renderer_destroyed() +{ + if (m_bgfx_library_initialized) + { + osd_printf_verbose("No more renderers - shutting down BGFX library\n"); + imguiDestroy(); + bgfx::shutdown(); + m_bgfx_library_initialized = false; + m_max_texture_size = 0; + } +} + + +//============================================================ +// video_bgfx::load_config +//============================================================ + +void video_bgfx::load_config(config_type cfg_type, config_level cfg_level, util::xml::data_node const *parentnode) +{ + if ((cfg_type == config_type::SYSTEM) && parentnode) + m_load_notifier(*parentnode); +} + + +//============================================================ +// video_bgfx::save_config +//============================================================ +void video_bgfx::save_config(config_type cfg_type, util::xml::data_node *parentnode) +{ + if (cfg_type == config_type::SYSTEM) + m_save_notifier(*parentnode); +} + + +//============================================================ +// video_bgfx::init_bgfx_library //============================================================ -// DEBUGGING + +bool video_bgfx::init_bgfx_library(osd_window &window) +{ + osd_dim const wdim = window.get_size(); + + bgfx::Init init; + init.type = bgfx::RendererType::Count; + init.vendorId = BGFX_PCI_ID_NONE; + init.resolution.width = wdim.width(); + init.resolution.height = wdim.height(); + init.resolution.numBackBuffers = 1; + init.resolution.reset = video_config.waitvsync ? BGFX_RESET_VSYNC : BGFX_RESET_NONE; + if (!set_platform_data(init.platformData, window)) + { + osd_printf_error("Setting BGFX platform data failed\n"); + return false; + } + + std::string_view const backend(m_options->bgfx_backend()); + if (backend == "auto") + ; // do nothing + else if (backend == "dx9" || backend == "d3d9") + init.type = bgfx::RendererType::Direct3D9; + else if (backend == "dx11" || backend == "d3d11") + init.type = bgfx::RendererType::Direct3D11; + else if (backend == "dx12" || backend == "d3d12") + init.type = bgfx::RendererType::Direct3D12; + else if (backend == "gles") + init.type = bgfx::RendererType::OpenGLES; + else if (backend == "glsl" || backend == "opengl") + init.type = bgfx::RendererType::OpenGL; + else if (backend == "vulkan") + init.type = bgfx::RendererType::Vulkan; + else if (backend == "metal") + init.type = bgfx::RendererType::Metal; + else + osd_printf_warning("Unknown BGFX backend type '%s', going with auto-detection.\n", backend); + + if (!bgfx::init(init)) + return false; + + bgfx::reset(wdim.width(), wdim.height(), video_config.waitvsync ? BGFX_RESET_VSYNC : BGFX_RESET_NONE); + + // Enable debug text if requested + bool bgfx_debug = m_options->bgfx_debug(); + bgfx::setDebug(bgfx_debug ? BGFX_DEBUG_STATS : BGFX_DEBUG_TEXT); + + // Get actual maximum texture size + bgfx::Caps const *const caps = bgfx::getCaps(); + m_max_texture_size = caps->limits.maxTextureSize; + + ScreenVertex::init(); + + imguiCreate(); + + return true; +} + + //============================================================ +// Utility for setting up window handle +//============================================================ + +bool video_bgfx::set_platform_data(bgfx::PlatformData &platform_data, osd_window const &window) +{ +#if defined(OSD_WINDOWS) + platform_data.ndt = nullptr; + platform_data.nwh = dynamic_cast<win_window_info const &>(window).platform_window(); +#elif defined(OSD_MAC) + platform_data.ndt = nullptr; + platform_data.nwh = GetOSWindow(dynamic_cast<mac_window_info const &>(window).platform_window()); +#elif defined(SDLMAME_EMSCRIPTEN) + platform_data.ndt = nullptr; + platform_data.nwh = (void *)"#canvas"; // HTML5 target selector +#else // defined(OSD_*) + SDL_SysWMinfo wmi; + SDL_VERSION(&wmi.version); + if (!SDL_GetWindowWMInfo(dynamic_cast<sdl_window_info const &>(window).platform_window(), &wmi)) + { + osd_printf_error("BGFX: Error getting SDL window info: %s\n", SDL_GetError()); + return false; + } + + switch (wmi.subsystem) + { +#if defined(SDL_VIDEO_DRIVER_WINDOWS) + case SDL_SYSWM_WINDOWS: + platform_data.ndt = nullptr; + platform_data.nwh = wmi.info.win.window; + break; +#endif +#if defined(SDL_VIDEO_DRIVER_X11) + case SDL_SYSWM_X11: + platform_data.ndt = wmi.info.x11.display; + platform_data.nwh = (void *)uintptr_t(wmi.info.x11.window); + break; +#endif +#if defined(SDL_VIDEO_DRIVER_COCOA) + case SDL_SYSWM_COCOA: + platform_data.ndt = nullptr; + platform_data.nwh = wmi.info.cocoa.window; + break; +#endif +#if defined(SDL_VIDEO_DRIVER_WAYLAND) && SDL_VERSION_ATLEAST(2, 0, 16) + case SDL_SYSWM_WAYLAND: + platform_data.ndt = wmi.info.wl.display; + platform_data.nwh = wmi.info.wl.surface; + if (!platform_data.nwh) + { + osd_printf_error("BGFX: Error creating a Wayland window\n"); + return false; + } + platform_data.type = bgfx::NativeWindowHandleType::Wayland; + break; +#endif +#if defined(SDL_VIDEO_DRIVER_ANDROID) + case SDL_SYSWM_ANDROID: + platform_data.ndt = nullptr; + platform_data.nwh = wmi.info.android.window; + break; +#endif + default: + osd_printf_error("BGFX: Unsupported SDL window manager type %u\n", wmi.subsystem); + return false; + } +#endif // defined(OSD_*) + + platform_data.context = nullptr; + platform_data.backBuffer = nullptr; + platform_data.backBufferDS = nullptr; + bgfx::setPlatformData(platform_data); + + return true; +} + +} // anonymous namespace + +} // namespace osd + +MODULE_DEFINITION(RENDERER_BGFX, osd::video_bgfx) + + //============================================================ // CONSTANTS @@ -64,6 +475,8 @@ uint32_t const renderer_bgfx::PACKABLE_SIZE = 128; uint32_t const renderer_bgfx::WHITE_HASH = 0x87654321; char const *const renderer_bgfx::WINDOW_PREFIX = "Window 0, "; + + //============================================================ // MACROS //============================================================ @@ -71,45 +484,113 @@ char const *const renderer_bgfx::WINDOW_PREFIX = "Window 0, "; #define GIBBERISH (0) #define SCENE_VIEW (0) + + //============================================================ // STATICS //============================================================ -bool renderer_bgfx::s_window_set = false; uint32_t renderer_bgfx::s_current_view = 0; +uint32_t renderer_bgfx::s_width[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +uint32_t renderer_bgfx::s_height[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + + +//============================================================ +// helper for getting native platform window +//============================================================ + +#ifdef OSD_SDL +static std::pair<void *, bool> sdlNativeWindowHandle(SDL_Window *window) +{ + SDL_SysWMinfo wmi; + SDL_VERSION(&wmi.version); + if (!SDL_GetWindowWMInfo(window, &wmi)) + return std::make_pair(nullptr, false); + + switch (wmi.subsystem) + { +#if defined(SDL_VIDEO_DRIVER_WINDOWS) + case SDL_SYSWM_WINDOWS: + return std::make_pair(wmi.info.win.window, true); +#endif +#if defined(SDL_VIDEO_DRIVER_X11) + case SDL_SYSWM_X11: + return std::make_pair((void *)uintptr_t(wmi.info.x11.window), true); +#endif +#if defined(SDL_VIDEO_DRIVER_COCOA) + case SDL_SYSWM_COCOA: + return std::make_pair(wmi.info.cocoa.window, true); +#endif +#if defined(SDL_VIDEO_DRIVER_WAYLAND) && SDL_VERSION_ATLEAST(2, 0, 16) + case SDL_SYSWM_WAYLAND: + return std::make_pair(wmi.info.wl.surface, true); +#endif +#if defined(SDL_VIDEO_DRIVER_ANDROID) + case SDL_SYSWM_ANDROID: + return std::make_pair(wmi.info.android.window, true); +#endif + default: + return std::make_pair(nullptr, false); + } +} +#endif // OSD_SDL + + //============================================================ // renderer_bgfx - constructor //============================================================ -renderer_bgfx::renderer_bgfx(std::shared_ptr<osd_window> w) - : osd_renderer(w, FLAG_NONE) - , m_options(downcast<osd_options &>(w->machine().options())) +renderer_bgfx::renderer_bgfx(osd_window &window, parent_module &parent) + : osd_renderer(window) + , m_module(parent) , m_framebuffer(nullptr) , m_texture_cache(nullptr) , m_dimensions(0, 0) - , m_textures(nullptr) - , m_targets(nullptr) - , m_shaders(nullptr) - , m_effects(nullptr) - , m_chains(nullptr) - , m_ortho_view(nullptr) , m_max_view(0) , m_avi_view(nullptr) , m_avi_writer(nullptr) , m_avi_target(nullptr) + , m_load_sub(parent.subscribe_load(&renderer_bgfx::load_config, this)) + , m_save_sub(parent.subscribe_save(&renderer_bgfx::save_config, this)) { + // load settings if recreated after fullscreen toggle + util::xml::data_node *windownode = m_module().persistent_settings().get_child("window"); + while (windownode) + { + if (windownode->get_attribute_int("index", -1) != window.index()) + { + windownode = windownode->get_next_sibling("window"); + } + else + { + if (!m_config) + { + m_config = util::xml::file::create(); + windownode->copy_into(*m_config); + } + std::exchange(windownode, windownode->get_next_sibling("window"))->delete_node(); + } + } } + + //============================================================ // renderer_bgfx - destructor //============================================================ renderer_bgfx::~renderer_bgfx() { + // persist settings across fullscreen toggle + if (m_config) + m_config->get_first_child()->copy_into(m_module().persistent_settings()); + else if (m_chains) + m_chains->save_config(m_module().persistent_settings()); + bgfx::reset(0, 0, BGFX_RESET_NONE); - bgfx::touch(0); - bgfx::frame(); + if (m_avi_writer != nullptr && m_avi_writer->recording()) { m_avi_writer->stop(); @@ -123,257 +604,99 @@ renderer_bgfx::~renderer_bgfx() delete [] m_avi_data; delete m_avi_view; } - - // Cleanup. - delete m_chains; - delete m_effects; - delete m_shaders; - delete m_textures; - delete m_targets; } + + //============================================================ // renderer_bgfx::create //============================================================ -#ifdef OSD_WINDOWS -inline void winSetHwnd(::HWND _window) -{ - bgfx::PlatformData pd; - pd.ndt = NULL; - pd.nwh = _window; - pd.context = NULL; - pd.backBuffer = NULL; - pd.backBufferDS = NULL; - bgfx::setPlatformData(pd); -} -#elif defined(OSD_MAC) -inline void macSetWindow(void *_window) -{ - bgfx::PlatformData pd; - pd.ndt = NULL; - pd.nwh = GetOSWindow(_window); - pd.context = NULL; - pd.backBuffer = NULL; - pd.backBufferDS = NULL; - bgfx::setPlatformData(pd); -} -#elif defined(OSD_SDL) -static void* sdlNativeWindowHandle(SDL_Window* _window) -{ - SDL_SysWMinfo wmi; - SDL_VERSION(&wmi.version); - if (!SDL_GetWindowWMInfo(_window, &wmi)) - { - return nullptr; - } - -# if BX_PLATFORM_LINUX || BX_PLATFORM_BSD || BX_PLATFORM_RPI - return (void*)wmi.info.x11.window; -# elif BX_PLATFORM_OSX - return wmi.info.cocoa.window; -# elif BX_PLATFORM_WINDOWS - return wmi.info.win.window; -# elif BX_PLATFORM_STEAMLINK - return wmi.info.vivante.window; -# elif BX_PLATFORM_EMSCRIPTEN || BX_PLATFORM_ANDROID - return nullptr; -# endif // BX_PLATFORM_ -} - -inline bool sdlSetWindow(SDL_Window* _window) -{ - SDL_SysWMinfo wmi; - SDL_VERSION(&wmi.version); - if (!SDL_GetWindowWMInfo(_window, &wmi) ) - { - return false; - } - - bgfx::PlatformData pd; -# if BX_PLATFORM_LINUX || BX_PLATFORM_BSD - pd.ndt = wmi.info.x11.display; - pd.nwh = (void*)(uintptr_t)wmi.info.x11.window; -# elif BX_PLATFORM_OSX - pd.ndt = NULL; - pd.nwh = wmi.info.cocoa.window; -# elif BX_PLATFORM_WINDOWS - pd.ndt = NULL; - pd.nwh = wmi.info.win.window; -# elif BX_PLATFORM_STEAMLINK - pd.ndt = wmi.info.vivante.display; - pd.nwh = wmi.info.vivante.window; -# endif // BX_PLATFORM_ - pd.context = NULL; - pd.backBuffer = NULL; - pd.backBufferDS = NULL; - bgfx::setPlatformData(pd); - - return true; -} -#elif defined(OSD_UWP) -inline void winrtSetWindow(::IUnknown* _window) -{ - bgfx::PlatformData pd; - pd.ndt = NULL; - pd.nwh = _window; - pd.context = NULL; - pd.backBuffer = NULL; - pd.backBufferDS = NULL; - bgfx::setPlatformData(pd); -} - -IInspectable* AsInspectable(Platform::Agile<Windows::UI::Core::CoreWindow> win) -{ - return reinterpret_cast<IInspectable*>(win.Get()); -} -#endif - int renderer_bgfx::create() { - // create renderer - std::shared_ptr<osd_window> win = assert_window(); - osd_dim wdim = win->get_size(); - m_width[win->m_index] = wdim.width(); - m_height[win->m_index] = wdim.height(); - if (win->m_index == 0) - { - if (!s_window_set) - { - s_window_set = true; - ScreenVertex::init(); - } - else - { - bgfx::shutdown(); - bgfx::PlatformData blank_pd; - memset(&blank_pd, 0, sizeof(bgfx::PlatformData)); - bgfx::setPlatformData(blank_pd); - } -#ifdef OSD_WINDOWS - winSetHwnd(std::static_pointer_cast<win_window_info>(win)->platform_window()); -#elif defined(OSD_UWP) + const osd_dim wdim = window().get_size(); + s_width[window().index()] = wdim.width(); + s_height[window().index()] = wdim.height(); + m_dimensions = wdim; - winrtSetWindow(AsInspectable(std::static_pointer_cast<uwp_window_info>(win)->platform_window())); -#elif defined(OSD_MAC) - macSetWindow(std::static_pointer_cast<mac_window_info>(win)->platform_window()); -#else - sdlSetWindow(std::dynamic_pointer_cast<sdl_window_info>(win)->platform_window()); -#endif - std::string backend(m_options.bgfx_backend()); - bgfx::Init init; - init.type = bgfx::RendererType::Count; - init.vendorId = BGFX_PCI_ID_NONE; - init.resolution.width = wdim.width(); - init.resolution.height = wdim.height(); - init.resolution.reset = BGFX_RESET_NONE; - if (backend == "auto") - { - } - else if (backend == "dx9" || backend == "d3d9") - { - init.type = bgfx::RendererType::Direct3D9; - } - else if (backend == "dx11" || backend == "d3d11") - { - init.type = bgfx::RendererType::Direct3D11; - } - else if (backend == "gles") - { - init.type = bgfx::RendererType::OpenGLES; - } - else if (backend == "glsl" || backend == "opengl") - { - init.type = bgfx::RendererType::OpenGL; - } - else if (backend == "metal") - { - init.type = bgfx::RendererType::Metal; - } - else - { - printf("Unknown backend type '%s', going with auto-detection\n", backend.c_str()); - } - bgfx::init(init); - bgfx::reset(m_width[win->m_index], m_height[win->m_index], video_config.waitvsync ? BGFX_RESET_VSYNC : BGFX_RESET_NONE); - // Enable debug text. - bgfx::setDebug(m_options.bgfx_debug() ? BGFX_DEBUG_STATS : BGFX_DEBUG_TEXT); - m_dimensions = osd_dim(m_width[0], m_height[0]); - } - - m_textures = new texture_manager(); - m_targets = new target_manager(*m_textures); - - m_shaders = new shader_manager(m_options); - m_effects = new effect_manager(m_options, *m_shaders); + // finish creating the renderer + m_textures = std::make_unique<texture_manager>(); + m_targets = std::make_unique<target_manager>(*m_textures); - if (win->m_index != 0) + if (window().index() != 0) { #ifdef OSD_WINDOWS - m_framebuffer = m_targets->create_backbuffer(std::static_pointer_cast<win_window_info>(win)->platform_window(), m_width[win->m_index], m_height[win->m_index]); -#elif defined(OSD_UWP) - m_framebuffer = m_targets->create_backbuffer(AsInspectable(std::static_pointer_cast<uwp_window_info>(win)->platform_window()), m_width[win->m_index], m_height[win->m_index]); + m_framebuffer = m_targets->create_backbuffer(dynamic_cast<win_window_info &>(window()).platform_window(), s_width[window().index()], s_height[window().index()]); #elif defined(OSD_MAC) - m_framebuffer = m_targets->create_backbuffer(GetOSWindow(std::static_pointer_cast<mac_window_info>(win)->platform_window()), m_width[win->m_index], m_height[win->m_index]); + m_framebuffer = m_targets->create_backbuffer(GetOSWindow(dynamic_cast<mac_window_info &>(window()).platform_window()), s_width[window().index()], s_height[window().index()]); #else - m_framebuffer = m_targets->create_backbuffer(sdlNativeWindowHandle(std::dynamic_pointer_cast<sdl_window_info>(win)->platform_window()), m_width[win->m_index], m_height[win->m_index]); + auto const [winhdl, success] = sdlNativeWindowHandle(dynamic_cast<sdl_window_info &>(window()).platform_window()); + if (!success) + { + m_targets.reset(); + m_textures.reset(); + return -1; + } + m_framebuffer = m_targets->create_backbuffer(winhdl, s_width[window().index()], s_height[window().index()]); #endif - bgfx::touch(win->m_index); + bgfx::touch(window().index()); - if (m_ortho_view) { + if (m_ortho_view) m_ortho_view->set_backbuffer(m_framebuffer); - } } - // Create program from shaders. - m_gui_effect[0] = m_effects->effect("gui_opaque"); - m_gui_effect[1] = m_effects->effect("gui_blend"); - m_gui_effect[2] = m_effects->effect("gui_multiply"); - m_gui_effect[3] = m_effects->effect("gui_add"); - - m_screen_effect[0] = m_effects->effect("screen_opaque"); - m_screen_effect[1] = m_effects->effect("screen_blend"); - m_screen_effect[2] = m_effects->effect("screen_multiply"); - m_screen_effect[3] = m_effects->effect("screen_add"); - - if ( m_gui_effect[0] == nullptr || m_gui_effect[1] == nullptr || m_gui_effect[2] == nullptr || m_gui_effect[3] == nullptr || - m_screen_effect[0] == nullptr || m_screen_effect[1] == nullptr || m_screen_effect[2] == nullptr || m_screen_effect[3] == nullptr) - { - fatalerror("BGFX: Unable to load required shaders. Please check and reinstall the %s folder\n", m_options.bgfx_path()); - } + m_shaders = std::make_unique<shader_manager>(); + m_effects = std::make_unique<effect_manager>(*m_shaders); - m_chains = new chain_manager(win->machine(), m_options, *m_textures, *m_targets, *m_effects, win->m_index, *this); + // Create program from shaders. + m_gui_effect[0] = m_effects->get_or_load_effect(m_module().options(), "gui_opaque"); + m_gui_effect[1] = m_effects->get_or_load_effect(m_module().options(), "gui_blend"); + m_gui_effect[2] = m_effects->get_or_load_effect(m_module().options(), "gui_multiply"); + m_gui_effect[3] = m_effects->get_or_load_effect(m_module().options(), "gui_add"); + + m_screen_effect[0] = m_effects->get_or_load_effect(m_module().options(), "screen_opaque"); + m_screen_effect[1] = m_effects->get_or_load_effect(m_module().options(), "screen_blend"); + m_screen_effect[2] = m_effects->get_or_load_effect(m_module().options(), "screen_multiply"); + m_screen_effect[3] = m_effects->get_or_load_effect(m_module().options(), "screen_add"); + + const uint32_t max_prescale_size = std::min(2u * std::max(wdim.width(), wdim.height()), m_module().max_texture_size()); + m_chains = std::make_unique<chain_manager>( + window().machine(), + m_module().options(), + *m_textures, + *m_targets, + *m_effects, + window().index(), + *this, + window().prescale(), + max_prescale_size); m_sliders_dirty = true; uint32_t flags = BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP | BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_MIP_POINT; - m_texture_cache = m_textures->create_texture("#cache", bgfx::TextureFormat::RGBA8, CACHE_SIZE, CACHE_SIZE, nullptr, flags); + m_texture_cache = m_textures->create_texture("#cache", bgfx::TextureFormat::BGRA8, CACHE_SIZE, 0, CACHE_SIZE, nullptr, flags); memset(m_white, 0xff, sizeof(uint32_t) * 16 * 16); m_texinfo.push_back(rectangle_packer::packable_rectangle(WHITE_HASH, PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32), 16, 16, 16, nullptr, m_white)); - imguiCreate(); - return 0; } + + //============================================================ // renderer_bgfx::record //============================================================ void renderer_bgfx::record() { - std::shared_ptr<osd_window> win = assert_window(); - - if (win->m_index > 0) - { + if (window().index() > 0) return; - } if (m_avi_writer == nullptr) { - m_avi_writer = new avi_write(win->machine(), m_width[0], m_height[0]); - m_avi_data = new uint8_t[m_width[0] * m_height[0] * 4]; - m_avi_bitmap.allocate(m_width[0], m_height[0]); + m_avi_writer = new avi_write(window().machine(), s_width[0], s_height[0]); + m_avi_data = new uint8_t[s_width[0] * s_height[0] * 4]; + m_avi_bitmap.allocate(s_width[0], s_height[0]); } if (m_avi_writer->recording()) @@ -387,9 +710,9 @@ void renderer_bgfx::record() } else { - m_avi_writer->record(m_options.bgfx_avi_name()); - m_avi_target = m_targets->create_target("avibuffer", bgfx::TextureFormat::RGBA8, m_width[0], m_height[0], TARGET_STYLE_CUSTOM, false, true, 1, 0); - m_avi_texture = bgfx::createTexture2D(m_width[0], m_height[0], false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_BLIT_DST | BGFX_TEXTURE_READ_BACK); + m_avi_writer->record(m_module().options().bgfx_avi_name()); + m_avi_target = m_targets->create_target("avibuffer", bgfx::TextureFormat::BGRA8, s_width[0], s_height[0], 1, 1, TARGET_STYLE_CUSTOM, false, true, 1, 0); + m_avi_texture = bgfx::createTexture2D(s_width[0], s_height[0], false, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_BLIT_DST | BGFX_TEXTURE_READ_BACK); if (m_avi_view == nullptr) { @@ -398,28 +721,6 @@ void renderer_bgfx::record() } } -bool renderer_bgfx::init(running_machine &machine) -{ - const char *bgfx_path = downcast<osd_options &>(machine.options()).bgfx_path(); - - osd::directory::ptr directory = osd::directory::open(bgfx_path); - if (directory == nullptr) - { - osd_printf_verbose("Unable to find the %s folder. Please reinstall it to use the BGFX renderer\n", bgfx_path); - return true; - } - - return false; -} - -void renderer_bgfx::exit() -{ - imguiDestroy(); - - bgfx::shutdown(); - s_window_set = false; -} - //============================================================ // drawsdl_xy_to_render_target //============================================================ @@ -441,12 +742,12 @@ int renderer_bgfx::xy_to_render_target(int x, int y, int *xt, int *yt) // drawbgfx_window_draw //============================================================ -bgfx::VertexDecl ScreenVertex::ms_decl; +bgfx::VertexLayout ScreenVertex::ms_decl; void renderer_bgfx::put_packed_quad(render_primitive *prim, uint32_t hash, ScreenVertex* vertices) { rectangle_packer::packed_rectangle& rect = m_hash_to_entry[hash]; - float size = float(CACHE_SIZE); + auto size = float(CACHE_SIZE); float u0 = (float(rect.x()) + 0.5f) / size; float v0 = (float(rect.y()) + 0.5f) / size; float u1 = u0 + (float(rect.width()) - 1.0f) / size; @@ -498,9 +799,9 @@ void renderer_bgfx::vertex(ScreenVertex* vertex, float x, float y, float z, uint vertex->m_v = v; } -void renderer_bgfx::render_post_screen_quad(int view, render_primitive* prim, bgfx::TransientVertexBuffer* buffer, int32_t screen) +void renderer_bgfx::render_post_screen_quad(int view, render_primitive* prim, bgfx::TransientVertexBuffer* buffer, int32_t screen, int window_index) { - ScreenVertex* vertices = reinterpret_cast<ScreenVertex*>(buffer->data); + auto* vertices = reinterpret_cast<ScreenVertex*>(buffer->data); float x[4] = { prim->bounds.x0, prim->bounds.x1, prim->bounds.x0, prim->bounds.x1 }; float y[4] = { prim->bounds.y0, prim->bounds.y0, prim->bounds.y1, prim->bounds.y1 }; @@ -514,15 +815,24 @@ void renderer_bgfx::render_post_screen_quad(int view, render_primitive* prim, bg vertex(&vertices[4], x[2], y[2], 0, 0xffffffff, u[2], v[2]); vertex(&vertices[5], x[0], y[0], 0, 0xffffffff, u[0], v[0]); - uint32_t texture_flags = BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP; + uint32_t texture_flags = 0U; + if (!PRIMFLAG_GET_TEXWRAP(prim->flags)) + texture_flags |= BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP; if (video_config.filter == 0) - { texture_flags |= BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_MIP_POINT; - } uint32_t blend = PRIMFLAG_GET_BLENDMODE(prim->flags); bgfx::setVertexBuffer(0,buffer); bgfx::setTexture(0, m_screen_effect[blend]->uniform("s_tex")->handle(), m_targets->target(screen, "output")->texture(), texture_flags); + + bgfx_uniform* inv_view_dims = m_screen_effect[blend]->uniform("u_inv_view_dims"); + if (inv_view_dims) + { + float values[2] = { -1.0f / s_width[window_index], 1.0f / s_height[window_index] }; + inv_view_dims->set(values, sizeof(float) * 2); + inv_view_dims->upload(); + } + m_screen_effect[blend]->submit(m_ortho_view->get_index()); } @@ -531,15 +841,15 @@ void renderer_bgfx::render_avi_quad() m_avi_view->set_index(s_current_view); m_avi_view->setup(); - bgfx::setViewRect(s_current_view, 0, 0, m_width[0], m_height[0]); - bgfx::setViewClear(s_current_view, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x00000000, 1.0f, 0); + bgfx::setViewRect(s_current_view, 0, 0, s_width[0], s_height[0]); + bgfx::setViewClear(s_current_view, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x000000ff, 1.0f, 0); bgfx::TransientVertexBuffer buffer; bgfx::allocTransientVertexBuffer(&buffer, 6, ScreenVertex::ms_decl); - ScreenVertex* vertices = reinterpret_cast<ScreenVertex*>(buffer.data); + auto* vertices = reinterpret_cast<ScreenVertex*>(buffer.data); - float x[4] = { 0.0f, float(m_width[0]), 0.0f, float(m_width[0]) }; - float y[4] = { 0.0f, 0.0f, float(m_height[0]), float(m_height[0]) }; + float x[4] = { 0.0f, float(s_width[0]), 0.0f, float(s_width[0]) }; + float y[4] = { 0.0f, 0.0f, float(s_height[0]), float(s_height[0]) }; float u[4] = { 0.0f, 1.0f, 0.0f, 1.0f }; float v[4] = { 0.0f, 0.0f, 1.0f, 1.0f }; uint32_t rgba = 0xffffffff; @@ -553,13 +863,23 @@ void renderer_bgfx::render_avi_quad() bgfx::setVertexBuffer(0,&buffer); bgfx::setTexture(0, m_gui_effect[PRIMFLAG_GET_BLENDMODE(BLENDMODE_NONE)]->uniform("s_tex")->handle(), m_avi_target->texture()); - m_gui_effect[PRIMFLAG_GET_BLENDMODE(BLENDMODE_NONE)]->submit(s_current_view); + + bgfx_effect* effect = m_gui_effect[PRIMFLAG_GET_BLENDMODE(BLENDMODE_NONE)]; + bgfx_uniform* inv_view_dims = effect->uniform("u_inv_view_dims"); + if (inv_view_dims) + { + float values[2] = { -1.0f / s_width[0], 1.0f / s_height[0] }; + inv_view_dims->set(values, sizeof(float) * 2); + inv_view_dims->upload(); + } + + effect->submit(s_current_view); s_current_view++; } -void renderer_bgfx::render_textured_quad(render_primitive* prim, bgfx::TransientVertexBuffer* buffer) +void renderer_bgfx::render_textured_quad(render_primitive* prim, bgfx::TransientVertexBuffer* buffer, int window_index) { - ScreenVertex* vertices = reinterpret_cast<ScreenVertex*>(buffer->data); + auto* vertices = reinterpret_cast<ScreenVertex*>(buffer->data); uint32_t rgba = u32Color(prim->color.r * 255, prim->color.g * 255, prim->color.b * 255, prim->color.a * 255); float x[4] = { prim->bounds.x0, prim->bounds.x1, prim->bounds.x0, prim->bounds.x1 }; @@ -574,25 +894,50 @@ void renderer_bgfx::render_textured_quad(render_primitive* prim, bgfx::Transient vertex(&vertices[4], x[2], y[2], 0, rgba, u[2], v[2]); vertex(&vertices[5], x[0], y[0], 0, rgba, u[0], v[0]); - uint32_t texture_flags = BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP; - if (video_config.filter == 0) - { + uint32_t texture_flags = 0U; + if (!PRIMFLAG_GET_TEXWRAP(prim->flags)) + texture_flags |= BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP; + if (!PRIMFLAG_GET_ANTIALIAS(prim->flags)) texture_flags |= BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_MIP_POINT; - } + const bool is_screen = PRIMFLAG_GET_SCREENTEX(prim->flags); uint16_t tex_width(prim->texture.width); uint16_t tex_height(prim->texture.height); - bgfx::TextureHandle texture = m_textures->create_or_update_mame_texture(prim->flags & PRIMFLAG_TEXFORMAT_MASK - , tex_width, tex_height, prim->texture.rowpixels, prim->texture.palette, prim->texture.base, prim->texture.seqid - , texture_flags, prim->texture.unique_id, prim->texture.old_id); + bgfx::TextureHandle texture = BGFX_INVALID_HANDLE; + if (is_screen) + { + const bgfx::Memory* mem = bgfx_util::mame_texture_data_to_bgra32(prim->flags & PRIMFLAG_TEXFORMAT_MASK + , tex_width, tex_height, prim->texture.rowpixels, prim->texture.palette, prim->texture.base); + texture = bgfx::createTexture2D(tex_width, tex_height, false, 1, bgfx::TextureFormat::BGRA8, texture_flags, mem); + } + else + { + texture = m_textures->create_or_update_mame_texture(prim->flags & PRIMFLAG_TEXFORMAT_MASK + , tex_width, prim->texture.width_margin, tex_height, prim->texture.rowpixels, prim->texture.palette, prim->texture.base, prim->texture.seqid + , texture_flags, prim->texture.unique_id, prim->texture.old_id); + } - bgfx_effect** effects = PRIMFLAG_GET_SCREENTEX(prim->flags) ? m_screen_effect : m_gui_effect; + bgfx_effect** effects = is_screen ? m_screen_effect : m_gui_effect; uint32_t blend = PRIMFLAG_GET_BLENDMODE(prim->flags); bgfx::setVertexBuffer(0,buffer); bgfx::setTexture(0, effects[blend]->uniform("s_tex")->handle(), texture); + + bgfx_uniform* inv_view_dims = effects[blend]->uniform("u_inv_view_dims"); + if (inv_view_dims) + { + float values[2] = { -1.0f / s_width[window_index], 1.0f / s_height[window_index] }; + inv_view_dims->set(values, sizeof(float) * 2); + inv_view_dims->upload(); + } + effects[blend]->submit(m_ortho_view->get_index()); + + if (is_screen) + { + bgfx::destroy(texture); + } } #define MAX_TEMP_COORDS 100 @@ -805,18 +1150,15 @@ uint32_t renderer_bgfx::u32Color(uint32_t r, uint32_t g, uint32_t b, uint32_t a int renderer_bgfx::draw(int update) { - std::shared_ptr<osd_window> win = assert_window(); - - int window_index = win->m_index; + int window_index = window().index(); m_seen_views.clear(); - if (m_ortho_view) { + if (m_ortho_view) m_ortho_view->set_index(UINT_MAX); - } - osd_dim wdim = win->get_size(); - m_width[window_index] = wdim.width(); - m_height[window_index] = wdim.height(); + osd_dim wdim = window().get_size(); + s_width[window_index] = wdim.width(); + s_height[window_index] = wdim.height(); // Set view 0 default viewport. if (window_index == 0) @@ -824,9 +1166,9 @@ int renderer_bgfx::draw(int update) s_current_view = 0; } - win->m_primlist->acquire_lock(); - s_current_view += m_chains->handle_screen_chains(s_current_view, win->m_primlist->first(), *win.get()); - win->m_primlist->release_lock(); + window().m_primlist->acquire_lock(); + uint32_t num_screens = m_chains->update_screen_textures(s_current_view, window().m_primlist->first(), window()); + window().m_primlist->release_lock(); bool skip_frame = update_dimensions(); if (skip_frame) @@ -834,6 +1176,26 @@ int renderer_bgfx::draw(int update) return 0; } + if (num_screens) + { + // Restore config after counting screens the first time + // Doing this here is hacky - it means config is restored at the wrong + // time if the initial view has no screens and the user switches to a + // view with screens. The trouble is there's no real interface between + // the render targets and the renderer so we don't actually know when + // we're first called on to render a live view (as opposed to an info + // screen). + if (m_config) + { + osd_printf_verbose("BGFX: Applying configuration for window %d\n", window().index()); + m_chains->load_config(*m_config->get_first_child()); + m_config.reset(); + } + + uint32_t chain_view_count = m_chains->process_screen_chains(s_current_view, window()); + s_current_view += chain_view_count; + } + if (s_current_view > m_max_view) { m_max_view = s_current_view; @@ -843,12 +1205,12 @@ int renderer_bgfx::draw(int update) s_current_view = m_max_view; } - win->m_primlist->acquire_lock(); + window().m_primlist->acquire_lock(); // Mark our texture atlas as dirty if we need to do so bool atlas_valid = update_atlas(); - render_primitive *prim = win->m_primlist->first(); + render_primitive *prim = window().m_primlist->first(); std::vector<void*> sources; while (prim != nullptr) { @@ -873,12 +1235,21 @@ int renderer_bgfx::draw(int update) } } - buffer_status status = buffer_primitives(atlas_valid, &prim, &buffer, screen); + buffer_status status = buffer_primitives(atlas_valid, &prim, &buffer, screen, window_index); if (status != BUFFER_EMPTY && status != BUFFER_SCREEN) { - bgfx::setVertexBuffer(0,&buffer); + bgfx::setVertexBuffer(0, &buffer); bgfx::setTexture(0, m_gui_effect[blend]->uniform("s_tex")->handle(), m_texture_cache->texture()); + + bgfx_uniform* inv_view_dims = m_gui_effect[blend]->uniform("u_inv_view_dims"); + if (inv_view_dims) + { + float values[2] = { -1.0f / s_width[window_index], 1.0f / s_height[window_index] }; + inv_view_dims->set(values, sizeof(float) * 2); + inv_view_dims->upload(); + } + m_gui_effect[blend]->submit(m_ortho_view->get_index()); } @@ -888,11 +1259,11 @@ int renderer_bgfx::draw(int update) } } - win->m_primlist->release_lock(); + window().m_primlist->release_lock(); // This dummy draw call is here to make sure that view 0 is cleared // if no other draw calls are submitted to view 0. - bgfx::touch(s_current_view > 0 ? s_current_view - 1 : 0); + //bgfx::touch(s_current_view > 0 ? s_current_view - 1 : 0); // Advance to next frame. Rendering thread will be kicked to // process submitted rendering primitives. @@ -904,7 +1275,10 @@ int renderer_bgfx::draw(int update) bgfx::touch(s_current_view); update_recording(); } + } + if (window().index() == osd_common_t::window_list().size() - 1) + { bgfx::frame(); } @@ -919,7 +1293,7 @@ void renderer_bgfx::update_recording() int i = 0; for (int y = 0; y < m_avi_bitmap.height(); y++) { - uint32_t *dst = &m_avi_bitmap.pix32(y); + uint32_t *dst = &m_avi_bitmap.pix(y); for (int x = 0; x < m_avi_bitmap.width(); x++) { @@ -933,8 +1307,7 @@ void renderer_bgfx::update_recording() void renderer_bgfx::add_audio_to_recording(const int16_t *buffer, int samples_this_frame) { - std::shared_ptr<osd_window> win = assert_window(); - if (m_avi_writer != nullptr && m_avi_writer->recording() && win->m_index == 0) + if (m_avi_writer != nullptr && m_avi_writer->recording() && window().index() == 0) { m_avi_writer->audio_frame(buffer, samples_this_frame); } @@ -942,47 +1315,36 @@ void renderer_bgfx::add_audio_to_recording(const int16_t *buffer, int samples_th bool renderer_bgfx::update_dimensions() { - std::shared_ptr<osd_window> win = assert_window(); - - const uint32_t window_index = win->m_index; - const uint32_t width = m_width[window_index]; - const uint32_t height = m_height[window_index]; + const uint32_t window_index = window().index(); + const uint32_t width = s_width[window_index]; + const uint32_t height = s_height[window_index]; - if (window_index == 0) + if (m_dimensions != osd_dim(width, height)) { - if ((m_dimensions != osd_dim(width, height))) - { - bgfx::reset(width, height, video_config.waitvsync ? BGFX_RESET_VSYNC : BGFX_RESET_NONE); - m_dimensions = osd_dim(width, height); - } - } - else - { - if ((m_dimensions != osd_dim(width, height))) - { - bgfx::reset(win->main_window()->get_size().width(), win->main_window()->get_size().height(), video_config.waitvsync ? BGFX_RESET_VSYNC : BGFX_RESET_NONE); - m_dimensions = osd_dim(width, height); + bgfx::reset(width, height, video_config.waitvsync ? BGFX_RESET_VSYNC : BGFX_RESET_NONE); + m_dimensions = osd_dim(width, height); - delete m_framebuffer; + if (window().index() != 0) + { #ifdef OSD_WINDOWS - m_framebuffer = m_targets->create_backbuffer(std::static_pointer_cast<win_window_info>(win)->platform_window(), width, height); -#elif defined(OSD_UWP) - m_framebuffer = m_targets->create_backbuffer(AsInspectable(std::static_pointer_cast<uwp_window_info>(win)->platform_window()), width, height); + m_framebuffer = m_targets->create_backbuffer(dynamic_cast<win_window_info &>(window()).platform_window(), width, height); #elif defined(OSD_MAC) - m_framebuffer = m_targets->create_backbuffer(GetOSWindow(std::static_pointer_cast<mac_window_info>(win)->platform_window()), width, height); + m_framebuffer = m_targets->create_backbuffer(GetOSWindow(dynamic_cast<mac_window_info &>(window()).platform_window()), width, height); #else - m_framebuffer = m_targets->create_backbuffer(sdlNativeWindowHandle(std::dynamic_pointer_cast<sdl_window_info>(win)->platform_window()), width, height); + m_framebuffer = m_targets->create_backbuffer(sdlNativeWindowHandle(dynamic_cast<sdl_window_info &>(window()).platform_window()).first, width, height); #endif if (m_ortho_view) + { m_ortho_view->set_backbuffer(m_framebuffer); - + } bgfx::setViewFrameBuffer(s_current_view, m_framebuffer->target()); - bgfx::setViewClear(s_current_view, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x00000000, 1.0f, 0); - bgfx::setViewMode(s_current_view, bgfx::ViewMode::Sequential); - bgfx::touch(s_current_view); - bgfx::frame(); - return true; } + + bgfx::setViewClear(s_current_view, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x000000ff, 1.0f, 0); + bgfx::setViewMode(s_current_view, bgfx::ViewMode::Sequential); + bgfx::touch(s_current_view); + bgfx::frame(); + return true; } return false; } @@ -991,17 +1353,38 @@ void renderer_bgfx::setup_ortho_view() { if (!m_ortho_view) { - m_ortho_view = new bgfx_ortho_view(this, s_current_view, m_framebuffer, m_seen_views); + m_ortho_view = std::make_unique<bgfx_ortho_view>(this, 0, m_framebuffer, m_seen_views); } - m_ortho_view->update(); - if (m_ortho_view->get_index() == UINT_MAX) { + if (m_ortho_view->get_index() == UINT_MAX) + { m_ortho_view->set_index(s_current_view); m_ortho_view->setup(); s_current_view++; } + m_ortho_view->update(); } -renderer_bgfx::buffer_status renderer_bgfx::buffer_primitives(bool atlas_valid, render_primitive** prim, bgfx::TransientVertexBuffer* buffer, int32_t screen) +render_primitive_list *renderer_bgfx::get_primitives() +{ + // determines whether the screen container is transformed by the chain's shaders + bool chain_transform = false; + + // check the first chain + bgfx_chain* chain = this->m_chains->screen_chain(0); + if (chain != nullptr) + { + chain_transform = chain->transform(); + } + + osd_dim wdim = window().get_size(); + if (wdim.width() > 0 && wdim.height() > 0) + window().target()->set_bounds(wdim.width(), wdim.height(), window().pixel_aspect()); + + window().target()->set_transform_container(!chain_transform); + return &window().target()->get_primitives(); +} + +renderer_bgfx::buffer_status renderer_bgfx::buffer_primitives(bool atlas_valid, render_primitive** prim, bgfx::TransientVertexBuffer* buffer, int32_t screen, int window_index) { int vertices = 0; @@ -1043,18 +1426,18 @@ renderer_bgfx::buffer_status renderer_bgfx::buffer_primitives(bool atlas_valid, { #if SCENE_VIEW setup_view(s_current_view, true); - render_post_screen_quad(s_current_view, *prim, buffer, screen); + render_post_screen_quad(s_current_view, *prim, buffer, screen, window_index); s_current_view++; #else setup_ortho_view(); - render_post_screen_quad(m_ortho_view->get_index(), *prim, buffer, screen); + render_post_screen_quad(m_ortho_view->get_index(), *prim, buffer, screen, window_index); #endif return BUFFER_SCREEN; } else { setup_ortho_view(); - render_textured_quad(*prim, buffer); + render_textured_quad(*prim, buffer, window_index); return BUFFER_EMPTY; } } @@ -1131,8 +1514,12 @@ void renderer_bgfx::process_atlas_packs(std::vector<std::vector<rectangle_packer continue; } m_hash_to_entry[rect.hash()] = rect; - const bgfx::Memory* mem = bgfx_util::mame_texture_data_to_bgfx_texture_data(rect.format(), rect.width(), rect.height(), rect.rowpixels(), rect.palette(), rect.base()); - bgfx::updateTexture2D(m_texture_cache->texture(), 0, 0, rect.x(), rect.y(), rect.width(), rect.height(), mem); + bgfx::TextureFormat::Enum dst_format = bgfx::TextureFormat::BGRA8; + uint16_t pitch = rect.width(); + 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, rect.format(), rect.rowpixels(), 0, rect.height(), rect.palette(), rect.base(), pitch, width_div_factor, width_mul_factor); + bgfx::updateTexture2D(m_texture_cache->texture(), 0, 0, rect.x(), rect.y(), (rect.width() * width_mul_factor) / width_div_factor, rect.height(), mem, pitch); } } } @@ -1160,7 +1547,8 @@ uint32_t renderer_bgfx::get_texture_hash(render_primitive *prim) } return hash; #else - return (reinterpret_cast<size_t>(prim->texture.base)) & 0xffffffff; + //return (reinterpret_cast<size_t>(prim->texture.base)) & 0xffffffff; + return (reinterpret_cast<size_t>(prim->texture.base) ^ reinterpret_cast<size_t>(prim->texture.palette)) & 0xffffffff; #endif } @@ -1168,9 +1556,8 @@ bool renderer_bgfx::check_for_dirty_atlas() { bool atlas_dirty = false; - std::shared_ptr<osd_window> win = assert_window(); std::map<uint32_t, rectangle_packer::packable_rectangle> acquired_infos; - for (render_primitive &prim : *win->m_primlist) + for (render_primitive &prim : *window().m_primlist) { bool pack = prim.packable(PACKABLE_SIZE); if (prim.type == render_primitive::QUAD && prim.texture.base != nullptr && pack) @@ -1183,8 +1570,7 @@ bool renderer_bgfx::check_for_dirty_atlas() atlas_dirty = true; m_texinfo.push_back(rectangle_packer::packable_rectangle(hash, prim.flags & PRIMFLAG_TEXFORMAT_MASK, - prim.texture.width, prim.texture.height, - prim.texture.rowpixels, prim.texture.palette, prim.texture.base)); + prim.texture.width, prim.texture.height, prim.texture.rowpixels, prim.texture.palette, prim.texture.base)); acquired_infos[hash] = m_texinfo[m_texinfo.size() - 1]; } } @@ -1261,11 +1647,44 @@ void renderer_bgfx::set_sliders_dirty() m_sliders_dirty = true; } -uint32_t renderer_bgfx::get_window_width(uint32_t index) const { - return m_width[index]; +uint32_t renderer_bgfx::get_window_width(uint32_t index) const +{ + return s_width[index]; +} + +uint32_t renderer_bgfx::get_window_height(uint32_t index) const +{ + return s_height[index]; } -uint32_t renderer_bgfx::get_window_height(uint32_t index) const { - return m_height[index]; + +void renderer_bgfx::load_config(util::xml::data_node const &parentnode) +{ + util::xml::data_node const *windownode = parentnode.get_child("window"); + while (windownode) + { + if (windownode->get_attribute_int("index", -1) != window().index()) + { + windownode = windownode->get_next_sibling("window"); + continue; + } + + if (!m_config) + m_config = util::xml::file::create(); + else + m_config->get_first_child()->delete_node(); + windownode->copy_into(*m_config); + m_config->get_first_child()->set_attribute("persist", "0"); + osd_printf_verbose("BGFX: Found configuration for window %d\n", window().index()); + break; + } } + +void renderer_bgfx::save_config(util::xml::data_node &parentnode) +{ + if (m_config) + m_config->get_first_child()->copy_into(parentnode); + else + m_chains->save_config(parentnode); +} |