Main Restorations Software Audio/Jukebox/MP3 Everything Else Buy/Sell/Trade
Project Announcements Monitor/Video GroovyMAME Merit/JVL Touchscreen Meet Up Retail Vendors
Driving & Racing Woodworking Software Support Forums Consoles Project Arcade Reviews
Automated Projects Artwork Frontend Support Forums Pinball Forum Discussion Old Boards
Raspberry Pi & Dev Board controls.dat Linux Miscellaneous Arcade Wiki Discussion Old Archives
Lightguns Arcade1Up Try the site in https mode Site News

Unread posts | New Replies | Recent posts | Rules | Chatroom | Wiki | File Repository | RSS | Submit news

  

Author Topic: CRT-LCD MAME V1.3 (new ultra-optimized version currently under development)  (Read 894 times)

0 Members and 1 Guest are viewing this topic.

Olivcade

  • Trade Count: (0)
  • Jr. Member
  • **
  • Offline Offline
  • Posts: 9
  • Last login:Today at 02:56:58 am
  • I want to build my own arcade controls!
Hello TEAM :-)

I'm offering you a new version of MAME currently under development:

README – CRT-MAME 0.168 V1.3

Binary files and source code available here on GitHub:

https://github.com/HardCade/hardcade/releases

Development Version – December 2025
© 2025 Hardcade – PlayRetro

===========================================================================================
PROJECT: CRT-MAME 0.168 Edition

CRT-MAME 0.168 is a specialized version of MAME 0.168 optimized for: 15 kHz CRT monitors (arcade, TV, PVM/BVM, Hantarex, Nanao, etc.) and LCD

monitors

Minimal input lag,

advanced and precise refresh rate control per game.

Objectives:

    - Achieve minimal input lag
    - Achieve increased display performance and superior behavior (compared to existing emulators) for 15 kHz CRTs.
    - Achieve ultra-smooth display and optimal performance on LCD screens.

===============================================
CURRENT MAIN FEATURES (subject to change)
==============================================


- Saving the Refresh Rate slider to CFG files

- Improved slider (precision, stability, rounding, defect handling)

- Added Windows input timestamp (anti-lag preparation)

- Added Late Input Polling (reduces input lag by a full frame)

- Added Direct3D optimization – "Direct Present Minimal" (reduces display lag)

- Added Adaptive HardSync (stabilizes frame timing and prevents stuttering, reduces overall latency)

More features and improvements are coming soon...


===========================================================
LIST OF MODIFIED FILES
=============================================================================

src/emu/screen.cpp
src/emu/screen.h
src/emu/ui/ui.cpp
src/emu/video.cpp src/
osd/windows/input.cpp src/osd/ui/ui.cpp
src/emu/video.cpp src/osd/windows/input.cpp
src/osd/modules/render/d3d/d3d9intf.cpp


=============================================================
CRT-MAME 0.168 — V1.3
Change Notes
==================================================================
1) SLIDER REFRESH RATE CFG — Initial Save (V1)

Functionality:
Automatic saving and reloading of the user's frequency in:
cfg/[game_name].cfg

Modified files:

src/emu/video.cpp → config_save_screen_refresh() / config_load_screen_refresh()

-------------------------------------------------------------------------------------------------------------------------------

2) SLIDER REFRESH RATE — Improvements (V2)

Improvements:

Slider in the TAB menu is functional and stable.

Rounded to 3 decimal places for exact consistency.

Saved only if there is a real difference.

Added original frequency for proper comparison.

Immediate application of the new frequency.

Modified files:

src/emu/ui/ui.cpp — slider_refresh()

src/emu/screen.h — m_user_refresh_rate, setters/getters, default value

src/emu/screen.cpp — initialization default refresh

src/emu/video.cpp — V2 CFG load/save


NEW FUNCTION ADDED in src/emu/video.cpp:

//-------------------------------------------------
// HARDCADE config_load_screen_refresh - load screen refresh rates EDIT
//---------------------------------------

static void config_load_screen_refresh(running_machine &machine, int cfg_type, xml_data_node *parentnode)
{
    // only load game configurations
    if (cfg_type != CONFIG_TYPE_GAME || parentnode == NULL)
        return;

    // iterate over screen nodes
    for (xml_data_node *screennode = xml_get_sibling(parentnode->child, "screen");
        screennode != NULL;
        screennode = xml_get_sibling(screennode->next, "screen"))
    {
        // get the screen tag
        const char *screen_tag = xml_get_attribute_string(screennode, "tag", "");
        if (screen_tag
== 0)
            continues; continues;
       
        // find the matching screen device
        screen_device_iterator iter(machine.root_device());
        for (screen_device *screen = iter.first(); screen != NULL; screen = iter.next ())
        {
            if (strcmp(screen->tag(), screen_tag) == 0)
            {
                // load and apply the refresh rate
                double refresh = xml_get_attribute_float(screennode, "refresh", 0.0);
                if (refresh > 0.0)
                {
                    // store the user refresh rate
                    screen->set_user_refresh_rate(refresh);
                   
                    // apply it immediately
                    int width = screen->width();
                    int height = screen->height();
                    const rectangle &visarea = screen->visible_area();
                    screen->configure(width, height, visaarea, HZ_TO_ATTOSECONDS(refresh));
                }
                break;
            } }
        }
    }
//

------------------------------------------------
// HARDCADE config_save_screen_refresh - save screen refresh rates
//------------------------------------------------

static void config_save_screen_refresh(running_machine &machine, int cfg_type, xml_data_node *parentnode)
{
    // only save game configurations
    if (cfg_type != CONFIG_TYPE_GAME || parentnode == NULL)
        return;

    // iterate over all screens
    screen_device_iterator iter(machine.root_device());
    for (screen_device *screen = iter.first(); screen != NULL; screen = iter.next ())
    {
        // only save if user has set a custom refresh rate
        double refresh = screen->user_refresh_rate();
        if (refresh > 0.0)
        {
            // create a screen node
            xml_data_node *screennode = xml_add_child(parentnode, "screen", NULL);
            if (screennode != NULL)
            {
                xml_set_attribute(screennode, "tag", screen->tag());
                xml_set_attribute_float(screennode, "refresh", refresh);
            }
        }
    }
}


FUNCTION MODIFIED IN in src/emu/ui/ui.cpp:

//-------------------------------------------------
// HARDCADE slider_refresh - refresh rate slider callback
//-------------------------------------------------

static INT32 slider_refresh(running_machine &machine, void *arg, std::string *str, INT32 newval)
{
    screen_device *screen = reinterpret_cast<screen_device *>(arg);
    double defrefresh = screen->default_refresh_rate();
    double refresh;

    if (newval != SLIDER_NOCHANGE)
    {
        int width = screen->width();
        int height = screen->height();
        const rectangle &visarea = screen->visible_area();
       
        // new raw value
        double new_refresh = defrefresh + (double)newval * 0.001;
       
        // APPLY the value (imprecise, that's normal)
        screen->configure(width, height, visarea, HZ_TO_ATTOSECONDS(new_refresh));

        // ROUNDED for display and saving
        double rounded_new = floor(new_refresh * 1000.0 + 0.5) / 1000.0;
        double rounded_default = floor(defrefresh * 1000.0 + 0.5) / 1000.0;

        // SAVE only the rounded value
        if (rounded_new != rounded_default)
            screen->set_user_refresh_rate(rounded_new); // <-- CORRECT !
        else
            screen->set_user_refresh_rate(0.0);
    }

    if (str != NULL)
        strprintf(*str, "%.3ffps", ATTOSECONDS_TO_HZ(screen->frame_period().attoseconds()));

    refresh = ATTOSECONDS_TO_HZ(screen->frame_period().attoseconds());
    return floor((refresh - defrefresh) * 1000.0 + 0.5);
}

-------------------------------------------------------------------------------------------------------------------------------


3) INPUT LAG — Windows Timestamp (V3)

Objective: To capture the exact moment an input is updated.

Functionality:
Added a high-precision timestamp during updates:

Win32 keyboard,

RawInput,

DirectInput (older USB + HID joysticks).

Modified files:

src/osd/windows/input.cpp

, added UINT64 last_timestamp to class device_info,

added devinfo->last_timestamp = osd_ticks(); to:

win32_keyboard_poll(),

rawinput_keyboard_update()

, dinput_joystick_poll().

-------------------------------------------------------------------------------------------------------------------------------

4) INPUT LAG — Late Input Polling (V3b)

Major new feature: Added Late Input Polling (LIP), reducing input lag by 1 frame.

  - Device polling moved to just before input processing
  - Reduces input lag by a full frame
  - Added function: late_input_poll()
  - Integrated into windows_osd_interface::update()


Principle:
Force ultra-late device polling just before Windows processes the frame's messages → fresher input = 1 frame saved.

Additions:

a) New function

src/osd/windows/input.cpp:

void late_input_poll(running_machine &machine)
{
    osd_lock_acquire(input_lock);

    if (keyboard_list) device_list_poll_devices(keyboard_list);
    if (mouse_list) device_list_poll_devices(mouse_list);
    if (lightgun_list) device_list_poll_devices(lightgun_list);
    if (joystick_list) device_list_poll_devices(joystick_list);

    last_poll = GetTickCount();

    osd_lock_release(input_lock);
}

b) Call in the Windows loop (critical)

In src/osd/windows/video.cpp, function:

    Insertion of late_input_poll(machine()) into windows_osd_interface::update()
    Addition of extern void late_input_poll(running_machine &machine);

-------------------------------------------------------------------------------------------------------------------------------

5) Direct3D Optimization – "Direct Present Minimal"

A GPU optimization inspired by GroovyMAME allowing a reduction in display lag.

- Added features:

Immediate image presentation via SwapChain->Present()

Bypass of Direct3D internal buffering

Reduced GPU lag by approximately 1 frame

Compatible with Windows XP / Direct3D 9

Safe fallback if the option is not supported by the driver

- Modified files:

src/osd/modules/render/d3d/d3d9intf.cpp

- Complete replacement of the function:

device_present()

// HARDCADE MODIFICATION Direct Present Minimal //////////////////////////////////////
static HRESULT device_present(device *dev, const RECT *source, const RECT *dest, HWND override, RGNDATA *dirty, DWORD flags)
{
    IDirect3DDevice9 *device = (IDirect3DDevice9 *)dev;

    // If flags are provided, prefer presenting via the swapchain with those flags
    if (flags != 0)
    {
        IDirect3DSwapChain9 *chain = NULL;
        HRESULT result = IDirect3DDevice9_GetSwapChain(device, 0, &chain);
        if (result == D3D_OK && chain != NULL)
        {
            result = IDirect3DSwapChain9_Present(chain, source, dest, override, dirty, flags);
            IDirect3DSwapChain9_Release(chain);
            return result;
        }
    }

    // Attempt to present via the swapchain with FORCEIMMEDIATE if available.
    // This is preferred because IDirect3DDevice9::Present() has no flags parameter.
    IDirect3DSwapChain9 *chain = NULL;
    HRESULT r = IDirect3DDevice9_GetSwapChain(device, 0, &chain);
    if (r == D3D_OK && chain != NULL)
    {
#ifdef D3DPRESENT_FORCEIMMEDIATE
        HRESULT pres = IDirect3DSwapChain9_Present(chain, source, dest, override, dirty, D3DPRESENT_FORCEIMMEDIATE);
#else
        // Fall back to zero flags if FORCEIMMEDIATE is not defined
        HRESULT pres = IDirect3DSwapChain9_Present(chain, source, dest, override, dirty, 0);
#endif
        IDirect3DSwapChain9_Release(chain);
        return pres;
    }

    // Last-resort fallback: call device Present (no flags)
    return IDirect3DDevice9_Present(device, source, dest, override, dirty);
}

// HARDCADE Direct Present Minimal ////////////////////////////////////


- Quick Description

The patch forces Direct3D to present the image as soon as possible, without going through the usual GPU queue.
Result: more direct display, image closer to real-time timing, better responsiveness at 15 kHz and LCD.

- Interaction with other optimizations

This optimization is in addition to:

Custom refresh rate saving

Late Input Polling

DirectInput / RawInput system improvements

No known incompatibilities.

Recommended INI configuration to benefit from the GPU improvement:

-video d3d
-waitvsync 0

-------------------------------------------------------------------------------------------------------------------------------

6) HARDCADE CRT-MAME — Adaptive HardSync

Adds a lightweight CPU synchronization system before video rendering, compatible with Windows XP and lower-end systems.

Effect:

Reduces micro-stuttering

Avoids premature Present() calls

No CPU load (Sleep(0))

Works with: DirectDraw, Direct3D, GDI

- Changes applied
Modified file: src/osd/windows/video.cpp

In the function:

void windows_osd_interface::update(bool skip_redraw)

A new block has been added before the Late Input Poll:

// HARDCADE CRT-MAME: Adaptive HardSync (reduced latency)

if (video_config.waitvsync == FALSE && video_config.syncrefresh == FALSE)
{
    DWORD now = timeGetTime();
    DWORD delta = now - last_event_check;

    if (delta < 10)
    {
        Sleep(0); // yield CPU → stabilize the timing
    }
}

- Objective of Adaptive HardSync:

Stabilize frame timing and prevent oscillations

; Reduce overall latency without blocking the machine

; Works even with old or slow video cards;

Simplified and safer version than true Hard Sync; GroovyMAME


=================================
VERSION
===================================

CRT-MAME 0.168 — V1.3
December 2025
© 2025 Hardcade – PlayRetro – Olivier Mileo
==================================================================================



« Last Edit: Yesterday at 04:08:54 am by Olivcade »
Hardcade / PlayRetro Frontend development / Mame 0.168 Slider Refresh Save 1.2 development

Hardcade Frontend : https://sourceforge.net/projects/arcade-frontend/

Mame 0.168 Slider Refresh Save 1.2 : https://github.com/HardCade/hardcade

Olivcade

  • Trade Count: (0)
  • Jr. Member
  • **
  • Offline Offline
  • Posts: 9
  • Last login:Today at 02:56:58 am
  • I want to build my own arcade controls!

Update version 1.3

README – CRT-MAME 0.168 V1.3

Binary files and source code available here on GitHub:

https://github.com/HardCade/hardcade/releases

Development Version – December 2025
© 2025 Hardcade – PlayRetro

===========================================================================================
PROJECT: CRT-MAME 0.168 Edition

CRT-MAME 0.168 is a specialized version of MAME 0.168 optimized for: 15 kHz CRT monitors (arcade, TV, PVM/BVM, Hantarex, Nanao, etc.) and LCD

monitors

Minimal input lag,

advanced and precise refresh rate control per game.

Objectives:

    - Achieve minimal input lag
    - Achieve increased display performance and superior behavior (compared to existing emulators) for 15 kHz CRTs.
    - Achieve ultra-smooth display and optimal performance on LCD screens.

===============================================
CURRENT MAIN FEATURES (subject to change)
==============================================


- Saving the Refresh Rate slider to CFG files

- Improved slider (precision, stability, rounding, defect handling)

- Added Windows input timestamp (anti-lag preparation)

- Added Late Input Polling (reduces input lag by a full frame)

- Added Direct3D optimization – "Direct Present Minimal" (reduces display lag)

- Added Adaptive HardSync (stabilizes frame timing and prevents stuttering, reduces overall latency)

More features and improvements are coming soon...
Hardcade / PlayRetro Frontend development / Mame 0.168 Slider Refresh Save 1.2 development

Hardcade Frontend : https://sourceforge.net/projects/arcade-frontend/

Mame 0.168 Slider Refresh Save 1.2 : https://github.com/HardCade/hardcade