summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd
diff options
context:
space:
mode:
Diffstat (limited to 'src/osd')
-rw-r--r--src/osd/asio.h12
-rw-r--r--src/osd/eigcc.h148
-rw-r--r--src/osd/eigccarm.h332
-rw-r--r--src/osd/eigccppc.h214
-rw-r--r--src/osd/eigccx86.h251
-rw-r--r--src/osd/eivc.h100
-rw-r--r--src/osd/eivcarm.h75
-rw-r--r--src/osd/eivcx86.h114
-rw-r--r--src/osd/eminline.h227
-rw-r--r--src/osd/interface/audio.h54
-rw-r--r--src/osd/interface/inputcode.h907
-rw-r--r--src/osd/interface/inputdev.h66
-rw-r--r--src/osd/interface/inputfwd.h36
-rw-r--r--src/osd/interface/inputman.h46
-rw-r--r--src/osd/interface/inputseq.cpp210
-rw-r--r--src/osd/interface/inputseq.h107
-rw-r--r--src/osd/interface/midiport.h50
-rw-r--r--src/osd/interface/nethandler.cpp23
-rw-r--r--src/osd/interface/nethandler.h70
-rw-r--r--src/osd/interface/uievents.h61
-rw-r--r--src/osd/mac/macmain.cpp17
-rw-r--r--src/osd/mac/osdmac.h14
-rw-r--r--src/osd/mac/video.cpp160
-rw-r--r--src/osd/mac/window.cpp204
-rw-r--r--src/osd/mac/window.h57
-rw-r--r--src/osd/mac/windowcontroller.mm2
-rw-r--r--src/osd/modules/debugger/debug_module.h13
-rw-r--r--src/osd/modules/debugger/debuggdbstub.cpp1021
-rw-r--r--src/osd/modules/debugger/debugimgui.cpp682
-rw-r--r--src/osd/modules/debugger/debugosx.mm39
-rw-r--r--src/osd/modules/debugger/debugqt.cpp394
-rw-r--r--src/osd/modules/debugger/debugwin.cpp291
-rw-r--r--src/osd/modules/debugger/none.cpp21
-rw-r--r--src/osd/modules/debugger/osx/debugcommandhistory.h5
-rw-r--r--src/osd/modules/debugger/osx/debugcommandhistory.mm32
-rw-r--r--src/osd/modules/debugger/osx/debugconsole.mm86
-rw-r--r--src/osd/modules/debugger/osx/debugosx.h35
-rw-r--r--src/osd/modules/debugger/osx/debugview.mm94
-rw-r--r--src/osd/modules/debugger/osx/debugwindowhandler.h13
-rw-r--r--src/osd/modules/debugger/osx/debugwindowhandler.mm69
-rw-r--r--src/osd/modules/debugger/osx/deviceinfoviewer.mm23
-rw-r--r--src/osd/modules/debugger/osx/devicesviewer.mm10
-rw-r--r--src/osd/modules/debugger/osx/disassemblyview.mm55
-rw-r--r--src/osd/modules/debugger/osx/disassemblyviewer.mm31
-rw-r--r--src/osd/modules/debugger/osx/errorlogviewer.mm12
-rw-r--r--src/osd/modules/debugger/osx/exceptionpointsview.h23
-rw-r--r--src/osd/modules/debugger/osx/exceptionpointsview.mm27
-rw-r--r--src/osd/modules/debugger/osx/memoryview.mm199
-rw-r--r--src/osd/modules/debugger/osx/memoryviewer.mm20
-rw-r--r--src/osd/modules/debugger/osx/pointsviewer.mm94
-rw-r--r--src/osd/modules/debugger/osx/registerpointsview.h23
-rw-r--r--src/osd/modules/debugger/osx/registerpointsview.mm27
-rw-r--r--src/osd/modules/debugger/osx/registersview.mm6
-rw-r--r--src/osd/modules/debugger/qt/breakpointswindow.cpp151
-rw-r--r--src/osd/modules/debugger/qt/breakpointswindow.h44
-rw-r--r--src/osd/modules/debugger/qt/dasmwindow.cpp292
-rw-r--r--src/osd/modules/debugger/qt/dasmwindow.h69
-rw-r--r--src/osd/modules/debugger/qt/debuggerview.cpp431
-rw-r--r--src/osd/modules/debugger/qt/debuggerview.h45
-rw-r--r--src/osd/modules/debugger/qt/deviceinformationwindow.cpp103
-rw-r--r--src/osd/modules/debugger/qt/deviceinformationwindow.h44
-rw-r--r--src/osd/modules/debugger/qt/deviceswindow.cpp85
-rw-r--r--src/osd/modules/debugger/qt/deviceswindow.h50
-rw-r--r--src/osd/modules/debugger/qt/logwindow.cpp47
-rw-r--r--src/osd/modules/debugger/qt/logwindow.h39
-rw-r--r--src/osd/modules/debugger/qt/mainwindow.cpp409
-rw-r--r--src/osd/modules/debugger/qt/mainwindow.h155
-rw-r--r--src/osd/modules/debugger/qt/memorywindow.cpp558
-rw-r--r--src/osd/modules/debugger/qt/memorywindow.h88
-rw-r--r--src/osd/modules/debugger/qt/windowqt.cpp264
-rw-r--r--src/osd/modules/debugger/qt/windowqt.h113
-rw-r--r--src/osd/modules/debugger/win/consolewininfo.cpp620
-rw-r--r--src/osd/modules/debugger/win/consolewininfo.h21
-rw-r--r--src/osd/modules/debugger/win/debugbaseinfo.cpp27
-rw-r--r--src/osd/modules/debugger/win/debugbaseinfo.h9
-rw-r--r--src/osd/modules/debugger/win/debugviewinfo.cpp492
-rw-r--r--src/osd/modules/debugger/win/debugviewinfo.h27
-rw-r--r--src/osd/modules/debugger/win/debugwin.h20
-rw-r--r--src/osd/modules/debugger/win/debugwininfo.cpp162
-rw-r--r--src/osd/modules/debugger/win/debugwininfo.h53
-rw-r--r--src/osd/modules/debugger/win/disasmbasewininfo.cpp47
-rw-r--r--src/osd/modules/debugger/win/disasmbasewininfo.h13
-rw-r--r--src/osd/modules/debugger/win/disasmviewinfo.cpp32
-rw-r--r--src/osd/modules/debugger/win/disasmviewinfo.h15
-rw-r--r--src/osd/modules/debugger/win/disasmwininfo.cpp44
-rw-r--r--src/osd/modules/debugger/win/disasmwininfo.h14
-rw-r--r--src/osd/modules/debugger/win/editwininfo.cpp59
-rw-r--r--src/osd/modules/debugger/win/editwininfo.h15
-rw-r--r--src/osd/modules/debugger/win/logviewinfo.cpp6
-rw-r--r--src/osd/modules/debugger/win/logviewinfo.h11
-rw-r--r--src/osd/modules/debugger/win/logwininfo.cpp25
-rw-r--r--src/osd/modules/debugger/win/logwininfo.h12
-rw-r--r--src/osd/modules/debugger/win/memoryviewinfo.cpp143
-rw-r--r--src/osd/modules/debugger/win/memoryviewinfo.h39
-rw-r--r--src/osd/modules/debugger/win/memorywininfo.cpp262
-rw-r--r--src/osd/modules/debugger/win/memorywininfo.h13
-rw-r--r--src/osd/modules/debugger/win/pointswininfo.cpp99
-rw-r--r--src/osd/modules/debugger/win/pointswininfo.h13
-rw-r--r--src/osd/modules/debugger/win/uimetrics.cpp93
-rw-r--r--src/osd/modules/debugger/win/uimetrics.h46
-rw-r--r--src/osd/modules/debugger/xmlconfig.cpp54
-rw-r--r--src/osd/modules/debugger/xmlconfig.h72
-rw-r--r--src/osd/modules/diagnostics/diagnostics_win32.cpp126
-rw-r--r--src/osd/modules/diagnostics/none.cpp5
-rw-r--r--src/osd/modules/file/posixdir.cpp13
-rw-r--r--src/osd/modules/file/posixdomain.cpp207
-rw-r--r--src/osd/modules/file/posixfile.cpp236
-rw-r--r--src/osd/modules/file/posixfile.h20
-rw-r--r--src/osd/modules/file/posixptty.cpp68
-rw-r--r--src/osd/modules/file/posixsocket.cpp188
-rw-r--r--src/osd/modules/file/stdfile.cpp119
-rw-r--r--src/osd/modules/file/windir.cpp8
-rw-r--r--src/osd/modules/file/winfile.cpp243
-rw-r--r--src/osd/modules/file/winfile.h25
-rw-r--r--src/osd/modules/file/winptty.cpp56
-rw-r--r--src/osd/modules/file/winrtdir.cpp8
-rw-r--r--src/osd/modules/file/winrtfile.cpp26
-rw-r--r--src/osd/modules/file/winrtfile.h2
-rw-r--r--src/osd/modules/file/winrtptty.cpp3
-rw-r--r--src/osd/modules/file/winrtsocket.cpp5
-rw-r--r--src/osd/modules/file/winsocket.cpp135
-rw-r--r--src/osd/modules/font/font_dwrite.cpp55
-rw-r--r--src/osd/modules/font/font_module.h2
-rw-r--r--src/osd/modules/font/font_none.cpp16
-rw-r--r--src/osd/modules/font/font_osx.cpp42
-rw-r--r--src/osd/modules/font/font_sdl.cpp38
-rw-r--r--src/osd/modules/font/font_windows.cpp34
-rw-r--r--src/osd/modules/input/assignmenthelper.cpp592
-rw-r--r--src/osd/modules/input/assignmenthelper.h118
-rw-r--r--src/osd/modules/input/input_common.cpp400
-rw-r--r--src/osd/modules/input/input_common.h504
-rw-r--r--src/osd/modules/input/input_dinput.cpp1540
-rw-r--r--src/osd/modules/input/input_dinput.h331
-rw-r--r--src/osd/modules/input/input_mac.cpp13
-rw-r--r--src/osd/modules/input/input_module.h20
-rw-r--r--src/osd/modules/input/input_none.cpp72
-rw-r--r--src/osd/modules/input/input_rawinput.cpp1028
-rw-r--r--src/osd/modules/input/input_sdl.cpp2751
-rw-r--r--src/osd/modules/input/input_sdlcommon.cpp318
-rw-r--r--src/osd/modules/input/input_sdlcommon.h204
-rw-r--r--src/osd/modules/input/input_uwp.cpp649
-rw-r--r--src/osd/modules/input/input_win32.cpp622
-rw-r--r--src/osd/modules/input/input_wincommon.h40
-rw-r--r--src/osd/modules/input/input_windows.cpp130
-rw-r--r--src/osd/modules/input/input_windows.h75
-rw-r--r--src/osd/modules/input/input_winhybrid.cpp351
-rw-r--r--src/osd/modules/input/input_x11.cpp678
-rw-r--r--src/osd/modules/input/input_xinput.cpp3164
-rw-r--r--src/osd/modules/input/input_xinput.h142
-rw-r--r--src/osd/modules/lib/osdlib.h136
-rw-r--r--src/osd/modules/lib/osdlib_macosx.cpp228
-rw-r--r--src/osd/modules/lib/osdlib_unix.cpp261
-rw-r--r--src/osd/modules/lib/osdlib_uwp.cpp190
-rw-r--r--src/osd/modules/lib/osdlib_win32.cpp239
-rw-r--r--src/osd/modules/lib/osdobj_common.cpp686
-rw-r--r--src/osd/modules/lib/osdobj_common.h149
-rw-r--r--src/osd/modules/midi/midi_module.h26
-rw-r--r--src/osd/modules/midi/none.cpp87
-rw-r--r--src/osd/modules/midi/portmidi.cpp374
-rw-r--r--src/osd/modules/monitor/monitor_common.cpp11
-rw-r--r--src/osd/modules/monitor/monitor_common.h36
-rw-r--r--src/osd/modules/monitor/monitor_dxgi.cpp24
-rw-r--r--src/osd/modules/monitor/monitor_mac.cpp4
-rw-r--r--src/osd/modules/monitor/monitor_module.h3
-rw-r--r--src/osd/modules/monitor/monitor_sdl.cpp18
-rw-r--r--src/osd/modules/monitor/monitor_win32.cpp8
-rw-r--r--src/osd/modules/netdev/netdev_common.cpp39
-rw-r--r--src/osd/modules/netdev/netdev_common.h36
-rw-r--r--src/osd/modules/netdev/netdev_module.h23
-rw-r--r--src/osd/modules/netdev/none.cpp35
-rw-r--r--src/osd/modules/netdev/pcap.cpp248
-rw-r--r--src/osd/modules/netdev/taptun.cpp170
-rw-r--r--src/osd/modules/opengl/gl_shader_mgr.cpp376
-rw-r--r--src/osd/modules/opengl/gl_shader_mgr.h84
-rw-r--r--src/osd/modules/opengl/gl_shader_tool.cpp649
-rw-r--r--src/osd/modules/opengl/gl_shader_tool.h221
-rw-r--r--src/osd/modules/opengl/osd_opengl.h156
-rw-r--r--src/osd/modules/osdhelper.h4
-rw-r--r--src/osd/modules/osdmodule.cpp121
-rw-r--r--src/osd/modules/osdmodule.h86
-rw-r--r--src/osd/modules/osdwindow.cpp162
-rw-r--r--src/osd/modules/osdwindow.h399
-rw-r--r--src/osd/modules/output/console.cpp18
-rw-r--r--src/osd/modules/output/network.cpp308
-rw-r--r--src/osd/modules/output/none.cpp16
-rw-r--r--src/osd/modules/output/output_module.h24
-rw-r--r--src/osd/modules/output/win32_output.cpp68
-rw-r--r--src/osd/modules/output/win32_output.h12
-rw-r--r--src/osd/modules/render/aviwrite.cpp20
-rw-r--r--src/osd/modules/render/aviwrite.h17
-rw-r--r--src/osd/modules/render/bgfx/blendreader.cpp11
-rw-r--r--src/osd/modules/render/bgfx/chain.cpp88
-rw-r--r--src/osd/modules/render/bgfx/chain.h27
-rw-r--r--src/osd/modules/render/bgfx/chainentry.cpp126
-rw-r--r--src/osd/modules/render/bgfx/chainentry.h27
-rw-r--r--src/osd/modules/render/bgfx/chainentryreader.cpp147
-rw-r--r--src/osd/modules/render/bgfx/chainentryreader.h12
-rw-r--r--src/osd/modules/render/bgfx/chainmanager.cpp647
-rw-r--r--src/osd/modules/render/bgfx/chainmanager.h116
-rw-r--r--src/osd/modules/render/bgfx/chainreader.cpp62
-rw-r--r--src/osd/modules/render/bgfx/chainreader.h15
-rw-r--r--src/osd/modules/render/bgfx/clearreader.cpp22
-rw-r--r--src/osd/modules/render/bgfx/clearreader.h14
-rw-r--r--src/osd/modules/render/bgfx/depthreader.cpp8
-rw-r--r--src/osd/modules/render/bgfx/depthreader.h10
-rw-r--r--src/osd/modules/render/bgfx/effect.cpp46
-rw-r--r--src/osd/modules/render/bgfx/effect.h22
-rw-r--r--src/osd/modules/render/bgfx/effectmanager.cpp129
-rw-r--r--src/osd/modules/render/bgfx/effectmanager.h29
-rw-r--r--src/osd/modules/render/bgfx/effectreader.cpp166
-rw-r--r--src/osd/modules/render/bgfx/effectreader.h25
-rw-r--r--src/osd/modules/render/bgfx/entryuniform.h12
-rw-r--r--src/osd/modules/render/bgfx/entryuniformreader.cpp12
-rw-r--r--src/osd/modules/render/bgfx/entryuniformreader.h14
-rw-r--r--src/osd/modules/render/bgfx/frameparameter.cpp8
-rw-r--r--src/osd/modules/render/bgfx/frameparameter.h16
-rw-r--r--src/osd/modules/render/bgfx/inputpair.cpp87
-rw-r--r--src/osd/modules/render/bgfx/inputpair.h6
-rw-r--r--src/osd/modules/render/bgfx/parameter.h15
-rw-r--r--src/osd/modules/render/bgfx/paramreader.cpp34
-rw-r--r--src/osd/modules/render/bgfx/paramreader.h14
-rw-r--r--src/osd/modules/render/bgfx/paramuniform.h8
-rw-r--r--src/osd/modules/render/bgfx/paramuniformreader.cpp10
-rw-r--r--src/osd/modules/render/bgfx/paramuniformreader.h16
-rw-r--r--src/osd/modules/render/bgfx/shadermanager.cpp90
-rw-r--r--src/osd/modules/render/bgfx/shadermanager.h29
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/blurs/fs_smart-blur.sc36
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/blurs/vs_smart-blur.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/crt-geom/crt-geom_common.sc203
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_crt-geom-deluxe.sc202
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_crt-geom.sc257
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_gaussx.sc37
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_gaussy.sc37
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_lowpass.sc37
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_mipmap8.sc148
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_phosphor_apply.sc29
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_phosphor_update.sc27
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/crt-geom/varying.def.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_crt-geom.sc102
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_gaussx.sc17
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_gaussy.sc17
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_lowpass.sc53
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_mipmap8.sc16
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_phosphor_apply.sc11
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_phosphor_update.sc11
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/crt/vs_crt-caligari.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/default/vs_blit.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/eagle/fs_eagle.sc30
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/eagle/vs_eagle.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_chroma.sc9
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_defocus.sc2
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_distortion.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_ntsc_decode.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_ntsc_encode.sc4
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_scanline.sc27
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_chroma.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_color.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_deconverge.sc4
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_defocus.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_distortion.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_ntsc_decode.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_ntsc_encode.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_phosphor.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_post.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_prescale.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_scanline.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hqx/fs_hq2x.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hqx/fs_hq3x.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hqx/fs_hq4x.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hqx/vs_hq2x.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hqx/vs_hq3x.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hqx/vs_hq4x.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/lcd-grid/fs_lcd-grid.sc106
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/lcd-grid/fs_persistence.sc16
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/lcd-grid/varying.def.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/lcd-grid/vs_lcd-grid.sc19
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/lcd-grid/vs_persistence.sc19
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/misc/fs_blit_bcg.sc24
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/misc/fs_blit_palette16.sc37
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/misc/fs_blit_rgb32.sc14
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/misc/fs_blit_yuy16.sc38
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/misc/fs_bob-and-ghost-deinterlace.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/misc/fs_deposterize-pass0.sc4
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/misc/fs_deposterize-pass1.sc4
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/misc/fs_lut.sc13
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/misc/vs_blit.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/misc/vs_bob-and-ghost-deinterlace.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/misc/vs_deposterize-pass0.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/misc/vs_deposterize-pass1.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/misc/vs_lut.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/misc/vs_resize_blit.sc21
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/misc/vs_saturation.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_horizontal/fs_gaussian.sc2
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_horizontal/vs_gaussian.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_horizontal/vs_offset_sat.sc9
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_vertical/fs_gaussian.sc2
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_vertical/vs_gaussian.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_vertical/vs_offset_sat.sc9
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_horizontal/fs_gaussian.sc2
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_horizontal/vs_gaussian.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_horizontal/vs_offset_sat.sc9
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_vertical/fs_gaussian.sc2
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_vertical/vs_gaussian.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_vertical/vs_offset_sat.sc9
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/unfiltered/vs_blit.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/warp/fs_dilation-horizontal-fast.sc4
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/warp/vs_dilation-horizontal-fast.sc14
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv1-noblend.sc4
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv2-3d.sc10
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv2-fast.sc10
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv2-noblend.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv2.sc10
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv3-noblend.sc10
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv3.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_custom-jinc2-sharper.sc20
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-2xbr-3d-pass0.sc20
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-2xbr-3d-pass1.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-2xbr-3d-pass2.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass0.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass1.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass1f.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass2.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass3.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass3f.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-fast-pass0.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-fast-pass1.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-fast-pass2.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-pass0.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-pass1.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-pass2.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_custom-jinc2-sharper.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-2xbr-3d-pass0.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-2xbr-3d-pass1.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-2xbr-3d-pass2.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass0.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass1.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass1f.sc4
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass2.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass3.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass3f.sc4
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-fast-pass0.sc9
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-fast-pass1.sc9
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-fast-pass2.sc9
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-pass0.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-pass1.sc9
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-pass2.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-pass3.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv1-noblend.sc4
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv2-3d.sc4
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv2-fast.sc4
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv2-noblend.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv2.sc4
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv3-noblend.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv3.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-sharp.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v2-gamma.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v2.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v4-gamma.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v4.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v4b.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v5-gamma.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid.sc10
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-sharp.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v2-gamma.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v2.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v4-gamma.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v4.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v4b.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v5-gamma.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-a-pass0.sc4
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-accuracy-pass0.sc4
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-accuracy-pass1.sc12
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-b-pass0.sc4
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-c-pass0.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-d-pass0.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-noblend-pass1.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-pass1.sc10
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-a-pass0.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-accuracy-pass0.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-accuracy-pass1.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-b-pass0.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-c-pass0.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-d-pass0.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-noblend-pass1.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-pass1.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv3-multipass/fs_xbr-lv3-pass0.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv3-multipass/fs_xbr-lv3-pass1.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv3-multipass/vs_xbr-lv3-pass0.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv3-multipass/vs_xbr-lv3-pass1.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/fs_xbr-mlv4-pass1.sc8
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/fs_xbr-mlv4-pass2.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/fs_xbr-mlv4-pass3.sc4
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/fs_xbr-mlv4-pass4.sc10
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass1.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass2.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass3.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass4.sc6
-rw-r--r--src/osd/modules/render/bgfx/shaders/fs_screen.sc2
-rw-r--r--src/osd/modules/render/bgfx/shaders/makefile27
-rw-r--r--src/osd/modules/render/bgfx/shaders/shader.mk68
-rw-r--r--src/osd/modules/render/bgfx/shaders/vs_gui.sc5
-rw-r--r--src/osd/modules/render/bgfx/shaders/vs_screen.sc5
-rw-r--r--src/osd/modules/render/bgfx/slider.cpp49
-rw-r--r--src/osd/modules/render/bgfx/slider.h25
-rw-r--r--src/osd/modules/render/bgfx/sliderreader.cpp80
-rw-r--r--src/osd/modules/render/bgfx/sliderreader.h16
-rw-r--r--src/osd/modules/render/bgfx/slideruniform.cpp10
-rw-r--r--src/osd/modules/render/bgfx/slideruniform.h10
-rw-r--r--src/osd/modules/render/bgfx/slideruniformreader.cpp17
-rw-r--r--src/osd/modules/render/bgfx/slideruniformreader.h16
-rw-r--r--src/osd/modules/render/bgfx/statereader.cpp27
-rw-r--r--src/osd/modules/render/bgfx/statereader.h32
-rw-r--r--src/osd/modules/render/bgfx/suppressor.cpp9
-rw-r--r--src/osd/modules/render/bgfx/suppressor.h10
-rw-r--r--src/osd/modules/render/bgfx/suppressorreader.cpp25
-rw-r--r--src/osd/modules/render/bgfx/suppressorreader.h12
-rw-r--r--src/osd/modules/render/bgfx/target.cpp24
-rw-r--r--src/osd/modules/render/bgfx/target.h15
-rw-r--r--src/osd/modules/render/bgfx/targetmanager.cpp138
-rw-r--r--src/osd/modules/render/bgfx/targetmanager.h37
-rw-r--r--src/osd/modules/render/bgfx/targetreader.cpp66
-rw-r--r--src/osd/modules/render/bgfx/targetreader.h14
-rw-r--r--src/osd/modules/render/bgfx/texture.cpp26
-rw-r--r--src/osd/modules/render/bgfx/texture.h18
-rw-r--r--src/osd/modules/render/bgfx/texturehandleprovider.h14
-rw-r--r--src/osd/modules/render/bgfx/texturemanager.cpp170
-rw-r--r--src/osd/modules/render/bgfx/texturemanager.h40
-rw-r--r--src/osd/modules/render/bgfx/timeparameter.cpp6
-rw-r--r--src/osd/modules/render/bgfx/timeparameter.h15
-rw-r--r--src/osd/modules/render/bgfx/uniform.cpp24
-rw-r--r--src/osd/modules/render/bgfx/uniform.h14
-rw-r--r--src/osd/modules/render/bgfx/uniformreader.cpp34
-rw-r--r--src/osd/modules/render/bgfx/uniformreader.h16
-rw-r--r--src/osd/modules/render/bgfx/valueuniform.cpp10
-rw-r--r--src/osd/modules/render/bgfx/valueuniform.h10
-rw-r--r--src/osd/modules/render/bgfx/valueuniformreader.cpp8
-rw-r--r--src/osd/modules/render/bgfx/valueuniformreader.h15
-rw-r--r--src/osd/modules/render/bgfx/vertex.h2
-rw-r--r--src/osd/modules/render/bgfx/view.cpp19
-rw-r--r--src/osd/modules/render/bgfx/view.h6
-rw-r--r--src/osd/modules/render/bgfx/windowparameter.h18
-rw-r--r--src/osd/modules/render/bgfx/writereader.h8
-rw-r--r--src/osd/modules/render/bgfxutil.cpp118
-rw-r--r--src/osd/modules/render/bgfxutil.h8
-rw-r--r--src/osd/modules/render/binpacker.cpp9
-rw-r--r--src/osd/modules/render/binpacker.h38
-rw-r--r--src/osd/modules/render/blit13.ipp (renamed from src/osd/modules/render/blit13.h)20
-rw-r--r--src/osd/modules/render/copyutil.h119
-rw-r--r--src/osd/modules/render/d3d/d3dcomm.h108
-rw-r--r--src/osd/modules/render/d3d/d3dhlsl.cpp1054
-rw-r--r--src/osd/modules/render/d3d/d3dhlsl.h263
-rw-r--r--src/osd/modules/render/draw13.cpp755
-rw-r--r--src/osd/modules/render/draw13.h213
-rw-r--r--src/osd/modules/render/drawbgfx.cpp1147
-rw-r--r--src/osd/modules/render/drawbgfx.h115
-rw-r--r--src/osd/modules/render/drawd3d.cpp1087
-rw-r--r--src/osd/modules/render/drawd3d.h67
-rw-r--r--src/osd/modules/render/drawgdi.cpp131
-rw-r--r--src/osd/modules/render/drawgdi.h55
-rw-r--r--src/osd/modules/render/drawnone.cpp88
-rw-r--r--src/osd/modules/render/drawnone.h33
-rw-r--r--src/osd/modules/render/drawogl.cpp1200
-rw-r--r--src/osd/modules/render/drawogl.h242
-rw-r--r--src/osd/modules/render/drawsdl.cpp370
-rw-r--r--src/osd/modules/render/drawsdl.h88
-rw-r--r--src/osd/modules/render/render_module.h38
-rw-r--r--src/osd/modules/render/sdlglcontext.h55
-rw-r--r--src/osd/modules/render/winglcontext.h201
-rw-r--r--src/osd/modules/sound/coreaudio_sound.cpp244
-rw-r--r--src/osd/modules/sound/direct_sound.cpp459
-rw-r--r--src/osd/modules/sound/js_sound.cpp32
-rw-r--r--src/osd/modules/sound/js_sound.js38
-rw-r--r--src/osd/modules/sound/none.cpp23
-rw-r--r--src/osd/modules/sound/pa_sound.cpp89
-rw-r--r--src/osd/modules/sound/pipewire_sound.cpp823
-rw-r--r--src/osd/modules/sound/pulse_sound.cpp545
-rw-r--r--src/osd/modules/sound/sdl_sound.cpp531
-rw-r--r--src/osd/modules/sound/sound_module.cpp61
-rw-r--r--src/osd/modules/sound/sound_module.h73
-rw-r--r--src/osd/modules/sound/xaudio2_sound.cpp180
-rw-r--r--src/osd/osdcomm.h61
-rw-r--r--src/osd/osdcore.cpp116
-rw-r--r--src/osd/osdcore.h676
-rw-r--r--src/osd/osdepend.h45
-rw-r--r--src/osd/osdfile.h287
-rw-r--r--src/osd/osdnet.cpp139
-rw-r--r--src/osd/osdnet.h51
-rw-r--r--src/osd/osdsync.cpp112
-rw-r--r--src/osd/osdsync.h14
-rw-r--r--src/osd/sdl/android_main.cpp11
-rw-r--r--src/osd/sdl/osdsdl.cpp852
-rw-r--r--src/osd/sdl/osdsdl.h220
-rw-r--r--src/osd/sdl/sdlmain.cpp442
-rw-r--r--src/osd/sdl/sdlopts.cpp127
-rw-r--r--src/osd/sdl/sdlopts.h100
-rwxr-xr-x[-rw-r--r--]src/osd/sdl/taputil.sh4
-rw-r--r--src/osd/sdl/video.cpp217
-rw-r--r--src/osd/sdl/window.cpp792
-rw-r--r--src/osd/sdl/window.h133
-rw-r--r--src/osd/strconv.cpp128
-rw-r--r--src/osd/strconv.h49
-rw-r--r--src/osd/uwp/uwpcompat.cpp103
-rw-r--r--src/osd/uwp/uwpcompat.h139
-rw-r--r--src/osd/uwp/video.cpp203
-rw-r--r--src/osd/uwp/video.h19
-rw-r--r--src/osd/uwp/window.cpp1146
-rw-r--r--src/osd/uwp/window.h166
-rw-r--r--src/osd/watchdog.cpp2
-rw-r--r--src/osd/windows/ledutil.cpp6
-rw-r--r--src/osd/windows/main.cpp34
-rw-r--r--src/osd/windows/video.cpp129
-rw-r--r--src/osd/windows/window.cpp1555
-rw-r--r--src/osd/windows/window.h169
-rw-r--r--src/osd/windows/winmain.cpp423
-rw-r--r--src/osd/windows/winmain.h309
-rw-r--r--src/osd/windows/winmenu.cpp33
-rw-r--r--src/osd/windows/winopts.cpp157
-rw-r--r--src/osd/windows/winopts.h232
-rw-r--r--src/osd/windows/winutf8.cpp44
-rw-r--r--src/osd/windows/winutil.cpp117
-rw-r--r--src/osd/windows/winutil.h21
522 files changed, 36484 insertions, 23331 deletions
diff --git a/src/osd/asio.h b/src/osd/asio.h
index 3ee31a467d7..0643bf332b4 100644
--- a/src/osd/asio.h
+++ b/src/osd/asio.h
@@ -17,19 +17,13 @@
#pragma GCC diagnostic ignored "-Wunused-variable"
#endif
-#if defined(WIN32) && !defined(_WIN32_WINNT)
-#if defined(OSD_WINDOWS)
-#define _WIN32_WINNT 0x0501
-#else
-#define _WIN32_WINNT 0x0603
-#endif
+#if defined(_WIN32) && !defined(_WIN32_WINNT)
+#define _WIN32_WINNT 0x0600
#endif
+
#define ASIO_HEADER_ONLY
#define ASIO_STANDALONE
#define ASIO_SEPARATE_COMPILATION
-#define ASIO_NOEXCEPT noexcept(true)
-#define ASIO_NOEXCEPT_OR_NOTHROW noexcept(true)
-#define ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true)
#include <asio.hpp>
#undef interface
diff --git a/src/osd/eigcc.h b/src/osd/eigcc.h
new file mode 100644
index 00000000000..2c5bf34ba72
--- /dev/null
+++ b/src/osd/eigcc.h
@@ -0,0 +1,148 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ eigccppc.h
+
+ Inline implementations for GCC compilers. This code is automatically
+ included if appropriate by eminline.h.
+
+***************************************************************************/
+
+#ifndef MAME_OSD_EIGCC_H
+#define MAME_OSD_EIGCC_H
+
+#include <cassert>
+
+
+/***************************************************************************
+ INLINE MATH FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ addu_32x32_co - perform an unsigned 32 bit + 32
+ bit addition and return the result with carry
+ out
+-------------------------------------------------*/
+
+#ifndef addu_32x32_co
+#define addu_32x32_co _addu_32x32_co
+inline bool _addu_32x32_co(uint32_t a, uint32_t b, uint32_t &sum)
+{
+ return __builtin_add_overflow(a, b, &sum);
+}
+#endif
+
+
+/*-------------------------------------------------
+ addu_64x64_co - perform an unsigned 64 bit + 64
+ bit addition and return the result with carry
+ out
+-------------------------------------------------*/
+
+#ifndef addu_64x64_co
+#define addu_64x64_co _addu_64x64_co
+inline bool _addu_64x64_co(uint64_t a, uint64_t b, uint64_t &sum)
+{
+ return __builtin_add_overflow(a, b, &sum);
+}
+#endif
+
+
+
+/***************************************************************************
+ INLINE BIT MANIPULATION FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ count_leading_zeros_32 - return the number of
+ leading zero bits in a 32-bit value
+-------------------------------------------------*/
+
+#ifndef count_leading_zeros_32
+#define count_leading_zeros_32 _count_leading_zeros_32
+inline uint8_t _count_leading_zeros_32(uint32_t val)
+{
+ // uses CPU feature if available, otherwise falls back to runtime library call
+ static_assert(sizeof(val) == sizeof(unsigned), "expected 32-bit unsigned int");
+ return uint8_t(unsigned(val ? __builtin_clz(val) : 32));
+}
+#endif
+
+
+/*-------------------------------------------------
+ count_leading_ones_32 - return the number of
+ leading one bits in a 32-bit value
+-------------------------------------------------*/
+
+#ifndef count_leading_ones_32
+#define count_leading_ones_32 _count_leading_ones_32
+inline uint8_t _count_leading_ones_32(uint32_t val)
+{
+ return count_leading_zeros_32(~val);
+}
+#endif
+
+
+/*-------------------------------------------------
+ count_leading_zeros_64 - return the number of
+ leading zero bits in a 64-bit value
+-------------------------------------------------*/
+
+#ifndef count_leading_zeros_64
+#define count_leading_zeros_64 _count_leading_zeros_64
+inline uint8_t _count_leading_zeros_64(uint64_t val)
+{
+ // uses CPU feature if available, otherwise falls back to runtime library call
+ static_assert(sizeof(val) == sizeof(unsigned long long), "expected 64-bit unsigned long long int");
+ return uint8_t(unsigned(val ? __builtin_clzll(val) : 64));
+}
+#endif
+
+
+/*-------------------------------------------------
+ count_leading_ones_64 - return the number of
+ leading one bits in a 64-bit value
+-------------------------------------------------*/
+
+#ifndef count_leading_ones_64
+#define count_leading_ones_64 _count_leading_ones_64
+inline uint8_t _count_leading_ones_64(uint64_t val)
+{
+ return count_leading_zeros_64(~val);
+}
+#endif
+
+
+/*-------------------------------------------------
+ population_count_32 - return the number of
+ one bits in a 32-bit value
+-------------------------------------------------*/
+
+#ifndef population_count_32
+#define population_count_32 _population_count_32
+inline unsigned _population_count_32(uint32_t val)
+{
+ // uses CPU feature if available, otherwise falls back to implementation similar to eminline.h
+ static_assert(sizeof(val) == sizeof(unsigned), "expected 32-bit unsigned int");
+ return unsigned(__builtin_popcount(static_cast<unsigned>(val)));
+}
+#endif
+
+
+/*-------------------------------------------------
+ population_count_64 - return the number of
+ one bits in a 64-bit value
+-------------------------------------------------*/
+
+#ifndef population_count_64
+#define population_count_64 _population_count_64
+inline unsigned _population_count_64(uint64_t val)
+{
+ // uses CPU feature if available, otherwise falls back to implementation similar to eminline.h
+ static_assert(sizeof(val) == sizeof(unsigned long long), "expected 64-bit unsigned long long int");
+ return unsigned(__builtin_popcountll(static_cast<unsigned long long>(val)));
+}
+#endif
+
+#endif // MAME_OSD_EIGCC_H
diff --git a/src/osd/eigccarm.h b/src/osd/eigccarm.h
new file mode 100644
index 00000000000..90004daf9d4
--- /dev/null
+++ b/src/osd/eigccarm.h
@@ -0,0 +1,332 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ eigccarm.h
+
+ ARM/AArch64 inline implementations for GCC compilers. This code is
+ automatically included if appropriate by eminline.h.
+
+***************************************************************************/
+
+#ifndef MAME_OSD_EIGCCARM_H
+#define MAME_OSD_EIGCCARM_H
+
+
+/***************************************************************************
+ INLINE MATH FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ mul_32x32 - perform a signed 32 bit x 32 bit
+ multiply and return the full 64 bit result
+-------------------------------------------------*/
+
+// GCC can do a good job of this.
+
+
+/*-------------------------------------------------
+ mulu_32x32 - perform an unsigned 32 bit x
+ 32 bit multiply and return the full 64 bit
+ result
+-------------------------------------------------*/
+
+// GCC can do a good job of this
+
+
+/*-------------------------------------------------
+ mul_32x32_hi - perform a signed 32 bit x 32 bit
+ multiply and return the upper 32 bits of the
+ result
+-------------------------------------------------*/
+
+// GCC can do a good job of this
+
+
+/*-------------------------------------------------
+ mulu_32x32_hi - perform an unsigned 32 bit x
+ 32 bit multiply and return the upper 32 bits
+ of the result
+-------------------------------------------------*/
+
+// GCC can do a good job of this
+
+
+/*-------------------------------------------------
+ mul_32x32_shift - perform a signed 32 bit x
+ 32 bit multiply and shift the result by the
+ given number of bits before truncating the
+ result to 32 bits
+-------------------------------------------------*/
+
+#if !defined(__aarch64__)
+#define mul_32x32_shift _mul_32x32_shift
+inline int32_t ATTR_CONST ATTR_FORCE_INLINE
+_mul_32x32_shift(int32_t val1, int32_t val2, uint8_t shift)
+{
+ uint32_t l, h;
+
+ __asm__ (
+ " smull %[l], %[h], %[val1], %[val2] \n"
+ : [l] "=r" (l)
+ , [h] "=r" (h)
+ : [val1] "%r" (val1)
+ , [val2] "r" (val2)
+ );
+
+ // Valid for (0 <= shift <= 31)
+ return int32_t((l >> shift) | (h << (32 - shift)));
+}
+#endif
+
+
+/*-------------------------------------------------
+ mulu_32x32_shift - perform an unsigned 32 bit x
+ 32 bit multiply and shift the result by the
+ given number of bits before truncating the
+ result to 32 bits
+-------------------------------------------------*/
+
+#if !defined(__aarch64__)
+#define mulu_32x32_shift _mulu_32x32_shift
+inline uint32_t ATTR_CONST ATTR_FORCE_INLINE
+_mulu_32x32_shift(uint32_t val1, uint32_t val2, uint8_t shift)
+{
+ uint32_t l, h;
+
+ __asm__ (
+ " umull %[l], %[h], %[val1], %[val2] \n"
+ : [l] "=r" (l)
+ , [h] "=r" (h)
+ : [val1] "%r" (val1)
+ , [val2] "r" (val2)
+ );
+
+ // Valid for (0 <= shift <= 31)
+ return (l >> shift) | (h << (32 - shift));
+}
+#endif
+
+
+/*-------------------------------------------------
+ div_64x32 - perform a signed 64 bit x 32 bit
+ divide and return the 32 bit quotient
+-------------------------------------------------*/
+
+// TBD
+
+
+/*-------------------------------------------------
+ divu_64x32 - perform an unsigned 64 bit x 32 bit
+ divide and return the 32 bit quotient
+-------------------------------------------------*/
+
+// TBD
+
+
+/*-------------------------------------------------
+ div_64x32_rem - perform a signed 64 bit x 32
+ bit divide and return the 32 bit quotient and
+ 32 bit remainder
+-------------------------------------------------*/
+
+// TBD
+
+
+/*-------------------------------------------------
+ divu_64x32_rem - perform an unsigned 64 bit x
+ 32 bit divide and return the 32 bit quotient
+ and 32 bit remainder
+-------------------------------------------------*/
+
+// TBD
+
+
+/*-------------------------------------------------
+ div_32x32_shift - perform a signed divide of
+ two 32 bit values, shifting the first before
+ division, and returning the 32 bit quotient
+-------------------------------------------------*/
+
+// TBD
+
+
+/*-------------------------------------------------
+ divu_32x32_shift - perform an unsigned divide of
+ two 32 bit values, shifting the first before
+ division, and returning the 32 bit quotient
+-------------------------------------------------*/
+
+// TBD
+
+
+/*-------------------------------------------------
+ mod_64x32 - perform a signed 64 bit x 32 bit
+ divide and return the 32 bit remainder
+-------------------------------------------------*/
+
+// TBD
+
+
+/*-------------------------------------------------
+ modu_64x32 - perform an unsigned 64 bit x 32 bit
+ divide and return the 32 bit remainder
+-------------------------------------------------*/
+
+// TBD
+
+
+/*-------------------------------------------------
+ recip_approx - compute an approximate floating
+ point reciprocal
+-------------------------------------------------*/
+
+#if defined(__aarch64__)
+#define recip_approx _recip_approx
+inline float ATTR_CONST ATTR_FORCE_INLINE
+_recip_approx(float value)
+{
+ float result;
+
+ __asm__ (
+ " frecpe %s[result], %s[value] \n"
+ : [result] "=w" (result)
+ : [value] "w" (value)
+ );
+
+ return result;
+}
+#endif
+
+
+/*-------------------------------------------------
+ mul_64x64 - perform a signed 64 bit x 64 bit
+ multiply and return the full 128 bit result
+-------------------------------------------------*/
+
+#if defined(__aarch64__)
+#define mul_64x64 _mul_64x64
+inline int64_t ATTR_FORCE_INLINE
+_mul_64x64(int64_t a, int64_t b, int64_t &hi)
+{
+ __int128 const r(__int128(a) * b);
+ hi = int64_t(uint64_t((unsigned __int128)r >> 64));
+ return int64_t(uint64_t((unsigned __int128)r));
+}
+#endif
+
+
+/*-------------------------------------------------
+ mulu_64x64 - perform an unsigned 64 bit x 64
+ bit multiply and return the full 128 bit result
+-------------------------------------------------*/
+
+#if defined(__aarch64__)
+#define mulu_64x64 _mulu_64x64
+inline uint64_t ATTR_FORCE_INLINE
+_mulu_64x64(uint64_t a, uint64_t b, uint64_t &hi)
+{
+ unsigned __int128 const r((unsigned __int128)a * b);
+ hi = uint64_t(r >> 64);
+ return uint64_t(r);
+}
+#endif
+
+
+
+/***************************************************************************
+ INLINE BIT MANIPULATION FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ count_leading_zeros_32 - return the number of
+ leading zero bits in a 32-bit value
+-------------------------------------------------*/
+
+#if defined(__aarch64__)
+#define count_leading_zeros_32 _count_leading_zeros_32
+inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
+_count_leading_zeros_32(uint32_t value)
+{
+ uint32_t result;
+
+ __asm__ (
+ " clz %w[result], %w[value] \n"
+ : [result] "=r" (result)
+ : [value] "r" (value)
+ );
+
+ return uint8_t(result);
+}
+#endif
+
+
+/*-------------------------------------------------
+ count_leading_ones_32 - return the number of
+ leading one bits in a 32-bit value
+-------------------------------------------------*/
+
+#if defined(__aarch64__)
+#define count_leading_ones_32 _count_leading_ones_32
+inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
+_count_leading_ones_32(uint32_t value)
+{
+ uint32_t result;
+
+ __asm__ (
+ " clz %w[result], %w[value] \n"
+ : [result] "=r" (result)
+ : [value] "r" (~value)
+ );
+
+ return uint8_t(result);
+}
+#endif
+
+
+/*-------------------------------------------------
+ count_leading_zeros_64 - return the number of
+ leading zero bits in a 64-bit value
+-------------------------------------------------*/
+
+#if defined(__aarch64__)
+#define count_leading_zeros_64 _count_leading_zeros_64
+inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
+_count_leading_zeros_64(uint64_t value)
+{
+ uint64_t result;
+
+ __asm__ (
+ " clz %[result], %[value] \n"
+ : [result] "=r" (result)
+ : [value] "r" (value)
+ );
+
+ return uint8_t(result);
+}
+#endif
+
+
+/*-------------------------------------------------
+ count_leading_ones_64 - return the number of
+ leading one bits in a 64-bit value
+-------------------------------------------------*/
+
+#if defined(__aarch64__)
+#define count_leading_ones_64 _count_leading_ones_64
+inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
+_count_leading_ones_64(uint64_t value)
+{
+ uint64_t result;
+
+ __asm__ (
+ " clz %[result], %[value] \n"
+ : [result] "=r" (result)
+ : [value] "r" (~value)
+ );
+
+ return uint8_t(result);
+}
+#endif
+
+#endif // MAME_OSD_EIGCCARM_H
diff --git a/src/osd/eigccppc.h b/src/osd/eigccppc.h
index 56a4c65d5b1..b1f0fc638a7 100644
--- a/src/osd/eigccppc.h
+++ b/src/osd/eigccppc.h
@@ -22,7 +22,7 @@
multiply and return the full 64 bit result
-------------------------------------------------*/
-/* GCC can do a good job of this. */
+// GCC can do a good job of this.
/*-------------------------------------------------
@@ -31,7 +31,7 @@
result
-------------------------------------------------*/
-/* GCC can do a good job of this */
+// GCC can do a good job of this
/*-------------------------------------------------
@@ -40,21 +40,7 @@
result
-------------------------------------------------*/
-#define mul_32x32_hi _mul_32x32_hi
-static inline int32_t ATTR_CONST ATTR_FORCE_INLINE
-_mul_32x32_hi(int32_t val1, int32_t val2)
-{
- int32_t result;
-
- __asm__ (
- " mulhw %[result], %[val1], %[val2] \n"
- : [result] "=r" (result)
- : [val1] "%r" (val1)
- , [val2] "r" (val2)
- );
-
- return result;
-}
+// GCC can do a good job of this
/*-------------------------------------------------
@@ -63,21 +49,7 @@ _mul_32x32_hi(int32_t val1, int32_t val2)
of the result
-------------------------------------------------*/
-#define mulu_32x32_hi _mulu_32x32_hi
-static inline uint32_t ATTR_CONST ATTR_FORCE_INLINE
-_mulu_32x32_hi(uint32_t val1, uint32_t val2)
-{
- uint32_t result;
-
- __asm__ (
- " mulhwu %[result], %[val1], %[val2] \n"
- : [result] "=r" (result)
- : [val1] "%r" (val1)
- , [val2] "r" (val2)
- );
-
- return result;
-}
+// GCC can do a good job of this
/*-------------------------------------------------
@@ -89,27 +61,22 @@ _mulu_32x32_hi(uint32_t val1, uint32_t val2)
#if !defined(__ppc64__) && !defined(__PPC64__) && !defined(_ARCH_PPC64)
#define mul_32x32_shift _mul_32x32_shift
-static inline int32_t ATTR_CONST ATTR_FORCE_INLINE
+inline int32_t ATTR_CONST ATTR_FORCE_INLINE
_mul_32x32_shift(int32_t val1, int32_t val2, uint8_t shift)
{
- int32_t result;
+ uint32_t l, h;
- /* Valid for (0 <= shift <= 32) */
__asm__ (
- " mullw %[result], %[val1], %[val2] \n"
- " mulhw %[val1], %[val1], %[val2] \n"
- " srw %[result], %[result], %[shift] \n"
- " subfic %[shift], %[shift], 0x20 \n"
- " slw %[val1], %[val1], %[shift] \n"
- " or %[result], %[result], %[val1] \n"
- : [result] "=&r" (result)
- , [shift] "+r" (shift)
- , [val1] "+r" (val1)
- : [val2] "r" (val2)
- : "xer"
+ " mullw %[l], %[val1], %[val2] \n"
+ " mulhw %[h], %[val1], %[val2] \n"
+ : [l] "=&r" (l)
+ , [h] "=r" (h)
+ : [val1] "%r" (val1)
+ , [val2] "r" (val2)
);
- return result;
+ // Valid for (0 <= shift <= 31)
+ return int32_t((l >> shift) | (h << (32 - shift)));
}
#endif
@@ -123,27 +90,22 @@ _mul_32x32_shift(int32_t val1, int32_t val2, uint8_t shift)
#if !defined(__ppc64__) && !defined(__PPC64__) && !defined(_ARCH_PPC64)
#define mulu_32x32_shift _mulu_32x32_shift
-static inline uint32_t ATTR_CONST ATTR_FORCE_INLINE
+inline uint32_t ATTR_CONST ATTR_FORCE_INLINE
_mulu_32x32_shift(uint32_t val1, uint32_t val2, uint8_t shift)
{
- uint32_t result;
+ uint32_t l, h;
- /* Valid for (0 <= shift <= 32) */
__asm__ (
- " mullw %[result], %[val1], %[val2] \n"
- " mulhwu %[val1], %[val1], %[val2] \n"
- " srw %[result], %[result], %[shift] \n"
- " subfic %[shift], %[shift], 0x20 \n"
- " slw %[val1], %[val1], %[shift] \n"
- " or %[result], %[result], %[val1] \n"
- : [result] "=&r" (result)
- , [shift] "+r" (shift)
- , [val1] "+r" (val1)
- : [val2] "r" (val2)
- : "xer"
+ " mullw %[l], %[val1], %[val2] \n"
+ " mulhwu %[h], %[val1], %[val2] \n"
+ : [l] "=&r" (l)
+ , [h] "=r" (h)
+ : [val1] "%r" (val1)
+ , [val2] "r" (val2)
);
- return result;
+ // Valid for (0 <= shift <= 31)
+ return (l >> shift) | (h << (32 - shift));
}
#endif
@@ -153,7 +115,7 @@ _mulu_32x32_shift(uint32_t val1, uint32_t val2, uint8_t shift)
divide and return the 32 bit quotient
-------------------------------------------------*/
-/* TBD */
+// TBD
/*-------------------------------------------------
@@ -161,7 +123,7 @@ _mulu_32x32_shift(uint32_t val1, uint32_t val2, uint8_t shift)
divide and return the 32 bit quotient
-------------------------------------------------*/
-/* TBD */
+// TBD
/*-------------------------------------------------
@@ -170,7 +132,7 @@ _mulu_32x32_shift(uint32_t val1, uint32_t val2, uint8_t shift)
32 bit remainder
-------------------------------------------------*/
-/* TBD */
+// TBD
/*-------------------------------------------------
@@ -179,7 +141,7 @@ _mulu_32x32_shift(uint32_t val1, uint32_t val2, uint8_t shift)
and 32 bit remainder
-------------------------------------------------*/
-/* TBD */
+// TBD
/*-------------------------------------------------
@@ -188,7 +150,7 @@ _mulu_32x32_shift(uint32_t val1, uint32_t val2, uint8_t shift)
division, and returning the 32 bit quotient
-------------------------------------------------*/
-/* TBD */
+// TBD
/*-------------------------------------------------
@@ -197,7 +159,7 @@ _mulu_32x32_shift(uint32_t val1, uint32_t val2, uint8_t shift)
division, and returning the 32 bit quotient
-------------------------------------------------*/
-/* TBD */
+// TBD
/*-------------------------------------------------
@@ -205,7 +167,7 @@ _mulu_32x32_shift(uint32_t val1, uint32_t val2, uint8_t shift)
divide and return the 32 bit remainder
-------------------------------------------------*/
-/* TBD */
+// TBD
/*-------------------------------------------------
@@ -213,7 +175,7 @@ _mulu_32x32_shift(uint32_t val1, uint32_t val2, uint8_t shift)
divide and return the 32 bit remainder
-------------------------------------------------*/
-/* TBD */
+// TBD
/*-------------------------------------------------
@@ -222,7 +184,7 @@ _mulu_32x32_shift(uint32_t val1, uint32_t val2, uint8_t shift)
-------------------------------------------------*/
#define recip_approx _recip_approx
-static inline float ATTR_CONST ATTR_FORCE_INLINE
+inline float ATTR_CONST ATTR_FORCE_INLINE
_recip_approx(float value)
{
float result;
@@ -237,50 +199,130 @@ _recip_approx(float value)
}
+/*-------------------------------------------------
+ mul_64x64 - perform a signed 64 bit x 64 bit
+ multiply and return the full 128 bit result
+-------------------------------------------------*/
+
+#if defined(__ppc64__) || defined(__PPC64___) || defined(_ARCH_PPC64)
+#define mul_64x64 _mul_64x64
+inline int64_t ATTR_FORCE_INLINE
+_mul_64x64(int64_t a, int64_t b, int64_t &hi)
+{
+ __int128 const r(__int128(a) * b);
+ hi = int64_t(uint64_t((unsigned __int128)r >> 64));
+ return int64_t(uint64_t((unsigned __int128)r));
+}
+#endif
+
+
+/*-------------------------------------------------
+ mulu_64x64 - perform an unsigned 64 bit x 64
+ bit multiply and return the full 128 bit result
+-------------------------------------------------*/
+
+#if defined(__ppc64__) || defined(__PPC64___) || defined(_ARCH_PPC64)
+#define mulu_64x64 _mulu_64x64
+inline uint64_t ATTR_FORCE_INLINE
+_mulu_64x64(uint64_t a, uint64_t b, uint64_t &hi)
+{
+ unsigned __int128 const r((unsigned __int128)a * b);
+ hi = uint64_t(r >> 64);
+ return uint64_t(r);
+}
+#endif
+
+
/***************************************************************************
INLINE BIT MANIPULATION FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
- count_leading_zeros - return the number of
+ count_leading_zeros_32 - return the number of
leading zero bits in a 32-bit value
-------------------------------------------------*/
-#define count_leading_zeros _count_leading_zeros
-static inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
-_count_leading_zeros(uint32_t value)
+#define count_leading_zeros_32 _count_leading_zeros_32
+inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
+_count_leading_zeros_32(uint32_t value)
{
uint32_t result;
__asm__ (
" cntlzw %[result], %[value] \n"
- : [result] "=r" (result) /* result can be in any register */
- : [value] "r" (value) /* 'value' can be in any register */
+ : [result] "=r" (result)
+ : [value] "r" (value)
);
- return result;
+ return uint8_t(result);
}
/*-------------------------------------------------
- count_leading_ones - return the number of
+ count_leading_ones_32 - return the number of
leading one bits in a 32-bit value
-------------------------------------------------*/
-#define count_leading_ones _count_leading_ones
-static inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
-_count_leading_ones(uint32_t value)
+#define count_leading_ones_32 _count_leading_ones_32
+inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
+_count_leading_ones_32(uint32_t value)
{
uint32_t result;
__asm__ (
- " cntlzw %[result], %[result] \n"
- : [result] "=r" (result) /* result can be in any register */
- : [value] "r" (~value) /* 'value' can be in any register */
+ " cntlzw %[result], %[value] \n"
+ : [result] "=r" (result)
+ : [value] "r" (~value)
);
- return result;
+ return uint8_t(result);
}
+
+/*-------------------------------------------------
+ count_leading_zeros_64 - return the number of
+ leading zero bits in a 64-bit value
+-------------------------------------------------*/
+
+#if defined(__ppc64__) || defined(__PPC64___) || defined(_ARCH_PPC64)
+#define count_leading_zeros_64 _count_leading_zeros_64
+inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
+_count_leading_zeros_64(uint64_t value)
+{
+ uint64_t result;
+
+ __asm__ (
+ " cntlzd %[result], %[value] \n"
+ : [result] "=r" (result)
+ : [value] "r" (value)
+ );
+
+ return uint8_t(result);
+}
+#endif
+
+
+/*-------------------------------------------------
+ count_leading_ones_64 - return the number of
+ leading one bits in a 64-bit value
+-------------------------------------------------*/
+
+#if defined(__ppc64__) || defined(__PPC64___) || defined(_ARCH_PPC64)
+#define count_leading_ones_64 _count_leading_ones_64
+inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
+_count_leading_ones_64(uint64_t value)
+{
+ uint64_t result;
+
+ __asm__ (
+ " cntlzd %[result], %[value] \n"
+ : [result] "=r" (result)
+ : [value] "r" (~value)
+ );
+
+ return uint8_t(result);
+}
+#endif
+
#endif // MAME_OSD_EIGCCPPC_H
diff --git a/src/osd/eigccx86.h b/src/osd/eigccx86.h
index 3c8f63aa47e..39fa7df80a6 100644
--- a/src/osd/eigccx86.h
+++ b/src/osd/eigccx86.h
@@ -15,7 +15,7 @@
// Include MMX/SSE intrinsics headers
#ifdef __SSE2__
-#include <stdlib.h>
+#include <cstdlib>
#include <mmintrin.h> // MMX
#include <xmmintrin.h> // SSE
#include <emmintrin.h> // SSE2
@@ -31,22 +31,7 @@
multiply and return the full 64 bit result
-------------------------------------------------*/
-#ifndef __x86_64__
-#define mul_32x32 _mul_32x32
-inline int64_t ATTR_CONST ATTR_FORCE_INLINE
-_mul_32x32(int32_t a, int32_t b)
-{
- int64_t result;
- __asm__ (
- " imull %[b] ;"
- : [result] "=A" (result) // result in edx:eax
- : [a] "%a" (a) // 'a' should also be in eax on entry
- , [b] "rm" (b) // 'b' can be memory or register
- : "cc" // Clobbers condition codes
- );
- return result;
-}
-#endif
+// GCC can do a good job of this.
/*-------------------------------------------------
@@ -55,22 +40,7 @@ _mul_32x32(int32_t a, int32_t b)
result
-------------------------------------------------*/
-#ifndef __x86_64__
-#define mulu_32x32 _mulu_32x32
-inline uint64_t ATTR_CONST ATTR_FORCE_INLINE
-_mulu_32x32(uint32_t a, uint32_t b)
-{
- uint64_t result;
- __asm__ (
- " mull %[b] ;"
- : [result] "=A" (result) // result in edx:eax
- : [a] "%a" (a) // 'a' should also be in eax on entry
- , [b] "rm" (b) // 'b' can be memory or register
- : "cc" // Clobbers condition codes
- );
- return result;
-}
-#endif
+// GCC can do a good job of this.
/*-------------------------------------------------
@@ -79,21 +49,7 @@ _mulu_32x32(uint32_t a, uint32_t b)
result
-------------------------------------------------*/
-#define mul_32x32_hi _mul_32x32_hi
-inline int32_t ATTR_CONST ATTR_FORCE_INLINE
-_mul_32x32_hi(int32_t a, int32_t b)
-{
- int32_t result, temp;
- __asm__ (
- " imull %[b] ;"
- : [result] "=d" (result) // result in edx
- , [temp] "=a" (temp) // This is effectively a clobber
- : [a] "a" (a) // 'a' should be in eax on entry
- , [b] "rm" (b) // 'b' can be memory or register
- : "cc" // Clobbers condition codes
- );
- return result;
-}
+// GCC can do a good job of this.
/*-------------------------------------------------
@@ -102,21 +58,7 @@ _mul_32x32_hi(int32_t a, int32_t b)
of the result
-------------------------------------------------*/
-#define mulu_32x32_hi _mulu_32x32_hi
-inline uint32_t ATTR_CONST ATTR_FORCE_INLINE
-_mulu_32x32_hi(uint32_t a, uint32_t b)
-{
- uint32_t result, temp;
- __asm__ (
- " mull %[b] ;"
- : [result] "=d" (result) // result in edx
- , [temp] "=a" (temp) // This is effectively a clobber
- : [a] "a" (a) // 'a' should be in eax on entry
- , [b] "rm" (b) // 'b' can be memory or register
- : "cc" // Clobbers condition codes
- );
- return result;
-}
+// GCC can do a good job of this.
/*-------------------------------------------------
@@ -241,21 +183,19 @@ _divu_64x32(uint64_t a, uint32_t b)
#define div_64x32_rem _div_64x32_rem
inline int32_t ATTR_FORCE_INLINE
-_div_64x32_rem(int64_t dividend, int32_t divisor, int32_t *remainder)
+_div_64x32_rem(int64_t dividend, int32_t divisor, int32_t &remainder)
{
int32_t quotient;
#ifndef __x86_64__
-
// Throws arithmetic exception if result doesn't fit in 32 bits
__asm__ (
" idivl %[divisor] ;"
: [result] "=a" (quotient) // quotient ends up in eax
- , [remainder] "=d" (*remainder) // remainder ends up in edx
+ , [remainder] "=d" (remainder) // remainder ends up in edx
: [dividend] "A" (dividend) // 'dividend' in edx:eax
, [divisor] "rm" (divisor) // 'divisor' in register or memory
: "cc" // clobbers condition codes
);
-
#else
int32_t const divh{ int32_t(uint32_t(uint64_t(dividend) >> 32)) };
int32_t const divl{ int32_t(uint32_t(uint64_t(dividend))) };
@@ -264,13 +204,12 @@ _div_64x32_rem(int64_t dividend, int32_t divisor, int32_t *remainder)
__asm__ (
" idivl %[divisor] ;"
: [result] "=a" (quotient) // quotient ends up in eax
- , [remainder] "=d" (*remainder) // remainder ends up in edx
+ , [remainder] "=d" (remainder) // remainder ends up in edx
: [divl] "a" (divl) // 'dividend' in edx:eax
, [divh] "d" (divh)
, [divisor] "rm" (divisor) // 'divisor' in register or memory
: "cc" // clobbers condition codes
);
-
#endif
return quotient;
}
@@ -284,21 +223,19 @@ _div_64x32_rem(int64_t dividend, int32_t divisor, int32_t *remainder)
#define divu_64x32_rem _divu_64x32_rem
inline uint32_t ATTR_FORCE_INLINE
-_divu_64x32_rem(uint64_t dividend, uint32_t divisor, uint32_t *remainder)
+_divu_64x32_rem(uint64_t dividend, uint32_t divisor, uint32_t &remainder)
{
uint32_t quotient;
#ifndef __x86_64__
-
// Throws arithmetic exception if result doesn't fit in 32 bits
__asm__ (
" divl %[divisor] ;"
: [result] "=a" (quotient) // quotient ends up in eax
- , [remainder] "=d" (*remainder) // remainder ends up in edx
+ , [remainder] "=d" (remainder) // remainder ends up in edx
: [dividend] "A" (dividend) // 'dividend' in edx:eax
, [divisor] "rm" (divisor) // 'divisor' in register or memory
: "cc" // clobbers condition codes
);
-
#else
uint32_t const divh{ uint32_t(dividend >> 32) };
uint32_t const divl{ uint32_t(dividend) };
@@ -307,7 +244,7 @@ _divu_64x32_rem(uint64_t dividend, uint32_t divisor, uint32_t *remainder)
__asm__ (
" divl %[divisor] ;"
: [result] "=a" (quotient) // quotient ends up in eax
- , [remainder] "=d" (*remainder) // remainder ends up in edx
+ , [remainder] "=d" (remainder) // remainder ends up in edx
: [divl] "a" (divl) // 'dividend' in edx:eax
, [divh] "d" (divh)
, [divisor] "rm" (divisor) // 'divisor' in register or memory
@@ -444,11 +381,11 @@ _modu_64x32(uint64_t a, uint32_t b)
#ifdef __SSE2__
#define recip_approx _recip_approx
-inline float ATTR_CONST
+inline float ATTR_CONST ATTR_FORCE_INLINE
_recip_approx(float value)
{
- __m128 const value_xmm = _mm_set_ss(value);
- __m128 const result_xmm = _mm_rcp_ss(value_xmm);
+ __m128 const value_xmm(_mm_set_ss(value));
+ __m128 const result_xmm(_mm_rcp_ss(value_xmm));
float result;
_mm_store_ss(&result, result_xmm);
return result;
@@ -464,10 +401,10 @@ _recip_approx(float value)
#ifdef __x86_64__
#define mul_64x64 _mul_64x64
inline int64_t ATTR_FORCE_INLINE
-_mul_64x64(int64_t a, int64_t b, int64_t *hi)
+_mul_64x64(int64_t a, int64_t b, int64_t &hi)
{
__int128 const r(__int128(a) * b);
- *hi = int64_t(uint64_t((unsigned __int128)r >> 64));
+ hi = int64_t(uint64_t((unsigned __int128)r >> 64));
return int64_t(uint64_t((unsigned __int128)r));
}
#endif
@@ -481,10 +418,10 @@ _mul_64x64(int64_t a, int64_t b, int64_t *hi)
#ifdef __x86_64__
#define mulu_64x64 _mulu_64x64
inline uint64_t ATTR_FORCE_INLINE
-_mulu_64x64(uint64_t a, uint64_t b, uint64_t *hi)
+_mulu_64x64(uint64_t a, uint64_t b, uint64_t &hi)
{
unsigned __int128 const r((unsigned __int128)a * b);
- *hi = uint64_t(r >> 64);
+ hi = uint64_t(r >> 64);
return uint64_t(r);
}
#endif
@@ -496,13 +433,13 @@ _mulu_64x64(uint64_t a, uint64_t b, uint64_t *hi)
***************************************************************************/
/*-------------------------------------------------
- count_leading_zeros - return the number of
+ count_leading_zeros_32 - return the number of
leading zero bits in a 32-bit value
-------------------------------------------------*/
-#define count_leading_zeros _count_leading_zeros
+#define count_leading_zeros_32 _count_leading_zeros_32
inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
-_count_leading_zeros(uint32_t value)
+_count_leading_zeros_32(uint32_t value)
{
uint32_t result;
__asm__ (
@@ -513,18 +450,18 @@ _count_leading_zeros(uint32_t value)
, [bias] "rm" (~uint32_t(0)) // 'bias' can be register or memory
: "cc" // clobbers condition codes
);
- return 31U - result;
+ return uint8_t(31U - result);
}
/*-------------------------------------------------
- count_leading_ones - return the number of
+ count_leading_ones_32 - return the number of
leading one bits in a 32-bit value
-------------------------------------------------*/
-#define count_leading_ones _count_leading_ones
+#define count_leading_ones_32 _count_leading_ones_32
inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
-_count_leading_ones(uint32_t value)
+_count_leading_ones_32(uint32_t value)
{
uint32_t result;
__asm__ (
@@ -535,7 +472,143 @@ _count_leading_ones(uint32_t value)
, [bias] "rm" (~uint32_t(0)) // 'bias' can be register or memory
: "cc" // clobbers condition codes
);
- return 31U - result;
+ return uint8_t(31U - result);
+}
+
+
+/*-------------------------------------------------
+ count_leading_zeros_64 - return the number of
+ leading zero bits in a 64-bit value
+-------------------------------------------------*/
+
+#ifdef __x86_64__
+#define count_leading_zeros_64 _count_leading_zeros_64
+inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
+_count_leading_zeros_64(uint64_t value)
+{
+ uint64_t result;
+ __asm__ (
+ " bsrq %[value], %[result] ;"
+ " cmovzq %[bias], %[result] ;"
+ : [result] "=&r" (result) // result can be in any register
+ : [value] "rm" (value) // 'value' can be register or memory
+ , [bias] "rm" (~uint64_t(0)) // 'bias' can be register or memory
+ : "cc" // clobbers condition codes
+ );
+ return uint8_t(63U - result);
}
+#endif
+
+
+/*-------------------------------------------------
+ count_leading_ones_64 - return the number of
+ leading one bits in a 64-bit value
+-------------------------------------------------*/
+
+#ifdef __x86_64__
+#define count_leading_ones_64 _count_leading_ones_64
+inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
+_count_leading_ones_64(uint64_t value)
+{
+ uint64_t result;
+ __asm__ (
+ " bsrq %[value], %[result] ;"
+ " cmovzq %[bias], %[result] ;"
+ : [result] "=&r" (result) // result can be in any register
+ : [value] "rm" (~value) // 'value' can be register or memory
+ , [bias] "rm" (~uint64_t(0)) // 'bias' can be register or memory
+ : "cc" // clobbers condition codes
+ );
+ return uint8_t(63U - result);
+}
+#endif
+
+
+/*-------------------------------------------------
+ rotl_32 - circularly shift a 32-bit value left
+ by the specified number of bits (modulo 32)
+-------------------------------------------------*/
+
+#define rotl_32 _rotl_32
+inline uint32_t ATTR_CONST ATTR_FORCE_INLINE
+_rotl_32(uint32_t val, int shift)
+{
+ uint32_t result;
+ __asm__ (
+ " roll %[shift], %[value] ;"
+ : [result] "=rm" (result) // result can be in register or memory
+ : [value] "%0" (val) // 'value' is updated with result
+ , [shift] "Ic" (uint8_t(unsigned(shift))) // 'shift' must be constant in 0-31 range or in cl
+ : "cc" // clobbers condition codes
+ );
+ return result;
+}
+
+
+/*-------------------------------------------------
+ rotr_32 - circularly shift a 32-bit value right
+ by the specified number of bits (modulo 32)
+-------------------------------------------------*/
+
+#define rotr_32 _rotr_32
+inline uint32_t ATTR_CONST ATTR_FORCE_INLINE
+rotr_32(uint32_t val, int shift)
+{
+ uint32_t result;
+ __asm__ (
+ " rorl %[shift], %[value] ;"
+ : [result] "=rm" (result) // result can be in register or memory
+ : [value] "%0" (val) // 'value' is updated with result
+ , [shift] "Ic" (uint8_t(unsigned(shift))) // 'shift' must be constant in 0-31 range or in cl
+ : "cc" // clobbers condition codes
+ );
+ return result;
+}
+
+
+/*-------------------------------------------------
+ rotl_64 - circularly shift a 64-bit value left
+ by the specified number of bits (modulo 64)
+-------------------------------------------------*/
+
+#ifdef __x86_64__
+#define rotl_64 _rotl_64
+inline uint64_t ATTR_CONST ATTR_FORCE_INLINE
+_rotl_64(uint64_t val, int shift)
+{
+ uint64_t result;
+ __asm__ (
+ " rolq %[shift], %[value] ;"
+ : [result] "=rm" (result) // result can be in register or memory
+ : [value] "%0" (val) // 'value' is updated with result
+ , [shift] "Jc" (uint8_t(unsigned(shift))) // 'shift' must be constant in 0-63 range or in cl
+ : "cc" // clobbers condition codes
+ );
+ return result;
+}
+#endif
+
+
+/*-------------------------------------------------
+ rotr_64 - circularly shift a 64-bit value right
+ by the specified number of bits (modulo 64)
+-------------------------------------------------*/
+
+#ifdef __x86_64__
+#define rotr_64 _rotr_64
+inline uint64_t ATTR_CONST ATTR_FORCE_INLINE
+rotr_64(uint64_t val, int shift)
+{
+ uint64_t result;
+ __asm__ (
+ " rorq %[shift], %[value] ;"
+ : [result] "=rm" (result) // result can be in register or memory
+ : [value] "%0" (val) // 'value' is updated with result
+ , [shift] "Jc" (uint8_t(unsigned(shift))) // 'shift' must be constant in 0-63 range or in cl
+ : "cc" // clobbers condition codes
+ );
+ return result;
+}
+#endif
#endif // MAME_OSD_EIGCCX86_H
diff --git a/src/osd/eivc.h b/src/osd/eivc.h
index 3fa34f51b3c..5c41726d2b1 100644
--- a/src/osd/eivc.h
+++ b/src/osd/eivc.h
@@ -14,21 +14,27 @@
#pragma once
#include <intrin.h>
+#include <stdlib.h>
+
#pragma intrinsic(_BitScanReverse)
+#if defined(_M_X64) || defined(_M_ARM64)
+#pragma intrinsic(_BitScanReverse64)
+#endif
+
/***************************************************************************
INLINE BIT MANIPULATION FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
- count_leading_zeros - return the number of
+ count_leading_zeros_32 - return the number of
leading zero bits in a 32-bit value
-------------------------------------------------*/
-#ifndef count_leading_zeros
-#define count_leading_zeros _count_leading_zeros
-inline uint8_t _count_leading_zeros(uint32_t value)
+#ifndef count_leading_zeros_32
+#define count_leading_zeros_32 _count_leading_zeros_32
+__forceinline uint8_t _count_leading_zeros_32(uint32_t value)
{
unsigned long index;
return _BitScanReverse(&index, value) ? (31U - index) : 32U;
@@ -37,17 +43,95 @@ inline uint8_t _count_leading_zeros(uint32_t value)
/*-------------------------------------------------
- count_leading_ones - return the number of
+ count_leading_ones_32 - return the number of
leading one bits in a 32-bit value
-------------------------------------------------*/
-#ifndef count_leading_ones
-#define count_leading_ones _count_leading_ones
-inline uint8_t _count_leading_ones(uint32_t value)
+#ifndef count_leading_ones_32
+#define count_leading_ones_32 _count_leading_ones_32
+__forceinline uint8_t _count_leading_ones_32(uint32_t value)
{
unsigned long index;
return _BitScanReverse(&index, ~value) ? (31U - index) : 32U;
}
#endif
+
+/*-------------------------------------------------
+ count_leading_zeros_64 - return the number of
+ leading zero bits in a 64-bit value
+-------------------------------------------------*/
+
+#ifndef count_leading_zeros_64
+#define count_leading_zeros_64 _count_leading_zeros_64
+__forceinline uint8_t _count_leading_zeros_64(uint64_t value)
+{
+ unsigned long index;
+#if defined(_M_X64) || defined(_M_ARM64)
+ return _BitScanReverse64(&index, value) ? (63U - index) : 64U;
+#else
+ return _BitScanReverse(&index, uint32_t(value >> 32)) ? (31U - index) : _BitScanReverse(&index, uint32_t(value)) ? (63U - index) : 64U;
+#endif
+}
+#endif
+
+
+/*-------------------------------------------------
+ count_leading_ones_64 - return the number of
+ leading one bits in a 64-bit value
+-------------------------------------------------*/
+
+#ifndef count_leading_ones_64
+#define count_leading_ones_64 _count_leading_ones_64
+__forceinline uint8_t _count_leading_ones_64(uint64_t value)
+{
+ unsigned long index;
+#if defined(_M_X64) || defined(_M_ARM64)
+ return _BitScanReverse64(&index, ~value) ? (63U - index) : 64U;
+#else
+ return _BitScanReverse(&index, ~uint32_t(value >> 32)) ? (31U - index) : _BitScanReverse(&index, ~uint32_t(value)) ? (63U - index) : 64U;
+#endif
+}
+#endif
+
+
+/*-------------------------------------------------
+ rotl_32 - circularly shift a 32-bit value left
+ by the specified number of bits (modulo 32)
+-------------------------------------------------*/
+
+#ifndef rotl_32
+#define rotl_32 _rotl
+#endif
+
+
+/*-------------------------------------------------
+ rotr_32 - circularly shift a 32-bit value right
+ by the specified number of bits (modulo 32)
+-------------------------------------------------*/
+
+#ifndef rotr_32
+#define rotr_32 _rotr
+#endif
+
+
+/*-------------------------------------------------
+ rotl_64 - circularly shift a 64-bit value left
+ by the specified number of bits (modulo 64)
+-------------------------------------------------*/
+
+#ifndef rotl_64
+#define rotl_64 _rotl64
+#endif
+
+
+/*-------------------------------------------------
+ rotr_64 - circularly shift a 64-bit value right
+ by the specified number of bits (modulo 64)
+-------------------------------------------------*/
+
+#ifndef rotr_64
+#define rotr_64 _rotr64
+#endif
+
#endif // MAME_OSD_EIVC_H
diff --git a/src/osd/eivcarm.h b/src/osd/eivcarm.h
new file mode 100644
index 00000000000..5e612cb25fb
--- /dev/null
+++ b/src/osd/eivcarm.h
@@ -0,0 +1,75 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+//============================================================
+//
+// eivcarm.h
+//
+// ARM/AArch64 inline implementations for MSVC compiler.
+//
+//============================================================
+
+#ifndef MAME_OSD_EIVCARM_H
+#define MAME_OSD_EIVCARM_H
+
+#pragma once
+
+#include <intrin.h>
+
+#pragma intrinsic(_CountLeadingZeros)
+#pragma intrinsic(_CountLeadingZeros64)
+#pragma intrinsic(_CountLeadingOnes)
+#pragma intrinsic(_CountLeadingOnes64)
+
+
+/***************************************************************************
+ INLINE BIT MANIPULATION FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ count_leading_zeros_32 - return the number of
+ leading zero bits in a 32-bit value
+-------------------------------------------------*/
+
+#define count_leading_zeros_32 _count_leading_zeros_32
+__forceinline uint8_t _count_leading_zeros_32(uint32_t value)
+{
+ return uint8_t(_CountLeadingZeros(value));
+}
+
+
+/*-------------------------------------------------
+ count_leading_ones_32 - return the number of
+ leading one bits in a 32-bit value
+-------------------------------------------------*/
+
+#define count_leading_ones_32 _count_leading_ones_32
+__forceinline uint8_t _count_leading_ones_32(uint32_t value)
+{
+ return uint8_t(_CountLeadingOnes(value));
+}
+
+
+/*-------------------------------------------------
+ count_leading_zeros_64 - return the number of
+ leading zero bits in a 64-bit value
+-------------------------------------------------*/
+
+#define count_leading_zeros_64 _count_leading_zeros_64
+__forceinline uint8_t _count_leading_zeros_64(uint64_t value)
+{
+ return uint8_t(_CountLeadingZeros64(value));
+}
+
+
+/*-------------------------------------------------
+ count_leading_ones_64 - return the number of
+ leading one bits in a 64-bit value
+-------------------------------------------------*/
+
+#define count_leading_ones_64 _count_leading_ones_64
+__forceinline uint8_t _count_leading_ones_64(uint64_t value)
+{
+ return uint8_t(_CountLeadingOnes64(value));
+}
+
+#endif // MAME_OSD_EIVCARM_H
diff --git a/src/osd/eivcx86.h b/src/osd/eivcx86.h
index 3fd3e70948c..f6c4c90d9a2 100644
--- a/src/osd/eivcx86.h
+++ b/src/osd/eivcx86.h
@@ -13,11 +13,12 @@
#pragma once
-#ifdef PTR64
+#if defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP >= 2))
#include <emmintrin.h>
-#include <intrin.h>
#endif
+#include <intrin.h>
+
/***************************************************************************
INLINE MATH FUNCTIONS
@@ -28,9 +29,9 @@
multiply and return the full 64 bit result
-------------------------------------------------*/
-#ifndef PTR64
+#ifndef _M_X64
#define mul_32x32 _mul_32x32
-static inline int64_t _mul_32x32(int32_t a, int32_t b)
+inline int64_t _mul_32x32(int32_t a, int32_t b)
{
// in theory this should work, but it is untested
__asm
@@ -49,9 +50,9 @@ static inline int64_t _mul_32x32(int32_t a, int32_t b)
result
-------------------------------------------------*/
-#ifndef PTR64
+#ifndef _M_X64
#define mulu_32x32 _mulu_32x32
-static inline uint64_t _mulu_32x32(uint32_t a, uint32_t b)
+inline uint64_t _mulu_32x32(uint32_t a, uint32_t b)
{
// in theory this should work, but it is untested
__asm
@@ -70,9 +71,9 @@ static inline uint64_t _mulu_32x32(uint32_t a, uint32_t b)
result
-------------------------------------------------*/
-#ifndef PTR64
+#ifndef _M_X64
#define mul_32x32_hi _mul_32x32_hi
-static inline int32_t _mul_32x32_hi(int32_t a, int32_t b)
+inline int32_t _mul_32x32_hi(int32_t a, int32_t b)
{
int32_t result;
@@ -94,9 +95,9 @@ static inline int32_t _mul_32x32_hi(int32_t a, int32_t b)
of the result
-------------------------------------------------*/
-#ifndef PTR64
+#ifndef _M_X64
#define mulu_32x32_hi _mulu_32x32_hi
-static inline uint32_t _mulu_32x32_hi(uint32_t a, uint32_t b)
+inline uint32_t _mulu_32x32_hi(uint32_t a, uint32_t b)
{
int32_t result;
@@ -119,7 +120,7 @@ static inline uint32_t _mulu_32x32_hi(uint32_t a, uint32_t b)
result to 32 bits
-------------------------------------------------*/
-#ifndef PTR64
+#ifndef _M_X64
#define mul_32x32_shift _mul_32x32_shift
static inline int32_t _mul_32x32_shift(int32_t a, int32_t b, uint8_t shift)
{
@@ -146,9 +147,9 @@ static inline int32_t _mul_32x32_shift(int32_t a, int32_t b, uint8_t shift)
result to 32 bits
-------------------------------------------------*/
-#ifndef PTR64
+#ifndef _M_X64
#define mulu_32x32_shift _mulu_32x32_shift
-static inline uint32_t _mulu_32x32_shift(uint32_t a, uint32_t b, uint8_t shift)
+inline uint32_t _mulu_32x32_shift(uint32_t a, uint32_t b, uint8_t shift)
{
int32_t result;
@@ -171,9 +172,9 @@ static inline uint32_t _mulu_32x32_shift(uint32_t a, uint32_t b, uint8_t shift)
divide and return the 32 bit quotient
-------------------------------------------------*/
-#ifndef PTR64
+#ifndef _M_X64
#define div_64x32 _div_64x32
-static inline int32_t _div_64x32(int64_t a, int32_t b)
+inline int32_t _div_64x32(int64_t a, int32_t b)
{
int32_t result;
int32_t alow = a;
@@ -197,9 +198,9 @@ static inline int32_t _div_64x32(int64_t a, int32_t b)
divide and return the 32 bit quotient
-------------------------------------------------*/
-#ifndef PTR64
+#ifndef _M_X64
#define divu_64x32 _divu_64x32
-static inline uint32_t _divu_64x32(uint64_t a, uint32_t b)
+inline uint32_t _divu_64x32(uint64_t a, uint32_t b)
{
uint32_t result;
uint32_t alow = a;
@@ -224,9 +225,9 @@ static inline uint32_t _divu_64x32(uint64_t a, uint32_t b)
32 bit remainder
-------------------------------------------------*/
-#ifndef PTR64
+#ifndef _M_X64
#define div_64x32_rem _div_64x32_rem
-static inline int32_t _div_64x32_rem(int64_t a, int32_t b, int32_t *remainder)
+inline int32_t _div_64x32_rem(int64_t a, int32_t b, int32_t &remainder)
{
int32_t result;
int32_t alow = a;
@@ -242,7 +243,7 @@ static inline int32_t _div_64x32_rem(int64_t a, int32_t b, int32_t *remainder)
mov rem,edx
}
- *remainder = rem;
+ remainder = rem;
return result;
}
#endif
@@ -254,9 +255,9 @@ static inline int32_t _div_64x32_rem(int64_t a, int32_t b, int32_t *remainder)
and 32 bit remainder
-------------------------------------------------*/
-#ifndef PTR64
+#ifndef _M_X64
#define divu_64x32_rem _divu_64x32_rem
-static inline uint32_t _divu_64x32_rem(uint64_t a, uint32_t b, uint32_t *remainder)
+inline uint32_t _divu_64x32_rem(uint64_t a, uint32_t b, uint32_t &remainder)
{
uint32_t result;
uint32_t alow = a;
@@ -272,7 +273,7 @@ static inline uint32_t _divu_64x32_rem(uint64_t a, uint32_t b, uint32_t *remaind
mov rem,edx
}
- *remainder = rem;
+ remainder = rem;
return result;
}
#endif
@@ -284,9 +285,9 @@ static inline uint32_t _divu_64x32_rem(uint64_t a, uint32_t b, uint32_t *remaind
division, and returning the 32 bit quotient
-------------------------------------------------*/
-#ifndef PTR64
+#ifndef _M_X64
#define div_32x32_shift _div_32x32_shift
-static inline int32_t _div_32x32_shift(int32_t a, int32_t b, uint8_t shift)
+inline int32_t _div_32x32_shift(int32_t a, int32_t b, uint8_t shift)
{
int32_t result;
@@ -312,9 +313,9 @@ static inline int32_t _div_32x32_shift(int32_t a, int32_t b, uint8_t shift)
division, and returning the 32 bit quotient
-------------------------------------------------*/
-#ifndef PTR64
+#ifndef _M_X64
#define divu_32x32_shift _divu_32x32_shift
-static inline uint32_t _divu_32x32_shift(uint32_t a, uint32_t b, uint8_t shift)
+inline uint32_t _divu_32x32_shift(uint32_t a, uint32_t b, uint8_t shift)
{
uint32_t result;
@@ -339,7 +340,7 @@ static inline uint32_t _divu_32x32_shift(uint32_t a, uint32_t b, uint8_t shift)
divide and return the 32 bit remainder
-------------------------------------------------*/
-#ifndef PTR64
+#ifndef _M_X64
#define mod_64x32 _mod_64x32
static inline int32_t _mod_64x32(int64_t a, int32_t b)
{
@@ -365,9 +366,9 @@ static inline int32_t _mod_64x32(int64_t a, int32_t b)
divide and return the 32 bit remainder
-------------------------------------------------*/
-#ifndef PTR64
+#ifndef _M_X64
#define modu_64x32 _modu_64x32
-static inline uint32_t _modu_64x32(uint64_t a, uint32_t b)
+inline uint32_t _modu_64x32(uint64_t a, uint32_t b)
{
uint32_t result;
uint32_t alow = a;
@@ -391,9 +392,9 @@ static inline uint32_t _modu_64x32(uint64_t a, uint32_t b)
point reciprocal
-------------------------------------------------*/
-#ifdef PTR64
+#if defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP >= 2))
#define recip_approx _recip_approx
-static inline float _recip_approx(float z)
+inline float _recip_approx(float z)
{
__m128 const mz = _mm_set_ss(z);
__m128 const mooz = _mm_rcp_ss(mz);
@@ -409,8 +410,12 @@ static inline float _recip_approx(float z)
multiply and return the full 128 bit result
-------------------------------------------------*/
-#ifdef PTR64
-#define mul_64x64 _mul128
+#ifdef _M_X64
+#define mul_64x64 _mul_64x64
+__forceinline int64_t _mul_64x64(int64_t a, int64_t b, int64_t &hi)
+{
+ return _mul128(a, b, &hi);
+}
#endif
@@ -419,8 +424,45 @@ static inline float _recip_approx(float z)
bit multiply and return the full 128 bit result
-------------------------------------------------*/
-#ifdef PTR64
-#define mulu_64x64 _umul128
+#ifdef _M_X64
+#define mulu_64x64 _mulu_64x64
+__forceinline int64_t _mulu_64x64(uint64_t a, uint64_t b, uint64_t &hi)
+{
+ return _umul128(a, b, &hi);
+}
#endif
+
+/*-------------------------------------------------
+ addu_32x32_co - perform an unsigned 32 bit + 32
+ bit addition and return the result with carry
+ out
+-------------------------------------------------*/
+
+#define addu_32x32_co _addu_32x32_co
+__forceinline bool _addu_32x32_co(uint32_t a, uint32_t b, uint32_t &sum)
+{
+ return _addcarry_u32(0, a, b, &sum);
+}
+
+
+/*-------------------------------------------------
+ addu_64x64_co - perform an unsigned 64 bit + 64
+ bit addition and return the result with carry
+ out
+-------------------------------------------------*/
+
+#define addu_64x64_co _addu_64x64_co
+__forceinline bool _addu_64x64_co(uint64_t a, uint64_t b, uint64_t &sum)
+{
+#ifdef _M_X64
+ return _addcarry_u64(0, a, b, &sum);
+#else
+ uint32_t l, h;
+ bool const result = _addcarry_u32(_addcarry_u32(0, uint32_t(a), uint32_t(b), &l), uint32_t(a >> 32), uint32_t(b >> 32), &h);
+ sum = (uint64_t(h) << 32) | l;
+ return result;
+#endif
+}
+
#endif // MAME_OSD_EIVCX86_H
diff --git a/src/osd/eminline.h b/src/osd/eminline.h
index eb8ffaa9748..6d54a21a45f 100644
--- a/src/osd/eminline.h
+++ b/src/osd/eminline.h
@@ -25,22 +25,22 @@
#include "eigccx86.h"
#elif defined(__ppc__) || defined (__PPC__) || defined(__ppc64__) || defined(__PPC64__)
#include "eigccppc.h"
-#else
-#error "no matching assembler implementations found - please compile with NOASM=1"
+#elif defined(__arm__) || defined(__aarch64__)
+#include "eigccarm.h"
#endif
+#include "eigcc.h"
+
#elif defined(_MSC_VER)
-#if (defined(_M_IX86) || defined(_M_X64))
+#if defined(_M_IX86) || defined(_M_X64)
#include "eivcx86.h"
+#elif defined(_M_ARM) || defined(_M_ARM64)
+#include "eivcarm.h"
#endif
#include "eivc.h"
-#else
-
-#error "no matching assembler implementations found - please compile with NOASM=1"
-
#endif
#endif // !defined(MAME_NOASM)
@@ -56,7 +56,7 @@
-------------------------------------------------*/
#ifndef mul_32x32
-inline int64_t mul_32x32(int32_t a, int32_t b)
+constexpr int64_t mul_32x32(int32_t a, int32_t b)
{
return int64_t(a) * int64_t(b);
}
@@ -70,7 +70,7 @@ inline int64_t mul_32x32(int32_t a, int32_t b)
-------------------------------------------------*/
#ifndef mulu_32x32
-inline uint64_t mulu_32x32(uint32_t a, uint32_t b)
+constexpr uint64_t mulu_32x32(uint32_t a, uint32_t b)
{
return uint64_t(a) * uint64_t(b);
}
@@ -84,7 +84,7 @@ inline uint64_t mulu_32x32(uint32_t a, uint32_t b)
-------------------------------------------------*/
#ifndef mul_32x32_hi
-inline int32_t mul_32x32_hi(int32_t a, int32_t b)
+constexpr int32_t mul_32x32_hi(int32_t a, int32_t b)
{
return uint32_t((int64_t(a) * int64_t(b)) >> 32);
}
@@ -98,7 +98,7 @@ inline int32_t mul_32x32_hi(int32_t a, int32_t b)
-------------------------------------------------*/
#ifndef mulu_32x32_hi
-inline uint32_t mulu_32x32_hi(uint32_t a, uint32_t b)
+constexpr uint32_t mulu_32x32_hi(uint32_t a, uint32_t b)
{
return uint32_t((uint64_t(a) * uint64_t(b)) >> 32);
}
@@ -113,7 +113,7 @@ inline uint32_t mulu_32x32_hi(uint32_t a, uint32_t b)
-------------------------------------------------*/
#ifndef mul_32x32_shift
-inline int32_t mul_32x32_shift(int32_t a, int32_t b, uint8_t shift)
+constexpr int32_t mul_32x32_shift(int32_t a, int32_t b, uint8_t shift)
{
return int32_t((int64_t(a) * int64_t(b)) >> shift);
}
@@ -128,7 +128,7 @@ inline int32_t mul_32x32_shift(int32_t a, int32_t b, uint8_t shift)
-------------------------------------------------*/
#ifndef mulu_32x32_shift
-inline uint32_t mulu_32x32_shift(uint32_t a, uint32_t b, uint8_t shift)
+constexpr uint32_t mulu_32x32_shift(uint32_t a, uint32_t b, uint8_t shift)
{
return uint32_t((uint64_t(a) * uint64_t(b)) >> shift);
}
@@ -141,7 +141,7 @@ inline uint32_t mulu_32x32_shift(uint32_t a, uint32_t b, uint8_t shift)
-------------------------------------------------*/
#ifndef div_64x32
-inline int32_t div_64x32(int64_t a, int32_t b)
+constexpr int32_t div_64x32(int64_t a, int32_t b)
{
return a / int64_t(b);
}
@@ -154,7 +154,7 @@ inline int32_t div_64x32(int64_t a, int32_t b)
-------------------------------------------------*/
#ifndef divu_64x32
-inline uint32_t divu_64x32(uint64_t a, uint32_t b)
+constexpr uint32_t divu_64x32(uint64_t a, uint32_t b)
{
return a / uint64_t(b);
}
@@ -168,10 +168,10 @@ inline uint32_t divu_64x32(uint64_t a, uint32_t b)
-------------------------------------------------*/
#ifndef div_64x32_rem
-inline int32_t div_64x32_rem(int64_t a, int32_t b, int32_t *remainder)
+inline int32_t div_64x32_rem(int64_t a, int32_t b, int32_t &remainder)
{
- int32_t const res = div_64x32(a, b);
- *remainder = a - (int64_t(b) * res);
+ int32_t const res(div_64x32(a, b));
+ remainder = a - (int64_t(b) * res);
return res;
}
#endif
@@ -184,10 +184,10 @@ inline int32_t div_64x32_rem(int64_t a, int32_t b, int32_t *remainder)
-------------------------------------------------*/
#ifndef divu_64x32_rem
-inline uint32_t divu_64x32_rem(uint64_t a, uint32_t b, uint32_t *remainder)
+inline uint32_t divu_64x32_rem(uint64_t a, uint32_t b, uint32_t &remainder)
{
- uint32_t const res = divu_64x32(a, b);
- *remainder = a - (uint64_t(b) * res);
+ uint32_t const res(divu_64x32(a, b));
+ remainder = a - (uint64_t(b) * res);
return res;
}
#endif
@@ -200,7 +200,7 @@ inline uint32_t divu_64x32_rem(uint64_t a, uint32_t b, uint32_t *remainder)
-------------------------------------------------*/
#ifndef div_32x32_shift
-inline int32_t div_32x32_shift(int32_t a, int32_t b, uint8_t shift)
+constexpr int32_t div_32x32_shift(int32_t a, int32_t b, uint8_t shift)
{
return (int64_t(a) << shift) / int64_t(b);
}
@@ -214,7 +214,7 @@ inline int32_t div_32x32_shift(int32_t a, int32_t b, uint8_t shift)
-------------------------------------------------*/
#ifndef divu_32x32_shift
-inline uint32_t divu_32x32_shift(uint32_t a, uint32_t b, uint8_t shift)
+constexpr uint32_t divu_32x32_shift(uint32_t a, uint32_t b, uint8_t shift)
{
return (uint64_t(a) << shift) / uint64_t(b);
}
@@ -227,7 +227,7 @@ inline uint32_t divu_32x32_shift(uint32_t a, uint32_t b, uint8_t shift)
-------------------------------------------------*/
#ifndef mod_64x32
-inline int32_t mod_64x32(int64_t a, int32_t b)
+constexpr int32_t mod_64x32(int64_t a, int32_t b)
{
return a - (b * div_64x32(a, b));
}
@@ -240,7 +240,7 @@ inline int32_t mod_64x32(int64_t a, int32_t b)
-------------------------------------------------*/
#ifndef modu_64x32
-inline uint32_t modu_64x32(uint64_t a, uint32_t b)
+constexpr uint32_t modu_64x32(uint64_t a, uint32_t b)
{
return a - (b * divu_64x32(a, b));
}
@@ -253,7 +253,7 @@ inline uint32_t modu_64x32(uint64_t a, uint32_t b)
-------------------------------------------------*/
#ifndef recip_approx
-inline float recip_approx(float value)
+constexpr float recip_approx(float value)
{
return 1.0f / value;
}
@@ -266,7 +266,7 @@ inline float recip_approx(float value)
-------------------------------------------------*/
#ifndef mul_64x64
-inline int64_t mul_64x64(int64_t a, int64_t b, int64_t *hi)
+inline int64_t mul_64x64(int64_t a, int64_t b, int64_t &hi)
{
uint64_t const a_hi = uint64_t(a) >> 32;
uint64_t const b_hi = uint64_t(b) >> 32;
@@ -279,13 +279,13 @@ inline int64_t mul_64x64(int64_t a, int64_t b, int64_t *hi)
uint64_t const ab_hi = a_hi * b_hi;
uint64_t const carry = ((ab_lo >> 32) + uint32_t(ab_m1) + uint32_t(ab_m2)) >> 32;
- *hi = ab_hi + (ab_m1 >> 32) + (ab_m2 >> 32) + carry;
+ hi = ab_hi + (ab_m1 >> 32) + (ab_m2 >> 32) + carry;
// adjust for sign
if (a < 0)
- *hi -= b;
+ hi -= b;
if (b < 0)
- *hi -= a;
+ hi -= a;
return ab_lo + (ab_m1 << 32) + (ab_m2 << 32);
}
@@ -298,7 +298,7 @@ inline int64_t mul_64x64(int64_t a, int64_t b, int64_t *hi)
-------------------------------------------------*/
#ifndef mulu_64x64
-inline uint64_t mulu_64x64(uint64_t a, uint64_t b, uint64_t *hi)
+inline uint64_t mulu_64x64(uint64_t a, uint64_t b, uint64_t &hi)
{
uint64_t const a_hi = uint32_t(a >> 32);
uint64_t const b_hi = uint32_t(b >> 32);
@@ -311,25 +311,55 @@ inline uint64_t mulu_64x64(uint64_t a, uint64_t b, uint64_t *hi)
uint64_t const ab_hi = a_hi * b_hi;
uint64_t const carry = ((ab_lo >> 32) + uint32_t(ab_m1) + uint32_t(ab_m2)) >> 32;
- *hi = ab_hi + (ab_m1 >> 32) + (ab_m2 >> 32) + carry;
+ hi = ab_hi + (ab_m1 >> 32) + (ab_m2 >> 32) + carry;
return ab_lo + (ab_m1 << 32) + (ab_m2 << 32);
}
#endif
+/*-------------------------------------------------
+ addu_32x32_co - perform an unsigned 32 bit + 32
+ bit addition and return the result with carry
+ out
+-------------------------------------------------*/
+
+#ifndef addu_32x32_co
+inline bool addu_32x32_co(uint32_t a, uint32_t b, uint32_t &sum)
+{
+ sum = a + b;
+ return (a > sum) || (b > sum);
+}
+#endif
+
+
+/*-------------------------------------------------
+ addu_64x64_co - perform an unsigned 64 bit + 64
+ bit addition and return the result with carry
+ out
+-------------------------------------------------*/
+
+#ifndef addu_64x64_co
+inline bool addu_64x64_co(uint64_t a, uint64_t b, uint64_t &sum)
+{
+ sum = a + b;
+ return (a > sum) || (b > sum);
+}
+#endif
+
+
/***************************************************************************
INLINE BIT MANIPULATION FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
- count_leading_zeros - return the number of
+ count_leading_zeros_32 - return the number of
leading zero bits in a 32-bit value
-------------------------------------------------*/
-#ifndef count_leading_zeros
-inline uint8_t count_leading_zeros(uint32_t val)
+#ifndef count_leading_zeros_32
+inline uint8_t count_leading_zeros_32(uint32_t val)
{
if (!val) return 32U;
uint8_t count;
@@ -340,12 +370,12 @@ inline uint8_t count_leading_zeros(uint32_t val)
/*-------------------------------------------------
- count_leading_ones - return the number of
+ count_leading_ones_32 - return the number of
leading one bits in a 32-bit value
-------------------------------------------------*/
-#ifndef count_leading_ones
-inline uint8_t count_leading_ones(uint32_t val)
+#ifndef count_leading_ones_32
+inline uint8_t count_leading_ones_32(uint32_t val)
{
uint8_t count;
for (count = 0; int32_t(val) < 0; count++) val <<= 1;
@@ -355,22 +385,48 @@ inline uint8_t count_leading_ones(uint32_t val)
/*-------------------------------------------------
+ count_leading_zeros_64 - return the number of
+ leading zero bits in a 64-bit value
+-------------------------------------------------*/
+
+#ifndef count_leading_zeros_64
+inline uint8_t count_leading_zeros_64(uint64_t val)
+{
+ if (!val) return 64U;
+ uint8_t count;
+ for (count = 0; int64_t(val) >= 0; count++) val <<= 1;
+ return count;
+}
+#endif
+
+
+/*-------------------------------------------------
+ count_leading_ones_64 - return the number of
+ leading one bits in a 64-bit value
+-------------------------------------------------*/
+
+#ifndef count_leading_ones_64
+inline uint8_t count_leading_ones_64(uint64_t val)
+{
+ uint8_t count;
+ for (count = 0; int64_t(val) < 0; count++) val <<= 1;
+ return count;
+}
+#endif
+
+
+/*-------------------------------------------------
population_count_32 - return the number of
one bits in a 32-bit value
-------------------------------------------------*/
#ifndef population_count_32
-#if defined(__NetBSD__)
-#define population_count_32 popcount32
-#else
inline unsigned population_count_32(uint32_t val)
{
-#if defined(__GNUC__)
- // uses CPU feature if available, otherwise falls back to implementation similar to what follows
- static_assert(sizeof(val) == sizeof(unsigned), "expected 32-bit unsigned int");
- return unsigned(__builtin_popcount(static_cast<unsigned>(val)));
+#if defined(__NetBSD__)
+ return popcount32(val);
#else
- // optimal Hamming weight assuing fast 32*32->32
+ // optimal Hamming weight assuming fast 32*32->32
constexpr uint32_t m1(0x55555555);
constexpr uint32_t m2(0x33333333);
constexpr uint32_t m4(0x0f0f0f0f);
@@ -382,7 +438,6 @@ inline unsigned population_count_32(uint32_t val)
#endif
}
#endif
-#endif
/*-------------------------------------------------
@@ -391,15 +446,10 @@ inline unsigned population_count_32(uint32_t val)
-------------------------------------------------*/
#ifndef population_count_64
-#if defined(__NetBSD__)
-#define population_count_64 popcount64
-#else
inline unsigned population_count_64(uint64_t val)
{
-#if defined(__GNUC__)
- // uses CPU feature if available, otherwise falls back to implementation similar to what follows
- static_assert(sizeof(val) == sizeof(unsigned long long), "expected 64-bit unsigned long long int");
- return unsigned(__builtin_popcountll(static_cast<unsigned long long>(val)));
+#if defined(__NetBSD__)
+ return popcount64(val);
#else
// guess that architectures with 64-bit pointers have 64-bit multiplier
if (sizeof(void *) >= sizeof(uint64_t))
@@ -422,6 +472,73 @@ inline unsigned population_count_64(uint64_t val)
#endif
}
#endif
+
+
+/*-------------------------------------------------
+ rotl_32 - circularly shift a 32-bit value left
+ by the specified number of bits (modulo 32)
+-------------------------------------------------*/
+
+#ifndef rotl_32
+constexpr uint32_t rotl_32(uint32_t val, int shift)
+{
+ shift &= 31;
+ if (shift)
+ return val << shift | val >> (32 - shift);
+ else
+ return val;
+}
+#endif
+
+
+/*-------------------------------------------------
+ rotr_32 - circularly shift a 32-bit value right
+ by the specified number of bits (modulo 32)
+-------------------------------------------------*/
+
+#ifndef rotr_32
+constexpr uint32_t rotr_32(uint32_t val, int shift)
+{
+ shift &= 31;
+ if (shift)
+ return val >> shift | val << (32 - shift);
+ else
+ return val;
+}
+#endif
+
+
+/*-------------------------------------------------
+ rotl_64 - circularly shift a 64-bit value left
+ by the specified number of bits (modulo 64)
+-------------------------------------------------*/
+
+#ifndef rotl_64
+constexpr uint64_t rotl_64(uint64_t val, int shift)
+{
+ shift &= 63;
+ if (shift)
+ return val << shift | val >> (64 - shift);
+ else
+ return val;
+}
+#endif
+
+
+/*-------------------------------------------------
+ rotr_64 - circularly shift a 64-bit value right
+ by the specified number of bits (modulo 64)
+-------------------------------------------------*/
+
+#ifndef rotr_64
+constexpr uint64_t rotr_64(uint64_t val, int shift)
+{
+ shift &= 63;
+ if (shift)
+ return val >> shift | val << (64 - shift);
+ else
+ return val;
+}
#endif
@@ -437,7 +554,7 @@ inline unsigned population_count_64(uint64_t val)
-------------------------------------------------*/
#ifndef get_profile_ticks
-inline int64_t get_profile_ticks()
+inline int64_t get_profile_ticks() noexcept
{
return osd_ticks();
}
diff --git a/src/osd/interface/audio.h b/src/osd/interface/audio.h
new file mode 100644
index 00000000000..f40744cfff6
--- /dev/null
+++ b/src/osd/interface/audio.h
@@ -0,0 +1,54 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+
+#ifndef MAME_OSD_INTERFACE_AUDIO_H
+#define MAME_OSD_INTERFACE_AUDIO_H
+
+#pragma once
+
+#include <array>
+#include <cmath>
+#include <string>
+#include <vector>
+
+
+namespace osd {
+
+struct audio_rate_range {
+ uint32_t m_default_rate;
+ uint32_t m_min_rate;
+ uint32_t m_max_rate;
+};
+
+struct audio_info {
+ struct node_info {
+ std::string m_name;
+ uint32_t m_id;
+ audio_rate_range m_rate;
+ std::vector<std::string> m_port_names;
+ std::vector<std::array<double, 3> > m_port_positions;
+ uint32_t m_sinks;
+ uint32_t m_sources;
+
+ std::string name() const { return (m_sinks ? "o:" : "i:") + m_name; }
+ };
+
+ struct stream_info {
+ uint32_t m_id;
+ uint32_t m_node;
+ std::vector<float> m_volumes;
+ };
+
+ uint32_t m_generation;
+ uint32_t m_default_sink;
+ uint32_t m_default_source;
+ std::vector<node_info> m_nodes;
+ std::vector<stream_info> m_streams;
+};
+
+inline float db_to_linear(float db) { return (db <= -96.0F) ? 0.0F : std::pow(10.0F, db / 20.0F); }
+inline float linear_to_db(float linear) { return (linear <= (1.0F / 65536.0F)) ? -96.0F : (20.0F * std::log10(linear)); }
+
+} // namespace osd
+
+#endif // MAME_OSD_INTERFACE_AUDIO_H
diff --git a/src/osd/interface/inputcode.h b/src/osd/interface/inputcode.h
new file mode 100644
index 00000000000..c056e78f401
--- /dev/null
+++ b/src/osd/interface/inputcode.h
@@ -0,0 +1,907 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ inputcode.h
+
+ Codes for representing host controls
+
+***************************************************************************/
+#ifndef MAME_OSD_INTERFACE_INPUTCODE_H
+#define MAME_OSD_INTERFACE_INPUTCODE_H
+
+#pragma once
+
+#include "osdcomm.h"
+
+#include <cassert>
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+// maximum number of axis/buttons/hats with ITEM_IDs for use by osd layer
+constexpr int INPUT_MAX_AXIS = 8;
+constexpr int INPUT_MAX_BUTTONS = 32;
+constexpr int INPUT_MAX_HATS = 4;
+constexpr int INPUT_MAX_ADD_SWITCH = 16;
+constexpr int INPUT_MAX_ADD_ABSOLUTE = 16;
+constexpr int INPUT_MAX_ADD_RELATIVE = 16;
+
+
+// device classes
+enum input_device_class
+{
+ DEVICE_CLASS_INVALID,
+ DEVICE_CLASS_FIRST_VALID,
+ DEVICE_CLASS_KEYBOARD = DEVICE_CLASS_FIRST_VALID,
+ DEVICE_CLASS_MOUSE,
+ DEVICE_CLASS_LIGHTGUN,
+ DEVICE_CLASS_JOYSTICK,
+ DEVICE_CLASS_LAST_VALID = DEVICE_CLASS_JOYSTICK,
+ DEVICE_CLASS_INTERNAL,
+ DEVICE_CLASS_MAXIMUM
+};
+DECLARE_ENUM_INCDEC_OPERATORS(input_device_class)
+
+
+// device index
+constexpr int DEVICE_INDEX_MAXIMUM = 0xff;
+
+
+// input item classes
+enum input_item_class
+{
+ ITEM_CLASS_INVALID,
+ ITEM_CLASS_SWITCH,
+ ITEM_CLASS_ABSOLUTE,
+ ITEM_CLASS_RELATIVE,
+ ITEM_CLASS_MAXIMUM
+};
+
+
+// input item modifiers
+enum input_item_modifier
+{
+ ITEM_MODIFIER_NONE,
+ ITEM_MODIFIER_REVERSE,
+ ITEM_MODIFIER_POS,
+ ITEM_MODIFIER_NEG,
+ ITEM_MODIFIER_LEFT,
+ ITEM_MODIFIER_RIGHT,
+ ITEM_MODIFIER_UP,
+ ITEM_MODIFIER_DOWN,
+ ITEM_MODIFIER_MAXIMUM
+};
+
+
+// standard item IDs
+enum input_item_id
+{
+ ITEM_ID_INVALID,
+ ITEM_ID_FIRST_VALID,
+
+ // standard keyboard IDs
+ ITEM_ID_A = ITEM_ID_FIRST_VALID,
+ ITEM_ID_B,
+ ITEM_ID_C,
+ ITEM_ID_D,
+ ITEM_ID_E,
+ ITEM_ID_F,
+ ITEM_ID_G,
+ ITEM_ID_H,
+ ITEM_ID_I,
+ ITEM_ID_J,
+ ITEM_ID_K,
+ ITEM_ID_L,
+ ITEM_ID_M,
+ ITEM_ID_N,
+ ITEM_ID_O,
+ ITEM_ID_P,
+ ITEM_ID_Q,
+ ITEM_ID_R,
+ ITEM_ID_S,
+ ITEM_ID_T,
+ ITEM_ID_U,
+ ITEM_ID_V,
+ ITEM_ID_W,
+ ITEM_ID_X,
+ ITEM_ID_Y,
+ ITEM_ID_Z,
+ ITEM_ID_0,
+ ITEM_ID_1,
+ ITEM_ID_2,
+ ITEM_ID_3,
+ ITEM_ID_4,
+ ITEM_ID_5,
+ ITEM_ID_6,
+ ITEM_ID_7,
+ ITEM_ID_8,
+ ITEM_ID_9,
+ ITEM_ID_F1,
+ ITEM_ID_F2,
+ ITEM_ID_F3,
+ ITEM_ID_F4,
+ ITEM_ID_F5,
+ ITEM_ID_F6,
+ ITEM_ID_F7,
+ ITEM_ID_F8,
+ ITEM_ID_F9,
+ ITEM_ID_F10,
+ ITEM_ID_F11,
+ ITEM_ID_F12,
+ ITEM_ID_F13,
+ ITEM_ID_F14,
+ ITEM_ID_F15,
+ ITEM_ID_F16,
+ ITEM_ID_F17,
+ ITEM_ID_F18,
+ ITEM_ID_F19,
+ ITEM_ID_F20,
+ ITEM_ID_ESC,
+ ITEM_ID_TILDE,
+ ITEM_ID_MINUS,
+ ITEM_ID_EQUALS,
+ ITEM_ID_BACKSPACE,
+ ITEM_ID_TAB,
+ ITEM_ID_OPENBRACE,
+ ITEM_ID_CLOSEBRACE,
+ ITEM_ID_ENTER,
+ ITEM_ID_COLON,
+ ITEM_ID_QUOTE,
+ ITEM_ID_BACKSLASH,
+ ITEM_ID_BACKSLASH2,
+ ITEM_ID_COMMA,
+ ITEM_ID_STOP,
+ ITEM_ID_SLASH,
+ ITEM_ID_SPACE,
+ ITEM_ID_INSERT,
+ ITEM_ID_DEL,
+ ITEM_ID_HOME,
+ ITEM_ID_END,
+ ITEM_ID_PGUP,
+ ITEM_ID_PGDN,
+ ITEM_ID_LEFT,
+ ITEM_ID_RIGHT,
+ ITEM_ID_UP,
+ ITEM_ID_DOWN,
+ ITEM_ID_0_PAD,
+ ITEM_ID_1_PAD,
+ ITEM_ID_2_PAD,
+ ITEM_ID_3_PAD,
+ ITEM_ID_4_PAD,
+ ITEM_ID_5_PAD,
+ ITEM_ID_6_PAD,
+ ITEM_ID_7_PAD,
+ ITEM_ID_8_PAD,
+ ITEM_ID_9_PAD,
+ ITEM_ID_SLASH_PAD,
+ ITEM_ID_ASTERISK,
+ ITEM_ID_MINUS_PAD,
+ ITEM_ID_PLUS_PAD,
+ ITEM_ID_DEL_PAD,
+ ITEM_ID_ENTER_PAD,
+ ITEM_ID_BS_PAD,
+ ITEM_ID_TAB_PAD,
+ ITEM_ID_00_PAD,
+ ITEM_ID_000_PAD,
+ ITEM_ID_COMMA_PAD,
+ ITEM_ID_EQUALS_PAD,
+ ITEM_ID_PRTSCR,
+ ITEM_ID_PAUSE,
+ ITEM_ID_LSHIFT,
+ ITEM_ID_RSHIFT,
+ ITEM_ID_LCONTROL,
+ ITEM_ID_RCONTROL,
+ ITEM_ID_LALT,
+ ITEM_ID_RALT,
+ ITEM_ID_SCRLOCK,
+ ITEM_ID_NUMLOCK,
+ ITEM_ID_CAPSLOCK,
+ ITEM_ID_LWIN,
+ ITEM_ID_RWIN,
+ ITEM_ID_MENU,
+ ITEM_ID_CANCEL,
+
+ // standard mouse/joystick/gun IDs
+ ITEM_ID_XAXIS,
+ ITEM_ID_YAXIS,
+ ITEM_ID_ZAXIS,
+ ITEM_ID_RXAXIS,
+ ITEM_ID_RYAXIS,
+ ITEM_ID_RZAXIS,
+ ITEM_ID_SLIDER1,
+ ITEM_ID_SLIDER2,
+ ITEM_ID_BUTTON1,
+ ITEM_ID_BUTTON2,
+ ITEM_ID_BUTTON3,
+ ITEM_ID_BUTTON4,
+ ITEM_ID_BUTTON5,
+ ITEM_ID_BUTTON6,
+ ITEM_ID_BUTTON7,
+ ITEM_ID_BUTTON8,
+ ITEM_ID_BUTTON9,
+ ITEM_ID_BUTTON10,
+ ITEM_ID_BUTTON11,
+ ITEM_ID_BUTTON12,
+ ITEM_ID_BUTTON13,
+ ITEM_ID_BUTTON14,
+ ITEM_ID_BUTTON15,
+ ITEM_ID_BUTTON16,
+ ITEM_ID_BUTTON17,
+ ITEM_ID_BUTTON18,
+ ITEM_ID_BUTTON19,
+ ITEM_ID_BUTTON20,
+ ITEM_ID_BUTTON21,
+ ITEM_ID_BUTTON22,
+ ITEM_ID_BUTTON23,
+ ITEM_ID_BUTTON24,
+ ITEM_ID_BUTTON25,
+ ITEM_ID_BUTTON26,
+ ITEM_ID_BUTTON27,
+ ITEM_ID_BUTTON28,
+ ITEM_ID_BUTTON29,
+ ITEM_ID_BUTTON30,
+ ITEM_ID_BUTTON31,
+ ITEM_ID_BUTTON32,
+ ITEM_ID_START,
+ ITEM_ID_SELECT,
+
+ // Hats
+ ITEM_ID_HAT1UP,
+ ITEM_ID_HAT1DOWN,
+ ITEM_ID_HAT1LEFT,
+ ITEM_ID_HAT1RIGHT,
+ ITEM_ID_HAT2UP,
+ ITEM_ID_HAT2DOWN,
+ ITEM_ID_HAT2LEFT,
+ ITEM_ID_HAT2RIGHT,
+ ITEM_ID_HAT3UP,
+ ITEM_ID_HAT3DOWN,
+ ITEM_ID_HAT3LEFT,
+ ITEM_ID_HAT3RIGHT,
+ ITEM_ID_HAT4UP,
+ ITEM_ID_HAT4DOWN,
+ ITEM_ID_HAT4LEFT,
+ ITEM_ID_HAT4RIGHT,
+
+ // Additional IDs
+ ITEM_ID_ADD_SWITCH1,
+ ITEM_ID_ADD_SWITCH2,
+ ITEM_ID_ADD_SWITCH3,
+ ITEM_ID_ADD_SWITCH4,
+ ITEM_ID_ADD_SWITCH5,
+ ITEM_ID_ADD_SWITCH6,
+ ITEM_ID_ADD_SWITCH7,
+ ITEM_ID_ADD_SWITCH8,
+ ITEM_ID_ADD_SWITCH9,
+ ITEM_ID_ADD_SWITCH10,
+ ITEM_ID_ADD_SWITCH11,
+ ITEM_ID_ADD_SWITCH12,
+ ITEM_ID_ADD_SWITCH13,
+ ITEM_ID_ADD_SWITCH14,
+ ITEM_ID_ADD_SWITCH15,
+ ITEM_ID_ADD_SWITCH16,
+
+ ITEM_ID_ADD_ABSOLUTE1,
+ ITEM_ID_ADD_ABSOLUTE2,
+ ITEM_ID_ADD_ABSOLUTE3,
+ ITEM_ID_ADD_ABSOLUTE4,
+ ITEM_ID_ADD_ABSOLUTE5,
+ ITEM_ID_ADD_ABSOLUTE6,
+ ITEM_ID_ADD_ABSOLUTE7,
+ ITEM_ID_ADD_ABSOLUTE8,
+ ITEM_ID_ADD_ABSOLUTE9,
+ ITEM_ID_ADD_ABSOLUTE10,
+ ITEM_ID_ADD_ABSOLUTE11,
+ ITEM_ID_ADD_ABSOLUTE12,
+ ITEM_ID_ADD_ABSOLUTE13,
+ ITEM_ID_ADD_ABSOLUTE14,
+ ITEM_ID_ADD_ABSOLUTE15,
+ ITEM_ID_ADD_ABSOLUTE16,
+
+ ITEM_ID_ADD_RELATIVE1,
+ ITEM_ID_ADD_RELATIVE2,
+ ITEM_ID_ADD_RELATIVE3,
+ ITEM_ID_ADD_RELATIVE4,
+ ITEM_ID_ADD_RELATIVE5,
+ ITEM_ID_ADD_RELATIVE6,
+ ITEM_ID_ADD_RELATIVE7,
+ ITEM_ID_ADD_RELATIVE8,
+ ITEM_ID_ADD_RELATIVE9,
+ ITEM_ID_ADD_RELATIVE10,
+ ITEM_ID_ADD_RELATIVE11,
+ ITEM_ID_ADD_RELATIVE12,
+ ITEM_ID_ADD_RELATIVE13,
+ ITEM_ID_ADD_RELATIVE14,
+ ITEM_ID_ADD_RELATIVE15,
+ ITEM_ID_ADD_RELATIVE16,
+
+ // generic other IDs
+ ITEM_ID_OTHER_SWITCH,
+ ITEM_ID_OTHER_AXIS_ABSOLUTE,
+ ITEM_ID_OTHER_AXIS_RELATIVE,
+ ITEM_ID_MAXIMUM,
+
+ // internal codes for sequences
+ ITEM_ID_SEQ_END,
+ ITEM_ID_SEQ_DEFAULT,
+ ITEM_ID_SEQ_NOT,
+ ITEM_ID_SEQ_OR,
+
+ // absolute maximum ID
+ ITEM_ID_ABSOLUTE_MAXIMUM = 0xfff
+};
+DECLARE_ENUM_INCDEC_OPERATORS(input_item_id)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// a combined code that describes a particular input on a particular device
+
+class input_code
+{
+public:
+ // construction/destruction
+ constexpr input_code(
+ input_device_class devclass = DEVICE_CLASS_INVALID,
+ int devindex = 0,
+ input_item_class itemclass = ITEM_CLASS_INVALID,
+ input_item_modifier modifier = ITEM_MODIFIER_NONE,
+ input_item_id itemid = ITEM_ID_INVALID) noexcept
+ : m_internal(((devclass & 0xf) << 28) | ((devindex & 0xff) << 20) | ((itemclass & 0xf) << 16) | ((modifier & 0xf) << 12) | (itemid & 0xfff))
+ {
+ assert(devclass >= 0 && devclass < DEVICE_CLASS_MAXIMUM);
+ assert(devindex >= 0 && devindex < DEVICE_INDEX_MAXIMUM);
+ assert(itemclass >= 0 && itemclass < ITEM_CLASS_MAXIMUM);
+ assert(modifier >= 0 && modifier < ITEM_MODIFIER_MAXIMUM);
+ assert(itemid >= 0 && itemid < ITEM_ID_ABSOLUTE_MAXIMUM);
+ }
+ constexpr input_code(const input_code &src) noexcept = default;
+
+ // operators
+ constexpr bool operator==(const input_code &rhs) const noexcept { return m_internal == rhs.m_internal; }
+ constexpr bool operator!=(const input_code &rhs) const noexcept { return m_internal != rhs.m_internal; }
+ constexpr bool operator<(const input_code &rhs) const noexcept { return m_internal < rhs.m_internal; }
+
+ // getters
+ constexpr bool internal() const noexcept { return device_class() == DEVICE_CLASS_INTERNAL; }
+ constexpr input_device_class device_class() const noexcept { return input_device_class((m_internal >> 28) & 0xf); }
+ constexpr int device_index() const noexcept { return ((m_internal >> 20) & 0xff); }
+ constexpr input_item_class item_class() const noexcept { return input_item_class((m_internal >> 16) & 0xf); }
+ constexpr input_item_modifier item_modifier() const noexcept { return input_item_modifier((m_internal >> 12) & 0xf); }
+ constexpr input_item_id item_id() const noexcept { return input_item_id(m_internal & 0xfff); }
+
+ // setters
+ void set_device_class(input_device_class devclass) noexcept
+ {
+ assert(0 == (std::underlying_type_t<input_device_class>(devclass) & ~0xf));
+ m_internal = (m_internal & ~(0xf << 28)) | ((devclass & 0xf) << 28);
+ }
+ void set_device_index(int devindex) noexcept
+ {
+ assert(devindex >= 0 && devindex <= 0xff);
+ m_internal = (m_internal & ~(0xff << 20)) | ((devindex & 0xff) << 20);
+ }
+ void set_item_class(input_item_class itemclass) noexcept
+ {
+ assert(0 == (std::underlying_type_t<input_item_class>(itemclass) & ~0xf));
+ m_internal = (m_internal & ~(0xf << 16)) | ((itemclass & 0xf) << 16);
+ }
+ void set_item_modifier(input_item_modifier modifier) noexcept
+ {
+ assert(0 == (std::underlying_type_t<input_item_modifier>(modifier) & ~0xf));
+ m_internal = (m_internal & ~(0xf << 12)) | ((modifier & 0xf) << 12);
+ }
+ void set_item_id(input_item_id itemid) noexcept
+ {
+ assert(0 == (std::underlying_type_t<input_item_id>(itemid) & ~0xfff));
+ m_internal = (m_internal & ~0xfff) | (itemid & 0xfff);
+ }
+
+private:
+ osd::u32 m_internal;
+};
+
+
+
+//**************************************************************************
+// MACROS
+//**************************************************************************
+
+// invalid codes
+#define INPUT_CODE_INVALID input_code()
+
+// keyboard codes
+constexpr input_code KEYCODE_A_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_A); }
+constexpr input_code KEYCODE_B_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_B); }
+constexpr input_code KEYCODE_C_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_C); }
+constexpr input_code KEYCODE_D_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_D); }
+constexpr input_code KEYCODE_E_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_E); }
+constexpr input_code KEYCODE_F_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F); }
+constexpr input_code KEYCODE_G_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_G); }
+constexpr input_code KEYCODE_H_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_H); }
+constexpr input_code KEYCODE_I_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_I); }
+constexpr input_code KEYCODE_J_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_J); }
+constexpr input_code KEYCODE_K_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_K); }
+constexpr input_code KEYCODE_L_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_L); }
+constexpr input_code KEYCODE_M_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_M); }
+constexpr input_code KEYCODE_N_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_N); }
+constexpr input_code KEYCODE_O_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_O); }
+constexpr input_code KEYCODE_P_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_P); }
+constexpr input_code KEYCODE_Q_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_Q); }
+constexpr input_code KEYCODE_R_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_R); }
+constexpr input_code KEYCODE_S_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_S); }
+constexpr input_code KEYCODE_T_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_T); }
+constexpr input_code KEYCODE_U_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_U); }
+constexpr input_code KEYCODE_V_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_V); }
+constexpr input_code KEYCODE_W_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_W); }
+constexpr input_code KEYCODE_X_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_X); }
+constexpr input_code KEYCODE_Y_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_Y); }
+constexpr input_code KEYCODE_Z_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_Z); }
+constexpr input_code KEYCODE_0_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_0); }
+constexpr input_code KEYCODE_1_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_1); }
+constexpr input_code KEYCODE_2_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_2); }
+constexpr input_code KEYCODE_3_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_3); }
+constexpr input_code KEYCODE_4_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_4); }
+constexpr input_code KEYCODE_5_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_5); }
+constexpr input_code KEYCODE_6_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_6); }
+constexpr input_code KEYCODE_7_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_7); }
+constexpr input_code KEYCODE_8_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_8); }
+constexpr input_code KEYCODE_9_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_9); }
+constexpr input_code KEYCODE_F1_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F1); }
+constexpr input_code KEYCODE_F2_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F2); }
+constexpr input_code KEYCODE_F3_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F3); }
+constexpr input_code KEYCODE_F4_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F4); }
+constexpr input_code KEYCODE_F5_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F5); }
+constexpr input_code KEYCODE_F6_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F6); }
+constexpr input_code KEYCODE_F7_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F7); }
+constexpr input_code KEYCODE_F8_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F8); }
+constexpr input_code KEYCODE_F9_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F9); }
+constexpr input_code KEYCODE_F10_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F10); }
+constexpr input_code KEYCODE_F11_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F11); }
+constexpr input_code KEYCODE_F12_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F12); }
+constexpr input_code KEYCODE_F13_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F13); }
+constexpr input_code KEYCODE_F14_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F14); }
+constexpr input_code KEYCODE_F15_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F15); }
+constexpr input_code KEYCODE_F16_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F16); }
+constexpr input_code KEYCODE_F17_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F17); }
+constexpr input_code KEYCODE_F18_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F18); }
+constexpr input_code KEYCODE_F19_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F19); }
+constexpr input_code KEYCODE_F20_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F20); }
+constexpr input_code KEYCODE_ESC_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_ESC); }
+constexpr input_code KEYCODE_TILDE_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_TILDE); }
+constexpr input_code KEYCODE_MINUS_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_MINUS); }
+constexpr input_code KEYCODE_EQUALS_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_EQUALS); }
+constexpr input_code KEYCODE_BACKSPACE_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BACKSPACE); }
+constexpr input_code KEYCODE_TAB_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_TAB); }
+constexpr input_code KEYCODE_OPENBRACE_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_OPENBRACE); }
+constexpr input_code KEYCODE_CLOSEBRACE_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_CLOSEBRACE); }
+constexpr input_code KEYCODE_ENTER_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_ENTER); }
+constexpr input_code KEYCODE_COLON_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_COLON); }
+constexpr input_code KEYCODE_QUOTE_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_QUOTE); }
+constexpr input_code KEYCODE_BACKSLASH_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BACKSLASH); }
+constexpr input_code KEYCODE_BACKSLASH2_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BACKSLASH2); }
+constexpr input_code KEYCODE_COMMA_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_COMMA); }
+constexpr input_code KEYCODE_STOP_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_STOP); }
+constexpr input_code KEYCODE_SLASH_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_SLASH); }
+constexpr input_code KEYCODE_SPACE_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_SPACE); }
+constexpr input_code KEYCODE_INSERT_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_INSERT); }
+constexpr input_code KEYCODE_DEL_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_DEL); }
+constexpr input_code KEYCODE_HOME_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_HOME); }
+constexpr input_code KEYCODE_END_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_END); }
+constexpr input_code KEYCODE_PGUP_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_PGUP); }
+constexpr input_code KEYCODE_PGDN_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_PGDN); }
+constexpr input_code KEYCODE_LEFT_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_LEFT); }
+constexpr input_code KEYCODE_RIGHT_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_RIGHT); }
+constexpr input_code KEYCODE_UP_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_UP); }
+constexpr input_code KEYCODE_DOWN_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_DOWN); }
+constexpr input_code KEYCODE_0_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_0_PAD); }
+constexpr input_code KEYCODE_1_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_1_PAD); }
+constexpr input_code KEYCODE_2_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_2_PAD); }
+constexpr input_code KEYCODE_3_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_3_PAD); }
+constexpr input_code KEYCODE_4_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_4_PAD); }
+constexpr input_code KEYCODE_5_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_5_PAD); }
+constexpr input_code KEYCODE_6_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_6_PAD); }
+constexpr input_code KEYCODE_7_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_7_PAD); }
+constexpr input_code KEYCODE_8_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_8_PAD); }
+constexpr input_code KEYCODE_9_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_9_PAD); }
+constexpr input_code KEYCODE_SLASH_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_SLASH_PAD); }
+constexpr input_code KEYCODE_ASTERISK_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_ASTERISK); }
+constexpr input_code KEYCODE_MINUS_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_MINUS_PAD); }
+constexpr input_code KEYCODE_PLUS_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_PLUS_PAD); }
+constexpr input_code KEYCODE_DEL_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_DEL_PAD); }
+constexpr input_code KEYCODE_ENTER_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_ENTER_PAD); }
+constexpr input_code KEYCODE_BS_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BS_PAD); }
+constexpr input_code KEYCODE_TAB_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_TAB_PAD); }
+constexpr input_code KEYCODE_00_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_00_PAD); }
+constexpr input_code KEYCODE_000_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_000_PAD); }
+constexpr input_code KEYCODE_COMMA_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_COMMA_PAD); }
+constexpr input_code KEYCODE_EQUALS_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_EQUALS_PAD); }
+constexpr input_code KEYCODE_PRTSCR_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_PRTSCR); }
+constexpr input_code KEYCODE_PAUSE_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_PAUSE); }
+constexpr input_code KEYCODE_LSHIFT_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_LSHIFT); }
+constexpr input_code KEYCODE_RSHIFT_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_RSHIFT); }
+constexpr input_code KEYCODE_LCONTROL_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_LCONTROL); }
+constexpr input_code KEYCODE_RCONTROL_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_RCONTROL); }
+constexpr input_code KEYCODE_LALT_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_LALT); }
+constexpr input_code KEYCODE_RALT_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_RALT); }
+constexpr input_code KEYCODE_SCRLOCK_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_SCRLOCK); }
+constexpr input_code KEYCODE_NUMLOCK_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_NUMLOCK); }
+constexpr input_code KEYCODE_CAPSLOCK_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_CAPSLOCK); }
+constexpr input_code KEYCODE_LWIN_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_LWIN); }
+constexpr input_code KEYCODE_RWIN_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_RWIN); }
+constexpr input_code KEYCODE_MENU_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_MENU); }
+constexpr input_code KEYCODE_CANCEL_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_CANCEL); }
+
+#define KEYCODE_A KEYCODE_A_INDEXED(0)
+#define KEYCODE_B KEYCODE_B_INDEXED(0)
+#define KEYCODE_C KEYCODE_C_INDEXED(0)
+#define KEYCODE_D KEYCODE_D_INDEXED(0)
+#define KEYCODE_E KEYCODE_E_INDEXED(0)
+#define KEYCODE_F KEYCODE_F_INDEXED(0)
+#define KEYCODE_G KEYCODE_G_INDEXED(0)
+#define KEYCODE_H KEYCODE_H_INDEXED(0)
+#define KEYCODE_I KEYCODE_I_INDEXED(0)
+#define KEYCODE_J KEYCODE_J_INDEXED(0)
+#define KEYCODE_K KEYCODE_K_INDEXED(0)
+#define KEYCODE_L KEYCODE_L_INDEXED(0)
+#define KEYCODE_M KEYCODE_M_INDEXED(0)
+#define KEYCODE_N KEYCODE_N_INDEXED(0)
+#define KEYCODE_O KEYCODE_O_INDEXED(0)
+#define KEYCODE_P KEYCODE_P_INDEXED(0)
+#define KEYCODE_Q KEYCODE_Q_INDEXED(0)
+#define KEYCODE_R KEYCODE_R_INDEXED(0)
+#define KEYCODE_S KEYCODE_S_INDEXED(0)
+#define KEYCODE_T KEYCODE_T_INDEXED(0)
+#define KEYCODE_U KEYCODE_U_INDEXED(0)
+#define KEYCODE_V KEYCODE_V_INDEXED(0)
+#define KEYCODE_W KEYCODE_W_INDEXED(0)
+#define KEYCODE_X KEYCODE_X_INDEXED(0)
+#define KEYCODE_Y KEYCODE_Y_INDEXED(0)
+#define KEYCODE_Z KEYCODE_Z_INDEXED(0)
+#define KEYCODE_0 KEYCODE_0_INDEXED(0)
+#define KEYCODE_1 KEYCODE_1_INDEXED(0)
+#define KEYCODE_2 KEYCODE_2_INDEXED(0)
+#define KEYCODE_3 KEYCODE_3_INDEXED(0)
+#define KEYCODE_4 KEYCODE_4_INDEXED(0)
+#define KEYCODE_5 KEYCODE_5_INDEXED(0)
+#define KEYCODE_6 KEYCODE_6_INDEXED(0)
+#define KEYCODE_7 KEYCODE_7_INDEXED(0)
+#define KEYCODE_8 KEYCODE_8_INDEXED(0)
+#define KEYCODE_9 KEYCODE_9_INDEXED(0)
+#define KEYCODE_F1 KEYCODE_F1_INDEXED(0)
+#define KEYCODE_F2 KEYCODE_F2_INDEXED(0)
+#define KEYCODE_F3 KEYCODE_F3_INDEXED(0)
+#define KEYCODE_F4 KEYCODE_F4_INDEXED(0)
+#define KEYCODE_F5 KEYCODE_F5_INDEXED(0)
+#define KEYCODE_F6 KEYCODE_F6_INDEXED(0)
+#define KEYCODE_F7 KEYCODE_F7_INDEXED(0)
+#define KEYCODE_F8 KEYCODE_F8_INDEXED(0)
+#define KEYCODE_F9 KEYCODE_F9_INDEXED(0)
+#define KEYCODE_F10 KEYCODE_F10_INDEXED(0)
+#define KEYCODE_F11 KEYCODE_F11_INDEXED(0)
+#define KEYCODE_F12 KEYCODE_F12_INDEXED(0)
+#define KEYCODE_F13 KEYCODE_F13_INDEXED(0)
+#define KEYCODE_F14 KEYCODE_F14_INDEXED(0)
+#define KEYCODE_F15 KEYCODE_F15_INDEXED(0)
+#define KEYCODE_F16 KEYCODE_F16_INDEXED(0)
+#define KEYCODE_F17 KEYCODE_F17_INDEXED(0)
+#define KEYCODE_F18 KEYCODE_F18_INDEXED(0)
+#define KEYCODE_F19 KEYCODE_F19_INDEXED(0)
+#define KEYCODE_F20 KEYCODE_F20_INDEXED(0)
+#define KEYCODE_ESC KEYCODE_ESC_INDEXED(0)
+#define KEYCODE_TILDE KEYCODE_TILDE_INDEXED(0)
+#define KEYCODE_MINUS KEYCODE_MINUS_INDEXED(0)
+#define KEYCODE_EQUALS KEYCODE_EQUALS_INDEXED(0)
+#define KEYCODE_BACKSPACE KEYCODE_BACKSPACE_INDEXED(0)
+#define KEYCODE_TAB KEYCODE_TAB_INDEXED(0)
+#define KEYCODE_OPENBRACE KEYCODE_OPENBRACE_INDEXED(0)
+#define KEYCODE_CLOSEBRACE KEYCODE_CLOSEBRACE_INDEXED(0)
+#define KEYCODE_ENTER KEYCODE_ENTER_INDEXED(0)
+#define KEYCODE_COLON KEYCODE_COLON_INDEXED(0)
+#define KEYCODE_QUOTE KEYCODE_QUOTE_INDEXED(0)
+#define KEYCODE_BACKSLASH KEYCODE_BACKSLASH_INDEXED(0)
+#define KEYCODE_BACKSLASH2 KEYCODE_BACKSLASH2_INDEXED(0)
+#define KEYCODE_COMMA KEYCODE_COMMA_INDEXED(0)
+#define KEYCODE_STOP KEYCODE_STOP_INDEXED(0)
+#define KEYCODE_SLASH KEYCODE_SLASH_INDEXED(0)
+#define KEYCODE_SPACE KEYCODE_SPACE_INDEXED(0)
+#define KEYCODE_INSERT KEYCODE_INSERT_INDEXED(0)
+#define KEYCODE_DEL KEYCODE_DEL_INDEXED(0)
+#define KEYCODE_HOME KEYCODE_HOME_INDEXED(0)
+#define KEYCODE_END KEYCODE_END_INDEXED(0)
+#define KEYCODE_PGUP KEYCODE_PGUP_INDEXED(0)
+#define KEYCODE_PGDN KEYCODE_PGDN_INDEXED(0)
+#define KEYCODE_LEFT KEYCODE_LEFT_INDEXED(0)
+#define KEYCODE_RIGHT KEYCODE_RIGHT_INDEXED(0)
+#define KEYCODE_UP KEYCODE_UP_INDEXED(0)
+#define KEYCODE_DOWN KEYCODE_DOWN_INDEXED(0)
+#define KEYCODE_0_PAD KEYCODE_0_PAD_INDEXED(0)
+#define KEYCODE_1_PAD KEYCODE_1_PAD_INDEXED(0)
+#define KEYCODE_2_PAD KEYCODE_2_PAD_INDEXED(0)
+#define KEYCODE_3_PAD KEYCODE_3_PAD_INDEXED(0)
+#define KEYCODE_4_PAD KEYCODE_4_PAD_INDEXED(0)
+#define KEYCODE_5_PAD KEYCODE_5_PAD_INDEXED(0)
+#define KEYCODE_6_PAD KEYCODE_6_PAD_INDEXED(0)
+#define KEYCODE_7_PAD KEYCODE_7_PAD_INDEXED(0)
+#define KEYCODE_8_PAD KEYCODE_8_PAD_INDEXED(0)
+#define KEYCODE_9_PAD KEYCODE_9_PAD_INDEXED(0)
+#define KEYCODE_SLASH_PAD KEYCODE_SLASH_PAD_INDEXED(0)
+#define KEYCODE_ASTERISK KEYCODE_ASTERISK_INDEXED(0)
+#define KEYCODE_MINUS_PAD KEYCODE_MINUS_PAD_INDEXED(0)
+#define KEYCODE_PLUS_PAD KEYCODE_PLUS_PAD_INDEXED(0)
+#define KEYCODE_DEL_PAD KEYCODE_DEL_PAD_INDEXED(0)
+#define KEYCODE_ENTER_PAD KEYCODE_ENTER_PAD_INDEXED(0)
+#define KEYCODE_BS_PAD KEYCODE_BS_PAD_INDEXED(0)
+#define KEYCODE_TAB_PAD KEYCODE_TAB_PAD_INDEXED(0)
+#define KEYCODE_00_PAD KEYCODE_00_PAD_INDEXED(0)
+#define KEYCODE_000_PAD KEYCODE_000_PAD_INDEXED(0)
+#define KEYCODE_COMMA_PAD KEYCODE_COMMA_PAD_INDEXED(0)
+#define KEYCODE_EQUALS_PAD KEYCODE_EQUALS_PAD_INDEXED(0)
+#define KEYCODE_PRTSCR KEYCODE_PRTSCR_INDEXED(0)
+#define KEYCODE_PAUSE KEYCODE_PAUSE_INDEXED(0)
+#define KEYCODE_LSHIFT KEYCODE_LSHIFT_INDEXED(0)
+#define KEYCODE_RSHIFT KEYCODE_RSHIFT_INDEXED(0)
+#define KEYCODE_LCONTROL KEYCODE_LCONTROL_INDEXED(0)
+#define KEYCODE_RCONTROL KEYCODE_RCONTROL_INDEXED(0)
+#define KEYCODE_LALT KEYCODE_LALT_INDEXED(0)
+#define KEYCODE_RALT KEYCODE_RALT_INDEXED(0)
+#define KEYCODE_SCRLOCK KEYCODE_SCRLOCK_INDEXED(0)
+#define KEYCODE_NUMLOCK KEYCODE_NUMLOCK_INDEXED(0)
+#define KEYCODE_CAPSLOCK KEYCODE_CAPSLOCK_INDEXED(0)
+#define KEYCODE_LWIN KEYCODE_LWIN_INDEXED(0)
+#define KEYCODE_RWIN KEYCODE_RWIN_INDEXED(0)
+#define KEYCODE_MENU KEYCODE_MENU_INDEXED(0)
+#define KEYCODE_CANCEL KEYCODE_CANCEL_INDEXED(0)
+
+// mouse axes as relative devices
+constexpr input_code MOUSECODE_X_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_RELATIVE, ITEM_MODIFIER_NONE, ITEM_ID_XAXIS); }
+constexpr input_code MOUSECODE_Y_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_RELATIVE, ITEM_MODIFIER_NONE, ITEM_ID_YAXIS); }
+constexpr input_code MOUSECODE_Z_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_RELATIVE, ITEM_MODIFIER_NONE, ITEM_ID_ZAXIS); }
+
+#define MOUSECODE_X MOUSECODE_X_INDEXED(0)
+#define MOUSECODE_Y MOUSECODE_Y_INDEXED(0)
+#define MOUSECODE_Z MOUSECODE_Z_INDEXED(0)
+
+// mouse axes as switches in +/- direction
+constexpr input_code MOUSECODE_X_POS_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_XAXIS); }
+constexpr input_code MOUSECODE_X_NEG_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_XAXIS); }
+constexpr input_code MOUSECODE_Y_POS_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_YAXIS); }
+constexpr input_code MOUSECODE_Y_NEG_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_YAXIS); }
+constexpr input_code MOUSECODE_Z_POS_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_ZAXIS); }
+constexpr input_code MOUSECODE_Z_NEG_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_ZAXIS); }
+
+#define MOUSECODE_X_POS_SWITCH MOUSECODE_X_POS_SWITCH_INDEXED(0)
+#define MOUSECODE_X_NEG_SWITCH MOUSECODE_X_NEG_SWITCH_INDEXED(0)
+#define MOUSECODE_Y_POS_SWITCH MOUSECODE_Y_POS_SWITCH_INDEXED(0)
+#define MOUSECODE_Y_NEG_SWITCH MOUSECODE_Y_NEG_SWITCH_INDEXED(0)
+#define MOUSECODE_Z_POS_SWITCH MOUSECODE_Z_POS_SWITCH_INDEXED(0)
+#define MOUSECODE_Z_NEG_SWITCH MOUSECODE_Z_NEG_SWITCH_INDEXED(0)
+
+// mouse buttons
+constexpr input_code MOUSECODE_BUTTON1_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON1); }
+constexpr input_code MOUSECODE_BUTTON2_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON2); }
+constexpr input_code MOUSECODE_BUTTON3_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON3); }
+constexpr input_code MOUSECODE_BUTTON4_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON4); }
+constexpr input_code MOUSECODE_BUTTON5_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON5); }
+constexpr input_code MOUSECODE_BUTTON6_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON6); }
+constexpr input_code MOUSECODE_BUTTON7_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON7); }
+constexpr input_code MOUSECODE_BUTTON8_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON8); }
+
+#define MOUSECODE_BUTTON1 MOUSECODE_BUTTON1_INDEXED(0)
+#define MOUSECODE_BUTTON2 MOUSECODE_BUTTON2_INDEXED(0)
+#define MOUSECODE_BUTTON3 MOUSECODE_BUTTON3_INDEXED(0)
+#define MOUSECODE_BUTTON4 MOUSECODE_BUTTON4_INDEXED(0)
+#define MOUSECODE_BUTTON5 MOUSECODE_BUTTON5_INDEXED(0)
+#define MOUSECODE_BUTTON6 MOUSECODE_BUTTON6_INDEXED(0)
+#define MOUSECODE_BUTTON7 MOUSECODE_BUTTON7_INDEXED(0)
+#define MOUSECODE_BUTTON8 MOUSECODE_BUTTON8_INDEXED(0)
+
+// gun axes as absolute devices
+constexpr input_code GUNCODE_X_INDEXED(int n) { return input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_XAXIS); }
+constexpr input_code GUNCODE_Y_INDEXED(int n) { return input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_YAXIS); }
+
+#define GUNCODE_X GUNCODE_X_INDEXED(0)
+#define GUNCODE_Y GUNCODE_Y_INDEXED(0)
+
+// gun buttons
+constexpr input_code GUNCODE_BUTTON1_INDEXED(int n) { return input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON1); }
+constexpr input_code GUNCODE_BUTTON2_INDEXED(int n) { return input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON2); }
+constexpr input_code GUNCODE_BUTTON3_INDEXED(int n) { return input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON3); }
+constexpr input_code GUNCODE_BUTTON4_INDEXED(int n) { return input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON4); }
+constexpr input_code GUNCODE_BUTTON5_INDEXED(int n) { return input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON5); }
+constexpr input_code GUNCODE_BUTTON6_INDEXED(int n) { return input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON6); }
+constexpr input_code GUNCODE_BUTTON7_INDEXED(int n) { return input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON7); }
+constexpr input_code GUNCODE_BUTTON8_INDEXED(int n) { return input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON8); }
+
+#define GUNCODE_BUTTON1 GUNCODE_BUTTON1_INDEXED(0)
+#define GUNCODE_BUTTON2 GUNCODE_BUTTON2_INDEXED(0)
+#define GUNCODE_BUTTON3 GUNCODE_BUTTON3_INDEXED(0)
+#define GUNCODE_BUTTON4 GUNCODE_BUTTON4_INDEXED(0)
+#define GUNCODE_BUTTON5 GUNCODE_BUTTON5_INDEXED(0)
+#define GUNCODE_BUTTON6 GUNCODE_BUTTON6_INDEXED(0)
+#define GUNCODE_BUTTON7 GUNCODE_BUTTON7_INDEXED(0)
+#define GUNCODE_BUTTON8 GUNCODE_BUTTON8_INDEXED(0)
+
+// joystick axes as absolute devices
+constexpr input_code JOYCODE_X_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_XAXIS); }
+constexpr input_code JOYCODE_Y_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_YAXIS); }
+constexpr input_code JOYCODE_Z_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_ZAXIS); }
+constexpr input_code JOYCODE_U_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_RXAXIS); }
+constexpr input_code JOYCODE_V_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_RYAXIS); }
+constexpr input_code JOYCODE_W_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_RZAXIS); }
+
+#define JOYCODE_X JOYCODE_X_INDEXED(0)
+#define JOYCODE_Y JOYCODE_Y_INDEXED(0)
+#define JOYCODE_Z JOYCODE_Z_INDEXED(0)
+#define JOYCODE_U JOYCODE_U_INDEXED(0)
+#define JOYCODE_V JOYCODE_V_INDEXED(0)
+#define JOYCODE_W JOYCODE_W_INDEXED(0)
+
+// joystick axes as absolute half-axes
+constexpr input_code JOYCODE_X_POS_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_XAXIS); }
+constexpr input_code JOYCODE_X_NEG_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_XAXIS); }
+constexpr input_code JOYCODE_Y_POS_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_YAXIS); }
+constexpr input_code JOYCODE_Y_NEG_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_YAXIS); }
+constexpr input_code JOYCODE_Z_POS_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_ZAXIS); }
+constexpr input_code JOYCODE_Z_NEG_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_ZAXIS); }
+constexpr input_code JOYCODE_U_POS_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_RXAXIS); }
+constexpr input_code JOYCODE_U_NEG_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_RXAXIS); }
+constexpr input_code JOYCODE_V_POS_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_RYAXIS); }
+constexpr input_code JOYCODE_V_NEG_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_RYAXIS); }
+constexpr input_code JOYCODE_W_POS_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_RZAXIS); }
+constexpr input_code JOYCODE_W_NEG_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_RZAXIS); }
+
+#define JOYCODE_X_POS_ABSOLUTE JOYCODE_X_POS_ABSOLUTE_INDEXED(0)
+#define JOYCODE_X_NEG_ABSOLUTE JOYCODE_X_NEG_ABSOLUTE_INDEXED(0)
+#define JOYCODE_Y_POS_ABSOLUTE JOYCODE_Y_POS_ABSOLUTE_INDEXED(0)
+#define JOYCODE_Y_NEG_ABSOLUTE JOYCODE_Y_NEG_ABSOLUTE_INDEXED(0)
+#define JOYCODE_Z_POS_ABSOLUTE JOYCODE_Z_POS_ABSOLUTE_INDEXED(0)
+#define JOYCODE_Z_NEG_ABSOLUTE JOYCODE_Z_NEG_ABSOLUTE_INDEXED(0)
+#define JOYCODE_U_POS_ABSOLUTE JOYCODE_U_POS_ABSOLUTE_INDEXED(0)
+#define JOYCODE_U_NEG_ABSOLUTE JOYCODE_U_NEG_ABSOLUTE_INDEXED(0)
+#define JOYCODE_V_POS_ABSOLUTE JOYCODE_V_POS_ABSOLUTE_INDEXED(0)
+#define JOYCODE_V_NEG_ABSOLUTE JOYCODE_V_NEG_ABSOLUTE_INDEXED(0)
+#define JOYCODE_W_POS_ABSOLUTE JOYCODE_W_POS_ABSOLUTE_INDEXED(0)
+#define JOYCODE_W_NEG_ABSOLUTE JOYCODE_W_NEG_ABSOLUTE_INDEXED(0)
+
+// joystick axes as switches; X/Y are specially handled for left/right/up/down mapping
+constexpr input_code JOYCODE_X_LEFT_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_LEFT, ITEM_ID_XAXIS); }
+constexpr input_code JOYCODE_X_RIGHT_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_RIGHT, ITEM_ID_XAXIS); }
+constexpr input_code JOYCODE_Y_UP_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_UP, ITEM_ID_YAXIS); }
+constexpr input_code JOYCODE_Y_DOWN_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_DOWN, ITEM_ID_YAXIS); }
+constexpr input_code JOYCODE_Z_POS_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_ZAXIS); }
+constexpr input_code JOYCODE_Z_NEG_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_ZAXIS); }
+constexpr input_code JOYCODE_U_POS_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_RXAXIS); }
+constexpr input_code JOYCODE_U_NEG_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_RXAXIS); }
+constexpr input_code JOYCODE_V_POS_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_RYAXIS); }
+constexpr input_code JOYCODE_V_NEG_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_RYAXIS); }
+constexpr input_code JOYCODE_W_POS_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_RZAXIS); }
+constexpr input_code JOYCODE_W_NEG_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_RZAXIS); }
+
+#define JOYCODE_X_LEFT_SWITCH JOYCODE_X_LEFT_SWITCH_INDEXED(0)
+#define JOYCODE_X_RIGHT_SWITCH JOYCODE_X_RIGHT_SWITCH_INDEXED(0)
+#define JOYCODE_Y_UP_SWITCH JOYCODE_Y_UP_SWITCH_INDEXED(0)
+#define JOYCODE_Y_DOWN_SWITCH JOYCODE_Y_DOWN_SWITCH_INDEXED(0)
+#define JOYCODE_Z_POS_SWITCH JOYCODE_Z_POS_SWITCH_INDEXED(0)
+#define JOYCODE_Z_NEG_SWITCH JOYCODE_Z_NEG_SWITCH_INDEXED(0)
+#define JOYCODE_U_POS_SWITCH JOYCODE_U_POS_SWITCH_INDEXED(0)
+#define JOYCODE_U_NEG_SWITCH JOYCODE_U_NEG_SWITCH_INDEXED(0)
+#define JOYCODE_V_POS_SWITCH JOYCODE_V_POS_SWITCH_INDEXED(0)
+#define JOYCODE_V_NEG_SWITCH JOYCODE_V_NEG_SWITCH_INDEXED(0)
+#define JOYCODE_W_POS_SWITCH JOYCODE_W_POS_SWITCH_INDEXED(0)
+#define JOYCODE_W_NEG_SWITCH JOYCODE_W_NEG_SWITCH_INDEXED(0)
+
+// joystick buttons
+constexpr input_code JOYCODE_BUTTON1_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON1); }
+constexpr input_code JOYCODE_BUTTON2_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON2); }
+constexpr input_code JOYCODE_BUTTON3_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON3); }
+constexpr input_code JOYCODE_BUTTON4_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON4); }
+constexpr input_code JOYCODE_BUTTON5_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON5); }
+constexpr input_code JOYCODE_BUTTON6_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON6); }
+constexpr input_code JOYCODE_BUTTON7_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON7); }
+constexpr input_code JOYCODE_BUTTON8_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON8); }
+constexpr input_code JOYCODE_BUTTON9_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON9); }
+constexpr input_code JOYCODE_BUTTON10_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON10); }
+constexpr input_code JOYCODE_BUTTON11_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON11); }
+constexpr input_code JOYCODE_BUTTON12_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON12); }
+constexpr input_code JOYCODE_BUTTON13_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON13); }
+constexpr input_code JOYCODE_BUTTON14_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON14); }
+constexpr input_code JOYCODE_BUTTON15_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON15); }
+constexpr input_code JOYCODE_BUTTON16_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON16); }
+constexpr input_code JOYCODE_BUTTON17_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON17); }
+constexpr input_code JOYCODE_BUTTON18_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON18); }
+constexpr input_code JOYCODE_BUTTON19_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON19); }
+constexpr input_code JOYCODE_BUTTON20_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON20); }
+constexpr input_code JOYCODE_BUTTON21_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON21); }
+constexpr input_code JOYCODE_BUTTON22_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON22); }
+constexpr input_code JOYCODE_BUTTON23_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON23); }
+constexpr input_code JOYCODE_BUTTON24_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON24); }
+constexpr input_code JOYCODE_BUTTON25_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON25); }
+constexpr input_code JOYCODE_BUTTON26_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON26); }
+constexpr input_code JOYCODE_BUTTON27_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON27); }
+constexpr input_code JOYCODE_BUTTON28_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON28); }
+constexpr input_code JOYCODE_BUTTON29_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON29); }
+constexpr input_code JOYCODE_BUTTON30_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON30); }
+constexpr input_code JOYCODE_BUTTON31_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON31); }
+constexpr input_code JOYCODE_BUTTON32_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON32); }
+constexpr input_code JOYCODE_START_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_START); }
+constexpr input_code JOYCODE_SELECT_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_SELECT); }
+
+#define JOYCODE_BUTTON1 JOYCODE_BUTTON1_INDEXED(0)
+#define JOYCODE_BUTTON2 JOYCODE_BUTTON2_INDEXED(0)
+#define JOYCODE_BUTTON3 JOYCODE_BUTTON3_INDEXED(0)
+#define JOYCODE_BUTTON4 JOYCODE_BUTTON4_INDEXED(0)
+#define JOYCODE_BUTTON5 JOYCODE_BUTTON5_INDEXED(0)
+#define JOYCODE_BUTTON6 JOYCODE_BUTTON6_INDEXED(0)
+#define JOYCODE_BUTTON7 JOYCODE_BUTTON7_INDEXED(0)
+#define JOYCODE_BUTTON8 JOYCODE_BUTTON8_INDEXED(0)
+#define JOYCODE_BUTTON9 JOYCODE_BUTTON9_INDEXED(0)
+#define JOYCODE_BUTTON10 JOYCODE_BUTTON10_INDEXED(0)
+#define JOYCODE_BUTTON11 JOYCODE_BUTTON11_INDEXED(0)
+#define JOYCODE_BUTTON12 JOYCODE_BUTTON12_INDEXED(0)
+#define JOYCODE_BUTTON13 JOYCODE_BUTTON13_INDEXED(0)
+#define JOYCODE_BUTTON14 JOYCODE_BUTTON14_INDEXED(0)
+#define JOYCODE_BUTTON15 JOYCODE_BUTTON15_INDEXED(0)
+#define JOYCODE_BUTTON16 JOYCODE_BUTTON16_INDEXED(0)
+#define JOYCODE_BUTTON17 JOYCODE_BUTTON17_INDEXED(0)
+#define JOYCODE_BUTTON18 JOYCODE_BUTTON18_INDEXED(0)
+#define JOYCODE_BUTTON19 JOYCODE_BUTTON19_INDEXED(0)
+#define JOYCODE_BUTTON20 JOYCODE_BUTTON20_INDEXED(0)
+#define JOYCODE_BUTTON21 JOYCODE_BUTTON21_INDEXED(0)
+#define JOYCODE_BUTTON22 JOYCODE_BUTTON22_INDEXED(0)
+#define JOYCODE_BUTTON23 JOYCODE_BUTTON23_INDEXED(0)
+#define JOYCODE_BUTTON24 JOYCODE_BUTTON24_INDEXED(0)
+#define JOYCODE_BUTTON25 JOYCODE_BUTTON25_INDEXED(0)
+#define JOYCODE_BUTTON26 JOYCODE_BUTTON26_INDEXED(0)
+#define JOYCODE_BUTTON27 JOYCODE_BUTTON27_INDEXED(0)
+#define JOYCODE_BUTTON28 JOYCODE_BUTTON28_INDEXED(0)
+#define JOYCODE_BUTTON29 JOYCODE_BUTTON29_INDEXED(0)
+#define JOYCODE_BUTTON30 JOYCODE_BUTTON30_INDEXED(0)
+#define JOYCODE_BUTTON31 JOYCODE_BUTTON31_INDEXED(0)
+#define JOYCODE_BUTTON32 JOYCODE_BUTTON32_INDEXED(0)
+#define JOYCODE_START JOYCODE_START_INDEXED(0)
+#define JOYCODE_SELECT JOYCODE_SELECT_INDEXED(0)
+
+// joystick hats
+constexpr input_code JOYCODE_HAT1UP_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_HAT1UP); }
+constexpr input_code JOYCODE_HAT1DOWN_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_HAT1DOWN); }
+constexpr input_code JOYCODE_HAT1LEFT_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_HAT1LEFT); }
+constexpr input_code JOYCODE_HAT1RIGHT_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_HAT1RIGHT); }
+constexpr input_code JOYCODE_HAT2UP_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_HAT2UP); }
+constexpr input_code JOYCODE_HAT2DOWN_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_HAT2DOWN); }
+constexpr input_code JOYCODE_HAT2LEFT_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_HAT2LEFT); }
+constexpr input_code JOYCODE_HAT2RIGHT_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_HAT2RIGHT); }
+constexpr input_code JOYCODE_HAT3UP_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_HAT3UP); }
+constexpr input_code JOYCODE_HAT3DOWN_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_HAT3DOWN); }
+constexpr input_code JOYCODE_HAT3LEFT_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_HAT3LEFT); }
+constexpr input_code JOYCODE_HAT3RIGHT_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_HAT3RIGHT); }
+constexpr input_code JOYCODE_HAT4UP_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_HAT4UP); }
+constexpr input_code JOYCODE_HAT4DOWN_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_HAT4DOWN); }
+constexpr input_code JOYCODE_HAT4LEFT_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_HAT4LEFT); }
+constexpr input_code JOYCODE_HAT4RIGHT_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_HAT4RIGHT); }
+
+#define JOYCODE_HAT1UP JOYCODE_HAT1UP_INDEXED(0)
+#define JOYCODE_HAT1DOWN JOYCODE_HAT1DOWN_INDEXED(0)
+#define JOYCODE_HAT1LEFT JOYCODE_HAT1LEFT_INDEXED(0)
+#define JOYCODE_HAT1RIGHT JOYCODE_HAT1RIGHT_INDEXED(0)
+#define JOYCODE_HAT2UP JOYCODE_HAT2UP_INDEXED(0)
+#define JOYCODE_HAT2DOWN JOYCODE_HAT2DOWN_INDEXED(0)
+#define JOYCODE_HAT2LEFT JOYCODE_HAT2LEFT_INDEXED(0)
+#define JOYCODE_HAT2RIGHT JOYCODE_HAT2RIGHT_INDEXED(0)
+#define JOYCODE_HAT3UP JOYCODE_HAT3UP_INDEXED(0)
+#define JOYCODE_HAT3DOWN JOYCODE_HAT3DOWN_INDEXED(0)
+#define JOYCODE_HAT3LEFT JOYCODE_HAT3LEFT_INDEXED(0)
+#define JOYCODE_HAT3RIGHT JOYCODE_HAT3RIGHT_INDEXED(0)
+#define JOYCODE_HAT4UP JOYCODE_HAT4UP_INDEXED(0)
+#define JOYCODE_HAT4DOWN JOYCODE_HAT4DOWN_INDEXED(0)
+#define JOYCODE_HAT4LEFT JOYCODE_HAT4LEFT_INDEXED(0)
+#define JOYCODE_HAT4RIGHT JOYCODE_HAT4RIGHT_INDEXED(0)
+
+
+#endif // MAME_OSD_INTERFACE_INPUTCODE_H
diff --git a/src/osd/interface/inputdev.h b/src/osd/interface/inputdev.h
new file mode 100644
index 00000000000..564c1c426d8
--- /dev/null
+++ b/src/osd/interface/inputdev.h
@@ -0,0 +1,66 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ inputdev.h
+
+ OSD interface to input devices
+
+***************************************************************************/
+#ifndef MAME_OSD_INTERFACE_INPUTDEV_H
+#define MAME_OSD_INTERFACE_INPUTDEV_H
+
+#pragma once
+
+#include "inputcode.h"
+#include "inputfwd.h"
+
+#include <string_view>
+#include <tuple>
+#include <vector>
+
+
+namespace osd {
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// base for application representation of host input device
+
+class input_device
+{
+protected:
+ virtual ~input_device() = default;
+
+public:
+ using assignment_vector = std::vector<std::tuple<ioport_type, input_seq_type, input_seq> >;
+
+ // relative devices return ~512 units per on-screen pixel
+ static inline constexpr s32 RELATIVE_PER_PIXEL = 512;
+
+ // absolute devices return values between -65536 and +65536
+ static inline constexpr s32 ABSOLUTE_MIN = -65'536;
+ static inline constexpr s32 ABSOLUTE_MAX = 65'536;
+
+ // invalid memory value for axis polling
+ static inline constexpr s32 INVALID_AXIS_VALUE = 0x7fff'ffff;
+
+ // callback for getting the value of an individual input on a device
+ typedef s32 (*item_get_state_func)(void *device_internal, void *item_internal);
+
+ // add a control item to an input device
+ virtual input_item_id add_item(
+ std::string_view name,
+ std::string_view tokenhint,
+ input_item_id itemid,
+ item_get_state_func getstate,
+ void *internal) = 0;
+
+ // set additional default assignments suitable for device
+ virtual void set_default_assignments(assignment_vector &&assignments) = 0;
+};
+
+} // namespace osd
+
+#endif // MAME_OSD_INTERFACE_INPUTDEV_H
diff --git a/src/osd/interface/inputfwd.h b/src/osd/interface/inputfwd.h
new file mode 100644
index 00000000000..b87831fca59
--- /dev/null
+++ b/src/osd/interface/inputfwd.h
@@ -0,0 +1,36 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ inputfwd.h
+
+ Forward declarations for OSD input interface types
+
+***************************************************************************/
+#ifndef MAME_OSD_INTERFACE_INPUTFWD_H
+#define MAME_OSD_INTERFACE_INPUTFWD_H
+
+#include <cstdint>
+
+#pragma once
+
+
+//**************************************************************************
+// FORWARD DECLARATIONS
+//**************************************************************************
+
+enum ioport_type : std::uint32_t;
+enum input_seq_type : int;
+
+class input_code;
+
+
+namespace osd {
+
+class input_device;
+class input_manager;
+class input_seq;
+
+} // namespace osd
+
+#endif // MAME_OSD_INTERFACE_INPUTFWD_H
diff --git a/src/osd/interface/inputman.h b/src/osd/interface/inputman.h
new file mode 100644
index 00000000000..da4c1b6b9f5
--- /dev/null
+++ b/src/osd/interface/inputman.h
@@ -0,0 +1,46 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ inputman.h
+
+ OSD interface to the input manager
+
+***************************************************************************/
+#ifndef MAME_OSD_INTERFACE_INPUTMAN_H
+#define MAME_OSD_INTERFACE_INPUTMAN_H
+
+#pragma once
+
+#include "inputcode.h"
+#include "inputfwd.h"
+
+#include <string_view>
+
+
+namespace osd {
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// interface to application input manager
+
+class input_manager
+{
+protected:
+ virtual ~input_manager() = default;
+
+public:
+ virtual bool class_enabled(input_device_class devclass) const = 0;
+
+ virtual input_device &add_device(
+ input_device_class devclass,
+ std::string_view name,
+ std::string_view id,
+ void *internal = nullptr) = 0;
+};
+
+} // namespace osd
+
+#endif // MAME_OSD_INTERFACE_INPUTMAN_H
diff --git a/src/osd/interface/inputseq.cpp b/src/osd/interface/inputseq.cpp
new file mode 100644
index 00000000000..da1f2b98b26
--- /dev/null
+++ b/src/osd/interface/inputseq.cpp
@@ -0,0 +1,210 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ inputseq.cpp
+
+ A combination of hosts inputs that can be assigned to a control.
+
+***************************************************************************/
+
+#include "inputseq.h"
+
+
+namespace osd {
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+// additional expanded input codes for sequences
+constexpr input_code input_seq::end_code;
+constexpr input_code input_seq::default_code;
+constexpr input_code input_seq::not_code;
+constexpr input_code input_seq::or_code;
+
+// constant sequences
+const input_seq input_seq::empty_seq;
+
+
+
+//**************************************************************************
+// INPUT SEQ
+//**************************************************************************
+
+//-------------------------------------------------
+// operator+= - append a code to the end of an
+// input sequence
+//-------------------------------------------------
+
+input_seq &input_seq::operator+=(input_code code) noexcept
+{
+ // if not enough room, return false
+ const int curlength = length();
+ if (curlength < m_code.size())
+ {
+ m_code[curlength] = code;
+ if ((curlength + 1) < m_code.size())
+ m_code[curlength + 1] = end_code;
+ }
+ return *this;
+}
+
+
+//-------------------------------------------------
+// operator|= - append a code to a sequence; if
+// the sequence is non-empty, insert an OR
+// before the new code
+//-------------------------------------------------
+
+input_seq &input_seq::operator|=(input_code code) noexcept
+{
+ // overwrite end/default with the new code
+ if (m_code[0] == default_code)
+ {
+ m_code[0] = code;
+ m_code[1] = end_code;
+ }
+ else
+ {
+ // otherwise, append an OR token and then the new code
+ const int curlength = length();
+ if ((curlength + 1) < m_code.size())
+ {
+ m_code[curlength] = or_code;
+ m_code[curlength + 1] = code;
+ if ((curlength + 2) < m_code.size())
+ m_code[curlength + 2] = end_code;
+ }
+ }
+ return *this;
+}
+
+
+//-------------------------------------------------
+// length - return the length of the sequence
+//-------------------------------------------------
+
+int input_seq::length() const noexcept
+{
+ // find the end token; error if none found
+ for (int seqnum = 0; seqnum < m_code.size(); seqnum++)
+ if (m_code[seqnum] == end_code)
+ return seqnum;
+ return m_code.size();
+}
+
+
+//-------------------------------------------------
+// is_valid - return true if a given sequence is
+// valid
+//-------------------------------------------------
+
+bool input_seq::is_valid() const noexcept
+{
+ // "default" can only be of length 1
+ if (m_code[0] == default_code)
+ return m_code[1] == end_code;
+
+ // scan the sequence for valid codes
+ input_item_class lastclass = ITEM_CLASS_INVALID;
+ input_code lastcode = INPUT_CODE_INVALID;
+ decltype(m_code) positive_codes;
+ decltype(m_code) negative_codes;
+ auto positive_codes_end = positive_codes.begin();
+ auto negative_codes_end = negative_codes.begin();
+ for (input_code code : m_code)
+ {
+ // invalid codes are never permitted
+ if (code == INPUT_CODE_INVALID)
+ return false;
+
+ // if we hit an OR or the end, validate the previous chunk
+ if (code == or_code || code == end_code)
+ {
+ // must be at least one positive code
+ if (positive_codes.begin() == positive_codes_end)
+ return false;
+
+ // last code must not have been an internal code
+ if (lastcode.internal())
+ return false;
+
+ // if this is the end, we're ok
+ if (code == end_code)
+ return true;
+
+ // reset the state for the next chunk
+ positive_codes_end = positive_codes.begin();
+ negative_codes_end = negative_codes.begin();
+ lastclass = ITEM_CLASS_INVALID;
+ }
+ else if (code == not_code)
+ {
+ // if we hit a NOT, make sure we don't have a double
+ if (lastcode == not_code)
+ return false;
+ }
+ else
+ {
+ // track positive codes, and don't allow positive and negative for the same code
+ if (lastcode != not_code)
+ {
+ *positive_codes_end++ = code;
+ if (std::find(negative_codes.begin(), negative_codes_end, code) != negative_codes_end)
+ return false;
+ }
+ else
+ {
+ *negative_codes_end++ = code;
+ if (std::find(positive_codes.begin(), positive_codes_end, code) != positive_codes_end)
+ return false;
+ }
+
+ // non-switch items can't have a NOT
+ input_item_class itemclass = code.item_class();
+ if (itemclass != ITEM_CLASS_SWITCH && lastcode == not_code)
+ return false;
+
+ // absolute/relative items must all be the same class
+ if ((lastclass == ITEM_CLASS_ABSOLUTE && itemclass != ITEM_CLASS_ABSOLUTE) ||
+ (lastclass == ITEM_CLASS_RELATIVE && itemclass != ITEM_CLASS_RELATIVE))
+ return false;
+ }
+
+ // remember the last code
+ lastcode = code;
+ }
+
+ // if we got here, we were missing an END token; fail
+ return false;
+}
+
+
+//-------------------------------------------------
+// backspace - "backspace" over the last entry in
+// a sequence
+//-------------------------------------------------
+
+void input_seq::backspace() noexcept
+{
+ // if we have at least one entry, remove it
+ const int curlength = length();
+ if (curlength > 0)
+ m_code[curlength - 1] = end_code;
+}
+
+
+//-------------------------------------------------
+// replace - replace all instances of oldcode
+// with newcode in a sequence
+//-------------------------------------------------
+
+void input_seq::replace(input_code oldcode, input_code newcode) noexcept
+{
+ for (input_code &elem : m_code)
+ if (elem == oldcode)
+ elem = newcode;
+}
+
+} // namespace osd
diff --git a/src/osd/interface/inputseq.h b/src/osd/interface/inputseq.h
new file mode 100644
index 00000000000..62704462d47
--- /dev/null
+++ b/src/osd/interface/inputseq.h
@@ -0,0 +1,107 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ inputseq.h
+
+ A combination of hosts inputs that can be assigned to a control.
+
+***************************************************************************/
+#ifndef MAME_OSD_INTERFACE_INPUTSEQ_H
+#define MAME_OSD_INTERFACE_INPUTSEQ_H
+
+#pragma once
+
+#include "inputcode.h"
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <utility>
+
+
+namespace osd {
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// a combination of input_codes, supporting AND/OR and inversion
+
+class input_seq
+{
+public:
+ // construction/destruction
+ input_seq() noexcept : input_seq(std::make_index_sequence<std::tuple_size<decltype(m_code)>::value>())
+ {
+ }
+ template <typename... T>
+ input_seq(input_code code_0, T... code_n) noexcept :
+ input_seq(std::make_index_sequence<std::tuple_size<decltype(m_code)>::value - sizeof...(T) - 1>(), code_0, code_n...)
+ {
+ }
+ constexpr input_seq(const input_seq &rhs) noexcept = default;
+
+ // operators
+ bool operator==(const input_seq &rhs) const noexcept { return m_code == rhs.m_code; }
+ bool operator!=(const input_seq &rhs) const noexcept { return m_code != rhs.m_code; }
+ constexpr input_code operator[](int index) const noexcept { return (index >= 0 && index < m_code.size()) ? m_code[index] : end_code; }
+ input_seq &operator+=(input_code code) noexcept;
+ input_seq &operator|=(input_code code) noexcept;
+
+ // getters
+ constexpr bool empty() const noexcept { return m_code[0] == end_code; }
+ constexpr int max_size() const noexcept { return std::tuple_size<decltype(m_code)>::value; }
+ int length() const noexcept;
+ bool is_valid() const noexcept;
+ constexpr bool is_default() const noexcept { return m_code[0] == default_code; }
+
+ // setters
+ template <typename... T> void set(input_code code_0, T... code_n) noexcept
+ {
+ static_assert(sizeof...(T) < std::tuple_size<decltype(m_code)>::value, "too many codes for input_seq");
+ set<0>(code_0, code_n...);
+ }
+ void reset() noexcept { set(end_code); }
+ void set_default() noexcept { set(default_code); }
+ void backspace() noexcept;
+ void replace(input_code oldcode, input_code newcode) noexcept;
+
+ // constant codes used in sequences
+ static constexpr input_code end_code { DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_END };
+ static constexpr input_code default_code { DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_DEFAULT };
+ static constexpr input_code not_code { DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_NOT };
+ static constexpr input_code or_code { DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_OR };
+
+ // constant sequences
+ static const input_seq empty_seq;
+
+private:
+ static constexpr input_code get_end_code(size_t) noexcept { return end_code; }
+
+ template <size_t... N, typename... T>
+ input_seq(std::integer_sequence<size_t, N...>, T... code) noexcept : m_code({ code..., get_end_code(N)... })
+ {
+ }
+ template <size_t... N>
+ input_seq(std::integer_sequence<size_t, N...>) noexcept : m_code({ get_end_code(N)... })
+ {
+ }
+
+ template <unsigned N> void set() noexcept
+ {
+ std::fill(std::next(m_code.begin(), N), m_code.end(), end_code);
+ }
+ template <unsigned N, typename... T> void set(input_code code_0, T... code_n) noexcept
+ {
+ m_code[N] = code_0;
+ set<N + 1>(code_n...);
+ }
+
+ // internal state
+ std::array<input_code, 16> m_code;
+};
+
+} // namespace osd
+
+#endif // MAME_OSD_INTERFACE_INPUTSEQ_H
diff --git a/src/osd/interface/midiport.h b/src/osd/interface/midiport.h
new file mode 100644
index 00000000000..47c5bbc5c52
--- /dev/null
+++ b/src/osd/interface/midiport.h
@@ -0,0 +1,50 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ midiport.h
+
+ OSD interface to midi ports
+
+***************************************************************************/
+#ifndef MAME_OSD_INTERFACE_MIDIPORT_H
+#define MAME_OSD_INTERFACE_MIDIPORT_H
+
+#pragma once
+
+#include <cstdint>
+#include <string>
+
+
+namespace osd {
+
+class midi_input_port
+{
+public:
+ virtual ~midi_input_port() = default;
+
+ virtual bool poll() = 0;
+ virtual int read(uint8_t *pOut) = 0;
+};
+
+
+class midi_output_port
+{
+public:
+ virtual ~midi_output_port() = default;
+
+ virtual void write(uint8_t data) = 0;
+};
+
+struct midi_port_info
+{
+ std::string name;
+ bool input;
+ bool output;
+ bool default_input;
+ bool default_output;
+};
+
+} // namespace osd
+
+#endif // MAME_OSD_INTERFACE_MIDIPORT_H
diff --git a/src/osd/interface/nethandler.cpp b/src/osd/interface/nethandler.cpp
new file mode 100644
index 00000000000..f3715df9b12
--- /dev/null
+++ b/src/osd/interface/nethandler.cpp
@@ -0,0 +1,23 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ nethandler.cpp
+
+ OSD interface to virtual networking handlers
+
+***************************************************************************/
+
+#include "nethandler.h"
+
+#include <algorithm>
+
+
+namespace osd {
+
+network_handler::network_handler() noexcept
+{
+ std::fill(std::begin(m_mac), std::end(m_mac), 0);
+}
+
+} // namespace osd
diff --git a/src/osd/interface/nethandler.h b/src/osd/interface/nethandler.h
new file mode 100644
index 00000000000..9513b158d99
--- /dev/null
+++ b/src/osd/interface/nethandler.h
@@ -0,0 +1,70 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ nethandler.h
+
+ OSD interface to virtual networking handlers
+
+***************************************************************************/
+#ifndef MAME_OSD_INTERFACE_NETHANDLER_H
+#define MAME_OSD_INTERFACE_NETHANDLER_H
+
+#pragma once
+
+#include "osdcomm.h"
+
+#include <array>
+#include <string_view>
+
+
+namespace osd {
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+
+// base for virtual network interface handler
+
+class network_handler
+{
+public:
+ network_handler() noexcept;
+
+ virtual void recv_cb(u8 *buf, int len) = 0;
+
+ std::array<u8, 6> const &get_mac() noexcept { return m_mac; }
+
+protected:
+ ~network_handler() = default;
+
+ std::array<u8, 6> m_mac;
+};
+
+
+// interface to network device
+
+class network_device
+{
+public:
+ virtual ~network_device() = default;
+
+ virtual void start() = 0;
+ virtual void stop() = 0;
+ virtual void poll() = 0;
+ virtual int send(const void *buf, int len) = 0;
+};
+
+
+// description of an available network device
+
+struct network_device_info
+{
+ int id;
+ std::string_view description;
+};
+
+} // namespace osd
+
+#endif // MAME_OSD_INTERFACE_NETHANDLER_H
diff --git a/src/osd/interface/uievents.h b/src/osd/interface/uievents.h
new file mode 100644
index 00000000000..199d612713a
--- /dev/null
+++ b/src/osd/interface/uievents.h
@@ -0,0 +1,61 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles, Vas Crabb
+/***************************************************************************
+
+ uievents.h
+
+ OSD UI event interfaces
+
+***************************************************************************/
+#ifndef MAME_OSD_INTERFACE_UIEVENTS_H
+#define MAME_OSD_INTERFACE_UIEVENTS_H
+
+
+//**************************************************************************
+// FORWARD DECLARATIONS
+//**************************************************************************
+
+class render_target;
+
+
+namespace osd {
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// UI event handler interface
+
+class ui_event_handler
+{
+protected:
+ ~ui_event_handler() = default;
+
+public:
+ enum class pointer
+ {
+ UNKNOWN,
+ MOUSE,
+ PEN,
+ TOUCH
+ };
+
+ // window events
+ virtual void push_window_focus_event(render_target *target) = 0;
+ virtual void push_window_defocus_event(render_target *target) = 0;
+
+ // legacy mouse events
+ virtual void push_mouse_wheel_event(render_target *target, s32 x, s32 y, short delta, int lines) = 0;
+
+ // pointer events
+ virtual void push_pointer_update(render_target *target, pointer type, u16 ptrid, u16 device, s32 x, s32 y, u32 buttons, u32 pressed, u32 released, s16 clicks) = 0;
+ virtual void push_pointer_leave(render_target *target, pointer type, u16 ptrid, u16 device, s32 x, s32 y, u32 released, s16 clicks) = 0;
+ virtual void push_pointer_abort(render_target *target, pointer type, u16 ptrid, u16 device, s32 x, s32 y, u32 released, s16 clicks) = 0;
+
+ // text input events
+ virtual void push_char_event(render_target *target, char32_t ch) = 0;
+};
+
+} // namespace osd
+
+#endif // MAME_OSD_INTERFACE_UIEVENTS_H
diff --git a/src/osd/mac/macmain.cpp b/src/osd/mac/macmain.cpp
index 40bcd7d1882..a778046c159 100644
--- a/src/osd/mac/macmain.cpp
+++ b/src/osd/mac/macmain.cpp
@@ -17,8 +17,10 @@
#include <unistd.h>
// MAME headers
+#include "corestr.h"
#include "osdepend.h"
#include "emu.h"
+#include "main.h"
#include "emuopts.h"
#include "strconv.h"
@@ -41,12 +43,11 @@
//============================================================
const options_entry mac_options::s_option_entries[] =
-{
- { MACOPTION_INIPATH, INI_PATH, OPTION_STRING, "path to ini files" },
+ {
+ {MACOPTION_INIPATH, INI_PATH, core_options::option_type::STRING, "path to ini files"},
- // End of list
- { nullptr }
-};
+ // End of list
+ {nullptr}};
//============================================================
// mac_options
@@ -58,7 +59,7 @@ mac_options::mac_options()
std::string ini_path(INI_PATH);
add_entries(mac_options::s_option_entries);
strreplace(ini_path,"APP_NAME", emulator_info::get_appname_lower());
- set_default_value(MACOPTION_INIPATH, ini_path.c_str());
+ set_default_value(MACOPTION_INIPATH, std::move(ini_path));
}
//============================================================
@@ -146,7 +147,6 @@ static void defines_verbose(void)
osd_printf_verbose("\n");
osd_printf_verbose("Build defines 1: ");
MACRO_VERBOSE(LSB_FIRST);
- MACRO_VERBOSE(PTR64);
MACRO_VERBOSE(MAME_NOASM);
MACRO_VERBOSE(MAME_DEBUG);
MACRO_VERBOSE(BIGENDIAN);
@@ -192,8 +192,6 @@ static void osd_mac_info(void)
void mac_osd_interface::video_register()
{
- video_options_add("opengl", nullptr);
- video_options_add("bgfx", nullptr);
}
//============================================================
@@ -231,6 +229,7 @@ void mac_osd_interface::init(running_machine &machine)
int bench = options().bench();
if (bench > 0)
{
+ options().set_value(OPTION_SLEEP, false, OPTION_PRIORITY_MAXIMUM);
options().set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM);
options().set_value(OSDOPTION_SOUND, "none", OPTION_PRIORITY_MAXIMUM);
options().set_value(OSDOPTION_VIDEO, "none", OPTION_PRIORITY_MAXIMUM);
diff --git a/src/osd/mac/osdmac.h b/src/osd/mac/osdmac.h
index 1ed9e6b8a5b..081c5757c17 100644
--- a/src/osd/mac/osdmac.h
+++ b/src/osd/mac/osdmac.h
@@ -44,11 +44,13 @@ public:
// general overridables
virtual void init(running_machine &machine) override;
virtual void update(bool skip_redraw) override;
+ virtual void input_update(bool relative_reset) override;
+ virtual void check_osd_inputs() override;
// input overridables
- virtual void customize_input_type_list(simple_list<input_type_entry> &typelist) override;
+ virtual void customize_input_type_list(std::vector<input_type_entry> &typelist) override;
- virtual void video_register() override;
+ virtual void video_register();
virtual bool video_init() override;
virtual bool window_init() override;
@@ -56,18 +58,16 @@ public:
virtual void video_exit() override;
virtual void window_exit() override;
+ virtual void process_events() override;
+ virtual bool has_focus() const override;
+
// sdl specific
- void poll_inputs(running_machine &machine);
void release_keys();
bool should_hide_mouse();
void process_events_buf();
virtual mac_options &options() override { return m_options; }
-protected:
- virtual void build_slider_list() override;
- virtual void update_slider_list() override;
-
private:
virtual void osd_exit() override;
diff --git a/src/osd/mac/video.cpp b/src/osd/mac/video.cpp
index 638e7a949b3..d441b5f07f3 100644
--- a/src/osd/mac/video.cpp
+++ b/src/osd/mac/video.cpp
@@ -21,6 +21,9 @@
#include "window.h"
#include "osdmac.h"
#include "modules/lib/osdlib.h"
+#include "modules/monitor/monitor_module.h"
+
+extern void MacPollInputs(); // in windowcontroller.mm
//============================================================
// CONSTANTS
@@ -41,9 +44,6 @@ osd_video_config video_config;
//============================================================
// PROTOTYPES
//============================================================
-
-static void check_osd_inputs(running_machine &machine);
-
static void get_resolution(const char *defdata, const char *data, osd_window_config *config, int report_error);
@@ -73,10 +73,12 @@ bool mac_osd_interface::video_init()
get_resolution(options().resolution(), options().resolution(index), &conf, true);
// create window ...
- std::shared_ptr<mac_window_info> win = std::make_shared<mac_window_info>(machine(), index, m_monitor_module->pick_monitor(reinterpret_cast<osd_options &>(options()), index), &conf);
+ auto win = std::make_unique<mac_window_info>(machine(), *m_render, index, m_monitor_module->pick_monitor(reinterpret_cast<osd_options &>(options()), index), &conf);
if (win->window_init())
return false;
+
+ s_window_list.emplace_back(std::move(win));
}
return true;
@@ -103,64 +105,60 @@ void mac_osd_interface::update(bool skip_redraw)
if (!skip_redraw)
{
// profiler_mark(PROFILER_BLIT);
- for (auto window : osd_common_t::s_window_list)
+ for (auto const &window : osd_common_t::window_list())
window->update();
// profiler_mark(PROFILER_END);
}
- // poll the joystick values here
- downcast<mac_osd_interface&>(machine().osd()).poll_inputs(machine());
-
- check_osd_inputs(machine());
// if we're running, disable some parts of the debugger
if ((machine().debug_flags & DEBUG_FLAG_OSD_ENABLED) != 0)
debugger_update();
}
//============================================================
-// check_osd_inputs
+// input_update
//============================================================
-static void check_osd_inputs(running_machine &machine)
+void mac_osd_interface::input_update(bool relative_reset)
{
- // check for toggling fullscreen mode
- if (machine.ui_input().pressed(IPT_OSD_1))
- {
- for (auto curwin : osd_common_t::s_window_list)
- std::static_pointer_cast<mac_window_info>(curwin)->toggle_full_screen();
- }
+ // poll the joystick values here
+ process_events_buf();
+ MacPollInputs();
+ poll_input_modules(relative_reset);
+}
- auto window = osd_common_t::s_window_list.front();
- if (machine.ui_input().pressed(IPT_OSD_2))
- {
- //FIXME: on a per window basis
- video_config.fullstretch = !video_config.fullstretch;
- window->target()->set_scale_mode(video_config.fullstretch? SCALE_FRACTIONAL : SCALE_INTEGER);
- machine.ui().popup_time(1, "Uneven stretch %s", video_config.fullstretch? "enabled":"disabled");
- }
+//============================================================
+// check_osd_inputs
+//============================================================
- if (machine.ui_input().pressed(IPT_OSD_4))
+void mac_osd_interface::check_osd_inputs()
+{
+ // check for toggling fullscreen mode (don't do this in debug mode)
+ if (machine().ui_input().pressed(IPT_OSD_1) && !(machine().debug_flags & DEBUG_FLAG_OSD_ENABLED))
{
- //FIXME: on a per window basis
- video_config.keepaspect = !video_config.keepaspect;
- window->target()->set_keepaspect(video_config.keepaspect);
- machine.ui().popup_time(1, "Keepaspect %s", video_config.keepaspect? "enabled":"disabled");
+ // destroy the renderers first so that the render module can bounce if it depends on having a window handle
+ for (auto it = window_list().rbegin(); window_list().rend() != it; ++it)
+ (*it)->renderer_reset();
+ for (auto const &curwin : window_list())
+ dynamic_cast<mac_window_info &>(*curwin).toggle_full_screen();
}
+ auto const &window = window_list().front();
+
//FIXME: on a per window basis
- if (machine.ui_input().pressed(IPT_OSD_5))
+ if (machine().ui_input().pressed(IPT_OSD_5))
{
video_config.filter = !video_config.filter;
- machine.ui().popup_time(1, "Filter %s", video_config.filter? "enabled":"disabled");
+ machine().ui().popup_time(1, "Filter %s", video_config.filter? "enabled":"disabled");
}
- if (machine.ui_input().pressed(IPT_OSD_6))
- std::static_pointer_cast<mac_window_info>(window)->modify_prescale(-1);
+ if (machine().ui_input().pressed(IPT_OSD_6))
+ dynamic_cast<mac_window_info &>(*window).modify_prescale(-1);
- if (machine.ui_input().pressed(IPT_OSD_7))
- std::static_pointer_cast<mac_window_info>(window)->modify_prescale(1);
+ if (machine().ui_input().pressed(IPT_OSD_7))
+ dynamic_cast<mac_window_info &>(*window).modify_prescale(1);
- if (machine.ui_input().pressed(IPT_OSD_8))
+ if (machine().ui_input().pressed(IPT_OSD_8))
window->renderer().record();
}
@@ -170,51 +168,16 @@ static void check_osd_inputs(running_machine &machine)
void mac_osd_interface::extract_video_config()
{
- const char *stemp;
-
// global options: extract the data
video_config.windowed = options().window();
video_config.prescale = options().prescale();
video_config.filter = options().filter();
- video_config.keepaspect = options().keep_aspect();
video_config.numscreens = options().numscreens();
- video_config.fullstretch = options().uneven_stretch();
// if we are in debug mode, never go full screen
if (machine().debug_flags & DEBUG_FLAG_OSD_ENABLED)
video_config.windowed = true;
- // default to working video please
- video_config.novideo = 0;
-
- // d3d options: extract the data
- stemp = options().video();
- if (strcmp(stemp, "auto") == 0)
- {
- stemp = "opengl";
- }
-
- if (strcmp(stemp, OSDOPTVAL_NONE) == 0)
- {
- video_config.mode = VIDEO_MODE_SOFT;
- video_config.novideo = 1;
-
- if (!emulator_info::standalone() && options().seconds_to_run() == 0)
- osd_printf_warning("Warning: -video none doesn't make much sense without -seconds_to_run\n");
- }
-
- else if (strcmp(stemp, MACOPTVAL_OPENGL) == 0)
- video_config.mode = VIDEO_MODE_OPENGL;
- else if (strcmp(stemp, MACOPTVAL_BGFX) == 0)
- {
- video_config.mode = VIDEO_MODE_BGFX;
- }
- else
- {
- osd_printf_warning("Invalid video value %s; reverting to OpenGL\n", stemp);
- video_config.mode = VIDEO_MODE_OPENGL;
- }
-
video_config.switchres = options().switch_res();
video_config.waitvsync = options().wait_vsync();
video_config.syncrefresh = options().sync_refresh();
@@ -224,63 +187,12 @@ void mac_osd_interface::extract_video_config()
video_config.syncrefresh = 0;
}
- if (video_config.prescale < 1 || video_config.prescale > 3)
+ if (video_config.prescale < 1 || video_config.prescale > 8)
{
osd_printf_warning("Invalid prescale option, reverting to '1'\n");
video_config.prescale = 1;
}
- // default to working video please
- video_config.forcepow2texture = options().gl_force_pow2_texture();
- video_config.allowtexturerect = !(options().gl_no_texture_rect());
- video_config.vbo = options().gl_vbo();
- video_config.pbo = options().gl_pbo();
- video_config.glsl = options().gl_glsl();
- if ( video_config.glsl )
- {
- int i;
- video_config.glsl_filter = options().glsl_filter();
- video_config.glsl_shader_mamebm_num=0;
- for(i=0; i<GLSL_SHADER_MAX; i++)
- {
- stemp = options().shader_mame(i);
- if (stemp && strcmp(stemp, OSDOPTVAL_NONE) != 0 && strlen(stemp)>0)
- {
- video_config.glsl_shader_mamebm[i] = (char *) malloc(strlen(stemp)+1);
- strcpy(video_config.glsl_shader_mamebm[i], stemp);
- video_config.glsl_shader_mamebm_num++;
- } else {
- video_config.glsl_shader_mamebm[i] = nullptr;
- }
- }
- video_config.glsl_shader_scrn_num=0;
- for(i=0; i<GLSL_SHADER_MAX; i++)
- {
- stemp = options().shader_screen(i);
- if (stemp && strcmp(stemp, OSDOPTVAL_NONE) != 0 && strlen(stemp)>0)
- {
- video_config.glsl_shader_scrn[i] = (char *) malloc(strlen(stemp)+1);
- strcpy(video_config.glsl_shader_scrn[i], stemp);
- video_config.glsl_shader_scrn_num++;
- } else {
- video_config.glsl_shader_scrn[i] = nullptr;
- }
- }
- } else {
- int i;
- video_config.glsl_filter = 0;
- video_config.glsl_shader_mamebm_num=0;
- for(i=0; i<GLSL_SHADER_MAX; i++)
- {
- video_config.glsl_shader_mamebm[i] = nullptr;
- }
- video_config.glsl_shader_scrn_num=0;
- for(i=0; i<GLSL_SHADER_MAX; i++)
- {
- video_config.glsl_shader_scrn[i] = nullptr;
- }
- }
-
// misc options: sanity check values
// global options: sanity check values
diff --git a/src/osd/mac/window.cpp b/src/osd/mac/window.cpp
index 3993b3502d2..161bc8b677b 100644
--- a/src/osd/mac/window.cpp
+++ b/src/osd/mac/window.cpp
@@ -9,7 +9,7 @@
//============================================================
// standard C headers
-#include <math.h>
+#include <cmath>
#ifndef _MSC_VER
#include <unistd.h>
#endif
@@ -20,14 +20,13 @@
#include "emu.h"
#include "emuopts.h"
#include "render.h"
+#include "screen.h"
#include "ui/uimain.h"
// OSD headers
#include "window.h"
#include "osdmac.h"
-#include "modules/render/drawbgfx.h"
-#include "modules/render/drawogl.h"
#include "modules/monitor/monitor_common.h"
//============================================================
@@ -68,48 +67,22 @@ bool mac_osd_interface::window_init()
{
osd_printf_verbose("Enter macwindow_init\n");
- // initialize the drawers
-
- switch (video_config.mode)
- {
- case VIDEO_MODE_BGFX:
- renderer_bgfx::init(machine());
- break;
- case VIDEO_MODE_OPENGL:
- renderer_ogl::init(machine());
- break;
- }
-
// set up the window list
osd_printf_verbose("Leave macwindow_init\n");
return true;
}
-void mac_osd_interface::update_slider_list()
+void mac_osd_interface::process_events()
{
- for (auto window : osd_common_t::s_window_list)
- {
- // check if any window has dirty sliders
- if (window->renderer().sliders_dirty())
- {
- build_slider_list();
- return;
- }
- }
}
-void mac_osd_interface::build_slider_list()
+bool mac_osd_interface::has_focus() const
{
- m_sliders.clear();
-
- for (auto window : osd_common_t::s_window_list)
- {
- std::vector<ui::menu_item> window_sliders = window->renderer().get_slider_list();
- m_sliders.insert(m_sliders.end(), window_sliders.begin(), window_sliders.end());
- }
+ return true;
}
+
//============================================================
// macwindow_exit
// (main thread)
@@ -122,23 +95,11 @@ void mac_osd_interface::window_exit()
// free all the windows
while (!osd_common_t::s_window_list.empty())
{
- auto window = osd_common_t::s_window_list.front();
-
- // Part of destroy removes the window from the list
+ auto window = std::move(osd_common_t::s_window_list.back());
+ s_window_list.pop_back();
window->destroy();
}
- switch(video_config.mode)
- {
- case VIDEO_MODE_BGFX:
- renderer_bgfx::exit();
- break;
- case VIDEO_MODE_OPENGL:
- renderer_ogl::exit();
- break;
- default:
- break;
- }
osd_printf_verbose("Leave macwindow_exit\n");
}
@@ -217,8 +178,6 @@ void mac_window_info::toggle_full_screen()
m_windowed_dim = get_size();
}
- // reset UI to main menu
- machine().ui().menu_reset();
// kill off the drawers
renderer_reset();
if (fullscreen() && video_config.switchres)
@@ -229,7 +188,7 @@ void mac_window_info::toggle_full_screen()
downcast<mac_osd_interface &>(machine().osd()).release_keys();
- set_renderer(osd_renderer::make_for_type(video_config.mode, shared_from_this()));
+ renderer_create();
// toggle the window mode
set_fullscreen(!fullscreen());
@@ -241,7 +200,7 @@ void mac_window_info::modify_prescale(int dir)
{
int new_prescale = prescale();
- if (dir > 0 && prescale() < 3)
+ if (dir > 0 && prescale() < 8)
new_prescale = prescale() + 1;
if (dir < 0 && prescale() > 1)
new_prescale = prescale() - 1;
@@ -261,8 +220,8 @@ void mac_window_info::modify_prescale(int dir)
notify_changed();
m_prescale = new_prescale;
}
- machine().ui().popup_time(1, "Prescale %d", prescale());
}
+ machine().ui().popup_time(1, "Prescale %d", prescale());
}
//============================================================
@@ -307,25 +266,11 @@ int mac_window_info::window_init()
// set the initial maximized state
// FIXME: Does not belong here
- mac_options &options = downcast<mac_options &>(m_machine.options());
- m_startmaximized = options.maximize();
+ m_startmaximized = downcast<mac_options &>(machine().options()).maximize();
- // add us to the list
- osd_common_t::s_window_list.push_back(std::static_pointer_cast<mac_window_info>(shared_from_this()));
+ create_target();
- set_renderer(osd_renderer::make_for_type(video_config.mode, static_cast<osd_window*>(this)->shared_from_this()));
-
- // load the layout
- m_target = m_machine.render().target_alloc();
-
- // set the specific view
- set_starting_view(m_index, options.view(), options.view(m_index));
-
- // make the window title
- if (video_config.numscreens == 1)
- sprintf(m_title, "%s: %s [%s]", emulator_info::get_appname(), m_machine.system().type.fullname(), m_machine.system().name);
- else
- sprintf(m_title, "%s: %s [%s] - Screen %d", emulator_info::get_appname(), m_machine.system().type.fullname(), m_machine.system().name, m_index);
+ renderer_create();
result = complete_create();
@@ -360,18 +305,6 @@ void mac_window_info::complete_destroy()
downcast<mac_osd_interface &>(machine().osd()).release_keys();
}
-void mac_window_info::destroy()
-{
- // remove us from the list
- osd_common_t::s_window_list.remove(std::static_pointer_cast<mac_window_info>(shared_from_this()));
-
- // free the textures etc
- complete_destroy();
-
- // free the render target, after the textures!
- machine().render().target_free(m_target);
-}
-
//============================================================
// pick_best_mode
@@ -386,7 +319,7 @@ osd_dim mac_window_info::pick_best_mode()
osd_dim ret(0,0);
#if 0
// determine the minimum width/height for the selected target
- m_target->compute_minimum_size(minimum_width, minimum_height);
+ target()->compute_minimum_size(minimum_width, minimum_height);
// use those as the target for now
target_width = minimum_width * std::max(1, prescale());
@@ -399,7 +332,7 @@ osd_dim mac_window_info::pick_best_mode()
}
// FIXME: this should be provided by monitor !
- num = SDL_GetNumDisplayModes(m_monitor->oshandle());
+ num = SDL_GetNumDisplayModes(monitor()->oshandle());
if (num == 0)
{
@@ -411,7 +344,7 @@ osd_dim mac_window_info::pick_best_mode()
for (i = 0; i < num; ++i)
{
SDL_DisplayMode mode;
- SDL_GetDisplayMode(m_monitor->oshandle(), i, &mode);
+ SDL_GetDisplayMode(monitor()->oshandle(), i, &mode);
// compute initial score based on difference between target and current
size_score = 1.0f / (1.0f + abs((int32_t)mode.w - target_width) + abs((int32_t)mode.h - target_height));
@@ -462,12 +395,12 @@ void mac_window_info::update()
update_cursor_state();
// if we're visible and running and not in the middle of a resize, draw
- if (m_target != nullptr)
+ if (target() != nullptr)
{
int tempwidth, tempheight;
// see if the games video mode has changed
- m_target->compute_minimum_size(tempwidth, tempheight);
+ target()->compute_minimum_size(tempwidth, tempheight);
if (osd_dim(tempwidth, tempheight) != m_minimum_dim)
{
m_minimum_dim = osd_dim(tempwidth, tempheight);
@@ -499,13 +432,10 @@ void mac_window_info::update()
// and redraw now
- // Some configurations require events to be polled in the worker thread
- downcast< mac_osd_interface& >(machine().osd()).process_events_buf();
-
// Check whether window has vector screens
{
- const screen_device *screen = screen_device_iterator(machine().root_device()).byindex(m_index);
+ const screen_device *screen = screen_device_enumerator(machine().root_device()).byindex(index());
if ((screen != nullptr) && (screen->screen_type() == SCREEN_TYPE_VECTOR))
renderer().set_flags(osd_renderer::FLAG_HAS_VECTOR_SCREEN);
else
@@ -535,31 +465,10 @@ void mac_window_info::update()
//============================================================
-// set_starting_view
-// (main thread)
-//============================================================
-
-void mac_window_info::set_starting_view(int index, const char *defview, const char *view)
-{
- int viewindex;
-
- // choose non-auto over auto
- if (strcmp(view, "auto") == 0 && strcmp(defview, "auto") != 0)
- view = defview;
-
- // query the video system to help us pick a view
- viewindex = target()->configured_view(view, index, video_config.numscreens);
-
- // set the view
- target()->set_view(viewindex);
-}
-
-
-//============================================================
// complete_create
//============================================================
-extern void *CreateMAMEWindow(char *title, int x, int y, int w, int h, bool isFullscreen);
+extern void *CreateMAMEWindow(const char *title, int x, int y, int w, int h, bool isFullscreen);
extern void *GetOSWindow(void *wincontroller);
int mac_window_info::complete_create()
@@ -582,9 +491,13 @@ int mac_window_info::complete_create()
temp = m_windowed_dim;
}
else if (m_startmaximized)
- temp = get_max_bounds(video_config.keepaspect );
+ {
+ temp = get_max_bounds(keepaspect());
+ }
else
- temp = get_min_bounds(video_config.keepaspect );
+ {
+ temp = get_min_bounds(keepaspect());
+ }
// create the window .....
osd_printf_verbose("Enter mac_window_info::complete_create\n");
@@ -592,7 +505,7 @@ int mac_window_info::complete_create()
// get monitor work area for centering
osd_rect work = monitor()->usuable_position_size();
- auto window = CreateMAMEWindow(m_title,
+ auto window = CreateMAMEWindow(title().c_str(),
work.left() + (work.width() - temp.width()) / 2,
work.top() + (work.height() - temp.height()) / 2,
temp.width(), temp.height(), fullscreen());
@@ -605,24 +518,6 @@ int mac_window_info::complete_create()
set_platform_window(window);
- // set main window
- if (m_index > 0)
- {
- for (auto w : osd_common_t::s_window_list)
- {
- if (w->m_index == 0)
- {
- set_main_window(std::dynamic_pointer_cast<osd_window>(w));
- break;
- }
- }
- }
- else
- {
- // We must be the main window
- set_main_window(shared_from_this());
- }
-
// update monitor resolution after mode change to ensure proper pixel aspect
monitor()->refresh();
if (fullscreen() && video_config.switchres)
@@ -712,14 +607,13 @@ osd_rect mac_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int ad
int32_t viswidth, visheight;
int32_t adjwidth, adjheight;
float pixel_aspect;
- std::shared_ptr<osd_monitor_info> monitor = m_monitor;
// do not constrain aspect ratio for integer scaled views
- if (m_target->scale_mode() != SCALE_FRACTIONAL)
+ if (target()->scale_mode() != SCALE_FRACTIONAL)
return rect;
// get the pixel aspect ratio for the target monitor
- pixel_aspect = monitor->pixel_aspect();
+ pixel_aspect = monitor()->pixel_aspect();
// determine the proposed width/height
propwidth = rect.width() - extrawidth;
@@ -731,21 +625,21 @@ osd_rect mac_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int ad
{
case WMSZ_BOTTOM:
case WMSZ_TOP:
- m_target->compute_visible_area(10000, propheight, pixel_aspect, m_target->orientation(), propwidth, propheight);
+ target()->compute_visible_area(10000, propheight, pixel_aspect, target()->orientation(), propwidth, propheight);
break;
case WMSZ_LEFT:
case WMSZ_RIGHT:
- m_target->compute_visible_area(propwidth, 10000, pixel_aspect, m_target->orientation(), propwidth, propheight);
+ target()->compute_visible_area(propwidth, 10000, pixel_aspect, target()->orientation(), propwidth, propheight);
break;
default:
- m_target->compute_visible_area(propwidth, propheight, pixel_aspect, m_target->orientation(), propwidth, propheight);
+ target()->compute_visible_area(propwidth, propheight, pixel_aspect, target()->orientation(), propwidth, propheight);
break;
}
// get the minimum width/height for the current layout
- m_target->compute_minimum_size(minwidth, minheight);
+ target()->compute_minimum_size(minwidth, minheight);
// clamp against the absolute minimum
propwidth = std::max(propwidth, MIN_WINDOW_DIM);
@@ -758,13 +652,13 @@ osd_rect mac_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int ad
// clamp against the maximum (fit on one screen for full screen mode)
if (m_fullscreen)
{
- maxwidth = monitor->position_size().width() - extrawidth;
- maxheight = monitor->position_size().height() - extraheight;
+ maxwidth = monitor()->position_size().width() - extrawidth;
+ maxheight = monitor()->position_size().height() - extraheight;
}
else
{
- maxwidth = monitor->usuable_position_size().width() - extrawidth;
- maxheight = monitor->usuable_position_size().height() - extraheight;
+ maxwidth = monitor()->usuable_position_size().width() - extrawidth;
+ maxheight = monitor()->usuable_position_size().height() - extraheight;
// further clamp to the maximum width/height in the window
if (m_win_config.width != 0)
@@ -778,7 +672,7 @@ osd_rect mac_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int ad
propheight = std::min(propheight, maxheight);
// compute the visible area based on the proposed rectangle
- m_target->compute_visible_area(propwidth, propheight, pixel_aspect, m_target->orientation(), viswidth, visheight);
+ target()->compute_visible_area(propwidth, propheight, pixel_aspect, target()->orientation(), viswidth, visheight);
// compute the adjustments we need to make
adjwidth = (viswidth + extrawidth) - rect.width();
@@ -826,7 +720,7 @@ osd_dim mac_window_info::get_min_bounds(int constrain)
//assert(GetCurrentThreadId() == window_threadid);
// get the minimum target size
- m_target->compute_minimum_size(minwidth, minheight);
+ target()->compute_minimum_size(minwidth, minheight);
// expand to our minimum dimensions
if (minwidth < MIN_WINDOW_DIM)
@@ -839,7 +733,7 @@ osd_dim mac_window_info::get_min_bounds(int constrain)
minheight += wnd_extra_height();
// if we want it constrained, figure out which one is larger
- if (constrain && m_target->scale_mode() == SCALE_FRACTIONAL)
+ if (constrain && target()->scale_mode() == SCALE_FRACTIONAL)
{
// first constrain with no height limit
osd_rect test1(0,0,minwidth,10000);
@@ -892,8 +786,8 @@ osd_dim mac_window_info::get_max_bounds(int constrain)
//assert(GetCurrentThreadId() == window_threadid);
// compute the maximum client area
- // m_monitor->refresh();
- osd_rect maximum = m_monitor->usuable_position_size();
+ // monitor()->refresh();
+ osd_rect maximum = monitor()->usuable_position_size();
// clamp to the window's max
int tempw = maximum.width();
@@ -914,7 +808,7 @@ osd_dim mac_window_info::get_max_bounds(int constrain)
maximum = maximum.resize(tempw, temph);
// constrain to fit
- if (constrain && m_target->scale_mode() == SCALE_FRACTIONAL)
+ if (constrain && target()->scale_mode() == SCALE_FRACTIONAL)
maximum = constrain_to_aspect_ratio(maximum, WMSZ_BOTTOMRIGHT);
// remove extra window stuff
@@ -929,25 +823,19 @@ osd_dim mac_window_info::get_max_bounds(int constrain)
mac_window_info::mac_window_info(
running_machine &a_machine,
+ render_module &renderprovider,
int index,
std::shared_ptr<osd_monitor_info> a_monitor,
const osd_window_config *config)
- : osd_window_t(*config)
- , m_next(nullptr)
+ : osd_window_t(a_machine, renderprovider, index, a_monitor, *config)
, m_startmaximized(0)
// Following three are used by input code to defer resizes
, m_minimum_dim(0, 0)
, m_windowed_dim(0, 0)
, m_rendered_event(0, 1)
- , m_target(nullptr)
- , m_machine(a_machine)
- , m_monitor(a_monitor)
- , m_fullscreen(0)
, m_mouse_captured(false)
, m_mouse_hidden(false)
{
- m_index = index;
-
//FIXME: these should be per_window in config-> or even better a bit set
m_fullscreen = !video_config.windowed;
m_prescale = video_config.prescale;
diff --git a/src/osd/mac/window.h b/src/osd/mac/window.h
index 24e749a425b..fce0b5f54bf 100644
--- a/src/osd/mac/window.h
+++ b/src/osd/mac/window.h
@@ -8,11 +8,13 @@
//
//============================================================
-#ifndef __MACWINDOW__
-#define __MACWINDOW__
+#ifndef MAME_OSD_MAC_WINDOW_H
+#define MAME_OSD_MAC_WINDOW_H
+
+#pragma once
#include "osdmac.h"
-#include "video.h"
+#include "osdsync.h"
#include "modules/osdwindow.h"
@@ -28,12 +30,12 @@ class render_target;
typedef uintptr_t HashT;
-#define OSDWORK_CALLBACK(name) void *name(void *param, ATTR_UNUSED int threadid)
+#define OSDWORK_CALLBACK(name) void *name(void *param, int threadid)
class mac_window_info : public osd_window_t<void *>
{
public:
- mac_window_info(running_machine &a_machine, int index, std::shared_ptr<osd_monitor_info> a_monitor,
+ mac_window_info(running_machine &a_machine, render_module &renderprovider, int index, std::shared_ptr<osd_monitor_info> a_monitor,
const osd_window_config *config);
~mac_window_info();
@@ -44,7 +46,7 @@ public:
void toggle_full_screen();
void modify_prescale(int dir);
void resize(int32_t width, int32_t height);
- void destroy() override;
+ void complete_destroy() override;
void capture_pointer() override;
void release_pointer() override;
@@ -57,20 +59,8 @@ public:
int xy_to_render_target(int x, int y, int *xt, int *yt);
- running_machine &machine() const override { return m_machine; }
- osd_monitor_info *monitor() const override { return m_monitor.get(); }
- int fullscreen() const override { return m_fullscreen; }
-
- render_target *target() override { return m_target; }
-
- int prescale() const { return m_prescale; }
-
- // Pointer to next window
- mac_window_info * m_next;
-
private:
// window handle and info
- char m_title[256];
int m_startmaximized;
// dimensions
@@ -79,18 +69,15 @@ private:
// rendering info
osd_event m_rendered_event;
- render_target * m_target;
//int m_extra_flags;
// returns 0 on success, else 1
int complete_create();
- void complete_destroy();
private:
int wnd_extra_width();
int wnd_extra_height();
- void set_starting_view(int index, const char *defview, const char *view);
osd_rect constrain_to_aspect_ratio(const osd_rect &rect, int adjustment);
osd_dim get_min_bounds(int constrain);
osd_dim get_max_bounds(int constrain);
@@ -98,37 +85,11 @@ private:
osd_dim pick_best_mode();
void set_fullscreen(int afullscreen) { m_fullscreen = afullscreen; }
- // Pointer to machine
- running_machine & m_machine;
-
// monitor info
- std::shared_ptr<osd_monitor_info> m_monitor;
- int m_fullscreen;
bool m_mouse_captured;
bool m_mouse_hidden;
void measure_fps(int update);
};
-struct osd_draw_callbacks
-{
- osd_renderer *(*create)(osd_window *window);
-};
-
-//============================================================
-// PROTOTYPES
-//============================================================
-
-//============================================================
-// PROTOTYPES - drawogl.c
-//============================================================
-
-int drawogl_init(running_machine &machine, osd_draw_callbacks *callbacks);
-
-//============================================================
-// PROTOTYPES - drawbgfx.c
-//============================================================
-
-int drawbgfx_init(running_machine &machine, osd_draw_callbacks *callbacks);
-
-#endif /* __MACWINDOW__ */
+#endif // MAME_OSD_MAC_WINDOW_H
diff --git a/src/osd/mac/windowcontroller.mm b/src/osd/mac/windowcontroller.mm
index dd49d559b0b..3a4b046d662 100644
--- a/src/osd/mac/windowcontroller.mm
+++ b/src/osd/mac/windowcontroller.mm
@@ -109,7 +109,7 @@ void *GetOSWindow(void *wincontroller)
return [wc getWindow];
}
-void *CreateMAMEWindow(char *title, int x, int y, int w, int h, bool isFullscreen)
+void *CreateMAMEWindow(const char *title, int x, int y, int w, int h, bool isFullscreen)
{
NSRect bounds = NSMakeRect(x, y, w, h);
NSUInteger style = NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask;
diff --git a/src/osd/modules/debugger/debug_module.h b/src/osd/modules/debugger/debug_module.h
index fb659a1b312..1c5b1973c8e 100644
--- a/src/osd/modules/debugger/debug_module.h
+++ b/src/osd/modules/debugger/debug_module.h
@@ -4,13 +4,15 @@
* debug_module.h
*
*/
+#ifndef MAME_OSD_DEBUGGER_DEBUG_MODULE_H
+#define MAME_OSD_DEBUGGER_DEBUG_MODULE_H
-#ifndef DEBUG_MODULE_H_
-#define DEBUG_MODULE_H_
+#pragma once
#include "osdepend.h"
#include "modules/osdmodule.h"
+
//============================================================
// CONSTANTS
//============================================================
@@ -20,14 +22,11 @@
class debug_module
{
public:
-
- virtual ~debug_module() { }
+ virtual ~debug_module() = default;
virtual void init_debugger(running_machine &machine) = 0;
virtual void wait_for_debugger(device_t &device, bool firststop) = 0;
virtual void debugger_update() = 0;
};
-
-
-#endif /* DEBUG_MODULE_H_ */
+#endif // MAME_OSD_DEBUGGER_DEBUG_MODULE_H
diff --git a/src/osd/modules/debugger/debuggdbstub.cpp b/src/osd/modules/debugger/debuggdbstub.cpp
index 4c7e4e3707e..729280f2134 100644
--- a/src/osd/modules/debugger/debuggdbstub.cpp
+++ b/src/osd/modules/debugger/debuggdbstub.cpp
@@ -7,15 +7,26 @@
//============================================================
#include "emu.h"
+#include "debug_module.h"
+
#include "debug/debugcon.h"
#include "debug/debugcpu.h"
+#include "debug/points.h"
#include "debug/textbuf.h"
-#include "debug_module.h"
#include "debugger.h"
+
#include "modules/lib/osdobj_common.h"
#include "modules/osdmodule.h"
+#include "fileio.h"
+
#include <cinttypes>
+#include <string_view>
+
+
+namespace osd {
+
+namespace {
//-------------------------------------------------------------------------
#define MAX_PACKET_SIZE 16384
@@ -37,71 +48,85 @@ static const char *const gdb_register_type_str[] = {
struct gdb_register_map
{
const char *arch;
- const char *feature;
- struct gdb_register_description
+ struct gdb_feature
{
- const char *state_name;
- const char *gdb_name;
- bool stop_packet;
- gdb_register_type gdb_type;
- int override_bitsize;
-
- gdb_register_description(const char *_state_name=nullptr, const char *_gdb_name=nullptr, bool _stop_packet=false, gdb_register_type _gdb_type=TYPE_INT, int _override_bitsize=-1)
- : state_name(_state_name)
- , gdb_name(_gdb_name)
- , stop_packet(_stop_packet)
- , gdb_type(_gdb_type)
- , override_bitsize(_override_bitsize)
+ const char *feature_name;
+ struct gdb_register_description
+ {
+ const char *state_name;
+ const char *gdb_name;
+ bool stop_packet;
+ gdb_register_type gdb_type;
+ int override_bitsize;
+
+ gdb_register_description(const char *_state_name = nullptr, const char *_gdb_name = nullptr, bool _stop_packet = false, gdb_register_type _gdb_type = TYPE_INT, int _override_bitsize = -1)
+ : state_name(_state_name)
+ , gdb_name(_gdb_name)
+ , stop_packet(_stop_packet)
+ , gdb_type(_gdb_type)
+ , override_bitsize(_override_bitsize)
+ {
+ }
+ };
+ std::vector<gdb_register_description> registers;
+
+ gdb_feature(const char *_feature_name, std::initializer_list<gdb_register_description> _registers)
+ : feature_name(_feature_name)
+ , registers(_registers)
{
}
};
- std::vector<gdb_register_description> registers;
+ std::vector<gdb_feature> features;
};
//-------------------------------------------------------------------------
static const gdb_register_map gdb_register_map_i486 =
{
"i386",
- "org.gnu.gdb.i386.core",
{
- { "EAX", "eax", false, TYPE_INT },
- { "ECX", "ecx", false, TYPE_INT },
- { "EDX", "edx", false, TYPE_INT },
- { "EBX", "ebx", false, TYPE_INT },
- { "ESP", "esp", true, TYPE_DATA_POINTER },
- { "EBP", "ebp", true, TYPE_DATA_POINTER },
- { "ESI", "esi", false, TYPE_INT },
- { "EDI", "edi", false, TYPE_INT },
- { "EIP", "eip", true, TYPE_CODE_POINTER },
- { "EFLAGS", "eflags", false, TYPE_INT }, // TODO describe bitfield
- { "CS", "cs", false, TYPE_INT },
- { "SS", "ss", false, TYPE_INT },
- { "DS", "ds", false, TYPE_INT },
- { "ES", "es", false, TYPE_INT },
- { "FS", "fs", false, TYPE_INT },
- { "GS", "gs", false, TYPE_INT },
- // TODO fix x87 registers!
- // The x87 registers are just plain wrong for a few reasons:
- // - The st* registers use a dummy variable in i386_device, so we
- // don't retrieve the real value (also the bitsize is wrong);
- // - The seg/off/op registers don't seem to be exported in the
- // state.
- { "ST0", "st0", false, TYPE_I387_EXT },
- { "ST1", "st1", false, TYPE_I387_EXT },
- { "ST2", "st2", false, TYPE_I387_EXT },
- { "ST3", "st3", false, TYPE_I387_EXT },
- { "ST4", "st4", false, TYPE_I387_EXT },
- { "ST5", "st5", false, TYPE_I387_EXT },
- { "ST6", "st6", false, TYPE_I387_EXT },
- { "ST7", "st7", false, TYPE_I387_EXT },
- { "x87_CW", "fctrl", false, TYPE_INT },
- { "x87_SW", "fstat", false, TYPE_INT },
- { "x87_TAG", "ftag", false, TYPE_INT },
- { "EAX", "fiseg", false, TYPE_INT },
- { "EAX", "fioff", false, TYPE_INT },
- { "EAX", "foseg", false, TYPE_INT },
- { "EAX", "fooff", false, TYPE_INT },
- { "EAX", "fop", false, TYPE_INT },
+ {
+ "org.gnu.gdb.i386.core",
+ {
+ { "EAX", "eax", false, TYPE_INT },
+ { "ECX", "ecx", false, TYPE_INT },
+ { "EDX", "edx", false, TYPE_INT },
+ { "EBX", "ebx", false, TYPE_INT },
+ { "ESP", "esp", true, TYPE_DATA_POINTER },
+ { "EBP", "ebp", true, TYPE_DATA_POINTER },
+ { "ESI", "esi", false, TYPE_INT },
+ { "EDI", "edi", false, TYPE_INT },
+ { "EIP", "eip", true, TYPE_CODE_POINTER },
+ { "EFLAGS", "eflags", false, TYPE_INT }, // TODO describe bitfield
+ { "CS", "cs", false, TYPE_INT },
+ { "SS", "ss", false, TYPE_INT },
+ { "DS", "ds", false, TYPE_INT },
+ { "ES", "es", false, TYPE_INT },
+ { "FS", "fs", false, TYPE_INT },
+ { "GS", "gs", false, TYPE_INT },
+ // TODO fix x87 registers!
+ // The x87 registers are just plain wrong for a few reasons:
+ // - The st* registers use a dummy variable in i386_device, so we
+ // don't retrieve the real value (also the bitsize is wrong);
+ // - The seg/off/op registers don't seem to be exported in the
+ // state.
+ { "ST0", "st0", false, TYPE_I387_EXT },
+ { "ST1", "st1", false, TYPE_I387_EXT },
+ { "ST2", "st2", false, TYPE_I387_EXT },
+ { "ST3", "st3", false, TYPE_I387_EXT },
+ { "ST4", "st4", false, TYPE_I387_EXT },
+ { "ST5", "st5", false, TYPE_I387_EXT },
+ { "ST6", "st6", false, TYPE_I387_EXT },
+ { "ST7", "st7", false, TYPE_I387_EXT },
+ { "x87_CW", "fctrl", false, TYPE_INT },
+ { "x87_SW", "fstat", false, TYPE_INT },
+ { "x87_TAG", "ftag", false, TYPE_INT },
+ { "EAX", "fiseg", false, TYPE_INT },
+ { "EAX", "fioff", false, TYPE_INT },
+ { "EAX", "foseg", false, TYPE_INT },
+ { "EAX", "fooff", false, TYPE_INT },
+ { "EAX", "fop", false, TYPE_INT },
+ }
+ }
}
};
@@ -109,25 +134,29 @@ static const gdb_register_map gdb_register_map_i486 =
static const gdb_register_map gdb_register_map_arm7 =
{
"arm",
- "org.gnu.gdb.arm.core",
{
- { "R0", "r0", false, TYPE_INT },
- { "R1", "r1", false, TYPE_INT },
- { "R2", "r2", false, TYPE_INT },
- { "R3", "r3", false, TYPE_INT },
- { "R4", "r4", false, TYPE_INT },
- { "R5", "r5", false, TYPE_INT },
- { "R6", "r6", false, TYPE_INT },
- { "R7", "r7", false, TYPE_INT },
- { "R8", "r8", false, TYPE_INT },
- { "R9", "r9", false, TYPE_INT },
- { "R10", "r10", false, TYPE_INT },
- { "R11", "r11", false, TYPE_INT },
- { "R12", "r12", false, TYPE_INT },
- { "R13", "sp", true, TYPE_DATA_POINTER },
- { "R14", "lr", true, TYPE_INT },
- { "R15", "pc", true, TYPE_CODE_POINTER },
- { "CPSR", "cpsr", false, TYPE_INT }, // TODO describe bitfield
+ {
+ "org.gnu.gdb.arm.core",
+ {
+ { "R0", "r0", false, TYPE_INT },
+ { "R1", "r1", false, TYPE_INT },
+ { "R2", "r2", false, TYPE_INT },
+ { "R3", "r3", false, TYPE_INT },
+ { "R4", "r4", false, TYPE_INT },
+ { "R5", "r5", false, TYPE_INT },
+ { "R6", "r6", false, TYPE_INT },
+ { "R7", "r7", false, TYPE_INT },
+ { "R8", "r8", false, TYPE_INT },
+ { "R9", "r9", false, TYPE_INT },
+ { "R10", "r10", false, TYPE_INT },
+ { "R11", "r11", false, TYPE_INT },
+ { "R12", "r12", false, TYPE_INT },
+ { "R13", "sp", true, TYPE_DATA_POINTER },
+ { "R14", "lr", true, TYPE_INT },
+ { "R15", "pc", true, TYPE_CODE_POINTER },
+ { "CPSR", "cpsr", false, TYPE_INT }, // TODO describe bitfield
+ }
+ }
}
};
@@ -135,46 +164,50 @@ static const gdb_register_map gdb_register_map_arm7 =
static const gdb_register_map gdb_register_map_ppc601 =
{
"powerpc:common",
- "org.gnu.gdb.power.core",
{
- { "R0", "r0", false, TYPE_INT },
- { "R1", "r1", false, TYPE_INT },
- { "R2", "r2", false, TYPE_INT },
- { "R3", "r3", false, TYPE_INT },
- { "R4", "r4", false, TYPE_INT },
- { "R5", "r5", false, TYPE_INT },
- { "R6", "r6", false, TYPE_INT },
- { "R7", "r7", false, TYPE_INT },
- { "R8", "r8", false, TYPE_INT },
- { "R9", "r9", false, TYPE_INT },
- { "R10", "r10", false, TYPE_INT },
- { "R11", "r11", false, TYPE_INT },
- { "R12", "r12", false, TYPE_INT },
- { "R13", "r13", false, TYPE_INT },
- { "R14", "r14", false, TYPE_INT },
- { "R15", "r15", false, TYPE_INT },
- { "R16", "r16", false, TYPE_INT },
- { "R17", "r17", false, TYPE_INT },
- { "R18", "r18", false, TYPE_INT },
- { "R19", "r19", false, TYPE_INT },
- { "R20", "r20", false, TYPE_INT },
- { "R21", "r21", false, TYPE_INT },
- { "R22", "r22", false, TYPE_INT },
- { "R23", "r23", false, TYPE_INT },
- { "R24", "r24", false, TYPE_INT },
- { "R25", "r25", false, TYPE_INT },
- { "R26", "r26", false, TYPE_INT },
- { "R27", "r27", false, TYPE_INT },
- { "R28", "r28", false, TYPE_INT },
- { "R29", "r29", false, TYPE_INT },
- { "R30", "r30", false, TYPE_INT },
- { "R31", "r31", false, TYPE_INT },
- { "PC", "pc", true, TYPE_CODE_POINTER },
- { "MSR", "msr", false, TYPE_INT },
- { "CR", "cr", false, TYPE_INT },
- { "LR", "lr", true, TYPE_CODE_POINTER },
- { "CTR", "ctr", false, TYPE_INT },
- { "XER", "xer", false, TYPE_INT },
+ {
+ "org.gnu.gdb.power.core",
+ {
+ { "R0", "r0", false, TYPE_INT },
+ { "R1", "r1", false, TYPE_INT },
+ { "R2", "r2", false, TYPE_INT },
+ { "R3", "r3", false, TYPE_INT },
+ { "R4", "r4", false, TYPE_INT },
+ { "R5", "r5", false, TYPE_INT },
+ { "R6", "r6", false, TYPE_INT },
+ { "R7", "r7", false, TYPE_INT },
+ { "R8", "r8", false, TYPE_INT },
+ { "R9", "r9", false, TYPE_INT },
+ { "R10", "r10", false, TYPE_INT },
+ { "R11", "r11", false, TYPE_INT },
+ { "R12", "r12", false, TYPE_INT },
+ { "R13", "r13", false, TYPE_INT },
+ { "R14", "r14", false, TYPE_INT },
+ { "R15", "r15", false, TYPE_INT },
+ { "R16", "r16", false, TYPE_INT },
+ { "R17", "r17", false, TYPE_INT },
+ { "R18", "r18", false, TYPE_INT },
+ { "R19", "r19", false, TYPE_INT },
+ { "R20", "r20", false, TYPE_INT },
+ { "R21", "r21", false, TYPE_INT },
+ { "R22", "r22", false, TYPE_INT },
+ { "R23", "r23", false, TYPE_INT },
+ { "R24", "r24", false, TYPE_INT },
+ { "R25", "r25", false, TYPE_INT },
+ { "R26", "r26", false, TYPE_INT },
+ { "R27", "r27", false, TYPE_INT },
+ { "R28", "r28", false, TYPE_INT },
+ { "R29", "r29", false, TYPE_INT },
+ { "R30", "r30", false, TYPE_INT },
+ { "R31", "r31", false, TYPE_INT },
+ { "PC", "pc", true, TYPE_CODE_POINTER },
+ { "MSR", "msr", false, TYPE_INT },
+ { "CR", "cr", false, TYPE_INT },
+ { "LR", "lr", true, TYPE_CODE_POINTER },
+ { "CTR", "ctr", false, TYPE_INT },
+ { "XER", "xer", false, TYPE_INT },
+ }
+ }
}
};
@@ -182,43 +215,78 @@ static const gdb_register_map gdb_register_map_ppc601 =
static const gdb_register_map gdb_register_map_r4600 =
{
"mips",
- "org.gnu.gdb.mips.cpu",
{
- { "zero", "r0", false, TYPE_INT, 32 },
- { "at", "r1", false, TYPE_INT, 32 },
- { "v0", "r2", false, TYPE_INT, 32 },
- { "v1", "r3", false, TYPE_INT, 32 },
- { "a0", "r4", false, TYPE_INT, 32 },
- { "a1", "r5", false, TYPE_INT, 32 },
- { "a2", "r6", false, TYPE_INT, 32 },
- { "a3", "r7", false, TYPE_INT, 32 },
- { "t0", "r8", false, TYPE_INT, 32 },
- { "t1", "r9", false, TYPE_INT, 32 },
- { "t2", "r10", false, TYPE_INT, 32 },
- { "t3", "r11", false, TYPE_INT, 32 },
- { "t4", "r12", false, TYPE_INT, 32 },
- { "t5", "r13", false, TYPE_INT, 32 },
- { "t6", "r14", false, TYPE_INT, 32 },
- { "t7", "r15", false, TYPE_INT, 32 },
- { "s0", "r16", false, TYPE_INT, 32 },
- { "s1", "r17", false, TYPE_INT, 32 },
- { "s2", "r18", false, TYPE_INT, 32 },
- { "s3", "r19", false, TYPE_INT, 32 },
- { "s4", "r20", false, TYPE_INT, 32 },
- { "s5", "r21", false, TYPE_INT, 32 },
- { "s6", "r22", false, TYPE_INT, 32 },
- { "s7", "r23", false, TYPE_INT, 32 },
- { "t8", "r24", false, TYPE_INT, 32 },
- { "t9", "r25", false, TYPE_INT, 32 },
- { "k0", "r26", false, TYPE_INT, 32 },
- { "k1", "r27", false, TYPE_INT, 32 },
- { "gp", "r28", false, TYPE_INT, 32 },
- { "sp", "r29", false, TYPE_INT, 32 },
- { "fp", "r30", false, TYPE_INT, 32 },
- { "ra", "r31", false, TYPE_INT, 32 },
- { "LO", "lo", false, TYPE_INT, 32 },
- { "HI", "hi", false, TYPE_INT, 32 },
- { "PC", "pc", true, TYPE_CODE_POINTER, 32 },
+ {
+ "org.gnu.gdb.mips.cpu",
+ {
+ { "zero", "r0", false, TYPE_INT, 32 },
+ { "at", "r1", false, TYPE_INT, 32 },
+ { "v0", "r2", false, TYPE_INT, 32 },
+ { "v1", "r3", false, TYPE_INT, 32 },
+ { "a0", "r4", false, TYPE_INT, 32 },
+ { "a1", "r5", false, TYPE_INT, 32 },
+ { "a2", "r6", false, TYPE_INT, 32 },
+ { "a3", "r7", false, TYPE_INT, 32 },
+ { "t0", "r8", false, TYPE_INT, 32 },
+ { "t1", "r9", false, TYPE_INT, 32 },
+ { "t2", "r10", false, TYPE_INT, 32 },
+ { "t3", "r11", false, TYPE_INT, 32 },
+ { "t4", "r12", false, TYPE_INT, 32 },
+ { "t5", "r13", false, TYPE_INT, 32 },
+ { "t6", "r14", false, TYPE_INT, 32 },
+ { "t7", "r15", false, TYPE_INT, 32 },
+ { "s0", "r16", false, TYPE_INT, 32 },
+ { "s1", "r17", false, TYPE_INT, 32 },
+ { "s2", "r18", false, TYPE_INT, 32 },
+ { "s3", "r19", false, TYPE_INT, 32 },
+ { "s4", "r20", false, TYPE_INT, 32 },
+ { "s5", "r21", false, TYPE_INT, 32 },
+ { "s6", "r22", false, TYPE_INT, 32 },
+ { "s7", "r23", false, TYPE_INT, 32 },
+ { "t8", "r24", false, TYPE_INT, 32 },
+ { "t9", "r25", false, TYPE_INT, 32 },
+ { "k0", "r26", false, TYPE_INT, 32 },
+ { "k1", "r27", false, TYPE_INT, 32 },
+ { "gp", "r28", false, TYPE_INT, 32 },
+ { "sp", "r29", false, TYPE_INT, 32 },
+ { "fp", "r30", false, TYPE_INT, 32 },
+ { "ra", "r31", false, TYPE_INT, 32 },
+ { "LO", "lo", false, TYPE_INT, 32 },
+ { "HI", "hi", false, TYPE_INT, 32 },
+ { "PC", "pc", true, TYPE_CODE_POINTER, 32 },
+ }
+ }
+ }
+};
+
+//-------------------------------------------------------------------------
+static const gdb_register_map gdb_register_map_m68030 =
+{
+ "m68k",
+ {
+ {
+ "org.gnu.gdb.m68k.core",
+ {
+ { "D0", "d0", false, TYPE_INT },
+ { "D1", "d1", false, TYPE_INT },
+ { "D2", "d2", false, TYPE_INT },
+ { "D3", "d3", false, TYPE_INT },
+ { "D4", "d4", false, TYPE_INT },
+ { "D5", "d5", false, TYPE_INT },
+ { "D6", "d6", false, TYPE_INT },
+ { "D7", "d7", false, TYPE_INT },
+ { "A0", "a0", false, TYPE_INT },
+ { "A1", "a1", false, TYPE_INT },
+ { "A2", "a2", false, TYPE_INT },
+ { "A3", "a3", false, TYPE_INT },
+ { "A4", "a4", false, TYPE_INT },
+ { "A5", "a5", false, TYPE_INT },
+ { "A6", "fp", true, TYPE_INT },
+ { "SP", "sp", true, TYPE_INT },
+ { "SR", "ps", false, TYPE_INT }, // NOTE GDB named it ps, but it's actually sr
+ { "CURPC","pc", true, TYPE_CODE_POINTER },
+ }
+ }
}
};
@@ -226,26 +294,62 @@ static const gdb_register_map gdb_register_map_r4600 =
static const gdb_register_map gdb_register_map_m68020pmmu =
{
"m68k",
- "org.gnu.gdb.m68k.core",
{
- { "D0", "d0", false, TYPE_INT },
- { "D1", "d1", false, TYPE_INT },
- { "D2", "d2", false, TYPE_INT },
- { "D3", "d3", false, TYPE_INT },
- { "D4", "d4", false, TYPE_INT },
- { "D5", "d5", false, TYPE_INT },
- { "D6", "d6", false, TYPE_INT },
- { "D7", "d7", false, TYPE_INT },
- { "A0", "a0", false, TYPE_INT },
- { "A1", "a1", false, TYPE_INT },
- { "A2", "a2", false, TYPE_INT },
- { "A3", "a3", false, TYPE_INT },
- { "A4", "a4", false, TYPE_INT },
- { "A5", "a5", false, TYPE_INT },
- { "A6", "fp", true, TYPE_INT },
- { "A7", "sp", true, TYPE_INT },
- { "SR", "ps", false, TYPE_INT }, // NOTE GDB named it ps, but it's actually sr
- { "PC", "pc", true, TYPE_CODE_POINTER },
+ {
+ "org.gnu.gdb.m68k.core",
+ {
+ { "D0", "d0", false, TYPE_INT },
+ { "D1", "d1", false, TYPE_INT },
+ { "D2", "d2", false, TYPE_INT },
+ { "D3", "d3", false, TYPE_INT },
+ { "D4", "d4", false, TYPE_INT },
+ { "D5", "d5", false, TYPE_INT },
+ { "D6", "d6", false, TYPE_INT },
+ { "D7", "d7", false, TYPE_INT },
+ { "A0", "a0", false, TYPE_INT },
+ { "A1", "a1", false, TYPE_INT },
+ { "A2", "a2", false, TYPE_INT },
+ { "A3", "a3", false, TYPE_INT },
+ { "A4", "a4", false, TYPE_INT },
+ { "A5", "a5", false, TYPE_INT },
+ { "A6", "fp", true, TYPE_INT },
+ { "SP", "sp", true, TYPE_INT },
+ { "SR", "ps", false, TYPE_INT }, // NOTE GDB named it ps, but it's actually sr
+ { "CURPC","pc", true, TYPE_CODE_POINTER },
+ }
+ }
+ }
+};
+
+//-------------------------------------------------------------------------
+static const gdb_register_map gdb_register_map_m68000 =
+{
+ "m68k",
+ {
+ {
+ "org.gnu.gdb.m68k.core",
+ {
+ { "D0", "d0", false, TYPE_INT },
+ { "D1", "d1", false, TYPE_INT },
+ { "D2", "d2", false, TYPE_INT },
+ { "D3", "d3", false, TYPE_INT },
+ { "D4", "d4", false, TYPE_INT },
+ { "D5", "d5", false, TYPE_INT },
+ { "D6", "d6", false, TYPE_INT },
+ { "D7", "d7", false, TYPE_INT },
+ { "A0", "a0", false, TYPE_INT },
+ { "A1", "a1", false, TYPE_INT },
+ { "A2", "a2", false, TYPE_INT },
+ { "A3", "a3", false, TYPE_INT },
+ { "A4", "a4", false, TYPE_INT },
+ { "A5", "a5", false, TYPE_INT },
+ { "A6", "fp", true, TYPE_INT },
+ { "SP", "sp", true, TYPE_INT },
+ { "SR", "ps", false, TYPE_INT }, // NOTE GDB named it ps, but it's actually sr
+ { "CURPC","pc", true, TYPE_CODE_POINTER },
+ //NOTE m68-elf-gdb complains about fpcontrol register not present but 68000 doesn't have floating point so...
+ }
+ }
}
};
@@ -253,20 +357,24 @@ static const gdb_register_map gdb_register_map_m68020pmmu =
static const gdb_register_map gdb_register_map_z80 =
{
"z80",
- "mame.z80",
{
- { "AF", "af", false, TYPE_INT },
- { "BC", "bc", false, TYPE_INT },
- { "DE", "de", false, TYPE_INT },
- { "HL", "hl", false, TYPE_INT },
- { "AF2", "af'", false, TYPE_INT },
- { "BC2", "bc'", false, TYPE_INT },
- { "DE2", "de'", false, TYPE_INT },
- { "HL2", "hl'", false, TYPE_INT },
- { "IX", "ix", false, TYPE_INT },
- { "IY", "iy", false, TYPE_INT },
- { "SP", "sp", true, TYPE_DATA_POINTER },
- { "PC", "pc", true, TYPE_CODE_POINTER },
+ {
+ "mame.z80",
+ {
+ { "AF", "af", false, TYPE_INT },
+ { "BC", "bc", false, TYPE_INT },
+ { "DE", "de", false, TYPE_INT },
+ { "HL", "hl", false, TYPE_INT },
+ { "AF2", "af'", false, TYPE_INT },
+ { "BC2", "bc'", false, TYPE_INT },
+ { "DE2", "de'", false, TYPE_INT },
+ { "HL2", "hl'", false, TYPE_INT },
+ { "IX", "ix", false, TYPE_INT },
+ { "IY", "iy", false, TYPE_INT },
+ { "SP", "sp", true, TYPE_DATA_POINTER },
+ { "PC", "pc", true, TYPE_CODE_POINTER },
+ }
+ }
}
};
@@ -274,14 +382,270 @@ static const gdb_register_map gdb_register_map_z80 =
static const gdb_register_map gdb_register_map_m6502 =
{
"m6502",
- "mame.m6502",
{
- { "A", "a", false, TYPE_INT },
- { "X", "x", false, TYPE_INT },
- { "Y", "y", false, TYPE_INT },
- { "P", "p", false, TYPE_INT },
- { "PC", "pc", true, TYPE_CODE_POINTER },
- { "SP", "sp", true, TYPE_DATA_POINTER },
+ {
+ "mame.m6502",
+ {
+ { "A", "a", false, TYPE_INT },
+ { "X", "x", false, TYPE_INT },
+ { "Y", "y", false, TYPE_INT },
+ { "P", "p", false, TYPE_INT },
+ { "SP", "sp", true, TYPE_DATA_POINTER },
+ { "PC", "pc", true, TYPE_CODE_POINTER },
+ }
+ }
+ }
+};
+
+
+//-------------------------------------------------------------------------
+static const gdb_register_map gdb_register_map_m6809 =
+{
+ "m6809",
+ {
+ {
+ "mame.m6809",
+ {
+ { "A", "a", false, TYPE_INT },
+ { "B", "b", false, TYPE_INT },
+ { "D", "d", false, TYPE_INT },
+ { "X", "x", false, TYPE_INT },
+ { "Y", "y", false, TYPE_INT },
+ { "U", "u", true, TYPE_DATA_POINTER },
+ { "PC", "pc", true, TYPE_CODE_POINTER },
+ { "S", "s", true, TYPE_DATA_POINTER },
+ { "CC", "cc", false, TYPE_INT }, // TODO describe bitfield
+ { "DP", "dp", false, TYPE_INT },
+ }
+ }
+ }
+};
+
+
+//-------------------------------------------------------------------------
+static const gdb_register_map gdb_register_map_score7 =
+{
+ "score7",
+ {
+ {
+ "mame.score7",
+ {
+ { "r0", "r0", true, TYPE_DATA_POINTER },
+ { "r1", "r1", false, TYPE_INT },
+ { "r2", "r2", false, TYPE_INT },
+ { "r3", "r3", false, TYPE_INT },
+ { "r4", "r4", false, TYPE_INT },
+ { "r5", "r5", false, TYPE_INT },
+ { "r6", "r6", false, TYPE_INT },
+ { "r7", "r7", false, TYPE_INT },
+ { "r8", "r8", false, TYPE_INT },
+ { "r9", "r9", false, TYPE_INT },
+ { "r10", "r10", false, TYPE_INT },
+ { "r11", "r11", false, TYPE_INT },
+ { "r12", "r12", false, TYPE_INT },
+ { "r13", "r13", false, TYPE_INT },
+ { "r14", "r14", false, TYPE_INT },
+ { "r15", "r15", false, TYPE_INT },
+ { "r16", "r16", false, TYPE_INT },
+ { "r17", "r17", false, TYPE_INT },
+ { "r18", "r18", false, TYPE_INT },
+ { "r19", "r19", false, TYPE_INT },
+ { "r20", "r20", false, TYPE_INT },
+ { "r21", "r21", false, TYPE_INT },
+ { "r22", "r22", false, TYPE_INT },
+ { "r23", "r23", false, TYPE_INT },
+ { "r24", "r24", false, TYPE_INT },
+ { "r25", "r25", false, TYPE_INT },
+ { "r26", "r26", false, TYPE_INT },
+ { "r27", "r27", false, TYPE_INT },
+ { "r28", "r28", false, TYPE_INT },
+ { "r29", "r29", false, TYPE_INT },
+ { "r30", "r30", false, TYPE_INT },
+ { "r31", "r31", false, TYPE_INT },
+ { "cr0", "PSR", false, TYPE_INT },
+ { "cr1", "COND", false, TYPE_INT },
+ { "cr2", "ECR", false, TYPE_INT },
+ { "cr3", "EXCPVEC", false, TYPE_INT },
+ { "cr4", "CCR", false, TYPE_INT },
+ { "cr5", "EPC", false, TYPE_INT },
+ { "cr6", "EMA", false, TYPE_INT },
+ { "cr7", "TLBLOCK", false, TYPE_INT },
+ { "cr8", "TLBPT", false, TYPE_INT },
+ { "cr9", "PEADDR", false, TYPE_INT },
+ { "cr10", "TLBRPT", false, TYPE_INT },
+ { "cr11", "PEVN", false, TYPE_INT },
+ { "cr12", "PECTX", false, TYPE_INT },
+ { "cr15", "LIMPFN", false, TYPE_INT },
+ { "cr16", "LDMPFN", false, TYPE_INT },
+ { "cr18", "PREV", false, TYPE_INT },
+ { "cr29", "DREG", false, TYPE_INT },
+ { "PC", "PC", true, TYPE_CODE_POINTER }, // actually Debug exception program counter (DEPC)
+ { "cr31", "DSAVE", false, TYPE_INT },
+ { "sr0", "COUNTER", false, TYPE_INT },
+ { "sr1", "LDCR", false, TYPE_INT },
+ { "sr2", "STCR", false, TYPE_INT },
+ { "ceh", "CEH", false, TYPE_INT },
+ { "cel", "CEL", false, TYPE_INT },
+ }
+ }
+ }
+};
+
+
+//-------------------------------------------------------------------------
+static const gdb_register_map gdb_register_map_nios2 =
+{
+ "nios2",
+ {
+ {
+ "org.gnu.gdb.nios2.cpu",
+ {
+ { "zero", "zero", false, TYPE_INT },
+ { "at", "at", false, TYPE_INT },
+ { "r2", "r2", false, TYPE_INT },
+ { "r3", "r3", false, TYPE_INT },
+ { "r4", "r4", false, TYPE_INT },
+ { "r5", "r5", false, TYPE_INT },
+ { "r6", "r6", false, TYPE_INT },
+ { "r7", "r7", false, TYPE_INT },
+ { "r8", "r8", false, TYPE_INT },
+ { "r9", "r9", false, TYPE_INT },
+ { "r10", "r10", false, TYPE_INT },
+ { "r11", "r11", false, TYPE_INT },
+ { "r12", "r12", false, TYPE_INT },
+ { "r13", "r13", false, TYPE_INT },
+ { "r14", "r14", false, TYPE_INT },
+ { "r15", "r15", false, TYPE_INT },
+ { "r16", "r16", false, TYPE_INT },
+ { "r17", "r17", false, TYPE_INT },
+ { "r18", "r18", false, TYPE_INT },
+ { "r19", "r19", false, TYPE_INT },
+ { "r20", "r20", false, TYPE_INT },
+ { "r21", "r21", false, TYPE_INT },
+ { "r22", "r22", false, TYPE_INT },
+ { "r23", "r23", false, TYPE_INT },
+ { "et", "et", false, TYPE_INT },
+ { "bt", "bt", false, TYPE_INT },
+ { "gp", "gp", false, TYPE_DATA_POINTER },
+ { "sp", "sp", true, TYPE_DATA_POINTER },
+ { "fp", "fp", false, TYPE_DATA_POINTER },
+ { "ea", "ea", false, TYPE_CODE_POINTER },
+ { "ba", "sstatus", false, TYPE_INT }, // this is Altera's fault
+ { "ra", "ra", false, TYPE_CODE_POINTER },
+ { "status", "status", false, TYPE_INT },
+ { "estatus", "estatus", false, TYPE_INT },
+ { "bstatus", "bstatus", false, TYPE_INT },
+ { "ienable", "ienable", false, TYPE_INT },
+ { "ipending", "ipending", false, TYPE_INT },
+ { "cpuid", "cpuid", false, TYPE_INT },
+ { "ctl6", "ctl6", false, TYPE_INT },
+ { "exception","exception",false, TYPE_INT },
+ { "pteaddr", "pteaddr", false, TYPE_INT },
+ { "tlbacc", "tlbacc", false, TYPE_INT },
+ { "tlbmisc", "tlbmisc", false, TYPE_INT },
+ { "eccinj", "eccinj", false, TYPE_INT },
+ { "badaddr", "badaddr", false, TYPE_INT },
+ { "config", "config", false, TYPE_INT },
+ { "mpubase", "mpubase", false, TYPE_INT },
+ { "mpuacc", "mpuacc", false, TYPE_INT },
+ { "PC", "pc", true, TYPE_CODE_POINTER },
+ }
+ }
+ }
+};
+
+//-------------------------------------------------------------------------
+static const gdb_register_map gdb_register_map_psxcpu =
+{
+ "mips",
+ {
+ {
+ "org.gnu.gdb.mips.cpu",
+ {
+ { "zero", "r0", false, TYPE_INT },
+ { "at", "r1", false, TYPE_INT },
+ { "v0", "r2", false, TYPE_INT },
+ { "v1", "r3", false, TYPE_INT },
+ { "a0", "r4", false, TYPE_INT },
+ { "a1", "r5", false, TYPE_INT },
+ { "a2", "r6", false, TYPE_INT },
+ { "a3", "r7", false, TYPE_INT },
+ { "t0", "r8", false, TYPE_INT },
+ { "t1", "r9", false, TYPE_INT },
+ { "t2", "r10", false, TYPE_INT },
+ { "t3", "r11", false, TYPE_INT },
+ { "t4", "r12", false, TYPE_INT },
+ { "t5", "r13", false, TYPE_INT },
+ { "t6", "r14", false, TYPE_INT },
+ { "t7", "r15", false, TYPE_INT },
+ { "s0", "r16", false, TYPE_INT },
+ { "s1", "r17", false, TYPE_INT },
+ { "s2", "r18", false, TYPE_INT },
+ { "s3", "r19", false, TYPE_INT },
+ { "s4", "r20", false, TYPE_INT },
+ { "s5", "r21", false, TYPE_INT },
+ { "s6", "r22", false, TYPE_INT },
+ { "s7", "r23", false, TYPE_INT },
+ { "t8", "r24", false, TYPE_INT },
+ { "t9", "r25", false, TYPE_INT },
+ { "k0", "r26", false, TYPE_INT },
+ { "k1", "r27", false, TYPE_INT },
+ { "gp", "r28", false, TYPE_INT },
+ { "sp", "r29", false, TYPE_INT },
+ { "fp", "r30", false, TYPE_INT },
+ { "ra", "r31", false, TYPE_CODE_POINTER },
+ { "lo", "lo", false, TYPE_INT },
+ { "hi", "hi", false, TYPE_INT },
+ { "pc", "pc", true, TYPE_CODE_POINTER },
+ }
+ },
+ {
+ "org.gnu.gdb.mips.cp0",
+ {
+ { "SR", "status", false, TYPE_INT },
+ { "BadA", "badvaddr", false, TYPE_INT },
+ { "Cause", "cause", false, TYPE_INT },
+ }
+ },
+ {
+ "org.gnu.gdb.mips.fpu",
+ {
+ { "zero", "f0", false, TYPE_INT },
+ { "zero", "f1", false, TYPE_INT },
+ { "zero", "f2", false, TYPE_INT },
+ { "zero", "f3", false, TYPE_INT },
+ { "zero", "f4", false, TYPE_INT },
+ { "zero", "f5", false, TYPE_INT },
+ { "zero", "f6", false, TYPE_INT },
+ { "zero", "f7", false, TYPE_INT },
+ { "zero", "f8", false, TYPE_INT },
+ { "zero", "f9", false, TYPE_INT },
+ { "zero", "f10", false, TYPE_INT },
+ { "zero", "f11", false, TYPE_INT },
+ { "zero", "f12", false, TYPE_INT },
+ { "zero", "f13", false, TYPE_INT },
+ { "zero", "f14", false, TYPE_INT },
+ { "zero", "f15", false, TYPE_INT },
+ { "zero", "f16", false, TYPE_INT },
+ { "zero", "f17", false, TYPE_INT },
+ { "zero", "f18", false, TYPE_INT },
+ { "zero", "f19", false, TYPE_INT },
+ { "zero", "f20", false, TYPE_INT },
+ { "zero", "f21", false, TYPE_INT },
+ { "zero", "f22", false, TYPE_INT },
+ { "zero", "f23", false, TYPE_INT },
+ { "zero", "f24", false, TYPE_INT },
+ { "zero", "f25", false, TYPE_INT },
+ { "zero", "f26", false, TYPE_INT },
+ { "zero", "f27", false, TYPE_INT },
+ { "zero", "f28", false, TYPE_INT },
+ { "zero", "f29", false, TYPE_INT },
+ { "zero", "f30", false, TYPE_INT },
+ { "zero", "f31", false, TYPE_INT },
+ { "zero", "fcsr", false, TYPE_INT },
+ { "zero", "fir" , false, TYPE_INT },
+ }
+ }
}
};
@@ -291,17 +655,40 @@ static const std::map<std::string, const gdb_register_map &> gdb_register_maps =
{ "arm7_le", gdb_register_map_arm7 },
{ "r4600", gdb_register_map_r4600 },
{ "ppc601", gdb_register_map_ppc601 },
+ { "m68030", gdb_register_map_m68030 },
{ "m68020pmmu", gdb_register_map_m68020pmmu },
+ { "m68000", gdb_register_map_m68000 },
{ "z80", gdb_register_map_z80 },
+ { "z80n", gdb_register_map_z80 },
+ { "z84c015", gdb_register_map_z80 },
{ "m6502", gdb_register_map_m6502 },
+ { "m6507", gdb_register_map_m6502 },
+ { "m6510", gdb_register_map_m6502 },
+ { "m65ce02", gdb_register_map_m6502 },
+ { "rp2a03", gdb_register_map_m6502 },
+ { "w65c02", gdb_register_map_m6502 },
+ { "w65c02s", gdb_register_map_m6502 },
+ { "m6809", gdb_register_map_m6809 },
+ { "score7", gdb_register_map_score7 },
+ { "nios2", gdb_register_map_nios2 },
+ { "cxd8530q", gdb_register_map_psxcpu },
+ { "cxd8530aq", gdb_register_map_psxcpu },
+ { "cxd8530bq", gdb_register_map_psxcpu },
+ { "cxd8530cq", gdb_register_map_psxcpu },
+ { "cxd8606q", gdb_register_map_psxcpu },
+ { "cxd8606aq", gdb_register_map_psxcpu },
+ { "cxd8606bq", gdb_register_map_psxcpu },
+ { "cxd8606cq", gdb_register_map_psxcpu },
+ { "cxd8661r", gdb_register_map_psxcpu },
};
//-------------------------------------------------------------------------
class debug_gdbstub : public osd_module, public debug_module
{
public:
- debug_gdbstub()
- : osd_module(OSD_DEBUG_PROVIDER, "gdbstub"), debug_module(),
+ debug_gdbstub() :
+ osd_module(OSD_DEBUG_PROVIDER, "gdbstub"), debug_module(),
+ m_readbuf_state(PACKET_START),
m_machine(nullptr),
m_maincpu(nullptr),
m_state(nullptr),
@@ -309,6 +696,7 @@ public:
m_address_space(nullptr),
m_debugger_cpu(nullptr),
m_debugger_console(nullptr),
+ m_debugger_host(),
m_debugger_port(0),
m_socket(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE),
m_is_be(false),
@@ -329,7 +717,7 @@ public:
virtual ~debug_gdbstub() { }
- virtual int init(const osd_options &options) override;
+ virtual int init(osd_interface &osd, const osd_options &options) override;
virtual void exit() override;
virtual void init_debugger(running_machine &machine) override;
@@ -346,9 +734,9 @@ public:
bool is_thread_id_ok(const char *buf);
void handle_character(char ch);
- void send_nack(void);
- void send_ack(void);
- void handle_packet(void);
+ void send_nack();
+ void send_ack();
+ void handle_packet();
enum cmd_reply
{
@@ -374,6 +762,7 @@ public:
cmd_reply handle_P(const char *buf);
cmd_reply handle_q(const char *buf);
cmd_reply handle_s(const char *buf);
+ cmd_reply handle_T(const char *buf);
cmd_reply handle_z(const char *buf);
cmd_reply handle_Z(const char *buf);
@@ -387,12 +776,12 @@ public:
readbuf_state m_readbuf_state;
- void generate_target_xml(void);
+ void generate_target_xml();
- int readchar(void);
+ int readchar();
- void send_reply(const char *str);
- void send_stop_packet(void);
+ void send_reply(std::string_view str);
+ void send_stop_packet();
private:
running_machine *m_machine;
@@ -402,6 +791,7 @@ private:
address_space *m_address_space;
debugger_cpu *m_debugger_cpu;
debugger_console *m_debugger_console;
+ std::string m_debugger_host;
int m_debugger_port;
emu_file m_socket;
bool m_is_be;
@@ -413,6 +803,7 @@ private:
struct gdb_register
{
+ std::string gdb_feature_name;
std::string gdb_name;
int gdb_regnum;
gdb_register_type gdb_type;
@@ -422,12 +813,11 @@ private:
std::vector<gdb_register> m_gdb_registers;
std::set<int> m_stop_reply_registers;
std::string m_gdb_arch;
- std::string m_gdb_feature;
std::map<offs_t, uint64_t> m_address_map;
- device_debug::breakpoint *m_triggered_breakpoint;
- device_debug::watchpoint *m_triggered_watchpoint;
+ debug_breakpoint *m_triggered_breakpoint;
+ debug_watchpoint *m_triggered_watchpoint;
std::string m_target_xml;
@@ -442,14 +832,15 @@ private:
};
//-------------------------------------------------------------------------
-int debug_gdbstub::init(const osd_options &options)
+int debug_gdbstub::init(osd_interface &osd, const osd_options &options)
{
+ m_debugger_host = options.debugger_host();
m_debugger_port = options.debugger_port();
return 0;
}
//-------------------------------------------------------------------------
-void debug_gdbstub::exit(void)
+void debug_gdbstub::exit()
{
}
@@ -460,7 +851,7 @@ void debug_gdbstub::init_debugger(running_machine &machine)
}
//-------------------------------------------------------------------------
-int debug_gdbstub::readchar(void)
+int debug_gdbstub::readchar()
{
// NOTE: we don't use m_socket.getc() because it does not work with
// sockets (it assumes seeking is possible).
@@ -480,11 +871,11 @@ int debug_gdbstub::readchar(void)
}
//-------------------------------------------------------------------------
-static std::string escape_packet(const std::string src)
+static std::string escape_packet(std::string_view src)
{
std::string result;
result.reserve(src.length());
- for ( char ch: src )
+ for ( char ch : src )
{
if ( ch == '#' || ch == '$' || ch == '}' )
{
@@ -497,7 +888,7 @@ static std::string escape_packet(const std::string src)
}
//-------------------------------------------------------------------------
-void debug_gdbstub::generate_target_xml(void)
+void debug_gdbstub::generate_target_xml()
{
// Note: we do not attempt to replicate the regnum values from old
// GDB clients that did not support target.xml.
@@ -505,11 +896,23 @@ void debug_gdbstub::generate_target_xml(void)
target_xml += "<?xml version=\"1.0\"?>\n";
target_xml += "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">\n";
target_xml += "<target version=\"1.0\">\n";
- target_xml += string_format("<architecture>%s</architecture>\n", m_gdb_arch.c_str());
- target_xml += string_format(" <feature name=\"%s\">\n", m_gdb_feature.c_str());
+ target_xml += string_format("<architecture>%s</architecture>\n", m_gdb_arch);
+ std::string feature_name;
for ( const auto &reg: m_gdb_registers )
- target_xml += string_format(" <reg name=\"%s\" bitsize=\"%d\" type=\"%s\"/>\n", reg.gdb_name.c_str(), reg.gdb_bitsize, gdb_register_type_str[reg.gdb_type]);
- target_xml += " </feature>\n";
+ {
+ if (feature_name != reg.gdb_feature_name)
+ {
+ if (!feature_name.empty())
+ target_xml += " </feature>\n";
+
+ feature_name = reg.gdb_feature_name;
+ target_xml += string_format(" <feature name=\"%s\">\n", feature_name);
+ }
+
+ target_xml += string_format(" <reg name=\"%s\" bitsize=\"%d\" type=\"%s\"/>\n", reg.gdb_name, reg.gdb_bitsize, gdb_register_type_str[reg.gdb_type]);
+ }
+ if (!feature_name.empty())
+ target_xml += " </feature>\n";
target_xml += "</target>\n";
m_target_xml = escape_packet(target_xml);
}
@@ -522,13 +925,18 @@ void debug_gdbstub::wait_for_debugger(device_t &device, bool firststop)
if ( firststop && !m_initialized )
{
- m_maincpu = m_machine->root_device().subdevice(":maincpu");
+ // find the "main" CPU, which is the first CPU (gdbstub doesn't have any notion of switching CPUs)
+ m_maincpu = device_interface_enumerator<cpu_device>(m_machine->root_device()).first();
+ if (!m_maincpu)
+ fatalerror("gdbstub: cannot find any CPUs\n");
+
const char *cpuname = m_maincpu->shortname();
auto it = gdb_register_maps.find(cpuname);
if ( it == gdb_register_maps.end() )
fatalerror("gdbstub: cpuname %s not found in gdb stub descriptions\n", cpuname);
- m_state = &m_maincpu->state();
+ m_maincpu->interface(m_state);
+ assert(m_state != nullptr);
m_memory = &m_maincpu->memory();
m_address_space = &m_memory->space(AS_PROGRAM);
m_debugger_cpu = &m_machine->debugger().cpu();
@@ -544,59 +952,60 @@ void debug_gdbstub::wait_for_debugger(device_t &device, bool firststop)
uint64_t datamask = entry->datamask();
int index = entry->index();
const std::string &format_string = entry->format_string();
- osd_printf_info("[%3d] datasize %d mask %016" PRIx64 " [%s] [%s]\n", index, datasize, datamask, symbol, format_string.c_str());
+ osd_printf_info("[%3d] datasize %d mask %016" PRIx64 " [%s] [%s]\n", index, datasize, datamask, symbol, format_string);
}
#endif
const gdb_register_map &register_map = it->second;
m_gdb_arch = register_map.arch;
- m_gdb_feature = register_map.feature;
int cur_gdb_regnum = 0;
- for ( const auto &reg: register_map.registers )
- {
- bool added = false;
- for ( const auto &entry: m_state->state_entries() )
+ for ( const auto &feature: register_map.features )
+ for ( const auto &reg: feature.registers )
{
- const char *symbol = entry->symbol();
- if ( strcmp(symbol, reg.state_name) == 0 )
+ bool added = false;
+ for ( const auto &entry: m_state->state_entries() )
{
- gdb_register new_reg;
- new_reg.gdb_name = reg.gdb_name;
- new_reg.gdb_regnum = cur_gdb_regnum;
- new_reg.gdb_type = reg.gdb_type;
- if ( reg.override_bitsize != -1 )
- new_reg.gdb_bitsize = reg.override_bitsize;
- else
- new_reg.gdb_bitsize = entry->datasize() * 8;
- new_reg.state_index = entry->index();
- m_gdb_registers.push_back(std::move(new_reg));
- if ( reg.stop_packet )
- m_stop_reply_registers.insert(cur_gdb_regnum);
- added = true;
- cur_gdb_regnum++;
- break;
+ const char *symbol = entry->symbol();
+ if ( strcmp(symbol, reg.state_name) == 0 )
+ {
+ gdb_register new_reg;
+ new_reg.gdb_feature_name = feature.feature_name;
+ new_reg.gdb_name = reg.gdb_name;
+ new_reg.gdb_regnum = cur_gdb_regnum;
+ new_reg.gdb_type = reg.gdb_type;
+ if ( reg.override_bitsize != -1 )
+ new_reg.gdb_bitsize = reg.override_bitsize;
+ else
+ new_reg.gdb_bitsize = entry->datasize() * 8;
+ new_reg.state_index = entry->index();
+ m_gdb_registers.push_back(std::move(new_reg));
+ if ( reg.stop_packet )
+ m_stop_reply_registers.insert(cur_gdb_regnum);
+ added = true;
+ cur_gdb_regnum++;
+ break;
+ }
}
+ if ( !added )
+ osd_printf_info("gdbstub: could not find register [%s]\n", reg.gdb_name);
}
- if ( !added )
- osd_printf_info("gdbstub: could not find register [%s]\n", reg.gdb_name);
- }
#if 0
for ( const auto &reg: m_gdb_registers )
- osd_printf_info(" %3d (%d) %d %d [%s]\n", reg.gdb_regnum, reg.state_index, reg.gdb_bitsize, reg.gdb_type, reg.gdb_name.c_str());
+ osd_printf_info(" %3d (%d) %d %d [%s]\n", reg.gdb_regnum, reg.state_index, reg.gdb_bitsize, reg.gdb_type, reg.gdb_name);
#endif
- std::string socket_name = string_format("socket.localhost:%d", m_debugger_port);
- osd_file::error filerr = m_socket.open(socket_name.c_str());
- if ( filerr != osd_file::error::NONE )
- fatalerror("gdbstub: failed to start listening on port %d\n", m_debugger_port);
- osd_printf_info("gdbstub: listening on port %d\n", m_debugger_port);
+ std::string socket_name = string_format("socket.%s:%d", m_debugger_host, m_debugger_port);
+ std::error_condition const filerr = m_socket.open(socket_name);
+ if ( filerr )
+ fatalerror("gdbstub: failed to start listening on address %s port %d\n", m_debugger_host, m_debugger_port);
+ osd_printf_info("gdbstub: listening on address %s port %d\n", m_debugger_host, m_debugger_port);
m_initialized = true;
}
else
{
- device_debug *debug = m_debugger_cpu->get_visible_cpu()->debug();
+ device_debug *debug = m_debugger_console->get_visible_cpu()->debug();
m_triggered_watchpoint = debug->triggered_watchpoint();
m_triggered_breakpoint = debug->triggered_breakpoint();
if ( m_send_stop_packet )
@@ -622,7 +1031,7 @@ void debug_gdbstub::wait_for_debugger(device_t &device, bool firststop)
}
//-------------------------------------------------------------------------
-void debug_gdbstub::debugger_update(void)
+void debug_gdbstub::debugger_update()
{
while ( true )
{
@@ -634,28 +1043,26 @@ void debug_gdbstub::debugger_update(void)
}
//-------------------------------------------------------------------------
-void debug_gdbstub::send_nack(void)
+void debug_gdbstub::send_nack()
{
- m_socket.puts("-");
+ m_socket.write("-", 1);
}
//-------------------------------------------------------------------------
-void debug_gdbstub::send_ack(void)
+void debug_gdbstub::send_ack()
{
- m_socket.puts("+");
+ m_socket.write("+", 1);
}
//-------------------------------------------------------------------------
-void debug_gdbstub::send_reply(const char *str)
+void debug_gdbstub::send_reply(std::string_view str)
{
- size_t length = strlen(str);
-
uint8_t checksum = 0;
- for ( size_t i = 0; i < length; i++ )
- checksum += str[i];
+ for ( char ch : str )
+ checksum += ch;
std::string reply = string_format("$%s#%02x", str, checksum);
- m_socket.puts(reply.c_str());
+ m_socket.write(reply.c_str(), reply.length());
}
@@ -683,7 +1090,7 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_c(const char *buf)
if ( *buf != '\0' )
return REPLY_UNSUPPORTED;
- m_debugger_cpu->get_visible_cpu()->debug()->go();
+ m_debugger_console->get_visible_cpu()->debug()->go();
m_send_stop_packet = true;
return REPLY_NONE;
}
@@ -696,7 +1103,7 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_D(const char *buf)
if ( *buf != '\0' )
return REPLY_UNSUPPORTED;
- m_debugger_cpu->get_visible_cpu()->debug()->go();
+ m_debugger_console->get_visible_cpu()->debug()->go();
m_dettached = true;
return REPLY_OK;
@@ -713,7 +1120,7 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_g(const char *buf)
std::string reply;
for ( const auto &reg: m_gdb_registers )
reply += get_register_string(reg.gdb_regnum);
- send_reply(reply.c_str());
+ send_reply(reply);
return REPLY_NONE;
}
@@ -752,7 +1159,7 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_H(const char *buf)
debug_gdbstub::cmd_reply debug_gdbstub::handle_k(const char *buf)
{
m_machine->schedule_exit();
- m_debugger_cpu->get_visible_cpu()->debug()->go();
+ m_debugger_console->get_visible_cpu()->debug()->go();
m_dettached = true;
m_socket.close();
return REPLY_NONE;
@@ -768,7 +1175,8 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_m(const char *buf)
return REPLY_ENN;
offs_t offset = address;
- if ( !m_memory->translate(m_address_space->spacenum(), TRANSLATE_READ_DEBUG, offset) )
+ address_space *tspace;
+ if ( !m_memory->translate(m_address_space->spacenum(), device_memory_interface::TR_READ, offset, tspace) )
return REPLY_ENN;
// Disable side effects while reading memory.
@@ -778,10 +1186,10 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_m(const char *buf)
reply.reserve(length * 2);
for ( int i = 0; i < length; i++ )
{
- uint8_t value = m_address_space->read_byte(offset + i);
+ uint8_t value = tspace->read_byte(offset + i);
reply += string_format("%02x", value);
}
- send_reply(reply.c_str());
+ send_reply(reply);
return REPLY_NONE;
}
@@ -813,7 +1221,8 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_M(const char *buf)
return REPLY_ENN;
offs_t offset = address;
- if ( !m_memory->translate(m_address_space->spacenum(), TRANSLATE_READ_DEBUG, offset) )
+ address_space *tspace;
+ if ( !m_memory->translate(m_address_space->spacenum(), device_memory_interface::TR_READ, offset, tspace) )
return REPLY_ENN;
std::vector<uint8_t> data;
@@ -821,7 +1230,7 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_M(const char *buf)
return REPLY_ENN;
for ( int i = 0; i < length; i++ )
- m_address_space->write_byte(offset + i, data[i]);
+ tspace->write_byte(offset + i, data[i]);
return REPLY_OK;
}
@@ -836,7 +1245,7 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_p(const char *buf)
if ( sscanf(buf, "%x", &gdb_regnum) != 1 || gdb_regnum >= m_gdb_registers.size() )
return REPLY_ENN;
std::string reply = get_register_string(gdb_regnum);
- send_reply(reply.c_str());
+ send_reply(reply);
return REPLY_NONE;
}
@@ -888,7 +1297,7 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_q(const char *buf)
if ( !hex_decode(&data, buf, strlen(buf) / 2) )
return REPLY_ENN;
std::string command(data.begin(), data.end());
- text_buffer *textbuf = m_debugger_console->get_console_textbuf();
+ text_buffer &textbuf = m_debugger_console->get_console_textbuf();
text_buffer_clear(textbuf);
m_debugger_console->execute_command(command, false);
uint32_t nlines = text_buffer_num_lines(textbuf);
@@ -903,7 +1312,7 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_q(const char *buf)
reply += string_format("%02x", *line++);
reply += "0A";
}
- send_reply(reply.c_str());
+ send_reply(reply);
return REPLY_NONE;
}
@@ -920,7 +1329,7 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_q(const char *buf)
{
std::string reply = string_format("PacketSize=%x", MAX_PACKET_SIZE);
reply += ";qXfer:features:read+";
- send_reply(reply.c_str());
+ send_reply(reply);
return REPLY_NONE;
}
else if ( name == "Xfer" )
@@ -941,7 +1350,7 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_q(const char *buf)
else
reply += 'l';
reply += m_target_xml.substr(offset, length);
- send_reply(reply.c_str());
+ send_reply(reply);
m_target_xml_sent = true;
return REPLY_NONE;
}
@@ -969,15 +1378,26 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_s(const char *buf)
if ( *buf != '\0' )
return REPLY_UNSUPPORTED;
- m_debugger_cpu->get_visible_cpu()->debug()->single_step();
+ m_debugger_console->get_visible_cpu()->debug()->single_step();
m_send_stop_packet = true;
return REPLY_NONE;
}
//-------------------------------------------------------------------------
+// Find out if the thread XX is alive.
+debug_gdbstub::cmd_reply debug_gdbstub::handle_T(const char *buf)
+{
+ if ( is_thread_id_ok(buf) )
+ return REPLY_OK;
+
+ // thread is dead
+ return REPLY_ENN;
+}
+
+//-------------------------------------------------------------------------
static bool remove_breakpoint(device_debug *debug, uint64_t address, int /*kind*/)
{
- const device_debug::breakpoint *bp = debug->breakpoint_find(address);
+ const debug_breakpoint *bp = debug->breakpoint_find(address);
if (bp != nullptr)
return debug->breakpoint_clear(bp->index());
return false;
@@ -1014,14 +1434,15 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_z(const char *buf)
// watchpoints
offs_t offset = address;
+ address_space *tspace;
if ( type == 2 || type == 3 || type == 4 )
{
- if ( !m_memory->translate(m_address_space->spacenum(), TRANSLATE_READ_DEBUG, offset) )
+ if ( !m_memory->translate(m_address_space->spacenum(), device_memory_interface::TR_READ, offset, tspace) )
return REPLY_ENN;
m_address_map.erase(offset);
}
- device_debug *debug = m_debugger_cpu->get_visible_cpu()->debug();
+ device_debug *debug = m_debugger_console->get_visible_cpu()->debug();
switch ( type )
{
// Note: software and hardware breakpoints are treated both the
@@ -1055,14 +1476,15 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_Z(const char *buf)
// watchpoints
offs_t offset = address;
+ address_space *tspace;
if ( type == 2 || type == 3 || type == 4 )
{
- if ( !m_memory->translate(m_address_space->spacenum(), TRANSLATE_READ_DEBUG, offset) )
+ if ( !m_memory->translate(m_address_space->spacenum(), device_memory_interface::TR_READ, offset, tspace) )
return REPLY_ENN;
m_address_map[offset] = address;
}
- device_debug *debug = m_debugger_cpu->get_visible_cpu()->debug();
+ device_debug *debug = m_debugger_console->get_visible_cpu()->debug();
switch ( type )
{
// Note: software and hardware breakpoints are treated both the
@@ -1073,15 +1495,15 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_Z(const char *buf)
return REPLY_OK;
case 2:
// write watchpoint
- debug->watchpoint_set(*m_address_space, read_or_write::WRITE, offset, kind, nullptr, nullptr);
+ debug->watchpoint_set(*m_address_space, read_or_write::WRITE, offset, kind);
return REPLY_OK;
case 3:
// read watchpoint
- debug->watchpoint_set(*m_address_space, read_or_write::READ, offset, kind, nullptr, nullptr);
+ debug->watchpoint_set(*m_address_space, read_or_write::READ, offset, kind);
return REPLY_OK;
case 4:
// access watchpoint
- debug->watchpoint_set(*m_address_space, read_or_write::READWRITE, offset, kind, nullptr, nullptr);
+ debug->watchpoint_set(*m_address_space, read_or_write::READWRITE, offset, kind);
return REPLY_OK;
}
@@ -1090,7 +1512,7 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_Z(const char *buf)
//-------------------------------------------------------------------------
-void debug_gdbstub::send_stop_packet(void)
+void debug_gdbstub::send_stop_packet()
{
int signal = 5; // GDB_SIGNAL_TRAP
std::string reply = string_format("T%02x", signal);
@@ -1115,11 +1537,11 @@ void debug_gdbstub::send_stop_packet(void)
if ( m_target_xml_sent )
for ( const auto &gdb_regnum: m_stop_reply_registers )
reply += string_format("%02x:%s;", gdb_regnum, get_register_string(gdb_regnum));
- send_reply(reply.c_str());
+ send_reply(reply);
}
//-------------------------------------------------------------------------
-void debug_gdbstub::handle_packet(void)
+void debug_gdbstub::handle_packet()
{
// For any command not supported by the stub, an empty response
// (‘$#00’) should be returned. That way it is possible to extend
@@ -1144,6 +1566,7 @@ void debug_gdbstub::handle_packet(void)
case 'P': reply = handle_P(buf); break;
case 'q': reply = handle_q(buf); break;
case 's': reply = handle_s(buf); break;
+ case 'T': reply = handle_T(buf); break;
case 'z': reply = handle_z(buf); break;
case 'Z': reply = handle_Z(buf); break;
}
@@ -1156,22 +1579,6 @@ void debug_gdbstub::handle_packet(void)
}
//-------------------------------------------------------------------------
-#define BYTESWAP_64(x) ((((x) << 56) & 0xFF00000000000000) \
- | (((x) << 40) & 0x00FF000000000000) \
- | (((x) << 24) & 0x0000FF0000000000) \
- | (((x) << 8) & 0x000000FF00000000) \
- | (((x) >> 8) & 0x00000000FF000000) \
- | (((x) >> 24) & 0x0000000000FF0000) \
- | (((x) >> 40) & 0x000000000000FF00) \
- | (((x) >> 56) & 0x00000000000000FF))
-#define BYTESWAP_32(x) ((((x) << 24) & 0xFF000000) \
- | (((x) << 8) & 0x00FF0000) \
- | (((x) >> 8) & 0x0000FF00) \
- | (((x) >> 24) & 0x000000FF))
-#define BYTESWAP_16(x) ((((x) << 8) & 0xFF00) \
- | (((x) >> 8) & 0x00FF))
-
-//-------------------------------------------------------------------------
std::string debug_gdbstub::get_register_string(int gdb_regnum)
{
const gdb_register &reg = m_gdb_registers[gdb_regnum];
@@ -1184,9 +1591,9 @@ std::string debug_gdbstub::get_register_string(int gdb_regnum)
value &= (1ULL << reg.gdb_bitsize) - 1;
if ( !m_is_be )
{
- value = (reg.gdb_bitsize == 64) ? BYTESWAP_64(value)
- : (reg.gdb_bitsize == 32) ? BYTESWAP_32(value)
- : (reg.gdb_bitsize == 16) ? BYTESWAP_16(value)
+ value = (reg.gdb_bitsize == 64) ? swapendian_int64(value)
+ : (reg.gdb_bitsize == 32) ? swapendian_int32(value)
+ : (reg.gdb_bitsize == 16) ? swapendian_int16(value)
: value;
}
return string_format(fmt, value);
@@ -1205,9 +1612,9 @@ bool debug_gdbstub::parse_register_string(uint64_t *pvalue, const char *buf, int
return false;
if ( !m_is_be )
{
- value = (reg.gdb_bitsize == 64) ? BYTESWAP_64(value)
- : (reg.gdb_bitsize == 32) ? BYTESWAP_32(value)
- : (reg.gdb_bitsize == 16) ? BYTESWAP_16(value)
+ value = (reg.gdb_bitsize == 64) ? swapendian_int64(value)
+ : (reg.gdb_bitsize == 32) ? swapendian_int32(value)
+ : (reg.gdb_bitsize == 16) ? swapendian_int16(value)
: value;
}
*pvalue = value;
@@ -1304,5 +1711,9 @@ void debug_gdbstub::handle_character(char ch)
}
}
+} // anonymous namespace
+
+} // namespace osd
+
//-------------------------------------------------------------------------
-MODULE_DEFINITION(DEBUG_GDBSTUB, debug_gdbstub)
+MODULE_DEFINITION(DEBUG_GDBSTUB, osd::debug_gdbstub)
diff --git a/src/osd/modules/debugger/debugimgui.cpp b/src/osd/modules/debugger/debugimgui.cpp
index 39dcb3310cf..e027cb5339c 100644
--- a/src/osd/modules/debugger/debugimgui.cpp
+++ b/src/osd/modules/debugger/debugimgui.cpp
@@ -3,9 +3,11 @@
// ImGui based debugger
#include "emu.h"
+#include "debug_module.h"
+
#include "imgui/imgui.h"
-#include "render.h"
-#include "uiinput.h"
+
+#include "imagedev/floppy.h"
#include "debug/debugvw.h"
#include "debug/dvdisasm.h"
@@ -14,30 +16,37 @@
#include "debug/dvwpoints.h"
#include "debug/debugcon.h"
#include "debug/debugcpu.h"
+#include "debugger.h"
+#include "render.h"
+#include "ui/uimain.h"
+#include "uiinput.h"
+
+#include "formats/flopimg.h"
#include "config.h"
-#include "debugger.h"
#include "modules/lib/osdobj_common.h"
-#include "debug_module.h"
#include "modules/osdmodule.h"
#include "zippath.h"
-#include "imagedev/floppy.h"
+
+namespace osd {
+
+namespace {
class debug_area
{
DISABLE_COPYING(debug_area);
public:
- debug_area(running_machine &machine, debug_view_type type)
- : next(nullptr),
- type(0),
- ofs_x(0),
- ofs_y(0),
- is_collapsed(false),
- exec_cmd(false),
- scroll_end(false),
- scroll_follow(false)
- {
+ debug_area(running_machine &machine, debug_view_type type) :
+ next(nullptr),
+ type(0),
+ ofs_x(0),
+ ofs_y(0),
+ is_collapsed(false),
+ exec_cmd(false),
+ scroll_end(false),
+ scroll_follow(false)
+ {
this->view = machine.debug_view().alloc_view(type, nullptr, this);
this->type = type;
this->m_machine = &machine;
@@ -55,7 +64,7 @@ public:
default:
break;
}
- }
+ }
~debug_area()
{
//this->target->debug_free(*this->container);
@@ -64,7 +73,7 @@ public:
running_machine &machine() const { assert(m_machine != nullptr); return *m_machine; }
- debug_area * next;
+ debug_area * next;
int type;
debug_view * view;
@@ -91,9 +100,11 @@ public:
class debug_imgui : public osd_module, public debug_module
{
public:
- debug_imgui()
- : osd_module(OSD_DEBUG_PROVIDER, "imgui"), debug_module(),
+ debug_imgui() :
+ osd_module(OSD_DEBUG_PROVIDER, "imgui"), debug_module(),
m_machine(nullptr),
+ m_take_ui(false),
+ m_current_pointer(-1),
m_mouse_x(0),
m_mouse_y(0),
m_mouse_button(false),
@@ -118,7 +129,7 @@ public:
virtual ~debug_imgui() { }
- virtual int init(const osd_options &options) override { return 0; }
+ virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
virtual void exit() override {};
virtual void init_debugger(running_machine &machine) override;
@@ -142,14 +153,13 @@ private:
struct image_type_entry
{
- floppy_image_format_t* format;
+ const floppy_image_format_t* format;
std::string shortname;
std::string longname;
};
- void handle_mouse();
+ void handle_events();
void handle_mouse_views();
- void handle_keys();
void handle_keys_views();
void handle_console(running_machine* machine);
void update();
@@ -172,19 +182,21 @@ private:
void refresh_filelist();
void refresh_typelist();
void update_cpu_view(device_t* device);
- static bool get_view_source(void* data, int idx, const char** out_text);
+ static const char* get_view_source(void* data, int idx);
static int history_set(ImGuiInputTextCallbackData* data);
running_machine* m_machine;
- int32_t m_mouse_x;
- int32_t m_mouse_y;
+ bool m_take_ui;
+ int32_t m_current_pointer;
+ int32_t m_mouse_x;
+ int32_t m_mouse_y;
bool m_mouse_button;
bool m_prev_mouse_button;
bool m_running;
const char* font_name;
float font_size;
ImVec2 m_text_size; // size of character (assumes monospaced font is in use)
- uint8_t m_key_char;
+ uint8_t m_key_char;
bool m_hide;
int m_win_count; // number of active windows, does not decrease, used to ID individual windows
bool m_has_images; // true if current system has any image devices
@@ -199,6 +211,7 @@ private:
file_entry* m_selected_file;
int m_format_sel;
char m_path[1024]; // path text field buffer
+ std::unordered_map<input_item_id,ImGuiKey> m_mapping;
};
// globals
@@ -225,11 +238,7 @@ static void view_list_remove(debug_area* item)
static debug_area *dview_alloc(running_machine &machine, debug_view_type type)
{
- debug_area *dv;
-
- dv = global_alloc(debug_area(machine, type));
-
- return dv;
+ return new debug_area(machine, type);
}
static inline void map_attr_to_fg_bg(unsigned char attr, rgb_t *fg, rgb_t *bg)
@@ -259,107 +268,92 @@ static inline void map_attr_to_fg_bg(unsigned char attr, rgb_t *fg, rgb_t *bg)
}
}
-bool debug_imgui::get_view_source(void* data, int idx, const char** out_text)
-{
- debug_view* vw = static_cast<debug_view*>(data);
- *out_text = vw->source_list().find(idx)->name();
- return true;
-}
-
-void debug_imgui::handle_mouse()
+const char* debug_imgui::get_view_source(void* data, int idx)
{
- m_prev_mouse_button = m_mouse_button;
- m_machine->ui_input().find_mouse(&m_mouse_x, &m_mouse_y, &m_mouse_button);
+ auto* vw = static_cast<debug_view*>(data);
+ return vw->source(idx)->name();
}
-void debug_imgui::handle_mouse_views()
-{
- rectangle rect;
- bool clicked = false;
- if(m_mouse_button == true && m_prev_mouse_button == false)
- clicked = true;
-
- // check all views, and pass mouse clicks to them
- if(!m_mouse_button)
- return;
- rect.min_x = view_main_disasm->ofs_x;
- rect.min_y = view_main_disasm->ofs_y;
- rect.max_x = view_main_disasm->ofs_x + view_main_disasm->view_width;
- rect.max_y = view_main_disasm->ofs_y + view_main_disasm->view_height;
- if(rect.contains(m_mouse_x,m_mouse_y) && clicked && view_main_disasm->has_focus)
- {
- debug_view_xy topleft = view_main_disasm->view->visible_position();
- debug_view_xy newpos;
- newpos.x = topleft.x + (m_mouse_x-view_main_disasm->ofs_x) / m_text_size.x;
- newpos.y = topleft.y + (m_mouse_y-view_main_disasm->ofs_y) / m_text_size.y;
- view_main_disasm->view->set_cursor_position(newpos);
- view_main_disasm->view->set_cursor_visible(true);
- }
- for(std::vector<debug_area*>::iterator it = view_list.begin();it != view_list.end();++it)
- {
- rect.min_x = (*it)->ofs_x;
- rect.min_y = (*it)->ofs_y;
- rect.max_x = (*it)->ofs_x + (*it)->view_width;
- rect.max_y = (*it)->ofs_y + (*it)->view_height;
- if(rect.contains(m_mouse_x,m_mouse_y) && clicked && (*it)->has_focus)
- {
- if((*it)->view->cursor_supported())
- {
- debug_view_xy topleft = (*it)->view->visible_position();
- debug_view_xy newpos;
- newpos.x = topleft.x + (m_mouse_x-(*it)->ofs_x) / m_text_size.x;
- newpos.y = topleft.y + (m_mouse_y-(*it)->ofs_y) / m_text_size.y;
- (*it)->view->set_cursor_position(newpos);
- (*it)->view->set_cursor_visible(true);
- }
- }
- }
-}
-
-void debug_imgui::handle_keys()
+void debug_imgui::handle_events()
{
ImGuiIO& io = ImGui::GetIO();
- ui_event event;
- debug_area* focus_view = nullptr;
// find view that has focus (should only be one at a time)
- for(std::vector<debug_area*>::iterator view_ptr = view_list.begin();view_ptr != view_list.end();++view_ptr)
+ debug_area* focus_view = nullptr;
+ for(auto view_ptr = view_list.begin();view_ptr != view_list.end(); ++view_ptr)
if((*view_ptr)->has_focus)
focus_view = *view_ptr;
// check views in main views also (only the disassembler view accepts inputs)
- if(view_main_disasm->has_focus)
- focus_view = view_main_disasm;
+ if(view_main_disasm)
+ if(view_main_disasm->has_focus)
+ focus_view = view_main_disasm;
- if(m_machine->input().code_pressed(KEYCODE_LCONTROL))
- io.KeyCtrl = true;
- else
- io.KeyCtrl = false;
- if(m_machine->input().code_pressed(KEYCODE_LSHIFT))
- io.KeyShift = true;
- else
- io.KeyShift = false;
- if(m_machine->input().code_pressed(KEYCODE_LALT))
- io.KeyAlt = true;
- else
- io.KeyAlt = false;
+ io.KeyCtrl = m_machine->input().code_pressed(KEYCODE_LCONTROL);
+ io.KeyShift = m_machine->input().code_pressed(KEYCODE_LSHIFT);
+ io.KeyAlt = m_machine->input().code_pressed(KEYCODE_LALT);
for(input_item_id id = ITEM_ID_A; id <= ITEM_ID_CANCEL; ++id)
{
if(m_machine->input().code_pressed(input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, id)))
- io.KeysDown[id] = true;
+ {
+ if(m_mapping.count(id))
+ io.AddKeyEvent(m_mapping[id], true);
+ }
else
- io.KeysDown[id] = false;
+ {
+ if(m_mapping.count(id))
+ io.AddKeyEvent(m_mapping[id], false);
+ }
}
+ m_prev_mouse_button = m_mouse_button;
m_key_char = 0;
- while (m_machine->ui_input().pop_event(&event))
+ ui_event event;
+ while(m_machine->ui_input().pop_event(&event))
{
switch (event.event_type)
{
- case ui_event::IME_CHAR:
- m_key_char = event.ch;
- if(focus_view != nullptr)
+ case ui_event::type::POINTER_UPDATE:
+ if(&m_machine->render().ui_target() != event.target)
+ break;
+ if(event.pointer_id != m_current_pointer)
+ {
+ if((0 > m_current_pointer) || ((event.pointer_pressed & 1) && !m_mouse_button))
+ m_current_pointer = event.pointer_id;
+ }
+ if(event.pointer_id == m_current_pointer)
+ {
+ bool changed = (m_mouse_x != event.pointer_x) || (m_mouse_y != event.pointer_y) || (m_mouse_button != bool(event.pointer_buttons & 1));
+ m_mouse_x = event.pointer_x;
+ m_mouse_y = event.pointer_y;
+ m_mouse_button = bool(event.pointer_buttons & 1);
+ if(changed)
+ {
+ io.MousePos = ImVec2(m_mouse_x,m_mouse_y);
+ io.MouseDown[0] = m_mouse_button;
+ }
+ }
+ break;
+ case ui_event::type::POINTER_LEAVE:
+ case ui_event::type::POINTER_ABORT:
+ if((&m_machine->render().ui_target() == event.target) && (event.pointer_id == m_current_pointer))
+ {
+ m_current_pointer = -1;
+ bool changed = (m_mouse_x != event.pointer_x) || (m_mouse_y != event.pointer_y) || m_mouse_button;
+ m_mouse_x = event.pointer_x;
+ m_mouse_y = event.pointer_y;
+ m_mouse_button = false;
+ if(changed)
+ {
+ io.MousePos = ImVec2(m_mouse_x,m_mouse_y);
+ io.MouseDown[0] = m_mouse_button;
+ }
+ }
+ break;
+ case ui_event::type::IME_CHAR:
+ m_key_char = event.ch; // FIXME: assigning 4-byte UCS4 character to 8-bit variable
+ if(focus_view)
focus_view->view->process_char(m_key_char);
return;
default:
@@ -368,108 +362,153 @@ void debug_imgui::handle_keys()
}
// global keys
- if(ImGui::IsKeyPressed(ITEM_ID_F3,false))
+ if(ImGui::IsKeyPressed(ImGuiKey_F3,false))
{
- if(ImGui::IsKeyDown(ITEM_ID_LSHIFT))
+ if(ImGui::IsKeyDown(ImGuiKey_LeftShift))
m_machine->schedule_hard_reset();
else
{
m_machine->schedule_soft_reset();
- m_machine->debugger().cpu().get_visible_cpu()->debug()->go();
+ m_machine->debugger().console().get_visible_cpu()->debug()->go();
}
}
- if(ImGui::IsKeyPressed(ITEM_ID_F5,false))
+ if(ImGui::IsKeyPressed(ImGuiKey_F5,false))
{
- m_machine->debugger().cpu().get_visible_cpu()->debug()->go();
+ m_machine->debugger().console().get_visible_cpu()->debug()->go();
m_running = true;
}
- if(ImGui::IsKeyPressed(ITEM_ID_F6,false))
+ if(ImGui::IsKeyPressed(ImGuiKey_F6,false))
{
- m_machine->debugger().cpu().get_visible_cpu()->debug()->go_next_device();
+ m_machine->debugger().console().get_visible_cpu()->debug()->go_next_device();
m_running = true;
}
- if(ImGui::IsKeyPressed(ITEM_ID_F7,false))
+ if(ImGui::IsKeyPressed(ImGuiKey_F7,false))
{
- m_machine->debugger().cpu().get_visible_cpu()->debug()->go_interrupt();
+ m_machine->debugger().console().get_visible_cpu()->debug()->go_interrupt();
m_running = true;
}
- if(ImGui::IsKeyPressed(ITEM_ID_F8,false))
- m_machine->debugger().cpu().get_visible_cpu()->debug()->go_vblank();
- if(ImGui::IsKeyPressed(ITEM_ID_F9,false))
- m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step_out();
- if(ImGui::IsKeyPressed(ITEM_ID_F10,false))
- m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step_over();
- if(ImGui::IsKeyPressed(ITEM_ID_F11,false))
- m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step();
- if(ImGui::IsKeyPressed(ITEM_ID_F12,false))
+ if(ImGui::IsKeyPressed(ImGuiKey_F8,false))
+ m_machine->debugger().console().get_visible_cpu()->debug()->go_vblank();
+ if(ImGui::IsKeyPressed(ImGuiKey_F9,false))
+ m_machine->debugger().console().get_visible_cpu()->debug()->single_step_out();
+ if(ImGui::IsKeyPressed(ImGuiKey_F10,false))
+ m_machine->debugger().console().get_visible_cpu()->debug()->single_step_over();
+ if(ImGui::IsKeyPressed(ImGuiKey_F11,false))
+ m_machine->debugger().console().get_visible_cpu()->debug()->single_step();
+ if(ImGui::IsKeyPressed(ImGuiKey_F12,false))
{
- m_machine->debugger().cpu().get_visible_cpu()->debug()->go();
+ m_machine->debugger().console().get_visible_cpu()->debug()->go();
m_hide = true;
}
- if(ImGui::IsKeyPressed(ITEM_ID_D,false) && ImGui::IsKeyDown(ITEM_ID_LCONTROL))
+ if(ImGui::IsKeyPressed(ImGuiKey_D,false) && io.KeyCtrl)
add_disasm(++m_win_count);
- if(ImGui::IsKeyPressed(ITEM_ID_M,false) && ImGui::IsKeyDown(ITEM_ID_LCONTROL))
+ if(ImGui::IsKeyPressed(ImGuiKey_M,false) && io.KeyCtrl)
add_memory(++m_win_count);
- if(ImGui::IsKeyPressed(ITEM_ID_B,false) && ImGui::IsKeyDown(ITEM_ID_LCONTROL))
+ if(ImGui::IsKeyPressed(ImGuiKey_B,false) && io.KeyCtrl)
add_bpoints(++m_win_count);
- if(ImGui::IsKeyPressed(ITEM_ID_W,false) && ImGui::IsKeyDown(ITEM_ID_LCONTROL))
+ if(ImGui::IsKeyPressed(ImGuiKey_W,false) && io.KeyCtrl)
add_wpoints(++m_win_count);
- if(ImGui::IsKeyPressed(ITEM_ID_L,false) && ImGui::IsKeyDown(ITEM_ID_LCONTROL))
+ if(ImGui::IsKeyPressed(ImGuiKey_L,false) && io.KeyCtrl)
add_log(++m_win_count);
}
+void debug_imgui::handle_mouse_views()
+{
+ rectangle rect;
+ bool clicked = false;
+ if(m_mouse_button == true && m_prev_mouse_button == false)
+ clicked = true;
+
+ // check all views, and pass mouse clicks to them
+ if(!m_mouse_button)
+ return;
+ rect.min_x = view_main_disasm->ofs_x;
+ rect.min_y = view_main_disasm->ofs_y;
+ rect.max_x = view_main_disasm->ofs_x + view_main_disasm->view_width;
+ rect.max_y = view_main_disasm->ofs_y + view_main_disasm->view_height;
+ if(rect.contains(m_mouse_x,m_mouse_y) && clicked && view_main_disasm->has_focus)
+ {
+ debug_view_xy topleft = view_main_disasm->view->visible_position();
+ debug_view_xy newpos;
+ newpos.x = topleft.x + (m_mouse_x-view_main_disasm->ofs_x) / m_text_size.x;
+ newpos.y = topleft.y + (m_mouse_y-view_main_disasm->ofs_y) / m_text_size.y;
+ view_main_disasm->view->set_cursor_position(newpos);
+ view_main_disasm->view->set_cursor_visible(true);
+ }
+ for(auto it = view_list.begin();it != view_list.end();++it)
+ {
+ rect.min_x = (*it)->ofs_x;
+ rect.min_y = (*it)->ofs_y;
+ rect.max_x = (*it)->ofs_x + (*it)->view_width;
+ rect.max_y = (*it)->ofs_y + (*it)->view_height;
+ if(rect.contains(m_mouse_x,m_mouse_y) && clicked && (*it)->has_focus)
+ {
+ if((*it)->view->cursor_supported())
+ {
+ debug_view_xy topleft = (*it)->view->visible_position();
+ debug_view_xy newpos;
+ newpos.x = topleft.x + (m_mouse_x-(*it)->ofs_x) / m_text_size.x;
+ newpos.y = topleft.y + (m_mouse_y-(*it)->ofs_y) / m_text_size.y;
+ (*it)->view->set_cursor_position(newpos);
+ (*it)->view->set_cursor_visible(true);
+ }
+ }
+ }
+}
+
void debug_imgui::handle_keys_views()
{
debug_area* focus_view = nullptr;
// find view that has focus (should only be one at a time)
- for(std::vector<debug_area*>::iterator view_ptr = view_list.begin();view_ptr != view_list.end();++view_ptr)
+ for(auto view_ptr = view_list.begin();view_ptr != view_list.end();++view_ptr)
if((*view_ptr)->has_focus)
focus_view = *view_ptr;
// check views in main views also (only the disassembler view accepts inputs)
- if(view_main_disasm->has_focus)
- focus_view = view_main_disasm;
+ if(view_main_disasm != nullptr)
+ if(view_main_disasm->has_focus)
+ focus_view = view_main_disasm;
// if no view has focus, then there's nothing to do
if(focus_view == nullptr)
return;
// pass keypresses to debug view with focus
- if(ImGui::IsKeyPressed(ITEM_ID_UP))
+ if(ImGui::IsKeyPressed(ImGuiKey_UpArrow))
focus_view->view->process_char(DCH_UP);
- if(ImGui::IsKeyPressed(ITEM_ID_DOWN))
+ if(ImGui::IsKeyPressed(ImGuiKey_DownArrow))
focus_view->view->process_char(DCH_DOWN);
- if(ImGui::IsKeyPressed(ITEM_ID_LEFT))
+ if(ImGui::IsKeyPressed(ImGuiKey_LeftArrow))
{
- if(ImGui::IsKeyDown(ITEM_ID_LCONTROL))
+ if(ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
focus_view->view->process_char(DCH_CTRLLEFT);
else
focus_view->view->process_char(DCH_LEFT);
}
- if(ImGui::IsKeyPressed(ITEM_ID_RIGHT))
+ if(ImGui::IsKeyPressed(ImGuiKey_RightArrow))
{
- if(ImGui::IsKeyDown(ITEM_ID_LCONTROL))
+ if(ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
focus_view->view->process_char(DCH_CTRLRIGHT);
else
focus_view->view->process_char(DCH_RIGHT);
}
- if(ImGui::IsKeyPressed(ITEM_ID_PGUP))
+ if(ImGui::IsKeyPressed(ImGuiKey_PageUp))
focus_view->view->process_char(DCH_PUP);
- if(ImGui::IsKeyPressed(ITEM_ID_PGDN))
+ if(ImGui::IsKeyPressed(ImGuiKey_PageDown))
focus_view->view->process_char(DCH_PDOWN);
- if(ImGui::IsKeyPressed(ITEM_ID_HOME))
+ if(ImGui::IsKeyPressed(ImGuiKey_Home))
{
- if(ImGui::IsKeyDown(ITEM_ID_LCONTROL))
+ if(ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
focus_view->view->process_char(DCH_CTRLHOME);
else
focus_view->view->process_char(DCH_HOME);
}
- if(ImGui::IsKeyPressed(ITEM_ID_END))
+ if(ImGui::IsKeyPressed(ImGuiKey_End))
{
- if(ImGui::IsKeyDown(ITEM_ID_LCONTROL))
+ if(ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
focus_view->view->process_char(DCH_CTRLEND);
else
focus_view->view->process_char(DCH_END);
@@ -484,7 +523,7 @@ void debug_imgui::handle_console(running_machine* machine)
// if console input is empty, then do a single step
if(strlen(view_main_console->console_input) == 0)
{
- m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step();
+ m_machine->debugger().console().get_visible_cpu()->debug()->single_step();
view_main_console->exec_cmd = false;
history_pos = view_main_console->console_history.size();
return;
@@ -522,7 +561,7 @@ void debug_imgui::handle_console(running_machine* machine)
// don't bother adding to history if the current command matches the previous one
if(view_main_console->console_prev != view_main_console->console_input)
{
- view_main_console->console_history.push_back(std::string(view_main_console->console_input));
+ view_main_console->console_history.emplace_back(std::string(view_main_console->console_input));
view_main_console->console_prev = view_main_console->console_input;
}
history_pos = view_main_console->console_history.size();
@@ -546,6 +585,8 @@ int debug_imgui::history_set(ImGuiInputTextCallbackData* data)
if(history_pos < view_main_console->console_history.size())
history_pos++;
break;
+ default:
+ break;
}
if(history_pos == view_main_console->console_history.size())
@@ -605,7 +646,10 @@ void debug_imgui::draw_view(debug_area* view_ptr, bool exp_change)
// temporarily set cursor to the last line, this will set the scroll bar range
if(view_ptr->type != DVT_MEMORY) // no scroll bars in memory views
+ {
ImGui::SetCursorPosY((totalsize.y) * fsize.y);
+ ImGui::Dummy(ImVec2(0,0)); // some object is required for validation
+ }
// set the visible area to be displayed
vsize.x = view_ptr->view_width / fsize.x;
@@ -754,13 +798,9 @@ void debug_imgui::add_log(int id)
void debug_imgui::draw_disasm(debug_area* view_ptr, bool* opened)
{
- const debug_view_source* src;
-
ImGui::SetNextWindowSize(ImVec2(view_ptr->width,view_ptr->height + ImGui::GetTextLineHeight()),ImGuiCond_Once);
if(ImGui::Begin(view_ptr->title.c_str(),opened,ImGuiWindowFlags_MenuBar))
{
- int idx;
- bool done = false;
bool exp_change = false;
view_ptr->is_collapsed = false;
@@ -768,7 +808,7 @@ void debug_imgui::draw_disasm(debug_area* view_ptr, bool* opened)
{
if(ImGui::BeginMenu("Options"))
{
- debug_view_disasm* disasm = downcast<debug_view_disasm*>(view_ptr->view);
+ auto* disasm = downcast<debug_view_disasm*>(view_ptr->view);
int rightcol = disasm->right_column();
if(ImGui::MenuItem("Raw opcodes", nullptr,(rightcol == DASM_RIGHTCOL_RAW) ? true : false))
@@ -788,7 +828,7 @@ void debug_imgui::draw_disasm(debug_area* view_ptr, bool* opened)
ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll;
if(m_running)
flags |= ImGuiInputTextFlags_ReadOnly;
- ImGui::Combo("##cpu",&view_ptr->src_sel,get_view_source,view_ptr->view,view_ptr->view->source_list().count());
+ ImGui::Combo("##cpu",&view_ptr->src_sel,get_view_source,view_ptr->view,view_ptr->view->source_count());
ImGui::SameLine();
ImGui::PushItemWidth(-1.0f);
if(ImGui::InputText("##addr",view_ptr->console_input,512,flags))
@@ -800,17 +840,15 @@ void debug_imgui::draw_disasm(debug_area* view_ptr, bool* opened)
ImGui::Separator();
// disassembly portion
- src = view_ptr->view->first_source();
- idx = 0;
- while (!done)
+ unsigned idx = 0;
+ const debug_view_source* src = view_ptr->view->source(idx);
+ do
{
if(view_ptr->src_sel == idx)
view_ptr->view->set_source(*src);
- idx++;
- src = src->next();
- if(src == nullptr)
- done = true;
+ src = view_ptr->view->source(++idx);
}
+ while (src);
ImGui::BeginChild("##disasm_output", ImVec2(ImGui::GetWindowWidth() - 16,ImGui::GetWindowHeight() - ImGui::GetTextLineHeight() - ImGui::GetCursorPosY())); // account for title bar and widgets already drawn
draw_view(view_ptr,exp_change);
@@ -841,13 +879,9 @@ void debug_imgui::add_disasm(int id)
void debug_imgui::draw_memory(debug_area* view_ptr, bool* opened)
{
- const debug_view_source* src;
-
ImGui::SetNextWindowSize(ImVec2(view_ptr->width,view_ptr->height + ImGui::GetTextLineHeight()),ImGuiCond_Once);
if(ImGui::Begin(view_ptr->title.c_str(),opened,ImGuiWindowFlags_MenuBar))
{
- int idx;
- bool done = false;
bool exp_change = false;
view_ptr->is_collapsed = false;
@@ -855,26 +889,42 @@ void debug_imgui::draw_memory(debug_area* view_ptr, bool* opened)
{
if(ImGui::BeginMenu("Options"))
{
- debug_view_memory* mem = downcast<debug_view_memory*>(view_ptr->view);
+ auto* mem = downcast<debug_view_memory*>(view_ptr->view);
bool physical = mem->physical();
bool rev = mem->reverse();
- int format = mem->get_data_format();
+ debug_view_memory::data_format format = mem->get_data_format();
uint32_t chunks = mem->chunks_per_row();
-
- if(ImGui::MenuItem("1-byte chunks", nullptr,(format == 1) ? true : false))
- mem->set_data_format(1);
- if(ImGui::MenuItem("2-byte chunks", nullptr,(format == 2) ? true : false))
- mem->set_data_format(2);
- if(ImGui::MenuItem("4-byte chunks", nullptr,(format == 4) ? true : false))
- mem->set_data_format(4);
- if(ImGui::MenuItem("8-byte chunks", nullptr,(format == 8) ? true : false))
- mem->set_data_format(8);
- if(ImGui::MenuItem("32-bit floating point", nullptr,(format == 9) ? true : false))
- mem->set_data_format(9);
- if(ImGui::MenuItem("64-bit floating point", nullptr,(format == 10) ? true : false))
- mem->set_data_format(10);
- if(ImGui::MenuItem("80-bit floating point", nullptr,(format == 11) ? true : false))
- mem->set_data_format(11);
+ int radix = mem->address_radix();
+
+ if(ImGui::MenuItem("1-byte hexadecimal", nullptr,(format == debug_view_memory::data_format::HEX_8BIT) ? true : false))
+ mem->set_data_format(debug_view_memory::data_format::HEX_8BIT);
+ if(ImGui::MenuItem("2-byte hexadecimal", nullptr,(format == debug_view_memory::data_format::HEX_16BIT) ? true : false))
+ mem->set_data_format(debug_view_memory::data_format::HEX_16BIT);
+ if(ImGui::MenuItem("4-byte hexadecimal", nullptr,(format == debug_view_memory::data_format::HEX_32BIT) ? true : false))
+ mem->set_data_format(debug_view_memory::data_format::HEX_32BIT);
+ if(ImGui::MenuItem("8-byte hexadecimal", nullptr,(format == debug_view_memory::data_format::HEX_64BIT) ? true : false))
+ mem->set_data_format(debug_view_memory::data_format::HEX_64BIT);
+ if(ImGui::MenuItem("1-byte octal", nullptr,(format == debug_view_memory::data_format::OCTAL_8BIT) ? true : false))
+ mem->set_data_format(debug_view_memory::data_format::OCTAL_8BIT);
+ if(ImGui::MenuItem("2-byte octal", nullptr,(format == debug_view_memory::data_format::OCTAL_16BIT) ? true : false))
+ mem->set_data_format(debug_view_memory::data_format::OCTAL_16BIT);
+ if(ImGui::MenuItem("4-byte octal", nullptr,(format == debug_view_memory::data_format::OCTAL_32BIT) ? true : false))
+ mem->set_data_format(debug_view_memory::data_format::OCTAL_32BIT);
+ if(ImGui::MenuItem("8-byte octal", nullptr,(format == debug_view_memory::data_format::OCTAL_64BIT) ? true : false))
+ mem->set_data_format(debug_view_memory::data_format::OCTAL_64BIT);
+ if(ImGui::MenuItem("32-bit floating point", nullptr,(format == debug_view_memory::data_format::FLOAT_32BIT) ? true : false))
+ mem->set_data_format(debug_view_memory::data_format::FLOAT_32BIT);
+ if(ImGui::MenuItem("64-bit floating point", nullptr,(format == debug_view_memory::data_format::FLOAT_64BIT) ? true : false))
+ mem->set_data_format(debug_view_memory::data_format::FLOAT_64BIT);
+ if(ImGui::MenuItem("80-bit floating point", nullptr,(format == debug_view_memory::data_format::FLOAT_80BIT) ? true : false))
+ mem->set_data_format(debug_view_memory::data_format::FLOAT_80BIT);
+ ImGui::Separator();
+ if(ImGui::MenuItem("Hexadecimal Addresses", nullptr,(radix == 16)))
+ mem->set_address_radix(16);
+ if(ImGui::MenuItem("Decimal Addresses", nullptr,(radix == 10)))
+ mem->set_address_radix(10);
+ if(ImGui::MenuItem("Octal Addresses", nullptr,(radix == 8)))
+ mem->set_address_radix(8);
ImGui::Separator();
if(ImGui::MenuItem("Logical addresses", nullptr,!physical))
mem->set_physical(false);
@@ -906,22 +956,20 @@ void debug_imgui::draw_memory(debug_area* view_ptr, bool* opened)
ImGui::PopItemWidth();
ImGui::SameLine();
ImGui::PushItemWidth(-1.0f);
- ImGui::Combo("##region",&view_ptr->src_sel,get_view_source,view_ptr->view,view_ptr->view->source_list().count());
+ ImGui::Combo("##region",&view_ptr->src_sel,get_view_source,view_ptr->view,view_ptr->view->source_count());
ImGui::PopItemWidth();
ImGui::Separator();
// memory editor portion
- src = view_ptr->view->first_source();
- idx = 0;
- while (!done)
+ unsigned idx = 0;
+ const debug_view_source* src = view_ptr->view->source(idx);
+ do
{
if(view_ptr->src_sel == idx)
view_ptr->view->set_source(*src);
- idx++;
- src = src->next();
- if(src == nullptr)
- done = true;
+ src = view_ptr->view->source(++idx);
}
+ while (src);
ImGui::BeginChild("##memory_output", ImVec2(ImGui::GetWindowWidth() - 16,ImGui::GetWindowHeight() - ImGui::GetTextLineHeight() - ImGui::GetCursorPosY())); // account for title bar and widgets already drawn
draw_view(view_ptr,exp_change);
@@ -954,24 +1002,25 @@ void debug_imgui::mount_image()
{
if(m_selected_file != nullptr)
{
- osd_file::error err;
+ std::error_condition err;
switch(m_selected_file->type)
{
case file_entry_type::DRIVE:
case file_entry_type::DIRECTORY:
{
util::zippath_directory::ptr dir;
- err = util::zippath_directory::open(m_selected_file->fullpath.c_str(), dir);
+ err = util::zippath_directory::open(m_selected_file->fullpath, dir);
}
- if(err == osd_file::error::NONE)
+ if(!err)
{
m_filelist_refresh = true;
strcpy(m_path,m_selected_file->fullpath.c_str());
}
break;
case file_entry_type::FILE:
- m_dialog_image->load(m_selected_file->fullpath.c_str());
+ m_dialog_image->load(m_selected_file->fullpath);
ImGui::CloseCurrentPopup();
+ m_mount_open = false;
break;
}
}
@@ -979,18 +1028,18 @@ void debug_imgui::mount_image()
void debug_imgui::create_image()
{
- image_init_result res;
+ std::pair<std::error_condition, std::string> res;
- if(m_dialog_image->image_type() == IO_FLOPPY)
+ auto *fd = dynamic_cast<floppy_image_device *>(m_dialog_image);
+ if(fd != nullptr)
{
- floppy_image_device *fd = static_cast<floppy_image_device *>(m_dialog_image);
res = fd->create(m_path,nullptr,nullptr);
- if(res == image_init_result::PASS)
+ if(!res.first)
fd->setup_write(m_typelist.at(m_format_sel).format);
}
else
res = m_dialog_image->create(m_path,nullptr,nullptr);
- if(res == image_init_result::PASS)
+ if(!res.first)
ImGui::CloseCurrentPopup();
// TODO: add a messagebox to display on an error
}
@@ -1004,32 +1053,29 @@ void debug_imgui::refresh_filelist()
m_filelist_refresh = false;
util::zippath_directory::ptr dir;
- osd_file::error const err = util::zippath_directory::open(m_path,dir);
- if(err == osd_file::error::NONE)
+ std::error_condition const err = util::zippath_directory::open(m_path,dir);
+ if(!err)
{
- int x = 0;
// add drives
- const char *volume_name;
- while((volume_name = osd_get_volume_name(x))!=nullptr)
+ for(std::string const &volume_name : osd_get_volume_names())
{
file_entry temp;
temp.type = file_entry_type::DRIVE;
- temp.basename = std::string(volume_name);
- temp.fullpath = std::string(volume_name);
+ temp.basename = volume_name;
+ temp.fullpath = volume_name;
m_filelist.emplace_back(std::move(temp));
- x++;
}
first = m_filelist.size();
- const osd::directory::entry *dirent;
+ const directory::entry *dirent;
while((dirent = dir->readdir()) != nullptr)
{
file_entry temp;
switch(dirent->type)
{
- case osd::directory::entry::entry_type::FILE:
+ case directory::entry::entry_type::FILE:
temp.type = file_entry_type::FILE;
break;
- case osd::directory::entry::entry_type::DIR:
+ case directory::entry::entry_type::DIR:
temp.type = file_entry_type::DIRECTORY;
break;
default:
@@ -1048,7 +1094,7 @@ void debug_imgui::refresh_filelist()
void debug_imgui::refresh_typelist()
{
- floppy_image_device *fd = static_cast<floppy_image_device *>(m_dialog_image);
+ auto *fd = static_cast<floppy_image_device *>(m_dialog_image);
m_typelist.clear();
if(m_dialog_image->formatlist().empty())
@@ -1056,8 +1102,7 @@ void debug_imgui::refresh_typelist()
if(fd == nullptr)
return;
- floppy_image_format_t* format_list = fd->get_formats();
- for(floppy_image_format_t* flist = format_list; flist; flist = flist->next)
+ for(const floppy_image_format_t* flist : fd->get_formats())
{
if(flist->supports_save())
{
@@ -1075,7 +1120,7 @@ void debug_imgui::draw_images_menu()
if(ImGui::BeginMenu("Images"))
{
int x = 0;
- for (device_image_interface &img : image_interface_iterator(m_machine->root_device()))
+ for (device_image_interface &img : image_interface_enumerator(m_machine->root_device()))
{
x++;
std::string str = string_format(" %s : %s##%i",img.device().name(),img.exists() ? img.filename() : "[Empty slot]",x);
@@ -1118,16 +1163,21 @@ void debug_imgui::draw_mount_dialog(const char* label)
{
// render dialog
//ImGui::SetNextWindowContentWidth(200.0f);
- if(ImGui::BeginPopupModal(label,NULL,ImGuiWindowFlags_AlwaysAutoResize))
+ if(ImGui::BeginPopupModal(label,nullptr,ImGuiWindowFlags_AlwaysAutoResize))
{
if(m_filelist_refresh)
refresh_filelist();
if(ImGui::InputText("##mountpath",m_path,1024,ImGuiInputTextFlags_EnterReturnsTrue))
m_filelist_refresh = true;
ImGui::Separator();
+
+ ImVec2 listbox_size;
+ listbox_size.x = 0.0f;
+ listbox_size.y = ImGui::GetTextLineHeightWithSpacing() * 15.25f;
+
+ if(ImGui::BeginListBox("##filelist",listbox_size))
{
- ImGui::ListBoxHeader("##filelist",m_filelist.size(),15);
- for(std::vector<file_entry>::iterator f = m_filelist.begin();f != m_filelist.end();++f)
+ for(auto f = m_filelist.begin();f != m_filelist.end();++f)
{
std::string txt_name;
bool sel = false;
@@ -1150,14 +1200,19 @@ void debug_imgui::draw_mount_dialog(const char* label)
{
m_selected_file = &(*f);
if(ImGui::IsMouseDoubleClicked(0))
+ {
mount_image();
+ }
}
}
- ImGui::ListBoxFooter();
+ ImGui::EndListBox();
}
ImGui::Separator();
if(ImGui::Button("Cancel##mount"))
+ {
ImGui::CloseCurrentPopup();
+ m_mount_open = false;
+ }
ImGui::SameLine();
if(ImGui::Button("OK##mount"))
mount_image();
@@ -1169,27 +1224,28 @@ void debug_imgui::draw_create_dialog(const char* label)
{
// render dialog
//ImGui::SetNextWindowContentWidth(200.0f);
- if(ImGui::BeginPopupModal(label,NULL,ImGuiWindowFlags_AlwaysAutoResize))
+ if(ImGui::BeginPopupModal(label,nullptr,ImGuiWindowFlags_AlwaysAutoResize))
{
ImGui::LabelText("##static1","Filename:");
ImGui::SameLine();
if(ImGui::InputText("##createfilename",m_path,1024,ImGuiInputTextFlags_EnterReturnsTrue))
{
auto entry = osd_stat(m_path);
- auto file_type = (entry != nullptr) ? entry->type : osd::directory::entry::entry_type::NONE;
- if(file_type == osd::directory::entry::entry_type::NONE)
+ auto file_type = (entry != nullptr) ? entry->type : directory::entry::entry_type::NONE;
+ if(file_type == directory::entry::entry_type::NONE)
create_image();
- if(file_type == osd::directory::entry::entry_type::FILE)
+ if(file_type == directory::entry::entry_type::FILE)
m_create_confirm_wait = true;
// cannot overwrite a directory, so nothing will be none in that case.
}
// format combo box for floppy devices
- if(m_dialog_image->image_type() == IO_FLOPPY)
+ auto *fd = dynamic_cast<floppy_image_device *>(m_dialog_image);
+ if(fd != nullptr)
{
std::string combo_str;
combo_str.clear();
- for(std::vector<image_type_entry>::iterator f = m_typelist.begin();f != m_typelist.end();++f)
+ for(auto f = m_typelist.begin();f != m_typelist.end();++f)
{
// TODO: perhaps do this at the time the format list is generated, rather than every frame
combo_str.append((*f).longname);
@@ -1217,17 +1273,21 @@ void debug_imgui::draw_create_dialog(const char* label)
{
ImGui::Separator();
if(ImGui::Button("Cancel##mount"))
+ {
ImGui::CloseCurrentPopup();
+ m_create_open = false;
+ }
ImGui::SameLine();
if(ImGui::Button("OK##mount"))
{
auto entry = osd_stat(m_path);
- auto file_type = (entry != nullptr) ? entry->type : osd::directory::entry::entry_type::NONE;
- if(file_type == osd::directory::entry::entry_type::NONE)
+ auto file_type = (entry != nullptr) ? entry->type : directory::entry::entry_type::NONE;
+ if(file_type == directory::entry::entry_type::NONE)
create_image();
- if(file_type == osd::directory::entry::entry_type::FILE)
+ if(file_type == directory::entry::entry_type::FILE)
m_create_confirm_wait = true;
// cannot overwrite a directory, so nothing will be none in that case.
+ m_create_open = false;
}
}
ImGui::EndPopup();
@@ -1237,6 +1297,10 @@ void debug_imgui::draw_create_dialog(const char* label)
void debug_imgui::draw_console()
{
ImGuiWindowFlags flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse;
+ bool show_menu = false;
+
+ if(view_main_disasm == nullptr || view_main_regs == nullptr || view_main_console == nullptr)
+ return;
ImGui::SetNextWindowSize(ImVec2(view_main_regs->width + view_main_disasm->width,view_main_disasm->height + view_main_console->height + ImGui::GetTextLineHeight()*3),ImGuiCond_Once);
if(ImGui::Begin(view_main_console->title.c_str(), nullptr,flags))
@@ -1247,6 +1311,7 @@ void debug_imgui::draw_console()
{
if(ImGui::BeginMenu("Debug"))
{
+ show_menu = true;
if(ImGui::MenuItem("New disassembly window", "Ctrl+D"))
add_disasm(++m_win_count);
if(ImGui::MenuItem("New memory window", "Ctrl+M"))
@@ -1260,46 +1325,47 @@ void debug_imgui::draw_console()
ImGui::Separator();
if(ImGui::MenuItem("Run", "F5"))
{
- m_machine->debugger().cpu().get_visible_cpu()->debug()->go();
+ m_machine->debugger().console().get_visible_cpu()->debug()->go();
m_running = true;
}
if(ImGui::MenuItem("Go to next CPU", "F6"))
{
- m_machine->debugger().cpu().get_visible_cpu()->debug()->go_next_device();
+ m_machine->debugger().console().get_visible_cpu()->debug()->go_next_device();
m_running = true;
}
if(ImGui::MenuItem("Run until next interrupt", "F7"))
{
- m_machine->debugger().cpu().get_visible_cpu()->debug()->go_interrupt();
+ m_machine->debugger().console().get_visible_cpu()->debug()->go_interrupt();
m_running = true;
}
if(ImGui::MenuItem("Run until VBLANK", "F8"))
- m_machine->debugger().cpu().get_visible_cpu()->debug()->go_vblank();
+ m_machine->debugger().console().get_visible_cpu()->debug()->go_vblank();
if(ImGui::MenuItem("Run and hide debugger", "F12"))
{
- m_machine->debugger().cpu().get_visible_cpu()->debug()->go();
+ m_machine->debugger().console().get_visible_cpu()->debug()->go();
m_hide = true;
}
ImGui::Separator();
if(ImGui::MenuItem("Single step", "F11"))
- m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step();
+ m_machine->debugger().console().get_visible_cpu()->debug()->single_step();
if(ImGui::MenuItem("Step over", "F10"))
- m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step_over();
+ m_machine->debugger().console().get_visible_cpu()->debug()->single_step_over();
if(ImGui::MenuItem("Step out", "F9"))
- m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step_out();
+ m_machine->debugger().console().get_visible_cpu()->debug()->single_step_out();
ImGui::EndMenu();
}
if(ImGui::BeginMenu("Window"))
{
+ show_menu = true;
if(ImGui::MenuItem("Show all"))
{
- for(std::vector<debug_area*>::iterator view_ptr = view_list.begin();view_ptr != view_list.end();++view_ptr)
+ for(auto view_ptr = view_list.begin();view_ptr != view_list.end();++view_ptr)
ImGui::SetWindowCollapsed((*view_ptr)->title.c_str(),false);
}
ImGui::Separator();
// list all extra windows, so we can un-collapse the windows if necessary
- for(std::vector<debug_area*>::iterator view_ptr = view_list.begin();view_ptr != view_list.end();++view_ptr)
+ for(auto view_ptr = view_list.begin();view_ptr != view_list.end();++view_ptr)
{
bool collapsed = false;
if((*view_ptr)->is_collapsed)
@@ -1310,7 +1376,10 @@ void debug_imgui::draw_console()
ImGui::EndMenu();
}
if(m_has_images)
+ {
+ show_menu = true;
draw_images_menu();
+ }
ImGui::EndMenuBar();
}
@@ -1341,20 +1410,18 @@ void debug_imgui::draw_console()
ImGui::PushItemWidth(-1.0f);
if(ImGui::InputText("##console_input",view_main_console->console_input,512,flags,history_set))
view_main_console->exec_cmd = true;
- if ((ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) && !ImGui::IsAnyItemActive() && !ImGui::IsMouseClicked(0)))
+ if ((ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) && !ImGui::IsAnyItemActive() && !ImGui::IsMouseClicked(0) && !show_menu))
ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
if(m_mount_open)
{
ImGui::OpenPopup("Mount Image");
- m_mount_open = false;
+ draw_mount_dialog("Mount Image"); // draw mount image dialog if open
}
if(m_create_open)
{
ImGui::OpenPopup("Create Image");
- m_create_open = false;
+ draw_create_dialog("Create Image"); // draw create image dialog if open
}
- draw_mount_dialog("Mount Image"); // draw mount image dialog if open
- draw_create_dialog("Create Image"); // draw create image dialog if open
ImGui::PopItemWidth();
ImGui::EndChild();
ImGui::End();
@@ -1367,7 +1434,6 @@ void debug_imgui::update()
//debug_area* view_ptr = view_list;
std::vector<debug_area*>::iterator view_ptr;
bool opened;
- int count = 0;
ImGui::PushStyleColor(ImGuiCol_WindowBg,ImVec4(1.0f,1.0f,1.0f,0.9f));
ImGui::PushStyleColor(ImGuiCol_Text,ImVec4(0.0f,0.0f,0.0f,1.0f));
ImGui::PushStyleColor(ImGuiCol_TextDisabled,ImVec4(0.0f,0.0f,1.0f,1.0f));
@@ -1412,13 +1478,12 @@ void debug_imgui::update()
break;
}
++view_ptr;
- count++;
}
// check for a closed window
if(to_delete != nullptr)
{
view_list_remove(to_delete);
- global_free(to_delete);
+ delete to_delete;
}
ImGui::PopStyleColor(12);
@@ -1433,31 +1498,44 @@ void debug_imgui::init_debugger(running_machine &machine)
fatalerror("Error: ImGui debugger requires the BGFX renderer.\n");
// check for any image devices (cassette, floppy, etc...)
- image_interface_iterator iter(m_machine->root_device());
+ image_interface_enumerator iter(m_machine->root_device());
if (iter.first() != nullptr)
m_has_images = true;
// map keys to ImGui inputs
- io.KeyMap[ImGuiKey_A] = ITEM_ID_A;
- io.KeyMap[ImGuiKey_C] = ITEM_ID_C;
- io.KeyMap[ImGuiKey_V] = ITEM_ID_V;
- io.KeyMap[ImGuiKey_X] = ITEM_ID_X;
- io.KeyMap[ImGuiKey_C] = ITEM_ID_C;
- io.KeyMap[ImGuiKey_Y] = ITEM_ID_Y;
- io.KeyMap[ImGuiKey_Z] = ITEM_ID_Z;
- io.KeyMap[ImGuiKey_Backspace] = ITEM_ID_BACKSPACE;
- io.KeyMap[ImGuiKey_Delete] = ITEM_ID_DEL;
- io.KeyMap[ImGuiKey_Tab] = ITEM_ID_TAB;
- io.KeyMap[ImGuiKey_PageUp] = ITEM_ID_PGUP;
- io.KeyMap[ImGuiKey_PageDown] = ITEM_ID_PGDN;
- io.KeyMap[ImGuiKey_Home] = ITEM_ID_HOME;
- io.KeyMap[ImGuiKey_End] = ITEM_ID_END;
- io.KeyMap[ImGuiKey_Escape] = ITEM_ID_ESC;
- io.KeyMap[ImGuiKey_Enter] = ITEM_ID_ENTER;
- io.KeyMap[ImGuiKey_LeftArrow] = ITEM_ID_LEFT;
- io.KeyMap[ImGuiKey_RightArrow] = ITEM_ID_RIGHT;
- io.KeyMap[ImGuiKey_UpArrow] = ITEM_ID_UP;
- io.KeyMap[ImGuiKey_DownArrow] = ITEM_ID_DOWN;
+ m_mapping[ITEM_ID_A] = ImGuiKey_A;
+ m_mapping[ITEM_ID_C] = ImGuiKey_C;
+ m_mapping[ITEM_ID_V] = ImGuiKey_V;
+ m_mapping[ITEM_ID_X] = ImGuiKey_X;
+ m_mapping[ITEM_ID_Y] = ImGuiKey_Y;
+ m_mapping[ITEM_ID_Z] = ImGuiKey_Z;
+ m_mapping[ITEM_ID_D] = ImGuiKey_D;
+ m_mapping[ITEM_ID_M] = ImGuiKey_M;
+ m_mapping[ITEM_ID_B] = ImGuiKey_B;
+ m_mapping[ITEM_ID_W] = ImGuiKey_W;
+ m_mapping[ITEM_ID_L] = ImGuiKey_L;
+ m_mapping[ITEM_ID_BACKSPACE] = ImGuiKey_Backspace;
+ m_mapping[ITEM_ID_DEL] = ImGuiKey_Delete;
+ m_mapping[ITEM_ID_TAB] = ImGuiKey_Tab;
+ m_mapping[ITEM_ID_PGUP] = ImGuiKey_PageUp;
+ m_mapping[ITEM_ID_PGDN] = ImGuiKey_PageDown;
+ m_mapping[ITEM_ID_HOME] = ImGuiKey_Home;
+ m_mapping[ITEM_ID_END] = ImGuiKey_End;
+ m_mapping[ITEM_ID_ESC] = ImGuiKey_Escape;
+ m_mapping[ITEM_ID_ENTER] = ImGuiKey_Enter;
+ m_mapping[ITEM_ID_LEFT] = ImGuiKey_LeftArrow;
+ m_mapping[ITEM_ID_RIGHT] = ImGuiKey_RightArrow;
+ m_mapping[ITEM_ID_UP] = ImGuiKey_UpArrow;
+ m_mapping[ITEM_ID_DOWN] = ImGuiKey_DownArrow;
+ m_mapping[ITEM_ID_F3] = ImGuiKey_F3;
+ m_mapping[ITEM_ID_F5] = ImGuiKey_F5;
+ m_mapping[ITEM_ID_F6] = ImGuiKey_F6;
+ m_mapping[ITEM_ID_F7] = ImGuiKey_F7;
+ m_mapping[ITEM_ID_F8] = ImGuiKey_F8;
+ m_mapping[ITEM_ID_F9] = ImGuiKey_F9;
+ m_mapping[ITEM_ID_F10] = ImGuiKey_F10;
+ m_mapping[ITEM_ID_F11] = ImGuiKey_F11;
+ m_mapping[ITEM_ID_F12] = ImGuiKey_F12;
// set key delay and repeat rates
io.KeyRepeatDelay = 0.400f;
@@ -1503,38 +1581,68 @@ void debug_imgui::wait_for_debugger(device_t &device, bool firststop)
}
if(firststop)
{
-// debug_show_all();
- device.machine().ui_input().reset();
+ //debug_show_all();
m_running = false;
}
+ if(!m_take_ui)
+ {
+ if (!m_machine->ui().set_ui_event_handler([this] () { return m_take_ui; }))
+ {
+ // can't break if we can't take over UI input
+ m_machine->debugger().console().get_visible_cpu()->debug()->go();
+ m_running = true;
+ return;
+ }
+ m_take_ui = true;
+
+ }
m_hide = false;
-// m_machine->ui_input().frame_update();
- handle_mouse();
- handle_keys();
+ m_machine->osd().input_update(false);
+ handle_events();
handle_console(m_machine);
update_cpu_view(&device);
- imguiBeginFrame(m_mouse_x,m_mouse_y,m_mouse_button ? IMGUI_MBUT_LEFT : 0, 0, width, height,m_key_char);
- update();
- imguiEndFrame();
+ imguiBeginFrame(m_mouse_x, m_mouse_y, m_mouse_button ? IMGUI_MBUT_LEFT : 0, 0, width, height,m_key_char);
handle_mouse_views();
handle_keys_views();
- m_machine->ui_input().reset(); // clear remaining inputs, so they don't fall through to the UI
+ update();
+ imguiEndFrame();
device.machine().osd().update(false);
+ osd_sleep(osd_ticks_per_second() / 1000 * 50);
}
void debug_imgui::debugger_update()
{
- if (m_machine && (m_machine->phase() == machine_phase::RUNNING) && !m_machine->debugger().cpu().is_stopped() && !m_hide)
+ if(!view_main_disasm || !view_main_regs || !view_main_console || !m_machine || (m_machine->phase() != machine_phase::RUNNING))
+ return;
+
+ if(!m_machine->debugger().cpu().is_stopped())
{
- uint32_t width = m_machine->render().ui_target().width();
- uint32_t height = m_machine->render().ui_target().height();
- handle_mouse();
- handle_keys();
- imguiBeginFrame(m_mouse_x,m_mouse_y,m_mouse_button ? IMGUI_MBUT_LEFT : 0, 0, width, height, m_key_char);
- update();
- imguiEndFrame();
+ if(m_take_ui)
+ {
+ m_take_ui = false;
+ m_current_pointer = -1;
+ m_prev_mouse_button = m_mouse_button;
+ if(m_mouse_button)
+ {
+ m_mouse_button = false;
+ ImGuiIO& io = ImGui::GetIO();
+ io.MouseDown[0] = false;
+ }
+ }
+ if(!m_hide)
+ {
+ uint32_t width = m_machine->render().ui_target().width();
+ uint32_t height = m_machine->render().ui_target().height();
+ imguiBeginFrame(m_mouse_x, m_mouse_y, 0, 0, width, height, m_key_char);
+ update();
+ imguiEndFrame();
+ }
}
}
-MODULE_DEFINITION(DEBUG_IMGUI, debug_imgui)
+} // anonymous namespace
+
+} // namespace osd
+
+MODULE_DEFINITION(DEBUG_IMGUI, osd::debug_imgui)
diff --git a/src/osd/modules/debugger/debugosx.mm b/src/osd/modules/debugger/debugosx.mm
index def790ef939..a4721e4d292 100644
--- a/src/osd/modules/debugger/debugosx.mm
+++ b/src/osd/modules/debugger/debugosx.mm
@@ -24,11 +24,6 @@
// MAMEOS headers
#include "modules/lib/osdobj_common.h"
#include "osx/debugosx.h"
-#ifdef OSD_MAC
-#include "osdmac.h"
-#else
-#include "osdsdl.h"
-#endif
#include "debug_module.h"
#import "osx/debugconsole.h"
@@ -61,17 +56,17 @@ public:
[m_console release];
}
- virtual int init(const osd_options &options);
- virtual void exit();
+ virtual int init(osd_interface &osd, const osd_options &options) override;
+ virtual void exit() override;
- virtual void init_debugger(running_machine &machine);
- virtual void wait_for_debugger(device_t &device, bool firststop);
- virtual void debugger_update();
+ virtual void init_debugger(running_machine &machine) override;
+ virtual void wait_for_debugger(device_t &device, bool firststop) override;
+ virtual void debugger_update() override;
private:
void create_console();
void build_menus();
- void config_load(config_type cfgtype, util::xml::data_node const *parentnode);
+ void config_load(config_type cfgtype, config_level cfglevel, util::xml::data_node const *parentnode);
void config_save(config_type cfgtype, util::xml::data_node *parentnode);
running_machine *m_machine;
@@ -91,7 +86,7 @@ std::atomic_bool debugger_osx::s_added_menus(false);
// initialise debugger module
//============================================================
-int debugger_osx::init(const osd_options &options)
+int debugger_osx::init(osd_interface &osd, const osd_options &options)
{
return 0;
}
@@ -129,8 +124,8 @@ void debugger_osx::init_debugger(running_machine &machine)
m_machine = &machine;
machine.configuration().config_register(
"debugger",
- config_load_delegate(&debugger_osx::config_load, this),
- config_save_delegate(&debugger_osx::config_save, this));
+ configuration_manager::load_delegate(&debugger_osx::config_load, this),
+ configuration_manager::save_delegate(&debugger_osx::config_save, this));
}
@@ -165,7 +160,7 @@ void debugger_osx::wait_for_debugger(device_t &device, bool firststop)
}
// get and process messages
- NSEvent *ev = [NSApp nextEventMatchingMask:NSAnyEventMask
+ NSEvent *ev = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:[NSDate distantFuture]
inMode:NSDefaultRunLoopMode
dequeue:YES];
@@ -211,7 +206,7 @@ void debugger_osx::build_menus()
{
NSMenuItem *item;
- NSMenu *const debugMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Debug"];
+ NSMenu *const debugMenu = [[NSMenu alloc] initWithTitle:@"Debug"];
item = [[NSApp mainMenu] insertItemWithTitle:@"Debug" action:NULL keyEquivalent:@"" atIndex:1];
[item setSubmenu:debugMenu];
[debugMenu release];
@@ -241,9 +236,9 @@ void debugger_osx::build_menus()
[[debugMenu addItemWithTitle:@"Hard Reset"
action:@selector(debugHardReset:)
keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF3FunctionKey]]
- setKeyEquivalentModifierMask:NSShiftKeyMask];
+ setKeyEquivalentModifierMask:NSEventModifierFlagShift];
- NSMenu *const runMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Run"];
+ NSMenu *const runMenu = [[NSMenu alloc] initWithTitle:@"Run"];
item = [[NSApp mainMenu] insertItemWithTitle:@"Run"
action:NULL
keyEquivalent:@""
@@ -295,7 +290,7 @@ void debugger_osx::build_menus()
[[runMenu addItemWithTitle:@"Step Out"
action:@selector(debugStepOut:)
keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF10FunctionKey]]
- setKeyEquivalentModifierMask:NSShiftKeyMask];
+ setKeyEquivalentModifierMask:NSEventModifierFlagShift];
}
}
@@ -305,9 +300,9 @@ void debugger_osx::build_menus()
// restore state based on configuration XML
//============================================================
-void debugger_osx::config_load(config_type cfgtype, util::xml::data_node const *parentnode)
+void debugger_osx::config_load(config_type cfgtype, config_level cfglevel, util::xml::data_node const *parentnode)
{
- if ((config_type::GAME == cfgtype) && parentnode)
+ if ((config_type::SYSTEM == cfgtype) && parentnode)
{
if (m_console)
{
@@ -331,7 +326,7 @@ void debugger_osx::config_load(config_type cfgtype, util::xml::data_node const *
void debugger_osx::config_save(config_type cfgtype, util::xml::data_node *parentnode)
{
- if ((config_type::GAME == cfgtype) && m_console)
+ if ((config_type::SYSTEM == cfgtype) && m_console)
{
NSAutoreleasePool *const pool = [[NSAutoreleasePool alloc] init];
NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:[NSValue valueWithPointer:m_machine],
diff --git a/src/osd/modules/debugger/debugqt.cpp b/src/osd/modules/debugger/debugqt.cpp
index 9156fd31c16..aeae07324e4 100644
--- a/src/osd/modules/debugger/debugqt.cpp
+++ b/src/osd/modules/debugger/debugqt.cpp
@@ -32,250 +32,102 @@
#include "qt/deviceswindow.h"
#include "qt/deviceinformationwindow.h"
-class debug_qt : public osd_module, public debug_module
-#if defined(WIN32) && !defined(SDLMAME_WIN32)
-, public QAbstractNativeEventFilter
-#endif
-{
-public:
- debug_qt()
- : osd_module(OSD_DEBUG_PROVIDER, "qt"), debug_module(),
- m_machine(nullptr)
- {
- }
-
- virtual ~debug_qt() { }
+#include "util/xmlfile.h"
- virtual int init(const osd_options &options) { return 0; }
- virtual void exit() { }
- virtual void init_debugger(running_machine &machine);
- virtual void wait_for_debugger(device_t &device, bool firststop);
- virtual void debugger_update();
-#if defined(WIN32) && !defined(SDLMAME_WIN32)
- virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *) Q_DECL_OVERRIDE;
+#if defined(SDLMAME_UNIX) || defined(SDLMAME_WIN32)
+extern int sdl_entered_debugger;
+#elif defined(_WIN32)
+void winwindow_update_cursor_state(running_machine &machine);
+bool winwindow_qt_filter(void *message);
#endif
-private:
- running_machine *m_machine;
-};
-
-
-namespace {
-//============================================================
-// "Global" variables to make QT happy
-//============================================================
-
-int qtArgc = 1;
-char qtArg0[] = "mame";
-char *qtArgv[] = { qtArg0, nullptr };
-
-bool oneShot = true;
-MainWindow *mainQtWindow = nullptr;
-
-//============================================================
-// XML configuration save/load
-//============================================================
-// Global variable used to feed the xml configuration callbacks
-std::vector<WindowQtConfig*> xmlConfigurations;
+namespace osd {
+namespace {
- void xml_configuration_load(running_machine &machine, config_type cfg_type, util::xml::data_node const *parentnode)
+class debug_qt : public osd_module, public debug_module, protected debugger::qt::DebuggerQt
+#if defined(_WIN32) && !defined(SDLMAME_WIN32)
+, public QAbstractNativeEventFilter
+#endif
{
- // We only care about game files
- if (cfg_type != config_type::GAME)
- return;
-
- // Might not have any data
- if (parentnode == nullptr)
- return;
-
- for (int i = 0; i < xmlConfigurations.size(); i++)
- delete xmlConfigurations[i];
- xmlConfigurations.clear();
-
- // Configuration load
- util::xml::data_node const * wnode = nullptr;
- for (wnode = parentnode->get_child("window"); wnode != nullptr; wnode = wnode->get_next_sibling("window"))
+public:
+ debug_qt() :
+ osd_module(OSD_DEBUG_PROVIDER, "qt"),
+ debug_module(),
+ m_machine(nullptr),
+ m_mainwindow(nullptr)
{
- WindowQtConfig::WindowType type = (WindowQtConfig::WindowType)wnode->get_attribute_int("type", WindowQtConfig::WIN_TYPE_UNKNOWN);
- switch (type)
- {
- case WindowQtConfig::WIN_TYPE_MAIN: xmlConfigurations.push_back(new MainWindowQtConfig()); break;
- case WindowQtConfig::WIN_TYPE_MEMORY: xmlConfigurations.push_back(new MemoryWindowQtConfig()); break;
- case WindowQtConfig::WIN_TYPE_DASM: xmlConfigurations.push_back(new DasmWindowQtConfig()); break;
- case WindowQtConfig::WIN_TYPE_LOG: xmlConfigurations.push_back(new LogWindowQtConfig()); break;
- case WindowQtConfig::WIN_TYPE_BREAK_POINTS: xmlConfigurations.push_back(new BreakpointsWindowQtConfig()); break;
- case WindowQtConfig::WIN_TYPE_DEVICES: xmlConfigurations.push_back(new DevicesWindowQtConfig()); break;
- case WindowQtConfig::WIN_TYPE_DEVICE_INFORMATION: xmlConfigurations.push_back(new DeviceInformationWindowQtConfig()); break;
- default: continue;
- }
- xmlConfigurations.back()->recoverFromXmlNode(*wnode);
}
-}
+ virtual ~debug_qt() { }
-void xml_configuration_save(running_machine &machine, config_type cfg_type, util::xml::data_node *parentnode)
-{
- // We only write to game configurations
- if (cfg_type != config_type::GAME)
- return;
+ virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
+ virtual void exit() override;
- for (int i = 0; i < xmlConfigurations.size(); i++)
+ virtual void init_debugger(running_machine &machine) override;
+ virtual void wait_for_debugger(device_t &device, bool firststop) override;
+ virtual void debugger_update() override;
+#if defined(_WIN32) && !defined(SDLMAME_WIN32)
+ virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *) override
{
- WindowQtConfig* config = xmlConfigurations[i];
-
- // Create an xml node
- util::xml::data_node *const debugger_node = parentnode->add_child("window", nullptr);
- if (debugger_node == nullptr)
- continue;
-
- // Insert the appropriate information
- config->addToXmlDataNode(*debugger_node);
+ winwindow_qt_filter(message);
+ return false;
}
-}
+#endif
+ virtual running_machine &machine() const override { return *m_machine; }
-void gather_save_configurations()
-{
- for (int i = 0; i < xmlConfigurations.size(); i++)
- delete xmlConfigurations[i];
- xmlConfigurations.clear();
+private:
+ void configuration_load(config_type which_type, config_level level, util::xml::data_node const *parentnode);
+ void configuration_save(config_type which_type, util::xml::data_node *parentnode);
+ void load_window_configurations(util::xml::data_node const &parentnode);
- // Loop over all the open windows
- foreach (QWidget* widget, QApplication::topLevelWidgets())
- {
- if (!widget->isVisible())
- continue;
-
- if (!widget->isWindow() || widget->windowType() != Qt::Window)
- continue;
-
- // Figure out its type
- if (dynamic_cast<MainWindow*>(widget))
- xmlConfigurations.push_back(new MainWindowQtConfig());
- else if (dynamic_cast<MemoryWindow*>(widget))
- xmlConfigurations.push_back(new MemoryWindowQtConfig());
- else if (dynamic_cast<DasmWindow*>(widget))
- xmlConfigurations.push_back(new DasmWindowQtConfig());
- else if (dynamic_cast<LogWindow*>(widget))
- xmlConfigurations.push_back(new LogWindowQtConfig());
- else if (dynamic_cast<BreakpointsWindow*>(widget))
- xmlConfigurations.push_back(new BreakpointsWindowQtConfig());
- else if (dynamic_cast<DevicesWindow*>(widget))
- xmlConfigurations.push_back(new DevicesWindowQtConfig());
- else if (dynamic_cast<DeviceInformationWindow*>(widget))
- xmlConfigurations.push_back(new DeviceInformationWindowQtConfig());
-
- xmlConfigurations.back()->buildFromQWidget(widget);
- }
-}
+ running_machine *m_machine;
+ debugger::qt::MainWindow *m_mainwindow;
+ util::xml::file::ptr m_config;
+};
//============================================================
-// Utilities
+// "Global" variables to make QT happy
//============================================================
-void load_and_clear_main_window_config(std::vector<WindowQtConfig*>& configList)
-{
- for (int i = 0; i < configList.size(); i++)
- {
- WindowQtConfig* config = configList[i];
- if (config->m_type == WindowQtConfig::WIN_TYPE_MAIN)
- {
- config->applyToQWidget(mainQtWindow);
- configList.erase(configList.begin()+i);
- break;
- }
- }
-}
-
-
-void setup_additional_startup_windows(running_machine& machine, std::vector<WindowQtConfig*>& configList)
-{
- for (int i = 0; i < configList.size(); i++)
- {
- WindowQtConfig* config = configList[i];
-
- WindowQt* foo = nullptr;
- switch (config->m_type)
- {
- case WindowQtConfig::WIN_TYPE_MEMORY:
- foo = new MemoryWindow(&machine); break;
- case WindowQtConfig::WIN_TYPE_DASM:
- foo = new DasmWindow(&machine); break;
- case WindowQtConfig::WIN_TYPE_LOG:
- foo = new LogWindow(&machine); break;
- case WindowQtConfig::WIN_TYPE_BREAK_POINTS:
- foo = new BreakpointsWindow(&machine); break;
- case WindowQtConfig::WIN_TYPE_DEVICES:
- foo = new DevicesWindow(&machine); break;
- case WindowQtConfig::WIN_TYPE_DEVICE_INFORMATION:
- foo = new DeviceInformationWindow(&machine); break;
- default: break;
- }
- config->applyToQWidget(foo);
- foo->show();
- }
-}
-
-
-void bring_main_window_to_front()
-{
- foreach (QWidget* widget, QApplication::topLevelWidgets())
- {
- if (!dynamic_cast<MainWindow*>(widget))
- continue;
- widget->activateWindow();
- widget->raise();
- }
-}
-
-} // anonymous namespace
+int qtArgc = 1;
+char qtArg0[] = "mame";
+char *qtArgv[] = { qtArg0, nullptr };
//============================================================
// Core functionality
//============================================================
-#if defined(WIN32) && !defined(SDLMAME_WIN32)
-bool winwindow_qt_filter(void *message);
-
-bool debug_qt::nativeEventFilter(const QByteArray &eventType, void *message, long *)
+void debug_qt::exit()
{
- winwindow_qt_filter(message);
- return false;
+ // If you've done a hard reset, clear out existing widgets
+ emit exitDebugger();
+ m_mainwindow = nullptr;
}
-#endif
+
void debug_qt::init_debugger(running_machine &machine)
{
- if (qApp == nullptr)
+ if (!qApp)
{
// If you're starting from scratch, create a new qApp
new QApplication(qtArgc, qtArgv);
-#if defined(WIN32) && !defined(SDLMAME_WIN32)
+#if defined(_WIN32) && !defined(SDLMAME_WIN32)
QAbstractEventDispatcher::instance()->installNativeEventFilter(this);
#endif
}
- else
- {
- // If you've done a hard reset, clear out existing widgets & get ready for re-init
- foreach (QWidget* widget, QApplication::topLevelWidgets())
- {
- if (!widget->isWindow() || widget->windowType() != Qt::Window)
- continue;
- delete widget;
- }
- oneShot = true;
- }
m_machine = &machine;
+
// Setup the configuration XML saving and loading
machine.configuration().config_register("debugger",
- config_load_delegate(&xml_configuration_load, &machine),
- config_save_delegate(&xml_configuration_save, &machine));
+ configuration_manager::load_delegate(&debug_qt::configuration_load, this),
+ configuration_manager::save_delegate(&debug_qt::configuration_save, this));
}
@@ -283,12 +135,6 @@ void debug_qt::init_debugger(running_machine &machine)
// Core functionality
//============================================================
-#if defined(SDLMAME_UNIX) || defined(SDLMAME_WIN32)
-extern int sdl_entered_debugger;
-#elif defined(WIN32)
-void winwindow_update_cursor_state(running_machine &machine);
-#endif
-
void debug_qt::wait_for_debugger(device_t &device, bool firststop)
{
#if defined(SDLMAME_UNIX) || defined(SDLMAME_WIN32)
@@ -296,81 +142,117 @@ void debug_qt::wait_for_debugger(device_t &device, bool firststop)
#endif
// Dialog initialization
- if (oneShot)
+ if (!m_mainwindow)
{
- mainQtWindow = new MainWindow(m_machine);
- load_and_clear_main_window_config(xmlConfigurations);
- setup_additional_startup_windows(*m_machine, xmlConfigurations);
- mainQtWindow->show();
- oneShot = false;
+ m_mainwindow = new debugger::qt::MainWindow(*this);
+ if (m_config)
+ {
+ load_window_configurations(*m_config->get_first_child());
+ m_config.reset();
+ }
+ m_mainwindow->show();
}
- // Insure all top level widgets are visible & bring main window to front
- foreach (QWidget* widget, QApplication::topLevelWidgets())
- {
- if (!widget->isWindow() || widget->windowType() != Qt::Window)
- continue;
- widget->show();
- }
+ // Ensure all top level widgets are visible & bring main window to front
+ emit showAllWindows();
if (firststop)
{
- bring_main_window_to_front();
+ m_mainwindow->activateWindow();
+ m_mainwindow->raise();
}
- // Set the main window to display the proper cpu
- mainQtWindow->setProcessor(&device);
+ // Set the main window to display the proper CPU
+ m_mainwindow->setProcessor(&device);
// Run our own QT event loop
osd_sleep(osd_ticks_per_second() / 1000 * 50);
qApp->processEvents(QEventLoop::AllEvents, 1);
- // Refresh everyone if requested
- if (mainQtWindow->wantsRefresh())
- {
- QWidgetList allWidgets = qApp->allWidgets();
- for (int i = 0; i < allWidgets.length(); i++)
- allWidgets[i]->update();
- mainQtWindow->clearRefreshFlag();
- }
+#if defined(_WIN32) && !defined(SDLMAME_WIN32)
+ winwindow_update_cursor_state(*m_machine); // make sure the cursor isn't hidden while in debugger
+#endif
+}
+
+
+//============================================================
+// Available for video.*
+//============================================================
+
+void debug_qt::debugger_update()
+{
+ qApp->processEvents(QEventLoop::AllEvents);
+}
- // Hide all top level widgets if requested
- if (mainQtWindow->wantsHide())
+
+void debug_qt::configuration_load(config_type which_type, config_level level, util::xml::data_node const *parentnode)
+{
+ // We only care about system configuration files for now
+ if ((config_type::SYSTEM == which_type) && parentnode)
{
- foreach (QWidget* widget, QApplication::topLevelWidgets())
+ if (m_mainwindow)
+ {
+ load_window_configurations(*parentnode);
+ }
+ else
{
- if (!widget->isWindow() || widget->windowType() != Qt::Window)
- continue;
- widget->hide();
+ m_config = util::xml::file::create();
+ parentnode->copy_into(*m_config);
}
- mainQtWindow->clearHideFlag();
}
+}
+
+
+void debug_qt::configuration_save(config_type which_type, util::xml::data_node *parentnode)
+{
+ // We only save system configuration for now
+ if ((config_type::SYSTEM == which_type) && parentnode)
+ emit saveConfiguration(*parentnode);
+}
- // Exit if the machine has been instructed to do so (scheduled event == exit || hard_reset)
- if (m_machine->scheduled_event_pending())
+
+void debug_qt::load_window_configurations(util::xml::data_node const &parentnode)
+{
+ for (util::xml::data_node const *wnode = parentnode.get_child(debugger::NODE_WINDOW); wnode; wnode = wnode->get_next_sibling(debugger::NODE_WINDOW))
{
- // Keep a list of windows we want to save.
- // We need to do this here because by the time xml_configuration_save gets called
- // all the QT windows are already gone.
- gather_save_configurations();
+ debugger::qt::WindowQt *win = nullptr;
+ switch (wnode->get_attribute_int(debugger::ATTR_WINDOW_TYPE, -1))
+ {
+ case debugger::WINDOW_TYPE_CONSOLE:
+ win = m_mainwindow;
+ break;
+ case debugger::WINDOW_TYPE_MEMORY_VIEWER:
+ win = new debugger::qt::MemoryWindow(*this);
+ break;
+ case debugger::WINDOW_TYPE_DISASSEMBLY_VIEWER:
+ win = new debugger::qt::DasmWindow(*this);
+ break;
+ case debugger::WINDOW_TYPE_ERROR_LOG_VIEWER:
+ win = new debugger::qt::LogWindow(*this);
+ break;
+ case debugger::WINDOW_TYPE_POINTS_VIEWER:
+ win = new debugger::qt::BreakpointsWindow(*this);
+ break;
+ case debugger::WINDOW_TYPE_DEVICES_VIEWER:
+ win = new debugger::qt::DevicesWindow(*this);
+ break;
+ case debugger::WINDOW_TYPE_DEVICE_INFO_VIEWER:
+ win = new debugger::qt::DeviceInformationWindow(*this);
+ break;
+ }
+ if (win)
+ win->restoreConfiguration(*wnode);
}
-#if defined(WIN32) && !defined(SDLMAME_WIN32)
- winwindow_update_cursor_state(*m_machine); // make sure the cursor isn't hidden while in debugger
-#endif
}
+} // anonymous namespace
-//============================================================
-// Available for video.*
-//============================================================
+} // namespace osd
-void debug_qt::debugger_update()
-{
- qApp->processEvents(QEventLoop::AllEvents, 1);
-}
+#else // USE_QTDEBUG
+
+namespace osd { namespace { MODULE_NOT_SUPPORTED(debug_qt, OSD_DEBUG_PROVIDER, "qt") } }
-#else /* SDLMAME_UNIX */
- MODULE_NOT_SUPPORTED(debug_qt, OSD_DEBUG_PROVIDER, "qt")
#endif
-MODULE_DEFINITION(DEBUG_QT, debug_qt)
+MODULE_DEFINITION(DEBUG_QT, osd::debug_qt)
diff --git a/src/osd/modules/debugger/debugwin.cpp b/src/osd/modules/debugger/debugwin.cpp
index 975e7ba6bc6..8ff26d40fb3 100644
--- a/src/osd/modules/debugger/debugwin.cpp
+++ b/src/osd/modules/debugger/debugwin.cpp
@@ -2,13 +2,12 @@
// copyright-holders:Aaron Giles, Vas Crabb
//============================================================
//
-// debugwin.c - Win32 debug window handling
+// debugwin.cpp - Win32 debug window handling
//
//============================================================
#include "emu.h"
#include "debug_module.h"
-#include "modules/osdmodule.h"
#if defined(OSD_WINDOWS) /*|| defined(SDLMAME_WIN32)*/
@@ -22,31 +21,50 @@
#include "win/pointswininfo.h"
#include "win/uimetrics.h"
+// emu
+#include "config.h"
#include "debugger.h"
#include "debug/debugcpu.h"
+#include "util/xmlfile.h"
+
+// osd/windows
#include "window.h"
-#include "../input/input_common.h"
-#include "../input/input_windows.h"
+#include "winmain.h"
+
+#include "../input/input_windows.h" // for the keyboard translation table
+
+namespace osd {
-class debugger_windows : public osd_module, public debug_module, protected debugger_windows_interface
+namespace {
+
+class debugger_windows :
+ public osd_module,
+ public debug_module,
+ protected debugger::win::debugger_windows_interface
{
public:
debugger_windows() :
osd_module(OSD_DEBUG_PROVIDER, "windows"),
debug_module(),
+ m_osd(nullptr),
m_machine(nullptr),
m_metrics(),
m_waiting_for_debugger(false),
m_window_list(),
- m_main_console(nullptr)
+ m_main_console(nullptr),
+ m_next_window_pos{ 0, 0 },
+ m_config(),
+ m_save_windows(true),
+ m_group_windows(true),
+ m_group_windows_setting(true)
{
}
virtual ~debugger_windows() { }
- virtual int init(const osd_options &options) override { return 0; }
+ virtual int init(osd_interface &osd, osd_options const &options) override;
virtual void exit() override;
virtual void init_debugger(running_machine &machine) override;
@@ -56,31 +74,63 @@ public:
protected:
virtual running_machine &machine() const override { return *m_machine; }
- virtual ui_metrics &metrics() const override { return *m_metrics; }
+ virtual debugger::win::ui_metrics &metrics() const override { return *m_metrics; }
+ virtual void set_color_theme(int index) override;
+ virtual bool get_save_window_arrangement() const override { return m_save_windows; }
+ virtual void set_save_window_arrangement(bool save) override { m_save_windows = save; }
+ virtual bool get_group_windows() const override { return m_group_windows; }
+ virtual bool get_group_windows_setting() const override { return m_group_windows_setting; }
+ virtual void set_group_windows_setting(bool group) override { m_group_windows_setting = group; }
virtual bool const &waiting_for_debugger() const override { return m_waiting_for_debugger; }
virtual bool seq_pressed() const override;
- virtual void create_memory_window() override { create_window<memorywin_info>(); }
- virtual void create_disasm_window() override { create_window<disasmwin_info>(); }
- virtual void create_log_window() override { create_window<logwin_info>(); }
- virtual void create_points_window() override { create_window<pointswin_info>(); }
- virtual void remove_window(debugwin_info &info) override;
+ virtual void create_memory_window() override { create_window<debugger::win::memorywin_info>(); }
+ virtual void create_disasm_window() override { create_window<debugger::win::disasmwin_info>(); }
+ virtual void create_log_window() override { create_window<debugger::win::logwin_info>(); }
+ virtual void create_points_window() override { create_window<debugger::win::pointswin_info>(); }
+ virtual void remove_window(debugger::win::debugwin_info &info) override;
virtual void show_all() override;
virtual void hide_all() override;
+ virtual void stagger_window(HWND window, int width, int height) override;
+
private:
template <typename T> T *create_window();
- running_machine *m_machine;
- std::unique_ptr<ui_metrics> m_metrics;
- bool m_waiting_for_debugger;
- std::vector<std::unique_ptr<debugwin_info>> m_window_list;
- consolewin_info *m_main_console;
+ void config_load(config_type cfgtype, config_level cfglevel, util::xml::data_node const *parentnode);
+ void config_save(config_type cfgtype, util::xml::data_node *parentnode);
+
+ void load_configuration(util::xml::data_node const &parentnode);
+
+ windows_osd_interface *m_osd;
+ running_machine *m_machine;
+ std::unique_ptr<debugger::win::ui_metrics> m_metrics;
+ bool m_waiting_for_debugger;
+ std::vector<std::unique_ptr<debugger::win::debugwin_info> > m_window_list;
+ debugger::win::consolewin_info *m_main_console;
+
+ POINT m_next_window_pos;
+ LONG m_window_start_x;
+
+ util::xml::file::ptr m_config;
+ bool m_save_windows;
+ bool m_group_windows;
+ bool m_group_windows_setting;
};
+int debugger_windows::init(osd_interface &osd, osd_options const &options)
+{
+ m_osd = dynamic_cast<windows_osd_interface *>(&osd);
+ if (!m_osd)
+ return -1;
+
+ return 0;
+}
+
+
void debugger_windows::exit()
{
// loop over windows and free them
@@ -96,23 +146,52 @@ void debugger_windows::exit()
void debugger_windows::init_debugger(running_machine &machine)
{
m_machine = &machine;
- m_metrics = std::make_unique<ui_metrics>(downcast<osd_options &>(m_machine->options()));
+ m_metrics = std::make_unique<debugger::win::ui_metrics>(downcast<osd_options &>(m_machine->options()));
+ machine.configuration().config_register(
+ "debugger",
+ configuration_manager::load_delegate(&debugger_windows::config_load, this),
+ configuration_manager::save_delegate(&debugger_windows::config_save, this));
}
void debugger_windows::wait_for_debugger(device_t &device, bool firststop)
{
// create a console window
- if (m_main_console == nullptr)
- m_main_console = create_window<consolewin_info>();
+ if (!m_main_console)
+ {
+ m_main_console = create_window<debugger::win::consolewin_info>();
+
+ // set the starting position for new auxiliary windows
+ HMONITOR const nearest_monitor = MonitorFromWindow(
+ dynamic_cast<win_window_info &>(*osd_common_t::window_list().front()).platform_window(),
+ MONITOR_DEFAULTTONEAREST);
+ if (nearest_monitor)
+ {
+ MONITORINFO info;
+ std::memset(&info, 0, sizeof(info));
+ info.cbSize = sizeof(info);
+ if (GetMonitorInfo(nearest_monitor, &info))
+ {
+ m_next_window_pos.x = info.rcWork.left + 100;
+ m_next_window_pos.y = info.rcWork.top + 100;
+ m_window_start_x = m_next_window_pos.x;
+ }
+ }
+ }
// update the views in the console to reflect the current CPU
- if (m_main_console != nullptr)
+ if (m_main_console)
m_main_console->set_cpu(device);
// when we are first stopped, adjust focus to us
- if (firststop && (m_main_console != nullptr))
+ if (firststop && m_main_console)
{
+ if (m_config)
+ {
+ for (util::xml::data_node const *node = m_config->get_first_child(); node; node = node->get_next_sibling())
+ load_configuration(*node);
+ m_config.reset();
+ }
m_main_console->set_foreground();
if (winwindow_has_focus())
m_main_console->set_default_focus();
@@ -123,7 +202,7 @@ void debugger_windows::wait_for_debugger(device_t &device, bool firststop)
show_all();
// run input polling to ensure that our status is in sync
- downcast<windows_osd_interface&>(machine().osd()).poll_input(*m_machine);
+ downcast<windows_osd_interface&>(machine().osd()).poll_input_modules(false);
// get and process messages
MSG message;
@@ -142,7 +221,7 @@ void debugger_windows::wait_for_debugger(device_t &device, bool firststop)
// process everything else
default:
- winwindow_dispatch_message(*m_machine, &message);
+ winwindow_dispatch_message(*m_machine, message);
break;
}
@@ -161,7 +240,7 @@ void debugger_windows::debugger_update()
{
HWND const focuswnd = GetFocus();
- m_machine->debugger().cpu().get_visible_cpu()->debug()->halt_on_next_instruction("User-initiated break\n");
+ m_machine->debugger().debug_break();
// if we were focused on some window's edit box, reset it to default
for (auto &info : m_window_list)
@@ -171,6 +250,14 @@ void debugger_windows::debugger_update()
}
+void debugger_windows::set_color_theme(int index)
+{
+ m_metrics->set_color_theme(index);
+ for (auto const &window : m_window_list)
+ window->redraw();
+}
+
+
bool debugger_windows::seq_pressed() const
{
input_seq const &seq = m_machine->ioport().type_seq(IPT_UI_DEBUG_BREAK);
@@ -222,7 +309,7 @@ bool debugger_windows::seq_pressed() const
}
-void debugger_windows::remove_window(debugwin_info &info)
+void debugger_windows::remove_window(debugger::win::debugwin_info &info)
{
for (auto it = m_window_list.begin(); it != m_window_list.end(); ++it)
if (it->get() == &info) {
@@ -241,28 +328,164 @@ void debugger_windows::show_all()
void debugger_windows::hide_all()
{
- SetForegroundWindow(std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window());
+ SetForegroundWindow(dynamic_cast<win_window_info &>(*osd_common_t::window_list().front()).platform_window());
for (auto &info : m_window_list)
info->hide();
}
-template <typename T> T *debugger_windows::create_window()
+void debugger_windows::stagger_window(HWND window, int width, int height)
+{
+ // get width/height for client size
+ RECT target;
+ target.left = 0;
+ target.top = 0;
+ target.right = width;
+ target.bottom = height;
+ if (!AdjustWindowRectEx(&target, GetWindowLong(window, GWL_STYLE), GetMenu(window) ? TRUE : FALSE,GetWindowLong(window, GWL_EXSTYLE)))
+ {
+ // really shouldn't end up here, but have to do something
+ SetWindowPos(window, HWND_TOP, m_next_window_pos.x, m_next_window_pos.y, width, height, SWP_SHOWWINDOW);
+ return;
+ }
+ target.right -= target.left;
+ target.bottom -= target.top;
+ target.left = target.top = 0;
+
+ // get the work area for the nearest monitor to the target position
+ HMONITOR const mon = MonitorFromPoint(m_next_window_pos, MONITOR_DEFAULTTONEAREST);
+ if (mon)
+ {
+ MONITORINFO info;
+ std::memset(&info, 0, sizeof(info));
+ info.cbSize = sizeof(info);
+ if (GetMonitorInfo(mon, &info))
+ {
+ // restart cascade if necessary
+ if (((m_next_window_pos.x + target.right) > info.rcWork.right) || ((m_next_window_pos.y + target.bottom) > info.rcWork.bottom))
+ {
+ m_next_window_pos.x = m_window_start_x += 16;
+ m_next_window_pos.y = info.rcWork.top + 100;
+ if ((m_next_window_pos.x + target.right) > info.rcWork.right)
+ m_next_window_pos.x = m_window_start_x = info.rcWork.left + 100;
+ }
+ }
+ }
+
+ // move the window and adjust the next position
+ MoveWindow(window, m_next_window_pos.x, m_next_window_pos.y, target.right, target.bottom, FALSE);
+ SetWindowPos(window, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
+ m_next_window_pos.x += 16;
+ m_next_window_pos.y += 16;
+}
+
+
+template <typename T>
+T *debugger_windows::create_window()
{
// allocate memory
std::unique_ptr<T> info = std::make_unique<T>(static_cast<debugger_windows_interface &>(*this));
if (info->is_valid())
{
+ T &result(*info);
m_window_list.push_back(std::move(info));
- T *ptr = dynamic_cast<T*>(m_window_list.back().get());
- return ptr;
+ return &result;
}
return nullptr;
}
-#else /* not windows */
-MODULE_NOT_SUPPORTED(debugger_windows, OSD_DEBUG_PROVIDER, "windows")
+void debugger_windows::config_load(config_type cfgtype, config_level cfglevel, util::xml::data_node const *parentnode)
+{
+ if (parentnode)
+ {
+ if (config_type::DEFAULT == cfgtype)
+ {
+ m_save_windows = 0 != parentnode->get_attribute_int(debugger::ATTR_DEBUGGER_SAVE_WINDOWS, m_save_windows ? 1 : 0);
+ m_group_windows = m_group_windows_setting = 0 != parentnode->get_attribute_int(debugger::ATTR_DEBUGGER_GROUP_WINDOWS, m_group_windows ? 1 : 0);
+ util::xml::data_node const *const colors = parentnode->get_child(debugger::NODE_COLORS);
+ if (colors)
+ m_metrics->set_color_theme(colors->get_attribute_int(debugger::ATTR_COLORS_THEME, m_metrics->get_color_theme()));
+ }
+ else if (config_type::SYSTEM == cfgtype)
+ {
+ if (m_main_console)
+ {
+ load_configuration(*parentnode);
+ }
+ else
+ {
+ if (!m_config)
+ m_config = util::xml::file::create();
+ parentnode->copy_into(*m_config);
+ }
+ }
+ }
+}
+
+
+void debugger_windows::config_save(config_type cfgtype, util::xml::data_node *parentnode)
+{
+ if (config_type::DEFAULT == cfgtype)
+ {
+ parentnode->set_attribute_int(debugger::ATTR_DEBUGGER_SAVE_WINDOWS, m_save_windows ? 1 : 0);
+ parentnode->set_attribute_int(debugger::ATTR_DEBUGGER_GROUP_WINDOWS, m_group_windows_setting ? 1 : 0);
+ util::xml::data_node *const colors = parentnode->add_child(debugger::NODE_COLORS, nullptr);
+ if (colors)
+ colors->set_attribute_int(debugger::ATTR_COLORS_THEME, m_metrics->get_color_theme());
+ }
+ else if (m_save_windows && (config_type::SYSTEM == cfgtype))
+ {
+ for (auto &info : m_window_list)
+ info->save_configuration(*parentnode);
+ }
+}
+
+
+void debugger_windows::load_configuration(util::xml::data_node const &parentnode)
+{
+ for (util::xml::data_node const *node = parentnode.get_child(debugger::NODE_WINDOW); node; node = node->get_next_sibling(debugger::NODE_WINDOW))
+ {
+ debugger::win::debugwin_info *win = nullptr;
+ switch (node->get_attribute_int(debugger::ATTR_WINDOW_TYPE, -1))
+ {
+ case debugger::WINDOW_TYPE_CONSOLE:
+ m_main_console->restore_configuration_from_node(*node);
+ break;
+ case debugger::WINDOW_TYPE_MEMORY_VIEWER:
+ win = create_window<debugger::win::memorywin_info>();
+ break;
+ case debugger::WINDOW_TYPE_DISASSEMBLY_VIEWER:
+ win = create_window<debugger::win::disasmwin_info>();
+ break;
+ case debugger::WINDOW_TYPE_ERROR_LOG_VIEWER:
+ win = create_window<debugger::win::logwin_info>();
+ break;
+ case debugger::WINDOW_TYPE_POINTS_VIEWER:
+ win = create_window<debugger::win::pointswin_info>();
+ break;
+ case debugger::WINDOW_TYPE_DEVICES_VIEWER:
+ // not supported
+ break;
+ case debugger::WINDOW_TYPE_DEVICE_INFO_VIEWER:
+ // not supported
+ break;
+ default:
+ break;
+ }
+ if (win)
+ win->restore_configuration_from_node(*node);
+ }
+}
+
+} // anonymous namespace
+
+} // namespace osd
+
+#else // not Windows
+
+namespace osd { namespace { MODULE_NOT_SUPPORTED(debugger_windows, OSD_DEBUG_PROVIDER, "windows") } }
+
#endif
-MODULE_DEFINITION(DEBUG_WINDOWS, debugger_windows)
+MODULE_DEFINITION(DEBUG_WINDOWS, osd::debugger_windows)
diff --git a/src/osd/modules/debugger/none.cpp b/src/osd/modules/debugger/none.cpp
index 3ce8d6572bc..61bd1bbbd3e 100644
--- a/src/osd/modules/debugger/none.cpp
+++ b/src/osd/modules/debugger/none.cpp
@@ -8,23 +8,28 @@
#include "emu.h"
#include "debug_module.h"
-#include "modules/osdmodule.h"
+#include "debug/debugcon.h"
#include "debug/debugcpu.h"
#include "debugger.h"
+
+namespace osd {
+
+namespace {
+
class debug_none : public osd_module, public debug_module
{
public:
- debug_none()
- : osd_module(OSD_DEBUG_PROVIDER, "none"), debug_module(),
+ debug_none() :
+ osd_module(OSD_DEBUG_PROVIDER, "none"), debug_module(),
m_machine(nullptr)
{
}
virtual ~debug_none() { }
- virtual int init(const osd_options &options) override { return 0; }
+ virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
virtual void exit() override { }
virtual void init_debugger(running_machine &machine) override;
@@ -42,11 +47,15 @@ void debug_none::init_debugger(running_machine &machine)
void debug_none::wait_for_debugger(device_t &device, bool firststop)
{
- m_machine->debugger().cpu().get_visible_cpu()->debug()->go();
+ m_machine->debugger().console().get_visible_cpu()->debug()->go();
}
void debug_none::debugger_update()
{
}
-MODULE_DEFINITION(DEBUG_NONE, debug_none)
+} // anonymous namespace
+
+} // namespace osd
+
+MODULE_DEFINITION(DEBUG_NONE, osd::debug_none)
diff --git a/src/osd/modules/debugger/osx/debugcommandhistory.h b/src/osd/modules/debugger/osx/debugcommandhistory.h
index f99767cb4be..e505aa4435c 100644
--- a/src/osd/modules/debugger/osx/debugcommandhistory.h
+++ b/src/osd/modules/debugger/osx/debugcommandhistory.h
@@ -8,6 +8,8 @@
#import "debugosx.h"
+#include "util/utilfwd.h"
+
#import <Cocoa/Cocoa.h>
@@ -32,4 +34,7 @@
- (void)reset;
- (void)clear;
+- (void)saveConfigurationToNode:(util::xml::data_node *)node;
+- (void)restoreConfigurationFromNode:(util::xml::data_node const *)node;
+
@end
diff --git a/src/osd/modules/debugger/osx/debugcommandhistory.mm b/src/osd/modules/debugger/osx/debugcommandhistory.mm
index 74a34904ae7..e2292f973b0 100644
--- a/src/osd/modules/debugger/osx/debugcommandhistory.mm
+++ b/src/osd/modules/debugger/osx/debugcommandhistory.mm
@@ -12,6 +12,8 @@
#import "debugcommandhistory.h"
+#include "util/xmlfile.h"
+
@implementation MAMEDebugCommandHistory
@@ -54,9 +56,9 @@
- (void)add:(NSString *)entry {
if (([history count] == 0) || ![[history objectAtIndex:0] isEqualToString:entry]) {
- [history insertObject:entry atIndex:0];
- while ([history count] > length)
+ while ([history count] >= length)
[history removeLastObject];
+ [history insertObject:entry atIndex:0];
}
position = 0;
}
@@ -110,4 +112,30 @@
[history removeAllObjects];
}
+
+- (void)saveConfigurationToNode:(util::xml::data_node *)node {
+ util::xml::data_node *const hist = node->add_child(osd::debugger::NODE_WINDOW_HISTORY, nullptr);
+ if (hist) {
+ for (NSInteger i = [history count]; 0 < i; --i)
+ hist->add_child(osd::debugger::NODE_HISTORY_ITEM, [[history objectAtIndex:(i - 1)] UTF8String]);
+ }
+}
+
+
+- (void)restoreConfigurationFromNode:(util::xml::data_node const *)node {
+ [self clear];
+ util::xml::data_node const *const hist = node->get_child(osd::debugger::NODE_WINDOW_HISTORY);
+ if (hist) {
+ util::xml::data_node const *item = hist->get_child(osd::debugger::NODE_HISTORY_ITEM);
+ while (item) {
+ if (item->get_value() && *item->get_value()) {
+ while ([history count] >= length)
+ [history removeLastObject];
+ [history insertObject:[NSString stringWithUTF8String:item->get_value()] atIndex:0];
+ }
+ item = item->get_next_sibling(osd::debugger::NODE_HISTORY_ITEM);
+ }
+ }
+}
+
@end
diff --git a/src/osd/modules/debugger/osx/debugconsole.mm b/src/osd/modules/debugger/osx/debugconsole.mm
index 1bd285e8c3b..9673dc852ab 100644
--- a/src/osd/modules/debugger/osx/debugconsole.mm
+++ b/src/osd/modules/debugger/osx/debugconsole.mm
@@ -24,6 +24,7 @@
#include "debugger.h"
#include "debug/debugcon.h"
#include "debug/debugcpu.h"
+#include "debug/points.h"
#include "util/xmlfile.h"
@@ -141,19 +142,25 @@
NSRect const available = [[NSScreen mainScreen] visibleFrame];
NSSize const regCurrent = [regScroll frame].size;
NSSize const regSize = [NSScrollView frameSizeForContentSize:[regView maximumFrameSize]
- hasHorizontalScroller:YES
- hasVerticalScroller:YES
- borderType:[regScroll borderType]];
+ horizontalScrollerClass:[NSScroller class]
+ verticalScrollerClass:[NSScroller class]
+ borderType:[regScroll borderType]
+ controlSize:NSControlSizeRegular
+ scrollerStyle:NSScrollerStyleOverlay];
NSSize const dasmCurrent = [dasmScroll frame].size;
NSSize const dasmSize = [NSScrollView frameSizeForContentSize:[dasmView maximumFrameSize]
- hasHorizontalScroller:YES
- hasVerticalScroller:YES
- borderType:[dasmScroll borderType]];
+ horizontalScrollerClass:[NSScroller class]
+ verticalScrollerClass:[NSScroller class]
+ borderType:[dasmScroll borderType]
+ controlSize:NSControlSizeRegular
+ scrollerStyle:NSScrollerStyleOverlay];
NSSize const consoleCurrent = [consoleContainer frame].size;
NSSize consoleSize = [NSScrollView frameSizeForContentSize:[consoleView maximumFrameSize]
- hasHorizontalScroller:YES
- hasVerticalScroller:YES
- borderType:[consoleScroll borderType]];
+ horizontalScrollerClass:[NSScroller class]
+ verticalScrollerClass:[NSScroller class]
+ borderType:[consoleScroll borderType]
+ controlSize:NSControlSizeRegular
+ scrollerStyle:NSScrollerStyleOverlay];
NSRect windowFrame = [window frame];
NSSize adjustment;
@@ -181,7 +188,7 @@
[dasmSplit setFrame:rhsFrame];
// select the current processor
- [self setCPU:machine->debugger().cpu().get_visible_cpu()];
+ [self setCPU:machine->debugger().console().get_visible_cpu()];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(auxiliaryWindowWillClose:)
@@ -219,7 +226,7 @@
NSString *command = [sender stringValue];
if ([command length] == 0)
{
- machine->debugger().cpu().get_visible_cpu()->debug()->single_step();
+ machine->debugger().console().get_visible_cpu()->debug()->single_step();
[history reset];
}
else
@@ -234,10 +241,10 @@
- (IBAction)debugToggleBreakpoint:(id)sender {
device_t &device = *[dasmView source]->device();
- if ([dasmView cursorVisible] && (machine->debugger().cpu().get_visible_cpu() == &device))
+ if ([dasmView cursorVisible] && (machine->debugger().console().get_visible_cpu() == &device))
{
offs_t const address = [dasmView selectedAddress];
- const device_debug::breakpoint *bp = [dasmView source]->device()->debug()->breakpoint_find(address);
+ const debug_breakpoint *bp = [dasmView source]->device()->debug()->breakpoint_find(address);
// if it doesn't exist, add a new one
NSString *command;
@@ -252,9 +259,9 @@
- (IBAction)debugToggleBreakpointEnable:(id)sender {
device_t &device = *[dasmView source]->device();
- if ([dasmView cursorVisible] && (machine->debugger().cpu().get_visible_cpu() == &device))
+ if ([dasmView cursorVisible] && (machine->debugger().console().get_visible_cpu() == &device))
{
- const device_debug::breakpoint *bp = [dasmView source]->device()->debug()->breakpoint_find([dasmView selectedAddress]);
+ const debug_breakpoint *bp = [dasmView source]->device()->debug()->breakpoint_find([dasmView selectedAddress]);
if (bp != nullptr)
{
NSString *command;
@@ -270,7 +277,7 @@
- (IBAction)debugRunToCursor:(id)sender {
device_t &device = *[dasmView source]->device();
- if ([dasmView cursorVisible] && (machine->debugger().cpu().get_visible_cpu() == &device))
+ if ([dasmView cursorVisible] && (machine->debugger().console().get_visible_cpu() == &device))
{
NSString *command = [NSString stringWithFormat:@"go 0x%lX", (unsigned long)[dasmView selectedAddress]];
machine->debugger().console().execute_command([command UTF8String], 1);
@@ -379,32 +386,35 @@
- (void)loadConfiguration:(util::xml::data_node const *)parentnode {
util::xml::data_node const *node = nullptr;
- for (node = parentnode->get_child("window"); node; node = node->get_next_sibling("window"))
+ for (node = parentnode->get_child(osd::debugger::NODE_WINDOW); node; node = node->get_next_sibling(osd::debugger::NODE_WINDOW))
{
MAMEDebugWindowHandler *win = nil;
- switch (node->get_attribute_int("type", -1))
+ switch (node->get_attribute_int(osd::debugger::ATTR_WINDOW_TYPE, -1))
{
- case MAME_DEBUGGER_WINDOW_TYPE_CONSOLE:
+ case osd::debugger::WINDOW_TYPE_CONSOLE:
[self restoreConfigurationFromNode:node];
break;
- case MAME_DEBUGGER_WINDOW_TYPE_MEMORY_VIEWER:
+ case osd::debugger::WINDOW_TYPE_MEMORY_VIEWER:
win = [[MAMEMemoryViewer alloc] initWithMachine:*machine console:self];
break;
- case MAME_DEBUGGER_WINDOW_TYPE_DISASSEMBLY_VIEWER:
+ case osd::debugger::WINDOW_TYPE_DISASSEMBLY_VIEWER:
win = [[MAMEDisassemblyViewer alloc] initWithMachine:*machine console:self];
break;
- case MAME_DEBUGGER_WINDOW_TYPE_ERROR_LOG_VIEWER:
+ case osd::debugger::WINDOW_TYPE_ERROR_LOG_VIEWER:
win = [[MAMEErrorLogViewer alloc] initWithMachine:*machine console:self];
break;
- case MAME_DEBUGGER_WINDOW_TYPE_POINTS_VIEWER:
+ case osd::debugger::WINDOW_TYPE_POINTS_VIEWER:
win = [[MAMEPointsViewer alloc] initWithMachine:*machine console:self];
break;
- case MAME_DEBUGGER_WINDOW_TYPE_DEVICES_VIEWER:
+ case osd::debugger::WINDOW_TYPE_DEVICES_VIEWER:
win = [[MAMEDevicesViewer alloc] initWithMachine:*machine console:self];
break;
- case MAME_DEBUGGER_WINDOW_TYPE_DEVICE_INFO_VIEWER:
- // FIXME: needs device info on init, make another variant
- //win = [[MAMEDeviceInfoViewer alloc] initWithMachine:*machine console:self];
+ case osd::debugger::WINDOW_TYPE_DEVICE_INFO_VIEWER:
+ {
+ // FIXME: feels like a leaky abstraction, but device is needed for init
+ device_t *const device = machine->root_device().subdevice(node->get_attribute_string(osd::debugger::ATTR_WINDOW_DEVICE_TAG, ":"));
+ win = [[MAMEDeviceInfoViewer alloc] initWithDevice:(device ? *device : machine->root_device()) machine:*machine console:self];
+ }
break;
default:
break;
@@ -422,34 +432,36 @@
- (void)saveConfigurationToNode:(util::xml::data_node *)node {
[super saveConfigurationToNode:node];
- node->set_attribute_int("type", MAME_DEBUGGER_WINDOW_TYPE_CONSOLE);
- util::xml::data_node *const splits = node->add_child("splits", nullptr);
+ node->set_attribute_int(osd::debugger::ATTR_WINDOW_TYPE, osd::debugger::WINDOW_TYPE_CONSOLE);
+ util::xml::data_node *const splits = node->add_child(osd::debugger::NODE_WINDOW_SPLITS, nullptr);
if (splits)
{
- splits->set_attribute_float("state",
+ splits->set_attribute_float(osd::debugger::ATTR_SPLITS_CONSOLE_STATE,
[regSplit isSubviewCollapsed:[[regSplit subviews] objectAtIndex:0]]
? 0.0
: NSMaxX([[[regSplit subviews] objectAtIndex:0] frame]));
- splits->set_attribute_float("disassembly",
+ splits->set_attribute_float(osd::debugger::ATTR_SPLITS_CONSOLE_DISASSEMBLY,
[dasmSplit isSubviewCollapsed:[[dasmSplit subviews] objectAtIndex:0]]
? 0.0
: NSMaxY([[[dasmSplit subviews] objectAtIndex:0] frame]));
}
[dasmView saveConfigurationToNode:node];
+ [history saveConfigurationToNode:node];
}
- (void)restoreConfigurationFromNode:(util::xml::data_node const *)node {
[super restoreConfigurationFromNode:node];
- util::xml::data_node const *const splits = node->get_child("splits");
+ util::xml::data_node const *const splits = node->get_child(osd::debugger::NODE_WINDOW_SPLITS);
if (splits)
{
- [regSplit setPosition:splits->get_attribute_float("state", NSMaxX([[[regSplit subviews] objectAtIndex:0] frame]))
+ [regSplit setPosition:splits->get_attribute_float(osd::debugger::ATTR_SPLITS_CONSOLE_STATE, NSMaxX([[[regSplit subviews] objectAtIndex:0] frame]))
ofDividerAtIndex:0];
- [dasmSplit setPosition:splits->get_attribute_float("disassembly", NSMaxY([[[dasmSplit subviews] objectAtIndex:0] frame]))
+ [dasmSplit setPosition:splits->get_attribute_float(osd::debugger::ATTR_SPLITS_CONSOLE_DISASSEMBLY, NSMaxY([[[dasmSplit subviews] objectAtIndex:0] frame]))
ofDividerAtIndex:0];
}
[dasmView restoreConfigurationFromNode:node];
+ [history restoreConfigurationFromNode:node];
}
@@ -499,7 +511,7 @@
[[NSNotificationCenter defaultCenter] postNotificationName:MAMEHideDebuggerNotification
object:self
userInfo:info];
- machine->debugger().cpu().get_visible_cpu()->debug()->go();
+ machine->debugger().console().get_visible_cpu()->debug()->go();
}
}
@@ -562,9 +574,9 @@
SEL const action = [item action];
BOOL const inContextMenu = ([item menu] == [dasmView menu]);
BOOL const haveCursor = [dasmView cursorVisible];
- BOOL const isCurrent = (machine->debugger().cpu().get_visible_cpu() == [dasmView source]->device());
+ BOOL const isCurrent = (machine->debugger().console().get_visible_cpu() == [dasmView source]->device());
- const device_debug::breakpoint *breakpoint = nullptr;
+ const debug_breakpoint *breakpoint = nullptr;
if (haveCursor)
{
breakpoint = [dasmView source]->device()->debug()->breakpoint_find([dasmView selectedAddress]);
diff --git a/src/osd/modules/debugger/osx/debugosx.h b/src/osd/modules/debugger/osx/debugosx.h
index 9d48402c032..6e0a47089d9 100644
--- a/src/osd/modules/debugger/osx/debugosx.h
+++ b/src/osd/modules/debugger/osx/debugosx.h
@@ -6,8 +6,13 @@
//
//============================================================
-#ifndef __SDL_DEBUGOSX__
-#define __SDL_DEBUGOSX__
+#ifndef MAME_OSD_DEBUGGER_OSX_DEBUGOSX_H
+#define MAME_OSD_DEBUGGER_OSX_DEBUGOSX_H
+
+#pragma once
+
+#include "../xmlconfig.h"
+
#define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
@@ -20,30 +25,6 @@
// standard Cocoa headers
#import <Cocoa/Cocoa.h>
-// workarounds for 10.6 warnings
-#ifdef MAC_OS_X_VERSION_MAX_ALLOWED
-
-#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
-
-@protocol NSWindowDelegate <NSObject>
-@end
-
-@protocol NSSplitViewDelegate <NSObject>
-@end
-
-@protocol NSControlTextEditingDelegate <NSObject>
-@end
-
-@protocol NSTextFieldDelegate <NSControlTextEditingDelegate>
-@end
-
-@protocol NSOutlineViewDataSource <NSObject>
-@end
-
-#endif // MAC_OS_X_VERSION_MAX_ALLOWED < 1060
-
-#endif // MAC_OS_X_VERSION_MAX_ALLOWED
-
#endif // __OBJC__
-#endif // __SDL_DEBUGOSX__
+#endif // MAME_OSD_DEBUGGER_OSX_DEBUGOSX_H
diff --git a/src/osd/modules/debugger/osx/debugview.mm b/src/osd/modules/debugger/osx/debugview.mm
index f3e4c6b8b64..504eaab8fe3 100644
--- a/src/osd/modules/debugger/osx/debugview.mm
+++ b/src/osd/modules/debugger/osx/debugview.mm
@@ -10,13 +10,14 @@
#include "emu.h"
#include "debugger.h"
+#include "debug/debugcon.h"
#include "debug/debugcpu.h"
#include "modules/lib/osdobj_common.h"
#include "util/xmlfile.h"
-#include <string.h>
+#include <cstring>
static NSColor *DefaultForeground;
@@ -50,6 +51,26 @@ static void debugwin_view_update(debug_view &view, void *osdprivate)
@implementation MAMEDebugView
+ (void)initialize {
+ // 10.15 and better get full adaptive Dark Mode support
+#if defined(MAC_OS_X_VERSION_10_15) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_15
+ DefaultForeground = [[NSColor textColor] retain];
+ ChangedForeground = [[NSColor systemRedColor] retain];
+ CommentForeground = [[NSColor systemGreenColor] retain];
+ // DCA_INVALID and DCA_DISABLED currently are not set by the core, so these 4 are unused
+ InvalidForeground = [[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:1.0 alpha:1.0] retain];
+ DisabledChangedForeground = [[NSColor colorWithCalibratedRed:0.5 green:0.125 blue:0.125 alpha:1.0] retain];
+ DisabledInvalidForeground = [[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.5 alpha:1.0] retain];
+ DisabledCommentForeground = [[NSColor colorWithCalibratedRed:0.0 green:0.25 blue:0.0 alpha:1.0] retain];
+
+ DefaultBackground = [[NSColor textBackgroundColor] retain];
+ VisitedBackground = [[NSColor systemTealColor] retain];
+ AncillaryBackground = [[NSColor unemphasizedSelectedContentBackgroundColor] retain];
+ SelectedBackground = [[NSColor selectedContentBackgroundColor] retain];
+ CurrentBackground = [[NSColor selectedControlColor] retain];
+ SelectedCurrentBackground = [[NSColor unemphasizedSelectedContentBackgroundColor] retain];
+ InactiveSelectedBackground = [[NSColor unemphasizedSelectedContentBackgroundColor] retain];
+ InactiveSelectedCurrentBackground = [[NSColor systemGrayColor] retain];
+#else
DefaultForeground = [[NSColor colorWithCalibratedWhite:0.0 alpha:1.0] retain];
ChangedForeground = [[NSColor colorWithCalibratedRed:0.875 green:0.0 blue:0.0 alpha:1.0] retain];
InvalidForeground = [[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:1.0 alpha:1.0] retain];
@@ -66,6 +87,7 @@ static void debugwin_view_update(debug_view &view, void *osdprivate)
SelectedCurrentBackground = [[NSColor colorWithCalibratedRed:0.875 green:0.625 blue:0.875 alpha:1.0] retain];
InactiveSelectedBackground = [[NSColor colorWithCalibratedWhite:0.875 alpha:1.0] retain];
InactiveSelectedCurrentBackground = [[NSColor colorWithCalibratedRed:0.875 green:0.5 blue:0.625 alpha:1.0] retain];
+#endif
NonWhiteCharacters = [[[NSCharacterSet whitespaceAndNewlineCharacterSet] invertedSet] retain];
}
@@ -255,7 +277,7 @@ static void debugwin_view_update(debug_view &view, void *osdprivate)
[self setFont:[[self class] defaultFontForMachine:m]];
- NSMenu *contextMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Context"];
+ NSMenu *contextMenu = [[NSMenu alloc] initWithTitle:@"Context"];
[self addContextMenuItemsToMenu:contextMenu];
[self setMenu:contextMenu];
[contextMenu release];
@@ -410,15 +432,15 @@ static void debugwin_view_update(debug_view &view, void *osdprivate)
NSRange const run = NSMakeRange(0, [text length]);
[text addAttribute:NSFontAttributeName value:font range:run];
NSPasteboard *const board = [NSPasteboard generalPasteboard];
- [board declareTypes:[NSArray arrayWithObject:NSRTFPboardType] owner:nil];
- [board setData:[text RTFFromRange:run documentAttributes:[NSDictionary dictionary]] forType:NSRTFPboardType];
+ [board declareTypes:[NSArray arrayWithObject:NSPasteboardTypeRTF] owner:nil];
+ [board setData:[text RTFFromRange:run documentAttributes:[NSDictionary dictionary]] forType:NSPasteboardTypeRTF];
[text deleteCharactersInRange:run];
}
- (IBAction)paste:(id)sender {
NSPasteboard *const board = [NSPasteboard generalPasteboard];
- NSString *const avail = [board availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]];
+ NSString *const avail = [board availableTypeFromArray:[NSArray arrayWithObject:NSPasteboardTypeString]];
if (avail == nil)
{
NSBeep();
@@ -492,22 +514,22 @@ static void debugwin_view_update(debug_view &view, void *osdprivate)
- (void)saveConfigurationToNode:(util::xml::data_node *)node {
if (view->cursor_supported())
{
- util::xml::data_node *const selection = node->add_child("selection", nullptr);
+ util::xml::data_node *const selection = node->add_child(osd::debugger::NODE_WINDOW_SELECTION, nullptr);
if (selection)
{
debug_view_xy const pos = view->cursor_position();
- selection->set_attribute_int("visible", view->cursor_visible() ? 1 : 0);
- selection->set_attribute_int("start_x", pos.x);
- selection->set_attribute_int("start_y", pos.y);
+ selection->set_attribute_int(osd::debugger::ATTR_SELECTION_CURSOR_VISIBLE, view->cursor_visible() ? 1 : 0);
+ selection->set_attribute_int(osd::debugger::ATTR_SELECTION_CURSOR_X, pos.x);
+ selection->set_attribute_int(osd::debugger::ATTR_SELECTION_CURSOR_Y, pos.y);
}
}
- util::xml::data_node *const scroll = node->add_child("scroll", nullptr);
+ util::xml::data_node *const scroll = node->add_child(osd::debugger::NODE_WINDOW_SCROLL, nullptr);
if (scroll)
{
NSRect const visible = [self visibleRect];
- scroll->set_attribute_float("position_x", visible.origin.x);
- scroll->set_attribute_float("position_y", visible.origin.y);
+ scroll->set_attribute_float(osd::debugger::ATTR_SCROLL_ORIGIN_X, visible.origin.x);
+ scroll->set_attribute_float(osd::debugger::ATTR_SCROLL_ORIGIN_Y, visible.origin.y);
}
}
@@ -515,23 +537,23 @@ static void debugwin_view_update(debug_view &view, void *osdprivate)
- (void)restoreConfigurationFromNode:(util::xml::data_node const *)node {
if (view->cursor_supported())
{
- util::xml::data_node const *const selection = node->get_child("selection");
+ util::xml::data_node const *const selection = node->get_child(osd::debugger::NODE_WINDOW_SELECTION);
if (selection)
{
debug_view_xy pos = view->cursor_position();
- view->set_cursor_visible(0 != selection->get_attribute_int("visible", view->cursor_visible() ? 1 : 0));
- pos.x = selection->get_attribute_int("start_x", pos.x);
- pos.y = selection->get_attribute_int("start_y", pos.y);
+ view->set_cursor_visible(0 != selection->get_attribute_int(osd::debugger::ATTR_SELECTION_CURSOR_VISIBLE, view->cursor_visible() ? 1 : 0));
+ pos.x = selection->get_attribute_int(osd::debugger::ATTR_SELECTION_CURSOR_X, pos.x);
+ pos.y = selection->get_attribute_int(osd::debugger::ATTR_SELECTION_CURSOR_Y, pos.y);
view->set_cursor_position(pos);
}
}
- util::xml::data_node const *const scroll = node->get_child("scroll");
+ util::xml::data_node const *const scroll = node->get_child(osd::debugger::NODE_WINDOW_SCROLL);
if (scroll)
{
NSRect visible = [self visibleRect];
- visible.origin.x = scroll->get_attribute_float("position_x", visible.origin.x);
- visible.origin.y = scroll->get_attribute_float("position_y", visible.origin.y);
+ visible.origin.x = scroll->get_attribute_float(osd::debugger::ATTR_SCROLL_ORIGIN_X, visible.origin.x);
+ visible.origin.y = scroll->get_attribute_float(osd::debugger::ATTR_SCROLL_ORIGIN_Y, visible.origin.y);
[self scrollRectToVisible:visible];
}
}
@@ -674,7 +696,7 @@ static void debugwin_view_update(debug_view &view, void *osdprivate)
NSUInteger start = 0, length = 0;
for (uint32_t col = origin.x; col < origin.x + size.x; col++)
{
- [[text mutableString] appendFormat:@"%c", data[col - origin.x].byte];
+ [[text mutableString] appendFormat:@"%C", unichar(data[col - origin.x].byte)];
if ((start < length) && (attr != data[col - origin.x].attrib))
{
NSRange const run = NSMakeRange(start, length - start);
@@ -742,8 +764,8 @@ static void debugwin_view_update(debug_view &view, void *osdprivate)
- (void)mouseDown:(NSEvent *)event {
NSPoint const location = [self convertPoint:[event locationInWindow] fromView:nil];
NSUInteger const modifiers = [event modifierFlags];
- view->process_click(((modifiers & NSCommandKeyMask) && [[self window] isMainWindow]) ? DCK_RIGHT_CLICK
- : (modifiers & NSAlternateKeyMask) ? DCK_MIDDLE_CLICK
+ view->process_click(((modifiers & NSEventModifierFlagCommand) && [[self window] isMainWindow]) ? DCK_RIGHT_CLICK
+ : (modifiers & NSEventModifierFlagOption) ? DCK_MIDDLE_CLICK
: DCK_LEFT_CLICK,
[self convertLocation:location]);
}
@@ -754,8 +776,8 @@ static void debugwin_view_update(debug_view &view, void *osdprivate)
NSPoint const location = [self convertPoint:[event locationInWindow] fromView:nil];
NSUInteger const modifiers = [event modifierFlags];
if (view->cursor_supported()
- && !(modifiers & NSAlternateKeyMask)
- && (!(modifiers & NSCommandKeyMask) || ![[self window] isMainWindow]))
+ && !(modifiers & NSEventModifierFlagOption)
+ && (!(modifiers & NSEventModifierFlagCommand) || ![[self window] isMainWindow]))
{
view->set_cursor_position([self convertLocation:location]);
view->set_cursor_visible(true);
@@ -782,34 +804,34 @@ static void debugwin_view_update(debug_view &view, void *osdprivate)
if ([str length] == 1)
{
- if (modifiers & NSNumericPadKeyMask)
+ if (modifiers & NSEventModifierFlagNumericPad)
{
switch ([str characterAtIndex:0])
{
case NSUpArrowFunctionKey:
- if (modifiers & NSCommandKeyMask)
+ if (modifiers & NSEventModifierFlagCommand)
view->process_char(DCH_CTRLHOME);
else
view->process_char(DCH_UP);
return;
case NSDownArrowFunctionKey:
- if (modifiers & NSCommandKeyMask)
+ if (modifiers & NSEventModifierFlagCommand)
view->process_char(DCH_CTRLEND);
else
view->process_char(DCH_DOWN);
return;
case NSLeftArrowFunctionKey:
- if (modifiers & NSCommandKeyMask)
+ if (modifiers & NSEventModifierFlagCommand)
[self typeCharacterAndScrollToCursor:DCH_HOME];
- else if (modifiers & NSAlternateKeyMask)
+ else if (modifiers & NSEventModifierFlagOption)
[self typeCharacterAndScrollToCursor:DCH_CTRLLEFT];
else
[self typeCharacterAndScrollToCursor:DCH_LEFT];
return;
case NSRightArrowFunctionKey:
- if (modifiers & NSCommandKeyMask)
+ if (modifiers & NSEventModifierFlagCommand)
[self typeCharacterAndScrollToCursor:DCH_END];
- else if (modifiers & NSAlternateKeyMask)
+ else if (modifiers & NSEventModifierFlagOption)
[self typeCharacterAndScrollToCursor:DCH_CTRLRIGHT];
else
[self typeCharacterAndScrollToCursor:DCH_RIGHT];
@@ -819,18 +841,18 @@ static void debugwin_view_update(debug_view &view, void *osdprivate)
return;
}
}
- else if (modifiers & NSFunctionKeyMask)
+ else if (modifiers & NSEventModifierFlagFunction)
{
switch ([str characterAtIndex:0])
{
case NSPageUpFunctionKey:
- if (modifiers & NSAlternateKeyMask)
+ if (modifiers & NSEventModifierFlagOption)
{
view->process_char(DCH_PUP);
return;
}
case NSPageDownFunctionKey:
- if (modifiers & NSAlternateKeyMask)
+ if (modifiers & NSEventModifierFlagOption)
{
view->process_char(DCH_PDOWN);
return;
@@ -871,7 +893,7 @@ static void debugwin_view_update(debug_view &view, void *osdprivate)
- (void)insertNewline:(id)sender {
- machine->debugger().cpu().get_visible_cpu()->debug()->single_step();
+ machine->debugger().console().get_visible_cpu()->debug()->single_step();
}
@@ -899,7 +921,7 @@ static void debugwin_view_update(debug_view &view, void *osdprivate)
if (action == @selector(paste:))
{
NSPasteboard *const board = [NSPasteboard generalPasteboard];
- return [board availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]] != nil;
+ return [board availableTypeFromArray:[NSArray arrayWithObject:NSPasteboardTypeString]] != nil;
}
else
{
diff --git a/src/osd/modules/debugger/osx/debugwindowhandler.h b/src/osd/modules/debugger/osx/debugwindowhandler.h
index c48bbb031b2..00c7327f2ba 100644
--- a/src/osd/modules/debugger/osx/debugwindowhandler.h
+++ b/src/osd/modules/debugger/osx/debugwindowhandler.h
@@ -23,19 +23,6 @@ extern NSString *const MAMEAuxiliaryDebugWindowWillCloseNotification;
extern NSString *const MAMESaveDebuggerConfigurationNotification;
-// for compatibility with the Qt debugger
-enum
-{
- MAME_DEBUGGER_WINDOW_TYPE_CONSOLE = 1,
- MAME_DEBUGGER_WINDOW_TYPE_MEMORY_VIEWER,
- MAME_DEBUGGER_WINDOW_TYPE_DISASSEMBLY_VIEWER,
- MAME_DEBUGGER_WINDOW_TYPE_ERROR_LOG_VIEWER,
- MAME_DEBUGGER_WINDOW_TYPE_POINTS_VIEWER,
- MAME_DEBUGGER_WINDOW_TYPE_DEVICES_VIEWER,
- MAME_DEBUGGER_WINDOW_TYPE_DEVICE_INFO_VIEWER
-};
-
-
@interface MAMEDebugWindowHandler : NSObject <NSWindowDelegate>
{
NSWindow *window;
diff --git a/src/osd/modules/debugger/osx/debugwindowhandler.mm b/src/osd/modules/debugger/osx/debugwindowhandler.mm
index 27d487c86ff..1341f420ed9 100644
--- a/src/osd/modules/debugger/osx/debugwindowhandler.mm
+++ b/src/osd/modules/debugger/osx/debugwindowhandler.mm
@@ -14,6 +14,7 @@
#import "debugview.h"
#include "debugger.h"
+#include "debug/debugcon.h"
#include "util/xmlfile.h"
@@ -42,7 +43,7 @@ NSString *const MAMESaveDebuggerConfigurationNotification = @"MAMESaveDebuggerCo
NSMenuItem *runParentItem = [menu addItemWithTitle:@"Run"
action:@selector(debugRun:)
keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF5FunctionKey]];
- NSMenu *runMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Run"];
+ NSMenu *runMenu = [[NSMenu alloc] initWithTitle:@"Run"];
[runParentItem setSubmenu:runMenu];
[runMenu release];
[runParentItem setKeyEquivalentModifierMask:0];
@@ -64,7 +65,7 @@ NSString *const MAMESaveDebuggerConfigurationNotification = @"MAMESaveDebuggerCo
setKeyEquivalentModifierMask:0];
NSMenuItem *stepParentItem = [menu addItemWithTitle:@"Step" action:NULL keyEquivalent:@""];
- NSMenu *stepMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Step"];
+ NSMenu *stepMenu = [[NSMenu alloc] initWithTitle:@"Step"];
[stepParentItem setSubmenu:stepMenu];
[stepMenu release];
[[stepMenu addItemWithTitle:@"Into"
@@ -78,10 +79,10 @@ NSString *const MAMESaveDebuggerConfigurationNotification = @"MAMESaveDebuggerCo
[[stepMenu addItemWithTitle:@"Out"
action:@selector(debugStepOut:)
keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF10FunctionKey]]
- setKeyEquivalentModifierMask:NSShiftKeyMask];
+ setKeyEquivalentModifierMask:NSEventModifierFlagShift];
NSMenuItem *resetParentItem = [menu addItemWithTitle:@"Reset" action:NULL keyEquivalent:@""];
- NSMenu *resetMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Reset"];
+ NSMenu *resetMenu = [[NSMenu alloc] initWithTitle:@"Reset"];
[resetParentItem setSubmenu:resetMenu];
[resetMenu release];
[[resetMenu addItemWithTitle:@"Soft"
@@ -91,12 +92,12 @@ NSString *const MAMESaveDebuggerConfigurationNotification = @"MAMESaveDebuggerCo
[[resetMenu addItemWithTitle:@"Hard"
action:@selector(debugHardReset:)
keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF3FunctionKey]]
- setKeyEquivalentModifierMask:NSShiftKeyMask];
+ setKeyEquivalentModifierMask:NSEventModifierFlagShift];
[menu addItem:[NSMenuItem separatorItem]];
NSMenuItem *newParentItem = [menu addItemWithTitle:@"New" action:NULL keyEquivalent:@""];
- NSMenu *newMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"New"];
+ NSMenu *newMenu = [[NSMenu alloc] initWithTitle:@"New"];
[newParentItem setSubmenu:newMenu];
[newMenu release];
[newMenu addItemWithTitle:@"Memory Window"
@@ -113,7 +114,7 @@ NSString *const MAMESaveDebuggerConfigurationNotification = @"MAMESaveDebuggerCo
keyEquivalent:@"b"];
[newMenu addItemWithTitle:@"Devices Window"
action:@selector(debugNewDevicesWindow:)
- keyEquivalent:@"D"];
+ keyEquivalent:@""];
[menu addItem:[NSMenuItem separatorItem]];
@@ -126,7 +127,7 @@ NSString *const MAMESaveDebuggerConfigurationNotification = @"MAMESaveDebuggerCo
NSPopUpButton *actionButton = [[NSPopUpButton alloc] initWithFrame:frame pullsDown:YES];
[actionButton setTitle:@""];
[actionButton addItemWithTitle:@""];
- [actionButton setBezelStyle:NSShadowlessSquareBezelStyle];
+ [actionButton setBezelStyle:NSBezelStyleShadowlessSquare];
[actionButton setFocusRingType:NSFocusRingTypeNone];
[[actionButton cell] setArrowPosition:NSPopUpArrowAtCenter];
[[self class] addCommonActionItems:[actionButton menu]];
@@ -139,10 +140,10 @@ NSString *const MAMESaveDebuggerConfigurationNotification = @"MAMESaveDebuggerCo
return nil;
window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 320, 240)
- styleMask:(NSTitledWindowMask |
- NSClosableWindowMask |
- NSMiniaturizableWindowMask |
- NSResizableWindowMask)
+ styleMask:(NSWindowStyleMaskTitled |
+ NSWindowStyleMaskClosable |
+ NSWindowStyleMaskMiniaturizable |
+ NSWindowStyleMaskResizable)
backing:NSBackingStoreBuffered
defer:YES];
[window setReleasedWhenClosed:NO];
@@ -189,12 +190,12 @@ NSString *const MAMESaveDebuggerConfigurationNotification = @"MAMESaveDebuggerCo
- (IBAction)debugBreak:(id)sender {
if (machine->debug_flags & DEBUG_FLAG_ENABLED)
- machine->debugger().cpu().get_visible_cpu()->debug()->halt_on_next_instruction("User-initiated break\n");
+ machine->debugger().console().get_visible_cpu()->debug()->halt_on_next_instruction("User-initiated break\n");
}
- (IBAction)debugRun:(id)sender {
- machine->debugger().cpu().get_visible_cpu()->debug()->go();
+ machine->debugger().console().get_visible_cpu()->debug()->go();
}
@@ -203,43 +204,43 @@ NSString *const MAMESaveDebuggerConfigurationNotification = @"MAMESaveDebuggerCo
object:self
userInfo:[NSDictionary dictionaryWithObject:[NSValue valueWithPointer:machine]
forKey:@"MAMEDebugMachine"]];
- machine->debugger().cpu().get_visible_cpu()->debug()->go();
+ machine->debugger().console().get_visible_cpu()->debug()->go();
}
- (IBAction)debugRunToNextCPU:(id)sender {
- machine->debugger().cpu().get_visible_cpu()->debug()->go_next_device();
+ machine->debugger().console().get_visible_cpu()->debug()->go_next_device();
}
- (IBAction)debugRunToNextInterrupt:(id)sender {
- machine->debugger().cpu().get_visible_cpu()->debug()->go_interrupt();
+ machine->debugger().console().get_visible_cpu()->debug()->go_interrupt();
}
- (IBAction)debugRunToNextVBLANK:(id)sender {
- machine->debugger().cpu().get_visible_cpu()->debug()->go_vblank();
+ machine->debugger().console().get_visible_cpu()->debug()->go_vblank();
}
- (IBAction)debugStepInto:(id)sender {
- machine->debugger().cpu().get_visible_cpu()->debug()->single_step();
+ machine->debugger().console().get_visible_cpu()->debug()->single_step();
}
- (IBAction)debugStepOver:(id)sender {
- machine->debugger().cpu().get_visible_cpu()->debug()->single_step_over();
+ machine->debugger().console().get_visible_cpu()->debug()->single_step_over();
}
- (IBAction)debugStepOut:(id)sender {
- machine->debugger().cpu().get_visible_cpu()->debug()->single_step_out();
+ machine->debugger().console().get_visible_cpu()->debug()->single_step_out();
}
- (IBAction)debugSoftReset:(id)sender {
machine->schedule_soft_reset();
- machine->debugger().cpu().get_visible_cpu()->debug()->go();
+ machine->debugger().console().get_visible_cpu()->debug()->go();
}
@@ -275,7 +276,7 @@ NSString *const MAMESaveDebuggerConfigurationNotification = @"MAMESaveDebuggerCo
if (m == machine)
{
util::xml::data_node *parentnode = (util::xml::data_node *)[[[notification userInfo] objectForKey:@"MAMEDebugParentNode"] pointerValue];
- util::xml::data_node *node = parentnode->add_child("window", nullptr);
+ util::xml::data_node *node = parentnode->add_child(osd::debugger::NODE_WINDOW, nullptr);
if (node)
[self saveConfigurationToNode:node];
}
@@ -284,19 +285,19 @@ NSString *const MAMESaveDebuggerConfigurationNotification = @"MAMESaveDebuggerCo
- (void)saveConfigurationToNode:(util::xml::data_node *)node {
NSRect frame = [window frame];
- node->set_attribute_float("position_x", frame.origin.x);
- node->set_attribute_float("position_y", frame.origin.y);
- node->set_attribute_float("size_x", frame.size.width);
- node->set_attribute_float("size_y", frame.size.height);
+ node->set_attribute_float(osd::debugger::ATTR_WINDOW_POSITION_X, frame.origin.x);
+ node->set_attribute_float(osd::debugger::ATTR_WINDOW_POSITION_Y, frame.origin.y);
+ node->set_attribute_float(osd::debugger::ATTR_WINDOW_WIDTH, frame.size.width);
+ node->set_attribute_float(osd::debugger::ATTR_WINDOW_HEIGHT, frame.size.height);
}
- (void)restoreConfigurationFromNode:(util::xml::data_node const *)node {
NSRect frame = [window frame];
- frame.origin.x = node->get_attribute_float("position_x", frame.origin.x);
- frame.origin.y = node->get_attribute_float("position_y", frame.origin.y);
- frame.size.width = node->get_attribute_float("size_x", frame.size.width);
- frame.size.height = node->get_attribute_float("size_y", frame.size.height);
+ frame.origin.x = node->get_attribute_float(osd::debugger::ATTR_WINDOW_POSITION_X, frame.origin.x);
+ frame.origin.y = node->get_attribute_float(osd::debugger::ATTR_WINDOW_POSITION_Y, frame.origin.y);
+ frame.size.width = node->get_attribute_float(osd::debugger::ATTR_WINDOW_WIDTH, frame.size.width);
+ frame.size.height = node->get_attribute_float(osd::debugger::ATTR_WINDOW_HEIGHT, frame.size.height);
NSSize min = [window minSize];
frame.size.width = std::max(frame.size.width, min.width);
@@ -492,15 +493,17 @@ NSString *const MAMESaveDebuggerConfigurationNotification = @"MAMESaveDebuggerCo
- (void)saveConfigurationToNode:(util::xml::data_node *)node {
[super saveConfigurationToNode:node];
- node->add_child("expression", util::xml::normalize_string([[self expression] UTF8String]));
+ node->add_child(osd::debugger::NODE_WINDOW_EXPRESSION, [[self expression] UTF8String]);
+ [history saveConfigurationToNode:node];
}
- (void)restoreConfigurationFromNode:(util::xml::data_node const *)node {
[super restoreConfigurationFromNode:node];
- util::xml::data_node const *const expr = node->get_child("expression");
+ util::xml::data_node const *const expr = node->get_child(osd::debugger::NODE_WINDOW_EXPRESSION);
if (expr && expr->get_value())
[self setExpression:[NSString stringWithUTF8String:expr->get_value()]];
+ [history restoreConfigurationFromNode:node];
}
@end
diff --git a/src/osd/modules/debugger/osx/deviceinfoviewer.mm b/src/osd/modules/debugger/osx/deviceinfoviewer.mm
index 61fdd8c8613..12f1ea1957a 100644
--- a/src/osd/modules/debugger/osx/deviceinfoviewer.mm
+++ b/src/osd/modules/debugger/osx/deviceinfoviewer.mm
@@ -54,14 +54,14 @@
- (NSTextField *)makeLabel:(NSString *)text {
NSTextField *const result = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 14)];
[result setAutoresizingMask:(NSViewMaxYMargin | NSViewMaxXMargin)];
- [[result cell] setControlSize:NSSmallControlSize];
+ [[result cell] setControlSize:NSControlSizeSmall];
[result setEditable:NO];
[result setSelectable:NO];
[result setBezeled:NO];
[result setBordered:NO];
[result setDrawsBackground:NO];
- [result setAlignment:NSRightTextAlignment];
- [result setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]];
+ [result setAlignment:NSTextAlignmentRight];
+ [result setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSControlSizeSmall]]];
[result setStringValue:text];
[result sizeToFit];
return result;
@@ -71,14 +71,14 @@
- (NSTextField *)makeField:(NSString *)text {
NSTextField *const result = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 14)];
[result setAutoresizingMask:(NSViewWidthSizable | NSViewMaxYMargin)];
- [[result cell] setControlSize:NSSmallControlSize];
+ [[result cell] setControlSize:NSControlSizeSmall];
[result setEditable:NO];
[result setSelectable:YES];
[result setBezeled:NO];
[result setBordered:NO];
[result setDrawsBackground:NO];
- [result setAlignment:NSLeftTextAlignment];
- [result setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]];
+ [result setAlignment:NSTextAlignmentLeft];
+ [result setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSControlSizeSmall]]];
[result setStringValue:text];
[result sizeToFit];
return result;
@@ -210,9 +210,11 @@
// create a scroll view for holding everything
NSSize desired = [NSScrollView frameSizeForContentSize:[contentView frame].size
- hasHorizontalScroller:YES
- hasVerticalScroller:YES
- borderType:NSNoBorder];
+ horizontalScrollerClass:[NSScroller class]
+ verticalScrollerClass:[NSScroller class]
+ borderType:NSNoBorder
+ controlSize:NSControlSizeRegular
+ scrollerStyle:NSScrollerStyleOverlay];
[window setContentSize:desired];
contentScroll = [[NSScrollView alloc] initWithFrame:[[window contentView] bounds]];
[contentScroll setDrawsBackground:NO];
@@ -237,7 +239,8 @@
- (void)saveConfigurationToNode:(util::xml::data_node *)node {
[super saveConfigurationToNode:node];
- node->set_attribute_int("type", MAME_DEBUGGER_WINDOW_TYPE_DEVICE_INFO_VIEWER);
+ node->set_attribute_int(osd::debugger::ATTR_WINDOW_TYPE, osd::debugger::WINDOW_TYPE_DEVICE_INFO_VIEWER);
+ node->set_attribute(osd::debugger::ATTR_WINDOW_DEVICE_TAG, device->tag());
}
@end
diff --git a/src/osd/modules/debugger/osx/devicesviewer.mm b/src/osd/modules/debugger/osx/devicesviewer.mm
index 23dba724b9d..02f63a41a6b 100644
--- a/src/osd/modules/debugger/osx/devicesviewer.mm
+++ b/src/osd/modules/debugger/osx/devicesviewer.mm
@@ -161,9 +161,11 @@
// calculate the optimal size for everything
NSSize const desired = [NSScrollView frameSizeForContentSize:NSMakeSize(480, 320)
- hasHorizontalScroller:YES
- hasVerticalScroller:YES
- borderType:[devicesScroll borderType]];
+ horizontalScrollerClass:[NSScroller class]
+ verticalScrollerClass:[NSScroller class]
+ borderType:[devicesScroll borderType]
+ controlSize:NSControlSizeRegular
+ scrollerStyle:NSScrollerStyleOverlay];
[self cascadeWindowWithDesiredSize:desired forView:devicesScroll];
// don't forget the result
@@ -185,7 +187,7 @@
- (void)saveConfigurationToNode:(util::xml::data_node *)node {
[super saveConfigurationToNode:node];
- node->set_attribute_int("type", MAME_DEBUGGER_WINDOW_TYPE_DEVICES_VIEWER);
+ node->set_attribute_int(osd::debugger::ATTR_WINDOW_TYPE, osd::debugger::WINDOW_TYPE_DEVICES_VIEWER);
}
diff --git a/src/osd/modules/debugger/osx/disassemblyview.mm b/src/osd/modules/debugger/osx/disassemblyview.mm
index 99bdc485147..c501d17230a 100644
--- a/src/osd/modules/debugger/osx/disassemblyview.mm
+++ b/src/osd/modules/debugger/osx/disassemblyview.mm
@@ -46,7 +46,7 @@
- (NSSize)maximumFrameSize {
debug_view_xy max(0, 0);
debug_view_source const *source = view->source();
- for (debug_view_source const *source = view->first_source(); source != nullptr; source = source->next())
+ for (auto &source : view->source_list())
{
view->set_source(*source);
debug_view_xy const current = view->total_size();
@@ -75,7 +75,7 @@
item = [menu addItemWithTitle:@"Disable Breakpoint"
action:@selector(debugToggleBreakpointEnable:)
keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF9FunctionKey]];
- [item setKeyEquivalentModifierMask:NSShiftKeyMask];
+ [item setKeyEquivalentModifierMask:NSEventModifierFlagShift];
[menu addItem:[NSMenuItem separatorItem]];
@@ -118,18 +118,23 @@
- (int)selectedSubviewIndex {
const debug_view_source *source = view->source();
if (source != nullptr)
- return view->source_list().indexof(*source);
+ return view->source_index(*source);
else
return -1;
}
- (void)selectSubviewAtIndex:(int)index {
- const int selected = view->source_list().indexof(*view->source());
- if (selected != index) {
- view->set_source(*view->source_list().find(index));
- if ([[self window] firstResponder] != self)
- view->set_cursor_visible(false);
+ const int selected = [self selectedSubviewIndex];
+ if (selected != index)
+ {
+ const debug_view_source *source = view->source(index);
+ if (source != nullptr)
+ {
+ view->set_source(*source);
+ if ([[self window] firstResponder] != self)
+ view->set_cursor_visible(false);
+ }
}
}
@@ -155,23 +160,21 @@
- (BOOL)selectSubviewForSpace:(address_space *)space {
if (space == nullptr) return NO;
- debug_view_disasm_source const *source = downcast<debug_view_disasm_source const *>(view->first_source());
- while ((source != nullptr) && (&source->space() != space))
- source = downcast<debug_view_disasm_source *>(source->next());
- if (source != nullptr)
+ for (auto &ptr : view->source_list())
{
- if (view->source() != source)
+ debug_view_disasm_source const *const source = downcast<debug_view_disasm_source const *>(ptr.get());
+ if (&source->space() == space)
{
- view->set_source(*source);
- if ([[self window] firstResponder] != self)
- view->set_cursor_visible(false);
+ if (view->source() != source)
+ {
+ view->set_source(*source);
+ if ([[self window] firstResponder] != self)
+ view->set_cursor_visible(false);
+ }
+ return YES;
}
- return YES;
- }
- else
- {
- return NO;
}
+ return NO;
}
@@ -211,7 +214,7 @@
action:@selector(debugToggleBreakpointEnable:)
keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF9FunctionKey]
atIndex:index++];
- [disableItem setKeyEquivalentModifierMask:NSShiftKeyMask];
+ [disableItem setKeyEquivalentModifierMask:NSEventModifierFlagShift];
NSMenu *runMenu = [[menu itemWithTitle:@"Run"] submenu];
NSMenuItem *runItem;
@@ -256,12 +259,12 @@
- (void)insertSubviewItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index {
- for (const debug_view_source *source = view->source_list().first(); source != nullptr; source = source->next())
+ for (auto &source : view->source_list())
{
[[menu insertItemWithTitle:[NSString stringWithUTF8String:source->name()]
action:NULL
keyEquivalent:@""
- atIndex:index++] setTag:view->source_list().indexof(*source)];
+ atIndex:index++] setTag:view->source_index(*source)];
}
if (index < [menu numberOfItems])
[menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
@@ -271,14 +274,14 @@
- (void)saveConfigurationToNode:(util::xml::data_node *)node {
[super saveConfigurationToNode:node];
debug_view_disasm *const dasmView = downcast<debug_view_disasm *>(view);
- node->set_attribute_int("rightbar", dasmView->right_column());
+ node->set_attribute_int(osd::debugger::ATTR_WINDOW_DISASSEMBLY_RIGHT_COLUMN, dasmView->right_column());
}
- (void)restoreConfigurationFromNode:(util::xml::data_node const *)node {
[super restoreConfigurationFromNode:node];
debug_view_disasm *const dasmView = downcast<debug_view_disasm *>(view);
- dasmView->set_right_column((disasm_right_column)node->get_attribute_int("rightbar", dasmView->right_column()));
+ dasmView->set_right_column((disasm_right_column)node->get_attribute_int(osd::debugger::ATTR_WINDOW_DISASSEMBLY_RIGHT_COLUMN, dasmView->right_column()));
}
@end
diff --git a/src/osd/modules/debugger/osx/disassemblyviewer.mm b/src/osd/modules/debugger/osx/disassemblyviewer.mm
index eb039f4ca17..a0659c00cfc 100644
--- a/src/osd/modules/debugger/osx/disassemblyviewer.mm
+++ b/src/osd/modules/debugger/osx/disassemblyviewer.mm
@@ -16,6 +16,7 @@
#include "debugger.h"
#include "debug/debugcon.h"
#include "debug/debugcpu.h"
+#include "debug/points.h"
#include "util/xmlfile.h"
@@ -44,11 +45,9 @@
[expressionField sizeToFit];
// create the subview popup
- subviewButton = [[NSPopUpButton alloc] initWithFrame:NSOffsetRect(expressionFrame,
- expressionFrame.size.width,
- 0)];
+ subviewButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)];
[subviewButton setAutoresizingMask:(NSViewWidthSizable | NSViewMinXMargin | NSViewMinYMargin)];
- [subviewButton setBezelStyle:NSShadowlessSquareBezelStyle];
+ [subviewButton setBezelStyle:NSBezelStyleShadowlessSquare];
[subviewButton setFocusRingType:NSFocusRingTypeNone];
[subviewButton setFont:defaultFont];
[subviewButton setTarget:self];
@@ -109,7 +108,7 @@
[actionButton release];
// set default state
- [dasmView selectSubviewForDevice:machine->debugger().cpu().get_visible_cpu()];
+ [dasmView selectSubviewForDevice:machine->debugger().console().get_visible_cpu()];
[dasmView setExpression:@"curpc"];
[expressionField setStringValue:@"curpc"];
[expressionField selectText:self];
@@ -119,9 +118,11 @@
// calculate the optimal size for everything
NSSize const desired = [NSScrollView frameSizeForContentSize:[dasmView maximumFrameSize]
- hasHorizontalScroller:YES
- hasVerticalScroller:YES
- borderType:[dasmScroll borderType]];
+ horizontalScrollerClass:[NSScroller class]
+ verticalScrollerClass:[NSScroller class]
+ borderType:[dasmScroll borderType]
+ controlSize:NSControlSizeRegular
+ scrollerStyle:NSScrollerStyleOverlay];
[self cascadeWindowWithDesiredSize:desired forView:dasmScroll];
// don't forget the result
@@ -176,12 +177,12 @@
{
device_t &device = *[dasmView source]->device();
offs_t const address = [dasmView selectedAddress];
- const device_debug::breakpoint *bp = device.debug()->breakpoint_find(address);
+ const debug_breakpoint *bp = device.debug()->breakpoint_find(address);
// if it doesn't exist, add a new one
if (bp == nullptr)
{
- uint32_t const bpnum = device.debug()->breakpoint_set(address, nullptr, nullptr);
+ uint32_t const bpnum = device.debug()->breakpoint_set(address);
machine->debugger().console().printf("Breakpoint %X set\n", bpnum);
}
else
@@ -203,7 +204,7 @@
{
device_t &device = *[dasmView source]->device();
offs_t const address = [dasmView selectedAddress];
- const device_debug::breakpoint *bp = device.debug()->breakpoint_find(address);
+ const debug_breakpoint *bp = device.debug()->breakpoint_find(address);
if (bp != nullptr)
{
device.debug()->breakpoint_enable(bp->index(), !bp->enabled());
@@ -231,15 +232,15 @@
- (void)saveConfigurationToNode:(util::xml::data_node *)node {
[super saveConfigurationToNode:node];
- node->set_attribute_int("type", MAME_DEBUGGER_WINDOW_TYPE_DISASSEMBLY_VIEWER);
- node->set_attribute_int("cpu", [dasmView selectedSubviewIndex]);
+ node->set_attribute_int(osd::debugger::ATTR_WINDOW_TYPE, osd::debugger::WINDOW_TYPE_DISASSEMBLY_VIEWER);
+ node->set_attribute_int(osd::debugger::ATTR_WINDOW_DISASSEMBLY_CPU, [dasmView selectedSubviewIndex]);
[dasmView saveConfigurationToNode:node];
}
- (void)restoreConfigurationFromNode:(util::xml::data_node const *)node {
[super restoreConfigurationFromNode:node];
- int const region = node->get_attribute_int("cpu", [dasmView selectedSubviewIndex]);
+ int const region = node->get_attribute_int(osd::debugger::ATTR_WINDOW_DISASSEMBLY_CPU, [dasmView selectedSubviewIndex]);
[dasmView selectSubviewAtIndex:region];
[window setTitle:[NSString stringWithFormat:@"Disassembly: %@", [dasmView selectedSubviewName]]];
[subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[dasmView selectedSubviewIndex]]];
@@ -252,7 +253,7 @@
BOOL const inContextMenu = ([item menu] == [dasmView menu]);
BOOL const haveCursor = [dasmView cursorVisible];
- const device_debug::breakpoint *breakpoint = nullptr;
+ const debug_breakpoint *breakpoint = nullptr;
if (haveCursor)
{
breakpoint = [dasmView source]->device()->debug()->breakpoint_find([dasmView selectedAddress]);
diff --git a/src/osd/modules/debugger/osx/errorlogviewer.mm b/src/osd/modules/debugger/osx/errorlogviewer.mm
index 1fd12c9c9c1..68d6f312b7c 100644
--- a/src/osd/modules/debugger/osx/errorlogviewer.mm
+++ b/src/osd/modules/debugger/osx/errorlogviewer.mm
@@ -43,11 +43,13 @@
// calculate the optimal size for everything
{
NSSize desired = [NSScrollView frameSizeForContentSize:[logView maximumFrameSize]
- hasHorizontalScroller:YES
- hasVerticalScroller:YES
- borderType:[logScroll borderType]];
+ horizontalScrollerClass:[NSScroller class]
+ verticalScrollerClass:[NSScroller class]
+ borderType:[logScroll borderType]
+ controlSize:NSControlSizeRegular
+ scrollerStyle:NSScrollerStyleOverlay];
- // this thing starts with no content, so its prefered height may be very small
+ // this thing starts with no content, so its preferred height may be very small
desired.height = std::max(desired.height, CGFloat(240));
[self cascadeWindowWithDesiredSize:desired forView:logScroll];
}
@@ -64,7 +66,7 @@
- (void)saveConfigurationToNode:(util::xml::data_node *)node {
[super saveConfigurationToNode:node];
- node->set_attribute_int("type", MAME_DEBUGGER_WINDOW_TYPE_ERROR_LOG_VIEWER);
+ node->set_attribute_int(osd::debugger::ATTR_WINDOW_TYPE, osd::debugger::WINDOW_TYPE_ERROR_LOG_VIEWER);
}
@end
diff --git a/src/osd/modules/debugger/osx/exceptionpointsview.h b/src/osd/modules/debugger/osx/exceptionpointsview.h
new file mode 100644
index 00000000000..73e3958c9b8
--- /dev/null
+++ b/src/osd/modules/debugger/osx/exceptionpointsview.h
@@ -0,0 +1,23 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+//============================================================
+//
+// exceptionpointsview.h - MacOS X Cocoa debug window handling
+//
+//============================================================
+
+#import "debugosx.h"
+
+#import "debugview.h"
+
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface MAMEExceptionpointsView : MAMEDebugView
+{
+}
+
+- (id)initWithFrame:(NSRect)f machine:(running_machine &)m;
+
+@end
diff --git a/src/osd/modules/debugger/osx/exceptionpointsview.mm b/src/osd/modules/debugger/osx/exceptionpointsview.mm
new file mode 100644
index 00000000000..c15f9c56f4f
--- /dev/null
+++ b/src/osd/modules/debugger/osx/exceptionpointsview.mm
@@ -0,0 +1,27 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+//============================================================
+//
+// exceptionpointsview.m - MacOS X Cocoa debug window handling
+//
+//============================================================
+
+#import "exceptionpointsview.h"
+
+#include "debug/debugvw.h"
+
+
+@implementation MAMEExceptionpointsView
+
+- (id)initWithFrame:(NSRect)f machine:(running_machine &)m {
+ if (!(self = [super initWithFrame:f type:DVT_EXCEPTION_POINTS machine:m wholeLineScroll:YES]))
+ return nil;
+ return self;
+}
+
+
+- (void)dealloc {
+ [super dealloc];
+}
+
+@end
diff --git a/src/osd/modules/debugger/osx/memoryview.mm b/src/osd/modules/debugger/osx/memoryview.mm
index b2c512d094b..24521e81ba4 100644
--- a/src/osd/modules/debugger/osx/memoryview.mm
+++ b/src/osd/modules/debugger/osx/memoryview.mm
@@ -9,7 +9,6 @@
#include "emu.h"
#import "memoryview.h"
-#include "debug/debugcpu.h"
#include "debug/debugvw.h"
#include "util/xmlfile.h"
@@ -36,7 +35,7 @@
if (action == @selector(showChunkSize:))
{
- [item setState:((tag == memview->get_data_format()) ? NSOnState : NSOffState)];
+ [item setState:((tag == int(memview->get_data_format())) ? NSOnState : NSOffState)];
return YES;
}
else if (action == @selector(showPhysicalAddresses:))
@@ -58,6 +57,11 @@
{
return (memview->chunks_per_row() + [item tag]) > 0;
}
+ else if (action == @selector(showAddressRadix:))
+ {
+ [item setState:((memview->address_radix() == [item tag]) ? NSOnState : NSOffState)];
+ return YES;
+ }
else
{
return [super validateMenuItem:item];
@@ -68,7 +72,7 @@
- (NSSize)maximumFrameSize {
debug_view_xy max(0, 0);
debug_view_source const *source = view->source();
- for (debug_view_source const *source = view->first_source(); source != nullptr; source = source->next())
+ for (auto &source : view->source_list())
{
view->set_source(*source);
debug_view_xy const current = view->total_size();
@@ -101,19 +105,23 @@
- (int)selectedSubviewIndex {
debug_view_source const *source = view->source();
if (source != nullptr)
- return view->source_list().indexof(*source);
+ return view->source_index(*source);
else
return -1;
}
- (void)selectSubviewAtIndex:(int)index {
- int const selected = view->source_list().indexof(*view->source());
+ int const selected = [self selectedSubviewIndex];
if (selected != index)
{
- view->set_source(*view->source_list().find(index));
- if ([[self window] firstResponder] != self)
- view->set_cursor_visible(false);
+ const debug_view_source *source = view->source(index);
+ if (source != nullptr)
+ {
+ view->set_source(*source);
+ if ([[self window] firstResponder] != self)
+ view->set_cursor_visible(false);
+ }
}
}
@@ -139,23 +147,21 @@
- (BOOL)selectSubviewForSpace:(address_space *)space {
if (space == nullptr) return NO;
- debug_view_memory_source const *source = downcast<debug_view_memory_source const *>(view->first_source());
- while ((source != nullptr) && (source->space() != space))
- source = downcast<debug_view_memory_source *>(source->next());
- if (source != nullptr)
+ for (auto &ptr : view->source_list())
{
- if (view->source() != source)
+ debug_view_memory_source const *const source = downcast<debug_view_memory_source const *>(ptr.get());
+ if (source->space() == space)
{
- view->set_source(*source);
- if ([[self window] firstResponder] != self)
- view->set_cursor_visible(false);
+ if (view->source() != source)
+ {
+ view->set_source(*source);
+ if ([[self window] firstResponder] != self)
+ view->set_cursor_visible(false);
+ }
+ return YES;
}
- return YES;
- }
- else
- {
- return NO;
}
+ return NO;
}
@@ -175,7 +181,7 @@
- (IBAction)showChunkSize:(id)sender {
- downcast<debug_view_memory *>(view)->set_data_format([sender tag]);
+ downcast<debug_view_memory *>(view)->set_data_format(debug_view_memory::data_format([sender tag]));
}
@@ -183,6 +189,9 @@
downcast<debug_view_memory *>(view)->set_physical([sender tag]);
}
+- (IBAction)showAddressRadix:(id)sender {
+ downcast<debug_view_memory *>(view)->set_address_radix([sender tag]);
+}
- (IBAction)showReverseView:(id)sender {
downcast<debug_view_memory *>(view)->set_reverse([sender tag]);
@@ -203,55 +212,125 @@
- (void)saveConfigurationToNode:(util::xml::data_node *)node {
[super saveConfigurationToNode:node];
debug_view_memory *const memView = downcast<debug_view_memory *>(view);
- node->set_attribute_int("reverse", memView->reverse() ? 1 : 0);
- node->set_attribute_int("addressmode", memView->physical() ? 1 : 0);
- node->set_attribute_int("dataformat", memView->get_data_format());
- node->set_attribute_int("rowchunks", memView->chunks_per_row());
+ node->set_attribute_int(osd::debugger::ATTR_WINDOW_MEMORY_REVERSE_COLUMNS, memView->reverse() ? 1 : 0);
+ node->set_attribute_int(osd::debugger::ATTR_WINDOW_MEMORY_ADDRESS_MODE, memView->physical() ? 1 : 0);
+ node->get_attribute_int(osd::debugger::ATTR_WINDOW_MEMORY_ADDRESS_RADIX, memView->address_radix());
+ node->set_attribute_int(osd::debugger::ATTR_WINDOW_MEMORY_DATA_FORMAT, int(memView->get_data_format()));
+ node->set_attribute_int(osd::debugger::ATTR_WINDOW_MEMORY_ROW_CHUNKS, memView->chunks_per_row());
}
- (void)restoreConfigurationFromNode:(util::xml::data_node const *)node {
[super restoreConfigurationFromNode:node];
debug_view_memory *const memView = downcast<debug_view_memory *>(view);
- memView->set_reverse(0 != node->get_attribute_int("reverse", memView->reverse() ? 1 : 0));
- memView->set_physical(0 != node->get_attribute_int("addressmode", memView->physical() ? 1 : 0));
- memView->set_data_format(node->get_attribute_int("dataformat", memView->get_data_format()));
- memView->set_chunks_per_row(node->get_attribute_int("rowchunks", memView->chunks_per_row()));
+ memView->set_reverse(0 != node->get_attribute_int(osd::debugger::ATTR_WINDOW_MEMORY_REVERSE_COLUMNS, memView->reverse() ? 1 : 0));
+ memView->set_physical(0 != node->get_attribute_int(osd::debugger::ATTR_WINDOW_MEMORY_ADDRESS_MODE, memView->physical() ? 1 : 0));
+ memView->set_address_radix(node->get_attribute_int(osd::debugger::ATTR_WINDOW_MEMORY_ADDRESS_RADIX, memView->address_radix()));
+ memView->set_data_format(debug_view_memory::data_format(node->get_attribute_int(osd::debugger::ATTR_WINDOW_MEMORY_DATA_FORMAT, int(memView->get_data_format()))));
+ memView->set_chunks_per_row(node->get_attribute_int(osd::debugger::ATTR_WINDOW_MEMORY_ROW_CHUNKS, memView->chunks_per_row()));
}
- (void)insertActionItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index {
- NSInteger tag;
- for (tag = 1; tag <= 8; tag <<= 1) {
- NSString *title = [NSString stringWithFormat:@"%ld-byte Chunks", (long)tag];
- NSMenuItem *chunkItem = [menu insertItemWithTitle:title
- action:@selector(showChunkSize:)
- keyEquivalent:[NSString stringWithFormat:@"%ld", (long)tag]
- atIndex:index++];
- [chunkItem setTarget:self];
- [chunkItem setTag:tag];
- }
+ NSMenuItem *chunkItem1 = [menu insertItemWithTitle:@"1-byte Chunks (Hex)"
+ action:@selector(showChunkSize:)
+ keyEquivalent:@"1"
+ atIndex:index++];
+ [chunkItem1 setTarget:self];
+ [chunkItem1 setTag:int(debug_view_memory::data_format::HEX_8BIT)];
- NSMenuItem *chunkItem = [menu insertItemWithTitle:@"32-bit floats"
- action:@selector(showChunkSize:)
- keyEquivalent:@"F"
- atIndex:index++];
- [chunkItem setTarget:self];
- [chunkItem setTag:9];
-
- NSMenuItem *chunkItem2 = [menu insertItemWithTitle:@"64-bit floats"
- action:@selector(showChunkSize:)
- keyEquivalent:@"D"
- atIndex:index++];
+ NSMenuItem *chunkItem2 = [menu insertItemWithTitle:@"2-byte Chunks (Hex)"
+ action:@selector(showChunkSize:)
+ keyEquivalent:@"2"
+ atIndex:index++];
[chunkItem2 setTarget:self];
- [chunkItem2 setTag:10];
+ [chunkItem2 setTag:int(debug_view_memory::data_format::HEX_16BIT)];
+
+ NSMenuItem *chunkItem4 = [menu insertItemWithTitle:@"4-byte Chunks (Hex)"
+ action:@selector(showChunkSize:)
+ keyEquivalent:@"4"
+ atIndex:index++];
+ [chunkItem4 setTarget:self];
+ [chunkItem4 setTag:int(debug_view_memory::data_format::HEX_32BIT)];
+
+ NSMenuItem *chunkItem8 = [menu insertItemWithTitle:@"8-byte Chunks (Hex)"
+ action:@selector(showChunkSize:)
+ keyEquivalent:@"8"
+ atIndex:index++];
+ [chunkItem8 setTarget:self];
+ [chunkItem8 setTag:int(debug_view_memory::data_format::HEX_64BIT)];
+
+ NSMenuItem *chunkItem12 = [menu insertItemWithTitle:@"1-byte Chunks (Octal)"
+ action:@selector(showChunkSize:)
+ keyEquivalent:@"3"
+ atIndex:index++];
+ [chunkItem12 setTarget:self];
+ [chunkItem12 setTag:int(debug_view_memory::data_format::OCTAL_8BIT)];
+
+ NSMenuItem *chunkItem13 = [menu insertItemWithTitle:@"2-byte Chunks (Octal)"
+ action:@selector(showChunkSize:)
+ keyEquivalent:@"5"
+ atIndex:index++];
+ [chunkItem13 setTarget:self];
+ [chunkItem13 setTag:int(debug_view_memory::data_format::OCTAL_16BIT)];
+
+ NSMenuItem *chunkItem14 = [menu insertItemWithTitle:@"4-byte Chunks (Octal)"
+ action:@selector(showChunkSize:)
+ keyEquivalent:@"7"
+ atIndex:index++];
+ [chunkItem14 setTarget:self];
+ [chunkItem14 setTag:int(debug_view_memory::data_format::OCTAL_32BIT)];
+
+ NSMenuItem *chunkItem15 = [menu insertItemWithTitle:@"8-byte Chunks (Octal)"
+ action:@selector(showChunkSize:)
+ keyEquivalent:@"9"
+ atIndex:index++];
+ [chunkItem15 setTarget:self];
+ [chunkItem15 setTag:int(debug_view_memory::data_format::OCTAL_64BIT)];
+
+ NSMenuItem *chunkItem9 = [menu insertItemWithTitle:@"32-bit Floating Point"
+ action:@selector(showChunkSize:)
+ keyEquivalent:@"F"
+ atIndex:index++];
+ [chunkItem9 setTarget:self];
+ [chunkItem9 setTag:int(debug_view_memory::data_format::FLOAT_32BIT)];
+
+ NSMenuItem *chunkItem10 = [menu insertItemWithTitle:@"64-bit Floating Point"
+ action:@selector(showChunkSize:)
+ keyEquivalent:@"D"
+ atIndex:index++];
+ [chunkItem10 setTarget:self];
+ [chunkItem10 setTag:int(debug_view_memory::data_format::FLOAT_64BIT)];
+
+ NSMenuItem *chunkItem11 = [menu insertItemWithTitle:@"80-bit Floating Point"
+ action:@selector(showChunkSize:)
+ keyEquivalent:@"E"
+ atIndex:index++];
+ [chunkItem11 setTarget:self];
+ [chunkItem11 setTag:int(debug_view_memory::data_format::FLOAT_80BIT)];
+
+ [menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
+
+ NSMenuItem *hexadecimalItem = [menu insertItemWithTitle:@"Hexadecimal Addresses"
+ action:@selector(showAddressRadix:)
+ keyEquivalent:@"H"
+ atIndex:index++];
+ [hexadecimalItem setTarget:self];
+ [hexadecimalItem setTag:16];
+
+ NSMenuItem *decimalItem = [menu insertItemWithTitle:@"Decimal Addresses"
+ action:@selector(showAddressRadix:)
+ keyEquivalent:@""
+ atIndex:index++];
+ [decimalItem setTarget:self];
+ [decimalItem setTag:10];
- NSMenuItem *chunkItem3 = [menu insertItemWithTitle:@"80-bit floats"
- action:@selector(showChunkSize:)
- keyEquivalent:@"E"
- atIndex:index++];
- [chunkItem3 setTarget:self];
- [chunkItem3 setTag:11];
+ NSMenuItem *octalItem = [menu insertItemWithTitle:@"Octal Addresses"
+ action:@selector(showAddressRadix:)
+ keyEquivalent:@"O"
+ atIndex:index++];
+ [octalItem setTarget:self];
+ [octalItem setTag:8];
[menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
@@ -299,12 +378,12 @@
- (void)insertSubviewItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index {
- for (const debug_view_source *source = view->source_list().first(); source != nullptr; source = source->next())
+ for (auto &source : view->source_list())
{
[[menu insertItemWithTitle:[NSString stringWithUTF8String:source->name()]
action:NULL
keyEquivalent:@""
- atIndex:index++] setTag:view->source_list().indexof(*source)];
+ atIndex:index++] setTag:view->source_index(*source)];
}
if (index < [menu numberOfItems])
[menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
diff --git a/src/osd/modules/debugger/osx/memoryviewer.mm b/src/osd/modules/debugger/osx/memoryviewer.mm
index 80d5434a826..1d45650dcbb 100644
--- a/src/osd/modules/debugger/osx/memoryviewer.mm
+++ b/src/osd/modules/debugger/osx/memoryviewer.mm
@@ -14,7 +14,7 @@
#import "memoryview.h"
#include "debugger.h"
-#include "debug/debugcpu.h"
+#include "debug/debugcon.h"
#include "debug/dvmemory.h"
#include "util/xmlfile.h"
@@ -46,7 +46,7 @@
// create the subview popup
subviewButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)];
[subviewButton setAutoresizingMask:(NSViewWidthSizable | NSViewMinXMargin | NSViewMinYMargin)];
- [subviewButton setBezelStyle:NSShadowlessSquareBezelStyle];
+ [subviewButton setBezelStyle:NSBezelStyleShadowlessSquare];
[subviewButton setFocusRingType:NSFocusRingTypeNone];
[subviewButton setFont:defaultFont];
[subviewButton setTarget:self];
@@ -108,7 +108,7 @@
[actionButton release];
// set default state
- [memoryView selectSubviewForDevice:machine->debugger().cpu().get_visible_cpu()];
+ [memoryView selectSubviewForDevice:machine->debugger().console().get_visible_cpu()];
[memoryView setExpression:@"0"];
[expressionField setStringValue:@"0"];
[expressionField selectText:self];
@@ -118,9 +118,11 @@
// calculate the optimal size for everything
NSSize const desired = [NSScrollView frameSizeForContentSize:[memoryView maximumFrameSize]
- hasHorizontalScroller:YES
- hasVerticalScroller:YES
- borderType:[memoryScroll borderType]];
+ horizontalScrollerClass:[NSScroller class]
+ verticalScrollerClass:[NSScroller class]
+ borderType:[memoryScroll borderType]
+ controlSize:NSControlSizeRegular
+ scrollerStyle:NSScrollerStyleOverlay];
[self cascadeWindowWithDesiredSize:desired forView:memoryScroll];
// don't forget the result
@@ -178,15 +180,15 @@
- (void)saveConfigurationToNode:(util::xml::data_node *)node {
[super saveConfigurationToNode:node];
- node->set_attribute_int("type", MAME_DEBUGGER_WINDOW_TYPE_MEMORY_VIEWER);
- node->set_attribute_int("memoryregion", [memoryView selectedSubviewIndex]);
+ node->set_attribute_int(osd::debugger::ATTR_WINDOW_TYPE, osd::debugger::WINDOW_TYPE_MEMORY_VIEWER);
+ node->set_attribute_int(osd::debugger::ATTR_WINDOW_MEMORY_REGION, [memoryView selectedSubviewIndex]);
[memoryView saveConfigurationToNode:node];
}
- (void)restoreConfigurationFromNode:(util::xml::data_node const *)node {
[super restoreConfigurationFromNode:node];
- int const region = node->get_attribute_int("memoryregion", [memoryView selectedSubviewIndex]);
+ int const region = node->get_attribute_int(osd::debugger::ATTR_WINDOW_MEMORY_REGION, [memoryView selectedSubviewIndex]);
[memoryView selectSubviewAtIndex:region];
[window setTitle:[NSString stringWithFormat:@"Memory: %@", [memoryView selectedSubviewName]]];
[subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[memoryView selectedSubviewIndex]]];
diff --git a/src/osd/modules/debugger/osx/pointsviewer.mm b/src/osd/modules/debugger/osx/pointsviewer.mm
index 8bd4dad3a1b..0fafe35a799 100644
--- a/src/osd/modules/debugger/osx/pointsviewer.mm
+++ b/src/osd/modules/debugger/osx/pointsviewer.mm
@@ -10,6 +10,8 @@
#import "pointsviewer.h"
#import "breakpointsview.h"
+#import "exceptionpointsview.h"
+#import "registerpointsview.h"
#import "watchpointsview.h"
#include "util/xmlfile.h"
@@ -18,9 +20,9 @@
@implementation MAMEPointsViewer
- (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c {
- MAMEDebugView *breakView, *watchView;
- NSScrollView *breakScroll, *watchScroll;
- NSTabViewItem *breakTab, *watchTab;
+ MAMEDebugView *breakView, *watchView, *registerView, *exceptionView;
+ NSScrollView *breakScroll, *watchScroll, *registerScroll, *exceptionScroll;
+ NSTabViewItem *breakTab, *watchTab, *registerTab, *exceptionTab;
NSPopUpButton *actionButton;
NSRect subviewFrame;
@@ -32,7 +34,7 @@
// create the subview popup
subviewButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)];
[subviewButton setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)];
- [subviewButton setBezelStyle:NSShadowlessSquareBezelStyle];
+ [subviewButton setBezelStyle:NSBezelStyleShadowlessSquare];
[subviewButton setFocusRingType:NSFocusRingTypeNone];
[subviewButton setFont:defaultFont];
[subviewButton setTarget:self];
@@ -44,6 +46,12 @@
[[[subviewButton menu] addItemWithTitle:@"All Watchpoints"
action:NULL
keyEquivalent:@""] setTag:1];
+ [[[subviewButton menu] addItemWithTitle:@"All Registerpoints"
+ action:NULL
+ keyEquivalent:@""] setTag:2];
+ [[[subviewButton menu] addItemWithTitle:@"All Exceptionpoints"
+ action:NULL
+ keyEquivalent:@""] setTag:3];
[subviewButton sizeToFit];
subviewFrame = [subviewButton frame];
subviewFrame.origin.x = subviewFrame.size.height;
@@ -82,7 +90,7 @@
[breakTab setView:breakScroll];
[breakScroll release];
- // create the breakpoints view
+ // create the watchpoints view
watchView = [[MAMEWatchpointsView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)
machine:*machine];
watchScroll = [[NSScrollView alloc] initWithFrame:[breakScroll frame]];
@@ -98,7 +106,39 @@
[watchTab setView:watchScroll];
[watchScroll release];
- // create a tabless tabview for the two subviews
+ // create the registerpoints view
+ registerView = [[MAMERegisterpointsView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)
+ machine:*machine];
+ registerScroll = [[NSScrollView alloc] initWithFrame:[breakScroll frame]];
+ [registerScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
+ [registerScroll setHasHorizontalScroller:YES];
+ [registerScroll setHasVerticalScroller:YES];
+ [registerScroll setAutohidesScrollers:YES];
+ [registerScroll setBorderType:NSNoBorder];
+ [registerScroll setDrawsBackground:NO];
+ [registerScroll setDocumentView:registerView];
+ [registerView release];
+ registerTab = [[NSTabViewItem alloc] initWithIdentifier:@""];
+ [registerTab setView:registerScroll];
+ [registerScroll release];
+
+ // create the exceptionpoints view
+ exceptionView = [[MAMEExceptionpointsView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)
+ machine:*machine];
+ exceptionScroll = [[NSScrollView alloc] initWithFrame:[breakScroll frame]];
+ [exceptionScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
+ [exceptionScroll setHasHorizontalScroller:YES];
+ [exceptionScroll setHasVerticalScroller:YES];
+ [exceptionScroll setAutohidesScrollers:YES];
+ [exceptionScroll setBorderType:NSNoBorder];
+ [exceptionScroll setDrawsBackground:NO];
+ [exceptionScroll setDocumentView:exceptionView];
+ [exceptionView release];
+ exceptionTab = [[NSTabViewItem alloc] initWithIdentifier:@""];
+ [exceptionTab setView:exceptionScroll];
+ [exceptionScroll release];
+
+ // create a tabless tabview for the four subviews
tabs = [[NSTabView alloc] initWithFrame:[breakScroll frame]];
[tabs setTabViewType:NSNoTabsNoBorder];
[tabs setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
@@ -106,6 +146,10 @@
[breakTab release];
[tabs addTabViewItem:watchTab];
[watchTab release];
+ [tabs addTabViewItem:registerTab];
+ [registerTab release];
+ [tabs addTabViewItem:exceptionTab];
+ [exceptionTab release];
[[window contentView] addSubview:tabs];
[tabs release];
@@ -117,15 +161,31 @@
// calculate the optimal size for everything
NSSize const breakDesired = [NSScrollView frameSizeForContentSize:[breakView maximumFrameSize]
- hasHorizontalScroller:YES
- hasVerticalScroller:YES
- borderType:[breakScroll borderType]];
+ horizontalScrollerClass:[NSScroller class]
+ verticalScrollerClass:[NSScroller class]
+ borderType:[breakScroll borderType]
+ controlSize:NSControlSizeRegular
+ scrollerStyle:NSScrollerStyleOverlay];
NSSize const watchDesired = [NSScrollView frameSizeForContentSize:[watchView maximumFrameSize]
- hasHorizontalScroller:YES
- hasVerticalScroller:YES
- borderType:[watchScroll borderType]];
- NSSize const desired = NSMakeSize(std::max(breakDesired.width, watchDesired.width),
- std::max(breakDesired.height, watchDesired.height));
+ horizontalScrollerClass:[NSScroller class]
+ verticalScrollerClass:[NSScroller class]
+ borderType:[watchScroll borderType]
+ controlSize:NSControlSizeRegular
+ scrollerStyle:NSScrollerStyleOverlay];
+ NSSize const registerDesired = [NSScrollView frameSizeForContentSize:[registerView maximumFrameSize]
+ horizontalScrollerClass:[NSScroller class]
+ verticalScrollerClass:[NSScroller class]
+ borderType:[registerScroll borderType]
+ controlSize:NSControlSizeRegular
+ scrollerStyle:NSScrollerStyleOverlay];
+ NSSize const exceptionDesired = [NSScrollView frameSizeForContentSize:[exceptionView maximumFrameSize]
+ horizontalScrollerClass:[NSScroller class]
+ verticalScrollerClass:[NSScroller class]
+ borderType:[exceptionScroll borderType]
+ controlSize:NSControlSizeRegular
+ scrollerStyle:NSScrollerStyleOverlay];
+ NSSize const desired = NSMakeSize(std::max({ breakDesired.width, watchDesired.width, registerDesired.width, exceptionDesired.width }),
+ std::max({ breakDesired.height, watchDesired.height, registerDesired.height, exceptionDesired.height }));
[self cascadeWindowWithDesiredSize:desired forView:tabs];
// don't forget the result
@@ -146,14 +206,14 @@
- (void)saveConfigurationToNode:(util::xml::data_node *)node {
[super saveConfigurationToNode:node];
- node->set_attribute_int("type", MAME_DEBUGGER_WINDOW_TYPE_POINTS_VIEWER);
- node->set_attribute_int("bwtype", [tabs indexOfTabViewItem:[tabs selectedTabViewItem]]);
+ node->set_attribute_int(osd::debugger::ATTR_WINDOW_TYPE, osd::debugger::WINDOW_TYPE_POINTS_VIEWER);
+ node->set_attribute_int(osd::debugger::ATTR_WINDOW_POINTS_TYPE, [tabs indexOfTabViewItem:[tabs selectedTabViewItem]]);
}
- (void)restoreConfigurationFromNode:(util::xml::data_node const *)node {
[super restoreConfigurationFromNode:node];
- int const tab = node->get_attribute_int("bwtype", [tabs indexOfTabViewItem:[tabs selectedTabViewItem]]);
+ int const tab = node->get_attribute_int(osd::debugger::ATTR_WINDOW_POINTS_TYPE, [tabs indexOfTabViewItem:[tabs selectedTabViewItem]]);
if ((0 <= tab) && ([tabs numberOfTabViewItems] > tab))
{
[subviewButton selectItemAtIndex:tab];
diff --git a/src/osd/modules/debugger/osx/registerpointsview.h b/src/osd/modules/debugger/osx/registerpointsview.h
new file mode 100644
index 00000000000..58faf954416
--- /dev/null
+++ b/src/osd/modules/debugger/osx/registerpointsview.h
@@ -0,0 +1,23 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+//============================================================
+//
+// registerpointsview.h - MacOS X Cocoa debug window handling
+//
+//============================================================
+
+#import "debugosx.h"
+
+#import "debugview.h"
+
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface MAMERegisterpointsView : MAMEDebugView
+{
+}
+
+- (id)initWithFrame:(NSRect)f machine:(running_machine &)m;
+
+@end
diff --git a/src/osd/modules/debugger/osx/registerpointsview.mm b/src/osd/modules/debugger/osx/registerpointsview.mm
new file mode 100644
index 00000000000..a701fe733ce
--- /dev/null
+++ b/src/osd/modules/debugger/osx/registerpointsview.mm
@@ -0,0 +1,27 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+//============================================================
+//
+// registerpointsview.m - MacOS X Cocoa debug window handling
+//
+//============================================================
+
+#import "registerpointsview.h"
+
+#include "debug/debugvw.h"
+
+
+@implementation MAMERegisterpointsView
+
+- (id)initWithFrame:(NSRect)f machine:(running_machine &)m {
+ if (!(self = [super initWithFrame:f type:DVT_REGISTER_POINTS machine:m wholeLineScroll:YES]))
+ return nil;
+ return self;
+}
+
+
+- (void)dealloc {
+ [super dealloc];
+}
+
+@end
diff --git a/src/osd/modules/debugger/osx/registersview.mm b/src/osd/modules/debugger/osx/registersview.mm
index 5c3e00a2b89..c710179c5bd 100644
--- a/src/osd/modules/debugger/osx/registersview.mm
+++ b/src/osd/modules/debugger/osx/registersview.mm
@@ -10,7 +10,7 @@
#include "emu.h"
#include "debugger.h"
-#include "debug/debugcpu.h"
+#include "debug/debugcon.h"
#include "debug/debugvw.h"
@@ -30,11 +30,11 @@
- (NSSize)maximumFrameSize {
debug_view_xy max;
- device_t *curcpu = machine->debugger().cpu().get_visible_cpu();
+ device_t *curcpu = machine->debugger().console().get_visible_cpu();
const debug_view_source *source = view->source_for_device(curcpu);
max.x = max.y = 0;
- for (const debug_view_source *source = view->source_list().first(); source != nullptr; source = source->next())
+ for (auto &source : view->source_list())
{
debug_view_xy current;
view->set_source(*source);
diff --git a/src/osd/modules/debugger/qt/breakpointswindow.cpp b/src/osd/modules/debugger/qt/breakpointswindow.cpp
index 5d091694d66..7dc3db34179 100644
--- a/src/osd/modules/debugger/qt/breakpointswindow.cpp
+++ b/src/osd/modules/debugger/qt/breakpointswindow.cpp
@@ -1,26 +1,29 @@
// license:BSD-3-Clause
// copyright-holders:Andrew Gardner
#include "emu.h"
+#include "breakpointswindow.h"
+
+#include "util/xmlfile.h"
+
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+#include <QtGui/QActionGroup>
+#else
#include <QtWidgets/QActionGroup>
+#endif
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QMenu>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QVBoxLayout>
-#include "breakpointswindow.h"
-#include "debug/debugcon.h"
-#include "debug/debugcpu.h"
-#include "debug/dvbpoints.h"
-#include "debug/dvwpoints.h"
+namespace osd::debugger::qt {
-
-BreakpointsWindow::BreakpointsWindow(running_machine* machine, QWidget* parent) :
- WindowQt(machine, nullptr)
+BreakpointsWindow::BreakpointsWindow(DebuggerQt &debugger, QWidget *parent) :
+ WindowQt(debugger, nullptr)
{
setWindowTitle("Debug: All Breakpoints");
- if (parent != nullptr)
+ if (parent)
{
QPoint parentPos = parent->pos();
setGeometry(parentPos.x()+100, parentPos.y()+100, 800, 400);
@@ -29,13 +32,13 @@ BreakpointsWindow::BreakpointsWindow(running_machine* machine, QWidget* parent)
//
// The main frame and its input and breakpoints widgets
//
- QFrame* mainWindowFrame = new QFrame(this);
+ QFrame *mainWindowFrame = new QFrame(this);
// The main breakpoints view
m_breakpointsView = new DebuggerView(DVT_BREAK_POINTS, m_machine, this);
// Layout
- QVBoxLayout* vLayout = new QVBoxLayout(mainWindowFrame);
+ QVBoxLayout *vLayout = new QVBoxLayout(mainWindowFrame);
vLayout->setObjectName("vlayout");
vLayout->setSpacing(3);
vLayout->setContentsMargins(2,2,2,2);
@@ -46,23 +49,38 @@ BreakpointsWindow::BreakpointsWindow(running_machine* machine, QWidget* parent)
//
// Menu bars
//
- QActionGroup* typeGroup = new QActionGroup(this);
+ QActionGroup *typeGroup = new QActionGroup(this);
typeGroup->setObjectName("typegroup");
- QAction* typeBreak = new QAction("Breakpoints", this);
+
+ QAction *typeBreak = new QAction("Breakpoints", this);
typeBreak->setObjectName("typebreak");
- QAction* typeWatch = new QAction("Watchpoints", this);
- typeWatch->setObjectName("typewatch");
typeBreak->setCheckable(true);
- typeWatch->setCheckable(true);
typeBreak->setActionGroup(typeGroup);
- typeWatch->setActionGroup(typeGroup);
typeBreak->setShortcut(QKeySequence("Ctrl+1"));
+
+ QAction *typeWatch = new QAction("Watchpoints", this);
+ typeWatch->setObjectName("typewatch");
+ typeWatch->setCheckable(true);
+ typeWatch->setActionGroup(typeGroup);
typeWatch->setShortcut(QKeySequence("Ctrl+2"));
+
+ QAction *typeRegister = new QAction("Registerpoints", this);
+ typeRegister->setObjectName("typeregister");
+ typeRegister->setCheckable(true);
+ typeRegister->setActionGroup(typeGroup);
+ typeRegister->setShortcut(QKeySequence("Ctrl+3"));
+
+ QAction *typeException = new QAction("Exceptionpoints", this);
+ typeException->setObjectName("typeexception");
+ typeException->setCheckable(true);
+ typeException->setActionGroup(typeGroup);
+ typeException->setShortcut(QKeySequence("Ctrl+4"));
+
typeBreak->setChecked(true);
connect(typeGroup, &QActionGroup::triggered, this, &BreakpointsWindow::typeChanged);
// Assemble the options menu
- QMenu* optionsMenu = menuBar()->addMenu("&Options");
+ QMenu *optionsMenu = menuBar()->addMenu("&Options");
optionsMenu->addActions(typeGroup->actions());
}
@@ -72,6 +90,50 @@ BreakpointsWindow::~BreakpointsWindow()
}
+void BreakpointsWindow::restoreConfiguration(util::xml::data_node const &node)
+{
+ WindowQt::restoreConfiguration(node);
+
+ auto const type = node.get_attribute_int(ATTR_WINDOW_POINTS_TYPE, -1);
+ QActionGroup *typeGroup = findChild<QActionGroup *>("typegroup");
+ if ((0 <= type) && (typeGroup->actions().size() > type))
+ typeGroup->actions()[type]->trigger();
+
+ m_breakpointsView->restoreConfigurationFromNode(node);
+
+}
+
+
+void BreakpointsWindow::saveConfigurationToNode(util::xml::data_node &node)
+{
+ WindowQt::saveConfigurationToNode(node);
+
+ node.set_attribute_int(ATTR_WINDOW_TYPE, WINDOW_TYPE_POINTS_VIEWER);
+ if (m_breakpointsView)
+ {
+ switch (m_breakpointsView->view()->type())
+ {
+ case DVT_BREAK_POINTS:
+ node.set_attribute_int(ATTR_WINDOW_POINTS_TYPE, 0);
+ break;
+ case DVT_WATCH_POINTS:
+ node.set_attribute_int(ATTR_WINDOW_POINTS_TYPE, 1);
+ break;
+ case DVT_REGISTER_POINTS:
+ node.set_attribute_int(ATTR_WINDOW_POINTS_TYPE, 2);
+ break;
+ case DVT_EXCEPTION_POINTS:
+ node.set_attribute_int(ATTR_WINDOW_POINTS_TYPE, 3);
+ break;
+ default:
+ break;
+ }
+ }
+
+ m_breakpointsView->saveConfigurationToNode(node);
+}
+
+
void BreakpointsWindow::typeChanged(QAction* changedTo)
{
// Clean
@@ -89,49 +151,20 @@ void BreakpointsWindow::typeChanged(QAction* changedTo)
m_breakpointsView = new DebuggerView(DVT_WATCH_POINTS, m_machine, this);
setWindowTitle("Debug: All Watchpoints");
}
+ else if (changedTo->text() == "Registerpoints")
+ {
+ m_breakpointsView = new DebuggerView(DVT_REGISTER_POINTS, m_machine, this);
+ setWindowTitle("Debug: All Registerpoints");
+ }
+ else if (changedTo->text() == "Exceptionpoints")
+ {
+ m_breakpointsView = new DebuggerView(DVT_EXCEPTION_POINTS, m_machine, this);
+ setWindowTitle("Debug: All Exceptionpoints");
+ }
// Re-register
- QVBoxLayout* layout = findChild<QVBoxLayout*>("vlayout");
+ QVBoxLayout *layout = findChild<QVBoxLayout *>("vlayout");
layout->addWidget(m_breakpointsView);
}
-
-
-//=========================================================================
-// BreakpointsWindowQtConfig
-//=========================================================================
-void BreakpointsWindowQtConfig::buildFromQWidget(QWidget* widget)
-{
- WindowQtConfig::buildFromQWidget(widget);
- BreakpointsWindow* window = dynamic_cast<BreakpointsWindow*>(widget);
-
- QActionGroup* typeGroup = window->findChild<QActionGroup*>("typegroup");
- if (typeGroup->checkedAction()->text() == "Breakpoints")
- m_bwType = 0;
- else if (typeGroup->checkedAction()->text() == "Watchpoints")
- m_bwType = 1;
-}
-
-
-void BreakpointsWindowQtConfig::applyToQWidget(QWidget* widget)
-{
- WindowQtConfig::applyToQWidget(widget);
- BreakpointsWindow* window = dynamic_cast<BreakpointsWindow*>(widget);
-
- QActionGroup* typeGroup = window->findChild<QActionGroup*>("typegroup");
- typeGroup->actions()[m_bwType]->trigger();
-}
-
-
-void BreakpointsWindowQtConfig::addToXmlDataNode(util::xml::data_node &node) const
-{
- WindowQtConfig::addToXmlDataNode(node);
- node.set_attribute_int("bwtype", m_bwType);
-}
-
-
-void BreakpointsWindowQtConfig::recoverFromXmlNode(util::xml::data_node const &node)
-{
- WindowQtConfig::recoverFromXmlNode(node);
- m_bwType = node.get_attribute_int("bwtype", m_bwType);
-}
+} // namespace osd::debugger::qt
diff --git a/src/osd/modules/debugger/qt/breakpointswindow.h b/src/osd/modules/debugger/qt/breakpointswindow.h
index 60bbdc4379f..0a07b4facfb 100644
--- a/src/osd/modules/debugger/qt/breakpointswindow.h
+++ b/src/osd/modules/debugger/qt/breakpointswindow.h
@@ -1,12 +1,14 @@
// license:BSD-3-Clause
// copyright-holders:Andrew Gardner
-#ifndef __DEBUG_QT_BREAK_POINTS_WINDOW_H__
-#define __DEBUG_QT_BREAK_POINTS_WINDOW_H__
+#ifndef MAME_DEBUGGER_QT_BREAKPOINTSWINDOW_H
+#define MAME_DEBUGGER_QT_BREAKPOINTSWINDOW_H
#include "debuggerview.h"
#include "windowqt.h"
+namespace osd::debugger::qt {
+
//============================================================
// The Breakpoints Window.
//============================================================
@@ -15,42 +17,22 @@ class BreakpointsWindow : public WindowQt
Q_OBJECT
public:
- BreakpointsWindow(running_machine* machine, QWidget* parent=nullptr);
+ BreakpointsWindow(DebuggerQt &debugger, QWidget *parent = nullptr);
virtual ~BreakpointsWindow();
+ virtual void restoreConfiguration(util::xml::data_node const &node) override;
-private slots:
- void typeChanged(QAction* changedTo);
+protected:
+ virtual void saveConfigurationToNode(util::xml::data_node &node) override;
+private slots:
+ void typeChanged(QAction *changedTo);
private:
// Widgets
- DebuggerView* m_breakpointsView;
-};
-
-
-//=========================================================================
-// A way to store the configuration of a window long enough to read/write.
-//=========================================================================
-class BreakpointsWindowQtConfig : public WindowQtConfig
-{
-public:
- BreakpointsWindowQtConfig() :
- WindowQtConfig(WIN_TYPE_BREAK_POINTS),
- m_bwType(0)
- {
- }
-
- ~BreakpointsWindowQtConfig() {}
-
- // Settings
- int m_bwType;
-
- void buildFromQWidget(QWidget* widget);
- void applyToQWidget(QWidget* widget);
- void addToXmlDataNode(util::xml::data_node &node) const;
- void recoverFromXmlNode(util::xml::data_node const &node);
+ DebuggerView *m_breakpointsView;
};
+} // namespace osd::debugger::qt
-#endif
+#endif // MAME_DEBUGGER_QT_BREAKPOINTSWINDOW_H
diff --git a/src/osd/modules/debugger/qt/dasmwindow.cpp b/src/osd/modules/debugger/qt/dasmwindow.cpp
index 5c575b400b1..e90054a3292 100644
--- a/src/osd/modules/debugger/qt/dasmwindow.cpp
+++ b/src/osd/modules/debugger/qt/dasmwindow.cpp
@@ -1,25 +1,38 @@
// license:BSD-3-Clause
// copyright-holders:Andrew Gardner
#include "emu.h"
+#include "dasmwindow.h"
+
+#include "debugger.h"
+#include "debug/debugcon.h"
+#include "debug/debugcpu.h"
+#include "debug/dvdisasm.h"
+#include "debug/points.h"
+
+#include "util/xmlfile.h"
+
+#include <QtGui/QKeyEvent>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QVBoxLayout>
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+#include <QtGui/QAction>
+#include <QtGui/QActionGroup>
+#else
#include <QtWidgets/QAction>
+#endif
#include <QtWidgets/QMenu>
#include <QtWidgets/QMenuBar>
-#include "dasmwindow.h"
-#include "debug/debugcon.h"
-#include "debug/debugcpu.h"
-#include "debug/dvdisasm.h"
+namespace osd::debugger::qt {
-
-DasmWindow::DasmWindow(running_machine* machine, QWidget* parent) :
- WindowQt(machine, nullptr)
+DasmWindow::DasmWindow(DebuggerQt &debugger, QWidget *parent) :
+ WindowQt(debugger, nullptr),
+ m_inputHistory()
{
setWindowTitle("Debug: Disassembly View");
- if (parent != nullptr)
+ if (parent)
{
QPoint parentPos = parent->pos();
setGeometry(parentPos.x()+100, parentPos.y()+100, 800, 400);
@@ -28,43 +41,42 @@ DasmWindow::DasmWindow(running_machine* machine, QWidget* parent) :
//
// The main frame and its input and log widgets
//
- QFrame* mainWindowFrame = new QFrame(this);
+ QFrame *mainWindowFrame = new QFrame(this);
// The top frame & groupbox that contains the input widgets
- QFrame* topSubFrame = new QFrame(mainWindowFrame);
+ QFrame *topSubFrame = new QFrame(mainWindowFrame);
// The input edit
m_inputEdit = new QLineEdit(topSubFrame);
connect(m_inputEdit, &QLineEdit::returnPressed, this, &DasmWindow::expressionSubmitted);
+ connect(m_inputEdit, &QLineEdit::textEdited, this, &DasmWindow::expressionEdited);
+ m_inputEdit->installEventFilter(this);
// The cpu combo box
m_cpuComboBox = new QComboBox(topSubFrame);
m_cpuComboBox->setObjectName("cpu");
m_cpuComboBox->setMinimumWidth(300);
- connect(m_cpuComboBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &DasmWindow::cpuChanged);
+ connect(m_cpuComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &DasmWindow::cpuChanged);
// The main disasm window
m_dasmView = new DebuggerView(DVT_DISASSEMBLY, m_machine, this);
connect(m_dasmView, &DebuggerView::updated, this, &DasmWindow::dasmViewUpdated);
// Force a recompute of the disassembly region
- downcast<debug_view_disasm*>(m_dasmView->view())->set_expression("curpc");
+ m_dasmView->view<debug_view_disasm>()->set_expression("curpc");
- // Populate the combo box & set the proper cpu
+ // Populate the combo box & set the proper CPU
populateComboBox();
- //const debug_view_source *source = mem->views[0]->view->source_for_device(curcpu);
- //gtk_combo_box_set_active(zone_w, mem->views[0]->view->source_list().indexof(*source));
- //mem->views[0]->view->set_source(*source);
-
+ setToCurrentCpu();
// Layout
- QHBoxLayout* subLayout = new QHBoxLayout(topSubFrame);
+ QHBoxLayout *subLayout = new QHBoxLayout(topSubFrame);
subLayout->addWidget(m_inputEdit);
subLayout->addWidget(m_cpuComboBox);
subLayout->setSpacing(3);
subLayout->setContentsMargins(2,2,2,2);
- QVBoxLayout* vLayout = new QVBoxLayout(mainWindowFrame);
+ QVBoxLayout *vLayout = new QVBoxLayout(mainWindowFrame);
vLayout->setSpacing(3);
vLayout->setContentsMargins(2,2,2,2);
vLayout->addWidget(topSubFrame);
@@ -80,18 +92,21 @@ DasmWindow::DasmWindow(running_machine* machine, QWidget* parent) :
m_breakpointEnableAct = new QAction("Disable Breakpoint at Cursor", this);
m_runToCursorAct = new QAction("Run to Cursor", this);
m_breakpointToggleAct->setShortcut(Qt::Key_F9);
- m_breakpointEnableAct->setShortcut(Qt::SHIFT + Qt::Key_F9);
+ m_breakpointEnableAct->setShortcut(Qt::SHIFT | Qt::Key_F9);
m_runToCursorAct->setShortcut(Qt::Key_F4);
connect(m_breakpointToggleAct, &QAction::triggered, this, &DasmWindow::toggleBreakpointAtCursor);
connect(m_breakpointEnableAct, &QAction::triggered, this, &DasmWindow::enableBreakpointAtCursor);
connect(m_runToCursorAct, &QAction::triggered, this, &DasmWindow::runToCursor);
// Right bar options
- QActionGroup* rightBarGroup = new QActionGroup(this);
+ QActionGroup *rightBarGroup = new QActionGroup(this);
rightBarGroup->setObjectName("rightbargroup");
- QAction* rightActRaw = new QAction("Raw Opcodes", this);
- QAction* rightActEncrypted = new QAction("Encrypted Opcodes", this);
- QAction* rightActComments = new QAction("Comments", this);
+ QAction *rightActRaw = new QAction("Raw Opcodes", this);
+ QAction *rightActEncrypted = new QAction("Encrypted Opcodes", this);
+ QAction *rightActComments = new QAction("Comments", this);
+ rightActRaw->setData(int(DASM_RIGHTCOL_RAW));
+ rightActEncrypted->setData(int(DASM_RIGHTCOL_ENCRYPTED));
+ rightActComments->setData(int(DASM_RIGHTCOL_COMMENTS));
rightActRaw->setCheckable(true);
rightActEncrypted->setCheckable(true);
rightActComments->setCheckable(true);
@@ -105,7 +120,7 @@ DasmWindow::DasmWindow(running_machine* machine, QWidget* parent) :
connect(rightBarGroup, &QActionGroup::triggered, this, &DasmWindow::rightBarChanged);
// Assemble the options menu
- QMenu* optionsMenu = menuBar()->addMenu("&Options");
+ QMenu *optionsMenu = menuBar()->addMenu("&Options");
optionsMenu->addAction(m_breakpointToggleAct);
optionsMenu->addAction(m_breakpointEnableAct);
optionsMenu->addAction(m_runToCursorAct);
@@ -119,18 +134,124 @@ DasmWindow::~DasmWindow()
}
+void DasmWindow::restoreConfiguration(util::xml::data_node const &node)
+{
+ WindowQt::restoreConfiguration(node);
+
+ debug_view_disasm &dasmview = *m_dasmView->view<debug_view_disasm>();
+
+ auto const cpu = node.get_attribute_int(ATTR_WINDOW_DISASSEMBLY_CPU, m_dasmView->sourceIndex());
+ if ((0 <= cpu) && (m_cpuComboBox->count() > cpu))
+ m_cpuComboBox->setCurrentIndex(cpu);
+
+ auto const rightbar = node.get_attribute_int(ATTR_WINDOW_DISASSEMBLY_RIGHT_COLUMN, dasmview.right_column());
+ QActionGroup *const rightBarGroup = findChild<QActionGroup *>("rightbargroup");
+ for (QAction *action : rightBarGroup->actions())
+ {
+ if (action->data().toInt() == rightbar)
+ {
+ action->trigger();
+ break;
+ }
+ }
+
+ util::xml::data_node const *const expression = node.get_child(NODE_WINDOW_EXPRESSION);
+ if (expression && expression->get_value())
+ {
+ m_inputEdit->setText(QString::fromUtf8(expression->get_value()));
+ expressionSubmitted();
+ }
+
+ m_dasmView->restoreConfigurationFromNode(node);
+ m_inputHistory.restoreConfigurationFromNode(node);
+}
+
+
+void DasmWindow::saveConfigurationToNode(util::xml::data_node &node)
+{
+ WindowQt::saveConfigurationToNode(node);
+
+ node.set_attribute_int(ATTR_WINDOW_TYPE, WINDOW_TYPE_DISASSEMBLY_VIEWER);
+
+ debug_view_disasm &dasmview = *m_dasmView->view<debug_view_disasm>();
+ node.set_attribute_int(ATTR_WINDOW_DISASSEMBLY_CPU, m_dasmView->sourceIndex());
+ node.set_attribute_int(ATTR_WINDOW_DISASSEMBLY_RIGHT_COLUMN, dasmview.right_column());
+ node.add_child(NODE_WINDOW_EXPRESSION, dasmview.expression());
+
+ m_dasmView->saveConfigurationToNode(node);
+ m_inputHistory.saveConfigurationToNode(node);
+}
+
+
+// Used to intercept the user hitting the up arrow in the input widget
+bool DasmWindow::eventFilter(QObject *obj, QEvent *event)
+{
+ // Only filter keypresses
+ if (event->type() != QEvent::KeyPress)
+ return QObject::eventFilter(obj, event);
+
+ QKeyEvent const &keyEvent = *static_cast<QKeyEvent *>(event);
+
+ // Catch up & down keys
+ if (keyEvent.key() == Qt::Key_Escape)
+ {
+ m_inputEdit->setText(QString::fromUtf8(m_dasmView->view<debug_view_disasm>()->expression()));
+ m_inputEdit->selectAll();
+ m_inputHistory.reset();
+ return true;
+ }
+ else if (keyEvent.key() == Qt::Key_Up)
+ {
+ QString const *const hist = m_inputHistory.previous(m_inputEdit->text());
+ if (hist)
+ {
+ m_inputEdit->setText(*hist);
+ m_inputEdit->setSelection(hist->size(), 0);
+ }
+ return true;
+ }
+ else if (keyEvent.key() == Qt::Key_Down)
+ {
+ QString const *const hist = m_inputHistory.next(m_inputEdit->text());
+ if (hist)
+ {
+ m_inputEdit->setText(*hist);
+ m_inputEdit->setSelection(hist->size(), 0);
+ }
+ return true;
+ }
+ else
+ {
+ return QObject::eventFilter(obj, event);
+ }
+}
+
+
void DasmWindow::cpuChanged(int index)
{
- m_dasmView->view()->set_source(*m_dasmView->view()->source_list().find(index));
- m_dasmView->viewport()->update();
+ if (index < m_dasmView->view()->source_count())
+ {
+ m_dasmView->view()->set_source(*m_dasmView->view()->source(index));
+ m_dasmView->viewport()->update();
+ }
}
void DasmWindow::expressionSubmitted()
{
const QString expression = m_inputEdit->text();
- downcast<debug_view_disasm*>(m_dasmView->view())->set_expression(expression.toLocal8Bit().data());
- m_dasmView->viewport()->update();
+ m_dasmView->view<debug_view_disasm>()->set_expression(expression.toUtf8().data());
+ m_inputEdit->selectAll();
+
+ // Add history
+ if (!expression.isEmpty())
+ m_inputHistory.add(expression);
+}
+
+
+void DasmWindow::expressionEdited(QString const &text)
+{
+ m_inputHistory.edit();
}
@@ -138,30 +259,28 @@ void DasmWindow::toggleBreakpointAtCursor(bool changedTo)
{
if (m_dasmView->view()->cursor_visible())
{
- offs_t const address = downcast<debug_view_disasm *>(m_dasmView->view())->selected_address();
+ offs_t const address = m_dasmView->view<debug_view_disasm>()->selected_address();
device_t *const device = m_dasmView->view()->source()->device();
device_debug *const cpuinfo = device->debug();
// Find an existing breakpoint at this address
- const device_debug::breakpoint *bp = cpuinfo->breakpoint_find(address);
+ const debug_breakpoint *bp = cpuinfo->breakpoint_find(address);
// If none exists, add a new one
- if (bp == nullptr)
+ if (!bp)
{
- int32_t bpindex = cpuinfo->breakpoint_set(address, nullptr, nullptr);
- m_machine->debugger().console().printf("Breakpoint %X set\n", bpindex);
+ int32_t bpindex = cpuinfo->breakpoint_set(address);
+ m_machine.debugger().console().printf("Breakpoint %X set\n", bpindex);
}
else
{
int32_t bpindex = bp->index();
cpuinfo->breakpoint_clear(bpindex);
- m_machine->debugger().console().printf("Breakpoint %X cleared\n", bpindex);
+ m_machine.debugger().console().printf("Breakpoint %X cleared\n", bpindex);
}
- m_machine->debug_view().update_all();
- m_machine->debugger().refresh_display();
+ m_machine.debug_view().update_all();
+ m_machine.debugger().refresh_display();
}
-
- refreshAll();
}
@@ -169,23 +288,21 @@ void DasmWindow::enableBreakpointAtCursor(bool changedTo)
{
if (m_dasmView->view()->cursor_visible())
{
- offs_t const address = downcast<debug_view_disasm *>(m_dasmView->view())->selected_address();
+ offs_t const address = m_dasmView->view<debug_view_disasm>()->selected_address();
device_t *const device = m_dasmView->view()->source()->device();
device_debug *const cpuinfo = device->debug();
// Find an existing breakpoint at this address
- const device_debug::breakpoint *bp = cpuinfo->breakpoint_find(address);
+ const debug_breakpoint *bp = cpuinfo->breakpoint_find(address);
- if (bp != nullptr)
+ if (bp)
{
cpuinfo->breakpoint_enable(bp->index(), !bp->enabled());
- m_machine->debugger().console().printf("Breakpoint %X %s\n", (uint32_t)bp->index(), bp->enabled() ? "enabled" : "disabled");
- m_machine->debug_view().update_all();
- m_machine->debugger().refresh_display();
+ m_machine.debugger().console().printf("Breakpoint %X %s\n", (uint32_t)bp->index(), bp->enabled() ? "enabled" : "disabled");
+ m_machine.debug_view().update_all();
+ m_machine.debugger().refresh_display();
}
}
-
- refreshAll();
}
@@ -193,7 +310,7 @@ void DasmWindow::runToCursor(bool changedTo)
{
if (m_dasmView->view()->cursor_visible())
{
- offs_t const address = downcast<debug_view_disasm*>(m_dasmView->view())->selected_address();
+ offs_t const address = m_dasmView->view<debug_view_disasm>()->selected_address();
m_dasmView->view()->source()->device()->debug()->go(address);
}
}
@@ -201,19 +318,8 @@ void DasmWindow::runToCursor(bool changedTo)
void DasmWindow::rightBarChanged(QAction* changedTo)
{
- debug_view_disasm* dasmView = downcast<debug_view_disasm*>(m_dasmView->view());
- if (changedTo->text() == "Raw Opcodes")
- {
- dasmView->set_right_column(DASM_RIGHTCOL_RAW);
- }
- else if (changedTo->text() == "Encrypted Opcodes")
- {
- dasmView->set_right_column(DASM_RIGHTCOL_ENCRYPTED);
- }
- else if (changedTo->text() == "Comments")
- {
- dasmView->set_right_column(DASM_RIGHTCOL_COMMENTS);
- }
+ debug_view_disasm *const dasmView = m_dasmView->view<debug_view_disasm>();
+ dasmView->set_right_column(disasm_right_column(changedTo->data().toInt()));
m_dasmView->viewport()->update();
}
@@ -225,14 +331,14 @@ void DasmWindow::dasmViewUpdated()
bool breakpointEnabled = false;
if (haveCursor)
{
- offs_t const address = downcast<debug_view_disasm *>(m_dasmView->view())->selected_address();
+ offs_t const address = m_dasmView->view<debug_view_disasm>()->selected_address();
device_t *const device = m_dasmView->view()->source()->device();
device_debug *const cpuinfo = device->debug();
// Find an existing breakpoint at this address
- const device_debug::breakpoint *bp = cpuinfo->breakpoint_find(address);
+ const debug_breakpoint *bp = cpuinfo->breakpoint_find(address);
- if (bp != nullptr)
+ if (bp)
{
haveBreakpoint = true;
breakpointEnabled = bp->enabled();
@@ -249,57 +355,29 @@ void DasmWindow::dasmViewUpdated()
void DasmWindow::populateComboBox()
{
- if (m_dasmView == nullptr)
+ if (!m_dasmView)
return;
m_cpuComboBox->clear();
- for (const debug_view_source &source : m_dasmView->view()->source_list())
+ for (auto &source : m_dasmView->view()->source_list())
{
- m_cpuComboBox->addItem(source.name());
+ m_cpuComboBox->addItem(source->name());
}
}
-//=========================================================================
-// DasmWindowQtConfig
-//=========================================================================
-void DasmWindowQtConfig::buildFromQWidget(QWidget* widget)
-{
- WindowQtConfig::buildFromQWidget(widget);
- DasmWindow* window = dynamic_cast<DasmWindow*>(widget);
- QComboBox* cpu = window->findChild<QComboBox*>("cpu");
- m_cpu = cpu->currentIndex();
-
- QActionGroup* rightBarGroup = window->findChild<QActionGroup*>("rightbargroup");
- if (rightBarGroup->checkedAction()->text() == "Raw Opcodes")
- m_rightBar = 0;
- else if (rightBarGroup->checkedAction()->text() == "Encrypted Opcodes")
- m_rightBar = 1;
- else if (rightBarGroup->checkedAction()->text() == "Comments")
- m_rightBar = 2;
-}
-
-void DasmWindowQtConfig::applyToQWidget(QWidget* widget)
-{
- WindowQtConfig::applyToQWidget(widget);
- DasmWindow* window = dynamic_cast<DasmWindow*>(widget);
- QComboBox* cpu = window->findChild<QComboBox*>("cpu");
- cpu->setCurrentIndex(m_cpu);
-
- QActionGroup* rightBarGroup = window->findChild<QActionGroup*>("rightbargroup");
- rightBarGroup->actions()[m_rightBar]->trigger();
-}
-
-void DasmWindowQtConfig::addToXmlDataNode(util::xml::data_node &node) const
+void DasmWindow::setToCurrentCpu()
{
- WindowQtConfig::addToXmlDataNode(node);
- node.set_attribute_int("cpu", m_cpu);
- node.set_attribute_int("rightbar", m_rightBar);
+ device_t *curCpu = m_machine.debugger().console().get_visible_cpu();
+ if (curCpu)
+ {
+ const debug_view_source *source = m_dasmView->view()->source_for_device(curCpu);
+ if (source)
+ {
+ const int listIndex = m_dasmView->view()->source_index(*source);
+ m_cpuComboBox->setCurrentIndex(listIndex);
+ }
+ }
}
-void DasmWindowQtConfig::recoverFromXmlNode(util::xml::data_node const &node)
-{
- WindowQtConfig::recoverFromXmlNode(node);
- m_cpu = node.get_attribute_int("cpu", m_cpu);
- m_rightBar = node.get_attribute_int("rightbar", m_rightBar);
-}
+} // namespace osd::debugger::qt
diff --git a/src/osd/modules/debugger/qt/dasmwindow.h b/src/osd/modules/debugger/qt/dasmwindow.h
index 27b652c04e8..df3fc0699a8 100644
--- a/src/osd/modules/debugger/qt/dasmwindow.h
+++ b/src/osd/modules/debugger/qt/dasmwindow.h
@@ -1,14 +1,18 @@
// license:BSD-3-Clause
// copyright-holders:Andrew Gardner
-#ifndef __DEBUG_QT_DASM_WINDOW_H__
-#define __DEBUG_QT_DASM_WINDOW_H__
+#ifndef MAME_DEBUGGER_QT_DASMWINDOW_H
+#define MAME_DEBUGGER_QT_DASMWINDOW_H
-#include <QtWidgets/QLineEdit>
-#include <QtWidgets/QComboBox>
+#pragma once
#include "debuggerview.h"
#include "windowqt.h"
+#include <QtWidgets/QComboBox>
+#include <QtWidgets/QLineEdit>
+
+
+namespace osd::debugger::qt {
//============================================================
// The Disassembly Window.
@@ -18,62 +22,47 @@ class DasmWindow : public WindowQt
Q_OBJECT
public:
- DasmWindow(running_machine* machine, QWidget* parent=nullptr);
+ DasmWindow(DebuggerQt &debugger, QWidget *parent = nullptr);
virtual ~DasmWindow();
+ virtual void restoreConfiguration(util::xml::data_node const &node) override;
+
+protected:
+ virtual void saveConfigurationToNode(util::xml::data_node &node) override;
+
+ // Used to intercept the user hitting the up arrow in the input widget
+ virtual bool eventFilter(QObject *obj, QEvent *event) override;
private slots:
void cpuChanged(int index);
void expressionSubmitted();
+ void expressionEdited(QString const &text);
void toggleBreakpointAtCursor(bool changedTo);
void enableBreakpointAtCursor(bool changedTo);
void runToCursor(bool changedTo);
- void rightBarChanged(QAction* changedTo);
+ void rightBarChanged(QAction *changedTo);
void dasmViewUpdated();
-
private:
void populateComboBox();
-
+ void setToCurrentCpu();
// Widgets
- QLineEdit* m_inputEdit;
- QComboBox* m_cpuComboBox;
- DebuggerView* m_dasmView;
+ QLineEdit *m_inputEdit;
+ QComboBox *m_cpuComboBox;
+ DebuggerView *m_dasmView;
// Menu items
- QAction* m_breakpointToggleAct;
- QAction* m_breakpointEnableAct;
- QAction* m_runToCursorAct;
-};
+ QAction *m_breakpointToggleAct;
+ QAction *m_breakpointEnableAct;
+ QAction *m_runToCursorAct;
-
-//=========================================================================
-// A way to store the configuration of a window long enough to read/write.
-//=========================================================================
-class DasmWindowQtConfig : public WindowQtConfig
-{
-public:
- DasmWindowQtConfig() :
- WindowQtConfig(WIN_TYPE_DASM),
- m_cpu(0),
- m_rightBar(0)
- {
- }
-
- ~DasmWindowQtConfig() {}
-
- // Settings
- int m_cpu;
- int m_rightBar;
-
- void buildFromQWidget(QWidget* widget);
- void applyToQWidget(QWidget* widget);
- void addToXmlDataNode(util::xml::data_node &node) const;
- void recoverFromXmlNode(util::xml::data_node const &node);
+ // Expression history
+ CommandHistory m_inputHistory;
};
+} // namespace osd::debugger::qt
-#endif
+#endif // MAME_DEBUGGER_QT_DASMWINDOW_H
diff --git a/src/osd/modules/debugger/qt/debuggerview.cpp b/src/osd/modules/debugger/qt/debuggerview.cpp
index 7dc16c0a3de..6a184dcfcca 100644
--- a/src/osd/modules/debugger/qt/debuggerview.cpp
+++ b/src/osd/modules/debugger/qt/debuggerview.cpp
@@ -1,80 +1,96 @@
// license:BSD-3-Clause
// copyright-holders:Andrew Gardner
#include "emu.h"
-#include <QtWidgets/QScrollBar>
-#include <QtWidgets/QApplication>
-#include <QtGui/QPainter>
-#include <QtGui/QKeyEvent>
-
#include "debuggerview.h"
+#include "../xmlconfig.h"
+
#include "modules/lib/osdobj_common.h"
+#include "xmlfile.h"
+
+#include <QtCore/QMimeData>
+#include <QtGui/QClipboard>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QPainter>
+#include <QtWidgets/QApplication>
+#include <QtWidgets/QScrollBar>
-DebuggerView::DebuggerView(const debug_view_type& type,
- running_machine* machine,
- QWidget* parent) :
+
+namespace osd::debugger::qt {
+
+DebuggerView::DebuggerView(
+ debug_view_type type,
+ running_machine &machine,
+ QWidget *parent) :
QAbstractScrollArea(parent),
- m_preferBottom(false),
+ m_machine(machine),
m_view(nullptr),
- m_machine(machine)
+ m_preferBottom(false)
{
- // I like setting the font per-view since it doesn't override the menuing fonts.
- const char *const selectedFont(downcast<osd_options &>(m_machine->options()).debugger_font());
- const float selectedFontSize(downcast<osd_options &>(m_machine->options()).debugger_font_size());
+ // I like setting the font per-view since it doesn't override the menu fonts.
+ const char *const selectedFont(downcast<osd_options &>(m_machine.options()).debugger_font());
+ const float selectedFontSize(downcast<osd_options &>(m_machine.options()).debugger_font_size());
QFont viewFontRequest((!*selectedFont || !strcmp(selectedFont, OSDOPTVAL_AUTO)) ? "Courier New" : selectedFont);
viewFontRequest.setFixedPitch(true);
viewFontRequest.setStyleHint(QFont::TypeWriter);
viewFontRequest.setPointSize((selectedFontSize <= 0) ? 11 : selectedFontSize);
setFont(viewFontRequest);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
- m_view = m_machine->debug_view().alloc_view(type,
- DebuggerView::debuggerViewUpdate,
- this);
+ m_view = m_machine.debug_view().alloc_view(
+ type,
+ DebuggerView::debuggerViewUpdate,
+ this);
- connect(verticalScrollBar(), &QScrollBar::valueChanged,
- this, &DebuggerView::verticalScrollSlot);
- connect(horizontalScrollBar(), &QScrollBar::valueChanged,
- this, &DebuggerView::horizontalScrollSlot);
+ connect(verticalScrollBar(), &QScrollBar::valueChanged, this, &DebuggerView::verticalScrollSlot);
+ connect(horizontalScrollBar(), &QScrollBar::valueChanged, this, &DebuggerView::horizontalScrollSlot);
}
DebuggerView::~DebuggerView()
{
- if (m_machine && m_view)
- m_machine->debug_view().free_view(*m_view);
+ if (m_view)
+ m_machine.debug_view().free_view(*m_view);
+}
+
+
+int DebuggerView::sourceIndex() const
+{
+ if (m_view)
+ {
+ debug_view_source const *const source = m_view->source();
+ if (source)
+ return m_view->source_index(*source);
+ }
+ return -1;
}
-void DebuggerView::paintEvent(QPaintEvent* event)
+
+void DebuggerView::paintEvent(QPaintEvent *event)
{
// Tell the MAME debug view how much real estate is available
QFontMetrics actualFont = fontMetrics();
- const double fontWidth = actualFont.width(QString(100, '_')) / 100.;
- const int fontHeight = std::max(1, actualFont.lineSpacing());
- m_view->set_visible_size(debug_view_xy(width()/fontWidth, height()/fontHeight));
-
+ double const fontWidth = actualFont.horizontalAdvance(QString(100, '_')) / 100.;
+ int const fontHeight = std::max(1, actualFont.lineSpacing());
+ int const contentWidth = width() - verticalScrollBar()->width();
+ int const lineWidth = contentWidth / fontWidth;
+ bool const fullWidth = lineWidth >= m_view->total_size().x;
+ int const contentHeight = height() - (fullWidth ? 0 : horizontalScrollBar()->height());
+ m_view->set_visible_size(debug_view_xy(lineWidth, contentHeight / fontHeight));
// Handle the scroll bars
- const int horizontalScrollCharDiff = m_view->total_size().x - m_view->visible_size().x;
- const int horizontalScrollSize = horizontalScrollCharDiff < 0 ? 0 : horizontalScrollCharDiff;
- horizontalScrollBar()->setRange(0, horizontalScrollSize);
-
- // If the horizontal scroll bar appears, make sure to adjust the vertical scrollbar accordingly
- const int verticalScrollAdjust = horizontalScrollSize > 0 ? 1 : 0;
+ int const horizontalScrollCharDiff = m_view->total_size().x - m_view->visible_size().x;
+ horizontalScrollBar()->setRange(0, (std::max)(0, horizontalScrollCharDiff));
+ horizontalScrollBar()->setPageStep(lineWidth - 1);
- const int verticalScrollCharDiff = m_view->total_size().y - m_view->visible_size().y;
- const int verticalScrollSize = verticalScrollCharDiff < 0 ? 0 : verticalScrollCharDiff+verticalScrollAdjust;
- bool atEnd = false;
- if (verticalScrollBar()->value() == verticalScrollBar()->maximum())
- {
- atEnd = true;
- }
+ int const verticalScrollCharDiff = m_view->total_size().y - m_view->visible_size().y;
+ int const verticalScrollSize = (std::max)(0, verticalScrollCharDiff);
+ bool const atEnd = verticalScrollBar()->value() == verticalScrollBar()->maximum();
verticalScrollBar()->setRange(0, verticalScrollSize);
+ verticalScrollBar()->setPageStep((contentHeight / fontHeight) - 1);
if (m_preferBottom && atEnd)
- {
verticalScrollBar()->setValue(verticalScrollSize);
- }
-
// Draw the viewport widget
QPainter painter(viewport());
@@ -87,84 +103,130 @@ void DebuggerView::paintEvent(QPaintEvent* event)
bgBrush.setStyle(Qt::SolidPattern);
painter.setPen(QPen(QColor(0,0,0)));
- size_t viewDataOffset = 0;
- const debug_view_xy& visibleCharDims = m_view->visible_size();
- const debug_view_char* viewdata = m_view->viewdata();
- for (int y = 0; y < visibleCharDims.y; y++)
+ const debug_view_xy visibleCharDims = m_view->visible_size();
+ const debug_view_char *viewdata = m_view->viewdata();
+ for (int y = 0; y < visibleCharDims.y; y++, viewdata += visibleCharDims.x)
{
int width = 1;
- for (int x = 0; x < visibleCharDims.x; viewDataOffset += width, x += width)
+ for (int x = 0; x < visibleCharDims.x; x += width)
{
- const unsigned char textAttr = viewdata[viewDataOffset].attrib;
+ const unsigned char textAttr = viewdata[x].attrib;
// Text color handling
QColor fgColor(0,0,0);
QColor bgColor(255,255,255);
- if(textAttr & DCA_VISITED)
- {
+ if (textAttr & DCA_VISITED)
bgColor.setRgb(0xc6, 0xe2, 0xff);
- }
- if(textAttr & DCA_ANCILLARY)
- {
+
+ if (textAttr & DCA_ANCILLARY)
bgColor.setRgb(0xe0, 0xe0, 0xe0);
- }
- if(textAttr & DCA_SELECTED)
- {
+
+ if (textAttr & DCA_SELECTED)
bgColor.setRgb(0xff, 0x80, 0x80);
- }
- if(textAttr & DCA_CURRENT)
- {
+
+ if (textAttr & DCA_CURRENT)
bgColor.setRgb(0xff, 0xff, 0x00);
- }
+
if ((textAttr & DCA_SELECTED) && (textAttr & DCA_CURRENT))
- {
bgColor.setRgb(0xff,0xc0,0x80);
- }
- if(textAttr & DCA_CHANGED)
- {
+
+ if (textAttr & DCA_CHANGED)
fgColor.setRgb(0xff, 0x00, 0x00);
- }
- if(textAttr & DCA_INVALID)
- {
+
+ if (textAttr & DCA_INVALID)
fgColor.setRgb(0x00, 0x00, 0xff);
- }
- if(textAttr & DCA_DISABLED)
+
+ if (textAttr & DCA_DISABLED)
{
- fgColor.setRgb((fgColor.red() + bgColor.red()) >> 1,
- (fgColor.green() + bgColor.green()) >> 1,
- (fgColor.blue() + bgColor.blue()) >> 1);
+ fgColor.setRgb(
+ (fgColor.red() + bgColor.red()) >> 1,
+ (fgColor.green() + bgColor.green()) >> 1,
+ (fgColor.blue() + bgColor.blue()) >> 1);
}
- if(textAttr & DCA_COMMENT)
- {
+
+ if (textAttr & DCA_COMMENT)
fgColor.setRgb(0x00, 0x80, 0x00);
- }
bgBrush.setColor(bgColor);
painter.setBackground(bgBrush);
painter.setPen(QPen(fgColor));
- QString text(QChar(viewdata[viewDataOffset].byte));
- for (width = 1; x + width < visibleCharDims.x; width++)
+ QString text(QChar(viewdata[x].byte));
+ for (width = 1; (x + width) < visibleCharDims.x; width++)
{
- if (textAttr != viewdata[viewDataOffset + width].attrib)
+ if (textAttr != viewdata[x + width].attrib)
break;
- text.append(QChar(viewdata[viewDataOffset + width].byte));
+ text.append(QChar(viewdata[x + width].byte));
}
// Your characters are not guaranteed to take up the entire length x fontWidth x fontHeight, so fill before.
- painter.fillRect(x*fontWidth, y*fontHeight, width*fontWidth, fontHeight, bgBrush);
+ painter.fillRect(
+ x * fontWidth,
+ y * fontHeight,
+ ((x + width) < visibleCharDims.x) ? (width * fontWidth) : (contentWidth - (x * fontWidth)),
+ fontHeight,
+ bgBrush);
+
+ if (((y + 1) == visibleCharDims.y) && (contentHeight > (visibleCharDims.y * fontHeight)))
+ {
+ if (textAttr & DCA_ANCILLARY)
+ bgColor.setRgb(0xe0, 0xe0, 0xe0);
+ else
+ bgColor.setRgb(0xff, 0xff, 0xff);
+ bgBrush.setColor(bgColor);
+ painter.fillRect(
+ x * fontWidth,
+ visibleCharDims.y * fontHeight,
+ ((x + width) < visibleCharDims.x) ? (width * fontWidth) : (contentWidth - (x * fontWidth)),
+ contentHeight - (visibleCharDims.y * fontHeight),
+ bgBrush);
+ }
// There is a touchy interplay between font height, drawing difference, visible position, etc
// Fonts don't get drawn "down and to the left" like boxes, so some wiggling is needed.
- painter.drawText(x*fontWidth, (y*fontHeight + (fontHeight*0.80)), text);
+ painter.drawText(x * fontWidth, (y * fontHeight + (fontHeight * 0.80)), text);
+ }
+ }
+}
+
+
+void DebuggerView::restoreConfigurationFromNode(util::xml::data_node const &node)
+{
+ if (m_view->cursor_supported())
+ {
+ util::xml::data_node const *const selection = node.get_child(NODE_WINDOW_SELECTION);
+ if (selection)
+ {
+ debug_view_xy pos = m_view->cursor_position();
+ m_view->set_cursor_visible(0 != selection->get_attribute_int(ATTR_SELECTION_CURSOR_VISIBLE, m_view->cursor_visible() ? 1 : 0));
+ selection->get_attribute_int(ATTR_SELECTION_CURSOR_X, pos.x);
+ selection->get_attribute_int(ATTR_SELECTION_CURSOR_Y, pos.y);
+ m_view->set_cursor_position(pos);
+ }
+ }
+}
+
+
+void DebuggerView::saveConfigurationToNode(util::xml::data_node &node)
+{
+ if (m_view->cursor_supported())
+ {
+ util::xml::data_node *const selection = node.add_child(NODE_WINDOW_SELECTION, nullptr);
+ if (selection)
+ {
+ debug_view_xy const pos = m_view->cursor_position();
+ selection->set_attribute_int(ATTR_SELECTION_CURSOR_VISIBLE, m_view->cursor_visible() ? 1 : 0);
+ selection->set_attribute_int(ATTR_SELECTION_CURSOR_X, pos.x);
+ selection->set_attribute_int(ATTR_SELECTION_CURSOR_Y, pos.y);
}
}
}
+
void DebuggerView::keyPressEvent(QKeyEvent* event)
{
- if (m_view == nullptr)
+ if (!m_view)
return QWidget::keyPressEvent(event);
Qt::KeyboardModifiers keyMods = QApplication::keyboardModifiers();
@@ -173,52 +235,54 @@ void DebuggerView::keyPressEvent(QKeyEvent* event)
int keyPress = -1;
switch (event->key())
{
- case Qt::Key_Up:
- keyPress = DCH_UP;
- break;
- case Qt::Key_Down:
- keyPress = DCH_DOWN;
- break;
- case Qt::Key_Left:
- keyPress = DCH_LEFT;
- if (ctrlDown) keyPress = DCH_CTRLLEFT;
- break;
- case Qt::Key_Right:
- keyPress = DCH_RIGHT;
- if (ctrlDown) keyPress = DCH_CTRLRIGHT;
- break;
- case Qt::Key_PageUp:
- keyPress = DCH_PUP;
- break;
- case Qt::Key_PageDown:
- keyPress = DCH_PDOWN;
- break;
- case Qt::Key_Home:
- keyPress = DCH_HOME;
- if (ctrlDown) keyPress = DCH_CTRLHOME;
- break;
- case Qt::Key_End:
- keyPress = DCH_END;
- if (ctrlDown) keyPress = DCH_CTRLEND;
- break;
- case Qt::Key_0: keyPress = '0'; break;
- case Qt::Key_1: keyPress = '1'; break;
- case Qt::Key_2: keyPress = '2'; break;
- case Qt::Key_3: keyPress = '3'; break;
- case Qt::Key_4: keyPress = '4'; break;
- case Qt::Key_5: keyPress = '5'; break;
- case Qt::Key_6: keyPress = '6'; break;
- case Qt::Key_7: keyPress = '7'; break;
- case Qt::Key_8: keyPress = '8'; break;
- case Qt::Key_9: keyPress = '9'; break;
- case Qt::Key_A: keyPress = 'a'; break;
- case Qt::Key_B: keyPress = 'b'; break;
- case Qt::Key_C: keyPress = 'c'; break;
- case Qt::Key_D: keyPress = 'd'; break;
- case Qt::Key_E: keyPress = 'e'; break;
- case Qt::Key_F: keyPress = 'f'; break;
- default:
- return QWidget::keyPressEvent(event);
+ case Qt::Key_Up:
+ keyPress = DCH_UP;
+ break;
+ case Qt::Key_Down:
+ keyPress = DCH_DOWN;
+ break;
+ case Qt::Key_Left:
+ keyPress = DCH_LEFT;
+ if (ctrlDown)
+ keyPress = DCH_CTRLLEFT;
+ break;
+ case Qt::Key_Right:
+ keyPress = DCH_RIGHT;
+ if (ctrlDown)
+ keyPress = DCH_CTRLRIGHT;
+ break;
+ case Qt::Key_PageUp:
+ keyPress = DCH_PUP;
+ break;
+ case Qt::Key_PageDown:
+ keyPress = DCH_PDOWN;
+ break;
+ case Qt::Key_Home:
+ keyPress = DCH_HOME;
+ if (ctrlDown) keyPress = DCH_CTRLHOME;
+ break;
+ case Qt::Key_End:
+ keyPress = DCH_END;
+ if (ctrlDown) keyPress = DCH_CTRLEND;
+ break;
+ case Qt::Key_0: keyPress = '0'; break;
+ case Qt::Key_1: keyPress = '1'; break;
+ case Qt::Key_2: keyPress = '2'; break;
+ case Qt::Key_3: keyPress = '3'; break;
+ case Qt::Key_4: keyPress = '4'; break;
+ case Qt::Key_5: keyPress = '5'; break;
+ case Qt::Key_6: keyPress = '6'; break;
+ case Qt::Key_7: keyPress = '7'; break;
+ case Qt::Key_8: keyPress = '8'; break;
+ case Qt::Key_9: keyPress = '9'; break;
+ case Qt::Key_A: keyPress = 'a'; break;
+ case Qt::Key_B: keyPress = 'b'; break;
+ case Qt::Key_C: keyPress = 'c'; break;
+ case Qt::Key_D: keyPress = 'd'; break;
+ case Qt::Key_E: keyPress = 'e'; break;
+ case Qt::Key_F: keyPress = 'f'; break;
+ default:
+ return QWidget::keyPressEvent(event);
}
m_view->set_cursor_visible(true);
@@ -232,26 +296,65 @@ void DebuggerView::keyPressEvent(QKeyEvent* event)
}
-void DebuggerView::mousePressEvent(QMouseEvent* event)
+void DebuggerView::mousePressEvent(QMouseEvent *event)
{
- if (m_view == nullptr)
+ if (!m_view)
return;
+ QFontMetrics actualFont = fontMetrics();
+ const double fontWidth = actualFont.horizontalAdvance(QString(100, '_')) / 100.;
+ const int fontHeight = std::max(1, actualFont.lineSpacing());
+
+ debug_view_xy const topLeft = m_view->visible_position();
+ debug_view_xy const visibleCharDims = m_view->visible_size();
+ debug_view_xy clickViewPosition;
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ const QPointF mousePosition = event->position();
+#else
+ const QPointF mousePosition = event->localPos();
+#endif
+ clickViewPosition.x = (std::min)(int(topLeft.x + (mousePosition.x() / fontWidth)), topLeft.x + visibleCharDims.x - 1);
+ clickViewPosition.y = (std::min)(int(topLeft.y + (mousePosition.y() / fontHeight)), topLeft.y + visibleCharDims.y - 1);
+
if (event->button() == Qt::LeftButton)
{
- QFontMetrics actualFont = fontMetrics();
- const double fontWidth = actualFont.width(QString(100, '_')) / 100.;
- const int fontHeight = std::max(1, actualFont.lineSpacing());
-
- debug_view_xy topLeft = m_view->visible_position();
- debug_view_xy clickViewPosition;
- clickViewPosition.x = topLeft.x + (event->x() / fontWidth);
- clickViewPosition.y = topLeft.y + (event->y() / fontHeight);
m_view->process_click(DCK_LEFT_CLICK, clickViewPosition);
-
- viewport()->update();
- update();
}
+ else if (event->button() == Qt::MiddleButton)
+ {
+ m_view->process_click(DCK_MIDDLE_CLICK, clickViewPosition);
+ }
+ else if (event->button() == Qt::RightButton)
+ {
+ if (m_view->cursor_supported())
+ {
+ m_view->set_cursor_position(clickViewPosition);
+ m_view->set_cursor_visible(true);
+ }
+ }
+
+ viewport()->update();
+ update();
+}
+
+
+void DebuggerView::contextMenuEvent(QContextMenuEvent *event)
+{
+ QMenu *const menu = new QMenu(this);
+ addItemsToContextMenu(menu);
+ menu->popup(event->globalPos());
+}
+
+
+void DebuggerView::addItemsToContextMenu(QMenu *menu)
+{
+ QAction *const copyAct = new QAction("Copy Visible", menu);
+ QAction *const pasteAct = new QAction("Paste", menu);
+ pasteAct->setEnabled(QApplication::clipboard()->mimeData()->hasText());
+ connect(copyAct, &QAction::triggered, this, &DebuggerView::copyVisibleSlot);
+ connect(pasteAct, &QAction::triggered, this, &DebuggerView::pasteSlot);
+ menu->addAction(copyAct);
+ menu->addAction(pasteAct);
}
@@ -267,13 +370,51 @@ void DebuggerView::horizontalScrollSlot(int value)
}
-void DebuggerView::debuggerViewUpdate(debug_view& debugView, void* osdPrivate)
+void DebuggerView::copyVisibleSlot()
{
- // Get a handle to the DebuggerView being updated & redraw
- DebuggerView* dView = (DebuggerView*)osdPrivate;
+ // get visible text
+ debug_view_xy const visarea = m_view->visible_size();
+ debug_view_char const *viewdata = m_view->viewdata();
+ if (!viewdata)
+ return;
+
+ // turn into a plain string, trimming trailing whitespace
+ std::string text;
+ for (uint32_t row = 0; row < visarea.y; row++, viewdata += visarea.x)
+ {
+ std::string::size_type const start = text.length();
+ for (uint32_t col = 0; col < visarea.x; ++col)
+ text += wchar_t(viewdata[col].byte);
+ std::string::size_type const nonblank = text.find_last_not_of("\t\n\v\r ");
+ if (nonblank != std::string::npos)
+ text.resize((std::max)(start, nonblank + 1));
+ text += "\n";
+ }
+
+ // copy to the clipboard
+ QApplication::clipboard()->setText(text.c_str());
+}
+
+
+void DebuggerView::pasteSlot()
+{
+ for (QChar ch : QApplication::clipboard()->text())
+ {
+ if ((32 <= ch.unicode()) && (127 >= ch.unicode()))
+ m_view->process_char(ch.unicode());
+ }
+}
+
+
+void DebuggerView::debuggerViewUpdate(debug_view &debugView, void *osdPrivate)
+{
+ // Get a handle to the DebuggerView being updated and redraw
+ DebuggerView *dView = reinterpret_cast<DebuggerView *>(osdPrivate);
dView->verticalScrollBar()->setValue(dView->view()->visible_position().y);
dView->horizontalScrollBar()->setValue(dView->view()->visible_position().x);
dView->viewport()->update();
dView->update();
emit dView->updated();
}
+
+} // namespace osd::debugger::qt
diff --git a/src/osd/modules/debugger/qt/debuggerview.h b/src/osd/modules/debugger/qt/debuggerview.h
index 2e1f35eb306..cc68dd69d30 100644
--- a/src/osd/modules/debugger/qt/debuggerview.h
+++ b/src/osd/modules/debugger/qt/debuggerview.h
@@ -1,50 +1,63 @@
// license:BSD-3-Clause
// copyright-holders:Andrew Gardner
-#ifndef __DEBUG_QT_DEBUGGER_VIEW_H__
-#define __DEBUG_QT_DEBUGGER_VIEW_H__
+#ifndef MAME_DEBUGGER_QT_DEBUGGERVIEW_H
+#define MAME_DEBUGGER_QT_DEBUGGERVIEW_H
-#include <QtWidgets/QAbstractScrollArea>
+#pragma once
#include "debug/debugvw.h"
+#include <QtWidgets/QAbstractScrollArea>
+#include <QtWidgets/QMenu>
+
+
+namespace osd::debugger::qt {
class DebuggerView : public QAbstractScrollArea
{
Q_OBJECT
public:
- DebuggerView(const debug_view_type& type,
- running_machine* machine,
- QWidget* parent=nullptr);
+ DebuggerView(debug_view_type type, running_machine &machine, QWidget *parent = nullptr);
virtual ~DebuggerView();
- void paintEvent(QPaintEvent* event);
+ virtual void paintEvent(QPaintEvent *event) override;
// Setters and accessors
void setPreferBottom(bool pb) { m_preferBottom = pb; }
- debug_view* view() { return m_view; }
+ debug_view *view() { return m_view; }
+ template <typename T> T *view() { return downcast<T *>(m_view); }
+ int sourceIndex() const;
+
+ virtual void restoreConfigurationFromNode(util::xml::data_node const &node);
+ virtual void saveConfigurationToNode(util::xml::data_node &node);
signals:
void updated();
protected:
- void keyPressEvent(QKeyEvent* event);
- void mousePressEvent(QMouseEvent* event);
+ virtual void keyPressEvent(QKeyEvent *event) override;
+ virtual void mousePressEvent(QMouseEvent *event) override;
+ virtual void contextMenuEvent(QContextMenuEvent *event) override;
+
+ virtual void addItemsToContextMenu(QMenu *menu);
private slots:
void verticalScrollSlot(int value);
void horizontalScrollSlot(int value);
-
+ void copyVisibleSlot();
+ void pasteSlot();
private:
// Callback to allow MAME to refresh the view
- static void debuggerViewUpdate(debug_view& debugView, void* osdPrivate);
+ static void debuggerViewUpdate(debug_view &debugView, void *osdPrivate);
- bool m_preferBottom;
+ running_machine &m_machine;
+ debug_view *m_view;
- debug_view* m_view;
- running_machine* m_machine;
+ bool m_preferBottom;
};
+} // namespace osd::debugger::qt
-#endif
+#endif // MAME_DEBUGGER_QT_DEBUGGERVIEW_H
diff --git a/src/osd/modules/debugger/qt/deviceinformationwindow.cpp b/src/osd/modules/debugger/qt/deviceinformationwindow.cpp
index 66142462a3b..2e06d8fb1ed 100644
--- a/src/osd/modules/debugger/qt/deviceinformationwindow.cpp
+++ b/src/osd/modules/debugger/qt/deviceinformationwindow.cpp
@@ -1,25 +1,28 @@
// license:BSD-3-Clause
// copyright-holders:Andrew Gardner
#include "emu.h"
+#include "deviceinformationwindow.h"
+
+#include "util/xmlfile.h"
+
#include <QtWidgets/QFrame>
#include <QtWidgets/QLabel>
#include <QtWidgets/QVBoxLayout>
-#include "deviceinformationwindow.h"
+namespace osd::debugger::qt {
-DeviceInformationWindow::DeviceInformationWindow(running_machine* machine, device_t* device, QWidget* parent) :
- WindowQt(machine, nullptr)
+DeviceInformationWindow::DeviceInformationWindow(DebuggerQt &debugger, device_t *device, QWidget *parent) :
+ WindowQt(debugger, nullptr),
+ m_device(device)
{
- m_device = device;
-
- if (parent != nullptr)
+ if (parent)
{
QPoint parentPos = parent->pos();
setGeometry(parentPos.x()+100, parentPos.y()+100, 600, 400);
}
- if(m_device)
+ if (m_device)
fill_device_information();
}
@@ -28,12 +31,29 @@ DeviceInformationWindow::~DeviceInformationWindow()
{
}
-void DeviceInformationWindow::fill_device_information()
+
+void DeviceInformationWindow::restoreConfiguration(util::xml::data_node const &node)
{
- char title[4069];
- sprintf(title, "Debug: Device %s", m_device->tag());
- setWindowTitle(title);
+ WindowQt::restoreConfiguration(node);
+ auto const tag = node.get_attribute_string(ATTR_WINDOW_DEVICE_TAG, ":");
+ set_device(tag);
+}
+
+
+void DeviceInformationWindow::saveConfigurationToNode(util::xml::data_node &node)
+{
+ WindowQt::saveConfigurationToNode(node);
+
+ node.set_attribute_int(ATTR_WINDOW_TYPE, WINDOW_TYPE_DEVICE_INFO_VIEWER);
+
+ node.set_attribute(ATTR_WINDOW_DEVICE_TAG, m_device->tag());
+}
+
+
+void DeviceInformationWindow::fill_device_information()
+{
+ setWindowTitle(util::string_format("Debug: Device %s", m_device->tag()).c_str());
QFrame *mainWindowFrame = new QFrame(this);
QVBoxLayout *vLayout = new QVBoxLayout(mainWindowFrame);
@@ -53,9 +73,11 @@ void DeviceInformationWindow::fill_device_information()
int cpos = 3;
device_interface *intf = m_device->interfaces().first();
- if(intf) {
+ if (intf)
+ {
gl1->addWidget(new QLabel(QString("Interfaces"), primaryFrame), cpos, 0);
- while(intf) {
+ while(intf)
+ {
gl1->addWidget(new QLabel(QString(intf->interface_type()), primaryFrame), cpos, 1);
cpos++;
intf = intf->interface_next();
@@ -65,16 +87,19 @@ void DeviceInformationWindow::fill_device_information()
vLayout->addWidget(primaryFrame);
device_memory_interface *d_memory;
- if(m_device->interface(d_memory)) {
+ if (m_device->interface(d_memory))
+ {
QFrame *f = new QFrame(mainWindowFrame);
f->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
QVBoxLayout *vb = new QVBoxLayout(f);
bool first = true;
- for(int i=0; i<d_memory->max_space_count(); i++)
- if(d_memory->has_space(i)) {
+ for (int i=0; i<d_memory->max_space_count(); i++)
+ if (d_memory->has_space(i))
+ {
QFrame *ff = new QFrame(f);
QHBoxLayout *hb = new QHBoxLayout(ff);
- if(first) {
+ if (first)
+ {
hb->addWidget(new QLabel("Memory maps"));
first = false;
}
@@ -92,46 +117,10 @@ void DeviceInformationWindow::fill_device_information()
void DeviceInformationWindow::set_device(const char *tag)
{
- m_device = m_machine->root_device().subdevice(tag);
- if(!m_device)
- m_device = &m_machine->root_device();
+ m_device = m_machine.root_device().subdevice(tag);
+ if (!m_device)
+ m_device = &m_machine.root_device();
fill_device_information();
}
-const char *DeviceInformationWindow::device_tag() const
-{
- return m_device->tag();
-}
-
-
-//=========================================================================
-// DeviceInformationWindowQtConfig
-//=========================================================================
-void DeviceInformationWindowQtConfig::buildFromQWidget(QWidget* widget)
-{
- WindowQtConfig::buildFromQWidget(widget);
- DeviceInformationWindow* window = dynamic_cast<DeviceInformationWindow*>(widget);
- m_device_tag = window->device_tag();
-}
-
-
-void DeviceInformationWindowQtConfig::applyToQWidget(QWidget* widget)
-{
- WindowQtConfig::applyToQWidget(widget);
- DeviceInformationWindow* window = dynamic_cast<DeviceInformationWindow*>(widget);
- window->set_device(m_device_tag.c_str());
-}
-
-
-void DeviceInformationWindowQtConfig::addToXmlDataNode(util::xml::data_node &node) const
-{
- WindowQtConfig::addToXmlDataNode(node);
- node.set_attribute("device-tag", m_device_tag.c_str());
-}
-
-
-void DeviceInformationWindowQtConfig::recoverFromXmlNode(util::xml::data_node const &node)
-{
- WindowQtConfig::recoverFromXmlNode(node);
- m_device_tag = node.get_attribute_string("device-tag", ":");
-}
+} // namespace osd::debugger::qt
diff --git a/src/osd/modules/debugger/qt/deviceinformationwindow.h b/src/osd/modules/debugger/qt/deviceinformationwindow.h
index 5ed1bfbde91..e036a76e782 100644
--- a/src/osd/modules/debugger/qt/deviceinformationwindow.h
+++ b/src/osd/modules/debugger/qt/deviceinformationwindow.h
@@ -1,10 +1,15 @@
// license:BSD-3-Clause
// copyright-holders:Andrew Gardner
-#ifndef __DEBUG_QT_DEVICE_INFORMATION_WINDOW_H__
-#define __DEBUG_QT_DEVICE_INFORMATION_WINDOW_H__
+#ifndef MAME_DEBUGGER_QT_DEVICEINFORMATIONWINDOW_H
+#define MAME_DEBUGGER_QT_DEVICEINFORMATIONWINDOW_H
+
+#pragma once
#include "windowqt.h"
+
+namespace osd::debugger::qt {
+
//============================================================
// The Device Information Window.
//============================================================
@@ -13,11 +18,15 @@ class DeviceInformationWindow : public WindowQt
Q_OBJECT
public:
- DeviceInformationWindow(running_machine* machine, device_t* device = nullptr, QWidget* parent=nullptr);
+ DeviceInformationWindow(DebuggerQt &debugger, device_t *device = nullptr, QWidget* parent=nullptr);
virtual ~DeviceInformationWindow();
void set_device(const char *tag);
- const char *device_tag() const;
+
+ virtual void restoreConfiguration(util::xml::data_node const &node) override;
+
+protected:
+ virtual void saveConfigurationToNode(util::xml::data_node &node) override;
private:
device_t *m_device;
@@ -25,29 +34,6 @@ private:
void fill_device_information();
};
+} // namespace osd::debugger::qt
-
-
-//=========================================================================
-// A way to store the configuration of a window long enough to read/write.
-//=========================================================================
-class DeviceInformationWindowQtConfig : public WindowQtConfig
-{
-public:
- std::string m_device_tag;
-
- DeviceInformationWindowQtConfig() :
- WindowQtConfig(WIN_TYPE_DEVICE_INFORMATION)
- {
- }
-
- ~DeviceInformationWindowQtConfig() {}
-
- void buildFromQWidget(QWidget* widget);
- void applyToQWidget(QWidget* widget);
- void addToXmlDataNode(util::xml::data_node &node) const;
- void recoverFromXmlNode(util::xml::data_node const &node);
-};
-
-
-#endif
+#endif // MAME_DEBUGGER_QT_DEVICEINFORMATIONWINDOW_H
diff --git a/src/osd/modules/debugger/qt/deviceswindow.cpp b/src/osd/modules/debugger/qt/deviceswindow.cpp
index 6313e9bf98e..2c39c8cb0e8 100644
--- a/src/osd/modules/debugger/qt/deviceswindow.cpp
+++ b/src/osd/modules/debugger/qt/deviceswindow.cpp
@@ -2,11 +2,17 @@
// copyright-holders:Andrew Gardner
#include "emu.h"
#include "deviceswindow.h"
+
#include "deviceinformationwindow.h"
-DevicesWindowModel::DevicesWindowModel(running_machine *machine, QObject *parent)
+#include "util/xmlfile.h"
+
+
+namespace osd::debugger::qt {
+
+DevicesWindowModel::DevicesWindowModel(running_machine &machine, QObject *parent) :
+ m_machine(machine)
{
- m_machine = machine;
}
DevicesWindowModel::~DevicesWindowModel()
@@ -15,12 +21,13 @@ DevicesWindowModel::~DevicesWindowModel()
QVariant DevicesWindowModel::data(const QModelIndex &index, int role) const
{
- if(!index.isValid() || role != Qt::DisplayRole)
+ if (!index.isValid() || role != Qt::DisplayRole)
return QVariant();
device_t *dev = static_cast<device_t *>(index.internalPointer());
- switch(index.column()) {
- case 0: return dev == &m_machine->root_device() ? QString("<root>") : QString(dev->basetag());
+ switch (index.column())
+ {
+ case 0: return (dev == &m_machine.root_device()) ? QString("<root>") : QString(dev->basetag());
case 1: return QString(dev->name());
}
@@ -29,38 +36,41 @@ QVariant DevicesWindowModel::data(const QModelIndex &index, int role) const
Qt::ItemFlags DevicesWindowModel::flags(const QModelIndex &index) const
{
- if(!index.isValid())
- return 0;
+ if (!index.isValid())
+ return Qt::NoItemFlags;
return QAbstractItemModel::flags(index);
}
QVariant DevicesWindowModel::headerData(int section, Qt::Orientation orientation, int role) const
{
- if(role != Qt::DisplayRole || section < 0 || section >= 2)
+ if (role != Qt::DisplayRole || section < 0 || section >= 2)
return QVariant();
return QString(section ? "Name" : "Tag");
}
QModelIndex DevicesWindowModel::index(int row, int column, const QModelIndex &parent) const
{
- if(!hasIndex(row, column, parent))
+ if (!hasIndex(row, column, parent))
return QModelIndex();
device_t *target = nullptr;
- if(!parent.isValid()) {
- if(row == 0)
- target = &m_machine->root_device();
+ if (!parent.isValid())
+ {
+ if (row == 0)
+ target = &m_machine.root_device();
- } else {
+ }
+ else
+ {
device_t *dparent = static_cast<device_t *>(parent.internalPointer());
int count = row;
for(target = dparent->subdevices().first(); count && target; target = target->next())
count--;
}
- if(target)
+ if (target)
return createIndex(row, column, target);
return QModelIndex();
@@ -68,19 +78,20 @@ QModelIndex DevicesWindowModel::index(int row, int column, const QModelIndex &pa
QModelIndex DevicesWindowModel::parent(const QModelIndex &index) const
{
- if(!index.isValid())
+ if (!index.isValid())
return QModelIndex();
device_t *dchild = static_cast<device_t *>(index.internalPointer());
device_t *dparent = dchild->owner();
- if(!dparent)
+ if (!dparent)
return QModelIndex();
device_t *dpp = dparent->owner();
int row = 0;
- if(dpp) {
- for(device_t *child = dpp->subdevices().first(); child && child != dparent; child = child->next())
+ if (dpp)
+ {
+ for (device_t *child = dpp->subdevices().first(); child && child != dparent; child = child->next())
row++;
}
return createIndex(row, 0, dparent);
@@ -88,7 +99,7 @@ QModelIndex DevicesWindowModel::parent(const QModelIndex &index) const
int DevicesWindowModel::rowCount(const QModelIndex &parent) const
{
- if(!parent.isValid())
+ if (!parent.isValid())
return 1;
device_t *dparent = static_cast<device_t *>(parent.internalPointer());
@@ -102,9 +113,9 @@ int DevicesWindowModel::columnCount(const QModelIndex &parent) const
-DevicesWindow::DevicesWindow(running_machine* machine, QWidget* parent) :
- WindowQt(machine, nullptr),
- m_devices_model(machine)
+DevicesWindow::DevicesWindow(DebuggerQt &debugger, QWidget *parent) :
+ WindowQt(debugger, nullptr),
+ m_devices_model(debugger.machine())
{
m_selected_device = nullptr;
@@ -143,35 +154,15 @@ void DevicesWindow::currentRowChanged(const QModelIndex &current, const QModelIn
void DevicesWindow::activated(const QModelIndex &index)
{
device_t *dev = static_cast<device_t *>(index.internalPointer());
- (new DeviceInformationWindow(m_machine, dev, this))->show();
-}
-
-
-
-//=========================================================================
-// DevicesWindowQtConfig
-//=========================================================================
-void DevicesWindowQtConfig::buildFromQWidget(QWidget* widget)
-{
- WindowQtConfig::buildFromQWidget(widget);
- // DevicesWindow* window = dynamic_cast<DevicesWindow*>(widget);
+ (new DeviceInformationWindow(m_debugger, dev, this))->show();
}
-void DevicesWindowQtConfig::applyToQWidget(QWidget* widget)
+void DevicesWindow::saveConfigurationToNode(util::xml::data_node &node)
{
- WindowQtConfig::applyToQWidget(widget);
- // DevicesWindow* window = dynamic_cast<DevicesWindow*>(widget);
-}
+ WindowQt::saveConfigurationToNode(node);
-
-void DevicesWindowQtConfig::addToXmlDataNode(util::xml::data_node &node) const
-{
- WindowQtConfig::addToXmlDataNode(node);
+ node.set_attribute_int(ATTR_WINDOW_TYPE, WINDOW_TYPE_DEVICES_VIEWER);
}
-
-void DevicesWindowQtConfig::recoverFromXmlNode(util::xml::data_node const &node)
-{
- WindowQtConfig::recoverFromXmlNode(node);
-}
+} // namespace osd::debugger::qt
diff --git a/src/osd/modules/debugger/qt/deviceswindow.h b/src/osd/modules/debugger/qt/deviceswindow.h
index 87e710a001b..d337817fac0 100644
--- a/src/osd/modules/debugger/qt/deviceswindow.h
+++ b/src/osd/modules/debugger/qt/deviceswindow.h
@@ -1,12 +1,16 @@
// license:BSD-3-Clause
// copyright-holders:Andrew Gardner
-#ifndef __DEBUG_QT_DEVICES_WINDOW_H__
-#define __DEBUG_QT_DEVICES_WINDOW_H__
+#ifndef MAME_DEBUGGER_QT_DEVICESWINDOW_H
+#define MAME_DEBUGGER_QT_DEVICESWINDOW_H
-#include <QtWidgets/QTreeView>
+#pragma once
#include "windowqt.h"
+#include <QtWidgets/QTreeView>
+
+
+namespace osd::debugger::qt {
//============================================================
// The model for the treeview
@@ -17,21 +21,19 @@ class DevicesWindowModel : public QAbstractItemModel
Q_OBJECT
public:
- explicit DevicesWindowModel(running_machine *machine, QObject *parent = 0);
+ explicit DevicesWindowModel(running_machine &machine, QObject *parent = nullptr);
~DevicesWindowModel();
QVariant data(const QModelIndex &index, int role) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
- QVariant headerData(int section, Qt::Orientation orientation,
- int role = Qt::DisplayRole) const;
- QModelIndex index(int row, int column,
- const QModelIndex &parent = QModelIndex()) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex &index) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
private:
- running_machine *m_machine;
+ running_machine &m_machine;
};
//============================================================
@@ -42,40 +44,22 @@ class DevicesWindow : public WindowQt
Q_OBJECT
public:
- DevicesWindow(running_machine* machine, QWidget* parent=nullptr);
+ DevicesWindow(DebuggerQt &debugger, QWidget *parent = nullptr);
virtual ~DevicesWindow();
public slots:
void currentRowChanged(const QModelIndex &current, const QModelIndex &previous);
void activated(const QModelIndex &index);
+protected:
+ virtual void saveConfigurationToNode(util::xml::data_node &node) override;
+
private:
QTreeView *m_devices_view;
DevicesWindowModel m_devices_model;
device_t *m_selected_device;
};
+} // namespace osd::debugger::qt
-
-
-//=========================================================================
-// A way to store the configuration of a window long enough to read/write.
-//=========================================================================
-class DevicesWindowQtConfig : public WindowQtConfig
-{
-public:
- DevicesWindowQtConfig() :
- WindowQtConfig(WIN_TYPE_DEVICES)
- {
- }
-
- ~DevicesWindowQtConfig() {}
-
- void buildFromQWidget(QWidget* widget);
- void applyToQWidget(QWidget* widget);
- void addToXmlDataNode(util::xml::data_node &node) const;
- void recoverFromXmlNode(util::xml::data_node const &node);
-};
-
-
-#endif
+#endif // MAME_DEBUGGER_QT_DEVICESWINDOW_H
diff --git a/src/osd/modules/debugger/qt/logwindow.cpp b/src/osd/modules/debugger/qt/logwindow.cpp
index d0478a24e40..c3a6b442f0f 100644
--- a/src/osd/modules/debugger/qt/logwindow.cpp
+++ b/src/osd/modules/debugger/qt/logwindow.cpp
@@ -1,21 +1,21 @@
// license:BSD-3-Clause
// copyright-holders:Andrew Gardner
#include "emu.h"
-#include <QtWidgets/QVBoxLayout>
-
#include "logwindow.h"
-#include "debug/debugcon.h"
-#include "debug/debugcpu.h"
-#include "debug/dvdisasm.h"
+#include "util/xmlfile.h"
+
+#include <QtWidgets/QVBoxLayout>
+
+namespace osd::debugger::qt {
-LogWindow::LogWindow(running_machine* machine, QWidget* parent) :
- WindowQt(machine, nullptr)
+LogWindow::LogWindow(DebuggerQt &debugger, QWidget *parent) :
+ WindowQt(debugger, nullptr)
{
setWindowTitle("Debug: Machine Log");
- if (parent != nullptr)
+ if (parent)
{
QPoint parentPos = parent->pos();
setGeometry(parentPos.x()+100, parentPos.y()+100, 800, 400);
@@ -24,12 +24,10 @@ LogWindow::LogWindow(running_machine* machine, QWidget* parent) :
//
// The main frame and its input and log widgets
//
- QFrame* mainWindowFrame = new QFrame(this);
+ QFrame *mainWindowFrame = new QFrame(this);
// The main log view
- m_logView = new DebuggerView(DVT_LOG,
- m_machine,
- this);
+ m_logView = new DebuggerView(DVT_LOG, m_machine, this);
// Layout
QVBoxLayout* vLayout = new QVBoxLayout(mainWindowFrame);
@@ -46,28 +44,21 @@ LogWindow::~LogWindow()
}
-//=========================================================================
-// LogWindowQtConfig
-//=========================================================================
-void LogWindowQtConfig::buildFromQWidget(QWidget* widget)
+void LogWindow::restoreConfiguration(util::xml::data_node const &node)
{
- WindowQtConfig::buildFromQWidget(widget);
-}
+ WindowQt::restoreConfiguration(node);
-
-void LogWindowQtConfig::applyToQWidget(QWidget* widget)
-{
- WindowQtConfig::applyToQWidget(widget);
+ m_logView->restoreConfigurationFromNode(node);
}
-void LogWindowQtConfig::addToXmlDataNode(util::xml::data_node &node) const
+void LogWindow::saveConfigurationToNode(util::xml::data_node &node)
{
- WindowQtConfig::addToXmlDataNode(node);
-}
+ WindowQt::saveConfigurationToNode(node);
+ node.set_attribute_int(ATTR_WINDOW_TYPE, WINDOW_TYPE_ERROR_LOG_VIEWER);
-void LogWindowQtConfig::recoverFromXmlNode(util::xml::data_node const &node)
-{
- WindowQtConfig::recoverFromXmlNode(node);
+ m_logView->saveConfigurationToNode(node);
}
+
+} // namespace osd::debugger::qt
diff --git a/src/osd/modules/debugger/qt/logwindow.h b/src/osd/modules/debugger/qt/logwindow.h
index 53228ceafca..f85d490ea75 100644
--- a/src/osd/modules/debugger/qt/logwindow.h
+++ b/src/osd/modules/debugger/qt/logwindow.h
@@ -1,12 +1,16 @@
// license:BSD-3-Clause
// copyright-holders:Andrew Gardner
-#ifndef __DEBUG_QT_LOG_WINDOW_H__
-#define __DEBUG_QT_LOG_WINDOW_H__
+#ifndef MAME_DEBUGGER_QT_LOGWINDOW_H
+#define MAME_DEBUGGER_QT_LOGWINDOW_H
+
+#pragma once
#include "debuggerview.h"
#include "windowqt.h"
+namespace osd::debugger::qt {
+
//============================================================
// The Log Window.
//============================================================
@@ -15,34 +19,19 @@ class LogWindow : public WindowQt
Q_OBJECT
public:
- LogWindow(running_machine* machine, QWidget* parent=nullptr);
+ LogWindow(DebuggerQt &debugger, QWidget *parent = nullptr);
virtual ~LogWindow();
+ virtual void restoreConfiguration(util::xml::data_node const &node) override;
+
+protected:
+ virtual void saveConfigurationToNode(util::xml::data_node &node) override;
private:
// Widgets
- DebuggerView* m_logView;
-};
-
-
-//=========================================================================
-// A way to store the configuration of a window long enough to read/write.
-//=========================================================================
-class LogWindowQtConfig : public WindowQtConfig
-{
-public:
- LogWindowQtConfig() :
- WindowQtConfig(WIN_TYPE_LOG)
- {
- }
-
- ~LogWindowQtConfig() {}
-
- void buildFromQWidget(QWidget* widget);
- void applyToQWidget(QWidget* widget);
- void addToXmlDataNode(util::xml::data_node &node) const;
- void recoverFromXmlNode(util::xml::data_node const &node);
+ DebuggerView *m_logView;
};
+} // namespace osd::debugger::qt
-#endif
+#endif // MAME_DEBUGGER_QT_LOGWINDOW_H
diff --git a/src/osd/modules/debugger/qt/mainwindow.cpp b/src/osd/modules/debugger/qt/mainwindow.cpp
index 6a79ebf955d..0085dac364b 100644
--- a/src/osd/modules/debugger/qt/mainwindow.cpp
+++ b/src/osd/modules/debugger/qt/mainwindow.cpp
@@ -1,47 +1,57 @@
// license:BSD-3-Clause
// copyright-holders:Andrew Gardner
#include "emu.h"
-#include <QtWidgets/QAction>
-#include <QtWidgets/QMenu>
-#include <QtWidgets/QMenuBar>
-#include <QtWidgets/QDockWidget>
-#include <QtWidgets/QScrollBar>
-#include <QtWidgets/QFileDialog>
-#include <QtGui/QCloseEvent>
-
#include "mainwindow.h"
+#include "debugger.h"
#include "debug/debugcon.h"
#include "debug/debugcpu.h"
#include "debug/dvdisasm.h"
+#include "debug/points.h"
+#include "util/xmlfile.h"
-MainWindow::MainWindow(running_machine* machine, QWidget* parent) :
- WindowQt(machine, nullptr),
- m_historyIndex(0),
- m_inputHistory()
+#include <QtGui/QCloseEvent>
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+#include <QtGui/QAction>
+#include <QtGui/QActionGroup>
+#else
+#include <QtWidgets/QAction>
+#endif
+#include <QtWidgets/QDockWidget>
+#include <QtWidgets/QFileDialog>
+#include <QtWidgets/QMenu>
+#include <QtWidgets/QMenuBar>
+#include <QtWidgets/QScrollBar>
+
+
+namespace osd::debugger::qt {
+
+MainWindow::MainWindow(DebuggerQt &debugger, QWidget *parent) :
+ WindowQt(debugger, nullptr),
+ m_inputHistory(),
+ m_exiting(false)
{
setGeometry(300, 300, 1000, 600);
//
// The main frame and its input and log widgets
//
- QFrame* mainWindowFrame = new QFrame(this);
+ QFrame *mainWindowFrame = new QFrame(this);
// The input line
m_inputEdit = new QLineEdit(mainWindowFrame);
connect(m_inputEdit, &QLineEdit::returnPressed, this, &MainWindow::executeCommandSlot);
+ connect(m_inputEdit, &QLineEdit::textEdited, this, &MainWindow::commandEditedSlot);
m_inputEdit->installEventFilter(this);
// The log view
- m_consoleView = new DebuggerView(DVT_CONSOLE,
- m_machine,
- mainWindowFrame);
+ m_consoleView = new DebuggerView(DVT_CONSOLE, m_machine, mainWindowFrame);
m_consoleView->setFocusPolicy(Qt::NoFocus);
m_consoleView->setPreferBottom(true);
- QVBoxLayout* vLayout = new QVBoxLayout(mainWindowFrame);
+ QVBoxLayout *vLayout = new QVBoxLayout(mainWindowFrame);
vLayout->addWidget(m_consoleView);
vLayout->addWidget(m_inputEdit);
vLayout->setSpacing(3);
@@ -57,18 +67,21 @@ MainWindow::MainWindow(running_machine* machine, QWidget* parent) :
m_breakpointEnableAct = new QAction("Disable Breakpoint at Cursor", this);
m_runToCursorAct = new QAction("Run to Cursor", this);
m_breakpointToggleAct->setShortcut(Qt::Key_F9);
- m_breakpointEnableAct->setShortcut(Qt::SHIFT + Qt::Key_F9);
+ m_breakpointEnableAct->setShortcut(Qt::SHIFT | Qt::Key_F9);
m_runToCursorAct->setShortcut(Qt::Key_F4);
connect(m_breakpointToggleAct, &QAction::triggered, this, &MainWindow::toggleBreakpointAtCursor);
connect(m_breakpointEnableAct, &QAction::triggered, this, &MainWindow::enableBreakpointAtCursor);
connect(m_runToCursorAct, &QAction::triggered, this, &MainWindow::runToCursor);
// Right bar options
- QActionGroup* rightBarGroup = new QActionGroup(this);
+ QActionGroup *rightBarGroup = new QActionGroup(this);
rightBarGroup->setObjectName("rightbargroup");
- QAction* rightActRaw = new QAction("Raw Opcodes", this);
- QAction* rightActEncrypted = new QAction("Encrypted Opcodes", this);
- QAction* rightActComments = new QAction("Comments", this);
+ QAction *rightActRaw = new QAction("Raw Opcodes", this);
+ QAction *rightActEncrypted = new QAction("Encrypted Opcodes", this);
+ QAction *rightActComments = new QAction("Comments", this);
+ rightActRaw->setData(int(DASM_RIGHTCOL_RAW));
+ rightActEncrypted->setData(int(DASM_RIGHTCOL_ENCRYPTED));
+ rightActComments->setData(int(DASM_RIGHTCOL_COMMENTS));
rightActRaw->setCheckable(true);
rightActEncrypted->setCheckable(true);
rightActComments->setCheckable(true);
@@ -82,7 +95,7 @@ MainWindow::MainWindow(running_machine* machine, QWidget* parent) :
connect(rightBarGroup, &QActionGroup::triggered, this, &MainWindow::rightBarChanged);
// Assemble the options menu
- QMenu* optionsMenu = menuBar()->addMenu("&Options");
+ QMenu *optionsMenu = menuBar()->addMenu("&Options");
optionsMenu->addAction(m_breakpointToggleAct);
optionsMenu->addAction(m_breakpointEnableAct);
optionsMenu->addAction(m_runToCursorAct);
@@ -92,22 +105,20 @@ MainWindow::MainWindow(running_machine* machine, QWidget* parent) :
//
// Images menu
//
- image_interface_iterator imageIterTest(m_machine->root_device());
- if (imageIterTest.first() != nullptr)
- {
+ image_interface_enumerator imageIterTest(m_machine.root_device());
+ if (imageIterTest.first())
createImagesMenu();
- }
//
// Dock window menu
//
- QMenu* dockMenu = menuBar()->addMenu("Doc&ks");
+ QMenu *dockMenu = menuBar()->addMenu("Doc&ks");
setCorner(Qt::TopRightCorner, Qt::TopDockWidgetArea);
setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
// The processor dock
- QDockWidget* cpuDock = new QDockWidget("processor", this);
+ QDockWidget *cpuDock = new QDockWidget("processor", this);
cpuDock->setObjectName("cpudock");
cpuDock->setAllowedAreas(Qt::LeftDockWidgetArea);
m_procFrame = new ProcessorDockWidget(m_machine, cpuDock);
@@ -117,7 +128,7 @@ MainWindow::MainWindow(running_machine* machine, QWidget* parent) :
dockMenu->addAction(cpuDock->toggleViewAction());
// The disassembly dock
- QDockWidget* dasmDock = new QDockWidget("dasm", this);
+ QDockWidget *dasmDock = new QDockWidget("dasm", this);
dasmDock->setObjectName("dasmdock");
dasmDock->setAllowedAreas(Qt::TopDockWidgetArea);
m_dasmFrame = new DasmDockWidget(m_machine, dasmDock);
@@ -134,7 +145,7 @@ MainWindow::~MainWindow()
}
-void MainWindow::setProcessor(device_t* processor)
+void MainWindow::setProcessor(device_t *processor)
{
// Cpu swap
m_procFrame->view()->view()->set_source(*m_procFrame->view()->view()->source_for_device(processor));
@@ -145,150 +156,172 @@ void MainWindow::setProcessor(device_t* processor)
m_dasmFrame->view()->verticalScrollBar()->setValue(m_dasmFrame->view()->view()->visible_position().y);
// Window title
- string_format("Debug: %s - %s '%s'", m_machine->system().name, processor->name(), processor->tag());
- setWindowTitle(string_format("Debug: %s - %s '%s'", m_machine->system().name, processor->name(), processor->tag()).c_str());
+ setWindowTitle(string_format("Debug: %s - %s '%s'", m_machine.system().name, processor->name(), processor->tag()).c_str());
}
-// Used to intercept the user clicking 'X' in the upper corner
-void MainWindow::closeEvent(QCloseEvent* event)
+void MainWindow::restoreConfiguration(util::xml::data_node const &node)
{
- debugActQuit();
+ WindowQt::restoreConfiguration(node);
+
+ debug_view_disasm &dasmview = *m_dasmFrame->view()->view<debug_view_disasm>();
- // Insure the window doesn't disappear before we get a chance to save its parameters
- event->ignore();
+ restoreState(QByteArray::fromPercentEncoding(node.get_attribute_string("qtwindowstate", "")));
+
+ auto const rightbar = node.get_attribute_int(ATTR_WINDOW_DISASSEMBLY_RIGHT_COLUMN, dasmview.right_column());
+ QActionGroup *const rightBarGroup = findChild<QActionGroup *>("rightbargroup");
+ for (QAction *action : rightBarGroup->actions())
+ {
+ if (action->data().toInt() == rightbar)
+ {
+ action->trigger();
+ break;
+ }
+ }
+
+ m_dasmFrame->view()->restoreConfigurationFromNode(node);
+ m_inputHistory.restoreConfigurationFromNode(node);
}
-// Used to intercept the user hitting the up arrow in the input widget
-bool MainWindow::eventFilter(QObject* obj, QEvent* event)
+void MainWindow::saveConfigurationToNode(util::xml::data_node &node)
{
- // Only filter keypresses
- QKeyEvent* keyEvent = nullptr;
- if (event->type() == QEvent::KeyPress)
+ WindowQt::saveConfigurationToNode(node);
+
+ node.set_attribute_int(ATTR_WINDOW_TYPE, WINDOW_TYPE_CONSOLE);
+
+ debug_view_disasm &dasmview = *m_dasmFrame->view()->view<debug_view_disasm>();
+ node.set_attribute_int(ATTR_WINDOW_DISASSEMBLY_RIGHT_COLUMN, dasmview.right_column());
+ node.set_attribute("qtwindowstate", saveState().toPercentEncoding().data());
+
+ m_dasmFrame->view()->saveConfigurationToNode(node);
+ m_inputHistory.saveConfigurationToNode(node);
+}
+
+
+// Used to intercept the user clicking 'X' in the upper corner
+void MainWindow::closeEvent(QCloseEvent *event)
+{
+ if (!m_exiting)
{
- keyEvent = static_cast<QKeyEvent*>(event);
+ // Don't actually close the window - it will be brought back on user break
+ debugActRunAndHide();
+ event->ignore();
}
- else
- {
+}
+
+
+// Used to intercept the user hitting the up arrow in the input widget
+bool MainWindow::eventFilter(QObject *obj, QEvent *event)
+{
+ // Only filter keypresses
+ if (event->type() != QEvent::KeyPress)
return QObject::eventFilter(obj, event);
- }
+
+ QKeyEvent const &keyEvent = *static_cast<QKeyEvent *>(event);
// Catch up & down keys
- if (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down)
+ if (keyEvent.key() == Qt::Key_Escape)
{
- if (keyEvent->key() == Qt::Key_Up)
- {
- if (m_historyIndex > 0)
- m_historyIndex--;
- }
- else if (keyEvent->key() == Qt::Key_Down)
- {
- if (m_historyIndex < m_inputHistory.size())
- m_historyIndex++;
- }
-
- // Populate the input edit or clear it if you're at the end
- if (m_historyIndex == m_inputHistory.size())
+ m_inputEdit->clear();
+ m_inputHistory.reset();
+ return true;
+ }
+ else if (keyEvent.key() == Qt::Key_Up)
+ {
+ QString const *const hist = m_inputHistory.previous(m_inputEdit->text());
+ if (hist)
{
- m_inputEdit->setText("");
+ m_inputEdit->setText(*hist);
+ m_inputEdit->setSelection(hist->size(), 0);
}
- else
+ return true;
+ }
+ else if (keyEvent.key() == Qt::Key_Down)
+ {
+ QString const *const hist = m_inputHistory.next(m_inputEdit->text());
+ if (hist)
{
- m_inputEdit->setText(m_inputHistory[m_historyIndex]);
+ m_inputEdit->setText(*hist);
+ m_inputEdit->setSelection(hist->size(), 0);
}
+ return true;
}
- else if (keyEvent->key() == Qt::Key_Enter)
+ else if (keyEvent.key() == Qt::Key_Enter)
{
executeCommand(false);
+ return true;
}
else
{
return QObject::eventFilter(obj, event);
}
-
- return true;
}
void MainWindow::toggleBreakpointAtCursor(bool changedTo)
{
- debug_view_disasm *const dasmView = downcast<debug_view_disasm*>(m_dasmFrame->view()->view());
- if (dasmView->cursor_visible() && (m_machine->debugger().cpu().get_visible_cpu() == dasmView->source()->device()))
+ debug_view_disasm *const dasmView = m_dasmFrame->view()->view<debug_view_disasm>();
+ if (dasmView->cursor_visible() && (m_machine.debugger().console().get_visible_cpu() == dasmView->source()->device()))
{
- offs_t const address = downcast<debug_view_disasm *>(dasmView)->selected_address();
+ offs_t const address = dasmView->selected_address();
device_debug *const cpuinfo = dasmView->source()->device()->debug();
// Find an existing breakpoint at this address
- const device_debug::breakpoint *bp = cpuinfo->breakpoint_find(address);
+ const debug_breakpoint *bp = cpuinfo->breakpoint_find(address);
// If none exists, add a new one
std::string command;
- if (bp == nullptr)
- {
+ if (!bp)
command = string_format("bpset 0x%X", address);
- }
else
- {
command = string_format("bpclear 0x%X", bp->index());
- }
- m_machine->debugger().console().execute_command(command.c_str(), true);
+ m_machine.debugger().console().execute_command(command, true);
+ m_machine.debug_view().update_all();
+ m_machine.debugger().refresh_display();
}
-
- refreshAll();
}
void MainWindow::enableBreakpointAtCursor(bool changedTo)
{
- debug_view_disasm *const dasmView = downcast<debug_view_disasm*>(m_dasmFrame->view()->view());
- if (dasmView->cursor_visible() && (m_machine->debugger().cpu().get_visible_cpu() == dasmView->source()->device()))
+ debug_view_disasm *const dasmView = m_dasmFrame->view()->view<debug_view_disasm>();
+ if (dasmView->cursor_visible() && (m_machine.debugger().console().get_visible_cpu() == dasmView->source()->device()))
{
offs_t const address = dasmView->selected_address();
device_debug *const cpuinfo = dasmView->source()->device()->debug();
// Find an existing breakpoint at this address
- const device_debug::breakpoint *bp = cpuinfo->breakpoint_find(address);
+ const debug_breakpoint *bp = cpuinfo->breakpoint_find(address);
- if (bp != nullptr)
+ if (bp)
{
int32_t const bpindex = bp->index();
std::string command = string_format(bp->enabled() ? "bpdisable 0x%X" : "bpenable 0x%X", bpindex);
- m_machine->debugger().console().execute_command(command.c_str(), true);
+ m_machine.debugger().console().execute_command(command, true);
+ m_machine.debug_view().update_all();
+ m_machine.debugger().refresh_display();
}
}
-
- refreshAll();
}
void MainWindow::runToCursor(bool changedTo)
{
- debug_view_disasm* dasmView = downcast<debug_view_disasm*>(m_dasmFrame->view()->view());
- if (dasmView->cursor_visible() && (m_machine->debugger().cpu().get_visible_cpu() == dasmView->source()->device()))
+ debug_view_disasm *const dasmView = m_dasmFrame->view()->view<debug_view_disasm>();
+ if (dasmView->cursor_visible() && (m_machine.debugger().console().get_visible_cpu() == dasmView->source()->device()))
{
- offs_t address = downcast<debug_view_disasm*>(dasmView)->selected_address();
+ offs_t address = dasmView->selected_address();
std::string command = string_format("go 0x%X", address);
- m_machine->debugger().console().execute_command(command.c_str(), true);
+ m_machine.debugger().console().execute_command(command, true);
}
}
-void MainWindow::rightBarChanged(QAction* changedTo)
+void MainWindow::rightBarChanged(QAction *changedTo)
{
- debug_view_disasm* dasmView = downcast<debug_view_disasm*>(m_dasmFrame->view()->view());
- if (changedTo->text() == "Raw Opcodes")
- {
- dasmView->set_right_column(DASM_RIGHTCOL_RAW);
- }
- else if (changedTo->text() == "Encrypted Opcodes")
- {
- dasmView->set_right_column(DASM_RIGHTCOL_ENCRYPTED);
- }
- else if (changedTo->text() == "Comments")
- {
- dasmView->set_right_column(DASM_RIGHTCOL_COMMENTS);
- }
+ debug_view_disasm *const dasmView = m_dasmFrame->view()->view<debug_view_disasm>();
+ dasmView->set_right_column(disasm_right_column(changedTo->data().toInt()));
m_dasmFrame->view()->viewport()->update();
}
@@ -297,33 +330,35 @@ void MainWindow::executeCommandSlot()
executeCommand(true);
}
-void MainWindow::executeCommand(bool withClear)
+void MainWindow::commandEditedSlot(QString const &text)
{
- QString command = m_inputEdit->text();
+ m_inputHistory.edit();
+}
- // A blank command is a "silent step"
+void MainWindow::executeCommand(bool withClear)
+{
+ QString const command = m_inputEdit->text();
if (command == "")
{
- m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step();
- return;
+ // A blank command is a "silent step"
+ m_machine.debugger().console().get_visible_cpu()->debug()->single_step();
+ m_inputHistory.reset();
}
+ else
+ {
+ // Send along the command
+ m_machine.debugger().console().execute_command(command.toUtf8().data(), true);
- // Send along the command
- m_machine->debugger().console().execute_command(command.toLocal8Bit().data(), true);
-
- // Add history & set the index to be the top of the stack
- addToHistory(command);
+ // Add history
+ m_inputHistory.add(command);
- // Clear out the text and reset the history pointer only if asked
- if (withClear)
- {
- m_inputEdit->clear();
- m_historyIndex = m_inputHistory.size();
+ // Clear out the text and reset the history pointer only if asked
+ if (withClear)
+ {
+ m_inputEdit->clear();
+ m_inputHistory.edit();
+ }
}
-
- // Refresh
- m_consoleView->viewport()->update();
- refreshAll();
}
@@ -331,25 +366,25 @@ void MainWindow::mountImage(bool changedTo)
{
// The image interface index was assigned to the QAction's data memeber
const int imageIndex = dynamic_cast<QAction*>(sender())->data().toInt();
- image_interface_iterator iter(m_machine->root_device());
+ image_interface_enumerator iter(m_machine.root_device());
device_image_interface *img = iter.byindex(imageIndex);
- if (img == nullptr)
+ if (!img)
{
- m_machine->debugger().console().printf("Something is wrong with the mount menu.\n");
- refreshAll();
+ m_machine.debugger().console().printf("Something is wrong with the mount menu.\n");
return;
}
// File dialog
- QString filename = QFileDialog::getOpenFileName(this,
- "Select an image file",
- QDir::currentPath(),
- tr("All files (*.*)"));
-
- if (img->load(filename.toUtf8().data()) != image_init_result::PASS)
+ QString filename = QFileDialog::getOpenFileName(
+ this,
+ "Select an image file",
+ QDir::currentPath(),
+ tr("All files (*.*)"));
+
+ auto [err, message] = img->load(filename.toUtf8().data());
+ if (err)
{
- m_machine->debugger().console().printf("Image could not be mounted.\n");
- refreshAll();
+ m_machine.debugger().console().printf("Image could not be mounted: %s\n", !message.empty() ? message : err.message());
return;
}
@@ -358,45 +393,43 @@ void MainWindow::mountImage(bool changedTo)
unmountAct->setEnabled(true);
// Set the mount name
- QMenu* parentMenuItem = dynamic_cast<QMenu*>(sender()->parent());
+ QMenu *parentMenuItem = dynamic_cast<QMenu *>(sender()->parent());
QString baseString = parentMenuItem->title();
baseString.truncate(baseString.lastIndexOf(QString(" : ")));
const QString newTitle = baseString + QString(" : ") + QString(img->filename());
parentMenuItem->setTitle(newTitle);
- m_machine->debugger().console().printf("Image %s mounted successfully.\n", filename.toUtf8().data());
- refreshAll();
+ m_machine.debugger().console().printf("Image %s mounted successfully.\n", filename.toUtf8().data());
}
void MainWindow::unmountImage(bool changedTo)
{
// The image interface index was assigned to the QAction's data memeber
- const int imageIndex = dynamic_cast<QAction*>(sender())->data().toInt();
- image_interface_iterator iter(m_machine->root_device());
+ const int imageIndex = dynamic_cast<QAction *>(sender())->data().toInt();
+ image_interface_enumerator iter(m_machine.root_device());
device_image_interface *img = iter.byindex(imageIndex);
img->unload();
// Deactivate the unmount menu option
- dynamic_cast<QAction*>(sender())->setEnabled(false);
+ dynamic_cast<QAction *>(sender())->setEnabled(false);
// Set the mount name
- QMenu* parentMenuItem = dynamic_cast<QMenu*>(sender()->parent());
+ QMenu *parentMenuItem = dynamic_cast<QMenu *>(sender()->parent());
QString baseString = parentMenuItem->title();
baseString.truncate(baseString.lastIndexOf(QString(" : ")));
const QString newTitle = baseString + QString(" : ") + QString("[empty slot]");
parentMenuItem->setTitle(newTitle);
- m_machine->debugger().console().printf("Image successfully unmounted.\n");
- refreshAll();
+ m_machine.debugger().console().printf("Image successfully unmounted.\n");
}
void MainWindow::dasmViewUpdated()
{
- debug_view_disasm *const dasmView = downcast<debug_view_disasm*>(m_dasmFrame->view()->view());
- bool const haveCursor = dasmView->cursor_visible() && (m_machine->debugger().cpu().get_visible_cpu() == dasmView->source()->device());
+ debug_view_disasm *const dasmView = m_dasmFrame->view()->view<debug_view_disasm>();
+ bool const haveCursor = dasmView->cursor_visible() && (m_machine.debugger().console().get_visible_cpu() == dasmView->source()->device());
bool haveBreakpoint = false;
bool breakpointEnabled = false;
if (haveCursor)
@@ -406,9 +439,9 @@ void MainWindow::dasmViewUpdated()
device_debug *const cpuinfo = device->debug();
// Find an existing breakpoint at this address
- const device_debug::breakpoint *bp = cpuinfo->breakpoint_find(address);
+ const debug_breakpoint *bp = cpuinfo->breakpoint_find(address);
- if (bp != nullptr)
+ if (bp)
{
haveBreakpoint = true;
breakpointEnabled = bp->enabled();
@@ -425,44 +458,32 @@ void MainWindow::dasmViewUpdated()
void MainWindow::debugActClose()
{
- m_machine->schedule_exit();
+ m_machine.schedule_exit();
}
-void MainWindow::addToHistory(const QString& command)
+void MainWindow::debuggerExit()
{
- if (command == "")
- return;
-
- // Always push back when there is no previous history
- if (m_inputHistory.size() == 0)
- {
- m_inputHistory.push_back(m_inputEdit->text());
- return;
- }
-
- // If there is previous history, make sure it's not what you just executed
- if (m_inputHistory.back() != m_inputEdit->text())
- {
- m_inputHistory.push_back(m_inputEdit->text());
- }
+ // this isn't called from a Qt event loop, so close() will leak the window object
+ m_exiting = true;
+ delete this;
}
void MainWindow::createImagesMenu()
{
- QMenu* imagesMenu = menuBar()->addMenu("&Images");
+ QMenu *imagesMenu = menuBar()->addMenu("&Images");
int interfaceIndex = 0;
- for (device_image_interface &img : image_interface_iterator(m_machine->root_device()))
+ for (device_image_interface &img : image_interface_enumerator(m_machine.root_device()))
{
std::string menuName = string_format("%s : %s", img.device().name(), img.exists() ? img.filename() : "[empty slot]");
- QMenu* interfaceMenu = imagesMenu->addMenu(menuName.c_str());
+ QMenu *interfaceMenu = imagesMenu->addMenu(menuName.c_str());
interfaceMenu->setObjectName(img.device().name());
- QAction* mountAct = new QAction("Mount...", interfaceMenu);
- QAction* unmountAct = new QAction("Unmount", interfaceMenu);
+ QAction *mountAct = new QAction("Mount...", interfaceMenu);
+ QAction *unmountAct = new QAction("Unmount", interfaceMenu);
mountAct->setObjectName("mount");
mountAct->setData(QVariant(interfaceIndex));
unmountAct->setObjectName("unmount");
@@ -483,52 +504,6 @@ void MainWindow::createImagesMenu()
}
-//=========================================================================
-// MainWindowQtConfig
-//=========================================================================
-void MainWindowQtConfig::buildFromQWidget(QWidget* widget)
-{
- WindowQtConfig::buildFromQWidget(widget);
- MainWindow* window = dynamic_cast<MainWindow*>(widget);
- m_windowState = window->saveState();
-
- QActionGroup* rightBarGroup = window->findChild<QActionGroup*>("rightbargroup");
- if (rightBarGroup->checkedAction()->text() == "Raw Opcodes")
- m_rightBar = 0;
- else if (rightBarGroup->checkedAction()->text() == "Encrypted Opcodes")
- m_rightBar = 1;
- else if (rightBarGroup->checkedAction()->text() == "Comments")
- m_rightBar = 2;
-}
-
-
-void MainWindowQtConfig::applyToQWidget(QWidget* widget)
-{
- WindowQtConfig::applyToQWidget(widget);
- MainWindow* window = dynamic_cast<MainWindow*>(widget);
- window->restoreState(m_windowState);
-
- QActionGroup* rightBarGroup = window->findChild<QActionGroup*>("rightbargroup");
- rightBarGroup->actions()[m_rightBar]->trigger();
-}
-
-
-void MainWindowQtConfig::addToXmlDataNode(util::xml::data_node &node) const
-{
- WindowQtConfig::addToXmlDataNode(node);
- node.set_attribute_int("rightbar", m_rightBar);
- node.set_attribute("qtwindowstate", m_windowState.toPercentEncoding().data());
-}
-
-
-void MainWindowQtConfig::recoverFromXmlNode(util::xml::data_node const &node)
-{
- WindowQtConfig::recoverFromXmlNode(node);
- const char* state = node.get_attribute_string("qtwindowstate", "");
- m_windowState = QByteArray::fromPercentEncoding(state);
- m_rightBar = node.get_attribute_int("rightbar", m_rightBar);
-}
-
DasmDockWidget::~DasmDockWidget()
{
}
@@ -536,3 +511,5 @@ DasmDockWidget::~DasmDockWidget()
ProcessorDockWidget::~ProcessorDockWidget()
{
}
+
+} // namespace osd::debugger::qt
diff --git a/src/osd/modules/debugger/qt/mainwindow.h b/src/osd/modules/debugger/qt/mainwindow.h
index 95a4e53ca99..762874b6aee 100644
--- a/src/osd/modules/debugger/qt/mainwindow.h
+++ b/src/osd/modules/debugger/qt/mainwindow.h
@@ -1,18 +1,23 @@
// license:BSD-3-Clause
// copyright-holders:Andrew Gardner
-#ifndef __DEBUG_QT_MAIN_WINDOW_H__
-#define __DEBUG_QT_MAIN_WINDOW_H__
+#ifndef MAME_DEBUGGER_QT_MAINWINDOW_H
+#define MAME_DEBUGGER_QT_MAINWINDOW_H
-#include <vector>
+#pragma once
+
+#include "debuggerview.h"
+#include "windowqt.h"
+
+#include "debug/dvdisasm.h"
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QComboBox>
-#include "debug/dvdisasm.h"
+#include <deque>
-#include "debuggerview.h"
-#include "windowqt.h"
+
+namespace osd::debugger::qt {
class DasmDockWidget;
class ProcessorDockWidget;
@@ -26,56 +31,60 @@ class MainWindow : public WindowQt
Q_OBJECT
public:
- MainWindow(running_machine* machine, QWidget* parent=nullptr);
+ MainWindow(DebuggerQt &debugger, QWidget *parent = nullptr);
virtual ~MainWindow();
- void setProcessor(device_t* processor);
+ void setProcessor(device_t *processor);
+ virtual void restoreConfiguration(util::xml::data_node const &node) override;
protected:
+ virtual void saveConfigurationToNode(util::xml::data_node &node) override;
+
// Used to intercept the user clicking 'X' in the upper corner
- void closeEvent(QCloseEvent* event);
+ virtual void closeEvent(QCloseEvent *event) override;
// Used to intercept the user hitting the up arrow in the input widget
- bool eventFilter(QObject* obj, QEvent* event);
-
+ virtual bool eventFilter(QObject *obj, QEvent *event) override;
private slots:
void toggleBreakpointAtCursor(bool changedTo);
void enableBreakpointAtCursor(bool changedTo);
void runToCursor(bool changedTo);
- void rightBarChanged(QAction* changedTo);
+ void rightBarChanged(QAction *changedTo);
void executeCommandSlot();
+ void commandEditedSlot(QString const &text);
void mountImage(bool changedTo);
void unmountImage(bool changedTo);
void dasmViewUpdated();
- // Closing the main window actually exits the program
- void debugActClose();
-
+ // Closing the main window hides the debugger and runs the emulated system
+ virtual void debugActClose() override;
+ virtual void debuggerExit() override;
private:
void createImagesMenu();
+ void executeCommand(bool withClear);
+
// Widgets and docks
- QLineEdit* m_inputEdit;
- DebuggerView* m_consoleView;
- ProcessorDockWidget* m_procFrame;
- DasmDockWidget* m_dasmFrame;
+ QLineEdit *m_inputEdit;
+ DebuggerView *m_consoleView;
+ ProcessorDockWidget *m_procFrame;
+ DasmDockWidget *m_dasmFrame;
// Menu items
- QAction* m_breakpointToggleAct;
- QAction* m_breakpointEnableAct;
- QAction* m_runToCursorAct;
+ QAction *m_breakpointToggleAct;
+ QAction *m_breakpointEnableAct;
+ QAction *m_runToCursorAct;
// Terminal history
- int m_historyIndex;
- std::vector<QString> m_inputHistory;
- void addToHistory(const QString& command);
- void executeCommand(bool withClear);
+ CommandHistory m_inputHistory;
+
+ bool m_exiting;
};
@@ -87,45 +96,31 @@ class DasmDockWidget : public QWidget
Q_OBJECT
public:
- DasmDockWidget(running_machine* machine, QWidget* parent=nullptr) :
+ DasmDockWidget(running_machine &machine, QWidget *parent = nullptr) :
QWidget(parent),
m_machine(machine)
{
- m_dasmView = new DebuggerView(DVT_DISASSEMBLY,
- m_machine,
- this);
+ m_dasmView = new DebuggerView(DVT_DISASSEMBLY, m_machine, this);
// Force a recompute of the disassembly region
downcast<debug_view_disasm*>(m_dasmView->view())->set_expression("curpc");
- QVBoxLayout* dvLayout = new QVBoxLayout(this);
+ QVBoxLayout *dvLayout = new QVBoxLayout(this);
dvLayout->addWidget(m_dasmView);
dvLayout->setContentsMargins(4,0,4,0);
}
-
virtual ~DasmDockWidget();
+ DebuggerView *view() { return m_dasmView; }
- DebuggerView* view() { return m_dasmView; }
-
-
- QSize minimumSizeHint() const
- {
- return QSize(150,150);
- }
-
-
- QSize sizeHint() const
- {
- return QSize(150,200);
- }
-
+ QSize minimumSizeHint() const { return QSize(150, 150); }
+ QSize sizeHint() const { return QSize(150, 200); }
private:
- DebuggerView* m_dasmView;
+ running_machine &m_machine;
- running_machine* m_machine;
+ DebuggerView *m_dasmView;
};
@@ -137,72 +132,32 @@ class ProcessorDockWidget : public QWidget
Q_OBJECT
public:
- ProcessorDockWidget(running_machine* machine,
- QWidget* parent=nullptr) :
+ ProcessorDockWidget(running_machine &machine, QWidget *parent = nullptr) :
QWidget(parent),
- m_processorView(nullptr),
- m_machine(machine)
+ m_machine(machine),
+ m_processorView(nullptr)
{
- m_processorView = new DebuggerView(DVT_STATE,
- m_machine,
- this);
+ m_processorView = new DebuggerView(DVT_STATE, m_machine, this);
m_processorView->setFocusPolicy(Qt::NoFocus);
- QVBoxLayout* cvLayout = new QVBoxLayout(this);
+ QVBoxLayout *cvLayout = new QVBoxLayout(this);
cvLayout->addWidget(m_processorView);
cvLayout->setContentsMargins(4,0,4,2);
}
-
virtual ~ProcessorDockWidget();
+ DebuggerView *view() { return m_processorView; }
- DebuggerView* view() { return m_processorView; }
-
-
- QSize minimumSizeHint() const
- {
- return QSize(150,300);
- }
-
-
- QSize sizeHint() const
- {
- return QSize(200,300);
- }
-
+ QSize minimumSizeHint() const { return QSize(150, 300); }
+ QSize sizeHint() const { return QSize(200, 300); }
private:
- DebuggerView* m_processorView;
-
- running_machine* m_machine;
-};
-
+ running_machine &m_machine;
-//=========================================================================
-// A way to store the configuration of a window long enough to read/write.
-//=========================================================================
-class MainWindowQtConfig : public WindowQtConfig
-{
-public:
- MainWindowQtConfig() :
- WindowQtConfig(WIN_TYPE_MAIN),
- m_rightBar(0),
- m_windowState()
- {}
-
- ~MainWindowQtConfig() {}
-
- // Settings
- int m_rightBar;
- QByteArray m_windowState;
-
- void buildFromQWidget(QWidget* widget);
- void applyToQWidget(QWidget* widget);
- void addToXmlDataNode(util::xml::data_node &node) const;
- void recoverFromXmlNode(util::xml::data_node const &node);
+ DebuggerView *m_processorView;
};
+} // namespace osd::debugger::qt
-
-#endif
+#endif // MAME_DEBUGGER_QT_MAINWINDOW_H
diff --git a/src/osd/modules/debugger/qt/memorywindow.cpp b/src/osd/modules/debugger/qt/memorywindow.cpp
index c799ab66c65..ec250055383 100644
--- a/src/osd/modules/debugger/qt/memorywindow.cpp
+++ b/src/osd/modules/debugger/qt/memorywindow.cpp
@@ -1,9 +1,23 @@
// license:BSD-3-Clause
// copyright-holders:Andrew Gardner
#include "emu.h"
+#include "memorywindow.h"
+
+#include "debugger.h"
+#include "debug/dvmemory.h"
+#include "debug/debugcon.h"
+#include "debug/debugcpu.h"
+
+#include "util/xmlfile.h"
+
#include <QtGui/QClipboard>
+#include <QtGui/QKeyEvent>
#include <QtGui/QMouseEvent>
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+#include <QtGui/QActionGroup>
+#else
#include <QtWidgets/QActionGroup>
+#endif
#include <QtWidgets/QApplication>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QMenu>
@@ -12,19 +26,16 @@
#include <QtWidgets/QToolTip>
#include <QtWidgets/QVBoxLayout>
-#include "memorywindow.h"
-
-#include "debug/dvmemory.h"
-#include "debug/debugcon.h"
-#include "debug/debugcpu.h"
+namespace osd::debugger::qt {
-MemoryWindow::MemoryWindow(running_machine* machine, QWidget* parent) :
- WindowQt(machine, nullptr)
+MemoryWindow::MemoryWindow(DebuggerQt &debugger, QWidget *parent) :
+ WindowQt(debugger, nullptr),
+ m_inputHistory()
{
setWindowTitle("Debug: Memory View");
- if (parent != nullptr)
+ if (parent)
{
QPoint parentPos = parent->pos();
setGeometry(parentPos.x()+100, parentPos.y()+100, 800, 400);
@@ -33,32 +44,34 @@ MemoryWindow::MemoryWindow(running_machine* machine, QWidget* parent) :
//
// The main frame and its input and log widgets
//
- QFrame* mainWindowFrame = new QFrame(this);
+ QFrame *mainWindowFrame = new QFrame(this);
// The top frame & groupbox that contains the input widgets
- QFrame* topSubFrame = new QFrame(mainWindowFrame);
+ QFrame *topSubFrame = new QFrame(mainWindowFrame);
// The input edit
m_inputEdit = new QLineEdit(topSubFrame);
connect(m_inputEdit, &QLineEdit::returnPressed, this, &MemoryWindow::expressionSubmitted);
+ connect(m_inputEdit, &QLineEdit::textEdited, this, &MemoryWindow::expressionEdited);
+ m_inputEdit->installEventFilter(this);
// The memory space combo box
m_memoryComboBox = new QComboBox(topSubFrame);
m_memoryComboBox->setObjectName("memoryregion");
m_memoryComboBox->setMinimumWidth(300);
- connect(m_memoryComboBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &MemoryWindow::memoryRegionChanged);
+ connect(m_memoryComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &MemoryWindow::memoryRegionChanged);
// The main memory window
m_memTable = new DebuggerMemView(DVT_MEMORY, m_machine, this);
// Layout
- QHBoxLayout* subLayout = new QHBoxLayout(topSubFrame);
+ QHBoxLayout *subLayout = new QHBoxLayout(topSubFrame);
subLayout->addWidget(m_inputEdit);
subLayout->addWidget(m_memoryComboBox);
subLayout->setSpacing(3);
subLayout->setContentsMargins(2,2,2,2);
- QVBoxLayout* vLayout = new QVBoxLayout(mainWindowFrame);
+ QVBoxLayout *vLayout = new QVBoxLayout(mainWindowFrame);
vLayout->setSpacing(3);
vLayout->setContentsMargins(2,2,2,2);
vLayout->addWidget(topSubFrame);
@@ -71,26 +84,38 @@ MemoryWindow::MemoryWindow(running_machine* machine, QWidget* parent) :
//
// Create a data format group
- QActionGroup* dataFormat = new QActionGroup(this);
+ QActionGroup *dataFormat = new QActionGroup(this);
dataFormat->setObjectName("dataformat");
- QAction* formatActOne = new QAction("1-byte chunks", this);
- QAction* formatActTwo = new QAction("2-byte chunks", this);
- QAction* formatActFour = new QAction("4-byte chunks", this);
- QAction* formatActEight = new QAction("8-byte chunks", this);
- QAction* formatAct32bitFloat = new QAction("32 bit floating point", this);
- QAction* formatAct64bitFloat = new QAction("64 bit floating point", this);
- QAction* formatAct80bitFloat = new QAction("80 bit floating point", this);
- formatActOne->setObjectName("formatActOne");
- formatActTwo->setObjectName("formatActTwo");
- formatActFour->setObjectName("formatActFour");
- formatActEight->setObjectName("formatActEight");
- formatAct32bitFloat->setObjectName("formatAct32bitFloat");
- formatAct64bitFloat->setObjectName("formatAct64bitFloat");
- formatAct80bitFloat->setObjectName("formatAct80bitFloat");
+ QAction *formatActOne = new QAction("1-byte Chunks (Hex)", this);
+ QAction *formatActTwo = new QAction("2-byte Chunks (Hex)", this);
+ QAction *formatActFour = new QAction("4-byte Chunks (Hex)", this);
+ QAction *formatActEight = new QAction("8-byte Chunks (Hex)", this);
+ QAction *formatActOneOctal = new QAction("1-byte Chunks (Octal)", this);
+ QAction *formatActTwoOctal = new QAction("2-byte Chunks (Octal)", this);
+ QAction *formatActFourOctal = new QAction("4-byte Chunks (Octal)", this);
+ QAction *formatActEightOctal = new QAction("8-byte Chunks (Octal)", this);
+ QAction *formatAct32bitFloat = new QAction("32-bit Floating Point", this);
+ QAction *formatAct64bitFloat = new QAction("64-bit Floating Point", this);
+ QAction *formatAct80bitFloat = new QAction("80-bit Floating Point", this);
+ formatActOne->setData(int(debug_view_memory::data_format::HEX_8BIT));
+ formatActTwo->setData(int(debug_view_memory::data_format::HEX_16BIT));
+ formatActFour->setData(int(debug_view_memory::data_format::HEX_32BIT));
+ formatActEight->setData(int(debug_view_memory::data_format::HEX_64BIT));
+ formatActOneOctal->setData(int(debug_view_memory::data_format::OCTAL_8BIT));
+ formatActTwoOctal->setData(int(debug_view_memory::data_format::OCTAL_16BIT));
+ formatActFourOctal->setData(int(debug_view_memory::data_format::OCTAL_32BIT));
+ formatActEightOctal->setData(int(debug_view_memory::data_format::OCTAL_64BIT));
+ formatAct32bitFloat->setData(int(debug_view_memory::data_format::FLOAT_32BIT));
+ formatAct64bitFloat->setData(int(debug_view_memory::data_format::FLOAT_64BIT));
+ formatAct80bitFloat->setData(int(debug_view_memory::data_format::FLOAT_80BIT));
formatActOne->setCheckable(true);
formatActTwo->setCheckable(true);
formatActFour->setCheckable(true);
formatActEight->setCheckable(true);
+ formatActOneOctal->setCheckable(true);
+ formatActTwoOctal->setCheckable(true);
+ formatActFourOctal->setCheckable(true);
+ formatActEightOctal->setCheckable(true);
formatAct32bitFloat->setCheckable(true);
formatAct64bitFloat->setCheckable(true);
formatAct80bitFloat->setCheckable(true);
@@ -98,6 +123,10 @@ MemoryWindow::MemoryWindow(running_machine* machine, QWidget* parent) :
formatActTwo->setActionGroup(dataFormat);
formatActFour->setActionGroup(dataFormat);
formatActEight->setActionGroup(dataFormat);
+ formatActOneOctal->setActionGroup(dataFormat);
+ formatActTwoOctal->setActionGroup(dataFormat);
+ formatActFourOctal->setActionGroup(dataFormat);
+ formatActEightOctal->setActionGroup(dataFormat);
formatAct32bitFloat->setActionGroup(dataFormat);
formatAct64bitFloat->setActionGroup(dataFormat);
formatAct80bitFloat->setActionGroup(dataFormat);
@@ -105,14 +134,23 @@ MemoryWindow::MemoryWindow(running_machine* machine, QWidget* parent) :
formatActTwo->setShortcut(QKeySequence("Ctrl+2"));
formatActFour->setShortcut(QKeySequence("Ctrl+4"));
formatActEight->setShortcut(QKeySequence("Ctrl+8"));
- formatAct32bitFloat->setShortcut(QKeySequence("Ctrl+9"));
+ formatActOneOctal->setShortcut(QKeySequence("Ctrl+3"));
+ formatActTwoOctal->setShortcut(QKeySequence("Ctrl+5"));
+ formatActFourOctal->setShortcut(QKeySequence("Ctrl+7"));
+ formatActEightOctal->setShortcut(QKeySequence("Ctrl+9"));
+ formatAct32bitFloat->setShortcut(QKeySequence("Ctrl+Shift+F"));
+ formatAct64bitFloat->setShortcut(QKeySequence("Ctrl+Shift+D"));
+ formatAct80bitFloat->setShortcut(QKeySequence("Ctrl+Shift+E"));
formatActOne->setChecked(true);
connect(dataFormat, &QActionGroup::triggered, this, &MemoryWindow::formatChanged);
- // Create a address display group
- QActionGroup* addressGroup = new QActionGroup(this);
+
+ // Create an address display group
+ QActionGroup *addressGroup = new QActionGroup(this);
addressGroup->setObjectName("addressgroup");
- QAction* addressActLogical = new QAction("Logical Addresses", this);
- QAction* addressActPhysical = new QAction("Physical Addresses", this);
+ QAction *addressActLogical = new QAction("Logical Addresses", this);
+ QAction *addressActPhysical = new QAction("Physical Addresses", this);
+ addressActLogical->setData(false);
+ addressActPhysical->setData(true);
addressActLogical->setCheckable(true);
addressActPhysical->setCheckable(true);
addressActLogical->setActionGroup(addressGroup);
@@ -122,27 +160,49 @@ MemoryWindow::MemoryWindow(running_machine* machine, QWidget* parent) :
addressActLogical->setChecked(true);
connect(addressGroup, &QActionGroup::triggered, this, &MemoryWindow::addressChanged);
+ // Create an address radix group
+ QActionGroup *radixGroup = new QActionGroup(this);
+ radixGroup->setObjectName("radixgroup");
+ QAction *radixActHexadecimal = new QAction("Hexadecimal Addresses", this);
+ QAction *radixActDecimal = new QAction("Decimal Addresses", this);
+ QAction *radixActOctal = new QAction("Octal Addresses", this);
+ radixActHexadecimal->setData(16);
+ radixActDecimal->setData(10);
+ radixActOctal->setData(8);
+ radixActHexadecimal->setCheckable(true);
+ radixActDecimal->setCheckable(true);
+ radixActOctal->setCheckable(true);
+ radixActHexadecimal->setActionGroup(radixGroup);
+ radixActDecimal->setActionGroup(radixGroup);
+ radixActOctal->setActionGroup(radixGroup);
+ radixActHexadecimal->setShortcut(QKeySequence("Ctrl+Shift+H"));
+ radixActOctal->setShortcut(QKeySequence("Ctrl+Shift+O"));
+ radixActHexadecimal->setChecked(true);
+ connect(radixGroup, &QActionGroup::triggered, this, &MemoryWindow::radixChanged);
+
// Create a reverse view radio
- QAction* reverseAct = new QAction("Reverse View", this);
+ QAction *reverseAct = new QAction("Reverse View", this);
reverseAct->setObjectName("reverse");
reverseAct->setCheckable(true);
reverseAct->setShortcut(QKeySequence("Ctrl+R"));
connect(reverseAct, &QAction::toggled, this, &MemoryWindow::reverseChanged);
// Create increase and decrease bytes-per-line actions
- QAction* increaseBplAct = new QAction("Increase Bytes Per Line", this);
- QAction* decreaseBplAct = new QAction("Decrease Bytes Per Line", this);
+ QAction *increaseBplAct = new QAction("Increase Bytes Per Line", this);
+ QAction *decreaseBplAct = new QAction("Decrease Bytes Per Line", this);
increaseBplAct->setShortcut(QKeySequence("Ctrl+P"));
decreaseBplAct->setShortcut(QKeySequence("Ctrl+O"));
connect(increaseBplAct, &QAction::triggered, this, &MemoryWindow::increaseBytesPerLine);
connect(decreaseBplAct, &QAction::triggered, this, &MemoryWindow::decreaseBytesPerLine);
// Assemble the options menu
- QMenu* optionsMenu = menuBar()->addMenu("&Options");
+ QMenu *optionsMenu = menuBar()->addMenu("&Options");
optionsMenu->addActions(dataFormat->actions());
optionsMenu->addSeparator();
optionsMenu->addActions(addressGroup->actions());
optionsMenu->addSeparator();
+ optionsMenu->addActions(radixGroup->actions());
+ optionsMenu->addSeparator();
optionsMenu->addAction(reverseAct);
optionsMenu->addSeparator();
optionsMenu->addAction(increaseBplAct);
@@ -164,98 +224,213 @@ MemoryWindow::~MemoryWindow()
}
-void MemoryWindow::memoryRegionChanged(int index)
+void MemoryWindow::restoreConfiguration(util::xml::data_node const &node)
{
- m_memTable->view()->set_source(*m_memTable->view()->source_list().find(index));
- m_memTable->viewport()->update();
+ WindowQt::restoreConfiguration(node);
+
+ debug_view_memory &memView = *m_memTable->view<debug_view_memory>();
+
+ auto const region = node.get_attribute_int(ATTR_WINDOW_MEMORY_REGION, m_memTable->sourceIndex());
+ if ((0 <= region) && (m_memoryComboBox->count() > region))
+ m_memoryComboBox->setCurrentIndex(region);
+
+ auto const reverse = node.get_attribute_int(ATTR_WINDOW_MEMORY_REVERSE_COLUMNS, memView.reverse() ? 1 : 0);
+ if (memView.reverse() != bool(reverse))
+ {
+ memView.set_reverse(bool(reverse));
+ findChild<QAction *>("reverse")->setChecked(bool(reverse));
+ }
- // Update the data format radio buttons to the memory region's default
- debug_view_memory* memView = downcast<debug_view_memory*>(m_memTable->view());
- switch(memView->get_data_format())
+ auto const mode = node.get_attribute_int(ATTR_WINDOW_MEMORY_ADDRESS_MODE, memView.physical() ? 1 : 0);
+ QActionGroup *const addressGroup = findChild<QActionGroup *>("addressgroup");
+ for (QAction *action : addressGroup->actions())
{
- case 1: dataFormatMenuItem("formatActOne")->setChecked(true); break;
- case 2: dataFormatMenuItem("formatActTwo")->setChecked(true); break;
- case 4: dataFormatMenuItem("formatActFour")->setChecked(true); break;
- case 8: dataFormatMenuItem("formatActEight")->setChecked(true); break;
- case 9: dataFormatMenuItem("formatAct32bitFloat")->setChecked(true); break;
- case 10: dataFormatMenuItem("formatAct64bitFloat")->setChecked(true); break;
- case 11: dataFormatMenuItem("formatAct80bitFloat")->setChecked(true); break;
- default: break;
+ if (action->data().toBool() == mode)
+ {
+ action->trigger();
+ break;
+ }
}
+
+ auto const radix = node.get_attribute_int(ATTR_WINDOW_MEMORY_ADDRESS_RADIX, memView.address_radix());
+ QActionGroup *const radixGroup = findChild<QActionGroup *>("radixgroup");
+ for (QAction *action : radixGroup->actions())
+ {
+ if (action->data().toInt() == radix)
+ {
+ action->trigger();
+ break;
+ }
+ }
+
+ auto const format = node.get_attribute_int(ATTR_WINDOW_MEMORY_DATA_FORMAT, int(memView.get_data_format()));
+ QActionGroup *const dataFormat = findChild<QActionGroup *>("dataformat");
+ for (QAction *action : dataFormat->actions())
+ {
+ if (action->data().toInt() == format)
+ {
+ action->trigger();
+ break;
+ }
+ }
+
+ auto const chunks = node.get_attribute_int(ATTR_WINDOW_MEMORY_ROW_CHUNKS, memView.chunks_per_row());
+ memView.set_chunks_per_row(chunks);
+
+ util::xml::data_node const *const expression = node.get_child(NODE_WINDOW_EXPRESSION);
+ if (expression && expression->get_value())
+ {
+ m_inputEdit->setText(QString::fromUtf8(expression->get_value()));
+ expressionSubmitted();
+ }
+
+ m_memTable->restoreConfigurationFromNode(node);
+ m_inputHistory.restoreConfigurationFromNode(node);
}
-void MemoryWindow::expressionSubmitted()
+void MemoryWindow::saveConfigurationToNode(util::xml::data_node &node)
{
- const QString expression = m_inputEdit->text();
- downcast<debug_view_memory*>(m_memTable->view())->set_expression(expression.toLocal8Bit().data());
+ WindowQt::saveConfigurationToNode(node);
- // Make the cursor pop
- m_memTable->view()->set_cursor_visible(true);
+ node.set_attribute_int(ATTR_WINDOW_TYPE, WINDOW_TYPE_MEMORY_VIEWER);
- // Check where the cursor is and adjust the scroll accordingly
- debug_view_xy cursorPosition = m_memTable->view()->cursor_position();
- // TODO: check if the region is already visible?
- m_memTable->verticalScrollBar()->setValue(cursorPosition.y);
+ debug_view_memory &memView = *m_memTable->view<debug_view_memory>();
+ node.set_attribute_int(ATTR_WINDOW_MEMORY_REGION, m_memTable->sourceIndex());
+ node.set_attribute_int(ATTR_WINDOW_MEMORY_REVERSE_COLUMNS, memView.reverse() ? 1 : 0);
+ node.set_attribute_int(ATTR_WINDOW_MEMORY_ADDRESS_MODE, memView.physical() ? 1 : 0);
+ node.set_attribute_int(ATTR_WINDOW_MEMORY_ADDRESS_RADIX, memView.address_radix());
+ node.set_attribute_int(ATTR_WINDOW_MEMORY_DATA_FORMAT, int(memView.get_data_format()));
+ node.set_attribute_int(ATTR_WINDOW_MEMORY_ROW_CHUNKS, memView.chunks_per_row());
+ node.add_child(NODE_WINDOW_EXPRESSION, memView.expression());
- m_memTable->update();
- m_memTable->viewport()->update();
+ m_memTable->saveConfigurationToNode(node);
+ m_inputHistory.saveConfigurationToNode(node);
}
-void MemoryWindow::formatChanged(QAction* changedTo)
+void MemoryWindow::memoryRegionChanged(int index)
{
- debug_view_memory* memView = downcast<debug_view_memory*>(m_memTable->view());
- if (changedTo->text() == "1-byte chunks")
- {
- memView->set_data_format(1);
- }
- else if (changedTo->text() == "2-byte chunks")
+ if (index < m_memTable->view()->source_count())
{
- memView->set_data_format(2);
- }
- else if (changedTo->text() == "4-byte chunks")
- {
- memView->set_data_format(4);
+ m_memTable->view()->set_source(*m_memTable->view()->source(index));
+ m_memTable->viewport()->update();
+
+ // Update the data format radio buttons to the memory region's default
+ debug_view_memory *const memView = m_memTable->view<debug_view_memory>();
+
+ QActionGroup *const dataFormat = findChild<QActionGroup *>("dataformat");
+ for (QAction *action : dataFormat->actions())
+ {
+ if (debug_view_memory::data_format(action->data().toInt()) == memView->get_data_format())
+ {
+ action->setChecked(true);
+ break;
+ }
+ }
+
+ QActionGroup *radixGroup = findChild<QActionGroup *>("radixgroup");
+ for (QAction *action : radixGroup->actions())
+ {
+ if (action->data().toInt() == memView->address_radix())
+ {
+ action->setChecked(true);
+ break;
+ }
+ }
}
- else if (changedTo->text() == "8-byte chunks")
+}
+
+
+// Used to intercept the user hitting the up arrow in the input widget
+bool MemoryWindow::eventFilter(QObject *obj, QEvent *event)
+{
+ // Only filter keypresses
+ if (event->type() != QEvent::KeyPress)
+ return QObject::eventFilter(obj, event);
+
+ QKeyEvent const &keyEvent = *static_cast<QKeyEvent *>(event);
+
+ // Catch up & down keys
+ if (keyEvent.key() == Qt::Key_Escape)
{
- memView->set_data_format(8);
+ m_inputEdit->setText(QString::fromUtf8(m_memTable->view<debug_view_memory>()->expression()));
+ m_inputEdit->selectAll();
+ m_inputHistory.reset();
+ return true;
}
- else if (changedTo->text() == "32 bit floating point")
+ else if (keyEvent.key() == Qt::Key_Up)
{
- memView->set_data_format(9);
+ QString const *const hist = m_inputHistory.previous(m_inputEdit->text());
+ if (hist)
+ {
+ m_inputEdit->setText(*hist);
+ m_inputEdit->setSelection(hist->size(), 0);
+ }
+ return true;
}
- else if (changedTo->text() == "64 bit floating point")
+ else if (keyEvent.key() == Qt::Key_Down)
{
- memView->set_data_format(10);
+ QString const *const hist = m_inputHistory.next(m_inputEdit->text());
+ if (hist)
+ {
+ m_inputEdit->setText(*hist);
+ m_inputEdit->setSelection(hist->size(), 0);
+ }
+ return true;
}
- else if (changedTo->text() == "80 bit floating point")
+ else
{
- memView->set_data_format(11);
+ return QObject::eventFilter(obj, event);
}
+}
+
+
+void MemoryWindow::expressionSubmitted()
+{
+ const QString expression = m_inputEdit->text();
+ m_memTable->view<debug_view_memory>()->set_expression(expression.toUtf8().data());
+ m_inputEdit->selectAll();
+
+ // Add history
+ if (!expression.isEmpty())
+ m_inputHistory.add(expression);
+}
+
+
+void MemoryWindow::expressionEdited(QString const &text)
+{
+ m_inputHistory.edit();
+}
+
+
+void MemoryWindow::formatChanged(QAction* changedTo)
+{
+ debug_view_memory *const memView = m_memTable->view<debug_view_memory>();
+ memView->set_data_format(debug_view_memory::data_format(changedTo->data().toInt()));
m_memTable->viewport()->update();
}
void MemoryWindow::addressChanged(QAction* changedTo)
{
- debug_view_memory* memView = downcast<debug_view_memory*>(m_memTable->view());
- if (changedTo->text() == "Logical Addresses")
- {
- memView->set_physical(false);
- }
- else if (changedTo->text() == "Physical Addresses")
- {
- memView->set_physical(true);
- }
+ debug_view_memory *const memView = m_memTable->view<debug_view_memory>();
+ memView->set_physical(changedTo->data().toBool());
+ m_memTable->viewport()->update();
+}
+
+
+void MemoryWindow::radixChanged(QAction* changedTo)
+{
+ debug_view_memory *const memView = m_memTable->view<debug_view_memory>();
+ memView->set_address_radix(changedTo->data().toInt());
m_memTable->viewport()->update();
}
void MemoryWindow::reverseChanged(bool changedTo)
{
- debug_view_memory* memView = downcast<debug_view_memory*>(m_memTable->view());
+ debug_view_memory *const memView = m_memTable->view<debug_view_memory>();
memView->set_reverse(changedTo);
m_memTable->viewport()->update();
}
@@ -263,7 +438,7 @@ void MemoryWindow::reverseChanged(bool changedTo)
void MemoryWindow::increaseBytesPerLine(bool changedTo)
{
- debug_view_memory* memView = downcast<debug_view_memory*>(m_memTable->view());
+ debug_view_memory *const memView = m_memTable->view<debug_view_memory>();
memView->set_chunks_per_row(memView->chunks_per_row() + 1);
m_memTable->viewport()->update();
}
@@ -271,7 +446,7 @@ void MemoryWindow::increaseBytesPerLine(bool changedTo)
void MemoryWindow::decreaseBytesPerLine(bool checked)
{
- debug_view_memory* memView = downcast<debug_view_memory*>(m_memTable->view());
+ debug_view_memory *const memView = m_memTable->view<debug_view_memory>();
memView->set_chunks_per_row(memView->chunks_per_row() - 1);
m_memTable->viewport()->update();
}
@@ -279,173 +454,98 @@ void MemoryWindow::decreaseBytesPerLine(bool checked)
void MemoryWindow::populateComboBox()
{
- if (m_memTable == nullptr)
+ if (!m_memTable)
return;
m_memoryComboBox->clear();
- for (const debug_view_source &source : m_memTable->view()->source_list())
- {
- m_memoryComboBox->addItem(source.name());
- }
+ for (auto &source : m_memTable->view()->source_list())
+ m_memoryComboBox->addItem(source->name());
}
void MemoryWindow::setToCurrentCpu()
{
- device_t* curCpu = m_machine->debugger().cpu().get_visible_cpu();
- const debug_view_source *source = m_memTable->view()->source_for_device(curCpu);
- const int listIndex = m_memTable->view()->source_list().indexof(*source);
- m_memoryComboBox->setCurrentIndex(listIndex);
-}
-
-
-// I have a hard time storing QActions as class members. This is a substitute.
-QAction* MemoryWindow::dataFormatMenuItem(const QString& itemName)
-{
- QList<QMenu*> menus = menuBar()->findChildren<QMenu*>();
- for (int i = 0; i < menus.length(); i++)
+ device_t *curCpu = m_machine.debugger().console().get_visible_cpu();
+ if (curCpu)
{
- if (menus[i]->title() != "&Options") continue;
- QList<QAction*> actions = menus[i]->actions();
- for (int j = 0; j < actions.length(); j++)
+ const debug_view_source *source = m_memTable->view()->source_for_device(curCpu);
+ if (source)
{
- if (actions[j]->objectName() == itemName)
- return actions[j];
+ const int listIndex = m_memTable->view()->source_index(*source);
+ m_memoryComboBox->setCurrentIndex(listIndex);
}
}
- return nullptr;
}
//=========================================================================
// DebuggerMemView
//=========================================================================
-void DebuggerMemView::mousePressEvent(QMouseEvent* event)
+void DebuggerMemView::addItemsToContextMenu(QMenu *menu)
{
- const bool leftClick = event->button() == Qt::LeftButton;
- const bool rightClick = event->button() == Qt::RightButton;
+ DebuggerView::addItemsToContextMenu(menu);
- if (leftClick || rightClick)
+ if (view()->cursor_visible())
{
- QFontMetrics actualFont = fontMetrics();
- const double fontWidth = actualFont.width(QString(100, '_')) / 100.;
- const int fontHeight = std::max(1, actualFont.lineSpacing());
-
- debug_view_xy topLeft = view()->visible_position();
- debug_view_xy clickViewPosition;
- clickViewPosition.x = topLeft.x + (event->x() / fontWidth);
- clickViewPosition.y = topLeft.y + (event->y() / fontHeight);
- if (leftClick)
- {
- view()->process_click(DCK_LEFT_CLICK, clickViewPosition);
- }
- else if (rightClick)
+ debug_view_memory &memView = *view<debug_view_memory>();
+ debug_view_memory_source const &source = downcast<debug_view_memory_source const &>(*memView.source());
+ address_space *const addressSpace = source.space();
+ if (addressSpace)
{
- // Display the last known PC to write to this memory location & copy it onto the clipboard
- debug_view_memory* memView = downcast<debug_view_memory*>(view());
- const offs_t address = memView->addressAtCursorPosition(clickViewPosition);
- const debug_view_memory_source* source = downcast<const debug_view_memory_source*>(memView->source());
- address_space* addressSpace = source->space();
- const int nativeDataWidth = addressSpace->data_width() / 8;
- const uint64_t memValue = source->device()->machine().debugger().cpu().read_memory(*addressSpace,
- addressSpace->address_to_byte(address),
- nativeDataWidth,
- true);
- const offs_t pc = source->device()->debug()->track_mem_pc_from_space_address_data(addressSpace->spacenum(),
- address,
- memValue);
- if (pc != (offs_t)(-1))
+ // get the last known PC to write to this memory location
+ debug_view_xy const pos = memView.cursor_position();
+ offs_t const address = addressSpace->byte_to_address(memView.addressAtCursorPosition(pos));
+ offs_t a = address & addressSpace->logaddrmask();
+ bool good = false;
+ address_space *tspace;
+ if (!addressSpace->device().memory().translate(addressSpace->spacenum(), device_memory_interface::TR_READ, a, tspace))
{
- // TODO: You can specify a box that the tooltip stays alive within - might be good?
- const QString addressAndPc = QString("Address %1 written at PC=%2").arg(address, 2, 16).arg(pc, 2, 16);
- QToolTip::showText(QCursor::pos(), addressAndPc, nullptr);
-
- // Copy the PC into the clipboard as well
- QClipboard *clipboard = QApplication::clipboard();
- clipboard->setText(QString("%1").arg(pc, 2, 16));
+ m_lastPc = "Bad address";
}
else
{
- QToolTip::showText(QCursor::pos(), "UNKNOWN PC", nullptr);
+ uint64_t memValue = tspace->unmap();
+ auto dis = tspace->device().machine().disable_side_effects();
+ switch (tspace->data_width())
+ {
+ case 8: memValue = tspace->read_byte(a); break;
+ case 16: memValue = tspace->read_word_unaligned(a); break;
+ case 32: memValue = tspace->read_dword_unaligned(a); break;
+ case 64: memValue = tspace->read_qword_unaligned(a); break;
+ }
+
+ offs_t const pc = source.device()->debug()->track_mem_pc_from_space_address_data(
+ tspace->spacenum(),
+ address,
+ memValue);
+ if (pc != offs_t(-1))
+ {
+ if (tspace->is_octal())
+ m_lastPc = QString("Address %1 written at PC=%2").arg(address, 2, 8).arg(pc, 2, 8);
+ else
+ m_lastPc = QString("Address %1 written at PC=%2").arg(address, 2, 16).arg(pc, 2, 16);
+ good = true;
+ }
+ else
+ {
+ m_lastPc = "Unknown PC";
+ }
}
- }
- viewport()->update();
- update();
+ if (!menu->isEmpty())
+ menu->addSeparator();
+ QAction *const act = new QAction(m_lastPc, menu);
+ act->setEnabled(good);
+ connect(act, &QAction::triggered, this, &DebuggerMemView::copyLastPc);
+ menu->addAction(act);
+ }
}
}
-//=========================================================================
-// MemoryWindowQtConfig
-//=========================================================================
-void MemoryWindowQtConfig::buildFromQWidget(QWidget* widget)
-{
- WindowQtConfig::buildFromQWidget(widget);
- MemoryWindow* window = dynamic_cast<MemoryWindow*>(widget);
- QComboBox* memoryRegion = window->findChild<QComboBox*>("memoryregion");
- m_memoryRegion = memoryRegion->currentIndex();
-
- QAction* reverse = window->findChild<QAction*>("reverse");
- m_reverse = reverse->isChecked();
-
- QActionGroup* addressGroup = window->findChild<QActionGroup*>("addressgroup");
- if (addressGroup->checkedAction()->text() == "Logical Addresses")
- m_addressMode = 0;
- else if (addressGroup->checkedAction()->text() == "Physical Addresses")
- m_addressMode = 1;
-
- QActionGroup* dataFormat = window->findChild<QActionGroup*>("dataformat");
- if (dataFormat->checkedAction()->text() == "1-byte chunks")
- m_dataFormat = 0;
- else if (dataFormat->checkedAction()->text() == "2-byte chunks")
- m_dataFormat = 1;
- else if (dataFormat->checkedAction()->text() == "4-byte chunks")
- m_dataFormat = 2;
- else if (dataFormat->checkedAction()->text() == "8-byte chunks")
- m_dataFormat = 3;
- else if (dataFormat->checkedAction()->text() == "32 bit floating point")
- m_dataFormat = 4;
- else if (dataFormat->checkedAction()->text() == "64 bit floating point")
- m_dataFormat = 5;
- else if (dataFormat->checkedAction()->text() == "80 bit floating point")
- m_dataFormat = 6;
-}
-
-
-void MemoryWindowQtConfig::applyToQWidget(QWidget* widget)
+void DebuggerMemView::copyLastPc()
{
- WindowQtConfig::applyToQWidget(widget);
- MemoryWindow* window = dynamic_cast<MemoryWindow*>(widget);
- QComboBox* memoryRegion = window->findChild<QComboBox*>("memoryregion");
- memoryRegion->setCurrentIndex(m_memoryRegion);
-
- QAction* reverse = window->findChild<QAction*>("reverse");
- if (m_reverse) reverse->trigger();
-
- QActionGroup* addressGroup = window->findChild<QActionGroup*>("addressgroup");
- addressGroup->actions()[m_addressMode]->trigger();
-
- QActionGroup* dataFormat = window->findChild<QActionGroup*>("dataformat");
- dataFormat->actions()[m_dataFormat]->trigger();
+ QApplication::clipboard()->setText(m_lastPc);
}
-
-void MemoryWindowQtConfig::addToXmlDataNode(util::xml::data_node &node) const
-{
- WindowQtConfig::addToXmlDataNode(node);
- node.set_attribute_int("memoryregion", m_memoryRegion);
- node.set_attribute_int("reverse", m_reverse);
- node.set_attribute_int("addressmode", m_addressMode);
- node.set_attribute_int("dataformat", m_dataFormat);
-}
-
-
-void MemoryWindowQtConfig::recoverFromXmlNode(util::xml::data_node const &node)
-{
- WindowQtConfig::recoverFromXmlNode(node);
- m_memoryRegion = node.get_attribute_int("memoryregion", m_memoryRegion);
- m_reverse = node.get_attribute_int("reverse", m_reverse);
- m_addressMode = node.get_attribute_int("addressmode", m_addressMode);
- m_dataFormat = node.get_attribute_int("dataformat", m_dataFormat);
-}
+} // namespace osd::debugger::qt
diff --git a/src/osd/modules/debugger/qt/memorywindow.h b/src/osd/modules/debugger/qt/memorywindow.h
index ff0c974c838..ed5c5b30cb0 100644
--- a/src/osd/modules/debugger/qt/memorywindow.h
+++ b/src/osd/modules/debugger/qt/memorywindow.h
@@ -1,14 +1,19 @@
// license:BSD-3-Clause
// copyright-holders:Andrew Gardner
-#ifndef __DEBUG_QT_MEMORY_WINDOW_H__
-#define __DEBUG_QT_MEMORY_WINDOW_H__
+#ifndef MAME_DEBUGGER_QT_MEMORYWINDOW_H
+#define MAME_DEBUGGER_QT_MEMORYWINDOW_H
-#include <QtWidgets/QLineEdit>
-#include <QtWidgets/QComboBox>
+#pragma once
#include "debuggerview.h"
#include "windowqt.h"
+#include <QtWidgets/QComboBox>
+#include <QtWidgets/QLineEdit>
+
+
+namespace osd::debugger::qt {
+
class DebuggerMemView;
@@ -20,31 +25,40 @@ class MemoryWindow : public WindowQt
Q_OBJECT
public:
- MemoryWindow(running_machine* machine, QWidget* parent=nullptr);
+ MemoryWindow(DebuggerQt &debugger, QWidget *parent = nullptr);
virtual ~MemoryWindow();
+ virtual void restoreConfiguration(util::xml::data_node const &node) override;
+
+protected:
+ virtual void saveConfigurationToNode(util::xml::data_node &node) override;
+
+ // Used to intercept the user hitting the up arrow in the input widget
+ virtual bool eventFilter(QObject *obj, QEvent *event) override;
private slots:
void memoryRegionChanged(int index);
void expressionSubmitted();
- void formatChanged(QAction* changedTo);
- void addressChanged(QAction* changedTo);
+ void expressionEdited(QString const &text);
+
+ void formatChanged(QAction *changedTo);
+ void addressChanged(QAction *changedTo);
+ void radixChanged(QAction *changedTo);
void reverseChanged(bool changedTo);
void increaseBytesPerLine(bool changedTo);
- void decreaseBytesPerLine(bool checked=false);
-
+ void decreaseBytesPerLine(bool checked = false);
private:
void populateComboBox();
void setToCurrentCpu();
- QAction* dataFormatMenuItem(const QString& itemName);
-
-private:
// Widgets
- QLineEdit* m_inputEdit;
- QComboBox* m_memoryComboBox;
- DebuggerMemView* m_memTable;
+ QLineEdit *m_inputEdit;
+ QComboBox *m_memoryComboBox;
+ DebuggerMemView *m_memTable;
+
+ // Expression history
+ CommandHistory m_inputHistory;
};
@@ -53,47 +67,25 @@ private:
//=========================================================================
class DebuggerMemView : public DebuggerView
{
+ Q_OBJECT
+
public:
- DebuggerMemView(const debug_view_type& type,
- running_machine* machine,
- QWidget* parent=nullptr)
+ DebuggerMemView(const debug_view_type& type, running_machine &machine, QWidget *parent = nullptr)
: DebuggerView(type, machine, parent)
{}
+
virtual ~DebuggerMemView() {}
protected:
- void mousePressEvent(QMouseEvent* event);
-};
+ virtual void addItemsToContextMenu(QMenu *menu) override;
+private slots:
+ void copyLastPc();
-//=========================================================================
-// A way to store the configuration of a window long enough to read/write.
-//=========================================================================
-class MemoryWindowQtConfig : public WindowQtConfig
-{
-public:
- MemoryWindowQtConfig() :
- WindowQtConfig(WIN_TYPE_MEMORY),
- m_reverse(0),
- m_addressMode(0),
- m_dataFormat(0),
- m_memoryRegion(0)
- {
- }
-
- ~MemoryWindowQtConfig() {}
-
- // Settings
- int m_reverse;
- int m_addressMode;
- int m_dataFormat;
- int m_memoryRegion;
-
- void buildFromQWidget(QWidget* widget);
- void applyToQWidget(QWidget* widget);
- void addToXmlDataNode(util::xml::data_node &node) const;
- void recoverFromXmlNode(util::xml::data_node const &node);
+private:
+ QString m_lastPc;
};
+} // namespace osd::debugger::qt
-#endif
+#endif // MAME_DEBUGGER_QT_MEMORYWINDOW_H
diff --git a/src/osd/modules/debugger/qt/windowqt.cpp b/src/osd/modules/debugger/qt/windowqt.cpp
index dda9ee64dc7..294871e6d22 100644
--- a/src/osd/modules/debugger/qt/windowqt.cpp
+++ b/src/osd/modules/debugger/qt/windowqt.cpp
@@ -1,104 +1,114 @@
// license:BSD-3-Clause
// copyright-holders:Andrew Gardner
#include "emu.h"
-#include <QtWidgets/QMenu>
-#include <QtWidgets/QMenuBar>
-
#include "windowqt.h"
-#include "logwindow.h"
-#include "dasmwindow.h"
-#include "memorywindow.h"
+
#include "breakpointswindow.h"
+#include "dasmwindow.h"
#include "deviceswindow.h"
+#include "logwindow.h"
+#include "memorywindow.h"
+#include "debugger.h"
+#include "debug/debugcon.h"
#include "debug/debugcpu.h"
-bool WindowQt::s_refreshAll = false;
-bool WindowQt::s_hideAll = false;
+#include "util/xmlfile.h"
+#include <QtWidgets/QMenu>
+#include <QtWidgets/QMenuBar>
+
+
+namespace osd::debugger::qt {
// Since all debug windows are intended to be top-level, this inherited
// constructor is always called with a nullptr parent. The passed-in parent widget,
// however, is often used to place each child window & the code to do this can
// be found in most of the inherited classes.
-WindowQt::WindowQt(running_machine* machine, QWidget* parent) :
+WindowQt::WindowQt(DebuggerQt &debugger, QWidget *parent) :
QMainWindow(parent),
- m_machine(machine)
+ m_debugger(debugger),
+ m_machine(debugger.machine())
{
setAttribute(Qt::WA_DeleteOnClose, true);
+ // Subscribe to signals
+ connect(&debugger, &DebuggerQt::exitDebugger, this, &WindowQt::debuggerExit);
+ connect(&debugger, &DebuggerQt::hideAllWindows, this, &WindowQt::hide);
+ connect(&debugger, &DebuggerQt::showAllWindows, this, &WindowQt::show);
+ connect(&debugger, &DebuggerQt::saveConfiguration, this, &WindowQt::saveConfiguration);
+
// The Debug menu bar
- QAction* debugActOpenMemory = new QAction("New &Memory Window", this);
+ QAction *debugActOpenMemory = new QAction("New &Memory Window", this);
debugActOpenMemory->setShortcut(QKeySequence("Ctrl+M"));
connect(debugActOpenMemory, &QAction::triggered, this, &WindowQt::debugActOpenMemory);
- QAction* debugActOpenDasm = new QAction("New &Dasm Window", this);
+ QAction *debugActOpenDasm = new QAction("New &Disassembly Window", this);
debugActOpenDasm->setShortcut(QKeySequence("Ctrl+D"));
connect(debugActOpenDasm, &QAction::triggered, this, &WindowQt::debugActOpenDasm);
- QAction* debugActOpenLog = new QAction("New &Log Window", this);
+ QAction *debugActOpenLog = new QAction("New Error &Log Window", this);
debugActOpenLog->setShortcut(QKeySequence("Ctrl+L"));
connect(debugActOpenLog, &QAction::triggered, this, &WindowQt::debugActOpenLog);
- QAction* debugActOpenPoints = new QAction("New &Break|Watchpoints Window", this);
+ QAction *debugActOpenPoints = new QAction("New (&Break|Watch)points Window", this);
debugActOpenPoints->setShortcut(QKeySequence("Ctrl+B"));
connect(debugActOpenPoints, &QAction::triggered, this, &WindowQt::debugActOpenPoints);
- QAction* debugActOpenDevices = new QAction("New D&evices Window", this);
- debugActOpenDevices->setShortcut(QKeySequence("Shift+Ctrl+D"));
+ QAction *debugActOpenDevices = new QAction("New D&evices Window", this);
connect(debugActOpenDevices, &QAction::triggered, this, &WindowQt::debugActOpenDevices);
- QAction* dbgActRun = new QAction("Run", this);
+ QAction *dbgActRun = new QAction("Run", this);
dbgActRun->setShortcut(Qt::Key_F5);
connect(dbgActRun, &QAction::triggered, this, &WindowQt::debugActRun);
- QAction* dbgActRunAndHide = new QAction("Run And Hide Debugger", this);
+ QAction *dbgActRunAndHide = new QAction("Run And Hide Debugger", this);
dbgActRunAndHide->setShortcut(Qt::Key_F12);
connect(dbgActRunAndHide, &QAction::triggered, this, &WindowQt::debugActRunAndHide);
- QAction* dbgActRunToNextCpu = new QAction("Run to Next CPU", this);
+ QAction *dbgActRunToNextCpu = new QAction("Run to Next CPU", this);
dbgActRunToNextCpu->setShortcut(Qt::Key_F6);
connect(dbgActRunToNextCpu, &QAction::triggered, this, &WindowQt::debugActRunToNextCpu);
- QAction* dbgActRunNextInt = new QAction("Run to Next Interrupt on This CPU", this);
+ QAction *dbgActRunNextInt = new QAction("Run to Next Interrupt on This CPU", this);
dbgActRunNextInt->setShortcut(Qt::Key_F7);
connect(dbgActRunNextInt, &QAction::triggered, this, &WindowQt::debugActRunNextInt);
- QAction* dbgActRunNextVBlank = new QAction("Run to Next VBlank", this);
+ QAction *dbgActRunNextVBlank = new QAction("Run to Next VBlank", this);
dbgActRunNextVBlank->setShortcut(Qt::Key_F8);
connect(dbgActRunNextVBlank, &QAction::triggered, this, &WindowQt::debugActRunNextVBlank);
- QAction* dbgActStepInto = new QAction("Step Into", this);
+ QAction *dbgActStepInto = new QAction("Step Into", this);
dbgActStepInto->setShortcut(Qt::Key_F11);
connect(dbgActStepInto, &QAction::triggered, this, &WindowQt::debugActStepInto);
- QAction* dbgActStepOver = new QAction("Step Over", this);
+ QAction *dbgActStepOver = new QAction("Step Over", this);
dbgActStepOver->setShortcut(Qt::Key_F10);
connect(dbgActStepOver, &QAction::triggered, this, &WindowQt::debugActStepOver);
- QAction* dbgActStepOut = new QAction("Step Out", this);
+ QAction *dbgActStepOut = new QAction("Step Out", this);
dbgActStepOut->setShortcut(QKeySequence("Shift+F11"));
connect(dbgActStepOut, &QAction::triggered, this, &WindowQt::debugActStepOut);
- QAction* dbgActSoftReset = new QAction("Soft Reset", this);
+ QAction *dbgActSoftReset = new QAction("Soft Reset", this);
dbgActSoftReset->setShortcut(Qt::Key_F3);
connect(dbgActSoftReset, &QAction::triggered, this, &WindowQt::debugActSoftReset);
- QAction* dbgActHardReset = new QAction("Hard Reset", this);
+ QAction *dbgActHardReset = new QAction("Hard Reset", this);
dbgActHardReset->setShortcut(QKeySequence("Shift+F3"));
connect(dbgActHardReset, &QAction::triggered, this, &WindowQt::debugActHardReset);
- QAction* dbgActClose = new QAction("Close &Window", this);
+ QAction *dbgActClose = new QAction("Close &Window", this);
dbgActClose->setShortcut(QKeySequence::Close);
connect(dbgActClose, &QAction::triggered, this, &WindowQt::debugActClose);
- QAction* dbgActQuit = new QAction("&Quit", this);
+ QAction *dbgActQuit = new QAction("&Quit", this);
dbgActQuit->setShortcut(QKeySequence::Quit);
connect(dbgActQuit, &QAction::triggered, this, &WindowQt::debugActQuit);
// Construct the menu
- QMenu* debugMenu = menuBar()->addMenu("&Debug");
+ QMenu *debugMenu = menuBar()->addMenu("&Debug");
debugMenu->addAction(debugActOpenMemory);
debugMenu->addAction(debugActOpenDasm);
debugMenu->addAction(debugActOpenLog);
@@ -127,9 +137,10 @@ WindowQt::~WindowQt()
{
}
+
void WindowQt::debugActOpenMemory()
{
- MemoryWindow* foo = new MemoryWindow(m_machine, this);
+ MemoryWindow *foo = new MemoryWindow(m_debugger, this);
// A valiant effort, but it just doesn't wanna' hide behind the main window & not make a new toolbar icon
// foo->setWindowFlags(Qt::Dialog);
// foo->setWindowFlags(foo->windowFlags() & ~Qt::WindowStaysOnTopHint);
@@ -139,7 +150,7 @@ void WindowQt::debugActOpenMemory()
void WindowQt::debugActOpenDasm()
{
- DasmWindow* foo = new DasmWindow(m_machine, this);
+ DasmWindow *foo = new DasmWindow(m_debugger, this);
// A valiant effort, but it just doesn't wanna' hide behind the main window & not make a new toolbar icon
// foo->setWindowFlags(Qt::Dialog);
// foo->setWindowFlags(foo->windowFlags() & ~Qt::WindowStaysOnTopHint);
@@ -149,7 +160,7 @@ void WindowQt::debugActOpenDasm()
void WindowQt::debugActOpenLog()
{
- LogWindow* foo = new LogWindow(m_machine, this);
+ LogWindow *foo = new LogWindow(m_debugger, this);
// A valiant effort, but it just doesn't wanna' hide behind the main window & not make a new toolbar icon
// foo->setWindowFlags(Qt::Dialog);
// foo->setWindowFlags(foo->windowFlags() & ~Qt::WindowStaysOnTopHint);
@@ -159,7 +170,7 @@ void WindowQt::debugActOpenLog()
void WindowQt::debugActOpenPoints()
{
- BreakpointsWindow* foo = new BreakpointsWindow(m_machine, this);
+ BreakpointsWindow *foo = new BreakpointsWindow(m_debugger, this);
// A valiant effort, but it just doesn't wanna' hide behind the main window & not make a new toolbar icon
// foo->setWindowFlags(Qt::Dialog);
// foo->setWindowFlags(foo->windowFlags() & ~Qt::WindowStaysOnTopHint);
@@ -169,7 +180,7 @@ void WindowQt::debugActOpenPoints()
void WindowQt::debugActOpenDevices()
{
- DevicesWindow* foo = new DevicesWindow(m_machine, this);
+ DevicesWindow *foo = new DevicesWindow(m_debugger, this);
// A valiant effort, but it just doesn't wanna' hide behind the main window & not make a new toolbar icon
// foo->setWindowFlags(Qt::Dialog);
// foo->setWindowFlags(foo->windowFlags() & ~Qt::WindowStaysOnTopHint);
@@ -179,54 +190,54 @@ void WindowQt::debugActOpenDevices()
void WindowQt::debugActRun()
{
- m_machine->debugger().cpu().get_visible_cpu()->debug()->go();
+ m_machine.debugger().console().get_visible_cpu()->debug()->go();
}
void WindowQt::debugActRunAndHide()
{
- m_machine->debugger().cpu().get_visible_cpu()->debug()->go();
- hideAll();
+ m_machine.debugger().console().get_visible_cpu()->debug()->go();
+ m_debugger.hideAll();
}
void WindowQt::debugActRunToNextCpu()
{
- m_machine->debugger().cpu().get_visible_cpu()->debug()->go_next_device();
+ m_machine.debugger().console().get_visible_cpu()->debug()->go_next_device();
}
void WindowQt::debugActRunNextInt()
{
- m_machine->debugger().cpu().get_visible_cpu()->debug()->go_interrupt();
+ m_machine.debugger().console().get_visible_cpu()->debug()->go_interrupt();
}
void WindowQt::debugActRunNextVBlank()
{
- m_machine->debugger().cpu().get_visible_cpu()->debug()->go_vblank();
+ m_machine.debugger().console().get_visible_cpu()->debug()->go_vblank();
}
void WindowQt::debugActStepInto()
{
- m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step();
+ m_machine.debugger().console().get_visible_cpu()->debug()->single_step();
}
void WindowQt::debugActStepOver()
{
- m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step_over();
+ m_machine.debugger().console().get_visible_cpu()->debug()->single_step_over();
}
void WindowQt::debugActStepOut()
{
- m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step_out();
+ m_machine.debugger().console().get_visible_cpu()->debug()->single_step_out();
}
void WindowQt::debugActSoftReset()
{
- m_machine->schedule_soft_reset();
- m_machine->debugger().cpu().get_visible_cpu()->debug()->single_step();
+ m_machine.schedule_soft_reset();
+ m_machine.debugger().console().get_visible_cpu()->debug()->single_step();
}
void WindowQt::debugActHardReset()
{
- m_machine->schedule_hard_reset();
+ m_machine.schedule_hard_reset();
}
void WindowQt::debugActClose()
@@ -236,43 +247,158 @@ void WindowQt::debugActClose()
void WindowQt::debugActQuit()
{
- m_machine->schedule_exit();
+ m_machine.schedule_exit();
+}
+
+void WindowQt::debuggerExit()
+{
+ // this isn't called from a Qt event loop, so close() will leak the window object
+ delete this;
+}
+
+
+void WindowQt::restoreConfiguration(util::xml::data_node const &node)
+{
+ QPoint p(geometry().topLeft());
+ p.setX(node.get_attribute_int(ATTR_WINDOW_POSITION_X, p.x()));
+ p.setY(node.get_attribute_int(ATTR_WINDOW_POSITION_Y, p.y()));
+
+ QSize s(size());
+ s.setWidth(node.get_attribute_int(ATTR_WINDOW_WIDTH, s.width()));
+ s.setHeight(node.get_attribute_int(ATTR_WINDOW_HEIGHT, s.height()));
+
+ // TODO: sanity checks, restrict to screen area
+
+ setGeometry(p.x(), p.y(), s.width(), s.height());
+}
+
+
+void WindowQt::saveConfiguration(util::xml::data_node &parentnode)
+{
+ util::xml::data_node *const node = parentnode.add_child(NODE_WINDOW, nullptr);
+ if (node)
+ saveConfigurationToNode(*node);
}
-//=========================================================================
-// WindowQtConfig
-//=========================================================================
-void WindowQtConfig::buildFromQWidget(QWidget* widget)
+void WindowQt::saveConfigurationToNode(util::xml::data_node &node)
{
- m_position.setX(widget->geometry().topLeft().x());
- m_position.setY(widget->geometry().topLeft().y());
- m_size.setX(widget->size().width());
- m_size.setY(widget->size().height());
+ node.set_attribute_int(ATTR_WINDOW_POSITION_X, geometry().topLeft().x());
+ node.set_attribute_int(ATTR_WINDOW_POSITION_Y, geometry().topLeft().y());
+ node.set_attribute_int(ATTR_WINDOW_WIDTH, size().width());
+ node.set_attribute_int(ATTR_WINDOW_HEIGHT, size().height());
}
-void WindowQtConfig::applyToQWidget(QWidget* widget)
+CommandHistory::CommandHistory() :
+ m_history(),
+ m_current(),
+ m_position(-1)
{
- widget->setGeometry(m_position.x(), m_position.y(), m_size.x(), m_size.y());
}
-void WindowQtConfig::addToXmlDataNode(util::xml::data_node &node) const
+CommandHistory::~CommandHistory()
{
- node.set_attribute_int("type", m_type);
- node.set_attribute_int("position_x", m_position.x());
- node.set_attribute_int("position_y", m_position.y());
- node.set_attribute_int("size_x", m_size.x());
- node.set_attribute_int("size_y", m_size.y());
}
-void WindowQtConfig::recoverFromXmlNode(util::xml::data_node const &node)
+void CommandHistory::add(QString const &entry)
{
- m_size.setX(node.get_attribute_int("size_x", m_size.x()));
- m_size.setY(node.get_attribute_int("size_y", m_size.y()));
- m_position.setX(node.get_attribute_int("position_x", m_position.x()));
- m_position.setY(node.get_attribute_int("position_y", m_position.y()));
- m_type = (WindowQtConfig::WindowType)node.get_attribute_int("type", m_type);
+ if (m_history.empty() || (m_history.front() != entry))
+ {
+ while (m_history.size() >= CAPACITY)
+ m_history.pop_back();
+ m_history.push_front(entry);
+ }
+ m_position = 0;
}
+
+
+QString const *CommandHistory::previous(QString const &current)
+{
+ if ((m_position + 1) < m_history.size())
+ {
+ if (0 > m_position)
+ m_current = std::make_unique<QString>(current);
+ return &m_history[++m_position];
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+
+QString const *CommandHistory::next(QString const &current)
+{
+ if (0 < m_position)
+ {
+ return &m_history[--m_position];
+ }
+ else if (!m_position && m_current && (m_history.front() != *m_current))
+ {
+ --m_position;
+ return m_current.get();
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+
+void CommandHistory::edit()
+{
+ if (!m_position)
+ --m_position;
+}
+
+
+void CommandHistory::reset()
+{
+ m_position = -1;
+ m_current.reset();
+}
+
+
+void CommandHistory::clear()
+{
+ m_position = -1;
+ m_current.reset();
+ m_history.clear();
+}
+
+
+void CommandHistory::restoreConfigurationFromNode(util::xml::data_node const &node)
+{
+ clear();
+ util::xml::data_node const *const historynode = node.get_child(NODE_WINDOW_HISTORY);
+ if (historynode)
+ {
+ util::xml::data_node const *itemnode = historynode->get_child(NODE_HISTORY_ITEM);
+ while (itemnode)
+ {
+ if (itemnode->get_value() && *itemnode->get_value())
+ {
+ while (m_history.size() >= CAPACITY)
+ m_history.pop_back();
+ m_history.push_front(QString::fromUtf8(itemnode->get_value()));
+ }
+ itemnode = itemnode->get_next_sibling(NODE_HISTORY_ITEM);
+ }
+ }
+}
+
+
+void CommandHistory::saveConfigurationToNode(util::xml::data_node &node)
+{
+ util::xml::data_node *const historynode = node.add_child(NODE_WINDOW_HISTORY, nullptr);
+ if (historynode)
+ {
+ for (auto it = m_history.crbegin(); m_history.crend() != it; ++it)
+ historynode->add_child(NODE_HISTORY_ITEM, it->toUtf8().data());
+ }
+}
+
+} // namespace osd::debugger::qt
diff --git a/src/osd/modules/debugger/qt/windowqt.h b/src/osd/modules/debugger/qt/windowqt.h
index 29debc70bc6..b5e933e8a0c 100644
--- a/src/osd/modules/debugger/qt/windowqt.h
+++ b/src/osd/modules/debugger/qt/windowqt.h
@@ -1,12 +1,38 @@
// license:BSD-3-Clause
// copyright-holders:Andrew Gardner
-#ifndef __DEBUG_QT_WINDOW_QT_H__
-#define __DEBUG_QT_WINDOW_QT_H__
+#ifndef MAME_DEBUGGER_QT_WINDOWQT_H
+#define MAME_DEBUGGER_QT_WINDOWQT_H
+
+#include "../xmlconfig.h"
#include <QtWidgets/QMainWindow>
-#include "config.h"
-#include "debugger.h"
+#include <deque>
+#include <memory>
+
+
+namespace osd::debugger::qt {
+
+//============================================================
+// The Qt debugger module interface
+//============================================================
+class DebuggerQt : public QObject
+{
+ Q_OBJECT
+
+public:
+ virtual ~DebuggerQt() { }
+
+ virtual running_machine &machine() const = 0;
+
+ void hideAll() { emit hideAllWindows(); }
+
+signals:
+ void exitDebugger();
+ void hideAllWindows();
+ void showAllWindows();
+ void saveConfiguration(util::xml::data_node &parentnode);
+};
//============================================================
@@ -17,18 +43,9 @@ class WindowQt : public QMainWindow
Q_OBJECT
public:
- WindowQt(running_machine* machine, QWidget* parent=nullptr);
virtual ~WindowQt();
- // The interface to an all-window refresh
- void refreshAll() { s_refreshAll = true; }
- bool wantsRefresh() { return s_refreshAll; }
- void clearRefreshFlag() { s_refreshAll = false; }
-
- void hideAll() { s_hideAll = true; }
- bool wantsHide() { return s_hideAll; }
- void clearHideFlag() { s_hideAll = false; }
-
+ virtual void restoreConfiguration(util::xml::data_node const &node);
protected slots:
void debugActOpenMemory();
@@ -48,52 +65,48 @@ protected slots:
void debugActHardReset();
virtual void debugActClose();
void debugActQuit();
+ virtual void debuggerExit();
+private slots:
+ void saveConfiguration(util::xml::data_node &parentnode);
protected:
- running_machine* m_machine;
+ WindowQt(DebuggerQt &debugger, QWidget *parent = nullptr);
+
+ virtual void saveConfigurationToNode(util::xml::data_node &node);
- static bool s_refreshAll;
- static bool s_hideAll;
+ DebuggerQt &m_debugger;
+ running_machine &m_machine;
};
-//=========================================================================
-// A way to store the configuration of a window long enough to read/write.
-//=========================================================================
-class WindowQtConfig
+//============================================================
+// Command history helper
+//============================================================
+class CommandHistory
{
public:
- enum WindowType
- {
- WIN_TYPE_UNKNOWN,
- WIN_TYPE_MAIN,
- WIN_TYPE_MEMORY,
- WIN_TYPE_DASM,
- WIN_TYPE_LOG,
- WIN_TYPE_BREAK_POINTS,
- WIN_TYPE_DEVICES,
- WIN_TYPE_DEVICE_INFORMATION
- };
+ CommandHistory();
+ ~CommandHistory();
-public:
- WindowQtConfig(const WindowType& type=WIN_TYPE_UNKNOWN) :
- m_type(type),
- m_size(800, 600),
- m_position(120, 120)
- {}
- virtual ~WindowQtConfig() {}
-
- // Settings
- WindowType m_type;
- QPoint m_size;
- QPoint m_position;
-
- virtual void buildFromQWidget(QWidget* widget);
- virtual void applyToQWidget(QWidget* widget);
- virtual void addToXmlDataNode(util::xml::data_node &node) const;
- virtual void recoverFromXmlNode(util::xml::data_node const &node);
+ void add(QString const &entry);
+ QString const *previous(QString const &current);
+ QString const *next(QString const &current);
+ void edit();
+ void reset();
+ void clear();
+
+ void restoreConfigurationFromNode(util::xml::data_node const &node);
+ void saveConfigurationToNode(util::xml::data_node &node);
+
+private:
+ static inline constexpr unsigned CAPACITY = 100U;
+
+ std::deque<QString> m_history;
+ std::unique_ptr<QString> m_current;
+ int m_position;
};
+} // namespace osd::debugger::qt
-#endif
+#endif // MAME_DEBUGGER_QT_WINDOWQT_H
diff --git a/src/osd/modules/debugger/win/consolewininfo.cpp b/src/osd/modules/debugger/win/consolewininfo.cpp
index a9811f5fc93..a5dfd04cc55 100644
--- a/src/osd/modules/debugger/win/consolewininfo.cpp
+++ b/src/osd/modules/debugger/win/consolewininfo.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Aaron Giles, Vas Crabb
//============================================================
//
-// consolewininfo.c - Win32 debug window handling
+// consolewininfo.cpp - Win32 debug window handling
//
//============================================================
@@ -12,47 +12,245 @@
#include "debugviewinfo.h"
#include "uimetrics.h"
-#include "debugger.h"
+// devices
+#include "imagedev/cassette.h"
+
+// emu
#include "debug/debugcon.h"
+#include "debugger.h"
+#include "image.h"
+#include "softlist_dev.h"
#include "debug/debugcpu.h"
-#include "imagedev/cassette.h"
-#include "strconv.h"
+// util
+#include "util/xmlfile.h"
+
+// osd/windows
#include "winutf8.h"
+// osd
+#include "strconv.h"
+
+// C++
+#include <vector>
+
+// Windows
+#include <commctrl.h>
+#include <shlobj.h>
+#include <shobjidl.h>
+#include <shtypes.h>
+#include <wrl/client.h>
+
+
+namespace osd::debugger::win {
+
+namespace {
+
+class comdlg_filter_helper
+{
+public:
+ comdlg_filter_helper(comdlg_filter_helper const &) = delete;
+ comdlg_filter_helper &operator=(comdlg_filter_helper const &) = delete;
+
+ comdlg_filter_helper(device_image_interface &device, bool include_archives)
+ {
+ m_count = 0U;
+
+ std::wstring const extensions = osd::text::to_wstring(device.file_extensions());
+ std::wstring_view extview = extensions;
+ m_description = L"Media Image Files (";
+ for (auto comma = extview.find(','); !extview.empty(); comma = extview.find(','))
+ {
+ bool const found = std::wstring_view::npos != comma;
+ std::wstring_view const ext = found ? extview.substr(0, comma) : extview;
+ extview.remove_prefix(found ? (comma + 1) : extview.length());
+ if (m_extensions.empty())
+ {
+ m_default = ext;
+ m_description.append(L"*.");
+ m_extensions.append(L"*.");
+ }
+ else
+ {
+ m_description.append(L"; *.");
+ m_extensions.append(L";*.");
+ }
+ m_description.append(ext);
+ m_extensions.append(ext);
+ }
+ m_description.append(1, L')');
+ m_specs[m_count].pszName = m_description.c_str();
+ m_specs[m_count].pszSpec = m_extensions.c_str();
+ ++m_count;
+
+ if (include_archives)
+ {
+ m_specs[m_count].pszName = L"Archive Files (*.zip; *.7z)";
+ m_specs[m_count].pszSpec = L"*.zip;*.7z";
+ ++m_count;
+ }
+
+ m_specs[m_count].pszName = L"All Files (*.*)";
+ m_specs[m_count].pszSpec = L"*.*";
+ ++m_count;
+ }
+
+ UINT file_types() const noexcept
+ {
+ return m_count;
+ }
+
+ COMDLG_FILTERSPEC const *filter_spec() const noexcept
+ {
+ return m_specs;
+ }
+
+ LPCWSTR default_extension() const noexcept
+ {
+ return m_default.c_str();
+ }
+
+private:
+ COMDLG_FILTERSPEC m_specs[3];
+ std::wstring m_description;
+ std::wstring m_extensions;
+ std::wstring m_default;
+ UINT m_count;
+};
+
+
+template <typename T>
+void choose_image(device_image_interface &device, HWND owner, REFCLSID class_id, bool allow_archives, T &&handler)
+{
+ HRESULT hr;
+
+ // create file dialog
+ Microsoft::WRL::ComPtr<IFileDialog> dialog;
+ hr = CoCreateInstance(class_id, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&dialog));
+
+ // set file types
+ if (SUCCEEDED(hr))
+ {
+ DWORD flags;
+ hr = dialog->GetOptions(&flags);
+ if (SUCCEEDED(hr))
+ hr = dialog->SetOptions(flags | FOS_NOCHANGEDIR | FOS_FORCEFILESYSTEM);
+ comdlg_filter_helper filters(device, allow_archives);
+ if (SUCCEEDED(hr))
+ hr = dialog->SetFileTypes(filters.file_types(), filters.filter_spec());
+ if (SUCCEEDED(hr))
+ hr = dialog->SetFileTypeIndex(1);
+ if (SUCCEEDED(hr))
+ hr = dialog->SetDefaultExtension(filters.default_extension());
+ }
+
+ // set starting folder
+ if (SUCCEEDED(hr))
+ {
+ std::string dir = device.working_directory();
+ if (dir.empty())
+ {
+ dir = device.device().machine().image().setup_working_directory();
+ device.set_working_directory(dir);
+ }
+ std::string full;
+ if (!dir.empty() && !osd_get_full_path(full, dir))
+ {
+ // FIXME: strip off archive names - opening a file inside an archive decompresses it to a temporary location
+ std::wstring wfull = osd::text::to_wstring(full);
+ Microsoft::WRL::ComPtr<IShellItem> item;
+ if (SUCCEEDED(SHCreateItemFromParsingName(wfull.c_str(), nullptr, IID_PPV_ARGS(&item))))
+ {
+ //dialog->SetFolder(item); disabled until
+ }
+ }
+ }
+
+ // show the dialog
+ if (SUCCEEDED(hr))
+ {
+ hr = dialog->Show(owner);
+ if (HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr)
+ return;
+ }
+ if (SUCCEEDED(hr))
+ {
+ Microsoft::WRL::ComPtr<IShellItem> result;
+ hr = dialog->GetResult(&result);
+ if (SUCCEEDED(hr))
+ {
+ PWSTR selection = nullptr;
+ hr = result->GetDisplayName(SIGDN_FILESYSPATH, &selection);
+ if (SUCCEEDED(hr))
+ {
+ std::string const utf_selection = osd::text::from_wstring(selection);
+ CoTaskMemFree(selection);
+ handler(utf_selection);
+ }
+ }
+ }
+
+ if (!SUCCEEDED(hr))
+ {
+ int pressed;
+ TaskDialog(
+ owner,
+ nullptr, // instance
+ nullptr, // title
+ L"Error showing file dialog",
+ nullptr, // content
+ TDCBF_OK_BUTTON,
+ TD_ERROR_ICON,
+ &pressed);
+ }
+}
+
+} // anonymous namespace
+
+
consolewin_info::consolewin_info(debugger_windows_interface &debugger) :
disasmbasewin_info(debugger, true, "Debug", nullptr),
m_current_cpu(nullptr),
m_devices_menu(nullptr)
{
- if ((window() == nullptr) || (m_views[0] == nullptr))
+ if (!window() || !m_views[0])
goto cleanup;
// create the views
- m_views[1].reset(global_alloc(debugview_info(debugger, *this, window(), DVT_STATE)));
+ m_views[1].reset(new debugview_info(debugger, *this, window(), DVT_STATE));
if (!m_views[1]->is_valid())
goto cleanup;
- m_views[2].reset(global_alloc(debugview_info(debugger, *this, window(), DVT_CONSOLE)));
+ m_views[2].reset(new debugview_info(debugger, *this, window(), DVT_CONSOLE));
if (!m_views[2]->is_valid())
goto cleanup;
{
- // Add image menu only if image devices exist
- image_interface_iterator iter(machine().root_device());
+ // add image menu only if image devices exist
+ image_interface_enumerator iter(machine().root_device());
if (iter.first() != nullptr)
{
m_devices_menu = CreatePopupMenu();
for (device_image_interface &img : iter)
{
- if (!img.user_loadable())
- continue;
- osd::text::tstring tc_buf = osd::text::to_tstring(string_format("%s : %s", img.device().name(), img.exists() ? img.filename() : "[no image]"));
- AppendMenu(m_devices_menu, MF_ENABLED, 0, tc_buf.c_str());
+ if (img.user_loadable())
+ {
+ osd::text::tstring tc_buf = osd::text::to_tstring(string_format("%s : %s", img.device().name(), img.exists() ? img.filename() : "[no image]"));
+ AppendMenu(m_devices_menu, MF_ENABLED, 0, tc_buf.c_str());
+ }
}
AppendMenu(GetMenu(window()), MF_ENABLED | MF_POPUP, (UINT_PTR)m_devices_menu, TEXT("Media"));
}
+ // add the settings menu
+ HMENU const settingsmenu = CreatePopupMenu();
+ AppendMenu(settingsmenu, MF_ENABLED, ID_SAVE_WINDOWS, TEXT("Save Window Arrangement"));
+ AppendMenu(settingsmenu, MF_ENABLED, ID_GROUP_WINDOWS, TEXT("Group Debugger Windows (requires restart)"));
+ AppendMenu(settingsmenu, MF_DISABLED | MF_SEPARATOR, 0, TEXT(""));
+ AppendMenu(settingsmenu, MF_ENABLED, ID_LIGHT_BACKGROUND, TEXT("Light Background"));
+ AppendMenu(settingsmenu, MF_ENABLED, ID_DARK_BACKGROUND, TEXT("Dark Background"));
+ AppendMenu(GetMenu(window()), MF_ENABLED | MF_POPUP, (UINT_PTR)settingsmenu, TEXT("Settings"));
+
// get the work bounds
RECT work_bounds, bounds;
SystemParametersInfo(SPI_GETWORKAREA, 0, &work_bounds, 0);
@@ -78,7 +276,7 @@ consolewin_info::consolewin_info(debugger_windows_interface &debugger) :
}
// recompute the children
- set_cpu(*machine().debugger().cpu().get_visible_cpu());
+ set_cpu(*machine().debugger().console().get_visible_cpu());
// mark the edit box as the default focus and set it
editwin_info::set_default_focus();
@@ -163,11 +361,11 @@ void consolewin_info::update_menu()
{
disasmbasewin_info::update_menu();
- if (m_devices_menu != nullptr)
+ if (m_devices_menu)
{
// create the image menu
uint32_t cnt = 0;
- for (device_image_interface &img : image_interface_iterator(machine().root_device()))
+ for (device_image_interface &img : image_interface_enumerator(machine().root_device()))
{
if (!img.user_loadable())
continue;
@@ -184,8 +382,8 @@ void consolewin_info::update_menu()
if (img.is_readonly())
flags_for_writing |= MF_GRAYED;
- // not working properly, removed for now until investigation can be done
- //if (get_softlist_info(&img))
+ // FIXME: needs a real software item picker to be useful
+ //if (get_softlist_info(img))
// AppendMenu(devicesubmenu, MF_STRING, new_item + DEVOPTION_ITEM, TEXT("Mount Item..."));
AppendMenu(devicesubmenu, MF_STRING, new_item + DEVOPTION_OPEN, TEXT("Mount File..."));
@@ -199,7 +397,7 @@ void consolewin_info::update_menu()
if (img.device().type() == CASSETTE)
{
- cassette_state const state = cassette_state(downcast<cassette_image_device *>(&img.device())->get_state() & CASSETTE_MASK_UISTATE);
+ cassette_state const state = downcast<cassette_image_device *>(&img.device())->get_state() & CASSETTE_MASK_UISTATE;
AppendMenu(devicesubmenu, MF_SEPARATOR, 0, nullptr);
AppendMenu(devicesubmenu, flags_for_exists | ((state == CASSETTE_STOPPED) ? MF_CHECKED : 0), new_item + DEVOPTION_CASSETTE_STOPPAUSE, TEXT("Pause/Stop"));
AppendMenu(devicesubmenu, flags_for_exists | ((state == CASSETTE_PLAY) ? MF_CHECKED : 0), new_item + DEVOPTION_CASSETTE_PLAY, TEXT("Play"));
@@ -208,9 +406,9 @@ void consolewin_info::update_menu()
AppendMenu(devicesubmenu, flags_for_exists, new_item + DEVOPTION_CASSETTE_FASTFORWARD, TEXT("Fast Forward"));
AppendMenu(devicesubmenu, MF_SEPARATOR, 0, nullptr);
// Motor state can be overriden by the driver
- cassette_state const motor_state = cassette_state(downcast<cassette_image_device *>(&img.device())->get_state() & CASSETTE_MASK_MOTOR);
+ cassette_state const motor_state = downcast<cassette_image_device *>(&img.device())->get_state() & CASSETTE_MASK_MOTOR;
AppendMenu(devicesubmenu, flags_for_exists | ((motor_state == CASSETTE_MOTOR_ENABLED) ? MF_CHECKED : 0), new_item + DEVOPTION_CASSETTE_MOTOR, TEXT("Motor"));
- cassette_state const speaker_state = cassette_state(downcast<cassette_image_device *>(&img.device())->get_state() & CASSETTE_MASK_SPEAKER);
+ cassette_state const speaker_state = downcast<cassette_image_device *>(&img.device())->get_state() & CASSETTE_MASK_SPEAKER;
AppendMenu(devicesubmenu, flags_for_exists | ((speaker_state == CASSETTE_SPEAKER_ENABLED) ? MF_CHECKED : 0), new_item + DEVOPTION_CASSETTE_SOUND, TEXT("Audio while Loading"));
}
}
@@ -249,239 +447,105 @@ void consolewin_info::update_menu()
cnt++;
}
}
+
+ HMENU const menu = GetMenu(window());
+ CheckMenuItem(menu, ID_SAVE_WINDOWS, MF_BYCOMMAND | (debugger().get_save_window_arrangement() ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(menu, ID_GROUP_WINDOWS, MF_BYCOMMAND | (debugger().get_group_windows_setting() ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(menu, ID_LIGHT_BACKGROUND, MF_BYCOMMAND | ((ui_metrics::THEME_LIGHT_BACKGROUND == metrics().get_color_theme()) ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(menu, ID_DARK_BACKGROUND, MF_BYCOMMAND | ((ui_metrics::THEME_DARK_BACKGROUND == metrics().get_color_theme()) ? MF_CHECKED : MF_UNCHECKED));
}
bool consolewin_info::handle_command(WPARAM wparam, LPARAM lparam)
{
- if ((HIWORD(wparam) == 0) && (LOWORD(wparam) >= ID_DEVICE_OPTIONS))
+ if (HIWORD(wparam) == 0)
{
- uint32_t const devid = (LOWORD(wparam) - ID_DEVICE_OPTIONS) / DEVOPTION_MAX;
- image_interface_iterator iter(machine().root_device());
- device_image_interface *const img = iter.byindex(devid);
- if (img != nullptr)
+ if (LOWORD(wparam) >= ID_DEVICE_OPTIONS)
{
- switch ((LOWORD(wparam) - ID_DEVICE_OPTIONS) % DEVOPTION_MAX)
+ uint32_t const devid = (LOWORD(wparam) - ID_DEVICE_OPTIONS) / DEVOPTION_MAX;
+ image_interface_enumerator iter(machine().root_device());
+ device_image_interface *const img = iter.byindex(devid);
+ if (img != nullptr)
{
- case DEVOPTION_ITEM :
- {
- std::string filter;
- build_generic_filter(nullptr, false, filter);
- {
- osd::text::tstring t_filter = osd::text::to_tstring(filter);
-
- // convert a pipe-char delimited string into a NUL delimited string
- for (int i = 0; t_filter[i] != '\0'; i++)
- {
- if (t_filter[i] == '|')
- t_filter[i] = '\0';
- }
-
- std::string opt_name = img->instance_name();
- std::string as = slmap.find(opt_name)->second;
-
- /* Make sure a folder was specified, and that it exists */
- if ((!osd::directory::open(as.c_str())) || (as.find(':') == std::string::npos))
- {
- /* Default to emu directory */
- osd_get_full_path(as, ".");
- }
- osd::text::tstring t_dir = osd::text::to_tstring(as);
-
- // display the dialog
- TCHAR selectedFilename[MAX_PATH];
- selectedFilename[0] = '\0';
- OPENFILENAME ofn;
- memset(&ofn, 0, sizeof(ofn));
- ofn.lStructSize = sizeof(ofn);
- ofn.hwndOwner = nullptr;
- ofn.lpstrFile = selectedFilename;
- ofn.lpstrFile[0] = '\0';
- ofn.nMaxFile = MAX_PATH;
- ofn.lpstrFilter = t_filter.c_str();
- ofn.nFilterIndex = 1;
- ofn.lpstrFileTitle = nullptr;
- ofn.nMaxFileTitle = 0;
- ofn.lpstrInitialDir = t_dir.c_str();
- ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
-
- if (GetOpenFileName(&ofn))
- {
- std::string buf = std::string(osd::text::from_tstring(selectedFilename));
- // Get the Item name out of the full path
- size_t t1 = buf.find(".zip"); // get rid of zip name and anything after
- if (t1 != std::string::npos)
- buf.erase(t1);
- t1 = buf.find(".7z"); // get rid of 7zip name and anything after
- if (t1 != std::string::npos)
- buf.erase(t1);
- t1 = buf.find_last_of("\\"); // put the swlist name in
- buf[t1] = ':';
- t1 = buf.find_last_of("\\"); // get rid of path; we only want the item name
- buf.erase(0, t1+1);
-
- // load software
- img->load_software( buf.c_str());
- }
- }
- }
- return true;
- case DEVOPTION_OPEN :
- {
- std::string filter;
- build_generic_filter(img, false, filter);
- {
- osd::text::tstring t_filter = osd::text::to_tstring(filter);
-
- // convert a pipe-char delimited string into a NUL delimited string
- for (int i = 0; t_filter[i] != '\0'; i++)
- {
- if (t_filter[i] == '|')
- t_filter[i] = '\0';
- }
-
- char buf[400];
- std::string as;
- strcpy(buf, machine().options().emu_options::sw_path());
- // This pulls out the first path from a multipath field
- const char* t1 = strtok(buf, ";");
- if (t1)
- as = t1; // the first path of many
- else
- as = buf; // the only path
-
- /* Make sure a folder was specified, and that it exists */
- if ((!osd::directory::open(as.c_str())) || (as.find(':') == std::string::npos))
- {
- /* Default to emu directory */
- osd_get_full_path(as, ".");
- }
- osd::text::tstring t_dir = osd::text::to_tstring(as);
-
- TCHAR selectedFilename[MAX_PATH];
- selectedFilename[0] = '\0';
- OPENFILENAME ofn;
- memset(&ofn, 0, sizeof(ofn));
- ofn.lStructSize = sizeof(ofn);
- ofn.hwndOwner = nullptr;
- ofn.lpstrFile = selectedFilename;
- ofn.lpstrFile[0] = '\0';
- ofn.nMaxFile = MAX_PATH;
- ofn.lpstrFilter = t_filter.c_str();
- ofn.nFilterIndex = 1;
- ofn.lpstrFileTitle = nullptr;
- ofn.nMaxFileTitle = 0;
- ofn.lpstrInitialDir = t_dir.c_str();
- ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
-
- if (GetOpenFileName(&ofn))
- {
- auto utf8_buf = osd::text::from_tstring(selectedFilename);
- img->load(utf8_buf.c_str());
- }
- }
- }
- return true;
- case DEVOPTION_CREATE:
- {
- std::string filter;
- build_generic_filter(img, true, filter);
- {
- osd::text::tstring t_filter = osd::text::to_tstring(filter);
- // convert a pipe-char delimited string into a NUL delimited string
- for (int i = 0; t_filter[i] != '\0'; i++)
- {
- if (t_filter[i] == '|')
- t_filter[i] = '\0';
- }
-
- char buf[400];
- std::string as;
- strcpy(buf, machine().options().emu_options::sw_path());
- // This pulls out the first path from a multipath field
- const char* t1 = strtok(buf, ";");
- if (t1)
- as = t1; // the first path of many
- else
- as = buf; // the only path
-
- /* Make sure a folder was specified, and that it exists */
- if ((!osd::directory::open(as.c_str())) || (as.find(':') == std::string::npos))
- {
- /* Default to emu directory */
- osd_get_full_path(as, ".");
- }
- osd::text::tstring t_dir = osd::text::to_tstring(as);
-
- TCHAR selectedFilename[MAX_PATH];
- selectedFilename[0] = '\0';
- OPENFILENAME ofn;
- memset(&ofn, 0, sizeof(ofn));
- ofn.lStructSize = sizeof(ofn);
- ofn.hwndOwner = nullptr;
- ofn.lpstrFile = selectedFilename;
- ofn.lpstrFile[0] = '\0';
- ofn.nMaxFile = MAX_PATH;
- ofn.lpstrFilter = t_filter.c_str();
- ofn.nFilterIndex = 1;
- ofn.lpstrFileTitle = nullptr;
- ofn.nMaxFileTitle = 0;
- ofn.lpstrInitialDir = t_dir.c_str();
- ofn.Flags = OFN_PATHMUSTEXIST;
-
- if (GetSaveFileName(&ofn))
- {
- auto utf8_buf = osd::text::from_tstring(selectedFilename);
- img->create(utf8_buf.c_str(), img->device_get_indexed_creatable_format(0), nullptr);
- }
- }
- }
- return true;
- case DEVOPTION_CLOSE:
- img->unload();
- return true;
- }
- if (img->device().type() == CASSETTE)
- {
- cassette_image_device *const cassette = downcast<cassette_image_device *>(&img->device());
- bool s;
switch ((LOWORD(wparam) - ID_DEVICE_OPTIONS) % DEVOPTION_MAX)
{
- case DEVOPTION_CASSETTE_STOPPAUSE:
- cassette->change_state(CASSETTE_STOPPED, CASSETTE_MASK_UISTATE);
+ case DEVOPTION_ITEM:
+ // TODO: this is supposed to show a software list item picker - it never worked properly
return true;
- case DEVOPTION_CASSETTE_PLAY:
- cassette->change_state(CASSETTE_PLAY, CASSETTE_MASK_UISTATE);
+ case DEVOPTION_OPEN :
+ open_image_file(*img);
return true;
- case DEVOPTION_CASSETTE_RECORD:
- cassette->change_state(CASSETTE_RECORD, CASSETTE_MASK_UISTATE);
+ case DEVOPTION_CREATE:
+ create_image_file(*img);
return true;
- case DEVOPTION_CASSETTE_REWIND:
- cassette->seek(0.0, SEEK_SET); // to start
+ case DEVOPTION_CLOSE:
+ img->unload();
return true;
- case DEVOPTION_CASSETTE_FASTFORWARD:
- cassette->seek(+300.0, SEEK_CUR); // 5 minutes forward or end, whichever comes first
- break;
- case DEVOPTION_CASSETTE_MOTOR:
- s =((cassette->get_state() & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_DISABLED);
- cassette->change_state(s ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
- break;
- case DEVOPTION_CASSETTE_SOUND:
- s =((cassette->get_state() & CASSETTE_MASK_SPEAKER) == CASSETTE_SPEAKER_MUTED);
- cassette->change_state(s ? CASSETTE_SPEAKER_ENABLED : CASSETTE_SPEAKER_MUTED, CASSETTE_MASK_SPEAKER);
- break;
+ }
+ if (img->device().type() == CASSETTE)
+ {
+ auto *const cassette = downcast<cassette_image_device *>(&img->device());
+ bool s;
+ switch ((LOWORD(wparam) - ID_DEVICE_OPTIONS) % DEVOPTION_MAX)
+ {
+ case DEVOPTION_CASSETTE_STOPPAUSE:
+ cassette->change_state(CASSETTE_STOPPED, CASSETTE_MASK_UISTATE);
+ return true;
+ case DEVOPTION_CASSETTE_PLAY:
+ cassette->change_state(CASSETTE_PLAY, CASSETTE_MASK_UISTATE);
+ return true;
+ case DEVOPTION_CASSETTE_RECORD:
+ cassette->change_state(CASSETTE_RECORD, CASSETTE_MASK_UISTATE);
+ return true;
+ case DEVOPTION_CASSETTE_REWIND:
+ cassette->seek(0.0, SEEK_SET); // to start
+ return true;
+ case DEVOPTION_CASSETTE_FASTFORWARD:
+ cassette->seek(+300.0, SEEK_CUR); // 5 minutes forward or end, whichever comes first
+ return true;
+ case DEVOPTION_CASSETTE_MOTOR:
+ s = ((cassette->get_state() & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_DISABLED);
+ cassette->change_state(s ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
+ return true;
+ case DEVOPTION_CASSETTE_SOUND:
+ s = ((cassette->get_state() & CASSETTE_MASK_SPEAKER) == CASSETTE_SPEAKER_MUTED);
+ cassette->change_state(s ? CASSETTE_SPEAKER_ENABLED : CASSETTE_SPEAKER_MUTED, CASSETTE_MASK_SPEAKER);
+ return true;
+ }
}
}
}
+ else switch (LOWORD(wparam))
+ {
+ case ID_SAVE_WINDOWS:
+ debugger().set_save_window_arrangement(!debugger().get_save_window_arrangement());
+ return true;
+ case ID_GROUP_WINDOWS:
+ debugger().set_group_windows_setting(!debugger().get_group_windows_setting());
+ return true;
+ case ID_LIGHT_BACKGROUND:
+ debugger().set_color_theme(ui_metrics::THEME_LIGHT_BACKGROUND);
+ return true;
+ case ID_DARK_BACKGROUND:
+ debugger().set_color_theme(ui_metrics::THEME_DARK_BACKGROUND);
+ return true;
+ }
}
return disasmbasewin_info::handle_command(wparam, lparam);
}
+void consolewin_info::save_configuration_to_node(util::xml::data_node &node)
+{
+ disasmbasewin_info::save_configuration_to_node(node);
+ node.set_attribute_int(ATTR_WINDOW_TYPE, WINDOW_TYPE_CONSOLE);
+}
+
+
void consolewin_info::process_string(std::string const &string)
{
if (string.empty()) // an empty string is a single step
- machine().debugger().cpu().get_visible_cpu()->debug()->single_step();
+ machine().debugger().console().get_visible_cpu()->debug()->single_step();
else // otherwise, just process the command
machine().debugger().console().execute_command(string, true);
@@ -490,94 +554,60 @@ void consolewin_info::process_string(std::string const &string)
}
-void consolewin_info::build_generic_filter(device_image_interface *img, bool is_save, std::string &filter)
+void consolewin_info::open_image_file(device_image_interface &device)
{
- std::string file_extension;
-
- if (img)
- file_extension = img->file_extensions();
-
- if (!is_save)
- file_extension.append(",zip,7z");
-
- add_filter_entry(filter, "Common image types", file_extension.c_str());
-
- filter.append("All files (*.*)|*.*|");
-
- if (!is_save)
- filter.append("Compressed Images (*.zip;*.7z)|*.zip;*.7z|");
+ choose_image(
+ device,
+ window(),
+ CLSID_FileOpenDialog,
+ true,
+ [this, &device] (std::string_view selection)
+ {
+ auto [err, message] = device.load(selection);
+ if (err)
+ machine().debugger().console().printf("Error mounting image file: %s\n", !message.empty() ? message : err.message());
+ });
}
-void consolewin_info::add_filter_entry(std::string &dest, const char *description, const char *extensions)
+void consolewin_info::create_image_file(device_image_interface &device)
{
- // add the description
- dest.append(description);
- dest.append(" (");
-
- // add the extensions to the description
- copy_extension_list(dest, extensions);
-
- // add the trailing rparen and '|' character
- dest.append(")|");
-
- // now add the extension list itself
- copy_extension_list(dest, extensions);
-
- // append a '|'
- dest.append("|");
+ choose_image(
+ device,
+ window(),
+ CLSID_FileSaveDialog,
+ false,
+ [this, &device] (std::string_view selection)
+ {
+ auto [err, message] = device.create(selection, device.device_get_indexed_creatable_format(0), nullptr);
+ if (err)
+ machine().debugger().console().printf("Error creating image file: %s\n", !message.empty() ? message : err.message());
+ });
}
-void consolewin_info::copy_extension_list(std::string &dest, const char *extensions)
-{
- // our extension lists are comma delimited; Win32 expects to see lists
- // delimited by semicolons
- char const *s = extensions;
- while (*s)
- {
- // append a semicolon if not at the beginning
- if (s != extensions)
- dest.push_back(';');
-
- // append ".*"
- dest.append("*.");
-
- // append the file extension
- while (*s && (*s != ','))
- dest.push_back(*s++);
-
- // if we found a comma, advance
- while(*s == ',')
- s++;
- }
-}
-
-//============================================================
-// get_softlist_info
-//============================================================
-bool consolewin_info::get_softlist_info(device_image_interface *img)
+bool consolewin_info::get_softlist_info(device_image_interface &device)
{
bool has_software = false;
bool passes_tests = false;
- std::string sl_dir, opt_name = img->instance_name();
+ std::string sl_dir, opt_name = device.instance_name();
// Get the path to suitable software
- for (software_list_device &swlist : software_list_device_iterator(machine().root_device()))
+ for (software_list_device &swlist : software_list_device_enumerator(machine().root_device()))
{
for (const software_info &swinfo : swlist.get_info())
{
const software_part &part = swinfo.parts().front();
if (swlist.is_compatible(part) == SOFTWARE_IS_COMPATIBLE)
{
- for (device_image_interface &image : image_interface_iterator(machine().root_device()))
+ for (device_image_interface &image : image_interface_enumerator(machine().root_device()))
{
if (!image.user_loadable())
continue;
if (!has_software && (opt_name == image.instance_name()))
{
- const char *interface = image.image_interface();
- if (interface && part.matches_interface(interface))
+ const char *intf = image.image_interface();
+ if (intf && part.matches_interface(intf))
{
sl_dir = "\\" + swlist.list_name();
has_software = true;
@@ -598,7 +628,7 @@ bool consolewin_info::get_softlist_info(device_image_interface *img)
while (sl_root && !passes_tests)
{
std::string test_path = sl_root + sl_dir;
- if (osd::directory::open(test_path.c_str()))
+ if (osd::directory::open(test_path))
{
passes_tests = true;
slmap[opt_name] = test_path;
@@ -609,3 +639,5 @@ bool consolewin_info::get_softlist_info(device_image_interface *img)
return passes_tests;
}
+
+} // namespace osd::debugger::win
diff --git a/src/osd/modules/debugger/win/consolewininfo.h b/src/osd/modules/debugger/win/consolewininfo.h
index 7f8ccc13aec..e79ba667a11 100644
--- a/src/osd/modules/debugger/win/consolewininfo.h
+++ b/src/osd/modules/debugger/win/consolewininfo.h
@@ -5,15 +5,18 @@
// consolewininfo.h - Win32 debug window handling
//
//============================================================
+#ifndef MAME_DEBUGGER_WIN_CONSOLEWININFO_H
+#define MAME_DEBUGGER_WIN_CONSOLEWININFO_H
-#ifndef __DEBUG_WIN_CONSOLE_WIN_INFO_H__
-#define __DEBUG_WIN_CONSOLE_WIN_INFO_H__
+#pragma once
#include "debugwin.h"
#include "disasmbasewininfo.h"
+namespace osd::debugger::win {
+
class consolewin_info : public disasmbasewin_info
{
public:
@@ -26,6 +29,7 @@ protected:
virtual void recompute_children() override;
virtual void update_menu() override;
virtual bool handle_command(WPARAM wparam, LPARAM lparam) override;
+ virtual void save_configuration_to_node(util::xml::data_node &node) override;
private:
enum
@@ -46,14 +50,15 @@ private:
virtual void process_string(std::string const &string) override;
- static void build_generic_filter(device_image_interface *img, bool is_save, std::string &filter);
- static void add_filter_entry(std::string &dest, char const *description, char const *extensions);
- static void copy_extension_list(std::string &dest, char const *extensions);
- bool get_softlist_info(device_image_interface *img);
+ void open_image_file(device_image_interface &device);
+ void create_image_file(device_image_interface &device);
+ bool get_softlist_info(device_image_interface &img);
device_t *m_current_cpu;
- HMENU m_devices_menu;
+ HMENU m_devices_menu;
std::map<std::string,std::string> slmap;
};
-#endif
+} // namespace osd::debugger::win
+
+#endif // MAME_DEBUGGER_WIN_CONSOLEWININFO_H
diff --git a/src/osd/modules/debugger/win/debugbaseinfo.cpp b/src/osd/modules/debugger/win/debugbaseinfo.cpp
index 4914d54cfad..0de7331cbc8 100644
--- a/src/osd/modules/debugger/win/debugbaseinfo.cpp
+++ b/src/osd/modules/debugger/win/debugbaseinfo.cpp
@@ -10,6 +10,8 @@
#include "debugbaseinfo.h"
+namespace osd::debugger::win {
+
debugbase_info::debugbase_info(debugger_windows_interface &debugger) :
m_debugger(debugger),
m_machine(debugger.machine()),
@@ -21,12 +23,10 @@ debugbase_info::debugbase_info(debugger_windows_interface &debugger) :
void debugbase_info::smart_set_window_bounds(HWND wnd, HWND parent, RECT const &bounds)
{
- RECT curbounds;
- int flags = 0;
-
// first get the current bounds, relative to the parent
+ RECT curbounds;
GetWindowRect(wnd, &curbounds);
- if (parent != nullptr)
+ if (parent)
{
RECT parentbounds;
GetWindowRect(parent, &parentbounds);
@@ -37,6 +37,7 @@ void debugbase_info::smart_set_window_bounds(HWND wnd, HWND parent, RECT const &
}
// if the position matches, don't change it
+ int flags = 0;
if (curbounds.top == bounds.top && curbounds.left == bounds.left)
flags |= SWP_NOMOVE;
if ((curbounds.bottom - curbounds.top) == (bounds.bottom - bounds.top) &&
@@ -45,17 +46,21 @@ void debugbase_info::smart_set_window_bounds(HWND wnd, HWND parent, RECT const &
// if we need to, reposition the window
if (flags != (SWP_NOMOVE | SWP_NOSIZE))
- SetWindowPos(wnd, nullptr,
- bounds.left, bounds.top,
- bounds.right - bounds.left, bounds.bottom - bounds.top,
- SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | flags);
+ {
+ SetWindowPos(
+ wnd, nullptr,
+ bounds.left, bounds.top,
+ bounds.right - bounds.left, bounds.bottom - bounds.top,
+ SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | flags);
+ }
}
-
void debugbase_info::smart_show_window(HWND wnd, bool show)
{
- BOOL const visible = IsWindowVisible(wnd);
- if ((visible && !show) || (!visible && show))
+ bool const visible = bool(IsWindowVisible(wnd));
+ if (visible != show)
ShowWindow(wnd, show ? SW_SHOW : SW_HIDE);
}
+
+} // namespace osd::debugger::win
diff --git a/src/osd/modules/debugger/win/debugbaseinfo.h b/src/osd/modules/debugger/win/debugbaseinfo.h
index 03fd5a8018d..da874a6b8fd 100644
--- a/src/osd/modules/debugger/win/debugbaseinfo.h
+++ b/src/osd/modules/debugger/win/debugbaseinfo.h
@@ -5,13 +5,15 @@
// debugbaseinfo.h - Win32 debug window handling
//
//============================================================
+#ifndef MAME_DEBUGGER_WIN_DEBUGBASEINFO_H
+#define MAME_DEBUGGER_WIN_DEBUGBASEINFO_H
-#ifndef __DEBUG_WIN_DEBUG_BASE_INFO_H__
-#define __DEBUG_WIN_DEBUG_BASE_INFO_H__
+#pragma once
#include "debugwin.h"
+namespace osd::debugger::win {
class debugbase_info
{
@@ -35,5 +37,6 @@ private:
bool const &m_waiting_for_debugger;
};
+} // namespace osd::debugger::win
-#endif
+#endif // MAME_DEBUGGER_WIN_DEBUGBASEINFO_H
diff --git a/src/osd/modules/debugger/win/debugviewinfo.cpp b/src/osd/modules/debugger/win/debugviewinfo.cpp
index 97238ff8862..8f3f05c16d2 100644
--- a/src/osd/modules/debugger/win/debugviewinfo.cpp
+++ b/src/osd/modules/debugger/win/debugviewinfo.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Aaron Giles, Vas Crabb
//============================================================
//
-// debugview.c - Win32 debug window handling
+// debugviewinfo.cpp - Win32 debug window handling
//
//============================================================
@@ -12,12 +12,20 @@
#include "debugwininfo.h"
#include "uimetrics.h"
#include "debugger.h"
+
+#include "debug/debugcon.h"
#include "debug/debugcpu.h"
+#include "util/xmlfile.h"
+
#include "strconv.h"
#include "winutil.h"
+#include <mmsystem.h>
+
+
+namespace osd::debugger::win {
// debugger view styles
#define DEBUG_VIEW_STYLE WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN
@@ -45,14 +53,15 @@ debugview_info::debugview_info(debugger_windows_interface &debugger, debugwin_in
m_view(nullptr),
m_wnd(nullptr),
m_hscroll(nullptr),
- m_vscroll(nullptr)
+ m_vscroll(nullptr),
+ m_contextmenu(nullptr)
{
register_window_class();
// create the child view
m_wnd = CreateWindowEx(DEBUG_VIEW_STYLE_EX, TEXT("MAMEDebugView"), nullptr, DEBUG_VIEW_STYLE,
0, 0, 100, 100, parent, nullptr, GetModuleHandleUni(), this);
- if (m_wnd == nullptr)
+ if (!m_wnd)
goto cleanup;
// create the scroll bars
@@ -60,27 +69,27 @@ debugview_info::debugview_info(debugger_windows_interface &debugger, debugwin_in
0, 0, 100, CW_USEDEFAULT, m_wnd, nullptr, GetModuleHandleUni(), this);
m_vscroll = CreateWindowEx(VSCROLL_STYLE_EX, TEXT("SCROLLBAR"), nullptr, VSCROLL_STYLE,
0, 0, CW_USEDEFAULT, 100, m_wnd, nullptr, GetModuleHandleUni(), this);
- if ((m_hscroll == nullptr) || (m_vscroll == nullptr))
+ if (!m_hscroll || !m_vscroll)
goto cleanup;
// create the debug view
m_view = machine().debug_view().alloc_view(type, &debugview_info::static_update, this);
- if (m_view == nullptr)
+ if (!m_view)
goto cleanup;
return;
cleanup:
- if (m_hscroll != nullptr)
+ if (m_hscroll)
DestroyWindow(m_hscroll);
m_hscroll = nullptr;
- if (m_vscroll != nullptr)
+ if (m_vscroll)
DestroyWindow(m_vscroll);
m_vscroll = nullptr;
- if (m_wnd != nullptr)
+ if (m_wnd)
DestroyWindow(m_wnd);
m_wnd = nullptr;
- if (m_view != nullptr)
+ if (m_view)
machine().debug_view().free_view(*m_view);
m_view = nullptr;
}
@@ -88,7 +97,9 @@ cleanup:
debugview_info::~debugview_info()
{
- if (m_wnd != nullptr)
+ if (m_contextmenu)
+ DestroyMenu(m_contextmenu);
+ if (m_wnd)
DestroyWindow(m_wnd);
if (m_view)
machine().debug_view().free_view(*m_view);
@@ -111,14 +122,14 @@ uint32_t debugview_info::maxwidth()
{
uint32_t max = m_view->total_size().x;
debug_view_source const *const cursource = m_view->source();
- for (const debug_view_source &source : m_view->source_list())
+ for (auto &source : m_view->source_list())
{
- m_view->set_source(source);
+ m_view->set_source(*source);
uint32_t const chars = m_view->total_size().x;
if (max < chars)
max = chars;
}
- if (cursource != nullptr)
+ if (cursource)
m_view->set_source(*cursource);
return (max * metrics().debug_font_width()) + metrics().vscroll_width();
}
@@ -163,27 +174,35 @@ void debugview_info::send_vscroll(int delta)
void debugview_info::send_pageup()
{
if (m_vscroll)
- {
SendMessage(m_wnd, WM_VSCROLL, SB_PAGELEFT, (LPARAM)m_vscroll);
- }
}
void debugview_info::send_pagedown()
{
if (m_vscroll)
- {
SendMessage(m_wnd, WM_VSCROLL, SB_PAGERIGHT, (LPARAM)m_vscroll);
+}
+
+
+int debugview_info::source_index() const
+{
+ if (m_view)
+ {
+ debug_view_source const *const source = m_view->source();
+ if (source)
+ return m_view->source_index(*source);
}
+ return -1;
}
char const *debugview_info::source_name() const
{
- if (m_view != nullptr)
+ if (m_view)
{
debug_view_source const *const source = m_view->source();
- if (source != nullptr)
+ if (source)
return source->name();
}
return "";
@@ -192,10 +211,10 @@ char const *debugview_info::source_name() const
device_t *debugview_info::source_device() const
{
- if (m_view != nullptr)
+ if (m_view)
{
debug_view_source const *const source = m_view->source();
- if (source != nullptr)
+ if (source)
return source->device();
}
return nullptr;
@@ -204,10 +223,10 @@ device_t *debugview_info::source_device() const
bool debugview_info::source_is_visible_cpu() const
{
- if (m_view != nullptr)
+ if (m_view)
{
const debug_view_source *const source = m_view->source();
- return (source != nullptr) && (machine().debugger().cpu().get_visible_cpu() == source->device());
+ return source && (machine().debugger().console().get_visible_cpu() == source->device());
}
return false;
}
@@ -215,10 +234,10 @@ bool debugview_info::source_is_visible_cpu() const
bool debugview_info::set_source_index(int index)
{
- if (m_view != nullptr)
+ if (m_view)
{
- const debug_view_source *const source = m_view->source_list().find(index);
- if (source != nullptr)
+ const debug_view_source *const source = m_view->source(index);
+ if (source)
{
m_view->set_source(*source);
return true;
@@ -230,10 +249,10 @@ bool debugview_info::set_source_index(int index)
bool debugview_info::set_source_for_device(device_t &device)
{
- if (m_view != nullptr)
+ if (m_view)
{
const debug_view_source *const source = m_view->source_for_device(&device);
- if (source != nullptr)
+ if (source)
{
m_view->set_source(*source);
return true;
@@ -245,8 +264,8 @@ bool debugview_info::set_source_for_device(device_t &device)
bool debugview_info::set_source_for_visible_cpu()
{
- device_t *const curcpu = machine().debugger().cpu().get_visible_cpu();
- if (curcpu != nullptr)
+ device_t *const curcpu = machine().debugger().console().get_visible_cpu();
+ if (curcpu)
return set_source_for_device(*curcpu);
else
return false;
@@ -264,7 +283,7 @@ HWND debugview_info::create_source_combobox(HWND parent, LONG_PTR userdata)
// populate the combobox
debug_view_source const *const cursource = m_view->source();
int maxlength = 0;
- for (debug_view_source const *source = m_view->first_source(); source != nullptr; source = source->next())
+ for (auto &source : m_view->source_list())
{
int const length = strlen(source->name());
if (length > maxlength)
@@ -272,9 +291,9 @@ HWND debugview_info::create_source_combobox(HWND parent, LONG_PTR userdata)
auto t_name = osd::text::to_tstring(source->name());
SendMessage(result, CB_ADDSTRING, 0, (LPARAM)t_name.c_str());
}
- if (cursource != nullptr)
+ if (cursource)
{
- SendMessage(result, CB_SETCURSEL, m_view->source_list().indexof(*cursource), 0);
+ SendMessage(result, CB_SETCURSEL, m_view->source_index(*cursource), 0);
SendMessage(result, CB_SETDROPPEDWIDTH, ((maxlength + 2) * metrics().debug_font_width()) + metrics().vscroll_width(), 0);
m_view->set_source(*cursource);
}
@@ -282,6 +301,165 @@ HWND debugview_info::create_source_combobox(HWND parent, LONG_PTR userdata)
}
+void debugview_info::restore_configuration_from_node(util::xml::data_node const &node)
+{
+ if (m_view->cursor_supported())
+ {
+ util::xml::data_node const *const selection = node.get_child(NODE_WINDOW_SELECTION);
+ if (selection)
+ {
+ debug_view_xy pos = m_view->cursor_position();
+ m_view->set_cursor_visible(0 != selection->get_attribute_int(ATTR_SELECTION_CURSOR_VISIBLE, m_view->cursor_visible() ? 1 : 0));
+ selection->get_attribute_int(ATTR_SELECTION_CURSOR_X, pos.x);
+ selection->get_attribute_int(ATTR_SELECTION_CURSOR_Y, pos.y);
+ m_view->set_cursor_position(pos);
+ }
+ }
+
+ util::xml::data_node const *const scroll = node.get_child(NODE_WINDOW_SCROLL);
+ if (scroll)
+ {
+ debug_view_xy origin = m_view->visible_position();
+ origin.x = scroll->get_attribute_int(ATTR_SCROLL_ORIGIN_X, origin.x * metrics().debug_font_width()) / metrics().debug_font_width();
+ origin.y = scroll->get_attribute_int(ATTR_SCROLL_ORIGIN_Y, origin.y * metrics().debug_font_height()) / metrics().debug_font_height();
+ m_view->set_visible_position(origin);
+ }
+}
+
+
+void debugview_info::save_configuration_to_node(util::xml::data_node &node)
+{
+ if (m_view->cursor_supported())
+ {
+ util::xml::data_node *const selection = node.add_child(NODE_WINDOW_SELECTION, nullptr);
+ if (selection)
+ {
+ debug_view_xy const pos = m_view->cursor_position();
+ selection->set_attribute_int(ATTR_SELECTION_CURSOR_VISIBLE, m_view->cursor_visible() ? 1 : 0);
+ selection->set_attribute_int(ATTR_SELECTION_CURSOR_X, pos.x);
+ selection->set_attribute_int(ATTR_SELECTION_CURSOR_Y, pos.y);
+ }
+ }
+
+ util::xml::data_node *const scroll = node.add_child(NODE_WINDOW_SCROLL, nullptr);
+ if (scroll)
+ {
+ debug_view_xy const origin = m_view->visible_position();
+ scroll->set_attribute_int(ATTR_SCROLL_ORIGIN_X, origin.x * metrics().debug_font_width());
+ scroll->set_attribute_int(ATTR_SCROLL_ORIGIN_Y, origin.y * metrics().debug_font_height());
+ }
+}
+
+
+void debugview_info::add_items_to_context_menu(HMENU menu)
+{
+ AppendMenu(menu, MF_ENABLED, ID_CONTEXT_COPY_VISIBLE, TEXT("Copy Visible"));
+ AppendMenu(menu, MF_ENABLED, ID_CONTEXT_PASTE, TEXT("Paste"));
+}
+
+
+void debugview_info::update_context_menu(HMENU menu)
+{
+ EnableMenuItem(menu, ID_CONTEXT_PASTE, MF_BYCOMMAND | (IsClipboardFormatAvailable(CF_UNICODETEXT) ? MF_ENABLED : MF_GRAYED));
+}
+
+
+void debugview_info::handle_context_menu(unsigned command)
+{
+ switch (command)
+ {
+ case ID_CONTEXT_COPY_VISIBLE:
+ {
+ // get visible text
+ debug_view_xy const visarea = m_view->visible_size();
+ debug_view_char const *viewdata = m_view->viewdata();
+ if (!viewdata)
+ {
+ PlaySound(TEXT("SystemAsterisk"), nullptr, SND_SYNC);
+ break;
+ }
+
+ // turn into a plain string, trimming trailing whitespace
+ std::wstring text;
+ for (uint32_t row = 0; row < visarea.y; row++, viewdata += visarea.x)
+ {
+ std::wstring::size_type const start = text.length();
+ for (uint32_t col = 0; col < visarea.x; ++col)
+ text += wchar_t(viewdata[col].byte);
+ std::wstring::size_type const nonblank = text.find_last_not_of(L"\t\n\v\r ");
+ if (nonblank != std::wstring::npos)
+ text.resize((std::max)(start, nonblank + 1));
+ text += L"\r\n";
+ }
+
+ // copy to the clipboard
+ HGLOBAL const clip = GlobalAlloc(GMEM_MOVEABLE, (text.length() + 1) * sizeof(wchar_t));
+ if (!clip)
+ {
+ PlaySound(TEXT("SystemAsterisk"), nullptr, SND_SYNC);
+ break;
+ }
+ if (!OpenClipboard(m_wnd))
+ {
+ GlobalFree(clip);
+ PlaySound(TEXT("SystemAsterisk"), nullptr, SND_SYNC);
+ break;
+ }
+ EmptyClipboard();
+ LPWSTR const lock = reinterpret_cast<LPWSTR>(GlobalLock(clip));
+ std::copy_n(text.c_str(), text.length() + 1, lock);
+ GlobalUnlock(clip);
+ if (!SetClipboardData(CF_UNICODETEXT, clip))
+ {
+ GlobalFree(clip);
+ PlaySound(TEXT("SystemAsterisk"), nullptr, SND_SYNC);
+ }
+ CloseClipboard();
+ break;
+ }
+
+ case ID_CONTEXT_PASTE:
+ if (!IsClipboardFormatAvailable(CF_UNICODETEXT) || !OpenClipboard(m_wnd))
+ {
+ PlaySound(TEXT("SystemAsterisk"), nullptr, SND_SYNC);
+ }
+ else
+ {
+ HGLOBAL const clip = GetClipboardData(CF_UNICODETEXT);
+ LPCWSTR lock = clip ? reinterpret_cast<LPCWSTR>(GlobalLock(clip)) : nullptr;
+ if (!clip || !lock)
+ {
+ PlaySound(TEXT("SystemAsterisk"), nullptr, SND_SYNC);
+ }
+ else
+ {
+ try
+ {
+ while (*lock)
+ {
+ if ((32 <= *lock) && (127 >= *lock))
+ m_view->process_char(*lock);
+ ++lock;
+ }
+ }
+ catch (...)
+ {
+ GlobalUnlock(clip);
+ CloseClipboard();
+ throw;
+ }
+ GlobalUnlock(clip);
+ }
+ CloseClipboard();
+ }
+ break;
+
+ default:
+ osd_printf_warning("debugview_info: unhandled context menu item %u\n", command);
+ }
+}
+
+
void debugview_info::draw_contents(HDC windc)
{
debug_view_char const *viewdata = m_view->viewdata();
@@ -290,18 +468,22 @@ void debugview_info::draw_contents(HDC windc)
// get the client rect
RECT client;
GetClientRect(m_wnd, &client);
+ bool const need_filldown = client.bottom > (metrics().debug_font_height() * visarea.y);
// create a compatible DC and an offscreen bitmap
HDC const dc = CreateCompatibleDC(windc);
- if (dc == nullptr)
+ if (!dc)
return;
HBITMAP const bitmap = CreateCompatibleBitmap(windc, client.right, client.bottom);
- if (bitmap == nullptr)
+ if (!bitmap)
{
DeleteDC(dc);
return;
}
HGDIOBJ const oldbitmap = SelectObject(dc, bitmap);
+ bool const show_hscroll = m_hscroll && IsWindowVisible(m_hscroll);
+ if (show_hscroll)
+ client.bottom -= metrics().hscroll_height();
// set the font
HGDIOBJ const oldfont = SelectObject(dc, metrics().debug_font());
@@ -312,11 +494,13 @@ void debugview_info::draw_contents(HDC windc)
// iterate over rows and columns
for (uint32_t row = 0; row < visarea.y; row++)
{
+ bool do_filldown = (row == (visarea.y - 1)) && need_filldown;
+
// loop twice; once to fill the background and once to draw the text
for (int iter = 0; iter < 2; iter++)
{
COLORREF fgcolor;
- COLORREF bgcolor = RGB(0xff,0xff,0xff);
+ COLORREF bgcolor = metrics().view_colors(DCA_NORMAL).second;
HBRUSH bgbrush = nullptr;
int last_attrib = -1;
TCHAR buffer[256];
@@ -340,41 +524,49 @@ void debugview_info::draw_contents(HDC windc)
{
COLORREF oldbg = bgcolor;
- // reset to standard colors
- fgcolor = RGB(0x00,0x00,0x00);
- bgcolor = RGB(0xff,0xff,0xff);
-
- // pick new fg/bg colors
- if (viewdata[col].attrib & DCA_VISITED) bgcolor = RGB(0xc6, 0xe2, 0xff);
- if (viewdata[col].attrib & DCA_ANCILLARY) bgcolor = RGB(0xe0,0xe0,0xe0);
- if (viewdata[col].attrib & DCA_SELECTED) bgcolor = RGB(0xff,0x80,0x80);
- if (viewdata[col].attrib & DCA_CURRENT) bgcolor = RGB(0xff,0xff,0x00);
- if ((viewdata[col].attrib & DCA_SELECTED) && (viewdata[col].attrib & DCA_CURRENT)) bgcolor = RGB(0xff,0xc0,0x80);
- if (viewdata[col].attrib & DCA_CHANGED) fgcolor = RGB(0xff,0x00,0x00);
- if (viewdata[col].attrib & DCA_INVALID) fgcolor = RGB(0x00,0x00,0xff);
- if (viewdata[col].attrib & DCA_DISABLED) fgcolor = RGB((GetRValue(fgcolor) + GetRValue(bgcolor)) / 2, (GetGValue(fgcolor) + GetGValue(bgcolor)) / 2, (GetBValue(fgcolor) + GetBValue(bgcolor)) / 2);
- if (viewdata[col].attrib & DCA_COMMENT) fgcolor = RGB(0x00,0x80,0x00);
+ // pick new colors
+ std::tie(fgcolor, bgcolor) = metrics().view_colors(viewdata[col].attrib);
// flush any pending drawing
if (count > 0)
{
bounds.right = bounds.left + (count * metrics().debug_font_width());
if (iter == 0)
+ {
FillRect(dc, &bounds, bgbrush);
+ if (do_filldown)
+ {
+ COLORREF const filldown = metrics().view_colors(last_attrib & DCA_ANCILLARY).second;
+ if (oldbg != filldown)
+ {
+ DeleteObject(bgbrush);
+ bgbrush = CreateSolidBrush(filldown);
+ oldbg = filldown;
+ }
+ RECT padding = bounds;
+ padding.top = padding.bottom;
+ padding.bottom = client.bottom;
+ FillRect(dc, &padding, bgbrush);
+ }
+ }
else
+ {
ExtTextOut(dc, bounds.left, bounds.top, 0, nullptr, buffer, count, nullptr);
+ }
bounds.left = bounds.right;
count = 0;
}
// set the new colors
- if (iter == 0 && oldbg != bgcolor)
+ if (iter == 1)
+ {
+ SetTextColor(dc, fgcolor);
+ }
+ else if (oldbg != bgcolor)
{
DeleteObject(bgbrush);
bgbrush = CreateSolidBrush(bgcolor);
}
- else if (iter == 1)
- SetTextColor(dc, fgcolor);
last_attrib = viewdata[col].attrib;
}
@@ -383,33 +575,43 @@ void debugview_info::draw_contents(HDC windc)
}
// flush any remaining stuff
- if (count > 0)
- {
- bounds.right = bounds.left + (count * metrics().debug_font_width());
- if (iter == 0)
- FillRect(dc, &bounds, bgbrush);
- else
- ExtTextOut(dc, bounds.left, bounds.top, 0, nullptr, buffer, count, nullptr);
- }
-
- // erase to the end of the line
+ bounds.right = bounds.left + (count * metrics().debug_font_width());
if (iter == 0)
{
- bounds.left = bounds.right;
+ // erase to the end of the line
bounds.right = client.right;
FillRect(dc, &bounds, bgbrush);
+ if (do_filldown)
+ {
+ COLORREF const filldown = metrics().view_colors(last_attrib & DCA_ANCILLARY).second;
+ if (bgcolor != filldown)
+ {
+ DeleteObject(bgbrush);
+ bgbrush = CreateSolidBrush(filldown);
+ }
+ bounds.top = bounds.bottom;
+ bounds.bottom = client.bottom;
+ FillRect(dc, &bounds, bgbrush);
+ }
DeleteObject(bgbrush);
}
+ else if (count > 0)
+ {
+ ExtTextOut(dc, bounds.left, bounds.top, 0, nullptr, buffer, count, nullptr);
+ }
}
// advance viewdata
viewdata += visarea.x;
}
- // erase anything beyond the bottom with white
- GetClientRect(m_wnd, &client);
- client.top = visarea.y * metrics().debug_font_height();
- FillRect(dc, &client, (HBRUSH)GetStockObject(WHITE_BRUSH));
+ // prevent garbage from showing in the corner
+ if (show_hscroll)
+ {
+ client.top = client.bottom;
+ client.bottom = client.top + metrics().hscroll_height();
+ FillRect(dc, &client, (HBRUSH)GetStockObject(WHITE_BRUSH));
+ }
// reset the font
SetBkMode(dc, oldbkmode);
@@ -428,47 +630,48 @@ void debugview_info::draw_contents(HDC windc)
void debugview_info::update()
{
- RECT bounds, vscroll_bounds, hscroll_bounds;
- debug_view_xy totalsize, visiblesize, topleft;
- bool show_vscroll, show_hscroll;
SCROLLINFO scrollinfo;
+ // get the updated total rows/cols and left row/col
+ debug_view_xy const totalsize = m_view->total_size();
+ debug_view_xy topleft = m_view->visible_position();
+
// get the view window bounds
+ RECT bounds;
GetClientRect(m_wnd, &bounds);
+ debug_view_xy visiblesize;
visiblesize.x = (bounds.right - bounds.left) / metrics().debug_font_width();
visiblesize.y = (bounds.bottom - bounds.top) / metrics().debug_font_height();
- // get the updated total rows/cols and left row/col
- totalsize = m_view->total_size();
- topleft = m_view->visible_position();
-
// determine if we need to show the scrollbars
- show_vscroll = show_hscroll = false;
- if (totalsize.x > visiblesize.x && bounds.bottom >= metrics().hscroll_height())
+ bool const fit_hscroll = (bounds.bottom - bounds.top) > metrics().hscroll_height();
+ bool show_hscroll = fit_hscroll && (totalsize.x > visiblesize.x);
+ if (show_hscroll)
{
bounds.bottom -= metrics().hscroll_height();
visiblesize.y = (bounds.bottom - bounds.top) / metrics().debug_font_height();
- show_hscroll = true;
- }
- if (totalsize.y > visiblesize.y && bounds.right >= metrics().vscroll_width())
- {
- bounds.right -= metrics().vscroll_width();
- visiblesize.x = (bounds.right - bounds.left) / metrics().debug_font_width();
- show_vscroll = true;
}
- if (!show_vscroll && totalsize.y > visiblesize.y && bounds.right >= metrics().vscroll_width())
+ bool const fit_vscroll = (bounds.right - bounds.left) > metrics().vscroll_width();
+ bool const show_vscroll = fit_vscroll && (totalsize.y > visiblesize.y);
+ if (show_vscroll)
{
bounds.right -= metrics().vscroll_width();
visiblesize.x = (bounds.right - bounds.left) / metrics().debug_font_width();
- show_vscroll = true;
+ if (fit_hscroll && !show_hscroll && (totalsize.x > visiblesize.x))
+ {
+ bounds.bottom -= metrics().hscroll_height();
+ visiblesize.y = (bounds.bottom - bounds.top) / metrics().debug_font_height();
+ show_hscroll = true;
+ }
}
// compute the bounds of the scrollbars
+ RECT vscroll_bounds;
GetClientRect(m_wnd, &vscroll_bounds);
vscroll_bounds.left = vscroll_bounds.right - metrics().vscroll_width();
if (show_hscroll)
vscroll_bounds.bottom -= metrics().hscroll_height();
-
+ RECT hscroll_bounds;
GetClientRect(m_wnd, &hscroll_bounds);
hscroll_bounds.top = hscroll_bounds.bottom - metrics().hscroll_height();
if (show_vscroll)
@@ -481,26 +684,34 @@ void debugview_info::update()
topleft.x = std::max(totalsize.x - visiblesize.x, 0);
// fill out the scroll info struct for the vertical scrollbar
- scrollinfo.cbSize = sizeof(scrollinfo);
- scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
- scrollinfo.nMin = 0;
- scrollinfo.nMax = totalsize.y - 1;
- scrollinfo.nPage = visiblesize.y;
- scrollinfo.nPos = topleft.y;
- SetScrollInfo(m_vscroll, SB_CTL, &scrollinfo, TRUE);
+ if (m_vscroll)
+ {
+ scrollinfo.cbSize = sizeof(scrollinfo);
+ scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
+ scrollinfo.nMin = 0;
+ scrollinfo.nMax = totalsize.y - 1;
+ scrollinfo.nPage = visiblesize.y;
+ scrollinfo.nPos = topleft.y;
+ SetScrollInfo(m_vscroll, SB_CTL, &scrollinfo, TRUE);
+ }
// fill out the scroll info struct for the horizontal scrollbar
- scrollinfo.cbSize = sizeof(scrollinfo);
- scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
- scrollinfo.nMin = 0;
- scrollinfo.nMax = totalsize.x - 1;
- scrollinfo.nPage = visiblesize.x;
- scrollinfo.nPos = topleft.x;
- SetScrollInfo(m_hscroll, SB_CTL, &scrollinfo, TRUE);
+ if (m_hscroll)
+ {
+ scrollinfo.cbSize = sizeof(scrollinfo);
+ scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
+ scrollinfo.nMin = 0;
+ scrollinfo.nMax = totalsize.x - 1;
+ scrollinfo.nPage = visiblesize.x;
+ scrollinfo.nPos = topleft.x;
+ SetScrollInfo(m_hscroll, SB_CTL, &scrollinfo, TRUE);
+ }
// update window info
- visiblesize.y++;
- visiblesize.x++;
+ if (((bounds.right - bounds.left) > (visiblesize.x * metrics().debug_font_width())) && ((topleft.x + visiblesize.x) < totalsize.x))
+ visiblesize.x++;
+ if (((bounds.bottom - bounds.top) > (visiblesize.y * metrics().debug_font_height())) && ((topleft.y + visiblesize.y) < totalsize.y))
+ visiblesize.y++;
m_view->set_visible_size(visiblesize);
m_view->set_visible_position(topleft);
@@ -580,7 +791,41 @@ uint32_t debugview_info::process_scroll(WORD type, HWND wnd)
scrollinfo.nPos = result;
SetScrollInfo(wnd, SB_CTL, &scrollinfo, TRUE);
- return (uint32_t)result;
+ return uint32_t(result);
+}
+
+
+bool debugview_info::process_context_menu(int x, int y)
+{
+ // don't show a menu if not in client rect
+ RECT clientrect;
+ GetClientRect(m_wnd, &clientrect);
+ POINT loc{ x, y };
+ ScreenToClient(m_wnd, &loc);
+ if (!PtInRect(&clientrect, loc))
+ return false;
+
+ // create the context menu if we haven’t already
+ if (!m_contextmenu)
+ {
+ m_contextmenu = CreatePopupMenu();
+ if (!m_contextmenu)
+ return false;
+ add_items_to_context_menu(m_contextmenu);
+ }
+
+ // show the context menu
+ update_context_menu(m_contextmenu);
+ BOOL const command(TrackPopupMenu(
+ m_contextmenu,
+ (GetSystemMetrics(SM_MENUDROPALIGNMENT) ? TPM_RIGHTALIGN : TPM_LEFTALIGN) | TPM_LEFTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD,
+ x, y,
+ 0,
+ m_wnd,
+ nullptr));
+ if (command)
+ handle_context_menu(command);
+ return true;
}
@@ -603,7 +848,7 @@ LRESULT debugview_info::view_proc(UINT message, WPARAM wparam, LPARAM lparam)
case WM_SYSKEYDOWN:
if (wparam != VK_F10)
return DefWindowProc(m_wnd, message, wparam, lparam);
- // (fall through)
+ [[fallthrough]];
case WM_KEYDOWN:
{
if (m_owner.handle_key(wparam, lparam))
@@ -717,17 +962,33 @@ LRESULT debugview_info::view_proc(UINT message, WPARAM wparam, LPARAM lparam)
// mouse click
case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
{
- debug_view_xy topleft = m_view->visible_position();
+ debug_view_xy const topleft = m_view->visible_position();
+ debug_view_xy const visiblesize = m_view->visible_size();
debug_view_xy newpos;
- newpos.x = topleft.x + GET_X_LPARAM(lparam) / metrics().debug_font_width();
- newpos.y = topleft.y + GET_Y_LPARAM(lparam) / metrics().debug_font_height();
- m_view->process_click(DCK_LEFT_CLICK, newpos);
+ newpos.x = std::max(std::min<int>(topleft.x + GET_X_LPARAM(lparam) / metrics().debug_font_width(), topleft.x + visiblesize.x - 1), 0);
+ newpos.y = std::max(std::min<int>(topleft.y + GET_Y_LPARAM(lparam) / metrics().debug_font_height(), topleft.y + visiblesize.y - 1), 0);
+ m_view->process_click((message == WM_LBUTTONDOWN) ? DCK_LEFT_CLICK : DCK_MIDDLE_CLICK, newpos);
SetFocus(m_wnd);
break;
}
- // hscroll
+ // right click
+ case WM_RBUTTONDOWN:
+ if (m_view->cursor_supported())
+ {
+ debug_view_xy const topleft = m_view->visible_position();
+ debug_view_xy const visiblesize = m_view->visible_size();
+ debug_view_xy newpos;
+ newpos.x = std::max(std::min<int>(topleft.x + GET_X_LPARAM(lparam) / metrics().debug_font_width(), topleft.x + visiblesize.x - 1), 0);
+ newpos.y = std::max(std::min<int>(topleft.y + GET_Y_LPARAM(lparam) / metrics().debug_font_height(), topleft.y + visiblesize.y - 1), 0);
+ m_view->set_cursor_position(newpos);
+ m_view->set_cursor_visible(true);
+ }
+ return DefWindowProc(m_wnd, message, wparam, lparam);
+
+ // horizontal scroll
case WM_HSCROLL:
{
debug_view_xy topleft = m_view->visible_position();
@@ -737,7 +998,7 @@ LRESULT debugview_info::view_proc(UINT message, WPARAM wparam, LPARAM lparam)
break;
}
- // vscroll
+ // vertical scroll
case WM_VSCROLL:
{
debug_view_xy topleft = m_view->visible_position();
@@ -747,6 +1008,11 @@ LRESULT debugview_info::view_proc(UINT message, WPARAM wparam, LPARAM lparam)
break;
}
+ case WM_CONTEXTMENU:
+ if (!process_context_menu(GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam)))
+ return DefWindowProc(m_wnd, message, wparam, lparam);
+ break;
+
// everything else: defaults
default:
return DefWindowProc(m_wnd, message, wparam, lparam);
@@ -758,7 +1024,7 @@ LRESULT debugview_info::view_proc(UINT message, WPARAM wparam, LPARAM lparam)
void debugview_info::static_update(debug_view &view, void *osdprivate)
{
- debugview_info *const info = (debugview_info *)osdprivate;
+ auto *const info = (debugview_info *)osdprivate;
assert(info->m_view == &view);
info->update();
}
@@ -774,7 +1040,7 @@ LRESULT CALLBACK debugview_info::static_view_proc(HWND wnd, UINT message, WPARAM
return 0;
}
- debugview_info *const info = (debugview_info *)(uintptr_t)GetWindowLongPtr(wnd, GWLP_USERDATA);
+ auto *const info = (debugview_info *)(uintptr_t)GetWindowLongPtr(wnd, GWLP_USERDATA);
if (info == nullptr)
return DefWindowProc(wnd, message, wparam, lparam);
@@ -810,3 +1076,5 @@ void debugview_info::register_window_class()
s_window_class_registered = true;
}
}
+
+} // namespace osd::debugger::win
diff --git a/src/osd/modules/debugger/win/debugviewinfo.h b/src/osd/modules/debugger/win/debugviewinfo.h
index 37d6930e445..a009c368441 100644
--- a/src/osd/modules/debugger/win/debugviewinfo.h
+++ b/src/osd/modules/debugger/win/debugviewinfo.h
@@ -5,9 +5,10 @@
// debugviewinfo.h - Win32 debug window handling
//
//============================================================
+#ifndef MAME_DEBUGGER_WIN_DEBUGVIEWINFO_H
+#define MAME_DEBUGGER_WIN_DEBUGVIEWINFO_H
-#ifndef __DEBUG_WIN_DEBUG_VIEW_INFO_H__
-#define __DEBUG_WIN_DEBUG_VIEW_INFO_H__
+#pragma once
#include "debugwin.h"
@@ -16,6 +17,8 @@
#include "debug/debugvw.h"
+namespace osd::debugger::win {
+
class debugview_info : protected debugbase_info
{
public:
@@ -41,6 +44,7 @@ public:
bool cursor_supported() const { return m_view->cursor_supported(); }
bool cursor_visible() const { return m_view->cursor_visible(); }
+ int source_index() const;
char const *source_name() const;
device_t *source_device() const;
bool source_is_visible_cpu() const;
@@ -50,13 +54,27 @@ public:
HWND create_source_combobox(HWND parent, LONG_PTR userdata);
+ virtual void restore_configuration_from_node(util::xml::data_node const &node);
+ virtual void save_configuration_to_node(util::xml::data_node &node);
+
protected:
+ enum
+ {
+ ID_CONTEXT_COPY_VISIBLE = 1,
+ ID_CONTEXT_PASTE
+ };
+
template <typename T> T *view() const { return downcast<T *>(m_view); }
+ virtual void add_items_to_context_menu(HMENU menu);
+ virtual void update_context_menu(HMENU menu);
+ virtual void handle_context_menu(unsigned command);
+
private:
void draw_contents(HDC windc);
void update();
uint32_t process_scroll(WORD type, HWND wnd);
+ bool process_context_menu(int x, int y);
LRESULT view_proc(UINT message, WPARAM wparam, LPARAM lparam);
static void static_update(debug_view &view, void *osdprivate);
@@ -69,8 +87,11 @@ private:
HWND m_wnd;
HWND m_hscroll;
HWND m_vscroll;
+ HMENU m_contextmenu;
static bool s_window_class_registered;
};
-#endif
+} // namespace osd::debugger::win
+
+#endif // MAME_DEBUGGER_WIN_DEBUGVIEWINFO_H
diff --git a/src/osd/modules/debugger/win/debugwin.h b/src/osd/modules/debugger/win/debugwin.h
index ea78f126d5b..d8af29b795e 100644
--- a/src/osd/modules/debugger/win/debugwin.h
+++ b/src/osd/modules/debugger/win/debugwin.h
@@ -5,9 +5,12 @@
// debugwin.h - Win32 debug window handling
//
//============================================================
+#ifndef MAME_DEBUGGER_WIN_DEBUGWIN_H
+#define MAME_DEBUGGER_WIN_DEBUGWIN_H
-#ifndef __DEBUG_WIN_DEBUG_WIN_H__
-#define __DEBUG_WIN_DEBUG_WIN_H__
+#pragma once
+
+#include "../xmlconfig.h"
// standard windows headers
#include <windows.h>
@@ -19,6 +22,7 @@
#endif
+namespace osd::debugger::win {
class debugview_info;
class debugwin_info;
@@ -33,6 +37,12 @@ public:
virtual running_machine &machine() const = 0;
virtual ui_metrics &metrics() const = 0;
+ virtual void set_color_theme(int index) = 0;
+ virtual bool get_save_window_arrangement() const = 0;
+ virtual void set_save_window_arrangement(bool save) = 0;
+ virtual bool get_group_windows() const = 0;
+ virtual bool get_group_windows_setting() const = 0;
+ virtual void set_group_windows_setting(bool group) = 0;
virtual bool const &waiting_for_debugger() const = 0;
virtual bool seq_pressed() const = 0;
@@ -45,6 +55,10 @@ public:
virtual void show_all() = 0;
virtual void hide_all() = 0;
+
+ virtual void stagger_window(HWND window, int width, int height) = 0;
};
-#endif
+} // namespace osd::debugger::win
+
+#endif // MAME_DEBUGGER_WIN_DEBUGWIN_H
diff --git a/src/osd/modules/debugger/win/debugwininfo.cpp b/src/osd/modules/debugger/win/debugwininfo.cpp
index ac60b980439..f27f7933f08 100644
--- a/src/osd/modules/debugger/win/debugwininfo.cpp
+++ b/src/osd/modules/debugger/win/debugwininfo.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Aaron Giles, Vas Crabb
//============================================================
//
-// debugwininfo.c - Win32 debug window handling
+// debugwininfo.cpp - Win32 debug window handling
//
//============================================================
@@ -12,13 +12,21 @@
#include "debugviewinfo.h"
#include "debugger.h"
+#include "debug/debugcon.h"
#include "debug/debugcpu.h"
+
+#include "util/xmlfile.h"
+
#include "window.h"
#include "winutf8.h"
-
#include "winutil.h"
+
#include "modules/lib/osdobj_common.h"
+#include <cstring>
+
+
+namespace osd::debugger::win {
bool debugwin_info::s_window_class_registered = false;
@@ -36,9 +44,16 @@ debugwin_info::debugwin_info(debugger_windows_interface &debugger, bool is_main_
{
register_window_class();
- m_wnd = win_create_window_ex_utf8(DEBUG_WINDOW_STYLE_EX, "MAMEDebugWindow", title, DEBUG_WINDOW_STYLE,
- 0, 0, 100, 100, std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window(), create_standard_menubar(), GetModuleHandleUni(), this);
- if (m_wnd == nullptr)
+ m_wnd = win_create_window_ex_utf8(
+ DEBUG_WINDOW_STYLE_EX, "MAMEDebugWindow", title, DEBUG_WINDOW_STYLE,
+ 0, 0, 100, 100,
+ debugger.get_group_windows()
+ ? dynamic_cast<win_window_info &>(*osd_common_t::window_list().front()).platform_window()
+ : nullptr,
+ create_standard_menubar(),
+ GetModuleHandleUni(),
+ this);
+ if (!m_wnd)
return;
RECT work_bounds;
@@ -53,6 +68,12 @@ debugwin_info::~debugwin_info()
}
+void debugwin_info::redraw()
+{
+ RedrawWindow(m_wnd, nullptr, nullptr, RDW_INVALIDATE | RDW_ALLCHILDREN);
+}
+
+
void debugwin_info::destroy()
{
for (int curview = 0; curview < MAX_VIEWS; curview++)
@@ -250,6 +271,89 @@ bool debugwin_info::handle_key(WPARAM wparam, LPARAM lparam)
}
+void debugwin_info::save_configuration(util::xml::data_node &parentnode)
+{
+ util::xml::data_node *const node = parentnode.add_child(NODE_WINDOW, nullptr);
+ if (node)
+ save_configuration_to_node(*node);
+}
+
+
+void debugwin_info::restore_configuration_from_node(util::xml::data_node const &node)
+{
+ // get current size to use for defaults
+ RECT bounds;
+ POINT origin;
+ origin.x = 0;
+ origin.y = 0;
+ if (!GetClientRect(window(), &bounds) && ClientToScreen(window(), &origin))
+ return;
+
+ // get saved size and adjust for window chrome
+ RECT desired;
+ desired.left = node.get_attribute_int(ATTR_WINDOW_POSITION_X, origin.x);
+ desired.top = node.get_attribute_int(ATTR_WINDOW_POSITION_Y, origin.y);
+ desired.right = desired.left + node.get_attribute_int(ATTR_WINDOW_WIDTH, bounds.right);
+ desired.bottom = desired.top + node.get_attribute_int(ATTR_WINDOW_HEIGHT, bounds.bottom);
+ // TODO: sanity checks...
+ if (!AdjustWindowRectEx(&desired, DEBUG_WINDOW_STYLE, GetMenu(window()) ? TRUE : FALSE, DEBUG_WINDOW_STYLE_EX))
+ return;
+
+ // actually move the window
+ MoveWindow(
+ window(),
+ desired.left,
+ desired.top,
+ desired.right - desired.left,
+ desired.bottom - desired.top,
+ TRUE);
+
+ // restrict to one monitor and avoid toolbars
+ HMONITOR const nearest_monitor = MonitorFromWindow(window(), MONITOR_DEFAULTTONEAREST);
+ if (nearest_monitor)
+ {
+ MONITORINFO info;
+ std::memset(&info, 0, sizeof(info));
+ info.cbSize = sizeof(info);
+ if (GetMonitorInfo(nearest_monitor, &info))
+ {
+ if (desired.right > info.rcWork.right)
+ {
+ desired.left -= desired.right - info.rcWork.right;
+ desired.right = info.rcWork.right;
+ }
+ if (desired.bottom > info.rcWork.bottom)
+ {
+ desired.top -= desired.bottom - info.rcWork.bottom;
+ desired.bottom = info.rcWork.bottom;
+ }
+ if (desired.left < info.rcWork.left)
+ {
+ desired.right += info.rcWork.left - desired.left;
+ desired.left = info.rcWork.left;
+ }
+ if (desired.top < info.rcWork.top)
+ {
+ desired.bottom += info.rcWork.top - desired.top;
+ desired.top = info.rcWork.top;
+ }
+ desired.bottom = std::min(info.rcWork.bottom, desired.bottom);
+ desired.right = std::min(info.rcWork.right, desired.right);
+ MoveWindow(
+ window(),
+ desired.left,
+ desired.top,
+ desired.right - desired.left,
+ desired.bottom - desired.top,
+ TRUE);
+ }
+ }
+
+ // sort out contents
+ recompute_children();
+}
+
+
void debugwin_info::recompute_children()
{
if (m_views[0] != nullptr)
@@ -299,39 +403,40 @@ bool debugwin_info::handle_command(WPARAM wparam, LPARAM lparam)
case ID_RUN_AND_HIDE:
debugger().hide_all();
+ [[fallthrough]];
case ID_RUN:
- machine().debugger().cpu().get_visible_cpu()->debug()->go();
+ machine().debugger().console().get_visible_cpu()->debug()->go();
return true;
case ID_NEXT_CPU:
- machine().debugger().cpu().get_visible_cpu()->debug()->go_next_device();
+ machine().debugger().console().get_visible_cpu()->debug()->go_next_device();
return true;
case ID_RUN_VBLANK:
- machine().debugger().cpu().get_visible_cpu()->debug()->go_vblank();
+ machine().debugger().console().get_visible_cpu()->debug()->go_vblank();
return true;
case ID_RUN_IRQ:
- machine().debugger().cpu().get_visible_cpu()->debug()->go_interrupt();
+ machine().debugger().console().get_visible_cpu()->debug()->go_interrupt();
return true;
case ID_STEP:
- machine().debugger().cpu().get_visible_cpu()->debug()->single_step();
+ machine().debugger().console().get_visible_cpu()->debug()->single_step();
return true;
case ID_STEP_OVER:
- machine().debugger().cpu().get_visible_cpu()->debug()->single_step_over();
+ machine().debugger().console().get_visible_cpu()->debug()->single_step_over();
return true;
case ID_STEP_OUT:
- machine().debugger().cpu().get_visible_cpu()->debug()->single_step_out();
+ machine().debugger().console().get_visible_cpu()->debug()->single_step_out();
return true;
case ID_REWIND_STEP:
machine().rewind_step();
// clear all PC & memory tracks
- for (device_t &device : device_iterator(machine().root_device()))
+ for (device_t &device : device_enumerator(machine().root_device()))
{
device.debug()->track_pc_data_clear();
device.debug()->track_mem_data_clear();
@@ -348,7 +453,7 @@ bool debugwin_info::handle_command(WPARAM wparam, LPARAM lparam)
case ID_SOFT_RESET:
machine().schedule_soft_reset();
- machine().debugger().cpu().get_visible_cpu()->debug()->go();
+ machine().debugger().console().get_visible_cpu()->debug()->go();
return true;
case ID_EXIT:
@@ -390,6 +495,22 @@ void debugwin_info::draw_border(HDC dc, RECT &bounds)
}
+void debugwin_info::save_configuration_to_node(util::xml::data_node &node)
+{
+ RECT bounds;
+ POINT origin;
+ origin.x = 0;
+ origin.y = 0;
+ if (GetClientRect(window(), &bounds) && ClientToScreen(window(), &origin))
+ {
+ node.set_attribute_int(ATTR_WINDOW_POSITION_X, origin.x);
+ node.set_attribute_int(ATTR_WINDOW_POSITION_Y, origin.y);
+ node.set_attribute_int(ATTR_WINDOW_WIDTH, bounds.right);
+ node.set_attribute_int(ATTR_WINDOW_HEIGHT, bounds.bottom);
+ }
+}
+
+
void debugwin_info::draw_border(HDC dc, HWND child)
{
RECT bounds;
@@ -437,11 +558,10 @@ LRESULT debugwin_info::window_proc(UINT message, WPARAM wparam, LPARAM lparam)
// get min/max info: set the minimum window size
case WM_GETMINMAXINFO:
{
- MINMAXINFO *minmax = (MINMAXINFO *)lparam;
+ auto *minmax = (MINMAXINFO *)lparam;
minmax->ptMinTrackSize.x = m_minwidth;
minmax->ptMinTrackSize.y = m_minheight;
- minmax->ptMaxSize.x = minmax->ptMaxTrackSize.x = m_maxwidth;
- minmax->ptMaxSize.y = minmax->ptMaxTrackSize.y = m_maxheight;
+ // Leave default ptMaxSize and ptMaxTrackSize so maximum size is not restricted
break;
}
@@ -507,7 +627,7 @@ LRESULT debugwin_info::window_proc(UINT message, WPARAM wparam, LPARAM lparam)
if (m_is_main_console)
{
debugger().hide_all();
- machine().debugger().cpu().get_visible_cpu()->debug()->go();
+ machine().debugger().console().get_visible_cpu()->debug()->go();
}
else
{
@@ -575,14 +695,14 @@ LRESULT CALLBACK debugwin_info::static_window_proc(HWND wnd, UINT message, WPARA
{
// set the info pointer
CREATESTRUCT const *const createinfo = (CREATESTRUCT *)lparam;
- debugwin_info *const info = (debugwin_info *)createinfo->lpCreateParams;
+ auto *const info = (debugwin_info *)createinfo->lpCreateParams;
SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)createinfo->lpCreateParams);
if (info->m_handler)
SetWindowLongPtr(wnd, GWLP_WNDPROC, (LONG_PTR)info->m_handler);
return 0;
}
- debugwin_info *const info = (debugwin_info *)(uintptr_t)GetWindowLongPtr(wnd, GWLP_USERDATA);
+ auto *const info = (debugwin_info *)(uintptr_t)GetWindowLongPtr(wnd, GWLP_USERDATA);
if (info == nullptr)
return DefWindowProc(wnd, message, wparam, lparam);
@@ -618,3 +738,5 @@ void debugwin_info::register_window_class()
s_window_class_registered = true;
}
}
+
+} // namespace osd::debugger::win
diff --git a/src/osd/modules/debugger/win/debugwininfo.h b/src/osd/modules/debugger/win/debugwininfo.h
index 2090985d3f9..cf3587253f6 100644
--- a/src/osd/modules/debugger/win/debugwininfo.h
+++ b/src/osd/modules/debugger/win/debugwininfo.h
@@ -5,20 +5,21 @@
// debugwininfo.h - Win32 debug window handling
//
//============================================================
+#ifndef MAME_DEBUGGER_WIN_DEBUGWININFO_H
+#define MAME_DEBUGGER_WIN_DEBUGWININFO_H
-#ifndef __DEBUG_WIN_DEBUG_WIN_INFO_H__
-#define __DEBUG_WIN_DEBUG_WIN_INFO_H__
+#pragma once
#include "debugwin.h"
#include "debugbaseinfo.h"
+namespace osd::debugger::win {
class debugwin_info : protected debugbase_info
{
public:
- debugwin_info(debugger_windows_interface &debugger, bool is_main_console, LPCSTR title, WNDPROC handler);
virtual ~debugwin_info();
bool is_valid() const { return m_wnd != nullptr; }
@@ -40,6 +41,7 @@ public:
void show() const { smart_show_window(m_wnd, true); }
void hide() const { smart_show_window(m_wnd, false); }
void set_foreground() const { SetForegroundWindow(m_wnd); }
+ void redraw();
void destroy();
virtual bool set_default_focus();
@@ -49,6 +51,9 @@ public:
virtual bool handle_key(WPARAM wparam, LPARAM lparam);
+ void save_configuration(util::xml::data_node &parentnode);
+ virtual void restore_configuration_from_node(util::xml::data_node const &node);
+
protected:
static DWORD const DEBUG_WINDOW_STYLE = (WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN) & (~WS_MINIMIZEBOX & ~WS_MAXIMIZEBOX);
static DWORD const DEBUG_WINDOW_STYLE_EX = 0;
@@ -75,13 +80,20 @@ protected:
ID_SOFT_RESET,
ID_EXIT,
- ID_1_BYTE_CHUNKS,
- ID_2_BYTE_CHUNKS,
- ID_4_BYTE_CHUNKS,
- ID_8_BYTE_CHUNKS,
- ID_FLOATING_POINT_32BIT,
- ID_FLOATING_POINT_64BIT,
- ID_FLOATING_POINT_80BIT,
+ ID_1_BYTE_CHUNKS_HEX,
+ ID_2_BYTE_CHUNKS_HEX,
+ ID_4_BYTE_CHUNKS_HEX,
+ ID_8_BYTE_CHUNKS_HEX,
+ ID_1_BYTE_CHUNKS_OCT,
+ ID_2_BYTE_CHUNKS_OCT,
+ ID_4_BYTE_CHUNKS_OCT,
+ ID_8_BYTE_CHUNKS_OCT,
+ ID_FLOAT_32BIT,
+ ID_FLOAT_64BIT,
+ ID_FLOAT_80BIT,
+ ID_HEX_ADDRESSES,
+ ID_DEC_ADDRESSES,
+ ID_OCT_ADDRESSES,
ID_LOGICAL_ADDRESSES,
ID_PHYSICAL_ADDRESSES,
ID_REVERSE_VIEW,
@@ -97,12 +109,21 @@ protected:
ID_SHOW_BREAKPOINTS,
ID_SHOW_WATCHPOINTS,
+ ID_SHOW_REGISTERPOINTS,
+ ID_SHOW_EXCEPTIONPOINTS,
ID_CLEAR_LOG,
+ ID_SAVE_WINDOWS,
+ ID_GROUP_WINDOWS,
+ ID_LIGHT_BACKGROUND,
+ ID_DARK_BACKGROUND,
+
ID_DEVICE_OPTIONS // always keep this at the end
};
+ debugwin_info(debugger_windows_interface &debugger, bool is_main_console, LPCSTR title, WNDPROC handler);
+
bool is_main_console() const { return m_is_main_console; }
HWND window() const { return m_wnd; }
uint32_t minwidth() const { return m_minwidth; }
@@ -117,6 +138,8 @@ protected:
void draw_border(HDC dc, RECT &bounds);
void draw_border(HDC dc, HWND child);
+ virtual void save_configuration_to_node(util::xml::data_node &node);
+
std::unique_ptr<debugview_info> m_views[MAX_VIEWS];
private:
@@ -133,12 +156,14 @@ private:
HWND m_wnd;
WNDPROC const m_handler;
- uint32_t m_minwidth, m_maxwidth;
- uint32_t m_minheight, m_maxheight;
+ uint32_t m_minwidth, m_maxwidth;
+ uint32_t m_minheight, m_maxheight;
- uint16_t m_ignore_char_lparam;
+ uint16_t m_ignore_char_lparam;
static bool s_window_class_registered;
};
-#endif
+} // namespace osd::debugger::win
+
+#endif // MAME_DEBUGGER_WIN_DEBUGWININFO_H
diff --git a/src/osd/modules/debugger/win/disasmbasewininfo.cpp b/src/osd/modules/debugger/win/disasmbasewininfo.cpp
index c466e059f23..48771c4f133 100644
--- a/src/osd/modules/debugger/win/disasmbasewininfo.cpp
+++ b/src/osd/modules/debugger/win/disasmbasewininfo.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Aaron Giles, Vas Crabb
//============================================================
//
-// disasmbasewininfo.c - Win32 debug window handling
+// disasmbasewininfo.cpp - Win32 debug window handling
//
//============================================================
@@ -15,18 +15,21 @@
#include "debugger.h"
#include "debug/debugcon.h"
#include "debug/debugcpu.h"
+#include "debug/points.h"
//#include "winutf8.h"
+namespace osd::debugger::win {
+
disasmbasewin_info::disasmbasewin_info(debugger_windows_interface &debugger, bool is_main_console, LPCSTR title, WNDPROC handler) :
editwin_info(debugger, is_main_console, title, handler)
{
if (!window())
return;
- m_views[0].reset(global_alloc(disasmview_info(debugger, *this, window())));
- if ((m_views[0] == nullptr) || !m_views[0]->is_valid())
+ m_views[0].reset(new disasmview_info(debugger, *this, window()));
+ if (!m_views[0] || !m_views[0]->is_valid())
{
m_views[0].reset();
return;
@@ -105,7 +108,7 @@ void disasmbasewin_info::update_menu()
{
editwin_info::update_menu();
- disasmview_info *const dasmview = downcast<disasmview_info *>(m_views[0].get());
+ auto *const dasmview = downcast<disasmview_info *>(m_views[0].get());
HMENU const menu = GetMenu(window());
bool const disasm_cursor_visible = dasmview->cursor_visible();
@@ -115,9 +118,9 @@ void disasmbasewin_info::update_menu()
device_debug *const debug = dasmview->source_device()->debug();
// first find an existing breakpoint at this address
- const device_debug::breakpoint *bp = debug->breakpoint_find(address);
+ const debug_breakpoint *bp = debug->breakpoint_find(address);
- if (bp == nullptr)
+ if (!bp)
{
ModifyMenu(menu, ID_TOGGLE_BREAKPOINT, MF_BYCOMMAND, ID_TOGGLE_BREAKPOINT, TEXT("Set breakpoint at cursor\tF9"));
ModifyMenu(menu, ID_DISABLE_BREAKPOINT, MF_BYCOMMAND, ID_DISABLE_BREAKPOINT, TEXT("Disable breakpoint at cursor\tShift+F9"));
@@ -130,7 +133,7 @@ void disasmbasewin_info::update_menu()
else
ModifyMenu(menu, ID_DISABLE_BREAKPOINT, MF_BYCOMMAND, ID_DISABLE_BREAKPOINT, TEXT("Enable breakpoint at cursor\tShift+F9"));
}
- bool const available = (bp != nullptr) && (!is_main_console() || dasmview->source_is_visible_cpu());
+ bool const available = bp && (!is_main_console() || dasmview->source_is_visible_cpu());
EnableMenuItem(menu, ID_DISABLE_BREAKPOINT, MF_BYCOMMAND | (available ? MF_ENABLED : MF_GRAYED));
}
else
@@ -151,7 +154,7 @@ void disasmbasewin_info::update_menu()
bool disasmbasewin_info::handle_command(WPARAM wparam, LPARAM lparam)
{
- disasmview_info *const dasmview = downcast<disasmview_info *>(m_views[0].get());
+ auto *const dasmview = downcast<disasmview_info *>(m_views[0].get());
switch (HIWORD(wparam))
{
@@ -166,14 +169,14 @@ bool disasmbasewin_info::handle_command(WPARAM wparam, LPARAM lparam)
device_debug *const debug = dasmview->source_device()->debug();
// first find an existing breakpoint at this address
- const device_debug::breakpoint *bp = debug->breakpoint_find(address);
+ const debug_breakpoint *bp = debug->breakpoint_find(address);
// if it doesn't exist, add a new one
if (!is_main_console())
{
if (bp == nullptr)
{
- int32_t bpindex = debug->breakpoint_set(address, nullptr, nullptr);
+ int32_t bpindex = debug->breakpoint_set(address);
machine().debugger().console().printf("Breakpoint %X set\n", bpindex);
}
else
@@ -192,7 +195,7 @@ bool disasmbasewin_info::handle_command(WPARAM wparam, LPARAM lparam)
command = string_format("bpset 0x%X", address);
else
command = string_format("bpclear 0x%X", bp->index());
- machine().debugger().console().execute_command(command.c_str(), true);
+ machine().debugger().console().execute_command(command, true);
}
}
return true;
@@ -204,7 +207,7 @@ bool disasmbasewin_info::handle_command(WPARAM wparam, LPARAM lparam)
device_debug *const debug = dasmview->source_device()->debug();
// first find an existing breakpoint at this address
- const device_debug::breakpoint *bp = debug->breakpoint_find(address);
+ const debug_breakpoint *bp = debug->breakpoint_find(address);
// if it doesn't exist, add a new one
if (bp != nullptr)
@@ -220,7 +223,7 @@ bool disasmbasewin_info::handle_command(WPARAM wparam, LPARAM lparam)
{
std::string command;
command = string_format(bp->enabled() ? "bpdisable 0x%X" : "bpenable 0x%X", (uint32_t)bp->index());
- machine().debugger().console().execute_command(command.c_str(), true);
+ machine().debugger().console().execute_command(command, true);
}
}
}
@@ -234,7 +237,7 @@ bool disasmbasewin_info::handle_command(WPARAM wparam, LPARAM lparam)
{
std::string command;
command = string_format("go 0x%X", address);
- machine().debugger().console().execute_command(command.c_str(), true);
+ machine().debugger().console().execute_command(command, true);
}
else
{
@@ -262,3 +265,19 @@ bool disasmbasewin_info::handle_command(WPARAM wparam, LPARAM lparam)
}
return editwin_info::handle_command(wparam, lparam);
}
+
+
+void disasmbasewin_info::restore_configuration_from_node(util::xml::data_node const &node)
+{
+ editwin_info::restore_configuration_from_node(node);
+ m_views[0]->restore_configuration_from_node(node);
+}
+
+
+void disasmbasewin_info::save_configuration_to_node(util::xml::data_node &node)
+{
+ editwin_info::save_configuration_to_node(node);
+ m_views[0]->save_configuration_to_node(node);
+}
+
+} // namespace osd::debugger::win
diff --git a/src/osd/modules/debugger/win/disasmbasewininfo.h b/src/osd/modules/debugger/win/disasmbasewininfo.h
index 26cd481b7f6..1ef8245b5a0 100644
--- a/src/osd/modules/debugger/win/disasmbasewininfo.h
+++ b/src/osd/modules/debugger/win/disasmbasewininfo.h
@@ -5,15 +5,18 @@
// disasmbasewininfo.h - Win32 debug window handling
//
//============================================================
+#ifndef MAME_DEBUGGER_WIN_DISASMBASEWININFO_H
+#define MAME_DEBUGGER_WIN_DISASMBASEWININFO_H
-#ifndef __DEBUG_WIN_DISASM_BASE_WIN_INFO_H__
-#define __DEBUG_WIN_DISASM_BASE_WIN_INFO_H__
+#pragma once
#include "debugwin.h"
#include "editwininfo.h"
+namespace osd::debugger::win {
+
class disasmbasewin_info : public editwin_info
{
public:
@@ -21,10 +24,14 @@ public:
virtual ~disasmbasewin_info();
virtual bool handle_key(WPARAM wparam, LPARAM lparam) override;
+ virtual void restore_configuration_from_node(util::xml::data_node const &node) override;
protected:
virtual void update_menu() override;
virtual bool handle_command(WPARAM wparam, LPARAM lparam) override;
+ virtual void save_configuration_to_node(util::xml::data_node &node) override;
};
-#endif
+} // namespace osd::debugger::win
+
+#endif // MAME_DEBUGGER_WIN_DISASMBASEWININFO_H
diff --git a/src/osd/modules/debugger/win/disasmviewinfo.cpp b/src/osd/modules/debugger/win/disasmviewinfo.cpp
index 8884bee5195..3cf9dbd70ff 100644
--- a/src/osd/modules/debugger/win/disasmviewinfo.cpp
+++ b/src/osd/modules/debugger/win/disasmviewinfo.cpp
@@ -2,13 +2,17 @@
// copyright-holders:Aaron Giles, Vas Crabb
//============================================================
//
-// disasmviewinfo.c - Win32 debug window handling
+// disasmviewinfo.cpp - Win32 debug window handling
//
//============================================================
#include "emu.h"
#include "disasmviewinfo.h"
+#include "util/xmlfile.h"
+
+
+namespace osd::debugger::win {
disasmview_info::disasmview_info(debugger_windows_interface &debugger, debugwin_info &owner, HWND parent) :
debugview_info(debugger, owner, parent, DVT_DISASSEMBLY)
@@ -21,6 +25,12 @@ disasmview_info::~disasmview_info()
}
+char const *disasmview_info::expression() const
+{
+ return view<debug_view_disasm>()->expression();
+}
+
+
disasm_right_column disasmview_info::right_column() const
{
return view<debug_view_disasm>()->right_column();
@@ -43,3 +53,23 @@ void disasmview_info::set_right_column(disasm_right_column contents)
{
view<debug_view_disasm>()->set_right_column(contents);
}
+
+
+void disasmview_info::restore_configuration_from_node(util::xml::data_node const &node)
+{
+ debug_view_disasm &dasmview(*view<debug_view_disasm>());
+ dasmview.set_right_column(disasm_right_column(node.get_attribute_int(ATTR_WINDOW_DISASSEMBLY_RIGHT_COLUMN, dasmview.right_column())));
+
+ debugview_info::restore_configuration_from_node(node);
+}
+
+
+void disasmview_info::save_configuration_to_node(util::xml::data_node &node)
+{
+ debugview_info::save_configuration_to_node(node);
+
+ debug_view_disasm &dasmview(*view<debug_view_disasm>());
+ node.set_attribute_int(ATTR_WINDOW_DISASSEMBLY_RIGHT_COLUMN, dasmview.right_column());
+}
+
+} // namespace osd::debugger::win
diff --git a/src/osd/modules/debugger/win/disasmviewinfo.h b/src/osd/modules/debugger/win/disasmviewinfo.h
index d1e7090ef2f..809f92b0c14 100644
--- a/src/osd/modules/debugger/win/disasmviewinfo.h
+++ b/src/osd/modules/debugger/win/disasmviewinfo.h
@@ -5,9 +5,10 @@
// disasmviewinfo.h - Win32 debug window handling
//
//============================================================
+#ifndef MAME_DEBUGGER_WIN_DISASMVIEWINFO_H
+#define MAME_DEBUGGER_WIN_DISASMVIEWINFO_H
-#ifndef __DEBUG_WIN_DISASM_VIEW_INFO_H__
-#define __DEBUG_WIN_DISASM_VIEW_INFO_H__
+#pragma once
#include "debugwin.h"
@@ -16,17 +17,25 @@
#include "debug/dvdisasm.h"
+namespace osd::debugger::win {
+
class disasmview_info : public debugview_info
{
public:
disasmview_info(debugger_windows_interface &debugger, debugwin_info &owner, HWND parent);
virtual ~disasmview_info();
+ char const *expression() const;
disasm_right_column right_column() const;
offs_t selected_address() const;
void set_expression(const std::string &expression);
void set_right_column(disasm_right_column contents);
+
+ virtual void restore_configuration_from_node(util::xml::data_node const &node) override;
+ virtual void save_configuration_to_node(util::xml::data_node &node) override;
};
-#endif
+} // namespace osd::debugger::win
+
+#endif // MAME_DEBUGGER_WIN_DISASMVIEWINFO_H
diff --git a/src/osd/modules/debugger/win/disasmwininfo.cpp b/src/osd/modules/debugger/win/disasmwininfo.cpp
index b94eadbba03..6b38609ace8 100644
--- a/src/osd/modules/debugger/win/disasmwininfo.cpp
+++ b/src/osd/modules/debugger/win/disasmwininfo.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Aaron Giles, Vas Crabb
//============================================================
//
-// disasmwininfo.c - Win32 debug window handling
+// disasmwininfo.cpp - Win32 debug window handling
//
//============================================================
@@ -12,9 +12,14 @@
#include "debugviewinfo.h"
#include "disasmviewinfo.h"
#include "uimetrics.h"
+
+#include "util/xmlfile.h"
+
#include "winutf8.h"
+namespace osd::debugger::win {
+
disasmwin_info::disasmwin_info(debugger_windows_interface &debugger) :
disasmbasewin_info(debugger, false, "Disassembly", nullptr),
m_combownd(nullptr)
@@ -34,11 +39,11 @@ disasmwin_info::disasmwin_info(debugger_windows_interface &debugger) :
update_caption();
// recompute the children once to get the maxwidth
- disasmwin_info::recompute_children();
+ recompute_children();
// position the window and recompute children again
- SetWindowPos(window(), HWND_TOP, 100, 100, maxwidth(), 200, SWP_SHOWWINDOW);
- disasmwin_info::recompute_children();
+ debugger.stagger_window(window(), maxwidth(), 200);
+ recompute_children();
// mark the edit box as the default focus and set it
editwin_info::set_default_focus();
@@ -143,3 +148,34 @@ void disasmwin_info::update_caption()
{
win_set_window_text_utf8(window(), std::string("Disassembly: ").append(m_views[0]->source_name()).c_str());
}
+
+
+void disasmwin_info::restore_configuration_from_node(util::xml::data_node const &node)
+{
+ m_views[0]->set_source_index(node.get_attribute_int(ATTR_WINDOW_DISASSEMBLY_CPU, m_views[0]->source_index()));
+ int const cursource = m_views[0]->source_index();
+ if (0 <= cursource)
+ SendMessage(m_combownd, CB_SETCURSEL, cursource, 0);
+ update_caption();
+
+ util::xml::data_node const *const expr = node.get_child(NODE_WINDOW_EXPRESSION);
+ if (expr && expr->get_value())
+ {
+ set_editwnd_text(expr->get_value());
+ process_string(expr->get_value());
+ }
+
+ disasmbasewin_info::restore_configuration_from_node(node);
+}
+
+
+void disasmwin_info::save_configuration_to_node(util::xml::data_node &node)
+{
+ disasmbasewin_info::save_configuration_to_node(node);
+
+ node.set_attribute_int(ATTR_WINDOW_TYPE, WINDOW_TYPE_DISASSEMBLY_VIEWER);
+ node.set_attribute_int(ATTR_WINDOW_DISASSEMBLY_CPU, m_views[0]->source_index());
+ node.add_child(NODE_WINDOW_EXPRESSION, downcast<disasmview_info *>(m_views[0].get())->expression());
+}
+
+} // namespace osd::debugger::win
diff --git a/src/osd/modules/debugger/win/disasmwininfo.h b/src/osd/modules/debugger/win/disasmwininfo.h
index 34e8275f2f9..e5a5ceaaa0e 100644
--- a/src/osd/modules/debugger/win/disasmwininfo.h
+++ b/src/osd/modules/debugger/win/disasmwininfo.h
@@ -5,25 +5,31 @@
// disasmwininfo.h - Win32 debug window handling
//
//============================================================
+#ifndef MAME_DEBUGGER_WIN_DISASMWININFO_H
+#define MAME_DEBUGGER_WIN_DISASMWININFO_H
-#ifndef __DEBUG_WIN_DISASM_WIN_INFO_H__
-#define __DEBUG_WIN_DISASM_WIN_INFO_H__
+#pragma once
#include "debugwin.h"
#include "disasmbasewininfo.h"
+namespace osd::debugger::win {
+
class disasmwin_info : public disasmbasewin_info
{
public:
disasmwin_info(debugger_windows_interface &debugger);
virtual ~disasmwin_info();
+ virtual void restore_configuration_from_node(util::xml::data_node const &node) override;
+
protected:
virtual void recompute_children() override;
virtual bool handle_command(WPARAM wparam, LPARAM lparam) override;
virtual void draw_contents(HDC dc) override;
+ virtual void save_configuration_to_node(util::xml::data_node &node) override;
private:
virtual void process_string(const std::string &string) override;
@@ -33,4 +39,6 @@ private:
HWND m_combownd;
};
-#endif
+} // namespace osd::debugger::win
+
+#endif // MAME_DEBUGGER_WIN_DISASMWININFO_H
diff --git a/src/osd/modules/debugger/win/editwininfo.cpp b/src/osd/modules/debugger/win/editwininfo.cpp
index af3dd1bf66e..c62d2b1f4f7 100644
--- a/src/osd/modules/debugger/win/editwininfo.cpp
+++ b/src/osd/modules/debugger/win/editwininfo.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Aaron Giles, Vas Crabb
//============================================================
//
-// editwininfo.c - Win32 debug window handling
+// editwininfo.cpp - Win32 debug window handling
//
//============================================================
@@ -12,18 +12,22 @@
#include "debugviewinfo.h"
#include "uimetrics.h"
+#include "xmlfile.h"
+
#include "strconv.h"
#include "winutil.h"
+namespace osd::debugger::win {
+
namespace {
constexpr DWORD EDIT_BOX_STYLE = WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL;
constexpr DWORD EDIT_BOX_STYLE_EX = 0;
constexpr int MAX_EDIT_STRING = 256;
-constexpr int HISTORY_LENGTH = 20;
+constexpr int HISTORY_LENGTH = 100;
} // anonymous namespace
@@ -34,7 +38,7 @@ editwin_info::editwin_info(debugger_windows_interface &debugger, bool is_main_co
m_edit_defstr(),
m_original_editproc(nullptr),
m_history(),
- m_last_history(0)
+ m_last_history(-1)
{
if (window() == nullptr)
return;
@@ -105,6 +109,43 @@ void editwin_info::draw_contents(HDC dc)
}
+void editwin_info::restore_configuration_from_node(util::xml::data_node const &node)
+{
+ m_history.clear();
+ util::xml::data_node const *const hist = node.get_child(NODE_WINDOW_HISTORY);
+ if (hist)
+ {
+ util::xml::data_node const *item = hist->get_child(NODE_HISTORY_ITEM);
+ while (item)
+ {
+ if (item->get_value() && *item->get_value())
+ {
+ while (m_history.size() >= HISTORY_LENGTH)
+ m_history.pop_back();
+ m_history.emplace_front(osd::text::to_tstring(item->get_value()));
+ }
+ item = item->get_next_sibling(NODE_HISTORY_ITEM);
+ }
+ }
+ m_last_history = -1;
+
+ debugwin_info::restore_configuration_from_node(node);
+}
+
+
+void editwin_info::save_configuration_to_node(util::xml::data_node &node)
+{
+ debugwin_info::save_configuration_to_node(node);
+
+ util::xml::data_node *const hist = node.add_child(NODE_WINDOW_HISTORY, nullptr);
+ if (hist)
+ {
+ for (auto it = m_history.crbegin(); m_history.crend() != it; ++it)
+ hist->add_child(NODE_HISTORY_ITEM, osd::text::from_tstring(*it).c_str());
+ }
+}
+
+
LRESULT editwin_info::edit_proc(UINT message, WPARAM wparam, LPARAM lparam)
{
// handle a few messages
@@ -114,7 +155,7 @@ LRESULT editwin_info::edit_proc(UINT message, WPARAM wparam, LPARAM lparam)
case WM_SYSKEYDOWN:
if (wparam != VK_F10)
return CallWindowProc(m_original_editproc, m_editwnd, message, wparam, lparam);
- // (fall through)
+ [[fallthrough]];
case WM_KEYDOWN:
switch (wparam)
{
@@ -185,7 +226,7 @@ LRESULT editwin_info::edit_proc(UINT message, WPARAM wparam, LPARAM lparam)
case 13: // carriage return
{
// fetch the text
- SendMessage(m_editwnd, WM_GETTEXT, WPARAM(ARRAY_LENGTH(buffer)), LPARAM(buffer));
+ SendMessage(m_editwnd, WM_GETTEXT, WPARAM(std::size(buffer)), LPARAM(buffer));
// add to the history if it's not a repeat of the last one
if (buffer[0] && (m_history.empty() || _tcscmp(buffer, m_history[0].c_str())))
@@ -194,12 +235,12 @@ LRESULT editwin_info::edit_proc(UINT message, WPARAM wparam, LPARAM lparam)
m_history.pop_back();
m_history.emplace_front(buffer);
}
- m_last_history = m_history.size() - 1;
+ m_last_history = -1;
// process
{
auto utf8_buffer = osd::text::from_tstring(buffer);
- process_string(utf8_buffer.c_str());
+ process_string(utf8_buffer);
}
}
break;
@@ -237,7 +278,9 @@ LRESULT editwin_info::edit_proc(UINT message, WPARAM wparam, LPARAM lparam)
LRESULT CALLBACK editwin_info::static_edit_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam)
{
- editwin_info *const info = (editwin_info *)uintptr_t(GetWindowLongPtr(wnd, GWLP_USERDATA));
+ auto *const info = (editwin_info *)uintptr_t(GetWindowLongPtr(wnd, GWLP_USERDATA));
assert(info->m_editwnd == wnd);
return info->edit_proc(message, wparam, lparam);
}
+
+} // namespace osd::debugger::win
diff --git a/src/osd/modules/debugger/win/editwininfo.h b/src/osd/modules/debugger/win/editwininfo.h
index 1aaee55f1e9..e2c0ce3c4b8 100644
--- a/src/osd/modules/debugger/win/editwininfo.h
+++ b/src/osd/modules/debugger/win/editwininfo.h
@@ -5,9 +5,10 @@
// editwininfo.h - Win32 debug window handling
//
//============================================================
+#ifndef MAME_DEBUGGER_WIN_EDITWININFO_H
+#define MAME_DEBUGGER_WIN_EDITWININFO_H
-#ifndef MAME_DEBUG_WIN_EDIT_WIN_INFO_H
-#define MAME_DEBUG_WIN_EDIT_WIN_INFO_H
+#pragma once
#include "debugwin.h"
@@ -17,6 +18,8 @@
#include <string>
+namespace osd::debugger::win {
+
class editwin_info : public debugwin_info
{
public:
@@ -27,6 +30,8 @@ public:
virtual bool set_default_focus() override;
+ virtual void restore_configuration_from_node(util::xml::data_node const &node) override;
+
protected:
constexpr static DWORD COMBO_BOX_STYLE = WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL;
constexpr static DWORD COMBO_BOX_STYLE_EX = 0;
@@ -38,6 +43,8 @@ protected:
virtual void draw_contents(HDC dc) override;
+ virtual void save_configuration_to_node(util::xml::data_node &node) override;
+
private:
typedef std::deque<std::basic_string<TCHAR> > history_deque;
@@ -54,4 +61,6 @@ private:
int m_last_history;
};
-#endif
+} // namespace osd::debugger::win
+
+#endif // MAME_DEBUGGER_WIN_EDITWININFO_H
diff --git a/src/osd/modules/debugger/win/logviewinfo.cpp b/src/osd/modules/debugger/win/logviewinfo.cpp
index affd4acd17a..c6bbdfacb88 100644
--- a/src/osd/modules/debugger/win/logviewinfo.cpp
+++ b/src/osd/modules/debugger/win/logviewinfo.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Samuele Zannoli
//============================================================
//
-// logviewinfo.c - Win32 debug log window handling
+// logviewinfo.cpp - Win32 debug log window handling
//
//============================================================
@@ -12,6 +12,8 @@
#include "debug/dvtext.h"
+namespace osd::debugger::win {
+
logview_info::logview_info(debugger_windows_interface &debugger, debugwin_info &owner, HWND parent) :
debugview_info(debugger, owner, parent, DVT_LOG)
{
@@ -27,3 +29,5 @@ void logview_info::clear()
{
view<debug_view_log>()->clear();
}
+
+} // namespace osd::debugger::win
diff --git a/src/osd/modules/debugger/win/logviewinfo.h b/src/osd/modules/debugger/win/logviewinfo.h
index da598038864..15de2a3a095 100644
--- a/src/osd/modules/debugger/win/logviewinfo.h
+++ b/src/osd/modules/debugger/win/logviewinfo.h
@@ -5,15 +5,18 @@
// logviewinfo.h - Win32 debug log window handling
//
//============================================================
+#ifndef MAME_DEBUGGER_WIN_LOGVIEWINFO_H
+#define MAME_DEBUGGER_WIN_LOGVIEWINFO_H
-#ifndef __DEBUG_WIN_LOG_VIEW_INFO_H__
-#define __DEBUG_WIN_LOG_VIEW_INFO_H__
+#pragma once
#include "debugwin.h"
#include "debugviewinfo.h"
+namespace osd::debugger::win {
+
class logview_info : public debugview_info
{
public:
@@ -23,4 +26,6 @@ public:
void clear();
};
-#endif
+} // namespace osd::debugger::win
+
+#endif // MAME_DEBUGGER_WIN_LOGVIEWINFO_H
diff --git a/src/osd/modules/debugger/win/logwininfo.cpp b/src/osd/modules/debugger/win/logwininfo.cpp
index 6d2cd59b554..40515906bb1 100644
--- a/src/osd/modules/debugger/win/logwininfo.cpp
+++ b/src/osd/modules/debugger/win/logwininfo.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Aaron Giles, Vas Crabb
//============================================================
//
-// logwininfo.c - Win32 debug window handling
+// logwininfo.cpp - Win32 debug window handling
//
//============================================================
@@ -12,6 +12,10 @@
#include "debugviewinfo.h"
#include "logviewinfo.h"
+#include "util/xmlfile.h"
+
+
+namespace osd::debugger::win {
logwin_info::logwin_info(debugger_windows_interface &debugger) :
debugwin_info(debugger, false, std::string("Errorlog: ").append(debugger.machine().system().type.fullname()).append(" [").append(debugger.machine().system().name).append("]").c_str(), nullptr)
@@ -19,7 +23,7 @@ logwin_info::logwin_info(debugger_windows_interface &debugger) :
if (!window())
return;
- m_views[0].reset(global_alloc(logview_info(debugger, *this, window())));
+ m_views[0].reset(new logview_info(debugger, *this, window()));
if ((m_views[0] == nullptr) || !m_views[0]->is_valid())
{
m_views[0].reset();
@@ -41,11 +45,9 @@ logwin_info::logwin_info(debugger_windows_interface &debugger) :
// clamp the min/max size
set_maxwidth(bounds.right - bounds.left);
- // position the window at the bottom-right
- SetWindowPos(window(), HWND_TOP, 100, 100, bounds.right - bounds.left, bounds.bottom - bounds.top, SWP_SHOWWINDOW);
-
- // recompute the children
- debugwin_info::recompute_children();
+ // position the window and recompute children
+ debugger.stagger_window(window(), bounds.right - bounds.left, bounds.bottom - bounds.top);
+ recompute_children();
}
@@ -63,3 +65,12 @@ bool logwin_info::handle_command(WPARAM wparam, LPARAM lparam)
}
return debugwin_info::handle_command(wparam, lparam);
}
+
+
+void logwin_info::save_configuration_to_node(util::xml::data_node &node)
+{
+ debugwin_info::save_configuration_to_node(node);
+ node.set_attribute_int(ATTR_WINDOW_TYPE, WINDOW_TYPE_ERROR_LOG_VIEWER);
+}
+
+} // namespace osd::debugger::win
diff --git a/src/osd/modules/debugger/win/logwininfo.h b/src/osd/modules/debugger/win/logwininfo.h
index a816b6f3da3..4e822f1b534 100644
--- a/src/osd/modules/debugger/win/logwininfo.h
+++ b/src/osd/modules/debugger/win/logwininfo.h
@@ -5,15 +5,18 @@
// logwininfo.h - Win32 debug window handling
//
//============================================================
+#ifndef MAME_DEBUGGER_WIN_LOGWININFO_H
+#define MAME_DEBUGGER_WIN_LOGWININFO_H
-#ifndef __DEBUG_WIN_LOG_WIN_INFO_H__
-#define __DEBUG_WIN_LOG_WIN_INFO_H__
+#pragma once
#include "debugwin.h"
#include "debugwininfo.h"
+namespace osd::debugger::win {
+
class logwin_info : public debugwin_info
{
public:
@@ -22,6 +25,9 @@ public:
protected:
virtual bool handle_command(WPARAM wparam, LPARAM lparam) override;
+ virtual void save_configuration_to_node(util::xml::data_node &node) override;
};
-#endif
+} // namespace osd::debugger::win
+
+#endif // MAME_DEBUGGER_WIN_LOGWININFO_H
diff --git a/src/osd/modules/debugger/win/memoryviewinfo.cpp b/src/osd/modules/debugger/win/memoryviewinfo.cpp
index 423679f26a9..90e23a557a9 100644
--- a/src/osd/modules/debugger/win/memoryviewinfo.cpp
+++ b/src/osd/modules/debugger/win/memoryviewinfo.cpp
@@ -2,15 +2,19 @@
// copyright-holders:Aaron Giles, Vas Crabb
//============================================================
//
-// memoryviewinfo.c - Win32 debug window handling
+// memoryviewinfo.cpp - Win32 debug window handling
//
//============================================================
#include "emu.h"
#include "memoryviewinfo.h"
-#include "debug/dvmemory.h"
+#include "util/xmlfile.h"
+#include "strconv.h"
+
+
+namespace osd::debugger::win {
memoryview_info::memoryview_info(debugger_windows_interface &debugger, debugwin_info &owner, HWND parent) :
debugview_info(debugger, owner, parent, DVT_MEMORY)
@@ -23,7 +27,13 @@ memoryview_info::~memoryview_info()
}
-uint8_t memoryview_info::data_format() const
+char const *memoryview_info::expression() const
+{
+ return view<debug_view_memory>()->expression();
+}
+
+
+debug_view_memory::data_format memoryview_info::data_format() const
{
return view<debug_view_memory>()->get_data_format();
}
@@ -46,13 +56,18 @@ bool memoryview_info::physical() const
return view<debug_view_memory>()->physical();
}
+int memoryview_info::address_radix() const
+{
+ return view<debug_view_memory>()->address_radix();
+}
+
void memoryview_info::set_expression(const std::string &string)
{
view<debug_view_memory>()->set_expression(string);
}
-void memoryview_info::set_data_format(uint8_t dataformat)
+void memoryview_info::set_data_format(debug_view_memory::data_format dataformat)
{
view<debug_view_memory>()->set_data_format(dataformat);
}
@@ -71,3 +86,123 @@ void memoryview_info::set_physical(bool physical)
{
view<debug_view_memory>()->set_physical(physical);
}
+
+void memoryview_info::set_address_radix(int radix)
+{
+ view<debug_view_memory>()->set_address_radix(radix);
+}
+
+
+void memoryview_info::restore_configuration_from_node(util::xml::data_node const &node)
+{
+ debug_view_memory &memview(*view<debug_view_memory>());
+ memview.set_reverse(0 != node.get_attribute_int(ATTR_WINDOW_MEMORY_REVERSE_COLUMNS, memview.reverse() ? 1 : 0));
+ memview.set_physical(0 != node.get_attribute_int(ATTR_WINDOW_MEMORY_ADDRESS_MODE, memview.physical() ? 1 : 0));
+ memview.set_address_radix(node.get_attribute_int(ATTR_WINDOW_MEMORY_ADDRESS_RADIX, memview.address_radix()));
+ memview.set_data_format(debug_view_memory::data_format(node.get_attribute_int(ATTR_WINDOW_MEMORY_DATA_FORMAT, int(memview.get_data_format()))));
+ memview.set_chunks_per_row(node.get_attribute_int(ATTR_WINDOW_MEMORY_ROW_CHUNKS, memview.chunks_per_row()));
+
+ debugview_info::restore_configuration_from_node(node);
+}
+
+
+void memoryview_info::save_configuration_to_node(util::xml::data_node &node)
+{
+ debugview_info::save_configuration_to_node(node);
+
+ debug_view_memory &memview(*view<debug_view_memory>());
+ node.set_attribute_int(ATTR_WINDOW_MEMORY_REVERSE_COLUMNS, memview.reverse() ? 1 : 0);
+ node.set_attribute_int(ATTR_WINDOW_MEMORY_ADDRESS_MODE, memview.physical() ? 1 : 0);
+ node.set_attribute_int(ATTR_WINDOW_MEMORY_ADDRESS_RADIX, memview.address_radix());
+ node.set_attribute_int(ATTR_WINDOW_MEMORY_DATA_FORMAT, int(memview.get_data_format()));
+ node.set_attribute_int(ATTR_WINDOW_MEMORY_ROW_CHUNKS, memview.chunks_per_row());
+}
+
+
+void memoryview_info::add_items_to_context_menu(HMENU menu)
+{
+ debugview_info::add_items_to_context_menu(menu);
+
+ AppendMenu(menu, MF_DISABLED | MF_SEPARATOR, 0, TEXT(""));
+ AppendMenu(menu, MF_GRAYED, ID_CONTEXT_LAST_PC, TEXT("Last PC"));
+}
+
+void memoryview_info::update_context_menu(HMENU menu)
+{
+ debugview_info::update_context_menu(menu);
+
+ bool enable = false;
+ debug_view_memory &memview(*view<debug_view_memory>());
+ debug_view_memory_source const &source = downcast<debug_view_memory_source const &>(*memview.source());
+ address_space *const space = source.space();
+ if (space)
+ {
+ if (memview.cursor_visible())
+ {
+ // get the last known PC to write to this memory location
+ debug_view_xy const pos = memview.cursor_position();
+ offs_t const address = space->byte_to_address(memview.addressAtCursorPosition(pos));
+ offs_t a = address & space->logaddrmask();
+ address_space *tspace;
+ if (!space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, a, tspace))
+ {
+ m_lastpc = "Bad address";
+ }
+ else
+ {
+ uint64_t memval = tspace->unmap();
+ auto dis = tspace->device().machine().disable_side_effects();
+ switch (tspace->data_width())
+ {
+ case 8: memval = tspace->read_byte(a); break;
+ case 16: memval = tspace->read_word_unaligned(a); break;
+ case 32: memval = tspace->read_dword_unaligned(a); break;
+ case 64: memval = tspace->read_qword_unaligned(a); break;
+ }
+
+ offs_t const pc = source.device()->debug()->track_mem_pc_from_space_address_data(
+ tspace->spacenum(),
+ address,
+ memval);
+ if (pc != offs_t(-1))
+ {
+ if (tspace->is_octal())
+ m_lastpc = util::string_format("Address %o written at PC=%o", address, pc);
+ else
+ m_lastpc = util::string_format("Address %x written at PC=%x", address, pc);
+ enable = true;
+ }
+ else
+ {
+ m_lastpc = "Unknown PC";
+ }
+ }
+ }
+ else
+ {
+ m_lastpc = "No address";
+ }
+ }
+ else
+ {
+ m_lastpc = "Not an address space";
+ }
+ ModifyMenuW(menu, ID_CONTEXT_LAST_PC, MF_BYCOMMAND, ID_CONTEXT_LAST_PC, osd::text::to_wstring(m_lastpc).c_str());
+ EnableMenuItem(menu, ID_CONTEXT_LAST_PC, MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED));
+}
+
+void memoryview_info::handle_context_menu(unsigned command)
+{
+ switch (command)
+ {
+ case ID_CONTEXT_LAST_PC:
+ // TODO: copy to clipboard
+ return;
+
+ default:
+ debugview_info::handle_context_menu(command);
+ };
+
+}
+
+} // namespace osd::debugger::win
diff --git a/src/osd/modules/debugger/win/memoryviewinfo.h b/src/osd/modules/debugger/win/memoryviewinfo.h
index 2ab810654f3..514c6c13ec6 100644
--- a/src/osd/modules/debugger/win/memoryviewinfo.h
+++ b/src/osd/modules/debugger/win/memoryviewinfo.h
@@ -5,14 +5,20 @@
// memoryviewinfo.h - Win32 debug window handling
//
//============================================================
+#ifndef MAME_DEBUGGER_WIN_MEMORYVIEWINFO_H
+#define MAME_DEBUGGER_WIN_MEMORYVIEWINFO_H
-#ifndef __DEBUG_WIN_MEMORY_VIEW_INFO_H__
-#define __DEBUG_WIN_MEMORY_VIEW_INFO_H__
+#pragma once
#include "debugwin.h"
-
#include "debugviewinfo.h"
+#include "debug/dvmemory.h"
+
+#include <string>
+
+
+namespace osd::debugger::win {
class memoryview_info : public debugview_info
{
@@ -20,16 +26,37 @@ public:
memoryview_info(debugger_windows_interface &debugger, debugwin_info &owner, HWND parent);
virtual ~memoryview_info();
- uint8_t data_format() const;
+ char const *expression() const;
+ debug_view_memory::data_format data_format() const;
uint32_t chunks_per_row() const;
bool reverse() const;
bool physical() const;
+ int address_radix() const;
void set_expression(const std::string &string);
- void set_data_format(uint8_t dataformat);
+ void set_data_format(debug_view_memory::data_format dataformat);
void set_chunks_per_row(uint32_t rowchunks);
void set_reverse(bool reverse);
void set_physical(bool physical);
+ void set_address_radix(int radix);
+
+ virtual void restore_configuration_from_node(util::xml::data_node const &node) override;
+ virtual void save_configuration_to_node(util::xml::data_node &node) override;
+
+protected:
+ enum
+ {
+ ID_CONTEXT_LAST_PC = 101
+ };
+
+ virtual void add_items_to_context_menu(HMENU menu) override;
+ virtual void update_context_menu(HMENU menu) override;
+ virtual void handle_context_menu(unsigned command) override;
+
+private:
+ std::string m_lastpc;
};
-#endif
+} // namespace osd::debugger::win
+
+#endif // MAME_DEBUGGER_WIN_MEMORYVIEWINFO_H
diff --git a/src/osd/modules/debugger/win/memorywininfo.cpp b/src/osd/modules/debugger/win/memorywininfo.cpp
index 6f461295ec2..92078854e2e 100644
--- a/src/osd/modules/debugger/win/memorywininfo.cpp
+++ b/src/osd/modules/debugger/win/memorywininfo.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Aaron Giles, Vas Crabb
//============================================================
//
-// memorywininfo.c - Win32 debug window handling
+// memorywininfo.cpp - Win32 debug window handling
//
//============================================================
@@ -13,9 +13,13 @@
#include "memoryviewinfo.h"
#include "uimetrics.h"
+#include "util/xmlfile.h"
+
#include "winutf8.h"
+namespace osd::debugger::win {
+
memorywin_info::memorywin_info(debugger_windows_interface &debugger) :
editwin_info(debugger, false, "Memory", nullptr),
m_combownd(nullptr)
@@ -23,7 +27,7 @@ memorywin_info::memorywin_info(debugger_windows_interface &debugger) :
if (!window())
return;
- m_views[0].reset(global_alloc(memoryview_info(debugger, *this, window())));
+ m_views[0].reset(new memoryview_info(debugger, *this, window()));
if ((m_views[0] == nullptr) || !m_views[0]->is_valid())
{
m_views[0].reset();
@@ -32,21 +36,29 @@ memorywin_info::memorywin_info(debugger_windows_interface &debugger) :
// create the options menu
HMENU const optionsmenu = CreatePopupMenu();
- AppendMenu(optionsmenu, MF_ENABLED, ID_1_BYTE_CHUNKS, TEXT("1-byte chunks\tCtrl+1"));
- AppendMenu(optionsmenu, MF_ENABLED, ID_2_BYTE_CHUNKS, TEXT("2-byte chunks\tCtrl+2"));
- AppendMenu(optionsmenu, MF_ENABLED, ID_4_BYTE_CHUNKS, TEXT("4-byte chunks\tCtrl+4"));
- AppendMenu(optionsmenu, MF_ENABLED, ID_8_BYTE_CHUNKS, TEXT("8-byte chunks\tCtrl+8"));
- AppendMenu(optionsmenu, MF_ENABLED, ID_FLOATING_POINT_32BIT, TEXT("32 bit floating point\tCtrl+9"));
- AppendMenu(optionsmenu, MF_ENABLED, ID_FLOATING_POINT_64BIT, TEXT("64 bit floating point"));
- AppendMenu(optionsmenu, MF_ENABLED, ID_FLOATING_POINT_80BIT, TEXT("80 bit floating point"));
+ AppendMenu(optionsmenu, MF_ENABLED, ID_1_BYTE_CHUNKS_HEX, TEXT("1-byte Chunks (Hex)\tCtrl+1"));
+ AppendMenu(optionsmenu, MF_ENABLED, ID_2_BYTE_CHUNKS_HEX, TEXT("2-byte Chunks (Hex)\tCtrl+2"));
+ AppendMenu(optionsmenu, MF_ENABLED, ID_4_BYTE_CHUNKS_HEX, TEXT("4-byte Chunks (Hex)\tCtrl+4"));
+ AppendMenu(optionsmenu, MF_ENABLED, ID_8_BYTE_CHUNKS_HEX, TEXT("8-byte Chunks (Hex)\tCtrl+8"));
+ AppendMenu(optionsmenu, MF_ENABLED, ID_1_BYTE_CHUNKS_OCT, TEXT("1-byte Chunks (Octal)\tCtrl+3"));
+ AppendMenu(optionsmenu, MF_ENABLED, ID_2_BYTE_CHUNKS_OCT, TEXT("2-byte Chunks (Octal)\tCtrl+5"));
+ AppendMenu(optionsmenu, MF_ENABLED, ID_4_BYTE_CHUNKS_OCT, TEXT("4-byte Chunks (Octal)\tCtrl+7"));
+ AppendMenu(optionsmenu, MF_ENABLED, ID_8_BYTE_CHUNKS_OCT, TEXT("8-byte Chunks (Octal)\tCtrl+9"));
+ AppendMenu(optionsmenu, MF_ENABLED, ID_FLOAT_32BIT, TEXT("32-bit Floating Point\tCtrl+Shift+F"));
+ AppendMenu(optionsmenu, MF_ENABLED, ID_FLOAT_64BIT, TEXT("64-bit Floating Point\tCtrl+Shift+D"));
+ AppendMenu(optionsmenu, MF_ENABLED, ID_FLOAT_80BIT, TEXT("80-bit Floating Point\tCtrl+Shift+E"));
+ AppendMenu(optionsmenu, MF_DISABLED | MF_SEPARATOR, 0, TEXT(""));
+ AppendMenu(optionsmenu, MF_ENABLED, ID_HEX_ADDRESSES, TEXT("Hexadecimal Addresses\tCtrl+Shift+H"));
+ AppendMenu(optionsmenu, MF_ENABLED, ID_DEC_ADDRESSES, TEXT("Decimal Addresses"));
+ AppendMenu(optionsmenu, MF_ENABLED, ID_OCT_ADDRESSES, TEXT("Octal Addresses\tCtrl+Shift+O"));
AppendMenu(optionsmenu, MF_DISABLED | MF_SEPARATOR, 0, TEXT(""));
AppendMenu(optionsmenu, MF_ENABLED, ID_LOGICAL_ADDRESSES, TEXT("Logical Addresses\tCtrl+L"));
AppendMenu(optionsmenu, MF_ENABLED, ID_PHYSICAL_ADDRESSES, TEXT("Physical Addresses\tCtrl+Y"));
AppendMenu(optionsmenu, MF_DISABLED | MF_SEPARATOR, 0, TEXT(""));
AppendMenu(optionsmenu, MF_ENABLED, ID_REVERSE_VIEW, TEXT("Reverse View\tCtrl+R"));
AppendMenu(optionsmenu, MF_DISABLED | MF_SEPARATOR, 0, TEXT(""));
- AppendMenu(optionsmenu, MF_ENABLED, ID_INCREASE_MEM_WIDTH, TEXT("Increase bytes per line\tCtrl+P"));
- AppendMenu(optionsmenu, MF_ENABLED, ID_DECREASE_MEM_WIDTH, TEXT("Decrease bytes per line\tCtrl+O"));
+ AppendMenu(optionsmenu, MF_ENABLED, ID_INCREASE_MEM_WIDTH, TEXT("Increase Bytes Per Line\tCtrl+P"));
+ AppendMenu(optionsmenu, MF_ENABLED, ID_DECREASE_MEM_WIDTH, TEXT("Decrease Bytes Per Line\tCtrl+O"));
AppendMenu(GetMenu(window()), MF_ENABLED | MF_POPUP, (UINT_PTR)optionsmenu, TEXT("Options"));
// set up the view to track the initial expression
@@ -63,11 +75,11 @@ memorywin_info::memorywin_info(debugger_windows_interface &debugger) :
update_caption();
// recompute the children once to get the maxwidth
- memorywin_info::recompute_children();
+ recompute_children();
// position the window and recompute children again
- SetWindowPos(window(), HWND_TOP, 100, 100, maxwidth(), 200, SWP_SHOWWINDOW);
- memorywin_info::recompute_children();
+ debugger.stagger_window(window(), maxwidth(), 200);
+ recompute_children();
// mark the edit box as the default focus and set it
editwin_info::set_default_focus();
@@ -83,47 +95,87 @@ bool memorywin_info::handle_key(WPARAM wparam, LPARAM lparam)
{
if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
{
- switch (wparam)
+ if (GetAsyncKeyState(VK_SHIFT))
{
- case '1':
- SendMessage(window(), WM_COMMAND, ID_1_BYTE_CHUNKS, 0);
- return true;
+ switch (wparam)
+ {
+ case 'F':
+ SendMessage(window(), WM_COMMAND, ID_FLOAT_32BIT, 0);
+ return true;
- case '2':
- SendMessage(window(), WM_COMMAND, ID_2_BYTE_CHUNKS, 0);
- return true;
+ case 'D':
+ SendMessage(window(), WM_COMMAND, ID_FLOAT_64BIT, 0);
+ return true;
- case '4':
- SendMessage(window(), WM_COMMAND, ID_4_BYTE_CHUNKS, 0);
- return true;
+ case 'E':
+ SendMessage(window(), WM_COMMAND, ID_FLOAT_80BIT, 0);
+ return true;
- case '8':
- SendMessage(window(), WM_COMMAND, ID_8_BYTE_CHUNKS, 0);
- return true;
+ case 'H':
+ SendMessage(window(), WM_COMMAND, ID_HEX_ADDRESSES, 0);
+ return true;
- case '9':
- SendMessage(window(), WM_COMMAND, ID_FLOATING_POINT_32BIT, 0);
- return true;
+ case 'O':
+ SendMessage(window(), WM_COMMAND, ID_OCT_ADDRESSES, 0);
+ return true;
+ }
+ }
+ else
+ {
+ switch (wparam)
+ {
+ case '1':
+ SendMessage(window(), WM_COMMAND, ID_1_BYTE_CHUNKS_HEX, 0);
+ return true;
- case 'L':
- SendMessage(window(), WM_COMMAND, ID_LOGICAL_ADDRESSES, 0);
- return true;
+ case '2':
+ SendMessage(window(), WM_COMMAND, ID_2_BYTE_CHUNKS_HEX, 0);
+ return true;
- case 'Y':
- SendMessage(window(), WM_COMMAND, ID_PHYSICAL_ADDRESSES, 0);
- return true;
+ case '4':
+ SendMessage(window(), WM_COMMAND, ID_4_BYTE_CHUNKS_HEX, 0);
+ return true;
- case 'R':
- SendMessage(window(), WM_COMMAND, ID_REVERSE_VIEW, 0);
- return true;
+ case '8':
+ SendMessage(window(), WM_COMMAND, ID_8_BYTE_CHUNKS_HEX, 0);
+ return true;
- case 'P':
- SendMessage(window(), WM_COMMAND, ID_INCREASE_MEM_WIDTH, 0);
- return true;
+ case '3':
+ SendMessage(window(), WM_COMMAND, ID_1_BYTE_CHUNKS_OCT, 0);
+ return true;
- case 'O':
- SendMessage(window(), WM_COMMAND, ID_DECREASE_MEM_WIDTH, 0);
- return true;
+ case '5':
+ SendMessage(window(), WM_COMMAND, ID_2_BYTE_CHUNKS_OCT, 0);
+ return true;
+
+ case '7':
+ SendMessage(window(), WM_COMMAND, ID_4_BYTE_CHUNKS_OCT, 0);
+ return true;
+
+ case '9':
+ SendMessage(window(), WM_COMMAND, ID_8_BYTE_CHUNKS_OCT, 0);
+ return true;
+
+ case 'L':
+ SendMessage(window(), WM_COMMAND, ID_LOGICAL_ADDRESSES, 0);
+ return true;
+
+ case 'Y':
+ SendMessage(window(), WM_COMMAND, ID_PHYSICAL_ADDRESSES, 0);
+ return true;
+
+ case 'R':
+ SendMessage(window(), WM_COMMAND, ID_REVERSE_VIEW, 0);
+ return true;
+
+ case 'P':
+ SendMessage(window(), WM_COMMAND, ID_INCREASE_MEM_WIDTH, 0);
+ return true;
+
+ case 'O':
+ SendMessage(window(), WM_COMMAND, ID_DECREASE_MEM_WIDTH, 0);
+ return true;
+ }
}
}
return editwin_info::handle_key(wparam, lparam);
@@ -178,25 +230,37 @@ void memorywin_info::update_menu()
{
editwin_info::update_menu();
- memoryview_info *const memview = downcast<memoryview_info *>(m_views[0].get());
+ auto *const memview = downcast<memoryview_info *>(m_views[0].get());
HMENU const menu = GetMenu(window());
- CheckMenuItem(menu, ID_1_BYTE_CHUNKS, MF_BYCOMMAND | (memview->data_format() == 1 ? MF_CHECKED : MF_UNCHECKED));
- CheckMenuItem(menu, ID_2_BYTE_CHUNKS, MF_BYCOMMAND | (memview->data_format() == 2 ? MF_CHECKED : MF_UNCHECKED));
- CheckMenuItem(menu, ID_4_BYTE_CHUNKS, MF_BYCOMMAND | (memview->data_format() == 4 ? MF_CHECKED : MF_UNCHECKED));
- CheckMenuItem(menu, ID_8_BYTE_CHUNKS, MF_BYCOMMAND | (memview->data_format() == 8 ? MF_CHECKED : MF_UNCHECKED));
- CheckMenuItem(menu, ID_FLOATING_POINT_32BIT, MF_BYCOMMAND | (memview->data_format() == 9 ? MF_CHECKED : MF_UNCHECKED));
- CheckMenuItem(menu, ID_FLOATING_POINT_64BIT, MF_BYCOMMAND | (memview->data_format() == 10 ? MF_CHECKED : MF_UNCHECKED));
- CheckMenuItem(menu, ID_FLOATING_POINT_80BIT, MF_BYCOMMAND | (memview->data_format() == 11 ? MF_CHECKED : MF_UNCHECKED));
+
+ CheckMenuItem(menu, ID_1_BYTE_CHUNKS_HEX, MF_BYCOMMAND | ((memview->data_format() == debug_view_memory::data_format::HEX_8BIT) ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(menu, ID_2_BYTE_CHUNKS_HEX, MF_BYCOMMAND | ((memview->data_format() == debug_view_memory::data_format::HEX_16BIT) ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(menu, ID_4_BYTE_CHUNKS_HEX, MF_BYCOMMAND | ((memview->data_format() == debug_view_memory::data_format::HEX_32BIT) ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(menu, ID_8_BYTE_CHUNKS_HEX, MF_BYCOMMAND | ((memview->data_format() == debug_view_memory::data_format::HEX_64BIT) ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(menu, ID_1_BYTE_CHUNKS_OCT, MF_BYCOMMAND | ((memview->data_format() == debug_view_memory::data_format::OCTAL_8BIT) ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(menu, ID_2_BYTE_CHUNKS_OCT, MF_BYCOMMAND | ((memview->data_format() == debug_view_memory::data_format::OCTAL_16BIT) ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(menu, ID_4_BYTE_CHUNKS_OCT, MF_BYCOMMAND | ((memview->data_format() == debug_view_memory::data_format::OCTAL_32BIT) ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(menu, ID_8_BYTE_CHUNKS_OCT, MF_BYCOMMAND | ((memview->data_format() == debug_view_memory::data_format::OCTAL_64BIT) ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(menu, ID_FLOAT_32BIT, MF_BYCOMMAND | ((memview->data_format() == debug_view_memory::data_format::FLOAT_32BIT) ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(menu, ID_FLOAT_64BIT, MF_BYCOMMAND | ((memview->data_format() == debug_view_memory::data_format::FLOAT_64BIT) ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(menu, ID_FLOAT_80BIT, MF_BYCOMMAND | ((memview->data_format() == debug_view_memory::data_format::FLOAT_80BIT) ? MF_CHECKED : MF_UNCHECKED));
+
+ CheckMenuItem(menu, ID_HEX_ADDRESSES, MF_BYCOMMAND | ((memview->address_radix() == 16) ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(menu, ID_DEC_ADDRESSES, MF_BYCOMMAND | ((memview->address_radix() == 10) ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(menu, ID_OCT_ADDRESSES, MF_BYCOMMAND | ((memview->address_radix() == 8) ? MF_CHECKED : MF_UNCHECKED));
+
CheckMenuItem(menu, ID_LOGICAL_ADDRESSES, MF_BYCOMMAND | (memview->physical() ? MF_UNCHECKED : MF_CHECKED));
CheckMenuItem(menu, ID_PHYSICAL_ADDRESSES, MF_BYCOMMAND | (memview->physical() ? MF_CHECKED : MF_UNCHECKED));
+
CheckMenuItem(menu, ID_REVERSE_VIEW, MF_BYCOMMAND | (memview->reverse() ? MF_CHECKED : MF_UNCHECKED));
+
EnableMenuItem(menu, ID_DECREASE_MEM_WIDTH, MF_BYCOMMAND | ((memview->chunks_per_row() > 1) ? MF_ENABLED : MF_GRAYED));
}
bool memorywin_info::handle_command(WPARAM wparam, LPARAM lparam)
{
- memoryview_info *const memview = downcast<memoryview_info *>(m_views[0].get());
+ auto *const memview = downcast<memoryview_info *>(m_views[0].get());
switch (HIWORD(wparam))
{
// combo box selection changed
@@ -219,32 +283,60 @@ bool memorywin_info::handle_command(WPARAM wparam, LPARAM lparam)
case 0:
switch (LOWORD(wparam))
{
- case ID_1_BYTE_CHUNKS:
- memview->set_data_format(1);
+ case ID_1_BYTE_CHUNKS_HEX:
+ memview->set_data_format(debug_view_memory::data_format::HEX_8BIT);
+ return true;
+
+ case ID_2_BYTE_CHUNKS_HEX:
+ memview->set_data_format(debug_view_memory::data_format::HEX_16BIT);
+ return true;
+
+ case ID_4_BYTE_CHUNKS_HEX:
+ memview->set_data_format(debug_view_memory::data_format::HEX_32BIT);
+ return true;
+
+ case ID_8_BYTE_CHUNKS_HEX:
+ memview->set_data_format(debug_view_memory::data_format::HEX_64BIT);
return true;
- case ID_2_BYTE_CHUNKS:
- memview->set_data_format(2);
+ case ID_1_BYTE_CHUNKS_OCT:
+ memview->set_data_format(debug_view_memory::data_format::OCTAL_8BIT);
return true;
- case ID_4_BYTE_CHUNKS:
- memview->set_data_format(4);
+ case ID_2_BYTE_CHUNKS_OCT:
+ memview->set_data_format(debug_view_memory::data_format::OCTAL_16BIT);
return true;
- case ID_8_BYTE_CHUNKS:
- memview->set_data_format(8);
+ case ID_4_BYTE_CHUNKS_OCT:
+ memview->set_data_format(debug_view_memory::data_format::OCTAL_32BIT);
return true;
- case ID_FLOATING_POINT_32BIT:
- memview->set_data_format(9);
+ case ID_8_BYTE_CHUNKS_OCT:
+ memview->set_data_format(debug_view_memory::data_format::OCTAL_64BIT);
return true;
- case ID_FLOATING_POINT_64BIT:
- memview->set_data_format(10);
+ case ID_FLOAT_32BIT:
+ memview->set_data_format(debug_view_memory::data_format::FLOAT_32BIT);
return true;
- case ID_FLOATING_POINT_80BIT:
- memview->set_data_format(11);
+ case ID_FLOAT_64BIT:
+ memview->set_data_format(debug_view_memory::data_format::FLOAT_64BIT);
+ return true;
+
+ case ID_FLOAT_80BIT:
+ memview->set_data_format(debug_view_memory::data_format::FLOAT_80BIT);
+ return true;
+
+ case ID_HEX_ADDRESSES:
+ memview->set_address_radix(16);
+ return true;
+
+ case ID_DEC_ADDRESSES:
+ memview->set_address_radix(10);
+ return true;
+
+ case ID_OCT_ADDRESSES:
+ memview->set_address_radix(8);
return true;
case ID_LOGICAL_ADDRESSES:
@@ -300,3 +392,37 @@ void memorywin_info::update_caption()
{
win_set_window_text_utf8(window(), std::string("Memory: ").append(m_views[0]->source_name()).c_str());
}
+
+
+void memorywin_info::restore_configuration_from_node(util::xml::data_node const &node)
+{
+ m_views[0]->set_source_index(node.get_attribute_int(ATTR_WINDOW_MEMORY_REGION, m_views[0]->source_index()));
+ int const cursource = m_views[0]->source_index();
+ if (0 <= cursource)
+ SendMessage(m_combownd, CB_SETCURSEL, cursource, 0);
+ update_caption();
+
+ util::xml::data_node const *const expr = node.get_child(NODE_WINDOW_EXPRESSION);
+ if (expr && expr->get_value())
+ {
+ set_editwnd_text(expr->get_value());
+ process_string(expr->get_value());
+ }
+
+ editwin_info::restore_configuration_from_node(node);
+
+ m_views[0]->restore_configuration_from_node(node);
+}
+
+
+void memorywin_info::save_configuration_to_node(util::xml::data_node &node)
+{
+ editwin_info::save_configuration_to_node(node);
+
+ node.set_attribute_int(ATTR_WINDOW_TYPE, WINDOW_TYPE_MEMORY_VIEWER);
+ node.set_attribute_int(ATTR_WINDOW_MEMORY_REGION, m_views[0]->source_index());
+ node.add_child(NODE_WINDOW_EXPRESSION, downcast<memoryview_info *>(m_views[0].get())->expression());
+ m_views[0]->save_configuration_to_node(node);
+}
+
+} // namespace osd::debugger::win
diff --git a/src/osd/modules/debugger/win/memorywininfo.h b/src/osd/modules/debugger/win/memorywininfo.h
index 501d7acc76f..a0a4072be0f 100644
--- a/src/osd/modules/debugger/win/memorywininfo.h
+++ b/src/osd/modules/debugger/win/memorywininfo.h
@@ -5,15 +5,18 @@
// memorywininfo.h - Win32 debug window handling
//
//============================================================
+#ifndef MAME_DEBUGGER_WIN_MEMORYWININFO_H
+#define MAME_DEBUGGER_WIN_MEMORYWININFO_H
-#ifndef __DEBUG_WIN_MEMORY_WIN_INFO_H__
-#define __DEBUG_WIN_MEMORY_WIN_INFO_H__
+#pragma once
#include "debugwin.h"
#include "editwininfo.h"
+namespace osd::debugger::win {
+
class memorywin_info : public editwin_info
{
public:
@@ -21,12 +24,14 @@ public:
virtual ~memorywin_info();
virtual bool handle_key(WPARAM wparam, LPARAM lparam) override;
+ virtual void restore_configuration_from_node(util::xml::data_node const &node) override;
protected:
virtual void recompute_children() override;
virtual void update_menu() override;
virtual bool handle_command(WPARAM wparam, LPARAM lparam) override;
virtual void draw_contents(HDC dc) override;
+ virtual void save_configuration_to_node(util::xml::data_node &node) override;
private:
virtual void process_string(const std::string &string) override;
@@ -36,4 +41,6 @@ private:
HWND m_combownd;
};
-#endif
+} // namespace osd::debugger::win
+
+#endif // MAME_DEBUGGER_WIN_MEMORYWININFO_H
diff --git a/src/osd/modules/debugger/win/pointswininfo.cpp b/src/osd/modules/debugger/win/pointswininfo.cpp
index 24a8f865e6f..70ec6606280 100644
--- a/src/osd/modules/debugger/win/pointswininfo.cpp
+++ b/src/osd/modules/debugger/win/pointswininfo.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Aaron Giles, Vas Crabb
//============================================================
//
-// pointswininfo.c - Win32 debug window handling
+// pointswininfo.cpp - Win32 debug window handling
//
//============================================================
@@ -11,16 +11,20 @@
#include "debugviewinfo.h"
+#include "util/xmlfile.h"
+
#include "winutf8.h"
+namespace osd::debugger::win {
+
pointswin_info::pointswin_info(debugger_windows_interface &debugger) :
debugwin_info(debugger, false, std::string("All Breakpoints").c_str(), nullptr)
{
if (!window())
return;
- m_views[0].reset(global_alloc(debugview_info(debugger, *this, window(), DVT_BREAK_POINTS)));
+ m_views[0].reset(new debugview_info(debugger, *this, window(), DVT_BREAK_POINTS));
if ((m_views[0] == nullptr) || !m_views[0]->is_valid())
{
m_views[0].reset();
@@ -31,6 +35,8 @@ pointswin_info::pointswin_info(debugger_windows_interface &debugger) :
HMENU const optionsmenu = CreatePopupMenu();
AppendMenu(optionsmenu, MF_ENABLED, ID_SHOW_BREAKPOINTS, TEXT("Breakpoints\tCtrl+1"));
AppendMenu(optionsmenu, MF_ENABLED, ID_SHOW_WATCHPOINTS, TEXT("Watchpoints\tCtrl+2"));
+ AppendMenu(optionsmenu, MF_ENABLED, ID_SHOW_REGISTERPOINTS, TEXT("Registerpoints\tCtrl+3"));
+ AppendMenu(optionsmenu, MF_ENABLED, ID_SHOW_EXCEPTIONPOINTS, TEXT("Exceptionpoints\tCtrl+4"));
AppendMenu(GetMenu(window()), MF_ENABLED | MF_POPUP, (UINT_PTR)optionsmenu, TEXT("Options"));
// compute a client rect
@@ -43,11 +49,9 @@ pointswin_info::pointswin_info(debugger_windows_interface &debugger) :
// clamp the min/max size
set_maxwidth(bounds.right - bounds.left);
- // position the window at the bottom-right
- SetWindowPos(window(), HWND_TOP, 100, 100, bounds.right - bounds.left, bounds.bottom - bounds.top, SWP_SHOWWINDOW);
-
- // recompute the children
- debugwin_info::recompute_children();
+ // position the window and recompute children
+ debugger.stagger_window(window(), bounds.right - bounds.left, bounds.bottom - bounds.top);
+ recompute_children();
}
@@ -69,6 +73,14 @@ bool pointswin_info::handle_key(WPARAM wparam, LPARAM lparam)
case '2':
SendMessage(window(), WM_COMMAND, ID_SHOW_WATCHPOINTS, 0);
return true;
+
+ case '3':
+ SendMessage(window(), WM_COMMAND, ID_SHOW_REGISTERPOINTS, 0);
+ return true;
+
+ case '4':
+ SendMessage(window(), WM_COMMAND, ID_SHOW_EXCEPTIONPOINTS, 0);
+ return true;
}
}
@@ -83,6 +95,8 @@ void pointswin_info::update_menu()
HMENU const menu = GetMenu(window());
CheckMenuItem(menu, ID_SHOW_BREAKPOINTS, MF_BYCOMMAND | (m_views[0]->type() == DVT_BREAK_POINTS ? MF_CHECKED : MF_UNCHECKED));
CheckMenuItem(menu, ID_SHOW_WATCHPOINTS, MF_BYCOMMAND | (m_views[0]->type() == DVT_WATCH_POINTS ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(menu, ID_SHOW_REGISTERPOINTS, MF_BYCOMMAND | (m_views[0]->type() == DVT_REGISTER_POINTS ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(menu, ID_SHOW_EXCEPTIONPOINTS, MF_BYCOMMAND | (m_views[0]->type() == DVT_EXCEPTION_POINTS ? MF_CHECKED : MF_UNCHECKED));
}
@@ -96,7 +110,7 @@ bool pointswin_info::handle_command(WPARAM wparam, LPARAM lparam)
{
case ID_SHOW_BREAKPOINTS:
m_views[0].reset();
- m_views[0].reset(global_alloc(debugview_info(debugger(), *this, window(), DVT_BREAK_POINTS)));
+ m_views[0].reset(new debugview_info(debugger(), *this, window(), DVT_BREAK_POINTS));
if (!m_views[0]->is_valid())
m_views[0].reset();
win_set_window_text_utf8(window(), "All Breakpoints");
@@ -105,14 +119,81 @@ bool pointswin_info::handle_command(WPARAM wparam, LPARAM lparam)
case ID_SHOW_WATCHPOINTS:
m_views[0].reset();
- m_views[0].reset(global_alloc(debugview_info(debugger(), *this, window(), DVT_WATCH_POINTS)));
+ m_views[0].reset(new debugview_info(debugger(), *this, window(), DVT_WATCH_POINTS));
if (!m_views[0]->is_valid())
m_views[0].reset();
win_set_window_text_utf8(window(), "All Watchpoints");
recompute_children();
return true;
+
+ case ID_SHOW_REGISTERPOINTS:
+ m_views[0].reset();
+ m_views[0].reset(new debugview_info(debugger(), *this, window(), DVT_REGISTER_POINTS));
+ if (!m_views[0]->is_valid())
+ m_views[0].reset();
+ win_set_window_text_utf8(window(), "All Registerpoints");
+ recompute_children();
+ return true;
+
+ case ID_SHOW_EXCEPTIONPOINTS:
+ m_views[0].reset();
+ m_views[0].reset(new debugview_info(debugger(), *this, window(), DVT_EXCEPTION_POINTS));
+ if (!m_views[0]->is_valid())
+ m_views[0].reset();
+ win_set_window_text_utf8(window(), "All Exceptionpoints");
+ recompute_children();
+ return true;
}
break;
}
return debugwin_info::handle_command(wparam, lparam);
}
+
+
+void pointswin_info::restore_configuration_from_node(util::xml::data_node const &node)
+{
+ switch (node.get_attribute_int(ATTR_WINDOW_POINTS_TYPE, -1))
+ {
+ case 0:
+ SendMessage(window(), WM_COMMAND, ID_SHOW_BREAKPOINTS, 0);
+ break;
+ case 1:
+ SendMessage(window(), WM_COMMAND, ID_SHOW_WATCHPOINTS, 0);
+ break;
+ case 2:
+ SendMessage(window(), WM_COMMAND, ID_SHOW_REGISTERPOINTS, 0);
+ break;
+ case 3:
+ SendMessage(window(), WM_COMMAND, ID_SHOW_EXCEPTIONPOINTS, 0);
+ break;
+ }
+
+ debugwin_info::restore_configuration_from_node(node);
+}
+
+
+void pointswin_info::save_configuration_to_node(util::xml::data_node &node)
+{
+ debugwin_info::save_configuration_to_node(node);
+
+ node.set_attribute_int(ATTR_WINDOW_TYPE, WINDOW_TYPE_POINTS_VIEWER);
+ switch (m_views[0]->type())
+ {
+ case DVT_BREAK_POINTS:
+ node.set_attribute_int(ATTR_WINDOW_POINTS_TYPE, 0);
+ break;
+ case DVT_WATCH_POINTS:
+ node.set_attribute_int(ATTR_WINDOW_POINTS_TYPE, 1);
+ break;
+ case DVT_REGISTER_POINTS:
+ node.set_attribute_int(ATTR_WINDOW_POINTS_TYPE, 2);
+ break;
+ case DVT_EXCEPTION_POINTS:
+ node.set_attribute_int(ATTR_WINDOW_POINTS_TYPE, 3);
+ break;
+ default:
+ break;
+ }
+}
+
+} // namespace osd::debugger::win
diff --git a/src/osd/modules/debugger/win/pointswininfo.h b/src/osd/modules/debugger/win/pointswininfo.h
index 8ba1b31fc00..506c68519e8 100644
--- a/src/osd/modules/debugger/win/pointswininfo.h
+++ b/src/osd/modules/debugger/win/pointswininfo.h
@@ -5,15 +5,18 @@
// pointswininfo.h - Win32 debug window handling
//
//============================================================
+#ifndef MAME_DEBUGGER_WIN_POINTSWININFO_H
+#define MAME_DEBUGGER_WIN_POINTSWININFO_H
-#ifndef __DEBUG_WIN_POINTS_WIN_INFO_H__
-#define __DEBUG_WIN_POINTS_WIN_INFO_H__
+#pragma once
#include "debugwin.h"
#include "debugwininfo.h"
+namespace osd::debugger::win {
+
class pointswin_info : public debugwin_info
{
public:
@@ -21,10 +24,14 @@ public:
virtual ~pointswin_info();
virtual bool handle_key(WPARAM wparam, LPARAM lparam) override;
+ virtual void restore_configuration_from_node(util::xml::data_node const &node) override;
protected:
virtual void update_menu() override;
virtual bool handle_command(WPARAM wparam, LPARAM lparam) override;
+ virtual void save_configuration_to_node(util::xml::data_node &node) override;
};
-#endif
+} // namespace osd::debugger::win
+
+#endif // MAME_DEBUGGER_WIN_POINTSWININFO_H
diff --git a/src/osd/modules/debugger/win/uimetrics.cpp b/src/osd/modules/debugger/win/uimetrics.cpp
index 67eb045c619..e3d21cda06d 100644
--- a/src/osd/modules/debugger/win/uimetrics.cpp
+++ b/src/osd/modules/debugger/win/uimetrics.cpp
@@ -2,15 +2,48 @@
// copyright-holders:Aaron Giles, Vas Crabb
//============================================================
//
-// uimetrics.c - Win32 debug window handling
+// uimetrics.cpp - Win32 debug window handling
//
//============================================================
#include "emu.h"
#include "uimetrics.h"
+#include "debug/debugvw.h"
+
#include "strconv.h"
+#include <algorithm>
+
+
+namespace osd::debugger::win {
+
+COLORREF const ui_metrics::s_themes[][COLOR_COUNT] = {
+ {
+ RGB(0x00, 0x00, 0x00), // foreground normal
+ RGB(0xff, 0x00, 0x00), // foreground changed
+ RGB(0x00, 0x00, 0xff), // foreground invalid
+ RGB(0x00, 0x80, 0x00), // foreground comment
+ RGB(0xff, 0xff, 0xff), // background normal
+ RGB(0xff, 0x80, 0x80), // background selected
+ RGB(0xe0, 0xe0, 0xe0), // background ancillary
+ RGB(0xff, 0xff, 0x00), // background current
+ RGB(0xff, 0xc0, 0x80), // background current selected
+ RGB(0xc0, 0xe0, 0xff) // background visited
+ },
+ {
+ RGB(0xe0, 0xe0, 0xe0), // foreground normal
+ RGB(0xff, 0x60, 0xff), // foreground changed
+ RGB(0x00, 0xc0, 0xe0), // foreground invalid
+ RGB(0x00, 0xe0, 0x00), // foreground comment
+ RGB(0x00, 0x00, 0x00), // background normal
+ RGB(0xe0, 0x00, 0x00), // background selected
+ RGB(0x40, 0x40, 0x40), // background ancillary
+ RGB(0x00, 0x00, 0xc0), // background current
+ RGB(0xb0, 0x60, 0x00), // background current selected
+ RGB(0x00, 0x40, 0x80) // background visited
+ } };
+
ui_metrics::ui_metrics(osd_options const &options) :
m_debug_font(nullptr),
@@ -22,7 +55,7 @@ ui_metrics::ui_metrics(osd_options const &options) :
{
// create a temporary DC
HDC const temp_dc = GetDC(nullptr);
- if (temp_dc != nullptr)
+ if (temp_dc)
{
float const size = options.debugger_font_size();
char const *const face = options.debugger_font();
@@ -47,6 +80,9 @@ ui_metrics::ui_metrics(osd_options const &options) :
SelectObject(temp_dc, old_font);
ReleaseDC(nullptr, temp_dc);
}
+
+ // set default color theme
+ set_color_theme(THEME_LIGHT_BACKGROUND);
}
@@ -69,3 +105,56 @@ ui_metrics::~ui_metrics()
if (m_debug_font)
DeleteObject(m_debug_font);
}
+
+
+std::pair<COLORREF, COLORREF> ui_metrics::view_colors(u8 attrib) const
+{
+ std::pair<COLORREF, COLORREF> result;
+
+ if (attrib & DCA_SELECTED)
+ result.second = (attrib & DCA_CURRENT) ? m_colors[COLOR_BG_CURRENT_SELECTED] : m_colors[COLOR_BG_SELECTED];
+ else if (attrib & DCA_CURRENT)
+ result.second = m_colors[COLOR_BG_CURRENT];
+ else if (attrib & DCA_ANCILLARY)
+ result.second = m_colors[COLOR_BG_ANCILLARY];
+ else if (attrib & DCA_VISITED)
+ result.second = m_colors[COLOR_BG_VISITED];
+ else
+ result.second = m_colors[COLOR_BG_NORMAL];
+
+ if (DCA_COMMENT & attrib)
+ {
+ result.first = m_colors[COLOR_FG_COMMENT];
+ }
+ else
+ {
+ if (attrib & DCA_INVALID)
+ result.first = m_colors[COLOR_FG_INVALID];
+ else if (attrib & DCA_CHANGED)
+ result.first = m_colors[COLOR_FG_CHANGED];
+ else
+ result.first = m_colors[COLOR_FG_NORMAL];
+
+ if (attrib & DCA_DISABLED)
+ {
+ result.first = RGB(
+ (GetRValue(result.first) + GetRValue(result.second) + 1) >> 1,
+ (GetGValue(result.first) + GetGValue(result.second) + 1) >> 1,
+ (GetBValue(result.first) + GetBValue(result.second) + 1) >> 1);
+ }
+ }
+
+ return result;
+}
+
+
+void ui_metrics::set_color_theme(int index)
+{
+ if ((0 <= index) && (std::size(s_themes) > index))
+ {
+ std::copy(std::begin(s_themes[index]), std::end(s_themes[index]), m_colors);
+ m_color_theme = index;
+ }
+}
+
+} // namespace osd::debugger::win
diff --git a/src/osd/modules/debugger/win/uimetrics.h b/src/osd/modules/debugger/win/uimetrics.h
index a360d66924e..e45ae810fa6 100644
--- a/src/osd/modules/debugger/win/uimetrics.h
+++ b/src/osd/modules/debugger/win/uimetrics.h
@@ -5,19 +5,29 @@
// uimetrics.h - Win32 debug window handling
//
//============================================================
+#ifndef MAME_DEBUGGER_WIN_UIMETRICS_H
+#define MAME_DEBUGGER_WIN_UIMETRICS_H
-#ifndef __DEBUG_WIN_UI_METRICS_H__
-#define __DEBUG_WIN_UI_METRICS_H__
+#pragma once
#include "debugwin.h"
-
#include "modules/lib/osdobj_common.h"
+#include <utility>
+
+
+namespace osd::debugger::win {
class ui_metrics
{
public:
+ enum
+ {
+ THEME_LIGHT_BACKGROUND,
+ THEME_DARK_BACKGROUND
+ };
+
ui_metrics(osd_options const &options);
ui_metrics(ui_metrics const &that);
~ui_metrics();
@@ -30,7 +40,28 @@ public:
uint32_t hscroll_height() const { return m_hscroll_height; }
uint32_t vscroll_width() const { return m_vscroll_width; }
+ std::pair<COLORREF, COLORREF> view_colors(u8 attrib) const;
+ int get_color_theme() const { return m_color_theme; }
+ void set_color_theme(int index);
+
private:
+ enum
+ {
+ COLOR_FG_NORMAL,
+ COLOR_FG_CHANGED,
+ COLOR_FG_INVALID,
+ COLOR_FG_COMMENT,
+
+ COLOR_BG_NORMAL,
+ COLOR_BG_SELECTED,
+ COLOR_BG_ANCILLARY,
+ COLOR_BG_CURRENT,
+ COLOR_BG_CURRENT_SELECTED,
+ COLOR_BG_VISITED,
+
+ COLOR_COUNT
+ };
+
HFONT m_debug_font;
uint32_t m_debug_font_height;
uint32_t m_debug_font_width;
@@ -38,6 +69,13 @@ private:
uint32_t const m_hscroll_height;
uint32_t const m_vscroll_width;
+
+ COLORREF m_colors[COLOR_COUNT];
+ int m_color_theme;
+
+ static COLORREF const s_themes[][COLOR_COUNT];
};
-#endif
+} // namespace osd::debugger::win
+
+#endif // MAME_DEBUGGER_WIN_UIMETRICS_H
diff --git a/src/osd/modules/debugger/xmlconfig.cpp b/src/osd/modules/debugger/xmlconfig.cpp
new file mode 100644
index 00000000000..977e7b55e70
--- /dev/null
+++ b/src/osd/modules/debugger/xmlconfig.cpp
@@ -0,0 +1,54 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+
+#include "xmlconfig.h"
+
+namespace osd::debugger {
+
+char const *const NODE_WINDOW = "window";
+char const *const NODE_COLORS = "colors";
+
+char const *const NODE_WINDOW_SPLITS = "splits";
+char const *const NODE_WINDOW_SELECTION = "selection";
+char const *const NODE_WINDOW_SCROLL = "scroll";
+char const *const NODE_WINDOW_EXPRESSION = "expression";
+char const *const NODE_WINDOW_HISTORY = "history";
+
+char const *const NODE_HISTORY_ITEM = "item";
+
+char const *const ATTR_DEBUGGER_SAVE_WINDOWS = "savewindows";
+char const *const ATTR_DEBUGGER_GROUP_WINDOWS = "groupwindows";
+
+char const *const ATTR_WINDOW_TYPE = "type";
+char const *const ATTR_WINDOW_POSITION_X = "position_x";
+char const *const ATTR_WINDOW_POSITION_Y = "position_y";
+char const *const ATTR_WINDOW_WIDTH = "size_x";
+char const *const ATTR_WINDOW_HEIGHT = "size_y";
+
+char const *const ATTR_WINDOW_MEMORY_REGION = "memoryregion";
+char const *const ATTR_WINDOW_MEMORY_REVERSE_COLUMNS = "reverse";
+char const *const ATTR_WINDOW_MEMORY_ADDRESS_MODE = "addressmode";
+char const *const ATTR_WINDOW_MEMORY_ADDRESS_RADIX = "addressradix";
+char const *const ATTR_WINDOW_MEMORY_DATA_FORMAT = "dataformat";
+char const *const ATTR_WINDOW_MEMORY_ROW_CHUNKS = "rowchunks";
+
+char const *const ATTR_WINDOW_DISASSEMBLY_CPU = "cpu";
+char const *const ATTR_WINDOW_DISASSEMBLY_RIGHT_COLUMN = "rightbar";
+
+char const *const ATTR_WINDOW_POINTS_TYPE = "bwtype";
+
+char const *const ATTR_WINDOW_DEVICE_TAG = "device-tag";
+
+char const *const ATTR_COLORS_THEME = "theme";
+
+char const *const ATTR_SPLITS_CONSOLE_STATE = "state";
+char const *const ATTR_SPLITS_CONSOLE_DISASSEMBLY = "disassembly";
+
+char const *const ATTR_SELECTION_CURSOR_VISIBLE = "visible";
+char const *const ATTR_SELECTION_CURSOR_X = "start_x";
+char const *const ATTR_SELECTION_CURSOR_Y = "start_y";
+
+char const *const ATTR_SCROLL_ORIGIN_X = "position_x";
+char const *const ATTR_SCROLL_ORIGIN_Y = "position_y";
+
+} // namespace osd::debugger
diff --git a/src/osd/modules/debugger/xmlconfig.h b/src/osd/modules/debugger/xmlconfig.h
new file mode 100644
index 00000000000..6ae476cdec7
--- /dev/null
+++ b/src/osd/modules/debugger/xmlconfig.h
@@ -0,0 +1,72 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+#ifndef MAME_OSD_DEBUGGER_XMLCONFIG_H
+#define MAME_OSD_DEBUGGER_XMLCONFIG_H
+
+#pragma once
+
+namespace osd::debugger {
+
+// Qt debugger started using these numeric types - they should be switched to mnemonics at some point
+enum
+{
+
+WINDOW_TYPE_CONSOLE = 1,
+WINDOW_TYPE_MEMORY_VIEWER,
+WINDOW_TYPE_DISASSEMBLY_VIEWER,
+WINDOW_TYPE_ERROR_LOG_VIEWER,
+WINDOW_TYPE_POINTS_VIEWER,
+WINDOW_TYPE_DEVICES_VIEWER,
+WINDOW_TYPE_DEVICE_INFO_VIEWER
+
+};
+
+extern char const *const NODE_WINDOW;
+extern char const *const NODE_COLORS;
+
+extern char const *const NODE_WINDOW_SPLITS;
+extern char const *const NODE_WINDOW_SELECTION;
+extern char const *const NODE_WINDOW_SCROLL;
+extern char const *const NODE_WINDOW_EXPRESSION;
+extern char const *const NODE_WINDOW_HISTORY;
+
+extern char const *const NODE_HISTORY_ITEM;
+
+extern char const *const ATTR_DEBUGGER_SAVE_WINDOWS;
+extern char const *const ATTR_DEBUGGER_GROUP_WINDOWS;
+
+extern char const *const ATTR_WINDOW_TYPE;
+extern char const *const ATTR_WINDOW_POSITION_X;
+extern char const *const ATTR_WINDOW_POSITION_Y;
+extern char const *const ATTR_WINDOW_WIDTH;
+extern char const *const ATTR_WINDOW_HEIGHT;
+
+extern char const *const ATTR_WINDOW_MEMORY_REGION;
+extern char const *const ATTR_WINDOW_MEMORY_REVERSE_COLUMNS;
+extern char const *const ATTR_WINDOW_MEMORY_ADDRESS_MODE;
+extern char const *const ATTR_WINDOW_MEMORY_ADDRESS_RADIX;
+extern char const *const ATTR_WINDOW_MEMORY_DATA_FORMAT;
+extern char const *const ATTR_WINDOW_MEMORY_ROW_CHUNKS;
+
+extern char const *const ATTR_WINDOW_DISASSEMBLY_CPU;
+extern char const *const ATTR_WINDOW_DISASSEMBLY_RIGHT_COLUMN;
+
+extern char const *const ATTR_WINDOW_POINTS_TYPE;
+
+extern char const *const ATTR_WINDOW_DEVICE_TAG;
+
+extern char const *const ATTR_COLORS_THEME;
+
+extern char const *const ATTR_SPLITS_CONSOLE_STATE;
+extern char const *const ATTR_SPLITS_CONSOLE_DISASSEMBLY;
+
+extern char const *const ATTR_SELECTION_CURSOR_VISIBLE;
+extern char const *const ATTR_SELECTION_CURSOR_X;
+extern char const *const ATTR_SELECTION_CURSOR_Y;
+
+extern char const *const ATTR_SCROLL_ORIGIN_X;
+extern char const *const ATTR_SCROLL_ORIGIN_Y;
+
+} // namespace osd::debugger
+
+#endif // MAME_OSD_DEBUGGER_XMLCONFIG_H
diff --git a/src/osd/modules/diagnostics/diagnostics_win32.cpp b/src/osd/modules/diagnostics/diagnostics_win32.cpp
index 677cd93bff7..660d4d91682 100644
--- a/src/osd/modules/diagnostics/diagnostics_win32.cpp
+++ b/src/osd/modules/diagnostics/diagnostics_win32.cpp
@@ -9,12 +9,13 @@
#include "emu.h"
#include "diagnostics_module.h"
+#include "corestr.h"
+
#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
// standard windows headers
#include <windows.h>
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
#include <debugger.h>
#include <psapi.h>
@@ -99,7 +100,7 @@ private:
void scan_cache_for_address(uintptr_t address);
void format_symbol(const char *name, uint32_t displacement, const char *filename = nullptr, int linenumber = 0);
- static uintptr_t get_text_section_base();
+ static uintptr_t get_text_section_base(ULONG &size);
struct cache_entry
{
@@ -115,8 +116,9 @@ private:
std::string m_symfile;
std::string m_buffer;
HANDLE m_process;
- uintptr_t m_last_base;
- uintptr_t m_text_base;
+ uintptr_t m_last_base;
+ uintptr_t m_text_base;
+ ULONG m_text_size;
osd::dynamic_module::ptr m_dbghelp_dll;
@@ -167,8 +169,8 @@ bool stack_walker::s_initialized = false;
// stack_walker - constructor
//-------------------------------------------------
-stack_walker::stack_walker()
- : m_process(GetCurrentProcess()),
+stack_walker::stack_walker() :
+ m_process(GetCurrentProcess()),
m_thread(GetCurrentThread()),
m_first(true)
{
@@ -214,14 +216,18 @@ bool stack_walker::reset()
m_stackframe.AddrStack.Mode = AddrModeFlat;
// pull architecture-specific fields from the context
-#ifdef PTR64
+#if defined(__x86_64__) || defined(_M_X64)
m_stackframe.AddrPC.Offset = m_context.Rip;
m_stackframe.AddrFrame.Offset = m_context.Rsp;
m_stackframe.AddrStack.Offset = m_context.Rsp;
-#else
+#elif defined(__i386__) || defined(_M_IX86)
m_stackframe.AddrPC.Offset = m_context.Eip;
m_stackframe.AddrFrame.Offset = m_context.Ebp;
m_stackframe.AddrStack.Offset = m_context.Esp;
+#elif defined(__aarch64__) || defined(_M_ARM64)
+ m_stackframe.AddrPC.Offset = m_context.Pc;
+ m_stackframe.AddrFrame.Offset = m_context.Fp;
+ m_stackframe.AddrStack.Offset = m_context.Sp;
#endif
return true;
}
@@ -240,14 +246,18 @@ void stack_walker::reset(CONTEXT &initial, HANDLE thread)
m_stackframe.AddrStack.Mode = AddrModeFlat;
// pull architecture-specific fields from the context
-#ifdef PTR64
+#if defined(__x86_64__) || defined(_M_X64)
m_stackframe.AddrPC.Offset = m_context.Rip;
m_stackframe.AddrFrame.Offset = m_context.Rsp;
m_stackframe.AddrStack.Offset = m_context.Rsp;
-#else
+#elif defined(__i386__) || defined(_M_IX86)
m_stackframe.AddrPC.Offset = m_context.Eip;
m_stackframe.AddrFrame.Offset = m_context.Ebp;
m_stackframe.AddrStack.Offset = m_context.Esp;
+#elif defined(__aarch64__) || defined(_M_ARM64)
+ m_stackframe.AddrPC.Offset = m_context.Pc;
+ m_stackframe.AddrFrame.Offset = m_context.Fp;
+ m_stackframe.AddrStack.Offset = m_context.Sp;
#endif
}
@@ -261,10 +271,14 @@ bool stack_walker::unwind()
// if we were able to initialize, then we have everything we need
if (s_initialized)
{
-#ifdef PTR64
+#if defined(__x86_64__) || defined(_M_X64)
return (*m_stack_walk_64)(IMAGE_FILE_MACHINE_AMD64, m_process, m_thread, &m_stackframe, &m_context, nullptr, *m_sym_function_table_access_64, *m_sym_get_module_base_64, nullptr);
-#else
+#elif defined(__i386__) || defined(_M_IX86)
return (*m_stack_walk_64)(IMAGE_FILE_MACHINE_I386, m_process, m_thread, &m_stackframe, &m_context, nullptr, *m_sym_function_table_access_64, *m_sym_get_module_base_64, nullptr);
+#elif defined(__aarch64__) || defined(_M_ARM64)
+ return (*m_stack_walk_64)(IMAGE_FILE_MACHINE_ARM64, m_process, m_thread, &m_stackframe, &m_context, nullptr, *m_sym_function_table_access_64, *m_sym_get_module_base_64, nullptr);
+#else
+ return false;
#endif
}
@@ -287,8 +301,8 @@ bool stack_walker::unwind()
// symbol_manager - constructor
//-------------------------------------------------
-symbol_manager::symbol_manager(const char *argv0)
- : m_mapfile(argv0),
+symbol_manager::symbol_manager(const char *argv0) :
+ m_mapfile(argv0),
m_symfile(argv0),
m_process(GetCurrentProcess()),
m_last_base(0),
@@ -298,7 +312,7 @@ symbol_manager::symbol_manager(const char *argv0)
// compute the name of the mapfile
int extoffs = m_mapfile.find_last_of('.');
if (extoffs != -1)
- m_mapfile.substr(0, extoffs);
+ m_mapfile = m_mapfile.substr(0, extoffs);
m_mapfile.append(".map");
// and the name of the symfile
@@ -308,7 +322,7 @@ symbol_manager::symbol_manager(const char *argv0)
m_symfile.append(".sym");
// figure out the base of the .text section
- m_text_base = get_text_section_base();
+ m_text_base = get_text_section_base(m_text_size);
#endif
// expand the buffer to be decently large up front
@@ -377,6 +391,10 @@ bool symbol_manager::query_system_for_address(uintptr_t address)
info.MaxNameLen = sizeof(info_buffer) - sizeof(info);
if ((*m_sym_from_addr)(m_process, address, &displacement, &info))
{
+ // if the address is within our image, but the symbol is at or below the text base, it's useless (lld produces these)
+ if (info.Address <= m_text_base && address > m_text_base && address < m_text_base + m_text_size)
+ return false;
+
// try to get source info as well; again we are returned an ANSI string
IMAGEHLP_LINE64 lineinfo = { sizeof(lineinfo) };
DWORD linedisp;
@@ -503,6 +521,9 @@ bool symbol_manager::parse_sym_line(const char *line, uintptr_t &address, std::s
// first look for a (ty) entry
const char *type = strstr(line, "(ty 20)");
if (type == nullptr)
+ type = strstr(line, "(ty 20)");
+
+ if (type == nullptr)
return false;
// scan forward in the line to find the address
@@ -529,7 +550,7 @@ bool symbol_manager::parse_sym_line(const char *line, uintptr_t &address, std::s
chptr++;
// extract the symbol name
- strtrimspace(symbol.assign(chptr));
+ symbol.assign(strtrimspace(chptr));
return (symbol.length() > 0);
}
}
@@ -569,7 +590,7 @@ bool symbol_manager::parse_map_line(const char *line, uintptr_t &address, std::s
chptr++;
// extract the symbol name
- strtrimspace(symbol.assign(chptr));
+ symbol.assign(strtrimspace(chptr));
return (symbol.length() > 0);
}
#endif
@@ -602,7 +623,7 @@ void symbol_manager::format_symbol(const char *name, uint32_t displacement, cons
// of the .text section
//-------------------------------------------------
-uintptr_t symbol_manager::get_text_section_base()
+uintptr_t symbol_manager::get_text_section_base(ULONG &size)
{
osd::dynamic_module::ptr m_dbghelp_dll = osd::dynamic_module::open({ "dbghelp.dll" });
@@ -610,7 +631,7 @@ uintptr_t symbol_manager::get_text_section_base()
ImageNtHeader_fn image_nt_header = m_dbghelp_dll->bind<ImageNtHeader_fn>("ImageNtHeader");
// start with the image base
- PVOID base = reinterpret_cast<PVOID>(GetModuleHandleUni());
+ auto base = reinterpret_cast<PVOID>(GetModuleHandleUni());
assert(base != nullptr);
// make sure we have the functions we need
@@ -623,10 +644,14 @@ uintptr_t symbol_manager::get_text_section_base()
// look ourself up (assuming we are in the .text section)
PIMAGE_SECTION_HEADER section = (*image_rva_to_section)(headers, base, reinterpret_cast<uintptr_t>(get_text_section_base) - reinterpret_cast<uintptr_t>(base));
if (section != nullptr)
+ {
+ size = section->SizeOfRawData;
return reinterpret_cast<uintptr_t>(base) + section->VirtualAddress;
+ }
}
// fallback to returning the image base (wrong)
+ size = 0;
return reinterpret_cast<uintptr_t>(base);
}
@@ -640,8 +665,8 @@ uintptr_t symbol_manager::get_text_section_base()
// sampling_profiler - constructor
//-------------------------------------------------
-sampling_profiler::sampling_profiler(uint32_t max_seconds, uint8_t stack_depth = 0)
- : m_target_thread(nullptr),
+sampling_profiler::sampling_profiler(uint32_t max_seconds, uint8_t stack_depth = 0) :
+ m_target_thread(nullptr),
m_thread(nullptr),
m_thread_id(0),
m_thread_exit(false),
@@ -663,7 +688,7 @@ sampling_profiler::~sampling_profiler()
}
-//-------------------------------------------------
+////-------------------------------------------------
// start - begin gathering profiling information
//-------------------------------------------------
@@ -712,8 +737,8 @@ void sampling_profiler::stop()
int CLIB_DECL sampling_profiler::compare_address(const void *item1, const void *item2)
{
- const uintptr_t *entry1 = reinterpret_cast<const uintptr_t *>(item1);
- const uintptr_t *entry2 = reinterpret_cast<const uintptr_t *>(item2);
+ const auto *entry1 = reinterpret_cast<const uintptr_t *>(item1);
+ const auto *entry2 = reinterpret_cast<const uintptr_t *>(item2);
int mincount = std::min(entry1[0], entry2[0]);
// sort in order of: bucket, caller, caller's caller, etc.
@@ -733,8 +758,8 @@ int CLIB_DECL sampling_profiler::compare_address(const void *item1, const void *
int CLIB_DECL sampling_profiler::compare_frequency(const void *item1, const void *item2)
{
- const uintptr_t *entry1 = reinterpret_cast<const uintptr_t *>(item1);
- const uintptr_t *entry2 = reinterpret_cast<const uintptr_t *>(item2);
+ const auto *entry1 = reinterpret_cast<const uintptr_t *>(item1);
+ const auto *entry2 = reinterpret_cast<const uintptr_t *>(item2);
// sort by frequency, then by address
if (entry1[0] != entry2[0])
@@ -984,7 +1009,7 @@ private:
// print the state of the CPU
fprintf(stderr, "-----------------------------------------------------\n");
-#ifdef PTR64
+#if defined(__x86_64__) || defined(_M_X64)
fprintf(stderr, "RAX=%p RBX=%p RCX=%p RDX=%p\n",
(void *)info->ContextRecord->Rax,
(void *)info->ContextRecord->Rbx,
@@ -1005,7 +1030,7 @@ private:
(void *)info->ContextRecord->R13,
(void *)info->ContextRecord->R14,
(void *)info->ContextRecord->R15);
-#else
+#elif defined(__i386__) || defined(_M_IX86)
fprintf(stderr, "EAX=%p EBX=%p ECX=%p EDX=%p\n",
(void *)info->ContextRecord->Eax,
(void *)info->ContextRecord->Ebx,
@@ -1016,6 +1041,47 @@ private:
(void *)info->ContextRecord->Edi,
(void *)info->ContextRecord->Ebp,
(void *)info->ContextRecord->Esp);
+#elif defined(__aarch64__) || defined(_M_ARM64)
+ fprintf(stderr, " X0=%p X1=%p X2=%p X3=%p\n",
+ (void *)info->ContextRecord->X0,
+ (void *)info->ContextRecord->X1,
+ (void *)info->ContextRecord->X2,
+ (void *)info->ContextRecord->X3);
+ fprintf(stderr, " X4=%p X5=%p X6=%p X7=%p\n",
+ (void *)info->ContextRecord->X4,
+ (void *)info->ContextRecord->X5,
+ (void *)info->ContextRecord->X6,
+ (void *)info->ContextRecord->X7);
+ fprintf(stderr, " X8=%p X9=%p X10=%p X11=%p\n",
+ (void *)info->ContextRecord->X8,
+ (void *)info->ContextRecord->X9,
+ (void *)info->ContextRecord->X10,
+ (void *)info->ContextRecord->X11);
+ fprintf(stderr, "X12=%p X13=%p X14=%p X15=%p\n",
+ (void *)info->ContextRecord->X12,
+ (void *)info->ContextRecord->X13,
+ (void *)info->ContextRecord->X14,
+ (void *)info->ContextRecord->X15);
+ fprintf(stderr, "X16=%p X17=%p X18=%p X19=%p\n",
+ (void *)info->ContextRecord->X16,
+ (void *)info->ContextRecord->X17,
+ (void *)info->ContextRecord->X18,
+ (void *)info->ContextRecord->X19);
+ fprintf(stderr, "X20=%p X21=%p X22=%p X23=%p\n",
+ (void *)info->ContextRecord->X20,
+ (void *)info->ContextRecord->X21,
+ (void *)info->ContextRecord->X22,
+ (void *)info->ContextRecord->X23);
+ fprintf(stderr, "X24=%p X25=%p X26=%p X27=%p\n",
+ (void *)info->ContextRecord->X24,
+ (void *)info->ContextRecord->X25,
+ (void *)info->ContextRecord->X26,
+ (void *)info->ContextRecord->X27);
+ fprintf(stderr, "X28=%p FP=%p LR=%p SP=%p\n",
+ (void *)info->ContextRecord->X28,
+ (void *)info->ContextRecord->Fp,
+ (void *)info->ContextRecord->Lr,
+ (void *)info->ContextRecord->Sp);
#endif
// reprint the actual exception address
@@ -1087,6 +1153,4 @@ diagnostics_module * diagnostics_module::get_instance()
return &s_instance;
}
-#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-
#endif
diff --git a/src/osd/modules/diagnostics/none.cpp b/src/osd/modules/diagnostics/none.cpp
index 8a731fe9009..4663e8aa4d8 100644
--- a/src/osd/modules/diagnostics/none.cpp
+++ b/src/osd/modules/diagnostics/none.cpp
@@ -35,13 +35,8 @@ public:
// Determine if diagnostics_none should be used based on OSD
#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
-#include <winapifamily.h>
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
#define USE_DIAG_NONE 0 // Desktop Windows
#else
-#define USE_DIAG_NONE 1 // Universal Windows
-#endif
-#else
#define USE_DIAG_NONE 1 // SDL and others
#endif
diff --git a/src/osd/modules/file/posixdir.cpp b/src/osd/modules/file/posixdir.cpp
index 2a755a513fe..282a58acfc9 100644
--- a/src/osd/modules/file/posixdir.cpp
+++ b/src/osd/modules/file/posixdir.cpp
@@ -22,7 +22,7 @@
#endif
#endif
-#ifdef WIN32
+#ifdef _WIN32
#define _FILE_OFFSET_BITS 64
#endif
@@ -40,6 +40,7 @@
#define _DARWIN_C_SOURCE // to get DT_xxx on OS X
#include "osdcore.h"
+#include "osdfile.h"
#include "modules/lib/osdlib.h"
#include "util/strformat.h"
@@ -62,13 +63,13 @@ namespace {
// CONSTANTS
//============================================================
-#if defined(WIN32)
+#if defined(_WIN32)
constexpr char PATHSEPCH = '\\';
#else
constexpr char PATHSEPCH = '/';
#endif
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__EMSCRIPTEN__) || defined(__ANDROID__) || defined(WIN32) || defined(SDLMAME_NO64BITIO)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__EMSCRIPTEN__) || defined(__ANDROID__) || defined(_WIN32) || defined(SDLMAME_NO64BITIO)
using sdl_dirent = struct dirent;
using sdl_stat = struct stat;
#define sdl_readdir readdir
@@ -192,7 +193,7 @@ bool posix_directory::open_impl(std::string const &dirname)
{
assert(!m_fd);
- osd_subst_env(m_path, dirname);
+ m_path = dirname;
m_fd.reset(::opendir(m_path.c_str()));
return bool(m_fd);
}
@@ -223,7 +224,7 @@ directory::ptr directory::open(std::string const &dirname)
// osd_subst_env
//============================================================
-void osd_subst_env(std::string &dst, std::string const &src)
+std::string osd_subst_env(std::string_view src)
{
std::string result, var;
auto start = src.begin();
@@ -291,5 +292,5 @@ void osd_subst_env(std::string &dst, std::string const &src)
}
}
- dst = std::move(result);
+ return result;
}
diff --git a/src/osd/modules/file/posixdomain.cpp b/src/osd/modules/file/posixdomain.cpp
deleted file mode 100644
index 633187819a7..00000000000
--- a/src/osd/modules/file/posixdomain.cpp
+++ /dev/null
@@ -1,207 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Olivier Galibert, R. Belmont, Vas Crabb
-//============================================================
-//
-// sdldomain.c - SDL socket (unix) access functions
-//
-// SDLMAME by Olivier Galibert and R. Belmont
-//
-//============================================================
-
-#include "posixfile.h"
-
-#include <cassert>
-#include <cerrno>
-#include <cstdio>
-
-#include <sys/select.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-
-namespace {
-char const *const posixfile_domain_identifier = "domain.";
-
-
-class posix_osd_domain : public osd_file
-{
-public:
- posix_osd_domain(posix_osd_domain const &) = delete;
- posix_osd_domain(posix_osd_domain &&) = delete;
- posix_osd_domain& operator=(posix_osd_domain const &) = delete;
- posix_osd_domain& operator=(posix_osd_domain &&) = delete;
-
- posix_osd_domain(int sock, bool listening)
- : m_sock(sock)
- , m_listening(listening)
- {
- assert(m_sock >= 0);
- }
-
- virtual ~posix_osd_domain()
- {
- ::close(m_sock);
- }
-
- virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override
- {
- fd_set readfds;
- FD_ZERO(&readfds);
- FD_SET(m_sock, &readfds);
-
- struct timeval timeout;
- timeout.tv_sec = timeout.tv_usec = 0;
-
- if (select(m_sock + 1, &readfds, nullptr, nullptr, &timeout) < 0)
- {
- char line[80];
- std::sprintf(line, "%s : %s : %d ", __func__, __FILE__, __LINE__);
- std::perror(line);
- return errno_to_file_error(errno);
- }
- else if (FD_ISSET(m_sock, &readfds))
- {
- if (!m_listening)
- {
- // connected socket
- ssize_t const result = ::read(m_sock, buffer, count);
- if (result < 0)
- {
- return errno_to_file_error(errno);
- }
- else
- {
- actual = std::uint32_t(size_t(result));
- return error::NONE;
- }
- }
- else
- {
- // listening socket
- int const accepted = ::accept(m_sock, nullptr, nullptr);
- if (accepted < 0)
- {
- return errno_to_file_error(errno);
- }
- else
- {
- ::close(m_sock);
- m_sock = accepted;
- m_listening = false;
- actual = 0;
-
- return error::NONE;
- }
- }
- }
- else
- {
- return error::FAILURE;
- }
- }
-
- virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override
- {
- ssize_t const result = ::write(m_sock, buffer, count);
- if (result < 0)
- return errno_to_file_error(errno);
-
- actual = std::uint32_t(size_t(result));
- return error::NONE;
- }
-
- virtual error truncate(std::uint64_t offset) override
- {
- // doesn't make sense on socket
- return error::INVALID_ACCESS;
- }
-
- virtual error flush() override
- {
- // there's no simple way to flush buffers on a socket anyway
- return error::NONE;
- }
-
-private:
- int m_sock;
- bool m_listening;
-};
-
-} // anonymous namespace
-
-
-bool posix_check_domain_path(std::string const &path)
-{
- if (strncmp(path.c_str(), posixfile_domain_identifier, strlen(posixfile_domain_identifier)) == 0)
- return true;
- return false;
-}
-
-
-osd_file::error posix_open_domain(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize)
-{
- struct sockaddr_un sau;
- memset(&sau, 0, sizeof(sau));
- sau.sun_family = AF_UNIX;
- strncpy(sau.sun_path, &path.c_str()[strlen(posixfile_domain_identifier)], sizeof(sau.sun_path)-1);
-
- int const sock = ::socket(AF_UNIX, SOCK_STREAM, 0);
- if (sock < 0)
- return errno_to_file_error(errno);
-
- fcntl(sock, F_SETFL, O_NONBLOCK);
-
- // listening socket support
- if (openflags & OPEN_FLAG_CREATE)
- {
- if (::bind(sock, reinterpret_cast<struct sockaddr const *>(&sau), sizeof(struct sockaddr_un)) < 0)
- {
- int const err = errno;
- ::close(sock);
- return errno_to_file_error(err);
- }
-
- // start to listen...
- if (::listen(sock, 1) < 0)
- {
- int const err = errno;
- ::close(sock);
- return errno_to_file_error(err);
- }
-
- // mark socket as "listening"
- try
- {
- file = std::make_unique<posix_osd_domain>(sock, true);
- filesize = 0;
- return osd_file::error::NONE;
- }
- catch (...)
- {
- ::close(sock);
- return osd_file::error::OUT_OF_MEMORY;
- }
- }
- else
- {
- if (::connect(sock, reinterpret_cast<struct sockaddr const *>(&sau), sizeof(struct sockaddr_un)) < 0)
- {
- ::close(sock);
- return osd_file::error::ACCESS_DENIED; // have to return this value or bitb won't try to bind on connect failure
- }
- try
- {
- file = std::make_unique<posix_osd_domain>(sock, false);
- filesize = 0;
- return osd_file::error::NONE;
- }
- catch (...)
- {
- ::close(sock);
- return osd_file::error::OUT_OF_MEMORY;
- }
- }
-}
diff --git a/src/osd/modules/file/posixfile.cpp b/src/osd/modules/file/posixfile.cpp
index 8c78d28cbd5..8aebde2adc2 100644
--- a/src/osd/modules/file/posixfile.cpp
+++ b/src/osd/modules/file/posixfile.cpp
@@ -22,7 +22,7 @@
#endif
#endif
-#ifdef WIN32
+#ifdef _WIN32
#define _FILE_OFFSET_BITS 64
#endif
@@ -37,8 +37,14 @@
#endif
#endif
+// Fix for MacOS compilation errors
+#if defined(__APPLE__) && !defined(_DARWIN_C_SOURCE)
+#define _DARWIN_C_SOURCE
+#endif
+
// MAME headers
#include "posixfile.h"
+#include "osdcore.h"
#include "unicode.h"
#include <cassert>
@@ -50,19 +56,20 @@
#include <vector>
#include <fcntl.h>
-#include <limits.h>
+#include <climits>
#include <sys/stat.h>
-#include <stdlib.h>
+#include <cstdlib>
#include <unistd.h>
namespace {
+
//============================================================
// CONSTANTS
//============================================================
-#if defined(WIN32)
+#if defined(_WIN32)
constexpr char PATHSEPCH = '\\';
constexpr char INVPATHSEPCH = '/';
#else
@@ -79,7 +86,7 @@ public:
posix_osd_file& operator=(posix_osd_file const &) = delete;
posix_osd_file& operator=(posix_osd_file &&) = delete;
- posix_osd_file(int fd) : m_fd(fd)
+ posix_osd_file(int fd) noexcept : m_fd(fd)
{
assert(m_fd >= 0);
}
@@ -89,68 +96,68 @@ public:
::close(m_fd);
}
- virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override
+ virtual std::error_condition read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) noexcept override
{
ssize_t result;
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__EMSCRIPTEN__) || defined(__ANDROID__)
result = ::pread(m_fd, buffer, size_t(count), off_t(std::make_unsigned_t<off_t>(offset)));
-#elif defined(WIN32) || defined(SDLMAME_NO64BITIO)
+#elif defined(_WIN32) || defined(SDLMAME_NO64BITIO)
if (lseek(m_fd, off_t(std::make_unsigned_t<off_t>(offset)), SEEK_SET) < 0)
- return errno_to_file_error(errno)
+ return std::error_condition(errno, std::generic_category());
result = ::read(m_fd, buffer, size_t(count));
#else
result = ::pread64(m_fd, buffer, size_t(count), off64_t(offset));
#endif
if (result < 0)
- return errno_to_file_error(errno);
+ return std::error_condition(errno, std::generic_category());
actual = std::uint32_t(std::size_t(result));
- return error::NONE;
+ return std::error_condition();
}
- virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override
+ virtual std::error_condition write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) noexcept override
{
ssize_t result;
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__EMSCRIPTEN__) || defined(__ANDROID__)
result = ::pwrite(m_fd, buffer, size_t(count), off_t(std::make_unsigned_t<off_t>(offset)));
-#elif defined(WIN32) || defined(SDLMAME_NO64BITIO)
+#elif defined(_WIN32) || defined(SDLMAME_NO64BITIO)
if (lseek(m_fd, off_t(std::make_unsigned_t<off_t>(offset)), SEEK_SET) < 0)
- return errno_to_file_error(errno)
+ return std::error_condition(errno, std::generic_category());
result = ::write(m_fd, buffer, size_t(count));
#else
result = ::pwrite64(m_fd, buffer, size_t(count), off64_t(offset));
#endif
if (result < 0)
- return errno_to_file_error(errno);
+ return std::error_condition(errno, std::generic_category());
actual = std::uint32_t(std::size_t(result));
- return error::NONE;
+ return std::error_condition();
}
- virtual error truncate(std::uint64_t offset) override
+ virtual std::error_condition truncate(std::uint64_t offset) noexcept override
{
int result;
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__EMSCRIPTEN__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__EMSCRIPTEN__) || defined(_WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__)
result = ::ftruncate(m_fd, off_t(std::make_unsigned_t<off_t>(offset)));
#else
result = ::ftruncate64(m_fd, off64_t(offset));
#endif
if (result < 0)
- return errno_to_file_error(errno);
+ return std::error_condition(errno, std::generic_category());
- return error::NONE;
+ return std::error_condition();
}
- virtual error flush() override
+ virtual std::error_condition flush() noexcept override
{
// no user-space buffering on unistd I/O
- return error::NONE;
+ return std::error_condition();
}
private:
@@ -162,9 +169,9 @@ private:
// is_path_separator
//============================================================
-bool is_path_separator(char c)
+bool is_path_separator(char c) noexcept
{
-#if defined(WIN32)
+#if defined(_WIN32)
return (c == PATHSEPCH) || (c == INVPATHSEPCH);
#else
return c == PATHSEPCH;
@@ -176,31 +183,36 @@ bool is_path_separator(char c)
// create_path_recursive
//============================================================
-osd_file::error create_path_recursive(std::string const &path)
+std::error_condition create_path_recursive(std::string_view path) noexcept
{
// if there's still a separator, and it's not the root, nuke it and recurse
auto const sep = path.rfind(PATHSEPCH);
- if ((sep != std::string::npos) && (sep > 0) && (path[sep - 1] != PATHSEPCH))
+ if ((sep != std::string_view::npos) && (sep > 0) && (path[sep - 1] != PATHSEPCH))
{
- osd_file::error const err = create_path_recursive(path.substr(0, sep));
- if (err != osd_file::error::NONE)
+ std::error_condition err = create_path_recursive(path.substr(0, sep));
+ if (err)
return err;
}
+ // need a NUL-terminated version of the subpath
+ std::string p;
+ try { p = path; }
+ catch (...) { return std::errc::not_enough_memory; }
+
// if the path already exists, we're done
struct stat st;
- if (!::stat(path.c_str(), &st))
- return osd_file::error::NONE;
+ if (!::stat(p.c_str(), &st))
+ return std::error_condition();
// create the path
-#ifdef WIN32
- if (mkdir(path.c_str()) < 0)
+#ifdef _WIN32
+ if (mkdir(p.c_str()) < 0)
#else
- if (mkdir(path.c_str(), 0777) < 0)
+ if (mkdir(p.c_str(), 0777) < 0)
#endif
- return errno_to_file_error(errno);
+ return std::error_condition(errno, std::generic_category());
else
- return osd_file::error::NONE;
+ return std::error_condition();
}
} // anonymous namespace
@@ -210,7 +222,7 @@ osd_file::error create_path_recursive(std::string const &path)
// osd_file::open
//============================================================
-osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, ptr &file, std::uint64_t &filesize)
+std::error_condition osd_file::open(std::string const &path, std::uint32_t openflags, ptr &file, std::uint64_t &filesize) noexcept
{
std::string dst;
if (posix_check_socket_path(path))
@@ -233,23 +245,22 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags,
}
else
{
- return error::INVALID_ACCESS;
+ return std::errc::invalid_argument;
}
-#if defined(WIN32)
+#if defined(_WIN32)
access |= O_BINARY;
#endif
// convert the path into something compatible
dst = path;
-#if defined(WIN32)
+#if defined(_WIN32)
for (auto it = dst.begin(); it != dst.end(); ++it)
*it = (INVPATHSEPCH == *it) ? PATHSEPCH : *it;
#endif
- osd_subst_env(dst, dst);
// attempt to open the file
int fd = -1;
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(_WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__)
fd = ::open(dst.c_str(), access, 0666);
#else
fd = ::open64(dst.c_str(), access, 0666);
@@ -257,6 +268,9 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags,
if (fd < 0)
{
+ // save the error from the first attempt to open the file
+ std::error_condition openerr(errno, std::generic_category());
+
// create the path if necessary
if ((openflags & OPEN_FLAG_CREATE) && (openflags & OPEN_FLAG_CREATE_PATHS))
{
@@ -264,29 +278,33 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags,
if (pathsep != std::string::npos)
{
// create the path up to the file
- osd_file::error const error = create_path_recursive(dst.substr(0, pathsep));
+ std::error_condition const createrr = create_path_recursive(dst.substr(0, pathsep));
// attempt to reopen the file
- if (error == osd_file::error::NONE)
+ if (!createrr)
{
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(_WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__)
fd = ::open(dst.c_str(), access, 0666);
#else
fd = ::open64(dst.c_str(), access, 0666);
#endif
}
+ if (fd < 0)
+ {
+ openerr.assign(errno, std::generic_category());
+ }
}
}
// if we still failed, clean up and free
if (fd < 0)
{
- return errno_to_file_error(errno);
+ return openerr;
}
}
// get the file size
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(_WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__)
struct stat st;
if (::fstat(fd, &st) < 0)
#else
@@ -294,22 +312,20 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags,
if (::fstat64(fd, &st) < 0)
#endif
{
- int const error = errno;
+ std::error_condition staterr(errno, std::generic_category());
::close(fd);
- return errno_to_file_error(error);
+ return staterr;
}
- filesize = std::uint64_t(std::make_unsigned_t<decltype(st.st_size)>(st.st_size));
- try
- {
- file = std::make_unique<posix_osd_file>(fd);
- return error::NONE;
- }
- catch (...)
+ osd_file::ptr result(new (std::nothrow) posix_osd_file(fd));
+ if (!result)
{
::close(fd);
- return error::OUT_OF_MEMORY;
+ return std::errc::not_enough_memory;
}
+ file = std::move(result);
+ filesize = std::uint64_t(std::make_unsigned_t<decltype(st.st_size)>(st.st_size));
+ return std::error_condition();
}
@@ -317,9 +333,9 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags,
// osd_file::openpty
//============================================================
-osd_file::error osd_file::openpty(ptr &file, std::string &name)
+std::error_condition osd_file::openpty(ptr &file, std::string &name) noexcept
{
- std::uint64_t filesize;
+ std::uint64_t filesize;
return posix_open_ptty(OPEN_FLAG_READ | OPEN_FLAG_WRITE, file, filesize, name);
}
@@ -328,12 +344,12 @@ osd_file::error osd_file::openpty(ptr &file, std::string &name)
// osd_file::remove
//============================================================
-osd_file::error osd_file::remove(std::string const &filename)
+std::error_condition osd_file::remove(std::string const &filename) noexcept
{
if (::unlink(filename.c_str()) < -1)
- return errno_to_file_error(errno);
+ return std::error_condition(errno, std::generic_category());
else
- return error::NONE;
+ return std::error_condition();
}
@@ -341,7 +357,7 @@ osd_file::error osd_file::remove(std::string const &filename)
// osd_get_physical_drive_geometry
//============================================================
-bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders, uint32_t *heads, uint32_t *sectors, uint32_t *bps)
+bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders, uint32_t *heads, uint32_t *sectors, uint32_t *bps) noexcept
{
return false; // no, no way, huh-uh, forget it
}
@@ -353,7 +369,7 @@ bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders,
std::unique_ptr<osd::directory::entry> osd_stat(const std::string &path)
{
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) || defined(__HAIKU__) || defined(_WIN32) || defined(SDLMAME_NO64BITIO) || defined(__ANDROID__)
struct stat st;
int const err = ::stat(path.c_str(), &st);
#else
@@ -364,13 +380,17 @@ std::unique_ptr<osd::directory::entry> osd_stat(const std::string &path)
// create an osd_directory_entry; be sure to make sure that the caller can
// free all resources by just freeing the resulting osd_directory_entry
- osd::directory::entry *result;
- try { result = reinterpret_cast<osd::directory::entry *>(::operator new(sizeof(*result) + path.length() + 1)); }
- catch (...) { return nullptr; }
+ auto const result = reinterpret_cast<osd::directory::entry *>(
+ ::operator new(
+ sizeof(osd::directory::entry) + path.length() + 1,
+ std::align_val_t(alignof(osd::directory::entry)),
+ std::nothrow));
+ if (!result) return nullptr;
new (result) osd::directory::entry;
- std::strcpy(reinterpret_cast<char *>(result) + sizeof(*result), path.c_str());
- result->name = reinterpret_cast<char *>(result) + sizeof(*result);
+ auto const resultname = reinterpret_cast<char *>(result) + sizeof(*result);
+ std::strcpy(resultname, path.c_str());
+ result->name = resultname;
result->type = S_ISDIR(st.st_mode) ? osd::directory::entry::entry_type::DIR : osd::directory::entry::entry_type::FILE;
result->size = std::uint64_t(std::make_unsigned_t<decltype(st.st_size)>(st.st_size));
result->last_modified = std::chrono::system_clock::from_time_t(st.st_mtime);
@@ -383,58 +403,58 @@ std::unique_ptr<osd::directory::entry> osd_stat(const std::string &path)
// osd_get_full_path
//============================================================
-osd_file::error osd_get_full_path(std::string &dst, std::string const &path)
+std::error_condition osd_get_full_path(std::string &dst, std::string const &path) noexcept
{
try
{
-#if defined(WIN32)
+#if defined(_WIN32)
std::vector<char> path_buffer(MAX_PATH);
if (::_fullpath(&path_buffer[0], path.c_str(), MAX_PATH))
{
dst = &path_buffer[0];
- return osd_file::error::NONE;
+ return std::error_condition();
}
else
{
- return osd_file::error::FAILURE;
+ return std::errc::io_error; // TODO: better error reporting?
}
#else
std::unique_ptr<char, void (*)(void *)> canonical(::realpath(path.c_str(), nullptr), &std::free);
if (canonical)
{
dst = canonical.get();
- return osd_file::error::NONE;
+ return std::error_condition();
}
std::vector<char> path_buffer(PATH_MAX);
if (::realpath(path.c_str(), &path_buffer[0]))
{
dst = &path_buffer[0];
- return osd_file::error::NONE;
+ return std::error_condition();
}
else if (path[0] == PATHSEPCH)
{
dst = path;
- return osd_file::error::NONE;
+ return std::error_condition();
}
else
{
while (!::getcwd(&path_buffer[0], path_buffer.size()))
{
if (errno != ERANGE)
- return errno_to_file_error(errno);
+ return std::error_condition(errno, std::generic_category());
else
path_buffer.resize(path_buffer.size() * 2);
}
dst.assign(&path_buffer[0]).push_back(PATHSEPCH);
dst.append(path);
- return osd_file::error::NONE;
+ return std::error_condition();
}
#endif
}
catch (...)
{
- return osd_file::error::OUT_OF_MEMORY;
+ return std::errc::not_enough_memory;
}
}
@@ -443,11 +463,11 @@ osd_file::error osd_get_full_path(std::string &dst, std::string const &path)
// osd_is_absolute_path
//============================================================
-bool osd_is_absolute_path(std::string const &path)
+bool osd_is_absolute_path(std::string const &path) noexcept
{
if (!path.empty() && is_path_separator(path[0]))
return true;
-#if !defined(WIN32)
+#if !defined(_WIN32)
else if (!path.empty() && (path[0] == '.') && (!path[1] || is_path_separator(path[1]))) // FIXME: why is this even here? foo/./bar is a valid way to refer to foo/bar
return true;
#elif !defined(UNDER_CE)
@@ -463,12 +483,22 @@ bool osd_is_absolute_path(std::string const &path)
// osd_get_volume_name
//============================================================
-const char *osd_get_volume_name(int idx)
+std::string osd_get_volume_name(int idx)
{
if (idx == 0)
return "/";
else
- return nullptr;
+ return std::string();
+}
+
+
+//============================================================
+// osd_get_volume_names
+//============================================================
+
+std::vector<std::string> osd_get_volume_names()
+{
+ return std::vector<std::string>{ "/" };
}
@@ -476,12 +506,12 @@ const char *osd_get_volume_name(int idx)
// osd_is_valid_filename_char
//============================================================
-bool osd_is_valid_filename_char(char32_t uchar)
+bool osd_is_valid_filename_char(char32_t uchar) noexcept
{
// The only one that's actually invalid is the slash
// The other two are just problematic because they're the escape character and path separator
return osd_is_valid_filepath_char(uchar)
-#if defined(WIN32)
+#if defined(_WIN32)
&& uchar != PATHSEPCH
&& uchar != INVPATHSEPCH
#else
@@ -496,12 +526,12 @@ bool osd_is_valid_filename_char(char32_t uchar)
// osd_is_valid_filepath_char
//============================================================
-bool osd_is_valid_filepath_char(char32_t uchar)
+bool osd_is_valid_filepath_char(char32_t uchar) noexcept
{
// One could argue that colon should be in here too because it functions as path separator
return uchar >= 0x20
&& !(uchar >= '\x7F' && uchar <= '\x9F')
-#if defined(WIN32)
+#if defined(_WIN32)
&& uchar != '<'
&& uchar != '>'
&& uchar != '\"'
@@ -511,39 +541,3 @@ bool osd_is_valid_filepath_char(char32_t uchar)
#endif
&& uchar_isvalid(uchar);
}
-
-
-//============================================================
-// errno_to_file_error
-//============================================================
-
-osd_file::error errno_to_file_error(int error)
-{
- switch (error)
- {
- case 0:
- return osd_file::error::NONE;
-
- case ENOENT:
- case ENOTDIR:
- return osd_file::error::NOT_FOUND;
-
- case EACCES:
- case EROFS:
-#ifndef WIN32
- case ETXTBSY:
-#endif
- case EEXIST:
- case EPERM:
- case EISDIR:
- case EINVAL:
- return osd_file::error::ACCESS_DENIED;
-
- case ENFILE:
- case EMFILE:
- return osd_file::error::TOO_MANY_FILES;
-
- default:
- return osd_file::error::FAILURE;
- }
-}
diff --git a/src/osd/modules/file/posixfile.h b/src/osd/modules/file/posixfile.h
index 6f585ff827a..eb6f010859e 100644
--- a/src/osd/modules/file/posixfile.h
+++ b/src/osd/modules/file/posixfile.h
@@ -7,25 +7,29 @@
// SDLMAME by Olivier Galibert and R. Belmont
//
//============================================================
+#ifndef MAME_OSD_MODULES_FILE_POSIXFILE_H
+#define MAME_OSD_MODULES_FILE_POSIXFILE_H
+#pragma once
-#include "osdcore.h"
+#include "osdfile.h"
#include <cstdint>
#include <string>
+#include <system_error>
//============================================================
// PROTOTYPES
//============================================================
-bool posix_check_socket_path(std::string const &path);
-osd_file::error posix_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize);
+bool posix_check_socket_path(std::string const &path) noexcept;
+std::error_condition posix_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept;
-bool posix_check_domain_path(std::string const &path);
-osd_file::error posix_open_domain(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize);
+bool posix_check_domain_path(std::string const &path) noexcept;
+std::error_condition posix_open_domain(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept;
-bool posix_check_ptty_path(std::string const &path);
-osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize, std::string &name);
+bool posix_check_ptty_path(std::string const &path) noexcept;
+std::error_condition posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize, std::string &name) noexcept;
-osd_file::error errno_to_file_error(int error);
+#endif // MAME_OSD_MODULES_FILE_POSIXFILE_H
diff --git a/src/osd/modules/file/posixptty.cpp b/src/osd/modules/file/posixptty.cpp
index 6e468cf172f..57ff069a2ce 100644
--- a/src/osd/modules/file/posixptty.cpp
+++ b/src/osd/modules/file/posixptty.cpp
@@ -15,11 +15,11 @@
#include <cstring>
#include <fcntl.h>
-#include <limits.h>
+#include <climits>
#include <unistd.h>
-#include <stdlib.h>
+#include <cstdlib>
-#if defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+#if defined(__FreeBSD__) || defined(__DragonFly__)
#include <termios.h>
#include <libutil.h>
#elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
@@ -52,7 +52,7 @@ public:
posix_osd_ptty& operator=(posix_osd_ptty const &) = delete;
posix_osd_ptty& operator=(posix_osd_ptty &&) = delete;
- posix_osd_ptty(int fd) : m_fd(fd)
+ posix_osd_ptty(int fd) noexcept : m_fd(fd)
{
assert(m_fd >= 0);
}
@@ -62,36 +62,36 @@ public:
::close(m_fd);
}
- virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override
+ virtual std::error_condition read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) noexcept override
{
ssize_t const result = ::read(m_fd, buffer, count);
if (result < 0)
- return errno_to_file_error(errno);
+ return std::error_condition(errno, std::generic_category());
actual = std::uint32_t(size_t(result));
- return error::NONE;
+ return std::error_condition();
}
- virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override
+ virtual std::error_condition write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) noexcept override
{
ssize_t const result = ::write(m_fd, buffer, count);
if (result < 0)
- return errno_to_file_error(errno);
+ return std::error_condition(errno, std::generic_category());
actual = std::uint32_t(size_t(result));
- return error::NONE;
+ return std::error_condition();
}
- virtual error truncate(std::uint64_t offset) override
+ virtual std::error_condition truncate(std::uint64_t offset) noexcept override
{
// doesn't make sense on ptty
- return error::INVALID_ACCESS;
+ return std::errc::bad_file_descriptor;
}
- virtual error flush() override
+ virtual std::error_condition flush() noexcept override
{
// no userspace buffers on read/write
- return error::NONE;
+ return std::error_condition();
}
private:
@@ -101,14 +101,18 @@ private:
} // anonymous namespace
-bool posix_check_ptty_path(std::string const &path)
+bool posix_check_ptty_path(std::string const &path) noexcept
{
return strncmp(path.c_str(), posix_ptty_identifier, strlen(posix_ptty_identifier)) == 0;
}
-osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize, std::string &name)
+std::error_condition posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize, std::string &name) noexcept
{
+#if defined(__ANDROID__)
+ return std::errc::not_supported; // TODO: revisit this error code
+#else // defined(__ANDROID__)
+ // TODO: handling of the slave path is insecure - should use ptsname_r/ttyname_r in a loop
#if (defined(sun) || defined(__sun)) && (defined(__SVR4) || defined(__svr4__))
int access = O_NOCTTY;
if (openflags & OPEN_FLAG_WRITE)
@@ -116,11 +120,11 @@ osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, st
else if (openflags & OPEN_FLAG_READ)
access |= O_RDONLY;
else
- return osd_file::error::INVALID_ACCESS;
+ return std::errc::invalid_argument;
int const masterfd = ::posix_openpt(access);
if (masterfd < 0)
- return errno_to_file_error(errno);
+ return std::error_condition(errno, std::generic_category());
// grant access to slave device and check that it can be opened
char const *slavepath;
@@ -130,9 +134,9 @@ osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, st
((slavepath = ::ptsname(masterfd)) == nullptr) ||
((slavefd = ::open(slavepath, O_RDWR | O_NOCTTY)) < 0))
{
- int const err = errno;
+ std::error_condition err(errno, std::generic_category());
::close(masterfd);
- return errno_to_file_error(err);
+ return err;
}
// check that it's possible to stack BSD-compatibility STREAMS modules
@@ -140,23 +144,20 @@ osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, st
(::ioctl(slavefd, I_PUSH, "ldterm") < 0) ||
(::ioctl(slavefd, I_PUSH, "ttcompat") < 0))
{
- int const err = errno;
+ std::error_condition err(errno, std::generic_category());
::close(slavefd);
::close(masterfd);
- return errno_to_file_error(err);
+ return err;
}
-#elif defined(__ANDROID__)
- int masterfd = -1, slavefd = -1;
- char slavepath[PATH_MAX];
#else
struct termios tios;
std::memset(&tios, 0, sizeof(tios));
- ::cfmakeraw(&tios);
+ ::cfmakeraw(&tios); // TODO: this is a non-standard BSDism - should set flags some other way
int masterfd = -1, slavefd = -1;
char slavepath[PATH_MAX];
if (::openpty(&masterfd, &slavefd, slavepath, &tios, nullptr) < 0)
- return errno_to_file_error(errno);
+ return std::error_condition(errno, std::generic_category());
#endif
::close(slavefd);
@@ -164,16 +165,16 @@ osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, st
int const oldflags = ::fcntl(masterfd, F_GETFL, 0);
if (oldflags < 0)
{
- int const err = errno;
+ std::error_condition err(errno, std::generic_category());
::close(masterfd);
- return errno_to_file_error(err);
+ return err;
}
if (::fcntl(masterfd, F_SETFL, oldflags | O_NONBLOCK) < 0)
{
- int const err = errno;
+ std::error_condition err(errno, std::generic_category());
::close(masterfd);
- return errno_to_file_error(err);
+ return err;
}
try
@@ -181,11 +182,12 @@ osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, st
name = slavepath;
file = std::make_unique<posix_osd_ptty>(masterfd);
filesize = 0;
- return osd_file::error::NONE;
+ return std::error_condition();
}
catch (...)
{
::close(masterfd);
- return osd_file::error::OUT_OF_MEMORY;
+ return std::errc::not_enough_memory;
}
+#endif // defined(__ANDROID__)
}
diff --git a/src/osd/modules/file/posixsocket.cpp b/src/osd/modules/file/posixsocket.cpp
index edb95816077..6a23e747ea1 100644
--- a/src/osd/modules/file/posixsocket.cpp
+++ b/src/osd/modules/file/posixsocket.cpp
@@ -2,7 +2,8 @@
// copyright-holders:Olivier Galibert, R. Belmont, Vas Crabb
//============================================================
//
-// sdlsocket.c - SDL socket (inet) access functions
+// sdlsocket.c - SDL socket (inet, unix domain) access
+// functions
//
// SDLMAME by Olivier Galibert and R. Belmont
//
@@ -13,19 +14,24 @@
#include <cassert>
#include <cerrno>
#include <cstdio>
+#include <cstring>
#include <arpa/inet.h>
+#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/time.h>
+#include <sys/un.h>
#include <unistd.h>
namespace {
+
char const *const posixfile_socket_identifier = "socket.";
+char const *const posixfile_domain_identifier = "domain.";
class posix_osd_socket : public osd_file
@@ -36,7 +42,7 @@ public:
posix_osd_socket& operator=(posix_osd_socket const &) = delete;
posix_osd_socket& operator=(posix_osd_socket &&) = delete;
- posix_osd_socket(int sock, bool listening)
+ posix_osd_socket(int sock, bool listening) noexcept
: m_sock(sock)
, m_listening(listening)
{
@@ -48,7 +54,7 @@ public:
::close(m_sock);
}
- virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override
+ virtual std::error_condition read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) noexcept override
{
fd_set readfds;
FD_ZERO(&readfds);
@@ -57,12 +63,9 @@ public:
struct timeval timeout;
timeout.tv_sec = timeout.tv_usec = 0;
- if (select(m_sock + 1, &readfds, nullptr, nullptr, &timeout) < 0)
+ if (::select(m_sock + 1, &readfds, nullptr, nullptr, &timeout) < 0)
{
- char line[80];
- std::sprintf(line, "%s : %s : %d ", __func__, __FILE__, __LINE__);
- std::perror(line);
- return errno_to_file_error(errno);
+ return std::error_condition(errno, std::generic_category());
}
else if (FD_ISSET(m_sock, &readfds))
{
@@ -72,12 +75,12 @@ public:
ssize_t const result = ::read(m_sock, buffer, count);
if (result < 0)
{
- return errno_to_file_error(errno);
+ return std::error_condition(errno, std::generic_category());
}
else
{
actual = std::uint32_t(size_t(result));
- return error::NONE;
+ return std::error_condition();
}
}
else
@@ -86,7 +89,7 @@ public:
int const accepted = ::accept(m_sock, nullptr, nullptr);
if (accepted < 0)
{
- return errno_to_file_error(errno);
+ return std::error_condition(errno, std::generic_category());
}
else
{
@@ -95,36 +98,38 @@ public:
m_listening = false;
actual = 0;
- return error::NONE;
+ return std::error_condition();
}
}
}
else
{
- return error::FAILURE;
+ // no data available
+ actual = 0;
+ return std::errc::operation_would_block;
}
}
- virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override
+ virtual std::error_condition write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) noexcept override
{
ssize_t const result = ::write(m_sock, buffer, count);
if (result < 0)
- return errno_to_file_error(errno);
+ return std::error_condition(errno, std::generic_category());
actual = std::uint32_t(size_t(result));
- return error::NONE;
+ return std::error_condition();
}
- virtual error truncate(std::uint64_t offset) override
+ virtual std::error_condition truncate(std::uint64_t offset) noexcept override
{
// doesn't make sense on socket
- return error::INVALID_ACCESS;
+ return std::errc::bad_file_descriptor;
}
- virtual error flush() override
+ virtual std::error_condition flush() noexcept override
{
// there's no simple way to flush buffers on a socket anyway
- return error::NONE;
+ return std::error_condition();
}
private:
@@ -132,6 +137,54 @@ private:
bool m_listening;
};
+
+template <typename T>
+std::error_condition create_socket(T const &sa, int sock, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept
+{
+ osd_file::ptr result;
+ if (openflags & OPEN_FLAG_CREATE)
+ {
+ // listening socket support
+ // bind socket...
+ if (::bind(sock, reinterpret_cast<struct sockaddr const *>(&sa), sizeof(sa)) < 0)
+ {
+ std::error_condition binderr(errno, std::generic_category());
+ ::close(sock);
+ return binderr;
+ }
+
+ // start to listen...
+ if (::listen(sock, 1) < 0)
+ {
+ std::error_condition lstnerr(errno, std::generic_category());
+ ::close(sock);
+ return lstnerr;
+ }
+
+ // mark socket as "listening"
+ result.reset(new (std::nothrow) posix_osd_socket(sock, true));
+ }
+ else
+ {
+ if (::connect(sock, reinterpret_cast<struct sockaddr const *>(&sa), sizeof(sa)) < 0)
+ {
+ std::error_condition connerr(errno, std::generic_category());
+ ::close(sock);
+ return connerr;
+ }
+ result.reset(new (std::nothrow) posix_osd_socket(sock, false));
+ }
+
+ if (!result)
+ {
+ ::close(sock);
+ return std::errc::not_enough_memory;
+ }
+ file = std::move(result);
+ filesize = 0;
+ return std::error_condition();
+}
+
} // anonymous namespace
@@ -140,7 +193,7 @@ private:
specification has the format "socket." host ":" port. Host may be simple
or fully qualified. Port must be between 1 and 65535.
*/
-bool posix_check_socket_path(std::string const &path)
+bool posix_check_socket_path(std::string const &path) noexcept
{
if (strncmp(path.c_str(), posixfile_socket_identifier, strlen(posixfile_socket_identifier)) == 0 &&
strchr(path.c_str(), ':') != nullptr) return true;
@@ -148,7 +201,15 @@ bool posix_check_socket_path(std::string const &path)
}
-osd_file::error posix_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize)
+bool posix_check_domain_path(std::string const &path) noexcept
+{
+ if (strncmp(path.c_str(), posixfile_domain_identifier, strlen(posixfile_domain_identifier)) == 0)
+ return true;
+ return false;
+}
+
+
+std::error_condition posix_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept
{
char hostname[256];
int port;
@@ -156,7 +217,7 @@ osd_file::error posix_open_socket(std::string const &path, std::uint32_t openfla
struct hostent const *const localhost = ::gethostbyname(hostname);
if (!localhost)
- return osd_file::error::NOT_FOUND;
+ return std::errc::no_such_file_or_directory;
struct sockaddr_in sai;
memset(&sai, 0, sizeof(sai));
@@ -166,75 +227,38 @@ osd_file::error posix_open_socket(std::string const &path, std::uint32_t openfla
int const sock = ::socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
- return errno_to_file_error(errno);
+ return std::error_condition(errno, std::generic_category());
int const flag = 1;
- if (::setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<const char *>(&flag), sizeof(flag)) < 0)
+ if ((::setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<const char *>(&flag), sizeof(flag)) < 0) ||
+ (::setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char *>(&flag), sizeof(flag)) < 0))
{
- int const err = errno;
+ std::error_condition sockopterr(errno, std::generic_category());
::close(sock);
- return errno_to_file_error(err);
+ return sockopterr;
}
- if (::setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char *>(&flag), sizeof(flag)) < 0)
- {
- int const err = errno;
- ::close(sock);
- return errno_to_file_error(err);
- }
+ return create_socket(sai, sock, openflags, file, filesize);
+}
- // listening socket support
- if (openflags & OPEN_FLAG_CREATE)
- {
- //printf("Listening for client at '%s' on port '%d'\n", hostname, port);
- // bind socket...
- if (::bind(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(struct sockaddr)) < 0)
- {
- int const err = errno;
- ::close(sock);
- return errno_to_file_error(err);
- }
+std::error_condition posix_open_domain(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept
+{
+ struct sockaddr_un sau;
+ memset(&sau, 0, sizeof(sau));
+ sau.sun_family = AF_UNIX;
+ strncpy(sau.sun_path, &path.c_str()[strlen(posixfile_domain_identifier)], sizeof(sau.sun_path)-1);
- // start to listen...
- if (::listen(sock, 1) < 0)
- {
- int const err = errno;
- ::close(sock);
- return errno_to_file_error(err);
- }
+ int const sock = ::socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0)
+ return std::error_condition(errno, std::generic_category());
- // mark socket as "listening"
- try
- {
- file = std::make_unique<posix_osd_socket>(sock, true);
- filesize = 0;
- return osd_file::error::NONE;
- }
- catch (...)
- {
- ::close(sock);
- return osd_file::error::OUT_OF_MEMORY;
- }
- }
- else
+ if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0)
{
- //printf("Connecting to server '%s' on port '%d'\n", hostname, port);
- if (::connect(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(struct sockaddr)) < 0)
- {
- ::close(sock);
- return osd_file::error::ACCESS_DENIED; // have to return this value or bitb won't try to bind on connect failure
- }
- try
- {
- file = std::make_unique<posix_osd_socket>(sock, false);
- filesize = 0;
- return osd_file::error::NONE;
- }
- catch (...)
- {
- ::close(sock);
- return osd_file::error::OUT_OF_MEMORY;
- }
+ std::error_condition cntlerr(errno, std::generic_category());
+ ::close(sock);
+ return cntlerr;
}
+
+ return create_socket(sau, sock, openflags, file, filesize);
}
diff --git a/src/osd/modules/file/stdfile.cpp b/src/osd/modules/file/stdfile.cpp
index cb1f1b536b2..4fd4662b884 100644
--- a/src/osd/modules/file/stdfile.cpp
+++ b/src/osd/modules/file/stdfile.cpp
@@ -7,11 +7,14 @@
//============================================================
#include "osdcore.h"
+#include "osdfile.h"
#include <cassert>
+#include <cerrno>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
+#include <limits>
#include <string>
#include <stdio.h> // for fileno
@@ -19,11 +22,15 @@
namespace {
+
class std_osd_file : public osd_file
{
public:
- std_osd_file(FILE *f) : m_file(f) { assert(m_file); }
+ std_osd_file(FILE *f) noexcept : m_file(f)
+ {
+ assert(m_file);
+ }
//============================================================
// osd_close
@@ -32,59 +39,81 @@ public:
virtual ~std_osd_file() override
{
// close the file handle
- if (m_file) std::fclose(m_file);
+ if (m_file)
+ std::fclose(m_file);
}
//============================================================
// osd_read
//============================================================
- virtual error read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) override
+ virtual std::error_condition read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) noexcept override
{
- // seek to the new location; note that most fseek implementations are limited to 32 bits
+ // seek to the new location; note that most fseek implementations are limited to the range of long int
+ if (std::numeric_limits<long>::max() < offset)
+ return std::errc::invalid_argument;
if (std::fseek(m_file, offset, SEEK_SET) < 0)
- return error::FAILURE;
+ return std::error_condition(errno, std::generic_category());
// perform the read
std::size_t const count = std::fread(buffer, 1, length, m_file);
+ if ((count < length) && std::ferror(m_file))
+ {
+ std::clearerr(m_file);
+ return std::error_condition(errno, std::generic_category());
+ }
actual = count;
- return error::NONE;
+ return std::error_condition();
}
//============================================================
// osd_write
//============================================================
- virtual error write(const void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) override
+ virtual std::error_condition write(const void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) noexcept override
{
- // seek to the new location; note that most fseek implementations are limited to 32 bits
+ // seek to the new location; note that most fseek implementations are limited to the range of long int
+ if (std::numeric_limits<long>::max() < offset)
+ return std::errc::invalid_argument;
if (std::fseek(m_file, offset, SEEK_SET) < 0)
- return error::FAILURE;
+ return std::error_condition(errno, std::generic_category());
// perform the write
std::size_t const count = std::fwrite(buffer, 1, length, m_file);
+ if (count < length)
+ {
+ std::clearerr(m_file);
+ return std::error_condition(errno, std::generic_category());
+ }
actual = count;
- return error::NONE;
+ return std::error_condition();
}
//============================================================
// osd_truncate
//============================================================
- error truncate(std::uint64_t offset) override
+ virtual std::error_condition truncate(std::uint64_t offset) noexcept override
{
- return (ftruncate(fileno(m_file), offset) < 0) ? error::FAILURE : error::NONE;
+ // this is present in POSIX but not C/C++
+ if (::ftruncate(::fileno(m_file), offset) < 0)
+ return std::error_condition(errno, std::generic_category());
+ else
+ return std::error_condition();
}
//============================================================
// osd_fflush
//============================================================
- virtual error flush() override
+ virtual std::error_condition flush() noexcept override
{
- return (std::fflush(m_file) == EOF) ? error::FAILURE : error::NONE;
+ if (!std::fflush(m_file))
+ return std::error_condition();
+ else
+ return std::error_condition(errno, std::generic_category());
}
private:
@@ -98,7 +127,7 @@ private:
// osd_open
//============================================================
-osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, ptr &file, std::uint64_t &filesize)
+std::error_condition osd_file::open(std::string const &path, std::uint32_t openflags, ptr &file, std::uint64_t &filesize) noexcept
{
// based on the flags, choose a mode
const char *mode;
@@ -112,12 +141,12 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags,
else if (openflags & OPEN_FLAG_READ)
mode = "rb";
else
- return error::INVALID_ACCESS;
+ return std::errc::invalid_argument;
// open the file
FILE *const fileptr = std::fopen(path.c_str(), mode);
if (!fileptr)
- return error::NOT_FOUND;
+ return std::error_condition(errno, std::generic_category());
// get the size -- note that most fseek/ftell implementations are limited to 32 bits
long length;
@@ -125,21 +154,20 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags,
((length = std::ftell(fileptr)) < 0) ||
(std::fseek(fileptr, 0, SEEK_SET) < 0))
{
+ std::error_condition err(errno, std::generic_category());
std::fclose(fileptr);
- return error::FAILURE;
+ return err;
}
- try
- {
- file = std::make_unique<std_osd_file>(fileptr);
- filesize = std::int64_t(length);
- return error::NONE;
- }
- catch (...)
+ osd_file::ptr result(new (std::nothrow) std_osd_file(fileptr));
+ if (!result)
{
std::fclose(fileptr);
- return error::OUT_OF_MEMORY;
+ return std::errc::not_enough_memory;
}
+ file = std::move(result);
+ filesize = std::int64_t(length);
+ return std::error_condition();
}
@@ -147,9 +175,9 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags,
// osd_openpty
//============================================================
-osd_file::error osd_file::openpty(ptr &file, std::string &name)
+std::error_condition osd_file::openpty(ptr &file, std::string &name) noexcept
{
- return error::FAILURE;
+ return std::errc::not_supported;
}
@@ -157,9 +185,12 @@ osd_file::error osd_file::openpty(ptr &file, std::string &name)
// osd_rmfile
//============================================================
-osd_file::error osd_file::remove(std::string const &filename)
+std::error_condition osd_file::remove(std::string const &filename) noexcept
{
- return (std::remove(filename.c_str()) < 0) ? error::FAILURE : error::NONE;
+ if (!std::remove(filename.c_str()))
+ return std::error_condition();
+ else
+ return std::error_condition(errno, std::generic_category());
}
@@ -167,7 +198,7 @@ osd_file::error osd_file::remove(std::string const &filename)
// osd_get_physical_drive_geometry
//============================================================
-bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders, uint32_t *heads, uint32_t *sectors, uint32_t *bps)
+bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders, uint32_t *heads, uint32_t *sectors, uint32_t *bps) noexcept
{
// there is no standard way of doing this, so we always return false, indicating
// that a given path is not a physical drive
@@ -179,7 +210,7 @@ bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders,
// osd_uchar_from_osdchar
//============================================================
-int osd_uchar_from_osdchar(char32_t *uchar, const char *osdchar, size_t count)
+int osd_uchar_from_osdchar(char32_t *uchar, const char *osdchar, size_t count) noexcept
{
// we assume a standard 1:1 mapping of characters to the first 256 unicode characters
*uchar = (uint8_t)*osdchar;
@@ -219,13 +250,14 @@ osd_directory_entry *osd_stat(const std::string &path)
// osd_get_full_path
//============================================================
-osd_file::error osd_get_full_path(std::string &dst, std::string const &path)
+std::error_condition osd_get_full_path(std::string &dst, std::string const &path) noexcept
{
// derive the full path of the file in an allocated string
// for now just fake it since we don't presume any underlying file system
- dst = path;
+ try { dst = path; }
+ catch (...) { return std::errc::not_enough_memory; }
- return osd_file::error::NONE;
+ return std::error_condition();
}
@@ -233,7 +265,7 @@ osd_file::error osd_get_full_path(std::string &dst, std::string const &path)
// osd_is_absolute_path
//============================================================
-bool osd_is_absolute_path(std::string const &path)
+bool osd_is_absolute_path(std::string const &path) noexcept
{
// assume no for everything
return false;
@@ -244,8 +276,19 @@ bool osd_is_absolute_path(std::string const &path)
// osd_get_volume_name
//============================================================
-const char *osd_get_volume_name(int idx)
+std::string osd_get_volume_name(int idx)
+{
+ // we don't expose volumes
+ return std::string();
+}
+
+
+//============================================================
+// osd_get_volume_names
+//============================================================
+
+std::vector<std::string> osd_get_volume_names()
{
// we don't expose volumes
- return nullptr;
+ return std::vector<std::string>();
}
diff --git a/src/osd/modules/file/windir.cpp b/src/osd/modules/file/windir.cpp
index f9575b27e74..34606dcba6f 100644
--- a/src/osd/modules/file/windir.cpp
+++ b/src/osd/modules/file/windir.cpp
@@ -12,7 +12,7 @@
#include <tchar.h>
// MAME headers
-#include "osdcore.h"
+#include "osdfile.h"
#include "strformat.h"
// MAMEOS headers
@@ -20,8 +20,8 @@
#include "winutil.h"
// standard C headers
-#include <stdio.h>
-#include <ctype.h>
+#include <cstdio>
+#include <cctype>
#include <cassert>
#include <cstring>
@@ -108,7 +108,7 @@ bool win_directory::open_impl(std::string const &dirname)
assert(m_find == INVALID_HANDLE_VALUE);
// append \*.* to the directory name
- std::string dirfilter = string_format("%s\\*.*", dirname);
+ std::string dirfilter = util::string_format("%s\\*.*", dirname);
// convert the path to TCHARs
osd::text::tstring t_dirfilter = osd::text::to_tstring(dirfilter);
diff --git a/src/osd/modules/file/winfile.cpp b/src/osd/modules/file/winfile.cpp
index 5df7c4bb8b1..84c754cdd6f 100644
--- a/src/osd/modules/file/winfile.cpp
+++ b/src/osd/modules/file/winfile.cpp
@@ -6,7 +6,6 @@
//
//============================================================
-
#include "winfile.h"
// MAMEOS headers
@@ -20,17 +19,19 @@
#include <cassert>
#include <cstring>
+#include <memory>
// standard windows headers
#include <windows.h>
#include <winioctl.h>
#include <tchar.h>
#include <shlwapi.h>
-#include <stdlib.h>
-#include <ctype.h>
+#include <cstdlib>
+#include <cctype>
namespace {
+
//============================================================
// TYPE DEFINITIONS
//============================================================
@@ -43,7 +44,7 @@ public:
win_osd_file& operator=(win_osd_file const &) = delete;
win_osd_file& operator=(win_osd_file &&) = delete;
- win_osd_file(HANDLE handle) : m_handle(handle)
+ win_osd_file(HANDLE handle) noexcept : m_handle(handle)
{
assert(m_handle);
assert(INVALID_HANDLE_VALUE != m_handle);
@@ -55,59 +56,59 @@ public:
CloseHandle(m_handle);
}
- virtual error read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) override
+ virtual std::error_condition read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) noexcept override
{
// attempt to set the file pointer
LARGE_INTEGER largeOffset;
largeOffset.QuadPart = offset;
if (!SetFilePointerEx(m_handle, largeOffset, nullptr, FILE_BEGIN))
- return win_error_to_file_error(GetLastError());
+ return win_error_to_error_condition(GetLastError());
// then perform the read
DWORD result = 0;
if (!ReadFile(m_handle, buffer, length, &result, nullptr))
- return win_error_to_file_error(GetLastError());
+ return win_error_to_error_condition(GetLastError());
actual = result;
- return error::NONE;
+ return std::error_condition();
}
- virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) override
+ virtual std::error_condition write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) noexcept override
{
// attempt to set the file pointer
LARGE_INTEGER largeOffset;
largeOffset.QuadPart = offset;
if (!SetFilePointerEx(m_handle, largeOffset, nullptr, FILE_BEGIN))
- return win_error_to_file_error(GetLastError());
+ return win_error_to_error_condition(GetLastError());
// then perform the write
DWORD result = 0;
if (!WriteFile(m_handle, buffer, length, &result, nullptr))
- return win_error_to_file_error(GetLastError());
+ return win_error_to_error_condition(GetLastError());
actual = result;
- return error::NONE;
+ return std::error_condition();
}
- virtual error truncate(std::uint64_t offset) override
+ virtual std::error_condition truncate(std::uint64_t offset) noexcept override
{
// attempt to set the file pointer
LARGE_INTEGER largeOffset;
largeOffset.QuadPart = offset;
if (!SetFilePointerEx(m_handle, largeOffset, nullptr, FILE_BEGIN))
- return win_error_to_file_error(GetLastError());
+ return win_error_to_error_condition(GetLastError());
// then perform the truncation
if (!SetEndOfFile(m_handle))
- return win_error_to_file_error(GetLastError());
+ return win_error_to_error_condition(GetLastError());
else
- return error::NONE;
+ return std::error_condition();
}
- virtual error flush() override
+ virtual std::error_condition flush() noexcept override
{
// shouldn't be any userspace buffers on the file handle
- return error::NONE;
+ return std::error_condition();
}
private:
@@ -160,22 +161,19 @@ DWORD create_path_recursive(TCHAR *path)
// osd_open
//============================================================
-osd_file::error osd_file::open(std::string const &orig_path, uint32_t openflags, ptr &file, std::uint64_t &filesize)
+std::error_condition osd_file::open(std::string const &path, uint32_t openflags, ptr &file, std::uint64_t &filesize) noexcept
{
- std::string path;
- try { osd_subst_env(path, orig_path); }
- catch (...) { return error::OUT_OF_MEMORY; }
-
if (win_check_socket_path(path))
return win_open_socket(path, openflags, file, filesize);
else if (win_check_ptty_path(path))
return win_open_ptty(path, openflags, file, filesize);
// convert path to TCHAR
- osd::text::tstring t_path = osd::text::to_tstring(path);
+ osd::text::tstring t_path;
+ try { t_path = osd::text::to_tstring(path); }
+ catch (...) { return std::errc::not_enough_memory; }
- // convert the path into something Windows compatible (the actual interesting part appears
- // to have been commented out???)
+ // convert the path into something Windows compatible (the actual interesting part appears to have been commented out???)
for (auto iter = t_path.begin(); iter != t_path.end(); iter++)
*iter = /* ('/' == *iter) ? '\\' : */ *iter;
@@ -185,7 +183,8 @@ osd_file::error osd_file::open(std::string const &orig_path, uint32_t openflags,
{
disposition = (!is_path_to_physical_drive(path.c_str()) && (openflags & OPEN_FLAG_CREATE)) ? CREATE_ALWAYS : OPEN_EXISTING;
access = (openflags & OPEN_FLAG_READ) ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_WRITE;
- if (is_path_to_physical_drive(path.c_str())) access |= GENERIC_READ;
+ if (is_path_to_physical_drive(path.c_str()))
+ access |= GENERIC_READ;
sharemode = FILE_SHARE_READ;
}
else if (openflags & OPEN_FLAG_READ)
@@ -196,7 +195,7 @@ osd_file::error osd_file::open(std::string const &orig_path, uint32_t openflags,
}
else
{
- return error::INVALID_ACCESS;
+ return std::errc::invalid_argument;
}
// attempt to open the file
@@ -226,7 +225,7 @@ osd_file::error osd_file::open(std::string const &orig_path, uint32_t openflags,
// if we still failed, clean up and free
if (INVALID_HANDLE_VALUE == h)
- return win_error_to_file_error(err);
+ return win_error_to_error_condition(err);
}
// get the file size
@@ -256,21 +255,19 @@ osd_file::error osd_file::open(std::string const &orig_path, uint32_t openflags,
if (NO_ERROR != err)
{
CloseHandle(h);
- return win_error_to_file_error(err);
+ return win_error_to_error_condition(err);
}
}
- try
- {
- file = std::make_unique<win_osd_file>(h);
- filesize = (std::uint64_t(upper) << 32) | lower;
- return error::NONE;
- }
- catch (...)
+ osd_file::ptr result(new (std::nothrow) win_osd_file(h));
+ if (!result)
{
CloseHandle(h);
- return error::OUT_OF_MEMORY;
+ return std::errc::not_enough_memory;
}
+ file = std::move(result);
+ filesize = (std::uint64_t(upper) << 32) | lower;
+ return std::error_condition();
}
@@ -279,9 +276,9 @@ osd_file::error osd_file::open(std::string const &orig_path, uint32_t openflags,
// osd_openpty
//============================================================
-osd_file::error osd_file::openpty(ptr &file, std::string &name)
+std::error_condition osd_file::openpty(ptr &file, std::string &name) noexcept
{
- return error::FAILURE;
+ return std::errc::not_supported; // TODO: revisit this error code
}
@@ -290,13 +287,15 @@ osd_file::error osd_file::openpty(ptr &file, std::string &name)
// osd_rmfile
//============================================================
-osd_file::error osd_file::remove(std::string const &filename)
+std::error_condition osd_file::remove(std::string const &filename) noexcept
{
- osd::text::tstring tempstr = osd::text::to_tstring(filename);
+ osd::text::tstring tempstr;
+ try { tempstr = osd::text::to_tstring(filename); }
+ catch (...) { return std::errc::not_enough_memory; }
- error filerr = error::NONE;
+ std::error_condition filerr;
if (!DeleteFile(tempstr.c_str()))
- filerr = win_error_to_file_error(GetLastError());
+ filerr = win_error_to_error_condition(GetLastError());
return filerr;
}
@@ -307,7 +306,7 @@ osd_file::error osd_file::remove(std::string const &filename)
// osd_get_physical_drive_geometry
//============================================================
-bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders, uint32_t *heads, uint32_t *sectors, uint32_t *bps)
+bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders, uint32_t *heads, uint32_t *sectors, uint32_t *bps) noexcept
{
DISK_GEOMETRY dg;
DWORD bytesRead;
@@ -319,10 +318,17 @@ bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders,
return false;
// do a create file on the drive
- auto t_filename = osd::text::to_tstring(filename);
- file = CreateFile(t_filename.c_str(), GENERIC_READ, FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, nullptr);
- if (file == INVALID_HANDLE_VALUE)
+ try
+ {
+ auto t_filename = osd::text::to_tstring(filename);
+ file = CreateFile(t_filename.c_str(), GENERIC_READ, FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, nullptr);
+ if (file == INVALID_HANDLE_VALUE)
+ return false;
+ }
+ catch (...)
+ {
return false;
+ }
// device I/O control should return the geometry
result = DeviceIoControl(file, IOCTL_DISK_GET_DRIVE_GEOMETRY, nullptr, 0, &dg, sizeof(dg), &bytesRead, nullptr);
@@ -397,19 +403,29 @@ std::unique_ptr<osd::directory::entry> osd_stat(const std::string &path)
// osd_get_full_path
//============================================================
-osd_file::error osd_get_full_path(std::string &dst, std::string const &path)
+std::error_condition osd_get_full_path(std::string &dst, std::string const &path) noexcept
{
- // convert the path to TCHARs
- osd::text::tstring t_path = osd::text::to_tstring(path);
-
- // canonicalize the path
- TCHAR buffer[MAX_PATH];
- if (!GetFullPathName(t_path.c_str(), ARRAY_LENGTH(buffer), buffer, nullptr))
- return win_error_to_file_error(GetLastError());
-
- // convert the result back to UTF-8
- osd::text::from_tstring(dst, buffer);
- return osd_file::error::NONE;
+ try
+ {
+ // get the length of the full path
+ std::wstring const w_path(osd::text::to_wstring(path));
+ DWORD const length(GetFullPathNameW(w_path.c_str(), 0, nullptr, nullptr));
+ if (!length)
+ return win_error_to_error_condition(GetLastError());
+
+ // allocate a buffer and get the canonical path
+ std::unique_ptr<wchar_t []> buffer(std::make_unique<wchar_t []>(length));
+ if (!GetFullPathNameW(w_path.c_str(), length, buffer.get(), nullptr))
+ return win_error_to_error_condition(GetLastError());
+
+ // convert the result back to UTF-8
+ osd::text::from_wstring(dst, buffer.get());
+ return std::error_condition();
+ }
+ catch (...)
+ {
+ return std::errc::not_enough_memory; // the string conversions can throw bad_alloc
+ }
}
@@ -418,10 +434,9 @@ osd_file::error osd_get_full_path(std::string &dst, std::string const &path)
// osd_is_absolute_path
//============================================================
-bool osd_is_absolute_path(std::string const &path)
+bool osd_is_absolute_path(std::string const &path) noexcept
{
- osd::text::tstring t_path = osd::text::to_tstring(path);
- return !PathIsRelative(t_path.c_str());
+ return !PathIsRelativeW(osd::text::to_wstring(path).c_str());
}
@@ -430,20 +445,57 @@ bool osd_is_absolute_path(std::string const &path)
// osd_get_volume_name
//============================================================
-const char *osd_get_volume_name(int idx)
+std::string osd_get_volume_name(int idx)
{
- static char szBuffer[128];
- const char *p;
+ std::vector<wchar_t> buffer;
+ DWORD length(GetLogicalDriveStringsW(0, nullptr));
+ while (length && (buffer.size() < (length + 1)))
+ {
+ buffer.clear();
+ buffer.resize(length + 1);
+ length = GetLogicalDriveStringsW(length, &buffer[0]);
+ }
+ if (!length)
+ return std::string();
+
+ wchar_t const *p(&buffer[0]);
+ while (idx-- && *p)
+ {
+ while (*p++) { }
+ }
+
+ std::string result;
+ osd::text::from_wstring(result, p);
+ return result;
+}
- GetLogicalDriveStringsA(ARRAY_LENGTH(szBuffer), szBuffer);
- p = szBuffer;
- while(idx--) {
- p += strlen(p) + 1;
- if (!*p) return nullptr;
+//============================================================
+// osd_get_volume_names
+//============================================================
+
+std::vector<std::string> osd_get_volume_names()
+{
+ std::vector<std::string> result;
+ std::vector<wchar_t> buffer;
+ DWORD length(GetLogicalDriveStringsW(0, nullptr));
+ while (length && (buffer.size() < (length + 1)))
+ {
+ buffer.clear();
+ buffer.resize(length + 1);
+ length = GetLogicalDriveStringsW(length, &buffer[0]);
}
+ if (!length)
+ return result;
- return p;
+ wchar_t const *p(&buffer[0]);
+ std::wstring vol;
+ while (*p)
+ {
+ osd::text::from_wstring(result.emplace_back(), p);
+ while (*p++) { }
+ }
+ return result;
}
@@ -452,7 +504,7 @@ const char *osd_get_volume_name(int idx)
// osd_is_valid_filename_char
//============================================================
-bool osd_is_valid_filename_char(char32_t uchar)
+bool osd_is_valid_filename_char(char32_t uchar) noexcept
{
return osd_is_valid_filepath_char(uchar)
&& uchar != '/'
@@ -466,7 +518,7 @@ bool osd_is_valid_filename_char(char32_t uchar)
// osd_is_valid_filepath_char
//============================================================
-bool osd_is_valid_filepath_char(char32_t uchar)
+bool osd_is_valid_filepath_char(char32_t uchar) noexcept
{
return uchar >= 0x20
&& uchar != '<'
@@ -478,46 +530,3 @@ bool osd_is_valid_filepath_char(char32_t uchar)
&& !(uchar >= '\x7F' && uchar <= '\x9F')
&& uchar_isvalid(uchar);
}
-
-
-
-//============================================================
-// win_error_to_file_error
-//============================================================
-
-osd_file::error win_error_to_file_error(DWORD error)
-{
- osd_file::error filerr;
-
- // convert a Windows error to a osd_file::error
- switch (error)
- {
- case ERROR_SUCCESS:
- filerr = osd_file::error::NONE;
- break;
-
- case ERROR_OUTOFMEMORY:
- filerr = osd_file::error::OUT_OF_MEMORY;
- break;
-
- case ERROR_FILE_NOT_FOUND:
- case ERROR_FILENAME_EXCED_RANGE:
- case ERROR_PATH_NOT_FOUND:
- case ERROR_INVALID_NAME:
- filerr = osd_file::error::NOT_FOUND;
- break;
-
- case ERROR_ACCESS_DENIED:
- filerr = osd_file::error::ACCESS_DENIED;
- break;
-
- case ERROR_SHARING_VIOLATION:
- filerr = osd_file::error::ALREADY_OPEN;
- break;
-
- default:
- filerr = osd_file::error::FAILURE;
- break;
- }
- return filerr;
-}
diff --git a/src/osd/modules/file/winfile.h b/src/osd/modules/file/winfile.h
index 9a6f1b8fc34..90cf6e69a60 100644
--- a/src/osd/modules/file/winfile.h
+++ b/src/osd/modules/file/winfile.h
@@ -5,13 +5,16 @@
// winfile.h - File access functions
//
//============================================================
-#ifndef MAME_OSD_WINDOWS_WINFILE_H
-#define MAME_OSD_WINDOWS_WINFILE_H
+#ifndef MAME_OSD_MODULES_FILE_WINFILE_H
+#define MAME_OSD_MODULES_FILE_WINFILE_H
-#include "osdcore.h"
+#pragma once
+
+#include "osdfile.h"
#include <cstdint>
#include <string>
+#include <system_error>
#include <winsock2.h>
@@ -20,15 +23,13 @@
// PROTOTYPES
//============================================================
-bool win_init_sockets();
-void win_cleanup_sockets();
-
-bool win_check_socket_path(std::string const &path);
-osd_file::error win_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize);
+bool win_init_sockets() noexcept;
+void win_cleanup_sockets() noexcept;
-bool win_check_ptty_path(std::string const &path);
-osd_file::error win_open_ptty(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize);
+bool win_check_socket_path(std::string const &path) noexcept;
+std::error_condition win_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept;
-osd_file::error win_error_to_file_error(DWORD error);
+bool win_check_ptty_path(std::string const &path) noexcept;
+std::error_condition win_open_ptty(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept;
-#endif // MAME_OSD_WINDOWS_WINFILE_H
+#endif // MAME_OSD_MODULES_FILE_WINFILE_H
diff --git a/src/osd/modules/file/winptty.cpp b/src/osd/modules/file/winptty.cpp
index 943f1fbaa52..9aac0c5a990 100644
--- a/src/osd/modules/file/winptty.cpp
+++ b/src/osd/modules/file/winptty.cpp
@@ -8,12 +8,14 @@
#include "winutil.h"
#include <cassert>
+#include <cstdlib>
+#include <cstring>
#include <windows.h>
-#include <stdlib.h>
namespace {
+
char const *const winfile_ptty_identifier = "\\\\.\\pipe\\";
@@ -25,7 +27,7 @@ public:
win_osd_ptty& operator=(win_osd_ptty const &) = delete;
win_osd_ptty& operator=(win_osd_ptty &&) = delete;
- win_osd_ptty(HANDLE handle) : m_handle(handle)
+ win_osd_ptty(HANDLE handle) noexcept : m_handle(handle)
{
assert(m_handle);
assert(INVALID_HANDLE_VALUE != m_handle);
@@ -38,36 +40,36 @@ public:
CloseHandle(m_handle);
}
- virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override
+ virtual std::error_condition read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) noexcept override
{
DWORD bytes_read;
if (!ReadFile(m_handle, buffer, count, &bytes_read, nullptr))
- return win_error_to_file_error(GetLastError());
+ return win_error_to_error_condition(GetLastError());
actual = bytes_read;
- return error::NONE;
+ return std::error_condition();
}
- virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override
+ virtual std::error_condition write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) noexcept override
{
DWORD bytes_written;
if (!WriteFile(m_handle, buffer, count, &bytes_written, nullptr))
- return win_error_to_file_error(GetLastError());
+ return win_error_to_error_condition(GetLastError());
actual = bytes_written;
- return error::NONE;
+ return std::error_condition();
}
- virtual error truncate(std::uint64_t offset) override
+ virtual std::error_condition truncate(std::uint64_t offset) noexcept override
{
// doesn't make sense for a PTTY
- return error::INVALID_ACCESS;
+ return std::errc::bad_file_descriptor;
}
- virtual error flush() override
+ virtual std::error_condition flush() noexcept override
{
// don't want to wait for client to read all data as implied by FlushFileBuffers
- return error::NONE;
+ return std::error_condition();
}
private:
@@ -77,40 +79,42 @@ private:
} // anonymous namespace
-bool win_check_ptty_path(std::string const &path)
+bool win_check_ptty_path(std::string const &path) noexcept
{
if (strncmp(path.c_str(), winfile_ptty_identifier, strlen(winfile_ptty_identifier)) == 0) return true;
return false;
}
-osd_file::error win_open_ptty(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize)
+std::error_condition win_open_ptty(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept
{
- osd::text::tstring t_name = osd::text::to_tstring(path);
+ osd::text::tstring t_name;
+ try { t_name = osd::text::to_tstring(path); }
+ catch (...) { return std::errc::not_enough_memory; }
HANDLE pipe = CreateFileW(t_name.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if (INVALID_HANDLE_VALUE == pipe)
{
- pipe = CreateNamedPipe(t_name.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT, 1, 32, 32, 0, nullptr);
+ if (openflags & OPEN_FLAG_CREATE)
+ pipe = CreateNamedPipe(t_name.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT, 1, 32, 32, 0, nullptr);
if (INVALID_HANDLE_VALUE == pipe)
- return osd_file::error::ACCESS_DENIED;
+ return win_error_to_error_condition(GetLastError());
}
else
{
DWORD state = PIPE_NOWAIT;
- SetNamedPipeHandleState(pipe, &state, NULL, NULL);
+ SetNamedPipeHandleState(pipe, &state, nullptr, nullptr);
+ // TODO: check for error?
}
- try
- {
- file = std::make_unique<win_osd_ptty>(pipe);
- filesize = 0;
- return osd_file::error::NONE;
- }
- catch (...)
+ osd_file::ptr result(new (std::nothrow) win_osd_ptty(pipe));
+ if (!result)
{
CloseHandle(pipe);
- return osd_file::error::OUT_OF_MEMORY;
+ return std::errc::not_enough_memory;
}
+ file = std::move(result);
+ filesize = 0;
+ return std::error_condition();
}
diff --git a/src/osd/modules/file/winrtdir.cpp b/src/osd/modules/file/winrtdir.cpp
index be42b6fd874..19c328ea094 100644
--- a/src/osd/modules/file/winrtdir.cpp
+++ b/src/osd/modules/file/winrtdir.cpp
@@ -12,16 +12,16 @@
#include <tchar.h>
// MAME headers
-#include "osdcore.h"
#include "strformat.h"
// MAMEOS headers
+#include "osdfile.h"
#include "strconv.h"
#include "../../windows/winutil.h"
// standard C headers
-#include <stdio.h>
-#include <ctype.h>
+#include <cstdio>
+#include <cctype>
#include <cassert>
#include <cstring>
@@ -108,7 +108,7 @@ bool win_directory::open_impl(std::string const &dirname)
assert(m_find == INVALID_HANDLE_VALUE);
// append \*.* to the directory name
- std::string dirfilter = string_format("%s\\*.*", dirname);
+ std::string dirfilter = util::string_format("%s\\*.*", dirname);
// convert the path to TCHARs
osd::text::tstring t_dirfilter = osd::text::to_tstring(dirfilter);
diff --git a/src/osd/modules/file/winrtfile.cpp b/src/osd/modules/file/winrtfile.cpp
index 83d8d7c4915..5053f6e0199 100644
--- a/src/osd/modules/file/winrtfile.cpp
+++ b/src/osd/modules/file/winrtfile.cpp
@@ -26,8 +26,8 @@
#include <winioctl.h>
#include <tchar.h>
#include <shlwapi.h>
-#include <stdlib.h>
-#include <ctype.h>
+#include <cstdlib>
+#include <cctype>
namespace {
@@ -160,12 +160,8 @@ DWORD create_path_recursive(TCHAR *path)
// osd_open
//============================================================
-osd_file::error osd_file::open(std::string const &orig_path, uint32_t openflags, ptr &file, std::uint64_t &filesize)
+osd_file::error osd_file::open(std::string const &path, uint32_t openflags, ptr &file, std::uint64_t &filesize)
{
- std::string path;
- try { osd_subst_env(path, orig_path); }
- catch (...) { return error::OUT_OF_MEMORY; }
-
if (win_check_socket_path(path))
return win_open_socket(path, openflags, file, filesize);
else if (win_check_ptty_path(path))
@@ -350,7 +346,7 @@ osd_file::error osd_get_full_path(std::string &dst, std::string const &path)
// canonicalize the path
TCHAR buffer[MAX_PATH];
- if (!GetFullPathName(t_path.c_str(), ARRAY_LENGTH(buffer), buffer, nullptr))
+ if (!GetFullPathName(t_path.c_str(), std::size(buffer), buffer, nullptr))
return win_error_to_file_error(GetLastError());
// convert the result back to UTF-8
@@ -380,9 +376,19 @@ bool osd_is_absolute_path(std::string const &path)
// osd_get_volume_name
//============================================================
-const char *osd_get_volume_name(int idx)
+std::string osd_get_volume_name(int idx)
+{
+ return std::string();
+}
+
+
+//============================================================
+// osd_get_volume_names
+//============================================================
+
+std::vector<std::string> osd_get_volume_names()
{
- return nullptr;
+ return std::vector<std::string>();
}
diff --git a/src/osd/modules/file/winrtfile.h b/src/osd/modules/file/winrtfile.h
index 9a6f1b8fc34..927cb299545 100644
--- a/src/osd/modules/file/winrtfile.h
+++ b/src/osd/modules/file/winrtfile.h
@@ -8,7 +8,7 @@
#ifndef MAME_OSD_WINDOWS_WINFILE_H
#define MAME_OSD_WINDOWS_WINFILE_H
-#include "osdcore.h"
+#include "osdfile.h"
#include <cstdint>
#include <string>
diff --git a/src/osd/modules/file/winrtptty.cpp b/src/osd/modules/file/winrtptty.cpp
index ec1e6e73b38..cda1f128503 100644
--- a/src/osd/modules/file/winrtptty.cpp
+++ b/src/osd/modules/file/winrtptty.cpp
@@ -9,7 +9,8 @@
#include <cassert>
#include <windows.h>
-#include <stdlib.h>
+#include <cstdlib>
+#include <cstring>
namespace {
diff --git a/src/osd/modules/file/winrtsocket.cpp b/src/osd/modules/file/winrtsocket.cpp
index 3f2241c25b5..d66551870f9 100644
--- a/src/osd/modules/file/winrtsocket.cpp
+++ b/src/osd/modules/file/winrtsocket.cpp
@@ -14,13 +14,14 @@
#include <cassert>
#include <cstdio>
+#include <cstring>
// standard windows headers
#include <windows.h>
#include <winioctl.h>
#include <tchar.h>
-#include <stdlib.h>
-#include <ctype.h>
+#include <cstdlib>
+#include <cctype>
namespace {
diff --git a/src/osd/modules/file/winsocket.cpp b/src/osd/modules/file/winsocket.cpp
index a383a876f9d..d04538963ea 100644
--- a/src/osd/modules/file/winsocket.cpp
+++ b/src/osd/modules/file/winsocket.cpp
@@ -6,7 +6,6 @@
//
//============================================================
-
#include "winfile.h"
// MAMEOS headers
@@ -17,16 +16,18 @@
#include <cassert>
#include <cstdio>
+#include <cstring>
// standard windows headers
#include <windows.h>
#include <winioctl.h>
#include <tchar.h>
-#include <stdlib.h>
-#include <ctype.h>
+#include <cstdlib>
+#include <cctype>
namespace {
+
char const *const winfile_socket_identifier = "socket.";
@@ -38,7 +39,7 @@ public:
win_osd_socket& operator=(win_osd_socket const &) = delete;
win_osd_socket& operator=(win_osd_socket &&) = delete;
- win_osd_socket(SOCKET s, bool l)
+ win_osd_socket(SOCKET s, bool l) noexcept
: m_socket(s)
, m_listening(l)
{
@@ -50,7 +51,7 @@ public:
closesocket(m_socket);
}
- virtual error read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) override
+ virtual std::error_condition read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) noexcept override
{
fd_set readfds;
FD_ZERO(&readfds);
@@ -61,10 +62,7 @@ public:
if (select(m_socket + 1, &readfds, nullptr, nullptr, &timeout) < 0)
{
- char line[80];
- std::sprintf(line, "win_read_socket : %s : %d ", __FILE__, __LINE__);
- std::perror(line);
- return error::FAILURE;
+ return wsa_error_to_file_error(WSAGetLastError());
}
else if (FD_ISSET(m_socket, &readfds))
{
@@ -79,7 +77,7 @@ public:
else
{
actual = result;
- return error::NONE;
+ return std::error_condition();
}
}
else
@@ -97,50 +95,82 @@ public:
m_listening = false;
actual = 0;
- return error::NONE;
+ return std::error_condition();
}
}
}
else
{
- return error::FAILURE;
+ // no data available
+ actual = 0;
+ return std::errc::operation_would_block;
}
}
- virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) override
+ virtual std::error_condition write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) noexcept override
{
auto const result = send(m_socket, reinterpret_cast<const char *>(buffer), length, 0);
if (result < 0)
return wsa_error_to_file_error(WSAGetLastError());
actual = result;
- return error::NONE;
+ return std::error_condition();
}
- virtual error truncate(std::uint64_t offset) override
+ virtual std::error_condition truncate(std::uint64_t offset) noexcept override
{
// doesn't make sense for a socket
- return error::INVALID_ACCESS;
+ return std::errc::bad_file_descriptor;
}
- virtual error flush() override
+ virtual std::error_condition flush() noexcept override
{
// no buffers to flush
- return error::NONE;
+ return std::error_condition();
}
- static error wsa_error_to_file_error(int err)
+ static std::error_condition wsa_error_to_file_error(int err)
{
+ // TODO: determine if there's a better way to do this
switch (err)
{
- case 0: return error::NONE;
- case WSAEACCES: return error::ACCESS_DENIED;
- case WSAEADDRINUSE: return error::ALREADY_OPEN;
- case WSAEADDRNOTAVAIL: return error::NOT_FOUND;
- case WSAECONNREFUSED: return error::NOT_FOUND;
- case WSAEHOSTUNREACH: return error::NOT_FOUND;
- case WSAENETUNREACH: return error::NOT_FOUND;
- default: return error::FAILURE;
+ case 0: return std::error_condition();
+ case WSA_NOT_ENOUGH_MEMORY: return std::errc::not_enough_memory;
+ case WSA_INVALID_PARAMETER: return std::errc::invalid_argument;
+ case WSAEINTR: return std::errc::interrupted;
+ case WSAEBADF: return std::errc::bad_file_descriptor;
+ case WSAEACCES: return std::errc::permission_denied;
+ case WSAEFAULT: return std::errc::bad_address;
+ case WSAEINVAL: return std::errc::invalid_argument;
+ case WSAEMFILE: return std::errc::too_many_files_open;
+ case WSAENETRESET: return std::errc::network_reset;
+ case WSAECONNABORTED: return std::errc::connection_aborted;
+ case WSAEWOULDBLOCK: return std::errc::operation_would_block;
+ case WSAEINPROGRESS: return std::errc::operation_in_progress;
+ case WSAEALREADY: return std::errc::connection_already_in_progress;
+ case WSAENOTSOCK: return std::errc::not_a_socket;
+ case WSAEDESTADDRREQ: return std::errc::destination_address_required;
+ case WSAEMSGSIZE: return std::errc::message_size;
+ case WSAEPROTOTYPE: return std::errc::wrong_protocol_type;
+ case WSAENOPROTOOPT: return std::errc::no_protocol_option;
+ case WSAEPROTONOSUPPORT: return std::errc::protocol_not_supported;
+ case WSAEOPNOTSUPP: return std::errc::operation_not_supported;
+ case WSAEAFNOSUPPORT: return std::errc::address_family_not_supported;
+ case WSAEADDRINUSE: return std::errc::address_in_use;
+ case WSAEADDRNOTAVAIL: return std::errc::address_not_available;
+ case WSAENETDOWN: return std::errc::network_down;
+ case WSAENETUNREACH: return std::errc::network_unreachable;
+ case WSAECONNRESET: return std::errc::connection_reset;
+ case WSAENOBUFS: return std::errc::no_buffer_space;
+ case WSAEISCONN: return std::errc::already_connected;
+ case WSAENOTCONN: return std::errc::not_connected;
+ case WSAETIMEDOUT: return std::errc::timed_out;
+ case WSAECONNREFUSED: return std::errc::connection_refused;
+ case WSAEHOSTUNREACH: return std::errc::host_unreachable;
+ case WSAECANCELLED: return std::errc::operation_canceled;
+
+ // TODO: better default error code?
+ default: return std::errc::io_error;
}
}
@@ -152,7 +182,7 @@ private:
} // anonymous namespace
-bool win_init_sockets()
+bool win_init_sockets() noexcept
{
WSADATA wsaData;
WORD const version = MAKEWORD(2, 0);
@@ -178,13 +208,13 @@ bool win_init_sockets()
}
-void win_cleanup_sockets()
+void win_cleanup_sockets() noexcept
{
WSACleanup();
}
-bool win_check_socket_path(std::string const &path)
+bool win_check_socket_path(std::string const &path) noexcept
{
if (strncmp(path.c_str(), winfile_socket_identifier, strlen(winfile_socket_identifier)) == 0 &&
strchr(path.c_str(), ':') != nullptr) return true;
@@ -192,7 +222,7 @@ bool win_check_socket_path(std::string const &path)
}
-osd_file::error win_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize)
+std::error_condition win_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept
{
char hostname[256];
int port;
@@ -200,7 +230,7 @@ osd_file::error win_open_socket(std::string const &path, std::uint32_t openflags
struct hostent const *const localhost = gethostbyname(hostname);
if (!localhost)
- return osd_file::error::NOT_FOUND;
+ return std::errc::no_such_file_or_directory;
struct sockaddr_in sai;
memset(&sai, 0, sizeof(sai));
@@ -221,11 +251,12 @@ osd_file::error win_open_socket(std::string const &path, std::uint32_t openflags
}
// listening socket support
+ osd_file::ptr result;
if (openflags & OPEN_FLAG_CREATE)
{
//printf("Listening for client at '%s' on port '%d'\n", hostname, port);
// bind socket...
- if (bind(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(struct sockaddr)) == SOCKET_ERROR)
+ if (bind(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(sai)) == SOCKET_ERROR)
{
int const err = WSAGetLastError();
closesocket(sock);
@@ -241,36 +272,26 @@ osd_file::error win_open_socket(std::string const &path, std::uint32_t openflags
}
// mark socket as "listening"
- try
- {
- file = std::make_unique<win_osd_socket>(sock, true);
- filesize = 0;
- return osd_file::error::NONE;
- }
- catch (...)
- {
- closesocket(sock);
- return osd_file::error::OUT_OF_MEMORY;
- }
+ result.reset(new (std::nothrow) win_osd_socket(sock, true));
}
else
{
//printf("Connecting to server '%s' on port '%d'\n", hostname, port);
- if (connect(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(struct sockaddr)) == SOCKET_ERROR)
- {
- closesocket(sock);
- return osd_file::error::ACCESS_DENIED; // have to return this value or bitb won't try to bind on connect failure
- }
- try
- {
- file = std::make_unique<win_osd_socket>(sock, false);
- filesize = 0;
- return osd_file::error::NONE;
- }
- catch (...)
+ if (connect(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(sai)) == SOCKET_ERROR)
{
+ int const err = WSAGetLastError();
closesocket(sock);
- return osd_file::error::OUT_OF_MEMORY;
+ return win_osd_socket::wsa_error_to_file_error(err);
}
+ result.reset(new (std::nothrow) win_osd_socket(sock, false));
+ }
+
+ if (!result)
+ {
+ closesocket(sock);
+ return std::errc::not_enough_memory;
}
+ file = std::move(result);
+ filesize = 0;
+ return std::error_condition();
}
diff --git a/src/osd/modules/font/font_dwrite.cpp b/src/osd/modules/font/font_dwrite.cpp
index f60ef7580c4..ec152fb1b0d 100644
--- a/src/osd/modules/font/font_dwrite.cpp
+++ b/src/osd/modules/font/font_dwrite.cpp
@@ -6,14 +6,23 @@
*/
#include "font_module.h"
-#include "modules/osdmodule.h"
+
#include "modules/lib/osdlib.h"
-#if defined(OSD_WINDOWS) || defined(OSD_UWP)
+#if defined(OSD_WINDOWS)
-#include <windows.h>
+#include "corestr.h"
+#include "winutil.h"
+
+#include "osdcore.h"
+#include "strconv.h"
+
+#include <cmath>
#include <memory>
+#include <stdexcept>
+
+#include <windows.h>
// Windows Imaging Components
#include <wincodec.h>
@@ -32,9 +41,10 @@ DEFINE_GUID(GUID_WICPixelFormat8bppAlpha, 0xe6cd0116, 0xeeba, 0x4161, 0xaa, 0x85
#include <wrl/client.h>
#undef interface
-#include "strconv.h"
-#include "corestr.h"
-#include "winutil.h"
+
+namespace osd {
+
+namespace {
using namespace Microsoft::WRL;
@@ -146,7 +156,7 @@ HRESULT SaveBitmap2(bitmap_argb32 &bitmap, const WCHAR *filename)
uint32_t* pRow = pBitmap.get() + (y * bitmap.width());
for (int x = 0; x < bitmap.width(); x++)
{
- uint32_t pixel = bitmap.pix32(y, x);
+ uint32_t pixel = bitmap.pix(y, x);
pRow[x] = (pixel == 0xFFFFFFFF) ? rgb_t(0xFF, 0x00, 0x00, 0x00) : rgb_t(0xFF, 0xFF, 0xFF, 0xFF);
}
}
@@ -226,7 +236,7 @@ public:
{
if (m_designUnitsPerEm != other.m_designUnitsPerEm || m_emSizeInDip != other.m_emSizeInDip)
{
- throw emu_fatalerror("Attempted subtraction of FontDimension with different scale.");
+ throw std::invalid_argument("Attempted subtraction of FontDimension with different scale.");
}
return FontDimension(m_designUnitsPerEm, m_emSizeInDip, m_designUnits - other.m_designUnits);
@@ -236,7 +246,7 @@ public:
{
if (m_designUnitsPerEm != other.m_designUnitsPerEm || m_emSizeInDip != other.m_emSizeInDip)
{
- throw emu_fatalerror("Attempted addition of FontDimension with different scale.");
+ throw std::invalid_argument("Attempted addition of FontDimension with different scale.");
}
return FontDimension(m_designUnitsPerEm, m_emSizeInDip, m_designUnits + other.m_designUnits);
@@ -353,20 +363,16 @@ public:
// accept qualifiers from the name
std::string name(_name);
if (name.compare("default") == 0)
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
- name = "Tahoma";
-#else
name = "Segoe UI";
-#endif
bool bold = (strreplace(name, "[B]", "") + strreplace(name, "[b]", "") > 0);
bool italic = (strreplace(name, "[I]", "") + strreplace(name, "[i]", "") > 0);
// convert the face name
- std::wstring familyName = osd::text::to_wstring(name.c_str());
+ std::wstring familyName = text::to_wstring(name);
// find the font
HR_RET0(find_font(
- familyName.c_str(),
+ familyName,
bold ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL,
@@ -570,7 +576,7 @@ public:
// copy the bits into it
for (int y = 0; y < bitmap.height(); y++)
{
- uint32_t *dstrow = &bitmap.pix32(y);
+ uint32_t *dstrow = &bitmap.pix(y);
uint8_t *srcrow = &pixels[(y + actbounds.min_y) * bmwidth];
for (int x = 0; x < bitmap.width(); x++)
{
@@ -624,7 +630,7 @@ private:
HR_RETHR(fonts->FindFamilyName(familyName.c_str(), &family_index, &exists));
if (!exists)
{
- osd_printf_error("Font with family name %S does not exist.\n", familyName.c_str());
+ osd_printf_error("Font with family name %s does not exist.\n", text::from_wstring(familyName));
return E_FAIL;
}
@@ -675,7 +681,7 @@ public:
return true;
}
- virtual int init(const osd_options &options) override
+ virtual int init(osd_interface &osd, const osd_options &options) override
{
HRESULT result;
@@ -743,7 +749,7 @@ public:
std::unique_ptr<WCHAR[]> name = nullptr;
HR_RET0(get_localized_familyname(names, name));
- std::string utf8_name = osd::text::from_wstring(name.get());
+ std::string utf8_name = text::from_wstring(name.get());
name.reset();
// Review: should the config name, be unlocalized?
@@ -807,8 +813,15 @@ private:
}
};
+} // anonymous namespace
+
+} // namespace osd
+
#else
-MODULE_NOT_SUPPORTED(font_dwrite, OSD_FONT_PROVIDER, "dwrite")
+
+namespace osd { namespace { MODULE_NOT_SUPPORTED(font_dwrite, OSD_FONT_PROVIDER, "dwrite") } }
+
#endif
-MODULE_DEFINITION(FONT_DWRITE, font_dwrite)
+
+MODULE_DEFINITION(FONT_DWRITE, osd::font_dwrite)
diff --git a/src/osd/modules/font/font_module.h b/src/osd/modules/font/font_module.h
index 81ffaca74e5..7fe04e32628 100644
--- a/src/osd/modules/font/font_module.h
+++ b/src/osd/modules/font/font_module.h
@@ -24,7 +24,7 @@
class font_module
{
public:
- virtual ~font_module() { }
+ virtual ~font_module() = default;
/** attempt to allocate a font instance */
virtual osd_font::ptr font_alloc() = 0;
diff --git a/src/osd/modules/font/font_none.cpp b/src/osd/modules/font/font_none.cpp
index dc6116625a8..abf56007b00 100644
--- a/src/osd/modules/font/font_none.cpp
+++ b/src/osd/modules/font/font_none.cpp
@@ -4,9 +4,12 @@
* font_none.c
*
*/
-
#include "font_module.h"
-#include "modules/osdmodule.h"
+
+
+namespace osd {
+
+namespace {
class osd_font_none : public osd_font
{
@@ -23,10 +26,15 @@ class font_none : public osd_module, public font_module
public:
font_none() : osd_module(OSD_FONT_PROVIDER, "none"), font_module() { }
- virtual int init(const osd_options &options) override { return 0; }
+ virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
virtual osd_font::ptr font_alloc() override { return std::make_unique<osd_font_none>(); }
virtual bool get_font_families(std::string const &font_path, std::vector<std::pair<std::string, std::string> > &result) override { return false; }
};
-MODULE_DEFINITION(FONT_NONE, font_none)
+} // anonymous namespace
+
+} // namespace osd
+
+
+MODULE_DEFINITION(FONT_NONE, osd::font_none)
diff --git a/src/osd/modules/font/font_osx.cpp b/src/osd/modules/font/font_osx.cpp
index 5074c1f4bcd..a020d51ddce 100644
--- a/src/osd/modules/font/font_osx.cpp
+++ b/src/osd/modules/font/font_osx.cpp
@@ -6,12 +6,12 @@
*/
#include "font_module.h"
-#include "modules/osdmodule.h"
#ifdef SDLMAME_MACOSX
-#include "corealloc.h"
+#include "emucore.h"
#include "fileio.h"
+#include "osdcore.h"
#include <ApplicationServices/ApplicationServices.h>
#include <CoreFoundation/CoreFoundation.h>
@@ -54,8 +54,20 @@ private:
bool osd_font_osx::open(std::string const &font_path, std::string const &name, int &height)
{
- osd_printf_verbose("osd_font_osx::open: name=\"%s\"\n", name.c_str());
- CFStringRef const font_name(CFStringCreateWithCString(nullptr, name.c_str(), kCFStringEncodingUTF8));
+ osd_printf_verbose("osd_font_osx::open: name=\"%s\"\n", name);
+
+ CFStringRef font_name;
+ if (name == "default")
+ {
+ // Arial Unicode MS comes with Mac OS X 10.5 and later and is the only Mac default font with
+ // the Unicode characters used by the vgmplay and aristmk5 layouts.
+ font_name = CFStringCreateWithCString(nullptr, "Arial Unicode MS", kCFStringEncodingUTF8);
+ }
+ else
+ {
+ font_name = CFStringCreateWithCString(nullptr, name.c_str(), kCFStringEncodingUTF8);
+ }
+
if (!font_name)
{
osd_printf_verbose("osd_font_osx::open: failed to create CFString from font name (invalid UTF-8?)\n");
@@ -73,7 +85,7 @@ bool osd_font_osx::open(std::string const &font_path, std::string const &name, i
CFRelease(font_name);
if (!font_descriptor)
{
- osd_printf_verbose("osd_font_osx::open: failed to create CoreText font descriptor for \"%s\"\n", name.c_str());
+ osd_printf_verbose("osd_font_osx::open: failed to create CoreText font descriptor for \"%s\"\n", name);
return false;
}
@@ -81,7 +93,7 @@ bool osd_font_osx::open(std::string const &font_path, std::string const &name, i
CFRelease(font_descriptor);
if (!ct_font)
{
- osd_printf_verbose("osd_font_osx::open: failed to create CoreText font for \"%s\"\n", name.c_str());
+ osd_printf_verbose("osd_font_osx::open: failed to create CoreText font for \"%s\"\n", name);
return false;
}
@@ -141,9 +153,16 @@ bool osd_font_osx::get_bitmap(char32_t chnum, bitmap_argb32 &bitmap, std::int32_
osd_printf_verbose("osd_font_osd::get_bitmap: failed to get glyph for U+%04X\n", unsigned(chnum));
// try to get glyph metrics
+ #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100
+ CGRect const bounds(CTFontGetBoundingRectsForGlyphs(m_font, kCTFontOrientationHorizontal, &glyph, nullptr, count));
+ CGSize advance(CGSizeZero);
+ CTFontGetAdvancesForGlyphs(m_font, kCTFontOrientationHorizontal, &glyph, &advance, count);
+ #else
CGRect const bounds(CTFontGetBoundingRectsForGlyphs(m_font, kCTFontHorizontalOrientation, &glyph, nullptr, count));
CGSize advance(CGSizeZero);
CTFontGetAdvancesForGlyphs(m_font, kCTFontHorizontalOrientation, &glyph, &advance, count);
+ #endif
+
// CGNullRect can indicate failure, but it's also a valid rectangle for spaces in some fonts (e.g. Hiragino family)
if (CGRectEqualToRect(bounds, CGRectNull) && CGSizeEqualToSize(advance, CGSizeZero))
@@ -171,7 +190,12 @@ bool osd_font_osx::get_bitmap(char32_t chnum, bitmap_argb32 &bitmap, std::int32_
CGContextSetRGBFillColor(context_ref, 1.0, 1.0, 1.0, 1.0);
CGContextSetFont(context_ref, font_ref);
CGContextSetFontSize(context_ref, POINT_SIZE);
+ #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
+ CGPoint pos = CGPointMake(0, 0);
+ CTFontDrawGlyphs(m_font, &glyph, &pos, 1, context_ref);
+ #else
CGContextShowGlyphs(context_ref, &glyph, count);
+ #endif
CGFontRelease(font_ref);
CGContextRelease(context_ref);
}
@@ -187,7 +211,7 @@ class font_osx : public osd_module, public font_module
public:
font_osx() : osd_module(OSD_FONT_PROVIDER, "osx"), font_module() { }
- virtual int init(const osd_options &options) override { return 0; }
+ virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
virtual osd_font::ptr font_alloc() override { return std::make_unique<osd_font_osx>(); }
virtual bool get_font_families(std::string const &font_path, std::vector<std::pair<std::string, std::string> > &result) override;
@@ -218,8 +242,8 @@ private:
bool font_osx::get_font_families(std::string const &font_path, std::vector<std::pair<std::string, std::string> > &result)
{
CFStringRef keys[] = { kCTFontCollectionRemoveDuplicatesOption };
- std::uintptr_t values[ARRAY_LENGTH(keys)] = { 1 };
- CFDictionaryRef const options = CFDictionaryCreate(kCFAllocatorDefault, (void const **)keys, (void const **)values, ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, nullptr);
+ std::uintptr_t values[std::size(keys)] = { 1 };
+ CFDictionaryRef const options = CFDictionaryCreate(kCFAllocatorDefault, (void const **)keys, (void const **)values, std::size(keys), &kCFTypeDictionaryKeyCallBacks, nullptr);
CTFontCollectionRef const collection = CTFontCollectionCreateFromAvailableFonts(nullptr);
CFRelease(options);
if (!collection) return false;
diff --git a/src/osd/modules/font/font_sdl.cpp b/src/osd/modules/font/font_sdl.cpp
index 62a97d39149..514e0cc0784 100644
--- a/src/osd/modules/font/font_sdl.cpp
+++ b/src/osd/modules/font/font_sdl.cpp
@@ -6,20 +6,17 @@
*/
#include "font_module.h"
-#include "modules/osdmodule.h"
#if defined(SDLMAME_UNIX) && !defined(SDLMAME_MACOSX) && !defined(SDLMAME_HAIKU) && !defined(SDLMAME_ANDROID)
#include "corestr.h"
-#include "corealloc.h"
+#include "emucore.h"
#include "fileio.h"
#include "unicode.h"
+#include "osdcore.h"
-#ifdef SDLMAME_EMSCRIPTEN
-#include <SDL_ttf.h>
-#else
#include <SDL2/SDL_ttf.h>
-#endif
+
#if !defined(SDLMAME_HAIKU) && !defined(SDLMAME_EMSCRIPTEN)
#include <fontconfig/fontconfig.h>
#endif
@@ -88,15 +85,15 @@ bool osd_font_sdl::open(std::string const &font_path, std::string const &_name,
// if no success, try the font path
if (!font)
{
- osd_printf_verbose("Searching font %s in -%s path/s\n", family.c_str(), font_path.c_str());
+ osd_printf_verbose("Searching font %s in -%s path/s\n", family, font_path);
//emu_file file(options().font_path(), OPEN_FLAG_READ);
- emu_file file(font_path.c_str(), OPEN_FLAG_READ);
- if (file.open(family.c_str()) == osd_file::error::NONE)
+ emu_file file(font_path, OPEN_FLAG_READ);
+ if (!file.open(family))
{
std::string full_name = file.fullpath();
font = TTF_OpenFont_Magic(full_name, POINT_SIZE, 0);
if (font)
- osd_printf_verbose("Found font %s\n", full_name.c_str());
+ osd_printf_verbose("Found font %s\n", full_name);
}
}
@@ -112,7 +109,7 @@ bool osd_font_sdl::open(std::string const &font_path, std::string const &_name,
{
if (!BDF_Check_Magic(name))
{
- osd_printf_verbose("font %s is not TrueType or BDF, using MAME default\n", name.c_str());
+ osd_printf_verbose("font %s is not TrueType or BDF, using MAME default\n", name);
}
return false;
}
@@ -162,7 +159,7 @@ bool osd_font_sdl::get_bitmap(char32_t chnum, bitmap_argb32 &bitmap, std::int32_
{
SDL_Color const fcol = { 0xff, 0xff, 0xff };
char ustr[16];
- ustr[utf8_from_uchar(ustr, ARRAY_LENGTH(ustr), chnum)] = '\0';
+ ustr[utf8_from_uchar(ustr, std::size(ustr), chnum)] = '\0';
std::unique_ptr<SDL_Surface, void (*)(SDL_Surface *)> const drawsurf(TTF_RenderUTF8_Solid(m_font.get(), ustr, fcol), &SDL_FreeSurface);
// was nothing returned?
@@ -174,7 +171,7 @@ bool osd_font_sdl::get_bitmap(char32_t chnum, bitmap_argb32 &bitmap, std::int32_
// copy the rendered character image into it
for (int y = 0; y < bitmap.height(); y++)
{
- std::uint32_t *const dstrow = &bitmap.pix32(y);
+ std::uint32_t *const dstrow = &bitmap.pix(y);
std::uint8_t const *const srcrow = reinterpret_cast<std::uint8_t const *>(drawsurf->pixels) + (y * drawsurf->pitch);
for (int x = 0; x < drawsurf->w; x++)
@@ -194,14 +191,13 @@ bool osd_font_sdl::get_bitmap(char32_t chnum, bitmap_argb32 &bitmap, std::int32_
osd_font_sdl::TTF_Font_ptr osd_font_sdl::TTF_OpenFont_Magic(std::string const &name, int fsize, long index)
{
emu_file file(OPEN_FLAG_READ);
- if (file.open(name.c_str()) == osd_file::error::NONE)
+ if (!file.open(name))
{
unsigned char const ttf_magic[] = { 0x00, 0x01, 0x00, 0x00, 0x00 };
unsigned char const ttc1_magic[] = { 0x74, 0x74, 0x63, 0x66, 0x00, 0x01, 0x00, 0x00 };
unsigned char const ttc2_magic[] = { 0x74, 0x74, 0x63, 0x66, 0x00, 0x02, 0x00, 0x00 };
- auto buffer_size = std::max({ sizeof(ttf_magic), sizeof(ttc1_magic), sizeof(ttc2_magic) });
- unsigned char buffer[buffer_size];
- auto const bytes_read = file.read(buffer, buffer_size);
+ unsigned char buffer[std::max({ sizeof(ttf_magic), sizeof(ttc1_magic), sizeof(ttc2_magic) })];
+ auto const bytes_read = file.read(buffer, std::size(buffer));
file.close();
if (((bytes_read >= sizeof(ttf_magic)) && !std::memcmp(buffer, ttf_magic, sizeof(ttf_magic))) ||
@@ -215,7 +211,7 @@ osd_font_sdl::TTF_Font_ptr osd_font_sdl::TTF_OpenFont_Magic(std::string const &n
bool osd_font_sdl::BDF_Check_Magic(std::string const &name)
{
emu_file file(OPEN_FLAG_READ);
- if (file.open(name.c_str()) == osd_file::error::NONE)
+ if (!file.open(name))
{
unsigned char const magic[] = { 'S', 'T', 'A', 'R', 'T', 'F', 'O', 'N', 'T' };
unsigned char buffer[sizeof(magic)];
@@ -304,7 +300,7 @@ public:
return std::make_unique<osd_font_sdl>();
}
- virtual int init(const osd_options &options) override
+ virtual int init(osd_interface &osd, const osd_options &options) override
{
if (TTF_Init() == -1)
{
@@ -350,10 +346,10 @@ bool font_sdl::get_font_families(std::string const &font_path, std::vector<std::
{
auto const compare_fonts = [](std::pair<std::string, std::string> const &a, std::pair<std::string, std::string> const &b) -> bool
{
- int const second = core_stricmp(a.second.c_str(), b.second.c_str());
+ int const second = core_stricmp(a.second, b.second);
if (second < 0) return true;
else if (second > 0) return false;
- else return core_stricmp(b.first.c_str(), b.first.c_str()) < 0;
+ else return core_stricmp(b.first, b.first) < 0;
};
std::string config((const char *)val.u.s);
std::string display(config);
diff --git a/src/osd/modules/font/font_windows.cpp b/src/osd/modules/font/font_windows.cpp
index 95f10c0a051..0ec65b67aea 100644
--- a/src/osd/modules/font/font_windows.cpp
+++ b/src/osd/modules/font/font_windows.cpp
@@ -1,22 +1,19 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/*
- * font_windows.c
+ * font_windows.cpp
*
*/
#include "font_module.h"
-#include "modules/osdmodule.h"
#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
-#include "font_module.h"
-#include "modules/osdmodule.h"
-
#include "strconv.h"
+#include "unicode.h"
#include "corestr.h"
-#include "corealloc.h"
+#include "osdcore.h"
#include <cstring>
@@ -27,7 +24,10 @@
#include <io.h>
+namespace osd {
+
namespace {
+
class osd_font_windows : public osd_font
{
public:
@@ -84,8 +84,8 @@ bool osd_font_windows::open(std::string const &font_path, std::string const &_na
logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
// copy in the face name
- osd::text::tstring face = osd::text::to_tstring(name);
- _tcsncpy(logfont.lfFaceName, face.c_str(), ARRAY_LENGTH(logfont.lfFaceName));
+ text::tstring face = text::to_tstring(name);
+ _tcsncpy(logfont.lfFaceName, face.c_str(), std::size(logfont.lfFaceName));
logfont.lfFaceName[sizeof(logfont.lfFaceName) / sizeof(TCHAR)-1] = 0;
// create the font
@@ -109,8 +109,8 @@ bool osd_font_windows::open(std::string const &font_path, std::string const &_na
}
// if it doesn't match our request, fail
- std::string utf = osd::text::from_tstring(&realname[0]);
- int result = core_stricmp(utf.c_str(), name.c_str());
+ std::string utf = text::from_tstring(&realname[0]);
+ int result = core_stricmp(utf, name);
// if we didn't match, nuke our font and fall back
if (result != 0)
@@ -200,7 +200,7 @@ bool osd_font_windows::get_bitmap(char32_t chnum, bitmap_argb32 &bitmap, int32_t
// now draw the character
char16_t tempchar[UTF16_CHAR_MAX];
- UINT const count = INT(utf16_from_uchar(tempchar, ARRAY_LENGTH(tempchar), chnum));
+ UINT const count = INT(utf16_from_uchar(tempchar, std::size(tempchar), chnum));
SetTextColor(dummyDC, RGB(0xff, 0xff, 0xff));
SetBkColor(dummyDC, RGB(0x00, 0x00, 0x00));
ExtTextOutW(dummyDC, 50 + abc.abcA, 50, ETO_OPAQUE, nullptr, reinterpret_cast<LPCWSTR>(tempchar), count, nullptr);
@@ -260,7 +260,7 @@ bool osd_font_windows::get_bitmap(char32_t chnum, bitmap_argb32 &bitmap, int32_t
// copy the bits into it
for (int y = 0; y < bitmap.height(); y++)
{
- uint32_t *dstrow = &bitmap.pix32(y);
+ uint32_t *dstrow = &bitmap.pix(y);
uint8_t *srcrow = &bits[(y + actbounds.min_y) * rowbytes];
for (int x = 0; x < bitmap.width(); x++)
{
@@ -289,7 +289,7 @@ class font_win : public osd_module, public font_module
public:
font_win() : osd_module(OSD_FONT_PROVIDER, "win"), font_module() { }
- virtual int init(const osd_options &options) override { return 0; }
+ virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
virtual osd_font::ptr font_alloc() override { return std::make_unique<osd_font_windows>(); }
@@ -299,7 +299,7 @@ private:
static int CALLBACK font_family_callback(LOGFONT const *lpelfe, TEXTMETRIC const *lpntme, DWORD FontType, LPARAM lParam)
{
auto &result = *reinterpret_cast<std::vector<std::pair<std::string, std::string> > *>(lParam);
- std::string face = osd::text::from_tstring(lpelfe->lfFaceName);
+ std::string face = text::from_tstring(lpelfe->lfFaceName);
if ((face[0] != '@') && (result.empty() || (result.back().first != face))) result.emplace_back(face, face);
return TRUE;
}
@@ -327,10 +327,12 @@ bool font_win::get_font_families(std::string const &font_path, std::vector<std::
} // anonymous namespace
+} // namespace osd
+
#else // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
-MODULE_NOT_SUPPORTED(font_win, OSD_FONT_PROVIDER, "win")
+namespace osd { namespace { MODULE_NOT_SUPPORTED(font_win, OSD_FONT_PROVIDER, "win") } }
#endif // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
-MODULE_DEFINITION(FONT_WINDOWS, font_win)
+MODULE_DEFINITION(FONT_WINDOWS, osd::font_win)
diff --git a/src/osd/modules/input/assignmenthelper.cpp b/src/osd/modules/input/assignmenthelper.cpp
new file mode 100644
index 00000000000..c044d4b7aa7
--- /dev/null
+++ b/src/osd/modules/input/assignmenthelper.cpp
@@ -0,0 +1,592 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+//============================================================
+//
+// assignmenthelper.cpp - input assignment setup helper
+//
+//============================================================
+
+#include "assignmenthelper.h"
+
+#include "interface/inputseq.h"
+
+#include "inpttype.h"
+
+
+namespace osd {
+
+bool joystick_assignment_helper::add_assignment(
+ input_device::assignment_vector &assignments,
+ ioport_type fieldtype,
+ input_seq_type seqtype,
+ input_item_class itemclass,
+ input_item_modifier modifier,
+ std::initializer_list<input_item_id> items)
+{
+ for (input_item_id item : items)
+ {
+ if (ITEM_ID_INVALID != item)
+ {
+ assignments.emplace_back(
+ fieldtype,
+ seqtype,
+ input_seq(input_code(DEVICE_CLASS_JOYSTICK, 0, itemclass, modifier, item)));
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool joystick_assignment_helper::add_button_assignment(
+ input_device::assignment_vector &assignments,
+ ioport_type field_type,
+ std::initializer_list<input_item_id> items)
+{
+ return add_assignment(
+ assignments,
+ field_type,
+ SEQ_TYPE_STANDARD,
+ ITEM_CLASS_SWITCH,
+ ITEM_MODIFIER_NONE,
+ items);
+}
+
+
+bool joystick_assignment_helper::add_button_pair_assignment(
+ input_device::assignment_vector &assignments,
+ ioport_type field1,
+ ioport_type field2,
+ input_item_id button1,
+ input_item_id button2)
+{
+ if ((ITEM_ID_INVALID == button1) || (ITEM_ID_INVALID == button2))
+ return false;
+
+ assignments.emplace_back(
+ field1,
+ SEQ_TYPE_STANDARD,
+ make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, button1));
+ assignments.emplace_back(
+ field2,
+ SEQ_TYPE_STANDARD,
+ make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, button2));
+ return true;
+}
+
+
+bool joystick_assignment_helper::add_axis_inc_dec_assignment(
+ input_device::assignment_vector &assignments,
+ ioport_type field_type,
+ input_item_id button_dec,
+ input_item_id button_inc)
+{
+ if ((ITEM_ID_INVALID == button_dec) || (ITEM_ID_INVALID == button_inc))
+ return false;
+
+ assignments.emplace_back(
+ field_type,
+ SEQ_TYPE_DECREMENT,
+ make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, button_dec));
+ assignments.emplace_back(
+ field_type,
+ SEQ_TYPE_INCREMENT,
+ make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, button_inc));
+ return true;
+}
+
+
+bool joystick_assignment_helper::add_axis_pair_assignment(
+ input_device::assignment_vector &assignments,
+ ioport_type field1,
+ ioport_type field2,
+ input_item_id axis)
+{
+ if (ITEM_ID_INVALID == axis)
+ return false;
+
+ assignments.emplace_back(
+ field1,
+ SEQ_TYPE_STANDARD,
+ make_code(
+ ITEM_CLASS_SWITCH,
+ (ITEM_ID_XAXIS == axis) ? ITEM_MODIFIER_LEFT : (ITEM_ID_YAXIS == axis) ? ITEM_MODIFIER_UP : ITEM_MODIFIER_NEG,
+ axis));
+ assignments.emplace_back(
+ field2,
+ SEQ_TYPE_STANDARD,
+ make_code(
+ ITEM_CLASS_SWITCH,
+ (ITEM_ID_XAXIS == axis) ? ITEM_MODIFIER_RIGHT : (ITEM_ID_YAXIS == axis) ? ITEM_MODIFIER_DOWN : ITEM_MODIFIER_POS,
+ axis));
+ return true;
+}
+
+
+bool joystick_assignment_helper::consume_button_pair(
+ input_device::assignment_vector &assignments,
+ ioport_type field1,
+ ioport_type field2,
+ input_item_id &button1,
+ input_item_id &button2)
+{
+ if (!add_button_pair_assignment(assignments, field1, field2, button1, button2))
+ return false;
+
+ button1 = ITEM_ID_INVALID;
+ button2 = ITEM_ID_INVALID;
+ return true;
+}
+
+
+bool joystick_assignment_helper::consume_trigger_pair(
+ input_device::assignment_vector &assignments,
+ ioport_type field1,
+ ioport_type field2,
+ input_item_id &axis1,
+ input_item_id &axis2)
+{
+ if ((ITEM_ID_INVALID == axis1) || (ITEM_ID_INVALID == axis2))
+ return false;
+
+ assignments.emplace_back(
+ field1,
+ SEQ_TYPE_STANDARD,
+ make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, axis1));
+ assignments.emplace_back(
+ field2,
+ SEQ_TYPE_STANDARD,
+ make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, axis2));
+ axis1 = ITEM_ID_INVALID;
+ axis2 = ITEM_ID_INVALID;
+ return true;
+}
+
+
+bool joystick_assignment_helper::consume_axis_pair(
+ input_device::assignment_vector &assignments,
+ ioport_type field1,
+ ioport_type field2,
+ input_item_id &axis)
+{
+ if (!add_axis_pair_assignment(assignments, field1, field2, axis))
+ return false;
+
+ axis = ITEM_ID_INVALID;
+ return true;
+}
+
+
+void joystick_assignment_helper::add_directional_assignments(
+ input_device::assignment_vector &assignments,
+ input_item_id xaxis,
+ input_item_id yaxis,
+ input_item_id leftswitch,
+ input_item_id rightswitch,
+ input_item_id upswitch,
+ input_item_id downswitch)
+{
+ // see if we have complementary pairs of directional switches
+ bool const hswitches = (ITEM_ID_INVALID != leftswitch) && (ITEM_ID_INVALID != rightswitch);
+ bool const vswitches = (ITEM_ID_INVALID != upswitch) && (ITEM_ID_INVALID != downswitch);
+
+ // use X axis if present
+ if (ITEM_ID_INVALID != xaxis)
+ {
+ // use this for horizontal axis movement
+ input_seq const xseq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, xaxis));
+ assignments.emplace_back(IPT_PADDLE, SEQ_TYPE_STANDARD, xseq);
+ assignments.emplace_back(IPT_POSITIONAL, SEQ_TYPE_STANDARD, xseq);
+ assignments.emplace_back(IPT_DIAL, SEQ_TYPE_STANDARD, xseq);
+ assignments.emplace_back(IPT_TRACKBALL_X, SEQ_TYPE_STANDARD, xseq);
+ assignments.emplace_back(IPT_AD_STICK_X, SEQ_TYPE_STANDARD, xseq);
+ assignments.emplace_back(IPT_LIGHTGUN_X, SEQ_TYPE_STANDARD, xseq);
+
+ // use it for the main left/right control, too
+ input_seq leftseq(make_code(ITEM_CLASS_SWITCH, (ITEM_ID_XAXIS == xaxis) ? ITEM_MODIFIER_LEFT : ITEM_MODIFIER_NEG, xaxis));
+ input_seq rightseq(make_code(ITEM_CLASS_SWITCH, (ITEM_ID_XAXIS == xaxis) ? ITEM_MODIFIER_RIGHT : ITEM_MODIFIER_POS, xaxis));
+ if (ITEM_ID_INVALID != leftswitch)
+ {
+ leftseq += input_seq::or_code;
+ leftseq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, leftswitch);
+ }
+ if (ITEM_ID_INVALID != rightswitch)
+ {
+ rightseq += input_seq::or_code;
+ rightseq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, rightswitch);
+ }
+ assignments.emplace_back(IPT_JOYSTICK_LEFT, SEQ_TYPE_STANDARD, leftseq);
+ assignments.emplace_back(IPT_JOYSTICK_RIGHT, SEQ_TYPE_STANDARD, rightseq);
+
+ // use for vertical navigation if there's no Y axis, or horizontal otherwise
+ if (ITEM_ID_INVALID != yaxis)
+ {
+ // if left/right are both present but not both up/down, they'll be taken for vertical navigation
+ if (hswitches && !vswitches)
+ {
+ leftseq.backspace();
+ if (ITEM_ID_INVALID != upswitch)
+ leftseq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, upswitch);
+ else
+ leftseq.backspace();
+
+ rightseq.backspace();
+ if (ITEM_ID_INVALID != downswitch)
+ rightseq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, downswitch);
+ else
+ rightseq.backspace();
+ }
+ assignments.emplace_back(IPT_UI_LEFT, SEQ_TYPE_STANDARD, leftseq);
+ assignments.emplace_back(IPT_UI_RIGHT, SEQ_TYPE_STANDARD, rightseq);
+ }
+ else
+ {
+ // prefer D-pad up/down for vertical navigation if present
+ if (!hswitches || vswitches)
+ {
+ while (leftseq.length() > 1)
+ leftseq.backspace();
+ if (ITEM_ID_INVALID != upswitch)
+ {
+ leftseq += input_seq::or_code;
+ leftseq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, upswitch);
+ }
+
+ while (rightseq.length() > 1)
+ rightseq.backspace();
+ if (ITEM_ID_INVALID != downswitch)
+ {
+ rightseq += input_seq::or_code;
+ rightseq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, downswitch);
+ }
+ }
+ assignments.emplace_back(IPT_UI_UP, SEQ_TYPE_STANDARD, leftseq);
+ assignments.emplace_back(IPT_UI_DOWN, SEQ_TYPE_STANDARD, rightseq);
+ }
+ }
+ else
+ {
+ // without a primary analog X axis, we still want D-pad left/right controls if possible
+ add_button_assignment(assignments, IPT_JOYSTICK_LEFT, { leftswitch });
+ add_button_assignment(assignments, IPT_JOYSTICK_RIGHT, { rightswitch });
+
+ // vertical navigation gets first pick on directional controls
+ add_button_assignment(assignments, IPT_UI_LEFT, { (hswitches && !vswitches) ? upswitch : leftswitch });
+ add_button_assignment(assignments, IPT_UI_RIGHT, { (hswitches && !vswitches) ? downswitch : rightswitch });
+ }
+
+ // use Y axis if present
+ if (ITEM_ID_INVALID != yaxis)
+ {
+ // use this for vertical axis movement
+ input_seq const yseq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, yaxis));
+ assignments.emplace_back(IPT_PADDLE_V, SEQ_TYPE_STANDARD, yseq);
+ assignments.emplace_back(IPT_POSITIONAL_V, SEQ_TYPE_STANDARD, yseq);
+ assignments.emplace_back(IPT_DIAL_V, SEQ_TYPE_STANDARD, yseq);
+ assignments.emplace_back(IPT_TRACKBALL_Y, SEQ_TYPE_STANDARD, yseq);
+ assignments.emplace_back(IPT_AD_STICK_Y, SEQ_TYPE_STANDARD, yseq);
+ assignments.emplace_back(IPT_LIGHTGUN_Y, SEQ_TYPE_STANDARD, yseq);
+
+ // use it for the main up/down control, too
+ input_seq upseq(make_code(ITEM_CLASS_SWITCH, (ITEM_ID_YAXIS == yaxis) ? ITEM_MODIFIER_UP : ITEM_MODIFIER_NEG, yaxis));
+ input_seq downseq(make_code(ITEM_CLASS_SWITCH, (ITEM_ID_YAXIS == yaxis) ? ITEM_MODIFIER_DOWN : ITEM_MODIFIER_POS, yaxis));
+ if (ITEM_ID_INVALID != upswitch)
+ {
+ upseq += input_seq::or_code;
+ upseq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, upswitch);
+ }
+ if (ITEM_ID_INVALID != downswitch)
+ {
+ downseq += input_seq::or_code;
+ downseq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, downswitch);
+ }
+ assignments.emplace_back(IPT_JOYSTICK_UP, SEQ_TYPE_STANDARD, upseq);
+ assignments.emplace_back(IPT_JOYSTICK_DOWN, SEQ_TYPE_STANDARD, downseq);
+
+ // if available, this is used for vertical navigation
+ if (hswitches && !vswitches)
+ {
+ if (upseq.length() > 1)
+ upseq.backspace();
+ else
+ upseq += input_seq::or_code;
+ upseq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, leftswitch);
+
+ if (downseq.length() > 1)
+ downseq.backspace();
+ else
+ downseq += input_seq::or_code;
+ downseq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, rightswitch);
+ }
+ assignments.emplace_back(IPT_UI_UP, SEQ_TYPE_STANDARD, upseq);
+ assignments.emplace_back(IPT_UI_DOWN, SEQ_TYPE_STANDARD, downseq);
+ }
+ else
+ {
+ // without a primary analog Y axis, we still want D-pad up/down controls if possible
+ add_button_assignment(assignments, IPT_JOYSTICK_UP, { upswitch });
+ add_button_assignment(assignments, IPT_JOYSTICK_DOWN, { downswitch });
+
+ // vertical navigation may be assigned to X axis if Y axis is not present
+ bool const dpadflip = (ITEM_ID_INVALID != xaxis) == (!hswitches || vswitches);
+ add_button_assignment(
+ assignments,
+ (ITEM_ID_INVALID != xaxis) ? IPT_UI_LEFT : IPT_UI_UP,
+ { dpadflip ? leftswitch : upswitch });
+ add_button_assignment(
+ assignments,
+ (ITEM_ID_INVALID != xaxis) ? IPT_UI_RIGHT : IPT_UI_DOWN,
+ { dpadflip ? rightswitch : downswitch });
+ }
+
+ // if we're missing either primary axis, fall back to D-pad for analog increment/decrement
+ if ((ITEM_ID_INVALID == xaxis) || (ITEM_ID_INVALID == yaxis))
+ {
+ if (ITEM_ID_INVALID != leftswitch)
+ {
+ input_seq const leftseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, leftswitch));
+ assignments.emplace_back(IPT_PADDLE, SEQ_TYPE_DECREMENT, leftseq);
+ assignments.emplace_back(IPT_POSITIONAL, SEQ_TYPE_DECREMENT, leftseq);
+ assignments.emplace_back(IPT_DIAL, SEQ_TYPE_DECREMENT, leftseq);
+ assignments.emplace_back(IPT_TRACKBALL_X, SEQ_TYPE_DECREMENT, leftseq);
+ assignments.emplace_back(IPT_AD_STICK_X, SEQ_TYPE_DECREMENT, leftseq);
+ assignments.emplace_back(IPT_LIGHTGUN_X, SEQ_TYPE_DECREMENT, leftseq);
+ }
+ if (ITEM_ID_INVALID != rightswitch)
+ {
+ input_seq const rightseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, rightswitch));
+ assignments.emplace_back(IPT_PADDLE, SEQ_TYPE_INCREMENT, rightseq);
+ assignments.emplace_back(IPT_POSITIONAL, SEQ_TYPE_INCREMENT, rightseq);
+ assignments.emplace_back(IPT_DIAL, SEQ_TYPE_INCREMENT, rightseq);
+ assignments.emplace_back(IPT_TRACKBALL_X, SEQ_TYPE_INCREMENT, rightseq);
+ assignments.emplace_back(IPT_AD_STICK_X, SEQ_TYPE_INCREMENT, rightseq);
+ assignments.emplace_back(IPT_LIGHTGUN_X, SEQ_TYPE_INCREMENT, rightseq);
+ }
+ if (ITEM_ID_INVALID != upswitch)
+ {
+ input_seq const upseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, upswitch));
+ assignments.emplace_back(IPT_PADDLE_V, SEQ_TYPE_DECREMENT, upseq);
+ assignments.emplace_back(IPT_POSITIONAL_V, SEQ_TYPE_DECREMENT, upseq);
+ assignments.emplace_back(IPT_DIAL_V, SEQ_TYPE_DECREMENT, upseq);
+ assignments.emplace_back(IPT_TRACKBALL_Y, SEQ_TYPE_DECREMENT, upseq);
+ assignments.emplace_back(IPT_AD_STICK_Y, SEQ_TYPE_DECREMENT, upseq);
+ assignments.emplace_back(IPT_LIGHTGUN_Y, SEQ_TYPE_DECREMENT, upseq);
+ }
+ if (ITEM_ID_INVALID != downswitch)
+ {
+ input_seq const downseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, downswitch));
+ assignments.emplace_back(IPT_PADDLE_V, SEQ_TYPE_INCREMENT, downseq);
+ assignments.emplace_back(IPT_POSITIONAL_V, SEQ_TYPE_INCREMENT, downseq);
+ assignments.emplace_back(IPT_DIAL_V, SEQ_TYPE_INCREMENT, downseq);
+ assignments.emplace_back(IPT_TRACKBALL_Y, SEQ_TYPE_INCREMENT, downseq);
+ assignments.emplace_back(IPT_AD_STICK_Y, SEQ_TYPE_INCREMENT, downseq);
+ assignments.emplace_back(IPT_LIGHTGUN_Y, SEQ_TYPE_INCREMENT, downseq);
+ }
+ }
+}
+
+
+void joystick_assignment_helper::add_twin_stick_assignments(
+ input_device::assignment_vector &assignments,
+ input_item_id leftx,
+ input_item_id lefty,
+ input_item_id rightx,
+ input_item_id righty,
+ input_item_id leftleft,
+ input_item_id leftright,
+ input_item_id leftup,
+ input_item_id leftdown,
+ input_item_id rightleft,
+ input_item_id rightright,
+ input_item_id rightup,
+ input_item_id rightdown)
+{
+ // we'll add these at the end if they aren't empty
+ input_seq leftleftseq, leftrightseq, leftupseq, leftdownseq;
+ input_seq rightleftseq, rightrightseq, rightupseq, rightdownseq;
+
+ // only use axes if there are at least two axes in the same orientation
+ bool const useaxes =
+ ((ITEM_ID_INVALID != leftx) && (ITEM_ID_INVALID != rightx)) ||
+ ((ITEM_ID_INVALID != lefty) && (ITEM_ID_INVALID != righty));
+ if (useaxes)
+ {
+ // left stick
+ if (ITEM_ID_INVALID != leftx)
+ {
+ leftleftseq += make_code(
+ ITEM_CLASS_SWITCH,
+ (ITEM_ID_XAXIS == leftx) ? ITEM_MODIFIER_LEFT : ITEM_MODIFIER_NEG,
+ leftx);
+ leftrightseq += make_code(
+ ITEM_CLASS_SWITCH,
+ (ITEM_ID_XAXIS == leftx) ? ITEM_MODIFIER_RIGHT : ITEM_MODIFIER_POS,
+ leftx);
+ }
+ if (ITEM_ID_INVALID != lefty)
+ {
+ leftupseq += make_code(
+ ITEM_CLASS_SWITCH,
+ (ITEM_ID_YAXIS == lefty) ? ITEM_MODIFIER_UP : ITEM_MODIFIER_NEG,
+ lefty);
+ leftdownseq += make_code(
+ ITEM_CLASS_SWITCH,
+ (ITEM_ID_YAXIS == lefty) ? ITEM_MODIFIER_DOWN : ITEM_MODIFIER_POS,
+ lefty);
+ }
+
+ // right stick
+ if (ITEM_ID_INVALID != rightx)
+ {
+ rightleftseq += make_code(
+ ITEM_CLASS_SWITCH,
+ (ITEM_ID_XAXIS == rightx) ? ITEM_MODIFIER_LEFT : ITEM_MODIFIER_NEG,
+ rightx);
+ rightrightseq += make_code(
+ ITEM_CLASS_SWITCH,
+ (ITEM_ID_XAXIS == rightx) ? ITEM_MODIFIER_RIGHT : ITEM_MODIFIER_POS,
+ rightx);
+ }
+ if (ITEM_ID_INVALID != righty)
+ {
+ rightupseq += make_code(
+ ITEM_CLASS_SWITCH,
+ (ITEM_ID_YAXIS == righty) ? ITEM_MODIFIER_UP : ITEM_MODIFIER_NEG,
+ righty);
+ rightdownseq += make_code(
+ ITEM_CLASS_SWITCH,
+ (ITEM_ID_YAXIS == righty) ? ITEM_MODIFIER_DOWN : ITEM_MODIFIER_POS,
+ righty);
+ }
+ }
+
+ // only use switches if we have at least one pair of matching opposing directions
+ bool const lefth = (ITEM_ID_INVALID != leftleft) && (ITEM_ID_INVALID != leftright);
+ bool const leftv = (ITEM_ID_INVALID != leftup) && (ITEM_ID_INVALID != leftdown);
+ bool const righth = (ITEM_ID_INVALID != rightleft) && (ITEM_ID_INVALID != rightright);
+ bool const rightv = (ITEM_ID_INVALID != rightup) && (ITEM_ID_INVALID != rightdown);
+ if ((lefth && righth) || (leftv && rightv))
+ {
+ // left stick
+ if (ITEM_ID_INVALID != leftleft)
+ {
+ if (!leftleftseq.empty())
+ leftleftseq += input_seq::or_code;
+ leftleftseq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, leftleft);
+ }
+ if (ITEM_ID_INVALID != leftright)
+ {
+ if (!leftrightseq.empty())
+ leftrightseq += input_seq::or_code;
+ leftrightseq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, leftright);
+ }
+ if (ITEM_ID_INVALID != leftup)
+ {
+ if (!leftupseq.empty())
+ leftupseq += input_seq::or_code;
+ leftupseq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, leftup);
+ }
+ if (ITEM_ID_INVALID != leftdown)
+ {
+ if (!leftdownseq.empty())
+ leftdownseq += input_seq::or_code;
+ leftdownseq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, leftdown);
+ }
+
+ // right stick
+ if (ITEM_ID_INVALID != rightleft)
+ {
+ if (!rightleftseq.empty())
+ rightleftseq += input_seq::or_code;
+ rightleftseq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, rightleft);
+ }
+ if (ITEM_ID_INVALID != rightright)
+ {
+ if (!rightrightseq.empty())
+ rightrightseq += input_seq::or_code;
+ rightrightseq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, rightright);
+ }
+ if (ITEM_ID_INVALID != rightup)
+ {
+ if (!rightupseq.empty())
+ rightupseq += input_seq::or_code;
+ rightupseq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, rightup);
+ }
+ if (ITEM_ID_INVALID != rightdown)
+ {
+ if (!rightdownseq.empty())
+ rightdownseq += input_seq::or_code;
+ rightdownseq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, rightdown);
+ }
+ }
+
+ // now add collected assignments
+ if (!leftleftseq.empty())
+ assignments.emplace_back(IPT_JOYSTICKLEFT_LEFT, SEQ_TYPE_STANDARD, leftleftseq);
+ if (!leftrightseq.empty())
+ assignments.emplace_back(IPT_JOYSTICKLEFT_RIGHT, SEQ_TYPE_STANDARD, leftrightseq);
+ if (!leftupseq.empty())
+ assignments.emplace_back(IPT_JOYSTICKLEFT_UP, SEQ_TYPE_STANDARD, leftupseq);
+ if (!leftdownseq.empty())
+ assignments.emplace_back(IPT_JOYSTICKLEFT_DOWN, SEQ_TYPE_STANDARD, leftdownseq);
+ if (!rightleftseq.empty())
+ assignments.emplace_back(IPT_JOYSTICKRIGHT_LEFT, SEQ_TYPE_STANDARD, rightleftseq);
+ if (!rightrightseq.empty())
+ assignments.emplace_back(IPT_JOYSTICKRIGHT_RIGHT, SEQ_TYPE_STANDARD, rightrightseq);
+ if (!rightupseq.empty())
+ assignments.emplace_back(IPT_JOYSTICKRIGHT_UP, SEQ_TYPE_STANDARD, rightupseq);
+ if (!rightdownseq.empty())
+ assignments.emplace_back(IPT_JOYSTICKRIGHT_DOWN, SEQ_TYPE_STANDARD, rightdownseq);
+}
+
+
+void joystick_assignment_helper::choose_primary_stick(
+ input_item_id (&stickaxes)[2][2],
+ input_item_id leftx,
+ input_item_id lefty,
+ input_item_id rightx,
+ input_item_id righty)
+{
+ if ((ITEM_ID_INVALID != leftx) && (ITEM_ID_INVALID != lefty))
+ {
+ // left stick has both axes, make it primary
+ stickaxes[0][0] = leftx;
+ stickaxes[0][1] = lefty;
+ stickaxes[1][0] = rightx;
+ stickaxes[1][1] = righty;
+ }
+ else if ((ITEM_ID_INVALID != rightx) && (ITEM_ID_INVALID != righty))
+ {
+ // right stick has both axes, make it primary
+ stickaxes[0][0] = rightx;
+ stickaxes[0][1] = righty;
+ stickaxes[1][0] = leftx;
+ stickaxes[1][1] = lefty;
+ }
+ else if (ITEM_ID_INVALID != leftx)
+ {
+ // degenerate case - left X and possibly right X or Y
+ stickaxes[0][0] = leftx;
+ stickaxes[0][1] = righty;
+ stickaxes[1][0] = rightx;
+ stickaxes[1][1] = ITEM_ID_INVALID;
+ }
+ else if ((ITEM_ID_INVALID != rightx) || (ITEM_ID_INVALID != lefty))
+ {
+ // degenerate case - right X and possibly left Y, or one or two Y axes
+ stickaxes[0][0] = rightx;
+ stickaxes[0][1] = lefty;
+ stickaxes[1][0] = ITEM_ID_INVALID;
+ stickaxes[1][1] = righty;
+ }
+ else
+ {
+ // degenerate case - one Y axis at most
+ stickaxes[0][0] = ITEM_ID_INVALID;
+ stickaxes[0][1] = righty;
+ stickaxes[1][0] = ITEM_ID_INVALID;
+ stickaxes[1][1] = ITEM_ID_INVALID;
+ }
+}
+
+} // namespace osd
diff --git a/src/osd/modules/input/assignmenthelper.h b/src/osd/modules/input/assignmenthelper.h
new file mode 100644
index 00000000000..ff5a9d34072
--- /dev/null
+++ b/src/osd/modules/input/assignmenthelper.h
@@ -0,0 +1,118 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+//============================================================
+//
+// assignmenthelper.h - input assignment setup helper
+//
+//============================================================
+#ifndef MAME_OSD_INPUT_ASSIGNMENTHELPER_H
+#define MAME_OSD_INPUT_ASSIGNMENTHELPER_H
+
+#pragma once
+
+#include "interface/inputcode.h"
+#include "interface/inputdev.h"
+
+#include <initializer_list>
+
+
+namespace osd {
+
+class joystick_assignment_helper
+{
+protected:
+ static constexpr input_code make_code(
+ input_item_class itemclass,
+ input_item_modifier modifier,
+ input_item_id item)
+ {
+ return input_code(DEVICE_CLASS_JOYSTICK, 0, itemclass, modifier, item);
+ }
+
+ static bool add_assignment(
+ input_device::assignment_vector &assignments,
+ ioport_type fieldtype,
+ input_seq_type seqtype,
+ input_item_class itemclass,
+ input_item_modifier modifier,
+ std::initializer_list<input_item_id> items);
+
+ static bool add_button_assignment(
+ input_device::assignment_vector &assignments,
+ ioport_type field_type,
+ std::initializer_list<input_item_id> items);
+
+ static bool add_button_pair_assignment(
+ input_device::assignment_vector &assignments,
+ ioport_type field1,
+ ioport_type field2,
+ input_item_id button1,
+ input_item_id button2);
+
+ static bool add_axis_inc_dec_assignment(
+ input_device::assignment_vector &assignments,
+ ioport_type field_type,
+ input_item_id button_dec,
+ input_item_id button_inc);
+
+ static bool add_axis_pair_assignment(
+ input_device::assignment_vector &assignments,
+ ioport_type field1,
+ ioport_type field2,
+ input_item_id axis);
+
+ static bool consume_button_pair(
+ input_device::assignment_vector &assignments,
+ ioport_type field1,
+ ioport_type field2,
+ input_item_id &button1,
+ input_item_id &button2);
+
+ static bool consume_trigger_pair(
+ input_device::assignment_vector &assignments,
+ ioport_type field1,
+ ioport_type field2,
+ input_item_id &axis1,
+ input_item_id &axis2);
+
+ static bool consume_axis_pair(
+ input_device::assignment_vector &assignments,
+ ioport_type field1,
+ ioport_type field2,
+ input_item_id &axis);
+
+ static void add_directional_assignments(
+ input_device::assignment_vector &assignments,
+ input_item_id xaxis,
+ input_item_id yaxis,
+ input_item_id leftswitch,
+ input_item_id rightswitch,
+ input_item_id upswitch,
+ input_item_id downswitch);
+
+ static void add_twin_stick_assignments(
+ input_device::assignment_vector &assignments,
+ input_item_id leftx,
+ input_item_id lefty,
+ input_item_id rightx,
+ input_item_id righty,
+ input_item_id leftleft,
+ input_item_id leftright,
+ input_item_id leftup,
+ input_item_id leftdown,
+ input_item_id rightleft,
+ input_item_id rightright,
+ input_item_id rightup,
+ input_item_id rightdown);
+
+ static void choose_primary_stick(
+ input_item_id (&stickaxes)[2][2],
+ input_item_id leftx,
+ input_item_id lefty,
+ input_item_id rightx,
+ input_item_id righty);
+};
+
+} // namespace osd
+
+#endif // MAME_OSD_INPUT_ASSIGNMENTHELPER_H
diff --git a/src/osd/modules/input/input_common.cpp b/src/osd/modules/input/input_common.cpp
index ab51b6bbe34..f3de3ca186e 100644
--- a/src/osd/modules/input/input_common.cpp
+++ b/src/osd/modules/input/input_common.cpp
@@ -8,201 +8,202 @@
//
//============================================================
-#include "input_module.h"
-#include "modules/lib/osdobj_common.h"
-
-#include <memory>
-
-// MAME headers
-#include "emu.h"
+#include "input_common.h"
-// winnt.h defines this
-#ifdef DELETE
-#undef DELETE
-#endif
+#include "modules/lib/osdobj_common.h"
-#include "input_common.h"
+#include "emu.h" // so we can get an input manager from the running machine
//============================================================
// Keyboard translation table
//============================================================
-#if defined(OSD_WINDOWS)
+#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
#include <windows.h>
-#define KEY_TRANS_ENTRY0(mame, sdlsc, sdlkey, disc, virtual, uwp, ascii, UI) { ITEM_ID_##mame, KEY_ ## disc, virtual, ascii, "ITEM_ID_"#mame, (char *) UI }
-#define KEY_TRANS_ENTRY1(mame, sdlsc, sdlkey, disc, virtual, uwp, ascii) { ITEM_ID_##mame, KEY_ ## disc, virtual, ascii, "ITEM_ID_"#mame, (char*) #mame }
-#elif defined(OSD_SDL)
-// SDL include
+#include <dinput.h>
+#define DIK_UNKNOWN 0xffff // intentionally impossible
+#define KEY_TRANS_WIN32(disc, virtual) DIK_##disc, virtual,
+#else
+#define KEY_TRANS_WIN32(disc, virtual)
+#endif
+
+#if defined(OSD_SDL) || defined(SDLMAME_WIN32)
#include <SDL2/SDL.h>
-#define KEY_TRANS_ENTRY0(mame, sdlsc, sdlkey, disc, virtual, uwp, ascii, UI) { ITEM_ID_##mame, SDL_SCANCODE_ ## sdlsc, ascii, "ITEM_ID_"#mame, (char *) UI }
-#define KEY_TRANS_ENTRY1(mame, sdlsc, sdlkey, disc, virtual, uwp, ascii) { ITEM_ID_##mame, SDL_SCANCODE_ ## sdlsc, ascii, "ITEM_ID_"#mame, (char*) #mame }
-#elif defined(OSD_UWP)
-#define KEY_TRANS_ENTRY0(mame, sdlsc, sdlkey, disc, virtual, uwp, ascii, UI) { ITEM_ID_##mame, KEY_ ## disc, Windows::System::VirtualKey:: ## uwp, ascii, "ITEM_ID_"#mame, (char *) UI }
-#define KEY_TRANS_ENTRY1(mame, sdlsc, sdlkey, disc, virtual, uwp, ascii) { ITEM_ID_##mame, KEY_ ## disc, Windows::System::VirtualKey:: ## uwp, ascii, "ITEM_ID_"#mame, (char*) #mame }
+#define KEY_TRANS_SDL(sdlsc) SDL_SCANCODE_##sdlsc,
#else
-// osd mini
+#define KEY_TRANS_SDL(sdlsc)
+#endif
+
+#define KEY_TRANS_ENTRY0(mame, sdlsc, disc, virtual, ascii, UI) { ITEM_ID_##mame, KEY_TRANS_SDL(sdlsc) KEY_TRANS_WIN32(disc, virtual) ascii, "ITEM_ID_"#mame, UI }
+#define KEY_TRANS_ENTRY1(mame, sdlsc, disc, virtual, ascii) { ITEM_ID_##mame, KEY_TRANS_SDL(sdlsc) KEY_TRANS_WIN32(disc, virtual) ascii, "ITEM_ID_"#mame, #mame }
+
+// winnt.h defines this
+#ifdef DELETE
+#undef DELETE
#endif
-// FIXME: sdl_key can be removed from the table below. It is no longer used.
+#if defined(OSD_WINDOWS) || defined(OSD_SDL)
-#if defined(OSD_WINDOWS) || defined(OSD_SDL) || defined(OSD_UWP)
key_trans_entry keyboard_trans_table::s_default_table[] =
{
- // MAME key sdl scancode sdl key di scancode virtual key uwp vkey ascii ui
- KEY_TRANS_ENTRY0(ESC, ESCAPE, ESCAPE, ESCAPE, VK_ESCAPE, Escape, 27, "ESCAPE"),
- KEY_TRANS_ENTRY1(1, 1, 1, 1, '1', Number1, '1'),
- KEY_TRANS_ENTRY1(2, 2, 2, 2, '2', Number2, '2'),
- KEY_TRANS_ENTRY1(3, 3, 3, 3, '3', Number3, '3'),
- KEY_TRANS_ENTRY1(4, 4, 4, 4, '4', Number4, '4'),
- KEY_TRANS_ENTRY1(5, 5, 5, 5, '5', Number5, '5'),
- KEY_TRANS_ENTRY1(6, 6, 6, 6, '6', Number6, '6'),
- KEY_TRANS_ENTRY1(7, 7, 7, 7, '7', Number7, '7'),
- KEY_TRANS_ENTRY1(8, 8, 8, 8, '8', Number8, '8'),
- KEY_TRANS_ENTRY1(9, 9, 9, 9, '9', Number9, '9'),
- KEY_TRANS_ENTRY1(0, 0, 0, 0, '0', Number0, '0'),
- KEY_TRANS_ENTRY1(MINUS, MINUS, MINUS, MINUS, VK_OEM_MINUS, None, '-'),
- KEY_TRANS_ENTRY1(EQUALS, EQUALS, EQUALS, EQUALS, VK_OEM_PLUS, None, '='),
- KEY_TRANS_ENTRY1(BACKSPACE, BACKSPACE, BACKSPACE, BACK, VK_BACK, Back, 8),
- KEY_TRANS_ENTRY1(TAB, TAB, TAB, TAB, VK_TAB, Tab, 9),
- KEY_TRANS_ENTRY1(Q, Q, q, Q, 'Q', Q, 'Q'),
- KEY_TRANS_ENTRY1(W, W, w, W, 'W', W, 'W'),
- KEY_TRANS_ENTRY1(E, E, e, E, 'E', E, 'E'),
- KEY_TRANS_ENTRY1(R, R, r, R, 'R', R, 'R'),
- KEY_TRANS_ENTRY1(T, T, t, T, 'T', T, 'T'),
- KEY_TRANS_ENTRY1(Y, Y, y, Y, 'Y', Y, 'Y'),
- KEY_TRANS_ENTRY1(U, U, u, U, 'U', U, 'U'),
- KEY_TRANS_ENTRY1(I, I, i, I, 'I', I, 'I'),
- KEY_TRANS_ENTRY1(O, O, o, O, 'O', O, 'O'),
- KEY_TRANS_ENTRY1(P, P, p, P, 'P', P, 'P'),
- KEY_TRANS_ENTRY1(OPENBRACE, LEFTBRACKET, LEFTBRACKET, LBRACKET, VK_OEM_4, None, '['),
- KEY_TRANS_ENTRY1(CLOSEBRACE, RIGHTBRACKET, RIGHTBRACKET, RBRACKET, VK_OEM_6, None, ']'),
- KEY_TRANS_ENTRY0(ENTER, RETURN, RETURN, RETURN, VK_RETURN, Enter, 13, "RETURN"),
- KEY_TRANS_ENTRY1(LCONTROL, LCTRL, LCTRL, LCONTROL, VK_LCONTROL, LeftControl, 0),
- KEY_TRANS_ENTRY1(A, A, a, A, 'A', A, 'A'),
- KEY_TRANS_ENTRY1(S, S, s, S, 'S', S, 'S'),
- KEY_TRANS_ENTRY1(D, D, d, D, 'D', D, 'D'),
- KEY_TRANS_ENTRY1(F, F, f, F, 'F', F, 'F'),
- KEY_TRANS_ENTRY1(G, G, g, G, 'G', G, 'G'),
- KEY_TRANS_ENTRY1(H, H, h, H, 'H', H, 'H'),
- KEY_TRANS_ENTRY1(J, J, j, J, 'J', J, 'J'),
- KEY_TRANS_ENTRY1(K, K, k, K, 'K', K, 'K'),
- KEY_TRANS_ENTRY1(L, L, l, L, 'L', L, 'L'),
- KEY_TRANS_ENTRY1(COLON, SEMICOLON, SEMICOLON, SEMICOLON, VK_OEM_1, None, ';'),
- KEY_TRANS_ENTRY1(QUOTE, APOSTROPHE, QUOTE, APOSTROPHE, VK_OEM_7, None, '\''),
- KEY_TRANS_ENTRY1(TILDE, GRAVE, BACKQUOTE, GRAVE, VK_OEM_3, None, '`'),
- KEY_TRANS_ENTRY1(LSHIFT, LSHIFT, LSHIFT, LSHIFT, VK_LSHIFT, LeftShift, 0),
- KEY_TRANS_ENTRY1(BACKSLASH, BACKSLASH, BACKSLASH, BACKSLASH, VK_OEM_5, None, '\\'),
-// KEY_TRANS_ENTRY1(BACKSLASH2, NONUSHASH, UNKNOWN, OEM_102, VK_OEM_102, None, '<'),
+ // MAME key SDL scancode DI scancode virtual key ASCII UI
+ KEY_TRANS_ENTRY0(ESC, ESCAPE, ESCAPE, VK_ESCAPE, 27, "ESCAPE"),
+ KEY_TRANS_ENTRY1(1, 1, 1, '1', '1'),
+ KEY_TRANS_ENTRY1(2, 2, 2, '2', '2'),
+ KEY_TRANS_ENTRY1(3, 3, 3, '3', '3'),
+ KEY_TRANS_ENTRY1(4, 4, 4, '4', '4'),
+ KEY_TRANS_ENTRY1(5, 5, 5, '5', '5'),
+ KEY_TRANS_ENTRY1(6, 6, 6, '6', '6'),
+ KEY_TRANS_ENTRY1(7, 7, 7, '7', '7'),
+ KEY_TRANS_ENTRY1(8, 8, 8, '8', '8'),
+ KEY_TRANS_ENTRY1(9, 9, 9, '9', '9'),
+ KEY_TRANS_ENTRY1(0, 0, 0, '0', '0'),
+ KEY_TRANS_ENTRY1(MINUS, MINUS, MINUS, VK_OEM_MINUS, '-'),
+ KEY_TRANS_ENTRY1(EQUALS, EQUALS, EQUALS, VK_OEM_PLUS, '='),
+ KEY_TRANS_ENTRY1(BACKSPACE, BACKSPACE, BACK, VK_BACK, 8),
+ KEY_TRANS_ENTRY1(TAB, TAB, TAB, VK_TAB, 9),
+ KEY_TRANS_ENTRY1(Q, Q, Q, 'Q', 'Q'),
+ KEY_TRANS_ENTRY1(W, W, W, 'W', 'W'),
+ KEY_TRANS_ENTRY1(E, E, E, 'E', 'E'),
+ KEY_TRANS_ENTRY1(R, R, R, 'R', 'R'),
+ KEY_TRANS_ENTRY1(T, T, T, 'T', 'T'),
+ KEY_TRANS_ENTRY1(Y, Y, Y, 'Y', 'Y'),
+ KEY_TRANS_ENTRY1(U, U, U, 'U', 'U'),
+ KEY_TRANS_ENTRY1(I, I, I, 'I', 'I'),
+ KEY_TRANS_ENTRY1(O, O, O, 'O', 'O'),
+ KEY_TRANS_ENTRY1(P, P, P, 'P', 'P'),
+ KEY_TRANS_ENTRY1(OPENBRACE, LEFTBRACKET, LBRACKET, VK_OEM_4, '['),
+ KEY_TRANS_ENTRY1(CLOSEBRACE, RIGHTBRACKET, RBRACKET, VK_OEM_6, ']'),
+ KEY_TRANS_ENTRY0(ENTER, RETURN, RETURN, VK_RETURN, 13, "RETURN"),
+ KEY_TRANS_ENTRY1(LCONTROL, LCTRL, LCONTROL, VK_LCONTROL, 0),
+ KEY_TRANS_ENTRY1(A, A, A, 'A', 'A'),
+ KEY_TRANS_ENTRY1(S, S, S, 'S', 'S'),
+ KEY_TRANS_ENTRY1(D, D, D, 'D', 'D'),
+ KEY_TRANS_ENTRY1(F, F, F, 'F', 'F'),
+ KEY_TRANS_ENTRY1(G, G, G, 'G', 'G'),
+ KEY_TRANS_ENTRY1(H, H, H, 'H', 'H'),
+ KEY_TRANS_ENTRY1(J, J, J, 'J', 'J'),
+ KEY_TRANS_ENTRY1(K, K, K, 'K', 'K'),
+ KEY_TRANS_ENTRY1(L, L, L, 'L', 'L'),
+ KEY_TRANS_ENTRY1(COLON, SEMICOLON, SEMICOLON, VK_OEM_1, ';'),
+ KEY_TRANS_ENTRY1(QUOTE, APOSTROPHE, APOSTROPHE, VK_OEM_7, '\''),
+ KEY_TRANS_ENTRY1(TILDE, GRAVE, GRAVE, VK_OEM_3, '`'),
+ KEY_TRANS_ENTRY1(LSHIFT, LSHIFT, LSHIFT, VK_LSHIFT, 0),
+ KEY_TRANS_ENTRY1(BACKSLASH, BACKSLASH, BACKSLASH, VK_OEM_5, '\\'),
+// KEY_TRANS_ENTRY1(BACKSLASH2, NONUSHASH, UNKNOWN, OEM_102, VK_OEM_102, '<'),
// This is the additional key that ISO keyboards have over ANSI ones, located between left shift and Y.
- KEY_TRANS_ENTRY1(BACKSLASH2, NONUSBACKSLASH, UNKNOWN, OEM_102, VK_OEM_102, None, '<'),
- KEY_TRANS_ENTRY1(Z, Z, z, Z, 'Z', Z, 'Z'),
- KEY_TRANS_ENTRY1(X, X, x, X, 'X', X, 'X'),
- KEY_TRANS_ENTRY1(C, C, c, C, 'C', C, 'C'),
- KEY_TRANS_ENTRY1(V, V, v, V, 'V', V, 'V'),
- KEY_TRANS_ENTRY1(B, B, b, B, 'B', B, 'B'),
- KEY_TRANS_ENTRY1(N, N, n, N, 'N', N, 'N'),
- KEY_TRANS_ENTRY1(M, M, m, M, 'M', M, 'M'),
- KEY_TRANS_ENTRY1(COMMA, COMMA, COMMA, COMMA, VK_OEM_COMMA, None, ','),
- KEY_TRANS_ENTRY1(STOP, PERIOD, PERIOD, PERIOD, VK_OEM_PERIOD, None, '.'),
- KEY_TRANS_ENTRY1(SLASH, SLASH, SLASH, SLASH, VK_OEM_2, None, '/'),
- KEY_TRANS_ENTRY1(RSHIFT, RSHIFT, RSHIFT, RSHIFT, VK_RSHIFT, RightShift, 0),
- KEY_TRANS_ENTRY1(ASTERISK, KP_MULTIPLY, KP_MULTIPLY, MULTIPLY, VK_MULTIPLY, Multiply, '*'),
- KEY_TRANS_ENTRY1(LALT, LALT, LALT, LMENU, VK_LMENU, LeftMenu, 0),
- KEY_TRANS_ENTRY1(SPACE, SPACE, SPACE, SPACE, VK_SPACE, Space, ' '),
- KEY_TRANS_ENTRY1(CAPSLOCK, CAPSLOCK, CAPSLOCK, CAPITAL, VK_CAPITAL, CapitalLock, 0),
- KEY_TRANS_ENTRY1(F1, F1, F1, F1, VK_F1, F1, 0),
- KEY_TRANS_ENTRY1(F2, F2, F2, F2, VK_F2, F2, 0),
- KEY_TRANS_ENTRY1(F3, F3, F3, F3, VK_F3, F3, 0),
- KEY_TRANS_ENTRY1(F4, F4, F4, F4, VK_F4, F4, 0),
- KEY_TRANS_ENTRY1(F5, F5, F5, F5, VK_F5, F5, 0),
- KEY_TRANS_ENTRY1(F6, F6, F6, F6, VK_F6, F6, 0),
- KEY_TRANS_ENTRY1(F7, F7, F7, F7, VK_F7, F7, 0),
- KEY_TRANS_ENTRY1(F8, F8, F8, F8, VK_F8, F8, 0),
- KEY_TRANS_ENTRY1(F9, F9, F9, F9, VK_F9, F9, 0),
- KEY_TRANS_ENTRY1(F10, F10, F10, F10, VK_F10, F10, 0),
- KEY_TRANS_ENTRY1(NUMLOCK, NUMLOCKCLEAR, NUMLOCKCLEAR, NUMLOCK, VK_NUMLOCK, NumberKeyLock, 0),
- KEY_TRANS_ENTRY1(SCRLOCK, SCROLLLOCK, SCROLLLOCK, SCROLL, VK_SCROLL, Scroll, 0),
- KEY_TRANS_ENTRY1(7_PAD, KP_7, KP_7, NUMPAD7, VK_NUMPAD7, NumberPad7, 0),
- KEY_TRANS_ENTRY1(8_PAD, KP_8, KP_8, NUMPAD8, VK_NUMPAD8, NumberPad8, 0),
- KEY_TRANS_ENTRY1(9_PAD, KP_9, KP_9, NUMPAD9, VK_NUMPAD9, NumberPad9, 0),
- KEY_TRANS_ENTRY1(MINUS_PAD, KP_MINUS, KP_MINUS, SUBTRACT, VK_SUBTRACT, Subtract, 0),
- KEY_TRANS_ENTRY1(4_PAD, KP_4, KP_4, NUMPAD4, VK_NUMPAD4, NumberPad4, 0),
- KEY_TRANS_ENTRY1(5_PAD, KP_5, KP_5, NUMPAD5, VK_NUMPAD5, NumberPad5, 0),
- KEY_TRANS_ENTRY1(6_PAD, KP_6, KP_6, NUMPAD6, VK_NUMPAD6, NumberPad6, 0),
- KEY_TRANS_ENTRY1(PLUS_PAD, KP_PLUS, KP_PLUS, ADD, VK_ADD, Add, 0),
- KEY_TRANS_ENTRY1(1_PAD, KP_1, KP_1, NUMPAD1, VK_NUMPAD1, NumberPad1, 0),
- KEY_TRANS_ENTRY1(2_PAD, KP_2, KP_2, NUMPAD2, VK_NUMPAD2, NumberPad2, 0),
- KEY_TRANS_ENTRY1(3_PAD, KP_3, KP_3, NUMPAD3, VK_NUMPAD3, NumberPad3, 0),
- KEY_TRANS_ENTRY1(0_PAD, KP_0, KP_0, NUMPAD0, VK_NUMPAD0, NumberPad0, 0),
- KEY_TRANS_ENTRY1(DEL_PAD, KP_PERIOD, KP_PERIOD, DECIMAL, VK_DECIMAL, Decimal, 0),
- KEY_TRANS_ENTRY1(F11, F11, F11, F11, VK_F11, F11, 0),
- KEY_TRANS_ENTRY1(F12, F12, F12, F12, VK_F12, F12, 0),
- KEY_TRANS_ENTRY1(F13, F13, F13, F13, VK_F13, F13, 0),
- KEY_TRANS_ENTRY1(F14, F14, F14, F14, VK_F14, F14, 0),
- KEY_TRANS_ENTRY1(F15, F15, F15, F15, VK_F15, F15, 0),
- KEY_TRANS_ENTRY1(ENTER_PAD, KP_ENTER, KP_ENTER, NUMPADENTER, VK_RETURN, None, 0),
- KEY_TRANS_ENTRY1(RCONTROL, RCTRL, RCTRL, RCONTROL, VK_RCONTROL, RightControl, 0),
- KEY_TRANS_ENTRY1(SLASH_PAD, KP_DIVIDE, KP_DIVIDE, DIVIDE, VK_DIVIDE, Divide, 0),
- KEY_TRANS_ENTRY1(PRTSCR, PRINTSCREEN, PRINTSCREEN, SYSRQ, 0, Print, 0),
- KEY_TRANS_ENTRY1(RALT, RALT, RALT, RMENU, VK_RMENU, RightMenu, 0),
- KEY_TRANS_ENTRY1(HOME, HOME, HOME, HOME, VK_HOME, Home, 0),
- KEY_TRANS_ENTRY1(UP, UP, UP, UP, VK_UP, Up, 0),
- KEY_TRANS_ENTRY1(PGUP, PAGEUP, PAGEUP, PRIOR, VK_PRIOR, PageUp, 0),
- KEY_TRANS_ENTRY1(LEFT, LEFT, LEFT, LEFT, VK_LEFT, Left, 0),
- KEY_TRANS_ENTRY1(RIGHT, RIGHT, RIGHT, RIGHT, VK_RIGHT, Right, 0),
- KEY_TRANS_ENTRY1(END, END, END, END, VK_END, End, 0),
- KEY_TRANS_ENTRY1(DOWN, DOWN, DOWN, DOWN, VK_DOWN, Down, 0),
- KEY_TRANS_ENTRY1(PGDN, PAGEDOWN, PAGEDOWN, NEXT, VK_NEXT, PageDown, 0),
- KEY_TRANS_ENTRY1(INSERT, INSERT, INSERT, INSERT, VK_INSERT, Insert, 0),
- KEY_TRANS_ENTRY0(DEL, DELETE, DELETE, DELETE, VK_DELETE, Delete, 0, "DELETE"),
- KEY_TRANS_ENTRY1(LWIN, LGUI, LGUI, LWIN, VK_LWIN, LeftWindows, 0),
- KEY_TRANS_ENTRY1(RWIN, RGUI, RGUI, RWIN, VK_RWIN, RightWindows, 0),
- KEY_TRANS_ENTRY1(MENU, MENU, MENU, APPS, VK_APPS, Menu, 0),
- KEY_TRANS_ENTRY1(PAUSE, PAUSE, PAUSE, PAUSE, VK_PAUSE, Pause, 0),
- KEY_TRANS_ENTRY0(CANCEL, CANCEL, CANCEL, UNKNOWN, 0, Cancel, 0, "CANCEL"),
- KEY_TRANS_ENTRY1(BS_PAD, KP_BACKSPACE, KP_BACKSPACE, UNKNOWN, 0, None, 0),
- KEY_TRANS_ENTRY1(TAB_PAD, KP_TAB, KP_TAB, UNKNOWN, 0, None, 0),
- KEY_TRANS_ENTRY1(00_PAD, KP_00, KP_00, UNKNOWN, 0, None, 0),
- KEY_TRANS_ENTRY1(000_PAD, KP_000, KP_000, UNKNOWN, 0, None, 0),
- KEY_TRANS_ENTRY1(COMMA_PAD, KP_COMMA, KP_COMMA, NUMPADCOMMA, 0, None, 0),
- KEY_TRANS_ENTRY1(EQUALS_PAD, KP_EQUALS, KP_EQUALS, NUMPADEQUALS, 0, None, 0),
-
- // New keys introduced in Windows 2000. These have no MAME codes to
- // preserve compatibility with old config files that may refer to them
- // as e.g. FORWARD instead of e.g. KEYCODE_WEBFORWARD. They need table
- // entries anyway because otherwise they aren't recognized when
- // GetAsyncKeyState polling is used (as happens currently when MAME is
- // paused). Some codes are missing because the mapping to vkey codes
- // isn't clear, and MapVirtualKey is no help.
- KEY_TRANS_ENTRY1(OTHER_SWITCH, MUTE, MUTE, MUTE, VK_VOLUME_MUTE, None, 0),
- KEY_TRANS_ENTRY1(OTHER_SWITCH, VOLUMEDOWN, VOLUMEDOWN, VOLUMEDOWN, VK_VOLUME_DOWN, None, 0),
- KEY_TRANS_ENTRY1(OTHER_SWITCH, VOLUMEUP, VOLUMEUP, VOLUMEUP, VK_VOLUME_UP, None, 0),
- KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_HOME, AC_HOME, WEBHOME, VK_BROWSER_HOME, None, 0),
- KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_SEARCH, AC_SEARCH, WEBSEARCH, VK_BROWSER_SEARCH, None, 0),
- KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_BOOKMARKS, AC_BOOKMARKS, WEBFAVORITES, VK_BROWSER_FAVORITES, None, 0),
- KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_REFRESH, AC_REFRESH, WEBREFRESH, VK_BROWSER_REFRESH, None, 0),
- KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_STOP, AC_STOP, WEBSTOP, VK_BROWSER_STOP, None, 0),
- KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_FORWARD, AC_FORWARD, WEBFORWARD, VK_BROWSER_FORWARD, None, 0),
- KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_BACK, AC_BACK, WEBBACK, VK_BROWSER_BACK, None, 0),
- KEY_TRANS_ENTRY1(OTHER_SWITCH, MAIL, MAIL, MAIL, VK_LAUNCH_MAIL, None, 0),
- KEY_TRANS_ENTRY1(OTHER_SWITCH, MEDIASELECT, MEDIASELECT, MEDIASELECT, VK_LAUNCH_MEDIA_SELECT, None, 0),
- KEY_TRANS_ENTRY0(INVALID, UNKNOWN, UNKNOWN, ESCAPE, 0, None, 0, "INVALID")
+ KEY_TRANS_ENTRY1(BACKSLASH2, NONUSBACKSLASH, OEM_102, VK_OEM_102, '<'),
+ KEY_TRANS_ENTRY1(Z, Z, Z, 'Z', 'Z'),
+ KEY_TRANS_ENTRY1(X, X, X, 'X', 'X'),
+ KEY_TRANS_ENTRY1(C, C, C, 'C', 'C'),
+ KEY_TRANS_ENTRY1(V, V, V, 'V', 'V'),
+ KEY_TRANS_ENTRY1(B, B, B, 'B', 'B'),
+ KEY_TRANS_ENTRY1(N, N, N, 'N', 'N'),
+ KEY_TRANS_ENTRY1(M, M, M, 'M', 'M'),
+ KEY_TRANS_ENTRY1(COMMA, COMMA, COMMA, VK_OEM_COMMA, ','),
+ KEY_TRANS_ENTRY1(STOP, PERIOD, PERIOD, VK_OEM_PERIOD, '.'),
+ KEY_TRANS_ENTRY1(SLASH, SLASH, SLASH, VK_OEM_2, '/'),
+ KEY_TRANS_ENTRY1(RSHIFT, RSHIFT, RSHIFT, VK_RSHIFT, 0),
+ KEY_TRANS_ENTRY1(ASTERISK, KP_MULTIPLY, MULTIPLY, VK_MULTIPLY, '*'),
+ KEY_TRANS_ENTRY1(LALT, LALT, LMENU, VK_LMENU, 0),
+ KEY_TRANS_ENTRY1(SPACE, SPACE, SPACE, VK_SPACE, ' '),
+ KEY_TRANS_ENTRY1(CAPSLOCK, CAPSLOCK, CAPITAL, VK_CAPITAL, 0),
+ KEY_TRANS_ENTRY1(F1, F1, F1, VK_F1, 0),
+ KEY_TRANS_ENTRY1(F2, F2, F2, VK_F2, 0),
+ KEY_TRANS_ENTRY1(F3, F3, F3, VK_F3, 0),
+ KEY_TRANS_ENTRY1(F4, F4, F4, VK_F4, 0),
+ KEY_TRANS_ENTRY1(F5, F5, F5, VK_F5, 0),
+ KEY_TRANS_ENTRY1(F6, F6, F6, VK_F6, 0),
+ KEY_TRANS_ENTRY1(F7, F7, F7, VK_F7, 0),
+ KEY_TRANS_ENTRY1(F8, F8, F8, VK_F8, 0),
+ KEY_TRANS_ENTRY1(F9, F9, F9, VK_F9, 0),
+ KEY_TRANS_ENTRY1(F10, F10, F10, VK_F10, 0),
+ KEY_TRANS_ENTRY1(NUMLOCK, NUMLOCKCLEAR, NUMLOCK, VK_NUMLOCK, 0),
+ KEY_TRANS_ENTRY1(SCRLOCK, SCROLLLOCK, SCROLL, VK_SCROLL, 0),
+ KEY_TRANS_ENTRY1(7_PAD, KP_7, NUMPAD7, VK_NUMPAD7, 0),
+ KEY_TRANS_ENTRY1(8_PAD, KP_8, NUMPAD8, VK_NUMPAD8, 0),
+ KEY_TRANS_ENTRY1(9_PAD, KP_9, NUMPAD9, VK_NUMPAD9, 0),
+ KEY_TRANS_ENTRY1(MINUS_PAD, KP_MINUS, SUBTRACT, VK_SUBTRACT, 0),
+ KEY_TRANS_ENTRY1(4_PAD, KP_4, NUMPAD4, VK_NUMPAD4, 0),
+ KEY_TRANS_ENTRY1(5_PAD, KP_5, NUMPAD5, VK_NUMPAD5, 0),
+ KEY_TRANS_ENTRY1(6_PAD, KP_6, NUMPAD6, VK_NUMPAD6, 0),
+ KEY_TRANS_ENTRY1(PLUS_PAD, KP_PLUS, ADD, VK_ADD, 0),
+ KEY_TRANS_ENTRY1(1_PAD, KP_1, NUMPAD1, VK_NUMPAD1, 0),
+ KEY_TRANS_ENTRY1(2_PAD, KP_2, NUMPAD2, VK_NUMPAD2, 0),
+ KEY_TRANS_ENTRY1(3_PAD, KP_3, NUMPAD3, VK_NUMPAD3, 0),
+ KEY_TRANS_ENTRY1(0_PAD, KP_0, NUMPAD0, VK_NUMPAD0, 0),
+ KEY_TRANS_ENTRY1(DEL_PAD, KP_PERIOD, DECIMAL, VK_DECIMAL, 0),
+ KEY_TRANS_ENTRY1(F11, F11, F11, VK_F11, 0),
+ KEY_TRANS_ENTRY1(F12, F12, F12, VK_F12, 0),
+ KEY_TRANS_ENTRY1(F13, F13, F13, VK_F13, 0),
+ KEY_TRANS_ENTRY1(F14, F14, F14, VK_F14, 0),
+ KEY_TRANS_ENTRY1(F15, F15, F15, VK_F15, 0),
+ KEY_TRANS_ENTRY1(ENTER_PAD, KP_ENTER, NUMPADENTER, VK_RETURN, 0),
+ KEY_TRANS_ENTRY1(RCONTROL, RCTRL, RCONTROL, VK_RCONTROL, 0),
+ KEY_TRANS_ENTRY1(SLASH_PAD, KP_DIVIDE, DIVIDE, VK_DIVIDE, 0),
+ KEY_TRANS_ENTRY1(PRTSCR, PRINTSCREEN, SYSRQ, 0, 0),
+ KEY_TRANS_ENTRY1(RALT, RALT, RMENU, VK_RMENU, 0),
+ KEY_TRANS_ENTRY1(HOME, HOME, HOME, VK_HOME, 0),
+ KEY_TRANS_ENTRY1(UP, UP, UP, VK_UP, 0),
+ KEY_TRANS_ENTRY1(PGUP, PAGEUP, PRIOR, VK_PRIOR, 0),
+ KEY_TRANS_ENTRY1(LEFT, LEFT, LEFT, VK_LEFT, 0),
+ KEY_TRANS_ENTRY1(RIGHT, RIGHT, RIGHT, VK_RIGHT, 0),
+ KEY_TRANS_ENTRY1(END, END, END, VK_END, 0),
+ KEY_TRANS_ENTRY1(DOWN, DOWN, DOWN, VK_DOWN, 0),
+ KEY_TRANS_ENTRY1(PGDN, PAGEDOWN, NEXT, VK_NEXT, 0),
+ KEY_TRANS_ENTRY1(INSERT, INSERT, INSERT, VK_INSERT, 0),
+ KEY_TRANS_ENTRY0(DEL, DELETE, DELETE, VK_DELETE, 0, "DELETE"),
+ KEY_TRANS_ENTRY1(LWIN, LGUI, LWIN, VK_LWIN, 0),
+ KEY_TRANS_ENTRY1(RWIN, RGUI, RWIN, VK_RWIN, 0),
+ KEY_TRANS_ENTRY1(MENU, MENU, APPS, VK_APPS, 0),
+ KEY_TRANS_ENTRY1(PAUSE, PAUSE, PAUSE, VK_PAUSE, 0),
+ KEY_TRANS_ENTRY1(CANCEL, CANCEL, UNKNOWN, 0, 0),
+ KEY_TRANS_ENTRY1(BS_PAD, KP_BACKSPACE, UNKNOWN, 0, 0),
+ KEY_TRANS_ENTRY1(TAB_PAD, KP_TAB, UNKNOWN, 0, 0),
+ KEY_TRANS_ENTRY1(00_PAD, KP_00, UNKNOWN, 0, 0),
+ KEY_TRANS_ENTRY1(000_PAD, KP_000, UNKNOWN, 0, 0),
+ KEY_TRANS_ENTRY1(COMMA_PAD, KP_COMMA, NUMPADCOMMA, VK_SEPARATOR, 0),
+ KEY_TRANS_ENTRY1(EQUALS_PAD, KP_EQUALS, NUMPADEQUALS, VK_OEM_NEC_EQUAL, 0),
+
+ // keys that have no specific MAME input item IDs
+ KEY_TRANS_ENTRY0(OTHER_SWITCH, AUDIONEXT, NEXTTRACK, VK_MEDIA_NEXT_TRACK, 0, "AUDIONEXT"),
+ KEY_TRANS_ENTRY0(OTHER_SWITCH, AUDIOMUTE, MUTE, VK_VOLUME_MUTE, 0, "VOLUMEMUTE"),
+ KEY_TRANS_ENTRY0(OTHER_SWITCH, AUDIOPLAY, PLAYPAUSE, VK_MEDIA_PLAY_PAUSE, 0, "AUDIOPLAY"),
+ KEY_TRANS_ENTRY0(OTHER_SWITCH, AUDIOSTOP, MEDIASTOP, VK_MEDIA_STOP, 0, "AUDIOSTOP"),
+ KEY_TRANS_ENTRY0(OTHER_SWITCH, VOLUMEDOWN, VOLUMEDOWN, VK_VOLUME_DOWN, 0, "VOLUMEDOWN"),
+ KEY_TRANS_ENTRY0(OTHER_SWITCH, VOLUMEUP, VOLUMEUP, VK_VOLUME_UP, 0, "VOLUMEUP"),
+ KEY_TRANS_ENTRY0(OTHER_SWITCH, AC_HOME, WEBHOME, VK_BROWSER_HOME, 0, "NAVHOME"),
+ KEY_TRANS_ENTRY0(OTHER_SWITCH, AC_SEARCH, WEBSEARCH, VK_BROWSER_SEARCH, 0, "NAVSEARCH"),
+ KEY_TRANS_ENTRY0(OTHER_SWITCH, AC_BOOKMARKS, WEBFAVORITES, VK_BROWSER_FAVORITES, 0, "NAVFAVORITES"),
+ KEY_TRANS_ENTRY0(OTHER_SWITCH, AC_REFRESH, WEBREFRESH, VK_BROWSER_REFRESH, 0, "NAVREFRESH"),
+ KEY_TRANS_ENTRY0(OTHER_SWITCH, AC_STOP, WEBSTOP, VK_BROWSER_STOP, 0, "NAVSTOP"),
+ KEY_TRANS_ENTRY0(OTHER_SWITCH, AC_FORWARD, WEBFORWARD, VK_BROWSER_FORWARD, 0, "NAVFORWARD"),
+ KEY_TRANS_ENTRY0(OTHER_SWITCH, AC_BACK, WEBBACK, VK_BROWSER_BACK, 0, "NAVBACK"),
+ KEY_TRANS_ENTRY0(OTHER_SWITCH, MAIL, MAIL, VK_LAUNCH_MAIL, 0, "MAIL"),
+ KEY_TRANS_ENTRY0(OTHER_SWITCH, MEDIASELECT, MEDIASELECT, VK_LAUNCH_MEDIA_SELECT, 0, "MEDIASEL"),
+
+ // sentinel
+ KEY_TRANS_ENTRY0(INVALID, UNKNOWN, UNKNOWN, 0, 0, "INVALID")
};
// The private constructor to create the default instance
keyboard_trans_table::keyboard_trans_table()
{
m_table = s_default_table;
- m_table_size = ARRAY_LENGTH(s_default_table);
+ m_table_size = std::size(s_default_table);
}
-#else
+
+#else // defined(OSD_WINDOWS) || defined(OSD_SDL)
+
keyboard_trans_table::keyboard_trans_table()
{
m_table = nullptr;
m_table_size = 0;
}
-#endif
+#endif // defined(OSD_WINDOWS) || defined(OSD_SDL)
+
+
// public constructor to allow creation of non-default instances
keyboard_trans_table::keyboard_trans_table(std::unique_ptr<key_trans_entry[]> entries, unsigned int size)
{
@@ -231,14 +232,12 @@ input_item_id keyboard_trans_table::lookup_mame_code(const char *scode) const
}
// Windows specific lookup methods
-#if defined(OSD_WINDOWS) || defined(OSD_UWP)
+#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
input_item_id keyboard_trans_table::map_di_scancode_to_itemid(int scancode) const
{
- int tablenum;
-
// scan the table for a match
- for (tablenum = 0; tablenum < m_table_size; tablenum++)
+ for (int tablenum = 0; tablenum < m_table_size; tablenum++)
if (m_table[tablenum].scan_code == scancode)
return m_table[tablenum].mame_key;
@@ -246,10 +245,6 @@ input_item_id keyboard_trans_table::map_di_scancode_to_itemid(int scancode) cons
return ITEM_ID_OTHER_SWITCH;
}
-#endif
-
-#if defined(OSD_WINDOWS)
-
//============================================================
// wininput_vkey_for_mame_code
//============================================================
@@ -259,48 +254,53 @@ int keyboard_trans_table::vkey_for_mame_code(input_code code) const
// only works for keyboard switches
if (code.device_class() == DEVICE_CLASS_KEYBOARD && code.item_class() == ITEM_CLASS_SWITCH)
{
- input_item_id id = code.item_id();
- int tablenum;
+ const input_item_id id = code.item_id();
// scan the table for a match
- for (tablenum = 0; tablenum < m_table_size; tablenum++)
+ for (int tablenum = 0; tablenum < m_table_size; tablenum++)
if (m_table[tablenum].mame_key == id)
return m_table[tablenum].virtual_key;
}
return 0;
}
-#endif
-
-#if defined(OSD_UWP)
+#endif // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
-const char* keyboard_trans_table::ui_label_for_mame_key(input_item_id itemid) const
+input_module_base::input_module_base(const char *type, const char* name) :
+ osd_module(type, name),
+ m_clock(),
+ m_last_poll(timepoint_type::min()),
+ m_background_input(false),
+ m_options(nullptr),
+ m_manager(nullptr)
{
- // scan the table for a match
- for (int tablenum = 0; tablenum < m_table_size; tablenum++)
- if (m_table[tablenum].mame_key == itemid)
- return m_table[tablenum].ui_name;
-
- // We didn't find one
- return nullptr;
}
-#endif
-
-
-int input_module_base::init(const osd_options &options)
+int input_module_base::init(osd_interface &osd, const osd_options &options)
{
m_options = &options;
- m_mouse_enabled = options.mouse();
- m_lightgun_enabled = options.lightgun();
+ // don't enable background input when debugging
+ m_background_input = !options.debug() && options.background_input();
+
+ return 0;
+}
+
+void input_module_base::input_init(running_machine &machine)
+{
+ m_manager = &machine.input();
+}
- int result = init_internal();
- if (result != 0)
- return result;
+void input_module_base::poll_if_necessary(bool relative_reset)
+{
+ timepoint_type const now = m_clock.now();
+ if (relative_reset || (now >= (m_last_poll + std::chrono::milliseconds(MIN_POLLING_INTERVAL))))
+ {
+ // grab the current time
+ m_last_poll = now;
- m_input_paused = false;
- m_input_enabled = true;
+ before_poll();
- return 0;
+ poll(relative_reset);
+ }
}
diff --git a/src/osd/modules/input/input_common.h b/src/osd/modules/input/input_common.h
index b4005a6b76a..73ddd2bf936 100644
--- a/src/osd/modules/input/input_common.h
+++ b/src/osd/modules/input/input_common.h
@@ -7,20 +7,26 @@
// SDLMAME by Olivier Galibert and R. Belmont
//
//============================================================
+#ifndef MAME_OSD_INPUT_INPUT_COMMON_H
+#define MAME_OSD_INPUT_INPUT_COMMON_H
-#ifndef INPUT_COMMON_H_
-#define INPUT_COMMON_H_
+#pragma once
#include "input_module.h"
-#include "inputdev.h"
+#include "interface/inputdev.h"
+#include "interface/inputman.h"
+#include "modules/osdmodule.h"
+#include "util/strformat.h"
+
+#include <algorithm>
+#include <cassert>
#include <chrono>
+#include <functional>
#include <memory>
#include <mutex>
#include <queue>
-#include <algorithm>
-#include <functional>
//============================================================
@@ -41,225 +47,66 @@ enum
#define MAX_HATS 8
#define MAX_POV 4
-/****************************************************************************
-* DirectInput compatible keyboard scan codes
-****************************************************************************/
-#define KEY_UNKNOWN 0x00
-#define KEY_ESCAPE 0x01
-#define KEY_1 0x02
-#define KEY_2 0x03
-#define KEY_3 0x04
-#define KEY_4 0x05
-#define KEY_5 0x06
-#define KEY_6 0x07
-#define KEY_7 0x08
-#define KEY_8 0x09
-#define KEY_9 0x0A
-#define KEY_0 0x0B
-#define KEY_MINUS 0x0C /* - on main keyboard */
-#define KEY_EQUALS 0x0D
-#define KEY_BACK 0x0E /* backspace */
-#define KEY_TAB 0x0F
-#define KEY_Q 0x10
-#define KEY_W 0x11
-#define KEY_E 0x12
-#define KEY_R 0x13
-#define KEY_T 0x14
-#define KEY_Y 0x15
-#define KEY_U 0x16
-#define KEY_I 0x17
-#define KEY_O 0x18
-#define KEY_P 0x19
-#define KEY_LBRACKET 0x1A
-#define KEY_RBRACKET 0x1B
-#define KEY_RETURN 0x1C /* Enter on main keyboard */
-#define KEY_LCONTROL 0x1D
-#define KEY_A 0x1E
-#define KEY_S 0x1F
-#define KEY_D 0x20
-#define KEY_F 0x21
-#define KEY_G 0x22
-#define KEY_H 0x23
-#define KEY_J 0x24
-#define KEY_K 0x25
-#define KEY_L 0x26
-#define KEY_SEMICOLON 0x27
-#define KEY_APOSTROPHE 0x28
-#define KEY_GRAVE 0x29 /* accent grave */
-#define KEY_LSHIFT 0x2A
-#define KEY_BACKSLASH 0x2B
-#define KEY_Z 0x2C
-#define KEY_X 0x2D
-#define KEY_C 0x2E
-#define KEY_V 0x2F
-#define KEY_B 0x30
-#define KEY_N 0x31
-#define KEY_M 0x32
-#define KEY_COMMA 0x33
-#define KEY_PERIOD 0x34 /* . on main keyboard */
-#define KEY_SLASH 0x35 /* / on main keyboard */
-#define KEY_RSHIFT 0x36
-#define KEY_MULTIPLY 0x37 /* * on numeric keypad */
-#define KEY_LMENU 0x38 /* left Alt */
-#define KEY_SPACE 0x39
-#define KEY_CAPITAL 0x3A
-#define KEY_F1 0x3B
-#define KEY_F2 0x3C
-#define KEY_F3 0x3D
-#define KEY_F4 0x3E
-#define KEY_F5 0x3F
-#define KEY_F6 0x40
-#define KEY_F7 0x41
-#define KEY_F8 0x42
-#define KEY_F9 0x43
-#define KEY_F10 0x44
-#define KEY_NUMLOCK 0x45
-#define KEY_SCROLL 0x46 /* Scroll Lock */
-#define KEY_NUMPAD7 0x47
-#define KEY_NUMPAD8 0x48
-#define KEY_NUMPAD9 0x49
-#define KEY_SUBTRACT 0x4A /* - on numeric keypad */
-#define KEY_NUMPAD4 0x4B
-#define KEY_NUMPAD5 0x4C
-#define KEY_NUMPAD6 0x4D
-#define KEY_ADD 0x4E /* + on numeric keypad */
-#define KEY_NUMPAD1 0x4F
-#define KEY_NUMPAD2 0x50
-#define KEY_NUMPAD3 0x51
-#define KEY_NUMPAD0 0x52
-#define KEY_DECIMAL 0x53 /* . on numeric keypad */
-#define KEY_OEM_102 0x56 /* <> or \| on RT 102-key keyboard (Non-U.S.) */
-#define KEY_F11 0x57
-#define KEY_F12 0x58
-#define KEY_F13 0x64 /* (NEC PC98) */
-#define KEY_F14 0x65 /* (NEC PC98) */
-#define KEY_F15 0x66 /* (NEC PC98) */
-#define KEY_KANA 0x70 /* (Japanese keyboard) */
-#define KEY_ABNT_C1 0x73 /* /? on Brazilian keyboard */
-#define KEY_CONVERT 0x79 /* (Japanese keyboard) */
-#define KEY_NOCONVERT 0x7B /* (Japanese keyboard) */
-#define KEY_YEN 0x7D /* (Japanese keyboard) */
-#define KEY_ABNT_C2 0x7E /* Numpad . on Brazilian keyboard */
-#define KEY_NUMPADEQUALS 0x8D /* = on numeric keypad (NEC PC98) */
-#define KEY_PREVTRACK 0x90 /* Previous Track (DIK_CIRCUMFLEX on Japanese keyboard) */
-#define KEY_AT 0x91 /* (NEC PC98) */
-#define KEY_COLON 0x92 /* (NEC PC98) */
-#define KEY_UNDERLINE 0x93 /* (NEC PC98) */
-#define KEY_KANJI 0x94 /* (Japanese keyboard) */
-#define KEY_STOP 0x95 /* (NEC PC98) */
-#define KEY_AX 0x96 /* (Japan AX) */
-#define KEY_UNLABELED 0x97 /* (J3100) */
-#define KEY_NEXTTRACK 0x99 /* Next Track */
-#define KEY_NUMPADENTER 0x9C /* Enter on numeric keypad */
-#define KEY_RCONTROL 0x9D
-#define KEY_MUTE 0xA0 /* Mute */
-#define KEY_CALCULATOR 0xA1 /* Calculator */
-#define KEY_PLAYPAUSE 0xA2 /* Play / Pause */
-#define KEY_MEDIASTOP 0xA4 /* Media Stop */
-#define KEY_VOLUMEDOWN 0xAE /* Volume - */
-#define KEY_VOLUMEUP 0xB0 /* Volume + */
-#define KEY_WEBHOME 0xB2 /* Web home */
-#define KEY_NUMPADCOMMA 0xB3 /* , on numeric keypad (NEC PC98) */
-#define KEY_DIVIDE 0xB5 /* / on numeric keypad */
-#define KEY_SYSRQ 0xB7
-#define KEY_RMENU 0xB8 /* right Alt */
-#define KEY_PAUSE 0xC5 /* Pause */
-#define KEY_HOME 0xC7 /* Home on arrow keypad */
-#define KEY_UP 0xC8 /* UpArrow on arrow keypad */
-#define KEY_PRIOR 0xC9 /* PgUp on arrow keypad */
-#define KEY_LEFT 0xCB /* LeftArrow on arrow keypad */
-#define KEY_RIGHT 0xCD /* RightArrow on arrow keypad */
-#define KEY_END 0xCF /* End on arrow keypad */
-#define KEY_DOWN 0xD0 /* DownArrow on arrow keypad */
-#define KEY_NEXT 0xD1 /* PgDn on arrow keypad */
-#define KEY_INSERT 0xD2 /* Insert on arrow keypad */
-#define KEY_DELETE 0xD3 /* Delete on arrow keypad */
-#define KEY_LWIN 0xDB /* Left Windows key */
-#define KEY_RWIN 0xDC /* Right Windows key */
-#define KEY_APPS 0xDD /* AppMenu key */
-#define KEY_POWER 0xDE /* System Power */
-#define KEY_SLEEP 0xDF /* System Sleep */
-#define KEY_WAKE 0xE3 /* System Wake */
-#define KEY_WEBSEARCH 0xE5 /* Web Search */
-#define KEY_WEBFAVORITES 0xE6 /* Web Favorites */
-#define KEY_WEBREFRESH 0xE7 /* Web Refresh */
-#define KEY_WEBSTOP 0xE8 /* Web Stop */
-#define KEY_WEBFORWARD 0xE9 /* Web Forward */
-#define KEY_WEBBACK 0xEA /* Web Back */
-#define KEY_MYCOMPUTER 0xEB /* My Computer */
-#define KEY_MAIL 0xEC /* Mail */
-#define KEY_MEDIASELECT 0xED /* Media Select */
//============================================================
// device_info
//============================================================
-class input_device_list;
-
class device_info
{
- friend input_device_list;
-
private:
- std::string m_name;
- std::string m_id;
- input_device * m_device;
- running_machine & m_machine;
+ const std::string m_name;
+ const std::string m_id;
input_module & m_module;
- input_device_class m_deviceclass;
public:
// Constructor
- device_info(running_machine &machine, const char *name, const char *id, input_device_class deviceclass, input_module &module)
- : m_name(name),
- m_id(id),
- m_device(nullptr),
- m_machine(machine),
- m_module(module),
- m_deviceclass(deviceclass)
+ device_info(std::string &&name, std::string &&id, input_module &module) :
+ m_name(std::move(name)),
+ m_id(std::move(id)),
+ m_module(module)
{
}
// Destructor
- virtual ~device_info() {}
+ virtual ~device_info() = default;
// Getters
- running_machine & machine() const { return m_machine; }
- const char * name() const { return m_name.c_str(); }
- const char * id() const { return m_id.c_str(); }
- input_device * device() const { return m_device; }
- input_module & module() const { return m_module; }
- input_device_class deviceclass() const { return m_deviceclass; }
+ const std::string &name() const { return m_name; }
+ const std::string &id() const { return m_id; }
+ input_module &module() const { return m_module; }
// Poll and reset methods
- virtual void poll() {};
+ virtual void poll(bool relative_reset) = 0;
virtual void reset() = 0;
+ virtual void configure(osd::input_device &device) = 0;
};
+
//============================================================
// event_based_device
//============================================================
-#define DEFAULT_EVENT_QUEUE_SIZE 20
-
template <class TEvent>
class event_based_device : public device_info
{
private:
- std::queue<TEvent> m_event_queue;
+ static inline constexpr unsigned DEFAULT_EVENT_QUEUE_SIZE = 64;
+
+ std::queue<TEvent> m_event_queue;
protected:
std::mutex m_device_lock;
- virtual void process_event(TEvent &ev) = 0;
+ virtual void process_event(TEvent const &ev) = 0;
public:
- event_based_device(running_machine &machine, const char *name, const char *id, input_device_class deviceclass, input_module &module)
- : device_info(machine, name, id, deviceclass, module)
+ event_based_device(std::string &&name, std::string &&id, input_module &module) :
+ device_info(std::move(name), std::move(id), module)
{
}
- void queue_events(const TEvent *events, int count)
+ void queue_events(TEvent const *events, int count)
{
std::lock_guard<std::mutex> scope_lock(m_device_lock);
for (int i = 0; i < count; i++)
@@ -270,38 +117,46 @@ public:
m_event_queue.pop();
}
- void virtual poll() override
+ virtual void poll(bool relative_reset) override
{
std::lock_guard<std::mutex> scope_lock(m_device_lock);
// Process each event until the queue is empty
while (!m_event_queue.empty())
{
- TEvent &next_event = m_event_queue.front();
- process_event(next_event);
+ process_event(m_event_queue.front());
m_event_queue.pop();
}
}
+
+ virtual void reset() override
+ {
+ std::lock_guard<std::mutex> scope_lock(m_device_lock);
+ std::queue<TEvent>().swap(m_event_queue);
+ }
};
+
//============================================================
// input_device_list class
//============================================================
+template <typename Info>
class input_device_list
{
private:
- std::vector<std::unique_ptr<device_info>> m_list;
+ std::vector<std::unique_ptr<Info> > m_list;
public:
- size_t size() const { return m_list.size(); }
- auto begin() { return m_list.begin(); }
- auto end() { return m_list.end(); }
+ auto size() const { return m_list.size(); }
+ auto empty() const { return m_list.empty(); }
+ auto begin() const { return m_list.begin(); }
+ auto end() const { return m_list.end(); }
- void poll_devices()
+ void poll_devices(bool relative_reset)
{
for (auto &device: m_list)
- device->poll();
+ device->poll(relative_reset);
}
void reset_devices()
@@ -310,17 +165,11 @@ public:
device->reset();
}
- void free_device(device_info* devinfo)
- {
- // find the device to remove
- auto device_matches = [devinfo](std::unique_ptr<device_info> &device) { return devinfo == device.get(); };
- m_list.erase(std::remove_if(std::begin(m_list), std::end(m_list), device_matches), m_list.end());
- }
-
- void for_each_device(std::function<void (device_info*)> action)
+ template <typename T>
+ void for_each_device(T &&action)
{
for (auto &device: m_list)
- action(device.get());
+ action(*device);
}
void free_all_devices()
@@ -329,46 +178,34 @@ public:
m_list.pop_back();
}
- template <typename TActual, typename... TArgs>
- TActual* create_device(running_machine &machine, const char *name, const char *id, input_module &module, TArgs&&... args)
+ template <typename Actual>
+ Actual &add_device(std::unique_ptr<Actual> &&devinfo)
{
- // allocate the device object
- auto devinfo = std::make_unique<TActual>(machine, name, id, module, std::forward<TArgs>(args)...);
-
- return add_device(machine, std::move(devinfo));
- }
-
- template <typename TActual>
- TActual* add_device(running_machine &machine, std::unique_ptr<TActual> devinfo)
- {
- // Add the device to the machine
- devinfo->m_device = machine.input().device_class(devinfo->deviceclass()).add_device(devinfo->name(), devinfo->id(), devinfo.get());
-
- // append us to the list
- m_list.push_back(std::move(devinfo));
-
- return static_cast<TActual*>(m_list.back().get());
+ // append us to the list and return reference
+ Actual &result = *devinfo;
+ m_list.emplace_back(std::move(devinfo));
+ return result;
}
};
+
// keyboard translation table
-struct key_trans_entry {
+struct key_trans_entry
+{
input_item_id mame_key;
-#if defined(OSD_SDL)
+#if defined(OSD_SDL) || defined(SDLMAME_WIN32)
int sdl_scancode;
-#elif defined(OSD_WINDOWS)
- int scan_code;
+#endif
+#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
+ uint16_t scan_code;
unsigned char virtual_key;
-#elif defined(OSD_UWP)
- int scan_code;
- Windows::System::VirtualKey virtual_key;
#endif
char ascii_key;
- char const * mame_key_name;
- char * ui_name;
+ char const * mame_key_name;
+ char const * ui_name;
};
class keyboard_trans_table
@@ -381,7 +218,7 @@ private:
std::unique_ptr<key_trans_entry[]> m_custom_table;
key_trans_entry * m_table;
- uint32_t m_table_size;
+ uint32_t m_table_size;
public:
// constructor
@@ -394,12 +231,9 @@ public:
input_item_id lookup_mame_code(const char * scode) const;
int lookup_mame_index(const char * scode) const;
-#if defined(OSD_WINDOWS)
+#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
input_item_id map_di_scancode_to_itemid(int di_scancode) const;
int vkey_for_mame_code(input_code code) const;
-#elif defined(OSD_UWP)
- input_item_id map_di_scancode_to_itemid(int di_scancode) const;
- const char* ui_label_for_mame_key(input_item_id code) const;
#endif
static keyboard_trans_table& instance()
@@ -411,155 +245,153 @@ public:
key_trans_entry & operator [](int i) const { return m_table[i]; }
};
+
//============================================================
// input_module_base - base class for input modules
//============================================================
-class osd_options;
-
-typedef std::chrono::high_resolution_clock clock_type;
-typedef std::chrono::time_point<std::chrono::high_resolution_clock> timepoint_type;
-
-// 10 milliseconds polling interval
-#define MIN_POLLING_INTERVAL 10
-
-class input_module_base : public input_module
+class input_module_base : public osd_module, public input_module
{
-public:
- input_module_base(const char *type, const char* name)
- : input_module(type, name),
- m_input_enabled(false),
- m_mouse_enabled(false),
- m_lightgun_enabled(false),
- m_input_paused(false),
- m_options(nullptr)
- {
- }
-
private:
- bool m_input_enabled;
- bool m_mouse_enabled;
- bool m_lightgun_enabled;
- bool m_input_paused;
- const osd_options * m_options;
- input_device_list m_devicelist;
+ // 10 milliseconds polling interval
+ static constexpr inline unsigned MIN_POLLING_INTERVAL = 2;
+
+ using clock_type = std::chrono::high_resolution_clock;
+ using timepoint_type = std::chrono::time_point<std::chrono::high_resolution_clock>;
+
clock_type m_clock;
timepoint_type m_last_poll;
+ bool m_background_input;
+ const osd_options * m_options;
+ osd::input_manager * m_manager;
+
+ virtual void poll(bool relative_reset) = 0;
protected:
- void set_mouse_enabled(bool value) { m_mouse_enabled = value; }
+ input_module_base(char const *type, char const *name);
+
+ osd::input_manager & manager() { assert(m_manager); return *m_manager; }
+ const osd_options * options() const { return m_options; }
+ bool background_input() const { return m_background_input; }
+
+ virtual void before_poll() { }
public:
+ virtual int init(osd_interface &osd, const osd_options &options) override;
- const osd_options * options() const { return m_options; }
- input_device_list * devicelist() { return &m_devicelist; }
- bool input_enabled() const { return m_input_enabled; }
- bool input_paused() const { return m_input_paused; }
- bool mouse_enabled() const { return m_mouse_enabled; }
- bool lightgun_enabled() const { return m_lightgun_enabled; }
+ virtual void input_init(running_machine &machine) override;
+ virtual void poll_if_necessary(bool relative_reset) override;
+
+ virtual void reset_devices() = 0; // SDL OSD uses this to forcibly release keys
+};
- int init(const osd_options &options) override;
- void poll_if_necessary(running_machine &machine) override
+//============================================================
+// input_module_impl - base class for input modules
+//============================================================
+
+template <typename Info, typename OsdImpl>
+class input_module_impl : public input_module_base
+{
+public:
+ virtual void exit() override
{
- auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(m_clock.now() - m_last_poll);
- if (elapsed.count() >= MIN_POLLING_INTERVAL)
- {
- poll(machine);
- }
+ devicelist().free_all_devices();
}
- virtual void poll(running_machine &machine)
+ virtual int init(osd_interface &osd, const osd_options &options) override
{
- // ignore if not enabled
- if (m_input_enabled)
- {
- // grab the current time
- m_last_poll = m_clock.now();
+ m_osd = dynamic_cast<OsdImpl *>(&osd);
+ if (!m_osd)
+ return -1;
- before_poll(machine);
+ return input_module_base::init(osd, options);
+ }
- // track if mouse/lightgun is enabled, for mouse hiding purposes
- m_mouse_enabled = machine.input().device_class(DEVICE_CLASS_MOUSE).enabled();
- m_lightgun_enabled = machine.input().device_class(DEVICE_CLASS_LIGHTGUN).enabled();
- }
+ virtual void reset_devices() override { devicelist().reset_devices(); }
- // poll all of the devices
- if (should_poll_devices(machine))
- {
- m_devicelist.poll_devices();
- }
- else
- {
- m_devicelist.reset_devices();
- }
+protected:
+ using input_module_base::input_module_base;
+
+ input_device_list<Info> &devicelist() { return m_devicelist; }
+ OsdImpl &osd() { assert(m_osd); return *m_osd; }
+
+ virtual void before_poll() override
+ {
+ // periodically process events, in case they're not coming through
+ // this also will make sure the mouse state is up-to-date
+ osd().process_events();
}
- virtual void pause() override
+ virtual bool should_poll_devices()
{
- // keep track of the paused state
- m_input_paused = true;
+ return background_input() || osd().has_focus();
}
- virtual void resume() override
+ template <typename Actual, typename... Params>
+ Actual &create_device(input_device_class deviceclass, std::string &&name, std::string &&id, Params &&... args)
{
- // keep track of the paused state
- m_input_paused = false;
+ // allocate the device object and add it to the input manager
+ return add_device(
+ deviceclass,
+ std::make_unique<Actual>(std::move(name), std::move(id), *this, std::forward<Params>(args)...));
}
- virtual void exit() override
+ template <typename Actual>
+ Actual &add_device(input_device_class deviceclass, std::unique_ptr<Actual> &&devinfo)
{
- devicelist()->free_all_devices();
+ // add it to the input manager and append it to the list
+ osd::input_device &osddev = manager().add_device(deviceclass, devinfo->name(), devinfo->id(), devinfo.get());
+ devinfo->configure(osddev);
+ return devicelist().add_device(std::move(devinfo));
}
-protected:
- virtual int init_internal() { return 0; }
- virtual bool should_poll_devices(running_machine &machine) = 0;
- virtual void before_poll(running_machine &machine) {}
+private:
+ virtual void poll(bool relative_reset) override final
+ {
+ // poll all of the devices
+ if (should_poll_devices())
+ m_devicelist.poll_devices(relative_reset);
+ else
+ m_devicelist.reset_devices();
+ }
+
+ input_device_list<Info> m_devicelist;
+ OsdImpl *m_osd = nullptr;
};
+
template <class TItem>
int generic_button_get_state(void *device_internal, void *item_internal)
{
- device_info *devinfo = static_cast<device_info *>(device_internal);
- TItem *itemdata = static_cast<TItem*>(item_internal);
-
// return the current state
- devinfo->module().poll_if_necessary(devinfo->machine());
- return *itemdata >> 7;
+ return *reinterpret_cast<TItem const *>(item_internal) >> 7;
}
+
template <class TItem>
int generic_axis_get_state(void *device_internal, void *item_internal)
{
- device_info *devinfo = static_cast<device_info *>(device_internal);
- TItem *axisdata = static_cast<TItem*>(item_internal);
-
- // return the current state
- devinfo->module().poll_if_necessary(devinfo->machine());
- return *axisdata;
+ return *reinterpret_cast<TItem const *>(item_internal);
}
+
//============================================================
// default_button_name
//============================================================
-inline static const char *default_button_name(int which)
+inline std::string default_button_name(int which)
{
- static char buffer[20];
- snprintf(buffer, ARRAY_LENGTH(buffer), "B%d", which);
- return buffer;
+ return util::string_format("Button %d", which + 1);
}
//============================================================
// default_pov_name
//============================================================
-inline static const char *default_pov_name(int which)
+inline std::string default_pov_name(int which)
{
- static char buffer[20];
- snprintf(buffer, ARRAY_LENGTH(buffer), "POV%d", which);
- return buffer;
+ return util::string_format("Hat %d", which + 1);
}
// default axis names
@@ -569,27 +401,25 @@ const char *const default_axis_name[] =
"RY", "RZ", "SL1", "SL2"
};
-inline static int32_t normalize_absolute_axis(double raw, double rawmin, double rawmax)
+inline int32_t normalize_absolute_axis(double raw, double rawmin, double rawmax)
{
- double center = (rawmax + rawmin) / 2.0;
-
- // make sure we have valid data
+ // make sure we have valid arguments
if (rawmin >= rawmax)
return int32_t(raw);
- // above center
+ double const center = (rawmax + rawmin) / 2.0;
if (raw >= center)
{
- double result = (raw - center) * INPUT_ABSOLUTE_MAX / (rawmax - center);
- return std::min(result, (double)INPUT_ABSOLUTE_MAX);
+ // above center
+ double const result = (raw - center) * double(osd::input_device::ABSOLUTE_MAX) / (rawmax - center);
+ return int32_t(std::min(result, double(osd::input_device::ABSOLUTE_MAX)));
}
-
- // below center
else
{
- double result = -((center - raw) * (double)-INPUT_ABSOLUTE_MIN / (center - rawmin));
- return std::max(result, (double)INPUT_ABSOLUTE_MIN);
+ // below center
+ double result = -((center - raw) * double(-osd::input_device::ABSOLUTE_MIN) / (center - rawmin));
+ return int32_t(std::max(result, double(osd::input_device::ABSOLUTE_MIN)));
}
}
-#endif // INPUT_COMMON_H_
+#endif // MAME_OSD_INPUT_INPUT_COMMON_H
diff --git a/src/osd/modules/input/input_dinput.cpp b/src/osd/modules/input/input_dinput.cpp
index 0b5eb348dc0..6f539c2f7fc 100644
--- a/src/osd/modules/input/input_dinput.cpp
+++ b/src/osd/modules/input/input_dinput.cpp
@@ -1,281 +1,354 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles, Brad Hughes
+// copyright-holders:Aaron Giles, Brad Hughes, Vas Crabb
//============================================================
//
// input_dinput.cpp - Windows DirectInput support
//
//============================================================
+/*
+
+DirectInput joystick input is a bit of a mess. It gives eight axes
+called X, Y, Z, Rx, Ry, Rz, slider 0 and slider 1. The driver can
+assign arbitrary physical axes to these axes. Up to four hat switches
+are supported, giving a direction in hundredths of degrees. In theory,
+this supports dial-like controls with an arbitrary number of stops. In
+practice, it just makes dealing with 8-way hat switches more complicated
+and prevents contradictory inputs from being reported altogether.
+
+You may get a vague indication of the type of controller, and you can
+obtain usage information for HID controllers.
+
+The Windows HID driver supposedly uses the following mappings:
+
+0x01 Generic Desktop 0x30 X X
+0x01 Generic Desktop 0x31 Y Y
+0x01 Generic Desktop 0x32 Z Z
+0x01 Generic Desktop 0x33 Rx Rx
+0x01 Generic Desktop 0x34 Ry Ry
+0x01 Generic Desktop 0x35 Rz Rz
+0x01 Generic Desktop 0x36 Slider Slider
+0x01 Generic Desktop 0x37 Dial Slider
+0x01 Generic Desktop 0x39 Hat Switch POV Hat
+0x02 Simulation 0xBA Rudder Rz
+0x02 Simulation 0xBB Throttle Slider
+0x02 Simulation 0xC4 Accelerator Y
+0x02 Simulation 0xC5 Brake Rz
+0x02 Simulation 0xC8 Steering X
+
+Anything without an explicit mapping is treated as a button.
+
+The WinMM driver supposedly uses the following axis mappings:
+
+X X
+Y Y
+Z Slider
+R Rz
+U Slider
+V Slider
+
+The actual mapping used by various controllers doesn't match what you
+might expect from the HID mapping.
+
+Gamepads:
+
+Axis Logitech DS4 Xinput Switch
+X Left X Left X Left X Left X
+Y Left Y Left Y Left Y Left Y
+Z Right X Right X Triggers
+Rx Left trigger Right X Right X
+Ry Right trigger Right Y Right Y
+Rz Right Y Right Y
+
+Thrustmaster controllers:
+
+Axis HOTAS Side stick Throttle/Pedals Dual Throttles Triple Throttles Driving
+X Aileron Aileron Mini Stick X Left Throttle Right Brake Steering
+Y Elevator Elevator Mini stick Y Right Throttle Left Brake Brake
+Z Throttle Throttle Flaps Rudder
+Rx Right Brake Right Brake Right Brake Left Throttle
+Ry Left Brake Left Brake Left Brake Centre Throttle
+Rz Twist Rudder Rocker Air Brake Right Throttle Accelerator
+Slider 0 Rocker Throttle Antenna Rudder Clutch
+Slider 1 Rudder Rudder
+
+Logitech controllers:
+
+Axis Pro Wheels
+X Steering
+Y
+Z
+Rx Accelerator
+Ry Brake
+Rz Clutch
+Slider 0
+Slider 1
+
+MFG Crosswind pedals:
+
+X Left Brake
+Y Right Brake
+Rz Rudder
+
+*/
-#include "input_module.h"
#include "modules/osdmodule.h"
-#if defined(OSD_WINDOWS)
+#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
-// standard windows headers
-#include <windows.h>
-#include <initguid.h>
-#include <tchar.h>
-#include <wrl/client.h>
+#include "input_dinput.h"
-// undef WINNT for dinput.h to prevent duplicate definition
-#undef WINNT
-#include <dinput.h>
-#undef interface
+#include "interface/inputseq.h"
+#include "windows/winutil.h"
-#include <mutex>
+// emu
+#include "inpttype.h"
-// MAME headers
-#include "emu.h"
-#include "strconv.h"
+// lib/util
+#include "util/corestr.h"
-// MAMEOS headers
-#include "window.h"
-#include "winutil.h"
+#ifdef SDLMAME_WIN32
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_syswm.h>
+#endif
-#include "input_common.h"
-#include "input_windows.h"
-#include "input_dinput.h"
+#include <algorithm>
+#include <cmath>
+#include <iterator>
+#include <memory>
-using namespace Microsoft::WRL;
+// standard windows headers
+#include <initguid.h>
+#include <tchar.h>
-static int32_t dinput_joystick_pov_get_state(void *device_internal, void *item_internal);
-//============================================================
-// dinput_set_dword_property
-//============================================================
+namespace osd {
-#if DIRECTINPUT_VERSION >= 0x0800
-static HRESULT dinput_set_dword_property(ComPtr<IDirectInputDevice8> device, REFGUID property_guid, DWORD object, DWORD how, DWORD value)
-#else
-static HRESULT dinput_set_dword_property(ComPtr<IDirectInputDevice> device, REFGUID property_guid, DWORD object, DWORD how, DWORD value)
-#endif
+namespace {
+
+std::string guid_to_string(GUID const &guid)
{
- DIPROPDWORD dipdw;
+ // size of a GUID string with dashes plus NUL terminator
+ char guid_string[37];
+ snprintf(
+ guid_string, std::size(guid_string),
+ "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ guid.Data1, guid.Data2, guid.Data3,
+ guid.Data4[0], guid.Data4[1], guid.Data4[2],
+ guid.Data4[3], guid.Data4[4], guid.Data4[5],
+ guid.Data4[6], guid.Data4[7]);
+
+ return guid_string;
+}
- dipdw.diph.dwSize = sizeof(dipdw);
- dipdw.diph.dwHeaderSize = sizeof(dipdw.diph);
- dipdw.diph.dwObj = object;
- dipdw.diph.dwHow = how;
- dipdw.dwData = value;
- return device->SetProperty(property_guid, &dipdw.diph);
-}
//============================================================
-// dinput_device - base directinput device
+// dinput_keyboard_device - DirectInput keyboard device
//============================================================
-dinput_device::dinput_device(running_machine &machine, const char *name, const char *id, input_device_class deviceclass, input_module &module)
- : device_info(machine, name, id, deviceclass, module),
- dinput({nullptr})
+class dinput_keyboard_device : public dinput_device
{
-}
+public:
+ dinput_keyboard_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
+ DIDEVCAPS const &caps,
+ LPCDIDATAFORMAT format);
+
+ virtual void poll(bool relative_reset) override;
+ virtual void reset() override;
+ virtual void configure(input_device &device) override;
+
+private:
+ std::mutex m_device_lock;
+ keyboard_state m_keyboard;
+};
-dinput_device::~dinput_device()
+dinput_keyboard_device::dinput_keyboard_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
+ DIDEVCAPS const &caps,
+ LPCDIDATAFORMAT format) :
+ dinput_device(std::move(name), std::move(id), module, std::move(device), caps, format),
+ m_keyboard({ { 0 } })
{
- if (dinput.device != nullptr)
- dinput.device.Reset();
}
-HRESULT dinput_device::poll_dinput(LPVOID pState) const
+void dinput_keyboard_device::poll(bool relative_reset)
{
- HRESULT result;
-
- // first poll the device, then get the state
-#if DIRECTINPUT_VERSION >= 0x0800
- dinput.device->Poll();
-#else
- if (dinput.device2 != nullptr)
- dinput.device2->Poll();
-#endif
+ // poll the DirectInput immediate state
+ std::lock_guard<std::mutex> scope_lock(m_device_lock);
+ poll_dinput(&m_keyboard.state);
+}
- // GetDeviceState returns the immediate state
- result = dinput.device->GetDeviceState(dinput.format->dwDataSize, pState);
+void dinput_keyboard_device::reset()
+{
+ memset(&m_keyboard.state, 0, sizeof(m_keyboard.state));
+}
- // handle lost inputs here
- if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED)
+void dinput_keyboard_device::configure(input_device &device)
+{
+ // populate it
+ char defname[20];
+ for (unsigned keynum = 0; keynum < MAX_KEYS; keynum++)
{
- result = dinput.device->Acquire();
- if (result == DI_OK)
- result = dinput.device->GetDeviceState(dinput.format->dwDataSize, pState);
+ input_item_id itemid = keyboard_trans_table::instance().map_di_scancode_to_itemid(keynum);
+
+ // generate/fetch the name
+ snprintf(defname, std::size(defname), "Scan%03d", keynum);
+
+ // add the item to the device
+ device.add_item(
+ item_name(keynum, defname, nullptr),
+ strmakeupper(defname),
+ itemid,
+ generic_button_get_state<uint8_t>,
+ &m_keyboard.state[keynum]);
}
-
- return result;
}
+
//============================================================
-// dinput_keyboard_device - directinput keyboard device
+// dinput_mouse_device - DirectInput mouse device
//============================================================
-dinput_keyboard_device::dinput_keyboard_device(running_machine &machine, const char *name, const char *id, input_module &module)
- : dinput_device(machine, name, id, DEVICE_CLASS_KEYBOARD, module),
- keyboard({{0}})
+class dinput_mouse_device : public dinput_device
{
-}
+public:
+ dinput_mouse_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
+ DIDEVCAPS const &caps,
+ LPCDIDATAFORMAT format);
+
+ void poll(bool relative_reset) override;
+ void reset() override;
+ virtual void configure(input_device &device) override;
+
+private:
+ DIMOUSESTATE2 m_mouse;
+};
-// Polls the direct input immediate state
-void dinput_keyboard_device::poll()
+dinput_mouse_device::dinput_mouse_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
+ DIDEVCAPS const &caps,
+ LPCDIDATAFORMAT format) :
+ dinput_device(std::move(name), std::move(id), module, std::move(device), caps, format),
+ m_mouse({0})
{
- std::lock_guard<std::mutex> scope_lock(m_device_lock);
-
- // Poll the state
- dinput_device::poll_dinput(&keyboard.state);
+ // cap the number of axes and buttons based on the format
+ m_caps.dwAxes = std::min(m_caps.dwAxes, DWORD(3));
+ m_caps.dwButtons = std::min(m_caps.dwButtons, DWORD((m_format == &c_dfDIMouse) ? 4 : 8));
}
-void dinput_keyboard_device::reset()
-{
- memset(&keyboard.state, 0, sizeof(keyboard.state));
-}
-
-//============================================================
-// dinput_api_helper - DirectInput API helper
-//============================================================
-
-dinput_api_helper::dinput_api_helper(int version)
- : m_dinput(nullptr),
- m_dinput_version(version),
- m_dinput_create_prt(nullptr)
+void dinput_mouse_device::poll(bool relative_reset)
{
+ // poll
+ if (relative_reset && (poll_dinput(&m_mouse) == DI_OK))
+ {
+ // scale the axis data
+ m_mouse.lX *= input_device::RELATIVE_PER_PIXEL;
+ m_mouse.lY *= input_device::RELATIVE_PER_PIXEL;
+ m_mouse.lZ *= input_device::RELATIVE_PER_PIXEL;
+ }
}
-dinput_api_helper::~dinput_api_helper()
+void dinput_mouse_device::reset()
{
- m_dinput.Reset();
+ memset(&m_mouse, 0, sizeof(m_mouse));
}
-int dinput_api_helper::initialize()
+void dinput_mouse_device::configure(input_device &device)
{
- HRESULT result;
-
-#if DIRECTINPUT_VERSION >= 0x0800
- if (m_dinput_version >= 0x0800)
+ // populate the axes
+ for (int axisnum = 0; axisnum < m_caps.dwAxes; axisnum++)
{
- result = DirectInput8Create(GetModuleHandleUni(), m_dinput_version, IID_IDirectInput8, reinterpret_cast<void **>(m_dinput.GetAddressOf()), nullptr);
- if (result != DI_OK)
- {
- m_dinput_version = 0;
- return result;
- }
+ // add to the mouse device and optionally to the gun device as well
+ device.add_item(
+ item_name(offsetof(DIMOUSESTATE, lX) + axisnum * sizeof(LONG), default_axis_name[axisnum], nullptr),
+ std::string_view(),
+ input_item_id(ITEM_ID_XAXIS + axisnum),
+ generic_axis_get_state<LONG>,
+ &m_mouse.lX + axisnum);
}
- else
-#endif
- {
- m_dinput_dll = osd::dynamic_module::open({ "dinput.dll" });
- m_dinput_create_prt = m_dinput_dll->bind<dinput_create_fn>("DirectInputCreateW");
- if (m_dinput_create_prt == nullptr)
- {
- osd_printf_verbose("Legacy DirectInput library dinput.dll is not available\n");
- return ERROR_DLL_NOT_FOUND;
- }
+ // populate the buttons
+ for (int butnum = 0; butnum < m_caps.dwButtons; butnum++)
+ {
+ auto offset = reinterpret_cast<uintptr_t>(&static_cast<DIMOUSESTATE *>(nullptr)->rgbButtons[butnum]);
- // first attempt to initialize DirectInput at v7
- m_dinput_version = 0x0700;
- result = (*m_dinput_create_prt)(GetModuleHandleUni(), m_dinput_version, m_dinput.GetAddressOf(), nullptr);
- if (result != DI_OK)
- {
- // if that fails, try version 5
- m_dinput_version = 0x0500;
- result = (*m_dinput_create_prt)(GetModuleHandleUni(), m_dinput_version, m_dinput.GetAddressOf(), nullptr);
- if (result != DI_OK)
- {
- m_dinput_version = 0;
- return result;
- }
- }
+ // add to the mouse device
+ device.add_item(
+ item_name(offset, default_button_name(butnum), nullptr),
+ std::string_view(),
+ input_item_id(ITEM_ID_BUTTON1 + butnum),
+ generic_button_get_state<BYTE>,
+ &m_mouse.rgbButtons[butnum]);
}
-
- osd_printf_verbose("DirectInput: Using DirectInput %d\n", m_dinput_version >> 8);
- return 0;
-}
-
-
-HRESULT dinput_api_helper::enum_attached_devices(int devclass, device_enum_interface *enumerate_interface, void *state) const
-{
- device_enum_interface::dinput_callback_context ctx;
- ctx.self = enumerate_interface;
- ctx.state = state;
-
- return m_dinput->EnumDevices(devclass, device_enum_interface::enum_callback, &ctx, DIEDFL_ATTACHEDONLY);
}
//============================================================
-// dinput_module - base directinput module
+// dinput_module - base DirectInput module
//============================================================
-class dinput_module : public wininput_module, public device_enum_interface
+class dinput_module : public input_module_impl<dinput_device, osd_common_t>
{
-protected:
- std::unique_ptr<dinput_api_helper> m_dinput_helper;
-
public:
- dinput_module(const char* type, const char* name)
- : wininput_module(type, name),
- m_dinput_helper(nullptr)
+ dinput_module(const char* type, const char* name) :
+ input_module_impl<dinput_device, osd_common_t>(type, name),
+ m_dinput_helper(nullptr)
{
}
- int init_internal() override
+ virtual int init(osd_interface &osd, osd_options const &options) override
{
- m_dinput_helper = std::make_unique<dinput_api_helper>(DIRECTINPUT_VERSION);
- int result = m_dinput_helper->initialize();
- if (result != 0)
+ m_dinput_helper = std::make_unique<dinput_api_helper>();
+ int const result = m_dinput_helper->initialize();
+ if (result)
+ {
+ m_dinput_helper.reset();
return result;
+ }
- return 0;
+ return input_module_impl<dinput_device, osd_common_t>::init(osd, options);
}
- void exit() override
+ virtual void exit() override
{
- wininput_module::exit();
- m_dinput_helper.reset();
- }
+ input_module_impl<dinput_device, osd_common_t>::exit();
- void input_init(running_machine &machine) override
- {
- HRESULT result = m_dinput_helper->enum_attached_devices(dinput_devclass(), this, &machine);
- if (result != DI_OK)
- fatalerror("DirectInput: Unable to enumerate keyboards (result=%08X)\n", static_cast<uint32_t>(result));
+ m_dinput_helper.reset();
}
- static std::string device_item_name(dinput_device * devinfo, int offset, const char * defstring, const TCHAR * suffix)
+ virtual void input_init(running_machine &machine) override
{
- DIDEVICEOBJECTINSTANCE instance = { 0 };
- HRESULT result;
-
- // query the key name
- instance.dwSize = sizeof(instance);
- result = devinfo->dinput.device->GetObjectInfo(&instance, offset, DIPH_BYOFFSET);
+ input_module_impl<dinput_device, osd_common_t>::input_init(machine);
- // if we got an error and have no default string, just return nullptr
+ HRESULT const result = m_dinput_helper->enum_attached_devices(
+ dinput_devclass(),
+ [this] (LPCDIDEVICEINSTANCE instance) { return device_enum_callback(instance); });
if (result != DI_OK)
- {
- if (defstring == nullptr)
- return nullptr;
-
- // Return the default value
- return std::string(defstring);
- }
-
- // convert the name to utf8
- std::string namestring = osd::text::from_tstring(instance.tszName);
-
- // if no suffix, return as-is
- if (suffix == nullptr)
- return namestring;
-
- // convert the suffix to utf8
- std::string suffix_utf8 = osd::text::from_tstring(suffix);
-
- // Concat the name and suffix
- return namestring + " " + suffix_utf8;
+ fatalerror("DirectInput: Unable to enumerate devices (result=%08X)\n", uint32_t(result));
}
protected:
virtual int dinput_devclass() = 0;
+ virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance) = 0;
+
+ std::unique_ptr<dinput_api_helper> m_dinput_helper;
};
+
class keyboard_input_dinput : public dinput_module
{
public:
@@ -284,69 +357,30 @@ public:
{
}
- int dinput_devclass() override
+protected:
+ virtual int dinput_devclass() override
{
-#if DIRECTINPUT_VERSION >= 0x0800
return DI8DEVCLASS_KEYBOARD;
-#else
- return DIDEVTYPE_KEYBOARD;
-#endif
}
- BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
+ virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance) override
{
- running_machine &machine = *static_cast<running_machine *>(ref);
- dinput_keyboard_device *devinfo;
- int keynum;
-
// allocate and link in a new device
- devinfo = m_dinput_helper->create_device<dinput_keyboard_device>(machine, *this, instance, &c_dfDIKeyboard, nullptr, dinput_cooperative_level::FOREGROUND);
- if (devinfo == nullptr)
- goto exit;
-
- // populate it
- for (keynum = 0; keynum < MAX_KEYS; keynum++)
- {
- input_item_id itemid = keyboard_trans_table::instance().map_di_scancode_to_itemid(keynum);
- char defname[20];
- std::string name;
-
- // generate/fetch the name
- snprintf(defname, ARRAY_LENGTH(defname), "Scan%03d", keynum);
- name = device_item_name(devinfo, keynum, defname, nullptr);
+ auto devinfo = m_dinput_helper->create_device<dinput_keyboard_device>(
+ *this,
+ instance,
+ &c_dfDIKeyboard,
+ nullptr,
+ background_input() ? dinput_cooperative_level::BACKGROUND : dinput_cooperative_level::FOREGROUND,
+ [] (auto...) { return true; });
+ if (devinfo)
+ add_device(DEVICE_CLASS_KEYBOARD, std::move(devinfo));
- // add the item to the device
- devinfo->device()->add_item(name.c_str(), itemid, generic_button_get_state<std::uint8_t>, &devinfo->keyboard.state[keynum]);
- }
-
- exit:
return DIENUM_CONTINUE;
}
};
-dinput_mouse_device::dinput_mouse_device(running_machine &machine, const char *name, const char *id, input_module &module)
- : dinput_device(machine, name, id, DEVICE_CLASS_MOUSE, module),
- mouse({0})
-{
-}
-
-void dinput_mouse_device::poll()
-{
- // poll
- dinput_device::poll_dinput(&mouse);
-
- // scale the axis data
- mouse.lX *= INPUT_RELATIVE_PER_PIXEL;
- mouse.lY *= INPUT_RELATIVE_PER_PIXEL;
- mouse.lZ *= INPUT_RELATIVE_PER_PIXEL;
-}
-
-void dinput_mouse_device::reset()
-{
- memset(&mouse, 0, sizeof(mouse));
-}
-
class mouse_input_dinput : public dinput_module
{
public:
@@ -355,284 +389,954 @@ public:
{
}
- int dinput_devclass() override
+protected:
+ virtual int dinput_devclass() override
{
-#if DIRECTINPUT_VERSION >= 0x0800
return DI8DEVCLASS_POINTER;
-#else
- return DIDEVTYPE_MOUSE;
-#endif
}
- BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
+ virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance) override
{
- dinput_mouse_device *devinfo = nullptr;
- running_machine &machine = *static_cast<running_machine *>(ref);
- int axisnum, butnum;
- HRESULT result;
-
// allocate and link in a new device
- devinfo = m_dinput_helper->create_device<dinput_mouse_device>(machine, *this, instance, &c_dfDIMouse2, &c_dfDIMouse, dinput_cooperative_level::FOREGROUND);
- if (devinfo == nullptr)
- goto exit;
+ auto devinfo = m_dinput_helper->create_device<dinput_mouse_device>(
+ *this,
+ instance,
+ &c_dfDIMouse2,
+ &c_dfDIMouse,
+ background_input() ? dinput_cooperative_level::BACKGROUND : dinput_cooperative_level::FOREGROUND,
+ [] (auto const &device, auto const &format) -> bool
+ {
+ // set relative mode
+ HRESULT const result = dinput_api_helper::set_dword_property(
+ device,
+ DIPROP_AXISMODE,
+ 0,
+ DIPH_DEVICE,
+ DIPROPAXISMODE_REL);
+ if ((result != DI_OK) && (result != DI_PROPNOEFFECT))
+ {
+ osd_printf_error("DirectInput: Unable to set relative mode for mouse.\n");
+ return false;
+ }
+ return true;
+ });
+ if (devinfo)
+ add_device(DEVICE_CLASS_MOUSE, std::move(devinfo));
- // set relative mode on the mouse device
- result = dinput_set_dword_property(devinfo->dinput.device, DIPROP_AXISMODE, 0, DIPH_DEVICE, DIPROPAXISMODE_REL);
- if (result != DI_OK && result != DI_PROPNOEFFECT)
- {
- osd_printf_error("DirectInput: Unable to set relative mode for mouse %u (%s)\n", static_cast<unsigned int>(devicelist()->size()), devinfo->name());
- goto error;
- }
+ return DIENUM_CONTINUE;
+ }
+};
- // cap the number of axes and buttons based on the format
- devinfo->dinput.caps.dwAxes = std::min(devinfo->dinput.caps.dwAxes, DWORD(3));
- devinfo->dinput.caps.dwButtons = std::min(devinfo->dinput.caps.dwButtons, DWORD((devinfo->dinput.format == &c_dfDIMouse) ? 4 : 8));
- // populate the axes
- for (axisnum = 0; axisnum < devinfo->dinput.caps.dwAxes; axisnum++)
- {
- // add to the mouse device and optionally to the gun device as well
- std::string name = device_item_name(devinfo, offsetof(DIMOUSESTATE, lX) + axisnum * sizeof(LONG), default_axis_name[axisnum], nullptr);
- devinfo->device()->add_item(
- name.c_str(),
- static_cast<input_item_id>(ITEM_ID_XAXIS + axisnum),
- generic_axis_get_state<LONG>,
- &devinfo->mouse.lX + axisnum);
- }
+class joystick_input_dinput : public dinput_module
+{
+public:
+ joystick_input_dinput() :
+ dinput_module(OSD_JOYSTICKINPUT_PROVIDER, "dinput")
+ {
+ }
- // populate the buttons
- for (butnum = 0; butnum < devinfo->dinput.caps.dwButtons; butnum++)
- {
- uintptr_t offset = reinterpret_cast<uintptr_t>(&static_cast<DIMOUSESTATE *>(nullptr)->rgbButtons[butnum]);
+protected:
+ virtual int dinput_devclass() override
+ {
+ return DI8DEVCLASS_GAMECTRL;
+ }
- // add to the mouse device
- std::string name = device_item_name(devinfo, offset, default_button_name(butnum), nullptr);
- devinfo->device()->add_item(
- name.c_str(),
- static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum),
- generic_button_get_state<BYTE>,
- &devinfo->mouse.rgbButtons[butnum]);
- }
+ virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance) override
+ {
+ // allocate and link in a new device
+ auto devinfo = m_dinput_helper->create_device<dinput_joystick_device>(
+ *this,
+ instance,
+ &c_dfDIJoystick,
+ nullptr,
+ background_input() ? dinput_cooperative_level::BACKGROUND : dinput_cooperative_level::FOREGROUND,
+ [] (auto const &device, auto const &format) -> bool
+ {
+ // set absolute mode
+ HRESULT const result = dinput_api_helper::set_dword_property(
+ device,
+ DIPROP_AXISMODE,
+ 0,
+ DIPH_DEVICE,
+ DIPROPAXISMODE_ABS);
+ if ((result != DI_OK) && (result != DI_PROPNOEFFECT))
+ {
+ osd_printf_error("DirectInput: Unable to set absolute mode for joystick.\n");
+ return false;
+ }
+ return true;
+ });
+ if (devinfo)
+ add_device(DEVICE_CLASS_JOYSTICK, std::move(devinfo));
- exit:
return DIENUM_CONTINUE;
-
- error:
- if (devinfo != nullptr)
- devicelist()->free_device(devinfo);
- goto exit;
}
};
-dinput_joystick_device::dinput_joystick_device(running_machine &machine, const char *name, const char *id, input_module &module)
- : dinput_device(machine, name, id, DEVICE_CLASS_JOYSTICK, module),
- joystick({{0}})
+} // anonymous namespace
+
+
+//============================================================
+// dinput_device - base DirectInput device
+//============================================================
+
+dinput_device::dinput_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
+ DIDEVCAPS const &caps,
+ LPCDIDATAFORMAT format) :
+ device_info(std::move(name), std::move(id), module),
+ m_device(std::move(device)),
+ m_caps(caps),
+ m_format(format)
{
}
-void dinput_joystick_device::reset()
+HRESULT dinput_device::poll_dinput(LPVOID pState) const
+{
+ HRESULT result;
+
+ // first poll the device, then get the state
+ result = m_device->Poll();
+
+ // handle lost inputs here
+ if ((result == DIERR_INPUTLOST) || (result == DIERR_NOTACQUIRED))
+ {
+ result = m_device->Acquire();
+ if ((result == DI_OK) || (result == S_FALSE))
+ result = m_device->Poll();
+ }
+
+ // GetDeviceState returns the immediate state
+ if ((result == DI_OK) || (result == DI_NOEFFECT))
+ result = m_device->GetDeviceState(m_format->dwDataSize, pState);
+
+ return result;
+}
+
+std::string dinput_device::item_name(int offset, std::string_view defstring, const char *suffix) const
{
- memset(&joystick.state, 0, sizeof(joystick.state));
+ // query the key name
+ DIDEVICEOBJECTINSTANCE instance = { 0 };
+ instance.dwSize = sizeof(instance);
+ HRESULT const result = m_device->GetObjectInfo(&instance, offset, DIPH_BYOFFSET);
+
+ // use the default value if it failed
+ std::string name;
+ if (result != DI_OK)
+ name = defstring;
+ else
+ name = text::from_tstring(instance.tszName);
+
+ // if no suffix, return as-is
+ if (suffix)
+ name.append(" ").append(suffix);
+
+ return name;
}
-void dinput_joystick_device::poll()
+
+//============================================================
+// dinput_joystick_device - directinput joystick device
+//============================================================
+
+dinput_joystick_device::dinput_joystick_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
+ DIDEVCAPS const &caps,
+ LPCDIDATAFORMAT format) :
+ dinput_device(std::move(name), std::move(id), module, std::move(device), caps, format),
+ m_joystick({ { 0 } })
{
- int axisnum;
+ // cap the number of axes, POVs, and buttons based on the format
+ m_caps.dwAxes = std::min(m_caps.dwAxes, DWORD(8));
+ m_caps.dwPOVs = std::min(m_caps.dwPOVs, DWORD(4));
+ m_caps.dwButtons = std::min(m_caps.dwButtons, DWORD(128));
+}
- // poll the device first
- if (dinput_device::poll_dinput(&joystick.state) != ERROR_SUCCESS)
- return;
+void dinput_joystick_device::reset()
+{
+ memset(&m_joystick.state, 0, sizeof(m_joystick.state));
+ std::fill(std::begin(m_joystick.state.rgdwPOV), std::end(m_joystick.state.rgdwPOV), 0xffff);
+}
- // normalize axis values
- for (axisnum = 0; axisnum < 8; axisnum++)
+void dinput_joystick_device::poll(bool relative_reset)
+{
+ // poll the device first
+ if (dinput_device::poll_dinput(&m_joystick.state) == DI_OK)
{
- LONG *axis = (&joystick.state.lX) + axisnum;
- *axis = normalize_absolute_axis(*axis, joystick.rangemin[axisnum], joystick.rangemax[axisnum]);
+ // normalize axis values
+ for (int axisnum = 0; axisnum < 8; axisnum++)
+ {
+ auto const range = m_joystick.rangemax[axisnum] - m_joystick.rangemin[axisnum];
+ if (range)
+ {
+ // assumes output range is symmetrical
+ LONG *const axis = &m_joystick.state.lX + axisnum;
+ double const offset = *axis - m_joystick.rangemin[axisnum];
+ double const scaled = offset * double(input_device::ABSOLUTE_MAX - input_device::ABSOLUTE_MIN) / double(range);
+ *axis = lround(std::clamp<double>(scaled + input_device::ABSOLUTE_MIN, input_device::ABSOLUTE_MIN, input_device::ABSOLUTE_MAX));
+ }
+ }
}
}
-int dinput_joystick_device::configure()
+void dinput_joystick_device::configure(input_device &device)
{
+ input_device::assignment_vector assignments;
HRESULT result;
- uint32_t axisnum, axiscount;
-
- auto devicelist = static_cast<input_module_base&>(module()).devicelist();
- // temporary approximation of index
- int devindex = devicelist->size();
-
- // set absolute mode
- result = dinput_set_dword_property(dinput.device, DIPROP_AXISMODE, 0, DIPH_DEVICE, DIPROPAXISMODE_ABS);
- if (result != DI_OK && result != DI_PROPNOEFFECT)
- osd_printf_warning("DirectInput: Unable to set absolute mode for joystick %d (%s)\n", devindex, name());
+ // get device information - it gives clues about axis usage
+ DIDEVICEINSTANCE info;
+ info.dwSize = sizeof(info);
+ result = m_device->GetDeviceInfo(&info);
+ bool hid = false;
+ uint8_t type = DI8DEVTYPE_DEVICE;
+ uint8_t subtype = 0;
+ if (result == DI_OK)
+ {
+ hid = (info.dwDevType & DIDEVTYPE_HID) != 0;
+ type = info.dwDevType & 0x00ff;
+ subtype = (info.dwDevType >> 8) & 0x00ff;
+ osd_printf_verbose(
+ "DirectInput: Device type=0x%02X subtype=0x%02X HID=%u\n",
+ type,
+ subtype,
+ hid ? "yes" : "no");
+ }
// turn off deadzone; we do our own calculations
- result = dinput_set_dword_property(dinput.device, DIPROP_DEADZONE, 0, DIPH_DEVICE, 0);
- if (result != DI_OK && result != DI_PROPNOEFFECT)
- osd_printf_warning("DirectInput: Unable to reset deadzone for joystick %d (%s)\n", devindex, name());
+ result = dinput_api_helper::set_dword_property(m_device, DIPROP_DEADZONE, 0, DIPH_DEVICE, 0);
+ if ((result != DI_OK) && (result != DI_PROPNOEFFECT))
+ osd_printf_warning("DirectInput: Unable to reset deadzone for joystick %s.\n", name());
// turn off saturation; we do our own calculations
- result = dinput_set_dword_property(dinput.device, DIPROP_SATURATION, 0, DIPH_DEVICE, 10000);
- if (result != DI_OK && result != DI_PROPNOEFFECT)
- osd_printf_warning("DirectInput: Unable to reset saturation for joystick %d (%s)\n", devindex, name());
-
- // cap the number of axes, POVs, and buttons based on the format
- dinput.caps.dwAxes = std::min(dinput.caps.dwAxes, DWORD(8));
- dinput.caps.dwPOVs = std::min(dinput.caps.dwPOVs, DWORD(4));
- dinput.caps.dwButtons = std::min(dinput.caps.dwButtons, DWORD(128));
+ result = dinput_api_helper::set_dword_property(m_device, DIPROP_SATURATION, 0, DIPH_DEVICE, 10000);
+ if ((result != DI_OK) && (result != DI_PROPNOEFFECT))
+ osd_printf_warning("DirectInput: Unable to reset saturation for joystick %s.\n", name());
// populate the axes
- for (axisnum = axiscount = 0; axiscount < dinput.caps.dwAxes && axisnum < 8; axisnum++)
+ input_item_id axisitems[8];
+ std::fill(std::begin(axisitems), std::end(axisitems), ITEM_ID_INVALID);
+ for (uint32_t axisnum = 0, axiscount = 0; (axiscount < m_caps.dwAxes) && (axisnum < 8); axisnum++)
{
- DIPROPRANGE dipr;
- std::string name;
-
// fetch the range of this axis
+ DIPROPRANGE dipr;
dipr.diph.dwSize = sizeof(dipr);
dipr.diph.dwHeaderSize = sizeof(dipr.diph);
dipr.diph.dwObj = offsetof(DIJOYSTATE2, lX) + axisnum * sizeof(LONG);
dipr.diph.dwHow = DIPH_BYOFFSET;
- result = dinput.device->GetProperty(DIPROP_RANGE, &dipr.diph);
+ result = m_device->GetProperty(DIPROP_RANGE, &dipr.diph);
if (result != DI_OK)
+ {
+ // this is normal when axes are skipped, e.g. X/Y/Z present, rX/rY absent, rZ present
+ osd_printf_verbose("DirectInput: Unable to get properties for joystick %s axis %u.\n", name(), axisnum);
continue;
+ }
- joystick.rangemin[axisnum] = dipr.lMin;
- joystick.rangemax[axisnum] = dipr.lMax;
+ m_joystick.rangemin[axisnum] = dipr.lMin;
+ m_joystick.rangemax[axisnum] = dipr.lMax;
// populate the item description as well
- name = dinput_module::device_item_name(this, offsetof(DIJOYSTATE2, lX) + axisnum * sizeof(LONG), default_axis_name[axisnum], nullptr);
- device()->add_item(
- name.c_str(),
- static_cast<input_item_id>(ITEM_ID_XAXIS + axisnum),
- generic_axis_get_state<LONG>,
- &joystick.state.lX + axisnum);
+ axisitems[axisnum] = device.add_item(
+ item_name(offsetof(DIJOYSTATE2, lX) + axisnum * sizeof(LONG), default_axis_name[axisnum], nullptr),
+ std::string_view(),
+ input_item_id(ITEM_ID_XAXIS + axisnum),
+ generic_axis_get_state<LONG>,
+ &m_joystick.state.lX + axisnum);
axiscount++;
}
- // populate the POVs
- for (uint32_t povnum = 0; povnum < dinput.caps.dwPOVs; povnum++)
+ // take a guess at which axes might be pedals depending on type and remap onto negative half of range
+ input_item_id pedalitems[3] = { ITEM_ID_INVALID, ITEM_ID_INVALID, ITEM_ID_INVALID };
+ if (DI8DEVTYPE_FLIGHT == type)
{
- std::string name;
+ // Rx/Ry are often used for brakes
+ bool const rxpedal = (ITEM_ID_INVALID != axisitems[3]) && !m_joystick.rangemin[3] && (0 < m_joystick.rangemax[3]);
+ bool const rypedal = (ITEM_ID_INVALID != axisitems[4]) && !m_joystick.rangemin[4] && (0 < m_joystick.rangemax[4]);
+ if (rxpedal && rypedal)
+ {
+ pedalitems[0] = axisitems[3];
+ m_joystick.rangemin[3] = m_joystick.rangemax[3];
+ m_joystick.rangemax[3] = -m_joystick.rangemax[3];
+ pedalitems[1] = axisitems[4];
+ m_joystick.rangemin[4] = m_joystick.rangemax[4];
+ m_joystick.rangemax[4] = -m_joystick.rangemax[4];
+ }
+ }
+ else if (DI8DEVTYPE_DRIVING == type)
+ {
+ bool const ypedal = (ITEM_ID_INVALID != axisitems[1]) && !m_joystick.rangemin[1] && (0 < m_joystick.rangemax[1]);
+ bool const rxpedal = (ITEM_ID_INVALID != axisitems[3]) && !m_joystick.rangemin[3] && (0 < m_joystick.rangemax[3]);
+ bool const rypedal = (ITEM_ID_INVALID != axisitems[4]) && !m_joystick.rangemin[4] && (0 < m_joystick.rangemax[4]);
+ bool const rzpedal = (ITEM_ID_INVALID != axisitems[5]) && !m_joystick.rangemin[5] && (0 < m_joystick.rangemax[5]);
+ bool const s0pedal = (ITEM_ID_INVALID != axisitems[6]) && !m_joystick.rangemin[6] && (0 < m_joystick.rangemax[6]);
+ if (DI8DEVTYPEDRIVING_DUALPEDALS == subtype)
+ {
+ // dual pedals are usually Y and Rz
+ if (ypedal && rzpedal)
+ {
+ pedalitems[0] = axisitems[1];
+ m_joystick.rangemin[1] = m_joystick.rangemax[1];
+ m_joystick.rangemax[1] = -m_joystick.rangemax[1];
+
+ pedalitems[1] = axisitems[5];
+ m_joystick.rangemin[5] = m_joystick.rangemax[5];
+ m_joystick.rangemax[5] = -m_joystick.rangemax[5];
+ }
+ }
+ else if (DI8DEVTYPEDRIVING_THREEPEDALS == subtype)
+ {
+ // triple pedals may be Y, Rz and slider 0, or Rx, Ry and Rz
+ if (ypedal && rzpedal && s0pedal)
+ {
+ pedalitems[0] = axisitems[1];
+ m_joystick.rangemin[1] = m_joystick.rangemax[1];
+ m_joystick.rangemax[1] = -m_joystick.rangemax[1];
+
+ pedalitems[1] = axisitems[5];
+ m_joystick.rangemin[5] = m_joystick.rangemax[5];
+ m_joystick.rangemax[5] = -m_joystick.rangemax[5];
+
+ pedalitems[2] = axisitems[6];
+ m_joystick.rangemin[6] = m_joystick.rangemax[6];
+ m_joystick.rangemax[6] = -m_joystick.rangemax[6];
+ }
+ else if (rxpedal && rypedal && rzpedal)
+ {
+ pedalitems[0] = axisitems[3];
+ m_joystick.rangemin[3] = m_joystick.rangemax[3];
+ m_joystick.rangemax[3] = -m_joystick.rangemax[3];
+
+ pedalitems[1] = axisitems[4];
+ m_joystick.rangemin[4] = m_joystick.rangemax[4];
+ m_joystick.rangemax[4] = -m_joystick.rangemax[4];
+
+ pedalitems[2] = axisitems[5];
+ m_joystick.rangemin[5] = m_joystick.rangemax[5];
+ m_joystick.rangemax[5] = -m_joystick.rangemax[5];
+ }
+ }
+ }
+
+ // populate the POV hats
+ input_item_id povitems[4][4];
+ for (auto &pov : povitems)
+ std::fill(std::begin(pov), std::end(pov), ITEM_ID_INVALID);
+ for (uint32_t povnum = 0; povnum < m_caps.dwPOVs; povnum++)
+ {
// left
- name = dinput_module::device_item_name(this, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("L"));
- device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, reinterpret_cast<void *>(static_cast<uintptr_t>(povnum * 4 + POVDIR_LEFT)));
+ povitems[povnum][0] = device.add_item(
+ item_name(offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), "Left"),
+ std::string_view(),
+ input_item_id((povnum * 4) + ITEM_ID_HAT1LEFT),
+ &dinput_joystick_device::pov_get_state,
+ reinterpret_cast<void *>(uintptr_t(povnum * 4 + POVDIR_LEFT)));
// right
- name = dinput_module::device_item_name(this, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("R"));
- device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, reinterpret_cast<void *>(static_cast<uintptr_t>(povnum * 4 + POVDIR_RIGHT)));
+ povitems[povnum][1] = device.add_item(
+ item_name(offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), "Right"),
+ std::string_view(),
+ input_item_id((povnum * 4) + ITEM_ID_HAT1RIGHT),
+ &dinput_joystick_device::pov_get_state,
+ reinterpret_cast<void *>(uintptr_t(povnum * 4 + POVDIR_RIGHT)));
// up
- name = dinput_module::device_item_name(this, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("U"));
- device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, reinterpret_cast<void *>(static_cast<uintptr_t>(povnum * 4 + POVDIR_UP)));
+ povitems[povnum][2] = device.add_item(
+ item_name(offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), "Up"),
+ std::string_view(),
+ input_item_id((povnum * 4) + ITEM_ID_HAT1UP),
+ &dinput_joystick_device::pov_get_state,
+ reinterpret_cast<void *>(uintptr_t(povnum * 4 + POVDIR_UP)));
// down
- name = dinput_module::device_item_name(this, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("D"));
- device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, reinterpret_cast<void *>(static_cast<uintptr_t>(povnum * 4 + POVDIR_DOWN)));
+ povitems[povnum][3] = device.add_item(
+ item_name(offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), "Down"),
+ std::string_view(),
+ input_item_id((povnum * 4) + ITEM_ID_HAT1DOWN),
+ &dinput_joystick_device::pov_get_state,
+ reinterpret_cast<void *>(uintptr_t(povnum * 4 + POVDIR_DOWN)));
}
// populate the buttons
- for (uint32_t butnum = 0; butnum < dinput.caps.dwButtons; butnum++)
+ for (uint32_t butnum = 0; butnum < m_caps.dwButtons; butnum++)
{
- uintptr_t offset = reinterpret_cast<uintptr_t>(&static_cast<DIJOYSTATE2 *>(nullptr)->rgbButtons[butnum]);
- std::string name = dinput_module::device_item_name(this, offset, default_button_name(butnum), nullptr);
+ auto offset = reinterpret_cast<uintptr_t>(&static_cast<DIJOYSTATE2 *>(nullptr)->rgbButtons[butnum]);
input_item_id itemid;
-
if (butnum < INPUT_MAX_BUTTONS)
- itemid = static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum);
+ itemid = input_item_id(ITEM_ID_BUTTON1 + butnum);
else if (butnum < INPUT_MAX_BUTTONS + INPUT_MAX_ADD_SWITCH)
- itemid = static_cast<input_item_id>(ITEM_ID_ADD_SWITCH1 - INPUT_MAX_BUTTONS + butnum);
+ itemid = input_item_id(ITEM_ID_ADD_SWITCH1 - INPUT_MAX_BUTTONS + butnum);
else
itemid = ITEM_ID_OTHER_SWITCH;
- device()->add_item(name.c_str(), itemid, generic_button_get_state<BYTE>, &joystick.state.rgbButtons[butnum]);
- }
+ input_item_id const actual = device.add_item(
+ item_name(offset, default_button_name(butnum), nullptr),
+ std::string_view(),
+ itemid,
+ generic_button_get_state<BYTE>,
+ &m_joystick.state.rgbButtons[butnum]);
- return 0;
-}
+ // there are sixteen action button types
+ if (butnum < 16)
+ {
+ input_seq const seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, actual));
+ assignments.emplace_back(ioport_type(IPT_BUTTON1 + butnum), SEQ_TYPE_STANDARD, seq);
-class joystick_input_dinput : public dinput_module
-{
-public:
- joystick_input_dinput() :
- dinput_module(OSD_JOYSTICKINPUT_PROVIDER, "dinput")
- {
+ // assign the first few buttons to UI actions and pedals
+ // TODO: don't map pedals for driving controls that have them present
+ switch (butnum)
+ {
+ case 0:
+ assignments.emplace_back(IPT_PEDAL, SEQ_TYPE_INCREMENT, seq);
+ assignments.emplace_back(IPT_UI_SELECT, SEQ_TYPE_STANDARD, seq);
+ break;
+ case 1:
+ assignments.emplace_back(IPT_PEDAL2, SEQ_TYPE_INCREMENT, seq);
+ assignments.emplace_back((3 > m_caps.dwButtons) ? IPT_UI_CLEAR : IPT_UI_BACK, SEQ_TYPE_STANDARD, seq);
+ break;
+ case 2:
+ assignments.emplace_back(IPT_PEDAL3, SEQ_TYPE_INCREMENT, seq);
+ assignments.emplace_back(IPT_UI_CLEAR, SEQ_TYPE_STANDARD, seq);
+ break;
+ case 3:
+ assignments.emplace_back(IPT_UI_HELP, SEQ_TYPE_STANDARD, seq);
+ break;
+ }
+ }
}
- int dinput_devclass() override
+ // add default assignments depending on type
+ if (DI8DEVTYPE_FLIGHT == type)
{
-#if DIRECTINPUT_VERSION >= 0x0800
- return DI8DEVCLASS_GAMECTRL;
-#else
- return DIDEVTYPE_JOYSTICK;
-#endif
- }
+ if (((ITEM_ID_INVALID == axisitems[0]) || (ITEM_ID_INVALID == axisitems[1])) && (1 <= m_caps.dwPOVs))
+ {
+ // X or Y missing, fall back to using POV hat for navigation
+ add_directional_assignments(
+ assignments,
+ axisitems[0],
+ axisitems[1],
+ povitems[0][0],
+ povitems[0][1],
+ povitems[0][2],
+ povitems[0][3]);
+
+ // try using throttle for zoom/focus
+ if (ITEM_ID_INVALID != axisitems[2])
+ {
+ input_seq const negseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, axisitems[2]));
+ input_seq const posseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, axisitems[2]));
+ if (ITEM_ID_INVALID != axisitems[5])
+ {
+ assignments.emplace_back(IPT_UI_ZOOM_IN, SEQ_TYPE_STANDARD, posseq);
+ assignments.emplace_back(IPT_UI_ZOOM_OUT, SEQ_TYPE_STANDARD, negseq);
+ assignments.emplace_back(IPT_UI_FOCUS_PREV, SEQ_TYPE_STANDARD, negseq);
+ assignments.emplace_back(IPT_UI_FOCUS_NEXT, SEQ_TYPE_STANDARD, posseq);
+ }
+ else
+ {
+ assignments.emplace_back(IPT_UI_PREV_GROUP, SEQ_TYPE_STANDARD, posseq);
+ assignments.emplace_back(IPT_UI_NEXT_GROUP, SEQ_TYPE_STANDARD, negseq);
+ }
+ }
- BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
- {
- dinput_cooperative_level cooperative_level = dinput_cooperative_level::FOREGROUND;
- running_machine &machine = *static_cast<running_machine *>(ref);
- dinput_joystick_device *devinfo;
- int result = 0;
+ // try using twist/rudder for next/previous group
+ if (ITEM_ID_INVALID != axisitems[5])
+ {
+ input_seq const negseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, axisitems[5]));
+ input_seq const posseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, axisitems[5]));
+ assignments.emplace_back(IPT_UI_PREV_GROUP, SEQ_TYPE_STANDARD, negseq);
+ assignments.emplace_back(IPT_UI_NEXT_GROUP, SEQ_TYPE_STANDARD, posseq);
+ }
+ }
+ else
+ {
+ // only use stick for primary navigation/movement
+ add_directional_assignments(
+ assignments,
+ axisitems[0],
+ axisitems[1],
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID);
+
+ // try using hat for secondary navigation functions
+ if (1 <= m_caps.dwPOVs)
+ {
+ input_seq const leftseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, povitems[0][0]));
+ input_seq const rightseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, povitems[0][1]));
+ input_seq const upseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, povitems[0][2]));
+ input_seq const downseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, povitems[0][3]));
+ if ((ITEM_ID_INVALID != axisitems[2]) || (ITEM_ID_INVALID != axisitems[5]))
+ {
+ assignments.emplace_back(IPT_UI_PREV_GROUP, SEQ_TYPE_STANDARD, leftseq);
+ assignments.emplace_back(IPT_UI_NEXT_GROUP, SEQ_TYPE_STANDARD, rightseq);
+ assignments.emplace_back(IPT_UI_PAGE_UP, SEQ_TYPE_STANDARD, upseq);
+ assignments.emplace_back(IPT_UI_PAGE_DOWN, SEQ_TYPE_STANDARD, downseq);
+ }
+ else
+ {
+ assignments.emplace_back(IPT_UI_FOCUS_PREV, SEQ_TYPE_STANDARD, leftseq);
+ assignments.emplace_back(IPT_UI_FOCUS_NEXT, SEQ_TYPE_STANDARD, rightseq);
+ assignments.emplace_back(IPT_UI_ZOOM_OUT, SEQ_TYPE_STANDARD, leftseq);
+ assignments.emplace_back(IPT_UI_ZOOM_IN, SEQ_TYPE_STANDARD, rightseq);
+ assignments.emplace_back(IPT_UI_PREV_GROUP, SEQ_TYPE_STANDARD, upseq);
+ assignments.emplace_back(IPT_UI_NEXT_GROUP, SEQ_TYPE_STANDARD, downseq);
+ }
+ }
- if (!osd_common_t::s_window_list.empty() && osd_common_t::s_window_list.front()->win_has_menu())
- cooperative_level = dinput_cooperative_level::BACKGROUND;
+ // try using throttle for zoom
+ if (ITEM_ID_INVALID != axisitems[2])
+ {
+ input_seq const negseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, axisitems[2]));
+ input_seq const posseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, axisitems[2]));
+ if ((1 <= m_caps.dwPOVs) || (ITEM_ID_INVALID != axisitems[5]))
+ {
+ assignments.emplace_back(IPT_UI_ZOOM_IN, SEQ_TYPE_STANDARD, posseq);
+ assignments.emplace_back(IPT_UI_ZOOM_OUT, SEQ_TYPE_STANDARD, negseq);
+ if ((1 > m_caps.dwPOVs) || (ITEM_ID_INVALID == axisitems[5]))
+ {
+ assignments.emplace_back(IPT_UI_FOCUS_PREV, SEQ_TYPE_STANDARD, negseq);
+ assignments.emplace_back(IPT_UI_FOCUS_NEXT, SEQ_TYPE_STANDARD, posseq);
+ }
+ }
+ else
+ {
+ assignments.emplace_back(IPT_UI_PREV_GROUP, SEQ_TYPE_STANDARD, posseq);
+ assignments.emplace_back(IPT_UI_NEXT_GROUP, SEQ_TYPE_STANDARD, negseq);
+ }
+ }
- // allocate and link in a new device
- devinfo = m_dinput_helper->create_device<dinput_joystick_device>(machine, *this, instance, &c_dfDIJoystick, nullptr, cooperative_level);
- if (devinfo == nullptr)
- goto exit;
+ // try using twist/rudder for focus next/previous
+ if (ITEM_ID_INVALID != axisitems[5])
+ {
+ input_seq const negseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, axisitems[5]));
+ input_seq const posseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, axisitems[5]));
+ if (1 <= m_caps.dwPOVs)
+ {
+ assignments.emplace_back(IPT_UI_FOCUS_PREV, SEQ_TYPE_STANDARD, negseq);
+ assignments.emplace_back(IPT_UI_FOCUS_NEXT, SEQ_TYPE_STANDARD, posseq);
+ if (ITEM_ID_INVALID == axisitems[2])
+ {
+ assignments.emplace_back(IPT_UI_ZOOM_IN, SEQ_TYPE_STANDARD, posseq);
+ assignments.emplace_back(IPT_UI_ZOOM_OUT, SEQ_TYPE_STANDARD, negseq);
+ }
+ }
+ else
+ {
+ assignments.emplace_back(IPT_UI_PREV_GROUP, SEQ_TYPE_STANDARD, negseq);
+ assignments.emplace_back(IPT_UI_NEXT_GROUP, SEQ_TYPE_STANDARD, posseq);
+ }
+ }
+ }
- result = devinfo->configure();
- if (result != 0)
+ // Z or slider 0 is usually the throttle - use one of them for joystick Z
+ add_assignment(
+ assignments,
+ IPT_AD_STICK_Z,
+ SEQ_TYPE_STANDARD,
+ ITEM_CLASS_ABSOLUTE,
+ ITEM_MODIFIER_NONE,
+ { axisitems[2], axisitems[6] });
+
+ // use Z for the first two pedals if present
+ if (ITEM_ID_INVALID != axisitems[2])
{
- osd_printf_error("Failed to configure DI Joystick device. Error 0x%x\n", static_cast<unsigned int>(result));
+ // TODO: use Rx/Ry as well if they appear to be brakes
+ input_seq const pedal1seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, axisitems[2]));
+ input_seq const pedal2seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, axisitems[2]));
+ assignments.emplace_back(IPT_PEDAL, SEQ_TYPE_STANDARD, pedal1seq);
+ assignments.emplace_back(IPT_PEDAL2, SEQ_TYPE_STANDARD, pedal2seq);
+ }
+ }
+ else if (DI8DEVTYPE_DRIVING == type)
+ {
+ // use the wheel and D-pad for navigation and directional controls
+ add_directional_assignments(
+ assignments,
+ axisitems[0],
+ ITEM_ID_INVALID,
+ povitems[0][0],
+ povitems[0][1],
+ povitems[0][2],
+ povitems[0][3]);
+
+ // check subtype to determine how pedals should be assigned
+ if (DI8DEVTYPEDRIVING_COMBINEDPEDALS == subtype)
+ {
+ if (ITEM_ID_INVALID != axisitems[1])
+ {
+ // put first two pedals on opposite sides of Y axis
+ assignments.emplace_back(
+ IPT_PEDAL,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, axisitems[1])));
+ assignments.emplace_back(
+ IPT_PEDAL2,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, axisitems[1])));
+
+ // use for previous/next group as well
+ assignments.emplace_back(
+ IPT_UI_NEXT_GROUP,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, axisitems[1])));
+ assignments.emplace_back(
+ IPT_UI_PREV_GROUP,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, axisitems[1])));
+ }
+ }
+ else
+ {
+ // see if we have individual pedals
+ if (ITEM_ID_INVALID != pedalitems[0])
+ {
+ assignments.emplace_back(
+ IPT_PEDAL,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, pedalitems[0])));
+ assignments.emplace_back(
+ IPT_UI_NEXT_GROUP,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, pedalitems[0])));
+ }
+ if (ITEM_ID_INVALID != pedalitems[1])
+ {
+ assignments.emplace_back(
+ IPT_PEDAL2,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, pedalitems[1])));
+ assignments.emplace_back(
+ IPT_UI_PREV_GROUP,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, pedalitems[1])));
+ }
+ if (ITEM_ID_INVALID != pedalitems[2])
+ {
+ assignments.emplace_back(
+ IPT_PEDAL3,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, pedalitems[2])));
+ assignments.emplace_back(
+ IPT_UI_FOCUS_NEXT,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, pedalitems[2])));
+ }
+ }
+ }
+ else
+ {
+ // assume this is a gamepad - see if it looks like it has dual analog sticks
+ input_item_id stickaxes[2][2] = {
+ { axisitems[0], axisitems[1] },
+ { ITEM_ID_INVALID, ITEM_ID_INVALID } };
+ input_item_id pedalaxis = ITEM_ID_INVALID;
+ if ((ITEM_ID_INVALID != axisitems[2]) && (ITEM_ID_INVALID != axisitems[5]))
+ {
+ // assume Z/Rz are right stick
+ stickaxes[1][0] = axisitems[2];
+ stickaxes[1][1] = axisitems[5];
+ add_twin_stick_assignments(
+ assignments,
+ stickaxes[0][0],
+ stickaxes[0][1],
+ stickaxes[1][0],
+ stickaxes[1][1],
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID);
+ }
+ else if ((ITEM_ID_INVALID != axisitems[3]) && (ITEM_ID_INVALID != axisitems[4]))
+ {
+ // assume Rx/Ry are right stick and Z is triggers if present
+ stickaxes[1][0] = axisitems[3];
+ stickaxes[1][1] = axisitems[4];
+ pedalaxis = axisitems[2];
+ add_twin_stick_assignments(
+ assignments,
+ stickaxes[0][0],
+ stickaxes[0][1],
+ stickaxes[1][0],
+ stickaxes[1][1],
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID);
+ }
+ else
+ {
+ // if Z is present, use it as secondary Y
+ stickaxes[1][1] = axisitems[2];
}
- exit:
- return DIENUM_CONTINUE;
+ // try to find a "complete" stick for primary movement controls
+ input_item_id diraxis[2][2];
+ choose_primary_stick(diraxis, stickaxes[0][0], stickaxes[0][1], stickaxes[1][0], stickaxes[1][1]);
+ add_directional_assignments(
+ assignments,
+ diraxis[0][0],
+ diraxis[0][1],
+ povitems[0][0],
+ povitems[0][1],
+ povitems[0][2],
+ povitems[0][3]);
+
+ // assign a secondary stick axis to joystick Z
+ add_assignment(
+ assignments,
+ IPT_AD_STICK_Z,
+ SEQ_TYPE_STANDARD,
+ ITEM_CLASS_ABSOLUTE,
+ ITEM_MODIFIER_NONE,
+ { diraxis[1][1], diraxis[1][0] });
+
+ // try to find a suitable axis to use for the first two pedals
+ add_assignment(
+ assignments,
+ IPT_PEDAL,
+ SEQ_TYPE_STANDARD,
+ ITEM_CLASS_ABSOLUTE,
+ ITEM_MODIFIER_NEG,
+ { pedalaxis, diraxis[1][1], diraxis[0][1] });
+ add_assignment(
+ assignments,
+ IPT_PEDAL2,
+ SEQ_TYPE_STANDARD,
+ ITEM_CLASS_ABSOLUTE,
+ ITEM_MODIFIER_POS,
+ { pedalaxis, diraxis[1][1], diraxis[0][1] });
+
+ // try to choose an axis for previous/next group
+ if (ITEM_ID_INVALID != pedalaxis)
+ {
+ // this is reversed because right trigger is negative direction
+ assignments.emplace_back(
+ IPT_UI_PREV_GROUP,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, pedalaxis)));
+ assignments.emplace_back(
+ IPT_UI_NEXT_GROUP,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, pedalaxis)));
+ pedalaxis = ITEM_ID_INVALID;
+ }
+ else if (consume_axis_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, diraxis[1][1]))
+ {
+ // took secondary Y
+ }
+ else if (consume_axis_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, diraxis[1][0]))
+ {
+ // took secondary X
+ }
+
+ // use secondary Y for page up/down if available
+ consume_axis_pair(assignments, IPT_UI_PAGE_UP, IPT_UI_PAGE_DOWN, diraxis[1][1]);
+
+ // put focus previous/next and zoom on secondary X if available
+ add_axis_pair_assignment(assignments, IPT_UI_FOCUS_PREV, IPT_UI_FOCUS_NEXT, diraxis[1][0]);
+ add_axis_pair_assignment(assignments, IPT_UI_ZOOM_OUT, IPT_UI_ZOOM_IN, diraxis[1][0]);
}
-};
-//============================================================
-// dinput_joystick_pov_get_state
-//============================================================
+ // set default assignments
+ device.set_default_assignments(std::move(assignments));
+}
-static int32_t dinput_joystick_pov_get_state(void *device_internal, void *item_internal)
+int32_t dinput_joystick_device::pov_get_state(void *device_internal, void *item_internal)
{
- dinput_joystick_device *devinfo = static_cast<dinput_joystick_device *>(device_internal);
- int povnum = reinterpret_cast<uintptr_t>(item_internal) / 4;
- int povdir = reinterpret_cast<uintptr_t>(item_internal) % 4;
- int32_t result = 0;
- DWORD pov;
+ auto *const devinfo = static_cast<dinput_joystick_device *>(device_internal);
+ int const povnum = uintptr_t(item_internal) / 4;
+ int const povdir = uintptr_t(item_internal) % 4;
// get the current state
- devinfo->module().poll_if_necessary(devinfo->machine());
- pov = devinfo->joystick.state.rgdwPOV[povnum];
+ DWORD const pov = devinfo->m_joystick.state.rgdwPOV[povnum];
// if invalid, return 0
if ((pov & 0xffff) == 0xffff)
- return result;
+ return 0;
// return the current state
switch (povdir)
{
- case POVDIR_LEFT: result = (pov >= 22500 && pov <= 31500); break;
- case POVDIR_RIGHT: result = (pov >= 4500 && pov <= 13500); break;
- case POVDIR_UP: result = (pov >= 31500 || pov <= 4500); break;
- case POVDIR_DOWN: result = (pov >= 13500 && pov <= 22500); break;
+ case POVDIR_LEFT: return (pov >= 22500) && (pov <= 31500);
+ case POVDIR_RIGHT: return (pov >= 4500) && (pov <= 13500);
+ case POVDIR_UP: return (pov >= 31500) || (pov <= 4500);
+ case POVDIR_DOWN: return (pov >= 13500) && (pov <= 22500);
}
- return result;
+
+ return 0;
+}
+
+
+//============================================================
+// dinput_api_helper - DirectInput API helper
+//============================================================
+
+dinput_api_helper::dinput_api_helper()
+{
+}
+
+dinput_api_helper::~dinput_api_helper()
+{
+}
+
+int dinput_api_helper::initialize()
+{
+ HRESULT result = DirectInput8Create(GetModuleHandleUni(), DIRECTINPUT_VERSION, IID_IDirectInput8, &m_dinput, nullptr);
+ if (result != DI_OK)
+ {
+ return result;
+ }
+
+ osd_printf_verbose("DirectInput: Using DirectInput %d\n", DIRECTINPUT_VERSION >> 8);
+ return 0;
+}
+
+
+std::pair<Microsoft::WRL::ComPtr<IDirectInputDevice8>, LPCDIDATAFORMAT> dinput_api_helper::open_device(
+ LPCDIDEVICEINSTANCE instance,
+ LPCDIDATAFORMAT format1,
+ LPCDIDATAFORMAT format2,
+ dinput_cooperative_level cooperative_level)
+{
+ HRESULT result;
+
+ // attempt to create a device
+ Microsoft::WRL::ComPtr<IDirectInputDevice8> device;
+ result = m_dinput->CreateDevice(instance->guidInstance, &device, nullptr);
+ if (result != DI_OK)
+ {
+ osd_printf_error("DirectInput: Unable to create device.\n");
+ return std::make_pair(nullptr, nullptr);
+ }
+
+ // attempt to set the data format
+ LPCDIDATAFORMAT format = format1;
+ result = device->SetDataFormat(format);
+ if ((result != DI_OK) && format2)
+ {
+ // use the secondary format if available
+ osd_printf_verbose("DirectInput: Error setting primary data format, trying secondary format.\n");
+ format = format2;
+ result = device->SetDataFormat(format);
+ }
+ if (result != DI_OK)
+ {
+ osd_printf_error("DirectInput: Unable to set data format.\n");
+ return std::make_pair(nullptr, nullptr);
+ }
+
+ // default window to the first window in the list
+ // For now, we always use the desktop window due to multiple issues:
+ // * MAME recreates windows on toggling fullscreen. DirectInput really doesn't like this.
+ // * DirectInput doesn't like the window used for D3D fullscreen exclusive mode.
+ // * With multiple windows, the first window needs to have focus when using foreground mode.
+ // This makes it impossible to use force feedback as that requires foreground exclusive mode.
+ // The only way to get around this would be to reopen devices on focus changes.
+ [[maybe_unused]] HWND window_handle;
+ DWORD di_cooperative_level;
+#if defined(OSD_WINDOWS)
+ auto const &window = dynamic_cast<win_window_info &>(*osd_common_t::window_list().front());
+ bool const standalone_window = !window.attached_mode();
+#elif defined(SDLMAME_WIN32)
+ auto const &window = dynamic_cast<sdl_window_info &>(*osd_common_t::window_list().front());
+ bool const standalone_window = true;
+#endif
+ if (!standalone_window)
+ {
+ // in attached mode we have to ignore the caller and hook up to the desktop window
+ window_handle = GetDesktopWindow();
+ di_cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
+ }
+ else
+ {
+#if defined(OSD_WINDOWS)
+ window_handle = window.platform_window();
+#elif defined(SDLMAME_WIN32)
+ auto const sdlwindow = window.platform_window();
+ SDL_SysWMinfo info;
+ SDL_VERSION(&info.version);
+ if (!SDL_GetWindowWMInfo(sdlwindow, &info))
+ return std::make_pair(nullptr, nullptr);
+ window_handle = info.info.win.window;
+#endif
+ switch (cooperative_level)
+ {
+ case dinput_cooperative_level::BACKGROUND:
+ di_cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
+ break;
+ case dinput_cooperative_level::FOREGROUND:
+ //di_cooperative_level = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE;
+ di_cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
+ break;
+ default:
+ throw false;
+ }
+ }
+
+ // set the cooperative level
+ result = device->SetCooperativeLevel(GetDesktopWindow(), di_cooperative_level);
+ if (result != DI_OK)
+ {
+ osd_printf_error("DirectInput: Unable to set cooperative level.\n");
+ return std::make_pair(nullptr, nullptr);
+ }
+
+ // return new device
+ return std::make_pair(std::move(device), format);
+}
+
+
+std::string dinput_api_helper::make_id(LPCDIDEVICEINSTANCE instance)
+{
+ // use name, product GUID and instance GUID as identifier
+ return
+ text::from_tstring(instance->tszInstanceName) +
+ " product_" +
+ guid_to_string(instance->guidProduct) +
+ " instance_" +
+ guid_to_string(instance->guidInstance);
}
-#else
+} // namespace osd
+
+
+#else // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
+
+#include "input_module.h"
+
+namespace osd {
+
+namespace {
+
MODULE_NOT_SUPPORTED(keyboard_input_dinput, OSD_KEYBOARDINPUT_PROVIDER, "dinput")
MODULE_NOT_SUPPORTED(mouse_input_dinput, OSD_MOUSEINPUT_PROVIDER, "dinput")
MODULE_NOT_SUPPORTED(joystick_input_dinput, OSD_JOYSTICKINPUT_PROVIDER, "dinput")
-#endif
-MODULE_DEFINITION(KEYBOARDINPUT_DINPUT, keyboard_input_dinput)
-MODULE_DEFINITION(MOUSEINPUT_DINPUT, mouse_input_dinput)
-MODULE_DEFINITION(JOYSTICKINPUT_DINPUT, joystick_input_dinput)
+} // anonymous namespace
+
+} // namespace osd
+
+#endif // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
+
+MODULE_DEFINITION(KEYBOARDINPUT_DINPUT, osd::keyboard_input_dinput)
+MODULE_DEFINITION(MOUSEINPUT_DINPUT, osd::mouse_input_dinput)
+MODULE_DEFINITION(JOYSTICKINPUT_DINPUT, osd::joystick_input_dinput)
diff --git a/src/osd/modules/input/input_dinput.h b/src/osd/modules/input/input_dinput.h
index a2b6c2edcbb..98fdfb011bb 100644
--- a/src/osd/modules/input/input_dinput.h
+++ b/src/osd/modules/input/input_dinput.h
@@ -1,54 +1,42 @@
-#ifndef INPUT_DINPUT_H_
-#define INPUT_DINPUT_H_
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles, Brad Hughes, Vas Crabb
+//============================================================
+//
+// input_dinput.h - Windows DirectInput support
+//
+//============================================================
+#ifndef MAME_OSD_INPUT_INPUT_DINPUT_H
+#define MAME_OSD_INPUT_INPUT_DINPUT_H
+
+#pragma once
+
+#include "assignmenthelper.h"
+#include "input_wincommon.h"
-#include "input_common.h"
#include "modules/lib/osdlib.h"
+#include "modules/lib/osdobj_common.h"
-//============================================================
-// dinput_device - base directinput device
-//============================================================
+#include "window.h"
-// DirectInput-specific information about a device
-struct dinput_api_state
-{
-#if DIRECTINPUT_VERSION >= 0x0800
- Microsoft::WRL::ComPtr<IDirectInputDevice8> device;
-#else
- Microsoft::WRL::ComPtr<IDirectInputDevice> device;
- Microsoft::WRL::ComPtr<IDirectInputDevice2> device2;
-#endif
- DIDEVCAPS caps;
- LPCDIDATAFORMAT format;
-};
+#include "strconv.h"
-class device_enum_interface
-{
-public:
- struct dinput_callback_context
- {
- device_enum_interface * self;
- void * state;
- };
+#include <memory>
+#include <mutex>
+#include <string>
+#include <string_view>
+#include <type_traits>
+#include <utility>
- virtual ~device_enum_interface()
- {
- }
+#include <windows.h>
+#include <dinput.h>
+#include <wrl/client.h>
- static BOOL CALLBACK enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref)
- {
- auto context = static_cast<dinput_callback_context*>(ref);
- return context->self->device_enum_callback(instance, context->state);
- }
- virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) = 0;
-};
+namespace osd {
-// Typedef for dynamically loaded function
-#if DIRECTINPUT_VERSION >= 0x0800
-typedef HRESULT (WINAPI *dinput_create_fn)(HINSTANCE, DWORD, LPDIRECTINPUT8 *, LPUNKNOWN);
-#else
-typedef HRESULT (WINAPI *dinput_create_fn)(HINSTANCE, DWORD, LPDIRECTINPUT *, LPUNKNOWN);
-#endif
+//============================================================
+// dinput_device - base directinput device
+//============================================================
enum class dinput_cooperative_level
{
@@ -58,187 +46,144 @@ enum class dinput_cooperative_level
class dinput_api_helper
{
-private:
-#if DIRECTINPUT_VERSION >= 0x0800
- Microsoft::WRL::ComPtr<IDirectInput8> m_dinput;
-#else
- Microsoft::WRL::ComPtr<IDirectInput> m_dinput;
-#endif
- int m_dinput_version;
- osd::dynamic_module::ptr m_dinput_dll;
- dinput_create_fn m_dinput_create_prt;
-
public:
- dinput_api_helper(int version);
- virtual ~dinput_api_helper();
+ dinput_api_helper();
+ ~dinput_api_helper();
+
int initialize();
- template<class TDevice>
- TDevice* create_device(
- running_machine &machine,
- input_module_base &module,
- LPCDIDEVICEINSTANCE instance,
- LPCDIDATAFORMAT format1,
- LPCDIDATAFORMAT format2,
- dinput_cooperative_level cooperative_level)
+ template <typename TDevice, typename TCallback>
+ std::unique_ptr<TDevice> create_device(
+ input_module_base &module,
+ LPCDIDEVICEINSTANCE instance,
+ LPCDIDATAFORMAT format1,
+ LPCDIDATAFORMAT format2,
+ dinput_cooperative_level cooperative_level,
+ TCallback &&callback)
{
- HRESULT result;
- std::shared_ptr<win_window_info> window;
- HWND hwnd;
-
- // convert instance name to utf8
- std::string utf8_instance_name = osd::text::from_tstring(instance->tszInstanceName);
-
- // set device id to name + product unique identifier + instance unique identifier
- std::string utf8_instance_id = utf8_instance_name + " product_" + guid_to_string(instance->guidProduct) + " instance_" + guid_to_string(instance->guidInstance);
-
- // allocate memory for the device object
- TDevice* devinfo = module.devicelist()->create_device<TDevice>(machine, utf8_instance_name.c_str(), utf8_instance_id.c_str(), module);
-
- // attempt to create a device
- result = m_dinput->CreateDevice(instance->guidInstance, devinfo->dinput.device.GetAddressOf(), nullptr);
- if (result != DI_OK)
- goto error;
-
-#if DIRECTINPUT_VERSION < 0x0800
- // try to get a version 2 device for it so we can use the poll method
- result = devinfo->dinput.device.CopyTo(IID_IDirectInputDevice2, reinterpret_cast<void**>(devinfo->dinput.device2.GetAddressOf()));
+ auto [device, format] = open_device(instance, format1, format2, cooperative_level);
+ if (!device)
+ return nullptr;
+
+ // get the capabilities
+ DIDEVCAPS caps;
+ caps.dwSize = sizeof(caps);
+ HRESULT const result = device->GetCapabilities(&caps);
if (result != DI_OK)
- devinfo->dinput.device2 = nullptr;
-#endif
+ return nullptr;
- // get the caps
- devinfo->dinput.caps.dwSize = sizeof(devinfo->dinput.caps);
- result = devinfo->dinput.device->GetCapabilities(&devinfo->dinput.caps);
- if (result != DI_OK)
- goto error;
+ if (!callback(device, format))
+ return nullptr;
- // attempt to set the data format
- devinfo->dinput.format = format1;
- result = devinfo->dinput.device->SetDataFormat(devinfo->dinput.format);
- if (result != DI_OK)
- {
- // use the secondary format if available
- if (format2 != nullptr)
- {
- devinfo->dinput.format = format2;
- result = devinfo->dinput.device->SetDataFormat(devinfo->dinput.format);
- }
- if (result != DI_OK)
- goto error;
- }
-
- // default window to the first window in the list
- window = std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front());
- DWORD di_cooperative_level;
- if (window->attached_mode())
- {
- // in attached mode we have to ignore the caller and hook up to the desktop window
- hwnd = GetDesktopWindow();
- di_cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
- }
- else
- {
- hwnd = window->platform_window();
- switch (cooperative_level)
- {
- case dinput_cooperative_level::BACKGROUND:
- di_cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
- break;
- case dinput_cooperative_level::FOREGROUND:
- di_cooperative_level = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE;
- break;
- default:
- throw false;
- }
- }
-
- // set the cooperative level
- result = devinfo->dinput.device->SetCooperativeLevel(hwnd, di_cooperative_level);
- if (result != DI_OK)
- goto error;
+ // allocate memory for the device object
+ return std::make_unique<TDevice>(
+ text::from_tstring(instance->tszInstanceName),
+ make_id(instance),
+ module,
+ std::move(device),
+ caps,
+ format);
+ }
- return devinfo;
+ template <typename T>
+ HRESULT enum_attached_devices(int devclass, T &&callback) const
+ {
+ return m_dinput->EnumDevices(
+ devclass,
+ &di_enum_devices_cb<std::remove_reference_t<T> >,
+ LPVOID(&callback),
+ DIEDFL_ATTACHEDONLY);
+ }
- error:
- module.devicelist()->free_device(devinfo);
- return nullptr;
+ template <typename T>
+ static HRESULT set_dword_property(
+ T &&device,
+ REFGUID property_guid,
+ DWORD object,
+ DWORD how,
+ DWORD value)
+ {
+ DIPROPDWORD dipdw;
+ dipdw.diph.dwSize = sizeof(dipdw);
+ dipdw.diph.dwHeaderSize = sizeof(dipdw.diph);
+ dipdw.diph.dwObj = object;
+ dipdw.diph.dwHow = how;
+ dipdw.dwData = value;
+
+ return device->SetProperty(property_guid, &dipdw.diph);
}
- HRESULT enum_attached_devices(int devclass, device_enum_interface *enumerate_interface, void *state) const;
+private:
+ std::pair<Microsoft::WRL::ComPtr<IDirectInputDevice8>, LPCDIDATAFORMAT> open_device(
+ LPCDIDEVICEINSTANCE instance,
+ LPCDIDATAFORMAT format1,
+ LPCDIDATAFORMAT format2,
+ dinput_cooperative_level cooperative_level);
+
+ static std::string make_id(LPCDIDEVICEINSTANCE instance);
- static std::string guid_to_string(const GUID& guid)
+ template <typename T>
+ static BOOL CALLBACK di_enum_devices_cb(LPCDIDEVICEINSTANCE instance, LPVOID ref)
{
- // Size of a GUID string with dashes plus null terminator
- char guid_string[37];
-
- snprintf(
- guid_string, ARRAY_LENGTH(guid_string),
- "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
- guid.Data1, guid.Data2, guid.Data3,
- guid.Data4[0], guid.Data4[1], guid.Data4[2],
- guid.Data4[3], guid.Data4[4], guid.Data4[5],
- guid.Data4[6], guid.Data4[7]);
-
- return guid_string;
+ return (*reinterpret_cast<T *>(ref))(instance);
}
+
+ Microsoft::WRL::ComPtr<IDirectInput8> m_dinput;
+ dynamic_module::ptr m_dinput_dll;
};
+
class dinput_device : public device_info
{
-public:
- dinput_api_state dinput;
-
- dinput_device(running_machine &machine, const char *name, const char *id, input_device_class deviceclass, input_module &module);
- virtual ~dinput_device();
-
protected:
- HRESULT poll_dinput(LPVOID pState) const;
-};
-
-class dinput_keyboard_device : public dinput_device
-{
-private:
- std::mutex m_device_lock;
+ dinput_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
+ DIDEVCAPS const &caps,
+ LPCDIDATAFORMAT format);
-public:
- keyboard_state keyboard;
+ HRESULT poll_dinput(LPVOID pState) const;
- dinput_keyboard_device(running_machine &machine, const char *name, const char *id, input_module &module);
+ std::string item_name(int offset, std::string_view defstr, char const *suffix) const;
- void poll() override;
- void reset() override;
+ // DirectInput-specific information about a device
+ Microsoft::WRL::ComPtr<IDirectInputDevice8> const m_device;
+ DIDEVCAPS m_caps;
+ LPCDIDATAFORMAT const m_format;
};
-class dinput_mouse_device : public dinput_device
+
+class dinput_joystick_device : public dinput_device, protected joystick_assignment_helper
{
public:
- mouse_state mouse;
+ dinput_joystick_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
+ DIDEVCAPS const &caps,
+ LPCDIDATAFORMAT format);
-public:
- dinput_mouse_device(running_machine &machine, const char *name, const char *id, input_module &module);
- void poll() override;
void reset() override;
-};
+ void poll(bool relative_reset) override;
+ void configure(input_device &device) override;
-// state information for a joystick; DirectInput state must be first element
-struct dinput_joystick_state
-{
- DIJOYSTATE state;
- LONG rangemin[8];
- LONG rangemax[8];
-};
+private:
+ // state information for a joystick; DirectInput state must be first element
+ struct dinput_joystick_state
+ {
+ DIJOYSTATE state;
+ LONG rangemin[8];
+ LONG rangemax[8];
+ };
-class dinput_joystick_device : public dinput_device
-{
-public:
- dinput_joystick_state joystick;
-public:
- dinput_joystick_device(running_machine &machine, const char *name, const char *id, input_module &module);
- void reset() override;
- void poll() override;
- int configure();
+ static int32_t pov_get_state(void *device_internal, void *item_internal);
+
+ dinput_joystick_state m_joystick;
};
+} // namespace osd
-#endif
+#endif // MAME_OSD_INPUT_INPUT_DINPUT_H
diff --git a/src/osd/modules/input/input_mac.cpp b/src/osd/modules/input/input_mac.cpp
index 4dd030b331a..90360adaa3f 100644
--- a/src/osd/modules/input/input_mac.cpp
+++ b/src/osd/modules/input/input_mac.cpp
@@ -14,8 +14,8 @@
#if defined(OSD_MAC)
// System headers
-#include <ctype.h>
-#include <stddef.h>
+#include <cctype>
+#include <cstddef>
#include <mutex>
#include <memory>
#include <algorithm>
@@ -31,15 +31,8 @@
#include "../../mac/osdmac.h"
#include "input_common.h"
-extern void MacPollInputs();
-
-void mac_osd_interface::customize_input_type_list(simple_list<input_type_entry> &typelist)
-{
-}
-
-void mac_osd_interface::poll_inputs(running_machine &machine)
+void mac_osd_interface::customize_input_type_list(std::vector<input_type_entry> &typelist)
{
- MacPollInputs();
}
void mac_osd_interface::release_keys()
diff --git a/src/osd/modules/input/input_module.h b/src/osd/modules/input/input_module.h
index d521d0d1860..64e5ebb2332 100644
--- a/src/osd/modules/input/input_module.h
+++ b/src/osd/modules/input/input_module.h
@@ -5,29 +5,23 @@
// input_module.h - OSD input module contracts
//
//============================================================
+#ifndef MAME_OSD_INPUT_INPUT_MODULE_H
+#define MAME_OSD_INPUT_INPUT_MODULE_H
-#ifndef INPUT_MODULE_H_
-#define INPUT_MODULE_H_
+#pragma once
#include "osdepend.h"
#include "modules/osdmodule.h"
-class input_module : public osd_module
+class input_module
{
public:
- input_module(const char *type, const char *name)
- : osd_module(type, name)
- {
- }
-
- virtual ~input_module() { }
+ virtual ~input_module() = default;
virtual void input_init(running_machine &machine) = 0;
- virtual void poll_if_necessary(running_machine &machine) = 0;
- virtual void pause() = 0;
- virtual void resume() = 0;
+ virtual void poll_if_necessary(bool relative_reset) = 0;
};
//============================================================
@@ -39,4 +33,4 @@ public:
#define OSD_LIGHTGUNINPUT_PROVIDER "lightgunprovider"
#define OSD_JOYSTICKINPUT_PROVIDER "joystickprovider"
-#endif /* INPUT_MODULE_H_ */
+#endif // MAME_OSD_INPUT_INPUT_MODULE_H
diff --git a/src/osd/modules/input/input_none.cpp b/src/osd/modules/input/input_none.cpp
index 0bad0fb1e7b..96c3f116868 100644
--- a/src/osd/modules/input/input_none.cpp
+++ b/src/osd/modules/input/input_none.cpp
@@ -7,60 +7,58 @@
//============================================================
#include "input_module.h"
-#include "modules/osdmodule.h"
-class keyboard_input_none : public input_module
+
+namespace osd {
+
+namespace {
+
+class keyboard_input_none : public osd_module, public input_module
{
public:
- keyboard_input_none()
- : input_module(OSD_KEYBOARDINPUT_PROVIDER, "none") {}
- int init(const osd_options &options) override { return 0; }
- void poll_if_necessary(running_machine &machine) override {};
- void input_init(running_machine &machine) override {};
- void pause() override {};
- void resume() override {};
+ keyboard_input_none() : osd_module(OSD_KEYBOARDINPUT_PROVIDER, "none") { }
+ int init(osd_interface &osd, const osd_options &options) override { return 0; }
+ void input_init(running_machine &machine) override { }
+ void poll_if_necessary(bool relative_reset) override { }
};
-MODULE_DEFINITION(KEYBOARD_NONE, keyboard_input_none)
-class mouse_input_none : public input_module
+class mouse_input_none : public osd_module, public input_module
{
public:
- mouse_input_none()
- : input_module(OSD_MOUSEINPUT_PROVIDER, "none") {}
- int init(const osd_options &options) override { return 0; }
- void input_init(running_machine &machine) override {};
- void poll_if_necessary(running_machine &machine) override {};
- void pause() override {};
- void resume() override {};
+ mouse_input_none() : osd_module(OSD_MOUSEINPUT_PROVIDER, "none") { }
+ int init(osd_interface &osd, const osd_options &options) override { return 0; }
+ void input_init(running_machine &machine) override { }
+ void poll_if_necessary(bool relative_reset) override { }
};
-MODULE_DEFINITION(MOUSE_NONE, mouse_input_none)
-class lightgun_input_none : public input_module
+class lightgun_input_none : public osd_module, public input_module
{
public:
- lightgun_input_none()
- : input_module(OSD_LIGHTGUNINPUT_PROVIDER, "none") {}
- int init(const osd_options &options) override { return 0; }
- void input_init(running_machine &machine) override {};
- void poll_if_necessary(running_machine &machine) override {};
- void pause() override {};
- void resume() override {};
+ lightgun_input_none() : osd_module(OSD_LIGHTGUNINPUT_PROVIDER, "none") { }
+ int init(osd_interface &osd, const osd_options &options) override { return 0; }
+ void input_init(running_machine &machine) override { }
+ void poll_if_necessary(bool relative_reset) override { }
};
-MODULE_DEFINITION(LIGHTGUN_NONE, lightgun_input_none)
-class joystick_input_none : public input_module
+class joystick_input_none : public osd_module, public input_module
{
public:
- joystick_input_none()
- : input_module(OSD_JOYSTICKINPUT_PROVIDER, "none") {}
- int init(const osd_options &options) override { return 0; }
- void input_init(running_machine &machine) override {};
- void poll_if_necessary(running_machine &machine) override {};
- void pause() override {};
- void resume() override {};
+ joystick_input_none() : osd_module(OSD_JOYSTICKINPUT_PROVIDER, "none") { }
+ int init(osd_interface &osd, const osd_options &options) override { return 0; }
+ void input_init(running_machine &machine) override { }
+ void poll_if_necessary(bool relative_reset) override { }
};
-MODULE_DEFINITION(JOYSTICK_NONE, joystick_input_none)
+} // anonymous namesapce
+
+} // namespace osd
+
+
+
+MODULE_DEFINITION(KEYBOARD_NONE, osd::keyboard_input_none)
+MODULE_DEFINITION(MOUSE_NONE, osd::mouse_input_none)
+MODULE_DEFINITION(LIGHTGUN_NONE, osd::lightgun_input_none)
+MODULE_DEFINITION(JOYSTICK_NONE, osd::joystick_input_none)
diff --git a/src/osd/modules/input/input_rawinput.cpp b/src/osd/modules/input/input_rawinput.cpp
index 9243ec4a0f4..5b6813dcd59 100644
--- a/src/osd/modules/input/input_rawinput.cpp
+++ b/src/osd/modules/input/input_rawinput.cpp
@@ -6,41 +6,39 @@
//
//============================================================
-#include "input_module.h"
#include "modules/osdmodule.h"
#if defined(OSD_WINDOWS)
-// standard windows headers
-#include <windows.h>
-#include <tchar.h>
-#undef interface
+#include "input_windows.h"
-#include <mutex>
-#include <functional>
-#include <algorithm>
+#include "input_wincommon.h"
-// MAME headers
-#include "emu.h"
-#include "strconv.h"
-
-// MAMEOS headers
-#include "modules/lib/osdlib.h"
#include "winmain.h"
#include "window.h"
-#include "input_common.h"
-#include "input_windows.h"
+#include "modules/lib/osdlib.h"
+#include "strconv.h"
-//============================================================
-// MACROS
-//============================================================
+// MAME headers
+#include "inpttype.h"
+
+#include <algorithm>
+#include <cassert>
+#include <chrono>
+#include <functional>
+#include <mutex>
+#include <new>
+#include <utility>
+
+// standard windows headers
+#include <windows.h>
+#include <tchar.h>
-// Typedefs for dynamically loaded functions
-typedef UINT (WINAPI *get_rawinput_device_list_ptr)(PRAWINPUTDEVICELIST, PUINT, UINT);
-typedef UINT (WINAPI *get_rawinput_data_ptr)( HRAWINPUT, UINT, LPVOID, PUINT, UINT);
-typedef UINT (WINAPI *get_rawinput_device_info_ptr)(HANDLE, UINT, LPVOID, PUINT);
-typedef BOOL (WINAPI *register_rawinput_devices_ptr)(PCRAWINPUTDEVICE, UINT, UINT);
+
+namespace osd {
+
+namespace {
class safe_regkey
{
@@ -48,17 +46,24 @@ private:
HKEY m_key;
public:
- safe_regkey()
- : m_key(nullptr)
- {
- }
+ safe_regkey() : m_key(nullptr) { }
+ safe_regkey(safe_regkey const &) = delete;
+ safe_regkey(safe_regkey &&key) : m_key(key.m_key) { key.m_key = nullptr; }
+ explicit safe_regkey(HKEY key) : m_key(key) { }
- explicit safe_regkey(HKEY key)
- : m_key(key)
+ ~safe_regkey() { close(); }
+
+ safe_regkey &operator=(safe_regkey const &) = delete;
+
+ safe_regkey &operator=(safe_regkey &&key)
{
+ close();
+ m_key = key.m_key;
+ key.m_key = nullptr;
+ return *this;
}
- bool valid() const { return m_key != nullptr; }
+ explicit operator bool() const { return m_key != nullptr; }
void close()
{
@@ -69,70 +74,68 @@ public:
}
}
- ~safe_regkey()
- {
- close();
- }
-
operator HKEY() const { return m_key; }
-};
-//============================================================
-// reg_open_key
-//============================================================
-
-static safe_regkey reg_open_key(HKEY basekey, const std::wstring &subkey)
-{
- HKEY key;
- if (RegOpenKeyEx(basekey, subkey.c_str(), 0, KEY_READ, &key) == ERROR_SUCCESS)
- return safe_regkey(key);
+ safe_regkey open(std::wstring const &subkey) const { return open(m_key, subkey); }
- return safe_regkey();
+ std::wstring enum_key(int index) const
+ {
+ WCHAR keyname[256];
+ DWORD namelen = std::size(keyname);
+ if (RegEnumKeyEx(m_key, index, keyname, &namelen, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS)
+ return std::wstring(keyname, namelen);
+ else
+ return std::wstring();
+ }
-}
+ std::wstring query_string(WCHAR const *path) const
+ {
+ // first query to get the length
+ DWORD datalen;
+ if (RegQueryValueExW(m_key, path, nullptr, nullptr, nullptr, &datalen) != ERROR_SUCCESS)
+ return std::wstring();
-//============================================================
-// reg_enum_key
-//============================================================
+ // allocate a buffer
+ auto buffer = std::make_unique<WCHAR []>((datalen + (sizeof(WCHAR) * 2) - 1) / sizeof(WCHAR));
-static std::wstring reg_enum_key(HKEY key, int index)
-{
- WCHAR keyname[MAX_PATH];
- DWORD namelen;
- if (RegEnumKeyEx(key, index, keyname, &namelen, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS)
- return std::wstring(keyname, namelen);
+ // now get the actual data
+ if (RegQueryValueExW(m_key, path, nullptr, nullptr, reinterpret_cast<LPBYTE>(buffer.get()), &datalen) != ERROR_SUCCESS)
+ return std::wstring();
- return std::wstring();
-}
-
-//============================================================
-// reg_query_string
-//============================================================
-
-static std::wstring reg_query_string(HKEY key, const TCHAR *path)
-{
- DWORD datalen;
- LONG result;
+ buffer[datalen / sizeof(WCHAR)] = 0;
+ return std::wstring(buffer.get());
+ }
- // first query to get the length
- result = RegQueryValueEx(key, path, nullptr, nullptr, nullptr, &datalen);
- if (result != ERROR_SUCCESS)
- return std::wstring();
+ template <typename T> void foreach_subkey(T &&action) const
+ {
+ std::wstring name;
+ for (int i = 0; ; i++)
+ {
+ name = enum_key(i);
+ if (name.empty())
+ break;
- // allocate a buffer
- auto buffer = std::make_unique<TCHAR[]>(datalen + sizeof(TCHAR));
- buffer[datalen / sizeof(TCHAR)] = 0;
+ safe_regkey const subkey = open(name);
+ if (!subkey)
+ break;
- // now get the actual data
- result = RegQueryValueEx(key, path, nullptr, nullptr, reinterpret_cast<LPBYTE>(buffer.get()), &datalen);
- if (result == ERROR_SUCCESS)
- return std::wstring(buffer.get());
+ bool const shouldcontinue = action(subkey);
+ if (!shouldcontinue)
+ break;
+ }
+ }
- // otherwise return an empty string
- return std::wstring();
-}
+ static safe_regkey open(HKEY basekey, std::wstring const &subkey)
+ {
+ HKEY key(nullptr);
+ if (RegOpenKeyEx(basekey, subkey.c_str(), 0, KEY_READ, &key) == ERROR_SUCCESS)
+ return safe_regkey(key);
+ else
+ return safe_regkey();
+ }
+};
-static std::wstring trim_prefix(const std::wstring &devicename)
+std::wstring trim_prefix(const std::wstring &devicename)
{
// remove anything prior to the final semicolon
auto semicolon_index = devicename.find_last_of(';');
@@ -142,22 +145,22 @@ static std::wstring trim_prefix(const std::wstring &devicename)
return devicename;
}
-static std::wstring compute_device_regpath(const std::wstring &name)
+std::wstring compute_device_regpath(const std::wstring &name)
{
static const std::wstring basepath(L"SYSTEM\\CurrentControlSet\\Enum\\");
// allocate a temporary string and concatenate the base path plus the name
- auto regpath_buffer = std::make_unique<TCHAR[]>(basepath.length() + 1 + name.length());
+ auto regpath_buffer = std::make_unique<WCHAR []>(basepath.length() + 1 + name.length());
wcscpy(regpath_buffer.get(), basepath.c_str());
- WCHAR * chdst = regpath_buffer.get() + basepath.length();
+ WCHAR *chdst = regpath_buffer.get() + basepath.length();
// convert all # to \ in the name
for (int i = 4; i < name.length(); i++)
- *chdst++ = (name[i] == '#') ? '\\' : name[i];
+ *chdst++ = (name[i] == '#') ? L'\\' : name[i];
*chdst = 0;
// remove the final chunk
- chdst = wcsrchr(regpath_buffer.get(), '\\');
+ chdst = wcsrchr(regpath_buffer.get(), L'\\');
if (chdst == nullptr)
return std::wstring();
@@ -166,15 +169,15 @@ static std::wstring compute_device_regpath(const std::wstring &name)
return std::wstring(regpath_buffer.get());
}
-static std::wstring improve_name_from_base_path(const std::wstring &regpath, bool *hid)
+std::wstring improve_name_from_base_path(const std::wstring &regpath, bool *hid)
{
// now try to open the registry key
- auto device_key = reg_open_key(HKEY_LOCAL_MACHINE, regpath);
- if (!device_key.valid())
+ auto device_key = safe_regkey::open(HKEY_LOCAL_MACHINE, regpath);
+ if (!device_key)
return std::wstring();
// fetch the device description; if it exists, we are finished
- auto regstring = reg_query_string(device_key, L"DeviceDesc");
+ auto regstring = device_key.query_string(L"DeviceDesc");
if (!regstring.empty())
return trim_prefix(regstring);
@@ -183,25 +186,7 @@ static std::wstring improve_name_from_base_path(const std::wstring &regpath, boo
return std::wstring();
}
-static void foreach_subkey(HKEY key, std::function<bool(HKEY)> action)
-{
- for (int i = 0; ; i++)
- {
- std::wstring name = reg_enum_key(key, i);
- if (name.empty())
- break;
-
- safe_regkey subkey = reg_open_key(key, name);
- if (!subkey.valid())
- break;
-
- bool shouldcontinue = action(subkey);
- if (!shouldcontinue)
- break;
- }
-}
-
-static std::wstring improve_name_from_usb_path(const std::wstring &regpath)
+std::wstring improve_name_from_usb_path(const std::wstring &regpath)
{
static const std::wstring usbbasepath(L"SYSTEM\\CurrentControlSet\\Enum\\USB");
@@ -213,40 +198,43 @@ static std::wstring improve_name_from_usb_path(const std::wstring &regpath)
std::wstring parentid = regpath.substr(last_slash_index + 1);
// open the USB key
- auto usb_key = reg_open_key(HKEY_LOCAL_MACHINE, usbbasepath);
- if (!usb_key.valid())
+ auto usb_key = safe_regkey::open(HKEY_LOCAL_MACHINE, usbbasepath);
+ if (!usb_key)
return std::wstring();
std::wstring regstring;
- foreach_subkey(usb_key, [&regstring, &parentid](HKEY subkey)
- {
- foreach_subkey(subkey, [&regstring, &parentid](HKEY endkey)
- {
- std::wstring endparentid = reg_query_string(endkey, L"ParentIdPrefix");
+ usb_key.foreach_subkey(
+ [&regstring, &parentid] (safe_regkey const &subkey)
+ {
+ subkey.foreach_subkey(
+ [&regstring, &parentid] (safe_regkey const &endkey)
+ {
+ std::wstring endparentid = endkey.query_string(L"ParentIdPrefix");
- // This key doesn't have a ParentIdPrefix
- if (endparentid.empty())
- return true;
+ // This key doesn't have a ParentIdPrefix
+ if (endparentid.empty())
+ return true;
- // do we have a match?
- if (parentid.find(endparentid) == 0)
- regstring = reg_query_string(endkey, L"DeviceDesc");
+ // do we have a match?
+ if (parentid.find(endparentid) == 0)
+ regstring = endkey.query_string(L"DeviceDesc");
- return regstring.empty();
- });
+ return regstring.empty();
+ });
- return regstring.empty();
- });
+ return regstring.empty();
+ });
return trim_prefix(regstring);
}
+
//============================================================
// rawinput_device_improve_name
//============================================================
-static std::wstring rawinput_device_improve_name(const std::wstring &name)
+std::wstring rawinput_device_improve_name(const std::wstring &name)
{
// The RAW name received is formatted as:
// \??\type-id#hardware-id#instance-id#{DeviceClasses-id}
@@ -282,20 +270,36 @@ static std::wstring rawinput_device_improve_name(const std::wstring &name)
class rawinput_device : public event_based_device<RAWINPUT>
{
-private:
- HANDLE m_handle;
-
public:
- rawinput_device(running_machine& machine, const char *name, const char *id, input_device_class deviceclass, input_module& module)
- : event_based_device(machine, name, id, deviceclass, module),
- m_handle(nullptr)
+ rawinput_device(std::string &&name, std::string &&id, input_module &module, HANDLE handle) :
+ event_based_device(std::move(name), std::move(id), module),
+ m_handle(handle)
{
}
HANDLE device_handle() const { return m_handle; }
- void set_handle(HANDLE handle) { m_handle = handle; }
+
+ bool reconnect_candidate(std::string_view i) const { return !m_handle && (id() == i); }
+
+ void detach_device()
+ {
+ assert(m_handle);
+ m_handle = nullptr;
+ osd_printf_verbose("RawInput: %s [ID %s] disconnected\n", name(), id());
+ }
+
+ void attach_device(HANDLE handle)
+ {
+ assert(!m_handle);
+ m_handle = handle;
+ osd_printf_verbose("RawInput: %s [ID %s] reconnected\n", name(), id());
+ }
+
+private:
+ HANDLE m_handle;
};
+
//============================================================
// rawinput_keyboard_device
//============================================================
@@ -303,490 +307,672 @@ public:
class rawinput_keyboard_device : public rawinput_device
{
public:
- keyboard_state keyboard;
+ rawinput_keyboard_device(std::string &&name, std::string &&id, input_module &module, HANDLE handle) :
+ rawinput_device(std::move(name), std::move(id), module, handle),
+ m_pause_pressed(std::chrono::steady_clock::time_point::min()),
+ m_e1(0xffff),
+ m_keyboard({ { 0 } })
+ {
+ }
- rawinput_keyboard_device(running_machine& machine, const char *name, const char *id, input_module& module)
- : rawinput_device(machine, name, id, DEVICE_CLASS_KEYBOARD, module),
- keyboard({{0}})
+ virtual void reset() override
{
+ rawinput_device::reset();
+ m_pause_pressed = std::chrono::steady_clock::time_point::min();
+ memset(&m_keyboard, 0, sizeof(m_keyboard));
+ m_e1 = 0xffff;
}
- void reset() override
+ virtual void poll(bool relative_reset) override
{
- memset(&keyboard, 0, sizeof(keyboard));
+ rawinput_device::poll(relative_reset);
+ if (m_keyboard.state[0x80 | 0x45] && (std::chrono::steady_clock::now() > (m_pause_pressed + std::chrono::milliseconds(30))))
+ m_keyboard.state[0x80 | 0x45] = 0x00;
}
- void process_event(RAWINPUT &rawinput) override
+ virtual void process_event(RAWINPUT const &rawinput) override
{
// determine the full DIK-compatible scancode
- uint8_t scancode = (rawinput.data.keyboard.MakeCode & 0x7f) | ((rawinput.data.keyboard.Flags & RI_KEY_E0) ? 0x80 : 0x00);
+ uint8_t scancode;
- // scancode 0xaa is a special shift code we need to ignore
- if (scancode == 0xaa)
+ // the only thing that uses this is Pause
+ if (rawinput.data.keyboard.Flags & RI_KEY_E1)
+ {
+ m_e1 = rawinput.data.keyboard.MakeCode;
return;
+ }
+ else if (0xffff != m_e1)
+ {
+ auto const e1 = std::exchange(m_e1, 0xffff);
+ if (!(rawinput.data.keyboard.Flags & RI_KEY_E0))
+ {
+ if (((e1 & ~USHORT(0x80)) == 0x1d) && ((rawinput.data.keyboard.MakeCode & ~USHORT(0x80)) == 0x45))
+ {
+ if (rawinput.data.keyboard.Flags & RI_KEY_BREAK)
+ return; // RawInput generates a fake break immediately after the make - ignore it
+
+ m_pause_pressed = std::chrono::steady_clock::now();
+ scancode = 0x80 | 0x45;
+ }
+ else
+ {
+ return; // no idea
+ }
+ }
+ else
+ {
+ return; // shouldn't happen, ignore it
+ }
+ }
+ else
+ {
+ // strip bit 7 of the make code to work around dodgy drivers that set it for key up events
+ if (rawinput.data.keyboard.MakeCode & ~USHORT(0xff))
+ {
+ // won't fit in a byte along with the E0 flag
+ return;
+ }
+ scancode = (rawinput.data.keyboard.MakeCode & 0x7f) | ((rawinput.data.keyboard.Flags & RI_KEY_E0) ? 0x80 : 0x00);
+
+ // fake shift generated with cursor control and Ins/Del for compatibility with very old DOS software
+ if (scancode == 0xaa)
+ return;
+ }
// set or clear the key
- keyboard.state[scancode] = (rawinput.data.keyboard.Flags & RI_KEY_BREAK) ? 0x00 : 0x80;
+ m_keyboard.state[scancode] = (rawinput.data.keyboard.Flags & RI_KEY_BREAK) ? 0x00 : 0x80;
}
+
+ virtual void configure(input_device &device) override
+ {
+ keyboard_trans_table const &table = keyboard_trans_table::instance();
+
+ // FIXME: GetKeyNameTextW is for scan codes from WM_KEYDOWN, which aren't quite the same as DIK_* keycodes
+ // in particular, NumLock and Pause are reversed for US-style keyboard systems
+ for (unsigned keynum = 0; keynum < MAX_KEYS; keynum++)
+ {
+ input_item_id itemid = table.map_di_scancode_to_itemid(keynum);
+ WCHAR keyname[100];
+
+ // generate the name
+ // FIXME: GetKeyNameText gives bogus names for media keys and various other things
+ // in many cases it ignores the "extended" bit and returns the key name corresponding to the scan code alone
+ LONG lparam = ((keynum & 0x7f) << 16) | ((keynum & 0x80) << 17);
+ if ((keynum & 0x7f) == 0x45)
+ lparam ^= 0x0100'0000; // horrid hack
+ if (GetKeyNameTextW(lparam, keyname, std::size(keyname)) == 0)
+ _snwprintf(keyname, std::size(keyname), L"Scan%03d", keynum);
+ std::string name = text::from_wstring(keyname);
+
+ // add the item to the device
+ device.add_item(
+ name,
+ util::string_format("SCAN%03d", keynum),
+ itemid,
+ generic_button_get_state<std::uint8_t>,
+ &m_keyboard.state[keynum]);
+ }
+ }
+
+private:
+ std::chrono::steady_clock::time_point m_pause_pressed;
+ uint16_t m_e1;
+ keyboard_state m_keyboard;
};
+
//============================================================
// rawinput_mouse_device
//============================================================
class rawinput_mouse_device : public rawinput_device
{
-private:
- std::mutex m_device_lock;
public:
- mouse_state mouse;
-
- rawinput_mouse_device(running_machine& machine, const char *name, const char *id, input_module& module)
- : rawinput_device(machine, name, id, DEVICE_CLASS_MOUSE, module),
- mouse({0})
+ rawinput_mouse_device(std::string &&name, std::string &&id, input_module &module, HANDLE handle) :
+ rawinput_device(std::move(name), std::move(id), module, handle),
+ m_mouse({0}),
+ m_x(0),
+ m_y(0),
+ m_v(0),
+ m_h(0)
{
}
- void poll() override
+ virtual void poll(bool relative_reset) override
{
- mouse.lX = 0;
- mouse.lY = 0;
- mouse.lZ = 0;
-
- rawinput_device::poll();
+ rawinput_device::poll(relative_reset);
+ if (relative_reset)
+ {
+ m_mouse.lX = std::exchange(m_x, 0);
+ m_mouse.lY = std::exchange(m_y, 0);
+ m_mouse.lV = std::exchange(m_v, 0);
+ m_mouse.lH = std::exchange(m_h, 0);
+ }
}
- void reset() override
+ virtual void reset() override
{
- memset(&mouse, 0, sizeof(mouse));
+ rawinput_device::reset();
+ memset(&m_mouse, 0, sizeof(m_mouse));
+ m_x = m_y = m_v = m_h = 0;
}
- void process_event(RAWINPUT &rawinput) override
+ virtual void configure(input_device &device) override
{
+ // populate the axes
+ device.add_item(
+ "X",
+ std::string_view(),
+ ITEM_ID_XAXIS,
+ generic_axis_get_state<LONG>,
+ &m_mouse.lX);
+ device.add_item(
+ "Y",
+ std::string_view(),
+ ITEM_ID_YAXIS,
+ generic_axis_get_state<LONG>,
+ &m_mouse.lY);
+ device.add_item(
+ "Scroll V",
+ std::string_view(),
+ ITEM_ID_ZAXIS,
+ generic_axis_get_state<LONG>,
+ &m_mouse.lV);
+ device.add_item(
+ "Scroll H",
+ std::string_view(),
+ ITEM_ID_RZAXIS,
+ generic_axis_get_state<LONG>,
+ &m_mouse.lH);
+
+ // populate the buttons
+ for (int butnum = 0; butnum < 5; butnum++)
+ {
+ device.add_item(
+ default_button_name(butnum),
+ std::string_view(),
+ input_item_id(ITEM_ID_BUTTON1 + butnum),
+ generic_button_get_state<BYTE>,
+ &m_mouse.rgbButtons[butnum]);
+ }
+ }
+ virtual void process_event(RAWINPUT const &rawinput) override
+ {
// If this data was intended for a rawinput mouse
if (rawinput.data.mouse.usFlags == MOUSE_MOVE_RELATIVE)
{
+ m_x += rawinput.data.mouse.lLastX * input_device::RELATIVE_PER_PIXEL;
+ m_y += rawinput.data.mouse.lLastY * input_device::RELATIVE_PER_PIXEL;
- mouse.lX += rawinput.data.mouse.lLastX * INPUT_RELATIVE_PER_PIXEL;
- mouse.lY += rawinput.data.mouse.lLastY * INPUT_RELATIVE_PER_PIXEL;
-
- // update zaxis
+ // update Z/Rz axes (vertical/horizontal scroll)
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_WHEEL)
- mouse.lZ += static_cast<int16_t>(rawinput.data.mouse.usButtonData) * INPUT_RELATIVE_PER_PIXEL;
+ m_v += int16_t(rawinput.data.mouse.usButtonData) * input_device::RELATIVE_PER_PIXEL;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_HWHEEL)
+ m_h += int16_t(rawinput.data.mouse.usButtonData) * input_device::RELATIVE_PER_PIXEL;
// update the button states; always update the corresponding mouse buttons
- if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) mouse.rgbButtons[0] = 0x80;
- if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP) mouse.rgbButtons[0] = 0x00;
- if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) mouse.rgbButtons[1] = 0x80;
- if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP) mouse.rgbButtons[1] = 0x00;
- if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) mouse.rgbButtons[2] = 0x80;
- if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP) mouse.rgbButtons[2] = 0x00;
- if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) mouse.rgbButtons[3] = 0x80;
- if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) mouse.rgbButtons[3] = 0x00;
- if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) mouse.rgbButtons[4] = 0x80;
- if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) mouse.rgbButtons[4] = 0x00;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) m_mouse.rgbButtons[0] = 0x80;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP) m_mouse.rgbButtons[0] = 0x00;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) m_mouse.rgbButtons[1] = 0x80;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP) m_mouse.rgbButtons[1] = 0x00;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) m_mouse.rgbButtons[2] = 0x80;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP) m_mouse.rgbButtons[2] = 0x00;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) m_mouse.rgbButtons[3] = 0x80;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) m_mouse.rgbButtons[3] = 0x00;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) m_mouse.rgbButtons[4] = 0x80;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) m_mouse.rgbButtons[4] = 0x00;
}
}
+
+private:
+ mouse_state m_mouse;
+ LONG m_x, m_y, m_v, m_h;
};
+
//============================================================
// rawinput_lightgun_device
//============================================================
class rawinput_lightgun_device : public rawinput_device
{
-private:
- std::mutex m_device_lock;
public:
- mouse_state lightgun;
-
- rawinput_lightgun_device(running_machine& machine, const char *name, const char *id, input_module& module)
- : rawinput_device(machine, name, id, DEVICE_CLASS_LIGHTGUN, module),
- lightgun({0})
+ rawinput_lightgun_device(std::string &&name, std::string &&id, input_module &module, HANDLE handle) :
+ rawinput_device(std::move(name), std::move(id), module, handle),
+ m_lightgun({0}),
+ m_v(0),
+ m_h(0)
{
}
- void poll() override
+ virtual void poll(bool relative_reset) override
{
- lightgun.lZ = 0;
+ rawinput_device::poll(relative_reset);
+ if (relative_reset)
+ {
+ m_lightgun.lV = std::exchange(m_v, 0);
+ m_lightgun.lH = std::exchange(m_h, 0);
+ }
+ }
- rawinput_device::poll();
+ virtual void reset() override
+ {
+ rawinput_device::reset();
+ memset(&m_lightgun, 0, sizeof(m_lightgun));
+ m_v = 0;
+ m_h = 0;
}
- void reset() override
+ virtual void configure(input_device &device) override
{
- memset(&lightgun, 0, sizeof(lightgun));
+ // populate the axes
+ for (int axisnum = 0; axisnum < 2; axisnum++)
+ {
+ device.add_item(
+ default_axis_name[axisnum],
+ std::string_view(),
+ input_item_id(ITEM_ID_XAXIS + axisnum),
+ generic_axis_get_state<LONG>,
+ &m_lightgun.lX + axisnum);
+ }
+
+ // scroll wheels are always relative if present
+ device.add_item(
+ "Scroll V",
+ std::string_view(),
+ ITEM_ID_ADD_RELATIVE1,
+ generic_axis_get_state<LONG>,
+ &m_lightgun.lV);
+ device.add_item(
+ "Scroll H",
+ std::string_view(),
+ ITEM_ID_ADD_RELATIVE2,
+ generic_axis_get_state<LONG>,
+ &m_lightgun.lH);
+
+ // populate the buttons
+ for (int butnum = 0; butnum < 5; butnum++)
+ {
+ device.add_item(
+ default_button_name(butnum),
+ std::string_view(),
+ input_item_id(ITEM_ID_BUTTON1 + butnum),
+ generic_button_get_state<BYTE>,
+ &m_lightgun.rgbButtons[butnum]);
+ }
}
- void process_event(RAWINPUT &rawinput) override
+ virtual void process_event(RAWINPUT const &rawinput) override
{
// If this data was intended for a rawinput lightgun
if (rawinput.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE)
{
-
// update the X/Y positions
- lightgun.lX = normalize_absolute_axis(rawinput.data.mouse.lLastX, 0, INPUT_ABSOLUTE_MAX);
- lightgun.lY = normalize_absolute_axis(rawinput.data.mouse.lLastY, 0, INPUT_ABSOLUTE_MAX);
+ m_lightgun.lX = normalize_absolute_axis(rawinput.data.mouse.lLastX, 0, input_device::ABSOLUTE_MAX);
+ m_lightgun.lY = normalize_absolute_axis(rawinput.data.mouse.lLastY, 0, input_device::ABSOLUTE_MAX);
- // update zaxis
+ // update Z/Rz axes
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_WHEEL)
- lightgun.lZ += static_cast<int16_t>(rawinput.data.mouse.usButtonData) * INPUT_RELATIVE_PER_PIXEL;
+ m_v += int16_t(rawinput.data.mouse.usButtonData) * input_device::RELATIVE_PER_PIXEL;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_HWHEEL)
+ m_h += int16_t(rawinput.data.mouse.usButtonData) * input_device::RELATIVE_PER_PIXEL;
// update the button states; always update the corresponding mouse buttons
- if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) lightgun.rgbButtons[0] = 0x80;
- if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP) lightgun.rgbButtons[0] = 0x00;
- if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) lightgun.rgbButtons[1] = 0x80;
- if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP) lightgun.rgbButtons[1] = 0x00;
- if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) lightgun.rgbButtons[2] = 0x80;
- if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP) lightgun.rgbButtons[2] = 0x00;
- if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) lightgun.rgbButtons[3] = 0x80;
- if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) lightgun.rgbButtons[3] = 0x00;
- if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) lightgun.rgbButtons[4] = 0x80;
- if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) lightgun.rgbButtons[4] = 0x00;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) m_lightgun.rgbButtons[0] = 0x80;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP) m_lightgun.rgbButtons[0] = 0x00;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) m_lightgun.rgbButtons[1] = 0x80;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP) m_lightgun.rgbButtons[1] = 0x00;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) m_lightgun.rgbButtons[2] = 0x80;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP) m_lightgun.rgbButtons[2] = 0x00;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) m_lightgun.rgbButtons[3] = 0x80;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) m_lightgun.rgbButtons[3] = 0x00;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) m_lightgun.rgbButtons[4] = 0x80;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) m_lightgun.rgbButtons[4] = 0x00;
}
}
+
+private:
+ mouse_state m_lightgun;
+ LONG m_v, m_h;
};
+
//============================================================
-// rawinput_module - base class for rawinput modules
+// rawinput_module - base class for RawInput modules
//============================================================
-class rawinput_module : public wininput_module
+class rawinput_module : public wininput_module<rawinput_device>
{
private:
- osd::dynamic_module::ptr m_user32_dll;
- get_rawinput_device_list_ptr get_rawinput_device_list;
- get_rawinput_data_ptr get_rawinput_data;
- get_rawinput_device_info_ptr get_rawinput_device_info;
- register_rawinput_devices_ptr register_rawinput_devices;
- std::mutex m_module_lock;
+ std::mutex m_module_lock;
public:
- rawinput_module(const char *type, const char* name)
- : wininput_module(type, name),
- get_rawinput_device_list(nullptr),
- get_rawinput_data(nullptr),
- get_rawinput_device_info(nullptr),
- register_rawinput_devices(nullptr)
+ rawinput_module(const char *type, const char *name) : wininput_module<rawinput_device>(type, name)
{
}
- bool probe() override
+ virtual bool probe() override
{
- m_user32_dll = osd::dynamic_module::open({ "user32.dll" });
-
- get_rawinput_device_list = m_user32_dll->bind<get_rawinput_device_list_ptr>("GetRawInputDeviceList");
- get_rawinput_data = m_user32_dll->bind<get_rawinput_data_ptr>("GetRawInputData");
- get_rawinput_device_info = m_user32_dll->bind<get_rawinput_device_info_ptr>("GetRawInputDeviceInfoW");
- register_rawinput_devices = m_user32_dll->bind<register_rawinput_devices_ptr>("RegisterRawInputDevices");
-
- if (!get_rawinput_device_list || !get_rawinput_data ||
- !get_rawinput_device_info || !register_rawinput_devices )
- {
- return false;
- }
-
return true;
}
- void input_init(running_machine &machine) override
+ virtual void input_init(running_machine &machine) override
{
- // get the number of devices, allocate a device list, and fetch it
- UINT device_count = 0;
- if ((*get_rawinput_device_list)(nullptr, &device_count, sizeof(RAWINPUTDEVICELIST)) != 0)
- return;
+ wininput_module<rawinput_device>::input_init(machine);
- if (device_count == 0)
+ // get initial number of devices
+ UINT device_count = 0;
+ if (GetRawInputDeviceList(nullptr, &device_count, sizeof(RAWINPUTDEVICELIST)) != 0)
+ {
+ osd_printf_error("Error getting initial number of RawInput devices.\n");
return;
-
- auto rawinput_devices = std::make_unique<RAWINPUTDEVICELIST[]>(device_count);
- if ((*get_rawinput_device_list)(rawinput_devices.get(), &device_count, sizeof(RAWINPUTDEVICELIST)) == -1)
+ }
+ if (!device_count)
return;
- // iterate backwards through devices; new devices are added at the head
- for (int devnum = device_count - 1; devnum >= 0; devnum--)
+ std::unique_ptr<RAWINPUTDEVICELIST []> rawinput_devices;
+ UINT retrieved;
+ do
{
- RAWINPUTDEVICELIST *device = &rawinput_devices[devnum];
- add_rawinput_device(machine, device);
+ rawinput_devices.reset(new (std::nothrow) RAWINPUTDEVICELIST [device_count]);
+ if (!rawinput_devices)
+ {
+ osd_printf_error("Error allocating buffer for RawInput device list.\n");
+ return;
+ }
+ retrieved = GetRawInputDeviceList(rawinput_devices.get(), &device_count, sizeof(RAWINPUTDEVICELIST));
}
-
- // don't enable global inputs when debugging
- if (!machine.options().debug())
+ while ((UINT(-1) == retrieved) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER));
+ if (UINT(-1) == retrieved)
{
- m_global_inputs_enabled = downcast<windows_options &>(machine.options()).global_inputs();
+ osd_printf_error("Error listing RawInput devices.\n");
+ return;
}
+ // iterate backwards through devices; new devices are added at the head
+ for (int devnum = retrieved - 1; devnum >= 0; devnum--)
+ add_rawinput_device(rawinput_devices[devnum]);
+
// If we added no devices, no need to register for notifications
- if (devicelist()->size() == 0)
+ if (devicelist().empty())
return;
// finally, register to receive raw input WM_INPUT messages if we found devices
RAWINPUTDEVICE registration;
registration.usUsagePage = usagepage();
registration.usUsage = usage();
- registration.dwFlags = m_global_inputs_enabled ? 0x00000100 : 0;
- registration.hwndTarget = std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window();
+ registration.dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
+ registration.hwndTarget = dynamic_cast<win_window_info &>(*osd_common_t::window_list().front()).platform_window();
// register the device
- (*register_rawinput_devices)(&registration, 1, sizeof(registration));
+ RegisterRawInputDevices(&registration, 1, sizeof(registration));
}
protected:
- virtual void add_rawinput_device(running_machine& machine, RAWINPUTDEVICELIST * device) = 0;
+ virtual void add_rawinput_device(RAWINPUTDEVICELIST const &device) = 0;
virtual USHORT usagepage() = 0;
virtual USHORT usage() = 0;
- int init_internal() override
- {
- if (!get_rawinput_device_list || !get_rawinput_data ||
- !get_rawinput_device_info || !register_rawinput_devices )
- {
- return 1;
- }
-
- osd_printf_verbose("RawInput: APIs detected\n");
- return 0;
- }
-
template<class TDevice>
- TDevice* create_rawinput_device(running_machine &machine, PRAWINPUTDEVICELIST rawinputdevice)
+ TDevice *create_rawinput_device(input_device_class deviceclass, RAWINPUTDEVICELIST const &rawinputdevice)
{
- TDevice* devinfo;
- UINT name_length = 0;
// determine the length of the device name, allocate it, and fetch it if not nameless
- if ((*get_rawinput_device_info)(rawinputdevice->hDevice, RIDI_DEVICENAME, nullptr, &name_length) != 0)
+ UINT name_length = 0;
+ if (GetRawInputDeviceInfoW(rawinputdevice.hDevice, RIDI_DEVICENAME, nullptr, &name_length) != 0)
return nullptr;
- std::unique_ptr<TCHAR[]> tname = std::make_unique<TCHAR[]>(name_length + 1);
- if (name_length > 1 && (*get_rawinput_device_info)(rawinputdevice->hDevice, RIDI_DEVICENAME, tname.get(), &name_length) == -1)
+ std::unique_ptr<WCHAR []> tname = std::make_unique<WCHAR []>(name_length + 1);
+ if (name_length > 1 && GetRawInputDeviceInfoW(rawinputdevice.hDevice, RIDI_DEVICENAME, tname.get(), &name_length) == UINT(-1))
return nullptr;
// if this is an RDP name, skip it
- if (_tcsstr(tname.get(), TEXT("Root#RDP_")) != nullptr)
+ if (wcsstr(tname.get(), L"Root#RDP_") != nullptr)
return nullptr;
- // improve the name and then allocate a device
- std::wstring name = rawinput_device_improve_name(tname.get());
-
- // convert name to utf8
- std::string utf8_name = osd::text::from_wstring(name.c_str());
-
- // set device id to raw input name
- std::string utf8_id = osd::text::from_wstring(tname.get());
+ // improve the name
+ std::string utf8_name = text::from_wstring(rawinput_device_improve_name(tname.get()));
- devinfo = devicelist()->create_device<TDevice>(machine, utf8_name.c_str(), utf8_id.c_str(), *this);
+ // set device ID to raw input name
+ std::string utf8_id = text::from_wstring(tname.get());
- // Add the handle
- devinfo->set_handle(rawinputdevice->hDevice);
+ tname.reset();
- return devinfo;
+ // allocate a device
+ return &create_device<TDevice>(
+ deviceclass,
+ std::move(utf8_name),
+ std::move(utf8_id),
+ rawinputdevice.hDevice);
}
- bool handle_input_event(input_event eventid, void* eventdata) override
+ virtual bool handle_input_event(input_event eventid, void const *eventdata) override
{
- // Only handle raw input data
- if (!input_enabled() || eventid != INPUT_EVENT_RAWINPUT)
- return false;
-
- HRAWINPUT rawinputdevice = *static_cast<HRAWINPUT*>(eventdata);
-
- BYTE small_buffer[4096];
- std::unique_ptr<BYTE[]> larger_buffer;
- LPBYTE data = small_buffer;
- UINT size;
-
- // ignore if not enabled
- if (!input_enabled())
- return false;
+ switch (eventid)
+ {
+ // handle raw input data
+ case INPUT_EVENT_RAWINPUT:
+ {
+ HRAWINPUT const rawinputdevice = *reinterpret_cast<HRAWINPUT const *>(eventdata);
+
+ union { RAWINPUT r; BYTE b[4096]; } small_buffer;
+ std::unique_ptr<BYTE []> larger_buffer;
+ LPVOID data = &small_buffer;
+ UINT size;
+
+ // determine the size of data buffer we need
+ if (GetRawInputData(rawinputdevice, RID_INPUT, nullptr, &size, sizeof(RAWINPUTHEADER)) != 0)
+ return false;
+
+ // if necessary, allocate a temporary buffer and fetch the data
+ if (size > sizeof(small_buffer))
+ {
+ larger_buffer.reset(new (std::align_val_t(alignof(RAWINPUT)), std::nothrow) BYTE [size]);
+ data = larger_buffer.get();
+ if (!data)
+ return false;
+ }
+
+ // fetch the data and process the appropriate message types
+ UINT result = GetRawInputData(rawinputdevice, RID_INPUT, data, &size, sizeof(RAWINPUTHEADER));
+ if (UINT(-1) == result)
+ {
+ return false;
+ }
+ else if (result)
+ {
+ std::lock_guard<std::mutex> scope_lock(m_module_lock);
+
+ auto *const input = reinterpret_cast<RAWINPUT const *>(data);
+ if (!input->header.hDevice)
+ return false;
+
+ // find the device in the list and update
+ auto target_device = std::find_if(
+ devicelist().begin(),
+ devicelist().end(),
+ [input] (auto const &device)
+ {
+ return input->header.hDevice == device->device_handle();
+ });
+ if (devicelist().end() == target_device)
+ return false;
+
+ (*target_device)->queue_events(input, 1);
+ return true;
+ }
+ }
+ break;
- // determine the size of databuffer we need
- if ((*get_rawinput_data)(rawinputdevice, RID_INPUT, nullptr, &size, sizeof(RAWINPUTHEADER)) != 0)
- return false;
+ case INPUT_EVENT_ARRIVAL:
+ {
+ HRAWINPUT const rawinputdevice = *reinterpret_cast<HRAWINPUT const *>(eventdata);
+
+ // determine the length of the device name, allocate it, and fetch it if not nameless
+ UINT name_length = 0;
+ if (GetRawInputDeviceInfoW(rawinputdevice, RIDI_DEVICENAME, nullptr, &name_length) != 0)
+ return false;
+
+ std::unique_ptr<WCHAR []> tname = std::make_unique<WCHAR []>(name_length + 1);
+ if (name_length > 1 && GetRawInputDeviceInfoW(rawinputdevice, RIDI_DEVICENAME, tname.get(), &name_length) == UINT(-1))
+ return false;
+ std::string utf8_id = text::from_wstring(tname.get());
+ tname.reset();
+
+ std::lock_guard<std::mutex> scope_lock(m_module_lock);
+
+ // find the device in the list and update
+ auto target_device = std::find_if(
+ devicelist().begin(),
+ devicelist().end(),
+ [&utf8_id] (auto const &device)
+ {
+ return device->reconnect_candidate(utf8_id);
+ });
+ if (devicelist().end() == target_device)
+ return false;
+
+ (*target_device)->attach_device(rawinputdevice);
+ return true;
+ }
+ break;
- // if necessary, allocate a temporary buffer and fetch the data
- if (size > sizeof(small_buffer))
- {
- larger_buffer = std::make_unique<BYTE[]>(size);
- data = larger_buffer.get();
- if (data == nullptr)
- return false;
- }
+ case INPUT_EVENT_REMOVAL:
+ {
+ HRAWINPUT const rawinputdevice = *reinterpret_cast<HRAWINPUT const *>(eventdata);
- // fetch the data and process the appropriate message types
- bool result = (*get_rawinput_data)(static_cast<HRAWINPUT>(rawinputdevice), RID_INPUT, data, &size, sizeof(RAWINPUTHEADER));
- if (result)
- {
- std::lock_guard<std::mutex> scope_lock(m_module_lock);
+ std::lock_guard<std::mutex> scope_lock(m_module_lock);
- RAWINPUT *input = reinterpret_cast<RAWINPUT*>(data);
+ // find the device in the list and update
+ auto target_device = std::find_if(
+ devicelist().begin(),
+ devicelist().end(),
+ [rawinputdevice] (auto const &device)
+ {
+ return rawinputdevice == device->device_handle();
+ });
- // find the device in the list and update
- auto target_device = std::find_if(devicelist()->begin(), devicelist()->end(), [input](auto &device)
- {
- auto devinfo = dynamic_cast<rawinput_device*>(device.get());
- return devinfo != nullptr && input->header.hDevice == devinfo->device_handle();
- });
+ if (devicelist().end() == target_device)
+ return false;
- if (target_device != devicelist()->end())
- {
- static_cast<rawinput_device*>((*target_device).get())->queue_events(input, 1);
+ (*target_device)->reset();
+ (*target_device)->detach_device();
return true;
}
+ break;
+
+ default:
+ break;
}
+ // must have been unhandled
return false;
}
};
+
//============================================================
-// keyboard_input_rawinput - rawinput keyboard module
+// keyboard_input_rawinput - RawInput keyboard module
//============================================================
class keyboard_input_rawinput : public rawinput_module
{
public:
- keyboard_input_rawinput()
- : rawinput_module(OSD_KEYBOARDINPUT_PROVIDER, "rawinput")
+ keyboard_input_rawinput() : rawinput_module(OSD_KEYBOARDINPUT_PROVIDER, "rawinput")
{
}
protected:
- USHORT usagepage() override { return 1; }
- USHORT usage() override { return 6; }
- void add_rawinput_device(running_machine& machine, RAWINPUTDEVICELIST * device) override
+ virtual USHORT usagepage() override { return 1; }
+ virtual USHORT usage() override { return 6; }
+
+ virtual void add_rawinput_device(RAWINPUTDEVICELIST const &device) override
{
// make sure this is a keyboard
- if (device->dwType != RIM_TYPEKEYBOARD)
+ if (device.dwType != RIM_TYPEKEYBOARD)
return;
// allocate and link in a new device
- rawinput_keyboard_device *devinfo = create_rawinput_device<rawinput_keyboard_device>(machine, device);
- if (devinfo == nullptr)
- return;
-
- keyboard_trans_table &table = keyboard_trans_table::instance();
-
- // populate it
- for (int keynum = 0; keynum < MAX_KEYS; keynum++)
- {
- input_item_id itemid = table.map_di_scancode_to_itemid(keynum);
- TCHAR keyname[100];
-
- // generate the name
- if (GetKeyNameText(((keynum & 0x7f) << 16) | ((keynum & 0x80) << 17), keyname, ARRAY_LENGTH(keyname)) == 0)
- _sntprintf(keyname, ARRAY_LENGTH(keyname), TEXT("Scan%03d"), keynum);
- std::string name = osd::text::from_tstring(keyname);
-
- // add the item to the device
- devinfo->device()->add_item(name.c_str(), itemid, generic_button_get_state<std::uint8_t>, &devinfo->keyboard.state[keynum]);
- }
+ create_rawinput_device<rawinput_keyboard_device>(DEVICE_CLASS_KEYBOARD, device);
}
};
+
//============================================================
-// mouse_input_rawinput - rawinput mouse module
+// mouse_input_rawinput - RawInput mouse module
//============================================================
class mouse_input_rawinput : public rawinput_module
{
public:
- mouse_input_rawinput()
- : rawinput_module(OSD_MOUSEINPUT_PROVIDER, "rawinput")
+ mouse_input_rawinput() : rawinput_module(OSD_MOUSEINPUT_PROVIDER, "rawinput")
{
}
protected:
- USHORT usagepage() override { return 1; }
- USHORT usage() override { return 2; }
- void add_rawinput_device(running_machine& machine, RAWINPUTDEVICELIST * device) override
+ virtual USHORT usagepage() override { return 1; }
+ virtual USHORT usage() override { return 2; }
+
+ virtual void add_rawinput_device(RAWINPUTDEVICELIST const &device) override
{
// make sure this is a mouse
- if (device->dwType != RIM_TYPEMOUSE)
+ if (device.dwType != RIM_TYPEMOUSE)
return;
// allocate and link in a new device
- rawinput_mouse_device *devinfo = create_rawinput_device<rawinput_mouse_device>(machine, device);
- if (devinfo == nullptr)
- return;
-
- // populate the axes
- for (int axisnum = 0; axisnum < 3; axisnum++)
- {
- devinfo->device()->add_item(
- default_axis_name[axisnum],
- static_cast<input_item_id>(ITEM_ID_XAXIS + axisnum),
- generic_axis_get_state<LONG>,
- &devinfo->mouse.lX + axisnum);
- }
-
- // populate the buttons
- for (int butnum = 0; butnum < 5; butnum++)
- {
- devinfo->device()->add_item(
- default_button_name(butnum),
- static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum),
- generic_button_get_state<BYTE>,
- &devinfo->mouse.rgbButtons[butnum]);
- }
+ create_rawinput_device<rawinput_mouse_device>(DEVICE_CLASS_MOUSE, device);
}
};
+
//============================================================
-// lightgun_input_rawinput - rawinput lightgun module
+// lightgun_input_rawinput - RawInput lightgun module
//============================================================
class lightgun_input_rawinput : public rawinput_module
{
public:
- lightgun_input_rawinput()
- : rawinput_module(OSD_LIGHTGUNINPUT_PROVIDER, "rawinput")
+ lightgun_input_rawinput() : rawinput_module(OSD_LIGHTGUNINPUT_PROVIDER, "rawinput")
{
}
protected:
- USHORT usagepage() override { return 1; }
- USHORT usage() override { return 2; }
- void add_rawinput_device(running_machine& machine, RAWINPUTDEVICELIST * device) override
- {
+ virtual USHORT usagepage() override { return 1; }
+ virtual USHORT usage() override { return 2; }
+ virtual void add_rawinput_device(RAWINPUTDEVICELIST const &device) override
+ {
// make sure this is a mouse
- if (device->dwType != RIM_TYPEMOUSE)
+ if (device.dwType != RIM_TYPEMOUSE)
return;
// allocate and link in a new device
- rawinput_lightgun_device *devinfo = create_rawinput_device<rawinput_lightgun_device>(machine, device);
- if (devinfo == nullptr)
- return;
-
- // populate the axes
- for (int axisnum = 0; axisnum < 3; axisnum++)
- {
- devinfo->device()->add_item(
- default_axis_name[axisnum],
- static_cast<input_item_id>(ITEM_ID_XAXIS + axisnum),
- generic_axis_get_state<LONG>,
- &devinfo->lightgun.lX + axisnum);
- }
-
- // populate the buttons
- for (int butnum = 0; butnum < 5; butnum++)
- {
- devinfo->device()->add_item(
- default_button_name(butnum),
- static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum),
- generic_button_get_state<BYTE>,
- &devinfo->lightgun.rgbButtons[butnum]);
- }
+ create_rawinput_device<rawinput_lightgun_device>(DEVICE_CLASS_LIGHTGUN, device);
}
};
-#else
+} // anonymous namespace
+
+} // namespace osd
+
+#else // defined(OSD_WINDOWS)
+
+#include "input_module.h"
+
+namespace osd {
+
+namespace {
+
MODULE_NOT_SUPPORTED(keyboard_input_rawinput, OSD_KEYBOARDINPUT_PROVIDER, "rawinput")
MODULE_NOT_SUPPORTED(mouse_input_rawinput, OSD_MOUSEINPUT_PROVIDER, "rawinput")
MODULE_NOT_SUPPORTED(lightgun_input_rawinput, OSD_LIGHTGUNINPUT_PROVIDER, "rawinput")
-#endif
-MODULE_DEFINITION(KEYBOARDINPUT_RAWINPUT, keyboard_input_rawinput)
-MODULE_DEFINITION(MOUSEINPUT_RAWINPUT, mouse_input_rawinput)
-MODULE_DEFINITION(LIGHTGUNINPUT_RAWINPUT, lightgun_input_rawinput)
+} // anonymous namespace
+
+} // namespace osd
+
+#endif // defined(OSD_WINDOWS)
+
+MODULE_DEFINITION(KEYBOARDINPUT_RAWINPUT, osd::keyboard_input_rawinput)
+MODULE_DEFINITION(MOUSEINPUT_RAWINPUT, osd::mouse_input_rawinput)
+MODULE_DEFINITION(LIGHTGUNINPUT_RAWINPUT, osd::lightgun_input_rawinput)
diff --git a/src/osd/modules/input/input_sdl.cpp b/src/osd/modules/input/input_sdl.cpp
index 40fe037f8c7..f1fb0241b40 100644
--- a/src/osd/modules/input/input_sdl.cpp
+++ b/src/osd/modules/input/input_sdl.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes
+// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes, Vas Crabb
//============================================================
//
// input_sdl.cpp - SDL 2.0 implementation of MAME input routines
@@ -12,32 +12,39 @@
//============================================================
#include "input_module.h"
+
#include "modules/osdmodule.h"
-#if defined(SDLMAME_SDL2)
+#if defined(OSD_SDL)
-// standard sdl header
-#include <SDL2/SDL.h>
-#include <ctype.h>
-// ReSharper disable once CppUnusedIncludeDirective
-#include <stddef.h>
-#include <mutex>
-#include <memory>
-#include <queue>
-#include <iterator>
-#include <algorithm>
+#include "assignmenthelper.h"
+#include "input_common.h"
-// MAME headers
-#include "emu.h"
-#include "uiinput.h"
-#include "strconv.h"
+#include "interface/inputseq.h"
+#include "modules/lib/osdobj_common.h"
+#include "sdl/osdsdl.h"
-// MAMEOS headers
-#include "input_common.h"
-#include "../lib/osdobj_common.h"
-#include "input_sdlcommon.h"
-#include "../../sdl/osdsdl.h"
-#include "../../sdl/window.h"
+// emu
+#include "inpttype.h"
+
+// standard SDL header
+#include <SDL2/SDL.h>
+
+#include <algorithm>
+#include <cctype>
+#include <chrono>
+#include <cmath>
+#include <cstddef>
+#include <cstring>
+#include <initializer_list>
+#include <iterator>
+#include <list>
+#include <memory>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <tuple>
+#include <utility>
// winnt.h defines this
#ifdef DELETE
@@ -45,9 +52,217 @@
#endif
-// FIXME: sdl does not properly report the window for certain OS.
-#define GET_FOCUS_WINDOW(ev) focus_window()
-//#define GET_FOCUS_WINDOW(ev) window_from_id((ev)->windowID)
+namespace osd {
+
+namespace {
+
+char const *const CONTROLLER_AXIS_XBOX[]{
+ "LSX",
+ "LSY",
+ "RSX",
+ "RSY",
+ "LT",
+ "RT" };
+
+char const *const CONTROLLER_AXIS_PS[]{
+ "LSX",
+ "LSY",
+ "RSX",
+ "RSY",
+ "L2",
+ "R2" };
+
+char const *const CONTROLLER_AXIS_SWITCH[]{
+ "LSX",
+ "LSY",
+ "RSX",
+ "RSY",
+ "ZL",
+ "ZR" };
+
+char const *const CONTROLLER_BUTTON_XBOX360[]{
+ "A",
+ "B",
+ "X",
+ "Y",
+ "Back",
+ "Guide",
+ "Start",
+ "LSB",
+ "RSB",
+ "LB",
+ "RB",
+ "D-pad Up",
+ "D-pad Down",
+ "D-pad Left",
+ "D-pad Right",
+ "Share",
+ "P1",
+ "P2",
+ "P3",
+ "P4",
+ "Touchpad" };
+
+char const *const CONTROLLER_BUTTON_XBOXONE[]{
+ "A",
+ "B",
+ "X",
+ "Y",
+ "View",
+ "Logo",
+ "Menu",
+ "LSB",
+ "RSB",
+ "LB",
+ "RB",
+ "D-pad Up",
+ "D-pad Down",
+ "D-pad Left",
+ "D-pad Right",
+ "Share",
+ "P1",
+ "P2",
+ "P3",
+ "P4",
+ "Touchpad" };
+
+char const *const CONTROLLER_BUTTON_PS3[]{
+ "Cross",
+ "Circle",
+ "Square",
+ "Triangle",
+ "Select",
+ "PS",
+ "Start",
+ "L3",
+ "R3",
+ "L1",
+ "R1",
+ "D-pad Up",
+ "D-pad Down",
+ "D-pad Left",
+ "D-pad Right",
+ "Mute",
+ "P1",
+ "P2",
+ "P3",
+ "P4",
+ "Touchpad" };
+
+char const *const CONTROLLER_BUTTON_PS4[]{
+ "Cross",
+ "Circle",
+ "Square",
+ "Triangle",
+ "Share",
+ "PS",
+ "Options",
+ "L3",
+ "R3",
+ "L1",
+ "R1",
+ "D-pad Up",
+ "D-pad Down",
+ "D-pad Left",
+ "D-pad Right",
+ "Mute",
+ "P1",
+ "P2",
+ "P3",
+ "P4",
+ "Touchpad" };
+
+char const *const CONTROLLER_BUTTON_PS5[]{
+ "Cross",
+ "Circle",
+ "Square",
+ "Triangle",
+ "Create",
+ "PS",
+ "Options",
+ "L3",
+ "R3",
+ "L1",
+ "R1",
+ "D-pad Up",
+ "D-pad Down",
+ "D-pad Left",
+ "D-pad Right",
+ "Mute",
+ "P1",
+ "P2",
+ "P3",
+ "P4",
+ "Touchpad" };
+
+char const *const CONTROLLER_BUTTON_SWITCH[]{
+ "A",
+ "B",
+ "X",
+ "Y",
+ "-",
+ "Home",
+ "+",
+ "LSB",
+ "RSB",
+ "L",
+ "R",
+ "D-pad Up",
+ "D-pad Down",
+ "D-pad Left",
+ "D-pad Right",
+ "Capture",
+ "RSR",
+ "LSL",
+ "RSL",
+ "LSR",
+ "Touchpad" };
+
+[[maybe_unused]] char const *const CONTROLLER_BUTTON_STADIA[]{
+ "A",
+ "B",
+ "X",
+ "Y",
+ "Options",
+ "Logo",
+ "Menu",
+ "L3",
+ "R3",
+ "L1",
+ "R1",
+ "D-pad Up",
+ "D-pad Down",
+ "D-pad Left",
+ "D-pad Right",
+ "Capture",
+ "P1",
+ "P2",
+ "P3",
+ "P4",
+ "Touchpad" };
+
+[[maybe_unused]] char const *const CONTROLLER_BUTTON_SHIELD[]{
+ "A",
+ "B",
+ "X",
+ "Y",
+ "Back",
+ "Logo",
+ "Start",
+ "LSB",
+ "RSB",
+ "LB",
+ "RB",
+ "D-pad Up",
+ "D-pad Down",
+ "D-pad Left",
+ "D-pad Right",
+ "Share",
+ "P1",
+ "P2",
+ "P3",
+ "P4",
+ "Touchpad" };
struct key_lookup_table
{
@@ -56,12 +271,8 @@ struct key_lookup_table
};
#define KE(x) { SDL_SCANCODE_ ## x, "SDL_SCANCODE_" #x },
-#define KE8(A, B, C, D, E, F, G, H) KE(A) KE(B) KE(C) KE(D) KE(E) KE(F) KE(G) KE(H)
-#define KE7(A, B, C, D, E, F, G) KE(A) KE(B) KE(C) KE(D) KE(E) KE(F) KE(G)
-#define KE5(A, B, C, D, E) KE(A) KE(B) KE(C) KE(D) KE(E)
-#define KE3(A, B, C) KE(A) KE(B) KE(C)
-static key_lookup_table sdl_lookup_table[] =
+key_lookup_table const sdl_lookup_table[] =
{
KE(UNKNOWN)
@@ -320,520 +531,1711 @@ static key_lookup_table sdl_lookup_table[] =
KE(APP1)
KE(APP2)
+};
+
+//============================================================
+// lookup_sdl_code
+//============================================================
+int lookup_sdl_code(std::string_view scode)
{
- -1, ""
+ auto const found = std::find_if(
+ std::begin(sdl_lookup_table),
+ std::end(sdl_lookup_table),
+ [&scode] (auto const &key) { return scode == key.name; });
+ return (std::end(sdl_lookup_table) != found) ? found->code : -1;
}
-};
+
//============================================================
-// lookup_sdl_code
+// sdl_device
//============================================================
-static int lookup_sdl_code(const char *scode)
+using sdl_device = event_based_device<SDL_Event>;
+
+
+//============================================================
+// sdl_keyboard_device
+//============================================================
+
+class sdl_keyboard_device : public sdl_device
{
- int i = 0;
+public:
+ sdl_keyboard_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ keyboard_trans_table const &trans_table) :
+ sdl_device(std::move(name), std::move(id), module),
+ m_trans_table(trans_table),
+ m_keyboard({{0}}),
+ m_capslock_pressed(std::chrono::steady_clock::time_point::min())
+ {
+ }
- while (sdl_lookup_table[i].code >= 0)
+ virtual void poll(bool relative_reset) override
{
- if (!strcmp(scode, sdl_lookup_table[i].name))
- return sdl_lookup_table[i].code;
- i++;
+ sdl_device::poll(relative_reset);
+
+#ifdef __APPLE__
+ if (m_keyboard.state[SDL_SCANCODE_CAPSLOCK] && (std::chrono::steady_clock::now() > (m_capslock_pressed + std::chrono::milliseconds(30))))
+ m_keyboard.state[SDL_SCANCODE_CAPSLOCK] = 0x00;
+#endif
}
- return -1;
-}
+
+ virtual void process_event(SDL_Event const &event) override
+ {
+ switch (event.type)
+ {
+ case SDL_KEYDOWN:
+ if (event.key.keysym.scancode == SDL_SCANCODE_CAPSLOCK)
+ m_capslock_pressed = std::chrono::steady_clock::now();
+
+ m_keyboard.state[event.key.keysym.scancode] = 0x80;
+ break;
+
+ case SDL_KEYUP:
+#ifdef __APPLE__
+ if (event.key.keysym.scancode == SDL_SCANCODE_CAPSLOCK)
+ break;
+#endif
+
+ m_keyboard.state[event.key.keysym.scancode] = 0x00;
+ break;
+ }
+ }
+
+ virtual void reset() override
+ {
+ sdl_device::reset();
+ memset(&m_keyboard.state, 0, sizeof(m_keyboard.state));
+ m_capslock_pressed = std::chrono::steady_clock::time_point::min();
+ }
+
+ virtual void configure(input_device &device) override
+ {
+ // populate it
+ for (int keynum = 0; m_trans_table[keynum].mame_key != ITEM_ID_INVALID; keynum++)
+ {
+ input_item_id itemid = m_trans_table[keynum].mame_key;
+ device.add_item(
+ m_trans_table[keynum].ui_name,
+ std::string_view(),
+ itemid,
+ generic_button_get_state<s32>,
+ &m_keyboard.state[m_trans_table[keynum].sdl_scancode]);
+ }
+ }
+
+private:
+ // state information for a keyboard
+ struct keyboard_state
+ {
+ s32 state[0x3ff]; // must be s32!
+ s8 oldkey[MAX_KEYS];
+ s8 currkey[MAX_KEYS];
+ };
+
+ keyboard_trans_table const &m_trans_table;
+ keyboard_state m_keyboard;
+ std::chrono::steady_clock::time_point m_capslock_pressed;
+};
+
//============================================================
-// sdl_device
+// sdl_mouse_device_base
//============================================================
-class sdl_device : public event_based_device<SDL_Event>
+class sdl_mouse_device_base : public sdl_device
{
public:
- sdl_device(running_machine &machine, const char *name, const char *id, input_device_class devclass, input_module &module)
- : event_based_device(machine, name, id, devclass, module)
+ virtual void poll(bool relative_reset) override
{
+ sdl_device::poll(relative_reset);
+
+ if (relative_reset)
+ {
+ m_mouse.lV = std::exchange(m_v, 0);
+ m_mouse.lH = std::exchange(m_h, 0);
+ }
+ }
+
+ virtual void reset() override
+ {
+ sdl_device::reset();
+ memset(&m_mouse, 0, sizeof(m_mouse));
+ m_v = m_h = 0;
}
protected:
- std::shared_ptr<sdl_window_info> focus_window()
+ // state information for a mouse
+ struct mouse_state
+ {
+ s32 lX, lY, lV, lH;
+ s32 buttons[MAX_BUTTONS];
+ };
+
+ sdl_mouse_device_base(std::string &&name, std::string &&id, input_module &module) :
+ sdl_device(std::move(name), std::move(id), module),
+ m_mouse({0}),
+ m_v(0),
+ m_h(0)
{
- return sdl_event_manager::instance().focus_window();
}
+
+ void add_common_items(input_device &device, unsigned buttons)
+ {
+ // add horizontal and vertical axes - relative for a mouse or absolute for a gun
+ device.add_item(
+ "X",
+ std::string_view(),
+ ITEM_ID_XAXIS,
+ generic_axis_get_state<s32>,
+ &m_mouse.lX);
+ device.add_item(
+ "Y",
+ std::string_view(),
+ ITEM_ID_YAXIS,
+ generic_axis_get_state<s32>,
+ &m_mouse.lY);
+
+ // add buttons
+ for (int button = 0; button < buttons; button++)
+ {
+ input_item_id itemid = (input_item_id)(ITEM_ID_BUTTON1 + button);
+ int const offset = button ^ (((1 == button) || (2 == button)) ? 3 : 0);
+ device.add_item(
+ default_button_name(button),
+ std::string_view(),
+ itemid,
+ generic_button_get_state<s32>,
+ &m_mouse.buttons[offset]);
+ }
+ }
+
+ mouse_state m_mouse;
+ s32 m_v, m_h;
};
+
//============================================================
-// sdl_keyboard_device
+// sdl_mouse_device
//============================================================
-class sdl_keyboard_device : public sdl_device
+class sdl_mouse_device : public sdl_mouse_device_base
{
public:
- keyboard_state keyboard;
+ sdl_mouse_device(std::string &&name, std::string &&id, input_module &module) :
+ sdl_mouse_device_base(std::move(name), std::move(id), module),
+ m_x(0),
+ m_y(0)
+ {
+ }
- sdl_keyboard_device(running_machine &machine, const char *name, const char *id, input_module &module)
- : sdl_device(machine, name, id, DEVICE_CLASS_KEYBOARD, module),
- keyboard({{0}})
+ virtual void poll(bool relative_reset) override
{
+ sdl_mouse_device_base::poll(relative_reset);
+
+ if (relative_reset)
+ {
+ m_mouse.lX = std::exchange(m_x, 0);
+ m_mouse.lY = std::exchange(m_y, 0);
+ }
}
- void process_event(SDL_Event &sdlevent) override
+ virtual void reset() override
{
- switch (sdlevent.type)
+ sdl_mouse_device_base::reset();
+ m_x = m_y = 0;
+ }
+
+ virtual void configure(input_device &device) override
+ {
+ add_common_items(device, 5);
+
+ // add scroll axes
+ device.add_item(
+ "Scroll V",
+ std::string_view(),
+ ITEM_ID_ZAXIS,
+ generic_axis_get_state<s32>,
+ &m_mouse.lV);
+ device.add_item(
+ "Scroll H",
+ std::string_view(),
+ ITEM_ID_RZAXIS,
+ generic_axis_get_state<s32>,
+ &m_mouse.lH);
+ }
+
+ virtual void process_event(SDL_Event const &event) override
+ {
+ switch (event.type)
{
- case SDL_KEYDOWN:
- keyboard.state[sdlevent.key.keysym.scancode] = 0x80;
- if (sdlevent.key.keysym.sym < 0x20)
- machine().ui_input().push_char_event(osd_common_t::s_window_list.front()->target(), sdlevent.key.keysym.sym);
+ case SDL_MOUSEMOTION:
+ m_x += event.motion.xrel * input_device::RELATIVE_PER_PIXEL;
+ m_y += event.motion.yrel * input_device::RELATIVE_PER_PIXEL;
break;
- case SDL_KEYUP:
- keyboard.state[sdlevent.key.keysym.scancode] = 0x00;
+ case SDL_MOUSEBUTTONDOWN:
+ m_mouse.buttons[event.button.button - 1] = 0x80;
break;
- case SDL_TEXTINPUT:
- if (*sdlevent.text.text)
- {
- auto window = GET_FOCUS_WINDOW(&event.text);
- //printf("Focus window is %p - wl %p\n", window, osd_common_t::s_window_list);
- if (window != nullptr)
- {
- auto ptr = sdlevent.text.text;
- auto len = std::strlen(sdlevent.text.text);
- while (len)
- {
- char32_t ch;
- auto chlen = uchar_from_utf8(&ch, ptr, len);
- if (0 > chlen)
- {
- ch = 0x0fffd;
- chlen = 1;
- }
- ptr += chlen;
- len -= chlen;
- machine().ui_input().push_char_event(window->target(), ch);
- }
- }
- }
+ case SDL_MOUSEBUTTONUP:
+ m_mouse.buttons[event.button.button - 1] = 0;
+ break;
+
+ case SDL_MOUSEWHEEL:
+ // adjust SDL 1-per-click to match Win32 120-per-click
+#if SDL_VERSION_ATLEAST(2, 0, 18)
+ m_v += std::lround(event.wheel.preciseY * 120 * input_device::RELATIVE_PER_PIXEL);
+ m_h += std::lround(event.wheel.preciseX * 120 * input_device::RELATIVE_PER_PIXEL);
+#else
+ m_v += event.wheel.y * 120 * input_device::RELATIVE_PER_PIXEL;
+ m_h += event.wheel.x * 120 * input_device::RELATIVE_PER_PIXEL;
+#endif
break;
}
}
- void reset() override
- {
- memset(&keyboard.state, 0, sizeof(keyboard.state));
- }
+private:
+ s32 m_x, m_y;
};
+
//============================================================
-// sdl_mouse_device
+// sdl_lightgun_device
//============================================================
-class sdl_mouse_device : public sdl_device
+class sdl_lightgun_device : public sdl_mouse_device_base
{
-private:
- const std::chrono::milliseconds double_click_speed = std::chrono::milliseconds(250);
- std::chrono::system_clock::time_point last_click;
- int last_x;
- int last_y;
-
public:
- mouse_state mouse;
+ sdl_lightgun_device(std::string &&name, std::string &&id, input_module &module) :
+ sdl_mouse_device_base(std::move(name), std::move(id), module),
+ m_x(0),
+ m_y(0),
+ m_window(0)
+ {
+ }
- sdl_mouse_device(running_machine &machine, const char *name, const char *id, input_module &module)
- : sdl_device(machine, name, id, DEVICE_CLASS_MOUSE, module),
- last_x(0),
- last_y(0),
- mouse({0})
+ virtual void poll(bool relative_reset) override
{
+ sdl_mouse_device_base::poll(relative_reset);
+
+ SDL_Window *const win(m_window ? SDL_GetWindowFromID(m_window) : nullptr);
+ if (win)
+ {
+ int w, h;
+ SDL_GetWindowSize(win, &w, &h);
+ m_mouse.lX = normalize_absolute_axis(m_x, 0, w - 1);
+ m_mouse.lY = normalize_absolute_axis(m_y, 0, h - 1);
+ }
+ else
+ {
+ m_mouse.lX = 0;
+ m_mouse.lY = 0;
+ }
}
- void reset() override
+ virtual void reset() override
{
- memset(&mouse, 0, sizeof(mouse));
+ sdl_mouse_device_base::reset();
+ m_x = m_y = 0;
+ m_window = 0;
}
- void poll() override
+ virtual void configure(input_device &device) override
{
- mouse.lX = 0;
- mouse.lY = 0;
- sdl_device::poll();
+ add_common_items(device, 5);
+
+ // add scroll axes
+ device.add_item(
+ "Scroll V",
+ std::string_view(),
+ ITEM_ID_ADD_RELATIVE1,
+ generic_axis_get_state<s32>,
+ &m_mouse.lV);
+ device.add_item(
+ "Scroll H",
+ std::string_view(),
+ ITEM_ID_ADD_RELATIVE2,
+ generic_axis_get_state<s32>,
+ &m_mouse.lH);
}
- virtual void process_event(SDL_Event &sdlevent) override
+ virtual void process_event(SDL_Event const &event) override
{
- switch (sdlevent.type)
+ switch (event.type)
{
case SDL_MOUSEMOTION:
- mouse.lX += sdlevent.motion.xrel * INPUT_RELATIVE_PER_PIXEL;
- mouse.lY += sdlevent.motion.yrel * INPUT_RELATIVE_PER_PIXEL;
-
- {
- int cx = -1, cy = -1;
- auto window = GET_FOCUS_WINDOW(&sdlevent.motion);
-
- if (window != nullptr && window->xy_to_render_target(sdlevent.motion.x, sdlevent.motion.y, &cx, &cy))
- machine().ui_input().push_mouse_move_event(window->target(), cx, cy);
- }
+ m_x = event.motion.x;
+ m_y = event.motion.y;
+ m_window = event.motion.windowID;
break;
case SDL_MOUSEBUTTONDOWN:
- mouse.buttons[sdlevent.button.button - 1] = 0x80;
- //printf("But down %d %d %d %d %s\n", event.button.which, event.button.button, event.button.x, event.button.y, devinfo->name.c_str());
- if (sdlevent.button.button == 1)
- {
- int cx, cy;
- auto click = std::chrono::system_clock::now();
- auto window = GET_FOCUS_WINDOW(&sdlevent.button);
- if (window != nullptr && window->xy_to_render_target(sdlevent.button.x, sdlevent.button.y, &cx, &cy))
- {
- machine().ui_input().push_mouse_down_event(window->target(), cx, cy);
+ m_mouse.buttons[event.button.button - 1] = 0x80;
+ m_x = event.button.x;
+ m_y = event.button.y;
+ m_window = event.button.windowID;
+ break;
- // avoid overflow with std::chrono::time_point::min() by adding rather than subtracting
- if (click < last_click + double_click_speed
- && (cx >= last_x - 4 && cx <= last_x + 4)
- && (cy >= last_y - 4 && cy <= last_y + 4))
- {
- last_click = std::chrono::time_point<std::chrono::system_clock>::min();
- machine().ui_input().push_mouse_double_click_event(window->target(), cx, cy);
- }
- else
- {
- last_click = click;
- last_x = cx;
- last_y = cy;
- }
- }
- }
+ case SDL_MOUSEBUTTONUP:
+ m_mouse.buttons[event.button.button - 1] = 0;
+ m_x = event.button.x;
+ m_y = event.button.y;
+ m_window = event.button.windowID;
+ break;
- else if (sdlevent.button.button == 3)
- {
- int cx, cy;
- auto window = GET_FOCUS_WINDOW(&sdlevent.button);
+ case SDL_MOUSEWHEEL:
+ // adjust SDL 1-per-click to match Win32 120-per-click
+#if SDL_VERSION_ATLEAST(2, 0, 18)
+ m_v += std::lround(event.wheel.preciseY * 120 * input_device::RELATIVE_PER_PIXEL);
+ m_h += std::lround(event.wheel.preciseX * 120 * input_device::RELATIVE_PER_PIXEL);
+#else
+ m_v += event.wheel.y * 120 * input_device::RELATIVE_PER_PIXEL;
+ m_h += event.wheel.x * 120 * input_device::RELATIVE_PER_PIXEL;
+#endif
+ break;
- if (window != nullptr && window->xy_to_render_target(sdlevent.button.x, sdlevent.button.y, &cx, &cy))
- {
- machine().ui_input().push_mouse_rdown_event(window->target(), cx, cy);
- }
- }
+ case SDL_WINDOWEVENT:
+ if ((event.window.windowID == m_window) && (SDL_WINDOWEVENT_LEAVE == event.window.event))
+ m_window = 0;
break;
+ }
+ }
- case SDL_MOUSEBUTTONUP:
- mouse.buttons[sdlevent.button.button - 1] = 0;
- //printf("But up %d %d %d %d\n", event.button.which, event.button.button, event.button.x, event.button.y);
+private:
+ s32 m_x, m_y;
+ u32 m_window;
+};
- if (sdlevent.button.button == 1)
- {
- int cx, cy;
- auto window = GET_FOCUS_WINDOW(&sdlevent.button);
- if (window != nullptr && window->xy_to_render_target(sdlevent.button.x, sdlevent.button.y, &cx, &cy))
- {
- machine().ui_input().push_mouse_up_event(window->target(), cx, cy);
- }
- }
- else if (sdlevent.button.button == 3)
- {
- int cx, cy;
- auto window = GET_FOCUS_WINDOW(&sdlevent.button);
+//============================================================
+// sdl_dual_lightgun_device
+//============================================================
+
+class sdl_dual_lightgun_device : public sdl_mouse_device_base
+{
+public:
+ sdl_dual_lightgun_device(std::string &&name, std::string &&id, input_module &module, u8 index) :
+ sdl_mouse_device_base(std::move(name), std::move(id), module),
+ m_index(index)
+ {
+ }
+
+ virtual void configure(input_device &device) override
+ {
+ add_common_items(device, 2);
+ }
- if (window != nullptr && window->xy_to_render_target(sdlevent.button.x, sdlevent.button.y, &cx, &cy))
+ virtual void process_event(SDL_Event const &event) override
+ {
+ switch (event.type)
+ {
+ case SDL_MOUSEBUTTONDOWN:
+ {
+ SDL_Window *const win(SDL_GetWindowFromID(event.button.windowID));
+ u8 const button = translate_button(event);
+ if (win && ((button / 2) == m_index))
{
- machine().ui_input().push_mouse_rup_event(window->target(), cx, cy);
+ int w, h;
+ SDL_GetWindowSize(win, &w, &h);
+ m_mouse.buttons[(button & 1) << 1] = 0x80;
+ m_mouse.lX = normalize_absolute_axis(event.button.x, 0, w - 1);
+ m_mouse.lY = normalize_absolute_axis(event.button.y, 0, h - 1);
}
}
break;
- case SDL_MOUSEWHEEL:
- auto window = GET_FOCUS_WINDOW(&sdlevent.wheel);
- if (window != nullptr)
- machine().ui_input().push_mouse_wheel_event(window->target(), 0, 0, sdlevent.wheel.y, 3);
+ case SDL_MOUSEBUTTONUP:
+ {
+ u8 const button = translate_button(event);
+ if ((button / 2) == m_index)
+ m_mouse.buttons[(button & 1) << 1] = 0;
+ }
break;
}
}
+
+private:
+ static u8 translate_button(SDL_Event const &event)
+ {
+ u8 const index(event.button.button - 1);
+ return index ^ (((1 == index) || (2 == index)) ? 3 : 0);
+ }
+
+ u8 const m_index;
};
+
//============================================================
-// sdl_joystick_device
+// sdl_joystick_device_base
//============================================================
-// state information for a joystick
-struct sdl_joystick_state
+class sdl_joystick_device_base : public sdl_device, protected joystick_assignment_helper
{
- int32_t axes[MAX_AXES];
- int32_t buttons[MAX_BUTTONS];
- int32_t hatsU[MAX_HATS], hatsD[MAX_HATS], hatsL[MAX_HATS], hatsR[MAX_HATS];
- int32_t balls[MAX_AXES];
-};
+public:
+ std::optional<std::string> const &serial() const { return m_serial; }
+ SDL_JoystickID instance() const { return m_instance; }
-struct sdl_api_state
-{
- SDL_Joystick *device;
- SDL_Haptic *hapdevice;
- SDL_JoystickID joystick_id;
-};
+ bool is_instance(SDL_JoystickID instance) const { return m_instance == instance; }
-class sdl_joystick_device : public sdl_device
-{
-public:
- sdl_joystick_state joystick;
- sdl_api_state sdl_state;
+ bool reconnect_match(std::string_view g, char const *s) const
+ {
+ return
+ (0 > m_instance) &&
+ (id() == g) &&
+ ((s && serial() && (*serial() == s)) || (!s && !serial()));
+ }
- sdl_joystick_device(running_machine &machine, const char *name, const char *id, input_module &module)
- : sdl_device(machine, name, id, DEVICE_CLASS_JOYSTICK, module),
- joystick({{0}}),
- sdl_state({ nullptr })
+protected:
+ sdl_joystick_device_base(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ char const *serial) :
+ sdl_device(std::move(name), std::move(id), module),
+ m_instance(-1)
{
+ if (serial)
+ m_serial = serial;
}
- ~sdl_joystick_device()
+ void set_instance(SDL_JoystickID instance)
{
- if (sdl_state.device != nullptr)
- {
- if (sdl_state.hapdevice != nullptr)
- {
- SDL_HapticClose(sdl_state.hapdevice);
- sdl_state.hapdevice = nullptr;
- }
- SDL_JoystickClose(sdl_state.device);
- sdl_state.device = nullptr;
- }
+ assert(0 > m_instance);
+ assert(0 <= instance);
+
+ m_instance = instance;
}
- void reset() override
+ void clear_instance()
+ {
+ m_instance = -1;
+ }
+
+private:
+ std::optional<std::string> m_serial;
+ SDL_JoystickID m_instance;
+};
+
+
+//============================================================
+// sdl_joystick_device
+//============================================================
+
+class sdl_joystick_device : public sdl_joystick_device_base
+{
+public:
+ sdl_joystick_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ SDL_Joystick *joy,
+ char const *serial) :
+ sdl_joystick_device_base(
+ std::move(name),
+ std::move(id),
+ module,
+ serial),
+ m_joystick({{0}}),
+ m_joydevice(joy),
+ m_hapdevice(SDL_HapticOpenFromJoystick(joy))
{
- memset(&joystick, 0, sizeof(joystick));
+ set_instance(SDL_JoystickInstanceID(joy));
}
- void process_event(SDL_Event &sdlevent) override
+ virtual void configure(input_device &device) override
{
- switch (sdlevent.type)
+ input_device::assignment_vector assignments;
+ char tempname[32];
+
+ int const axiscount = SDL_JoystickNumAxes(m_joydevice);
+ int const buttoncount = SDL_JoystickNumButtons(m_joydevice);
+ int const hatcount = SDL_JoystickNumHats(m_joydevice);
+ int const ballcount = SDL_JoystickNumBalls(m_joydevice);
+
+ // loop over all axes
+ input_item_id axisactual[MAX_AXES];
+ for (int axis = 0; (axis < MAX_AXES) && (axis < axiscount); axis++)
{
- case SDL_JOYAXISMOTION:
- joystick.axes[sdlevent.jaxis.axis] = (sdlevent.jaxis.value * 2);
- break;
+ input_item_id itemid;
- case SDL_JOYBALLMOTION:
- //printf("Ball %d %d\n", sdlevent.jball.xrel, sdlevent.jball.yrel);
- joystick.balls[sdlevent.jball.ball * 2] = sdlevent.jball.xrel * INPUT_RELATIVE_PER_PIXEL;
- joystick.balls[sdlevent.jball.ball * 2 + 1] = sdlevent.jball.yrel * INPUT_RELATIVE_PER_PIXEL;
- break;
+ if (axis < INPUT_MAX_AXIS)
+ itemid = input_item_id(ITEM_ID_XAXIS + axis);
+ else if (axis < (INPUT_MAX_AXIS + INPUT_MAX_ADD_ABSOLUTE))
+ itemid = input_item_id(ITEM_ID_ADD_ABSOLUTE1 + axis - INPUT_MAX_AXIS);
+ else
+ itemid = ITEM_ID_OTHER_AXIS_ABSOLUTE;
+
+ snprintf(tempname, sizeof(tempname), "A%d", axis + 1);
+ axisactual[axis] = device.add_item(
+ tempname,
+ std::string_view(),
+ itemid,
+ generic_axis_get_state<s32>,
+ &m_joystick.axes[axis]);
+ }
- case SDL_JOYHATMOTION:
- if (sdlevent.jhat.value & SDL_HAT_UP)
- {
- joystick.hatsU[sdlevent.jhat.hat] = 0x80;
- }
+ // loop over all buttons
+ for (int button = 0; (button < MAX_BUTTONS) && (button < buttoncount); button++)
+ {
+ input_item_id itemid;
+
+ m_joystick.buttons[button] = 0;
+
+ if (button < INPUT_MAX_BUTTONS)
+ itemid = input_item_id(ITEM_ID_BUTTON1 + button);
+ else if (button < INPUT_MAX_BUTTONS + INPUT_MAX_ADD_SWITCH)
+ itemid = input_item_id(ITEM_ID_ADD_SWITCH1 + button - INPUT_MAX_BUTTONS);
else
+ itemid = ITEM_ID_OTHER_SWITCH;
+
+ input_item_id const actual = device.add_item(
+ default_button_name(button),
+ std::string_view(),
+ itemid,
+ generic_button_get_state<s32>,
+ &m_joystick.buttons[button]);
+
+ // there are sixteen action button types
+ if (button < 16)
{
- joystick.hatsU[sdlevent.jhat.hat] = 0;
- }
- if (sdlevent.jhat.value & SDL_HAT_DOWN)
- {
- joystick.hatsD[sdlevent.jhat.hat] = 0x80;
+ input_seq const seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, actual));
+ assignments.emplace_back(ioport_type(IPT_BUTTON1 + button), SEQ_TYPE_STANDARD, seq);
+
+ // assign the first few buttons to UI actions and pedals
+ switch (button)
+ {
+ case 0:
+ assignments.emplace_back(IPT_PEDAL, SEQ_TYPE_INCREMENT, seq);
+ assignments.emplace_back(IPT_UI_SELECT, SEQ_TYPE_STANDARD, seq);
+ break;
+ case 1:
+ assignments.emplace_back(IPT_PEDAL2, SEQ_TYPE_INCREMENT, seq);
+ assignments.emplace_back((3 > buttoncount) ? IPT_UI_CLEAR : IPT_UI_BACK, SEQ_TYPE_STANDARD, seq);
+ break;
+ case 2:
+ assignments.emplace_back(IPT_PEDAL3, SEQ_TYPE_INCREMENT, seq);
+ assignments.emplace_back(IPT_UI_CLEAR, SEQ_TYPE_STANDARD, seq);
+ break;
+ case 3:
+ assignments.emplace_back(IPT_UI_HELP, SEQ_TYPE_STANDARD, seq);
+ break;
+ }
}
+ }
+
+ // loop over all hats
+ input_item_id hatactual[MAX_HATS][4];
+ for (int hat = 0; (hat < MAX_HATS) && (hat < hatcount); hat++)
+ {
+ input_item_id itemid;
+
+ snprintf(tempname, sizeof(tempname), "Hat %d Up", hat + 1);
+ itemid = input_item_id((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1UP + (4 * hat) : ITEM_ID_OTHER_SWITCH);
+ hatactual[hat][0] = device.add_item(
+ tempname,
+ std::string_view(),
+ itemid,
+ generic_button_get_state<s32>,
+ &m_joystick.hatsU[hat]);
+
+ snprintf(tempname, sizeof(tempname), "Hat %d Down", hat + 1);
+ itemid = input_item_id((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1DOWN + (4 * hat) : ITEM_ID_OTHER_SWITCH);
+ hatactual[hat][1] = device.add_item(
+ tempname,
+ std::string_view(),
+ itemid,
+ generic_button_get_state<s32>,
+ &m_joystick.hatsD[hat]);
+
+ snprintf(tempname, sizeof(tempname), "Hat %d Left", hat + 1);
+ itemid = input_item_id((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1LEFT + (4 * hat) : ITEM_ID_OTHER_SWITCH);
+ hatactual[hat][2] = device.add_item(
+ tempname,
+ std::string_view(),
+ itemid,
+ generic_button_get_state<s32>,
+ &m_joystick.hatsL[hat]);
+
+ snprintf(tempname, sizeof(tempname), "Hat %d Right", hat + 1);
+ itemid = input_item_id((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1RIGHT + (4 * hat) : ITEM_ID_OTHER_SWITCH);
+ hatactual[hat][3] = device.add_item(
+ tempname,
+ std::string_view(),
+ itemid,
+ generic_button_get_state<s32>,
+ &m_joystick.hatsR[hat]);
+ }
+
+ // loop over all (track)balls
+ for (int ball = 0; (ball < (MAX_AXES / 2)) && (ball < ballcount); ball++)
+ {
+ int itemid;
+
+ if (ball * 2 < INPUT_MAX_ADD_RELATIVE)
+ itemid = ITEM_ID_ADD_RELATIVE1 + ball * 2;
else
+ itemid = ITEM_ID_OTHER_AXIS_RELATIVE;
+
+ snprintf(tempname, sizeof(tempname), "R%d X", ball + 1);
+ input_item_id const xactual = device.add_item(
+ tempname,
+ std::string_view(),
+ input_item_id(itemid),
+ generic_axis_get_state<s32>,
+ &m_joystick.balls[ball * 2]);
+
+ snprintf(tempname, sizeof(tempname), "R%d Y", ball + 1);
+ input_item_id const yactual = device.add_item(
+ tempname,
+ std::string_view(),
+ input_item_id(itemid + 1),
+ generic_axis_get_state<s32>,
+ &m_joystick.balls[ball * 2 + 1]);
+
+ if (0 == ball)
{
- joystick.hatsD[sdlevent.jhat.hat] = 0;
+ // assign the first trackball to dial, trackball, mouse and lightgun inputs
+ input_seq const xseq(make_code(ITEM_CLASS_RELATIVE, ITEM_MODIFIER_NONE, xactual));
+ input_seq const yseq(make_code(ITEM_CLASS_RELATIVE, ITEM_MODIFIER_NONE, yactual));
+ assignments.emplace_back(IPT_DIAL, SEQ_TYPE_STANDARD, xseq);
+ assignments.emplace_back(IPT_DIAL_V, SEQ_TYPE_STANDARD, yseq);
+ assignments.emplace_back(IPT_TRACKBALL_X, SEQ_TYPE_STANDARD, xseq);
+ assignments.emplace_back(IPT_TRACKBALL_Y, SEQ_TYPE_STANDARD, yseq);
+ assignments.emplace_back(IPT_LIGHTGUN_X, SEQ_TYPE_STANDARD, xseq);
+ assignments.emplace_back(IPT_LIGHTGUN_Y, SEQ_TYPE_STANDARD, yseq);
+ assignments.emplace_back(IPT_MOUSE_X, SEQ_TYPE_STANDARD, xseq);
+ assignments.emplace_back(IPT_MOUSE_Y, SEQ_TYPE_STANDARD, yseq);
+ if (2 > axiscount)
+ {
+ // use it for joystick inputs if axes are limited
+ assignments.emplace_back(IPT_AD_STICK_X, SEQ_TYPE_STANDARD, xseq);
+ assignments.emplace_back(IPT_AD_STICK_Y, SEQ_TYPE_STANDARD, yseq);
+ }
+ else
+ {
+ // use for non-centring throttle control
+ assignments.emplace_back(IPT_AD_STICK_Z, SEQ_TYPE_STANDARD, yseq);
+ }
}
- if (sdlevent.jhat.value & SDL_HAT_LEFT)
+ else if ((1 == ball) && (2 > axiscount))
{
- joystick.hatsL[sdlevent.jhat.hat] = 0x80;
+ // provide a non-centring throttle control
+ input_seq const yseq(make_code(ITEM_CLASS_RELATIVE, ITEM_MODIFIER_NONE, yactual));
+ assignments.emplace_back(IPT_AD_STICK_Z, SEQ_TYPE_STANDARD, yseq);
}
- else
+ }
+
+ // set up default assignments for axes and hats
+ add_directional_assignments(
+ assignments,
+ (1 <= axiscount) ? axisactual[0] : ITEM_ID_INVALID, // assume first axis is X
+ (2 <= axiscount) ? axisactual[1] : ITEM_ID_INVALID, // assume second axis is Y
+ (1 <= hatcount) ? hatactual[0][2] : ITEM_ID_INVALID,
+ (1 <= hatcount) ? hatactual[0][3] : ITEM_ID_INVALID,
+ (1 <= hatcount) ? hatactual[0][0] : ITEM_ID_INVALID,
+ (1 <= hatcount) ? hatactual[0][1] : ITEM_ID_INVALID);
+ if (2 <= axiscount)
+ {
+ // put pedals on the last of the second, third or fourth axis
+ input_item_id const pedalitem = axisactual[(std::min)(axiscount, 4) - 1];
+ assignments.emplace_back(
+ IPT_PEDAL,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, pedalitem)));
+ assignments.emplace_back(
+ IPT_PEDAL2,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, pedalitem)));
+ }
+ if (3 <= axiscount)
+ {
+ // assign X/Y to one of the twin sticks
+ assignments.emplace_back(
+ (4 <= axiscount) ? IPT_JOYSTICKLEFT_LEFT : IPT_JOYSTICKRIGHT_LEFT,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_LEFT, axisactual[0])));
+ assignments.emplace_back(
+ (4 <= axiscount) ? IPT_JOYSTICKLEFT_RIGHT : IPT_JOYSTICKRIGHT_RIGHT,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_RIGHT, axisactual[0])));
+ assignments.emplace_back(
+ (4 <= axiscount) ? IPT_JOYSTICKLEFT_UP : IPT_JOYSTICKRIGHT_UP,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_UP, axisactual[1])));
+ assignments.emplace_back(
+ (4 <= axiscount) ? IPT_JOYSTICKLEFT_DOWN : IPT_JOYSTICKRIGHT_DOWN,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_DOWN, axisactual[1])));
+
+ // use third or fourth axis for Z
+ input_seq const seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, axisactual[(std::min)(axiscount, 4) - 1]));
+ assignments.emplace_back(IPT_AD_STICK_Z, SEQ_TYPE_STANDARD, seq);
+
+ // use this for focus next/previous to make system selection menu practical to navigate
+ input_seq const upseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, axisactual[2]));
+ input_seq const downseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, axisactual[2]));
+ assignments.emplace_back(IPT_UI_FOCUS_PREV, SEQ_TYPE_STANDARD, upseq);
+ assignments.emplace_back(IPT_UI_FOCUS_NEXT, SEQ_TYPE_STANDARD, downseq);
+ if (4 <= axiscount)
{
- joystick.hatsL[sdlevent.jhat.hat] = 0;
+ // use for zoom as well if there's another axis to use for previous/next group
+ assignments.emplace_back(IPT_UI_ZOOM_IN, SEQ_TYPE_STANDARD, downseq);
+ assignments.emplace_back(IPT_UI_ZOOM_OUT, SEQ_TYPE_STANDARD, upseq);
}
- if (sdlevent.jhat.value & SDL_HAT_RIGHT)
+
+ // use this for twin sticks, too
+ assignments.emplace_back((4 <= axiscount) ? IPT_JOYSTICKRIGHT_LEFT : IPT_JOYSTICKLEFT_UP, SEQ_TYPE_STANDARD, upseq);
+ assignments.emplace_back((4 <= axiscount) ? IPT_JOYSTICKRIGHT_RIGHT : IPT_JOYSTICKLEFT_DOWN, SEQ_TYPE_STANDARD, downseq);
+
+ // put previous/next group on the last of the third or fourth axis
+ input_item_id const groupitem = axisactual[(std::min)(axiscount, 4) - 1];
+ assignments.emplace_back(
+ IPT_UI_PREV_GROUP,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, groupitem)));
+ assignments.emplace_back(
+ IPT_UI_NEXT_GROUP,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, groupitem)));
+ }
+ if (4 <= axiscount)
+ {
+ // use this for twin sticks
+ input_seq const upseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, axisactual[3]));
+ input_seq const downseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, axisactual[3]));
+ assignments.emplace_back(IPT_JOYSTICKRIGHT_UP, SEQ_TYPE_STANDARD, upseq);
+ assignments.emplace_back(IPT_JOYSTICKRIGHT_DOWN, SEQ_TYPE_STANDARD, downseq);
+ }
+
+ // set default assignments
+ device.set_default_assignments(std::move(assignments));
+ }
+
+ ~sdl_joystick_device()
+ {
+ close_device();
+ }
+
+ virtual void reset() override
+ {
+ sdl_joystick_device_base::reset();
+ clear_buffer();
+ }
+
+ virtual void process_event(SDL_Event const &event) override
+ {
+ if (!m_joydevice)
+ return;
+
+ switch (event.type)
+ {
+ case SDL_JOYAXISMOTION:
+ if (event.jaxis.axis < MAX_AXES)
+ m_joystick.axes[event.jaxis.axis] = (event.jaxis.value * 2);
+ break;
+
+ case SDL_JOYBALLMOTION:
+ //printf("Ball %d %d\n", event.jball.xrel, event.jball.yrel);
+ if (event.jball.ball < (MAX_AXES / 2))
{
- joystick.hatsR[sdlevent.jhat.hat] = 0x80;
+ m_joystick.balls[event.jball.ball * 2] = event.jball.xrel * input_device::RELATIVE_PER_PIXEL;
+ m_joystick.balls[event.jball.ball * 2 + 1] = event.jball.yrel * input_device::RELATIVE_PER_PIXEL;
}
- else
+ break;
+
+ case SDL_JOYHATMOTION:
+ if (event.jhat.hat < MAX_HATS)
{
- joystick.hatsR[sdlevent.jhat.hat] = 0;
+ m_joystick.hatsU[event.jhat.hat] = (event.jhat.value & SDL_HAT_UP) ? 0x80 : 0;
+ m_joystick.hatsD[event.jhat.hat] = (event.jhat.value & SDL_HAT_DOWN) ? 0x80 : 0;
+ m_joystick.hatsL[event.jhat.hat] = (event.jhat.value & SDL_HAT_LEFT) ? 0x80 : 0;
+ m_joystick.hatsR[event.jhat.hat] = (event.jhat.value & SDL_HAT_RIGHT) ? 0x80 : 0;
}
break;
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
- joystick.buttons[sdlevent.jbutton.button] = (sdlevent.jbutton.state == SDL_PRESSED) ? 0x80 : 0;
+ if (event.jbutton.button < MAX_BUTTONS)
+ m_joystick.buttons[event.jbutton.button] = (event.jbutton.state == SDL_PRESSED) ? 0x80 : 0;
break;
+
+ case SDL_JOYDEVICEREMOVED:
+ osd_printf_verbose("Joystick: %s [ID %s] disconnected\n", name(), id());
+ clear_instance();
+ clear_buffer();
+ close_device();
+ break;
+ }
+ }
+
+ bool has_haptic() const
+ {
+ return m_hapdevice != nullptr;
+ }
+
+ void attach_device(SDL_Joystick *joy)
+ {
+ assert(joy);
+ assert(!m_joydevice);
+
+ set_instance(SDL_JoystickInstanceID(joy));
+ m_joydevice = joy;
+ m_hapdevice = SDL_HapticOpenFromJoystick(joy);
+
+ osd_printf_verbose("Joystick: %s [ID %s] reconnected\n", name(), id());
+ }
+
+protected:
+ // state information for a joystick
+ struct sdl_joystick_state
+ {
+ s32 axes[MAX_AXES];
+ s32 buttons[MAX_BUTTONS];
+ s32 hatsU[MAX_HATS], hatsD[MAX_HATS], hatsL[MAX_HATS], hatsR[MAX_HATS];
+ s32 balls[MAX_AXES];
+ };
+
+ sdl_joystick_state m_joystick;
+
+private:
+ SDL_Joystick *m_joydevice;
+ SDL_Haptic *m_hapdevice;
+
+ void clear_buffer()
+ {
+ memset(&m_joystick, 0, sizeof(m_joystick));
+ }
+
+ void close_device()
+ {
+ if (m_joydevice)
+ {
+ if (m_hapdevice)
+ {
+ SDL_HapticClose(m_hapdevice);
+ m_hapdevice = nullptr;
+ }
+ SDL_JoystickClose(m_joydevice);
+ m_joydevice = nullptr;
}
}
};
+
+//============================================================
+// sdl_sixaxis_joystick_device
+//============================================================
+
class sdl_sixaxis_joystick_device : public sdl_joystick_device
{
public:
- sdl_sixaxis_joystick_device(running_machine &machine, const char *name, const char *id, input_module &module)
- : sdl_joystick_device(machine, name, id, module)
- {
- }
+ using sdl_joystick_device::sdl_joystick_device;
- void process_event(SDL_Event &sdlevent) override
+ virtual void process_event(SDL_Event const &event) override
{
- switch (sdlevent.type)
+ switch (event.type)
{
case SDL_JOYAXISMOTION:
{
- int axis = sdlevent.jaxis.axis;
-
+ int const axis = event.jaxis.axis;
if (axis <= 3)
{
- joystick.axes[sdlevent.jaxis.axis] = (sdlevent.jaxis.value * 2);
+ m_joystick.axes[event.jaxis.axis] = (event.jaxis.value * 2);
}
else
{
- int magic = (sdlevent.jaxis.value / 2) + 16384;
- joystick.axes[sdlevent.jaxis.axis] = magic;
+ int const magic = (event.jaxis.value / 2) + 16384;
+ m_joystick.axes[event.jaxis.axis] = magic;
}
}
break;
default:
// Call the base for other events
- sdl_joystick_device::process_event(sdlevent);
+ sdl_joystick_device::process_event(event);
break;
}
}
};
+
//============================================================
-// sdl_input_module
+// sdl_game_controller_device
//============================================================
-class sdl_input_module : public input_module_base, public sdl_event_subscriber
+class sdl_game_controller_device : public sdl_joystick_device_base
{
public:
- sdl_input_module(const char *type)
- : input_module_base(type, "sdl")
+ sdl_game_controller_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ SDL_GameController *ctrl,
+ char const *serial) :
+ sdl_joystick_device_base(
+ std::move(name),
+ std::move(id),
+ module,
+ serial),
+ m_controller({{0}}),
+ m_ctrldevice(ctrl)
+ {
+ set_instance(SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(ctrl)));
+ }
+
+ ~sdl_game_controller_device()
{
+ close_device();
}
- void input_init(running_machine &machine) override
+ virtual void configure(input_device &device) override
{
- if (machine.debug_flags & DEBUG_FLAG_OSD_ENABLED)
+ input_device::assignment_vector assignments;
+ char const *const *axisnames = CONTROLLER_AXIS_XBOX;
+ char const *const *buttonnames = CONTROLLER_BUTTON_XBOX360;
+ bool digitaltriggers = false;
+ bool avoidpaddles = false;
+ auto const ctrltype = SDL_GameControllerGetType(m_ctrldevice);
+ switch (ctrltype)
+ {
+ case SDL_CONTROLLER_TYPE_UNKNOWN:
+ osd_printf_verbose("Game Controller: ... unknown type\n", int(ctrltype));
+ break;
+ case SDL_CONTROLLER_TYPE_XBOX360:
+ osd_printf_verbose("Game Controller: ... Xbox 360 type\n");
+ axisnames = CONTROLLER_AXIS_XBOX;
+ buttonnames = CONTROLLER_BUTTON_XBOX360;
+ break;
+ case SDL_CONTROLLER_TYPE_XBOXONE:
+ osd_printf_verbose("Game Controller: ... Xbox One type\n");
+ axisnames = CONTROLLER_AXIS_XBOX;
+ buttonnames = CONTROLLER_BUTTON_XBOXONE;
+ break;
+ case SDL_CONTROLLER_TYPE_PS3:
+ osd_printf_verbose("Game Controller: ... PlayStation 3 type\n");
+ axisnames = CONTROLLER_AXIS_PS;
+ buttonnames = CONTROLLER_BUTTON_PS3;
+ break;
+ case SDL_CONTROLLER_TYPE_PS4:
+ osd_printf_verbose("Game Controller: ... PlayStation 4 type\n");
+ axisnames = CONTROLLER_AXIS_PS;
+ buttonnames = CONTROLLER_BUTTON_PS4;
+ break;
+ case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO:
+ osd_printf_verbose("Game Controller: ... Switch Pro Controller type\n");
+ axisnames = CONTROLLER_AXIS_SWITCH;
+ buttonnames = CONTROLLER_BUTTON_SWITCH;
+ digitaltriggers = true;
+ break;
+ //case SDL_CONTROLLER_TYPE_VIRTUAL:
+ case SDL_CONTROLLER_TYPE_PS5:
+ osd_printf_verbose("Game Controller: ... PlayStation 5 type\n");
+ axisnames = CONTROLLER_AXIS_PS;
+ buttonnames = CONTROLLER_BUTTON_PS5;
+ break;
+#if SDL_VERSION_ATLEAST(2, 0, 16)
+ //case SDL_CONTROLLER_TYPE_AMAZON_LUNA:
+ case SDL_CONTROLLER_TYPE_GOOGLE_STADIA:
+ osd_printf_verbose("Game Controller: ... Google Stadia type\n");
+ axisnames = CONTROLLER_AXIS_PS;
+ buttonnames = CONTROLLER_BUTTON_STADIA;
+ break;
+#endif
+#if SDL_VERSION_ATLEAST(2, 24, 0)
+ case SDL_CONTROLLER_TYPE_NVIDIA_SHIELD:
+ osd_printf_verbose("Game Controller: ... NVIDIA Shield type\n");
+ axisnames = CONTROLLER_AXIS_XBOX;
+ buttonnames = CONTROLLER_BUTTON_SHIELD;
+ break;
+ //case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT:
+ //case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT:
+ case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR:
+ osd_printf_verbose("Game Controller: ... Joy-Con pair type\n");
+ axisnames = CONTROLLER_AXIS_SWITCH;
+ buttonnames = CONTROLLER_BUTTON_SWITCH;
+ digitaltriggers = true;
+ avoidpaddles = true;
+ break;
+#endif
+ default: // default to Xbox 360 names
+ osd_printf_verbose("Game Controller: ... unrecognized type (%d)\n", int(ctrltype));
+ break;
+ }
+
+ // keep track of item numbers as we add controls
+ std::pair<input_item_id, input_item_id> axisitems[SDL_CONTROLLER_AXIS_MAX];
+ input_item_id buttonitems[SDL_CONTROLLER_BUTTON_MAX];
+ std::tuple<input_item_id, SDL_GameControllerButton, SDL_GameControllerAxis> numberedbuttons[16];
+ std::fill(
+ std::begin(axisitems),
+ std::end(axisitems),
+ std::make_pair(ITEM_ID_INVALID, ITEM_ID_INVALID));
+ std::fill(
+ std::begin(buttonitems),
+ std::end(buttonitems),
+ ITEM_ID_INVALID);
+ std::fill(
+ std::begin(numberedbuttons),
+ std::end(numberedbuttons),
+ std::make_tuple(ITEM_ID_INVALID, SDL_CONTROLLER_BUTTON_INVALID, SDL_CONTROLLER_AXIS_INVALID));
+
+ // add axes
+ std::tuple<SDL_GameControllerAxis, input_item_id, bool> const axes[]{
+ { SDL_CONTROLLER_AXIS_LEFTX, ITEM_ID_XAXIS, false },
+ { SDL_CONTROLLER_AXIS_LEFTY, ITEM_ID_YAXIS, false },
+ { SDL_CONTROLLER_AXIS_RIGHTX, ITEM_ID_ZAXIS, false },
+ { SDL_CONTROLLER_AXIS_RIGHTY, ITEM_ID_RZAXIS, false },
+ { SDL_CONTROLLER_AXIS_TRIGGERLEFT, ITEM_ID_SLIDER1, true },
+ { SDL_CONTROLLER_AXIS_TRIGGERRIGHT, ITEM_ID_SLIDER2, true } };
+ for (auto [axis, item, buttontest] : axes)
+ {
+ bool avail = !buttontest || !digitaltriggers;
+ avail = avail && SDL_GameControllerHasAxis(m_ctrldevice, axis);
+ if (avail)
+ {
+ auto const binding = SDL_GameControllerGetBindForAxis(m_ctrldevice, axis);
+ switch (binding.bindType)
+ {
+ case SDL_CONTROLLER_BINDTYPE_NONE:
+ avail = false;
+ break;
+ case SDL_CONTROLLER_BINDTYPE_BUTTON:
+ if (buttontest)
+ avail = false;
+ break;
+ default:
+ break;
+ }
+ }
+ if (avail)
+ {
+ axisitems[axis].first = device.add_item(
+ axisnames[axis],
+ std::string_view(),
+ item,
+ generic_axis_get_state<s32>,
+ &m_controller.axes[axis]);
+ }
+ }
+
+ // add automatically numbered buttons
+ std::tuple<SDL_GameControllerButton, SDL_GameControllerAxis, bool> const generalbuttons[]{
+ { SDL_CONTROLLER_BUTTON_A, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_B, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_X, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_Y, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_LEFTSHOULDER, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_INVALID, SDL_CONTROLLER_AXIS_TRIGGERLEFT, true },
+ { SDL_CONTROLLER_BUTTON_INVALID, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, true },
+ { SDL_CONTROLLER_BUTTON_LEFTSTICK, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_RIGHTSTICK, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_PADDLE1, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_PADDLE2, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_PADDLE3, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_PADDLE4, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_GUIDE, SDL_CONTROLLER_AXIS_INVALID, false },
+ { SDL_CONTROLLER_BUTTON_MISC1, SDL_CONTROLLER_AXIS_INVALID, false },
+ { SDL_CONTROLLER_BUTTON_TOUCHPAD, SDL_CONTROLLER_AXIS_INVALID, false },
+ };
+ input_item_id button_item = ITEM_ID_BUTTON1;
+ unsigned buttoncount = 0;
+ for (auto [button, axis, field] : generalbuttons)
+ {
+ bool avail = true;
+ input_item_id actual = ITEM_ID_INVALID;
+ if (SDL_CONTROLLER_BUTTON_INVALID != button)
+ {
+ avail = SDL_GameControllerHasButton(m_ctrldevice, button);
+ if (avail)
+ {
+ auto const binding = SDL_GameControllerGetBindForButton(m_ctrldevice, button);
+ switch (binding.bindType)
+ {
+ case SDL_CONTROLLER_BINDTYPE_NONE:
+ avail = false;
+ break;
+ default:
+ break;
+ }
+ }
+ if (avail)
+ {
+ actual = buttonitems[button] = device.add_item(
+ buttonnames[button],
+ std::string_view(),
+ button_item++,
+ generic_button_get_state<s32>,
+ &m_controller.buttons[button]);
+ if (field && (std::size(numberedbuttons) > buttoncount))
+ std::get<1>(numberedbuttons[buttoncount]) = button;
+ }
+ }
+ else
+ {
+ avail = SDL_GameControllerHasAxis(m_ctrldevice, axis);
+ if (avail)
+ {
+ auto const binding = SDL_GameControllerGetBindForAxis(m_ctrldevice, axis);
+ switch (binding.bindType)
+ {
+ case SDL_CONTROLLER_BINDTYPE_NONE:
+ avail = false;
+ break;
+ case SDL_CONTROLLER_BINDTYPE_BUTTON:
+ break;
+ default:
+ avail = digitaltriggers;
+ }
+ }
+ if (avail)
+ {
+ actual = axisitems[axis].second = device.add_item(
+ axisnames[axis],
+ std::string_view(),
+ button_item++,
+ [] (void *device_internal, void *item_internal) -> int
+ {
+ return (*reinterpret_cast<s32 const *>(item_internal) <= -16'384) ? 1 : 0;
+ },
+ &m_controller.axes[axis]);
+ if (field && (std::size(numberedbuttons) > buttoncount))
+ std::get<2>(numberedbuttons[buttoncount]) = axis;
+ }
+ }
+
+ // add default button assignments
+ if (field && avail && (std::size(numberedbuttons) > buttoncount))
+ {
+ std::get<0>(numberedbuttons[buttoncount]) = actual;
+ add_button_assignment(assignments, ioport_type(IPT_BUTTON1 + buttoncount++), { actual });
+ }
+ }
+
+ // add buttons with fixed item IDs
+ std::pair<SDL_GameControllerButton, input_item_id> const fixedbuttons[]{
+ { SDL_CONTROLLER_BUTTON_BACK, ITEM_ID_SELECT },
+ { SDL_CONTROLLER_BUTTON_START, ITEM_ID_START },
+ { SDL_CONTROLLER_BUTTON_DPAD_UP, ITEM_ID_HAT1UP },
+ { SDL_CONTROLLER_BUTTON_DPAD_DOWN, ITEM_ID_HAT1DOWN },
+ { SDL_CONTROLLER_BUTTON_DPAD_LEFT, ITEM_ID_HAT1LEFT },
+ { SDL_CONTROLLER_BUTTON_DPAD_RIGHT, ITEM_ID_HAT1RIGHT } };
+ for (auto [button, item] : fixedbuttons)
{
- osd_printf_warning("Debug Build: Disabling input grab for -debug\n");
- set_mouse_enabled(false);
+ bool avail = true;
+ avail = SDL_GameControllerHasButton(m_ctrldevice, button);
+ if (avail)
+ {
+ auto const binding = SDL_GameControllerGetBindForButton(m_ctrldevice, button);
+ switch (binding.bindType)
+ {
+ case SDL_CONTROLLER_BINDTYPE_NONE:
+ avail = false;
+ break;
+ default:
+ break;
+ }
+ }
+ if (avail)
+ {
+ buttonitems[button] = device.add_item(
+ buttonnames[button],
+ std::string_view(),
+ item,
+ generic_button_get_state<s32>,
+ &m_controller.buttons[button]);
+ }
}
+
+ // try to get a "complete" joystick for primary movement controls
+ input_item_id diraxis[2][2];
+ choose_primary_stick(
+ diraxis,
+ axisitems[SDL_CONTROLLER_AXIS_LEFTX].first,
+ axisitems[SDL_CONTROLLER_AXIS_LEFTY].first,
+ axisitems[SDL_CONTROLLER_AXIS_RIGHTX].first,
+ axisitems[SDL_CONTROLLER_AXIS_RIGHTY].first);
+
+ // now set up controls using the primary joystick
+ add_directional_assignments(
+ assignments,
+ diraxis[0][0],
+ diraxis[0][1],
+ buttonitems[SDL_CONTROLLER_BUTTON_DPAD_LEFT],
+ buttonitems[SDL_CONTROLLER_BUTTON_DPAD_RIGHT],
+ buttonitems[SDL_CONTROLLER_BUTTON_DPAD_UP],
+ buttonitems[SDL_CONTROLLER_BUTTON_DPAD_DOWN]);
+
+ // assign a secondary stick axis to joystick Z if available
+ bool const zaxis = add_assignment(
+ assignments,
+ IPT_AD_STICK_Z,
+ SEQ_TYPE_STANDARD,
+ ITEM_CLASS_ABSOLUTE,
+ ITEM_MODIFIER_NONE,
+ { diraxis[1][1], diraxis[1][0] });
+ if (!zaxis)
+ {
+ // if both triggers are present, combine them, or failing that, fall back to a pair of buttons
+ if ((ITEM_ID_INVALID != axisitems[SDL_CONTROLLER_AXIS_TRIGGERLEFT].first) && (ITEM_ID_INVALID != axisitems[SDL_CONTROLLER_AXIS_TRIGGERRIGHT].first))
+ {
+ assignments.emplace_back(
+ IPT_AD_STICK_Z,
+ SEQ_TYPE_STANDARD,
+ input_seq(
+ make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, axisitems[SDL_CONTROLLER_AXIS_TRIGGERLEFT].first),
+ make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_REVERSE, axisitems[SDL_CONTROLLER_AXIS_TRIGGERRIGHT].first)));
+ }
+ else if (add_axis_inc_dec_assignment(assignments, IPT_AD_STICK_Z, buttonitems[SDL_CONTROLLER_BUTTON_LEFTSHOULDER], buttonitems[SDL_CONTROLLER_BUTTON_RIGHTSHOULDER]))
+ {
+ // took shoulder buttons
+ }
+ else if (add_axis_inc_dec_assignment(assignments, IPT_AD_STICK_Z, axisitems[SDL_CONTROLLER_AXIS_TRIGGERLEFT].second, axisitems[SDL_CONTROLLER_AXIS_TRIGGERRIGHT].second))
+ {
+ // took trigger buttons
+ }
+ else if (add_axis_inc_dec_assignment(assignments, IPT_AD_STICK_Z, buttonitems[SDL_CONTROLLER_BUTTON_PADDLE1], buttonitems[SDL_CONTROLLER_BUTTON_PADDLE2]))
+ {
+ // took P1/P2
+ }
+ else if (add_axis_inc_dec_assignment(assignments, IPT_AD_STICK_Z, buttonitems[SDL_CONTROLLER_BUTTON_PADDLE3], buttonitems[SDL_CONTROLLER_BUTTON_PADDLE4]))
+ {
+ // took P3/P4
+ }
+ }
+
+ // prefer trigger axes for pedals, otherwise take half axes and buttons
+ unsigned pedalbutton = 0;
+ if (!add_assignment(assignments, IPT_PEDAL, SEQ_TYPE_STANDARD, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, { axisitems[SDL_CONTROLLER_AXIS_TRIGGERRIGHT].first }))
+ {
+ add_assignment(
+ assignments,
+ IPT_PEDAL,
+ SEQ_TYPE_STANDARD,
+ ITEM_CLASS_ABSOLUTE,
+ ITEM_MODIFIER_NEG,
+ { diraxis[1][1], diraxis[0][1] });
+ bool const incbutton = add_assignment(
+ assignments,
+ IPT_PEDAL,
+ SEQ_TYPE_INCREMENT,
+ ITEM_CLASS_SWITCH,
+ ITEM_MODIFIER_NONE,
+ { axisitems[SDL_CONTROLLER_AXIS_TRIGGERRIGHT].second, buttonitems[SDL_CONTROLLER_BUTTON_RIGHTSHOULDER] });
+ if (!incbutton)
+ {
+ if (add_assignment(assignments, IPT_PEDAL, SEQ_TYPE_INCREMENT, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, { std::get<0>(numberedbuttons[pedalbutton]) }))
+ ++pedalbutton;
+ }
+ }
+ if (!add_assignment(assignments, IPT_PEDAL2, SEQ_TYPE_STANDARD, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, { axisitems[SDL_CONTROLLER_AXIS_TRIGGERLEFT].first }))
+ {
+ add_assignment(
+ assignments,
+ IPT_PEDAL2,
+ SEQ_TYPE_STANDARD,
+ ITEM_CLASS_ABSOLUTE,
+ ITEM_MODIFIER_POS,
+ { diraxis[1][1], diraxis[0][1] });
+ bool const incbutton = add_assignment(
+ assignments,
+ IPT_PEDAL2,
+ SEQ_TYPE_INCREMENT,
+ ITEM_CLASS_SWITCH,
+ ITEM_MODIFIER_NONE,
+ { axisitems[SDL_CONTROLLER_AXIS_TRIGGERLEFT].second, buttonitems[SDL_CONTROLLER_BUTTON_LEFTSHOULDER] });
+ if (!incbutton)
+ {
+ if (add_assignment(assignments, IPT_PEDAL2, SEQ_TYPE_INCREMENT, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, { std::get<0>(numberedbuttons[pedalbutton]) }))
+ ++pedalbutton;
+ }
+ }
+ add_assignment(assignments, IPT_PEDAL3, SEQ_TYPE_INCREMENT, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, { std::get<0>(numberedbuttons[pedalbutton]) });
+
+ // potentially use thumb sticks and/or D-pad and A/B/X/Y diamond for twin sticks
+ add_twin_stick_assignments(
+ assignments,
+ axisitems[SDL_CONTROLLER_AXIS_LEFTX].first,
+ axisitems[SDL_CONTROLLER_AXIS_LEFTY].first,
+ axisitems[SDL_CONTROLLER_AXIS_RIGHTX].first,
+ axisitems[SDL_CONTROLLER_AXIS_RIGHTY].first,
+ buttonitems[SDL_CONTROLLER_BUTTON_DPAD_LEFT],
+ buttonitems[SDL_CONTROLLER_BUTTON_DPAD_RIGHT],
+ buttonitems[SDL_CONTROLLER_BUTTON_DPAD_UP],
+ buttonitems[SDL_CONTROLLER_BUTTON_DPAD_DOWN],
+ buttonitems[SDL_CONTROLLER_BUTTON_X],
+ buttonitems[SDL_CONTROLLER_BUTTON_B],
+ buttonitems[SDL_CONTROLLER_BUTTON_Y],
+ buttonitems[SDL_CONTROLLER_BUTTON_A]);
+
+ // add assignments for buttons with fixed functions
+ add_button_assignment(assignments, IPT_SELECT, { buttonitems[SDL_CONTROLLER_BUTTON_BACK] });
+ add_button_assignment(assignments, IPT_START, { buttonitems[SDL_CONTROLLER_BUTTON_START] });
+ add_button_assignment(assignments, IPT_UI_MENU, { buttonitems[SDL_CONTROLLER_BUTTON_GUIDE] });
+
+ // the first button is always UI select
+ if (add_button_assignment(assignments, IPT_UI_SELECT, { std::get<0>(numberedbuttons[0]) }))
+ {
+ if (SDL_CONTROLLER_BUTTON_INVALID != std::get<1>(numberedbuttons[0]))
+ buttonitems[std::get<1>(numberedbuttons[0])] = ITEM_ID_INVALID;
+ if (SDL_CONTROLLER_AXIS_INVALID != std::get<2>(numberedbuttons[0]))
+ axisitems[std::get<2>(numberedbuttons[0])].second = ITEM_ID_INVALID;
+ }
+
+ // try to get a matching pair of buttons for previous/next group
+ if (consume_button_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, axisitems[SDL_CONTROLLER_AXIS_TRIGGERLEFT].second, axisitems[SDL_CONTROLLER_AXIS_TRIGGERRIGHT].second))
+ {
+ // took digital triggers
+ }
+ else if (!avoidpaddles && consume_button_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, buttonitems[SDL_CONTROLLER_BUTTON_PADDLE1], buttonitems[SDL_CONTROLLER_BUTTON_PADDLE2]))
+ {
+ // took upper paddles
+ }
+ else if (consume_trigger_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, axisitems[SDL_CONTROLLER_AXIS_TRIGGERLEFT].first, axisitems[SDL_CONTROLLER_AXIS_TRIGGERRIGHT].first))
+ {
+ // took analog triggers
+ }
+ else if (!avoidpaddles && consume_button_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, buttonitems[SDL_CONTROLLER_BUTTON_PADDLE3], buttonitems[SDL_CONTROLLER_BUTTON_PADDLE4]))
+ {
+ // took lower paddles
+ }
+ else if (consume_axis_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, diraxis[1][1]))
+ {
+ // took secondary Y
+ }
+ else if (consume_axis_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, diraxis[1][0]))
+ {
+ // took secondary X
+ }
+
+ // try to get a matching pair of buttons for page up/down
+ if (!avoidpaddles && consume_button_pair(assignments, IPT_UI_PAGE_UP, IPT_UI_PAGE_DOWN, buttonitems[SDL_CONTROLLER_BUTTON_PADDLE1], buttonitems[SDL_CONTROLLER_BUTTON_PADDLE2]))
+ {
+ // took upper paddles
+ }
+ else if (!avoidpaddles && consume_button_pair(assignments, IPT_UI_PAGE_UP, IPT_UI_PAGE_DOWN, buttonitems[SDL_CONTROLLER_BUTTON_PADDLE3], buttonitems[SDL_CONTROLLER_BUTTON_PADDLE4]))
+ {
+ // took lower paddles
+ }
+ else
+ if (consume_trigger_pair(assignments, IPT_UI_PAGE_UP, IPT_UI_PAGE_DOWN, axisitems[SDL_CONTROLLER_AXIS_TRIGGERLEFT].first, axisitems[SDL_CONTROLLER_AXIS_TRIGGERRIGHT].first))
+ {
+ // took analog triggers
+ }
+ else if (consume_axis_pair(assignments, IPT_UI_PAGE_UP, IPT_UI_PAGE_DOWN, diraxis[1][1]))
+ {
+ // took secondary Y
+ }
+
+ // try to assign X button to UI clear
+ if (add_button_assignment(assignments, IPT_UI_CLEAR, { buttonitems[SDL_CONTROLLER_BUTTON_X] }))
+ {
+ buttonitems[SDL_CONTROLLER_BUTTON_X] = ITEM_ID_INVALID;
+ }
+ else
+ {
+ // otherwise try to find an unassigned button
+ for (auto [item, button, axis] : numberedbuttons)
+ {
+ if ((SDL_CONTROLLER_BUTTON_INVALID != button) && (ITEM_ID_INVALID != buttonitems[button]))
+ {
+ add_button_assignment(assignments, IPT_UI_CLEAR, { item });
+ buttonitems[button] = ITEM_ID_INVALID;
+ break;
+ }
+ else if ((SDL_CONTROLLER_AXIS_INVALID != axis) && (ITEM_ID_INVALID != axisitems[axis].second))
+ {
+ add_button_assignment(assignments, IPT_UI_CLEAR, { item });
+ axisitems[axis].second = ITEM_ID_INVALID;
+ break;
+ }
+ }
+ }
+
+ // try to assign B button to UI back
+ if (add_button_assignment(assignments, IPT_UI_BACK, { buttonitems[SDL_CONTROLLER_BUTTON_B] }))
+ {
+ buttonitems[SDL_CONTROLLER_BUTTON_X] = ITEM_ID_INVALID;
+ }
+ else
+ {
+ // otherwise try to find an unassigned button
+ for (auto [item, button, axis] : numberedbuttons)
+ {
+ if ((SDL_CONTROLLER_BUTTON_INVALID != button) && (ITEM_ID_INVALID != buttonitems[button]))
+ {
+ add_button_assignment(assignments, IPT_UI_CLEAR, { item });
+ buttonitems[button] = ITEM_ID_INVALID;
+ break;
+ }
+ else if ((SDL_CONTROLLER_AXIS_INVALID != axis) && (ITEM_ID_INVALID != axisitems[axis].second))
+ {
+ add_button_assignment(assignments, IPT_UI_CLEAR, { item });
+ axisitems[axis].second = ITEM_ID_INVALID;
+ break;
+ }
+ }
+ }
+
+ // try to assign Y button to UI help
+ if (add_button_assignment(assignments, IPT_UI_HELP, { buttonitems[SDL_CONTROLLER_BUTTON_Y] }))
+ {
+ buttonitems[SDL_CONTROLLER_BUTTON_Y] = ITEM_ID_INVALID;
+ }
+ else
+ {
+ // otherwise try to find an unassigned button
+ for (auto [item, button, axis] : numberedbuttons)
+ {
+ if ((SDL_CONTROLLER_BUTTON_INVALID != button) && (ITEM_ID_INVALID != buttonitems[button]))
+ {
+ add_button_assignment(assignments, IPT_UI_HELP, { item });
+ buttonitems[button] = ITEM_ID_INVALID;
+ break;
+ }
+ else if ((SDL_CONTROLLER_AXIS_INVALID != axis) && (ITEM_ID_INVALID != axisitems[axis].second))
+ {
+ add_button_assignment(assignments, IPT_UI_HELP, { item });
+ axisitems[axis].second = ITEM_ID_INVALID;
+ break;
+ }
+ }
+ }
+
+ // put focus previous/next on the shoulder buttons if available - this can be overloaded with zoom
+ if (add_button_pair_assignment(assignments, IPT_UI_FOCUS_PREV, IPT_UI_FOCUS_NEXT, buttonitems[SDL_CONTROLLER_BUTTON_LEFTSHOULDER], buttonitems[SDL_CONTROLLER_BUTTON_RIGHTSHOULDER]))
+ {
+ // took shoulder buttons
+ }
+ else if (add_axis_pair_assignment(assignments, IPT_UI_FOCUS_PREV, IPT_UI_FOCUS_NEXT, diraxis[1][0]))
+ {
+ // took secondary X
+ }
+ else if (add_axis_pair_assignment(assignments, IPT_UI_FOCUS_PREV, IPT_UI_FOCUS_NEXT, diraxis[1][1]))
+ {
+ // took secondary Y
+ }
+
+ // put zoom on the secondary stick if available, or fall back to shoulder buttons
+ if (add_axis_pair_assignment(assignments, IPT_UI_ZOOM_OUT, IPT_UI_ZOOM_IN, diraxis[1][0]))
+ {
+ // took secondary X
+ if (axisitems[SDL_CONTROLLER_AXIS_LEFTX].first == diraxis[1][0])
+ add_button_assignment(assignments, IPT_UI_ZOOM_DEFAULT, { buttonitems[SDL_CONTROLLER_BUTTON_LEFTSTICK] });
+ else if (axisitems[SDL_CONTROLLER_AXIS_RIGHTX].first == diraxis[1][0])
+ add_button_assignment(assignments, IPT_UI_ZOOM_DEFAULT, { buttonitems[SDL_CONTROLLER_BUTTON_RIGHTSTICK] });
+ diraxis[1][0] = ITEM_ID_INVALID;
+ }
+ else if (add_axis_pair_assignment(assignments, IPT_UI_ZOOM_IN, IPT_UI_ZOOM_OUT, diraxis[1][1]))
+ {
+ // took secondary Y
+ if (axisitems[SDL_CONTROLLER_AXIS_LEFTY].first == diraxis[1][1])
+ add_button_assignment(assignments, IPT_UI_ZOOM_DEFAULT, { buttonitems[SDL_CONTROLLER_BUTTON_LEFTSTICK] });
+ else if (axisitems[SDL_CONTROLLER_AXIS_RIGHTY].first == diraxis[1][1])
+ add_button_assignment(assignments, IPT_UI_ZOOM_DEFAULT, { buttonitems[SDL_CONTROLLER_BUTTON_RIGHTSTICK] });
+ diraxis[1][1] = ITEM_ID_INVALID;
+ }
+ else if (consume_button_pair(assignments, IPT_UI_ZOOM_OUT, IPT_UI_ZOOM_IN, buttonitems[SDL_CONTROLLER_BUTTON_LEFTSHOULDER], buttonitems[SDL_CONTROLLER_BUTTON_RIGHTSHOULDER]))
+ {
+ // took shoulder buttons
+ }
+
+ // set default assignments
+ device.set_default_assignments(std::move(assignments));
}
- void exit() override
+ virtual void reset() override
{
- // unsubscribe for events
- sdl_event_manager::instance().unsubscribe(this);
+ sdl_joystick_device_base::reset();
+ clear_buffer();
+ }
+
+ virtual void process_event(SDL_Event const &event) override
+ {
+ if (!m_ctrldevice)
+ return;
+
+ switch (event.type)
+ {
+ case SDL_CONTROLLERAXISMOTION:
+ if (event.caxis.axis < SDL_CONTROLLER_AXIS_MAX)
+ {
+ switch (event.caxis.axis)
+ {
+ case SDL_CONTROLLER_AXIS_TRIGGERLEFT: // MAME wants negative values for triggers
+ case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
+ m_controller.axes[event.caxis.axis] = -normalize_absolute_axis(event.caxis.value, -32'767, 32'767);
+ break;
+ default:
+ m_controller.axes[event.caxis.axis] = normalize_absolute_axis(event.caxis.value, -32'767, 32'767);
+ }
+ }
+ break;
- input_module_base::exit();
+ case SDL_CONTROLLERBUTTONDOWN:
+ case SDL_CONTROLLERBUTTONUP:
+ if (event.cbutton.button < SDL_CONTROLLER_BUTTON_MAX)
+ m_controller.buttons[event.cbutton.button] = (event.cbutton.state == SDL_PRESSED) ? 0x80 : 0x00;
+ break;
+
+ case SDL_CONTROLLERDEVICEREMOVED:
+ osd_printf_verbose("Game Controller: %s [ID %s] disconnected\n", name(), id());
+ clear_instance();
+ clear_buffer();
+ close_device();
+ break;
+ }
}
- void before_poll(running_machine& machine) override
+ void attach_device(SDL_GameController *ctrl)
{
- // Tell the event manager to process events and push them to the devices
- sdl_event_manager::instance().process_events(machine);
+ assert(ctrl);
+ assert(!m_ctrldevice);
+
+ set_instance(SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(ctrl)));
+ m_ctrldevice = ctrl;
+
+ osd_printf_verbose("Game Controller: %s [ID %s] reconnected\n", name(), id());
}
- bool should_poll_devices(running_machine& machine) override
+private:
+ // state information for a game controller
+ struct sdl_controller_state
{
- return sdl_event_manager::instance().has_focus() && input_enabled();
+ s32 axes[SDL_CONTROLLER_AXIS_MAX];
+ s32 buttons[SDL_CONTROLLER_BUTTON_MAX];
+ };
+
+ sdl_controller_state m_controller;
+ SDL_GameController *m_ctrldevice;
+
+ void clear_buffer()
+ {
+ memset(&m_controller, 0, sizeof(m_controller));
}
- void handle_event(SDL_Event &sdlevent) override
+ void close_device()
{
- // By default dispatch event to every device
- devicelist()->for_each_device([&sdlevent](auto device) {
- downcast<sdl_device*>(device)->queue_events(&sdlevent, 1);
- });
+ if (m_ctrldevice)
+ {
+ SDL_GameControllerClose(m_ctrldevice);
+ m_ctrldevice = nullptr;
+ }
}
};
+
//============================================================
-// sdl_keyboard_module
+// sdl_input_module
//============================================================
-class sdl_keyboard_module : public sdl_input_module
+template <typename Info>
+class sdl_input_module :
+ public input_module_impl<Info, sdl_osd_interface>,
+ protected sdl_event_manager::subscriber
{
- keyboard_trans_table * m_key_trans_table;
public:
- sdl_keyboard_module()
- : sdl_input_module(OSD_KEYBOARDINPUT_PROVIDER), m_key_trans_table(nullptr)
+ sdl_input_module(char const *type, char const *name) :
+ input_module_impl<Info, sdl_osd_interface>(type, name)
{
}
- void input_init(running_machine &machine) override
+ virtual void exit() override
{
- sdl_input_module::input_init(machine);
+ // unsubscribe for events
+ unsubscribe();
- static int event_types[] = {
- static_cast<int>(SDL_KEYDOWN),
- static_cast<int>(SDL_KEYUP),
- static_cast<int>(SDL_TEXTINPUT)
- };
+ input_module_impl<Info, sdl_osd_interface>::exit();
+ }
- sdl_event_manager::instance().subscribe(event_types, ARRAY_LENGTH(event_types), this);
+protected:
+ virtual void handle_event(SDL_Event const &event) override
+ {
+ // dispatch event to every device by default
+ this->devicelist().for_each_device(
+ [&event] (auto &device) { device.queue_events(&event, 1); });
+ }
+};
- sdl_keyboard_device *devinfo;
- // Read our keymap and store a pointer to our table
- m_key_trans_table = sdlinput_read_keymap(machine);
+//============================================================
+// sdl_keyboard_module
+//============================================================
- keyboard_trans_table& local_table = *m_key_trans_table;
+class sdl_keyboard_module : public sdl_input_module<sdl_keyboard_device>
+{
+public:
+ sdl_keyboard_module() :
+ sdl_input_module<sdl_keyboard_device>(OSD_KEYBOARDINPUT_PROVIDER, "sdl")
+ {
+ }
- osd_printf_verbose("Keyboard: Start initialization\n");
+ virtual void input_init(running_machine &machine) override
+ {
+ sdl_input_module<sdl_keyboard_device>::input_init(machine);
- // SDL only has 1 keyboard add it now
- devinfo = devicelist()->create_device<sdl_keyboard_device>(machine, "System keyboard", "System keyboard", *this);
+ constexpr int event_types[] = {
+ int(SDL_KEYDOWN),
+ int(SDL_KEYUP) };
- // populate it
- for (int keynum = 0; local_table[keynum].mame_key != ITEM_ID_INVALID; keynum++)
- {
- input_item_id itemid = local_table[keynum].mame_key;
+ subscribe(osd(), event_types);
+
+ // Read our keymap and store a pointer to our table
+ sdlinput_read_keymap();
- // generate the default / modified name
- char defname[20];
- snprintf(defname, sizeof(defname) - 1, "%s", local_table[keynum].ui_name);
+ osd_printf_verbose("Keyboard: Start initialization\n");
- devinfo->device()->add_item(defname, itemid, generic_button_get_state<std::int32_t>, &devinfo->keyboard.state[local_table[keynum].sdl_scancode]);
- }
+ // SDL only has 1 keyboard add it now
+ auto &devinfo = create_device<sdl_keyboard_device>(
+ DEVICE_CLASS_KEYBOARD,
+ "System keyboard",
+ "System keyboard",
+ *m_key_trans_table);
- osd_printf_verbose("Keyboard: Registered %s\n", devinfo->name());
+ osd_printf_verbose("Keyboard: Registered %s\n", devinfo.name());
osd_printf_verbose("Keyboard: End initialization\n");
}
private:
- static keyboard_trans_table* sdlinput_read_keymap(running_machine &machine)
+ void sdlinput_read_keymap()
{
- char *keymap_filename;
- FILE *keymap_file;
- int line = 1;
- int sdl2section = 0;
-
keyboard_trans_table &default_table = keyboard_trans_table::instance();
- if (!machine.options().bool_value(SDLOPTION_KEYMAP))
- return &default_table;
-
- keymap_filename = (char *)downcast<sdl_options &>(machine.options()).keymap_file();
- osd_printf_verbose("Keymap: Start reading keymap_file %s\n", keymap_filename);
-
- keymap_file = fopen(keymap_filename, "r");
- if (keymap_file == nullptr)
- {
- osd_printf_warning("Keymap: Unable to open keymap %s, using default\n", keymap_filename);
- return &default_table;
- }
-
// Allocate a block of translation entries big enough to hold what's in the default table
- auto key_trans_entries = std::make_unique<key_trans_entry[]>(default_table.size());
+ auto key_trans_entries = std::make_unique<key_trans_entry []>(default_table.size());
- // copy the elements from the default table
+ // copy the elements from the default table and ask SDL for key names
for (int i = 0; i < default_table.size(); i++)
+ {
key_trans_entries[i] = default_table[i];
+ char const *const name = SDL_GetScancodeName(SDL_Scancode(default_table[i].sdl_scancode));
+ if (name && *name)
+ key_trans_entries[i].ui_name = name;
+ }
// Allocate the trans table to be associated with the machine so we don't have to free it
- keyboard_trans_table *custom_table = auto_alloc(machine, keyboard_trans_table(std::move(key_trans_entries), default_table.size()));
+ m_key_trans_table = std::make_unique<keyboard_trans_table>(std::move(key_trans_entries), default_table.size());
+
+ if (!options()->bool_value(SDLOPTION_KEYMAP))
+ return;
+
+ const char *const keymap_filename = dynamic_cast<sdl_options const &>(*options()).keymap_file();
+ osd_printf_verbose("Keymap: Start reading keymap_file %s\n", keymap_filename);
+
+ FILE *const keymap_file = fopen(keymap_filename, "r");
+ if (!keymap_file)
+ {
+ osd_printf_warning("Keymap: Unable to open keymap %s, using default\n", keymap_filename);
+ return;
+ }
+ int line = 1;
+ int sdl2section = 0;
while (!feof(keymap_file))
{
char buf[256];
@@ -864,34 +2266,36 @@ private:
if (sk >= 0 && index >= 0)
{
- key_trans_entry &entry = (*custom_table)[index];
+ key_trans_entry &entry = (*m_key_trans_table)[index];
entry.sdl_scancode = sk;
- entry.ui_name = auto_alloc_array(machine, char, strlen(kns) + 1);
- strcpy(entry.ui_name, kns);
+ entry.ui_name = const_cast<char *>(m_ui_names.emplace_back(kns).c_str());
osd_printf_verbose("Keymap: Mapped <%s> to <%s> with ui-text <%s>\n", sks, mks, kns);
}
else
+ {
osd_printf_error("Keymap: Error on line %d - %s key not found: %s\n", line, (sk<0) ? "sdl" : "mame", buf);
+ }
}
}
line++;
}
fclose(keymap_file);
osd_printf_verbose("Keymap: Processed %d lines\n", line);
-
- return custom_table;
}
+
+ std::unique_ptr<keyboard_trans_table> m_key_trans_table;
+ std::list<std::string> m_ui_names;
};
+
//============================================================
// sdl_mouse_module
//============================================================
-class sdl_mouse_module : public sdl_input_module
+class sdl_mouse_module : public sdl_input_module<sdl_mouse_device>
{
public:
- sdl_mouse_module()
- : sdl_input_module(OSD_MOUSEINPUT_PROVIDER)
+ sdl_mouse_module() : sdl_input_module<sdl_mouse_device>(OSD_MOUSEINPUT_PROVIDER, "sdl")
{
}
@@ -899,285 +2303,578 @@ public:
{
sdl_input_module::input_init(machine);
- static int event_types[] = {
- static_cast<int>(SDL_MOUSEMOTION),
- static_cast<int>(SDL_MOUSEBUTTONDOWN),
- static_cast<int>(SDL_MOUSEBUTTONUP),
- static_cast<int>(SDL_MOUSEWHEEL)
- };
-
- sdl_event_manager::instance().subscribe(event_types, ARRAY_LENGTH(event_types), this);
+ constexpr int event_types[] = {
+ int(SDL_MOUSEMOTION),
+ int(SDL_MOUSEBUTTONDOWN),
+ int(SDL_MOUSEBUTTONUP),
+ int(SDL_MOUSEWHEEL) };
- sdl_mouse_device *devinfo;
- char defname[20];
- int button;
+ subscribe(osd(), event_types);
osd_printf_verbose("Mouse: Start initialization\n");
// SDL currently only supports one mouse
- devinfo = devicelist()->create_device<sdl_mouse_device>(machine, "System mouse", "System mouse", *this);
-
- // add the axes
- devinfo->device()->add_item("X", ITEM_ID_XAXIS, generic_axis_get_state<std::int32_t>, &devinfo->mouse.lX);
- devinfo->device()->add_item("Y", ITEM_ID_YAXIS, generic_axis_get_state<std::int32_t>, &devinfo->mouse.lY);
+ auto &devinfo = create_device<sdl_mouse_device>(
+ DEVICE_CLASS_MOUSE,
+ "System mouse",
+ "System mouse");
- for (button = 0; button < 4; button++)
- {
- input_item_id itemid = (input_item_id)(ITEM_ID_BUTTON1 + button);
- snprintf(defname, sizeof(defname), "B%d", button + 1);
-
- devinfo->device()->add_item(defname, itemid, generic_button_get_state<std::int32_t>, &devinfo->mouse.buttons[button]);
- }
-
- osd_printf_verbose("Mouse: Registered %s\n", devinfo->name());
+ osd_printf_verbose("Mouse: Registered %s\n", devinfo.name());
osd_printf_verbose("Mouse: End initialization\n");
}
};
-static void devmap_register(device_map_t &devmap, int physical_idx, const std::string &name)
-{
- // Attempt to find the entry by name
- auto entry = std::find_if(std::begin(devmap.map), std::end(devmap.map), [&name](auto &item)
- {
- return item.name == name && item.physical < 0;
- });
+//============================================================
+// sdl_lightgun_module
+//============================================================
- // If we didn't find it by name, find the first free slot
- if (entry == std::end(devmap.map))
+class sdl_lightgun_module : public sdl_input_module<sdl_mouse_device_base>
+{
+public:
+ sdl_lightgun_module() : sdl_input_module<sdl_mouse_device_base>(OSD_LIGHTGUNINPUT_PROVIDER, "sdl")
{
- entry = std::find_if(std::begin(devmap.map), std::end(devmap.map), [](auto &item) { return item.name.empty(); });
}
- if (entry != std::end(devmap.map))
+ virtual void input_init(running_machine &machine) override
{
- entry->physical = physical_idx;
- entry->name = name;
- int logical_idx = std::distance(std::begin(devmap.map), entry);
- devmap.logical[physical_idx] = logical_idx;
+ auto &sdlopts = dynamic_cast<sdl_options const &>(*options());
+ sdl_input_module::input_init(machine);
+ bool const dual(sdlopts.dual_lightgun());
+
+ if (!dual)
+ {
+ constexpr int event_types[] = {
+ int(SDL_MOUSEMOTION),
+ int(SDL_MOUSEBUTTONDOWN),
+ int(SDL_MOUSEBUTTONUP),
+ int(SDL_MOUSEWHEEL),
+ int(SDL_WINDOWEVENT) };
+ subscribe(osd(), event_types);
+ }
+ else
+ {
+ constexpr int event_types[] = {
+ int(SDL_MOUSEBUTTONDOWN),
+ int(SDL_MOUSEBUTTONUP) };
+ subscribe(osd(), event_types);
+ }
+
+ osd_printf_verbose("Lightgun: Start initialization\n");
+
+ if (!dual)
+ {
+ auto &devinfo = create_device<sdl_lightgun_device>(
+ DEVICE_CLASS_LIGHTGUN,
+ "System pointer gun 1",
+ "System pointer gun 1");
+ osd_printf_verbose("Lightgun: Registered %s\n", devinfo.name());
+ }
+ else
+ {
+ auto &dev1info = create_device<sdl_dual_lightgun_device>(
+ DEVICE_CLASS_LIGHTGUN,
+ "System pointer gun 1",
+ "System pointer gun 1",
+ 0);
+ osd_printf_verbose("Lightgun: Registered %s\n", dev1info.name());
+
+ auto &dev2info = create_device<sdl_dual_lightgun_device>(
+ DEVICE_CLASS_LIGHTGUN,
+ "System pointer gun 2",
+ "System pointer gun 2",
+ 1);
+ osd_printf_verbose("Lightgun: Registered %s\n", dev2info.name());
+ }
+
+ osd_printf_verbose("Lightgun: End initialization\n");
}
-}
+};
+
//============================================================
-// sdl_joystick_module
+// sdl_joystick_module_base
//============================================================
-class sdl_joystick_module : public sdl_input_module
+class sdl_joystick_module_base : public sdl_input_module<sdl_joystick_device_base>
{
-private:
- device_map_t m_joy_map;
- bool m_initialized_joystick;
- bool m_initialized_haptic;
- bool m_sixaxis_mode;
-public:
- sdl_joystick_module()
- : sdl_input_module(OSD_JOYSTICKINPUT_PROVIDER), m_initialized_joystick(false), m_initialized_haptic(false), m_sixaxis_mode(false)
+protected:
+ sdl_joystick_module_base(char const *name) :
+ sdl_input_module<sdl_joystick_device_base>(OSD_JOYSTICKINPUT_PROVIDER, name),
+ m_initialized_joystick(false),
+ m_initialized_haptic(false)
{
}
- virtual void exit() override
+ virtual ~sdl_joystick_module_base()
+ {
+ assert(!m_initialized_joystick);
+ assert(!m_initialized_haptic);
+ }
+
+ bool have_joystick() const { return m_initialized_joystick; }
+ bool have_haptic() const { return m_initialized_haptic; }
+
+ void init_joystick()
{
- sdl_input_module::exit();
+ assert(!m_initialized_joystick);
+ assert(!m_initialized_haptic);
+
+ m_initialized_joystick = !SDL_InitSubSystem(SDL_INIT_JOYSTICK);
+ if (!m_initialized_joystick)
+ {
+ osd_printf_error("Could not initialize SDL Joystick subsystem: %s.\n", SDL_GetError());
+ return;
+ }
+ m_initialized_haptic = !SDL_InitSubSystem(SDL_INIT_HAPTIC);
+ if (!m_initialized_haptic)
+ osd_printf_verbose("Could not initialize SDL Haptic subsystem: %s.\n", SDL_GetError());
+ }
+
+ void quit_joystick()
+ {
if (m_initialized_joystick)
{
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
+ m_initialized_joystick = false;
}
if (m_initialized_haptic)
{
SDL_QuitSubSystem(SDL_INIT_HAPTIC);
+ m_initialized_haptic = false;
}
}
- virtual void input_init(running_machine &machine) override
+ sdl_joystick_device *create_joystick_device(int index, bool sixaxis)
{
- SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
-
- m_initialized_joystick = !SDL_InitSubSystem(SDL_INIT_JOYSTICK);
- if (!m_initialized_joystick)
+ // open the joystick device
+ SDL_Joystick *const joy = SDL_JoystickOpen(index);
+ if (!joy)
{
- osd_printf_error("Could not initialize SDL Joystick: %s.\n", SDL_GetError());
- return;
+ osd_printf_error("Joystick: Could not open SDL joystick %d: %s.\n", index, SDL_GetError());
+ return nullptr;
}
- m_initialized_haptic = !SDL_InitSubSystem(SDL_INIT_HAPTIC);
- if (!m_initialized_haptic)
+ // get basic info
+ char const *const name = SDL_JoystickName(joy);
+ SDL_JoystickGUID guid = SDL_JoystickGetGUID(joy);
+ char guid_str[256];
+ guid_str[0] = '\0';
+ SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str) - 1);
+ char const *const serial = SDL_JoystickGetSerial(joy);
+ std::string id(guid_str);
+ if (serial)
+ id.append(1, '-').append(serial);
+
+ // print some diagnostic info
+ osd_printf_verbose("Joystick: %s [GUID %s] Vendor ID %04X, Product ID %04X, Revision %04X, Serial %s\n",
+ name ? name : "<nullptr>",
+ guid_str,
+ SDL_JoystickGetVendor(joy),
+ SDL_JoystickGetProduct(joy),
+ SDL_JoystickGetProductVersion(joy),
+ serial ? serial : "<nullptr>");
+ osd_printf_verbose("Joystick: ... %d axes, %d buttons %d hats %d balls\n",
+ SDL_JoystickNumAxes(joy),
+ SDL_JoystickNumButtons(joy),
+ SDL_JoystickNumHats(joy),
+ SDL_JoystickNumBalls(joy));
+ if (SDL_JoystickNumButtons(joy) > MAX_BUTTONS)
+ osd_printf_verbose("Joystick: ... Has %d buttons which exceeds supported %d buttons\n", SDL_JoystickNumButtons(joy), MAX_BUTTONS);
+
+ // instantiate device
+ sdl_joystick_device &devinfo = sixaxis
+ ? create_device<sdl_sixaxis_joystick_device>(DEVICE_CLASS_JOYSTICK, name ? name : guid_str, guid_str, joy, serial)
+ : create_device<sdl_joystick_device>(DEVICE_CLASS_JOYSTICK, name ? name : guid_str, guid_str, joy, serial);
+
+ if (devinfo.has_haptic())
+ osd_printf_verbose("Joystick: ... Has haptic capability\n");
+ else
+ osd_printf_verbose("Joystick: ... Does not have haptic capability\n");
+
+ return &devinfo;
+ }
+
+ void dispatch_joystick_event(SDL_Event const &event)
+ {
+ // figure out which joystick this event is destined for
+ sdl_joystick_device_base *const target_device = find_joystick(event.jdevice.which); // FIXME: this depends on SDL_JoystickID being the same size as Sint32
+
+ // if we find a matching joystick, dispatch the event to the joystick
+ if (target_device)
+ target_device->queue_events(&event, 1);
+ }
+
+ device_info *find_reconnect_match(SDL_JoystickGUID const &guid, char const *serial)
+ {
+ char guid_str[256];
+ guid_str[0] = '\0';
+ SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str) - 1);
+ auto target_device = std::find_if(
+ devicelist().begin(),
+ devicelist().end(),
+ [&guid_str, &serial] (auto const &device)
+ {
+ return device->reconnect_match(guid_str, serial);
+ });
+ return (devicelist().end() != target_device) ? target_device->get() : nullptr;
+ }
+
+ sdl_joystick_device_base *find_joystick(SDL_JoystickID instance)
+ {
+ for (auto &device : devicelist())
{
- osd_printf_verbose("Could not initialize SDL Haptic subsystem: %s.\n", SDL_GetError());
+ if (device->is_instance(instance))
+ return device.get();
}
+ return nullptr;
+ }
- sdl_input_module::input_init(machine);
+private:
+ bool m_initialized_joystick;
+ bool m_initialized_haptic;
+};
+
+
+//============================================================
+// sdl_joystick_module
+//============================================================
+
+class sdl_joystick_module : public sdl_joystick_module_base
+{
+public:
+ sdl_joystick_module() : sdl_joystick_module_base("sdljoy")
+ {
+ }
- char tempname[512];
+ virtual void exit() override
+ {
+ sdl_joystick_module_base::exit();
- m_sixaxis_mode = downcast<const sdl_options*>(options())->sixaxis();
+ quit_joystick();
+ }
- devmap_init(machine, &m_joy_map, SDLOPTION_JOYINDEX, 8, "Joystick mapping");
+ virtual void input_init(running_machine &machine) override
+ {
+ auto &sdlopts = dynamic_cast<sdl_options const &>(*options());
+ bool const sixaxis_mode = sdlopts.sixaxis();
- osd_printf_verbose("Joystick: Start initialization\n");
- int physical_stick;
- for (physical_stick = 0; physical_stick < SDL_NumJoysticks(); physical_stick++)
- {
- std::string joy_name = remove_spaces(SDL_JoystickNameForIndex(physical_stick));
- devmap_register(m_joy_map, physical_stick, joy_name);
- }
+ if (!sdlopts.debug() && sdlopts.background_input())
+ SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
+ SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
- for (int stick = 0; stick < MAX_DEVMAP_ENTRIES; stick++)
- {
- sdl_joystick_device *devinfo = create_joystick_device(machine, &m_joy_map, stick, DEVICE_CLASS_JOYSTICK);
+ init_joystick();
+ if (!have_joystick())
+ return;
- if (devinfo == nullptr)
- continue;
+ sdl_joystick_module_base::input_init(machine);
- physical_stick = m_joy_map.map[stick].physical;
- SDL_Joystick *joy = SDL_JoystickOpen(physical_stick);
- devinfo->sdl_state.device = joy;
- devinfo->sdl_state.joystick_id = SDL_JoystickInstanceID(joy);
- devinfo->sdl_state.hapdevice = SDL_HapticOpenFromJoystick(joy);
+ osd_printf_verbose("Joystick: Start initialization\n");
+ for (int physical_stick = 0; physical_stick < SDL_NumJoysticks(); physical_stick++)
+ create_joystick_device(physical_stick, sixaxis_mode);
+
+ constexpr int event_types[] = {
+ int(SDL_JOYAXISMOTION),
+ int(SDL_JOYBALLMOTION),
+ int(SDL_JOYHATMOTION),
+ int(SDL_JOYBUTTONDOWN),
+ int(SDL_JOYBUTTONUP),
+ int(SDL_JOYDEVICEADDED),
+ int(SDL_JOYDEVICEREMOVED) };
+ subscribe(osd(), event_types);
- osd_printf_verbose("Joystick: %s\n", SDL_JoystickNameForIndex(physical_stick));
- osd_printf_verbose("Joystick: ... %d axes, %d buttons %d hats %d balls\n", SDL_JoystickNumAxes(joy), SDL_JoystickNumButtons(joy), SDL_JoystickNumHats(joy), SDL_JoystickNumBalls(joy));
- osd_printf_verbose("Joystick: ... Physical id %d mapped to logical id %d\n", physical_stick, stick + 1);
- if (devinfo->sdl_state.hapdevice != nullptr)
+ osd_printf_verbose("Joystick: End initialization\n");
+ }
+
+ virtual void handle_event(SDL_Event const &event) override
+ {
+ if (SDL_JOYDEVICEADDED == event.type)
+ {
+ SDL_Joystick *const joy = SDL_JoystickOpen(event.jdevice.which);
+ if (!joy)
{
- osd_printf_verbose("Joystick: ... Has haptic capability\n");
+ osd_printf_error("Joystick: Could not open SDL joystick %d: %s.\n", event.jdevice.which, SDL_GetError());
}
else
{
- osd_printf_verbose("Joystick: ... Does not have haptic capability\n");
+ SDL_JoystickGUID guid = SDL_JoystickGetGUID(joy);
+ char const *const serial = SDL_JoystickGetSerial(joy);
+ auto *const target_device = find_reconnect_match(guid, serial);
+ if (target_device)
+ {
+ auto &devinfo = dynamic_cast<sdl_joystick_device &>(*target_device);
+ devinfo.attach_device(joy);
+ }
+ else
+ {
+ SDL_JoystickClose(joy);
+ }
}
+ }
+ else
+ {
+ dispatch_joystick_event(event);
+ }
+ }
+};
- // loop over all axes
- for (int axis = 0; axis < SDL_JoystickNumAxes(joy); axis++)
- {
- input_item_id itemid;
- if (axis < INPUT_MAX_AXIS)
- itemid = (input_item_id)(ITEM_ID_XAXIS + axis);
- else if (axis < INPUT_MAX_AXIS + INPUT_MAX_ADD_ABSOLUTE)
- itemid = (input_item_id)(ITEM_ID_ADD_ABSOLUTE1 - INPUT_MAX_AXIS + axis);
- else
- itemid = ITEM_ID_OTHER_AXIS_ABSOLUTE;
+//============================================================
+// sdl_game_controller_module
+//============================================================
- snprintf(tempname, sizeof(tempname), "A%d %s", axis, devinfo->name());
- devinfo->device()->add_item(tempname, itemid, generic_axis_get_state<std::int32_t>, &devinfo->joystick.axes[axis]);
- }
+class sdl_game_controller_module : public sdl_joystick_module_base
+{
+public:
+ sdl_game_controller_module() :
+ sdl_joystick_module_base("sdlgame"),
+ m_initialized_game_controller(false)
+ {
+ }
- // loop over all buttons
- for (int button = 0; button < SDL_JoystickNumButtons(joy); button++)
- {
- input_item_id itemid;
+ virtual void exit() override
+ {
+ sdl_joystick_module_base::exit();
- devinfo->joystick.buttons[button] = 0;
+ if (m_initialized_game_controller)
+ SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
- if (button < INPUT_MAX_BUTTONS)
- itemid = (input_item_id)(ITEM_ID_BUTTON1 + button);
- else if (button < INPUT_MAX_BUTTONS + INPUT_MAX_ADD_SWITCH)
- itemid = (input_item_id)(ITEM_ID_ADD_SWITCH1 - INPUT_MAX_BUTTONS + button);
- else
- itemid = ITEM_ID_OTHER_SWITCH;
+ quit_joystick();
+ }
- snprintf(tempname, sizeof(tempname), "button %d", button);
- devinfo->device()->add_item(tempname, itemid, generic_button_get_state<std::int32_t>, &devinfo->joystick.buttons[button]);
- }
+ virtual void input_init(running_machine &machine) override
+ {
+ auto &sdlopts = dynamic_cast<sdl_options const &>(*options());
+ bool const sixaxis_mode = sdlopts.sixaxis();
- // loop over all hats
- for (int hat = 0; hat < SDL_JoystickNumHats(joy); hat++)
- {
- input_item_id itemid;
-
- snprintf(tempname, sizeof(tempname), "hat %d Up", hat);
- itemid = (input_item_id)((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1UP + 4 * hat : ITEM_ID_OTHER_SWITCH);
- devinfo->device()->add_item(tempname, itemid, generic_button_get_state<std::int32_t>, &devinfo->joystick.hatsU[hat]);
- snprintf(tempname, sizeof(tempname), "hat %d Down", hat);
- itemid = (input_item_id)((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1DOWN + 4 * hat : ITEM_ID_OTHER_SWITCH);
- devinfo->device()->add_item(tempname, itemid, generic_button_get_state<std::int32_t>, &devinfo->joystick.hatsD[hat]);
- snprintf(tempname, sizeof(tempname), "hat %d Left", hat);
- itemid = (input_item_id)((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1LEFT + 4 * hat : ITEM_ID_OTHER_SWITCH);
- devinfo->device()->add_item(tempname, itemid, generic_button_get_state<std::int32_t>, &devinfo->joystick.hatsL[hat]);
- snprintf(tempname, sizeof(tempname), "hat %d Right", hat);
- itemid = (input_item_id)((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1RIGHT + 4 * hat : ITEM_ID_OTHER_SWITCH);
- devinfo->device()->add_item(tempname, itemid, generic_button_get_state<std::int32_t>, &devinfo->joystick.hatsR[hat]);
- }
+ if (!sdlopts.debug() && sdlopts.background_input())
+ SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
+ SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
- // loop over all (track)balls
- for (int ball = 0; ball < SDL_JoystickNumBalls(joy); ball++)
- {
- int itemid;
+ init_joystick();
+ if (!have_joystick())
+ return;
- if (ball * 2 < INPUT_MAX_ADD_RELATIVE)
- itemid = ITEM_ID_ADD_RELATIVE1 + ball * 2;
+ m_initialized_game_controller = !SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER);
+ if (m_initialized_game_controller)
+ {
+ char const *const mapfile = sdlopts.controller_mapping_file();
+ if (mapfile && *mapfile && std::strcmp(mapfile, OSDOPTVAL_NONE))
+ {
+ auto const count = SDL_GameControllerAddMappingsFromFile(mapfile);
+ if (0 <= count)
+ osd_printf_verbose("Game Controller: %d controller mapping(s) added from file [%s].\n", count, mapfile);
else
- itemid = ITEM_ID_OTHER_AXIS_RELATIVE;
-
- snprintf(tempname, sizeof(tempname), "R%d %s", ball * 2, devinfo->name());
- devinfo->device()->add_item(tempname, (input_item_id)itemid, generic_axis_get_state<std::int32_t>, &devinfo->joystick.balls[ball * 2]);
- snprintf(tempname, sizeof(tempname), "R%d %s", ball * 2 + 1, devinfo->name());
- devinfo->device()->add_item(tempname, (input_item_id)(itemid + 1), generic_axis_get_state<std::int32_t>, &devinfo->joystick.balls[ball * 2 + 1]);
+ osd_printf_error("Game Controller: Error adding mappings from file [%s]: %s.\n", mapfile, SDL_GetError());
}
}
+ else
+ {
+ osd_printf_warning("Could not initialize SDL Game Controller: %s.\n", SDL_GetError());
+ }
- static int event_types[] = {
- static_cast<int>(SDL_JOYAXISMOTION),
- static_cast<int>(SDL_JOYBALLMOTION),
- static_cast<int>(SDL_JOYHATMOTION),
- static_cast<int>(SDL_JOYBUTTONDOWN),
- static_cast<int>(SDL_JOYBUTTONUP)
- };
+ sdl_joystick_module_base::input_init(machine);
- sdl_event_manager::instance().subscribe(event_types, ARRAY_LENGTH(event_types), this);
+ osd_printf_verbose("Game Controller: Start initialization\n");
+ for (int physical_stick = 0; physical_stick < SDL_NumJoysticks(); physical_stick++)
+ {
+ // try to open as a game controller
+ SDL_GameController *ctrl = nullptr;
+ if (m_initialized_game_controller && SDL_IsGameController(physical_stick))
+ {
+ ctrl = SDL_GameControllerOpen(physical_stick);
+ if (!ctrl)
+ osd_printf_warning("Game Controller: Could not open SDL game controller %d: %s.\n", physical_stick, SDL_GetError());
+ }
- osd_printf_verbose("Joystick: End initialization\n");
+ // fall back to joystick API if necessary
+ if (!ctrl)
+ create_joystick_device(physical_stick, sixaxis_mode);
+ else
+ create_game_controller_device(physical_stick, ctrl);
+ }
+
+ constexpr int joy_event_types[] = {
+ int(SDL_JOYAXISMOTION),
+ int(SDL_JOYBALLMOTION),
+ int(SDL_JOYHATMOTION),
+ int(SDL_JOYBUTTONDOWN),
+ int(SDL_JOYBUTTONUP),
+ int(SDL_JOYDEVICEADDED),
+ int(SDL_JOYDEVICEREMOVED) };
+ constexpr int event_types[] = {
+ int(SDL_JOYAXISMOTION),
+ int(SDL_JOYBALLMOTION),
+ int(SDL_JOYHATMOTION),
+ int(SDL_JOYBUTTONDOWN),
+ int(SDL_JOYBUTTONUP),
+ int(SDL_JOYDEVICEADDED),
+ int(SDL_JOYDEVICEREMOVED),
+ int(SDL_CONTROLLERAXISMOTION),
+ int(SDL_CONTROLLERBUTTONDOWN),
+ int(SDL_CONTROLLERBUTTONUP),
+ int(SDL_CONTROLLERDEVICEADDED),
+ int(SDL_CONTROLLERDEVICEREMOVED) };
+ if (m_initialized_game_controller)
+ subscribe(osd(), event_types);
+ else
+ subscribe(osd(), joy_event_types);
+
+ osd_printf_verbose("Game Controller: End initialization\n");
}
- virtual void handle_event(SDL_Event &sdlevent) override
+ virtual void handle_event(SDL_Event const &event) override
{
- // Figure out which joystick this event id destined for
- auto target_device = std::find_if(devicelist()->begin(), devicelist()->end(), [&sdlevent](auto &device)
+ switch (event.type)
{
- std::unique_ptr<device_info> &ptr = device;
- return downcast<sdl_joystick_device*>(ptr.get())->sdl_state.joystick_id == sdlevent.jdevice.which;
- });
+ case SDL_JOYDEVICEADDED:
+ {
+ // make sure this isn't an event for a reconnected game controller
+ auto const controller = find_joystick(SDL_JoystickGetDeviceInstanceID(event.jdevice.which));
+ if (find_joystick(SDL_JoystickGetDeviceInstanceID(event.jdevice.which)))
+ {
+ osd_printf_verbose(
+ "Game Controller: Got SDL joystick added event for reconnected game controller %s [ID %s]\n",
+ controller->name(),
+ controller->id());
+ break;
+ }
- // If we find a matching joystick, dispatch the event to the joystick
- if (target_device != devicelist()->end())
- {
- downcast<sdl_joystick_device*>((*target_device).get())->queue_events(&sdlevent, 1);
+ SDL_Joystick *const joy = SDL_JoystickOpen(event.jdevice.which);
+ if (!joy)
+ {
+ osd_printf_error("Joystick: Could not open SDL joystick %d: %s.\n", event.jdevice.which, SDL_GetError());
+ break;
+ }
+
+ SDL_JoystickGUID guid = SDL_JoystickGetGUID(joy);
+ char const *const serial = SDL_JoystickGetSerial(joy);
+ auto *const target_device = find_reconnect_match(guid, serial);
+ if (target_device)
+ {
+ // if this downcast fails, opening as a game controller worked initially but failed on reconnection
+ auto *const devinfo = dynamic_cast<sdl_joystick_device *>(target_device);
+ if (devinfo)
+ devinfo->attach_device(joy);
+ else
+ SDL_JoystickClose(joy);
+ }
+ else
+ {
+ SDL_JoystickClose(joy);
+ }
+ }
+ break;
+
+ // for devices supported by the game controller API, this is received before the corresponding SDL_JOYDEVICEADDED
+ case SDL_CONTROLLERDEVICEADDED:
+ if (m_initialized_game_controller)
+ {
+ SDL_GameController *const ctrl = SDL_GameControllerOpen(event.cdevice.which);
+ if (!ctrl)
+ {
+ osd_printf_error("Game Controller: Could not open SDL game controller %d: %s.\n", event.cdevice.which, SDL_GetError());
+ break;
+ }
+
+ SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(event.cdevice.which);
+ char const *const serial = SDL_GameControllerGetSerial(ctrl);
+ auto *const target_device = find_reconnect_match(guid, serial);
+ if (target_device)
+ {
+ // downcast can fail if there was an error opening the device as a game controller the first time
+ auto *const devinfo = dynamic_cast<sdl_game_controller_device *>(target_device);
+ if (devinfo)
+ devinfo->attach_device(ctrl);
+ else
+ SDL_GameControllerClose(ctrl);
+ }
+ else
+ {
+ SDL_GameControllerClose(ctrl);
+ }
+ }
+ break;
+
+ default:
+ dispatch_joystick_event(event);
}
}
private:
- sdl_joystick_device* create_joystick_device(running_machine &machine, device_map_t *devmap, int index, input_device_class devclass)
+ sdl_game_controller_device *create_game_controller_device(int index, SDL_GameController *ctrl)
{
- char tempname[20];
-
- if (devmap->map[index].name.empty())
+ // get basic info
+ char const *const name = SDL_GameControllerName(ctrl);
+ SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(index);
+ char guid_str[256];
+ guid_str[0] = '\0';
+ SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str) - 1);
+ char const *const serial = SDL_GameControllerGetSerial(ctrl);
+ std::string id(guid_str);
+ if (serial)
+ id.append(1, '-').append(serial);
+
+ // print some diagnostic info
+ osd_printf_verbose("Game Controller: %s [GUID %s] Vendor ID %04X, Product ID %04X, Revision %04X, Serial %s\n",
+ name ? name : "<nullptr>",
+ guid_str,
+ SDL_GameControllerGetVendor(ctrl),
+ SDL_GameControllerGetProduct(ctrl),
+ SDL_GameControllerGetProductVersion(ctrl),
+ serial ? serial : "<nullptr>");
+ char *const mapping = SDL_GameControllerMapping(ctrl);
+ if (mapping)
{
- // only map place holders if there were mappings specified
- if (devmap->initialized)
- {
- snprintf(tempname, ARRAY_LENGTH(tempname), "NC%d", index);
- m_sixaxis_mode
- ? devicelist()->create_device<sdl_sixaxis_joystick_device>(machine, tempname, tempname, *this)
- : devicelist()->create_device<sdl_joystick_device>(machine, tempname, tempname, *this);
- }
-
- return nullptr;
+ osd_printf_verbose("Game Controller: ... mapping [%s]\n", mapping);
+ SDL_free(mapping);
+ }
+ else
+ {
+ osd_printf_verbose("Game Controller: ... no mapping\n");
}
- return m_sixaxis_mode
- ? devicelist()->create_device<sdl_sixaxis_joystick_device>(machine, devmap->map[index].name.c_str(), devmap->map[index].name.c_str(), *this)
- : devicelist()->create_device<sdl_joystick_device>(machine, devmap->map[index].name.c_str(), devmap->map[index].name.c_str(), *this);
+ // instantiate device
+ sdl_game_controller_device &devinfo = create_device<sdl_game_controller_device>(
+ DEVICE_CLASS_JOYSTICK,
+ name ? name : guid_str,
+ guid_str,
+ ctrl,
+ serial);
+ return &devinfo;
}
+
+ bool m_initialized_game_controller;
};
-#else
+} // anonymous namespace
+
+} // namespace osd
+
+
+#else // defined(SDLMAME_SDL2)
+
+namespace osd {
+
+namespace {
+
MODULE_NOT_SUPPORTED(sdl_keyboard_module, OSD_KEYBOARDINPUT_PROVIDER, "sdl")
MODULE_NOT_SUPPORTED(sdl_mouse_module, OSD_MOUSEINPUT_PROVIDER, "sdl")
-MODULE_NOT_SUPPORTED(sdl_joystick_module, OSD_JOYSTICKINPUT_PROVIDER, "sdl")
-#endif
+MODULE_NOT_SUPPORTED(sdl_lightgun_module, OSD_LIGHTGUNINPUT_PROVIDER, "sdl")
+MODULE_NOT_SUPPORTED(sdl_joystick_module, OSD_JOYSTICKINPUT_PROVIDER, "sdljoy")
+MODULE_NOT_SUPPORTED(sdl_game_controller_module, OSD_JOYSTICKINPUT_PROVIDER, "sdlgame")
+
+} // anonymous namespace
+
+} // namespace osd
+
+#endif // defined(SDLMAME_SDL2)
+
-MODULE_DEFINITION(KEYBOARDINPUT_SDL, sdl_keyboard_module)
-MODULE_DEFINITION(MOUSEINPUT_SDL, sdl_mouse_module)
-MODULE_DEFINITION(JOYSTICKINPUT_SDL, sdl_joystick_module)
+MODULE_DEFINITION(KEYBOARDINPUT_SDL, osd::sdl_keyboard_module)
+MODULE_DEFINITION(MOUSEINPUT_SDL, osd::sdl_mouse_module)
+MODULE_DEFINITION(LIGHTGUNINPUT_SDL, osd::sdl_lightgun_module)
+MODULE_DEFINITION(JOYSTICKINPUT_SDLJOY, osd::sdl_joystick_module)
+MODULE_DEFINITION(JOYSTICKINPUT_SDLGAME, osd::sdl_game_controller_module)
diff --git a/src/osd/modules/input/input_sdlcommon.cpp b/src/osd/modules/input/input_sdlcommon.cpp
deleted file mode 100644
index a5982ea891d..00000000000
--- a/src/osd/modules/input/input_sdlcommon.cpp
+++ /dev/null
@@ -1,318 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes
-//============================================================
-//
-// input_sdlcommon.cpp - SDL Common code shared by SDL modules
-//
-// Note: this code is also used by the X11 input modules
-//
-//============================================================
-
-#include "input_module.h"
-#include "modules/osdmodule.h"
-
-#if defined(OSD_SDL)
-
-// standard sdl header
-#include <SDL2/SDL.h>
-#include <ctype.h>
-#include <stddef.h>
-#include <mutex>
-#include <memory>
-#include <algorithm>
-
-// MAME headers
-#include "emu.h"
-#include "osdepend.h"
-#include "ui/uimain.h"
-#include "uiinput.h"
-#include "window.h"
-#include "strconv.h"
-
-#include "../../sdl/osdsdl.h"
-#include "input_common.h"
-#include "input_sdlcommon.h"
-
-#define GET_WINDOW(ev) window_from_id((ev)->windowID)
-//#define GET_WINDOW(ev) ((ev)->windowID)
-
-static std::shared_ptr<sdl_window_info> window_from_id(Uint32 windowID)
-{
- SDL_Window *sdl_window = SDL_GetWindowFromID(windowID);
-
- auto& windows = osd_common_t::s_window_list;
- auto window = std::find_if(windows.begin(), windows.end(), [sdl_window](std::shared_ptr<osd_window> w)
- {
- return std::static_pointer_cast<sdl_window_info>(w)->platform_window() == sdl_window;
- });
-
- if (window == windows.end())
- return nullptr;
-
- return std::static_pointer_cast<sdl_window_info>(*window);
-}
-
-void sdl_event_manager::process_events(running_machine &machine)
-{
- std::lock_guard<std::mutex> scope_lock(m_lock);
- SDL_Event sdlevent;
- while (SDL_PollEvent(&sdlevent))
- {
- // process window events if they come in
- if (sdlevent.type == SDL_WINDOWEVENT)
- process_window_event(machine, sdlevent);
-
- // Find all subscribers for the event type
- auto subscribers = m_subscription_index.equal_range(sdlevent.type);
-
- // Dispatch the events
- std::for_each(subscribers.first, subscribers.second, [&sdlevent](auto sub)
- {
- sub.second->handle_event(sdlevent);
- });
- }
-}
-
-void sdl_event_manager::process_window_event(running_machine &machine, SDL_Event &sdlevent)
-{
- std::shared_ptr<sdl_window_info> window = GET_WINDOW(&sdlevent.window);
-
- if (window == nullptr)
- {
- // This condition may occur when the fullscreen toggle is used
- osd_printf_verbose("Skipped window event due to missing window param from SDL\n");
- return;
- }
-
- switch (sdlevent.window.event)
- {
- case SDL_WINDOWEVENT_SHOWN:
- m_has_focus = true;
- break;
-
- case SDL_WINDOWEVENT_CLOSE:
- machine.schedule_exit();
- break;
-
- case SDL_WINDOWEVENT_LEAVE:
- machine.ui_input().push_mouse_leave_event(window->target());
- m_mouse_over_window = 0;
- break;
-
- case SDL_WINDOWEVENT_MOVED:
- window->notify_changed();
- m_focus_window = window;
- m_has_focus = true;
- break;
-
- case SDL_WINDOWEVENT_RESIZED:
-#ifdef SDLMAME_LINUX
- /* FIXME: SDL2 sends some spurious resize events on Ubuntu
- * while in fullscreen mode. Ignore them for now.
- */
- if (!window->fullscreen())
-#endif
- {
- //printf("event data1,data2 %d x %d %ld\n", event.window.data1, event.window.data2, sizeof(SDL_Event));
- window->resize(sdlevent.window.data1, sdlevent.window.data2);
- }
- m_focus_window = window;
- m_has_focus = true;
- break;
-
- case SDL_WINDOWEVENT_ENTER:
- m_mouse_over_window = 1;
- /* fall through */
- case SDL_WINDOWEVENT_FOCUS_GAINED:
- case SDL_WINDOWEVENT_EXPOSED:
- case SDL_WINDOWEVENT_MAXIMIZED:
- case SDL_WINDOWEVENT_RESTORED:
- m_focus_window = window;
- m_has_focus = true;
- break;
-
- case SDL_WINDOWEVENT_MINIMIZED:
- case SDL_WINDOWEVENT_FOCUS_LOST:
- m_has_focus = false;
- break;
- }
-}
-
-//============================================================
-// customize_input_type_list
-//============================================================
-
-void sdl_osd_interface::customize_input_type_list(simple_list<input_type_entry> &typelist)
-{
- input_item_id mameid_code;
- input_code ui_code;
- const char* uimode;
- char fullmode[64];
-
- // loop over the defaults
- for (input_type_entry &entry : typelist)
- {
- switch (entry.type())
- {
- // configurable UI mode switch
- case IPT_UI_TOGGLE_UI:
- uimode = options().ui_mode_key();
- if (!strcmp(uimode, "auto"))
- {
-#if defined(__APPLE__) && defined(__MACH__)
- mameid_code = keyboard_trans_table::instance().lookup_mame_code("ITEM_ID_INSERT");
-#else
- mameid_code = keyboard_trans_table::instance().lookup_mame_code("ITEM_ID_SCRLOCK");
-#endif
- }
- else
- {
- snprintf(fullmode, 63, "ITEM_ID_%s", uimode);
- mameid_code = keyboard_trans_table::instance().lookup_mame_code(fullmode);
- }
- ui_code = input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, input_item_id(mameid_code));
- entry.defseq(SEQ_TYPE_STANDARD).set(ui_code);
- break;
- // alt-enter for fullscreen
- case IPT_OSD_1:
- entry.configure_osd("TOGGLE_FULLSCREEN", "Toggle Fullscreen");
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_ENTER, KEYCODE_LALT);
- break;
-
- // disable UI_SELECT when LALT is down, this stops selecting
- // things in the menu when toggling fullscreen with LALT+ENTER
- /* case IPT_UI_SELECT:
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_ENTER, input_seq::not_code, KEYCODE_LALT);
- break;*/
-
- // page down for fastforward (must be OSD_3 as per src/emu/ui.c)
- case IPT_UI_FAST_FORWARD:
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_PGDN);
- break;
-
- // OSD hotkeys use LCTRL and start at F3, they start at
- // F3 because F1-F2 are hardcoded into many drivers to
- // various dipswitches, and pressing them together with
- // LCTRL will still press/toggle these dipswitches.
-
- // LCTRL-F3 to toggle fullstretch
- case IPT_OSD_2:
- entry.configure_osd("TOGGLE_FULLSTRETCH", "Toggle Uneven stretch");
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F3, KEYCODE_LCONTROL);
- break;
- // add a Not lcrtl condition to the reset key
- case IPT_UI_SOFT_RESET:
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F3, input_seq::not_code, KEYCODE_LCONTROL, input_seq::not_code, KEYCODE_LSHIFT);
- break;
-
- // LCTRL-F4 to toggle keep aspect
- case IPT_OSD_4:
- entry.configure_osd("TOGGLE_KEEP_ASPECT", "Toggle Keepaspect");
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F4, KEYCODE_LCONTROL);
- break;
- // add a Not lcrtl condition to the show gfx key
- case IPT_UI_SHOW_GFX:
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F4, input_seq::not_code, KEYCODE_LCONTROL);
- break;
-
- // LCTRL-F5 to toggle OpenGL filtering
- case IPT_OSD_5:
- entry.configure_osd("TOGGLE_FILTER", "Toggle Filter");
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F5, KEYCODE_LCONTROL);
- break;
- // add a Not lcrtl condition to the toggle debug key
- case IPT_UI_TOGGLE_DEBUG:
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F5, input_seq::not_code, KEYCODE_LCONTROL);
- break;
-
- // LCTRL-F6 to decrease OpenGL prescaling
- case IPT_OSD_6:
- entry.configure_osd("DECREASE_PRESCALE", "Decrease Prescaling");
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F6, KEYCODE_LCONTROL);
- break;
- // add a Not lcrtl condition to the toggle cheat key
- case IPT_UI_TOGGLE_CHEAT:
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F6, input_seq::not_code, KEYCODE_LCONTROL);
- break;
-
- // LCTRL-F7 to increase OpenGL prescaling
- case IPT_OSD_7:
- entry.configure_osd("INCREASE_PRESCALE", "Increase Prescaling");
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F7, KEYCODE_LCONTROL);
- break;
-
- // lshift-lalt-F12 for fullscreen video (BGFX)
- case IPT_OSD_8:
- entry.configure_osd("RENDER_AVI", "Record Rendered Video");
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, KEYCODE_LSHIFT, KEYCODE_LALT);
- break;
-
- // add a Not lcrtl condition to the load state key
- case IPT_UI_LOAD_STATE:
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F7, input_seq::not_code, KEYCODE_LCONTROL, input_seq::not_code, KEYCODE_LSHIFT);
- break;
-
- // add a Not lcrtl condition to the throttle key
- case IPT_UI_THROTTLE:
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F10, input_seq::not_code, KEYCODE_LCONTROL);
- break;
-
- // disable the config menu if the ALT key is down
- // (allows ALT-TAB to switch between apps)
- case IPT_UI_CONFIGURE:
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_TAB, input_seq::not_code, KEYCODE_LALT, input_seq::not_code, KEYCODE_RALT);
- break;
-
-#if defined(__APPLE__) && defined(__MACH__)
- // 78-key Apple MacBook & Bluetooth keyboards have no right control key
- case IPT_MAHJONG_SCORE:
- if (entry.player() == 0)
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_SLASH);
- break;
-#endif
-
- // leave everything else alone
- default:
- break;
- }
- }
-}
-
-void sdl_osd_interface::poll_inputs(running_machine &machine)
-{
- m_keyboard_input->poll_if_necessary(machine);
- m_mouse_input->poll_if_necessary(machine);
- m_lightgun_input->poll_if_necessary(machine);
- m_joystick_input->poll_if_necessary(machine);
-}
-
-void sdl_osd_interface::release_keys()
-{
- auto keybd = dynamic_cast<input_module_base*>(m_keyboard_input);
- if (keybd != nullptr)
- keybd->devicelist()->reset_devices();
-}
-
-bool sdl_osd_interface::should_hide_mouse()
-{
- // if we are paused, no
- if (machine().paused())
- return false;
-
- // if neither mice nor lightguns enabled in the core, then no
- if (!options().mouse() && !options().lightgun())
- return false;
-
- if (!sdl_event_manager::instance().mouse_over_window())
- return false;
-
- // otherwise, yes
- return true;
-}
-
-void sdl_osd_interface::process_events_buf()
-{
- SDL_PumpEvents();
-}
-
-#endif
diff --git a/src/osd/modules/input/input_sdlcommon.h b/src/osd/modules/input/input_sdlcommon.h
deleted file mode 100644
index 377b04d71c9..00000000000
--- a/src/osd/modules/input/input_sdlcommon.h
+++ /dev/null
@@ -1,204 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes
-//============================================================
-//
-// input_sdlcommon.h - SDL Common code shared by SDL modules
-//
-// Note: this code is also used by the X11 input modules
-//
-//============================================================
-
-#ifndef INPUT_SDLCOMMON_H_
-#define INPUT_SDLCOMMON_H_
-
-#include <unordered_map>
-#include <algorithm>
-
-#define MAX_DEVMAP_ENTRIES 16
-#define SDL_MODULE_EVENT_BUFFER_SIZE 5
-
-// state information for a keyboard
-struct keyboard_state
-{
- int32_t state[0x3ff]; // must be int32_t!
- int8_t oldkey[MAX_KEYS];
- int8_t currkey[MAX_KEYS];
-};
-
-// state information for a mouse
-struct mouse_state
-{
- int32_t lX, lY;
- int32_t buttons[MAX_BUTTONS];
-};
-
-
-// state information for a joystick; DirectInput state must be first element
-struct joystick_state
-{
- SDL_Joystick *device;
- int32_t axes[MAX_AXES];
- int32_t buttons[MAX_BUTTONS];
- int32_t hatsU[MAX_HATS], hatsD[MAX_HATS], hatsL[MAX_HATS], hatsR[MAX_HATS];
- int32_t balls[MAX_AXES];
-};
-
-struct device_map_t
-{
- struct {
- std::string name;
- int physical;
- } map[MAX_DEVMAP_ENTRIES];
- int logical[MAX_DEVMAP_ENTRIES];
- int initialized;
-};
-
-//============================================================
-// event_manager_t
-//============================================================
-
-class sdl_event_subscriber
-{
-public:
- virtual ~sdl_event_subscriber() {}
- virtual void handle_event(SDL_Event &sdlevent) = 0;
-};
-
-template <class TSubscriber>
-class event_manager_t
-{
-protected:
- std::mutex m_lock;
- std::unordered_multimap<int, TSubscriber*> m_subscription_index;
- event_manager_t()
- {
- }
-
-public:
- virtual ~event_manager_t()
- {
- }
-
- void subscribe(int* event_types, int num_event_types, TSubscriber *subscriber)
- {
- std::lock_guard<std::mutex> scope_lock(m_lock);
-
- // Add the subscription
- for (int i = 0; i < num_event_types; i++)
- {
- m_subscription_index.emplace(event_types[i], subscriber);
- }
- }
-
- void unsubscribe(TSubscriber *subscriber)
- {
- std::lock_guard<std::mutex> scope_lock(m_lock);
-
- // Remove the events that match the subscriber
- for (auto it = begin(m_subscription_index); it != end(m_subscription_index);)
- {
- if (it->second == subscriber)
- {
- it = m_subscription_index.erase(it);
- }
- else
- {
- ++it;
- }
- }
- }
-
- virtual void process_events(running_machine &machine) = 0;
-};
-
-class sdl_window_info;
-
-class sdl_event_manager : public event_manager_t<sdl_event_subscriber>
-{
-private:
- bool m_mouse_over_window;
- bool m_has_focus;
- std::shared_ptr<sdl_window_info> m_focus_window;
-
- sdl_event_manager()
- : m_mouse_over_window(true),
- m_has_focus(true),
- m_focus_window(nullptr)
- {
- }
-
-public:
- bool mouse_over_window() const { return m_mouse_over_window; }
- bool has_focus() const { return m_focus_window != nullptr; }
- std::shared_ptr<sdl_window_info> focus_window() const { return m_focus_window; }
-
- static sdl_event_manager& instance()
- {
- static sdl_event_manager s_instance;
- return s_instance;
- }
-
- void process_events(running_machine &machine) override;
-
-private:
- void process_window_event(running_machine &machine, SDL_Event &sdlevent);
-};
-
-//============================================================
-// INLINE FUNCTIONS
-//============================================================
-
-static inline std::string remove_spaces(const char *s)
-{
- // Remove the spaces
- auto output = std::string(s);
- output.erase(std::remove_if(output.begin(), output.end(), isspace), output.end());
-
- return output;
-}
-
-//============================================================
-// devmap_init - initializes a device_map based on
-// an input option prefix and max number of devices
-//============================================================
-
-static inline void devmap_init(running_machine &machine, device_map_t *devmap, const char *opt, int max_devices, const char *label)
-{
- int dev;
- char defname[20];
-
- // The max devices the user specified, better not be bigger than the max the arrays can old
- assert(max_devices <= MAX_DEVMAP_ENTRIES);
-
- // Initialize the map to default uninitialized values
- for (dev = 0; dev < MAX_DEVMAP_ENTRIES; dev++)
- {
- devmap->map[dev].name.clear();
- devmap->map[dev].physical = -1;
- devmap->logical[dev] = -1;
- }
- devmap->initialized = 0;
-
- // populate the device map up to the max number of devices
- for (dev = 0; dev < max_devices; dev++)
- {
- const char *dev_name;
-
- // derive the parameter name from the option name and index. For instance: lightgun_index1 to lightgun_index8
- sprintf(defname, "%s%d", opt, dev + 1);
-
- // Get the user-specified name that matches the parameter
- dev_name = machine.options().value(defname);
-
- // If they've specified a name and it's not "auto", treat it as a custom mapping
- if (dev_name && *dev_name && strcmp(dev_name, OSDOPTVAL_AUTO))
- {
- // remove the spaces from the name store it in the index
- devmap->map[dev].name = remove_spaces(dev_name);
- osd_printf_verbose("%s: Logical id %d: %s\n", label, dev + 1, devmap->map[dev].name.c_str());
- devmap->initialized = 1;
- }
- }
-}
-
-#endif
diff --git a/src/osd/modules/input/input_uwp.cpp b/src/osd/modules/input/input_uwp.cpp
deleted file mode 100644
index 6b3b8675cff..00000000000
--- a/src/osd/modules/input/input_uwp.cpp
+++ /dev/null
@@ -1,649 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Brad Hughes
-//============================================================
-//
-// input_uwp.cpp - UWP input implementation
-//
-//============================================================
-
-#include "input_module.h"
-#include "modules/osdmodule.h"
-
-#if defined(OSD_UWP)
-
-#include <agile.h>
-#include <ppltasks.h>
-#include <collection.h>
-#undef interface
-
-// MAME headers
-#include "emu.h"
-#include "uiinput.h"
-#include "strconv.h"
-
-// MAMEOS headers
-#include "winmain.h"
-#include "input_common.h"
-#include "input_windows.h"
-
-#define UWP_BUTTON_COUNT 32
-
-using namespace concurrency;
-using namespace Windows::UI::Core;
-using namespace Windows::Foundation;
-using namespace Windows::Foundation::Collections;
-using namespace Windows::Gaming::Input;
-
-//============================================================
-// UWP Base device/module implementation
-//============================================================
-
-//============================================================
-// UwpInputDevice - base class for implementing an input
-// device in C++/CX. To be used with uwp_input_device
-//============================================================
-
-private ref class UwpInputDevice
-{
-private:
- running_machine & m_machine;
- std::string m_name;
- std::string m_id;
- input_device_class m_devclass;
- input_module & m_module;
- input_device *m_inputdevice;
-
-internal:
- UwpInputDevice(running_machine &machine, const char *name, const char *id, input_device_class deviceclass, input_module &module)
- : m_machine(machine),
- m_name(name),
- m_id(id),
- m_devclass(deviceclass),
- m_module(module),
- m_inputdevice(nullptr)
- {
- }
-
- property running_machine & Machine
- {
- running_machine & get() { return m_machine; }
- }
-
- property const std::string & Name
- {
- const std::string & get() { return m_name; }
- }
-
- property const std::string & Id
- {
- const std::string & get() { return m_id; }
- }
-
- property input_device_class DeviceClass
- {
- input_device_class get() { return m_devclass; }
- }
-
- property input_module & Module
- {
- input_module & get() { return m_module; }
- }
-
- property input_device* InputDevice
- {
- input_device* get() { return m_inputdevice; }
- void set(input_device* value) { m_inputdevice = value; }
- }
-
- virtual void Poll()
- {
- }
-
- virtual void Reset()
- {
- }
-};
-
-//============================================================
-// uwp_input_device - a device that can be used to wrap a
-// C++/CX ref class for an input device implementation
-//============================================================
-
-class uwp_input_device : public device_info
-{
-private:
- UwpInputDevice ^m_wrapped_device;
-
-public:
- uwp_input_device(UwpInputDevice ^device)
- : device_info(device->Machine, device->Name.c_str(), device->Id.c_str(), device->DeviceClass, device->Module),
- m_wrapped_device(device)
- {
- }
-
- void poll() override
- {
- m_wrapped_device->Poll();
- }
-
- void reset() override
- {
- m_wrapped_device->Reset();
- }
-};
-
-//============================================================
-// UwpInputModule - a base class that can be used to
-// implement an input module with a C++/CX class.
-// normally used with uwp_wininput_module
-//============================================================
-
-class uwp_input_module;
-
-private ref class UwpInputModule
-{
-private:
- const std::string m_type;
- const std::string m_name;
- uwp_input_module *m_module;
-
-internal:
- UwpInputModule(const char *type, const char *name)
- : m_type(type),
- m_name(name),
- m_module(nullptr)
- {
- }
-
- property const std::string & Type
- {
- const std::string & get() { return m_type; }
- }
-
- property const std::string & Name
- {
- const std::string & get() { return m_name; }
- }
-
- property uwp_input_module * NativeModule
- {
- uwp_input_module * get() { return m_module; }
- void set(uwp_input_module * value) { m_module = value; }
- }
-
- virtual void input_init(running_machine &machine)
- {
- }
-};
-
-//============================================================
-// uwp_input_module - an input module that can be
-// used to create an input module with a C++/CX ref class
-//============================================================
-
-class uwp_input_module : public wininput_module
-{
-private:
- UwpInputModule^ m_refmodule;
-
-public:
- uwp_input_module(UwpInputModule^ refmodule)
- : wininput_module(refmodule->Type.c_str(), refmodule->Name.c_str()),
- m_refmodule(refmodule)
- {
- refmodule->NativeModule = this;
- }
-
- void input_init(running_machine &machine) override
- {
- m_refmodule->input_init(machine);
- }
-};
-
-//============================================================
-// UWP Keyboard Implementation
-//============================================================
-
-//============================================================
-// UwpKeyboardDevice
-//============================================================
-
-private ref class UwpKeyboardDevice : public UwpInputDevice
-{
-private:
- keyboard_state keyboard;
- Platform::Agile<CoreWindow> m_coreWindow;
- std::mutex m_state_lock;
-
-internal:
- UwpKeyboardDevice(Platform::Agile<CoreWindow> coreWindow, running_machine& machine, char *name, const char *id, input_module &module)
- : UwpInputDevice(machine, name, id, DEVICE_CLASS_KEYBOARD, module),
- keyboard({{0}}),
- m_coreWindow(coreWindow)
- {
- coreWindow->Dispatcher->AcceleratorKeyActivated += ref new TypedEventHandler<CoreDispatcher^, AcceleratorKeyEventArgs^>(this, &UwpKeyboardDevice::OnAcceleratorKeyActivated);
- coreWindow->KeyDown += ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &UwpKeyboardDevice::OnKeyDown);
- coreWindow->KeyUp += ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &UwpKeyboardDevice::OnKeyUp);
- coreWindow->CharacterReceived += ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &UwpKeyboardDevice::OnCharacterReceived);
- }
-
- void Reset() override
- {
- std::lock_guard<std::mutex> scope_lock(m_state_lock);
- memset(&keyboard, 0, sizeof(keyboard));
- }
-
- void Configure()
- {
- keyboard_trans_table &table = keyboard_trans_table::instance();
-
- // populate it indexed by the scancode
- for (int keynum = KEY_UNKNOWN + 1; keynum < MAX_KEYS; keynum++)
- {
- input_item_id itemid = table.map_di_scancode_to_itemid(keynum);
- const char *keyname = table.ui_label_for_mame_key(itemid);
-
- char temp[256];
- if (keyname == nullptr)
- {
- snprintf(temp, ARRAY_LENGTH(temp), "Scan%03d", keynum);
- keyname = temp;
- }
-
- // add the item to the device
- this->InputDevice->add_item(keyname, itemid, generic_button_get_state<std::uint8_t>, &keyboard.state[keynum]);
- }
- }
-
- void OnKeyDown(CoreWindow^ win, KeyEventArgs^ args)
- {
- std::lock_guard<std::mutex> scope_lock(m_state_lock);
- CorePhysicalKeyStatus status = args->KeyStatus;
- int discancode = (status.ScanCode & 0x7f) | (status.IsExtendedKey ? 0x80 : 0x00);
- keyboard.state[discancode] = 0x80;
- }
-
- void OnKeyUp(CoreWindow^ win, KeyEventArgs^ args)
- {
- std::lock_guard<std::mutex> scope_lock(m_state_lock);
- CorePhysicalKeyStatus status = args->KeyStatus;
- int discancode = (status.ScanCode & 0x7f) | (status.IsExtendedKey ? 0x80 : 0x00);
- keyboard.state[discancode] = 0;
- }
-
- void OnCharacterReceived(CoreWindow ^sender, CharacterReceivedEventArgs ^args)
- {
- this->Machine.ui_input().push_char_event(osd_common_t::s_window_list.front()->target(), args->KeyCode);
- }
-
- void OnAcceleratorKeyActivated(CoreDispatcher ^sender, AcceleratorKeyEventArgs ^args)
- {
- std::lock_guard<std::mutex> scope_lock(m_state_lock);
- auto eventType = args->EventType;
- if (eventType == CoreAcceleratorKeyEventType::SystemKeyDown ||
- eventType == CoreAcceleratorKeyEventType::SystemKeyUp)
- {
- CorePhysicalKeyStatus status = args->KeyStatus;
- int discancode = (status.ScanCode & 0x7f) | (status.IsExtendedKey ? 0x80 : 0x00);
- keyboard.state[discancode] =
- eventType == CoreAcceleratorKeyEventType::SystemKeyDown ? 0x80 : 0;
- }
- }
-};
-
-//============================================================
-// UwpKeyboardModule
-//============================================================
-
-private ref class UwpKeyboardModule : public UwpInputModule
-{
-private:
- running_machine *m_machine;
-
-internal:
- UwpKeyboardModule()
- : UwpInputModule(OSD_KEYBOARDINPUT_PROVIDER, "uwp")
- {
- }
-
- void input_init(running_machine &machine) override
- {
- auto first_window = std::static_pointer_cast<uwp_window_info>(osd_common_t::s_window_list.front());
- auto coreWindow = first_window->platform_window();
-
- // allocate the UWP implementation of the device object
- UwpKeyboardDevice ^refdevice = ref new UwpKeyboardDevice(coreWindow, machine, "UWP Keyboard 1", "UWP Keyboard 1", *this->NativeModule);
-
- // Allocate the wrapper and add it to the list
- auto created_devinfo = std::make_unique<uwp_input_device>(refdevice);
- uwp_input_device *devinfo = NativeModule->devicelist()->add_device<uwp_input_device>(machine, std::move(created_devinfo));
-
- // Give the UWP implementation a handle to the input_device
- refdevice->InputDevice = devinfo->device();
-
- // Configure the device
- refdevice->Configure();
- }
-};
-
-//============================================================
-// uwp_keyboard_module
-//============================================================
-
-class uwp_keyboard_module : public uwp_input_module
-{
-public:
- uwp_keyboard_module()
- : uwp_input_module(ref new UwpKeyboardModule())
- {
- }
-};
-
-// default axis names
-static const char *const uwp_axis_name[] =
-{
- "LSX",
- "LSY",
- "RSX",
- "RSY"
-};
-
-static const input_item_id uwp_axis_ids[] =
-{
- ITEM_ID_XAXIS,
- ITEM_ID_YAXIS,
- ITEM_ID_RXAXIS,
- ITEM_ID_RYAXIS
-};
-
-struct gamepad_state
-{
- BYTE buttons[UWP_BUTTON_COUNT];
- LONG left_trigger;
- LONG right_trigger;
- LONG left_thumb_x;
- LONG left_thumb_y;
- LONG right_thumb_x;
- LONG right_thumb_y;
-};
-
-// Maps different UWP GameControllerButtonLabels to a halfway-sane input_item_id in many cases
-static input_item_id buttonlabel_to_itemid[] =
-{
- input_item_id::ITEM_ID_INVALID, // GameControllerButtonLabel::None
- input_item_id::ITEM_ID_SELECT, // GameControllerButtonLabel::XboxBack
- input_item_id::ITEM_ID_START, // GameControllerButtonLabel::XboxStart
- input_item_id::ITEM_ID_START, // GameControllerButtonLabel::XboxMenu
- input_item_id::ITEM_ID_SELECT, // GameControllerButtonLabel::XboxView
- input_item_id::ITEM_ID_HAT1UP, // GameControllerButtonLabel::XboxUp
- input_item_id::ITEM_ID_HAT1DOWN, // GameControllerButtonLabel::XboxDown
- input_item_id::ITEM_ID_HAT1LEFT, // GameControllerButtonLabel::XboxLeft
- input_item_id::ITEM_ID_HAT1RIGHT, // GameControllerButtonLabel::XboxRight
- input_item_id::ITEM_ID_BUTTON1, // GameControllerButtonLabel::XboxA
- input_item_id::ITEM_ID_BUTTON2, // GameControllerButtonLabel::XboxB
- input_item_id::ITEM_ID_BUTTON3, // GameControllerButtonLabel::XboxX
- input_item_id::ITEM_ID_BUTTON4, // GameControllerButtonLabel::XboxY
- input_item_id::ITEM_ID_BUTTON5, // GameControllerButtonLabel::XboxLeftBumper
- input_item_id::ITEM_ID_ZAXIS, // GameControllerButtonLabel::XboxLeftTrigger
- input_item_id::ITEM_ID_BUTTON7, // GameControllerButtonLabel::XboxLeftStickButton
- input_item_id::ITEM_ID_BUTTON6, // GameControllerButtonLabel::XboxRightBumper
- input_item_id::ITEM_ID_RZAXIS, // GameControllerButtonLabel::XboxRightTrigger
- input_item_id::ITEM_ID_BUTTON8, // GameControllerButtonLabel::XboxRightStickButton
- input_item_id::ITEM_ID_BUTTON9, // GameControllerButtonLabel::XboxPaddle1
- input_item_id::ITEM_ID_BUTTON10, // GameControllerButtonLabel::XboxPaddle2
- input_item_id::ITEM_ID_BUTTON11, // GameControllerButtonLabel::XboxPaddle3
- input_item_id::ITEM_ID_BUTTON12, // GameControllerButtonLabel::XboxPaddle4
- input_item_id::ITEM_ID_INVALID, // GameControllerButtonLabel_Mode
- input_item_id::ITEM_ID_SELECT, // GameControllerButtonLabel_Select
- input_item_id::ITEM_ID_START, // GameControllerButtonLabel_Menu
- input_item_id::ITEM_ID_SELECT, // GameControllerButtonLabel_View
- input_item_id::ITEM_ID_SELECT, // GameControllerButtonLabel_Back
- input_item_id::ITEM_ID_START, // GameControllerButtonLabel_Start
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Options
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Share
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Up
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Down
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Left
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Right
- input_item_id::ITEM_ID_BUTTON1, // GameControllerButtonLabel_LetterA
- input_item_id::ITEM_ID_BUTTON2, // GameControllerButtonLabel_LetterB
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_LetterC
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_LetterL
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_LetterR
- input_item_id::ITEM_ID_BUTTON3, // GameControllerButtonLabel_LetterX
- input_item_id::ITEM_ID_BUTTON4, // GameControllerButtonLabel_LetterY
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_LetterZ
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Cross
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Circle
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Square
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Triangle
- input_item_id::ITEM_ID_BUTTON5, // GameControllerButtonLabel_LeftBumper
- input_item_id::ITEM_ID_ZAXIS, // GameControllerButtonLabel_LeftTrigger
- input_item_id::ITEM_ID_BUTTON7, // GameControllerButtonLabel_LeftStickButton
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Left1
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Left2
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Left3
- input_item_id::ITEM_ID_BUTTON6, // GameControllerButtonLabel_RightBumper
- input_item_id::ITEM_ID_RZAXIS, // GameControllerButtonLabel_RightTrigger
- input_item_id::ITEM_ID_BUTTON8, // GameControllerButtonLabel_RightStickButton
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Right1
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Right2
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Right3
- input_item_id::ITEM_ID_BUTTON9, // GameControllerButtonLabel_Paddle1
- input_item_id::ITEM_ID_BUTTON10, // GameControllerButtonLabel_Paddle2
- input_item_id::ITEM_ID_BUTTON11, // GameControllerButtonLabel_Paddle3
- input_item_id::ITEM_ID_BUTTON12, // GameControllerButtonLabel_Paddle4
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Plus
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Minus
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_DownLeftArrow
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_DialLeft
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_DialRight
- input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Suspension
-};
-
-//============================================================
-// UwpJoystickDevice
-//============================================================
-
-private ref class UwpJoystickDevice : public UwpInputDevice
-{
-private:
- Gamepad ^m_pad;
- bool m_configured;
- gamepad_state state;
-
-internal:
- UwpJoystickDevice(Gamepad^ pad, running_machine &machine, const char *name, const char *id, input_module &module)
- : UwpInputDevice(machine, name, id, DEVICE_CLASS_JOYSTICK, module),
- m_pad(pad),
- m_configured(false),
- state({0})
- {}
-
- void Poll() override
- {
- // If the device hasn't been configured, don't poll
- if (!m_configured)
- return;
-
- GamepadReading reading = m_pad->GetCurrentReading();
-
- for (int butnum = 0; butnum < UWP_BUTTON_COUNT; butnum++)
- {
- GamepadButtons currentButton = GamepadButtons(1 << butnum);
- state.buttons[butnum] = (reading.Buttons & currentButton) != GamepadButtons::None ? 0xFF : 0;
- }
-
- // Now grab the axis values
- // Each of the thumbstick axis members is a signed value between -32768 and 32767 describing the position of the thumbstick
- // However, the Y axis values are inverted from what MAME expects, so negate the value
- state.left_thumb_x = normalize_absolute_axis(reading.LeftThumbstickX, -1, 1);
- state.left_thumb_y = -normalize_absolute_axis(reading.LeftThumbstickY, -1, 1);
- state.right_thumb_x = normalize_absolute_axis(reading.RightThumbstickX, -1, 1);
- state.right_thumb_y = -normalize_absolute_axis(reading.RightThumbstickY, -1, 1);
-
- // Get the trigger values
- state.left_trigger = normalize_absolute_axis(reading.LeftTrigger, 0.0, 1.0);
- state.right_trigger = normalize_absolute_axis(reading.RightTrigger, 0.0, 1.0);
-
- // For the UI, triggering UI_CONFIGURE is odd. It requires a EVENT_CHAR first
- static constexpr int menuhotkey = (int)(GamepadButtons::View | GamepadButtons::X);
- if (((int)reading.Buttons & menuhotkey) == menuhotkey)
- {
- ui_event uiev;
- memset(&uiev, 0, sizeof(uiev));
- uiev.event_type = ui_event::IME_CHAR;
- this->Machine.ui_input().push_event(uiev);
- }
- }
-
- void Reset() override
- {
- memset(&state, 0, sizeof(state));
- }
-
- void Configure()
- {
- // If the device has already been configured, don't do it again
- if (m_configured)
- return;
-
- GamepadReading r = m_pad->GetCurrentReading();
-
- // Add the axes
- for (int axisnum = 0; axisnum < 4; axisnum++)
- {
- this->InputDevice->add_item(
- uwp_axis_name[axisnum],
- uwp_axis_ids[axisnum],
- generic_axis_get_state<LONG>,
- &state.left_thumb_x + axisnum);
- }
-
- // populate the buttons
- for (int butnum = 0; butnum < UWP_BUTTON_COUNT; butnum++)
- {
- GamepadButtons button = GamepadButtons(1 << butnum);
- auto label = m_pad->GetButtonLabel(button);
- if (label != GameControllerButtonLabel::None)
- {
- std::string desc = osd::text::from_wstring(label.ToString()->Data());
- this->InputDevice->add_item(
- desc.c_str(),
- buttonlabel_to_itemid[static_cast<int>(label)],
- generic_button_get_state<BYTE>,
- &state.buttons[butnum]);
- }
- }
-
- this->InputDevice->add_item(
- "Left Trigger",
- ITEM_ID_ZAXIS,
- generic_axis_get_state<LONG>,
- &state.left_trigger);
-
- this->InputDevice->add_item(
- "Right Trigger",
- ITEM_ID_RZAXIS,
- generic_axis_get_state<LONG>,
- &state.right_trigger);
-
- m_configured = true;
- }
-};
-
-//============================================================
-// UwpJoystickModule
-//============================================================
-
-private ref class UwpJoystickModule : public UwpInputModule
-{
-private:
- boolean m_joysticks_discovered;
-
-internal:
- UwpJoystickModule()
- : UwpInputModule(OSD_JOYSTICKINPUT_PROVIDER, "uwp"),
- m_joysticks_discovered(false)
- {
- }
-
- void input_init(running_machine &machine) override
- {
- PerformGamepadDiscovery();
-
- auto pads = Gamepad::Gamepads;
-
- int padindex = 0;
- std::for_each(begin(pads), end(pads), [&](Gamepad^ pad)
- {
- uwp_input_device *devinfo;
-
- std::ostringstream namestream;
- namestream << "UWP Gamepad " << (padindex + 1);
-
- auto name = namestream.str();
-
- // allocate the UWP implementation of the device object
- UwpJoystickDevice ^refdevice = ref new UwpJoystickDevice(pad, machine, name.c_str(), name.c_str(), *this->NativeModule);
-
- // Allocate the wrapper and add it to the list
- auto created_devinfo = std::make_unique<uwp_input_device>(refdevice);
- devinfo = NativeModule->devicelist()->add_device<uwp_input_device>(machine, std::move(created_devinfo));
-
- // Give the UWP implementation a handle to the input_device
- refdevice->InputDevice = devinfo->device();
-
- // Configure the device
- refdevice->Configure();
-
- padindex++;
- });
- }
-
-private:
- void PerformGamepadDiscovery()
- {
- Gamepad::GamepadAdded += ref new EventHandler<Gamepad ^>(this, &UwpJoystickModule::OnGamepadAdded);
- auto start = std::chrono::system_clock::now();
-
- // We need to pause a bit and pump events so gamepads get discovered
- while (std::chrono::system_clock::now() - start < std::chrono::milliseconds(1000))
- CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
-
- m_joysticks_discovered = true;
- }
-
- void OnGamepadAdded(Platform::Object ^sender, Gamepad ^pad)
- {
- if (m_joysticks_discovered)
- {
- osd_printf_error("Input: UWP Compatible %s gamepad plugged in AFTER discovery complete!\n", pad->IsWireless ? "Wireless" : "Wired");
- }
- else
- {
- osd_printf_verbose("Input: UWP Compatible %s gamepad discovered.\n", pad->IsWireless ? "Wireless" : "Wired");
- }
- }
-};
-
-//============================================================
-// uwp_joystick_module
-//============================================================
-
-class uwp_joystick_module : public uwp_input_module
-{
-public:
- uwp_joystick_module()
- : uwp_input_module(ref new UwpJoystickModule())
- {
- }
-};
-
-#else
-MODULE_NOT_SUPPORTED(uwp_keyboard_module, OSD_KEYBOARDINPUT_PROVIDER, "uwp")
-MODULE_NOT_SUPPORTED(uwp_joystick_module, OSD_JOYSTICKINPUT_PROVIDER, "uwp")
-#endif
-
-MODULE_DEFINITION(KEYBOARDINPUT_UWP, uwp_keyboard_module)
-MODULE_DEFINITION(JOYSTICKINPUT_UWP, uwp_joystick_module)
diff --git a/src/osd/modules/input/input_win32.cpp b/src/osd/modules/input/input_win32.cpp
index c07a1c681d8..921c902ad31 100644
--- a/src/osd/modules/input/input_win32.cpp
+++ b/src/osd/modules/input/input_win32.cpp
@@ -7,25 +7,28 @@
//============================================================
#include "input_module.h"
-#include "modules/osdmodule.h"
#if defined(OSD_WINDOWS)
+#include "input_windows.h"
+
+#include "input_wincommon.h"
+
+// osd/windows
+#include "window.h"
+
+// emu
+#include "inpttype.h"
+
+#include "strconv.h"
+
// standard windows headers
-#include <windows.h>
#include <tchar.h>
-#undef interface
-// MAME headers
-#include "emu.h"
-#include "strconv.h"
-// MAMEOS headers
-#include "winmain.h"
-#include "window.h"
+namespace osd {
-#include "input_common.h"
-#include "input_windows.h"
+namespace {
//============================================================
// win32_keyboard_device
@@ -35,117 +38,118 @@
class win32_keyboard_device : public event_based_device<KeyPressEventArgs>
{
public:
- keyboard_state keyboard;
+ win32_keyboard_device(std::string &&name, std::string &&id, input_module &module) :
+ event_based_device(std::move(name), std::move(id), module),
+ m_keyboard({{0}})
+ {
+ }
- win32_keyboard_device(running_machine& machine, const char *name, const char *id, input_module &module)
- : event_based_device(machine, name, id, DEVICE_CLASS_KEYBOARD, module),
- keyboard({{0}})
+ virtual void reset() override
{
+ event_based_device::reset();
+ memset(&m_keyboard, 0, sizeof(m_keyboard));
}
- void reset() override
+ virtual void configure(input_device &device) override
{
- memset(&keyboard, 0, sizeof(keyboard));
+ keyboard_trans_table const &table = keyboard_trans_table::instance();
+
+ for (int keynum = 0; keynum < MAX_KEYS; keynum++)
+ {
+ input_item_id itemid = table.map_di_scancode_to_itemid(keynum);
+ TCHAR keyname[100];
+
+ // generate the name
+ // FIXME: GetKeyNameText gives bogus names for media keys and various other things
+ // in many cases it ignores the "extended" bit and returns the key name corresponding to the scan code alone
+ if (GetKeyNameText(((keynum & 0x7f) << 16) | ((keynum & 0x80) << 17), keyname, std::size(keyname)) == 0)
+ _sntprintf(keyname, std::size(keyname), TEXT("Scan%03d"), keynum);
+ std::string name = text::from_tstring(keyname);
+
+ // add the item to the device
+ device.add_item(
+ name,
+ util::string_format("SCAN%03d", keynum),
+ itemid,
+ generic_button_get_state<std::uint8_t>,
+ &m_keyboard.state[keynum]);
+ }
}
protected:
- void process_event(KeyPressEventArgs &args) override
+ virtual void process_event(KeyPressEventArgs const &args) override
{
- keyboard.state[args.scancode] = args.event_id == INPUT_EVENT_KEYDOWN ? 0x80 : 0x00;
+ m_keyboard.state[args.scancode] = args.event_id == INPUT_EVENT_KEYDOWN ? 0x80 : 0x00;
}
+
+private:
+ keyboard_state m_keyboard;
};
+
//============================================================
// keyboard_input_win32 - win32 keyboard input module
//============================================================
-class keyboard_input_win32 : public wininput_module
+class keyboard_input_win32 : public wininput_module<win32_keyboard_device>
{
-private:
-
public:
- keyboard_input_win32()
- : wininput_module(OSD_KEYBOARDINPUT_PROVIDER, "win32")
+ keyboard_input_win32() : wininput_module<win32_keyboard_device>(OSD_KEYBOARDINPUT_PROVIDER, "win32")
{
}
virtual void input_init(running_machine &machine) override
{
- // Add a single win32 keyboard device that we'll monitor using Win32
- win32_keyboard_device *devinfo = devicelist()->create_device<win32_keyboard_device>(machine, "Win32 Keyboard 1", "Win32 Keyboard 1", *this);
-
- keyboard_trans_table &table = keyboard_trans_table::instance();
-
- // populate it
- for (int keynum = 0; keynum < MAX_KEYS; keynum++)
- {
- input_item_id itemid = table.map_di_scancode_to_itemid(keynum);
- TCHAR keyname[100];
-
- // generate the name
- if (GetKeyNameText(((keynum & 0x7f) << 16) | ((keynum & 0x80) << 17), keyname, ARRAY_LENGTH(keyname)) == 0)
- _sntprintf(keyname, ARRAY_LENGTH(keyname), TEXT("Scan%03d"), keynum);
- std::string name = osd::text::from_tstring(keyname);
+ wininput_module<win32_keyboard_device>::input_init(machine);
- // add the item to the device
- devinfo->device()->add_item(name.c_str(), itemid, generic_button_get_state<std::uint8_t>, &devinfo->keyboard.state[keynum]);
- }
+ // Add a single win32 keyboard device that we'll monitor using Win32
+ create_device<win32_keyboard_device>(DEVICE_CLASS_KEYBOARD, "Win32 Keyboard 1", "Win32 Keyboard 1");
}
- bool handle_input_event(input_event eventid, void *eventdata) override
+ virtual bool handle_input_event(input_event eventid, void const *eventdata) override
{
- if (!input_enabled())
- return false;
-
- KeyPressEventArgs *args;
-
switch (eventid)
{
- case INPUT_EVENT_KEYDOWN:
- case INPUT_EVENT_KEYUP:
- args = static_cast<KeyPressEventArgs*>(eventdata);
- devicelist()->for_each_device([args](auto device)
- {
- auto keyboard = dynamic_cast<win32_keyboard_device*>(device);
- if (keyboard != nullptr)
- keyboard->queue_events(args, 1);
- });
-
- return true;
-
- default:
- return false;
+ case INPUT_EVENT_KEYDOWN:
+ case INPUT_EVENT_KEYUP:
+ devicelist().for_each_device(
+ [args = reinterpret_cast<KeyPressEventArgs const *>(eventdata)] (auto &device)
+ {
+ device.queue_events(args, 1);
+ });
+ return false; // we still want text input events to be generated
+
+ default:
+ return false;
}
}
};
+
//============================================================
// win32_mouse_device
//============================================================
-struct win32_mouse_state
-{
- POINT last_point;
-};
-
-class win32_mouse_device : public event_based_device<MouseButtonEventArgs>
+class win32_mouse_device : public event_based_device<MouseUpdateEventArgs>
{
public:
- mouse_state mouse;
- win32_mouse_state win32_mouse;
-
- win32_mouse_device(running_machine& machine, const char *name, const char *id, input_module &module)
- : event_based_device(machine, name, id, DEVICE_CLASS_MOUSE, module),
- mouse({0}),
- win32_mouse({{0}})
+ win32_mouse_device(std::string &&name, std::string &&id, input_module &module) :
+ event_based_device(std::move(name), std::move(id), module),
+ m_mouse({0}),
+ m_win32_mouse({{0}}),
+ m_vscroll(0),
+ m_hscroll(0)
{
}
- void poll() override
+ virtual void poll(bool relative_reset) override
{
- event_based_device::poll();
+ event_based_device::poll(relative_reset);
- CURSORINFO cursor_info = {0};
+ if (!relative_reset)
+ return;
+
+ CURSORINFO cursor_info = { 0 };
cursor_info.cbSize = sizeof(CURSORINFO);
GetCursorInfo(&cursor_info);
@@ -154,145 +158,228 @@ public:
if (!(cursor_info.flags & CURSOR_SHOWING))
{
// We measure the position change from the previously set center position
- mouse.lX = (cursor_info.ptScreenPos.x - win32_mouse.last_point.x) * INPUT_RELATIVE_PER_PIXEL;
- mouse.lY = (cursor_info.ptScreenPos.y - win32_mouse.last_point.y) * INPUT_RELATIVE_PER_PIXEL;
+ m_mouse.lX = (cursor_info.ptScreenPos.x - m_win32_mouse.last_point.x) * input_device::RELATIVE_PER_PIXEL;
+ m_mouse.lY = (cursor_info.ptScreenPos.y - m_win32_mouse.last_point.y) * input_device::RELATIVE_PER_PIXEL;
RECT window_pos = {0};
- GetWindowRect(std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window(), &window_pos);
+ GetWindowRect(
+ dynamic_cast<win_window_info &>(*osd_common_t::window_list().front()).platform_window(),
+ &window_pos);
// We reset the cursor position to the middle of the window each frame
- win32_mouse.last_point.x = window_pos.left + (window_pos.right - window_pos.left) / 2;
- win32_mouse.last_point.y = window_pos.top + (window_pos.bottom - window_pos.top) / 2;
+ m_win32_mouse.last_point.x = window_pos.left + (window_pos.right - window_pos.left) / 2;
+ m_win32_mouse.last_point.y = window_pos.top + (window_pos.bottom - window_pos.top) / 2;
- SetCursorPos(win32_mouse.last_point.x, win32_mouse.last_point.y);
+ SetCursorPos(m_win32_mouse.last_point.x, m_win32_mouse.last_point.y);
}
+
+ // update scroll axes
+ m_mouse.lV = std::exchange(m_vscroll, 0) * input_device::RELATIVE_PER_PIXEL;
+ m_mouse.lH = std::exchange(m_hscroll, 0) * input_device::RELATIVE_PER_PIXEL;
}
- void reset() override
+ virtual void configure(input_device &device) override
{
- memset(&mouse, 0, sizeof(mouse));
- memset(&win32_mouse, 0, sizeof(win32_mouse));
+ // populate the axes
+ device.add_item(
+ "X",
+ std::string_view(),
+ ITEM_ID_XAXIS,
+ generic_axis_get_state<LONG>,
+ &m_mouse.lX);
+ device.add_item(
+ "Y",
+ std::string_view(),
+ ITEM_ID_YAXIS,
+ generic_axis_get_state<LONG>,
+ &m_mouse.lY);
+ device.add_item(
+ "Scroll V",
+ std::string_view(),
+ ITEM_ID_ZAXIS,
+ generic_axis_get_state<LONG>,
+ &m_mouse.lV);
+ device.add_item(
+ "Scroll H",
+ std::string_view(),
+ ITEM_ID_RZAXIS,
+ generic_axis_get_state<LONG>,
+ &m_mouse.lH);
+
+ // populate the buttons
+ for (int butnum = 0; butnum < 5; butnum++)
+ {
+ device.add_item(
+ default_button_name(butnum),
+ std::string_view(),
+ input_item_id(ITEM_ID_BUTTON1 + butnum),
+ generic_button_get_state<BYTE>,
+ &m_mouse.rgbButtons[butnum]);
+ }
+ }
+
+ virtual void reset() override
+ {
+ event_based_device::reset();
+ memset(&m_mouse, 0, sizeof(m_mouse));
+ memset(&m_win32_mouse, 0, sizeof(m_win32_mouse));
+ m_vscroll = m_hscroll = 0;
}
protected:
- void process_event(MouseButtonEventArgs &args) override
+ virtual void process_event(MouseUpdateEventArgs const &args) override
{
// set the button state
- mouse.rgbButtons[args.button] = args.keydown ? 0x80 : 0x00;
+ assert(!(args.pressed & args.released));
+ for (unsigned i = 0; 5 > i; ++i)
+ {
+ if (BIT(args.pressed, i))
+ m_mouse.rgbButtons[i] = 0x80;
+ else if (BIT(args.released, i))
+ m_mouse.rgbButtons[i] = 0x00;
+ }
- // Make sure we have a fresh mouse position on button down
- if (args.keydown)
- module().poll_if_necessary(machine());
+ // accumulate scroll delta
+ m_vscroll += args.vdelta;
+ m_hscroll += args.hdelta;
}
+
+private:
+ struct win32_mouse_state
+ {
+ POINT last_point;
+ };
+
+ mouse_state m_mouse;
+ win32_mouse_state m_win32_mouse;
+ long m_vscroll, m_hscroll;
};
+
//============================================================
// mouse_input_win32 - win32 mouse input module
//============================================================
-class mouse_input_win32 : public wininput_module
+class mouse_input_win32 : public wininput_module<win32_mouse_device>
{
public:
- mouse_input_win32()
- : wininput_module(OSD_MOUSEINPUT_PROVIDER, "win32")
+ mouse_input_win32() : wininput_module<win32_mouse_device>(OSD_MOUSEINPUT_PROVIDER, "win32")
{
}
virtual void input_init(running_machine &machine) override
{
- win32_mouse_device *devinfo;
- int axisnum, butnum;
+ wininput_module<win32_mouse_device>::input_init(machine);
- if (!input_enabled() || !mouse_enabled())
+ if (!options()->mouse())
return;
// allocate a device
- devinfo = devicelist()->create_device<win32_mouse_device>(machine, "Win32 Mouse 1", "Win32 Mouse 1", *this);
- if (devinfo == nullptr)
- return;
+ create_device<win32_mouse_device>(DEVICE_CLASS_MOUSE, "Win32 Mouse 1", "Win32 Mouse 1");
+ }
- // populate the axes
- for (axisnum = 0; axisnum < 2; axisnum++)
+ virtual bool handle_input_event(input_event eventid, void const *eventdata) override
+ {
+ if (manager().class_enabled(DEVICE_CLASS_MOUSE))
{
- devinfo->device()->add_item(
- default_axis_name[axisnum],
- static_cast<input_item_id>(ITEM_ID_XAXIS + axisnum),
- generic_axis_get_state<LONG>,
- &devinfo->mouse.lX + axisnum);
+ if ((eventid == INPUT_EVENT_MOUSE_BUTTON) || (eventid == INPUT_EVENT_MOUSE_WHEEL))
+ {
+ auto const *const args = reinterpret_cast<MouseUpdateEventArgs const *>(eventdata);
+ devicelist().for_each_device(
+ [args] (auto &device) { device.queue_events(args, 1); });
+ return true;
+ }
}
- // populate the buttons
- for (butnum = 0; butnum < 2; butnum++)
- {
- devinfo->device()->add_item(
- default_button_name(butnum),
- static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum),
- generic_button_get_state<BYTE>,
- &devinfo->mouse.rgbButtons[butnum]);
- }
+ return false;
}
+};
+
+
+//============================================================
+// win32_lightgun_device_base
+//============================================================
- bool handle_input_event(input_event eventid, void *eventdata) override
+class win32_lightgun_device_base : public event_based_device<MouseUpdateEventArgs>
+{
+public:
+ virtual void reset() override
{
- if (!input_enabled() || !mouse_enabled() || eventid != INPUT_EVENT_MOUSE_BUTTON)
- return false;
+ event_based_device::reset();
+ memset(&m_mouse, 0, sizeof(m_mouse));
+ }
- auto args = static_cast<MouseButtonEventArgs*>(eventdata);
- devicelist()->for_each_device([args](auto device)
+protected:
+ win32_lightgun_device_base(
+ std::string &&name,
+ std::string &&id,
+ input_module &module) :
+ event_based_device(std::move(name), std::move(id), module),
+ m_mouse({ 0 })
+ {
+ }
+
+ void do_configure(input_device &device, unsigned buttons)
+ {
+ // populate the axes
+ for (int axisnum = 0; axisnum < 2; axisnum++)
{
- auto mouse = dynamic_cast<win32_mouse_device*>(device);
- if (mouse != nullptr)
- mouse->queue_events(args, 1);
- });
+ device.add_item(
+ default_axis_name[axisnum],
+ std::string_view(),
+ input_item_id(ITEM_ID_XAXIS + axisnum),
+ generic_axis_get_state<LONG>,
+ &m_mouse.lX + axisnum);
+ }
- return true;
+ // populate the buttons
+ for (int butnum = 0; butnum < buttons; butnum++)
+ {
+ device.add_item(
+ default_button_name(butnum),
+ std::string_view(),
+ input_item_id(ITEM_ID_BUTTON1 + butnum),
+ generic_button_get_state<BYTE>,
+ &m_mouse.rgbButtons[butnum]);
+ }
}
+
+ mouse_state m_mouse;
};
+
+
//============================================================
// win32_lightgun_device
//============================================================
-class win32_lightgun_device : public event_based_device<MouseButtonEventArgs>
+class win32_lightgun_device : public win32_lightgun_device_base
{
-private:
- BOOL m_lightgun_shared_axis_mode;
- int m_gun_index;
-
public:
- mouse_state mouse;
-
- win32_lightgun_device(running_machine& machine, const char *name, const char *id, input_module &module)
- : event_based_device(machine, name, id, DEVICE_CLASS_LIGHTGUN, module),
- m_lightgun_shared_axis_mode(FALSE),
- m_gun_index(0),
- mouse({0})
+ win32_lightgun_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module) :
+ win32_lightgun_device_base(std::move(name), std::move(id), module),
+ m_vscroll(0),
+ m_hscroll(0)
{
- m_lightgun_shared_axis_mode = downcast<windows_options &>(machine.options()).dual_lightgun();
-
- // Since we are about to be added to the list, the current size is the zero-based index of where we will be
- m_gun_index = downcast<wininput_module&>(module).devicelist()->size();
}
- void poll() override
+ virtual void poll(bool relative_reset) override
{
- event_based_device::poll();
+ event_based_device::poll(relative_reset);
int32_t xpos = 0, ypos = 0;
- POINT mousepos;
-
- // if we are using the shared axis hack, the data is updated via Windows messages only
- if (m_lightgun_shared_axis_mode)
- return;
// get the cursor position and transform into final results
+ POINT mousepos;
GetCursorPos(&mousepos);
- if (!osd_common_t::s_window_list.empty())
+ if (!osd_common_t::window_list().empty())
{
- RECT client_rect;
-
// get the position relative to the window
- HWND hwnd = std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window();
+ HWND const hwnd = dynamic_cast<win_window_info &>(*osd_common_t::window_list().front()).platform_window();
+ RECT client_rect;
GetClientRect(hwnd, &client_rect);
ScreenToClient(hwnd, &mousepos);
@@ -302,149 +389,194 @@ public:
}
// update the X/Y positions
- mouse.lX = xpos;
- mouse.lY = ypos;
+ m_mouse.lX = xpos;
+ m_mouse.lY = ypos;
+
+ // update the scroll axes if appropriate
+ if (relative_reset)
+ {
+ m_mouse.lV = std::exchange(m_vscroll, 0) * input_device::RELATIVE_PER_PIXEL;
+ m_mouse.lH = std::exchange(m_hscroll, 0) * input_device::RELATIVE_PER_PIXEL;
+ }
+ }
+
+ virtual void configure(input_device &device) override
+ {
+ do_configure(device, 5);
+
+ // add scroll axes
+ device.add_item(
+ "Scroll V",
+ std::string_view(),
+ ITEM_ID_ADD_RELATIVE1,
+ generic_axis_get_state<LONG>,
+ &m_mouse.lV);
+ device.add_item(
+ "Scroll H",
+ std::string_view(),
+ ITEM_ID_ADD_RELATIVE2,
+ generic_axis_get_state<LONG>,
+ &m_mouse.lH);
}
- void reset() override
+ virtual void reset() override
{
- memset(&mouse, 0, sizeof(mouse));
+ win32_lightgun_device_base::reset();
+ m_vscroll = m_hscroll = 0;
}
protected:
- void process_event(MouseButtonEventArgs &args) override
+ virtual void process_event(MouseUpdateEventArgs const &args) override
{
- // Are we in shared axis mode?
- if (m_lightgun_shared_axis_mode)
- {
- handle_shared_axis_mode(args);
- }
- else
+ // In non-shared axis mode, just update the button state
+ assert(!(args.pressed & args.released));
+ for (unsigned i = 0; 5 > i; ++i)
{
- // In non-shared axis mode, just update the button state
- mouse.rgbButtons[args.button] = args.keydown ? 0x80 : 0x00;
+ if (BIT(args.pressed, i))
+ m_mouse.rgbButtons[i] = 0x80;
+ else if (BIT(args.released, i))
+ m_mouse.rgbButtons[i] = 0x00;
}
+
+ // accumulate scroll delta
+ m_vscroll += args.vdelta;
+ m_hscroll += args.hdelta;
}
private:
- void handle_shared_axis_mode(MouseButtonEventArgs &args)
- {
- int button = args.button;
+ long m_vscroll, m_hscroll;
+};
- // We only handle the first four buttons in shared axis mode
- if (button > 3)
- return;
- // First gun doesn't handle buttons 2 & 3
- if (button >= 2 && m_gun_index == 0)
- return;
+//============================================================
+// win32_dual_lightgun_device
+//============================================================
- // Second gun doesn't handle buttons 0 & 1
- if (button < 2 && m_gun_index == 1)
- return;
+class win32_dual_lightgun_device : public win32_lightgun_device_base
+{
+public:
+ win32_dual_lightgun_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ int index) :
+ win32_lightgun_device_base(std::move(name), std::move(id), module),
+ m_gun_index(index)
+ {
+ }
- // Adjust the button if we're the second lightgun
- int logical_button = m_gun_index == 1 ? button - 2 : button;
+ virtual void configure(input_device &device) override
+ {
+ do_configure(device, 2);
+ }
- // set the button state
- mouse.rgbButtons[logical_button] = args.keydown ? 0x80 : 0x00;
- if (args.keydown)
+protected:
+ virtual void process_event(MouseUpdateEventArgs const &args) override
+ {
+ // We only handle the first four buttons in shared axis mode
+ assert(!(args.pressed & args.released));
+ for (unsigned i = 0; 2 > i; ++i)
{
- RECT client_rect;
- POINT mousepos;
+ // Adjust the button if we're the second lightgun
+ unsigned const bit = i + ((1 == m_gun_index) ? 2 : 0);
+ if (BIT(args.pressed, bit))
+ {
+ m_mouse.rgbButtons[i] = 0x80;
- // get the position relative to the window
- HWND hwnd = std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window();
- GetClientRect(hwnd, &client_rect);
- mousepos.x = args.xpos;
- mousepos.y = args.ypos;
- ScreenToClient(hwnd, &mousepos);
+ // get the position relative to the window
+ HWND const hwnd = dynamic_cast<win_window_info &>(*osd_common_t::window_list().front()).platform_window();
+ RECT client_rect;
+ GetClientRect(hwnd, &client_rect);
- // convert to absolute coordinates
- mouse.lX = normalize_absolute_axis(mousepos.x, client_rect.left, client_rect.right);
- mouse.lY = normalize_absolute_axis(mousepos.y, client_rect.top, client_rect.bottom);
+ POINT mousepos;
+ mousepos.x = args.xpos;
+ mousepos.y = args.ypos;
+ ScreenToClient(hwnd, &mousepos);
+
+ // convert to absolute coordinates
+ m_mouse.lX = normalize_absolute_axis(mousepos.x, client_rect.left, client_rect.right);
+ m_mouse.lY = normalize_absolute_axis(mousepos.y, client_rect.top, client_rect.bottom);
+ }
+ else if (BIT(args.released, bit))
+ {
+ m_mouse.rgbButtons[i] = 0x00;
+ }
}
}
+
+private:
+ int const m_gun_index;
};
+
//============================================================
// lightgun_input_win32 - win32 lightgun input module
//============================================================
-class lightgun_input_win32 : public wininput_module
+class lightgun_input_win32 : public wininput_module<win32_lightgun_device_base>
{
public:
- lightgun_input_win32()
- : wininput_module(OSD_LIGHTGUNINPUT_PROVIDER, "win32")
- {
- }
-
- int init_internal() override
+ lightgun_input_win32() : wininput_module<win32_lightgun_device_base>(OSD_LIGHTGUNINPUT_PROVIDER, "win32")
{
- return 0;
}
virtual void input_init(running_machine &machine) override
{
- int max_guns = downcast<windows_options&>(machine.options()).dual_lightgun() ? 2 : 1;
+ wininput_module<win32_lightgun_device_base>::input_init(machine);
+
+ bool const shared_axis_mode = dynamic_cast<windows_options const &>(*options()).dual_lightgun();
+ int const max_guns = shared_axis_mode ? 2 : 1;
// allocate the lightgun devices
for (int gunnum = 0; gunnum < max_guns; gunnum++)
{
static const char *const gun_names[] = { "Win32 Gun 1", "Win32 Gun 2" };
- win32_lightgun_device *devinfo;
- int axisnum, butnum;
// allocate a device
- devinfo = devicelist()->create_device<win32_lightgun_device>(machine, gun_names[gunnum], gun_names[gunnum], *this);
- if (devinfo == nullptr)
- break;
-
- // populate the axes
- for (axisnum = 0; axisnum < 2; axisnum++)
- {
- devinfo->device()->add_item(
- default_axis_name[axisnum],
- static_cast<input_item_id>(ITEM_ID_XAXIS + axisnum),
- generic_axis_get_state<LONG>,
- &devinfo->mouse.lX + axisnum);
- }
-
- // populate the buttons
- for (butnum = 0; butnum < 2; butnum++)
- {
- devinfo->device()->add_item(
- default_button_name(butnum),
- static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum),
- generic_button_get_state<BYTE>,
- &devinfo->mouse.rgbButtons[butnum]);
- }
+ if (shared_axis_mode)
+ create_device<win32_dual_lightgun_device>(DEVICE_CLASS_LIGHTGUN, gun_names[gunnum], gun_names[gunnum], gunnum);
+ else
+ create_device<win32_lightgun_device>(DEVICE_CLASS_LIGHTGUN, gun_names[gunnum], gun_names[gunnum]);
}
}
- bool handle_input_event(input_event eventid, void* eventdata) override
+ virtual bool handle_input_event(input_event eventid, void const *eventdata) override
{
- if (!input_enabled() || !lightgun_enabled() || eventid != INPUT_EVENT_MOUSE_BUTTON)
- return false;
-
- auto args = static_cast<MouseButtonEventArgs*>(eventdata);
- devicelist()->for_each_device([args](auto device)
+ if (manager().class_enabled(DEVICE_CLASS_LIGHTGUN))
{
- auto lightgun = dynamic_cast<win32_lightgun_device*>(device);
- if (lightgun != nullptr)
- lightgun->queue_events(args, 1);
- });
+ if ((eventid == INPUT_EVENT_MOUSE_BUTTON) || (eventid == INPUT_EVENT_MOUSE_WHEEL))
+ {
+ auto const *const args = reinterpret_cast<MouseUpdateEventArgs const *>(eventdata);
+ devicelist().for_each_device(
+ [args] (auto &device) { device.queue_events(args, 1); });
+ return true;
+ }
+ }
- return true;
+ return false;
}
};
-#else
+} // anonymous namespace
+
+} // namespace osd
+
+#else // defined(OSD_WINDOWS)
+
+namespace osd {
+
+namespace {
+
MODULE_NOT_SUPPORTED(keyboard_input_win32, OSD_KEYBOARDINPUT_PROVIDER, "win32")
MODULE_NOT_SUPPORTED(mouse_input_win32, OSD_MOUSEINPUT_PROVIDER, "win32")
MODULE_NOT_SUPPORTED(lightgun_input_win32, OSD_LIGHTGUNINPUT_PROVIDER, "win32")
-#endif
-MODULE_DEFINITION(KEYBOARDINPUT_WIN32, keyboard_input_win32)
-MODULE_DEFINITION(MOUSEINPUT_WIN32, mouse_input_win32)
-MODULE_DEFINITION(LIGHTGUNINPUT_WIN32, lightgun_input_win32)
+} // anonymous namespace
+
+} // namespace osd
+
+#endif // defined(OSD_WINDOWS)
+
+MODULE_DEFINITION(KEYBOARDINPUT_WIN32, osd::keyboard_input_win32)
+MODULE_DEFINITION(MOUSEINPUT_WIN32, osd::mouse_input_win32)
+MODULE_DEFINITION(LIGHTGUNINPUT_WIN32, osd::lightgun_input_win32)
diff --git a/src/osd/modules/input/input_wincommon.h b/src/osd/modules/input/input_wincommon.h
new file mode 100644
index 00000000000..6b34d60abca
--- /dev/null
+++ b/src/osd/modules/input/input_wincommon.h
@@ -0,0 +1,40 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+//============================================================
+//
+// input_wincommon.h - Common code used by Windows input modules
+//
+//============================================================
+#ifndef MAME_OSD_INPUT_INPUT_WINCOMMON_H
+#define MAME_OSD_INPUT_INPUT_WINCOMMON_H
+
+#pragma once
+
+#include "input_common.h"
+
+#include <windows.h>
+
+
+namespace osd {
+
+// state information for a keyboard
+struct keyboard_state
+{
+ uint8_t state[MAX_KEYS];
+ int8_t oldkey[MAX_KEYS];
+ int8_t currkey[MAX_KEYS];
+};
+
+// state information for a mouse
+struct mouse_state
+{
+ LONG lX;
+ LONG lY;
+ LONG lV;
+ LONG lH;
+ BYTE rgbButtons[8];
+};
+
+} // namespace osd
+
+#endif // MAME_OSD_INPUT_INPUT_WINCOMMON_H
diff --git a/src/osd/modules/input/input_windows.cpp b/src/osd/modules/input/input_windows.cpp
index 164ee0e3c31..12002ccf893 100644
--- a/src/osd/modules/input/input_windows.cpp
+++ b/src/osd/modules/input/input_windows.cpp
@@ -8,123 +8,109 @@
#include "input_module.h"
-#if defined(OSD_WINDOWS) || defined(OSD_UWP)
+#if defined(OSD_WINDOWS)
// MAME headers
#include "emu.h"
-#include "osdepend.h"
-// MAMEOS headers
+#include "input_windows.h"
+
+#include "window.h"
#include "winmain.h"
-#include "input_common.h"
-#include "input_windows.h"
+#include "util/language.h"
-bool windows_osd_interface::should_hide_mouse() const
-{
- bool hidemouse = false;
- wininput_module* mod;
+#include "osdepend.h"
- mod = dynamic_cast<wininput_module*>(m_keyboard_input);
- if (mod) hidemouse |= mod->should_hide_mouse();
- mod = dynamic_cast<wininput_module*>(m_mouse_input);
- if (mod) hidemouse |= mod->should_hide_mouse();
+bool windows_osd_interface::should_hide_mouse() const
+{
+ if (!winwindow_has_focus())
+ return false;
- mod = dynamic_cast<wininput_module*>(m_lightgun_input);
- if (mod) hidemouse |= mod->should_hide_mouse();
+ if (machine().paused())
+ return false;
- mod = dynamic_cast<wininput_module*>(m_joystick_input);
- if (mod) hidemouse |= mod->should_hide_mouse();
+ // track if mouse/lightgun is enabled, for mouse hiding purposes
+ bool const mouse_enabled = machine().input().class_enabled(DEVICE_CLASS_MOUSE);
+ bool const lightgun_enabled = machine().input().class_enabled(DEVICE_CLASS_LIGHTGUN);
+ if (!mouse_enabled && !lightgun_enabled)
+ return false;
- return hidemouse;
+ return true;
}
-bool windows_osd_interface::handle_input_event(input_event eventid, void* eventdata) const
+bool windows_osd_interface::handle_input_event(input_event eventid, void const *eventdata) const
{
bool handled = false;
- wininput_module* mod;
+ wininput_event_handler *mod;
- mod = dynamic_cast<wininput_module*>(m_keyboard_input);
- if (mod) handled |= mod->handle_input_event(eventid, eventdata);
+ mod = dynamic_cast<wininput_event_handler *>(m_keyboard_input);
+ if (mod)
+ handled |= mod->handle_input_event(eventid, eventdata);
- mod = dynamic_cast<wininput_module*>(m_mouse_input);
- if (mod) handled |= mod->handle_input_event(eventid, eventdata);
+ mod = dynamic_cast<wininput_event_handler *>(m_mouse_input);
+ if (mod)
+ handled |= mod->handle_input_event(eventid, eventdata);
- mod = dynamic_cast<wininput_module*>(m_lightgun_input);
- if (mod) handled |= mod->handle_input_event(eventid, eventdata);
+ mod = dynamic_cast<wininput_event_handler *>(m_lightgun_input);
+ if (mod)
+ handled |= mod->handle_input_event(eventid, eventdata);
- mod = dynamic_cast<wininput_module*>(m_joystick_input);
- if (mod) handled |= mod->handle_input_event(eventid, eventdata);
+ mod = dynamic_cast<wininput_event_handler *>(m_joystick_input);
+ if (mod)
+ handled |= mod->handle_input_event(eventid, eventdata);
return handled;
}
-void windows_osd_interface::poll_input(running_machine &machine) const
-{
- m_keyboard_input->poll_if_necessary(machine);
- m_mouse_input->poll_if_necessary(machine);
- m_lightgun_input->poll_if_necessary(machine);
- m_joystick_input->poll_if_necessary(machine);
-}
-
//============================================================
// customize_input_type_list
//============================================================
-void windows_osd_interface::customize_input_type_list(simple_list<input_type_entry> &typelist)
+void windows_osd_interface::customize_input_type_list(std::vector<input_type_entry> &typelist)
{
- const char* uimode;
-
// loop over the defaults
for (input_type_entry &entry : typelist)
switch (entry.type())
{
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
// disable the config menu if the ALT key is down
// (allows ALT-TAB to switch between windows apps)
- case IPT_UI_CONFIGURE:
+ case IPT_UI_MENU:
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_TAB, input_seq::not_code, KEYCODE_LALT, input_seq::not_code, KEYCODE_RALT);
break;
-#else
- // UWP: Hotkey Select + X => UI_CONFIGURE (Menu)
- case IPT_UI_CONFIGURE:
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_TAB, input_seq::or_code, JOYCODE_SELECT, JOYCODE_BUTTON3);
- break;
- // UWP: Hotkey Select + Start => CANCEL
- case IPT_UI_CANCEL:
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_ESC, input_seq::or_code, JOYCODE_SELECT, JOYCODE_START);
- break;
-#endif
// configurable UI mode switch
case IPT_UI_TOGGLE_UI:
- uimode = options().ui_mode_key();
- if (strcmp(uimode, "auto"))
{
- std::string fullmode = "ITEM_ID_";
- fullmode += uimode;
- input_item_id const mameid_code = keyboard_trans_table::instance().lookup_mame_code(fullmode.c_str());
- if (ITEM_ID_INVALID != mameid_code)
+ char const *const uimode = options().ui_mode_key();
+ if (uimode && *uimode && strcmp(uimode, "auto"))
{
- input_code const ui_code = input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, input_item_id(mameid_code));
- entry.defseq(SEQ_TYPE_STANDARD).set(ui_code);
+ std::string fullmode("ITEM_ID_");
+ fullmode.append(uimode);
+ input_item_id const mameid_code = keyboard_trans_table::instance().lookup_mame_code(fullmode.c_str());
+ if (ITEM_ID_INVALID != mameid_code)
+ {
+ input_code const ui_code = input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, input_item_id(mameid_code));
+ entry.defseq(SEQ_TYPE_STANDARD).set(ui_code);
+ }
}
}
break;
// alt-enter for fullscreen
case IPT_OSD_1:
- entry.configure_osd("TOGGLE_FULLSCREEN", "Toggle Fullscreen");
+ entry.configure_osd("TOGGLE_FULLSCREEN", N_p("input-name", "Toggle Fullscreen"));
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_ENTER, KEYCODE_LALT, input_seq::or_code, KEYCODE_ENTER, KEYCODE_RALT);
break;
// lalt-F12 for fullscreen snap (HLSL)
case IPT_OSD_2:
- entry.configure_osd("RENDER_SNAP", "Take Rendered Snapshot");
+ entry.configure_osd("RENDER_SNAP", N_p("input-name", "Take Rendered Snapshot"));
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, KEYCODE_LALT, input_seq::not_code, KEYCODE_LSHIFT);
break;
+
// add a NOT-lalt to our default F12
case IPT_UI_SNAPSHOT: // emu/input.c: input_seq(KEYCODE_F12, input_seq::not_code, KEYCODE_LSHIFT)
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_LALT);
@@ -132,7 +118,7 @@ void windows_osd_interface::customize_input_type_list(simple_list<input_type_ent
// lshift-lalt-F12 for fullscreen video (HLSL, BGFX)
case IPT_OSD_3:
- entry.configure_osd("RENDER_AVI", "Record Rendered Video");
+ entry.configure_osd("RENDER_AVI", N_p("input-name", "Record Rendered Video"));
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, KEYCODE_LSHIFT, KEYCODE_LALT);
break;
@@ -146,19 +132,15 @@ void windows_osd_interface::customize_input_type_list(simple_list<input_type_ent
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, KEYCODE_LSHIFT, KEYCODE_LCONTROL, input_seq::not_code, KEYCODE_LALT);
break;
- // add a NOT-lalt to write timecode file
- case IPT_UI_TIMECODE: // emu/input.c: input_seq(KEYCODE_F12, input_seq::not_code, KEYCODE_LSHIFT)
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_LALT);
- break;
-
- // lctrl-lalt-F5 to toggle post-processing
+ // lalt-F10 to toggle post-processing
case IPT_OSD_4:
- entry.configure_osd("POST_PROCESS", "Toggle Post-Processing");
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F5, KEYCODE_LALT, KEYCODE_LCONTROL);
+ entry.configure_osd("POST_PROCESS", N_p("input-name", "Toggle Post-Processing"));
+ entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F10, KEYCODE_LALT);
break;
- // add a NOT-lctrl-lalt to our default F5
- case IPT_UI_TOGGLE_DEBUG: // emu/input.c: input_seq(KEYCODE_F5)
- entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F5, input_seq::not_code, KEYCODE_LCONTROL, input_seq::not_code, KEYCODE_LALT);
+
+ // add a Not LALT condition to the throttle key
+ case IPT_UI_THROTTLE:
+ entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F10, input_seq::not_code, KEYCODE_LALT);
break;
// leave everything else alone
@@ -167,4 +149,4 @@ void windows_osd_interface::customize_input_type_list(simple_list<input_type_ent
}
}
-#endif
+#endif // defined(OSD_WINDOWS)
diff --git a/src/osd/modules/input/input_windows.h b/src/osd/modules/input/input_windows.h
index 7afc487fb62..882f80d053b 100644
--- a/src/osd/modules/input/input_windows.h
+++ b/src/osd/modules/input/input_windows.h
@@ -5,83 +5,44 @@
// input_windows.h - Common code used by Windows input modules
//
//============================================================
+#ifndef MAME_OSD_INPUT_INPUT_WINDOWS_H
+#define MAME_OSD_INPUT_INPUT_WINDOWS_H
-#ifndef INPUT_WIN_H_
-#define INPUT_WIN_H_
+#pragma once
-// standard windows headers
-#include <windows.h>
-#undef interface
+#include "input_common.h"
#include "window.h"
#include "winmain.h"
+// standard windows headers
+#include <windows.h>
+
+
//============================================================
// TYPEDEFS
//============================================================
-// state information for a keyboard
-struct keyboard_state
-{
- uint8_t state[MAX_KEYS];
- int8_t oldkey[MAX_KEYS];
- int8_t currkey[MAX_KEYS];
-};
-
-// state information for a mouse (matches DIMOUSESTATE exactly)
-struct mouse_state
-{
- LONG lX;
- LONG lY;
- LONG lZ;
- BYTE rgbButtons[8];
-};
-class wininput_module : public input_module_base
+class wininput_event_handler
{
protected:
- bool m_global_inputs_enabled;
+ wininput_event_handler() = default;
+ virtual ~wininput_event_handler() = default;
public:
- wininput_module(const char * type, const char * name)
- : input_module_base(type, name),
- m_global_inputs_enabled(false)
+ virtual bool handle_input_event(input_event eventid, void const *data)
{
- }
-
- virtual ~wininput_module() { }
-
- virtual bool should_hide_mouse()
- {
- if (winwindow_has_focus() // has focus
- && (!video_config.windowed || !osd_common_t::s_window_list.front()->win_has_menu()) // not windowed or doesn't have a menu
- && (input_enabled() && !input_paused()) // input enabled and not paused
- && (mouse_enabled() || lightgun_enabled())) // either mouse or lightgun enabled in the core
- {
- return true;
- }
-
return false;
}
+};
- virtual bool handle_input_event(input_event eventid, void* data)
- {
- return false;
- }
+template <typename Info>
+class wininput_module : public input_module_impl<Info, osd_common_t>, public wininput_event_handler
+{
protected:
-
- void before_poll(running_machine& machine) override
- {
- // periodically process events, in case they're not coming through
- // this also will make sure the mouse state is up-to-date
- winwindow_process_events_periodic(machine);
- }
-
- bool should_poll_devices(running_machine &machine) override
- {
- return input_enabled() && (m_global_inputs_enabled || winwindow_has_focus());
- }
+ using input_module_impl<Info, osd_common_t>::input_module_impl;
};
-#endif
+#endif // MAME_OSD_INPUT_INPUT_WINDOWS_H
diff --git a/src/osd/modules/input/input_winhybrid.cpp b/src/osd/modules/input/input_winhybrid.cpp
index 1436ae009d6..2f1023e24fb 100644
--- a/src/osd/modules/input/input_winhybrid.cpp
+++ b/src/osd/modules/input/input_winhybrid.cpp
@@ -6,48 +6,31 @@
//
//============================================================
-#include "input_module.h"
#include "modules/osdmodule.h"
-#if defined(OSD_WINDOWS)
+#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
+
+#include "input_dinput.h"
+#include "input_xinput.h"
-#include <list>
#include <vector>
-// standard windows headers
-#include <windows.h>
-#include <wrl/client.h>
+#include <oleauto.h>
#include <wbemcli.h>
-// XInput/DirectInput
-#include <xinput.h>
-#include <dinput.h>
-
-#undef interface
-// MAME headers
-#include "emu.h"
-
-// MAMEOS headers
-#include "strconv.h"
-#include "winmain.h"
-
-#include "input_common.h"
-#include "input_windows.h"
-#include "input_xinput.h"
-#include "input_dinput.h"
+namespace osd {
-using namespace Microsoft::WRL;
+namespace {
-template<class TCom>
+template <class TCom>
class ComArray
{
private:
- std::vector<TCom*> m_entries;
+ std::vector<TCom *> m_entries;
public:
- ComArray(size_t capacity)
- : m_entries(capacity, nullptr)
+ ComArray(size_t capacity) : m_entries(capacity, nullptr)
{
}
@@ -56,7 +39,7 @@ public:
Release();
}
- TCom** ReleaseAndGetAddressOf()
+ TCom **ReleaseAndGetAddressOf()
{
Release();
@@ -64,7 +47,7 @@ public:
return &m_entries[0];
}
- TCom* operator [] (int i)
+ TCom *operator[](int i)
{
return m_entries[i];
}
@@ -76,12 +59,12 @@ public:
void Release()
{
- for (int i = 0; i < m_entries.size(); i++)
+ for (auto &entry : m_entries)
{
- if (m_entries[i] != nullptr)
+ if (entry)
{
- m_entries[i]->Release();
- m_entries[i] = nullptr;
+ entry->Release();
+ entry = nullptr;
}
}
}
@@ -91,7 +74,7 @@ struct bstr_deleter
{
void operator () (BSTR bstr) const
{
- if (bstr != nullptr)
+ if (bstr)
SysFreeString(bstr);
}
};
@@ -104,8 +87,8 @@ private:
public:
variant_wrapper()
- : m_variant({0})
{
+ VariantInit(&m_variant);
}
~variant_wrapper()
@@ -133,28 +116,24 @@ public:
typedef std::unique_ptr<OLECHAR, bstr_deleter> bstr_ptr;
+
//============================================================
// winhybrid_joystick_module
//============================================================
-class winhybrid_joystick_module : public wininput_module, public device_enum_interface
+class winhybrid_joystick_module : public input_module_impl<device_info, osd_common_t>
{
private:
- std::shared_ptr<xinput_api_helper> m_xinput_helper;
+ std::unique_ptr<xinput_api_helper> m_xinput_helper;
std::unique_ptr<dinput_api_helper> m_dinput_helper;
- std::list<DWORD> m_xinput_deviceids;
- bool m_xinput_detect_failed;
public:
- winhybrid_joystick_module()
- : wininput_module(OSD_JOYSTICKINPUT_PROVIDER, "winhybrid"),
- m_xinput_helper(nullptr),
- m_dinput_helper(nullptr),
- m_xinput_detect_failed(false)
+ winhybrid_joystick_module() :
+ input_module_impl<device_info, osd_common_t>(OSD_JOYSTICKINPUT_PROVIDER, "winhybrid")
{
}
- bool probe() override
+ virtual bool probe() override
{
int status = init_helpers();
if (status != 0)
@@ -166,10 +145,12 @@ public:
return true;
}
- int init(const osd_options &options) override
+ virtual int init(osd_interface &osd, const osd_options &options) override
{
+ int status;
+
// Call the base
- int status = wininput_module::init(options);
+ status = input_module_impl<device_info, osd_common_t>::init(osd, options);
if (status != 0)
return status;
@@ -184,129 +165,116 @@ public:
return 0;
}
- BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
+ virtual void input_init(running_machine &machine) override
{
- dinput_cooperative_level cooperative_level = dinput_cooperative_level::FOREGROUND;
- running_machine &machine = *static_cast<running_machine *>(ref);
- dinput_joystick_device *devinfo;
- int result = 0;
-
- // First check if this device is XInput Compatible. If so, don't add it here
- // as it'll be picked up by Xinput
- if (!m_xinput_detect_failed && is_xinput_device(&instance->guidProduct))
- {
- osd_printf_verbose("Skipping DirectInput for XInput compatible joystick %S.\n", instance->tszInstanceName);
- goto exit;
- }
+ input_module_impl<device_info, osd_common_t>::input_init(machine);
- if (!osd_common_t::s_window_list.empty() && osd_common_t::s_window_list.front()->win_has_menu())
- cooperative_level = dinput_cooperative_level::BACKGROUND;
-
- // allocate and link in a new device
- devinfo = m_dinput_helper->create_device<dinput_joystick_device>(machine, *this, instance, &c_dfDIJoystick, nullptr, cooperative_level);
- if (devinfo == nullptr)
- goto exit;
-
- result = devinfo->configure();
+ bool xinput_detect_failed = false;
+ std::vector<DWORD> xinput_deviceids;
+ HRESULT result = get_xinput_devices(xinput_deviceids);
if (result != 0)
{
- osd_printf_error("Failed to configure DI Joystick device. Error 0x%x\n", static_cast<unsigned int>(result));
+ xinput_detect_failed = true;
+ xinput_deviceids.clear();
+ osd_printf_warning("XInput device detection failed. XInput won't be used. Error: 0x%X\n", uint32_t(result));
}
- exit:
- return DIENUM_CONTINUE;
- }
-
- void exit() override
- {
- m_xinput_helper.reset();
- m_dinput_helper.reset();
-
- wininput_module::exit();
- }
-
-protected:
- virtual void input_init(running_machine &machine) override
- {
- HRESULT result = get_xinput_devices(m_xinput_deviceids);
- if (result != 0)
- {
- m_xinput_detect_failed = true;
- osd_printf_warning("XInput device detection failed. XInput won't be used. Error: 0x%X\n", static_cast<unsigned int>(result));
- }
+ // Enumerate all the DirectInput joysticks and add them if they aren't XInput compatible
+ result = m_dinput_helper->enum_attached_devices(
+ DI8DEVCLASS_GAMECTRL,
+ [this, &xinput_deviceids] (LPCDIDEVICEINSTANCE instance)
+ {
+ // First check if this device is XInput compatible.
+ // If so, don't add it here as it'll be picked up by Xinput.
+ auto const found = std::find(
+ xinput_deviceids.begin(),
+ xinput_deviceids.end(),
+ instance->guidProduct.Data1);
+ if (xinput_deviceids.end() != found)
+ {
+ osd_printf_verbose("Skipping DirectInput for XInput compatible joystick %S.\n", instance->tszInstanceName);
+ return DIENUM_CONTINUE;
+ }
- // Enumerate all the directinput joysticks and add them if they aren't xinput compatible
- result = m_dinput_helper->enum_attached_devices(DI8DEVCLASS_GAMECTRL, this, &machine);
+ // allocate and link in a new device
+ auto devinfo = m_dinput_helper->create_device<dinput_joystick_device>(
+ *this,
+ instance,
+ &c_dfDIJoystick,
+ nullptr,
+ background_input() ? dinput_cooperative_level::BACKGROUND : dinput_cooperative_level::FOREGROUND,
+ [] (auto const &device, auto const &format) -> bool
+ {
+ // set absolute mode
+ HRESULT const result = dinput_api_helper::set_dword_property(
+ device,
+ DIPROP_AXISMODE,
+ 0,
+ DIPH_DEVICE,
+ DIPROPAXISMODE_ABS);
+ if ((result != DI_OK) && (result != DI_PROPNOEFFECT))
+ {
+ osd_printf_error("DirectInput: Unable to set absolute mode for joystick.\n");
+ return false;
+ }
+ return true;
+ });
+ if (devinfo)
+ add_device(DEVICE_CLASS_JOYSTICK, std::move(devinfo));
+
+ return DIENUM_CONTINUE;
+ });
if (result != DI_OK)
- fatalerror("DirectInput: Unable to enumerate keyboards (result=%08X)\n", static_cast<uint32_t>(result));
-
- xinput_joystick_device *devinfo;
+ fatalerror("DirectInput: Unable to enumerate game controllers (result=%08X).\n", uint32_t(result));
// now add all xinput devices
- if (!m_xinput_detect_failed)
+ if (!xinput_detect_failed)
{
// Loop through each gamepad to determine if they are connected
for (UINT i = 0; i < XUSER_MAX_COUNT; i++)
{
- XINPUT_STATE state = { 0 };
-
- if (m_xinput_helper->xinput_get_state(i, &state) == ERROR_SUCCESS)
- {
- // allocate and link in a new device
- devinfo = m_xinput_helper->create_xinput_device(machine, i, *this);
- if (devinfo == nullptr)
- continue;
-
- // Configure each gamepad to add buttons and Axes, etc.
- devinfo->configure();
- }
+ // allocate and link in a new device
+ auto devinfo = m_xinput_helper->create_xinput_device(i, *this);
+ if (devinfo)
+ add_device(DEVICE_CLASS_JOYSTICK, std::move(devinfo));
}
}
}
+ virtual void exit() override
+ {
+ input_module_impl<device_info, osd_common_t>::exit();
+
+ m_xinput_helper.reset();
+ m_dinput_helper.reset();
+ }
+
private:
int init_helpers()
{
- int status = 0;
-
- if (m_xinput_helper == nullptr)
+ if (!m_xinput_helper)
{
- m_xinput_helper = std::make_shared<xinput_api_helper>();
- status = m_xinput_helper->initialize();
+ m_xinput_helper = std::make_unique<xinput_api_helper>();
+ int const status = m_xinput_helper->initialize();
if (status != 0)
{
- osd_printf_verbose("xinput_api_helper failed to initialize! Error: %u\n", static_cast<unsigned int>(status));
+ osd_printf_verbose("Failed to initialize XInput API! Error: %u\n", static_cast<unsigned int>(status));
return -1;
}
}
- if (m_dinput_helper == nullptr)
+ if (!m_dinput_helper)
{
- m_dinput_helper = std::make_unique<dinput_api_helper>(DIRECTINPUT_VERSION);
- status = m_dinput_helper->initialize();
+ m_dinput_helper = std::make_unique<dinput_api_helper>();
+ int const status = m_dinput_helper->initialize();
if (status != DI_OK)
{
- osd_printf_verbose("dinput_api_helper failed to initialize! Error: %u\n", static_cast<unsigned int>(status));
+ osd_printf_verbose("Failed to initialize DirectInput API! Error: %u\n", static_cast<unsigned int>(status));
return -1;
}
}
- return status;
- }
-
- //-----------------------------------------------------------------------------
- // Returns true if the DirectInput device is also an XInput device.
- //-----------------------------------------------------------------------------
- bool is_xinput_device(const GUID* pGuidProductFromDirectInput)
- {
- // Check each xinput device to see if this device's vid/pid matches
- for (auto devid = m_xinput_deviceids.begin(); devid != m_xinput_deviceids.end(); ++devid)
- {
- if (*devid == pGuidProductFromDirectInput->Data1)
- return true;
- }
-
- return false;
+ return 0;
}
//-----------------------------------------------------------------------------
@@ -316,54 +284,43 @@ private:
// Checking against a VID/PID of 0x028E/0x045E won't find 3rd party or future
// XInput devices.
//-----------------------------------------------------------------------------
- HRESULT get_xinput_devices(std::list<DWORD> &xinput_id_list) const
+ HRESULT get_xinput_devices(std::vector<DWORD> &xinput_deviceids)
{
- ComPtr<IWbemServices> pIWbemServices;
- ComPtr<IEnumWbemClassObject> pEnumDevices;
- ComPtr<IWbemLocator> pIWbemLocator;
- ComArray<IWbemClassObject> pDevices(20);
- bstr_ptr bstrDeviceID;
- bstr_ptr bstrClassName;
- bstr_ptr bstrNamespace;
- DWORD uReturned = 0;
- UINT iDevice;
- variant_wrapper var;
- HRESULT hr;
+ xinput_deviceids.clear();
- // CoInit if needed
- CoInitialize(nullptr);
+ HRESULT hr;
// Create WMI
+ Microsoft::WRL::ComPtr<IWbemLocator> pIWbemLocator;
hr = CoCreateInstance(
- __uuidof(WbemLocator),
- nullptr,
- CLSCTX_INPROC_SERVER,
- __uuidof(IWbemLocator),
- reinterpret_cast<void**>(pIWbemLocator.GetAddressOf()));
-
- if (FAILED(hr) || pIWbemLocator == nullptr)
+ __uuidof(WbemLocator),
+ nullptr,
+ CLSCTX_INPROC_SERVER,
+ __uuidof(IWbemLocator),
+ reinterpret_cast<void **>(pIWbemLocator.GetAddressOf()));
+ if (FAILED(hr) || !pIWbemLocator)
{
osd_printf_error("Creating WbemLocator failed. Error: 0x%X\n", static_cast<unsigned int>(hr));
return hr;
}
// Create BSTRs for WMI
- bstrNamespace = bstr_ptr(SysAllocString(L"\\\\.\\root\\cimv2"));
- bstrDeviceID = bstr_ptr(SysAllocString(L"DeviceID"));
- bstrClassName = bstr_ptr(SysAllocString(L"Win32_PNPEntity"));
+ bstr_ptr bstrNamespace = bstr_ptr(SysAllocString(L"\\\\.\\root\\cimv2"));
+ bstr_ptr bstrDeviceID = bstr_ptr(SysAllocString(L"DeviceID"));
+ bstr_ptr bstrClassName = bstr_ptr(SysAllocString(L"Win32_PNPEntity"));
// Connect to WMI
+ Microsoft::WRL::ComPtr<IWbemServices> pIWbemServices;
hr = pIWbemLocator->ConnectServer(
- bstrNamespace.get(),
- nullptr,
- nullptr,
- nullptr,
- 0L,
- nullptr,
- nullptr,
- pIWbemServices.GetAddressOf());
-
- if (FAILED(hr) || pIWbemServices == nullptr)
+ bstrNamespace.get(),
+ nullptr,
+ nullptr,
+ nullptr,
+ 0L,
+ nullptr,
+ nullptr,
+ pIWbemServices.GetAddressOf());
+ if (FAILED(hr) || !pIWbemServices)
{
osd_printf_error("Connecting to WMI Server failed. Error: 0x%X\n", static_cast<unsigned int>(hr));
return hr;
@@ -371,38 +328,41 @@ private:
// Switch security level to IMPERSONATE
(void)CoSetProxyBlanket(
- pIWbemServices.Get(),
- RPC_C_AUTHN_WINNT,
- RPC_C_AUTHZ_NONE,
- nullptr,
- RPC_C_AUTHN_LEVEL_CALL,
- RPC_C_IMP_LEVEL_IMPERSONATE,
- nullptr,
- 0);
+ pIWbemServices.Get(),
+ RPC_C_AUTHN_WINNT,
+ RPC_C_AUTHZ_NONE,
+ nullptr,
+ RPC_C_AUTHN_LEVEL_CALL,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ nullptr,
+ 0);
// Get list of Win32_PNPEntity devices
+ Microsoft::WRL::ComPtr<IEnumWbemClassObject> pEnumDevices;
hr = pIWbemServices->CreateInstanceEnum(bstrClassName.get(), 0, nullptr, pEnumDevices.GetAddressOf());
- if (FAILED(hr) || pEnumDevices == nullptr)
+ if (FAILED(hr) || !pEnumDevices)
{
osd_printf_error("Getting list of Win32_PNPEntity devices failed. Error: 0x%X\n", static_cast<unsigned int>(hr));
return hr;
}
// Loop over all devices
- for (; ; )
+ ComArray<IWbemClassObject> pDevices(20);
+ variant_wrapper var;
+ for ( ; ; )
{
// Get a few at a time
+ DWORD uReturned = 0;
hr = pEnumDevices->Next(10000, pDevices.Size(), pDevices.ReleaseAndGetAddressOf(), &uReturned);
if (FAILED(hr))
{
osd_printf_error("Enumerating WMI classes failed. Error: 0x%X\n", static_cast<unsigned int>(hr));
return hr;
}
-
if (uReturned == 0)
break;
- for (iDevice = 0; iDevice < uReturned; iDevice++)
+ for (UINT iDevice = 0; iDevice < uReturned; iDevice++)
{
if (!pDevices[iDevice])
continue;
@@ -416,19 +376,18 @@ private:
if (wcsstr(var.Get().bstrVal, L"IG_"))
{
// If it does, then get the VID/PID from var.bstrVal
- DWORD dwPid = 0, dwVid = 0;
- WCHAR* strVid = wcsstr(var.Get().bstrVal, L"VID_");
+ DWORD dwVid = 0;
+ WCHAR const *const strVid = wcsstr(var.Get().bstrVal, L"VID_");
if (strVid && swscanf(strVid, L"VID_%4X", &dwVid) != 1)
dwVid = 0;
- WCHAR* strPid = wcsstr(var.Get().bstrVal, L"PID_");
+ DWORD dwPid = 0;
+ WCHAR const *const strPid = wcsstr(var.Get().bstrVal, L"PID_");
if (strPid && swscanf(strPid, L"PID_%4X", &dwPid) != 1)
dwPid = 0;
- DWORD dwVidPid = MAKELONG(dwVid, dwPid);
-
- // Add the VID/PID to a linked list
- xinput_id_list.push_back(dwVidPid);
+ // Add the VID/PID to a list
+ xinput_deviceids.push_back(MAKELONG(dwVid, dwPid));
}
}
}
@@ -441,8 +400,16 @@ private:
}
};
-#else
-MODULE_NOT_SUPPORTED(winhybrid_joystick_module, OSD_JOYSTICKINPUT_PROVIDER, "winhybrid")
-#endif
+} // anonymous namespace
+
+} // namespace osd
+
+#else // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
+
+#include "input_module.h"
+
+namespace osd { namespace { MODULE_NOT_SUPPORTED(winhybrid_joystick_module, OSD_JOYSTICKINPUT_PROVIDER, "winhybrid") } }
+
+#endif // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
-MODULE_DEFINITION(JOYSTICKINPUT_WINHYBRID, winhybrid_joystick_module)
+MODULE_DEFINITION(JOYSTICKINPUT_WINHYBRID, osd::winhybrid_joystick_module)
diff --git a/src/osd/modules/input/input_x11.cpp b/src/osd/modules/input/input_x11.cpp
index 40df3d528b6..5230dfd7164 100644
--- a/src/osd/modules/input/input_x11.cpp
+++ b/src/osd/modules/input/input_x11.cpp
@@ -9,34 +9,41 @@
//============================================================
#include "input_module.h"
+
#include "modules/osdmodule.h"
#if defined(SDLMAME_SDL2) && !defined(SDLMAME_WIN32) && defined(USE_XINPUT) && USE_XINPUT
+#include "input_common.h"
+
+#include "sdl/osdsdl.h"
+
+// MAME headers
+#include "inpttype.h"
+
+// standard SDL header
+#include <SDL2/SDL.h>
+
// for X11 xinput
#include <X11/Xlib.h>
#include <X11/extensions/XInput.h>
#include <X11/Xutil.h>
-// standard sdl header
-#include <SDL2/SDL.h>
-#include <ctype.h>
-#include <stddef.h>
-#include <mutex>
+#include <algorithm>
+#include <cctype>
+#include <cstddef>
+#include <cstdio>
+#include <cstring>
#include <memory>
+#include <mutex>
#include <queue>
#include <string>
-#include <algorithm>
+#include <unordered_map>
-// MAME headers
-#include "emu.h"
-#include "osdepend.h"
-// MAMEOS headers
-#include "../lib/osdobj_common.h"
-#include "input_common.h"
-#include "../../sdl/osdsdl.h"
-#include "input_sdlcommon.h"
+namespace osd {
+
+namespace {
#define MAX_DEVMAP_ENTRIES 16
@@ -49,20 +56,6 @@ static int key_release_type = INVALID_EVENT_TYPE;
static int proximity_in_type = INVALID_EVENT_TYPE;
static int proximity_out_type = INVALID_EVENT_TYPE;
-// state information for a lightgun
-struct lightgun_state
-{
- int32_t lX, lY;
- int32_t buttons[MAX_BUTTONS];
-};
-
-struct x11_api_state
-{
- XID deviceid; // X11 device id
- int32_t maxx, maxy;
- int32_t minx, miny;
-};
-
//============================================================
// DEBUG MACROS
//============================================================
@@ -71,56 +64,64 @@ struct x11_api_state
#define XI_DBG(format, ...) osd_printf_verbose(format, __VA_ARGS__)
#define print_motion_event(motion) print_motion_event_impl(motion)
-static inline void print_motion_event_impl(XDeviceMotionEvent *motion)
+inline void print_motion_event_impl(XDeviceMotionEvent const *motion)
{
/*
* print a lot of debug informations of the motion event(s).
*/
osd_printf_verbose(
- "XDeviceMotionEvent:\n"
- " type: %d\n"
- " serial: %lu\n"
- " send_event: %d\n"
- " display: %p\n"
- " window: --\n"
- " deviceid: %lu\n"
- " root: --\n"
- " subwindow: --\n"
- " time: --\n"
- " x: %d, y: %d\n"
- " x_root: %d, y_root: %d\n"
- " state: %u\n"
- " is_hint: %2.2X\n"
- " same_screen: %d\n"
- " device_state: %u\n"
- " axes_count: %2.2X\n"
- " first_axis: %2.2X\n"
- " axis_data[6]: {%d,%d,%d,%d,%d,%d}\n",
- motion->type,
- motion->serial,
- motion->send_event,
- motion->display,
- /* motion->window, */
- motion->deviceid,
- /* motion->root */
- /* motion->subwindow */
- /* motion->time, */
- motion->x, motion->y,
- motion->x_root, motion->y_root,
- motion->state,
- motion->is_hint,
- motion->same_screen,
- motion->device_state,
- motion->axes_count,
- motion->first_axis,
- motion->axis_data[0], motion->axis_data[1], motion->axis_data[2], motion->axis_data[3], motion->axis_data[4], motion->axis_data[5]
- );
+ "XDeviceMotionEvent:\n"
+ " type: %d\n"
+ " serial: %lu\n"
+ " send_event: %d\n"
+ " display: %p\n"
+ " window: --\n"
+ " deviceid: %lu\n"
+ " root: --\n"
+ " subwindow: --\n"
+ " time: --\n"
+ " x: %d, y: %d\n"
+ " x_root: %d, y_root: %d\n"
+ " state: %u\n"
+ " is_hint: %2.2X\n"
+ " same_screen: %d\n"
+ " device_state: %u\n"
+ " axes_count: %2.2X\n"
+ " first_axis: %2.2X\n"
+ " axis_data[6]: {%d,%d,%d,%d,%d,%d}\n",
+ motion->type,
+ motion->serial,
+ motion->send_event,
+ motion->display,
+ /* motion->window, */
+ motion->deviceid,
+ /* motion->root */
+ /* motion->subwindow */
+ /* motion->time, */
+ motion->x, motion->y,
+ motion->x_root, motion->y_root,
+ motion->state,
+ motion->is_hint,
+ motion->same_screen,
+ motion->device_state,
+ motion->axes_count,
+ motion->first_axis,
+ motion->axis_data[0], motion->axis_data[1], motion->axis_data[2], motion->axis_data[3], motion->axis_data[4], motion->axis_data[5]);
}
#else
-#define XI_DBG(format, ...) while(0) {}
-#define print_motion_event(motion) while(0) {}
+#define XI_DBG(format, ...) do { } while (false)
+#define print_motion_event(motion) do { } while (false)
#endif
+
+inline std::string remove_spaces(const char *s)
+{
+ std::string output(s);
+ output.erase(std::remove_if(output.begin(), output.end(), isspace), output.end());
+ return output;
+}
+
+
//============================================================
// lightgun helpers: copy-past from xinfo
//============================================================
@@ -138,7 +139,7 @@ find_device_info(Display *display,
bool is_id = true;
XID id = static_cast<XID>(-1);
- for(loop = 0; loop < len; loop++)
+ for (loop = 0; loop < len; loop++)
{
if (!isdigit(name[loop]))
{
@@ -154,7 +155,7 @@ find_device_info(Display *display,
devices = XListInputDevices(display, &num_devices);
- for(loop = 0; loop < num_devices; loop++)
+ for (loop = 0; loop < num_devices; loop++)
{
osd_printf_verbose("Evaluating device with name: %s\n", devices[loop].name);
@@ -185,7 +186,7 @@ find_device_info(Display *display,
}
//Copypasted from xinfo
-static int
+int
register_events(
Display *dpy,
XDeviceInfo *info,
@@ -252,32 +253,90 @@ register_events(
return number;
}
-//============================================================
-// x11_event_manager
-//============================================================
-class x11_event_handler
+struct device_map
{
-public:
- virtual ~x11_event_handler() {}
+ static inline constexpr unsigned MAX_ENTRIES = 16;
+
+ struct {
+ std::string name;
+ int physical;
+ } map[MAX_ENTRIES];
+ int logical[MAX_ENTRIES];
+ int initialized;
+
+ void init(osd_options const &options, const char *opt, int max_devices, const char *label)
+ {
+ // initialize based on an input option prefix and max number of devices
+ char defname[20];
+
+ // The max devices the user specified, better not be bigger than the max the arrays can old
+ assert(max_devices <= MAX_ENTRIES);
- virtual void handle_event(XEvent &xevent) = 0;
+ // Initialize the map to default uninitialized values
+ for (int dev = 0; dev < MAX_ENTRIES; dev++)
+ {
+ map[dev].name.clear();
+ map[dev].physical = -1;
+ logical[dev] = -1;
+ }
+ initialized = 0;
+
+ // populate the device map up to the max number of devices
+ for (int dev = 0; dev < max_devices; dev++)
+ {
+ const char *dev_name;
+
+ // derive the parameter name from the option name and index. For instance: lightgun_index1 to lightgun_index8
+ sprintf(defname, "%s%d", opt, dev + 1);
+
+ // Get the user-specified name that matches the parameter
+ dev_name = options.value(defname);
+
+ // If they've specified a name and it's not "auto", treat it as a custom mapping
+ if (dev_name && *dev_name && strcmp(dev_name, OSDOPTVAL_AUTO))
+ {
+ // remove the spaces from the name store it in the index
+ map[dev].name = remove_spaces(dev_name);
+ osd_printf_verbose("%s: Logical id %d: %s\n", label, dev + 1, map[dev].name);
+ initialized = 1;
+ }
+ }
+ }
};
-class x11_event_manager : public event_manager_t<x11_event_handler>
+
+//============================================================
+// x11_event_manager
+//============================================================
+
+class x11_event_manager : public event_subscription_manager<XEvent, int>
{
private:
- Display * m_display;
-
- x11_event_manager()
- : event_manager_t(),
- m_display(nullptr)
+ struct x_cleanup
{
- }
+ void operator()(Display *ptr) const
+ {
+ if (ptr)
+ XCloseDisplay(ptr);
+ }
+ void operator()(XExtensionVersion *ptr) const
+ {
+ if (ptr)
+ XFree(ptr);
+ }
+ };
+
+ template <typename T> using x_ptr = std::unique_ptr<T, x_cleanup>;
+
+ x_ptr<Display> m_display;
+
+ x11_event_manager() = default;
+
public:
- Display * display() const { return m_display; }
+ Display *display() const { return m_display.get(); }
- static x11_event_manager& instance()
+ static x11_event_manager &instance()
{
static x11_event_manager s_instance;
return s_instance;
@@ -285,20 +344,20 @@ public:
int initialize()
{
- std::lock_guard<std::mutex> scope_lock(m_lock);
+ std::lock_guard<std::mutex> scope_lock(subscription_mutex());
- if (m_display != nullptr)
+ if (m_display)
return 0;
- m_display = XOpenDisplay(nullptr);
- if (m_display == nullptr)
+ m_display.reset(XOpenDisplay(nullptr));
+ if (!m_display)
{
osd_printf_verbose("Unable to connect to X server\n");
return -1;
}
- XExtensionVersion *version = XGetExtensionVersion(m_display, INAME);
- if (!version || (version == reinterpret_cast<XExtensionVersion*>(NoSuchExtension)))
+ x_ptr<XExtensionVersion> version(XGetExtensionVersion(m_display.get(), INAME));
+ if (!version || (version.get() == reinterpret_cast<XExtensionVersion *>(NoSuchExtension)))
{
osd_printf_verbose("xinput extension not available!\n");
return -1;
@@ -307,28 +366,24 @@ public:
return 0;
}
- void process_events(running_machine &machine) override
+ void process_events()
{
- std::lock_guard<std::mutex> scope_lock(m_lock);
- XEvent xevent;
+ std::lock_guard<std::mutex> scope_lock(subscription_mutex());
- //Get XInput events
- while (XPending(m_display) != 0)
- {
- XNextEvent(m_display, &xevent);
-
- // Find all subscribers for the event type
- auto subscribers = m_subscription_index.equal_range(xevent.type);
+ // If X11 has become invalid for some reason, XPending will crash. Assert instead.
+ assert(m_display);
- // Dispatch the events
- std::for_each(subscribers.first, subscribers.second, [&xevent](auto &pair)
- {
- pair.second->handle_event(xevent);
- });
+ // Get XInput events
+ while (XPending(m_display.get()) != 0)
+ {
+ XEvent event;
+ XNextEvent(m_display.get(), &event);
+ dispatch_event(event.type, event);
}
}
};
+
//============================================================
// x11_input_device
//============================================================
@@ -336,15 +391,23 @@ public:
class x11_input_device : public event_based_device<XEvent>
{
public:
- x11_api_state x11_state;
-
- x11_input_device(running_machine &machine, const char *name, const char *id, input_device_class devclass, input_module &module)
- : event_based_device(machine, name, id, devclass, module),
- x11_state({0})
+ x11_input_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ XDeviceInfo const *info) :
+ event_based_device(std::move(name), std::move(id), module),
+ m_device_id(info ? info->id : 0)
{
}
+
+ XID const &device_id() const { return m_device_id; }
+
+protected:
+ XID const m_device_id; // X11 device ID
};
+
//============================================================
// x11_lightgun_device
//============================================================
@@ -352,55 +415,124 @@ public:
class x11_lightgun_device : public x11_input_device
{
public:
- lightgun_state lightgun;
+ x11_lightgun_device(
+ std::string &&name,
+ std::string &&id,
+ input_module
+ &module,
+ XDeviceInfo *info) :
+ x11_input_device(std::move(name), std::move(id), module, info),
+ m_axis_count(0),
+ m_button_count(0),
+ m_maxx(0),
+ m_maxy(0),
+ m_minx(0),
+ m_miny(0),
+ m_lightgun({ 0 })
+ {
+ if (info && (info->num_classes > 0))
+ {
+ // Grab device info and translate to stuff MAME can use
+ XAnyClassPtr any = static_cast<XAnyClassPtr>(info->inputclassinfo);
+ for (int i = 0; i < info->num_classes; i++)
+ {
+ switch (any->c_class)
+ {
+ // Set the axis min/max ranges if we got them
+ case ValuatorClass:
+ {
+ auto const valuator_info = reinterpret_cast<XValuatorInfoPtr>(any);
+ auto axis_info = reinterpret_cast<XAxisInfoPtr>(reinterpret_cast<char *>(valuator_info) + sizeof(XValuatorInfo));
+ for (int j = 0; (j < valuator_info->num_axes) && (j < 2); j++, axis_info++)
+ {
+ if (j == 0)
+ {
+ XI_DBG("Set minx=%d, maxx=%d\n", axis_info->min_value, axis_info->max_value);
+ m_axis_count = 1;
+ m_maxx = axis_info->max_value;
+ m_minx = axis_info->min_value;
+ }
+
+ if (j == 1)
+ {
+ XI_DBG("Set miny=%d, maxy=%d\n", axis_info->min_value, axis_info->max_value);
+ m_axis_count = 2;
+ m_maxy = axis_info->max_value;
+ m_miny = axis_info->min_value;
+ }
+ }
+ }
+ break;
+
+ // Count the lightgun buttons based on what we read
+ case ButtonClass:
+ {
+ XButtonInfoPtr b = reinterpret_cast<XButtonInfoPtr>(any);
+ if (b->num_buttons < 0)
+ m_button_count = 0;
+ else if (b->num_buttons <= MAX_BUTTONS)
+ m_button_count = b->num_buttons;
+ else
+ m_button_count = MAX_BUTTONS;
+ }
+ break;
+ }
- x11_lightgun_device(running_machine &machine, const char *name, const char *id, input_module &module)
- : x11_input_device(machine, name, id, DEVICE_CLASS_LIGHTGUN, module),
- lightgun({0})
+ any = reinterpret_cast<XAnyClassPtr>(reinterpret_cast<char *>(any) + any->length);
+ }
+ }
+ }
+
+ virtual void reset() override
{
+ memset(&m_lightgun, 0, sizeof(m_lightgun));
}
- void process_event(XEvent &xevent) override
+ virtual void configure(input_device &device) override
+ {
+ // Add buttons
+ for (int button = 0; button < m_button_count; button++)
+ {
+ input_item_id const itemid = input_item_id(ITEM_ID_BUTTON1 + button);
+ device.add_item(default_button_name(button), std::string_view(), itemid, generic_button_get_state<std::int32_t>, &m_lightgun.buttons[button]);
+ }
+
+ // Add X and Y axis
+ if (1 <= m_axis_count)
+ device.add_item("X", std::string_view(), ITEM_ID_XAXIS, generic_axis_get_state<std::int32_t>, &m_lightgun.lX);
+ if (2 <= m_axis_count)
+ device.add_item("Y", std::string_view(), ITEM_ID_YAXIS, generic_axis_get_state<std::int32_t>, &m_lightgun.lY);
+ }
+
+ virtual void process_event(XEvent const &xevent) override
{
if (xevent.type == motion_type)
{
- XDeviceMotionEvent *motion = reinterpret_cast<XDeviceMotionEvent *>(&xevent);
+ auto const motion = reinterpret_cast<XDeviceMotionEvent const *>(&xevent);
print_motion_event(motion);
- /*
- * We have to check with axis will start on array index 0.
- * We have also to check the number of axes that are stored in the array.
- */
+ // We have to check with axis will start on array index 0.
+ // We also have to check the number of axes that are stored in the array.
switch (motion->first_axis)
{
- /*
- * Starting with x, check number of axis, if there is also the y axis stored.
- */
+ // Starting with x, check number of axes, if there is also the y axis stored.
case 0:
if (motion->axes_count >= 1)
- {
- lightgun.lX = normalize_absolute_axis(motion->axis_data[0], x11_state.minx, x11_state.maxx);
- if (motion->axes_count >= 2)
- {
- lightgun.lY = normalize_absolute_axis(motion->axis_data[1], x11_state.miny, x11_state.maxy);
- }
- }
+ m_lightgun.lX = normalize_absolute_axis(motion->axis_data[0], m_minx, m_maxx);
+ if (motion->axes_count >= 2)
+ m_lightgun.lY = normalize_absolute_axis(motion->axis_data[1], m_miny, m_maxy);
break;
- /*
- * Starting with y, ...
- */
+ // Starting with y, ...
case 1:
if (motion->axes_count >= 1)
- {
- lightgun.lY = normalize_absolute_axis(motion->axis_data[0], x11_state.miny, x11_state.maxy);
- }
+ m_lightgun.lY = normalize_absolute_axis(motion->axis_data[0], m_miny, m_maxy);
break;
}
}
else if (xevent.type == button_press_type || xevent.type == button_release_type)
{
- XDeviceButtonEvent *button = reinterpret_cast<XDeviceButtonEvent *>(&xevent);
+ auto const button = reinterpret_cast<XDeviceButtonEvent const *>(&xevent);
/*
* SDL/X11 Number the buttons 1,2,3, while windows and other parts of MAME
@@ -408,140 +540,160 @@ public:
* -1 the button number to align the numbering schemes.
*/
int button_number = button->button;
- switch (button_number)
+ if (button_number <= MAX_BUTTONS)
{
+ switch (button_number)
+ {
case 2:
- button_number = 3;
- break;
case 3:
- button_number = 2;
+ button_number ^= 1;
break;
+ }
+ m_lightgun.buttons[button_number - 1] = (xevent.type == button_press_type) ? 0x80 : 0;
}
- lightgun.buttons[button_number - 1] = (xevent.type == button_press_type) ? 0x80 : 0;
}
}
- void reset() override
+private:
+ struct lightgun_state
{
- memset(&lightgun, 0, sizeof(lightgun));
- }
+ int32_t lX, lY;
+ int32_t buttons[MAX_BUTTONS];
+ };
+
+ int m_axis_count;
+ int m_button_count;
+ int32_t m_maxx;
+ int32_t m_maxy;
+ int32_t m_minx;
+ int32_t m_miny;
+ lightgun_state m_lightgun;
};
+
//============================================================
// x11_lightgun_module
//============================================================
-class x11_lightgun_module : public input_module_base, public x11_event_handler
+class x11_lightgun_module : public input_module_impl<x11_input_device, osd_common_t>, public x11_event_manager::subscriber
{
private:
- device_map_t m_lightgun_map;
- Display * m_display;
+ device_map m_lightgun_map;
+ Display *m_display;
+
public:
- x11_lightgun_module()
- : input_module_base(OSD_LIGHTGUNINPUT_PROVIDER, "x11"),
- m_display(nullptr)
+ x11_lightgun_module() :
+ input_module_impl<x11_input_device, osd_common_t>(OSD_LIGHTGUNINPUT_PROVIDER, "x11"),
+ m_display(nullptr)
{
}
- void input_init(running_machine &machine) override
+ virtual bool probe() override
{
- int index;
+ // If there is no X server, X11 lightguns cannot be supported
+ Display *const display = XOpenDisplay(nullptr);
+ if (!display)
+ return false;
+ XCloseDisplay(display);
- osd_printf_verbose("Lightgun: Begin initialization\n");
-
- devmap_init(machine, &m_lightgun_map, SDLOPTION_LIGHTGUNINDEX, 8, "Lightgun mapping");
+ return true;
+ }
+ virtual int init(osd_interface &osd, osd_options const &options) override
+ {
+ // If the X server has become invalid, a crash can occur
x11_event_manager::instance().initialize();
m_display = x11_event_manager::instance().display();
+ if (!m_display)
+ return -1;
+
+ return input_module_impl<x11_input_device, osd_common_t>::init(osd, options);
+ }
+
+ virtual void input_init(running_machine &machine) override
+ {
+ assert(m_display);
+
+ input_module_impl<x11_input_device, osd_common_t>::input_init(machine);
+
+ osd_printf_verbose("Lightgun: Begin initialization\n");
+
+ m_lightgun_map.init(*options(), SDLOPTION_LIGHTGUNINDEX, 8, "Lightgun mapping");
// Loop through all 8 possible devices
- for (index = 0; index < 8; index++)
+ for (int index = 0; index < 8; index++)
{
- XDeviceInfo *info;
-
// Skip if the name is empty
- if (m_lightgun_map.map[index].name.length() == 0)
+ if (m_lightgun_map.map[index].name.empty())
continue;
- x11_lightgun_device *devinfo;
+ // Find the device info associated with the name
std::string const &name = m_lightgun_map.map[index].name;
- char defname[512];
+ osd_printf_verbose("%i: %s\n", index, name);
+ XDeviceInfo *const info = find_device_info(m_display, name.c_str(), 0);
+ if (!info)
+ osd_printf_verbose("Lightgun: Can't find device %s!\n", name);
- // Register and add the device
- devinfo = create_lightgun_device(machine, index);
- osd_printf_verbose("%i: %s\n", index, name.c_str());
-
- // Find the device info associated with the name
- info = find_device_info(m_display, name.c_str(), 0);
+ // previously had code to use "NC%d" format if name was empty
+ // but that couldn't happen because device creation would be skipped
- // If we couldn't find the device, skip
- if (info == nullptr)
- {
- osd_printf_verbose("Can't find device %s!\n", name.c_str());
- continue;
- }
+ // Register and add the device
+ create_device<x11_lightgun_device>(
+ DEVICE_CLASS_LIGHTGUN,
+ std::string(name),
+ std::string(name),
+ info);
- //Grab device info and translate to stuff mame can use
- if (info->num_classes > 0)
+ // Register this device to receive event notifications
+ if (info)
{
- // Add the lightgun buttons based on what we read
- add_lightgun_buttons(static_cast<XAnyClassPtr>(info->inputclassinfo), info->num_classes, devinfo);
-
- // Also, set the axix min/max ranges if we got them
- set_lightgun_axis_props(static_cast<XAnyClassPtr>(info->inputclassinfo), info->num_classes, devinfo);
+ int const events_registered = register_events(m_display, info, name.c_str(), 0);
+ osd_printf_verbose("Device %i: Registered %i events.\n", int(info->id), events_registered);
}
+ }
- // Add X and Y axis
- sprintf(defname, "X %s", devinfo->name());
- devinfo->device()->add_item(defname, ITEM_ID_XAXIS, generic_axis_get_state<std::int32_t>, &devinfo->lightgun.lX);
-
- sprintf(defname, "Y %s", devinfo->name());
- devinfo->device()->add_item(defname, ITEM_ID_YAXIS, generic_axis_get_state<std::int32_t>, &devinfo->lightgun.lY);
-
- // Save the device id
- devinfo->x11_state.deviceid = info->id;
+ // register ourself to handle events from event manager
+ int const event_types[] = { motion_type, button_press_type, button_release_type };
+ osd_printf_verbose("Events types to register: motion:%d, press:%d, release:%d\n", motion_type, button_press_type, button_release_type);
+ subscribe(x11_event_manager::instance(), event_types);
- // Register this device to receive event notifications
- int events_registered = register_events(m_display, info, m_lightgun_map.map[index].name.c_str(), 0);
- osd_printf_verbose("Device %i: Registered %i events.\n", static_cast<int>(info->id), events_registered);
+ osd_printf_verbose("Lightgun: End initialization\n");
+ }
- // register ourself to handle events from event manager
- int event_types[] = { motion_type, button_press_type, button_release_type };
- osd_printf_verbose("Events types to register: motion:%d, press:%d, release:%d\n", motion_type, button_press_type, button_release_type);
- x11_event_manager::instance().subscribe(event_types, ARRAY_LENGTH(event_types), this);
- }
+ virtual void exit() override
+ {
+ // unsubscribe from events
+ unsubscribe();
- osd_printf_verbose("Lightgun: End initialization\n");
+ input_module_impl<x11_input_device, osd_common_t>::exit();
}
- bool should_poll_devices(running_machine &machine) override
+ virtual bool should_poll_devices() override
{
- return sdl_event_manager::instance().has_focus();
+ return osd().has_focus();
}
- void before_poll(running_machine &machine) override
+ virtual void before_poll() override
{
- if (!should_poll_devices(machine))
- return;
+ // trigger the SDL event manager so it can process window events
+ input_module_impl<x11_input_device, osd_common_t>::before_poll();
// Tell the event manager to process events and push them to the devices
- x11_event_manager::instance().process_events(machine);
-
- // Also trigger the SDL event manager so it can process window events
- sdl_event_manager::instance().process_events(machine);
+ if (should_poll_devices())
+ x11_event_manager::instance().process_events();
}
- void handle_event(XEvent &xevent) override
+ virtual void handle_event(XEvent const &xevent) override
{
XID deviceid;
if (xevent.type == motion_type)
{
- XDeviceMotionEvent *motion = reinterpret_cast<XDeviceMotionEvent *>(&xevent);
+ auto const motion = reinterpret_cast<XDeviceMotionEvent const *>(&xevent);
deviceid = motion->deviceid;
}
else if (xevent.type == button_press_type || xevent.type == button_release_type)
{
- XDeviceButtonEvent *button = reinterpret_cast<XDeviceButtonEvent *>(&xevent);
+ auto const button = reinterpret_cast<XDeviceButtonEvent const *>(&xevent);
deviceid = button->deviceid;
}
else
@@ -550,97 +702,27 @@ public:
}
// Figure out which lightgun this event id destined for
- auto target_device = std::find_if(devicelist()->begin(), devicelist()->end(), [deviceid](auto &device)
- {
- std::unique_ptr<device_info> &ptr = device;
- return downcast<x11_input_device*>(ptr.get())->x11_state.deviceid == deviceid;
- });
+ auto target_device = std::find_if(
+ devicelist().begin(),
+ devicelist().end(),
+ [&deviceid] (auto &device) { return device->device_id() == deviceid; });
// If we find a matching lightgun, dispatch the event to the lightgun
- if (target_device != devicelist()->end())
- {
- downcast<x11_input_device*>((*target_device).get())->queue_events(&xevent, 1);
- }
+ if (target_device != devicelist().end())
+ (*target_device)->queue_events(&xevent, 1);
}
+};
-private:
- x11_lightgun_device* create_lightgun_device(running_machine &machine, int index)
- {
- char tempname[20];
-
- if (m_lightgun_map.map[index].name.length() == 0)
- {
- if (m_lightgun_map.initialized)
- {
- snprintf(tempname, ARRAY_LENGTH(tempname), "NC%d", index);
- devicelist()->create_device<x11_lightgun_device>(machine, tempname, tempname, *this);
- }
-
- return nullptr;
- }
-
- return devicelist()->create_device<x11_lightgun_device>(machine, m_lightgun_map.map[index].name.c_str(), m_lightgun_map.map[index].name.c_str(), *this);
- }
-
- void add_lightgun_buttons(XAnyClassPtr first_info_class, int num_classes, x11_lightgun_device *devinfo) const
- {
- XAnyClassPtr any = first_info_class;
-
- for (int i = 0; i < num_classes; i++)
- {
- switch (any->c_class)
- {
- case ButtonClass:
- XButtonInfoPtr b = reinterpret_cast<XButtonInfoPtr>(any);
- for (int button = 0; button < b->num_buttons; button++)
- {
- input_item_id itemid = static_cast<input_item_id>(ITEM_ID_BUTTON1 + button);
- devinfo->device()->add_item(default_button_name(button), itemid, generic_button_get_state<std::int32_t>, &devinfo->lightgun.buttons[button]);
- }
- break;
- }
+} // anonymous namespace
- any = reinterpret_cast<XAnyClassPtr>(reinterpret_cast<char *>(any) + any->length);
- }
- }
+} // namespace osd
- void set_lightgun_axis_props(XAnyClassPtr first_info_class, int num_classes, x11_lightgun_device *devinfo) const
- {
- XAnyClassPtr any = first_info_class;
- for (int i = 0; i < num_classes; i++)
- {
- switch (any->c_class)
- {
- case ValuatorClass:
- XValuatorInfoPtr valuator_info = reinterpret_cast<XValuatorInfoPtr>(any);
- XAxisInfoPtr axis_info = reinterpret_cast<XAxisInfoPtr>(reinterpret_cast<char *>(valuator_info) + sizeof(XValuatorInfo));
- for (int j = 0; j < valuator_info->num_axes; j++, axis_info++)
- {
- if (j == 0)
- {
- XI_DBG("Set minx=%d, maxx=%d\n", axis_info->min_value, axis_info->max_value);
- devinfo->x11_state.maxx = axis_info->max_value;
- devinfo->x11_state.minx = axis_info->min_value;
- }
+#else // defined(SDLMAME_SDL2) && !defined(SDLMAME_WIN32) && defined(USE_XINPUT) && USE_XINPUT
- if (j == 1)
- {
- XI_DBG("Set miny=%d, maxy=%d\n", axis_info->min_value, axis_info->max_value);
- devinfo->x11_state.maxy = axis_info->max_value;
- devinfo->x11_state.miny = axis_info->min_value;
- }
- }
- break;
- }
+namespace osd { namespace { MODULE_NOT_SUPPORTED(x11_lightgun_module, OSD_LIGHTGUNINPUT_PROVIDER, "x11") } }
- any = reinterpret_cast<XAnyClassPtr>(reinterpret_cast<char *>(any) + any->length);
- }
- }
-};
+#endif // defined(SDLMAME_SDL2) && !defined(SDLMAME_WIN32) && defined(USE_XINPUT) && USE_XINPUT
-#else
-MODULE_NOT_SUPPORTED(x11_lightgun_module, OSD_LIGHTGUNINPUT_PROVIDER, "x11")
-#endif
-MODULE_DEFINITION(LIGHTGUN_X11, x11_lightgun_module)
+MODULE_DEFINITION(LIGHTGUN_X11, osd::x11_lightgun_module)
diff --git a/src/osd/modules/input/input_xinput.cpp b/src/osd/modules/input/input_xinput.cpp
index 67348ebe162..474ef6fe7ff 100644
--- a/src/osd/modules/input/input_xinput.cpp
+++ b/src/osd/modules/input/input_xinput.cpp
@@ -1,223 +1,2997 @@
// license:BSD-3-Clause
-// copyright-holders:Brad Hughes
+// copyright-holders:Brad Hughes, Vas Crabb
//============================================================
//
// input_xinput.cpp - XInput API input support for Windows
//
//============================================================
+/*
-#include "input_module.h"
-#include "modules/osdmodule.h"
+XInput is infamously inflexible. It currently only supports a single
+controller type (game controller) with a fixed report format. The
+report format includes:
+* 16-bit field for single-bit buttons and D-pad directions (two bits
+ undefined)
+* Two 8-bit axis values, used for triggers, pedals, buttons or throttle
+ and rudder controls, depending on the controller
+* Four 16-bit axis values, used for joysticks, steering wheels or hat
+ switches, depending on the controller
+
+Some button names have changed at various times:
+* Face buttons White and Black became shoulder buttons LB and RB,
+ respectively.
+* Navigation buttons Start and Back became Menu and View, respectively.
+
+Subtype Gamepad Wheel Arcade stick Arcade pad Flight stick Dance pad Guitar Drum kit
+
+D-pad D-pad D-pad Joystick D-pad Foot switch D-Pad/Strum D-pad
+L trigger Trigger Brake Button Button Rudder Pickup select^
+R trigger Trigger Accelerator Button Button Throttle ^
+L stick X Stick Wheel Roll
+L stick Y Stick Pitch
+R stick X Stick Hat left/right Whammy bar
+R stick Y Stick Hat up/down Orientation
+
+A Button Button Button Button Primary fire Foot switch Fret 1 Floor tom
+B Button Button Button Button Secondary fire Foot switch Fret 2 Snare
+X Button Button Button Button Button Foot switch Fret 4 Low tom
+Y Button Button Button Button Button Foot switch Fret 3 High tom
+LB Button Button Button^ Button Button^ Fret 5 Bass drum
+RB Button Button Button^ Button Button^ Button^ Button^
+LSB Button Button^ Button^ Button^ Button^ Fret modifier^ Button^
+RSB Button Button^ Button^ Button^ Button^ Button^ Button^
+
+^ optional
+
+
+At least the vast majority of controllers report 8-bit trigger
+resolution and 10-bit stick resolution, even when the physical controls
+use digital switches. Resolution can't be used to reliably detect
+nominal analog axes controlled by switches.
+
+Some arcade sticks report unknown or gamepad subtype, but have a single
+digital joystick with a switch to select between controlling the D-pad,
+left stick and right stick. You can't assume that all three can be
+controlled at the same time.
+
+Many controllers don't correctly report the absence of analog sticks.
+
+
+Some controllers use capabilities to indicate extended controller type
+information:
+
+ Type Sub LSX LSY RSX
+Band Hero Wireless Guitar 0x01 0x07 0x1430 0x0705 0x0001
+Band Hero Wireless Drum Kit 0x01 0x08 0x1430 0x0805 0x0001
+DJ Hero 2 Turntable 0x01 0x17 0x1430 0x1705 0x0001
+Rock Band 3 Wireless Keyboard 0x01 0x0f 0x1bad 0x1330 0x0004
+
+
+There are multiple physical button layouts for arcade sticks, for
+example:
+
+Gamester Xbox Arcade Stick, Hori Real Arcade Pro EX
+LT X Y LB
+RT A B RB
+
+PXN 0082 Arcade Stick
+LB X Y RB
+LT A B RT
+
+Mortal Kombat Tournament Edition Arcade Stick
+ X Y
+ RT
+LB A B
+
+Hori Fighting Stick EX2
+ B X Y
+A LT RT
+
+Hori Real Arcade Pro VX-SA Kai, Razer Atrox
+ B X Y LB
+A LT RT RB
+
+Hori Real Arcade Pro.V Kai, Mad Catz EGO Arcade Stick, Mayflash F300, Mayflash F500
+ X Y RB LB
+A B RT LT
+
+Mad Catz WWE All Stars Brawl Stick
+ X Y LB LT
+A B RB RT
+
+Arcade pads typically have six face buttons, and come with different
+layouts corresponding to the latter two arcade stick layouts, with the
+rightmost column on the shoulder buttons. Examples of face button
+layouts:
+
+Hori Fighting Commander OCTA, Mad Catz Street Fighter IV FightPad, PowerA FUSION Wired FightPad
+X Y RB
+A B RT
-#if defined(OSD_WINDOWS)
+Hori Pad EX Turbo 2, Mad Catz WWE All Stars BrawlPad, Mortal Kombat X Fight Pad, PDP Versus Fighting Pad
+X Y LB
+A B RB
-// standard windows headers
-#include <windows.h>
-// XInput header
-#include <xinput.h>
+Dance mats usually have this layout:
+BK ST
+B U A
+L R
+Y D X
-#undef interface
+This layout seems somewhat unusual:
+BK ST
+A U B
+L R
+X D Y
-// MAME headers
-#include "emu.h"
+This layout is also available but rare:
+BK ST
+A U B
+L R
+Y D X
-// MAMEOS headers
-#include "winutil.h"
-#include "winmain.h"
-#include "input_common.h"
-#include "input_windows.h"
+Drum kits also have multiple layouts.
+
+Rock Band:
+B Y X A
+ LB
+
+Guitar Hero:
+ Y RB
+A X B
+ LB
+
+
+Rock Band keyboards use axes as bit fields:
+
+LT 7 C
+LT 6 C#
+LT 5 D
+LT 4 D#
+LT 3 E
+LT 2 F
+LT 1 F#
+LT 0 G
+RT 7 G#
+RT 6 A
+RT 5 A#
+RT 4 B
+RT 3 C
+RT 2 C#
+RT 1 D
+RT 0 D#
+LSX 7 E
+LSX 6 F
+LSX 5 F#
+LSX 4 G
+LSX 3 G#
+LSX 2 A
+LSX 1 A#
+LSX 0 B
+LSX 15 C
+
+*/
+
+#include "modules/osdmodule.h"
+
+#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
+
#include "input_xinput.h"
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#include "assignmenthelper.h"
+
+#include "interface/inputseq.h"
+#include "modules/lib/osdobj_common.h"
+
+// emu
+#include "inpttype.h"
+
+// lib/util
+#include "util/coretmpl.h"
+
+#include "eminline.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <iterator>
+#include <string>
+#include <tuple>
+#include <utility>
+
+
#define XINPUT_LIBRARIES { "xinput1_4.dll", "xinput9_1_0.dll" }
-#else
-#define XINPUT_LIBRARIES { "xinput1_4.dll" }
-#endif
-int xinput_api_helper::initialize()
+#define XINPUT_AXIS_MINVALUE (-32'767)
+#define XINPUT_AXIS_MAXVALUE (32'767)
+
+namespace osd {
+
+namespace {
+
+using util::BIT;
+
+
+char const *const AXIS_NAMES_GAMEPAD[]{
+ "LSX",
+ "LSY",
+ "RSX",
+ "RSY",
+ "LT",
+ "RT" };
+
+char const *const AXIS_NAMES_WHEEL[]{
+ "Wheel",
+ "LSY",
+ "RSX",
+ "RSY",
+ "Brake",
+ "Accelerator" };
+
+char const *const AXIS_NAMES_GUITAR[]{
+ "LSX",
+ "LSY",
+ "Whammy Bar",
+ "Orientation",
+ "Pickup Selector",
+ "RT" };
+
+input_item_id const AXIS_IDS_GAMEPAD[]{
+ ITEM_ID_XAXIS,
+ ITEM_ID_YAXIS,
+ ITEM_ID_ZAXIS,
+ ITEM_ID_RZAXIS,
+ ITEM_ID_SLIDER1,
+ ITEM_ID_SLIDER2 };
+
+char const *const HAT_NAMES_GAMEPAD[]{
+ "D-pad Up",
+ "D-pad Down",
+ "D-pad Left",
+ "D-pad Right",
+ "POV Hat Up",
+ "POV Hat Down",
+ "POV Hat Left",
+ "POV Hat Right" };
+
+char const *const HAT_NAMES_ARCADE_STICK[]{
+ "Joystick Up",
+ "Joystick Down",
+ "Joystick Left",
+ "Joystick Right",
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr };
+
+char const *const HAT_NAMES_GUITAR[]{
+ "Strum/D-pad Up",
+ "Strum/D-pad Down",
+ "D-pad Left",
+ "D-pad Right" };
+
+char const *const BUTTON_NAMES_GAMEPAD[]{
+ "A",
+ "B",
+ "X",
+ "Y",
+ "LT",
+ "RT",
+ "LB",
+ "RB",
+ "LSB",
+ "RSB" };
+
+char const *const BUTTON_NAMES_FLIGHT_STICK[]{
+ "A",
+ "B",
+ "X",
+ "Y",
+ "LB",
+ "RB",
+ "LSB",
+ "RSB" };
+
+char const *const BUTTON_NAMES_GUITAR[]{
+ "Fret 1",
+ "Fret 2",
+ "Fret 3",
+ "Fret 4",
+ "Fret 5",
+ "Fret Modifier",
+ "RB",
+ "RSB" };
+
+char const *const BUTTON_NAMES_DRUMKIT[]{
+ "Green", // floor tom
+ "Red", // snare
+ "Blue", // low tom
+ "Yellow", // Rock Band high tom, Guitar Hero hi-hat
+ "Orange", // Guitar Hero crash cymbal
+ "Bass Drum",
+ "LSB",
+ "RSB" };
+
+char const *const BUTTON_NAMES_KEYBOARD[]{
+ "A",
+ "B",
+ "X",
+ "Y",
+ "LB",
+ "RB",
+ "LSB",
+ "RSB" };
+
+
+
+//============================================================
+// base class for XInput controller handlers
+//============================================================
+
+class xinput_device_base : public device_info, protected joystick_assignment_helper
{
- m_xinput_dll = osd::dynamic_module::open(XINPUT_LIBRARIES);
+protected:
+ xinput_device_base(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ u32 player,
+ XINPUT_CAPABILITIES const &caps,
+ xinput_api_helper const &helper);
- XInputGetState = m_xinput_dll->bind<xinput_get_state_fn>("XInputGetState");
- XInputGetCapabilities = m_xinput_dll->bind<xinput_get_caps_fn>("XInputGetCapabilities");
+ // capabilities
+ BYTE device_type() const { return m_capabilities.Type; }
+ BYTE device_subtype() const { return m_capabilities.SubType; }
+ bool has_button(WORD mask) const { return (m_capabilities.Gamepad.wButtons & mask) != 0; }
+ bool has_trigger_left() const { return m_capabilities.Gamepad.bLeftTrigger != 0; }
+ bool has_trigger_right() const { return m_capabilities.Gamepad.bRightTrigger != 0; }
+ bool has_thumb_left_x() const { return m_capabilities.Gamepad.sThumbLX != 0; }
+ bool has_thumb_left_y() const { return m_capabilities.Gamepad.sThumbLY != 0; }
+ bool has_thumb_right_x() const { return m_capabilities.Gamepad.sThumbRX != 0; }
+ bool has_thumb_right_y() const { return m_capabilities.Gamepad.sThumbRY != 0; }
- if (!XInputGetState || !XInputGetCapabilities)
+ // device state
+ WORD buttons() const { return m_xinput_state.Gamepad.wButtons; }
+ BYTE trigger_left() const { return m_xinput_state.Gamepad.bLeftTrigger; }
+ BYTE trigger_right() const { return m_xinput_state.Gamepad.bRightTrigger; }
+ SHORT thumb_left_x() const { return m_xinput_state.Gamepad.sThumbLX; }
+ SHORT thumb_left_y() const { return m_xinput_state.Gamepad.sThumbLY; }
+ SHORT thumb_right_x() const { return m_xinput_state.Gamepad.sThumbRX; }
+ SHORT thumb_right_y() const { return m_xinput_state.Gamepad.sThumbRY; }
+
+ bool read_state();
+ bool is_reset() const { return m_reset; }
+ void set_reset() { m_reset = true; }
+
+protected:
+ template <unsigned M, unsigned N>
+ static bool assign_ui_button(
+ input_device::assignment_vector &assignments,
+ ioport_type type,
+ unsigned preferred,
+ input_item_id (&switch_ids)[M],
+ unsigned const (&numbered_buttons)[N],
+ unsigned button_count);
+
+ template <unsigned M, unsigned N>
+ static void assign_ui_actions(
+ input_device::assignment_vector &assignments,
+ unsigned preferred_back,
+ unsigned preferred_clear,
+ unsigned preferred_help,
+ unsigned start,
+ unsigned back,
+ input_item_id (&switch_ids)[M],
+ unsigned const (&numbered_buttons)[N],
+ unsigned button_count);
+
+private:
+ bool probe_extended_type();
+
+ u32 const m_player_index;
+ XINPUT_CAPABILITIES m_capabilities;
+ XINPUT_STATE m_xinput_state;
+ bool m_reset;
+
+ xinput_api_helper const &m_xinput_helper;
+};
+
+
+xinput_device_base::xinput_device_base(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ u32 player,
+ XINPUT_CAPABILITIES const &caps,
+ xinput_api_helper const &helper) :
+ device_info(std::move(name), std::move(id), module),
+ m_player_index(player),
+ m_capabilities(caps),
+ m_xinput_state{ 0 },
+ m_reset(true),
+ m_xinput_helper(helper)
+{
+ // get friendly names for controller type and subtype
+ char const *type_name = "unsupported";
+ char const *subtype_name = "unsupported";
+ switch (m_capabilities.Type)
{
- osd_printf_verbose("Could not find XInput. Please try to reinstall DirectX runtime package.\n");
- return -1;
+ case XINPUT_DEVTYPE_GAMEPAD:
+ type_name = "game controller";
+ switch (m_capabilities.SubType)
+ {
+ case 0x00: // XINPUT_DEVSUBTYPE_UNKNOWN: work around MinGW header issues
+ subtype_name = "unknown";
+ break;
+ case XINPUT_DEVSUBTYPE_GAMEPAD:
+ subtype_name = "gamepad";
+ break;
+ case XINPUT_DEVSUBTYPE_WHEEL:
+ subtype_name = "wheel";
+ break;
+ case XINPUT_DEVSUBTYPE_ARCADE_STICK:
+ subtype_name = "arcade stick";
+ break;
+ case 0x04: // XINPUT_DEVSUBTYPE_FLIGHT_STICK: work around MinGW header issues
+ subtype_name = "flight stick";
+ break;
+ case XINPUT_DEVSUBTYPE_DANCE_PAD:
+ subtype_name = "dance pad";
+ break;
+ case XINPUT_DEVSUBTYPE_GUITAR:
+ subtype_name = "guitar";
+ break;
+ case XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE:
+ subtype_name = "alternate guitar";
+ break;
+ case XINPUT_DEVSUBTYPE_DRUM_KIT:
+ subtype_name = "drum kit";
+ break;
+ case XINPUT_DEVSUBTYPE_GUITAR_BASS:
+ subtype_name = "bass guitar";
+ break;
+ case XINPUT_DEVSUBTYPE_ARCADE_PAD:
+ subtype_name = "arcade pad";
+ break;
+ }
+ break;
}
- return 0;
+ // detect invalid axis resolutions
+ bool const ltcap_bad = m_capabilities.Gamepad.bLeftTrigger && count_leading_zeros_32(m_capabilities.Gamepad.bLeftTrigger << 24);
+ bool const rtcap_bad = m_capabilities.Gamepad.bRightTrigger && count_leading_zeros_32(m_capabilities.Gamepad.bRightTrigger << 24);
+ bool const lsxcap_bad = m_capabilities.Gamepad.sThumbLX && count_leading_zeros_32(m_capabilities.Gamepad.sThumbLX << 16);
+ bool const lsycap_bad = m_capabilities.Gamepad.sThumbLY && count_leading_zeros_32(m_capabilities.Gamepad.sThumbLY << 16);
+ bool const rsxcap_bad = m_capabilities.Gamepad.sThumbRX && count_leading_zeros_32(m_capabilities.Gamepad.sThumbRX << 16);
+ bool const rsycap_bad = m_capabilities.Gamepad.sThumbRY && count_leading_zeros_32(m_capabilities.Gamepad.sThumbRY << 16);
+
+ // log some diagnostic information
+ osd_printf_verbose(
+ "XInput: Configuring player %d type 0x%02X (%s) sub type 0x%02X (%s).\n",
+ m_player_index + 1,
+ m_capabilities.Type,
+ type_name,
+ m_capabilities.SubType,
+ subtype_name);
+ osd_printf_verbose(
+ "XInput: Switch capabilities A=%d B=%d X=%d Y=%d LB=%d RB=%d LSB=%d RSB=%d Start=%d Back=%d Up=%d Down=%d Left=%d Right=%d.\n",
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_A) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_B) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_X) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_Y) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_START) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) ? 1 : 0);
+ osd_printf_verbose(
+ "XInput: Axis capabilities LT=0x%02X (%d-bit%s) RT=0x%02X (%d-bit%s) LSX=0x%04X (%d-bit%s) LSY=0x%04X (%d-bit%s) RSX=0x%04X (%d-bit%s) RSY=0x%04X (%d-bit%s).\n",
+ m_capabilities.Gamepad.bLeftTrigger,
+ count_leading_ones_32(u32(m_capabilities.Gamepad.bLeftTrigger) << 24),
+ ltcap_bad ? ", invalid" : "",
+ m_capabilities.Gamepad.bRightTrigger,
+ count_leading_ones_32(u32(m_capabilities.Gamepad.bRightTrigger) << 24),
+ rtcap_bad ? ", invalid" : "",
+ m_capabilities.Gamepad.sThumbLX,
+ count_leading_ones_32(u32(u16(m_capabilities.Gamepad.sThumbLX)) << 16),
+ lsxcap_bad ? ", invalid" : "",
+ m_capabilities.Gamepad.sThumbLY,
+ count_leading_ones_32(u32(u16(m_capabilities.Gamepad.sThumbLY)) << 16),
+ lsycap_bad ? ", invalid" : "",
+ m_capabilities.Gamepad.sThumbRX,
+ count_leading_ones_32(u32(u16(m_capabilities.Gamepad.sThumbRX)) << 16),
+ rsxcap_bad ? ", invalid" : "",
+ m_capabilities.Gamepad.sThumbRY,
+ count_leading_ones_32(u32(u16(m_capabilities.Gamepad.sThumbRY)) << 16),
+ rsycap_bad ? ", invalid" : "");
+
+ // ignore capabilities if invalid
+ if (!probe_extended_type())
+ {
+ bool ignore_caps = false;
+ if (ltcap_bad || rtcap_bad || lsxcap_bad || lsycap_bad || rsxcap_bad || rsycap_bad)
+ {
+ // Retro-Bit Sega Saturn Control Pad reports garbage for axis resolutions and absence of several buttons
+ osd_printf_verbose("XInput: Ignoring invalid capabilities (invalid axis resolution).\n");
+ ignore_caps = true;
+ }
+ else if (!m_capabilities.Gamepad.wButtons && !m_capabilities.Gamepad.bLeftTrigger && !m_capabilities.Gamepad.bRightTrigger && !m_capabilities.Gamepad.sThumbLX && !m_capabilities.Gamepad.sThumbLY && !m_capabilities.Gamepad.sThumbRX && !m_capabilities.Gamepad.sThumbRY)
+ {
+ // 8BitDo SN30 Pro V1 reports no controls at all, which would be completely useless
+ osd_printf_verbose("XInput: Ignoring invalid capabilities (no controls reported).\n");
+ ignore_caps = true;
+ }
+ if (ignore_caps)
+ {
+ m_capabilities.Gamepad.wButtons = 0xf3ff;
+ m_capabilities.Gamepad.bLeftTrigger = 0xff;
+ m_capabilities.Gamepad.bRightTrigger = 0xff;
+ m_capabilities.Gamepad.sThumbLX = s16(u16(0xffc0));
+ m_capabilities.Gamepad.sThumbLY = s16(u16(0xffc0));
+ m_capabilities.Gamepad.sThumbRX = s16(u16(0xffc0));
+ m_capabilities.Gamepad.sThumbRY = s16(u16(0xffc0));
+ }
+ }
}
+
+bool xinput_device_base::read_state()
+{
+ // save previous packet number and try to read peripheral state
+ DWORD const prevpacket = m_xinput_state.dwPacketNumber;
+ HRESULT const result = m_xinput_helper.xinput_get_state(m_player_index, &m_xinput_state);
+
+ // only update if it succeeded and the packed number changed
+ if (FAILED(result))
+ {
+ return false;
+ }
+ else if (m_reset)
+ {
+ m_reset = false;
+ return true;
+ }
+ else
+ {
+ return prevpacket != m_xinput_state.dwPacketNumber;
+ }
+}
+
+
+template <unsigned M, unsigned N>
+bool xinput_device_base::assign_ui_button(
+ input_device::assignment_vector &assignments,
+ ioport_type type,
+ unsigned preferred,
+ input_item_id (&switch_ids)[M],
+ unsigned const (&numbered_buttons)[N],
+ unsigned button_count)
+{
+ assert(N >= button_count);
+
+ // use preferred button if available
+ if (add_button_assignment(assignments, type, { switch_ids[preferred] }))
+ {
+ switch_ids[preferred] = ITEM_ID_INVALID;
+ return true;
+ }
+
+ // otherwise find next available button
+ for (unsigned i = 0; button_count > i; ++i)
+ {
+ if (add_button_assignment(assignments, type, { switch_ids[numbered_buttons[i]] }))
+ {
+ switch_ids[numbered_buttons[i]] = ITEM_ID_INVALID;
+ return true;
+ }
+ }
+
+ // didn't find a suitable button
+ return false;
+}
+
+
+template <unsigned M, unsigned N>
+void xinput_device_base::assign_ui_actions(
+ input_device::assignment_vector &assignments,
+ unsigned preferred_back,
+ unsigned preferred_clear,
+ unsigned preferred_help,
+ unsigned start,
+ unsigned back,
+ input_item_id (&switch_ids)[M],
+ unsigned const (&numbered_buttons)[N],
+ unsigned button_count)
+{
+ // the first button is always UI select if present, or we can fall back to start
+ if (1U <= button_count)
+ {
+ add_button_assignment(assignments, IPT_UI_SELECT, { switch_ids[numbered_buttons[0]] });
+ switch_ids[numbered_buttons[0]] = ITEM_ID_INVALID;
+ }
+ else if (add_button_assignment(assignments, IPT_UI_SELECT, { switch_ids[start] }))
+ {
+ switch_ids[start] = ITEM_ID_INVALID;
+ }
+
+ // UI clear is usually X
+ assign_ui_button(
+ assignments,
+ IPT_UI_CLEAR,
+ preferred_clear,
+ switch_ids,
+ numbered_buttons,
+ button_count);
+
+ // UI back can fall back from B to the back button
+ bool const assigned_back = assign_ui_button(
+ assignments,
+ IPT_UI_BACK,
+ preferred_back,
+ switch_ids,
+ numbered_buttons,
+ button_count);
+ if (!assigned_back)
+ {
+ if (add_button_assignment(assignments, IPT_UI_BACK, { switch_ids[back] }))
+ switch_ids[back] = ITEM_ID_INVALID;
+ }
+
+ // help takes Y if present
+ assign_ui_button(
+ assignments,
+ IPT_UI_HELP,
+ preferred_help,
+ switch_ids,
+ numbered_buttons,
+ button_count);
+}
+
+
+bool xinput_device_base::probe_extended_type()
+{
+ switch (m_capabilities.Gamepad.sThumbLX)
+ {
+ case 0x1430:
+ switch (m_capabilities.Gamepad.sThumbLY)
+ {
+ case 0x0705:
+ osd_printf_verbose("XInput: Detected Band Hero guitar controller.\n");
+ m_capabilities.Gamepad.sThumbLX = s16(u16(0xffc0)); // neck slider
+ m_capabilities.Gamepad.sThumbLY = 0;
+ m_capabilities.Gamepad.sThumbRX = s16(u16(0xffc0)); // whammy bar
+ return true;
+ case 0x0805:
+ osd_printf_verbose("XInput: Detected Band Hero drum kit controller.\n");
+ m_capabilities.Gamepad.sThumbLX = 0;
+ m_capabilities.Gamepad.sThumbLY = s16(u16(0xffc0)); // green/red velocity
+ m_capabilities.Gamepad.sThumbRX = s16(u16(0xffc0)); // blue/yellow velocity
+ return true;
+ case 0x1705:
+ osd_printf_verbose("XInput: Detected DJ Hero turntable controller.\n");
+ m_capabilities.Gamepad.sThumbLX = 0;
+ m_capabilities.Gamepad.sThumbLY = s16(u16(0xffc0)); // turntable
+ m_capabilities.Gamepad.sThumbRX = s16(u16(0xffc0)); // effects dial
+ return true;
+ }
+ break;
+ case 0x1bad:
+ switch (m_capabilities.Gamepad.sThumbLY)
+ {
+ case 0x1330:
+ osd_printf_verbose("XInput: Detected Rock Band keyboard controller.\n");
+ m_capabilities.Gamepad.sThumbLX = 0; // keys, velocity
+ m_capabilities.Gamepad.sThumbLY = 0; // not present?
+ m_capabilities.Gamepad.sThumbRX = 0; // not present?
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+
+
//============================================================
-// create_xinput_device
+// general XInput controller handler
//============================================================
-xinput_joystick_device * xinput_api_helper::create_xinput_device(running_machine &machine, UINT index, wininput_module &module)
+class xinput_joystick_device : public xinput_device_base
{
- xinput_joystick_device *devinfo;
+public:
+ xinput_joystick_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ u32 player,
+ XINPUT_CAPABILITIES const &caps,
+ xinput_api_helper const &helper);
- XINPUT_CAPABILITIES caps = { 0 };
- if (FAILED(xinput_get_capabilities(index, 0, &caps)))
+ virtual void poll(bool relative_reset) override;
+ virtual void reset() override;
+ virtual void configure(input_device &device) override;
+
+private:
+ static inline constexpr USHORT SWITCH_BITS[] =
{
- // If we can't get the capabilities skip this device
- return nullptr;
+ XINPUT_GAMEPAD_A,
+ XINPUT_GAMEPAD_B,
+ XINPUT_GAMEPAD_X,
+ XINPUT_GAMEPAD_Y,
+ XINPUT_GAMEPAD_LEFT_SHOULDER,
+ XINPUT_GAMEPAD_RIGHT_SHOULDER,
+ XINPUT_GAMEPAD_LEFT_THUMB,
+ XINPUT_GAMEPAD_RIGHT_THUMB,
+ XINPUT_GAMEPAD_START,
+ XINPUT_GAMEPAD_BACK,
+
+ XINPUT_GAMEPAD_DPAD_UP,
+ XINPUT_GAMEPAD_DPAD_DOWN,
+ XINPUT_GAMEPAD_DPAD_LEFT,
+ XINPUT_GAMEPAD_DPAD_RIGHT
+ };
+
+ enum
+ {
+ SWITCH_A, // button bits
+ SWITCH_B,
+ SWITCH_X,
+ SWITCH_Y,
+ SWITCH_LB,
+ SWITCH_RB,
+ SWITCH_LSB,
+ SWITCH_RSB,
+ SWITCH_START,
+ SWITCH_BACK,
+
+ SWITCH_DPAD_UP, // D-pad bits
+ SWITCH_DPAD_DOWN,
+ SWITCH_DPAD_LEFT,
+ SWITCH_DPAD_RIGHT,
+
+ SWITCH_LT, // for arcade stick/pad with LT/RT buttons
+ SWITCH_RT,
+
+ SWITCH_TOTAL
+ };
+
+ enum
+ {
+ AXIS_LT, // half-axes for triggers
+ AXIS_RT,
+
+ AXIS_LSX, // full-precision axes
+ AXIS_LSY,
+ AXIS_RSX,
+ AXIS_RSY,
+
+ AXIS_TOTAL
+ };
+
+ static bool assign_pedal(
+ input_device::assignment_vector &assignments,
+ bool fallback_shoulder,
+ ioport_type type,
+ input_item_id preferred_axis,
+ input_item_id fallback_axis1,
+ input_item_id fallback_axis2,
+ input_item_modifier fallback_axis_modifier,
+ input_item_id trigger_button,
+ input_item_id shoulder_button,
+ input_item_id numbered_button);
+
+ u8 m_switches[SWITCH_TOTAL];
+ s32 m_axes[AXIS_TOTAL];
+};
+
+
+xinput_joystick_device::xinput_joystick_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ u32 player,
+ XINPUT_CAPABILITIES const &caps,
+ xinput_api_helper const &helper) :
+ xinput_device_base(std::move(name), std::move(id), module, player, caps, helper)
+{
+ std::fill(std::begin(m_switches), std::end(m_switches), 0);
+ std::fill(std::begin(m_axes), std::end(m_axes), 0);
+}
+
+
+void xinput_joystick_device::poll(bool relative_reset)
+{
+ // poll the device first, and skip if nothing changed
+ if (!read_state())
+ return;
+
+ // translate button bits
+ for (unsigned i = 0; std::size(SWITCH_BITS) > i; ++i)
+ m_switches[SWITCH_A + i] = (buttons() & SWITCH_BITS[i]) ? 0xff : 0x00;
+
+ // translate the triggers onto the negative side of the axes
+ m_axes[AXIS_LT] = -normalize_absolute_axis(trigger_left(), -255, 255);
+ m_axes[AXIS_RT] = -normalize_absolute_axis(trigger_right(), -255, 255);
+
+ // translate full-precision axes - Y direction is opposite to what MAME uses
+ m_axes[AXIS_LSX] = normalize_absolute_axis(thumb_left_x(), XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
+ m_axes[AXIS_LSY] = normalize_absolute_axis(-thumb_left_y(), XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
+ m_axes[AXIS_RSX] = normalize_absolute_axis(thumb_right_x(), XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
+ m_axes[AXIS_RSY] = normalize_absolute_axis(-thumb_right_y(), XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
+
+ // translate LT/RT switches for arcade sticks/pads
+ m_switches[SWITCH_LT] = (0x80 <= trigger_left()) ? 0xff : 0x00;
+ m_switches[SWITCH_RT] = (0x80 <= trigger_right()) ? 0xff : 0x00;
+}
+
+
+void xinput_joystick_device::reset()
+{
+ set_reset();
+ std::fill(std::begin(m_switches), std::end(m_switches), 0);
+ std::fill(std::begin(m_axes), std::end(m_axes), 0);
+}
+
+
+void xinput_joystick_device::configure(input_device &device)
+{
+ // TODO: proper support for dance mat controllers
+
+ // default characteristics for a gamepad
+ bool button_diamond = true;
+ bool pedal_fallback_shoulder = true;
+ bool lt_rt_button = false;
+ char const *const *axis_names = AXIS_NAMES_GAMEPAD;
+ input_item_id const *preferred_axis_ids = AXIS_IDS_GAMEPAD;
+ char const *const *hat_names = HAT_NAMES_GAMEPAD;
+ char const *const *button_names = BUTTON_NAMES_GAMEPAD;
+
+ // consider the device type to decide how to map controls
+ switch (device_type())
+ {
+ case XINPUT_DEVTYPE_GAMEPAD:
+ switch (device_subtype())
+ {
+ case XINPUT_DEVSUBTYPE_WHEEL:
+ pedal_fallback_shoulder = false;
+ axis_names = AXIS_NAMES_WHEEL;
+ break;
+ case XINPUT_DEVSUBTYPE_ARCADE_STICK:
+ button_diamond = false;
+ lt_rt_button = true;
+ hat_names = HAT_NAMES_ARCADE_STICK;
+ break;
+ case XINPUT_DEVSUBTYPE_DANCE_PAD:
+ // TODO: proper support
+ button_diamond = false;
+ break;
+ case XINPUT_DEVSUBTYPE_ARCADE_PAD:
+ button_diamond = false;
+ lt_rt_button = true;
+ break;
+ }
+ break;
}
- char device_name[16];
- snprintf(device_name, sizeof(device_name), "XInput Player %u", index + 1);
+ // track item IDs for setting up default assignments
+ input_device::assignment_vector assignments;
+ input_item_id axis_ids[AXIS_TOTAL];
+ input_item_id switch_ids[SWITCH_TOTAL];
+ std::fill(std::begin(switch_ids), std::end(switch_ids), ITEM_ID_INVALID);
- // allocate the device object
- devinfo = module.devicelist()->create_device<xinput_joystick_device>(machine, device_name, device_name, module, shared_from_this());
+ // add bidirectional axes
+ bool const axis_caps[]{
+ has_thumb_left_x(),
+ has_thumb_left_y(),
+ has_thumb_right_x(),
+ has_thumb_right_y() };
+ for (unsigned i = 0; std::size(axis_caps) > i; ++i)
+ {
+ if (axis_caps[i])
+ {
+ axis_ids[AXIS_LSX + i] = device.add_item(
+ axis_names[i],
+ std::string_view(),
+ preferred_axis_ids[i],
+ generic_axis_get_state<s32>,
+ &m_axes[AXIS_LSX + i]);
+ }
+ else
+ {
+ axis_ids[AXIS_LSX + i] = ITEM_ID_INVALID;
+ }
+ }
- // Set the player ID
- devinfo->xinput_state.player_index = index;
+ // add hats
+ bool const hat_caps[]{
+ has_button(XINPUT_GAMEPAD_DPAD_UP),
+ has_button(XINPUT_GAMEPAD_DPAD_DOWN),
+ has_button(XINPUT_GAMEPAD_DPAD_LEFT),
+ has_button(XINPUT_GAMEPAD_DPAD_RIGHT) };
+ for (unsigned i = 0; (SWITCH_DPAD_RIGHT - SWITCH_DPAD_UP) >= i; ++i)
+ {
+ if (hat_caps[i])
+ {
+ switch_ids[SWITCH_DPAD_UP + i] = device.add_item(
+ hat_names[i],
+ std::string_view(),
+ input_item_id(ITEM_ID_HAT1UP + i), // matches up/down/left/right order
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_DPAD_UP + i]);
+ }
+ }
- // Assign the caps we captured earlier
- devinfo->xinput_state.caps = caps;
+ // add buttons
+ std::pair<unsigned, bool> const button_caps[]{
+ { SWITCH_A, has_button(XINPUT_GAMEPAD_A) },
+ { SWITCH_B, has_button(XINPUT_GAMEPAD_B) },
+ { SWITCH_X, has_button(XINPUT_GAMEPAD_X) },
+ { SWITCH_Y, has_button(XINPUT_GAMEPAD_Y) },
+ { SWITCH_LT, lt_rt_button && has_trigger_left() },
+ { SWITCH_RT, lt_rt_button && has_trigger_right() },
+ { SWITCH_LB, has_button(XINPUT_GAMEPAD_LEFT_SHOULDER) },
+ { SWITCH_RB, has_button(XINPUT_GAMEPAD_RIGHT_SHOULDER) },
+ { SWITCH_LSB, has_button(XINPUT_GAMEPAD_LEFT_THUMB) },
+ { SWITCH_RSB, has_button(XINPUT_GAMEPAD_RIGHT_THUMB) } };
+ input_item_id button_id = ITEM_ID_BUTTON1;
+ unsigned button_count = 0;
+ unsigned numbered_buttons[SWITCH_RSB - SWITCH_A + 1];
+ for (unsigned i = 0; std::size(button_caps) > i; ++i)
+ {
+ auto const [offset, supported] = button_caps[i];
+ if (supported)
+ {
+ switch_ids[offset] = device.add_item(
+ button_names[i],
+ std::string_view(),
+ button_id++,
+ generic_button_get_state<u8>,
+ &m_switches[offset]);
+ numbered_buttons[button_count] = offset;
+
+ // use these for automatically numbered buttons
+ assignments.emplace_back(
+ ioport_type(IPT_BUTTON1 + button_count++),
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, switch_ids[offset])));
+ }
+ }
+
+ // add start/back
+ if (has_button(XINPUT_GAMEPAD_START))
+ {
+ switch_ids[SWITCH_START] = device.add_item(
+ "Start",
+ std::string_view(),
+ ITEM_ID_START,
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_START]);
+ add_button_assignment(assignments, IPT_START, { switch_ids[SWITCH_START] });
+ }
+ if (has_button(XINPUT_GAMEPAD_BACK))
+ {
+ switch_ids[SWITCH_BACK] = device.add_item(
+ "Back",
+ std::string_view(),
+ ITEM_ID_SELECT,
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_BACK]);
+ add_button_assignment(assignments, IPT_SELECT, { switch_ids[SWITCH_BACK] });
+ }
- return devinfo;
+ // add triggers/pedals
+ if (!lt_rt_button)
+ {
+ for (unsigned i = 0; (AXIS_RT - AXIS_LT) >= i; ++i)
+ {
+ if (i ? has_trigger_right() : has_trigger_left())
+ {
+ axis_ids[AXIS_LT + i] = device.add_item(
+ axis_names[std::size(axis_caps) + i],
+ std::string_view(),
+ preferred_axis_ids[std::size(axis_caps) + i],
+ generic_axis_get_state<s32>,
+ &m_axes[AXIS_LT + i]);
+ }
+ else
+ {
+ axis_ids[AXIS_LT + i] = ITEM_ID_INVALID;
+ }
+ }
+ }
+
+ // try to get a "complete" joystick for primary movement controls
+ input_item_id directional_axes[2][2];
+ choose_primary_stick(
+ directional_axes,
+ axis_ids[AXIS_LSX],
+ axis_ids[AXIS_LSY],
+ axis_ids[AXIS_RSX],
+ axis_ids[AXIS_RSY]);
+
+ // now set up controls using the primary joystick
+ add_directional_assignments(
+ assignments,
+ directional_axes[0][0],
+ directional_axes[0][1],
+ switch_ids[SWITCH_DPAD_LEFT],
+ switch_ids[SWITCH_DPAD_RIGHT],
+ switch_ids[SWITCH_DPAD_UP],
+ switch_ids[SWITCH_DPAD_DOWN]);
+
+ // assign a secondary stick axis to joystick Z if available
+ bool const stick_z = add_assignment(
+ assignments,
+ IPT_AD_STICK_Z,
+ SEQ_TYPE_STANDARD,
+ ITEM_CLASS_ABSOLUTE,
+ ITEM_MODIFIER_NONE,
+ { directional_axes[1][1], directional_axes[1][0] });
+ if (!stick_z)
+ {
+ // if both triggers are present, combine them, or failing that, fall back to a pair of buttons
+ if ((ITEM_ID_INVALID != axis_ids[AXIS_LT]) && (ITEM_ID_INVALID != axis_ids[AXIS_RT]))
+ {
+ assignments.emplace_back(
+ IPT_AD_STICK_Z,
+ SEQ_TYPE_STANDARD,
+ input_seq(
+ make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, axis_ids[AXIS_LT]),
+ make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_REVERSE, axis_ids[AXIS_RT])));
+ }
+ else if (add_axis_inc_dec_assignment(assignments, IPT_AD_STICK_Z, switch_ids[SWITCH_LB], switch_ids[SWITCH_RB]))
+ {
+ // took shoulder buttons
+ }
+ else if (add_axis_inc_dec_assignment(assignments, IPT_AD_STICK_Z, switch_ids[SWITCH_LT], switch_ids[SWITCH_RT]))
+ {
+ // took trigger buttons
+ }
+ }
+
+ // prefer trigger axes for pedals, otherwise take half axes and buttons
+ unsigned pedal_button = 0;
+ bool const pedal1_numbered_button = assign_pedal(
+ assignments,
+ pedal_fallback_shoulder,
+ IPT_PEDAL,
+ axis_ids[AXIS_RT],
+ directional_axes[1][1],
+ directional_axes[0][1],
+ ITEM_MODIFIER_NEG,
+ switch_ids[SWITCH_RT],
+ switch_ids[SWITCH_RB],
+ (pedal_button < button_count)
+ ? switch_ids[numbered_buttons[pedal_button]]
+ : ITEM_ID_INVALID);
+ if (pedal1_numbered_button)
+ ++pedal_button;
+ bool const pedal2_numbered_button = assign_pedal(
+ assignments,
+ pedal_fallback_shoulder,
+ IPT_PEDAL2,
+ axis_ids[AXIS_LT],
+ directional_axes[1][1],
+ directional_axes[0][1],
+ ITEM_MODIFIER_POS,
+ switch_ids[SWITCH_LT],
+ switch_ids[SWITCH_LB],
+ (pedal_button < button_count)
+ ? switch_ids[numbered_buttons[pedal_button]]
+ : ITEM_ID_INVALID);
+ if (pedal2_numbered_button)
+ ++pedal_button;
+ if (pedal_button < button_count)
+ {
+ input_item_id const pedal_button_id = switch_ids[numbered_buttons[pedal_button]];
+ assignments.emplace_back(
+ IPT_PEDAL3,
+ SEQ_TYPE_INCREMENT,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, pedal_button_id)));
+ }
+
+ // potentially use thumb sticks and/or D-pad and A/B/X/Y diamond for twin sticks
+ add_twin_stick_assignments(
+ assignments,
+ axis_ids[AXIS_LSX],
+ axis_ids[AXIS_LSY],
+ axis_ids[AXIS_RSX],
+ axis_ids[AXIS_RSY],
+ button_diamond ? switch_ids[SWITCH_DPAD_LEFT] : ITEM_ID_INVALID,
+ button_diamond ? switch_ids[SWITCH_DPAD_RIGHT] : ITEM_ID_INVALID,
+ button_diamond ? switch_ids[SWITCH_DPAD_UP] : ITEM_ID_INVALID,
+ button_diamond ? switch_ids[SWITCH_DPAD_DOWN] : ITEM_ID_INVALID,
+ button_diamond ? switch_ids[SWITCH_X] : ITEM_ID_INVALID,
+ button_diamond ? switch_ids[SWITCH_B] : ITEM_ID_INVALID,
+ button_diamond ? switch_ids[SWITCH_Y] : ITEM_ID_INVALID,
+ button_diamond ? switch_ids[SWITCH_A] : ITEM_ID_INVALID);
+
+ // assign UI select/back/clear/help
+ assign_ui_actions(
+ assignments,
+ SWITCH_B,
+ SWITCH_X,
+ SWITCH_Y,
+ SWITCH_START,
+ SWITCH_BACK,
+ switch_ids,
+ numbered_buttons,
+ button_count);
+
+ // try to get a matching pair of buttons for previous/next group
+ if (consume_button_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, switch_ids[SWITCH_LT], switch_ids[SWITCH_RT]))
+ {
+ // took digital triggers
+ }
+ else if (consume_trigger_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, axis_ids[AXIS_LT], axis_ids[AXIS_RT]))
+ {
+ // took analog triggers
+ }
+ else if (consume_axis_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, directional_axes[1][1]))
+ {
+ // took secondary Y
+ }
+ else if (consume_axis_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, directional_axes[1][0]))
+ {
+ // took secondary X
+ }
+
+ // try to assign secondary stick to page up/down
+ consume_axis_pair(assignments, IPT_UI_PAGE_UP, IPT_UI_PAGE_DOWN, directional_axes[1][1]);
+
+ // put focus previous/next on the shoulder buttons if available - this can be overloaded with zoom
+ if (add_button_pair_assignment(assignments, IPT_UI_FOCUS_PREV, IPT_UI_FOCUS_NEXT, switch_ids[SWITCH_LB], switch_ids[SWITCH_RB]))
+ {
+ // took shoulder buttons
+ }
+ else if (add_axis_pair_assignment(assignments, IPT_UI_FOCUS_PREV, IPT_UI_FOCUS_NEXT, directional_axes[1][0]))
+ {
+ // took secondary X
+ }
+
+ // put zoom on the secondary stick if available, or fall back to shoulder buttons
+ if (add_axis_pair_assignment(assignments, IPT_UI_ZOOM_OUT, IPT_UI_ZOOM_IN, directional_axes[1][0]))
+ {
+ // took secondary X
+ if (axis_ids[AXIS_LSX] == directional_axes[1][0])
+ add_button_assignment(assignments, IPT_UI_ZOOM_DEFAULT, { switch_ids[SWITCH_LSB] });
+ else if (axis_ids[AXIS_RSX] == directional_axes[1][0])
+ add_button_assignment(assignments, IPT_UI_ZOOM_DEFAULT, { switch_ids[SWITCH_RSB] });
+ directional_axes[1][0] = ITEM_ID_INVALID;
+ }
+ else if (consume_button_pair(assignments, IPT_UI_ZOOM_OUT, IPT_UI_ZOOM_IN, switch_ids[SWITCH_LB], switch_ids[SWITCH_RB]))
+ {
+ // took shoulder buttons
+ }
+
+ // set default assignments
+ device.set_default_assignments(std::move(assignments));
+}
+
+
+bool xinput_joystick_device::assign_pedal(
+ input_device::assignment_vector &assignments,
+ bool fallback_shoulder,
+ ioport_type type,
+ input_item_id preferred_axis,
+ input_item_id fallback_axis1,
+ input_item_id fallback_axis2,
+ input_item_modifier fallback_axis_modifier,
+ input_item_id trigger_button,
+ input_item_id shoulder_button,
+ input_item_id numbered_button)
+{
+ // first try the preferred trigger/pedal axis
+ if (ITEM_ID_INVALID != preferred_axis)
+ {
+ assignments.emplace_back(
+ type,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, preferred_axis)));
+ return false;
+ }
+
+ // try adding half a joystick axis
+ add_assignment(
+ assignments,
+ type,
+ SEQ_TYPE_STANDARD,
+ ITEM_CLASS_ABSOLUTE,
+ fallback_axis_modifier,
+ { fallback_axis1, fallback_axis2 });
+
+ // try a trigger button
+ if (ITEM_ID_INVALID != trigger_button)
+ {
+ assignments.emplace_back(
+ type,
+ SEQ_TYPE_INCREMENT,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, trigger_button)));
+ return false;
+ }
+
+ // try a shoulder button if appropriate
+ if (fallback_shoulder && (ITEM_ID_INVALID != shoulder_button))
+ {
+ assignments.emplace_back(
+ type,
+ SEQ_TYPE_INCREMENT,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, shoulder_button)));
+ return false;
+ }
+
+ // if no numbered button, nothing can be done
+ if (ITEM_ID_INVALID == numbered_button)
+ return false;
+
+ // last resort
+ assignments.emplace_back(
+ type,
+ SEQ_TYPE_INCREMENT,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, numbered_button)));
+ return true;
}
+
+
//============================================================
-// xinput_joystick_device
+// XInput flight stick handler
//============================================================
-xinput_joystick_device::xinput_joystick_device(running_machine &machine, const char *name, char const *id, input_module &module, std::shared_ptr<xinput_api_helper> helper)
- : device_info(machine, name, id, DEVICE_CLASS_JOYSTICK, module),
- gamepad({{0}}),
- xinput_state({0}),
- m_xinput_helper(helper),
- m_configured(false)
+class xinput_flight_stick_device : public xinput_device_base
{
+public:
+ xinput_flight_stick_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ u32 player,
+ XINPUT_CAPABILITIES const &caps,
+ xinput_api_helper const &helper);
+
+ virtual void poll(bool relative_reset) override;
+ virtual void reset() override;
+ virtual void configure(input_device &device) override;
+
+private:
+ static inline constexpr USHORT SWITCH_BITS[] =
+ {
+ XINPUT_GAMEPAD_A,
+ XINPUT_GAMEPAD_B,
+ XINPUT_GAMEPAD_X,
+ XINPUT_GAMEPAD_Y,
+ XINPUT_GAMEPAD_LEFT_SHOULDER,
+ XINPUT_GAMEPAD_RIGHT_SHOULDER,
+ XINPUT_GAMEPAD_LEFT_THUMB,
+ XINPUT_GAMEPAD_RIGHT_THUMB,
+ XINPUT_GAMEPAD_START,
+ XINPUT_GAMEPAD_BACK,
+
+ XINPUT_GAMEPAD_DPAD_UP,
+ XINPUT_GAMEPAD_DPAD_DOWN,
+ XINPUT_GAMEPAD_DPAD_LEFT,
+ XINPUT_GAMEPAD_DPAD_RIGHT
+ };
+
+ enum
+ {
+ SWITCH_A, // button bits
+ SWITCH_B,
+ SWITCH_X,
+ SWITCH_Y,
+ SWITCH_LB,
+ SWITCH_RB,
+ SWITCH_LSB,
+ SWITCH_RSB,
+ SWITCH_START,
+ SWITCH_BACK,
+
+ SWITCH_DPAD_UP, // D-pad bits
+ SWITCH_DPAD_DOWN,
+ SWITCH_DPAD_LEFT,
+ SWITCH_DPAD_RIGHT,
+
+ SWITCH_HAT_UP, // for POV hat as right stick
+ SWITCH_HAT_DOWN,
+ SWITCH_HAT_LEFT,
+ SWITCH_HAT_RIGHT,
+
+ SWITCH_TOTAL
+ };
+
+ enum
+ {
+ AXIS_RUDDER, // LT/RT mapped as bidirectional axes
+ AXIS_THROTTLE,
+
+ AXIS_X, // full-precision axes
+ AXIS_Y,
+
+ AXIS_TOTAL
+ };
+
+ u8 m_switches[SWITCH_TOTAL];
+ s32 m_axes[AXIS_TOTAL];
+};
+
+
+xinput_flight_stick_device::xinput_flight_stick_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ u32 player,
+ XINPUT_CAPABILITIES const &caps,
+ xinput_api_helper const &helper) :
+ xinput_device_base(std::move(name), std::move(id), module, player, caps, helper)
+{
+ std::fill(std::begin(m_switches), std::end(m_switches), 0);
+ std::fill(std::begin(m_axes), std::end(m_axes), 0);
}
-void xinput_joystick_device::poll()
+
+void xinput_flight_stick_device::poll(bool relative_reset)
{
- if (!m_configured)
+ // poll the device first, and skip if nothing changed
+ if (!read_state())
return;
- // poll the device first
- HRESULT result = m_xinput_helper->xinput_get_state(xinput_state.player_index, &xinput_state.xstate);
+ // translate button bits
+ for (unsigned i = 0; std::size(SWITCH_BITS) > i; ++i)
+ m_switches[SWITCH_A + i] = (buttons() & SWITCH_BITS[i]) ? 0xff : 0x00;
- // If we can't poll the device, skip
- if (FAILED(result))
- return;
+ // translate rudder and throttle
+ m_axes[AXIS_RUDDER] = normalize_absolute_axis(trigger_left(), 0, 255);
+ m_axes[AXIS_THROTTLE] = normalize_absolute_axis(trigger_right(), 0, 255);
+
+ // translate full-precision axes - Y direction is opposite to what MAME uses
+ m_axes[AXIS_X] = normalize_absolute_axis(thumb_left_x(), XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
+ m_axes[AXIS_Y] = normalize_absolute_axis(-thumb_left_y(), XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
+
+ // translate right stick as POV hat
+ m_switches[SWITCH_HAT_UP] = (16'384 <= thumb_right_y()) ? 0xff : 0x00;
+ m_switches[SWITCH_HAT_DOWN] = (-16'384 >= thumb_right_y()) ? 0xff : 0x00;
+ m_switches[SWITCH_HAT_LEFT] = (-16'384 >= thumb_right_x()) ? 0xff : 0x00;
+ m_switches[SWITCH_HAT_RIGHT] = (16'384 <= thumb_right_x()) ? 0xff : 0x00;
+}
+
+
+void xinput_flight_stick_device::reset()
+{
+ set_reset();
+ std::fill(std::begin(m_switches), std::end(m_switches), 0);
+ std::fill(std::begin(m_axes), std::end(m_axes), 0);
+}
+
+
+void xinput_flight_stick_device::configure(input_device &device)
+{
+ // track item IDs for setting up default assignments
+ input_device::assignment_vector assignments;
+ input_item_id switch_ids[SWITCH_TOTAL];
+ std::fill(std::begin(switch_ids), std::end(switch_ids), ITEM_ID_INVALID);
+
+ // add bidirectional axes
+ std::tuple<input_item_id, char const *, bool> const axis_caps[]{
+ { ITEM_ID_RZAXIS, "Rudder", has_trigger_left() },
+ { ITEM_ID_ZAXIS, "Throttle", has_trigger_right() },
+ { ITEM_ID_XAXIS, "Joystick X", has_thumb_left_x() },
+ { ITEM_ID_YAXIS, "Joystick Y", has_thumb_left_y() } };
+ input_item_id axis_ids[AXIS_TOTAL];
+ for (unsigned i = 0; AXIS_TOTAL > i; ++i)
+ {
+ auto const [id, name, supported] = axis_caps[i];
+ if (supported)
+ {
+ axis_ids[i] = device.add_item(
+ name,
+ std::string_view(),
+ id,
+ generic_axis_get_state<s32>,
+ &m_axes[i]);
+ }
+ else
+ {
+ axis_ids[i] = ITEM_ID_INVALID;
+ }
+ }
+
+ // add hats
+ bool const hat_caps[]{
+ has_button(XINPUT_GAMEPAD_DPAD_UP),
+ has_button(XINPUT_GAMEPAD_DPAD_DOWN),
+ has_button(XINPUT_GAMEPAD_DPAD_LEFT),
+ has_button(XINPUT_GAMEPAD_DPAD_RIGHT),
+ has_thumb_right_x(),
+ has_thumb_right_x(),
+ has_thumb_right_y(),
+ has_thumb_right_y() };
+ for (unsigned i = 0; (SWITCH_HAT_RIGHT - SWITCH_DPAD_UP) >= i; ++i)
+ {
+ if (hat_caps[i])
+ {
+ switch_ids[SWITCH_DPAD_UP + i] = device.add_item(
+ HAT_NAMES_GAMEPAD[i],
+ std::string_view(),
+ input_item_id(ITEM_ID_HAT1UP + i), // matches up/down/left/right order
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_DPAD_UP + i]);
+ }
+ }
+
+ // add buttons
+ input_item_id button_id = ITEM_ID_BUTTON1;
+ unsigned button_count = 0;
+ unsigned numbered_buttons[SWITCH_RSB - SWITCH_A + 1];
+ for (unsigned i = 0; (SWITCH_RSB - SWITCH_A) >= i; ++i)
+ {
+ if (has_button(SWITCH_BITS[i]))
+ {
+ switch_ids[SWITCH_A + i] = device.add_item(
+ BUTTON_NAMES_FLIGHT_STICK[i],
+ std::string_view(),
+ button_id++,
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_A + i]);
+ numbered_buttons[button_count] = SWITCH_A + i;
+
+ // use these for automatically numbered buttons and pedals
+ input_seq const seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, switch_ids[SWITCH_A + i]));
+ assignments.emplace_back(ioport_type(IPT_BUTTON1 + button_count), SEQ_TYPE_STANDARD, seq);
+ if (3 > button_count)
+ assignments.emplace_back(ioport_type(IPT_PEDAL + button_count), SEQ_TYPE_INCREMENT, seq);
+ ++button_count;
+ }
+ }
+
+ // add start/back
+ if (has_button(XINPUT_GAMEPAD_START))
+ {
+ switch_ids[SWITCH_START] = device.add_item(
+ "Start",
+ std::string_view(),
+ ITEM_ID_START,
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_START]);
+ add_button_assignment(assignments, IPT_START, { switch_ids[SWITCH_START] });
+ }
+ if (has_button(XINPUT_GAMEPAD_BACK))
+ {
+ switch_ids[SWITCH_BACK] = device.add_item(
+ "Back",
+ std::string_view(),
+ ITEM_ID_SELECT,
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_BACK]);
+ add_button_assignment(assignments, IPT_SELECT, { switch_ids[SWITCH_BACK] });
+ }
- // Copy the XState into State
- // Start with the POV (DPAD)
- for (int povindex = 0; povindex < XINPUT_MAX_POV; povindex++)
+ // use throttle for joystick Z, or rudder if it isn't available
+ add_assignment(
+ assignments,
+ IPT_AD_STICK_Z,
+ SEQ_TYPE_STANDARD,
+ ITEM_CLASS_ABSOLUTE,
+ ITEM_MODIFIER_NONE,
+ { axis_ids[AXIS_THROTTLE], axis_ids[AXIS_RUDDER] });
+
+ // if throttle is available, use it for first two pedals, too
+ if (ITEM_ID_INVALID != axis_ids[AXIS_THROTTLE])
{
- int currentPov = xinput_pov_dir[povindex];
- gamepad.povs[povindex] = (xinput_state.xstate.Gamepad.wButtons & currentPov) ? 0xFF : 0;
+ assignments.emplace_back(
+ IPT_PEDAL,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, axis_ids[AXIS_THROTTLE])));
+ assignments.emplace_back(
+ IPT_PEDAL2,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, axis_ids[AXIS_THROTTLE])));
}
- // Now do the buttons
- for (int buttonindex = 0; buttonindex < XINPUT_MAX_BUTTONS; buttonindex++)
+ // find something to use for directional controls and navigation
+ bool const axis_missing = (ITEM_ID_INVALID == axis_ids[AXIS_X]) || (ITEM_ID_INVALID == axis_ids[AXIS_Y]);
+ bool const hat_complete = has_thumb_right_x() && has_thumb_right_y();
+ if (axis_missing && hat_complete)
+ {
+ // X or Y missing - rely on POV hat
+ add_directional_assignments(
+ assignments,
+ axis_ids[AXIS_X],
+ axis_ids[AXIS_Y],
+ switch_ids[SWITCH_HAT_LEFT],
+ switch_ids[SWITCH_HAT_RIGHT],
+ switch_ids[SWITCH_HAT_UP],
+ switch_ids[SWITCH_HAT_DOWN]);
+
+ // choose something for previous/next group
+ if (consume_button_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, switch_ids[SWITCH_DPAD_UP], switch_ids[SWITCH_DPAD_DOWN]))
+ {
+ // took D-pad up/down
+ }
+ else if (consume_button_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, switch_ids[SWITCH_DPAD_LEFT], switch_ids[SWITCH_DPAD_RIGHT]))
+ {
+ // took D-pad left/right
+ }
+ else if (consume_axis_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, axis_ids[AXIS_RUDDER]))
+ {
+ // took rudder
+ }
+ else if (consume_axis_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, axis_ids[AXIS_THROTTLE]))
+ {
+ // took throttle
+ }
+
+ // choose something for zoom and focus previous/next
+ if (add_axis_pair_assignment(assignments, IPT_UI_ZOOM_OUT, IPT_UI_ZOOM_IN, axis_ids[AXIS_THROTTLE]))
+ {
+ if (!add_axis_pair_assignment(assignments, IPT_UI_FOCUS_PREV, IPT_UI_FOCUS_NEXT, axis_ids[AXIS_RUDDER]))
+ add_axis_pair_assignment(assignments, IPT_UI_FOCUS_PREV, IPT_UI_FOCUS_NEXT, axis_ids[AXIS_THROTTLE]);
+ }
+ else if (add_axis_pair_assignment(assignments, IPT_UI_ZOOM_OUT, IPT_UI_ZOOM_IN, axis_ids[AXIS_RUDDER]))
+ {
+ add_axis_pair_assignment(assignments, IPT_UI_FOCUS_PREV, IPT_UI_FOCUS_NEXT, axis_ids[AXIS_RUDDER]);
+ }
+ else if (add_button_pair_assignment(assignments, IPT_UI_ZOOM_OUT, IPT_UI_ZOOM_IN, switch_ids[SWITCH_DPAD_LEFT], switch_ids[SWITCH_DPAD_RIGHT]))
+ {
+ consume_button_pair(assignments, IPT_UI_FOCUS_PREV, IPT_UI_FOCUS_NEXT, switch_ids[SWITCH_DPAD_LEFT], switch_ids[SWITCH_DPAD_RIGHT]);
+ }
+ }
+ else
{
- int currentButton = xinput_buttons[buttonindex];
- gamepad.buttons[buttonindex] = (xinput_state.xstate.Gamepad.wButtons & currentButton) ? 0xFF : 0;
+ // only use stick for the primary directional controls
+ add_directional_assignments(
+ assignments,
+ axis_ids[AXIS_X],
+ axis_ids[AXIS_Y],
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID);
+
+ // assign the POV hat differently depending on whether rudder and/or throttle are present
+ if ((ITEM_ID_INVALID != axis_ids[AXIS_RUDDER]) || (ITEM_ID_INVALID != axis_ids[AXIS_THROTTLE]))
+ {
+ // previous/next group
+ if (consume_button_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, switch_ids[SWITCH_HAT_LEFT], switch_ids[SWITCH_HAT_RIGHT]))
+ {
+ // took hat left/right
+ }
+ else if (consume_button_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, switch_ids[SWITCH_DPAD_LEFT], switch_ids[SWITCH_DPAD_RIGHT]))
+ {
+ // took D-pad left/right
+ }
+ else if (consume_button_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, switch_ids[SWITCH_HAT_UP], switch_ids[SWITCH_HAT_DOWN]))
+ {
+ // took hat up/down
+ }
+ else if (consume_button_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, switch_ids[SWITCH_DPAD_UP], switch_ids[SWITCH_DPAD_DOWN]))
+ {
+ // took D-pad up/down
+ }
+ else if (consume_axis_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, axis_ids[AXIS_RUDDER]))
+ {
+ // took rudder
+ }
+ else if (consume_axis_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, axis_ids[AXIS_THROTTLE]))
+ {
+ // took throttle
+ }
+
+ // page up/down
+ if (consume_button_pair(assignments, IPT_UI_PAGE_UP, IPT_UI_PAGE_DOWN, switch_ids[SWITCH_HAT_UP], switch_ids[SWITCH_HAT_DOWN]))
+ {
+ // took hat up/down
+ }
+ else if (consume_button_pair(assignments, IPT_UI_PAGE_UP, IPT_UI_PAGE_DOWN, switch_ids[SWITCH_DPAD_UP], switch_ids[SWITCH_DPAD_DOWN]))
+ {
+ // took D-pad up/down
+ }
+ else if (consume_button_pair(assignments, IPT_UI_PAGE_UP, IPT_UI_PAGE_DOWN, switch_ids[SWITCH_DPAD_LEFT], switch_ids[SWITCH_DPAD_RIGHT]))
+ {
+ // took D-pad left/right
+ }
+
+ // home/end
+ if (consume_button_pair(assignments, IPT_UI_HOME, IPT_UI_END, switch_ids[SWITCH_DPAD_UP], switch_ids[SWITCH_DPAD_DOWN]))
+ {
+ // took D-pad up/down
+ }
+ else if (consume_button_pair(assignments, IPT_UI_HOME, IPT_UI_END, switch_ids[SWITCH_DPAD_LEFT], switch_ids[SWITCH_DPAD_RIGHT]))
+ {
+ // took D-pad left/right
+ }
+
+ // assign something for zoom - this can overlap with focus previous/next
+ if (add_axis_pair_assignment(assignments, IPT_UI_ZOOM_OUT, IPT_UI_ZOOM_IN, axis_ids[AXIS_THROTTLE]))
+ {
+ // took throttle
+ }
+ else if (add_button_pair_assignment(assignments, IPT_UI_ZOOM_OUT, IPT_UI_ZOOM_IN, switch_ids[SWITCH_DPAD_LEFT], switch_ids[SWITCH_DPAD_RIGHT]))
+ {
+ // took D-pad left/right
+ }
+ else if (add_axis_pair_assignment(assignments, IPT_UI_ZOOM_OUT, IPT_UI_ZOOM_IN, axis_ids[AXIS_RUDDER]))
+ {
+ // took rudder
+ }
+
+ // assign something for focus previous/next
+ if (add_axis_pair_assignment(assignments, IPT_UI_FOCUS_PREV, IPT_UI_FOCUS_NEXT, axis_ids[AXIS_RUDDER]))
+ {
+ // took rudder
+ }
+ else if (add_button_pair_assignment(assignments, IPT_UI_FOCUS_PREV, IPT_UI_FOCUS_NEXT, switch_ids[SWITCH_DPAD_LEFT], switch_ids[SWITCH_DPAD_RIGHT]))
+ {
+ // took D-pad left/right
+ }
+ else if (add_axis_pair_assignment(assignments, IPT_UI_FOCUS_PREV, IPT_UI_FOCUS_NEXT, axis_ids[AXIS_THROTTLE]))
+ {
+ // took throttle
+ }
+ }
+ else
+ {
+ // previous/next group
+ if (consume_button_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, switch_ids[SWITCH_HAT_UP], switch_ids[SWITCH_HAT_DOWN]))
+ {
+ // took hat up/down
+ }
+ else if (consume_button_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, switch_ids[SWITCH_DPAD_UP], switch_ids[SWITCH_DPAD_DOWN]))
+ {
+ // took D-pad up/down
+ }
+ else if (consume_button_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, switch_ids[SWITCH_HAT_LEFT], switch_ids[SWITCH_HAT_RIGHT]))
+ {
+ // took hat left/right
+ }
+ else if (consume_button_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, switch_ids[SWITCH_DPAD_LEFT], switch_ids[SWITCH_DPAD_RIGHT]))
+ {
+ // took D-pad left/right
+ }
+
+ // try to choose something for focus previous/next
+ if (add_button_pair_assignment(assignments, IPT_UI_FOCUS_PREV, IPT_UI_FOCUS_NEXT, switch_ids[SWITCH_HAT_LEFT], switch_ids[SWITCH_HAT_RIGHT]))
+ {
+ // took hat left/right - use it for zoom as well
+ consume_button_pair(assignments, IPT_UI_ZOOM_OUT, IPT_UI_ZOOM_IN, switch_ids[SWITCH_HAT_LEFT], switch_ids[SWITCH_HAT_RIGHT]);
+ }
+ else if (add_button_pair_assignment(assignments, IPT_UI_FOCUS_PREV, IPT_UI_FOCUS_NEXT, switch_ids[SWITCH_DPAD_LEFT], switch_ids[SWITCH_DPAD_RIGHT]))
+ {
+ // took D-pad left/right - use it for zoom as well
+ consume_button_pair(assignments, IPT_UI_ZOOM_OUT, IPT_UI_ZOOM_IN, switch_ids[SWITCH_DPAD_LEFT], switch_ids[SWITCH_DPAD_RIGHT]);
+ }
+ else if (add_button_pair_assignment(assignments, IPT_UI_FOCUS_PREV, IPT_UI_FOCUS_NEXT, switch_ids[SWITCH_DPAD_UP], switch_ids[SWITCH_DPAD_DOWN]))
+ {
+ // took D-pad left/right - use it for zoom as well
+ consume_button_pair(assignments, IPT_UI_ZOOM_OUT, IPT_UI_ZOOM_IN, switch_ids[SWITCH_DPAD_UP], switch_ids[SWITCH_DPAD_DOWN]);
+ }
+
+ // use D-pad for page up/down and home/end if it's still available
+ if (consume_button_pair(assignments, IPT_UI_PAGE_UP, IPT_UI_PAGE_DOWN, switch_ids[SWITCH_DPAD_UP], switch_ids[SWITCH_DPAD_DOWN]))
+ {
+ // took D-pad up/down
+ }
+ else if (consume_button_pair(assignments, IPT_UI_PAGE_UP, IPT_UI_PAGE_DOWN, switch_ids[SWITCH_DPAD_LEFT], switch_ids[SWITCH_DPAD_RIGHT]))
+ {
+ // took D-pad left/right
+ }
+ consume_button_pair(assignments, IPT_UI_HOME, IPT_UI_END, switch_ids[SWITCH_DPAD_LEFT], switch_ids[SWITCH_DPAD_RIGHT]);
+ }
}
- // Now grab the axis values
- // Each of the thumbstick axis members is a signed value between -32768 and 32767 describing the position of the thumbstick
- // However, the Y axis values are inverted from what MAME expects, so negate the value
- gamepad.left_thumb_x = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbLX, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
- gamepad.left_thumb_y = normalize_absolute_axis(-xinput_state.xstate.Gamepad.sThumbLY, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
- gamepad.right_thumb_x = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbRX, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
- gamepad.right_thumb_y = normalize_absolute_axis(-xinput_state.xstate.Gamepad.sThumbRY, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
+ // assign UI select/back/clear/help
+ assign_ui_actions(
+ assignments,
+ SWITCH_B,
+ SWITCH_X,
+ SWITCH_Y,
+ SWITCH_START,
+ SWITCH_BACK,
+ switch_ids,
+ numbered_buttons,
+ button_count);
- // Now the triggers, place them on half-axes (negative side)
- gamepad.left_trigger = -normalize_absolute_axis(xinput_state.xstate.Gamepad.bLeftTrigger, -255, 255);
- gamepad.right_trigger = -normalize_absolute_axis(xinput_state.xstate.Gamepad.bRightTrigger, -255, 255);
+ // set default assignments
+ device.set_default_assignments(std::move(assignments));
}
-void xinput_joystick_device::reset()
+
+
+//============================================================
+// XInput guitar handler
+//============================================================
+
+class xinput_guitar_device : public xinput_device_base
{
- memset(&gamepad, 0, sizeof(gamepad));
+public:
+ xinput_guitar_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ u32 player,
+ XINPUT_CAPABILITIES const &caps,
+ xinput_api_helper const &helper);
+
+ virtual void poll(bool relative_reset) override;
+ virtual void reset() override;
+ virtual void configure(input_device &device) override;
+
+private:
+ static inline constexpr USHORT SWITCH_BITS[] =
+ {
+ XINPUT_GAMEPAD_A,
+ XINPUT_GAMEPAD_B,
+ XINPUT_GAMEPAD_Y,
+ XINPUT_GAMEPAD_X,
+ XINPUT_GAMEPAD_LEFT_SHOULDER,
+ XINPUT_GAMEPAD_LEFT_THUMB,
+ XINPUT_GAMEPAD_RIGHT_SHOULDER,
+ XINPUT_GAMEPAD_RIGHT_THUMB,
+ XINPUT_GAMEPAD_START,
+ XINPUT_GAMEPAD_BACK,
+
+ XINPUT_GAMEPAD_DPAD_UP,
+ XINPUT_GAMEPAD_DPAD_DOWN,
+ XINPUT_GAMEPAD_DPAD_LEFT,
+ XINPUT_GAMEPAD_DPAD_RIGHT
+ };
+
+ enum
+ {
+ SWITCH_FRET1,
+ SWITCH_FRET2,
+ SWITCH_FRET3,
+ SWITCH_FRET4,
+ SWITCH_FRET5,
+ SWITCH_FRET_MOD, // indicates a "solo fret" is pressed, not a separate button
+ SWITCH_RB, // often reported present but no physical button
+ SWITCH_RSB, // usually reported absent
+ SWITCH_START,
+ SWITCH_BACK, // also used for "Star Power" in some games
+
+ SWITCH_DPAD_UP, // D-pad bits
+ SWITCH_DPAD_DOWN,
+ SWITCH_DPAD_LEFT,
+ SWITCH_DPAD_RIGHT,
+
+ SWITCH_TOTAL
+ };
+
+ enum
+ {
+ AXIS_SLIDER, // LSX, positive toward bridge
+ AXIS_LSY, // not used on guitar controllers?
+ AXIS_WHAMMY, // RSX, single-ended, neutral at negative extreme
+
+ AXIS_ORIENT_NECK, // RSY
+ AXIS_ORIENT_BRIDGE, // LT, toward zero with frets up
+ AXIS_ORIENT_BODY, // RT, toward zero in right-handed orientation
+
+ AXIS_PICKUP, // LT, positive extreme at one end
+
+ AXIS_TOTAL
+ };
+
+ u8 m_switches[SWITCH_TOTAL];
+ s32 m_axes[AXIS_TOTAL];
+};
+
+
+xinput_guitar_device::xinput_guitar_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ u32 player,
+ XINPUT_CAPABILITIES const &caps,
+ xinput_api_helper const &helper) :
+ xinput_device_base(std::move(name), std::move(id), module, player, caps, helper)
+{
+ std::fill(std::begin(m_switches), std::end(m_switches), 0);
+ std::fill(std::begin(m_axes), std::end(m_axes), 0);
+}
+
+
+void xinput_guitar_device::poll(bool relative_reset)
+{
+ // poll the device first, and skip if nothing changed
+ if (!read_state())
+ return;
+
+ // translate button bits
+ for (unsigned i = 0; std::size(SWITCH_BITS) > i; ++i)
+ m_switches[SWITCH_FRET1 + i] = (buttons() & SWITCH_BITS[i]) ? 0xff : 0x00;
+
+ // translate miscellaneous axes
+ m_axes[AXIS_SLIDER] = normalize_absolute_axis(thumb_left_x(), XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
+ m_axes[AXIS_LSY] = normalize_absolute_axis(-thumb_left_y(), XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
+ m_axes[AXIS_WHAMMY] = -normalize_absolute_axis(s32(thumb_right_x()) + 32'768, -65'535, 65'535);
+
+ // translate orientation sensors
+ m_axes[AXIS_ORIENT_NECK] = normalize_absolute_axis(-thumb_right_y(), XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
+ m_axes[AXIS_ORIENT_BRIDGE] = normalize_absolute_axis(trigger_left(), 0, 255);
+ m_axes[AXIS_ORIENT_BODY] = normalize_absolute_axis(trigger_right(), 0, 255);
+
+ // translate pickup selector
+ m_axes[AXIS_PICKUP] = -normalize_absolute_axis(trigger_left(), -255, 255);
+}
+
+
+void xinput_guitar_device::reset()
+{
+ set_reset();
+ std::fill(std::begin(m_switches), std::end(m_switches), 0);
+ std::fill(std::begin(m_axes), std::end(m_axes), 0);
+}
+
+
+void xinput_guitar_device::configure(input_device &device)
+{
+ // TODO: does subtype 0x06 indicate digital neck orientation sensor or lack of three-axis accelerometer?
+
+ // track item IDs for setting up default assignments
+ input_device::assignment_vector assignments;
+ input_item_id switch_ids[SWITCH_TOTAL];
+ std::fill(std::begin(switch_ids), std::end(switch_ids), ITEM_ID_INVALID);
+
+ // add axes
+ std::tuple<input_item_id, char const *, bool> const axis_caps[]{
+ { ITEM_ID_RXAXIS, "Neck Slider", has_thumb_left_x() },
+ { ITEM_ID_RYAXIS, "LSY", has_thumb_left_y() },
+ { ITEM_ID_SLIDER1, "Whammy Bar", has_thumb_right_x() },
+ { ITEM_ID_YAXIS, "Neck Orientation", has_thumb_right_y() },
+ { ITEM_ID_XAXIS, "Bridge Orientation", has_trigger_left() && has_trigger_right() },
+ { ITEM_ID_ZAXIS, "Body Orientation", has_trigger_right() },
+ { ITEM_ID_SLIDER2, "Pickup Selector", has_trigger_left() && !has_trigger_right() } };
+ input_item_id axis_ids[AXIS_TOTAL];
+ for (unsigned i = 0; AXIS_TOTAL > i; ++i)
+ {
+ auto const [item, name, supported] = axis_caps[i];
+ if (supported)
+ {
+ axis_ids[i] = device.add_item(
+ name,
+ std::string_view(),
+ item,
+ generic_axis_get_state<s32>,
+ &m_axes[i]);
+ }
+ else
+ {
+ axis_ids[i] = ITEM_ID_INVALID;
+ }
+ }
+
+ // add hats
+ for (unsigned i = 0; (SWITCH_DPAD_RIGHT - SWITCH_DPAD_UP) >= i; ++i)
+ {
+ if (has_button(SWITCH_BITS[SWITCH_DPAD_UP + i]))
+ {
+ switch_ids[SWITCH_DPAD_UP + i] = device.add_item(
+ HAT_NAMES_GUITAR[i],
+ std::string_view(),
+ input_item_id(ITEM_ID_HAT1UP + i), // matches up/down/left/right order
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_DPAD_UP + i]);
+ }
+ }
+
+ // add buttons
+ input_item_id button_id = ITEM_ID_BUTTON1;
+ unsigned button_count = 0;
+ unsigned numbered_buttons[SWITCH_FRET5 - SWITCH_FRET1 + 1];
+ for (unsigned i = 0; (SWITCH_RSB - SWITCH_FRET1) >= i; ++i)
+ {
+ if (has_button(SWITCH_BITS[i]))
+ {
+ switch_ids[SWITCH_FRET1 + i] = device.add_item(
+ BUTTON_NAMES_GUITAR[i],
+ std::string_view(),
+ button_id++,
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_FRET1 + i]);
+
+ // use fret buttons for automatically numbered buttons and pedals
+ if ((SWITCH_FRET5 - SWITCH_FRET1) >= i)
+ {
+ numbered_buttons[button_count] = SWITCH_FRET1 + i;
+ input_seq const seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, switch_ids[SWITCH_FRET1 + i]));
+ assignments.emplace_back(ioport_type(IPT_BUTTON1 + button_count), SEQ_TYPE_STANDARD, seq);
+ if (((ITEM_ID_INVALID != axis_ids[AXIS_WHAMMY]) ? 2 : 3) > button_count)
+ {
+ ioport_type const first_pedal = (ITEM_ID_INVALID != axis_ids[AXIS_WHAMMY])
+ ? IPT_PEDAL2
+ : IPT_PEDAL;
+ assignments.emplace_back(
+ ioport_type(first_pedal + button_count),
+ SEQ_TYPE_INCREMENT,
+ seq);
+ }
+ ++button_count;
+ }
+ }
+ }
+
+ // add start/back
+ if (has_button(XINPUT_GAMEPAD_START))
+ {
+ switch_ids[SWITCH_START] = device.add_item(
+ "Start",
+ std::string_view(),
+ ITEM_ID_START,
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_START]);
+ add_button_assignment(assignments, IPT_START, { switch_ids[SWITCH_START] });
+ }
+ if (has_button(XINPUT_GAMEPAD_BACK))
+ {
+ switch_ids[SWITCH_BACK] = device.add_item(
+ "Back",
+ std::string_view(),
+ ITEM_ID_SELECT,
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_BACK]);
+ add_button_assignment(assignments, IPT_SELECT, { switch_ids[SWITCH_BACK] });
+ }
+
+ // use the D-pad for directional controls - accelerometers are an annoyance
+ add_directional_assignments(
+ assignments,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ switch_ids[SWITCH_DPAD_LEFT],
+ switch_ids[SWITCH_DPAD_RIGHT],
+ switch_ids[SWITCH_DPAD_UP],
+ switch_ids[SWITCH_DPAD_DOWN]);
+
+ // use the whammy bar for the first pedal and focus next if present
+ if (ITEM_ID_INVALID != axis_ids[AXIS_WHAMMY])
+ {
+ assignments.emplace_back(
+ IPT_PEDAL,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, axis_ids[AXIS_WHAMMY])));
+ assignments.emplace_back(
+ IPT_UI_FOCUS_NEXT,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, axis_ids[AXIS_WHAMMY])));
+ }
+
+ // use the neck slider for a couple of things if it's present
+ if (ITEM_ID_INVALID != axis_ids[AXIS_SLIDER])
+ {
+ input_seq const seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, axis_ids[AXIS_SLIDER]));
+ assignments.emplace_back(IPT_PADDLE, SEQ_TYPE_STANDARD, seq);
+ assignments.emplace_back(IPT_AD_STICK_X, SEQ_TYPE_STANDARD, seq);
+ }
+
+ // assign UI select/back/clear/help
+ assign_ui_actions(
+ assignments,
+ SWITCH_FRET2,
+ SWITCH_FRET3,
+ SWITCH_FRET4,
+ SWITCH_START,
+ SWITCH_BACK,
+ switch_ids,
+ numbered_buttons,
+ button_count);
+
+ // set default assignments
+ device.set_default_assignments(std::move(assignments));
}
-void xinput_joystick_device::configure()
+
+
+//============================================================
+// XInput drum kit handler
+//============================================================
+
+class xinput_drumkit_device : public xinput_device_base
{
- std::lock_guard<std::mutex> scope_lock(m_device_lock);
+public:
+ xinput_drumkit_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ u32 player,
+ XINPUT_CAPABILITIES const &caps,
+ xinput_api_helper const &helper);
+
+ virtual void poll(bool relative_reset) override;
+ virtual void reset() override;
+ virtual void configure(input_device &device) override;
+
+private:
+ static inline constexpr USHORT SWITCH_BITS[] =
+ {
+ XINPUT_GAMEPAD_A,
+ XINPUT_GAMEPAD_B,
+ XINPUT_GAMEPAD_X,
+ XINPUT_GAMEPAD_Y,
+ XINPUT_GAMEPAD_RIGHT_SHOULDER,
+ XINPUT_GAMEPAD_LEFT_SHOULDER,
+ XINPUT_GAMEPAD_LEFT_THUMB,
+ XINPUT_GAMEPAD_RIGHT_THUMB,
+ XINPUT_GAMEPAD_START,
+ XINPUT_GAMEPAD_BACK,
+
+ XINPUT_GAMEPAD_DPAD_UP,
+ XINPUT_GAMEPAD_DPAD_DOWN,
+ XINPUT_GAMEPAD_DPAD_LEFT,
+ XINPUT_GAMEPAD_DPAD_RIGHT
+ };
+
+ enum
+ {
+ SWITCH_GREEN, // button bits
+ SWITCH_RED,
+ SWITCH_BLUE,
+ SWITCH_YELLOW,
+ SWITCH_ORANGE,
+ SWITCH_BASS_DRUM,
+ SWITCH_LSB,
+ SWITCH_RSB,
+ SWITCH_START,
+ SWITCH_BACK,
- if (m_configured)
+ SWITCH_DPAD_UP, // D-pad bits
+ SWITCH_DPAD_DOWN,
+ SWITCH_DPAD_LEFT,
+ SWITCH_DPAD_RIGHT,
+
+ SWITCH_TOTAL
+ };
+
+ enum
+ {
+ AXIS_GREEN, // LSY low
+ AXIS_RED, // LSY high
+ AXIS_BLUE, // RSX high
+ AXIS_YELLOW, // RSX low
+ AXIS_ORANGE, // RSY low
+ AXIS_BASS_DRUM, // RSY high
+
+ AXIS_TOTAL
+ };
+
+ u8 m_switches[SWITCH_TOTAL];
+ s32 m_axes[AXIS_TOTAL];
+};
+
+
+xinput_drumkit_device::xinput_drumkit_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ u32 player,
+ XINPUT_CAPABILITIES const &caps,
+ xinput_api_helper const &helper) :
+ xinput_device_base(std::move(name), std::move(id), module, player, caps, helper)
+{
+ std::fill(std::begin(m_switches), std::end(m_switches), 0);
+ std::fill(std::begin(m_axes), std::end(m_axes), 0);
+}
+
+
+void xinput_drumkit_device::poll(bool relative_reset)
+{
+ // poll the device first, and skip if nothing changed
+ if (!read_state())
return;
- // Add the axes
- for (int axisnum = 0; axisnum < XINPUT_MAX_AXIS; axisnum++)
+ // translate button bits
+ for (unsigned i = 0; std::size(SWITCH_BITS) > i; ++i)
+ m_switches[SWITCH_GREEN + i] = (buttons() & SWITCH_BITS[i]) ? 0xff : 0x00;
+
+ // translate axes
+ m_axes[AXIS_GREEN] = -normalize_absolute_axis(BIT(u16(thumb_left_y()), 0, 8), -255, 255);
+ m_axes[AXIS_RED] = -normalize_absolute_axis(BIT(u16(thumb_left_y()), 8, 8), -255, 255);
+ m_axes[AXIS_BLUE] = -normalize_absolute_axis(BIT(u16(thumb_right_x()), 8, 8), -255, 255);
+ m_axes[AXIS_YELLOW] = -normalize_absolute_axis(BIT(u16(thumb_right_x()), 0, 8), -255, 255);
+ m_axes[AXIS_ORANGE] = -normalize_absolute_axis(BIT(u16(thumb_right_y()), 0, 8), -255, 255);
+ m_axes[AXIS_BASS_DRUM] = -normalize_absolute_axis(BIT(u16(thumb_right_y()), 8, 8), -255, 255);
+}
+
+
+void xinput_drumkit_device::reset()
+{
+ set_reset();
+ std::fill(std::begin(m_switches), std::end(m_switches), 0);
+ std::fill(std::begin(m_axes), std::end(m_axes), 0);
+}
+
+
+void xinput_drumkit_device::configure(input_device &device)
+{
+ // track item IDs for setting up default assignments
+ input_device::assignment_vector assignments;
+ input_item_id switch_ids[SWITCH_TOTAL];
+ std::fill(std::begin(switch_ids), std::end(switch_ids), ITEM_ID_INVALID);
+
+ // add axes
+ std::tuple<input_item_id, char const *, bool> const axis_caps[]{
+ { ITEM_ID_XAXIS, "Green Velocity", has_thumb_left_y() },
+ { ITEM_ID_YAXIS, "Red Velocity", has_thumb_left_y() },
+ { ITEM_ID_ZAXIS, "Blue Velocity", has_thumb_right_x() },
+ { ITEM_ID_RXAXIS, "Yellow Velocity", has_thumb_right_x() },
+ { ITEM_ID_RYAXIS, "Orange Velocity", has_thumb_right_y() },
+ { ITEM_ID_RZAXIS, "Bass Drum Velocity", has_thumb_right_y() } };
+ for (unsigned i = 0; (AXIS_BASS_DRUM - AXIS_GREEN) >= i; ++i)
{
- device()->add_item(
- xinput_axis_name[axisnum],
- xinput_axis_ids[axisnum],
- generic_axis_get_state<LONG>,
- &gamepad.left_thumb_x + axisnum);
+ auto const [item, name, supported] = axis_caps[i];
+ if (supported)
+ {
+ device.add_item(
+ name,
+ std::string_view(),
+ item,
+ generic_axis_get_state<s32>,
+ &m_axes[AXIS_GREEN + i]);
+ }
}
- // Populate the POVs
- // For XBOX, we treat the DPAD as a hat switch
- for (int povnum = 0; povnum < XINPUT_MAX_POV; povnum++)
+ // add hats
+ for (unsigned i = 0; (SWITCH_DPAD_RIGHT - SWITCH_DPAD_UP) >= i; ++i)
{
- device()->add_item(
- xinput_pov_names[povnum],
- ITEM_ID_OTHER_SWITCH,
- generic_button_get_state<BYTE>,
- &gamepad.povs[povnum]);
+ if (has_button(SWITCH_BITS[SWITCH_DPAD_UP + i]))
+ {
+ switch_ids[SWITCH_DPAD_UP + i] = device.add_item(
+ HAT_NAMES_GAMEPAD[i],
+ std::string_view(),
+ input_item_id(ITEM_ID_HAT1UP + i), // matches up/down/left/right order
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_DPAD_UP + i]);
+ }
}
- // populate the buttons
- for (int butnum = 0; butnum < XINPUT_MAX_BUTTONS; butnum++)
+ // add buttons
+ unsigned button_count = 0;
+ unsigned numbered_buttons[SWITCH_RSB - SWITCH_GREEN + 1];
+ for (unsigned i = 0; (SWITCH_RSB - SWITCH_GREEN) >= i; ++i)
{
- device()->add_item(
- xinput_button_names[butnum],
- static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum),
- generic_button_get_state<BYTE>,
- &gamepad.buttons[butnum]);
+ if (has_button(SWITCH_BITS[i]))
+ {
+ switch_ids[SWITCH_GREEN + i] = device.add_item(
+ BUTTON_NAMES_DRUMKIT[i],
+ std::string_view(),
+ input_item_id(ITEM_ID_BUTTON1 + button_count),
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_GREEN + i]);
+ numbered_buttons[button_count] = SWITCH_GREEN + i;
+
+ // use these for automatically numbered buttons and pedals
+ input_seq const seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, switch_ids[SWITCH_GREEN + i]));
+ assignments.emplace_back(ioport_type(IPT_BUTTON1 + button_count), SEQ_TYPE_STANDARD, seq);
+ if (3 > button_count)
+ assignments.emplace_back(ioport_type(IPT_PEDAL + button_count), SEQ_TYPE_INCREMENT, seq);
+ ++button_count;
+ }
}
- device()->add_item(
- "RT",
- ITEM_ID_ZAXIS,
- generic_axis_get_state<LONG>,
- &gamepad.right_trigger);
+ // add start/back
+ if (has_button(XINPUT_GAMEPAD_START))
+ {
+ switch_ids[SWITCH_START] = device.add_item(
+ "Start",
+ std::string_view(),
+ ITEM_ID_START,
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_START]);
+ add_button_assignment(assignments, IPT_START, { switch_ids[SWITCH_START] });
+ }
+ if (has_button(XINPUT_GAMEPAD_BACK))
+ {
+ switch_ids[SWITCH_BACK] = device.add_item(
+ "Back",
+ std::string_view(),
+ ITEM_ID_SELECT,
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_BACK]);
+ add_button_assignment(assignments, IPT_SELECT, { switch_ids[SWITCH_BACK] });
+ }
- device()->add_item(
- "LT",
- ITEM_ID_RZAXIS,
- generic_axis_get_state<LONG>,
- &gamepad.left_trigger);
+ // use the D-pad for directional controls
+ add_directional_assignments(
+ assignments,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ switch_ids[SWITCH_DPAD_LEFT],
+ switch_ids[SWITCH_DPAD_RIGHT],
+ switch_ids[SWITCH_DPAD_UP],
+ switch_ids[SWITCH_DPAD_DOWN]);
+
+ // use the D-pad and A/B/X/Y diamond for twin sticks
+ add_twin_stick_assignments(
+ assignments,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ switch_ids[SWITCH_DPAD_LEFT],
+ switch_ids[SWITCH_DPAD_RIGHT],
+ switch_ids[SWITCH_DPAD_UP],
+ switch_ids[SWITCH_DPAD_DOWN],
+ switch_ids[SWITCH_BLUE],
+ switch_ids[SWITCH_RED],
+ switch_ids[SWITCH_YELLOW],
+ switch_ids[SWITCH_GREEN]);
- m_configured = true;
+ // assign UI select/back/clear/help
+ assign_ui_actions(
+ assignments,
+ SWITCH_RED,
+ SWITCH_BLUE,
+ SWITCH_YELLOW,
+ SWITCH_START,
+ SWITCH_BACK,
+ switch_ids,
+ numbered_buttons,
+ button_count);
+
+ // use bass drum pedal for focus next if available to make the system selection menu usable
+ if (add_button_assignment(assignments, IPT_UI_FOCUS_NEXT, { switch_ids[SWITCH_BASS_DRUM] }))
+ switch_ids[SWITCH_BASS_DRUM] = ITEM_ID_INVALID;
+
+ // set default assignments
+ device.set_default_assignments(std::move(assignments));
}
+
+
//============================================================
-// xinput_joystick_module
+// XInput turntable handler
//============================================================
-class xinput_joystick_module : public wininput_module
+class xinput_turntable_device : public xinput_device_base
{
+public:
+ xinput_turntable_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ u32 player,
+ XINPUT_CAPABILITIES const &caps,
+ xinput_api_helper const &helper);
+
+ virtual void poll(bool relative_reset) override;
+ virtual void reset() override;
+ virtual void configure(input_device &device) override;
+
private:
- std::shared_ptr<xinput_api_helper> m_xinput_helper;
+ static inline constexpr USHORT SWITCH_BITS[] =
+ {
+ XINPUT_GAMEPAD_A,
+ XINPUT_GAMEPAD_B,
+ XINPUT_GAMEPAD_X,
+ XINPUT_GAMEPAD_Y,
+ XINPUT_GAMEPAD_LEFT_SHOULDER,
+ XINPUT_GAMEPAD_RIGHT_SHOULDER,
+ XINPUT_GAMEPAD_LEFT_THUMB,
+ XINPUT_GAMEPAD_RIGHT_THUMB,
+ XINPUT_GAMEPAD_START,
+ XINPUT_GAMEPAD_BACK,
+
+ XINPUT_GAMEPAD_DPAD_UP,
+ XINPUT_GAMEPAD_DPAD_DOWN,
+ XINPUT_GAMEPAD_DPAD_LEFT,
+ XINPUT_GAMEPAD_DPAD_RIGHT
+ };
+ enum
+ {
+ SWITCH_A, // button bits
+ SWITCH_B,
+ SWITCH_X,
+ SWITCH_Y,
+ SWITCH_LB,
+ SWITCH_RB,
+ SWITCH_LSB,
+ SWITCH_RSB,
+ SWITCH_START,
+ SWITCH_BACK,
+
+ SWITCH_DPAD_UP, // D-pad bits
+ SWITCH_DPAD_DOWN,
+ SWITCH_DPAD_LEFT,
+ SWITCH_DPAD_RIGHT,
+
+ SWITCH_GREEN, // RT bits
+ SWITCH_RED,
+ SWITCH_BLUE,
+
+ SWITCH_TOTAL
+ };
+
+ enum
+ {
+ AXIS_TURNTABLE, // LSY
+ AXIS_EFFECT, // RSX
+ AXIS_CROSSFADE, // RSY
+
+ AXIS_TOTAL
+ };
+
+ u8 m_switches[SWITCH_TOTAL];
+ s32 m_axes[AXIS_TOTAL];
+ u16 m_prev_effect;
+};
+
+
+xinput_turntable_device::xinput_turntable_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ u32 player,
+ XINPUT_CAPABILITIES const &caps,
+ xinput_api_helper const &helper) :
+ xinput_device_base(std::move(name), std::move(id), module, player, caps, helper),
+ m_prev_effect(0)
+{
+ std::fill(std::begin(m_switches), std::end(m_switches), 0);
+ std::fill(std::begin(m_axes), std::end(m_axes), 0);
+}
+
+
+void xinput_turntable_device::poll(bool relative_reset)
+{
+ // poll the device first
+ bool const was_reset = is_reset();
+ if (read_state())
+ {
+ // translate button bits
+ for (unsigned i = 0; std::size(SWITCH_BITS) > i; ++i)
+ m_switches[SWITCH_A + i] = (buttons() & SWITCH_BITS[i]) ? 0xff : 0x00;
+
+ // translate RT bits
+ for (unsigned i = 0; (SWITCH_BLUE - SWITCH_GREEN) >= i; ++i)
+ m_switches[SWITCH_GREEN + i] = BIT(trigger_right(), i) ? 0xff : 0x00;
+
+ // translate axes
+ m_axes[AXIS_TURNTABLE] = s32(thumb_left_y()) * input_device::RELATIVE_PER_PIXEL * 2;
+ m_axes[AXIS_CROSSFADE] = normalize_absolute_axis(thumb_right_y(), XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
+ }
+
+ // handle effect dial
+ if (was_reset)
+ {
+ // just grab the current count after regaining focus
+ m_prev_effect = u16(thumb_right_x());
+ }
+ else if (relative_reset)
+ {
+ // convert value to relative displacement
+ s32 effect_delta = s32(u32(u16(thumb_right_x()))) - s32(u32(m_prev_effect));
+ m_prev_effect = u16(thumb_right_x());
+ if (0x8000 < effect_delta)
+ effect_delta -= 0x1'0000;
+ else if (-0x8000 > effect_delta)
+ effect_delta += 0x1'0000;
+ m_axes[AXIS_EFFECT] = effect_delta * input_device::RELATIVE_PER_PIXEL / 128;
+ }
+}
+
+
+void xinput_turntable_device::reset()
+{
+ set_reset();
+ std::fill(std::begin(m_switches), std::end(m_switches), 0);
+ std::fill(std::begin(m_axes), std::end(m_axes), 0);
+}
+
+
+void xinput_turntable_device::configure(input_device &device)
+{
+ // track item IDs for setting up default assignments
+ input_device::assignment_vector assignments;
+ input_item_id switch_ids[SWITCH_TOTAL];
+ std::fill(std::begin(switch_ids), std::end(switch_ids), ITEM_ID_INVALID);
+
+ // add axes
+ input_item_id const turntable_id = device.add_item(
+ "Turntable",
+ std::string_view(),
+ ITEM_ID_ADD_RELATIVE1,
+ generic_axis_get_state<s32>,
+ &m_axes[AXIS_TURNTABLE]);
+ input_item_id const effect_id = device.add_item(
+ "Effect",
+ std::string_view(),
+ ITEM_ID_ADD_RELATIVE2,
+ generic_axis_get_state<s32>,
+ &m_axes[AXIS_EFFECT]);
+ input_item_id const crossfade_id = device.add_item(
+ "Crossfade",
+ std::string_view(),
+ ITEM_ID_XAXIS,
+ generic_axis_get_state<s32>,
+ &m_axes[AXIS_CROSSFADE]);
+
+ // add hats
+ for (unsigned i = 0; (SWITCH_DPAD_RIGHT - SWITCH_DPAD_UP) >= i; ++i)
+ {
+ if (has_button(SWITCH_BITS[SWITCH_DPAD_UP + i]))
+ {
+ switch_ids[SWITCH_DPAD_UP + i] = device.add_item(
+ HAT_NAMES_GAMEPAD[i],
+ std::string_view(),
+ input_item_id(ITEM_ID_HAT1UP + i), // matches up/down/left/right order
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_DPAD_UP + i]);
+ }
+ }
+
+ // add buttons
+ input_item_id button_id = ITEM_ID_BUTTON1;
+ unsigned button_count = 0;
+ unsigned numbered_buttons[SWITCH_RSB - SWITCH_A + 1];
+ for (unsigned i = 0; (SWITCH_RSB - SWITCH_A) >= i; ++i)
+ {
+ if (has_button(SWITCH_BITS[i]))
+ {
+ switch_ids[SWITCH_A + i] = device.add_item(
+ BUTTON_NAMES_KEYBOARD[i],
+ std::string_view(),
+ button_id++,
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_A + i]);
+ numbered_buttons[button_count] = SWITCH_A + i;
+
+ // use these for automatically numbered buttons and pedals
+ input_seq const seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, switch_ids[SWITCH_A + i]));
+ assignments.emplace_back(ioport_type(IPT_BUTTON1 + button_count), SEQ_TYPE_STANDARD, seq);
+ if (3 > button_count)
+ assignments.emplace_back(ioport_type(IPT_PEDAL + button_count), SEQ_TYPE_INCREMENT, seq);
+ ++button_count;
+ }
+ }
+
+ // turntable buttons activate these as well as A/B/X
+ switch_ids[SWITCH_GREEN] = device.add_item(
+ "Green",
+ std::string_view(),
+ button_id++,
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_GREEN]);
+ switch_ids[SWITCH_RED] = device.add_item(
+ "Red",
+ std::string_view(),
+ button_id++,
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_RED]);
+ switch_ids[SWITCH_BLUE] = device.add_item(
+ "Blue",
+ std::string_view(),
+ button_id++,
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_BLUE]);
+
+ // add start/back
+ if (has_button(XINPUT_GAMEPAD_START))
+ {
+ switch_ids[SWITCH_START] = device.add_item(
+ "Start",
+ std::string_view(),
+ ITEM_ID_START,
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_START]);
+ add_button_assignment(assignments, IPT_START, { switch_ids[SWITCH_START] });
+ }
+ if (has_button(XINPUT_GAMEPAD_BACK))
+ {
+ switch_ids[SWITCH_BACK] = device.add_item(
+ "Back",
+ std::string_view(),
+ ITEM_ID_SELECT,
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_BACK]);
+ add_button_assignment(assignments, IPT_SELECT, { switch_ids[SWITCH_BACK] });
+ }
+
+ // use D-pad and A/B/X/Y diamond for twin sticks
+ add_twin_stick_assignments(
+ assignments,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ switch_ids[SWITCH_DPAD_LEFT],
+ switch_ids[SWITCH_DPAD_RIGHT],
+ switch_ids[SWITCH_DPAD_UP],
+ switch_ids[SWITCH_DPAD_DOWN],
+ switch_ids[SWITCH_X],
+ switch_ids[SWITCH_B],
+ switch_ids[SWITCH_Y],
+ switch_ids[SWITCH_A]);
+
+ // for most analog player controls, use turntable for X and effect for Y
+ input_seq const turntable_seq(make_code(ITEM_CLASS_RELATIVE, ITEM_MODIFIER_NONE, turntable_id));
+ input_seq const effect_seq(make_code(ITEM_CLASS_RELATIVE, ITEM_MODIFIER_NONE, effect_id));
+ input_seq const crossfade_seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, crossfade_id));
+ input_seq joystick_left_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, turntable_id));
+ input_seq joystick_right_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, turntable_id));
+ input_seq joystick_up_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, effect_id));
+ input_seq joystick_down_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, effect_id));
+ assignments.emplace_back(IPT_PADDLE, SEQ_TYPE_STANDARD, turntable_seq);
+ assignments.emplace_back(IPT_PADDLE_V, SEQ_TYPE_STANDARD, effect_seq);
+ assignments.emplace_back(IPT_POSITIONAL, SEQ_TYPE_STANDARD, crossfade_seq);
+ assignments.emplace_back(IPT_POSITIONAL_V, SEQ_TYPE_STANDARD, effect_seq);
+ assignments.emplace_back(IPT_DIAL, SEQ_TYPE_STANDARD, turntable_seq);
+ assignments.emplace_back(IPT_DIAL_V, SEQ_TYPE_STANDARD, effect_seq);
+ assignments.emplace_back(IPT_TRACKBALL_X, SEQ_TYPE_STANDARD, turntable_seq);
+ assignments.emplace_back(IPT_TRACKBALL_Y, SEQ_TYPE_STANDARD, effect_seq);
+ assignments.emplace_back(IPT_AD_STICK_X, SEQ_TYPE_STANDARD, turntable_seq);
+ assignments.emplace_back(IPT_AD_STICK_Y, SEQ_TYPE_STANDARD, effect_seq);
+ assignments.emplace_back(IPT_AD_STICK_Z, SEQ_TYPE_STANDARD, crossfade_seq);
+ assignments.emplace_back(IPT_LIGHTGUN_X, SEQ_TYPE_STANDARD, turntable_seq);
+ assignments.emplace_back(IPT_LIGHTGUN_Y, SEQ_TYPE_STANDARD, effect_seq);
+ assignments.emplace_back(IPT_MOUSE_X, SEQ_TYPE_STANDARD, turntable_seq);
+ assignments.emplace_back(IPT_MOUSE_Y, SEQ_TYPE_STANDARD, effect_seq);
+
+ // use D-pad for analog controls as well if present
+ bool const have_dpad_left = ITEM_ID_INVALID != switch_ids[SWITCH_DPAD_LEFT];
+ bool const have_dpad_right = ITEM_ID_INVALID != switch_ids[SWITCH_DPAD_RIGHT];
+ bool const have_dpad_up = ITEM_ID_INVALID != switch_ids[SWITCH_DPAD_UP];
+ bool const have_dpad_down = ITEM_ID_INVALID != switch_ids[SWITCH_DPAD_DOWN];
+ if (have_dpad_left)
+ {
+ input_code const code(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, switch_ids[SWITCH_DPAD_LEFT]));
+ input_seq const left_seq(code);
+ joystick_left_seq += input_seq::or_code;
+ joystick_left_seq += code;
+ assignments.emplace_back(IPT_PADDLE, SEQ_TYPE_DECREMENT, left_seq);
+ assignments.emplace_back(IPT_POSITIONAL, SEQ_TYPE_DECREMENT, left_seq);
+ assignments.emplace_back(IPT_DIAL, SEQ_TYPE_DECREMENT, left_seq);
+ assignments.emplace_back(IPT_TRACKBALL_X, SEQ_TYPE_DECREMENT, left_seq);
+ assignments.emplace_back(IPT_AD_STICK_X, SEQ_TYPE_DECREMENT, left_seq);
+ assignments.emplace_back(IPT_LIGHTGUN_X, SEQ_TYPE_DECREMENT, left_seq);
+ }
+ if (have_dpad_right)
+ {
+ input_code const code(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, switch_ids[SWITCH_DPAD_RIGHT]));
+ input_seq const right_seq(code);
+ joystick_right_seq += input_seq::or_code;
+ joystick_right_seq += code;
+ assignments.emplace_back(IPT_PADDLE, SEQ_TYPE_INCREMENT, right_seq);
+ assignments.emplace_back(IPT_POSITIONAL, SEQ_TYPE_INCREMENT, right_seq);
+ assignments.emplace_back(IPT_DIAL, SEQ_TYPE_INCREMENT, right_seq);
+ assignments.emplace_back(IPT_TRACKBALL_X, SEQ_TYPE_INCREMENT, right_seq);
+ assignments.emplace_back(IPT_AD_STICK_X, SEQ_TYPE_INCREMENT, right_seq);
+ assignments.emplace_back(IPT_LIGHTGUN_X, SEQ_TYPE_INCREMENT, right_seq);
+ }
+ if (have_dpad_up)
+ {
+ input_code const code(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, switch_ids[SWITCH_DPAD_UP]));
+ input_seq const up_seq(code);
+ joystick_up_seq += input_seq::or_code;
+ joystick_up_seq += code;
+ assignments.emplace_back(IPT_PADDLE_V, SEQ_TYPE_DECREMENT, up_seq);
+ assignments.emplace_back(IPT_POSITIONAL_V, SEQ_TYPE_DECREMENT, up_seq);
+ assignments.emplace_back(IPT_DIAL_V, SEQ_TYPE_DECREMENT, up_seq);
+ assignments.emplace_back(IPT_TRACKBALL_Y, SEQ_TYPE_DECREMENT, up_seq);
+ assignments.emplace_back(IPT_AD_STICK_Y, SEQ_TYPE_DECREMENT, up_seq);
+ assignments.emplace_back(IPT_LIGHTGUN_Y, SEQ_TYPE_DECREMENT, up_seq);
+ }
+ if (have_dpad_down)
+ {
+ input_code const code(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, switch_ids[SWITCH_DPAD_DOWN]));
+ input_seq const down_seq(code);
+ joystick_down_seq += input_seq::or_code;
+ joystick_down_seq += code;
+ assignments.emplace_back(IPT_PADDLE_V, SEQ_TYPE_INCREMENT, down_seq);
+ assignments.emplace_back(IPT_POSITIONAL_V, SEQ_TYPE_INCREMENT, down_seq);
+ assignments.emplace_back(IPT_DIAL_V, SEQ_TYPE_INCREMENT, down_seq);
+ assignments.emplace_back(IPT_TRACKBALL_Y, SEQ_TYPE_INCREMENT, down_seq);
+ assignments.emplace_back(IPT_AD_STICK_Y, SEQ_TYPE_INCREMENT, down_seq);
+ assignments.emplace_back(IPT_LIGHTGUN_Y, SEQ_TYPE_INCREMENT, down_seq);
+ }
+ assignments.emplace_back(IPT_JOYSTICK_LEFT, SEQ_TYPE_STANDARD, joystick_left_seq);
+ assignments.emplace_back(IPT_JOYSTICK_RIGHT, SEQ_TYPE_STANDARD, joystick_right_seq);
+ assignments.emplace_back(IPT_JOYSTICK_UP, SEQ_TYPE_STANDARD, joystick_up_seq);
+ assignments.emplace_back(IPT_JOYSTICK_DOWN, SEQ_TYPE_STANDARD, joystick_down_seq);
+
+ // choose navigation controls
+ input_seq ui_up_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, turntable_id));
+ input_seq ui_down_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, turntable_id));
+ input_seq ui_left_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, effect_id));
+ input_seq ui_right_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, effect_id));
+ if ((have_dpad_up && have_dpad_down) || !have_dpad_left || !have_dpad_right)
+ {
+ if (have_dpad_up)
+ {
+ ui_up_seq += input_seq::or_code;
+ ui_up_seq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, switch_ids[SWITCH_DPAD_UP]);
+ }
+ if (have_dpad_down)
+ {
+ ui_down_seq += input_seq::or_code;
+ ui_down_seq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, switch_ids[SWITCH_DPAD_DOWN]);
+ }
+ if (have_dpad_left)
+ {
+ ui_left_seq += input_seq::or_code;
+ ui_left_seq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, switch_ids[SWITCH_DPAD_LEFT]);
+ }
+ if (have_dpad_right)
+ {
+ ui_right_seq += input_seq::or_code;
+ ui_right_seq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, switch_ids[SWITCH_DPAD_RIGHT]);
+ }
+ }
+ else
+ {
+ if (have_dpad_left)
+ {
+ ui_up_seq += input_seq::or_code;
+ ui_up_seq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, switch_ids[SWITCH_DPAD_LEFT]);
+ }
+ if (have_dpad_right)
+ {
+ ui_down_seq += input_seq::or_code;
+ ui_down_seq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, switch_ids[SWITCH_DPAD_RIGHT]);
+ }
+ if (have_dpad_up)
+ {
+ ui_left_seq += input_seq::or_code;
+ ui_left_seq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, switch_ids[SWITCH_DPAD_UP]);
+ }
+ if (have_dpad_down)
+ {
+ ui_right_seq += input_seq::or_code;
+ ui_right_seq += make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, switch_ids[SWITCH_DPAD_DOWN]);
+ }
+ }
+ assignments.emplace_back(IPT_UI_UP, SEQ_TYPE_STANDARD, ui_up_seq);
+ assignments.emplace_back(IPT_UI_DOWN, SEQ_TYPE_STANDARD, ui_down_seq);
+ assignments.emplace_back(IPT_UI_LEFT, SEQ_TYPE_STANDARD, ui_left_seq);
+ assignments.emplace_back(IPT_UI_RIGHT, SEQ_TYPE_STANDARD, ui_right_seq);
+
+ // assign UI select/back/clear/help
+ assign_ui_actions(
+ assignments,
+ SWITCH_B,
+ SWITCH_X,
+ SWITCH_Y,
+ SWITCH_START,
+ SWITCH_BACK,
+ switch_ids,
+ numbered_buttons,
+ std::min<unsigned>(button_count, 4));
+
+ // set default assignments
+ device.set_default_assignments(std::move(assignments));
+}
+
+
+
+//============================================================
+// XInput keyboard handler
+//============================================================
+
+class xinput_keyboard_device : public xinput_device_base
+{
public:
- xinput_joystick_module()
- : wininput_module(OSD_JOYSTICKINPUT_PROVIDER, "xinput"),
- m_xinput_helper(nullptr)
+ xinput_keyboard_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ u32 player,
+ XINPUT_CAPABILITIES const &caps,
+ xinput_api_helper const &helper);
+
+ virtual void poll(bool relative_reset) override;
+ virtual void reset() override;
+ virtual void configure(input_device &device) override;
+
+private:
+ static inline constexpr USHORT SWITCH_BITS[] =
{
+ XINPUT_GAMEPAD_A,
+ XINPUT_GAMEPAD_B,
+ XINPUT_GAMEPAD_X,
+ XINPUT_GAMEPAD_Y,
+ XINPUT_GAMEPAD_LEFT_SHOULDER,
+ XINPUT_GAMEPAD_RIGHT_SHOULDER,
+ XINPUT_GAMEPAD_LEFT_THUMB,
+ XINPUT_GAMEPAD_RIGHT_THUMB,
+ XINPUT_GAMEPAD_START,
+ XINPUT_GAMEPAD_BACK,
+
+ XINPUT_GAMEPAD_DPAD_UP,
+ XINPUT_GAMEPAD_DPAD_DOWN,
+ XINPUT_GAMEPAD_DPAD_LEFT,
+ XINPUT_GAMEPAD_DPAD_RIGHT
+ };
+
+ enum
+ {
+ SWITCH_A, // button bits
+ SWITCH_B,
+ SWITCH_X,
+ SWITCH_Y,
+ SWITCH_LB,
+ SWITCH_RB,
+ SWITCH_LSB,
+ SWITCH_RSB,
+ SWITCH_START,
+ SWITCH_BACK,
+
+ SWITCH_DPAD_UP, // D-pad bits
+ SWITCH_DPAD_DOWN,
+ SWITCH_DPAD_LEFT,
+ SWITCH_DPAD_RIGHT,
+
+ SWITCH_C1,
+ SWITCH_C3 = SWITCH_C1 + 24,
+
+ SWITCH_TOTAL
+ };
+
+ enum
+ {
+ AXIS_VELOCITY, // field in LSX
+ AXIS_PEDAL, // RSY, most positive value neutral
+
+ AXIS_TOTAL
+ };
+
+ u8 m_switches[SWITCH_TOTAL];
+ s32 m_axes[AXIS_TOTAL];
+};
+
+
+xinput_keyboard_device::xinput_keyboard_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ u32 player,
+ XINPUT_CAPABILITIES const &caps,
+ xinput_api_helper const &helper) :
+ xinput_device_base(std::move(name), std::move(id), module, player, caps, helper)
+{
+ std::fill(std::begin(m_switches), std::end(m_switches), 0);
+ std::fill(std::begin(m_axes), std::end(m_axes), 0);
+}
+
+
+void xinput_keyboard_device::poll(bool relative_reset)
+{
+ // TODO: how many bits are really velocity?
+ // TODO: how are touch strip and overdrive read?
+
+ // poll the device first, and skip if nothing changed
+ if (!read_state())
+ return;
+
+ // translate button bits
+ for (unsigned i = 0; std::size(SWITCH_BITS) > i; ++i)
+ m_switches[SWITCH_A + i] = (buttons() & SWITCH_BITS[i]) ? 0xff : 0x00;
+
+ // translate keys
+ for (unsigned i = 0; 8 > i; ++i)
+ {
+ m_switches[SWITCH_C1 + i] = BIT(trigger_left(), 7 - i) ? 0xff : 0x00;
+ m_switches[SWITCH_C1 + 8 + i] = BIT(trigger_right(), 7 - i) ? 0xff : 0x00;
+ m_switches[SWITCH_C1 + 16 + i] = BIT(thumb_left_x(), 7 - i) ? 0xff : 0x00;
}
+ m_switches[SWITCH_C3] = BIT(thumb_left_x(), 15) ? 0xff : 0x00;
- int init(const osd_options &options) override
+ // translate axes
+ m_axes[AXIS_VELOCITY] = -normalize_absolute_axis(BIT(thumb_left_x(), 8, 7), -127, 127);
+ m_axes[AXIS_PEDAL] = -normalize_absolute_axis(32'767 - thumb_right_y(), -32'767, 32'767);
+}
+
+
+void xinput_keyboard_device::reset()
+{
+ set_reset();
+ std::fill(std::begin(m_switches), std::end(m_switches), 0);
+ std::fill(std::begin(m_axes), std::end(m_axes), 0);
+}
+
+
+void xinput_keyboard_device::configure(input_device &device)
+{
+ // track item IDs for setting up default assignments
+ input_device::assignment_vector assignments;
+ input_item_id switch_ids[SWITCH_TOTAL];
+ std::fill(std::begin(switch_ids), std::end(switch_ids), ITEM_ID_INVALID);
+
+ // add axes
+ device.add_item(
+ "Velocity",
+ std::string_view(),
+ ITEM_ID_SLIDER1,
+ generic_axis_get_state<s32>,
+ &m_axes[AXIS_VELOCITY]);
+ input_item_id const pedal_id = device.add_item(
+ "Pedal",
+ std::string_view(),
+ ITEM_ID_SLIDER2,
+ generic_axis_get_state<s32>,
+ &m_axes[AXIS_PEDAL]);
+ assignments.emplace_back(
+ IPT_PEDAL,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, pedal_id)));
+
+ // add hats
+ for (unsigned i = 0; (SWITCH_DPAD_RIGHT - SWITCH_DPAD_UP) >= i; ++i)
+ {
+ if (has_button(SWITCH_BITS[SWITCH_DPAD_UP + i]))
+ {
+ switch_ids[SWITCH_DPAD_UP + i] = device.add_item(
+ HAT_NAMES_GAMEPAD[i],
+ std::string_view(),
+ input_item_id(ITEM_ID_HAT1UP + i), // matches up/down/left/right order
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_DPAD_UP + i]);
+ }
+ }
+
+ // add buttons
+ input_item_id button_id = ITEM_ID_BUTTON1;
+ unsigned button_count = 0;
+ unsigned numbered_buttons[SWITCH_RSB - SWITCH_A + 1];
+ for (unsigned i = 0; (SWITCH_RSB - SWITCH_A) >= i; ++i)
+ {
+ if (has_button(SWITCH_BITS[i]))
+ {
+ switch_ids[SWITCH_A + i] = device.add_item(
+ BUTTON_NAMES_KEYBOARD[i],
+ std::string_view(),
+ button_id++,
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_A + i]);
+ numbered_buttons[button_count] = SWITCH_A + i;
+
+ // use these for automatically numbered buttons and pedals
+ input_seq const seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, switch_ids[SWITCH_A + i]));
+ assignments.emplace_back(ioport_type(IPT_BUTTON1 + button_count), SEQ_TYPE_STANDARD, seq);
+ if (3 > button_count)
+ assignments.emplace_back(ioport_type(IPT_PEDAL + button_count), SEQ_TYPE_INCREMENT, seq);
+ ++button_count;
+ }
+ }
+
+ // add keys
+ char const *const key_formats[]{
+ "C %d", "C# %d", "D %d", "D# %d", "E %d", "F %d", "F# %d", "G %d", "G# %d", "A %d", "A# %d", "B %d" };
+ std::pair<ioport_type, ioport_type> const key_ids[]{
+ { IPT_MAHJONG_A, IPT_HANAFUDA_A }, // C
+ { IPT_MAHJONG_SCORE, IPT_INVALID }, // C#
+ { IPT_MAHJONG_B, IPT_HANAFUDA_B }, // D
+ { IPT_MAHJONG_DOUBLE_UP, IPT_INVALID }, // D#
+ { IPT_MAHJONG_C, IPT_HANAFUDA_C }, // E
+ { IPT_MAHJONG_D, IPT_HANAFUDA_D }, // F
+ { IPT_MAHJONG_BIG, IPT_INVALID }, // F#
+ { IPT_MAHJONG_E, IPT_HANAFUDA_E }, // G
+ { IPT_MAHJONG_SMALL, IPT_INVALID }, // G#
+ { IPT_MAHJONG_F, IPT_HANAFUDA_F }, // A
+ { IPT_MAHJONG_LAST_CHANCE, IPT_INVALID }, // A#
+ { IPT_MAHJONG_G, IPT_HANAFUDA_G }, // B
+ { IPT_MAHJONG_H, IPT_HANAFUDA_H }, // C
+ { IPT_MAHJONG_KAN, IPT_INVALID }, // C#
+ { IPT_MAHJONG_I, IPT_INVALID }, // D
+ { IPT_MAHJONG_PON, IPT_INVALID }, // D#
+ { IPT_MAHJONG_J, IPT_INVALID }, // E
+ { IPT_MAHJONG_K, IPT_INVALID }, // F
+ { IPT_MAHJONG_CHI, IPT_INVALID }, // F#
+ { IPT_MAHJONG_L, IPT_INVALID }, // G
+ { IPT_MAHJONG_REACH, IPT_INVALID }, // G#
+ { IPT_MAHJONG_M, IPT_HANAFUDA_YES }, // A
+ { IPT_MAHJONG_RON, IPT_INVALID }, // A#
+ { IPT_MAHJONG_N, IPT_HANAFUDA_NO }, // B
+ { IPT_MAHJONG_O, IPT_INVALID } }; // C
+ for (unsigned i = 0; (SWITCH_C3 - SWITCH_C1) >= i; ++i)
+ {
+ switch_ids[SWITCH_C1 + i] = device.add_item(
+ util::string_format(key_formats[i % 12], (i / 12) + 1),
+ std::string_view(),
+ (ITEM_ID_BUTTON32 >= button_id) ? button_id++ : ITEM_ID_OTHER_SWITCH,
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_C1 + i]);
+
+ // add mahjong/hanafuda control assignments
+ input_seq const seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, switch_ids[SWITCH_C1 + i]));
+ if (IPT_INVALID != key_ids[i].first)
+ assignments.emplace_back(key_ids[i].first, SEQ_TYPE_STANDARD, seq);
+ if (IPT_INVALID != key_ids[i].second)
+ assignments.emplace_back(key_ids[i].second, SEQ_TYPE_STANDARD, seq);
+ }
+
+ // add start/back
+ if (has_button(XINPUT_GAMEPAD_START))
{
+ switch_ids[SWITCH_START] = device.add_item(
+ "Start",
+ std::string_view(),
+ ITEM_ID_START,
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_START]);
+ add_button_assignment(assignments, IPT_START, { switch_ids[SWITCH_START] });
+ }
+ if (has_button(XINPUT_GAMEPAD_BACK))
+ {
+ switch_ids[SWITCH_BACK] = device.add_item(
+ "Back",
+ std::string_view(),
+ ITEM_ID_SELECT,
+ generic_button_get_state<u8>,
+ &m_switches[SWITCH_BACK]);
+ add_button_assignment(assignments, IPT_SELECT, { switch_ids[SWITCH_BACK] });
+ }
+
+ // use the D-pad for directional controls
+ add_directional_assignments(
+ assignments,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ switch_ids[SWITCH_DPAD_LEFT],
+ switch_ids[SWITCH_DPAD_RIGHT],
+ switch_ids[SWITCH_DPAD_UP],
+ switch_ids[SWITCH_DPAD_DOWN]);
+
+ // use the D-pad and A/B/X/Y diamond for twin sticks
+ add_twin_stick_assignments(
+ assignments,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ switch_ids[SWITCH_DPAD_LEFT],
+ switch_ids[SWITCH_DPAD_RIGHT],
+ switch_ids[SWITCH_DPAD_UP],
+ switch_ids[SWITCH_DPAD_DOWN],
+ switch_ids[SWITCH_X],
+ switch_ids[SWITCH_B],
+ switch_ids[SWITCH_Y],
+ switch_ids[SWITCH_A]);
+
+ // assign UI select/back/clear/help
+ assign_ui_actions(
+ assignments,
+ SWITCH_B,
+ SWITCH_X,
+ SWITCH_Y,
+ SWITCH_START,
+ SWITCH_BACK,
+ switch_ids,
+ numbered_buttons,
+ button_count);
+
+ // set default assignments
+ device.set_default_assignments(std::move(assignments));
+}
+
+
+
+//============================================================
+// XInput joystick module
+//============================================================
+
+class xinput_joystick_module : public input_module_impl<device_info, osd_common_t>
+{
+public:
+ xinput_joystick_module() : input_module_impl<device_info, osd_common_t>(OSD_JOYSTICKINPUT_PROVIDER, "xinput")
+ {
+ }
+
+ virtual int init(osd_interface &osd, const osd_options &options) override
+ {
+ int status;
+
// Call the base
- int status = wininput_module::init(options);
+ status = input_module_impl<device_info, osd_common_t>::init(osd, options);
if (status != 0)
return status;
// Create and initialize our helper
- m_xinput_helper = std::make_shared<xinput_api_helper>();
+ m_xinput_helper = std::make_unique<xinput_api_helper>();
status = m_xinput_helper->initialize();
if (status != 0)
{
@@ -228,32 +3002,140 @@ public:
return 0;
}
-protected:
virtual void input_init(running_machine &machine) override
{
- xinput_joystick_device *devinfo;
+ input_module_impl<device_info, osd_common_t>::input_init(machine);
// Loop through each gamepad to determine if they are connected
for (UINT i = 0; i < XUSER_MAX_COUNT; i++)
{
- XINPUT_STATE state = {0};
+ // allocate and link in a new device
+ auto devinfo = m_xinput_helper->create_xinput_device(i, *this);
+ if (devinfo)
+ add_device(DEVICE_CLASS_JOYSTICK, std::move(devinfo));
+ }
+ }
- if (m_xinput_helper->xinput_get_state(i, &state) == ERROR_SUCCESS)
- {
- // allocate and link in a new device
- devinfo = m_xinput_helper->create_xinput_device(machine, i, *this);
- if (devinfo == nullptr)
- continue;
+ virtual void exit() override
+ {
+ input_module_impl<device_info, osd_common_t>::exit();
- // Configure each gamepad to add buttons and Axes, etc.
- devinfo->configure();
- }
- }
+ m_xinput_helper.reset();
}
+
+private:
+ std::unique_ptr<xinput_api_helper> m_xinput_helper;
};
-#else
-MODULE_NOT_SUPPORTED(xinput_joystick_module, OSD_JOYSTICKINPUT_PROVIDER, "xinput")
-#endif
+} // anonymous namespace
+
+
+
+int xinput_api_helper::initialize()
+{
+ m_xinput_dll = dynamic_module::open(XINPUT_LIBRARIES);
+
+ XInputGetState = m_xinput_dll->bind<xinput_get_state_fn>("XInputGetState");
+ XInputGetCapabilities = m_xinput_dll->bind<xinput_get_caps_fn>("XInputGetCapabilities");
+
+ if (!XInputGetState || !XInputGetCapabilities)
+ {
+ osd_printf_error("XInput: Could not find API functions.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+//============================================================
+// create_xinput_device
+//============================================================
+
+std::unique_ptr<device_info> xinput_api_helper::create_xinput_device(
+ UINT index,
+ input_module_base &module)
+{
+ // If we can't get the capabilities skip this device
+ XINPUT_STATE state{ 0 };
+ if (xinput_get_state(index, &state) != ERROR_SUCCESS)
+ return nullptr;
+ XINPUT_CAPABILITIES caps{ 0 };
+ if (FAILED(xinput_get_capabilities(index, 0, &caps)))
+ return nullptr;
+
+ char device_name[16];
+ snprintf(device_name, sizeof(device_name), "XInput Player %u", index + 1);
+
+ // allocate specialised device objects
+ switch (caps.Type)
+ {
+ case XINPUT_DEVTYPE_GAMEPAD:
+ switch (caps.SubType)
+ {
+ case 0x04: // XINPUT_DEVSUBTYPE_FLIGHT_STICK: work around MinGW header issues
+ return std::make_unique<xinput_flight_stick_device>(
+ device_name,
+ device_name,
+ module,
+ index,
+ caps,
+ *this);
+ case XINPUT_DEVSUBTYPE_GUITAR:
+ case XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE:
+ case XINPUT_DEVSUBTYPE_GUITAR_BASS:
+ return std::make_unique<xinput_guitar_device>(
+ device_name,
+ device_name,
+ module,
+ index,
+ caps,
+ *this);
+ case XINPUT_DEVSUBTYPE_DRUM_KIT:
+ return std::make_unique<xinput_drumkit_device>(
+ device_name,
+ device_name,
+ module,
+ index,
+ caps,
+ *this);
+ case 0x0f:
+ return std::make_unique<xinput_keyboard_device>(
+ device_name,
+ device_name,
+ module,
+ index,
+ caps,
+ *this);
+ case 0x17:
+ return std::make_unique<xinput_turntable_device>(
+ device_name,
+ device_name,
+ module,
+ index,
+ caps,
+ *this);
+ }
+ }
+
+ // create default general-purpose device
+ return std::make_unique<xinput_joystick_device>(
+ device_name,
+ device_name,
+ module,
+ index,
+ caps,
+ *this);
+}
+
+} // namespace osd
+
+#else // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
+
+#include "input_module.h"
+
+namespace osd { namespace { MODULE_NOT_SUPPORTED(xinput_joystick_module, OSD_JOYSTICKINPUT_PROVIDER, "xinput") } }
+
+#endif // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
-MODULE_DEFINITION(JOYSTICKINPUT_XINPUT, xinput_joystick_module)
+MODULE_DEFINITION(JOYSTICKINPUT_XINPUT, osd::xinput_joystick_module)
diff --git a/src/osd/modules/input/input_xinput.h b/src/osd/modules/input/input_xinput.h
index 9772e941bb7..fa36b7a2622 100644
--- a/src/osd/modules/input/input_xinput.h
+++ b/src/osd/modules/input/input_xinput.h
@@ -1,111 +1,30 @@
-#ifndef INPUT_XINPUT_H_
-#define INPUT_XINPUT_H_
+// license:BSD-3-Clause
+// copyright-holders:Brad Hughes, Vas Crabb
+#ifndef MAME_OSD_INPUT_INPUT_XINPUT_H
+#define MAME_OSD_INPUT_INPUT_XINPUT_H
-#include <mutex>
+#pragma once
-#include "modules/lib/osdlib.h"
-
-#define XINPUT_MAX_POV 4
-#define XINPUT_MAX_BUTTONS 10
-#define XINPUT_MAX_AXIS 4
-
-#define XINPUT_AXIS_MINVALUE -32767
-#define XINPUT_AXIS_MAXVALUE 32767
-
-class xinput_joystick_device;
-// default axis names
-static const char *const xinput_axis_name[] =
-{
- "LSX",
- "LSY",
- "RSX",
- "RSY"
-};
-
-static const input_item_id xinput_axis_ids[] =
-{
- ITEM_ID_XAXIS,
- ITEM_ID_YAXIS,
- ITEM_ID_RXAXIS,
- ITEM_ID_RYAXIS
-};
-
-static const USHORT xinput_pov_dir[] = {
- XINPUT_GAMEPAD_DPAD_UP,
- XINPUT_GAMEPAD_DPAD_DOWN,
- XINPUT_GAMEPAD_DPAD_LEFT,
- XINPUT_GAMEPAD_DPAD_RIGHT
-};
-
-static const char *const xinput_pov_names[] = {
- "DPAD Up",
- "DPAD Down",
- "DPAD Left",
- "DPAD Right"
-};
+#include "input_common.h"
-static const USHORT xinput_buttons[] = {
- XINPUT_GAMEPAD_A,
- XINPUT_GAMEPAD_B,
- XINPUT_GAMEPAD_X,
- XINPUT_GAMEPAD_Y,
- XINPUT_GAMEPAD_LEFT_SHOULDER,
- XINPUT_GAMEPAD_RIGHT_SHOULDER,
- XINPUT_GAMEPAD_START,
- XINPUT_GAMEPAD_BACK,
- XINPUT_GAMEPAD_LEFT_THUMB,
- XINPUT_GAMEPAD_RIGHT_THUMB,
-};
+#include "modules/lib/osdlib.h"
-static const char *const xinput_button_names[] = {
- "A",
- "B",
- "X",
- "Y",
- "LB",
- "RB",
- "Start",
- "Back",
- "LS",
- "RS"
-};
+#include <memory>
-struct gamepad_state
-{
- BYTE buttons[XINPUT_MAX_BUTTONS];
- BYTE povs[XINPUT_MAX_POV];
- LONG left_trigger;
- LONG right_trigger;
- LONG left_thumb_x;
- LONG left_thumb_y;
- LONG right_thumb_x;
- LONG right_thumb_y;
-};
+#include <windows.h>
+#include <xinput.h>
-// state information for a gamepad; state must be first element
-struct xinput_api_state
-{
- uint32_t player_index;
- XINPUT_STATE xstate;
- XINPUT_CAPABILITIES caps;
-};
-// Typedefs for dynamically loaded functions
-typedef DWORD (WINAPI *xinput_get_state_fn)(DWORD, XINPUT_STATE *);
-typedef DWORD (WINAPI *xinput_get_caps_fn)(DWORD, DWORD, XINPUT_CAPABILITIES *);
+namespace osd {
-class xinput_api_helper : public std::enable_shared_from_this<xinput_api_helper>
+class xinput_api_helper
{
public:
- xinput_api_helper()
- : m_xinput_dll(nullptr),
- XInputGetState(nullptr),
- XInputGetCapabilities(nullptr)
- {
- }
+ xinput_api_helper() { }
int initialize();
- xinput_joystick_device * create_xinput_device(running_machine &machine, UINT index, wininput_module &module);
+
+ std::unique_ptr<device_info> create_xinput_device(UINT index, input_module_base &module);
DWORD xinput_get_state(DWORD dwUserindex, XINPUT_STATE *pState) const
{
@@ -118,28 +37,15 @@ public:
}
private:
- osd::dynamic_module::ptr m_xinput_dll;
- xinput_get_state_fn XInputGetState;
- xinput_get_caps_fn XInputGetCapabilities;
-};
-
-class xinput_joystick_device : public device_info
-{
-public:
- gamepad_state gamepad;
- xinput_api_state xinput_state;
-
-private:
- std::shared_ptr<xinput_api_helper> m_xinput_helper;
- std::mutex m_device_lock;
- bool m_configured;
-
-public:
- xinput_joystick_device(running_machine &machine, const char *name, const char *id, input_module &module, std::shared_ptr<xinput_api_helper> helper);
+ // Typedefs for dynamically loaded functions
+ typedef DWORD (WINAPI *xinput_get_state_fn)(DWORD, XINPUT_STATE *);
+ typedef DWORD (WINAPI *xinput_get_caps_fn)(DWORD, DWORD, XINPUT_CAPABILITIES *);
- void poll() override;
- void reset() override;
- void configure();
+ dynamic_module::ptr m_xinput_dll = nullptr;
+ xinput_get_state_fn XInputGetState = nullptr;
+ xinput_get_caps_fn XInputGetCapabilities = nullptr;
};
-#endif
+} // namespace osd
+
+#endif // MAME_OSD_INPUT_INPUT_XINPUT_H
diff --git a/src/osd/modules/lib/osdlib.h b/src/osd/modules/lib/osdlib.h
index 0095244d6fe..967cb0d61ae 100644
--- a/src/osd/modules/lib/osdlib.h
+++ b/src/osd/modules/lib/osdlib.h
@@ -12,15 +12,21 @@
// - osd_ticks
// - osd_sleep
//============================================================
+#ifndef MAME_OSD_LIB_OSDLIB_H
+#define MAME_OSD_LIB_OSDLIB_H
-#ifndef __OSDLIB__
-#define __OSDLIB__
+#pragma once
+#include <cstdint>
+#include <initializer_list>
#include <string>
+#include <string_view>
+#include <system_error>
#include <type_traits>
#include <vector>
#include <memory>
+
/*-----------------------------------------------------------------------------
osd_process_kill: kill the current process
@@ -33,7 +39,7 @@
None.
-----------------------------------------------------------------------------*/
-void osd_process_kill(void);
+void osd_process_kill();
/*-----------------------------------------------------------------------------
@@ -53,10 +59,108 @@ void osd_process_kill(void);
int osd_setenv(const char *name, const char *value, int overwrite);
-/*-----------------------------------------------------------------------------
- osd_get_clipboard_text: retrieves text from the clipboard
------------------------------------------------------------------------------*/
-std::string osd_get_clipboard_text(void);
+/// \brief Get clipboard text
+///
+/// Gets current clipboard content as UTF-8 text. Returns an empty
+/// string if the clipboard contents cannot be converted to plain text.
+/// \return Clipboard contents or an empty string.
+std::string osd_get_clipboard_text() noexcept;
+
+
+/// \brief Set clipboard text
+///
+/// Sets the desktop environment's clipboard contents to the supplied
+/// UTF-8 text. The contents of the clipboard may be changed on error.
+/// \param [in] text The text to copy to the clipboard.
+/// \return An error condition if the operation failed or is
+/// unsupported.
+std::error_condition osd_set_clipboard_text(std::string_view text) noexcept;
+
+
+namespace osd {
+
+bool invalidate_instruction_cache(void const *start, std::size_t size) noexcept;
+
+
+class virtual_memory_allocation
+{
+public:
+ enum : unsigned
+ {
+ NONE = 0x00,
+ READ = 0x01,
+ WRITE = 0x02,
+ EXECUTE = 0x04,
+ READ_WRITE = READ | WRITE,
+ READ_EXECUTE = READ | EXECUTE,
+ READ_WRITE_EXECUTE = READ | WRITE | EXECUTE
+ };
+
+ virtual_memory_allocation(virtual_memory_allocation const &) = delete;
+ virtual_memory_allocation &operator=(virtual_memory_allocation const &) = delete;
+
+ virtual_memory_allocation() noexcept { }
+ virtual_memory_allocation(std::initializer_list<std::size_t> blocks, unsigned intent) noexcept
+ {
+ m_memory = do_alloc(blocks, intent, m_size, m_page_size);
+ }
+ virtual_memory_allocation(virtual_memory_allocation &&that) noexcept : m_memory(that.m_memory), m_size(that.m_size), m_page_size(that.m_page_size)
+ {
+ that.m_memory = nullptr;
+ that.m_size = that.m_page_size = 0U;
+ }
+ ~virtual_memory_allocation()
+ {
+ if (m_memory)
+ do_free(m_memory, m_size);
+ }
+
+ explicit operator bool() const noexcept { return bool(m_memory); }
+ void *get() noexcept { return m_memory; }
+ std::size_t size() const noexcept { return m_size; }
+ std::size_t page_size() const noexcept { return m_page_size; }
+
+ bool set_access(std::size_t start, std::size_t size, unsigned access) noexcept
+ {
+ if ((start % m_page_size) || (size % m_page_size) || (start > m_size) || ((m_size - start) < size))
+ return false;
+ else
+ return do_set_access(reinterpret_cast<std::uint8_t *>(m_memory) + start, size, access);
+ }
+
+ virtual_memory_allocation &operator=(std::nullptr_t) noexcept
+ {
+ if (m_memory)
+ do_free(m_memory, m_size);
+ m_memory = nullptr;
+ m_size = m_page_size = 0U;
+ return *this;
+ }
+
+ virtual_memory_allocation &operator=(virtual_memory_allocation &&that) noexcept
+ {
+ if (&that != this)
+ {
+ if (m_memory)
+ do_free(m_memory, m_size);
+ m_memory = that.m_memory;
+ m_size = that.m_size;
+ m_page_size = that.m_page_size;
+ that.m_memory = nullptr;
+ that.m_size = that.m_page_size = 0U;
+ }
+ return *this;
+ }
+
+private:
+ static void *do_alloc(std::initializer_list<std::size_t> blocks, unsigned intent, std::size_t &size, std::size_t &page_size) noexcept;
+ static void do_free(void *start, std::size_t size) noexcept;
+ static bool do_set_access(void *start, std::size_t size, unsigned access) noexcept;
+
+ void *m_memory = nullptr;
+ std::size_t m_size = 0U, m_page_size = 0U;
+};
+
/*-----------------------------------------------------------------------------
dynamic_module: load functions from optional shared libraries
@@ -69,7 +173,6 @@ std::string osd_get_clipboard_text(void);
revisions of a same library)
-----------------------------------------------------------------------------*/
-namespace osd {
class dynamic_module
{
public:
@@ -77,10 +180,10 @@ public:
static ptr open(std::vector<std::string> &&libraries);
- virtual ~dynamic_module() { };
+ virtual ~dynamic_module() { }
template <typename T>
- typename std::enable_if<std::is_pointer<T>::value, T>::type bind(char const *symbol)
+ typename std::enable_if_t<std::is_pointer_v<T>, T> bind(char const *symbol)
{
return reinterpret_cast<T>(get_symbol_address(symbol));
}
@@ -102,20 +205,9 @@ protected:
// Calling then looks like: DYNAMIC_CALL(CreateDXGIFactory1, p1, p2, etc)
//=========================================================================================================
-#if !defined(OSD_UWP)
-
#define OSD_DYNAMIC_API(apiname, ...) osd::dynamic_module::ptr m_##apiname##module = osd::dynamic_module::open( { __VA_ARGS__ } )
#define OSD_DYNAMIC_API_FN(apiname, ret, conv, fname, ...) ret(conv *m_##fname##_pfn)( __VA_ARGS__ ) = m_##apiname##module->bind<ret(conv *)( __VA_ARGS__ )>(#fname)
#define OSD_DYNAMIC_CALL(fname, ...) (*m_##fname##_pfn) ( __VA_ARGS__ )
#define OSD_DYNAMIC_API_TEST(fname) (m_##fname##_pfn != nullptr)
-#else
-
-#define OSD_DYNAMIC_API(apiname, ...)
-#define OSD_DYNAMIC_API_FN(apiname, ret, conv, fname, ...)
-#define OSD_DYNAMIC_CALL(fname, ...) fname( __VA_ARGS__ )
-#define OSD_DYNAMIC_API_TEST(fname) (true)
-
-#endif
-
-#endif /* __OSDLIB__ */
+#endif // MAME_OSD_LIB_OSDLIB_H
diff --git a/src/osd/modules/lib/osdlib_macosx.cpp b/src/osd/modules/lib/osdlib_macosx.cpp
index 372293ec1a3..54836f9ec69 100644
--- a/src/osd/modules/lib/osdlib_macosx.cpp
+++ b/src/osd/modules/lib/osdlib_macosx.cpp
@@ -8,26 +8,26 @@
//
//============================================================
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/sysctl.h>
-#include <sys/types.h>
-#include <signal.h>
-#include <dlfcn.h>
+// MAME headers
+#include "osdcore.h"
+#include "osdlib.h"
+#include <csignal>
#include <cstdio>
+#include <cstdlib>
#include <iomanip>
#include <memory>
+#include <dlfcn.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <Carbon/Carbon.h>
-// MAME headers
-#include "osdcore.h"
-#include "osdlib.h"
//============================================================
// osd_getenv
@@ -56,36 +56,6 @@ void osd_process_kill()
kill(getpid(), SIGKILL);
}
-//============================================================
-// osd_alloc_executable
-//
-// allocates "size" bytes of executable memory. this must take
-// things like NX support into account.
-//============================================================
-
-void *osd_alloc_executable(size_t size)
-{
-#if defined(SDLMAME_BSD) || defined(SDLMAME_MACOSX)
- return (void *)mmap(0, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
-#elif defined(SDLMAME_UNIX)
- return (void *)mmap(0, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, 0, 0);
-#endif
-}
-
-//============================================================
-// osd_free_executable
-//
-// frees memory allocated with osd_alloc_executable
-//============================================================
-
-void osd_free_executable(void *ptr, size_t size)
-{
-#ifdef SDLMAME_SOLARIS
- munmap((char *)ptr, size);
-#else
- munmap(ptr, size);
-#endif
-}
//============================================================
// osd_break_into_debugger
@@ -98,7 +68,7 @@ void osd_break_into_debugger(const char *message)
struct kinfo_proc info;
info.kp_proc.p_flag = 0;
std::size_t infosz = sizeof(info);
- sysctl(mib, ARRAY_LENGTH(mib), &info, &infosz, nullptr, 0);
+ sysctl(mib, std::size(mib), &info, &infosz, nullptr, 0);
if (info.kp_proc.p_flag & P_TRACED)
{
printf("MAME exception: %s\n", message);
@@ -113,10 +83,26 @@ void osd_break_into_debugger(const char *message)
//============================================================
+// osd_get_cache_line_size
+//============================================================
+
+std::pair<std::error_condition, unsigned> osd_get_cache_line_size() noexcept
+{
+ size_t result = 0;
+ size_t resultsize = sizeof(result);
+ int const err = sysctlbyname("hw.cachelinesize", &result, &resultsize, 0, 0);
+ if (!err)
+ return std::make_pair(std::error_condition(), unsigned(result));
+ else
+ return std::make_pair(std::error_condition(err, std::generic_category()), 0U);
+}
+
+
+//============================================================
// osd_get_clipboard_text
//============================================================
-std::string osd_get_clipboard_text(void)
+std::string osd_get_clipboard_text() noexcept
{
std::string result;
bool has_result = false;
@@ -152,31 +138,48 @@ std::string osd_get_clipboard_text(void)
CFStringEncoding encoding;
if (UTTypeConformsTo(flavor_type, kUTTypeUTF16PlainText))
encoding = kCFStringEncodingUTF16;
- else if (UTTypeConformsTo (flavor_type, kUTTypeUTF8PlainText))
+ else if (UTTypeConformsTo(flavor_type, kUTTypeUTF8PlainText))
encoding = kCFStringEncodingUTF8;
- else if (UTTypeConformsTo (flavor_type, kUTTypePlainText))
+ else if (UTTypeConformsTo(flavor_type, kUTTypePlainText))
encoding = kCFStringEncodingMacRoman;
else
continue;
CFDataRef flavor_data;
err = PasteboardCopyItemFlavorData(pasteboard_ref, item_id, flavor_type, &flavor_data);
+ if (err)
+ continue;
- if (!err)
+ CFDataRef utf8_data;
+ if (kCFStringEncodingUTF8 == encoding)
+ {
+ utf8_data = flavor_data;
+ }
+ else
{
CFStringRef string_ref = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, flavor_data, encoding);
- CFDataRef data_ref = CFStringCreateExternalRepresentation (kCFAllocatorDefault, string_ref, kCFStringEncodingUTF8, '?');
- CFRelease(string_ref);
CFRelease(flavor_data);
+ if (!string_ref)
+ continue;
- CFIndex const length = CFDataGetLength(data_ref);
- CFRange const range = CFRangeMake(0, length);
-
- result.resize(length);
- CFDataGetBytes(data_ref, range, reinterpret_cast<unsigned char *>(&result[0]));
- has_result = true;
+ utf8_data = CFStringCreateExternalRepresentation(kCFAllocatorDefault, string_ref, kCFStringEncodingUTF8, '?');
+ CFRelease(string_ref);
+ }
- CFRelease(data_ref);
+ if (utf8_data)
+ {
+ CFIndex const length = CFDataGetLength(utf8_data);
+ CFRange const range = CFRangeMake(0, length);
+ try
+ {
+ result.resize(length);
+ CFDataGetBytes(utf8_data, range, reinterpret_cast<UInt8 *>(result.data()));
+ has_result = true;
+ }
+ catch (std::bad_alloc const &)
+ {
+ }
+ CFRelease(utf8_data);
}
}
@@ -188,34 +191,72 @@ std::string osd_get_clipboard_text(void)
return result;
}
+
//============================================================
-// osd_getpid
+// osd_set_clipboard_text
//============================================================
-int osd_getpid(void)
+std::error_condition osd_set_clipboard_text(std::string_view text) noexcept
{
- return getpid();
+ // FIXME: better conversion of OSStatus to std::error_condition
+ OSStatus err;
+
+ CFDataRef const data = CFDataCreate(kCFAllocatorDefault, reinterpret_cast<UInt8 const *>(text.data()), text.length());
+ if (!data)
+ return std::errc::not_enough_memory;
+
+ PasteboardRef pasteboard_ref;
+ err = PasteboardCreate(kPasteboardClipboard, &pasteboard_ref);
+ if (err)
+ {
+ CFRelease(data);
+ return std::errc::io_error;
+ }
+
+ err = PasteboardClear(pasteboard_ref);
+ if (err)
+ {
+ CFRelease(data);
+ CFRelease(pasteboard_ref);
+ return std::errc::io_error;
+ }
+
+ err = PasteboardPutItemFlavor(pasteboard_ref, PasteboardItemID(1), kUTTypeUTF8PlainText, data, kPasteboardFlavorNoFlags);
+ CFRelease(data);
+ CFRelease(pasteboard_ref);
+ if (err)
+ return std::errc::io_error;
+
+ return std::error_condition();
}
+
//============================================================
-// dynamic_module_posix_impl
+// osd_getpid
//============================================================
+int osd_getpid() noexcept
+{
+ return getpid();
+}
+
+
namespace osd {
+
+namespace {
+
class dynamic_module_posix_impl : public dynamic_module
{
public:
- dynamic_module_posix_impl(std::vector<std::string> &libraries)
- : m_module(nullptr)
+ dynamic_module_posix_impl(std::vector<std::string> &&libraries) : m_libraries(std::move(libraries))
{
- m_libraries = libraries;
}
virtual ~dynamic_module_posix_impl() override
{
- if (m_module != nullptr)
+ if (m_module)
dlclose(m_module);
- };
+ }
protected:
virtual generic_fptr_t get_symbol_address(char const *symbol) override
@@ -225,19 +266,17 @@ protected:
* one of them, all additional symbols will be loaded from the same library
*/
if (m_module)
- {
return reinterpret_cast<generic_fptr_t>(dlsym(m_module, symbol));
- }
for (auto const &library : m_libraries)
{
- void *module = dlopen(library.c_str(), RTLD_LAZY);
+ void *const module = dlopen(library.c_str(), RTLD_LAZY);
if (module != nullptr)
{
- generic_fptr_t function = reinterpret_cast<generic_fptr_t>(dlsym(module, symbol));
+ generic_fptr_t const function = reinterpret_cast<generic_fptr_t>(dlsym(module, symbol));
- if (function != nullptr)
+ if (function)
{
m_module = module;
return function;
@@ -254,12 +293,61 @@ protected:
private:
std::vector<std::string> m_libraries;
- void * m_module;
+ void * m_module = nullptr;
};
+} // anonymous namespace
+
+
+bool invalidate_instruction_cache(void const *start, std::size_t size) noexcept
+{
+ char const *const begin(reinterpret_cast<char const *>(start));
+ char const *const end(begin + size);
+ __builtin___clear_cache(const_cast<char *>(begin), const_cast<char *>(end));
+ return true;
+}
+
+
+void *virtual_memory_allocation::do_alloc(std::initializer_list<std::size_t> blocks, unsigned intent, std::size_t &size, std::size_t &page_size) noexcept
+{
+ long const p(sysconf(_SC_PAGE_SIZE));
+ if (0 >= p)
+ return nullptr;
+ std::size_t s(0);
+ for (std::size_t b : blocks)
+ s += (b + p - 1) / p;
+ s *= p;
+ if (!s)
+ return nullptr;
+ void *const result(mmap(nullptr, s, PROT_NONE, MAP_ANON | MAP_SHARED, -1, 0));
+ if (result == (void *)-1)
+ return nullptr;
+ size = s;
+ page_size = p;
+ return result;
+}
+
+void virtual_memory_allocation::do_free(void *start, std::size_t size) noexcept
+{
+ munmap(start, size);
+}
+
+bool virtual_memory_allocation::do_set_access(void *start, std::size_t size, unsigned access) noexcept
+{
+ int prot((NONE == access) ? PROT_NONE : 0);
+ if (access & READ)
+ prot |= PROT_READ;
+ if (access & WRITE)
+ prot |= PROT_WRITE;
+ if (access & EXECUTE)
+ prot |= PROT_EXEC;
+ return mprotect(start, size, prot) == 0;
+}
+
+
dynamic_module::ptr dynamic_module::open(std::vector<std::string> &&names)
{
- return std::make_unique<dynamic_module_posix_impl>(names);
+ return std::make_unique<dynamic_module_posix_impl>(std::move(names));
}
} // namespace osd
diff --git a/src/osd/modules/lib/osdlib_unix.cpp b/src/osd/modules/lib/osdlib_unix.cpp
index 178fb4594cb..1cfa9b1f183 100644
--- a/src/osd/modules/lib/osdlib_unix.cpp
+++ b/src/osd/modules/lib/osdlib_unix.cpp
@@ -8,23 +8,25 @@
//
//============================================================
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <signal.h>
-#include <dlfcn.h>
+// MAME headers
+#include "osdcore.h"
+#include "osdlib.h"
+#include <SDL2/SDL.h>
+
+#include <csignal>
#include <cstdio>
+#include <cstdlib>
+#include <cstring>
#include <iomanip>
#include <memory>
+#include <string_view>
+#include <dlfcn.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <unistd.h>
-// MAME headers
-#include "osdcore.h"
-#include "osdlib.h"
-
-#include <SDL2/SDL.h>
//============================================================
// osd_getenv
@@ -53,105 +55,175 @@ void osd_process_kill()
kill(getpid(), SIGKILL);
}
+
//============================================================
-// osd_alloc_executable
-//
-// allocates "size" bytes of executable memory. this must take
-// things like NX support into account.
+// osd_break_into_debugger
//============================================================
-void *osd_alloc_executable(size_t size)
+void osd_break_into_debugger(const char *message)
{
-#if defined(SDLMAME_BSD) || defined(SDLMAME_MACOSX) || defined(SDLMAME_EMSCRIPTEN)
- return (void *)mmap(0, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
+#if defined(__linux__)
+ bool do_break = false;
+ FILE *const f = std::fopen("/proc/self/status", "r");
+ if (f)
+ {
+ using namespace std::literals;
+
+ std::string_view const tag = "TracerPid:\t"sv;
+ char buf[128];
+ bool ignore = false;
+ while (std::fgets(buf, std::size(buf), f))
+ {
+ // ignore excessively long lines
+ auto const len = strnlen(buf, std::size(buf));
+ bool const noeol = !len || ('\n' != buf[len - 1]);
+ if (ignore || noeol)
+ {
+ ignore = noeol;
+ continue;
+ }
+
+ if (!std::strncmp(buf, tag.data(), tag.length()))
+ {
+ long tpid;
+ if ((std::sscanf(buf + tag.length(), "%ld", &tpid) == 1) && (0 != tpid))
+ do_break = true;
+ break;
+ }
+ }
+ std::fclose(f);
+ }
+#elif defined(MAME_DEBUG)
+ bool const do_break = true;
#else
- return (void *)mmap(0, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, 0, 0);
+ bool const do_break = false;
#endif
+ if (do_break)
+ {
+ printf("MAME exception: %s\n", message);
+ printf("Attempting to fall into debugger\n");
+ kill(getpid(), SIGTRAP);
+ }
+ else
+ {
+ printf("Ignoring MAME exception: %s\n", message);
+ }
}
+
//============================================================
-// osd_free_executable
-//
-// frees memory allocated with osd_alloc_executable
+// osd_get_cache_line_size
//============================================================
-void osd_free_executable(void *ptr, size_t size)
+std::pair<std::error_condition, unsigned> osd_get_cache_line_size() noexcept
{
-#ifdef SDLMAME_SOLARIS
- munmap((char *)ptr, size);
-#else
- munmap(ptr, size);
+#if defined(__linux__)
+ FILE *const f = std::fopen("/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size", "r");
+ if (!f)
+ return std::make_pair(std::error_condition(errno, std::generic_category()), 0U);
+
+ unsigned result = 0;
+ auto const cnt = std::fscanf(f, "%u", &result);
+ std::fclose(f);
+ if (1 == cnt)
+ return std::make_pair(std::error_condition(), result);
+ else
+ return std::make_pair(std::errc::io_error, 0U);
+#else // defined(__linux__)
+ return std::make_pair(std::errc::not_supported, 0U);
#endif
}
-//============================================================
-// osd_break_into_debugger
-//============================================================
-void osd_break_into_debugger(const char *message)
+#ifdef SDLMAME_ANDROID
+std::string osd_get_clipboard_text() noexcept
{
- #ifdef MAME_DEBUG
- printf("MAME exception: %s\n", message);
- printf("Attempting to fall into debugger\n");
- kill(getpid(), SIGTRAP);
- #else
- printf("Ignoring MAME exception: %s\n", message);
- #endif
+ return std::string();
}
-#ifdef SDLMAME_ANDROID
-std::string osd_get_clipboard_text(void)
+std::error_condition osd_set_clipboard_text(std::string_view text) noexcept
{
- return std::string();
+ return std::errc::io_error; // TODO: better error code?
}
#else
//============================================================
// osd_get_clipboard_text
//============================================================
-std::string osd_get_clipboard_text(void)
+std::string osd_get_clipboard_text() noexcept
{
+ // TODO: better error handling
std::string result;
if (SDL_HasClipboardText())
{
- char *temp = SDL_GetClipboardText();
- result.assign(temp);
- SDL_free(temp);
+ char *const temp = SDL_GetClipboardText();
+ if (temp)
+ {
+ try
+ {
+ result.assign(temp);
+ }
+ catch (std::bad_alloc const &)
+ {
+ }
+ SDL_free(temp);
+ }
}
return result;
}
+
+//============================================================
+// osd_set_clipboard_text
+//============================================================
+
+std::error_condition osd_set_clipboard_text(std::string_view text) noexcept
+{
+ try
+ {
+ std::string const clip(text); // need to do this to ensure there's a terminating NUL for SDL
+ if (0 > SDL_SetClipboardText(clip.c_str()))
+ {
+ // SDL_GetError returns a message, can't really convert it to an error condition
+ return std::errc::io_error; // TODO: better error code?
+ }
+
+ return std::error_condition();
+ }
+ catch (std::bad_alloc const &)
+ {
+ return std::errc::not_enough_memory;
+ }
+}
#endif
//============================================================
// osd_getpid
//============================================================
-int osd_getpid(void)
+int osd_getpid() noexcept
{
return getpid();
}
-//============================================================
-// dynamic_module_posix_impl
-//============================================================
namespace osd {
+
+namespace {
+
class dynamic_module_posix_impl : public dynamic_module
{
public:
- dynamic_module_posix_impl(std::vector<std::string> &libraries)
- : m_module(nullptr)
+ dynamic_module_posix_impl(std::vector<std::string> &&libraries) : m_libraries(std::move(libraries))
{
- m_libraries = libraries;
}
virtual ~dynamic_module_posix_impl() override
{
- if (m_module != nullptr)
+ if (m_module)
dlclose(m_module);
- };
+ }
protected:
virtual generic_fptr_t get_symbol_address(char const *symbol) override
@@ -161,19 +233,17 @@ protected:
* one of them, all additional symbols will be loaded from the same library
*/
if (m_module)
- {
return reinterpret_cast<generic_fptr_t>(dlsym(m_module, symbol));
- }
for (auto const &library : m_libraries)
{
- void *module = dlopen(library.c_str(), RTLD_LAZY);
+ void *const module = dlopen(library.c_str(), RTLD_LAZY);
if (module != nullptr)
{
- generic_fptr_t function = reinterpret_cast<generic_fptr_t>(dlsym(module, symbol));
+ generic_fptr_t const function = reinterpret_cast<generic_fptr_t>(dlsym(module, symbol));
- if (function != nullptr)
+ if (function)
{
m_module = module;
return function;
@@ -190,12 +260,81 @@ protected:
private:
std::vector<std::string> m_libraries;
- void * m_module;
+ void * m_module = nullptr;
};
+} // anonymous namespace
+
+
+bool invalidate_instruction_cache(void const *start, std::size_t size) noexcept
+{
+#if !defined(SDLMAME_EMSCRIPTEN)
+ char const *const begin(reinterpret_cast<char const *>(start));
+ char const *const end(begin + size);
+ __builtin___clear_cache(const_cast<char *>(begin), const_cast<char *>(end));
+#endif
+ return true;
+}
+
+
+void *virtual_memory_allocation::do_alloc(std::initializer_list<std::size_t> blocks, unsigned intent, std::size_t &size, std::size_t &page_size) noexcept
+{
+ long const p(sysconf(_SC_PAGE_SIZE));
+ if (0 >= p)
+ return nullptr;
+ std::size_t s(0);
+ for (std::size_t b : blocks)
+ s += (b + p - 1) / p;
+ s *= p;
+ if (!s)
+ return nullptr;
+#if defined __NetBSD__
+ int req((NONE == intent) ? PROT_NONE : 0);
+ if (intent & READ)
+ req |= PROT_READ;
+ if (intent & WRITE)
+ req |= PROT_WRITE;
+ if (intent & EXECUTE)
+ req |= PROT_EXEC;
+ int const prot(PROT_MPROTECT(req));
+#else
+ int const prot(PROT_NONE);
+#endif
+#if defined(SDLMAME_BSD) || defined(SDLMAME_MACOSX) || defined(SDLMAME_EMSCRIPTEN)
+ int const fd(-1);
+#else
+ // TODO: portable applications are supposed to use -1 for anonymous mappings - detect whatever requires 0 specifically
+ int const fd(0);
+#endif
+ void *const result(mmap(nullptr, s, prot, MAP_ANON | MAP_SHARED, fd, 0));
+ if (result == (void *)-1)
+ return nullptr;
+ size = s;
+ page_size = p;
+ return result;
+}
+
+void virtual_memory_allocation::do_free(void *start, std::size_t size) noexcept
+{
+ munmap(reinterpret_cast<char *>(start), size);
+}
+
+bool virtual_memory_allocation::do_set_access(void *start, std::size_t size, unsigned access) noexcept
+{
+ int prot((NONE == access) ? PROT_NONE : 0);
+ if (access & READ)
+ prot |= PROT_READ;
+ if (access & WRITE)
+ prot |= PROT_WRITE;
+ if (access & EXECUTE)
+ prot |= PROT_EXEC;
+ return mprotect(reinterpret_cast<char *>(start), size, prot) == 0;
+}
+
+
dynamic_module::ptr dynamic_module::open(std::vector<std::string> &&names)
{
- return std::make_unique<dynamic_module_posix_impl>(names);
+ return std::make_unique<dynamic_module_posix_impl>(std::move(names));
}
} // namespace osd
diff --git a/src/osd/modules/lib/osdlib_uwp.cpp b/src/osd/modules/lib/osdlib_uwp.cpp
deleted file mode 100644
index 8d20c552cab..00000000000
--- a/src/osd/modules/lib/osdlib_uwp.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes
-//============================================================
-//
-// sdlos_*.c - OS specific low level code
-//
-// SDLMAME by Olivier Galibert and R. Belmont
-//
-//============================================================
-
-#include <windows.h>
-#include <mmsystem.h>
-
-#include <stdlib.h>
-
-#include <cstdio>
-#include <memory>
-
-// MAME headers
-#include "osdlib.h"
-#include "osdcomm.h"
-#include "osdcore.h"
-#include "strconv.h"
-
-#include <windows.h>
-#include <wrl\client.h>
-
-#include "strconv.h"
-
-using namespace Platform;
-using namespace Windows::ApplicationModel::DataTransfer;
-using namespace Windows::Foundation;
-
-#include <map>
-
-//============================================================
-// GLOBAL VARIABLES
-//============================================================
-
-std::map<const char *, std::unique_ptr<char>> g_runtime_environment;
-
-//============================================================
-// osd_getenv
-//============================================================
-
-const char *osd_getenv(const char *name)
-{
- for (auto iter = g_runtime_environment.begin(); iter != g_runtime_environment.end(); iter++)
- {
- if (stricmp(iter->first, name) == 0)
- {
- osd_printf_debug("ENVIRONMENT: Get %s = value: '%s'", name, iter->second.get());
- return iter->second.get();
- }
- }
-
- return nullptr;
-}
-
-
-//============================================================
-// osd_setenv
-//============================================================
-
-int osd_setenv(const char *name, const char *value, int overwrite)
-{
- if (!overwrite)
- {
- if (osd_getenv(name) != nullptr)
- return 0;
- }
-
- auto buf = std::make_unique<char>(strlen(name) + strlen(value) + 2);
- sprintf(buf.get(), "%s=%s", name, value);
-
- g_runtime_environment[name] = std::move(buf);
- osd_printf_debug("ENVIRONMENT: Set %s to value: '%s'", name, buf.get());
-
- return 0;
-}
-
-//============================================================
-// osd_process_kill
-//============================================================
-
-void osd_process_kill()
-{
- TerminateProcess(GetCurrentProcess(), -1);
-}
-
-//============================================================
-// osd_alloc_executable
-//
-// allocates "size" bytes of executable memory. this must take
-// things like NX support into account.
-//============================================================
-
-void *osd_alloc_executable(size_t size)
-{
- return nullptr;
-}
-
-
-//============================================================
-// osd_free_executable
-//
-// frees memory allocated with osd_alloc_executable
-//============================================================
-
-void osd_free_executable(void *ptr, size_t size)
-{
-}
-
-
-//============================================================
-// osd_break_into_debugger
-//============================================================
-
-void osd_break_into_debugger(const char *message)
-{
- if (IsDebuggerPresent())
- {
- OutputDebugStringA(message);
- __debugbreak();
- }
-}
-
-//============================================================
-// get_clipboard_text_by_format
-//============================================================
-
-static bool get_clipboard_text_by_format(std::string &result_text, UINT format, std::string (*convert)(LPCVOID data))
-{
- DataPackageView^ dataPackageView;
- IAsyncOperation<String^>^ getTextOp;
- String^ clipboardText;
-
- dataPackageView = Clipboard::GetContent();
- getTextOp = dataPackageView->GetTextAsync();
- clipboardText = getTextOp->GetResults();
-
- result_text = convert(clipboardText->Data());
- return !result_text.empty();
-}
-
-//============================================================
-// convert_wide
-//============================================================
-
-static std::string convert_wide(LPCVOID data)
-{
- return osd::text::from_wstring((LPCWSTR) data);
-}
-
-//============================================================
-// convert_ansi
-//============================================================
-
-static std::string convert_ansi(LPCVOID data)
-{
- return osd::text::from_astring((LPCSTR) data);
-}
-
-//============================================================
-// osd_get_clipboard_text
-//============================================================
-
-std::string osd_get_clipboard_text(void)
-{
- std::string result;
-
- // try to access unicode text
- if (!get_clipboard_text_by_format(result, CF_UNICODETEXT, convert_wide))
- {
- // try to access ANSI text
- get_clipboard_text_by_format(result, CF_TEXT, convert_ansi);
- }
-
- return result;
-}
-
-//============================================================
-// osd_getpid
-//============================================================
-
-int osd_getpid(void)
-{
- return GetCurrentProcessId();
-}
-
diff --git a/src/osd/modules/lib/osdlib_win32.cpp b/src/osd/modules/lib/osdlib_win32.cpp
index 911f95c3bfe..cf3fd7c9320 100644
--- a/src/osd/modules/lib/osdlib_win32.cpp
+++ b/src/osd/modules/lib/osdlib_win32.cpp
@@ -8,27 +8,27 @@
//
//============================================================
-#include <windows.h>
-#include <mmsystem.h>
-
-#include <stdlib.h>
-#ifndef _MSC_VER
-#include <unistd.h>
-#endif
-
-#include <cstdio>
-#include <memory>
-
// MAME headers
#include "osdlib.h"
#include "osdcomm.h"
#include "osdcore.h"
#include "strconv.h"
-#ifdef OSD_WINDOWS
#include "winutf8.h"
+#include "winutil.h"
+
+#include <algorithm>
+#include <cstdio>
+#include <cstdlib>
+
+#include <windows.h>
+#include <memoryapi.h>
+
+#ifndef _MSC_VER
+#include <unistd.h>
#endif
+
//============================================================
// GLOBAL VARIABLES
//============================================================
@@ -82,30 +82,6 @@ void osd_process_kill()
TerminateProcess(GetCurrentProcess(), -1);
}
-//============================================================
-// osd_alloc_executable
-//
-// allocates "size" bytes of executable memory. this must take
-// things like NX support into account.
-//============================================================
-
-void *osd_alloc_executable(size_t size)
-{
- return VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
-}
-
-
-//============================================================
-// osd_free_executable
-//
-// frees memory allocated with osd_alloc_executable
-//============================================================
-
-void osd_free_executable(void *ptr, size_t size)
-{
- VirtualFree(ptr, 0, MEM_RELEASE);
-}
-
//============================================================
// osd_break_into_debugger
@@ -130,6 +106,42 @@ void osd_break_into_debugger(const char *message)
#endif
}
+
+//============================================================
+// osd_get_cache_line_size
+//============================================================
+
+std::pair<std::error_condition, unsigned> osd_get_cache_line_size() noexcept
+{
+ DWORD resultsize = 0;
+ if (GetLogicalProcessorInformation(nullptr, &resultsize) || (ERROR_INSUFFICIENT_BUFFER != GetLastError()) || !resultsize)
+ return std::make_pair(std::errc::operation_not_permitted, 0U);
+
+ auto const result = reinterpret_cast<SYSTEM_LOGICAL_PROCESSOR_INFORMATION *>(std::malloc(resultsize));
+ if (!result)
+ return std::make_pair(std::errc::not_enough_memory, 0U);
+
+ if (!GetLogicalProcessorInformation(result, &resultsize))
+ {
+ std::free(result);
+ return std::make_pair(std::errc::operation_not_permitted, 0U);
+ }
+
+ for (unsigned i = 0; i < (resultsize / sizeof(result[0])); ++i)
+ {
+ if ((RelationCache == result[i].Relationship) && (1 == result[i].Cache.Level))
+ {
+ unsigned const linesize = result[i].Cache.LineSize;
+ std::free(result);
+ return std::make_pair(std::error_condition(), linesize);
+ }
+ }
+
+ std::free(result);
+ return std::make_pair(std::errc::operation_not_permitted, 0U);
+}
+
+
//============================================================
// get_clipboard_text_by_format
//============================================================
@@ -192,25 +204,92 @@ static std::string convert_ansi(LPCVOID data)
// osd_get_clipboard_text
//============================================================
-std::string osd_get_clipboard_text(void)
+std::string osd_get_clipboard_text() noexcept
{
std::string result;
- // try to access unicode text
- if (!get_clipboard_text_by_format(result, CF_UNICODETEXT, convert_wide))
+ // TODO: better error handling
+ try
+ {
+ // try to access unicode text
+ if (!get_clipboard_text_by_format(result, CF_UNICODETEXT, convert_wide))
+ {
+ // try to access ANSI text
+ get_clipboard_text_by_format(result, CF_TEXT, convert_ansi);
+ }
+ }
+ catch (...)
{
- // try to access ANSI text
- get_clipboard_text_by_format(result, CF_TEXT, convert_ansi);
}
return result;
}
//============================================================
+// osd_set_clipboard_text
+//============================================================
+
+std::error_condition osd_set_clipboard_text(std::string_view text) noexcept
+{
+ try
+ {
+ // convert the text to a wide char string and create a moveable global block
+ std::wstring const wtext = osd::text::to_wstring(text);
+ HGLOBAL const clip = GlobalAlloc(GMEM_MOVEABLE, (text.length() + 1) * sizeof(wchar_t));
+ if (!clip)
+ return win_error_to_error_condition(GetLastError());
+ LPWSTR const lock = reinterpret_cast<LPWSTR>(GlobalLock(clip));
+ if (!lock)
+ {
+ DWORD const err(GetLastError());
+ GlobalFree(clip);
+ return win_error_to_error_condition(err);
+ }
+
+ // clear current clipboard contents
+ if (!OpenClipboard(nullptr))
+ {
+ DWORD const err(GetLastError());
+ GlobalUnlock(clip);
+ GlobalFree(clip);
+ return win_error_to_error_condition(err);
+ }
+ if (!EmptyClipboard())
+ {
+ DWORD const err(GetLastError());
+ CloseClipboard();
+ GlobalUnlock(clip);
+ GlobalFree(clip);
+ return win_error_to_error_condition(err);
+ }
+
+ // copy the text (plus NUL terminator) to the moveable block and put it on the clipboard
+ std::copy_n(wtext.c_str(), wtext.length() + 1, lock);
+ GlobalUnlock(clip);
+ if (!SetClipboardData(CF_UNICODETEXT, clip))
+ {
+ DWORD const err(GetLastError());
+ CloseClipboard();
+ GlobalFree(clip);
+ return win_error_to_error_condition(err);
+ }
+
+ // clean up
+ if (!CloseClipboard())
+ return win_error_to_error_condition(GetLastError());
+ return std::error_condition();
+ }
+ catch (std::bad_alloc const &)
+ {
+ return std::errc::not_enough_memory;
+ }
+}
+
+//============================================================
// osd_getpid
//============================================================
-int osd_getpid(void)
+int osd_getpid() noexcept
{
return GetCurrentProcessId();
}
@@ -219,29 +298,25 @@ int osd_getpid(void)
// osd_dynamic_bind
//============================================================
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
// for classic desktop applications
#define load_library(filename) LoadLibrary(filename)
-#else
-// for Windows Store universal applications
-#define load_library(filename) LoadPackagedLibrary(filename, 0)
-#endif
namespace osd {
+
+namespace {
+
class dynamic_module_win32_impl : public dynamic_module
{
public:
- dynamic_module_win32_impl(std::vector<std::string> &libraries)
- : m_module(nullptr)
+ dynamic_module_win32_impl(std::vector<std::string> &&libraries) : m_libraries(std::move(libraries))
{
- m_libraries = libraries;
}
virtual ~dynamic_module_win32_impl() override
{
- if (m_module != nullptr)
+ if (m_module)
FreeLibrary(m_module);
- };
+ }
protected:
virtual generic_fptr_t get_symbol_address(char const *symbol) override
@@ -251,20 +326,18 @@ protected:
* one of them, all additional symbols will be loaded from the same library
*/
if (m_module)
- {
return reinterpret_cast<generic_fptr_t>(GetProcAddress(m_module, symbol));
- }
for (auto const &library : m_libraries)
{
- osd::text::tstring tempstr = osd::text::to_tstring(library);
- HMODULE module = load_library(tempstr.c_str());
+ osd::text::tstring const tempstr = osd::text::to_tstring(library);
+ HMODULE const module = load_library(tempstr.c_str());
- if (module != nullptr)
+ if (module)
{
- generic_fptr_t function = reinterpret_cast<generic_fptr_t>(GetProcAddress(module, symbol));
+ auto const function = reinterpret_cast<generic_fptr_t>(GetProcAddress(module, symbol));
- if (function != nullptr)
+ if (function)
{
m_module = module;
return function;
@@ -281,12 +354,56 @@ protected:
private:
std::vector<std::string> m_libraries;
- HMODULE m_module;
+ HMODULE m_module = nullptr;
};
+} // anonymous namespace
+
+
+bool invalidate_instruction_cache(void const *start, std::size_t size) noexcept
+{
+ return FlushInstructionCache(GetCurrentProcess(), start, size) != 0;
+}
+
+
+void *virtual_memory_allocation::do_alloc(std::initializer_list<std::size_t> blocks, unsigned intent, std::size_t &size, std::size_t &page_size) noexcept
+{
+ SYSTEM_INFO info;
+ GetSystemInfo(&info);
+ SIZE_T s(0);
+ for (std::size_t b : blocks)
+ s += (b + info.dwPageSize - 1) / info.dwPageSize;
+ s *= info.dwPageSize;
+ if (!s)
+ return nullptr;
+ LPVOID const result(VirtualAlloc(nullptr, s, MEM_COMMIT, PAGE_NOACCESS));
+ if (result)
+ {
+ size = s;
+ page_size = info.dwPageSize;
+ }
+ return result;
+}
+
+void virtual_memory_allocation::do_free(void *start, std::size_t size) noexcept
+{
+ VirtualFree(start, 0, MEM_RELEASE);
+}
+
+bool virtual_memory_allocation::do_set_access(void *start, std::size_t size, unsigned access) noexcept
+{
+ DWORD p;
+ if (access & EXECUTE)
+ p = (access & WRITE) ? PAGE_EXECUTE_READWRITE : (access & READ) ? PAGE_EXECUTE_READ : PAGE_EXECUTE;
+ else
+ p = (access & WRITE) ? PAGE_READWRITE : (access & READ) ? PAGE_READONLY : PAGE_NOACCESS;
+ return VirtualAlloc(start, size, MEM_COMMIT, p) != nullptr;
+}
+
+
dynamic_module::ptr dynamic_module::open(std::vector<std::string> &&names)
{
- return std::make_unique<dynamic_module_win32_impl>(names);
+ return std::make_unique<dynamic_module_win32_impl>(std::move(names));
}
} // namespace osd
diff --git a/src/osd/modules/lib/osdobj_common.cpp b/src/osd/modules/lib/osdobj_common.cpp
index 51474b810b0..24148889570 100644
--- a/src/osd/modules/lib/osdobj_common.cpp
+++ b/src/osd/modules/lib/osdobj_common.cpp
@@ -2,164 +2,188 @@
// copyright-holders:Aaron Giles
/***************************************************************************
- osdepend.c
+ osdobj_common.h
OS-dependent code interface.
***************************************************************************/
+#include "osdobj_common.h"
+
+#include "modules/osdwindow.h"
+#include "modules/debugger/debug_module.h"
+#include "modules/font/font_module.h"
+#include "modules/input/input_module.h"
+#include "modules/midi/midi_module.h"
+#include "modules/netdev/netdev_module.h"
+#include "modules/monitor/monitor_module.h"
+#include "modules/netdev/netdev_module.h"
+#include "modules/render/render_module.h"
+#include "modules/sound/sound_module.h"
+
+#include "watchdog.h"
#include "emu.h"
-#include "osdepend.h"
-#include "modules/lib/osdobj_common.h"
+#include "../frontend/mame/ui/menuitem.h"
+
+#include <iostream>
+
const options_entry osd_options::s_option_entries[] =
{
- { nullptr, nullptr, OPTION_HEADER, "OSD KEYBOARD MAPPING OPTIONS" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "OSD INPUT MAPPING OPTIONS" },
#if defined(SDLMAME_MACOSX) || defined(OSD_MAC)
- { OSDOPTION_UIMODEKEY, "DEL", OPTION_STRING, "key to enable/disable MAME controls when emulated system has keyboard inputs" },
+ { OSDOPTION_UIMODEKEY, "DEL", core_options::option_type::STRING, "key to enable/disable MAME controls when emulated system has keyboard inputs" },
#else
- { OSDOPTION_UIMODEKEY, "SCRLOCK", OPTION_STRING, "key to enable/disable MAME controls when emulated system has keyboard inputs" },
+ { OSDOPTION_UIMODEKEY, "auto", core_options::option_type::STRING, "key to enable/disable MAME controls when emulated system has keyboard inputs" },
#endif // SDLMAME_MACOSX
-
- { nullptr, nullptr, OPTION_HEADER, "OSD FONT OPTIONS" },
- { OSD_FONT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for UI font: " },
-
- { nullptr, nullptr, OPTION_HEADER, "OSD OUTPUT OPTIONS" },
- { OSD_OUTPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for output notifications: " },
-
- { nullptr, nullptr, OPTION_HEADER, "OSD INPUT OPTIONS" },
- { OSD_KEYBOARDINPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for keyboard input: " },
- { OSD_MOUSEINPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for mouse input: " },
- { OSD_LIGHTGUNINPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for lightgun input: " },
- { OSD_JOYSTICKINPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for joystick input: " },
-
- { nullptr, nullptr, OPTION_HEADER, "OSD CLI OPTIONS" },
- { OSDCOMMAND_LIST_MIDI_DEVICES ";mlist", "0", OPTION_COMMAND, "list available MIDI I/O devices" },
- { OSDCOMMAND_LIST_NETWORK_ADAPTERS ";nlist", "0", OPTION_COMMAND, "list available network adapters" },
-
- { nullptr, nullptr, OPTION_HEADER, "OSD DEBUGGING OPTIONS" },
- { OSDOPTION_DEBUGGER, OSDOPTVAL_AUTO, OPTION_STRING, "debugger used: " },
- { OSDOPTION_DEBUGGER_PORT, "23946", OPTION_INTEGER, "port to use for gdbstub debugger" },
- { OSDOPTION_DEBUGGER_FONT ";dfont", OSDOPTVAL_AUTO, OPTION_STRING, "font to use for debugger views" },
- { OSDOPTION_DEBUGGER_FONT_SIZE ";dfontsize", "0", OPTION_FLOAT, "font size to use for debugger views" },
- { OSDOPTION_WATCHDOG ";wdog", "0", OPTION_INTEGER, "force the program to terminate if no updates within specified number of seconds" },
-
- { nullptr, nullptr, OPTION_HEADER, "OSD PERFORMANCE OPTIONS" },
- { OSDOPTION_NUMPROCESSORS ";np", OSDOPTVAL_AUTO, OPTION_STRING, "number of processors; this overrides the number the system reports" },
- { OSDOPTION_BENCH, "0", OPTION_INTEGER, "benchmark for the given number of emulated seconds; implies -video none -sound none -nothrottle" },
-
- { nullptr, nullptr, OPTION_HEADER, "OSD VIDEO OPTIONS" },
-// OS X can be trusted to have working hardware OpenGL, so default to it on for the best user experience
- { OSDOPTION_VIDEO, OSDOPTVAL_AUTO, OPTION_STRING, "video output method: " },
- { OSDOPTION_NUMSCREENS "(1-4)", "1", OPTION_INTEGER, "number of output screens/windows to create; usually, you want just one" },
- { OSDOPTION_WINDOW ";w", "0", OPTION_BOOLEAN, "enable window mode; otherwise, full screen mode is assumed" },
- { OSDOPTION_MAXIMIZE ";max", "1", OPTION_BOOLEAN, "default to maximized windows" },
- { OSDOPTION_WAITVSYNC ";vs", "0", OPTION_BOOLEAN, "enable waiting for the start of VBLANK before flipping screens (reduces tearing effects)" },
- { OSDOPTION_SYNCREFRESH ";srf", "0", OPTION_BOOLEAN, "enable using the start of VBLANK for throttling instead of the game time" },
- { OSD_MONITOR_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "monitor discovery method: " },
+ { OSDOPTION_CONTROLLER_MAP_FILE ";ctrlmap", OSDOPTVAL_NONE, core_options::option_type::PATH, "game controller mapping file" },
+ { OSDOPTION_BACKGROUND_INPUT, "0", core_options::option_type::BOOLEAN, "don't ignore input when losing UI focus" },
+
+ { nullptr, nullptr, core_options::option_type::HEADER, "OSD FONT OPTIONS" },
+ { OSD_FONT_PROVIDER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "provider for UI font: " },
+
+ { nullptr, nullptr, core_options::option_type::HEADER, "OSD OUTPUT OPTIONS" },
+ { OSD_OUTPUT_PROVIDER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "provider for output notifications: " },
+
+ { nullptr, nullptr, core_options::option_type::HEADER, "OSD INPUT OPTIONS" },
+ { OSD_KEYBOARDINPUT_PROVIDER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "provider for keyboard input: " },
+ { OSD_MOUSEINPUT_PROVIDER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "provider for mouse input: " },
+ { OSD_LIGHTGUNINPUT_PROVIDER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "provider for lightgun input: " },
+ { OSD_JOYSTICKINPUT_PROVIDER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "provider for joystick input: " },
+
+ { nullptr, nullptr, core_options::option_type::HEADER, "OSD CLI OPTIONS" },
+ { OSDCOMMAND_LIST_MIDI_DEVICES ";mlist", "0", core_options::option_type::COMMAND, "list available MIDI I/O devices" },
+ { OSDCOMMAND_LIST_NETWORK_ADAPTERS ";nlist", "0", core_options::option_type::COMMAND, "list available network adapters" },
+
+ { nullptr, nullptr, core_options::option_type::HEADER, "OSD DEBUGGING OPTIONS" },
+ { OSDOPTION_DEBUGGER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "debugger used: " },
+ { OSDOPTION_DEBUGGER_HOST, "localhost", core_options::option_type::STRING, "address to bind to for gdbstub debugger" },
+ { OSDOPTION_DEBUGGER_PORT, "23946", core_options::option_type::INTEGER, "port to use for gdbstub debugger" },
+ { OSDOPTION_DEBUGGER_FONT ";dfont", OSDOPTVAL_AUTO, core_options::option_type::STRING, "font to use for debugger views" },
+ { OSDOPTION_DEBUGGER_FONT_SIZE ";dfontsize", "0", core_options::option_type::FLOAT, "font size to use for debugger views" },
+ { OSDOPTION_WATCHDOG ";wdog", "0", core_options::option_type::INTEGER, "force the program to terminate if no updates within specified number of seconds" },
+
+ { nullptr, nullptr, core_options::option_type::HEADER, "OSD PERFORMANCE OPTIONS" },
+ { OSDOPTION_NUMPROCESSORS ";np", OSDOPTVAL_AUTO, core_options::option_type::STRING, "number of processors; this overrides the number the system reports" },
+ { OSDOPTION_BENCH, "0", core_options::option_type::INTEGER, "benchmark for the given number of emulated seconds; implies -video none -sound none -nothrottle" },
+
+ { nullptr, nullptr, core_options::option_type::HEADER, "OSD VIDEO OPTIONS" },
+ { OSDOPTION_VIDEO, OSDOPTVAL_AUTO, core_options::option_type::STRING, "video output method: " },
+ { OSDOPTION_NUMSCREENS "(1-4)", "1", core_options::option_type::INTEGER, "number of output screens/windows to create; usually, you want just one" },
+ { OSDOPTION_WINDOW ";w", "0", core_options::option_type::BOOLEAN, "enable window mode; otherwise, full screen mode is assumed" },
+ { OSDOPTION_MAXIMIZE ";max", "1", core_options::option_type::BOOLEAN, "default to maximized windows" },
+ { OSDOPTION_WAITVSYNC ";vs", "0", core_options::option_type::BOOLEAN, "enable waiting for the start of VBLANK before flipping screens (reduces tearing effects)" },
+ { OSDOPTION_SYNCREFRESH ";srf", "0", core_options::option_type::BOOLEAN, "enable using the start of VBLANK for throttling instead of the game time" },
+ { OSD_MONITOR_PROVIDER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "monitor discovery method: " },
// per-window options
- { nullptr, nullptr, OPTION_HEADER, "OSD PER-WINDOW VIDEO OPTIONS" },
- { OSDOPTION_SCREEN, OSDOPTVAL_AUTO, OPTION_STRING, "explicit name of the first screen; 'auto' here will try to make a best guess" },
- { OSDOPTION_ASPECT ";screen_aspect", OSDOPTVAL_AUTO, OPTION_STRING, "aspect ratio for all screens; 'auto' here will try to make a best guess" },
- { OSDOPTION_RESOLUTION ";r", OSDOPTVAL_AUTO, OPTION_STRING, "preferred resolution for all screens; format is <width>x<height>[@<refreshrate>] or 'auto'" },
- { OSDOPTION_VIEW, OSDOPTVAL_AUTO, OPTION_STRING, "preferred view for all screens" },
-
- { OSDOPTION_SCREEN "0", OSDOPTVAL_AUTO, OPTION_STRING, "explicit name of the first screen; 'auto' here will try to make a best guess" },
- { OSDOPTION_ASPECT "0", OSDOPTVAL_AUTO, OPTION_STRING, "aspect ratio of the first screen; 'auto' here will try to make a best guess" },
- { OSDOPTION_RESOLUTION "0;r0", OSDOPTVAL_AUTO, OPTION_STRING, "preferred resolution of the first screen; format is <width>x<height>[@<refreshrate>] or 'auto'" },
- { OSDOPTION_VIEW "0", OSDOPTVAL_AUTO, OPTION_STRING, "preferred view for the first screen" },
-
- { OSDOPTION_SCREEN "1", OSDOPTVAL_AUTO, OPTION_STRING, "explicit name of the second screen; 'auto' here will try to make a best guess" },
- { OSDOPTION_ASPECT "1", OSDOPTVAL_AUTO, OPTION_STRING, "aspect ratio of the second screen; 'auto' here will try to make a best guess" },
- { OSDOPTION_RESOLUTION "1;r1", OSDOPTVAL_AUTO, OPTION_STRING, "preferred resolution of the second screen; format is <width>x<height>[@<refreshrate>] or 'auto'" },
- { OSDOPTION_VIEW "1", OSDOPTVAL_AUTO, OPTION_STRING, "preferred view for the second screen" },
-
- { OSDOPTION_SCREEN "2", OSDOPTVAL_AUTO, OPTION_STRING, "explicit name of the third screen; 'auto' here will try to make a best guess" },
- { OSDOPTION_ASPECT "2", OSDOPTVAL_AUTO, OPTION_STRING, "aspect ratio of the third screen; 'auto' here will try to make a best guess" },
- { OSDOPTION_RESOLUTION "2;r2", OSDOPTVAL_AUTO, OPTION_STRING, "preferred resolution of the third screen; format is <width>x<height>[@<refreshrate>] or 'auto'" },
- { OSDOPTION_VIEW "2", OSDOPTVAL_AUTO, OPTION_STRING, "preferred view for the third screen" },
-
- { OSDOPTION_SCREEN "3", OSDOPTVAL_AUTO, OPTION_STRING, "explicit name of the fourth screen; 'auto' here will try to make a best guess" },
- { OSDOPTION_ASPECT "3", OSDOPTVAL_AUTO, OPTION_STRING, "aspect ratio of the fourth screen; 'auto' here will try to make a best guess" },
- { OSDOPTION_RESOLUTION "3;r3", OSDOPTVAL_AUTO, OPTION_STRING, "preferred resolution of the fourth screen; format is <width>x<height>[@<refreshrate>] or 'auto'" },
- { OSDOPTION_VIEW "3", OSDOPTVAL_AUTO, OPTION_STRING, "preferred view for the fourth screen" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "OSD PER-WINDOW VIDEO OPTIONS" },
+ { OSDOPTION_SCREEN, OSDOPTVAL_AUTO, core_options::option_type::STRING, "explicit name of the first screen; 'auto' here will try to make a best guess" },
+ { OSDOPTION_ASPECT ";screen_aspect", OSDOPTVAL_AUTO, core_options::option_type::STRING, "aspect ratio for all screens; 'auto' here will try to make a best guess" },
+ { OSDOPTION_RESOLUTION ";r", OSDOPTVAL_AUTO, core_options::option_type::STRING, "preferred resolution for all screens; format is <width>x<height>[@<refreshrate>] or 'auto'" },
+ { OSDOPTION_VIEW, OSDOPTVAL_AUTO, core_options::option_type::STRING, "preferred view for all screens" },
+
+ { OSDOPTION_SCREEN "0", OSDOPTVAL_AUTO, core_options::option_type::STRING, "explicit name of the first screen; 'auto' here will try to make a best guess" },
+ { OSDOPTION_ASPECT "0", OSDOPTVAL_AUTO, core_options::option_type::STRING, "aspect ratio of the first screen; 'auto' here will try to make a best guess" },
+ { OSDOPTION_RESOLUTION "0;r0", OSDOPTVAL_AUTO, core_options::option_type::STRING, "preferred resolution of the first screen; format is <width>x<height>[@<refreshrate>] or 'auto'" },
+ { OSDOPTION_VIEW "0", OSDOPTVAL_AUTO, core_options::option_type::STRING, "preferred view for the first screen" },
+
+ { OSDOPTION_SCREEN "1", OSDOPTVAL_AUTO, core_options::option_type::STRING, "explicit name of the second screen; 'auto' here will try to make a best guess" },
+ { OSDOPTION_ASPECT "1", OSDOPTVAL_AUTO, core_options::option_type::STRING, "aspect ratio of the second screen; 'auto' here will try to make a best guess" },
+ { OSDOPTION_RESOLUTION "1;r1", OSDOPTVAL_AUTO, core_options::option_type::STRING, "preferred resolution of the second screen; format is <width>x<height>[@<refreshrate>] or 'auto'" },
+ { OSDOPTION_VIEW "1", OSDOPTVAL_AUTO, core_options::option_type::STRING, "preferred view for the second screen" },
+
+ { OSDOPTION_SCREEN "2", OSDOPTVAL_AUTO, core_options::option_type::STRING, "explicit name of the third screen; 'auto' here will try to make a best guess" },
+ { OSDOPTION_ASPECT "2", OSDOPTVAL_AUTO, core_options::option_type::STRING, "aspect ratio of the third screen; 'auto' here will try to make a best guess" },
+ { OSDOPTION_RESOLUTION "2;r2", OSDOPTVAL_AUTO, core_options::option_type::STRING, "preferred resolution of the third screen; format is <width>x<height>[@<refreshrate>] or 'auto'" },
+ { OSDOPTION_VIEW "2", OSDOPTVAL_AUTO, core_options::option_type::STRING, "preferred view for the third screen" },
+
+ { OSDOPTION_SCREEN "3", OSDOPTVAL_AUTO, core_options::option_type::STRING, "explicit name of the fourth screen; 'auto' here will try to make a best guess" },
+ { OSDOPTION_ASPECT "3", OSDOPTVAL_AUTO, core_options::option_type::STRING, "aspect ratio of the fourth screen; 'auto' here will try to make a best guess" },
+ { OSDOPTION_RESOLUTION "3;r3", OSDOPTVAL_AUTO, core_options::option_type::STRING, "preferred resolution of the fourth screen; format is <width>x<height>[@<refreshrate>] or 'auto'" },
+ { OSDOPTION_VIEW "3", OSDOPTVAL_AUTO, core_options::option_type::STRING, "preferred view for the fourth screen" },
// full screen options
- { nullptr, nullptr, OPTION_HEADER, "OSD FULL SCREEN OPTIONS" },
- { OSDOPTION_SWITCHRES, "0", OPTION_BOOLEAN, "enable resolution switching" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "OSD FULL SCREEN OPTIONS" },
+ { OSDOPTION_SWITCHRES, "0", core_options::option_type::BOOLEAN, "enable resolution switching" },
- { nullptr, nullptr, OPTION_HEADER, "OSD ACCELERATED VIDEO OPTIONS" },
- { OSDOPTION_FILTER ";glfilter;flt", "1", OPTION_BOOLEAN, "use bilinear filtering when scaling emulated video" },
- { OSDOPTION_PRESCALE "(1-3)", "1", OPTION_INTEGER, "scale emulated video by this factor before applying filters/shaders" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "OSD ACCELERATED VIDEO OPTIONS" },
+ { OSDOPTION_FILTER ";glfilter;flt", "1", core_options::option_type::BOOLEAN, "use bilinear filtering when scaling emulated video" },
+ { OSDOPTION_PRESCALE "(1-20)", "1", core_options::option_type::INTEGER, "scale emulated video by this factor before applying filters/shaders" },
#if USE_OPENGL
- { nullptr, nullptr, OPTION_HEADER, "OpenGL-SPECIFIC OPTIONS" },
- { OSDOPTION_GL_FORCEPOW2TEXTURE, "0", OPTION_BOOLEAN, "force power-of-two texture sizes (default no)" },
- { OSDOPTION_GL_NOTEXTURERECT, "0", OPTION_BOOLEAN, "don't use OpenGL GL_ARB_texture_rectangle (default on)" },
- { OSDOPTION_GL_VBO, "1", OPTION_BOOLEAN, "enable OpenGL VBO if available (default on)" },
- { OSDOPTION_GL_PBO, "1", OPTION_BOOLEAN, "enable OpenGL PBO if available (default on)" },
- { OSDOPTION_GL_GLSL, "0", OPTION_BOOLEAN, "enable OpenGL GLSL if available (default off)" },
- { OSDOPTION_GLSL_FILTER, "1", OPTION_STRING, "enable OpenGL GLSL filtering instead of FF filtering 0-plain, 1-bilinear (default), 2-bicubic" },
- { OSDOPTION_SHADER_MAME "0", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader set mame bitmap 0" },
- { OSDOPTION_SHADER_MAME "1", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader set mame bitmap 1" },
- { OSDOPTION_SHADER_MAME "2", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader set mame bitmap 2" },
- { OSDOPTION_SHADER_MAME "3", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader set mame bitmap 3" },
- { OSDOPTION_SHADER_MAME "4", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader set mame bitmap 4" },
- { OSDOPTION_SHADER_MAME "5", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader set mame bitmap 5" },
- { OSDOPTION_SHADER_MAME "6", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader set mame bitmap 6" },
- { OSDOPTION_SHADER_MAME "7", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader set mame bitmap 7" },
- { OSDOPTION_SHADER_MAME "8", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader set mame bitmap 8" },
- { OSDOPTION_SHADER_MAME "9", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader set mame bitmap 9" },
- { OSDOPTION_SHADER_SCREEN "0", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader screen bitmap 0" },
- { OSDOPTION_SHADER_SCREEN "1", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader screen bitmap 1" },
- { OSDOPTION_SHADER_SCREEN "2", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader screen bitmap 2" },
- { OSDOPTION_SHADER_SCREEN "3", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader screen bitmap 3" },
- { OSDOPTION_SHADER_SCREEN "4", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader screen bitmap 4" },
- { OSDOPTION_SHADER_SCREEN "5", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader screen bitmap 5" },
- { OSDOPTION_SHADER_SCREEN "6", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader screen bitmap 6" },
- { OSDOPTION_SHADER_SCREEN "7", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader screen bitmap 7" },
- { OSDOPTION_SHADER_SCREEN "8", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader screen bitmap 8" },
- { OSDOPTION_SHADER_SCREEN "9", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader screen bitmap 9" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "OpenGL-SPECIFIC OPTIONS" },
+ { OSDOPTION_GL_FORCEPOW2TEXTURE, "0", core_options::option_type::BOOLEAN, "force power-of-two texture sizes (default no)" },
+ { OSDOPTION_GL_NOTEXTURERECT, "0", core_options::option_type::BOOLEAN, "don't use OpenGL GL_ARB_texture_rectangle (default on)" },
+ { OSDOPTION_GL_VBO, "1", core_options::option_type::BOOLEAN, "enable OpenGL VBO if available (default on)" },
+ { OSDOPTION_GL_PBO, "1", core_options::option_type::BOOLEAN, "enable OpenGL PBO if available (default on)" },
+ { OSDOPTION_GL_GLSL, "0", core_options::option_type::BOOLEAN, "enable OpenGL GLSL if available (default off)" },
+ { OSDOPTION_GLSL_FILTER, "1", core_options::option_type::STRING, "enable OpenGL GLSL filtering instead of FF filtering 0-plain, 1-bilinear (default), 2-bicubic" },
+ { OSDOPTION_SHADER_MAME "0", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader set mame bitmap 0" },
+ { OSDOPTION_SHADER_MAME "1", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader set mame bitmap 1" },
+ { OSDOPTION_SHADER_MAME "2", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader set mame bitmap 2" },
+ { OSDOPTION_SHADER_MAME "3", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader set mame bitmap 3" },
+ { OSDOPTION_SHADER_MAME "4", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader set mame bitmap 4" },
+ { OSDOPTION_SHADER_MAME "5", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader set mame bitmap 5" },
+ { OSDOPTION_SHADER_MAME "6", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader set mame bitmap 6" },
+ { OSDOPTION_SHADER_MAME "7", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader set mame bitmap 7" },
+ { OSDOPTION_SHADER_MAME "8", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader set mame bitmap 8" },
+ { OSDOPTION_SHADER_MAME "9", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader set mame bitmap 9" },
+ { OSDOPTION_SHADER_SCREEN "0", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader screen bitmap 0" },
+ { OSDOPTION_SHADER_SCREEN "1", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader screen bitmap 1" },
+ { OSDOPTION_SHADER_SCREEN "2", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader screen bitmap 2" },
+ { OSDOPTION_SHADER_SCREEN "3", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader screen bitmap 3" },
+ { OSDOPTION_SHADER_SCREEN "4", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader screen bitmap 4" },
+ { OSDOPTION_SHADER_SCREEN "5", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader screen bitmap 5" },
+ { OSDOPTION_SHADER_SCREEN "6", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader screen bitmap 6" },
+ { OSDOPTION_SHADER_SCREEN "7", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader screen bitmap 7" },
+ { OSDOPTION_SHADER_SCREEN "8", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader screen bitmap 8" },
+ { OSDOPTION_SHADER_SCREEN "9", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader screen bitmap 9" },
#endif
- { nullptr, nullptr, OPTION_HEADER, "OSD SOUND OPTIONS" },
- { OSDOPTION_SOUND, OSDOPTVAL_AUTO, OPTION_STRING, "sound output method: " },
- { OSDOPTION_AUDIO_LATENCY "(1-5)", "2", OPTION_INTEGER, "set audio latency (increase to reduce glitches, decrease for responsiveness)" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "OSD SOUND OPTIONS" },
+ { OSDOPTION_SOUND, OSDOPTVAL_AUTO, core_options::option_type::STRING, "sound output method: " },
+ { OSDOPTION_AUDIO_LATENCY "(0-5)", "2", core_options::option_type::INTEGER, "set audio latency (increase to reduce glitches, decrease for responsiveness)" },
#ifndef NO_USE_PORTAUDIO
- { nullptr, nullptr, OPTION_HEADER, "PORTAUDIO OPTIONS" },
- { OSDOPTION_PA_API, OSDOPTVAL_NONE, OPTION_STRING, "PortAudio API" },
- { OSDOPTION_PA_DEVICE, OSDOPTVAL_NONE, OPTION_STRING, "PortAudio device" },
- { OSDOPTION_PA_LATENCY "(0-0.25)", "0", OPTION_FLOAT, "suggested latency in seconds, 0 for default" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "PORTAUDIO OPTIONS" },
+ { OSDOPTION_PA_API, OSDOPTVAL_NONE, core_options::option_type::STRING, "PortAudio API" },
+ { OSDOPTION_PA_DEVICE, OSDOPTVAL_NONE, core_options::option_type::STRING, "PortAudio device" },
+ { OSDOPTION_PA_LATENCY "(0-0.25)", "0", core_options::option_type::FLOAT, "suggested latency in seconds, 0 for default" },
#endif
#ifdef SDLMAME_MACOSX
- { nullptr, nullptr, OPTION_HEADER, "CoreAudio-SPECIFIC OPTIONS" },
- { OSDOPTION_AUDIO_OUTPUT, OSDOPTVAL_AUTO, OPTION_STRING, "audio output device" },
- { OSDOPTION_AUDIO_EFFECT "0", OSDOPTVAL_NONE, OPTION_STRING, "AudioUnit effect 0" },
- { OSDOPTION_AUDIO_EFFECT "1", OSDOPTVAL_NONE, OPTION_STRING, "AudioUnit effect 1" },
- { OSDOPTION_AUDIO_EFFECT "2", OSDOPTVAL_NONE, OPTION_STRING, "AudioUnit effect 2" },
- { OSDOPTION_AUDIO_EFFECT "3", OSDOPTVAL_NONE, OPTION_STRING, "AudioUnit effect 3" },
- { OSDOPTION_AUDIO_EFFECT "4", OSDOPTVAL_NONE, OPTION_STRING, "AudioUnit effect 4" },
- { OSDOPTION_AUDIO_EFFECT "5", OSDOPTVAL_NONE, OPTION_STRING, "AudioUnit effect 5" },
- { OSDOPTION_AUDIO_EFFECT "6", OSDOPTVAL_NONE, OPTION_STRING, "AudioUnit effect 6" },
- { OSDOPTION_AUDIO_EFFECT "7", OSDOPTVAL_NONE, OPTION_STRING, "AudioUnit effect 7" },
- { OSDOPTION_AUDIO_EFFECT "8", OSDOPTVAL_NONE, OPTION_STRING, "AudioUnit effect 8" },
- { OSDOPTION_AUDIO_EFFECT "9", OSDOPTVAL_NONE, OPTION_STRING, "AudioUnit effect 9" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "CoreAudio-SPECIFIC OPTIONS" },
+ { OSDOPTION_AUDIO_OUTPUT, OSDOPTVAL_AUTO, core_options::option_type::STRING, "audio output device" },
+ { OSDOPTION_AUDIO_EFFECT "0", OSDOPTVAL_NONE, core_options::option_type::STRING, "AudioUnit effect 0" },
+ { OSDOPTION_AUDIO_EFFECT "1", OSDOPTVAL_NONE, core_options::option_type::STRING, "AudioUnit effect 1" },
+ { OSDOPTION_AUDIO_EFFECT "2", OSDOPTVAL_NONE, core_options::option_type::STRING, "AudioUnit effect 2" },
+ { OSDOPTION_AUDIO_EFFECT "3", OSDOPTVAL_NONE, core_options::option_type::STRING, "AudioUnit effect 3" },
+ { OSDOPTION_AUDIO_EFFECT "4", OSDOPTVAL_NONE, core_options::option_type::STRING, "AudioUnit effect 4" },
+ { OSDOPTION_AUDIO_EFFECT "5", OSDOPTVAL_NONE, core_options::option_type::STRING, "AudioUnit effect 5" },
+ { OSDOPTION_AUDIO_EFFECT "6", OSDOPTVAL_NONE, core_options::option_type::STRING, "AudioUnit effect 6" },
+ { OSDOPTION_AUDIO_EFFECT "7", OSDOPTVAL_NONE, core_options::option_type::STRING, "AudioUnit effect 7" },
+ { OSDOPTION_AUDIO_EFFECT "8", OSDOPTVAL_NONE, core_options::option_type::STRING, "AudioUnit effect 8" },
+ { OSDOPTION_AUDIO_EFFECT "9", OSDOPTVAL_NONE, core_options::option_type::STRING, "AudioUnit effect 9" },
#endif
- { nullptr, nullptr, OPTION_HEADER, "BGFX POST-PROCESSING OPTIONS" },
- { OSDOPTION_BGFX_PATH, "bgfx", OPTION_STRING, "path to BGFX-related files" },
- { OSDOPTION_BGFX_BACKEND, "auto", OPTION_STRING, "BGFX backend to use (d3d9, d3d11, metal, opengl, gles)" },
- { OSDOPTION_BGFX_DEBUG, "0", OPTION_BOOLEAN, "enable BGFX debugging statistics" },
- { OSDOPTION_BGFX_SCREEN_CHAINS, "default", OPTION_STRING, "comma-delimited list of screen chain JSON names, colon-delimited per-window" },
- { OSDOPTION_BGFX_SHADOW_MASK, "slot-mask.png", OPTION_STRING, "shadow mask texture name" },
- { OSDOPTION_BGFX_LUT, "", OPTION_STRING, "LUT texture name" },
- { OSDOPTION_BGFX_AVI_NAME, OSDOPTVAL_AUTO, OPTION_STRING, "filename for BGFX output logging" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "OSD MIDI OPTIONS" },
+ { OSDOPTION_MIDI_PROVIDER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "MIDI I/O method: " },
+
+ { nullptr, nullptr, core_options::option_type::HEADER, "OSD EMULATED NETWORKING OPTIONS" },
+ { OSDOPTION_NETWORK_PROVIDER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "Emulated networking provider: " },
+
+ { nullptr, nullptr, core_options::option_type::HEADER, "BGFX POST-PROCESSING OPTIONS" },
+ { OSDOPTION_BGFX_PATH, "bgfx", core_options::option_type::PATH, "path to BGFX-related files" },
+ { OSDOPTION_BGFX_BACKEND, "auto", core_options::option_type::STRING, "BGFX backend to use (d3d9, d3d11, d3d12, metal, opengl, gles, vulkan)" },
+ { OSDOPTION_BGFX_DEBUG, "0", core_options::option_type::BOOLEAN, "enable BGFX debugging statistics" },
+ { OSDOPTION_BGFX_SCREEN_CHAINS, "", core_options::option_type::STRING, "comma-delimited list of screen chain JSON names, colon-delimited per-window" },
+ { OSDOPTION_BGFX_SHADOW_MASK, "slot-mask.png", core_options::option_type::STRING, "shadow mask texture name" },
+ { OSDOPTION_BGFX_LUT, "lut-default.png", core_options::option_type::STRING, "LUT texture name" },
+ { OSDOPTION_BGFX_AVI_NAME, OSDOPTVAL_AUTO, core_options::option_type::PATH, "filename for BGFX output logging" },
- // End of list
+ // End of list
{ nullptr }
};
@@ -170,7 +194,7 @@ osd_options::osd_options()
}
// Window list
-std::list<std::shared_ptr<osd_window>> osd_common_t::s_window_list;
+std::list<std::unique_ptr<osd_window> > osd_common_t::s_window_list;
//-------------------------------------------------
// osd_interface - constructor
@@ -184,6 +208,7 @@ osd_common_t::osd_common_t(osd_options &options)
, m_sound(nullptr)
, m_debugger(nullptr)
, m_midi(nullptr)
+ , m_network(nullptr)
, m_keyboard_input(nullptr)
, m_mouse_input(nullptr)
, m_lightgun_input(nullptr)
@@ -205,7 +230,7 @@ osd_common_t::~osd_common_t()
osd_output::pop(this);
}
-#define REGISTER_MODULE(_O, _X ) { extern const module_type _X; _O . register_module( _X ); }
+#define REGISTER_MODULE(O, X) { extern const module_type X; O.register_module(X); }
void osd_common_t::register_options()
{
@@ -215,6 +240,26 @@ void osd_common_t::register_options()
REGISTER_MODULE(m_mod_man, FONT_SDL);
REGISTER_MODULE(m_mod_man, FONT_NONE);
+#if defined(SDLMAME_EMSCRIPTEN)
+ REGISTER_MODULE(m_mod_man, RENDERER_SDL1); // don't bother trying to use video acceleration in browsers
+#endif
+#if defined(OSD_WINDOWS)
+ REGISTER_MODULE(m_mod_man, RENDERER_D3D); // this is only built for OSD=windows, there's no dummy stub
+#endif
+#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
+ REGISTER_MODULE(m_mod_man, RENDERER_BGFX); // try BGFX before GDI on windows to get DirectX 10/11 acceleration
+#endif
+ REGISTER_MODULE(m_mod_man, RENDERER_GDI); // GDI ahead of OpenGL as there's a chance Windows has no OpenGL
+ REGISTER_MODULE(m_mod_man, RENDERER_OPENGL);
+#if !defined(OSD_WINDOWS) && !defined(SDLMAME_WIN32)
+ REGISTER_MODULE(m_mod_man, RENDERER_BGFX); // try BGFX after OpenGL on other operating systems for now
+#endif
+ REGISTER_MODULE(m_mod_man, RENDERER_SDL2);
+#if !defined(SDLMAME_EMSCRIPTEN)
+ REGISTER_MODULE(m_mod_man, RENDERER_SDL1);
+#endif
+ REGISTER_MODULE(m_mod_man, RENDERER_NONE);
+
REGISTER_MODULE(m_mod_man, SOUND_DSOUND);
REGISTER_MODULE(m_mod_man, SOUND_XAUDIO2);
REGISTER_MODULE(m_mod_man, SOUND_COREAUDIO);
@@ -223,6 +268,12 @@ void osd_common_t::register_options()
#ifndef NO_USE_PORTAUDIO
REGISTER_MODULE(m_mod_man, SOUND_PORTAUDIO);
#endif
+#ifndef NO_USE_PULSEAUDIO
+ REGISTER_MODULE(m_mod_man, SOUND_PULSEAUDIO);
+#endif
+#ifndef NO_USE_PIPEWIRE
+ REGISTER_MODULE(m_mod_man, SOUND_PIPEWIRE);
+#endif
REGISTER_MODULE(m_mod_man, SOUND_NONE);
REGISTER_MODULE(m_mod_man, MONITOR_SDL);
@@ -254,7 +305,6 @@ void osd_common_t::register_options()
REGISTER_MODULE(m_mod_man, KEYBOARDINPUT_RAWINPUT);
REGISTER_MODULE(m_mod_man, KEYBOARDINPUT_DINPUT);
REGISTER_MODULE(m_mod_man, KEYBOARDINPUT_WIN32);
- REGISTER_MODULE(m_mod_man, KEYBOARDINPUT_UWP);
REGISTER_MODULE(m_mod_man, KEYBOARD_NONE);
REGISTER_MODULE(m_mod_man, MOUSEINPUT_SDL);
@@ -263,16 +313,17 @@ void osd_common_t::register_options()
REGISTER_MODULE(m_mod_man, MOUSEINPUT_WIN32);
REGISTER_MODULE(m_mod_man, MOUSE_NONE);
+ REGISTER_MODULE(m_mod_man, LIGHTGUNINPUT_SDL);
REGISTER_MODULE(m_mod_man, LIGHTGUN_X11);
REGISTER_MODULE(m_mod_man, LIGHTGUNINPUT_RAWINPUT);
REGISTER_MODULE(m_mod_man, LIGHTGUNINPUT_WIN32);
REGISTER_MODULE(m_mod_man, LIGHTGUN_NONE);
- REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_SDL);
+ REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_SDLGAME);
+ REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_SDLJOY);
REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_WINHYBRID);
REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_DINPUT);
REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_XINPUT);
- REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_UWP);
REGISTER_MODULE(m_mod_man, JOYSTICK_NONE);
REGISTER_MODULE(m_mod_man, OUTPUT_NONE);
@@ -282,95 +333,34 @@ void osd_common_t::register_options()
// after initialization we know which modules are supported
-
- const char *names[20];
- int num;
- std::vector<const char *> dnames;
-
- m_mod_man.get_module_names(OSD_MONITOR_PROVIDER, 20, &num, names);
- for (int i = 0; i < num; i++)
- dnames.push_back(names[i]);
- update_option(OSD_MONITOR_PROVIDER, dnames);
-
- m_mod_man.get_module_names(OSD_FONT_PROVIDER, 20, &num, names);
- dnames.clear();
- for (int i = 0; i < num; i++)
- dnames.push_back(names[i]);
- update_option(OSD_FONT_PROVIDER, dnames);
-
- m_mod_man.get_module_names(OSD_KEYBOARDINPUT_PROVIDER, 20, &num, names);
- dnames.clear();
- for (int i = 0; i < num; i++)
- dnames.push_back(names[i]);
- update_option(OSD_KEYBOARDINPUT_PROVIDER, dnames);
-
- m_mod_man.get_module_names(OSD_MOUSEINPUT_PROVIDER, 20, &num, names);
- dnames.clear();
- for (int i = 0; i < num; i++)
- dnames.push_back(names[i]);
- update_option(OSD_MOUSEINPUT_PROVIDER, dnames);
-
- m_mod_man.get_module_names(OSD_LIGHTGUNINPUT_PROVIDER, 20, &num, names);
- dnames.clear();
- for (int i = 0; i < num; i++)
- dnames.push_back(names[i]);
- update_option(OSD_LIGHTGUNINPUT_PROVIDER, dnames);
-
- m_mod_man.get_module_names(OSD_JOYSTICKINPUT_PROVIDER, 20, &num, names);
- dnames.clear();
- for (int i = 0; i < num; i++)
- dnames.push_back(names[i]);
- update_option(OSD_JOYSTICKINPUT_PROVIDER, dnames);
-
- m_mod_man.get_module_names(OSD_SOUND_PROVIDER, 20, &num, names);
- dnames.clear();
- for (int i = 0; i < num; i++)
- dnames.push_back(names[i]);
- update_option(OSD_SOUND_PROVIDER, dnames);
-
-#if 0
- // Register midi options and update options
- m_mod_man.get_module_names(OSD_MIDI_PROVIDER, 20, &num, names);
- dnames.clear();
- for (int i = 0; i < num; i++)
- dnames.push_back(names[i]);
- update_option(OSD_MIDI_PROVIDER, dnames);
-#endif
-
- // Register debugger options and update options
- m_mod_man.get_module_names(OSD_DEBUG_PROVIDER, 20, &num, names);
- dnames.clear();
- for (int i = 0; i < num; i++)
- dnames.push_back(names[i]);
- update_option(OSD_DEBUG_PROVIDER, dnames);
-
- m_mod_man.get_module_names(OSD_OUTPUT_PROVIDER, 20, &num, names);
- dnames.clear();
- for (int i = 0; i < num; i++)
- dnames.push_back(names[i]);
- update_option(OSD_OUTPUT_PROVIDER, dnames);
-
- // Register video options and update options
- video_options_add("none", nullptr);
- video_register();
- update_option(OSDOPTION_VIDEO, m_video_names);
+ update_option(OSD_FONT_PROVIDER, m_mod_man.get_module_names(OSD_FONT_PROVIDER));
+ update_option(OSD_RENDERER_PROVIDER, m_mod_man.get_module_names(OSD_RENDERER_PROVIDER));
+ update_option(OSD_SOUND_PROVIDER, m_mod_man.get_module_names(OSD_SOUND_PROVIDER));
+ update_option(OSD_MONITOR_PROVIDER, m_mod_man.get_module_names(OSD_MONITOR_PROVIDER));
+ update_option(OSD_KEYBOARDINPUT_PROVIDER, m_mod_man.get_module_names(OSD_KEYBOARDINPUT_PROVIDER));
+ update_option(OSD_MOUSEINPUT_PROVIDER, m_mod_man.get_module_names(OSD_MOUSEINPUT_PROVIDER));
+ update_option(OSD_LIGHTGUNINPUT_PROVIDER, m_mod_man.get_module_names(OSD_LIGHTGUNINPUT_PROVIDER));
+ update_option(OSD_JOYSTICKINPUT_PROVIDER, m_mod_man.get_module_names(OSD_JOYSTICKINPUT_PROVIDER));
+ update_option(OSD_MIDI_PROVIDER, m_mod_man.get_module_names(OSD_MIDI_PROVIDER));
+ update_option(OSD_NETDEV_PROVIDER, m_mod_man.get_module_names(OSD_NETDEV_PROVIDER));
+ update_option(OSD_DEBUG_PROVIDER, m_mod_man.get_module_names(OSD_DEBUG_PROVIDER));
+ update_option(OSD_OUTPUT_PROVIDER, m_mod_man.get_module_names(OSD_OUTPUT_PROVIDER));
}
-void osd_common_t::update_option(const std::string &key, std::vector<const char *> &values)
+void osd_common_t::update_option(const std::string &key, std::vector<std::string_view> const &values)
{
std::string current_value(m_options.description(key.c_str()));
std::string new_option_value("");
for (unsigned int index = 0; index < values.size(); index++)
{
- std::string t(values[index]);
if (new_option_value.length() > 0)
{
- if( index != (values.size()-1))
+ if (index != (values.size() - 1))
new_option_value.append(", ");
else
new_option_value.append(" or ");
}
- new_option_value.append(t);
+ new_option_value.append(values[index]);
}
m_option_descs[key] = current_value + new_option_value;
@@ -381,28 +371,28 @@ void osd_common_t::update_option(const std::string &key, std::vector<const char
//-------------------------------------------------
// output_callback - callback for osd_printf_...
//-------------------------------------------------
-void osd_common_t::output_callback(osd_output_channel channel, const char *msg, va_list args)
+void osd_common_t::output_callback(osd_output_channel channel, const util::format_argument_pack<char> &args)
{
switch (channel)
{
- case OSD_OUTPUT_CHANNEL_ERROR:
- case OSD_OUTPUT_CHANNEL_WARNING:
- vfprintf(stderr, msg, args);
- break;
- case OSD_OUTPUT_CHANNEL_INFO:
- case OSD_OUTPUT_CHANNEL_LOG:
- vfprintf(stdout, msg, args);
- break;
- case OSD_OUTPUT_CHANNEL_VERBOSE:
- if (verbose()) vfprintf(stdout, msg, args);
- break;
- case OSD_OUTPUT_CHANNEL_DEBUG:
+ case OSD_OUTPUT_CHANNEL_ERROR:
+ case OSD_OUTPUT_CHANNEL_WARNING:
+ util::stream_format(std::cerr, args);
+ break;
+ case OSD_OUTPUT_CHANNEL_INFO:
+ case OSD_OUTPUT_CHANNEL_LOG:
+ util::stream_format(std::cout, args);
+ break;
+ case OSD_OUTPUT_CHANNEL_VERBOSE:
+ if (verbose()) util::stream_format(std::cout, args);
+ break;
+ case OSD_OUTPUT_CHANNEL_DEBUG:
#ifdef MAME_DEBUG
- vfprintf(stdout, msg, args);
+ util::stream_format(std::cout, args);
#endif
- break;
- default:
- break;
+ break;
+ default:
+ break;
}
}
@@ -442,7 +432,7 @@ void osd_common_t::init(running_machine &machine)
m_machine = &machine;
- osd_options &options = downcast<osd_options &>(machine.options());
+ auto &options = downcast<osd_options &>(machine.options());
// extract the verbose printing option
if (options.verbose())
set_verbose(true);
@@ -478,9 +468,6 @@ void osd_common_t::update(bool skip_redraw)
//
if (m_watchdog != nullptr)
m_watchdog->reset();
-
- update_slider_list();
-
}
@@ -522,46 +509,65 @@ void osd_common_t::debugger_update()
}
-//-------------------------------------------------
-// update_audio_stream - update the stereo audio
-// stream
-//-------------------------------------------------
+bool osd_common_t::sound_external_per_channel_volume()
+{
+ return m_sound->external_per_channel_volume();
+}
-void osd_common_t::update_audio_stream(const int16_t *buffer, int samples_this_frame)
+bool osd_common_t::sound_split_streams_per_source()
{
- //
- // This method is called whenever the system has new audio data to stream.
- // It provides an array of stereo samples in L-R order which should be
- // output at the configured sample_rate.
- //
- m_sound->update_audio_stream(m_machine->video().throttled(), buffer,samples_this_frame);
+ return m_sound->split_streams_per_source();
}
+uint32_t osd_common_t::sound_get_generation()
+{
+ return m_sound->get_generation();
+}
-//-------------------------------------------------
-// set_mastervolume - set the system volume
-//-------------------------------------------------
+osd::audio_info osd_common_t::sound_get_information()
+{
+ return m_sound->get_information();
+}
-void osd_common_t::set_mastervolume(int attenuation)
+uint32_t osd_common_t::sound_stream_sink_open(uint32_t node, std::string name, uint32_t rate)
{
- //
- // Attenuation is the attenuation in dB (a negative number).
- // To convert from dB to a linear volume scale do the following:
- // volume = MAX_VOLUME;
- // while (attenuation++ < 0)
- // volume /= 1.122018454; // = (10 ^ (1/20)) = 1dB
- //
- if (m_sound != nullptr)
- m_sound->set_mastervolume(attenuation);
+ return m_sound->stream_sink_open(node, name, rate);
}
+uint32_t osd_common_t::sound_stream_source_open(uint32_t node, std::string name, uint32_t rate)
+{
+ return m_sound->stream_source_open(node, name, rate);
+}
+
+void osd_common_t::sound_stream_set_volumes(uint32_t id, const std::vector<float> &db)
+{
+ m_sound->stream_set_volumes(id, db);
+}
+
+void osd_common_t::sound_stream_close(uint32_t id)
+{
+ m_sound->stream_close(id);
+}
+
+void osd_common_t::sound_stream_sink_update(uint32_t id, const int16_t *buffer, int samples_this_frame)
+{
+ m_sound->stream_sink_update(id, buffer, samples_this_frame);
+}
+
+void osd_common_t::sound_stream_source_update(uint32_t id, int16_t *buffer, int samples_this_frame)
+{
+ m_sound->stream_source_update(id, buffer, samples_this_frame);
+}
+
+
+
//-------------------------------------------------
// customize_input_type_list - provide OSD
// additions/modifications to the input list
//-------------------------------------------------
-void osd_common_t::customize_input_type_list(simple_list<input_type_entry> &typelist)
+void osd_common_t::customize_input_type_list(std::vector<input_type_entry> &typelist)
{
//
// inptport.c defines some general purpose defaults for key and joystick bindings.
@@ -583,6 +589,31 @@ void osd_common_t::customize_input_type_list(simple_list<input_type_entry> &type
std::vector<ui::menu_item> osd_common_t::get_slider_list()
{
+ // check if any window has dirty sliders
+ bool dirty = false;
+ for (const auto &window : window_list())
+ {
+ if (window->has_renderer() && window->renderer().sliders_dirty())
+ {
+ dirty = true;
+ break;
+ }
+ }
+
+ if (dirty)
+ {
+ m_sliders.clear();
+
+ for (const auto &window : osd_common_t::window_list())
+ {
+ if (window->has_renderer())
+ {
+ std::vector<ui::menu_item> window_sliders = window->renderer().get_slider_list();
+ m_sliders.insert(m_sliders.end(), window_sliders.begin(), window_sliders.end());
+ }
+ }
+ }
+
return m_sliders;
}
@@ -607,28 +638,50 @@ bool osd_common_t::execute_command(const char *command)
{
if (strcmp(command, OSDCOMMAND_LIST_NETWORK_ADAPTERS) == 0)
{
- osd_module *om = select_module_options(options(), OSD_NETDEV_PROVIDER);
-
- if (om->probe())
+ auto &om = select_module_options<netdev_module>(OSD_NETDEV_PROVIDER);
+ auto const interfaces = om.list_devices();
+ if (interfaces.empty())
{
- om->init(options());
- osd_list_network_adapters();
- om->exit();
+ printf("No supported network interfaces were found\n");
}
+ else
+ {
+ printf("Available network interfaces:\n");
+ for (auto &entry : interfaces)
+ {
+ printf(" %.*s\n", int(entry.description.length()), entry.description.data());
+ }
+ }
+ dynamic_cast<osd_module &>(om).exit();
return true;
}
else if (strcmp(command, OSDCOMMAND_LIST_MIDI_DEVICES) == 0)
{
- osd_module *om = select_module_options(options(), OSD_MIDI_PROVIDER);
- midi_module *pm = select_module_options<midi_module *>(options(), OSD_MIDI_PROVIDER);
-
- if (om->probe())
+ auto &om = select_module_options<midi_module>(OSD_MIDI_PROVIDER);
+ auto const ports = om.list_midi_ports();
+ if (ports.empty())
+ {
+ printf("No MIDI ports were found\n");
+ }
+ else
{
- om->init(options());
- pm->list_midi_devices();
- om->exit();
+ printf("MIDI input ports:\n");
+ for (auto const &port : ports)
+ {
+ if (port.input)
+ printf(port.default_input ? "%s (default)\n" : "%s\n", port.name.c_str());
+ }
+
+ printf("\nMIDI output ports:\n");
+ for (auto const &port : ports)
+ {
+ if (port.output)
+ printf(port.default_output ? "%s (default)\n" : "%s\n", port.name.c_str());
+ }
}
+ dynamic_cast<osd_module &>(om).exit();
+
return true;
}
@@ -644,10 +697,10 @@ static void output_notifier_callback(const char *outname, int32_t value, void *p
void osd_common_t::init_subsystems()
{
// monitors have to be initialized before video init
- m_monitor_module = select_module_options<monitor_module *>(options(), OSD_MONITOR_PROVIDER);
- assert(m_monitor_module != nullptr);
- m_monitor_module->init(options());
+ m_monitor_module = &select_module_options<monitor_module>(OSD_MONITOR_PROVIDER);
+ // various modules depend on having a window handle
+ m_render = &select_module_options<render_module>(OSD_RENDERER_PROVIDER);
if (!video_init())
{
video_exit();
@@ -657,32 +710,24 @@ void osd_common_t::init_subsystems()
exit(-1);
}
- m_keyboard_input = select_module_options<input_module *>(options(), OSD_KEYBOARDINPUT_PROVIDER);
- m_mouse_input = select_module_options<input_module *>(options(), OSD_MOUSEINPUT_PROVIDER);
- m_lightgun_input = select_module_options<input_module *>(options(), OSD_LIGHTGUNINPUT_PROVIDER);
- m_joystick_input = select_module_options<input_module *>(options(), OSD_JOYSTICKINPUT_PROVIDER);
-
- m_font_module = select_module_options<font_module *>(options(), OSD_FONT_PROVIDER);
- m_sound = select_module_options<sound_module *>(options(), OSD_SOUND_PROVIDER);
- m_sound->m_sample_rate = options().sample_rate();
- m_sound->m_audio_latency = options().audio_latency();
+ m_keyboard_input = &select_module_options<input_module>(OSD_KEYBOARDINPUT_PROVIDER);
+ m_mouse_input = &select_module_options<input_module>(OSD_MOUSEINPUT_PROVIDER);
+ m_lightgun_input = &select_module_options<input_module>(OSD_LIGHTGUNINPUT_PROVIDER);
+ m_joystick_input = &select_module_options<input_module>(OSD_JOYSTICKINPUT_PROVIDER);
- m_debugger = select_module_options<debug_module *>(options(), OSD_DEBUG_PROVIDER);
+ m_font_module = &select_module_options<font_module>(OSD_FONT_PROVIDER);
+ m_sound = &select_module_options<sound_module>(OSD_SOUND_PROVIDER);
- select_module_options<netdev_module *>(options(), OSD_NETDEV_PROVIDER);
+ m_debugger = &select_module_options<debug_module>(OSD_DEBUG_PROVIDER);
- m_midi = select_module_options<midi_module *>(options(), OSD_MIDI_PROVIDER);
+ m_midi = &select_module_options<midi_module>(OSD_MIDI_PROVIDER);
- m_output = select_module_options<output_module *>(options(), OSD_OUTPUT_PROVIDER);
- m_output->set_machine(&machine());
- machine().output().set_notifier(nullptr, output_notifier_callback, this);
+ m_network = &select_module_options<netdev_module>(OSD_NETDEV_PROVIDER);
- m_mod_man.init(options());
+ m_output = &select_module_options<output_module>(OSD_OUTPUT_PROVIDER);
+ machine().output().set_global_notifier(output_notifier_callback, this);
input_init();
- // we need pause callbacks
- machine().add_notifier(MACHINE_NOTIFY_PAUSE, machine_notify_delegate(&osd_common_t::input_pause, this));
- machine().add_notifier(MACHINE_NOTIFY_RESUME, machine_notify_delegate(&osd_common_t::input_resume, this));
}
bool osd_common_t::video_init()
@@ -700,10 +745,6 @@ bool osd_common_t::no_sound()
return (strcmp(options().sound(),"none")==0) ? true : false;
}
-void osd_common_t::video_register()
-{
-}
-
bool osd_common_t::input_init()
{
m_keyboard_input->input_init(machine());
@@ -713,20 +754,12 @@ bool osd_common_t::input_init()
return true;
}
-void osd_common_t::input_pause()
+void osd_common_t::poll_input_modules(bool relative_reset)
{
- m_keyboard_input->pause();
- m_mouse_input->pause();
- m_lightgun_input->pause();
- m_joystick_input->pause();
-}
-
-void osd_common_t::input_resume()
-{
- m_keyboard_input->resume();
- m_mouse_input->resume();
- m_lightgun_input->resume();
- m_joystick_input->resume();
+ m_keyboard_input->poll_if_necessary(relative_reset);
+ m_mouse_input->poll_if_necessary(relative_reset);
+ m_lightgun_input->poll_if_necessary(relative_reset);
+ m_joystick_input->poll_if_necessary(relative_reset);
}
void osd_common_t::exit_subsystems()
@@ -744,13 +777,46 @@ void osd_common_t::window_exit()
void osd_common_t::osd_exit()
{
+ // destroy the renderers before shutting down their parent module
+ for (auto it = window_list().rbegin(); window_list().rend() != it; ++it)
+ (*it)->renderer_reset();
+
m_mod_man.exit();
exit_subsystems();
}
-void osd_common_t::video_options_add(const char *name, void *type)
+osd_font::ptr osd_common_t::font_alloc()
+{
+ return m_font_module->font_alloc();
+}
+
+bool osd_common_t::get_font_families(std::string const &font_path, std::vector<std::pair<std::string, std::string> > &result)
+{
+ return m_font_module->get_font_families(font_path, result);
+}
+
+std::unique_ptr<osd::midi_input_port> osd_common_t::create_midi_input(std::string_view name)
+{
+ return m_midi->create_input(name);
+}
+
+std::unique_ptr<osd::midi_output_port> osd_common_t::create_midi_output(std::string_view name)
+{
+ return m_midi->create_output(name);
+}
+
+std::vector<osd::midi_port_info> osd_common_t::list_midi_ports()
+{
+ return m_midi->list_midi_ports();
+}
+
+std::unique_ptr<osd::network_device> osd_common_t::open_network_device(int id, osd::network_handler &handler)
+{
+ return m_network->open_device(id, handler);
+}
+
+std::vector<osd::network_device_info> osd_common_t::list_network_devices()
{
- //m_video_options.add(name, type, false);
- m_video_names.push_back(name);
+ return m_network->list_devices();
}
diff --git a/src/osd/modules/lib/osdobj_common.h b/src/osd/modules/lib/osdobj_common.h
index 37e043f53ad..ff0d0b9a6dd 100644
--- a/src/osd/modules/lib/osdobj_common.h
+++ b/src/osd/modules/lib/osdobj_common.h
@@ -2,41 +2,48 @@
// copyright-holders:Aaron Giles
/***************************************************************************
- osdepend.h
+ osdobj_common.h
OS-dependent code interface.
*******************************************************************c********/
-
-#pragma once
-
#ifndef MAME_OSD_LIB_OSDOBJ_COMMON_H
#define MAME_OSD_LIB_OSDOBJ_COMMON_H
+#pragma once
+
+#include "osdcore.h"
#include "osdepend.h"
-#include "watchdog.h"
+
#include "modules/osdmodule.h"
-#include "modules/font/font_module.h"
-#include "modules/input/input_module.h"
-#include "modules/sound/sound_module.h"
-#include "modules/debugger/debug_module.h"
-#include "modules/netdev/netdev_module.h"
-#include "modules/midi/midi_module.h"
#include "modules/output/output_module.h"
-#include "modules/monitor/monitor_module.h"
+
#include "emuopts.h"
-#include "../frontend/mame/ui/menuitem.h"
+
+#include "strformat.h"
+
+#include <iosfwd>
+#include <list>
+#include <memory>
+#include <string>
+#include <string_view>
+#include <unordered_map>
+#include <vector>
+
//============================================================
// Defines
//============================================================
#define OSDOPTION_UIMODEKEY "uimodekey"
+#define OSDOPTION_CONTROLLER_MAP_FILE "controller_map"
+#define OSDOPTION_BACKGROUND_INPUT "background_input"
#define OSDCOMMAND_LIST_MIDI_DEVICES "listmidi"
#define OSDCOMMAND_LIST_NETWORK_ADAPTERS "listnetwork"
#define OSDOPTION_DEBUGGER "debugger"
+#define OSDOPTION_DEBUGGER_HOST "debugger_host"
#define OSDOPTION_DEBUGGER_PORT "debugger_port"
#define OSDOPTION_DEBUGGER_FONT "debugger_font"
#define OSDOPTION_DEBUGGER_FONT_SIZE "debugger_font_size"
@@ -81,8 +88,9 @@
#define OSDOPTION_AUDIO_OUTPUT "audio_output"
#define OSDOPTION_AUDIO_EFFECT "audio_effect"
-#define OSDOPTVAL_AUTO "auto"
-#define OSDOPTVAL_NONE "none"
+#define OSDOPTION_MIDI_PROVIDER "midiprovider"
+
+#define OSDOPTION_NETWORK_PROVIDER "networkprovider"
#define OSDOPTION_BGFX_PATH "bgfx_path"
#define OSDOPTION_BGFX_BACKEND "bgfx_backend"
@@ -92,6 +100,9 @@
#define OSDOPTION_BGFX_LUT "bgfx_lut"
#define OSDOPTION_BGFX_AVI_NAME "bgfx_avi_name"
+#define OSDOPTVAL_AUTO "auto"
+#define OSDOPTVAL_NONE "none"
+
//============================================================
// TYPE DEFINITIONS
//============================================================
@@ -104,9 +115,12 @@ public:
// keyboard mapping
const char *ui_mode_key() const { return value(OSDOPTION_UIMODEKEY); }
+ const char *controller_mapping_file() const { return value(OSDOPTION_CONTROLLER_MAP_FILE); }
+ bool background_input() const { return bool_value(OSDOPTION_BACKGROUND_INPUT); }
// debugging options
const char *debugger() const { return value(OSDOPTION_DEBUGGER); }
+ const char *debugger_host() const { return value(OSDOPTION_DEBUGGER_HOST); }
int debugger_port() const { return int_value(OSDOPTION_DEBUGGER_PORT); }
const char *debugger_font() const { return value(OSDOPTION_DEBUGGER_FONT); }
float debugger_font_size() const { return float_value(OSDOPTION_DEBUGGER_FONT_SIZE); }
@@ -129,10 +143,10 @@ public:
const char *aspect() const { return value(OSDOPTION_ASPECT); }
const char *resolution() const { return value(OSDOPTION_RESOLUTION); }
const char *view() const { return value(OSDOPTION_VIEW); }
- const char *screen(int index) const { return value(string_format("%s%d", OSDOPTION_SCREEN, index).c_str()); }
- const char *aspect(int index) const { return value(string_format("%s%d", OSDOPTION_ASPECT, index).c_str()); }
- const char *resolution(int index) const { return value(string_format("%s%d", OSDOPTION_RESOLUTION, index).c_str()); }
- const char *view(int index) const { return value(string_format("%s%d", OSDOPTION_VIEW, index).c_str()); }
+ const char *screen(int index) const { return value(util::string_format("%s%d", OSDOPTION_SCREEN, index)); }
+ const char *aspect(int index) const { return value(util::string_format("%s%d", OSDOPTION_ASPECT, index)); }
+ const char *resolution(int index) const { return value(util::string_format("%s%d", OSDOPTION_RESOLUTION, index)); }
+ const char *view(int index) const { return value(util::string_format("%s%d", OSDOPTION_VIEW, index)); }
// full screen options
bool switch_res() const { return bool_value(OSDOPTION_SWITCHRES); }
@@ -148,8 +162,8 @@ public:
bool gl_pbo() const { return bool_value(OSDOPTION_GL_PBO); }
bool gl_glsl() const { return bool_value(OSDOPTION_GL_GLSL); }
int glsl_filter() const { return int_value(OSDOPTION_GLSL_FILTER); }
- const char *shader_mame(int index) const { return value(string_format("%s%d", OSDOPTION_SHADER_MAME, index).c_str()); }
- const char *shader_screen(int index) const { return value(string_format("%s%d", OSDOPTION_SHADER_SCREEN, index).c_str()); }
+ const char *shader_mame(int index) const { return value(util::string_format("%s%d", OSDOPTION_SHADER_MAME, index)); }
+ const char *shader_screen(int index) const { return value(util::string_format("%s%d", OSDOPTION_SHADER_SCREEN, index)); }
// sound options
const char *sound() const { return value(OSDOPTION_SOUND); }
@@ -157,7 +171,7 @@ public:
// CoreAudio specific options
const char *audio_output() const { return value(OSDOPTION_AUDIO_OUTPUT); }
- const char *audio_effect(int index) const { return value(string_format("%s%d", OSDOPTION_AUDIO_EFFECT, index).c_str()); }
+ const char *audio_effect(int index) const { return value(util::string_format("%s%d", OSDOPTION_AUDIO_EFFECT, index)); }
// BGFX specific options
const char *bgfx_path() const { return value(OSDOPTION_BGFX_PATH); }
@@ -171,13 +185,24 @@ public:
// PortAudio options
const char *pa_api() const { return value(OSDOPTION_PA_API); }
const char *pa_device() const { return value(OSDOPTION_PA_DEVICE); }
- const float pa_latency() const { return float_value(OSDOPTION_PA_LATENCY); }
+ float pa_latency() const { return float_value(OSDOPTION_PA_LATENCY); }
static const options_entry s_option_entries[];
};
// ======================> osd_interface
+
+class debug_module;
+class font_module;
+class input_module;
+class midi_module;
+class monitor_module;
+class netdev_module;
+class osd_watchdog;
class osd_window;
+class output_module;
+class render_module;
+class sound_module;
// description of the currently-running machine
class osd_common_t : public osd_interface, osd_output
@@ -199,24 +224,40 @@ public:
virtual void wait_for_debugger(device_t &device, bool firststop) override;
// audio overridables
- virtual void update_audio_stream(const int16_t *buffer, int samples_this_frame) override;
- virtual void set_mastervolume(int attenuation) override;
virtual bool no_sound() override;
+ virtual bool sound_external_per_channel_volume() override;
+ virtual bool sound_split_streams_per_source() override;
+ virtual uint32_t sound_get_generation() override;
+ virtual osd::audio_info sound_get_information() override;
+ virtual uint32_t sound_stream_sink_open(uint32_t node, std::string name, uint32_t rate) override;
+ virtual uint32_t sound_stream_source_open(uint32_t node, std::string name, uint32_t rate) override;
+ virtual void sound_stream_set_volumes(uint32_t id, const std::vector<float> &db) override;
+ virtual void sound_stream_close(uint32_t id) override;
+ virtual void sound_stream_sink_update(uint32_t id, const int16_t *buffer, int samples_this_frame) override;
+ virtual void sound_stream_source_update(uint32_t id, int16_t *buffer, int samples_this_frame) override;
// input overridables
- virtual void customize_input_type_list(simple_list<input_type_entry> &typelist) override;
+ virtual void customize_input_type_list(std::vector<input_type_entry> &typelist) override;
// video overridables
virtual void add_audio_to_recording(const int16_t *buffer, int samples_this_frame) override;
virtual std::vector<ui::menu_item> get_slider_list() override;
+ // font interface
+ virtual osd_font::ptr font_alloc() override;
+ virtual bool get_font_families(std::string const &font_path, std::vector<std::pair<std::string, std::string> > &result) override;
+
// command option overrides
virtual bool execute_command(const char *command) override;
- virtual osd_font::ptr font_alloc() override { return m_font_module->font_alloc(); }
- virtual bool get_font_families(std::string const &font_path, std::vector<std::pair<std::string, std::string> > &result) override { return m_font_module->get_font_families(font_path, result); }
+ // MIDI interface
+ virtual std::unique_ptr<osd::midi_input_port> create_midi_input(std::string_view name) override;
+ virtual std::unique_ptr<osd::midi_output_port> create_midi_output(std::string_view name) override;
+ virtual std::vector<osd::midi_port_info> list_midi_ports() override;
- virtual osd_midi_device *create_midi_device() override { return m_midi->create_midi_device(); }
+ // network interface
+ virtual std::unique_ptr<osd::network_device> open_network_device(int id, osd::network_handler &handler) override;
+ virtual std::vector<osd::network_device_info> list_network_devices() override;
// FIXME: everything below seems to be osd specific and not part of
// this INTERFACE but part of the osd IMPLEMENTATION
@@ -229,36 +270,34 @@ public:
virtual void init_subsystems();
virtual bool video_init();
- virtual void video_register();
virtual bool window_init();
- virtual void input_resume();
-
virtual void exit_subsystems();
virtual void video_exit();
virtual void window_exit();
virtual void osd_exit();
- virtual void video_options_add(const char *name, void *type);
-
virtual osd_options &options() { return m_options; }
// osd_output interface ...
- virtual void output_callback(osd_output_channel channel, const char *msg, va_list args) override;
+ virtual void output_callback(osd_output_channel channel, const util::format_argument_pack<char> &args) override;
bool verbose() const { return m_print_verbose; }
virtual void set_verbose(bool print_verbose) override { m_print_verbose = print_verbose; }
void notify(const char *outname, int32_t value) const { m_output->notify(outname, value); }
- static std::list<std::shared_ptr<osd_window>> s_window_list;
+ virtual void process_events() = 0;
+ virtual bool has_focus() const = 0;
+
+ static const std::list<std::unique_ptr<osd_window> > &window_list() { return s_window_list; }
protected:
virtual bool input_init();
- virtual void input_pause();
- virtual void build_slider_list() { }
- virtual void update_slider_list() { }
+ void poll_input_modules(bool relative_reset);
+
+ static std::list<std::unique_ptr<osd_window> > s_window_list;
private:
// internal state
@@ -270,31 +309,30 @@ private:
osd_module_manager m_mod_man;
font_module *m_font_module;
- void update_option(const std::string &key, std::vector<const char *> &values);
+ void update_option(const std::string &key, std::vector<std::string_view> const &values);
// FIXME: should be elsewhere
- osd_module *select_module_options(const core_options &opts, const std::string &opt_name)
+ template<class C>
+ C &select_module_options(const std::string &opt_name)
{
- std::string opt_val = opts.exists(opt_name) ? opts.value(opt_name.c_str()) : "";
- if (opt_val.compare("auto")==0)
+ std::string opt_val = options().exists(opt_name) ? options().value(opt_name) : "";
+ if (opt_val == "auto")
+ {
opt_val = "";
+ }
else if (!m_mod_man.type_has_name(opt_name.c_str(), opt_val.c_str()))
{
- osd_printf_warning("Value %s not supported for option %s - falling back to auto\n", opt_val.c_str(), opt_name.c_str());
+ osd_printf_warning("Value %s not supported for option %s - falling back to auto\n", opt_val, opt_name);
opt_val = "";
}
- return m_mod_man.select_module(opt_name.c_str(), opt_val.c_str());
- }
-
- template<class C>
- C select_module_options(const core_options &opts, const std::string &opt_name)
- {
- return dynamic_cast<C>(select_module_options(opts, opt_name));
+ return m_mod_man.select_module<C>(*this, options(), opt_name.c_str(), opt_val.c_str());
}
protected:
+ render_module* m_render;
sound_module* m_sound;
debug_module* m_debugger;
midi_module* m_midi;
+ netdev_module* m_network;
input_module* m_keyboard_input;
input_module* m_mouse_input;
input_module* m_lightgun_input;
@@ -305,16 +343,7 @@ protected:
std::vector<ui::menu_item> m_sliders;
private:
- std::vector<const char *> m_video_names;
std::unordered_map<std::string, std::string> m_option_descs;
};
-
-// this template function creates a stub which constructs a debugger
-template<class _DeviceClass>
-debug_module *osd_debugger_creator()
-{
- return global_alloc(_DeviceClass());
-}
-
#endif // MAME_OSD_LIB_OSDOBJ_COMMON_H
diff --git a/src/osd/modules/midi/midi_module.h b/src/osd/modules/midi/midi_module.h
index 6c50cdd3edc..61eef311aa6 100644
--- a/src/osd/modules/midi/midi_module.h
+++ b/src/osd/modules/midi/midi_module.h
@@ -4,12 +4,18 @@
* midi_module.h
*
*/
+#ifndef MAME_OSD_MODULES_MIDI_MIDI_MODULE_H
+#define MAME_OSD_MODULES_MIDI_MIDI_MODULE_H
-#ifndef MIDI_MODULE_H_
-#define MIDI_MODULE_H_
+#pragma once
+
+#include "interface/midiport.h"
+
+#include <memory>
+#include <string>
+#include <string_view>
+#include <vector>
-#include "osdepend.h"
-#include "modules/osdmodule.h"
//============================================================
// CONSTANTS
@@ -20,13 +26,13 @@
class midi_module
{
public:
- virtual ~midi_module() { }
+ virtual ~midi_module() = default;
+
// specific routines
- virtual osd_midi_device *create_midi_device() = 0;
- // FIXME: should return a list of strings ...
- virtual void list_midi_devices(void) = 0;
+ virtual std::unique_ptr<osd::midi_input_port> create_input(std::string_view name) = 0;
+ virtual std::unique_ptr<osd::midi_output_port> create_output(std::string_view name) = 0;
+ virtual std::vector<osd::midi_port_info> list_midi_ports() = 0;
};
-
-#endif /* MIDI_MODULE_H_ */
+#endif // MAME_OSD_MODULES_MIDI_MIDI_MODULE_H
diff --git a/src/osd/modules/midi/none.cpp b/src/osd/modules/midi/none.cpp
index adacee7d634..2a50bf71a84 100644
--- a/src/osd/modules/midi/none.cpp
+++ b/src/osd/modules/midi/none.cpp
@@ -6,89 +6,36 @@
Empty shim for systems not supporting midi / portmidi
-*******************************************************************c********/
+***************************************************************************/
-#include "osdcore.h"
-#include "corealloc.h"
-#include "modules/osdmodule.h"
#include "midi_module.h"
-class none_module : public osd_module, public midi_module
-{
-public:
+#include "modules/osdmodule.h"
+#include "osdcore.h"
- none_module()
- : osd_module(OSD_MIDI_PROVIDER, "pm"), midi_module()
- {
- }
- virtual ~none_module() { }
+#include <memory>
- virtual int init(const osd_options &options) override;
- virtual void exit() override;
- virtual osd_midi_device *create_midi_device() override;
- virtual void list_midi_devices(void) override;
-};
+namespace osd {
+namespace {
-class osd_midi_device_none : public osd_midi_device
+class none_module : public osd_module, public midi_module
{
public:
- virtual ~osd_midi_device_none() { }
- virtual bool open_input(const char *devname) override;
- virtual bool open_output(const char *devname) override;
- virtual void close() override;
- virtual bool poll() override;
- virtual int read(uint8_t *pOut) override;
- virtual void write(uint8_t data) override;
-};
+ none_module() : osd_module(OSD_MIDI_PROVIDER, "none"), midi_module() { }
-osd_midi_device *none_module::create_midi_device()
-{
- return global_alloc(osd_midi_device_none());
-}
-
-
-int none_module::init(const osd_options &options)
-{
- return 0;
-}
+ virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
+ virtual void exit() override { }
-void none_module::exit()
-{
-}
-
-void none_module::list_midi_devices(void)
-{
- osd_printf_warning("\nMIDI is not supported in this build\n");
-}
-
-bool osd_midi_device_none::open_input(const char *devname)
-{
- return false;
-}
-
-bool osd_midi_device_none::open_output(const char *devname)
-{
- return false;
-}
-
-void osd_midi_device_none::close()
-{
-}
+ virtual std::unique_ptr<midi_input_port> create_input(std::string_view name) override { return nullptr; }
+ virtual std::unique_ptr<midi_output_port> create_output(std::string_view name) override { return nullptr; }
+ virtual std::vector<osd::midi_port_info> list_midi_ports() override { return std::vector<osd::midi_port_info>(); }
+};
-bool osd_midi_device_none::poll()
-{
- return false;
-}
+} // anonymous namespace
-int osd_midi_device_none::read(uint8_t *pOut)
-{
- return 0;
-}
+} // namespace osd
-void osd_midi_device_none::write(uint8_t data)
-{
-}
-MODULE_DEFINITION(MIDI_NONE, none_module)
+MODULE_DEFINITION(MIDI_NONE, osd::none_module)
diff --git a/src/osd/modules/midi/portmidi.cpp b/src/osd/modules/midi/portmidi.cpp
index 418295a7a5c..07372af1469 100644
--- a/src/osd/modules/midi/portmidi.cpp
+++ b/src/osd/modules/midi/portmidi.cpp
@@ -2,72 +2,88 @@
// copyright-holders:R. Belmont
/***************************************************************************
- portmap.c
+ portmidi.cpp
Midi implementation based on portmidi library
*******************************************************************c********/
+#include "midi_module.h"
+
+#include "modules/osdmodule.h"
+
#ifndef NO_USE_MIDI
+#include "interface/midiport.h"
+#include "osdcore.h" // osd_printf_*
+
#include <portmidi.h>
-#include "osdcore.h"
-#include "corealloc.h"
-#include "modules/osdmodule.h"
-#include "midi_module.h"
+
+#include <cstdio>
+#include <cstring>
+
+
+namespace osd {
+
+namespace {
class pm_module : public osd_module, public midi_module
{
public:
- pm_module()
- : osd_module(OSD_MIDI_PROVIDER, "pm"), midi_module()
+ pm_module() : osd_module(OSD_MIDI_PROVIDER, "pm"), midi_module()
{
}
virtual ~pm_module() { }
- virtual int init(const osd_options &options)override;
- virtual void exit()override;
+ virtual int init(osd_interface &osd, const osd_options &options) override;
+ virtual void exit() override;
- virtual osd_midi_device *create_midi_device() override;
- virtual void list_midi_devices(void) override;
+ virtual std::unique_ptr<midi_input_port> create_input(std::string_view name) override;
+ virtual std::unique_ptr<midi_output_port> create_output(std::string_view name) override;
+ virtual std::vector<osd::midi_port_info> list_midi_ports() override;
};
-static const int RX_EVENT_BUF_SIZE = 512;
+static constexpr unsigned RX_EVENT_BUF_SIZE = 512;
-#define MIDI_SYSEX 0xf0
-#define MIDI_EOX 0xf7
+static constexpr uint8_t MIDI_SYSEX = 0xf0;
+static constexpr uint8_t MIDI_EOX = 0xf7;
-class osd_midi_device_pm : public osd_midi_device
+class midi_input_pm : public midi_input_port
{
public:
- osd_midi_device_pm(): pmStream(nullptr), xmit_cnt(0), last_status(0), rx_sysex(false) { }
- virtual ~osd_midi_device_pm() { }
- virtual bool open_input(const char *devname) override;
- virtual bool open_output(const char *devname) override;
- virtual void close() override;
+ midi_input_pm(PortMidiStream *stream) : m_stream(stream), m_rx_sysex(false) { }
+ virtual ~midi_input_pm();
+
virtual bool poll() override;
virtual int read(uint8_t *pOut) override;
- virtual void write(uint8_t data) override;
private:
- PortMidiStream *pmStream;
- PmEvent rx_evBuf[RX_EVENT_BUF_SIZE];
- uint8_t xmit_in[4]; // Pm_Messages mean we can at most have 3 residue bytes
- int xmit_cnt;
- uint8_t last_status;
- bool rx_sysex;
+ PortMidiStream *const m_stream;
+ PmEvent m_evbuf[RX_EVENT_BUF_SIZE];
+ bool m_rx_sysex;
};
-osd_midi_device *pm_module::create_midi_device()
+class midi_output_pm : public midi_output_port
{
- return global_alloc(osd_midi_device_pm());
-}
+public:
+ midi_output_pm(PortMidiStream *stream) : m_stream(stream), m_xmit_cnt(0), m_last_status(0) { }
+ virtual ~midi_output_pm();
+
+ virtual void write(uint8_t data) override;
+private:
+ PortMidiStream *const m_stream;
+ uint8_t m_xmit_in[4]; // Pm_Messages mean we can at most have 3 residue bytes
+ int m_xmit_cnt;
+ uint8_t m_last_status;
+};
-int pm_module::init(const osd_options &options)
+
+int pm_module::init(osd_interface &osd, const osd_options &options)
{
+ // FIXME: check error return code
Pm_Initialize();
return 0;
}
@@ -77,151 +93,126 @@ void pm_module::exit()
Pm_Terminate();
}
-void pm_module::list_midi_devices(void)
+std::unique_ptr<midi_input_port> pm_module::create_input(std::string_view name)
{
- int num_devs = Pm_CountDevices();
- const PmDeviceInfo *pmInfo;
-
- printf("\n");
-
- if (num_devs == 0)
+ int found_dev = -1;
+ if (name == "default")
{
- printf("No MIDI ports were found\n");
- return;
+ found_dev = Pm_GetDefaultInputDeviceID();
}
-
- printf("MIDI input ports:\n");
- for (int i = 0; i < num_devs; i++)
+ else
{
- pmInfo = Pm_GetDeviceInfo(i);
-
- if (pmInfo->input)
+ int const num_devs = Pm_CountDevices();
+ for (found_dev = 0; num_devs > found_dev; ++found_dev)
{
- printf("%s %s\n", pmInfo->name, (i == Pm_GetDefaultInputDeviceID()) ? "(default)" : "");
+ auto const info = Pm_GetDeviceInfo(found_dev);
+ if (info->input && (name == info->name))
+ break;
}
+ if (num_devs <= found_dev)
+ found_dev = -1;
}
- printf("\nMIDI output ports:\n");
- for (int i = 0; i < num_devs; i++)
+ if (0 > found_dev)
{
- pmInfo = Pm_GetDeviceInfo(i);
-
- if (pmInfo->output)
- {
- printf("%s %s\n", pmInfo->name, (i == Pm_GetDefaultOutputDeviceID()) ? "(default)" : "");
- }
+ osd_printf_warning("No MIDI input device named '%s' was found.\n", name);
+ return nullptr;
}
-}
-bool osd_midi_device_pm::open_input(const char *devname)
-{
- int num_devs = Pm_CountDevices();
- int found_dev = -1;
- const PmDeviceInfo *pmInfo;
- PortMidiStream *stm;
-
- if (!strcmp("default", devname))
- {
- found_dev = Pm_GetDefaultInputDeviceID();
- }
- else
+ PortMidiStream *stream = nullptr;
+ PmError const err = Pm_OpenInput(&stream, found_dev, nullptr, RX_EVENT_BUF_SIZE, nullptr, nullptr);
+ if (pmNoError != err)
{
- for (int i = 0; i < num_devs; i++)
- {
- pmInfo = Pm_GetDeviceInfo(i);
-
- if (pmInfo->input)
- {
- if (!strcmp(devname, pmInfo->name))
- {
- found_dev = i;
- break;
- }
- }
- }
+ osd_printf_error("Error opening PortMidi device '%s' for input.\n", name);
+ return nullptr;
}
- if (found_dev >= 0)
+ try
{
- if (Pm_OpenInput(&stm, found_dev, nullptr, RX_EVENT_BUF_SIZE, nullptr, nullptr) == pmNoError)
- {
- pmStream = stm;
- return true;
- }
- else
- {
- printf("Couldn't open PM device\n");
- return false;
- }
+ return std::make_unique<midi_input_pm>(stream);
}
- else
+ catch (...)
{
- return false;
+ Pm_Close(stream);
+ return nullptr;
}
}
-bool osd_midi_device_pm::open_output(const char *devname)
+std::unique_ptr<midi_output_port> pm_module::create_output(std::string_view name)
{
- int num_devs = Pm_CountDevices();
int found_dev = -1;
- const PmDeviceInfo *pmInfo;
- PortMidiStream *stm;
-
- if (!strcmp("default", devname))
+ if (name == "default")
{
found_dev = Pm_GetDefaultOutputDeviceID();
}
else
{
- for (int i = 0; i < num_devs; i++)
+ int const num_devs = Pm_CountDevices();
+ for (found_dev = 0; num_devs > found_dev; ++found_dev)
{
- pmInfo = Pm_GetDeviceInfo(i);
-
- if (pmInfo->output)
- {
- if (!strcmp(devname, pmInfo->name))
- {
- found_dev = i;
- break;
- }
- }
+ auto const info = Pm_GetDeviceInfo(found_dev);
+ if (info->output && (name == info->name))
+ break;
}
+ if (num_devs <= found_dev)
+ found_dev = -1;
}
- if (found_dev >= 0)
+ PortMidiStream *stream = nullptr;
+ PmError const err = Pm_OpenOutput(&stream, found_dev, nullptr, 100, nullptr, nullptr, 0);
+ if (pmNoError != err)
{
- if (Pm_OpenOutput(&stm, found_dev, nullptr, 100, nullptr, nullptr, 0) == pmNoError)
- {
- pmStream = stm;
- return true;
- }
- else
- {
- printf("Couldn't open PM device\n");
- return false;
- }
+ osd_printf_error("Error opening PortMidi device '%s' for output.\n", name);
+ return nullptr;
}
- else
+
+ try
{
- return false;
+ return std::make_unique<midi_output_pm>(stream);
+ }
+ catch (...)
+ {
+ Pm_Close(stream);
+ return nullptr;
}
}
-void osd_midi_device_pm::close()
+std::vector<osd::midi_port_info> pm_module::list_midi_ports()
{
- Pm_Close(pmStream);
+ int const num_devs = Pm_CountDevices();
+ int const def_input = Pm_GetDefaultInputDeviceID();
+ int const def_output = Pm_GetDefaultOutputDeviceID();
+ std::vector<osd::midi_port_info> result;
+ result.reserve(num_devs);
+ for (int i = 0; num_devs > i; ++i)
+ {
+ auto const pm_info = Pm_GetDeviceInfo(i);
+ result.emplace_back(osd::midi_port_info{
+ pm_info->name,
+ 0 != pm_info->input,
+ 0 != pm_info->output,
+ def_input == i,
+ def_output == i });
+ }
+ return result;
}
-bool osd_midi_device_pm::poll()
+
+midi_input_pm::~midi_input_pm()
{
- PmError chk = Pm_Poll(pmStream);
+ if (m_stream)
+ Pm_Close(m_stream);
+}
+bool midi_input_pm::poll()
+{
+ PmError const chk = Pm_Poll(m_stream);
return (chk == pmGotData) ? true : false;
}
-int osd_midi_device_pm::read(uint8_t *pOut)
+int midi_input_pm::read(uint8_t *pOut)
{
- int msgsRead = Pm_Read(pmStream, rx_evBuf, RX_EVENT_BUF_SIZE);
+ int msgsRead = Pm_Read(m_stream, m_evbuf, RX_EVENT_BUF_SIZE);
int bytesOut = 0;
if (msgsRead <= 0)
@@ -231,23 +222,23 @@ int osd_midi_device_pm::read(uint8_t *pOut)
for (int msg = 0; msg < msgsRead; msg++)
{
- uint8_t status = Pm_MessageStatus(rx_evBuf[msg].message);
+ uint8_t status = Pm_MessageStatus(m_evbuf[msg].message);
- if (rx_sysex)
+ if (m_rx_sysex)
{
if (status & 0x80) // sys real-time imposing on us?
{
if (status == 0xf2)
{
*pOut++ = status;
- *pOut++ = Pm_MessageData1(rx_evBuf[msg].message);
- *pOut++ = Pm_MessageData2(rx_evBuf[msg].message);
+ *pOut++ = Pm_MessageData1(m_evbuf[msg].message);
+ *pOut++ = Pm_MessageData2(m_evbuf[msg].message);
bytesOut += 3;
}
else if (status == 0xf3)
{
*pOut++ = status;
- *pOut++ = Pm_MessageData1(rx_evBuf[msg].message);
+ *pOut++ = Pm_MessageData1(m_evbuf[msg].message);
bytesOut += 2;
}
else
@@ -256,7 +247,7 @@ int osd_midi_device_pm::read(uint8_t *pOut)
bytesOut++;
if (status == MIDI_EOX)
{
- rx_sysex = false;
+ m_rx_sysex = false;
}
}
}
@@ -264,15 +255,15 @@ int osd_midi_device_pm::read(uint8_t *pOut)
{
for (int i = 0; i < 4; i++)
{
- uint8_t byte = rx_evBuf[msg].message & 0xff;
+ uint8_t byte = m_evbuf[msg].message & 0xff;
*pOut++ = byte;
bytesOut++;
if (byte == MIDI_EOX)
{
- rx_sysex = false;
+ m_rx_sysex = false;
break;
}
- rx_evBuf[msg].message >>= 8;
+ m_evbuf[msg].message >>= 8;
}
}
}
@@ -283,7 +274,7 @@ int osd_midi_device_pm::read(uint8_t *pOut)
case 0xc: // 2-byte messages
case 0xd:
*pOut++ = status;
- *pOut++ = Pm_MessageData1(rx_evBuf[msg].message);
+ *pOut++ = Pm_MessageData1(m_evbuf[msg].message);
bytesOut += 2;
break;
@@ -293,30 +284,30 @@ int osd_midi_device_pm::read(uint8_t *pOut)
case 0: // System Exclusive
{
*pOut++ = status; // this should be OK: the shortest legal sysex is F0 tt dd F7, I believe
- *pOut++ = (rx_evBuf[msg].message>>8) & 0xff;
- *pOut++ = (rx_evBuf[msg].message>>16) & 0xff;
- uint8_t last = *pOut++ = (rx_evBuf[msg].message>>24) & 0xff;
+ *pOut++ = (m_evbuf[msg].message>>8) & 0xff;
+ *pOut++ = (m_evbuf[msg].message>>16) & 0xff;
+ uint8_t last = *pOut++ = (m_evbuf[msg].message>>24) & 0xff;
bytesOut += 4;
- rx_sysex = (last != MIDI_EOX);
+ m_rx_sysex = (last != MIDI_EOX);
break;
}
case 7: // End of System Exclusive
*pOut++ = status;
bytesOut += 1;
- rx_sysex = false;
+ m_rx_sysex = false;
break;
case 2: // song pos
*pOut++ = status;
- *pOut++ = Pm_MessageData1(rx_evBuf[msg].message);
- *pOut++ = Pm_MessageData2(rx_evBuf[msg].message);
+ *pOut++ = Pm_MessageData1(m_evbuf[msg].message);
+ *pOut++ = Pm_MessageData2(m_evbuf[msg].message);
bytesOut += 3;
break;
case 3: // song select
*pOut++ = status;
- *pOut++ = Pm_MessageData1(rx_evBuf[msg].message);
+ *pOut++ = Pm_MessageData1(m_evbuf[msg].message);
bytesOut += 2;
break;
@@ -329,8 +320,8 @@ int osd_midi_device_pm::read(uint8_t *pOut)
default:
*pOut++ = status;
- *pOut++ = Pm_MessageData1(rx_evBuf[msg].message);
- *pOut++ = Pm_MessageData2(rx_evBuf[msg].message);
+ *pOut++ = Pm_MessageData1(m_evbuf[msg].message);
+ *pOut++ = Pm_MessageData2(m_evbuf[msg].message);
bytesOut += 3;
break;
}
@@ -340,57 +331,64 @@ int osd_midi_device_pm::read(uint8_t *pOut)
return bytesOut;
}
-void osd_midi_device_pm::write(uint8_t data)
+
+midi_output_pm::~midi_output_pm()
+{
+ if (m_stream)
+ Pm_Close(m_stream);
+}
+
+void midi_output_pm::write(uint8_t data)
{
int bytes_needed = 0;
PmEvent ev;
ev.timestamp = 0; // use the current time
-// printf("write: %02x (%d)\n", data, xmit_cnt);
+// printf("write: %02x (%d)\n", data, m_xmit_cnt);
// reject data bytes when no valid status exists
- if ((last_status == 0) && !(data & 0x80))
+ if ((m_last_status == 0) && !(data & 0x80))
{
- xmit_cnt = 0;
+ m_xmit_cnt = 0;
return;
}
- if (xmit_cnt >= 4)
+ if (m_xmit_cnt >= 4)
{
printf("MIDI out: packet assembly overflow, contact MAMEdev!\n");
return;
}
// handle sysex
- if (last_status == MIDI_SYSEX)
+ if (m_last_status == MIDI_SYSEX)
{
-// printf("sysex: %02x (%d)\n", data, xmit_cnt);
+// printf("sysex: %02x (%d)\n", data, m_xmit_cnt);
// if we get a status that isn't sysex, assume it's system common
if ((data & 0x80) && (data != MIDI_EOX))
{
// printf("common during sysex!\n");
ev.message = Pm_Message(data, 0, 0);
- Pm_Write(pmStream, &ev, 1);
+ Pm_Write(m_stream, &ev, 1);
return;
}
- xmit_in[xmit_cnt++] = data;
+ m_xmit_in[m_xmit_cnt++] = data;
// if EOX or 4 bytes filled, transmit 4 bytes
- if ((xmit_cnt == 4) || (data == MIDI_EOX))
+ if ((m_xmit_cnt == 4) || (data == MIDI_EOX))
{
- ev.message = xmit_in[0] | (xmit_in[1]<<8) | (xmit_in[2]<<16) | (xmit_in[3]<<24);
- Pm_Write(pmStream, &ev, 1);
- xmit_in[0] = xmit_in[1] = xmit_in[2] = xmit_in[3] = 0;
- xmit_cnt = 0;
+ ev.message = m_xmit_in[0] | (m_xmit_in[1]<<8) | (m_xmit_in[2]<<16) | (m_xmit_in[3]<<24);
+ Pm_Write(m_stream, &ev, 1);
+ m_xmit_in[0] = m_xmit_in[1] = m_xmit_in[2] = m_xmit_in[3] = 0;
+ m_xmit_cnt = 0;
// printf("SysEx packet: %08x\n", ev.message);
// if this is EOX, kill the running status
if (data == MIDI_EOX)
{
- last_status = 0;
+ m_last_status = 0;
}
}
@@ -398,33 +396,33 @@ void osd_midi_device_pm::write(uint8_t data)
}
// handle running status. don't allow system real-time messages to be considered as running status.
- if ((xmit_cnt == 0) && (data & 0x80) && (data < 0xf8))
+ if ((m_xmit_cnt == 0) && (data & 0x80) && (data < 0xf8))
{
- last_status = data;
+ m_last_status = data;
}
- if ((xmit_cnt == 0) && !(data & 0x80))
+ if ((m_xmit_cnt == 0) && !(data & 0x80))
{
- xmit_in[xmit_cnt++] = last_status;
- xmit_in[xmit_cnt++] = data;
-// printf("\trunning status: [%d] = %02x, [%d] = %02x, last_status = %02x\n", xmit_cnt-2, last_status, xmit_cnt-1, data, last_status);
+ m_xmit_in[m_xmit_cnt++] = m_last_status;
+ m_xmit_in[m_xmit_cnt++] = data;
+// printf("\trunning status: [%d] = %02x, [%d] = %02x, m_last_status = %02x\n", m_xmit_cnt-2, m_last_status, m_xmit_cnt-1, data, m_last_status);
}
else
{
- xmit_in[xmit_cnt++] = data;
-// printf("\tNRS: [%d] = %02x\n", xmit_cnt-1, data);
+ m_xmit_in[m_xmit_cnt++] = data;
+// printf("\tNRS: [%d] = %02x\n", m_xmit_cnt-1, data);
}
- if ((xmit_cnt == 1) && (xmit_in[0] == MIDI_SYSEX))
+ if ((m_xmit_cnt == 1) && (m_xmit_in[0] == MIDI_SYSEX))
{
// printf("Start SysEx!\n");
- last_status = MIDI_SYSEX;
+ m_last_status = MIDI_SYSEX;
return;
}
// are we there yet?
-// printf("status check: %02x\n", xmit_in[0]);
- switch ((xmit_in[0]>>4) & 0xf)
+// printf("status check: %02x\n", m_xmit_in[0]);
+ switch ((m_xmit_in[0]>>4) & 0xf)
{
case 0xc: // 2-byte messages
case 0xd:
@@ -432,7 +430,7 @@ void osd_midi_device_pm::write(uint8_t data)
break;
case 0xf: // system common
- switch (xmit_in[0] & 0xf)
+ switch (m_xmit_in[0] & 0xf)
{
case 0: // System Exclusive is handled above
break;
@@ -457,20 +455,24 @@ void osd_midi_device_pm::write(uint8_t data)
break;
}
- if (xmit_cnt == bytes_needed)
+ if (m_xmit_cnt == bytes_needed)
{
- ev.message = Pm_Message(xmit_in[0], xmit_in[1], xmit_in[2]);
- Pm_Write(pmStream, &ev, 1);
- xmit_cnt = 0;
+ ev.message = Pm_Message(m_xmit_in[0], m_xmit_in[1], m_xmit_in[2]);
+ Pm_Write(m_stream, &ev, 1);
+ m_xmit_cnt = 0;
}
}
+
+} // anonymous namespace
+
+} // namespace osd
+
#else
- #include "modules/osdmodule.h"
- #include "midi_module.h"
- MODULE_NOT_SUPPORTED(pm_module, OSD_MIDI_PROVIDER, "pm")
+namespace osd { namespace { MODULE_NOT_SUPPORTED(pm_module, OSD_MIDI_PROVIDER, "pm") } }
+
#endif
-MODULE_DEFINITION(MIDI_PM, pm_module)
+MODULE_DEFINITION(MIDI_PM, osd::pm_module)
diff --git a/src/osd/modules/monitor/monitor_common.cpp b/src/osd/modules/monitor/monitor_common.cpp
index 8f935db7da2..f6a338d327c 100644
--- a/src/osd/modules/monitor/monitor_common.cpp
+++ b/src/osd/modules/monitor/monitor_common.cpp
@@ -5,12 +5,15 @@
*
*/
-#include "emu.h"
-#include <algorithm>
-
#include "monitor_common.h"
+
+#include "modules/lib/osdobj_common.h"
#include "modules/osdwindow.h"
+#include "osdcore.h"
+
+#include <algorithm>
+
std::shared_ptr<osd_monitor_info> monitor_module_base::pick_monitor(osd_options& options, int index)
{
// get the aspect ratio
@@ -93,7 +96,7 @@ float monitor_module_base::get_aspect(const char* defdata, const char* data, int
return float(num) / float(den);
}
-int monitor_module_base::init(const osd_options& options)
+int monitor_module_base::init(osd_interface &osd, const osd_options &options)
{
if (!m_initialized)
{
diff --git a/src/osd/modules/monitor/monitor_common.h b/src/osd/modules/monitor/monitor_common.h
index 4316722c9bb..4b1d17d2f1f 100644
--- a/src/osd/modules/monitor/monitor_common.h
+++ b/src/osd/modules/monitor/monitor_common.h
@@ -4,11 +4,17 @@
* monitor_common.h
*
*/
-#ifndef __MONITOR_COMMON_H__
-#define __MONITOR_COMMON_H__
+#ifndef MAME_OSD_MONITOR_MONITOR_COMMON_H
+#define MAME_OSD_MONITOR_MONITOR_COMMON_H
-#include "modules/lib/osdobj_common.h"
+#pragma once
+
+#include "monitor_module.h"
+
+#include <cstdint>
#include <map>
+#include <memory>
+
//============================================================
// monitor_module_base
@@ -16,32 +22,30 @@
class monitor_module_base : public monitor_module
{
-private:
- std::map<std::uint64_t, std::shared_ptr<osd_monitor_info>> m_monitor_index;
-
-protected:
- bool m_initialized;
-
public:
- monitor_module_base(const char* type, const char* name)
- : monitor_module(type, name),
- m_initialized(false)
+ monitor_module_base(const char* type, const char* name) :
+ monitor_module(type, name),
+ m_initialized(false)
{
}
std::shared_ptr<osd_monitor_info> pick_monitor(osd_options& options, int index) override;
std::shared_ptr<osd_monitor_info> monitor_from_handle(std::uint64_t handle) override;
- int init(const osd_options& options) override;
+ int init(osd_interface &osd, const osd_options& options) override;
void exit() override;
protected:
- virtual int init_internal(const osd_options& options) = 0;
+ virtual int init_internal(const osd_options &options) = 0;
void add_monitor(std::shared_ptr<osd_monitor_info> monitor);
+ bool m_initialized;
+
private:
- std::shared_ptr<osd_monitor_info> pick_monitor_internal(osd_options& options, int index);
static float get_aspect(const char *defdata, const char *data, int report_error);
+
+ std::map<std::uint64_t, std::shared_ptr<osd_monitor_info> > m_monitor_index;
+ std::shared_ptr<osd_monitor_info> pick_monitor_internal(osd_options& options, int index);
};
-#endif
+#endif // MAME_OSD_MONITOR_MONITOR_COMMON_H
diff --git a/src/osd/modules/monitor/monitor_dxgi.cpp b/src/osd/modules/monitor/monitor_dxgi.cpp
index 3eadadced24..d4ab80d2f33 100644
--- a/src/osd/modules/monitor/monitor_dxgi.cpp
+++ b/src/osd/modules/monitor/monitor_dxgi.cpp
@@ -5,11 +5,10 @@
*
*/
-#include "emu.h"
#include "modules/osdmodule.h"
#include "monitor_module.h"
-#if defined(OSD_WINDOWS) || defined(OSD_UWP)
+#if defined(OSD_WINDOWS)
// standard windows headers
#include <windows.h>
@@ -20,6 +19,7 @@
#include "strconv.h"
#include "modules/lib/osdlib.h"
#include "monitor_common.h"
+#include "osdcore.h"
#include "window.h"
#include "windows/video.h"
@@ -79,7 +79,6 @@ public:
if (!m_initialized)
return nullptr;
-#if defined(OSD_WINDOWS)
RECT p;
p.top = rect.top();
p.left = rect.left();
@@ -89,13 +88,6 @@ public:
auto nearest = monitor_from_handle(reinterpret_cast<std::uintptr_t>(MonitorFromRect(&p, MONITOR_DEFAULTTONEAREST)));
assert(nearest != nullptr);
return nearest;
-#elif defined(OSD_UWP)
- if (list().size() == 0)
- return nullptr;
-
- // For now just return first monitor
- return list()[0];
-#endif
}
// Currently this method implementation is duplicated from the win32 module
@@ -105,17 +97,9 @@ public:
if (!m_initialized)
return nullptr;
-#if defined(OSD_WINDOWS)
auto nearest = monitor_from_handle(reinterpret_cast<std::uintptr_t>(MonitorFromWindow(static_cast<const win_window_info &>(window).platform_window(), MONITOR_DEFAULTTONEAREST)));
assert(nearest != nullptr);
return nearest;
-#elif defined(OSD_UWP)
- if (list().size() == 0)
- return nullptr;
-
- // For now just return first monitor
- return list()[0];
-#endif
}
protected:
@@ -164,9 +148,9 @@ protected:
// if we're verbose, print the list of monitors
{
- for (auto monitor : list())
+ for (const auto &monitor : list())
{
- osd_printf_verbose("Video: Monitor %I64u = \"%s\" %s\n", monitor->oshandle(), monitor->devicename().c_str(), monitor->is_primary() ? "(primary)" : "");
+ osd_printf_verbose("Video: Monitor %u = \"%s\" %s\n", monitor->oshandle(), monitor->devicename(), monitor->is_primary() ? "(primary)" : "");
}
}
diff --git a/src/osd/modules/monitor/monitor_mac.cpp b/src/osd/modules/monitor/monitor_mac.cpp
index 74523105cf0..e81afa7ffae 100644
--- a/src/osd/modules/monitor/monitor_mac.cpp
+++ b/src/osd/modules/monitor/monitor_mac.cpp
@@ -8,7 +8,6 @@
//
//============================================================
-#include "emu.h"
#include "modules/osdmodule.h"
#include "monitor_module.h"
@@ -21,6 +20,7 @@
#include "modules/osdwindow.h"
#include "monitor_common.h"
+#include "osdcore.h"
#include "window.h"
//============================================================
@@ -115,7 +115,7 @@ protected:
// allocate a new monitor info
std::shared_ptr<osd_monitor_info> monitor = std::make_shared<mac_monitor_info>(*this, displayList[disp], temp, 1.0f);
- osd_printf_verbose("Adding monitor %s (%d x %d)\n", monitor->devicename().c_str(),
+ osd_printf_verbose("Adding monitor %s (%d x %d)\n", monitor->devicename(),
monitor->position_size().width(), monitor->position_size().height());
// guess the aspect ratio assuming square pixels
diff --git a/src/osd/modules/monitor/monitor_module.h b/src/osd/modules/monitor/monitor_module.h
index 3244e7fd42b..38e7e02fec2 100644
--- a/src/osd/modules/monitor/monitor_module.h
+++ b/src/osd/modules/monitor/monitor_module.h
@@ -8,6 +8,7 @@
#ifndef MAME_OSD_MODULES_MONITOR_MONITORMODULE_H
#define MAME_OSD_MODULES_MONITOR_MONITORMODULE_H
+#include <cstdint>
#include <vector>
#include "modules/osdmodule.h"
@@ -53,7 +54,7 @@ public:
float aspect() const { return m_aspect; }
float pixel_aspect() const { return m_aspect / (float(m_pos_size.width()) / float(m_pos_size.height())); }
- void update_resolution(const int new_width, const int new_height) const { m_pos_size.resize(new_width, new_height); }
+ void update_resolution(const int new_width, const int new_height) { m_pos_size = m_pos_size.resize(new_width, new_height); }
void set_aspect(const float a) { m_aspect = a; }
bool is_primary() const { return m_is_primary; }
diff --git a/src/osd/modules/monitor/monitor_sdl.cpp b/src/osd/modules/monitor/monitor_sdl.cpp
index b32ade230e1..679c7a4f97d 100644
--- a/src/osd/modules/monitor/monitor_sdl.cpp
+++ b/src/osd/modules/monitor/monitor_sdl.cpp
@@ -5,19 +5,24 @@
*
*/
-#include "emu.h"
#include "modules/osdmodule.h"
#include "monitor_module.h"
#if defined(OSD_SDL)
-#include <algorithm>
-#include <SDL2/SDL.h>
+#include "monitor_common.h"
+#include "modules/lib/osdobj_common.h"
#include "modules/osdwindow.h"
-#include "monitor_common.h"
+
+#include "osdcore.h"
#include "window.h"
+#include <SDL2/SDL.h>
+
+#include <algorithm>
+
+
inline osd_rect SDL_Rect_to_osd_rect(const SDL_Rect &r)
{
return osd_rect(r.x, r.y, r.w, r.h);
@@ -118,8 +123,9 @@ protected:
// allocate a new monitor info
std::shared_ptr<osd_monitor_info> monitor = std::make_shared<sdl_monitor_info>(*this, i, temp, 1.0f);
- osd_printf_verbose("Adding monitor %s (%d x %d)\n", monitor->devicename().c_str(),
- monitor->position_size().width(), monitor->position_size().height());
+ osd_printf_verbose("Adding monitor %s (%d x %d)\n",
+ monitor->devicename(),
+ monitor->position_size().width(), monitor->position_size().height());
// guess the aspect ratio assuming square pixels
monitor->set_aspect(static_cast<float>(monitor->position_size().width()) / static_cast<float>(monitor->position_size().height()));
diff --git a/src/osd/modules/monitor/monitor_win32.cpp b/src/osd/modules/monitor/monitor_win32.cpp
index 5a7405c463c..1766ca358a1 100644
--- a/src/osd/modules/monitor/monitor_win32.cpp
+++ b/src/osd/modules/monitor/monitor_win32.cpp
@@ -5,7 +5,6 @@
*
*/
-#include "emu.h"
#include "modules/osdmodule.h"
#include "monitor_module.h"
@@ -15,6 +14,7 @@
#include <windows.h>
#undef interface
+#include "osdcore.h"
#include "strconv.h"
#include "windows/video.h"
#include "window.h"
@@ -94,9 +94,9 @@ protected:
// if we're verbose, print the list of monitors
{
- for (auto monitor : list())
+ for (const auto &monitor : list())
{
- osd_printf_verbose("Video: Monitor %I64u = \"%s\" %s\n", monitor->oshandle(), monitor->devicename().c_str(), monitor->is_primary() ? "(primary)" : "");
+ osd_printf_verbose("Video: Monitor %u = \"%s\" %s\n", monitor->oshandle(), monitor->devicename(), monitor->is_primary() ? "(primary)" : "");
}
}
@@ -106,7 +106,7 @@ protected:
private:
static BOOL CALLBACK monitor_enum_callback(HMONITOR handle, HDC dc, LPRECT rect, LPARAM data)
{
- win32_monitor_module* self = reinterpret_cast<win32_monitor_module*>(data);
+ auto* self = reinterpret_cast<win32_monitor_module*>(data);
MONITORINFOEX info;
BOOL result;
diff --git a/src/osd/modules/netdev/netdev_common.cpp b/src/osd/modules/netdev/netdev_common.cpp
new file mode 100644
index 00000000000..b6a2328c7a6
--- /dev/null
+++ b/src/osd/modules/netdev/netdev_common.cpp
@@ -0,0 +1,39 @@
+// license:BSD-3-Clause
+// copyright-holders:Carl
+
+#include "netdev_common.h"
+
+
+namespace osd {
+
+network_device_base::network_device_base(network_handler &handler)
+ : m_handler(handler)
+ , m_stopped(true)
+{
+}
+
+network_device_base::~network_device_base()
+{
+}
+
+void network_device_base::start()
+{
+ m_stopped = false;
+}
+
+void network_device_base::stop()
+{
+ m_stopped = true;
+}
+
+void network_device_base::poll()
+{
+ uint8_t *buf;
+ int len;
+ while (!m_stopped && (len = recv_dev(&buf)))
+ {
+ m_handler.recv_cb(buf, len);
+ }
+}
+
+} // namespace osd
diff --git a/src/osd/modules/netdev/netdev_common.h b/src/osd/modules/netdev/netdev_common.h
new file mode 100644
index 00000000000..95d961a438a
--- /dev/null
+++ b/src/osd/modules/netdev/netdev_common.h
@@ -0,0 +1,36 @@
+// license:BSD-3-Clause
+// copyright-holders:Carl
+#ifndef MAME_OSD_NETDEV_NETDEV_COMMON_H
+#define MAME_OSD_NETDEV_NETDEV_COMMON_H
+
+#pragma once
+
+#include "interface/nethandler.h"
+
+#include <cstdint>
+
+
+namespace osd {
+
+class network_device_base : public network_device
+{
+public:
+ virtual ~network_device_base();
+
+ virtual void start() override;
+ virtual void stop() override;
+ virtual void poll() override;
+
+protected:
+ network_device_base(network_handler &handler);
+
+ virtual int recv_dev(uint8_t **buf) = 0;
+
+private:
+ network_handler &m_handler;
+ bool m_stopped;
+};
+
+} // namespace osd
+
+#endif // MAME_OSD_NETDEV_NETDEV_COMMON_H
diff --git a/src/osd/modules/netdev/netdev_module.h b/src/osd/modules/netdev/netdev_module.h
index b1d537cacf5..3636c3a23cb 100644
--- a/src/osd/modules/netdev/netdev_module.h
+++ b/src/osd/modules/netdev/netdev_module.h
@@ -4,25 +4,30 @@
* netdev_module.h
*
*/
+#ifndef MAME_OSD_NETDEV_NETDEV_MODULE_H
+#define MAME_OSD_NETDEV_NETDEV_MODULE_H
-#ifndef NETDEV_MODULE_H_
-#define NETDEV_MODULE_H_
+#pragma once
+
+#include "interface/nethandler.h"
+
+#include <memory>
+#include <vector>
-#include "osdepend.h"
-#include "modules/osdmodule.h"
//============================================================
// CONSTANTS
//============================================================
-#define OSD_NETDEV_PROVIDER "netdevprovider"
+#define OSD_NETDEV_PROVIDER "networkprovider"
class netdev_module
{
public:
- virtual ~netdev_module() { }
- // no specific routines below ... may change
-};
+ virtual ~netdev_module() = default;
+ virtual std::unique_ptr<osd::network_device> open_device(int id, osd::network_handler &handler) = 0;
+ virtual std::vector<osd::network_device_info> list_devices() = 0;
+};
-#endif /* NETDEV_MODULE_H_ */
+#endif // MAME_OSD_NETDEV_NETDEV_MODULE_H
diff --git a/src/osd/modules/netdev/none.cpp b/src/osd/modules/netdev/none.cpp
index a5b520f26a5..284ff51a962 100644
--- a/src/osd/modules/netdev/none.cpp
+++ b/src/osd/modules/netdev/none.cpp
@@ -4,20 +4,45 @@
* none.c
*
*/
-
#include "netdev_module.h"
+
#include "modules/osdmodule.h"
+#include <memory>
+#include <vector>
+
+
+namespace osd {
+
+namespace {
+
class netdev_none : public osd_module, public netdev_module
{
public:
- netdev_none()
- : osd_module(OSD_NETDEV_PROVIDER, "none"), netdev_module()
+ netdev_none() : osd_module(OSD_NETDEV_PROVIDER, "none"), netdev_module()
{
}
virtual ~netdev_none() { }
- virtual int init(const osd_options &options) override { return 0; }
+
+ virtual int init(osd_interface &osd, const osd_options &options) override
+ {
+ return 0;
+ }
+
+ virtual std::unique_ptr<network_device> open_device(int id, network_handler &handler) override
+ {
+ return std::unique_ptr<network_device>();
+ }
+
+ virtual std::vector<network_device_info> list_devices() override
+ {
+ return std::vector<network_device_info>();
+ }
};
-MODULE_DEFINITION(NETDEV_NONE, netdev_none)
+} // anonymous namespace
+
+} // namespace osd
+
+MODULE_DEFINITION(NETDEV_NONE, osd::netdev_none)
diff --git a/src/osd/modules/netdev/pcap.cpp b/src/osd/modules/netdev/pcap.cpp
index 68e9512b14a..8ad62773d58 100644
--- a/src/osd/modules/netdev/pcap.cpp
+++ b/src/osd/modules/netdev/pcap.cpp
@@ -1,22 +1,31 @@
// license:BSD-3-Clause
// copyright-holders:Carl
-#if defined(OSD_NET_USE_PCAP)
-
-#include "emu.h"
-#include "osdnet.h"
#include "netdev_module.h"
+
#include "modules/osdmodule.h"
+
+#if defined(OSD_NET_USE_PCAP)
+
+#include "netdev_common.h"
+
#include "modules/lib/osdlib.h"
+#include "osdcore.h" // osd_printf_*
+
+#include "util/strformat.h" // string_format
+
+#include <memory>
+#include <vector>
+
#if defined(SDLMAME_WIN32) || defined(OSD_WINDOWS)
#include <windows.h>
#undef interface
#define LIB_NAME "wpcap.dll"
#elif defined(SDLMAME_MACOSX)
+#include <atomic>
#include <pthread.h>
-#include <libkern/OSAtomic.h>
#define LIB_NAME "libpcap.dylib"
#else
@@ -25,6 +34,10 @@
#include <pcap.h>
+namespace osd {
+
+namespace {
+
// Typedefs for dynamically loaded functions
typedef int (*pcap_findalldevs_fn)(pcap_if_t **, char *);
typedef pcap_t *(*pcap_open_live_fn)(const char *, int, int, int, char *);
@@ -39,16 +52,16 @@ typedef int (*pcap_dispatch_fn)(pcap_t *, int, pcap_handler, u_char *);
class pcap_module : public osd_module, public netdev_module
{
public:
- pcap_module()
- : osd_module(OSD_NETDEV_PROVIDER, "pcap"), netdev_module(),
- pcap_findalldevs_dl(nullptr), pcap_open_live_dl(nullptr), pcap_next_ex_dl(nullptr), pcap_compile_dl(nullptr),
- pcap_close_dl(nullptr), pcap_setfilter_dl(nullptr), pcap_sendpacket_dl(nullptr), pcap_set_datalink_dl(nullptr), pcap_dispatch_dl(nullptr)
+ pcap_module() :
+ osd_module(OSD_NETDEV_PROVIDER, "pcap"), netdev_module(),
+ pcap_findalldevs_dl(nullptr), pcap_open_live_dl(nullptr), pcap_next_ex_dl(nullptr), pcap_compile_dl(nullptr),
+ pcap_close_dl(nullptr), pcap_setfilter_dl(nullptr), pcap_sendpacket_dl(nullptr), pcap_set_datalink_dl(nullptr), pcap_dispatch_dl(nullptr)
{
}
virtual ~pcap_module() { }
- virtual int init(const osd_options &options) override;
+ virtual int init(osd_interface &osd, const osd_options &options) override;
virtual void exit() override;
virtual bool probe() override
@@ -76,6 +89,20 @@ public:
return true;
}
+ virtual std::unique_ptr<network_device> open_device(int id, network_handler &handler) override;
+ virtual std::vector<network_device_info> list_devices() override;
+
+private:
+ struct device_info
+ {
+ std::string name;
+ std::string description;
+ };
+
+ class netdev_pcap;
+
+ std::vector<device_info> m_devices;
+
osd::dynamic_module::ptr pcap_dll;
pcap_findalldevs_fn pcap_findalldevs_dl;
@@ -89,192 +116,161 @@ public:
pcap_dispatch_fn pcap_dispatch_dl;
};
-// FIXME: bridge between pcap_module and netdev_pcap
-static pcap_module *module = nullptr;
-
-#ifdef SDLMAME_MACOSX
-struct netdev_pcap_context {
- uint8_t *pkt;
- int len;
- pcap_t *p;
-
- uint8_t packets[32][1600];
- int packetlens[32];
- int head;
- int tail;
-};
-#endif
-
-class netdev_pcap : public osd_netdev
+class pcap_module::netdev_pcap : public network_device_base
{
public:
- netdev_pcap(const char *name, class device_network_interface *ifdev, int rate);
+ netdev_pcap(pcap_module &module, const char *name, network_handler &handler);
~netdev_pcap();
- virtual int send(uint8_t *buf, int len) override;
- virtual void set_mac(const char *mac) override;
+ virtual int send(void const *buf, int len) override;
+
protected:
virtual int recv_dev(uint8_t **buf) override;
+
private:
+ pcap_module &m_module;
pcap_t *m_p;
#ifdef SDLMAME_MACOSX
- struct netdev_pcap_context m_ctx;
pthread_t m_thread;
+ uint8_t *pkt;
+ int len;
+ pcap_t *p;
+ uint8_t m_pktbuf[2048];
+
+ uint8_t m_packets[32][1600];
+ int m_packetlens[32];
+ std::atomic<int> m_head;
+ std::atomic<int> m_tail;
+
+ static void pcap_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes);
+ static void *pcap_blocker(void *arg);
#endif
};
#ifdef SDLMAME_MACOSX
-static void netdev_pcap_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) {
- struct netdev_pcap_context *ctx = (struct netdev_pcap_context*)user;
+void pcap_module::netdev_pcap::pcap_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
+{
+ netdev_pcap *const ctx = reinterpret_cast<netdev_pcap *>(user);
- if(!ctx->p) return;
+ if (!ctx->p)
+ return;
- if(OSAtomicCompareAndSwapInt((ctx->head+1) & 0x1F, ctx->tail, &ctx->tail)) {
+ int const curr = ctx->m_head.load(std::memory_order_relaxed);
+ int const next = (curr + 1) & 0x1f;
+ if (ctx->m_tail.load(std::memory_order_acquire) == next)
+ {
printf("buffer full, dropping packet\n");
return;
}
- memcpy(ctx->packets[ctx->head], bytes, h->len);
- ctx->packetlens[ctx->head] = h->len;
- OSAtomicCompareAndSwapInt(ctx->head, (ctx->head+1) & 0x1F, &ctx->head);
+ memcpy(ctx->m_packets[curr], bytes, h->len);
+ ctx->m_packetlens[curr] = h->len;
+ ctx->m_head.store(next, std::memory_order_release);
}
-static void *netdev_pcap_blocker(void *arg) {
- struct netdev_pcap_context *ctx = (struct netdev_pcap_context*)arg;
+void *pcap_module::netdev_pcap::pcap_blocker(void *arg)
+{
+ netdev_pcap *const ctx = reinterpret_cast<netdev_pcap *>(arg);
- while(ctx && ctx->p) {
- (*module->pcap_dispatch_dl)(ctx->p, 1, netdev_pcap_handler, (u_char*)ctx);
- }
+ while (ctx && ctx->p)
+ (*ctx->m_module.pcap_dispatch_dl)(ctx->p, 1, &netdev_pcap::pcap_handler, reinterpret_cast<u_char *>(ctx));
- return 0;
+ return nullptr;
}
#endif
-netdev_pcap::netdev_pcap(const char *name, class device_network_interface *ifdev, int rate)
- : osd_netdev(ifdev, rate)
+pcap_module::netdev_pcap::netdev_pcap(pcap_module &module, const char *name, network_handler &handler) :
+ network_device_base(handler),
+ m_module(module),
+ m_p(nullptr)
{
char errbuf[PCAP_ERRBUF_SIZE];
#if defined(SDLMAME_WIN32) || defined(OSD_WINDOWS)
- m_p = (*module->pcap_open_live_dl)(name, 65535, 1, -1, errbuf);
+ m_p = (*m_module.pcap_open_live_dl)(name, 65535, 1, -1, errbuf);
#else
- m_p = (*module->pcap_open_live_dl)(name, 65535, 1, 1, errbuf);
+ m_p = (*m_module.pcap_open_live_dl)(name, 65535, 1, 1, errbuf);
#endif
if(!m_p)
{
osd_printf_error("Unable to open %s: %s\n", name, errbuf);
return;
}
- if ((*module->pcap_set_datalink_dl)(m_p, DLT_EN10MB) == -1)
+ if ((*m_module.pcap_set_datalink_dl)(m_p, DLT_EN10MB) == -1)
{
osd_printf_error("Unable to set %s to ethernet", name);
- (*module->pcap_close_dl)(m_p);
+ (*m_module.pcap_close_dl)(m_p);
m_p = nullptr;
return;
}
- netdev_pcap::set_mac(get_mac());
#ifdef SDLMAME_MACOSX
- m_ctx.head = 0;
- m_ctx.tail = 0;
- m_ctx.p = m_p;
- pthread_create(&m_thread, nullptr, netdev_pcap_blocker, &m_ctx);
+ m_head = 0;
+ m_tail = 0;
+ p = m_p;
+ pthread_create(&m_thread, nullptr, &netdev_pcap::pcap_blocker, this);
#endif
}
-void netdev_pcap::set_mac(const char *mac)
+int pcap_module::netdev_pcap::send(void const *buf, int len)
{
- char filter[256];
- struct bpf_program fp;
- if(!m_p) return;
-#ifdef SDLMAME_MACOSX
- sprintf(filter, "not ether src %.2X:%.2X:%.2X:%.2X:%.2X:%.2X and (ether dst %.2X:%.2X:%.2X:%.2X:%.2X:%.2X or ether multicast or ether broadcast or ether dst 09:00:07:ff:ff:ff)", (unsigned char)mac[0], (unsigned char)mac[1], (unsigned char)mac[2],(unsigned char)mac[3], (unsigned char)mac[4], (unsigned char)mac[5], (unsigned char)mac[0], (unsigned char)mac[1], (unsigned char)mac[2],(unsigned char)mac[3], (unsigned char)mac[4], (unsigned char)mac[5]);
-#else
- sprintf(filter, "ether dst %.2X:%.2X:%.2X:%.2X:%.2X:%.2X or ether multicast or ether broadcast", (unsigned char)mac[0], (unsigned char)mac[1], (unsigned char)mac[2],(unsigned char)mac[3], (unsigned char)mac[4], (unsigned char)mac[5]);
-#endif
- if ((*module->pcap_compile_dl)(m_p, &fp, filter, 1, 0) == -1) {
- osd_printf_error("Error with pcap_compile\n");
- }
- if ((*module->pcap_setfilter_dl)(m_p, &fp) == -1) {
- osd_printf_error("Error with pcap_setfilter\n");
- }
-}
-
-int netdev_pcap::send(uint8_t *buf, int len)
-{
- int ret;
- if(!m_p) {
+ if (!m_p)
+ {
printf("send invoked, but no pcap context\n");
return 0;
}
- ret = (*module->pcap_sendpacket_dl)(m_p, buf, len);
+ int ret = (*m_module.pcap_sendpacket_dl)(m_p, reinterpret_cast<const u_char *>(buf), len);
printf("sent packet length %d, returned %d\n", len, ret);
return ret ? len : 0;
- //return (!pcap_sendpacket_dl(m_p, buf, len))?len:0;
+ //return (!pcap_sendpacket_dl(m_p, reinterpret_cast<const u_char *>(buf), len)) ? len : 0;
}
-int netdev_pcap::recv_dev(uint8_t **buf)
+int pcap_module::netdev_pcap::recv_dev(uint8_t **buf)
{
-#ifdef SDLMAME_MACOSX
- uint8_t pktbuf[2048];
- int ret;
-
// no device open?
- if(!m_p) return 0;
+ if (!m_p)
+ return 0;
+#ifdef SDLMAME_MACOSX
// Empty
- if(OSAtomicCompareAndSwapInt(m_ctx.head, m_ctx.tail, &m_ctx.tail)) {
+ int const curr = m_tail.load(std::memory_order_relaxed);
+ if (m_head.load(std::memory_order_acquire) == curr)
return 0;
- }
- memcpy(pktbuf, m_ctx.packets[m_ctx.tail], m_ctx.packetlens[m_ctx.tail]);
- ret = m_ctx.packetlens[m_ctx.tail];
- OSAtomicCompareAndSwapInt(m_ctx.tail, (m_ctx.tail+1) & 0x1F, &m_ctx.tail);
- *buf = pktbuf;
+ memcpy(m_pktbuf, m_packets[curr], m_packetlens[curr]);
+ int ret = m_packetlens[curr];
+ m_tail.store((curr + 1) & 0x1f, std::memory_order_release);
+ *buf = m_pktbuf;
return ret;
#else
struct pcap_pkthdr *header;
- if(!m_p) return 0;
- return ((*module->pcap_next_ex_dl)(m_p, &header, (const u_char **)buf) == 1)?header->len:0;
+ return ((*m_module.pcap_next_ex_dl)(m_p, &header, (const u_char **)buf) == 1)?header->len:0;
#endif
}
-netdev_pcap::~netdev_pcap()
+pcap_module::netdev_pcap::~netdev_pcap()
{
#ifdef SDLMAME_MACOSX
- m_ctx.p = nullptr;
+ p = nullptr;
pthread_cancel(m_thread);
pthread_join(m_thread, nullptr);
#endif
- if(m_p) (*module->pcap_close_dl)(m_p);
+ if(m_p) (*m_module.pcap_close_dl)(m_p);
m_p = nullptr;
}
-static CREATE_NETDEV(create_pcap)
-{
- class netdev_pcap *dev = global_alloc(netdev_pcap(ifname, ifdev, rate));
- return dynamic_cast<osd_netdev *>(dev);
-}
-
-int pcap_module::init(const osd_options &options)
+int pcap_module::init(osd_interface &osd, const osd_options &options)
{
pcap_if_t *devs;
char errbuf[PCAP_ERRBUF_SIZE];
- // FIXME: bridge between pcap_module and netdev_pcap
- module = this;
-
if ((*pcap_findalldevs_dl)(&devs, errbuf) == -1)
{
osd_printf_error("Unable to get network devices: %s\n", errbuf);
return 1;
}
- while(devs)
+ while (devs)
{
- if(devs->description) {
- add_netdev(devs->name, devs->description, create_pcap);
- } else {
- add_netdev(devs->name, devs->name, create_pcap);
- }
+ m_devices.emplace_back(device_info{ devs->name, devs->description ? devs->description : devs->name });
devs = devs->next;
}
return 0;
@@ -282,15 +278,35 @@ int pcap_module::init(const osd_options &options)
void pcap_module::exit()
{
- clear_netdev();
+ m_devices.clear();
}
+std::unique_ptr<network_device> pcap_module::open_device(int id, network_handler &handler)
+{
+ if ((0 > id) || (m_devices.size() <= id))
+ return nullptr;
+
+ return std::make_unique<netdev_pcap>(*this, m_devices[id].name.c_str(), handler);
+}
+
+std::vector<network_device_info> pcap_module::list_devices()
+{
+ std::vector<network_device_info> result;
+ result.reserve(m_devices.size());
+ for (int id = 0; m_devices.size() > id; ++id)
+ result.emplace_back(network_device_info{ id, m_devices[id].description });
+ return result;
+}
+
+} // anonymous namespace
+
+} // namespace osd
+
#else
- #include "modules/osdmodule.h"
- #include "netdev_module.h"
- MODULE_NOT_SUPPORTED(pcap_module, OSD_NETDEV_PROVIDER, "pcap")
+namespace osd { namespace { MODULE_NOT_SUPPORTED(pcap_module, OSD_NETDEV_PROVIDER, "pcap") } }
+
#endif
-MODULE_DEFINITION(NETDEV_PCAP, pcap_module)
+MODULE_DEFINITION(NETDEV_PCAP, osd::pcap_module)
diff --git a/src/osd/modules/netdev/taptun.cpp b/src/osd/modules/netdev/taptun.cpp
index 91ca323a178..b765a667ae7 100644
--- a/src/osd/modules/netdev/taptun.cpp
+++ b/src/osd/modules/netdev/taptun.cpp
@@ -1,8 +1,23 @@
// license:BSD-3-Clause
// copyright-holders:Carl
+#include "netdev_module.h"
+
+#include "modules/osdmodule.h"
+
#if defined(OSD_NET_USE_TAPTUN)
-#if defined(WIN32)
+#include "netdev_common.h"
+
+#include "osdcore.h" // osd_printf_verbose
+#include "osdfile.h" // PATH_SEPARATOR
+
+#include "util/hashing.h" // crc32_creator
+#include "util/unicode.h"
+
+#include <memory>
+#include <vector>
+
+#if defined(_WIN32)
#include <windows.h>
#include <winioctl.h>
#else
@@ -10,19 +25,14 @@
#include <fcntl.h>
#include <sys/ioctl.h>
#include <net/if.h>
-#include <errno.h>
+#include <cerrno>
#endif
-#include "emu.h"
-#include "osdnet.h"
-#include "modules/osdmodule.h"
-#include "netdev_module.h"
-
#ifdef __linux__
#define IFF_TAP 0x0002
#define IFF_NO_PI 0x1000
#define TUNSETIFF _IOW('T', 202, int)
-#elif defined(WIN32)
+#elif defined(_WIN32)
#include "tap-windows6/tap-windows.h"
// for some reason this isn't defined in the header, and presumably it changes
@@ -30,6 +40,10 @@
#define PRODUCT_TAP_WIN_COMPONENT_ID "tap0901"
#endif
+namespace osd {
+
+namespace {
+
// Ethernet minimum frame length
static constexpr int ETHERNET_MIN_FRAME = 64;
@@ -42,26 +56,39 @@ public:
}
virtual ~taptun_module() { }
- virtual int init(const osd_options &options);
- virtual void exit();
+ virtual int init(osd_interface &osd, const osd_options &options) override;
+ virtual void exit() override;
+
+ virtual bool probe() override { return true; }
+
+ virtual std::unique_ptr<network_device> open_device(int id, network_handler &handler) override;
+ virtual std::vector<network_device_info> list_devices() override;
+
+private:
+ struct device_info
+ {
+ std::string name;
+ std::string description;
+ };
- virtual bool probe() { return true; }
+ std::vector<device_info> m_devices;
};
-class netdev_tap : public osd_netdev
+class netdev_tap : public network_device_base
{
public:
- netdev_tap(const char *name, class device_network_interface *ifdev, int rate);
+ netdev_tap(const char *name, network_handler &handler);
~netdev_tap();
- int send(uint8_t *buf, int len) override;
- void set_mac(const char *mac) override;
+ int send(void const *buf, int len) override;
+
protected:
int recv_dev(uint8_t **buf) override;
+
private:
-#if defined(WIN32)
+#if defined(_WIN32)
HANDLE m_handle = INVALID_HANDLE_VALUE;
OVERLAPPED m_overlapped;
bool m_receive_pending;
@@ -69,22 +96,20 @@ private:
int m_fd = -1;
char m_ifname[10];
#endif
- char m_mac[6];
uint8_t m_buf[2048];
};
-netdev_tap::netdev_tap(const char *name, class device_network_interface *ifdev, int rate)
- : osd_netdev(ifdev, rate)
+netdev_tap::netdev_tap(const char *name, network_handler &handler)
+ : network_device_base(handler)
{
-#ifdef __linux__
- struct ifreq ifr;
-
+#if defined(__linux__)
m_fd = -1;
if((m_fd = open("/dev/net/tun", O_RDWR)) == -1) {
osd_printf_verbose("tap: open failed %d\n", errno);
return;
}
+ struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
sprintf(ifr.ifr_name, "tap-mess-%d-0", getuid());
@@ -97,7 +122,7 @@ netdev_tap::netdev_tap(const char *name, class device_network_interface *ifdev,
osd_printf_verbose("netdev_tap: network up!\n");
strncpy(m_ifname, ifr.ifr_name, 10);
fcntl(m_fd, F_SETFL, O_NONBLOCK);
-#elif defined(WIN32)
+#elif defined(_WIN32)
std::wstring device_path(L"" USERMODEDEVICEDIR);
device_path.append(wstring_from_utf8(name));
device_path.append(L"" TAP_WIN_SUFFIX);
@@ -120,7 +145,7 @@ netdev_tap::netdev_tap(const char *name, class device_network_interface *ifdev,
netdev_tap::~netdev_tap()
{
-#if defined(WIN32)
+#if defined(_WIN32)
if (m_handle != INVALID_HANDLE_VALUE)
{
if (m_receive_pending)
@@ -133,11 +158,6 @@ netdev_tap::~netdev_tap()
#endif
}
-void netdev_tap::set_mac(const char *mac)
-{
- memcpy(m_mac, mac, 6);
-}
-
static u32 finalise_frame(u8 buf[], u32 length)
{
/*
@@ -168,8 +188,8 @@ static u32 finalise_frame(u8 buf[], u32 length)
return length;
}
-#if defined(WIN32)
-int netdev_tap::send(uint8_t *buf, int len)
+#if defined(_WIN32)
+int netdev_tap::send(void const *buf, int len)
{
OVERLAPPED overlapped = {};
@@ -233,7 +253,7 @@ static std::wstring safe_string(WCHAR value[], int length)
}
// find the friendly name for an adapter in the registry
-static std::wstring get_connection_name(std::wstring &id)
+static std::wstring get_connection_name(std::wstring const &id)
{
std::wstring result;
@@ -285,16 +305,21 @@ static std::vector<std::wstring> get_tap_adapters()
// check if the ComponentId value indicates a TAP-Windows adapter
if (RegQueryValueExW(unit_key, L"ComponentId", NULL, &data_type, LPBYTE(component_id), &component_id_len) == ERROR_SUCCESS
- && data_type == REG_SZ
- && safe_string(component_id, component_id_len) == L"" PRODUCT_TAP_WIN_COMPONENT_ID)
+ && data_type == REG_SZ)
{
- WCHAR net_cfg_instance_id[MAX_PATH];
- DWORD net_cfg_instance_id_len = sizeof(net_cfg_instance_id);
-
- // add the adapter to the result
- if (RegQueryValueExW(unit_key, L"NetCfgInstanceId", NULL, &data_type, LPBYTE(net_cfg_instance_id), &net_cfg_instance_id_len) == ERROR_SUCCESS
- && data_type == REG_SZ)
- result.push_back(safe_string(net_cfg_instance_id, net_cfg_instance_id_len));
+ std::wstring const value(safe_string(component_id, component_id_len));
+
+ // some older versions may not set the "root\" prefix
+ if (value == L"root\\" PRODUCT_TAP_WIN_COMPONENT_ID || value == L"" PRODUCT_TAP_WIN_COMPONENT_ID)
+ {
+ WCHAR net_cfg_instance_id[MAX_PATH];
+ DWORD net_cfg_instance_id_len = sizeof(net_cfg_instance_id);
+
+ // add the adapter to the result
+ if (RegQueryValueExW(unit_key, L"NetCfgInstanceId", NULL, &data_type, LPBYTE(net_cfg_instance_id), &net_cfg_instance_id_len) == ERROR_SUCCESS
+ && data_type == REG_SZ)
+ result.push_back(safe_string(net_cfg_instance_id, net_cfg_instance_id_len));
+ }
}
RegCloseKey(unit_key);
@@ -310,7 +335,7 @@ static std::vector<std::wstring> get_tap_adapters()
return result;
}
#else
-int netdev_tap::send(uint8_t *buf, int len)
+int netdev_tap::send(void const *buf, int len)
{
if(m_fd == -1) return 0;
len = write(m_fd, buf, len);
@@ -319,51 +344,64 @@ int netdev_tap::send(uint8_t *buf, int len)
int netdev_tap::recv_dev(uint8_t **buf)
{
- int len;
- if(m_fd == -1) return 0;
- // exit if we didn't receive anything, got an error, got a broadcast or multicast packet,
- // are in promiscuous mode or got a packet with our mac.
- do {
- len = read(m_fd, m_buf, sizeof(m_buf));
- } while((len > 0) && memcmp(get_mac(), m_buf, 6) && !get_promisc() && !(m_buf[0] & 1));
+ if (0 > m_fd)
+ return 0;
+
+ int len = read(m_fd, m_buf, sizeof(m_buf));
if (len > 0)
len = finalise_frame(m_buf, len);
*buf = m_buf;
- return (len == -1)?0:len;
+ return (len == -1) ? 0 : len;
}
#endif
-static CREATE_NETDEV(create_tap)
-{
- class netdev_tap *dev = global_alloc(netdev_tap(ifname, ifdev, rate));
- return dynamic_cast<osd_netdev *>(dev);
-}
-
-int taptun_module::init(const osd_options &options)
+int taptun_module::init(osd_interface &osd, const osd_options &options)
{
-#if defined(WIN32)
- for (std::wstring &id : get_tap_adapters())
- add_netdev(utf8_from_wstring(id).c_str(), utf8_from_wstring(get_connection_name(id)).c_str(), create_tap);
+#if defined(_WIN32)
+ auto const adapters = get_tap_adapters();
+ m_devices.reserve(adapters.size());
+ for (std::wstring const &id : adapters)
+ m_devices.emplace_back(device_info{ utf8_from_wstring(id), utf8_from_wstring(get_connection_name(id)) });
#else
- add_netdev("tap", "TAP/TUN Device", create_tap);
+ m_devices.emplace_back(device_info{ "tap", "TUN/TAP Device" });
#endif
return 0;
}
void taptun_module::exit()
{
- clear_netdev();
+ m_devices.clear();
}
+std::unique_ptr<network_device> taptun_module::open_device(int id, network_handler &handler)
+{
+ if ((0 > id) || (m_devices.size() <= id))
+ return nullptr;
+
+ return std::make_unique<netdev_tap>(m_devices[id].name.c_str(), handler);
+}
+
+std::vector<network_device_info> taptun_module::list_devices()
+{
+ std::vector<network_device_info> result;
+ result.reserve(m_devices.size());
+ for (int id = 0; m_devices.size() > id; ++id)
+ result.emplace_back(network_device_info{ id, m_devices[id].description });
+ return result;
+}
+
+} // anonymous namespace
+
+} // namespace osd
+
#else
- #include "modules/osdmodule.h"
- #include "netdev_module.h"
- MODULE_NOT_SUPPORTED(taptun_module, OSD_NETDEV_PROVIDER, "taptun")
+namespace osd { namespace { MODULE_NOT_SUPPORTED(taptun_module, OSD_NETDEV_PROVIDER, "taptun") } }
+
#endif
-MODULE_DEFINITION(NETDEV_TAPTUN, taptun_module)
+MODULE_DEFINITION(NETDEV_TAPTUN, osd::taptun_module)
diff --git a/src/osd/modules/opengl/gl_shader_mgr.cpp b/src/osd/modules/opengl/gl_shader_mgr.cpp
index 0cf3f9b6617..4567a8e8085 100644
--- a/src/osd/modules/opengl/gl_shader_mgr.cpp
+++ b/src/osd/modules/opengl/gl_shader_mgr.cpp
@@ -1,13 +1,17 @@
// license:BSD-3-Clause
// copyright-holders:Sven Gothel
-#include <stdio.h> /* snprintf */
-#include <stdlib.h> /* malloc */
+
+#include "gl_shader_mgr.h"
#include "osdcomm.h"
-#include "osd_opengl.h"
-#include "gl_shader_mgr.h"
-#include "gl_shader_tool.h"
+#include "util/strformat.h"
+
+#include <algorithm>
+#include <iterator>
+
+
+namespace {
#define GLSL_VERTEX_SHADER_INT_NUMBER 1 // general
#define GLSL_VERTEX_SHADER_MAX_NUMBER 2 // general + custom
@@ -15,16 +19,16 @@
#ifdef GLSL_SOURCE_ON_DISK
-static char const *const glsl_mamebm_vsh_files [GLSL_VERTEX_SHADER_INT_NUMBER] =
+static char const *const glsl_mamebm_vsh_files[GLSL_VERTEX_SHADER_INT_NUMBER] =
{
- "/tmp/glsl_general.vsh" // general
+ "/tmp/glsl_general.vsh" // general
};
-static char const *const glsl_mamebm_fsh_files [GLSL_SHADER_FEAT_INT_NUMBER] =
+static char const *const glsl_mamebm_fsh_files[glsl_shader_info::FEAT_INT_NUMBER] =
{
- "/tmp/glsl_plain_rgb32_dir.fsh", // rgb32 dir plain
- "/tmp/glsl_bilinear_rgb32_dir.fsh", // rgb32 dir bilinear
- "/tmp/glsl_bicubic_rgb32_dir.fsh", // rgb32 dir bicubic
+ "/tmp/glsl_plain_rgb32_dir.fsh", // rgb32 dir plain
+ "/tmp/glsl_bilinear_rgb32_dir.fsh", // rgb32 dir bilinear
+ "/tmp/glsl_bicubic_rgb32_dir.fsh", // rgb32 dir bicubic
};
#else // GLSL_SOURCE_ON_DISK
@@ -35,209 +39,239 @@ static char const *const glsl_mamebm_fsh_files [GLSL_SHADER_FEAT_INT_NUMBER] =
#include "shader/glsl_bilinear_rgb32_dir.fsh.c"
#include "shader/glsl_bicubic_rgb32_dir.fsh.c"
-static char const *const glsl_mamebm_vsh_sources [GLSL_VERTEX_SHADER_INT_NUMBER] =
+static char const *const glsl_mamebm_vsh_sources[GLSL_VERTEX_SHADER_INT_NUMBER] =
{
- glsl_general_vsh_src // general
+ glsl_general_vsh_src // general
};
-static char const *const glsl_mamebm_fsh_sources [GLSL_SHADER_FEAT_INT_NUMBER] =
+static char const *const glsl_mamebm_fsh_sources[glsl_shader_info::FEAT_INT_NUMBER] =
{
- glsl_plain_rgb32_dir_fsh_src, // rgb32 dir plain
- glsl_bilinear_rgb32_dir_fsh_src, // rgb32 dir bilinear
- glsl_bicubic_rgb32_dir_fsh_src, // rgb32 dir bicubic
+ glsl_plain_rgb32_dir_fsh_src, // rgb32 dir plain
+ glsl_bilinear_rgb32_dir_fsh_src, // rgb32 dir bilinear
+ glsl_bicubic_rgb32_dir_fsh_src, // rgb32 dir bicubic
};
#endif // GLSL_SOURCE_ON_DISK
-static char const *const glsl_mamebm_filter_names [GLSL_SHADER_FEAT_MAX_NUMBER] =
-{
- "plain",
- "bilinear",
- "bicubic",
- "custom"
-};
-
-static GLhandleARB glsl_mamebm_programs [GLSL_SHADER_FEAT_MAX_NUMBER+9] =
-{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* rgb32 dir: plain, bilinear, bicubic, custom0-9, .. */
-};
+static char const *const glsl_mamebm_filter_names[glsl_shader_info::FEAT_MAX_NUMBER]{
+ "plain",
+ "bilinear",
+ "bicubic",
+ "custom" };
/**
* fragment shader -> vertex shader mapping
*/
-static int glsl_mamebm_fsh2vsh[GLSL_SHADER_FEAT_MAX_NUMBER] =
+static const int glsl_mamebm_fsh2vsh[glsl_shader_info::FEAT_MAX_NUMBER] =
{
0, // plain -> general
0, // bilinear -> general
0, // bicubic -> general
- 1, // custom -> custom
-};
-
-static GLhandleARB glsl_mamebm_vsh_shader[GLSL_VERTEX_SHADER_MAX_NUMBER+9] =
-{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-}; /* general, custom0-9 */
-
-static GLhandleARB glsl_mamebm_fsh_shader [GLSL_SHADER_FEAT_MAX_NUMBER+9] =
-{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* rgb32 dir: plain, bilinear, bicubic, custom0-9 */
+ 1, // custom -> custom
};
-static GLhandleARB glsl_scrn_programs [10] =
-{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* rgb32: custom0-9, .. */
-};
-
-static GLhandleARB glsl_scrn_vsh_shader[10] =
-{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-}; /* custom0-9 */
-
-static GLhandleARB glsl_scrn_fsh_shader [10] =
-{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-}; /* rgb32: custom0-9 */
-
-const char * glsl_shader_get_filter_name_mamebm(int glslShaderFeature)
-{
- if ( !(0 <= glslShaderFeature && glslShaderFeature < GLSL_SHADER_FEAT_MAX_NUMBER) )
- return "illegal shader feature";
-
- return glsl_mamebm_filter_names[glslShaderFeature];
-}
-
-GLhandleARB glsl_shader_get_program_mamebm(int glslShaderFeature, int idx)
-{
- if ( !(0 <= glslShaderFeature && glslShaderFeature < GLSL_SHADER_FEAT_MAX_NUMBER) )
- return 0;
-
- return glsl_mamebm_programs[glslShaderFeature+idx];
-}
-
-GLhandleARB glsl_shader_get_program_scrn(int idx)
+class glsl_shader_impl : public glsl_shader_info
{
- if ( !(0 <= idx && idx < 10) )
- return 0;
-
- return glsl_scrn_programs[idx];
-}
+public:
+ glsl_shader_impl(
+#if defined(USE_DISPATCH_GL)
+ osd_gl_dispatch *gld
+#endif
+ )
+#if defined(USE_DISPATCH_GL)
+ : glsl_shader_info(gld)
+#endif
+ {
+ std::fill(std::begin(mamebm_programs), std::end(mamebm_programs), GLhandleARB(0));
+ std::fill(std::begin(mamebm_vsh_shader), std::end(mamebm_vsh_shader), GLhandleARB(0));
+ std::fill(std::begin(mamebm_fsh_shader), std::end(mamebm_fsh_shader), GLhandleARB(0));
+ std::fill(std::begin(scrn_programs), std::end(scrn_programs), GLhandleARB(0));
+ std::fill(std::begin(scrn_vsh_shader), std::end(scrn_vsh_shader), GLhandleARB(0));
+ std::fill(std::begin(scrn_fsh_shader), std::end(scrn_fsh_shader), GLhandleARB(0));
+ }
-glsl_shader_info *glsl_shader_init(osd_gl_context *gl_ctx)
-{
- int i,j, err;
+ bool initalize(osd_gl_context &gl_ctx)
+ {
+ if (!load_extension(gl_ctx))
+ return false;
- err = gl_shader_loadExtention(gl_ctx);
- if(err) return nullptr;
+ int err = 0;
- for (i=0; !err && i<GLSL_VERTEX_SHADER_INT_NUMBER; i++)
- {
- #ifdef GLSL_SOURCE_ON_DISK
- if(glsl_mamebm_vsh_files[i])
- err = gl_compile_shader_file ( &glsl_mamebm_vsh_shader[i], GL_VERTEX_SHADER_ARB,
- glsl_mamebm_vsh_files[i], 0);
- #else
- if(glsl_mamebm_vsh_sources[i])
- err = gl_compile_shader_source( &glsl_mamebm_vsh_shader[i], GL_VERTEX_SHADER_ARB,
- glsl_mamebm_vsh_sources[i], 0);
- #endif
+ for (int i = 0; !err && (i < GLSL_VERTEX_SHADER_INT_NUMBER); i++)
+ {
+#ifdef GLSL_SOURCE_ON_DISK
+ if (glsl_mamebm_vsh_files[i])
+ err = compile_file(
+ &mamebm_vsh_shader[i],
+ GL_VERTEX_SHADER_ARB,
+ glsl_mamebm_vsh_files[i],
+ false);
+#else
+ if (glsl_mamebm_vsh_sources[i])
+ err = compile_source(
+ &mamebm_vsh_shader[i],
+ GL_VERTEX_SHADER_ARB,
+ glsl_mamebm_vsh_sources[i],
+ false);
+#endif
+ }
+ if (err)
+ return false;
+
+ for (int j = 0; !err && (j < FEAT_INT_NUMBER); j++)
+ {
+#ifdef GLSL_SOURCE_ON_DISK
+ if (glsl_mamebm_fsh_files[j])
+ err = compile_files(
+ &mamebm_programs[j],
+ &mamebm_vsh_shader[glsl_mamebm_fsh2vsh[j]],
+ &mamebm_fsh_shader[j],
+ nullptr, // precompiled
+ glsl_mamebm_fsh_files[j],
+ false);
+#else
+ if (glsl_mamebm_fsh_sources[j])
+ err = compile_sources(
+ &mamebm_programs[j],
+ &mamebm_vsh_shader[glsl_mamebm_fsh2vsh[j]],
+ &mamebm_fsh_shader[j],
+ nullptr, // precompiled
+ glsl_mamebm_fsh_sources[j]);
+#endif
+ }
+ if (err)
+ return false;
+
+ return true;
}
- if(err) return nullptr;
-
- for (j=0; !err && j<GLSL_SHADER_FEAT_INT_NUMBER; j++)
+ virtual ~glsl_shader_impl()
{
- #ifdef GLSL_SOURCE_ON_DISK
- if(glsl_mamebm_fsh_files[j])
- err = gl_compile_shader_files (&glsl_mamebm_programs[j],
- &glsl_mamebm_vsh_shader[glsl_mamebm_fsh2vsh[j]],
- &glsl_mamebm_fsh_shader[j],
- nullptr /*precompiled*/, glsl_mamebm_fsh_files[j], 0);
- #else
- if(glsl_mamebm_fsh_sources[j])
- err = gl_compile_shader_sources(&glsl_mamebm_programs[j],
- &glsl_mamebm_vsh_shader[glsl_mamebm_fsh2vsh[j]],
- &glsl_mamebm_fsh_shader[j],
- nullptr /*precompiled*/, glsl_mamebm_fsh_sources[j]);
- #endif
+ pfn_glUseProgramObjectARB(0);
+ glFinish();
+
+ for (int i = 0; i < GLSL_VERTEX_SHADER_MAX_NUMBER + 9; i++)
+ {
+ if (mamebm_vsh_shader[i])
+ delete_shader(nullptr, &mamebm_vsh_shader[i], nullptr);
+ }
+
+ for (int j = 0; j < FEAT_MAX_NUMBER + 9; j++)
+ {
+ if (mamebm_fsh_shader[j])
+ delete_shader(nullptr, nullptr, &mamebm_fsh_shader[j]);
+ }
+
+ for (int j = 0; j < FEAT_MAX_NUMBER + 9; j++)
+ {
+ if (mamebm_programs[j])
+ delete_shader(&mamebm_programs[j], nullptr, nullptr);
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ if (scrn_vsh_shader[i])
+ delete_shader(nullptr, &scrn_vsh_shader[i], nullptr);
+ if (scrn_fsh_shader[i])
+ delete_shader(nullptr, nullptr, &scrn_fsh_shader[i]);
+ if (scrn_programs[i])
+ delete_shader(&scrn_programs[i], nullptr, nullptr);
+ }
}
- if (err) return nullptr;
- return (glsl_shader_info *) malloc(sizeof(glsl_shader_info *));
-}
-int glsl_shader_free(glsl_shader_info *shinfo)
-{
- int i,j;
+ virtual const char *get_filter_name_mamebm(int glslShaderFeature) override
+ {
+ if ((0 > glslShaderFeature) || (glslShaderFeature >= FEAT_MAX_NUMBER))
+ return "illegal shader feature";
- pfn_glUseProgramObjectARB(0); // back to fixed function pipeline
- glFinish();
+ return glsl_mamebm_filter_names[glslShaderFeature];
+ }
- for (i=0; i<GLSL_VERTEX_SHADER_MAX_NUMBER+9; i++)
+ virtual GLhandleARB get_program_mamebm(int glslShaderFeature, int idx) override
{
- if ( glsl_mamebm_vsh_shader[i] )
- (void) gl_delete_shader(nullptr, &glsl_mamebm_vsh_shader[i], nullptr);
+ if ((0 > glslShaderFeature) || (glslShaderFeature >= FEAT_MAX_NUMBER))
+ return 0;
+
+ return mamebm_programs[glslShaderFeature + idx];
}
- for (j=0; j<GLSL_SHADER_FEAT_MAX_NUMBER+9; j++)
+ virtual GLhandleARB get_program_scrn(int idx) override
{
- if ( glsl_mamebm_fsh_shader[j] )
- (void) gl_delete_shader(nullptr, nullptr, &glsl_mamebm_fsh_shader[j]);
+ if ((0 > idx) || (idx >= 10))
+ return 0;
+
+ return scrn_programs[idx];
}
- for (j=0; j<GLSL_SHADER_FEAT_MAX_NUMBER+9; j++)
+ virtual int add_mamebm(const char *custShaderPrefix, int idx) override
{
- if ( glsl_mamebm_programs[j] )
- (void) gl_delete_shader( &glsl_mamebm_programs[j], nullptr, nullptr);
+ int err;
+
+ err = compile_file(
+ &mamebm_vsh_shader[GLSL_VERTEX_SHADER_CUSTOM + idx],
+ GL_VERTEX_SHADER_ARB,
+ util::string_format("%s.vsh", custShaderPrefix).c_str(),
+ false);
+ if (err)
+ return err;
+
+ err = compile_files(
+ &mamebm_programs[FEAT_CUSTOM + idx],
+ &mamebm_vsh_shader[GLSL_VERTEX_SHADER_CUSTOM + idx],
+ &mamebm_fsh_shader[FEAT_CUSTOM + idx],
+ nullptr, // precompiled
+ util::string_format("%s_rgb32_dir.fsh", custShaderPrefix).c_str(),
+ false);
+ return err;
}
- for (i=0; i<10; i++)
+ virtual int add_scrn(const char *custShaderPrefix, int idx) override
{
- if ( glsl_scrn_vsh_shader[i] )
- (void) gl_delete_shader(nullptr, &glsl_scrn_vsh_shader[i], nullptr);
- if ( glsl_scrn_fsh_shader[i] )
- (void) gl_delete_shader(nullptr, nullptr, &glsl_scrn_fsh_shader[i]);
- if ( glsl_scrn_programs[i] )
- (void) gl_delete_shader( &glsl_scrn_programs[i], nullptr, nullptr);
+ int err;
+
+ err = compile_file(
+ &scrn_vsh_shader[idx],
+ GL_VERTEX_SHADER_ARB,
+ util::string_format("%s.vsh", custShaderPrefix).c_str(),
+ false);
+ if (err)
+ return err;
+
+ err = compile_files(
+ &scrn_programs[idx],
+ &scrn_vsh_shader[idx],
+ &scrn_fsh_shader[idx],
+ nullptr, // precompiled
+ util::string_format("%s.fsh", custShaderPrefix).c_str(),
+ false);
+ return err;
}
- free(shinfo);
- return 0;
-}
-
-int glsl_shader_add_mamebm(glsl_shader_info *shinfo, const char * custShaderPrefix, int idx)
-{
- int err;
- static char fname[8192];
-
- snprintf(fname, 8192, "%s.vsh", custShaderPrefix); fname[8191]=0;
-
- err = gl_compile_shader_file ( &glsl_mamebm_vsh_shader[GLSL_VERTEX_SHADER_CUSTOM+idx], GL_VERTEX_SHADER_ARB, fname, 0);
- if(err) return err;
-
- snprintf(fname, 8192, "%s_rgb32_dir.fsh", custShaderPrefix); fname[8191]=0;
+private:
+ GLhandleARB mamebm_programs[FEAT_MAX_NUMBER + 9]; // rgb32 dir: plain, bilinear, bicubic, custom0-9, ..
+ GLhandleARB mamebm_vsh_shader[GLSL_VERTEX_SHADER_MAX_NUMBER + 9]; // general, custom0-9
+ GLhandleARB mamebm_fsh_shader[FEAT_MAX_NUMBER+9]; // rgb32 dir: plain, bilinear, bicubic, custom0-9
+ GLhandleARB scrn_programs[10]; // rgb32: custom0-9, ..
+ GLhandleARB scrn_vsh_shader[10]; // custom0-9
+ GLhandleARB scrn_fsh_shader[10]; // rgb32: custom0-9
+};
- err = gl_compile_shader_files (&glsl_mamebm_programs[GLSL_SHADER_FEAT_CUSTOM+idx],
- &glsl_mamebm_vsh_shader[GLSL_VERTEX_SHADER_CUSTOM+idx],
- &glsl_mamebm_fsh_shader[GLSL_SHADER_FEAT_CUSTOM+idx],
- nullptr /*precompiled*/, fname, 0);
+} // anonymous namespace
- return err;
-}
-int glsl_shader_add_scrn(glsl_shader_info *shinfo, const char * custShaderPrefix, int idx)
+std::unique_ptr<glsl_shader_info> glsl_shader_info::init(
+ osd_gl_context &gl_ctx
+#if defined(USE_DISPATCH_GL)
+ , osd_gl_dispatch *gld
+#endif
+ )
{
- int err;
- static char fname[8192];
-
- snprintf(fname, 8192, "%s.vsh", custShaderPrefix); fname[8191]=0;
-
- err = gl_compile_shader_file ( &glsl_scrn_vsh_shader[idx], GL_VERTEX_SHADER_ARB, fname, 0);
- if(err) return err;
-
- snprintf(fname, 8192, "%s.fsh", custShaderPrefix); fname[8191]=0;
-
- err = gl_compile_shader_files (&glsl_scrn_programs[idx],
- &glsl_scrn_vsh_shader[idx],
- &glsl_scrn_fsh_shader[idx],
- nullptr /*precompiled*/, fname, 0);
- return err;
+ auto result = std::make_unique<glsl_shader_impl>(
+#if defined(USE_DISPATCH_GL)
+ gld
+#endif
+ );
+ if (!result->initalize(gl_ctx))
+ result.reset();
+ return result;
}
diff --git a/src/osd/modules/opengl/gl_shader_mgr.h b/src/osd/modules/opengl/gl_shader_mgr.h
index f95ec8c2244..ad9e248ac5f 100644
--- a/src/osd/modules/opengl/gl_shader_mgr.h
+++ b/src/osd/modules/opengl/gl_shader_mgr.h
@@ -1,51 +1,57 @@
// license:BSD-3-Clause
// copyright-holders:Sven Gothel
+#ifndef MAME_OSD_OPENGL_GL_SHADER_MGR_H
+#define MAME_OSD_OPENGL_GL_SHADER_MGR_H
-#ifndef GL_SHADER_MGR_H
-#define GL_SHADER_MGR_H
+#pragma once
+#include "gl_shader_tool.h"
#include "osd_opengl.h"
+#include <memory>
+
+
// #define GLSL_SOURCE_ON_DISK 1
-enum GLSL_SHADER_FEATURE {
- GLSL_SHADER_FEAT_PLAIN,
- GLSL_SHADER_FEAT_BILINEAR,
- GLSL_SHADER_FEAT_BICUBIC,
- GLSL_SHADER_FEAT_INT_NUMBER,
- GLSL_SHADER_FEAT_CUSTOM = GLSL_SHADER_FEAT_INT_NUMBER,
- GLSL_SHADER_FEAT_MAX_NUMBER
-};
-// old code passed sdl_info * to functions here
-// however the parameter was not used
-// changed interface to more generic one.
-struct glsl_shader_info
+class glsl_shader_info : public gl_shader_tool
{
- int dummy; // avoid compiler breakage
+public:
+ enum FEATURE
+ {
+ FEAT_PLAIN,
+ FEAT_BILINEAR,
+ FEAT_BICUBIC,
+ FEAT_INT_NUMBER,
+ FEAT_CUSTOM = FEAT_INT_NUMBER,
+ FEAT_MAX_NUMBER
+ };
+
+ using gl_shader_tool::gl_shader_tool;
+
+ virtual ~glsl_shader_info() = default;
+
+ /**
+ * returns the GLSL program if ok/available, otherwise 0
+ */
+ virtual GLhandleARB get_program_mamebm(int glslShaderFeature, int idx) = 0;
+
+ virtual const char *get_filter_name_mamebm(int glslShaderFeature) = 0;
+
+ virtual int add_mamebm(const char *custShaderPrefix, int idx) = 0;
+
+ virtual GLhandleARB get_program_scrn(int idx) = 0;
+ virtual int add_scrn(const char *custShaderPrefix, int idx) = 0;
+
+ /**
+ * returns pointer if OK, otherwise nullptr
+ */
+ static std::unique_ptr<glsl_shader_info> init(
+ osd_gl_context &gl_ctx
+#if defined(USE_DISPATCH_GL)
+ , osd_gl_dispatch *gld
+#endif
+ );
};
-
-/**
- * returns pointer if ok, otherwise nullptr
- */
-glsl_shader_info *glsl_shader_init(osd_gl_context *gl_ctx);
-
-/**
- * returns 0 if ok, otherwise an error value
- */
-int glsl_shader_free(glsl_shader_info *shinfo);
-
-/**
- * returns the GLSL program if ok/available, otherwise 0
- */
-GLhandleARB glsl_shader_get_program_mamebm(int glslShaderFeature, int idx);
-
-const char * glsl_shader_get_filter_name_mamebm(int glslShaderFeature);
-
-int glsl_shader_add_mamebm(glsl_shader_info *shinfo, const char * custShaderPrefix, int idx);
-
-GLhandleARB glsl_shader_get_program_scrn(int idx);
-int glsl_shader_add_scrn(glsl_shader_info *shinfo, const char * custShaderPrefix, int idx);
-
-#endif // GL_SHADER_MGR_H
+#endif // MAME_OSD_OPENGL_GL_SHADER_MGR_H
diff --git a/src/osd/modules/opengl/gl_shader_tool.cpp b/src/osd/modules/opengl/gl_shader_tool.cpp
index dedb59fbb7c..fb880178b98 100644
--- a/src/osd/modules/opengl/gl_shader_tool.cpp
+++ b/src/osd/modules/opengl/gl_shader_tool.cpp
@@ -15,59 +15,90 @@
*
*/
-#include "emu.h"
#include "gl_shader_tool.h"
-PFNGLGETOBJECTPARAMETERIVARBPROC pfn_glGetObjectParameterivARB= nullptr;
-PFNGLGETINFOLOGARBPROC pfn_glGetInfoLogARB= nullptr;
-PFNGLDELETEOBJECTARBPROC pfn_glDeleteObjectARB= nullptr;
-PFNGLCREATESHADEROBJECTARBPROC pfn_glCreateShaderObjectARB= nullptr;
-PFNGLSHADERSOURCEARBPROC pfn_glShaderSourceARB= nullptr;
-PFNGLCOMPILESHADERARBPROC pfn_glCompileShaderARB= nullptr;
-PFNGLCREATEPROGRAMOBJECTARBPROC pfn_glCreateProgramObjectARB= nullptr;
-PFNGLATTACHOBJECTARBPROC pfn_glAttachObjectARB= nullptr;
-PFNGLLINKPROGRAMARBPROC pfn_glLinkProgramARB= nullptr;
-PFNGLVALIDATEPROGRAMARBPROC pfn_glValidateProgramARB= nullptr;
-PFNGLUSEPROGRAMOBJECTARBPROC pfn_glUseProgramObjectARB= nullptr;
-PFNGLGETUNIFORMLOCATIONARBPROC pfn_glGetUniformLocationARB= nullptr;
-PFNGLUNIFORM1FARBPROC pfn_glUniform1fARB= nullptr;
-PFNGLUNIFORM1IARBPROC pfn_glUniform1iARB= nullptr;
-PFNGLUNIFORM1FVARBPROC pfn_glUniform1fvARB= nullptr;
-PFNGLUNIFORM2FVARBPROC pfn_glUniform2fvARB= nullptr;
-PFNGLUNIFORM3FVARBPROC pfn_glUniform3fvARB= nullptr;
-PFNGLUNIFORM4FVARBPROC pfn_glUniform4fvARB= nullptr;
-PFNGLUNIFORM1IVARBPROC pfn_glUniform1ivARB= nullptr;
-PFNGLUNIFORM2IVARBPROC pfn_glUniform2ivARB= nullptr;
-PFNGLUNIFORM3IVARBPROC pfn_glUniform3ivARB= nullptr;
-PFNGLUNIFORM4IVARBPROC pfn_glUniform4ivARB= nullptr;
-
-
-int gl_shader_loadExtention(osd_gl_context *gl_ctx)
+#include "osdcore.h"
+
+
+#define GL_CHECK_ERROR_VERBOSE() check_error(CHECK_ALWAYS_VERBOSE, __FILE__, __LINE__)
+#define GL_CHECK_ERROR_NORMAL() check_error(CHECK_VERBOSE, __FILE__, __LINE__)
+#define GL_CHECK_ERROR_QUIET() check_error(CHECK_QUIET, __FILE__, __LINE__)
+#define GL_CHECK_ERROR(m) check_error(m, __FILE__, __LINE__)
+
+#define GL_SHADER_CHECK_ERROR_VERBOSE(o,q) check_error(o, q, CHECK_ALWAYS_VERBOSE, __FILE__, __LINE__)
+#define GL_SHADER_CHECK_ERROR_NORMAL(o,q) check_error(o, q, CHECK_VERBOSE, __FILE__, __LINE__)
+#define GL_SHADER_CHECK_ERROR_QUIET(o,q) check_error(o, q, CHECK_QUIET, __FILE__, __LINE__)
+#define GL_SHADER_CHECK_ERROR(o,q,m) check_error(o, q, m, __FILE__, __LINE__)
+
+#ifdef GL_SHADER_TOOL_DEBUG
+ #define GL_SHADER_CHECK(o, q) GL_SHADER_CHECK_ERROR_VERBOSE(o, q)
+ #define GL_CHECK() GL_CHECK_ERROR_VERBOSE()
+#else
+ #define GL_SHADER_CHECK(o, q) GL_SHADER_CHECK_ERROR_NORMAL(o, q)
+ #define GL_CHECK() GL_CHECK_ERROR_NORMAL()
+#endif
+
+
+gl_shader_tool::gl_shader_tool(
+#if defined(USE_DISPATCH_GL)
+ osd_gl_dispatch *gld
+#endif
+ )
+ : pfn_glGetObjectParameterivARB(nullptr)
+ , pfn_glGetInfoLogARB(nullptr)
+ , pfn_glDeleteObjectARB(nullptr)
+ , pfn_glCreateShaderObjectARB(nullptr)
+ , pfn_glShaderSourceARB(nullptr)
+ , pfn_glCompileShaderARB(nullptr)
+ , pfn_glCreateProgramObjectARB(nullptr)
+ , pfn_glAttachObjectARB(nullptr)
+ , pfn_glLinkProgramARB(nullptr)
+ , pfn_glValidateProgramARB(nullptr)
+ , pfn_glUseProgramObjectARB(nullptr)
+ , pfn_glGetUniformLocationARB(nullptr)
+ , pfn_glUniform1fARB(nullptr)
+ , pfn_glUniform1iARB(nullptr)
+ , pfn_glUniform1fvARB(nullptr)
+ , pfn_glUniform2fvARB(nullptr)
+ , pfn_glUniform3fvARB(nullptr)
+ , pfn_glUniform4fvARB(nullptr)
+ , pfn_glUniform1ivARB(nullptr)
+ , pfn_glUniform2ivARB(nullptr)
+ , pfn_glUniform3ivARB(nullptr)
+ , pfn_glUniform4ivARB(nullptr)
+#if defined(USE_DISPATCH_GL)
+ , gl_dispatch(gld)
+#endif
+{
+}
+
+
+bool gl_shader_tool::load_extension(osd_gl_context &gl_ctx)
{
- pfn_glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) gl_ctx->getProcAddress("glGetObjectParameterivARB");
- pfn_glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) gl_ctx->getProcAddress ("glGetInfoLogARB");
- pfn_glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) gl_ctx->getProcAddress ("glDeleteObjectARB");
- pfn_glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) gl_ctx->getProcAddress ("glCreateShaderObjectARB");
- pfn_glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) gl_ctx->getProcAddress ("glShaderSourceARB");
- pfn_glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) gl_ctx->getProcAddress ("glCompileShaderARB");
- pfn_glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) gl_ctx->getProcAddress ("glCreateProgramObjectARB");
- pfn_glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) gl_ctx->getProcAddress ("glAttachObjectARB");
- pfn_glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) gl_ctx->getProcAddress ("glLinkProgramARB");
- pfn_glValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC) gl_ctx->getProcAddress ("glValidateProgramARB");
- pfn_glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) gl_ctx->getProcAddress ("glUseProgramObjectARB");
- pfn_glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) gl_ctx->getProcAddress ("glGetUniformLocationARB");
- pfn_glUniform1fARB = (PFNGLUNIFORM1FARBPROC) gl_ctx->getProcAddress ("glUniform1fARB");
- pfn_glUniform1iARB = (PFNGLUNIFORM1IARBPROC) gl_ctx->getProcAddress ("glUniform1iARB");
- pfn_glUniform1fvARB = (PFNGLUNIFORM1FVARBPROC) gl_ctx->getProcAddress ("glUniform1fvARB");
- pfn_glUniform2fvARB = (PFNGLUNIFORM2FVARBPROC) gl_ctx->getProcAddress ("glUniform2fvARB");
- pfn_glUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) gl_ctx->getProcAddress ("glUniform3fvARB");
- pfn_glUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) gl_ctx->getProcAddress ("glUniform4fvARB");
- pfn_glUniform1ivARB = (PFNGLUNIFORM1IVARBPROC) gl_ctx->getProcAddress ("glUniform1ivARB");
- pfn_glUniform2ivARB = (PFNGLUNIFORM2IVARBPROC) gl_ctx->getProcAddress ("glUniform2ivARB");
- pfn_glUniform3ivARB = (PFNGLUNIFORM3IVARBPROC) gl_ctx->getProcAddress ("glUniform3ivARB");
- pfn_glUniform4ivARB = (PFNGLUNIFORM4IVARBPROC) gl_ctx->getProcAddress ("glUniform4ivARB");
-
- if ( pfn_glGetObjectParameterivARB && pfn_glGetInfoLogARB && pfn_glDeleteObjectARB && pfn_glCreateShaderObjectARB &&
+ gl_ctx.get_proc_address(pfn_glGetObjectParameterivARB, "glGetObjectParameterivARB");
+ gl_ctx.get_proc_address(pfn_glGetInfoLogARB, "glGetInfoLogARB");
+ gl_ctx.get_proc_address(pfn_glDeleteObjectARB, "glDeleteObjectARB");
+ gl_ctx.get_proc_address(pfn_glCreateShaderObjectARB, "glCreateShaderObjectARB");
+ gl_ctx.get_proc_address(pfn_glShaderSourceARB, "glShaderSourceARB");
+ gl_ctx.get_proc_address(pfn_glCompileShaderARB, "glCompileShaderARB");
+ gl_ctx.get_proc_address(pfn_glCreateProgramObjectARB, "glCreateProgramObjectARB");
+ gl_ctx.get_proc_address(pfn_glAttachObjectARB, "glAttachObjectARB");
+ gl_ctx.get_proc_address(pfn_glLinkProgramARB, "glLinkProgramARB");
+ gl_ctx.get_proc_address(pfn_glValidateProgramARB, "glValidateProgramARB");
+ gl_ctx.get_proc_address(pfn_glUseProgramObjectARB, "glUseProgramObjectARB");
+ gl_ctx.get_proc_address(pfn_glGetUniformLocationARB, "glGetUniformLocationARB");
+ gl_ctx.get_proc_address(pfn_glUniform1fARB, "glUniform1fARB");
+ gl_ctx.get_proc_address(pfn_glUniform1iARB, "glUniform1iARB");
+ gl_ctx.get_proc_address(pfn_glUniform1fvARB, "glUniform1fvARB");
+ gl_ctx.get_proc_address(pfn_glUniform2fvARB, "glUniform2fvARB");
+ gl_ctx.get_proc_address(pfn_glUniform3fvARB, "glUniform3fvARB");
+ gl_ctx.get_proc_address(pfn_glUniform4fvARB, "glUniform4fvARB");
+ gl_ctx.get_proc_address(pfn_glUniform1ivARB, "glUniform1ivARB");
+ gl_ctx.get_proc_address(pfn_glUniform2ivARB, "glUniform2ivARB");
+ gl_ctx.get_proc_address(pfn_glUniform3ivARB, "glUniform3ivARB");
+ gl_ctx.get_proc_address(pfn_glUniform4ivARB, "glUniform4ivARB");
+
+ if (pfn_glGetObjectParameterivARB && pfn_glGetInfoLogARB && pfn_glDeleteObjectARB && pfn_glCreateShaderObjectARB &&
pfn_glShaderSourceARB && pfn_glCompileShaderARB && pfn_glCreateProgramObjectARB && pfn_glAttachObjectARB &&
pfn_glLinkProgramARB && pfn_glValidateProgramARB && pfn_glUseProgramObjectARB &&
pfn_glGetUniformLocationARB && pfn_glUniform1fARB && pfn_glUniform1iARB &&
@@ -75,62 +106,52 @@ int gl_shader_loadExtention(osd_gl_context *gl_ctx)
pfn_glUniform1ivARB && pfn_glUniform2ivARB && pfn_glUniform3ivARB && pfn_glUniform4ivARB
)
{
- return 0;
+ return true;
}
osd_printf_error("OpenGL: missing ARB shader function: ");
- if (!pfn_glGetObjectParameterivARB) osd_printf_error("glGetObjectParameterivARB, ");
- if (!pfn_glGetInfoLogARB) osd_printf_error("glGetInfoLogARB, ");
- if (!pfn_glDeleteObjectARB) osd_printf_error("glDeleteObjectARB, ");
- if (!pfn_glCreateShaderObjectARB) osd_printf_error("glCreateShaderObjectARB, ");
- if (!pfn_glShaderSourceARB) osd_printf_error("glShaderSourceARB, ");
- if (!pfn_glCompileShaderARB) osd_printf_error("glCompileShaderARB, ");
- if (!pfn_glCreateProgramObjectARB) osd_printf_error("glCreateProgramObjectARB, ");
- if (!pfn_glAttachObjectARB) osd_printf_error("glAttachObjectARB, ");
- if (!pfn_glLinkProgramARB) osd_printf_error("glLinkProgramARB, ");
- if (!pfn_glValidateProgramARB) osd_printf_error("glValidateProgramARB, ");
- if (!pfn_glUseProgramObjectARB) osd_printf_error("glUseProgramObjectARB, ");
- if (!pfn_glGetUniformLocationARB) osd_printf_error("glGetUniformLocationARB, ");
- if (!pfn_glUniform1fARB) osd_printf_error("glUniform1fARB, ");
- if (!pfn_glUniform1iARB) osd_printf_error("glUniform1iARB");
- if (!pfn_glUniform1fvARB) osd_printf_error("glUniform1fvARB, ");
- if (!pfn_glUniform2fvARB) osd_printf_error("glUniform2fvARB, ");
- if (!pfn_glUniform3fvARB) osd_printf_error("glUniform3fvARB, ");
- if (!pfn_glUniform4fvARB) osd_printf_error("glUniform4fvARB, ");
- if (!pfn_glUniform1ivARB) osd_printf_error("glUniform1ivARB");
- if (!pfn_glUniform2ivARB) osd_printf_error("glUniform2ivARB");
- if (!pfn_glUniform3ivARB) osd_printf_error("glUniform3ivARB");
- if (!pfn_glUniform4ivARB) osd_printf_error("glUniform4ivARB");
+ if (!pfn_glGetObjectParameterivARB) osd_printf_error(" glGetObjectParameterivARB");
+ if (!pfn_glGetInfoLogARB) osd_printf_error(" glGetInfoLogARB");
+ if (!pfn_glDeleteObjectARB) osd_printf_error(" glDeleteObjectARB");
+ if (!pfn_glCreateShaderObjectARB) osd_printf_error(" glCreateShaderObjectARB");
+ if (!pfn_glShaderSourceARB) osd_printf_error(" glShaderSourceARB");
+ if (!pfn_glCompileShaderARB) osd_printf_error(" glCompileShaderARB");
+ if (!pfn_glCreateProgramObjectARB) osd_printf_error(" glCreateProgramObjectARB");
+ if (!pfn_glAttachObjectARB) osd_printf_error(" glAttachObjectARB");
+ if (!pfn_glLinkProgramARB) osd_printf_error(" glLinkProgramARB");
+ if (!pfn_glValidateProgramARB) osd_printf_error(" glValidateProgramARB");
+ if (!pfn_glUseProgramObjectARB) osd_printf_error(" glUseProgramObjectARB");
+ if (!pfn_glGetUniformLocationARB) osd_printf_error(" glGetUniformLocationARB");
+ if (!pfn_glUniform1fARB) osd_printf_error(" glUniform1fARB");
+ if (!pfn_glUniform1iARB) osd_printf_error(" glUniform1iARB");
+ if (!pfn_glUniform1fvARB) osd_printf_error(" glUniform1fvARB");
+ if (!pfn_glUniform2fvARB) osd_printf_error(" glUniform2fvARB");
+ if (!pfn_glUniform3fvARB) osd_printf_error(" glUniform3fvARB");
+ if (!pfn_glUniform4fvARB) osd_printf_error(" glUniform4fvARB");
+ if (!pfn_glUniform1ivARB) osd_printf_error(" glUniform1ivARB");
+ if (!pfn_glUniform2ivARB) osd_printf_error(" glUniform2ivARB");
+ if (!pfn_glUniform3ivARB) osd_printf_error(" glUniform3ivARB");
+ if (!pfn_glUniform4ivARB) osd_printf_error(" glUniform4ivARB");
osd_printf_error("\n");
- return -1;
+ return false;
}
-int gl_check_error(GLSLCheckMode m, const char *file, const int line)
+int gl_shader_tool::check_error(GLSLCheckMode m, const char *file, const int line)
{
- GLenum glerr = glGetError();
-
- if (GL_NO_ERROR != glerr)
- {
- if ( CHECK_VERBOSE <= m )
- {
- osd_printf_warning( "%s:%d: GL Error: %d 0x%X\n", file, line, (int)glerr, (unsigned int)glerr);
- }
- }
- return (GL_NO_ERROR != glerr)? glerr : 0;
+ GLenum const glerr = glGetError();
+ if (GL_NO_ERROR != glerr)
+ {
+ if (CHECK_VERBOSE <= m)
+ osd_printf_warning("%s:%d: GL Error: %d 0x%X\n", file, line, int(glerr), unsigned(glerr));
+ }
+ return (GL_NO_ERROR != glerr) ? glerr : 0;
}
-int gl_shader_check_error(GLhandleARB obj, GLenum obj_query, GLSLCheckMode m, const char *file, const int line)
+int gl_shader_tool::check_error(GLhandleARB obj, GLenum obj_query, GLSLCheckMode m, const char *file, const int line)
{
- GLsizei length;
- GLcharARB buffer[255];
- GLenum glerr;
- GLint param;
- int res=0;
-
- glerr = gl_check_error(m, file, line);
-
- if(!obj)
+ GLenum const glerr = check_error(m, file, line);
+ if (!obj)
return glerr;
if(obj_query != GL_OBJECT_TYPE_ARB &&
@@ -144,79 +165,88 @@ int gl_shader_check_error(GLhandleARB obj, GLenum obj_query, GLSLCheckMode m, co
return -1;
}
+ GLint param;
pfn_glGetObjectParameterivARB(obj, obj_query, &param);
+ int res = 0;
switch(obj_query)
{
- case GL_OBJECT_TYPE_ARB:
- if( param!=GL_PROGRAM_OBJECT_ARB && param!=GL_SHADER_OBJECT_ARB )
+ case GL_OBJECT_TYPE_ARB:
+ if (param != GL_PROGRAM_OBJECT_ARB && param != GL_SHADER_OBJECT_ARB)
{
if ( CHECK_VERBOSE <= m )
osd_printf_warning("%s:%d: GL Error: object type 0x%X generation failed\n", file, line, (unsigned int)(uintptr_t)obj);
res=-1;
- } else if ( CHECK_ALWAYS_VERBOSE <= m )
+ }
+ else if (CHECK_ALWAYS_VERBOSE <= m)
{
- if(param==GL_PROGRAM_OBJECT_ARB)
+ if (param==GL_PROGRAM_OBJECT_ARB)
osd_printf_warning("%s:%d: GL Error: object type 0x%X is PROGRAM, successful\n", file, line, (unsigned int)(uintptr_t)obj);
else
osd_printf_warning("%s:%d: GL Info: object type 0x%X is SHADER, successful\n", file, line, (unsigned int)(uintptr_t)obj);
}
break;
- case GL_OBJECT_DELETE_STATUS_ARB:
- if(param!=1)
+ case GL_OBJECT_DELETE_STATUS_ARB:
+ if (param != 1)
{
- if ( CHECK_ALWAYS_VERBOSE <= m )
+ if (CHECK_ALWAYS_VERBOSE <= m)
osd_printf_warning("%s:%d: GL Info: object 0x%X not yet marked for deletion\n", file, line, (unsigned int)(uintptr_t)obj);
- } else if ( CHECK_ALWAYS_VERBOSE <= m )
+ }
+ else if (CHECK_ALWAYS_VERBOSE <= m)
{
osd_printf_warning("%s:%d: GL Info: object 0x%X deletion successful\n", file, line, (unsigned int)(uintptr_t)obj);
}
break;
- case GL_OBJECT_COMPILE_STATUS_ARB:
- if(param!=1)
+ case GL_OBJECT_COMPILE_STATUS_ARB:
+ if (param != 1)
{
- if ( CHECK_VERBOSE <= m )
+ if (CHECK_VERBOSE <= m)
osd_printf_warning("%s:%d: GL Error: object 0x%X compilation failed\n", file, line, (unsigned int)(uintptr_t)obj);
- res=-1;
- } else if ( CHECK_ALWAYS_VERBOSE <= m )
+ res = -1;
+ }
+ else if (CHECK_ALWAYS_VERBOSE <= m)
{
osd_printf_warning("%s:%d: GL Info: object 0x%X compiled successful\n", file, line, (unsigned int)(uintptr_t)obj);
}
break;
- case GL_OBJECT_LINK_STATUS_ARB:
- if(param!=1)
+ case GL_OBJECT_LINK_STATUS_ARB:
+ if (param != 1)
{
- if ( CHECK_VERBOSE <= m )
+ if (CHECK_VERBOSE <= m)
osd_printf_warning("%s:%d: GL Error: object 0x%X linking failed\n", file, line, (unsigned int)(uintptr_t)obj);
- res=-1;
- } else if ( CHECK_ALWAYS_VERBOSE <= m )
+ res = -1;
+ }
+ else if (CHECK_ALWAYS_VERBOSE <= m)
{
osd_printf_warning("%s:%d: GL Info: object 0x%X linked successful\n", file, line, (unsigned int)(uintptr_t)obj);
}
break;
- case GL_OBJECT_VALIDATE_STATUS_ARB:
- if(param!=1)
+ case GL_OBJECT_VALIDATE_STATUS_ARB:
+ if (param != 1)
{
- if ( CHECK_VERBOSE <= m )
+ if (CHECK_VERBOSE <= m)
osd_printf_warning("%s:%d: GL Error: object 0x%X validation failed\n", file, line, (unsigned int)(uintptr_t)obj);
- res=-1;
- } else if ( CHECK_ALWAYS_VERBOSE <= m )
+ res = -1;
+ }
+ else if (CHECK_ALWAYS_VERBOSE <= m
+ )
{
osd_printf_warning("%s:%d: GL Info: object 0x%X validation successful\n", file, line, (unsigned int)(uintptr_t)obj);
}
break;
- }
+ }
- if ( res<0 || CHECK_ALWAYS_VERBOSE <= m )
+ if (res < 0 || CHECK_ALWAYS_VERBOSE <= m)
{
+ GLsizei length;
+ GLcharARB buffer[255];
length=0;
pfn_glGetInfoLogARB(obj, sizeof(buffer), &length, buffer);
- if(length>0)
+ if (length>0)
osd_printf_warning("%s:%d glInfoLog: %s\n", file, line, buffer);
}
- (void) glGetError(); // ;-)
-
+ (void)glGetError(); // ;-)
return res;
}
@@ -234,157 +264,175 @@ int gl_round_to_pow2(int v)
return v;
}
-int gl_texture_check_size(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height,
- GLint border, GLenum format, GLenum type,
- GLint *avail_width, GLint *avail_height,
- int verbose)
+int gl_shader_tool::texture_check_size(
+ GLenum target,
+ GLint level,
+ GLint internalFormat,
+ GLsizei width,
+ GLsizei height,
+ GLint border,
+ GLenum format,
+ GLenum type,
+ GLint *avail_width,
+ GLint *avail_height,
+ bool verbose)
{
- int err=1;
- GLenum texTargetProxy = (target==GL_TEXTURE_RECTANGLE_ARB)?GL_PROXY_TEXTURE_RECTANGLE_ARB:GL_PROXY_TEXTURE_2D;
-
- if ( !avail_width || !avail_height)
- return -1;
+ if (!avail_width || !avail_height)
+ return -1;
*avail_width = 0;
*avail_height = 0;
GL_CHECK_ERROR_QUIET();
- /* Test the max texture size */
- while(err && width>=1 && height>=1 /* && width>=64 && height>=64 */)
- {
- glTexImage2D (texTargetProxy, level,
- internalFormat,
- width, height,
- border, format, type, nullptr);
- if ( 0!=(err=GL_CHECK_ERROR_NORMAL() )) return err;
-
- glGetTexLevelParameteriv( texTargetProxy, level, GL_TEXTURE_WIDTH, avail_width);
- glGetTexLevelParameteriv( texTargetProxy, level, GL_TEXTURE_HEIGHT, avail_height);
- if ( 0!=(err=GL_CHECK_ERROR_NORMAL() )) return err;
-
- if ( (*avail_width) != width || (*avail_height) != height )
+ // Test the max texture size
+ int err = 1;
+ GLenum const texTargetProxy = (target == GL_TEXTURE_RECTANGLE_ARB) ? GL_PROXY_TEXTURE_RECTANGLE_ARB : GL_PROXY_TEXTURE_2D;
+ while (err && width>=1 && height>=1 /* && width>=64 && height>=64 */)
{
- err=1;
-
- if(verbose)
+ glTexImage2D(texTargetProxy, level,
+ internalFormat,
+ width, height,
+ border, format, type, nullptr);
+ if (0 != (err=GL_CHECK_ERROR_NORMAL()))
+ return err;
+
+ glGetTexLevelParameteriv(texTargetProxy, level, GL_TEXTURE_WIDTH, avail_width);
+ glGetTexLevelParameteriv(texTargetProxy, level, GL_TEXTURE_HEIGHT, avail_height);
+ if (0 != (err=GL_CHECK_ERROR_NORMAL()))
+ return err;
+
+ if ((*avail_width != width) || (*avail_height != height))
{
- osd_printf_warning("gl_texture_size_check: "
- "TexImage2D(0x%X, %d, 0x%X, %d, %d, %d, 0x%X, 0x%X): returned size does not match: %dx%d\n",
- (unsigned int)target, (int)level, (int)internalFormat,
- (int)width, (int)height, (int)border, (unsigned int)format, (unsigned int)type,
- (int)*avail_width, (int)*avail_height);
- }
-
- if ( (*avail_width) == width )
- height /= 2;
- else if ( (*avail_height) == height )
- width /= 2;
- else if (width > height)
+ err = 1;
+
+ if (verbose)
+ {
+ osd_printf_warning("gl_texture_size_check: "
+ "TexImage2D(0x%X, %d, 0x%X, %d, %d, %d, 0x%X, 0x%X): returned size does not match: %dx%d\n",
+ (unsigned int)target, (int)level, (int)internalFormat,
+ width, height, border, (unsigned int)format, (unsigned int)type,
+ *avail_width, *avail_height);
+ }
+
+ if (*avail_width == width)
+ height /= 2;
+ else if (*avail_height == height)
width /= 2;
- else
+ else if (width > height)
+ width /= 2;
+ else
height /= 2;
- if(verbose)
+ if (verbose)
+ {
+ osd_printf_verbose("gl_texture_size_check: trying [%dx%d] !\n", height, width);
+ }
+ }
+ else
{
- fprintf (stderr, "gl_texture_size_check: trying [%dx%d] !\n", (int)height, (int)width);
+ err = 0;
}
- } else {
- err=0;
- }
}
- if(!err)
+ if (!err)
{
- *avail_width = width;
+ *avail_width = width;
*avail_height = height;
}
return err;
}
-static int delete_shader_tool( GLhandleARB *program, GLhandleARB *vertex_shader, GLhandleARB *fragment_shader, int externalcall)
+int gl_shader_tool::delete_shader_tool(
+ GLhandleARB *program,
+ GLhandleARB *vertex_shader,
+ GLhandleARB *fragment_shader,
+ bool externalcall)
{
- int res=0;
+ int res = 0;
GL_CHECK_ERROR_QUIET();
- if(program!= nullptr && *program!=0)
+ if (program && *program!=0)
{
pfn_glDeleteObjectARB(*program);
- if(externalcall)
- {
+ if (externalcall)
res |= GL_SHADER_CHECK(*program, GL_OBJECT_DELETE_STATUS_ARB);
- }
- *program=0;
+ *program = 0;
}
- if(vertex_shader!= nullptr && *vertex_shader!=0)
+ if (vertex_shader && *vertex_shader!=0)
{
pfn_glDeleteObjectARB(*vertex_shader);
- if(externalcall)
- {
+ if (externalcall)
res |= GL_SHADER_CHECK(*vertex_shader, GL_OBJECT_DELETE_STATUS_ARB);
- }
*vertex_shader=0;
}
- if(fragment_shader!= nullptr && *fragment_shader!=0)
+ if (fragment_shader && *fragment_shader!=0)
{
pfn_glDeleteObjectARB(*fragment_shader);
- if(externalcall)
- {
+ if (externalcall)
res |= GL_SHADER_CHECK(*fragment_shader, GL_OBJECT_DELETE_STATUS_ARB);
- }
*fragment_shader=0;
}
- return res;
+ return res;
}
-int gl_compile_shader_source( GLhandleARB *shader, GLenum type, const char * shader_source, int verbose )
+int gl_shader_tool::compile_source(
+ GLhandleARB *shader,
+ GLenum type,
+ const char *shader_source,
+ bool verbose)
{
- int err = 0;
+ int err = 0;
- if(shader== nullptr || shader_source== nullptr)
+ if (!shader || !shader_source)
{
- if(shader== nullptr)
+ if (!shader)
osd_printf_warning("error: gl_compile_shader_source: nullptr shader passed\n");
- if(shader_source== nullptr)
+ if (!shader_source)
osd_printf_warning("error: gl_compile_shader_source: nullptr shader source passed\n");
return -1;
}
- *shader = pfn_glCreateShaderObjectARB(type);
- err=GL_SHADER_CHECK(*shader, GL_OBJECT_TYPE_ARB);
- if(err) goto errout;
+ *shader = pfn_glCreateShaderObjectARB(type);
+ err = GL_SHADER_CHECK(*shader, GL_OBJECT_TYPE_ARB);
+ if (err)
+ goto errout;
- pfn_glShaderSourceARB(*shader, 1, (const GLcharARB **)&shader_source, nullptr);
+ pfn_glShaderSourceARB(*shader, 1, (const GLcharARB **)&shader_source, nullptr);
- pfn_glCompileShaderARB(*shader);
- err=GL_SHADER_CHECK(*shader, GL_OBJECT_COMPILE_STATUS_ARB);
- if(err) goto errout;
+ pfn_glCompileShaderARB(*shader);
+ err = GL_SHADER_CHECK(*shader, GL_OBJECT_COMPILE_STATUS_ARB);
+ if (err)
+ goto errout;
- if(verbose)
+ if (verbose)
osd_printf_warning( "<%s>\n", shader_source);
return 0;
errout:
- if(*shader!=0)
- {
+ if (*shader != 0)
pfn_glDeleteObjectARB(*shader);
- }
+
osd_printf_warning("failed to process shader: <%s>\n", shader_source);
- return err;
+ return err;
}
-int gl_compile_shader_file( GLhandleARB *shader, GLenum type, const char * shader_file, int verbose )
+int gl_shader_tool::compile_file(
+ GLhandleARB *shader,
+ GLenum type,
+ const char *shader_file,
+ bool verbose)
{
- if(shader== nullptr || shader_file== nullptr)
+ if (!shader || !shader_file)
{
- if(shader== nullptr)
+ if (!shader)
osd_printf_warning("error: gl_compile_shader_source: nullptr shader passed\n");
- if(shader_file== nullptr)
+ if (!shader_file)
osd_printf_warning("error: gl_compile_shader_source: nullptr shader file passed\n");
return -1;
}
FILE *const file = fopen(shader_file, "r");
- if(!file)
+ if (!file)
{
osd_printf_warning("cannot open shader_file: %s\n", shader_file);
return -1;
@@ -395,19 +443,20 @@ int gl_compile_shader_file( GLhandleARB *shader, GLenum type, const char * shade
int const buffer_len = (int)ftell(file);
fseek(file, 0, SEEK_SET);
- GLcharARB *const buffer = (GLcharARB *)malloc(buffer_len + 1);
+ auto *const buffer = (GLcharARB *)malloc(buffer_len + 1);
memset(buffer, 0, buffer_len + 1);
/* Load Shader Sources */
- for( int i = 0, c = 0; i<buffer_len && EOF!=(c=fgetc(file)); i++ )
- buffer[i]=(char)c;
+ for (int i = 0, c = 0; i<buffer_len && EOF!=(c=fgetc(file)); i++)
+ buffer[i] = char(c);
fclose(file);
- int const err=gl_compile_shader_source(shader, type, buffer, verbose);
+ int const err = compile_source(shader, type, buffer, verbose);
free(buffer);
- if(err) goto errout;
+ if (err)
+ goto errout;
- if(verbose)
+ if (verbose)
osd_printf_warning("shader file: %s\n", shader_file);
return 0;
@@ -418,180 +467,204 @@ errout:
}
-int gl_compile_shader_files( GLhandleARB *program, GLhandleARB *vertex_shader, GLhandleARB *fragment_shader,
- const char * vertex_shader_file,
- const char * fragment_shader_file,
- int verbose
- )
+int gl_shader_tool::compile_files(
+ GLhandleARB *program,
+ GLhandleARB *vertex_shader,
+ GLhandleARB *fragment_shader,
+ const char * vertex_shader_file,
+ const char * fragment_shader_file,
+ bool verbose)
{
int err;
if (!program)
{
- err=-1;
+ err = -1;
osd_printf_warning("no program ptr passed\n");
goto errout;
}
if (!vertex_shader)
{
- err=-1;
+ err = -1;
osd_printf_warning("no vertex_shader ptr passed\n");
goto errout;
}
if (!fragment_shader)
{
- err=-1;
+ err = -1;
osd_printf_warning("no fragment_shader ptr passed\n");
goto errout;
}
- *program = pfn_glCreateProgramObjectARB();
- err=GL_SHADER_CHECK(*program, GL_OBJECT_TYPE_ARB);
- if(err) goto errout;
+ *program = pfn_glCreateProgramObjectARB();
+ err=GL_SHADER_CHECK(*program, GL_OBJECT_TYPE_ARB);
+ if (err)
+ goto errout;
- if(!vertex_shader_file)
+ if (!vertex_shader_file)
{
if (!(*vertex_shader))
{
- err=-1;
+ err = -1;
osd_printf_warning("no vertex_shader_file, nor vertex_shader id passed\n");
goto errout;
}
- err=GL_SHADER_CHECK(*vertex_shader, GL_OBJECT_TYPE_ARB);
- if(err) goto errout;
- } else {
- err = gl_compile_shader_file(vertex_shader, GL_VERTEX_SHADER_ARB, vertex_shader_file, verbose);
- if(err) return err;
+ err = GL_SHADER_CHECK(*vertex_shader, GL_OBJECT_TYPE_ARB);
+ if (err)
+ goto errout;
+ }
+ else
+ {
+ err = compile_file(vertex_shader, GL_VERTEX_SHADER_ARB, vertex_shader_file, verbose);
+ if (err)
+ return err;
}
- pfn_glAttachObjectARB(*program, *vertex_shader);
+ pfn_glAttachObjectARB(*program, *vertex_shader);
- if(!fragment_shader_file)
+ if (!fragment_shader_file)
{
if (!(*fragment_shader))
{
- err=-1;
+ err = -1;
osd_printf_warning("no fragment_shader_file, nor fragment_shader id passed\n");
goto errout;
}
- err=GL_SHADER_CHECK(*fragment_shader, GL_OBJECT_TYPE_ARB);
- if(err) goto errout;
- } else {
- err = gl_compile_shader_file(fragment_shader, GL_FRAGMENT_SHADER_ARB, fragment_shader_file, verbose);
- if(err) return err;
+ err = GL_SHADER_CHECK(*fragment_shader, GL_OBJECT_TYPE_ARB);
+ if (err)
+ goto errout;
+ }
+ else
+ {
+ err = compile_file(fragment_shader, GL_FRAGMENT_SHADER_ARB, fragment_shader_file, verbose);
+ if (err)
+ return err;
}
- pfn_glAttachObjectARB(*program, *fragment_shader);
+ pfn_glAttachObjectARB(*program, *fragment_shader);
- pfn_glLinkProgramARB(*program);
- err=GL_SHADER_CHECK(*program, GL_OBJECT_LINK_STATUS_ARB);
- if(err) goto errout;
+ pfn_glLinkProgramARB(*program);
+ err = GL_SHADER_CHECK(*program, GL_OBJECT_LINK_STATUS_ARB);
+ if (err)
+ goto errout;
- pfn_glValidateProgramARB(*program);
- err=GL_SHADER_CHECK(*program, GL_OBJECT_VALIDATE_STATUS_ARB);
- if(err) goto errout;
+ pfn_glValidateProgramARB(*program);
+ err = GL_SHADER_CHECK(*program, GL_OBJECT_VALIDATE_STATUS_ARB);
+ if (err)
+ goto errout;
- return 0;
+ return 0;
errout:
- delete_shader_tool(program, vertex_shader, fragment_shader, 0);
- return err;
+ delete_shader_tool(program, vertex_shader, fragment_shader, false);
+ return err;
}
-int gl_compile_shader_sources( GLhandleARB *program, GLhandleARB *vertex_shader, GLhandleARB *fragment_shader,
- const GLcharARB * vertex_shader_source,
- const GLcharARB * fragment_shader_source
- )
+int gl_shader_tool::compile_sources(
+ GLhandleARB *program,
+ GLhandleARB *vertex_shader,
+ GLhandleARB *fragment_shader,
+ const GLcharARB * vertex_shader_source,
+ const GLcharARB * fragment_shader_source)
{
- int err = 0;
+ int err = 0;
if (!program)
{
- err=-1;
+ err = -1;
osd_printf_warning("no program ptr passed\n");
goto errout;
}
if (!vertex_shader)
{
- err=-1;
+ err = -1;
osd_printf_warning("no vertex_shader ptr passed\n");
goto errout;
}
if (!fragment_shader)
{
- err=-1;
+ err = -1;
osd_printf_warning("no fragment_shader ptr passed\n");
goto errout;
}
- *program = pfn_glCreateProgramObjectARB();
- err=GL_SHADER_CHECK(*program, GL_OBJECT_TYPE_ARB);
- if(err) goto errout;
+ *program = pfn_glCreateProgramObjectARB();
+ err = GL_SHADER_CHECK(*program, GL_OBJECT_TYPE_ARB);
+ if (err)
+ goto errout;
- if(!vertex_shader_source)
+ if (!vertex_shader_source)
{
if (!(*vertex_shader))
{
- err=-1;
+ err = -1;
osd_printf_warning("no vertex_shader_source nor a vertex_shader id passed\n");
goto errout;
}
- err=GL_SHADER_CHECK(*vertex_shader, GL_OBJECT_TYPE_ARB);
- if(err) goto errout;
+ err = GL_SHADER_CHECK(*vertex_shader, GL_OBJECT_TYPE_ARB);
+ if (err)
+ goto errout;
}
- if(!fragment_shader_source)
+ if (!fragment_shader_source)
{
if (!(*fragment_shader))
{
- err=-1;
+ err = -1;
osd_printf_warning("no fragment_shader_source nor a fragment_shader id passed\n");
goto errout;
}
- err=GL_SHADER_CHECK(*fragment_shader, GL_OBJECT_TYPE_ARB);
- if(err) goto errout;
+ err = GL_SHADER_CHECK(*fragment_shader, GL_OBJECT_TYPE_ARB);
+ if (err)
+ goto errout;
}
- if(vertex_shader_source)
+ if (vertex_shader_source)
{
- err=gl_compile_shader_source(vertex_shader, GL_VERTEX_SHADER_ARB, vertex_shader_source, 0);
- if(err) goto errout;
+ err = compile_source(vertex_shader, GL_VERTEX_SHADER_ARB, vertex_shader_source, false);
+ if (err)
+ goto errout;
}
- pfn_glAttachObjectARB(*program, *vertex_shader);
+ pfn_glAttachObjectARB(*program, *vertex_shader);
- if(fragment_shader_source)
+ if (fragment_shader_source)
{
- err=gl_compile_shader_source(fragment_shader, GL_FRAGMENT_SHADER_ARB, fragment_shader_source, 0);
- if(err) goto errout;
+ err = compile_source(fragment_shader, GL_FRAGMENT_SHADER_ARB, fragment_shader_source, false);
+ if (err)
+ goto errout;
}
- pfn_glAttachObjectARB(*program, *fragment_shader);
+ pfn_glAttachObjectARB(*program, *fragment_shader);
- pfn_glLinkProgramARB(*program);
- err=GL_SHADER_CHECK(*program, GL_OBJECT_LINK_STATUS_ARB);
- if(err) {
+ pfn_glLinkProgramARB(*program);
+ err = GL_SHADER_CHECK(*program, GL_OBJECT_LINK_STATUS_ARB);
+ if (err)
+ {
osd_printf_warning("failed to link program\n");
osd_printf_warning("vertex shader: <%s>\n", vertex_shader_source);
osd_printf_warning("fragment shader: <%s>\n", fragment_shader_source);
goto errout;
}
- pfn_glValidateProgramARB(*program);
- err=GL_SHADER_CHECK(*program, GL_OBJECT_VALIDATE_STATUS_ARB);
- if(err) {
+ pfn_glValidateProgramARB(*program);
+ err = GL_SHADER_CHECK(*program, GL_OBJECT_VALIDATE_STATUS_ARB);
+ if (err)
+ {
osd_printf_warning("failed to validate program\n");
osd_printf_warning("vertex shader: <%s>\n", vertex_shader_source);
osd_printf_warning("fragment shader: <%s>\n", fragment_shader_source);
goto errout;
}
- return 0;
+ return 0;
errout:
- delete_shader_tool(program, vertex_shader, fragment_shader, 0);
- return err;
-
+ delete_shader_tool(program, vertex_shader, fragment_shader, false);
+ return err;
}
-int gl_delete_shader( GLhandleARB *program, GLhandleARB *vertex_shader, GLhandleARB *fragment_shader )
+int gl_shader_tool::delete_shader(
+ GLhandleARB *program,
+ GLhandleARB *vertex_shader,
+ GLhandleARB *fragment_shader)
{
- return delete_shader_tool(program, vertex_shader, fragment_shader, 1);
+ return delete_shader_tool(program, vertex_shader, fragment_shader, true);
}
diff --git a/src/osd/modules/opengl/gl_shader_tool.h b/src/osd/modules/opengl/gl_shader_tool.h
index 2e0160cf85d..50845bd590f 100644
--- a/src/osd/modules/opengl/gl_shader_tool.h
+++ b/src/osd/modules/opengl/gl_shader_tool.h
@@ -7,7 +7,8 @@
* Copyright (c) 2007, Sven Gothel
* Copyright (c) 2007, MAME Team
*
- * GPL version 2
+ * May be distributed under the terms of the GNU General Public
+ * License, version 2.0, or the 3-Clause BSD License.
*
* OpenGL GLSL ARB extensions:
*
@@ -17,10 +18,14 @@
* GL_ARB_fragment_shader
*
*/
+#ifndef MAME_OSD_OPENGL_GL_SHADER_TOOL_H
+#define MAME_OSD_OPENGL_GL_SHADER_TOOL_H
+#pragma once
-#ifndef _GL_SHADER_TOOL_
-#define _GL_SHADER_TOOL_
+#include "osd_opengl.h"
+
+#include <stdint.h>
#ifdef __cplusplus
extern "C" {
@@ -36,14 +41,10 @@ extern "C" {
*
*/
-#include <stdint.h>
-
#ifndef GL_GLEXT_PROTOTYPES
#define GL_GLEXT_PROTOTYPES 1
#endif
-#include "osd_opengl.h"
-
#if defined(SDLMAME_MACOSX)
#ifndef APIENTRY
@@ -55,80 +56,6 @@ extern "C" {
#endif
-typedef void * (APIENTRYP PFNGLGETPROCADDRESSOS)(const char *procName);
-
-/**
- * YOU HAVE TO CALL THIS FUNCTION ONCE !
- * @return 0 - ok .. all shader ARB functions loaded
- * otherwise !=0
- */
-int gl_shader_loadExtention(osd_gl_context *gl_ctx);
-
-enum GLSLCheckMode {
- CHECK_QUIET, /* just return 0, if no error, otherwise the GL error code, no stderr output */
- CHECK_VERBOSE, /* same as CHECK_QUIET, but in the case of an error, use stderr to be verbose */
- CHECK_ALWAYS_VERBOSE /* always print out all information available */
-};
-
-#define GL_CHECK_ERROR_VERBOSE() gl_check_error(CHECK_ALWAYS_VERBOSE,__FILE__,__LINE__)
-#define GL_CHECK_ERROR_NORMAL() gl_check_error(CHECK_VERBOSE,__FILE__,__LINE__)
-#define GL_CHECK_ERROR_QUIET() gl_check_error(CHECK_QUIET,__FILE__,__LINE__)
-#define GL_CHECK_ERROR(m) gl_check_error(m,__FILE__,__LINE__)
-
-#define GL_SHADER_CHECK_ERROR_VERBOSE(o,q) gl_shader_check_error(o,q,CHECK_ALWAYS_VERBOSE,__FILE__,__LINE__)
-#define GL_SHADER_CHECK_ERROR_NORMAL(o,q) gl_shader_check_error(o,q,CHECK_VERBOSE,__FILE__,__LINE__)
-#define GL_SHADER_CHECK_ERROR_QUIET(o,q) gl_shader_check_error(o,q,CHECK_QUIET,__FILE__,__LINE__)
-#define GL_SHADER_CHECK_ERROR(o,q,m) gl_shader_check_error(o,q,m,__FILE__,__LINE__)
-
-#ifdef GL_SHADER_TOOL_DEBUG
- #define GL_SHADER_CHECK(o,q) GL_SHADER_CHECK_ERROR_VERBOSE(o,q)
- #define GL_CHECK() GL_CHECK_ERROR_VERBOSE()
-#else
- #define GL_SHADER_CHECK(o,q) GL_SHADER_CHECK_ERROR_NORMAL(o,q)
- #define GL_CHECK() GL_CHECK_ERROR_NORMAL()
-#endif
-
-int gl_check_error(GLSLCheckMode m, const char *file, const int line);
-
-int gl_texture_check_size(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height,
- GLint border, GLenum format, GLenum type,
- GLsizei *avail_width, GLsizei *avail_height,
- int verbose);
-
-int gl_round_to_pow2(int v);
-
-/**
- * @param obj_query Can be either GL_OBJECT_TYPE_ARB, GL_OBJECT_DELETE_STATUS_ARB, GL_OBJECT_COMPILE_STATUS_ARB,
- * GL_OBJECT_LINK_STATUS_ARB, GL_OBJECT_VALIDATE_STATUS_ARB
- * Should be used after the referring action, i.e. GL_OBJECT_DELETE_STATUS_ARB after a
- * glDeleteObjectARB call, etc.
- */
-int gl_shader_check_error(GLhandleARB obj, GLenum obj_query, GLSLCheckMode m, const char *file, const int line);
-
-int gl_compile_shader_file ( GLhandleARB *shader, GLenum type, const char * shader_file, int verbose );
-int gl_compile_shader_source( GLhandleARB *shader, GLenum type, const char * shader_source, int verbose );
-
-/**
- * you can pass either a valid shader_file, or a precompiled vertex_shader,
- * this is true for both, vertex and fragment shaders.
- */
-int gl_compile_shader_files( GLhandleARB *program, GLhandleARB *vertex_shader, GLhandleARB *fragment_shader,
- const char * vertex_shader_file,
- const char * fragment_shader_file,
- int verbose
- );
-
-/**
- * you can pass either a valid shader_file, or a precompiled vertex_shader,
- * this is true for both, vertex and fragment shaders.
- */
-int gl_compile_shader_sources( GLhandleARB *program, GLhandleARB *vertex_shader, GLhandleARB *fragment_shader,
- const GLcharARB * vertex_shader_source,
- const GLcharARB * fragment_shader_source
- );
-
-int gl_delete_shader( GLhandleARB *program, GLhandleARB *vertex_shader, GLhandleARB *fragment_shader );
-
#if defined(SDLMAME_MACOSX)
#ifndef GL_ARB_shader_objects
typedef char GLcharARB;
@@ -158,32 +85,118 @@ typedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC) (GLint location, GLsizei count,
typedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value);
#endif
-extern PFNGLGETOBJECTPARAMETERIVARBPROC pfn_glGetObjectParameterivARB;
-extern PFNGLGETINFOLOGARBPROC pfn_glGetInfoLogARB;
-extern PFNGLDELETEOBJECTARBPROC pfn_glDeleteObjectARB;
-extern PFNGLCREATESHADEROBJECTARBPROC pfn_glCreateShaderObjectARB;
-extern PFNGLSHADERSOURCEARBPROC pfn_glShaderSourceARB;
-extern PFNGLCOMPILESHADERARBPROC pfn_glCompileShaderARB;
-extern PFNGLCREATEPROGRAMOBJECTARBPROC pfn_glCreateProgramObjectARB;
-extern PFNGLATTACHOBJECTARBPROC pfn_glAttachObjectARB;
-extern PFNGLLINKPROGRAMARBPROC pfn_glLinkProgramARB;
-extern PFNGLVALIDATEPROGRAMARBPROC pfn_glValidateProgramARB;
-extern PFNGLUSEPROGRAMOBJECTARBPROC pfn_glUseProgramObjectARB;
-extern PFNGLGETUNIFORMLOCATIONARBPROC pfn_glGetUniformLocationARB;
-extern PFNGLUNIFORM1FARBPROC pfn_glUniform1fARB;
-extern PFNGLUNIFORM1IARBPROC pfn_glUniform1iARB;
-extern PFNGLUNIFORM1FVARBPROC pfn_glUniform1fvARB;
-extern PFNGLUNIFORM2FVARBPROC pfn_glUniform2fvARB;
-extern PFNGLUNIFORM3FVARBPROC pfn_glUniform3fvARB;
-extern PFNGLUNIFORM4FVARBPROC pfn_glUniform4fvARB;
-extern PFNGLUNIFORM1IVARBPROC pfn_glUniform1ivARB;
-extern PFNGLUNIFORM2IVARBPROC pfn_glUniform2ivARB;
-extern PFNGLUNIFORM3IVARBPROC pfn_glUniform3ivARB;
-extern PFNGLUNIFORM4IVARBPROC pfn_glUniform4ivARB;
-
+typedef void * (APIENTRYP PFNGLGETPROCADDRESSOS)(const char *procName);
#ifdef __cplusplus
}
#endif
+class gl_shader_tool
+{
+public:
+ gl_shader_tool(
+#if defined(USE_DISPATCH_GL)
+ osd_gl_dispatch *gld
#endif
+ );
+
+ PFNGLGETOBJECTPARAMETERIVARBPROC pfn_glGetObjectParameterivARB;
+ PFNGLGETINFOLOGARBPROC pfn_glGetInfoLogARB;
+ PFNGLDELETEOBJECTARBPROC pfn_glDeleteObjectARB;
+ PFNGLCREATESHADEROBJECTARBPROC pfn_glCreateShaderObjectARB;
+ PFNGLSHADERSOURCEARBPROC pfn_glShaderSourceARB;
+ PFNGLCOMPILESHADERARBPROC pfn_glCompileShaderARB;
+ PFNGLCREATEPROGRAMOBJECTARBPROC pfn_glCreateProgramObjectARB;
+ PFNGLATTACHOBJECTARBPROC pfn_glAttachObjectARB;
+ PFNGLLINKPROGRAMARBPROC pfn_glLinkProgramARB;
+ PFNGLVALIDATEPROGRAMARBPROC pfn_glValidateProgramARB;
+ PFNGLUSEPROGRAMOBJECTARBPROC pfn_glUseProgramObjectARB;
+ PFNGLGETUNIFORMLOCATIONARBPROC pfn_glGetUniformLocationARB;
+ PFNGLUNIFORM1FARBPROC pfn_glUniform1fARB;
+ PFNGLUNIFORM1IARBPROC pfn_glUniform1iARB;
+ PFNGLUNIFORM1FVARBPROC pfn_glUniform1fvARB;
+ PFNGLUNIFORM2FVARBPROC pfn_glUniform2fvARB;
+ PFNGLUNIFORM3FVARBPROC pfn_glUniform3fvARB;
+ PFNGLUNIFORM4FVARBPROC pfn_glUniform4fvARB;
+ PFNGLUNIFORM1IVARBPROC pfn_glUniform1ivARB;
+ PFNGLUNIFORM2IVARBPROC pfn_glUniform2ivARB;
+ PFNGLUNIFORM3IVARBPROC pfn_glUniform3ivARB;
+ PFNGLUNIFORM4IVARBPROC pfn_glUniform4ivARB;
+
+ /**
+ * YOU HAVE TO CALL THIS FUNCTION ONCE !
+ * @return true - ok .. all shader ARB functions loaded
+ * otherwise false
+ */
+ bool load_extension(osd_gl_context &gl_ctx);
+
+ int texture_check_size(
+ GLenum target,
+ GLint level,
+ GLint internalFormat,
+ GLsizei width,
+ GLsizei height,
+ GLint border,
+ GLenum format,
+ GLenum type,
+ GLsizei *avail_width,
+ GLsizei *avail_height,
+ bool verbose);
+
+protected:
+ int compile_file(GLhandleARB *shader, GLenum type, const char *shader_file, bool verbose);
+ int compile_source(GLhandleARB *shader, GLenum type, const char *shader_source, bool verbose);
+
+ /**
+ * you can pass either a valid shader_file, or a precompiled vertex_shader,
+ * this is true for both, vertex and fragment shaders.
+ */
+ int compile_files(
+ GLhandleARB *program,
+ GLhandleARB *vertex_shader,
+ GLhandleARB *fragment_shader,
+ const char *vertex_shader_file,
+ const char *fragment_shader_file,
+ bool verbose);
+
+ /**
+ * you can pass either a valid shader_file, or a precompiled vertex_shader,
+ * this is true for both, vertex and fragment shaders.
+ */
+ int compile_sources(
+ GLhandleARB *program,
+ GLhandleARB *vertex_shader,
+ GLhandleARB *fragment_shader,
+ const GLcharARB *vertex_shader_source,
+ const GLcharARB *fragment_shader_source);
+
+ int delete_shader(GLhandleARB *program, GLhandleARB *vertex_shader, GLhandleARB *fragment_shader);
+
+#if defined(USE_DISPATCH_GL)
+ osd_gl_dispatch *const gl_dispatch; // name is magic, can't be changed
+#endif
+
+private:
+ enum GLSLCheckMode
+ {
+ CHECK_QUIET, // just return 0, if no error, otherwise the GL error code, no stderr output
+ CHECK_VERBOSE, // same as CHECK_QUIET, but in the case of an error, use stderr to be verbose
+ CHECK_ALWAYS_VERBOSE // always print out all information available
+ };
+
+ int check_error(GLSLCheckMode m, const char *file, const int line);
+
+ /**
+ * @param obj_query Can be either GL_OBJECT_TYPE_ARB, GL_OBJECT_DELETE_STATUS_ARB, GL_OBJECT_COMPILE_STATUS_ARB,
+ * GL_OBJECT_LINK_STATUS_ARB, GL_OBJECT_VALIDATE_STATUS_ARB
+ * Should be used after the referring action, i.e. GL_OBJECT_DELETE_STATUS_ARB after a
+ * glDeleteObjectARB call, etc.
+ */
+ int check_error(GLhandleARB obj, GLenum obj_query, GLSLCheckMode m, const char *file, const int line);
+
+ int delete_shader_tool(GLhandleARB *program, GLhandleARB *vertex_shader, GLhandleARB *fragment_shader, bool externalcall);
+};
+
+int gl_round_to_pow2(int v);
+
+#endif // MAME_OSD_OPENGL_GL_SHADER_TOOL_H
diff --git a/src/osd/modules/opengl/osd_opengl.h b/src/osd/modules/opengl/osd_opengl.h
index 47d0b3c429c..712b3b880b4 100644
--- a/src/osd/modules/opengl/osd_opengl.h
+++ b/src/osd/modules/opengl/osd_opengl.h
@@ -21,7 +21,7 @@
#ifdef _MSC_VER
#include <windows.h>
#include "GL/GL.h"
- #include "bgfx/3rdparty/khronos/gl/glext.h "
+ #include "bgfx/3rdparty/khronos/gl/glext.h"
#ifndef USE_DISPATCH_GL
#include "bgfx/3rdparty/khronos/wgl/wglext.h"
#endif
@@ -36,35 +36,38 @@
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#else
- #include <SDL2/SDL_version.h>
-
- #if (SDL_VERSION_ATLEAST(1,2,10))
- #if defined(SDLMAME_WIN32)
- // Avoid that winnt.h (included via sdl_opengl.h, windows.h, windef.h includes intrin.h
- #define __INTRIN_H_
- #endif
- #include <SDL2/SDL_opengl.h>
- #endif
+ #include <SDL2/SDL_version.h>
+ #include <SDL2/SDL_opengl.h>
#endif
class osd_gl_context
{
public:
- osd_gl_context() { }
- virtual ~osd_gl_context() { }
- virtual void MakeCurrent() = 0;
- virtual const char *LastErrorMsg() = 0;
- virtual void *getProcAddress(const char *proc) = 0;
+ virtual ~osd_gl_context() = default;
+
+ virtual explicit operator bool() const = 0;
+
+ virtual void make_current() = 0;
+ virtual const char *last_error_message() = 0;
+ virtual void *get_proc_address(const char *proc) = 0;
+
/*
* 0 for immediate updates,
* 1 for updates synchronized with the vertical retrace,
* -1 for late swap tearing
*
- * returns -1 if swap interval is not supported
- *
+ * returns false if swap interval is not supported
*/
- virtual int SetSwapInterval(const int swap) = 0;
- virtual void SwapBuffer() = 0;
+ virtual bool set_swap_interval(const int swap) = 0;
+
+ virtual void swap_buffer() = 0;
+
+ template <typename T>
+ bool get_proc_address(T &ptr, const char *name)
+ {
+ ptr = T(uintptr_t(get_proc_address(name)));
+ return bool(ptr);
+ }
};
@@ -100,11 +103,6 @@
#undef OSD_GL
#undef OSD_GL_UNUSED
-#ifdef _MSC_VER
- extern "C" osd_gl_dispatch *gl_dispatch;
-#endif
- extern osd_gl_dispatch *gl_dispatch;
-
/*
* Use gl_mangle to map function names
*/
@@ -127,67 +125,67 @@
*
***************************************************************/
- #define glAccum MANGLE(Accum)
- #define glActiveStencilFaceEXT MANGLE(ActiveStencilFaceEXT)
- #define glActiveTextureARB MANGLE(ActiveTextureARB)
- #define glActiveTexture MANGLE(ActiveTexture)
- #define glAlphaFragmentOp1ATI MANGLE(AlphaFragmentOp1ATI)
- #define glAlphaFragmentOp2ATI MANGLE(AlphaFragmentOp2ATI)
- #define glAlphaFragmentOp3ATI MANGLE(AlphaFragmentOp3ATI)
- #define glAlphaFunc MANGLE(AlphaFunc)
- #define glApplyTextureEXT MANGLE(ApplyTextureEXT)
- #define glAreProgramsResidentNV MANGLE(AreProgramsResidentNV)
+ #define glAccum MANGLE(Accum)
+ #define glActiveStencilFaceEXT MANGLE(ActiveStencilFaceEXT)
+ #define glActiveTextureARB MANGLE(ActiveTextureARB)
+ #define glActiveTexture MANGLE(ActiveTexture)
+ #define glAlphaFragmentOp1ATI MANGLE(AlphaFragmentOp1ATI)
+ #define glAlphaFragmentOp2ATI MANGLE(AlphaFragmentOp2ATI)
+ #define glAlphaFragmentOp3ATI MANGLE(AlphaFragmentOp3ATI)
+ #define glAlphaFunc MANGLE(AlphaFunc)
+ #define glApplyTextureEXT MANGLE(ApplyTextureEXT)
+ #define glAreProgramsResidentNV MANGLE(AreProgramsResidentNV)
#define glAreTexturesResidentEXT MANGLE(AreTexturesResidentEXT)
- #define glAreTexturesResident MANGLE(AreTexturesResident)
- #define glArrayElementEXT MANGLE(ArrayElementEXT)
- #define glArrayElement MANGLE(ArrayElement)
- #define glArrayObjectATI MANGLE(ArrayObjectATI)
- #define glAsyncMarkerSGIX MANGLE(AsyncMarkerSGIX)
- #define glAttachObjectARB MANGLE(AttachObjectARB)
- #define glAttachShader MANGLE(AttachShader)
+ #define glAreTexturesResident MANGLE(AreTexturesResident)
+ #define glArrayElementEXT MANGLE(ArrayElementEXT)
+ #define glArrayElement MANGLE(ArrayElement)
+ #define glArrayObjectATI MANGLE(ArrayObjectATI)
+ #define glAsyncMarkerSGIX MANGLE(AsyncMarkerSGIX)
+ #define glAttachObjectARB MANGLE(AttachObjectARB)
+ #define glAttachShader MANGLE(AttachShader)
#define glBeginFragmentShaderATI MANGLE(BeginFragmentShaderATI)
- #define glBegin MANGLE(Begin)
- #define glBeginOcclusionQueryNV MANGLE(BeginOcclusionQueryNV)
- #define glBeginQueryARB MANGLE(BeginQueryARB)
- #define glBeginQuery MANGLE(BeginQuery)
- #define glBeginVertexShaderEXT MANGLE(BeginVertexShaderEXT)
- #define glBindAttribLocationARB MANGLE(BindAttribLocationARB)
- #define glBindAttribLocation MANGLE(BindAttribLocation)
- #define glBindBufferARB MANGLE(BindBufferARB)
- #define glBindBuffer MANGLE(BindBuffer)
- #define glBindFragmentShaderATI MANGLE(BindFragmentShaderATI)
- #define glBindFramebufferEXT MANGLE(BindFramebufferEXT)
- #define glBindLightParameterEXT MANGLE(BindLightParameterEXT)
+ #define glBegin MANGLE(Begin)
+ #define glBeginOcclusionQueryNV MANGLE(BeginOcclusionQueryNV)
+ #define glBeginQueryARB MANGLE(BeginQueryARB)
+ #define glBeginQuery MANGLE(BeginQuery)
+ #define glBeginVertexShaderEXT MANGLE(BeginVertexShaderEXT)
+ #define glBindAttribLocationARB MANGLE(BindAttribLocationARB)
+ #define glBindAttribLocation MANGLE(BindAttribLocation)
+ #define glBindBufferARB MANGLE(BindBufferARB)
+ #define glBindBuffer MANGLE(BindBuffer)
+ #define glBindFragmentShaderATI MANGLE(BindFragmentShaderATI)
+ #define glBindFramebufferEXT MANGLE(BindFramebufferEXT)
+ #define glBindLightParameterEXT MANGLE(BindLightParameterEXT)
#define glBindMaterialParameterEXT MANGLE(BindMaterialParameterEXT)
- #define glBindParameterEXT MANGLE(BindParameterEXT)
- #define glBindProgramARB MANGLE(BindProgramARB)
- #define glBindProgramNV MANGLE(BindProgramNV)
- #define glBindRenderbufferEXT MANGLE(BindRenderbufferEXT)
+ #define glBindParameterEXT MANGLE(BindParameterEXT)
+ #define glBindProgramARB MANGLE(BindProgramARB)
+ #define glBindProgramNV MANGLE(BindProgramNV)
+ #define glBindRenderbufferEXT MANGLE(BindRenderbufferEXT)
#define glBindTexGenParameterEXT MANGLE(BindTexGenParameterEXT)
- #define glBindTextureEXT MANGLE(BindTextureEXT)
- #define glBindTexture MANGLE(BindTexture)
- #define glBindTextureUnitParameterEXT MANGLE(BindTextureUnitParameterEXT)
- #define glBindVertexArrayAPPLE MANGLE(BindVertexArrayAPPLE)
- #define glBindVertexShaderEXT MANGLE(BindVertexShaderEXT)
- #define glBinormal3bEXT MANGLE(Binormal3bEXT)
- #define glBinormal3bvEXT MANGLE(Binormal3bvEXT)
- #define glBinormal3dEXT MANGLE(Binormal3dEXT)
- #define glBinormal3dvEXT MANGLE(Binormal3dvEXT)
- #define glBinormal3fEXT MANGLE(Binormal3fEXT)
- #define glBinormal3fvEXT MANGLE(Binormal3fvEXT)
- #define glBinormal3iEXT MANGLE(Binormal3iEXT)
- #define glBinormal3ivEXT MANGLE(Binormal3ivEXT)
- #define glBinormal3sEXT MANGLE(Binormal3sEXT)
- #define glBinormal3svEXT MANGLE(Binormal3svEXT)
- #define glBinormalPointerEXT MANGLE(BinormalPointerEXT)
- #define glBitmap MANGLE(Bitmap)
- #define glBlendColorEXT MANGLE(BlendColorEXT)
- #define glBlendColor MANGLE(BlendColor)
- #define glBlendEquationEXT MANGLE(BlendEquationEXT)
- #define glBlendEquation MANGLE(BlendEquation)
+ #define glBindTextureEXT MANGLE(BindTextureEXT)
+ #define glBindTexture MANGLE(BindTexture)
+ #define glBindTextureUnitParameterEXT MANGLE(BindTextureUnitParameterEXT)
+ #define glBindVertexArrayAPPLE MANGLE(BindVertexArrayAPPLE)
+ #define glBindVertexShaderEXT MANGLE(BindVertexShaderEXT)
+ #define glBinormal3bEXT MANGLE(Binormal3bEXT)
+ #define glBinormal3bvEXT MANGLE(Binormal3bvEXT)
+ #define glBinormal3dEXT MANGLE(Binormal3dEXT)
+ #define glBinormal3dvEXT MANGLE(Binormal3dvEXT)
+ #define glBinormal3fEXT MANGLE(Binormal3fEXT)
+ #define glBinormal3fvEXT MANGLE(Binormal3fvEXT)
+ #define glBinormal3iEXT MANGLE(Binormal3iEXT)
+ #define glBinormal3ivEXT MANGLE(Binormal3ivEXT)
+ #define glBinormal3sEXT MANGLE(Binormal3sEXT)
+ #define glBinormal3svEXT MANGLE(Binormal3svEXT)
+ #define glBinormalPointerEXT MANGLE(BinormalPointerEXT)
+ #define glBitmap MANGLE(Bitmap)
+ #define glBlendColorEXT MANGLE(BlendColorEXT)
+ #define glBlendColor MANGLE(BlendColor)
+ #define glBlendEquationEXT MANGLE(BlendEquationEXT)
+ #define glBlendEquation MANGLE(BlendEquation)
#define glBlendEquationSeparateATI MANGLE(BlendEquationSeparateATI)
#define glBlendEquationSeparateEXT MANGLE(BlendEquationSeparateEXT)
- #define glBlendEquationSeparate MANGLE(BlendEquationSeparate)
+ #define glBlendEquationSeparate MANGLE(BlendEquationSeparate)
#define glBlendFunc MANGLE(BlendFunc)
#define glBlendFuncSeparateEXT MANGLE(BlendFuncSeparateEXT)
#define glBlendFuncSeparateINGR MANGLE(BlendFuncSeparateINGR)
diff --git a/src/osd/modules/osdhelper.h b/src/osd/modules/osdhelper.h
index 093c392e249..85cbfc906c1 100644
--- a/src/osd/modules/osdhelper.h
+++ b/src/osd/modules/osdhelper.h
@@ -20,8 +20,8 @@ public:
constexpr int width() const { return m_w; }
constexpr int height() const { return m_h; }
- constexpr bool operator!=(const osd_dim &other) { return (m_w != other.width()) || (m_h != other.height()); }
- constexpr bool operator==(const osd_dim &other) { return (m_w == other.width()) && (m_h == other.height()); }
+ constexpr bool operator!=(const osd_dim &other) const { return (m_w != other.width()) || (m_h != other.height()); }
+ constexpr bool operator==(const osd_dim &other) const { return (m_w == other.width()) && (m_h == other.height()); }
private:
int m_w;
diff --git a/src/osd/modules/osdmodule.cpp b/src/osd/modules/osdmodule.cpp
index 75adc5c75bb..0fb43d4331a 100644
--- a/src/osd/modules/osdmodule.cpp
+++ b/src/osd/modules/osdmodule.cpp
@@ -1,47 +1,38 @@
// license:BSD-3-Clause
// copyright-holders:Couriersud
/*
- * osdmodule.c
+ * osdmodule.cpp
*
*/
#include "modules/osdmodule.h"
+#include "emucore.h"
+
+#include "osdcore.h"
+
#include <algorithm>
osd_module_manager::osd_module_manager()
{
- for (int i=0; i<MAX_MODULES; i++)
- {
- m_modules[i] = nullptr;
- m_selected[i] = nullptr;
- }
}
+
osd_module_manager::~osd_module_manager()
{
- for (int i = 0; m_modules[i] != nullptr; i++)
- {
- global_free(m_modules[i]);
- }
}
void osd_module_manager::register_module(const module_type &mod_type)
{
- auto const slot = std::find(std::begin(m_modules), std::end(m_modules), nullptr);
- if (std::end(m_modules) == slot)
- throw emu_fatalerror("osd_module_manager::register_module: Module registration beyond MAX_MODULES!");
-
- osd_module *module = mod_type();
+ std::unique_ptr<osd_module> module = mod_type();
if (module->probe())
{
osd_printf_verbose("===> registered module %s %s\n", module->name(), module->type());
- *slot = module;
+ m_modules.emplace_back(std::move(module));
}
else
{
osd_printf_verbose("===> not supported %s %s\n", module->name(), module->type());
- global_free(module);
}
}
@@ -54,64 +45,96 @@ osd_module *osd_module_manager::get_module_generic(const char *type, const char
{
int const i = get_module_index(type, name);
if (i >= 0)
- return m_modules[i];
+ return m_modules[i].get();
else
return nullptr;
}
-osd_module *osd_module_manager::select_module(const char *type, const char *name)
+osd_module &osd_module_manager::select_module(osd_interface &osd, const osd_options &options, const char *type, const char *name)
{
- osd_module *m = get_module_generic(type, name);
-
- // FIXME: check if already exists!
- int i;
- for (i = 0; m_selected[i] != nullptr; i++)
- ;
- m_selected[i] = m;
- return m;
-}
+ // see if a module of this type has already been already selected
+ for (osd_module &existing : m_selected)
+ {
+ if (existing.type() == type)
+ {
+ osd_printf_warning(
+ "Attempt to select %s module %s after selecting module %s\n",
+ type,
+ (name && *name) ? name : "<default>",
+ existing.name());
+ return existing;
+ }
+ }
-void osd_module_manager::init(const osd_options &options)
-{
- for (int i = 0; m_selected[i] != nullptr; i++)
+ // try to start the selected module
+ osd_module *const m = get_module_generic(type, name);
+ if (m)
{
- m_selected[i]->init(options);
+ //osd_printf_verbose("Attempting to initialize %s module %s\n", type, m->name());
+ if (!m->init(osd, options))
+ {
+ m_selected.emplace_back(*m);
+ return *m;
+ }
+ osd_printf_verbose("Initializing %s module %s failed\n", type, m->name());
+ }
+ else
+ {
+ osd_printf_verbose("Could not find %s module %s\n", type, name ? name : "<default>");
+ }
+
+ // walk down the list until something works
+ for (auto const &fallback : m_modules)
+ {
+ if ((fallback->type() == type) && (fallback.get() != m))
+ {
+ osd_printf_verbose("Attempting to initialize %s module %s\n", type, fallback->name());
+ if (!fallback->init(osd, options))
+ {
+ osd_printf_warning(
+ m
+ ? "Initializing %s module %s failed, falling back to %s\n"
+ : "Could not find %s module %s, falling back to %s\n",
+ type,
+ m ? m->name() : (name && *name) ? name : "<default>",
+ fallback->name());
+ m_selected.emplace_back(*fallback);
+ return *fallback;
+ }
+ }
}
+
+ // can't deal with absence of a module, and at least the "none" module should have worked
+ throw emu_fatalerror("All %s modules failed to initialize", type);
}
void osd_module_manager::exit()
{
// Find count
- int cnt;
- for (cnt = 0; m_selected[cnt] != nullptr; cnt++)
- ;
- for (int i = cnt - 1; i >= 0; i--)
+ while (!m_selected.empty())
{
- m_selected[i]->exit();
- m_selected[i] = nullptr;
+ m_selected.back().get().exit();
+ m_selected.pop_back();
}
}
int osd_module_manager::get_module_index(const char *type, const char *name) const
{
- for (int i = 0; m_modules[i] != nullptr; i++)
+ for (int i = 0; m_modules.size() > i; i++)
{
- if (strcmp(m_modules[i]->type(), type) == 0 && ((name[0] == 0) || (strcmp(name, m_modules[i]->name())==0)))
+ if ((m_modules[i]->type() == type) && (!name[0] || (m_modules[i]->name() == name)))
return i;
}
return -1;
}
-void osd_module_manager::get_module_names(const char *type, const int max, int *num, const char *names[]) const
+std::vector<std::string_view> osd_module_manager::get_module_names(const char *type) const
{
- *num = 0;
- for (int i = 0; m_modules[i] != nullptr; i++)
+ std::vector<std::string_view> result;
+ for (auto &m : m_modules)
{
- if ((strcmp(m_modules[i]->type(), type) == 0) && (*num < max))
- {
- names[*num] = m_modules[i]->name();
- *num = *num + 1;
- }
-
+ if (m->type() == type)
+ result.emplace_back(m->name());
}
+ return result;
}
diff --git a/src/osd/modules/osdmodule.h b/src/osd/modules/osdmodule.h
index 95178b27f70..b690f874706 100644
--- a/src/osd/modules/osdmodule.h
+++ b/src/osd/modules/osdmodule.h
@@ -7,62 +7,68 @@
OSD module management
*******************************************************************c********/
-
-//#pragma once
-
#ifndef MAME_OSD_MODULES_OSDMODULE_H
#define MAME_OSD_MODULES_OSDMODULE_H
-#include "osdcore.h"
-#include "osdepend.h"
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <string_view>
+#include <vector>
+
//============================================================
// TYPE DEFINITIONS
//============================================================
+class osd_interface;
class osd_options;
-class osd_module;
-// ======================> osd_module
+
+//============================================================
+// TYPE DEFINITIONS
+//============================================================
class osd_module
{
public:
-
- osd_module(const char *type, const char *name)
- : m_name(name), m_type(type)
- {}
virtual ~osd_module() { }
- const char * name() const { return m_name.c_str(); }
- const char * type() const { return m_type.c_str(); }
+ std::string const &name() const { return m_name; }
+ std::string const &type() const { return m_type; }
virtual bool probe() { return true; }
- virtual int init(const osd_options &options) = 0;
+ virtual int init(osd_interface &osd, const osd_options &options) = 0;
virtual void exit() { }
+protected:
+ osd_module(const char *type, const char *name) : m_name(name), m_type(type) { }
+ osd_module(osd_module const &) = delete;
+
private:
- std::string m_name;
- std::string m_type;
+ std::string const m_name;
+ std::string const m_type;
};
+
// a module_type is simply a pointer to its alloc function
-typedef osd_module *(*module_type)();
+typedef std::unique_ptr<osd_module> (*module_type)();
+
// this template function creates a stub which constructs a module
-template<class ModuleClass>
-osd_module *module_creator()
+template <class ModuleClass>
+std::unique_ptr<osd_module> module_creator()
{
- return global_alloc(ModuleClass());
+ return std::unique_ptr<osd_module>(new ModuleClass);
}
+
class osd_module_manager
{
public:
-
- static const int MAX_MODULES = 64;
-
osd_module_manager();
~osd_module_manager();
@@ -72,38 +78,38 @@ public:
osd_module *get_module_generic(const char *type, const char *name);
template<class C>
- C select_module(const char *type, const char *name = "")
+ C &select_module(osd_interface &osd, const osd_options &options, const char *type, const char *name = "")
{
- return dynamic_cast<C>(select_module(type, name));
+ return dynamic_cast<C &>(select_module(osd, options, type, name));
}
- osd_module *select_module(const char *type, const char *name = "");
+ osd_module &select_module(osd_interface &osd, const osd_options &options, const char *type, const char *name = "");
- void get_module_names(const char *type, const int max, int *num, const char *names[]) const;
-
- void init(const osd_options &options);
+ std::vector<std::string_view> get_module_names(const char *type) const;
void exit();
private:
int get_module_index(const char *type, const char *name) const;
- osd_module *m_modules[MAX_MODULES];
- osd_module *m_selected[MAX_MODULES];
+ std::vector<std::unique_ptr<osd_module> > m_modules;
+ std::vector<std::reference_wrapper<osd_module> > m_selected;
};
+
#define MODULE_DEFINITION(mod_id, mod_class) \
- extern const module_type mod_id ; \
- const module_type mod_id = &module_creator< mod_class >;
+ extern const module_type mod_id ; \
+ const module_type mod_id = &module_creator<mod_class>;
#define MODULE_NOT_SUPPORTED(mod_class, mod_type, mod_name) \
- class mod_class : public osd_module { \
- public: \
- mod_class () : osd_module(mod_type, mod_name) { } \
- virtual ~mod_class() { } \
- virtual int init(const osd_options &options) override { return -1; } \
- virtual bool probe() override { return false; } \
- };
+ class mod_class : public osd_module \
+ { \
+ public: \
+ mod_class () : osd_module(mod_type, mod_name) { } \
+ virtual ~mod_class() { } \
+ virtual int init(osd_interface &osd, const osd_options &options) override { return -1; } \
+ virtual bool probe() override { return false; } \
+ };
#endif /* MAME_OSD_MODULES_OSDMODULE_H */
diff --git a/src/osd/modules/osdwindow.cpp b/src/osd/modules/osdwindow.cpp
index 64b6528f5f3..38b86e652e0 100644
--- a/src/osd/modules/osdwindow.cpp
+++ b/src/osd/modules/osdwindow.cpp
@@ -9,50 +9,132 @@
#include "emu.h"
#include "osdwindow.h"
-#include "render/drawnone.h"
-#include "render/drawbgfx.h"
-#if (USE_OPENGL)
-#include "render/drawogl.h"
-#endif
-#if defined(OSD_WINDOWS)
-#include "render/drawgdi.h"
-#include "render/drawd3d.h"
-#elif defined(OSD_SDL)
-#include "render/draw13.h"
-#include "render/drawsdl.h"
-#endif
+// osd/modules
+#include "lib/osdobj_common.h"
+#include "monitor/monitor_module.h"
+#include "render/render_module.h"
+
+// emu
+#include "main.h"
+#include "render.h"
+
+
+osd_window::osd_window(
+ running_machine &machine,
+ render_module &renderprovider,
+ int index,
+ const std::shared_ptr<osd_monitor_info> &monitor,
+ const osd_window_config &config) :
+ m_target(nullptr),
+ m_primlist(nullptr),
+ m_win_config(config),
+ m_index(index),
+ m_fullscreen(false),
+ m_prescale(1),
+ m_machine(machine),
+ m_renderprovider(renderprovider),
+ m_monitor(std::move(monitor)),
+ m_renderer(nullptr),
+ m_title(
+ util::string_format(
+ (video_config.numscreens > 1)
+ ? "%3$s [%4$s] screen %5$d - %1$s %2$s (%6$s%7$sP%8$d)"
+ : "%3$s [%4$s] - %1$s %2$s (%6$s%7$sP%8$d)",
+ emulator_info::get_appname(),
+ emulator_info::get_bare_build_version(),
+ machine.system().type.fullname(),
+ machine.system().name,
+ index,
+ (sizeof(int) == sizeof(void *)) ? "I" : "",
+ (sizeof(long) == sizeof(void *)) ? "L" : (sizeof(long long) == sizeof(void *)) ? "LL" : "",
+ sizeof(void *) * 8))
+{
+}
+
+osd_window::~osd_window()
+{
+}
float osd_window::pixel_aspect() const
{
return monitor()->pixel_aspect();
}
-std::unique_ptr<osd_renderer> osd_renderer::make_for_type(int mode, std::shared_ptr<osd_window> window, int extra_flags)
-{
- switch(mode)
- {
-#if defined(OSD_WINDOWS) || defined(OSD_UWP)
- case VIDEO_MODE_NONE:
- return std::make_unique<renderer_none>(window);
-#endif
- case VIDEO_MODE_BGFX:
- return std::make_unique<renderer_bgfx>(window);
-#if (USE_OPENGL)
- case VIDEO_MODE_OPENGL:
- return std::make_unique<renderer_ogl>(window);
-#endif
-#if defined(OSD_WINDOWS)
- case VIDEO_MODE_GDI:
- return std::make_unique<renderer_gdi>(window);
- case VIDEO_MODE_D3D:
- return std::make_unique<renderer_d3d9>(window);
-#elif defined(OSD_SDL)
- case VIDEO_MODE_SDL2ACCEL:
- return std::make_unique<renderer_sdl2>(window, extra_flags);
- case VIDEO_MODE_SOFT:
- return std::make_unique<renderer_sdl1>(window, extra_flags);
-#endif
- default:
- return nullptr;
- }
+bool osd_window::swap_xy() const
+{
+ bool orientation_swap_xy =
+ (machine().system().flags & ORIENTATION_SWAP_XY) == ORIENTATION_SWAP_XY;
+ bool rotation_swap_xy =
+ (target()->orientation() & ORIENTATION_SWAP_XY) == ORIENTATION_SWAP_XY;
+ return orientation_swap_xy ^ rotation_swap_xy;
+};
+
+bool osd_window::keepaspect() const
+{
+ if (m_target != nullptr)
+ return m_target->keepaspect();
+ else
+ return false;
+}
+
+std::shared_ptr<osd_monitor_info> osd_window::monitor_from_rect(const osd_rect *proposed) const
+{
+ std::shared_ptr<osd_monitor_info> monitor;
+
+ if (fullscreen() || !m_monitor) // in full screen, just use the configured monitor
+ monitor = m_monitor;
+ else if (proposed) // in window mode, find the nearest
+ monitor = m_monitor->module().monitor_from_rect(*proposed);
+ else
+ monitor = m_monitor->module().monitor_from_window(*this);
+
+ return monitor;
+}
+
+void osd_window::create_target()
+{
+ // load the layout
+ m_target = m_machine.render().target_alloc();
+
+ // set the specific view
+ osd_options &options = downcast<osd_options &>(m_machine.options());
+ set_starting_view(m_index, options.view(), options.view(m_index));
+}
+
+bool osd_window::renderer_interactive() const
+{
+ return m_renderprovider.is_interactive();
+}
+
+bool osd_window::renderer_sdl_needs_opengl() const
+{
+ return m_renderprovider.sdl_needs_opengl();
+}
+
+void osd_window::renderer_create()
+{
+ m_renderer = m_renderprovider.create(*this);
+}
+
+void osd_window::set_starting_view(int index, const char *defview, const char *view)
+{
+ // choose non-auto over auto
+ if ((!*view || !strcmp(view, "auto")) && (*defview && strcmp(defview, "auto")))
+ view = defview;
+
+ // query the video system to help us pick a view
+ int viewindex = m_target->configured_view(view, index, video_config.numscreens);
+
+ // set the view
+ m_target->set_view(viewindex);
+}
+
+void osd_window::destroy()
+{
+ // free the textures etc
+ complete_destroy();
+
+ // free the render target, after the textures!
+ m_machine.render().target_free(m_target);
+ m_target = nullptr;
}
diff --git a/src/osd/modules/osdwindow.h b/src/osd/modules/osdwindow.h
index 3fe020c56fe..9167a775682 100644
--- a/src/osd/modules/osdwindow.h
+++ b/src/osd/modules/osdwindow.h
@@ -6,13 +6,21 @@
//
//============================================================
-#ifndef __OSDWINDOW__
-#define __OSDWINDOW__
+#ifndef MAME_OSD_MODULES_OSDWINDOW_H
+#define MAME_OSD_MODULES_OSDWINDOW_H
-#include "render.h"
+#pragma once
+
+#include "emucore.h"
#include "osdhelper.h"
#include "../frontend/mame/ui/menuitem.h"
+#include <cassert>
+#include <chrono>
+#include <memory>
+#include <string>
+#include <vector>
+
// standard windows headers
#ifdef OSD_WINDOWS
#include <windows.h>
@@ -20,32 +28,16 @@
#include <mmsystem.h>
#endif
-#ifdef OSD_SDL
-// forward declaration
-struct SDL_Window;
-#endif
-
//============================================================
// TYPE DEFINITIONS
//============================================================
-class osd_options;
+class osd_monitor_info;
+class render_module;
class render_primitive_list;
-enum
-{
- VIDEO_MODE_NONE = 0,
- VIDEO_MODE_GDI,
- VIDEO_MODE_BGFX,
-#if defined(USE_OPENGL) && USE_OPENGL
- VIDEO_MODE_OPENGL,
-#endif
- VIDEO_MODE_SDL2ACCEL,
- VIDEO_MODE_D3D,
- VIDEO_MODE_SOFT,
+class osd_renderer;
- VIDEO_MODE_COUNT
-};
class osd_window_config
{
@@ -59,58 +51,37 @@ public:
int refresh; // decoded refresh
};
-class osd_renderer;
-class osd_monitor_info;
-class osd_window : public std::enable_shared_from_this<osd_window>
+class osd_window
{
public:
- osd_window(const osd_window_config &config)
- :
-#ifdef OSD_WINDOWS
- m_dc(nullptr), m_resize_state(0),
-#endif
- m_primlist(nullptr),
- m_win_config(config),
- m_index(0),
- m_prescale(1),
- m_renderer(nullptr),
- m_main(nullptr)
- {}
-
- virtual ~osd_window() { }
+ virtual ~osd_window();
- virtual render_target *target() = 0;
- virtual int fullscreen() const = 0;
- virtual running_machine &machine() const = 0;
+ render_target *target() const { return m_target; }
+ int fullscreen() const { return m_fullscreen; }
+ running_machine &machine() const { return m_machine; }
+ const std::string &title() const { return m_title; }
bool has_renderer() const { return m_renderer != nullptr; }
osd_renderer &renderer() const { return *m_renderer; }
- void set_renderer(std::unique_ptr<osd_renderer> renderer)
- {
- m_renderer = std::move(renderer);
- }
- void renderer_reset() { m_renderer.reset(); }
+ void renderer_reset() { m_renderer.reset(); } // public because OSD object calls it directly during teardown
- int prescale() const { return m_prescale; };
+ int index() const { return m_index; }
+ int prescale() const { return m_prescale; }
float pixel_aspect() const;
- bool swap_xy()
- {
- bool orientation_swap_xy =
- (machine().system().flags & ORIENTATION_SWAP_XY) == ORIENTATION_SWAP_XY;
- bool rotation_swap_xy =
- (target()->orientation() & ORIENTATION_SWAP_XY) == ORIENTATION_SWAP_XY;
- return orientation_swap_xy ^ rotation_swap_xy;
- };
+ bool swap_xy() const;
+
+ bool keepaspect() const;
virtual osd_dim get_size() = 0;
- virtual osd_monitor_info *monitor() const = 0;
+ osd_monitor_info *monitor() const { return m_monitor.get(); }
+ std::shared_ptr<osd_monitor_info> monitor_from_rect(const osd_rect *proposed) const;
- std::shared_ptr<osd_window> main_window() const { return m_main; }
- void set_main_window(std::shared_ptr<osd_window> main) { m_main = main; }
+ void create_target();
+ void destroy();
// Clips the pointer to the bounds of this window
virtual void capture_pointer() = 0;
@@ -122,45 +93,252 @@ public:
virtual void hide_pointer() = 0;
virtual void update() = 0;
- virtual void destroy() = 0;
+ virtual void complete_destroy() = 0;
-#if defined(OSD_WINDOWS) || defined(OSD_UWP)
- virtual bool win_has_menu() = 0;
-#endif
+protected:
+ static inline constexpr int CLICK_DISTANCE = 16; // in pointer units squared
+ static inline constexpr int TAP_DISTANCE = 49; // taps are less repeatable than clicks
-#ifdef OSD_WINDOWS
- HDC m_dc; // only used by GDI renderer!
- int m_resize_state;
-#endif
+ struct prev_touch
+ {
+ prev_touch() = default;
+ prev_touch(prev_touch const &) = default;
+ prev_touch(prev_touch &&) = default;
+ prev_touch &operator=(prev_touch const &) = default;
+ prev_touch &operator=(prev_touch &&) = default;
+
+ std::chrono::steady_clock::time_point when = std::chrono::steady_clock::time_point::min();
+ int x = 0, y = 0, cnt = 0;
+ };
+
+ struct pointer_dev_info
+ {
+ pointer_dev_info() = default;
+ pointer_dev_info(pointer_dev_info const &) = default;
+ pointer_dev_info(pointer_dev_info &&) = default;
+ pointer_dev_info &operator=(pointer_dev_info const &) = default;
+ pointer_dev_info &operator=(pointer_dev_info &&) = default;
+
+ unsigned clear_expired_touches(std::chrono::steady_clock::time_point const &now, std::chrono::steady_clock::duration const &time);
+ unsigned consume_touch(unsigned i);
+
+ prev_touch touches[8];
+ };
+
+ struct pointer_info
+ {
+ pointer_info(pointer_info const &) = default;
+ pointer_info(pointer_info &&) = default;
+ pointer_info &operator=(pointer_info const &) = default;
+ pointer_info &operator=(pointer_info &&) = default;
+
+ pointer_info(unsigned i, unsigned d);
+
+ void primary_down(
+ int cx,
+ int cy,
+ std::chrono::steady_clock::duration const &time,
+ int tolerance,
+ bool checkprev,
+ std::vector<pointer_dev_info> &devices);
+ void check_primary_hold_drag(
+ int cx,
+ int cy,
+ std::chrono::steady_clock::duration const &time,
+ int tolerance);
+
+ std::chrono::steady_clock::time_point pressed;
+ unsigned index, device;
+ int x, y;
+ unsigned buttons;
+ int pressedx, pressedy;
+ int clickcnt;
+ };
+
+ osd_window(
+ running_machine &machine,
+ render_module &renderprovider,
+ int index,
+ const std::shared_ptr<osd_monitor_info> &monitor,
+ const osd_window_config &config);
+
+ bool renderer_interactive() const;
+ bool renderer_sdl_needs_opengl() const;
+ void renderer_create();
+
+private:
+ void set_starting_view(int index, const char *defview, const char *view);
+
+private:
+ render_target *m_target;
+public:
render_primitive_list *m_primlist;
osd_window_config m_win_config;
+private:
int m_index;
protected:
+ bool m_fullscreen;
int m_prescale;
+
private:
- std::unique_ptr<osd_renderer> m_renderer;
- std::shared_ptr<osd_window> m_main;
+ running_machine &m_machine;
+ render_module &m_renderprovider;
+ std::shared_ptr<osd_monitor_info> m_monitor;
+ std::unique_ptr<osd_renderer> m_renderer;
+ const std::string m_title;
};
-template <class TWindowHandle>
-class osd_window_t : public osd_window
+
+inline unsigned osd_window::pointer_dev_info::clear_expired_touches(
+ std::chrono::steady_clock::time_point const &now,
+ std::chrono::steady_clock::duration const &time)
{
-private:
- TWindowHandle m_platform_window;
-public:
- osd_window_t(const osd_window_config &config)
- : osd_window(config),
- m_platform_window(nullptr)
+ // find first non-expired touch (if any)
+ unsigned end(0);
+ while ((std::size(touches) > end) && touches[end].cnt && ((touches[end].when + time) < now))
+ touches[end++].cnt = 0;
+
+ // shift non-expired touches back if necessary
+ if (end)
+ {
+ unsigned pos(0);
+ while ((std::size(touches) > end) && touches[end].cnt)
+ {
+ touches[pos++] = std::move(touches[end]);
+ touches[end++].cnt = 0;
+ }
+ return pos;
+ }
+ else
+ {
+ while ((std::size(touches) > end) && touches[end].cnt)
+ ++end;
+ return end;
+ }
+}
+
+inline unsigned osd_window::pointer_dev_info::consume_touch(unsigned i)
+{
+ assert(std::size(touches) > i);
+ touches[i].cnt = 0;
+ unsigned pos(i + 1);
+ while ((std::size(touches) > pos) && touches[pos].cnt)
+ {
+ touches[i++] = std::move(touches[pos]);
+ touches[pos++].cnt = 0;
+ }
+ return i;
+}
+
+inline osd_window::pointer_info::pointer_info(unsigned i, unsigned d) :
+ pressed(std::chrono::steady_clock::time_point::min()),
+ index(i),
+ device(d),
+ x(-1),
+ y(-1),
+ buttons(0),
+ pressedx(0),
+ pressedy(0),
+ clickcnt(0)
+{
+}
+
+inline void osd_window::pointer_info::primary_down(
+ int cx,
+ int cy,
+ std::chrono::steady_clock::duration const &time,
+ int tolerance,
+ bool checkprev,
+ std::vector<pointer_dev_info> &devices)
+{
+ auto const now(std::chrono::steady_clock::now());
+ auto const exp(time + pressed);
+ if (0 > clickcnt)
+ {
+ // previous click turned into a hold/drag
+ clickcnt = 1;
+ }
+ else if (clickcnt)
+ {
+ // potential multi-click action
+ int const dx(cx - pressedx);
+ int const dy(cy - pressedy);
+ int const distance((dx * dx) + (dy * dy));
+ if ((exp < now) || (tolerance < distance))
+ clickcnt = 1;
+ else
+ ++clickcnt;
+ }
+ else
+ {
+ // first click for this pointer, but may need to check previous touches
+ clickcnt = 1;
+ if (checkprev)
+ {
+ if (devices.size() > device)
+ {
+ auto &devinfo(devices[device]);
+ unsigned const end(devinfo.clear_expired_touches(now, time));
+ for (int i = 0; end > i; ++i)
+ {
+ int const dx(cx - devinfo.touches[i].x);
+ int const dy(cy - devinfo.touches[i].y);
+ int const distance((dx * dx) + (dy * dy));
+ if (tolerance >= distance)
+ {
+ // close match - consume it
+ clickcnt = devinfo.touches[i].cnt + 1;
+ devinfo.consume_touch(i);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // record the time/location where the pointer was pressed
+ pressed = now;
+ pressedx = cx;
+ pressedy = cy;
+}
+
+inline void osd_window::pointer_info::check_primary_hold_drag(
+ int cx,
+ int cy,
+ std::chrono::steady_clock::duration const &time,
+ int tolerance)
+{
+ // check for conversion to a (multi-)click-and-hold/drag
+ if (0 < clickcnt)
{
+ auto const now(std::chrono::steady_clock::now());
+ auto const exp(time + pressed);
+ int const dx(cx - pressedx);
+ int const dy(cy - pressedy);
+ int const distance((dx * dx) + (dy * dy));
+ if ((exp < now) || (tolerance < distance))
+ clickcnt = -clickcnt;
}
+}
+
+template <class TWindowHandle>
+class osd_window_t : public osd_window
+{
+public:
TWindowHandle platform_window() const { return m_platform_window; }
+protected:
+ using osd_window::osd_window;
+
void set_platform_window(TWindowHandle window)
{
assert(window == nullptr || m_platform_window == nullptr);
m_platform_window = window;
}
+
+private:
+ TWindowHandle m_platform_window = nullptr;
};
@@ -170,31 +348,13 @@ public:
/* Generic flags */
static const int FLAG_NONE = 0x0000;
- static const int FLAG_NEEDS_OPENGL = 0x0001;
- static const int FLAG_HAS_VECTOR_SCREEN = 0x0002;
+ static const int FLAG_HAS_VECTOR_SCREEN = 0x0001;
- /* SDL 1.2 flags */
- static const int FLAG_NEEDS_DOUBLEBUF = 0x0100;
- static const int FLAG_NEEDS_ASYNCBLIT = 0x0200;
-
- osd_renderer(std::shared_ptr<osd_window> window, const int flags)
- : m_sliders_dirty(false), m_window(window), m_flags(flags)
- { }
+ osd_renderer(osd_window &window) : m_sliders_dirty(false), m_window(window), m_flags(0) { }
virtual ~osd_renderer() { }
- std::shared_ptr<osd_window> assert_window() const
- {
- auto win = m_window.lock();
- if (!win)
- throw emu_fatalerror("osd_renderer::assert_window: Window weak_ptr is not available!");
- return win;
- }
-
- std::shared_ptr<osd_window> try_getwindow() const
- {
- return m_window.lock();
- }
+ osd_window &window() const { return m_window; }
bool has_flags(const int flag) const { return ((m_flags & flag)) == flag; }
void set_flags(int aflag) { m_flags |= aflag; }
@@ -210,14 +370,12 @@ public:
virtual void add_audio_to_recording(const int16_t *buffer, int samples_this_frame) { }
virtual std::vector<ui::menu_item> get_slider_list() { return m_sliders; }
virtual int draw(const int update) = 0;
- virtual int xy_to_render_target(const int x, const int y, int *xt, int *yt) { return 0; };
- virtual void save() { };
- virtual void record() { };
- virtual void toggle_fsfx() { };
+ virtual int xy_to_render_target(const int x, const int y, int *xt, int *yt) { return 0; }
+ virtual void save() { }
+ virtual void record() { }
+ virtual void toggle_fsfx() { }
virtual bool sliders_dirty() { return m_sliders_dirty; }
- static std::unique_ptr<osd_renderer> make_for_type(int mode, std::shared_ptr<osd_window> window, int extra_flags = FLAG_NONE);
-
protected:
virtual void build_slider_list() { }
@@ -227,7 +385,7 @@ protected:
std::vector<ui::menu_item> m_sliders;
private:
- std::weak_ptr<osd_window> m_window;
+ osd_window &m_window;
int m_flags;
};
@@ -239,10 +397,6 @@ private:
#define MAX_VIDEO_WINDOWS (4)
-#define VIDEO_SCALE_MODE_NONE (0)
-
-#define GLSL_SHADER_MAX 10
-
//============================================================
// TYPE DEFINITIONS
@@ -253,40 +407,22 @@ struct osd_video_config
// global configuration
int windowed; // start windowed?
int prescale; // prescale factor
- int keepaspect; // keep aspect ratio
int numscreens; // number of screens
- int fullstretch; // fractional stretch
// hardware options
- int mode; // output mode
int waitvsync; // spin until vsync
int syncrefresh; // sync only to refresh rate
int switchres; // switch resolutions
// d3d, accel, opengl
int filter; // enable filtering
- //int filter; // enable filtering, disabled if glsl_filter>0
-
- // OpenGL options
- int glsl;
- int glsl_filter; // glsl filtering, >0 disables filter
- char * glsl_shader_mamebm[GLSL_SHADER_MAX]; // custom glsl shader set, mame bitmap
- int glsl_shader_mamebm_num; // custom glsl shader set number, mame bitmap
- char * glsl_shader_scrn[GLSL_SHADER_MAX]; // custom glsl shader set, screen bitmap
- int glsl_shader_scrn_num; // custom glsl shader number, screen bitmap
- int pbo;
- int vbo;
- int allowtexturerect; // allow GL_ARB_texture_rectangle, default: no
- int forcepow2texture; // force power of two textures, default: no
-
- // dd, d3d
+
+ // d3d
int triplebuf; // triple buffer
//============================================================
// SDL - options
//============================================================
- int novideo; // don't draw, for pure CPU benchmarking
-
int centerh;
int centerv;
@@ -298,9 +434,6 @@ struct osd_video_config
// X11 options
int restrictonemonitor; // in fullscreen, confine to Xinerama monitor 0
-
- // YUV options
- int scale_mode;
};
//============================================================
@@ -309,4 +442,4 @@ struct osd_video_config
extern osd_video_config video_config;
-#endif /* __OSDWINDOW__ */
+#endif // MAME_OSD_MODULES_OSDWINDOW_H
diff --git a/src/osd/modules/output/console.cpp b/src/osd/modules/output/console.cpp
index c9983736fb0..14e0f0fdebf 100644
--- a/src/osd/modules/output/console.cpp
+++ b/src/osd/modules/output/console.cpp
@@ -9,18 +9,23 @@
*******************************************************************c********/
#include "output_module.h"
+
#include "modules/osdmodule.h"
+#include "osdcore.h"
+
+namespace osd {
+
+namespace {
class output_console : public osd_module, public output_module
{
public:
- output_console()
- : osd_module(OSD_OUTPUT_PROVIDER, "console"), output_module()
+ output_console() : osd_module(OSD_OUTPUT_PROVIDER, "console")
{
}
virtual ~output_console() { }
- virtual int init(const osd_options &options) override { return 0; }
+ virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
virtual void exit() override { }
// output_module
@@ -29,4 +34,9 @@ public:
};
-MODULE_DEFINITION(OUTPUT_CONSOLE, output_console)
+} // anonymous namespace
+
+} // namespace osd
+
+
+MODULE_DEFINITION(OUTPUT_CONSOLE, osd::output_console)
diff --git a/src/osd/modules/output/network.cpp b/src/osd/modules/output/network.cpp
index e92b009670f..26ce3619a4c 100644
--- a/src/osd/modules/output/network.cpp
+++ b/src/osd/modules/output/network.cpp
@@ -9,8 +9,9 @@
***************************************************************************/
#include "output_module.h"
-#include "modules/osdmodule.h"
+
#include "modules/lib/osdobj_common.h"
+#include "modules/osdmodule.h"
#include "emu.h"
@@ -19,181 +20,182 @@
#define ASIO_HAS_EPOLL
#endif
-#include <thread>
-#include <set>
#include "asio.h"
+#include <memory>
+#include <set>
+#include <thread>
+
+
+namespace osd {
+
+namespace {
+
class output_client
{
public:
- virtual ~output_client() {}
- virtual void deliver(std::string &msg) = 0;
+ virtual ~output_client() { }
+ virtual void deliver(std::string &msg) = 0;
};
using output_client_ptr = std::shared_ptr<output_client>;
using client_set = std::set<output_client_ptr>;
-class output_session : public output_client,
- public std::enable_shared_from_this<output_session>
+class output_session : public output_client, public std::enable_shared_from_this<output_session>
{
public:
- output_session(asio::ip::tcp::socket socket, client_set *clients) :
- m_socket(std::move(socket)),
- m_clients(clients)
- {
- }
-
- void start(running_machine &machine)
- {
- m_machine = &machine;
- m_clients->insert(shared_from_this());
- // now send "mame_start = rom" to the newly connected client
- std::snprintf(m_data, max_length, "mame_start = %s\r", machine.system().name);
- do_write(std::strlen(m_data));
- do_read();
- }
-
-private:
- void deliver(std::string &msg)
- {
- std::strncpy(m_data, msg.c_str(), max_length);
- do_write(msg.size());
- }
+ output_session(asio::ip::tcp::socket socket, client_set *clients) :
+ m_socket(std::move(socket)),
+ m_clients(clients)
+ {
+ }
- void handle_message(char *msg)
- {
- const char *equals_delimiter = " = ";
- char *msg_name = strtok(msg, equals_delimiter);
- char *msg_value = strtok(NULL, equals_delimiter);
+ void start(running_machine &machine)
+ {
+ m_machine = &machine;
+ m_clients->insert(shared_from_this());
+ // now send "mame_start = rom" to the newly connected client
+ std::snprintf(m_data, max_length, "mame_start = %s\r", machine.system().name);
+ do_write(std::strlen(m_data));
+ do_read();
+ }
- //printf("handle_message: msg_name [%s] msg_value [%s]\n", msg_name, msg_value);
+private:
+ void deliver(std::string &msg)
+ {
+ std::strncpy(m_data, msg.c_str(), max_length);
+ do_write(msg.size());
+ }
- if (std::strcmp(msg_name, "mame_message") == 0)
+ void handle_message(char *msg)
{
- const char *comma_delimiter = ",";
- msg_name = strtok(msg_value, comma_delimiter);
- msg_value = strtok(NULL, comma_delimiter);
- int id = atoi(msg_name);
- int value = atoi(msg_value);
+ const char *equals_delimiter = " = ";
+ char *msg_name = strtok(msg, equals_delimiter);
+ char *msg_value = strtok(NULL, equals_delimiter);
- switch(id)
+ //printf("handle_message: msg_name [%s] msg_value [%s]\n", msg_name, msg_value);
+
+ if (std::strcmp(msg_name, "mame_message") == 0)
{
- case IM_MAME_PAUSE:
- if (value == 1 && !machine().paused())
- {
- machine().pause();
- }
- else if (value == 0 && machine().paused())
- {
- machine().resume();
- }
- break;
- case IM_MAME_SAVESTATE:
- if (value == 0)
- {
- machine().schedule_load("auto");
- }
- else if (value == 1)
+ const char *comma_delimiter = ",";
+ msg_name = strtok(msg_value, comma_delimiter);
+ msg_value = strtok(NULL, comma_delimiter);
+ int id = atoi(msg_name);
+ int value = atoi(msg_value);
+
+ switch(id)
{
- machine().schedule_save("auto");
+ case output_module::IM_MAME_PAUSE:
+ if (value == 1 && !machine().paused())
+ machine().pause();
+ else if (value == 0 && machine().paused())
+ machine().resume();
+ break;
+ case output_module::IM_MAME_SAVESTATE:
+ if (value == 0)
+ machine().schedule_load("auto");
+ else if (value == 1)
+ machine().schedule_save("auto");
+ break;
}
- break;
}
- }
-}
-
- void do_read()
- {
- auto self(shared_from_this());
- m_socket.async_read_some(asio::buffer(m_input_m_data, max_length),
- [this, self](std::error_code ec, std::size_t length)
- {
- if (!ec)
- {
- if (length > 0)
+ }
+
+ void do_read()
+ {
+ auto self(shared_from_this());
+ m_socket.async_read_some(
+ asio::buffer(m_input_m_data, max_length),
+ [this, self] (std::error_code ec, std::size_t length)
{
- m_input_m_data[length] = '\0';
- handle_message(m_input_m_data);
- }
- do_read();
- }
- else
- {
- m_clients->erase(shared_from_this());
- }
- });
- }
-
- void do_write(std::size_t length)
- {
- auto self(shared_from_this());
- asio::async_write(m_socket, asio::buffer(m_data, length),
- [this, self](std::error_code ec, std::size_t /*length*/)
- {
- if (ec)
- {
- m_clients->erase(shared_from_this());
- }
- });
- }
-
- running_machine &machine() const { return *m_machine; }
-
- asio::ip::tcp::socket m_socket;
- enum { max_length = 1024 };
- char m_data[max_length];
- char m_input_m_data[max_length];
- client_set *m_clients;
- running_machine *m_machine;
+ if (!ec)
+ {
+ if (length > 0)
+ {
+ m_input_m_data[length] = '\0';
+ handle_message(m_input_m_data);
+ }
+ do_read();
+ }
+ else
+ {
+ m_clients->erase(shared_from_this());
+ }
+ });
+ }
+
+ void do_write(std::size_t length)
+ {
+ auto self(shared_from_this());
+ asio::async_write(
+ m_socket,
+ asio::buffer(m_data, length),
+ [this, self] (std::error_code ec, std::size_t /*length*/)
+ {
+ if (ec)
+ {
+ m_clients->erase(shared_from_this());
+ }
+ });
+ }
+
+ running_machine &machine() const { return *m_machine; }
+
+ asio::ip::tcp::socket m_socket;
+ enum { max_length = 1024 };
+ char m_data[max_length];
+ char m_input_m_data[max_length];
+ client_set *m_clients;
+ running_machine *m_machine;
};
class output_network_server
{
public:
- output_network_server(asio::io_context& io_context, short port, running_machine &machine) :
- m_acceptor(io_context, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port))
- {
- m_machine = &machine;
- do_accept();
- }
-
- void deliver_to_all(std::string msg)
- {
- for (auto client: m_clients)
- client->deliver(msg);
- }
+ output_network_server(asio::io_context& io_context, short port, running_machine &machine) :
+ m_acceptor(io_context, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port))
+ {
+ m_machine = &machine;
+ do_accept();
+ }
+
+ void deliver_to_all(std::string msg)
+ {
+ for (const auto &client: m_clients)
+ client->deliver(msg);
+ }
private:
- void do_accept()
- {
- m_acceptor.async_accept(
- [this](std::error_code ec, asio::ip::tcp::socket socket)
- {
- if (!ec)
- {
- std::make_shared<output_session>(std::move(socket),&m_clients)->start(machine());
- }
+ void do_accept()
+ {
+ m_acceptor.async_accept(
+ [this] (std::error_code ec, asio::ip::tcp::socket socket)
+ {
+ if (!ec)
+ {
+ std::make_shared<output_session>(std::move(socket),&m_clients)->start(machine());
+ }
- do_accept();
- });
- }
+ do_accept();
+ });
+ }
- running_machine &machine() const { return *m_machine; }
+ running_machine &machine() const { return *m_machine; }
- asio::ip::tcp::acceptor m_acceptor;
- client_set m_clients;
- running_machine *m_machine;
+ asio::ip::tcp::acceptor m_acceptor;
+ client_set m_clients;
+ running_machine *m_machine;
};
class output_network : public osd_module, public output_module
{
public:
- output_network()
- : osd_module(OSD_OUTPUT_PROVIDER, "network"),
- output_module(),
- m_io_context(nullptr), m_server(nullptr)
+ output_network() :
+ osd_module(OSD_OUTPUT_PROVIDER, "network"),
+ output_module(),
+ m_machine(nullptr)
{
}
@@ -201,9 +203,10 @@ public:
{
}
- virtual int init(const osd_options &options) override
+ virtual int init(osd_interface &osd, const osd_options &options) override
{
- m_working_thread = std::thread([](output_network* self) { self->process_output(); }, this);
+ m_machine = &downcast<osd_common_t &>(osd).machine();
+ m_working_thread = std::thread([] (output_network* self) { self->process_output(); }, this);
return 0;
}
@@ -213,31 +216,38 @@ public:
notify("mame_stop", 1);
m_io_context->stop();
m_working_thread.join();
- delete m_server;
- delete m_io_context;
+ m_server.reset();
+ m_io_context.reset();
+ m_machine = nullptr;
}
// output_module
virtual void notify(const char *outname, int32_t value) override
{
- static char buf[256];
- sprintf(buf, "%s = %d\r", ((outname==nullptr) ? "none" : outname), value);
- m_server->deliver_to_all(buf);
+ auto msg = util::string_format("%s = %d\r", ((outname==nullptr) ? "none" : outname), value);
+ m_server->deliver_to_all(msg);
}
// implementation
void process_output()
{
- m_io_context = new asio::io_context();
- m_server = new output_network_server(*m_io_context, 8000, machine());
+ m_io_context.reset(new asio::io_context);
+ m_server.reset(new output_network_server(*m_io_context, 8000, machine()));
m_io_context->run();
}
private:
+ running_machine &machine() { return *m_machine; }
+
std::thread m_working_thread;
- asio::io_context *m_io_context;
- output_network_server *m_server;
+ std::unique_ptr<asio::io_context> m_io_context;
+ std::unique_ptr<output_network_server> m_server;
+ running_machine *m_machine;
};
-MODULE_DEFINITION(OUTPUT_NETWORK, output_network)
+} // anonymous namespace
+
+} // namespace osd
+
+MODULE_DEFINITION(OUTPUT_NETWORK, osd::output_network)
diff --git a/src/osd/modules/output/none.cpp b/src/osd/modules/output/none.cpp
index a4a613ef29f..3e06921827d 100644
--- a/src/osd/modules/output/none.cpp
+++ b/src/osd/modules/output/none.cpp
@@ -9,18 +9,22 @@
*******************************************************************c********/
#include "output_module.h"
+
#include "modules/osdmodule.h"
+namespace osd {
+
+namespace {
+
class output_none : public osd_module, public output_module
{
public:
- output_none()
- : osd_module(OSD_OUTPUT_PROVIDER, "none"), output_module()
+ output_none() : osd_module(OSD_OUTPUT_PROVIDER, "none")
{
}
virtual ~output_none() { }
- virtual int init(const osd_options &options) override { return 0; }
+ virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
virtual void exit() override { }
// output_module
@@ -29,4 +33,8 @@ public:
};
-MODULE_DEFINITION(OUTPUT_NONE, output_none)
+} // anonymous namespace
+
+} // namespace osd
+
+MODULE_DEFINITION(OUTPUT_NONE, osd::output_none)
diff --git a/src/osd/modules/output/output_module.h b/src/osd/modules/output/output_module.h
index 9046fda3252..ae86cfe9084 100644
--- a/src/osd/modules/output/output_module.h
+++ b/src/osd/modules/output/output_module.h
@@ -4,12 +4,15 @@
* outpout_module.h
*
*/
+#ifndef MAME_OSD_OUTPUT_OUTPUT_MODULE_H
+#define MAME_OSD_OUTPUT_OUTPUT_MODULE_H
-#ifndef OUTPUT_MODULE_H_
-#define OUTPUT_MODULE_H_
+#pragma once
#include "osdepend.h"
-#include "modules/osdmodule.h"
+
+#include <cstdint>
+
//============================================================
// CONSTANTS
@@ -17,22 +20,15 @@
#define OSD_OUTPUT_PROVIDER "output"
-#define IM_MAME_PAUSE 0
-#define IM_MAME_SAVESTATE 1
-
class output_module
{
public:
- output_module(): m_machine(nullptr) { }
+ static inline constexpr unsigned IM_MAME_PAUSE = 0;
+ static inline constexpr unsigned IM_MAME_SAVESTATE = 1;
- virtual ~output_module() { }
+ virtual ~output_module() = default;
virtual void notify(const char *outname, int32_t value) = 0;
-
- void set_machine(running_machine *machine) { m_machine = machine; };
- running_machine &machine() const { return *m_machine; }
-private:
- running_machine *m_machine;
};
-#endif /* OUTPUT_MODULE_H_ */
+#endif // MAME_OSD_OUTPUT_OUTPUT_MODULE_H
diff --git a/src/osd/modules/output/win32_output.cpp b/src/osd/modules/output/win32_output.cpp
index 3ee2cd6c17e..0d2d355b577 100644
--- a/src/osd/modules/output/win32_output.cpp
+++ b/src/osd/modules/output/win32_output.cpp
@@ -7,22 +7,27 @@
//============================================================
#include "output_module.h"
+
#include "modules/osdmodule.h"
-#include "modules/lib/osdobj_common.h"
#if defined(OSD_WINDOWS)
-// standard windows headers
-#include <windows.h>
+#include "win32_output.h"
+
+#include "winmain.h"
+#include "winutil.h"
// MAME headers
#include "emu.h"
-#include "winmain.h"
-#include "winutil.h"
-#include "win32_output.h"
+// standard windows headers
+#include <windows.h>
+namespace osd {
+
+namespace {
+
//============================================================
// CONSTANTS
//============================================================
@@ -66,30 +71,36 @@ class output_win32 : public osd_module, public output_module
{
public:
output_win32()
- : osd_module(OSD_OUTPUT_PROVIDER, "windows"), output_module(), m_output_hwnd(nullptr), m_clientlist(nullptr)
+ : osd_module(OSD_OUTPUT_PROVIDER, "windows")
+ , output_module()
+ , m_output_hwnd(nullptr)
+ , m_clientlist(nullptr)
+ , m_machine(nullptr)
{
}
virtual ~output_win32() { }
- virtual int init(const osd_options &options) override;
+ virtual int init(osd_interface &osd, const osd_options &options) override;
virtual void exit() override;
// output_module
-
virtual void notify(const char *outname, int32_t value) override;
- int create_window_class(void);
+ running_machine &machine() { return *m_machine; }
+
LRESULT register_client(HWND hwnd, LPARAM id);
LRESULT unregister_client(HWND hwnd, LPARAM id);
LRESULT send_id_string(HWND hwnd, LPARAM id);
private:
+ int create_window_class();
// our HWND
HWND m_output_hwnd;
// client list
registered_client * m_clientlist;
+ running_machine * m_machine;
};
@@ -97,8 +108,10 @@ private:
// output_init
//============================================================
-int output_win32::init(const osd_options &options)
+int output_win32::init(osd_interface &osd, const osd_options &options)
{
+ m_machine = &downcast<osd_common_t &>(osd).machine();
+
int result;
// reset globals
@@ -162,7 +175,7 @@ void output_win32::exit()
{
registered_client *temp = m_clientlist;
m_clientlist = temp->next;
- global_free(temp);
+ delete temp;
}
// broadcast a shutdown message
@@ -174,7 +187,7 @@ void output_win32::exit()
// create_window_class
//============================================================
-int output_win32::create_window_class(void)
+int output_win32::create_window_class()
{
static bool classes_created = false;
@@ -226,12 +239,13 @@ static LRESULT CALLBACK output_window_proc(HWND wnd, UINT message, WPARAM wparam
{
switch(wparam)
{
- case IM_MAME_PAUSE:
+ case output_module::IM_MAME_PAUSE:
if (lparam == 1 && !output.machine().paused())
output.machine().pause();
else if (lparam == 0 && output.machine().paused())
output.machine().resume();
- case IM_MAME_SAVESTATE:
+ break;
+ case output_module::IM_MAME_SAVESTATE:
if (lparam == 0)
output.machine().schedule_load("auto");
else if (lparam == 1)
@@ -261,19 +275,19 @@ LRESULT output_win32::register_client(HWND hwnd, LPARAM id)
if ((*client)->id == id)
{
(*client)->hwnd = hwnd;
- machine().output().notify_all(this);
+ machine().output().notify_all([this] (const char *outname, int32_t value) { notify(outname, value); });
return 1;
}
// add us to the end
- *client = global_alloc(registered_client);
+ *client = new registered_client;
(*client)->next = nullptr;
(*client)->id = id;
(*client)->hwnd = hwnd;
(*client)->machine = &machine();
// request a notification for all outputs
- machine().output().notify_all(this);
+ machine().output().notify_all([this] (const char *outname, int32_t value) { notify(outname, value); });
return 0;
}
@@ -293,7 +307,7 @@ LRESULT output_win32::unregister_client(HWND hwnd, LPARAM id)
{
registered_client *temp = *client;
*client = (*client)->next;
- global_free(temp);
+ delete temp;
found = true;
break;
}
@@ -326,7 +340,7 @@ LRESULT output_win32::send_id_string(HWND hwnd, LPARAM id)
// allocate memory for the message
datalen = sizeof(copydata_id_string) + strlen(name) + 1;
std::vector<uint8_t> buffer(datalen);
- copydata_id_string *temp = (copydata_id_string *)&buffer[0];
+ auto *temp = (copydata_id_string *)&buffer[0];
temp->id = id;
strcpy(temp->string, name);
@@ -346,18 +360,20 @@ LRESULT output_win32::send_id_string(HWND hwnd, LPARAM id)
void output_win32::notify(const char *outname, int32_t value)
{
- registered_client *client;
// loop over clients and notify them
- for (client = m_clientlist; client != nullptr; client = client->next)
- {
+ for (registered_client *client = m_clientlist; client != nullptr; client = client->next)
PostMessage(client->hwnd, om_mame_update_state, client->machine->output().name_to_id(outname), value);
- }
}
+} // anonymous namespace
+
+} // namespace osd
#else
- MODULE_NOT_SUPPORTED(output_win32, OSD_OUTPUT_PROVIDER, "windows")
+
+namespace osd { namespace { MODULE_NOT_SUPPORTED(output_win32, OSD_OUTPUT_PROVIDER, "windows") } }
+
#endif
-MODULE_DEFINITION(OUTPUT_WIN32, output_win32)
+MODULE_DEFINITION(OUTPUT_WIN32, osd::output_win32)
diff --git a/src/osd/modules/output/win32_output.h b/src/osd/modules/output/win32_output.h
index f0996b52082..bff3219b21f 100644
--- a/src/osd/modules/output/win32_output.h
+++ b/src/osd/modules/output/win32_output.h
@@ -2,12 +2,14 @@
// copyright-holders:Aaron Giles
//============================================================
//
-// output.h - Win32 implementation of MAME output routines
+// win32_output.h - Win32 implementation of MAME output routines
//
//============================================================
-#ifndef __WINDOWS_OUTPUT_H__
-#define __WINDOWS_OUTPUT_H__
+#ifndef MAME_OSD_OUTPUT_WIN32_OUTPUT_H
+#define MAME_OSD_OUTPUT_WIN32_OUTPUT_H
+
+#pragma once
//============================================================
@@ -83,8 +85,8 @@
struct copydata_id_string
{
- uint32_t id; // ID that was requested
+ uint32_t id; // ID that was requested
char string[1]; // string array containing the data
};
-#endif /* __WINDOWS_OUTPUT_H__ */
+#endif // MAME_OSD_OUTPUT_WIN32_OUTPUT_H
diff --git a/src/osd/modules/render/aviwrite.cpp b/src/osd/modules/render/aviwrite.cpp
index b1a4a013af4..e758d467e37 100644
--- a/src/osd/modules/render/aviwrite.cpp
+++ b/src/osd/modules/render/aviwrite.cpp
@@ -10,6 +10,7 @@
#include "aviwrite.h"
#include "modules/lib/osdobj_common.h"
+#include "fileio.h"
#include "screen.h"
@@ -31,7 +32,7 @@ avi_write::~avi_write()
}
}
-void avi_write::record(const char *name)
+void avi_write::record(std::string_view name)
{
if (m_recording)
{
@@ -47,7 +48,7 @@ void avi_write::stop()
end_avi_recording();
}
-void avi_write::begin_avi_recording(const char *name)
+void avi_write::begin_avi_recording(std::string_view name)
{
// stop any existing recording
end_avi_recording();
@@ -56,7 +57,7 @@ void avi_write::begin_avi_recording(const char *name)
m_frame = 0;
m_next_frame_time = m_machine.time();
- const screen_device *primary_screen = screen_device_iterator(m_machine.root_device()).first();
+ const screen_device *primary_screen = screen_device_enumerator(m_machine.root_device()).first();
// build up information about this new movie
avi_file::movie_info info;
info.video_format = 0;
@@ -71,7 +72,7 @@ void avi_write::begin_avi_recording(const char *name)
info.audio_timescale = m_machine.sample_rate();
info.audio_sampletime = 1;
info.audio_numsamples = 0;
- info.audio_channels = 2;
+ info.audio_channels = m_machine.sound().outputs_count();
info.audio_samplebits = 16;
info.audio_samplerate = m_machine.sample_rate();
@@ -80,12 +81,12 @@ void avi_write::begin_avi_recording(const char *name)
// create a new temporary movie file
emu_file tempfile(m_machine.options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
- const osd_file::error filerr = (!name || !name[0] || !std::strcmp(name, OSDOPTVAL_AUTO))
+ const std::error_condition filerr = (name.empty() || name == OSDOPTVAL_AUTO)
? m_machine.video().open_next(tempfile, "avi")
: tempfile.open(name);
// if we succeeded, make a copy of the name and create the real file over top
- if (filerr == osd_file::error::NONE)
+ if (!filerr)
{
const std::string fullpath = tempfile.fullpath();
tempfile.close();
@@ -141,9 +142,10 @@ void avi_write::audio_frame(const int16_t *buffer, int samples_this_frame)
if (m_output_file != nullptr)
{
// write the next frame
- avi_file::error avierr = m_output_file->append_sound_samples(0, buffer + 0, samples_this_frame, 1);
- if (avierr == avi_file::error::NONE)
- avierr = m_output_file->append_sound_samples(1, buffer + 1, samples_this_frame, 1);
+ int channels = m_machine.sound().outputs_count();
+ avi_file::error avierr = avi_file::error::NONE;
+ for (int channel = 0; channel != channels && avierr == avi_file::error::NONE; channel ++)
+ avierr = m_output_file->append_sound_samples(channel, buffer + channel, samples_this_frame, channels-1);
if (avierr != avi_file::error::NONE)
{
osd_printf_error("Error while logging AVI audio frame: %s\n", avi_file::error_string(avierr));
diff --git a/src/osd/modules/render/aviwrite.h b/src/osd/modules/render/aviwrite.h
index e59ce275168..a933dc2a3e6 100644
--- a/src/osd/modules/render/aviwrite.h
+++ b/src/osd/modules/render/aviwrite.h
@@ -6,13 +6,20 @@
//
//============================================================
+#ifndef MAME_RENDER_AVIWRITE_H
+#define MAME_RENDER_AVIWRITE_H
+
#pragma once
-#ifndef __RENDER_AVIWRITE__
-#define __RENDER_AVIWRITE__
+// emu
+#include "attotime.h"
+// lib/util
#include "aviio.h"
+#include <string_view>
+
+
class running_machine;
class avi_write
@@ -21,7 +28,7 @@ public:
avi_write(running_machine& machine, uint32_t width, uint32_t height);
~avi_write();
- void record(const char *name);
+ void record(std::string_view name);
void stop();
void audio_frame(const int16_t *buffer, int samples_this_frame);
void video_frame(bitmap_rgb32& snap);
@@ -30,7 +37,7 @@ public:
bool recording() const { return m_recording; }
private:
- void begin_avi_recording(const char *name);
+ void begin_avi_recording(std::string_view name);
void end_avi_recording();
running_machine& m_machine;
@@ -47,4 +54,4 @@ private:
attotime m_next_frame_time;
};
-#endif // __RENDER_AVIWRITE__
+#endif // MAME_RENDER_AVIWRITE_H
diff --git a/src/osd/modules/render/bgfx/blendreader.cpp b/src/osd/modules/render/bgfx/blendreader.cpp
index 9e7ddb17ce3..53cd57a9f4a 100644
--- a/src/osd/modules/render/bgfx/blendreader.cpp
+++ b/src/osd/modules/render/bgfx/blendreader.cpp
@@ -44,8 +44,11 @@ uint64_t blend_reader::read_from_value(const Value& value)
uint64_t equation = get_enum_from_value(value, "equation", BGFX_STATE_BLEND_EQUATION_ADD, EQUATION_NAMES, EQUATION_COUNT);
uint64_t srccolor = get_enum_from_value(value, "srcColor", BGFX_STATE_BLEND_ONE, FUNCTION_NAMES, FUNCTION_COUNT);
uint64_t dstcolor = get_enum_from_value(value, "dstColor", BGFX_STATE_BLEND_ZERO, FUNCTION_NAMES, FUNCTION_COUNT);
- uint64_t srcalpha = get_enum_from_value(value, "srcAlpha", BGFX_STATE_BLEND_ONE, FUNCTION_NAMES, FUNCTION_COUNT);
- uint64_t dstalpha = get_enum_from_value(value, "dstAlpha", BGFX_STATE_BLEND_ZERO, FUNCTION_NAMES, FUNCTION_COUNT);
-
- return BGFX_STATE_BLEND_EQUATION(equation) | BGFX_STATE_BLEND_FUNC_SEPARATE(srccolor, dstcolor, srcalpha, dstalpha);
+ if (value.HasMember("srcAlpha") && value.HasMember("dstAlpha"))
+ {
+ uint64_t srcalpha = get_enum_from_value(value, "srcAlpha", BGFX_STATE_BLEND_ONE, FUNCTION_NAMES, FUNCTION_COUNT);
+ uint64_t dstalpha = get_enum_from_value(value, "dstAlpha", BGFX_STATE_BLEND_ZERO, FUNCTION_NAMES, FUNCTION_COUNT);
+ return BGFX_STATE_BLEND_EQUATION(equation) | BGFX_STATE_BLEND_FUNC_SEPARATE(srccolor, dstcolor, srcalpha, dstalpha);
+ }
+ return BGFX_STATE_BLEND_EQUATION(equation) | BGFX_STATE_BLEND_FUNC(srccolor, dstcolor);
}
diff --git a/src/osd/modules/render/bgfx/chain.cpp b/src/osd/modules/render/bgfx/chain.cpp
index c7691973854..8d5adb0ec25 100644
--- a/src/osd/modules/render/bgfx/chain.cpp
+++ b/src/osd/modules/render/bgfx/chain.cpp
@@ -6,33 +6,48 @@
//
//============================================================
+#include "chain.h"
+
#include "emu.h"
+#include "render.h"
+#include "rendlay.h"
+#include "screen.h"
#include <bx/timer.h>
#include "slider.h"
#include "parameter.h"
#include "entryuniform.h"
+#include "valueuniform.h"
#include "texturemanager.h"
#include "targetmanager.h"
+#include "chainmanager.h"
#include "target.h"
#include "vertex.h"
-#include "screen.h"
+#include "clear.h"
#include "modules/osdwindow.h"
-#include "chain.h"
-
-bgfx_chain::bgfx_chain(std::string name, std::string author, bool transform, target_manager& targets, std::vector<bgfx_slider*> sliders, std::vector<bgfx_parameter*> params, std::vector<bgfx_chain_entry*> entries, std::vector<bgfx_target*> target_list, std::uint32_t screen_index)
- : m_name(name)
- , m_author(author)
+bgfx_chain::bgfx_chain(
+ std::string &&name,
+ std::string &&author,
+ bool transform,
+ target_manager& targets,
+ std::vector<bgfx_slider*> &&sliders,
+ std::vector<bgfx_parameter*> &&params,
+ std::vector<bgfx_chain_entry*> &&entries,
+ std::vector<bgfx_target*> &&target_list,
+ std::uint32_t screen_index)
+ : m_name(std::move(name))
+ , m_author(std::move(author))
, m_transform(transform)
, m_targets(targets)
- , m_sliders(sliders)
- , m_params(params)
- , m_entries(entries)
- , m_target_list(target_list)
+ , m_sliders(std::move(sliders))
+ , m_params(std::move(params))
+ , m_entries(std::move(entries))
+ , m_target_list(std::move(target_list))
, m_current_time(0)
, m_screen_index(screen_index)
+ , m_has_converter(false)
{
for (bgfx_target* target : m_target_list)
{
@@ -72,14 +87,14 @@ void bgfx_chain::repopulate_targets()
}
}
-void bgfx_chain::process(render_primitive* prim, int view, int screen, texture_manager& textures, osd_window& window, uint64_t blend)
+void bgfx_chain::process(chain_manager::screen_prim &prim, int view, int screen, texture_manager& textures, osd_window& window)
{
- screen_device_iterator screen_iterator(window.machine().root_device());
+ screen_device_enumerator screen_iterator(window.machine().root_device());
screen_device* screen_device = screen_iterator.byindex(screen);
- uint16_t screen_count(window.target()->current_view()->screens().count());
- uint16_t screen_width(floorf(prim->get_quad_width() + 0.5f));
- uint16_t screen_height(floorf(prim->get_quad_height() + 0.5f));
+ uint16_t screen_count(window.target()->current_view().visible_screen_count());
+ uint16_t screen_width = prim.m_quad_width;
+ uint16_t screen_height = prim.m_quad_height;
uint32_t rotation_type =
(window.target()->orientation() & ROT90) == ROT90 ? 1 :
(window.target()->orientation() & ROT180) == ROT180 ? 2 :
@@ -102,11 +117,12 @@ void bgfx_chain::process(render_primitive* prim, int view, int screen, texture_m
}
int current_view = view;
- for (bgfx_chain_entry* entry : m_entries)
+ for (size_t i = 0; i < m_entries.size(); i++)
{
- if (!entry->skip())
+ if (!m_entries[i]->skip())
{
- entry->submit(current_view, prim, textures, screen_count, screen_width, screen_height, screen_scale_x, screen_scale_y, screen_offset_x, screen_offset_y, rotation_type, swap_xy, blend, screen);
+ m_entries[i]->submit(current_view, prim, textures, screen_count, screen_width, screen_height, screen_scale_x, screen_scale_y, screen_offset_x, screen_offset_y,
+ rotation_type, swap_xy, screen);
current_view++;
}
}
@@ -115,13 +131,13 @@ void bgfx_chain::process(render_primitive* prim, int view, int screen, texture_m
static int64_t last = m_current_time;
const int64_t frameTime = m_current_time - last;
last = m_current_time;
- const double freq = double(bx::getHPFrequency());
+ const auto freq = double(bx::getHPFrequency());
const double toMs = 1000.0 / freq;
const double frameTimeInSeconds = (double)frameTime / 1000000.0;
for (bgfx_parameter* param : m_params)
{
- param->tick(frameTimeInSeconds* toMs);
+ param->tick(frameTimeInSeconds * toMs);
}
}
@@ -138,3 +154,35 @@ uint32_t bgfx_chain::applicable_passes()
return applicable_passes;
}
+
+void bgfx_chain::insert_effect(uint32_t index, bgfx_effect *effect, const bool apply_tint, std::string name, std::string source, chain_manager &chains)
+{
+ auto *clear = new clear_state(BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH | BGFX_CLEAR_STENCIL, 0, 1.0f, 0);
+ std::vector<bgfx_suppressor*> suppressors;
+
+ std::vector<bgfx_input_pair*> inputs;
+ std::vector<std::string> available_textures;
+ inputs.push_back(new bgfx_input_pair(0, "s_tex", source, available_textures, "", chains, m_screen_index));
+ inputs.push_back(new bgfx_input_pair(1, "s_pal", "palette", available_textures, "", chains, m_screen_index));
+
+ std::vector<bgfx_entry_uniform*> uniforms;
+ float value = 1.0f;
+ float values[4] = { 1.0f, 1.0f, 0.0f, 0.0f };
+ uniforms.push_back(new bgfx_value_uniform(new bgfx_uniform("s_tex", bgfx::UniformType::Sampler), &value, 1));
+ uniforms.push_back(new bgfx_value_uniform(new bgfx_uniform("s_pal", bgfx::UniformType::Sampler), &value, 1));
+ uniforms.push_back(new bgfx_value_uniform(new bgfx_uniform("u_tex_size0", bgfx::UniformType::Vec4), values, 4));
+ uniforms.push_back(new bgfx_value_uniform(new bgfx_uniform("u_tex_size1", bgfx::UniformType::Vec4), values, 4));
+ uniforms.push_back(new bgfx_value_uniform(new bgfx_uniform("u_inv_tex_size0", bgfx::UniformType::Vec4), values, 4));
+ uniforms.push_back(new bgfx_value_uniform(new bgfx_uniform("u_inv_tex_size1", bgfx::UniformType::Vec4), values, 4));
+ uniforms.push_back(new bgfx_value_uniform(new bgfx_uniform("u_tex_bounds0", bgfx::UniformType::Vec4), values, 4));
+ uniforms.push_back(new bgfx_value_uniform(new bgfx_uniform("u_tex_bounds1", bgfx::UniformType::Vec4), values, 4));
+ uniforms.push_back(new bgfx_value_uniform(new bgfx_uniform("u_inv_tex_bounds0", bgfx::UniformType::Vec4), values, 4));
+ uniforms.push_back(new bgfx_value_uniform(new bgfx_uniform("u_inv_tex_bounds1", bgfx::UniformType::Vec4), values, 4));
+
+ m_entries.insert(m_entries.begin() + index, new bgfx_chain_entry(name, effect, clear, suppressors, inputs, uniforms, m_targets, "screen", apply_tint));
+
+ const uint32_t screen_width = chains.targets().width(TARGET_STYLE_GUEST, m_screen_index);
+ const uint32_t screen_height = chains.targets().height(TARGET_STYLE_GUEST, m_screen_index);
+ m_targets.destroy_target("screen", m_screen_index);
+ m_targets.create_target("screen", bgfx::TextureFormat::BGRA8, screen_width, screen_height, 1, 1, TARGET_STYLE_GUEST, true, false, 1, m_screen_index);
+}
diff --git a/src/osd/modules/render/bgfx/chain.h b/src/osd/modules/render/bgfx/chain.h
index 157f92173cf..5d84bb1ed0c 100644
--- a/src/osd/modules/render/bgfx/chain.h
+++ b/src/osd/modules/render/bgfx/chain.h
@@ -6,18 +6,17 @@
//
//============================================================
+#ifndef MAME_RENDER_BGFX_CHAIN_H
+#define MAME_RENDER_BGFX_CHAIN_H
+
#pragma once
-#ifndef __DRAWBGFX_CHAIN__
-#define __DRAWBGFX_CHAIN__
+#include "chainentry.h"
#include <string>
#include <vector>
#include <map>
-#include "chainentry.h"
-
-class render_primitive;
class bgfx_slider;
class bgfx_parameter;
class texture_manager;
@@ -28,17 +27,25 @@ class osd_window;
class bgfx_chain
{
public:
- bgfx_chain(std::string name, std::string author, bool transform, target_manager& targets, std::vector<bgfx_slider*> sliders, std::vector<bgfx_parameter*> params, std::vector<bgfx_chain_entry*> entries, std::vector<bgfx_target*> target_list, uint32_t screen_index);
+ bgfx_chain(std::string &&name, std::string &&author, bool transform, target_manager& targets, std::vector<bgfx_slider*> &&sliders, std::vector<bgfx_parameter*> &&params, std::vector<bgfx_chain_entry*> &&entries, std::vector<bgfx_target*> &&target_list, uint32_t screen_index);
~bgfx_chain();
- void process(render_primitive* prim, int view, int screen, texture_manager& textures, osd_window &window, uint64_t blend = 0L);
+ void process(chain_manager::screen_prim &prim, int view, int screen, texture_manager& textures, osd_window &window);
void repopulate_targets();
// Getters
+ const std::string &name() const { return m_name; }
std::vector<bgfx_slider*>& sliders() { return m_sliders; }
std::vector<bgfx_chain_entry*>& entries() { return m_entries; }
uint32_t applicable_passes();
- bool transform() { return m_transform; }
+ bool transform() const { return m_transform; }
+ bool has_converter() const { return m_has_converter; }
+ bool has_adjuster() const { return m_has_adjuster; }
+
+ // Setters
+ void set_has_converter(bool has_converter) { m_has_converter = has_converter; }
+ void set_has_adjuster(bool has_adjuster) { m_has_adjuster = has_adjuster; }
+ void insert_effect(uint32_t index, bgfx_effect *effect, const bool apply_tint, std::string name, std::string source, chain_manager &chains);
private:
std::string m_name;
@@ -53,6 +60,8 @@ private:
std::map<std::string, bgfx_target*> m_target_map;
int64_t m_current_time;
uint32_t m_screen_index;
+ bool m_has_converter;
+ bool m_has_adjuster;
};
-#endif // __DRAWBGFX_CHAIN__
+#endif // MAME_RENDER_BGFX_CHAIN_H
diff --git a/src/osd/modules/render/bgfx/chainentry.cpp b/src/osd/modules/render/bgfx/chainentry.cpp
index d48e279e9d2..c3f3ee3a8e3 100644
--- a/src/osd/modules/render/bgfx/chainentry.cpp
+++ b/src/osd/modules/render/bgfx/chainentry.cpp
@@ -9,10 +9,11 @@
//
//============================================================
-#include "emu.h"
+#include "chainmanager.h"
#include <bgfx/bgfx.h>
#include <bx/math.h>
+#include <cmath>
#include "chainentry.h"
@@ -25,10 +26,12 @@
#include "vertex.h"
#include "suppressor.h"
+#include "emucore.h"
#include "render.h"
-bgfx_chain_entry::bgfx_chain_entry(std::string name, bgfx_effect* effect, clear_state* clear, std::vector<bgfx_suppressor*> suppressors, std::vector<bgfx_input_pair*> inputs, std::vector<bgfx_entry_uniform*> uniforms, target_manager& targets, std::string output)
+bgfx_chain_entry::bgfx_chain_entry(std::string name, bgfx_effect* effect, clear_state* clear, std::vector<bgfx_suppressor*> suppressors, std::vector<bgfx_input_pair*> inputs,
+ std::vector<bgfx_entry_uniform*> uniforms, target_manager& targets, std::string output, bool apply_tint)
: m_name(name)
, m_effect(effect)
, m_clear(clear)
@@ -37,6 +40,7 @@ bgfx_chain_entry::bgfx_chain_entry(std::string name, bgfx_effect* effect, clear_
, m_uniforms(uniforms)
, m_targets(targets)
, m_output(output)
+ , m_apply_tint(apply_tint)
{
}
@@ -52,12 +56,18 @@ bgfx_chain_entry::~bgfx_chain_entry()
delete uniform;
}
m_uniforms.clear();
- delete m_clear;
+ if (m_clear)
+ {
+ delete m_clear;
+ }
}
-void bgfx_chain_entry::submit(int view, render_primitive* prim, texture_manager& textures, uint16_t screen_count, uint16_t screen_width, uint16_t screen_height, float screen_scale_x, float screen_scale_y, float screen_offset_x, float screen_offset_y, uint32_t rotation_type, bool swap_xy, uint64_t blend, int32_t screen)
+void bgfx_chain_entry::submit(int view, chain_manager::screen_prim &prim, texture_manager& textures, uint16_t screen_count, uint16_t screen_width, uint16_t screen_height,
+ float screen_scale_x, float screen_scale_y, float screen_offset_x, float screen_offset_y, uint32_t rotation_type, bool swap_xy, int32_t screen)
{
- if (!setup_view(view, screen_width, screen_height, screen))
+ uint16_t view_width = screen_width;
+ uint16_t view_height = screen_height;
+ if (!setup_view(textures, view, screen_width, screen_height, screen, view_width, view_height))
{
return;
}
@@ -67,11 +77,22 @@ void bgfx_chain_entry::submit(int view, render_primitive* prim, texture_manager&
input->bind(m_effect, screen);
}
+ uint32_t tint = 0xffffffff;
+ if (m_apply_tint)
+ {
+ const uint8_t a = (uint8_t)std::round(prim.m_prim->color.a * 255);
+ const uint8_t r = (uint8_t)std::round(prim.m_prim->color.r * 255);
+ const uint8_t g = (uint8_t)std::round(prim.m_prim->color.g * 255);
+ const uint8_t b = (uint8_t)std::round(prim.m_prim->color.b * 255);
+ tint = (a << 24) | (b << 16) | (g << 8) | r;
+ }
+
bgfx::TransientVertexBuffer buffer;
- put_screen_buffer(prim, &buffer);
- bgfx::setVertexBuffer(0,&buffer);
+ put_screen_buffer(view_width, view_height, tint, &buffer);
+ bgfx::setVertexBuffer(0, &buffer);
- setup_auto_uniforms(prim, textures, screen_count, screen_width, screen_height, screen_scale_x, screen_scale_y, screen_offset_x, screen_offset_y, rotation_type, swap_xy, screen);
+ setup_auto_uniforms(prim, textures, screen_count, view_width, view_height, screen_width, screen_height, screen_scale_x, screen_scale_y, screen_offset_x, screen_offset_y,
+ rotation_type, swap_xy, screen);
for (bgfx_entry_uniform* uniform : m_uniforms)
{
@@ -81,7 +102,7 @@ void bgfx_chain_entry::submit(int view, render_primitive* prim, texture_manager&
}
}
- m_effect->submit(view, blend);
+ m_effect->submit(view);
if (m_targets.target(screen, m_output) != nullptr)
{
@@ -89,6 +110,43 @@ void bgfx_chain_entry::submit(int view, render_primitive* prim, texture_manager&
}
}
+void bgfx_chain_entry::setup_auto_uniforms(chain_manager::screen_prim &prim, texture_manager& textures, uint16_t screen_count, uint16_t view_width, uint16_t view_height,
+ uint16_t screen_width, uint16_t screen_height, float screen_scale_x, float screen_scale_y, float screen_offset_x, float screen_offset_y,
+ uint32_t rotation_type, bool swap_xy, int32_t screen)
+{
+ setup_viewsize_uniforms(view_width, view_height);
+ setup_screensize_uniforms(textures, screen_width, screen_height, screen);
+ setup_screenscale_uniforms(screen_scale_x, screen_scale_y);
+ setup_screenoffset_uniforms(screen_offset_x, screen_offset_y);
+ setup_screencount_uniforms(screen_count);
+ setup_sourcesize_uniform(prim);
+ setup_targetsize_uniform(screen);
+ setup_targetscale_uniform(screen);
+ setup_rotationtype_uniform(rotation_type);
+ setup_swapxy_uniform(swap_xy);
+ setup_quaddims_uniform(prim);
+ setup_screenindex_uniform(screen);
+}
+
+void bgfx_chain_entry::setup_viewsize_uniforms(uint16_t view_width, uint16_t view_height)
+{
+ float width(view_width);
+ float height(view_height);
+ bgfx_uniform* view_dims = m_effect->uniform("u_view_dims");
+ if (view_dims != nullptr)
+ {
+ float values[2] = { width, height };
+ view_dims->set(values, sizeof(float) * 2);
+ }
+
+ bgfx_uniform* inv_view_dims = m_effect->uniform("u_inv_view_dims");
+ if (inv_view_dims != nullptr)
+ {
+ float values[2] = { -1.0f / width, 1.0f / height };
+ inv_view_dims->set(values, sizeof(float) * 2);
+ }
+}
+
void bgfx_chain_entry::setup_screensize_uniforms(texture_manager& textures, uint16_t screen_width, uint16_t screen_height, int32_t screen)
{
float width = screen_width;
@@ -145,13 +203,12 @@ void bgfx_chain_entry::setup_screencount_uniforms(uint16_t screen_count)
}
}
-void bgfx_chain_entry::setup_sourcesize_uniform(render_primitive* prim) const
+void bgfx_chain_entry::setup_sourcesize_uniform(chain_manager::screen_prim &prim) const
{
bgfx_uniform* source_dims = m_effect->uniform("u_source_dims");
if (source_dims != nullptr)
{
- float values[2] = { float(prim->texture.width), float(prim->texture.height) };
- source_dims->set(values, sizeof(float) * 2);
+ source_dims->set(&prim.m_tex_width, sizeof(float) * 2);
}
}
@@ -203,12 +260,12 @@ void bgfx_chain_entry::setup_swapxy_uniform(bool swap_xy) const
}
}
-void bgfx_chain_entry::setup_quaddims_uniform(render_primitive* prim) const
+void bgfx_chain_entry::setup_quaddims_uniform(chain_manager::screen_prim &prim) const
{
bgfx_uniform* quad_dims_uniform = m_effect->uniform("u_quad_dims");
if (quad_dims_uniform != nullptr)
{
- float values[2] = { float(floor((prim->bounds.x1 - prim->bounds.x0) + 0.5f)), float(floor((prim->bounds.y1 - prim->bounds.y0) + 0.5f)) };
+ float values[2] = { float(prim.m_quad_width), float(prim.m_quad_height) };
quad_dims_uniform->set(values, sizeof(float) * 2);
}
}
@@ -223,22 +280,8 @@ void bgfx_chain_entry::setup_screenindex_uniform(int32_t screen) const
}
}
-void bgfx_chain_entry::setup_auto_uniforms(render_primitive* prim, texture_manager& textures, uint16_t screen_count, uint16_t screen_width, uint16_t screen_height, float screen_scale_x, float screen_scale_y, float screen_offset_x, float screen_offset_y, uint32_t rotation_type, bool swap_xy, int32_t screen)
-{
- setup_screensize_uniforms(textures, screen_width, screen_height, screen);
- setup_screenscale_uniforms(screen_scale_x, screen_scale_y);
- setup_screenoffset_uniforms(screen_offset_x, screen_offset_y);
- setup_screencount_uniforms(screen_count);
- setup_sourcesize_uniform(prim);
- setup_targetsize_uniform(screen);
- setup_targetscale_uniform(screen);
- setup_rotationtype_uniform(rotation_type);
- setup_swapxy_uniform(swap_xy);
- setup_quaddims_uniform(prim);
- setup_screenindex_uniform(screen);
-}
-
-bool bgfx_chain_entry::setup_view(int view, uint16_t screen_width, uint16_t screen_height, int32_t screen) const
+bool bgfx_chain_entry::setup_view(texture_manager &textures, int view, uint16_t screen_width, uint16_t screen_height, int32_t screen,
+ uint16_t &out_view_width, uint16_t &out_view_height) const
{
bgfx::FrameBufferHandle handle = BGFX_INVALID_HANDLE;
uint16_t width = screen_width;
@@ -257,18 +300,23 @@ bool bgfx_chain_entry::setup_view(int view, uint16_t screen_width, uint16_t scre
bgfx::setViewFrameBuffer(view, handle);
bgfx::setViewRect(view, 0, 0, width, height);
+ out_view_width = width;
+ out_view_height = height;
const bgfx::Caps* caps = bgfx::getCaps();
+ std::string name = m_inputs[0]->texture() + std::to_string(screen);
+ const float right_ratio = float(textures.provider(name)->width()) / textures.provider(name)->rowpixels();
+
float projMat[16];
- bx::mtxOrtho(projMat, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f, 0.0f, caps->homogeneousDepth);
+ bx::mtxOrtho(projMat, 0.0f, right_ratio, 1.0f, 0.0f, 0.0f, 100.0f, 0.0f, caps->homogeneousDepth);
bgfx::setViewTransform(view, nullptr, projMat);
m_clear->bind(view);
return true;
}
-void bgfx_chain_entry::put_screen_buffer(render_primitive* prim, bgfx::TransientVertexBuffer* buffer) const
+void bgfx_chain_entry::put_screen_buffer(uint16_t screen_width, uint16_t screen_height, uint32_t screen_tint, bgfx::TransientVertexBuffer* buffer) const
{
if (6 == bgfx::getAvailTransientVertexBuffer(6, ScreenVertex::ms_decl))
{
@@ -279,7 +327,7 @@ void bgfx_chain_entry::put_screen_buffer(render_primitive* prim, bgfx::Transient
return;
}
- ScreenVertex* vertex = reinterpret_cast<ScreenVertex*>(buffer->data);
+ auto* vertex = reinterpret_cast<ScreenVertex*>(buffer->data);
float x[4] = { 0, 1, 0, 1 };
float y[4] = { 0, 0, 1, 1 };
@@ -296,42 +344,42 @@ void bgfx_chain_entry::put_screen_buffer(render_primitive* prim, bgfx::Transient
vertex[0].m_x = x[0];
vertex[0].m_y = y[0];
vertex[0].m_z = 0;
- vertex[0].m_rgba = 0xffffffff;
+ vertex[0].m_rgba = screen_tint;
vertex[0].m_u = u[0];
vertex[0].m_v = v[0];
vertex[1].m_x = x[1];
vertex[1].m_y = y[1];
vertex[1].m_z = 0;
- vertex[1].m_rgba = 0xffffffff;
+ vertex[1].m_rgba = screen_tint;
vertex[1].m_u = u[1];
vertex[1].m_v = v[1];
vertex[2].m_x = x[3];
vertex[2].m_y = y[3];
vertex[2].m_z = 0;
- vertex[2].m_rgba = 0xffffffff;
+ vertex[2].m_rgba = screen_tint;
vertex[2].m_u = u[3];
vertex[2].m_v = v[3];
vertex[3].m_x = x[3];
vertex[3].m_y = y[3];
vertex[3].m_z = 0;
- vertex[3].m_rgba = 0xffffffff;
+ vertex[3].m_rgba = screen_tint;
vertex[3].m_u = u[3];
vertex[3].m_v = v[3];
vertex[4].m_x = x[2];
vertex[4].m_y = y[2];
vertex[4].m_z = 0;
- vertex[4].m_rgba = 0xffffffff;
+ vertex[4].m_rgba = screen_tint;
vertex[4].m_u = u[2];
vertex[4].m_v = v[2];
vertex[5].m_x = x[0];
vertex[5].m_y = y[0];
vertex[5].m_z = 0;
- vertex[5].m_rgba = 0xffffffff;
+ vertex[5].m_rgba = screen_tint;
vertex[5].m_u = u[0];
vertex[5].m_v = v[0];
}
diff --git a/src/osd/modules/render/bgfx/chainentry.h b/src/osd/modules/render/bgfx/chainentry.h
index 64130c5c93e..a7504187879 100644
--- a/src/osd/modules/render/bgfx/chainentry.h
+++ b/src/osd/modules/render/bgfx/chainentry.h
@@ -11,8 +11,8 @@
#pragma once
-#ifndef __DRAWBGFX_CHAIN_ENTRY__
-#define __DRAWBGFX_CHAIN_ENTRY__
+#ifndef DRAWBGFX_CHAIN_ENTRY
+#define DRAWBGFX_CHAIN_ENTRY
#include <bgfx/bgfx.h>
@@ -21,8 +21,8 @@
#include "inputpair.h"
#include "targetmanager.h"
+#include "chainmanager.h"
-class render_primitive;
class bgfx_effect;
class bgfx_target;
class bgfx_entry_uniform;
@@ -34,10 +34,12 @@ class target_manager;
class bgfx_chain_entry
{
public:
- bgfx_chain_entry(std::string name, bgfx_effect* effect, clear_state* clear, std::vector<bgfx_suppressor*> suppressors, std::vector<bgfx_input_pair*> inputs, std::vector<bgfx_entry_uniform*> uniforms, target_manager& targets, std::string output);
+ bgfx_chain_entry(std::string name, bgfx_effect* effect, clear_state* clear, std::vector<bgfx_suppressor*> suppressors, std::vector<bgfx_input_pair*> inputs,
+ std::vector<bgfx_entry_uniform*> uniforms, target_manager& targets, std::string output, bool apply_tint);
~bgfx_chain_entry();
- void submit(int view, render_primitive* prim, texture_manager& textures, uint16_t screen_count, uint16_t screen_width, uint16_t screen_height, float screen_scale_x, float screen_scale_y, float screen_offset_x, float screen_offset_y, uint32_t rotation_type, bool swap_xy, uint64_t blend, int32_t screen);
+ void submit(int view, chain_manager::screen_prim &prim, texture_manager& textures, uint16_t screen_count, uint16_t screen_width, uint16_t screen_height,
+ float screen_scale_x, float screen_scale_y, float screen_offset_x, float screen_offset_y, uint32_t rotation_type, bool swap_xy, int32_t screen);
// Getters
std::string name() const { return m_name; }
@@ -45,21 +47,25 @@ public:
bool skip();
private:
- void setup_auto_uniforms(render_primitive* prim, texture_manager& textures, uint16_t screen_count, uint16_t screen_width, uint16_t screen_height, float screen_scale_x, float screen_scale_y, float screen_offset_x, float screen_offset_y, uint32_t rotation_type, bool swap_xy, int32_t screen);
+ void setup_auto_uniforms(chain_manager::screen_prim &prim, texture_manager& textures, uint16_t screen_count, uint16_t view_width, uint16_t view_height,
+ uint16_t screen_width, uint16_t screen_height, float screen_scale_x, float screen_scale_y, float screen_offset_x, float screen_offset_y,
+ uint32_t rotation_type, bool swap_xy, int32_t screen);
+ void setup_viewsize_uniforms(uint16_t view_width, uint16_t view_height);
void setup_screensize_uniforms(texture_manager& textures, uint16_t screen_width, uint16_t screen_height, int32_t screen);
void setup_screenscale_uniforms(float screen_scale_x, float screen_scale_y);
void setup_screenoffset_uniforms(float screen_offset_x, float screen_offset_y);
void setup_screencount_uniforms(uint16_t screen_count);
- void setup_sourcesize_uniform(render_primitive* prim) const;
+ void setup_sourcesize_uniform(chain_manager::screen_prim &prim) const;
void setup_targetsize_uniform(int32_t screen) const;
void setup_targetscale_uniform(int32_t screen) const;
void setup_rotationtype_uniform(uint32_t rotation_type) const;
void setup_swapxy_uniform(bool swap_xy) const;
- void setup_quaddims_uniform(render_primitive* prim) const;
+ void setup_quaddims_uniform(chain_manager::screen_prim &prim) const;
void setup_screenindex_uniform(int32_t screen) const;
- bool setup_view(int view, uint16_t screen_width, uint16_t screen_height, int32_t screen) const;
- void put_screen_buffer(render_primitive* prim, bgfx::TransientVertexBuffer* buffer) const;
+ bool setup_view(texture_manager& textures, int view, uint16_t screen_width, uint16_t screen_height, int32_t screen,
+ uint16_t &out_view_width, uint16_t &out_view_height) const;
+ void put_screen_buffer(uint16_t screen_width, uint16_t screen_height, uint32_t screen_tint, bgfx::TransientVertexBuffer* buffer) const;
std::string m_name;
bgfx_effect* m_effect;
@@ -69,6 +75,7 @@ private:
std::vector<bgfx_entry_uniform*> m_uniforms;
target_manager& m_targets;
std::string m_output;
+ bool m_apply_tint;
};
#endif // __DRAWBGFX_CHAIN_ENTRY__
diff --git a/src/osd/modules/render/bgfx/chainentryreader.cpp b/src/osd/modules/render/bgfx/chainentryreader.cpp
index bff221ec40c..ce58816e827 100644
--- a/src/osd/modules/render/bgfx/chainentryreader.cpp
+++ b/src/osd/modules/render/bgfx/chainentryreader.cpp
@@ -6,16 +6,15 @@
//
//============================================================
-#include <string>
+#include "chainentryreader.h"
-#include "emu.h"
+#include "emucore.h"
+#include "fileio.h"
#include "rendutil.h"
#include <modules/render/copyutil.h>
#include <modules/lib/osdobj_common.h>
-#include "chainentryreader.h"
-
#include "texturemanager.h"
#include "targetmanager.h"
#include "effectmanager.h"
@@ -30,15 +29,21 @@
#include "clear.h"
#include "clearreader.h"
-bgfx_chain_entry* chain_entry_reader::read_from_value(const Value& value, std::string prefix, chain_manager& chains, std::map<std::string, bgfx_slider*>& sliders, std::map<std::string, bgfx_parameter*>& params, uint32_t screen_index)
+bgfx_chain_entry* chain_entry_reader::read_from_value(
+ const Value &value,
+ const std::string &prefix,
+ chain_manager &chains,
+ std::map<std::string, bgfx_slider*> &sliders,
+ std::map<std::string, bgfx_parameter*> &params,
+ uint32_t screen_index)
{
if (!validate_parameters(value, prefix))
{
- printf("Failed validation\n");
+ osd_printf_error("Chain entry failed validation.\n");
return nullptr;
}
- bgfx_effect* effect = chains.effects().effect(value["effect"].GetString());
+ bgfx_effect* effect = chains.effects().get_or_load_effect(chains.options(), value["effect"].GetString());
if (effect == nullptr)
{
return nullptr;
@@ -53,18 +58,18 @@ bgfx_chain_entry* chain_entry_reader::read_from_value(const Value& value, std::s
for (uint32_t i = 0; i < input_array.Size(); i++)
{
const Value& input = input_array[i];
- if (!READER_CHECK(input.HasMember("sampler"), (prefix + "input[" + std::to_string(i) + ": Must have string value 'sampler' (what sampler are we binding to?)\n").c_str())) return nullptr;
- if (!READER_CHECK(input["sampler"].IsString(), (prefix + "input[" + std::to_string(i) + ": Value 'sampler' must be a string\n").c_str())) return nullptr;
+ if (!READER_CHECK(input.HasMember("sampler"), "%sinput[%u]: Must have string value 'sampler' (what sampler are we binding to?)\n", prefix, i)) return nullptr;
+ if (!READER_CHECK(input["sampler"].IsString(), "%sinput[%u]: Value 'sampler' must be a string\n", prefix, i)) return nullptr;
bool has_texture = input.HasMember("texture");
bool has_target = input.HasMember("target");
bool has_option = input.HasMember("option");
- if (!READER_CHECK(has_texture || has_target || has_option, (prefix + "input[" + std::to_string(i) + ": Must have string value 'target', 'texture' or 'option' (what source are we using?)\n").c_str())) return nullptr;
- if (!READER_CHECK(!has_texture || input["texture"].IsString(), (prefix + "input[" + std::to_string(i) + ": Value 'texture' must be a string\n").c_str())) return nullptr;
- if (!READER_CHECK(!has_target || input["target"].IsString(), (prefix + "input[" + std::to_string(i) + ": Value 'target' must be a string\n").c_str())) return nullptr;
- if (!READER_CHECK(!has_option || input["option"].IsString(), (prefix + "input[" + std::to_string(i) + ": Value 'option' must be a string\n").c_str())) return nullptr;
- if (!READER_CHECK(has_target || !input.HasMember("bilinear") || input["bilinear"].IsBool(), (prefix + "input[" + std::to_string(i) + ": Value 'bilinear' must be a boolean\n").c_str())) return nullptr;
- if (!READER_CHECK(has_target || !input.HasMember("clamp") || input["clamp"].IsBool(), (prefix + "input[" + std::to_string(i) + ": Value 'clamp' must be a boolean\n").c_str())) return nullptr;
- if (!READER_CHECK(has_texture || has_option || !input.HasMember("selection") || input["selection"].IsString(), (prefix + "input[" + std::to_string(i) + ": Value 'selection' must be a string\n").c_str())) return nullptr;
+ if (!READER_CHECK(has_texture || has_target || has_option, "%sinput[%u]: Must have string value 'target', 'texture' or 'option' (what source are we using?)\n", prefix, i)) return nullptr;
+ if (!READER_CHECK(!has_texture || input["texture"].IsString(), "%sinput[%u]: Value 'texture' must be a string\n", prefix, i)) return nullptr;
+ if (!READER_CHECK(!has_target || input["target"].IsString(), "%sinput[%u]: Value 'target' must be a string\n", prefix, i)) return nullptr;
+ if (!READER_CHECK(!has_option || input["option"].IsString(), "%sinput[%u]: Value 'option' must be a string\n", prefix, i)) return nullptr;
+ if (!READER_CHECK(has_target || !input.HasMember("bilinear") || input["bilinear"].IsBool(), "%sinput[%u]: Value 'bilinear' must be a boolean\n", prefix, i)) return nullptr;
+ if (!READER_CHECK(has_target || !input.HasMember("clamp") || input["clamp"].IsBool(), "%sinput[%u]: Value 'clamp' must be a boolean\n", prefix, i)) return nullptr;
+ if (!READER_CHECK(has_texture || has_option || !input.HasMember("selection") || input["selection"].IsString(), "%sinput[%u]: Value 'selection' must be a string\n", prefix, i)) return nullptr;
bool bilinear = get_bool(input, "bilinear", true);
bool clamp = get_bool(input, "clamp", false);
std::string selection = get_string(input, "selection", "");
@@ -84,7 +89,7 @@ bgfx_chain_entry* chain_entry_reader::read_from_value(const Value& value, std::s
texture_name = chains.options().value(option.c_str());
}
- if (texture_name != "" && texture_name != "screen")
+ if (texture_name != "" && texture_name != "screen" && texture_name != "palette")
{
if (selection == "")
{
@@ -109,59 +114,48 @@ bgfx_chain_entry* chain_entry_reader::read_from_value(const Value& value, std::s
}
// get directory of file
- std::string directory_path = std::string(chains.options().art_path());
- std::string file_directory = "";
const size_t last_slash = texture_name.rfind('/');
- if (last_slash != std::string::npos)
- {
- file_directory = texture_name.substr(0, last_slash);
-
- directory_path += "/" + file_directory;
- }
-
- osd::directory::ptr directory = osd::directory::open(directory_path);
- if (directory)
+ const std::string file_directory = last_slash != std::string::npos ? texture_name.substr(0, last_slash) : std::string();
+ file_enumerator directory_path(chains.options().art_path());
+ while (const osd::directory::entry *entry = directory_path.next(file_directory.empty() ? nullptr : file_directory.c_str()))
{
- for (const osd::directory::entry *entry = directory->read(); entry != nullptr; entry = directory->read())
+ if (entry->type == osd::directory::entry::entry_type::FILE)
{
- if (entry->type == osd::directory::entry::entry_type::FILE)
+ std::string file(entry->name);
+ std::string extension(".png");
+
+ // split into file name and extension
+ std::string file_name;
+ std::string file_extension;
+ const size_t last_dot = file.rfind('.');
+ if (last_dot != std::string::npos)
{
- std::string file(entry->name);
- std::string extension(".png");
-
- // split into file name and extension
- std::string file_name;
- std::string file_extension;
- const size_t last_dot = file.rfind('.');
- if (last_dot != std::string::npos)
- {
- file_name = file.substr(0, last_dot);
- file_extension = file.substr(last_dot, file.length() - last_dot);
- }
+ file_name = file.substr(0, last_dot);
+ file_extension = file.substr(last_dot, file.length() - last_dot);
+ }
- std::string file_path;
- if (file_directory == "")
- {
- file_path = file;
- }
- else
- {
- file_path = file_directory + "/" + file;
- }
+ std::string file_path;
+ if (file_directory == "")
+ {
+ file_path = file;
+ }
+ else
+ {
+ file_path = file_directory + PATH_SEPARATOR + file;
+ }
- // check for .png extension
- if (file_extension == extension)
+ // check for .png extension
+ if (file_extension == extension && std::find(texture_names.begin(), texture_names.end(), file_path) == texture_names.end())
+ {
+ // create textures for all files containd in the path of the specified file name
+ uint32_t flags = bilinear ? 0u : (BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_MIP_POINT);
+ flags |= clamp ? (BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP | BGFX_SAMPLER_W_CLAMP) : 0u;
+ bgfx_texture* texture = chains.textures().create_png_texture(chains.options().art_path(), file_path, file_path, flags, screen_index);
+ if (texture == nullptr)
{
- // create textures for all files containd in the path of the specified file name
- uint32_t flags = bilinear ? 0u : (BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_MIP_POINT);
- flags |= clamp ? (BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP | BGFX_SAMPLER_W_CLAMP) : 0u;
- bgfx_texture* texture = chains.textures().create_png_texture(chains.options().art_path(), file_path, file_path, flags, screen_index);
- if (texture == nullptr)
- {
- return nullptr;
- }
- texture_names.push_back(file_path);
+ return nullptr;
}
+ texture_names.push_back(file_path);
}
}
}
@@ -178,11 +172,15 @@ bgfx_chain_entry* chain_entry_reader::read_from_value(const Value& value, std::s
}
std::string sampler = input["sampler"].GetString();
- bgfx_input_pair* input_pair = new bgfx_input_pair(i, sampler, texture_name, texture_names, selection, chains, screen_index);
+ auto* input_pair = new bgfx_input_pair(i, sampler, texture_name, texture_names, selection, chains, screen_index);
inputs.push_back(input_pair);
}
}
+ // Parse whether or not to apply screen tint in this pass
+ bool applytint = get_bool(value, "applytint", false);
+
+ // Parse uniforms
std::vector<bgfx_entry_uniform*> uniforms;
if (value.HasMember("uniforms"))
{
@@ -228,19 +226,20 @@ bgfx_chain_entry* chain_entry_reader::read_from_value(const Value& value, std::s
}
std::string output = value["output"].GetString();
- return new bgfx_chain_entry(name, effect, clear, suppressors, inputs, uniforms, chains.targets(), output);
+ return new bgfx_chain_entry(name, effect, clear, suppressors, inputs, uniforms, chains.targets(), output, applytint);
}
-bool chain_entry_reader::validate_parameters(const Value& value, std::string prefix)
+bool chain_entry_reader::validate_parameters(const Value& value, const std::string &prefix)
{
- if (!READER_CHECK(value.HasMember("effect"), (prefix + "Must have string value 'effect' (what effect does this entry use?)\n").c_str())) return false;
- if (!READER_CHECK(value["effect"].IsString(), (prefix + "Value 'effect' must be a string\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("name"), (prefix + "Must have string value 'effect' (what effect does this entry use?)\n").c_str())) return false;
- if (!READER_CHECK(value["name"].IsString(), (prefix + "Value 'name' must be a string\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("output"), (prefix + "Must have string value 'offset' (what target are we rendering to?)\n").c_str())) return false;
- if (!READER_CHECK(value["output"].IsString(), (prefix + "Value 'output' must be a string\n").c_str())) return false;
- if (!READER_CHECK(!value.HasMember("input") || value["input"].IsArray(), (prefix + "Value 'input' must be an array\n").c_str())) return false;
- if (!READER_CHECK(!value.HasMember("uniforms") || value["uniforms"].IsArray(), (prefix + "Value 'uniforms' must be an array\n").c_str())) return false;
- if (!READER_CHECK(!value.HasMember("disablewhen") || value["disablewhen"].IsArray(), (prefix + "Value 'disablewhen' must be an array\n").c_str())) return false;
+ if (!READER_CHECK(value.HasMember("effect"), "%sMust have string value 'effect' (what effect does this entry use?)\n", prefix)) return false;
+ if (!READER_CHECK(value["effect"].IsString(), "%sValue 'effect' must be a string\n", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("name"), "%sMust have string value 'effect' (what effect does this entry use?)\n", prefix)) return false;
+ if (!READER_CHECK(value["name"].IsString(), "%sValue 'name' must be a string\n", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("output"), "%sMust have string value 'offset' (what target are we rendering to?)\n", prefix)) return false;
+ if (!READER_CHECK(value["output"].IsString(), "%sValue 'output' must be a string\n", prefix)) return false;
+ if (!READER_CHECK(!value.HasMember("input") || value["input"].IsArray(), "%sValue 'input' must be an array\n", prefix)) return false;
+ if (!READER_CHECK(!value.HasMember("uniforms") || value["uniforms"].IsArray(), "%sValue 'uniforms' must be an array\n", prefix)) return false;
+ if (!READER_CHECK(!value.HasMember("disablewhen") || value["disablewhen"].IsArray(), "%sValue 'disablewhen' must be an array\n", prefix)) return false;
+ if (!READER_CHECK(!value.HasMember("applytint") || value["applytint"].IsBool(), "%sValue 'applytint' must be a bool\n", prefix)) return false;
return true;
}
diff --git a/src/osd/modules/render/bgfx/chainentryreader.h b/src/osd/modules/render/bgfx/chainentryreader.h
index 0f604e9a71f..583e972732c 100644
--- a/src/osd/modules/render/bgfx/chainentryreader.h
+++ b/src/osd/modules/render/bgfx/chainentryreader.h
@@ -5,15 +5,15 @@
// chainentryreader.h - BGFX chain entry JSON reader
//
//============================================================
+#ifndef MAME_RENDER_BGFX_CHAINENTRYREADER_H
+#define MAME_RENDER_BGFX_CHAINENTRYREADER_H
#pragma once
-#ifndef __DRAWBGFX_CHAIN_ENTRY_READER__
-#define __DRAWBGFX_CHAIN_ENTRY_READER__
+#include "statereader.h"
#include <map>
-#include "statereader.h"
class bgfx_chain_entry;
class bgfx_slider;
@@ -23,10 +23,10 @@ class chain_manager;
class chain_entry_reader : public state_reader
{
public:
- static bgfx_chain_entry* read_from_value(const Value& value, std::string prefix, chain_manager& chains, std::map<std::string, bgfx_slider*>& sliders, std::map<std::string, bgfx_parameter*>& params, uint32_t screen_index);
+ static bgfx_chain_entry* read_from_value(const Value& value, const std::string &prefix, chain_manager& chains, std::map<std::string, bgfx_slider*>& sliders, std::map<std::string, bgfx_parameter*>& params, uint32_t screen_index);
private:
- static bool validate_parameters(const Value& value, std::string prefix);
+ static bool validate_parameters(const Value& value, const std::string &prefix);
};
-#endif // __DRAWBGFX_CHAIN_ENTRY_READER__
+#endif // MAME_RENDER_BGFX_CHAINENTRYREADER_H
diff --git a/src/osd/modules/render/bgfx/chainmanager.cpp b/src/osd/modules/render/bgfx/chainmanager.cpp
index 62df9be9613..a15f2f1e584 100644
--- a/src/osd/modules/render/bgfx/chainmanager.cpp
+++ b/src/osd/modules/render/bgfx/chainmanager.cpp
@@ -9,13 +9,16 @@
//
//============================================================
+#include "chainmanager.h"
+
#include <bx/readerwriter.h>
#include <bx/file.h>
-#include "emu.h"
+#include "emucore.h"
+#include "render.h"
#include "../frontend/mame/ui/slider.h"
-#include "osdcore.h"
+#include "modules/lib/osdobj_common.h"
#include "modules/osdwindow.h"
#include <rapidjson/document.h>
@@ -23,32 +26,67 @@
#include "bgfxutil.h"
-#include "chainmanager.h"
-#include "chainreader.h"
#include "chain.h"
-
-#include "texture.h"
-#include "target.h"
+#include "chainreader.h"
#include "slider.h"
+#include "target.h"
+#include "texture.h"
#include "sliderdirtynotifier.h"
+#include "util/path.h"
+#include "util/unicode.h"
+#include "util/xmlfile.h"
+
+#include "osdcore.h"
+#include "osdfile.h"
+
+#include <algorithm>
+#include <locale>
+
+
using namespace rapidjson;
-const uint32_t chain_manager::CHAIN_NONE = 0;
+chain_manager::screen_prim::screen_prim(render_primitive *prim)
+{
+ m_prim = prim;
+ m_screen_width = uint16_t(floorf(prim->get_full_quad_width() + 0.5f));
+ m_screen_height = uint16_t(floorf(prim->get_full_quad_height() + 0.5f));
+ m_quad_width = uint16_t(floorf(prim->get_quad_width() + 0.5f));
+ m_quad_height = uint16_t(floorf(prim->get_quad_height() + 0.5f));
+ m_tex_width = prim->texture.width;
+ m_tex_height = prim->texture.height;
+ m_rowpixels = prim->texture.rowpixels;
+ m_palette_length = prim->texture.palette_length;
+ m_flags = prim->flags;
+}
-chain_manager::chain_manager(running_machine& machine, osd_options& options, texture_manager& textures, target_manager& targets, effect_manager& effects, uint32_t window_index, slider_dirty_notifier& slider_notifier)
+chain_manager::chain_manager(
+ running_machine& machine,
+ const osd_options& options,
+ texture_manager& textures,
+ target_manager& targets,
+ effect_manager& effects,
+ uint32_t window_index,
+ slider_dirty_notifier& slider_notifier,
+ uint16_t user_prescale,
+ uint16_t max_prescale_size)
: m_machine(machine)
, m_options(options)
, m_textures(textures)
, m_targets(targets)
, m_effects(effects)
, m_window_index(window_index)
+ , m_user_prescale(user_prescale)
+ , m_max_prescale_size(max_prescale_size)
, m_slider_notifier(slider_notifier)
, m_screen_count(0)
+ , m_default_chain_index(-1)
{
+ m_converters.clear();
refresh_available_chains();
parse_chain_selections(options.bgfx_screen_chains());
+ init_texture_converters();
}
chain_manager::~chain_manager()
@@ -56,14 +94,65 @@ chain_manager::~chain_manager()
destroy_chains();
}
+void chain_manager::init_texture_converters()
+{
+ m_converters.push_back(nullptr);
+ m_converters.push_back(m_effects.get_or_load_effect(m_options, "misc/texconv_palette16"));
+ m_converters.push_back(m_effects.get_or_load_effect(m_options, "misc/texconv_rgb32"));
+ m_converters.push_back(nullptr);
+ m_converters.push_back(m_effects.get_or_load_effect(m_options, "misc/texconv_yuy16"));
+ m_adjuster = m_effects.get_or_load_effect(m_options, "misc/bcg_adjust");
+}
+
+void chain_manager::get_default_chain_info(std::string &out_chain_name, int32_t &out_chain_index)
+{
+ if (m_default_chain_index == -1)
+ {
+ out_chain_index = CHAIN_NONE;
+ out_chain_name = "";
+ return;
+ }
+
+ out_chain_index = m_default_chain_index;
+ out_chain_name = "default";
+ return;
+}
+
void chain_manager::refresh_available_chains()
{
m_available_chains.clear();
- m_available_chains.push_back(chain_desc("none", ""));
-
- std::string chains_path;
- osd_subst_env(chains_path, util::string_format("%s" PATH_SEPARATOR "chains", m_options.bgfx_path()));
- find_available_chains(chains_path, "");
+ m_available_chains.emplace_back("none", "");
+
+ find_available_chains(util::path_concat(m_options.bgfx_path(), "chains"), "");
+ std::collate<wchar_t> const &coll = std::use_facet<std::collate<wchar_t> >(std::locale());
+ std::sort(
+ m_available_chains.begin(),
+ m_available_chains.end(),
+ [&coll] (chain_desc const &x, chain_desc const &y) -> bool
+ {
+ if (x.m_name == "none")
+ return y.m_name != "none";
+ else if (y.m_name == "none")
+ return false;
+ else if (x.m_name == "default")
+ return y.m_name != "default";
+ else if (y.m_name == "default")
+ return false;
+ std::wstring const xstr = wstring_from_utf8(x.m_name);
+ std::wstring const ystr = wstring_from_utf8(y.m_name);
+ return coll.compare(xstr.data(), xstr.data() + xstr.size(), ystr.data(), ystr.data() + ystr.size()) < 0;
+ });
+
+ if (m_default_chain_index == -1)
+ {
+ for (size_t i = 0; i < m_available_chains.size(); i++)
+ {
+ if (m_available_chains[i].m_name == "default")
+ {
+ m_default_chain_index = int32_t(i);
+ }
+ }
+ }
destroy_unloaded_chains();
}
@@ -73,7 +162,7 @@ void chain_manager::destroy_unloaded_chains()
// O(shaders*available_chains), but we don't care because asset reloading happens rarely
for (int i = 0; i < m_chain_names.size(); i++)
{
- std::string name = m_chain_names[i];
+ const std::string &name = m_chain_names[i];
if (name.length() > 0)
{
for (chain_desc desc : m_available_chains)
@@ -82,8 +171,7 @@ void chain_manager::destroy_unloaded_chains()
{
delete m_screen_chains[i];
m_screen_chains[i] = nullptr;
- m_chain_names[i] = "";
- m_current_chain[i] = CHAIN_NONE;
+ get_default_chain_info(m_chain_names[i], m_current_chain[i]);
break;
}
}
@@ -91,107 +179,109 @@ void chain_manager::destroy_unloaded_chains()
}
}
-void chain_manager::find_available_chains(std::string root, std::string path)
+void chain_manager::find_available_chains(std::string_view root, std::string_view path)
{
- osd::directory::ptr directory = osd::directory::open(root + path);
- if (directory != nullptr)
+ osd::directory::ptr directory = osd::directory::open(path.empty() ? std::string(root) : util::path_concat(root, path));
+ if (directory)
{
- for (const osd::directory::entry *entry = directory->read(); entry != nullptr; entry = directory->read())
+ for (const osd::directory::entry *entry = directory->read(); entry; entry = directory->read())
{
if (entry->type == osd::directory::entry::entry_type::FILE)
{
- std::string name(entry->name);
- std::string extension(".json");
+ const std::string_view name(entry->name);
+ const std::string_view extension(".json");
// Does the name has at least one character in addition to ".json"?
if (name.length() > extension.length())
{
size_t start = name.length() - extension.length();
- std::string test_segment = name.substr(start, extension.length());
+ const std::string_view test_segment = name.substr(start, extension.length());
// Does it end in .json?
if (test_segment == extension)
{
- m_available_chains.push_back(chain_desc(name.substr(0, start), path));
+ m_available_chains.emplace_back(std::string(name.substr(0, start)), std::string(path));
}
}
}
else if (entry->type == osd::directory::entry::entry_type::DIR)
{
- std::string name = entry->name;
- if (!(name == "." || name == ".."))
+ const std::string_view name = entry->name;
+ if ((name != ".") && (name != ".."))
{
- std::string appended_path = path + "/" + name;
- if (path.length() == 0)
- {
- appended_path = name;
- }
- find_available_chains(root, path + "/" + name);
+ if (path.empty())
+ find_available_chains(root, name);
+ else
+ find_available_chains(root, util::path_concat(path, name));
}
}
}
}
}
-bgfx_chain* chain_manager::load_chain(std::string name, uint32_t screen_index)
+std::unique_ptr<bgfx_chain> chain_manager::load_chain(std::string name, uint32_t screen_index)
{
if (name.length() < 5 || (name.compare(name.length() - 5, 5, ".json") != 0))
{
- name = name + ".json";
+ name += ".json";
}
- std::string path;
- osd_subst_env(path, util::string_format("%s" PATH_SEPARATOR "chains" PATH_SEPARATOR, m_options.bgfx_path()));
- path += name;
+ const std::string path = util::path_concat(m_options.bgfx_path(), "chains", name);
bx::FileReader reader;
if (!bx::open(&reader, path.c_str()))
{
- printf("Unable to open chain file %s, falling back to no post processing\n", path.c_str());
+ osd_printf_warning("Unable to open chain file %s, falling back to no post processing\n", path);
return nullptr;
}
- int32_t size(bx::getSize(&reader));
+ const int32_t size(bx::getSize(&reader));
+
+ bx::ErrorAssert err;
+ std::unique_ptr<char []> data(new (std::nothrow) char [size + 1]);
+ if (!data)
+ {
+ osd_printf_error("Out of memory reading chain file %s\n", path);
+ bx::close(&reader);
+ return nullptr;
+ }
- char* data = new char[size + 1];
- bx::read(&reader, reinterpret_cast<void*>(data), size);
+ bx::read(&reader, reinterpret_cast<void*>(data.get()), size, &err);
bx::close(&reader);
data[size] = 0;
Document document;
- document.Parse<kParseCommentsFlag>(data);
-
- delete [] data;
+ document.Parse<kParseCommentsFlag>(data.get());
+ data.reset();
if (document.HasParseError())
{
std::string error(GetParseError_En(document.GetParseError()));
- printf("Unable to parse chain %s. Errors returned:\n", path.c_str());
- printf("%s\n", error.c_str());
+ osd_printf_warning("Unable to parse chain %s. Errors returned:\n%s\n", path, error);
return nullptr;
}
- bgfx_chain* chain = chain_reader::read_from_value(document, name + ": ", *this, screen_index);
+ std::unique_ptr<bgfx_chain> chain = chain_reader::read_from_value(document, name + ": ", *this, screen_index, m_user_prescale, m_max_prescale_size);
- if (chain == nullptr)
+ if (!chain)
{
- printf("Unable to load chain %s, falling back to no post processing\n", path.c_str());
+ osd_printf_warning("Unable to load chain %s, falling back to no post processing\n", path);
return nullptr;
}
return chain;
}
-void chain_manager::parse_chain_selections(std::string chain_str)
+void chain_manager::parse_chain_selections(std::string_view chain_str)
{
- std::vector<std::string> chain_names = split_option_string(chain_str);
+ std::vector<std::string_view> chain_names = split_option_string(chain_str);
if (chain_names.empty())
chain_names.push_back("default");
- while (m_current_chain.size() != chain_names.size())
+ while (m_current_chain.size() < chain_names.size())
{
- m_screen_chains.push_back(nullptr);
- m_chain_names.push_back("");
+ m_screen_chains.emplace_back(nullptr);
+ m_chain_names.emplace_back();
m_current_chain.push_back(CHAIN_NONE);
}
@@ -201,9 +291,7 @@ void chain_manager::parse_chain_selections(std::string chain_str)
for (chain_index = 0; chain_index < m_available_chains.size(); chain_index++)
{
if (m_available_chains[chain_index].m_name == chain_names[index])
- {
break;
- }
}
if (chain_index < m_available_chains.size())
@@ -219,24 +307,35 @@ void chain_manager::parse_chain_selections(std::string chain_str)
}
}
-std::vector<std::string> chain_manager::split_option_string(std::string chain_str) const
+std::vector<std::string_view> chain_manager::split_option_string(std::string_view chain_str) const
{
- std::vector<std::string> chain_names;
+ std::vector<std::string_view> chain_names;
- uint32_t length = chain_str.length();
+ const uint32_t length = chain_str.length();
uint32_t win = 0;
uint32_t last_start = 0;
- for (uint32_t i = 0; i < length + 1; i++)
+ for (uint32_t i = 0; i <= length; i++)
{
- if (i == length || chain_str[i] == ',' || chain_str[i] == ':')
+ if (i == length || (chain_str[i] == ',') || (chain_str[i] == ':'))
{
- if (win == m_window_index)
+ if ((win == 0) || (win == m_window_index))
{
- chain_names.push_back(chain_str.substr(last_start, i - last_start));
+ // treat an empty string as equivalent to "default"
+ if (i > last_start)
+ chain_names.push_back(chain_str.substr(last_start, i - last_start));
+ else
+ chain_names.push_back("default");
}
+
last_start = i + 1;
- if (chain_str[i] == ':')
+ if ((i < length) && (chain_str[i] == ':'))
{
+ // no point walking the rest of the string if this was our window
+ if (win == m_window_index)
+ break;
+
+ // don't use first for all if more than one window is specified
+ chain_names.clear();
win++;
}
}
@@ -253,7 +352,7 @@ void chain_manager::load_chains()
{
chain_desc& desc = m_available_chains[m_current_chain[chain]];
m_chain_names[chain] = desc.m_name;
- m_screen_chains[chain] = load_chain(desc.m_path + "/" + desc.m_name, uint32_t(chain));
+ m_screen_chains[chain] = load_chain(util::path_concat(desc.m_path, desc.m_name), uint32_t(chain)).release();
}
}
}
@@ -288,19 +387,9 @@ bgfx_chain* chain_manager::screen_chain(uint32_t screen)
}
}
-void chain_manager::process_screen_quad(uint32_t view, uint32_t screen, render_primitive* prim, osd_window &window)
+void chain_manager::process_screen_quad(uint32_t view, uint32_t screen, screen_prim &prim, osd_window& window)
{
- uint16_t tex_width(prim->texture.width);
- uint16_t tex_height(prim->texture.height);
-
- const bgfx::Memory* mem = bgfx_util::mame_texture_data_to_bgfx_texture_data(prim->flags & PRIMFLAG_TEXFORMAT_MASK,
- tex_width, tex_height, prim->texture.rowpixels, prim->texture.palette, prim->texture.base);
-
- std::string full_name = "screen" + std::to_string(screen);
- bgfx_texture *texture = new bgfx_texture(full_name, bgfx::TextureFormat::RGBA8, tex_width, tex_height, mem, BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP | BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_MIP_POINT);
- m_textures.add_provider(full_name, texture);
-
- const bool any_targets_rebuilt = m_targets.update_target_sizes(screen, tex_width, tex_height, TARGET_STYLE_GUEST);
+ const bool any_targets_rebuilt = m_targets.update_target_sizes(screen, prim.m_tex_width, prim.m_tex_height, TARGET_STYLE_GUEST, m_user_prescale, m_max_prescale_size);
if (any_targets_rebuilt)
{
for (bgfx_chain* chain : m_screen_chains)
@@ -313,24 +402,26 @@ void chain_manager::process_screen_quad(uint32_t view, uint32_t screen, render_p
}
bgfx_chain* chain = screen_chain(screen);
- chain->process(prim, view, screen, m_textures, window, bgfx_util::get_blend_state(PRIMFLAG_GET_BLENDMODE(prim->flags)));
+ chain->process(prim, view, screen, m_textures, window);
view += chain->applicable_passes();
-
- m_textures.add_provider(full_name, nullptr);
- delete texture;
}
-std::vector<render_primitive*> chain_manager::count_screens(render_primitive* prim)
+uint32_t chain_manager::count_screens(render_primitive* prim)
{
- std::vector<render_primitive*> screens;
-
- int screen_count = 0;
+ uint32_t screen_count = 0;
while (prim != nullptr)
{
if (PRIMFLAG_GET_SCREENTEX(prim->flags))
{
+ if (screen_count < m_screen_prims.size())
+ {
+ m_screen_prims[screen_count] = prim;
+ }
+ else
+ {
+ m_screen_prims.push_back(prim);
+ }
screen_count++;
- screens.push_back(prim);
}
prim = prim->next();
}
@@ -338,10 +429,15 @@ std::vector<render_primitive*> chain_manager::count_screens(render_primitive* pr
if (screen_count > 0)
{
update_screen_count(screen_count);
- m_targets.update_screen_count(screen_count);
+ m_targets.update_screen_count(screen_count, m_user_prescale, m_max_prescale_size);
}
- return screens;
+ if (screen_count < m_screen_prims.size())
+ {
+ m_screen_prims.resize(screen_count);
+ }
+
+ return screen_count;
}
void chain_manager::update_screen_count(uint32_t screen_count)
@@ -355,8 +451,12 @@ void chain_manager::update_screen_count(uint32_t screen_count)
while (m_screen_chains.size() < m_screen_count)
{
m_screen_chains.push_back(nullptr);
- m_chain_names.push_back("");
- m_current_chain.push_back(CHAIN_NONE);
+
+ int32_t chain_index = CHAIN_NONE;
+ std::string chain_name;
+ get_default_chain_info(chain_name, chain_index);
+ m_chain_names.emplace_back(std::move(chain_name));
+ m_current_chain.push_back(chain_index);
}
// Ensure we have a screen chain selection slider per screen
@@ -369,11 +469,20 @@ void chain_manager::update_screen_count(uint32_t screen_count)
}
}
-int32_t chain_manager::slider_changed(running_machine &machine, void *arg, int id, std::string *str, int32_t newval)
+void chain_manager::set_current_chain(uint32_t screen, int32_t chain_index)
+{
+ if (chain_index < m_available_chains.size() && screen < m_current_chain.size() && screen < m_chain_names.size())
+ {
+ m_current_chain[screen] = chain_index;
+ m_chain_names[screen] = m_available_chains[chain_index].m_name;
+ }
+}
+
+int32_t chain_manager::slider_changed(int id, std::string *str, int32_t newval)
{
if (newval != SLIDER_NOCHANGE)
{
- m_current_chain[id] = newval;
+ set_current_chain(id, newval);
std::vector<std::vector<float>> settings = slider_settings();
reload_chains();
@@ -384,7 +493,7 @@ int32_t chain_manager::slider_changed(running_machine &machine, void *arg, int i
if (str != nullptr)
{
- *str = string_format("%s", m_available_chains[m_current_chain[id]].m_name.c_str());
+ *str = m_available_chains[m_current_chain[id]].m_name;
}
return m_current_chain[id];
@@ -397,42 +506,151 @@ void chain_manager::create_selection_slider(uint32_t screen_index)
return;
}
- std::unique_ptr<slider_state> state = make_unique_clear<slider_state>();
-
- state->minval = 0;
- state->defval = m_current_chain[screen_index];
- state->maxval = m_available_chains.size() - 1;
- state->incval = 1;
+ int32_t minval = 0;
+ int32_t defval = m_current_chain[screen_index];
+ int32_t maxval = m_available_chains.size() - 1;
+ int32_t incval = 1;
using namespace std::placeholders;
- state->update = std::bind(&chain_manager::slider_changed, this, _1, _2, _3, _4, _5);
- state->arg = this;
- state->id = screen_index;
- state->description = "Window " + std::to_string(m_window_index) + ", Screen " + std::to_string(screen_index) + " Effect:";
-
- ui::menu_item item;
- item.text = state->description;
- item.subtext = "";
- item.flags = 0;
- item.ref = state.get();
- item.type = ui::menu_item_type::SLIDER;
- m_selection_sliders.push_back(item);
- m_core_sliders.push_back(std::move(state));
+ auto state = std::make_unique<slider_state>(
+ util::string_format("Window %1$u, Screen %2$u Effect", m_window_index, screen_index),
+ minval, defval, maxval, incval,
+ std::bind(&chain_manager::slider_changed, this, screen_index, _1, _2));
+
+ ui::menu_item item(ui::menu_item_type::SLIDER, state.get());
+ item.set_text(state->description);
+ m_selection_sliders.emplace_back(item);
+ m_core_sliders.emplace_back(std::move(state));
}
-uint32_t chain_manager::handle_screen_chains(uint32_t view, render_primitive *starting_prim, osd_window& window)
+uint32_t chain_manager::update_screen_textures(uint32_t view, render_primitive *starting_prim, osd_window& window)
{
- std::vector<render_primitive*> screens = count_screens(starting_prim);
+ if (!count_screens(starting_prim))
+ return 0;
- if (screens.size() == 0)
+ for (int screen = 0; screen < m_screen_prims.size(); screen++)
{
- return 0;
+ screen_prim &prim = m_screen_prims[screen];
+ uint16_t tex_width(prim.m_tex_width);
+ uint16_t tex_height(prim.m_tex_height);
+
+ bgfx_texture* texture = screen < m_screen_textures.size() ? m_screen_textures[screen] : nullptr;
+ bgfx_texture* palette = screen < m_screen_palettes.size() ? m_screen_palettes[screen] : nullptr;
+
+ const uint32_t src_format = (prim.m_flags & PRIMFLAG_TEXFORMAT_MASK) >> PRIMFLAG_TEXFORMAT_SHIFT;
+ const bool needs_conversion = m_converters[src_format] != nullptr;
+ const bool needs_adjust = prim.m_prim->texture.palette != nullptr && src_format != TEXFORMAT_PALETTE16;
+ const std::string screen_index = std::to_string(screen);
+ const std::string source_name = "source" + screen_index;
+ const std::string screen_name = "screen" + screen_index;
+ const std::string palette_name = "palette" + screen_index;
+ const std::string &full_name = (needs_conversion || needs_adjust) ? source_name : screen_name;
+ if (texture && (texture->width() != tex_width || texture->height() != tex_height))
+ {
+ m_textures.remove_provider(full_name);
+ m_textures.remove_provider(palette_name);
+ texture = nullptr;
+ palette = nullptr;
+ }
+
+ bgfx::TextureFormat::Enum dst_format = bgfx::TextureFormat::BGRA8;
+ uint16_t pitch = prim.m_rowpixels;
+ 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, prim.m_flags & PRIMFLAG_TEXFORMAT_MASK,
+ prim.m_rowpixels, prim.m_prim->texture.width_margin, tex_height, prim.m_prim->texture.palette, prim.m_prim->texture.base, pitch, width_div_factor, width_mul_factor);
+
+ if (!texture)
+ {
+ uint32_t flags = BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_MIP_POINT;
+ if (!PRIMFLAG_GET_TEXWRAP(prim.m_flags))
+ flags |= BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP;
+ auto newtex = std::make_unique<bgfx_texture>(full_name, dst_format, tex_width, prim.m_prim->texture.width_margin, tex_height, mem, flags, pitch, prim.m_rowpixels, width_div_factor, width_mul_factor);
+ texture = newtex.get();
+ m_textures.add_provider(full_name, std::move(newtex));
+
+ if (prim.m_prim->texture.palette)
+ {
+ uint16_t palette_width = uint16_t(std::min(prim.m_palette_length, 256U));
+ uint16_t palette_height = uint16_t(std::max((prim.m_palette_length + 255) / 256, 1U));
+ m_palette_temp.resize(palette_width * palette_height * 4);
+ memcpy(&m_palette_temp[0], prim.m_prim->texture.palette, prim.m_palette_length * 4);
+ const bgfx::Memory *palmem = bgfx::copy(&m_palette_temp[0], palette_width * palette_height * 4);
+ auto newpal = std::make_unique<bgfx_texture>(palette_name, bgfx::TextureFormat::BGRA8, palette_width, 0, palette_height, palmem, BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP | BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_MIP_POINT, palette_width * 4);
+ palette = newpal.get();
+ m_textures.add_provider(palette_name, std::move(newpal));
+ }
+
+ while (screen >= m_screen_textures.size())
+ {
+ m_screen_textures.emplace_back(nullptr);
+ }
+ m_screen_textures[screen] = texture;
+
+ while (screen >= m_screen_palettes.size())
+ {
+ m_screen_palettes.emplace_back(nullptr);
+ }
+ if (palette)
+ {
+ m_screen_palettes[screen] = palette;
+ }
+ }
+ else
+ {
+ texture->update(mem, pitch, prim.m_prim->texture.width_margin);
+
+ if (prim.m_prim->texture.palette)
+ {
+ uint16_t palette_width = uint16_t(std::min(prim.m_palette_length, 256U));
+ uint16_t palette_height = uint16_t(std::max((prim.m_palette_length + 255) / 256, 1U));
+ const uint32_t palette_size = palette_width * palette_height * 4;
+ m_palette_temp.resize(palette_size);
+ memcpy(&m_palette_temp[0], prim.m_prim->texture.palette, prim.m_palette_length * 4);
+ const bgfx::Memory *palmem = bgfx::copy(&m_palette_temp[0], palette_size);
+
+ if (palette)
+ {
+ palette->update(palmem);
+ }
+ else
+ {
+ auto newpal = std::make_unique<bgfx_texture>(palette_name, bgfx::TextureFormat::BGRA8, palette_width, 0, palette_height, palmem, BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP | BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_MIP_POINT, palette_width * 4);
+ palette = newpal.get();
+ m_textures.add_provider(palette_name, std::move(newpal));
+ while (screen >= m_screen_palettes.size())
+ {
+ m_screen_palettes.emplace_back(nullptr);
+ }
+ m_screen_palettes[screen] = palette;
+ }
+ }
+ }
+
+ const bool has_tint = (prim.m_prim->color.a != 1.0f) || (prim.m_prim->color.r != 1.0f) || (prim.m_prim->color.g != 1.0f) || (prim.m_prim->color.b != 1.0f);
+ bgfx_chain* chain = screen_chain(screen);
+ if (chain && needs_adjust && !chain->has_adjuster())
+ {
+ const bool apply_tint = !needs_conversion && has_tint;
+ chain->insert_effect(chain->has_converter() ? 1 : 0, m_adjuster, apply_tint, "XXadjust", needs_conversion ? "screen" : "source", *this);
+ chain->set_has_adjuster(true);
+ }
+ if (chain && needs_conversion && !chain->has_converter())
+ {
+ chain->insert_effect(0, m_converters[src_format], has_tint, "XXconvert", "source", *this);
+ chain->set_has_converter(true);
+ }
}
+ return m_screen_prims.size();
+}
+
+uint32_t chain_manager::process_screen_chains(uint32_t view, osd_window& window)
+{
// Process each screen as necessary
uint32_t used_views = 0;
uint32_t screen_index = 0;
- for (render_primitive* prim : screens)
+ for (screen_prim &prim : m_screen_prims)
{
if (m_current_chain[screen_index] == CHAIN_NONE || screen_chain(screen_index) == nullptr)
{
@@ -440,14 +658,14 @@ uint32_t chain_manager::handle_screen_chains(uint32_t view, render_primitive *st
continue;
}
- uint16_t screen_width(floorf(prim->get_full_quad_width() + 0.5f));
- uint16_t screen_height(floorf(prim->get_full_quad_height() + 0.5f));
+ uint16_t screen_width = prim.m_screen_width;
+ uint16_t screen_height = prim.m_screen_height;
if (window.swap_xy())
{
std::swap(screen_width, screen_height);
}
- const bool any_targets_rebuilt = m_targets.update_target_sizes(screen_index, screen_width, screen_height, TARGET_STYLE_NATIVE);
+ const bool any_targets_rebuilt = m_targets.update_target_sizes(screen_index, screen_width, screen_height, TARGET_STYLE_NATIVE, m_user_prescale, m_max_prescale_size);
if (any_targets_rebuilt)
{
for (bgfx_chain* chain : m_screen_chains)
@@ -472,12 +690,12 @@ uint32_t chain_manager::handle_screen_chains(uint32_t view, render_primitive *st
bool chain_manager::has_applicable_chain(uint32_t screen)
{
- return screen < m_screen_count && m_current_chain[screen] != CHAIN_NONE && m_screen_chains[screen] != nullptr;
+ return (screen < m_screen_count) && (m_current_chain[screen] != CHAIN_NONE) && m_screen_chains[screen];
}
bool chain_manager::needs_sliders()
{
- return m_screen_count > 0 && m_available_chains.size() > 1;
+ return (m_screen_count > 0) && (m_available_chains.size() > 1);
}
void chain_manager::restore_slider_settings(int32_t id, std::vector<std::vector<float>>& settings)
@@ -500,7 +718,7 @@ void chain_manager::restore_slider_settings(int32_t id, std::vector<std::vector<
continue;
}
- std::vector<bgfx_slider*> chain_sliders = chain->sliders();
+ const std::vector<bgfx_slider*> &chain_sliders = chain->sliders();
for (size_t slider = 0; slider < chain_sliders.size(); slider++)
{
chain_sliders[slider]->import(settings[index][slider]);
@@ -508,6 +726,151 @@ void chain_manager::restore_slider_settings(int32_t id, std::vector<std::vector<
}
}
+void chain_manager::load_config(util::xml::data_node const &windownode)
+{
+ // treat source INI files or more specific as higher priority than CFG
+ // FIXME: leaky abstraction - this depends on a front-end implementation detail
+ bool const persist = windownode.get_attribute_int("persist", 1) != 0;
+ bool const default_chains = (OPTION_PRIORITY_NORMAL + 5) > m_options.get_entry(OSDOPTION_BGFX_SCREEN_CHAINS)->priority();
+ bool const explicit_chains = !persist && !default_chains && *m_options.bgfx_screen_chains();
+
+ // if chains weren't explicitly specified, restore the chains from the config file
+ if (explicit_chains)
+ {
+ osd_printf_verbose(
+ "BGFX: Ignoring chain selection from window 0 configuration due to explicitly specified chains\n",
+ m_window_index);
+ }
+ else
+ {
+ bool changed = false;
+ util::xml::data_node const *screennode = windownode.get_child("screen");
+ while (screennode)
+ {
+ auto const index = screennode->get_attribute_int("index", -1);
+ if ((0 <= index) && (m_screen_count > index))
+ {
+ char const *const chainname = screennode->get_attribute_string("chain", nullptr);
+ if (chainname)
+ {
+ auto const found = std::find_if(
+ m_available_chains.begin(),
+ m_available_chains.end(),
+ [&chainname] (auto const &avail) { return avail.m_name == chainname; });
+ if (m_available_chains.end() != found)
+ {
+ auto const chainnum = found - m_available_chains.begin();
+ if (chainnum != m_current_chain[index])
+ {
+ m_current_chain[index] = chainnum;
+ changed = true;
+ }
+ }
+ }
+ }
+
+ screennode = screennode->get_next_sibling("screen");
+ }
+
+ if (changed)
+ reload_chains();
+ }
+
+ // now apply slider settings for screens with chains matching config
+ util::xml::data_node const *screennode = windownode.get_child("screen");
+ while (screennode)
+ {
+ auto const index = screennode->get_attribute_int("index", -1);
+ if ((0 <= index) && (m_screen_count > index) && (m_screen_chains.size() > index))
+ {
+ bgfx_chain *const chain = m_screen_chains[index];
+ char const *const chainname = screennode->get_attribute_string("chain", nullptr);
+ if (chain && chainname && (m_available_chains[m_current_chain[index]].m_name == chainname))
+ {
+ auto const &sliders = chain->sliders();
+
+ util::xml::data_node const *slidernode = screennode->get_child("slider");
+ while (slidernode)
+ {
+ char const *const slidername = slidernode->get_attribute_string("name", nullptr);
+ if (slidername)
+ {
+ auto const found = std::find_if(
+ sliders.begin(),
+ sliders.end(),
+ [&slidername] (auto const &slider) { return slider->name() == slidername; });
+ if (sliders.end() != found)
+ {
+ bgfx_slider &slider = **found;
+ switch (slider.type())
+ {
+ case bgfx_slider::SLIDER_INT_ENUM:
+ case bgfx_slider::SLIDER_INT:
+ {
+ slider_state const &core = *slider.core_slider();
+ int32_t const val = slidernode->get_attribute_int("value", core.defval);
+ slider.update(nullptr, std::clamp(val, core.minval, core.maxval));
+ }
+ break;
+ default:
+ {
+ float const val = slidernode->get_attribute_float("value", slider.default_value());
+ slider.import(std::clamp(val, slider.min_value(), slider.max_value()));
+ }
+ }
+ }
+ }
+
+ slidernode = slidernode->get_next_sibling("slider");
+ }
+ }
+ }
+ screennode = screennode->get_next_sibling("screen");
+ }
+}
+
+void chain_manager::save_config(util::xml::data_node &parentnode)
+{
+ if (!needs_sliders())
+ return;
+
+ util::xml::data_node *const windownode = parentnode.add_child("window", nullptr);
+ windownode->set_attribute_int("index", m_window_index);
+
+ for (size_t index = 0; index < m_screen_chains.size() && index < m_screen_count; index++)
+ {
+ bgfx_chain *const chain = m_screen_chains[index];
+ if (!chain)
+ continue;
+
+ util::xml::data_node *const screennode = windownode->add_child("screen", nullptr);
+ screennode->set_attribute_int("index", index);
+ screennode->set_attribute("chain", m_available_chains[m_current_chain[index]].m_name.c_str());
+
+ for (bgfx_slider *slider : chain->sliders())
+ {
+ auto const val = slider->update(nullptr, SLIDER_NOCHANGE);
+ if (val == slider->core_slider()->defval)
+ continue;
+
+ util::xml::data_node *const slidernode = screennode->add_child("slider", nullptr);
+ slidernode->set_attribute("name", slider->name().c_str());
+ switch (slider->type())
+ {
+ case bgfx_slider::SLIDER_INT_ENUM:
+ case bgfx_slider::SLIDER_INT:
+ slidernode->set_attribute_int("value", val);
+ break;
+ default:
+ slidernode->set_attribute_float("value", slider->value());
+ }
+ }
+ }
+
+ if (!windownode->get_first_child())
+ windownode->delete_node();
+}
+
std::vector<std::vector<float>> chain_manager::slider_settings()
{
std::vector<std::vector<float>> curr;
@@ -527,7 +890,7 @@ std::vector<std::vector<float>> chain_manager::slider_settings()
continue;
}
- std::vector<bgfx_slider*> chain_sliders = chain->sliders();
+ const std::vector<bgfx_slider*> &chain_sliders = chain->sliders();
for (bgfx_slider* slider : chain_sliders)
{
curr[index].push_back(slider->value());
@@ -556,46 +919,38 @@ std::vector<ui::menu_item> chain_manager::get_slider_list()
continue;
}
- std::vector<bgfx_chain_entry*> chain_entries = chain->entries();
+ const std::vector<bgfx_chain_entry*> &chain_entries = chain->entries();
for (bgfx_chain_entry* entry : chain_entries)
{
- std::vector<bgfx_input_pair*> entry_inputs = entry->inputs();
+ const std::vector<bgfx_input_pair*> &entry_inputs = entry->inputs();
for (bgfx_input_pair* input : entry_inputs)
{
std::vector<ui::menu_item> input_sliders = input->get_slider_list();
- for (ui::menu_item slider : input_sliders)
+ for (ui::menu_item &slider : input_sliders)
{
- sliders.push_back(slider);
+ sliders.emplace_back(slider);
}
}
}
- std::vector<bgfx_slider*> chain_sliders = chain->sliders();
+ const std::vector<bgfx_slider*> &chain_sliders = chain->sliders();
for (bgfx_slider* slider : chain_sliders)
{
- slider_state* core_slider = slider->core_slider();
+ slider_state *const core_slider = slider->core_slider();
- ui::menu_item item;
- item.text = core_slider->description;
- item.subtext = "";
- item.flags = 0;
- item.ref = core_slider;
- item.type = ui::menu_item_type::SLIDER;
- m_selection_sliders.push_back(item);
+ ui::menu_item item(ui::menu_item_type::SLIDER, core_slider);
+ item.set_text(core_slider->description);
+ m_selection_sliders.emplace_back(item);
- sliders.push_back(item);
+ sliders.emplace_back(std::move(item));
}
if (chain_sliders.size() > 0)
{
- ui::menu_item item;
- item.text = MENU_SEPARATOR_ITEM;
- item.subtext = "";
- item.flags = 0;
- item.ref = nullptr;
- item.type = ui::menu_item_type::SEPARATOR;
+ ui::menu_item item(ui::menu_item_type::SEPARATOR);
+ item.set_text(MENU_SEPARATOR_ITEM);
- sliders.push_back(item);
+ sliders.emplace_back(std::move(item));
}
}
diff --git a/src/osd/modules/render/bgfx/chainmanager.h b/src/osd/modules/render/bgfx/chainmanager.h
index 4c76a02ee25..0d489d0bd72 100644
--- a/src/osd/modules/render/bgfx/chainmanager.h
+++ b/src/osd/modules/render/bgfx/chainmanager.h
@@ -9,20 +9,23 @@
//
//============================================================
+#ifndef MAME_RENDER_BGFX_CHAINMANAGER_H
+#define MAME_RENDER_BGFX_CHAINMANAGER_H
+
#pragma once
-#ifndef __DRAWBGFX_CHAIN_MANAGER__
-#define __DRAWBGFX_CHAIN_MANAGER__
+#include "effectmanager.h"
+#include "targetmanager.h"
+#include "texturemanager.h"
+
+#include "util/utilfwd.h"
-#include <vector>
#include <map>
#include <string>
+#include <string_view>
+#include <utility>
+#include <vector>
-#include "texturemanager.h"
-#include "targetmanager.h"
-#include "effectmanager.h"
-#include "../frontend/mame/ui/menuitem.h"
-#include "../frontend/mame/ui/sliderchangednotifier.h"
class running_machine;
class osd_window;
@@ -30,33 +33,42 @@ struct slider_state;
class slider_dirty_notifier;
class render_primitive;
+namespace ui { class menu_item; }
+
class bgfx_chain;
class bgfx_slider;
-class chain_desc
+class chain_manager
{
public:
- chain_desc(std::string name, std::string path)
- : m_name(name)
- , m_path(path)
+ class screen_prim
{
- }
-
- const std::string m_name;
- const std::string m_path;
-};
-
-class chain_manager : public slider_changed_notifier
-{
-public:
- chain_manager(running_machine& machine, osd_options& options, texture_manager& textures, target_manager& targets, effect_manager& effects, uint32_t window_index, slider_dirty_notifier& slider_notifier);
+ public:
+ screen_prim() = default;
+ screen_prim(render_primitive *prim);
+
+ render_primitive *m_prim = nullptr;
+ uint16_t m_screen_width = 0;
+ uint16_t m_screen_height = 0;
+ uint16_t m_quad_width = 0;
+ uint16_t m_quad_height = 0;
+ float m_tex_width = 0.0f;
+ float m_tex_height = 0.0f;
+ int m_rowpixels = 0;
+ uint32_t m_palette_length = 0;
+ uint32_t m_flags = 0;
+ };
+
+ chain_manager(running_machine& machine, const osd_options& options, texture_manager& textures, target_manager& targets, effect_manager& effects, uint32_t window_index,
+ slider_dirty_notifier& slider_notifier, uint16_t user_prescale, uint16_t max_prescale_size);
~chain_manager();
- uint32_t handle_screen_chains(uint32_t view, render_primitive *starting_prim, osd_window& window);
+ uint32_t update_screen_textures(uint32_t view, render_primitive *starting_prim, osd_window& window);
+ uint32_t process_screen_chains(uint32_t view, osd_window& window);
// Getters
running_machine& machine() const { return m_machine; }
- osd_options& options() const { return m_options; }
+ const osd_options& options() const { return m_options; }
texture_manager& textures() const { return m_textures; }
target_manager& targets() const { return m_targets; }
effect_manager& effects() const { return m_effects; }
@@ -64,7 +76,7 @@ public:
uint32_t window_index() const { return m_window_index; }
uint32_t screen_count() const { return m_screen_count; }
bgfx_chain* screen_chain(uint32_t screen);
- bgfx_chain* load_chain(std::string name, uint32_t screen_index);
+ std::unique_ptr<bgfx_chain> load_chain(std::string name, uint32_t screen_index);
bool has_applicable_chain(uint32_t screen);
std::vector<ui::menu_item> get_slider_list();
std::vector<std::vector<float>> slider_settings();
@@ -72,42 +84,76 @@ public:
// Setters
void restore_slider_settings(int32_t id, std::vector<std::vector<float>>& settings);
+ void load_config(util::xml::data_node const &screennode);
+ void save_config(util::xml::data_node &parentnode);
+
private:
+ class chain_desc
+ {
+ public:
+ chain_desc(const chain_desc &) = default;
+ chain_desc(chain_desc &&) = default;
+ chain_desc &operator=(const chain_desc &) = default;
+ chain_desc &operator=(chain_desc &&) = default;
+
+ chain_desc(std::string &&name, std::string &&path)
+ : m_name(std::move(name))
+ , m_path(std::move(path))
+ {
+ }
+
+ std::string m_name;
+ std::string m_path;
+ };
+
void load_chains();
void destroy_chains();
void reload_chains();
+ void init_texture_converters();
+
+ void get_default_chain_info(std::string &out_chain_name, int32_t &out_chain_index);
void refresh_available_chains();
void destroy_unloaded_chains();
- void find_available_chains(std::string root, std::string path);
- void parse_chain_selections(std::string chain_str);
- std::vector<std::string> split_option_string(std::string chain_str) const;
+ void find_available_chains(std::string_view root, std::string_view path);
+ void parse_chain_selections(std::string_view chain_str);
+ std::vector<std::string_view> split_option_string(std::string_view chain_str) const;
void update_screen_count(uint32_t screen_count);
- virtual int32_t slider_changed(running_machine &machine, void *arg, int id, std::string *str, int32_t newval) override;
+ void set_current_chain(uint32_t screen, int32_t chain_index);
+ int32_t slider_changed(int id, std::string *str, int32_t newval);
void create_selection_slider(uint32_t screen_index);
bool needs_sliders();
- std::vector<render_primitive*> count_screens(render_primitive* prim);
- void process_screen_quad(uint32_t view, uint32_t screen, render_primitive* prim, osd_window &window);
+ uint32_t count_screens(render_primitive* prim);
+ void process_screen_quad(uint32_t view, uint32_t screen, screen_prim &prim, osd_window& window);
running_machine& m_machine;
- osd_options& m_options;
+ const osd_options& m_options;
texture_manager& m_textures;
target_manager& m_targets;
effect_manager& m_effects;
uint32_t m_window_index;
+ uint16_t m_user_prescale;
+ uint16_t m_max_prescale_size;
slider_dirty_notifier& m_slider_notifier;
uint32_t m_screen_count;
+ int32_t m_default_chain_index;
std::vector<chain_desc> m_available_chains;
std::vector<bgfx_chain*> m_screen_chains;
std::vector<std::string> m_chain_names;
std::vector<ui::menu_item> m_selection_sliders;
std::vector<std::unique_ptr<slider_state>> m_core_sliders;
std::vector<int32_t> m_current_chain;
-
- static const uint32_t CHAIN_NONE;
+ std::vector<bgfx_texture*> m_screen_textures;
+ std::vector<bgfx_texture*> m_screen_palettes;
+ std::vector<bgfx_effect*> m_converters;
+ bgfx_effect * m_adjuster;
+ std::vector<screen_prim> m_screen_prims;
+ std::vector<uint8_t> m_palette_temp;
+
+ static inline constexpr uint32_t CHAIN_NONE = 0;
};
-#endif // __DRAWBGFX_CHAIN_MANAGER__
+#endif // MAME_RENDER_BGFX_CHAINMANAGER_H
diff --git a/src/osd/modules/render/bgfx/chainreader.cpp b/src/osd/modules/render/bgfx/chainreader.cpp
index 20e7080dbbe..362baa42c82 100644
--- a/src/osd/modules/render/bgfx/chainreader.cpp
+++ b/src/osd/modules/render/bgfx/chainreader.cpp
@@ -6,25 +6,28 @@
//
//============================================================
-#include <string>
-#include <vector>
-#include <map>
-
-#include "emu.h"
-#include <modules/lib/osdobj_common.h>
-
#include "chainreader.h"
+
#include "chain.h"
+#include "chainentryreader.h"
#include "chainmanager.h"
-#include "sliderreader.h"
+#include "parameter.h"
#include "paramreader.h"
-#include "chainentryreader.h"
-#include "targetreader.h"
-#include "targetmanager.h"
#include "slider.h"
-#include "parameter.h"
+#include "sliderreader.h"
+#include "targetmanager.h"
+#include "targetreader.h"
+
+#include <vector>
+#include <map>
-bgfx_chain* chain_reader::read_from_value(const Value& value, std::string prefix, chain_manager& chains, uint32_t screen_index)
+std::unique_ptr<bgfx_chain> chain_reader::read_from_value(
+ const Value& value,
+ const std::string &prefix,
+ chain_manager& chains,
+ uint32_t screen_index,
+ uint16_t user_prescale,
+ uint16_t max_prescale_size)
{
if (!validate_parameters(value, prefix))
{
@@ -98,7 +101,7 @@ bgfx_chain* chain_reader::read_from_value(const Value& value, std::string prefix
// TODO: Move into its own reader
for (uint32_t i = 0; i < target_array.Size(); i++)
{
- bgfx_target* target = target_reader::read_from_value(target_array[i], prefix + "targets[" + std::to_string(i) + "]: ", chains, screen_index);
+ bgfx_target* target = target_reader::read_from_value(target_array[i], prefix + "targets[" + std::to_string(i) + "]: ", chains, screen_index, user_prescale, max_prescale_size);
if (target == nullptr)
{
return nullptr;
@@ -123,19 +126,28 @@ bgfx_chain* chain_reader::read_from_value(const Value& value, std::string prefix
}
}
- return new bgfx_chain(name, author, transform, chains.targets(), sliders, parameters, entries, target_list, screen_index);
+ return std::make_unique<bgfx_chain>(
+ std::move(name),
+ std::move(author),
+ transform,
+ chains.targets(),
+ std::move(sliders),
+ std::move(parameters),
+ std::move(entries),
+ std::move(target_list),
+ screen_index);
}
-bool chain_reader::validate_parameters(const Value& value, std::string prefix)
+bool chain_reader::validate_parameters(const Value& value, const std::string &prefix)
{
- if (!READER_CHECK(value.HasMember("name"), (prefix + "Must have string value 'name'\n").c_str())) return false;
- if (!READER_CHECK(value["name"].IsString(), (prefix + "Value 'name' must be a string\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("author"), (prefix + "Must have string value 'author'\n").c_str())) return false;
- if (!READER_CHECK(value["author"].IsString(), (prefix + "Value 'author' must be a string\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("passes"), (prefix + "Must have array value 'passes'\n").c_str())) return false;
- if (!READER_CHECK(value["passes"].IsArray(), (prefix + "Value 'passes' must be an array\n").c_str())) return false;
- if (!READER_CHECK(!value.HasMember("sliders") || value["sliders"].IsArray(), (prefix + "Value 'sliders' must be an array\n").c_str())) return false;
- if (!READER_CHECK(!value.HasMember("parameters") || value["parameters"].IsArray(), (prefix + "Value 'parameters' must be an array\n").c_str())) return false;
- if (!READER_CHECK(!value.HasMember("targets") || value["targets"].IsArray(), (prefix + "Value 'targets' must be an array\n").c_str())) return false;
+ if (!READER_CHECK(value.HasMember("name"), "%sMust have string value 'name'\n", prefix)) return false;
+ if (!READER_CHECK(value["name"].IsString(), "%sValue 'name' must be a string\n", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("author"), "%sMust have string value 'author'\n", prefix)) return false;
+ if (!READER_CHECK(value["author"].IsString(), "%sValue 'author' must be a string\n", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("passes"), "%sMust have array value 'passes'\n", prefix)) return false;
+ if (!READER_CHECK(value["passes"].IsArray(), "%sValue 'passes' must be an array\n", prefix)) return false;
+ if (!READER_CHECK(!value.HasMember("sliders") || value["sliders"].IsArray(), "%sValue 'sliders' must be an array\n", prefix)) return false;
+ if (!READER_CHECK(!value.HasMember("parameters") || value["parameters"].IsArray(), "%sValue 'parameters' must be an array\n", prefix)) return false;
+ if (!READER_CHECK(!value.HasMember("targets") || value["targets"].IsArray(), "%sValue 'targets' must be an array\n", prefix)) return false;
return true;
}
diff --git a/src/osd/modules/render/bgfx/chainreader.h b/src/osd/modules/render/bgfx/chainreader.h
index a2fa3ba28a5..6bbd2058501 100644
--- a/src/osd/modules/render/bgfx/chainreader.h
+++ b/src/osd/modules/render/bgfx/chainreader.h
@@ -6,23 +6,26 @@
//
//============================================================
-#pragma once
+#ifndef MAME_RENDER_BGFX_CHAINREADER_H
+#define MAME_RENDER_BGFX_CHAINREADER_H
-#ifndef __DRAWBGFX_CHAIN_READER__
-#define __DRAWBGFX_CHAIN_READER__
+#pragma once
#include "statereader.h"
+#include <memory>
+#include <string>
+
class bgfx_chain;
class chain_manager;
class chain_reader : public state_reader
{
public:
- static bgfx_chain* read_from_value(const Value& value, std::string prefix, chain_manager& chains, uint32_t screen_index);
+ static std::unique_ptr<bgfx_chain> read_from_value(const Value& value, const std::string &prefix, chain_manager& chains, uint32_t screen_index, uint16_t user_prescale, uint16_t max_prescale_size);
private:
- static bool validate_parameters(const Value& value, std::string prefix);
+ static bool validate_parameters(const Value& value, const std::string &prefix);
};
-#endif // __DRAWBGFX_CHAIN_READER__
+#endif // MAME_RENDER_BGFX_CHAINREADER_H
diff --git a/src/osd/modules/render/bgfx/clearreader.cpp b/src/osd/modules/render/bgfx/clearreader.cpp
index 3cbd714463c..58c4d5f01aa 100644
--- a/src/osd/modules/render/bgfx/clearreader.cpp
+++ b/src/osd/modules/render/bgfx/clearreader.cpp
@@ -6,13 +6,15 @@
//
//============================================================
-#include <bgfx/bgfx.h>
-
#include "clearreader.h"
#include "clear.h"
-clear_state* clear_reader::read_from_value(const Value& value, std::string prefix)
+#include <bgfx/bgfx.h>
+
+#include <algorithm>
+
+clear_state* clear_reader::read_from_value(const Value& value, const std::string &prefix)
{
if (!validate_parameters(value, prefix))
{
@@ -29,10 +31,8 @@ clear_state* clear_reader::read_from_value(const Value& value, std::string prefi
const Value& colors = value["clearcolor"];
for (int i = 0; i < colors.Size(); i++)
{
- if (!READER_CHECK(colors[i].IsNumber(), (prefix + "clearcolor[" + std::to_string(i) + "] must be a numeric value\n").c_str())) return nullptr;
- int32_t val = int32_t(float(colors[i].GetDouble()) * 255.0f);
- if (val > 255) val = 255;
- if (val < 0) val = 0;
+ if (!READER_CHECK(colors[i].IsNumber(), "%sclearcolor[%d] must be a numeric value\n", prefix, i)) return nullptr;
+ auto val = std::clamp<int32_t>(float(colors[i].GetDouble()) * 255.0f, 0, 255);
clear_color |= val << (24 - (i * 3));
}
clear_flags |= BGFX_CLEAR_COLOR;
@@ -53,10 +53,10 @@ clear_state* clear_reader::read_from_value(const Value& value, std::string prefi
return new clear_state(clear_flags, clear_color, clear_depth, clear_stencil);
}
-bool clear_reader::validate_parameters(const Value& value, std::string prefix)
+bool clear_reader::validate_parameters(const Value& value, const std::string &prefix)
{
- if (!READER_CHECK(!value.HasMember("clearcolor") || (value["clearcolor"].IsArray() && value["clearcolor"].GetArray().Size() == 4), (prefix + "'clearcolor' must be an array of four numeric RGBA values representing the color to which to clear the color buffer\n").c_str())) return false;
- if (!READER_CHECK(!value.HasMember("cleardepth") || value["cleardepth"].IsNumber(), (prefix + "'cleardepth' must be a numeric value representing the depth to which to clear the depth buffer\n").c_str())) return false;
- if (!READER_CHECK(!value.HasMember("clearstencil") || value["clearstencil"].IsNumber(), (prefix + "'clearstencil' must be a numeric value representing the stencil value to which to clear the stencil buffer\n").c_str())) return false;
+ if (!READER_CHECK(!value.HasMember("clearcolor") || (value["clearcolor"].IsArray() && value["clearcolor"].GetArray().Size() == 4), "%s'clearcolor' must be an array of four numeric RGBA values representing the color to which to clear the color buffer\n", prefix)) return false;
+ if (!READER_CHECK(!value.HasMember("cleardepth") || value["cleardepth"].IsNumber(), "%s'cleardepth' must be a numeric value representing the depth to which to clear the depth buffer\n", prefix)) return false;
+ if (!READER_CHECK(!value.HasMember("clearstencil") || value["clearstencil"].IsNumber(), "%s'clearstencil' must be a numeric value representing the stencil value to which to clear the stencil buffer\n", prefix)) return false;
return true;
}
diff --git a/src/osd/modules/render/bgfx/clearreader.h b/src/osd/modules/render/bgfx/clearreader.h
index 80605ea35f3..1c2063e95de 100644
--- a/src/osd/modules/render/bgfx/clearreader.h
+++ b/src/osd/modules/render/bgfx/clearreader.h
@@ -6,26 +6,26 @@
//
//============================================================
+#ifndef MAME_RENDER_BGFX_CLEARREADER_H
+#define MAME_RENDER_BGFX_CLEARREADER_H
+
#pragma once
-#ifndef __DRAWBGFX_CLEAR_READER__
-#define __DRAWBGFX_CLEAR_READER__
+#include "statereader.h"
#include <string>
-#include "statereader.h"
-
class clear_state;
class clear_reader : public state_reader {
public:
- static clear_state* read_from_value(const Value& value, std::string prefix);
+ static clear_state* read_from_value(const Value& value, const std::string &prefix);
private:
- static bool validate_parameters(const Value& value, std::string prefix);
+ static bool validate_parameters(const Value& value, const std::string &prefix);
static const int FLAG_COUNT = 3;
static const string_to_enum FLAG_NAMES[FLAG_COUNT];
};
-#endif // __DRAWBGFX_CLEAR_READER__
+#endif // MAME_RENDER_BGFX_CLEARREADER_H
diff --git a/src/osd/modules/render/bgfx/depthreader.cpp b/src/osd/modules/render/bgfx/depthreader.cpp
index 97502d9028e..bcfc568b0da 100644
--- a/src/osd/modules/render/bgfx/depthreader.cpp
+++ b/src/osd/modules/render/bgfx/depthreader.cpp
@@ -6,10 +6,10 @@
//
//============================================================
-#include <bgfx/bgfx.h>
-
#include "depthreader.h"
+#include <bgfx/bgfx.h>
+
const depth_reader::string_to_enum depth_reader::FUNCTION_NAMES[depth_reader::FUNCTION_COUNT] = {
{ "never", BGFX_STATE_DEPTH_TEST_NEVER },
{ "less", BGFX_STATE_DEPTH_TEST_LESS },
@@ -21,12 +21,12 @@ const depth_reader::string_to_enum depth_reader::FUNCTION_NAMES[depth_reader::FU
{ "always", BGFX_STATE_DEPTH_TEST_ALWAYS }
};
-uint64_t depth_reader::read_from_value(const Value& value, std::string prefix)
+uint64_t depth_reader::read_from_value(const Value& value, const std::string &prefix)
{
uint64_t write_enable = 0;
if (value.HasMember("writeenable"))
{
- if (!READER_CHECK(value["writeenable"].IsBool(), (prefix + "Value 'writeenable' must be a boolean\n").c_str())) return 0;
+ if (!READER_CHECK(value["writeenable"].IsBool(), "%sValue 'writeenable' must be a boolean\n", prefix)) return 0;
write_enable = value["writeenable"].GetBool() ? BGFX_STATE_WRITE_Z : 0;
}
diff --git a/src/osd/modules/render/bgfx/depthreader.h b/src/osd/modules/render/bgfx/depthreader.h
index 9e2c99a0b29..0815732850f 100644
--- a/src/osd/modules/render/bgfx/depthreader.h
+++ b/src/osd/modules/render/bgfx/depthreader.h
@@ -6,10 +6,10 @@
//
//============================================================
-#pragma once
+#ifndef MAME_RENDER_BGFX_DEPTHREADER_H
+#define MAME_RENDER_BGFX_DEPTHREADER_H
-#ifndef __DRAWBGFX_DEPTH_READER__
-#define __DRAWBGFX_DEPTH_READER__
+#pragma once
#include <string>
@@ -17,11 +17,11 @@
class depth_reader : public state_reader {
public:
- static uint64_t read_from_value(const Value& value, std::string prefix);
+ static uint64_t read_from_value(const Value& value, const std::string &prefix);
private:
static const int FUNCTION_COUNT = 8;
static const string_to_enum FUNCTION_NAMES[FUNCTION_COUNT];
};
-#endif // __DRAWBGFX_DEPTH_READER__
+#endif // MAME_RENDER_BGFX_DEPTHREADER_H
diff --git a/src/osd/modules/render/bgfx/effect.cpp b/src/osd/modules/render/bgfx/effect.cpp
index fb3d7d933ba..18b43cca9bf 100644
--- a/src/osd/modules/render/bgfx/effect.cpp
+++ b/src/osd/modules/render/bgfx/effect.cpp
@@ -11,52 +11,52 @@
#include "uniform.h"
#include "modules/osdmodule.h"
+#include "osdcore.h"
-bgfx_effect::bgfx_effect(uint64_t state, bgfx::ShaderHandle vertex_shader, bgfx::ShaderHandle fragment_shader, std::vector<bgfx_uniform*> uniforms)
- : m_state(state)
+#include <utility>
+
+
+bgfx_effect::bgfx_effect(std::string &&name, uint64_t state, bgfx::ShaderHandle vertex_shader, bgfx::ShaderHandle fragment_shader, std::vector<std::unique_ptr<bgfx_uniform> > &uniforms)
+ : m_name(std::move(name))
+ , m_state(state)
{
m_program_handle = bgfx::createProgram(vertex_shader, fragment_shader, false);
- for (int i = 0; i < uniforms.size(); i++)
+ for (auto &uniform : uniforms)
{
- if (m_uniforms[uniforms[i]->name()] != nullptr)
+ const auto existing = m_uniforms.find(uniform->name());
+ if (existing != m_uniforms.end())
{
- osd_printf_verbose("Uniform %s appears to be duplicated in one or more effects, please double-check the effect JSON files.\n", uniforms[i]->name().c_str());
- delete uniforms[i];
+ osd_printf_verbose("Uniform %s appears to be duplicated in one or more effects, please double-check the effect JSON files.\n", uniform->name());
+ uniform.reset();
continue;
}
- m_uniforms[uniforms[i]->name()] = uniforms[i];
+ uniform->create();
+ m_uniforms.emplace(uniform->name(), std::move(uniform));
}
}
bgfx_effect::~bgfx_effect()
{
- for (std::pair<std::string, bgfx_uniform*> uniform : m_uniforms)
- {
- delete uniform.second;
- }
m_uniforms.clear();
bgfx::destroy(m_program_handle);
}
void bgfx_effect::submit(int view, uint64_t blend)
{
- for (std::pair<std::string, bgfx_uniform*> uniform_pair : m_uniforms)
+ for (auto &[name, uniform] : m_uniforms)
{
- (uniform_pair.second)->upload();
+ uniform->upload();
}
- bgfx::setState(m_state | blend);
+
+ const uint64_t final_state = (blend != ~0ULL) ? ((m_state & ~BGFX_STATE_BLEND_MASK) | blend) : m_state;
+
+ bgfx::setState(final_state);
bgfx::submit(view, m_program_handle);
}
-bgfx_uniform* bgfx_effect::uniform(std::string name)
+bgfx_uniform* bgfx_effect::uniform(const std::string &name)
{
- std::map<std::string, bgfx_uniform*>::iterator iter = m_uniforms.find(name);
-
- if (iter != m_uniforms.end())
- {
- return iter->second;
- }
-
- return nullptr;
+ const auto iter = m_uniforms.find(name);
+ return (iter != m_uniforms.end()) ? iter->second.get() : nullptr;
}
diff --git a/src/osd/modules/render/bgfx/effect.h b/src/osd/modules/render/bgfx/effect.h
index 02ef9fd4f54..07646e6302e 100644
--- a/src/osd/modules/render/bgfx/effect.h
+++ b/src/osd/modules/render/bgfx/effect.h
@@ -6,32 +6,36 @@
//
//============================================================
-#pragma once
+#ifndef MAME_RENDER_BGFX_EFFECT_H
+#define MAME_RENDER_BGFX_EFFECT_H
-#ifndef __DRAWBGFX_EFFECT__
-#define __DRAWBGFX_EFFECT__
+#pragma once
#include <bgfx/bgfx.h>
-#include <vector>
#include <map>
+#include <memory>
#include <string>
+#include <vector>
+
class bgfx_uniform;
class bgfx_effect
{
public:
- bgfx_effect(uint64_t state, bgfx::ShaderHandle vertex_shader, bgfx::ShaderHandle fragment_shader, std::vector<bgfx_uniform*> uniforms);
+ bgfx_effect(std::string &&name, uint64_t state, bgfx::ShaderHandle vertex_shader, bgfx::ShaderHandle fragment_shader, std::vector<std::unique_ptr<bgfx_uniform> > &uniforms);
~bgfx_effect();
- void submit(int view, uint64_t blend = 0L);
- bgfx_uniform* uniform(std::string name);
+ void submit(int view, uint64_t blend = ~0ULL);
+ bgfx_uniform *uniform(const std::string &name);
+ bool is_valid() const { return m_program_handle.idx != bgfx::kInvalidHandle; }
private:
+ std::string m_name;
uint64_t m_state;
bgfx::ProgramHandle m_program_handle;
- std::map<std::string, bgfx_uniform*> m_uniforms;
+ std::map<std::string, std::unique_ptr<bgfx_uniform> > m_uniforms;
};
-#endif // __DRAWBGFX_EFFECT__
+#endif // MAME_RENDER_BGFX_EFFECT_H
diff --git a/src/osd/modules/render/bgfx/effectmanager.cpp b/src/osd/modules/render/bgfx/effectmanager.cpp
index 6462ae75f72..e5e5d1698f6 100644
--- a/src/osd/modules/render/bgfx/effectmanager.cpp
+++ b/src/osd/modules/render/bgfx/effectmanager.cpp
@@ -9,86 +9,119 @@
//
//============================================================
+#include "effectmanager.h"
+
+#include "effect.h"
+#include "effectreader.h"
+#include "shadermanager.h"
+
+#include "path.h"
+
+#include "osdfile.h"
+#include "modules/lib/osdobj_common.h"
+
#include <rapidjson/document.h>
#include <rapidjson/error/en.h>
#include <bx/readerwriter.h>
#include <bx/file.h>
-#include "emu.h"
-
#include <bgfx/bgfx.h>
-#include "effectmanager.h"
-#include "effectreader.h"
-#include "effect.h"
+#include <utility>
-using namespace rapidjson;
-effect_manager::~effect_manager()
+static bool prepare_effect_document(const std::string &name, const osd_options &options, rapidjson::Document &document)
{
- for (std::pair<std::string, bgfx_effect*> effect : m_effects)
- {
- delete effect.second;
- }
- m_effects.clear();
-}
-
-bgfx_effect* effect_manager::effect(std::string name)
-{
- std::map<std::string, bgfx_effect*>::iterator iter = m_effects.find(name);
- if (iter != m_effects.end())
+ std::string full_name = name;
+ if (full_name.length() < 5 || (full_name.compare(full_name.length() - 5, 5, ".json") != 0))
{
- return iter->second;
+ full_name += ".json";
}
- return load_effect(name);
-}
-
-bgfx_effect* effect_manager::load_effect(std::string name)
-{
- std::string full_name = name;
- if (full_name.length() < 5 || (full_name.compare(full_name.length() - 5, 5, ".json") != 0)) {
- full_name = full_name + ".json";
- }
- std::string path;
- osd_subst_env(path, util::string_format("%s" PATH_SEPARATOR "effects" PATH_SEPARATOR, m_options.bgfx_path()));
- path += full_name;
+ const std::string path = util::path_concat(options.bgfx_path(), "effects", full_name);
bx::FileReader reader;
if (!bx::open(&reader, path.c_str()))
{
- printf("Unable to open effect file %s\n", path.c_str());
- return nullptr;
+ osd_printf_error("Unable to open effect file %s\n", path);
+ return false;
}
- int32_t size (bx::getSize(&reader));
+ const int32_t size = bx::getSize(&reader);
+ std::unique_ptr<char []> data(new (std::nothrow) char [size + 1]);
+ if (!data)
+ {
+ osd_printf_error("Out of memory reading effect file %s\n", path);
+ bx::close(&reader);
+ return false;
+ }
- char* data = new char[size + 1];
- bx::read(&reader, reinterpret_cast<void*>(data), size);
+ bx::ErrorAssert err;
+ bx::read(&reader, reinterpret_cast<void*>(data.get()), size, &err);
bx::close(&reader);
data[size] = 0;
- Document document;
- document.Parse<kParseCommentsFlag>(data);
+ document.Parse<rapidjson::kParseCommentsFlag>(data.get());
+ data.reset();
- delete [] data;
+ if (document.HasParseError())
+ {
+ std::string error(rapidjson::GetParseError_En(document.GetParseError()));
+ osd_printf_error("Unable to parse effect %s. Errors returned:\n%s\n", path, error);
+ return false;
+ }
+
+ return true;
+}
+
+
+// keep constructor and destructor out-of-line so the header works with forward declarations
+
+effect_manager::effect_manager(shader_manager& shaders) : m_shaders(shaders)
+{
+}
+
+effect_manager::~effect_manager()
+{
+ // the map will automatically dispose of the effects
+}
- if (document.HasParseError()) {
- std::string error(GetParseError_En(document.GetParseError()));
- printf("Unable to parse effect %s. Errors returned:\n", path.c_str());
- printf("%s\n", error.c_str());
+bgfx_effect* effect_manager::get_or_load_effect(const osd_options &options, const std::string &name)
+{
+ const auto iter = m_effects.find(name);
+ if (iter != m_effects.end())
+ return iter->second.get();
+
+ return load_effect(options, name);
+}
+
+bgfx_effect* effect_manager::load_effect(const osd_options &options, const std::string &name)
+{
+ rapidjson::Document document;
+ if (!prepare_effect_document(name, options, document))
+ {
return nullptr;
}
- bgfx_effect* effect = effect_reader::read_from_value(document, "Effect '" + name + "': ", m_shaders);
+ std::unique_ptr<bgfx_effect> effect = effect_reader::read_from_value(name, document, "Effect '" + name + "': ", options, m_shaders);
- if (effect == nullptr) {
- printf("Unable to load effect %s\n", path.c_str());
+ if (!effect)
+ {
+ osd_printf_error("Unable to load effect %s\n", name);
return nullptr;
}
- m_effects[name] = effect;
+ return m_effects.emplace(name, std::move(effect)).first->second.get();
+}
+
+bool effect_manager::validate_effect(const osd_options &options, const std::string &name)
+{
+ rapidjson::Document document;
+ if (!prepare_effect_document(name, options, document))
+ {
+ return false;
+ }
- return effect;
+ return effect_reader::validate_value(document, "Effect '" + name + "': ", options);
}
diff --git a/src/osd/modules/render/bgfx/effectmanager.h b/src/osd/modules/render/bgfx/effectmanager.h
index 8125741c7ff..697d468dc5c 100644
--- a/src/osd/modules/render/bgfx/effectmanager.h
+++ b/src/osd/modules/render/bgfx/effectmanager.h
@@ -9,34 +9,35 @@
//
//============================================================
-#pragma once
+#ifndef MAME_RENDER_BGFX_EFFECTMANAGER_H
+#define MAME_RENDER_BGFX_EFFECTMANAGER_H
-#ifndef __DRAWBGFX_EFFECT_MANAGER__
-#define __DRAWBGFX_EFFECT_MANAGER__
+#pragma once
#include <map>
+#include <memory>
#include <string>
-#include <bgfx/bgfx.h>
-
-#include "shadermanager.h"
class bgfx_effect;
+class osd_options;
+class shader_manager;
-class effect_manager {
+class effect_manager
+{
public:
- effect_manager(osd_options& options, shader_manager& shaders) : m_options(options), m_shaders(shaders) { }
+ effect_manager(shader_manager& shaders);
~effect_manager();
// Getters
- bgfx_effect* effect(std::string name);
+ bgfx_effect* get_or_load_effect(const osd_options &options, const std::string &name);
+ static bool validate_effect(const osd_options &options, const std::string &name);
private:
- bgfx_effect* load_effect(std::string name);
+ bgfx_effect* load_effect(const osd_options &options, const std::string &name);
- osd_options& m_options;
- shader_manager& m_shaders;
- std::map<std::string, bgfx_effect*> m_effects;
+ shader_manager &m_shaders;
+ std::map<std::string, std::unique_ptr<bgfx_effect> > m_effects;
};
-#endif // __DRAWBGFX_EFFECT_MANAGER__
+#endif // MAME_RENDER_BGFX_EFFECTMANAGER_H
diff --git a/src/osd/modules/render/bgfx/effectreader.cpp b/src/osd/modules/render/bgfx/effectreader.cpp
index 3e51cb9d9dc..befdc598537 100644
--- a/src/osd/modules/render/bgfx/effectreader.cpp
+++ b/src/osd/modules/render/bgfx/effectreader.cpp
@@ -6,30 +6,87 @@
//
//============================================================
-#include <string>
-
-#include <bgfx/bgfx.h>
-
-#include "emu.h"
+#include "effectreader.h"
-#include "effect.h"
#include "blendreader.h"
-#include "depthreader.h"
#include "cullreader.h"
-#include "writereader.h"
+#include "depthreader.h"
+#include "effect.h"
#include "shadermanager.h"
-#include "uniformreader.h"
#include "uniform.h"
+#include "uniformreader.h"
+#include "writereader.h"
-#include "effectreader.h"
+#include <utility>
-bgfx_effect* effect_reader::read_from_value(const Value& value, std::string prefix, shader_manager& shaders)
+
+std::unique_ptr<bgfx_effect> effect_reader::read_from_value(
+ const std::string &name,
+ const Value &value,
+ const std::string &prefix,
+ const osd_options &options,
+ shader_manager &shaders)
{
- if (!validate_parameters(value, prefix))
+ uint64_t flags = 0;
+ std::string vertex_name;
+ std::string fragment_name;
+ std::vector<std::unique_ptr<bgfx_uniform> > uniforms;
+
+ if (!get_base_effect_data(value, prefix, flags, vertex_name, fragment_name, uniforms))
{
return nullptr;
}
+ bgfx::ShaderHandle vertex_shader = BGFX_INVALID_HANDLE;
+ bgfx::ShaderHandle fragment_shader = BGFX_INVALID_HANDLE;
+
+ if (!get_shader_data(value, options, shaders, vertex_name, vertex_shader, fragment_name, fragment_shader))
+ {
+ return nullptr;
+ }
+
+ std::unique_ptr<bgfx_effect> effect(new bgfx_effect(std::string(name), flags, vertex_shader, fragment_shader, uniforms));
+ if (!effect->is_valid())
+ return nullptr;
+
+ return effect;
+}
+
+bool effect_reader::validate_value(const Value& value, const std::string &prefix, const osd_options &options)
+{
+ if (!validate_parameters(value, prefix))
+ return false;
+
+ uint64_t flags = 0;
+ std::string vertex_name;
+ std::string fragment_name;
+ std::vector<std::unique_ptr<bgfx_uniform> > uniforms;
+
+ if (!get_base_effect_data(value, prefix, flags, vertex_name, fragment_name, uniforms))
+ return false;
+
+ if (!shader_manager::is_shader_present(options, vertex_name))
+ return false;
+
+ if (!shader_manager::is_shader_present(options, fragment_name))
+ return false;
+
+ return true;
+}
+
+bool effect_reader::get_base_effect_data(
+ const Value& value,
+ const std::string &prefix,
+ uint64_t &flags,
+ std::string &vertex_name,
+ std::string &fragment_name,
+ std::vector<std::unique_ptr<bgfx_uniform> > &uniforms)
+{
+ if (!validate_parameters(value, prefix))
+ {
+ return false;
+ }
+
uint64_t blend = 0;
if (value.HasMember("blend"))
{
@@ -38,34 +95,21 @@ bgfx_effect* effect_reader::read_from_value(const Value& value, std::string pref
uint64_t depth = depth_reader::read_from_value(value["depth"], prefix + "depth: ");
uint64_t cull = cull_reader::read_from_value(value["cull"]);
uint64_t write = write_reader::read_from_value(value["write"]);
+ flags = blend | depth | cull | write;
- std::vector<bgfx_uniform*> uniforms;
const Value& uniform_array = value["uniforms"];
for (uint32_t i = 0; i < uniform_array.Size(); i++)
{
- bgfx_uniform* uniform = uniform_reader::read_from_value(uniform_array[i], prefix + "uniforms[" + std::to_string(i) + "]: ");
- if (uniform == nullptr)
+ auto uniform = uniform_reader::read_from_value(uniform_array[i], prefix + "uniforms[" + std::to_string(i) + "]: ");
+ if (!uniform)
{
- return nullptr;
+ return false;
}
- uniforms.push_back(uniform);
+ uniforms.emplace_back(std::move(uniform));
}
- std::string vertex_name(value["vertex"].GetString());
- bgfx::ShaderHandle vertex_shader = shaders.shader(vertex_name);
- if (vertex_shader.idx == 0xffff)
- {
- for (bgfx_uniform* uniform : uniforms)
- {
- if (uniform != nullptr)
- {
- delete uniform;
- }
- }
- return nullptr;
- }
+ vertex_name = value["vertex"].GetString();
- std::string fragment_name("");
if (value.HasMember("fragment"))
{
fragment_name = value["fragment"].GetString();
@@ -74,33 +118,49 @@ bgfx_effect* effect_reader::read_from_value(const Value& value, std::string pref
{
fragment_name = value["pixel"].GetString();
}
- bgfx::ShaderHandle fragment_shader = shaders.shader(fragment_name);
- if (fragment_shader.idx == 0xffff)
+ else
{
- for (bgfx_uniform* uniform : uniforms)
- {
- if (uniform != nullptr)
- {
- delete uniform;
- }
- }
- return nullptr;
+ fragment_name = "";
+ }
+
+ return true;
+}
+
+bool effect_reader::get_shader_data(
+ const Value &value,
+ const osd_options &options,
+ shader_manager &shaders,
+ std::string &vertex_name,
+ bgfx::ShaderHandle &vertex_shader,
+ std::string &fragment_name,
+ bgfx::ShaderHandle &fragment_shader)
+{
+ vertex_shader = shaders.load_shader(options, vertex_name);
+ if (vertex_shader.idx == bgfx::kInvalidHandle)
+ {
+ return false;
}
- return new bgfx_effect(blend | depth | cull | write, vertex_shader, fragment_shader, uniforms);
+ fragment_shader = shaders.load_shader(options, fragment_name);
+ if (fragment_shader.idx == bgfx::kInvalidHandle)
+ {
+ return false;
+ }
+
+ return true;
}
-bool effect_reader::validate_parameters(const Value& value, std::string prefix)
+bool effect_reader::validate_parameters(const Value& value, const std::string &prefix)
{
- if (!READER_CHECK(value.HasMember("depth"), (prefix + "Must have object value 'depth' (what are our Z-buffer settings?)\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("cull"), (prefix + "Must have object value 'cull' (do we cull triangles based on winding?)\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("write"), (prefix + "Must have object value 'write' (what are our color buffer write settings?)\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("vertex"), (prefix + "Must have string value 'vertex' (what is our vertex shader?)\n").c_str())) return false;
- if (!READER_CHECK(value["vertex"].IsString(), (prefix + "Value 'vertex' must be a string\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("fragment") || value.HasMember("pixel"), (prefix + "Must have string value named 'fragment' or 'pixel' (what is our fragment/pixel shader?)\n").c_str())) return false;
- if (!READER_CHECK(!value.HasMember("fragment") || value["fragment"].IsString(), (prefix + "Value 'fragment' must be a string\n").c_str())) return false;
- if (!READER_CHECK(!value.HasMember("pixel") || value["pixel"].IsString(), (prefix + "Value 'pixel' must be a string\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("uniforms"), (prefix + "Must have array value 'uniforms' (what are our shader's parameters?)\n").c_str())) return false;
- if (!READER_CHECK(value["uniforms"].IsArray(), (prefix + "Value 'uniforms' must be an array\n").c_str())) return false;
+ if (!READER_CHECK(value.HasMember("depth"), "%sMust have object value 'depth' (what are our Z-buffer settings?)\n", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("cull"), "%sMust have object value 'cull' (do we cull triangles based on winding?)\n", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("write"), "%sMust have object value 'write' (what are our color buffer write settings?)\n", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("vertex"), "%sMust have string value 'vertex' (what is our vertex shader?)\n", prefix)) return false;
+ if (!READER_CHECK(value["vertex"].IsString(), "%sValue 'vertex' must be a string\n", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("fragment") || value.HasMember("pixel"), "%sMust have string value named 'fragment' or 'pixel' (what is our fragment/pixel shader?)\n", prefix)) return false;
+ if (!READER_CHECK(!value.HasMember("fragment") || value["fragment"].IsString(), "%sValue 'fragment' must be a string\n", prefix)) return false;
+ if (!READER_CHECK(!value.HasMember("pixel") || value["pixel"].IsString(), "%sValue 'pixel' must be a string\n", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("uniforms"), "%sMust have array value 'uniforms' (what are our shader's parameters?)\n", prefix)) return false;
+ if (!READER_CHECK(value["uniforms"].IsArray(), "%sValue 'uniforms' must be an array\n", prefix)) return false;
return true;
}
diff --git a/src/osd/modules/render/bgfx/effectreader.h b/src/osd/modules/render/bgfx/effectreader.h
index 0bc1b334435..db590e5eeb3 100644
--- a/src/osd/modules/render/bgfx/effectreader.h
+++ b/src/osd/modules/render/bgfx/effectreader.h
@@ -6,25 +6,38 @@
//
//============================================================
+#ifndef MAME_RENDER_BGFX_EFFECTREADER_H
+#define MAME_RENDER_BGFX_EFFECTREADER_H
+
#pragma once
-#ifndef __DRAWBGFX_EFFECT_READER__
-#define __DRAWBGFX_EFFECT_READER__
+#include "statereader.h"
+
+#include <bgfx/bgfx.h>
+#include <memory>
#include <string>
+#include <vector>
-#include "statereader.h"
class bgfx_effect;
+class bgfx_uniform;
+class osd_options;
class shader_manager;
+
class effect_reader : public state_reader
{
public:
- static bgfx_effect* read_from_value(const Value& value, std::string prefix, shader_manager& shaders);
+ static std::unique_ptr<bgfx_effect> read_from_value(const std::string &name, const Value& value, const std::string &prefix, const osd_options &options, shader_manager& shaders);
+ static bool validate_value(const Value& value, const std::string &prefix, const osd_options &options);
private:
- static bool validate_parameters(const Value& value, std::string prefix);
+ static bool get_base_effect_data(const Value& value, const std::string &prefix, uint64_t &flags, std::string &vertex_name, std::string &fragment_name,
+ std::vector<std::unique_ptr<bgfx_uniform> > &uniforms);
+ static bool get_shader_data(const Value& value, const osd_options &options, shader_manager &shaders, std::string &vertex_name, bgfx::ShaderHandle &vertex_shader,
+ std::string &fragment_name, bgfx::ShaderHandle &fragment_shader);
+ static bool validate_parameters(const Value& value, const std::string &prefix);
};
-#endif // __DRAWBGFX_EFFECT_READER__
+#endif // MAME_RENDER_BGFX_EFFECTREADER_H
diff --git a/src/osd/modules/render/bgfx/entryuniform.h b/src/osd/modules/render/bgfx/entryuniform.h
index 4ba30250e6e..88ccc3e536d 100644
--- a/src/osd/modules/render/bgfx/entryuniform.h
+++ b/src/osd/modules/render/bgfx/entryuniform.h
@@ -9,15 +9,15 @@
//
//============================================================
+#ifndef MAME_RENDER_BGFX_ENTRYUNIFORM_H
+#define MAME_RENDER_BGFX_ENTRYUNIFORM_H
+
#pragma once
-#ifndef __DRAWBGFX_ENTRY_UNIFORM__
-#define __DRAWBGFX_ENTRY_UNIFORM__
+#include "uniform.h"
#include <bgfx/bgfx.h>
-#include "uniform.h"
-
class bgfx_entry_uniform
{
public:
@@ -25,10 +25,10 @@ public:
virtual ~bgfx_entry_uniform() { }
virtual void bind() = 0;
- std::string name() const { return m_uniform->name(); }
+ const std::string &name() const { return m_uniform->name(); }
protected:
bgfx_uniform* m_uniform;
};
-#endif // __DRAWBGFX_ENTRY_UNIFORM__
+#endif // MAME_RENDER_BGFX_ENTRYUNIFORM_H
diff --git a/src/osd/modules/render/bgfx/entryuniformreader.cpp b/src/osd/modules/render/bgfx/entryuniformreader.cpp
index 947f4c56e90..62c618f39a7 100644
--- a/src/osd/modules/render/bgfx/entryuniformreader.cpp
+++ b/src/osd/modules/render/bgfx/entryuniformreader.cpp
@@ -15,7 +15,7 @@
#include "paramuniformreader.h"
#include "uniform.h"
-bgfx_entry_uniform* entry_uniform_reader::read_from_value(const Value& value, std::string prefix, bgfx_effect* effect, std::map<std::string, bgfx_slider*>& sliders, std::map<std::string, bgfx_parameter*>& params)
+bgfx_entry_uniform* entry_uniform_reader::read_from_value(const Value& value, const std::string &prefix, bgfx_effect* effect, std::map<std::string, bgfx_slider*>& sliders, std::map<std::string, bgfx_parameter*>& params)
{
if (!validate_parameters(value, prefix))
{
@@ -25,7 +25,7 @@ bgfx_entry_uniform* entry_uniform_reader::read_from_value(const Value& value, st
std::string name = value["uniform"].GetString();
bgfx_uniform* uniform = effect->uniform(name);
- if (!READER_CHECK(uniform != nullptr, (prefix + "Uniform '" + name + " does not appear to exist\n").c_str()))
+ if (!READER_CHECK(uniform != nullptr, "%sUniform '%s' does not appear to exist\n", prefix, name))
{
return nullptr;
}
@@ -44,16 +44,16 @@ bgfx_entry_uniform* entry_uniform_reader::read_from_value(const Value& value, st
}
else
{
- READER_CHECK(false, (prefix + "Unrecognized uniform type for uniform binding " + name).c_str());
+ READER_CHECK(false, "%sUnrecognized uniform type for uniform binding %s", prefix, name);
}
return nullptr;
}
-bool entry_uniform_reader::validate_parameters(const Value& value, std::string prefix)
+bool entry_uniform_reader::validate_parameters(const Value& value, const std::string &prefix)
{
- if (!READER_CHECK(value.HasMember("uniform"), (prefix + "Must have string value 'uniform' (what uniform are we mapping?)\n").c_str())) return false;
- if (!READER_CHECK(value["uniform"].IsString(), (prefix + "Value 'effect' must be a string\n").c_str())) return false;
+ if (!READER_CHECK(value.HasMember("uniform"), "%sMust have string value 'uniform' (what uniform are we mapping?)\n", prefix)) return false;
+ if (!READER_CHECK(value["uniform"].IsString(), "%sValue 'effect' must be a string\n", prefix)) return false;
return true;
}
diff --git a/src/osd/modules/render/bgfx/entryuniformreader.h b/src/osd/modules/render/bgfx/entryuniformreader.h
index 73c66269a5e..c85a2647826 100644
--- a/src/osd/modules/render/bgfx/entryuniformreader.h
+++ b/src/osd/modules/render/bgfx/entryuniformreader.h
@@ -6,16 +6,16 @@
//
//============================================================
+#ifndef MAME_RENDER_BGFX_ENTRYUNIFORMREADER_H
+#define MAME_RENDER_BGFX_ENTRYUNIFORMREADER_H
+
#pragma once
-#ifndef __DRAWBGFX_ENTRY_UNIFORM_READER__
-#define __DRAWBGFX_ENTRY_UNIFORM_READER__
+#include "statereader.h"
#include <string>
#include <map>
-#include "statereader.h"
-
class bgfx_entry_uniform;
class bgfx_slider;
class bgfx_effect;
@@ -24,10 +24,10 @@ class bgfx_parameter;
class entry_uniform_reader : public state_reader
{
public:
- static bgfx_entry_uniform* read_from_value(const Value& value, std::string prefix, bgfx_effect* effect, std::map<std::string, bgfx_slider*>& sliders, std::map<std::string, bgfx_parameter*>& params);
+ static bgfx_entry_uniform* read_from_value(const Value& value, const std::string &prefix, bgfx_effect* effect, std::map<std::string, bgfx_slider*>& sliders, std::map<std::string, bgfx_parameter*>& params);
private:
- static bool validate_parameters(const Value& value, std::string prefix);
+ static bool validate_parameters(const Value& value, const std::string &prefix);
};
-#endif // __DRAWBGFX_ENTRY_UNIFORM_READER__
+#endif // MAME_RENDER_BGFX_ENTRYUNIFORMREADER_H
diff --git a/src/osd/modules/render/bgfx/frameparameter.cpp b/src/osd/modules/render/bgfx/frameparameter.cpp
index 841d4d0d2e5..6b16fe1d5fa 100644
--- a/src/osd/modules/render/bgfx/frameparameter.cpp
+++ b/src/osd/modules/render/bgfx/frameparameter.cpp
@@ -8,8 +8,10 @@
#include "frameparameter.h"
-bgfx_frame_parameter::bgfx_frame_parameter(std::string name, parameter_type type, uint32_t period)
- : bgfx_parameter(name, type)
+#include <utility>
+
+bgfx_frame_parameter::bgfx_frame_parameter(std::string &&name, parameter_type type, uint32_t period)
+ : bgfx_parameter(std::move(name), type)
, m_current_frame(0)
, m_period(period)
{
@@ -20,7 +22,7 @@ float bgfx_frame_parameter::value()
return float(m_current_frame);
}
-void bgfx_frame_parameter::tick(double /*delta*/)
+void bgfx_frame_parameter::tick(double delta)
{
m_current_frame++;
m_current_frame %= m_period;
diff --git a/src/osd/modules/render/bgfx/frameparameter.h b/src/osd/modules/render/bgfx/frameparameter.h
index e559d13c1d8..2a1e8f6094b 100644
--- a/src/osd/modules/render/bgfx/frameparameter.h
+++ b/src/osd/modules/render/bgfx/frameparameter.h
@@ -6,22 +6,20 @@
//
//============================================================
-#pragma once
+#ifndef MAME_RENDER_BGFX_FRAMEPARAMETER_H
+#define MAME_RENDER_BGFX_FRAMEPARAMETER_H
-#ifndef __DRAWBGFX_FRAME_PARAMETER__
-#define __DRAWBGFX_FRAME_PARAMETER__
+#pragma once
-#include <bgfx/bgfx.h>
+#include "parameter.h"
+#include <cstdint>
#include <string>
-#include "parameter.h"
-
class bgfx_frame_parameter : public bgfx_parameter
{
public:
- bgfx_frame_parameter(std::string name, parameter_type type, uint32_t period);
- virtual ~bgfx_frame_parameter() { }
+ bgfx_frame_parameter(std::string &&name, parameter_type type, uint32_t period);
virtual float value() override;
virtual void tick(double delta) override;
@@ -31,4 +29,4 @@ private:
uint32_t m_period;
};
-#endif // __DRAWBGFX_FRAME_PARAMETER__
+#endif // MAME_RENDER_BGFX_FRAMEPARAMETER_H
diff --git a/src/osd/modules/render/bgfx/inputpair.cpp b/src/osd/modules/render/bgfx/inputpair.cpp
index 98d0594e27a..154252db04f 100644
--- a/src/osd/modules/render/bgfx/inputpair.cpp
+++ b/src/osd/modules/render/bgfx/inputpair.cpp
@@ -9,20 +9,20 @@
//
//============================================================
-#include "emu.h"
-#include "../frontend/mame/ui/slider.h"
-
-#include "emucore.h"
-
#include "inputpair.h"
-#include "texture.h"
-#include "target.h"
-#include "effect.h"
-#include "render.h"
-#include "uniform.h"
+
#include "chainmanager.h"
+#include "effect.h"
#include "slider.h"
#include "sliderdirtynotifier.h"
+#include "target.h"
+#include "texture.h"
+#include "uniform.h"
+
+#include "../frontend/mame/ui/slider.h"
+
+#include "util/strformat.h"
+
bgfx_input_pair::bgfx_input_pair(int index, std::string sampler, std::string texture, std::vector<std::string> available_textures, std::string selection, chain_manager& chains, uint32_t screen_index)
: m_index(index)
@@ -42,27 +42,46 @@ bgfx_input_pair::bgfx_input_pair(int index, std::string sampler, std::string tex
bgfx_input_pair::~bgfx_input_pair()
{
+ m_slider_state.reset();
}
void bgfx_input_pair::bind(bgfx_effect *effect, const int32_t screen) const
{
- assert(effect->uniform(m_sampler) != nullptr);
+ if (effect->uniform(m_sampler) == nullptr)
+ return;
+
std::string name = m_texture + std::to_string(screen);
bgfx_texture_handle_provider* provider = chains().textures().provider(name);
+ if (!provider)
+ return;
+
+ float rowpixels(provider->rowpixels());
+ float width_margin(provider->width_margin());
+ float height(provider->height());
+
bgfx_uniform *tex_size = effect->uniform("u_tex_size" + std::to_string(m_index));
- if (tex_size != nullptr)
+ if (tex_size && provider)
{
- float values[2] = { float(provider->width()), float(provider->height()) };
+ float values[2] = { rowpixels, height };
tex_size->set(values, sizeof(float) * 2);
}
- bgfx::setTexture(m_index, effect->uniform(m_sampler)->handle(), chains().textures().handle(name));
-}
+ bgfx_uniform *inv_tex_size = effect->uniform("u_inv_tex_size" + std::to_string(m_index));
+ if (inv_tex_size && provider)
+ {
+ float values[2] = { 1.0f / rowpixels, 1.0f / height };
+ inv_tex_size->set(values, sizeof(float) * 2);
+ }
-int32_t bgfx_input_pair::slider_changed(running_machine &machine, void *arg, int id, std::string *str, int32_t newval)
-{
- return texture_changed(id, str, newval);
+ bgfx_uniform *tex_bounds = effect->uniform("u_tex_bounds" + std::to_string(m_index));
+ if (tex_bounds && provider)
+ {
+ float values[4] = { width_margin / rowpixels, 0.0f, 1.0f + width_margin / rowpixels, 1.0f };
+ tex_bounds->set(values, sizeof(float) * 4);
+ }
+
+ bgfx::setTexture(m_index, effect->uniform(m_sampler)->handle(), chains().textures().handle(name));
}
int32_t bgfx_input_pair::texture_changed(int32_t id, std::string *str, int32_t newval)
@@ -91,7 +110,7 @@ int32_t bgfx_input_pair::texture_changed(int32_t id, std::string *str, int32_t n
file_name = file.substr(0, last_dot);
}
- *str = string_format("%s", file_name.c_str());
+ *str = file_name;
}
return m_current_texture;
@@ -99,25 +118,19 @@ int32_t bgfx_input_pair::texture_changed(int32_t id, std::string *str, int32_t n
void bgfx_input_pair::create_selection_slider(uint32_t screen_index)
{
- m_slider_state = make_unique_clear<slider_state>();
-
- m_slider_state->minval = 0;
- m_slider_state->defval = m_current_texture;
- m_slider_state->maxval = m_available_textures.size() - 1;
- m_slider_state->incval = 1;
+ int32_t minval = 0;
+ int32_t defval = m_current_texture;
+ int32_t maxval = m_available_textures.size() - 1;
+ int32_t incval = 1;
using namespace std::placeholders;
- m_slider_state->update = std::bind(&bgfx_input_pair::slider_changed, this, _1, _2, _3, _4, _5);
- m_slider_state->arg = this;
- m_slider_state->id = screen_index;
- m_slider_state->description = "Window " + std::to_string(chains().window_index()) + ", Screen " + std::to_string(screen_index) + " " + m_selection + ":";
-
- ui::menu_item item;
- item.text = m_slider_state->description;
- item.subtext = "";
- item.flags = 0;
- item.ref = m_slider_state.get();
- item.type = ui::menu_item_type::SLIDER;
+ m_slider_state = std::make_unique<slider_state>(
+ util::string_format("Window %1$u, Screen %1$u %3$s", chains().window_index(), screen_index, m_selection),
+ minval, defval, maxval, incval,
+ std::bind(&bgfx_input_pair::texture_changed, this, screen_index, _1, _2));
+
+ ui::menu_item item(ui::menu_item_type::SLIDER, m_slider_state.get());
+ item.set_text(m_slider_state->description);
m_selection_slider = item;
}
@@ -131,9 +144,7 @@ std::vector<ui::menu_item> bgfx_input_pair::get_slider_list()
std::vector<ui::menu_item> sliders;
if (!needs_sliders())
- {
return sliders;
- }
sliders.push_back(m_selection_slider);
diff --git a/src/osd/modules/render/bgfx/inputpair.h b/src/osd/modules/render/bgfx/inputpair.h
index fb3fc58e1f7..668d652200d 100644
--- a/src/osd/modules/render/bgfx/inputpair.h
+++ b/src/osd/modules/render/bgfx/inputpair.h
@@ -14,16 +14,17 @@
#ifndef __DRAWBGFX_INPUT_PAIR__
#define __DRAWBGFX_INPUT_PAIR__
+#include <memory>
#include <string>
+#include <vector>
#include "../frontend/mame/ui/menuitem.h"
-#include "../frontend/mame/ui/sliderchangednotifier.h"
struct slider_state;
class bgfx_effect;
class chain_manager;
-class bgfx_input_pair : public slider_changed_notifier
+class bgfx_input_pair
{
public:
bgfx_input_pair(int index, std::string sampler, std::string texture, std::vector<std::string> available_textures, std::string selection, chain_manager& chains, uint32_t screen_index);
@@ -39,7 +40,6 @@ public:
std::vector<ui::menu_item> get_slider_list();
private:
- virtual int32_t slider_changed(running_machine &machine, void *arg, int /*id*/, std::string *str, int32_t newval) override;
void create_selection_slider(uint32_t screen_index);
bool needs_sliders();
diff --git a/src/osd/modules/render/bgfx/parameter.h b/src/osd/modules/render/bgfx/parameter.h
index 2df18365a4c..baa2ff017ad 100644
--- a/src/osd/modules/render/bgfx/parameter.h
+++ b/src/osd/modules/render/bgfx/parameter.h
@@ -10,12 +10,13 @@
//
//============================================================
-#pragma once
+#ifndef MAME_RENDER_BGFX_PARAMETER_H
+#define MAME_RENDER_BGFX_PARAMETER_H
-#ifndef __DRAWBGFX_PARAMETER__
-#define __DRAWBGFX_PARAMETER__
+#pragma once
#include <string>
+#include <utility>
class bgfx_parameter
{
@@ -27,18 +28,18 @@ public:
PARAM_TIME
};
- bgfx_parameter(std::string name, parameter_type type) : m_name(name), m_type(type) { }
- virtual ~bgfx_parameter() { }
+ bgfx_parameter(std::string &&name, parameter_type type) : m_name(std::move(name)), m_type(type) { }
+ virtual ~bgfx_parameter() = default;
virtual void tick(double delta) = 0;
// Getters
virtual float value() = 0;
- std::string name() const { return m_name; }
+ const std::string &name() const { return m_name; }
protected:
std::string m_name;
parameter_type m_type;
};
-#endif // __DRAWBGFX_PARAMETER__
+#endif // MAME_RENDER_BGFX_PARAMETER_H
diff --git a/src/osd/modules/render/bgfx/paramreader.cpp b/src/osd/modules/render/bgfx/paramreader.cpp
index f24bb6a475b..0eeb5f22e84 100644
--- a/src/osd/modules/render/bgfx/paramreader.cpp
+++ b/src/osd/modules/render/bgfx/paramreader.cpp
@@ -6,15 +6,13 @@
//
//============================================================
-#include <string>
-
#include "paramreader.h"
-#include "parameter.h"
+#include "chainmanager.h"
#include "frameparameter.h"
-#include "windowparameter.h"
+#include "parameter.h"
#include "timeparameter.h"
-#include "chainmanager.h"
+#include "windowparameter.h"
const parameter_reader::string_to_enum parameter_reader::TYPE_NAMES[parameter_reader::TYPE_COUNT] = {
{ "frame", bgfx_parameter::parameter_type::PARAM_FRAME },
@@ -22,7 +20,7 @@ const parameter_reader::string_to_enum parameter_reader::TYPE_NAMES[parameter_re
{ "time", bgfx_parameter::parameter_type::PARAM_TIME }
};
-bgfx_parameter* parameter_reader::read_from_value(const Value& value, std::string prefix, chain_manager& chains)
+bgfx_parameter* parameter_reader::read_from_value(const Value& value, const std::string &prefix, chain_manager& chains)
{
if (!validate_parameters(value, prefix))
{
@@ -35,32 +33,32 @@ bgfx_parameter* parameter_reader::read_from_value(const Value& value, std::strin
if (type == bgfx_parameter::parameter_type::PARAM_FRAME)
{
uint32_t period = int(value["period"].GetDouble());
- return new bgfx_frame_parameter(name, type, period);
+ return new bgfx_frame_parameter(std::move(name), type, period);
}
else if (type == bgfx_parameter::parameter_type::PARAM_WINDOW)
{
- return new bgfx_window_parameter(name, type, chains.window_index());
+ return new bgfx_window_parameter(std::move(name), type, chains.window_index());
}
else if (type == bgfx_parameter::parameter_type::PARAM_TIME)
{
- float limit = float(value["limit"].GetDouble());
- return new bgfx_time_parameter(name, type, limit);
+ auto limit = float(value["limit"].GetDouble());
+ return new bgfx_time_parameter(std::move(name), type, limit);
}
else
{
- READER_CHECK(false, (prefix + "Unknown parameter type '" + std::string(value["type"].GetString()) + "'\n").c_str());
+ READER_CHECK(false, "%sUnknown parameter type '%s'\n", prefix, value["type"].GetString());
}
return nullptr;
}
-bool parameter_reader::validate_parameters(const Value& value, std::string prefix)
+bool parameter_reader::validate_parameters(const Value& value, const std::string &prefix)
{
- if (!READER_CHECK(value.HasMember("name"), (prefix + "Must have string value 'name'\n").c_str())) return false;
- if (!READER_CHECK(value["name"].IsString(), (prefix + "Value 'name' must be a string\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("type"), (prefix + "Must have string value 'type'\n").c_str())) return false;
- if (!READER_CHECK(value["type"].IsString(), (prefix + "Value 'type' must be a string\n").c_str())) return false;
- if (!READER_CHECK(!value.HasMember("period") || value["period"].IsNumber(), (prefix + "Value 'period' must be numeric\n").c_str())) return false;
- if (!READER_CHECK(!value.HasMember("limit") || value["limit"].IsNumber(), (prefix + "Value 'period' must be numeric\n").c_str())) return false;
+ if (!READER_CHECK(value.HasMember("name"), "%sMust have string value 'name'\n", prefix)) return false;
+ if (!READER_CHECK(value["name"].IsString(), "%sValue 'name' must be a string\n", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("type"), "%sMust have string value 'type'\n", prefix)) return false;
+ if (!READER_CHECK(value["type"].IsString(), "%sValue 'type' must be a string\n", prefix)) return false;
+ if (!READER_CHECK(!value.HasMember("period") || value["period"].IsNumber(), "%sValue 'period' must be numeric\n", prefix)) return false;
+ if (!READER_CHECK(!value.HasMember("limit") || value["limit"].IsNumber(), "%sValue 'period' must be numeric\n", prefix)) return false;
return true;
}
diff --git a/src/osd/modules/render/bgfx/paramreader.h b/src/osd/modules/render/bgfx/paramreader.h
index 013d6589cc3..bfd23b14a42 100644
--- a/src/osd/modules/render/bgfx/paramreader.h
+++ b/src/osd/modules/render/bgfx/paramreader.h
@@ -6,26 +6,28 @@
//
//============================================================
-#pragma once
+#ifndef MAME_RENDER_BGFX_PARAMREADER_H
+#define MAME_RENDER_BGFX_PARAMREADER_H
-#ifndef __DRAWBGFX_PARAM_READER__
-#define __DRAWBGFX_PARAM_READER__
+#pragma once
#include "statereader.h"
+#include <string>
+
class bgfx_parameter;
class chain_manager;
class parameter_reader : public state_reader
{
public:
- static bgfx_parameter* read_from_value(const Value& value, std::string prefix, chain_manager& chains);
+ static bgfx_parameter* read_from_value(const Value& value, const std::string &prefix, chain_manager& chains);
private:
- static bool validate_parameters(const Value& value, std::string prefix);
+ static bool validate_parameters(const Value& value, const std::string &prefix);
static const int TYPE_COUNT = 3;
static const string_to_enum TYPE_NAMES[TYPE_COUNT];
};
-#endif // __DRAWBGFX_PARAM_READER__
+#endif // MAME_RENDER_BGFX_PARAMREADER_H
diff --git a/src/osd/modules/render/bgfx/paramuniform.h b/src/osd/modules/render/bgfx/paramuniform.h
index b49fb2c7d61..5f5b69c96a6 100644
--- a/src/osd/modules/render/bgfx/paramuniform.h
+++ b/src/osd/modules/render/bgfx/paramuniform.h
@@ -6,10 +6,10 @@
//
//============================================================
-#pragma once
+#ifndef MAME_RENDER_BGFX_PARAMUNIFORM_H
+#define MAME_RENDER_BGFX_PARAMUNIFORM_H
-#ifndef __DRAWBGFX_PARAM_UNIFORM__
-#define __DRAWBGFX_PARAM_UNIFORM__
+#pragma once
#include "entryuniform.h"
@@ -26,4 +26,4 @@ private:
bgfx_parameter* m_param;
};
-#endif // __DRAWBGFX_PARAM_UNIFORM__
+#endif // MAME_RENDER_BGFX_PARAMUNIFORM_H
diff --git a/src/osd/modules/render/bgfx/paramuniformreader.cpp b/src/osd/modules/render/bgfx/paramuniformreader.cpp
index 2b613fc216c..8c5cd265195 100644
--- a/src/osd/modules/render/bgfx/paramuniformreader.cpp
+++ b/src/osd/modules/render/bgfx/paramuniformreader.cpp
@@ -9,10 +9,10 @@
#include "paramuniformreader.h"
#include "entryuniform.h"
-#include "paramuniform.h"
#include "parameter.h"
+#include "paramuniform.h"
-bgfx_entry_uniform* param_uniform_reader::read_from_value(const Value& value, std::string prefix, bgfx_uniform* uniform, std::map<std::string, bgfx_parameter*>& params)
+bgfx_entry_uniform* param_uniform_reader::read_from_value(const Value& value, const std::string &prefix, bgfx_uniform* uniform, std::map<std::string, bgfx_parameter*>& params)
{
if (!validate_parameters(value, prefix))
{
@@ -24,9 +24,9 @@ bgfx_entry_uniform* param_uniform_reader::read_from_value(const Value& value, st
return new bgfx_param_uniform(uniform, params[parameter]);
}
-bool param_uniform_reader::validate_parameters(const Value& value, std::string prefix)
+bool param_uniform_reader::validate_parameters(const Value& value, const std::string &prefix)
{
- if (!READER_CHECK(value.HasMember("parameter"), (prefix + "Must have string value 'parameter' (what parameter is being mapped?)\n").c_str())) return false;
- if (!READER_CHECK(value["parameter"].IsString(), (prefix + "Value 'parameter' must be a string\n").c_str())) return false;
+ if (!READER_CHECK(value.HasMember("parameter"), "%sMust have string value 'parameter' (what parameter is being mapped?)\n", prefix)) return false;
+ if (!READER_CHECK(value["parameter"].IsString(), "%sValue 'parameter' must be a string\n", prefix)) return false;
return true;
}
diff --git a/src/osd/modules/render/bgfx/paramuniformreader.h b/src/osd/modules/render/bgfx/paramuniformreader.h
index baf281b562b..b1ed2a87f69 100644
--- a/src/osd/modules/render/bgfx/paramuniformreader.h
+++ b/src/osd/modules/render/bgfx/paramuniformreader.h
@@ -6,15 +6,15 @@
//
//==================================================================
+#ifndef MAME_RENDER_BGFX_PARAMUNIFORMREADER_H
+#define MAME_RENDER_BGFX_PARAMUNIFORMREADER_H
+
#pragma once
-#ifndef __DRAWBGFX_PARAM_UNIFORM_READER__
-#define __DRAWBGFX_PARAM_UNIFORM_READER__
+#include "statereader.h"
-#include <string>
#include <map>
-
-#include "statereader.h"
+#include <string>
class bgfx_entry_uniform;
class bgfx_uniform;
@@ -23,10 +23,10 @@ class bgfx_parameter;
class param_uniform_reader : public state_reader
{
public:
- static bgfx_entry_uniform* read_from_value(const Value& value, std::string prefix, bgfx_uniform* uniform, std::map<std::string, bgfx_parameter*>& params);
+ static bgfx_entry_uniform* read_from_value(const Value& value, const std::string &prefix, bgfx_uniform* uniform, std::map<std::string, bgfx_parameter*>& params);
private:
- static bool validate_parameters(const Value& value, std::string prefix);
+ static bool validate_parameters(const Value& value, const std::string &prefix);
};
-#endif // __DRAWBGFX_PARAM_UNIFORM_READER__
+#endif // MAME_RENDER_BGFX_PARAMUNIFORMREADER_H
diff --git a/src/osd/modules/render/bgfx/shadermanager.cpp b/src/osd/modules/render/bgfx/shadermanager.cpp
index 7583b58dec5..282029cb96a 100644
--- a/src/osd/modules/render/bgfx/shadermanager.cpp
+++ b/src/osd/modules/render/bgfx/shadermanager.cpp
@@ -9,15 +9,17 @@
//
//============================================================
-#include <bx/math.h>
-#include <bx/readerwriter.h>
-#include <bx/file.h>
+#include "shadermanager.h"
-#include "emu.h"
+#include "emucore.h"
-#include <bgfx/bgfx.h>
+#include "osdfile.h"
+#include "modules/lib/osdobj_common.h"
+
+#include <bx/file.h>
+#include <bx/math.h>
+#include <bx/readerwriter.h>
-#include "shadermanager.h"
shader_manager::~shader_manager()
{
@@ -28,7 +30,7 @@ shader_manager::~shader_manager()
m_shaders.clear();
}
-bgfx::ShaderHandle shader_manager::shader(std::string name)
+bgfx::ShaderHandle shader_manager::get_or_load_shader(const osd_options &options, const std::string &name)
{
std::map<std::string, bgfx::ShaderHandle>::iterator iter = m_shaders.find(name);
if (iter != m_shaders.end())
@@ -36,13 +38,60 @@ bgfx::ShaderHandle shader_manager::shader(std::string name)
return iter->second;
}
- return load_shader(name);
+ bgfx::ShaderHandle handle = load_shader(options, name);
+ if (handle.idx != bgfx::kInvalidHandle)
+ {
+ m_shaders[name] = handle;
+ }
+
+ return handle;
+}
+
+bgfx::ShaderHandle shader_manager::load_shader(const osd_options &options, const std::string &name)
+{
+ std::string shader_path = make_path_string(options, name);
+ const bgfx::Memory* mem = load_mem(shader_path + name + ".bin");
+ if (mem != nullptr)
+ {
+ return bgfx::createShader(mem);
+ }
+
+ return BGFX_INVALID_HANDLE;
}
-bgfx::ShaderHandle shader_manager::load_shader(std::string name)
+bool shader_manager::is_shader_present(const osd_options &options, const std::string &name)
{
- std::string shader_path(m_options.bgfx_path());
+ std::string shader_path = make_path_string(options, name);
+ std::string file_name = shader_path + name + ".bin";
+ bx::FileReader reader;
+ bx::ErrorAssert err;
+ if (bx::open(&reader, file_name.c_str()))
+ {
+ uint32_t expected_size(bx::getSize(&reader));
+ uint8_t *data = new uint8_t[expected_size];
+ uint32_t read_size = (uint32_t)bx::read(&reader, data, expected_size, &err);
+ delete [] data;
+ bx::close(&reader);
+
+ return expected_size == read_size;
+ }
+
+ return false;
+}
+
+std::string shader_manager::make_path_string(const osd_options &options, const std::string &name)
+{
+ std::string shader_path(options.bgfx_path());
shader_path += PATH_SEPARATOR "shaders" PATH_SEPARATOR;
+
+#if defined(SDLMAME_EMSCRIPTEN)
+ // Hard-code renderer type to OpenGL ES for emscripten builds since the
+ // bgfx::getRendererType() is called here before BGFX has been
+ // initialized and therefore gives the wrong renderer type (Noop).
+ shader_path += "essl" PATH_SEPARATOR;
+ return shader_path;
+#endif
+
switch (bgfx::getRendererType())
{
case bgfx::RendererType::Noop:
@@ -79,29 +128,18 @@ bgfx::ShaderHandle shader_manager::load_shader(std::string name)
fatalerror("Unknown BGFX renderer type %d", bgfx::getRendererType());
}
shader_path += PATH_SEPARATOR;
- osd_subst_env(shader_path, shader_path);
-
- const bgfx::Memory* mem = load_mem(shader_path + name + ".bin");
- if (mem != nullptr)
- {
- bgfx::ShaderHandle handle = bgfx::createShader(mem);
-
- m_shaders[name] = handle;
-
- return handle;
- }
-
- return BGFX_INVALID_HANDLE;
+ return shader_path;
}
-const bgfx::Memory* shader_manager::load_mem(std::string name)
+const bgfx::Memory* shader_manager::load_mem(const std::string &name)
{
bx::FileReader reader;
if (bx::open(&reader, name.c_str()))
{
+ bx::ErrorAssert err;
uint32_t size(bx::getSize(&reader));
const bgfx::Memory* mem = bgfx::alloc(size + 1);
- bx::read(&reader, mem->data, size);
+ bx::read(&reader, mem->data, size, &err);
bx::close(&reader);
mem->data[mem->size - 1] = '\0';
@@ -109,7 +147,7 @@ const bgfx::Memory* shader_manager::load_mem(std::string name)
}
else
{
- printf("Unable to load shader %s\n", name.c_str());
+ osd_printf_error("Unable to load shader %s\n", name);
}
return nullptr;
}
diff --git a/src/osd/modules/render/bgfx/shadermanager.h b/src/osd/modules/render/bgfx/shadermanager.h
index bee48dcea81..12ac739d35a 100644
--- a/src/osd/modules/render/bgfx/shadermanager.h
+++ b/src/osd/modules/render/bgfx/shadermanager.h
@@ -9,33 +9,36 @@
//
//============================================================
-#pragma once
+#ifndef MAME_RENDER_BGFX_SHADERMANAGER_H
+#define MAME_RENDER_BGFX_SHADERMANAGER_H
-#ifndef __DRAWBGFX_SHADER_MANAGER__
-#define __DRAWBGFX_SHADER_MANAGER__
+#pragma once
#include <bgfx/bgfx.h>
-#include "modules/lib/osdobj_common.h"
-
#include <map>
#include <string>
-class shader_manager {
+class osd_options;
+
+
+class shader_manager
+{
public:
- shader_manager(osd_options& options) : m_options(options) { }
+ shader_manager() { }
~shader_manager();
// Getters
- bgfx::ShaderHandle shader(std::string name);
+ bgfx::ShaderHandle get_or_load_shader(const osd_options &options, const std::string &name);
+ static bgfx::ShaderHandle load_shader(const osd_options &options, const std::string &name);
+ static bool is_shader_present(const osd_options &options, const std::string &name);
private:
- bgfx::ShaderHandle load_shader(std::string name);
- static const bgfx::Memory* load_mem(std::string name);
+ static std::string make_path_string(const osd_options &options, const std::string &name);
+ static const bgfx::Memory* load_mem(const std::string &name);
- std::map<std::string, bgfx::ShaderHandle> m_shaders;
- osd_options& m_options;
+ std::map<std::string, bgfx::ShaderHandle> m_shaders;
};
-#endif // __DRAWBGFX_SHADER_MANAGER__
+#endif // MAME_RENDER_BGFX_SHADERMANAGER_H
diff --git a/src/osd/modules/render/bgfx/shaders/chains/blurs/fs_smart-blur.sc b/src/osd/modules/render/bgfx/shaders/chains/blurs/fs_smart-blur.sc
index 78229ec9c49..6ea70cb6aac 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/blurs/fs_smart-blur.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/blurs/fs_smart-blur.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_color0
/*
Hyllian Smart-Blur Shader
-
+
Copyright (C) 2011-2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -39,26 +39,26 @@ uniform vec4 SB_THRESHOLD;
bool eq(vec3 c1, vec3 c2)
{
- vec3 df = abs(c1 - c2);
- return df.r < SB_THRESHOLD.r && df.g < SB_THRESHOLD.g && df.b < SB_THRESHOLD.b;
+ vec3 df = abs(c1 - c2);
+ return df.r < SB_THRESHOLD.r && df.g < SB_THRESHOLD.g && df.b < SB_THRESHOLD.b;
}
void main()
{
- vec3 A = texture2D(s_p, v_texcoord1.xw).xyz;
- vec3 B = texture2D(s_p, v_texcoord1.yw).xyz;
- vec3 C = texture2D(s_p, v_texcoord1.zw).xyz;
- vec3 D = texture2D(s_p, v_texcoord2.xw).xyz;
- vec3 E = texture2D(s_p, v_texcoord2.yw).xyz;
- vec3 F = texture2D(s_p, v_texcoord2.zw).xyz;
- vec3 G = texture2D(s_p, v_texcoord3.xw).xyz;
- vec3 H = texture2D(s_p, v_texcoord3.yw).xyz;
- vec3 I = texture2D(s_p, v_texcoord3.zw).xyz;
+ vec3 A = texture2D(s_p, v_texcoord1.xw).xyz;
+ vec3 B = texture2D(s_p, v_texcoord1.yw).xyz;
+ vec3 C = texture2D(s_p, v_texcoord1.zw).xyz;
+ vec3 D = texture2D(s_p, v_texcoord2.xw).xyz;
+ vec3 E = texture2D(s_p, v_texcoord2.yw).xyz;
+ vec3 F = texture2D(s_p, v_texcoord2.zw).xyz;
+ vec3 G = texture2D(s_p, v_texcoord3.xw).xyz;
+ vec3 H = texture2D(s_p, v_texcoord3.yw).xyz;
+ vec3 I = texture2D(s_p, v_texcoord3.zw).xyz;
- if (eq(E,F) && eq(E,H) && eq(E,I) && eq(E,B) && eq(E,C) && eq(E,A) && eq(E,D) && eq(E,G))
- {
- E = (A + B + C + D + E + F + G + H + I) / 9.0;
- }
+ if (eq(E,F) && eq(E,H) && eq(E,I) && eq(E,B) && eq(E,C) && eq(E,A) && eq(E,D) && eq(E,G))
+ {
+ E = (A + B + C + D + E + F + G + H + I) / 9.0;
+ }
- gl_FragColor = vec4(E, 1.0);
-} \ No newline at end of file
+ gl_FragColor = vec4(E, 1.0);
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/blurs/vs_smart-blur.sc b/src/osd/modules/render/bgfx/shaders/chains/blurs/vs_smart-blur.sc
index c82d7c82bec..40b0947da38 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/blurs/vs_smart-blur.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/blurs/vs_smart-blur.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_color0
/*
Hyllian Smart-Blur Shader
-
+
Copyright (C) 2011-2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -32,10 +32,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_color0
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
vec2 ps = 1.0 / u_tex_size0.xy;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/crt-geom_common.sc b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/crt-geom_common.sc
new file mode 100644
index 00000000000..9118e42d5c8
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/crt-geom_common.sc
@@ -0,0 +1,203 @@
+// Comment the next line to disable interpolation in linear gamma (and gain speed).
+//#define LINEAR_PROCESSING
+
+// Enable 3x oversampling of the beam profile
+#define OVERSAMPLE
+
+// Use the older, purely gaussian beam profile
+#define USEGAUSSIAN
+
+// Macros.
+#define FIX(c) max(abs(c), 1e-5)
+#define PI 3.141592653589
+
+vec4 TEX2D(vec2 c)
+{
+ vec2 underscan = step(0.0,c) * step(0.0,vec2_splat(1.0)-c);
+ vec4 col = texture2D(mpass_texture, c) * vec4_splat(underscan.x*underscan.y);
+#ifdef LINEAR_PROCESSING
+ col = pow(col, vec4_splat(CRTgamma.x));
+#endif
+ return col;
+}
+
+// Enable screen curvature.
+uniform vec4 curvature;
+
+uniform vec4 spot_size;
+uniform vec4 spot_growth;
+uniform vec4 spot_growth_power;
+
+uniform vec4 u_interp;
+
+uniform vec4 aperture_strength;
+uniform vec4 aperture_brightboost;
+
+uniform vec4 CRTgamma;
+uniform vec4 monitorsRGB;
+uniform vec4 monitorgamma;
+
+uniform vec4 overscan;
+uniform vec4 aspect;
+
+uniform vec4 d;
+uniform vec4 R;
+
+uniform vec4 cornersize;
+uniform vec4 cornersmooth;
+
+float intersect(vec2 xy , vec2 sinangle, vec2 cosangle)
+{
+ float A = dot(xy,xy)+d.x*d.x;
+ float B = 2.0*(R.x*(dot(xy,sinangle)-d.x*cosangle.x*cosangle.y)-d.x*d.x);
+ float C = d.x*d.x + 2.0*R.x*d.x*cosangle.x*cosangle.y;
+ return (-B-sqrt(B*B-4.0*A*C))/(2.0*A);
+}
+
+vec2 bkwtrans(vec2 xy, vec2 sinangle, vec2 cosangle)
+{
+ float c = intersect(xy, sinangle, cosangle);
+ vec2 pt = vec2_splat(c)*xy;
+ pt -= vec2_splat(-R.x)*sinangle;
+ pt /= vec2_splat(R.x);
+ vec2 tang = sinangle/cosangle;
+ vec2 poc = pt/cosangle;
+ float A = dot(tang,tang)+1.0;
+ float B = -2.0*dot(poc,tang);
+ float C = dot(poc,poc)-1.0;
+ float a = (-B+sqrt(B*B-4.0*A*C))/(2.0*A);
+ vec2 uv = (pt-a*sinangle)/cosangle;
+ float r = FIX(R.x*acos(a));
+ return uv*r/sin(r/R.x);
+}
+
+vec2 transform(vec2 coord, vec3 stretch, vec2 sinangle, vec2 cosangle)
+{
+ coord = (coord-vec2_splat(0.5))*aspect.xy*stretch.z+stretch.xy;
+ return (bkwtrans(coord, sinangle, cosangle)/overscan.xy/aspect.xy+vec2_splat(0.5));
+}
+
+float corner(vec2 coord)
+{
+ coord = (coord - vec2_splat(0.5)) * overscan.xy + vec2_splat(0.5);
+ coord = min(coord, vec2_splat(1.0)-coord) * aspect.xy;
+ vec2 cdist = vec2_splat(cornersize.x);
+ coord = (cdist - min(coord,cdist));
+ float dist = sqrt(dot(coord,coord));
+ return clamp((max(cdist.x,1e-3)-dist)*cornersmooth.x,0.0, 1.0);
+}
+
+// Calculate the influence of a scanline on the current pixel.
+//
+// 'distance' is the distance in texture coordinates from the current
+// pixel to the scanline in question.
+// 'color' is the colour of the scanline at the horizontal location of
+// the current pixel.
+vec4 scanlineWeights(float distance, vec4 color)
+{
+ // "wid" controls the width of the scanline beam, for each RGB channel
+ // The "weights" lines basically specify the formula that gives
+ // you the profile of the beam, i.e. the intensity as
+ // a function of distance from the vertical center of the
+ // scanline. In this case, it is gaussian if width=2, and
+ // becomes nongaussian for larger widths. Ideally this should
+ // be normalized so that the integral across the beam is
+ // independent of its width. That is, for a narrower beam
+ // "weights" should have a higher peak at the center of the
+ // scanline than for a wider beam.
+#ifdef USEGAUSSIAN
+ vec4 wid = spot_size.x + spot_growth.x * pow(color, vec4_splat(spot_growth_power.x));
+ vec4 weights = vec4(distance / wid);
+ float maxwid = spot_size.x + spot_growth.x;
+ float norm = maxwid / ( 1.0 + exp(-1.0/(maxwid*maxwid)) );
+ return norm * exp(-weights * weights) / wid;
+#else
+ vec4 wid = 2.0 + 2.0 * pow(color, vec4_splat(4.0));
+ vec4 weights = vec4_splat(distance / 0.3);
+ return 1.4 * exp(-pow(weights * inversesqrt(0.5 * wid), wid)) / (0.6 + 0.2 * wid);
+#endif
+}
+
+vec4 cubic(vec4 x, float B, float C)
+{
+ // https://en.wikipedia.org/wiki/Mitchell%E2%80%93Netravali_filters
+ vec2 a = x.yz; // components in [0,1]
+ vec2 b = x.xw; // components in [1,2]
+ vec2 a2 = a*a;
+ vec2 b2 = b*b;
+ a = (2.0-1.5*B-1.0*C)*a*a2 + (-3.0+2.0*B+C)*a2 + (1.0-(1.0/3.0)*B);
+ b = ((-1.0/6.0)*B-C)*b*b2 + (B+5.0*C)*b2 + (-2.0*B-8.0*C)*b + ((4.0/3.0)*B+4.0*C);
+ return vec4(b.x,a.x,a.y,b.y);
+}
+
+vec4 x_coeffs(vec4 x, float pos_x)
+{
+ if (u_interp.x < 0.5) { // box
+ float wid = length(vec2(dFdx(pos_x),dFdy(pos_x)));
+ float dx = clamp((0.5 + 0.5*wid - x.y)/wid, 0.0, 1.0);
+ return vec4(0.0,dx,1.0-dx,0.0);
+ } else if (u_interp.x < 1.5) { // linear
+ return vec4(0.0, 1.0-x.y, 1.0-x.z, 0.0);
+ } else if (u_interp.x < 2.5) { // Lanczos
+ // Prevent division by zero.
+ vec4 coeffs = FIX(PI * x);
+ // Lanczos2 kernel.
+ coeffs = 2.0 * sin(coeffs) * sin(coeffs / 2.0) / (coeffs * coeffs);
+ // Normalize.
+ coeffs /= dot(coeffs, vec4_splat(1.0));
+ return coeffs;
+ } else if (u_interp.x < 3.5) { // Catmull-Rom
+ return cubic(x,0.0,0.5);
+ } else if (u_interp.x < 4.5) { // Mitchell-Netravali
+ return cubic(x,1.0/3.0,1.0/3.0);
+ } else /*if (u_interp.x < 5.5)*/ { // B-spline
+ return cubic(x,1.0,0.0);
+ }
+}
+
+vec4 sample_scanline(vec2 xy, vec4 coeffs, float onex)
+{
+ // Calculate the effective colour of the given
+ // scanline at the horizontal location of the current pixel,
+ // using the Lanczos coefficients.
+ vec4 col = clamp(TEX2D(xy + vec2(-onex, 0.0))*coeffs.x +
+ TEX2D(xy)*coeffs.y +
+ TEX2D(xy +vec2(onex, 0.0))*coeffs.z +
+ TEX2D(xy + vec2(2.0 * onex, 0.0))*coeffs.w , 0.0, 1.0);
+ return col;
+}
+
+vec3 apply_shadow_mask(vec2 coord, vec3 col)
+{
+ vec2 xy = coord * u_quad_dims.xy / u_tex_size1.xy;
+ vec4 mask = texture2D(mask_texture, xy);
+ // count of total bright pixels is encoded in the mask's alpha channel
+ float nbright = 255.0 - 255.0*mask.a;
+ // fraction of bright pixels in the mask
+ float fbright = nbright / ( u_tex_size1.x * u_tex_size1.y );
+ // average darkening factor of the mask
+ float aperture_average = mix(1.0-aperture_strength.x*(1.0-aperture_brightboost.x), 1.0, fbright);
+ // colour of dark mask pixels
+ vec3 clow = vec3_splat(1.0-aperture_strength.x) * col + vec3_splat(aperture_strength.x*(aperture_brightboost.x)) * col * col;
+ float ifbright = 1.0 / fbright;
+ // colour of bright mask pixels
+ vec3 chi = vec3_splat(ifbright*aperture_average) * col - vec3_splat(ifbright - 1.0) * clow;
+ return mix(clow,chi,mask.rgb); // mask texture selects dark vs bright
+}
+
+vec3 linear_to_sRGB(vec3 col)
+{
+ // only applies the gamma ramp; does not adjust the primaries
+ vec3 linear_ramp = vec3(lessThan(col, vec3_splat(0.0031308)));
+ vec3 clin = col * vec3_splat(12.92);
+ vec3 cpow = pow(col, vec3_splat(1.0/2.4)) * vec3_splat(1.055) - vec3_splat(0.055);
+ return mix(cpow, clin, linear_ramp);
+}
+
+vec3 linear_to_output(vec3 col)
+{
+ if (monitorsRGB.x > 0.5)
+ return linear_to_sRGB(col);
+ else
+ return pow(col, vec3_splat(1.0 / monitorgamma.x));
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_crt-geom-deluxe.sc b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_crt-geom-deluxe.sc
index c5cfcbf2cdc..5b8a633a642 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_crt-geom-deluxe.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_crt-geom-deluxe.sc
@@ -12,120 +12,33 @@ $input v_sinangle, v_cosangle, v_stretch, v_one, v_texCoord
#include "common.sh"
-// Comment the next line to disable interpolation in linear gamma (and gain speed).
-//#define LINEAR_PROCESSING
-
-// Enable 3x oversampling of the beam profile
-#define OVERSAMPLE
-
-// Use the older, purely gaussian beam profile
-#define USEGAUSSIAN
-
-// Macros.
-#define FIX(c) max(abs(c), 1e-5)
-#define PI 3.141592653589
-
SAMPLER2D(mpass_texture, 0);
SAMPLER2D(mask_texture, 1);
SAMPLER2D(blur_texture, 2);
-
-#ifdef LINEAR_PROCESSING
-# define TEX2D(c) pow(texture2D(mpass_texture, (c)), vec4(CRTgamma))
-#else
-# define TEX2D(c) texture2D(mpass_texture, (c))
-#endif
-
-// Enable screen curvature.
-uniform vec4 curvature;
+SAMPLER2D(mipmap_texture, 3);
uniform vec4 u_tex_size0;
uniform vec4 u_tex_size1;
uniform vec4 u_quad_dims;
-uniform vec4 aperture_strength;
-
-uniform vec4 CRTgamma;
-uniform vec4 monitorgamma;
-
-uniform vec4 overscan;
-uniform vec4 aspect;
-
-uniform vec4 d;
-uniform vec4 R;
-
-uniform vec4 cornersize;
-uniform vec4 cornersmooth;
+#include "crt-geom_common.sc"
uniform vec4 halation;
+uniform vec4 rasterbloom;
-float intersect(vec2 xy , vec2 sinangle, vec2 cosangle)
-{
- float A = dot(xy,xy)+d.x*d.x;
- float B = 2.0*(R.x*(dot(xy,sinangle)-d.x*cosangle.x*cosangle.y)-d.x*d.x);
- float C = d.x*d.x + 2.0*R.x*d.x*cosangle.x*cosangle.y;
- return (-B-sqrt(B*B-4.0*A*C))/(2.0*A);
-}
-
-vec2 bkwtrans(vec2 xy, vec2 sinangle, vec2 cosangle)
-{
- float c = intersect(xy, sinangle, cosangle);
- vec2 pt = vec2_splat(c)*xy;
- pt -= vec2_splat(-R.x)*sinangle;
- pt /= vec2_splat(R.x);
- vec2 tang = sinangle/cosangle;
- vec2 poc = pt/cosangle;
- float A = dot(tang,tang)+1.0;
- float B = -2.0*dot(poc,tang);
- float C = dot(poc,poc)-1.0;
- float a = (-B+sqrt(B*B-4.0*A*C))/(2.0*A);
- vec2 uv = (pt-a*sinangle)/cosangle;
- float r = FIX(R.x*acos(a));
- return uv*r/sin(r/R.x);
-}
+uniform vec4 blurwidth;
-vec2 transform(vec2 coord, vec3 stretch, vec2 sinangle, vec2 cosangle)
+vec4 texblur(vec2 c)
{
- coord = (coord-vec2_splat(0.5))*aspect.xy*stretch.z+stretch.xy;
- return (bkwtrans(coord, sinangle, cosangle)/overscan.xy/aspect.xy+vec2_splat(0.5));
-}
-
-float corner(vec2 coord)
-{
- coord = (coord - vec2_splat(0.5)) * overscan.xy + vec2_splat(0.5);
- coord = min(coord, vec2_splat(1.0)-coord) * aspect.xy;
- vec2 cdist = vec2_splat(cornersize.x);
- coord = (cdist - min(coord,cdist));
- float dist = sqrt(dot(coord,coord));
- return clamp((max(cdist.x,1e-3)-dist)*cornersmooth.x,0.0, 1.0);
-}
-
-// Calculate the influence of a scanline on the current pixel.
-//
-// 'distance' is the distance in texture coordinates from the current
-// pixel to the scanline in question.
-// 'color' is the colour of the scanline at the horizontal location of
-// the current pixel.
-vec4 scanlineWeights(float distance, vec4 color)
-{
- // "wid" controls the width of the scanline beam, for each RGB channel
- // The "weights" lines basically specify the formula that gives
- // you the profile of the beam, i.e. the intensity as
- // a function of distance from the vertical center of the
- // scanline. In this case, it is gaussian if width=2, and
- // becomes nongaussian for larger widths. Ideally this should
- // be normalized so that the integral across the beam is
- // independent of its width. That is, for a narrower beam
- // "weights" should have a higher peak at the center of the
- // scanline than for a wider beam.
-#ifdef USEGAUSSIAN
- vec4 wid = 0.3 + 0.1 * pow(color, vec4_splat(3.0));
- vec4 weights = vec4(distance / wid);
- return 0.4 * exp(-weights * weights) / wid;
-#else
- vec4 wid = 2.0 + 2.0 * pow(color, vec4_splat(4.0));
- vec4 weights = vec4_splat(distance / 0.3);
- return 1.4 * exp(-pow(weights * inversesqrt(0.5 * wid), wid)) / (0.6 + 0.2 * wid);
-#endif
+ vec4 col = pow(texture2D(blur_texture,c), vec4(vec3_splat(CRTgamma.x),1.0));
+ // taper the blur texture outside its border with a gaussian
+ float w = blurwidth.x / 320.0;
+ c = min(c, vec2_splat(1.0)-c) * aspect.xy * vec2_splat(1.0/w);
+ vec2 e2c = exp(-c*c);
+ // approximation of erf gives smooth step
+ // (convolution of gaussian with step)
+ c = (step(0.0,c)-vec2_splat(0.5)) * sqrt(vec2_splat(1.0)-e2c) * (vec2_splat(1.0) + vec2_splat(0.1749)*e2c) + vec2_splat(0.5);
+ return col * vec4_splat( c.x * c.y );
}
void main()
@@ -136,6 +49,10 @@ void main()
// | | | | |
// -------------------------------
// | | | | |
+ // | 00 | 10 | 20 | 30 | <-- previous scanline
+ // | | | | |
+ // -------------------------------
+ // | | | | |
// | 01 | 11 | 21 | 31 | <-- current scanline
// | | @ | | |
// -------------------------------
@@ -147,9 +64,10 @@ void main()
//
// Each character-cell represents a pixel on the output
// surface, "@" represents the current pixel (always somewhere
- // in the bottom half of the current scan-line, or the top-half
- // of the next scanline). The grid of lines represents the
+ // in the current scan-line). The grid of lines represents the
// edges of the texels of the underlying texture.
+ // The "deluxe" shader includes contributions from the
+ // previous, current, and next scanlines.
// Texture coordinates of the texel containing the active pixel.
vec2 xy;
@@ -157,79 +75,69 @@ void main()
xy = transform(v_texCoord, v_stretch, v_sinangle, v_cosangle);
else
xy = (v_texCoord-vec2_splat(0.5))/overscan.xy+vec2_splat(0.5);
- vec2 xy0 = xy;
float cval = corner(xy);
+ // extract average brightness from the mipmap texture
+ float avgbright = dot(texture2D(mipmap_texture,vec2(1.0,1.0)).rgb,vec3_splat(1.0))/3.0;
+ float rbloom = 1.0 - rasterbloom.x * ( avgbright - 0.5 );
+ // expand the screen when average brightness is higher
+ xy = (xy - vec2_splat(0.5)) * rbloom + vec2_splat(0.5);
+ vec2 xy0 = xy;
// Of all the pixels that are mapped onto the texel we are
// currently rendering, which pixel are we currently rendering?
- vec2 ratio_scale = xy * u_tex_size0.xy - vec2_splat(0.5);
-
+ vec2 ratio_scale = xy * u_tex_size0.xy - vec2(0.5,0.0);
+
#ifdef OVERSAMPLE
float filter = fwidth(ratio_scale.y);
#endif
- vec2 uv_ratio = fract(ratio_scale);
+ vec2 uv_ratio = fract(ratio_scale) - vec2(0.0,0.5);
// Snap to the center of the underlying texel.
xy = (floor(ratio_scale) + vec2_splat(0.5)) / u_tex_size0.xy;
- // Calculate Lanczos scaling coefficients describing the effect
+ // Calculate scaling coefficients describing the effect
// of various neighbour texels in a scanline on the current
// pixel.
- vec4 coeffs = PI * vec4(1.0 + uv_ratio.x, uv_ratio.x, 1.0 - uv_ratio.x, 2.0 - uv_ratio.x);
-
- // Prevent division by zero.
- coeffs = FIX(coeffs);
-
- // Lanczos2 kernel.
- coeffs = 2.0 * sin(coeffs) * sin(coeffs / 2.0) / (coeffs * coeffs);
-
- // Normalize.
- coeffs /= dot(coeffs, vec4_splat(1.0));
-
- // Calculate the effective colour of the current and next
- // scanlines at the horizontal location of the current pixel,
- // using the Lanczos coefficients above.
- vec4 col = clamp(TEX2D(xy + vec2(-v_one.x, 0.0))*coeffs.x +
- TEX2D(xy)*coeffs.y +
- TEX2D(xy +vec2(v_one.x, 0.0))*coeffs.z +
- TEX2D(xy + vec2(2.0 * v_one.x, 0.0))*coeffs.w , 0.0, 1.0);
-
- vec4 col2 = clamp(TEX2D(xy + vec2(-v_one.x, v_one.y))*coeffs.x +
- TEX2D(xy + vec2(0.0, v_one.y))*coeffs.y +
- TEX2D(xy + v_one)*coeffs.z +
- TEX2D(xy + vec2(2.0 * v_one.x, v_one.y))*coeffs.w , 0.0, 1.0);
+ vec4 coeffs = x_coeffs(vec4(1.0 + uv_ratio.x, uv_ratio.x, 1.0 - uv_ratio.x, 2.0 - uv_ratio.x), ratio_scale.x);
+ vec4 col = sample_scanline(xy, coeffs, v_one.x);
+ vec4 col_prev = sample_scanline(xy + vec2(0.0,-v_one.y), coeffs, v_one.x);
+ vec4 col_next = sample_scanline(xy + vec2(0.0, v_one.y), coeffs, v_one.x);
#ifndef LINEAR_PROCESSING
col = pow(col , vec4_splat(CRTgamma.x));
- col2 = pow(col2, vec4_splat(CRTgamma.x));
+ col_prev = pow(col_prev, vec4_splat(CRTgamma.x));
+ col_next = pow(col_next, vec4_splat(CRTgamma.x));
#endif
// Calculate the influence of the current and next scanlines on
// the current pixel.
vec4 weights = scanlineWeights(uv_ratio.y, col);
- vec4 weights2 = scanlineWeights(1.0 - uv_ratio.y, col2);
+ vec4 weights_prev = scanlineWeights(uv_ratio.y + 1.0, col_prev);
+ vec4 weights_next = scanlineWeights(uv_ratio.y - 1.0, col_next);
#ifdef OVERSAMPLE
uv_ratio.y =uv_ratio.y+1.0/3.0*filter;
weights = (weights+scanlineWeights(uv_ratio.y, col))/3.0;
- weights2=(weights2+scanlineWeights(abs(1.0-uv_ratio.y), col2))/3.0;
+ weights_prev=(weights_prev+scanlineWeights(uv_ratio.y+1.0, col_prev))/3.0;
+ weights_next=(weights_next+scanlineWeights(uv_ratio.y-1.0, col_next))/3.0;
uv_ratio.y =uv_ratio.y-2.0/3.0*filter;
- weights=weights+scanlineWeights(abs(uv_ratio.y), col)/3.0;
- weights2=weights2+scanlineWeights(abs(1.0-uv_ratio.y), col2)/3.0;
+ weights=weights+scanlineWeights(uv_ratio.y, col)/3.0;
+ weights_prev=weights_prev+scanlineWeights(uv_ratio.y+1.0, col_prev)/3.0;
+ weights_next=weights_next+scanlineWeights(uv_ratio.y-1.0, col_next)/3.0;
#endif
- vec3 mul_res = (col * weights + col2 * weights2).rgb;
+ vec4 mul_res = col * weights + col_prev * weights_prev + col_next * weights_next;
// halation and corners
- vec3 blur = pow(texture2D(blur_texture,xy0).rgb, vec3_splat(CRTgamma.x));
- mul_res = mix(mul_res, blur, halation.x) * vec3_splat(cval);
-
- // Convert the image gamma for display on our output device.
- mul_res = pow(mul_res, vec3_splat(1.0 / monitorgamma.x));
+ vec4 blur = texblur(xy0);
+ // include factor of rbloom:
+ // (probably imperceptible) brightness reduction when raster grows
+ mul_res = mix(mul_res, blur, halation.x) * vec4_splat(cval*rbloom);
// Shadow mask
- xy = v_texCoord.xy * u_quad_dims.xy / u_tex_size1.xy;
- vec3 mask = texture2D(mask_texture, xy).rgb;
- mask = mix(vec3_splat(1.0), mask, aperture_strength.x);
-
- gl_FragColor = vec4(mul_res*mask, col.a);
+ vec3 cout = apply_shadow_mask(v_texCoord.xy, mul_res.rgb);
+
+ // Convert the image gamma for display on our output device.
+ cout = linear_to_output(cout);
+
+ gl_FragColor = vec4(cout,1.0);
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_crt-geom.sc b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_crt-geom.sc
index 919ba46d0ab..5226a9999cc 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_crt-geom.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_crt-geom.sc
@@ -12,216 +12,91 @@ $input v_sinangle, v_cosangle, v_stretch, v_one, v_texCoord
#include "common.sh"
-// Comment the next line to disable interpolation in linear gamma (and gain speed).
-//#define LINEAR_PROCESSING
-
-// Enable 3x oversampling of the beam profile
-#define OVERSAMPLE
-
-// Use the older, purely gaussian beam profile
-#define USEGAUSSIAN
-
-// Macros.
-#define FIX(c) max(abs(c), 1e-5)
-#define PI 3.141592653589
-
SAMPLER2D(mpass_texture, 0);
SAMPLER2D(mask_texture, 1);
-#ifdef LINEAR_PROCESSING
-# define TEX2D(c) pow(texture2D(mpass_texture, (c)), vec4(CRTgamma))
-#else
-# define TEX2D(c) texture2D(mpass_texture, (c))
-#endif
-
-// Enable screen curvature.
-uniform vec4 curvature;
uniform vec4 u_tex_size0;
uniform vec4 u_tex_size1;
uniform vec4 u_quad_dims;
-uniform vec4 aperture_strength;
-
-uniform vec4 CRTgamma;
-uniform vec4 monitorgamma;
-
-uniform vec4 overscan;
-uniform vec4 aspect;
+#include "crt-geom_common.sc"
-uniform vec4 d;
-uniform vec4 R;
-uniform vec4 cornersize;
-uniform vec4 cornersmooth;
-
-float intersect(vec2 xy , vec2 sinangle, vec2 cosangle)
+void main()
{
- float A = dot(xy,xy)+d.x*d.x;
- float B = 2.0*(R.x*(dot(xy,sinangle)-d.x*cosangle.x*cosangle.y)-d.x*d.x);
- float C = d.x*d.x + 2.0*R.x*d.x*cosangle.x*cosangle.y;
- return (-B-sqrt(B*B-4.0*A*C))/(2.0*A);
-}
+ // Here's a helpful diagram to keep in mind while trying to
+ // understand the code:
+ //
+ // | | | | |
+ // -------------------------------
+ // | | | | |
+ // | 01 | 11 | 21 | 31 | <-- current scanline
+ // | | @ | | |
+ // -------------------------------
+ // | | | | |
+ // | 02 | 12 | 22 | 32 | <-- next scanline
+ // | | | | |
+ // -------------------------------
+ // | | | | |
+ //
+ // Each character-cell represents a pixel on the output
+ // surface, "@" represents the current pixel (always somewhere
+ // in the bottom half of the current scan-line, or the top-half
+ // of the next scanline). The grid of lines represents the
+ // edges of the texels of the underlying texture.
+
+ // Texture coordinates of the texel containing the active pixel.
+ vec2 xy;
+ if (curvature.x > 0.5)
+ xy = transform(v_texCoord, v_stretch, v_sinangle, v_cosangle);
+ else
+ xy = (v_texCoord-vec2_splat(0.5))/overscan.xy+vec2_splat(0.5);
+ float cval = corner(xy);
+
+ // Of all the pixels that are mapped onto the texel we are
+ // currently rendering, which pixel are we currently rendering?
+ vec2 ratio_scale = xy * u_tex_size0.xy - vec2_splat(0.5);
-vec2 bkwtrans(vec2 xy, vec2 sinangle, vec2 cosangle)
-{
- float c = intersect(xy, sinangle, cosangle);
- vec2 pt = vec2_splat(c)*xy;
- pt -= vec2_splat(-R.x)*sinangle;
- pt /= vec2_splat(R.x);
- vec2 tang = sinangle/cosangle;
- vec2 poc = pt/cosangle;
- float A = dot(tang,tang)+1.0;
- float B = -2.0*dot(poc,tang);
- float C = dot(poc,poc)-1.0;
- float a = (-B+sqrt(B*B-4.0*A*C))/(2.0*A);
- vec2 uv = (pt-a*sinangle)/cosangle;
- float r = FIX(R.x*acos(a));
- return uv*r/sin(r/R.x);
-}
+#ifdef OVERSAMPLE
+ float filter = fwidth(ratio_scale.y);
+#endif
+ vec2 uv_ratio = fract(ratio_scale);
-vec2 transform(vec2 coord, vec3 stretch, vec2 sinangle, vec2 cosangle)
-{
- coord = (coord-vec2_splat(0.5))*aspect.xy*stretch.z+stretch.xy;
- return (bkwtrans(coord, sinangle, cosangle)/overscan.xy/aspect.xy+vec2_splat(0.5));
-}
+ // Snap to the center of the underlying texel.
+ xy = (floor(ratio_scale) + vec2_splat(0.5)) / u_tex_size0.xy;
-float corner(vec2 coord)
-{
- coord = (coord - vec2_splat(0.5)) * overscan.xy + vec2_splat(0.5);
- coord = min(coord, vec2_splat(1.0)-coord) * aspect.xy;
- vec2 cdist = vec2_splat(cornersize.x);
- coord = (cdist - min(coord,cdist));
- float dist = sqrt(dot(coord,coord));
- return clamp((max(cdist.x,1e-3)-dist)*cornersmooth.x,0.0, 1.0);
-}
+ // Calculate scaling coefficients describing the effect
+ // of various neighbour texels in a scanline on the current
+ // pixel.
+ vec4 coeffs = x_coeffs(vec4(1.0 + uv_ratio.x, uv_ratio.x, 1.0 - uv_ratio.x, 2.0 - uv_ratio.x), ratio_scale.x);
-// Calculate the influence of a scanline on the current pixel.
-//
-// 'distance' is the distance in texture coordinates from the current
-// pixel to the scanline in question.
-// 'color' is the colour of the scanline at the horizontal location of
-// the current pixel.
-vec4 scanlineWeights(float distance, vec4 color)
-{
- // "wid" controls the width of the scanline beam, for each RGB channel
- // The "weights" lines basically specify the formula that gives
- // you the profile of the beam, i.e. the intensity as
- // a function of distance from the vertical center of the
- // scanline. In this case, it is gaussian if width=2, and
- // becomes nongaussian for larger widths. Ideally this should
- // be normalized so that the integral across the beam is
- // independent of its width. That is, for a narrower beam
- // "weights" should have a higher peak at the center of the
- // scanline than for a wider beam.
-#ifdef USEGAUSSIAN
- vec4 wid = 0.3 + 0.1 * pow(color, vec4_splat(3.0));
- vec4 weights = vec4(distance / wid);
- return 0.4 * exp(-weights * weights) / wid;
-#else
- vec4 wid = 2.0 + 2.0 * pow(color, vec4_splat(4.0));
- vec4 weights = vec4_splat(distance / 0.3);
- return 1.4 * exp(-pow(weights * inversesqrt(0.5 * wid), wid)) / (0.6 + 0.2 * wid);
+ vec4 col = sample_scanline(xy, coeffs, v_one.x);
+ vec4 col2 = sample_scanline(xy + vec2(0.0, v_one.y), coeffs, v_one.x);
+
+#ifndef LINEAR_PROCESSING
+ col = pow(col , vec4_splat(CRTgamma.x));
+ col2 = pow(col2, vec4_splat(CRTgamma.x));
#endif
-}
-void main()
-{
- // Here's a helpful diagram to keep in mind while trying to
- // understand the code:
- //
- // | | | | |
- // -------------------------------
- // | | | | |
- // | 01 | 11 | 21 | 31 | <-- current scanline
- // | | @ | | |
- // -------------------------------
- // | | | | |
- // | 02 | 12 | 22 | 32 | <-- next scanline
- // | | | | |
- // -------------------------------
- // | | | | |
- //
- // Each character-cell represents a pixel on the output
- // surface, "@" represents the current pixel (always somewhere
- // in the bottom half of the current scan-line, or the top-half
- // of the next scanline). The grid of lines represents the
- // edges of the texels of the underlying texture.
-
- // Texture coordinates of the texel containing the active pixel.
- vec2 xy;
- if (curvature.x > 0.5)
- xy = transform(v_texCoord, v_stretch, v_sinangle, v_cosangle);
- else
- xy = (v_texCoord-vec2_splat(0.5))/overscan.xy+vec2_splat(0.5);
- float cval = corner(xy);
-
- // Of all the pixels that are mapped onto the texel we are
- // currently rendering, which pixel are we currently rendering?
- vec2 ratio_scale = xy * u_tex_size0.xy - vec2_splat(0.5);
-
+ // Calculate the influence of the current and next scanlines on
+ // the current pixel.
+ vec4 weights = scanlineWeights(uv_ratio.y, col);
+ vec4 weights2 = scanlineWeights(1.0 - uv_ratio.y, col2);
#ifdef OVERSAMPLE
- float filter = fwidth(ratio_scale.y);
+ uv_ratio.y =uv_ratio.y+1.0/3.0*filter;
+ weights = (weights+scanlineWeights(uv_ratio.y, col))/3.0;
+ weights2=(weights2+scanlineWeights(abs(1.0-uv_ratio.y), col2))/3.0;
+ uv_ratio.y =uv_ratio.y-2.0/3.0*filter;
+ weights=weights+scanlineWeights(abs(uv_ratio.y), col)/3.0;
+ weights2=weights2+scanlineWeights(abs(1.0-uv_ratio.y), col2)/3.0;
#endif
- vec2 uv_ratio = fract(ratio_scale);
-
- // Snap to the center of the underlying texel.
- xy = (floor(ratio_scale) + vec2_splat(0.5)) / u_tex_size0.xy;
-
- // Calculate Lanczos scaling coefficients describing the effect
- // of various neighbour texels in a scanline on the current
- // pixel.
- vec4 coeffs = PI * vec4(1.0 + uv_ratio.x, uv_ratio.x, 1.0 - uv_ratio.x, 2.0 - uv_ratio.x);
-
- // Prevent division by zero.
- coeffs = FIX(coeffs);
-
- // Lanczos2 kernel.
- coeffs = 2.0 * sin(coeffs) * sin(coeffs / 2.0) / (coeffs * coeffs);
-
- // Normalize.
- coeffs /= dot(coeffs, vec4_splat(1.0));
-
- // Calculate the effective colour of the current and next
- // scanlines at the horizontal location of the current pixel,
- // using the Lanczos coefficients above.
- vec4 col = clamp(TEX2D(xy + vec2(-v_one.x, 0.0))*coeffs.x +
- TEX2D(xy)*coeffs.y +
- TEX2D(xy +vec2(v_one.x, 0.0))*coeffs.z +
- TEX2D(xy + vec2(2.0 * v_one.x, 0.0))*coeffs.w , 0.0, 1.0);
-
- vec4 col2 = clamp(TEX2D(xy + vec2(-v_one.x, v_one.y))*coeffs.x +
- TEX2D(xy + vec2(0.0, v_one.y))*coeffs.y +
- TEX2D(xy + v_one)*coeffs.z +
- TEX2D(xy + vec2(2.0 * v_one.x, v_one.y))*coeffs.w , 0.0, 1.0);
+ vec4 mul_res = col * weights + col2 * weights2 * vec4_splat(cval);
+ // Shadow mask
+ vec3 cout = apply_shadow_mask(v_texCoord.xy, mul_res.rgb);
-#ifndef LINEAR_PROCESSING
- col = pow(col , vec4_splat(CRTgamma.x));
- col2 = pow(col2, vec4_splat(CRTgamma.x));
-#endif
+ // Convert the image gamma for display on our output device.
+ cout = linear_to_output(cout);
- // Calculate the influence of the current and next scanlines on
- // the current pixel.
- vec4 weights = scanlineWeights(uv_ratio.y, col);
- vec4 weights2 = scanlineWeights(1.0 - uv_ratio.y, col2);
-#ifdef OVERSAMPLE
- uv_ratio.y =uv_ratio.y+1.0/3.0*filter;
- weights = (weights+scanlineWeights(uv_ratio.y, col))/3.0;
- weights2=(weights2+scanlineWeights(abs(1.0-uv_ratio.y), col2))/3.0;
- uv_ratio.y =uv_ratio.y-2.0/3.0*filter;
- weights=weights+scanlineWeights(abs(uv_ratio.y), col)/3.0;
- weights2=weights2+scanlineWeights(abs(1.0-uv_ratio.y), col2)/3.0;
-#endif
- vec3 mul_res = (col * weights + col2 * weights2).rgb * vec3_splat(cval);
-
- // Convert the image gamma for display on our output device.
- mul_res = pow(mul_res, vec3_splat(1.0 / monitorgamma.x));
-
- // Color the texel.
-
- xy = v_texCoord.xy * u_quad_dims.xy / u_tex_size1.xy;
- vec3 mask = texture2D(mask_texture, xy).rgb;
- mask = mix(vec3_splat(1.0), mask, aperture_strength.x);
-
- gl_FragColor = vec4(mul_res*mask, col.a);
+ gl_FragColor = vec4(cout,mul_res.a);
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_gaussx.sc b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_gaussx.sc
index f45d1d5df81..6290ae330eb 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_gaussx.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_gaussx.sc
@@ -1,4 +1,4 @@
-$input v_texCoord, v_coeffs
+$input v_texCoord, v_coeffs, v_coeffs2
#include "common.sh"
@@ -6,24 +6,33 @@ uniform vec4 u_gamma;
uniform vec4 u_tex_size0;
SAMPLER2D(s_tex, 0);
-#define TEX2D(v) pow(texture2D(s_tex, v).rgb, vec3_splat(u_gamma.x))
+#define TEX2D(v) pow(texture2D(s_tex, v), vec4(vec3_splat(u_gamma.x), 1.0))
void main()
{
- vec3 sum = vec3_splat(0.0);
+ vec4 sum = vec4_splat(0.0);
float onex = 1.0/u_tex_size0.x;
- sum += TEX2D(v_texCoord + vec2(-4.0 * onex, 0.0)) * vec3_splat(v_coeffs.w);
- sum += TEX2D(v_texCoord + vec2(-3.0 * onex, 0.0)) * vec3_splat(v_coeffs.z);
- sum += TEX2D(v_texCoord + vec2(-2.0 * onex, 0.0)) * vec3_splat(v_coeffs.y);
- sum += TEX2D(v_texCoord + vec2(-1.0 * onex, 0.0)) * vec3_splat(v_coeffs.x);
+ sum += TEX2D(v_texCoord + vec2(-8.0 * onex, 0.0)) * vec4_splat(v_coeffs2.w);
+ sum += TEX2D(v_texCoord + vec2(-7.0 * onex, 0.0)) * vec4_splat(v_coeffs2.z);
+ sum += TEX2D(v_texCoord + vec2(-6.0 * onex, 0.0)) * vec4_splat(v_coeffs2.y);
+ sum += TEX2D(v_texCoord + vec2(-5.0 * onex, 0.0)) * vec4_splat(v_coeffs2.x);
+ sum += TEX2D(v_texCoord + vec2(-4.0 * onex, 0.0)) * vec4_splat(v_coeffs.w);
+ sum += TEX2D(v_texCoord + vec2(-3.0 * onex, 0.0)) * vec4_splat(v_coeffs.z);
+ sum += TEX2D(v_texCoord + vec2(-2.0 * onex, 0.0)) * vec4_splat(v_coeffs.y);
+ sum += TEX2D(v_texCoord + vec2(-1.0 * onex, 0.0)) * vec4_splat(v_coeffs.x);
sum += TEX2D(v_texCoord);
- sum += TEX2D(v_texCoord + vec2(+1.0 * onex, 0.0)) * vec3_splat(v_coeffs.x);
- sum += TEX2D(v_texCoord + vec2(+2.0 * onex, 0.0)) * vec3_splat(v_coeffs.y);
- sum += TEX2D(v_texCoord + vec2(+3.0 * onex, 0.0)) * vec3_splat(v_coeffs.z);
- sum += TEX2D(v_texCoord + vec2(+4.0 * onex, 0.0)) * vec3_splat(v_coeffs.w);
+ sum += TEX2D(v_texCoord + vec2(+1.0 * onex, 0.0)) * vec4_splat(v_coeffs.x);
+ sum += TEX2D(v_texCoord + vec2(+2.0 * onex, 0.0)) * vec4_splat(v_coeffs.y);
+ sum += TEX2D(v_texCoord + vec2(+3.0 * onex, 0.0)) * vec4_splat(v_coeffs.z);
+ sum += TEX2D(v_texCoord + vec2(+4.0 * onex, 0.0)) * vec4_splat(v_coeffs.w);
+ sum += TEX2D(v_texCoord + vec2(+5.0 * onex, 0.0)) * vec4_splat(v_coeffs2.x);
+ sum += TEX2D(v_texCoord + vec2(+6.0 * onex, 0.0)) * vec4_splat(v_coeffs2.y);
+ sum += TEX2D(v_texCoord + vec2(+7.0 * onex, 0.0)) * vec4_splat(v_coeffs2.z);
+ sum += TEX2D(v_texCoord + vec2(+8.0 * onex, 0.0)) * vec4_splat(v_coeffs2.w);
- float norm = 1.0 / (1.0 + 2.0*(v_coeffs.x+v_coeffs.y+v_coeffs.z+v_coeffs.w));
-
- gl_FragColor = vec4( pow(sum*vec3_splat(norm), vec3_splat(1.0/u_gamma.x)), 1.0 );
+ float norm = 1.0 / (1.0 + 2.0*(v_coeffs.x+v_coeffs.y+v_coeffs.z+v_coeffs.w
+ +v_coeffs2.x+v_coeffs2.y+v_coeffs2.z+v_coeffs2.w));
+
+ gl_FragColor = pow(sum*vec4_splat(norm), vec4(vec3_splat(1.0/u_gamma.x), 1.0));
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_gaussy.sc b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_gaussy.sc
index 107d1d7a5bb..9f4eace6cbe 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_gaussy.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_gaussy.sc
@@ -1,4 +1,4 @@
-$input v_texCoord, v_coeffs
+$input v_texCoord, v_coeffs, v_coeffs2
#include "common.sh"
@@ -6,24 +6,33 @@ uniform vec4 u_gamma;
uniform vec4 u_tex_size0;
SAMPLER2D(s_tex, 0);
-#define TEX2D(v) pow(texture2D(s_tex, v).rgb, vec3_splat(u_gamma.x))
+#define TEX2D(v) pow(texture2D(s_tex, v), vec4(vec3_splat(u_gamma.x), 1.0))
void main()
{
- vec3 sum = vec3_splat(0.0);
+ vec4 sum = vec4_splat(0.0);
float oney = 1.0/u_tex_size0.y;
- sum += TEX2D(v_texCoord + vec2(0.0, -4.0 * oney)) * vec3_splat(v_coeffs.w);
- sum += TEX2D(v_texCoord + vec2(0.0, -3.0 * oney)) * vec3_splat(v_coeffs.z);
- sum += TEX2D(v_texCoord + vec2(0.0, -2.0 * oney)) * vec3_splat(v_coeffs.y);
- sum += TEX2D(v_texCoord + vec2(0.0, -1.0 * oney)) * vec3_splat(v_coeffs.x);
+ sum += TEX2D(v_texCoord + vec2(0.0, -8.0 * oney)) * vec4_splat(v_coeffs2.w);
+ sum += TEX2D(v_texCoord + vec2(0.0, -7.0 * oney)) * vec4_splat(v_coeffs2.z);
+ sum += TEX2D(v_texCoord + vec2(0.0, -6.0 * oney)) * vec4_splat(v_coeffs2.y);
+ sum += TEX2D(v_texCoord + vec2(0.0, -5.0 * oney)) * vec4_splat(v_coeffs2.x);
+ sum += TEX2D(v_texCoord + vec2(0.0, -4.0 * oney)) * vec4_splat(v_coeffs.w);
+ sum += TEX2D(v_texCoord + vec2(0.0, -3.0 * oney)) * vec4_splat(v_coeffs.z);
+ sum += TEX2D(v_texCoord + vec2(0.0, -2.0 * oney)) * vec4_splat(v_coeffs.y);
+ sum += TEX2D(v_texCoord + vec2(0.0, -1.0 * oney)) * vec4_splat(v_coeffs.x);
sum += TEX2D(v_texCoord);
- sum += TEX2D(v_texCoord + vec2(0.0, +1.0 * oney)) * vec3_splat(v_coeffs.x);
- sum += TEX2D(v_texCoord + vec2(0.0, +2.0 * oney)) * vec3_splat(v_coeffs.y);
- sum += TEX2D(v_texCoord + vec2(0.0, +3.0 * oney)) * vec3_splat(v_coeffs.z);
- sum += TEX2D(v_texCoord + vec2(0.0, +4.0 * oney)) * vec3_splat(v_coeffs.w);
+ sum += TEX2D(v_texCoord + vec2(0.0, +1.0 * oney)) * vec4_splat(v_coeffs.x);
+ sum += TEX2D(v_texCoord + vec2(0.0, +2.0 * oney)) * vec4_splat(v_coeffs.y);
+ sum += TEX2D(v_texCoord + vec2(0.0, +3.0 * oney)) * vec4_splat(v_coeffs.z);
+ sum += TEX2D(v_texCoord + vec2(0.0, +4.0 * oney)) * vec4_splat(v_coeffs.w);
+ sum += TEX2D(v_texCoord + vec2(0.0, +5.0 * oney)) * vec4_splat(v_coeffs2.x);
+ sum += TEX2D(v_texCoord + vec2(0.0, +6.0 * oney)) * vec4_splat(v_coeffs2.y);
+ sum += TEX2D(v_texCoord + vec2(0.0, +7.0 * oney)) * vec4_splat(v_coeffs2.z);
+ sum += TEX2D(v_texCoord + vec2(0.0, +8.0 * oney)) * vec4_splat(v_coeffs2.w);
- float norm = 1.0 / (1.0 + 2.0*(v_coeffs.x+v_coeffs.y+v_coeffs.z+v_coeffs.w));
-
- gl_FragColor = vec4( pow(sum*vec3_splat(norm), vec3_splat(1.0/u_gamma.x)), 1.0 );
+ float norm = 1.0 / (1.0 + 2.0*(v_coeffs.x+v_coeffs.y+v_coeffs.z+v_coeffs.w
+ +v_coeffs2.x+v_coeffs2.y+v_coeffs2.z+v_coeffs2.w));
+
+ gl_FragColor = pow(sum*vec4_splat(norm), vec4(vec3_splat(1.0/u_gamma.x), 1.0));
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_lowpass.sc b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_lowpass.sc
new file mode 100644
index 00000000000..37ab685957c
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_lowpass.sc
@@ -0,0 +1,37 @@
+$input v_texCoord, v_lpcoeffs1, v_lpcoeffs2
+
+#include "common.sh"
+
+SAMPLER2D(s_screen, 0);
+
+uniform vec4 u_tex_size0;
+
+vec3 sample_screen(vec2 c)
+{
+ vec2 underscan = step(0.0,c) * step(0.0,vec2_splat(1.0)-c);
+ vec3 col = texture2D(s_screen, c).rgb * vec3_splat(underscan.x*underscan.y);
+ return col;
+}
+
+void main()
+{
+ float onex = 1.0/u_tex_size0.x;
+
+ vec3 sum = sample_screen(v_texCoord) * vec3_splat(v_lpcoeffs1.x);
+ sum +=sample_screen(v_texCoord+vec2(-1.0*onex,0.0))*vec3_splat(v_lpcoeffs1.y);
+ sum +=sample_screen(v_texCoord+vec2( 1.0*onex,0.0))*vec3_splat(v_lpcoeffs1.y);
+ sum +=sample_screen(v_texCoord+vec2(-2.0*onex,0.0))*vec3_splat(v_lpcoeffs1.z);
+ sum +=sample_screen(v_texCoord+vec2( 2.0*onex,0.0))*vec3_splat(v_lpcoeffs1.z);
+ sum +=sample_screen(v_texCoord+vec2(-3.0*onex,0.0))*vec3_splat(v_lpcoeffs1.w);
+ sum +=sample_screen(v_texCoord+vec2( 3.0*onex,0.0))*vec3_splat(v_lpcoeffs1.w);
+ sum +=sample_screen(v_texCoord+vec2(-4.0*onex,0.0))*vec3_splat(v_lpcoeffs2.x);
+ sum +=sample_screen(v_texCoord+vec2( 4.0*onex,0.0))*vec3_splat(v_lpcoeffs2.x);
+ sum +=sample_screen(v_texCoord+vec2(-5.0*onex,0.0))*vec3_splat(v_lpcoeffs2.y);
+ sum +=sample_screen(v_texCoord+vec2( 5.0*onex,0.0))*vec3_splat(v_lpcoeffs2.y);
+ sum +=sample_screen(v_texCoord+vec2(-6.0*onex,0.0))*vec3_splat(v_lpcoeffs2.z);
+ sum +=sample_screen(v_texCoord+vec2( 6.0*onex,0.0))*vec3_splat(v_lpcoeffs2.z);
+ sum +=sample_screen(v_texCoord+vec2(-7.0*onex,0.0))*vec3_splat(v_lpcoeffs2.w);
+ sum +=sample_screen(v_texCoord+vec2( 7.0*onex,0.0))*vec3_splat(v_lpcoeffs2.w);
+
+ gl_FragColor = vec4( sum, texture2D(s_screen, v_texCoord).a );
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_mipmap8.sc b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_mipmap8.sc
new file mode 100644
index 00000000000..2e0f8038053
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_mipmap8.sc
@@ -0,0 +1,148 @@
+$input v_texCoord
+
+#include "common.sh"
+
+SAMPLER2D(s_screen, 0);
+SAMPLER2D(s_mipmap, 1);
+
+uniform vec4 u_tex_size0;
+uniform vec4 u_tex_size1;
+uniform vec4 u_smooth;
+
+/*
+ * Based loosely on the idea outlined at
+ * https://nyorain.github.io/mipmap-compute-shader.html
+ * Each higher mipmap level is delayed by one frame.
+ *
+ * A rectangle containing (1,1) has the last mipmap level
+ * (normally a single pixel containing the average of the frame),
+ * passed through a two-tap IIR temporal filter.
+ */
+
+const vec2 v05 = vec2(0.5,0.5);
+
+// pix has integer coordinates -> average four pixels using bilinear filtering
+vec4 sample_screen(vec2 pix)
+{
+ vec2 border = step(-0.5, u_tex_size0.xy - pix);
+ float weight = border.x * border.y;
+
+ // avoid boundary! if dimensions are odd, average 1 or 2 pixels
+ vec2 x = clamp(pix, vec2_splat(0.0), u_tex_size0.xy - v05);
+ // if we're at the boundary, include weight factor
+ // -> effectively always average 4 pixels, with some of them possibly zero
+ border = clamp(u_tex_size0.xy-x,0.0,1.0);
+ weight *= border.x * border.y;
+
+ vec4 tex = texture2D(s_screen, x / u_tex_size0.xy);
+
+ return tex * vec4_splat(weight);
+}
+
+vec4 sample_mipmap(vec2 pix, vec2 offset, vec2 size)
+{
+ vec2 border = step(-0.5, size - pix) * step(-0.5, pix);
+ float weight = border.x * border.y;
+
+ // avoid boundary! if dimensions are odd, average 1 or 2 pixels
+ vec2 x = clamp(pix, vec2_splat(0.0), size - v05);
+ // if we're at the boundary, include weight factor
+ // -> effectively always average 4 pixels, with some of them possibly zero
+ border = clamp(size-x,0.0,1.0);
+ weight *= border.x * border.y;
+
+ vec4 tex = texture2D(s_mipmap, (x + offset) / u_tex_size0.xy);
+
+ return tex * vec4_splat(weight);
+}
+
+void main()
+{
+ vec2 pix = v_texCoord.xy * u_tex_size0.xy;
+ vec2 x = pix*vec2_splat(8.0);
+ if (pix.x < u_tex_size0.x * 0.5) {
+ // first level: sample from screen texture
+
+ // sample 4x4 grid
+ // each sample uses bilinear filtering to average a 2x2 region
+ // overall reduction by 8x8
+ vec4 tex = ( sample_screen(x + vec2(-3.0,-3.0))
+ + sample_screen(x + vec2(-3.0,-1.0))
+ + sample_screen(x + vec2(-3.0, 1.0))
+ + sample_screen(x + vec2(-3.0, 3.0))
+ + sample_screen(x + vec2(-1.0,-3.0))
+ + sample_screen(x + vec2(-1.0,-1.0))
+ + sample_screen(x + vec2(-1.0, 1.0))
+ + sample_screen(x + vec2(-1.0, 3.0))
+ + sample_screen(x + vec2( 1.0,-3.0))
+ + sample_screen(x + vec2( 1.0,-1.0))
+ + sample_screen(x + vec2( 1.0, 1.0))
+ + sample_screen(x + vec2( 1.0, 3.0))
+ + sample_screen(x + vec2( 3.0,-3.0))
+ + sample_screen(x + vec2( 3.0,-1.0))
+ + sample_screen(x + vec2( 3.0, 1.0))
+ + sample_screen(x + vec2( 3.0, 3.0)) ) * 0.0625;
+
+ gl_FragColor = vec4(tex.rgb,1.0);
+ } else {
+ // higher levels: sample from mipmap texture
+ vec2 newsize = u_tex_size0.xy; // size of texture being sampled
+ float fac = 8.0; // keep track of the linear reduction factor
+ float dx = u_tex_size0.x;
+ vec2 offset = vec2_splat(0.0);
+ vec2 offset0 = offset;
+ bool fc = false;
+
+ for (int i = 0; i < 3; i++) { // 3 is sufficient for dimensions up to 4k
+ // place subsequent levels to the right
+ if (pix.x > dx * 0.5) {
+ dx = dx * 0.5;
+ newsize = ceil(newsize*v05*v05*v05); // size of sampled texture is eighthed
+ fac *= 8.0;
+ offset0 = offset;
+ offset.x = offset.x + dx;
+ pix.x -= dx;
+ x = pix * vec2_splat(8.0);
+ if (newsize.x < 8.5 && newsize.y < 8.5) { // reducing to a single pixel
+ fc = true;
+ break;
+ }
+ } else break;
+ }
+
+ if (fc)
+ x = vec2(4.0,4.0);
+
+ vec4 tex = ( sample_mipmap(x + vec2(-3.0,-3.0),offset0,newsize)
+ + sample_mipmap(x + vec2(-3.0,-1.0),offset0,newsize)
+ + sample_mipmap(x + vec2(-3.0, 1.0),offset0,newsize)
+ + sample_mipmap(x + vec2(-3.0, 3.0),offset0,newsize)
+ + sample_mipmap(x + vec2(-1.0,-3.0),offset0,newsize)
+ + sample_mipmap(x + vec2(-1.0,-1.0),offset0,newsize)
+ + sample_mipmap(x + vec2(-1.0, 1.0),offset0,newsize)
+ + sample_mipmap(x + vec2(-1.0, 3.0),offset0,newsize)
+ + sample_mipmap(x + vec2( 1.0,-3.0),offset0,newsize)
+ + sample_mipmap(x + vec2( 1.0,-1.0),offset0,newsize)
+ + sample_mipmap(x + vec2( 1.0, 1.0),offset0,newsize)
+ + sample_mipmap(x + vec2( 1.0, 3.0),offset0,newsize)
+ + sample_mipmap(x + vec2( 3.0,-3.0),offset0,newsize)
+ + sample_mipmap(x + vec2( 3.0,-1.0),offset0,newsize)
+ + sample_mipmap(x + vec2( 3.0, 1.0),offset0,newsize)
+ + sample_mipmap(x + vec2( 3.0, 3.0),offset0,newsize) ) * 0.0625;
+
+ if (fc) { // this sample yields average over the whole screen
+ // apply a compensation for the zeros included in the 8^n average
+ float f = fac*fac / (u_tex_size0.x * u_tex_size0.y);
+ vec4 col = tex * vec4_splat(f);
+ if (v_texCoord.y * u_tex_size1.y < ( offset0.y + u_tex_size1.y ) * 0.5) {
+ gl_FragColor = col;
+ } else {
+ // we are near (1,1): in this region include the temporal filter
+ vec4 old = texture2D(s_mipmap, v_texCoord.xy);
+ gl_FragColor = mix(col,old,u_smooth.x);
+ }
+ } else {
+ gl_FragColor = tex;
+ }
+ }
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_phosphor_apply.sc b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_phosphor_apply.sc
index e70036084ff..f7e116696cb 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_phosphor_apply.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_phosphor_apply.sc
@@ -7,19 +7,36 @@ SAMPLER2D(s_phosphor, 1);
uniform vec4 u_phosphor_power;
uniform vec4 u_phosphor_amplitude;
+uniform vec4 u_phosphor_cutoff;
uniform vec4 u_gamma;
+float decay(float t)
+{
+ // transition smoothly from power to linear at t=t1
+ float t1 = u_phosphor_cutoff.x / ( 1.0 + u_gamma.x / u_phosphor_power.x );
+ float tpow = pow( clamp(t,0.0,t1), -u_phosphor_power.x );
+ // smoothly fade out for t in [t1,cutoff]: linear in gamma space
+ t = clamp(t, 0.0, u_phosphor_cutoff.x);
+ float y = ( t < t1
+ ? tpow
+ : tpow * pow( ( u_phosphor_cutoff.x - t ) / ( u_phosphor_cutoff.x - t1 ), u_gamma.x ) );
+ return y;
+}
+
void main()
{
vec4 screen = texture2D(s_screen, v_texCoord);
vec4 phosphor = texture2D(s_phosphor, v_texCoord);
- vec3 cscrn = pow(screen.rgb, vec3_splat(u_gamma.x));
- vec3 cphos = pow(phosphor.rgb, vec3_splat(u_gamma.x));
+ vec4 cscrn = pow(screen, vec4(vec3_splat(u_gamma.x), 1.0));
+ vec4 cphos = pow(phosphor, vec4(vec3_splat(u_gamma.x), 1.0));
+
+ // encode the upper 2 bits of the time elapsed in the lower 2 bits of b
+ float t = 255.0*phosphor.a + fract(phosphor.b*255.0/4.0)*1024.0;
+
+ cphos *= vec4_splat( u_phosphor_amplitude.x * decay(t) );
- cphos *= vec3_splat( u_phosphor_amplitude.x / pow(255.0*phosphor.a,u_phosphor_power.x) );
+ vec4 col = pow(cscrn + cphos, vec4(vec3_splat(1.0/u_gamma.x), 1.0));
- vec3 col = pow(cscrn + cphos, vec3_splat(1.0/u_gamma.x));
-
- gl_FragColor = vec4(col, 1.0);
+ gl_FragColor = col;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_phosphor_update.sc b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_phosphor_update.sc
index 5215054b0db..824a008e96b 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_phosphor_update.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/fs_phosphor_update.sc
@@ -7,8 +7,22 @@ SAMPLER2D(s_phosphor, 1);
uniform vec4 u_phosphor_power;
uniform vec4 u_phosphor_amplitude;
+uniform vec4 u_phosphor_cutoff;
uniform vec4 u_gamma;
+float decay(float t)
+{
+ // transition smoothly from power to linear at t=t1
+ float t1 = u_phosphor_cutoff.x / ( 1.0 + u_gamma.x / u_phosphor_power.x );
+ float tpow = pow( clamp(t,0.0,t1), -u_phosphor_power.x );
+ // smoothly fade out for t in [t1,cutoff]: linear in gamma space
+ t = clamp(t, 0.0, u_phosphor_cutoff.x);
+ float y = ( t < t1
+ ? tpow
+ : tpow * pow( ( u_phosphor_cutoff.x - t ) / ( u_phosphor_cutoff.x - t1 ), u_gamma.x ) );
+ return y;
+}
+
void main()
{
vec4 screen = texture2D(s_screen, v_texCoord);
@@ -17,8 +31,15 @@ void main()
vec3 lum = vec3(0.299,0.587,0.114);
float bscrn = dot(pow(screen.rgb,vec3_splat(u_gamma.x)),lum);
float bphos = dot(pow(phosphor.rgb,vec3_splat(u_gamma.x)),lum);
- //bscrn /= pow(1.0,u_phosphor_power.x);
- bphos /= pow(1.0+255.0*phosphor.a,u_phosphor_power.x);
- gl_FragColor = ( bscrn > bphos ? vec4(screen.rgb,1.0/255.0) : vec4(phosphor.rgb,phosphor.a+1.0/255.0) );
+ // encode the upper 2 bits of the time elapsed in the lower 2 bits of b
+ float t = 1.0 + 255.0*phosphor.a + fract(phosphor.b*255.0/4.0)*1024.0;
+
+ bphos = ( t > 1023.0 ? 0.0 : bphos * decay(t) );
+
+ gl_FragColor = ( bscrn >= bphos
+ ? vec4(screen.rg,floor(screen.b*255.0/4.0)*4.0/255.0,1.0/255.0)
+ : vec4(phosphor.rg,
+ (floor(phosphor.b*255.0/4.0)*4.0 + floor(t/256.0))/255.0,
+ fract(t/256.0)*256.0/255.0 ) );
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/varying.def.sc b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/varying.def.sc
index 034ca88185b..0de371e22c8 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/varying.def.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/varying.def.sc
@@ -1,9 +1,12 @@
vec2 v_texCoord : TEXCOORD0 = vec2(0.0, 0.0);
vec3 v_stretch : TEXCOORD1 = vec3(0.0,0.0,0.0);
-vec2 v_sinangle : TEXCOORD2 = vec2(0.0,0.0);
+vec2 v_sinangle : TEXCOORD2 = vec2(0.0,0.0);
vec2 v_cosangle : TEXCOORD3 = vec2(0.0,0.0);
vec2 v_one : TEXCOORD4 = vec2(0.0,0.0);
vec4 v_coeffs : TEXCOORD5 = vec4(0.0,0.0,0.0,0.0);
+vec4 v_coeffs2 : TEXCOORD6 = vec4(0.0,0.0,0.0,0.0);
+vec4 v_lpcoeffs1: TEXCOORD7 = vec4(0.0,0.0,0.0,0.0);
+vec4 v_lpcoeffs2: TEXCOORD8 = vec4(0.0,0.0,0.0,0.0);
vec3 a_position : POSITION;
vec4 a_color0 : COLOR0;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_crt-geom.sc b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_crt-geom.sc
index cc3ed09aa14..4f17f0d0ec3 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_crt-geom.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_crt-geom.sc
@@ -19,78 +19,82 @@ uniform vec4 R;
uniform vec4 angle;
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
uniform vec4 u_rotation_type;
#define FIX(c) max(abs(c), 1e-5)
float intersect(vec2 xy , vec2 sinangle, vec2 cosangle)
{
- float A = dot(xy,xy)+d.x*d.x;
- float B = 2.0*(R.x*(dot(xy,sinangle)-d.x*cosangle.x*cosangle.y)-d.x*d.x);
- float C = d.x*d.x + 2.0*R.x*d.x*cosangle.x*cosangle.y;
- return (-B-sqrt(B*B-4.0*A*C))/(2.0*A);
+ float A = dot(xy,xy)+d.x*d.x;
+ float B = 2.0*(R.x*(dot(xy,sinangle)-d.x*cosangle.x*cosangle.y)-d.x*d.x);
+ float C = d.x*d.x + 2.0*R.x*d.x*cosangle.x*cosangle.y;
+ return (-B-sqrt(B*B-4.0*A*C))/(2.0*A);
}
vec2 bkwtrans(vec2 xy, vec2 sinangle, vec2 cosangle)
{
- float c = intersect(xy, sinangle, cosangle);
- vec2 pt = vec2_splat(c)*xy;
- pt -= vec2_splat(-R.x)*sinangle;
- pt /= vec2_splat(R.x);
- vec2 tang = sinangle/cosangle;
- vec2 poc = pt/cosangle;
- float A = dot(tang,tang)+1.0;
- float B = -2.0*dot(poc,tang);
- float C = dot(poc,poc)-1.0;
- float a = (-B+sqrt(B*B-4.0*A*C))/(2.0*A);
- vec2 uv = (pt-a*sinangle)/cosangle;
- float r = FIX(R.x*acos(a));
- return uv*r/sin(r/R.x);
+ float c = intersect(xy, sinangle, cosangle);
+ vec2 pt = vec2_splat(c)*xy;
+ pt -= vec2_splat(-R.x)*sinangle;
+ pt /= vec2_splat(R.x);
+ vec2 tang = sinangle/cosangle;
+ vec2 poc = pt/cosangle;
+ float A = dot(tang,tang)+1.0;
+ float B = -2.0*dot(poc,tang);
+ float C = dot(poc,poc)-1.0;
+ float a = (-B+sqrt(B*B-4.0*A*C))/(2.0*A);
+ vec2 uv = (pt-a*sinangle)/cosangle;
+ float r = FIX(R.x*acos(a));
+ return uv*r/sin(r/R.x);
}
vec2 fwtrans(vec2 uv, vec2 sinangle, vec2 cosangle)
{
- float r = FIX(sqrt(dot(uv,uv)));
- uv *= sin(r/R.x)/r;
- float x = 1.0-cos(r/R.x);
- float D = d.x/R.x + x*cosangle.x*cosangle.y+dot(uv,sinangle);
- return d.x*(uv*cosangle-x*sinangle)/D;
+ float r = FIX(sqrt(dot(uv,uv)));
+ uv *= sin(r/R.x)/r;
+ float x = 1.0-cos(r/R.x);
+ float D = d.x/R.x + x*cosangle.x*cosangle.y+dot(uv,sinangle);
+ return d.x*(uv*cosangle-x*sinangle)/D;
}
vec3 maxscale(vec2 sinangle, vec2 cosangle)
{
- vec2 c = bkwtrans(-R.x * sinangle / (1.0 + R.x/d.x*cosangle.x*cosangle.y), sinangle, cosangle);
- vec2 a = vec2(0.5,0.5)*aspect.xy;
- vec2 lo = vec2(fwtrans(vec2(-a.x,c.y), sinangle, cosangle).x,
- fwtrans(vec2(c.x,-a.y), sinangle, cosangle).y)/aspect.xy;
- vec2 hi = vec2(fwtrans(vec2(+a.x,c.y), sinangle, cosangle).x,
- fwtrans(vec2(c.x,+a.y), sinangle, cosangle).y)/aspect.xy;
- return vec3((hi+lo)*aspect.xy*0.5,max(hi.x-lo.x,hi.y-lo.y));
+ vec2 c = bkwtrans(-R.x * sinangle / (1.0 + R.x/d.x*cosangle.x*cosangle.y), sinangle, cosangle);
+ vec2 a = vec2(0.5,0.5)*aspect.xy;
+ vec2 lo = vec2(fwtrans(vec2(-a.x,c.y), sinangle, cosangle).x,
+ fwtrans(vec2(c.x,-a.y), sinangle, cosangle).y)/aspect.xy;
+ vec2 hi = vec2(fwtrans(vec2(+a.x,c.y), sinangle, cosangle).x,
+ fwtrans(vec2(c.x,+a.y), sinangle, cosangle).y)/aspect.xy;
+ return vec3((hi+lo)*aspect.xy*0.5,max(hi.x-lo.x,hi.y-lo.y));
}
void main()
{
- // Do the standard vertex processing.
- gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
- v_texCoord = a_texcoord0;
+ // Do the standard vertex processing.
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
+ v_texCoord = a_texcoord0;
- // Precalculate a bunch of useful values we'll need in the fragment
- // shader.
- vec2 ang;
- // if (u_rotation_type.x < 0.5)
- // ang = vec2(0.0,angle.x);
- // else if (u_rotation_type.x < 1.5)
- // ang = vec2(angle.x,0.0);
- // else if (u_rotation_type.x < 2.5)
- // ang = vec2(0.0,-angle.x);
- // else
- // ang = vec2(-angle.x,0.0);
- ang = angle.xy;
- v_sinangle = sin(ang);
- v_cosangle = cos(ang);
- v_stretch = maxscale(v_sinangle, v_cosangle);
+ // Precalculate a bunch of useful values we'll need in the fragment
+ // shader.
+ vec2 ang;
+ // if (u_rotation_type.x < 0.5)
+ // ang = vec2(0.0,angle.x);
+ // else if (u_rotation_type.x < 1.5)
+ // ang = vec2(angle.x,0.0);
+ // else if (u_rotation_type.x < 2.5)
+ // ang = vec2(0.0,-angle.x);
+ // else
+ // ang = vec2(-angle.x,0.0);
+ ang = angle.xy;
+ v_sinangle = sin(ang);
+ v_cosangle = cos(ang);
+ v_stretch = maxscale(v_sinangle, v_cosangle);
- // The size of one texel, in texture-coordinates.
- v_one = 1.0 / u_tex_size0.xy;
+ // The size of one texel, in texture-coordinates.
+ v_one = 1.0 / u_tex_size0.xy;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_gaussx.sc b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_gaussx.sc
index 4bd5a57e3ef..a5fb1d22622 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_gaussx.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_gaussx.sc
@@ -1,18 +1,23 @@
$input a_position, a_texcoord0, a_color0
-$output v_texCoord, v_coeffs
+$output v_texCoord, v_coeffs, v_coeffs2
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
uniform vec4 u_width;
uniform vec4 u_aspect;
void main()
{
- float wid = u_width.x*u_tex_size0.x/(320.*u_aspect.x);;
- v_coeffs = exp(vec4(1.,4.,9.,16.)*vec4_splat(-1.0/wid/wid));
+ float wid = u_width.x*u_tex_size0.x/(320.*u_aspect.x);
+ v_coeffs = exp(vec4(1.,4.,9.,16.)*vec4_splat(-1.0/wid/wid));
+ v_coeffs2 = exp(vec4(25.,36.,49.,64.)*vec4_splat(-1.0/wid/wid));
- // Do the standard vertex processing.
- gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
- v_texCoord = a_texcoord0;
+ // Do the standard vertex processing.
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
+ v_texCoord = a_texcoord0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_gaussy.sc b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_gaussy.sc
index 3ff1e07f236..93676cde1d5 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_gaussy.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_gaussy.sc
@@ -1,18 +1,23 @@
$input a_position, a_texcoord0, a_color0
-$output v_texCoord, v_coeffs
+$output v_texCoord, v_coeffs, v_coeffs2
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
uniform vec4 u_width;
uniform vec4 u_aspect;
void main()
{
- float wid = u_width.x*u_tex_size0.y/(320.*u_aspect.y);
- v_coeffs = exp(vec4(1.,4.,9.,16.)*vec4_splat(-1.0/wid/wid));
+ float wid = u_width.x*u_tex_size0.y/(320.*u_aspect.y);
+ v_coeffs = exp(vec4(1.,4.,9.,16.)*vec4_splat(-1.0/wid/wid));
+ v_coeffs2 = exp(vec4(25.,36.,49.,64.)*vec4_splat(-1.0/wid/wid));
- // Do the standard vertex processing.
- gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
- v_texCoord = a_texcoord0;
+ // Do the standard vertex processing.
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
+ v_texCoord = a_texcoord0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_lowpass.sc b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_lowpass.sc
new file mode 100644
index 00000000000..2ca983d41d7
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_lowpass.sc
@@ -0,0 +1,53 @@
+$input a_position, a_texcoord0, a_color0
+$output v_texCoord, v_lpcoeffs1, v_lpcoeffs2
+
+#include "common.sh"
+
+uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
+uniform vec4 u_lowpass_cutoff;
+uniform vec4 u_lowpass_width;
+
+void main()
+{
+ // Do the standard vertex processing.
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
+ v_texCoord = a_texcoord0;
+
+ // interpret the cutoff and width as target resolutions in pixels per scanline
+ // include factor of 1/2 because max frequency at given resolution is Nyquist
+ float a = 0.5 * u_lowpass_cutoff.x / u_tex_size0.x;
+ float b = 0.5 * u_lowpass_width.x / u_tex_size0.x;
+ float w0 = (a-0.5*b);
+ float w1 = (a+0.5*b);
+
+ float two_pi = 6.283185307179586;
+ vec3 n1 = vec3(1.0,2.0,3.0);
+ vec4 n2 = vec4(4.0,5.0,6.0,7.0);
+
+ // target frequency response:
+ // 1 for w < w0
+ // 0 for w > w1
+ // linearly decreasing for w0 < w < w1
+ // this will be approximated by including the lowest Fourier modes
+ if (w0 > 0.5) { // no filtering
+ v_lpcoeffs1 = vec4(1.0,0.0,0.0,0.0);
+ v_lpcoeffs2 = vec4_splat(0.0);
+ } else if (w1 > 0.5) { // don't reach zero
+ // here the target has a nonzero response at the Nyquist frequency
+ v_lpcoeffs1.x = w1 + w0 - (w1 - 0.5)*(w1 - 0.5)/(w1 - w0);
+ v_lpcoeffs1.yzw = 2.0 / ( two_pi*two_pi*(w1-w0)*n1*n1 ) * ( cos(two_pi*w0*n1) - cos(two_pi*0.5*n1) );
+ v_lpcoeffs2 = 2.0 / ( two_pi*two_pi*(w1-w0)*n2*n2 ) * ( cos(two_pi*w0*n2) - cos(two_pi*0.5*n2) );
+ } else if (w1 == w0) { // sharp cutoff
+ v_lpcoeffs1.x = 2.0 * w0;
+ v_lpcoeffs1.yzw = 2.0 / ( two_pi * n1 ) * sin(two_pi*w0*n1);
+ v_lpcoeffs2 = 2.0 / ( two_pi * n2 ) * sin(two_pi*w0*n2);
+ } else {
+ v_lpcoeffs1.x = w1 + w0;
+ v_lpcoeffs1.yzw = 2.0 / ( two_pi*two_pi*(w1-w0)*n1*n1 ) * ( cos(two_pi*w0*n1) - cos(two_pi*w1*n1) );
+ v_lpcoeffs2 = 2.0 / ( two_pi*two_pi*(w1-w0)*n2*n2 ) * ( cos(two_pi*w0*n2) - cos(two_pi*w1*n2) );
+ }
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_mipmap8.sc b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_mipmap8.sc
new file mode 100644
index 00000000000..8424e153cdb
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_mipmap8.sc
@@ -0,0 +1,16 @@
+$input a_position, a_texcoord0, a_color0
+$output v_texCoord
+
+#include "common.sh"
+
+uniform vec4 u_inv_view_dims;
+
+void main()
+{
+ // Do the standard vertex processing.
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
+ v_texCoord = a_texcoord0;
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_phosphor_apply.sc b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_phosphor_apply.sc
index bdd09148403..8424e153cdb 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_phosphor_apply.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_phosphor_apply.sc
@@ -3,9 +3,14 @@ $output v_texCoord
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
- // Do the standard vertex processing.
- gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
- v_texCoord = a_texcoord0;
+ // Do the standard vertex processing.
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
+ v_texCoord = a_texcoord0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_phosphor_update.sc b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_phosphor_update.sc
index bdd09148403..8424e153cdb 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_phosphor_update.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/crt-geom/vs_phosphor_update.sc
@@ -3,9 +3,14 @@ $output v_texCoord
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
- // Do the standard vertex processing.
- gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
- v_texCoord = a_texcoord0;
+ // Do the standard vertex processing.
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
+ v_texCoord = a_texcoord0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/crt/vs_crt-caligari.sc b/src/osd/modules/render/bgfx/shaders/chains/crt/vs_crt-caligari.sc
index 37a119ec7d4..ce22c1e7200 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/crt/vs_crt-caligari.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/crt/vs_crt-caligari.sc
@@ -32,14 +32,18 @@ $output v_texcoord0, v_texcoord1, v_color0
// Autos
uniform vec4 u_source_size;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
-
+
onex = vec2(1.0 / u_source_size.x, 0.0);
oney = vec2(0.0, 1.0 / u_source_size.y);
-
+
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/default/vs_blit.sc b/src/osd/modules/render/bgfx/shaders/chains/default/vs_blit.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/default/vs_blit.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/default/vs_blit.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/eagle/fs_eagle.sc b/src/osd/modules/render/bgfx/shaders/chains/eagle/fs_eagle.sc
index a07a848ffbd..ca769f5dc07 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/eagle/fs_eagle.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/eagle/fs_eagle.sc
@@ -7,7 +7,7 @@ $input v_color0, texCoord, t1, t2, t3, t4, t5, t6, t7, t8
/* Copied from the Dosbox source code */
/* Copyright (C) 2002-2007 The DOSBox Team */
/* License: GNU-GPL */
-/* Adapted by guest(r) on 16.4.2007 */
+/* Adapted by guest(r) on 16.4.2007 */
#include "common.sh"
@@ -32,10 +32,10 @@ float GET_RESULT(float A, float B, float C, float D)
float r = 0.0;
if (A == C) x += 1.0; else if (B == C) y += 1.0;
if (A == D) x += 1.0; else if (B == D) y += 1.0;
- if (x <= 1.0) r += 1.0;
+ if (x <= 1.0) r += 1.0;
if (y <= 1.0) r -= 1.0;
return r;
-}
+}
void main()
{
@@ -43,7 +43,7 @@ void main()
// Reading the texels
- vec3 C0 = texture2D(decal, t1.xy).xyz;
+ vec3 C0 = texture2D(decal, t1.xy).xyz;
vec3 C1 = texture2D(decal, t1.zw).xyz;
vec3 C2 = texture2D(decal, t2.xy).xyz;
vec3 D3 = texture2D(decal, t2.zw).xyz;
@@ -62,7 +62,7 @@ void main()
vec3 p00,p10,p01,p11;
- // reducing float3 to float
+ // reducing float3 to float
float c0 = reduce(C0); float c1 = reduce(C1);
float c2 = reduce(C2); float c3 = reduce(C3);
float c4 = reduce(C4); float c5 = reduce(C5);
@@ -76,7 +76,7 @@ void main()
/* Copied from the Dosbox source code */
/* Copyright (C) 2002-2007 The DOSBox Team */
/* License: GNU-GPL */
- /* Adapted by guest(r) on 16.4.2007 */
+ /* Adapted by guest(r) on 16.4.2007 */
if (c4 != c8)
{
if (c7 == c5)
@@ -122,16 +122,16 @@ void main()
else
{
p01 = 0.5 * (C4 + C5);
- }
+ }
- if ((c8 == d2) || (c3 == c4))
- {
+ if ((c8 == d2) || (c3 == c4))
+ {
p10 = 0.25 * (3.0 * C4 + C7);
- }
- else
- {
+ }
+ else
+ {
p10 = 0.5 * (C7 + C8);
- }
+ }
}
else
{
@@ -158,8 +158,8 @@ void main()
}
}
}
-
+
p10 = (fp.x < 0.50) ? (fp.y < 0.50 ? p00 : p10) : (fp.y < 0.50 ? p01: p11);
-
+
gl_FragColor = vec4(p10.rgb, 1.0);
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/eagle/vs_eagle.sc b/src/osd/modules/render/bgfx/shaders/chains/eagle/vs_eagle.sc
index d233629a036..095d5d562e0 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/eagle/vs_eagle.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/eagle/vs_eagle.sc
@@ -8,18 +8,22 @@ $output v_color0, texCoord, t1, t2, t3, t4, t5, t6, t7, t8
/* Copied from the Dosbox source code */
/* Copyright (C) 2002-2007 The DOSBox Team */
/* License: GNU-GPL */
-/* Adapted by guest(r) on 16.4.2007 */
+/* Adapted by guest(r) on 16.4.2007 */
#include "common.sh"
// Autos
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_color0 = a_color0;
-
+
vec2 ps = vec2(1.0, 1.0) / u_tex_size0.xy;
float dx = ps.x;
float dy = ps.y;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_chroma.sc b/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_chroma.sc
index 51bb14676d3..2c11ac8499b 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_chroma.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_chroma.sc
@@ -22,10 +22,11 @@ void main()
vec4 cin = texture2D(s_tex, v_texcoord0);
vec4 cout = vec4(0.0, 0.0, 0.0, cin.a);
mat3 xy = mat3(u_chroma_a.xyz, u_chroma_b.xyz, u_chroma_c.xyz);
- const mat3 XYZ_TO_sRGB = mat3(
- 3.2406, -0.9689, 0.0557,
- -1.5372, 1.8758, -0.2040,
- -0.4986, 0.0415, 1.0570
+
+ mat3 XYZ_TO_sRGB = mtxFromRows3(
+ vec3( 3.2406, -1.5372, -0.4986),
+ vec3(-0.9689, 1.8758, 0.0415),
+ vec3( 0.0557, -0.2040, 1.0570)
);
for (int i = 0; i < 3; ++i) {
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_defocus.sc b/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_defocus.sc
index cfb7b487596..20820f0c0a3 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_defocus.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_defocus.sc
@@ -25,7 +25,7 @@ void main()
{
// previously this pass was applied two times with offsets of 0.25, 0.5, 0.75, 1.0
// now this pass is applied only once with offsets of 0.25, 0.55, 1.0, 1.6 to achieve the same appearance as before till a maximum defocus of 2.0
- // 0.075x² + 0.225x + 0.25
+ // 0.075x² + 0.225x + 0.25
const vec2 Coord1Offset = vec2(-1.60, 0.25);
const vec2 Coord2Offset = vec2(-1.00, -0.55);
const vec2 Coord3Offset = vec2(-0.55, 1.00);
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_distortion.sc b/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_distortion.sc
index 36f4fa9eaad..ed4f6195944 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_distortion.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_distortion.sc
@@ -134,11 +134,11 @@ vec2 GetDistortedCoords(vec2 centerCoord, float amount, float amountCube)
float r2 = centerCoord.x * centerCoord.x + centerCoord.y * centerCoord.y;
float f = kcube == 0.0 ? 1.0 + r2 * k : 1.0 + r2 * (k + kcube * sqrt(r2));
- // fit screen bounds
+ // fit screen bounds
f /= 1.0 + amount * 0.25 + amountCube * 0.125;
// apply cubic distortion factor
- centerCoord *= f;
+ centerCoord *= f;
return centerCoord;
}
@@ -183,7 +183,7 @@ void main()
// corner distortion at least by the amount of the image distorition
float distortCornerAmount = max(u_distort_corner.x, u_distortion.x + u_cubic_distortion.x);
- float roundCornerAmount = u_round_corner.x * 0.5;
+ float roundCornerAmount = u_round_corner.x * 0.5;
float smoothBorderAmount = u_smooth_border.x * 0.5;
vec2 TexelDims = vec2(1.0 / u_target_dims.x, 1.0 / u_target_dims.y);
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_ntsc_decode.sc b/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_ntsc_decode.sc
index b196674a094..60b54381ec3 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_ntsc_decode.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_ntsc_decode.sc
@@ -52,7 +52,7 @@ void main()
vec4 PI = vec4(3.1415927, 3.1415927, 3.1415927, 3.1415927);
vec4 PI2 = vec4(6.2831854, 6.2831854, 6.2831854, 6.2831854);
-
+
vec4 Fc_y1 = (u_cc_value.xxxx - u_notch_width.xxxx * onehalf) * TimePerSample;
vec4 Fc_y2 = (u_cc_value.xxxx + u_notch_width.xxxx * onehalf) * TimePerSample;
vec4 Fc_y3 = u_y_freq_response.xxxx * TimePerSample;
@@ -69,7 +69,7 @@ void main()
vec4 Fc_y2_pi2 = Fc_y2 * PI2;
vec4 Fc_y3_pi2 = Fc_y3 * PI2;
vec4 PI2Length = PI2 / SampleCount;
-
+
vec4 W = PI2 * u_cc_value.xxxx * u_scan_time.xxxx;
vec4 WoPI = W / PI;
@@ -120,7 +120,7 @@ void main()
IAccum = IAccum + C * cos(WT) * FilterI;
QAccum = QAccum + C * sin(WT) * FilterQ;
}
-
+
vec3 YIQ = vec3(
(YAccum.r + YAccum.g + YAccum.b + YAccum.a),
(IAccum.r + IAccum.g + IAccum.b + IAccum.a) * 2.0,
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_ntsc_encode.sc b/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_ntsc_encode.sc
index 61964c10c30..e94eeff6962 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_ntsc_encode.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_ntsc_encode.sc
@@ -58,7 +58,7 @@ void main()
const float PI = 3.1415927;
const float PI2 = 6.2831854;
-
+
float W = PI2 * u_cc_value.x * u_scan_time.x;
float WoPI = W / PI;
@@ -69,4 +69,4 @@ void main()
vec4 TW = T * W;
gl_FragColor = Y + I * cos(TW) + Q * sin(TW);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_scanline.sc b/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_scanline.sc
index 5942c75bab6..2126398062b 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_scanline.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hlsl/fs_scanline.sc
@@ -37,34 +37,15 @@ SAMPLER2D(s_shadow, 1);
// Scanline Pixel Shader
//-----------------------------------------------------------------------------
-vec2 GetAdjustedCoords(vec2 coord)
-{
- // center coordinates
- coord -= 0.5;
-
- // apply screen scale
- coord *= u_screen_scale.xy;
-
- // un-center coordinates
- coord += 0.5;
-
- // apply screen offset
- coord += u_screen_offset.xy;
-
- return coord;
-}
-
void main()
{
- vec2 BaseCoord = GetAdjustedCoords(v_texcoord0);
-
// Color
- vec4 BaseColor = texture2D(s_tex, BaseCoord);
+ vec4 BaseColor = texture2D(s_tex, v_texcoord0);
// Clamp
- if (BaseCoord.x < 0.0 || BaseCoord.y < 0.0 || BaseCoord.x > 1.0 || BaseCoord.y > 1.0)
+ if (v_texcoord0.x < 0.0 || v_texcoord0.y < 0.0 || v_texcoord0.x > 1.0 || v_texcoord0.y > 1.0)
{
- gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
+ gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
else
{
@@ -76,7 +57,7 @@ void main()
float ColorBrightness = 0.299 * BaseColor.r + 0.587 * BaseColor.g + 0.114 * BaseColor.b;
- float ScanCoord = BaseCoord.y;
+ float ScanCoord = v_texcoord0.y;
ScanCoord += u_swap_xy.x > 0.0
? u_quad_dims.x <= u_source_dims.x * 2.0
? 0.5 / u_quad_dims.x // uncenter scanlines if the quad is less than twice the size of the source
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_chroma.sc b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_chroma.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_chroma.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_chroma.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_color.sc b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_color.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_color.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_color.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_deconverge.sc b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_deconverge.sc
index b77d85d1ea8..55c2f0e2e34 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_deconverge.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_deconverge.sc
@@ -8,6 +8,7 @@ $output v_color0, v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3
// Autos
uniform vec4 u_source_size;
+uniform vec4 u_inv_view_dims;
// User-supplied
uniform vec4 u_converge_red;
@@ -20,6 +21,9 @@ uniform vec4 u_radial_converge_blue;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
vec2 half_value = vec2(0.5, 0.5);
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_defocus.sc b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_defocus.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_defocus.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_defocus.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_distortion.sc b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_distortion.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_distortion.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_distortion.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_ntsc_decode.sc b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_ntsc_decode.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_ntsc_decode.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_ntsc_decode.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_ntsc_encode.sc b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_ntsc_encode.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_ntsc_encode.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_ntsc_encode.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_phosphor.sc b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_phosphor.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_phosphor.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_phosphor.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_post.sc b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_post.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_post.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_post.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_prescale.sc b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_prescale.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_prescale.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_prescale.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_scanline.sc b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_scanline.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_scanline.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hlsl/vs_scanline.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hqx/fs_hq2x.sc b/src/osd/modules/render/bgfx/shaders/chains/hqx/fs_hq2x.sc
index 38f81111567..3f6c2645ba4 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hqx/fs_hq2x.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hqx/fs_hq2x.sc
@@ -57,11 +57,11 @@ void main()
mat3 pattern = mat3(diff(w5, w1), diff(w5, w2), diff(w5, w3), diff(w5, w4), 0.0, diff(w5, w6), diff(w5, w7), diff(w5, w8), diff(w5, w9));
vec4 cross = vec4(diff(w4, w2), diff(w2, w6), diff(w8, w4), diff(w6, w8));
-
+
vec2 index;
index.x = dot(pattern[0], vec3( 1.0, 2.0, 4.0)) +
- dot(pattern[1], vec3( 8.0, 0.0, 16.0)) +
- dot(pattern[2], vec3(32.0, 64.0, 128.0));
+ dot(pattern[1], vec3( 8.0, 0.0, 16.0)) +
+ dot(pattern[2], vec3(32.0, 64.0, 128.0));
index.y = dot(cross, vec4(1.0, 2.0, 4.0, 8.0)) * SCALE * SCALE + dot(floor(fp * vec2(SCALE, SCALE)), vec2(1.0, SCALE));
vec2 step = vec2(1.0, 1.0) / vec2(256.0, 16.0 * (SCALE * SCALE));
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hqx/fs_hq3x.sc b/src/osd/modules/render/bgfx/shaders/chains/hqx/fs_hq3x.sc
index a29c2c00da8..1cb08a52da4 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hqx/fs_hq3x.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hqx/fs_hq3x.sc
@@ -57,11 +57,11 @@ void main()
mat3 pattern = mat3(diff(w5, w1), diff(w5, w2), diff(w5, w3), diff(w5, w4), 0.0, diff(w5, w6), diff(w5, w7), diff(w5, w8), diff(w5, w9));
vec4 cross = vec4(diff(w4, w2), diff(w2, w6), diff(w8, w4), diff(w6, w8));
-
+
vec2 index;
index.x = dot(pattern[0], vec3( 1.0, 2.0, 4.0)) +
- dot(pattern[1], vec3( 8.0, 0.0, 16.0)) +
- dot(pattern[2], vec3(32.0, 64.0, 128.0));
+ dot(pattern[1], vec3( 8.0, 0.0, 16.0)) +
+ dot(pattern[2], vec3(32.0, 64.0, 128.0));
index.y = dot(cross, vec4(1.0, 2.0, 4.0, 8.0)) * SCALE * SCALE + dot(floor(fp * vec2(SCALE, SCALE)), vec2(1.0, SCALE));
vec2 step = vec2(1.0, 1.0) / vec2(256.0, 16.0 * (SCALE * SCALE));
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hqx/fs_hq4x.sc b/src/osd/modules/render/bgfx/shaders/chains/hqx/fs_hq4x.sc
index e6c0e1c2aaa..6e87d47dc0c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hqx/fs_hq4x.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hqx/fs_hq4x.sc
@@ -57,11 +57,11 @@ void main()
mat3 pattern = mat3(diff(w5, w1), diff(w5, w2), diff(w5, w3), diff(w5, w4), 0.0, diff(w5, w6), diff(w5, w7), diff(w5, w8), diff(w5, w9));
vec4 cross = vec4(diff(w4, w2), diff(w2, w6), diff(w8, w4), diff(w6, w8));
-
+
vec2 index;
index.x = dot(pattern[0], vec3( 1.0, 2.0, 4.0)) +
- dot(pattern[1], vec3( 8.0, 0.0, 16.0)) +
- dot(pattern[2], vec3(32.0, 64.0, 128.0));
+ dot(pattern[1], vec3( 8.0, 0.0, 16.0)) +
+ dot(pattern[2], vec3(32.0, 64.0, 128.0));
index.y = dot(cross, vec4(1.0, 2.0, 4.0, 8.0)) * SCALE * SCALE + dot(floor(fp * vec2(SCALE, SCALE)), vec2(1.0, SCALE));
vec2 step = vec2(1.0, 1.0) / vec2(256.0, 16.0 * (SCALE * SCALE));
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hqx/vs_hq2x.sc b/src/osd/modules/render/bgfx/shaders/chains/hqx/vs_hq2x.sc
index a77ac7006f7..727f5763857 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hqx/vs_hq2x.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hqx/vs_hq2x.sc
@@ -8,12 +8,16 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_color0
// Autos
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_color0 = a_color0;
-
+
vec2 ps = vec2(1.0, 1.0) / u_tex_size0.xy;
float dx = ps.x;
float dy = ps.y;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hqx/vs_hq3x.sc b/src/osd/modules/render/bgfx/shaders/chains/hqx/vs_hq3x.sc
index a77ac7006f7..727f5763857 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hqx/vs_hq3x.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hqx/vs_hq3x.sc
@@ -8,12 +8,16 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_color0
// Autos
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_color0 = a_color0;
-
+
vec2 ps = vec2(1.0, 1.0) / u_tex_size0.xy;
float dx = ps.x;
float dy = ps.y;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hqx/vs_hq4x.sc b/src/osd/modules/render/bgfx/shaders/chains/hqx/vs_hq4x.sc
index a77ac7006f7..727f5763857 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/hqx/vs_hq4x.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/hqx/vs_hq4x.sc
@@ -8,12 +8,16 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_color0
// Autos
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_color0 = a_color0;
-
+
vec2 ps = vec2(1.0, 1.0) / u_tex_size0.xy;
float dx = ps.x;
float dy = ps.y;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/lcd-grid/fs_lcd-grid.sc b/src/osd/modules/render/bgfx/shaders/chains/lcd-grid/fs_lcd-grid.sc
new file mode 100644
index 00000000000..801d1a2e9a4
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/lcd-grid/fs_lcd-grid.sc
@@ -0,0 +1,106 @@
+$input v_color0, v_texcoord0
+
+// license:GPL-2.0+
+// copyright-holders:cgwg
+
+#include "common.sh"
+
+SAMPLER2D(s_tex, 0);
+
+uniform vec4 u_tex_size0;
+uniform vec4 u_quad_dims;
+uniform vec4 u_rsubpix;
+uniform vec4 u_gsubpix;
+uniform vec4 u_bsubpix;
+uniform vec4 u_gain;
+uniform vec4 u_LCDgamma;
+uniform vec4 u_blacklevel;
+uniform vec4 u_ambient;
+uniform vec4 u_BGR;
+uniform vec4 u_monitorgamma;
+uniform vec4 u_subpixsize;
+
+vec3 fetch_offset(vec2 coord, vec2 offset)
+{
+ vec2 x = coord + offset;
+ vec3 col = texture2D(s_tex, x).rgb;
+ vec3 col2 = pow(vec3_splat(u_gain.x) * col + vec3_splat(u_blacklevel.x), vec3_splat(u_LCDgamma.x)) + vec3_splat(u_ambient.x);
+ // want zero for outside pixels
+ vec4 b = step(0.0,vec4(x.x,x.y,1.0-x.x,1.0-x.y));
+ return vec3_splat(b.x*b.y*b.z*b.w) * col2;
+}
+
+float intsmear_func(float z, float c1, float c2, float c3, float c4, float c5, float c6)
+{
+ float z2 = z*z;
+ // both cases have c0=1
+ return z * (1.0 + z2*(c1 + z2*(c2 + z2*(c3 + z2*(c4 + z2*(c5 + z2*c6))))));
+}
+
+float intsmear_fx(float z)
+{
+ // integral of (1 - x^2 - x^4 + x^6)^2
+ return intsmear_func(z, -2.0/3.0, -1.0/5.0, 4.0/7.0, -1.0/9.0, -2.0/11.0, 1.0/13.0);
+}
+
+float intsmear_fy(float z)
+{
+ // integral of (1 - 2x^4 + x^6)^2
+ return intsmear_func(z, 0.0, -4.0/5.0, 2.0/7.0, 4.0/9.0, -4.0/11.0, 1.0/13.0);
+}
+
+float intsmear_x(float x, float dx, float d)
+{
+ float zl = clamp((x-dx*0.5)/d,-1.0,1.0);
+ float zh = clamp((x+dx*0.5)/d,-1.0,1.0);
+ return d * ( intsmear_fx(zh) - intsmear_fx(zl) )/dx;
+}
+float intsmear_y(float x, float dx, float d)
+{
+ float zl = clamp((x-dx*0.5)/d,-1.0,1.0);
+ float zh = clamp((x+dx*0.5)/d,-1.0,1.0);
+ return d * ( intsmear_fy(zh) - intsmear_fy(zl) )/dx;
+}
+
+void main()
+{
+ vec3 cr = pow(u_rsubpix.rgb, vec3_splat(u_monitorgamma.x));
+ vec3 cg = pow(u_gsubpix.rgb, vec3_splat(u_monitorgamma.x));
+ vec3 cb = pow(u_bsubpix.rgb, vec3_splat(u_monitorgamma.x));
+
+ vec2 tl = v_texcoord0 * u_tex_size0.xy - vec2(0.5,0.5);
+ vec2 tli = floor(tl);
+ float subpix = fract(tl.x) * 3.0;
+ float rsubpix = u_tex_size0.x / u_quad_dims.x * 3.0;
+
+ vec3 lcol, rcol;
+ lcol = vec3(intsmear_x(subpix+1.0, rsubpix, 3.0*u_subpixsize.x),
+ intsmear_x(subpix , rsubpix, 3.0*u_subpixsize.x),
+ intsmear_x(subpix-1.0, rsubpix, 3.0*u_subpixsize.x));
+ rcol = vec3(intsmear_x(subpix-2.0, rsubpix, 3.0*u_subpixsize.x),
+ intsmear_x(subpix-3.0, rsubpix, 3.0*u_subpixsize.x),
+ intsmear_x(subpix-4.0, rsubpix, 3.0*u_subpixsize.x));
+
+ if (u_BGR.x > 0.5) {
+ lcol.rgb = lcol.bgr;
+ rcol.rgb = rcol.bgr;
+ }
+
+ float tcol, bcol;
+ subpix = fract(tl.y);
+ rsubpix = u_tex_size0.y / u_quad_dims.y;
+ tcol = intsmear_y(subpix ,rsubpix, u_subpixsize.y);
+ bcol = intsmear_y(subpix-1.0,rsubpix, u_subpixsize.y);
+
+ tl = (tli + vec2_splat(0.5)) / u_tex_size0.xy;
+ vec2 one = vec2_splat(1.0) / u_tex_size0.xy;
+
+ vec3 ul = fetch_offset(tl, vec2(0,0) ) * lcol * vec3_splat(tcol);
+ vec3 br = fetch_offset(tl, one ) * rcol * vec3_splat(bcol);
+ vec3 bl = fetch_offset(tl, vec2(0,one.y)) * lcol * vec3_splat(bcol);
+ vec3 ur = fetch_offset(tl, vec2(one.x,0)) * rcol * vec3_splat(tcol);
+
+ vec3 csum = ul + br + bl + ur;
+ vec3 col = mul(mtxFromCols(u_rsubpix.rgb, u_gsubpix.rgb, u_bsubpix.rgb), csum);
+ gl_FragColor = vec4(pow(col, vec3_splat(1.0/u_monitorgamma.x)), 1.0);
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/lcd-grid/fs_persistence.sc b/src/osd/modules/render/bgfx/shaders/chains/lcd-grid/fs_persistence.sc
new file mode 100644
index 00000000000..4c9e998d3ec
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/lcd-grid/fs_persistence.sc
@@ -0,0 +1,16 @@
+$input v_color0, v_texcoord0
+
+#include "common.sh"
+
+SAMPLER2D(s_screen, 0);
+SAMPLER2D(s_motionblur, 1);
+
+uniform vec4 u_persistence;
+
+void main()
+{
+ vec4 screen = texture2D(s_screen , v_texcoord0);
+ vec4 motionblur = texture2D(s_motionblur, v_texcoord0);
+
+ gl_FragColor = mix(screen, motionblur, u_persistence.x);
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/lcd-grid/varying.def.sc b/src/osd/modules/render/bgfx/shaders/chains/lcd-grid/varying.def.sc
new file mode 100644
index 00000000000..2aa3cb425c0
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/lcd-grid/varying.def.sc
@@ -0,0 +1,6 @@
+vec4 v_color0 : COLOR0 = vec4(1.0, 0.0, 0.0, 1.0);
+vec2 v_texcoord0 : TEXCOORD0 = vec2(0.0, 0.0);
+
+vec3 a_position : POSITION;
+vec4 a_color0 : COLOR0;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/lcd-grid/vs_lcd-grid.sc b/src/osd/modules/render/bgfx/shaders/chains/lcd-grid/vs_lcd-grid.sc
new file mode 100644
index 00000000000..df2b37f203c
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/lcd-grid/vs_lcd-grid.sc
@@ -0,0 +1,19 @@
+$input a_position, a_texcoord0, a_color0
+$output v_texcoord0, v_color0
+
+// license:BSD-3-Clause
+// copyright-holders:Dario Manesku
+
+#include "common.sh"
+
+uniform vec4 u_inv_view_dims;
+
+void main()
+{
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
+ v_texcoord0 = a_texcoord0;
+ v_color0 = a_color0;
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/lcd-grid/vs_persistence.sc b/src/osd/modules/render/bgfx/shaders/chains/lcd-grid/vs_persistence.sc
new file mode 100644
index 00000000000..df2b37f203c
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/lcd-grid/vs_persistence.sc
@@ -0,0 +1,19 @@
+$input a_position, a_texcoord0, a_color0
+$output v_texcoord0, v_color0
+
+// license:BSD-3-Clause
+// copyright-holders:Dario Manesku
+
+#include "common.sh"
+
+uniform vec4 u_inv_view_dims;
+
+void main()
+{
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
+ v_texcoord0 = a_texcoord0;
+ v_color0 = a_color0;
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/misc/fs_blit_bcg.sc b/src/osd/modules/render/bgfx/shaders/chains/misc/fs_blit_bcg.sc
new file mode 100644
index 00000000000..37d64462c51
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/misc/fs_blit_bcg.sc
@@ -0,0 +1,24 @@
+$input v_color0, v_texcoord0
+
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+
+#include "common.sh"
+
+// Samplers
+SAMPLER2D(s_tex, 0);
+SAMPLER2D(s_pal, 1);
+
+uniform vec4 u_inv_tex_size1;
+
+void main()
+{
+ vec4 src = texture2D(s_tex, v_texcoord0);
+ vec2 blu_uv = vec2(src.b * 256.0, 0.0) * u_inv_tex_size1.xy;
+ vec2 grn_uv = vec2(src.g * 256.0, 1.0) * u_inv_tex_size1.xy;
+ vec2 red_uv = vec2(src.r * 256.0, 2.0) * u_inv_tex_size1.xy;
+ float blu = texture2D(s_pal, blu_uv).b;
+ float grn = texture2D(s_pal, grn_uv).g;
+ float red = texture2D(s_pal, red_uv).r;
+ gl_FragColor = vec4(red, grn, blu, src.a) * v_color0;
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/misc/fs_blit_palette16.sc b/src/osd/modules/render/bgfx/shaders/chains/misc/fs_blit_palette16.sc
new file mode 100644
index 00000000000..6ecfbcb1a72
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/misc/fs_blit_palette16.sc
@@ -0,0 +1,37 @@
+$input v_color0, v_texcoord0
+
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+
+#include "common.sh"
+
+// Samplers
+SAMPLER2D(s_tex, 0);
+SAMPLER2D(s_pal, 1);
+
+uniform vec4 u_tex_size0;
+uniform vec4 u_inv_tex_size0;
+uniform vec4 u_inv_tex_size1;
+
+void main()
+{
+ vec2 original_uv = v_texcoord0.xy * u_tex_size0.xy * vec2(2.0, 1.0);
+ float mod_val = mod(original_uv.x, 4.0);
+ vec2 rounded_uv = vec2(original_uv.x - mod_val, original_uv.y) * vec2(0.5, 1.0);
+
+ float inv_width = u_inv_tex_size0.x * 0.5;
+
+ vec2 palette_uv = vec2(0.0, 0.0);
+ if (mod_val < 2.0)
+ {
+ palette_uv.x = texture2D(s_tex, rounded_uv * u_inv_tex_size0.xy + vec2(inv_width * 0.5, 0.0)).r;
+ palette_uv.y = texture2D(s_tex, rounded_uv * u_inv_tex_size0.xy + vec2(inv_width * 1.5, 0.0)).r;
+ }
+ else
+ {
+ palette_uv.x = texture2D(s_tex, rounded_uv * u_inv_tex_size0.xy + vec2(inv_width * 2.5, 0.0)).r;
+ palette_uv.y = texture2D(s_tex, rounded_uv * u_inv_tex_size0.xy + vec2(inv_width * 3.5, 0.0)).r;
+ }
+
+ gl_FragColor = vec4(texture2D(s_pal, palette_uv * vec2(256.0, 256.0) * u_inv_tex_size1.xy).rgb, 1.0) * v_color0;
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/misc/fs_blit_rgb32.sc b/src/osd/modules/render/bgfx/shaders/chains/misc/fs_blit_rgb32.sc
new file mode 100644
index 00000000000..4292e6cddc6
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/misc/fs_blit_rgb32.sc
@@ -0,0 +1,14 @@
+$input v_color0, v_texcoord0
+
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+
+#include "common.sh"
+
+// Samplers
+SAMPLER2D(s_tex, 0);
+
+void main()
+{
+ gl_FragColor = vec4(texture2D(s_tex, v_texcoord0).rgb, 1.0) * v_color0;
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/misc/fs_blit_yuy16.sc b/src/osd/modules/render/bgfx/shaders/chains/misc/fs_blit_yuy16.sc
new file mode 100644
index 00000000000..af3eb3e3954
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/misc/fs_blit_yuy16.sc
@@ -0,0 +1,38 @@
+$input v_color0, v_texcoord0
+
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+
+#include "common.sh"
+
+// Samplers
+SAMPLER2D(s_tex, 0);
+
+uniform vec4 u_tex_size0;
+uniform vec4 u_inv_tex_size0;
+
+vec3 ycc_to_rgb(float y, float cb, float cr)
+{
+ float common = 1.168627 * (y - 0.062745);
+ float r = saturate(common + 1.603922 * (cr - 0.5));
+ float g = saturate(common - 0.392157 * (cb - 0.5) - 0.815686 * (cr - 0.5));
+ float b = saturate(common + 2.023529 * (cb - 0.5));
+ return vec3(r, g, b);
+}
+
+void main()
+{
+ vec2 half_texel = u_inv_tex_size0.xy * vec2(0.5, 0.5);
+
+ vec2 original_uv = v_texcoord0.xy * u_tex_size0.xy;
+ float mod_val = mod(original_uv.x, 2.0);
+ vec2 rounded_uv = vec2(original_uv.x - mod_val, original_uv.y);
+ vec4 srcpix = texture2D(s_tex, rounded_uv * u_inv_tex_size0.xy + half_texel.x);
+
+ float cr = srcpix.r;
+ float cb = srcpix.b;
+ if (mod_val < 1.0)
+ gl_FragColor = vec4(ycc_to_rgb(srcpix.g, cb, cr), 1.0) * v_color0;
+ else
+ gl_FragColor = vec4(ycc_to_rgb(srcpix.a, cb, cr), 1.0) * v_color0;
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/misc/fs_bob-and-ghost-deinterlace.sc b/src/osd/modules/render/bgfx/shaders/chains/misc/fs_bob-and-ghost-deinterlace.sc
index 45d38a0e020..d69e9a8f7bc 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/misc/fs_bob-and-ghost-deinterlace.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/misc/fs_bob-and-ghost-deinterlace.sc
@@ -7,7 +7,7 @@ $input v_color0, v_texcoord0
Bob-and-ghost Deinterlacing
Author: hunterk
License: Public domain
-
+
Note: This shader is designed to work with the typical interlaced output from an emulator, which displays both even and odd fields twice.
As such, it is inappropriate for general video use unless the video has already been similarly woven beforehand.
*/
@@ -30,7 +30,7 @@ void main()
float y;
// assume anything with a vertical resolution greater than 400 lines is interlaced
- if (u_tex_size0.y > 400.0)
+ if (u_tex_size0.y > 400.0)
{
y = u_tex_size0.y * v_texcoord0.y;// FIXME + IN.frame_count;
res = pow(vec4(texture2D(s0, v_texcoord0 + vec2(0.0, one_pixel.y))), exponent);
@@ -50,6 +50,6 @@ void main()
{
res = vec4(pow(texture2D(s0, v_texcoord0), exponent));
}
-
+
gl_FragColor = vec4(pow((res + color) / 2.0, inv_exponent));
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/misc/fs_deposterize-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/misc/fs_deposterize-pass0.sc
index cbff9f450e8..090485da1bc 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/misc/fs_deposterize-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/misc/fs_deposterize-pass0.sc
@@ -5,7 +5,7 @@ $input v_color0, v_texcoord0, v_texcoord1
/*
Hyllian's Deposterize Shader - Pass0
-
+
Copyright (C) 2011/2016 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -20,7 +20,7 @@ uniform vec4 DIFF_THRESH1;
vec3 df3(vec3 c1, vec3 c2)
{
- return abs(c1 - c2);
+ return abs(c1 - c2);
}
bvec3 le3(vec3 A, vec3 B, vec3 param)
diff --git a/src/osd/modules/render/bgfx/shaders/chains/misc/fs_deposterize-pass1.sc b/src/osd/modules/render/bgfx/shaders/chains/misc/fs_deposterize-pass1.sc
index c6e0e87b018..085f767358c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/misc/fs_deposterize-pass1.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/misc/fs_deposterize-pass1.sc
@@ -5,7 +5,7 @@ $input v_color0, v_texcoord0, v_texcoord1
/*
Hyllian's Deposterize Shader - Pass1
-
+
Copyright (C) 2011/2016 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -20,7 +20,7 @@ uniform vec4 DIFF_THRESH2;
vec3 df3(vec3 c1, vec3 c2)
{
- return abs(c1 - c2);
+ return abs(c1 - c2);
}
bvec3 le3(vec3 A, vec3 B, vec3 param)
diff --git a/src/osd/modules/render/bgfx/shaders/chains/misc/fs_lut.sc b/src/osd/modules/render/bgfx/shaders/chains/misc/fs_lut.sc
index 2c8cffab7e1..6b00e4a1934 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/misc/fs_lut.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/misc/fs_lut.sc
@@ -5,9 +5,9 @@ $input v_color0, v_texcoord0
#include "common.sh"
-#define LUT_TEXTURE_WIDTH 4096.0f
-#define LUT_SIZE 64.0f
-#define LUT_SCALE vec2(1.0f / LUT_TEXTURE_WIDTH, 1.0f / LUT_SIZE)
+// Autos
+uniform vec4 u_tex_size1;
+uniform vec4 u_inv_tex_size1;
SAMPLER2D(s_tex, 0);
SAMPLER2D(s_3dlut, 1);
@@ -17,13 +17,12 @@ void main()
vec4 bp = texture2D(s_tex, v_texcoord0);
vec3 color = bp.rgb;
// NOTE: Do not change the order of parameters here.
- vec3 lutcoord = vec3(color.rg * ((LUT_SIZE - 1.0f) + 0.5f) *
- LUT_SCALE, (LUT_SIZE - 1.0f) * color.b);
+ vec3 lutcoord = vec3(color.rg * ((u_tex_size1.y - 1.0) + 0.5) * u_inv_tex_size1.xy, (u_tex_size1.y - 1.0) * color.b);
float shift = floor(lutcoord.z);
- lutcoord.x += shift * LUT_SCALE.y;
+ lutcoord.x += shift * u_inv_tex_size1.y;
color.rgb = mix(texture2D(s_3dlut, lutcoord.xy).rgb,
- texture2D(s_3dlut, vec2(lutcoord.x + LUT_SCALE.y,
+ texture2D(s_3dlut, vec2(lutcoord.x + u_inv_tex_size1.y,
lutcoord.y)).rgb, lutcoord.z - shift);
gl_FragColor = vec4(color, bp.a) * v_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/misc/vs_blit.sc b/src/osd/modules/render/bgfx/shaders/chains/misc/vs_blit.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/misc/vs_blit.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/misc/vs_blit.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/misc/vs_bob-and-ghost-deinterlace.sc b/src/osd/modules/render/bgfx/shaders/chains/misc/vs_bob-and-ghost-deinterlace.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/misc/vs_bob-and-ghost-deinterlace.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/misc/vs_bob-and-ghost-deinterlace.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/misc/vs_deposterize-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/misc/vs_deposterize-pass0.sc
index 1c3b3ee592f..1ed054f1b9a 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/misc/vs_deposterize-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/misc/vs_deposterize-pass0.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_color0
/*
Hyllian's Deposterize Shader - Pass0 vertex shader
-
+
Copyright (C) 2011/2016 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -14,15 +14,19 @@ $output v_texcoord0, v_texcoord1, v_color0
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
vec2 ps = vec2(1.0 / u_tex_size0.xy);
float dx = ps.x;
float dy = ps.y;
-
+
// This line fixes a bug in ATI cards.
v_texcoord0 = a_texcoord0 + vec2(0.0000001, 0.0000001);
v_texcoord1 = v_texcoord0.xxxy + vec4(-dx, 0, dx, 0); // D E F
diff --git a/src/osd/modules/render/bgfx/shaders/chains/misc/vs_deposterize-pass1.sc b/src/osd/modules/render/bgfx/shaders/chains/misc/vs_deposterize-pass1.sc
index 7af87394655..69a23cb477c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/misc/vs_deposterize-pass1.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/misc/vs_deposterize-pass1.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_color0
/*
Hyllian's Deposterize Shader - Pass1 vertex shader
-
+
Copyright (C) 2011/2016 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -14,15 +14,19 @@ $output v_texcoord0, v_texcoord1, v_color0
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
vec2 ps = vec2(1.0 / u_tex_size0.xy);
float dx = ps.x;
float dy = ps.y;
-
+
// This line fixes a bug in ATI cards.
v_texcoord0 = a_texcoord0 + vec2(0.0000001, 0.0000001);
v_texcoord1 = v_texcoord0.xyyy + vec4(0, -dy, 0, dy); // D E F
diff --git a/src/osd/modules/render/bgfx/shaders/chains/misc/vs_lut.sc b/src/osd/modules/render/bgfx/shaders/chains/misc/vs_lut.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/misc/vs_lut.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/misc/vs_lut.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/misc/vs_resize_blit.sc b/src/osd/modules/render/bgfx/shaders/chains/misc/vs_resize_blit.sc
new file mode 100644
index 00000000000..0a9f2f178e1
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/misc/vs_resize_blit.sc
@@ -0,0 +1,21 @@
+$input a_position, a_texcoord0, a_color0
+$output v_texcoord0, v_color0
+
+// license:BSD-3-Clause
+// copyright-holders:Dario Manesku
+
+#include "common.sh"
+
+uniform vec4 u_inv_view_dims;
+uniform vec4 u_tex_bounds0;
+
+void main()
+{
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
+
+ v_texcoord0 = a_texcoord0 * (u_tex_bounds0.zw - u_tex_bounds0.xy) + u_tex_bounds0.xy;
+ v_color0 = a_color0;
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/misc/vs_saturation.sc b/src/osd/modules/render/bgfx/shaders/chains/misc/vs_saturation.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/misc/vs_saturation.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/misc/vs_saturation.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_horizontal/fs_gaussian.sc b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_horizontal/fs_gaussian.sc
index 5375561e8ac..cb6ecf95f0d 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_horizontal/fs_gaussian.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_horizontal/fs_gaussian.sc
@@ -22,7 +22,7 @@ SAMPLER2D(s_tex, 0);
void main()
{
vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
-
+
vec2 blur = (u_radius.xx * u_dimension.xy) / u_tex_size0.xy;
sum += texture2D(s_tex, v_texcoord0 - vec2(12.0, 12.0) * blur) * 0.001133;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_horizontal/vs_gaussian.sc b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_horizontal/vs_gaussian.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_horizontal/vs_gaussian.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_horizontal/vs_gaussian.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_horizontal/vs_offset_sat.sc b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_horizontal/vs_offset_sat.sc
index f071beaaa26..77d392ad813 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_horizontal/vs_offset_sat.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_horizontal/vs_offset_sat.sc
@@ -9,9 +9,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
- gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0 * vec2(0.16666666 * 0.9, 1.0 * 0.8) + vec2(0.1, 0.1);
v_color0 = a_color0;
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_vertical/fs_gaussian.sc b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_vertical/fs_gaussian.sc
index 5375561e8ac..cb6ecf95f0d 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_vertical/fs_gaussian.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_vertical/fs_gaussian.sc
@@ -22,7 +22,7 @@ SAMPLER2D(s_tex, 0);
void main()
{
vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
-
+
vec2 blur = (u_radius.xx * u_dimension.xy) / u_tex_size0.xy;
sum += texture2D(s_tex, v_texcoord0 - vec2(12.0, 12.0) * blur) * 0.001133;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_vertical/vs_gaussian.sc b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_vertical/vs_gaussian.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_vertical/vs_gaussian.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_vertical/vs_gaussian.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_vertical/vs_offset_sat.sc b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_vertical/vs_offset_sat.sc
index a9f6649c1e5..6d47076f992 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_vertical/vs_offset_sat.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_left_vertical/vs_offset_sat.sc
@@ -9,9 +9,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
- gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0 * vec2(1.0 * 0.8, 0.685185 * 0.9) + vec2(0.1, 0.1);
v_color0 = a_color0;
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_horizontal/fs_gaussian.sc b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_horizontal/fs_gaussian.sc
index 5375561e8ac..cb6ecf95f0d 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_horizontal/fs_gaussian.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_horizontal/fs_gaussian.sc
@@ -22,7 +22,7 @@ SAMPLER2D(s_tex, 0);
void main()
{
vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
-
+
vec2 blur = (u_radius.xx * u_dimension.xy) / u_tex_size0.xy;
sum += texture2D(s_tex, v_texcoord0 - vec2(12.0, 12.0) * blur) * 0.001133;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_horizontal/vs_gaussian.sc b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_horizontal/vs_gaussian.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_horizontal/vs_gaussian.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_horizontal/vs_gaussian.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_horizontal/vs_offset_sat.sc b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_horizontal/vs_offset_sat.sc
index a473bc4123c..403b880b5ec 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_horizontal/vs_offset_sat.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_horizontal/vs_offset_sat.sc
@@ -9,9 +9,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
- gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0 * vec2(0.16666666 * 0.9, 1.0 * 0.8) + vec2(0.9 - 0.16666666 * 0.9, 0.1);
v_color0 = a_color0;
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_vertical/fs_gaussian.sc b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_vertical/fs_gaussian.sc
index 5375561e8ac..cb6ecf95f0d 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_vertical/fs_gaussian.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_vertical/fs_gaussian.sc
@@ -22,7 +22,7 @@ SAMPLER2D(s_tex, 0);
void main()
{
vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
-
+
vec2 blur = (u_radius.xx * u_dimension.xy) / u_tex_size0.xy;
sum += texture2D(s_tex, v_texcoord0 - vec2(12.0, 12.0) * blur) * 0.001133;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_vertical/vs_gaussian.sc b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_vertical/vs_gaussian.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_vertical/vs_gaussian.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_vertical/vs_gaussian.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_vertical/vs_offset_sat.sc b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_vertical/vs_offset_sat.sc
index 8af6a293d8e..7121ae6651c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_vertical/vs_offset_sat.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/pillarbox_right_vertical/vs_offset_sat.sc
@@ -9,9 +9,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
- gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0 * vec2(1.0 * 0.8, 0.685185 * 0.9) + vec2(0.1, 0.9 - 0.685185 * 0.9);
v_color0 = a_color0;
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/unfiltered/vs_blit.sc b/src/osd/modules/render/bgfx/shaders/chains/unfiltered/vs_blit.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/unfiltered/vs_blit.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/unfiltered/vs_blit.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/warp/fs_dilation-horizontal-fast.sc b/src/osd/modules/render/bgfx/shaders/chains/warp/fs_dilation-horizontal-fast.sc
index 3f03d8e6adb..d4ba6141c82 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/warp/fs_dilation-horizontal-fast.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/warp/fs_dilation-horizontal-fast.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_color0
/*
Hyllian's dilation-horizontal-fast Shader
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -43,4 +43,4 @@ void main()
vec3 res = max(E, max(F, D));
gl_FragColor = vec4(res, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/warp/vs_dilation-horizontal-fast.sc b/src/osd/modules/render/bgfx/shaders/chains/warp/vs_dilation-horizontal-fast.sc
index 828dc3078cf..52e0fc2ae90 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/warp/vs_dilation-horizontal-fast.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/warp/vs_dilation-horizontal-fast.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_color0
/*
Hyllian's dilation-horizontal-fast Shader
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -32,20 +32,24 @@ $output v_texcoord0, v_texcoord1, v_color0
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
vec2 ps = 1.0 / u_tex_size0.xy;
float dx = ps.x;
float dy = ps.y;
- // B
- // D E F
- // H
+ // B
+ // D E F
+ // H
- v_texcoord1 = vec4(1.0 / u_tex_size0.xy, 0.0, 0.0); // F H
+ v_texcoord1 = vec4(1.0 / u_tex_size0.xy, 0.0, 0.0); // F H
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv1-noblend.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv1-noblend.sc
index 72212fa74a7..1963dfcd617 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv1-noblend.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv1-noblend.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_color0
/*
Hyllian's xBR-lv1-noblend Shader
-
+
Copyright (C) 2011-2014 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -129,4 +129,4 @@ void main()
// final sum and weight normalization
gl_FragColor = vec4(res, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv2-3d.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv2-3d.sc
index d9e44f0d4c7..988699a2642 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv2-3d.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv2-3d.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texcoo
/*
Hyllian's xBR-lv2-3d Shader
-
+
Copyright (C) 2011-2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -176,7 +176,7 @@ void main()
vec4 Ci = vec4(0.25, 0.25, 0.25, 0.25);
// These inequations define the line below which interpolation occurs.
- vec4 fx = (Ao*fp.y+Bo*fp.x);
+ vec4 fx = (Ao*fp.y+Bo*fp.x);
vec4 fx_left = (Ax*fp.y+Bx*fp.x);
vec4 fx_up = (Ay*fp.y+By*fp.x);
@@ -231,13 +231,13 @@ void main()
vec3 res1 = E.xyz;
res1 = mix(res1, mix(H.xyz, F.xyz, px.x), maximos.x);
res1 = mix(res1, mix(B.xyz, D.xyz, px.z), maximos.z);
-
+
vec3 res2 = E.xyz;
res2 = mix(res2, mix(F.xyz, B.xyz, px.y), maximos.y);
res2 = mix(res2, mix(D.xyz, H.xyz, px.w), maximos.w);
-
+
vec3 E_mix = (c_df(E.xyz, res2) >= c_df(E.xyz, res1)) ? vec3(1.0, 1.0, 1.0) : vec3(0.0, 0.0, 0.0);
vec3 res = mix(res1, res2, E_mix);
gl_FragColor = vec4(res, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv2-fast.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv2-fast.sc
index 1b47172209e..b4d461cfca0 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv2-fast.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv2-fast.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_color0
/*
Hyllian's xBR-lv2-lq Shader
-
+
Copyright (C) 2011/2015 Hyllian/Jararaca - sergiogdb@gmail.com
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
@@ -121,7 +121,7 @@ void main()
vec4 Ci = vec4(0.25, 0.25, 0.25, 0.25);
// These inequations define the line below which interpolation occurs.
- vec4 fx = (Ao*fp.y+Bo*fp.x);
+ vec4 fx = (Ao*fp.y+Bo*fp.x);
vec4 fx_left = (Ax*fp.y+Bx*fp.x);
vec4 fx_up = (Ay*fp.y+By*fp.x);
@@ -166,13 +166,13 @@ void main()
vec3 res1 = E.xyz;
res1 = mix(res1, mix(H.xyz, F.xyz, px.x), maximos.x);
res1 = mix(res1, mix(B.xyz, D.xyz, px.z), maximos.z);
-
+
vec3 res2 = E.xyz;
res2 = mix(res2, mix(F.xyz, B.xyz, px.y), maximos.y);
res2 = mix(res2, mix(D.xyz, H.xyz, px.w), maximos.w);
-
+
vec3 E_mix = (c_df(E.xyz, res2) >= c_df(E.xyz, res1)) ? vec3(1.0, 1.0, 1.0) : vec3(0.0, 0.0, 0.0);
vec3 res = mix(res1, res2, E_mix);
gl_FragColor = vec4(res, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv2-noblend.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv2-noblend.sc
index 80d7269349e..3168daf2ba8 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv2-noblend.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv2-noblend.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texcoo
/*
Hyllian's xBR-lv2-noblend Shader
-
+
Copyright (C) 2011-2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -148,7 +148,7 @@ void main()
#endif
interp_restriction_lv1 = clamp(interp_restriction_lv1, 0.0, 1.0);
-
+
vec4 interp_restriction_lv2_left = vec4(notEqual(e,g)) * vec4(notEqual(d,g));
vec4 interp_restriction_lv2_up = vec4(notEqual(e,c)) * vec4(notEqual(b,c));
@@ -174,4 +174,4 @@ void main()
vec3 res = mix(res1, res2, res_mix);
gl_FragColor = vec4(res, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv2.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv2.sc
index 0294c56b84f..75a6dd3296f 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv2.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv2.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texcoo
/*
Hyllian's xBR-lv2 Shader
-
+
Copyright (C) 2011-2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -136,10 +136,10 @@ void main()
vec4 Ci = vec4(0.25, 0.25, 0.25, 0.25);
// These inequations define the line below which interpolation occurs.
- vec4 fx = (Ao*fp.y+Bo*fp.x);
+ vec4 fx = (Ao*fp.y+Bo*fp.x);
vec4 fx_left = (Ax*fp.y+Bx*fp.x);
vec4 fx_up = (Ay*fp.y+By*fp.x);
-
+
vec4 interp_restriction_lv0 = vec4(notEqual(e,f)) * vec4(notEqual(e,h));
vec4 interp_restriction_lv1 = interp_restriction_lv0;
@@ -191,7 +191,7 @@ void main()
vec3 res1 = E.xyz;
res1 = mix(res1, mix(H.xyz, F.xyz, px.x), maximos.x);
res1 = mix(res1, mix(B.xyz, D.xyz, px.z), maximos.z);
-
+
vec3 res2 = E.xyz;
res2 = mix(res2, mix(F.xyz, B.xyz, px.y), maximos.y);
res2 = mix(res2, mix(D.xyz, H.xyz, px.w), maximos.w);
@@ -200,4 +200,4 @@ void main()
vec3 res = mix(res1, res2, E_mix);
gl_FragColor = vec4(res, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv3-noblend.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv3-noblend.sc
index 554c222db47..b13606724e5 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv3-noblend.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv3-noblend.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texcoo
/*
Hyllian's xBR-lv3-noblend - Shader
-
+
Copyright (C) 2011/2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -175,7 +175,7 @@ void main()
#endif
interp_restriction_lv1 = clamp(interp_restriction_lv1, 0.0, 1.0);
-
+
vec4 interp_restriction_lv2_left = vec4(notEqual(e,g)) * vec4(notEqual(d,g));
vec4 interp_restriction_lv2_up = vec4(notEqual(e,c)) * vec4(notEqual(b,c));
vec4 interp_restriction_lv3_left = eq2(g,g0) * vec4(notEqual(d0,g0));
@@ -186,11 +186,11 @@ void main()
vec4 one = vec4(1.0, 1.0, 1.0, 1.0);
vec4 zero = vec4(0.0, 0.0, 0.0, 0.0);
-
+
vec4 edri = vec4(lessThanEqual(wd1,wd2)) * interp_restriction_lv1;
vec4 edr = vec4(lessThan(wd1,wd2)) * interp_restriction_lv1 * ((1.0 - edri.yzwx) + (1.0 - edri.wxyz));
edr = clamp(edr, 0.0, 1.0);
-
+
vec4 hcDiff = df(h,c);
vec4 fgDiff = df(f,g);
vec4 edr_left = vec4(lessThanEqual(XBR_LV2_COEFFICIENT.xxxx * fgDiff, hcDiff)) * interp_restriction_lv2_left * edr * (1.0 - edri.yzwx) * eq(e,c);
@@ -210,4 +210,4 @@ void main()
vec3 res = mix(res1, res2, (df12.y >= df12.x) ? one.xyz : zero.xyz);
gl_FragColor = vec4(res, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv3.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv3.sc
index 162461d145b..e6a4eb79edb 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv3.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/fs_xbr-lv3.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texcoo
/*
Hyllian's xBR-lv3 Shader
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -154,7 +154,7 @@ void main()
vec4 Cw = vec4( 5.0, -1.0, -3.0, 3.0 );
// These inequations define the line below which interpolation occurs.
- vec4 fx = (Ao * fp.y + Bo * fp.x);
+ vec4 fx = (Ao * fp.y + Bo * fp.x);
vec4 fx_left = (Ax * fp.y + Bx * fp.x);
vec4 fx_up = (Ay * fp.y + By * fp.x);
vec4 fx3_left= (Az * fp.y + Bz * fp.x);
@@ -189,7 +189,7 @@ void main()
vec4 edr = vec4(lessThan(weighted_distance(e, c, g, i, h5, f4, h, f), weighted_distance( h, d, i5, f, i4, b, e, i))) * interp_restriction_lv1;
vec4 edr_left = vec4(lessThanEqual(XBR_LV2_COEFFICIENT.xxxx * df(f,g), df(h,c))) * interp_restriction_lv2_left;
vec4 edr_up = vec4(greaterThanEqual(df(f,g), XBR_LV2_COEFFICIENT.xxxx * df(h,c))) * interp_restriction_lv2_up;
-
+
vec4 edr3_left = interp_restriction_lv3_left;
vec4 edr3_up = interp_restriction_lv3_up;
@@ -232,4 +232,4 @@ void main()
vec3 res = mix(res1, res2, E_mix);
gl_FragColor = vec4(res, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_custom-jinc2-sharper.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_custom-jinc2-sharper.sc
index 0abd7ff41c9..fd9a2d72f94 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_custom-jinc2-sharper.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_custom-jinc2-sharper.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_color0
/*
Hyllian's jinc windowed-jinc 2-lobe sharper with anti-ringing Shader
-
+
Copyright (C) 2011-2014 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -18,14 +18,14 @@ uniform vec4 u_tex_size0;
SAMPLER2D(s_p, 0);
- /*
- This is an approximation of Jinc(x)*Jinc(x*r1/r2) for x < 2.5,
- where r1 and r2 are the first two zeros of jinc function.
- For a jinc 2-lobe best approximation, use A=0.5 and B=0.825.
- */
+/*
+ This is an approximation of Jinc(x)*Jinc(x*r1/r2) for x < 2.5,
+ where r1 and r2 are the first two zeros of jinc function.
+ For a jinc 2-lobe best approximation, use A=0.5 and B=0.825.
+*/
// A=0.5, B=0.825 is the best jinc approximation for x<2.5. if B=1.0, it's a lanczos filter.
-// Increase A to get more blur. Decrease it to get a sharper picture.
+// Increase A to get more blur. Decrease it to get a sharper picture.
// B = 0.825 to get rid of dithering. Increase B to get a fine sharpness, though dithering returns.
#define halfpi 1.5707963267948966192313216916398
@@ -47,12 +47,12 @@ float d(vec2 pt1, vec2 pt2)
vec4 min4(vec4 a, vec4 b, vec4 c, vec4 d)
{
- return min(a, min(b, min(c, d)));
+ return min(a, min(b, min(c, d)));
}
vec4 max4(vec4 a, vec4 b, vec4 c, vec4 d)
{
- return max(a, max(b, max(c, d)));
+ return max(a, max(b, max(c, d)));
}
vec4 resampler(vec4 x)
@@ -131,4 +131,4 @@ void main()
// final sum and weight normalization
gl_FragColor = vec4(color, 1);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-2xbr-3d-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-2xbr-3d-pass0.sc
index 8fa47570af5..fdb38420261 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-2xbr-3d-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-2xbr-3d-pass0.sc
@@ -4,9 +4,9 @@ $input v_texcoord0, v_color0
// copyright-holders:Hyllian
/*
-
+
******* Super XBR 3D Shader - pass0 *******
-
+
Copyright (c) 2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -95,23 +95,23 @@ float hv_wd(float i1, float i2, float i3, float i4, float e1, float e2, float e3
vec4 min4(vec4 a, vec4 b, vec4 c, vec4 d)
{
- return min(a, min(b, min(c, d)));
+ return min(a, min(b, min(c, d)));
}
vec4 max4(vec4 a, vec4 b, vec4 c, vec4 d)
{
- return max(a, max(b, max(c, d)));
+ return max(a, max(b, max(c, d)));
}
void main()
{
//Skip pixels on wrong grid
vec2 fraction = fract(v_texcoord0 * u_tex_size0.xy / XBR_RES);
- if (fraction.x < 0.5 || fraction.y < 0.5)
- {
- gl_FragColor = texture2D(s0, v_texcoord0);
- return;
- }
+ if (fraction.x < 0.5 || fraction.y < 0.5)
+ {
+ gl_FragColor = texture2D(s0, v_texcoord0);
+ return;
+ }
vec2 tex = (floor(v_texcoord0 * u_tex_size0.xy / XBR_RES) + vec2(0.5, 0.5)) * XBR_RES / u_tex_size0.xy;
@@ -224,4 +224,4 @@ void main()
color = block_3d ? color : E.xyz;
gl_FragColor = vec4(color, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-2xbr-3d-pass1.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-2xbr-3d-pass1.sc
index 72009ad3335..2af3f086523 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-2xbr-3d-pass1.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-2xbr-3d-pass1.sc
@@ -4,9 +4,9 @@ $input v_texcoord0, v_color0
// copyright-holders:Hyllian
/*
-
+
******* Super XBR 3D Shader - pass0 *******
-
+
Copyright (c) 2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -208,4 +208,4 @@ void main()
color = block_3d ? color : A;
gl_FragColor = vec4(color, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-2xbr-3d-pass2.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-2xbr-3d-pass2.sc
index c2656424ed6..1f205de0a1b 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-2xbr-3d-pass2.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-2xbr-3d-pass2.sc
@@ -4,9 +4,9 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_color0
// copyright-holders:Hyllian
/*
-
+
******* Super XBR 3D Shader - pass2 *******
-
+
Copyright (c) 2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -210,4 +210,4 @@ void main()
color = block_3d ? color : A.xyz;
gl_FragColor = vec4(color, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass0.sc
index 8a56a3899a6..389435952a7 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass0.sc
@@ -4,9 +4,9 @@ $input v_texcoord0, v_color0
// copyright-holders:Hyllian
/*
-
+
******* Super 4XBR 3D Shader - pass0 *******
-
+
Copyright (c) 2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -214,4 +214,4 @@ void main()
color = block_3d ? color : E.xyz;
gl_FragColor = vec4(color, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass1.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass1.sc
index 10288b45f5a..1c805080595 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass1.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass1.sc
@@ -4,9 +4,9 @@ $input v_texcoord0, v_color0
// copyright-holders:Hyllian
/*
-
+
******* Super 4XBR 3D Shader - pass1 *******
-
+
Copyright (c) 2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -207,4 +207,4 @@ void main()
color = block_3d ? color : A.xyz;
gl_FragColor = vec4(color, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass1f.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass1f.sc
index 51f2c6ea887..4587dc9cc93 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass1f.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass1f.sc
@@ -4,9 +4,9 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_color0
// copyright-holders:Hyllian
/*
-
+
******* Super 4XBR 3D Shader - pass1 *******
-
+
Copyright (c) 2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -208,4 +208,4 @@ void main()
color = block_3d ? color : A.xyz;
gl_FragColor = vec4(color, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass2.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass2.sc
index f1566381325..1f9727021d7 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass2.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass2.sc
@@ -4,9 +4,9 @@ $input v_texcoord0, v_color0
// copyright-holders:Hyllian
/*
-
+
******* Super 4XBR 3D Shader - pass2 *******
-
+
Copyright (c) 2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -223,4 +223,4 @@ void main()
color = block_3d ? color : E.xyz;
gl_FragColor = vec4(color, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass3.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass3.sc
index 3aa921a0e37..3e06eb4da47 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass3.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass3.sc
@@ -4,9 +4,9 @@ $input v_texcoord0, v_color0
// copyright-holders:Hyllian
/*
-
+
******* Super 4XBR 3D Shader - pass3 *******
-
+
Copyright (c) 2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -207,4 +207,4 @@ void main()
color = block_3d ? color : A.xyz;
gl_FragColor = vec4(color, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass3f.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass3f.sc
index b417613a657..2b119f5d066 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass3f.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-4xbr-3d-pass3f.sc
@@ -4,9 +4,9 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_color0
// copyright-holders:Hyllian
/*
-
+
******* Super 4XBR 3D Shader - pass3 *******
-
+
Copyright (c) 2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -208,4 +208,4 @@ void main()
color = block_3d ? color : A.xyz;
gl_FragColor = vec4(color, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-fast-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-fast-pass0.sc
index 84fc371a0a7..45bfdb1543b 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-fast-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-fast-pass0.sc
@@ -4,9 +4,9 @@ $input v_texcoord0, v_color0
// copyright-holders:Hyllian
/*
-
+
******* Super XBR Shader - pass0 *******
-
+
Copyright (c) 2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -161,9 +161,9 @@ void main()
vec4 d_mix = d_edge >= 0.0 ? vec4(1.0, 1.0, 1.0, 1.0) : vec4(0.0, 0.0, 0.0, 0.0);
vec4 min_sample = min4(E, F, H, I) + anti_ring * mix((P2-H)*(F-P1), (P0-E)*(I-P3), d_mix);
vec4 max_sample = max4(E, F, H, I) - anti_ring * mix((P2-H)*(F-P1), (P0-E)*(I-P3), d_mix);
-
+
color = clamp(color, min_sample.xyz, max_sample.xyz);
// color = mix(aux, color, 1-2.0*abs(edge_strength-0.5));
gl_FragColor = vec4(color, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-fast-pass1.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-fast-pass1.sc
index d67c215de66..0248c9f2357 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-fast-pass1.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-fast-pass1.sc
@@ -4,9 +4,9 @@ $input v_texcoord0, v_color0
// copyright-holders:Hyllian
/*
-
+
******* Super XBR Shader - pass1 *******
-
+
Copyright (c) 2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -155,5 +155,5 @@ void main()
color = clamp(color, min_sample.xyz, max_sample.xyz);
// color = mix(aux, color, 1-2.0*abs(edge_strength-0.5));
- gl_FragColor = vec4(color, 1.0);
-} \ No newline at end of file
+ gl_FragColor = vec4(color, 1.0);
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-fast-pass2.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-fast-pass2.sc
index 89e82d00a31..546525c861d 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-fast-pass2.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-fast-pass2.sc
@@ -4,9 +4,9 @@ $input v_texcoord0, v_color0
// copyright-holders:Hyllian
/*
-
+
******* Super XBR Shader - pass1 *******
-
+
Copyright (c) 2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -158,5 +158,5 @@ void main()
color = clamp(color, min_sample.xyz, max_sample.xyz);
// color = mix(aux, color, 1-2.0*abs(edge_strength-0.5));
- gl_FragColor = vec4(color, 1.0);
-} \ No newline at end of file
+ gl_FragColor = vec4(color, 1.0);
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-pass0.sc
index a1158ebecca..ebae083c9c5 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-pass0.sc
@@ -4,9 +4,9 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_color0
// copyright-holders:Hyllian
/*
-
+
******* Super XBR Shader - pass0 *******
-
+
Copyright (c) 2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -157,4 +157,4 @@ void main()
color = clamp(color, min_sample.xyz, max_sample.xyz);
gl_FragColor = vec4(color, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-pass1.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-pass1.sc
index 421fc78b58c..c99b19376cd 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-pass1.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-pass1.sc
@@ -4,9 +4,9 @@ $input v_texcoord0, v_color0
// copyright-holders:Hyllian
/*
-
+
******* Super XBR Shader - pass1 *******
-
+
Copyright (c) 2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -174,5 +174,5 @@ void main()
vec4 max_sample = max4(E, F, H, I) - anti_ring * mix((P2-H)*(F-P1), (P0-E)*(I-P3), d_mix);
color = clamp(color, min_sample.xyz, max_sample.xyz);
- gl_FragColor = vec4(color, 1.0);
-} \ No newline at end of file
+ gl_FragColor = vec4(color, 1.0);
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-pass2.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-pass2.sc
index c343dc155a2..0ac5170af33 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-pass2.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/fs_super-xbr-pass2.sc
@@ -4,9 +4,9 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_color0
// copyright-holders:Hyllian
/*
-
+
******* Super XBR Shader - pass1 *******
-
+
Copyright (c) 2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -166,5 +166,5 @@ void main()
vec4 max_sample = max4(E, F, H, I) - anti_ring * mix((P2-H)*(F-P1), (P0-E)*(I-P3), d_mix);
color = clamp(color, min_sample.xyz, max_sample.xyz);
- gl_FragColor = vec4(color, 1.0);
-} \ No newline at end of file
+ gl_FragColor = vec4(color, 1.0);
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_custom-jinc2-sharper.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_custom-jinc2-sharper.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_custom-jinc2-sharper.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_custom-jinc2-sharper.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-2xbr-3d-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-2xbr-3d-pass0.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-2xbr-3d-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-2xbr-3d-pass0.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-2xbr-3d-pass1.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-2xbr-3d-pass1.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-2xbr-3d-pass1.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-2xbr-3d-pass1.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-2xbr-3d-pass2.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-2xbr-3d-pass2.sc
index ae3b049b57a..335c9ef8b4c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-2xbr-3d-pass2.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-2xbr-3d-pass2.sc
@@ -5,9 +5,9 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_color
// copyright-holders:Hyllian
/*
-
+
******* Super XBR 3D Shader - pass2 *******
-
+
Copyright (c) 2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -33,10 +33,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_color
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
vec2 ps = 1.0 / u_tex_size0.xy;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass0.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass0.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass1.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass1.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass1.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass1.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass1f.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass1f.sc
index c5bd41ee120..338cadbe4b7 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass1f.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass1f.sc
@@ -7,10 +7,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_color
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
vec2 ps = 1.0 / u_tex_size0.xy;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass2.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass2.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass2.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass2.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass3.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass3.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass3.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass3.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass3f.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass3f.sc
index c5bd41ee120..338cadbe4b7 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass3f.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-4xbr-3d-pass3f.sc
@@ -7,10 +7,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_color
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
vec2 ps = 1.0 / u_tex_size0.xy;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-fast-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-fast-pass0.sc
index 67e2a4d6250..21e16b595e4 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-fast-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-fast-pass0.sc
@@ -5,9 +5,9 @@ $output v_texcoord0, v_color0
// copyright-holders:Hyllian
/*
-
+
******* Super XBR Shader - pass0 vertex shader *******
-
+
Copyright (c) 2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -32,9 +32,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-fast-pass1.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-fast-pass1.sc
index d76ec041199..fc33723ec9d 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-fast-pass1.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-fast-pass1.sc
@@ -5,9 +5,9 @@ $output v_texcoord0, v_color0
// copyright-holders:Hyllian
/*
-
+
******* Super XBR Shader - pass1 vertex shader *******
-
+
Copyright (c) 2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -32,9 +32,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-fast-pass2.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-fast-pass2.sc
index 579ee064622..a8ec5539c0b 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-fast-pass2.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-fast-pass2.sc
@@ -5,9 +5,9 @@ $output v_texcoord0, v_color0
// copyright-holders:Hyllian
/*
-
+
******* Super XBR Shader - pass2 vertex shader *******
-
+
Copyright (c) 2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -32,9 +32,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-pass0.sc
index f03cc46e2b7..8352137204e 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-pass0.sc
@@ -5,9 +5,9 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_color
// copyright-holders:Hyllian
/*
-
+
******* Super XBR Shader - pass0 vertex shader *******
-
+
Copyright (c) 2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -33,10 +33,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_color
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
vec2 ps = 1.0 / u_tex_size0.xy;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-pass1.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-pass1.sc
index 67e2a4d6250..21e16b595e4 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-pass1.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-pass1.sc
@@ -5,9 +5,9 @@ $output v_texcoord0, v_color0
// copyright-holders:Hyllian
/*
-
+
******* Super XBR Shader - pass0 vertex shader *******
-
+
Copyright (c) 2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -32,9 +32,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-pass2.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-pass2.sc
index 51ffe87fcaa..8f2d3277665 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-pass2.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-pass2.sc
@@ -5,9 +5,9 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_color
// copyright-holders:Hyllian
/*
-
+
******* Super XBR Shader - pass0 vertex shader *******
-
+
Copyright (c) 2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -33,10 +33,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_color
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
vec2 ps = 1.0 / u_tex_size0.xy;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-pass3.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-pass3.sc
index 51ffe87fcaa..8f2d3277665 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-pass3.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/super-xbr/vs_super-xbr-pass3.sc
@@ -5,9 +5,9 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_color
// copyright-holders:Hyllian
/*
-
+
******* Super XBR Shader - pass0 vertex shader *******
-
+
Copyright (c) 2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -33,10 +33,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_color
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
vec2 ps = 1.0 / u_tex_size0.xy;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv1-noblend.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv1-noblend.sc
index 3e97446a880..de23993d020 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv1-noblend.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv1-noblend.sc
@@ -7,10 +7,14 @@ $output v_texcoord0, v_texcoord1, v_color0
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
vec2 ps = 1.0 / u_tex_size0.xy;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv2-3d.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv2-3d.sc
index a3bb4330f45..7992b9eee51 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv2-3d.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv2-3d.sc
@@ -9,10 +9,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
uniform vec4 XBR_RES;
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
vec2 ps = XBR_RES.xx / u_tex_size0.xy;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv2-fast.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv2-fast.sc
index 38e92865308..48e9664b766 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv2-fast.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv2-fast.sc
@@ -7,10 +7,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_color0
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
// A1 B1 C1
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv2-noblend.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv2-noblend.sc
index 75541985e36..5bcf3e31f5a 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv2-noblend.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv2-noblend.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
/*
Hyllian's xBR-lv2-noblend Shader
-
+
Copyright (C) 2011-2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -33,10 +33,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
// A1 B1 C1
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv2.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv2.sc
index ce6e411b75d..22e993426ed 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv2.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv2.sc
@@ -7,10 +7,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
vec2 ps = 1.0 / u_tex_size0.xy;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv3-noblend.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv3-noblend.sc
index 5421eaf2955..5957004443c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv3-noblend.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv3-noblend.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
/*
Hyllian's xBR-lv3-noblend - Shader
-
+
Copyright (C) 2011/2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -33,10 +33,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
// A1 B1 C1
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv3.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv3.sc
index f4ee1f55ab3..a5ee8cee547 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv3.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/vs_xbr-lv3.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
/*
Hyllian's xBR-lv3 - Shader
-
+
Copyright (C) 2011/2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -33,10 +33,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
// A1 B1 C1
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-sharp.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-sharp.sc
index 533bfe0f762..6843efd251a 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-sharp.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-sharp.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texcoo
/*
Hyllian's 2xBR v3.7c+ReverseAA (squared) Shader
-
+
Copyright (C) 2011/2012 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -171,7 +171,7 @@ void main()
vec3 s = E.xyz;
vec3 n3 = H.xyz;
vec3 n4 = H5.xyz;
-
+
vec3 aa = n2 - n1;
vec3 bb = s - n2;
vec3 cc = n3 - s;
@@ -192,7 +192,7 @@ void main()
s = s1;
n3 = F.xyz;
n4 = F4.xyz;
-
+
aa = n2 - n1;
bb = s - n2;
cc = n3 - s;
@@ -333,4 +333,4 @@ void main()
}
gl_FragColor = vec4(res.xyz, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v2-gamma.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v2-gamma.sc
index ea58584408b..46b2c3d9162 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v2-gamma.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v2-gamma.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texcoo
/*
Hyllian's 2xBR v3.8c+ReverseAA (squared) Shader - beta1
-
+
Copyright (C) 2011/2012 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -176,7 +176,7 @@ void main()
vec4 Cy = vec4( 2.0, 0.0, -1.0, 0.5 );
// These inequations define the line below which interpolation occurs.
- vec4 fx = (Ao*fp.y+Bo*fp.x);
+ vec4 fx = (Ao*fp.y+Bo*fp.x);
vec4 fx_left = (Ax*fp.y+Bx*fp.x);
vec4 fx_up = (Ay*fp.y+By*fp.x);
@@ -262,4 +262,4 @@ void main()
res = mix(res, pix, blend);
gl_FragColor = vec4(clamp(GAMMA_OUT(res), 0.0, 1.0), 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v2.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v2.sc
index a4e59937d54..cbb6659d0cd 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v2.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v2.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texcoo
/*
Hyllian's 2xBR v3.8c+ReverseAA (squared) Shader - Dithering preserved
-
+
Copyright (C) 2011/2012 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -169,7 +169,7 @@ void main()
vec4 Cy = vec4( 2.0, 0.0, -1.0, 0.5 );
// These inequations define the line below which interpolation occurs.
- vec4 fx = (Ao*fp.y+Bo*fp.x);
+ vec4 fx = (Ao*fp.y+Bo*fp.x);
vec4 fx_left = (Ax*fp.y+Bx*fp.x);
vec4 fx_up = (Ay*fp.y+By*fp.x);
@@ -252,4 +252,4 @@ void main()
res = mix(res, pix, blend);
gl_FragColor = vec4(res, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v4-gamma.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v4-gamma.sc
index 254e8d878cb..45113f32e80 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v4-gamma.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v4-gamma.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texcoo
/*
Hyllian's 2xBR v3.8c+ReverseAA (squared) Shader - beta3
-
+
Copyright (C) 2011/2012 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -182,7 +182,7 @@ void main()
vec4 Cy = vec4( 2.0, 0.0, -1.0, 0.5 );
// These inequations define the line below which interpolation occurs.
- vec4 fx = (Ao*fp.y+Bo*fp.x);
+ vec4 fx = (Ao*fp.y+Bo*fp.x);
vec4 fx_left = (Ax*fp.y+Bx*fp.x);
vec4 fx_up = (Ay*fp.y+By*fp.x);
@@ -223,7 +223,7 @@ void main()
m = min(m, sharpness * abs(bb));
m = min(m, sharpness * abs(cc));
t = clamp(t, -m, m);
-
+
vec3 s1 = (2.0 * fp.y - 1.0) * t + s;
n1 = D0.xyz;
@@ -278,4 +278,4 @@ void main()
res = mix(res1, res2, step(c_df(E.xyz, res1), c_df(E.xyz, res2)));
gl_FragColor = vec4(clamp(GAMMA_OUT(res), 0.0, 1.0), 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v4.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v4.sc
index e3791fed702..efc8c57d752 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v4.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v4.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texcoo
/*
Hyllian's 2xBR v3.8c+ReverseAA (squared) Shader - v4
-
+
Copyright (C) 2011/2012 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -175,7 +175,7 @@ void main()
vec4 Cy = vec4( 2.0, 0.0, -1.0, 0.5 );
// These inequations define the line below which interpolation occurs.
- vec4 fx = (Ao*fp.y+Bo*fp.x);
+ vec4 fx = (Ao*fp.y+Bo*fp.x);
vec4 fx_left = (Ax*fp.y+Bx*fp.x);
vec4 fx_up = (Ay*fp.y+By*fp.x);
@@ -216,7 +216,7 @@ void main()
m = min(m, sharpness * abs(bb));
m = min(m, sharpness * abs(cc));
t = clamp(t, -m, m);
-
+
vec3 s1 = (2.0 * fp.y - 1.0) * t + s;
n1 = D0.xyz;
@@ -268,4 +268,4 @@ void main()
res = mix(res1, res2, step(c_df(E.xyz, res1), c_df(E.xyz, res2)));
gl_FragColor = vec4(res, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v4b.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v4b.sc
index 858342d25c6..0beb806443b 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v4b.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v4b.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texcoo
/*
Hyllian's 2xBR v3.8b+ReverseAA (semi-rounded) Shader - v4
-
+
Copyright (C) 2011/2012 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -160,7 +160,7 @@ void main()
vec4 Cy = vec4( 2.0, 0.0, -1.0, 0.5 );
// These inequations define the line below which interpolation occurs.
- vec4 fx = (Ao*fp.y+Bo*fp.x);
+ vec4 fx = (Ao*fp.y+Bo*fp.x);
vec4 fx_left = (Ax*fp.y+Bx*fp.x);
vec4 fx_up = (Ay*fp.y+By*fp.x);
@@ -201,7 +201,7 @@ void main()
m = min(m, sharpness * abs(bb));
m = min(m, sharpness * abs(cc));
t = clamp(t, -m, m);
-
+
vec3 s1 = (2.0 * fp.y - 1.0) * t + s;
n1 = D0.xyz;
@@ -253,4 +253,4 @@ void main()
res = mix(res1, res2, step(c_df(E.xyz, res1), c_df(E.xyz, res2)));
gl_FragColor = vec4(res, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v5-gamma.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v5-gamma.sc
index 1a4ad25e765..4e3c20169ec 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v5-gamma.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid-v5-gamma.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texcoo
/*
Hyllian's 2xBR v3.8c+ReverseAA (squared) Shader - beta3
-
+
Copyright (C) 2011/2012 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -182,7 +182,7 @@ void main()
vec4 Cy = vec4( 2.0, 0.0, -1.0, 0.5 );
// These inequations define the line below which interpolation occurs.
- vec4 fx = (Ao*fp.y+Bo*fp.x);
+ vec4 fx = (Ao*fp.y+Bo*fp.x);
vec4 fx_left = (Ax*fp.y+Bx*fp.x);
vec4 fx_up = (Ay*fp.y+By*fp.x);
@@ -223,7 +223,7 @@ void main()
m = min(m, sharpness * abs(bb));
m = min(m, sharpness * abs(cc));
t = clamp(t, -m, m);
-
+
vec3 s1 = (2.0 * fp.y - 1.0) * t + s;
n1 = D0.xyz;
@@ -285,4 +285,4 @@ void main()
res = mix(res, pix, blend);
gl_FragColor = vec4(clamp(GAMMA_OUT(res), 0.0, 1.0), 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid.sc
index bf3af2de385..aff101a1212 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/fs_2xbr-hybrid.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texcoo
/*
Hyllian's 2xBR v3.7c+ReverseAA (squared) Shader
-
+
Copyright (C) 2011/2012 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -176,7 +176,7 @@ void main()
vec3 s = E.xyz;
vec3 n3 = H.xyz;
vec3 n4 = H5.xyz;
-
+
vec3 aa = n2 - n1;
vec3 bb = s - n2;
vec3 cc = n3 - s;
@@ -189,7 +189,7 @@ void main()
m = min(m, 2.0 * abs(cc));
vec3 sim1 = (gt3(abs(bb) * 2.0, threshold) + gt3(abs(cc) * 2.0, threshold) + le3(abs(bb) * 2.0, xx) + le3(abs(cc) * 2.0, xx));
t = clamp(t, -m, m);
-
+
vec3 s1 = (2.0 * fp.y - 1.0) * t + s;
n1 = D0.xyz;
@@ -197,7 +197,7 @@ void main()
s = s1;
n3 = F.xyz;
n4 = F4.xyz;
-
+
aa = n2 - n1;
bb = s - n2;
cc = n3 - s;
@@ -338,4 +338,4 @@ void main()
}
gl_FragColor = vec4(res.xyz, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-sharp.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-sharp.sc
index 339c44e284c..35cc742cff1 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-sharp.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-sharp.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
/*
Hyllian's 2xBR v3.7c+ReverseAA (squared) Shader
-
+
Copyright (C) 2011/2012 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -43,10 +43,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
vec2 ps = 1.0 / u_tex_size0.xy;
@@ -60,7 +64,7 @@ void main()
// G5 H5 I5
// This line fix a bug in ATI cards.
- vec2 texCoord = a_texcoord0 + vec2(0.0000001, 0.0000001);
+ vec2 texCoord = a_texcoord0 + vec2(0.0000001, 0.0000001);
v_texcoord1 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx,-2.0*dy); // A1 B1 C1
v_texcoord2 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx, -dy); // A B C
v_texcoord3 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx, 0.0); // D E F
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v2-gamma.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v2-gamma.sc
index 9d5468107dd..3a9b0e56b1c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v2-gamma.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v2-gamma.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
/*
Hyllian's 2xBR v3.8c+ReverseAA (squared) Shader - beta1
-
+
Copyright (C) 2011/2012 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -43,10 +43,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
vec2 ps = 1.0 / u_tex_size0.xy;
@@ -60,7 +64,7 @@ void main()
// G5 H5 I5
// This line fix a bug in ATI cards.
- vec2 texCoord = a_texcoord0 + vec2(0.0000001, 0.0000001);
+ vec2 texCoord = a_texcoord0 + vec2(0.0000001, 0.0000001);
v_texcoord1 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx,-2.0*dy); // A1 B1 C1
v_texcoord2 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx, -dy); // A B C
v_texcoord3 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx, 0.0); // D E F
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v2.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v2.sc
index 8e73b14f713..c08e3988e24 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v2.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v2.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
/*
Hyllian's 2xBR v3.8c+ReverseAA (squared) Shader - Dithering preserved
-
+
Copyright (C) 2011/2012 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -43,10 +43,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
vec2 ps = 1.0 / u_tex_size0.xy;
@@ -60,7 +64,7 @@ void main()
// G5 H5 I5
// This line fix a bug in ATI cards.
- vec2 texCoord = a_texcoord0 + vec2(0.0000001, 0.0000001);
+ vec2 texCoord = a_texcoord0 + vec2(0.0000001, 0.0000001);
v_texcoord1 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx,-2.0*dy); // A1 B1 C1
v_texcoord2 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx, -dy); // A B C
v_texcoord3 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx, 0.0); // D E F
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v4-gamma.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v4-gamma.sc
index b4509adf38c..8c2b0aec4cd 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v4-gamma.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v4-gamma.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
/*
Hyllian's 2xBR v3.8c+ReverseAA (squared) Shader - beta3
-
+
Copyright (C) 2011/2012 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -43,10 +43,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
vec2 ps = 1.0 / u_tex_size0.xy;
@@ -60,7 +64,7 @@ void main()
// G5 H5 I5
// This line fix a bug in ATI cards.
- vec2 texCoord = a_texcoord0 + vec2(0.0000001, 0.0000001);
+ vec2 texCoord = a_texcoord0 + vec2(0.0000001, 0.0000001);
v_texcoord1 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx,-2.0*dy); // A1 B1 C1
v_texcoord2 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx, -dy); // A B C
v_texcoord3 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx, 0.0); // D E F
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v4.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v4.sc
index b00c03fbce3..d7328857ffd 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v4.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v4.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
/*
Hyllian's 2xBR v3.8c+ReverseAA (squared) Shader - v4
-
+
Copyright (C) 2011/2012 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -43,10 +43,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
vec2 ps = 1.0 / u_tex_size0.xy;
@@ -60,7 +64,7 @@ void main()
// G5 H5 I5
// This line fix a bug in ATI cards.
- vec2 texCoord = a_texcoord0 + vec2(0.0000001, 0.0000001);
+ vec2 texCoord = a_texcoord0 + vec2(0.0000001, 0.0000001);
v_texcoord1 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx,-2.0*dy); // A1 B1 C1
v_texcoord2 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx, -dy); // A B C
v_texcoord3 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx, 0.0); // D E F
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v4b.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v4b.sc
index 2a33ced4126..48ebe4f0a54 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v4b.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v4b.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
/*
Hyllian's 2xBR v3.8b+ReverseAA (semi-rounded) Shader - v4
-
+
Copyright (C) 2011/2012 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -43,10 +43,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
vec2 ps = 1.0 / u_tex_size0.xy;
@@ -60,7 +64,7 @@ void main()
// G5 H5 I5
// This line fix a bug in ATI cards.
- vec2 texCoord = a_texcoord0 + vec2(0.0000001, 0.0000001);
+ vec2 texCoord = a_texcoord0 + vec2(0.0000001, 0.0000001);
v_texcoord1 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx,-2.0*dy); // A1 B1 C1
v_texcoord2 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx, -dy); // A B C
v_texcoord3 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx, 0.0); // D E F
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v5-gamma.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v5-gamma.sc
index b4509adf38c..8c2b0aec4cd 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v5-gamma.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid-v5-gamma.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
/*
Hyllian's 2xBR v3.8c+ReverseAA (squared) Shader - beta3
-
+
Copyright (C) 2011/2012 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -43,10 +43,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
vec2 ps = 1.0 / u_tex_size0.xy;
@@ -60,7 +64,7 @@ void main()
// G5 H5 I5
// This line fix a bug in ATI cards.
- vec2 texCoord = a_texcoord0 + vec2(0.0000001, 0.0000001);
+ vec2 texCoord = a_texcoord0 + vec2(0.0000001, 0.0000001);
v_texcoord1 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx,-2.0*dy); // A1 B1 C1
v_texcoord2 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx, -dy); // A B C
v_texcoord3 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx, 0.0); // D E F
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid.sc
index 339c44e284c..35cc742cff1 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-hybrid/vs_2xbr-hybrid.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
/*
Hyllian's 2xBR v3.7c+ReverseAA (squared) Shader
-
+
Copyright (C) 2011/2012 Hyllian/Jararaca - sergiogdb@gmail.com
*/
@@ -43,10 +43,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
vec2 ps = 1.0 / u_tex_size0.xy;
@@ -60,7 +64,7 @@ void main()
// G5 H5 I5
// This line fix a bug in ATI cards.
- vec2 texCoord = a_texcoord0 + vec2(0.0000001, 0.0000001);
+ vec2 texCoord = a_texcoord0 + vec2(0.0000001, 0.0000001);
v_texcoord1 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx,-2.0*dy); // A1 B1 C1
v_texcoord2 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx, -dy); // A B C
v_texcoord3 = v_texcoord0.xxxy + vec4( -dx, 0.0, dx, 0.0); // D E F
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-a-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-a-pass0.sc
index 5af6ea86cc4..37759601aad 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-a-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-a-pass0.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texcoo
/*
Hyllian's xBR LV2 A (squared) - pass0 Shader
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -156,4 +156,4 @@ void main()
info.z = dot(edr_up, vec4(8.0, 4.0, 2.0, 1.0));
gl_FragColor = vec4(remapTo01(info, vec3(0.0, 0.0, 0.0), vec3(255.0, 255.0, 255.0)), 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-accuracy-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-accuracy-pass0.sc
index 668922ec18c..5c1fb0c9d47 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-accuracy-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-accuracy-pass0.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texcoo
/*
Hyllian's xBR LV2 Accuracy - pass0 Shader
-
+
Copyright (C) 2011-2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -171,4 +171,4 @@ void main()
info.w = dot(edri, vec4(8.0, 4.0, 2.0, 1.0));
gl_FragColor = remapTo01(info, vec4(0.0, 0.0, 0.0, 0.0), vec4(255.0, 255.0, 255.0, 255.0));
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-accuracy-pass1.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-accuracy-pass1.sc
index a32605fca4e..19ebe21366f 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-accuracy-pass1.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-accuracy-pass1.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_color0
/*
Hyllian's xBR LV2 Accuracy - pass1 Shader
-
+
Copyright (C) 2011-2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -85,7 +85,7 @@ vec4 unpack_info(float i)
float frac_val = fract(i / 2.0f);
info.w = round(frac_val);
i = i / 2.0f - frac_val;
-
+
frac_val = fract(i / 2.0f);
info.z = round(frac_val);
i = i / 2.0f - frac_val;
@@ -118,7 +118,7 @@ void main()
mat4 h = mat4(H, F, B, D);
// These inequations define the line below which interpolation occurs.
- vec4 fx = (Ao*fp.y+Bo*fp.x);
+ vec4 fx = (Ao*fp.y+Bo*fp.x);
vec4 fx_left = (Ax*fp.y+Bx*fp.x);
vec4 fx_up = (Ay*fp.y+By*fp.x);
@@ -148,13 +148,13 @@ void main()
vec4 res1 = E;
res1 = mix(res1, mix(H, F, px.x), maximos.x);
res1 = mix(res1, mix(B, D, px.z), maximos.z);
-
+
vec4 res2 = E;
res2 = mix(res2, mix(F, B, px.y), maximos.y);
res2 = mix(res2, mix(D, H, px.w), maximos.w);
-
+
vec3 E_mix = (df1(E, res2) >= df1(E, res1)) ? vec3(1.0, 1.0, 1.0) : vec3(0.0, 0.0, 0.0);
vec3 res = mix(res1.xyz, res2.xyz, E_mix);
gl_FragColor = vec4(res, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-b-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-b-pass0.sc
index 9f9c2836454..0b51db92660 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-b-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-b-pass0.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texcoo
/*
Hyllian's xBR LV2 B (squared) - pass0 Shader
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -157,4 +157,4 @@ void main()
info.z = dot(edr_up, vec4(8.0, 4.0, 2.0, 1.0));
gl_FragColor = vec4(remapTo01(info, vec3(0.0, 0.0, 0.0), vec3(255.0, 255.0, 255.0)), 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-c-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-c-pass0.sc
index e7cc84b299d..c03b2f83af4 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-c-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-c-pass0.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texcoo
/*
Hyllian's xBR LV2 C (squared) - pass0 Shader
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -119,15 +119,15 @@ void main()
vec4 interp_restriction_lv1 = clamp(vec4(notEqual(e,f)) * vec4(notEqual(e,h)) * ( neq(f,b) * neq(f,c) + neq(h,d) * neq(h,g) + eq(e,i) * (neq(f,f4) * neq(f,i4) + neq(h,h5) * neq(h,i5)) + eq(e,g) + eq(e,c)), vec4(0.0, 0.0, 0.0, 0.0), vec4(1.0, 1.0, 1.0, 1.0));
vec4 interp_restriction_lv2_left = vec4(notEqual(e,g)) * vec4(notEqual(d,g));
vec4 interp_restriction_lv2_up = vec4(notEqual(e,c)) * vec4(notEqual(b,c));
-
+
vec4 edr = vec4(lessThan(weighted_distance(e, c, g, i, h5, f4, h, f), weighted_distance(h, d, i5, f, i4, b, e, i))) * interp_restriction_lv1;
vec4 edr_left = vec4(lessThanEqual(coef * df(f,g), df(h,c))) * interp_restriction_lv2_left * edr;
vec4 edr_up = vec4(greaterThanEqual(df(f,g), coef * df(h,c))) * interp_restriction_lv2_up * edr;
-
+
vec3 info;
info.x = dot(edr, vec4(8.0, 4.0, 2.0, 1.0));
info.y = dot(edr_left, vec4(8.0, 4.0, 2.0, 1.0));
info.z = dot(edr_up, vec4(8.0, 4.0, 2.0, 1.0));
gl_FragColor = vec4(remapTo01(info, vec3(0.0, 0.0, 0.0), vec3(255.0, 255.0, 255.0)), 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-d-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-d-pass0.sc
index c168b2622a7..e19f6be1eca 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-d-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-d-pass0.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texcoo
/*
Hyllian's xBR LV2 D (squared) - pass0 Shader
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -149,7 +149,7 @@ void main()
vec4 interp_restriction_lv2_up = (ne(e,c) * ne(b,c));
interp_restriction_lv1 = clamp(interp_restriction_lv1, 0.0, 1.0);
-
+
vec4 edr = lt(weighted_distance(e, c, g, i, h5, f4, h, f), weighted_distance(h, d, i5, f, i4, b, e, i)) * interp_restriction_lv1;
vec4 edr_left = le(coef * df(f,g), df(h,c)) * interp_restriction_lv2_left * edr;
vec4 edr_up = ge(df(f,g), coef * df(h,c)) * interp_restriction_lv2_up * edr;
@@ -160,4 +160,4 @@ void main()
info.z = dot(vec4(edr_up ), vec4(8.0, 4.0, 2.0, 1.0));
gl_FragColor = vec4(remapTo01(info, vec3(0.0, 0.0, 0.0), vec3(255.0, 255.0, 255.0)), 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-noblend-pass1.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-noblend-pass1.sc
index c46dd90ba0a..4d15482b4c6 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-noblend-pass1.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-noblend-pass1.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_color0
/*
Hyllian's xBR LV2 - noblend - pass1 Shader
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -94,7 +94,7 @@ vec4 unpack_info(float i)
float frac_val = fract(i / 2.0f);
info.w = round(frac_val);
i = i / 2.0f - frac_val;
-
+
frac_val = fract(i / 2.0f);
info.z = round(frac_val);
i = i / 2.0f - frac_val;
@@ -159,4 +159,4 @@ void main()
vec3 res = mix(res1, res2, step(df12.x, df12.y));
gl_FragColor = vec4(res, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-pass1.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-pass1.sc
index 6316e485725..b5de4e02fbf 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-pass1.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/fs_xbr-lv2-pass1.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_color0
/*
Hyllian's xBR LV2 - pass1 Shader
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -57,7 +57,7 @@ vec4 unpack_info(float i)
float frac_val = fract(i / 2.0f);
info.w = round(frac_val);
i = i / 2.0f - frac_val;
-
+
frac_val = fract(i / 2.0f);
info.z = round(frac_val);
i = i / 2.0f - frac_val;
@@ -100,7 +100,7 @@ void main()
vec4 Cy = vec4(2.0, 0.0, -1.0, 0.5);
// These inequations define the line below which interpolation occurs.
- vec4 fx = (Ao*fp.y+Bo*fp.x);
+ vec4 fx = (Ao*fp.y+Bo*fp.x);
vec4 fx_left = (Ax*fp.y+Bx*fp.x);
vec4 fx_up = (Ay*fp.y+By*fp.x);
@@ -128,7 +128,7 @@ void main()
mat4 pix = mat4(mix(E, mix(H, F, px.x), maximo.x), mix(E, mix(F, B, px.y), maximo.y), mix(E, mix(B, D, px.z), maximo.z), mix(E, mix(D, H, px.w), maximo.w));
vec4 pixel = instMul(yuv_weighted, pix);
-
+
vec4 diff = df(pixel,e);
vec3 res = pix[0].xyz;
@@ -150,4 +150,4 @@ void main()
}
gl_FragColor = vec4(res, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-a-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-a-pass0.sc
index 3a80bf6f7bb..15490257390 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-a-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-a-pass0.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
/*
Hyllian's xBR LV2 A (squared) - pass0 Shader
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -34,10 +34,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
// A1 B1 C1
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-accuracy-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-accuracy-pass0.sc
index 4cd8b064523..f63eb7b2391 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-accuracy-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-accuracy-pass0.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
/*
Hyllian's xBR LV2 Accuracy - pass0 Shader
-
+
Copyright (C) 2011-2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -33,10 +33,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
// A1 B1 C1
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-accuracy-pass1.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-accuracy-pass1.sc
index c20050aa1f4..db8c513319b 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-accuracy-pass1.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-accuracy-pass1.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_color0
/*
Hyllian's xBR LV2 Accuracy - pass1 Shader
-
+
Copyright (C) 2011-2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -33,10 +33,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_color0
#include "common.sh"
uniform vec4 u_tex_size1;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
// A1 B1 C1
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-b-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-b-pass0.sc
index 5515f4f4904..0c317f16cc7 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-b-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-b-pass0.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
/*
Hyllian's xBR LV2 B (squared) - pass0 Shader
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -34,10 +34,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
// A1 B1 C1
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-c-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-c-pass0.sc
index 9d0b7161844..fbcf72fd706 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-c-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-c-pass0.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
/*
Hyllian's xBR LV2 C (squared) - pass0 Shader
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -34,10 +34,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
// A1 B1 C1
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-d-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-d-pass0.sc
index 8f9b4f316d9..e75cc78ac8c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-d-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-d-pass0.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
/*
Hyllian's xBR LV2 D (squared) - pass0 Shader
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -34,10 +34,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
// A1 B1 C1
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-noblend-pass1.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-noblend-pass1.sc
index 86df31a48e4..56cebbd6540 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-noblend-pass1.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-noblend-pass1.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_color0
/*
Hyllian's xBR LV2 - noblend - pass1 Shader
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -32,10 +32,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_color0
#include "common.sh"
uniform vec4 u_tex_size1;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
// A1 B1 C1
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-pass1.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-pass1.sc
index d678e8b0541..c35e62e81ac 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-pass1.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv2-multipass/vs_xbr-lv2-pass1.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_color0
/*
Hyllian's xBR LV2 - pass1 Shader
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -34,10 +34,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_color0
#include "common.sh"
uniform vec4 u_tex_size1;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
// A1 B1 C1
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv3-multipass/fs_xbr-lv3-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv3-multipass/fs_xbr-lv3-pass0.sc
index e9328bb4015..229f2f93936 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv3-multipass/fs_xbr-lv3-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv3-multipass/fs_xbr-lv3-pass0.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texcoo
/*
Hyllian's xBR level 3 pass0 Shader
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -120,7 +120,7 @@ vec4 weighted_distance(vec4 a, vec4 b, vec4 c, vec4 d, vec4 e, vec4 f, vec4 g, v
LEFT = UP = LEFT3 = UP3 = 0.0; \
PX0 = vec2(0.0, PX); \
LIN0 = vec4(0.0, 0.0, 0.0, 0.0); \
- } \
+ }
@@ -213,4 +213,4 @@ void main()
lin0.w, lin1.w, lin2.w, lin3.w));
gl_FragColor = vec4(remapTo01(info, vec4(255.0, 255.0, 255.0, 255.0)));
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv3-multipass/fs_xbr-lv3-pass1.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv3-multipass/fs_xbr-lv3-pass1.sc
index df6d0a72265..407aaf2aaf6 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv3-multipass/fs_xbr-lv3-pass1.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv3-multipass/fs_xbr-lv3-pass1.sc
@@ -5,7 +5,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_color0
/*
Hyllian's xBR level 3 pass1 Shader
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -70,7 +70,7 @@ vec4 unpack_info(float i)
float frac_val = fract(i / 2.0f);
info.w = round(frac_val);
i = i / 2.0f - frac_val;
-
+
frac_val = fract(i / 2.0f);
info.z = round(frac_val);
i = i / 2.0f - frac_val;
@@ -124,7 +124,7 @@ void main()
info_nr = info_nr / 2.0 - frac_val;
info_nr = info_nr / 2.0 - fract(info_nr / 2.0);
info_nr = info_nr / 2.0 - fract(info_nr / 2.0);
-
+
frac_val = fract(info_nr / 2.0);
float pxr = round(frac_val);
info_nr = info_nr / 2.0 - frac_val;
@@ -177,4 +177,4 @@ void main()
}
gl_FragColor = vec4(color, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv3-multipass/vs_xbr-lv3-pass0.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv3-multipass/vs_xbr-lv3-pass0.sc
index d4420512bd4..8ae8f8df41c 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv3-multipass/vs_xbr-lv3-pass0.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv3-multipass/vs_xbr-lv3-pass0.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
/*
Hyllian's xBR level 3 pass0 Shader
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -34,10 +34,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
// A1 B1 C1
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv3-multipass/vs_xbr-lv3-pass1.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv3-multipass/vs_xbr-lv3-pass1.sc
index edfd9fa3dd9..439005d2941 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv3-multipass/vs_xbr-lv3-pass1.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-lv3-multipass/vs_xbr-lv3-pass1.sc
@@ -6,7 +6,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_color0
/*
Hyllian's xBR level 3 pass1 Shader
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -32,10 +32,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_color0
uniform vec4 u_tex_size1;
uniform vec4 u_target_dims;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
// A3 B3 C3
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/fs_xbr-mlv4-pass1.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/fs_xbr-mlv4-pass1.sc
index fe2e3188052..1fe133cebfc 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/fs_xbr-mlv4-pass1.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/fs_xbr-mlv4-pass1.sc
@@ -6,7 +6,7 @@ $input v_texcoord0, v_texcoord1, v_color0
/*
Hyllian's xBR MultiLevel4 Shader - Pass1
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -43,7 +43,7 @@ const vec4 eq_thresholdold = vec4(15.0, 15.0, 15.0, 15.0);
const vec4 eq_threshold = vec4( 2.0, 2.0, 2.0, 2.0);
const vec4 eq_threshold3 = vec4(25.0, 25.0, 25.0, 25.0);
const vec4 yuv_weight = vec4( 4.0, 1.0, 2.0, 0.0);
-const mat4 yuvT = mat4(0.299, -0.169, 0.499, 0.0, 0.587, -0.331, -0.418, 0.0, 0.114, 0.499, -0.0813, 0.0, 0.0, 0.0, 0.0, 0.0);
+const mat4 yuvT = mat4(0.299, -0.169, 0.499, 0.0, 0.587, -0.331, -0.418, 0.0, 0.114, 0.499, -0.0813, 0.0, 0.0, 0.0, 0.0, 0.0);
const mat4 yuv = mat4(0.299, 0.587, 0.114, 0.0, -0.169, -0.331, 0.499, 0.0, 0.499, -0.418, -0.0813, 0.0, 0.0, 0.0, 0.0, 0.0);
const mat4 yuv_weighted = mat4(4.0 * vec4(0.299, 0.587, 0.114, 0.0), 2.0 * vec4(-0.169, -0.331, 0.499, 0.0), vec4(0.499, -0.418, -0.0813, 0.0), vec4(0.0, 0.0, 0.0, 0.0));
const vec4 maximo = vec4(255.0, 255.0, 255.0, 255.0);
@@ -111,7 +111,7 @@ vec4 weighted_distance(vec4 a, vec4 b, vec4 c, vec4 d, vec4 e, vec4 f, vec4 g, v
void main()
{
- vec4 A3 = TEX(-1,-3); vec4 B3 = TEX( 0,-3); vec4 C3 = TEX( 1,-3);
+ vec4 A3 = TEX(-1,-3); vec4 B3 = TEX( 0,-3); vec4 C3 = TEX( 1,-3);
vec4 A1 = TEX(-1,-2); vec4 B1 = TEX( 0,-2); vec4 C1 = TEX( 1,-2);
vec4 A2 = TEX(-3,-1); vec4 A0 = TEX(-2,-1); vec4 A = TEX(-1,-1);
vec4 B = TEX( 0,-1); vec4 C = TEX( 1,-1); vec4 C4 = TEX( 2,-1); vec4 C6 = TEX( 3,-1);
@@ -205,4 +205,4 @@ void main()
info.w = (edr4_left.w > 0.0 && edr4_up.w == 0.0) ? 8.0 : ((edr4_up.w > 0.0 && edr4_left.w == 0.0) ? 7.0 : ((edr3_left.w > 0.0 && edr3_up.w == 0.0) ? 6.0 : ((edr3_up.w > 0.0 && edr3_left.w == 0.0) ? 5.0 : ((edr_left.w > 0.0 && edr_up.w == 0.0) ? 4.0 : ((edr_up.w > 0.0 && edr_left.w == 0.0) ? 3.0 : (edr.w > 0.0 ? 2.0 : (edr0.w > 0.0 ? 1.0 : 0.0)))))));
gl_FragColor = vec4(remapTo01(info, maximo));
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/fs_xbr-mlv4-pass2.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/fs_xbr-mlv4-pass2.sc
index b0e0edf7778..7c2906246e6 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/fs_xbr-mlv4-pass2.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/fs_xbr-mlv4-pass2.sc
@@ -6,7 +6,7 @@ $input v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texcoo
/*
Hyllian's xBR MultiLevel4 Shader - Pass2
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -225,11 +225,11 @@ void main()
vec4 jag9 = clamp(jag91 * jag93 + jag92 * jag94 , 0.0, 1.0);
vec4 pe_select = eq(pe, zero) + ((one - nbrs) + jag1) * jag9;
-
+
pe.x = pe_select.x > 0.0 ? pe.x : 1.0;
pe.y = pe_select.y > 0.0 ? pe.y : 1.0;
pe.z = pe_select.z > 0.0 ? pe.z : 1.0;
pe.w = pe_select.w > 0.0 ? pe.w : 1.0;
gl_FragColor = vec4(remapTo01(pe, maximo));
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/fs_xbr-mlv4-pass3.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/fs_xbr-mlv4-pass3.sc
index 00391c77120..07490274d70 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/fs_xbr-mlv4-pass3.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/fs_xbr-mlv4-pass3.sc
@@ -6,7 +6,7 @@ $input v_texcoord0, v_texcoord1, v_color0
/*
Hyllian's xBR MultiLevel4 Shader - Pass3
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -169,4 +169,4 @@ void main()
lparam.w = addr.x * 8.0 + addr.y;
gl_FragColor = vec4(remapTo01(lparam, low, high));
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/fs_xbr-mlv4-pass4.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/fs_xbr-mlv4-pass4.sc
index 535f70a5a7d..bdd9f5b31db 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/fs_xbr-mlv4-pass4.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/fs_xbr-mlv4-pass4.sc
@@ -6,7 +6,7 @@ $input v_texcoord0, v_texcoord1, v_color0
/*
Hyllian's xBR MultiLevel4 Shader - Pass3
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -62,7 +62,7 @@ vec4 unpack_info(float i)
float frac_val = fract(i / 2.0f);
info.w = round(frac_val);
i = i / 2.0f - frac_val;
-
+
frac_val = fract(i / 2.0f);
info.z = round(frac_val);
i = i / 2.0f - frac_val;
@@ -110,13 +110,13 @@ vec3 color_mix(vec3 c, vec3 color, vec3 E)
ax.x = round(info); \
iq.x = dot(ax, bin) - 2.0; \
iq.y = dot(ay, bin) - 2.0; \
- PIXEL = texture2D(ORIG_texture, v_texcoord0 + iq.x * v_texcoord1.xy + iq.y * v_texcoord1.zw).xyz; \
+ PIXEL = texture2D(ORIG_texture, v_texcoord0 + iq.x * v_texcoord1.xy + iq.y * v_texcoord1.zw).xyz;
void main()
{
float scale_factor = u_target_size.x / u_tex_size1.x;
-
+
vec2 fp = fract(v_texcoord0 * u_tex_size1.xy) - vec2(0.5, 0.5); // pos = pixel position
vec4 UL = texture2D(decal, v_texcoord0 + 0.25 * v_texcoord1.xy + 0.25 * v_texcoord1.zw);
@@ -161,4 +161,4 @@ void main()
color = color_mix(c4, color, E.xyz);
gl_FragColor = vec4(color, 1.0);
-} \ No newline at end of file
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass1.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass1.sc
index bab183ddd30..24f3b396cc2 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass1.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass1.sc
@@ -7,7 +7,7 @@ $output v_texcoord0, v_texcoord1, v_color0
/*
Hyllian's xBR MultiLevel4 Shader - Pass1
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -33,10 +33,14 @@ $output v_texcoord0, v_texcoord1, v_color0
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
// A3 B3 C3
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass2.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass2.sc
index 71ebf7d574a..1d67bb87ebe 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass2.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass2.sc
@@ -7,7 +7,7 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
/*
Hyllian's xBR MultiLevel4 Shader - Pass2
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -33,10 +33,14 @@ $output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_texcoord4, v_texco
#include "common.sh"
uniform vec4 u_tex_size0;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
// A1 B1 C1
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass3.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass3.sc
index 19195ba5b27..2c85859340b 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass3.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass3.sc
@@ -7,7 +7,7 @@ $output v_texcoord0, v_texcoord1, v_color0
/*
Hyllian's xBR MultiLevel4 Shader - Pass3
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -33,10 +33,14 @@ $output v_texcoord0, v_texcoord1, v_color0
#include "common.sh"
uniform vec4 u_tex_size1;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
// A3 B3 C3
diff --git a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass4.sc b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass4.sc
index bf9f297ec9d..5e62a75a12e 100644
--- a/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass4.sc
+++ b/src/osd/modules/render/bgfx/shaders/chains/xbr/xbr-mlv4-multipass/vs_xbr-mlv4-pass4.sc
@@ -7,7 +7,7 @@ $output v_texcoord0, v_texcoord1, v_color0
/*
Hyllian's xBR MultiLevel4 Shader - Pass4
-
+
Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -33,10 +33,14 @@ $output v_texcoord0, v_texcoord1, v_color0
#include "common.sh"
uniform vec4 u_tex_size1;
+uniform vec4 u_inv_view_dims;
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
// A3 B3 C3
diff --git a/src/osd/modules/render/bgfx/shaders/fs_screen.sc b/src/osd/modules/render/bgfx/shaders/fs_screen.sc
index 52dac92785c..ab1bff59dee 100644
--- a/src/osd/modules/render/bgfx/shaders/fs_screen.sc
+++ b/src/osd/modules/render/bgfx/shaders/fs_screen.sc
@@ -6,7 +6,7 @@ $input v_color0, v_texcoord0
#include "common.sh"
// Samplers
-SAMPLER2D(s_tex, 0);
+SAMPLER2D(s_tex, 0);
void main()
{
diff --git a/src/osd/modules/render/bgfx/shaders/makefile b/src/osd/modules/render/bgfx/shaders/makefile
index 1ca45471b9b..c998f2564d9 100644
--- a/src/osd/modules/render/bgfx/shaders/makefile
+++ b/src/osd/modules/render/bgfx/shaders/makefile
@@ -12,25 +12,28 @@ SUBDIRS := $(patsubst .,,$(patsubst ./,,$(shell find . -type d)))
rebuild: main $(SUBDIRS)
endif
+.NOTPARALLEL:
$(SUBDIRS):
@echo $@
ifeq ($(OS),windows)
- @make -s --no-print-directory TARGET=0 SHADERS_DIR=$@/ clean all
- @make -s --no-print-directory TARGET=1 SHADERS_DIR=$@/ clean all
+ $(SILENT) $(MAKE) --no-print-directory TARGET=0 SHADERS_DIR=$@/ clean all SILENT="$(SILENT)"
+ $(SILENT) $(MAKE) --no-print-directory TARGET=1 SHADERS_DIR=$@/ clean all SILENT="$(SILENT)"
endif
- @make -s --no-print-directory TARGET=2 SHADERS_DIR=$@/ clean all
- @make -s --no-print-directory TARGET=3 SHADERS_DIR=$@/ clean all
- @make -s --no-print-directory TARGET=4 SHADERS_DIR=$@/ clean all
- @make -s --no-print-directory TARGET=5 SHADERS_DIR=$@/ clean all
+ $(SILENT) $(MAKE) --no-print-directory TARGET=2 SHADERS_DIR=$@/ clean all SILENT="$(SILENT)"
+ $(SILENT) $(MAKE) --no-print-directory TARGET=3 SHADERS_DIR=$@/ clean all SILENT="$(SILENT)"
+ $(SILENT) $(MAKE) --no-print-directory TARGET=4 SHADERS_DIR=$@/ clean all SILENT="$(SILENT)"
+ $(SILENT) $(MAKE) --no-print-directory TARGET=5 SHADERS_DIR=$@/ clean all SILENT="$(SILENT)"
+ $(SILENT) $(MAKE) --no-print-directory TARGET=7 SHADERS_DIR=$@/ clean all SILENT="$(SILENT)"
main:
ifeq ($(OS),windows)
- @make -s --no-print-directory TARGET=0 clean all
- @make -s --no-print-directory TARGET=1 clean all
+ $(SILENT) $(MAKE) --no-print-directory TARGET=0 clean all SILENT="$(SILENT)"
+ $(SILENT) $(MAKE) --no-print-directory TARGET=1 clean all SILENT="$(SILENT)"
endif
- @make -s --no-print-directory TARGET=2 clean all
- @make -s --no-print-directory TARGET=3 clean all
- @make -s --no-print-directory TARGET=4 clean all
- @make -s --no-print-directory TARGET=5 clean all
+ $(SILENT) $(MAKE) --no-print-directory TARGET=2 clean all SILENT="$(SILENT)"
+ $(SILENT) $(MAKE) --no-print-directory TARGET=3 clean all SILENT="$(SILENT)"
+ $(SILENT) $(MAKE) --no-print-directory TARGET=4 clean all SILENT="$(SILENT)"
+ $(SILENT) $(MAKE) --no-print-directory TARGET=5 clean all SILENT="$(SILENT)"
+ $(SILENT) $(MAKE) --no-print-directory TARGET=7 clean all SILENT="$(SILENT)"
.PHONY: main rebuild $(SUBDIRS)
diff --git a/src/osd/modules/render/bgfx/shaders/shader.mk b/src/osd/modules/render/bgfx/shaders/shader.mk
index e7db3cdc242..cc656d5e828 100644
--- a/src/osd/modules/render/bgfx/shaders/shader.mk
+++ b/src/osd/modules/render/bgfx/shaders/shader.mk
@@ -1,6 +1,6 @@
#
-# Copyright 2011-2019 Branimir Karadzic. All rights reserved.
-# License: http://www.opensource.org/licenses/BSD-2-Clause
+# Copyright 2011-2021 Branimir Karadzic.
+# License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
#
THISDIR:=../../../../../../3rdparty/bgfx/scripts
@@ -19,25 +19,51 @@ ifndef TARGET
.PHONY: all
all:
@echo Usage: make TARGET=# [clean, all, rebuild]
- @echo " TARGET=0 (hlsl - d3d9)"
- @echo " TARGET=1 (hlsl - d3d11)"
- @echo " TARGET=2 (essl - nacl)"
+ @echo " TARGET=0 (hlsl - d3d9 / Windows only!)"
+ @echo " TARGET=1 (hlsl - d3d11 / Windows only!)"
@echo " TARGET=3 (essl - android)"
@echo " TARGET=4 (glsl)"
@echo " TARGET=5 (metal)"
@echo " TARGET=6 (pssl)"
- @echo " TARGET=7 (spriv)"
- @echo " VERBOSE=1 show build commands."
+ @echo " TARGET=7 (spirv)"
+
+.PHONY: build
+build:
+ifeq ($(OS), windows)
+ @make -s --no-print-directory TARGET=0 all
+ @make -s --no-print-directory TARGET=1 all
+endif
+ @make -s --no-print-directory TARGET=3 all
+ @make -s --no-print-directory TARGET=4 all
+ @make -s --no-print-directory TARGET=5 all
+ @make -s --no-print-directory TARGET=7 all
+
+.PHONY: clean
+clean:
+ifeq ($(OS), windows)
+ @make -s --no-print-directory TARGET=0 clean
+ @make -s --no-print-directory TARGET=1 clean
+endif
+ @make -s --no-print-directory TARGET=3 clean
+ @make -s --no-print-directory TARGET=4 clean
+ @make -s --no-print-directory TARGET=5 clean
+ @make -s --no-print-directory TARGET=7 clean
+
+.PHONY: rebuild
+rebuild: clean build
+
else
+ADDITIONAL_INCLUDES?=
+
ifeq ($(TARGET), 0)
VS_FLAGS=--platform windows -p vs_3_0 -O 3
FS_FLAGS=--platform windows -p ps_3_0 -O 3
SHADER_PATH=shaders/dx9/$(SHADERS_DIR)
else
ifeq ($(TARGET), 1)
-VS_FLAGS=--platform windows -p vs_4_0 -O 3
-FS_FLAGS=--platform windows -p ps_4_0 -O 3
+VS_FLAGS=--platform windows -p vs_5_0 -O 3
+FS_FLAGS=--platform windows -p ps_5_0 -O 3
CS_FLAGS=--platform windows -p cs_5_0 -O 1
SHADER_PATH=shaders/dx11/$(SHADERS_DIR)
else
@@ -108,44 +134,38 @@ CS_BIN = $(addprefix $(BUILD_INTERMEDIATE_DIR)/, $(addsuffix .bin, $(basename $(
BIN = $(VS_BIN) $(FS_BIN)
ASM = $(VS_ASM) $(FS_ASM)
-ifeq ($(TARGET), 1)
+ifeq ($(TARGET), $(filter $(TARGET),1 3 4 5 6 7))
BIN += $(CS_BIN)
ASM += $(CS_ASM)
-else
-ifeq ($(TARGET), 3)
-BIN += $(CS_BIN)
-ASM += $(CS_ASM)
-else
-ifeq ($(TARGET), 4)
-BIN += $(CS_BIN)
-ASM += $(CS_ASM)
-endif
-endif
endif
-$(BUILD_INTERMEDIATE_DIR)/vs_%.bin : $(SHADERS_DIR)vs_%.sc
+$(BUILD_INTERMEDIATE_DIR)/vs_%.bin: $(SHADERS_DIR)vs_%.sc
@echo [$(<)]
$(SILENT) $(SHADERC) $(VS_FLAGS) --type vertex --depends -o $(@) -f $(<) --disasm
$(SILENT) cp $(@) $(BUILD_OUTPUT_DIR)/$(@F)
-$(BUILD_INTERMEDIATE_DIR)/fs_%.bin : $(SHADERS_DIR)fs_%.sc
+$(BUILD_INTERMEDIATE_DIR)/fs_%.bin: $(SHADERS_DIR)fs_%.sc
@echo [$(<)]
$(SILENT) $(SHADERC) $(FS_FLAGS) --type fragment --depends -o $(@) -f $(<) --disasm
$(SILENT) cp $(@) $(BUILD_OUTPUT_DIR)/$(@F)
-$(BUILD_INTERMEDIATE_DIR)/cs_%.bin : $(SHADERS_DIR)cs_%.sc
+$(BUILD_INTERMEDIATE_DIR)/cs_%.bin: $(SHADERS_DIR)cs_%.sc
@echo [$(<)]
$(SILENT) $(SHADERC) $(CS_FLAGS) --type compute --depends -o $(@) -f $(<) --disasm
$(SILENT) cp $(@) $(BUILD_OUTPUT_DIR)/$(@F)
.PHONY: all
all: dirs $(BIN)
- @echo Target $(SHADER_PATH)
+ @echo Target $(notdir $(CURDIR)) / $(SHADER_PATH)
.PHONY: clean
clean:
@echo Cleaning...
@-rm -vf $(BIN)
+
+.PHONY: cleanall
+cleanall:
+ @echo Cleaning...
@-$(call CMD_RMDIR,$(BUILD_INTERMEDIATE_DIR))
.PHONY: dirs
diff --git a/src/osd/modules/render/bgfx/shaders/vs_gui.sc b/src/osd/modules/render/bgfx/shaders/vs_gui.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/vs_gui.sc
+++ b/src/osd/modules/render/bgfx/shaders/vs_gui.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/shaders/vs_screen.sc b/src/osd/modules/render/bgfx/shaders/vs_screen.sc
index 405ef8feb3b..df2b37f203c 100644
--- a/src/osd/modules/render/bgfx/shaders/vs_screen.sc
+++ b/src/osd/modules/render/bgfx/shaders/vs_screen.sc
@@ -6,9 +6,14 @@ $output v_texcoord0, v_color0
#include "common.sh"
+uniform vec4 u_inv_view_dims;
+
void main()
{
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+#if BGFX_SHADER_LANGUAGE_HLSL && BGFX_SHADER_LANGUAGE_HLSL <= 300
+ gl_Position.xy += u_inv_view_dims.xy * gl_Position.w;
+#endif
v_texcoord0 = a_texcoord0;
v_color0 = a_color0;
}
diff --git a/src/osd/modules/render/bgfx/slider.cpp b/src/osd/modules/render/bgfx/slider.cpp
index 0cc97275497..dcd64c0c865 100644
--- a/src/osd/modules/render/bgfx/slider.cpp
+++ b/src/osd/modules/render/bgfx/slider.cpp
@@ -6,13 +6,15 @@
//
//============================================================
-#include "emu.h"
-
#include "slider.h"
#include "../frontend/mame/ui/slider.h"
-bgfx_slider::bgfx_slider(running_machine &machine, std::string name, float min, float def, float max, float step, slider_type type, screen_type screen, std::string format, std::string description, std::vector<std::string>& strings)
- : m_name(name)
+#include "strformat.h"
+
+#include <utility>
+
+bgfx_slider::bgfx_slider(running_machine &machine, std::string &&name, float min, float def, float max, float step, slider_type type, screen_type screen, std::string format, std::string description, std::vector<std::string>& strings)
+ : m_name(std::move(name))
, m_step(step)
, m_type(type)
, m_screen_type(screen)
@@ -25,7 +27,7 @@ bgfx_slider::bgfx_slider(running_machine &machine, std::string name, float min,
m_max = max;
m_value = def;
- for (std::string string : strings)
+ for (const std::string &string : strings)
{
m_strings.push_back(string);
}
@@ -37,38 +39,21 @@ bgfx_slider::~bgfx_slider()
{
}
-int32_t bgfx_slider::slider_changed(running_machine& /*machine*/, void *arg, int /*id*/, std::string *str, int32_t newval)
-{
- if (arg != nullptr)
- {
- return reinterpret_cast<bgfx_slider*>(arg)->update(str, newval);
- }
- return 0;
-}
-
void bgfx_slider::import(float val)
{
m_value = val;
- slider_changed(m_machine, this, m_slider_state->id, nullptr, int32_t(floor(m_value / m_step + 0.5f)));
+ update(nullptr, int32_t(floor(m_value / m_step + 0.5f)));
}
std::unique_ptr<slider_state> bgfx_slider::create_core_slider()
{
- auto state = make_unique_clear<slider_state>();
-
- state->minval = int32_t(floor(m_min / m_step + 0.5f));
- state->defval = int32_t(floor(m_default / m_step + 0.5f));
- state->maxval = int32_t(floor(m_max / m_step + 0.5f));
- state->incval = int32_t(floor(m_step / m_step + 0.5f));
+ int32_t minval = int32_t(floor(m_min / m_step + 0.5f));
+ int32_t defval = int32_t(floor(m_default / m_step + 0.5f));
+ int32_t maxval = int32_t(floor(m_max / m_step + 0.5f));
+ int32_t incval = int32_t(floor(m_step / m_step + 0.5f));
using namespace std::placeholders;
- state->update = std::bind(&bgfx_slider::slider_changed, this, _1, _2, _3, _4, _5);
-
- state->arg = this;
- state->id = 0;
- state->description = m_description;
-
- return state;
+ return std::make_unique<slider_state>(m_description, minval, defval, maxval, incval, std::bind(&bgfx_slider::update, this, _1, _2));
}
int32_t bgfx_slider::update(std::string *str, int32_t newval)
@@ -83,7 +68,7 @@ int32_t bgfx_slider::update(std::string *str, int32_t newval)
}
if (str != nullptr)
{
- *str = string_format(m_format, m_strings[as_int()]);
+ *str = util::string_format(m_format, m_strings[as_int()]);
}
return as_int();
}
@@ -96,21 +81,21 @@ int32_t bgfx_slider::update(std::string *str, int32_t newval)
}
if (str != nullptr)
{
- *str = string_format(m_format, as_int());
+ *str = util::string_format(m_format, as_int());
}
return as_int();
}
default:
{
- float *val_ptr = reinterpret_cast<float *>(&m_value);
+ auto *val_ptr = reinterpret_cast<float *>(&m_value);
if (newval != SLIDER_NOCHANGE)
{
*val_ptr = float(newval) * m_step;
}
if (str != nullptr)
{
- *str = string_format(m_format, *val_ptr);
+ *str = util::string_format(m_format, *val_ptr);
}
return int32_t(floor(*val_ptr / m_step + 0.5f));
}
diff --git a/src/osd/modules/render/bgfx/slider.h b/src/osd/modules/render/bgfx/slider.h
index d59f8587bd3..89a713da4b3 100644
--- a/src/osd/modules/render/bgfx/slider.h
+++ b/src/osd/modules/render/bgfx/slider.h
@@ -6,21 +6,24 @@
//
//============================================================
-#pragma once
+#ifndef MAME_RENDER_BGFX_SLIDER_H
+#define MAME_RENDER_BGFX_SLIDER_H
-#ifndef __DRAWBGFX_SLIDER__
-#define __DRAWBGFX_SLIDER__
+#pragma once
#include <bgfx/bgfx.h>
+#include <cmath>
+#include <cstdint>
+#include <memory>
#include <string>
#include <vector>
-#include "../frontend/mame/ui/sliderchangednotifier.h"
-
struct slider_state;
-class bgfx_slider : public slider_changed_notifier
+class running_machine;
+
+class bgfx_slider
{
public:
enum slider_type
@@ -44,16 +47,19 @@ public:
SLIDER_SCREEN_TYPE_ANY = SLIDER_SCREEN_TYPE_RASTER | SLIDER_SCREEN_TYPE_VECTOR | SLIDER_SCREEN_TYPE_LCD
};
- bgfx_slider(running_machine& machine, std::string name, float min, float def, float max, float step, slider_type type, screen_type screen, std::string format, std::string description, std::vector<std::string>& strings);
+ bgfx_slider(running_machine& machine, std::string &&name, float min, float def, float max, float step, slider_type type, screen_type screen, std::string format, std::string description, std::vector<std::string>& strings);
virtual ~bgfx_slider();
int32_t update(std::string *str, int32_t newval);
// Getters
- std::string name() const { return m_name; }
+ const std::string &name() const { return m_name; }
slider_type type() const { return m_type; }
float value() const { return m_value; }
float uniform_value() const { return float(m_value); }
+ float min_value() const { return m_min; }
+ float default_value() const { return m_default; }
+ float max_value() const { return m_max; }
slider_state *core_slider() const { return m_slider_state.get(); }
size_t size() const { return get_size_for_type(m_type); }
static size_t get_size_for_type(slider_type type);
@@ -62,7 +68,6 @@ public:
void import(float val);
protected:
- virtual int32_t slider_changed(running_machine &machine, void *arg, int /*id*/, std::string *str, int32_t newval) override;
std::unique_ptr<slider_state> create_core_slider();
int32_t as_int() const { return int32_t(floor(m_value / m_step + 0.5f)); }
@@ -81,4 +86,4 @@ protected:
running_machine&m_machine;
};
-#endif // __DRAWBGFX_SLIDER__
+#endif // MAME_RENDER_BGFX_SLIDER_H
diff --git a/src/osd/modules/render/bgfx/sliderreader.cpp b/src/osd/modules/render/bgfx/sliderreader.cpp
index 6d55c9b4db5..96ff2511c96 100644
--- a/src/osd/modules/render/bgfx/sliderreader.cpp
+++ b/src/osd/modules/render/bgfx/sliderreader.cpp
@@ -8,7 +8,6 @@
#include "sliderreader.h"
-#include "emu.h"
#include "slider.h"
#include "chainmanager.h"
@@ -34,7 +33,7 @@ const slider_reader::string_to_enum slider_reader::SCREEN_NAMES[slider_reader::S
{ "all", uint64_t(bgfx_slider::screen_type::SLIDER_SCREEN_TYPE_ANY) }
};
-std::vector<bgfx_slider*> slider_reader::read_from_value(const Value& value, std::string prefix, chain_manager& chains, uint32_t screen_index)
+std::vector<bgfx_slider*> slider_reader::read_from_value(const Value& value, const std::string &prefix, chain_manager& chains, uint32_t screen_index)
{
std::vector<bgfx_slider*> sliders;
@@ -56,11 +55,11 @@ std::vector<bgfx_slider*> slider_reader::read_from_value(const Value& value, std
const Value& string_array = value["strings"];
for (uint32_t i = 0; i < string_array.Size(); i++)
{
- if (!READER_CHECK(string_array[i].IsString(), (prefix + "Slider '" + name + "': strings[" + std::to_string(i) + "]: must be a string\n").c_str()))
+ if (!READER_CHECK(string_array[i].IsString(), "%sSlider '%s': strings[%u]: must be a string\n", prefix, name, i))
{
return sliders;
}
- strings.push_back(std::string(string_array[i].GetString()));
+ strings.emplace_back(std::string(string_array[i].GetString()));
}
}
@@ -83,18 +82,22 @@ std::vector<bgfx_slider*> slider_reader::read_from_value(const Value& value, std
break;
}
- std::string prefixed_desc = "Window " + std::to_string(chains.window_index()) + ", Screen " + std::to_string(screen_index) + ", " + description;
+ std::string prefixed_desc = util::string_format("Window %1$u, Screen %2$u, %3$s", chains.window_index(), screen_index, description);
if (slider_count > 1)
{
+ if (!READER_CHECK(value["min"].IsArray(), "%1$sSlider '%2$s': value 'min' must be an array", prefix, name))
+ return sliders;
+ if (!READER_CHECK(value["default"].IsArray(), "%1$sSlider '%2$s': value 'default' must be an array", prefix, name))
+ return sliders;
+ if (!READER_CHECK(value["max"].IsArray(), "%1$sSlider '%2$s': value 'max' must be an array", prefix, name))
+ return sliders;
+
float min[3];
float defaults[3];
float max[3];
- if (!READER_CHECK(value["min"].IsArray(), (prefix + "Slider '" + name + "': value 'min' must be an array\n").c_str())) return sliders;
- if (!READER_CHECK(value["default"].IsArray(), (prefix + "Slider '" + name + "': value 'default' must be an array\n").c_str())) return sliders;
- if (!READER_CHECK(value["max"].IsArray(), (prefix + "Slider '" + name + "': value 'max' must be an array\n").c_str())) return sliders;
- get_values(value, prefix + "Slider '" + name + "': 'min': ", "min", min, slider_count);
- get_values(value, prefix + "Slider '" + name + "': 'default': ", "default", defaults, slider_count);
- get_values(value, prefix + "Slider '" + name + "': 'max': ", "max", max, slider_count);
+ get_values(value, util::string_format("%1$sSlider '%2$s': 'min': ", prefix, name), "min", min, slider_count);
+ get_values(value, util::string_format("%1$sSlider '%2$s': 'default': ", prefix, name), "default", defaults, slider_count);
+ get_values(value, util::string_format("%1$sSlider '%2$s': 'max': ", prefix, name), "max", max, slider_count);
for (int index = 0; index < slider_count; index++)
{
std::string desc;
@@ -114,51 +117,50 @@ std::vector<bgfx_slider*> slider_reader::read_from_value(const Value& value, std
desc = prefixed_desc + "Invalid";
break;
}
- sliders.push_back(new bgfx_slider(chains.machine(), full_name, min[index], defaults[index], max[index], step, type, screen_type, format, desc, strings));
+ sliders.push_back(new bgfx_slider(chains.machine(), std::move(full_name), min[index], defaults[index], max[index], step, type, screen_type, format, desc, strings));
}
}
else
{
- float min = get_float(value, "min", 0.0f);
- float def = get_float(value, "default", 0.0f);
- float max = get_float(value, "max", 1.0f);
+ const float min = get_float(value, "min", 0.0f);
+ const float def = get_float(value, "default", 0.0f);
+ const float max = get_float(value, "max", 1.0f);
sliders.push_back(new bgfx_slider(chains.machine(), name + "0", min, def, max, step, type, screen_type, format, prefixed_desc, strings));
}
return sliders;
}
-bool slider_reader::get_values(const Value& value, std::string prefix, std::string name, float* values, const int count)
+bool slider_reader::get_values(const Value& value, const std::string &prefix, const std::string &name, float* values, const int count)
{
- const char* name_str = name.c_str();
- const Value& value_array = value[name_str];
+ const Value& value_array = value[name.c_str()];
for (uint32_t i = 0; i < value_array.Size() && i < count; i++)
{
- if (!READER_CHECK(value_array[i].IsNumber(), (prefix + "Entry " + std::to_string(i) + " must be a number\n").c_str())) return false;
+ if (!READER_CHECK(value_array[i].IsNumber(), "%sEntry %u must be a number\n", prefix, i)) return false;
values[i] = value_array[i].GetFloat();
}
return true;
}
-bool slider_reader::validate_parameters(const Value& value, std::string prefix)
+bool slider_reader::validate_parameters(const Value& value, const std::string &prefix)
{
- if (!READER_CHECK(value.HasMember("name"), (prefix + "Must have string value 'name'\n").c_str())) return false;
- if (!READER_CHECK(value["name"].IsString(), (prefix + "Value 'name' must be a string\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("min"), (prefix + "Must have a number or array value 'min'\n").c_str())) return false;
- if (!READER_CHECK(value["min"].IsNumber() || value["min"].IsArray(), (prefix + "Value 'min' must be a number or an array the size of the corresponding slider type\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("default"), (prefix + "Must have a number or array value 'default'\n").c_str())) return false;
- if (!READER_CHECK(value["default"].IsNumber() || value["default"].IsArray(), (prefix + "Value 'default' must be a number or an array the size of the corresponding slider type\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("max"), (prefix + "Must have a number or array value 'max'\n").c_str())) return false;
- if (!READER_CHECK(value["max"].IsNumber() || value["max"].IsArray(), (prefix + "Value 'max' must be a number or an array the size of the corresponding slider type\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("step"), (prefix + "Must have a number value 'step'\n").c_str())) return false;
- if (!READER_CHECK(value["step"].IsNumber(), (prefix + "Value 'step' must be a number (how much does this slider increment by internally?)\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("type"), (prefix + "Must have string value 'type'\n").c_str())) return false;
- if (!READER_CHECK(value["type"].IsString(), (prefix + "Value 'type' must be a string (what type of slider is this? [int_enum, int, float])\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("screen"), (prefix + "Must have string value 'screen'\n").c_str())) return false;
- if (!READER_CHECK(value["screen"].IsString(), (prefix + "Value 'screen' must be a string (what type of output device does this slider apply to? [none, raster, vector, crt, lcd, non_vector, any])\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("format"), (prefix + "Must have string value 'format'\n").c_str())) return false;
- if (!READER_CHECK(value["format"].IsString(), (prefix + "Value 'scale' must be a string (how would we display it in a printf?)").c_str())) return false;
- if (!READER_CHECK(value.HasMember("text"), (prefix + "Must have string value 'text'\n").c_str())) return false;
- if (!READER_CHECK(value["text"].IsString(), (prefix + "Value 'text' must be a string (how would you explain it?)").c_str())) return false;
- if (!READER_CHECK(!value.HasMember("strings") || value["strings"].IsArray(), (prefix + "Value 'strings' must be an array\n").c_str())) return false;
+ if (!READER_CHECK(value.HasMember("name"), "%1$sMust have string value 'name'", prefix)) return false;
+ if (!READER_CHECK(value["name"].IsString(), "%1$sValue 'name' must be a string", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("min"), "%1$sMust have a number or array value 'min'", prefix)) return false;
+ if (!READER_CHECK(value["min"].IsNumber() || value["min"].IsArray(), "%1$sValue 'min' must be a number or an array the size of the corresponding slider type", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("default"), "%1$sMust have a number or array value 'default'", prefix)) return false;
+ if (!READER_CHECK(value["default"].IsNumber() || value["default"].IsArray(), "%1$sValue 'default' must be a number or an array the size of the corresponding slider type", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("max"), "%1$sMust have a number or array value 'max'", prefix)) return false;
+ if (!READER_CHECK(value["max"].IsNumber() || value["max"].IsArray(), "%1$sValue 'max' must be a number or an array the size of the corresponding slider type", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("step"), "%1$sMust have a number value 'step'", prefix)) return false;
+ if (!READER_CHECK(value["step"].IsNumber(), "%1$sValue 'step' must be a number (how much does this slider increment by internally?)", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("type"), "%1$sMust have string value 'type'", prefix)) return false;
+ if (!READER_CHECK(value["type"].IsString(), "%1$sValue 'type' must be a string (what type of slider is this? [int_enum, int, float])", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("screen"), "%1$sMust have string value 'screen'", prefix)) return false;
+ if (!READER_CHECK(value["screen"].IsString(), "%1$sValue 'screen' must be a string (what type of output device does this slider apply to? [none, raster, vector, crt, lcd, non_vector, any])", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("format"), "%1$sMust have string value 'format'", prefix)) return false;
+ if (!READER_CHECK(value["format"].IsString(), "%1$sValue 'scale' must be a string (how would we display it in a printf?)", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("text"), "%1$sMust have string value 'text'", prefix)) return false;
+ if (!READER_CHECK(value["text"].IsString(), "%1$sValue 'text' must be a string (how would you explain it?)", prefix)) return false;
+ if (!READER_CHECK(!value.HasMember("strings") || value["strings"].IsArray(), "%1$sValue 'strings' must be an array", prefix)) return false;
return true;
}
diff --git a/src/osd/modules/render/bgfx/sliderreader.h b/src/osd/modules/render/bgfx/sliderreader.h
index 95c6872e171..dc905472cc8 100644
--- a/src/osd/modules/render/bgfx/sliderreader.h
+++ b/src/osd/modules/render/bgfx/sliderreader.h
@@ -6,26 +6,26 @@
//
//============================================================
+#ifndef MAME_RENDER_BGFX_SLIDERREADER_H
+#define MAME_RENDER_BGFX_SLIDERREADER_H
+
#pragma once
-#ifndef __DRAWBGFX_SLIDER_READER__
-#define __DRAWBGFX_SLIDER_READER__
+#include "statereader.h"
#include <vector>
-#include "statereader.h"
-
class bgfx_slider;
class chain_manager;
class slider_reader : public state_reader
{
public:
- static std::vector<bgfx_slider*> read_from_value(const Value& value, std::string prefix, chain_manager& chains, uint32_t screen_index);
+ static std::vector<bgfx_slider*> read_from_value(const Value& value, const std::string &prefix, chain_manager& chains, uint32_t screen_index);
private:
- static bool get_values(const Value& value, std::string prefix, std::string name, float* values, const int count);
- static bool validate_parameters(const Value& value, std::string prefix);
+ static bool get_values(const Value& value, const std::string &prefix, const std::string &name, float* values, const int count);
+ static bool validate_parameters(const Value& value, const std::string &prefix);
static const int TYPE_COUNT = 5;
static const string_to_enum TYPE_NAMES[TYPE_COUNT];
@@ -33,4 +33,4 @@ private:
static const string_to_enum SCREEN_NAMES[SCREEN_COUNT];
};
-#endif // __DRAWBGFX_SLIDER_READER__
+#endif // MAME_RENDER_BGFX_SLIDERREADER_H
diff --git a/src/osd/modules/render/bgfx/slideruniform.cpp b/src/osd/modules/render/bgfx/slideruniform.cpp
index 6770c7e10ac..bc116f51ff1 100644
--- a/src/osd/modules/render/bgfx/slideruniform.cpp
+++ b/src/osd/modules/render/bgfx/slideruniform.cpp
@@ -9,18 +9,16 @@
//
//============================================================
-#include "emu.h"
#include "slideruniform.h"
#include "slider.h"
-bgfx_slider_uniform::bgfx_slider_uniform(bgfx_uniform* uniform, std::vector<bgfx_slider*> sliders)
+#include <utility>
+
+bgfx_slider_uniform::bgfx_slider_uniform(bgfx_uniform* uniform, std::vector<bgfx_slider*> &&sliders)
: bgfx_entry_uniform(uniform)
+ , m_sliders(std::move(sliders))
{
- for (bgfx_slider* slider : sliders)
- {
- m_sliders.push_back(slider);
- }
}
void bgfx_slider_uniform::bind()
diff --git a/src/osd/modules/render/bgfx/slideruniform.h b/src/osd/modules/render/bgfx/slideruniform.h
index a2fa990dd1f..a08d2fb503d 100644
--- a/src/osd/modules/render/bgfx/slideruniform.h
+++ b/src/osd/modules/render/bgfx/slideruniform.h
@@ -9,10 +9,10 @@
//
//============================================================
-#pragma once
+#ifndef MAME_RENDER_BGFX_SLIDERUNIFORM_H
+#define MAME_RENDER_BGFX_SLIDERUNIFORM_H
-#ifndef __DRAWBGFX_SLIDER_UNIFORM__
-#define __DRAWBGFX_SLIDER_UNIFORM__
+#pragma once
#include "entryuniform.h"
@@ -23,7 +23,7 @@ class bgfx_slider;
class bgfx_slider_uniform : public bgfx_entry_uniform
{
public:
- bgfx_slider_uniform(bgfx_uniform* uniform, std::vector<bgfx_slider*> sliders);
+ bgfx_slider_uniform(bgfx_uniform* uniform, std::vector<bgfx_slider*> &&sliders);
virtual void bind() override;
@@ -31,4 +31,4 @@ private:
std::vector<bgfx_slider*> m_sliders;
};
-#endif // __DRAWBGFX_SLIDER_UNIFORM__
+#endif // MAME_RENDER_BGFX_SLIDERUNIFORM_H
diff --git a/src/osd/modules/render/bgfx/slideruniformreader.cpp b/src/osd/modules/render/bgfx/slideruniformreader.cpp
index eb359a01b2c..3fdeb0b21e6 100644
--- a/src/osd/modules/render/bgfx/slideruniformreader.cpp
+++ b/src/osd/modules/render/bgfx/slideruniformreader.cpp
@@ -6,16 +6,15 @@
//
//==================================================================
-#include "emu.h"
#include "slideruniformreader.h"
-#include <vector>
-
-#include "slideruniform.h"
#include "entryuniform.h"
#include "slider.h"
+#include "slideruniform.h"
+
+#include <vector>
-bgfx_entry_uniform* slider_uniform_reader::read_from_value(const Value& value, std::string prefix, bgfx_uniform* uniform, std::map<std::string, bgfx_slider*>& sliders)
+bgfx_entry_uniform* slider_uniform_reader::read_from_value(const Value& value, const std::string &prefix, bgfx_uniform* uniform, std::map<std::string, bgfx_slider*>& sliders)
{
if (!validate_parameters(value, prefix))
{
@@ -36,12 +35,12 @@ bgfx_entry_uniform* slider_uniform_reader::read_from_value(const Value& value, s
slider_list.push_back(sliders[name + "2"]);
}
- return new bgfx_slider_uniform(uniform, slider_list);
+ return new bgfx_slider_uniform(uniform, std::move(slider_list));
}
-bool slider_uniform_reader::validate_parameters(const Value& value, std::string prefix)
+bool slider_uniform_reader::validate_parameters(const Value& value, const std::string &prefix)
{
- if (!READER_CHECK(value.HasMember("slider"), (prefix + "Must have string value 'slider' (what slider are we getting the value of?)\n").c_str())) return false;
- if (!READER_CHECK(value["slider"].IsString(), (prefix + "Value 'slider' must be a string\n").c_str())) return false;
+ if (!READER_CHECK(value.HasMember("slider"), "%sMust have string value 'slider' (what slider are we getting the value of?)\n", prefix)) return false;
+ if (!READER_CHECK(value["slider"].IsString(), "%sValue 'slider' must be a string\n", prefix)) return false;
return true;
}
diff --git a/src/osd/modules/render/bgfx/slideruniformreader.h b/src/osd/modules/render/bgfx/slideruniformreader.h
index 0db387270b0..f39e7fc2fd8 100644
--- a/src/osd/modules/render/bgfx/slideruniformreader.h
+++ b/src/osd/modules/render/bgfx/slideruniformreader.h
@@ -6,27 +6,27 @@
//
//================================================================
+#ifndef MAME_RENDER_BGFX_SLIDERUNIFORMREADER_H
+#define MAME_RENDER_BGFX_SLIDERUNIFORMREADER_H
+
#pragma once
-#ifndef __DRAWBGFX_SLIDER_UNIFORM_READER__
-#define __DRAWBGFX_SLIDER_UNIFORM_READER__
+#include "entryuniform.h"
+#include "statereader.h"
#include <string>
#include <map>
-#include "entryuniform.h"
-#include "statereader.h"
-
class bgfx_uniform;
class bgfx_slider;
class slider_uniform_reader : public state_reader
{
public:
- static bgfx_entry_uniform* read_from_value(const Value& value, std::string prefix, bgfx_uniform* uniform, std::map<std::string, bgfx_slider*>& sliders);
+ static bgfx_entry_uniform* read_from_value(const Value& value, const std::string &prefix, bgfx_uniform* uniform, std::map<std::string, bgfx_slider*>& sliders);
private:
- static bool validate_parameters(const Value& value, std::string prefix);
+ static bool validate_parameters(const Value& value, const std::string &prefix);
};
-#endif // __DRAWBGFX_SLIDER_UNIFORM_READER__
+#endif // MAME_RENDER_BGFX_SLIDERUNIFORMREADER_H
diff --git a/src/osd/modules/render/bgfx/statereader.cpp b/src/osd/modules/render/bgfx/statereader.cpp
index 0f43ad71b09..277e6815185 100644
--- a/src/osd/modules/render/bgfx/statereader.cpp
+++ b/src/osd/modules/render/bgfx/statereader.cpp
@@ -9,7 +9,26 @@
#include "statereader.h"
-#include <math.h>
+#include "osdcore.h"
+
+#include <cmath>
+
+
+bool state_reader::V_READER_CHECK(bool condition, const util::format_argument_pack<char> &args)
+{
+ if (!condition)
+ osd_printf_error("Error: %s\n", util::string_format(args));
+
+ return condition;
+}
+
+bool state_reader::V_READER_WARN(bool condition, const util::format_argument_pack<char> &args)
+{
+ if (!condition)
+ osd_printf_warning("Warning: %s\n", util::string_format(args));
+
+ return condition;
+}
uint64_t state_reader::get_enum_from_value(const Value& value, std::string name, const uint64_t default_value, const string_to_enum* enums, const int count)
{
@@ -101,7 +120,7 @@ float state_reader::get_float(const Value& value, const std::string name, const
{
if (value.HasMember(name.c_str()))
{
- return (float)value[name.c_str()].GetDouble();
+ return float(value[name.c_str()].GetDouble());
}
return default_value;
}
@@ -112,7 +131,7 @@ void state_reader::get_float(const Value& value, const std::string name, float*
{
if (count == 1)
{
- *out = (float) value[name.c_str()].GetDouble();
+ *out = float(value[name.c_str()].GetDouble());
return;
}
else
@@ -130,7 +149,7 @@ void state_reader::get_vec_values(const Value& value_array, float* data, const u
{
for (unsigned int i = 0; i < count && i < value_array.Size(); i++)
{
- data[i] = (float) value_array[i].GetDouble();
+ data[i] = float(value_array[i].GetDouble());
}
}
diff --git a/src/osd/modules/render/bgfx/statereader.h b/src/osd/modules/render/bgfx/statereader.h
index 8026b4b07d0..69a795d9f04 100644
--- a/src/osd/modules/render/bgfx/statereader.h
+++ b/src/osd/modules/render/bgfx/statereader.h
@@ -7,16 +7,18 @@
//
//================================================================
+#ifndef MAME_RENDER_BGFX_STATEREADER_H
+#define MAME_RENDER_BGFX_STATEREADER_H
+
#pragma once
-#ifndef __DRAWBGFX_STATE_READER__
-#define __DRAWBGFX_STATE_READER__
+#include "util/strformat.h"
#include <rapidjson/document.h>
+#include <cstdint>
#include <string>
-#include "osdcore.h"
using namespace rapidjson;
@@ -45,22 +47,22 @@ protected:
static uint64_t get_param_from_string(std::string value, const string_to_enum* enums, const int count);
protected:
- static bool READER_CHECK(bool condition, const char* format, ...)
+ template <typename Format, typename... Params>
+ static bool READER_CHECK(bool condition, Format &&fmt, Params &&... args)
+ {
+ return V_READER_CHECK(condition, util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
+ }
+
+ template <typename Format, typename... Params>
+ static bool READER_WARN(bool condition, Format &&fmt, Params &&... args)
{
- if (!condition)
- {
- va_list ap;
- va_start(ap, format);
- char buf[2048];
- vsnprintf(buf, 2048, format, ap);
- osd_printf_error("Error: %s\n", buf);
- va_end(ap);
- }
- return condition;
+ return V_READER_WARN(condition, util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
}
private:
+ static bool V_READER_CHECK(bool condition, const util::format_argument_pack<char> &args);
+ static bool V_READER_WARN(bool condition, const util::format_argument_pack<char> &args);
static void get_vec_values(const Value& value_array, float* data, const unsigned int count);
};
-#endif // __DRAWBGFX_STATE_READER__
+#endif // MAME_RENDER_BGFX_STATEREADER_H
diff --git a/src/osd/modules/render/bgfx/suppressor.cpp b/src/osd/modules/render/bgfx/suppressor.cpp
index fa592255735..8ffb4be6d66 100644
--- a/src/osd/modules/render/bgfx/suppressor.cpp
+++ b/src/osd/modules/render/bgfx/suppressor.cpp
@@ -7,18 +7,19 @@
//
//============================================================
-#include "emu.h"
#include "suppressor.h"
#include "slider.h"
-bgfx_suppressor::bgfx_suppressor(std::vector<bgfx_slider*> sliders, uint32_t condition, combine_mode combine, void* value)
- : m_sliders(sliders)
+#include <cstring>
+
+bgfx_suppressor::bgfx_suppressor(std::vector<bgfx_slider*> &&sliders, uint32_t condition, combine_mode combine, void* value)
+ : m_sliders(std::move(sliders))
, m_condition(condition)
, m_combine(combine)
, m_value(nullptr)
{
- uint32_t size = sliders[0]->size();
+ uint32_t size = m_sliders[0]->size();
m_value = new uint8_t[size];
memcpy(m_value, value, size);
}
diff --git a/src/osd/modules/render/bgfx/suppressor.h b/src/osd/modules/render/bgfx/suppressor.h
index 343a621b72d..00276fbb398 100644
--- a/src/osd/modules/render/bgfx/suppressor.h
+++ b/src/osd/modules/render/bgfx/suppressor.h
@@ -7,10 +7,10 @@
//
//============================================================
-#pragma once
+#ifndef MAME_RENDER_BGFX_SUPPRESSOR_H
+#define MAME_RENDER_BGFX_SUPPRESSOR_H
-#ifndef __DRAWBGFX_SUPPRESSOR__
-#define __DRAWBGFX_SUPPRESSOR__
+#pragma once
#include <bgfx/bgfx.h>
@@ -34,7 +34,7 @@ public:
COMBINE_OR
};
- bgfx_suppressor(std::vector<bgfx_slider*> sliders, uint32_t condition, combine_mode combine, void* value);
+ bgfx_suppressor(std::vector<bgfx_slider*> &&sliders, uint32_t condition, combine_mode combine, void* value);
~bgfx_suppressor();
// Getters
@@ -48,4 +48,4 @@ private:
uint8_t* m_value;
};
-#endif // __DRAWBGFX_SUPPRESSOR__
+#endif // MAME_RENDER_BGFX_SUPPRESSOR_H
diff --git a/src/osd/modules/render/bgfx/suppressorreader.cpp b/src/osd/modules/render/bgfx/suppressorreader.cpp
index 77a109a264b..353b79ad9bf 100644
--- a/src/osd/modules/render/bgfx/suppressorreader.cpp
+++ b/src/osd/modules/render/bgfx/suppressorreader.cpp
@@ -6,9 +6,6 @@
//
//============================================================
-#include "emu.h"
-#include <string>
-
#include "suppressorreader.h"
#include "suppressor.h"
@@ -24,7 +21,7 @@ const suppressor_reader::string_to_enum suppressor_reader::COMBINE_NAMES[suppres
{ "or", bgfx_suppressor::combine_mode::COMBINE_OR }
};
-bgfx_suppressor* suppressor_reader::read_from_value(const Value& value, std::string prefix, std::map<std::string, bgfx_slider*>& sliders)
+bgfx_suppressor* suppressor_reader::read_from_value(const Value& value, const std::string &prefix, std::map<std::string, bgfx_slider*>& sliders)
{
if (!validate_parameters(value, prefix))
{
@@ -61,7 +58,7 @@ bgfx_suppressor* suppressor_reader::read_from_value(const Value& value, std::str
if (slider_count > 1)
{
get_values(value, prefix, "value", values, slider_count);
- if (!READER_CHECK(slider_count == value["value"].GetArray().Size(), (prefix + "Expected " + std::to_string(slider_count) + " values, got " + std::to_string(value["value"].GetArray().Size()) + "\n").c_str())) return nullptr;
+ if (!READER_CHECK(slider_count == value["value"].GetArray().Size(), "%sExpected %d values, got %u\n", prefix, slider_count, value["value"].GetArray().Size())) return nullptr;
for (int index = 1; index < slider_count; index++)
{
check_sliders.push_back(sliders[name + std::to_string(index)]);
@@ -72,25 +69,25 @@ bgfx_suppressor* suppressor_reader::read_from_value(const Value& value, std::str
values[0] = get_int(value, "value", 0);
}
- return new bgfx_suppressor(check_sliders, condition, mode, values);
+ return new bgfx_suppressor(std::move(check_sliders), condition, mode, values);
}
-bool suppressor_reader::validate_parameters(const Value& value, std::string prefix)
+bool suppressor_reader::validate_parameters(const Value& value, const std::string &prefix)
{
- if (!READER_CHECK(value.HasMember("name"), (prefix + "Must have string value 'name'\n").c_str())) return false;
- if (!READER_CHECK(value["name"].IsString(), (prefix + "Value 'name' must be a string\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("value"), (prefix + "Must have numeric or array value 'value'\n").c_str())) return false;
- if (!READER_CHECK(value["value"].IsNumber() || value["value"].IsArray(), (prefix + "Value 'value' must be a number or array the size of the corresponding slider type\n").c_str())) return false;
+ if (!READER_CHECK(value["type"].IsString(), "%sValue 'type' must be a string\n", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("name"), "%sMust have string value 'name'\n", prefix)) return false;
+ if (!READER_CHECK(value["name"].IsString(), "%sValue 'name' must be a string\n", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("value"), "%sMust have numeric or array value 'value'\n", prefix)) return false;
+ if (!READER_CHECK(value["value"].IsNumber() || value["value"].IsArray(), "%sValue 'value' must be a number or array the size of the corresponding slider type\n", prefix)) return false;
return true;
}
bool suppressor_reader::get_values(const Value& value, std::string prefix, std::string name, int* values, const int count)
{
- const char* name_str = name.c_str();
- const Value& value_array = value[name_str];
+ const Value& value_array = value[name.c_str()];
for (uint32_t i = 0; i < value_array.Size() && i < count; i++)
{
- if (!READER_CHECK(value_array[i].IsInt(), (prefix + "value[" + std::to_string(i) + "] must be an integer\n").c_str())) return false;
+ if (!READER_CHECK(value_array[i].IsInt(), "%svalue[%u] must be an integer\n", prefix, i)) return false;
values[i] = value_array[i].GetInt();
}
return true;
diff --git a/src/osd/modules/render/bgfx/suppressorreader.h b/src/osd/modules/render/bgfx/suppressorreader.h
index cf7d641997c..23855134c51 100644
--- a/src/osd/modules/render/bgfx/suppressorreader.h
+++ b/src/osd/modules/render/bgfx/suppressorreader.h
@@ -6,10 +6,10 @@
//
//============================================================
-#pragma once
+#ifndef MAME_RENDER_BGFX_SUPPRESSORREADER_H
+#define MAME_RENDER_BGFX_SUPPRESSORREADER_H
-#ifndef __DRAWBGFX_SUPPRESSOR_READER__
-#define __DRAWBGFX_SUPPRESSOR_READER__
+#pragma once
#include "statereader.h"
@@ -22,11 +22,11 @@ class bgfx_slider;
class suppressor_reader : public state_reader
{
public:
- static bgfx_suppressor* read_from_value(const Value& value, std::string prefix, std::map<std::string, bgfx_slider*>& sliders);
+ static bgfx_suppressor* read_from_value(const Value& value, const std::string &prefix, std::map<std::string, bgfx_slider*>& sliders);
private:
static bool get_values(const Value& value, std::string prefix, std::string name, int* values, const int count);
- static bool validate_parameters(const Value& value, std::string prefix);
+ static bool validate_parameters(const Value& value, const std::string &prefix);
static const int CONDITION_COUNT = 2;
static const string_to_enum CONDITION_NAMES[CONDITION_COUNT];
@@ -34,4 +34,4 @@ private:
static const string_to_enum COMBINE_NAMES[COMBINE_COUNT];
};
-#endif // __DRAWBGFX_SUPPRESSOR_READER__
+#endif // MAME_RENDER_BGFX_SUPPRESSORREADER_H
diff --git a/src/osd/modules/render/bgfx/target.cpp b/src/osd/modules/render/bgfx/target.cpp
index cb912aba9ef..dd9169cb6cd 100644
--- a/src/osd/modules/render/bgfx/target.cpp
+++ b/src/osd/modules/render/bgfx/target.cpp
@@ -10,13 +10,16 @@
#include "target.h"
-bgfx_target::bgfx_target(std::string name, bgfx::TextureFormat::Enum format, uint16_t width, uint16_t height, uint32_t style, bool double_buffer, bool filter, uint16_t scale, uint32_t screen)
+bgfx_target::bgfx_target(std::string name, bgfx::TextureFormat::Enum format, uint16_t width, uint16_t height, uint16_t xprescale, uint16_t yprescale,
+ uint32_t style, bool double_buffer, bool filter, uint16_t scale, uint32_t screen)
: m_name(name)
, m_format(format)
, m_targets(nullptr)
, m_textures(nullptr)
, m_width(width)
, m_height(height)
+ , m_xprescale(xprescale)
+ , m_yprescale(yprescale)
, m_double_buffer(double_buffer)
, m_style(style)
, m_filter(filter)
@@ -30,16 +33,24 @@ bgfx_target::bgfx_target(std::string name, bgfx::TextureFormat::Enum format, uin
{
m_width *= m_scale;
m_height *= m_scale;
+
uint32_t wrap_mode = BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP;
uint32_t filter_mode = filter ? (BGFX_SAMPLER_MIN_ANISOTROPIC | BGFX_SAMPLER_MAG_ANISOTROPIC) : (BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_MIP_POINT);
+ uint32_t depth_flags = wrap_mode | (BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_MIP_POINT);
- m_textures = new bgfx::TextureHandle[m_page_count];
+ m_textures = new bgfx::TextureHandle[m_page_count * 2];
m_targets = new bgfx::FrameBufferHandle[m_page_count];
for (int page = 0; page < m_page_count; page++)
{
- m_textures[page] = bgfx::createTexture2D(m_width, m_height, false, 1, format, wrap_mode | filter_mode | BGFX_TEXTURE_RT);
+ m_textures[page] = bgfx::createTexture2D(m_width * xprescale, m_height * yprescale, false, 1, format, wrap_mode | filter_mode | BGFX_TEXTURE_RT);
assert(m_textures[page].idx != 0xffff);
- m_targets[page] = bgfx::createFrameBuffer(1, &m_textures[page], false);
+
+ m_textures[m_page_count + page] = bgfx::createTexture2D(m_width * xprescale, m_height * yprescale, false, 1, bgfx::TextureFormat::D32F, depth_flags | BGFX_TEXTURE_RT);
+ assert(m_textures[m_page_count + page].idx != 0xffff);
+
+ bgfx::TextureHandle handles[2] = { m_textures[page], m_textures[m_page_count + page] };
+ m_targets[page] = bgfx::createFrameBuffer(2, handles, false);
+
assert(m_targets[page].idx != 0xffff);
}
@@ -54,6 +65,8 @@ bgfx_target::bgfx_target(void *handle, uint16_t width, uint16_t height)
, m_textures(nullptr)
, m_width(width)
, m_height(height)
+ , m_xprescale(1)
+ , m_yprescale(1)
, m_double_buffer(false)
, m_style(TARGET_STYLE_CUSTOM)
, m_filter(false)
@@ -64,7 +77,7 @@ bgfx_target::bgfx_target(void *handle, uint16_t width, uint16_t height)
, m_page_count(0)
{
m_targets = new bgfx::FrameBufferHandle[1];
- m_targets[0] = bgfx::createFrameBuffer(handle, width, height);
+ m_targets[0] = bgfx::createFrameBuffer(handle, width, height, bgfx::TextureFormat::Count, bgfx::TextureFormat::D32F);
// No backing texture
}
@@ -81,6 +94,7 @@ bgfx_target::~bgfx_target()
for (int page = 0; page < m_page_count; page++)
{
bgfx::destroy(m_targets[page]);
+ bgfx::destroy(m_textures[m_page_count + page]);
bgfx::destroy(m_textures[page]);
}
delete [] m_textures;
diff --git a/src/osd/modules/render/bgfx/target.h b/src/osd/modules/render/bgfx/target.h
index 53fd70dd46b..5b979373971 100644
--- a/src/osd/modules/render/bgfx/target.h
+++ b/src/osd/modules/render/bgfx/target.h
@@ -27,7 +27,8 @@ enum
class bgfx_target : public bgfx_texture_handle_provider
{
public:
- bgfx_target(std::string name, bgfx::TextureFormat::Enum format, uint16_t width, uint16_t height, uint32_t style, bool double_buffer, bool filter, uint16_t scale, uint32_t screen);
+ bgfx_target(std::string name, bgfx::TextureFormat::Enum format, uint16_t width, uint16_t height, uint16_t xprescale, uint16_t yprescale,
+ uint32_t style, bool double_buffer, bool filter, uint16_t scale, uint32_t screen);
bgfx_target(void *handle, uint16_t width, uint16_t height);
virtual ~bgfx_target();
@@ -42,12 +43,18 @@ public:
bool filter() const { return m_filter; }
uint16_t scale() const { return m_scale; }
uint32_t screen_index() const { return m_screen; }
+ uint16_t raw_width() const { return m_width; }
+ uint16_t raw_height() const { return m_height; }
// bgfx_texture_handle_provider
- virtual uint16_t width() const override { return m_width; }
- virtual uint16_t height() const override { return m_height; }
virtual bgfx::TextureHandle texture() const override;
virtual bool is_target() const override { return true; }
+ virtual uint16_t width() const override { return m_width * m_xprescale; }
+ virtual uint16_t width_margin() const override { return 0; }
+ virtual uint16_t height() const override { return m_height * m_yprescale; }
+ virtual uint16_t rowpixels() const override { return m_width * m_xprescale; }
+ virtual int width_div_factor() const override { return 1; }
+ virtual int width_mul_factor() const override { return 1; }
private:
std::string m_name;
@@ -59,6 +66,8 @@ private:
uint16_t m_width;
uint16_t m_height;
+ uint16_t m_xprescale;
+ uint16_t m_yprescale;
bool m_double_buffer;
uint32_t m_style;
diff --git a/src/osd/modules/render/bgfx/targetmanager.cpp b/src/osd/modules/render/bgfx/targetmanager.cpp
index dfc1678ee34..eae09c48008 100644
--- a/src/osd/modules/render/bgfx/targetmanager.cpp
+++ b/src/osd/modules/render/bgfx/targetmanager.cpp
@@ -9,15 +9,15 @@
//
//============================================================
-#include <bgfx/bgfx.h>
+#include "targetmanager.h"
-#include <vector>
+#include "bgfxutil.h"
+#include "target.h"
#include "modules/lib/osdobj_common.h"
-#include "targetmanager.h"
+#include <utility>
-#include "target.h"
const int32_t target_manager::MAX_SCREENS = 100;
@@ -29,98 +29,106 @@ target_manager::target_manager(texture_manager& textures)
target_manager::~target_manager()
{
- std::vector<bgfx_target*> to_delete;
- for (std::pair<std::string, bgfx_target*> target : m_targets)
- {
- if (target.second != nullptr)
- {
- to_delete.push_back(target.second);
- }
- }
- m_targets.clear();
-
- for (uint32_t i = 0; i < to_delete.size(); i++)
- {
- delete to_delete[i];
- }
+ for (auto iter = m_targets.begin(); iter != m_targets.end(); iter = m_targets.erase(iter))
+ m_textures.remove_provider(iter->first);
}
-bgfx_target* target_manager::create_target(std::string name, bgfx::TextureFormat::Enum format, uint16_t width, uint16_t height, uint32_t style, bool double_buffer, bool filter, uint16_t scale, uint32_t screen)
+bgfx_target* target_manager::create_target(
+ std::string &&name,
+ bgfx::TextureFormat::Enum format,
+ uint16_t width,
+ uint16_t height,
+ uint16_t xprescale,
+ uint16_t yprescale,
+ uint32_t style,
+ bool double_buffer,
+ bool filter,
+ uint16_t scale,
+ uint32_t screen)
{
- bgfx_target* target = new bgfx_target(name, format, width, height, style, double_buffer, filter, scale, screen);
- std::string full_name = name + std::to_string(screen);
+ const std::string full_name = name + std::to_string(screen);
- m_targets[full_name] = target;
+ auto iter = m_targets.find(full_name);
+ if (iter != m_targets.end())
+ {
+ iter->second.reset();
+ m_textures.remove_provider(full_name);
+ }
- m_textures.add_provider(full_name, target);
+ auto target = std::make_unique<bgfx_target>(std::move(name), format, width, height, xprescale, yprescale, style, double_buffer, filter, scale, screen);
+ if (iter != m_targets.end())
+ iter->second = std::move(target);
+ else
+ iter = m_targets.emplace(full_name, std::move(target)).first;
+ m_textures.add_provider(full_name, *iter->second);
- return target;
+ return iter->second.get();
}
-void target_manager::destroy_target(std::string name, uint32_t screen)
+void target_manager::destroy_target(const std::string &name, uint32_t screen)
{
- std::string full_name = (screen < 0) ? name : (name + std::to_string(screen));
- if (m_targets[full_name] != nullptr)
+ const std::string full_name = (screen < 0) ? name : (name + std::to_string(screen));
+ const auto found = m_targets.find(full_name);
+ if (found != m_targets.end())
{
- delete m_targets[full_name];
- m_targets[full_name] = nullptr;
+ m_targets.erase(found);
m_textures.remove_provider(full_name);
}
}
bgfx_target* target_manager::create_backbuffer(void *handle, uint16_t width, uint16_t height)
{
- bgfx_target* target = new bgfx_target(handle, width, height);
- m_targets["backbuffer"] = target;
- return target;
+ auto target = std::make_unique<bgfx_target>(handle, width, height);
+ return (m_targets["backbuffer"] = std::move(target)).get();
}
-bgfx_target* target_manager::target(uint32_t screen, std::string name)
+bgfx_target* target_manager::target(uint32_t screen, const std::string &name)
{
- std::string full_name = name + std::to_string(screen);
- bgfx_target* target = m_targets[full_name];
- if (target == nullptr)
+ const std::string full_name = name + std::to_string(screen);
+ const auto found = m_targets.find(full_name);
+ if (found != m_targets.end())
{
- osd_printf_verbose("Warning: Attempting to retrieve a nonexistent target '%s' for screen %d\n", name.c_str(), screen);
+ return found->second.get();
+ }
+ else
+ {
+ osd_printf_verbose("Warning: Attempting to retrieve a nonexistent target '%s' for screen %d\n", name, screen);
+ return nullptr;
}
- return target;
}
-bool target_manager::update_target_sizes(uint32_t screen, uint16_t width, uint16_t height, uint32_t style)
+bool target_manager::update_target_sizes(uint32_t screen, uint16_t width, uint16_t height, uint32_t style, uint16_t user_prescale, uint16_t max_prescale_size)
{
- if (style == TARGET_STYLE_CUSTOM) return false;
+ if (style == TARGET_STYLE_CUSTOM)
+ return false;
- std::vector<osd_dim>& sizes = style == TARGET_STYLE_GUEST ? m_guest_dims : m_native_dims;
+ std::vector<osd_dim> &sizes = (style == TARGET_STYLE_GUEST) ? m_guest_dims : m_native_dims;
// Ensure that there's an entry to fill
while (sizes.size() <= screen)
{
- sizes.push_back(osd_dim(0, 0));
+ sizes.emplace_back(0, 0);
}
if (width != sizes[screen].width() || height != sizes[screen].height())
{
sizes[screen] = osd_dim(width, height);
- rebuild_targets(screen, style);
+ rebuild_targets(screen, style, user_prescale, max_prescale_size);
return true;
}
return false;
}
-void target_manager::rebuild_targets(uint32_t screen, uint32_t style)
+void target_manager::rebuild_targets(uint32_t screen, uint32_t style, uint16_t user_prescale, uint16_t max_prescale_size)
{
if (style == TARGET_STYLE_CUSTOM) return;
std::vector<bgfx_target*> to_resize;
- for (std::pair<std::string, bgfx_target*> target_pair : m_targets)
+ for (const auto &[name, target] : m_targets)
{
- bgfx_target* target = target_pair.second;
- if (target == nullptr || target->style() != style || target->screen_index() != screen)
- {
- continue;
- }
- to_resize.push_back(target);
+ if (target && (target->style() == style) && (target->screen_index() == screen))
+ to_resize.push_back(target.get());
}
std::vector<osd_dim>& sizes = style == TARGET_STYLE_GUEST ? m_guest_dims : m_native_dims;
@@ -133,18 +141,20 @@ void target_manager::rebuild_targets(uint32_t screen, uint32_t style)
const uint16_t scale = target->scale();
const uint16_t width(sizes[screen].width());
const uint16_t height(sizes[screen].height());
- delete target;
+ uint16_t xprescale = user_prescale;
+ uint16_t yprescale = user_prescale;
+ bgfx_util::find_prescale_factor(width, height, max_prescale_size, xprescale, yprescale);
- create_target(name, format, width, height, style, double_buffered, filter, scale, screen);
+ create_target(std::move(name), format, width, height, xprescale, yprescale, style, double_buffered, filter, scale, screen);
}
}
-void target_manager::update_screen_count(uint32_t count)
+void target_manager::update_screen_count(uint32_t count, uint16_t user_prescale, uint16_t max_prescale_size)
{
// Ensure that there's an entry to fill
while (count > m_native_dims.size())
{
- m_native_dims.push_back(osd_dim(0, 0));
+ m_native_dims.emplace_back(osd_dim(0, 0));
}
if (count != m_screen_count)
@@ -155,26 +165,26 @@ void target_manager::update_screen_count(uint32_t count)
{
for (uint32_t screen = old_count; screen < m_screen_count; screen++)
{
- create_target_if_nonexistent(screen, "output", false, false, TARGET_STYLE_NATIVE);
+ create_output_if_nonexistent(screen, user_prescale, max_prescale_size);
}
}
}
}
-void target_manager::create_target_if_nonexistent(uint32_t screen, std::string name, bool double_buffered, bool filter, uint32_t style)
+void target_manager::create_output_if_nonexistent(uint32_t screen, uint16_t user_prescale, uint16_t max_prescale_size)
{
- if (style == TARGET_STYLE_CUSTOM) return;
-
- if (m_targets[name + std::to_string(screen)] != nullptr)
+ if (m_targets.find("output" + std::to_string(screen)) != m_targets.end())
{
return;
}
- std::vector<osd_dim>& sizes = style == TARGET_STYLE_GUEST ? m_guest_dims : m_native_dims;
- uint16_t width(sizes[screen].width());
- uint16_t height(sizes[screen].height());
+ uint16_t width(m_native_dims[screen].width());
+ uint16_t height(m_native_dims[screen].height());
+ uint16_t xprescale = user_prescale;
+ uint16_t yprescale = user_prescale;
+ bgfx_util::find_prescale_factor(width, height, max_prescale_size, xprescale, yprescale);
- create_target(name, bgfx::TextureFormat::RGBA8, width, height, style, double_buffered, filter, 1, screen);
+ create_target("output", bgfx::TextureFormat::BGRA8, width, height, xprescale, yprescale, TARGET_STYLE_NATIVE, false, false, 1, screen);
}
uint16_t target_manager::width(uint32_t style, uint32_t screen)
diff --git a/src/osd/modules/render/bgfx/targetmanager.h b/src/osd/modules/render/bgfx/targetmanager.h
index fa44e2c1bd6..38bba4c5db5 100644
--- a/src/osd/modules/render/bgfx/targetmanager.h
+++ b/src/osd/modules/render/bgfx/targetmanager.h
@@ -9,44 +9,49 @@
//
//============================================================
+#ifndef MAME_RENDER_BGFX_TARGETMANAGER_H
+#define MAME_RENDER_BGFX_TARGETMANAGER_H
+
#pragma once
-#ifndef __DRAWBGFX_TARGET_MANAGER__
-#define __DRAWBGFX_TARGET_MANAGER__
+#include "texturemanager.h"
-#include <map>
-#include <string>
+#include "modules/osdhelper.h"
#include <bgfx/bgfx.h>
-#include "modules/osdhelper.h"
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
-#include "texturemanager.h"
class bgfx_target;
-class target_manager {
+class target_manager
+{
public:
target_manager(texture_manager& textures);
~target_manager();
- bgfx_target* create_target(std::string name, bgfx::TextureFormat::Enum format, uint16_t width, uint16_t height, uint32_t style, bool double_buffer, bool filter, uint16_t scale, uint32_t screen);
- void destroy_target(std::string name, uint32_t screen = -1);
+ bgfx_target* create_target(std::string &&name, bgfx::TextureFormat::Enum format, uint16_t width, uint16_t height, uint16_t xprescale, uint16_t yprescale,
+ uint32_t style, bool double_buffer, bool filter, uint16_t scale, uint32_t screen);
+ void destroy_target(const std::string &name, uint32_t screen = -1);
bgfx_target* create_backbuffer(void *handle, uint16_t width, uint16_t height);
- bool update_target_sizes(uint32_t screen, uint16_t width, uint16_t height, uint32_t style);
- void update_screen_count(uint32_t count);
+ bool update_target_sizes(uint32_t screen, uint16_t width, uint16_t height, uint32_t style, uint16_t user_prescale, uint16_t max_prescale_size);
+ void update_screen_count(uint32_t count, uint16_t user_prescale, uint16_t max_prescale_size);
// Getters
- bgfx_target* target(uint32_t screen, std::string name);
+ bgfx_target* target(uint32_t screen, const std::string &name);
uint16_t width(uint32_t style, uint32_t screen);
uint16_t height(uint32_t style, uint32_t screen);
private:
- void rebuild_targets(uint32_t screen, uint32_t style);
- void create_target_if_nonexistent(uint32_t screen, std::string name, bool double_buffered, bool filter, uint32_t style);
+ void rebuild_targets(uint32_t screen, uint32_t style, uint16_t user_prescale, uint16_t max_prescale_size);
+ void create_output_if_nonexistent(uint32_t screen, uint16_t user_prescale, uint16_t max_prescale_size);
- std::map<std::string, bgfx_target*> m_targets;
+ std::map<std::string, std::unique_ptr<bgfx_target> > m_targets;
texture_manager& m_textures;
std::vector<osd_dim> m_guest_dims;
@@ -56,4 +61,4 @@ private:
static const int32_t MAX_SCREENS;
};
-#endif // __DRAWBGFX_TARGET_MANAGER__
+#endif // MAME_RENDER_BGFX_TARGETMANAGER_H
diff --git a/src/osd/modules/render/bgfx/targetreader.cpp b/src/osd/modules/render/bgfx/targetreader.cpp
index 71b82383a59..12386428822 100644
--- a/src/osd/modules/render/bgfx/targetreader.cpp
+++ b/src/osd/modules/render/bgfx/targetreader.cpp
@@ -6,22 +6,29 @@
//
//============================================================
-#include <string>
-
-#include "emu.h"
-#include <modules/lib/osdobj_common.h>
+#include "targetreader.h"
+#include "bgfxutil.h"
#include "chainmanager.h"
-#include "targetreader.h"
#include "target.h"
+#include "modules/lib/osdobj_common.h"
+
+#include <cmath>
+
const target_reader::string_to_enum target_reader::STYLE_NAMES[target_reader::STYLE_COUNT] = {
{ "guest", TARGET_STYLE_GUEST },
{ "native", TARGET_STYLE_NATIVE },
{ "custom", TARGET_STYLE_CUSTOM }
};
-bgfx_target* target_reader::read_from_value(const Value& value, std::string prefix, chain_manager& chains, uint32_t screen_index)
+bgfx_target* target_reader::read_from_value(
+ const Value& value,
+ const std::string &prefix,
+ chain_manager& chains,
+ uint32_t screen_index,
+ uint16_t user_prescale,
+ uint16_t max_prescale_size)
{
if (!validate_parameters(value, prefix))
{
@@ -37,40 +44,61 @@ bgfx_target* target_reader::read_from_value(const Value& value, std::string pref
{
scale = int(floor(value["scale"].GetDouble() + 0.5));
}
+ bool use_user_prescale = get_bool(value, "user_prescale", false);
uint16_t width = 0;
uint16_t height = 0;
+ uint16_t xprescale = 1;
+ uint16_t yprescale = 1;
switch (mode)
{
case TARGET_STYLE_GUEST:
+ {
width = chains.targets().width(TARGET_STYLE_GUEST, screen_index);
height = chains.targets().height(TARGET_STYLE_GUEST, screen_index);
+
+ if (use_user_prescale)
+ {
+ xprescale = user_prescale;
+ yprescale = user_prescale;
+ bgfx_util::find_prescale_factor(width, height, max_prescale_size, xprescale, yprescale);
+ }
break;
+ }
case TARGET_STYLE_NATIVE:
width = chains.targets().width(TARGET_STYLE_NATIVE, screen_index);
height = chains.targets().height(TARGET_STYLE_NATIVE, screen_index);
+
+ if (use_user_prescale)
+ {
+ xprescale = user_prescale;
+ yprescale = user_prescale;
+ bgfx_util::find_prescale_factor(width, height, max_prescale_size, xprescale, yprescale);
+ }
break;
case TARGET_STYLE_CUSTOM:
- if (!READER_CHECK(value.HasMember("width"), (prefix + "Target '" + target_name + "': Must have numeric value 'width'\n").c_str())) return nullptr;
- if (!READER_CHECK(value["width"].IsNumber(), (prefix + "Target '" + target_name + "': Value 'width' must be a number\n").c_str())) return nullptr;
- if (!READER_CHECK(value.HasMember("height"), (prefix + "Target '" + target_name + "': Must have numeric value 'height'\n").c_str())) return nullptr;
- if (!READER_CHECK(value["height"].IsNumber(), (prefix + "Target '" + target_name + "': Value 'height' must be a number\n").c_str())) return nullptr;
+ READER_WARN(!value.HasMember("user_prescale"), "%sTarget '%s': user_prescale parameter is not used for custom-type render targets.\n", prefix, target_name);
+ if (!READER_CHECK(value.HasMember("width"), "%sTarget '%s': Must have numeric value 'width'\n", prefix, target_name)) return nullptr;
+ if (!READER_CHECK(value["width"].IsNumber(), "%sTarget '%s': Value 'width' must be a number\n", prefix, target_name)) return nullptr;
+ if (!READER_CHECK(value.HasMember("height"), "%sTarget '%s': Must have numeric value 'height'\n", prefix, target_name)) return nullptr;
+ if (!READER_CHECK(value["height"].IsNumber(), "%sTarget '%s': Value 'height' must be a number\n", prefix, target_name)) return nullptr;
width = uint16_t(value["width"].GetDouble());
height = uint16_t(value["height"].GetDouble());
break;
}
- return chains.targets().create_target(target_name, bgfx::TextureFormat::RGBA8, width, height, mode, double_buffer, bilinear, scale, screen_index);
+ return chains.targets().create_target(std::move(target_name), bgfx::TextureFormat::BGRA8, width, height, xprescale, yprescale, mode, double_buffer, bilinear, scale, screen_index);
}
-bool target_reader::validate_parameters(const Value& value, std::string prefix)
+bool target_reader::validate_parameters(const Value& value, const std::string &prefix)
{
- if (!READER_CHECK(value.HasMember("name"), (prefix + "Must have string value 'name'\n").c_str())) return false;
- if (!READER_CHECK(value["name"].IsString(), (prefix + "Value 'name' must be a string\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("mode"), (prefix + "Must have string enum 'mode'\n").c_str())) return false;
- if (!READER_CHECK(value["mode"].IsString(), (prefix + "Value 'mode' must be a string (what screens does this apply to?)\n").c_str())) return false;
- if (!READER_CHECK(!value.HasMember("bilinear") || value["bilinear"].IsBool(), (prefix + "Value 'bilinear' must be a boolean\n").c_str())) return false;
- if (!READER_CHECK(!value.HasMember("doublebuffer") || value["doublebuffer"].IsBool(), (prefix + "Value 'doublebuffer' must be a boolean\n").c_str())) return false;
- if (!READER_CHECK(!value.HasMember("scale") || value["scale"].IsNumber(), (prefix + "Value 'scale' must be a numeric value\n").c_str())) return false;
+ if (!READER_CHECK(value.HasMember("name"), "%sMust have string value 'name'\n", prefix)) return false;
+ if (!READER_CHECK(value["name"].IsString(), "%sValue 'name' must be a string\n", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("mode"), "%sMust have string enum 'mode'\n", prefix)) return false;
+ if (!READER_CHECK(value["mode"].IsString(), "%sValue 'mode' must be a string (what screens does this apply to?)\n", prefix)) return false;
+ if (!READER_CHECK(!value.HasMember("bilinear") || value["bilinear"].IsBool(), "%sValue 'bilinear' must be a boolean\n", prefix)) return false;
+ if (!READER_CHECK(!value.HasMember("doublebuffer") || value["doublebuffer"].IsBool(), "%sValue 'doublebuffer' must be a boolean\n", prefix)) return false;
+ if (!READER_CHECK(!value.HasMember("user_prescale") || value["user_prescale"].IsBool(), "%sValue 'user_prescale' must be a boolean\n", prefix)) return false;
+ if (!READER_CHECK(!value.HasMember("scale") || value["scale"].IsNumber(), "%sValue 'scale' must be a numeric value\n", prefix)) return false;
return true;
}
diff --git a/src/osd/modules/render/bgfx/targetreader.h b/src/osd/modules/render/bgfx/targetreader.h
index 7edf5e456fa..2db81311359 100644
--- a/src/osd/modules/render/bgfx/targetreader.h
+++ b/src/osd/modules/render/bgfx/targetreader.h
@@ -6,28 +6,28 @@
//
//============================================================
+#ifndef MAME_RENDER_BGFX_TARGETREADER_H
+#define MAME_RENDER_BGFX_TARGETREADER_H
+
#pragma once
-#ifndef __DRAWBGFX_TARGET_READER__
-#define __DRAWBGFX_TARGET_READER__
+#include "statereader.h"
#include <string>
-#include "statereader.h"
-
class bgfx_target;
class chain_manager;
class target_reader : public state_reader
{
public:
- static bgfx_target* read_from_value(const Value& value, std::string prefix, chain_manager& chains, uint32_t screen_index);
+ static bgfx_target* read_from_value(const Value& value, const std::string &prefix, chain_manager& chains, uint32_t screen_index, uint16_t user_prescale, uint16_t max_prescale_size);
private:
- static bool validate_parameters(const Value& value, std::string prefix);
+ static bool validate_parameters(const Value& value, const std::string &prefix);
static const int STYLE_COUNT = 3;
static const string_to_enum STYLE_NAMES[STYLE_COUNT];
};
-#endif // __DRAWBGFX_TARGET_READER__
+#endif // MAME_RENDER_BGFX_TARGETREADER_H
diff --git a/src/osd/modules/render/bgfx/texture.cpp b/src/osd/modules/render/bgfx/texture.cpp
index ecbf51121ab..2ffa97c0b6f 100644
--- a/src/osd/modules/render/bgfx/texture.cpp
+++ b/src/osd/modules/render/bgfx/texture.cpp
@@ -6,15 +6,19 @@
//
//============================================================
-#include <string.h>
+#include <cstring>
#include "texture.h"
-bgfx_texture::bgfx_texture(std::string name, bgfx::TextureFormat::Enum format, uint16_t width, uint16_t height, uint32_t flags, void* data)
+bgfx_texture::bgfx_texture(std::string name, bgfx::TextureFormat::Enum format, uint16_t width, uint16_t width_margin, uint16_t height, uint32_t flags, void* data)
: m_name(name)
, m_format(format)
, m_width(width)
+ , m_width_margin(width_margin)
, m_height(height)
+ , m_rowpixels(width)
+ , m_width_div_factor(1)
+ , m_width_mul_factor(1)
{
bgfx::TextureInfo info;
bgfx::calcTextureSize(info, width, height, 1, false, false, 1, format);
@@ -32,18 +36,30 @@ bgfx_texture::bgfx_texture(std::string name, bgfx::TextureFormat::Enum format, u
}
}
-bgfx_texture::bgfx_texture(std::string name, bgfx::TextureFormat::Enum format, uint16_t width, uint16_t height, const bgfx::Memory* data, uint32_t flags)
+bgfx_texture::bgfx_texture(std::string name, bgfx::TextureFormat::Enum format, uint16_t width, uint16_t width_margin, uint16_t height, const bgfx::Memory* data, uint32_t flags, uint16_t pitch, uint16_t rowpixels, int width_div_factor, int width_mul_factor)
: m_name(name)
, m_format(format)
, m_width(width)
+ , m_width_margin(width_margin)
, m_height(height)
+ , m_rowpixels(rowpixels ? rowpixels : width)
+ , m_width_div_factor(width_div_factor)
+ , m_width_mul_factor(width_mul_factor)
{
+ int adjusted_width = (m_rowpixels * m_width_mul_factor) / m_width_div_factor;
bgfx::TextureInfo info;
- bgfx::calcTextureSize(info, width, height, 1, false, false, 1, format);
- m_texture = bgfx::createTexture2D(width, height, false, 1, format, flags, data);
+ bgfx::calcTextureSize(info, adjusted_width, height, 1, false, false, 1, format);
+ m_texture = bgfx::createTexture2D(adjusted_width, height, false, 1, format, flags, nullptr);
+ bgfx::updateTexture2D(m_texture, 0, 0, 0, 0, adjusted_width, height, data, pitch);
}
bgfx_texture::~bgfx_texture()
{
bgfx::destroy(m_texture);
}
+
+void bgfx_texture::update(const bgfx::Memory *data, uint16_t pitch, uint16_t width_margin)
+{
+ m_width_margin = width_margin;
+ bgfx::updateTexture2D(m_texture, 0, 0, 0, 0, (m_rowpixels * m_width_mul_factor) / m_width_div_factor, m_height, data, pitch);
+}
diff --git a/src/osd/modules/render/bgfx/texture.h b/src/osd/modules/render/bgfx/texture.h
index 7cb6d988150..ced0604dfcf 100644
--- a/src/osd/modules/render/bgfx/texture.h
+++ b/src/osd/modules/render/bgfx/texture.h
@@ -20,8 +20,8 @@
class bgfx_texture : public bgfx_texture_handle_provider
{
public:
- bgfx_texture(std::string name, bgfx::TextureFormat::Enum format, uint16_t width, uint16_t height, uint32_t flags, void* data);
- bgfx_texture(std::string name, bgfx::TextureFormat::Enum format, uint16_t width, uint16_t height, const bgfx::Memory* data, uint32_t flags = BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP);
+ bgfx_texture(std::string name, bgfx::TextureFormat::Enum format, uint16_t width, uint16_t width_margin, uint16_t height, uint32_t flags, void* data);
+ bgfx_texture(std::string name, bgfx::TextureFormat::Enum format, uint16_t width, uint16_t width_margin, uint16_t height, const bgfx::Memory* data, uint32_t flags = BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP, uint16_t pitch = UINT16_MAX, uint16_t rowpixels = 0, int width_div_factor = 1, int width_mul_factor = 1);
virtual ~bgfx_texture();
// Getters
@@ -29,16 +29,26 @@ public:
bgfx::TextureFormat::Enum format() const { return m_format; }
// bgfx_texture_handle_provider
- virtual uint16_t width() const override { return m_width; }
- virtual uint16_t height() const override { return m_height; }
virtual bgfx::TextureHandle texture() const override { return m_texture; }
virtual bool is_target() const override { return false; }
+ virtual uint16_t width() const override { return m_width; }
+ virtual uint16_t width_margin() const override { return m_width_margin; }
+ virtual uint16_t height() const override { return m_height; }
+ virtual uint16_t rowpixels() const override { return m_rowpixels; }
+ virtual int width_div_factor() const override { return m_width_div_factor; }
+ virtual int width_mul_factor() const override { return m_width_mul_factor; }
+
+ void update(const bgfx::Memory *data, uint16_t pitch = UINT16_MAX, uint16_t width_margin = 0);
protected:
std::string m_name;
bgfx::TextureFormat::Enum m_format;
uint16_t m_width;
+ uint16_t m_width_margin;
uint16_t m_height;
+ uint16_t m_rowpixels;
+ int m_width_div_factor;
+ int m_width_mul_factor;
bgfx::TextureHandle m_texture;
};
diff --git a/src/osd/modules/render/bgfx/texturehandleprovider.h b/src/osd/modules/render/bgfx/texturehandleprovider.h
index 5620e54974e..35e4e12dc43 100644
--- a/src/osd/modules/render/bgfx/texturehandleprovider.h
+++ b/src/osd/modules/render/bgfx/texturehandleprovider.h
@@ -7,23 +7,27 @@
//
//============================================================
-#pragma once
+#ifndef MAME_RENDER_BGFX_TEXTUREHANDLEPROVIDER_H
+#define MAME_RENDER_BGFX_TEXTUREHANDLEPROVIDER_H
-#ifndef __DRAWBGFX_TEXTURE_HANDLE_PROVIDER__
-#define __DRAWBGFX_TEXTURE_HANDLE_PROVIDER__
+#pragma once
#include <bgfx/bgfx.h>
class bgfx_texture_handle_provider
{
public:
- virtual ~bgfx_texture_handle_provider() { }
+ virtual ~bgfx_texture_handle_provider() = default;
// Getters
virtual bgfx::TextureHandle texture() const = 0;
virtual bool is_target() const = 0;
virtual uint16_t width() const = 0;
+ virtual uint16_t width_margin() const = 0;
virtual uint16_t height() const = 0;
+ virtual uint16_t rowpixels() const = 0;
+ virtual int width_div_factor() const = 0;
+ virtual int width_mul_factor() const = 0;
};
-#endif // __DRAWBGFX_TEXTURE_HANDLE_PROVIDER__
+#endif // MAME_RENDER_BGFX_TEXTUREHANDLEPROVIDER_H
diff --git a/src/osd/modules/render/bgfx/texturemanager.cpp b/src/osd/modules/render/bgfx/texturemanager.cpp
index a5fbca97f35..b9acd5748e8 100644
--- a/src/osd/modules/render/bgfx/texturemanager.cpp
+++ b/src/osd/modules/render/bgfx/texturemanager.cpp
@@ -9,23 +9,26 @@
//
//============================================================
-#include <bgfx/bgfx.h>
-
#include "texturemanager.h"
-#include "texture.h"
+
#include "bgfxutil.h"
-#include "rendutil.h"
+#include "texture.h"
+
#include "modules/render/copyutil.h"
+#include "osdcore.h"
+
+#include "emucore.h"
+#include "fileio.h"
+#include "rendutil.h"
+
+
+texture_manager::texture_manager()
+{
+ // out-of-line so header works with forward declarations
+}
texture_manager::~texture_manager()
{
- for (std::pair<std::string, bgfx_texture_handle_provider*> texture : m_textures)
- {
- if (texture.second != nullptr && !(texture.second)->is_target())
- {
- delete texture.second;
- }
- }
m_textures.clear();
for (std::pair<uint64_t, sequenced_handle> mame_texture : m_mame_textures)
@@ -35,68 +38,95 @@ texture_manager::~texture_manager()
m_mame_textures.clear();
}
-void texture_manager::add_provider(std::string name, bgfx_texture_handle_provider* provider)
+void texture_manager::add_provider(const std::string &name, std::unique_ptr<bgfx_texture_handle_provider> &&provider)
{
- std::map<std::string, bgfx_texture_handle_provider*>::iterator iter = m_textures.find(name);
+ const auto iter = m_textures.find(name);
if (iter != m_textures.end())
- {
- iter->second = provider;
- }
+ iter->second = std::make_pair(provider.get(), std::move(provider));
else
- {
- m_textures[name] = provider;
- }
+ m_textures.emplace(name, std::make_pair(provider.get(), std::move(provider)));
+}
+
+void texture_manager::add_provider(const std::string &name, bgfx_texture_handle_provider &provider)
+{
+ const auto iter = m_textures.find(name);
+ if (iter != m_textures.end())
+ iter->second = std::make_pair(&provider, nullptr);
+ else
+ m_textures.emplace(name, std::make_pair(&provider, nullptr));
}
-bgfx_texture* texture_manager::create_texture(std::string name, bgfx::TextureFormat::Enum format, uint32_t width, uint32_t height, void* data, uint32_t flags)
+bgfx_texture* texture_manager::create_texture(
+ const std::string &name,
+ bgfx::TextureFormat::Enum format,
+ uint32_t width,
+ uint32_t width_margin,
+ uint32_t height,
+ void* data,
+ uint32_t flags)
{
- bgfx_texture* texture = new bgfx_texture(name, format, width, height, flags, data);
- m_textures[name] = texture;
- return texture;
+ auto texture = std::make_unique<bgfx_texture>(name, format, width, width_margin, height, flags, data);
+ bgfx_texture &result = *texture;
+ m_textures[name] = std::make_pair(texture.get(), std::move(texture));
+ return &result;
}
-bgfx_texture* texture_manager::create_png_texture(std::string path, std::string file_name, std::string texture_name, uint32_t flags, uint32_t screen)
+bgfx_texture* texture_manager::create_png_texture(
+ const std::string &path,
+ const std::string &file_name,
+ std::string texture_name,
+ uint32_t flags,
+ uint32_t screen)
{
bitmap_argb32 bitmap;
- emu_file file(path.c_str(), OPEN_FLAG_READ);
- render_load_png(bitmap, file, nullptr, file_name.c_str());
+ emu_file file(path, OPEN_FLAG_READ);
+ if (!file.open(file_name))
+ {
+ render_load_png(bitmap, file);
+ file.close();
+ }
if (bitmap.width() == 0 || bitmap.height() == 0)
{
- printf("Unable to load PNG '%s' from path '%s'\n", path.c_str(), file_name.c_str());
+ osd_printf_error("Unable to load PNG '%s' from path '%s'\n", file_name, path);
return nullptr;
}
- uint8_t *data = new uint8_t[bitmap.width() * bitmap.height() * 4];
- uint32_t *data32 = reinterpret_cast<uint32_t *>(data);
-
const uint32_t width = bitmap.width();
const uint32_t height = bitmap.height();
+ auto data32 = std::make_unique<uint32_t []>(width * height);
+
const uint32_t rowpixels = bitmap.rowpixels();
- uint32_t* base = reinterpret_cast<uint32_t *>(bitmap.raw_pixptr(0));
+ auto* base = reinterpret_cast<uint32_t *>(bitmap.raw_pixptr(0));
for (int y = 0; y < height; y++)
{
- copy_util::copyline_argb32(data32 + y * width, base + y * rowpixels, width, nullptr);
+ copy_util::copyline_argb32_to_bgra(&data32[y * width], base + y * rowpixels, width, nullptr);
}
if (screen >= 0)
{
texture_name += std::to_string(screen);
}
- bgfx_texture* texture = create_texture(texture_name, bgfx::TextureFormat::RGBA8, width, height, data, flags);
-
- delete [] data;
-
- return texture;
+ return create_texture(texture_name, bgfx::TextureFormat::BGRA8, width, 0, height, data32.get(), flags);
}
-bgfx::TextureHandle texture_manager::create_or_update_mame_texture(uint32_t format, int width, int height
- , int rowpixels, const rgb_t *palette, void *base, uint32_t seqid, uint32_t flags, uint64_t key, uint64_t old_key)
+bgfx::TextureHandle texture_manager::create_or_update_mame_texture(
+ uint32_t format,
+ int width,
+ int width_margin,
+ int height,
+ int rowpixels,
+ const rgb_t *palette,
+ void *base,
+ uint32_t seqid,
+ uint32_t flags,
+ uint64_t key,
+ uint64_t old_key)
{
bgfx::TextureHandle handle = BGFX_INVALID_HANDLE;
if (old_key != ~0ULL)
{
- std::map<uint64_t, sequenced_handle>::iterator iter = m_mame_textures.find(old_key);
+ const auto iter = m_mame_textures.find(old_key);
if (iter != m_mame_textures.end())
{
handle = iter->second.handle;
@@ -116,8 +146,12 @@ bgfx::TextureHandle texture_manager::create_or_update_mame_texture(uint32_t form
}
else
{
- const bgfx::Memory* mem = bgfx_util::mame_texture_data_to_bgfx_texture_data(format, width, height, rowpixels, palette, base);
- bgfx::updateTexture2D(handle, 0, 0, 0, 0, (uint16_t)width, (uint16_t)height, mem);
+ bgfx::TextureFormat::Enum dst_format = bgfx::TextureFormat::BGRA8;
+ uint16_t pitch = 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, format, rowpixels, width_margin, height, palette, base, pitch, width_div_factor, width_mul_factor);
+ bgfx::updateTexture2D(handle, 0, 0, 0, 0, uint16_t((rowpixels * width_mul_factor) / width_div_factor), uint16_t(height), mem, pitch);
return handle;
}
}
@@ -127,7 +161,7 @@ bgfx::TextureHandle texture_manager::create_or_update_mame_texture(uint32_t form
}
else
{
- std::map<uint64_t, sequenced_handle>::iterator iter = m_mame_textures.find(key);
+ auto iter = m_mame_textures.find(key);
if (iter != m_mame_textures.end())
{
handle = iter->second.handle;
@@ -142,8 +176,12 @@ bgfx::TextureHandle texture_manager::create_or_update_mame_texture(uint32_t form
}
else
{
- const bgfx::Memory* mem = bgfx_util::mame_texture_data_to_bgfx_texture_data(format, width, height, rowpixels, palette, base);
- bgfx::updateTexture2D(handle, 0, 0, 0, 0, (uint16_t)width, (uint16_t)height, mem);
+ bgfx::TextureFormat::Enum dst_format = bgfx::TextureFormat::BGRA8;
+ uint16_t pitch = 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, format, rowpixels, width_margin, height, palette, base, pitch, width_div_factor, width_mul_factor);
+ bgfx::updateTexture2D(handle, 0, 0, 0, 0, uint16_t((rowpixels * width_mul_factor) / width_div_factor), uint16_t(height), mem, pitch);
return handle;
}
}
@@ -151,46 +189,40 @@ bgfx::TextureHandle texture_manager::create_or_update_mame_texture(uint32_t form
}
}
- const bgfx::Memory* mem = bgfx_util::mame_texture_data_to_bgfx_texture_data(format, width, height, rowpixels, palette, base);
- handle = bgfx::createTexture2D(width, height, false, 1, bgfx::TextureFormat::RGBA8, flags, nullptr);
- bgfx::updateTexture2D(handle, 0, 0, 0, 0, (uint16_t)width, (uint16_t)height, mem);
+ bgfx::TextureFormat::Enum dst_format = bgfx::TextureFormat::BGRA8;
+ uint16_t pitch = 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, format, rowpixels, width_margin, height, palette, base, pitch, width_div_factor, width_mul_factor);
+ const uint16_t adjusted_width = uint16_t((rowpixels * width_mul_factor) / width_div_factor);
+ handle = bgfx::createTexture2D(adjusted_width, height, false, 1, dst_format, flags, nullptr);
+ bgfx::updateTexture2D(handle, 0, 0, 0, 0, adjusted_width, uint16_t(height), mem, pitch);
m_mame_textures[key] = { handle, seqid, width, height };
return handle;
}
-bgfx::TextureHandle texture_manager::handle(std::string name)
+bgfx::TextureHandle texture_manager::handle(const std::string &name)
{
bgfx::TextureHandle handle = BGFX_INVALID_HANDLE;
- std::map<std::string, bgfx_texture_handle_provider*>::iterator iter = m_textures.find(name);
+ const auto iter = m_textures.find(name);
if (iter != m_textures.end())
- {
- handle = (iter->second)->texture();
- }
+ handle = iter->second.first->texture();
assert(handle.idx != bgfx::kInvalidHandle);
return handle;
}
-bgfx_texture_handle_provider* texture_manager::provider(std::string name)
+bgfx_texture_handle_provider* texture_manager::provider(const std::string &name)
{
- std::map<std::string, bgfx_texture_handle_provider*>::iterator iter = m_textures.find(name);
+ const auto iter = m_textures.find(name);
if (iter != m_textures.end())
- {
- return iter->second;
- }
-
- return nullptr;
+ return iter->second.first;
+ else
+ return nullptr;
}
-void texture_manager::remove_provider(std::string name, bool delete_provider)
+void texture_manager::remove_provider(const std::string &name)
{
- if (provider(name) != nullptr)
- {
- if (delete_provider)
- {
- delete m_textures[name];
- }
- m_textures[name] = nullptr;
- }
+ m_textures.erase(name);
}
diff --git a/src/osd/modules/render/bgfx/texturemanager.h b/src/osd/modules/render/bgfx/texturemanager.h
index 3345a1b0ed6..8ed5d410f75 100644
--- a/src/osd/modules/render/bgfx/texturemanager.h
+++ b/src/osd/modules/render/bgfx/texturemanager.h
@@ -9,39 +9,45 @@
//
//============================================================
-#pragma once
+#ifndef MAME_RENDER_BGFX_TEXTUREMANAGER_H
+#define MAME_RENDER_BGFX_TEXTUREMANAGER_H
-#ifndef DRAWBGFX_TEXTURE_MANAGER
-#define DRAWBGFX_TEXTURE_MANAGER
+#pragma once
-#include "emu.h"
+#include "bitmap.h"
+#include <cstdint>
#include <map>
+#include <memory>
#include <string>
+#include <utility>
#include <bgfx/bgfx.h>
+
class bgfx_texture_handle_provider;
class bgfx_texture;
-class texture_manager {
+class texture_manager
+{
public:
- texture_manager() { }
+ texture_manager();
~texture_manager();
- bgfx_texture* create_texture(std::string name, bgfx::TextureFormat::Enum format, uint32_t width, uint32_t height, void* data = nullptr, uint32_t flags = BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP);
- bgfx_texture* create_png_texture(std::string path, std::string file_name, std::string texture_name, uint32_t flags = BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP, uint32_t screen = -1);
- void add_provider(std::string name, bgfx_texture_handle_provider* texture);
- void remove_provider(std::string name, bool delete_provider = false);
- bgfx::TextureHandle create_or_update_mame_texture(uint32_t format, int width, int height
- , int rowpixels, const rgb_t *palette, void *base, uint32_t seqid, uint32_t flags, uint64_t key, uint64_t old_key);
+ bgfx_texture* create_texture(const std::string &name, bgfx::TextureFormat::Enum format, uint32_t width, uint32_t width_margin, uint32_t height, void* data = nullptr, uint32_t flags = BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP);
+ bgfx_texture* create_png_texture(const std::string &path, const std::string &file_name, std::string texture_name, uint32_t flags = BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP, uint32_t screen = -1);
+ void add_provider(const std::string &name, std::unique_ptr<bgfx_texture_handle_provider> &&texture);
+ void add_provider(const std::string &name, bgfx_texture_handle_provider &texture);
+ void remove_provider(const std::string &name);
+ bgfx::TextureHandle create_or_update_mame_texture(uint32_t format, int width, int width_margin, int height,
+ int rowpixels, const rgb_t *palette, void *base, uint32_t seqid, uint32_t flags, uint64_t key, uint64_t old_key);
// Getters
- bgfx::TextureHandle handle(std::string name);
- bgfx_texture_handle_provider* provider(std::string name);
+ bgfx::TextureHandle handle(const std::string &name);
+ bgfx_texture_handle_provider* provider(const std::string &name);
private:
- bgfx_texture* create_texture(std::string name);
+ bgfx_texture* create_texture(const std::string &name);
struct sequenced_handle
{
@@ -51,8 +57,8 @@ private:
int height;
};
- std::map<std::string, bgfx_texture_handle_provider*> m_textures;
+ std::map<std::string, std::pair<bgfx_texture_handle_provider *, std::unique_ptr<bgfx_texture_handle_provider> > > m_textures;
std::map<uint64_t, sequenced_handle> m_mame_textures;
};
-#endif // DRAWBGFX_TEXTURE_MANAGER
+#endif // MAME_RENDER_BGFX_TEXTUREMANAGER_H
diff --git a/src/osd/modules/render/bgfx/timeparameter.cpp b/src/osd/modules/render/bgfx/timeparameter.cpp
index cbcd56c8e6e..bc01bb33b61 100644
--- a/src/osd/modules/render/bgfx/timeparameter.cpp
+++ b/src/osd/modules/render/bgfx/timeparameter.cpp
@@ -8,8 +8,10 @@
#include "timeparameter.h"
-bgfx_time_parameter::bgfx_time_parameter(std::string name, parameter_type type, double limit)
- : bgfx_parameter(name, type)
+#include <utility>
+
+bgfx_time_parameter::bgfx_time_parameter(std::string &&name, parameter_type type, double limit)
+ : bgfx_parameter(std::move(name), type)
, m_current_time(0)
, m_limit(limit)
{
diff --git a/src/osd/modules/render/bgfx/timeparameter.h b/src/osd/modules/render/bgfx/timeparameter.h
index ad01f8f7e60..ff7005041ff 100644
--- a/src/osd/modules/render/bgfx/timeparameter.h
+++ b/src/osd/modules/render/bgfx/timeparameter.h
@@ -6,22 +6,19 @@
//
//============================================================
-#pragma once
+#ifndef MAME_RENDER_BGFX_TIMEPARAMETER_H
+#define MAME_RENDER_BGFX_TIMEPARAMETER_H
-#ifndef __DRAWBGFX_TIME_PARAMETER__
-#define __DRAWBGFX_TIME_PARAMETER__
+#pragma once
-#include <bgfx/bgfx.h>
+#include "parameter.h"
#include <string>
-#include "parameter.h"
-
class bgfx_time_parameter : public bgfx_parameter
{
public:
- bgfx_time_parameter(std::string name, parameter_type type, double limit);
- virtual ~bgfx_time_parameter() { }
+ bgfx_time_parameter(std::string &&name, parameter_type type, double limit);
virtual float value() override;
virtual void tick(double delta) override;
@@ -31,4 +28,4 @@ private:
double m_limit;
};
-#endif // __DRAWBGFX_TIME_PARAMETER__
+#endif // MAME_RENDER_BGFX_TIMEPARAMETER_H
diff --git a/src/osd/modules/render/bgfx/uniform.cpp b/src/osd/modules/render/bgfx/uniform.cpp
index ef33c11f128..238a6a4315d 100644
--- a/src/osd/modules/render/bgfx/uniform.cpp
+++ b/src/osd/modules/render/bgfx/uniform.cpp
@@ -7,13 +7,15 @@
//============================================================
#include "uniform.h"
+
#include <cstring>
+#include <utility>
-bgfx_uniform::bgfx_uniform(std::string name, bgfx::UniformType::Enum type)
- : m_name(name)
+bgfx_uniform::bgfx_uniform(std::string &&name, bgfx::UniformType::Enum type)
+ : m_name(std::move(name))
, m_type(type)
{
- m_handle = bgfx::createUniform(m_name.c_str(), m_type);
+ m_handle = BGFX_INVALID_HANDLE;
m_data_size = get_size_for_type(type);
if (m_data_size > 0)
{
@@ -23,13 +25,21 @@ bgfx_uniform::bgfx_uniform(std::string name, bgfx::UniformType::Enum type)
bgfx_uniform::~bgfx_uniform()
{
- bgfx::destroy(m_handle);
+ if (m_handle.idx != bgfx::kInvalidHandle)
+ {
+ bgfx::destroy(m_handle);
+ }
delete [] m_data;
}
+void bgfx_uniform::create()
+{
+ m_handle = bgfx::createUniform(m_name.c_str(), m_type);
+}
+
void bgfx_uniform::upload()
{
- if (m_type != bgfx::UniformType::Int1)
+ if (m_type != bgfx::UniformType::Sampler)
{
bgfx::setUniform(m_handle, m_data);
}
@@ -42,7 +52,7 @@ bgfx_uniform* bgfx_uniform::set(float* value)
bgfx_uniform* bgfx_uniform::set_int(int value)
{
- return set(&value, get_size_for_type(bgfx::UniformType::Int1));
+ return set(&value, get_size_for_type(bgfx::UniformType::Sampler));
}
bgfx_uniform* bgfx_uniform::set_mat3(float* value)
@@ -69,7 +79,7 @@ size_t bgfx_uniform::get_size_for_type(bgfx::UniformType::Enum type)
case bgfx::UniformType::Vec4:
return sizeof(float) * 4;
- case bgfx::UniformType::Int1:
+ case bgfx::UniformType::Sampler:
return sizeof(int);
case bgfx::UniformType::Mat3:
diff --git a/src/osd/modules/render/bgfx/uniform.h b/src/osd/modules/render/bgfx/uniform.h
index aa4c2cc097a..6a9999ca19f 100644
--- a/src/osd/modules/render/bgfx/uniform.h
+++ b/src/osd/modules/render/bgfx/uniform.h
@@ -6,10 +6,10 @@
//
//============================================================
-#pragma once
+#ifndef MAME_RENDER_BGFX_UNIFORM_H
+#define MAME_RENDER_BGFX_UNIFORM_H
-#ifndef __DRAWBGFX_UNIFORM__
-#define __DRAWBGFX_UNIFORM__
+#pragma once
#include <bgfx/bgfx.h>
@@ -18,13 +18,15 @@
class bgfx_uniform
{
public:
- bgfx_uniform(std::string name, bgfx::UniformType::Enum type);
+ bgfx_uniform(std::string &&name, bgfx::UniformType::Enum type);
virtual ~bgfx_uniform();
virtual void upload();
+ void create();
+
// Getters
- std::string name() { return m_name; }
+ const std::string &name() { return m_name; }
bgfx::UniformType::Enum type() const { return m_type; }
bgfx::UniformHandle handle() const { return m_handle; }
@@ -45,4 +47,4 @@ protected:
size_t m_data_size;
};
-#endif // __DRAWBGFX_UNIFORM__
+#endif // MAME_RENDER_BGFX_UNIFORM_H
diff --git a/src/osd/modules/render/bgfx/uniformreader.cpp b/src/osd/modules/render/bgfx/uniformreader.cpp
index 3e3cb5db318..d1eab8098c7 100644
--- a/src/osd/modules/render/bgfx/uniformreader.cpp
+++ b/src/osd/modules/render/bgfx/uniformreader.cpp
@@ -10,14 +10,17 @@
#include "uniform.h"
+#include <cstdlib>
+
+
const uniform_reader::string_to_enum uniform_reader::TYPE_NAMES[uniform_reader::TYPE_COUNT] = {
- { "int", bgfx::UniformType::Int1 },
+ { "int", bgfx::UniformType::Sampler },
{ "vec4", bgfx::UniformType::Vec4 },
{ "mat3", bgfx::UniformType::Mat3 },
{ "mat4", bgfx::UniformType::Mat4 }
};
-bgfx_uniform* uniform_reader::read_from_value(const Value& value, std::string prefix)
+std::unique_ptr<bgfx_uniform> uniform_reader::read_from_value(const Value& value, const std::string &prefix)
{
if (!validate_parameters(value, prefix))
{
@@ -31,33 +34,28 @@ bgfx_uniform* uniform_reader::read_from_value(const Value& value, std::string pr
const Value& value_array = value["values"];
const size_t array_size = value_array.Size() * sizeof(float);
- const size_t alloc_size = (type_size > array_size) ? type_size : array_size;
- float* data = reinterpret_cast<float*>(new char[alloc_size]);
+ auto* data = reinterpret_cast<float*>(std::malloc(std::max(type_size, array_size)));
unsigned int index = 0;
for (; index < type_size / 4 && index < value_array.Size(); index++)
- {
- data[index] = (float)value_array[index].GetDouble();
- }
+ data[index] = float(value_array[index].GetDouble());
for (; index < type_size / 4; index++)
- {
data[index] = 0.0f;
- }
- bgfx_uniform* uniform = new bgfx_uniform(name, type);
- uniform->set((void*)data, type_size);
- delete [] data;
+ auto uniform = std::make_unique<bgfx_uniform>(name, type);
+ uniform->set(data, type_size);
+ std::free(data);
return uniform;
}
-bool uniform_reader::validate_parameters(const Value& value, std::string prefix)
+bool uniform_reader::validate_parameters(const Value& value, const std::string &prefix)
{
- if (!READER_CHECK(value.HasMember("name"), (prefix + "Must have string value 'name' (what is this uniform called in the shader code?)\n").c_str())) return false;
- if (!READER_CHECK(value["name"].IsString(), (prefix + "Value 'name' must be a string\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("type"), (prefix + "Must have string value 'type' [int, vec4, mat3, mat4]\n").c_str())) return false;
- if (!READER_CHECK(value.HasMember("values"), (prefix + "Must have array value 'values' (what are the uniform's default values?)\n").c_str())) return false;
- if (!READER_CHECK(value["values"].IsArray(), (prefix + "Value 'values' must be an array\n").c_str())) return false;
+ if (!READER_CHECK(value.HasMember("name"), "%sMust have string value 'name' (what is this uniform called in the shader code?)\n", prefix)) return false;
+ if (!READER_CHECK(value["name"].IsString(), "%sValue 'name' must be a string\n", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("type"), "%sMust have string value 'type' [int, vec4, mat3, mat4]\n", prefix)) return false;
+ if (!READER_CHECK(value.HasMember("values"), "%sMust have array value 'values' (what are the uniform's default values?)\n", prefix)) return false;
+ if (!READER_CHECK(value["values"].IsArray(), "%sValue 'values' must be an array\n", prefix)) return false;
return true;
}
diff --git a/src/osd/modules/render/bgfx/uniformreader.h b/src/osd/modules/render/bgfx/uniformreader.h
index ce1b1e9ccbe..ebb3a485d63 100644
--- a/src/osd/modules/render/bgfx/uniformreader.h
+++ b/src/osd/modules/render/bgfx/uniformreader.h
@@ -6,27 +6,29 @@
//
//============================================================
+#ifndef MAME_RENDER_BGFX_UNIFORMREADER_H
+#define MAME_RENDER_BGFX_UNIFORMREADER_H
+
#pragma once
-#ifndef __DRAWBGFX_UNIFORM_READER__
-#define __DRAWBGFX_UNIFORM_READER__
+#include "statereader.h"
-#include <bgfx/bgfx.h>
+#include <memory>
+#include <string>
-#include "statereader.h"
class bgfx_uniform;
class uniform_reader : public state_reader
{
public:
- static bgfx_uniform* read_from_value(const Value& value, std::string prefix);
+ static std::unique_ptr<bgfx_uniform> read_from_value(const Value& value, const std::string &prefix);
private:
- static bool validate_parameters(const Value& value, std::string prefix);
+ static bool validate_parameters(const Value& value, const std::string &prefix);
static const int TYPE_COUNT = 4;
static const string_to_enum TYPE_NAMES[TYPE_COUNT];
};
-#endif // __DRAWBGFX_UNIFORM_READER__
+#endif // MAME_RENDER_BGFX_UNIFORMREADER_H
diff --git a/src/osd/modules/render/bgfx/valueuniform.cpp b/src/osd/modules/render/bgfx/valueuniform.cpp
index 8a018ac492a..e36ee3cbca8 100644
--- a/src/osd/modules/render/bgfx/valueuniform.cpp
+++ b/src/osd/modules/render/bgfx/valueuniform.cpp
@@ -10,13 +10,17 @@
//============================================================
#include "valueuniform.h"
-#include <cstring>
-bgfx_value_uniform::bgfx_value_uniform(bgfx_uniform* uniform, float* values, const int count)
+#include <algorithm>
+#include <cassert>
+
+
+bgfx_value_uniform::bgfx_value_uniform(bgfx_uniform* uniform, const float* values, const int count)
: bgfx_entry_uniform(uniform)
, m_count(count)
{
- memcpy(m_values, values, sizeof(float) * count);
+ assert(count <= std::size(m_values));
+ std::copy_n(values, count, m_values);
}
void bgfx_value_uniform::bind()
diff --git a/src/osd/modules/render/bgfx/valueuniform.h b/src/osd/modules/render/bgfx/valueuniform.h
index 40d207aa0bb..aa8139650a3 100644
--- a/src/osd/modules/render/bgfx/valueuniform.h
+++ b/src/osd/modules/render/bgfx/valueuniform.h
@@ -9,17 +9,17 @@
//
//============================================================
-#pragma once
+#ifndef MAME_RENDER_BGFX_VALUEUNIFORM_H
+#define MAME_RENDER_BGFX_VALUEUNIFORM_H
-#ifndef __DRAWBGFX_VALUE_UNIFORM__
-#define __DRAWBGFX_VALUE_UNIFORM__
+#pragma once
#include "entryuniform.h"
class bgfx_value_uniform : public bgfx_entry_uniform
{
public:
- bgfx_value_uniform(bgfx_uniform* uniform, float* values, const int count);
+ bgfx_value_uniform(bgfx_uniform* uniform, const float* values, const int count);
virtual void bind() override;
@@ -28,4 +28,4 @@ private:
const int m_count;
};
-#endif // __DRAWBGFX_VALUE_UNIFORM__
+#endif // MAME_RENDER_BGFX_VALUEUNIFORM_H
diff --git a/src/osd/modules/render/bgfx/valueuniformreader.cpp b/src/osd/modules/render/bgfx/valueuniformreader.cpp
index e71f1c86329..137a6d24719 100644
--- a/src/osd/modules/render/bgfx/valueuniformreader.cpp
+++ b/src/osd/modules/render/bgfx/valueuniformreader.cpp
@@ -11,7 +11,7 @@
#include "entryuniform.h"
#include "valueuniform.h"
-bgfx_entry_uniform* value_uniform_reader::read_from_value(const Value& value, std::string prefix, bgfx_uniform* uniform)
+bgfx_entry_uniform* value_uniform_reader::read_from_value(const Value& value, const std::string &prefix, bgfx_uniform* uniform)
{
if (!validate_parameters(value, prefix))
{
@@ -36,9 +36,9 @@ bgfx_entry_uniform* value_uniform_reader::read_from_value(const Value& value, st
return new bgfx_value_uniform(uniform, values, count);
}
-bool value_uniform_reader::validate_parameters(const Value& value, std::string prefix)
+bool value_uniform_reader::validate_parameters(const Value& value, const std::string &prefix)
{
- if (!READER_CHECK(value.HasMember("value"), (prefix + "Must have string value 'value' (what value is being assigned?)\n").c_str())) return false;
- if (!READER_CHECK(value["value"].IsArray() || value["value"].IsNumber(), (prefix + "Value 'value' must be numeric or an array\n").c_str())) return false;
+ if (!READER_CHECK(value.HasMember("value"), "%sMust have string value 'value' (what value is being assigned?)\n", prefix)) return false;
+ if (!READER_CHECK(value["value"].IsArray() || value["value"].IsNumber(), "%sValue 'value' must be numeric or an array\n", prefix)) return false;
return true;
}
diff --git a/src/osd/modules/render/bgfx/valueuniformreader.h b/src/osd/modules/render/bgfx/valueuniformreader.h
index 0b6fead1cca..ea544266a84 100644
--- a/src/osd/modules/render/bgfx/valueuniformreader.h
+++ b/src/osd/modules/render/bgfx/valueuniformreader.h
@@ -6,15 +6,14 @@
//
//================================================================
+#ifndef MAME_RENDER_BGFX_VALUEUNIFORMREADER_H
+#define MAME_RENDER_BGFX_VALUEUNIFORMREADER_H
+
#pragma once
-#ifndef __DRAWBGFX_VALUE_UNIFORM_READER__
-#define __DRAWBGFX_VALUE_UNIFORM_READER__
+#include "statereader.h"
#include <string>
-#include <map>
-
-#include "statereader.h"
class bgfx_entry_uniform;
class bgfx_uniform;
@@ -22,10 +21,10 @@ class bgfx_uniform;
class value_uniform_reader : public state_reader
{
public:
- static bgfx_entry_uniform* read_from_value(const Value& value, std::string prefix, bgfx_uniform* uniform);
+ static bgfx_entry_uniform* read_from_value(const Value& value, const std::string &prefix, bgfx_uniform* uniform);
private:
- static bool validate_parameters(const Value& value, std::string prefix);
+ static bool validate_parameters(const Value& value, const std::string &prefix);
};
-#endif // __DRAWBGFX_VALUE_UNIFORM_READER__
+#endif // MAME_RENDER_BGFX_VALUEUNIFORMREADER_H
diff --git a/src/osd/modules/render/bgfx/vertex.h b/src/osd/modules/render/bgfx/vertex.h
index 32b3c36064f..2036296a9d0 100644
--- a/src/osd/modules/render/bgfx/vertex.h
+++ b/src/osd/modules/render/bgfx/vertex.h
@@ -31,7 +31,7 @@ struct ScreenVertex
.end();
}
- static bgfx::VertexDecl ms_decl;
+ static bgfx::VertexLayout ms_decl;
};
#endif // __DRAWBGFX_VERTEX__
diff --git a/src/osd/modules/render/bgfx/view.cpp b/src/osd/modules/render/bgfx/view.cpp
index 893aa77c143..3a731fc71f8 100644
--- a/src/osd/modules/render/bgfx/view.cpp
+++ b/src/osd/modules/render/bgfx/view.cpp
@@ -1,6 +1,9 @@
-#include "emu.h"
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+
+#include "view.h"
+
#include "window.h"
-#include "rendutil.h"
#include "../drawbgfx.h"
#include <bx/math.h>
@@ -8,12 +11,9 @@
#include <bgfx/platform.h>
#include "target.h"
-#include "view.h"
void bgfx_view::update() {
- std::shared_ptr<osd_window> win = m_renderer->assert_window();
-
- const uint32_t window_index = win->m_index;
+ const uint32_t window_index = m_renderer->window().index();
const uint32_t width = m_renderer->get_window_width(window_index);
const uint32_t height = m_renderer->get_window_height(window_index);
@@ -26,11 +26,14 @@ void bgfx_view::update() {
}
void bgfx_ortho_view::setup() {
- if (m_window_index != 0)
+ if (m_window_index == 0)
+ {
+ bgfx::setViewFrameBuffer(m_index, BGFX_INVALID_HANDLE);
+ }
+ else
{
bgfx::setViewFrameBuffer(m_index, m_backbuffer->target());
}
-
bgfx::setViewRect(m_index, 0, 0, m_view_width, m_view_height);
while ((m_index + 1) > m_seen_views.size())
diff --git a/src/osd/modules/render/bgfx/view.h b/src/osd/modules/render/bgfx/view.h
index a1793f89d0b..b257eb12ea4 100644
--- a/src/osd/modules/render/bgfx/view.h
+++ b/src/osd/modules/render/bgfx/view.h
@@ -4,12 +4,14 @@
#pragma once
#include "window.h"
+
#include <climits>
class renderer_bgfx;
class bgfx_target;
-class bgfx_view {
+class bgfx_view
+{
public:
bgfx_view(renderer_bgfx *renderer, uint32_t index, bgfx_target *backbuffer, std::vector<uint32_t> &seen_views)
: m_renderer(renderer)
@@ -21,7 +23,7 @@ public:
, m_view_height(0)
, m_z_near(0.0f)
, m_z_far(100.0f)
- , m_clear_color(0)
+ , m_clear_color(0x000000ff)
, m_clear_depth(1.0f)
, m_clear_stencil(0)
, m_do_clear_color(true)
diff --git a/src/osd/modules/render/bgfx/windowparameter.h b/src/osd/modules/render/bgfx/windowparameter.h
index a30b928b817..45df9060c71 100644
--- a/src/osd/modules/render/bgfx/windowparameter.h
+++ b/src/osd/modules/render/bgfx/windowparameter.h
@@ -6,28 +6,26 @@
//
//============================================================
-#pragma once
+#ifndef MAME_RENDER_BGFX_WINDOWPARAMETER_H
+#define MAME_RENDER_BGFX_WINDOWPARAMETER_H
-#ifndef __DRAWBGFX_WINDOW_PARAMETER__
-#define __DRAWBGFX_WINDOW_PARAMETER__
+#pragma once
-#include <bgfx/bgfx.h>
+#include "parameter.h"
#include <string>
-
-#include "parameter.h"
+#include <utility>
class bgfx_window_parameter : public bgfx_parameter
{
public:
- bgfx_window_parameter(std::string name, parameter_type type, uint32_t index) : bgfx_parameter(name, type), m_index(index) { }
- virtual ~bgfx_window_parameter() { }
+ bgfx_window_parameter(std::string &&name, parameter_type type, uint32_t index) : bgfx_parameter(std::move(name), type), m_index(index) { }
virtual float value() override { return float(m_index); }
- virtual void tick(double delta) override { };
+ virtual void tick(double delta) override { }
private:
uint32_t m_index;
};
-#endif // __DRAWBGFX_WINDOW_PARAMETER__
+#endif // MAME_RENDER_BGFX_WINDOWPARAMETER_H
diff --git a/src/osd/modules/render/bgfx/writereader.h b/src/osd/modules/render/bgfx/writereader.h
index 7dcd1ac16c9..9f60efd846a 100644
--- a/src/osd/modules/render/bgfx/writereader.h
+++ b/src/osd/modules/render/bgfx/writereader.h
@@ -2,14 +2,14 @@
// copyright-holders:Ryan Holtz
//============================================================
//
-// cullreader.h - BGFX alpha/color write state JSON reader
+// writereader.h - BGFX alpha/color write state JSON reader
//
//============================================================
#pragma once
-#ifndef __DRAWBGFX_WRITE_READER__
-#define __DRAWBGFX_WRITE_READER__
+#ifndef DRAWBGFX_WRITE_READER
+#define DRAWBGFX_WRITE_READER
#include "statereader.h"
@@ -18,4 +18,4 @@ public:
static uint64_t read_from_value(const Value& value);
};
-#endif // __DRAWBGFX_WRITE_READER__
+#endif // DRAWBGFX_WRITE_READER
diff --git a/src/osd/modules/render/bgfxutil.cpp b/src/osd/modules/render/bgfxutil.cpp
index 5ba76cbd2a1..3d555bb60ad 100644
--- a/src/osd/modules/render/bgfxutil.cpp
+++ b/src/osd/modules/render/bgfxutil.cpp
@@ -7,42 +7,97 @@
//============================================================
// MAMEOS headers
-#include "emu.h"
#include "bgfxutil.h"
#include "copyutil.h"
+#include "emucore.h"
#include "render.h"
-const bgfx::Memory* bgfx_util::mame_texture_data_to_bgfx_texture_data(uint32_t format, int width, int height, int rowpixels, const rgb_t *palette, void *base)
+const bgfx::Memory* bgfx_util::mame_texture_data_to_bgfx_texture_data(bgfx::TextureFormat::Enum &dst_format, uint32_t src_format, int rowpixels, int width_margin, int height, const rgb_t *palette, void *base, uint16_t &out_pitch, int &width_div_factor, int &width_mul_factor)
{
- const bgfx::Memory* mem = bgfx::alloc(width * height * 4);
- uint32_t* data = reinterpret_cast<uint32_t*>(mem->data);
- uint16_t* src16 = reinterpret_cast<uint16_t*>(base);
- uint32_t* src32 = reinterpret_cast<uint32_t*>(base);
+ bgfx::TextureInfo info;
+ const bgfx::Memory *data = nullptr;
+ uint8_t *adjusted_base = (uint8_t *)base;
+
+ switch (src_format)
+ {
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_YUY16):
+ dst_format = bgfx::TextureFormat::BGRA8;
+ width_div_factor = 2;
+ width_mul_factor = 1;
+ out_pitch = rowpixels * 2;
+ bgfx::calcTextureSize(info, rowpixels / width_div_factor, height, 1, false, false, 1, dst_format);
+
+ if (width_margin)
+ {
+ adjusted_base -= width_margin * 2;
+ }
+ data = bgfx::copy(adjusted_base, info.storageSize);
+ break;
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_PALETTE16):
+ dst_format = bgfx::TextureFormat::R8;
+ width_div_factor = 1;
+ width_mul_factor = 2;
+ out_pitch = rowpixels * 2;
+ bgfx::calcTextureSize(info, rowpixels * width_mul_factor, height, 1, false, false, 1, dst_format);
+
+ if (width_margin)
+ {
+ adjusted_base -= width_margin * 2;
+ }
+ data = bgfx::copy(adjusted_base, info.storageSize);
+ break;
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32):
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_RGB32):
+ dst_format = bgfx::TextureFormat::BGRA8;
+ width_div_factor = 1;
+ width_mul_factor = 1;
+ out_pitch = rowpixels * 4;
+ bgfx::calcTextureSize(info, rowpixels, height, 1, false, false, 1, dst_format);
+
+ if (width_margin)
+ {
+ adjusted_base -= width_margin * 4;
+ }
+ data = bgfx::copy(adjusted_base, info.storageSize);
+ break;
+ }
+
+ return data;
+}
+
+const bgfx::Memory* bgfx_util::mame_texture_data_to_bgra32(uint32_t src_format, int width, int height, int rowpixels, const rgb_t *palette, void *base)
+{
+ const bgfx::Memory* mem = bgfx::alloc(rowpixels * height * 4);
+ auto* dst = reinterpret_cast<uint32_t*>(mem->data);
+ auto* src16 = reinterpret_cast<uint16_t*>(base);
+ auto* src32 = reinterpret_cast<uint32_t*>(base);
for (int y = 0; y < height; y++)
{
- uint32_t* dst_line = data + y * width;
- uint16_t* src_line16 = src16 + y * rowpixels;
- uint32_t* src_line32 = src32 + y * rowpixels;
- switch (format)
+ switch (src_format)
{
- case PRIMFLAG_TEXFORMAT(TEXFORMAT_PALETTE16):
- copy_util::copyline_palette16(dst_line, src_line16, width, palette);
- break;
- case PRIMFLAG_TEXFORMAT(TEXFORMAT_YUY16):
- copy_util::copyline_yuy16_to_argb(dst_line, src_line16, width, palette, 1);
- break;
- case PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32):
- copy_util::copyline_argb32(dst_line, src_line32, width, palette);
- break;
- case PRIMFLAG_TEXFORMAT(TEXFORMAT_RGB32):
- copy_util::copyline_rgb32(dst_line, src_line32, width, palette);
- break;
- default:
- break;
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_PALETTE16):
+ copy_util::copyline_palette16_to_bgra(dst, src16, width, palette);
+ src16 += rowpixels;
+ break;
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_YUY16):
+ copy_util::copyline_yuy16_to_bgra(dst, src16, width, palette, 1);
+ src16 += rowpixels;
+ break;
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32):
+ copy_util::copyline_argb32_to_bgra(dst, src32, width, palette);
+ src32 += rowpixels;
+ break;
+ case PRIMFLAG_TEXFORMAT(TEXFORMAT_RGB32):
+ copy_util::copyline_rgb32_to_bgra(dst, src32, width, palette);
+ src32 += rowpixels;
+ break;
+ default:
+ break;
}
+ dst += width;
}
return mem;
}
@@ -54,7 +109,8 @@ uint64_t bgfx_util::get_blend_state(uint32_t blend)
case BLENDMODE_ALPHA:
return BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA);
case BLENDMODE_RGB_MULTIPLY:
- return BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_DST_COLOR, BGFX_STATE_BLEND_ZERO);
+ //return BGFX_STATE_BLEND_FUNC_SEPARATE(BGFX_STATE_BLEND_DST_COLOR, BGFX_STATE_BLEND_INV_SRC_COLOR, BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_ZERO);
+ return BGFX_STATE_BLEND_FUNC_SEPARATE(BGFX_STATE_BLEND_DST_COLOR, BGFX_STATE_BLEND_ZERO, BGFX_STATE_BLEND_DST_ALPHA, BGFX_STATE_BLEND_ZERO);
case BLENDMODE_ADD:
return BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_ONE);
default:
@@ -62,3 +118,15 @@ uint64_t bgfx_util::get_blend_state(uint32_t blend)
}
return 0L;
}
+
+void bgfx_util::find_prescale_factor(uint16_t width, uint16_t height, uint16_t max_prescale_size, uint16_t &xprescale, uint16_t &yprescale)
+{
+ while (xprescale > 1 && width * xprescale > max_prescale_size)
+ {
+ xprescale--;
+ }
+ while (yprescale > 1 && height * yprescale > max_prescale_size)
+ {
+ yprescale--;
+ }
+}
diff --git a/src/osd/modules/render/bgfxutil.h b/src/osd/modules/render/bgfxutil.h
index c733987ef18..aa108a6fb3b 100644
--- a/src/osd/modules/render/bgfxutil.h
+++ b/src/osd/modules/render/bgfxutil.h
@@ -7,12 +7,18 @@
#include <bgfx/bgfx.h>
+#include "palette.h"
+
+#include <cstdint>
+
/* sdl_info is the information about SDL for the current screen */
class bgfx_util
{
public:
- static const bgfx::Memory* mame_texture_data_to_bgfx_texture_data(uint32_t format, int width, int height, int rowpixels, const rgb_t *palette, void *base);
+ static const bgfx::Memory* mame_texture_data_to_bgfx_texture_data(bgfx::TextureFormat::Enum &dst_format, uint32_t format, int rowpixels, int width_margin, int height, const rgb_t *palette, void *base, uint16_t &out_pitch, int &width_div_factor, int &width_mul_factor);
+ static const bgfx::Memory* mame_texture_data_to_bgra32(uint32_t src_format, int width, int height, int rowpixels, const rgb_t *palette, void *base);
static uint64_t get_blend_state(uint32_t blend);
+ static void find_prescale_factor(uint16_t width, uint16_t height, uint16_t max_prescale_size, uint16_t &xprescale, uint16_t &yprescale);
};
#endif // RENDER_BGFX_UTIL
diff --git a/src/osd/modules/render/binpacker.cpp b/src/osd/modules/render/binpacker.cpp
index aa80f600e2a..7c605ff7275 100644
--- a/src/osd/modules/render/binpacker.cpp
+++ b/src/osd/modules/render/binpacker.cpp
@@ -6,9 +6,10 @@
//
//============================================================
-#include "emu.h"
#include "binpacker.h"
+
#include <algorithm>
+#include <cstddef>
bool rectangle_packer::pack(const std::vector<packable_rectangle>& rects, std::vector<std::vector<packed_rectangle>>& packs, int pack_size)
{
@@ -19,7 +20,7 @@ bool rectangle_packer::pack(const std::vector<packable_rectangle>& rects, std::v
// Add rects to member array, and check to make sure none is too big
for (size_t rect = 0; rect < rects.size(); rect++)
{
- m_rects.push_back(rectangle(0, 0, rects[rect].width(), rects[rect].height(), rects[rect].hash(), rects[rect].format(), rects[rect].rowpixels(), rects[rect].palette(), rects[rect].base()));
+ m_rects.emplace_back(rectangle(0, 0, rects[rect].width(), rects[rect].height(), rects[rect].hash(), rects[rect].format(), rects[rect].rowpixels(), rects[rect].palette(), rects[rect].base()));
}
// Sort from greatest to least area
@@ -29,7 +30,7 @@ bool rectangle_packer::pack(const std::vector<packable_rectangle>& rects, std::v
while (m_num_packed < (int)m_rects.size())
{
int i = m_packs.size();
- m_packs.push_back(rectangle(m_pack_size));
+ m_packs.emplace_back(rectangle(m_pack_size));
m_roots.push_back(i);
if (!fill(i))
{
@@ -179,7 +180,7 @@ void rectangle_packer::add_pack_to_array(int pack, std::vector<packed_rectangle>
{
if (m_packs[pack].hash != 0)
{
- array.push_back(packed_rectangle(m_packs[pack].hash, m_packs[pack].format,
+ array.emplace_back(packed_rectangle(m_packs[pack].hash, m_packs[pack].format,
m_packs[pack].w, m_packs[pack].h, m_packs[pack].x, m_packs[pack].y,
m_packs[pack].rowpixels, m_packs[pack].palette, m_packs[pack].base));
diff --git a/src/osd/modules/render/binpacker.h b/src/osd/modules/render/binpacker.h
index 55bd03116e5..52efe4abb85 100644
--- a/src/osd/modules/render/binpacker.h
+++ b/src/osd/modules/render/binpacker.h
@@ -5,7 +5,9 @@
#ifndef __RECTPACKER_H__
#define __RECTPACKER_H__
+#include "bitmap.h"
+#include <cstdint>
#include <vector>
class rectangle_packer
@@ -27,7 +29,7 @@ public:
class packable_rectangle
{
public:
- packable_rectangle() : m_hash(0), m_width(-1), m_height(-1) { }
+ packable_rectangle() = default;
packable_rectangle(uint32_t hash, uint32_t format, int width, int height, int rowpixels, const rgb_t *palette, void *base)
: m_hash(hash)
, m_format(format)
@@ -48,19 +50,19 @@ public:
void* base() const { return m_base; }
private:
- uint32_t m_hash;
- uint32_t m_format;
- int m_width;
- int m_height;
- int m_rowpixels;
- const rgb_t* m_palette;
- void* m_base;
+ uint32_t m_hash = 0;
+ uint32_t m_format = 0;
+ int m_width = -1;
+ int m_height = -1;
+ int m_rowpixels = 0;
+ const rgb_t* m_palette = nullptr;
+ void* m_base = nullptr;
};
class packed_rectangle
{
public:
- packed_rectangle() : m_hash(0), m_format(0), m_width(-1), m_height(-1), m_x(-1), m_y(-1), m_rowpixels(0), m_palette(nullptr), m_base(nullptr) { }
+ packed_rectangle() = default;
packed_rectangle(const packed_rectangle& rect)
: m_hash(rect.m_hash)
, m_format(rect.m_format)
@@ -97,15 +99,15 @@ public:
void* base() const { return m_base; }
private:
- uint32_t m_hash;
- uint32_t m_format;
- int m_width;
- int m_height;
- int m_x;
- int m_y;
- int m_rowpixels;
- const rgb_t* m_palette;
- void* m_base;
+ uint32_t m_hash = 0;
+ uint32_t m_format = 0;
+ int m_width = -1;
+ int m_height = -1;
+ int m_x = -1;
+ int m_y = -1;
+ int m_rowpixels = 0;
+ const rgb_t* m_palette = nullptr;
+ void* m_base = nullptr;
};
bool pack(const std::vector<packable_rectangle>& rects, std::vector<std::vector<packed_rectangle>>& packs, int pack_size);
diff --git a/src/osd/modules/render/blit13.h b/src/osd/modules/render/blit13.ipp
index f3dcea9bf0d..1ac485bab8d 100644
--- a/src/osd/modules/render/blit13.h
+++ b/src/osd/modules/render/blit13.ipp
@@ -119,9 +119,9 @@ FUNCTOR(op_yuv16pal_argb32rot, return pixel_ycc_to_rgb_pal(&src, palbase); )
// Copy and rotation
//============================================================
-struct blit_base {
- blit_base(int dest_bpp, bool is_rot, bool is_passthrough)
- : m_dest_bpp(dest_bpp), m_is_rot(is_rot), m_is_passthrough(is_passthrough)
+struct blit_base
+{
+ blit_base(int dest_bpp, bool is_rot, bool is_passthrough) : m_dest_bpp(dest_bpp), m_is_rot(is_rot), m_is_passthrough(is_passthrough)
{ }
virtual ~blit_base() { }
@@ -137,13 +137,12 @@ struct blit_texcopy : public blit_base
blit_texcopy() : blit_base(sizeof(_dest_type) / _len_div, false, false) { }
void texop(const texture_info *texture, const render_texinfo *texsource) const override
{
- ATTR_UNUSED const rgb_t *palbase = texsource->palette;
- int x, y;
+ const rgb_t *palbase = texsource->palette;
/* loop over Y */
- for (y = 0; y < texsource->height; y++) {
+ for (int y = 0; y < texsource->height; y++) {
_src_type *src = (_src_type *)texsource->base + y * texsource->rowpixels / (_len_div);
_dest_type *dst = (_dest_type *)((uint8_t *)texture->m_pixels + y * texture->m_pitch);
- x = texsource->width / (_len_div);
+ int x = texsource->width / (_len_div);
while (x > 0) {
*dst++ = m_op.op(*src, palbase);
++src;
@@ -164,17 +163,16 @@ struct blit_texrot : public blit_base
blit_texrot() : blit_base(sizeof(_dest_type), true, false) { }
void texop(const texture_info *texture, const render_texinfo *texsource) const override
{
- ATTR_UNUSED const rgb_t *palbase = texsource->palette;
- int x, y;
+ const rgb_t *palbase = texsource->palette;
const quad_setup_data *setup = &texture->m_setup;
int dudx = setup->dudx;
int dvdx = setup->dvdx;
/* loop over Y */
- for (y = 0; y < setup->rotheight; y++) {
+ for (int y = 0; y < setup->rotheight; y++) {
int32_t curu = setup->startu + y * setup->dudy;
int32_t curv = setup->startv + y * setup->dvdy;
_dest_type *dst = (_dest_type *)((uint8_t *)texture->m_pixels + y * texture->m_pitch);
- x = setup->rotwidth;
+ int x = setup->rotwidth;
while (x>0) {
_src_type *src = (_src_type *) texsource->base + (curv >> 16) * texsource->rowpixels + (curu >> 16);
*dst++ = m_op.op(*src, palbase);
diff --git a/src/osd/modules/render/copyutil.h b/src/osd/modules/render/copyutil.h
index 715fcba0dca..65a47a5b332 100644
--- a/src/osd/modules/render/copyutil.h
+++ b/src/osd/modules/render/copyutil.h
@@ -11,6 +11,10 @@
#ifndef __RENDER_COPYUTIL__
#define __RENDER_COPYUTIL__
+#include "palette.h"
+
+#include <cassert>
+
class copy_util
{
@@ -24,6 +28,15 @@ public:
}
}
+ static inline void copyline_palette16_to_bgra(uint32_t *dst, const uint16_t *src, int width, const rgb_t *palette)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ rgb_t srcpixel = palette[*src++];
+ *dst++ = 0xff000000 | (srcpixel.r() << 16) | (srcpixel.g() << 8) | srcpixel.b();
+ }
+ }
+
static inline void copyline_rgb32(uint32_t *dst, const uint32_t *src, int width, const rgb_t *palette)
{
int x;
@@ -49,6 +62,32 @@ public:
}
}
+ static inline void copyline_rgb32_to_bgra(uint32_t *dst, const uint32_t *src, int width, const rgb_t *palette)
+ {
+ int x;
+
+ // palette (really RGB map) case
+ if (palette != nullptr)
+ {
+ for (x = 0; x < width; x++)
+ {
+ rgb_t srcpix = *src++;
+ uint32_t val = 0xff000000 | palette[0x200 + srcpix.b()] | palette[0x100 + srcpix.g()] | palette[srcpix.r()];
+ *dst++ = (val & 0xff00ff00) | ((val & 0x000000ff) << 16) | ((val & 0x00ff0000) >> 16);
+ }
+ }
+
+ // direct case
+ else
+ {
+ for (x = 0; x < width; x++)
+ {
+ rgb_t srcpix = *src++;
+ *dst++ = 0xff000000 | (srcpix.r() << 16) | (srcpix.g() << 8) | srcpix.b();
+ }
+ }
+ }
+
static inline void copyline_argb32(uint32_t *dst, const uint32_t *src, int width, const rgb_t *palette)
{
int x;
@@ -73,6 +112,31 @@ public:
}
}
+ static inline void copyline_argb32_to_bgra(uint32_t *dst, const uint32_t *src, int width, const rgb_t *palette)
+ {
+ int x;
+ // palette (really RGB map) case
+ if (palette != nullptr)
+ {
+ for (x = 0; x < width; x++)
+ {
+ rgb_t srcpix = *src++;
+ uint32_t val = (srcpix & 0xff000000) | palette[0x200 + srcpix.b()] | palette[0x100 + srcpix.g()] | palette[srcpix.r()];
+ *dst++ = (val & 0xff00ff00) | ((val & 0x000000ff) << 16) | ((val & 0x00ff0000) >> 16);
+ }
+ }
+
+ // direct case
+ else
+ {
+ for (x = 0; x < width; x++)
+ {
+ rgb_t srcpix = *src++;
+ *dst++ = (srcpix.a() << 24) | (srcpix.r() << 16) | (srcpix.g() << 8) | srcpix.b();
+ }
+ }
+ }
+
static inline uint32_t ycc_to_rgb(uint8_t y, uint8_t cb, uint8_t cr)
{
/* original equations:
@@ -116,14 +180,12 @@ public:
static inline void copyline_yuy16_to_argb(uint32_t *dst, const uint16_t *src, int width, const rgb_t *palette, int xprescale)
{
- int x;
-
assert(width % 2 == 0);
// palette (really RGB map) case
if (palette != nullptr)
{
- for (x = 0; x < width / 2; x++)
+ for (int x = 0; x < width / 2; x++)
{
uint16_t srcpix0 = *src++;
uint16_t srcpix1 = *src++;
@@ -139,7 +201,7 @@ public:
// direct case
else
{
- for (x = 0; x < width; x += 2)
+ for (int x = 0; x < width; x += 2)
{
uint16_t srcpix0 = *src++;
uint16_t srcpix1 = *src++;
@@ -152,6 +214,55 @@ public:
}
}
}
+
+ static inline void copyline_yuy16_to_bgra(uint32_t *dst, const uint16_t *src, int width, const rgb_t *palette, int xprescale)
+ {
+ assert(width % 2 == 0);
+
+ // palette (really RGB map) case
+ if (palette != nullptr)
+ {
+ for (int x = 0; x < width / 2; x++)
+ {
+ uint16_t srcpix0 = *src++;
+ uint16_t srcpix1 = *src++;
+ uint8_t cb = srcpix0 & 0xff;
+ uint8_t cr = srcpix1 & 0xff;
+ for (int x2 = 0; x2 < xprescale; x2++)
+ {
+ uint32_t val = ycc_to_rgb(palette[0x000 + (srcpix0 >> 8)], cb, cr);
+ *dst++ = (val & 0xff00ff00) | ((val & 0x000000ff) << 16) | ((val & 0x00ff0000) >> 16);
+ }
+ for (int x2 = 0; x2 < xprescale; x2++)
+ {
+ uint32_t val = ycc_to_rgb(palette[0x000 + (srcpix1 >> 8)], cb, cr);
+ *dst++ = (val & 0xff00ff00) | ((val & 0x000000ff) << 16) | ((val & 0x00ff0000) >> 16);
+ }
+ }
+ }
+
+ // direct case
+ else
+ {
+ for (int x = 0; x < width; x += 2)
+ {
+ uint16_t srcpix0 = *src++;
+ uint16_t srcpix1 = *src++;
+ uint8_t cb = srcpix0 & 0xff;
+ uint8_t cr = srcpix1 & 0xff;
+ for (int x2 = 0; x2 < xprescale; x2++)
+ {
+ uint32_t val = ycc_to_rgb(srcpix0 >> 8, cb, cr);
+ *dst++ = (val & 0xff00ff00) | ((val & 0x000000ff) << 16) | ((val & 0x00ff0000) >> 16);
+ }
+ for (int x2 = 0; x2 < xprescale; x2++)
+ {
+ uint32_t val = ycc_to_rgb(srcpix1 >> 8, cb, cr);
+ *dst++ = (val & 0xff00ff00) | ((val & 0x000000ff) << 16) | ((val & 0x00ff0000) >> 16);
+ }
+ }
+ }
+ }
};
#endif // __RENDER_COPYUTIL__
diff --git a/src/osd/modules/render/d3d/d3dcomm.h b/src/osd/modules/render/d3d/d3dcomm.h
index d576c5e7d0c..846d9dac791 100644
--- a/src/osd/modules/render/d3d/d3dcomm.h
+++ b/src/osd/modules/render/d3d/d3dcomm.h
@@ -6,8 +6,22 @@
//
//============================================================
-#ifndef __WIN_D3DCOMM__
-#define __WIN_D3DCOMM__
+#ifndef MAME_RENDER_D3D_D3DCOMM_H
+#define MAME_RENDER_D3D_D3DCOMM_H
+
+#pragma once
+
+// lib/util
+#include "bitmap.h"
+
+#include <windows.h>
+#include <d3d9.h>
+#include <wrl/client.h>
+
+#include <cstring>
+#include <memory>
+#include <vector>
+
//============================================================
// CONSTANTS
@@ -60,10 +74,7 @@ public:
class d3d_texture_manager
{
public:
- d3d_texture_manager(): m_renderer(nullptr), m_dynamic_supported(0), m_stretch_supported(0), m_yuv_format(), m_texture_caps(0), m_texture_max_aspect(0), m_texture_max_width(0), m_texture_max_height(0), m_default_texture(nullptr)
- { }
-
- d3d_texture_manager(renderer_d3d9 *d3d);
+ d3d_texture_manager(renderer_d3d9 &d3d, IDirect3D9 *d3dobj);
void update_textures();
@@ -73,9 +84,6 @@ public:
texture_info * find_texinfo(const render_texinfo *texture, uint32_t flags);
uint32_t texture_compute_hash(const render_texinfo *texture, uint32_t flags);
- bool is_dynamic_supported() const { return (bool)m_dynamic_supported; }
- void set_dynamic_supported(bool dynamic_supported) { m_dynamic_supported = dynamic_supported; }
- bool is_stretch_supported() const { return (bool)m_stretch_supported; }
D3DFORMAT get_yuv_format() const { return m_yuv_format; }
DWORD get_texture_caps() const { return m_texture_caps; }
@@ -85,14 +93,12 @@ public:
texture_info * get_default_texture() const { return m_default_texture; }
- renderer_d3d9 * get_d3d() const { return m_renderer; }
+ renderer_d3d9 & get_d3d() const { return m_renderer; }
- std::vector<std::unique_ptr<texture_info>> m_texture_list; // list of active textures
+ std::vector<std::unique_ptr<texture_info> > m_texture_list; // list of active textures
private:
- renderer_d3d9 * m_renderer;
- int m_dynamic_supported; // are dynamic textures supported?
- int m_stretch_supported; // is StretchRect with point filtering supported?
+ renderer_d3d9 & m_renderer;
D3DFORMAT m_yuv_format; // format to use for YUV textures
DWORD m_texture_caps; // textureCaps field
@@ -109,7 +115,7 @@ private:
class texture_info
{
public:
- texture_info(d3d_texture_manager *manager, const render_texinfo *texsource, int prescale, uint32_t flags);
+ texture_info(d3d_texture_manager &manager, const render_texinfo *texsource, int prescale, uint32_t flags);
~texture_info();
render_texinfo & get_texinfo() { return m_texinfo; }
@@ -130,15 +136,16 @@ public:
int get_cur_frame() const { return m_cur_frame; }
- IDirect3DTexture9 * get_tex() const { return m_d3dtex; }
- IDirect3DSurface9 * get_surface() const { return m_d3dsurface; }
- IDirect3DTexture9 * get_finaltex() const { return m_d3dfinaltex; }
+ IDirect3DTexture9 * get_finaltex() const { return m_d3dfinaltex.Get(); }
vec2f & get_uvstart() { return m_start; }
vec2f & get_uvstop() { return m_stop; }
vec2f & get_rawdims() { return m_rawdims; }
private:
+ using IDirect3DTexture9Ptr = Microsoft::WRL::ComPtr<IDirect3DTexture9>;
+ using IDirect3DSurface9Ptr = Microsoft::WRL::ComPtr<IDirect3DSurface9>;
+
void prescale();
void compute_size(int texwidth, int texheight);
void compute_size_subroutine(int texwidth, int texheight, int* p_width, int* p_height);
@@ -150,23 +157,23 @@ private:
inline void copyline_yuy16_to_uyvy(uint16_t *dst, const uint16_t *src, int width, const rgb_t *palette);
inline void copyline_yuy16_to_argb(uint32_t *dst, const uint16_t *src, int width, const rgb_t *palette);
- d3d_texture_manager * m_texture_manager; // texture manager pointer
+ d3d_texture_manager & m_texture_manager; // texture manager pointer
- renderer_d3d9 * m_renderer; // renderer pointer
+ renderer_d3d9 & m_renderer; // renderer pointer
- uint32_t m_hash; // hash value for the texture
- uint32_t m_flags; // rendering flags
+ const uint32_t m_hash; // hash value for the texture
+ const uint32_t m_flags; // rendering flags
render_texinfo m_texinfo; // copy of the texture info
+ const int m_type; // what type of texture are we?
vec2f m_start; // beggining UV coordinates
vec2f m_stop; // ending UV coordinates
vec2f m_rawdims; // raw dims of the texture
- int m_type; // what type of texture are we?
int m_xprescale, m_yprescale; // X/Y prescale factor
int m_xborderpix, m_yborderpix; // X/Y border pixels
int m_cur_frame; // what is our current frame?
- IDirect3DTexture9 * m_d3dtex; // Direct3D texture pointer
- IDirect3DSurface9 * m_d3dsurface; // Direct3D offscreen plain surface pointer
- IDirect3DTexture9 * m_d3dfinaltex; // Direct3D final (post-scaled) texture
+ IDirect3DTexture9Ptr m_d3dtex; // Direct3D texture pointer
+ IDirect3DSurface9Ptr m_d3dsurface; // Direct3D offscreen plain surface pointer
+ IDirect3DTexture9Ptr m_d3dfinaltex; // Direct3D final (post-scaled) texture
};
/* poly_info holds information about a single polygon/d3d primitive */
@@ -175,7 +182,7 @@ class poly_info
public:
void init(D3DPRIMITIVETYPE type, uint32_t count, uint32_t numverts,
uint32_t flags, texture_info *texture, uint32_t modmode,
- float prim_width, float prim_height)
+ float prim_width, float prim_height, uint32_t tint)
{
m_type = type;
m_count = count;
@@ -185,6 +192,7 @@ public:
m_modmode = modmode;
m_prim_width = prim_width;
m_prim_height = prim_height;
+ m_tint = tint;
}
D3DPRIMITIVETYPE type() const { return m_type; }
@@ -198,6 +206,8 @@ public:
float prim_width() const { return m_prim_width; }
float prim_height() const { return m_prim_height; }
+ DWORD tint() const { return m_tint; }
+
private:
D3DPRIMITIVETYPE m_type; // type of primitive
uint32_t m_count; // total number of primitives
@@ -209,6 +219,8 @@ private:
float m_prim_width; // used by quads
float m_prim_height; // used by quads
+
+ uint32_t m_tint; // color tint for primitive
};
/* vertex describes a single vertex */
@@ -227,24 +239,14 @@ class d3d_render_target
{
public:
// construction/destruction
- d3d_render_target(): target_width(0), target_height(0), width(0), height(0), screen_index(0), bloom_count(0)
+ d3d_render_target()
+ : target_width(0)
+ , target_height(0)
+ , width(0)
+ , height(0)
+ , screen_index(0)
+ , bloom_count(0)
{
- for (int index = 0; index < MAX_BLOOM_COUNT; index++)
- {
- bloom_texture[index] = nullptr;
- bloom_surface[index] = nullptr;
- }
-
- for (int index = 0; index < 2; index++)
- {
- source_texture[index] = nullptr;
- source_surface[index] = nullptr;
- target_texture[index] = nullptr;
- target_surface[index] = nullptr;
- }
-
- cache_texture = nullptr;
- cache_surface = nullptr;
}
~d3d_render_target();
@@ -262,20 +264,20 @@ public:
int screen_index;
- IDirect3DSurface9 *target_surface[2];
- IDirect3DTexture9 *target_texture[2];
- IDirect3DSurface9 *source_surface[2];
- IDirect3DTexture9 *source_texture[2];
+ Microsoft::WRL::ComPtr<IDirect3DSurface9> target_surface[2];
+ Microsoft::WRL::ComPtr<IDirect3DTexture9> target_texture[2];
+ Microsoft::WRL::ComPtr<IDirect3DSurface9> source_surface[2];
+ Microsoft::WRL::ComPtr<IDirect3DTexture9> source_texture[2];
- IDirect3DSurface9 *cache_surface;
- IDirect3DTexture9 *cache_texture;
+ Microsoft::WRL::ComPtr<IDirect3DSurface9> cache_surface;
+ Microsoft::WRL::ComPtr<IDirect3DTexture9> cache_texture;
- IDirect3DSurface9 *bloom_surface[MAX_BLOOM_COUNT];
- IDirect3DTexture9 *bloom_texture[MAX_BLOOM_COUNT];
+ Microsoft::WRL::ComPtr<IDirect3DSurface9> bloom_surface[MAX_BLOOM_COUNT];
+ Microsoft::WRL::ComPtr<IDirect3DTexture9> bloom_texture[MAX_BLOOM_COUNT];
float bloom_dims[MAX_BLOOM_COUNT][2];
int bloom_count;
};
-#endif
+#endif // MAME_RENDER_D3D_D3DCOMM_H
diff --git a/src/osd/modules/render/d3d/d3dhlsl.cpp b/src/osd/modules/render/d3d/d3dhlsl.cpp
index 2a91dade834..c0753f314f7 100644
--- a/src/osd/modules/render/d3d/d3dhlsl.cpp
+++ b/src/osd/modules/render/d3d/d3dhlsl.cpp
@@ -8,13 +8,18 @@
// MAME headers
#include "emu.h"
+
#include "drivenum.h"
+#include "emuopts.h"
+#include "fileio.h"
+#include "main.h"
#include "render.h"
+#include "rendlay.h"
#include "rendutil.h"
-#include "emuopts.h"
+#include "screen.h"
+
#include "aviio.h"
#include "png.h"
-#include "screen.h"
// MAMEOS headers
#include "winmain.h"
@@ -25,9 +30,13 @@
#include "strconv.h"
#include "d3dhlsl.h"
#include "../frontend/mame/ui/slider.h"
+
#include <array>
+#include <locale>
+#include <sstream>
#include <utility>
+
//============================================================
// PROTOTYPES
//============================================================
@@ -44,8 +53,6 @@ class movie_recorder
public:
movie_recorder(running_machine& machine, renderer_d3d9 *d3d, int width, int height)
: m_initialized(false), m_d3d(d3d), m_width(width), m_height(height)
- , m_sys_texture(nullptr), m_sys_surface(nullptr)
- , m_vid_texture(nullptr), m_vid_surface(nullptr)
{
HRESULT result;
@@ -76,17 +83,6 @@ public:
~movie_recorder()
{
- if (m_sys_texture != nullptr)
- m_sys_texture->Release();
-
- if (m_sys_surface != nullptr)
- m_sys_surface->Release();
-
- if (m_vid_texture != nullptr)
- m_vid_texture->Release();
-
- if (m_vid_surface != nullptr)
- m_vid_surface->Release();
}
void record(const char *name)
@@ -103,7 +99,7 @@ public:
return;
// copy the frame from video memory, where it is not accessible, to system memory
- HRESULT result = m_d3d->get_device()->GetRenderTargetData(m_vid_surface, m_sys_surface);
+ HRESULT result = m_d3d->get_device()->GetRenderTargetData(m_vid_surface.Get(), m_sys_surface.Get());
if (FAILED(result))
return;
@@ -114,8 +110,8 @@ public:
for (int y = 0; y < m_height; y++)
{
- DWORD *src = (DWORD *)((BYTE *)rect.pBits + y * rect.Pitch);
- uint32_t *dst = &m_frame.pix32(y);
+ auto *src = (DWORD *)((BYTE *)rect.pBits + y * rect.Pitch);
+ uint32_t *dst = &m_frame.pix(y);
for (int x = 0; x < m_width; x++)
{
@@ -138,7 +134,7 @@ public:
m_avi_writer->audio_frame(buffer, samples_this_frame);
}
- IDirect3DSurface9 * target_surface() { return m_vid_surface; }
+ IDirect3DSurface9 * target_surface() { return m_vid_surface.Get(); }
private:
bool m_initialized;
@@ -150,10 +146,10 @@ private:
bitmap_rgb32 m_frame;
int m_width;
int m_height;
- IDirect3DTexture9 * m_sys_texture; // texture in system memory
- IDirect3DSurface9 * m_sys_surface; // surface in system memory
- IDirect3DTexture9 * m_vid_texture; // texture in video memory
- IDirect3DSurface9 * m_vid_surface; // surface in video memory
+ Microsoft::WRL::ComPtr<IDirect3DTexture9> m_sys_texture; // texture in system memory
+ Microsoft::WRL::ComPtr<IDirect3DSurface9> m_sys_surface; // surface in system memory
+ Microsoft::WRL::ComPtr<IDirect3DTexture9> m_vid_texture; // texture in video memory
+ Microsoft::WRL::ComPtr<IDirect3DSurface9> m_vid_surface; // surface in video memory
};
@@ -162,51 +158,32 @@ private:
//============================================================
shaders::shaders() :
- d3dintf(nullptr),
machine(nullptr),
d3d(nullptr),
post_fx_enable(false),
oversampling_enable(false),
num_screens(0),
- curr_screen(0),
+ num_targets(0),
+ curr_target(0),
acc_t(0),
delta_t(0),
shadow_texture(nullptr),
lut_texture(nullptr),
ui_lut_texture(nullptr),
options(nullptr),
- black_surface(nullptr),
- black_texture(nullptr),
recording_movie(false),
render_snap(false),
- snap_copy_target(nullptr),
- snap_copy_texture(nullptr),
- snap_target(nullptr),
- snap_texture(nullptr),
snap_width(0),
snap_height(0),
initialized(false),
- backbuffer(nullptr),
curr_effect(nullptr),
- default_effect(nullptr),
- prescale_effect(nullptr),
- post_effect(nullptr),
- distortion_effect(nullptr),
- scanline_effect(nullptr),
- focus_effect(nullptr),
- phosphor_effect(nullptr),
- deconverge_effect(nullptr),
- color_effect(nullptr),
- ntsc_effect(nullptr),
- bloom_effect(nullptr),
- downsample_effect(nullptr),
- vector_effect(nullptr),
- chroma_effect(nullptr),
+ diffuse_texture(nullptr),
curr_texture(nullptr),
curr_render_target(nullptr),
curr_poly(nullptr),
d3dx_create_effect_from_file_ptr(nullptr)
{
+ std::fill(std::begin(target_to_screen), std::end(target_to_screen), 0);
}
@@ -216,14 +193,9 @@ shaders::shaders() :
shaders::~shaders()
{
- for (slider* slider : internal_sliders)
- {
- delete slider;
- }
-
- if (options != nullptr)
+ if (options && (&last_options != options))
{
- global_free(options);
+ delete options;
options = nullptr;
}
}
@@ -238,11 +210,9 @@ void shaders::save_snapshot()
if (!enabled())
return;
- auto win = d3d->assert_window();
-
int width = snap_width;
int height = snap_height;
- if (win->swap_xy())
+ if (d3d->window().swap_xy())
{
std::swap(width, height);
}
@@ -283,8 +253,7 @@ void shaders::record_movie()
return;
}
- auto win = d3d->assert_window();
- osd_dim wdim = win->get_size();
+ osd_dim wdim = d3d->window().get_size();
recorder = std::make_unique<movie_recorder>(*machine, d3d, wdim.width(), wdim.height());
recorder->record(downcast<windows_options &>(machine->options()).d3d_hlsl_write());
@@ -317,11 +286,9 @@ void shaders::render_snapshot(IDirect3DSurface9 *surface)
if (!enabled())
return;
- auto win = d3d->assert_window();
-
int width = snap_width;
int height = snap_height;
- if (win->swap_xy())
+ if (d3d->window().swap_xy())
{
std::swap(width, height);
}
@@ -331,7 +298,7 @@ void shaders::render_snapshot(IDirect3DSurface9 *surface)
return;
// copy the texture
- HRESULT result = d3d->get_device()->GetRenderTargetData(surface, snap_copy_target);
+ HRESULT result = d3d->get_device()->GetRenderTargetData(surface, snap_copy_target.Get());
if (FAILED(result))
return;
@@ -342,8 +309,8 @@ void shaders::render_snapshot(IDirect3DSurface9 *surface)
for (int y = 0; y < height; y++)
{
- DWORD *src = (DWORD *)((BYTE *)rect.pBits + y * rect.Pitch);
- uint32_t *dst = &snapshot.pix32(y);
+ auto *src = (DWORD *)((BYTE *)rect.pBits + y * rect.Pitch);
+ uint32_t *dst = &snapshot.pix(y);
for (int x = 0; x < width; x++)
{
@@ -352,49 +319,30 @@ void shaders::render_snapshot(IDirect3DSurface9 *surface)
}
emu_file file(machine->options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
- osd_file::error filerr = machine->video().open_next(file, "png");
- if (filerr != osd_file::error::NONE)
+ std::error_condition const filerr = machine->video().open_next(file, "png");
+ if (filerr)
return;
// add two text entries describing the image
std::string text1 = std::string(emulator_info::get_appname()).append(" ").append(emulator_info::get_build_version());
std::string text2 = std::string(machine->system().manufacturer).append(" ").append(machine->system().type.fullname());
- png_info pnginfo;
- pnginfo.add_text("Software", text1.c_str());
- pnginfo.add_text("System", text2.c_str());
+ util::png_info pnginfo;
+ pnginfo.add_text("Software", text1);
+ pnginfo.add_text("System", text2);
// now do the actual work
- png_error error = png_write_bitmap(file, &pnginfo, snapshot, 1 << 24, nullptr);
- if (error != PNGERR_NONE)
- osd_printf_error("Error generating PNG for HLSL snapshot: png_error = %d\n", error);
+ std::error_condition const error = util::png_write_bitmap(file, &pnginfo, snapshot, 1 << 24, nullptr);
+ if (error)
+ osd_printf_error("Error generating PNG for HLSL snapshot (%s:%d %s)\n", error.category().name(), error.value(), error.message());
result = snap_copy_target->UnlockRect();
if (FAILED(result))
osd_printf_verbose("Direct3D: Error %08lX during texture UnlockRect call\n", result);
- if (snap_texture != nullptr)
- {
- snap_texture->Release();
- snap_texture = nullptr;
- }
-
- if (snap_target != nullptr)
- {
- snap_target->Release();
- snap_target = nullptr;
- }
-
- if (snap_copy_texture != nullptr)
- {
- snap_copy_texture->Release();
- snap_copy_texture = nullptr;
- }
-
- if (snap_copy_target != nullptr)
- {
- snap_copy_target->Release();
- snap_copy_target = nullptr;
- }
+ snap_texture.Reset();
+ snap_target.Reset();
+ snap_copy_texture.Reset();
+ snap_copy_target.Reset();
}
@@ -434,25 +382,33 @@ void shaders::set_texture(texture_info *texture)
return;
}
- // set initial texture to use
- texture_info *default_texture = d3d->get_default_texture();
- default_effect->set_texture("Diffuse", (texture == nullptr) ? default_texture->get_finaltex() : texture->get_finaltex());
- if (options->yiq_enable)
+ if (texture)
{
- ntsc_effect->set_texture("Diffuse", (texture == nullptr) ? default_texture->get_finaltex() : texture->get_finaltex());
+ diffuse_texture = texture;
}
else
{
- color_effect->set_texture("Diffuse", (texture == nullptr) ? default_texture->get_finaltex() : texture->get_finaltex());
+ diffuse_texture = d3d->get_default_texture();
}
}
//============================================================
+// shaders::set_filter - indicates if screens should be
+// filtered on upscaling
+//============================================================
+
+void shaders::set_filter(bool filter_screens)
+{
+ this->filter_screens = filter_screens;
+}
+
+
+//============================================================
// shaders::init
//============================================================
-bool shaders::init(d3d_base *d3dintf, running_machine *machine, renderer_d3d9 *renderer)
+bool shaders::init(IDirect3D9 *d3dobj, running_machine *machine, renderer_d3d9 *renderer)
{
osd_printf_verbose("Direct3D: Initialize HLSL\n");
@@ -484,34 +440,29 @@ bool shaders::init(d3d_base *d3dintf, running_machine *machine, renderer_d3d9 *r
return false;
}
- d3dintf->post_fx_available = true;
-
- this->d3dintf = d3dintf;
+ this->d3dobj = d3dobj;
this->machine = machine;
this->d3d = renderer;
- enumerate_screens();
-
- windows_options &winoptions = downcast<windows_options &>(machine->options());
+ auto &winoptions = downcast<windows_options &>(machine->options());
post_fx_enable = winoptions.d3d_hlsl_enable();
oversampling_enable = winoptions.d3d_hlsl_oversampling();
snap_width = winoptions.d3d_snap_width();
snap_height = winoptions.d3d_snap_height();
- this->options = (hlsl_options*)global_alloc_clear<hlsl_options>();
- this->options->params_init = false;
-
- // copy last options if initialized
if (last_options.params_init)
{
+ // copy last options if initialized
osd_printf_verbose("Direct3D: First restore options\n");
options = &last_options;
}
-
- // read options if not initialized
- if (!options->params_init)
+ else
{
+ // read options if not initialized
+ options = new hlsl_options;
+ options->params_init = false;
+
strncpy(options->shadow_mask_texture, winoptions.screen_shadow_mask_texture(), sizeof(options->shadow_mask_texture));
options->shadow_mask_tile_mode = winoptions.screen_shadow_mask_tile_mode();
options->shadow_mask_alpha = winoptions.screen_shadow_mask_alpha();
@@ -593,6 +544,7 @@ bool shaders::init(d3d_base *d3dintf, running_machine *machine, renderer_d3d9 *r
osd_printf_verbose("Direct3D: First store options\n");
last_options = *options;
+ delete options;
options = &last_options;
}
@@ -607,11 +559,70 @@ bool shaders::init(d3d_base *d3dintf, running_machine *machine, renderer_d3d9 *r
//============================================================
+// shaders::begin_frame
+//
+// Enumerates the total number of screen textures present.
+//
+// Additionally, ensures the presence of necessary post-
+// processing geometry.
+//
+//============================================================
+
+void shaders::begin_frame(render_primitive_list *primlist)
+{
+ init_fsfx_quad();
+
+ std::fill(std::begin(target_to_screen), std::end(target_to_screen), 0);
+ std::fill(std::begin(targets_per_screen), std::end(targets_per_screen), 0);
+ EQUIVALENT_ARRAY(target_to_screen, render_container *) containers;
+
+ // Maximum potential runtime O(max_num_targets^2)
+ num_targets = 0;
+ num_screens = 0;
+ curr_target = 0;
+ for (render_primitive &prim : *primlist)
+ {
+ if (PRIMFLAG_GET_SCREENTEX(prim.flags))
+ {
+ int screen_index = 0;
+ for (; screen_index < num_screens && containers[screen_index] != prim.container; screen_index++);
+ containers[screen_index] = prim.container;
+ target_to_screen[num_targets] = screen_index;
+ targets_per_screen[screen_index]++;
+ if (screen_index >= num_screens)
+ num_screens++;
+ num_targets++;
+ }
+ }
+
+ diffuse_texture = d3d->get_default_texture();
+}
+
+
+//============================================================
+// shaders::end_frame
+//
+// Closes out any still-active effects at the end of
+// rendering.
+//
+//============================================================
+
+void shaders::end_frame()
+{
+ if (curr_effect->is_active())
+ {
+ curr_effect->end();
+ }
+}
+
+
+//============================================================
// shaders::init_fsfx_quad
//
// Called always at the start of each frame so that the two
// triangles used for the post-processing effects are always
-// at the beginning of the vertex buffer
+// at the beginning of the vertex buffer.
+//
//============================================================
void shaders::init_fsfx_quad()
@@ -708,7 +719,7 @@ int shaders::create_resources()
return 1;
}
black_texture->GetSurfaceLevel(0, &black_surface);
- result = d3d->get_device()->SetRenderTarget(0, black_surface);
+ result = d3d->get_device()->SetRenderTarget(0, black_surface.Get());
if (FAILED(result))
osd_printf_verbose("Direct3D: Error %08lX during device SetRenderTarget call\n", result);
@@ -716,12 +727,16 @@ int shaders::create_resources()
if (FAILED(result))
osd_printf_verbose("Direct3D: Error %08lX during device clear call\n", result);
- result = d3d->get_device()->SetRenderTarget(0, backbuffer);
+ result = d3d->get_device()->SetRenderTarget(0, backbuffer.Get());
if (FAILED(result))
osd_printf_verbose("Direct3D: Error %08lX during device SetRenderTarget call\n", result);
emu_file file(machine->options().art_path(), OPEN_FLAG_READ);
- render_load_png(shadow_bitmap, file, nullptr, options->shadow_mask_texture);
+ if (!file.open(options->shadow_mask_texture))
+ {
+ render_load_png(shadow_bitmap, file);
+ file.close();
+ }
// experimental: if we have a shadow bitmap, create a texture for it
if (shadow_bitmap.valid())
@@ -737,12 +752,16 @@ int shaders::create_resources()
texture.seqid = 0;
// now create it (no prescale, no wrap)
- auto tex = std::make_unique<texture_info>(d3d->get_texture_manager(), &texture, 1, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32));
+ auto tex = std::make_unique<texture_info>(*d3d->get_texture_manager(), &texture, 1, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32));
shadow_texture = tex.get();
d3d->get_texture_manager()->m_texture_list.push_back(std::move(tex));
}
- render_load_png(lut_bitmap, file, nullptr, options->lut_texture);
+ if (!file.open(options->lut_texture))
+ {
+ render_load_png(lut_bitmap, file);
+ file.close();
+ }
if (lut_bitmap.valid())
{
render_texinfo texture;
@@ -756,12 +775,16 @@ int shaders::create_resources()
texture.seqid = 0;
// now create it (no prescale, no wrap)
- auto tex = std::make_unique<texture_info>(d3d->get_texture_manager(), &texture, 1, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32));
+ auto tex = std::make_unique<texture_info>(*d3d->get_texture_manager(), &texture, 1, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32));
lut_texture = tex.get();
d3d->get_texture_manager()->m_texture_list.push_back(std::move(tex));
}
- render_load_png(ui_lut_bitmap, file, nullptr, options->ui_lut_texture);
+ if (!file.open(options->ui_lut_texture))
+ {
+ render_load_png(ui_lut_bitmap, file);
+ file.close();
+ }
if (ui_lut_bitmap.valid())
{
render_texinfo texture;
@@ -775,74 +798,66 @@ int shaders::create_resources()
texture.seqid = 0;
// now create it (no prescale, no wrap)
- auto tex = std::make_unique<texture_info>(d3d->get_texture_manager(), &texture, 1, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32));
+ auto tex = std::make_unique<texture_info>(*d3d->get_texture_manager(), &texture, 1, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32));
ui_lut_texture = tex.get();
d3d->get_texture_manager()->m_texture_list.push_back(std::move(tex));
}
const char *fx_dir = downcast<windows_options &>(machine->options()).screen_post_fx_dir();
- default_effect = new effect(this, d3d->get_device(), "primary.fx", fx_dir);
- post_effect = new effect(this, d3d->get_device(), "post.fx", fx_dir);
- distortion_effect = new effect(this, d3d->get_device(), "distortion.fx", fx_dir);
- prescale_effect = new effect(this, d3d->get_device(), "prescale.fx", fx_dir);
- phosphor_effect = new effect(this, d3d->get_device(), "phosphor.fx", fx_dir);
- focus_effect = new effect(this, d3d->get_device(), "focus.fx", fx_dir);
- scanline_effect = new effect(this, d3d->get_device(), "scanline.fx", fx_dir);
- deconverge_effect = new effect(this, d3d->get_device(), "deconverge.fx", fx_dir);
- color_effect = new effect(this, d3d->get_device(), "color.fx", fx_dir);
- ntsc_effect = new effect(this, d3d->get_device(), "ntsc.fx", fx_dir);
- bloom_effect = new effect(this, d3d->get_device(), "bloom.fx", fx_dir);
- downsample_effect = new effect(this, d3d->get_device(), "downsample.fx", fx_dir);
- vector_effect = new effect(this, d3d->get_device(), "vector.fx", fx_dir);
- chroma_effect = new effect(this, d3d->get_device(), "chroma.fx", fx_dir);
-
- if (!default_effect->is_valid() ||
- !post_effect->is_valid() ||
- !distortion_effect->is_valid() ||
- !prescale_effect->is_valid() ||
- !phosphor_effect->is_valid() ||
- !focus_effect->is_valid() ||
- !scanline_effect->is_valid() ||
- !deconverge_effect->is_valid() ||
- !color_effect->is_valid() ||
- !ntsc_effect->is_valid() ||
- !bloom_effect->is_valid() ||
- !downsample_effect->is_valid() ||
- !vector_effect->is_valid() ||
- !chroma_effect->is_valid())
- {
- return 1;
- }
-
- std::array<effect*, 15> effects = {
- default_effect,
- post_effect,
- distortion_effect,
- prescale_effect,
- phosphor_effect,
- focus_effect,
- scanline_effect,
- deconverge_effect,
- color_effect,
- ntsc_effect,
- color_effect,
- bloom_effect,
- downsample_effect,
- vector_effect,
- chroma_effect
- };
-
- for (int i = 0; i < effects.size(); i++)
- {
- effects[i]->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
- effects[i]->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS);
- effects[i]->add_uniform("TargetScale", uniform::UT_FLOAT, uniform::CU_TARGET_SCALE);
- effects[i]->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
- effects[i]->add_uniform("ScreenCount", uniform::UT_INT, uniform::CU_SCREEN_COUNT);
- effects[i]->add_uniform("QuadDims", uniform::UT_VEC2, uniform::CU_QUAD_DIMS);
- effects[i]->add_uniform("SwapXY", uniform::UT_BOOL, uniform::CU_SWAP_XY);
- effects[i]->add_uniform("VectorScreen", uniform::UT_BOOL, uniform::CU_VECTOR_SCREEN);
+ default_effect = std::make_unique<effect>(this, d3d->get_device(), "primary.fx", fx_dir);
+ ui_effect = std::make_unique<effect>(this, d3d->get_device(), "primary.fx", fx_dir);
+ ui_wrap_effect = std::make_unique<effect>(this, d3d->get_device(), "primary.fx", fx_dir);
+ vector_buffer_effect = std::make_unique<effect>(this, d3d->get_device(), "primary.fx", fx_dir);
+ post_effect = std::make_unique<effect>(this, d3d->get_device(), "post.fx", fx_dir);
+ distortion_effect = std::make_unique<effect>(this, d3d->get_device(), "distortion.fx", fx_dir);
+ prescale_effect = std::make_unique<effect>(this, d3d->get_device(), "prescale.fx", fx_dir);
+ prescale_point_effect = std::make_unique<effect>(this, d3d->get_device(), "prescale.fx", fx_dir);
+ phosphor_effect = std::make_unique<effect>(this, d3d->get_device(), "phosphor.fx", fx_dir);
+ focus_effect = std::make_unique<effect>(this, d3d->get_device(), "focus.fx", fx_dir);
+ scanline_effect = std::make_unique<effect>(this, d3d->get_device(), "scanline.fx", fx_dir);
+ deconverge_effect = std::make_unique<effect>(this, d3d->get_device(), "deconverge.fx", fx_dir);
+ color_effect = std::make_unique<effect>(this, d3d->get_device(), "color.fx", fx_dir);
+ ntsc_effect = std::make_unique<effect>(this, d3d->get_device(), "ntsc.fx", fx_dir);
+ bloom_effect = std::make_unique<effect>(this, d3d->get_device(), "bloom.fx", fx_dir);
+ downsample_effect = std::make_unique<effect>(this, d3d->get_device(), "downsample.fx", fx_dir);
+ vector_effect = std::make_unique<effect>(this, d3d->get_device(), "vector.fx", fx_dir);
+ chroma_effect = std::make_unique<effect>(this, d3d->get_device(), "chroma.fx", fx_dir);
+
+ std::array<effect*, 18> effects = {
+ default_effect.get(),
+ ui_effect.get(),
+ ui_wrap_effect.get(),
+ vector_buffer_effect.get(),
+ post_effect.get(),
+ distortion_effect.get(),
+ prescale_effect.get(),
+ prescale_point_effect.get(),
+ phosphor_effect.get(),
+ focus_effect.get(),
+ scanline_effect.get(),
+ deconverge_effect.get(),
+ color_effect.get(),
+ ntsc_effect.get(),
+ bloom_effect.get(),
+ downsample_effect.get(),
+ vector_effect.get(),
+ chroma_effect.get() };
+
+ for (effect *eff : effects)
+ {
+ if (!eff->is_valid())
+ return 1;
+ }
+
+ for (effect *eff : effects)
+ {
+ eff->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS);
+ eff->add_uniform("TargetScale", uniform::UT_FLOAT, uniform::CU_TARGET_SCALE);
+ eff->add_uniform("ScreenDims", uniform::UT_VEC2, uniform::CU_SCREEN_DIMS);
+ eff->add_uniform("ScreenCount", uniform::UT_INT, uniform::CU_SCREEN_COUNT);
+ eff->add_uniform("SwapXY", uniform::UT_BOOL, uniform::CU_SWAP_XY);
+ eff->add_uniform("VectorScreen", uniform::UT_BOOL, uniform::CU_VECTOR_SCREEN);
}
ntsc_effect->add_uniform("CCValue", uniform::UT_FLOAT, uniform::CU_NTSC_CCFREQ);
@@ -855,6 +870,7 @@ int shaders::create_resources()
ntsc_effect->add_uniform("IFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_IFREQ);
ntsc_effect->add_uniform("QFreqResponse", uniform::UT_FLOAT, uniform::CU_NTSC_QFREQ);
ntsc_effect->add_uniform("ScanTime", uniform::UT_FLOAT, uniform::CU_NTSC_HTIME);
+ ntsc_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
color_effect->add_uniform("RedRatios", uniform::UT_VEC3, uniform::CU_COLOR_RED_RATIOS);
color_effect->add_uniform("GrnRatios", uniform::UT_VEC3, uniform::CU_COLOR_GRN_RATIOS);
@@ -862,6 +878,8 @@ int shaders::create_resources()
color_effect->add_uniform("Offset", uniform::UT_VEC3, uniform::CU_COLOR_OFFSET);
color_effect->add_uniform("Scale", uniform::UT_VEC3, uniform::CU_COLOR_SCALE);
color_effect->add_uniform("Saturation", uniform::UT_FLOAT, uniform::CU_COLOR_SATURATION);
+ color_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
+ color_effect->add_uniform("LutEnable", uniform::UT_BOOL, uniform::CU_LUT_ENABLE);
deconverge_effect->add_uniform("ConvergeX", uniform::UT_VEC3, uniform::CU_CONVERGE_LINEAR_X);
deconverge_effect->add_uniform("ConvergeY", uniform::UT_VEC3, uniform::CU_CONVERGE_LINEAR_Y);
@@ -874,6 +892,8 @@ int shaders::create_resources()
scanline_effect->add_uniform("ScanlineVariation", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_VARIATION);
scanline_effect->add_uniform("ScanlineBrightScale", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_BRIGHT_SCALE);
scanline_effect->add_uniform("ScanlineBrightOffset", uniform::UT_FLOAT, uniform::CU_POST_SCANLINE_BRIGHT_OFFSET);
+ scanline_effect->add_uniform("QuadDims", uniform::UT_VEC2, uniform::CU_QUAD_DIMS);
+ scanline_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
focus_effect->add_uniform("Defocus", uniform::UT_VEC2, uniform::CU_FOCUS_SIZE);
@@ -886,9 +906,15 @@ int shaders::create_resources()
post_effect->add_uniform("Floor", uniform::UT_VEC3, uniform::CU_POST_FLOOR);
post_effect->add_uniform("ChomaMode", uniform::UT_INT, uniform::CU_CHROMA_MODE);
post_effect->add_uniform("ConversionGain", uniform::UT_VEC3, uniform::CU_CHROMA_CONVERSION_GAIN);
+ post_effect->add_uniform("QuadDims", uniform::UT_VEC2, uniform::CU_QUAD_DIMS);
+ post_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
phosphor_effect->add_uniform("Phosphor", uniform::UT_VEC3, uniform::CU_PHOSPHOR_LIFE);
+ bloom_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
+
+ downsample_effect->add_uniform("QuadDims", uniform::UT_VEC2, uniform::CU_QUAD_DIMS);
+
chroma_effect->add_uniform("YGain", uniform::UT_VEC3, uniform::CU_CHROMA_Y_GAIN);
chroma_effect->add_uniform("ChromaA", uniform::UT_VEC2, uniform::CU_CHROMA_A);
chroma_effect->add_uniform("ChromaB", uniform::UT_VEC2, uniform::CU_CHROMA_B);
@@ -901,9 +927,19 @@ int shaders::create_resources()
distortion_effect->add_uniform("RoundCornerAmount", uniform::UT_FLOAT, uniform::CU_POST_ROUND_CORNER);
distortion_effect->add_uniform("SmoothBorderAmount", uniform::UT_FLOAT, uniform::CU_POST_SMOOTH_BORDER);
distortion_effect->add_uniform("ReflectionAmount", uniform::UT_FLOAT, uniform::CU_POST_REFLECTION);
+ distortion_effect->add_uniform("QuadDims", uniform::UT_VEC2, uniform::CU_QUAD_DIMS);
+
+ prescale_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
+
+ prescale_point_effect->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS);
- default_effect->add_uniform("LutEnable", uniform::UT_BOOL, uniform::CU_LUT_ENABLE);
- default_effect->add_uniform("UiLutEnable", uniform::UT_BOOL, uniform::CU_UI_LUT_ENABLE);
+ ui_effect->add_uniform("LutEnable", uniform::UT_BOOL, uniform::CU_LUT_ENABLE);
+ ui_effect->add_uniform("UiLutEnable", uniform::UT_BOOL, uniform::CU_UI_LUT_ENABLE);
+
+ ui_wrap_effect->add_uniform("LutEnable", uniform::UT_BOOL, uniform::CU_LUT_ENABLE);
+ ui_wrap_effect->add_uniform("UiLutEnable", uniform::UT_BOOL, uniform::CU_UI_LUT_ENABLE);
+
+ vector_buffer_effect->add_uniform("LutEnable", uniform::UT_BOOL, uniform::CU_LUT_ENABLE);
return 0;
}
@@ -915,24 +951,24 @@ int shaders::create_resources()
void shaders::begin_draw()
{
- double t;
-
if (!enabled())
- {
return;
- }
- curr_screen = 0;
- curr_effect = default_effect;
+ curr_target = 0;
+
// Update for delta_time
- t = machine->time().as_double();
+ const double t = machine->time().as_double();
delta_t = t - acc_t;
acc_t = t;
default_effect->set_technique("ScreenTechnique");
+ ui_effect->set_technique("UiTechnique");
+ ui_wrap_effect->set_technique("UiWrapTechnique");
+ vector_buffer_effect->set_technique("VectorBufferTechnique");
post_effect->set_technique("DefaultTechnique");
distortion_effect->set_technique("DefaultTechnique");
prescale_effect->set_technique("DefaultTechnique");
+ prescale_point_effect->set_technique("PointTechnique");
phosphor_effect->set_technique("DefaultTechnique");
focus_effect->set_technique("DefaultTechnique");
scanline_effect->set_technique("DefaultTechnique");
@@ -945,11 +981,31 @@ void shaders::begin_draw()
vector_effect->set_technique("DefaultTechnique");
chroma_effect->set_technique("DefaultTechnique");
- HRESULT result = d3d->get_device()->SetRenderTarget(0, backbuffer);
+ HRESULT result = d3d->get_device()->SetRenderTarget(0, backbuffer.Get());
if (FAILED(result))
{
osd_printf_verbose("Direct3D: Error %08lX during device SetRenderTarget call\n", result);
}
+
+ set_curr_effect(default_effect.get());
+}
+
+
+//============================================================
+// shaders::set_curr_effect
+//============================================================
+
+void shaders::set_curr_effect(effect *curr_effect)
+{
+ if (this->curr_effect == curr_effect)
+ {
+ return;
+ }
+ if (this->curr_effect && this->curr_effect->is_active())
+ {
+ this->curr_effect->end();
+ }
+ this->curr_effect = curr_effect;
}
@@ -976,7 +1032,7 @@ void shaders::blit(
if (clear_dst)
{
- result = d3d->get_device()->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_ARGB(1,0,0,0), 0, 0);
+ result = d3d->get_device()->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0xff,0,0,0), 0, 0);
if (FAILED(result))
{
osd_printf_verbose("Direct3D: Error %08lX during device clear call\n", result);
@@ -984,24 +1040,17 @@ void shaders::blit(
}
}
- UINT num_passes = 0;
- curr_effect->begin(&num_passes, 0);
-
- for (UINT pass = 0; pass < num_passes; pass++)
+ if (!curr_effect->is_active())
{
- curr_effect->begin_pass(pass);
-
- // add the primitives
- result = d3d->get_device()->DrawPrimitive(prim_type, prim_index, prim_count);
- if (FAILED(result))
- {
- osd_printf_verbose("Direct3D: Error %08lX during device DrawPrimitive call\n", result);
- }
-
- curr_effect->end_pass();
+ curr_effect->begin(0);
}
- curr_effect->end();
+ // add the primitives
+ result = d3d->get_device()->DrawPrimitive(prim_type, prim_index, prim_count);
+ if (FAILED(result))
+ {
+ osd_printf_verbose("Direct3D: Error %08lX during device DrawPrimitive call\n", result);
+ }
}
//============================================================
@@ -1038,14 +1087,15 @@ int shaders::ntsc_pass(d3d_render_target *rt, int source_index, poly_info *poly,
// initial "Diffuse" texture is set in shaders::set_texture()
- curr_effect = ntsc_effect;
+ set_curr_effect(ntsc_effect.get());
+ curr_effect->set_texture("Diffuse", diffuse_texture->get_finaltex());
curr_effect->update_uniforms();
curr_effect->set_float("SignalOffset", signal_offset);
next_index = rt->next_index(next_index);
- blit(rt->source_surface[next_index], false, D3DPT_TRIANGLELIST, 0, 2);
+ blit(rt->source_surface[next_index].Get(), false, D3DPT_TRIANGLELIST, 0, 2);
- color_effect->set_texture("Diffuse", rt->source_texture[next_index]);
+ color_effect->set_texture("Diffuse", rt->source_texture[next_index].Get());
return next_index;
}
@@ -1085,22 +1135,32 @@ rgb_t shaders::apply_color_convolution(rgb_t color)
b = chroma[2] * saturation + luma;
return rgb_t(
- std::max(0, std::min(255, int(r * 255.0f))),
- std::max(0, std::min(255, int(g * 255.0f))),
- std::max(0, std::min(255, int(b * 255.0f))));
+ std::clamp(int(r * 255.0f), 0, 255),
+ std::clamp(int(g * 255.0f), 0, 255),
+ std::clamp(int(b * 255.0f), 0, 255));
}
int shaders::color_convolution_pass(d3d_render_target *rt, int source_index, poly_info *poly, int vertnum)
{
int next_index = source_index;
- curr_effect = color_effect;
- curr_effect->update_uniforms();
+ set_curr_effect(color_effect.get());
+
+ // initial "Diffuse" texture is set in shaders::ntsc_pass() if NTSC processing is enabled
+ if (!options->yiq_enable)
+ {
+ curr_effect->set_texture("Diffuse", diffuse_texture->get_finaltex());
+ }
- // initial "Diffuse" texture is set in shaders::set_texture() or the result of shaders::ntsc_pass()
+ curr_effect->update_uniforms();
+ uint32_t tint = (uint32_t)poly->tint();
+ float prim_tint[3] = { ((tint >> 16) & 0xff) / 255.0f, ((tint >> 8) & 0xff) / 255.0f, (tint & 0xff) / 255.0f };
+ curr_effect->set_vector("PrimTint", 3, prim_tint);
+ curr_effect->set_texture("LutTexture", !lut_texture ? nullptr : lut_texture->get_finaltex());
+ curr_effect->set_bool("UiLutEnable", false);
next_index = rt->next_index(next_index);
- blit(rt->source_surface[next_index], false, D3DPT_TRIANGLELIST, 0, 2);
+ blit(rt->source_surface[next_index].Get(), false, D3DPT_TRIANGLELIST, 0, 2);
return next_index;
}
@@ -1109,12 +1169,12 @@ int shaders::prescale_pass(d3d_render_target *rt, int source_index, poly_info *p
{
int next_index = source_index;
- curr_effect = prescale_effect;
+ set_curr_effect(filter_screens ? prescale_effect.get() : prescale_point_effect.get());
curr_effect->update_uniforms();
- curr_effect->set_texture("Diffuse", rt->source_texture[next_index]);
+ curr_effect->set_texture("Diffuse", rt->source_texture[next_index].Get());
next_index = rt->next_index(next_index);
- blit(rt->target_surface[next_index], false, D3DPT_TRIANGLELIST, 0, 2);
+ blit(rt->target_surface[next_index].Get(), false, D3DPT_TRIANGLELIST, 0, 2);
return next_index;
}
@@ -1132,12 +1192,12 @@ int shaders::deconverge_pass(d3d_render_target *rt, int source_index, poly_info
return next_index;
}
- curr_effect = deconverge_effect;
+ set_curr_effect(deconverge_effect.get());
curr_effect->update_uniforms();
- curr_effect->set_texture("Diffuse", rt->target_texture[next_index]);
+ curr_effect->set_texture("Diffuse", rt->target_texture[next_index].Get());
next_index = rt->next_index(next_index);
- blit(rt->target_surface[next_index], false, D3DPT_TRIANGLELIST, 0, 2);
+ blit(rt->target_surface[next_index].Get(), false, D3DPT_TRIANGLELIST, 0, 2);
return next_index;
}
@@ -1147,12 +1207,11 @@ int shaders::scanline_pass(d3d_render_target *rt, int source_index, poly_info *p
int next_index = source_index;
// skip scanline if alpha is 0
- if (options->scanline_alpha == 0.0f)
- return next_index;
+ //if (options->scanline_alpha == 0.0f)
+ //return next_index;
- auto win = d3d->assert_window();
- screen_device_iterator screen_iterator(machine->root_device());
- screen_device *screen = screen_iterator.byindex(curr_screen);
+ screen_device_enumerator screen_iterator(machine->root_device());
+ screen_device *screen = screen_iterator.byindex(target_to_screen[curr_target]);
render_container &screen_container = screen->container();
float xscale = 1.0f / screen_container.xscale();
float yscale = 1.0f / screen_container.yscale();
@@ -1161,16 +1220,16 @@ int shaders::scanline_pass(d3d_render_target *rt, int source_index, poly_info *p
float screen_scale[] = { xscale, yscale };
float screen_offset[] = { xoffset, yoffset };
- curr_effect = scanline_effect;
+ set_curr_effect(scanline_effect.get());
curr_effect->update_uniforms();
- curr_effect->set_texture("Diffuse", rt->target_texture[next_index]);
+ curr_effect->set_texture("Diffuse", rt->target_texture[next_index].Get());
curr_effect->set_vector("ScreenScale", 2, screen_scale);
curr_effect->set_vector("ScreenOffset", 2, screen_offset);
curr_effect->set_float("ScanlineOffset",
curr_texture->get_cur_frame() == 0 ?
0.0f : options->scanline_jitter);
next_index = rt->next_index(next_index);
- blit(rt->target_surface[next_index], false, D3DPT_TRIANGLELIST, 0, 2);
+ blit(rt->target_surface[next_index].Get(), false, D3DPT_TRIANGLELIST, 0, 2);
return next_index;
}
@@ -1184,12 +1243,12 @@ int shaders::defocus_pass(d3d_render_target *rt, int source_index, poly_info *po
return next_index;
}
- curr_effect = focus_effect;
+ set_curr_effect(focus_effect.get());
curr_effect->update_uniforms();
- curr_effect->set_texture("Diffuse", rt->target_texture[next_index]);
+ curr_effect->set_texture("Diffuse", rt->target_texture[next_index].Get());
next_index = rt->next_index(next_index);
- blit(rt->target_surface[next_index], false, D3DPT_TRIANGLELIST, 0, 2);
+ blit(rt->target_surface[next_index].Get(), false, D3DPT_TRIANGLELIST, 0, 2);
return next_index;
}
@@ -1205,23 +1264,23 @@ int shaders::phosphor_pass(d3d_render_target *rt, int source_index, poly_info *p
}
// Shader needs time between last update
- curr_effect = phosphor_effect;
+ set_curr_effect(phosphor_effect.get());
curr_effect->update_uniforms();
- curr_effect->set_texture("Diffuse", rt->target_texture[next_index]);
- curr_effect->set_texture("LastPass", rt->cache_texture);
+ curr_effect->set_texture("Diffuse", rt->target_texture[next_index].Get());
+ curr_effect->set_texture("LastPass", rt->cache_texture.Get());
curr_effect->set_bool("Passthrough", false);
curr_effect->set_float("DeltaTime", delta_time());
next_index = rt->next_index(next_index);
- blit(rt->target_surface[next_index], false, D3DPT_TRIANGLELIST, 0, 2);
+ blit(rt->target_surface[next_index].Get(), false, D3DPT_TRIANGLELIST, 0, 2);
// Pass along our phosphor'd screen
curr_effect->update_uniforms();
- curr_effect->set_texture("Diffuse", rt->target_texture[next_index]);
- curr_effect->set_texture("LastPass", rt->target_texture[next_index]);
+ curr_effect->set_texture("Diffuse", rt->target_texture[next_index].Get());
+ curr_effect->set_texture("LastPass", rt->target_texture[next_index].Get());
curr_effect->set_bool("Passthrough", true);
- blit(rt->cache_surface, false, D3DPT_TRIANGLELIST, 0, 2);
+ blit(rt->cache_surface.Get(), false, D3DPT_TRIANGLELIST, 0, 2);
return next_index;
}
@@ -1230,10 +1289,8 @@ int shaders::post_pass(d3d_render_target *rt, int source_index, poly_info *poly,
{
int next_index = source_index;
- auto win = d3d->assert_window();
-
- screen_device_iterator screen_iterator(machine->root_device());
- screen_device *screen = screen_iterator.byindex(curr_screen);
+ screen_device_enumerator screen_iterator(machine->root_device());
+ screen_device *screen = screen_iterator.byindex(target_to_screen[curr_target]);
render_container &screen_container = screen->container();
float xscale = 1.0f / screen_container.xscale();
@@ -1252,11 +1309,11 @@ int shaders::post_pass(d3d_render_target *rt, int source_index, poly_info *poly,
float(back_color_rgb.g()) / 255.0f,
float(back_color_rgb.b()) / 255.0f };
- curr_effect = post_effect;
+ set_curr_effect(post_effect.get());
curr_effect->update_uniforms();
- curr_effect->set_texture("ShadowTexture", shadow_texture == nullptr ? nullptr : shadow_texture->get_finaltex());
+ curr_effect->set_texture("ShadowTexture", !shadow_texture ? nullptr : shadow_texture->get_finaltex());
curr_effect->set_int("ShadowTileMode", options->shadow_mask_tile_mode);
- curr_effect->set_texture("DiffuseTexture", rt->target_texture[next_index]);
+ curr_effect->set_texture("DiffuseTexture", rt->target_texture[next_index].Get());
curr_effect->set_vector("BackColor", 3, back_color);
curr_effect->set_vector("ScreenScale", 2, screen_scale);
curr_effect->set_vector("ScreenOffset", 2, screen_offset);
@@ -1265,7 +1322,7 @@ int shaders::post_pass(d3d_render_target *rt, int source_index, poly_info *poly,
curr_effect->set_bool("PrepareBloom", prepare_bloom);
next_index = rt->next_index(next_index);
- blit(prepare_bloom ? rt->source_surface[next_index] : rt->target_surface[next_index], false, D3DPT_TRIANGLELIST, 0, 2);
+ blit(prepare_bloom ? rt->source_surface[next_index].Get() : rt->target_surface[next_index].Get(), false, D3DPT_TRIANGLELIST, 0, 2);
return next_index;
}
@@ -1274,11 +1331,11 @@ int shaders::chroma_pass(d3d_render_target *rt, int source_index, poly_info *pol
{
int next_index = source_index;
- curr_effect = chroma_effect;
+ set_curr_effect(chroma_effect.get());
curr_effect->update_uniforms();
- curr_effect->set_texture("Diffuse", rt->target_texture[next_index]);
+ curr_effect->set_texture("Diffuse", rt->target_texture[next_index].Get());
next_index = rt->next_index(next_index);
- blit(rt->target_surface[next_index], false, D3DPT_TRIANGLELIST, 0, 2);
+ blit(rt->target_surface[next_index].Get(), false, D3DPT_TRIANGLELIST, 0, 2);
return next_index;
}
@@ -1292,18 +1349,19 @@ int shaders::downsample_pass(d3d_render_target *rt, int source_index, poly_info
return next_index;
}
- curr_effect = downsample_effect;
- curr_effect->update_uniforms();
+ set_curr_effect(downsample_effect.get());
for (int bloom_index = 0; bloom_index < rt->bloom_count; bloom_index++)
{
+ curr_effect->update_uniforms();
curr_effect->set_vector("TargetDims", 2, rt->bloom_dims[bloom_index]);
curr_effect->set_texture("DiffuseTexture",
bloom_index == 0
- ? rt->source_texture[next_index]
- : rt->bloom_texture[bloom_index - 1]);
+ ? rt->source_texture[next_index].Get()
+ : rt->bloom_texture[bloom_index - 1].Get());
- blit(rt->bloom_surface[bloom_index], false, D3DPT_TRIANGLELIST, 0, 2);
+ blit(rt->bloom_surface[bloom_index].Get(), false, D3DPT_TRIANGLELIST, 0, 2);
+ downsample_effect->end();
}
return next_index;
@@ -1319,7 +1377,7 @@ int shaders::bloom_pass(d3d_render_target *rt, int source_index, poly_info *poly
return next_index;
}
- curr_effect = bloom_effect;
+ set_curr_effect(bloom_effect.get());
curr_effect->update_uniforms();
curr_effect->set_float("Level0Weight", options->bloom_level0_weight);
@@ -1336,22 +1394,22 @@ int shaders::bloom_pass(d3d_render_target *rt, int source_index, poly_info *poly
curr_effect->set_float("BloomScale", options->bloom_scale);
curr_effect->set_vector("BloomOverdrive", 3, options->bloom_overdrive);
- curr_effect->set_texture("DiffuseTexture", rt->target_texture[next_index]);
+ curr_effect->set_texture("DiffuseTexture", rt->target_texture[next_index].Get());
char name[14] = "BloomTexture*";
for (int index = 1; index < rt->bloom_count; index++)
{
name[12] = 'A' + index - 1;
- curr_effect->set_texture(name, rt->bloom_texture[index - 1]);
+ curr_effect->set_texture(name, rt->bloom_texture[index - 1].Get());
}
for (int index = rt->bloom_count; index < MAX_BLOOM_COUNT; index++)
{
name[12] = 'A' + index - 1;
- curr_effect->set_texture(name, black_texture);
+ curr_effect->set_texture(name, black_texture.Get());
}
next_index = rt->next_index(next_index);
- blit(rt->target_surface[next_index], false, D3DPT_TRIANGLELIST, 0, 2);
+ blit(rt->target_surface[next_index].Get(), false, D3DPT_TRIANGLELIST, 0, 2);
return next_index;
}
@@ -1372,12 +1430,12 @@ int shaders::distortion_pass(d3d_render_target *rt, int source_index, poly_info
return next_index;
}
- curr_effect = distortion_effect;
+ set_curr_effect(distortion_effect.get());
curr_effect->update_uniforms();
- curr_effect->set_texture("DiffuseTexture", rt->target_texture[next_index]);
+ curr_effect->set_texture("DiffuseTexture", rt->target_texture[next_index].Get());
next_index = rt->next_index(next_index);
- blit(rt->target_surface[next_index], false, D3DPT_TRIANGLELIST, 0, 2);
+ blit(rt->target_surface[next_index].Get(), false, D3DPT_TRIANGLELIST, 0, 2);
return next_index;
}
@@ -1386,14 +1444,14 @@ int shaders::vector_pass(d3d_render_target *rt, int source_index, poly_info *pol
{
int next_index = source_index;
- curr_effect = vector_effect;
+ set_curr_effect(vector_effect.get());
curr_effect->update_uniforms();
curr_effect->set_float("LengthRatio", options->vector_length_ratio);
curr_effect->set_float("LengthScale", options->vector_length_scale);
curr_effect->set_float("BeamSmooth", options->vector_beam_smooth);
// we need to clear the vector render target here
- blit(rt->target_surface[next_index], true, poly->type(), vertnum, poly->count());
+ blit(rt->target_surface[next_index].Get(), true, poly->type(), vertnum, poly->count());
return next_index;
}
@@ -1402,17 +1460,17 @@ int shaders::vector_buffer_pass(d3d_render_target *rt, int source_index, poly_in
{
int next_index = source_index;
- curr_effect = default_effect;
+ set_curr_effect(vector_buffer_effect.get());
+ curr_effect->set_texture("Diffuse", diffuse_texture->get_finaltex());
curr_effect->update_uniforms();
- curr_effect->set_technique("VectorBufferTechnique");
-
- curr_effect->set_texture("Diffuse", rt->target_texture[next_index]);
- curr_effect->set_texture("LutTexture", lut_texture == nullptr ? nullptr : lut_texture->get_finaltex());
+ curr_effect->set_texture("Diffuse", rt->target_texture[next_index].Get());
+ curr_effect->set_texture("LutTexture", !lut_texture ? nullptr : lut_texture->get_finaltex());
+ curr_effect->set_bool("UiLutEnable", false);
// we need to clear the vector render target here
next_index = rt->next_index(next_index);
- blit(rt->target_surface[next_index], true, D3DPT_TRIANGLELIST, 0, 2);
+ blit(rt->target_surface[next_index].Get(), true, D3DPT_TRIANGLELIST, 0, 2);
return next_index;
}
@@ -1423,14 +1481,16 @@ int shaders::screen_pass(d3d_render_target *rt, int source_index, poly_info *pol
d3d->set_blendmode(PRIMFLAG_GET_BLENDMODE(poly->flags()));
- curr_effect = default_effect;
+ set_curr_effect(default_effect.get());
+ curr_effect->set_texture("Diffuse", diffuse_texture->get_finaltex());
curr_effect->update_uniforms();
- curr_effect->set_technique("ScreenTechnique");
- curr_effect->set_texture("Diffuse", rt->target_texture[next_index]);
- curr_effect->set_texture("LutTexture", lut_texture == nullptr ? nullptr : lut_texture->get_finaltex());
+ curr_effect->set_texture("Diffuse", rt->target_texture[next_index].Get());
+ curr_effect->set_texture("LutTexture", nullptr);
+ curr_effect->set_bool("LutEnable", false);
+ curr_effect->set_bool("UiLutEnable", false);
- blit(backbuffer, false, poly->type(), vertnum, poly->count());
+ blit(backbuffer.Get(), false, poly->type(), vertnum, poly->count());
if (recording_movie)
{
@@ -1442,9 +1502,9 @@ int shaders::screen_pass(d3d_render_target *rt, int source_index, poly_info *pol
if (render_snap)
{
// we need to clear the snap render target here
- blit(snap_target, true, poly->type(), vertnum, poly->count());
+ blit(snap_target.Get(), true, poly->type(), vertnum, poly->count());
- render_snapshot(snap_target);
+ render_snapshot(snap_target.Get());
render_snap = false;
}
@@ -1456,11 +1516,11 @@ void shaders::ui_pass(poly_info *poly, int vertnum)
{
d3d->set_blendmode(PRIMFLAG_GET_BLENDMODE(poly->flags()));
- curr_effect = default_effect;
+ set_curr_effect(PRIMFLAG_GET_TEXWRAP(poly->flags()) ? ui_wrap_effect.get() : ui_effect.get());
+ curr_effect->set_texture("Diffuse", diffuse_texture->get_finaltex());
curr_effect->update_uniforms();
- curr_effect->set_technique("UiTechnique");
- curr_effect->set_texture("LutTexture", lut_texture == nullptr ? nullptr : ui_lut_texture->get_finaltex());
+ curr_effect->set_texture("LutTexture", !lut_texture ? nullptr : ui_lut_texture->get_finaltex());
blit(nullptr, false, poly->type(), vertnum, poly->count());
}
@@ -1480,8 +1540,6 @@ void shaders::render_quad(poly_info *poly, int vertnum)
curr_texture = poly->texture();
curr_poly = poly;
- auto win = d3d->assert_window();
-
if (PRIMFLAG_GET_SCREENTEX(poly->flags()))
{
if (curr_texture == nullptr)
@@ -1490,9 +1548,9 @@ void shaders::render_quad(poly_info *poly, int vertnum)
return;
}
- curr_screen = curr_screen < num_screens ? curr_screen : 0;
+ curr_target = curr_target < num_targets ? curr_target : 0;
- curr_render_target = find_render_target(curr_texture->get_width(), curr_texture->get_height(), curr_screen);
+ curr_render_target = find_render_target(curr_texture->get_width(), curr_texture->get_height(), curr_target);
d3d_render_target *rt = curr_render_target;
if (rt == nullptr)
@@ -1512,12 +1570,16 @@ void shaders::render_quad(poly_info *poly, int vertnum)
//next_index = phosphor_pass(rt, next_index, poly, vertnum);
// create bloom textures
- int old_index = next_index;
- next_index = post_pass(rt, next_index, poly, vertnum, true);
- next_index = downsample_pass(rt, next_index, poly, vertnum);
+ bool bloom_enabled = (options->bloom_scale > 0.0f);
+ if (bloom_enabled)
+ {
+ int old_index = next_index;
+ next_index = post_pass(rt, next_index, poly, vertnum, true);
+ next_index = downsample_pass(rt, next_index, poly, vertnum);
+ next_index = old_index;
+ }
- // apply bloom textures
- next_index = old_index;
+ // apply bloom textures (if enabled) and other post effects
next_index = post_pass(rt, next_index, poly, vertnum, false);
next_index = bloom_pass(rt, next_index, poly, vertnum);
next_index = phosphor_pass(rt, next_index, poly, vertnum);
@@ -1533,19 +1595,19 @@ void shaders::render_quad(poly_info *poly, int vertnum)
curr_texture->increment_frame_count();
curr_texture->mask_frame_count(options->yiq_phase_count);
- curr_screen++;
+ curr_target++;
}
else if (PRIMFLAG_GET_VECTOR(poly->flags()))
{
- curr_screen = curr_screen < num_screens ? curr_screen : 0;
+ curr_target = curr_target < num_targets ? curr_target : 0;
int source_width = int(poly->prim_width() + 0.5f);
int source_height = int(poly->prim_height() + 0.5f);
- if (win->swap_xy())
+ if (d3d->window().swap_xy())
{
std::swap(source_width, source_height);
}
- curr_render_target = find_render_target(source_width, source_height, curr_screen);
+ curr_render_target = find_render_target(source_width, source_height, curr_target);
d3d_render_target *rt = curr_render_target;
if (rt == nullptr)
@@ -1558,25 +1620,25 @@ void shaders::render_quad(poly_info *poly, int vertnum)
next_index = vector_pass(rt, next_index, poly, vertnum);
- HRESULT result = d3d->get_device()->SetRenderTarget(0, backbuffer);
+ HRESULT result = d3d->get_device()->SetRenderTarget(0, backbuffer.Get());
if (FAILED(result))
{
osd_printf_verbose("Direct3D: Error %08lX during device SetRenderTarget call\n", result);
}
- curr_screen++;
+ curr_target++;
}
else if (PRIMFLAG_GET_VECTORBUF(poly->flags()))
{
- curr_screen = curr_screen < num_screens ? curr_screen : 0;
+ curr_target = curr_target < num_targets ? curr_target : 0;
int source_width = int(poly->prim_width() + 0.5f);
int source_height = int(poly->prim_height() + 0.5f);
- if (win->swap_xy())
+ if (d3d->window().swap_xy())
{
std::swap(source_width, source_height);
}
- curr_render_target = find_render_target(source_width, source_height, curr_screen);
+ curr_render_target = find_render_target(source_width, source_height, curr_target);
d3d_render_target *rt = curr_render_target;
if (rt == nullptr)
@@ -1611,7 +1673,7 @@ void shaders::render_quad(poly_info *poly, int vertnum)
next_index = screen_pass(rt, next_index, poly, vertnum);
d3d->set_wrap(PRIMFLAG_GET_TEXWRAP(curr_texture->get_flags()) ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP);
- curr_screen++;
+ curr_target++;
}
else
{
@@ -1637,7 +1699,7 @@ void shaders::end_draw()
return;
}
- backbuffer->Release();
+ backbuffer->Release(); // TODO: where's the matching AddRef that requires this explicit Release?
}
@@ -1652,8 +1714,6 @@ d3d_render_target* shaders::get_texture_target(render_primitive *prim, int width
return nullptr;
}
- auto win = d3d->assert_window();
-
int source_width = width;
int source_height = height;
int source_screen = screen;
@@ -1661,7 +1721,7 @@ d3d_render_target* shaders::get_texture_target(render_primitive *prim, int width
int target_height = int(prim->get_full_quad_height() + 0.5f);
target_width *= oversampling_enable ? 2 : 1;
target_height *= oversampling_enable ? 2 : 1;
- if (win->swap_xy())
+ if (d3d->window().swap_xy())
{
std::swap(target_width, target_height);
}
@@ -1692,8 +1752,6 @@ d3d_render_target* shaders::get_vector_target(render_primitive *prim, int screen
return nullptr;
}
- auto win = d3d->assert_window();
-
int source_width = int(prim->get_quad_width() + 0.5f);
int source_height = int(prim->get_quad_height() + 0.5f);
int source_screen = screen;
@@ -1701,7 +1759,7 @@ d3d_render_target* shaders::get_vector_target(render_primitive *prim, int screen
int target_height = int(prim->get_full_quad_height() + 0.5f);
target_width *= oversampling_enable ? 2 : 1;
target_height *= oversampling_enable ? 2 : 1;
- if (win->swap_xy())
+ if (d3d->window().swap_xy())
{
std::swap(source_width, source_height);
std::swap(target_width, target_height);
@@ -1733,8 +1791,6 @@ bool shaders::create_vector_target(render_primitive *prim, int screen)
return false;
}
- auto win = d3d->assert_window();
-
int source_width = int(prim->get_quad_width() + 0.5f);
int source_height = int(prim->get_quad_height() + 0.5f);
int source_screen = screen;
@@ -1742,7 +1798,7 @@ bool shaders::create_vector_target(render_primitive *prim, int screen)
int target_height = int(prim->get_full_quad_height() + 0.5f);
target_width *= oversampling_enable ? 2 : 1;
target_height *= oversampling_enable ? 2 : 1;
- if (win->swap_xy())
+ if (d3d->window().swap_xy())
{
std::swap(source_width, source_height);
std::swap(target_width, target_height);
@@ -1778,16 +1834,6 @@ bool shaders::add_render_target(renderer_d3d9* d3d, render_primitive *prim, int
//============================================================
-// shaders::enumerate_screens
-//============================================================
-void shaders::enumerate_screens()
-{
- screen_device_iterator iter(machine->root_device());
- num_screens = iter.count();
-}
-
-
-//============================================================
// shaders::create_texture_target
//============================================================
@@ -1798,8 +1844,6 @@ bool shaders::create_texture_target(render_primitive *prim, int width, int heigh
return false;
}
- auto win = d3d->assert_window();
-
int source_width = width;
int source_height = height;
int source_screen = screen;
@@ -1807,7 +1851,7 @@ bool shaders::create_texture_target(render_primitive *prim, int width, int heigh
int target_height = int(prim->get_full_quad_height() + 0.5f);
target_width *= oversampling_enable ? 2 : 1;
target_height *= oversampling_enable ? 2 : 1;
- if (win->swap_xy())
+ if (d3d->window().swap_xy())
{
// source texture is already swapped
std::swap(target_width, target_height);
@@ -1845,93 +1889,29 @@ void shaders::delete_resources()
m_render_target_list.clear();
- if (downsample_effect != nullptr)
- {
- delete downsample_effect;
- downsample_effect = nullptr;
- }
- if (bloom_effect != nullptr)
- {
- delete bloom_effect;
- bloom_effect = nullptr;
- }
- if (vector_effect != nullptr)
- {
- delete vector_effect;
- vector_effect = nullptr;
- }
- if (default_effect != nullptr)
- {
- delete default_effect;
- default_effect = nullptr;
- }
- if (post_effect != nullptr)
- {
- delete post_effect;
- post_effect = nullptr;
- }
- if (distortion_effect != nullptr)
- {
- delete distortion_effect;
- distortion_effect = nullptr;
- }
- if (prescale_effect != nullptr)
- {
- delete prescale_effect;
- prescale_effect = nullptr;
- }
- if (phosphor_effect != nullptr)
- {
- delete phosphor_effect;
- phosphor_effect = nullptr;
- }
- if (focus_effect != nullptr)
- {
- delete focus_effect;
- focus_effect = nullptr;
- }
- if (scanline_effect != nullptr)
- {
- delete scanline_effect;
- scanline_effect = nullptr;
- }
- if (deconverge_effect != nullptr)
- {
- delete deconverge_effect;
- deconverge_effect = nullptr;
- }
- if (color_effect != nullptr)
- {
- delete color_effect;
- color_effect = nullptr;
- }
- if (ntsc_effect != nullptr)
- {
- delete ntsc_effect;
- ntsc_effect = nullptr;
- }
- if (chroma_effect != nullptr)
- {
- delete chroma_effect;
- chroma_effect = nullptr;
- }
-
- if (backbuffer != nullptr)
- {
- backbuffer->Release();
- backbuffer = nullptr;
- }
-
- if (black_surface != nullptr)
- {
- black_surface->Release();
- black_surface = nullptr;
- }
- if (black_texture != nullptr)
- {
- black_texture->Release();
- black_texture = nullptr;
- }
+ downsample_effect.reset();
+ bloom_effect.reset();
+ vector_effect.reset();
+ default_effect.reset();
+ ui_effect.reset();
+ ui_wrap_effect.reset();
+ vector_buffer_effect.reset();
+ post_effect.reset();
+ distortion_effect.reset();
+ prescale_effect.reset();
+ prescale_point_effect.reset();
+ phosphor_effect.reset();
+ focus_effect.reset();
+ scanline_effect.reset();
+ deconverge_effect.reset();
+ color_effect.reset();
+ ntsc_effect.reset();
+ chroma_effect.reset();
+
+ backbuffer.Reset();
+
+ black_surface.Reset();
+ black_texture.Reset();
shadow_bitmap.reset();
lut_bitmap.reset();
@@ -1945,25 +1925,24 @@ void shaders::delete_resources()
static void get_vector(const char *data, int count, float *out, bool report_error)
{
- if (count > 3 &&
- sscanf(data, "%f,%f,%f,%f", &out[0], &out[1], &out[2], &out[3]) < 4 && report_error)
- {
- osd_printf_error("Illegal quad vector value = %s\n", data);
- }
- else if (count > 2 &&
- sscanf(data, "%f,%f,%f", &out[0], &out[1], &out[2]) < 3 && report_error)
- {
- osd_printf_error("Illegal triple vector value = %s\n", data);
- }
- else if (count > 1 &&
- sscanf(data, "%f,%f", &out[0], &out[1]) < 2 && report_error)
- {
- osd_printf_error("Illegal double vector value = %s\n", data);
- }
- else if (count > 0 &&
- sscanf(data, "%f", &out[0]) < 1 && report_error)
+ std::istringstream is(data);
+ is.imbue(std::locale::classic());
+ for (int i = 0; count > i; )
{
- osd_printf_error("Illegal single vector value = %s\n", data);
+ is >> out[i];
+ bool bad = !is;
+ if (++i < count)
+ {
+ char ch;
+ is >> ch;
+ bad = bad || !is || (',' != ch);
+ }
+ if (bad)
+ {
+ if (report_error)
+ osd_printf_error("Illegal %d-item vector value = %s\n", count, data);
+ return;
+ }
}
}
@@ -1974,23 +1953,10 @@ static void get_vector(const char *data, int count, float *out, bool report_erro
// be done in a more ideal way.
//============================================================
-std::unique_ptr<slider_state> shaders::slider_alloc(int id, const char *title, int32_t minval, int32_t defval, int32_t maxval, int32_t incval, void *arg)
+std::unique_ptr<slider_state> shaders::slider_alloc(std::string &&title, int32_t minval, int32_t defval, int32_t maxval, int32_t incval, slider *arg)
{
- auto state = make_unique_clear<slider_state>();
-
- state->minval = minval;
- state->defval = defval;
- state->maxval = maxval;
- state->incval = incval;
-
using namespace std::placeholders;
- state->update = std::bind(&shaders::slider_changed, this, _1, _2, _3, _4, _5);
-
- state->arg = arg;
- state->id = id;
- state->description = title;
-
- return state;
+ return std::make_unique<slider_state>(std::move(title), minval, defval, maxval, incval, std::bind(&slider::update, arg, _1, _2));
}
@@ -2013,7 +1979,7 @@ int32_t slider::update(std::string *str, int32_t newval)
{
case SLIDER_INT_ENUM:
{
- int32_t *val_ptr = reinterpret_cast<int32_t *>(m_value);
+ auto *val_ptr = reinterpret_cast<int32_t *>(m_value);
if (newval != SLIDER_NOCHANGE)
{
*val_ptr = newval;
@@ -2041,7 +2007,7 @@ int32_t slider::update(std::string *str, int32_t newval)
default:
{
- float *val_ptr = reinterpret_cast<float *>(m_value);
+ auto *val_ptr = reinterpret_cast<float *>(m_value);
if (newval != SLIDER_NOCHANGE)
{
*val_ptr = (float)newval * m_desc->scale;
@@ -2056,16 +2022,7 @@ int32_t slider::update(std::string *str, int32_t newval)
return 0;
}
-int32_t shaders::slider_changed(running_machine& /*machine*/, void *arg, int /*id*/, std::string *str, int32_t newval)
-{
- if (arg != nullptr)
- {
- return reinterpret_cast<slider *>(arg)->update(str, newval);
- }
- return 0;
-}
-
-char shaders::last_system_name[16];
+char shaders::last_system_name[MAX_DRIVER_NAME_CHARS + 1];
hlsl_options shaders::last_options = { false };
@@ -2220,13 +2177,13 @@ slider_desc shaders::s_sliders[] =
{ "NTSC Frame Jitter Offset", 0, 0, 100, 1, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_JITTER, 0.01f, "%1.2f", {} },
{ "NTSC A Value", -100, 50, 100, 1, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_A_VALUE, 0.01f, "%1.2f", {} },
{ "NTSC B Value", -100, 50, 100, 1, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_B_VALUE, 0.01f, "%1.2f", {} },
- { "NTSC Incoming Phase Pixel Clock Scale",-300, 100, 300, 1, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_P_VALUE, 0.01f, "%1.2f", {} },
- { "NTSC Outgoing Phase Offset", -300, 0, 300, 1, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_O_VALUE, 0.01f, "%1.2f", {} },
- { "NTSC Color Carrier (Hz)", 0, 35795, 60000, 5, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_CC_VALUE, 0.001f, "%1.4f", {} },
- { "NTSC Color Notch Filter Width", 0, 100, 600, 5, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_N_VALUE, 0.01f, "%1.4f", {} },
- { "NTSC Y Signal Bandwidth (Hz)", 0, 600, 600, 5, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_Y_VALUE, 0.01f, "%1.4f", {} },
- { "NTSC I Signal Bandwidth (Hz)", 0, 120, 600, 5, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_I_VALUE, 0.01f, "%1.4f", {} },
- { "NTSC Q Signal Bandwidth (Hz)", 0, 60, 600, 5, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_Q_VALUE, 0.01f, "%1.4f", {} },
+ { "NTSC Incoming Phase Pixel Clock Scale",-300,100, 300, 1, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_P_VALUE, 0.01f, "%1.2f", {} },
+ { "NTSC Outgoing Phase Offset (radians)",-314, 0, 314, 1, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_O_VALUE, 0.01f, "%1.2f", {} },
+ { "NTSC Color Carrier (MHz)", 0, 31500,6*8800, 1, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_CC_VALUE, 1/8800.f, "%1.5f", {} },
+ { "NTSC Color Notch Filter Width (MHz)",0, 100, 600, 5, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_N_VALUE, 0.01f, "%1.2f", {} },
+ { "NTSC Y Signal Bandwidth (MHz)", 0, 600, 2100, 5, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_Y_VALUE, 0.01f, "%1.2f", {} },
+ { "NTSC I Signal Bandwidth (MHz)", 0, 120, 2100, 5, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_I_VALUE, 0.01f, "%1.2f", {} },
+ { "NTSC Q Signal Bandwidth (MHz)", 0, 60, 2100, 5, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_Q_VALUE, 0.01f, "%1.2f", {} },
{ "NTSC Scanline Duration (uSec)", 0, 5260, 10000, 1, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_LCD_OR_RASTER, SLIDER_NTSC_SCAN_TIME, 0.01f, "%1.2f", {} },
{ "3D LUT (Screen)", 0, 0, 1, 1, SLIDER_INT_ENUM, SLIDER_SCREEN_TYPE_ANY, SLIDER_LUT_ENABLE, 0, "%s", { "Off", "On" } },
{ nullptr, 0, 0, 0, 0, 0, 0, -1, 0, nullptr, {} }
@@ -2318,13 +2275,9 @@ void shaders::init_slider_list()
m_sliders.clear();
m_core_sliders.clear();
- for (slider* slider : internal_sliders)
- {
- delete slider;
- }
internal_sliders.clear();
- const screen_device *first_screen = screen_device_iterator(machine->root_device()).first();;
+ const screen_device *first_screen = screen_device_enumerator(machine->root_device()).first();
if (first_screen == nullptr)
{
return;
@@ -2354,37 +2307,32 @@ void shaders::init_slider_list()
for (int j = 0; j < count; j++)
{
- slider* slider_arg = new slider(desc, get_slider_option(desc->id, j), &options->params_dirty);
- internal_sliders.push_back(slider_arg);
+ slider &slider_arg = *internal_sliders.emplace_back(std::make_unique<slider>(desc, get_slider_option(desc->id, j), &options->params_dirty));
std::string name = desc->name;
switch (desc->slider_type)
{
case SLIDER_VEC2:
{
- std::string names[2] = { " X", " Y" };
- name = name + names[j];
+ char const *const names[2] = { " X", " Y" };
+ name += names[j];
break;
}
case SLIDER_COLOR:
{
- std::string names[3] = { " Red", " Green", " Blue" };
- name = name + names[j];
+ char const *const names[3] = { " Red", " Green", " Blue" };
+ name += names[j];
break;
}
default:
break;
}
- std::unique_ptr<slider_state> core_slider = slider_alloc(desc->id, name.c_str(), desc->minval, desc->defval, desc->maxval, desc->step, slider_arg);
+ std::unique_ptr<slider_state> core_slider = slider_alloc(std::move(name), desc->minval, desc->defval, desc->maxval, desc->step, &slider_arg);
- ui::menu_item item;
- item.text = core_slider->description;
- item.subtext = "";
- item.flags = 0;
- item.ref = core_slider.get();
- item.type = ui::menu_item_type::SLIDER;
- m_sliders.push_back(item);
- m_core_sliders.push_back(std::move(core_slider));
+ ui::menu_item item(ui::menu_item_type::SLIDER, core_slider.get());
+ item.set_text(core_slider->description);
+ m_sliders.emplace_back(item);
+ m_core_sliders.emplace_back(std::move(core_slider));
}
}
}
@@ -2414,8 +2362,7 @@ void uniform::update()
hlsl_options *options = shadersys->options;
renderer_d3d9 *d3d = shadersys->d3d;
- auto win = d3d->assert_window();
- const screen_device *first_screen = screen_device_iterator(win->machine().root_device()).first();
+ const screen_device *first_screen = screen_device_enumerator(d3d->window().machine().root_device()).first();
bool vector_screen =
first_screen != nullptr &&
@@ -2431,7 +2378,7 @@ void uniform::update()
}
case CU_SCREEN_COUNT:
{
- int screen_count = win->target()->current_view()->screens().count();
+ int screen_count = d3d->window().target()->current_view().visible_screen_count();
m_shader->set_int("ScreenCount", screen_count);
break;
}
@@ -2494,7 +2441,7 @@ void uniform::update()
case CU_SWAP_XY:
{
- m_shader->set_bool("SwapXY", win->swap_xy());
+ m_shader->set_bool("SwapXY", d3d->window().swap_xy());
break;
}
case CU_VECTOR_SCREEN:
@@ -2587,6 +2534,7 @@ void uniform::update()
break;
case CU_CHROMA_CONVERSION_GAIN:
m_shader->set_vector("ConversionGain", 3, &options->chroma_conversion_gain[0]);
+ break;
case CU_CHROMA_Y_GAIN:
m_shader->set_vector("YGain", 3, &options->chroma_y_gain[0]);
break;
@@ -2617,7 +2565,7 @@ void uniform::update()
m_shader->set_float("SmoothBorderAmount", options->smooth_border);
break;
case CU_POST_SHADOW_ALPHA:
- m_shader->set_float("ShadowAlpha", shadersys->shadow_texture == nullptr ? 0.0f : options->shadow_mask_alpha);
+ m_shader->set_float("ShadowAlpha", !shadersys->shadow_texture ? 0.0f : options->shadow_mask_alpha);
break;
case CU_POST_SHADOW_COUNT:
{
@@ -2692,12 +2640,14 @@ void uniform::update()
//============================================================
effect::effect(shaders *shadersys, IDirect3DDevice9 *dev, const char *name, const char *path)
+ : m_effect(nullptr)
+ , m_shaders(shadersys)
+ , m_num_passes(0)
+ , m_valid(false)
+ , m_active(false)
{
LPD3DXBUFFER buffer_errors = nullptr;
- m_shaders = shadersys;
- m_valid = false;
-
char name_cstr[1024];
sprintf(name_cstr, "%s\\%s", path, name);
auto effect_name = osd::text::to_tstring(name_cstr);
@@ -2724,6 +2674,12 @@ effect::effect(shaders *shadersys, IDirect3DDevice9 *dev, const char *name, cons
effect::~effect()
{
m_effect->Release();
+
+ m_vecs.clear();
+ m_floats.clear();
+ m_ints.clear();
+ m_bools.clear();
+ m_textures.clear();
}
void effect::add_uniform(const char *name, uniform::uniform_type type, int id)
@@ -2737,24 +2693,19 @@ void effect::update_uniforms()
(*uniform).update();
}
-void effect::begin(UINT *passes, DWORD flags)
+void effect::begin(DWORD flags)
{
- m_effect->Begin(passes, flags);
+ m_active = true;
+ m_num_passes = 0;
+ m_effect->Begin(&m_num_passes, flags);
+ m_effect->BeginPass(0);
}
void effect::end()
{
- m_effect->End();
-}
-
-void effect::begin_pass(UINT pass)
-{
- m_effect->BeginPass(pass);
-}
-
-void effect::end_pass()
-{
+ m_active = false;
m_effect->EndPass();
+ m_effect->End();
}
void effect::set_technique(const char *name)
@@ -2764,48 +2715,97 @@ void effect::set_technique(const char *name)
void effect::set_vector(D3DXHANDLE param, int count, float *vector)
{
- static D3DXVECTOR4 out_vector;
- if (count > 0)
- {
- out_vector.x = vector[0];
- }
- if (count > 1)
- {
- out_vector.y = vector[1];
- }
- if (count > 2)
+ count = std::min(count, 4);
+
+ auto iter = m_vecs.find(param);
+ if (iter != m_vecs.end())
{
- out_vector.z = vector[2];
+ D3DXVECTOR4 &data = iter->second;
+ if (!memcmp((float *)data, vector, sizeof(float) * count))
+ {
+ return;
+ }
+ memcpy(data, vector, sizeof(float) * count);
+ m_effect->SetVector(param, &iter->second);
}
- if (count > 3)
+ else
{
- out_vector.w = vector[3];
+ D3DXVECTOR4 vec;
+ memcpy((float *)vec, vector, sizeof(float) * count);
+ m_effect->SetVector(param, &vec);
+ m_vecs[param] = vec;
}
- m_effect->SetVector(param, &out_vector);
}
void effect::set_float(D3DXHANDLE param, float value)
{
+ auto iter = m_floats.find(param);
+ if (iter != m_floats.end())
+ {
+ if (iter->second == value)
+ {
+ return;
+ }
+ iter->second = value;
+ }
+ else
+ {
+ m_floats[param] = value;
+ }
m_effect->SetFloat(param, value);
}
void effect::set_int(D3DXHANDLE param, int value)
{
+ auto iter = m_ints.find(param);
+ if (iter != m_ints.end())
+ {
+ if (iter->second == value)
+ {
+ return;
+ }
+ iter->second = value;
+ }
+ else
+ {
+ m_ints[param] = value;
+ }
m_effect->SetInt(param, value);
}
void effect::set_bool(D3DXHANDLE param, bool value)
{
+ auto iter = m_bools.find(param);
+ if (iter != m_bools.end())
+ {
+ if (iter->second == value)
+ {
+ return;
+ }
+ iter->second = value;
+ }
+ else
+ {
+ m_bools[param] = value;
+ }
m_effect->SetBool(param, value);
}
-void effect::set_matrix(D3DXHANDLE param, D3DXMATRIX *matrix)
-{
- m_effect->SetMatrix(param, matrix);
-}
-
void effect::set_texture(D3DXHANDLE param, IDirect3DTexture9 *tex)
{
+ auto iter = m_textures.find(param);
+ if (iter != m_textures.end())
+ {
+ if (iter->second == (void *)tex)
+ {
+ return;
+ }
+ iter->second = (void *)tex;
+ }
+ else
+ {
+ m_textures[param] = (void *)tex;
+ }
m_effect->SetTexture(param, tex);
}
diff --git a/src/osd/modules/render/d3d/d3dhlsl.h b/src/osd/modules/render/d3d/d3dhlsl.h
index 7f7dacc4538..6820f3dd316 100644
--- a/src/osd/modules/render/d3d/d3dhlsl.h
+++ b/src/osd/modules/render/d3d/d3dhlsl.h
@@ -2,18 +2,23 @@
// copyright-holders:Aaron Giles
//============================================================
//
-// drawd3d.c - Win32 Direct3D HLSL-specific header
+// drawd3d.h - Win32 Direct3D HLSL-specific header
//
//============================================================
#ifndef __WIN_D3DHLSL__
#define __WIN_D3DHLSL__
-#include <vector>
#include "../frontend/mame/ui/menuitem.h"
#include "../frontend/mame/ui/slider.h"
#include "modules/lib/osdlib.h"
+#include <wrl/client.h>
+
+#include <map>
+#include <memory>
+#include <vector>
+
//============================================================
// TYPE DEFINITIONS
//============================================================
@@ -133,11 +138,8 @@ public:
effect(shaders *shadersys, IDirect3DDevice9 *dev, const char *name, const char *path);
~effect();
- void begin(UINT *passes, DWORD flags);
- void begin_pass(UINT pass);
-
+ void begin(DWORD flags);
void end();
- void end_pass();
void set_technique(const char *name);
@@ -145,7 +147,6 @@ public:
void set_float(D3DXHANDLE param, float value);
void set_int(D3DXHANDLE param, int value);
void set_bool(D3DXHANDLE param, bool value);
- void set_matrix(D3DXHANDLE param, D3DXMATRIX *matrix);
void set_texture(D3DXHANDLE param, IDirect3DTexture9 *tex);
void add_uniform(const char *name, uniform::uniform_type type, int id);
@@ -154,16 +155,26 @@ public:
D3DXHANDLE get_parameter(D3DXHANDLE param, const char *name);
shaders* get_shaders() { return m_shaders; }
+ uint32_t num_passes() { return m_num_passes; }
bool is_valid() { return m_valid; }
+ bool is_active() { return m_active; }
private:
std::vector<std::unique_ptr<uniform>> m_uniform_list;
ID3DXEffect *m_effect;
shaders *m_shaders;
+ uint32_t m_num_passes;
+
+ std::map<D3DXHANDLE, D3DXVECTOR4> m_vecs;
+ std::map<D3DXHANDLE, float> m_floats;
+ std::map<D3DXHANDLE, int> m_ints;
+ std::map<D3DXHANDLE, bool> m_bools;
+ std::map<D3DXHANDLE, void*> m_textures;
bool m_valid;
+ bool m_active;
};
class d3d_render_target;
@@ -175,92 +186,92 @@ class movie_recorder;
/* in the future this will be moved into an OSD/emu shared buffer */
struct hlsl_options
{
- bool params_init;
- bool params_dirty;
- int shadow_mask_tile_mode;
- float shadow_mask_alpha;
- char shadow_mask_texture[1024];
- int shadow_mask_count_x;
- int shadow_mask_count_y;
- float shadow_mask_u_size;
- float shadow_mask_v_size;
- float shadow_mask_u_offset;
- float shadow_mask_v_offset;
- float distortion;
- float cubic_distortion;
- float distort_corner;
- float round_corner;
- float smooth_border;
- float reflection;
- float vignetting;
- float scanline_alpha;
- float scanline_scale;
- float scanline_height;
- float scanline_variation;
- float scanline_bright_scale;
- float scanline_bright_offset;
- float scanline_jitter;
- float hum_bar_alpha;
- float defocus[2];
- float converge_x[3];
- float converge_y[3];
- float radial_converge_x[3];
- float radial_converge_y[3];
- float red_ratio[3];
- float grn_ratio[3];
- float blu_ratio[3];
- float offset[3];
- float scale[3];
- float power[3];
- float floor[3];
- float phosphor[3];
- float saturation;
- int chroma_mode;
- float chroma_a[2];
- float chroma_b[2];
- float chroma_c[2];
- float chroma_conversion_gain[3];
- float chroma_y_gain[3];
+ bool params_init = false;
+ bool params_dirty = false;
+ int shadow_mask_tile_mode = 0;
+ float shadow_mask_alpha = 0.0;
+ char shadow_mask_texture[1024]{ 0 };
+ int shadow_mask_count_x = 0;
+ int shadow_mask_count_y = 0;
+ float shadow_mask_u_size = 0.0;
+ float shadow_mask_v_size = 0.0;
+ float shadow_mask_u_offset = 0.0;
+ float shadow_mask_v_offset = 0.0;
+ float distortion = 0.0;
+ float cubic_distortion = 0.0;
+ float distort_corner = 0.0;
+ float round_corner = 0.0;
+ float smooth_border = 0.0;
+ float reflection = 0.0;
+ float vignetting = 0.0;
+ float scanline_alpha = 0.0;
+ float scanline_scale = 0.0;
+ float scanline_height = 0.0;
+ float scanline_variation = 0.0;
+ float scanline_bright_scale = 0.0;
+ float scanline_bright_offset = 0.0;
+ float scanline_jitter = 0.0;
+ float hum_bar_alpha = 0.0;
+ float defocus[2]{ 0.0 };
+ float converge_x[3]{ 0.0 };
+ float converge_y[3]{ 0.0 };
+ float radial_converge_x[3]{ 0.0 };
+ float radial_converge_y[3]{ 0.0 };
+ float red_ratio[3]{ 0.0 };
+ float grn_ratio[3]{ 0.0 };
+ float blu_ratio[3]{ 0.0 };
+ float offset[3]{ 0.0 };
+ float scale[3]{ 0.0 };
+ float power[3]{ 0.0 };
+ float floor[3]{ 0.0 };
+ float phosphor[3]{ 0.0 };
+ float saturation = 0.0;
+ int chroma_mode = 0;
+ float chroma_a[2]{ 0.0 };
+ float chroma_b[2]{ 0.0 };
+ float chroma_c[2]{ 0.0 };
+ float chroma_conversion_gain[3]{ 0.0 };
+ float chroma_y_gain[3]{ 0.0 };
// NTSC
- int yiq_enable;
- float yiq_jitter;
- float yiq_cc;
- float yiq_a;
- float yiq_b;
- float yiq_o;
- float yiq_p;
- float yiq_n;
- float yiq_y;
- float yiq_i;
- float yiq_q;
- float yiq_scan_time;
- int yiq_phase_count;
+ int yiq_enable = 0;
+ float yiq_jitter = 0.0;
+ float yiq_cc = 0.0;
+ float yiq_a = 0.0;
+ float yiq_b = 0.0;
+ float yiq_o = 0.0;
+ float yiq_p = 0.0;
+ float yiq_n = 0.0;
+ float yiq_y = 0.0;
+ float yiq_i = 0.0;
+ float yiq_q = 0.0;
+ float yiq_scan_time = 0.0;
+ int yiq_phase_count = 0;
// Vectors
- float vector_beam_smooth;
- float vector_length_scale;
- float vector_length_ratio;
+ float vector_beam_smooth = 0.0;
+ float vector_length_scale = 0.0;
+ float vector_length_ratio = 0.0;
// Bloom
- int bloom_blend_mode;
- float bloom_scale;
- float bloom_overdrive[3];
- float bloom_level0_weight;
- float bloom_level1_weight;
- float bloom_level2_weight;
- float bloom_level3_weight;
- float bloom_level4_weight;
- float bloom_level5_weight;
- float bloom_level6_weight;
- float bloom_level7_weight;
- float bloom_level8_weight;
+ int bloom_blend_mode = 0;
+ float bloom_scale = 0.0;
+ float bloom_overdrive[3]{ 0.0 };
+ float bloom_level0_weight = 0.0;
+ float bloom_level1_weight = 0.0;
+ float bloom_level2_weight = 0.0;
+ float bloom_level3_weight = 0.0;
+ float bloom_level4_weight = 0.0;
+ float bloom_level5_weight = 0.0;
+ float bloom_level6_weight = 0.0;
+ float bloom_level7_weight = 0.0;
+ float bloom_level8_weight = 0.0;
// Final
- char lut_texture[1024];
- int lut_enable;
- char ui_lut_texture[1024];
- int ui_lut_enable;
+ char lut_texture[1024]{ 0 };
+ int lut_enable = 0;
+ char ui_lut_texture[1024]{ 0 };
+ int ui_lut_enable = 0;
};
struct slider_desc
@@ -290,7 +301,7 @@ private:
void * m_value;
};
-class shaders : public slider_changed_notifier
+class shaders
{
friend class effect;
friend class uniform;
@@ -300,11 +311,14 @@ public:
shaders();
~shaders();
- bool init(d3d_base *d3dintf, running_machine *machine, renderer_d3d9 *renderer);
+ bool init(IDirect3D9 *d3dobj, running_machine *machine, renderer_d3d9 *renderer);
- bool enabled() { return post_fx_enable && d3dintf->post_fx_available; }
+ bool enabled() { return post_fx_enable && d3d->post_fx_available(); }
void toggle() { post_fx_enable = initialized && !post_fx_enable; }
+ void begin_frame(render_primitive_list *primlist);
+ void end_frame();
+
void begin_draw();
void end_draw();
@@ -323,6 +337,7 @@ public:
void init_fsfx_quad();
void set_texture(texture_info *info);
+ void set_filter(bool filter_screens);
void remove_render_target(int source_width, int source_height, uint32_t screen_index);
void remove_render_target(d3d_render_target *rt);
@@ -330,15 +345,18 @@ public:
void delete_resources();
// slider-related functions
- virtual int32_t slider_changed(running_machine &machine, void *arg, int /*id*/, std::string *str, int32_t newval) override;
- std::unique_ptr<slider_state> slider_alloc(int id, const char *title, int32_t minval, int32_t defval, int32_t maxval, int32_t incval, void *arg);
+ std::unique_ptr<slider_state> slider_alloc(std::string &&title, int32_t minval, int32_t defval, int32_t maxval, int32_t incval, slider *arg);
void init_slider_list();
std::vector<ui::menu_item> get_slider_list() { return m_sliders; }
void *get_slider_option(int id, int index = 0);
private:
+ using IDirect3D9Ptr = Microsoft::WRL::ComPtr<IDirect3D9>;
+ using IDirect3DTexture9Ptr = Microsoft::WRL::ComPtr<IDirect3DTexture9>;
+ using IDirect3DSurface9Ptr = Microsoft::WRL::ComPtr<IDirect3DSurface9>;
+
+ void set_curr_effect(effect *curr_effect);
void blit(IDirect3DSurface9 *dst, bool clear_dst, D3DPRIMITIVETYPE prim_type, uint32_t prim_index, uint32_t prim_count);
- void enumerate_screens();
void render_snapshot(IDirect3DSurface9 *surface);
// Time since last call, only updates once per render of all screens
@@ -365,7 +383,7 @@ private:
int screen_pass(d3d_render_target *rt, int source_index, poly_info *poly, int vertnum);
void ui_pass(poly_info *poly, int vertnum);
- d3d_base * d3dintf; // D3D interface
+ IDirect3D9Ptr d3dobj; // D3D interface
running_machine * machine;
renderer_d3d9 * d3d; // D3D renderer
@@ -373,7 +391,10 @@ private:
bool post_fx_enable; // overall enable flag
bool oversampling_enable; // oversampling enable flag
int num_screens; // number of emulated physical screens
- int curr_screen; // current screen for render target operations
+ int num_targets; // number of emulated screen targets (can be different from above; cf. artwork and Laserdisc games)
+ int curr_target; // current target index for render target operations
+ int targets_per_screen[256]; // screen target count per screen device/container index; estimated maximum count for array size
+ int target_to_screen[256]; // lookup from target index to screen device/container index; estimated maximum count for array size
double acc_t; // accumulated machine time
double delta_t; // data for delta_time
bitmap_argb32 shadow_bitmap; // shadow mask bitmap for post-processing shader
@@ -384,53 +405,59 @@ private:
texture_info * ui_lut_texture;
hlsl_options * options; // current options
- IDirect3DSurface9 * black_surface; // black dummy surface
- IDirect3DTexture9 * black_texture; // black dummy texture
+ IDirect3DSurface9Ptr black_surface; // black dummy surface
+ IDirect3DTexture9Ptr black_texture; // black dummy texture
bool recording_movie; // ongoing movie recording
std::unique_ptr<movie_recorder> recorder; // HLSL post-render movie recorder
bool render_snap; // whether or not to take HLSL post-render snapshot
- IDirect3DSurface9 * snap_copy_target; // snapshot destination surface in system memory
- IDirect3DTexture9 * snap_copy_texture; // snapshot destination surface in system memory
- IDirect3DSurface9 * snap_target; // snapshot upscaled surface
- IDirect3DTexture9 * snap_texture; // snapshot upscaled texture
+ IDirect3DSurface9Ptr snap_copy_target; // snapshot destination surface in system memory
+ IDirect3DTexture9Ptr snap_copy_texture; // snapshot destination surface in system memory
+ IDirect3DSurface9Ptr snap_target; // snapshot upscaled surface
+ IDirect3DTexture9Ptr snap_texture; // snapshot upscaled texture
int snap_width; // snapshot width
int snap_height; // snapshot height
bool initialized; // whether or not we're initialized
// HLSL effects
- IDirect3DSurface9 * backbuffer; // pointer to our device's backbuffer
+ IDirect3DSurface9Ptr backbuffer; // pointer to our device's backbuffer
effect * curr_effect; // pointer to the currently active effect object
- effect * default_effect; // pointer to the primary-effect object
- effect * prescale_effect; // pointer to the prescale-effect object
- effect * post_effect; // pointer to the post-effect object
- effect * distortion_effect; // pointer to the distortion-effect object
- effect * scanline_effect;
- effect * focus_effect; // pointer to the focus-effect object
- effect * phosphor_effect; // pointer to the phosphor-effect object
- effect * deconverge_effect; // pointer to the deconvergence-effect object
- effect * color_effect; // pointer to the color-effect object
- effect * ntsc_effect; // pointer to the NTSC effect object
- effect * bloom_effect; // pointer to the bloom composite effect
- effect * downsample_effect; // pointer to the bloom downsample effect
- effect * vector_effect; // pointer to the vector-effect object
- effect * chroma_effect;
-
+ std::unique_ptr<effect> default_effect; // pointer to the primary-effect object
+ std::unique_ptr<effect> ui_effect; // pointer to the UI-element effect object
+ std::unique_ptr<effect> ui_wrap_effect; // pointer to the UI-element effect object with texture wrapping
+ std::unique_ptr<effect> vector_buffer_effect; // pointer to the vector-buffering effect object
+ std::unique_ptr<effect> prescale_effect; // pointer to the prescale-effect object
+ std::unique_ptr<effect> prescale_point_effect; // pointer to the prescale-effect object with point filtering
+ std::unique_ptr<effect> post_effect; // pointer to the post-effect object
+ std::unique_ptr<effect> distortion_effect; // pointer to the distortion-effect object
+ std::unique_ptr<effect> scanline_effect;
+ std::unique_ptr<effect> focus_effect; // pointer to the focus-effect object
+ std::unique_ptr<effect> phosphor_effect; // pointer to the phosphor-effect object
+ std::unique_ptr<effect> deconverge_effect; // pointer to the deconvergence-effect object
+ std::unique_ptr<effect> color_effect; // pointer to the color-effect object
+ std::unique_ptr<effect> ntsc_effect; // pointer to the NTSC effect object
+ std::unique_ptr<effect> bloom_effect; // pointer to the bloom composite effect
+ std::unique_ptr<effect> downsample_effect; // pointer to the bloom downsample effect
+ std::unique_ptr<effect> vector_effect; // pointer to the vector-effect object
+ std::unique_ptr<effect> chroma_effect;
+
+ texture_info * diffuse_texture;
+ bool filter_screens;
texture_info * curr_texture;
d3d_render_target * curr_render_target;
poly_info * curr_poly;
std::vector<std::unique_ptr<d3d_render_target>> m_render_target_list;
- std::vector<slider*> internal_sliders;
+ std::vector<std::unique_ptr<slider> > internal_sliders;
std::vector<ui::menu_item> m_sliders;
- std::vector<std::unique_ptr<slider_state>> m_core_sliders;
+ std::vector<std::unique_ptr<slider_state> > m_core_sliders;
static slider_desc s_sliders[];
static hlsl_options last_options; // last used options
- static char last_system_name[16]; // last used system
+ static char last_system_name[MAX_DRIVER_NAME_CHARS + 1]; // last used system
osd::dynamic_module::ptr d3dx9_dll;
d3dx_create_effect_from_file_fn d3dx_create_effect_from_file_ptr;
diff --git a/src/osd/modules/render/draw13.cpp b/src/osd/modules/render/draw13.cpp
index f99ebf70601..a36ee8a8f52 100644
--- a/src/osd/modules/render/draw13.cpp
+++ b/src/osd/modules/render/draw13.cpp
@@ -2,7 +2,7 @@
// copyright-holders: Couriersud, Olivier Galibert, R. Belmont
//============================================================
//
-// draw13.c - SDL 2.0 drawing implementation
+// draw13.cpp - SDL 2.0 drawing implementation
//
// SDLMAME by Olivier Galibert and R. Belmont
//
@@ -10,24 +10,202 @@
//
//============================================================
-// standard C headers
-#include <math.h>
-#include <stdio.h>
+#include "render_module.h"
-// MAME headers
-#include "emu.h"
-#include "options.h"
+#include "modules/osdmodule.h"
+
+#if defined(OSD_SDL)
// OSD headers
-#include "osdsdl.h"
+#include "sdlopts.h"
#include "window.h"
-#include "draw13.h"
+// lib/util
+#include "options.h"
+
+// emu
+#include "emucore.h"
+#include "render.h"
+
+// standard SDL headers
+#include <SDL2/SDL.h>
+
+// standard C headers
+#include <algorithm>
+#include <cmath>
+#include <cstdio>
+#include <iterator>
+#include <list>
+
+
+namespace osd {
+
+namespace {
+
+struct quad_setup_data
+{
+ quad_setup_data() = default;
+
+ void compute(const render_primitive &prim, const int prescale);
+
+ int32_t dudx = 0, dvdx = 0, dudy = 0, dvdy = 0;
+ int32_t startu = 0, startv = 0;
+ int32_t rotwidth = 0, rotheight = 0;
+};
//============================================================
-// DEBUGGING
+// Textures
//============================================================
+class renderer_sdl2;
+struct copy_info_t;
+
+/* texture_info holds information about a texture */
+class texture_info
+{
+public:
+ texture_info(renderer_sdl2 *renderer, const render_texinfo &texsource, const quad_setup_data &setup, const uint32_t flags);
+ ~texture_info();
+
+ void set_data(const render_texinfo &texsource, const uint32_t flags);
+ void render_quad(const render_primitive &prim, const int x, const int y);
+ bool matches(const render_primitive &prim, const quad_setup_data &setup);
+
+ copy_info_t const *compute_size_type();
+
+ void *m_pixels; // pixels for the texture
+ int m_pitch;
+
+ copy_info_t const *m_copyinfo;
+ quad_setup_data m_setup;
+
+ osd_ticks_t m_last_access;
+
+ int raw_width() const { return m_texinfo.width; }
+ int raw_height() const { return m_texinfo.height; }
+
+ const render_texinfo &texinfo() const { return m_texinfo; }
+ render_texinfo &texinfo() { return m_texinfo; }
+
+ HashT hash() const { return m_hash; }
+ uint32_t flags() const { return m_flags; }
+
+private:
+ bool is_pixels_owned() const;
+
+ void set_coloralphamode(SDL_Texture *texture_id, const render_color *color);
+
+ Uint32 m_sdl_access;
+ renderer_sdl2 * m_renderer;
+ render_texinfo m_texinfo; // copy of the texture info
+ HashT m_hash; // hash value for the texture (must be >= pointer size)
+ uint32_t m_flags; // rendering flags
+
+ SDL_Texture * m_texture_id;
+ bool m_is_rotated;
+
+ int m_format; // texture format
+ SDL_BlendMode m_sdl_blendmode;
+};
+
+// inline functions and macros
+#include "blit13.ipp"
+
+//============================================================
+// TEXCOPY FUNCS
+//============================================================
+
+enum SDL_TEXFORMAT_E
+{
+ SDL_TEXFORMAT_ARGB32 = 0,
+ SDL_TEXFORMAT_RGB32,
+ SDL_TEXFORMAT_RGB32_PALETTED,
+ SDL_TEXFORMAT_YUY16,
+ SDL_TEXFORMAT_YUY16_PALETTED,
+ SDL_TEXFORMAT_PALETTE16,
+ SDL_TEXFORMAT_RGB15,
+ SDL_TEXFORMAT_RGB15_PALETTED,
+ SDL_TEXFORMAT_PALETTE16A,
+ SDL_TEXFORMAT_PALETTE16_ARGB1555,
+ SDL_TEXFORMAT_RGB15_ARGB1555,
+ SDL_TEXFORMAT_RGB15_PALETTED_ARGB1555,
+ SDL_TEXFORMAT_LAST = SDL_TEXFORMAT_RGB15_PALETTED_ARGB1555
+};
+
+struct copy_info_t
+{
+ int src_fmt;
+ Uint32 dst_fmt;
+ const blit_base *blitter;
+ Uint32 bm_mask;
+ const char *srcname;
+ const char *dstname;
+ /* Statistics */
+ mutable uint64_t pixel_count;
+ mutable int64_t time;
+ mutable int samples;
+ mutable int perf;
+ /* list */
+ copy_info_t const *next;
+};
+
+/* renderer_sdl2 is the information about SDL for the current screen */
+class renderer_sdl2 : public osd_renderer
+{
+public:
+ renderer_sdl2(
+ osd_window &window,
+ copy_info_t const *const (&blit_info)[SDL_TEXFORMAT_LAST + 1]);
+
+ virtual ~renderer_sdl2()
+ {
+ destroy_all_textures();
+ SDL_DestroyRenderer(m_sdl_renderer);
+ m_sdl_renderer = nullptr;
+ }
+
+ virtual int create() override;
+ virtual int draw(const int update) override;
+ virtual int xy_to_render_target(const int x, const int y, int *xt, int *yt) override;
+ virtual render_primitive_list *get_primitives() override;
+
+ int RendererSupportsFormat(Uint32 format, Uint32 access, const char *sformat);
+
+ SDL_Renderer *m_sdl_renderer;
+ copy_info_t const *const (&m_blit_info)[SDL_TEXFORMAT_LAST + 1];
+
+private:
+ void render_quad(texture_info *texture, const render_primitive &prim, const int x, const int y);
+
+ texture_info *texture_find(const render_primitive &prim, const quad_setup_data &setup);
+ texture_info *texture_update(const render_primitive &prim);
+
+ void destroy_all_textures();
+
+ int32_t m_blittimer;
+
+ std::list<texture_info> m_texlist; // list of active textures
+
+ float m_last_hofs;
+ float m_last_vofs;
+
+ int m_width;
+ int m_height;
+
+ osd_dim m_blit_dim;
+
+ struct
+ {
+ Uint32 format;
+ int status;
+ } fmt_support[30];
+
+ // Stats
+ int64_t m_last_blit_time;
+ int64_t m_last_blit_pixels;
+};
+
+
//============================================================
// CONSTANTS
//============================================================
@@ -60,9 +238,12 @@ static inline bool is_transparent(const float &a)
// CONSTRUCTOR & DESTRUCTOR
//============================================================
-renderer_sdl2::renderer_sdl2(std::shared_ptr<osd_window> window, int extra_flags)
- : osd_renderer(window, FLAG_NEEDS_OPENGL | extra_flags)
+renderer_sdl2::renderer_sdl2(
+ osd_window &window,
+ copy_info_t const *const (&blit_info)[SDL_TEXFORMAT_LAST + 1])
+ : osd_renderer(window)
, m_sdl_renderer(nullptr)
+ , m_blit_info(blit_info)
, m_blittimer(0)
, m_last_hofs(0)
, m_last_vofs(0)
@@ -77,112 +258,8 @@ renderer_sdl2::renderer_sdl2(std::shared_ptr<osd_window> window, int extra_flags
fmt_support[i].format = 0;
fmt_support[i].status = 0;
}
-
- if (!s_blit_info_initialized)
- {
- /* On OSX, calling this from drawsdl2_init will
- * prohibit fullscreen toggling. It is than not possible
- * to toggle from fullscreen to window mode.
- */
- expand_copy_info(s_blit_info_default);
- s_blit_info_initialized = true;
- }
}
-
-//============================================================
-// STATIC VARIABLES
-//============================================================
-
-#define BM_ALL (UINT32_MAX)
-//( SDL_BLENDMODE_MASK | SDL_BLENDMODE_BLEND | SDL_BLENDMODE_ADD | SDL_BLENDMODE_MOD)
-
-#define ENTRY(a,b,f) { SDL_TEXFORMAT_ ## a, SDL_PIXELFORMAT_ ## b, &texcopy_ ## f, BM_ALL, #a, #b, 0, 0, 0, 0}
-#define ENTRY_BM(a,b,f,bm) { SDL_TEXFORMAT_ ## a, SDL_PIXELFORMAT_ ## b, &texcopy_ ## f, bm, #a, #b, 0, 0, 0, 0}
-#define ENTRY_LR(a,b,f) { SDL_TEXFORMAT_ ## a, SDL_PIXELFORMAT_ ## b, &texcopy_ ## f, BM_ALL, #a, #b, 0, 0, 0, -1}
-
-const copy_info_t renderer_sdl2::s_blit_info_default[] =
-{
- /* no rotation */
- ENTRY(ARGB32, ARGB8888, argb32_argb32),
- ENTRY_LR(ARGB32, RGB888, argb32_rgb32),
- /* Entry primarily for directfb */
- ENTRY_BM(ARGB32, RGB888, argb32_rgb32, SDL_BLENDMODE_ADD),
- ENTRY_BM(ARGB32, RGB888, argb32_rgb32, SDL_BLENDMODE_MOD),
- ENTRY_BM(ARGB32, RGB888, argb32_rgb32, SDL_BLENDMODE_NONE),
-
- ENTRY(RGB32, ARGB8888, rgb32_argb32),
- ENTRY(RGB32, RGB888, rgb32_rgb32),
-
- ENTRY(RGB32_PALETTED, ARGB8888, rgb32pal_argb32),
- ENTRY(RGB32_PALETTED, RGB888, rgb32pal_argb32),
-
- ENTRY(YUY16, UYVY, yuv16_uyvy),
- ENTRY(YUY16, YUY2, yuv16_yuy2),
- ENTRY(YUY16, YVYU, yuv16_yvyu),
- ENTRY(YUY16, ARGB8888, yuv16_argb32),
- ENTRY(YUY16, RGB888, yuv16_argb32),
-
- ENTRY(YUY16_PALETTED, UYVY, yuv16pal_uyvy),
- ENTRY(YUY16_PALETTED, YUY2, yuv16pal_yuy2),
- ENTRY(YUY16_PALETTED, YVYU, yuv16pal_yvyu),
- ENTRY(YUY16_PALETTED, ARGB8888, yuv16pal_argb32),
- ENTRY(YUY16_PALETTED, RGB888, yuv16pal_argb32),
-
- ENTRY(PALETTE16, ARGB8888, pal16_argb32),
- ENTRY(PALETTE16, RGB888, pal16_argb32),
-
- ENTRY(RGB15, RGB555, rgb15_rgb555),
- ENTRY(RGB15, ARGB1555, rgb15_argb1555),
- ENTRY(RGB15, ARGB8888, rgb15_argb32),
- ENTRY(RGB15, RGB888, rgb15_argb32),
-
- ENTRY(RGB15_PALETTED, ARGB8888, rgb15pal_argb32),
- ENTRY(RGB15_PALETTED, RGB888, rgb15pal_argb32),
-
- ENTRY(PALETTE16A, ARGB8888, pal16a_argb32),
- ENTRY(PALETTE16A, RGB888, pal16a_rgb32),
-
- /* rotation */
- ENTRY(ARGB32, ARGB8888, rot_argb32_argb32),
- ENTRY_LR(ARGB32, RGB888, rot_argb32_rgb32),
- /* Entry primarily for directfb */
- ENTRY_BM(ARGB32, RGB888, rot_argb32_rgb32, SDL_BLENDMODE_ADD),
- ENTRY_BM(ARGB32, RGB888, rot_argb32_rgb32, SDL_BLENDMODE_MOD),
- ENTRY_BM(ARGB32, RGB888, rot_argb32_rgb32, SDL_BLENDMODE_NONE),
-
- ENTRY(RGB32, ARGB8888, rot_rgb32_argb32),
- ENTRY(RGB32, RGB888, rot_argb32_argb32),
-
- ENTRY(RGB32_PALETTED, ARGB8888, rot_rgb32pal_argb32),
- ENTRY(RGB32_PALETTED, RGB888, rot_rgb32pal_argb32),
-
- ENTRY(YUY16, ARGB8888, rot_yuv16_argb32rot),
- ENTRY(YUY16, RGB888, rot_yuv16_argb32rot),
-
- ENTRY(YUY16_PALETTED, ARGB8888, rot_yuv16pal_argb32rot),
- ENTRY(YUY16_PALETTED, RGB888, rot_yuv16pal_argb32rot),
-
- ENTRY(PALETTE16, ARGB8888, rot_pal16_argb32),
- ENTRY(PALETTE16, RGB888, rot_pal16_argb32),
-
- ENTRY(RGB15, RGB555, rot_rgb15_argb1555),
- ENTRY(RGB15, ARGB1555, rot_rgb15_argb1555),
- ENTRY(RGB15, ARGB8888, rot_rgb15_argb32),
- ENTRY(RGB15, RGB888, rot_rgb15_argb32),
-
- ENTRY(RGB15_PALETTED, ARGB8888, rot_rgb15pal_argb32),
- ENTRY(RGB15_PALETTED, RGB888, rot_rgb15pal_argb32),
-
- ENTRY(PALETTE16A, ARGB8888, rot_pal16a_argb32),
- ENTRY(PALETTE16A, RGB888, rot_pal16a_rgb32),
-
-{ -1 },
-};
-
-copy_info_t* renderer_sdl2::s_blit_info[SDL_TEXFORMAT_LAST+1] = { nullptr };
-bool renderer_sdl2::s_blit_info_initialized = false;
-
//============================================================
// INLINES
//============================================================
@@ -277,7 +354,7 @@ void renderer_sdl2::render_quad(texture_info *texture, const render_primitive &p
if (texture)
{
- copy_info_t *copyinfo = texture->m_copyinfo;
+ copy_info_t const *copyinfo = texture->m_copyinfo;
copyinfo->time -= osd_ticks();
texture->render_quad(prim, x, y);
copyinfo->time += osd_ticks();
@@ -288,7 +365,7 @@ void renderer_sdl2::render_quad(texture_info *texture, const render_primitive &p
copyinfo->time += (m_last_blit_time * (int64_t) (texture->raw_width() * texture->raw_height())) / (int64_t) m_last_blit_pixels;
}
copyinfo->samples++;
- copyinfo->perf = ( texture->m_copyinfo->pixel_count * (osd_ticks_per_second()/1000)) / texture->m_copyinfo->time;
+ copyinfo->perf = (texture->m_copyinfo->pixel_count * (osd_ticks_per_second()/1000)) / std::max<int64_t>(texture->m_copyinfo->time, 1);
}
else
{
@@ -329,59 +406,6 @@ int renderer_sdl2::RendererSupportsFormat(Uint32 format, Uint32 access, const ch
return 0;
}
-//============================================================
-// drawsdl_init
-//============================================================
-
-void renderer_sdl2::add_list(copy_info_t **head, const copy_info_t *element, Uint32 bm)
-{
- copy_info_t *newci = global_alloc(copy_info_t);
- *newci = *element;
-
- newci->bm_mask = bm;
- newci->next = *head;
- *head = newci;
-}
-
-void renderer_sdl2::expand_copy_info(const copy_info_t *list)
-{
- for (const copy_info_t *bi = list; bi->src_fmt != -1; bi++)
- {
- if (bi->bm_mask == BM_ALL)
- {
- add_list(&s_blit_info[bi->src_fmt], bi, SDL_BLENDMODE_NONE);
- add_list(&s_blit_info[bi->src_fmt], bi, SDL_BLENDMODE_ADD);
- add_list(&s_blit_info[bi->src_fmt], bi, SDL_BLENDMODE_MOD);
- add_list(&s_blit_info[bi->src_fmt], bi, SDL_BLENDMODE_BLEND);
- }
- else
- {
- add_list(&s_blit_info[bi->src_fmt], bi, bi->bm_mask);
- }
- }
-}
-
-// FIXME: machine only used to access options.
-void renderer_sdl2::init(running_machine &machine)
-{
- osd_printf_verbose("Using SDL native texturing driver (SDL 2.0+)\n");
-
-#if USE_OPENGL
- // Load the GL library now - else MT will fail
- const char *stemp = downcast<sdl_options &>(machine.options()).gl_lib();
-#else
- const char *stemp = nullptr;
-#endif
- if (stemp != nullptr && strcmp(stemp, OSDOPTVAL_AUTO) == 0)
- stemp = nullptr;
-
- // No fatalerror here since not all video drivers support GL !
- if (SDL_GL_LoadLibrary(stemp) != 0) // Load library (default for e==nullptr
- osd_printf_warning("Warning: Unable to load opengl library: %s\n", stemp ? stemp : "<default>");
- else
- osd_printf_verbose("Loaded opengl shared library: %s\n", stemp ? stemp : "<default>");
-}
-
//============================================================
// sdl_info::create
@@ -434,12 +458,10 @@ int renderer_sdl2::create()
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
}
- auto win = assert_window();
-
if (video_config.waitvsync)
- m_sdl_renderer = SDL_CreateRenderer(std::dynamic_pointer_cast<sdl_window_info>(win)->platform_window(), -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
+ m_sdl_renderer = SDL_CreateRenderer(dynamic_cast<sdl_window_info &>(window()).platform_window(), -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
else
- m_sdl_renderer = SDL_CreateRenderer(std::dynamic_pointer_cast<sdl_window_info>(win)->platform_window(), -1, SDL_RENDERER_ACCELERATED);
+ m_sdl_renderer = SDL_CreateRenderer(dynamic_cast<sdl_window_info &>(window()).platform_window(), -1, SDL_RENDERER_ACCELERATED);
if (!m_sdl_renderer)
{
@@ -483,18 +505,14 @@ int renderer_sdl2::xy_to_render_target(int x, int y, int *xt, int *yt)
void renderer_sdl2::destroy_all_textures()
{
- auto win = assert_window();
- if (win == nullptr)
- return;
-
- if(win->m_primlist)
+ if (window().m_primlist)
{
- win->m_primlist->acquire_lock();
- m_texlist.reset();
- win->m_primlist->release_lock();
+ window().m_primlist->acquire_lock();
+ m_texlist.clear();
+ window().m_primlist->release_lock();
}
else
- m_texlist.reset();
+ m_texlist.clear();
}
//============================================================
@@ -507,13 +525,7 @@ int renderer_sdl2::draw(int update)
float vofs, hofs;
int blit_pixels = 0;
- if (video_config.novideo)
- {
- return 0;
- }
-
- auto win = assert_window();
- osd_dim wdim = win->get_size();
+ osd_dim wdim = window().get_size();
if (has_flags(FI_CHANGED) || (wdim.width() != m_width) || (wdim.height() != m_height))
{
@@ -560,10 +572,10 @@ int renderer_sdl2::draw(int update)
m_last_hofs = hofs;
m_last_vofs = vofs;
- win->m_primlist->acquire_lock();
+ window().m_primlist->acquire_lock();
// now draw
- for (render_primitive &prim : *win->m_primlist)
+ for (render_primitive &prim : *window().m_primlist)
{
Uint8 sr, sg, sb, sa;
@@ -593,7 +605,7 @@ int renderer_sdl2::draw(int update)
}
}
- win->m_primlist->release_lock();
+ window().m_primlist->release_lock();
m_last_blit_pixels = blit_pixels;
m_last_blit_time = -osd_ticks();
@@ -612,22 +624,23 @@ int renderer_sdl2::draw(int update)
// texture_compute_size and type
//============================================================
-copy_info_t *texture_info::compute_size_type()
+copy_info_t const *texture_info::compute_size_type()
{
- copy_info_t *result = nullptr;
+ copy_info_t const *result = nullptr;
int maxperf = 0;
- for (copy_info_t *bi = renderer_sdl2::s_blit_info[m_format]; bi != nullptr; bi = bi->next)
+ for (copy_info_t const *bi = m_renderer->m_blit_info[m_format]; bi != nullptr; bi = bi->next)
{
- if ((m_is_rotated == bi->blitter->m_is_rot)
- && (m_sdl_blendmode == bi->bm_mask))
+ if ((m_is_rotated == bi->blitter->m_is_rot) && (m_sdl_blendmode == bi->bm_mask))
{
if (m_renderer->RendererSupportsFormat(bi->dst_fmt, m_sdl_access, bi->dstname))
{
- int perf = bi->perf;
+ int const perf = bi->perf;
if (perf == 0)
+ {
return bi;
- else if (perf > (maxperf * 102) / 100)
+ }
+ else if (perf > ((maxperf * 102) / 100))
{
result = bi;
maxperf = perf;
@@ -639,23 +652,21 @@ copy_info_t *texture_info::compute_size_type()
if (result)
return result;
- /* try last resort handlers */
- for (copy_info_t *bi = renderer_sdl2::s_blit_info[m_format]; bi != nullptr; bi = bi->next)
+ // try last resort handlers
+ for (copy_info_t const *bi = m_renderer->m_blit_info[m_format]; bi != nullptr; bi = bi->next)
{
- if ((m_is_rotated == bi->blitter->m_is_rot)
- && (m_sdl_blendmode == bi->bm_mask))
+ if ((m_is_rotated == bi->blitter->m_is_rot) && (m_sdl_blendmode == bi->bm_mask))
if (m_renderer->RendererSupportsFormat(bi->dst_fmt, m_sdl_access, bi->dstname))
return bi;
}
- //FIXME: crash implement a -do nothing handler */
+ //FIXME: crash implement a -do nothing handler
return nullptr;
}
-// FIXME:
bool texture_info::is_pixels_owned() const
-{ // do we own / allocated it ?
- return ((m_sdl_access == SDL_TEXTUREACCESS_STATIC)
- && (m_copyinfo->blitter->m_is_passthrough));
+{
+ // do we own / allocated it ?
+ return (m_sdl_access == SDL_TEXTUREACCESS_STATIC) && !m_copyinfo->blitter->m_is_passthrough;
}
//============================================================
@@ -745,12 +756,11 @@ texture_info::texture_info(renderer_sdl2 *renderer, const render_texinfo &texsou
m_pixels = malloc(m_setup.rotwidth * m_setup.rotheight * m_copyinfo->blitter->m_dest_bpp);
}
m_last_access = osd_ticks();
-
}
texture_info::~texture_info()
{
- if ( is_pixels_owned() && (m_pixels != nullptr) )
+ if (is_pixels_owned() && m_pixels)
free(m_pixels);
SDL_DestroyTexture(m_texture_id);
}
@@ -764,7 +774,7 @@ void texture_info::set_data(const render_texinfo &texsource, const uint32_t flag
m_copyinfo->time -= osd_ticks();
if (m_sdl_access == SDL_TEXTUREACCESS_STATIC)
{
- if ( m_copyinfo->blitter->m_is_passthrough )
+ if (m_copyinfo->blitter->m_is_passthrough)
{
m_pixels = texsource.base;
m_pitch = m_texinfo.rowpixels * m_copyinfo->blitter->m_dest_bpp;
@@ -778,11 +788,11 @@ void texture_info::set_data(const render_texinfo &texsource, const uint32_t flag
}
else
{
- SDL_LockTexture(m_texture_id, nullptr, (void **) &m_pixels, &m_pitch);
+ SDL_LockTexture(m_texture_id, nullptr, (void **)&m_pixels, &m_pitch);
if ( m_copyinfo->blitter->m_is_passthrough )
{
- uint8_t *src = (uint8_t *) texsource.base;
- uint8_t *dst = (uint8_t *) m_pixels;
+ const uint8_t *src = (uint8_t *)texsource.base;
+ uint8_t *dst = (uint8_t *)m_pixels;
int spitch = texsource.rowpixels * m_copyinfo->blitter->m_dest_bpp;
int num = texsource.width * m_copyinfo->blitter->m_dest_bpp;
int h = texsource.height;
@@ -868,64 +878,38 @@ void quad_setup_data::compute(const render_primitive &prim, const int prescale)
texture_info *renderer_sdl2::texture_find(const render_primitive &prim, const quad_setup_data &setup)
{
- HashT texhash = texture_compute_hash(prim.texture, prim.flags);
- texture_info *texture;
- osd_ticks_t now = osd_ticks();
+ const HashT texhash = texture_compute_hash(prim.texture, prim.flags);
+ const osd_ticks_t now = osd_ticks();
// find a match
- for (texture = m_texlist.first(); texture != nullptr; )
- if (texture->hash() == texhash &&
- texture->matches(prim, setup))
+ for (auto texture = m_texlist.begin(); texture != m_texlist.end(); )
+ {
+ if ((texture->hash() == texhash) && texture->matches(prim, setup))
{
- /* would we choose another blitter based on performance ? */
+ // would we choose another blitter based on performance?
if ((texture->m_copyinfo->samples & 0x7f) == 0x7f)
{
if (texture->m_copyinfo != texture->compute_size_type())
return nullptr;
}
texture->m_last_access = now;
- return texture;
+ return &*texture;
}
else
{
- /* free resources not needed any longer? */
- texture_info *expire = texture;
- texture = texture->next();
- if (now - expire->m_last_access > osd_ticks_per_second())
- m_texlist.remove(*expire);
+ // free resources not needed any longer?
+ if ((now - texture->m_last_access) > osd_ticks_per_second())
+ texture = m_texlist.erase(texture);
+ else
+ ++texture;
}
+ }
// nothing found
return nullptr;
}
//============================================================
-// exit
-//============================================================
-
-void renderer_sdl2::exit()
-{
- if (s_blit_info_initialized)
- {
- for (int i = 0; i <= SDL_TEXFORMAT_LAST; i++)
- {
- for (copy_info_t *bi = s_blit_info[i]; bi != nullptr; )
- {
- if (bi->pixel_count)
- osd_printf_verbose("%s -> %s %s blendmode 0x%02x, %d samples: %d KPixel/sec\n", bi->srcname, bi->dstname,
- bi->blitter->m_is_rot ? "rot" : "norot", bi->bm_mask, bi->samples,
- (int) bi->perf);
- copy_info_t *freeme = bi;
- bi = bi->next;
- global_free(freeme);
- }
- s_blit_info[i] = nullptr;
- }
- s_blit_info_initialized = false;
- }
-}
-
-//============================================================
// texture_update
//============================================================
@@ -934,22 +918,20 @@ texture_info * renderer_sdl2::texture_update(const render_primitive &prim)
quad_setup_data setup;
texture_info *texture;
- auto win = assert_window();
- setup.compute(prim, win->prescale());
+ setup.compute(prim, window().prescale());
texture = texture_find(prim, setup);
// if we didn't find one, create a new texture
- if (texture == nullptr && prim.texture.base != nullptr)
+ if (!texture && prim.texture.base)
{
- texture = global_alloc(texture_info(this, prim.texture, setup, prim.flags));
- /* add us to the texture list */
- m_texlist.prepend(*texture);
+ // add us to the texture list
+ texture = &m_texlist.emplace_front(this, prim.texture, setup, prim.flags);
}
- if (texture != nullptr)
+ if (texture)
{
- if (prim.texture.base != nullptr && texture->texinfo().seqid != prim.texture.seqid)
+ if (prim.texture.base && (texture->texinfo().seqid != prim.texture.seqid))
{
texture->texinfo().seqid = prim.texture.seqid;
// if we found it, but with a different seqid, copy the data
@@ -962,16 +944,249 @@ texture_info * renderer_sdl2::texture_update(const render_primitive &prim)
render_primitive_list *renderer_sdl2::get_primitives()
{
- auto win = assert_window();
- if (win == nullptr)
- return nullptr;
-
- osd_dim nd = win->get_size();
+ osd_dim nd = window().get_size();
if (nd != m_blit_dim)
{
m_blit_dim = nd;
notify_changed();
}
- win->target()->set_bounds(m_blit_dim.width(), m_blit_dim.height(), win->pixel_aspect());
- return &win->target()->get_primitives();
+ window().target()->set_bounds(m_blit_dim.width(), m_blit_dim.height(), window().pixel_aspect());
+ return &window().target()->get_primitives();
+}
+
+
+class video_sdl2 : public osd_module, public render_module
+{
+public:
+ video_sdl2()
+ : osd_module(OSD_RENDERER_PROVIDER, "accel")
+ , m_blit_info_initialized(false)
+ , m_gllib_loaded(false)
+ {
+ std::fill(std::begin(m_blit_info), std::end(m_blit_info), nullptr);
+ }
+ ~video_sdl2()
+ {
+ free_copy_info();
+ }
+
+ virtual int init(osd_interface &osd, osd_options const &options) override;
+ virtual void exit() override { free_copy_info(); }
+
+ virtual std::unique_ptr<osd_renderer> create(osd_window &window) override;
+
+protected:
+ virtual unsigned flags() const override { return FLAG_INTERACTIVE | FLAG_SDL_NEEDS_OPENGL; }
+
+private:
+ static inline constexpr Uint32 BM_ALL = UINT32_MAX; // SDL_BLENDMODE_MASK | SDL_BLENDMODE_BLEND | SDL_BLENDMODE_ADD | SDL_BLENDMODE_MOD
+
+ void expand_copy_info();
+ void free_copy_info();
+
+ static void add_list(copy_info_t const *&head, copy_info_t const &element, Uint32 bm);
+
+ copy_info_t const *m_blit_info[SDL_TEXFORMAT_LAST + 1];
+ bool m_blit_info_initialized;
+ bool m_gllib_loaded;
+
+ static copy_info_t const s_blit_info_default[];
+};
+
+int video_sdl2::init(osd_interface &osd, osd_options const &options)
+{
+ osd_printf_verbose("Using SDL native texturing driver (SDL 2.0+)\n");
+
+ // Load the GL library now - else MT will fail
+ char const *libname = nullptr;
+#if USE_OPENGL
+ libname = dynamic_cast<sdl_options const &>(options).gl_lib();
+ if (libname && (!*libname || !std::strcmp(libname, OSDOPTVAL_AUTO)))
+ libname = nullptr;
+#endif
+
+ if (!m_gllib_loaded)
+ {
+ // No fatalerror here since not all video drivers support GL!
+ if (SDL_GL_LoadLibrary(libname) != 0)
+ {
+ osd_printf_error("Unable to load OpenGL shared library: %s\n", libname ? libname : "<default>");
+ m_gllib_loaded = true;
+ }
+ else
+ {
+ osd_printf_verbose("Loaded OpenGL shared library: %s\n", libname ? libname : "<default>");
+ }
+ }
+
+ return 0;
+}
+
+std::unique_ptr<osd_renderer> video_sdl2::create(osd_window &window)
+{
+ if (!m_blit_info_initialized)
+ {
+ // On macOS, calling this from drawsdl2_init will prohibit fullscreen toggling.
+ // It is than not possible to toggle from fullscreen to window mode.
+ expand_copy_info();
+ m_blit_info_initialized = true;
+ }
+
+ return std::make_unique<renderer_sdl2>(window, m_blit_info);
+}
+
+void video_sdl2::expand_copy_info()
+{
+ for (const copy_info_t *bi = s_blit_info_default; bi->src_fmt != -1; bi++)
+ {
+ if (bi->bm_mask == BM_ALL)
+ {
+ add_list(m_blit_info[bi->src_fmt], *bi, SDL_BLENDMODE_NONE);
+ add_list(m_blit_info[bi->src_fmt], *bi, SDL_BLENDMODE_ADD);
+ add_list(m_blit_info[bi->src_fmt], *bi, SDL_BLENDMODE_MOD);
+ add_list(m_blit_info[bi->src_fmt], *bi, SDL_BLENDMODE_BLEND);
+ }
+ else
+ {
+ add_list(m_blit_info[bi->src_fmt], *bi, bi->bm_mask);
+ }
+ }
+}
+
+void video_sdl2::free_copy_info()
+{
+ if (m_blit_info_initialized)
+ {
+ for (int i = 0; i <= SDL_TEXFORMAT_LAST; i++)
+ {
+ for (copy_info_t const *bi = m_blit_info[i]; bi != nullptr; )
+ {
+ if (bi->pixel_count)
+ {
+ osd_printf_verbose(
+ "%s -> %s %s blendmode 0x%02x, %d samples: %d KPixel/sec\n",
+ bi->srcname,
+ bi->dstname,
+ bi->blitter->m_is_rot ? "rot" : "norot",
+ bi->bm_mask,
+ bi->samples,
+ bi->perf);
+ }
+ delete std::exchange(bi, bi->next);
+ }
+ m_blit_info[i] = nullptr;
+ }
+ m_blit_info_initialized = false;
+ }
+}
+
+void video_sdl2::add_list(copy_info_t const *&head, copy_info_t const &element, Uint32 bm)
+{
+ copy_info_t *const newci = new copy_info_t(element);
+
+ newci->bm_mask = bm;
+ newci->next = head;
+ head = newci;
}
+
+
+//============================================================
+// STATIC VARIABLES
+//============================================================
+
+#define ENTRY(a,b,f) { SDL_TEXFORMAT_ ## a, SDL_PIXELFORMAT_ ## b, &texcopy_ ## f, BM_ALL, #a, #b, 0, 0, 0, 0}
+#define ENTRY_BM(a,b,f,bm) { SDL_TEXFORMAT_ ## a, SDL_PIXELFORMAT_ ## b, &texcopy_ ## f, bm, #a, #b, 0, 0, 0, 0}
+#define ENTRY_LR(a,b,f) { SDL_TEXFORMAT_ ## a, SDL_PIXELFORMAT_ ## b, &texcopy_ ## f, BM_ALL, #a, #b, 0, 0, 0, -1}
+
+copy_info_t const video_sdl2::s_blit_info_default[] =
+{
+ /* no rotation */
+ ENTRY(ARGB32, ARGB8888, argb32_argb32),
+ ENTRY_LR(ARGB32, RGB888, argb32_rgb32),
+ /* Entry primarily for directfb */
+ ENTRY_BM(ARGB32, RGB888, argb32_rgb32, SDL_BLENDMODE_ADD),
+ ENTRY_BM(ARGB32, RGB888, argb32_rgb32, SDL_BLENDMODE_MOD),
+ ENTRY_BM(ARGB32, RGB888, argb32_rgb32, SDL_BLENDMODE_NONE),
+
+ ENTRY(RGB32, ARGB8888, rgb32_argb32),
+ ENTRY(RGB32, RGB888, rgb32_rgb32),
+
+ ENTRY(RGB32_PALETTED, ARGB8888, rgb32pal_argb32),
+ ENTRY(RGB32_PALETTED, RGB888, rgb32pal_argb32),
+
+ ENTRY(YUY16, UYVY, yuv16_uyvy),
+ ENTRY(YUY16, YUY2, yuv16_yuy2),
+ ENTRY(YUY16, YVYU, yuv16_yvyu),
+ ENTRY(YUY16, ARGB8888, yuv16_argb32),
+ ENTRY(YUY16, RGB888, yuv16_argb32),
+
+ ENTRY(YUY16_PALETTED, UYVY, yuv16pal_uyvy),
+ ENTRY(YUY16_PALETTED, YUY2, yuv16pal_yuy2),
+ ENTRY(YUY16_PALETTED, YVYU, yuv16pal_yvyu),
+ ENTRY(YUY16_PALETTED, ARGB8888, yuv16pal_argb32),
+ ENTRY(YUY16_PALETTED, RGB888, yuv16pal_argb32),
+
+ ENTRY(PALETTE16, ARGB8888, pal16_argb32),
+ ENTRY(PALETTE16, RGB888, pal16_argb32),
+
+ ENTRY(RGB15, RGB555, rgb15_rgb555),
+ ENTRY(RGB15, ARGB1555, rgb15_argb1555),
+ ENTRY(RGB15, ARGB8888, rgb15_argb32),
+ ENTRY(RGB15, RGB888, rgb15_argb32),
+
+ ENTRY(RGB15_PALETTED, ARGB8888, rgb15pal_argb32),
+ ENTRY(RGB15_PALETTED, RGB888, rgb15pal_argb32),
+
+ ENTRY(PALETTE16A, ARGB8888, pal16a_argb32),
+ ENTRY(PALETTE16A, RGB888, pal16a_rgb32),
+
+ /* rotation */
+ ENTRY(ARGB32, ARGB8888, rot_argb32_argb32),
+ ENTRY_LR(ARGB32, RGB888, rot_argb32_rgb32),
+ /* Entry primarily for directfb */
+ ENTRY_BM(ARGB32, RGB888, rot_argb32_rgb32, SDL_BLENDMODE_ADD),
+ ENTRY_BM(ARGB32, RGB888, rot_argb32_rgb32, SDL_BLENDMODE_MOD),
+ ENTRY_BM(ARGB32, RGB888, rot_argb32_rgb32, SDL_BLENDMODE_NONE),
+
+ ENTRY(RGB32, ARGB8888, rot_rgb32_argb32),
+ ENTRY(RGB32, RGB888, rot_argb32_argb32),
+
+ ENTRY(RGB32_PALETTED, ARGB8888, rot_rgb32pal_argb32),
+ ENTRY(RGB32_PALETTED, RGB888, rot_rgb32pal_argb32),
+
+ ENTRY(YUY16, ARGB8888, rot_yuv16_argb32rot),
+ ENTRY(YUY16, RGB888, rot_yuv16_argb32rot),
+
+ ENTRY(YUY16_PALETTED, ARGB8888, rot_yuv16pal_argb32rot),
+ ENTRY(YUY16_PALETTED, RGB888, rot_yuv16pal_argb32rot),
+
+ ENTRY(PALETTE16, ARGB8888, rot_pal16_argb32),
+ ENTRY(PALETTE16, RGB888, rot_pal16_argb32),
+
+ ENTRY(RGB15, RGB555, rot_rgb15_argb1555),
+ ENTRY(RGB15, ARGB1555, rot_rgb15_argb1555),
+ ENTRY(RGB15, ARGB8888, rot_rgb15_argb32),
+ ENTRY(RGB15, RGB888, rot_rgb15_argb32),
+
+ ENTRY(RGB15_PALETTED, ARGB8888, rot_rgb15pal_argb32),
+ ENTRY(RGB15_PALETTED, RGB888, rot_rgb15pal_argb32),
+
+ ENTRY(PALETTE16A, ARGB8888, rot_pal16a_argb32),
+ ENTRY(PALETTE16A, RGB888, rot_pal16a_rgb32),
+
+ { -1 },
+};
+
+} // anonymous namespace
+
+} // namespace osd
+
+
+#else // defined(OSD_SDL)
+
+namespace osd { namespace { MODULE_NOT_SUPPORTED(video_sdl2, OSD_RENDERER_PROVIDER, "accel") } }
+
+#endif // defined(OSD_SDL)
+
+
+MODULE_DEFINITION(RENDERER_SDL2, osd::video_sdl2)
diff --git a/src/osd/modules/render/draw13.h b/src/osd/modules/render/draw13.h
deleted file mode 100644
index 26a6bb565bf..00000000000
--- a/src/osd/modules/render/draw13.h
+++ /dev/null
@@ -1,213 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Couriersud, Olivier Galibert, R. Belmont
-//============================================================
-//
-// draw13.h - SDL 2.0 drawing implementation
-//
-// SDLMAME by Olivier Galibert and R. Belmont
-//
-//============================================================
-
-#pragma once
-
-#ifndef __DRAW20__
-#define __DRAW20__
-
-// OSD headers
-#ifndef OSD_WINDOWS
-#include "osdsdl.h"
-#include "window.h"
-#else
-#include "../windows/window.h"
-typedef uint64_t HashT;
-#endif
-
-// standard SDL headers
-#include <SDL2/SDL.h>
-
-struct quad_setup_data
-{
- quad_setup_data()
- : dudx(0)
- , dvdx(0)
- , dudy(0)
- , dvdy(0)
- , startu(0)
- , startv(0)
- , rotwidth(0)
- , rotheight(0)
- {
- }
-
- void compute(const render_primitive &prim, const int prescale);
-
- int32_t dudx, dvdx, dudy, dvdy;
- int32_t startu, startv;
- int32_t rotwidth, rotheight;
-};
-
-//============================================================
-// Textures
-//============================================================
-
-class renderer_sdl2;
-struct copy_info_t;
-
-/* texture_info holds information about a texture */
-class texture_info
-{
- friend class simple_list<texture_info>;
-public:
- texture_info(renderer_sdl2 *renderer, const render_texinfo &texsource, const quad_setup_data &setup, const uint32_t flags);
- ~texture_info();
-
- void set_data(const render_texinfo &texsource, const uint32_t flags);
- void render_quad(const render_primitive &prim, const int x, const int y);
- bool matches(const render_primitive &prim, const quad_setup_data &setup);
-
- copy_info_t *compute_size_type();
-
- void *m_pixels; // pixels for the texture
- int m_pitch;
-
- copy_info_t *m_copyinfo;
- quad_setup_data m_setup;
-
- osd_ticks_t m_last_access;
-
- int raw_width() const { return m_texinfo.width; }
- int raw_height() const { return m_texinfo.height; }
-
- texture_info *next() { return m_next; }
- const render_texinfo &texinfo() const { return m_texinfo; }
- render_texinfo &texinfo() { return m_texinfo; }
-
- HashT hash() const { return m_hash; }
- uint32_t flags() const { return m_flags; }
- // FIXME:
- bool is_pixels_owned() const;
-
-private:
- void set_coloralphamode(SDL_Texture *texture_id, const render_color *color);
-
- Uint32 m_sdl_access;
- renderer_sdl2 * m_renderer;
- render_texinfo m_texinfo; // copy of the texture info
- HashT m_hash; // hash value for the texture (must be >= pointer size)
- uint32_t m_flags; // rendering flags
-
- SDL_Texture * m_texture_id;
- bool m_is_rotated;
-
- int m_format; // texture format
- SDL_BlendMode m_sdl_blendmode;
-
- texture_info * m_next; // next texture in the list
-};
-
-//============================================================
-// TEXCOPY FUNCS
-//============================================================
-
-enum SDL_TEXFORMAT_E
-{
- SDL_TEXFORMAT_ARGB32 = 0,
- SDL_TEXFORMAT_RGB32,
- SDL_TEXFORMAT_RGB32_PALETTED,
- SDL_TEXFORMAT_YUY16,
- SDL_TEXFORMAT_YUY16_PALETTED,
- SDL_TEXFORMAT_PALETTE16,
- SDL_TEXFORMAT_RGB15,
- SDL_TEXFORMAT_RGB15_PALETTED,
- SDL_TEXFORMAT_PALETTE16A,
- SDL_TEXFORMAT_PALETTE16_ARGB1555,
- SDL_TEXFORMAT_RGB15_ARGB1555,
- SDL_TEXFORMAT_RGB15_PALETTED_ARGB1555,
- SDL_TEXFORMAT_LAST = SDL_TEXFORMAT_RGB15_PALETTED_ARGB1555
-};
-
-#include "blit13.h"
-
-struct copy_info_t
-{
- int src_fmt;
- Uint32 dst_fmt;
- const blit_base *blitter;
- Uint32 bm_mask;
- const char *srcname;
- const char *dstname;
- /* Statistics */
- uint64_t pixel_count;
- int64_t time;
- int samples;
- int perf;
- /* list */
- copy_info_t *next;
-};
-
-/* renderer_sdl2 is the information about SDL for the current screen */
-class renderer_sdl2 : public osd_renderer
-{
-public:
- renderer_sdl2(std::shared_ptr<osd_window> window, int extra_flags);
-
- virtual ~renderer_sdl2()
- {
- destroy_all_textures();
- SDL_DestroyRenderer(m_sdl_renderer);
- m_sdl_renderer = nullptr;
- }
-
- static void init(running_machine &machine);
- static void exit();
-
- virtual int create() override;
- virtual int draw(const int update) override;
- virtual int xy_to_render_target(const int x, const int y, int *xt, int *yt) override;
- virtual render_primitive_list *get_primitives() override;
-
- int RendererSupportsFormat(Uint32 format, Uint32 access, const char *sformat);
-
- SDL_Renderer * m_sdl_renderer;
-
- static copy_info_t* s_blit_info[SDL_TEXFORMAT_LAST+1];
-
-private:
- void expand_copy_info(const copy_info_t *list);
- void add_list(copy_info_t **head, const copy_info_t *element, Uint32 bm);
-
- void render_quad(texture_info *texture, const render_primitive &prim, const int x, const int y);
-
- texture_info *texture_find(const render_primitive &prim, const quad_setup_data &setup);
- texture_info *texture_update(const render_primitive &prim);
-
- void destroy_all_textures();
-
- int32_t m_blittimer;
-
-
- simple_list<texture_info> m_texlist; // list of active textures
-
- float m_last_hofs;
- float m_last_vofs;
-
- int m_width;
- int m_height;
-
- osd_dim m_blit_dim;
-
- struct
- {
- Uint32 format;
- int status;
- } fmt_support[30];
-
- // Stats
- int64_t m_last_blit_time;
- int64_t m_last_blit_pixels;
-
- static bool s_blit_info_initialized;
- static const copy_info_t s_blit_info_default[];
-};
-
-#endif // __DRAW20__
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);
+}
diff --git a/src/osd/modules/render/drawbgfx.h b/src/osd/modules/render/drawbgfx.h
index e7e648c27d1..bb9f538aafa 100644
--- a/src/osd/modules/render/drawbgfx.h
+++ b/src/osd/modules/render/drawbgfx.h
@@ -1,31 +1,34 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
+#ifndef MAME_RENDER_DRAWBGFX_H
+#define MAME_RENDER_DRAWBGFX_H
+
#pragma once
-#ifndef RENDER_BGFX
-#define RENDER_BGFX
+#include "binpacker.h"
+#include "bgfx/chain.h"
+#include "bgfx/chainmanager.h"
+#include "bgfx/vertex.h"
+#include "sliderdirtynotifier.h"
+
+#include "modules/osdwindow.h"
+
+#include "notifier.h"
#include <bgfx/bgfx.h>
#include <map>
+#include <memory>
#include <vector>
-#include "binpacker.h"
-#include "bgfx/vertex.h"
-#include "bgfx/chain.h"
-#include "bgfx/chainmanager.h"
-#include "sliderdirtynotifier.h"
-#include "../frontend/mame/ui/menuitem.h"
class texture_manager;
class target_manager;
class shader_manager;
class effect_manager;
-class chain_manager;
class bgfx_texture;
class bgfx_effect;
class bgfx_target;
-class bgfx_chain;
class bgfx_view;
class osd_options;
class avi_write;
@@ -34,11 +37,10 @@ class avi_write;
class renderer_bgfx : public osd_renderer, public slider_dirty_notifier
{
public:
- renderer_bgfx(std::shared_ptr<osd_window> w);
- virtual ~renderer_bgfx();
+ class parent_module;
- static bool init(running_machine &machine);
- static void exit();
+ renderer_bgfx(osd_window &window, parent_module &parent_module);
+ virtual ~renderer_bgfx();
virtual int create() override;
virtual int draw(const int update) override;
@@ -58,33 +60,30 @@ public:
uint32_t get_window_width(uint32_t index) const;
uint32_t get_window_height(uint32_t index) const;
- virtual render_primitive_list *get_primitives() override
- {
- auto win = try_getwindow();
- if (win == nullptr)
- return nullptr;
-
- // 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 = win->get_size();
- if (wdim.width() > 0 && wdim.height() > 0)
- win->target()->set_bounds(wdim.width(), wdim.height(), win->pixel_aspect());
-
- win->target()->set_transform_container(!chain_transform);
- return &win->target()->get_primitives();
- }
+ virtual render_primitive_list *get_primitives() override;
static char const *const WINDOW_PREFIX;
private:
+ enum buffer_status
+ {
+ BUFFER_PRE_FLUSH,
+ BUFFER_FLUSH,
+ BUFFER_SCREEN,
+ BUFFER_EMPTY,
+ BUFFER_DONE
+ };
+
+ class parent_module_holder
+ {
+ public:
+ parent_module_holder(parent_module &parent);
+ ~parent_module_holder();
+ parent_module &operator()() const { return m_parent; }
+ private:
+ parent_module &m_parent;
+ };
+
void vertex(ScreenVertex* vertex, float x, float y, float z, uint32_t rgba, float u, float v);
void render_avi_quad();
void update_recording();
@@ -94,18 +93,10 @@ private:
void setup_ortho_view();
void allocate_buffer(render_primitive *prim, uint32_t blend, bgfx::TransientVertexBuffer *buffer);
- enum buffer_status
- {
- BUFFER_PRE_FLUSH,
- BUFFER_FLUSH,
- BUFFER_SCREEN,
- BUFFER_EMPTY,
- BUFFER_DONE
- };
- buffer_status buffer_primitives(bool atlas_valid, render_primitive** prim, bgfx::TransientVertexBuffer* buffer, int32_t screen);
+ buffer_status buffer_primitives(bool atlas_valid, render_primitive** prim, bgfx::TransientVertexBuffer* buffer, int32_t screen, int window_index);
- void render_textured_quad(render_primitive* prim, bgfx::TransientVertexBuffer* buffer);
- void render_post_screen_quad(int view, render_primitive* prim, bgfx::TransientVertexBuffer* buffer, int32_t screen);
+ void render_textured_quad(render_primitive* prim, bgfx::TransientVertexBuffer* buffer, int window_index);
+ void render_post_screen_quad(int view, render_primitive* prim, bgfx::TransientVertexBuffer* buffer, int32_t screen, int window_index);
void put_packed_quad(render_primitive *prim, uint32_t hash, ScreenVertex* vertex);
void put_packed_line(render_primitive *prim, ScreenVertex* vertex);
@@ -121,7 +112,10 @@ private:
void process_atlas_packs(std::vector<std::vector<rectangle_packer::packed_rectangle>>& packed);
uint32_t get_texture_hash(render_primitive *prim);
- osd_options& m_options;
+ void load_config(util::xml::data_node const &parentnode);
+ void save_config(util::xml::data_node &parentnode);
+
+ parent_module_holder m_module; // keep this where it will be destructed last
bgfx_target *m_framebuffer;
bgfx_texture *m_texture_cache;
@@ -129,11 +123,11 @@ private:
// Original display_mode
osd_dim m_dimensions;
- texture_manager *m_textures;
- target_manager *m_targets;
- shader_manager *m_shaders;
- effect_manager *m_effects;
- chain_manager *m_chains;
+ std::unique_ptr<texture_manager> m_textures;
+ std::unique_ptr<target_manager> m_targets;
+ std::unique_ptr<shader_manager> m_shaders;
+ std::unique_ptr<effect_manager> m_effects;
+ std::unique_ptr<chain_manager> m_chains;
bgfx_effect *m_gui_effect[4];
bgfx_effect *m_screen_effect[4];
@@ -143,10 +137,8 @@ private:
std::vector<rectangle_packer::packable_rectangle> m_texinfo;
rectangle_packer m_packer;
- uint32_t m_width[16];
- uint32_t m_height[16];
uint32_t m_white[16*16];
- bgfx_view *m_ortho_view;
+ std::unique_ptr<bgfx_view> m_ortho_view;
uint32_t m_max_view;
bgfx_view *m_avi_view;
@@ -156,12 +148,17 @@ private:
bitmap_rgb32 m_avi_bitmap;
uint8_t *m_avi_data;
+ std::unique_ptr<util::xml::file> m_config;
+ const util::notifier_subscription m_load_sub;
+ const util::notifier_subscription m_save_sub;
+
static const uint16_t CACHE_SIZE;
static const uint32_t PACKABLE_SIZE;
static const uint32_t WHITE_HASH;
- static bool s_window_set;
static uint32_t s_current_view;
+ static uint32_t s_width[16];
+ static uint32_t s_height[16];
};
-#endif // RENDER_BGFX
+#endif // MAME_RENDER_DRAWBGFX_H
diff --git a/src/osd/modules/render/drawd3d.cpp b/src/osd/modules/render/drawd3d.cpp
index fd1331c47eb..542e2f8955d 100644
--- a/src/osd/modules/render/drawd3d.cpp
+++ b/src/osd/modules/render/drawd3d.cpp
@@ -8,25 +8,137 @@
// MAME headers
#include "emu.h"
+#include "emuopts.h"
#include "render.h"
-
#include "rendutil.h"
-#include "emuopts.h"
-#include "aviio.h"
+#include "screen.h"
// MAMEOS headers
-#include "winmain.h"
-#include "window.h"
#include "drawd3d.h"
-#include "modules/render/d3d/d3dhlsl.h"
+
+#include "d3d/d3dhlsl.h"
+
+#include "render_module.h"
+
+// from OSD implementation
+#include "window.h"
+#include "winmain.h"
+
+// general OSD headers
#include "modules/monitor/monitor_module.h"
+
+// lib/util
+#include "aviio.h"
+
#include <utility>
+
+//============================================================
+// OSD MODULE
+//============================================================
+
+namespace osd {
+
+namespace {
+
+class video_d3d : public osd_module, public render_module
+{
+public:
+ video_d3d()
+ : osd_module(OSD_RENDERER_PROVIDER, "d3d")
+ , m_options(nullptr)
+ {
+ }
+
+ virtual bool probe() override;
+ 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:
+ using d3d9_create_fn = IDirect3D9 *(WINAPI *)(UINT);
+
+ dynamic_module::ptr m_d3d9_dll;
+ Microsoft::WRL::ComPtr<IDirect3D9> m_d3dobj;
+ osd_options const *m_options;
+};
+
+
+//============================================================
+// video_d3d::probe
+//============================================================
+
+bool video_d3d::probe()
+{
+ // do a dry run of loading the Direct3D 9 DLL
+ return dynamic_module::open({ "d3d9.dll" })->bind<d3d9_create_fn>("Direct3DCreate9") != nullptr;
+}
+
+
+//============================================================
+// video_d3d::init
+//============================================================
+
+int video_d3d::init(osd_interface &osd, osd_options const &options)
+{
+ m_options = &options;
+
+ m_d3d9_dll = dynamic_module::open({ "d3d9.dll" });
+ auto const d3d9_create_ptr = m_d3d9_dll->bind<d3d9_create_fn>("Direct3DCreate9");
+ if (!d3d9_create_ptr)
+ {
+ osd_printf_warning("Direct3D: Could not find Direct3DCreate9 function in d3d9.dll\n");
+ m_d3d9_dll.reset();
+ m_options = nullptr;
+ return -1;
+ }
+
+ m_d3dobj.Attach((d3d9_create_ptr)(D3D_SDK_VERSION));
+ if (!m_d3dobj)
+ {
+ osd_printf_warning("Direct3D: Unable to initialize Direct3D 9\n");
+ m_d3d9_dll.reset();
+ m_options = nullptr;
+ return -1;
+ }
+
+ osd_printf_verbose("Direct3D: Using Direct3D 9\n");
+
+ return 0;
+}
+
+
+//============================================================
+// video_d3d::exit
//============================================================
-// TYPE DEFINITIONS
+
+void video_d3d::exit()
+{
+ m_d3dobj.Reset();
+ m_d3d9_dll.reset();
+ m_options = nullptr;
+}
+
+
//============================================================
+// video_d3d::create
+//============================================================
+
+std::unique_ptr<osd_renderer> video_d3d::create(osd_window &window)
+{
+ return std::make_unique<renderer_d3d9>(window, m_d3dobj);
+}
+
+} // anonymous namespace
+
+} // namespace osd
+
+MODULE_DEFINITION(RENDERER_D3D, osd::video_d3d)
-typedef IDirect3D9* (WINAPI *d3d9_create_fn)(UINT);
//============================================================
@@ -115,13 +227,6 @@ static inline uint32_t ycc_to_rgb(uint8_t y, uint8_t cb, uint8_t cr)
//============================================================
-// drawd3d_init
-//============================================================
-
-static d3d_base * d3dintf; // FIX ME
-
-
-//============================================================
// drawd3d_window_init
//============================================================
@@ -173,56 +278,22 @@ void renderer_d3d9::save()
render_primitive_list *renderer_d3d9::get_primitives()
{
RECT client;
- auto win = try_getwindow();
- if (win == nullptr)
- return nullptr;
-
- HWND hWnd = std::static_pointer_cast<win_window_info>(win)->platform_window();
+ HWND hWnd = dynamic_cast<win_window_info &>(window()).platform_window();
if (IsIconic(hWnd))
return nullptr;
- GetClientRectExceptMenu(hWnd, &client, win->fullscreen());
+ GetClientRectExceptMenu(hWnd, &client, window().fullscreen());
if (rect_width(&client) > 0 && rect_height(&client) > 0)
{
- win->target()->set_bounds(rect_width(&client), rect_height(&client), win->pixel_aspect());
- win->target()->set_max_update_rate((get_refresh() == 0) ? get_origmode().RefreshRate : get_refresh());
+ window().target()->set_bounds(rect_width(&client), rect_height(&client), window().pixel_aspect());
+ window().target()->set_max_update_rate((get_refresh() == 0) ? get_origmode().RefreshRate : get_refresh());
}
if (m_shaders != nullptr)
{
// do not transform primitives (scale, offset) if shaders are enabled, the shaders will handle the transformation
- win->target()->set_transform_container(!m_shaders->enabled());
+ window().target()->set_transform_container(!m_shaders->enabled());
}
- return &win->target()->get_primitives();
-}
-
-
-//============================================================
-// renderer_d3d9::init
-//============================================================
-
-bool renderer_d3d9::init(running_machine &machine)
-{
- d3dintf = global_alloc(d3d_base);
-
- d3dintf->d3d9_dll = osd::dynamic_module::open({ "d3d9.dll" });
-
- d3d9_create_fn d3d9_create_ptr = d3dintf->d3d9_dll->bind<d3d9_create_fn>("Direct3DCreate9");
- if (d3d9_create_ptr == nullptr)
- {
- osd_printf_verbose("Direct3D: Unable to find Direct3D 9 runtime library\n");
- return true;
- }
-
- d3dintf->d3dobj = (*d3d9_create_ptr)(D3D_SDK_VERSION);
- if (d3dintf->d3dobj == nullptr)
- {
- osd_printf_verbose("Direct3D: Unable to initialize Direct3D 9\n");
- return true;
- }
-
- osd_printf_verbose("Direct3D: Using Direct3D 9\n");
-
- return false;
+ return &window().target()->get_primitives();
}
@@ -237,7 +308,12 @@ int renderer_d3d9::draw(const int update)
return check;
begin_frame();
+
+ // reset blend mode
+ set_blendmode(BLENDMODE_NONE);
+
process_primitives();
+
end_frame();
return 0;
@@ -249,8 +325,12 @@ void renderer_d3d9::set_texture(texture_info *texture)
{
m_last_texture = texture;
m_last_texture_flags = (texture == nullptr ? 0 : texture->get_flags());
+ if (m_shaders->enabled())
+ {
+ m_shaders->set_texture(texture);
+ }
+
HRESULT result = m_device->SetTexture(0, (texture == nullptr) ? get_default_texture()->get_finaltex() : texture->get_finaltex());
- m_shaders->set_texture(texture);
if (FAILED(result))
osd_printf_verbose("Direct3D: Error %08lX during device set_texture call\n", result);
}
@@ -348,15 +428,20 @@ void renderer_d3d9::set_blendmode(int blendmode)
}
// adjust the bits that changed
+ bool new_blend_enable = false;
if (blendenable != m_last_blendenable)
{
m_last_blendenable = blendenable;
+ if (blendenable)
+ {
+ new_blend_enable = true;
+ }
HRESULT result = m_device->SetRenderState(D3DRS_ALPHABLENDENABLE, blendenable);
if (FAILED(result))
osd_printf_verbose("Direct3D: Error %08lX during device SetRenderState call\n", result);
}
- if (blendop != m_last_blendop)
+ if (blendop != m_last_blendop || new_blend_enable)
{
m_last_blendop = blendop;
HRESULT result = m_device->SetRenderState(D3DRS_BLENDOP, blendop);
@@ -364,7 +449,7 @@ void renderer_d3d9::set_blendmode(int blendmode)
osd_printf_verbose("Direct3D: Error %08lX during device SetRenderState call\n", result);
}
- if (blendsrc != m_last_blendsrc)
+ if (blendsrc != m_last_blendsrc || new_blend_enable)
{
m_last_blendsrc = blendsrc;
HRESULT result = m_device->SetRenderState(D3DRS_SRCBLEND, blendsrc);
@@ -372,7 +457,7 @@ void renderer_d3d9::set_blendmode(int blendmode)
osd_printf_verbose("Direct3D: Error %08lX during device SetRenderState call\n", result);
}
- if (blenddst != m_last_blenddst)
+ if (blenddst != m_last_blenddst || new_blend_enable)
{
m_last_blenddst = blenddst;
HRESULT result = m_device->SetRenderState(D3DRS_DESTBLEND, blenddst);
@@ -393,27 +478,15 @@ void renderer_d3d9::reset_render_states()
m_last_wrap = (D3DTEXTUREADDRESS)-1;
}
-d3d_texture_manager::d3d_texture_manager(renderer_d3d9 *d3d)
+d3d_texture_manager::d3d_texture_manager(renderer_d3d9 &d3d, IDirect3D9 *d3dobj)
+ : m_renderer(d3d)
+ , m_default_texture(nullptr)
{
- m_renderer = d3d;
-
- m_default_texture = nullptr;
-
D3DCAPS9 caps;
- HRESULT result = d3dintf->d3dobj->GetDeviceCaps(d3d->get_adapter(), D3DDEVTYPE_HAL, &caps);
+ HRESULT result = d3dobj->GetDeviceCaps(d3d.get_adapter(), D3DDEVTYPE_HAL, &caps);
if (FAILED(result))
osd_printf_verbose("Direct3D: Error %08lX during GetDeviceCaps call\n", result);
- // check for dynamic texture support
- m_dynamic_supported = ((caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) != 0);
- if (m_dynamic_supported)
- osd_printf_verbose("Direct3D: Using dynamic textures\n");
-
- // check for stretchrect support
- m_stretch_supported = ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFPOINT) != 0);
- if (m_stretch_supported && video_config.prescale > 1)
- osd_printf_verbose("Direct3D: Using StretchRect for prescaling\n");
-
// get texture caps
m_texture_caps = caps.TextureCaps;
m_texture_max_aspect = caps.MaxTextureAspectRatio;
@@ -422,35 +495,30 @@ d3d_texture_manager::d3d_texture_manager(renderer_d3d9 *d3d)
// pick a YUV texture format
m_yuv_format = D3DFMT_UYVY;
- result = d3dintf->d3dobj->CheckDeviceFormat(d3d->get_adapter(), D3DDEVTYPE_HAL, d3d->get_pixel_format(), 0, D3DRTYPE_TEXTURE, D3DFMT_UYVY);
+ result = d3dobj->CheckDeviceFormat(d3d.get_adapter(), D3DDEVTYPE_HAL, d3d.get_pixel_format(), 0, D3DRTYPE_TEXTURE, D3DFMT_UYVY);
if (FAILED(result))
{
m_yuv_format = D3DFMT_YUY2;
- result = d3dintf->d3dobj->CheckDeviceFormat(d3d->get_adapter(), D3DDEVTYPE_HAL, d3d->get_pixel_format(), 0, D3DRTYPE_TEXTURE, D3DFMT_YUY2);
+ result = d3dobj->CheckDeviceFormat(d3d.get_adapter(), D3DDEVTYPE_HAL, d3d.get_pixel_format(), 0, D3DRTYPE_TEXTURE, D3DFMT_YUY2);
if (FAILED(result))
m_yuv_format = D3DFMT_A8R8G8B8;
}
osd_printf_verbose("Direct3D: YUV format = %s\n", (m_yuv_format == D3DFMT_YUY2) ? "YUY2" : (m_yuv_format == D3DFMT_UYVY) ? "UYVY" : "RGB");
- auto win = d3d->assert_window();
-
// set the max texture size
- win->target()->set_max_texture_size(m_texture_max_width, m_texture_max_height);
- osd_printf_verbose("Direct3D: Max texture size = %dx%d\n", (int)m_texture_max_width, (int)m_texture_max_height);
+ d3d.window().target()->set_max_texture_size(m_texture_max_width, m_texture_max_height);
+ osd_printf_verbose("Direct3D: Max texture size = %dx%d\n", m_texture_max_width, m_texture_max_height);
}
void d3d_texture_manager::create_resources()
{
- auto win = m_renderer->assert_window();
-
m_default_bitmap.allocate(8, 8);
- m_default_bitmap.fill(rgb_t(0xff,0xff,0xff,0xff));
-
if (m_default_bitmap.valid())
{
- render_texinfo texture;
+ m_default_bitmap.fill(rgb_t(0xff,0xff,0xff,0xff));
// fake in the basic data so it looks like it came from render.c
+ render_texinfo texture;
texture.base = m_default_bitmap.raw_pixptr(0);
texture.rowpixels = m_default_bitmap.rowpixels();
texture.width = m_default_bitmap.width();
@@ -461,7 +529,7 @@ void d3d_texture_manager::create_resources()
texture.old_id = ~0ULL;
// now create it
- auto tex = std::make_unique<texture_info>(this, &texture, win->prescale(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32));
+ auto tex = std::make_unique<texture_info>(*this, &texture, m_renderer.window().prescale(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXFORMAT(TEXFORMAT_ARGB32));
m_default_texture = tex.get();
m_texture_list.push_back(std::move(tex));
}
@@ -470,7 +538,6 @@ void d3d_texture_manager::create_resources()
void d3d_texture_manager::delete_resources()
{
// is part of m_texlist and will be free'd there
- //global_free(m_default_texture);
m_default_texture = nullptr;
// free all textures
@@ -484,16 +551,16 @@ uint32_t d3d_texture_manager::texture_compute_hash(const render_texinfo *texture
texture_info *d3d_texture_manager::find_texinfo(const render_texinfo *texinfo, uint32_t flags)
{
- uint32_t hash = texture_compute_hash(texinfo, flags);
+ const uint32_t hash = texture_compute_hash(texinfo, flags);
// find a match
for (auto it = m_texture_list.begin(); it != m_texture_list.end(); it++)
{
- uint32_t test_screen = (uint32_t)((*it)->get_texinfo().unique_id >> 57);
- uint32_t test_page = (uint32_t)((*it)->get_texinfo().unique_id >> 56) & 1;
- uint32_t prim_screen = (uint32_t)(texinfo->unique_id >> 57);
- uint32_t prim_page = (uint32_t)(texinfo->unique_id >> 56) & 1;
- if (test_screen != prim_screen || test_page != prim_page)
+ const uint32_t test_screen = uint32_t((*it)->get_texinfo().unique_id >> 57);
+ const uint32_t test_page = uint32_t((*it)->get_texinfo().unique_id >> 56) & 1;
+ const uint32_t prim_screen = uint32_t(texinfo->unique_id >> 57);
+ const uint32_t prim_page = uint32_t(texinfo->unique_id >> 56) & 1;
+ if ((test_screen != prim_screen) || (test_page != prim_page))
continue;
if ((*it)->get_hash() == hash &&
@@ -509,11 +576,35 @@ texture_info *d3d_texture_manager::find_texinfo(const render_texinfo *texinfo, u
return nullptr;
}
-renderer_d3d9::renderer_d3d9(std::shared_ptr<osd_window> window)
- : osd_renderer(window, FLAG_NONE), m_adapter(0), m_width(0), m_height(0), m_refresh(0), m_create_error_count(0), m_device(nullptr), m_gamma_supported(0), m_pixformat(),
- m_vertexbuf(nullptr), m_lockedbuf(nullptr), m_numverts(0), m_vectorbatch(nullptr), m_batchindex(0), m_numpolys(0), m_toggle(false),
- m_screen_format(), m_last_texture(nullptr), m_last_texture_flags(0), m_last_blendenable(0), m_last_blendop(0), m_last_blendsrc(0), m_last_blenddst(0), m_last_filter(0),
- m_last_wrap(), m_last_modmode(0), m_shaders(nullptr), m_texture_manager(nullptr)
+renderer_d3d9::renderer_d3d9(osd_window &window, const IDirect3D9Ptr &d3dobj)
+ : osd_renderer(window)
+ , m_d3dobj(d3dobj)
+ , m_adapter(0)
+ , m_width(0)
+ , m_height(0)
+ , m_refresh(0)
+ , m_create_error_count(0)
+ , m_post_fx_available(true)
+ , m_gamma_supported(0)
+ , m_pixformat()
+ , m_lockedbuf(nullptr)
+ , m_numverts(0)
+ , m_vectorbatch(nullptr)
+ , m_batchindex(0)
+ , m_numpolys(0)
+ , m_toggle(false)
+ , m_screen_format()
+ , m_last_texture(nullptr)
+ , m_last_texture_flags(0)
+ , m_last_blendenable(0)
+ , m_last_blendop(0)
+ , m_last_blendsrc(0)
+ , m_last_blenddst(0)
+ , m_last_filter(0)
+ , m_last_wrap()
+ , m_last_modmode(0)
+ , m_shaders(nullptr)
+ , m_texture_manager()
{
}
@@ -528,8 +619,7 @@ int renderer_d3d9::initialize()
}
// create the device immediately for the full screen case (defer for window mode in update_window_size())
- auto win = assert_window();
- if (win->fullscreen() && device_create(std::static_pointer_cast<win_window_info>(win->main_window())->platform_window()))
+ if (window().fullscreen() && device_create(dynamic_cast<win_window_info &>(window()).main_window()->platform_window()))
{
return false;
}
@@ -539,10 +629,8 @@ int renderer_d3d9::initialize()
int renderer_d3d9::pre_window_draw_check()
{
- auto win = assert_window();
-
// if we're in the middle of resizing, leave things alone
- if (win->m_resize_state == RESIZE_STATE_RESIZING)
+ if (dynamic_cast<win_window_info &>(window()).m_resize_state == win_window_info::RESIZE_STATE_RESIZING)
return 0;
// check if shaders should be toggled
@@ -566,7 +654,7 @@ int renderer_d3d9::pre_window_draw_check()
}
// if we have a device, check the cooperative level
- if (m_device != nullptr)
+ if (m_device)
{
if (device_test_cooperative())
{
@@ -575,14 +663,14 @@ int renderer_d3d9::pre_window_draw_check()
}
// in window mode, we need to track the window size
- if (!win->fullscreen() || m_device == nullptr)
+ if (!window().fullscreen() || !m_device)
{
// if the size changes, skip this update since the render target will be out of date
if (update_window_size())
return 0;
// if we have no device, after updating the size, return an error so GDI can try
- if (m_device == nullptr)
+ if (!m_device)
return 1;
}
@@ -591,18 +679,16 @@ int renderer_d3d9::pre_window_draw_check()
void d3d_texture_manager::update_textures()
{
- auto win = m_renderer->assert_window();
-
- for (render_primitive &prim : *win->m_primlist)
+ for (render_primitive &prim : *m_renderer.window().m_primlist)
{
if (prim.texture.base != nullptr)
{
texture_info *texture = find_texinfo(&prim.texture, prim.flags);
if (texture == nullptr)
{
- int prescale = m_renderer->get_shaders()->enabled() ? 1 : win->prescale();
+ const int prescale = m_renderer.get_shaders()->enabled() ? 1 : m_renderer.window().prescale();
- auto tex = std::make_unique<texture_info>(this, &prim.texture, prescale, prim.flags);
+ auto tex = std::make_unique<texture_info>(*this, &prim.texture, prescale, prim.flags);
texture = tex.get();
m_texture_list.push_back(std::move(tex));
}
@@ -618,21 +704,19 @@ void d3d_texture_manager::update_textures()
}
}
- if (!m_renderer->get_shaders()->enabled())
- {
+ if (!m_renderer.get_shaders()->enabled())
return;
- }
int screen_index = 0;
- for (render_primitive &prim : *win->m_primlist)
+ for (render_primitive &prim : *m_renderer.window().m_primlist)
{
if (PRIMFLAG_GET_SCREENTEX(prim.flags))
{
- if (!m_renderer->get_shaders()->get_texture_target(&prim, prim.texture.width, prim.texture.height, screen_index))
+ if (!m_renderer.get_shaders()->get_texture_target(&prim, prim.texture.width, prim.texture.height, screen_index))
{
- if (!m_renderer->get_shaders()->create_texture_target(&prim, prim.texture.width, prim.texture.height, screen_index))
+ if (!m_renderer.get_shaders()->create_texture_target(&prim, prim.texture.width, prim.texture.height, screen_index))
{
- d3dintf->post_fx_available = false;
+ m_renderer.set_post_fx_unavailable();
break;
}
}
@@ -640,11 +724,11 @@ void d3d_texture_manager::update_textures()
}
else if (PRIMFLAG_GET_VECTORBUF(prim.flags))
{
- if (!m_renderer->get_shaders()->get_vector_target(&prim, screen_index))
+ if (!m_renderer.get_shaders()->get_vector_target(&prim, screen_index))
{
- if (!m_renderer->get_shaders()->create_vector_target(&prim, screen_index))
+ if (!m_renderer.get_shaders()->create_vector_target(&prim, screen_index))
{
- d3dintf->post_fx_available = false;
+ m_renderer.set_post_fx_unavailable();
break;
}
}
@@ -655,13 +739,11 @@ void d3d_texture_manager::update_textures()
void renderer_d3d9::begin_frame()
{
- auto win = assert_window();
-
- HRESULT result = m_device->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0);
+ HRESULT result = m_device->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0xff,0,0,0), 0, 0);
if (FAILED(result))
osd_printf_verbose("Direct3D: Error %08lX during device clear call\n", result);
- win->m_primlist->acquire_lock();
+ window().m_primlist->acquire_lock();
// first update any textures
m_texture_manager->update_textures();
@@ -672,16 +754,17 @@ void renderer_d3d9::begin_frame()
osd_printf_verbose("Direct3D: Error %08lX during device BeginScene call\n", result);
if (m_shaders->enabled())
- m_shaders->init_fsfx_quad();
+ m_shaders->begin_frame(window().m_primlist);
+
+ // set an initial default texture
+ set_texture(nullptr);
}
void renderer_d3d9::process_primitives()
{
- auto win = assert_window();
-
// loop over line primitives
int vector_count = 0;
- for (render_primitive &prim : *win->m_primlist)
+ for (render_primitive &prim : *window().m_primlist)
{
if (prim.type == render_primitive::LINE && PRIMFLAG_GET_VECTOR(prim.flags))
{
@@ -690,7 +773,7 @@ void renderer_d3d9::process_primitives()
}
// Rotating index for vector time offsets
- for (render_primitive &prim : *win->m_primlist)
+ for (render_primitive &prim : *window().m_primlist)
{
switch (prim.type)
{
@@ -721,13 +804,14 @@ void renderer_d3d9::process_primitives()
void renderer_d3d9::end_frame()
{
- auto win = assert_window();
-
- win->m_primlist->release_lock();
+ window().m_primlist->release_lock();
// flush any pending polygons
primitive_flush_pending();
+ if (m_shaders->enabled())
+ m_shaders->end_frame();
+
// finish the scene
HRESULT result = m_device->EndScene();
if (FAILED(result))
@@ -741,8 +825,6 @@ void renderer_d3d9::end_frame()
void renderer_d3d9::update_presentation_parameters()
{
- auto win = assert_window();
-
memset(&m_presentation, 0, sizeof(m_presentation));
m_presentation.BackBufferWidth = m_width;
m_presentation.BackBufferHeight = m_height;
@@ -750,14 +832,14 @@ void renderer_d3d9::update_presentation_parameters()
m_presentation.BackBufferCount = video_config.triplebuf ? 2 : 1;
m_presentation.MultiSampleType = D3DMULTISAMPLE_NONE;
m_presentation.SwapEffect = D3DSWAPEFFECT_DISCARD;
- m_presentation.hDeviceWindow = std::static_pointer_cast<win_window_info>(win)->platform_window();
- m_presentation.Windowed = !win->fullscreen() || win->win_has_menu();
+ m_presentation.hDeviceWindow = dynamic_cast<win_window_info &>(window()).platform_window();
+ m_presentation.Windowed = !window().fullscreen();
m_presentation.EnableAutoDepthStencil = FALSE;
m_presentation.AutoDepthStencilFormat = D3DFMT_D16;
m_presentation.Flags = 0;
m_presentation.FullScreen_RefreshRateInHz = m_refresh;
m_presentation.PresentationInterval = (
- (video_config.triplebuf && win->fullscreen())
+ (video_config.triplebuf && window().fullscreen())
|| video_config.waitvsync
|| video_config.syncrefresh)
? D3DPRESENT_INTERVAL_ONE
@@ -772,13 +854,11 @@ void renderer_d3d9::update_gamma_ramp()
return;
}
- auto win = assert_window();
-
// set the gamma if we need to
- if (win->fullscreen())
+ if (window().fullscreen())
{
// only set the gamma if it's not 1.0
- windows_options &options = downcast<windows_options &>(win->machine().options());
+ auto &options = downcast<windows_options &>(window().machine().options());
float brightness = options.full_screen_brightness();
float contrast = options.full_screen_contrast();
float gamma = options.full_screen_gamma();
@@ -801,44 +881,30 @@ void renderer_d3d9::update_gamma_ramp()
// device_create
//============================================================
-int renderer_d3d9::device_create(HWND device_hwnd)
+int renderer_d3d9::device_create(HWND hwnd)
{
+ // identify the actual window; this is needed so that -attach_window
+ // can work on a non-root HWND
+ HWND device_hwnd = GetAncestor(hwnd, GA_ROOT);
+
// if a device exists, free it
- if (m_device != nullptr)
- {
+ if (m_device)
device_delete();
- }
// verify the caps
if (!device_verify_caps())
- {
return 1;
- }
- m_texture_manager = global_alloc(d3d_texture_manager(this));
+ m_texture_manager = std::make_unique<d3d_texture_manager>(*this, m_d3dobj.Get());
-try_again:
// try for XRGB first
m_screen_format = D3DFMT_X8R8G8B8;
- HRESULT result = d3dintf->d3dobj->CheckDeviceFormat(m_adapter, D3DDEVTYPE_HAL, m_pixformat,
- m_texture_manager->is_dynamic_supported()
- ? D3DUSAGE_DYNAMIC
- : 0,
- D3DRTYPE_TEXTURE, m_screen_format);
+ HRESULT result = m_d3dobj->CheckDeviceFormat(m_adapter, D3DDEVTYPE_HAL, m_pixformat, D3DUSAGE_DYNAMIC, D3DRTYPE_TEXTURE, m_screen_format);
if (FAILED(result))
{
// if not, try for ARGB
m_screen_format = D3DFMT_A8R8G8B8;
- result = d3dintf->d3dobj->CheckDeviceFormat(m_adapter, D3DDEVTYPE_HAL, m_pixformat,
- m_texture_manager->is_dynamic_supported()
- ? D3DUSAGE_DYNAMIC
- : 0,
- D3DRTYPE_TEXTURE, m_screen_format);
- if (FAILED(result) && m_texture_manager->is_dynamic_supported())
- {
- m_texture_manager->set_dynamic_supported(false);
- goto try_again;
- }
+ result = m_d3dobj->CheckDeviceFormat(m_adapter, D3DDEVTYPE_HAL, m_pixformat, D3DUSAGE_DYNAMIC, D3DRTYPE_TEXTURE, m_screen_format);
if (FAILED(result))
{
osd_printf_error("Error: unable to configure a screen texture format\n");
@@ -850,8 +916,13 @@ try_again:
update_presentation_parameters();
// create the D3D device
- result = d3dintf->d3dobj->CreateDevice(
- m_adapter, D3DDEVTYPE_HAL, device_hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &m_presentation, &m_device);
+ result = m_d3dobj->CreateDevice(
+ m_adapter,
+ D3DDEVTYPE_HAL,
+ device_hwnd,
+ D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE,
+ &m_presentation,
+ &m_device);
if (FAILED(result))
{
// if we got a "DEVICELOST" error, it may be transitory; count it and only fail if
@@ -884,16 +955,13 @@ try_again:
int renderer_d3d9::device_create_resources()
{
- auto win = assert_window();
-
// create shaders only once
- if (m_shaders == nullptr)
- {
- m_shaders = (shaders*)global_alloc_clear<shaders>();
- }
+ if (!m_shaders)
+ m_shaders = std::make_unique<shaders>();
- if (m_shaders->init(d3dintf, &win->machine(), this))
+ if (m_shaders->init(m_d3dobj.Get(), &window().machine(), this))
{
+ m_post_fx_available = true;
m_shaders->init_slider_list();
m_sliders_dirty = true;
}
@@ -907,12 +975,12 @@ int renderer_d3d9::device_create_resources()
// allocate a vertex buffer to use
HRESULT result = m_device->CreateVertexBuffer(
- sizeof(vertex) * VERTEX_BUFFER_SIZE,
- D3DUSAGE_DYNAMIC | D3DUSAGE_SOFTWAREPROCESSING | D3DUSAGE_WRITEONLY,
- VERTEX_BASE_FORMAT | ((m_shaders->enabled())
- ? D3DFVF_XYZW
- : D3DFVF_XYZRHW),
- D3DPOOL_DEFAULT, &m_vertexbuf, nullptr);
+ sizeof(vertex) * VERTEX_BUFFER_SIZE,
+ D3DUSAGE_DYNAMIC | D3DUSAGE_SOFTWAREPROCESSING | D3DUSAGE_WRITEONLY,
+ VERTEX_BASE_FORMAT | (m_shaders->enabled() ? D3DFVF_XYZW : D3DFVF_XYZRHW),
+ D3DPOOL_DEFAULT,
+ &m_vertexbuf,
+ nullptr);
if (FAILED(result))
{
osd_printf_error("Error creating vertex buffer (%08X)\n", (uint32_t)result);
@@ -921,9 +989,7 @@ int renderer_d3d9::device_create_resources()
// set the vertex format
result = m_device->SetFVF(
- (D3DFORMAT)(VERTEX_BASE_FORMAT | ((m_shaders->enabled())
- ? D3DFVF_XYZW
- : D3DFVF_XYZRHW)));
+ D3DFORMAT(VERTEX_BASE_FORMAT | (m_shaders->enabled() ? D3DFVF_XYZW : D3DFVF_XYZRHW)));
if (FAILED(result))
{
osd_printf_error("Error setting vertex format (%08X)\n", (uint32_t)result);
@@ -975,23 +1041,6 @@ int renderer_d3d9::device_create_resources()
renderer_d3d9::~renderer_d3d9()
{
device_delete();
-
- // todo: throws error when switching from full screen to window mode
- //if (m_shaders != nullptr)
- //{
- // // delete the HLSL interface
- // global_free(m_shaders);
- // m_shaders = nullptr;
- //}
-}
-
-void renderer_d3d9::exit()
-{
- if (d3dintf != nullptr)
- {
- d3dintf->d3dobj->Release();
- global_free(d3dintf);
- }
}
void renderer_d3d9::device_delete()
@@ -1001,18 +1050,10 @@ void renderer_d3d9::device_delete()
// we do not delete the HLSL interface here
- if (m_texture_manager != nullptr)
- {
- global_free(m_texture_manager);
- m_texture_manager = nullptr;
- }
+ m_texture_manager.reset();
// free the device itself
- if (m_device != nullptr)
- {
- m_device->Release();
- m_device = nullptr;
- }
+ m_device.Reset();
}
@@ -1022,22 +1063,14 @@ void renderer_d3d9::device_delete()
void renderer_d3d9::device_delete_resources()
{
- if (m_shaders != nullptr)
- {
+ if (m_shaders)
m_shaders->delete_resources();
- }
- if (m_texture_manager != nullptr)
- {
+ if (m_texture_manager)
m_texture_manager->delete_resources();
- }
// free the vertex buffer
- if (m_vertexbuf != nullptr)
- {
- m_vertexbuf->Release();
- m_vertexbuf = nullptr;
- }
+ m_vertexbuf.Reset();
}
@@ -1050,7 +1083,7 @@ bool renderer_d3d9::device_verify_caps()
bool success = true;
D3DCAPS9 caps;
- HRESULT result = d3dintf->d3dobj->GetDeviceCaps(m_adapter, D3DDEVTYPE_HAL, &caps);
+ HRESULT result = m_d3dobj->GetDeviceCaps(m_adapter, D3DDEVTYPE_HAL, &caps);
if (FAILED(result))
{
osd_printf_verbose("Direct3D: Error %08lX during GetDeviceCaps call\n", result);
@@ -1060,7 +1093,7 @@ bool renderer_d3d9::device_verify_caps()
if (caps.MaxPixelShader30InstructionSlots < 512)
{
osd_printf_verbose("Direct3D: Warning - Device does not support Pixel Shader 3.0, falling back to non-PS rendering\n");
- d3dintf->post_fx_available = false;
+ set_post_fx_unavailable();
}
// verify presentation capabilities
@@ -1115,7 +1148,7 @@ bool renderer_d3d9::device_verify_caps()
}
// verify texture formats
- result = d3dintf->d3dobj->CheckDeviceFormat(m_adapter, D3DDEVTYPE_HAL, m_pixformat, 0, D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8);
+ result = m_d3dobj->CheckDeviceFormat(m_adapter, D3DDEVTYPE_HAL, m_pixformat, 0, D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8);
if (FAILED(result))
{
osd_printf_error("Direct3D Error: Your graphics card does not support the A8R8G8B8 texture format.\n");
@@ -1191,7 +1224,7 @@ int renderer_d3d9::config_adapter_mode()
// get the identifier
D3DADAPTER_IDENTIFIER9 id;
- HRESULT result = d3dintf->d3dobj->GetAdapterIdentifier(m_adapter, 0, &id);
+ HRESULT result = m_d3dobj->GetAdapterIdentifier(m_adapter, 0, &id);
if (FAILED(result))
{
osd_printf_error("Error getting identifier for adapter #%d\n", m_adapter);
@@ -1201,22 +1234,20 @@ int renderer_d3d9::config_adapter_mode()
osd_printf_verbose("Direct3D: Configuring adapter #%d = %s\n", m_adapter, id.Description);
// get the current display mode
- result = d3dintf->d3dobj->GetAdapterDisplayMode(m_adapter, &m_origmode);
+ result = m_d3dobj->GetAdapterDisplayMode(m_adapter, &m_origmode);
if (FAILED(result))
{
osd_printf_error("Error getting mode for adapter #%d\n", m_adapter);
return 1;
}
- auto win = assert_window();
-
- // choose a resolution: window mode case
- if (!win->fullscreen() || !video_config.switchres || win->win_has_menu())
+ if (!window().fullscreen() || !video_config.switchres)
{
- RECT client;
+ // choose a resolution: window mode case
// bounds are from the window client rect
- GetClientRectExceptMenu(std::static_pointer_cast<win_window_info>(win)->platform_window(), &client, win->fullscreen());
+ RECT client;
+ GetClientRectExceptMenu(dynamic_cast<win_window_info &>(window()).platform_window(), &client, window().fullscreen());
m_width = client.right - client.left;
m_height = client.bottom - client.top;
@@ -1227,14 +1258,14 @@ int renderer_d3d9::config_adapter_mode()
// make sure it's a pixel format we can get behind
if (m_pixformat != D3DFMT_X1R5G5B5 && m_pixformat != D3DFMT_R5G6B5 && m_pixformat != D3DFMT_X8R8G8B8)
{
- osd_printf_error("Device %s currently in an unsupported mode\n", win->monitor()->devicename().c_str());
+ osd_printf_error("Device %s currently in an unsupported mode\n", window().monitor()->devicename());
return 1;
}
}
-
- // choose a resolution: full screen mode case
else
{
+ // choose a resolution: full screen mode case
+
// default to the current mode exactly
m_width = m_origmode.Width;
m_height = m_origmode.Height;
@@ -1247,10 +1278,10 @@ int renderer_d3d9::config_adapter_mode()
}
// see if we can handle the device type
- result = d3dintf->d3dobj->CheckDeviceType(m_adapter, D3DDEVTYPE_HAL, m_pixformat, m_pixformat, !win->fullscreen());
+ result = m_d3dobj->CheckDeviceType(m_adapter, D3DDEVTYPE_HAL, m_pixformat, m_pixformat, !window().fullscreen());
if (FAILED(result))
{
- osd_printf_error("Proposed video mode not supported on device %s\n", win->monitor()->devicename().c_str());
+ osd_printf_error("Proposed video mode not supported on device %s\n", window().monitor()->devicename());
return 1;
}
@@ -1264,18 +1295,16 @@ int renderer_d3d9::config_adapter_mode()
int renderer_d3d9::get_adapter_for_monitor()
{
- int maxadapter = d3dintf->d3dobj->GetAdapterCount();
-
- auto win = assert_window();
+ int maxadapter = m_d3dobj->GetAdapterCount();
// iterate over adapters until we error or find a match
for (int adapternum = 0; adapternum < maxadapter; adapternum++)
{
// get the monitor for this adapter
- HMONITOR curmonitor = d3dintf->d3dobj->GetAdapterMonitor(adapternum);
+ HMONITOR curmonitor = m_d3dobj->GetAdapterMonitor(adapternum);
// if we match the proposed monitor, this is it
- if (curmonitor == reinterpret_cast<HMONITOR>(win->monitor()->oshandle()))
+ if (curmonitor == reinterpret_cast<HMONITOR>(window().monitor()->oshandle()))
{
return adapternum;
}
@@ -1296,10 +1325,8 @@ void renderer_d3d9::pick_best_mode()
int32_t minwidth, minheight;
float best_score = 0.0f;
- auto win = assert_window();
-
// determine the refresh rate of the primary screen
- const screen_device *primary_screen = screen_device_iterator(win->machine().root_device()).first();
+ const screen_device *primary_screen = screen_device_enumerator(window().machine().root_device()).first();
if (primary_screen != nullptr)
{
target_refresh = ATTOSECONDS_TO_HZ(primary_screen->refresh_attoseconds());
@@ -1309,14 +1336,14 @@ void renderer_d3d9::pick_best_mode()
// note: technically we should not be calling this from an alternate window
// thread; however, it is only done during init time, and the init code on
// the main thread is waiting for us to finish, so it is safe to do so here
- win->target()->compute_minimum_size(minwidth, minheight);
+ window().target()->compute_minimum_size(minwidth, minheight);
// use those as the target for now
int32_t target_width = minwidth;
int32_t target_height = minheight;
// determine the maximum number of modes
- int maxmodes = d3dintf->d3dobj->GetAdapterModeCount(m_adapter, D3DFMT_X8R8G8B8);
+ int maxmodes = m_d3dobj->GetAdapterModeCount(m_adapter, D3DFMT_X8R8G8B8);
// enumerate all the video modes and find the best match
osd_printf_verbose("Direct3D: Selecting video mode...\n");
@@ -1324,7 +1351,7 @@ void renderer_d3d9::pick_best_mode()
{
// check this mode
D3DDISPLAYMODE mode;
- HRESULT result = d3dintf->d3dobj->EnumAdapterModes(m_adapter, D3DFMT_X8R8G8B8, modenum, &mode);
+ HRESULT result = m_d3dobj->EnumAdapterModes(m_adapter, D3DFMT_X8R8G8B8, modenum, &mode);
if (FAILED(result))
break;
@@ -1344,7 +1371,7 @@ void renderer_d3d9::pick_best_mode()
size_score *= 0.1f;
// if we're looking for a particular mode, that's a winner
- if (mode.Width == win->m_win_config.width && mode.Height == win->m_win_config.height)
+ if (mode.Width == window().m_win_config.width && mode.Height == window().m_win_config.height)
size_score = 2.0f;
// compute refresh score
@@ -1355,7 +1382,7 @@ void renderer_d3d9::pick_best_mode()
refresh_score *= 0.1f;
// if we're looking for a particular refresh, make sure it matches
- if (mode.RefreshRate == win->m_win_config.refresh)
+ if (mode.RefreshRate == window().m_win_config.refresh)
refresh_score = 2.0f;
// weight size and refresh equally
@@ -1382,33 +1409,32 @@ void renderer_d3d9::pick_best_mode()
bool renderer_d3d9::update_window_size()
{
- auto win = assert_window();
-
// get the current window bounds
+ auto &win = dynamic_cast<win_window_info &>(window());
RECT client;
- GetClientRectExceptMenu(std::static_pointer_cast<win_window_info>(win)->platform_window(), &client, win->fullscreen());
+ GetClientRectExceptMenu(win.platform_window(), &client, window().fullscreen());
// if we have a device and matching width/height, nothing to do
- if (m_device != nullptr && rect_width(&client) == m_width && rect_height(&client) == m_height)
+ if (m_device && rect_width(&client) == m_width && rect_height(&client) == m_height)
{
// clear out any pending resizing if the area didn't change
- if (win->m_resize_state == RESIZE_STATE_PENDING)
- win->m_resize_state = RESIZE_STATE_NORMAL;
+ if (win.m_resize_state == win_window_info::RESIZE_STATE_PENDING)
+ win.m_resize_state = win_window_info::RESIZE_STATE_NORMAL;
return false;
}
// if we're in the middle of resizing, leave it alone as well
- if (win->m_resize_state == RESIZE_STATE_RESIZING)
+ if (win.m_resize_state == win_window_info::RESIZE_STATE_RESIZING)
return false;
// set the new bounds and create the device again
m_width = rect_width(&client);
m_height = rect_height(&client);
- if (device_create(std::static_pointer_cast<win_window_info>(win->main_window())->platform_window()))
+ if (device_create(win.main_window()->platform_window()))
return false;
// reset the resize state to normal, and indicate we made a change
- win->m_resize_state = RESIZE_STATE_NORMAL;
+ win.m_resize_state = win_window_info::RESIZE_STATE_NORMAL;
return true;
}
@@ -1419,8 +1445,6 @@ bool renderer_d3d9::update_window_size()
void renderer_d3d9::batch_vectors(int vector_count)
{
- auto win = assert_window();
-
float quad_width = 0.0f;
float quad_height = 0.0f;
float target_width = 0.0f;
@@ -1430,9 +1454,10 @@ void renderer_d3d9::batch_vectors(int vector_count)
int triangle_count = vector_count * 2;
m_vectorbatch = mesh_alloc(vertex_count);
m_batchindex = 0;
+ uint32_t tint = 0xffffffff;
uint32_t cached_flags = 0;
- for (render_primitive &prim : *win->m_primlist)
+ for (render_primitive &prim : *window().m_primlist)
{
switch (prim.type)
{
@@ -1441,6 +1466,12 @@ void renderer_d3d9::batch_vectors(int vector_count)
{
batch_vector(prim);
cached_flags = prim.flags;
+
+ const uint8_t a = (uint8_t)std::round(prim.color.a * 255);
+ const uint8_t r = (uint8_t)std::round(prim.color.r * 255);
+ const uint8_t g = (uint8_t)std::round(prim.color.g * 255);
+ const uint8_t b = (uint8_t)std::round(prim.color.b * 255);
+ tint = (a << 24) | (b << 16) | (g << 8) | r;
}
break;
@@ -1451,6 +1482,12 @@ void renderer_d3d9::batch_vectors(int vector_count)
quad_height = prim.get_quad_height();
target_width = prim.get_full_quad_width();
target_height = prim.get_full_quad_height();
+
+ const uint8_t a = (uint8_t)std::round(prim.color.a * 255);
+ const uint8_t r = (uint8_t)std::round(prim.color.r * 255);
+ const uint8_t g = (uint8_t)std::round(prim.color.g * 255);
+ const uint8_t b = (uint8_t)std::round(prim.color.b * 255);
+ tint = (a << 24) | (b << 16) | (g << 8) | r;
}
break;
@@ -1464,15 +1501,15 @@ void renderer_d3d9::batch_vectors(int vector_count)
if (m_shaders->enabled())
{
bool orientation_swap_xy =
- (win->machine().system().flags & ORIENTATION_SWAP_XY) == ORIENTATION_SWAP_XY;
+ (window().machine().system().flags & ORIENTATION_SWAP_XY) == ORIENTATION_SWAP_XY;
bool rotation_swap_xy =
- (win->target()->orientation() & ORIENTATION_SWAP_XY) == ORIENTATION_SWAP_XY;
+ (window().target()->orientation() & ORIENTATION_SWAP_XY) == ORIENTATION_SWAP_XY;
bool swap_xy = orientation_swap_xy ^ rotation_swap_xy;
- bool rotation_0 = win->target()->orientation() == ROT0;
- bool rotation_90 = win->target()->orientation() == ROT90;
- bool rotation_180 = win->target()->orientation() == ROT180;
- bool rotation_270 = win->target()->orientation() == ROT270;
+ bool rotation_0 = window().target()->orientation() == ROT0;
+ bool rotation_90 = window().target()->orientation() == ROT90;
+ bool rotation_180 = window().target()->orientation() == ROT180;
+ bool rotation_270 = window().target()->orientation() == ROT270;
bool flip_x =
((rotation_0 || rotation_270) && orientation_swap_xy) ||
((rotation_180 || rotation_270) && !orientation_swap_xy);
@@ -1480,8 +1517,8 @@ void renderer_d3d9::batch_vectors(int vector_count)
((rotation_0 || rotation_90) && orientation_swap_xy) ||
((rotation_180 || rotation_90) && !orientation_swap_xy);
- float screen_width = float(this->get_width());
- float screen_height = float(this->get_height());
+ auto screen_width = float(this->get_width());
+ auto screen_height = float(this->get_height());
float half_screen_width = screen_width * 0.5f;
float half_screen_height = screen_height * 0.5f;
float screen_swap_x_factor = 1.0f / screen_width * screen_height;
@@ -1528,7 +1565,7 @@ void renderer_d3d9::batch_vectors(int vector_count)
}
// now add a polygon entry
- m_poly[m_numpolys].init(D3DPT_TRIANGLELIST, triangle_count, vertex_count, cached_flags, nullptr, D3DTOP_MODULATE, quad_width, quad_height);
+ m_poly[m_numpolys].init(D3DPT_TRIANGLELIST, triangle_count, vertex_count, cached_flags, nullptr, D3DTOP_MODULATE, quad_width, quad_height, tint);
m_numpolys++;
}
@@ -1541,15 +1578,10 @@ void renderer_d3d9::batch_vector(const render_primitive &prim)
}
// compute the effective width based on the direction of the line
- float effwidth = prim.width;
- if (effwidth < 2.0f)
- {
- effwidth = 2.0f;
- }
+ float effwidth = std::max(prim.width, 2.0f);
// determine the bounds of a quad to draw this line
- render_bounds b0, b1;
- render_line_to_quad(&prim.bounds, effwidth, effwidth, &b0, &b1);
+ auto [b0, b1] = render_line_to_quad(prim.bounds, effwidth, effwidth);
float lx = b1.x1 - b0.x1;
float ly = b1.y1 - b0.y1;
@@ -1610,10 +1642,10 @@ void renderer_d3d9::batch_vector(const render_primitive &prim)
}
// determine the color of the line
- int32_t r = (int32_t)(prim.color.r * 255.0f);
- int32_t g = (int32_t)(prim.color.g * 255.0f);
- int32_t b = (int32_t)(prim.color.b * 255.0f);
- int32_t a = (int32_t)(prim.color.a * 255.0f);
+ auto r = (int32_t)(prim.color.r * 255.0f);
+ auto g = (int32_t)(prim.color.g * 255.0f);
+ auto b = (int32_t)(prim.color.b * 255.0f);
+ auto a = (int32_t)(prim.color.a * 255.0f);
DWORD color = D3DCOLOR_ARGB(a, r, g, b);
// set the color, Z parameters to standard values
@@ -1648,15 +1680,10 @@ void renderer_d3d9::draw_line(const render_primitive &prim)
}
// compute the effective width based on the direction of the line
- float effwidth = prim.width;
- if (effwidth < 1.0f)
- {
- effwidth = 1.0f;
- }
+ float effwidth = std::max(prim.width, 1.0f);
// determine the bounds of a quad to draw this line
- render_bounds b0, b1;
- render_line_to_quad(&prim.bounds, effwidth, 0.0f, &b0, &b1);
+ auto [b0, b1] = render_line_to_quad(prim.bounds, effwidth, 0.0f);
vertex[0].x = b0.x0;
vertex[0].y = b0.y0;
@@ -1680,10 +1707,10 @@ void renderer_d3d9::draw_line(const render_primitive &prim)
vertex[3].v0 = stop.c.y;
// determine the color of the line
- int32_t r = (int32_t)(prim.color.r * 255.0f);
- int32_t g = (int32_t)(prim.color.g * 255.0f);
- int32_t b = (int32_t)(prim.color.b * 255.0f);
- int32_t a = (int32_t)(prim.color.a * 255.0f);
+ auto r = (int32_t)std::round(prim.color.r * 255.0f);
+ auto g = (int32_t)std::round(prim.color.g * 255.0f);
+ auto b = (int32_t)std::round(prim.color.b * 255.0f);
+ auto a = (int32_t)std::round(prim.color.a * 255.0f);
DWORD color = D3DCOLOR_ARGB(a, r, g, b);
// set the color, Z parameters to standard values
@@ -1695,7 +1722,7 @@ void renderer_d3d9::draw_line(const render_primitive &prim)
}
// now add a polygon entry
- m_poly[m_numpolys].init(D3DPT_TRIANGLESTRIP, 2, 4, prim.flags, nullptr, D3DTOP_MODULATE, 0.0f, 0.0f);
+ m_poly[m_numpolys].init(D3DPT_TRIANGLESTRIP, 2, 4, prim.flags, nullptr, D3DTOP_MODULATE, 0.0f, 0.0f, (uint32_t)color);
m_numpolys++;
}
@@ -1749,10 +1776,10 @@ void renderer_d3d9::draw_quad(const render_primitive &prim)
}
// determine the color, allowing for over modulation
- int32_t r = (int32_t)(prim.color.r * 255.0f);
- int32_t g = (int32_t)(prim.color.g * 255.0f);
- int32_t b = (int32_t)(prim.color.b * 255.0f);
- int32_t a = (int32_t)(prim.color.a * 255.0f);
+ auto r = (int32_t)std::round(prim.color.r * 255.0f);
+ auto g = (int32_t)std::round(prim.color.g * 255.0f);
+ auto b = (int32_t)std::round(prim.color.b * 255.0f);
+ auto a = (int32_t)std::round(prim.color.a * 255.0f);
DWORD color = D3DCOLOR_ARGB(a, r, g, b);
// adjust half pixel X/Y offset, set the color, Z parameters to standard values
@@ -1766,7 +1793,7 @@ void renderer_d3d9::draw_quad(const render_primitive &prim)
}
// now add a polygon entry
- m_poly[m_numpolys].init(D3DPT_TRIANGLESTRIP, 2, 4, prim.flags, texture, D3DTOP_MODULATE, quad_width, quad_height);
+ m_poly[m_numpolys].init(D3DPT_TRIANGLESTRIP, 2, 4, prim.flags, texture, D3DTOP_MODULATE, quad_width, quad_height, (uint32_t)color);
m_numpolys++;
}
@@ -1826,7 +1853,7 @@ void renderer_d3d9::primitive_flush_pending()
m_lockedbuf = nullptr;
// set the stream
- result = m_device->SetStreamSource(0, m_vertexbuf, 0, sizeof(vertex));
+ result = m_device->SetStreamSource(0, m_vertexbuf.Get(), 0, sizeof(vertex));
if (FAILED(result))
osd_printf_verbose("Direct3D: Error %08lX during device SetStreamSource call\n", result);
@@ -1854,9 +1881,17 @@ void renderer_d3d9::primitive_flush_pending()
newfilter = FALSE;
if (PRIMFLAG_GET_SCREENTEX(flags))
newfilter = video_config.filter;
- set_filter(newfilter);
- set_wrap(PRIMFLAG_GET_TEXWRAP(flags) ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP);
- set_modmode(m_poly[polynum].modmode());
+
+ if (m_shaders->enabled())
+ {
+ m_shaders->set_filter(newfilter);
+ }
+ else
+ {
+ set_filter(newfilter);
+ set_wrap(PRIMFLAG_GET_TEXWRAP(flags) ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP);
+ set_modmode(m_poly[polynum].modmode());
+ }
}
if (vertnum + m_poly[polynum].numverts() > m_numverts)
@@ -1869,9 +1904,6 @@ void renderer_d3d9::primitive_flush_pending()
if(m_shaders->enabled())
{
- // reset blend mode (handled by shader passes)
- set_blendmode(BLENDMODE_NONE);
-
m_shaders->render_quad(&m_poly[polynum], vertnum);
}
else
@@ -1924,19 +1956,6 @@ void renderer_d3d9::set_sliders_dirty()
texture_info::~texture_info()
{
- if (m_d3dfinaltex != nullptr)
- {
- if (m_d3dtex == m_d3dfinaltex)
- m_d3dtex = nullptr;
-
- m_d3dfinaltex->Release();
- }
-
- if (m_d3dtex != nullptr)
- m_d3dtex->Release();
-
- if (m_d3dsurface != nullptr)
- m_d3dsurface->Release();
}
@@ -1944,181 +1963,117 @@ texture_info::~texture_info()
// texture_info constructor
//============================================================
-texture_info::texture_info(d3d_texture_manager *manager, const render_texinfo* texsource, int prescale, uint32_t flags)
+texture_info::texture_info(d3d_texture_manager &manager, const render_texinfo* texsource, int prescale, uint32_t flags)
+ : m_texture_manager(manager)
+ , m_renderer(manager.get_d3d())
+ , m_hash(manager.texture_compute_hash(texsource, flags))
+ , m_flags(flags)
+ , m_texinfo(*texsource)
+ , m_type(!PRIMFLAG_GET_SCREENTEX(flags) ? TEXTURE_TYPE_PLAIN : TEXTURE_TYPE_DYNAMIC) // required to compute texture size
+ , m_xprescale(PRIMFLAG_GET_SCREENTEX(flags) ? prescale : 1)
+ , m_yprescale(PRIMFLAG_GET_SCREENTEX(flags) ? prescale : 1)
{
- HRESULT result;
-
- // fill in the core data
- m_texture_manager = manager;
- m_renderer = m_texture_manager->get_d3d();
- m_hash = m_texture_manager->texture_compute_hash(texsource, flags);
- m_flags = flags;
- m_texinfo = *texsource;
- m_xprescale = prescale;
- m_yprescale = prescale;
-
- m_d3dtex = nullptr;
- m_d3dsurface = nullptr;
- m_d3dfinaltex = nullptr;
-
- // determine texture type, required to compute texture size
- if (!PRIMFLAG_GET_SCREENTEX(flags))
- {
- m_type = TEXTURE_TYPE_PLAIN;
- }
- else
- {
- if ((m_xprescale == 1 && m_yprescale == 1) || m_renderer->get_shaders()->enabled())
- {
- m_type = m_texture_manager->is_dynamic_supported() ? TEXTURE_TYPE_DYNAMIC : TEXTURE_TYPE_PLAIN;
- }
- else
- {
- if (m_texture_manager->is_stretch_supported() && PRIMFLAG_GET_TEXFORMAT(flags) != TEXFORMAT_YUY16)
- {
- m_type = TEXTURE_TYPE_SURFACE;
- }
- else
- {
- m_type = m_texture_manager->is_dynamic_supported() ? TEXTURE_TYPE_DYNAMIC : TEXTURE_TYPE_PLAIN;
- }
- }
- }
-
// compute the size
compute_size(texsource->width, texsource->height);
- // non-screen textures are easy
if (!PRIMFLAG_GET_SCREENTEX(flags))
{
+ // non-screen textures are easy
assert(PRIMFLAG_TEXFORMAT(flags) != TEXFORMAT_YUY16);
- result = m_renderer->get_device()->CreateTexture(m_rawdims.c.x, m_rawdims.c.y, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_d3dtex, nullptr);
+ const HRESULT result = m_renderer.get_device()->CreateTexture(m_rawdims.c.x, m_rawdims.c.y, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_d3dtex, nullptr);
if (FAILED(result))
goto error;
+
m_d3dfinaltex = m_d3dtex;
}
-
- // screen textures are allocated differently
else
{
- D3DFORMAT format;
- DWORD usage = m_texture_manager->is_dynamic_supported() ? D3DUSAGE_DYNAMIC : 0;
- D3DPOOL pool = m_texture_manager->is_dynamic_supported() ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
- int maxdim = std::max(m_renderer->get_presentation()->BackBufferWidth, m_renderer->get_presentation()->BackBufferHeight);
+ // screen textures are allocated differently
// pick the format
+ const DWORD usage = D3DUSAGE_DYNAMIC;
+ const D3DPOOL pool = D3DPOOL_DEFAULT;
+ D3DFORMAT format;
if (PRIMFLAG_GET_TEXFORMAT(flags) == TEXFORMAT_YUY16)
- {
- format = m_texture_manager->get_yuv_format();
- }
+ format = m_texture_manager.get_yuv_format();
else if (PRIMFLAG_GET_TEXFORMAT(flags) == TEXFORMAT_ARGB32)
- {
format = D3DFMT_A8R8G8B8;
- }
else
- {
- format = m_renderer->get_screen_format();
- }
+ format = m_renderer.get_screen_format();
// don't prescale above screen size
- while (m_xprescale > 1 && m_rawdims.c.x * m_xprescale >= 2 * maxdim)
- {
+ const int maxdim = std::max(
+ m_renderer.get_presentation()->BackBufferWidth,
+ m_renderer.get_presentation()->BackBufferHeight);
+
+ while ((m_xprescale > 1) && ((m_rawdims.c.x * m_xprescale) >= (2 * maxdim)))
m_xprescale--;
- }
- while (m_xprescale > 1 && m_rawdims.c.x * m_xprescale > manager->get_max_texture_width())
- {
+ while ((m_xprescale > 1) && ((m_rawdims.c.x * m_xprescale) > manager.get_max_texture_width()))
m_xprescale--;
- }
- while (m_yprescale > 1 && m_rawdims.c.y * m_yprescale >= 2 * maxdim)
- {
+
+ while ((m_yprescale > 1) && ((m_rawdims.c.y * m_yprescale) >= (2 * maxdim)))
m_yprescale--;
- }
- while (m_yprescale > 1 && m_rawdims.c.y * m_yprescale > manager->get_max_texture_height())
- {
+ while ((m_yprescale > 1) && ((m_rawdims.c.y * m_yprescale) > manager.get_max_texture_height()))
m_yprescale--;
- }
-
- auto win = m_renderer->assert_window();
- int prescale = win->prescale();
- if (m_xprescale != prescale || m_yprescale != prescale)
- {
+ const int prescale = m_renderer.window().prescale();
+ if ((m_xprescale != prescale) || (m_yprescale != prescale))
osd_printf_verbose("Direct3D: adjusting prescale from %dx%d to %dx%d\n", prescale, prescale, m_xprescale, m_yprescale);
- }
// loop until we allocate something or error
+ HRESULT result;
for (int attempt = 0; attempt < 2; attempt++)
{
- // second attempt is always 1:1
- if (attempt == 1)
+ if ((m_xprescale == 1) && (m_yprescale == 1))
{
- m_xprescale = m_yprescale = 1;
- }
-
- // screen textures with no prescaling are pretty easy
- if (m_xprescale == 1 && m_yprescale == 1)
- {
- result = m_renderer->get_device()->CreateTexture(m_rawdims.c.x, m_rawdims.c.y, 1, usage, format, pool, &m_d3dtex, nullptr);
+ // screen textures with no prescaling are pretty easy
+ result = m_renderer.get_device()->CreateTexture(m_rawdims.c.x, m_rawdims.c.y, 1, usage, format, pool, &m_d3dtex, nullptr);
if (result == D3D_OK)
{
m_d3dfinaltex = m_d3dtex;
break;
}
}
- // screen textures with prescaling require two allocations
else
{
- // use an offscreen plain surface for stretching if supported
- // (won't work for YUY textures)
- if (m_texture_manager->is_stretch_supported() && PRIMFLAG_GET_TEXFORMAT(flags) != TEXFORMAT_YUY16)
- {
- result = m_renderer->get_device()->CreateOffscreenPlainSurface(m_rawdims.c.x, m_rawdims.c.y, format, D3DPOOL_DEFAULT, &m_d3dsurface, nullptr);
- if (FAILED(result))
- {
- continue;
- }
- }
- // otherwise, we allocate a dynamic texture for the source
- else
+ // screen textures with prescaling require two allocations
+ result = m_renderer.get_device()->CreateTexture(m_rawdims.c.x, m_rawdims.c.y, 1, usage, format, pool, &m_d3dtex, nullptr);
+ if (result == D3D_OK)
{
- result = m_renderer->get_device()->CreateTexture(m_rawdims.c.x, m_rawdims.c.y, 1, usage, format, pool, &m_d3dtex, nullptr);
- if (FAILED(result))
- {
- continue;
- }
- }
+ // for the target surface, we allocate a render target texture
+ const int scwidth = m_rawdims.c.x * m_xprescale;
+ const int scheight = m_rawdims.c.y * m_yprescale;
- // for the target surface, we allocate a render target texture
- int scwidth = m_rawdims.c.x * m_xprescale;
- int scheight = m_rawdims.c.y * m_yprescale;
+ // target surfaces typically cannot be YCbCr, so we always pick RGB in that case
+ const D3DFORMAT finalfmt = (format != m_texture_manager.get_yuv_format()) ? format : D3DFMT_A8R8G8B8;
- // target surfaces typically cannot be YCbCr, so we always pick RGB in that case
- D3DFORMAT finalfmt = (format != m_texture_manager->get_yuv_format()) ? format : D3DFMT_A8R8G8B8;
+ result = m_renderer.get_device()->CreateTexture(scwidth, scheight, 1, D3DUSAGE_RENDERTARGET, finalfmt, D3DPOOL_DEFAULT, &m_d3dfinaltex, nullptr);
+ if (result == D3D_OK)
+ break;
- result = m_renderer->get_device()->CreateTexture(scwidth, scheight, 1, D3DUSAGE_RENDERTARGET, finalfmt, D3DPOOL_DEFAULT, &m_d3dfinaltex, nullptr);
- if (result == D3D_OK)
- {
- break;
+ m_d3dtex.Reset();
}
-
- m_d3dtex->Release();
- m_d3dtex = nullptr;
}
+
+ // second attempt is always 1:1
+ m_xprescale = m_yprescale = 1;
}
+ if (FAILED(result))
+ goto error;
}
// copy the data to the texture
+ assert(m_d3dtex);
+ assert(m_d3dfinaltex);
set_data(texsource, flags);
return;
error:
- d3dintf->post_fx_available = false;
+ m_renderer.set_post_fx_unavailable();
osd_printf_error("Direct3D: Critical warning: A texture failed to allocate. Expect things to get bad quickly.\n");
- if (m_d3dsurface != nullptr)
- m_d3dsurface->Release();
- if (m_d3dtex != nullptr)
- m_d3dtex->Release();
+ m_d3dsurface.Reset();
+ m_d3dtex.Reset();
}
@@ -2132,11 +2087,11 @@ void texture_info::compute_size_subroutine(int texwidth, int texheight, int* p_w
int finalwidth = texwidth;
// adjust the aspect ratio if we need to
- while (finalwidth < finalheight && finalheight / finalwidth > m_texture_manager->get_max_texture_aspect())
+ while (finalwidth < finalheight && finalheight / finalwidth > m_texture_manager.get_max_texture_aspect())
{
finalwidth *= 2;
}
- while (finalheight < finalwidth && finalwidth / finalheight > m_texture_manager->get_max_texture_aspect())
+ while (finalheight < finalwidth && finalwidth / finalheight > m_texture_manager.get_max_texture_aspect())
{
finalheight *= 2;
}
@@ -2158,7 +2113,7 @@ void texture_info::compute_size(int texwidth, int texheight)
m_xborderpix = 0;
m_yborderpix = 0;
- bool shaders_enabled = m_renderer->get_shaders()->enabled();
+ bool shaders_enabled = m_renderer.get_shaders()->enabled();
bool wrap_texture = (m_flags & PRIMFLAG_TEXWRAP_MASK) == PRIMFLAG_TEXWRAP_MASK;
// skip border when shaders are enabled
@@ -2168,8 +2123,8 @@ void texture_info::compute_size(int texwidth, int texheight)
if (!wrap_texture)
{
// note we need 2 pixels in X for YUY textures
- m_xborderpix = (PRIMFLAG_GET_TEXFORMAT(m_flags) == TEXFORMAT_YUY16) ? 2 : 1;
- m_yborderpix = 1;
+ //m_xborderpix = (PRIMFLAG_GET_TEXFORMAT(m_flags) == TEXFORMAT_YUY16) ? 2 : 1;
+ //m_yborderpix = 1;
}
}
@@ -2182,7 +2137,7 @@ void texture_info::compute_size(int texwidth, int texheight)
compute_size_subroutine(finalwidth, finalheight, &finalwidth, &finalheight);
// if we added pixels for the border, and that just barely pushed us over, take it back
- if (finalwidth > m_texture_manager->get_max_texture_width() || finalheight > m_texture_manager->get_max_texture_height())
+ if (finalwidth > m_texture_manager.get_max_texture_width() || finalheight > m_texture_manager.get_max_texture_height())
{
finalheight = texheight;
finalwidth = texwidth;
@@ -2195,10 +2150,18 @@ void texture_info::compute_size(int texwidth, int texheight)
}
// if we're above the max width/height, do what?
- if (finalwidth > m_texture_manager->get_max_texture_width() || finalheight > m_texture_manager->get_max_texture_height())
+ if (finalwidth > m_texture_manager.get_max_texture_width() || finalheight > m_texture_manager.get_max_texture_height())
{
static bool printed = false;
- if (!printed) osd_printf_warning("Texture too big! (wanted: %dx%d, max is %dx%d)\n", finalwidth, finalheight, (int)m_texture_manager->get_max_texture_width(), (int)m_texture_manager->get_max_texture_height());
+ if (!printed)
+ {
+ osd_printf_warning(
+ "Texture too big! (wanted: %dx%d, max is %dx%d)\n",
+ finalwidth,
+ finalheight,
+ m_texture_manager.get_max_texture_width(),
+ m_texture_manager.get_max_texture_height());
+ }
printed = true;
}
@@ -2451,9 +2414,9 @@ void texture_info::set_data(const render_texinfo *texsource, uint32_t flags)
break;
case TEXFORMAT_YUY16:
- if (m_texture_manager->get_yuv_format() == D3DFMT_YUY2)
+ if (m_texture_manager.get_yuv_format() == D3DFMT_YUY2)
copyline_yuy16_to_yuy2((uint16_t *)dst, (uint16_t *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette);
- else if (m_texture_manager->get_yuv_format() == D3DFMT_UYVY)
+ else if (m_texture_manager.get_yuv_format() == D3DFMT_UYVY)
copyline_yuy16_to_uyvy((uint16_t *)dst, (uint16_t *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette);
else
copyline_yuy16_to_argb((uint32_t *)dst, (uint16_t *)texsource->base + srcy * texsource->rowpixels, texsource->width, texsource->palette);
@@ -2488,132 +2451,109 @@ void texture_info::set_data(const render_texinfo *texsource, uint32_t flags)
void texture_info::prescale()
{
- IDirect3DSurface9 *scale_surface;
- HRESULT result;
- int i;
-
// if we don't need to, just skip it
- if (m_d3dtex == m_d3dfinaltex)
+ if (m_d3dtex.Get() == m_d3dfinaltex.Get())
+ {
+ assert(m_xprescale == 1);
+ assert(m_yprescale == 1);
return;
+ }
+
+ assert(m_d3dtex);
+ assert((m_xprescale > 1) || (m_yprescale > 1));
+ HRESULT result;
// for all cases, we need to get the surface of the render target
+ Microsoft::WRL::ComPtr<IDirect3DSurface9> scale_surface;
result = m_d3dfinaltex->GetSurfaceLevel(0, &scale_surface);
if (FAILED(result))
osd_printf_verbose("Direct3D: Error %08lX during texture GetSurfaceLevel call\n", result);
// if we have an offscreen plain surface, we can just StretchRect to it
- if (m_type == TEXTURE_TYPE_SURFACE)
- {
- assert(m_d3dsurface != nullptr);
- // set the source bounds
- RECT source;
- source.left = source.top = 0;
- source.right = m_texinfo.width + 2 * m_xborderpix;
- source.bottom = m_texinfo.height + 2 * m_yborderpix;
+ // first remember the original render target and set the new one
+ Microsoft::WRL::ComPtr<IDirect3DSurface9> backbuffer;
+ result = m_renderer.get_device()->GetRenderTarget(0, &backbuffer);
+ if (FAILED(result))
+ osd_printf_verbose("Direct3D: Error %08lX during device GetRenderTarget call\n", result);
+ result = m_renderer.get_device()->SetRenderTarget(0, scale_surface.Get());
+ if (FAILED(result))
+ osd_printf_verbose("Direct3D: Error %08lX during device SetRenderTarget call 1\n", result);
+ m_renderer.reset_render_states();
- // set the target bounds
- RECT dest;
- dest = source;
- dest.right *= m_xprescale;
- dest.bottom *= m_yprescale;
+ // start the scene
+ result = m_renderer.get_device()->BeginScene();
+ if (FAILED(result))
+ osd_printf_verbose("Direct3D: Error %08lX during device BeginScene call\n", result);
- // do the stretchrect
- result = m_renderer->get_device()->StretchRect(m_d3dsurface, &source, scale_surface, &dest, D3DTEXF_POINT);
- if (FAILED(result))
- osd_printf_verbose("Direct3D: Error %08lX during device stretct_rect call\n", result);
- }
+ // configure the rendering pipeline
+ m_renderer.set_filter(FALSE);
+ m_renderer.set_blendmode(BLENDMODE_NONE);
+ result = m_renderer.get_device()->SetTexture(0, m_d3dtex.Get());
+ if (FAILED(result))
+ osd_printf_verbose("Direct3D: Error %08lX during device SetTexture call\n", result);
- // if we are using a texture render target, we need to do more preparations
- else
+ // lock the vertex buffer
+ vertex *lockedbuf;
+ result = m_renderer.get_vertex_buffer()->Lock(0, 0, (VOID **)&lockedbuf, D3DLOCK_DISCARD);
+ if (FAILED(result))
+ osd_printf_verbose("Direct3D: Error %08lX during vertex buffer lock call\n", result);
+
+ // configure the X/Y coordinates on the target surface
+ lockedbuf[0].x = -0.5f;
+ lockedbuf[0].y = -0.5f;
+ lockedbuf[1].x = (float)((m_texinfo.width + 2 * m_xborderpix) * m_xprescale) - 0.5f;
+ lockedbuf[1].y = -0.5f;
+ lockedbuf[2].x = -0.5f;
+ lockedbuf[2].y = (float)((m_texinfo.height + 2 * m_yborderpix) * m_yprescale) - 0.5f;
+ lockedbuf[3].x = (float)((m_texinfo.width + 2 * m_xborderpix) * m_xprescale) - 0.5f;
+ lockedbuf[3].y = (float)((m_texinfo.height + 2 * m_yborderpix) * m_yprescale) - 0.5f;
+
+ // configure the U/V coordintes on the source texture
+ lockedbuf[0].u0 = 0.0f;
+ lockedbuf[0].v0 = 0.0f;
+ lockedbuf[1].u0 = (float)(m_texinfo.width + 2 * m_xborderpix) / (float)m_rawdims.c.x;
+ lockedbuf[1].v0 = 0.0f;
+ lockedbuf[2].u0 = 0.0f;
+ lockedbuf[2].v0 = (float)(m_texinfo.height + 2 * m_yborderpix) / (float)m_rawdims.c.y;
+ lockedbuf[3].u0 = (float)(m_texinfo.width + 2 * m_xborderpix) / (float)m_rawdims.c.x;
+ lockedbuf[3].v0 = (float)(m_texinfo.height + 2 * m_yborderpix) / (float)m_rawdims.c.y;
+
+ // reset the remaining vertex parameters
+ for (int i = 0; i < 4; i++)
{
- IDirect3DSurface9 *backbuffer;
-
- assert(m_d3dtex != nullptr);
-
- // first remember the original render target and set the new one
- result = m_renderer->get_device()->GetRenderTarget(0, &backbuffer);
- if (FAILED(result))
- osd_printf_verbose("Direct3D: Error %08lX during device GetRenderTarget call\n", result);
- result = m_renderer->get_device()->SetRenderTarget(0, scale_surface);
- if (FAILED(result))
- osd_printf_verbose("Direct3D: Error %08lX during device SetRenderTarget call 1\n", result);
- m_renderer->reset_render_states();
-
- // start the scene
- result = m_renderer->get_device()->BeginScene();
- if (FAILED(result))
- osd_printf_verbose("Direct3D: Error %08lX during device BeginScene call\n", result);
-
- // configure the rendering pipeline
- m_renderer->set_filter(FALSE);
- m_renderer->set_blendmode(BLENDMODE_NONE);
- result = m_renderer->get_device()->SetTexture(0, m_d3dtex);
- if (FAILED(result))
- osd_printf_verbose("Direct3D: Error %08lX during device SetTexture call\n", result);
-
- // lock the vertex buffer
- vertex *lockedbuf;
- result = m_renderer->get_vertex_buffer()->Lock(0, 0, (VOID **)&lockedbuf, D3DLOCK_DISCARD);
- if (FAILED(result))
- osd_printf_verbose("Direct3D: Error %08lX during vertex buffer lock call\n", result);
-
- // configure the X/Y coordinates on the target surface
- lockedbuf[0].x = -0.5f;
- lockedbuf[0].y = -0.5f;
- lockedbuf[1].x = (float)((m_texinfo.width + 2 * m_xborderpix) * m_xprescale) - 0.5f;
- lockedbuf[1].y = -0.5f;
- lockedbuf[2].x = -0.5f;
- lockedbuf[2].y = (float)((m_texinfo.height + 2 * m_yborderpix) * m_yprescale) - 0.5f;
- lockedbuf[3].x = (float)((m_texinfo.width + 2 * m_xborderpix) * m_xprescale) - 0.5f;
- lockedbuf[3].y = (float)((m_texinfo.height + 2 * m_yborderpix) * m_yprescale) - 0.5f;
-
- // configure the U/V coordintes on the source texture
- lockedbuf[0].u0 = 0.0f;
- lockedbuf[0].v0 = 0.0f;
- lockedbuf[1].u0 = (float)(m_texinfo.width + 2 * m_xborderpix) / (float)m_rawdims.c.x;
- lockedbuf[1].v0 = 0.0f;
- lockedbuf[2].u0 = 0.0f;
- lockedbuf[2].v0 = (float)(m_texinfo.height + 2 * m_yborderpix) / (float)m_rawdims.c.y;
- lockedbuf[3].u0 = (float)(m_texinfo.width + 2 * m_xborderpix) / (float)m_rawdims.c.x;
- lockedbuf[3].v0 = (float)(m_texinfo.height + 2 * m_yborderpix) / (float)m_rawdims.c.y;
-
- // reset the remaining vertex parameters
- for (i = 0; i < 4; i++)
- {
- lockedbuf[i].z = 0.0f;
- lockedbuf[i].rhw = 1.0f;
- lockedbuf[i].color = D3DCOLOR_ARGB(0xff,0xff,0xff,0xff);
- }
+ lockedbuf[i].z = 0.0f;
+ lockedbuf[i].rhw = 1.0f;
+ lockedbuf[i].color = D3DCOLOR_ARGB(0xff,0xff,0xff,0xff);
+ }
- // unlock the vertex buffer
- result = m_renderer->get_vertex_buffer()->Unlock();
- if (FAILED(result))
- osd_printf_verbose("Direct3D: Error %08lX during vertex buffer unlock call\n", result);
+ // unlock the vertex buffer
+ result = m_renderer.get_vertex_buffer()->Unlock();
+ if (FAILED(result))
+ osd_printf_verbose("Direct3D: Error %08lX during vertex buffer unlock call\n", result);
- // set the stream and draw the triangle strip
- result = m_renderer->get_device()->SetStreamSource(0, m_renderer->get_vertex_buffer(), 0, sizeof(vertex));
- if (FAILED(result))
- osd_printf_verbose("Direct3D: Error %08lX during device SetStreamSource call\n", result);
- result = m_renderer->get_device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
- if (FAILED(result))
- osd_printf_verbose("Direct3D: Error %08lX during device DrawPrimitive call\n", result);
+ // set the stream and draw the triangle strip
+ result = m_renderer.get_device()->SetStreamSource(0, m_renderer.get_vertex_buffer(), 0, sizeof(vertex));
+ if (FAILED(result))
+ osd_printf_verbose("Direct3D: Error %08lX during device SetStreamSource call\n", result);
+ result = m_renderer.get_device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
+ if (FAILED(result))
+ osd_printf_verbose("Direct3D: Error %08lX during device DrawPrimitive call\n", result);
- // end the scene
- result = m_renderer->get_device()->EndScene();
- if (FAILED(result))
- osd_printf_verbose("Direct3D: Error %08lX during device end_scene call\n", result);
+ // end the scene
+ result = m_renderer.get_device()->EndScene();
+ if (FAILED(result))
+ osd_printf_verbose("Direct3D: Error %08lX during device end_scene call\n", result);
- // reset the render target and release our reference to the backbuffer
- result = m_renderer->get_device()->SetRenderTarget(0, backbuffer);
- if (FAILED(result))
- osd_printf_verbose("Direct3D: Error %08lX during device SetRenderTarget call 2\n", result);
- backbuffer->Release();
- m_renderer->reset_render_states();
- }
+ // reset the render target and release our reference to the backbuffer
+ result = m_renderer.get_device()->SetRenderTarget(0, backbuffer.Get());
+ if (FAILED(result))
+ osd_printf_verbose("Direct3D: Error %08lX during device SetRenderTarget call 2\n", result);
+ backbuffer.Reset();
+ m_renderer.reset_render_states();
// release our reference to the target surface
- scale_surface->Release();
+ scale_surface.Reset();
}
@@ -2623,35 +2563,6 @@ void texture_info::prescale()
d3d_render_target::~d3d_render_target()
{
- for (int index = 0; index < MAX_BLOOM_COUNT; index++)
- {
- if (bloom_texture[index] != nullptr)
- bloom_texture[index]->Release();
-
- if (bloom_surface[index] != nullptr)
- bloom_surface[index]->Release();
- }
-
- for (int index = 0; index < 2; index++)
- {
- if (source_texture[index] != nullptr)
- source_texture[index]->Release();
-
- if (source_surface[index] != nullptr)
- source_surface[index]->Release();
-
- if (target_texture[index] != nullptr)
- target_texture[index]->Release();
-
- if (target_surface[index] != nullptr)
- target_surface[index]->Release();
- }
-
- if (cache_texture != nullptr)
- cache_texture->Release();
-
- if (cache_surface != nullptr)
- cache_surface->Release();
}
@@ -2692,9 +2603,7 @@ bool d3d_render_target::init(renderer_d3d9 *d3d, int source_width, int source_he
cache_texture->GetSurfaceLevel(0, &cache_surface);
- auto win = d3d->assert_window();
-
- const screen_device *first_screen = screen_device_iterator(win->machine().root_device()).first();
+ const screen_device *first_screen = screen_device_enumerator(d3d->window().machine().root_device()).first();
bool vector_screen =
first_screen != nullptr &&
first_screen->screen_type() == SCREEN_TYPE_VECTOR;
@@ -2702,8 +2611,8 @@ bool d3d_render_target::init(renderer_d3d9 *d3d, int source_width, int source_he
float scale_factor = 0.75f;
int scale_count = vector_screen ? MAX_BLOOM_COUNT : HALF_BLOOM_COUNT;
- float bloom_width = (float)source_width;
- float bloom_height = (float)source_height;
+ auto bloom_width = (float)source_width;
+ auto bloom_height = (float)source_height;
float bloom_size = bloom_width < bloom_height ? bloom_width : bloom_height;
for (int bloom_index = 0; bloom_index < scale_count && bloom_size >= 2.0f; bloom_size *= scale_factor)
{
diff --git a/src/osd/modules/render/drawd3d.h b/src/osd/modules/render/drawd3d.h
index 92923904d77..3ab7651d87c 100644
--- a/src/osd/modules/render/drawd3d.h
+++ b/src/osd/modules/render/drawd3d.h
@@ -5,25 +5,29 @@
// drawd3d.h - Win32 Direct3D header
//
//============================================================
+#ifndef MAME_OSD_MODULES_RENDER_DRAWD3D_H
+#define MAME_OSD_MODULES_RENDER_DRAWD3D_H
#pragma once
-#ifndef __WIN_DRAWD3D__
-#define __WIN_DRAWD3D__
+#include "d3d/d3dcomm.h"
+
+#include "modules/lib/osdlib.h"
+#include "modules/osdwindow.h"
-#ifdef OSD_WINDOWS
+#include "sliderdirtynotifier.h"
#include <windows.h>
#include <tchar.h>
#include <mmsystem.h>
#include <d3d9.h>
#include <d3dx9.h>
-#include <math.h>
#undef interface
-#include "d3d/d3dcomm.h"
-#include "sliderdirtynotifier.h"
-#include "modules/lib/osdlib.h"
+#include <memory>
+#include <vector>
+#include <cmath>
+
//============================================================
// CONSTANTS
@@ -36,15 +40,6 @@
// TYPE DEFINITIONS
//============================================================
-struct d3d_base
-{
- // internal objects
- IDirect3D9 *d3dobj;
- bool post_fx_available;
-
- osd::dynamic_module::ptr d3d9_dll;
-};
-
class shaders;
struct hlsl_options;
@@ -52,11 +47,10 @@ struct hlsl_options;
class renderer_d3d9 : public osd_renderer, public slider_dirty_notifier
{
public:
- renderer_d3d9(std::shared_ptr<osd_window> window);
- virtual ~renderer_d3d9();
+ using IDirect3D9Ptr = Microsoft::WRL::ComPtr<IDirect3D9>;
- static bool init(running_machine &machine);
- static void exit();
+ renderer_d3d9(osd_window &window, const IDirect3D9Ptr &d3dobj);
+ virtual ~renderer_d3d9();
virtual int create() override;
virtual render_primitive_list *get_primitives() override;
@@ -113,11 +107,13 @@ public:
vec2f get_dims() const { return vec2f(m_width, m_height); }
int get_height() const { return m_height; }
int get_refresh() const { return m_refresh; }
+ bool post_fx_available() const { return m_post_fx_available; }
+ void set_post_fx_unavailable() { m_post_fx_available = false; }
- IDirect3DDevice9 * get_device() const { return m_device; }
+ IDirect3DDevice9 * get_device() const { return m_device.Get(); }
D3DPRESENT_PARAMETERS * get_presentation() { return &m_presentation; }
- IDirect3DVertexBuffer9 *get_vertex_buffer() const { return m_vertexbuf; }
+ IDirect3DVertexBuffer9 *get_vertex_buffer() const { return m_vertexbuf.Get(); }
void set_toggle(bool toggle) { m_toggle = toggle; }
@@ -125,27 +121,32 @@ public:
D3DFORMAT get_pixel_format() const { return m_pixformat; }
D3DDISPLAYMODE get_origmode() const { return m_origmode; }
- uint32_t get_last_texture_flags() const { return m_last_texture_flags; }
+ uint32_t get_last_texture_flags() const { return m_last_texture_flags; }
- d3d_texture_manager * get_texture_manager() const { return m_texture_manager; }
+ d3d_texture_manager * get_texture_manager() const { return m_texture_manager.get(); }
texture_info * get_default_texture();
- shaders * get_shaders() const { return m_shaders; }
+ shaders * get_shaders() const { return m_shaders.get(); }
private:
+ using IDirect3DDevice9Ptr = Microsoft::WRL::ComPtr<IDirect3DDevice9>;
+ using IDirect3DVertexBuffer9Ptr = Microsoft::WRL::ComPtr<IDirect3DVertexBuffer9>;
+
+ const IDirect3D9Ptr m_d3dobj; // Direct3D 9 API object
int m_adapter; // ordinal adapter number
int m_width; // current width
int m_height; // current height
int m_refresh; // current refresh rate
int m_create_error_count; // number of consecutive create errors
+ bool m_post_fx_available;
- IDirect3DDevice9 * m_device; // pointer to the Direct3DDevice object
+ IDirect3DDevice9Ptr m_device; // pointer to the Direct3DDevice object
int m_gamma_supported; // is full screen gamma supported?
D3DPRESENT_PARAMETERS m_presentation; // set of presentation parameters
D3DDISPLAYMODE m_origmode; // original display mode for the adapter
D3DFORMAT m_pixformat; // pixel format we are using
- IDirect3DVertexBuffer9 *m_vertexbuf; // pointer to the vertex buffer object
+ IDirect3DVertexBuffer9Ptr m_vertexbuf; // pointer to the vertex buffer object
vertex * m_lockedbuf; // pointer to the locked vertex buffer
int m_numverts; // number of accumulated vertices
@@ -160,20 +161,18 @@ private:
D3DFORMAT m_screen_format; // format to use for screen textures
texture_info * m_last_texture; // previous texture
- uint32_t m_last_texture_flags; // previous texture flags
+ uint32_t m_last_texture_flags; // previous texture flags
int m_last_blendenable; // previous blendmode
int m_last_blendop; // previous blendmode
int m_last_blendsrc; // previous blendmode
int m_last_blenddst; // previous blendmode
int m_last_filter; // previous texture filter
- uint32_t m_last_wrap; // previous wrap state
+ uint32_t m_last_wrap; // previous wrap state
int m_last_modmode; // previous texture modulation
- shaders * m_shaders; // HLSL interface
+ std::unique_ptr<shaders> m_shaders; // HLSL interface
- d3d_texture_manager * m_texture_manager; // texture manager
+ std::unique_ptr<d3d_texture_manager> m_texture_manager; // texture manager
};
-#endif // OSD_WINDOWS
-
-#endif // __WIN_DRAWD3D__
+#endif // MAME_OSD_MODULES_RENDER_DRAWD3D_H
diff --git a/src/osd/modules/render/drawgdi.cpp b/src/osd/modules/render/drawgdi.cpp
index bd0e6425b6e..f922ca24e8f 100644
--- a/src/osd/modules/render/drawgdi.cpp
+++ b/src/osd/modules/render/drawgdi.cpp
@@ -2,24 +2,53 @@
// copyright-holders:Aaron Giles
//============================================================
//
-// drawgdi.c - Win32 GDI drawing
+// drawgdi.cpp - Win32 GDI drawing
//
//============================================================
+#include "render_module.h"
+
+#include "modules/osdmodule.h"
+
+#if defined(OSD_WINDOWS)
+
+#include "window.h"
+
+// emu
#include "emu.h"
-#include "drawgdi.h"
#include "rendersw.hxx"
-//============================================================
-// destructor
-//============================================================
+// standard windows headers
+#include <windows.h>
+
+
+namespace osd {
+
+namespace {
-renderer_gdi::~renderer_gdi()
+// renderer_gdi is the information for the current screen
+class renderer_gdi : public osd_renderer
{
- // free the bitmap memory
- if (m_bmdata != nullptr)
- global_free_array(m_bmdata);
-}
+public:
+ renderer_gdi(osd_window &window)
+ : osd_renderer(window)
+ , m_bmdata(nullptr)
+ , m_bmsize(0)
+ {
+ }
+
+ virtual int create() override;
+ virtual render_primitive_list *get_primitives() override;
+ virtual int draw(const int update) override;
+ virtual void save() override {}
+ virtual void record() override {}
+ virtual void toggle_fsfx() override {}
+
+private:
+ BITMAPINFO m_bminfo;
+ std::unique_ptr<uint8_t []> m_bmdata;
+ size_t m_bmsize;
+};
//============================================================
// renderer_gdi::create
@@ -37,6 +66,7 @@ int renderer_gdi::create()
m_bminfo.bmiHeader.biYPelsPerMeter = 0;
m_bminfo.bmiHeader.biClrUsed = 0;
m_bminfo.bmiHeader.biClrImportant = 0;
+
return 0;
}
@@ -46,16 +76,12 @@ int renderer_gdi::create()
render_primitive_list *renderer_gdi::get_primitives()
{
- auto win = try_getwindow();
- if (win == nullptr)
+ osd_dim const dimensions = window().get_size();
+ if ((dimensions.width() <= 0) || (dimensions.height() <= 0))
return nullptr;
- RECT client;
- GetClientRect(std::static_pointer_cast<win_window_info>(win)->platform_window(), &client);
- if ((rect_width(&client) == 0) || (rect_height(&client) == 0))
- return nullptr;
- win->target()->set_bounds(rect_width(&client), rect_height(&client), win->pixel_aspect());
- return &win->target()->get_primitives();
+ window().target()->set_bounds(dimensions.width(), dimensions.height(), window().pixel_aspect());
+ return &window().target()->get_primitives();
}
//============================================================
@@ -64,41 +90,78 @@ render_primitive_list *renderer_gdi::get_primitives()
int renderer_gdi::draw(const int update)
{
- auto win = assert_window();
+ auto &win = dynamic_cast<win_window_info &>(window());
// we don't have any special resize behaviors
- if (win->m_resize_state == RESIZE_STATE_PENDING)
- win->m_resize_state = RESIZE_STATE_NORMAL;
+ if (win.m_resize_state == win_window_info::RESIZE_STATE_PENDING)
+ win.m_resize_state = win_window_info::RESIZE_STATE_NORMAL;
// get the target bounds
RECT bounds;
- GetClientRect(std::static_pointer_cast<win_window_info>(win)->platform_window(), &bounds);
+ GetClientRect(win.platform_window(), &bounds);
// compute width/height/pitch of target
- int width = rect_width(&bounds);
- int height = rect_height(&bounds);
- int pitch = (width + 3) & ~3;
+ osd_dim const dimensions = win.get_size();
+ int const width = dimensions.width();
+ int const height = dimensions.height();
+ int const pitch = (width + 3) & ~3;
// make sure our temporary bitmap is big enough
- if (pitch * height * 4 > m_bmsize)
+ if ((pitch * height * 4) > m_bmsize)
{
m_bmsize = pitch * height * 4 * 2;
- global_free_array(m_bmdata);
- m_bmdata = global_alloc_array(uint8_t, m_bmsize);
+ m_bmdata.reset();
+ m_bmdata = std::make_unique<uint8_t []>(m_bmsize);
}
// draw the primitives to the bitmap
- win->m_primlist->acquire_lock();
- software_renderer<uint32_t, 0,0,0, 16,8,0>::draw_primitives(*win->m_primlist, m_bmdata, width, height, pitch);
- win->m_primlist->release_lock();
+ win.m_primlist->acquire_lock();
+ software_renderer<uint32_t, 0,0,0, 16,8,0>::draw_primitives(*win.m_primlist, m_bmdata.get(), width, height, pitch);
+ win.m_primlist->release_lock();
// fill in bitmap-specific info
m_bminfo.bmiHeader.biWidth = pitch;
m_bminfo.bmiHeader.biHeight = -height;
// blit to the screen
- StretchDIBits(win->m_dc, 0, 0, width, height,
- 0, 0, width, height,
- m_bmdata, &m_bminfo, DIB_RGB_COLORS, SRCCOPY);
+ StretchDIBits(
+ win.m_dc, 0, 0, width, height,
+ 0, 0, width, height,
+ m_bmdata.get(), &m_bminfo, DIB_RGB_COLORS, SRCCOPY);
+
return 0;
}
+
+
+class video_gdi : public osd_module, public render_module
+{
+public:
+ video_gdi() : osd_module(OSD_RENDERER_PROVIDER, "gdi") { }
+
+ virtual int init(osd_interface &osd, osd_options const &options) override { return 0; }
+ virtual void exit() override { }
+
+ virtual std::unique_ptr<osd_renderer> create(osd_window &window) override;
+
+protected:
+ virtual unsigned flags() const override { return FLAG_INTERACTIVE; }
+};
+
+std::unique_ptr<osd_renderer> video_gdi::create(osd_window &window)
+{
+ return std::make_unique<renderer_gdi>(window);
+}
+
+} // anonymous namespace
+
+} // namespace osd
+
+
+#else // defined(OSD_WINDOWS)
+
+namespace osd { namespace { MODULE_NOT_SUPPORTED(video_gdi, OSD_RENDERER_PROVIDER, "gdi") } }
+
+#endif // defined(OSD_WINDOWS)
+
+
+MODULE_DEFINITION(RENDERER_GDI, osd::video_gdi)
diff --git a/src/osd/modules/render/drawgdi.h b/src/osd/modules/render/drawgdi.h
deleted file mode 100644
index 49d05c18daa..00000000000
--- a/src/osd/modules/render/drawgdi.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
-//============================================================
-//
-// drawgdi.h - Win32 GDI drawing
-//
-//============================================================
-
-#pragma once
-
-#ifndef __DRAWGDI__
-#define __DRAWGDI__
-
-// standard windows headers
-#include <windows.h>
-
-// MAME headers
-
-// MAMEOS headers
-#include "window.h"
-
-
-//============================================================
-// TYPE DEFINITIONS
-//============================================================
-
-/* renderer_gdi is the information for the current screen */
-class renderer_gdi : public osd_renderer
-{
-public:
- renderer_gdi(std::shared_ptr<osd_window> window)
- : osd_renderer(window, FLAG_NONE)
- , m_bmdata(nullptr)
- , m_bmsize(0)
- {
- }
- virtual ~renderer_gdi();
-
- static bool init(running_machine &machine) { return false; }
- static void exit() { }
-
- virtual int create() override;
- virtual render_primitive_list *get_primitives() override;
- virtual int draw(const int update) override;
- virtual void save() override {};
- virtual void record() override {};
- virtual void toggle_fsfx() override {};
-
-private:
- BITMAPINFO m_bminfo;
- uint8_t * m_bmdata;
- size_t m_bmsize;
-};
-
-#endif // __DRAWGDI__
diff --git a/src/osd/modules/render/drawnone.cpp b/src/osd/modules/render/drawnone.cpp
index e8bbfa15432..55ce1bbed18 100644
--- a/src/osd/modules/render/drawnone.cpp
+++ b/src/osd/modules/render/drawnone.cpp
@@ -6,36 +6,76 @@
//
//============================================================
-// standard windows headers
-#include <windows.h>
+#include "render_module.h"
-// MAME headers
-#include "emu.h"
+#include "modules/lib/osdobj_common.h"
+#include "modules/osdmodule.h"
+#include "modules/osdwindow.h"
-#include "drawnone.h"
+#include "main.h"
+#include "render.h"
-//============================================================
-// drawnone_window_get_primitives
-//============================================================
+#include <memory>
+
+
+namespace osd {
+
+namespace {
+
+class renderer_none : public osd_renderer
+{
+public:
+ renderer_none(osd_window &window) : osd_renderer(window) { }
+
+ virtual int create() override { return 0; }
+ virtual render_primitive_list *get_primitives() override;
+ virtual int draw(const int update) override { return 0; }
+ virtual void save() override { }
+ virtual void record() override { }
+ virtual void toggle_fsfx() override { }
+};
render_primitive_list *renderer_none::get_primitives()
{
- auto win = try_getwindow();
- if (win == nullptr)
+ osd_dim const dimensions = window().get_size();
+ if ((dimensions.width() <= 0) || (dimensions.height() <= 0))
return nullptr;
- RECT client;
-#if defined(OSD_WINDOWS)
- GetClientRect(std::static_pointer_cast<win_window_info>(win)->platform_window(), &client);
-#elif defined(OSD_UWP)
- auto bounds = std::static_pointer_cast<uwp_window_info>(win)->platform_window()->Bounds;
- client.left = bounds.Left;
- client.right = bounds.Right;
- client.top = bounds.Top;
- client.bottom = bounds.Bottom;
-#endif
- if ((rect_width(&client) == 0) || (rect_height(&client) == 0))
- return nullptr;
- win->target()->set_bounds(rect_width(&client), rect_height(&client), win->pixel_aspect());
- return &win->target()->get_primitives();
+ window().target()->set_bounds(dimensions.width(), dimensions.height(), window().pixel_aspect());
+ return &window().target()->get_primitives();
+}
+
+
+class video_none : public osd_module, public render_module
+{
+public:
+ video_none() : osd_module(OSD_RENDERER_PROVIDER, "none") { }
+
+ 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 0; }
+};
+
+int video_none::init(osd_interface &osd, osd_options const &options)
+{
+ if (!emulator_info::standalone() && (options.seconds_to_run() == 0))
+ osd_printf_warning("Warning: -video none doesn't make much sense without -seconds_to_run\n");
+
+ return 0;
}
+
+std::unique_ptr<osd_renderer> video_none::create(osd_window &window)
+{
+ return std::make_unique<renderer_none>(window);
+}
+
+} // anonymous namespace
+
+} // namespace osd
+
+
+MODULE_DEFINITION(RENDERER_NONE, osd::video_none)
diff --git a/src/osd/modules/render/drawnone.h b/src/osd/modules/render/drawnone.h
deleted file mode 100644
index c884f969204..00000000000
--- a/src/osd/modules/render/drawnone.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
-//============================================================
-//
-// drawnone.h - stub "nothing" drawer
-//
-//============================================================
-
-#ifndef __DRAWNONE__
-#define __DRAWNONE__
-
-#include "window.h"
-
-class renderer_none : public osd_renderer
-{
-public:
- renderer_none(std::shared_ptr<osd_window> window)
- : osd_renderer(window, FLAG_NONE) { }
-
- virtual ~renderer_none() { }
-
- static bool init(running_machine &machine) { return false; }
- static void exit() { }
-
- virtual int create() override { return 0; }
- virtual render_primitive_list *get_primitives() override;
- virtual int draw(const int update) override { return 0; }
- virtual void save() override { }
- virtual void record() override { }
- virtual void toggle_fsfx() override { }
-};
-
-#endif // __DRAWNONE__
diff --git a/src/osd/modules/render/drawogl.cpp b/src/osd/modules/render/drawogl.cpp
index 6837e63bbe3..f9f76946bf4 100644
--- a/src/osd/modules/render/drawogl.cpp
+++ b/src/osd/modules/render/drawogl.cpp
@@ -12,35 +12,63 @@
//
//============================================================
-// standard C headers
-#include <math.h>
-#include <stdio.h>
+#include "render_module.h"
+
+#include "modules/osdmodule.h"
+
+#if USE_OPENGL
-// MAME headers
+// will be picked up from specific OSD implementation
+#include "window.h"
+
+// OSD common headers
+#include "modules/lib/osdlib.h"
+#include "modules/lib/osdobj_common.h"
+#include "modules/opengl/gl_shader_mgr.h"
#include "osdcomm.h"
-#include "emu.h"
-#include "emuopts.h"
-#ifdef OSD_MAC
+// OSD headers
+#if defined(OSD_WINDOWS)
+typedef uint64_t HashT;
+#include "winglcontext.h"
+#elif defined(OSD_MAC)
#define GL_SILENCE_DEPRECATION (1)
+#include "osdmac.h"
+#else
+#include "osdsdl.h"
+#include "sdlglcontext.h"
#endif
+// emu
+#include "emucore.h"
+#include "emuopts.h"
+#include "render.h"
+
+
#if !defined(OSD_WINDOWS) && !defined(OSD_MAC)
+
// standard SDL headers
#define TOBEMIGRATED 1
#include <SDL2/SDL.h>
-#endif
-#include "modules/lib/osdlib.h"
-#include "modules/lib/osdobj_common.h"
+#endif // !defined(OSD_WINDOWS && !defined(OSD_MAC)
-// OpenGL headers
-#include "modules/opengl/osd_opengl.h"
-#include "modules/opengl/gl_shader_tool.h"
-#include "modules/opengl/gl_shader_mgr.h"
+// standard C headers
+#include <cmath>
+#include <cstdio>
+#include <memory>
+#include <utility>
+
#if defined(SDLMAME_MACOSX) || defined(OSD_MAC)
+
+#include <cstring>
+#include <cstdio>
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
#ifndef APIENTRY
#define APIENTRY
#endif
@@ -67,7 +95,13 @@ typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum m_target, GLuint r
typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum m_target, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum m_target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers);
-#endif
+
+#endif // defined(SDLMAME_MACOSX) || defined(OSD_MAC)
+
+
+namespace osd {
+
+namespace {
// make sure the extensions compile OK everywhere
#ifndef GL_TEXTURE_STORAGE_HINT_APPLE
@@ -123,7 +157,283 @@ typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuin
#define GL_DEPTH_COMPONENT32 0x81A7
#endif
-#include "drawogl.h"
+
+//============================================================
+// Configuration
+//============================================================
+
+#define GLSL_SHADER_MAX 10
+
+struct ogl_video_config
+{
+ ogl_video_config() = default;
+
+ bool vbo = false;
+ bool pbo = false;
+ bool allowtexturerect = false; // allow GL_ARB_texture_rectangle, default: no
+ bool forcepow2texture = false; // force power of two textures, default: no
+ bool glsl = false;
+ int glsl_filter = 0; // glsl filtering, >0 disables filter
+ std::string glsl_shader_mamebm[GLSL_SHADER_MAX]; // custom glsl shader set, mame bitmap
+ int glsl_shader_mamebm_num = 0; // custom glsl shader set number, mame bitmap
+ std::string glsl_shader_scrn[GLSL_SHADER_MAX]; // custom glsl shader set, screen bitmap
+ int glsl_shader_scrn_num = 0; // custom glsl shader number, screen bitmap
+};
+
+
+//============================================================
+// Textures
+//============================================================
+
+/* ogl_texture_info holds information about a texture */
+class ogl_texture_info
+{
+public:
+ ogl_texture_info(
+#if defined(USE_DISPATCH_GL)
+ osd_gl_dispatch *gld
+#endif
+ )
+#if defined(USE_DISPATCH_GL)
+ : gl_dispatch(gld)
+#endif
+ {
+ for (int i=0; i<2; i++)
+ {
+ mpass_textureunit[i] = 0;
+ mpass_texture_mamebm[i] = 0;
+ mpass_fbo_mamebm[i] = 0;
+ mpass_texture_scrn[i] = 0;
+ mpass_fbo_scrn[i] = 0;
+ }
+ for (int i=0; i<8; i++)
+ texCoord[i] = 0.0f;
+ }
+
+#if defined(USE_DISPATCH_GL)
+ osd_gl_dispatch *const gl_dispatch; // name is magic, can't be changed
+#endif
+ HashT hash = 0; // hash value for the texture (must be >= pointer size)
+ uint32_t flags = 0; // rendering flags
+ render_texinfo texinfo; // copy of the texture info
+ int rawwidth = 0, rawheight = 0; // raw width/height of the texture
+ int rawwidth_create = 0; // raw width/height, pow2 compatible, if needed
+ int rawheight_create = 0; // (create and initial set the texture, not for copy!)
+ int type = 0; // what type of texture are we?
+ int format = 0; // texture format
+ int borderpix = 0; // do we have a 1 pixel border?
+ int xprescale = 0; // what is our X prescale factor?
+ int yprescale = 0; // what is our Y prescale factor?
+ int nocopy = 0; // must the texture date be copied?
+
+ uint32_t texture = 0; // OpenGL texture "name"/ID
+
+ GLenum texTarget = 0; // OpenGL texture target
+ int texpow2 = 0; // Is this texture pow2
+
+ uint32_t mpass_dest_idx = 0; // Multipass dest idx [0..1]
+ uint32_t mpass_textureunit[2]; // texture unit names for GLSL
+
+ uint32_t mpass_texture_mamebm[2]; // Multipass OpenGL texture "name"/ID for the shader
+ uint32_t mpass_fbo_mamebm[2]; // framebuffer object for this texture, multipass
+ uint32_t mpass_texture_scrn[2]; // Multipass OpenGL texture "name"/ID for the shader
+ uint32_t mpass_fbo_scrn[2]; // framebuffer object for this texture, multipass
+
+ uint32_t pbo = 0; // pixel buffer object for this texture (DYNAMIC only!)
+ uint32_t *data = nullptr; // pixels for the texture
+ bool data_own = false; // do we own / allocated it ?
+ GLfloat texCoord[8];
+ GLuint texCoordBufferName;
+
+};
+
+// renderer_ogl is the information about OpenGL for the current screen
+class renderer_ogl : public osd_renderer
+{
+public:
+ renderer_ogl(osd_window &window, ogl_video_config const &ogl_config)
+ : osd_renderer(window)
+ , m_ogl_config(ogl_config)
+ , m_blittimer(0)
+ , m_width(0)
+ , m_height(0)
+ , m_blit_dim(0, 0)
+ , m_initialized(0)
+ , m_last_blendmode(0)
+ , m_texture_max_width(0)
+ , m_texture_max_height(0)
+ , m_texpoweroftwo(0)
+ , m_usevbo(0)
+ , m_usepbo(0)
+ , m_usefbo(0)
+ , m_useglsl(0)
+ , m_glsl_program_num(0)
+ , m_glsl_program_mb2sc(0)
+ , m_usetexturerect(0)
+ , m_init_context(0)
+ , m_last_hofs(0.0f)
+ , m_last_vofs(0.0f)
+ , m_surf_w(0)
+ , m_surf_h(0)
+ {
+ for (int i=0; i < HASH_SIZE + OVERFLOW_SIZE; i++)
+ m_texhash[i] = nullptr;
+ for (int i=0; i < 2*GLSL_SHADER_MAX; i++)
+ m_glsl_program[i] = 0;
+ for (int i=0; i < 8; i++)
+ m_texVerticex[i] = 0.0f;
+ }
+ virtual ~renderer_ogl()
+ {
+ // free the memory in the window
+ destroy_all_textures();
+ }
+
+ virtual int create() override;
+ virtual int draw(const int update) override;
+
+#ifndef OSD_WINDOWS
+ virtual int xy_to_render_target(const int x, const int y, int *xt, int *yt) override;
+#endif
+ virtual render_primitive_list *get_primitives() override
+ {
+ osd_dim nd = window().get_size();
+ if (nd != m_blit_dim)
+ {
+ m_blit_dim = nd;
+ notify_changed();
+ }
+ if ((m_blit_dim.width() == 0) || (m_blit_dim.height() == 0))
+ return nullptr;
+ window().target()->set_bounds(m_blit_dim.width(), m_blit_dim.height(), window().pixel_aspect());
+ return &window().target()->get_primitives();
+ }
+
+#ifdef OSD_WINDOWS
+ virtual void save() override { }
+ virtual void record() override { }
+ virtual void toggle_fsfx() override { }
+#endif
+
+private:
+ static const uint32_t HASH_SIZE = ((1 << 18) + 1);
+ static const uint32_t OVERFLOW_SIZE = (1 << 12);
+
+ void destroy_all_textures();
+
+ void loadGLExtensions();
+ void loadgl_functions();
+ void initialize_gl();
+ void set_blendmode(int blendmode);
+ HashT texture_compute_hash(const render_texinfo *texture, uint32_t flags);
+ void texture_compute_type_subroutine(const render_texinfo *texsource, ogl_texture_info *texture, uint32_t flags);
+ void texture_compute_size_subroutine(ogl_texture_info *texture, uint32_t flags,
+ uint32_t width, uint32_t height,
+ int* p_width, int* p_height, int* p_width_create, int* p_height_create);
+ void texture_compute_size_type(const render_texinfo *texsource, ogl_texture_info *texture, uint32_t flags);
+ ogl_texture_info *texture_create(const render_texinfo *texsource, uint32_t flags);
+ int texture_shader_create(const render_texinfo *texsource, ogl_texture_info *texture, uint32_t flags);
+ ogl_texture_info *texture_find(const render_primitive *prim);
+ void texture_coord_update(ogl_texture_info *texture, const render_primitive *prim, int shaderIdx);
+ void texture_mpass_flip(ogl_texture_info *texture, int shaderIdx);
+ void texture_shader_update(ogl_texture_info *texture, render_container *container, int shaderIdx);
+ ogl_texture_info * texture_update(const render_primitive *prim, int shaderIdx);
+ void texture_disable(ogl_texture_info * texture);
+ void texture_all_disable();
+
+ int gl_checkFramebufferStatus() const;
+ int texture_fbo_create(uint32_t text_unit, uint32_t text_name, uint32_t fbo_name, int width, int height) const;
+ void texture_set_data(ogl_texture_info *texture, const render_texinfo *texsource, uint32_t flags) const;
+
+ int gl_check_error(bool log, const char *file, int line) const
+ {
+ GLenum const glerr = glGetError();
+ if (GL_NO_ERROR != glerr)
+ {
+ if (log)
+ osd_printf_warning("%s:%d: GL Error: %d 0x%X\n", file, line, int(glerr), unsigned(glerr));
+ }
+ return (GL_NO_ERROR != glerr) ? glerr : 0;
+ }
+
+#define GL_CHECK_ERROR_QUIET() gl_check_error(false, __FILE__, __LINE__)
+#define GL_CHECK_ERROR_NORMAL() gl_check_error(true, __FILE__, __LINE__)
+
+ ogl_video_config const &m_ogl_config;
+
+ int32_t m_blittimer;
+ int m_width;
+ int m_height;
+ osd_dim m_blit_dim;
+
+ std::unique_ptr<osd_gl_context> m_gl_context;
+ std::unique_ptr<glsl_shader_info> m_shader_tool;
+
+ int m_initialized; // is everything well initialized, i.e. all GL stuff etc.
+ // 3D info (GL mode only)
+ ogl_texture_info * m_texhash[HASH_SIZE + OVERFLOW_SIZE];
+ int m_last_blendmode; // previous blendmode
+ int32_t m_texture_max_width; // texture maximum width
+ int32_t m_texture_max_height; // texture maximum height
+ int m_texpoweroftwo; // must textures be power-of-2 sized?
+ int m_usevbo; // runtime check if VBO is available
+ int m_usepbo; // runtime check if PBO is available
+ int m_usefbo; // runtime check if FBO is available
+ int m_useglsl; // runtime check if GLSL is available
+
+ GLhandleARB m_glsl_program[2*GLSL_SHADER_MAX]; // GLSL programs, or 0
+ int m_glsl_program_num; // number of GLSL programs
+ int m_glsl_program_mb2sc; // GLSL program idx, which transforms
+ // the mame-bitmap. screen-bitmap (size/rotation/..)
+ // All progs <= glsl_program_mb2sc using the mame bitmap
+ // as input, otherwise the screen bitmap.
+ // All progs >= glsl_program_mb2sc using the screen bitmap
+ // as output, otherwise the mame bitmap.
+ int m_usetexturerect; // use ARB_texture_rectangle for non-power-of-2, general use
+
+ int m_init_context; // initialize context before next draw
+
+ float m_last_hofs;
+ float m_last_vofs;
+
+ // Static vars from draogl_window_dra
+ int32_t m_surf_w;
+ int32_t m_surf_h;
+ GLfloat m_texVerticex[8];
+
+#if defined(USE_DISPATCH_GL)
+ std::unique_ptr<osd_gl_dispatch> gl_dispatch; // name is magic, can't be changed
+#endif
+
+ // OGL 1.3
+#if defined(GL_ARB_multitexture) && !defined(OSD_MAC)
+ PFNGLACTIVETEXTUREARBPROC m_glActiveTexture = nullptr;
+#else
+ PFNGLACTIVETEXTUREPROC m_glActiveTexture = nullptr;
+#endif
+
+ // VBO
+ PFNGLGENBUFFERSPROC m_glGenBuffers = nullptr;
+ PFNGLDELETEBUFFERSPROC m_glDeleteBuffers = nullptr;
+ PFNGLBINDBUFFERPROC m_glBindBuffer = nullptr;
+ PFNGLBUFFERDATAPROC m_glBufferData = nullptr;
+ PFNGLBUFFERSUBDATAPROC m_glBufferSubData = nullptr;
+
+ // PBO
+ PFNGLMAPBUFFERPROC m_glMapBuffer = nullptr;
+ PFNGLUNMAPBUFFERPROC m_glUnmapBuffer = nullptr;
+
+ // FBO
+ PFNGLISFRAMEBUFFEREXTPROC m_glIsFramebuffer = nullptr;
+ PFNGLBINDFRAMEBUFFEREXTPROC m_glBindFramebuffer = nullptr;
+ PFNGLDELETEFRAMEBUFFERSEXTPROC m_glDeleteFramebuffers = nullptr;
+ PFNGLGENFRAMEBUFFERSEXTPROC m_glGenFramebuffers = nullptr;
+ PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC m_glCheckFramebufferStatus = nullptr;
+ PFNGLFRAMEBUFFERTEXTURE2DEXTPROC m_glFramebufferTexture2D = nullptr;
+
+ static bool s_shown_video_info;
+};
+
//============================================================
// DEBUGGING
@@ -236,103 +546,22 @@ void renderer_ogl::set_blendmode(int blendmode)
}
}
-//============================================================
-// STATIC VARIABLES
-//============================================================
-
-// OGL 1.3
-#if defined(GL_ARB_multitexture) && !defined(OSD_MAC)
-static PFNGLACTIVETEXTUREARBPROC pfn_glActiveTexture = nullptr;
-#else
-static PFNGLACTIVETEXTUREPROC pfn_glActiveTexture = nullptr;
-#endif
-
-// VBO
-static PFNGLGENBUFFERSPROC pfn_glGenBuffers = nullptr;
-static PFNGLDELETEBUFFERSPROC pfn_glDeleteBuffers = nullptr;
-static PFNGLBINDBUFFERPROC pfn_glBindBuffer = nullptr;
-static PFNGLBUFFERDATAPROC pfn_glBufferData = nullptr;
-static PFNGLBUFFERSUBDATAPROC pfn_glBufferSubData = nullptr;
-
-// PBO
-static PFNGLMAPBUFFERPROC pfn_glMapBuffer = nullptr;
-static PFNGLUNMAPBUFFERPROC pfn_glUnmapBuffer = nullptr;
-
-// FBO
-static PFNGLISFRAMEBUFFEREXTPROC pfn_glIsFramebuffer = nullptr;
-static PFNGLBINDFRAMEBUFFEREXTPROC pfn_glBindFramebuffer = nullptr;
-static PFNGLDELETEFRAMEBUFFERSEXTPROC pfn_glDeleteFramebuffers = nullptr;
-static PFNGLGENFRAMEBUFFERSEXTPROC pfn_glGenFramebuffers = nullptr;
-static PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC pfn_glCheckFramebufferStatus = nullptr;
-static PFNGLFRAMEBUFFERTEXTURE2DEXTPROC pfn_glFramebufferTexture2D = nullptr;
-
-static int glsl_shader_feature = GLSL_SHADER_FEAT_PLAIN;
-
-//============================================================
-// Textures
-//============================================================
-
-static void texture_set_data(ogl_texture_info *texture, const render_texinfo *texsource, uint32_t flags);
+static int glsl_shader_feature = glsl_shader_info::FEAT_PLAIN; // FIXME: why is this static?
//============================================================
// Static Variables
//============================================================
bool renderer_ogl::s_shown_video_info = false;
-bool renderer_ogl::s_dll_loaded = false;
-
-void renderer_ogl::init(running_machine &machine)
-{
- s_dll_loaded = false;
-
- load_gl_lib(machine);
-#if defined(OSD_WINDOWS)
- osd_printf_verbose("Using Windows OpenGL driver\n");
-#else
- osd_printf_verbose("Using SDL multi-window OpenGL driver (SDL 2.0+)\n");
-#endif
-}
-
-//============================================================
-// CONSTRUCTOR & DESTRUCTOR
-//============================================================
-
-renderer_ogl::~renderer_ogl()
-{
- // free the memory in the window
- destroy_all_textures();
-
- global_free(m_gl_context);
- m_gl_context = nullptr;
-}
-
-void renderer_ogl::exit()
-{
- for (int i = 0; i < video_config.glsl_shader_mamebm_num; i++)
- {
- if (nullptr != video_config.glsl_shader_mamebm[i])
- {
- free(video_config.glsl_shader_mamebm[i]);
- video_config.glsl_shader_mamebm[i] = nullptr;
- }
- }
- for (int i =0; i < video_config.glsl_shader_scrn_num; i++)
- {
- if (nullptr != video_config.glsl_shader_scrn[i])
- {
- free(video_config.glsl_shader_scrn[i]);
- video_config.glsl_shader_scrn[i] = nullptr;
- }
- }
-}
//============================================================
// Load the OGL function addresses
//============================================================
-static void loadgl_functions(osd_gl_context *context)
+void renderer_ogl::loadgl_functions()
{
-#ifdef USE_DISPATCH_GL
+#if defined(USE_DISPATCH_GL)
+ gl_dispatch = std::make_unique<osd_gl_dispatch>();
int err_count = 0;
@@ -340,11 +569,11 @@ static void loadgl_functions(osd_gl_context *context)
* while func will be expanded to disp_p->glBegin
*/
- #define OSD_GL(ret,func,params) \
- if (!( func = (ret (APIENTRY *)params) context->getProcAddress( #func ) )) \
- { err_count++; osd_printf_error("GL function %s not found!\n", #func ); }
+ #define OSD_GL(ret, func, params) \
+ if (!m_gl_context->get_proc_address(func, #func)) \
+ { err_count++; osd_printf_error("GL function %s not found!\n", #func); }
- #define OSD_GL_UNUSED(ret,func,params)
+ #define OSD_GL_UNUSED(ret, func, params)
#define GET_GLFUNC 1
#include "modules/opengl/osd_opengl.h"
@@ -356,45 +585,6 @@ static void loadgl_functions(osd_gl_context *context)
#endif
}
-//============================================================
-// Load GL library
-//============================================================
-
-#ifdef USE_DISPATCH_GL
-osd_gl_dispatch *gl_dispatch;
-#endif
-
-void renderer_ogl::load_gl_lib(running_machine &machine)
-{
- if (!s_dll_loaded)
- {
-#ifndef OSD_WINDOWS
-#ifdef USE_DISPATCH_GL
- /*
- * directfb and and x11 use this env var
- * SDL_VIDEO_GL_DRIVER
- */
- const char *stemp;
-
- stemp = downcast<sdl_options &>(machine.options()).gl_lib();
- if (stemp != nullptr && strcmp(stemp, OSDOPTVAL_AUTO) == 0)
- stemp = nullptr;
-
- if (SDL_GL_LoadLibrary(stemp) != 0) // Load library (default for e==nullptr
- {
- fatalerror("Unable to load opengl library: %s\n", stemp ? stemp : "<default>");
- }
- osd_printf_verbose("Loaded opengl shared library: %s\n", stemp ? stemp : "<default>");
- /* FIXME: must be freed as well */
-#endif
-#endif
-#ifdef USE_DISPATCH_GL
- gl_dispatch = global_alloc(osd_gl_dispatch);
-#endif
- s_dll_loaded = true;
- }
-}
-
void renderer_ogl::initialize_gl()
{
int has_and_allow_texturerect = 0;
@@ -420,7 +610,7 @@ void renderer_ogl::initialize_gl()
m_usefbo = 0;
m_useglsl = 0;
- if (video_config.allowtexturerect && (strstr(extstr, "GL_ARB_texture_rectangle") || strstr(extstr, "GL_EXT_texture_rectangle")))
+ if (m_ogl_config.allowtexturerect && (strstr(extstr, "GL_ARB_texture_rectangle") || strstr(extstr, "GL_EXT_texture_rectangle")))
{
has_and_allow_texturerect = 1;
if (!s_shown_video_info)
@@ -430,7 +620,7 @@ void renderer_ogl::initialize_gl()
}
// does this card support non-power-of-two sized textures? (they're faster, so use them if possible)
- if ( !video_config.forcepow2texture && strstr(extstr, "GL_ARB_texture_non_power_of_two"))
+ if ( !m_ogl_config.forcepow2texture && strstr(extstr, "GL_ARB_texture_non_power_of_two"))
{
if (!s_shown_video_info)
{
@@ -460,7 +650,7 @@ void renderer_ogl::initialize_gl()
if (strstr(extstr, "GL_ARB_vertex_buffer_object"))
{
- m_usevbo = video_config.vbo;
+ m_usevbo = m_ogl_config.vbo;
if (!s_shown_video_info)
{
if(m_usevbo)
@@ -474,7 +664,7 @@ void renderer_ogl::initialize_gl()
{
if( m_usevbo )
{
- m_usepbo = video_config.pbo;
+ m_usepbo = m_ogl_config.pbo;
if (!s_shown_video_info)
{
if(m_usepbo)
@@ -517,7 +707,7 @@ void renderer_ogl::initialize_gl()
strstr(extstr, "GL_ARB_fragment_shader")
)
{
- m_useglsl = video_config.glsl;
+ m_useglsl = m_ogl_config.glsl;
if (!s_shown_video_info)
{
if(m_useglsl)
@@ -557,24 +747,22 @@ void renderer_ogl::initialize_gl()
int renderer_ogl::create()
{
- auto win = assert_window();
-
// create renderer
#if defined(OSD_WINDOWS)
- m_gl_context = global_alloc(win_gl_context(std::static_pointer_cast<win_window_info>(win)->platform_window()));
+ m_gl_context.reset(new win_gl_context(dynamic_cast<win_window_info &>(window()).platform_window()));
#elif defined(OSD_MAC)
// TODO
-// m_gl_context = global_alloc(mac_gl_context(std::static_pointer_cast<mac_window_info>(win)->platform_window()));
+// m_gl_context.reset(new mac_gl_context(dynamic_cast<mac_window_info &>(window()).platform_window()));
#else
- m_gl_context = global_alloc(sdl_gl_context(std::static_pointer_cast<sdl_window_info>(win)->platform_window()));
+ m_gl_context.reset(new sdl_gl_context(dynamic_cast<sdl_window_info &>(window()).platform_window()));
#endif
- if (m_gl_context->LastErrorMsg() != nullptr)
+ if (!*m_gl_context)
{
- osd_printf_error("%s\n", m_gl_context->LastErrorMsg());
+ char const *const msg = m_gl_context->last_error_message();
+ osd_printf_error("Creating OpenGL context failed: %s\n", msg ? msg : "unknown error");
return 1;
}
- m_gl_context->SetSwapInterval(video_config.waitvsync ? 1 : 0);
-
+ m_gl_context->set_swap_interval(video_config.waitvsync ? 1 : 0);
m_blittimer = 0;
m_surf_w = 0;
@@ -590,10 +778,9 @@ int renderer_ogl::create()
/* load any GL function addresses
* this must be done here because we need a context
*/
- loadgl_functions(m_gl_context);
+ loadgl_functions();
initialize_gl();
-
m_init_context = 0;
osd_printf_verbose("Leave renderer_ogl::create\n");
@@ -623,27 +810,15 @@ int renderer_ogl::xy_to_render_target(int x, int y, int *xt, int *yt)
void renderer_ogl::destroy_all_textures()
{
- ogl_texture_info *texture = nullptr;
- bool lock=false;
- int i;
-
- if ( !m_initialized )
- return;
-
- auto win = try_getwindow();
- // During destroy this can get called
- // and the window is no longer available
- if (win == nullptr)
+ if (!m_initialized)
return;
- m_gl_context->MakeCurrent();
+ m_gl_context->make_current();
- if(win->m_primlist)
- {
- lock=true;
- win->m_primlist->acquire_lock();
- }
+ bool const lock = bool(window().m_primlist);
+ if (lock)
+ window().m_primlist->acquire_lock();
glFinish();
@@ -651,60 +826,54 @@ void renderer_ogl::destroy_all_textures()
glFinish();
glDisableClientState(GL_VERTEX_ARRAY);
- i=0;
- while (i<HASH_SIZE+OVERFLOW_SIZE)
+ for (int i = 0; i < (HASH_SIZE + OVERFLOW_SIZE); ++i)
{
- texture = m_texhash[i];
- m_texhash[i] = nullptr;
- if (texture != nullptr)
+ ogl_texture_info *const texture = std::exchange(m_texhash[i], nullptr);
+ if (texture)
{
- if(m_usevbo)
+ if (m_usevbo)
{
- pfn_glDeleteBuffers( 1, &(texture->texCoordBufferName) );
+ m_glDeleteBuffers( 1, &(texture->texCoordBufferName) );
texture->texCoordBufferName=0;
}
- if(m_usepbo && texture->pbo)
+ if (m_usepbo && texture->pbo)
{
- pfn_glDeleteBuffers( 1, (GLuint *)&(texture->pbo) );
+ m_glDeleteBuffers( 1, (GLuint *)&(texture->pbo) );
texture->pbo=0;
}
- if( m_glsl_program_num > 1 )
+ if (m_glsl_program_num > 1)
{
assert(m_usefbo);
- pfn_glDeleteFramebuffers(2, (GLuint *)&texture->mpass_fbo_mamebm[0]);
+ m_glDeleteFramebuffers(2, (GLuint *)&texture->mpass_fbo_mamebm[0]);
glDeleteTextures(2, (GLuint *)&texture->mpass_texture_mamebm[0]);
}
- if ( m_glsl_program_mb2sc < m_glsl_program_num - 1 )
+ if (m_glsl_program_mb2sc < m_glsl_program_num - 1)
{
assert(m_usefbo);
- pfn_glDeleteFramebuffers(2, (GLuint *)&texture->mpass_fbo_scrn[0]);
+ m_glDeleteFramebuffers(2, (GLuint *)&texture->mpass_fbo_scrn[0]);
glDeleteTextures(2, (GLuint *)&texture->mpass_texture_scrn[0]);
}
glDeleteTextures(1, (GLuint *)&texture->texture);
- if ( texture->data_own )
+ if (texture->data_own)
{
free(texture->data);
texture->data=nullptr;
texture->data_own=false;
}
- global_free(texture);
+ delete texture;
}
- i++;
- }
- if ( m_useglsl )
- {
- glsl_shader_free(m_glsl);
- m_glsl = nullptr;
}
+ m_shader_tool.reset();
+
m_initialized = 0;
if (lock)
- win->m_primlist->release_lock();
+ window().m_primlist->release_lock();
}
//============================================================
// loadGLExtensions
@@ -740,178 +909,138 @@ void renderer_ogl::loadGLExtensions()
// Get Pointers To The GL Functions
// VBO:
- if( m_usevbo )
+ if (m_usevbo)
{
- pfn_glGenBuffers = (PFNGLGENBUFFERSPROC) m_gl_context->getProcAddress("glGenBuffers");
- pfn_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) m_gl_context->getProcAddress("glDeleteBuffers");
- pfn_glBindBuffer = (PFNGLBINDBUFFERPROC) m_gl_context->getProcAddress("glBindBuffer");
- pfn_glBufferData = (PFNGLBUFFERDATAPROC) m_gl_context->getProcAddress("glBufferData");
- pfn_glBufferSubData = (PFNGLBUFFERSUBDATAPROC) m_gl_context->getProcAddress("glBufferSubData");
+ m_gl_context->get_proc_address(m_glGenBuffers, "glGenBuffers");
+ m_gl_context->get_proc_address(m_glDeleteBuffers, "glDeleteBuffers");
+ m_gl_context->get_proc_address(m_glBindBuffer, "glBindBuffer");
+ m_gl_context->get_proc_address(m_glBufferData, "glBufferData");
+ m_gl_context->get_proc_address(m_glBufferSubData, "glBufferSubData");
}
// PBO:
- if ( m_usepbo )
+ if (m_usepbo)
{
- pfn_glMapBuffer = (PFNGLMAPBUFFERPROC) m_gl_context->getProcAddress("glMapBuffer");
- pfn_glUnmapBuffer= (PFNGLUNMAPBUFFERPROC) m_gl_context->getProcAddress("glUnmapBuffer");
+ m_gl_context->get_proc_address(m_glMapBuffer, "glMapBuffer");
+ m_gl_context->get_proc_address(m_glUnmapBuffer, "glUnmapBuffer");
}
// FBO:
- if ( m_usefbo )
+ if (m_usefbo)
{
- pfn_glIsFramebuffer = (PFNGLISFRAMEBUFFEREXTPROC) m_gl_context->getProcAddress("glIsFramebufferEXT");
- pfn_glBindFramebuffer = (PFNGLBINDFRAMEBUFFEREXTPROC) m_gl_context->getProcAddress("glBindFramebufferEXT");
- pfn_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSEXTPROC) m_gl_context->getProcAddress("glDeleteFramebuffersEXT");
- pfn_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSEXTPROC) m_gl_context->getProcAddress("glGenFramebuffersEXT");
- pfn_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) m_gl_context->getProcAddress("glCheckFramebufferStatusEXT");
- pfn_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) m_gl_context->getProcAddress("glFramebufferTexture2DEXT");
+ m_gl_context->get_proc_address(m_glIsFramebuffer, "glIsFramebufferEXT");
+ m_gl_context->get_proc_address(m_glBindFramebuffer, "glBindFramebufferEXT");
+ m_gl_context->get_proc_address(m_glDeleteFramebuffers, "glDeleteFramebuffersEXT");
+ m_gl_context->get_proc_address(m_glGenFramebuffers, "glGenFramebuffersEXT");
+ m_gl_context->get_proc_address(m_glCheckFramebufferStatus, "glCheckFramebufferStatusEXT");
+ m_gl_context->get_proc_address(m_glFramebufferTexture2D, "glFramebufferTexture2DEXT");
}
- if ( m_usevbo &&
- ( !pfn_glGenBuffers || !pfn_glDeleteBuffers ||
- !pfn_glBindBuffer || !pfn_glBufferData || !pfn_glBufferSubData
- ) )
+ if (m_usevbo && (!m_glGenBuffers || !m_glDeleteBuffers || !m_glBindBuffer || !m_glBufferData || !m_glBufferSubData))
{
- m_usepbo=false;
+ m_usepbo = false;
if (_once)
{
- osd_printf_warning("OpenGL: VBO not supported, missing: ");
- if (!pfn_glGenBuffers)
- {
- osd_printf_warning("glGenBuffers, ");
- }
- if (!pfn_glDeleteBuffers)
- {
- osd_printf_warning("glDeleteBuffers");
- }
- if (!pfn_glBindBuffer)
- {
- osd_printf_warning("glBindBuffer, ");
- }
- if (!pfn_glBufferData)
- {
- osd_printf_warning("glBufferData, ");
- }
- if (!pfn_glBufferSubData)
- {
- osd_printf_warning("glBufferSubData, ");
- }
+ osd_printf_warning("OpenGL: VBO not supported, missing:");
+ if (!m_glGenBuffers)
+ osd_printf_warning(" glGenBuffers");
+ if (!m_glDeleteBuffers)
+ osd_printf_warning(" glDeleteBuffers");
+ if (!m_glBindBuffer)
+ osd_printf_warning(" glBindBuffer");
+ if (!m_glBufferData)
+ osd_printf_warning(" glBufferData");
+ if (!m_glBufferSubData)
+ osd_printf_warning(" glBufferSubData");
osd_printf_warning("\n");
}
- if ( m_usevbo )
+ if (m_usevbo)
{
if (_once)
- {
osd_printf_warning("OpenGL: PBO not supported, no VBO support.\n");
- }
- m_usepbo=false;
+ m_usepbo = false;
}
}
- if ( m_usepbo && ( !pfn_glMapBuffer || !pfn_glUnmapBuffer ) )
+ if (m_usepbo && (!m_glMapBuffer || !m_glUnmapBuffer))
{
- m_usepbo=false;
+ m_usepbo = false;
if (_once)
{
- osd_printf_warning("OpenGL: PBO not supported, missing: ");
- if (!pfn_glMapBuffer)
- {
- osd_printf_warning("glMapBuffer, ");
- }
- if (!pfn_glUnmapBuffer)
- {
- osd_printf_warning("glUnmapBuffer, ");
- }
+ osd_printf_warning("OpenGL: PBO not supported, missing:");
+ if (!m_glMapBuffer)
+ osd_printf_warning(" glMapBuffer");
+ if (!m_glUnmapBuffer)
+ osd_printf_warning(" glUnmapBuffer");
osd_printf_warning("\n");
}
}
if ( m_usefbo &&
- ( !pfn_glIsFramebuffer || !pfn_glBindFramebuffer || !pfn_glDeleteFramebuffers ||
- !pfn_glGenFramebuffers || !pfn_glCheckFramebufferStatus || !pfn_glFramebufferTexture2D
+ ( !m_glIsFramebuffer || !m_glBindFramebuffer || !m_glDeleteFramebuffers ||
+ !m_glGenFramebuffers || !m_glCheckFramebufferStatus || !m_glFramebufferTexture2D
))
{
- m_usefbo=false;
+ m_usefbo = false;
if (_once)
{
- osd_printf_warning("OpenGL: FBO not supported, missing: ");
- if (!pfn_glIsFramebuffer)
- {
- osd_printf_warning("pfn_glIsFramebuffer, ");
- }
- if (!pfn_glBindFramebuffer)
- {
- osd_printf_warning("pfn_glBindFramebuffer, ");
- }
- if (!pfn_glDeleteFramebuffers)
- {
- osd_printf_warning("pfn_glDeleteFramebuffers, ");
- }
- if (!pfn_glGenFramebuffers)
- {
- osd_printf_warning("pfn_glGenFramebuffers, ");
- }
- if (!pfn_glCheckFramebufferStatus)
- {
- osd_printf_warning("pfn_glCheckFramebufferStatus, ");
- }
- if (!pfn_glFramebufferTexture2D)
- {
- osd_printf_warning("pfn_glFramebufferTexture2D, ");
- }
+ osd_printf_warning("OpenGL: FBO not supported, missing:");
+ if (!m_glIsFramebuffer)
+ osd_printf_warning(" m_glIsFramebuffer");
+ if (!m_glBindFramebuffer)
+ osd_printf_warning(" m_glBindFramebuffer");
+ if (!m_glDeleteFramebuffers)
+ osd_printf_warning(" m_glDeleteFramebuffers");
+ if (!m_glGenFramebuffers)
+ osd_printf_warning(" m_glGenFramebuffers");
+ if (!m_glCheckFramebufferStatus)
+ osd_printf_warning(" m_glCheckFramebufferStatus");
+ if (!m_glFramebufferTexture2D)
+ osd_printf_warning(" m_glFramebufferTexture2D");
osd_printf_warning("\n");
}
}
if (_once)
{
- if ( m_usevbo )
- {
+ if (m_usevbo)
osd_printf_verbose("OpenGL: VBO supported\n");
- }
else
- {
osd_printf_warning("OpenGL: VBO not supported\n");
- }
- if ( m_usepbo )
- {
+ if (m_usepbo)
osd_printf_verbose("OpenGL: PBO supported\n");
- }
else
- {
osd_printf_warning("OpenGL: PBO not supported\n");
- }
- if ( m_usefbo )
- {
+ if (m_usefbo)
osd_printf_verbose("OpenGL: FBO supported\n");
- }
else
- {
osd_printf_warning("OpenGL: FBO not supported\n");
- }
}
- if ( m_useglsl )
+ if (m_useglsl)
{
#if defined(GL_ARB_multitexture) && !defined(OSD_MAC)
- pfn_glActiveTexture = (PFNGLACTIVETEXTUREARBPROC) m_gl_context->getProcAddress("glActiveTextureARB");
+ m_gl_context->get_proc_address(m_glActiveTexture, "glActiveTextureARB");
#else
- pfn_glActiveTexture = (PFNGLACTIVETEXTUREPROC) m_gl_context->getProcAddress("glActiveTexture");
+ m_gl_context->get_proc_address(m_glActiveTexture, "glActiveTexture");
#endif
- if (!pfn_glActiveTexture)
+ if (!m_glActiveTexture)
{
if (_once)
- {
osd_printf_warning("OpenGL: GLSL disabled, glActiveTexture(ARB) not supported\n");
- }
m_useglsl = 0;
}
}
- if ( m_useglsl )
+ if (m_useglsl)
{
- m_glsl = glsl_shader_init(m_gl_context);
- m_useglsl = (m_glsl != nullptr ? 1 : 0);
+ m_shader_tool = glsl_shader_info::init(
+ *m_gl_context
+#if defined(USE_DISPATCH_GL)
+ , gl_dispatch.get()
+#endif
+ );
+ m_useglsl = (m_shader_tool ? 1 : 0);
if ( ! m_useglsl )
{
@@ -922,9 +1051,9 @@ void renderer_ogl::loadGLExtensions()
}
}
- if ( m_useglsl )
+ if (m_useglsl)
{
- if (assert_window()->prescale() != 1 )
+ if (window().prescale() != 1 )
{
m_useglsl = 0;
if (_once)
@@ -934,15 +1063,14 @@ void renderer_ogl::loadGLExtensions()
}
}
- if ( m_useglsl )
+ if (m_useglsl)
{
- int i;
video_config.filter = false;
- glsl_shader_feature = GLSL_SHADER_FEAT_PLAIN;
+ glsl_shader_feature = glsl_shader_info::FEAT_PLAIN;
m_glsl_program_num = 0;
m_glsl_program_mb2sc = 0;
- for(i=0; i<video_config.glsl_shader_mamebm_num; i++)
+ for (int i=0; i<m_ogl_config.glsl_shader_mamebm_num; i++)
{
if ( !m_usefbo && m_glsl_program_num==1 )
{
@@ -953,60 +1081,65 @@ void renderer_ogl::loadGLExtensions()
break;
}
- if ( glsl_shader_add_mamebm(m_glsl, video_config.glsl_shader_mamebm[i], m_glsl_program_num) )
+ if ( m_shader_tool->add_mamebm(m_ogl_config.glsl_shader_mamebm[i].c_str(), m_glsl_program_num) )
{
osd_printf_error("OpenGL: GLSL loading mame bitmap shader %d failed (%s)\n",
- i, video_config.glsl_shader_mamebm[i]);
- } else {
- glsl_shader_feature = GLSL_SHADER_FEAT_CUSTOM;
+ i, m_ogl_config.glsl_shader_mamebm[i]);
+ }
+ else
+ {
+ glsl_shader_feature = glsl_shader_info::FEAT_CUSTOM;
if (_once)
{
osd_printf_verbose("OpenGL: GLSL using mame bitmap shader filter %d: '%s'\n",
- m_glsl_program_num, video_config.glsl_shader_mamebm[i]);
+ m_glsl_program_num, m_ogl_config.glsl_shader_mamebm[i]);
}
m_glsl_program_mb2sc = m_glsl_program_num; // the last mame_bitmap (mb) shader does it.
m_glsl_program_num++;
}
}
- if ( video_config.glsl_shader_scrn_num > 0 && m_glsl_program_num==0 )
+ if ( m_ogl_config.glsl_shader_scrn_num > 0 && m_glsl_program_num==0 )
{
osd_printf_verbose("OpenGL: GLSL cannot use screen bitmap shader without bitmap shader\n");
}
- for(i=0; m_usefbo && m_glsl_program_num>0 && i<video_config.glsl_shader_scrn_num; i++)
+ for(int i=0; m_usefbo && m_glsl_program_num>0 && i<m_ogl_config.glsl_shader_scrn_num; i++)
{
- if ( glsl_shader_add_scrn(m_glsl, video_config.glsl_shader_scrn[i],
- m_glsl_program_num-1-m_glsl_program_mb2sc) )
+ if ( m_shader_tool->add_scrn(m_ogl_config.glsl_shader_scrn[i].c_str(), m_glsl_program_num-1-m_glsl_program_mb2sc) )
{
osd_printf_error("OpenGL: GLSL loading screen bitmap shader %d failed (%s)\n",
- i, video_config.glsl_shader_scrn[i]);
- } else {
+ i, m_ogl_config.glsl_shader_scrn[i]);
+ }
+ else
+ {
if (_once)
{
osd_printf_verbose("OpenGL: GLSL using screen bitmap shader filter %d: '%s'\n",
- m_glsl_program_num, video_config.glsl_shader_scrn[i]);
+ m_glsl_program_num, m_ogl_config.glsl_shader_scrn[i]);
}
m_glsl_program_num++;
}
}
if ( 0==m_glsl_program_num &&
- 0 <= video_config.glsl_filter && video_config.glsl_filter < GLSL_SHADER_FEAT_INT_NUMBER )
+ 0 <= m_ogl_config.glsl_filter && m_ogl_config.glsl_filter < glsl_shader_info::FEAT_INT_NUMBER )
{
m_glsl_program_mb2sc = m_glsl_program_num; // the last mame_bitmap (mb) shader does it.
m_glsl_program_num++;
- glsl_shader_feature = video_config.glsl_filter;
+ glsl_shader_feature = m_ogl_config.glsl_filter;
if (_once)
{
osd_printf_verbose("OpenGL: GLSL using shader filter '%s', idx: %d, num %d (vid filter: %d)\n",
- glsl_shader_get_filter_name_mamebm(glsl_shader_feature),
+ m_shader_tool->get_filter_name_mamebm(glsl_shader_feature),
glsl_shader_feature, m_glsl_program_num, video_config.filter);
}
}
- } else {
+ }
+ else
+ {
if (_once)
{
osd_printf_verbose("OpenGL: using vid filter: %d\n", video_config.filter);
@@ -1026,16 +1159,7 @@ int renderer_ogl::draw(const int update)
float vofs, hofs;
int pendingPrimitive=GL_NO_PRIMITIVE, curPrimitive=GL_NO_PRIMITIVE;
-#ifdef TOBEMIGRATED
- if (video_config.novideo)
- {
- return 0;
- }
-#endif
-
- auto win = assert_window();
-
- osd_dim wdim = win->get_size();
+ osd_dim wdim = window().get_size();
if (has_flags(FI_CHANGED) || (wdim.width() != m_width) || (wdim.height() != m_height))
{
@@ -1047,7 +1171,7 @@ int renderer_ogl::draw(const int update)
clear_flags(FI_CHANGED);
}
- m_gl_context->MakeCurrent();
+ m_gl_context->make_current();
if (m_init_context)
{
@@ -1116,7 +1240,42 @@ int renderer_ogl::draw(const int update)
// |_________|
// (0,h) (w,h)
- glViewport(0.0, 0.0, (GLsizei) m_width, (GLsizei) m_height);
+ GLsizei iScale = 1;
+
+ /*
+ Mac hack: macOS version 10.15 and later flipped from assuming you don't support Retina to
+ assuming you do support Retina. SDL 2.0.11 is scheduled to fix this, but it's not out yet.
+ So we double-scale everything if you're on 10.15 or later and SDL is not at least version 2.0.11.
+ */
+ #if defined(SDLMAME_MACOSX) && !defined(OSD_MAC)
+ SDL_version sdlVers;
+ SDL_GetVersion(&sdlVers);
+ // Only do this if SDL is not at least 2.0.11.
+ if ((sdlVers.major == 2) && (sdlVers.minor == 0) && (sdlVers.patch < 11))
+ #endif
+ #if defined(SDLMAME_MACOSX) || defined(OSD_MAC)
+ {
+ // now get the Darwin kernel version
+ int dMaj, dMin, dPatch;
+ char versStr[64];
+ dMaj = dMin = dPatch = 0;
+ size_t size = sizeof(versStr);
+ int retVal = sysctlbyname("kern.osrelease", versStr, &size, NULL, 0);
+ if (retVal == 0)
+ {
+ sscanf(versStr, "%d.%d.%d", &dMaj, &dMin, &dPatch);
+ // 10.15 Catalina is Darwin version 19
+ if (dMaj >= 19)
+ {
+ // do the workaround for Retina being forced on
+ osd_printf_verbose("OpenGL: enabling Retina workaround\n");
+ iScale = 2;
+ }
+ }
+ }
+ #endif
+
+ glViewport(0.0, 0.0, (GLsizei) m_width * iScale, (GLsizei) m_height * iScale);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, (GLdouble) m_width, (GLdouble) m_height, 0.0, 0.0, -1.0);
@@ -1152,16 +1311,15 @@ int renderer_ogl::draw(const int update)
hofs = (cw - m_blit_dim.width()) / 2.0f;
}
}
-#else
#endif
m_last_hofs = hofs;
m_last_vofs = vofs;
- win->m_primlist->acquire_lock();
+ window().m_primlist->acquire_lock();
// now draw
- for (render_primitive &prim : *win->m_primlist)
+ for (render_primitive &prim : *window().m_primlist)
{
int i;
@@ -1196,6 +1354,10 @@ int renderer_ogl::draw(const int update)
if(pendingPrimitive!=curPrimitive)
{
+ if (curPrimitive==GL_POINTS)
+ glPointSize(prim.width);
+ else
+ glLineWidth(prim.width);
glBegin(curPrimitive);
pendingPrimitive=curPrimitive;
}
@@ -1212,11 +1374,6 @@ int renderer_ogl::draw(const int update)
}
#else
{
- const line_aa_step *step = line_aa_4step;
- render_bounds b0, b1;
- float r, g, b, a;
- float effwidth;
-
// we're not gonna play fancy here. close anything pending and let's go.
if (pendingPrimitive!=GL_NO_PRIMITIVE && pendingPrimitive!=curPrimitive)
{
@@ -1227,12 +1384,10 @@ int renderer_ogl::draw(const int update)
set_blendmode(sdl, PRIMFLAG_GET_BLENDMODE(prim.flags));
// compute the effective width based on the direction of the line
- effwidth = prim.width();
- if (effwidth < 0.5f)
- effwidth = 0.5f;
+ float effwidth = std::max(prim.width(), 0.5f);
// determine the bounds of a quad to draw this line
- render_line_to_quad(&prim.bounds, effwidth, 0.0f, &b0, &b1);
+ auto [b0, b1] = render_line_to_quad(prim.bounds, effwidth, 0.0f);
// fix window position
b0.x0 += hofs;
@@ -1245,7 +1400,7 @@ int renderer_ogl::draw(const int update)
b1.y1 += vofs;
// iterate over AA steps
- for (step = PRIMFLAG_GET_ANTIALIAS(prim.flags) ? line_aa_4step : line_aa_1step; step->weight != 0; step++)
+ for (const line_aa_step *step = PRIMFLAG_GET_ANTIALIAS(prim.flags) ? line_aa_4step : line_aa_1step; step->weight != 0; step++)
{
glBegin(GL_TRIANGLE_STRIP);
@@ -1262,14 +1417,10 @@ int renderer_ogl::draw(const int update)
glVertex2f(b1.x1 + step->xoffs, b1.y1 + step->yoffs);
// determine the color of the line
- r = (prim.color.r * step->weight);
- g = (prim.color.g * step->weight);
- b = (prim.color.b * step->weight);
- a = (prim.color.a * 255.0f);
- if (r > 1.0) r = 1.0;
- if (g > 1.0) g = 1.0;
- if (b > 1.0) b = 1.0;
- if (a > 1.0) a = 1.0;
+ float r = std::min(prim.color.r * step->weight, 1.0f);
+ float g = std::min(prim.color.g * step->weight, 1.0f);
+ float b = std::min(prim.color.b * step->weight, 1.0f);
+ float a = std::min(prim.color.a * 255.0f, 1.0f);
glColor4f(r, g, b, a);
// texture = texture_update(window, &prim, 0);
@@ -1377,10 +1528,10 @@ int renderer_ogl::draw(const int update)
pendingPrimitive=GL_NO_PRIMITIVE;
}
- win->m_primlist->release_lock();
+ window().m_primlist->release_lock();
m_init_context = 0;
- m_gl_context->SwapBuffer();
+ m_gl_context->swap_buffer();
return 0;
}
@@ -1513,9 +1664,8 @@ void renderer_ogl::texture_compute_size_subroutine(ogl_texture_info *texture, ui
while (texture->yprescale > 1 && height_create * texture->yprescale > m_texture_max_height)
texture->yprescale--;
- auto win = assert_window();
- if (PRIMFLAG_GET_SCREENTEX(flags) && (texture->xprescale != win->prescale() || texture->yprescale != win->prescale()))
- osd_printf_warning("SDL: adjusting prescale from %dx%d to %dx%d\n", win->prescale(), win->prescale(), texture->xprescale, texture->yprescale);
+ if (PRIMFLAG_GET_SCREENTEX(flags) && (texture->xprescale != window().prescale() || texture->yprescale != window().prescale()))
+ osd_printf_warning("SDL: adjusting prescale from %dx%d to %dx%d\n", window().prescale(), window().prescale(), texture->xprescale, texture->yprescale);
width *= texture->xprescale;
height *= texture->yprescale;
@@ -1610,10 +1760,9 @@ void renderer_ogl::texture_compute_size_type(const render_texinfo *texsource, og
// texture_create
//============================================================
-static int gl_checkFramebufferStatus(void)
+int renderer_ogl::gl_checkFramebufferStatus() const
{
- GLenum status;
- status=(GLenum)pfn_glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
+ GLenum const status = (GLenum)m_glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
switch(status) {
case GL_FRAMEBUFFER_COMPLETE_EXT:
return 0;
@@ -1653,14 +1802,14 @@ static int gl_checkFramebufferStatus(void)
return -1;
}
-static int texture_fbo_create(uint32_t text_unit, uint32_t text_name, uint32_t fbo_name, int width, int height)
+int renderer_ogl::texture_fbo_create(uint32_t text_unit, uint32_t text_name, uint32_t fbo_name, int width, int height) const
{
- pfn_glActiveTexture(text_unit);
- pfn_glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo_name);
+ m_glActiveTexture(text_unit);
+ m_glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo_name);
glBindTexture(GL_TEXTURE_2D, text_name);
{
GLint _width, _height;
- if ( gl_texture_check_size(GL_TEXTURE_2D, 0, GL_RGBA8, width, height,
+ if ( m_shader_tool->texture_check_size(GL_TEXTURE_2D, 0, GL_RGBA8, width, height,
0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, &_width, &_height, 1) )
{
osd_printf_error("cannot create fbo texture, req: %dx%d, avail: %dx%d - bail out\n",
@@ -1675,10 +1824,10 @@ static int texture_fbo_create(uint32_t text_unit, uint32_t text_name, uint32_t f
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- pfn_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ m_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, text_name, 0);
if ( gl_checkFramebufferStatus() )
@@ -1715,51 +1864,49 @@ int renderer_ogl::texture_shader_create(const render_texinfo *texsource, ogl_tex
for(i=0; i<m_glsl_program_num; i++)
{
if ( i<=m_glsl_program_mb2sc )
- {
- m_glsl_program[i] = glsl_shader_get_program_mamebm(glsl_shader_feature, i);
- } else {
- m_glsl_program[i] = glsl_shader_get_program_scrn(i-1-m_glsl_program_mb2sc);
- }
- pfn_glUseProgramObjectARB(m_glsl_program[i]);
+ m_glsl_program[i] = m_shader_tool->get_program_mamebm(glsl_shader_feature, i);
+ else
+ m_glsl_program[i] = m_shader_tool->get_program_scrn(i-1-m_glsl_program_mb2sc);
+ m_shader_tool->pfn_glUseProgramObjectARB(m_glsl_program[i]);
if ( i<=m_glsl_program_mb2sc )
{
// GL_TEXTURE0 GLSL Uniforms
- uniform_location = pfn_glGetUniformLocationARB(m_glsl_program[i], "color_texture");
- pfn_glUniform1iARB(uniform_location, 0);
+ uniform_location = m_shader_tool->pfn_glGetUniformLocationARB(m_glsl_program[i], "color_texture");
+ m_shader_tool->pfn_glUniform1iARB(uniform_location, 0);
GL_CHECK_ERROR_NORMAL();
}
{
GLfloat color_texture_sz[2] = { (GLfloat)texture->rawwidth, (GLfloat)texture->rawheight };
- uniform_location = pfn_glGetUniformLocationARB(m_glsl_program[i], "color_texture_sz");
- pfn_glUniform2fvARB(uniform_location, 1, &(color_texture_sz[0]));
+ uniform_location = m_shader_tool->pfn_glGetUniformLocationARB(m_glsl_program[i], "color_texture_sz");
+ m_shader_tool->pfn_glUniform2fvARB(uniform_location, 1, &(color_texture_sz[0]));
GL_CHECK_ERROR_NORMAL();
}
GLfloat color_texture_pow2_sz[2] = { (GLfloat)texture->rawwidth_create, (GLfloat)texture->rawheight_create };
- uniform_location = pfn_glGetUniformLocationARB(m_glsl_program[i], "color_texture_pow2_sz");
- pfn_glUniform2fvARB(uniform_location, 1, &(color_texture_pow2_sz[0]));
+ uniform_location = m_shader_tool->pfn_glGetUniformLocationARB(m_glsl_program[i], "color_texture_pow2_sz");
+ m_shader_tool->pfn_glUniform2fvARB(uniform_location, 1, &(color_texture_pow2_sz[0]));
GL_CHECK_ERROR_NORMAL();
GLfloat screen_texture_sz[2] = { (GLfloat) m_blit_dim.width(), (GLfloat) m_blit_dim.height() };
- uniform_location = pfn_glGetUniformLocationARB(m_glsl_program[i], "screen_texture_sz");
- pfn_glUniform2fvARB(uniform_location, 1, &(screen_texture_sz[0]));
+ uniform_location = m_shader_tool->pfn_glGetUniformLocationARB(m_glsl_program[i], "screen_texture_sz");
+ m_shader_tool->pfn_glUniform2fvARB(uniform_location, 1, &(screen_texture_sz[0]));
GL_CHECK_ERROR_NORMAL();
GLfloat screen_texture_pow2_sz[2] = { (GLfloat)surf_w_pow2, (GLfloat)surf_h_pow2 };
- uniform_location = pfn_glGetUniformLocationARB(m_glsl_program[i], "screen_texture_pow2_sz");
- pfn_glUniform2fvARB(uniform_location, 1, &(screen_texture_pow2_sz[0]));
+ uniform_location = m_shader_tool->pfn_glGetUniformLocationARB(m_glsl_program[i], "screen_texture_pow2_sz");
+ m_shader_tool->pfn_glUniform2fvARB(uniform_location, 1, &(screen_texture_pow2_sz[0]));
GL_CHECK_ERROR_NORMAL();
}
- pfn_glUseProgramObjectARB(m_glsl_program[0]); // start with 1st shader
+ m_shader_tool->pfn_glUseProgramObjectARB(m_glsl_program[0]); // start with 1st shader
if( m_glsl_program_num > 1 )
{
// multipass mode
// GL_TEXTURE2/GL_TEXTURE3
- pfn_glGenFramebuffers(2, (GLuint *)&texture->mpass_fbo_mamebm[0]);
+ m_glGenFramebuffers(2, (GLuint *)&texture->mpass_fbo_mamebm[0]);
glGenTextures(2, (GLuint *)&texture->mpass_texture_mamebm[0]);
for (i=0; i<2; i++)
@@ -1773,7 +1920,7 @@ int renderer_ogl::texture_shader_create(const render_texinfo *texsource, ogl_tex
}
}
- pfn_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
+ m_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
osd_printf_verbose("GL texture: mpass mame-bmp 2x %dx%d (pow2 %dx%d)\n",
texture->rawwidth, texture->rawheight, texture->rawwidth_create, texture->rawheight_create);
@@ -1783,7 +1930,7 @@ int renderer_ogl::texture_shader_create(const render_texinfo *texsource, ogl_tex
{
// multipass mode
// GL_TEXTURE2/GL_TEXTURE3
- pfn_glGenFramebuffers(2, (GLuint *)&texture->mpass_fbo_scrn[0]);
+ m_glGenFramebuffers(2, (GLuint *)&texture->mpass_fbo_scrn[0]);
glGenTextures(2, (GLuint *)&texture->mpass_texture_scrn[0]);
for (i=0; i<2; i++)
@@ -1804,14 +1951,14 @@ int renderer_ogl::texture_shader_create(const render_texinfo *texsource, ogl_tex
// GL_TEXTURE0
// get a name for this texture
glGenTextures(1, (GLuint *)&texture->texture);
- pfn_glActiveTexture(GL_TEXTURE0);
+ m_glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture->texture);
glPixelStorei(GL_UNPACK_ROW_LENGTH, texture->rawwidth_create);
uint32_t * dummy = nullptr;
GLint _width, _height;
- if ( gl_texture_check_size(GL_TEXTURE_2D, 0, GL_RGBA8,
+ if ( m_shader_tool->texture_check_size(GL_TEXTURE_2D, 0, GL_RGBA8,
texture->rawwidth_create, texture->rawheight_create,
0,
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
@@ -1833,7 +1980,7 @@ int renderer_ogl::texture_shader_create(const render_texinfo *texsource, ogl_tex
if ((PRIMFLAG_GET_SCREENTEX(flags)) && video_config.filter)
{
- assert( glsl_shader_feature == GLSL_SHADER_FEAT_PLAIN );
+ assert( glsl_shader_feature == glsl_shader_info::FEAT_PLAIN );
// screen textures get the user's choice of filtering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -1854,8 +2001,8 @@ int renderer_ogl::texture_shader_create(const render_texinfo *texsource, ogl_tex
}
else
{
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
GL_CHECK_ERROR_NORMAL();
@@ -1868,7 +2015,11 @@ ogl_texture_info *renderer_ogl::texture_create(const render_texinfo *texsource,
ogl_texture_info *texture;
// allocate a new texture
- texture = global_alloc(ogl_texture_info);
+ texture = new ogl_texture_info(
+#if defined(USE_DISPATCH_GL)
+ gl_dispatch.get()
+#endif
+ );
// fill in the core data
texture->hash = texture_compute_hash(texsource, flags);
@@ -1877,9 +2028,8 @@ ogl_texture_info *renderer_ogl::texture_create(const render_texinfo *texsource,
texture->texinfo.seqid = -1; // force set data
if (PRIMFLAG_GET_SCREENTEX(flags))
{
- auto win = assert_window();
- texture->xprescale = win->prescale();
- texture->yprescale = win->prescale();
+ texture->xprescale = window().prescale();
+ texture->yprescale = window().prescale();
}
else
{
@@ -1933,14 +2083,14 @@ ogl_texture_info *renderer_ogl::texture_create(const render_texinfo *texsource,
if ( texture->type != TEXTURE_TYPE_SHADER && m_useglsl)
{
- pfn_glUseProgramObjectARB(0); // back to fixed function pipeline
+ m_shader_tool->pfn_glUseProgramObjectARB(0); // back to fixed function pipeline
}
if ( texture->type==TEXTURE_TYPE_SHADER )
{
if ( texture_shader_create(texsource, texture, flags) )
{
- global_free(texture);
+ delete texture;
return nullptr;
}
}
@@ -1976,8 +2126,8 @@ ogl_texture_info *renderer_ogl::texture_create(const render_texinfo *texsource,
if( texture->texTarget==GL_TEXTURE_RECTANGLE_ARB )
{
// texture rectangles can't wrap
- glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
- glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} else {
// set wrapping mode appropriately
if (texture->flags & PRIMFLAG_TEXWRAP_MASK)
@@ -1987,8 +2137,8 @@ ogl_texture_info *renderer_ogl::texture_create(const render_texinfo *texsource,
}
else
{
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
}
}
@@ -1998,12 +2148,12 @@ ogl_texture_info *renderer_ogl::texture_create(const render_texinfo *texsource,
assert(m_usepbo);
// create the PBO
- pfn_glGenBuffers(1, (GLuint *)&texture->pbo);
+ m_glGenBuffers(1, (GLuint *)&texture->pbo);
- pfn_glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, texture->pbo);
+ m_glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, texture->pbo);
// set up the PBO dimension, ..
- pfn_glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB,
+ m_glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB,
texture->rawwidth * texture->rawheight * sizeof(uint32_t),
nullptr, GL_STREAM_DRAW);
}
@@ -2033,10 +2183,10 @@ ogl_texture_info *renderer_ogl::texture_create(const render_texinfo *texsource,
if (m_usevbo)
{
// Generate And Bind The Texture Coordinate Buffer
- pfn_glGenBuffers( 1, &(texture->texCoordBufferName) );
- pfn_glBindBuffer( GL_ARRAY_BUFFER_ARB, texture->texCoordBufferName );
+ m_glGenBuffers( 1, &(texture->texCoordBufferName) );
+ m_glBindBuffer( GL_ARRAY_BUFFER_ARB, texture->texCoordBufferName );
// Load The Data
- pfn_glBufferData( GL_ARRAY_BUFFER_ARB, 4*2*sizeof(GLfloat), texture->texCoord, GL_STREAM_DRAW );
+ m_glBufferData( GL_ARRAY_BUFFER_ARB, 4*2*sizeof(GLfloat), texture->texCoord, GL_STREAM_DRAW );
glTexCoordPointer( 2, GL_FLOAT, 0, (char *) nullptr ); // we are using ARB VBO buffers
}
else
@@ -2297,14 +2447,14 @@ static inline void copyline_yuy16_to_argb(uint32_t *dst, const uint16_t *src, in
// texture_set_data
//============================================================
-static void texture_set_data(ogl_texture_info *texture, const render_texinfo *texsource, uint32_t flags)
+void renderer_ogl::texture_set_data(ogl_texture_info *texture, const render_texinfo *texsource, uint32_t flags) const
{
if ( texture->type == TEXTURE_TYPE_DYNAMIC )
{
assert(texture->pbo);
assert(!texture->nocopy);
- texture->data = (uint32_t *) pfn_glMapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY);
+ texture->data = (uint32_t *) m_glMapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY);
}
// note that nocopy and borderpix are mutually exclusive, IOW
@@ -2371,7 +2521,7 @@ static void texture_set_data(ogl_texture_info *texture, const render_texinfo *te
if ( texture->type == TEXTURE_TYPE_SHADER )
{
- pfn_glActiveTexture(GL_TEXTURE0);
+ m_glActiveTexture(GL_TEXTURE0);
glBindTexture(texture->texTarget, texture->texture);
if (texture->nocopy)
@@ -2390,7 +2540,7 @@ static void texture_set_data(ogl_texture_info *texture, const render_texinfo *te
glPixelStorei(GL_UNPACK_ROW_LENGTH, texture->rawwidth);
// unmap the buffer from the CPU space so it can DMA
- pfn_glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB);
+ m_glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB);
// kick off the DMA
glTexSubImage2D(texture->texTarget, 0, 0, 0, texture->rawwidth, texture->rawheight,
@@ -2422,7 +2572,7 @@ static int compare_texture_primitive(const ogl_texture_info *texture, const rend
texture->texinfo.width == prim->texture.width &&
texture->texinfo.height == prim->texture.height &&
texture->texinfo.rowpixels == prim->texture.rowpixels &&
- /* texture->texinfo.palette == prim->texture.palette && */
+ texture->texinfo.palette == prim->texture.palette &&
((texture->flags ^ prim->flags) & (PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)) == 0)
return 1;
else
@@ -2540,12 +2690,12 @@ void renderer_ogl::texture_mpass_flip(ogl_texture_info *texture, int shaderIdx)
if ( shaderIdx>0 )
{
int uniform_location;
- uniform_location = pfn_glGetUniformLocationARB(m_glsl_program[shaderIdx], "mpass_texture");
- pfn_glUniform1iARB(uniform_location, texture->mpass_textureunit[mpass_src_idx]-GL_TEXTURE0);
+ uniform_location = m_shader_tool->pfn_glGetUniformLocationARB(m_glsl_program[shaderIdx], "mpass_texture");
+ m_shader_tool->pfn_glUniform1iARB(uniform_location, texture->mpass_textureunit[mpass_src_idx]-GL_TEXTURE0);
GL_CHECK_ERROR_NORMAL();
}
- pfn_glActiveTexture(texture->mpass_textureunit[mpass_src_idx]);
+ m_glActiveTexture(texture->mpass_textureunit[mpass_src_idx]);
if ( shaderIdx<=m_glsl_program_mb2sc )
{
glBindTexture(texture->texTarget, texture->mpass_texture_mamebm[mpass_src_idx]);
@@ -2554,22 +2704,22 @@ void renderer_ogl::texture_mpass_flip(ogl_texture_info *texture, int shaderIdx)
{
glBindTexture(texture->texTarget, texture->mpass_texture_scrn[mpass_src_idx]);
}
- pfn_glActiveTexture(texture->mpass_textureunit[texture->mpass_dest_idx]);
+ m_glActiveTexture(texture->mpass_textureunit[texture->mpass_dest_idx]);
glBindTexture(texture->texTarget, 0);
- pfn_glActiveTexture(texture->mpass_textureunit[texture->mpass_dest_idx]);
+ m_glActiveTexture(texture->mpass_textureunit[texture->mpass_dest_idx]);
if ( shaderIdx<m_glsl_program_num-1 )
{
if ( shaderIdx>=m_glsl_program_mb2sc )
{
glBindTexture(texture->texTarget, texture->mpass_texture_scrn[texture->mpass_dest_idx]);
- pfn_glBindFramebuffer(GL_FRAMEBUFFER_EXT, texture->mpass_fbo_scrn[texture->mpass_dest_idx]);
+ m_glBindFramebuffer(GL_FRAMEBUFFER_EXT, texture->mpass_fbo_scrn[texture->mpass_dest_idx]);
}
else
{
glBindTexture(texture->texTarget, texture->mpass_texture_mamebm[texture->mpass_dest_idx]);
- pfn_glBindFramebuffer(GL_FRAMEBUFFER_EXT, texture->mpass_fbo_mamebm[texture->mpass_dest_idx]);
+ m_glBindFramebuffer(GL_FRAMEBUFFER_EXT, texture->mpass_fbo_mamebm[texture->mpass_dest_idx]);
}
if ( shaderIdx==0 )
@@ -2590,7 +2740,7 @@ void renderer_ogl::texture_mpass_flip(ogl_texture_info *texture, int shaderIdx)
else
{
glBindTexture(texture->texTarget, 0);
- pfn_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
+ m_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
if ( m_glsl_program_mb2sc == m_glsl_program_num-1 )
{
@@ -2598,7 +2748,7 @@ void renderer_ogl::texture_mpass_flip(ogl_texture_info *texture, int shaderIdx)
GL_CHECK_ERROR_NORMAL();
}
- pfn_glActiveTexture(GL_TEXTURE0);
+ m_glActiveTexture(GL_TEXTURE0);
glBindTexture(texture->texTarget, 0);
}
}
@@ -2610,8 +2760,7 @@ void renderer_ogl::texture_shader_update(ogl_texture_info *texture, render_conta
if (container!=nullptr)
{
- render_container::user_settings settings;
- container->get_user_settings(settings);
+ render_container::user_settings settings = container->get_user_settings();
/* FIXME: the code below is in just for illustration issue on
* how to set shader variables. gamma, contrast and brightness are
* handled already by the core
@@ -2620,8 +2769,8 @@ void renderer_ogl::texture_shader_update(ogl_texture_info *texture, render_conta
vid_attributes[1] = settings.m_contrast;
vid_attributes[2] = settings.m_brightness;
vid_attributes[3] = 0.0f;
- uniform_location = pfn_glGetUniformLocationARB(m_glsl_program[shaderIdx], "vid_attributes");
- pfn_glUniform4fvARB(uniform_location, 1, &(vid_attributes[shaderIdx]));
+ uniform_location = m_shader_tool->pfn_glGetUniformLocationARB(m_glsl_program[shaderIdx], "vid_attributes");
+ m_shader_tool->pfn_glUniform4fvARB(uniform_location, 1, &(vid_attributes[shaderIdx]));
if ( GL_CHECK_ERROR_QUIET() ) {
osd_printf_verbose("GLSL: could not set 'vid_attributes' for shader prog idx %d\n", shaderIdx);
}
@@ -2642,12 +2791,12 @@ ogl_texture_info * renderer_ogl::texture_update(const render_primitive *prim, in
{
if ( texture->type == TEXTURE_TYPE_SHADER )
{
- pfn_glUseProgramObjectARB(m_glsl_program[shaderIdx]); // back to our shader
+ m_shader_tool->pfn_glUseProgramObjectARB(m_glsl_program[shaderIdx]); // back to our shader
}
else if ( texture->type == TEXTURE_TYPE_DYNAMIC )
{
assert ( m_usepbo ) ;
- pfn_glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, texture->pbo);
+ m_glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, texture->pbo);
glEnable(texture->texTarget);
}
else
@@ -2687,9 +2836,9 @@ ogl_texture_info * renderer_ogl::texture_update(const render_primitive *prim, in
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if(m_usevbo)
{
- pfn_glBindBuffer( GL_ARRAY_BUFFER_ARB, texture->texCoordBufferName );
+ m_glBindBuffer( GL_ARRAY_BUFFER_ARB, texture->texCoordBufferName );
// Load The Data
- pfn_glBufferSubData( GL_ARRAY_BUFFER_ARB, 0, 4*2*sizeof(GLfloat), texture->texCoord );
+ m_glBufferSubData( GL_ARRAY_BUFFER_ARB, 0, 4*2*sizeof(GLfloat), texture->texCoord );
glTexCoordPointer( 2, GL_FLOAT, 0, (char *) nullptr ); // we are using ARB VBO buffers
}
else
@@ -2706,34 +2855,41 @@ void renderer_ogl::texture_disable(ogl_texture_info * texture)
if ( texture->type == TEXTURE_TYPE_SHADER )
{
assert ( m_useglsl );
- pfn_glUseProgramObjectARB(0); // back to fixed function pipeline
- } else if ( texture->type == TEXTURE_TYPE_DYNAMIC )
+ m_shader_tool->pfn_glUseProgramObjectARB(0); // back to fixed function pipeline
+ }
+ else if ( texture->type == TEXTURE_TYPE_DYNAMIC )
{
- pfn_glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, 0);
+ m_glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, 0);
glDisable(texture->texTarget);
- } else {
+ }
+ else
+ {
glDisable(texture->texTarget);
}
}
void renderer_ogl::texture_all_disable()
{
- if ( m_useglsl )
+ if (m_useglsl)
{
- pfn_glUseProgramObjectARB(0); // back to fixed function pipeline
+ m_shader_tool->pfn_glUseProgramObjectARB(0); // back to fixed function pipeline
- pfn_glActiveTexture(GL_TEXTURE3);
+ m_glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, 0);
- if ( m_usefbo ) pfn_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
- pfn_glActiveTexture(GL_TEXTURE2);
+ if (m_usefbo)
+ m_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
+ m_glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, 0);
- if ( m_usefbo ) pfn_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
- pfn_glActiveTexture(GL_TEXTURE1);
+ if (m_usefbo)
+ m_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
+ m_glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
- if ( m_usefbo ) pfn_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
- pfn_glActiveTexture(GL_TEXTURE0);
+ if (m_usefbo)
+ m_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
+ m_glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
- if ( m_usefbo ) pfn_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
+ if (m_usefbo)
+ m_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
}
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
@@ -2746,10 +2902,140 @@ void renderer_ogl::texture_all_disable()
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if(m_usevbo)
{
- pfn_glBindBuffer( GL_ARRAY_BUFFER_ARB, 0); // unbind ..
+ m_glBindBuffer( GL_ARRAY_BUFFER_ARB, 0); // unbind ..
}
if ( m_usepbo )
{
- pfn_glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, 0);
+ m_glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, 0);
}
}
+
+
+class video_opengl : public osd_module, public render_module
+{
+public:
+ video_opengl()
+ : osd_module(OSD_RENDERER_PROVIDER, "opengl")
+#if defined(USE_DISPATCH_GL)
+ , m_dll_loaded(false)
+#endif
+ {
+ }
+ ~video_opengl() { 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 | FLAG_SDL_NEEDS_OPENGL; }
+
+private:
+ ogl_video_config m_ogl_config;
+#if defined(USE_DISPATCH_GL)
+ bool m_dll_loaded;
+#endif
+};
+
+int video_opengl::init(osd_interface &osd, osd_options const &options)
+{
+ m_ogl_config.vbo = options.gl_vbo();
+ m_ogl_config.pbo = options.gl_pbo();
+ m_ogl_config.allowtexturerect = !options.gl_no_texture_rect();
+ m_ogl_config.forcepow2texture = options.gl_force_pow2_texture();
+ m_ogl_config.glsl = options.gl_glsl();
+ if (m_ogl_config.glsl)
+ {
+ m_ogl_config.glsl_filter = options.glsl_filter();
+
+ m_ogl_config.glsl_shader_mamebm_num = 0;
+ for (int i = 0; i < GLSL_SHADER_MAX; i++)
+ {
+ char const *const stemp = options.shader_mame(i);
+ if (stemp && *stemp && strcmp(stemp, OSDOPTVAL_NONE))
+ m_ogl_config.glsl_shader_mamebm[m_ogl_config.glsl_shader_mamebm_num++] = stemp;
+ }
+
+ m_ogl_config.glsl_shader_scrn_num = 0;
+ for (int i = 0; i < GLSL_SHADER_MAX; i++)
+ {
+ char const *const stemp = options.shader_screen(i);
+ if (stemp && *stemp && strcmp(stemp, OSDOPTVAL_NONE))
+ m_ogl_config.glsl_shader_scrn[m_ogl_config.glsl_shader_scrn_num++] = stemp;
+ }
+ }
+ else
+ {
+ m_ogl_config.glsl_filter = 0;
+
+ m_ogl_config.glsl_shader_mamebm_num = 0;
+ for (std::string &s : m_ogl_config.glsl_shader_mamebm)
+ s.clear();
+
+ m_ogl_config.glsl_shader_scrn_num = 0;
+ for (std::string &s : m_ogl_config.glsl_shader_scrn)
+ s.clear();
+ }
+
+#if defined(USE_DISPATCH_GL)
+#if defined(OSD_SDL)
+ if (!m_dll_loaded)
+ {
+ // directfb and and x11 use this env var: SDL_VIDEO_GL_DRIVER
+ char const *libname = dynamic_cast<sdl_options const &>(options).gl_lib();
+ if (libname && (!*libname || !std::strcmp(libname, OSDOPTVAL_AUTO)))
+ libname = nullptr;
+
+ if (SDL_GL_LoadLibrary(libname) != 0)
+ {
+ osd_printf_error("Unable to load OpenGL shared library: %s\n", libname ? libname : "<default>");
+ return -1;
+ }
+
+ osd_printf_verbose("Loaded OpenGL shared library: %s\n", libname ? libname : "<default>");
+ }
+#endif // defined(OSD_SDL)
+ m_dll_loaded = true;
+#endif // defined(USE_DISPATCH_GL)
+
+#if defined(OSD_WINDOWS)
+ osd_printf_verbose("Using Windows OpenGL driver\n");
+#else // defined(OSD_WINDOWS)
+ osd_printf_verbose("Using SDL multi-window OpenGL driver (SDL 2.0+)\n");
+#endif // defined(OSD_WINDOWS)
+
+ return 0;
+}
+
+void video_opengl::exit()
+{
+#if defined(USE_DISPATCH_GL)
+#if defined(OSD_SDL)
+ if (m_dll_loaded)
+ SDL_GL_UnloadLibrary();
+#endif // defined(OSD_SDL)
+ m_dll_loaded = false;
+#endif // defined(USE_DISPATCH_GL)
+
+ m_ogl_config = ogl_video_config();
+}
+
+std::unique_ptr<osd_renderer> video_opengl::create(osd_window &window)
+{
+ return std::make_unique<renderer_ogl>(window, m_ogl_config);
+}
+
+} // anonymous namespace
+
+} // namespace osd
+
+
+#else // USE_OPENGL
+
+namespace osd { namespace { MODULE_NOT_SUPPORTED(video_opengl, OSD_RENDERER_PROVIDER, "opengl") } }
+
+#endif // USE_OPENGL
+
+
+MODULE_DEFINITION(RENDERER_OPENGL, osd::video_opengl)
diff --git a/src/osd/modules/render/drawogl.h b/src/osd/modules/render/drawogl.h
deleted file mode 100644
index 525ba0c3ffa..00000000000
--- a/src/osd/modules/render/drawogl.h
+++ /dev/null
@@ -1,242 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Olivier Galibert, R. Belmont
-//============================================================
-//
-// drawogl.h - SDL software and OpenGL implementation
-//
-// SDLMAME by Olivier Galibert and R. Belmont
-//
-//============================================================
-
-#pragma once
-
-#ifndef __DRAWOGL__
-#define __DRAWOGL__
-
-// OSD headers
-#ifndef OSD_WINDOWS
-#ifdef OSD_MAC
-#include "osdmac.h"
-#else
-#include "osdsdl.h"
-#endif
-#include "window.h"
-#else
-#include "../windows/window.h"
-typedef uint64_t HashT;
-#endif
-
-#if defined(OSD_WINDOWS)
-#include "winglcontext.h"
-#elif defined (OSD_MAC)
-#else
-#include "sdlglcontext.h"
-#endif
-
-#include "modules/opengl/gl_shader_mgr.h"
-
-//============================================================
-// Textures
-//============================================================
-
-/* ogl_texture_info holds information about a texture */
-class ogl_texture_info
-{
-public:
- ogl_texture_info()
- : hash(0), flags(0), rawwidth(0), rawheight(0),
- rawwidth_create(0), rawheight_create(0),
- type(0), format(0), borderpix(0), xprescale(0), yprescale(0), nocopy(0),
- texture(0), texTarget(0), texpow2(0), mpass_dest_idx(0), pbo(0), data(nullptr),
- data_own(0), texCoordBufferName(0)
- {
- for (int i=0; i<2; i++)
- {
- mpass_textureunit[i] = 0;
- mpass_texture_mamebm[i] = 0;
- mpass_fbo_mamebm[i] = 0;
- mpass_texture_scrn[i] = 0;
- mpass_fbo_scrn[i] = 0;
- }
- for (int i=0; i<8; i++)
- texCoord[i] = 0.0f;
- }
-
- HashT hash; // hash value for the texture (must be >= pointer size)
- uint32_t flags; // rendering flags
- render_texinfo texinfo; // copy of the texture info
- int rawwidth, rawheight; // raw width/height of the texture
- int rawwidth_create; // raw width/height, pow2 compatible, if needed
- int rawheight_create; // (create and initial set the texture, not for copy!)
- int type; // what type of texture are we?
- int format; // texture format
- int borderpix; // do we have a 1 pixel border?
- int xprescale; // what is our X prescale factor?
- int yprescale; // what is our Y prescale factor?
- int nocopy; // must the texture date be copied?
-
- uint32_t texture; // OpenGL texture "name"/ID
-
- GLenum texTarget; // OpenGL texture target
- int texpow2; // Is this texture pow2
-
- uint32_t mpass_dest_idx; // Multipass dest idx [0..1]
- uint32_t mpass_textureunit[2]; // texture unit names for GLSL
-
- uint32_t mpass_texture_mamebm[2];// Multipass OpenGL texture "name"/ID for the shader
- uint32_t mpass_fbo_mamebm[2]; // framebuffer object for this texture, multipass
- uint32_t mpass_texture_scrn[2]; // Multipass OpenGL texture "name"/ID for the shader
- uint32_t mpass_fbo_scrn[2]; // framebuffer object for this texture, multipass
-
- uint32_t pbo; // pixel buffer object for this texture (DYNAMIC only!)
- uint32_t *data; // pixels for the texture
- int data_own; // do we own / allocated it ?
- GLfloat texCoord[8];
- GLuint texCoordBufferName;
-
-};
-
-/* renderer_ogl is the information about OpenGL for the current screen */
-class renderer_ogl : public osd_renderer
-{
-public:
- renderer_ogl(std::shared_ptr<osd_window> window)
- : osd_renderer(window, FLAG_NEEDS_OPENGL)
- , m_blittimer(0)
- , m_width(0)
- , m_height(0)
- , m_blit_dim(0, 0)
- , m_gl_context(nullptr)
- , m_initialized(0)
- , m_last_blendmode(0)
- , m_texture_max_width(0)
- , m_texture_max_height(0)
- , m_texpoweroftwo(0)
- , m_usevbo(0)
- , m_usepbo(0)
- , m_usefbo(0)
- , m_useglsl(0)
- , m_glsl(nullptr)
- , m_glsl_program_num(0)
- , m_glsl_program_mb2sc(0)
- , m_usetexturerect(0)
- , m_init_context(0)
- , m_last_hofs(0.0f)
- , m_last_vofs(0.0f)
- , m_surf_w(0)
- , m_surf_h(0)
- {
- for (int i=0; i < HASH_SIZE + OVERFLOW_SIZE; i++)
- m_texhash[i] = nullptr;
- for (int i=0; i < 2*GLSL_SHADER_MAX; i++)
- m_glsl_program[i] = 0;
- for (int i=0; i < 8; i++)
- m_texVerticex[i] = 0.0f;
- }
- virtual ~renderer_ogl();
-
- static void init(running_machine &machine);
- static void exit();
-
- virtual int create() override;
- virtual int draw(const int update) override;
-
-#ifndef OSD_WINDOWS
- virtual int xy_to_render_target(const int x, const int y, int *xt, int *yt) override;
-#endif
- virtual render_primitive_list *get_primitives() override
- {
- auto win = try_getwindow();
- if (win == nullptr)
- return nullptr;
-
- osd_dim nd = win->get_size();
- if (nd != m_blit_dim)
- {
- m_blit_dim = nd;
- notify_changed();
- }
- if ((m_blit_dim.width() == 0) || (m_blit_dim.height() == 0))
- return nullptr;
- win->target()->set_bounds(m_blit_dim.width(), m_blit_dim.height(), win->pixel_aspect());
- return &win->target()->get_primitives();
- }
-
-#ifdef OSD_WINDOWS
- virtual void save() override { }
- virtual void record() override { }
- virtual void toggle_fsfx() override { }
-#endif
-
-private:
- static const uint32_t HASH_SIZE = ((1 << 10) + 1);
- static const uint32_t OVERFLOW_SIZE = (1 << 10);
-
- void destroy_all_textures();
-
- static void load_gl_lib(running_machine &machine);
- void loadGLExtensions();
- void initialize_gl();
- void set_blendmode(int blendmode);
- HashT texture_compute_hash(const render_texinfo *texture, uint32_t flags);
- void texture_compute_type_subroutine(const render_texinfo *texsource, ogl_texture_info *texture, uint32_t flags);
- void texture_compute_size_subroutine(ogl_texture_info *texture, uint32_t flags,
- uint32_t width, uint32_t height,
- int* p_width, int* p_height, int* p_width_create, int* p_height_create);
- void texture_compute_size_type(const render_texinfo *texsource, ogl_texture_info *texture, uint32_t flags);
- ogl_texture_info *texture_create(const render_texinfo *texsource, uint32_t flags);
- int texture_shader_create(const render_texinfo *texsource, ogl_texture_info *texture, uint32_t flags);
- ogl_texture_info *texture_find(const render_primitive *prim);
- void texture_coord_update(ogl_texture_info *texture, const render_primitive *prim, int shaderIdx);
- void texture_mpass_flip(ogl_texture_info *texture, int shaderIdx);
- void texture_shader_update(ogl_texture_info *texture, render_container *container, int shaderIdx);
- ogl_texture_info * texture_update(const render_primitive *prim, int shaderIdx);
- void texture_disable(ogl_texture_info * texture);
- void texture_all_disable();
-
- int32_t m_blittimer;
- int m_width;
- int m_height;
- osd_dim m_blit_dim;
-
- osd_gl_context *m_gl_context;
-
- int m_initialized; // is everything well initialized, i.e. all GL stuff etc.
- // 3D info (GL mode only)
- ogl_texture_info * m_texhash[HASH_SIZE + OVERFLOW_SIZE];
- int m_last_blendmode; // previous blendmode
- int32_t m_texture_max_width; // texture maximum width
- int32_t m_texture_max_height; // texture maximum height
- int m_texpoweroftwo; // must textures be power-of-2 sized?
- int m_usevbo; // runtime check if VBO is available
- int m_usepbo; // runtime check if PBO is available
- int m_usefbo; // runtime check if FBO is available
- int m_useglsl; // runtime check if GLSL is available
-
- glsl_shader_info *m_glsl; // glsl_shader_info
-
- GLhandleARB m_glsl_program[2*GLSL_SHADER_MAX]; // GLSL programs, or 0
- int m_glsl_program_num; // number of GLSL programs
- int m_glsl_program_mb2sc; // GLSL program idx, which transforms
- // the mame-bitmap. screen-bitmap (size/rotation/..)
- // All progs <= glsl_program_mb2sc using the mame bitmap
- // as input, otherwise the screen bitmap.
- // All progs >= glsl_program_mb2sc using the screen bitmap
- // as output, otherwise the mame bitmap.
- int m_usetexturerect; // use ARB_texture_rectangle for non-power-of-2, general use
-
- int m_init_context; // initialize context before next draw
-
- float m_last_hofs;
- float m_last_vofs;
-
- // Static vars from draogl_window_dra
- int32_t m_surf_w;
- int32_t m_surf_h;
- GLfloat m_texVerticex[8];
-
- static bool s_shown_video_info;
- static bool s_dll_loaded;
-};
-
-#endif // __DRAWOGL__
diff --git a/src/osd/modules/render/drawsdl.cpp b/src/osd/modules/render/drawsdl.cpp
index c80b59185af..b1a9e93f42e 100644
--- a/src/osd/modules/render/drawsdl.cpp
+++ b/src/osd/modules/render/drawsdl.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Couriersud, Olivier Galibert, R. Belmont
//============================================================
//
-// drawsdl.c - SDL software and OpenGL implementation
+// drawsdl.cpp - SDL software and OpenGL implementation
//
// SDLMAME by Olivier Galibert and R. Belmont
//
@@ -10,28 +10,37 @@
//
//============================================================
-// standard C headers
-#include <math.h>
-#include <stdio.h>
+#include "render_module.h"
+
+#include "modules/osdmodule.h"
+
+#if defined(OSD_SDL)
+
+// from specific OSD implementation
+#include "sdlopts.h"
+#include "window.h"
+
+// general OSD headers
+#include "modules/monitor/monitor_module.h"
// MAME headers
-#include "emu.h"
-#include "ui/uimain.h"
+#include "emucore.h"
+#include "render.h"
#include "rendersw.hxx"
-// standard SDL headers
+//#include "ui/uimain.h"
+
#include <SDL2/SDL.h>
-// OSD headers
-#include "osdsdl.h"
-#include "window.h"
+// standard C headers
+#include <cmath>
+#include <cstdio>
+#include <memory>
-#include "drawsdl.h"
-#include "modules/monitor/monitor_module.h"
-//============================================================
-// DEBUGGING
-//============================================================
+namespace osd {
+
+namespace {
//============================================================
// CONSTANTS
@@ -41,60 +50,90 @@
#define DRAW2_SCALEMODE_LINEAR "1"
#define DRAW2_SCALEMODE_BEST "2"
-//============================================================
-// PROTOTYPES
-//============================================================
-
-// YUV overlays
-
-static void yuv_RGB_to_YV12(const uint16_t *bitmap, uint8_t *ptr, const int pitch, \
- const uint32_t *lookup, const int width, const int height);
-static void yuv_RGB_to_YV12X2(const uint16_t *bitmap, uint8_t *ptr, const int pitch, \
- const uint32_t *lookup, const int width, const int height);
-static void yuv_RGB_to_YUY2(const uint16_t *bitmap, uint8_t *ptr, const int pitch, \
- const uint32_t *lookup, const int width, const int height);
-static void yuv_RGB_to_YUY2X2(const uint16_t *bitmap, uint8_t *ptr, const int pitch, \
- const uint32_t *lookup, const int width, const int height);
-
-// Static declarations
-static const sdl_scale_mode scale_modes[] =
+struct sdl_scale_mode
{
- { "none", 0, 0, 1, 1, DRAW2_SCALEMODE_NEAREST, 0, nullptr },
- { "hwblit", 1, 0, 1, 1, DRAW2_SCALEMODE_LINEAR, 0, nullptr },
- { "hwbest", 1, 0, 1, 1, DRAW2_SCALEMODE_BEST, 0, nullptr },
- /* SDL1.2 uses interpolation as well */
- { "yv12", 1, 1, 1, 1, DRAW2_SCALEMODE_BEST, SDL_PIXELFORMAT_YV12, yuv_RGB_to_YV12 },
- { "yv12x2", 1, 1, 2, 2, DRAW2_SCALEMODE_BEST, SDL_PIXELFORMAT_YV12, yuv_RGB_to_YV12X2 },
- { "yuy2", 1, 1, 1, 1, DRAW2_SCALEMODE_BEST, SDL_PIXELFORMAT_YUY2, yuv_RGB_to_YUY2 },
- { "yuy2x2", 1, 1, 2, 1, DRAW2_SCALEMODE_BEST, SDL_PIXELFORMAT_YUY2, yuv_RGB_to_YUY2X2 },
- { nullptr }
+ const char *name;
+ int is_scale; /* Scale mode? */
+ int is_yuv; /* Yuv mode? */
+ int mult_w; /* Width multiplier */
+ int mult_h; /* Height multiplier */
+ const char *sdl_scale_mode_hint; /* what to use as a hint ? */
+ int pixel_format; /* Pixel/Overlay format */
+ void (*yuv_blit)(const uint16_t *bitmap, uint8_t *ptr, const int pitch, const uint32_t *lookup, const int width, const int height);
};
-int drawsdl_scale_mode(const char *s)
-{
- const sdl_scale_mode *sm = scale_modes;
- int index;
- index = 0;
- while (sm->name != nullptr)
+// renderer_sdl1 is the information about SDL for the current screen
+class renderer_sdl1 : public osd_renderer
+{
+public:
+
+ renderer_sdl1(osd_window &w, sdl_scale_mode const &scale_mode)
+ : osd_renderer(w)
+ , m_scale_mode(scale_mode)
+ , m_sdl_renderer(nullptr)
+ , m_texture_id(nullptr)
+ , m_yuv_lookup()
+ , m_yuv_bitmap()
+ //, m_hw_scale_width(0)
+ //, m_hw_scale_height(0)
+ , m_last_hofs(0)
+ , m_last_vofs(0)
+ , m_blit_dim(0, 0)
+ , m_last_dim(0, 0)
{
- if (strcmp(sm->name, s) == 0)
- return index;
- index++;
- sm++;
}
- return -1;
-}
+ virtual ~renderer_sdl1();
+
+ virtual int create() override;
+ virtual int draw(const int update) override;
+ virtual int xy_to_render_target(const int x, const int y, int *xt, int *yt) override;
+ virtual render_primitive_list *get_primitives() override;
+
+private:
+ void show_info(struct SDL_RendererInfo *render_info);
+
+ void destroy_all_textures();
+ void yuv_init();
+ void setup_texture(const osd_dim &size);
+ void yuv_lookup_set(unsigned int pen, unsigned char red,
+ unsigned char green, unsigned char blue);
+
+ int32_t m_blittimer;
+
+ sdl_scale_mode const &m_scale_mode;
+ SDL_Renderer *m_sdl_renderer;
+ SDL_Texture *m_texture_id;
+
+ // YUV overlay
+ std::unique_ptr<uint32_t []> m_yuv_lookup;
+ std::unique_ptr<uint16_t []> m_yuv_bitmap;
+
+ // if we leave scaling to SDL and the underlying driver, this
+ // is the render_target_width/height to use
+
+ int m_last_hofs;
+ int m_last_vofs;
+ osd_dim m_blit_dim;
+ osd_dim m_last_dim;
+};
+
//============================================================
-// drawsdl_init
+// PROTOTYPES
//============================================================
-void renderer_sdl1::init(running_machine &machine)
-{
- osd_printf_verbose("Using SDL multi-window soft driver (SDL 2.0+)\n");
-}
+// YUV overlays
+
+static void yuv_RGB_to_YV12(const uint16_t *bitmap, uint8_t *ptr, const int pitch,
+ const uint32_t *lookup, const int width, const int height);
+static void yuv_RGB_to_YV12X2(const uint16_t *bitmap, uint8_t *ptr, const int pitch,
+ const uint32_t *lookup, const int width, const int height);
+static void yuv_RGB_to_YUY2(const uint16_t *bitmap, uint8_t *ptr, const int pitch,
+ const uint32_t *lookup, const int width, const int height);
+static void yuv_RGB_to_YUY2X2(const uint16_t *bitmap, uint8_t *ptr, const int pitch,
+ const uint32_t *lookup, const int width, const int height);
//============================================================
// setup_texture for window
@@ -102,42 +141,35 @@ void renderer_sdl1::init(running_machine &machine)
void renderer_sdl1::setup_texture(const osd_dim &size)
{
- const sdl_scale_mode *sdl_sm = &scale_modes[video_config.scale_mode];
SDL_DisplayMode mode;
uint32_t fmt;
- auto win = assert_window();
-
// Determine preferred pixelformat and set up yuv if necessary
- SDL_GetCurrentDisplayMode(win->monitor()->oshandle(), &mode);
+ SDL_GetCurrentDisplayMode(window().monitor()->oshandle(), &mode);
- if (m_yuv_bitmap)
- {
- global_free_array(m_yuv_bitmap);
- m_yuv_bitmap = nullptr;
- }
+ m_yuv_bitmap.reset();
- fmt = (sdl_sm->pixel_format ? sdl_sm->pixel_format : mode.format);
+ fmt = (m_scale_mode.pixel_format ? m_scale_mode.pixel_format : mode.format);
- if (sdl_sm->is_scale)
+ if (m_scale_mode.is_scale)
{
int m_hw_scale_width = 0;
int m_hw_scale_height = 0;
- win->target()->compute_minimum_size(m_hw_scale_width, m_hw_scale_height);
- if (win->prescale())
+ window().target()->compute_minimum_size(m_hw_scale_width, m_hw_scale_height);
+ if (window().prescale())
{
- m_hw_scale_width *= win->prescale();
- m_hw_scale_height *= win->prescale();
+ m_hw_scale_width *= window().prescale();
+ m_hw_scale_height *= window().prescale();
/* This must be a multiple of 2 */
m_hw_scale_width = (m_hw_scale_width + 1) & ~1;
}
- if (sdl_sm->is_yuv)
- m_yuv_bitmap = global_alloc_array(uint16_t, m_hw_scale_width * m_hw_scale_height);
+ if (m_scale_mode.is_yuv)
+ m_yuv_bitmap = std::make_unique<uint16_t []>(m_hw_scale_width * m_hw_scale_height);
- int w = m_hw_scale_width * sdl_sm->mult_w;
- int h = m_hw_scale_height * sdl_sm->mult_h;
+ int w = m_hw_scale_width * m_scale_mode.mult_w;
+ int h = m_hw_scale_height * m_scale_mode.mult_h;
m_texture_id = SDL_CreateTexture(m_sdl_renderer, fmt, SDL_TEXTUREACCESS_STREAMING, w, h);
@@ -186,26 +218,23 @@ void renderer_sdl1::show_info(struct SDL_RendererInfo *render_info)
int renderer_sdl1::create()
{
- const sdl_scale_mode *sm = &scale_modes[video_config.scale_mode];
-
- auto win = assert_window();
// create renderer
/* set hints ... */
- SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, sm->sdl_scale_mode_hint);
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, m_scale_mode.sdl_scale_mode_hint);
if (video_config.waitvsync)
- m_sdl_renderer = SDL_CreateRenderer(std::dynamic_pointer_cast<sdl_window_info>(win)->platform_window(), -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
+ m_sdl_renderer = SDL_CreateRenderer(dynamic_cast<sdl_window_info &>(window()).platform_window(), -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
else
- m_sdl_renderer = SDL_CreateRenderer(std::dynamic_pointer_cast<sdl_window_info>(win)->platform_window(), -1, SDL_RENDERER_ACCELERATED);
+ m_sdl_renderer = SDL_CreateRenderer(dynamic_cast<sdl_window_info &>(window()).platform_window(), -1, SDL_RENDERER_ACCELERATED);
if (!m_sdl_renderer)
{
if (video_config.waitvsync)
- m_sdl_renderer = SDL_CreateRenderer(std::dynamic_pointer_cast<sdl_window_info>(win)->platform_window(), -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_SOFTWARE);
+ m_sdl_renderer = SDL_CreateRenderer(dynamic_cast<sdl_window_info &>(window()).platform_window(), -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_SOFTWARE);
else
- m_sdl_renderer = SDL_CreateRenderer(std::dynamic_pointer_cast<sdl_window_info>(win)->platform_window(), -1, SDL_RENDERER_SOFTWARE);
+ m_sdl_renderer = SDL_CreateRenderer(dynamic_cast<sdl_window_info &>(window()).platform_window(), -1, SDL_RENDERER_SOFTWARE);
}
if (!m_sdl_renderer)
@@ -220,18 +249,18 @@ int renderer_sdl1::create()
// Check scale mode
- if (sm->pixel_format)
+ if (m_scale_mode.pixel_format)
{
int i;
int found = 0;
for (i=0; i < render_info.num_texture_formats; i++)
- if (sm->pixel_format == render_info.texture_formats[i])
+ if (m_scale_mode.pixel_format == render_info.texture_formats[i])
found = 1;
if (!found)
{
- fatalerror("window: Scale mode %s not supported!", sm->name);
+ fatalerror("window: Scale mode %s not supported!", m_scale_mode.name);
}
}
@@ -257,16 +286,6 @@ renderer_sdl1::~renderer_sdl1()
{
destroy_all_textures();
- if (m_yuv_lookup != nullptr)
- {
- global_free_array(m_yuv_lookup);
- m_yuv_lookup = nullptr;
- }
- if (m_yuv_bitmap != nullptr)
- {
- global_free_array(m_yuv_bitmap);
- m_yuv_bitmap = nullptr;
- }
SDL_DestroyRenderer(m_sdl_renderer);
}
@@ -302,7 +321,6 @@ void renderer_sdl1::destroy_all_textures()
int renderer_sdl1::draw(int update)
{
- const sdl_scale_mode *sm = &scale_modes[video_config.scale_mode];
uint8_t *surfptr;
int32_t pitch;
Uint32 rmask, gmask, bmask;
@@ -310,14 +328,7 @@ int renderer_sdl1::draw(int update)
int32_t vofs, hofs, blitwidth, blitheight, ch, cw;
int bpp;
- if (video_config.novideo)
- {
- return 0;
- }
-
- auto win = assert_window();
-
- osd_dim wdim = win->get_size();
+ osd_dim wdim = window().get_size();
if (has_flags(FI_CHANGED) || (wdim != m_last_dim))
{
destroy_all_textures();
@@ -384,15 +395,15 @@ int renderer_sdl1::draw(int update)
m_last_hofs = hofs;
m_last_vofs = vofs;
- win->m_primlist->acquire_lock();
+ window().m_primlist->acquire_lock();
int mamewidth, mameheight;
Uint32 fmt = 0;
int access = 0;
SDL_QueryTexture(m_texture_id, &fmt, &access, &mamewidth, &mameheight);
- mamewidth /= sm->mult_w;
- mameheight /= sm->mult_h;
+ mamewidth /= m_scale_mode.mult_w;
+ mameheight /= m_scale_mode.mult_h;
//printf("w h %d %d %d %d\n", mamewidth, mameheight, blitwidth, blitheight);
// rescale bounds
@@ -402,7 +413,7 @@ int renderer_sdl1::draw(int update)
// FIXME: this could be a lot easier if we get the primlist here!
// Bounds would be set fit for purpose and done!
- for (render_primitive &prim : *win->m_primlist)
+ for (render_primitive &prim : *window().m_primlist)
{
prim.bounds.x0 = floor(fw * prim.bounds.x0 + 0.5f);
prim.bounds.x1 = floor(fw * prim.bounds.x1 + 0.5f);
@@ -411,28 +422,32 @@ int renderer_sdl1::draw(int update)
}
// render to it
- if (!sm->is_yuv)
+ if (!m_scale_mode.is_yuv)
{
switch (rmask)
{
+ case 0xff000000:
+ software_renderer<uint32_t, 0,0,0, 24,16,8>::draw_primitives(*window().m_primlist, surfptr, mamewidth, mameheight, pitch / 4);
+ break;
+
case 0x0000ff00:
- software_renderer<uint32_t, 0,0,0, 8,16,24>::draw_primitives(*win->m_primlist, surfptr, mamewidth, mameheight, pitch / 4);
+ software_renderer<uint32_t, 0,0,0, 8,16,24>::draw_primitives(*window().m_primlist, surfptr, mamewidth, mameheight, pitch / 4);
break;
case 0x00ff0000:
- software_renderer<uint32_t, 0,0,0, 16,8,0>::draw_primitives(*win->m_primlist, surfptr, mamewidth, mameheight, pitch / 4);
+ software_renderer<uint32_t, 0,0,0, 16,8,0>::draw_primitives(*window().m_primlist, surfptr, mamewidth, mameheight, pitch / 4);
break;
case 0x000000ff:
- software_renderer<uint32_t, 0,0,0, 0,8,16>::draw_primitives(*win->m_primlist, surfptr, mamewidth, mameheight, pitch / 4);
+ software_renderer<uint32_t, 0,0,0, 0,8,16>::draw_primitives(*window().m_primlist, surfptr, mamewidth, mameheight, pitch / 4);
break;
case 0xf800:
- software_renderer<uint16_t, 3,2,3, 11,5,0>::draw_primitives(*win->m_primlist, surfptr, mamewidth, mameheight, pitch / 2);
+ software_renderer<uint16_t, 3,2,3, 11,5,0>::draw_primitives(*window().m_primlist, surfptr, mamewidth, mameheight, pitch / 2);
break;
case 0x7c00:
- software_renderer<uint16_t, 3,3,3, 10,5,0>::draw_primitives(*win->m_primlist, surfptr, mamewidth, mameheight, pitch / 2);
+ software_renderer<uint16_t, 3,3,3, 10,5,0>::draw_primitives(*window().m_primlist, surfptr, mamewidth, mameheight, pitch / 2);
break;
default:
@@ -444,11 +459,11 @@ int renderer_sdl1::draw(int update)
{
assert (m_yuv_bitmap != nullptr);
assert (surfptr != nullptr);
- software_renderer<uint16_t, 3,3,3, 10,5,0>::draw_primitives(*win->m_primlist, m_yuv_bitmap, mamewidth, mameheight, mamewidth);
- sm->yuv_blit((uint16_t *)m_yuv_bitmap, surfptr, pitch, m_yuv_lookup, mamewidth, mameheight);
+ software_renderer<uint16_t, 3,3,3, 10,5,0>::draw_primitives(*window().m_primlist, m_yuv_bitmap.get(), mamewidth, mameheight, mamewidth);
+ m_scale_mode.yuv_blit(m_yuv_bitmap.get(), surfptr, pitch, m_yuv_lookup.get(), mamewidth, mameheight);
}
- win->m_primlist->release_lock();
+ window().m_primlist->release_lock();
// unlock and flip
SDL_UnlockTexture(m_texture_id);
@@ -521,12 +536,11 @@ void renderer_sdl1::yuv_lookup_set(unsigned int pen, unsigned char red,
void renderer_sdl1::yuv_init()
{
- unsigned char r,g,b;
- if (m_yuv_lookup == nullptr)
- m_yuv_lookup = global_alloc_array(uint32_t, 65536);
- for (r = 0; r < 32; r++)
- for (g = 0; g < 32; g++)
- for (b = 0; b < 32; b++)
+ if (!m_yuv_lookup)
+ m_yuv_lookup = std::make_unique<uint32_t []>(65536);
+ for (unsigned char r = 0; r < 32; r++)
+ for (unsigned char g = 0; g < 32; g++)
+ for (unsigned char b = 0; b < 32; b++)
{
int idx = (r << 10) | (g << 5) | b;
yuv_lookup_set(idx,
@@ -538,7 +552,7 @@ void renderer_sdl1::yuv_init()
//uint32_t *lookup = sdl->m_yuv_lookup;
-static void yuv_RGB_to_YV12(const uint16_t *bitmap, uint8_t *ptr, const int pitch, \
+static void yuv_RGB_to_YV12(const uint16_t *bitmap, uint8_t *ptr, const int pitch,
const uint32_t *lookup, const int width, const int height)
{
int x, y;
@@ -592,7 +606,7 @@ static void yuv_RGB_to_YV12(const uint16_t *bitmap, uint8_t *ptr, const int pitc
}
}
-static void yuv_RGB_to_YV12X2(const uint16_t *bitmap, uint8_t *ptr, const int pitch, \
+static void yuv_RGB_to_YV12X2(const uint16_t *bitmap, uint8_t *ptr, const int pitch,
const uint32_t *lookup, const int width, const int height)
{
/* this one is used when scale==2 */
@@ -627,7 +641,7 @@ static void yuv_RGB_to_YV12X2(const uint16_t *bitmap, uint8_t *ptr, const int pi
}
}
-static void yuv_RGB_to_YUY2(const uint16_t *bitmap, uint8_t *ptr, const int pitch, \
+static void yuv_RGB_to_YUY2(const uint16_t *bitmap, uint8_t *ptr, const int pitch,
const uint32_t *lookup, const int width, const int height)
{
/* this one is used when scale==2 */
@@ -653,7 +667,7 @@ static void yuv_RGB_to_YUY2(const uint16_t *bitmap, uint8_t *ptr, const int pitc
}
}
-static void yuv_RGB_to_YUY2X2(const uint16_t *bitmap, uint8_t *ptr, const int pitch, \
+static void yuv_RGB_to_YUY2X2(const uint16_t *bitmap, uint8_t *ptr, const int pitch,
const uint32_t *lookup, const int width, const int height)
{
/* this one is used when scale==2 */
@@ -677,16 +691,98 @@ static void yuv_RGB_to_YUY2X2(const uint16_t *bitmap, uint8_t *ptr, const int pi
render_primitive_list *renderer_sdl1::get_primitives()
{
- auto win = try_getwindow();
- if (win == nullptr)
- return nullptr;
-
- osd_dim nd = win->get_size();
+ osd_dim nd = window().get_size();
if (nd != m_blit_dim)
{
m_blit_dim = nd;
notify_changed();
}
- win->target()->set_bounds(m_blit_dim.width(), m_blit_dim.height(), win->pixel_aspect());
- return &win->target()->get_primitives();
+ window().target()->set_bounds(m_blit_dim.width(), m_blit_dim.height(), window().pixel_aspect());
+ return &window().target()->get_primitives();
+}
+
+
+class video_sdl1 : public osd_module, public render_module
+{
+public:
+ video_sdl1()
+ : osd_module(OSD_RENDERER_PROVIDER, "soft")
+ , m_scale_mode(-1)
+ {
+ }
+
+ 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:
+ static int get_scale_mode(char const *modestr);
+
+ int m_scale_mode;
+
+ static sdl_scale_mode const s_scale_modes[];
+};
+
+int video_sdl1::init(osd_interface &osd, osd_options const &options)
+{
+ osd_printf_verbose("Using SDL multi-window soft driver (SDL 2.0+)\n");
+
+ // yuv settings ...
+ char const *const modestr = dynamic_cast<sdl_options const &>(options).scale_mode();
+ m_scale_mode = get_scale_mode(modestr);
+ if (m_scale_mode < 0)
+ {
+ osd_printf_warning("Invalid yuvmode value %s; reverting to none\n", modestr);
+ m_scale_mode = 0;
+ }
+
+ return 0;
+}
+
+std::unique_ptr<osd_renderer> video_sdl1::create(osd_window &window)
+{
+ return std::make_unique<renderer_sdl1>(window, s_scale_modes[m_scale_mode]);
+}
+
+int video_sdl1::get_scale_mode(char const *modestr)
+{
+ const sdl_scale_mode *sm = s_scale_modes;
+ int index = 0;
+ while (sm->name)
+ {
+ if (!strcmp(sm->name, modestr))
+ return index;
+ index++;
+ sm++;
+ }
+ return -1;
}
+
+sdl_scale_mode const video_sdl1::s_scale_modes[] = {
+ { "none", 0, 0, 1, 1, DRAW2_SCALEMODE_NEAREST, 0, nullptr },
+ { "hwblit", 1, 0, 1, 1, DRAW2_SCALEMODE_LINEAR, 0, nullptr },
+ { "hwbest", 1, 0, 1, 1, DRAW2_SCALEMODE_BEST, 0, nullptr },
+ /* SDL1.2 uses interpolation as well */
+ { "yv12", 1, 1, 1, 1, DRAW2_SCALEMODE_BEST, SDL_PIXELFORMAT_YV12, yuv_RGB_to_YV12 },
+ { "yv12x2", 1, 1, 2, 2, DRAW2_SCALEMODE_BEST, SDL_PIXELFORMAT_YV12, yuv_RGB_to_YV12X2 },
+ { "yuy2", 1, 1, 1, 1, DRAW2_SCALEMODE_BEST, SDL_PIXELFORMAT_YUY2, yuv_RGB_to_YUY2 },
+ { "yuy2x2", 1, 1, 2, 1, DRAW2_SCALEMODE_BEST, SDL_PIXELFORMAT_YUY2, yuv_RGB_to_YUY2X2 },
+ { nullptr } };
+
+} // anonymous namespace
+
+} // namespace osd
+
+
+#else // defined(OSD_SDL)
+
+namespace osd { namespace { MODULE_NOT_SUPPORTED(video_sdl1, OSD_RENDERER_PROVIDER, "soft") } }
+
+#endif // defined(OSD_SDL)
+
+
+MODULE_DEFINITION(RENDERER_SDL1, osd::video_sdl1)
diff --git a/src/osd/modules/render/drawsdl.h b/src/osd/modules/render/drawsdl.h
deleted file mode 100644
index 6c0b51c0663..00000000000
--- a/src/osd/modules/render/drawsdl.h
+++ /dev/null
@@ -1,88 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Couriersud, Olivier Galibert, R. Belmont
-//============================================================
-//
-// drawsdl.h - SDL software and OpenGL implementation
-//
-// SDLMAME by Olivier Galibert and R. Belmont
-//
-// yuvmodes by Couriersud
-//
-//============================================================
-
-#pragma once
-
-#ifndef __DRAWSDL1__
-#define __DRAWSDL1__
-
-#include <SDL2/SDL.h>
-
-/* renderer_sdl1 is the information about SDL for the current screen */
-class renderer_sdl1 : public osd_renderer
-{
-public:
-
- renderer_sdl1(std::shared_ptr<osd_window> w, int extra_flags)
- : osd_renderer(w, FLAG_NEEDS_OPENGL | extra_flags)
- , m_sdl_renderer(nullptr)
- , m_texture_id(nullptr)
- , m_yuv_lookup(nullptr)
- , m_yuv_bitmap(nullptr)
- //, m_hw_scale_width(0)
- //, m_hw_scale_height(0)
- , m_last_hofs(0)
- , m_last_vofs(0)
- , m_blit_dim(0, 0)
- , m_last_dim(0, 0)
- {
- }
- virtual ~renderer_sdl1();
-
- static void init(running_machine &machine);
- static void exit() { }
-
- virtual int create() override;
- virtual int draw(const int update) override;
- virtual int xy_to_render_target(const int x, const int y, int *xt, int *yt) override;
- virtual render_primitive_list *get_primitives() override;
-
-private:
- void show_info(struct SDL_RendererInfo *render_info);
-
- void destroy_all_textures();
- void yuv_init();
- void setup_texture(const osd_dim &size);
- void yuv_lookup_set(unsigned int pen, unsigned char red,
- unsigned char green, unsigned char blue);
-
- int32_t m_blittimer;
-
- SDL_Renderer *m_sdl_renderer;
- SDL_Texture *m_texture_id;
-
- // YUV overlay
- uint32_t *m_yuv_lookup;
- uint16_t *m_yuv_bitmap;
-
- // if we leave scaling to SDL and the underlying driver, this
- // is the render_target_width/height to use
-
- int m_last_hofs;
- int m_last_vofs;
- osd_dim m_blit_dim;
- osd_dim m_last_dim;
-};
-
-struct sdl_scale_mode
-{
- const char *name;
- int is_scale; /* Scale mode? */
- int is_yuv; /* Yuv mode? */
- int mult_w; /* Width multiplier */
- int mult_h; /* Height multiplier */
- const char *sdl_scale_mode_hint; /* what to use as a hint ? */
- int pixel_format; /* Pixel/Overlay format */
- void (*yuv_blit)(const uint16_t *bitmap, uint8_t *ptr, const int pitch, const uint32_t *lookup, const int width, const int height);
-};
-
-#endif // __DRAWSDL1__
diff --git a/src/osd/modules/render/render_module.h b/src/osd/modules/render/render_module.h
new file mode 100644
index 00000000000..b22f35fdb3c
--- /dev/null
+++ b/src/osd/modules/render/render_module.h
@@ -0,0 +1,38 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+#ifndef MAME_OSD_MODULES_RENDER_RENDER_MODULE_H
+#define MAME_OSD_MODULES_RENDER_RENDER_MODULE_H
+
+#pragma once
+
+#include "osdepend.h"
+#include "modules/osdmodule.h"
+
+#include <memory>
+
+
+#define OSD_RENDERER_PROVIDER "video"
+
+
+class osd_renderer;
+class osd_window;
+
+
+class render_module
+{
+public:
+ virtual ~render_module() = default;
+
+ virtual std::unique_ptr<osd_renderer> create(osd_window &window) = 0;
+
+ bool is_interactive() const { return flags() & FLAG_INTERACTIVE; }
+ bool sdl_needs_opengl() const { return flags() & FLAG_SDL_NEEDS_OPENGL; }
+
+protected:
+ static inline constexpr unsigned FLAG_INTERACTIVE = 1;
+ static inline constexpr unsigned FLAG_SDL_NEEDS_OPENGL = 2;
+
+ virtual unsigned flags() const = 0;
+};
+
+#endif // MAME_OSD_MODULES_RENDER_RENDER_MODULE_H
diff --git a/src/osd/modules/render/sdlglcontext.h b/src/osd/modules/render/sdlglcontext.h
index b8ff4d72aa2..d2055060bd6 100644
--- a/src/osd/modules/render/sdlglcontext.h
+++ b/src/osd/modules/render/sdlglcontext.h
@@ -8,61 +8,76 @@
//
//============================================================
+#ifndef MAME_RENDER_SDLGLCONTEXT_H
+#define MAME_RENDER_SDLGLCONTEXT_H
+
#pragma once
-#ifndef __SDL_GL_CONTEXT__
-#define __SDL_GL_CONTEXT__
+#include "modules/opengl/osd_opengl.h"
+
+#include "strformat.h"
#include <SDL2/SDL.h>
-#include "modules/opengl/osd_opengl.h"
+
+#include <string>
+
class sdl_gl_context : public osd_gl_context
{
public:
- sdl_gl_context(SDL_Window *window) : osd_gl_context(), m_context(0), m_window(window)
+ sdl_gl_context(SDL_Window *window) : m_context(0), m_window(window)
{
- m_error[0] = 0;
m_context = SDL_GL_CreateContext(window);
- if (!m_context)
+ if (!m_context)
{
- snprintf(m_error,255, "OpenGL not supported on this driver: %s", SDL_GetError());
+ try { m_error = util::string_format("OpenGL not supported on this driver: %s", SDL_GetError()); }
+ catch (...) { m_error.clear(); }
}
}
+
virtual ~sdl_gl_context()
{
- SDL_GL_DeleteContext(m_context);
+ if (m_context)
+ SDL_GL_DeleteContext(m_context);
}
- virtual void MakeCurrent() override
+
+ virtual explicit operator bool() const override
+ {
+ return bool(m_context);
+ }
+
+ virtual void make_current() override
{
SDL_GL_MakeCurrent(m_window, m_context);
}
- virtual int SetSwapInterval(const int swap) override
+ virtual bool set_swap_interval(const int swap) override
{
- return SDL_GL_SetSwapInterval(swap);
+ return 0 == SDL_GL_SetSwapInterval(swap);
}
- virtual const char *LastErrorMsg() override
+ virtual const char *last_error_message() override
{
- if (m_error[0] == 0)
- return nullptr;
+ if (!m_error.empty())
+ return m_error.c_str();
else
- return m_error;
+ return nullptr;
}
- virtual void *getProcAddress(const char *proc) override
+
+ virtual void *get_proc_address(const char *proc) override
{
return SDL_GL_GetProcAddress(proc);
}
- virtual void SwapBuffer() override
+ virtual void swap_buffer() override
{
SDL_GL_SwapWindow(m_window);
}
private:
SDL_GLContext m_context;
- SDL_Window *m_window;
- char m_error[256];
+ SDL_Window *const m_window;
+ std::string m_error;
};
-#endif // __SDL_GL_CONTEXT__
+#endif // MAME_RENDER_SDLGLCONTEXT_H
diff --git a/src/osd/modules/render/winglcontext.h b/src/osd/modules/render/winglcontext.h
index f0cb1b6af77..48d1462d2f6 100644
--- a/src/osd/modules/render/winglcontext.h
+++ b/src/osd/modules/render/winglcontext.h
@@ -7,168 +7,197 @@
// SDLMAME by Olivier Galibert and R. Belmont
//
//============================================================
+#ifndef MAME_RENDER_WINGLCONTEXT_H
+#define MAME_RENDER_WINGLCONTEXT_H
#pragma once
-#ifndef __WIN_GL_CONTEXT__
-#define __WIN_GL_CONTEXT__
-
#include "modules/opengl/osd_opengl.h"
#include "modules/lib/osdlib.h"
-// Typedefs for dynamically loaded functions
-typedef PROC (WINAPI *wglGetProcAddress_fn)(LPCSTR);
-typedef HGLRC (WINAPI *wglCreateContext_fn)(HDC);
-typedef BOOL (WINAPI *wglDeleteContext_fn)(HGLRC);
-typedef BOOL (WINAPI *wglMakeCurrent_fn)(HDC, HGLRC);
+#include "strconv.h"
+
+#include <cstring>
+#include <string>
-typedef const char * (WINAPI *wglGetExtensionsStringEXT_fn)(void);
-typedef BOOL (WINAPI *wglSwapIntervalEXT_fn)(int);
-typedef int (WINAPI *wglGetSwapIntervalEXT_fn)(void);
class win_gl_context : public osd_gl_context
{
public:
- win_gl_context(HWND window) : osd_gl_context(), m_context(0), m_window(nullptr), m_hdc(0)
- {
- m_error[0] = 0;
+ using osd_gl_context::get_proc_address;
+ win_gl_context(HWND window) : m_context(nullptr), m_window(window), m_hdc(nullptr)
+ {
+ // open DLL and bind required functions
opengl32_dll = osd::dynamic_module::open({ "opengl32.dll" });
-
pfn_wglGetProcAddress = opengl32_dll->bind<wglGetProcAddress_fn>("wglGetProcAddress");
pfn_wglCreateContext = opengl32_dll->bind<wglCreateContext_fn>("wglCreateContext");
pfn_wglDeleteContext = opengl32_dll->bind<wglDeleteContext_fn>("wglDeleteContext");
pfn_wglMakeCurrent = opengl32_dll->bind<wglMakeCurrent_fn>("wglMakeCurrent");
+ if (!pfn_wglGetProcAddress || !pfn_wglCreateContext || !pfn_wglDeleteContext || !pfn_wglMakeCurrent)
+ return;
- if (pfn_wglGetProcAddress == nullptr || pfn_wglCreateContext == nullptr ||
- pfn_wglDeleteContext == nullptr || pfn_wglMakeCurrent == nullptr)
+ m_hdc = GetDC(window);
+ if (!m_hdc)
{
+ get_last_error_string();
return;
}
- pfn_wglGetExtensionsStringEXT = (wglGetExtensionsStringEXT_fn)(*pfn_wglGetProcAddress)("wglGetExtensionsStringEXT");
+ if (setupPixelFormat())
+ {
+ m_context = (*pfn_wglCreateContext)(m_hdc);
+ if (!m_context)
+ get_last_error_string();
+ }
+ if (!m_context)
+ return;
+
+ (*pfn_wglMakeCurrent)(m_hdc, m_context);
+ get_proc_address(pfn_wglGetExtensionsStringEXT, "wglGetExtensionsStringEXT");
if (WGLExtensionSupported("WGL_EXT_swap_control"))
{
- pfn_wglSwapIntervalEXT = (BOOL (WINAPI *) (int)) getProcAddress("wglSwapIntervalEXT");
- pfn_wglGetSwapIntervalEXT = (int (WINAPI *) (void)) getProcAddress("wglGetSwapIntervalEXT");
+ get_proc_address(pfn_wglSwapIntervalEXT, "wglSwapIntervalEXT");
+ get_proc_address(pfn_wglGetSwapIntervalEXT, "wglGetSwapIntervalEXT");
}
else
{
pfn_wglSwapIntervalEXT = nullptr;
pfn_wglGetSwapIntervalEXT = nullptr;
}
-
- m_hdc = GetDC(window);
- if (!setupPixelFormat(m_hdc))
- {
- m_context = (*pfn_wglCreateContext)(m_hdc);
- if (!m_context)
- {
- FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, GetLastError(), 0, m_error, 255, nullptr);
- return;
- }
- (*pfn_wglMakeCurrent)(m_hdc, m_context);
- }
}
virtual ~win_gl_context()
{
- (*pfn_wglDeleteContext)(m_context);
- ReleaseDC(m_window, m_hdc);
+ if (m_context)
+ (*pfn_wglDeleteContext)(m_context);
+
+ if (m_hdc)
+ ReleaseDC(m_window, m_hdc);
+ }
+
+ virtual explicit operator bool() const override
+ {
+ return bool(m_context);
}
- virtual void MakeCurrent() override
+ virtual void make_current() override
{
(*pfn_wglMakeCurrent)(m_hdc, m_context);
}
- virtual const char *LastErrorMsg() override
+ virtual const char *last_error_message() override
{
- if (m_error[0] == 0)
- return nullptr;
+ if (!m_error.empty())
+ return m_error.c_str();
else
- return m_error;
+ return nullptr;
}
- virtual void *getProcAddress(const char *proc) override
+ virtual void *get_proc_address(const char *proc) override
{
- return (void *)(*pfn_wglGetProcAddress)(proc);
+ return reinterpret_cast<void *>(uintptr_t((*pfn_wglGetProcAddress)(proc)));
}
- virtual int SetSwapInterval(const int swap) override
+ virtual bool set_swap_interval(const int swap) override
{
- if (pfn_wglSwapIntervalEXT != nullptr)
- {
- pfn_wglSwapIntervalEXT(swap ? 1 : 0);
- }
- return 0;
+ if (!pfn_wglSwapIntervalEXT)
+ return false;
+
+ pfn_wglSwapIntervalEXT(swap ? 1 : 0);
+ return true;
}
- virtual void SwapBuffer() override
+ virtual void swap_buffer() override
{
SwapBuffers(m_hdc);
//wglSwapLayerBuffers(GetDC(window().m_hwnd), WGL_SWAP_MAIN_PLANE);
}
private:
+ // Typedefs for dynamically loaded functions
+ typedef PROC (WINAPI *wglGetProcAddress_fn)(LPCSTR);
+ typedef HGLRC (WINAPI *wglCreateContext_fn)(HDC);
+ typedef BOOL (WINAPI *wglDeleteContext_fn)(HGLRC);
+ typedef BOOL (WINAPI *wglMakeCurrent_fn)(HDC, HGLRC);
- int setupPixelFormat(HDC hDC)
+ typedef const char * (WINAPI *wglGetExtensionsStringEXT_fn)();
+ typedef BOOL (WINAPI *wglSwapIntervalEXT_fn)(int);
+ typedef int (WINAPI *wglGetSwapIntervalEXT_fn)();
+
+ bool setupPixelFormat()
{
PIXELFORMATDESCRIPTOR pfd = {
- sizeof(PIXELFORMATDESCRIPTOR), /* size */
- 1, /* version */
- PFD_SUPPORT_OPENGL |
- PFD_DRAW_TO_WINDOW |
- PFD_DOUBLEBUFFER, /* support double-buffering */
- PFD_TYPE_RGBA, /* color type */
- 32, /* prefered color depth */
- 0, 0, 0, 0, 0, 0, /* color bits (ignored) */
- 0, /* no alpha buffer */
- 0, /* alpha bits (ignored) */
- 0, /* no accumulation buffer */
- 0, 0, 0, 0, /* accum bits (ignored) */
- 16, /* depth buffer */
- 0, /* no stencil buffer */
- 0, /* no auxiliary buffers */
- PFD_MAIN_PLANE, /* main layer */
- 0, /* reserved */
- 0, 0, 0, /* no layer, visible, damage masks */
- };
-
- int pixelFormat = ChoosePixelFormat(hDC, &pfd);
-
+ sizeof(PIXELFORMATDESCRIPTOR), // size
+ 1, // version
+ PFD_SUPPORT_OPENGL |
+ PFD_DRAW_TO_WINDOW |
+ PFD_DOUBLEBUFFER, // support double-buffering
+ PFD_TYPE_RGBA, // color type
+ 32, // prefered color depth
+ 0, 0, 0, 0, 0, 0, // color bits (ignored)
+ 0, // no alpha buffer
+ 0, // alpha bits (ignored)
+ 0, // no accumulation buffer
+ 0, 0, 0, 0, // accum bits (ignored)
+ 16, // depth buffer
+ 0, // no stencil buffer
+ 0, // no auxiliary buffers
+ PFD_MAIN_PLANE, // main layer
+ 0, // reserved
+ 0, 0, 0, // no layer, visible, damage masks
+ };
+
+ const int pixelFormat = ChoosePixelFormat(m_hdc, &pfd);
if (pixelFormat == 0)
{
- strcpy(m_error, "ChoosePixelFormat failed.");
- return 1;
+ get_last_error_string();
+ return false;
}
- if (SetPixelFormat(hDC, pixelFormat, &pfd) != TRUE)
+ if (SetPixelFormat(m_hdc, pixelFormat, &pfd) != TRUE)
{
- strcpy(m_error, "SetPixelFormat failed.");
- return 1;
+ get_last_error_string();
+ return false;
}
- return 0;
+
+ return true;
}
bool WGLExtensionSupported(const char *extension_name)
{
- if (pfn_wglGetExtensionsStringEXT == nullptr)
+ if (!pfn_wglGetExtensionsStringEXT)
return false;
- // printf("%s\n", pfn_wglGetExtensionsStringEXT());
+ return strstr(pfn_wglGetExtensionsStringEXT(), extension_name) != nullptr;
+ }
- if (strstr(pfn_wglGetExtensionsStringEXT(), extension_name) != nullptr)
- return true;
- else
- return false;
+ void get_last_error_string()
+ {
+ LPTSTR buffer = nullptr;
+ const auto result = FormatMessage(
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ nullptr,
+ GetLastError(),
+ 0,
+ LPTSTR(&buffer),
+ 0,
+ nullptr);
+ if (!result || !buffer)
+ {
+ m_error.clear();
+ return;
+ }
+ try { m_error = osd::text::from_tstring(buffer); }
+ catch (...) { m_error.clear(); }
+ LocalFree(buffer);
}
HGLRC m_context;
- HWND m_window;
+ HWND const m_window;
HDC m_hdc;
- char m_error[256];
+ std::string m_error;
osd::dynamic_module::ptr opengl32_dll;
wglGetProcAddress_fn pfn_wglGetProcAddress;
@@ -181,4 +210,4 @@ private:
wglGetSwapIntervalEXT_fn pfn_wglGetSwapIntervalEXT;
};
-#endif // __WIN_GL_CONTEXT__
+#endif // MAME_RENDER_WINGLCONTEXT_H
diff --git a/src/osd/modules/sound/coreaudio_sound.cpp b/src/osd/modules/sound/coreaudio_sound.cpp
index d43d47a114f..7e9814af117 100644
--- a/src/osd/modules/sound/coreaudio_sound.cpp
+++ b/src/osd/modules/sound/coreaudio_sound.cpp
@@ -8,10 +8,11 @@
#include "sound_module.h"
#include "modules/osdmodule.h"
-#include "modules/lib/osdobj_common.h"
#ifdef SDLMAME_MACOSX
+#include "modules/lib/osdobj_common.h"
+
#include <AvailabilityMacros.h>
#include <AudioToolbox/AudioToolbox.h>
#include <AudioUnit/AudioUnit.h>
@@ -19,19 +20,14 @@
#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
-#include <string.h>
-
-
-#ifdef MAC_OS_X_VERSION_MAX_ALLOWED
-
-#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
+#include <memory>
+#include <new>
+#include <cstring>
-typedef ComponentDescription AudioComponentDescription;
-#endif // MAC_OS_X_VERSION_MAX_ALLOWED < 1060
-
-#endif // MAC_OS_X_VERSION_MAX_ALLOWED
+namespace osd {
+namespace {
class sound_coreaudio : public osd_module, public sound_module
{
@@ -41,14 +37,15 @@ public:
sound_module(),
m_graph(nullptr),
m_node_count(0),
+ m_sample_rate(0),
+ m_audio_latency(0),
m_sample_bytes(0),
m_headroom(0),
m_buffer_size(0),
- m_buffer(nullptr),
+ m_buffer(),
m_playpos(0),
m_writepos(0),
m_in_underrun(false),
- m_scale(128),
m_overflows(0),
m_underflows(0)
{
@@ -57,13 +54,12 @@ public:
{
}
- virtual int init(osd_options const &options) override;
+ virtual int init(osd_interface &osd, osd_options const &options) override;
virtual void exit() override;
// sound_module
- virtual void update_audio_stream(bool is_throttled, int16_t const *buffer, int samples_this_frame) override;
- virtual void set_mastervolume(int attenuation) override;
+ virtual void stream_sink_update(uint32_t, int16_t const *buffer, int samples_this_frame) override;
private:
struct node_detail
@@ -81,18 +77,10 @@ private:
EFFECT_COUNT_MAX = 10
};
- uint32_t clamped_latency() const { return unsigned(std::max(std::min(m_audio_latency, int(LATENCY_MAX)), int(LATENCY_MIN))); }
+ uint32_t clamped_latency() const { return unsigned(std::clamp<int>(m_audio_latency, LATENCY_MIN, LATENCY_MAX)); }
uint32_t buffer_avail() const { return ((m_writepos >= m_playpos) ? m_buffer_size : 0) + m_playpos - m_writepos; }
uint32_t buffer_used() const { return ((m_playpos > m_writepos) ? m_buffer_size : 0) + m_writepos - m_playpos; }
- void copy_scaled(void *dst, void const *src, uint32_t bytes) const
- {
- bytes /= sizeof(int16_t);
- int16_t const *s = (int16_t const *)src;
- for (int16_t *d = (int16_t *)dst; bytes > 0; bytes--, s++, d++)
- *d = (*s * m_scale) >> 7;
- }
-
bool create_graph(osd_options const &options);
bool add_output(char const *name);
bool add_device_output(char const *name);
@@ -125,8 +113,8 @@ private:
}
bool get_output_device_id(char const *name, AudioDeviceID &id) const;
- char *get_device_uid(AudioDeviceID id) const;
- char *get_device_name(AudioDeviceID id) const;
+ std::unique_ptr<char []> get_device_uid(AudioDeviceID id) const;
+ std::unique_ptr<char []> get_device_name(AudioDeviceID id) const;
UInt32 get_output_stream_count(
AudioDeviceID id,
char const *uid,
@@ -141,17 +129,14 @@ private:
CFPropertyListRef &class_info) const;
CFPropertyListRef load_property_list(char const *name) const;
- char *convert_cfstring_to_utf8(CFStringRef str) const
+ std::unique_ptr<char []> convert_cfstring_to_utf8(CFStringRef str) const
{
CFIndex const len = CFStringGetMaximumSizeForEncoding(
CFStringGetLength(str),
kCFStringEncodingUTF8);
- char *const result = global_alloc_array_clear<char>(len + 1);
- if (!CFStringGetCString(str, result, len + 1, kCFStringEncodingUTF8))
- {
- global_free_array(result);
- return nullptr;
- }
+ std::unique_ptr<char []> result = std::make_unique<char []>(len + 1);
+ if (!CFStringGetCString(str, result.get(), len + 1, kCFStringEncodingUTF8))
+ result.reset();
return result;
}
@@ -174,25 +159,28 @@ private:
unsigned m_node_count;
node_detail m_node_details[EFFECT_COUNT_MAX + 2];
- uint32_t m_sample_bytes;
- uint32_t m_headroom;
- uint32_t m_buffer_size;
- int8_t *m_buffer;
- uint32_t m_playpos;
- uint32_t m_writepos;
+ int m_sample_rate;
+ int m_audio_latency;
+ uint32_t m_sample_bytes;
+ uint32_t m_headroom;
+ uint32_t m_buffer_size;
+ std::unique_ptr<int8_t []> m_buffer;
+ uint32_t m_playpos;
+ uint32_t m_writepos;
bool m_in_underrun;
- int32_t m_scale;
unsigned m_overflows;
unsigned m_underflows;
};
-int sound_coreaudio::init(const osd_options &options)
+int sound_coreaudio::init(osd_interface &osd, const osd_options &options)
{
OSStatus err;
// Don't bother with any of this if sound is disabled
- if (sample_rate() == 0)
+ m_sample_rate = options.sample_rate();
+ m_audio_latency = options.audio_latency();
+ if (m_sample_rate == 0)
return 0;
// Create the output graph
@@ -202,7 +190,7 @@ int sound_coreaudio::init(const osd_options &options)
// Set audio stream format for two-channel native-endian 16-bit packed linear PCM
AudioStreamBasicDescription format;
- format.mSampleRate = sample_rate();
+ format.mSampleRate = m_sample_rate;
format.mFormatID = kAudioFormatLinearPCM;
format.mFormatFlags = kAudioFormatFlagsNativeEndian
| kLinearPCMFormatFlagIsSignedInteger
@@ -227,10 +215,13 @@ int sound_coreaudio::init(const osd_options &options)
m_sample_bytes = format.mBytesPerFrame;
// Allocate buffer
- m_headroom = m_sample_bytes * (clamped_latency() * sample_rate() / 40);
- m_buffer_size = m_sample_bytes * std::max<uint32_t>(sample_rate() * (clamped_latency() + 3) / 40, 256U);
- m_buffer = global_alloc_array_clear<int8_t>(m_buffer_size);
- if (!m_buffer)
+ m_headroom = m_sample_bytes * (clamped_latency() * m_sample_rate / 40);
+ m_buffer_size = m_sample_bytes * std::max<uint32_t>(m_sample_rate * (clamped_latency() + 3) / 40, 256U);
+ try
+ {
+ m_buffer = std::make_unique<int8_t []>(m_buffer_size);
+ }
+ catch (std::bad_alloc const &)
{
osd_printf_error("Could not allocate stream buffer\n");
goto close_graph_and_return_error;
@@ -238,7 +229,6 @@ int sound_coreaudio::init(const osd_options &options)
m_playpos = 0;
m_writepos = m_headroom;
m_in_underrun = false;
- m_scale = 128;
m_overflows = m_underflows = 0;
// Initialise and start
@@ -246,23 +236,21 @@ int sound_coreaudio::init(const osd_options &options)
if (noErr != err)
{
osd_printf_error("Could not initialize AudioUnit graph (%ld)\n", (long)err);
- goto free_buffer_and_return_error;
+ goto close_graph_and_return_error;
}
err = AUGraphStart(m_graph);
if (noErr != err)
{
osd_printf_error("Could not start AudioUnit graph (%ld)\n", (long)err);
AUGraphUninitialize(m_graph);
- goto free_buffer_and_return_error;
+ goto close_graph_and_return_error;
}
osd_printf_verbose("Audio: End initialization\n");
return 0;
-free_buffer_and_return_error:
- global_free_array(m_buffer);
- m_buffer_size = 0;
- m_buffer = nullptr;
close_graph_and_return_error:
+ m_buffer_size = 0;
+ m_buffer.reset();
AUGraphClose(m_graph);
DisposeAUGraph(m_graph);
m_graph = nullptr;
@@ -283,20 +271,16 @@ void sound_coreaudio::exit()
m_graph = nullptr;
m_node_count = 0;
}
- if (m_buffer)
- {
- global_free_array(m_buffer);
- m_buffer = nullptr;
- }
+ m_buffer.reset();
if (m_overflows || m_underflows)
osd_printf_verbose("Sound buffer: overflows=%u underflows=%u\n", m_overflows, m_underflows);
osd_printf_verbose("Audio: End deinitialization\n");
}
-void sound_coreaudio::update_audio_stream(bool is_throttled, int16_t const *buffer, int samples_this_frame)
+void sound_coreaudio::stream_sink_update(uint32_t, int16_t const *buffer, int samples_this_frame)
{
- if ((sample_rate() == 0) || !m_buffer)
+ if ((m_sample_rate == 0) || !m_buffer)
return;
uint32_t const bytes_this_frame = samples_this_frame * m_sample_bytes;
@@ -307,7 +291,7 @@ void sound_coreaudio::update_audio_stream(bool is_throttled, int16_t const *buff
}
uint32_t const chunk = std::min(m_buffer_size - m_writepos, bytes_this_frame);
- memcpy(m_buffer + m_writepos, (int8_t *)buffer, chunk);
+ memcpy(&m_buffer[m_writepos], (int8_t *)buffer, chunk);
m_writepos += chunk;
if (m_writepos >= m_buffer_size)
m_writepos = 0;
@@ -316,19 +300,12 @@ void sound_coreaudio::update_audio_stream(bool is_throttled, int16_t const *buff
{
assert(0U == m_writepos);
assert(m_playpos > (bytes_this_frame - chunk));
- memcpy(m_buffer, (int8_t *)buffer + chunk, bytes_this_frame - chunk);
+ memcpy(&m_buffer[0], (int8_t *)buffer + chunk, bytes_this_frame - chunk);
m_writepos += bytes_this_frame - chunk;
}
}
-void sound_coreaudio::set_mastervolume(int attenuation)
-{
- int const clamped_attenuation = std::max(std::min(attenuation, 0), -32);
- m_scale = (-32 == clamped_attenuation) ? 0 : (int32_t)(pow(10.0, clamped_attenuation / 20.0) * 128);
-}
-
-
bool sound_coreaudio::create_graph(osd_options const &options)
{
OSStatus err;
@@ -648,7 +625,7 @@ bool sound_coreaudio::get_output_device_id(
return false;
}
property_size /= sizeof(AudioDeviceID);
- AudioDeviceID *const devices = global_alloc_array_clear<AudioDeviceID>(property_size);
+ std::unique_ptr<AudioDeviceID []> const devices = std::make_unique<AudioDeviceID []>(property_size);
property_size *= sizeof(AudioDeviceID);
err = AudioObjectGetPropertyData(
kAudioObjectSystemObject,
@@ -656,20 +633,19 @@ bool sound_coreaudio::get_output_device_id(
0,
nullptr,
&property_size,
- devices);
+ devices.get());
UInt32 const device_count = property_size / sizeof(AudioDeviceID);
if (noErr != err)
{
osd_printf_error("Error getting audio device list (%ld)\n", (long)err);
- global_free_array(devices);
return false;
}
for (UInt32 i = 0; device_count > i; i++)
{
- char *const device_uid = get_device_uid(devices[i]);
- char *const device_name = get_device_name(devices[i]);
- if ((nullptr == device_uid) && (nullptr == device_name))
+ std::unique_ptr<char []> const device_uid = get_device_uid(devices[i]);
+ std::unique_ptr<char []> const device_name = get_device_name(devices[i]);
+ if (!device_uid && !device_name)
{
osd_printf_warning(
"Could not get UID or name for device %lu - skipping\n",
@@ -679,52 +655,46 @@ bool sound_coreaudio::get_output_device_id(
UInt32 const streams = get_output_stream_count(
devices[i],
- device_uid,
- device_name);
+ device_uid.get(),
+ device_name.get());
if (1U > streams)
{
osd_printf_verbose(
"No output streams found for device %s (%s) - skipping\n",
- (nullptr != device_name) ? device_name : "<anonymous>",
- (nullptr != device_uid) ? device_uid : "<unknown>");
- if (nullptr != device_uid) global_free_array(device_uid);
- if (nullptr != device_name) global_free_array(device_name);
+ device_name ? device_name.get() : "<anonymous>",
+ device_uid ? device_uid.get() : "<unknown>");
continue;
}
- for (std::size_t j = strlen(device_uid); (0 < j) && (' ' == device_uid[j - 1]); j--)
+ for (std::size_t j = strlen(device_uid.get()); (0 < j) && (' ' == device_uid[j - 1]); j--)
device_uid[j - 1] = '\0';
- for (std::size_t j = strlen(device_name); (0 < j) && (' ' == device_name[j - 1]); j--)
+ for (std::size_t j = strlen(device_name.get()); (0 < j) && (' ' == device_name[j - 1]); j--)
device_name[j - 1] = '\0';
- bool const matched_uid = (nullptr != device_uid) && !strcmp(name, device_uid);
- bool const matched_name = (nullptr != device_name) && !strcmp(name, device_name);
+ bool const matched_uid = device_uid && !strcmp(name, device_uid.get());
+ bool const matched_name = device_name && !strcmp(name, device_name.get());
if (matched_uid || matched_name)
{
osd_printf_verbose(
"Matched device %s (%s) with %lu output stream(s)\n",
- (nullptr != device_name) ? device_name : "<anonymous>",
- (nullptr != device_uid) ? device_uid : "<unknown>",
+ device_name ? device_name.get() : "<anonymous>",
+ device_uid ? device_uid.get() : "<unknown>",
(unsigned long)streams);
}
- global_free_array(device_uid);
- global_free_array(device_name);
if (matched_uid || matched_name)
{
id = devices[i];
- global_free_array(devices);
return true;
}
}
osd_printf_verbose("No audio output devices match %s\n", name);
- global_free_array(devices);
return false;
}
-char *sound_coreaudio::get_device_uid(AudioDeviceID id) const
+std::unique_ptr<char []> sound_coreaudio::get_device_uid(AudioDeviceID id) const
{
AudioObjectPropertyAddress const uid_addr = {
kAudioDevicePropertyDeviceUID,
@@ -747,9 +717,9 @@ char *sound_coreaudio::get_device_uid(AudioDeviceID id) const
(long)err);
return nullptr;
}
- char *const result = convert_cfstring_to_utf8(device_uid);
+ std::unique_ptr<char []> result = convert_cfstring_to_utf8(device_uid);
CFRelease(device_uid);
- if (nullptr == result)
+ if (!result)
{
osd_printf_warning(
"Error converting UID for audio device %lu to UTF-8\n",
@@ -759,7 +729,7 @@ char *sound_coreaudio::get_device_uid(AudioDeviceID id) const
}
-char *sound_coreaudio::get_device_name(AudioDeviceID id) const
+std::unique_ptr<char []> sound_coreaudio::get_device_name(AudioDeviceID id) const
{
AudioObjectPropertyAddress const name_addr = {
kAudioDevicePropertyDeviceNameCFString,
@@ -782,9 +752,9 @@ char *sound_coreaudio::get_device_name(AudioDeviceID id) const
(long)err);
return nullptr;
}
- char *const result = convert_cfstring_to_utf8(device_name);
+ std::unique_ptr<char []> result = convert_cfstring_to_utf8(device_name);
CFRelease(device_name);
- if (nullptr == result)
+ if (!result)
{
osd_printf_warning(
"Error converting name for audio device %lu to UTF-8\n",
@@ -913,51 +883,48 @@ CFPropertyListRef sound_coreaudio::load_property_list(char const *name) const
(UInt8 const *)name,
strlen(name),
false);
- if (nullptr == url)
- {
+ if (!url)
return nullptr;
- }
- CFDataRef data = nullptr;
- SInt32 err;
- Boolean const status = CFURLCreateDataAndPropertiesFromResource(
- nullptr,
- url,
- &data,
- nullptr,
- nullptr,
- &err);
+ CFReadStreamRef const stream = CFReadStreamCreateWithFile(nullptr, url);
CFRelease(url);
- if (!status)
+ if (!stream)
{
- osd_printf_error(
- "Error reading data from %s (%ld)\n",
- name,
- (long)err);
- if (nullptr != data) CFRelease(data);
+ osd_printf_error("Error opening file %s\n", name);
+ return nullptr;
+ }
+ if (!CFReadStreamOpen(stream))
+ {
+ CFRelease(stream);
+ osd_printf_error("Error opening file %s\n", name);
return nullptr;
}
- CFStringRef msg = nullptr;
- CFPropertyListRef const result = CFPropertyListCreateFromXMLData(
+ CFErrorRef msg = nullptr;
+ CFPropertyListRef const result = CFPropertyListCreateWithStream(
nullptr,
- data,
+ stream,
+ 0,
kCFPropertyListImmutable,
+ nullptr,
&msg);
- CFRelease(data);
- if ((nullptr == result) || (nullptr != msg))
- {
- char *buf = (nullptr != msg) ? convert_cfstring_to_utf8(msg) : nullptr;
- if (nullptr != msg)
+ CFReadStreamClose(stream);
+ CFRelease(stream);
+ if (!result || msg)
+ {
+ CFStringRef const desc = msg ? CFErrorCopyDescription(msg) : nullptr;
+ std::unique_ptr<char []> const buf = desc ? convert_cfstring_to_utf8(desc) : nullptr;
+ if (desc)
+ CFRelease(desc);
+ if (msg)
CFRelease(msg);
- if (nullptr != buf)
+ if (buf)
{
osd_printf_error(
"Error creating property list from %s: %s\n",
name,
- buf);
- global_free_array(buf);
+ buf.get());
}
else
{
@@ -965,7 +932,8 @@ CFPropertyListRef sound_coreaudio::load_property_list(char const *name) const
"Error creating property list from %s\n",
name);
}
- if (nullptr != result) CFRelease(result);
+ if (result)
+ CFRelease(result);
return nullptr;
}
@@ -997,7 +965,7 @@ OSStatus sound_coreaudio::render(
}
uint32_t const chunk = std::min(m_buffer_size - m_playpos, number_bytes);
- copy_scaled((int8_t *)data->mBuffers[0].mData, m_buffer + m_playpos, chunk);
+ memcpy((int8_t *)data->mBuffers[0].mData, &m_buffer[m_playpos], chunk);
m_playpos += chunk;
if (m_playpos >= m_buffer_size)
m_playpos = 0;
@@ -1006,7 +974,7 @@ OSStatus sound_coreaudio::render(
{
assert(0U == m_playpos);
assert(m_writepos >= (number_bytes - chunk));
- copy_scaled((int8_t *)data->mBuffers[0].mData + chunk, m_buffer, number_bytes - chunk);
+ memcpy((int8_t *)data->mBuffers[0].mData + chunk, &m_buffer[0], number_bytes - chunk);
m_playpos += number_bytes - chunk;
}
@@ -1025,8 +993,14 @@ OSStatus sound_coreaudio::render_callback(
return ((sound_coreaudio *)refcon)->render(action_flags, timestamp, bus_number, number_frames, data);
}
-#else /* SDLMAME_MACOSX */
- MODULE_NOT_SUPPORTED(sound_coreaudio, OSD_SOUND_PROVIDER, "coreaudio")
-#endif
+} // anonymous namespace
+
+} // namespace osd
+
+#else // SDLMAME_MACOSX
+
+namespace osd { namespace { MODULE_NOT_SUPPORTED(sound_coreaudio, OSD_SOUND_PROVIDER, "coreaudio") } }
+
+#endif // SDLMAME_MACOSX
-MODULE_DEFINITION(SOUND_COREAUDIO, sound_coreaudio)
+MODULE_DEFINITION(SOUND_COREAUDIO, osd::sound_coreaudio)
diff --git a/src/osd/modules/sound/direct_sound.cpp b/src/osd/modules/sound/direct_sound.cpp
index 4d6c8c26c50..7417def934c 100644
--- a/src/osd/modules/sound/direct_sound.cpp
+++ b/src/osd/modules/sound/direct_sound.cpp
@@ -11,236 +11,235 @@
#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
-// standard windows headers
-#include <windows.h>
-#include <mmsystem.h>
-
-// undef WINNT for dsound.h to prevent duplicate definition
-#undef WINNT
-#include <dsound.h>
-#undef interface
-
// MAME headers
-#include "emu.h"
-#include "osdepend.h"
#include "emuopts.h"
+// osd headers
+#include "modules/lib/osdobj_common.h"
+#include "osdepend.h"
+#include "osdcore.h"
+
#ifdef SDLMAME_WIN32
-#include "../../sdl/osdsdl.h"
+#include "sdl/window.h"
#include <SDL2/SDL_syswm.h>
-#include "../../sdl/window.h"
#else
#include "winmain.h"
#include "window.h"
#endif
+
#include <utility>
+// standard windows headers
+
+#include <windows.h>
+
+#include <mmreg.h>
+#include <mmsystem.h>
+
+#include <dsound.h>
+
+#include <wrl/client.h>
+
+
//============================================================
// DEBUGGING
//============================================================
#define LOG_SOUND 0
-#define LOG(x) do { if (LOG_SOUND) osd_printf_verbose x; } while(0)
+#define LOG(...) do { if (LOG_SOUND) osd_printf_verbose(__VA_ARGS__); } while(0)
-class sound_direct_sound : public osd_module, public sound_module
+namespace osd {
+
+namespace {
+
+class buffer_base
{
public:
+ explicit operator bool() const { return bool(m_buffer); }
- sound_direct_sound() :
- osd_module(OSD_SOUND_PROVIDER, "dsound"),
- sound_module(),
- m_dsound(nullptr),
- m_bytes_per_sample(0),
- m_primary_buffer(),
- m_stream_buffer(),
- m_stream_buffer_in(0),
- m_buffer_underflows(0),
- m_buffer_overflows(0)
- {
- }
- virtual ~sound_direct_sound() { }
+ unsigned long release() { return m_buffer.Reset(); }
- virtual int init(osd_options const &options) override;
- virtual void exit() override;
+protected:
+ Microsoft::WRL::ComPtr<IDirectSoundBuffer> m_buffer;
+};
- // sound_module
- virtual void update_audio_stream(bool is_throttled, int16_t const *buffer, int samples_this_frame) override;
- virtual void set_mastervolume(int attenuation) override;
-private:
- class buffer
+class primary_buffer : public buffer_base
+{
+public:
+ HRESULT create(LPDIRECTSOUND dsound)
{
- public:
- buffer() : m_buffer(nullptr) { }
- ~buffer() { release(); }
+ assert(!m_buffer);
+ DSBUFFERDESC desc;
+ memset(&desc, 0, sizeof(desc));
+ desc.dwSize = sizeof(desc);
+ desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2;
+ desc.lpwfxFormat = nullptr;
+ return dsound->CreateSoundBuffer(&desc, &m_buffer, nullptr);
+ }
- ULONG release()
- {
- ULONG const result = m_buffer ? m_buffer->Release() : 0;
- m_buffer = nullptr;
- return result;
- }
+ HRESULT get_format(WAVEFORMATEX &format) const
+ {
+ assert(m_buffer);
+ return m_buffer->GetFormat(&format, sizeof(format), nullptr);
+ }
- operator bool() const { return m_buffer; }
+ HRESULT set_format(WAVEFORMATEX const &format) const
+ {
+ assert(m_buffer);
+ return m_buffer->SetFormat(&format);
+ }
+};
- protected:
- LPDIRECTSOUNDBUFFER m_buffer;
- };
- class primary_buffer : public buffer
+class stream_buffer : public buffer_base
+{
+public:
+ HRESULT create(LPDIRECTSOUND dsound, DWORD size, WAVEFORMATEX &format)
{
- public:
- HRESULT create(LPDIRECTSOUND dsound)
- {
- assert(!m_buffer);
- DSBUFFERDESC desc;
- memset(&desc, 0, sizeof(desc));
- desc.dwSize = sizeof(desc);
- desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2;
- desc.lpwfxFormat = nullptr;
- return dsound->CreateSoundBuffer(&desc, &m_buffer, nullptr);
- }
+ assert(!m_buffer);
+ DSBUFFERDESC desc;
+ memset(&desc, 0, sizeof(desc));
+ desc.dwSize = sizeof(desc);
+ desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
+ desc.dwBufferBytes = size;
+ desc.lpwfxFormat = &format;
+ m_size = size;
+ return dsound->CreateSoundBuffer(&desc, &m_buffer, nullptr);
+ }
- HRESULT get_format(WAVEFORMATEX &format) const
- {
- assert(m_buffer);
- return m_buffer->GetFormat(&format, sizeof(format), nullptr);
- }
- HRESULT set_format(WAVEFORMATEX const &format) const
+ HRESULT play_looping() const
+ {
+ assert(m_buffer);
+ return m_buffer->Play(0, 0, DSBPLAY_LOOPING);
+ }
+ HRESULT stop() const
+ {
+ assert(m_buffer);
+ return m_buffer->Stop();
+ }
+ HRESULT get_current_positions(DWORD &play_pos, DWORD &write_pos) const
+ {
+ assert(m_buffer);
+ return m_buffer->GetCurrentPosition(&play_pos, &write_pos);
+ }
+ HRESULT copy_data(DWORD cursor, DWORD bytes, void const *data)
+ {
+ HRESULT result = lock(cursor, bytes);
+ if (DS_OK != result)
+ return result;
+
+ assert(m_bytes1);
+ assert((m_locked1 + m_locked2) >= bytes);
+ memcpy(m_bytes1, data, std::min(m_locked1, bytes));
+ if (m_locked1 < bytes)
{
- assert(m_buffer);
- return m_buffer->SetFormat(&format);
+ assert(m_bytes2);
+ memcpy(m_bytes2, (uint8_t const *)data + m_locked1, bytes - m_locked1);
}
- };
- class stream_buffer : public buffer
+ unlock();
+ return DS_OK;
+ }
+ HRESULT clear()
{
- public:
- stream_buffer() : m_size(0), m_bytes1(nullptr), m_bytes2(nullptr), m_locked1(0), m_locked2(0) { }
+ HRESULT result = lock_all();
+ if (DS_OK != result)
+ return result;
- HRESULT create(LPDIRECTSOUND dsound, DWORD size, WAVEFORMATEX &format)
- {
- assert(!m_buffer);
- DSBUFFERDESC desc;
- memset(&desc, 0, sizeof(desc));
- desc.dwSize = sizeof(desc);
- desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
- desc.dwBufferBytes = size;
- desc.lpwfxFormat = &format;
- m_size = size;
- return dsound->CreateSoundBuffer(&desc, &m_buffer, nullptr);
- }
+ assert(m_bytes1);
+ assert(!m_bytes2);
+ assert(m_size == m_locked1);
+ assert(0U == m_locked2);
+ memset(m_bytes1, 0, m_locked1);
- HRESULT play_looping() const
- {
- assert(m_buffer);
- return m_buffer->Play(0, 0, DSBPLAY_LOOPING);
- }
- HRESULT stop() const
- {
- assert(m_buffer);
- return m_buffer->Stop();
- }
- HRESULT set_volume(LONG volume) const
- {
- assert(m_buffer);
- return m_buffer->SetVolume(volume);
- }
- HRESULT set_min_volume() { return set_volume(DSBVOLUME_MIN); }
+ unlock();
+ return DS_OK;
+ }
- HRESULT get_current_positions(DWORD &play_pos, DWORD &write_pos) const
- {
- assert(m_buffer);
- return m_buffer->GetCurrentPosition(&play_pos, &write_pos);
- }
- HRESULT copy_data(DWORD cursor, DWORD bytes, void const *data)
- {
- HRESULT result = lock(cursor, bytes);
- if (DS_OK != result)
- return result;
-
- assert(m_bytes1);
- assert((m_locked1 + m_locked2) >= bytes);
- memcpy(m_bytes1, data, std::min(m_locked1, bytes));
- if (m_locked1 < bytes)
- {
- assert(m_bytes2);
- memcpy(m_bytes2, (uint8_t const *)data + m_locked1, bytes - m_locked1);
- }
-
- unlock();
- return DS_OK;
- }
- HRESULT clear()
- {
- HRESULT result = lock_all();
- if (DS_OK != result)
- return result;
-
- assert(m_bytes1);
- assert(!m_bytes2);
- assert(m_size == m_locked1);
- assert(0U == m_locked2);
- memset(m_bytes1, 0, m_locked1);
-
- unlock();
- return DS_OK;
- }
+ DWORD size() const { return m_size; }
- DWORD size() const { return m_size; }
+private:
+ HRESULT lock(DWORD cursor, DWORD bytes)
+ {
+ assert(cursor < m_size);
+ assert(bytes <= m_size);
+ assert(m_buffer);
+ assert(!m_bytes1);
+ return m_buffer->Lock(
+ cursor, bytes,
+ &m_bytes1,
+ &m_locked1,
+ &m_bytes2,
+ &m_locked2,
+ 0);
+ }
+ HRESULT lock_all() { return lock(0, m_size); }
+ HRESULT unlock()
+ {
+ assert(m_buffer);
+ assert(m_bytes1);
+ HRESULT const result = m_buffer->Unlock(
+ m_bytes1,
+ m_locked1,
+ m_bytes2,
+ m_locked2);
+ m_bytes1 = m_bytes2 = nullptr;
+ m_locked1 = m_locked2 = 0;
+ return result;
+ }
- protected:
- HRESULT lock(DWORD cursor, DWORD bytes)
- {
- assert(cursor < m_size);
- assert(bytes <= m_size);
- assert(m_buffer);
- assert(!m_bytes1);
- return m_buffer->Lock(
- cursor, bytes,
- &m_bytes1,
- &m_locked1,
- &m_bytes2,
- &m_locked2,
- 0);
- }
- HRESULT lock_all() { return lock(0, m_size); }
- HRESULT unlock()
- {
- assert(m_buffer);
- assert(m_bytes1);
- HRESULT const result = m_buffer->Unlock(
- m_bytes1,
- m_locked1,
- m_bytes2,
- m_locked2);
- m_bytes1 = m_bytes2 = nullptr;
- m_locked1 = m_locked2 = 0;
- return result;
- }
+ DWORD m_size = 0;
+ void *m_bytes1 = nullptr, *m_bytes2 = nullptr;
+ DWORD m_locked1 = 0, m_locked2 = 0;
+};
- DWORD m_size;
- void *m_bytes1, *m_bytes2;
- DWORD m_locked1, m_locked2;
- };
+class sound_direct_sound : public osd_module, public sound_module
+{
+public:
+ sound_direct_sound() :
+ osd_module(OSD_SOUND_PROVIDER, "dsound"),
+ sound_module(),
+ m_sample_rate(0),
+ m_audio_latency(0),
+ m_bytes_per_sample(0),
+ m_primary_buffer(),
+ m_stream_buffer(),
+ m_stream_buffer_in(0),
+ m_buffer_underflows(0),
+ m_buffer_overflows(0)
+ {
+ }
+
+ virtual int init(osd_interface &osd, osd_options const &options) override;
+ virtual void exit() override;
+
+ // sound_module
+ virtual void stream_sink_update(uint32_t, int16_t const *buffer, int samples_this_frame) override;
+
+private:
HRESULT dsound_init();
void dsound_kill();
HRESULT create_buffers(DWORD size, WAVEFORMATEX &format);
void destroy_buffers();
// DirectSound objects
- LPDIRECTSOUND m_dsound;
+ Microsoft::WRL::ComPtr<IDirectSound> m_dsound;
+
+ // configuration
+ int m_sample_rate;
+ int m_audio_latency;
// descriptors and formats
- uint32_t m_bytes_per_sample;
+ uint32_t m_bytes_per_sample;
// sound buffers
primary_buffer m_primary_buffer;
stream_buffer m_stream_buffer;
- uint32_t m_stream_buffer_in;
+ uint32_t m_stream_buffer_in;
// buffer over/underflow counts
unsigned m_buffer_underflows;
@@ -252,12 +251,16 @@ private:
// init
//============================================================
-int sound_direct_sound::init(osd_options const &options)
+int sound_direct_sound::init(osd_interface &osd, osd_options const &options)
{
- // attempt to initialize directsound
- // don't make it fatal if we can't -- we'll just run without sound
- dsound_init();
+ m_sample_rate = options.sample_rate();
+ m_audio_latency = options.audio_latency();
m_buffer_underflows = m_buffer_overflows = 0;
+
+ // attempt to initialize DirectSound
+ if (dsound_init() != DS_OK)
+ return -1;
+
return 0;
}
@@ -281,16 +284,16 @@ void sound_direct_sound::exit()
m_buffer_underflows);
}
- LOG(("Sound buffer: overflows=%u underflows=%u\n", m_buffer_overflows, m_buffer_underflows));
+ LOG("Sound buffer: overflows=%u underflows=%u\n", m_buffer_overflows, m_buffer_underflows);
}
//============================================================
-// update_audio_stream
+// stream_sink_update
//============================================================
-void sound_direct_sound::update_audio_stream(
- bool is_throttled,
+void sound_direct_sound::stream_sink_update(
+ uint32_t,
int16_t const *buffer,
int samples_this_frame)
{
@@ -307,7 +310,7 @@ void sound_direct_sound::update_audio_stream(
if (DS_OK != result)
return;
-//DWORD orig_write = write_position;
+ //DWORD orig_write = write_position;
// normalize the write position so it is always after the play position
if (write_position < play_position)
write_position += m_stream_buffer.size();
@@ -323,7 +326,7 @@ void sound_direct_sound::update_audio_stream(
// if we're between play and write positions, then bump forward, but only in full chunks
while (stream_in < write_position)
{
-//printf("Underflow: PP=%d WP=%d(%d) SI=%d(%d) BTF=%d\n", (int)play_position, (int)write_position, (int)orig_write, (int)stream_in, (int)m_stream_buffer_in, (int)bytes_this_frame);
+ //printf("Underflow: PP=%d WP=%d(%d) SI=%d(%d) BTF=%d\n", (int)play_position, (int)write_position, (int)orig_write, (int)stream_in, (int)m_stream_buffer_in, (int)bytes_this_frame);
m_buffer_underflows++;
stream_in += bytes_this_frame;
}
@@ -331,7 +334,7 @@ void sound_direct_sound::update_audio_stream(
// if we're going to overlap the play position, just skip this chunk
if ((stream_in + bytes_this_frame) > (play_position + m_stream_buffer.size()))
{
-//printf("Overflow: PP=%d WP=%d(%d) SI=%d(%d) BTF=%d\n", (int)play_position, (int)write_position, (int)orig_write, (int)stream_in, (int)m_stream_buffer_in, (int)bytes_this_frame);
+ //printf("Overflow: PP=%d WP=%d(%d) SI=%d(%d) BTF=%d\n", (int)play_position, (int)write_position, (int)orig_write, (int)stream_in, (int)m_stream_buffer_in, (int)bytes_this_frame);
m_buffer_overflows++;
return;
}
@@ -353,26 +356,6 @@ void sound_direct_sound::update_audio_stream(
//============================================================
-// set_mastervolume
-//============================================================
-
-void sound_direct_sound::set_mastervolume(int attenuation)
-{
- // clamp the attenuation to 0-32 range
- attenuation = std::max(std::min(attenuation, 0), -32);
-
- // set the master volume
- if (m_stream_buffer)
- {
- if (-32 == attenuation)
- m_stream_buffer.set_min_volume();
- else
- m_stream_buffer.set_volume(100 * attenuation);
- }
-}
-
-
-//============================================================
// dsound_init
//============================================================
@@ -385,7 +368,7 @@ HRESULT sound_direct_sound::dsound_init()
result = DirectSoundCreate(nullptr, &m_dsound, nullptr);
if (result != DS_OK)
{
- osd_printf_error("Error creating DirectSound: %08x\n", (unsigned)result);
+ osd_printf_error("Error creating DirectSound: %08x\n", result);
goto error;
}
@@ -395,7 +378,7 @@ HRESULT sound_direct_sound::dsound_init()
result = m_dsound->GetCaps(&dsound_caps);
if (result != DS_OK)
{
- osd_printf_error("Error getting DirectSound capabilities: %08x\n", (unsigned)result);
+ osd_printf_error("Error getting DirectSound capabilities: %08x\n", result);
goto error;
}
@@ -404,34 +387,40 @@ HRESULT sound_direct_sound::dsound_init()
#ifdef SDLMAME_WIN32
SDL_SysWMinfo wminfo;
SDL_VERSION(&wminfo.version);
- SDL_GetWindowWMInfo(std::dynamic_pointer_cast<sdl_window_info>(osd_common_t::s_window_list.front())->platform_window(), &wminfo);
+ if (!SDL_GetWindowWMInfo(dynamic_cast<sdl_window_info &>(*osd_common_t::window_list().front()).platform_window(), &wminfo))
+ {
+ result = DSERR_UNSUPPORTED; // just so it has something to return
+ goto error;
+ }
HWND const window = wminfo.info.win.window;
#else // SDLMAME_WIN32
- HWND const window = std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window();
+ HWND const window = dynamic_cast<win_window_info &>(*osd_common_t::window_list().front()).platform_window();
#endif // SDLMAME_WIN32
result = m_dsound->SetCooperativeLevel(window, DSSCL_PRIORITY);
}
if (result != DS_OK)
{
- osd_printf_error("Error setting DirectSound cooperative level: %08x\n", (unsigned)result);
+ osd_printf_error("Error setting DirectSound cooperative level: %08x\n", result);
goto error;
}
{
// make a format description for what we want
WAVEFORMATEX stream_format;
- stream_format.wBitsPerSample = 16;
stream_format.wFormatTag = WAVE_FORMAT_PCM;
stream_format.nChannels = 2;
- stream_format.nSamplesPerSec = sample_rate();
+ stream_format.nSamplesPerSec = m_sample_rate;
+ stream_format.wBitsPerSample = 16;
stream_format.nBlockAlign = stream_format.wBitsPerSample * stream_format.nChannels / 8;
stream_format.nAvgBytesPerSec = stream_format.nSamplesPerSec * stream_format.nBlockAlign;
+ stream_format.cbSize = 0;
// compute the buffer size based on the output sample rate
- DWORD stream_buffer_size = stream_format.nSamplesPerSec * stream_format.nBlockAlign * m_audio_latency / 10;
+ int audio_latency = std::max(m_audio_latency, 1);
+ DWORD stream_buffer_size = stream_format.nSamplesPerSec * stream_format.nBlockAlign * audio_latency / 10;
stream_buffer_size = std::max(DWORD(1024), (stream_buffer_size / 1024) * 1024);
- LOG(("stream_buffer_size = %u\n", (unsigned)stream_buffer_size));
+ LOG("stream_buffer_size = %u\n", stream_buffer_size);
// create the buffers
m_bytes_per_sample = stream_format.nBlockAlign;
@@ -445,7 +434,7 @@ HRESULT sound_direct_sound::dsound_init()
result = m_stream_buffer.play_looping();
if (result != DS_OK)
{
- osd_printf_error("Error playing: %08x\n", (uint32_t)result);
+ osd_printf_error("Error playing: %08x\n", result);
goto error;
}
return DS_OK;
@@ -465,9 +454,7 @@ error:
void sound_direct_sound::dsound_kill()
{
// release the object
- if (m_dsound)
- m_dsound->Release();
- m_dsound = nullptr;
+ m_dsound.Reset();
}
@@ -483,10 +470,10 @@ HRESULT sound_direct_sound::create_buffers(DWORD size, WAVEFORMATEX &format)
HRESULT result;
// create the primary buffer
- result = m_primary_buffer.create(m_dsound);
+ result = m_primary_buffer.create(m_dsound.Get());
if (result != DS_OK)
{
- osd_printf_error("Error creating primary DirectSound buffer: %08x\n", (unsigned)result);
+ osd_printf_error("Error creating primary DirectSound buffer: %08x\n", result);
goto error;
}
@@ -494,7 +481,7 @@ HRESULT sound_direct_sound::create_buffers(DWORD size, WAVEFORMATEX &format)
result = m_primary_buffer.set_format(format);
if (result != DS_OK)
{
- osd_printf_error("Error setting primary DirectSound buffer format: %08x\n", (unsigned)result);
+ osd_printf_error("Error setting primary DirectSound buffer format: %08x\n", result);
goto error;
}
@@ -503,20 +490,20 @@ HRESULT sound_direct_sound::create_buffers(DWORD size, WAVEFORMATEX &format)
result = m_primary_buffer.get_format(primary_format);
if (result != DS_OK)
{
- osd_printf_error("Error getting primary DirectSound buffer format: %08x\n", (unsigned)result);
+ osd_printf_error("Error getting primary DirectSound buffer format: %08x\n", result);
goto error;
}
osd_printf_verbose(
"DirectSound: Primary buffer: %d Hz, %d bits, %d channels\n",
- (int)primary_format.nSamplesPerSec,
- (int)primary_format.wBitsPerSample,
- (int)primary_format.nChannels);
+ primary_format.nSamplesPerSec,
+ primary_format.wBitsPerSample,
+ primary_format.nChannels);
// create the stream buffer
- result = m_stream_buffer.create(m_dsound, size, format);
+ result = m_stream_buffer.create(m_dsound.Get(), size, format);
if (result != DS_OK)
{
- osd_printf_error("Error creating DirectSound stream buffer: %08x\n", (unsigned)result);
+ osd_printf_error("Error creating DirectSound stream buffer: %08x\n", result);
goto error;
}
@@ -524,7 +511,7 @@ HRESULT sound_direct_sound::create_buffers(DWORD size, WAVEFORMATEX &format)
result = m_stream_buffer.clear();
if (result != DS_OK)
{
- osd_printf_error("Error locking DirectSound stream buffer: %08x\n", (unsigned)result);
+ osd_printf_error("Error locking DirectSound stream buffer: %08x\n", result);
goto error;
}
@@ -541,7 +528,7 @@ error:
// destroy_buffers
//============================================================
-void sound_direct_sound::destroy_buffers(void)
+void sound_direct_sound::destroy_buffers()
{
// stop any playback
if (m_stream_buffer)
@@ -554,8 +541,16 @@ void sound_direct_sound::destroy_buffers(void)
m_primary_buffer.release();
}
+} // anonymous namespace
+
+} // namespace osd
+
+
#else // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
- MODULE_NOT_SUPPORTED(sound_direct_sound, OSD_SOUND_PROVIDER, "dsound")
+
+namespace osd { namespace { MODULE_NOT_SUPPORTED(sound_direct_sound, OSD_SOUND_PROVIDER, "dsound") } }
+
#endif // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
-MODULE_DEFINITION(SOUND_DSOUND, sound_direct_sound)
+
+MODULE_DEFINITION(SOUND_DSOUND, osd::sound_direct_sound)
diff --git a/src/osd/modules/sound/js_sound.cpp b/src/osd/modules/sound/js_sound.cpp
index afcf6ec8f2b..1473ef9de2a 100644
--- a/src/osd/modules/sound/js_sound.cpp
+++ b/src/osd/modules/sound/js_sound.cpp
@@ -11,7 +11,7 @@
#include "sound_module.h"
#include "modules/osdmodule.h"
-#if (defined(SDLMAME_EMSCRIPTEN))
+#if defined(SDLMAME_EMSCRIPTEN)
#include "emscripten.h"
@@ -19,36 +19,30 @@ class sound_js : public osd_module, public sound_module
{
public:
- sound_js()
- : osd_module(OSD_SOUND_PROVIDER, "js"), sound_module()
+ sound_js() : osd_module(OSD_SOUND_PROVIDER, "js"), sound_module()
{
}
virtual ~sound_js() { }
- virtual int init(const osd_options &options) { return 0; }
+ virtual int init(osd_interface &osd, const osd_options &options) { return 0; }
virtual void exit() { }
// sound_module
- virtual void update_audio_stream(bool is_throttled, const int16_t *buffer, int samples_this_frame)
+ virtual void stream_sink_update(uint32_t, const int16_t *buffer, int samples_this_frame)
{
- EM_ASM_ARGS({
- // Forward audio stream update on to JS backend implementation.
- jsmame_update_audio_stream($0, $1);
- }, (unsigned int)buffer, samples_this_frame);
+ EM_ASM_ARGS(
+ {
+ // Forward audio stream update on to JS backend implementation.
+ jsmame_steam_update($1, $2);
+ },
+ (unsigned int)buffer,
+ samples_this_frame);
}
- virtual void set_mastervolume(int attenuation)
- {
- EM_ASM_ARGS({
- // Forward volume update on to JS backend implementation.
- jsmame_set_mastervolume($0);
- }, attenuation);
- }
-
};
-#else /* SDLMAME_UNIX */
+#else // SDLMAME_EMSCRIPTEN
MODULE_NOT_SUPPORTED(sound_js, OSD_SOUND_PROVIDER, "js")
-#endif
+#endif // SDLMAME_EMSCRIPTEN
MODULE_DEFINITION(SOUND_JS, sound_js)
diff --git a/src/osd/modules/sound/js_sound.js b/src/osd/modules/sound/js_sound.js
index 5cbcc380c1b..25f19231ae9 100644
--- a/src/osd/modules/sound/js_sound.js
+++ b/src/osd/modules/sound/js_sound.js
@@ -98,30 +98,7 @@ function disconnect_old_event() {
eventNode = null;
};
-function set_mastervolume (
- // even though it's 'attenuation' the value is negative, so...
- attenuation_in_decibels
-) {
- lazy_init();
- if (!context) return;
-
- // http://stackoverflow.com/questions/22604500/web-audio-api-working-with-decibels
- // seemingly incorrect/broken. figures. welcome to Web Audio
- // var gain_web_audio = 1.0 - Math.pow(10, 10 / attenuation_in_decibels);
-
- // HACK: Max attenuation in JSMESS appears to be 32.
- // Hit ' then left/right arrow to test.
- // FIXME: This is linear instead of log10 scale.
- var gain_web_audio = 1.0 + (+attenuation_in_decibels / +32);
- if (gain_web_audio < +0)
- gain_web_audio = +0;
- else if (gain_web_audio > +1)
- gain_web_audio = +1;
-
- gain_node.gain.value = gain_web_audio;
-};
-
-function update_audio_stream (
+function stream_sink_update (
pBuffer, // pointer into emscripten heap. int16 samples
samples_this_frame // int. number of samples at pBuffer address.
) {
@@ -173,10 +150,11 @@ function tick (event) {
start = 0;
}
}
- //Pad with silence if we're underrunning:
+ //Pad with latest if we're underrunning:
+ var idx = (index == 0 ? bufferSize : index) - 1;
while (index < 4096) {
- buffers[0][index] = 0;
- buffers[1][index++] = 0;
+ buffers[0][index] = buffers[0][idx];
+ buffers[1][index++] = buffers[1][idx];
}
//Deep inside the bowels of vendors bugs,
//we're using watchdog for a firefox bug,
@@ -206,14 +184,12 @@ function sample_count() {
}
return {
- set_mastervolume: set_mastervolume,
- update_audio_stream: update_audio_stream,
+ stream_sink_update: stream_sink_update,
get_context: get_context,
sample_count: sample_count
};
})();
-window.jsmame_set_mastervolume = jsmame_web_audio.set_mastervolume;
-window.jsmame_update_audio_stream = jsmame_web_audio.update_audio_stream;
+window.jsmame_stream_sink_update = jsmame_web_audio.stream_sink_update;
window.jsmame_sample_count = jsmame_web_audio.sample_count;
diff --git a/src/osd/modules/sound/none.cpp b/src/osd/modules/sound/none.cpp
index 685cdc884c2..bdb219636d0 100644
--- a/src/osd/modules/sound/none.cpp
+++ b/src/osd/modules/sound/none.cpp
@@ -2,32 +2,35 @@
// copyright-holders:Miodrag Milanovic
/***************************************************************************
- none.c
+ none.cpp
Dummy sound interface.
*******************************************************************c********/
#include "sound_module.h"
+
#include "modules/osdmodule.h"
+
+namespace osd {
+
+namespace {
+
class sound_none : public osd_module, public sound_module
{
public:
- sound_none()
- : osd_module(OSD_SOUND_PROVIDER, "none"), sound_module()
+ sound_none() : osd_module(OSD_SOUND_PROVIDER, "none")
{
}
virtual ~sound_none() { }
- virtual int init(const osd_options &options) override { return 0; }
+ virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
virtual void exit() override { }
+};
- // sound_module
-
- virtual void update_audio_stream(bool is_throttled, const int16_t *buffer, int samples_this_frame) override { }
- virtual void set_mastervolume(int attenuation) override { }
+} // anonymous namespace
-};
+} // namespace osd
-MODULE_DEFINITION(SOUND_NONE, sound_none)
+MODULE_DEFINITION(SOUND_NONE, osd::sound_none)
diff --git a/src/osd/modules/sound/pa_sound.cpp b/src/osd/modules/sound/pa_sound.cpp
index 41645318672..68200a9c3f1 100644
--- a/src/osd/modules/sound/pa_sound.cpp
+++ b/src/osd/modules/sound/pa_sound.cpp
@@ -9,44 +9,50 @@
*******************************************************************c********/
#include "sound_module.h"
+
#include "modules/osdmodule.h"
#ifndef NO_USE_PORTAUDIO
-#include <portaudio.h>
#include "modules/lib/osdobj_common.h"
+#include "osdcore.h"
-#include <iostream>
-#include <fstream>
-#include <sstream>
+#include <portaudio.h>
+
+#include <algorithm>
#include <atomic>
-#include <cmath>
#include <climits>
-#include <algorithm>
+#include <cmath>
+#include <fstream>
+#include <iostream>
+#include <sstream>
-#ifdef WIN32
+#ifdef _WIN32
#include "pa_win_wasapi.h"
#endif
+
+namespace osd {
+
+namespace {
+
#define LOG_FILE "pa.log"
#define LOG_BUFCNT 0
class sound_pa : public osd_module, public sound_module
{
public:
- sound_pa()
- : osd_module(OSD_SOUND_PROVIDER, "portaudio"), sound_module()
+ sound_pa() : osd_module(OSD_SOUND_PROVIDER, "portaudio")
{
}
virtual ~sound_pa() { }
- virtual int init(osd_options const &options) override;
+ virtual int init(osd_interface &osd, osd_options const &options) override;
virtual void exit() override;
// sound_module
- virtual void update_audio_stream(bool is_throttled, const s16 *buffer, int samples_this_frame) override;
- virtual void set_mastervolume(int attenuation) override;
+ virtual void stream_sink_update(uint32_t, const s16 *buffer, int samples_this_frame) override;
private:
// Lock free SPSC ring buffer
@@ -73,14 +79,14 @@ private:
writepos.store((writepos + n) % size);
}
- int write(const T* src, int n, int attenuation) {
+ int write(const T* src, int n) {
n = std::min<int>(n, size - reserve - count());
if (writepos + n > size) {
- att_memcpy(buf + writepos, src, sizeof(T) * (size - writepos), attenuation);
- att_memcpy(buf, src + (size - writepos), sizeof(T) * (n - (size - writepos)), attenuation);
+ memcpy(buf + writepos, src, sizeof(T) * (size - writepos));
+ memcpy(buf, src + (size - writepos), sizeof(T) * (n - (size - writepos)));
} else {
- att_memcpy(buf + writepos, src, sizeof(T) * n, attenuation);
+ memcpy(buf + writepos, src, sizeof(T) * n);
}
increment_writepos(n);
@@ -121,13 +127,6 @@ private:
return n;
}
-
- void att_memcpy(T* dest, const T* data, int n, int attenuation) {
- int level = powf(10.0, attenuation / 20.0) * 32768;
- n /= sizeof(T);
- while (n--)
- *dest++ = (*data++ * level) >> 15;
- }
};
enum
@@ -150,7 +149,8 @@ private:
PaStream* m_pa_stream;
PaError err;
- int m_attenuation;
+ int m_sample_rate;
+ int m_audio_latency;
audio_buffer<s16>* m_ab;
@@ -170,8 +170,12 @@ private:
#endif
};
-int sound_pa::init(osd_options const &options)
+int sound_pa::init(osd_interface &osd, osd_options const &options)
{
+ m_sample_rate = options.sample_rate();
+ if (!m_sample_rate)
+ return 0;
+
PaStreamParameters stream_params;
const PaStreamInfo* stream_info;
const PaHostApiInfo* api_info;
@@ -180,10 +184,6 @@ int sound_pa::init(osd_options const &options)
unsigned long frames_per_callback = paFramesPerBufferUnspecified;
double callback_interval;
- if (!sample_rate())
- return 0;
-
- m_attenuation = options.volume();
m_underflows = 0;
m_overflows = 0;
m_has_overflowed = false;
@@ -192,7 +192,7 @@ int sound_pa::init(osd_options const &options)
m_skip_threshold_ticks = 0;
m_osd_tps = osd_ticks_per_second();
m_buffer_min_ct = INT_MAX;
- m_audio_latency = std::min<int>(std::max<int>(m_audio_latency, LATENCY_MIN), LATENCY_MAX);
+ m_audio_latency = std::clamp<int>(options.audio_latency(), LATENCY_MIN, LATENCY_MAX);
try {
m_ab = new audio_buffer<s16>(m_sample_rate, 2);
@@ -216,7 +216,7 @@ int sound_pa::init(osd_options const &options)
// 0 = use default
stream_params.suggestedLatency = options.pa_latency() ? options.pa_latency() : device_info->defaultLowOutputLatency;
-#ifdef WIN32
+#ifdef _WIN32
PaWasapiStreamInfo wasapi_stream_info;
// if requested latency is less than 20 ms, we need to use exclusive mode
@@ -364,7 +364,7 @@ int sound_pa::callback(s16* output_buffer, size_t number_of_samples)
int adjust = m_buffer_min_ct - m_skip_threshold / 2;
// if adjustment is less than two milliseconds, don't bother
- if (adjust / 2 > sample_rate() / 500) {
+ if (adjust / 2 > m_sample_rate / 500) {
m_ab->increment_playpos(adjust);
m_has_overflowed = true;
}
@@ -379,7 +379,7 @@ int sound_pa::callback(s16* output_buffer, size_t number_of_samples)
m_ab->read(output_buffer, buf_ct);
std::memset(output_buffer + buf_ct, 0, (number_of_samples - buf_ct) * sizeof(s16));
- // if update_audio_stream has been called, note the underflow
+ // if stream_sink_update has been called, note the underflow
if (m_osd_ticks)
m_has_underflowed = true;
@@ -389,9 +389,9 @@ int sound_pa::callback(s16* output_buffer, size_t number_of_samples)
return paContinue;
}
-void sound_pa::update_audio_stream(bool is_throttled, const s16 *buffer, int samples_this_frame)
+void sound_pa::stream_sink_update(uint32_t, const s16 *buffer, int samples_this_frame)
{
- if (!sample_rate())
+ if (!m_sample_rate)
return;
#if LOG_BUFCNT
@@ -413,20 +413,15 @@ void sound_pa::update_audio_stream(bool is_throttled, const s16 *buffer, int sam
m_has_overflowed = false;
}
- m_ab->write(buffer, samples_this_frame * 2, m_attenuation);
+ m_ab->write(buffer, samples_this_frame * 2);
// for determining buffer overflows, take the sample here instead of in the callback
m_osd_ticks = osd_ticks();
}
-void sound_pa::set_mastervolume(int attenuation)
-{
- m_attenuation = attenuation;
-}
-
void sound_pa::exit()
{
- if (!sample_rate())
+ if (!m_sample_rate)
return;
#if LOG_BUFCNT
@@ -456,8 +451,14 @@ void sound_pa::exit()
osd_printf_verbose("Sound: overflows=%d underflows=%d\n", m_overflows, m_underflows);
}
+} // anonymous namespace
+
+} // namespace osd
+
#else
- MODULE_NOT_SUPPORTED(sound_pa, OSD_SOUND_PROVIDER, "portaudio")
+
+namespace osd { namespace { MODULE_NOT_SUPPORTED(sound_pa, OSD_SOUND_PROVIDER, "portaudio") } }
+
#endif
-MODULE_DEFINITION(SOUND_PORTAUDIO, sound_pa)
+MODULE_DEFINITION(SOUND_PORTAUDIO, osd::sound_pa)
diff --git a/src/osd/modules/sound/pipewire_sound.cpp b/src/osd/modules/sound/pipewire_sound.cpp
new file mode 100644
index 00000000000..8bf5b8e0afa
--- /dev/null
+++ b/src/osd/modules/sound/pipewire_sound.cpp
@@ -0,0 +1,823 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/***************************************************************************
+
+ piepewire_sound.c
+
+ PipeWire interface.
+
+***************************************************************************/
+
+#include "sound_module.h"
+#include "modules/osdmodule.h"
+
+#ifndef NO_USE_PIPEWIRE
+
+#define GNU_SOURCE
+#include "modules/lib/osdobj_common.h"
+
+#include <pipewire/pipewire.h>
+#include <pipewire/extensions/metadata.h>
+#include <spa/debug/pod.h>
+#include <spa/debug/dict.h>
+#include <spa/pod/builder.h>
+#include <spa/param/audio/raw-utils.h>
+#include <rapidjson/document.h>
+
+#include <map>
+
+class sound_pipewire : public osd_module, public sound_module
+{
+public:
+ sound_pipewire()
+ : osd_module(OSD_SOUND_PROVIDER, "pipewire"), sound_module()
+ {
+ }
+ virtual ~sound_pipewire() { }
+
+ virtual int init(osd_interface &osd, osd_options const &options) override;
+ virtual void exit() override;
+
+ virtual bool external_per_channel_volume() override { return true; }
+ virtual bool split_streams_per_source() override { return true; }
+
+ virtual uint32_t get_generation() override;
+ virtual osd::audio_info get_information() override;
+ virtual uint32_t stream_sink_open(uint32_t node, std::string name, uint32_t rate) override;
+ virtual uint32_t stream_source_open(uint32_t node, std::string name, uint32_t rate) override;
+ virtual void stream_set_volumes(uint32_t id, const std::vector<float> &db) override;
+ virtual void stream_close(uint32_t id) override;
+ virtual void stream_sink_update(uint32_t id, const int16_t *buffer, int samples_this_frame) override;
+ virtual void stream_source_update(uint32_t id, int16_t *buffer, int samples_this_frame) override;
+
+private:
+ struct position_info {
+ uint32_t m_position;
+ std::array<double, 3> m_coords;
+ };
+
+ static const position_info position_infos[];
+
+ static const char *const typenames[];
+ enum { AREC, APLAY };
+
+ struct node_info {
+ sound_pipewire *m_wire;
+ uint32_t m_id, m_osdid;
+ int m_type;
+ std::string m_serial;
+ std::string m_name;
+ std::string m_text_id;
+
+ // Audio node info
+ uint32_t m_sinks, m_sources;
+ std::vector<uint32_t> m_position_codes;
+ std::vector<std::string> m_port_names;
+ std::vector<std::array<double, 3>> m_positions;
+
+ osd::audio_rate_range m_rate;
+ bool m_has_s16;
+ bool m_has_iec958;
+
+ pw_node *m_node;
+ spa_hook m_node_listener;
+
+ node_info(sound_pipewire *wire, uint32_t id, uint32_t osdid, int type, std::string serial, std::string name, std::string text_id) : m_wire(wire), m_id(id), m_osdid(osdid), m_type(type), m_serial(serial), m_name(name), m_text_id(text_id), m_sinks(0), m_sources(0), m_rate{0, 0, 0}, m_has_s16(false), m_has_iec958(false), m_node(nullptr) {
+ spa_zero(m_node_listener);
+ }
+ };
+
+ struct stream_info {
+ sound_pipewire *m_wire;
+ bool m_is_output;
+ uint32_t m_osdid;
+ uint32_t m_node_id;
+ node_info *m_node;
+ uint32_t m_channels;
+ pw_stream *m_stream;
+ std::vector<float> m_volumes;
+ abuffer m_buffer;
+
+ stream_info(sound_pipewire *wire, bool is_output, uint32_t osdid, uint32_t channels) : m_wire(wire), m_is_output(is_output), m_osdid(osdid), m_channels(channels), m_stream(nullptr), m_buffer(channels) {}
+ };
+
+ static const pw_core_events core_events;
+ static const pw_registry_events registry_events;
+ static const pw_node_events node_events;
+ static const pw_metadata_events default_events;
+ static const pw_stream_events stream_sink_events;
+ static const pw_stream_events stream_source_events;
+
+ std::map<uint32_t, node_info> m_nodes;
+ std::map<uint32_t, uint32_t> m_node_osdid_to_id;
+
+ std::map<uint32_t, stream_info> m_streams;
+
+ pw_thread_loop *m_loop;
+ pw_context *m_context;
+ pw_core *m_core;
+ spa_hook m_core_listener;
+ pw_registry *m_registry;
+ spa_hook m_registry_listener;
+ pw_metadata *m_default;
+ spa_hook m_default_listener;
+
+ std::string m_default_audio_sink;
+ std::string m_default_audio_source;
+
+ uint32_t m_node_current_id, m_stream_current_id;
+ uint32_t m_generation;
+ bool m_wait_sync, m_wait_stream;
+
+ void sync();
+
+ void core_event_done(uint32_t id, int seq);
+ static void s_core_event_done(void *data, uint32_t id, int seq);
+
+ void register_node(uint32_t id, const spa_dict *props);
+ void register_port(uint32_t id, const spa_dict *props);
+ void register_link(uint32_t id, const spa_dict *props);
+ void register_default_metadata(uint32_t id);
+ void register_metadata(uint32_t id, const spa_dict *props);
+ void registry_event_global(uint32_t id, uint32_t permissions, const char *type, uint32_t version, const spa_dict *props);
+ static void s_registry_event_global(void *data, uint32_t id, uint32_t permissions, const char *type, uint32_t version, const spa_dict *props);
+
+ void registry_event_global_remove(uint32_t id);
+ static void s_registry_event_global_remove(void *data, uint32_t id);
+
+ void node_event_param(node_info *node, int seq, uint32_t id, uint32_t index, uint32_t next, const spa_pod *param);
+ static void s_node_event_param(void *data, int seq, uint32_t id, uint32_t index, uint32_t next, const spa_pod *param);
+
+ int default_event_property(uint32_t subject, const char *key, const char *type, const char *value);
+ static int s_default_event_property(void *data, uint32_t subject, const char *key, const char *type, const char *value);
+
+ void stream_sink_event_process(stream_info *stream);
+ static void s_stream_sink_event_process(void *data);
+
+ void stream_source_event_process(stream_info *stream);
+ static void s_stream_source_event_process(void *data);
+
+ void stream_event_param_changed(stream_info *stream, uint32_t id, const spa_pod *param);
+ static void s_stream_event_param_changed(void *data, uint32_t id, const spa_pod *param);
+};
+
+// Try to more or less map to speaker.h positions
+
+const sound_pipewire::position_info sound_pipewire::position_infos[] = {
+ { SPA_AUDIO_CHANNEL_MONO, { 0.0, 0.0, 1.0 } },
+ { SPA_AUDIO_CHANNEL_FL, { -0.2, 0.0, 1.0 } },
+ { SPA_AUDIO_CHANNEL_FR, { 0.2, 0.0, 1.0 } },
+ { SPA_AUDIO_CHANNEL_FC, { 0.0, 0.0, 1.0 } },
+ { SPA_AUDIO_CHANNEL_LFE, { 0.0, -0.5, 1.0 } },
+ { SPA_AUDIO_CHANNEL_RL, { -0.2, 0.0, -0.5 } },
+ { SPA_AUDIO_CHANNEL_RR, { 0.2, 0.0, -0.5 } },
+ { SPA_AUDIO_CHANNEL_RC, { 0.0, 0.0, -0.5 } },
+ { SPA_AUDIO_CHANNEL_UNKNOWN, { 0.0, 0.0, 0.0 } }
+};
+
+
+const char *const sound_pipewire::typenames[] = {
+ "Audio recorder", "Speaker"
+};
+
+const pw_core_events sound_pipewire::core_events = {
+ PW_VERSION_CORE_EVENTS,
+ nullptr, // info
+ s_core_event_done,
+ nullptr, // ping
+ nullptr, // error
+ nullptr, // remove_id
+ nullptr, // bound_id
+ nullptr, // add_mem
+ nullptr, // remove_mem
+ nullptr // bound_props
+};
+
+const pw_registry_events sound_pipewire::registry_events = {
+ PW_VERSION_REGISTRY_EVENTS,
+ s_registry_event_global,
+ s_registry_event_global_remove
+};
+
+const pw_node_events sound_pipewire::node_events = {
+ PW_VERSION_NODE_EVENTS,
+ nullptr, // info
+ s_node_event_param
+};
+
+const pw_metadata_events sound_pipewire::default_events = {
+ PW_VERSION_METADATA_EVENTS,
+ s_default_event_property
+};
+
+const pw_stream_events sound_pipewire::stream_sink_events = {
+ PW_VERSION_STREAM_EVENTS,
+ nullptr, // destroy
+ nullptr, // state changed
+ nullptr, // control info
+ nullptr, // io changed
+ s_stream_event_param_changed,
+ nullptr, // add buffer
+ nullptr, // remove buffer
+ s_stream_sink_event_process,
+ nullptr, // drained
+ nullptr, // command
+ nullptr // trigger done
+};
+
+const pw_stream_events sound_pipewire::stream_source_events = {
+ PW_VERSION_STREAM_EVENTS,
+ nullptr, // destroy
+ nullptr, // state changed
+ nullptr, // control info
+ nullptr, // io changed
+ s_stream_event_param_changed,
+ nullptr, // add buffer
+ nullptr, // remove buffer
+ s_stream_source_event_process,
+ nullptr, // drained
+ nullptr, // command
+ nullptr // trigger done
+};
+
+void sound_pipewire::register_node(uint32_t id, const spa_dict *props)
+{
+ const spa_dict_item *cls = spa_dict_lookup_item(props, PW_KEY_MEDIA_CLASS);
+ const spa_dict_item *desc = spa_dict_lookup_item(props, PW_KEY_NODE_DESCRIPTION);
+ const spa_dict_item *name = spa_dict_lookup_item(props, PW_KEY_NODE_NAME);
+ const spa_dict_item *serial = spa_dict_lookup_item(props, PW_KEY_OBJECT_SERIAL);
+ if(!cls)
+ return;
+ int type;
+ if(!strcmp(cls->value, "Audio/Source"))
+ type = AREC;
+ else if(!strcmp(cls->value, "Audio/Sink"))
+ type = APLAY;
+ else
+ return;
+
+ m_node_osdid_to_id[m_node_current_id] = id;
+ auto &node = m_nodes.emplace(id, node_info(this, id, m_node_current_id++, type, serial->value, desc ? desc->value : "?", name ? name->value : "?")).first->second;
+
+ // printf("node %03x: %s %s %s | %s\n", node.m_id, serial->value, typenames[node.m_type], node.m_name.c_str(), node.m_text_id.c_str());
+
+ node.m_node = (pw_node *)pw_registry_bind(m_registry, id, PW_TYPE_INTERFACE_Node, PW_VERSION_NODE, 0);
+ pw_node_add_listener(node.m_node, &node.m_node_listener, &node_events, &node);
+ pw_node_enum_params(node.m_node, 0, 3, 0, 0xffffffff, nullptr);
+ m_generation++;
+}
+
+void sound_pipewire::register_port(uint32_t id, const spa_dict *props)
+{
+ uint32_t node = strtol(spa_dict_lookup_item(props, PW_KEY_NODE_ID)->value, nullptr, 10);
+ auto ind = m_nodes.find(node);
+ if(ind == m_nodes.end())
+ return;
+
+ const spa_dict_item *channel = spa_dict_lookup_item(props, PW_KEY_AUDIO_CHANNEL);
+ const spa_dict_item *dir = spa_dict_lookup_item(props, PW_KEY_PORT_DIRECTION);
+ bool is_in = dir && !strcmp(dir->value, "in") ;
+ uint32_t index = strtol(spa_dict_lookup_item(props, PW_KEY_PORT_ID)->value, nullptr, 10);
+
+ if(is_in && ind->second.m_sinks <= index)
+ ind->second.m_sinks = index+1;
+ if(!is_in && ind->second.m_sources <= index)
+ ind->second.m_sources = index+1;
+
+ auto &port_names = ind->second.m_port_names;
+ if(port_names.size() <= index)
+ port_names.resize(index+1);
+
+ if(is_in || port_names[index].empty())
+ port_names[index] = channel ? channel->value : "?";
+
+ m_generation++;
+ // printf("port %03x.%d %03x: %s\n", node, index, id, port_names[index].c_str());
+}
+
+void sound_pipewire::register_link(uint32_t id, const spa_dict *props)
+{
+ const spa_dict_item *input = spa_dict_lookup_item(props, PW_KEY_LINK_INPUT_NODE);
+ const spa_dict_item *output = spa_dict_lookup_item(props, PW_KEY_LINK_OUTPUT_NODE);
+ if(!input || !output)
+ return;
+
+ uint32_t input_id = strtol(input->value, nullptr, 10);
+ uint32_t output_id = strtol(output->value, nullptr, 10);
+
+ for(auto &si : m_streams) {
+ stream_info &stream = si.second;
+ if(stream.m_is_output && stream.m_node_id == output_id && (stream.m_node && stream.m_node->m_id != input_id)) {
+ auto ni = m_nodes.find(input_id);
+ if(ni != m_nodes.end()) {
+ stream.m_node = &ni->second;
+ m_generation ++;
+ return;
+ }
+ }
+ if(!stream.m_is_output && stream.m_node_id == input_id && (stream.m_node && stream.m_node->m_id != output_id)) {
+ auto ni = m_nodes.find(output_id);
+ if(ni != m_nodes.end()) {
+ stream.m_node = &ni->second;
+ m_generation ++;
+ return;
+ }
+ }
+ }
+}
+
+void sound_pipewire::register_default_metadata(uint32_t id)
+{
+ m_default = (pw_metadata *)pw_registry_bind(m_registry, id, PW_TYPE_INTERFACE_Metadata, PW_VERSION_METADATA, 0);
+ pw_metadata_add_listener(m_default, &m_default_listener, &default_events, this);
+}
+
+void sound_pipewire::register_metadata(uint32_t id, const spa_dict *props)
+{
+ const spa_dict_item *mn = spa_dict_lookup_item(props, PW_KEY_METADATA_NAME);
+ if(mn && !strcmp(mn->value, "default"))
+ register_default_metadata(id);
+}
+
+void sound_pipewire::registry_event_global(uint32_t id,
+ uint32_t permissions, const char *type, uint32_t version,
+ const spa_dict *props)
+{
+ if(!strcmp(type, PW_TYPE_INTERFACE_Node))
+ register_node(id, props);
+ else if(!strcmp(type, PW_TYPE_INTERFACE_Port))
+ register_port(id, props);
+ else if(!strcmp(type, PW_TYPE_INTERFACE_Metadata))
+ register_metadata(id, props);
+ else if(!strcmp(type, PW_TYPE_INTERFACE_Link))
+ register_link(id, props);
+ else {
+ // printf("type %03x %s\n", id, type);
+ }
+}
+
+void sound_pipewire::s_registry_event_global(void *data, uint32_t id,
+ uint32_t permissions, const char *type, uint32_t version,
+ const spa_dict *props)
+{
+ ((sound_pipewire *)data)->registry_event_global(id, permissions, type, version, props);
+}
+
+void sound_pipewire::registry_event_global_remove(uint32_t id)
+{
+ auto ind = m_nodes.find(id);
+ if(ind == m_nodes.end())
+ return;
+
+ for(auto &istream : m_streams)
+ if(istream.second.m_node == &ind->second)
+ istream.second.m_node = nullptr;
+ m_nodes.erase(ind);
+ m_generation++;
+}
+
+void sound_pipewire::s_registry_event_global_remove(void *data, uint32_t id)
+{
+ ((sound_pipewire *)data)->registry_event_global_remove(id);
+}
+
+void sound_pipewire::node_event_param(node_info *node, int seq, uint32_t id, uint32_t index, uint32_t next, const spa_pod *param)
+{
+ if(id == SPA_PARAM_EnumFormat) {
+ const spa_pod_prop *subtype = spa_pod_find_prop(param, nullptr, SPA_FORMAT_mediaSubtype);
+ if(subtype) {
+ uint32_t sval;
+ if(!spa_pod_get_id(&subtype->value, &sval)) {
+ if(sval == SPA_MEDIA_SUBTYPE_raw) {
+ const spa_pod_prop *format = spa_pod_find_prop(param, nullptr, SPA_FORMAT_AUDIO_format);
+ const spa_pod_prop *rate = spa_pod_find_prop(param, nullptr, SPA_FORMAT_AUDIO_rate);
+ const spa_pod_prop *position = spa_pod_find_prop(param, nullptr, SPA_FORMAT_AUDIO_position);
+
+ if(format) {
+ uint32_t *entry;
+ SPA_POD_CHOICE_FOREACH((spa_pod_choice *)(&format->value), entry) {
+ if(*entry == SPA_AUDIO_FORMAT_S16)
+ node->m_has_s16 = true;
+ }
+ }
+ if(rate) {
+ if(rate->value.type == SPA_TYPE_Choice) {
+ struct spa_pod_choice_body *b = &((spa_pod_choice *)(&rate->value))->body;
+ uint32_t *choices = (uint32_t *)(b+1);
+ node->m_rate.m_default_rate = choices[0];
+ if(b->type == SPA_CHOICE_Range) {
+ node->m_rate.m_min_rate = choices[1];
+ node->m_rate.m_max_rate = choices[2];
+ } else {
+ node->m_rate.m_min_rate = node->m_rate.m_default_rate;
+ node->m_rate.m_max_rate = node->m_rate.m_default_rate;
+ }
+ }
+ }
+
+ if(position) {
+ uint32_t *entry;
+ node->m_position_codes.clear();
+ node->m_positions.clear();
+ SPA_POD_ARRAY_FOREACH((spa_pod_array *)(&position->value), entry) {
+ node->m_position_codes.push_back(*entry);
+ for(uint32_t i = 0;; i++) {
+ if((position_infos[i].m_position == *entry) || (position_infos[i].m_position == SPA_AUDIO_CHANNEL_UNKNOWN)) {
+ node->m_positions.push_back(position_infos[i].m_coords);
+ break;
+ }
+ }
+ }
+ }
+ } else if(sval == SPA_MEDIA_SUBTYPE_iec958)
+ node->m_has_iec958 = true;
+ }
+ }
+ m_generation++;
+
+ } else
+ spa_debug_pod(2, nullptr, param);
+}
+
+void sound_pipewire::s_node_event_param(void *data, int seq, uint32_t id, uint32_t index, uint32_t next, const spa_pod *param)
+{
+ node_info *n = (node_info *)data;
+ n->m_wire->node_event_param(n, seq, id, index, next, param);
+}
+
+int sound_pipewire::default_event_property(uint32_t subject, const char *key, const char *type, const char *value)
+{
+ if(!value)
+ return 0;
+ std::string val = value;
+ if(!strcmp(type, "Spa:String:JSON")) {
+ rapidjson::Document json;
+ json.Parse(value);
+ if(json.IsObject() && json.HasMember("name") && json["name"].IsString())
+ val = json["name"].GetString();
+ } else
+ val = value;
+
+ if(!strcmp(key, "default.audio.sink"))
+ m_default_audio_sink = val;
+
+ else if(!strcmp(key, "default.audio.source"))
+ m_default_audio_source = val;
+
+ return 0;
+}
+
+int sound_pipewire::s_default_event_property(void *data, uint32_t subject, const char *key, const char *type, const char *value)
+{
+ return ((sound_pipewire *)data)->default_event_property(subject, key, type, value);
+}
+
+int sound_pipewire::init(osd_interface &osd, osd_options const &options)
+{
+ spa_zero(m_core_listener);
+ spa_zero(m_registry_listener);
+ spa_zero(m_default_listener);
+
+ m_node_current_id = 1;
+ m_stream_current_id = 1;
+ m_generation = 1;
+
+ m_wait_sync = false;
+ m_wait_stream = false;
+
+ pw_init(nullptr, nullptr);
+ m_loop = pw_thread_loop_new(nullptr, nullptr);
+ m_context = pw_context_new(pw_thread_loop_get_loop(m_loop), nullptr, 0);
+ m_core = pw_context_connect(m_context, nullptr, 0);
+
+ if(!m_core)
+ return 1;
+
+ pw_core_add_listener(m_core, &m_core_listener, &core_events, this);
+
+ m_registry = pw_core_get_registry(m_core, PW_VERSION_REGISTRY, 0);
+ pw_registry_add_listener(m_registry, &m_registry_listener, &registry_events, this);
+
+ pw_thread_loop_start(m_loop);
+
+ // The first sync ensures that the initial information request is
+ // completed, the second that the subsequent ones (parameters
+ // retrieval) are completed too.
+ sync();
+ sync();
+
+ return 0;
+}
+
+void sound_pipewire::core_event_done(uint32_t id, int seq)
+{
+ m_wait_sync = false;
+ pw_thread_loop_signal(m_loop, false);
+}
+
+void sound_pipewire::s_core_event_done(void *data, uint32_t id, int seq)
+{
+ ((sound_pipewire *)data)->core_event_done(id, seq);
+}
+
+void sound_pipewire::sync()
+{
+ pw_thread_loop_lock(m_loop);
+ m_wait_sync = true;
+ pw_core_sync(m_core, PW_ID_CORE, 0);
+ while(m_wait_sync)
+ pw_thread_loop_wait(m_loop);
+ pw_thread_loop_unlock(m_loop);
+}
+
+void sound_pipewire::exit()
+{
+ pw_thread_loop_stop(m_loop);
+ for(const auto &si : m_streams)
+ pw_stream_destroy(si.second.m_stream);
+ for(const auto &ni : m_nodes)
+ pw_proxy_destroy((pw_proxy *)ni.second.m_node);
+ pw_proxy_destroy((pw_proxy *)m_default);
+ pw_proxy_destroy((pw_proxy *)m_registry);
+ pw_core_disconnect(m_core);
+ pw_context_destroy(m_context);
+ pw_thread_loop_destroy(m_loop);
+ pw_deinit();
+}
+
+uint32_t sound_pipewire::get_generation()
+{
+ pw_thread_loop_lock(m_loop);
+ uint32_t result = m_generation;
+ pw_thread_loop_unlock(m_loop);
+ return result;
+}
+
+osd::audio_info sound_pipewire::get_information()
+{
+ osd::audio_info result;
+ pw_thread_loop_lock(m_loop);
+ result.m_nodes.resize(m_nodes.size());
+ result.m_default_sink = 0;
+ result.m_default_source = 0;
+ result.m_generation = m_generation;
+ uint32_t node = 0;
+ for(auto &inode : m_nodes) {
+ result.m_nodes[node].m_name = inode.second.m_name;
+ result.m_nodes[node].m_id = inode.second.m_osdid;
+ result.m_nodes[node].m_rate = inode.second.m_rate;
+ result.m_nodes[node].m_sinks = inode.second.m_sinks;
+ result.m_nodes[node].m_sources = inode.second.m_sources;
+ result.m_nodes[node].m_port_names = inode.second.m_port_names;
+ result.m_nodes[node].m_port_positions = inode.second.m_positions;
+
+ if(inode.second.m_text_id == m_default_audio_sink)
+ result.m_default_sink = inode.second.m_osdid;
+ if(inode.second.m_text_id == m_default_audio_source)
+ result.m_default_source = inode.second.m_osdid;
+ node ++;
+ }
+
+ for(auto &istream : m_streams)
+ if(istream.second.m_node)
+ result.m_streams.emplace_back(osd::audio_info::stream_info { istream.second.m_osdid, istream.second.m_node->m_osdid, istream.second.m_volumes });
+
+ pw_thread_loop_unlock(m_loop);
+ return result;
+}
+
+void sound_pipewire::stream_sink_event_process(stream_info *stream)
+{
+ pw_buffer *buffer = pw_stream_dequeue_buffer(stream->m_stream);
+ if(!buffer)
+ return;
+
+ spa_buffer *sbuf = buffer->buffer;
+ stream->m_buffer.get((int16_t *)(sbuf->datas[0].data), buffer->requested);
+
+ sbuf->datas[0].chunk->offset = 0;
+ sbuf->datas[0].chunk->stride = stream->m_channels * 2;
+ sbuf->datas[0].chunk->size = buffer->requested * stream->m_channels * 2;
+
+ pw_stream_queue_buffer(stream->m_stream, buffer);
+}
+
+void sound_pipewire::s_stream_sink_event_process(void *data)
+{
+ stream_info *info = (stream_info *)(data);
+ info->m_wire->stream_sink_event_process(info);
+}
+
+void sound_pipewire::stream_source_event_process(stream_info *stream)
+{
+ pw_buffer *buffer = pw_stream_dequeue_buffer(stream->m_stream);
+ if(!buffer)
+ return;
+
+ spa_buffer *sbuf = buffer->buffer;
+ stream->m_buffer.push((int16_t *)(sbuf->datas[0].data), sbuf->datas[0].chunk->size / stream->m_channels / 2);
+ pw_stream_queue_buffer(stream->m_stream, buffer);
+}
+
+void sound_pipewire::s_stream_source_event_process(void *data)
+{
+ stream_info *info = (stream_info *)(data);
+ info->m_wire->stream_source_event_process(info);
+}
+
+void sound_pipewire::stream_event_param_changed(stream_info *stream, uint32_t id, const spa_pod *param)
+{
+ if(id == SPA_PARAM_Props) {
+ const spa_pod_prop *vols = spa_pod_find_prop(param, nullptr, SPA_PROP_channelVolumes);
+ if(vols) {
+ bool initial = stream->m_volumes.empty();
+ stream->m_volumes.clear();
+ float *entry;
+ SPA_POD_ARRAY_FOREACH((spa_pod_array *)(&vols->value), entry) {
+ stream->m_volumes.push_back(osd::linear_to_db(*entry));
+ }
+ if(!stream->m_volumes.empty()) {
+ if(initial) {
+ m_wait_stream = false;
+ pw_thread_loop_signal(m_loop, false);
+ } else
+ m_generation++;
+ }
+ }
+ }
+}
+
+void sound_pipewire::s_stream_event_param_changed(void *data, uint32_t id, const spa_pod *param)
+{
+ stream_info *info = (stream_info *)(data);
+ info->m_wire->stream_event_param_changed(info, id, param);
+}
+
+uint32_t sound_pipewire::stream_sink_open(uint32_t node, std::string name, uint32_t rate)
+{
+ pw_thread_loop_lock(m_loop);
+ auto ni = m_node_osdid_to_id.find(node);
+ if(ni == m_node_osdid_to_id.end()) {
+ pw_thread_loop_unlock(m_loop);
+ return 0;
+ }
+ node_info &snode = m_nodes.find(ni->second)->second;
+
+ uint32_t id = m_stream_current_id++;
+ auto &stream = m_streams.emplace(id, stream_info(this, true, id, snode.m_sinks)).first->second;
+
+ stream.m_stream = pw_stream_new_simple(pw_thread_loop_get_loop(m_loop),
+ name.c_str(),
+ pw_properties_new(PW_KEY_MEDIA_TYPE, "Audio",
+ PW_KEY_MEDIA_CATEGORY, "Playback",
+ PW_KEY_MEDIA_ROLE, "Game",
+ PW_KEY_TARGET_OBJECT, snode.m_serial.c_str(),
+ nullptr),
+ &stream_sink_events,
+ &stream);
+ stream.m_node = &snode;
+
+ const spa_pod *params;
+ spa_audio_info_raw format = {
+ SPA_AUDIO_FORMAT_S16,
+ 0,
+ rate,
+ stream.m_channels
+ };
+ for(uint32_t i=0; i != snode.m_sinks; i++)
+ format.position[i] = snode.m_position_codes[i];
+
+ uint8_t buffer[1024];
+ spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
+ params = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &format);
+
+ pw_stream_connect(stream.m_stream,
+ PW_DIRECTION_OUTPUT,
+ PW_ID_ANY,
+ pw_stream_flags(PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_MAP_BUFFERS | PW_STREAM_FLAG_RT_PROCESS),
+ &params, 1);
+
+ m_wait_stream = true;
+ while(m_wait_stream)
+ pw_thread_loop_wait(m_loop);
+
+ stream.m_node_id = pw_stream_get_node_id(stream.m_stream);
+ pw_thread_loop_unlock(m_loop);
+
+ return id;
+}
+
+uint32_t sound_pipewire::stream_source_open(uint32_t node, std::string name, uint32_t rate)
+{
+ pw_thread_loop_lock(m_loop);
+ auto ni = m_node_osdid_to_id.find(node);
+ if(ni == m_node_osdid_to_id.end()) {
+ pw_thread_loop_unlock(m_loop);
+ return 0;
+ }
+ node_info &snode = m_nodes.find(ni->second)->second;
+
+ uint32_t id = m_stream_current_id++;
+ auto &stream = m_streams.emplace(id, stream_info(this, false, id, snode.m_sources)).first->second;
+
+ stream.m_stream = pw_stream_new_simple(pw_thread_loop_get_loop(m_loop),
+ name.c_str(),
+ pw_properties_new(PW_KEY_MEDIA_TYPE, "Audio",
+ PW_KEY_MEDIA_CATEGORY, "Record",
+ PW_KEY_MEDIA_ROLE, "Game",
+ PW_KEY_TARGET_OBJECT, snode.m_serial.c_str(),
+ nullptr),
+ &stream_source_events,
+ &stream);
+ stream.m_node = &snode;
+
+ const spa_pod *params;
+ spa_audio_info_raw format = {
+ SPA_AUDIO_FORMAT_S16,
+ 0,
+ rate,
+ stream.m_channels
+ };
+ for(uint32_t i=0; i != snode.m_sources; i++)
+ format.position[i] = snode.m_position_codes[i];
+
+ uint8_t buffer[1024];
+ spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
+ params = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &format);
+
+ pw_stream_connect(stream.m_stream,
+ PW_DIRECTION_INPUT,
+ PW_ID_ANY,
+ pw_stream_flags(PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_MAP_BUFFERS | PW_STREAM_FLAG_RT_PROCESS),
+ &params, 1);
+
+ m_wait_stream = true;
+ while(m_wait_stream)
+ pw_thread_loop_wait(m_loop);
+
+ stream.m_node_id = pw_stream_get_node_id(stream.m_stream);
+ pw_thread_loop_unlock(m_loop);
+
+ return id;
+}
+
+void sound_pipewire::stream_set_volumes(uint32_t id, const std::vector<float> &db)
+{
+ pw_thread_loop_lock(m_loop);
+ auto si = m_streams.find(id);
+ if(si == m_streams.end()) {
+ pw_thread_loop_unlock(m_loop);
+ return;
+ }
+ stream_info &stream = si->second;
+ stream.m_volumes = db;
+ std::vector<float> linear;
+ for(float db1 : db)
+ linear.push_back(osd::db_to_linear(db1));
+ pw_stream_set_control(stream.m_stream, SPA_PROP_channelVolumes, linear.size(), linear.data(), 0);
+ pw_thread_loop_unlock(m_loop);
+}
+
+void sound_pipewire::stream_close(uint32_t id)
+{
+ pw_thread_loop_lock(m_loop);
+ auto si = m_streams.find(id);
+ if(si == m_streams.end()) {
+ pw_thread_loop_unlock(m_loop);
+ return;
+ }
+ stream_info &stream = si->second;
+ pw_stream_destroy(stream.m_stream);
+ m_streams.erase(si);
+ pw_thread_loop_unlock(m_loop);
+}
+
+void sound_pipewire::stream_sink_update(uint32_t id, const int16_t *buffer, int samples_this_frame)
+{
+ pw_thread_loop_lock(m_loop);
+ auto si = m_streams.find(id);
+ if(si == m_streams.end()) {
+ pw_thread_loop_unlock(m_loop);
+ return;
+ }
+ si->second.m_buffer.push(buffer, samples_this_frame);
+ pw_thread_loop_unlock(m_loop);
+}
+
+void sound_pipewire::stream_source_update(uint32_t id, int16_t *buffer, int samples_this_frame)
+{
+ pw_thread_loop_lock(m_loop);
+ auto si = m_streams.find(id);
+ if(si == m_streams.end()) {
+ pw_thread_loop_unlock(m_loop);
+ return;
+ }
+ si->second.m_buffer.get(buffer, samples_this_frame);
+ pw_thread_loop_unlock(m_loop);
+}
+
+#else
+ MODULE_NOT_SUPPORTED(sound_pipewire, OSD_SOUND_PROVIDER, "pipewire")
+#endif
+
+MODULE_DEFINITION(SOUND_PIPEWIRE, sound_pipewire)
diff --git a/src/osd/modules/sound/pulse_sound.cpp b/src/osd/modules/sound/pulse_sound.cpp
new file mode 100644
index 00000000000..4b7c87b6b9b
--- /dev/null
+++ b/src/osd/modules/sound/pulse_sound.cpp
@@ -0,0 +1,545 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/***************************************************************************
+
+ pulse_sound.c
+
+ PulseAudio interface.
+
+*******************************************************************c********/
+
+#include "sound_module.h"
+#include "modules/osdmodule.h"
+
+#ifndef NO_USE_PULSEAUDIO
+
+#define GNU_SOURCE
+
+#include <pulse/pulseaudio.h>
+#include <map>
+
+#include "modules/lib/osdobj_common.h"
+
+class sound_pulse : public osd_module, public sound_module
+{
+public:
+ sound_pulse()
+ : osd_module(OSD_SOUND_PROVIDER, "pulse"), sound_module()
+ {
+ }
+ virtual ~sound_pulse() { }
+
+ virtual int init(osd_interface &osd, osd_options const &options) override;
+ virtual void exit() override;
+
+ virtual bool external_per_channel_volume() override { return false; }
+ virtual bool split_streams_per_source() override { return true; }
+
+ virtual uint32_t get_generation() override;
+ virtual osd::audio_info get_information() override;
+ virtual uint32_t stream_sink_open(uint32_t node, std::string name, uint32_t rate) override;
+ virtual void stream_set_volumes(uint32_t id, const std::vector<float> &db) override;
+ virtual void stream_close(uint32_t id) override;
+ virtual void stream_sink_update(uint32_t, const int16_t *buffer, int samples_this_frame) override;
+
+private:
+ struct position_info {
+ pa_channel_position_t m_position;
+ std::array<double, 3> m_coords;
+ };
+
+ static const position_info position_infos[];
+ static const char *const typenames[];
+ enum { AREC, APLAY };
+
+ struct node_info {
+ sound_pulse *m_pulse;
+ uint32_t m_id, m_osdid;
+ int m_type;
+ std::string m_name, m_desc;
+
+ // Audio node info
+ std::vector<pa_channel_position_t> m_position_codes;
+ std::vector<std::string> m_position_names;
+ std::vector<std::array<double, 3>> m_positions;
+ uint32_t m_sink_port_count, m_source_port_count;
+
+ osd::audio_rate_range m_rate;
+
+ node_info(sound_pulse *pulse, uint32_t id, uint32_t osdid, int type, std::string name, std::string desc) : m_pulse(pulse), m_id(id), m_osdid(osdid), m_type(type), m_name(name), m_desc(desc), m_sink_port_count(0), m_source_port_count(0), m_rate{0, 0, 0} {
+ }
+ };
+
+ struct stream_info {
+ sound_pulse *m_pulse;
+ uint32_t m_osdid;
+ uint32_t m_pulse_id;
+ node_info *m_target_node;
+ uint32_t m_channels;
+ pa_stream *m_stream;
+ std::vector<float> m_volumes;
+ abuffer m_buffer;
+
+ stream_info(sound_pulse *pulse, uint32_t osdid, uint32_t channels) : m_pulse(pulse), m_osdid(osdid), m_pulse_id(0), m_channels(channels), m_stream(nullptr), m_volumes(channels), m_buffer(channels) {}
+ };
+
+ std::map<uint32_t, node_info> m_nodes;
+ std::map<uint32_t, uint32_t> m_node_osdid_to_id;
+
+ std::map<uint32_t, stream_info> m_streams;
+ std::map<uint32_t, uint32_t> m_stream_pulse_id_to_osdid;
+
+ pa_threaded_mainloop *m_mainloop;
+ pa_context *m_context;
+ uint32_t m_node_current_id, m_stream_current_id;
+ uint32_t m_generation;
+ bool m_wait_stream, m_wait_init;
+
+ std::string m_default_audio_sink;
+ std::string m_default_audio_source;
+
+ static void i_server_info(pa_context *, const pa_server_info *i, void *self);
+ void server_info(const pa_server_info *i);
+ static void i_context_notify(pa_context *, void *self);
+ void context_notify();
+ static void i_context_subscribe(pa_context *, pa_subscription_event_type_t t, uint32_t idx, void *self);
+ void context_subscribe(pa_subscription_event_type_t t, uint32_t idx);
+ static void i_stream_notify(pa_stream *, void *self);
+ void stream_notify(stream_info *stream);
+ static void i_stream_write_request(pa_stream *, size_t size, void *self);
+ void stream_write_request(stream_info *stream, size_t size);
+ static void i_source_info(pa_context *, const pa_source_info *i, int eol, void *self);
+ void source_info(const pa_source_info *i, int eol);
+ static void i_sink_info_new(pa_context *, const pa_sink_info *i, int eol, void *self);
+ void sink_info_new(const pa_sink_info *i, int eol);
+ static void i_sink_input_info_change(pa_context *, const pa_sink_input_info *i, int eol, void *self);
+ void sink_input_info_change(stream_info *stream, const pa_sink_input_info *i, int eol);
+
+ void generic_error(const char *msg);
+ void generic_pa_error(const char *msg, int err);
+};
+
+// Try to more or less map to speaker.h positions
+
+const sound_pulse::position_info sound_pulse::position_infos[] = {
+ { PA_CHANNEL_POSITION_MONO, { 0.0, 0.0, 1.0 } },
+ { PA_CHANNEL_POSITION_FRONT_LEFT, { -0.2, 0.0, 1.0 } },
+ { PA_CHANNEL_POSITION_FRONT_RIGHT, { 0.2, 0.0, 1.0 } },
+ { PA_CHANNEL_POSITION_FRONT_CENTER, { 0.0, 0.0, 1.0 } },
+ { PA_CHANNEL_POSITION_LFE, { 0.0, -0.5, 1.0 } },
+ { PA_CHANNEL_POSITION_REAR_LEFT, { -0.2, 0.0, -0.5 } },
+ { PA_CHANNEL_POSITION_REAR_RIGHT, { 0.2, 0.0, -0.5 } },
+ { PA_CHANNEL_POSITION_REAR_CENTER, { 0.0, 0.0, -0.5 } },
+ { PA_CHANNEL_POSITION_MAX, { 0.0, 0.0, 0.0 } }
+};
+
+
+const char *const sound_pulse::typenames[] = {
+ "Audio recorder", "Speaker"
+};
+
+void sound_pulse::generic_error(const char *msg)
+{
+ perror(msg);
+ ::exit(1);
+}
+
+void sound_pulse::generic_pa_error(const char *msg, int err)
+{
+ fprintf(stderr, "%s: %s\n", msg, pa_strerror(err));
+ ::exit(1);
+}
+
+void sound_pulse::context_notify()
+{
+ fprintf(stderr, "context notify\n");
+ pa_context_state state = pa_context_get_state(m_context);
+ if(state == PA_CONTEXT_READY) {
+ pa_context_subscribe(m_context, PA_SUBSCRIPTION_MASK_ALL, nullptr, this);
+ pa_context_get_sink_info_list(m_context, i_sink_info_new, (void *)this);
+
+ } else if(state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED) {
+ m_generation = 0x80000000;
+ pa_threaded_mainloop_signal(m_mainloop, 0);
+ }
+}
+
+void sound_pulse::i_context_notify(pa_context *, void *self)
+{
+ static_cast<sound_pulse *>(self)->context_notify();
+}
+
+void sound_pulse::stream_notify(stream_info *stream)
+{
+ pa_stream_state state = pa_stream_get_state(stream->m_stream);
+
+ fprintf(stderr, "stream notify\n");
+ if(state == PA_STREAM_READY || state == PA_STREAM_FAILED || state == PA_STREAM_TERMINATED) {
+ m_wait_stream = false;
+ pa_threaded_mainloop_signal(m_mainloop, 0);
+ }
+}
+
+void sound_pulse::i_stream_notify(pa_stream *, void *self)
+{
+ stream_info *si = static_cast<stream_info *>(self);
+ si->m_pulse->stream_notify(si);
+}
+
+void sound_pulse::stream_write_request(stream_info *stream, size_t size)
+{
+ // This is called with the thread locked
+ while(size) {
+ void *buffer;
+ size_t bsize = size;
+ int err = pa_stream_begin_write(stream->m_stream, &buffer, &bsize);
+ if(err)
+ generic_pa_error("stream begin write", err);
+ uint32_t frames = bsize/2/stream->m_channels;
+ uint32_t bytes = frames*2*stream->m_channels;
+ stream->m_buffer.get((int16_t *)buffer, frames);
+ err = pa_stream_write(stream->m_stream, buffer, bytes, nullptr, 0, PA_SEEK_RELATIVE);
+ if(err)
+ generic_pa_error("stream write", err);
+ size -= bytes;
+ }
+}
+
+void sound_pulse::i_stream_write_request(pa_stream *, size_t size, void *self)
+{
+ stream_info *si = static_cast<stream_info *>(self);
+ si->m_pulse->stream_write_request(si, size);
+}
+
+
+void sound_pulse::server_info(const pa_server_info *i)
+{
+ m_default_audio_sink = i->default_sink_name;
+ m_default_audio_source = i->default_source_name;
+ fprintf(stderr, "defaults %s %s\n", i->default_sink_name, i->default_source_name);
+ m_generation++;
+ if(m_wait_init) {
+ m_wait_init = false;
+ pa_threaded_mainloop_signal(m_mainloop, 0);
+ }
+}
+
+void sound_pulse::i_server_info(pa_context *, const pa_server_info *i, void *self)
+{
+ static_cast<sound_pulse *>(self)->server_info(i);
+}
+
+void sound_pulse::source_info(const pa_source_info *i, int eol)
+{
+ if(eol) {
+ if(m_wait_init)
+ pa_context_get_server_info(m_context, i_server_info, (void *)this);
+ return;
+ }
+ auto ni = m_nodes.find(i->index);
+ if(ni != m_nodes.end()) {
+ // Add the monitoring sources to the node
+ ni->second.m_source_port_count = i->channel_map.channels;
+ return;
+ }
+
+ fprintf(stderr, "new source %d (%s)\n", i->index, i->description);
+ m_node_osdid_to_id[m_node_current_id] = i->index;
+ auto &node = m_nodes.emplace(i->index, node_info(this, i->index, m_node_current_id++, AREC, i->name, i->description)).first->second;
+
+ node.m_source_port_count = i->channel_map.channels;
+ for(int chan=0; chan != i->channel_map.channels; chan++) {
+ pa_channel_position_t pos = i->channel_map.map[chan];
+ node.m_position_codes.push_back(pos);
+ node.m_position_names.push_back(pa_channel_position_to_pretty_string(pos));
+ for(uint32_t j = 0;; j++) {
+ if((position_infos[j].m_position == pos) || (position_infos[j].m_position == PA_CHANNEL_POSITION_MAX)) {
+ node.m_positions.push_back(position_infos[j].m_coords);
+ break;
+ }
+ }
+ }
+}
+
+void sound_pulse::i_source_info(pa_context *, const pa_source_info *i, int eol, void *self)
+{
+ static_cast<sound_pulse *>(self)->source_info(i, eol);
+}
+
+void sound_pulse::sink_info_new(const pa_sink_info *i, int eol)
+{
+ if(eol) {
+ if(m_wait_init)
+ pa_context_get_source_info_list(m_context, i_source_info, (void *)this);
+ return;
+ }
+
+ fprintf(stderr, "new sink %d (%s)\n", i->index, i->description);
+ fprintf(stderr, "rate %d\n", i->sample_spec.rate);
+ m_node_osdid_to_id[m_node_current_id] = i->index;
+ auto &node = m_nodes.emplace(i->index, node_info(this, i->index, m_node_current_id++, APLAY, i->name, i->description)).first->second;
+
+ node.m_sink_port_count = i->channel_map.channels;
+ for(int chan=0; chan != i->channel_map.channels; chan++) {
+ pa_channel_position_t pos = i->channel_map.map[chan];
+ node.m_position_codes.push_back(pos);
+ node.m_position_names.push_back(pa_channel_position_to_pretty_string(pos));
+ for(uint32_t j = 0;; j++) {
+ if((position_infos[j].m_position == pos) || (position_infos[j].m_position == PA_CHANNEL_POSITION_MAX)) {
+ node.m_positions.push_back(position_infos[j].m_coords);
+ break;
+ }
+ }
+ }
+ m_generation++;
+}
+
+void sound_pulse::i_sink_info_new(pa_context *, const pa_sink_info *i, int eol, void *self)
+{
+ static_cast<sound_pulse *>(self)->sink_info_new(i, eol);
+}
+
+
+void sound_pulse::sink_input_info_change(stream_info *stream, const pa_sink_input_info *i, int eol)
+{
+ if(eol)
+ return;
+
+ auto ni = m_nodes.find(i->sink);
+ if(ni != m_nodes.end())
+ stream->m_target_node = &ni->second;
+
+ for(uint32_t port = 0; port != stream->m_channels; port++)
+ stream->m_volumes[port] = pa_sw_volume_to_dB(i->volume.values[port]);
+
+ fprintf(stderr, "change stream %d/%d sink=%s [%f %f]\n", stream->m_osdid, stream->m_pulse_id, stream->m_target_node->m_desc.c_str(), stream->m_volumes[0], stream->m_volumes[1]);
+ m_generation++;
+}
+
+void sound_pulse::i_sink_input_info_change(pa_context *, const pa_sink_input_info *i, int eol, void *self)
+{
+ fprintf(stderr, "i_sink_input_info_change %p %d\n", i, eol);
+ stream_info *stream = static_cast<stream_info *>(self);
+ stream->m_pulse->sink_input_info_change(stream, i, eol);
+}
+
+void sound_pulse::context_subscribe(pa_subscription_event_type_t t, uint32_t idx)
+{
+ // This is called with the thread locked
+ static const char *const evt[] = { "sink", "source", "sink-input", "source-output", "module", "client", "cache", "server", "autoload", "card" };
+ static const char *const evt2[] = { "new", "change", "remove" };
+ switch(int(t)) {
+ case PA_SUBSCRIPTION_EVENT_REMOVE | PA_SUBSCRIPTION_EVENT_SINK:
+ case PA_SUBSCRIPTION_EVENT_REMOVE | PA_SUBSCRIPTION_EVENT_SOURCE: {
+ auto si = m_nodes.find(idx);
+ if(si == m_nodes.end())
+ break;
+ fprintf(stderr, "removing %s\n", si->second.m_desc.c_str());
+ for(auto &istream : m_streams)
+ if(istream.second.m_target_node == &si->second)
+ istream.second.m_target_node = nullptr;
+ m_nodes.erase(si);
+ m_generation++;
+ break;
+ }
+
+ case PA_SUBSCRIPTION_EVENT_NEW | PA_SUBSCRIPTION_EVENT_SINK:
+ pa_context_get_sink_info_by_index(m_context, idx, i_sink_info_new, this);
+ break;
+
+ case PA_SUBSCRIPTION_EVENT_NEW | PA_SUBSCRIPTION_EVENT_SOURCE:
+ pa_context_get_source_info_by_index(m_context, idx, i_source_info, this);
+ break;
+
+ case PA_SUBSCRIPTION_EVENT_CHANGE | PA_SUBSCRIPTION_EVENT_SERVER:
+ pa_context_get_server_info(m_context, i_server_info, (void *)this);
+ break;
+
+ case PA_SUBSCRIPTION_EVENT_CHANGE | PA_SUBSCRIPTION_EVENT_SINK_INPUT: {
+ auto si1 = m_stream_pulse_id_to_osdid.find(idx);
+ if(si1 == m_stream_pulse_id_to_osdid.end())
+ break;
+ auto si = m_streams.find(si1->second);
+ if(si == m_streams.end())
+ break;
+ pa_context_get_sink_input_info(m_context, idx, i_sink_input_info_change, (void *)&si->second);
+ break;
+ }
+
+ default:
+ fprintf(stderr, "event %s %s %d\n", evt2[t>>4], evt[t&15], idx);
+ }
+}
+
+void sound_pulse::i_context_subscribe(pa_context *, pa_subscription_event_type_t t, uint32_t idx, void *self)
+{
+ static_cast<sound_pulse *>(self)->context_subscribe(t, idx);
+}
+
+
+
+int sound_pulse::init(osd_interface &osd, osd_options const &options)
+{
+ m_node_current_id = 1;
+ m_stream_current_id = 1;
+ m_generation = 0;
+ m_wait_stream = false;
+ m_wait_init = true;
+
+ m_mainloop = pa_threaded_mainloop_new();
+ m_context = pa_context_new(pa_threaded_mainloop_get_api(m_mainloop), "MAME");
+ pa_context_set_state_callback(m_context, i_context_notify, this);
+ pa_context_set_subscribe_callback(m_context, i_context_subscribe, this);
+ pa_context_connect(m_context, nullptr, PA_CONTEXT_NOFLAGS, nullptr);
+ pa_threaded_mainloop_start(m_mainloop);
+
+ pa_threaded_mainloop_lock(m_mainloop);
+ while(m_wait_init)
+ pa_threaded_mainloop_wait(m_mainloop);
+ pa_threaded_mainloop_unlock(m_mainloop);
+ if(m_generation >= 0x80000000)
+ return 1;
+
+ return 0;
+}
+
+uint32_t sound_pulse::get_generation()
+{
+ pa_threaded_mainloop_lock(m_mainloop);
+ uint32_t result = m_generation;
+ pa_threaded_mainloop_unlock(m_mainloop);
+ return result;
+}
+
+osd::audio_info sound_pulse::get_information()
+{
+ osd::audio_info result;
+ pa_threaded_mainloop_lock(m_mainloop);
+ result.m_nodes.resize(m_nodes.size());
+ result.m_default_sink = 0;
+ result.m_default_source = 0;
+ result.m_generation = m_generation;
+ uint32_t node = 0;
+ for(auto &inode : m_nodes) {
+ result.m_nodes[node].m_name = inode.second.m_desc;
+ result.m_nodes[node].m_id = inode.second.m_osdid;
+ result.m_nodes[node].m_rate = inode.second.m_rate;
+ result.m_nodes[node].m_sinks = inode.second.m_sink_port_count;
+ result.m_nodes[node].m_sources = inode.second.m_source_port_count;
+ result.m_nodes[node].m_port_names = inode.second.m_position_names;
+ result.m_nodes[node].m_port_positions = inode.second.m_positions;
+
+ if(inode.second.m_name == m_default_audio_sink)
+ result.m_default_sink = inode.second.m_osdid;
+ if(inode.second.m_name == m_default_audio_source)
+ result.m_default_source = inode.second.m_osdid;
+ node ++;
+ }
+
+ for(auto &istream : m_streams)
+ if(istream.second.m_target_node)
+ result.m_streams.emplace_back(osd::audio_info::stream_info { istream.second.m_osdid, istream.second.m_target_node->m_osdid, istream.second.m_volumes });
+
+ pa_threaded_mainloop_unlock(m_mainloop);
+ return result;
+}
+
+uint32_t sound_pulse::stream_sink_open(uint32_t node, std::string name, uint32_t rate)
+{
+ pa_threaded_mainloop_lock(m_mainloop);
+ auto ni = m_node_osdid_to_id.find(node);
+ if(ni == m_node_osdid_to_id.end()) {
+ pa_threaded_mainloop_unlock(m_mainloop);
+ return 0;
+ }
+ node_info &snode = m_nodes.find(ni->second)->second;
+
+ uint32_t id = m_stream_current_id++;
+ auto &stream = m_streams.emplace(id, stream_info(this, id, snode.m_sink_port_count)).first->second;
+
+ pa_sample_spec ss;
+#ifdef LSB_FIRST
+ ss.format = PA_SAMPLE_S16LE;
+#else
+ ss.format = PA_SAMPLE_S16BE;
+#endif
+ ss.rate = rate;
+ ss.channels = stream.m_channels;
+ stream.m_stream = pa_stream_new(m_context, name.c_str(), &ss, nullptr);
+ pa_stream_set_state_callback(stream.m_stream, i_stream_notify, &stream);
+ pa_stream_set_write_callback(stream.m_stream, i_stream_write_request, &stream);
+
+ pa_buffer_attr battr;
+ battr.fragsize = uint32_t(-1);
+ battr.maxlength = 1024;
+ battr.minreq = uint32_t(-1);
+ battr.prebuf = uint32_t(-1);
+ battr.tlength = uint32_t(-1);
+
+ int err = pa_stream_connect_playback(stream.m_stream, snode.m_name.c_str(), &battr, pa_stream_flags_t(PA_STREAM_ADJUST_LATENCY|PA_STREAM_START_UNMUTED), nullptr, nullptr);
+ if(err)
+ generic_pa_error("stream connect playback", err);
+
+ stream.m_target_node = &snode;
+
+ m_wait_stream = true;
+ while(m_wait_stream)
+ pa_threaded_mainloop_wait(m_mainloop);
+
+ stream.m_pulse_id = pa_stream_get_index(stream.m_stream);
+ m_stream_pulse_id_to_osdid[stream.m_pulse_id] = id;
+
+ fprintf(stderr, "stream id %d\n", stream.m_pulse_id);
+ pa_threaded_mainloop_unlock(m_mainloop);
+
+ return id;
+}
+
+void sound_pulse::stream_sink_update(uint32_t id, const int16_t *buffer, int samples_this_frame)
+{
+ pa_threaded_mainloop_lock(m_mainloop);
+ auto si = m_streams.find(id);
+ if(si == m_streams.end()) {
+ pa_threaded_mainloop_unlock(m_mainloop);
+ return;
+ }
+ si->second.m_buffer.push(buffer, samples_this_frame);
+ pa_threaded_mainloop_unlock(m_mainloop);
+}
+
+void sound_pulse::stream_set_volumes(uint32_t id, const std::vector<float> &db)
+{
+}
+
+void sound_pulse::stream_close(uint32_t id)
+{
+ pa_threaded_mainloop_lock(m_mainloop);
+ auto si = m_streams.find(id);
+ if(si == m_streams.end()) {
+ pa_threaded_mainloop_unlock(m_mainloop);
+ return;
+ }
+ stream_info &stream = si->second;
+ pa_stream_set_state_callback(stream.m_stream, nullptr, &stream);
+ pa_stream_set_write_callback(stream.m_stream, nullptr, &stream);
+ pa_stream_disconnect(stream.m_stream);
+ m_streams.erase(si);
+ pa_threaded_mainloop_unlock(m_mainloop);
+}
+
+void sound_pulse::exit()
+{
+ for(const auto &si : m_streams) {
+ pa_stream_disconnect(si.second.m_stream);
+ pa_stream_unref(si.second.m_stream);
+ }
+
+ pa_context_unref(m_context);
+ pa_threaded_mainloop_free(m_mainloop);
+}
+
+#else
+ MODULE_NOT_SUPPORTED(sound_pulse, OSD_SOUND_PROVIDER, "pulse")
+#endif
+
+MODULE_DEFINITION(SOUND_PULSEAUDIO, sound_pulse)
diff --git a/src/osd/modules/sound/sdl_sound.cpp b/src/osd/modules/sound/sdl_sound.cpp
index 5ff8f2e6821..35c11eae86d 100644
--- a/src/osd/modules/sound/sdl_sound.cpp
+++ b/src/osd/modules/sound/sdl_sound.cpp
@@ -9,458 +9,231 @@
//============================================================
#include "sound_module.h"
+
#include "modules/osdmodule.h"
#if (defined(OSD_SDL) || defined(USE_SDL_SOUND))
+#include "modules/lib/osdobj_common.h"
+#include "osdcore.h"
+
// standard sdl header
#include <SDL2/SDL.h>
-// MAME headers
-#include "emu.h"
-#include "emuopts.h"
-
-#include "../../sdl/osdsdl.h"
-
#include <algorithm>
+#include <cmath>
#include <fstream>
#include <memory>
+#include <map>
-//============================================================
-// DEBUGGING
-//============================================================
-#define LOG_SOUND 0
+namespace osd {
-//============================================================
-// CLASS
-//============================================================
+namespace {
class sound_sdl : public osd_module, public sound_module
{
public:
-
- // number of samples per SDL callback
- static const int SDL_XFER_SAMPLES = 512;
-
sound_sdl() :
- osd_module(OSD_SOUND_PROVIDER, "sdl"), sound_module(),
- stream_in_initialized(0),
- attenuation(0), buf_locked(0), stream_buffer(nullptr), stream_buffer_size(0), buffer_underflows(0), buffer_overflows(0)
-{
- sdl_xfer_samples = SDL_XFER_SAMPLES;
+ osd_module(OSD_SOUND_PROVIDER, "sdl"), sound_module()
+ {
}
+
virtual ~sound_sdl() { }
- virtual int init(const osd_options &options) override;
+ virtual int init(osd_interface &osd, const osd_options &options) override;
virtual void exit() override;
- // sound_module
+ virtual bool external_per_channel_volume() override { return false; }
+ virtual bool split_streams_per_source() override { return false; }
- virtual void update_audio_stream(bool is_throttled, const int16_t *buffer, int samples_this_frame) override;
- virtual void set_mastervolume(int attenuation) override;
+ virtual uint32_t get_generation() override;
+ virtual osd::audio_info get_information() override;
+ virtual uint32_t stream_sink_open(uint32_t node, std::string name, uint32_t rate) override;
+ virtual void stream_close(uint32_t id) override;
+ virtual void stream_sink_update(uint32_t id, const int16_t *buffer, int samples_this_frame) override;
private:
- class ring_buffer
- {
- public:
- ring_buffer(size_t size);
-
- size_t data_size() const { return (tail - head + buffer_size) % buffer_size; }
- size_t free_size() const { return (head - tail - 1 + buffer_size) % buffer_size; }
- int append(const void *data, size_t size);
- int pop(void *data, size_t size);
-
- private:
- std::unique_ptr<int8_t []> const buffer;
- size_t const buffer_size;
- int head = 0, tail = 0;
+ struct device_info {
+ std::string m_name;
+ int m_freq;
+ uint8_t m_channels;
+ device_info(const char *name, int freq, uint8_t channels) : m_name(name), m_freq(freq), m_channels(channels) {}
};
- static void sdl_callback(void *userdata, Uint8 *stream, int len);
-
- void lock_buffer();
- void unlock_buffer();
- void attenuate(int16_t *data, int bytes);
- void copy_sample_data(bool is_throttled, const int16_t *data, int bytes_to_copy);
- int sdl_create_buffers();
- void sdl_destroy_buffers();
-
- int sdl_xfer_samples;
- int stream_in_initialized;
- int attenuation;
+ struct stream_info {
+ uint32_t m_id;
+ SDL_AudioDeviceID m_sdl_id;
+ abuffer m_buffer;
+ stream_info(uint32_t id, uint8_t channels) : m_id(id), m_sdl_id(0), m_buffer(channels) {}
+ };
- int buf_locked;
- std::unique_ptr<ring_buffer> stream_buffer;
- uint32_t stream_buffer_size;
+ std::vector<device_info> m_devices;
+ uint32_t m_default_sink;
+ uint32_t m_stream_next_id;
+ std::map<uint32_t, std::unique_ptr<stream_info>> m_streams;
- // diagnostics
- int buffer_underflows;
- int buffer_overflows;
- std::unique_ptr<std::ofstream> sound_log;
+ static void sink_callback(void *userdata, Uint8 *stream, int len);
};
-
-//============================================================
-// PARAMETERS
-//============================================================
-
-// maximum audio latency
-#define MAX_AUDIO_LATENCY 5
-
-//============================================================
-// ring_buffer - constructor
-//============================================================
-
-sound_sdl::ring_buffer::ring_buffer(size_t size)
- : buffer(std::make_unique<int8_t []>(size + 1)), buffer_size(size + 1)
-{
- // A size+1 bytes buffer is allocated because it can never be full.
- // Otherwise the case head == tail couldn't be distinguished between a
- // full buffer and an empty buffer.
- std::fill_n(buffer.get(), size + 1, 0);
-}
-
//============================================================
-// ring_buffer::append
+// sound_sdl::init
//============================================================
-int sound_sdl::ring_buffer::append(const void *data, size_t size)
+int sound_sdl::init(osd_interface &osd, const osd_options &options)
{
- if (free_size() < size)
- return -1;
+ m_stream_next_id = 1;
- int8_t const *const data8 = reinterpret_cast<int8_t const *>(data);
- size_t sz = buffer_size - tail;
- if (size <= sz)
- sz = size;
- else
- std::copy_n(&data8[sz], size - sz, &buffer[0]);
-
- std::copy_n(data8, sz, &buffer[tail]);
- tail = (tail + size) % buffer_size;
-
- return 0;
-}
-
-//============================================================
-// ring_buffer::pop
-//============================================================
-
-int sound_sdl::ring_buffer::pop(void *data, size_t size)
-{
- if (data_size() < size)
+ if(SDL_InitSubSystem(SDL_INIT_AUDIO)) {
+ osd_printf_error("Could not initialize SDL %s\n", SDL_GetError());
return -1;
-
- int8_t *const data8 = reinterpret_cast<int8_t *>(data);
- size_t sz = buffer_size - head;
- if (size <= sz)
- sz = size;
- else
- {
- std::copy_n(&buffer[0], size - sz, &data8[sz]);
- std::fill_n(&buffer[0], size - sz, 0);
}
- std::copy_n(&buffer[head], sz, data8);
- std::fill_n(&buffer[head], sz, 0);
- head = (head + size) % buffer_size;
-
+ osd_printf_verbose("Audio: Start initialization\n");
+ char const *const audio_driver = SDL_GetCurrentAudioDriver();
+ osd_printf_verbose("Audio: Driver is %s\n", audio_driver ? audio_driver : "not initialized");
+
+ // Capture is not implemented in SDL2, and the enumeration
+ // interface is different in SDL3
+ int dev_count = SDL_GetNumAudioDevices(0);
+ for(int i=0; i != dev_count; i++) {
+ SDL_AudioSpec spec;
+ const char *name = SDL_GetAudioDeviceName(i, 0);
+ int err = SDL_GetAudioDeviceSpec(i, 0, &spec);
+ if(!err)
+ m_devices.emplace_back(name, spec.freq, spec.channels);
+ }
+ char *def_name;
+ SDL_AudioSpec def_spec;
+ if(!SDL_GetDefaultAudioInfo(&def_name, &def_spec, 0)) {
+ uint32_t idx;
+ for(idx = 0; idx != m_devices.size() && m_devices[idx].m_name != def_name; idx++);
+ if(idx == m_devices.size())
+ m_devices.emplace_back(def_name, def_spec.freq, def_spec.channels);
+ m_default_sink = idx+1;
+ SDL_free(def_name);
+ } else
+ m_default_sink = 0;
return 0;
}
-//============================================================
-// sound_sdl - destructor
-//============================================================
-
-//============================================================
-// lock_buffer
-//============================================================
-void sound_sdl::lock_buffer()
+void sound_sdl::exit()
{
- if (!buf_locked)
- SDL_LockAudio();
- buf_locked++;
-
- if (LOG_SOUND)
- *sound_log << "locking\n";
+ SDL_QuitSubSystem(SDL_INIT_AUDIO);
}
-//============================================================
-// unlock_buffer
-//============================================================
-void sound_sdl::unlock_buffer()
+uint32_t sound_sdl::get_generation()
{
- buf_locked--;
- if (!buf_locked)
- SDL_UnlockAudio();
-
- if (LOG_SOUND)
- *sound_log << "unlocking\n";
-
+ // sdl2 is not dynamic w.r.t devices
+ return 1;
}
-//============================================================
-// Apply attenuation
-//============================================================
+osd::audio_info sound_sdl::get_information()
+{
+ enum { FL, FR, FC, LFE, BL, BR, BC, SL, SR };
+ static const char *const posname[9] = { "FL", "FR", "FC", "LFE", "BL", "BR", "BC", "SL", "SR" };
+
+ static std::array<double, 3> pos3d[9] = {
+ { -0.2, 0.0, 1.0 },
+ { 0.2, 0.0, 1.0 },
+ { 0.0, 0.0, 1.0 },
+ { 0.0, -0.5, 1.0 },
+ { -0.2, 0.0, -0.5 },
+ { 0.2, 0.0, -0.5 },
+ { 0.0, 0.0, -0.5 },
+ { -0.2, 0.0, 0.0 },
+ { 0.2, 0.0, 0.0 },
+ };
+
+ static const uint32_t positions[8][8] = {
+ { FC },
+ { FL, FR },
+ { FL, FR, LFE },
+ { FL, FR, BL, BR },
+ { FL, FR, LFE, BL, BR },
+ { FL, FR, FC, LFE, BL, BR },
+ { FL, FR, FC, LFE, BC, SL, SR },
+ { FL, FR, FC, LFE, BL, BR, SL, SR }
+ };
-void sound_sdl::attenuate(int16_t *data, int bytes_to_copy)
-{
- int level = (int) (pow(10.0, (double) attenuation / 20.0) * 128.0);
- int count = bytes_to_copy / sizeof(*data);
- while (count > 0)
- {
- *data = (*data * level) >> 7; /* / 128 */
- data++;
- count--;
+ osd::audio_info result;
+ result.m_nodes.resize(m_devices.size());
+ result.m_default_sink = m_default_sink;
+ result.m_default_source = 0;
+ result.m_generation = 1;
+ for(uint32_t node = 0; node != m_devices.size(); node++) {
+ result.m_nodes[node].m_name = m_devices[node].m_name;
+ result.m_nodes[node].m_id = node + 1;
+ uint32_t freq = m_devices[node].m_freq;
+ result.m_nodes[node].m_rate = audio_rate_range{ freq, freq, freq };
+ result.m_nodes[node].m_sinks = m_devices[node].m_channels;
+ for(uint32_t port = 0; port != m_devices[node].m_channels; port++) {
+ uint32_t pos = positions[m_devices[node].m_channels-1][port];
+ result.m_nodes[node].m_port_names.push_back(posname[pos]);
+ result.m_nodes[node].m_port_positions.push_back(pos3d[pos]);
+ }
}
+ return result;
}
-//============================================================
-// copy_sample_data
-//============================================================
-
-void sound_sdl::copy_sample_data(bool is_throttled, const int16_t *data, int bytes_to_copy)
+uint32_t sound_sdl::stream_sink_open(uint32_t node, std::string name, uint32_t rate)
{
- lock_buffer();
- int const err = stream_buffer->append(data, bytes_to_copy);
- unlock_buffer();
-
- if (LOG_SOUND && err)
- *sound_log << "Late detection of overflow. This shouldn't happen.\n";
-}
+ device_info &dev = m_devices[node-1];
+ std::unique_ptr<stream_info> stream = std::make_unique<stream_info>(m_stream_next_id ++, dev.m_channels);
+ SDL_AudioSpec dspec, ospec;
+ dspec.freq = rate;
+ dspec.format = AUDIO_S16SYS;
+ dspec.channels = dev.m_channels;
+ dspec.samples = 512;
+ dspec.callback = sink_callback;
+ dspec.userdata = stream.get();
-//============================================================
-// update_audio_stream
-//============================================================
-
-void sound_sdl::update_audio_stream(bool is_throttled, const int16_t *buffer, int samples_this_frame)
-{
- // if nothing to do, don't do it
- if (sample_rate() == 0 || !stream_buffer)
- return;
-
-
- if (!stream_in_initialized)
- {
- // Fill in some zeros to prevent an initial buffer underflow
- int8_t zero = 0;
- size_t zsize = stream_buffer->free_size() / 2;
- while (zsize--)
- stream_buffer->append(&zero, 1);
-
- // start playing
- SDL_PauseAudio(0);
- stream_in_initialized = 1;
- }
-
- size_t bytes_this_frame = samples_this_frame * sizeof(*buffer) * 2;
- size_t free_size = stream_buffer->free_size();
- size_t data_size = stream_buffer->data_size();
-
- if (stream_buffer->free_size() < bytes_this_frame) {
- if (LOG_SOUND)
- util::stream_format(*sound_log, "Overflow: DS=%u FS=%u BTF=%u\n", data_size, free_size, bytes_this_frame);
- buffer_overflows++;
- return;
- }
-
- copy_sample_data(is_throttled, buffer, bytes_this_frame);
-
- size_t nfree_size = stream_buffer->free_size();
- size_t ndata_size = stream_buffer->data_size();
- if (LOG_SOUND)
- util::stream_format(*sound_log, "Appended data: DS=%u(%u) FS=%u(%u) BTF=%u\n", data_size, ndata_size, free_size, nfree_size, bytes_this_frame);
-}
-
-
-
-//============================================================
-// set_mastervolume
-//============================================================
-
-void sound_sdl::set_mastervolume(int _attenuation)
-{
- // clamp the attenuation to 0-32 range
- attenuation = std::max(std::min(_attenuation, 0), -32);
-
- if (stream_in_initialized)
- {
- if (attenuation == -32)
- SDL_PauseAudio(1);
- else
- SDL_PauseAudio(0);
- }
+ stream->m_sdl_id = SDL_OpenAudioDevice(dev.m_name.c_str(), 0, &dspec, &ospec, 0);
+ if(!stream->m_sdl_id)
+ return 0;
+ SDL_PauseAudioDevice(stream->m_sdl_id, 0);
+ uint32_t id = stream->m_id;
+ m_streams[stream->m_id] = std::move(stream);
+ return id;
}
-//============================================================
-// sdl_callback
-//============================================================
-void sound_sdl::sdl_callback(void *userdata, Uint8 *stream, int len)
+void sound_sdl::stream_close(uint32_t id)
{
- sound_sdl *thiz = reinterpret_cast<sound_sdl *>(userdata);
- size_t const free_size = thiz->stream_buffer->free_size();
- size_t const data_size = thiz->stream_buffer->data_size();
-
- if (data_size < len)
- {
- thiz->buffer_underflows++;
- if (LOG_SOUND)
- util::stream_format(*thiz->sound_log, "Underflow at sdl_callback: DS=%u FS=%u Len=%d\n", data_size, free_size, len);
-
- // Maybe read whatever is left in the stream_buffer anyway?
- memset(stream, 0, len);
+ auto si = m_streams.find(id);
+ if(si == m_streams.end())
return;
- }
-
- int err = thiz->stream_buffer->pop((void *)stream, len);
- if (LOG_SOUND && err)
- *thiz->sound_log << "Late detection of underflow. This shouldn't happen.\n";
-
- thiz->attenuate((int16_t *)stream, len);
-
- if (LOG_SOUND)
- util::stream_format(*thiz->sound_log, "callback: xfer DS=%u FS=%u Len=%d\n", data_size, free_size, len);
-}
-
-
-//============================================================
-// sound_sdl::init
-//============================================================
-
-int sound_sdl::init(const osd_options &options)
-{
- int n_channels = 2;
- int audio_latency;
- SDL_AudioSpec aspec, obtained;
- char audio_driver[16] = "";
-
- if (LOG_SOUND)
- sound_log = std::make_unique<std::ofstream>(SDLMAME_SOUND_LOG);
-
- // skip if sound disabled
- if (sample_rate() != 0)
- {
- if (SDL_InitSubSystem(SDL_INIT_AUDIO))
- {
- osd_printf_error("Could not initialize SDL %s\n", SDL_GetError());
- return -1;
- }
-
- osd_printf_verbose("Audio: Start initialization\n");
- strncpy(audio_driver, SDL_GetCurrentAudioDriver(), sizeof(audio_driver));
- osd_printf_verbose("Audio: Driver is %s\n", audio_driver);
-
- sdl_xfer_samples = SDL_XFER_SAMPLES;
- stream_in_initialized = 0;
-
- // set up the audio specs
- aspec.freq = sample_rate();
- aspec.format = AUDIO_S16SYS; // keep endian independent
- aspec.channels = n_channels;
- aspec.samples = sdl_xfer_samples;
- aspec.callback = sdl_callback;
- aspec.userdata = this;
-
- if (SDL_OpenAudio(&aspec, &obtained) < 0)
- goto cant_start_audio;
-
- osd_printf_verbose("Audio: frequency: %d, channels: %d, samples: %d\n",
- obtained.freq, obtained.channels, obtained.samples);
-
- sdl_xfer_samples = obtained.samples;
-
- // pin audio latency
- audio_latency = std::max(std::min(m_audio_latency, MAX_AUDIO_LATENCY), 1);
-
- // compute the buffer sizes
- stream_buffer_size = (sample_rate() * 2 * sizeof(int16_t) * (2 + audio_latency)) / 30;
- stream_buffer_size = (stream_buffer_size / 1024) * 1024;
- if (stream_buffer_size < 1024)
- stream_buffer_size = 1024;
-
- // create the buffers
- if (sdl_create_buffers())
- goto cant_create_buffers;
-
- // set the startup volume
- set_mastervolume(attenuation);
- osd_printf_verbose("Audio: End initialization\n");
- return 0;
-
- // error handling
- cant_create_buffers:
- cant_start_audio:
- osd_printf_verbose("Audio: Initialization failed. SDL error: %s\n", SDL_GetError());
-
- return -1;
- }
-
- return 0;
+ SDL_CloseAudioDevice(si->second->m_sdl_id);
+ m_streams.erase(si);
}
-
-
-//============================================================
-// sdl_kill
-//============================================================
-
-void sound_sdl::exit()
+void sound_sdl::stream_sink_update(uint32_t id, const int16_t *buffer, int samples_this_frame)
{
- // if nothing to do, don't do it
- if (sample_rate() == 0)
+ auto si = m_streams.find(id);
+ if(si == m_streams.end())
return;
-
- osd_printf_verbose("sdl_kill: closing audio\n");
- SDL_CloseAudio();
-
- SDL_QuitSubSystem(SDL_INIT_AUDIO);
-
- // kill the buffers
- sdl_destroy_buffers();
-
- // print out over/underflow stats
- if (buffer_overflows || buffer_underflows)
- osd_printf_verbose("Sound buffer: overflows=%d underflows=%d\n", buffer_overflows, buffer_underflows);
-
- if (LOG_SOUND)
- {
- util::stream_format(*sound_log, "Sound buffer: overflows=%d underflows=%d\n", buffer_overflows, buffer_underflows);
- sound_log.reset();
- }
+ stream_info *stream = si->second.get();
+ SDL_LockAudioDevice(stream->m_sdl_id);
+ stream->m_buffer.push(buffer, samples_this_frame);
+ SDL_UnlockAudioDevice(stream->m_sdl_id);
}
-
-
-//============================================================
-// dsound_create_buffers
-//============================================================
-
-int sound_sdl::sdl_create_buffers()
+void sound_sdl::sink_callback(void *userdata, uint8_t *data, int len)
{
- osd_printf_verbose("sdl_create_buffers: creating stream buffer of %u bytes\n", stream_buffer_size);
-
- stream_buffer = std::make_unique<ring_buffer>(stream_buffer_size);
- buf_locked = 0;
- return 0;
+ stream_info *stream = reinterpret_cast<stream_info *>(userdata);
+ stream->m_buffer.get((int16_t *)data, len / 2 / stream->m_buffer.channels());
}
-//============================================================
-// sdl_destroy_buffers
-//============================================================
+} // anonymous namespace
+
+} // namespace osd
-void sound_sdl::sdl_destroy_buffers()
-{
- // release the buffer
- stream_buffer.reset();
-}
+#else // (defined(OSD_SDL) || defined(USE_SDL_SOUND))
+namespace osd { namespace { MODULE_NOT_SUPPORTED(sound_sdl, OSD_SOUND_PROVIDER, "sdl") } }
-#else /* SDLMAME_UNIX */
- MODULE_NOT_SUPPORTED(sound_sdl, OSD_SOUND_PROVIDER, "sdl")
#endif
-MODULE_DEFINITION(SOUND_SDL, sound_sdl)
+MODULE_DEFINITION(SOUND_SDL, osd::sound_sdl)
diff --git a/src/osd/modules/sound/sound_module.cpp b/src/osd/modules/sound/sound_module.cpp
new file mode 100644
index 00000000000..5dc13eb3246
--- /dev/null
+++ b/src/osd/modules/sound/sound_module.cpp
@@ -0,0 +1,61 @@
+// license:BSD-3-Clause
+// copyright-holders:O. Galibert
+
+
+#include "emu.h"
+#include "sound_module.h"
+
+void sound_module::abuffer::get(int16_t *data, uint32_t samples)
+{
+ uint32_t pos = 0;
+ while(pos != samples) {
+ if(m_buffers.empty()) {
+ while(pos != samples) {
+ memcpy(data, m_last_sample.data(), m_channels*2);
+ data += m_channels;
+ pos ++;
+ }
+ break;
+ }
+
+ auto &buf = m_buffers.front();
+ if(buf.m_data.empty()) {
+ m_buffers.erase(m_buffers.begin());
+ continue;
+ }
+
+ uint32_t avail = buf.m_data.size() / m_channels - buf.m_cpos;
+ if(avail > samples - pos) {
+ avail = samples - pos;
+ memcpy(data, buf.m_data.data() + buf.m_cpos * m_channels, avail * 2 * m_channels);
+ buf.m_cpos += avail;
+ break;
+ }
+
+ memcpy(data, buf.m_data.data() + buf.m_cpos * m_channels, avail * 2 * m_channels);
+ m_buffers.erase(m_buffers.begin());
+ pos += avail;
+ data += avail * m_channels;
+ }
+}
+
+void sound_module::abuffer::push(const int16_t *data, uint32_t samples)
+{
+ m_buffers.resize(m_buffers.size() + 1);
+ auto &buf = m_buffers.back();
+ buf.m_cpos = 0;
+ buf.m_data.resize(samples * m_channels);
+ memcpy(buf.m_data.data(), data, samples * 2 * m_channels);
+ memcpy(m_last_sample.data(), data + (samples-1) * m_channels, 2 * m_channels);
+
+ if(m_buffers.size() > 10)
+ // If there are way too many buffers, drop some so only 10 are left (roughly 0.2s)
+ m_buffers.erase(m_buffers.begin(), m_buffers.begin() + m_buffers.size() - 10);
+
+ else if(m_buffers.size() >= 5)
+ // If there are too many buffers, remove five samples per buffer
+ // to slowly resync to reduce latency (4 seconds to
+ // compensate one buffer, roughly)
+ buf.m_cpos = 5;
+}
+
diff --git a/src/osd/modules/sound/sound_module.h b/src/osd/modules/sound/sound_module.h
index d9f597ad0d9..2498db84107 100644
--- a/src/osd/modules/sound/sound_module.h
+++ b/src/osd/modules/sound/sound_module.h
@@ -4,33 +4,76 @@
* sound_module.h
*
*/
+#ifndef MAME_OSD_SOUND_SOUND_MODULE_H
+#define MAME_OSD_SOUND_SOUND_MODULE_H
-#ifndef SOUND_MODULE_H_
-#define SOUND_MODULE_H_
+#pragma once
-#include "osdepend.h"
-#include "modules/osdmodule.h"
+#include <osdepend.h>
-//============================================================
-// CONSTANTS
-//============================================================
+#include <cstdint>
+#include <array>
+#include <vector>
+#include <string>
#define OSD_SOUND_PROVIDER "sound"
class sound_module
{
public:
- sound_module() : m_sample_rate(0), m_audio_latency(1) { }
+ virtual ~sound_module() = default;
- virtual ~sound_module() { }
+ virtual uint32_t get_generation() { return 1; }
+ virtual osd::audio_info get_information() {
+ osd::audio_info result;
+ result.m_generation = 1;
+ result.m_default_sink = 1;
+ result.m_default_source = 0;
+ result.m_nodes.resize(1);
+ result.m_nodes[0].m_name = "";
+ result.m_nodes[0].m_id = 1;
+ result.m_nodes[0].m_rate.m_default_rate = 0; // Magic value meaning "use configured sample rate"
+ result.m_nodes[0].m_rate.m_min_rate = 0;
+ result.m_nodes[0].m_rate.m_max_rate = 0;
+ result.m_nodes[0].m_sinks = 2;
+ result.m_nodes[0].m_sources = 0;
+ result.m_nodes[0].m_port_names.push_back("L");
+ result.m_nodes[0].m_port_names.push_back("R");
+ result.m_nodes[0].m_port_positions.emplace_back(std::array<double, 3>({ -0.2, 0.0, 1.0 }));
+ result.m_nodes[0].m_port_positions.emplace_back(std::array<double, 3>({ 0.2, 0.0, 1.0 }));
+ result.m_streams.resize(1);
+ result.m_streams[0].m_id = 1;
+ result.m_streams[0].m_node = 1;
+ return result;
+ }
+ virtual bool external_per_channel_volume() { return false; }
+ virtual bool split_streams_per_source() { return false; }
- virtual void update_audio_stream(bool is_throttled, const int16_t *buffer, int samples_this_frame) = 0;
- virtual void set_mastervolume(int attenuation) = 0;
+ virtual uint32_t stream_sink_open(uint32_t node, std::string name, uint32_t rate) { return 1; }
+ virtual uint32_t stream_source_open(uint32_t node, std::string name, uint32_t rate) { return 0; }
+ virtual void stream_set_volumes(uint32_t id, const std::vector<float> &db) {}
+ virtual void stream_close(uint32_t id) {}
+ virtual void stream_sink_update(uint32_t id, const int16_t *buffer, int samples_this_frame) {}
+ virtual void stream_source_update(uint32_t id, int16_t *buffer, int samples_this_frame) {}
- int sample_rate() const { return m_sample_rate; }
+protected:
+ class abuffer {
+ public:
+ abuffer(uint32_t channels) : m_channels(channels), m_last_sample(channels, 0) {}
+ void get(int16_t *data, uint32_t samples);
+ void push(const int16_t *data, uint32_t samples);
+ uint32_t channels() const { return m_channels; }
- int m_sample_rate;
- int m_audio_latency;
+ private:
+ struct buffer {
+ uint32_t m_cpos;
+ std::vector<int16_t> m_data;
+ };
+
+ uint32_t m_channels;
+ std::vector<int16_t> m_last_sample;
+ std::vector<buffer> m_buffers;
+ };
};
-#endif /* FONT_MODULE_H_ */
+#endif // MAME_OSD_SOUND_SOUND_MODULE_H
diff --git a/src/osd/modules/sound/xaudio2_sound.cpp b/src/osd/modules/sound/xaudio2_sound.cpp
index 1d9e1036f9a..a865f2527fe 100644
--- a/src/osd/modules/sound/xaudio2_sound.cpp
+++ b/src/osd/modules/sound/xaudio2_sound.cpp
@@ -7,9 +7,24 @@
//====================================================================
#include "sound_module.h"
+
#include "modules/osdmodule.h"
-#if defined(OSD_WINDOWS) || defined(OSD_UWP)
+#if defined(OSD_WINDOWS) | defined(SDLMAME_WIN32)
+
+// OSD headers
+#include "modules/lib/osdlib.h"
+#include "modules/lib/osdobj_common.h"
+#include "osdcore.h"
+#include "osdepend.h"
+#include "windows/winutil.h"
+
+// stdlib includes
+#include <algorithm>
+#include <chrono>
+#include <mutex>
+#include <queue>
+#include <thread>
// standard windows headers
#include <windows.h>
@@ -19,21 +34,10 @@
// XAudio2 include
#include <xaudio2.h>
-#undef interface
-// stdlib includes
-#include <mutex>
-#include <thread>
-#include <queue>
-#include <chrono>
+namespace osd {
-// MAME headers
-#include "emu.h"
-#include "osdepend.h"
-
-#include "winutil.h"
-
-#include "modules/lib/osdlib.h"
+namespace {
//============================================================
// Constants
@@ -180,29 +184,6 @@ public:
// The main class for the XAudio2 sound module implementation
class sound_xaudio2 : public osd_module, public sound_module, public IXAudio2VoiceCallback
{
-private:
- Microsoft::WRL::ComPtr<IXAudio2> m_xAudio2;
- mastering_voice_ptr m_masterVoice;
- src_voice_ptr m_sourceVoice;
- DWORD m_sample_bytes;
- std::unique_ptr<BYTE[]> m_buffer;
- DWORD m_buffer_size;
- DWORD m_buffer_count;
- DWORD m_writepos;
- std::mutex m_buffer_lock;
- HANDLE m_hEventBufferCompleted;
- HANDLE m_hEventDataAvailable;
- HANDLE m_hEventExiting;
- std::thread m_audioThread;
- std::queue<xaudio2_buffer> m_queue;
- std::unique_ptr<bufferpool> m_buffer_pool;
- uint32_t m_overflows;
- uint32_t m_underflows;
- BOOL m_in_underflow;
- BOOL m_initialized;
- OSD_DYNAMIC_API(xaudio2, "XAudio2_9.dll", "XAudio2_8.dll");
- OSD_DYNAMIC_API_FN(xaudio2, HRESULT, WINAPI, XAudio2Create, IXAudio2 **, uint32_t, XAUDIO2_PROCESSOR);
-
public:
sound_xaudio2() :
osd_module(OSD_SOUND_PROVIDER, "xaudio2"),
@@ -210,6 +191,8 @@ public:
m_xAudio2(nullptr),
m_masterVoice(nullptr),
m_sourceVoice(nullptr),
+ m_sample_rate(0),
+ m_audio_latency(0),
m_sample_bytes(0),
m_buffer(nullptr),
m_buffer_size(0),
@@ -226,26 +209,23 @@ public:
{
}
- virtual ~sound_xaudio2() { }
-
bool probe() override;
- int init(osd_options const &options) override;
+ int init(osd_interface &osd, osd_options const &options) override;
void exit() override;
// sound_module
- void update_audio_stream(bool is_throttled, int16_t const *buffer, int samples_this_frame) override;
- void set_mastervolume(int attenuation) override;
+ void stream_sink_update(uint32_t, int16_t const *buffer, int samples_this_frame) override;
+private:
// Xaudio callbacks
- void STDAPICALLTYPE OnVoiceProcessingPassStart(uint32_t bytes_required) override;
- void STDAPICALLTYPE OnVoiceProcessingPassEnd() override {}
- void STDAPICALLTYPE OnStreamEnd() override {}
- void STDAPICALLTYPE OnBufferStart(void* pBufferContext) override {}
- void STDAPICALLTYPE OnLoopEnd(void* pBufferContext) override {}
- void STDAPICALLTYPE OnVoiceError(void* pBufferContext, HRESULT error) override {}
- void STDAPICALLTYPE OnBufferEnd(void *pBufferContext) override;
+ void STDAPICALLTYPE OnVoiceProcessingPassStart(uint32_t bytes_required) noexcept override;
+ void STDAPICALLTYPE OnVoiceProcessingPassEnd() noexcept override {}
+ void STDAPICALLTYPE OnStreamEnd() noexcept override {}
+ void STDAPICALLTYPE OnBufferStart(void* pBufferContext) noexcept override {}
+ void STDAPICALLTYPE OnLoopEnd(void* pBufferContext) noexcept override {}
+ void STDAPICALLTYPE OnVoiceError(void* pBufferContext, HRESULT error) noexcept override {}
+ void STDAPICALLTYPE OnBufferEnd(void *pBufferContext) noexcept override;
-private:
void create_buffers(const WAVEFORMATEX &format);
HRESULT create_voices(const WAVEFORMATEX &format);
void process_audio();
@@ -253,6 +233,31 @@ private:
void submit_needed();
void roll_buffer();
BOOL submit_next_queued();
+
+ Microsoft::WRL::ComPtr<IXAudio2> m_xAudio2;
+ mastering_voice_ptr m_masterVoice;
+ src_voice_ptr m_sourceVoice;
+ int m_sample_rate;
+ int m_audio_latency;
+ DWORD m_sample_bytes;
+ std::unique_ptr<BYTE[]> m_buffer;
+ DWORD m_buffer_size;
+ DWORD m_buffer_count;
+ DWORD m_writepos;
+ std::mutex m_buffer_lock;
+ HANDLE m_hEventBufferCompleted;
+ HANDLE m_hEventDataAvailable;
+ HANDLE m_hEventExiting;
+ std::thread m_audioThread;
+ std::queue<xaudio2_buffer> m_queue;
+ std::unique_ptr<bufferpool> m_buffer_pool;
+ uint32_t m_overflows;
+ uint32_t m_underflows;
+ BOOL m_in_underflow;
+ BOOL m_initialized;
+
+ OSD_DYNAMIC_API(xaudio2, "XAudio2_9.dll", "XAudio2_8.dll");
+ OSD_DYNAMIC_API_FN(xaudio2, HRESULT, WINAPI, XAudio2Create, IXAudio2 **, uint32_t, XAUDIO2_PROCESSOR);
};
//============================================================
@@ -268,14 +273,9 @@ bool sound_xaudio2::probe()
// init
//============================================================
-int sound_xaudio2::init(osd_options const &options)
+int sound_xaudio2::init(osd_interface &osd, osd_options const &options)
{
- HRESULT result;
- WAVEFORMATEX format = {0};
- auto init_start = std::chrono::system_clock::now();
- std::chrono::milliseconds init_time;
-
- CoInitializeEx(nullptr, COINIT_MULTITHREADED);
+ auto const init_start = std::chrono::system_clock::now();
// Make sure our XAudio2Create entrypoint is bound
if (!OSD_DYNAMIC_API_TEST(XAudio2Create))
@@ -284,6 +284,13 @@ int sound_xaudio2::init(osd_options const &options)
return 1;
}
+ HRESULT result;
+ std::chrono::milliseconds init_time;
+ WAVEFORMATEX format = { 0 };
+
+ m_sample_rate = options.sample_rate();
+ m_audio_latency = options.audio_latency();
+
// Create the IXAudio2 object
HR_GOERR(OSD_DYNAMIC_CALL(XAudio2Create, m_xAudio2.GetAddressOf(), 0, XAUDIO2_DEFAULT_PROCESSOR));
@@ -291,7 +298,7 @@ int sound_xaudio2::init(osd_options const &options)
format.wBitsPerSample = 16;
format.wFormatTag = WAVE_FORMAT_PCM;
format.nChannels = 2;
- format.nSamplesPerSec = sample_rate();
+ format.nSamplesPerSec = m_sample_rate;
format.nBlockAlign = format.wBitsPerSample * format.nChannels / 8;
format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
@@ -310,10 +317,10 @@ int sound_xaudio2::init(osd_options const &options)
HR_GOERR(m_sourceVoice->Start());
// Start the thread listening
- m_audioThread = std::thread([](sound_xaudio2* self) { self->process_audio(); }, this);
+ m_audioThread = std::thread([] (sound_xaudio2 *self) { self->process_audio(); }, this);
init_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - init_start);
- osd_printf_verbose("Sound: XAudio2 initialized. %d ms.\n", static_cast<int>(init_time.count()));
+ osd_printf_verbose("Sound: XAudio2 initialized. %d ms.\n", init_time.count());
m_initialized = TRUE;
return 0;
@@ -368,15 +375,15 @@ void sound_xaudio2::exit()
}
//============================================================
-// update_audio_stream
+// stream_sink_update
//============================================================
-void sound_xaudio2::update_audio_stream(
- bool is_throttled,
+void sound_xaudio2::stream_sink_update(
+ uint32_t,
int16_t const *buffer,
int samples_this_frame)
{
- if (!m_initialized || sample_rate() == 0 || !m_buffer)
+ if (!m_initialized || m_sample_rate == 0 || !m_buffer)
return;
uint32_t const bytes_this_frame = samples_this_frame * m_sample_bytes;
@@ -406,37 +413,11 @@ void sound_xaudio2::update_audio_stream(
}
//============================================================
-// set_mastervolume
-//============================================================
-
-void sound_xaudio2::set_mastervolume(int attenuation)
-{
- if (!m_initialized)
- return;
-
- assert(m_sourceVoice);
-
- HRESULT result;
-
- // clamp the attenuation to 0-32 range
- attenuation = std::max(std::min(attenuation, 0), -32);
-
- // Ranges from 1.0 to XAUDIO2_MAX_VOLUME_LEVEL indicate additional gain
- // Ranges from 0 to 1.0 indicate a reduced volume level
- // 0 indicates silence
- // We only support a reduction from 1.0, so we generate values in the range 0.0 to 1.0
- float scaledVolume = (32.0f + attenuation) / 32.0f;
-
- // set the master volume
- HR_RETV(m_sourceVoice->SetVolume(scaledVolume));
-}
-
-//============================================================
// IXAudio2VoiceCallback::OnBufferEnd
//============================================================
// The XAudio2 voice callback triggered when a buffer finishes playing
-void sound_xaudio2::OnBufferEnd(void *pBufferContext)
+void sound_xaudio2::OnBufferEnd(void *pBufferContext) noexcept
{
BYTE* completed_buffer = static_cast<BYTE*>(pBufferContext);
if (completed_buffer != nullptr)
@@ -453,7 +434,7 @@ void sound_xaudio2::OnBufferEnd(void *pBufferContext)
//============================================================
// The XAudio2 voice callback triggered on every pass
-void sound_xaudio2::OnVoiceProcessingPassStart(uint32_t bytes_required)
+void sound_xaudio2::OnVoiceProcessingPassStart(uint32_t bytes_required) noexcept
{
if (bytes_required == 0)
{
@@ -479,7 +460,8 @@ void sound_xaudio2::create_buffers(const WAVEFORMATEX &format)
{
// Compute the buffer size
// buffer size is equal to the bytes we need to hold in memory per X tenths of a second where X is audio_latency
- float audio_latency_in_seconds = m_audio_latency / 10.0f;
+ int audio_latency = std::max(m_audio_latency, 1);
+ float audio_latency_in_seconds = audio_latency / 10.0f;
uint32_t format_bytes_per_second = format.nSamplesPerSec * format.nBlockAlign;
uint32_t total_buffer_size = format_bytes_per_second * audio_latency_in_seconds * RESAMPLE_TOLERANCE;
@@ -526,7 +508,7 @@ HRESULT sound_xaudio2::create_voices(const WAVEFORMATEX &format)
m_xAudio2->CreateMasteringVoice(
&temp_master_voice,
format.nChannels,
- sample_rate()));
+ m_sample_rate));
m_masterVoice = mastering_voice_ptr(temp_master_voice);
@@ -693,9 +675,15 @@ void sound_xaudio2::roll_buffer()
}
}
+} // anonymous namespace
+
+} // namespace osd
+
#else
-MODULE_NOT_SUPPORTED(sound_xaudio2, OSD_SOUND_PROVIDER, "xaudio2")
+
+namespace osd { namespace { MODULE_NOT_SUPPORTED(sound_xaudio2, OSD_SOUND_PROVIDER, "xaudio2") } }
+
#endif
-MODULE_DEFINITION(SOUND_XAUDIO2, sound_xaudio2)
+MODULE_DEFINITION(SOUND_XAUDIO2, osd::sound_xaudio2)
diff --git a/src/osd/osdcomm.h b/src/osd/osdcomm.h
index eb600e65360..516dd3e681a 100644
--- a/src/osd/osdcomm.h
+++ b/src/osd/osdcomm.h
@@ -8,15 +8,15 @@
fundamental integral types as well as compiler-specific tweaks.
***************************************************************************/
-
-#pragma once
-
#ifndef MAME_OSD_OSDCOMM_H
#define MAME_OSD_OSDCOMM_H
-#include <stdio.h>
-#include <string.h>
+#pragma once
+
#include <cstdint>
+#include <cstdio>
+#include <cstring>
+
#include <type_traits>
@@ -24,15 +24,14 @@
COMPILER-SPECIFIC NASTINESS
***************************************************************************/
-/* The Win32 port requires this constant for variable arg routines. */
+// The Win32 port requires this constant for variable arg routines.
#ifndef CLIB_DECL
#define CLIB_DECL
#endif
-/* Some optimizations/warnings cleanups for GCC */
+// Some optimizations/warnings cleanups for GCC
#if defined(__GNUC__)
-#define ATTR_UNUSED __attribute__((__unused__))
#define ATTR_PRINTF(x,y) __attribute__((format(printf, x, y)))
#define ATTR_CONST __attribute__((const))
#define ATTR_FORCE_INLINE __attribute__((always_inline))
@@ -42,7 +41,6 @@
#define EXPECTED(exp) __builtin_expect(!!(exp), 1)
#define RESTRICT __restrict__
#else
-#define ATTR_UNUSED
#define ATTR_PRINTF(x,y)
#define ATTR_CONST
#define ATTR_FORCE_INLINE __forceinline
@@ -73,28 +71,12 @@ using s64 = std::int64_t;
} // namespace OSD
+
/***************************************************************************
FUNDAMENTAL MACROS
***************************************************************************/
-/* Concatenate/extract 32-bit halves of 64-bit values */
-constexpr uint64_t concat_64(uint32_t hi, uint32_t lo) { return (uint64_t(hi) << 32) | uint32_t(lo); }
-constexpr uint32_t extract_64hi(uint64_t val) { return uint32_t(val >> 32); }
-constexpr uint32_t extract_64lo(uint64_t val) { return uint32_t(val); }
-
-// Highly useful template for compile-time knowledge of an array size
-template <typename T, size_t N> constexpr size_t ARRAY_LENGTH(T (&)[N]) { return N;}
-
-// For declaring an array of the same dimensions as another array (including multi-dimensional arrays)
-template <typename T, typename U> struct equivalent_array_or_type { typedef T type; };
-template <typename T, typename U, std::size_t N> struct equivalent_array_or_type<T, U[N]> { typedef typename equivalent_array_or_type<T, U>::type type[N]; };
-template <typename T, typename U> using equivalent_array_or_type_t = typename equivalent_array_or_type<T, U>::type;
-template <typename T, typename U> struct equivalent_array { };
-template <typename T, typename U, std::size_t N> struct equivalent_array<T, U[N]> { typedef equivalent_array_or_type_t<T, U> type[N]; };
-template <typename T, typename U> using equivalent_array_t = typename equivalent_array<T, U>::type;
-#define EQUIVALENT_ARRAY(a, T) equivalent_array_t<T, std::remove_reference_t<decltype(a)> >
-
-/* Macros for normalizing data into big or little endian formats */
+// Macros for normalizing data into big or little endian formats
constexpr uint16_t swapendian_int16(uint16_t val) { return (val << 8) | (val >> 8); }
constexpr uint32_t swapendian_int32_partial16(uint32_t val) { return ((val << 8) & 0xFF00FF00U) | ((val >> 8) & 0x00FF00FFU); }
@@ -118,7 +100,7 @@ constexpr uint64_t big_endianize_int64(uint64_t x) { return x; }
constexpr uint16_t little_endianize_int16(uint16_t x) { return swapendian_int16(x); }
constexpr uint32_t little_endianize_int32(uint32_t x) { return swapendian_int32(x); }
constexpr uint64_t little_endianize_int64(uint64_t x) { return swapendian_int64(x); }
-#endif /* LSB_FIRST */
+#endif // LSB_FIRST
#ifdef _MSC_VER
using ssize_t = std::make_signed_t<size_t>;
@@ -130,4 +112,25 @@ using ssize_t = std::make_signed_t<size_t>;
#endif
#endif
-#endif /* MAME_OSD_OSDCOMM_H */
+
+// macro for defining a copy constructor and assignment operator to prevent copying
+#define DISABLE_COPYING(TYPE) \
+ TYPE(const TYPE &) = delete; \
+ TYPE &operator=(const TYPE &) = delete
+
+// macro for declaring enumeration operators that increment/decrement like plain old C
+#define DECLARE_ENUM_INCDEC_OPERATORS(TYPE) \
+inline TYPE &operator++(TYPE &value) { return value = TYPE(std::underlying_type_t<TYPE>(value) + 1); } \
+inline TYPE &operator--(TYPE &value) { return value = TYPE(std::underlying_type_t<TYPE>(value) - 1); } \
+inline TYPE operator++(TYPE &value, int) { TYPE const old(value); ++value; return old; } \
+inline TYPE operator--(TYPE &value, int) { TYPE const old(value); --value; return old; }
+
+// macro for declaring bitwise operators for an enumerated type
+#define DECLARE_ENUM_BITWISE_OPERATORS(TYPE) \
+constexpr TYPE operator~(TYPE value) { return TYPE(~std::underlying_type_t<TYPE>(value)); } \
+constexpr TYPE operator&(TYPE a, TYPE b) { return TYPE(std::underlying_type_t<TYPE>(a) & std::underlying_type_t<TYPE>(b)); } \
+constexpr TYPE operator|(TYPE a, TYPE b) { return TYPE(std::underlying_type_t<TYPE>(a) | std::underlying_type_t<TYPE>(b)); } \
+inline TYPE &operator&=(TYPE &a, TYPE b) { return a = a & b; } \
+inline TYPE &operator|=(TYPE &a, TYPE b) { return a = a | b; }
+
+#endif // MAME_OSD_OSDCOMM_H
diff --git a/src/osd/osdcore.cpp b/src/osd/osdcore.cpp
index 51032555438..84b3dde3b05 100644
--- a/src/osd/osdcore.cpp
+++ b/src/osd/osdcore.cpp
@@ -6,12 +6,12 @@
#include <chrono>
#if defined(SDLMAME_ANDROID)
-#include <SDL2/SDL.h>
+#include <android/log.h>
#endif
#ifdef _WIN32
#include <windows.h>
-#include <stdio.h>
+#include <cstdio>
#include <shellapi.h>
#include "strconv.h"
#endif
@@ -26,7 +26,7 @@ static int m_ptr = -1;
void osd_output::push(osd_output *delegate)
{
- if (m_ptr < MAXSTACK)
+ if (m_ptr < MAXSTACK - 1)
{
delegate->m_chain = (m_ptr >= 0 ? m_stack[m_ptr] : nullptr);
m_ptr++;
@@ -37,7 +37,7 @@ void osd_output::push(osd_output *delegate)
void osd_output::pop(osd_output *delegate)
{
int f = -1;
- for (int i=0; i<=m_ptr; i++)
+ for (int i = 0; i <= m_ptr; i++)
if (m_stack[i] == delegate)
{
f = i;
@@ -59,129 +59,93 @@ void osd_output::pop(osd_output *delegate)
***************************************************************************/
/*-------------------------------------------------
- osd_printf_error - output an error to the
+ osd_vprintf_error - output an error to the
appropriate callback
-------------------------------------------------*/
-void CLIB_DECL osd_printf_error(const char *format, ...)
+void osd_vprintf_error(util::format_argument_pack<char> const &args)
{
- va_list argptr;
-
- /* do the output */
- va_start(argptr, format);
#if defined(SDLMAME_ANDROID)
- SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_ERROR, format, argptr);
+ __android_log_write(ANDROID_LOG_ERROR, "MAME", util::string_format(args).c_str());
#else
- if (m_ptr >= 0) m_stack[m_ptr]->output_callback(OSD_OUTPUT_CHANNEL_ERROR, format, argptr);
+ if (m_ptr >= 0) m_stack[m_ptr]->output_callback(OSD_OUTPUT_CHANNEL_ERROR, args);
#endif
- va_end(argptr);
}
/*-------------------------------------------------
- osd_printf_warning - output a warning to the
+ osd_vprintf_warning - output a warning to the
appropriate callback
-------------------------------------------------*/
-void CLIB_DECL osd_printf_warning(const char *format, ...)
+void osd_vprintf_warning(util::format_argument_pack<char> const &args)
{
- va_list argptr;
-
- /* do the output */
- va_start(argptr, format);
#if defined(SDLMAME_ANDROID)
- SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_ERROR, format, argptr);
+ __android_log_write(ANDROID_LOG_WARN, "MAME", util::string_format(args).c_str());
#else
- if (m_ptr >= 0) m_stack[m_ptr]->output_callback(OSD_OUTPUT_CHANNEL_WARNING, format, argptr);
+ if (m_ptr >= 0) m_stack[m_ptr]->output_callback(OSD_OUTPUT_CHANNEL_WARNING, args);
#endif
- va_end(argptr);
}
/*-------------------------------------------------
- osd_printf_info - output info text to the
+ osd_vprintf_info - output info text to the
appropriate callback
-------------------------------------------------*/
-void CLIB_DECL osd_printf_info(const char *format, ...)
+void osd_vprintf_info(util::format_argument_pack<char> const &args)
{
- va_list argptr;
-
- /* do the output */
- va_start(argptr, format);
#if defined(SDLMAME_ANDROID)
- SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, format, argptr);
+ __android_log_write(ANDROID_LOG_INFO, "MAME", util::string_format(args).c_str());
#else
- if (m_ptr >= 0) m_stack[m_ptr]->output_callback(OSD_OUTPUT_CHANNEL_INFO, format, argptr);
+ if (m_ptr >= 0) m_stack[m_ptr]->output_callback(OSD_OUTPUT_CHANNEL_INFO, args);
#endif
- va_end(argptr);
}
/*-------------------------------------------------
- osd_printf_verbose - output verbose text to
+ osd_vprintf_verbose - output verbose text to
the appropriate callback
-------------------------------------------------*/
-void CLIB_DECL osd_printf_verbose(const char *format, ...)
+void osd_vprintf_verbose(util::format_argument_pack<char> const &args)
{
- va_list argptr;
-
- /* do the output */
- va_start(argptr, format);
#if defined(SDLMAME_ANDROID)
- SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_VERBOSE, format, argptr);
+ __android_log_write( ANDROID_LOG_VERBOSE, "MAME", util::string_format(args).c_str());
#else
- if (m_ptr >= 0) m_stack[m_ptr]->output_callback(OSD_OUTPUT_CHANNEL_VERBOSE, format, argptr);
+ if (m_ptr >= 0) m_stack[m_ptr]->output_callback(OSD_OUTPUT_CHANNEL_VERBOSE, args);
#endif
- va_end(argptr);
}
/*-------------------------------------------------
- osd_printf_debug - output debug text to the
+ osd_vprintf_debug - output debug text to the
appropriate callback
-------------------------------------------------*/
-void CLIB_DECL osd_printf_debug(const char *format, ...)
+void osd_vprintf_debug(util::format_argument_pack<char> const &args)
{
- va_list argptr;
-
- /* do the output */
- va_start(argptr, format);
#if defined(SDLMAME_ANDROID)
- SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, format, argptr);
+ __android_log_write(ANDROID_LOG_DEBUG, "MAME", util::string_format(args).c_str());
#else
- if (m_ptr >= 0) m_stack[m_ptr]->output_callback(OSD_OUTPUT_CHANNEL_DEBUG, format, argptr);
+ if (m_ptr >= 0) m_stack[m_ptr]->output_callback(OSD_OUTPUT_CHANNEL_DEBUG, args);
#endif
- va_end(argptr);
}
-/*-------------------------------------------------
- osd_printf_log - output log text to the
- appropriate callback
--------------------------------------------------*/
-
-#ifdef UNUSED_FUNCTION
-void CLIB_DECL osd_printf_log(const char *format, ...)
-{
- va_list argptr;
-
- /* do the output */
- va_start(argptr, format);
- output_cb[OSD_OUTPUT_CHANNEL_LOG])(format, argptr);
- va_end(argptr);
-}
-#endif
-
//============================================================
// osd_ticks
//============================================================
-osd_ticks_t osd_ticks(void)
+osd_ticks_t osd_ticks() noexcept
{
+#ifdef _WIN32
+ LARGE_INTEGER val;
+ QueryPerformanceCounter(&val);
+ return val.QuadPart;
+#else
return std::chrono::high_resolution_clock::now().time_since_epoch().count();
+#endif
}
@@ -189,18 +153,24 @@ osd_ticks_t osd_ticks(void)
// osd_ticks_per_second
//============================================================
-osd_ticks_t osd_ticks_per_second(void)
+osd_ticks_t osd_ticks_per_second() noexcept
{
+#ifdef _WIN32
+ LARGE_INTEGER val;
+ QueryPerformanceFrequency(&val);
+ return val.QuadPart;
+#else
return std::chrono::high_resolution_clock::period::den / std::chrono::high_resolution_clock::period::num;
+#endif
}
//============================================================
// osd_sleep
//============================================================
-void osd_sleep(osd_ticks_t duration)
+void osd_sleep(osd_ticks_t duration) noexcept
{
-#ifdef WIN32
+#ifdef _WIN32
// sleep_for appears to oversleep on Windows with gcc 8
Sleep(duration / (osd_ticks_per_second() / 1000));
#else
@@ -220,7 +190,7 @@ void osd_sleep(osd_ticks_t duration)
std::vector<std::string> osd_get_command_line(int argc, char *argv[])
{
std::vector<std::string> results;
-#ifdef WIN32
+#ifdef _WIN32
{
// Get the command line from Windows
int count;
@@ -236,7 +206,7 @@ std::vector<std::string> osd_get_command_line(int argc, char *argv[])
LocalFree(wide_args);
}
-#else // !WIN32
+#else // !_WIN32
{
// for non Windows platforms, we are assuming that arguments are
// already UTF-8; we just need to convert to std::vector<std::string>
@@ -244,6 +214,6 @@ std::vector<std::string> osd_get_command_line(int argc, char *argv[])
for (int i = 0; i < argc; i++)
results.emplace_back(argv[i]);
}
-#endif // WIN32
+#endif // _WIN32
return results;
}
diff --git a/src/osd/osdcore.h b/src/osd/osdcore.h
index 22179f9da45..b3dc2099913 100644
--- a/src/osd/osdcore.h
+++ b/src/osd/osdcore.h
@@ -1,284 +1,42 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
-/***************************************************************************
-
- osdcore.h
-
- Core OS-dependent code interface.
-
-****************************************************************************
-
- The prototypes in this file describe the interfaces that the MAME core
- and various tools rely upon to interact with the outside world. They are
- broken out into several categories.
-
-***************************************************************************/
-
-#pragma once
-
+/// \file
+/// \brief Core OS-dependent code interface
+///
+/// The prototypes in this file describe the interfaces that the MAME
+/// core and various tools rely on to interact with the outside world.
+/// They are broken out into several categories.
#ifndef MAME_OSD_OSDCORE_H
#define MAME_OSD_OSDCORE_H
+#pragma once
+
#include "osdcomm.h"
-#include <chrono>
-#include <cstdarg>
+#include "strformat.h"
+
#include <cstdint>
-#include <memory>
+#include <iosfwd>
#include <string>
+#include <string_view>
+#include <system_error>
+#include <utility>
#include <vector>
-/***************************************************************************
- FILE I/O INTERFACES
-***************************************************************************/
-
-/* Make sure we have a path separator (default to /) */
-#ifndef PATH_SEPARATOR
-#if defined(_WIN32)
-#define PATH_SEPARATOR "\\"
-#else
-#define PATH_SEPARATOR "/"
-#endif
-#endif
-
-/* flags controlling file access */
-#define OPEN_FLAG_READ 0x0001 /* open for read */
-#define OPEN_FLAG_WRITE 0x0002 /* open for write */
-#define OPEN_FLAG_CREATE 0x0004 /* create & truncate file */
-#define OPEN_FLAG_CREATE_PATHS 0x0008 /* create paths as necessary */
-#define OPEN_FLAG_NO_PRELOAD 0x0010 /* do not decompress on open */
-
-// osd_file is an interface which represents an open file/PTY/socket
-class osd_file
-{
-public:
- // error codes returned by routines below
- enum class error
- {
- NONE,
- FAILURE,
- OUT_OF_MEMORY,
- NOT_FOUND,
- ACCESS_DENIED,
- ALREADY_OPEN,
- TOO_MANY_FILES,
- INVALID_DATA,
- INVALID_ACCESS
- };
-
- typedef std::unique_ptr<osd_file> ptr;
-
-
- /*-----------------------------------------------------------------------------
- osd_file::open: open a new file.
-
- Parameters:
-
- path - path to the file to open
-
- openflags - some combination of:
-
- OPEN_FLAG_READ - open the file for read access
- OPEN_FLAG_WRITE - open the file for write access
- OPEN_FLAG_CREATE - create/truncate the file when opening
- OPEN_FLAG_CREATE_PATHS - specifies that non-existant paths
- should be created if necessary
-
- file - reference to an osd_file::ptr to receive the newly-opened file
- handle; this is only valid if the function returns FILERR_NONE
-
- filesize - reference to a uint64_t to receive the size of the opened
- file; this is only valid if the function returns FILERR_NONE
-
- Return value:
-
- a file_error describing any error that occurred while opening
- the file, or FILERR_NONE if no error occurred
-
- Notes:
-
- This function is called by core_fopen and several other places in
- the core to access files. These functions will construct paths by
- concatenating various search paths held in the options.c options
- database with partial paths specified by the core. The core assumes
- that the path separator is the first character of the string
- PATH_SEPARATOR, but does not interpret any path separators in the
- search paths, so if you use a different path separator in a search
- path, you may get a mixture of PATH_SEPARATORs (from the core) and
- alternate path separators (specified by users and placed into the
- options database).
- -----------------------------------------------------------------------------*/
- static error open(std::string const &path, std::uint32_t openflags, ptr &file, std::uint64_t &filesize);
-
-
- /*-----------------------------------------------------------------------------
- osd_file::openpty: create a new PTY pair
-
- Parameters:
-
- file - reference to an osd_file::ptr to receive the handle of the master
- side of the newly-created PTY; this is only valid if the function
- returns FILERR_NONE
-
- name - reference to string where slave filename will be stored
-
- Return value:
-
- a file_error describing any error that occurred while creating the
- PTY, or FILERR_NONE if no error occurred
- -----------------------------------------------------------------------------*/
- static error openpty(ptr &file, std::string &name);
-
-
- /*-----------------------------------------------------------------------------
- osd_file::~osd_file: close an open file
- -----------------------------------------------------------------------------*/
- virtual ~osd_file() { }
-
-
- /*-----------------------------------------------------------------------------
- osd_file::read: read from an open file
-
- Parameters:
-
- buffer - pointer to memory that will receive the data read
-
- offset - offset within the file to read from
-
- length - number of bytes to read from the file
-
- actual - reference to a uint32_t to receive the number of bytes actually
- read during the operation; valid only if the function returns
- FILERR_NONE
-
- Return value:
-
- a file_error describing any error that occurred while reading
- from the file, or FILERR_NONE if no error occurred
- -----------------------------------------------------------------------------*/
- virtual error read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) = 0;
-
-
- /*-----------------------------------------------------------------------------
- osd_file::write: write to an open file
-
- Parameters:
-
- buffer - pointer to memory that contains the data to write
-
- offset - offset within the file to write to
-
- length - number of bytes to write to the file
-
- actual - reference to a uint32_t to receive the number of bytes actually
- written during the operation; valid only if the function returns
- FILERR_NONE
-
- Return value:
-
- a file_error describing any error that occurred while writing to
- the file, or FILERR_NONE if no error occurred
- -----------------------------------------------------------------------------*/
- virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) = 0;
-
-
- /*-----------------------------------------------------------------------------
- osd_file::truncate: change the size of an open file
-
- Parameters:
-
-. offset - future size of the file
-
- Return value:
-
- a file_error describing any error that occurred while writing to
- the file, or FILERR_NONE if no error occurred
- -----------------------------------------------------------------------------*/
- virtual error truncate(std::uint64_t offset) = 0;
-
-
- /*-----------------------------------------------------------------------------
- osd_file::flush: flush file buffers
-
- Parameters:
-
- file - handle to a file previously opened via osd_open
-
- Return value:
-
- a file_error describing any error that occurred while flushing file
- buffers, or FILERR_NONE if no error occurred
- -----------------------------------------------------------------------------*/
- virtual error flush() = 0;
-
-
- /*-----------------------------------------------------------------------------
- osd_file::remove: deletes a file
-
- Parameters:
-
- filename - path to file to delete
-
- Return value:
-
- a file_error describing any error that occurred while deleting
- the file, or FILERR_NONE if no error occurred
- -----------------------------------------------------------------------------*/
- static error remove(std::string const &filename);
-};
-
-
-
-/*-----------------------------------------------------------------------------
- osd_getenv: return pointer to environment variable
-
- Parameters:
-
- name - name of environment variable
-
- Return value:
-
- pointer to value
------------------------------------------------------------------------------*/
+/// \brief Get environment variable value
+///
+/// \param [in] name Name of the environment variable as a
+/// NUL-terminated string.
+/// \return Pointer to environment variable value as a NUL-terminated
+/// string if found, or nullptr if not found.
const char *osd_getenv(const char *name);
-/*-----------------------------------------------------------------------------
- osd_getpid: gets process id
-
- Return value:
-
- process id
------------------------------------------------------------------------------*/
-int osd_getpid();
-
-/*-----------------------------------------------------------------------------
- osd_get_physical_drive_geometry: if the given path points to a physical
- drive, return the geometry of that drive
-
- Parameters:
-
- filename - pointer to a path which might describe a physical drive
-
- cylinders - pointer to a uint32_t to receive the number of cylinders
- of the physical drive
-
- heads - pointer to a uint32_t to receive the number of heads per
- cylinder of the physical drive
-
- sectors - pointer to a uint32_t to receive the number of sectors per
- cylinder of the physical drive
- bps - pointer to a uint32_t to receive the number of bytes per sector
- of the physical drive
-
- Return value:
-
- true if the filename points to a physical drive and if the values
- pointed to by cylinders, heads, sectors, and bps are valid; false in
- any other case
------------------------------------------------------------------------------*/
-bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders, uint32_t *heads, uint32_t *sectors, uint32_t *bps);
+/// \brief Get current process ID
+///
+/// \return The process ID of the current process.
+int osd_getpid() noexcept;
/*-----------------------------------------------------------------------------
@@ -302,115 +60,6 @@ bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders,
int osd_uchar_from_osdchar(char32_t *uchar, const char *osdchar, size_t count);
-/*-----------------------------------------------------------------------------
- osd_is_valid_filename_char: is the given character legal for filenames?
-
- Parameters:
-
- uchar - the character to check
-
- Return value:
-
- Whether this character is legal in a filename
------------------------------------------------------------------------------*/
-
-bool osd_is_valid_filename_char(char32_t uchar);
-
-
-/*-----------------------------------------------------------------------------
- osd_is_valid_filepath_char: is the given character legal for paths?
-
- Parameters:
-
- uchar - the character to check
-
- Return value:
-
- Whether this character is legal in a file path
------------------------------------------------------------------------------*/
-
-bool osd_is_valid_filepath_char(char32_t uchar);
-
-
-/***************************************************************************
- DIRECTORY INTERFACES
-***************************************************************************/
-
-namespace osd
-{
- // directory is an opaque type which represents an open directory
- class directory
- {
- public:
- typedef std::unique_ptr<directory> ptr;
-
- // osd::directory::entry contains basic information about a file when iterating through
- // a directory
- class entry
- {
- public:
- enum class entry_type
- {
- NONE,
- FILE,
- DIR,
- OTHER
- };
-
- const char * name; // name of the entry
- entry_type type; // type of the entry
- std::uint64_t size; // size of the entry
- std::chrono::system_clock::time_point last_modified; // last modified time
- };
-
- // -----------------------------------------------------------------------------
- // osd::directory::open: open a directory for iteration
- //
- // Parameters:
- //
- // dirname - path to the directory in question
- //
- // Return value:
- //
- // upon success, this function should return an directory pointer
- // which contains opaque data necessary to traverse the directory; on
- // failure, this function should return nullptr
- // -----------------------------------------------------------------------------
- static ptr open(std::string const &dirname);
-
- // -----------------------------------------------------------------------------
- // osd::directory::~directory: close an open directory
- // -----------------------------------------------------------------------------
- virtual ~directory() { }
-
- // -----------------------------------------------------------------------------
- // osd::directory::read: return information about the next entry in the directory
- //
- // Return value:
- //
- // a constant pointer to an entry representing the current item
- // in the directory, or nullptr, indicating that no more entries are
- // present
- // -----------------------------------------------------------------------------
- virtual const entry *read() = 0;
- };
-};
-
-
-/*-----------------------------------------------------------------------------
- osd_is_absolute_path: returns whether the specified path is absolute
-
- Parameters:
-
- path - the path in question
-
- Return value:
-
- non-zero if the path is absolute, zero otherwise
------------------------------------------------------------------------------*/
-bool osd_is_absolute_path(const std::string &path);
-
-
/***************************************************************************
TIMING INTERFACES
@@ -438,7 +87,7 @@ typedef uint64_t osd_ticks_t;
accurate. It is ok if this call is not ultra-fast, since it is
primarily used for once/frame synchronization.
-----------------------------------------------------------------------------*/
-osd_ticks_t osd_ticks(void);
+osd_ticks_t osd_ticks() noexcept;
/*-----------------------------------------------------------------------------
@@ -453,7 +102,7 @@ osd_ticks_t osd_ticks(void);
an osd_ticks_t value which represents the number of ticks per
second
-----------------------------------------------------------------------------*/
-osd_ticks_t osd_ticks_per_second(void);
+osd_ticks_t osd_ticks_per_second() noexcept;
/*-----------------------------------------------------------------------------
@@ -478,7 +127,9 @@ osd_ticks_t osd_ticks_per_second(void);
sleep occurs for, the OSD layer should strive to sleep for less time
than specified rather than sleeping too long.
-----------------------------------------------------------------------------*/
-void osd_sleep(osd_ticks_t duration);
+void osd_sleep(osd_ticks_t duration) noexcept;
+
+
/***************************************************************************
WORK ITEM INTERFACES
@@ -693,171 +344,37 @@ void osd_work_item_release(osd_work_item *item);
MISCELLANEOUS INTERFACES
***************************************************************************/
-/*-----------------------------------------------------------------------------
- osd_alloc_executable: allocate memory that can contain executable code
-
- Parameters:
-
- size - the number of bytes to allocate
-
- Return value:
-
- a pointer to the allocated memory
-
- Notes:
-
- On many systems, this call may acceptably map to malloc(). On systems
- where pages are tagged with "no execute" privileges, it may be
- necessary to perform some kind of special allocation to ensure that
- code placed into this buffer can be executed.
------------------------------------------------------------------------------*/
-void *osd_alloc_executable(size_t size);
-
-
-/*-----------------------------------------------------------------------------
- osd_free_executable: free memory allocated by osd_alloc_executable
-
- Parameters:
-
- ptr - the pointer returned from osd_alloc_executable
-
- size - the number of bytes originally requested
-
- Return value:
-
- None
------------------------------------------------------------------------------*/
-void osd_free_executable(void *ptr, size_t size);
-
-
-/*-----------------------------------------------------------------------------
- osd_break_into_debugger: break into the hosting system's debugger if one
- is attached
-
- Parameters:
-
- message - pointer to string to output to the debugger
-
- Return value:
-
- None.
-
- Notes:
-
- This function is called when an assertion or other important error
- occurs. If a debugger is attached to the current process, it should
- break into the debugger and display the given message.
------------------------------------------------------------------------------*/
+/// \brief Break into host debugger if attached
+///
+/// This function is called when a fatal error occurs. If a debugger is
+/// attached, it should break and display the specified message.
+/// \param [in] message Message to output to the debugger as a
+/// NUL-terminated string.
void osd_break_into_debugger(const char *message);
-/*-----------------------------------------------------------------------------
- osd_get_clipboard_text: retrieves text from the clipboard
------------------------------------------------------------------------------*/
-std::string osd_get_clipboard_text(void);
+/// \brief Get cache line size in bytes
+///
+/// This function gets the host CPU's level 1 cache line size in bytes.
+/// \return A pair consisting of an error condition and the cache line
+/// size in bytes if successful.
+std::pair<std::error_condition, unsigned> osd_get_cache_line_size() noexcept;
-/***************************************************************************
- DIRECTORY INTERFACES
-***************************************************************************/
-
-/*-----------------------------------------------------------------------------
- osd_stat: return a directory entry for a path
-
- Parameters:
- path - path in question
-
- Return value:
-
- an allocated pointer to an osd::directory::entry representing
- info on the path; even if the file does not exist.
-
------------------------------------------------------------------------------*/
-std::unique_ptr<osd::directory::entry> osd_stat(std::string const &path);
-
-/***************************************************************************
- PATH INTERFACES
-***************************************************************************/
-
-/*-----------------------------------------------------------------------------
- osd_get_full_path: retrieves the full path
-
- Parameters:
-
- path - the path in question
- dst - reference to receive new path
-
- Return value:
-
- file error
-
------------------------------------------------------------------------------*/
-osd_file::error osd_get_full_path(std::string &dst, std::string const &path);
-
-
-/***************************************************************************
- MIDI I/O INTERFACES
-***************************************************************************/
-
-class osd_midi_device
-{
-public:
- virtual ~osd_midi_device() { }
- // free result with osd_close_midi_channel()
- virtual bool open_input(const char *devname) = 0;
- // free result with osd_close_midi_channel()
- virtual bool open_output(const char *devname) = 0;
- virtual void close() = 0;
- virtual bool poll() = 0;
- virtual int read(uint8_t *pOut) = 0;
- virtual void write(uint8_t data) = 0;
-};
-
-//FIXME: really needed here?
-void osd_list_network_adapters(void);
/***************************************************************************
UNCATEGORIZED INTERFACES
***************************************************************************/
/*-----------------------------------------------------------------------------
- osd_get_volume_name: retrieves the volume name
-
- Parameters:
-
- idx - order number of volume
-
- Return value:
-
- pointer to volume name
-
------------------------------------------------------------------------------*/
-const char *osd_get_volume_name(int idx);
-
-/*-----------------------------------------------------------------------------
osd_subst_env: substitute environment variables with values
Parameters:
- dst - result pointer
src - source string
-----------------------------------------------------------------------------*/
-void osd_subst_env(std::string &dst,std::string const &src);
-
-/* ----- output management ----- */
-
-// output channels
-enum osd_output_channel
-{
- OSD_OUTPUT_CHANNEL_ERROR,
- OSD_OUTPUT_CHANNEL_WARNING,
- OSD_OUTPUT_CHANNEL_INFO,
- OSD_OUTPUT_CHANNEL_DEBUG,
- OSD_OUTPUT_CHANNEL_VERBOSE,
- OSD_OUTPUT_CHANNEL_LOG,
- OSD_OUTPUT_CHANNEL_COUNT
-};
+std::string osd_subst_env(std::string_view src);
class osd_gpu
{
@@ -1010,33 +527,118 @@ public:
virtual void unbind_buffer(vertex_buffer_interface *vb) = 0;
};
+
+/// \defgroup osd_printf Diagnostic output functions
+/// \{
+
+// output channels
+enum osd_output_channel
+{
+ OSD_OUTPUT_CHANNEL_ERROR,
+ OSD_OUTPUT_CHANNEL_WARNING,
+ OSD_OUTPUT_CHANNEL_INFO,
+ OSD_OUTPUT_CHANNEL_DEBUG,
+ OSD_OUTPUT_CHANNEL_VERBOSE,
+ OSD_OUTPUT_CHANNEL_LOG,
+ OSD_OUTPUT_CHANNEL_COUNT
+};
+
class osd_output
{
public:
- osd_output() : m_chain(nullptr) { }
+ osd_output() { }
virtual ~osd_output() { }
- virtual void output_callback(osd_output_channel channel, const char *msg, va_list args) = 0;
+ virtual void output_callback(osd_output_channel channel, util::format_argument_pack<char> const &args) = 0;
static void push(osd_output *delegate);
static void pop(osd_output *delegate);
+
protected:
- void chain_output(osd_output_channel channel, const char *msg, va_list args) const
+ void chain_output(osd_output_channel channel, util::format_argument_pack<char> const &args) const
{
- if (m_chain != nullptr)
- m_chain->output_callback(channel, msg, args);
+ if (m_chain)
+ m_chain->output_callback(channel, args);
}
+
private:
- osd_output *m_chain;
+ osd_output *m_chain = nullptr;
};
-/* calls to be used by the code */
-void CLIB_DECL osd_printf_error(const char *format, ...) ATTR_PRINTF(1,2);
-void CLIB_DECL osd_printf_warning(const char *format, ...) ATTR_PRINTF(1,2);
-void CLIB_DECL osd_printf_info(const char *format, ...) ATTR_PRINTF(1,2);
-void CLIB_DECL osd_printf_verbose(const char *format, ...) ATTR_PRINTF(1,2);
-void CLIB_DECL osd_printf_debug(const char *format, ...) ATTR_PRINTF(1,2);
+void osd_vprintf_error(util::format_argument_pack<char> const &args);
+void osd_vprintf_warning(util::format_argument_pack<char> const &args);
+void osd_vprintf_info(util::format_argument_pack<char> const &args);
+void osd_vprintf_verbose(util::format_argument_pack<char> const &args);
+void osd_vprintf_debug(util::format_argument_pack<char> const &args);
+
+/// \brief Print error message
+///
+/// By default, error messages are sent to standard error. The relaxed
+/// format rules used by util::string_format apply.
+/// \param [in] fmt Message format string.
+/// \param [in] args Optional message format arguments.
+/// \sa util::string_format
+template <typename Format, typename... Params> void osd_printf_error(Format &&fmt, Params &&...args)
+{
+ return osd_vprintf_error(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
+}
+
+/// \brief Print warning message
+///
+/// By default, warning messages are sent to standard error. The
+/// relaxed format rules used by util::string_format apply.
+/// \param [in] fmt Message format string.
+/// \param [in] args Optional message format arguments.
+/// \sa util::string_format
+template <typename Format, typename... Params> void osd_printf_warning(Format &&fmt, Params &&...args)
+{
+ return osd_vprintf_warning(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
+}
+
+/// \brief Print informational message
+///
+/// By default, informational messages are sent to standard output.
+/// The relaxed format rules used by util::string_format apply.
+/// \param [in] fmt Message format string.
+/// \param [in] args Optional message format arguments.
+/// \sa util::string_format
+template <typename Format, typename... Params> void osd_printf_info(Format &&fmt, Params &&...args)
+{
+ return osd_vprintf_info(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
+}
+
+/// \brief Print verbose diagnostic message
+///
+/// Verbose diagnostic messages are disabled by default. If enabled,
+/// they are sent to standard output by default. The relaxed format
+/// rules used by util::string_format apply. Note that the format
+/// string and arguments will always be evaluated, even if verbose
+/// diagnostic messages are disabled.
+/// \param [in] fmt Message format string.
+/// \param [in] args Optional message format arguments.
+/// \sa util::string_format
+template <typename Format, typename... Params> void osd_printf_verbose(Format &&fmt, Params &&...args)
+{
+ return osd_vprintf_verbose(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
+}
+
+/// \brief Print debug message
+///
+/// By default, debug messages are sent to standard output for debug
+/// builds only. The relaxed format rules used by util::string_format
+/// apply. Note that the format string and arguments will always be
+/// evaluated, even if debug messages are disabled.
+/// \param [in] fmt Message format string.
+/// \param [in] args Optional message format arguments.
+/// \sa util::string_format
+template <typename Format, typename... Params> void osd_printf_debug(Format &&fmt, Params &&...args)
+{
+ return osd_vprintf_debug(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
+}
+
+/// \}
+
// returns command line arguments as an std::vector<std::string> in UTF-8
std::vector<std::string> osd_get_command_line(int argc, char *argv[]);
diff --git a/src/osd/osdepend.h b/src/osd/osdepend.h
index 2587b93e560..0c22440009f 100644
--- a/src/osd/osdepend.h
+++ b/src/osd/osdepend.h
@@ -13,18 +13,24 @@
#pragma once
-#include "emucore.h"
-#include "osdcore.h"
-#include "unicode.h"
-#include "../frontend/mame/ui/menuitem.h"
+#include "emufwd.h"
+#include "bitmap.h"
+#include "interface/audio.h"
+#include "interface/midiport.h"
+#include "interface/nethandler.h"
+
+#include <cstdint>
#include <memory>
#include <string>
+#include <string_view>
#include <vector>
-
+#include <array>
// forward references
-class input_type_entry; // FIXME: including emu.h does not work because emu.h includes osdepend.h
+class input_type_entry;
+namespace osd { class midi_input_port; class midi_output_port; }
+namespace ui { class menu_item; }
//============================================================
@@ -60,10 +66,11 @@ public:
class osd_interface
{
public:
-
// general overridables
virtual void init(running_machine &machine) = 0;
virtual void update(bool skip_redraw) = 0;
+ virtual void input_update(bool relative_reset) = 0;
+ virtual void check_osd_inputs() = 0;
virtual void set_verbose(bool print_verbose) = 0;
// debugger overridables
@@ -71,12 +78,20 @@ public:
virtual void wait_for_debugger(device_t &device, bool firststop) = 0;
// audio overridables
- virtual void update_audio_stream(const int16_t *buffer, int samples_this_frame) = 0;
- virtual void set_mastervolume(int attenuation) = 0;
virtual bool no_sound() = 0;
+ virtual bool sound_external_per_channel_volume() = 0;
+ virtual bool sound_split_streams_per_source() = 0;
+ virtual uint32_t sound_get_generation() = 0;
+ virtual osd::audio_info sound_get_information() = 0;
+ virtual uint32_t sound_stream_sink_open(uint32_t node, std::string name, uint32_t rate) = 0;
+ virtual uint32_t sound_stream_source_open(uint32_t node, std::string name, uint32_t rate) = 0;
+ virtual void sound_stream_close(uint32_t id) = 0;
+ virtual void sound_stream_sink_update(uint32_t id, const int16_t *buffer, int samples_this_frame) = 0;
+ virtual void sound_stream_source_update(uint32_t id, int16_t *buffer, int samples_this_frame) = 0;
+ virtual void sound_stream_set_volumes(uint32_t id, const std::vector<float> &db) = 0;
// input overridables
- virtual void customize_input_type_list(simple_list<input_type_entry> &typelist) = 0;
+ virtual void customize_input_type_list(std::vector<input_type_entry> &typelist) = 0;
// video overridables
virtual void add_audio_to_recording(const int16_t *buffer, int samples_this_frame) = 0;
@@ -89,8 +104,14 @@ public:
// command option overrides
virtual bool execute_command(const char *command) = 0;
- // midi interface
- virtual osd_midi_device *create_midi_device() = 0;
+ // MIDI interface
+ virtual std::unique_ptr<osd::midi_input_port> create_midi_input(std::string_view name) = 0;
+ virtual std::unique_ptr<osd::midi_output_port> create_midi_output(std::string_view name) = 0;
+ virtual std::vector<osd::midi_port_info> list_midi_ports() = 0;
+
+ // network interface
+ virtual std::unique_ptr<osd::network_device> open_network_device(int id, osd::network_handler &handler) = 0;
+ virtual std::vector<osd::network_device_info> list_network_devices() = 0;
protected:
virtual ~osd_interface() { }
diff --git a/src/osd/osdfile.h b/src/osd/osdfile.h
new file mode 100644
index 00000000000..bc3efbde805
--- /dev/null
+++ b/src/osd/osdfile.h
@@ -0,0 +1,287 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/// \file
+/// \brief Core OS-dependent file interface
+///
+/// The prototypes in this file describe the interfaces that the MAME
+/// core and various tools rely on to interact with the outside world.
+/// They are broken out into several categories.
+
+#ifndef MAME_OSD_OSDFILE_H
+#define MAME_OSD_OSDFILE_H
+
+#pragma once
+
+#include <chrono>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <vector>
+
+
+/***************************************************************************
+ FILE I/O INTERFACES
+***************************************************************************/
+
+/* Make sure we have a path separator (default to /) */
+#ifndef PATH_SEPARATOR
+#if defined(_WIN32)
+#define PATH_SEPARATOR "\\"
+#else
+#define PATH_SEPARATOR "/"
+#endif
+#endif
+
+/// \defgroup openflags File open flags
+/// \{
+
+/// Open file for reading.
+constexpr uint32_t OPEN_FLAG_READ = 0x0001;
+
+/// Open file for writing.
+constexpr uint32_t OPEN_FLAG_WRITE = 0x0002;
+
+/// Create the file, or truncate it if it exists.
+constexpr uint32_t OPEN_FLAG_CREATE = 0x0004;
+
+/// Create non-existent directories in the path.
+constexpr uint32_t OPEN_FLAG_CREATE_PATHS = 0x0008;
+
+/// Do not decompress into memory on open.
+constexpr uint32_t OPEN_FLAG_NO_PRELOAD = 0x0010;
+
+/// \}
+
+
+/// \brief Interface to file-like resources
+///
+/// This interface is used to access file-like and stream-like
+/// resources. Examples include plain files, TCP socket, named pipes,
+/// pseudo-terminals, and compressed archive members.
+class osd_file
+{
+public:
+ /// \brief Smart pointer to a file handle
+ typedef std::unique_ptr<osd_file> ptr;
+
+ /// \brief Open a new file handle
+ ///
+ /// This function is called by core_fopen and several other places
+ /// in the core to access files. These functions will construct
+ /// paths by concatenating various search paths held in the
+ /// options.c options database with partial paths specified by the
+ /// core. The core assumes that the path separator is the first
+ /// character of the string PATH_SEPARATOR, but does not interpret
+ /// any path separators in the search paths, so if you use a
+ /// different path separator in a search path, you may get a mixture
+ /// of PATH_SEPARATORs (from the core) and alternate path separators
+ /// (specified by users and placed into the options database).
+ /// \param [in] path Path to the file to open.
+ /// \param [in] openflags Combination of #OPEN_FLAG_READ,
+ /// #OPEN_FLAG_WRITE, #OPEN_FLAG_CREATE and
+ /// #OPEN_FLAG_CREATE_PATHS specifying the requested access mode
+ /// and open behaviour.
+ /// \param [out] file Receives the file handle if the operation
+ /// succeeds. Not valid if the operation fails.
+ /// \param [out] filesize Receives the size of the opened file if
+ /// the operation succeeded. Not valid if the operation failed.
+ /// Will be zero for stream-like objects (e.g. TCP sockets or
+ /// named pipes).
+ /// \return Result of the operation.
+ static std::error_condition open(std::string const &path, std::uint32_t openflags, ptr &file, std::uint64_t &filesize) noexcept;
+
+ /// \brief Create a new pseudo-terminal (PTY) pair
+ ///
+ /// \param [out] file Receives the handle of the master side of the
+ /// pseudo-terminal if the operation succeeds. Not valid if the
+ /// operation fails.
+ /// \param [out] name Receives the name of the slave side of the
+ /// pseudo-terminal if the operation succeeds. Not valid if the
+ /// operation fails.
+ /// \return Result of the operation.
+ static std::error_condition openpty(ptr &file, std::string &name) noexcept;
+
+ /// \brief Close an open file
+ virtual ~osd_file() { }
+
+ /// \brief Read from an open file
+ ///
+ /// Read data from an open file at specified offset. Note that the
+ /// seek and read are not guaranteed to be atomic, which may cause
+ /// issues in multi-threaded applications.
+ /// \param [out] buffer Pointer to memory that will receive the data
+ /// read.
+ /// \param [in] offset Byte offset within the file to read at,
+ /// relative to the start of the file. Ignored for stream-like
+ /// objects (e.g. TCP sockets or named pipes).
+ /// \param [in] length Number of bytes to read. Fewer bytes may be
+ /// read if the end of file is reached, or if no data is
+ /// available.
+ /// \param [out] actual Receives the number of bytes read if the
+ /// operation succeeds. Not valid if the operation fails.
+ /// \return Result of the operation.
+ virtual std::error_condition read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) noexcept = 0;
+
+ /// \brief Write to an open file
+ ///
+ /// Write data to an open file at specified offset. Note that the
+ /// seek and write are not guaranteed to be atomic, which may cause
+ /// issues in multi-threaded applications.
+ /// \param [in] buffer Pointer to memory containing data to write.
+ /// \param [in] offset Byte offset within the file to write at,
+ /// relative to the start of the file. Ignored for stream-like
+ /// objects (e.g. TCP sockets or named pipes).
+ /// \param [in] length Number of bytes to write.
+ /// \param [out] actual Receives the number of bytes written if the
+ /// operation succeeds. Not valid if the operation fails.
+ /// \return Result of the operation.
+ virtual std::error_condition write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) noexcept = 0;
+
+ /// \brief Change the size of an open file
+ ///
+ /// \param [in] offset Desired size of the file.
+ /// \return Result of the operation.
+ virtual std::error_condition truncate(std::uint64_t offset) noexcept = 0;
+
+ /// \brief Flush file buffers
+ ///
+ /// This flushes any data cached by the application, but does not
+ /// guarantee that all prior writes have reached persistent storage.
+ /// \return Result of the operation.
+ virtual std::error_condition flush() noexcept = 0;
+
+ /// \brief Delete a file
+ ///
+ /// \param [in] filename Path to the file to delete.
+ /// \return Result of the operation.
+ static std::error_condition remove(std::string const &filename) noexcept;
+};
+
+
+/// \brief Describe geometry of physical drive
+///
+/// If the given path points to a physical drive, return the geometry of
+/// that drive.
+///
+/// \param [in] filename Pointer to a path which might describe a
+/// physical drive.
+/// \param [out] cylinders Pointer to a uint32_t to receive the number of
+/// cylinders of the physical drive.
+/// \param [out] heads Pointer to a uint32_t to receive the number of
+/// heads per cylinder of the physical drive.
+/// \param [out] sectors Pointer to a uint32_t to receive the number of
+/// sectors per cylinder of the physical drive.
+/// \param [out] bps Pointer to a uint32_t to receive the number of
+/// bytes per sector of the physical drive.
+/// \return true if the filename points to a physical drive and if the
+/// values pointed to by cylinders, heads, sectors, and bps are valid;
+/// false in any other case
+bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders, uint32_t *heads, uint32_t *sectors, uint32_t *bps) noexcept;
+
+
+/// \brief Is the given character legal for filenames?
+///
+/// \param [in] uchar The character to check.
+/// \return Whether this character is legal in a filename.
+bool osd_is_valid_filename_char(char32_t uchar) noexcept;
+
+
+/// \brief Is the given character legal for paths?
+///
+/// \param [in] uchar The character to check.
+/// \return Whether this character is legal in a file path.
+bool osd_is_valid_filepath_char(char32_t uchar) noexcept;
+
+
+/***************************************************************************
+ DIRECTORY INTERFACES
+***************************************************************************/
+
+namespace osd
+{
+ // directory is an opaque type which represents an open directory
+ class directory
+ {
+ public:
+ typedef std::unique_ptr<directory> ptr;
+
+ // osd::directory::entry contains basic information about a file when iterating through
+ // a directory
+ class entry
+ {
+ public:
+ enum class entry_type
+ {
+ NONE,
+ FILE,
+ DIR,
+ OTHER
+ };
+
+ const char * name; // name of the entry
+ entry_type type; // type of the entry
+ std::uint64_t size; // size of the entry
+ std::chrono::system_clock::time_point last_modified; // last modified time
+ };
+
+ /// \brief Open a directory for iteration.
+ ///
+ /// \param [in] dirname Path to the directory in question.
+ /// \return Upon success, a directory pointer which contains opaque
+ /// data necessary to traverse the directory; on failure, nullptr.
+ static ptr open(std::string const &dirname);
+
+ /// \brief Close an open directory.
+ virtual ~directory() { }
+
+ /// \brief Return information about the next entry in the directory.
+ ///
+ /// \return A constant pointer to an entry representing the current
+ /// item in the directory, or nullptr, indicating that no more
+ /// entries are present.
+ virtual const entry *read() = 0;
+ };
+};
+
+
+/// \brief Return a directory entry for a path.
+///
+/// \param [in] path The path in question.
+/// \return An allocated pointer to an osd::directory::entry representing
+/// info on the path; even if the file does not exist.
+std::unique_ptr<osd::directory::entry> osd_stat(std::string const &path);
+
+
+/***************************************************************************
+ PATH INTERFACES
+***************************************************************************/
+
+/// \brief Returns whether the specified path is absolute.
+///
+/// \param [in] path The path in question.
+/// \return true if the path is absolute, false otherwise.
+bool osd_is_absolute_path(const std::string &path) noexcept;
+
+
+/// \brief Retrieves the full path.
+/// \param [in] path The path in question.
+/// \param [out] dst Reference to receive new path.
+/// \return File error.
+std::error_condition osd_get_full_path(std::string &dst, std::string const &path) noexcept;
+
+
+/// \brief Retrieves the volume name.
+///
+/// \param [in] idx Index number of volume.
+/// \return Volume name or empty string of out of range.
+std::string osd_get_volume_name(int idx);
+
+
+/// \brief Retrieves volume names.
+///
+/// \return Names of all mounted volumes.
+std::vector<std::string> osd_get_volume_names();
+
+
+#endif // MAME_OSD_OSDFILE_H
diff --git a/src/osd/osdnet.cpp b/src/osd/osdnet.cpp
deleted file mode 100644
index 3e1cb3596e1..00000000000
--- a/src/osd/osdnet.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Carl
-#include "emu.h"
-#include "osdnet.h"
-
-static class std::vector<std::unique_ptr<osd_netdev::entry_t>> netdev_list;
-
-void add_netdev(const char *name, const char *description, create_netdev func)
-{
- auto entry = make_unique_clear<osd_netdev::entry_t>();
- entry->id = netdev_list.size();
- strncpy(entry->name, name, 255);
- entry->name[255] = '\0';
- strncpy(entry->description, (description != nullptr) ? description : "(no name)", 255);
- entry->description[255] = '\0';
- entry->func = func;
- netdev_list.push_back(std::move(entry));
-}
-
-void clear_netdev()
-{
- netdev_list.clear();
-}
-
-const std::vector<std::unique_ptr<osd_netdev::entry_t>>& get_netdev_list()
-{
- return netdev_list;
-}
-
-class osd_netdev *open_netdev(int id, class device_network_interface *ifdev, int rate)
-{
- for(auto &entry : netdev_list)
- if(entry->id==id)
- return entry->func(entry->name, ifdev, rate);
- return nullptr;
-}
-
-osd_netdev::osd_netdev(class device_network_interface *ifdev, int rate)
-{
- m_dev = ifdev;
- m_timer = ifdev->device().machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(osd_netdev::recv), this));
- m_timer->adjust(attotime::from_hz(rate), 0, attotime::from_hz(rate));
-}
-
-osd_netdev::~osd_netdev()
-{
-}
-
-void osd_netdev::start()
-{
- m_timer->enable(true);
-}
-
-void osd_netdev::stop()
-{
- m_timer->enable(false);
-}
-
-int osd_netdev::send(uint8_t *buf, int len)
-{
- return 0;
-}
-
-void osd_netdev::recv(void *ptr, int param)
-{
- uint8_t *buf;
- int len;
- //const char atalkmac[] = { 0x09, 0x00, 0x07, 0xff, 0xff, 0xff };
- while(m_timer->enabled() && (len = recv_dev(&buf)))
- {
-#if 0
- if(buf[0] & 1)
- {
- if(memcmp("\xff\xff\xff\xff\xff\xff", buf, 6) && memcmp(atalkmac, buf, 6) && !m_dev->mcast_chk(buf, len)) continue;
- }
- else {
- //const unsigned char *ourmac = (const unsigned char *)get_mac();
- //printf("our mac: %.2X:%.2X:%.2X:%.2X:%.2X:%.2X dst mac: %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", ourmac[0], ourmac[1], ourmac[2], ourmac[3], ourmac[4], ourmac[5], buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
- if(memcmp(get_mac(), buf, 6) && !get_promisc()) continue;
- }
-#endif
-
- m_dev->recv_cb(buf, len);
- }
-}
-
-int osd_netdev::recv_dev(uint8_t **buf)
-{
- return 0;
-}
-
-void osd_netdev::set_mac(const char *mac)
-{
-}
-
-void osd_netdev::set_promisc(bool promisc)
-{
-}
-
-bool osd_netdev::get_promisc()
-{
- if(m_dev)
- return m_dev->get_promisc();
- return false;
-}
-
-const char *osd_netdev::get_mac()
-{
- if(m_dev)
- return m_dev->get_mac();
- return "\0\0\0\0\0\0";
-}
-
-int netdev_count()
-{
- return netdev_list.size();
-}
-
-void osd_list_network_adapters(void)
-{
- #ifdef USE_NETWORK
- int num_devs = netdev_list.size();
-
- if (num_devs == 0)
- {
- printf("No network adapters were found\n");
- return;
- }
-
- printf("Available network adapters:\n");
- for (auto &entry : netdev_list)
- {
- printf(" %s\n", entry->description);
- }
-
- #else
- printf("Network is not supported in this build\n");
- #endif
-}
diff --git a/src/osd/osdnet.h b/src/osd/osdnet.h
deleted file mode 100644
index 226ae2319a9..00000000000
--- a/src/osd/osdnet.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Carl
-#ifndef MAME_OSD_OSDNET_H
-#define MAME_OSD_OSDNET_H
-
-#pragma once
-
-class osd_netdev;
-
-#define CREATE_NETDEV(name) class osd_netdev *name(const char *ifname, class device_network_interface *ifdev, int rate)
-typedef class osd_netdev *(*create_netdev)(const char *ifname, class device_network_interface *ifdev, int rate);
-
-class osd_netdev
-{
-public:
- struct entry_t
- {
- int id;
- char name[256];
- char description[256];
- create_netdev func;
- };
- osd_netdev(class device_network_interface *ifdev, int rate);
- virtual ~osd_netdev();
- void start();
- void stop();
-
- virtual int send(uint8_t *buf, int len);
- virtual void set_mac(const char *mac);
- virtual void set_promisc(bool promisc);
-
- const char *get_mac();
- bool get_promisc();
-
-protected:
- virtual int recv_dev(uint8_t **buf);
-
-private:
- void recv(void *ptr, int param);
-
- class device_network_interface *m_dev;
- emu_timer *m_timer;
-};
-
-class osd_netdev *open_netdev(int id, class device_network_interface *ifdev, int rate);
-void add_netdev(const char *name, const char *description, create_netdev func);
-void clear_netdev();
-const std::vector<std::unique_ptr<osd_netdev::entry_t>>& get_netdev_list();
-int netdev_count();
-
-#endif // MAME_OSD_OSDNET_H
diff --git a/src/osd/osdsync.cpp b/src/osd/osdsync.cpp
index f8143aa2c51..b2300e93ee6 100644
--- a/src/osd/osdsync.cpp
+++ b/src/osd/osdsync.cpp
@@ -10,10 +10,10 @@
#include <windows.h>
#include <process.h>
#include <tchar.h>
-#include <stdlib.h>
+#include <cstdlib>
#ifdef __GNUC__
-#include <stdint.h>
+#include <cstdint>
#endif
#endif
#include <mutex>
@@ -85,14 +85,15 @@ static void spin_while_not(const volatile _AtomType * volatile atom, const _Main
// osd_num_processors
//============================================================
-int osd_get_num_processors(void)
+int osd_get_num_processors(bool heavy_mt)
{
#if defined(SDLMAME_EMSCRIPTEN)
// multithreading is not supported at this time
return 1;
#else
+ unsigned int threads = std::thread::hardware_concurrency();
// max out at 4 for now since scaling above that seems to do poorly
- return std::min(std::thread::hardware_concurrency(), 4U);
+ return heavy_mt ? threads : std::min(std::thread::hardware_concurrency(), 4U);
#endif
}
@@ -103,28 +104,27 @@ int osd_get_num_processors(void)
struct work_thread_info
{
work_thread_info(uint32_t aid, osd_work_queue &aqueue)
- : queue(aqueue)
- , handle(nullptr)
- , wakeevent(false, false) // auto-reset, not signalled
- , active(0)
- , id(aid)
+ : queue(aqueue)
+ , handle(nullptr)
+ , wakeevent(true, false) // manual reset, not signalled
+ , id(aid)
#if KEEP_STATISTICS
- , itemsdone(0)
- , actruntime(0)
- , runtime(0)
- , spintime(0)
- , waittime(0)
+ , itemsdone(0)
+ , actruntime(0)
+ , runtime(0)
+ , spintime(0)
+ , waittime(0)
#endif
{
}
+
osd_work_queue & queue; // pointer back to the queue
std::thread * handle; // handle to the thread
osd_event wakeevent; // wake event for the thread
- std::atomic<int32_t> active; // are we actively processing work?
- uint32_t id;
+ uint32_t id;
#if KEEP_STATISTICS
- int32_t itemsdone;
+ int32_t itemsdone;
osd_ticks_t actruntime;
osd_ticks_t runtime;
osd_ticks_t spintime;
@@ -136,21 +136,21 @@ struct work_thread_info
struct osd_work_queue
{
osd_work_queue()
- : list(nullptr)
- , tailptr(nullptr)
- , free(nullptr)
- , items(0)
- , livethreads(0)
- , waiting(0)
- , exiting(0)
- , threads(0)
- , flags(0)
- , doneevent(true, true) // manual reset, signalled
+ : list(nullptr)
+ , tailptr(nullptr)
+ , free(nullptr)
+ , items(0)
+ , livethreads(0)
+ , waiting(0)
+ , exiting(0)
+ , threads(0)
+ , flags(0)
+ , doneevent(true, true) // manual reset, signalled
#if KEEP_STATISTICS
- , itemsqueued(0)
- , setevents(0)
- , extraitems(0)
- , spinloops(0)
+ , itemsqueued(0)
+ , setevents(0)
+ , extraitems(0)
+ , spinloops(0)
#endif
{
}
@@ -180,14 +180,14 @@ struct osd_work_queue
struct osd_work_item
{
osd_work_item(osd_work_queue &aqueue)
- : next(nullptr)
- , queue(aqueue)
- , callback(nullptr)
- , param(nullptr)
- , result(nullptr)
- , event(nullptr) // manual reset, not signalled
- , flags(0)
- , done(false)
+ : next(nullptr)
+ , queue(aqueue)
+ , callback(nullptr)
+ , param(nullptr)
+ , result(nullptr)
+ , event(nullptr) // manual reset, not signalled
+ , flags(0)
+ , done(false)
{
}
@@ -197,7 +197,7 @@ struct osd_work_item
void * param; // callback parameter
void * result; // callback result
osd_event * event; // event signalled when complete
- uint32_t flags; // creation flags
+ uint32_t flags; // creation flags
std::atomic<int32_t> done; // is the item done?
};
@@ -211,8 +211,8 @@ int osd_num_processors = 0;
// FUNCTION PROTOTYPES
//============================================================
-static int effective_num_processors(void);
-static void * worker_thread_entry(void *param);
+static int effective_num_processors(bool heavy_mt);
+static void *worker_thread_entry(void *param);
static void worker_thread_process(osd_work_queue *queue, work_thread_info *thread);
static bool queue_has_list_items(osd_work_queue *queue);
@@ -251,7 +251,7 @@ int thread_adjust_priority(std::thread *thread, int adjust)
osd_work_queue *osd_work_queue_alloc(int flags)
{
int threadnum;
- int numprocs = effective_num_processors();
+ int numprocs = effective_num_processors(!(flags & WORK_QUEUE_FLAG_HIGH_FREQ));
osd_work_queue *queue;
int osdthreadnum = 0;
int allocthreadnum;
@@ -287,7 +287,7 @@ osd_work_queue *osd_work_queue_alloc(int flags)
if (flags & WORK_QUEUE_FLAG_MULTI)
allocthreadnum = queue->threads + 1;
else
- allocthreadnum = queue->threads;
+ allocthreadnum = std::max(queue->threads, 1u);
#if KEEP_STATISTICS
printf("osdprocs: %d effecprocs: %d threads: %d allocthreads: %d osdthreads: %d maxthreads: %d queuethreads: %d\n", osd_num_processors, numprocs, threadnum, allocthreadnum, osdthreadnum, WORK_MAX_THREADS, queue->threads);
@@ -445,20 +445,18 @@ void osd_work_queue_free(osd_work_queue *queue)
// free all items in the free list
while (queue->free.load() != nullptr)
{
- osd_work_item *item = (osd_work_item *)queue->free;
+ auto *item = (osd_work_item *)queue->free;
queue->free = item->next;
- if (item->event != nullptr)
- delete item->event;
+ delete item->event;
delete item;
}
// free all items in the active list
while (queue->list.load() != nullptr)
{
- osd_work_item *item = (osd_work_item *)queue->list;
+ auto *item = (osd_work_item *)queue->list;
queue->list = item->next;
- if (item->event != nullptr)
- delete item->event;
+ delete item->event;
delete item;
}
@@ -546,10 +544,9 @@ osd_work_item *osd_work_item_queue_multiple(osd_work_queue *queue, osd_work_call
{
work_thread_info *thread = queue->thread[threadnum];
- // if this thread is not active, wake him up
- if (!thread->active)
+ // Attempt to wake the thread
+ if (thread->wakeevent.set())
{
- thread->wakeevent.set();
add_to_stat(queue->setevents, 1);
// for non-shared, the first one we find is good enough
@@ -641,9 +638,9 @@ void osd_work_item_release(osd_work_item *item)
// effective_num_processors
//============================================================
-static int effective_num_processors(void)
+static int effective_num_processors(bool heavy_mt)
{
- int physprocs = osd_get_num_processors();
+ int physprocs = osd_get_num_processors(heavy_mt);
// osd_num_processors == 0 for 'auto'
if (osd_num_processors > 0)
@@ -672,7 +669,7 @@ static int effective_num_processors(void)
static void *worker_thread_entry(void *param)
{
- work_thread_info *thread = (work_thread_info *)param;
+ auto *thread = (work_thread_info *)param;
osd_work_queue &queue = thread->queue;
// loop until we exit
@@ -694,7 +691,6 @@ static void *worker_thread_entry(void *param)
break;
// indicate that we are live
- thread->active = true;
++queue.livethreads;
// process work items
@@ -719,7 +715,7 @@ static void *worker_thread_entry(void *param)
}
// decrement the live thread count
- thread->active = false;
+ thread->wakeevent.reset();
--queue.livethreads;
}
diff --git a/src/osd/osdsync.h b/src/osd/osdsync.h
index 3a286b60afa..21cb0aca34c 100644
--- a/src/osd/osdsync.h
+++ b/src/osd/osdsync.h
@@ -15,7 +15,7 @@
#include <atomic>
#include <condition_variable>
-#include "osdcomm.h"
+#include "osdcore.h"
/***************************************************************************
SYNCHRONIZATION INTERFACES - Events
@@ -136,16 +136,17 @@ public:
Return value:
- None
+ Whether or not the event was actually signalled (false if the event had already been signalled)
Notes:
All threads waiting for the event will be signalled.
-----------------------------------------------------------------------------*/
- void set()
+ bool set()
{
m_mutex.lock();
- if (m_signalled == false)
+ bool needs_signal = !m_signalled;
+ if (needs_signal)
{
m_signalled = true;
if (m_autoreset)
@@ -154,13 +155,14 @@ public:
m_cond.notify_all();
}
m_mutex.unlock();
+ return needs_signal;
}
private:
std::mutex m_mutex;
std::condition_variable m_cond;
- std::atomic<int32_t> m_autoreset;
- std::atomic<int32_t> m_signalled;
+ int32_t m_autoreset;
+ int32_t m_signalled;
};
diff --git a/src/osd/sdl/android_main.cpp b/src/osd/sdl/android_main.cpp
new file mode 100644
index 00000000000..00879ecbe27
--- /dev/null
+++ b/src/osd/sdl/android_main.cpp
@@ -0,0 +1,11 @@
+#ifdef __ANDROID__
+
+extern "C" int SDL_main(int argc, char *argv[]);
+
+// Using this in main library to prevent linker removing SDL_main
+int dummy_main(int argc, char** argv)
+{
+ return SDL_main(argc, argv);
+}
+
+#endif /* __ANDROID__ */
diff --git a/src/osd/sdl/osdsdl.cpp b/src/osd/sdl/osdsdl.cpp
new file mode 100644
index 00000000000..d9268869729
--- /dev/null
+++ b/src/osd/sdl/osdsdl.cpp
@@ -0,0 +1,852 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert, R. Belmont
+
+#include "osdsdl.h"
+
+#include "modules/input/input_common.h"
+#include "modules/lib/osdlib.h"
+#include "window.h"
+
+#include "util/language.h"
+#include "util/unicode.h"
+
+// TODO: reduce dependence on concrete emu classes
+#include "emu.h"
+#include "main.h"
+#include "uiinput.h"
+
+#include "ui/uimain.h"
+
+#include <algorithm>
+#include <cmath>
+#include <cstdio>
+#include <cstring>
+
+
+namespace {
+
+//============================================================
+// defines_verbose
+//============================================================
+
+#define MAC_EXPAND_STR(_m) #_m
+#define MACRO_VERBOSE(_mac) \
+ do { \
+ if (strcmp(MAC_EXPAND_STR(_mac), #_mac) != 0) \
+ osd_printf_verbose("%s=%s ", #_mac, MAC_EXPAND_STR(_mac)); \
+ } while (0)
+
+void defines_verbose()
+{
+ osd_printf_verbose("Build version: %s\n", emulator_info::get_build_version());
+ osd_printf_verbose("Build architecure: ");
+ MACRO_VERBOSE(SDLMAME_ARCH);
+ osd_printf_verbose("\n");
+ osd_printf_verbose("Build defines 1: ");
+ MACRO_VERBOSE(SDLMAME_UNIX);
+ MACRO_VERBOSE(SDLMAME_X11);
+ MACRO_VERBOSE(SDLMAME_WIN32);
+ MACRO_VERBOSE(SDLMAME_MACOSX);
+ MACRO_VERBOSE(SDLMAME_DARWIN);
+ MACRO_VERBOSE(SDLMAME_LINUX);
+ MACRO_VERBOSE(SDLMAME_SOLARIS);
+ MACRO_VERBOSE(SDLMAME_IRIX);
+ MACRO_VERBOSE(SDLMAME_BSD);
+ osd_printf_verbose("\n");
+ osd_printf_verbose("Build defines 1: ");
+ MACRO_VERBOSE(LSB_FIRST);
+ MACRO_VERBOSE(MAME_NOASM);
+ MACRO_VERBOSE(MAME_DEBUG);
+ MACRO_VERBOSE(BIGENDIAN);
+ MACRO_VERBOSE(CPP_COMPILE);
+ MACRO_VERBOSE(SYNC_IMPLEMENTATION);
+ osd_printf_verbose("\n");
+ osd_printf_verbose("SDL/OpenGL defines: ");
+ osd_printf_verbose("SDL_COMPILEDVERSION=%d ", SDL_COMPILEDVERSION);
+ MACRO_VERBOSE(USE_OPENGL);
+ MACRO_VERBOSE(USE_DISPATCH_GL);
+ osd_printf_verbose("\n");
+ osd_printf_verbose("Compiler defines A: ");
+ MACRO_VERBOSE(__GNUC__);
+ MACRO_VERBOSE(__GNUC_MINOR__);
+ MACRO_VERBOSE(__GNUC_PATCHLEVEL__);
+ MACRO_VERBOSE(__VERSION__);
+ osd_printf_verbose("\n");
+ osd_printf_verbose("Compiler defines B: ");
+ MACRO_VERBOSE(__amd64__);
+ MACRO_VERBOSE(__x86_64__);
+ MACRO_VERBOSE(__unix__);
+ MACRO_VERBOSE(__i386__);
+ MACRO_VERBOSE(__ppc__);
+ MACRO_VERBOSE(__ppc64__);
+ osd_printf_verbose("\n");
+ osd_printf_verbose("Compiler defines C: ");
+ MACRO_VERBOSE(_FORTIFY_SOURCE);
+ MACRO_VERBOSE(__USE_FORTIFY_LEVEL);
+ osd_printf_verbose("\n");
+}
+
+
+//============================================================
+// osd_sdl_info
+//============================================================
+
+void osd_sdl_info()
+{
+ int num = SDL_GetNumVideoDrivers();
+
+ osd_printf_verbose("Available videodrivers: ");
+ for (int i = 0; i < num; i++)
+ {
+ const char *name = SDL_GetVideoDriver(i);
+ osd_printf_verbose("%s ", name);
+ }
+ osd_printf_verbose("\n");
+
+ osd_printf_verbose("Current Videodriver: %s\n", SDL_GetCurrentVideoDriver());
+ num = SDL_GetNumVideoDisplays();
+ for (int i = 0; i < num; i++)
+ {
+ SDL_DisplayMode mode;
+
+ osd_printf_verbose("\tDisplay #%d\n", i);
+ if (SDL_GetDesktopDisplayMode(i, &mode) == 0)
+ osd_printf_verbose("\t\tDesktop Mode: %dx%d-%d@%d\n", mode.w, mode.h, SDL_BITSPERPIXEL(mode.format), mode.refresh_rate);
+ if (SDL_GetCurrentDisplayMode(i, &mode) == 0)
+ osd_printf_verbose("\t\tCurrent Display Mode: %dx%d-%d@%d\n", mode.w, mode.h, SDL_BITSPERPIXEL(mode.format), mode.refresh_rate);
+
+ osd_printf_verbose("\t\tRenderdrivers:\n");
+ for (int j = 0; j < SDL_GetNumRenderDrivers(); j++)
+ {
+ SDL_RendererInfo info;
+ SDL_GetRenderDriverInfo(j, &info);
+ osd_printf_verbose("\t\t\t%10s (%dx%d)\n", info.name, info.max_texture_width, info.max_texture_height);
+ }
+ }
+
+ osd_printf_verbose("Available audio drivers: \n");
+ num = SDL_GetNumAudioDrivers();
+ for (int i = 0; i < num; i++)
+ {
+ osd_printf_verbose("\t%-20s\n", SDL_GetAudioDriver(i));
+ }
+}
+
+
+sdl_window_info *window_from_id(Uint32 id)
+{
+ SDL_Window const *const sdl_window = SDL_GetWindowFromID(id);
+
+ auto const window = std::find_if(
+ osd_common_t::window_list().begin(),
+ osd_common_t::window_list().end(),
+ [sdl_window] (std::unique_ptr<osd_window> const &w)
+ {
+ return dynamic_cast<sdl_window_info &>(*w).platform_window() == sdl_window;
+ });
+
+ if (window == osd_common_t::window_list().end())
+ return nullptr;
+
+ return &static_cast<sdl_window_info &>(**window);
+}
+
+} // anonymous namespace
+
+
+
+//============================================================
+// SDL OSD interface
+//============================================================
+
+sdl_osd_interface::sdl_osd_interface(sdl_options &options) :
+ osd_common_t(options),
+ m_options(options),
+ m_focus_window(nullptr),
+ m_mouse_over_window(0),
+ m_modifier_keys(0),
+ m_last_click_time(std::chrono::steady_clock::time_point::min()),
+ m_last_click_x(0),
+ m_last_click_y(0),
+ m_enable_touch(false),
+ m_next_ptrdev(0)
+{
+}
+
+
+sdl_osd_interface::~sdl_osd_interface()
+{
+}
+
+
+void sdl_osd_interface::init(running_machine &machine)
+{
+ // call our parent
+ osd_common_t::init(machine);
+
+ const char *stemp;
+
+ // determine if we are benchmarking, and adjust options appropriately
+ int bench = options().bench();
+ if (bench > 0)
+ {
+ options().set_value(OPTION_SLEEP, false, OPTION_PRIORITY_MAXIMUM);
+ options().set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM);
+ options().set_value(OSDOPTION_SOUND, "none", OPTION_PRIORITY_MAXIMUM);
+ options().set_value(OSDOPTION_VIDEO, "none", OPTION_PRIORITY_MAXIMUM);
+ options().set_value(OPTION_SECONDS_TO_RUN, bench, OPTION_PRIORITY_MAXIMUM);
+ }
+
+ // Some driver options - must be before audio init!
+ stemp = options().audio_driver();
+ if (stemp != nullptr && strcmp(stemp, OSDOPTVAL_AUTO) != 0)
+ {
+ osd_printf_verbose("Setting SDL audiodriver '%s' ...\n", stemp);
+ osd_setenv(SDLENV_AUDIODRIVER, stemp, 1);
+ }
+
+ stemp = options().video_driver();
+ if (stemp != nullptr && strcmp(stemp, OSDOPTVAL_AUTO) != 0)
+ {
+ osd_printf_verbose("Setting SDL videodriver '%s' ...\n", stemp);
+ osd_setenv(SDLENV_VIDEODRIVER, stemp, 1);
+ }
+
+ stemp = options().render_driver();
+ if (stemp != nullptr)
+ {
+ if (strcmp(stemp, OSDOPTVAL_AUTO) != 0)
+ {
+ osd_printf_verbose("Setting SDL renderdriver '%s' ...\n", stemp);
+ //osd_setenv(SDLENV_RENDERDRIVER, stemp, 1);
+ SDL_SetHint(SDL_HINT_RENDER_DRIVER, stemp);
+ }
+ else
+ {
+#if defined(SDLMAME_WIN32)
+ // OpenGL renderer has less issues with mode switching on windows
+ osd_printf_verbose("Setting SDL renderdriver '%s' ...\n", "opengl");
+ //osd_setenv(SDLENV_RENDERDRIVER, stemp, 1);
+ SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
+#endif
+ }
+ }
+
+ /* Set the SDL environment variable for drivers wanting to load the
+ * lib at startup.
+ */
+#if USE_OPENGL
+ /* FIXME: move lib loading code from drawogl.c here */
+
+ stemp = options().gl_lib();
+ if (stemp != nullptr && strcmp(stemp, OSDOPTVAL_AUTO) != 0)
+ {
+ osd_setenv("SDL_VIDEO_GL_DRIVER", stemp, 1);
+ osd_printf_verbose("Setting SDL_VIDEO_GL_DRIVER = '%s' ...\n", stemp);
+ }
+#endif
+
+ /* get number of processors */
+ stemp = options().numprocessors();
+
+ osd_num_processors = 0;
+
+ if (strcmp(stemp, "auto") != 0)
+ {
+ osd_num_processors = atoi(stemp);
+ if (osd_num_processors < 1)
+ {
+ osd_printf_warning("numprocessors < 1 doesn't make much sense. Assuming auto ...\n");
+ osd_num_processors = 0;
+ }
+ }
+
+ /* do we want touch support or will we use mouse emulation? */
+ m_enable_touch = options().enable_touch();
+ try
+ {
+ if (m_enable_touch)
+ {
+ int const count(SDL_GetNumTouchDevices());
+ m_ptrdev_map.reserve(std::max<int>(count + 1, 8));
+ map_pointer_device(SDL_MOUSE_TOUCHID);
+ for (int i = 0; count > i; ++i)
+ {
+ SDL_TouchID const device(SDL_GetTouchDevice(i));
+ if (device)
+ map_pointer_device(device);
+ }
+ }
+ else
+ {
+ m_ptrdev_map.reserve(1);
+ map_pointer_device(SDL_MOUSE_TOUCHID);
+ }
+ }
+ catch (std::bad_alloc const &)
+ {
+ osd_printf_error("sdl_osd_interface: error allocating pointer data\n");
+ // survivable - it will still attempt to allocate mappings when it first sees devices
+ }
+
+#if defined(SDLMAME_ANDROID)
+ SDL_SetHint(SDL_HINT_VIDEO_EXTERNAL_CONTEXT, "1");
+#endif
+ /* Initialize SDL */
+
+ if (SDL_InitSubSystem(SDL_INIT_VIDEO))
+ {
+ osd_printf_error("Could not initialize SDL %s\n", SDL_GetError());
+ exit(-1);
+ }
+
+ osd_sdl_info();
+
+ defines_verbose();
+
+ osd_common_t::init_subsystems();
+
+ if (options().oslog())
+ {
+ using namespace std::placeholders;
+ machine.add_logerror_callback(std::bind(&sdl_osd_interface::output_oslog, this, _1));
+ }
+
+
+
+#ifdef SDLMAME_EMSCRIPTEN
+ SDL_EventState(SDL_TEXTINPUT, SDL_FALSE);
+#else
+ SDL_EventState(SDL_TEXTINPUT, SDL_TRUE);
+#endif
+}
+
+
+void sdl_osd_interface::input_update(bool relative_reset)
+{
+ process_events_buf();
+ poll_input_modules(relative_reset);
+}
+
+
+void sdl_osd_interface::customize_input_type_list(std::vector<input_type_entry> &typelist)
+{
+ // loop over the defaults
+ for (input_type_entry &entry : typelist)
+ {
+ switch (entry.type())
+ {
+ // configurable UI mode switch
+ case IPT_UI_TOGGLE_UI:
+ {
+ char const *const uimode = options().ui_mode_key();
+ input_item_id mameid_code = ITEM_ID_INVALID;
+ if (!uimode || !*uimode || !strcmp(uimode, "auto"))
+ {
+#if defined(__APPLE__) && defined(__MACH__)
+ mameid_code = keyboard_trans_table::instance().lookup_mame_code("ITEM_ID_INSERT");
+#endif
+ }
+ else
+ {
+ std::string fullmode("ITEM_ID_");
+ fullmode.append(uimode);
+ mameid_code = keyboard_trans_table::instance().lookup_mame_code(fullmode.c_str());
+ }
+ if (ITEM_ID_INVALID != mameid_code)
+ {
+ input_code const ui_code = input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, input_item_id(mameid_code));
+ entry.defseq(SEQ_TYPE_STANDARD).set(ui_code);
+ }
+ }
+ break;
+
+ // alt-enter for fullscreen
+ case IPT_OSD_1:
+ entry.configure_osd("TOGGLE_FULLSCREEN", N_p("input-name", "Toggle Fullscreen"));
+ entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_ENTER, KEYCODE_LALT);
+ break;
+
+ // page down for fastforward (must be OSD_3 as per src/emu/ui.c)
+ case IPT_UI_FAST_FORWARD:
+ entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_PGDN);
+ break;
+
+ // OSD hotkeys use LALT/LCTRL and start at F3, they start
+ // at F3 because F1-F2 are hardcoded into many drivers to
+ // various dipswitches, and pressing them together with
+ // LALT/LCTRL will still press/toggle these dipswitches.
+
+ // LALT-F10 to toggle OpenGL filtering
+ case IPT_OSD_5:
+ entry.configure_osd("TOGGLE_FILTER", N_p("input-name", "Toggle Filter"));
+ entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F10, KEYCODE_LALT);
+ break;
+
+ // add a Not LALT condition to the throttle key
+ case IPT_UI_THROTTLE:
+ entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F10, input_seq::not_code, KEYCODE_LALT);
+ break;
+
+ // LALT-F8 to decrease OpenGL prescaling
+ case IPT_OSD_6:
+ entry.configure_osd("DECREASE_PRESCALE", N_p("input-name", "Decrease Prescaling"));
+ entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F8, KEYCODE_LALT);
+ break;
+
+ // add a Not LALT condition to the frameskip dec key
+ case IPT_UI_FRAMESKIP_DEC:
+ entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F8, input_seq::not_code, KEYCODE_LALT, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT);
+ break;
+
+ // LALT-F9 to increase OpenGL prescaling
+ case IPT_OSD_7:
+ entry.configure_osd("INCREASE_PRESCALE", N_p("input-name", "Increase Prescaling"));
+ entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F9, KEYCODE_LALT);
+ break;
+
+ // add a Not LALT condition to the load state key
+ case IPT_UI_FRAMESKIP_INC:
+ entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F9, input_seq::not_code, KEYCODE_LALT);
+ break;
+
+ // LSHIFT-LALT-F12 for fullscreen video (BGFX)
+ case IPT_OSD_8:
+ entry.configure_osd("RENDER_AVI", N_p("input-name", "Record Rendered Video"));
+ entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, KEYCODE_LSHIFT, KEYCODE_LALT);
+ break;
+
+ // disable the config menu if the ALT key is down
+ // (allows ALT-TAB to switch between apps)
+ case IPT_UI_MENU:
+ entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_TAB, input_seq::not_code, KEYCODE_LALT, input_seq::not_code, KEYCODE_RALT);
+ break;
+
+#if defined(__APPLE__) && defined(__MACH__)
+ // 78-key Apple MacBook & Bluetooth keyboards have no right control key
+ case IPT_MAHJONG_SCORE:
+ if (entry.player() == 0)
+ entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_SLASH);
+ break;
+#endif
+
+ // leave everything else alone
+ default:
+ break;
+ }
+ }
+}
+
+
+void sdl_osd_interface::release_keys()
+{
+ auto const keybd = dynamic_cast<input_module_base *>(m_keyboard_input);
+ if (keybd)
+ keybd->reset_devices();
+}
+
+
+bool sdl_osd_interface::should_hide_mouse()
+{
+ // if we are paused, no
+ if (machine().paused())
+ return false;
+
+ // if neither mice nor lightguns are enabled in the core, then no
+ if (!options().mouse() && !options().lightgun())
+ return false;
+
+ if (!mouse_over_window())
+ return false;
+
+ // otherwise, yes
+ return true;
+}
+
+
+void sdl_osd_interface::process_events_buf()
+{
+ SDL_PumpEvents();
+}
+
+
+void sdl_osd_interface::process_events()
+{
+ std::lock_guard<std::mutex> lock(subscription_mutex());
+ SDL_Event event;
+ while (SDL_PollEvent(&event))
+ {
+ // handle UI events
+ switch (event.type)
+ {
+ case SDL_WINDOWEVENT:
+ process_window_event(event);
+ break;
+
+ case SDL_KEYDOWN:
+ if (event.key.keysym.scancode == SDL_SCANCODE_LCTRL)
+ m_modifier_keys |= MODIFIER_KEY_LCTRL;
+ else if (event.key.keysym.scancode == SDL_SCANCODE_RCTRL)
+ m_modifier_keys |= MODIFIER_KEY_RCTRL;
+ else if (event.key.keysym.scancode == SDL_SCANCODE_LSHIFT)
+ m_modifier_keys |= MODIFIER_KEY_LSHIFT;
+ else if (event.key.keysym.scancode == SDL_SCANCODE_RSHIFT)
+ m_modifier_keys |= MODIFIER_KEY_RSHIFT;
+
+ if (event.key.keysym.sym < 0x20)
+ {
+ // push control characters - they don't arrive as text input events
+ machine().ui_input().push_char_event(osd_common_t::window_list().front()->target(), event.key.keysym.sym);
+ }
+ else if (m_modifier_keys & MODIFIER_KEY_CTRL)
+ {
+ // SDL filters out control characters for text input, so they are decoded here
+ if (event.key.keysym.sym >= 0x40 && event.key.keysym.sym < 0x7f)
+ {
+ machine().ui_input().push_char_event(osd_common_t::window_list().front()->target(), event.key.keysym.sym & 0x1f);
+ }
+ else if (m_modifier_keys & MODIFIER_KEY_SHIFT)
+ {
+ if (event.key.keysym.sym == SDLK_2) // Ctrl-@ (NUL)
+ machine().ui_input().push_char_event(osd_common_t::window_list().front()->target(), 0x00);
+ else if (event.key.keysym.sym == SDLK_6) // Ctrl-^ (RS)
+ machine().ui_input().push_char_event(osd_common_t::window_list().front()->target(), 0x1e);
+ else if (event.key.keysym.sym == SDLK_MINUS) // Ctrl-_ (US)
+ machine().ui_input().push_char_event(osd_common_t::window_list().front()->target(), 0x1f);
+ }
+ }
+ break;
+
+ case SDL_KEYUP:
+ if (event.key.keysym.scancode == SDL_SCANCODE_LCTRL)
+ m_modifier_keys &= ~MODIFIER_KEY_LCTRL;
+ else if (event.key.keysym.scancode == SDL_SCANCODE_RCTRL)
+ m_modifier_keys &= ~MODIFIER_KEY_RCTRL;
+ else if (event.key.keysym.scancode == SDL_SCANCODE_LSHIFT)
+ m_modifier_keys &= ~MODIFIER_KEY_LSHIFT;
+ else if (event.key.keysym.scancode == SDL_SCANCODE_RSHIFT)
+ m_modifier_keys &= ~MODIFIER_KEY_RSHIFT;
+ break;
+
+ case SDL_TEXTINPUT:
+ process_textinput_event(event);
+ break;
+
+ case SDL_MOUSEMOTION:
+ if (!m_enable_touch || (SDL_TOUCH_MOUSEID != event.motion.which))
+ {
+ auto const window = window_from_id(event.motion.windowID);
+ if (!window)
+ break;
+
+ unsigned device;
+ try
+ {
+ device = map_pointer_device(SDL_MOUSE_TOUCHID);
+ }
+ catch (std::bad_alloc const &)
+ {
+ osd_printf_error("sdl_osd_interface: error allocating pointer data\n");
+ break;
+ }
+
+ int x, y;
+ window->xy_to_render_target(event.motion.x, event.motion.y, &x, &y);
+ window->mouse_moved(device, x, y);
+ }
+ break;
+
+ case SDL_MOUSEBUTTONDOWN:
+ case SDL_MOUSEBUTTONUP:
+ if (!m_enable_touch || (SDL_TOUCH_MOUSEID != event.button.which))
+ {
+ auto const window = window_from_id(event.button.windowID);
+ if (!window)
+ break;
+
+ unsigned device;
+ try
+ {
+ device = map_pointer_device(SDL_MOUSE_TOUCHID);
+ }
+ catch (std::bad_alloc const &)
+ {
+ osd_printf_error("sdl_osd_interface: error allocating pointer data\n");
+ break;
+ }
+
+ int x, y;
+ window->xy_to_render_target(event.button.x, event.button.y, &x, &y);
+ unsigned button(event.button.button - 1);
+ if ((1 == button) || (2 == button))
+ button ^= 3;
+ if (SDL_PRESSED == event.button.state)
+ window->mouse_down(device, x, y, button);
+ else
+ window->mouse_up(device, x, y, button);
+ }
+ break;
+
+ case SDL_MOUSEWHEEL:
+ {
+ auto const window = window_from_id(event.wheel.windowID);
+ if (window)
+ {
+ unsigned device;
+ try
+ {
+ device = map_pointer_device(SDL_MOUSE_TOUCHID);
+ }
+ catch (std::bad_alloc const &)
+ {
+ osd_printf_error("sdl_osd_interface: error allocating pointer data\n");
+ break;
+ }
+#if SDL_VERSION_ATLEAST(2, 0, 18)
+ window->mouse_wheel(device, std::lround(event.wheel.preciseY * 120));
+#else
+ window->mouse_wheel(device, event.wheel.y);
+#endif
+ }
+ }
+ break;
+
+ case SDL_FINGERMOTION:
+ case SDL_FINGERDOWN:
+ case SDL_FINGERUP:
+ if (m_enable_touch && (SDL_MOUSE_TOUCHID != event.tfinger.touchId))
+ {
+ // ignore if it doesn't map to a window we own
+ auto const window = window_from_id(event.tfinger.windowID);
+ if (!window)
+ break;
+
+ // map SDL touch device ID to a zero-based device number
+ unsigned device;
+ try
+ {
+ device = map_pointer_device(event.tfinger.touchId);
+ }
+ catch (std::bad_alloc const &)
+ {
+ osd_printf_error("sdl_osd_interface: error allocating pointer data\n");
+ break;
+ }
+
+ // convert normalised coordinates to what MAME wants
+ auto const size = window->get_size();
+ int const winx = std::lround(event.tfinger.x * size.width());
+ int const winy = std::lround(event.tfinger.y * size.height());
+ int x, y;
+ window->xy_to_render_target(winx, winy, &x, &y);
+
+ // call appropriate window method
+ switch (event.type)
+ {
+ case SDL_FINGERMOTION:
+ window->finger_moved(event.tfinger.fingerId, device, x, y);
+ break;
+ case SDL_FINGERDOWN:
+ window->finger_down(event.tfinger.fingerId, device, x, y);
+ break;
+ case SDL_FINGERUP:
+ window->finger_up(event.tfinger.fingerId, device, x, y);
+ break;
+ }
+ }
+ break;
+ }
+
+ // let input modules do their thing
+ dispatch_event(event.type, event);
+ }
+}
+
+
+void sdl_osd_interface::osd_exit()
+{
+ osd_common_t::osd_exit();
+
+ SDL_QuitSubSystem(SDL_INIT_VIDEO);
+}
+
+
+void sdl_osd_interface::output_oslog(const char *buffer)
+{
+ fputs(buffer, stderr);
+}
+
+
+void sdl_osd_interface::process_window_event(SDL_Event const &event)
+{
+ auto const window = window_from_id(event.window.windowID);
+
+ if (!window)
+ {
+ // This condition may occur when the fullscreen toggle is used
+ osd_printf_verbose("Skipped window event due to missing window param from SDL\n");
+ return;
+ }
+
+ switch (event.window.event)
+ {
+ case SDL_WINDOWEVENT_MOVED:
+ window->notify_changed();
+ m_focus_window = window;
+ break;
+
+ case SDL_WINDOWEVENT_RESIZED:
+#ifdef SDLMAME_LINUX
+ /* FIXME: SDL2 sends some spurious resize events on Ubuntu
+ * while in fullscreen mode. Ignore them for now.
+ */
+ if (!window->fullscreen())
+#endif
+ {
+ //printf("event data1,data2 %d x %d %ld\n", event.window.data1, event.window.data2, sizeof(SDL_Event));
+ window->resize(event.window.data1, event.window.data2);
+ }
+ break;
+
+ case SDL_WINDOWEVENT_ENTER:
+ {
+ m_mouse_over_window = 1;
+ unsigned device;
+ try
+ {
+ device = map_pointer_device(SDL_MOUSE_TOUCHID);
+ }
+ catch (std::bad_alloc const &)
+ {
+ osd_printf_error("sdl_osd_interface: error allocating pointer data\n");
+ break;
+ }
+ window->mouse_entered(device);
+ }
+ break;
+
+ case SDL_WINDOWEVENT_LEAVE:
+ {
+ m_mouse_over_window = 0;
+ unsigned device;
+ try
+ {
+ device = map_pointer_device(SDL_MOUSE_TOUCHID);
+ }
+ catch (std::bad_alloc const &)
+ {
+ osd_printf_error("sdl_osd_interface: error allocating pointer data\n");
+ break;
+ }
+ window->mouse_left(device);
+ }
+ break;
+
+ case SDL_WINDOWEVENT_FOCUS_GAINED:
+ m_focus_window = window;
+ machine().ui_input().push_window_focus_event(window->target());
+ break;
+
+ case SDL_WINDOWEVENT_FOCUS_LOST:
+ if (window == m_focus_window)
+ m_focus_window = nullptr;
+ machine().ui_input().push_window_defocus_event(window->target());
+ break;
+
+ case SDL_WINDOWEVENT_CLOSE:
+ machine().schedule_exit();
+ break;
+ }
+}
+
+void sdl_osd_interface::process_textinput_event(SDL_Event const &event)
+{
+ if (*event.text.text)
+ {
+ auto const window = focus_window(event.text);
+ //printf("Focus window is %p - wl %p\n", window, osd_common_t::window_list().front().get());
+ if (window != nullptr)
+ {
+ auto ptr = event.text.text;
+ auto len = std::strlen(event.text.text);
+ while (len)
+ {
+ char32_t ch;
+ auto chlen = uchar_from_utf8(&ch, ptr, len);
+ if (0 > chlen)
+ {
+ ch = 0x0fffd;
+ chlen = 1;
+ }
+ ptr += chlen;
+ len -= chlen;
+ machine().ui_input().push_char_event(window->target(), ch);
+ }
+ }
+ }
+}
+
+
+void sdl_osd_interface::check_osd_inputs()
+{
+ // check for toggling fullscreen mode (don't do this in debug mode)
+ if (machine().ui_input().pressed(IPT_OSD_1) && !(machine().debug_flags & DEBUG_FLAG_OSD_ENABLED))
+ {
+ // destroy the renderers first so that the render module can bounce if it depends on having a window handle
+ for (auto it = osd_common_t::window_list().rbegin(); osd_common_t::window_list().rend() != it; ++it)
+ (*it)->renderer_reset();
+ for (auto const &curwin : osd_common_t::window_list())
+ dynamic_cast<sdl_window_info &>(*curwin).toggle_full_screen();
+ }
+
+ auto const &window = osd_common_t::window_list().front();
+
+ if (USE_OPENGL)
+ {
+ // FIXME: on a per window basis
+ if (machine().ui_input().pressed(IPT_OSD_5))
+ {
+ video_config.filter = !video_config.filter;
+ machine().ui().popup_time(1, "Filter %s", video_config.filter? "enabled" : "disabled");
+ }
+ }
+
+ if (machine().ui_input().pressed(IPT_OSD_6))
+ dynamic_cast<sdl_window_info &>(*window).modify_prescale(-1);
+
+ if (machine().ui_input().pressed(IPT_OSD_7))
+ dynamic_cast<sdl_window_info &>(*window).modify_prescale(1);
+
+ if (machine().ui_input().pressed(IPT_OSD_8))
+ window->renderer().record();
+}
+
+
+template <typename T>
+sdl_window_info *sdl_osd_interface::focus_window(T const &event) const
+{
+ // FIXME: SDL does not properly report the window for certain versions of Ubuntu - is this still relevant?
+ if (m_enable_touch)
+ return window_from_id(event.windowID);
+ else
+ return m_focus_window;
+}
+
+
+unsigned sdl_osd_interface::map_pointer_device(SDL_TouchID device)
+{
+ auto devpos(std::lower_bound(
+ m_ptrdev_map.begin(),
+ m_ptrdev_map.end(),
+ device,
+ [] (std::pair<SDL_TouchID, unsigned> const &mapping, SDL_TouchID id)
+ {
+ return mapping.first < id;
+ }));
+ if ((m_ptrdev_map.end() == devpos) || (device != devpos->first))
+ {
+ devpos = m_ptrdev_map.emplace(devpos, device, m_next_ptrdev);
+ ++m_next_ptrdev;
+ }
+ return devpos->second;
+}
diff --git a/src/osd/sdl/osdsdl.h b/src/osd/sdl/osdsdl.h
index 4a320319f44..74730f69df5 100644
--- a/src/osd/sdl/osdsdl.h
+++ b/src/osd/sdl/osdsdl.h
@@ -1,47 +1,31 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert, R. Belmont
-#ifndef _osdsdl_h_
-#define _osdsdl_h_
+#ifndef MAME_OSD_SDL_OSDSDL_H
+#define MAME_OSD_SDL_OSDSDL_H
+
+#pragma once
+
+#include "sdlopts.h"
#include "modules/lib/osdobj_common.h"
#include "modules/osdmodule.h"
-#include "modules/font/font_module.h"
+
+#include <SDL2/SDL.h>
+
+#include <cassert>
+#include <chrono>
+#include <memory>
+#include <mutex>
+#include <unordered_map>
+#include <utility>
+#include <string>
+#include <vector>
+
//============================================================
// Defines
//============================================================
-#define SDLOPTION_INIPATH "inipath"
-#define SDLOPTION_SDLVIDEOFPS "sdlvideofps"
-#define SDLOPTION_USEALLHEADS "useallheads"
-#define SDLOPTION_CENTERH "centerh"
-#define SDLOPTION_CENTERV "centerv"
-
-#define SDLOPTION_SCALEMODE "scalemode"
-
-#define SDLOPTION_WAITVSYNC "waitvsync"
-#define SDLOPTION_SYNCREFRESH "syncrefresh"
-#define SDLOPTION_KEYMAP "keymap"
-#define SDLOPTION_KEYMAP_FILE "keymap_file"
-
-#define SDLOPTION_SIXAXIS "sixaxis"
-#define SDLOPTION_JOYINDEX "joy_idx"
-#define SDLOPTION_KEYBINDEX "keyb_idx"
-#define SDLOPTION_MOUSEINDEX "mouse_index"
-#if (USE_XINPUT)
-#define SDLOPTION_LIGHTGUNINDEX "lightgun_index"
-#endif
-
-#define SDLOPTION_AUDIODRIVER "audiodriver"
-#define SDLOPTION_VIDEODRIVER "videodriver"
-#define SDLOPTION_RENDERDRIVER "renderdriver"
-#define SDLOPTION_GL_LIB "gl_lib"
-
-#define SDLOPTVAL_OPENGL "opengl"
-#define SDLOPTVAL_SOFT "soft"
-#define SDLOPTVAL_SDL2ACCEL "accel"
-#define SDLOPTVAL_BGFX "bgfx"
-
#define SDLMAME_LED(x) "led" #x
// read by sdlmame
@@ -56,63 +40,103 @@
#define SDLENV_AUDIODRIVER "SDL_AUDIODRIVER"
#define SDLENV_RENDERDRIVER "SDL_VIDEO_RENDERER"
-#define SDLMAME_SOUND_LOG "sound.log"
-
-#ifdef SDLMAME_MACOSX
-/* Vas Crabb: Default GL-lib for MACOSX */
-#define SDLOPTVAL_GLLIB "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
-#else
-#define SDLOPTVAL_GLLIB OSDOPTVAL_AUTO
-#endif
-
//============================================================
// TYPE DEFINITIONS
//============================================================
-class sdl_options : public osd_options
+template <typename EventRecord, typename EventType>
+class event_subscription_manager
{
-public:
- // construction/destruction
- sdl_options();
-
- // performance options
- bool video_fps() const { return bool_value(SDLOPTION_SDLVIDEOFPS); }
+public: // need extra public section for forward declaration
+ class subscriber;
- // video options
- bool centerh() const { return bool_value(SDLOPTION_CENTERH); }
- bool centerv() const { return bool_value(SDLOPTION_CENTERV); }
- const char *scale_mode() const { return value(SDLOPTION_SCALEMODE); }
+private:
+ class impl
+ {
+ public:
+ std::mutex m_mutex;
+ std::unordered_multimap<EventType, subscriber *> m_subs;
+ };
- // full screen options
-#ifdef SDLMAME_X11
- bool use_all_heads() const { return bool_value(SDLOPTION_USEALLHEADS); }
-#endif
+ std::shared_ptr<impl> m_impl;
- // keyboard mapping
- bool keymap() const { return bool_value(SDLOPTION_KEYMAP); }
- const char *keymap_file() const { return value(SDLOPTION_KEYMAP_FILE); }
+protected:
+ event_subscription_manager() : m_impl(new impl)
+ {
+ }
- // joystick mapping
- const char *joy_index(int index) const { return value(string_format("%s%d", SDLOPTION_JOYINDEX, index).c_str()); }
- bool sixaxis() const { return bool_value(SDLOPTION_SIXAXIS); }
+ ~event_subscription_manager() = default;
- const char *mouse_index(int index) const { return value(string_format("%s%d", SDLOPTION_MOUSEINDEX, index).c_str()); }
- const char *keyboard_index(int index) const { return value(string_format("%s%d", SDLOPTION_KEYBINDEX, index).c_str()); }
+ std::mutex &subscription_mutex()
+ {
+ return m_impl->m_mutex;
+ }
- const char *video_driver() const { return value(SDLOPTION_VIDEODRIVER); }
- const char *render_driver() const { return value(SDLOPTION_RENDERDRIVER); }
- const char *audio_driver() const { return value(SDLOPTION_AUDIODRIVER); }
-#if USE_OPENGL
- const char *gl_lib() const { return value(SDLOPTION_GL_LIB); }
-#endif
+ void dispatch_event(EventType const &type, EventRecord const &event)
+ {
+ auto const matches = m_impl->m_subs.equal_range(type);
+ for (auto it = matches.first; matches.second != it; ++it)
+ it->second->handle_event(event);
+ }
-private:
- static const options_entry s_option_entries[];
+public:
+ class subscriber
+ {
+ public:
+ virtual void handle_event(EventRecord const &event) = 0;
+
+ protected:
+ subscriber() = default;
+
+ virtual ~subscriber()
+ {
+ unsubscribe();
+ }
+
+ template <typename T>
+ void subscribe(event_subscription_manager &host, T &&types)
+ {
+ assert(!m_host.lock());
+ assert(host.m_impl);
+
+ m_host = host.m_impl;
+
+ std::lock_guard<std::mutex> lock(host.m_impl->m_mutex);
+ for (auto const &t : types)
+ host.m_impl->m_subs.emplace(t, this);
+ }
+
+ void unsubscribe()
+ {
+ auto const host(m_host.lock());
+ m_host.reset();
+ if (host)
+ {
+ std::lock_guard<std::mutex> lock(host->m_mutex);
+ auto it = host->m_subs.begin();
+ while (host->m_subs.end() != it)
+ {
+ if (it->second == this)
+ it = host->m_subs.erase(it);
+ else
+ ++it;
+ }
+ }
+ }
+
+ private:
+ std::weak_ptr<impl> m_host;
+ };
};
-class sdl_osd_interface : public osd_common_t
+using sdl_event_manager = event_subscription_manager<SDL_Event, uint32_t>;
+
+
+class sdl_window_info;
+
+class sdl_osd_interface : public osd_common_t, public sdl_event_manager
{
public:
// construction/destruction
@@ -122,11 +146,11 @@ public:
// general overridables
virtual void init(running_machine &machine) override;
virtual void update(bool skip_redraw) override;
+ virtual void input_update(bool relative_reset) override;
+ virtual void check_osd_inputs() override;
// input overridables
- virtual void customize_input_type_list(simple_list<input_type_entry> &typelist) override;
-
- virtual void video_register() override;
+ virtual void customize_input_type_list(std::vector<input_type_entry> &typelist) override;
virtual bool video_init() override;
virtual bool window_init() override;
@@ -134,25 +158,53 @@ public:
virtual void video_exit() override;
virtual void window_exit() override;
- // sdl specific
- void poll_inputs(running_machine &machine);
+ // SDL-specific
+ virtual bool has_focus() const override { return bool(m_focus_window); }
void release_keys();
bool should_hide_mouse();
void process_events_buf();
virtual sdl_options &options() override { return m_options; }
-protected:
- virtual void build_slider_list() override;
- virtual void update_slider_list() override;
+ virtual void process_events() override;
private:
+ enum
+ {
+ MODIFIER_KEY_LCTRL = 0x01,
+ MODIFIER_KEY_RCTRL = 0x02,
+ MODIFIER_KEY_LSHIFT = 0x04,
+ MODIFIER_KEY_RSHIFT = 0x08,
+
+ MODIFIER_KEY_CTRL = MODIFIER_KEY_LCTRL | MODIFIER_KEY_RCTRL,
+ MODIFIER_KEY_SHIFT = MODIFIER_KEY_LSHIFT | MODIFIER_KEY_RSHIFT
+ };
+
virtual void osd_exit() override;
void extract_video_config();
void output_oslog(const char *buffer);
+ void process_window_event(SDL_Event const &event);
+ void process_textinput_event(SDL_Event const &event);
+
+ bool mouse_over_window() const { return m_mouse_over_window > 0; }
+ template <typename T> sdl_window_info *focus_window(T const &event) const;
+
+ unsigned map_pointer_device(SDL_TouchID device);
+
sdl_options &m_options;
+ sdl_window_info *m_focus_window;
+ int m_mouse_over_window;
+ uint8_t m_modifier_keys;
+
+ std::chrono::steady_clock::time_point m_last_click_time;
+ int m_last_click_x;
+ int m_last_click_y;
+
+ bool m_enable_touch;
+ unsigned m_next_ptrdev;
+ std::vector<std::pair<SDL_TouchID, unsigned> > m_ptrdev_map;
};
//============================================================
@@ -161,4 +213,4 @@ private:
extern int osd_num_processors;
-#endif
+#endif // MAME_OSD_SDL_OSDSDL_H
diff --git a/src/osd/sdl/sdlmain.cpp b/src/osd/sdl/sdlmain.cpp
index 37d1434a2e8..1933bde1de6 100644
--- a/src/osd/sdl/sdlmain.cpp
+++ b/src/osd/sdl/sdlmain.cpp
@@ -2,12 +2,30 @@
// copyright-holders:Olivier Galibert, R. Belmont
//============================================================
//
-// sdlmain.c - main file for SDLMAME.
+// sdlmain.cpp - main file for SDLMAME.
//
// SDLMAME by Olivier Galibert and R. Belmont
//
//============================================================
+// OSD headers
+#include "osdsdl.h"
+#include "modules/lib/osdlib.h"
+#include "modules/diagnostics/diagnostics_module.h"
+
+// MAME headers
+#include "emu.h"
+#include "emuopts.h"
+#include "main.h"
+#include "video.h"
+
+#include "corestr.h"
+
+#include "osdepend.h"
+#include "strconv.h"
+
+#include <SDL2/SDL.h>
+
// only for oslog callback
#include <functional>
@@ -28,39 +46,6 @@
#include <unistd.h>
#endif
-// only for strconv.h
-#if defined(SDLMAME_WIN32)
-#include <windows.h>
-#endif
-
-#include <SDL2/SDL.h>
-
-// MAME headers
-#include "osdepend.h"
-#include "emu.h"
-#include "emuopts.h"
-#include "strconv.h"
-
-// OSD headers
-#include "video.h"
-#include "osdsdl.h"
-#include "modules/lib/osdlib.h"
-#include "modules/diagnostics/diagnostics_module.h"
-
-//============================================================
-// OPTIONS
-//============================================================
-
-#ifndef INI_PATH
-#if defined(SDLMAME_WIN32)
- #define INI_PATH ".;ini;ini/presets"
-#elif defined(SDLMAME_MACOSX)
- #define INI_PATH "$HOME/Library/Application Support/APP_NAME;$HOME/.APP_NAME;.;ini"
-#else
- #define INI_PATH "$HOME/.APP_NAME;.;ini"
-#endif // MACOSX
-#endif // INI_PATH
-
//============================================================
// Global variables
@@ -70,108 +55,6 @@
int sdl_entered_debugger;
#endif
-//============================================================
-// Local variables
-//============================================================
-
-const options_entry sdl_options::s_option_entries[] =
-{
- { SDLOPTION_INIPATH, INI_PATH, OPTION_STRING, "path to ini files" },
-
- // performance options
- { nullptr, nullptr, OPTION_HEADER, "SDL PERFORMANCE OPTIONS" },
- { SDLOPTION_SDLVIDEOFPS, "0", OPTION_BOOLEAN, "show sdl video performance" },
- // video options
- { nullptr, nullptr, OPTION_HEADER, "SDL VIDEO OPTIONS" },
-// OS X can be trusted to have working hardware OpenGL, so default to it on for the best user experience
- { SDLOPTION_CENTERH, "1", OPTION_BOOLEAN, "center horizontally within the view area" },
- { SDLOPTION_CENTERV, "1", OPTION_BOOLEAN, "center vertically within the view area" },
- { SDLOPTION_SCALEMODE ";sm", OSDOPTVAL_NONE, OPTION_STRING, "Scale mode: none, hwblit, hwbest, yv12, yuy2, yv12x2, yuy2x2 (-video soft only)" },
-
- // full screen options
- #ifdef SDLMAME_X11
- { nullptr, nullptr, OPTION_HEADER, "SDL FULL SCREEN OPTIONS" },
- { SDLOPTION_USEALLHEADS, "0", OPTION_BOOLEAN, "split full screen image across monitors" },
- #endif
-
- // keyboard mapping
- { nullptr, nullptr, OPTION_HEADER, "SDL KEYBOARD MAPPING" },
- { SDLOPTION_KEYMAP, "0", OPTION_BOOLEAN, "enable keymap" },
- { SDLOPTION_KEYMAP_FILE, "keymap.dat", OPTION_STRING, "keymap filename" },
-
- // joystick mapping
- { nullptr, nullptr, OPTION_HEADER, "SDL JOYSTICK MAPPING" },
- { SDLOPTION_JOYINDEX "1", OSDOPTVAL_AUTO, OPTION_STRING, "name of joystick mapped to joystick #1" },
- { SDLOPTION_JOYINDEX "2", OSDOPTVAL_AUTO, OPTION_STRING, "name of joystick mapped to joystick #2" },
- { SDLOPTION_JOYINDEX "3", OSDOPTVAL_AUTO, OPTION_STRING, "name of joystick mapped to joystick #3" },
- { SDLOPTION_JOYINDEX "4", OSDOPTVAL_AUTO, OPTION_STRING, "name of joystick mapped to joystick #4" },
- { SDLOPTION_JOYINDEX "5", OSDOPTVAL_AUTO, OPTION_STRING, "name of joystick mapped to joystick #5" },
- { SDLOPTION_JOYINDEX "6", OSDOPTVAL_AUTO, OPTION_STRING, "name of joystick mapped to joystick #6" },
- { SDLOPTION_JOYINDEX "7", OSDOPTVAL_AUTO, OPTION_STRING, "name of joystick mapped to joystick #7" },
- { SDLOPTION_JOYINDEX "8", OSDOPTVAL_AUTO, OPTION_STRING, "name of joystick mapped to joystick #8" },
- { SDLOPTION_SIXAXIS, "0", OPTION_BOOLEAN, "use special handling for PS3 Sixaxis controllers" },
-
-#if (USE_XINPUT)
- // lightgun mapping
- { nullptr, nullptr, OPTION_HEADER, "SDL LIGHTGUN MAPPING" },
- { SDLOPTION_LIGHTGUNINDEX "1", OSDOPTVAL_AUTO, OPTION_STRING, "name of lightgun mapped to lightgun #1" },
- { SDLOPTION_LIGHTGUNINDEX "2", OSDOPTVAL_AUTO, OPTION_STRING, "name of lightgun mapped to lightgun #2" },
- { SDLOPTION_LIGHTGUNINDEX "3", OSDOPTVAL_AUTO, OPTION_STRING, "name of lightgun mapped to lightgun #3" },
- { SDLOPTION_LIGHTGUNINDEX "4", OSDOPTVAL_AUTO, OPTION_STRING, "name of lightgun mapped to lightgun #4" },
- { SDLOPTION_LIGHTGUNINDEX "5", OSDOPTVAL_AUTO, OPTION_STRING, "name of lightgun mapped to lightgun #5" },
- { SDLOPTION_LIGHTGUNINDEX "6", OSDOPTVAL_AUTO, OPTION_STRING, "name of lightgun mapped to lightgun #6" },
- { SDLOPTION_LIGHTGUNINDEX "7", OSDOPTVAL_AUTO, OPTION_STRING, "name of lightgun mapped to lightgun #7" },
- { SDLOPTION_LIGHTGUNINDEX "8", OSDOPTVAL_AUTO, OPTION_STRING, "name of lightgun mapped to lightgun #8" },
-#endif
-
- { nullptr, nullptr, OPTION_HEADER, "SDL MOUSE MAPPING" },
- { SDLOPTION_MOUSEINDEX "1", OSDOPTVAL_AUTO, OPTION_STRING, "name of mouse mapped to mouse #1" },
- { SDLOPTION_MOUSEINDEX "2", OSDOPTVAL_AUTO, OPTION_STRING, "name of mouse mapped to mouse #2" },
- { SDLOPTION_MOUSEINDEX "3", OSDOPTVAL_AUTO, OPTION_STRING, "name of mouse mapped to mouse #3" },
- { SDLOPTION_MOUSEINDEX "4", OSDOPTVAL_AUTO, OPTION_STRING, "name of mouse mapped to mouse #4" },
- { SDLOPTION_MOUSEINDEX "5", OSDOPTVAL_AUTO, OPTION_STRING, "name of mouse mapped to mouse #5" },
- { SDLOPTION_MOUSEINDEX "6", OSDOPTVAL_AUTO, OPTION_STRING, "name of mouse mapped to mouse #6" },
- { SDLOPTION_MOUSEINDEX "7", OSDOPTVAL_AUTO, OPTION_STRING, "name of mouse mapped to mouse #7" },
- { SDLOPTION_MOUSEINDEX "8", OSDOPTVAL_AUTO, OPTION_STRING, "name of mouse mapped to mouse #8" },
-
- { nullptr, nullptr, OPTION_HEADER, "SDL KEYBOARD MAPPING" },
- { SDLOPTION_KEYBINDEX "1", OSDOPTVAL_AUTO, OPTION_STRING, "name of keyboard mapped to keyboard #1" },
- { SDLOPTION_KEYBINDEX "2", OSDOPTVAL_AUTO, OPTION_STRING, "name of keyboard mapped to keyboard #2" },
- { SDLOPTION_KEYBINDEX "3", OSDOPTVAL_AUTO, OPTION_STRING, "name of keyboard mapped to keyboard #3" },
- { SDLOPTION_KEYBINDEX "4", OSDOPTVAL_AUTO, OPTION_STRING, "name of keyboard mapped to keyboard #4" },
- { SDLOPTION_KEYBINDEX "5", OSDOPTVAL_AUTO, OPTION_STRING, "name of keyboard mapped to keyboard #5" },
- { SDLOPTION_KEYBINDEX "6", OSDOPTVAL_AUTO, OPTION_STRING, "name of keyboard mapped to keyboard #6" },
- { SDLOPTION_KEYBINDEX "7", OSDOPTVAL_AUTO, OPTION_STRING, "name of keyboard mapped to keyboard #7" },
- { SDLOPTION_KEYBINDEX "8", OSDOPTVAL_AUTO, OPTION_STRING, "name of keyboard mapped to keyboard #8" },
-
- // SDL low level driver options
- { nullptr, nullptr, OPTION_HEADER, "SDL LOW-LEVEL DRIVER OPTIONS" },
- { SDLOPTION_VIDEODRIVER ";vd", OSDOPTVAL_AUTO, OPTION_STRING, "SDL video driver to use ('x11', 'directfb', ... or 'auto' for SDL default" },
- { SDLOPTION_RENDERDRIVER ";rd", OSDOPTVAL_AUTO, OPTION_STRING, "SDL render driver to use ('software', 'opengl', 'directfb' ... or 'auto' for SDL default" },
- { SDLOPTION_AUDIODRIVER ";ad", OSDOPTVAL_AUTO, OPTION_STRING, "SDL audio driver to use ('alsa', 'arts', ... or 'auto' for SDL default" },
-#if USE_OPENGL
- { SDLOPTION_GL_LIB, SDLOPTVAL_GLLIB, OPTION_STRING, "alternative libGL.so to use; 'auto' for system default" },
-#endif
-
- // End of list
- { nullptr }
-};
-
-//============================================================
-// sdl_options
-//============================================================
-
-sdl_options::sdl_options()
-: osd_options()
-{
-#if defined (SDLMAME_ANDROID)
- chdir (SDL_AndroidGetExternalStoragePath());
-#endif
- std::string ini_path(INI_PATH);
- add_entries(sdl_options::s_option_entries);
- strreplace(ini_path,"APP_NAME", emulator_info::get_appname_lower());
- set_default_value(SDLOPTION_INIPATH, ini_path.c_str());
-}
//============================================================
// main
@@ -228,290 +111,3 @@ int main(int argc, char** argv)
exit(res);
}
-
-//============================================================
-// constructor
-//============================================================
-
-sdl_osd_interface::sdl_osd_interface(sdl_options &options)
-: osd_common_t(options), m_options(options)
-{
-}
-
-
-//============================================================
-// destructor
-//============================================================
-
-sdl_osd_interface::~sdl_osd_interface()
-{
-}
-
-
-//============================================================
-// osd_exit
-//============================================================
-
-void sdl_osd_interface::osd_exit()
-{
- osd_common_t::osd_exit();
-
- SDL_QuitSubSystem(SDL_INIT_VIDEO);
-}
-
-//============================================================
-// defines_verbose
-//============================================================
-
-#define MAC_EXPAND_STR(_m) #_m
-#define MACRO_VERBOSE(_mac) \
- do { \
- if (strcmp(MAC_EXPAND_STR(_mac), #_mac) != 0) \
- osd_printf_verbose("%s=%s ", #_mac, MAC_EXPAND_STR(_mac)); \
- } while (0)
-
-#define _SDL_VER #SDL_MAJOR_VERSION "." #SDL_MINOR_VERSION "." #SDL_PATCHLEVEL
-
-static void defines_verbose(void)
-{
- osd_printf_verbose("Build version: %s\n", emulator_info::get_build_version());
- osd_printf_verbose("Build architecure: ");
- MACRO_VERBOSE(SDLMAME_ARCH);
- osd_printf_verbose("\n");
- osd_printf_verbose("Build defines 1: ");
- MACRO_VERBOSE(SDLMAME_UNIX);
- MACRO_VERBOSE(SDLMAME_X11);
- MACRO_VERBOSE(SDLMAME_WIN32);
- MACRO_VERBOSE(SDLMAME_MACOSX);
- MACRO_VERBOSE(SDLMAME_DARWIN);
- MACRO_VERBOSE(SDLMAME_LINUX);
- MACRO_VERBOSE(SDLMAME_SOLARIS);
- MACRO_VERBOSE(SDLMAME_IRIX);
- MACRO_VERBOSE(SDLMAME_BSD);
- osd_printf_verbose("\n");
- osd_printf_verbose("Build defines 1: ");
- MACRO_VERBOSE(LSB_FIRST);
- MACRO_VERBOSE(PTR64);
- MACRO_VERBOSE(MAME_NOASM);
- MACRO_VERBOSE(MAME_DEBUG);
- MACRO_VERBOSE(BIGENDIAN);
- MACRO_VERBOSE(CPP_COMPILE);
- MACRO_VERBOSE(SYNC_IMPLEMENTATION);
- osd_printf_verbose("\n");
- osd_printf_verbose("SDL/OpenGL defines: ");
- osd_printf_verbose("SDL_COMPILEDVERSION=%d ", SDL_COMPILEDVERSION);
- MACRO_VERBOSE(USE_OPENGL);
- MACRO_VERBOSE(USE_DISPATCH_GL);
- osd_printf_verbose("\n");
- osd_printf_verbose("Compiler defines A: ");
- MACRO_VERBOSE(__GNUC__);
- MACRO_VERBOSE(__GNUC_MINOR__);
- MACRO_VERBOSE(__GNUC_PATCHLEVEL__);
- MACRO_VERBOSE(__VERSION__);
- osd_printf_verbose("\n");
- osd_printf_verbose("Compiler defines B: ");
- MACRO_VERBOSE(__amd64__);
- MACRO_VERBOSE(__x86_64__);
- MACRO_VERBOSE(__unix__);
- MACRO_VERBOSE(__i386__);
- MACRO_VERBOSE(__ppc__);
- MACRO_VERBOSE(__ppc64__);
- osd_printf_verbose("\n");
- osd_printf_verbose("Compiler defines C: ");
- MACRO_VERBOSE(_FORTIFY_SOURCE);
- MACRO_VERBOSE(__USE_FORTIFY_LEVEL);
- osd_printf_verbose("\n");
-}
-
-//============================================================
-// osd_sdl_info
-//============================================================
-
-static void osd_sdl_info(void)
-{
- int i, num = SDL_GetNumVideoDrivers();
-
- osd_printf_verbose("Available videodrivers: ");
- for (i=0;i<num;i++)
- {
- const char *name = SDL_GetVideoDriver(i);
- osd_printf_verbose("%s ", name);
- }
- osd_printf_verbose("\n");
- osd_printf_verbose("Current Videodriver: %s\n", SDL_GetCurrentVideoDriver());
- num = SDL_GetNumVideoDisplays();
- for (i=0;i<num;i++)
- {
- SDL_DisplayMode mode;
- int j;
-
- osd_printf_verbose("\tDisplay #%d\n", i);
- if (SDL_GetDesktopDisplayMode(i, &mode))
- osd_printf_verbose("\t\tDesktop Mode: %dx%d-%d@%d\n", mode.w, mode.h, SDL_BITSPERPIXEL(mode.format), mode.refresh_rate);
- if (SDL_GetCurrentDisplayMode(i, &mode))
- osd_printf_verbose("\t\tCurrent Display Mode: %dx%d-%d@%d\n", mode.w, mode.h, SDL_BITSPERPIXEL(mode.format), mode.refresh_rate);
- osd_printf_verbose("\t\tRenderdrivers:\n");
- for (j=0; j<SDL_GetNumRenderDrivers(); j++)
- {
- SDL_RendererInfo info;
- SDL_GetRenderDriverInfo(j, &info);
- osd_printf_verbose("\t\t\t%10s (%dx%d)\n", info.name, info.max_texture_width, info.max_texture_height);
- }
- }
-
- osd_printf_verbose("Available audio drivers: \n");
- num = SDL_GetNumAudioDrivers();
- for (i=0;i<num;i++)
- {
- osd_printf_verbose("\t%-20s\n", SDL_GetAudioDriver(i));
- }
-}
-
-
-//============================================================
-// video_register
-//============================================================
-
-void sdl_osd_interface::video_register()
-{
- video_options_add("soft", nullptr);
- video_options_add("accel", nullptr);
-#if USE_OPENGL
- video_options_add("opengl", nullptr);
-#endif
- video_options_add("bgfx", nullptr);
- //video_options_add("auto", nullptr); // making d3d video default one
-}
-
-
-//============================================================
-// output_oslog
-//============================================================
-
-void sdl_osd_interface::output_oslog(const char *buffer)
-{
- fputs(buffer, stderr);
-}
-
-
-//============================================================
-// osd_setup_osd_specific_emu_options
-//============================================================
-
-void osd_setup_osd_specific_emu_options(emu_options &opts)
-{
- opts.add_entries(osd_options::s_option_entries);
-}
-
-
-//============================================================
-// init
-//============================================================
-
-void sdl_osd_interface::init(running_machine &machine)
-{
- // call our parent
- osd_common_t::init(machine);
-
- const char *stemp;
-
- // determine if we are benchmarking, and adjust options appropriately
- int bench = options().bench();
- if (bench > 0)
- {
- options().set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM);
- options().set_value(OSDOPTION_SOUND, "none", OPTION_PRIORITY_MAXIMUM);
- options().set_value(OSDOPTION_VIDEO, "none", OPTION_PRIORITY_MAXIMUM);
- options().set_value(OPTION_SECONDS_TO_RUN, bench, OPTION_PRIORITY_MAXIMUM);
- }
-
- // Some driver options - must be before audio init!
- stemp = options().audio_driver();
- if (stemp != nullptr && strcmp(stemp, OSDOPTVAL_AUTO) != 0)
- {
- osd_printf_verbose("Setting SDL audiodriver '%s' ...\n", stemp);
- osd_setenv(SDLENV_AUDIODRIVER, stemp, 1);
- }
-
- stemp = options().video_driver();
- if (stemp != nullptr && strcmp(stemp, OSDOPTVAL_AUTO) != 0)
- {
- osd_printf_verbose("Setting SDL videodriver '%s' ...\n", stemp);
- osd_setenv(SDLENV_VIDEODRIVER, stemp, 1);
- }
-
- stemp = options().render_driver();
- if (stemp != nullptr)
- {
- if (strcmp(stemp, OSDOPTVAL_AUTO) != 0)
- {
- osd_printf_verbose("Setting SDL renderdriver '%s' ...\n", stemp);
- //osd_setenv(SDLENV_RENDERDRIVER, stemp, 1);
- SDL_SetHint(SDL_HINT_RENDER_DRIVER, stemp);
- }
- else
- {
-#if defined(SDLMAME_WIN32)
- // OpenGL renderer has less issues with mode switching on windows
- osd_printf_verbose("Setting SDL renderdriver '%s' ...\n", "opengl");
- //osd_setenv(SDLENV_RENDERDRIVER, stemp, 1);
- SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
-#endif
- }
- }
-
- /* Set the SDL environment variable for drivers wanting to load the
- * lib at startup.
- */
-#if USE_OPENGL
- /* FIXME: move lib loading code from drawogl.c here */
-
- stemp = options().gl_lib();
- if (stemp != nullptr && strcmp(stemp, OSDOPTVAL_AUTO) != 0)
- {
- osd_setenv("SDL_VIDEO_GL_DRIVER", stemp, 1);
- osd_printf_verbose("Setting SDL_VIDEO_GL_DRIVER = '%s' ...\n", stemp);
- }
-#endif
-
- /* get number of processors */
- stemp = options().numprocessors();
-
- osd_num_processors = 0;
-
- if (strcmp(stemp, "auto") != 0)
- {
- osd_num_processors = atoi(stemp);
- if (osd_num_processors < 1)
- {
- osd_printf_warning("numprocessors < 1 doesn't make much sense. Assuming auto ...\n");
- osd_num_processors = 0;
- }
- }
-
- /* Initialize SDL */
-
- if (SDL_InitSubSystem(SDL_INIT_VIDEO)) {
- osd_printf_error("Could not initialize SDL %s\n", SDL_GetError());
- exit(-1);
- }
- osd_sdl_info();
-
- defines_verbose();
-
- osd_common_t::init_subsystems();
-
- if (options().oslog())
- {
- using namespace std::placeholders;
- machine.add_logerror_callback(std::bind(&sdl_osd_interface::output_oslog, this, _1));
- }
-
-
-
-#ifdef SDLMAME_EMSCRIPTEN
- SDL_EventState(SDL_TEXTINPUT, SDL_FALSE);
-#else
- SDL_EventState(SDL_TEXTINPUT, SDL_TRUE);
-#endif
-}
diff --git a/src/osd/sdl/sdlopts.cpp b/src/osd/sdl/sdlopts.cpp
new file mode 100644
index 00000000000..3953a47b7f8
--- /dev/null
+++ b/src/osd/sdl/sdlopts.cpp
@@ -0,0 +1,127 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert, R. Belmont
+
+#include "sdlopts.h"
+
+// emu
+#include "main.h"
+
+// lib/util
+#include "util/corestr.h"
+
+#include <SDL2/SDL.h>
+
+#include <string>
+
+#if defined(SDLMAME_ANDROID)
+#include "unistd.h"
+#endif
+
+
+namespace {
+
+//============================================================
+// OPTIONS
+//============================================================
+
+#ifndef INI_PATH
+#if defined(SDLMAME_WIN32)
+ #define INI_PATH ".;ini;ini/presets"
+#elif defined(SDLMAME_MACOSX)
+ #define INI_PATH "$HOME/Library/Application Support/APP_NAME;$HOME/.APP_NAME;.;ini"
+#else
+ #define INI_PATH "$HOME/.APP_NAME;.;ini"
+#endif // MACOSX
+#endif // INI_PATH
+
+
+//============================================================
+// Local variables
+//============================================================
+
+const options_entry f_sdl_option_entries[] =
+{
+ { SDLOPTION_INIPATH, INI_PATH, core_options::option_type::MULTIPATH, "path to ini files" },
+
+ // performance options
+ { nullptr, nullptr, core_options::option_type::HEADER, "SDL PERFORMANCE OPTIONS" },
+ { SDLOPTION_SDLVIDEOFPS, "0", core_options::option_type::BOOLEAN, "show sdl video performance" },
+ // video options
+ { nullptr, nullptr, core_options::option_type::HEADER, "SDL VIDEO OPTIONS" },
+// OS X can be trusted to have working hardware OpenGL, so default to it on for the best user experience
+ { SDLOPTION_CENTERH, "1", core_options::option_type::BOOLEAN, "center horizontally within the view area" },
+ { SDLOPTION_CENTERV, "1", core_options::option_type::BOOLEAN, "center vertically within the view area" },
+ { SDLOPTION_SCALEMODE ";sm", OSDOPTVAL_NONE, core_options::option_type::STRING, "Scale mode: none, hwblit, hwbest, yv12, yuy2, yv12x2, yuy2x2 (-video soft only)" },
+
+ // full screen options
+#ifdef SDLMAME_X11
+ { nullptr, nullptr, core_options::option_type::HEADER, "SDL FULL SCREEN OPTIONS" },
+ { SDLOPTION_USEALLHEADS, "0", core_options::option_type::BOOLEAN, "split full screen image across monitors" },
+ { SDLOPTION_ATTACH_WINDOW, "", core_options::option_type::STRING, "attach to arbitrary window" },
+#endif // SDLMAME_X11
+
+ // keyboard mapping
+ { nullptr, nullptr, core_options::option_type::HEADER, "SDL KEYBOARD MAPPING" },
+ { SDLOPTION_KEYMAP, "0", core_options::option_type::BOOLEAN, "enable keymap" },
+ { SDLOPTION_KEYMAP_FILE, "keymap.dat", core_options::option_type::PATH, "keymap filename" },
+
+ // joystick mapping
+ { nullptr, nullptr, core_options::option_type::HEADER, "SDL INPUT OPTIONS" },
+ { SDLOPTION_ENABLE_TOUCH, "0", core_options::option_type::BOOLEAN, "enable touch input support" },
+ { SDLOPTION_SIXAXIS, "0", core_options::option_type::BOOLEAN, "use special handling for PS3 Sixaxis controllers" },
+ { SDLOPTION_DUAL_LIGHTGUN ";dual", "0", core_options::option_type::BOOLEAN, "enable dual lightgun input" },
+
+#if (USE_XINPUT)
+ // lightgun mapping
+ { nullptr, nullptr, core_options::option_type::HEADER, "SDL LIGHTGUN MAPPING" },
+ { SDLOPTION_LIGHTGUNINDEX "1", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #1" },
+ { SDLOPTION_LIGHTGUNINDEX "2", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #2" },
+ { SDLOPTION_LIGHTGUNINDEX "3", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #3" },
+ { SDLOPTION_LIGHTGUNINDEX "4", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #4" },
+ { SDLOPTION_LIGHTGUNINDEX "5", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #5" },
+ { SDLOPTION_LIGHTGUNINDEX "6", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #6" },
+ { SDLOPTION_LIGHTGUNINDEX "7", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #7" },
+ { SDLOPTION_LIGHTGUNINDEX "8", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #8" },
+#endif
+
+ // SDL low level driver options
+ { nullptr, nullptr, core_options::option_type::HEADER, "SDL LOW-LEVEL DRIVER OPTIONS" },
+ { SDLOPTION_VIDEODRIVER ";vd", OSDOPTVAL_AUTO, core_options::option_type::STRING, "SDL video driver to use ('x11', 'directfb', ... or 'auto' for SDL default" },
+ { SDLOPTION_RENDERDRIVER ";rd", OSDOPTVAL_AUTO, core_options::option_type::STRING, "SDL render driver to use ('software', 'opengl', 'directfb' ... or 'auto' for SDL default" },
+ { SDLOPTION_AUDIODRIVER ";ad", OSDOPTVAL_AUTO, core_options::option_type::STRING, "SDL audio driver to use ('alsa', 'arts', ... or 'auto' for SDL default" },
+#if USE_OPENGL
+ { SDLOPTION_GL_LIB, SDLOPTVAL_GLLIB, core_options::option_type::STRING, "alternative libGL.so to use; 'auto' for system default" },
+#endif
+
+ // End of list
+ { nullptr }
+};
+
+} // anonymous namespace
+
+
+//============================================================
+// sdl_options
+//============================================================
+
+sdl_options::sdl_options() : osd_options()
+{
+#if defined(SDLMAME_ANDROID)
+ chdir(SDL_AndroidGetExternalStoragePath()); // FIXME: why is this here of all places?
+#endif
+ std::string ini_path(INI_PATH);
+ add_entries(f_sdl_option_entries);
+ strreplace(ini_path, "APP_NAME", emulator_info::get_appname_lower());
+ set_default_value(SDLOPTION_INIPATH, std::move(ini_path));
+}
+
+
+//============================================================
+// osd_setup_osd_specific_emu_options
+//============================================================
+
+void osd_setup_osd_specific_emu_options(emu_options &opts)
+{
+ opts.add_entries(osd_options::s_option_entries);
+ opts.add_entries(f_sdl_option_entries);
+}
diff --git a/src/osd/sdl/sdlopts.h b/src/osd/sdl/sdlopts.h
new file mode 100644
index 00000000000..f6338fe1db6
--- /dev/null
+++ b/src/osd/sdl/sdlopts.h
@@ -0,0 +1,100 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert, R. Belmont
+#ifndef MAME_OSD_SDL_SDLOPTS_H
+#define MAME_OSD_SDL_SDLOPTS_H
+
+#pragma once
+
+#include "modules/lib/osdobj_common.h"
+
+
+//============================================================
+// Option identifiers
+//============================================================
+
+#define SDLOPTION_INIPATH "inipath"
+#define SDLOPTION_SDLVIDEOFPS "sdlvideofps"
+#define SDLOPTION_USEALLHEADS "useallheads"
+#define SDLOPTION_ATTACH_WINDOW "attach_window"
+#define SDLOPTION_CENTERH "centerh"
+#define SDLOPTION_CENTERV "centerv"
+
+#define SDLOPTION_SCALEMODE "scalemode"
+
+#define SDLOPTION_WAITVSYNC "waitvsync"
+#define SDLOPTION_SYNCREFRESH "syncrefresh"
+#define SDLOPTION_KEYMAP "keymap"
+#define SDLOPTION_KEYMAP_FILE "keymap_file"
+
+#define SDLOPTION_ENABLE_TOUCH "enable_touch"
+#define SDLOPTION_SIXAXIS "sixaxis"
+#define SDLOPTION_DUAL_LIGHTGUN "dual_lightgun"
+#if defined(USE_XINPUT) && USE_XINPUT
+#define SDLOPTION_LIGHTGUNINDEX "lightgun_index"
+#endif
+
+#define SDLOPTION_AUDIODRIVER "audiodriver"
+#define SDLOPTION_VIDEODRIVER "videodriver"
+#define SDLOPTION_RENDERDRIVER "renderdriver"
+#define SDLOPTION_GL_LIB "gl_lib"
+
+
+//============================================================
+// Option values
+//============================================================
+
+#define SDLOPTVAL_OPENGL "opengl"
+#define SDLOPTVAL_SOFT "soft"
+#define SDLOPTVAL_SDL2ACCEL "accel"
+#define SDLOPTVAL_BGFX "bgfx"
+
+#ifdef SDLMAME_MACOSX
+/* Vas Crabb: Default GL-lib for MACOSX */
+#define SDLOPTVAL_GLLIB "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
+#else
+#define SDLOPTVAL_GLLIB OSDOPTVAL_AUTO
+#endif
+
+
+//============================================================
+// TYPE DEFINITIONS
+//============================================================
+
+class sdl_options : public osd_options
+{
+public:
+ // construction/destruction
+ sdl_options();
+
+ // performance options
+ bool video_fps() const { return bool_value(SDLOPTION_SDLVIDEOFPS); }
+
+ // video options
+ bool centerh() const { return bool_value(SDLOPTION_CENTERH); }
+ bool centerv() const { return bool_value(SDLOPTION_CENTERV); }
+ const char *scale_mode() const { return value(SDLOPTION_SCALEMODE); }
+
+ // full screen options
+#if defined(SDLMAME_X11)
+ bool use_all_heads() const { return bool_value(SDLOPTION_USEALLHEADS); }
+ const char *attach_window() const { return value(SDLOPTION_ATTACH_WINDOW); }
+#endif // SDLMAME_X11
+
+ // keyboard mapping
+ bool keymap() const { return bool_value(SDLOPTION_KEYMAP); }
+ const char *keymap_file() const { return value(SDLOPTION_KEYMAP_FILE); }
+
+ // input options
+ bool enable_touch() const { return bool_value(SDLOPTION_ENABLE_TOUCH); }
+ bool sixaxis() const { return bool_value(SDLOPTION_SIXAXIS); }
+ bool dual_lightgun() const { return bool_value(SDLOPTION_DUAL_LIGHTGUN); }
+
+ const char *video_driver() const { return value(SDLOPTION_VIDEODRIVER); }
+ const char *render_driver() const { return value(SDLOPTION_RENDERDRIVER); }
+ const char *audio_driver() const { return value(SDLOPTION_AUDIODRIVER); }
+#if USE_OPENGL
+ const char *gl_lib() const { return value(SDLOPTION_GL_LIB); }
+#endif
+};
+
+#endif // MAME_OSD_SDL_SDLOPTS_H
diff --git a/src/osd/sdl/taputil.sh b/src/osd/sdl/taputil.sh
index 1a22048b9ca..c230d7c19f8 100644..100755
--- a/src/osd/sdl/taputil.sh
+++ b/src/osd/sdl/taputil.sh
@@ -22,9 +22,9 @@ ip tuntap del dev $TAP mode tap
exit
fi
-if [ "$#" != "5" ]
+if [ "$#" != "4" ]
then
-echo "usage: mess-tap [-c] [-d] USER EMUADDR HOSTADDR MASK"
+echo "usage: mess-tap [-c] [-d] USER EMUADDR HOSTADDR"
echo "-c create interface"
echo "-d delete interface"
echo "USER user to own interface, required to delete"
diff --git a/src/osd/sdl/video.cpp b/src/osd/sdl/video.cpp
index 88bc1b51ce4..8fe836aabf2 100644
--- a/src/osd/sdl/video.cpp
+++ b/src/osd/sdl/video.cpp
@@ -2,30 +2,28 @@
// copyright-holders:Olivier Galibert, R. Belmont
//============================================================
//
-// video.c - SDL video handling
+// video.cpp - SDL video handling
//
// SDLMAME by Olivier Galibert and R. Belmont
//
//============================================================
-#include <SDL2/SDL.h>
-
-// MAME headers
-#include "emu.h"
-#include "rendutil.h"
-#include "ui/uimain.h"
-#include "emuopts.h"
-#include "uiinput.h"
+#include "window.h"
// MAMEOS headers
-#include "video.h"
-#include "window.h"
#include "osdsdl.h"
#include "modules/lib/osdlib.h"
+#include "modules/monitor/monitor_module.h"
+#include "modules/render/render_module.h"
-//============================================================
-// CONSTANTS
-//============================================================
+// MAME headers
+#include "emu.h"
+#include "emuopts.h"
+#include "main.h"
+#include "rendutil.h"
+#include "uiinput.h"
+
+#include <SDL2/SDL.h>
//============================================================
@@ -34,17 +32,11 @@
osd_video_config video_config;
-//============================================================
-// LOCAL VARIABLES
-//============================================================
-
//============================================================
// PROTOTYPES
//============================================================
-static void check_osd_inputs(running_machine &machine);
-
static void get_resolution(const char *defdata, const char *data, osd_window_config *config, int report_error);
@@ -70,16 +62,19 @@ bool sdl_osd_interface::video_init()
for (index = 0; index < video_config.numscreens; index++)
{
osd_window_config conf;
- memset(&conf, 0, sizeof(conf));
get_resolution(options().resolution(), options().resolution(index), &conf, true);
// create window ...
- std::shared_ptr<sdl_window_info> win = std::make_shared<sdl_window_info>(machine(), index, m_monitor_module->pick_monitor(reinterpret_cast<osd_options &>(options()), index), &conf);
-
+ auto win = std::make_unique<sdl_window_info>(machine(), *m_render, index, m_monitor_module->pick_monitor(reinterpret_cast<osd_options &>(options()), index), &conf);
if (win->window_init())
return false;
+
+ s_window_list.emplace_back(std::move(win));
}
+ if (m_render->is_interactive())
+ SDL_RaiseWindow(dynamic_cast<sdl_window_info &>(*osd_common_t::s_window_list.front()).platform_window());
+
return true;
}
@@ -104,86 +99,29 @@ void sdl_osd_interface::update(bool skip_redraw)
if (!skip_redraw)
{
// profiler_mark(PROFILER_BLIT);
- for (auto window : osd_common_t::s_window_list)
+ for (auto const &window : osd_common_t::window_list())
window->update();
// profiler_mark(PROFILER_END);
}
- // poll the joystick values here
- downcast<sdl_osd_interface&>(machine().osd()).poll_inputs(machine());
-
- check_osd_inputs(machine());
// if we're running, disable some parts of the debugger
if ((machine().debug_flags & DEBUG_FLAG_OSD_ENABLED) != 0)
debugger_update();
}
//============================================================
-// check_osd_inputs
-//============================================================
-
-static void check_osd_inputs(running_machine &machine)
-{
- // check for toggling fullscreen mode
- if (machine.ui_input().pressed(IPT_OSD_1))
- {
- for (auto curwin : osd_common_t::s_window_list)
- std::static_pointer_cast<sdl_window_info>(curwin)->toggle_full_screen();
- }
-
- auto window = osd_common_t::s_window_list.front();
- if (machine.ui_input().pressed(IPT_OSD_2))
- {
- //FIXME: on a per window basis
- video_config.fullstretch = !video_config.fullstretch;
- window->target()->set_scale_mode(video_config.fullstretch? SCALE_FRACTIONAL : SCALE_INTEGER);
- machine.ui().popup_time(1, "Uneven stretch %s", video_config.fullstretch? "enabled":"disabled");
- }
-
- if (machine.ui_input().pressed(IPT_OSD_4))
- {
- //FIXME: on a per window basis
- video_config.keepaspect = !video_config.keepaspect;
- window->target()->set_keepaspect(video_config.keepaspect);
- machine.ui().popup_time(1, "Keepaspect %s", video_config.keepaspect? "enabled":"disabled");
- }
-
- #if (USE_OPENGL)
- //FIXME: on a per window basis
- if (machine.ui_input().pressed(IPT_OSD_5))
- {
- video_config.filter = !video_config.filter;
- machine.ui().popup_time(1, "Filter %s", video_config.filter? "enabled":"disabled");
- }
- #endif
-
- if (machine.ui_input().pressed(IPT_OSD_6))
- std::static_pointer_cast<sdl_window_info>(window)->modify_prescale(-1);
-
- if (machine.ui_input().pressed(IPT_OSD_7))
- std::static_pointer_cast<sdl_window_info>(window)->modify_prescale(1);
-
- if (machine.ui_input().pressed(IPT_OSD_8))
- window->renderer().record();
-}
-
-//============================================================
// extract_video_config
//============================================================
void sdl_osd_interface::extract_video_config()
{
- const char *stemp;
-
video_config.perftest = options().video_fps();
// global options: extract the data
video_config.windowed = options().window();
video_config.prescale = options().prescale();
video_config.filter = options().filter();
- video_config.keepaspect = options().keep_aspect();
video_config.numscreens = options().numscreens();
- video_config.fullstretch = options().uneven_stretch();
#ifdef SDLMAME_X11
video_config.restrictonemonitor = !options().use_all_heads();
#endif
@@ -192,49 +130,6 @@ void sdl_osd_interface::extract_video_config()
if (machine().debug_flags & DEBUG_FLAG_OSD_ENABLED)
video_config.windowed = true;
- // default to working video please
- video_config.novideo = 0;
-
- // d3d options: extract the data
- stemp = options().video();
- if (strcmp(stemp, "auto") == 0)
- {
-#if (defined SDLMAME_MACOSX || defined SDLMAME_WIN32)
- stemp = "opengl";
-#elif (defined __STEAMLINK__)
- stemp = "bgfx";
-#else
- stemp = "soft";
-#endif
- }
- if (strcmp(stemp, SDLOPTVAL_SOFT) == 0)
- video_config.mode = VIDEO_MODE_SOFT;
- else if (strcmp(stemp, OSDOPTVAL_NONE) == 0)
- {
- video_config.mode = VIDEO_MODE_SOFT;
- video_config.novideo = 1;
-
- if (!emulator_info::standalone() && options().seconds_to_run() == 0)
- osd_printf_warning("Warning: -video none doesn't make much sense without -seconds_to_run\n");
- }
-#if (USE_OPENGL)
- else if (strcmp(stemp, SDLOPTVAL_OPENGL) == 0)
- video_config.mode = VIDEO_MODE_OPENGL;
-#endif
- else if ((strcmp(stemp, SDLOPTVAL_SDL2ACCEL) == 0))
- {
- video_config.mode = VIDEO_MODE_SDL2ACCEL;
- }
- else if (strcmp(stemp, SDLOPTVAL_BGFX) == 0)
- {
- video_config.mode = VIDEO_MODE_BGFX;
- }
- else
- {
- osd_printf_warning("Invalid video value %s; reverting to software\n", stemp);
- video_config.mode = VIDEO_MODE_SOFT;
- }
-
video_config.switchres = options().switch_res();
video_config.centerh = options().centerh();
video_config.centerv = options().centerv();
@@ -246,69 +141,12 @@ void sdl_osd_interface::extract_video_config()
video_config.syncrefresh = 0;
}
- if (video_config.prescale < 1 || video_config.prescale > 3)
+ if (video_config.prescale < 1 || video_config.prescale > 20)
{
osd_printf_warning("Invalid prescale option, reverting to '1'\n");
video_config.prescale = 1;
}
- #if (USE_OPENGL)
- // default to working video please
- video_config.forcepow2texture = options().gl_force_pow2_texture();
- video_config.allowtexturerect = !(options().gl_no_texture_rect());
- video_config.vbo = options().gl_vbo();
- video_config.pbo = options().gl_pbo();
- video_config.glsl = options().gl_glsl();
- if ( video_config.glsl )
- {
- int i;
-
- video_config.glsl_filter = options().glsl_filter();
-
- video_config.glsl_shader_mamebm_num=0;
-
- for(i=0; i<GLSL_SHADER_MAX; i++)
- {
- stemp = options().shader_mame(i);
- if (stemp && strcmp(stemp, OSDOPTVAL_NONE) != 0 && strlen(stemp)>0)
- {
- video_config.glsl_shader_mamebm[i] = (char *) malloc(strlen(stemp)+1);
- strcpy(video_config.glsl_shader_mamebm[i], stemp);
- video_config.glsl_shader_mamebm_num++;
- } else {
- video_config.glsl_shader_mamebm[i] = nullptr;
- }
- }
-
- video_config.glsl_shader_scrn_num=0;
-
- for(i=0; i<GLSL_SHADER_MAX; i++)
- {
- stemp = options().shader_screen(i);
- if (stemp && strcmp(stemp, OSDOPTVAL_NONE) != 0 && strlen(stemp)>0)
- {
- video_config.glsl_shader_scrn[i] = (char *) malloc(strlen(stemp)+1);
- strcpy(video_config.glsl_shader_scrn[i], stemp);
- video_config.glsl_shader_scrn_num++;
- } else {
- video_config.glsl_shader_scrn[i] = nullptr;
- }
- }
- } else {
- int i;
- video_config.glsl_filter = 0;
- video_config.glsl_shader_mamebm_num=0;
- for(i=0; i<GLSL_SHADER_MAX; i++)
- {
- video_config.glsl_shader_mamebm[i] = nullptr;
- }
- video_config.glsl_shader_scrn_num=0;
- for(i=0; i<GLSL_SHADER_MAX; i++)
- {
- video_config.glsl_shader_scrn[i] = nullptr;
- }
- }
-
- #endif /* USE_OPENGL */
+
// misc options: sanity check values
// global options: sanity check values
@@ -317,19 +155,6 @@ void sdl_osd_interface::extract_video_config()
osd_printf_warning("Invalid numscreens value %d; reverting to 1\n", video_config.numscreens);
video_config.numscreens = 1;
}
- // yuv settings ...
- stemp = options().scale_mode();
- video_config.scale_mode = drawsdl_scale_mode(stemp);
- if (video_config.scale_mode < 0)
- {
- osd_printf_warning("Invalid yuvmode value %s; reverting to none\n", stemp);
- video_config.scale_mode = VIDEO_SCALE_MODE_NONE;
- }
- if ( (video_config.mode != VIDEO_MODE_SOFT) && (video_config.scale_mode != VIDEO_SCALE_MODE_NONE) )
- {
- osd_printf_warning("scalemode is only for -video soft, overriding\n");
- video_config.scale_mode = VIDEO_SCALE_MODE_NONE;
- }
}
diff --git a/src/osd/sdl/window.cpp b/src/osd/sdl/window.cpp
index 875e06a7b3d..59be82238d0 100644
--- a/src/osd/sdl/window.cpp
+++ b/src/osd/sdl/window.cpp
@@ -8,40 +8,38 @@
//
//============================================================
-#ifdef SDLMAME_WIN32
-#include <windows.h>
-#endif
-
-// standard SDL headers
-#include <SDL2/SDL.h>
-
-// standard C headers
-#include <math.h>
-#ifndef _MSC_VER
-#include <unistd.h>
-#endif
-#include <list>
-#include <memory>
-
// MAME headers
-
#include "emu.h"
#include "emuopts.h"
#include "render.h"
+#include "screen.h"
+#include "uiinput.h"
#include "ui/uimain.h"
// OSD headers
-
-#include "window.h"
-#include "osdsdl.h"
-#include "modules/render/drawbgfx.h"
-#include "modules/render/drawsdl.h"
-#include "modules/render/draw13.h"
#include "modules/monitor/monitor_common.h"
-#if (USE_OPENGL)
-#include "modules/render/drawogl.h"
+#include "osdsdl.h"
+#include "window.h"
+
+// standard SDL headers
+#include <SDL2/SDL_syswm.h>
+
+// standard C headers
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <list>
+#include <memory>
+
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+
+#ifdef SDLMAME_WIN32
+#include <windows.h>
#endif
+
//============================================================
// PARAMETERS
//============================================================
@@ -66,19 +64,6 @@
#define SDL_VERSION_EQUALS(v1, vnum2) (SDL_VERSIONNUM(v1.major, v1.minor, v1.patch) == vnum2)
-class SDL_DM_Wrapper
-{
-public:
- SDL_DisplayMode mode;
-};
-
-// debugger
-//static int in_background;
-
-
-//============================================================
-// PROTOTYPES
-//============================================================
//============================================================
@@ -90,30 +75,10 @@ bool sdl_osd_interface::window_init()
{
osd_printf_verbose("Enter sdlwindow_init\n");
- // initialize the drawers
-
- switch (video_config.mode)
- {
- case VIDEO_MODE_BGFX:
- renderer_bgfx::init(machine());
- break;
-#if (USE_OPENGL)
- case VIDEO_MODE_OPENGL:
- renderer_ogl::init(machine());
- break;
-#endif
- case VIDEO_MODE_SDL2ACCEL:
- renderer_sdl2::init(machine());
- break;
- case VIDEO_MODE_SOFT:
- renderer_sdl1::init(machine());
- break;
- }
-
- /* We may want to set a number of the hints SDL2 provides.
- * The code below will document which hints were set.
- */
- const char * hints[] = { SDL_HINT_FRAMEBUFFER_ACCELERATION,
+ // We may want to set a number of the hints SDL2 provides.
+ // The code below will document which hints were set.
+ char const *const hints[] = {
+ SDL_HINT_FRAMEBUFFER_ACCELERATION,
SDL_HINT_RENDER_DRIVER, SDL_HINT_RENDER_OPENGL_SHADERS,
SDL_HINT_RENDER_SCALE_QUALITY,
SDL_HINT_RENDER_VSYNC,
@@ -124,23 +89,21 @@ bool sdl_osd_interface::window_init()
SDL_HINT_XINPUT_ENABLED, SDL_HINT_GAMECONTROLLERCONFIG,
SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, SDL_HINT_ALLOW_TOPMOST,
SDL_HINT_TIMER_RESOLUTION,
-#if SDL_VERSION_ATLEAST(2, 0, 2)
SDL_HINT_RENDER_DIRECT3D_THREADSAFE, SDL_HINT_VIDEO_ALLOW_SCREENSAVER,
SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK,
SDL_HINT_VIDEO_WIN_D3DCOMPILER, SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT,
SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES, SDL_HINT_MOUSE_RELATIVE_MODE_WARP,
-#endif
-#if SDL_VERSION_ATLEAST(2, 0, 3)
SDL_HINT_RENDER_DIRECT3D11_DEBUG, SDL_HINT_VIDEO_HIGHDPI_DISABLED,
SDL_HINT_WINRT_PRIVACY_POLICY_URL, SDL_HINT_WINRT_PRIVACY_POLICY_LABEL,
SDL_HINT_WINRT_HANDLE_BACK_BUTTON,
-#endif
- nullptr
- };
+ };
osd_printf_verbose("\nHints:\n");
- for (int i = 0; hints[i] != nullptr; i++)
- osd_printf_verbose("\t%-40s %s\n", hints[i], SDL_GetHint(hints[i]));
+ for (auto const hintname : hints)
+ {
+ char const *const hintvalue(SDL_GetHint(hintname));
+ osd_printf_verbose("\t%-40s %s\n", hintname, hintvalue ? hintvalue : "(NULL)");
+ }
// set up the window list
osd_printf_verbose("Leave sdlwindow_init\n");
@@ -148,30 +111,6 @@ bool sdl_osd_interface::window_init()
}
-void sdl_osd_interface::update_slider_list()
-{
- for (auto window : osd_common_t::s_window_list)
- {
- // check if any window has dirty sliders
- if (window->renderer().sliders_dirty())
- {
- build_slider_list();
- return;
- }
- }
-}
-
-void sdl_osd_interface::build_slider_list()
-{
- m_sliders.clear();
-
- for (auto window : osd_common_t::s_window_list)
- {
- std::vector<ui::menu_item> window_sliders = window->renderer().get_slider_list();
- m_sliders.insert(m_sliders.end(), window_sliders.begin(), window_sliders.end());
- }
-}
-
//============================================================
// sdlwindow_exit
// (main thread)
@@ -182,33 +121,14 @@ void sdl_osd_interface::window_exit()
osd_printf_verbose("Enter sdlwindow_exit\n");
// free all the windows
+ m_focus_window = nullptr;
while (!osd_common_t::s_window_list.empty())
{
- auto window = osd_common_t::s_window_list.front();
-
- // Part of destroy removes the window from the list
+ auto window = std::move(osd_common_t::s_window_list.back());
+ s_window_list.pop_back();
window->destroy();
}
- switch(video_config.mode)
- {
- case VIDEO_MODE_SDL2ACCEL:
- renderer_sdl1::exit();
- break;
- case VIDEO_MODE_SOFT:
- renderer_sdl1::exit();
- break;
- case VIDEO_MODE_BGFX:
- renderer_bgfx::exit();
- break;
-#if (USE_OPENGL)
- case VIDEO_MODE_OPENGL:
- renderer_ogl::exit();
- break;
-#endif
- default:
- break;
- }
osd_printf_verbose("Leave sdlwindow_exit\n");
}
@@ -293,8 +213,6 @@ void sdl_window_info::toggle_full_screen()
m_windowed_dim = get_size();
}
- // reset UI to main menu
- machine().ui().menu_reset();
// kill off the drawers
renderer_reset();
bool is_osx = false;
@@ -304,17 +222,14 @@ void sdl_window_info::toggle_full_screen()
#endif
if (fullscreen() && (video_config.switchres || is_osx))
{
- SDL_SetWindowFullscreen(platform_window(), 0); // Try to set mode
- SDL_SetWindowDisplayMode(platform_window(), &m_original_mode->mode); // Try to set mode
- SDL_SetWindowFullscreen(platform_window(), SDL_WINDOW_FULLSCREEN); // Try to set mode
+ SDL_SetWindowFullscreen(platform_window(), 0);
+ SDL_SetWindowDisplayMode(platform_window(), &m_original_mode);
+ SDL_SetWindowFullscreen(platform_window(), SDL_WINDOW_FULLSCREEN);
}
SDL_DestroyWindow(platform_window());
set_platform_window(nullptr);
-
downcast<sdl_osd_interface &>(machine().osd()).release_keys();
- set_renderer(osd_renderer::make_for_type(video_config.mode, shared_from_this()));
-
// toggle the window mode
set_fullscreen(!fullscreen());
@@ -325,7 +240,7 @@ void sdl_window_info::modify_prescale(int dir)
{
int new_prescale = prescale();
- if (dir > 0 && prescale() < 3)
+ if (dir > 0 && prescale() < 20)
new_prescale = prescale() + 1;
if (dir < 0 && prescale() > 1)
new_prescale = prescale() - 1;
@@ -342,11 +257,11 @@ void sdl_window_info::modify_prescale(int dir)
}
else
{
- notify_changed();
m_prescale = new_prescale;
+ notify_changed();
}
- machine().ui().popup_time(1, "Prescale %d", prescale());
}
+ machine().ui().popup_time(1, "Prescale %d", prescale());
}
//============================================================
@@ -393,6 +308,291 @@ int sdl_window_info::xy_to_render_target(int x, int y, int *xt, int *yt)
return renderer().xy_to_render_target(x, y, xt, yt);
}
+void sdl_window_info::mouse_entered(unsigned device)
+{
+ m_mouse_inside = true;
+}
+
+void sdl_window_info::mouse_left(unsigned device)
+{
+ m_mouse_inside = false;
+
+ auto info(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), SDL_FingerID(-1), &sdl_pointer_info::compare));
+ if ((m_active_pointers.end() == info) || (info->finger != SDL_FingerID(-1)))
+ return;
+
+ // leaving implicitly releases buttons, so check hold/drag if necessary
+ if (BIT(info->buttons, 0) && (0 < info->clickcnt))
+ {
+ auto const now(std::chrono::steady_clock::now());
+ auto const exp(std::chrono::milliseconds(250) + info->pressed);
+ int const dx(info->x - info->pressedx);
+ int const dy(info->y - info->pressedy);
+ int const distance((dx * dx) + (dy * dy));
+ if ((exp < now) || (CLICK_DISTANCE < distance))
+ info->clickcnt = -info->clickcnt;
+ }
+
+ // push to UI manager
+ machine().ui_input().push_pointer_leave(
+ target(),
+ osd::ui_event_handler::pointer::MOUSE,
+ info->index,
+ device,
+ info->x, info->y,
+ info->buttons, info->clickcnt);
+
+ // dump pointer data
+ m_pointer_mask &= ~(decltype(m_pointer_mask)(1) << info->index);
+ if (info->index < m_next_pointer)
+ m_next_pointer = info->index;
+ m_active_pointers.erase(info);
+}
+
+void sdl_window_info::mouse_down(unsigned device, int x, int y, unsigned button)
+{
+ if (!m_mouse_inside)
+ return;
+
+ auto const info(map_pointer(SDL_FingerID(-1), device));
+ if (m_active_pointers.end() == info)
+ return;
+
+ if ((x == info->x) && (y == info->y) && BIT(info->buttons, button))
+ return;
+
+ // detect multi-click actions
+ if (0 == button)
+ {
+ info->primary_down(
+ x,
+ y,
+ std::chrono::milliseconds(250),
+ CLICK_DISTANCE,
+ false,
+ m_ptrdev_info);
+ }
+
+ // update info and push to UI manager
+ auto const pressed(decltype(info->buttons)(1) << button);
+ info->x = x;
+ info->y = y;
+ info->buttons |= pressed;
+ machine().ui_input().push_pointer_update(
+ target(),
+ osd::ui_event_handler::pointer::MOUSE,
+ info->index,
+ device,
+ x, y,
+ info->buttons, pressed, 0, info->clickcnt);
+}
+
+void sdl_window_info::mouse_up(unsigned device, int x, int y, unsigned button)
+{
+ if (!m_mouse_inside)
+ return;
+
+ auto const info(map_pointer(SDL_FingerID(-1), device));
+ if (m_active_pointers.end() == info)
+ return;
+
+ if ((x == info->x) && (y == info->y) && !BIT(info->buttons, button))
+ return;
+
+ // detect multi-click actions
+ if (0 == button)
+ {
+ info->check_primary_hold_drag(
+ x,
+ y,
+ std::chrono::milliseconds(250),
+ CLICK_DISTANCE);
+ }
+
+ // update info and push to UI manager
+ auto const released(decltype(info->buttons)(1) << button);
+ info->x = x;
+ info->y = y;
+ info->buttons &= ~released;
+ machine().ui_input().push_pointer_update(
+ target(),
+ osd::ui_event_handler::pointer::MOUSE,
+ info->index,
+ device,
+ x, y,
+ info->buttons, 0, released, info->clickcnt);
+}
+
+void sdl_window_info::mouse_moved(unsigned device, int x, int y)
+{
+ if (!m_mouse_inside)
+ return;
+
+ auto const info(map_pointer(SDL_FingerID(-1), device));
+ if (m_active_pointers.end() == info)
+ return;
+
+ // detect multi-click actions
+ if (BIT(info->buttons, 0))
+ {
+ info->check_primary_hold_drag(
+ x,
+ y,
+ std::chrono::milliseconds(250),
+ CLICK_DISTANCE);
+ }
+
+ // update info and push to UI manager
+ info->x = x;
+ info->y = y;
+ machine().ui_input().push_pointer_update(
+ target(),
+ osd::ui_event_handler::pointer::MOUSE,
+ info->index,
+ device,
+ x, y,
+ info->buttons, 0, 0, info->clickcnt);
+}
+
+void sdl_window_info::mouse_wheel(unsigned device, int y)
+{
+ if (!m_mouse_inside)
+ return;
+
+ auto const info(map_pointer(SDL_FingerID(-1), device));
+ if (m_active_pointers.end() == info)
+ return;
+
+ // push to UI manager
+ machine().ui_input().push_mouse_wheel_event(target(), info->x, info->y, y, 3);
+}
+
+void sdl_window_info::finger_down(SDL_FingerID finger, unsigned device, int x, int y)
+{
+ auto const info(map_pointer(finger, device));
+ if (m_active_pointers.end() == info)
+ return;
+
+ assert(!info->buttons);
+
+ // detect multi-click actions
+ info->primary_down(
+ x,
+ y,
+ std::chrono::milliseconds(250),
+ TAP_DISTANCE,
+ true,
+ m_ptrdev_info);
+
+ // update info and push to UI manager
+ info->x = x;
+ info->y = y;
+ info->buttons = 1;
+ machine().ui_input().push_pointer_update(
+ target(),
+ osd::ui_event_handler::pointer::TOUCH,
+ info->index,
+ device,
+ x, y,
+ 1, 1, 0, info->clickcnt);
+}
+
+void sdl_window_info::finger_up(SDL_FingerID finger, unsigned device, int x, int y)
+{
+ auto info(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), finger, &sdl_pointer_info::compare));
+ if ((m_active_pointers.end() == info) || (info->finger != finger))
+ return;
+
+ assert(1 == info->buttons);
+
+ // check for conversion to a (multi-)click-and-hold/drag
+ info->check_primary_hold_drag(
+ x,
+ y,
+ std::chrono::milliseconds(250),
+ TAP_DISTANCE);
+
+ // need to remember touches to recognise multi-tap gestures
+ if (0 < info->clickcnt)
+ {
+ auto const now(std::chrono::steady_clock::now());
+ auto const time = std::chrono::milliseconds(250);
+ if ((time + info->pressed) >= now)
+ {
+ try
+ {
+ unsigned i(0);
+ if (m_ptrdev_info.size() > device)
+ i = m_ptrdev_info[device].clear_expired_touches(now, time);
+ else
+ m_ptrdev_info.resize(device + 1);
+
+ if (std::size(m_ptrdev_info[device].touches) > i)
+ {
+ m_ptrdev_info[device].touches[i].when = info->pressed;
+ m_ptrdev_info[device].touches[i].x = info->pressedx;
+ m_ptrdev_info[device].touches[i].y = info->pressedy;
+ m_ptrdev_info[device].touches[i].cnt = info->clickcnt;
+ }
+ }
+ catch (std::bad_alloc const &)
+ {
+ osd_printf_error("win_window_info: error allocating pointer data\n");
+ }
+ }
+ }
+
+ // push to UI manager
+ machine().ui_input().push_pointer_update(
+ target(),
+ osd::ui_event_handler::pointer::TOUCH,
+ info->index,
+ device,
+ x, y,
+ 0, 0, 1, info->clickcnt);
+ machine().ui_input().push_pointer_leave(
+ target(),
+ osd::ui_event_handler::pointer::TOUCH,
+ info->index,
+ device,
+ x, y,
+ 0, info->clickcnt);
+
+ // dump pointer data
+ m_pointer_mask &= ~(decltype(m_pointer_mask)(1) << info->index);
+ if (info->index < m_next_pointer)
+ m_next_pointer = info->index;
+ m_active_pointers.erase(info);
+}
+
+void sdl_window_info::finger_moved(SDL_FingerID finger, unsigned device, int x, int y)
+{
+ auto info(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), finger, &sdl_pointer_info::compare));
+ if ((m_active_pointers.end() == info) || (info->finger != finger))
+
+ assert(1 == info->buttons);
+
+ if ((x != info->x) || (y != info->y))
+ {
+ info->check_primary_hold_drag(
+ x,
+ y,
+ std::chrono::milliseconds(250),
+ TAP_DISTANCE);
+
+ // update info and push to UI manager
+ info->x = x;
+ info->y = y;
+ machine().ui_input().push_pointer_update(
+ target(),
+ osd::ui_event_handler::pointer::TOUCH,
+ info->index,
+ device,
+ x, y,
+ 1, 0, 0, info->clickcnt);
+ }
+}
+
//============================================================
// sdlwindow_video_window_create
// (main thread)
@@ -400,31 +600,13 @@ int sdl_window_info::xy_to_render_target(int x, int y, int *xt, int *yt)
int sdl_window_info::window_init()
{
- int result;
-
// set the initial maximized state
// FIXME: Does not belong here
- sdl_options &options = downcast<sdl_options &>(m_machine.options());
- m_startmaximized = options.maximize();
-
- // add us to the list
- osd_common_t::s_window_list.push_back(std::static_pointer_cast<sdl_window_info>(shared_from_this()));
+ m_startmaximized = downcast<sdl_options &>(machine().options()).maximize();
- set_renderer(osd_renderer::make_for_type(video_config.mode, static_cast<osd_window*>(this)->shared_from_this()));
-
- // load the layout
- m_target = m_machine.render().target_alloc();
-
- // set the specific view
- set_starting_view(m_index, options.view(), options.view(m_index));
-
- // make the window title
- if (video_config.numscreens == 1)
- sprintf(m_title, "%s: %s [%s]", emulator_info::get_appname(), m_machine.system().type.fullname(), m_machine.system().name);
- else
- sprintf(m_title, "%s: %s [%s] - Screen %d", emulator_info::get_appname(), m_machine.system().type.fullname(), m_machine.system().name, m_index);
+ create_target();
- result = complete_create();
+ int result = complete_create();
// handle error conditions
if (result == 1)
@@ -450,31 +632,17 @@ void sdl_window_info::complete_destroy()
if (fullscreen() && video_config.switchres)
{
- SDL_SetWindowFullscreen(platform_window(), 0); // Try to set mode
- SDL_SetWindowDisplayMode(platform_window(), &m_original_mode->mode); // Try to set mode
- SDL_SetWindowFullscreen(platform_window(), SDL_WINDOW_FULLSCREEN); // Try to set mode
+ SDL_SetWindowFullscreen(platform_window(), 0);
+ SDL_SetWindowDisplayMode(platform_window(), &m_original_mode);
+ SDL_SetWindowFullscreen(platform_window(), SDL_WINDOW_FULLSCREEN);
}
+ renderer_reset();
SDL_DestroyWindow(platform_window());
- // release all keys ...
+ set_platform_window(nullptr);
downcast<sdl_osd_interface &>(machine().osd()).release_keys();
}
-void sdl_window_info::destroy()
-{
- //osd_event_wait(window->rendered_event, osd_ticks_per_second()*10);
-
- // remove us from the list
- osd_common_t::s_window_list.remove(std::static_pointer_cast<sdl_window_info>(shared_from_this()));
-
- // free the textures etc
- complete_destroy();
-
- // free the render target, after the textures!
- machine().render().target_free(m_target);
-
-}
-
//============================================================
// pick_best_mode
@@ -489,7 +657,7 @@ osd_dim sdl_window_info::pick_best_mode()
osd_dim ret(0,0);
// determine the minimum width/height for the selected target
- m_target->compute_minimum_size(minimum_width, minimum_height);
+ target()->compute_minimum_size(minimum_width, minimum_height);
// use those as the target for now
target_width = minimum_width * std::max(1, prescale());
@@ -502,7 +670,7 @@ osd_dim sdl_window_info::pick_best_mode()
}
// FIXME: this should be provided by monitor !
- num = SDL_GetNumDisplayModes(m_monitor->oshandle());
+ num = SDL_GetNumDisplayModes(monitor()->oshandle());
if (num == 0)
{
@@ -514,7 +682,7 @@ osd_dim sdl_window_info::pick_best_mode()
for (i = 0; i < num; ++i)
{
SDL_DisplayMode mode;
- SDL_GetDisplayMode(m_monitor->oshandle(), i, &mode);
+ SDL_GetDisplayMode(monitor()->oshandle(), i, &mode);
// compute initial score based on difference between target and current
size_score = 1.0f / (1.0f + abs((int32_t)mode.w - target_width) + abs((int32_t)mode.h - target_height));
@@ -556,20 +724,16 @@ osd_dim sdl_window_info::pick_best_mode()
void sdl_window_info::update()
{
- osd_ticks_t event_wait_ticks;
-
// adjust the cursor state
- //sdlwindow_update_cursor_state(machine, window);
-
update_cursor_state();
// if we're visible and running and not in the middle of a resize, draw
- if (m_target != nullptr)
+ if (target() != nullptr)
{
int tempwidth, tempheight;
// see if the games video mode has changed
- m_target->compute_minimum_size(tempwidth, tempheight);
+ target()->compute_minimum_size(tempwidth, tempheight);
if (osd_dim(tempwidth, tempheight) != m_minimum_dim)
{
m_minimum_dim = osd_dim(tempwidth, tempheight);
@@ -586,6 +750,7 @@ void sdl_window_info::update()
}
}
+ osd_ticks_t event_wait_ticks;
if (video_config.waitvsync && video_config.syncrefresh)
event_wait_ticks = osd_ticks_per_second(); // block at most a second
else
@@ -601,13 +766,10 @@ void sdl_window_info::update()
// and redraw now
- // Some configurations require events to be polled in the worker thread
- downcast< sdl_osd_interface& >(machine().osd()).process_events_buf();
-
// Check whether window has vector screens
{
- const screen_device *screen = screen_device_iterator(machine().root_device()).byindex(m_index);
+ const screen_device *screen = screen_device_enumerator(machine().root_device()).byindex(index());
if ((screen != nullptr) && (screen->screen_type() == SCREEN_TYPE_VECTOR))
renderer().set_flags(osd_renderer::FLAG_HAS_VECTOR_SCREEN);
else
@@ -616,20 +778,20 @@ void sdl_window_info::update()
m_primlist = &primlist;
- // if no bitmap, just fill
if (m_primlist == nullptr)
{
+ // if no bitmap, just fill
}
- // otherwise, render with our drawing system
else
{
- if( video_config.perftest )
+ // otherwise, render with our drawing system
+ if (video_config.perftest)
measure_fps(update);
else
renderer().draw(update);
}
- /* all done, ready for next */
+ // all done, ready for next
m_rendered_event.set();
}
}
@@ -637,27 +799,6 @@ void sdl_window_info::update()
//============================================================
-// set_starting_view
-// (main thread)
-//============================================================
-
-void sdl_window_info::set_starting_view(int index, const char *defview, const char *view)
-{
- int viewindex;
-
- // choose non-auto over auto
- if (strcmp(view, "auto") == 0 && strcmp(defview, "auto") != 0)
- view = defview;
-
- // query the video system to help us pick a view
- viewindex = target()->configured_view(view, index, video_config.numscreens);
-
- // set the view
- target()->set_view(viewindex);
-}
-
-
-//============================================================
// complete_create
//============================================================
@@ -681,9 +822,13 @@ int sdl_window_info::complete_create()
temp = m_windowed_dim;
}
else if (m_startmaximized)
- temp = get_max_bounds(video_config.keepaspect );
+ {
+ temp = get_max_bounds(keepaspect());
+ }
else
- temp = get_min_bounds(video_config.keepaspect );
+ {
+ temp = get_min_bounds(keepaspect());
+ }
// create the window .....
@@ -694,50 +839,20 @@ int sdl_window_info::complete_create()
*
*/
osd_printf_verbose("Enter sdl_info::create\n");
- if (renderer().has_flags(osd_renderer::FLAG_NEEDS_OPENGL) && !video_config.novideo)
+ if (renderer_sdl_needs_opengl())
{
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
-
- /* FIXME: A reminder that gamma is wrong throughout MAME. Currently, SDL2.0 doesn't seem to
- * support the following attribute although my hardware lists GL_ARB_framebuffer_sRGB as an extension.
- *
- * SDL_GL_SetAttribute( SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 1 );
- *
- */
m_extra_flags = SDL_WINDOW_OPENGL;
}
else
- m_extra_flags = 0;
-
-#ifdef SDLMAME_MACOSX
- /* FIMXE: On OSX, SDL_WINDOW_FULLSCREEN_DESKTOP seems to be more reliable.
- * It however creates issues with white borders, i.e. the screen clear
- * does not work. This happens both with opengl and accel.
- */
-#endif
-
- // We need to workaround an issue in SDL 2.0.4 for OS X where setting the
- // relative mode on the mouse in fullscreen mode makes mouse events stop
- // It is fixed in the latest revisions so we'll assume it'll be fixed
- // in the next public SDL release as well
-#if defined(SDLMAME_MACOSX) && SDL_VERSION_ATLEAST(2, 0, 2) // SDL_HINT_MOUSE_RELATIVE_MODE_WARP is introduced in 2.0.2
- SDL_version linked;
- SDL_GetVersion(&linked);
- int revision = SDL_GetRevisionNumber();
-
- // If we're running the exact version of SDL 2.0.4 (revision 10001) from the
- // SDL web site, we need to work around this issue and send the warp mode hint
- if (SDL_VERSION_EQUALS(linked, SDL_VERSIONNUM(2, 0, 4)) && revision == 10001)
{
- osd_printf_verbose("Using warp mode for relative mouse in OS X SDL 2.0.4\n");
- SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1");
+ m_extra_flags = 0;
}
-#endif
// create the SDL window
// soft driver also used | SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_MOUSE_FOCUS
m_extra_flags |= (fullscreen() ?
- SDL_WINDOW_BORDERLESS | SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_FULLSCREEN : SDL_WINDOW_RESIZABLE);
+ SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_FULLSCREEN : SDL_WINDOW_RESIZABLE);
#if defined(SDLMAME_WIN32)
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
@@ -746,17 +861,74 @@ int sdl_window_info::complete_create()
// get monitor work area for centering
osd_rect work = monitor()->usuable_position_size();
- // create the SDL window
- auto sdlwindow = SDL_CreateWindow(m_title,
+ // create or attach to an existing window
+ SDL_Window *sdlwindow;
+#ifdef SDLMAME_X11
+ const char *attach_window = downcast<sdl_options &>(machine().options()).attach_window();
+#else
+ const char *attach_window = nullptr;
+#endif
+ if (attach_window && *attach_window)
+ {
+ // we're attaching to an existing window; parse the argument
+ unsigned long long attach_window_value;
+ try
+ {
+ attach_window_value = std::stoull(attach_window, nullptr, 0);
+ }
+ catch (std::invalid_argument &)
+ {
+ osd_printf_error("Invalid -attach_window value: %s\n", attach_window);
+ return 1;
+ }
+
+ // and attach to it
+ sdlwindow = SDL_CreateWindowFrom((void *)attach_window_value);
+ if (!sdlwindow)
+ {
+ osd_printf_error("Failed to attach to window \"%s\": %s\n", attach_window, SDL_GetError());
+ return 1;
+ }
+
+ // perform SDL subsystem-specific tasks
+ SDL_SysWMinfo swmi;
+ SDL_VERSION(&swmi.version);
+ if (SDL_GetWindowWMInfo(sdlwindow, &swmi))
+ {
+ switch (swmi.subsystem)
+ {
+#ifdef SDLMAME_X11
+ case SDL_SYSWM_X11:
+ // by default, SDL_CreateWindowFrom() doesn't ensure that we're getting the events that we
+ // expect
+ XSelectInput(swmi.info.x11.display, swmi.info.x11.window,
+ FocusChangeMask | EnterWindowMask | LeaveWindowMask |
+ PointerMotionMask | KeyPressMask | KeyReleaseMask |
+ PropertyChangeMask | StructureNotifyMask |
+ ExposureMask | KeymapStateMask);
+ break;
+#endif // SDLMAME_X11
+
+ default:
+ break;
+ }
+ }
+ }
+ else
+ {
+ // create the SDL window
+ sdlwindow = SDL_CreateWindow(title().c_str(),
work.left() + (work.width() - temp.width()) / 2,
work.top() + (work.height() - temp.height()) / 2,
temp.width(), temp.height(), m_extra_flags);
+ }
+
//window().sdl_window() = SDL_CreateWindow(window().m_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
// width, height, m_extra_flags);
if (sdlwindow == nullptr )
{
- if (renderer().has_flags(osd_renderer::FLAG_NEEDS_OPENGL))
+ if (renderer_sdl_needs_opengl())
osd_printf_error("OpenGL not supported on this driver: %s\n", SDL_GetError());
else
osd_printf_error("Window creation failed: %s\n", SDL_GetError());
@@ -764,13 +936,14 @@ int sdl_window_info::complete_create()
}
set_platform_window(sdlwindow);
+ renderer_create();
if (fullscreen() && video_config.switchres)
{
SDL_DisplayMode mode;
//SDL_GetCurrentDisplayMode(window().monitor()->handle, &mode);
SDL_GetWindowDisplayMode(platform_window(), &mode);
- m_original_mode->mode = mode;
+ m_original_mode = mode;
mode.w = temp.width();
mode.h = temp.height();
if (m_win_config.refresh)
@@ -802,24 +975,6 @@ int sdl_window_info::complete_create()
SDL_SetWindowGrab(platform_window(), SDL_TRUE);
#endif
- // set main window
- if (m_index > 0)
- {
- for (auto w : osd_common_t::s_window_list)
- {
- if (w->m_index == 0)
- {
- set_main_window(std::dynamic_pointer_cast<osd_window>(w));
- break;
- }
- }
- }
- else
- {
- // We must be the main window
- set_main_window(shared_from_this());
- }
-
// update monitor resolution after mode change to ensure proper pixel aspect
monitor()->refresh();
if (fullscreen() && video_config.switchres)
@@ -830,8 +985,8 @@ int sdl_window_info::complete_create()
return 1;
// Make sure we have a consistent state
- SDL_ShowCursor(0);
- SDL_ShowCursor(1);
+ SDL_ShowCursor(SDL_DISABLE);
+ SDL_ShowCursor(SDL_ENABLE);
return 0;
}
@@ -910,14 +1065,9 @@ osd_rect sdl_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int ad
int32_t viswidth, visheight;
int32_t adjwidth, adjheight;
float pixel_aspect;
- std::shared_ptr<osd_monitor_info> monitor = m_monitor;
-
- // do not constrain aspect ratio for integer scaled views
- if (m_target->scale_mode() != SCALE_FRACTIONAL)
- return rect;
// get the pixel aspect ratio for the target monitor
- pixel_aspect = monitor->pixel_aspect();
+ pixel_aspect = monitor()->pixel_aspect();
// determine the proposed width/height
propwidth = rect.width() - extrawidth;
@@ -929,21 +1079,21 @@ osd_rect sdl_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int ad
{
case WMSZ_BOTTOM:
case WMSZ_TOP:
- m_target->compute_visible_area(10000, propheight, pixel_aspect, m_target->orientation(), propwidth, propheight);
+ target()->compute_visible_area(10000, propheight, pixel_aspect, target()->orientation(), propwidth, propheight);
break;
case WMSZ_LEFT:
case WMSZ_RIGHT:
- m_target->compute_visible_area(propwidth, 10000, pixel_aspect, m_target->orientation(), propwidth, propheight);
+ target()->compute_visible_area(propwidth, 10000, pixel_aspect, target()->orientation(), propwidth, propheight);
break;
default:
- m_target->compute_visible_area(propwidth, propheight, pixel_aspect, m_target->orientation(), propwidth, propheight);
+ target()->compute_visible_area(propwidth, propheight, pixel_aspect, target()->orientation(), propwidth, propheight);
break;
}
// get the minimum width/height for the current layout
- m_target->compute_minimum_size(minwidth, minheight);
+ target()->compute_minimum_size(minwidth, minheight);
// clamp against the absolute minimum
propwidth = std::max(propwidth, MIN_WINDOW_DIM);
@@ -956,13 +1106,13 @@ osd_rect sdl_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int ad
// clamp against the maximum (fit on one screen for full screen mode)
if (m_fullscreen)
{
- maxwidth = monitor->position_size().width() - extrawidth;
- maxheight = monitor->position_size().height() - extraheight;
+ maxwidth = monitor()->position_size().width() - extrawidth;
+ maxheight = monitor()->position_size().height() - extraheight;
}
else
{
- maxwidth = monitor->usuable_position_size().width() - extrawidth;
- maxheight = monitor->usuable_position_size().height() - extraheight;
+ maxwidth = monitor()->usuable_position_size().width() - extrawidth;
+ maxheight = monitor()->usuable_position_size().height() - extraheight;
// further clamp to the maximum width/height in the window
if (m_win_config.width != 0)
@@ -976,7 +1126,11 @@ osd_rect sdl_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int ad
propheight = std::min(propheight, maxheight);
// compute the visible area based on the proposed rectangle
- m_target->compute_visible_area(propwidth, propheight, pixel_aspect, m_target->orientation(), viswidth, visheight);
+ target()->compute_visible_area(propwidth, propheight, pixel_aspect, target()->orientation(), viswidth, visheight);
+
+ // clamp visable area to the proposed rectangle
+ viswidth = std::min(viswidth, propwidth);
+ visheight = std::min(visheight, propheight);
// compute the adjustments we need to make
adjwidth = (viswidth + extrawidth) - rect.width();
@@ -1024,7 +1178,13 @@ osd_dim sdl_window_info::get_min_bounds(int constrain)
//assert(GetCurrentThreadId() == window_threadid);
// get the minimum target size
- m_target->compute_minimum_size(minwidth, minheight);
+ target()->compute_minimum_size(minwidth, minheight);
+
+ // check if visible area is bigger
+ int32_t viswidth, visheight;
+ target()->compute_visible_area(minwidth, minheight, monitor()->aspect(), target()->orientation(), viswidth, visheight);
+ minwidth = std::max(viswidth, minwidth);
+ minheight = std::max(visheight, minheight);
// expand to our minimum dimensions
if (minwidth < MIN_WINDOW_DIM)
@@ -1037,7 +1197,7 @@ osd_dim sdl_window_info::get_min_bounds(int constrain)
minheight += wnd_extra_height();
// if we want it constrained, figure out which one is larger
- if (constrain && m_target->scale_mode() == SCALE_FRACTIONAL)
+ if (constrain)
{
// first constrain with no height limit
osd_rect test1(0,0,minwidth,10000);
@@ -1089,8 +1249,8 @@ osd_dim sdl_window_info::get_max_bounds(int constrain)
//assert(GetCurrentThreadId() == window_threadid);
// compute the maximum client area
- // m_monitor->refresh();
- osd_rect maximum = m_monitor->usuable_position_size();
+ // monitor()->refresh();
+ osd_rect maximum = monitor()->usuable_position_size();
// clamp to the window's max
int tempw = maximum.width();
@@ -1111,7 +1271,7 @@ osd_dim sdl_window_info::get_max_bounds(int constrain)
maximum = maximum.resize(tempw, temph);
// constrain to fit
- if (constrain && m_target->scale_mode() == SCALE_FRACTIONAL)
+ if (constrain)
maximum = constrain_to_aspect_ratio(maximum, WMSZ_BOTTOMRIGHT);
// remove extra window stuff
@@ -1120,43 +1280,87 @@ osd_dim sdl_window_info::get_max_bounds(int constrain)
return maximum.dim();
}
+
+std::vector<sdl_window_info::sdl_pointer_info>::iterator sdl_window_info::map_pointer(SDL_FingerID finger, unsigned device)
+{
+ auto found(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), finger, &sdl_pointer_info::compare));
+ if ((m_active_pointers.end() != found) && (found->finger == finger))
+ return found;
+
+ if ((sizeof(m_next_pointer) * 8) <= m_next_pointer)
+ {
+ assert(~decltype(m_pointer_mask)(0) == m_pointer_mask);
+ osd_printf_warning("sdl_window_info: exceeded maximum number of active pointers\n");
+ return m_active_pointers.end();
+ }
+ assert(!BIT(m_pointer_mask, m_next_pointer));
+
+ try
+ {
+ found = m_active_pointers.emplace(
+ found,
+ sdl_pointer_info(finger, m_next_pointer, device));
+ m_pointer_mask |= decltype(m_pointer_mask)(1) << m_next_pointer;
+ do
+ {
+ ++m_next_pointer;
+ }
+ while (((sizeof(m_next_pointer) * 8) > m_next_pointer) && BIT(m_pointer_mask, m_next_pointer));
+
+ return found;
+ }
+ catch (std::bad_alloc const &)
+ {
+ osd_printf_error("sdl_window_info: error allocating pointer data\n");
+ return m_active_pointers.end();
+ }
+}
+
+
+inline sdl_window_info::sdl_pointer_info::sdl_pointer_info(SDL_FingerID f, unsigned i, unsigned d)
+ : pointer_info(i, d)
+ , finger(f)
+{
+}
+
+
+
+
//============================================================
// construction and destruction
//============================================================
sdl_window_info::sdl_window_info(
running_machine &a_machine,
+ render_module &renderprovider,
int index,
- std::shared_ptr<osd_monitor_info> a_monitor,
+ const std::shared_ptr<osd_monitor_info> &a_monitor,
const osd_window_config *config)
- : osd_window_t(*config)
- , m_next(nullptr)
+ : osd_window_t(a_machine, renderprovider, index, std::move(a_monitor), *config)
, m_startmaximized(0)
// Following three are used by input code to defer resizes
, m_minimum_dim(0, 0)
, m_windowed_dim(0, 0)
, m_rendered_event(0, 1)
- , m_target(nullptr)
, m_extra_flags(0)
- , m_machine(a_machine)
- , m_monitor(a_monitor)
- , m_fullscreen(0)
, m_mouse_captured(false)
, m_mouse_hidden(false)
+ , m_pointer_mask(0)
+ , m_next_pointer(0)
+ , m_mouse_inside(false)
{
- m_index = index;
-
//FIXME: these should be per_window in config-> or even better a bit set
m_fullscreen = !video_config.windowed;
m_prescale = video_config.prescale;
m_windowed_dim = osd_dim(config->width, config->height);
- m_original_mode = global_alloc(SDL_DM_Wrapper);
+
+ m_ptrdev_info.reserve(1);
+ m_active_pointers.reserve(16);
}
sdl_window_info::~sdl_window_info()
{
- global_free(m_original_mode);
}
diff --git a/src/osd/sdl/window.h b/src/osd/sdl/window.h
index d6010e91ed2..49fe452192f 100644
--- a/src/osd/sdl/window.h
+++ b/src/osd/sdl/window.h
@@ -8,17 +8,18 @@
//
//============================================================
-#ifndef __SDLWINDOW__
-#define __SDLWINDOW__
-
-#include "osdsdl.h"
-#include "video.h"
+#ifndef MAME_OSD_SDL_WINDOW_H
+#define MAME_OSD_SDL_WINDOW_H
#include "modules/osdwindow.h"
+#include "osdsync.h"
+
+#include <SDL2/SDL.h>
+#include <chrono>
#include <cstdint>
#include <memory>
-#include <list>
+#include <vector>
//============================================================
@@ -27,18 +28,18 @@
class render_target;
-// forward of SDL_DisplayMode not possible (typedef struct) - define wrapper
-
-class SDL_DM_Wrapper;
-
typedef uintptr_t HashT;
-#define OSDWORK_CALLBACK(name) void *name(void *param, ATTR_UNUSED int threadid)
+#define OSDWORK_CALLBACK(name) void *name(void *param, int threadid)
class sdl_window_info : public osd_window_t<SDL_Window*>
{
public:
- sdl_window_info(running_machine &a_machine, int index, std::shared_ptr<osd_monitor_info> a_monitor,
+ sdl_window_info(
+ running_machine &a_machine,
+ render_module &renderprovider,
+ int index,
+ const std::shared_ptr<osd_monitor_info> &a_monitor,
const osd_window_config *config);
~sdl_window_info();
@@ -49,7 +50,7 @@ public:
void toggle_full_screen();
void modify_prescale(int dir);
void resize(int32_t width, int32_t height);
- void destroy() override;
+ void complete_destroy() override;
void capture_pointer() override;
void release_pointer() override;
@@ -62,43 +63,36 @@ public:
int xy_to_render_target(int x, int y, int *xt, int *yt);
- running_machine &machine() const override { return m_machine; }
- osd_monitor_info *monitor() const override { return m_monitor.get(); }
- int fullscreen() const override { return m_fullscreen; }
-
- render_target *target() override { return m_target; }
-
- int prescale() const { return m_prescale; }
-
- // Pointer to next window
- sdl_window_info * m_next;
+ void mouse_entered(unsigned device);
+ void mouse_left(unsigned device);
+ void mouse_down(unsigned device, int x, int y, unsigned button);
+ void mouse_up(unsigned device, int x, int y, unsigned button);
+ void mouse_moved(unsigned device, int x, int y);
+ void mouse_wheel(unsigned device, int y);
+ void finger_down(SDL_FingerID finger, unsigned device, int x, int y);
+ void finger_up(SDL_FingerID finger, unsigned device, int x, int y);
+ void finger_moved(SDL_FingerID finger, unsigned device, int x, int y);
private:
- // window handle and info
- char m_title[256];
- int m_startmaximized;
+ struct sdl_pointer_info : public pointer_info
+ {
+ static constexpr bool compare(sdl_pointer_info const &info, SDL_FingerID finger) { return info.finger < finger; }
- // dimensions
- osd_dim m_minimum_dim;
- osd_dim m_windowed_dim;
+ sdl_pointer_info(sdl_pointer_info const &) = default;
+ sdl_pointer_info(sdl_pointer_info &&) = default;
+ sdl_pointer_info &operator=(sdl_pointer_info const &) = default;
+ sdl_pointer_info &operator=(sdl_pointer_info &&) = default;
- // rendering info
- osd_event m_rendered_event;
- render_target * m_target;
-
- // Original display_mode
- SDL_DM_Wrapper *m_original_mode;
+ sdl_pointer_info(SDL_FingerID, unsigned i, unsigned d);
- int m_extra_flags;
+ SDL_FingerID finger;
+ };
// returns 0 on success, else 1
int complete_create();
- void complete_destroy();
-private:
int wnd_extra_width();
int wnd_extra_height();
- void set_starting_view(int index, const char *defview, const char *view);
osd_rect constrain_to_aspect_ratio(const osd_rect &rect, int adjustment);
osd_dim get_min_bounds(int constrain);
osd_dim get_max_bounds(int constrain);
@@ -106,50 +100,35 @@ private:
osd_dim pick_best_mode();
void set_fullscreen(int afullscreen) { m_fullscreen = afullscreen; }
- // Pointer to machine
- running_machine & m_machine;
-
- // monitor info
- std::shared_ptr<osd_monitor_info> m_monitor;
- int m_fullscreen;
- bool m_mouse_captured;
- bool m_mouse_hidden;
-
void measure_fps(int update);
-};
-
-struct osd_draw_callbacks
-{
- osd_renderer *(*create)(osd_window *window);
-};
+ std::vector<sdl_pointer_info>::iterator map_pointer(SDL_FingerID finger, unsigned device);
-//============================================================
-// PROTOTYPES
-//============================================================
-
-//============================================================
-// PROTOTYPES - drawsdl.c
-//============================================================
-
-int drawsdl_scale_mode(const char *s);
-
-//============================================================
-// PROTOTYPES - drawogl.c
-//============================================================
+ // window handle and info
+ int m_startmaximized;
-int drawogl_init(running_machine &machine, osd_draw_callbacks *callbacks);
+ // dimensions
+ osd_dim m_minimum_dim;
+ osd_dim m_windowed_dim;
-//============================================================
-// PROTOTYPES - draw13.c
-//============================================================
+ // rendering info
+ osd_event m_rendered_event;
-int drawsdl2_init(running_machine &machine, osd_draw_callbacks *callbacks);
+ // Original display_mode
+ SDL_DisplayMode m_original_mode;
-//============================================================
-// PROTOTYPES - drawbgfx.c
-//============================================================
+ int m_extra_flags;
-int drawbgfx_init(running_machine &machine, osd_draw_callbacks *callbacks);
+ // monitor info
+ bool m_mouse_captured;
+ bool m_mouse_hidden;
+
+ // info on currently active pointers - 64 pointers ought to be enough for anyone
+ uint64_t m_pointer_mask;
+ unsigned m_next_pointer;
+ bool m_mouse_inside;
+ std::vector<pointer_dev_info> m_ptrdev_info;
+ std::vector<sdl_pointer_info> m_active_pointers;
+};
-#endif /* __SDLWINDOW__ */
+#endif // MAME_OSD_SDL_WINDOW_H
diff --git a/src/osd/strconv.cpp b/src/osd/strconv.cpp
index 9ea2e00bd1a..130f259d70f 100644
--- a/src/osd/strconv.cpp
+++ b/src/osd/strconv.cpp
@@ -5,54 +5,32 @@
// strconv.cpp - Win32 string conversion
//
//============================================================
-#if defined(SDLMAME_WIN32) || defined(OSD_WINDOWS) || defined(OSD_UWP)
-#include <windows.h>
-#endif
-#include <algorithm>
-#include <assert.h>
-// MAMEOS headers
+
#include "strconv.h"
-#if defined(SDLMAME_WIN32) || defined(OSD_WINDOWS) || defined(OSD_UWP)
+#include "unicode.h"
-namespace
-{
- // class designed to provide inputs to WideCharToMultiByte() and MultiByteToWideChar()
- template<typename T>
- class string_source
- {
- public:
- string_source(const T *str) : m_str(str), m_char_count(-1)
- {
- assert(str);
- }
+#include <algorithm>
+#include <cassert>
- string_source(const std::basic_string<T> &str) : m_str(str.c_str()), m_char_count((int)str.size() + 1)
- {
- }
- const T *string() const { return m_str; }; // returns pointer to actual characters
- int char_count() const { return m_char_count; } // returns the character count (including NUL terminater), or -1 if NUL terminated
+#if defined(_WIN32)
- private:
- const T *m_str;
- int m_char_count;
- };
-};
+#include <windows.h>
-namespace osd {
-namespace text {
+
+namespace osd::text {
//============================================================
// mbstring_from_wstring
//============================================================
-static std::string &mbstring_from_wstring(std::string &dst, UINT code_page, const string_source<wchar_t> &src)
+inline std::string &mbstring_from_wstring(std::string &dst, UINT code_page, const std::wstring_view &src)
{
// convert UTF-16 to the specified code page
- int dst_char_count = WideCharToMultiByte(code_page, 0, src.string(), src.char_count(), nullptr, 0, nullptr, nullptr);
- dst.resize(dst_char_count - 1);
- WideCharToMultiByte(code_page, 0, src.string(), src.char_count(), &dst[0], dst_char_count, nullptr, nullptr);
+ const int dst_char_count = WideCharToMultiByte(code_page, 0, src.data(), src.length(), nullptr, 0, nullptr, nullptr);
+ dst.resize(dst_char_count);
+ WideCharToMultiByte(code_page, 0, src.data(), src.length(), dst.data(), dst_char_count, nullptr, nullptr);
return dst;
}
@@ -62,12 +40,12 @@ static std::string &mbstring_from_wstring(std::string &dst, UINT code_page, cons
// wstring_from_mbstring
//============================================================
-static std::wstring &wstring_from_mbstring(std::wstring &dst, const string_source<char> &src, UINT code_page)
+inline std::wstring &wstring_from_mbstring(std::wstring &dst, const std::string_view &src, UINT code_page)
{
// convert multibyte string (in specified code page) to UTF-16
- int dst_char_count = MultiByteToWideChar(code_page, 0, src.string(), src.char_count(), nullptr, 0);
- dst.resize(dst_char_count - 1);
- MultiByteToWideChar(CP_UTF8, 0, src.string(), src.char_count(), &dst[0], dst_char_count - 1);
+ const int dst_char_count = MultiByteToWideChar(code_page, 0, src.data(), src.length(), nullptr, 0);
+ dst.resize(dst_char_count);
+ MultiByteToWideChar(code_page, 0, src.data(), src.length(), dst.data(), dst_char_count);
return dst;
}
@@ -77,13 +55,13 @@ static std::wstring &wstring_from_mbstring(std::wstring &dst, const string_sourc
// to_astring
//============================================================
-std::string &to_astring(std::string &dst, const std::string &s)
+std::string &to_astring(std::string &dst, std::string_view s)
{
// convert MAME string (UTF-8) to UTF-16
std::wstring wstring = to_wstring(s);
// convert UTF-16 to "ANSI code page" string
- return mbstring_from_wstring(dst, CP_ACP, string_source<wchar_t>(wstring));
+ return mbstring_from_wstring(dst, CP_ACP, wstring);
}
@@ -98,7 +76,7 @@ std::string &to_astring(std::string &dst, const char *s)
std::wstring wstring = to_wstring(s);
// convert UTF-16 to "ANSI code page" string
- return mbstring_from_wstring(dst, CP_ACP, string_source<wchar_t>(wstring));
+ return mbstring_from_wstring(dst, CP_ACP, wstring);
}
@@ -106,7 +84,7 @@ std::string &to_astring(std::string &dst, const char *s)
// to_astring
//============================================================
-std::string to_astring(const std::string &s)
+std::string to_astring(std::string_view s)
{
std::string result;
to_astring(result, s);
@@ -130,11 +108,11 @@ std::string to_astring(const char *s)
// from_astring
//============================================================
-std::string &from_astring(std::string &dst, const std::string &s)
+std::string &from_astring(std::string &dst, std::string_view s)
{
// convert "ANSI code page" string to UTF-16
std::wstring wstring;
- wstring_from_mbstring(wstring, string_source<char>(s), CP_ACP);
+ wstring_from_mbstring(wstring, s, CP_ACP);
// convert UTF-16 to MAME string (UTF-8)
return from_wstring(dst, wstring);
@@ -149,7 +127,7 @@ std::string &from_astring(std::string &dst, const CHAR *s)
{
// convert "ANSI code page" string to UTF-16
std::wstring wstring;
- wstring_from_mbstring(wstring, string_source<char>(s), CP_ACP);
+ wstring_from_mbstring(wstring, s, CP_ACP);
// convert UTF-16 to MAME string (UTF-8)
return from_wstring(dst, wstring);
@@ -160,7 +138,7 @@ std::string &from_astring(std::string &dst, const CHAR *s)
// from_astring
//============================================================
-std::string from_astring(const std::string &s)
+std::string from_astring(std::string_view s)
{
std::string result;
from_astring(result, s);
@@ -184,10 +162,10 @@ std::string from_astring(const CHAR *s)
// to_wstring
//============================================================
-std::wstring &to_wstring(std::wstring &dst, const std::string &s)
+std::wstring &to_wstring(std::wstring &dst, std::string_view s)
{
// convert MAME string (UTF-8) to UTF-16
- return wstring_from_mbstring(dst, string_source<char>(s), CP_UTF8);
+ return wstring_from_mbstring(dst, s, CP_UTF8);
}
@@ -198,7 +176,7 @@ std::wstring &to_wstring(std::wstring &dst, const std::string &s)
std::wstring &to_wstring(std::wstring &dst, const char *s)
{
// convert MAME string (UTF-8) to UTF-16
- return wstring_from_mbstring(dst, string_source<char>(s), CP_UTF8);
+ return wstring_from_mbstring(dst, s, CP_UTF8);
}
@@ -206,7 +184,7 @@ std::wstring &to_wstring(std::wstring &dst, const char *s)
// to_wstring
//============================================================
-std::wstring to_wstring(const std::string &s)
+std::wstring to_wstring(std::string_view s)
{
std::wstring result;
to_wstring(result, s);
@@ -230,10 +208,10 @@ std::wstring to_wstring(const char *s)
// from_wstring
//============================================================
-std::string &from_wstring(std::string &dst, const std::wstring &s)
+std::string &from_wstring(std::string &dst, std::wstring_view s)
{
// convert UTF-16 to MAME string (UTF-8)
- return mbstring_from_wstring(dst, CP_UTF8, string_source<wchar_t>(s));
+ return mbstring_from_wstring(dst, CP_UTF8, s);
}
@@ -244,7 +222,7 @@ std::string &from_wstring(std::string &dst, const std::wstring &s)
std::string &from_wstring(std::string &dst, const WCHAR *s)
{
// convert UTF-16 to MAME string (UTF-8)
- return mbstring_from_wstring(dst, CP_UTF8, string_source<wchar_t>(s));
+ return mbstring_from_wstring(dst, CP_UTF8, s);
}
@@ -252,7 +230,7 @@ std::string &from_wstring(std::string &dst, const WCHAR *s)
// from_wstring
//============================================================
-std::string from_wstring(const std::wstring &s)
+std::string from_wstring(std::wstring_view s)
{
std::string result;
from_wstring(result, s);
@@ -271,8 +249,7 @@ std::string from_wstring(const WCHAR *s)
return result;
}
-}; // namespace text
-}; // namespace osd
+} // namespace osd::text
//============================================================
@@ -281,15 +258,22 @@ std::string from_wstring(const WCHAR *s)
int osd_uchar_from_osdchar(char32_t *uchar, const char *osdchar, size_t count)
{
- WCHAR wch;
+ // handle UTF-8 internally
+ if (GetACP() == CP_UTF8)
+ return uchar_from_utf8(uchar, osdchar, count);
+
+ // FIXME: This makes multiple bad assumptions:
+ // * Assumes any character can be converted to a single wchar_t.
+ // * Assumes characters are either one byte or maximum number of bytes.
+ // * Doesn't handle nominal single-byte encodings with combining characters.
CPINFO cp;
-
if (!GetCPInfo(CP_ACP, &cp))
goto error;
// The multibyte char can't be bigger than the max character size
- count = std::min(count, size_t(cp.MaxCharSize));
+ count = std::min(count, size_t(IsDBCSLeadByte(*osdchar) ? cp.MaxCharSize : 1));
+ WCHAR wch;
if (MultiByteToWideChar(CP_ACP, 0, osdchar, static_cast<DWORD>(count), &wch, 1) == 0)
goto error;
@@ -302,23 +286,35 @@ error:
}
-#else
-#include "unicode.h"
+#else // _WIN32
+
//============================================================
// osd_uchar_from_osdchar
//============================================================
int osd_uchar_from_osdchar(char32_t *uchar, const char *osdchar, size_t count)
{
- wchar_t wch;
+ // TODO: should this handle count == 0?
+ if (!*osdchar)
+ {
+ // mbstowcs stops on encountering NUL and doesn't include it in the output count
+ *uchar = char32_t(0);
+ return 1;
+ }
+ // FIXME: mbstowcs depends on global state
+ wchar_t wch;
count = mbstowcs(&wch, (char *)osdchar, 1);
- if (count != -1)
+ if (count != size_t(-1))
+ {
*uchar = wch;
+ return int(count);
+ }
else
+ {
*uchar = 0;
-
- return count;
+ return -1;
+ }
}
-#endif
+#endif // _WIN32
diff --git a/src/osd/strconv.h b/src/osd/strconv.h
index f1eed54a49a..558987a167b 100644
--- a/src/osd/strconv.h
+++ b/src/osd/strconv.h
@@ -17,31 +17,31 @@
// FUNCTION PROTOTYPES
//============================================================
-#if defined(WIN32)
+#if defined(_WIN32)
+
+#include <string_view>
#include <windows.h>
-namespace osd
-{
- namespace text
- {
- std::string to_astring(const std::string &s);
- std::string to_astring(const char *s);
- std::string &to_astring(std::string &dst, const std::string &s);
- std::string &to_astring(std::string &dst, const char *s);
- std::string from_astring(const std::string &s);
- std::string from_astring(const CHAR *s);
- std::string &from_astring(std::string &dst, const std::string &s);
- std::string &from_astring(std::string &dst, const CHAR *s);
-
- std::wstring to_wstring(const std::string &s);
- std::wstring to_wstring(const char *s);
- std::wstring &to_wstring(std::wstring &dst, const std::string &s);
- std::wstring &to_wstring(std::wstring &dst, const char *s);
- std::string from_wstring(const std::wstring &s);
- std::string from_wstring(const WCHAR *s);
- std::string &from_wstring(std::string &dst, const std::wstring &s);
- std::string &from_wstring(std::string &dst, const WCHAR *s);
+namespace osd::text {
+
+std::string to_astring(std::string_view s);
+std::string to_astring(const char *s);
+std::string &to_astring(std::string &dst, std::string_view s);
+std::string &to_astring(std::string &dst, const char *s);
+std::string from_astring(const std::string_view s);
+std::string from_astring(const CHAR *s);
+std::string &from_astring(std::string &dst, std::string_view s);
+std::string &from_astring(std::string &dst, const CHAR *s);
+
+std::wstring to_wstring(std::string_view s);
+std::wstring to_wstring(const char *s);
+std::wstring &to_wstring(std::wstring &dst, std::string_view s);
+std::wstring &to_wstring(std::wstring &dst, const char *s);
+std::string from_wstring(const std::wstring_view s);
+std::string from_wstring(const WCHAR *s);
+std::string &from_wstring(std::string &dst, std::wstring_view s);
+std::string &from_wstring(std::string &dst, const WCHAR *s);
#ifdef UNICODE
typedef std::wstring tstring;
@@ -53,10 +53,9 @@ typedef std::string tstring;
#define from_tstring from_astring
#endif // UNICODE
- }
-}
+} // namespace osd::text
-#endif // defined(WIN32)
+#endif // defined(_WIN32)
#endif // MAME_OSD_STRCONV_H
diff --git a/src/osd/uwp/uwpcompat.cpp b/src/osd/uwp/uwpcompat.cpp
deleted file mode 100644
index bd7103b8e31..00000000000
--- a/src/osd/uwp/uwpcompat.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Brad Hughes, Miodrag Milanovic
-//============================================================
-//
-// uwpcompat.h - Universal Windows Platform compat forced includes
-//
-//============================================================
-
-#include "uwpcompat.h"
-
-#include <windows.h>
-#include <errno.h>
-
-#undef interface
-
-#include "emu.h"
-
-extern "C" {
-
- BOOL WINAPI GetVersionEx(
- _Inout_ LPOSVERSIONINFO lpVersionInfo
- )
- {
- lpVersionInfo->dwMajorVersion = 10;
- return TRUE;
- }
-
- HANDLE
- WINAPI
- CreateFileW(
- _In_ LPCWSTR lpFileName,
- _In_ DWORD dwDesiredAccess,
- _In_ DWORD dwShareMode,
- _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- _In_ DWORD dwCreationDisposition,
- _In_ DWORD dwFlagsAndAttributes,
- _In_opt_ HANDLE hTemplateFile
- )
- {
- // TODO: Handle other arguments that go into last param (pCreateExParams)
- return CreateFile2((wchar_t*)lpFileName, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL);
- }
-
- HANDLE
- WINAPI
- CreateFileA(
- _In_ LPCSTR lpFileName,
- _In_ DWORD dwDesiredAccess,
- _In_ DWORD dwShareMode,
- _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- _In_ DWORD dwCreationDisposition,
- _In_ DWORD dwFlagsAndAttributes,
- _In_opt_ HANDLE hTemplateFile
- )
- {
- wchar_t filepath[MAX_PATH + 1];
- if (MultiByteToWideChar(CP_ACP, 0, lpFileName, strlen(lpFileName), filepath, MAX_PATH))
- return CreateFileW(filepath, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
-
- SetLastError(E_FAIL);
- return INVALID_HANDLE_VALUE;
- }
-
- DWORD WINAPI GetTickCount(void)
- {
- return osd_ticks();
- }
-
- // This is only in here so callers get an error
- HMODULE WINAPI LoadLibraryExA(
- _In_ LPCSTR lpLibFileName,
- _Reserved_ HANDLE hFile,
- _In_ DWORD dwFlags
- )
- {
- SetLastError(ERROR_FILE_NOT_FOUND);
- return nullptr;
- }
-
- HMODULE WINAPI LoadLibraryExW(
- _In_ LPCWSTR lpLibFileName,
- _Reserved_ HANDLE hFile,
- _In_ DWORD dwFlags
- )
- {
- SetLastError(ERROR_FILE_NOT_FOUND);
- return nullptr;
- }
-
- DWORD WINAPI GetFileSize(
- _In_ HANDLE hFile,
- _Out_opt_ LPDWORD lpFileSizeHigh
- )
- {
- FILE_STANDARD_INFO file_info;
- GetFileInformationByHandleEx(hFile, FileStandardInfo, &file_info, sizeof(file_info));
- if(lpFileSizeHigh!=nullptr)
- {
- *lpFileSizeHigh = file_info.EndOfFile.HighPart;
- }
- return file_info.EndOfFile.LowPart;
- }
-}
diff --git a/src/osd/uwp/uwpcompat.h b/src/osd/uwp/uwpcompat.h
deleted file mode 100644
index 2d495238a99..00000000000
--- a/src/osd/uwp/uwpcompat.h
+++ /dev/null
@@ -1,139 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Brad Hughes, Miodrag Milanovic
-//============================================================
-//
-// uwpcompat.h - Universal Windows Platform compat forced includes
-//
-//============================================================
-
-#ifndef __UWPCOMPAT_H__
-#define __UWPCOMPAT_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef NOGDI
-#define NOGDI
-#endif
-#include <windows.h>
-#include <stdio.h>
-
-int system(const char *command);
-
-const char *getenv(const char *varname);
-
-HANDLE
-WINAPI
-CreateFileA(
- _In_ LPCSTR lpFileName,
- _In_ DWORD dwDesiredAccess,
- _In_ DWORD dwShareMode,
- _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- _In_ DWORD dwCreationDisposition,
- _In_ DWORD dwFlagsAndAttributes,
- _In_opt_ HANDLE hTemplateFile
- );
-
-HANDLE
-WINAPI
-CreateFileW(
- _In_ LPCWSTR lpFileName,
- _In_ DWORD dwDesiredAccess,
- _In_ DWORD dwShareMode,
- _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- _In_ DWORD dwCreationDisposition,
- _In_ DWORD dwFlagsAndAttributes,
- _In_opt_ HANDLE hTemplateFile
- );
-
-#ifdef UNICODE
-#define CreateFile CreateFileW
-#else
-#define CreateFile CreateFileA
-#endif // !UNICODE
-
-BOOL WINAPI GetVersionEx(
- _Inout_ LPOSVERSIONINFO lpVersionInfo
-);
-
-DWORD WINAPI GetTickCount(void);
-
-FILE *_popen(
- const char *command,
- const char *mode
- );
-
-int _pclose(
- FILE *stream);
-
-_Ret_maybenull_
-HMODULE WINAPI LoadLibraryA(
- _In_ LPCSTR lpFileName
-);
-
-_Ret_maybenull_
-HMODULE WINAPI LoadLibraryW(
- _In_ LPCWSTR lpFileName
-);
-
-#ifdef UNICODE
-#define LoadLibrary LoadLibraryW
-#else
-#define LoadLibrary LoadLibraryA
-#endif // !UNICODE
-
-_Ret_maybenull_
-HMODULE WINAPI GetModuleHandleA(
- _In_ LPCSTR lpModuleName
-);
-
-_Ret_maybenull_
-HMODULE WINAPI GetModuleHandleW(
- _In_ LPCWSTR lpModuleName
-);
-
-#ifdef UNICODE
-#define GetModuleHandle GetModuleHandleW
-#else
-#define GetModuleHandle GetModuleHandleA
-#endif // !UNICODE
-
-_Ret_maybenull_
-HMODULE
-WINAPI
-LoadLibraryExA(
- _In_ LPCSTR lpLibFileName,
- _Reserved_ HANDLE hFile,
- _In_ DWORD dwFlags
-);
-
-_Ret_maybenull_
-HMODULE
-WINAPI
-LoadLibraryExW(
- _In_ LPCWSTR lpLibFileName,
- _Reserved_ HANDLE hFile,
- _In_ DWORD dwFlags
-);
-
-#ifdef UNICODE
-#define LoadLibraryEx LoadLibraryExW
-#else
-#define LoadLibraryEx LoadLibraryExA
-#endif // !UNICODE
-
-DWORD
-WINAPI
-GetFileSize(
- _In_ HANDLE hFile,
- _Out_opt_ LPDWORD lpFileSizeHigh
-);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // __UWPCOMPAT_H__
-
-
diff --git a/src/osd/uwp/video.cpp b/src/osd/uwp/video.cpp
deleted file mode 100644
index f59b59c171b..00000000000
--- a/src/osd/uwp/video.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Brad Hughes, Aaron Giles
-//============================================================
-//
-// video.c - UWP video handling
-//
-//============================================================
-
-#include <exception>
-
-// standard windows headers
-#include <windows.h>
-#include <dxgi1_2.h>
-#include <wrl\client.h>
-#undef interface
-
-// MAME headers
-#include "emu.h"
-#include "emuopts.h"
-#include "render.h"
-#include "uiinput.h"
-
-// MAMEOS headers
-#include "winmain.h"
-#include "video.h"
-#include "window.h"
-#include "strconv.h"
-
-#include "modules/osdwindow.h"
-
-using namespace Platform;
-using namespace Microsoft::WRL;
-using namespace Windows::UI::Core;
-
-//============================================================
-// GLOBAL VARIABLES
-//============================================================
-
-osd_video_config video_config;
-
-
-//============================================================
-// PROTOTYPES
-//============================================================
-
-static void get_resolution(const char *defdata, const char *data, osd_window_config *config, int report_error);
-
-
-//============================================================
-// video_init
-//============================================================
-
-// FIXME: Temporary workaround
-static osd_window_config windows[MAX_VIDEO_WINDOWS]; // configuration data per-window
-
-bool windows_osd_interface::video_init()
-{
- // extract data from the options
- extract_video_config();
-
- // initialize the window system so we can make windows
- window_init();
-
- // create the windows
- windows_options &options = downcast<windows_options &>(machine().options());
- for (int index = 0; index < video_config.numscreens; index++)
- {
- uwp_window_info::create(machine(), index, m_monitor_module->pick_monitor(options, index), &windows[index]);
- }
-
- if (video_config.mode != VIDEO_MODE_NONE)
- {
- auto win = std::static_pointer_cast<uwp_window_info>(osd_common_t::s_window_list.front());
- win->platform_window()->Activate();
- }
-
- return true;
-}
-
-//============================================================
-// video_exit
-//============================================================
-
-void windows_osd_interface::video_exit()
-{
- window_exit();
-}
-
-//============================================================
-// update
-//============================================================
-
-void windows_osd_interface::update(bool skip_redraw)
-{
- osd_common_t::update(skip_redraw);
-
- // if we're not skipping this redraw, update all windows
- if (!skip_redraw)
- {
-// profiler_mark(PROFILER_BLIT);
- for (auto window : osd_common_t::s_window_list)
- window->update();
-// profiler_mark(PROFILER_END);
- }
-
- // poll the joystick values here
- winwindow_process_events(machine(), true, false);
- poll_input(machine());
- check_osd_inputs();
- // if we're running, disable some parts of the debugger
- if ((machine().debug_flags & DEBUG_FLAG_OSD_ENABLED) != 0)
- debugger_update();
-}
-
-
-//============================================================
-// check_osd_inputs
-//============================================================
-
-void windows_osd_interface::check_osd_inputs()
-{
-}
-
-
-
-//============================================================
-// extract_video_config
-//============================================================
-
-void windows_osd_interface::extract_video_config()
-{
- const char *stemp;
-
- // global options: extract the data
- video_config.windowed = options().window();
- video_config.prescale = options().prescale();
- video_config.filter = options().filter();
- video_config.keepaspect = options().keep_aspect();
- video_config.numscreens = options().numscreens();
-
- // if we are in debug mode, never go full screen
- if (machine().debug_flags & DEBUG_FLAG_OSD_ENABLED)
- video_config.windowed = TRUE;
-
- // per-window options: extract the data
- const char *default_resolution = options().resolution();
- get_resolution(default_resolution, options().resolution(0), &windows[0], TRUE);
- get_resolution(default_resolution, options().resolution(1), &windows[1], TRUE);
- get_resolution(default_resolution, options().resolution(2), &windows[2], TRUE);
- get_resolution(default_resolution, options().resolution(3), &windows[3], TRUE);
-
- // video options: extract the data
- stemp = options().video();
- if (strcmp(stemp, "auto") == 0)
- video_config.mode = VIDEO_MODE_BGFX;
- else if (strcmp(stemp, "bgfx") == 0)
- video_config.mode = VIDEO_MODE_BGFX;
- else if (strcmp(stemp, "none") == 0)
- {
- video_config.mode = VIDEO_MODE_NONE;
- if (!emulator_info::standalone() && options().seconds_to_run() == 0)
- osd_printf_warning("Warning: -video none doesn't make much sense without -seconds_to_run\n");
- }
- else
- {
- osd_printf_warning("Invalid video value %s; reverting to gdi\n", stemp);
- video_config.mode = VIDEO_MODE_GDI;
- }
- video_config.waitvsync = options().wait_vsync();
- video_config.syncrefresh = options().sync_refresh();
- video_config.triplebuf = options().triple_buffer();
- video_config.switchres = options().switch_res();
-
- if (video_config.prescale < 1 || video_config.prescale > 3)
- {
- osd_printf_warning("Invalid prescale option, reverting to '1'\n");
- video_config.prescale = 1;
- }
-}
-
-
-//============================================================
-// get_resolution
-//============================================================
-
-static void get_resolution(const char *defdata, const char *data, osd_window_config *config, int report_error)
-{
- config->width = config->height = config->depth = config->refresh = 0;
- if (strcmp(data, OSDOPTVAL_AUTO) == 0)
- {
- if (strcmp(defdata, OSDOPTVAL_AUTO) == 0)
- return;
- data = defdata;
- }
-
- if (sscanf(data, "%dx%dx%d", &config->width, &config->height, &config->depth) < 2 && report_error)
- osd_printf_error("Illegal resolution value = %s\n", data);
-
- const char * at_pos = strchr(data, '@');
- if (at_pos)
- if (sscanf(at_pos + 1, "%d", &config->refresh) < 1 && report_error)
- osd_printf_error("Illegal refresh rate in resolution value = %s\n", data);
-}
diff --git a/src/osd/uwp/video.h b/src/osd/uwp/video.h
deleted file mode 100644
index 5725a2bb0d4..00000000000
--- a/src/osd/uwp/video.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
-//============================================================
-//
-// video.h - UWP implementation of MAME video routines
-//
-//============================================================
-
-#ifndef __UWP_VIDEO__
-#define __UWP_VIDEO__
-
-#include "modules/osdhelper.h"
-
-inline osd_rect RECT_to_osd_rect(const RECT &r)
-{
- return osd_rect(r.left, r.top, r.right - r.left, r.bottom - r.top);
-}
-
-#endif
diff --git a/src/osd/uwp/window.cpp b/src/osd/uwp/window.cpp
deleted file mode 100644
index 12c67308f22..00000000000
--- a/src/osd/uwp/window.cpp
+++ /dev/null
@@ -1,1146 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
-//============================================================
-//
-// window.c - Win32 window handling
-//
-//============================================================
-
-#define LOG_TEMP_PAUSE 0
-
-// Needed for RAW Input
-#define WM_INPUT 0x00FF
-
-// standard C headers
-#include <process.h>
-
-#include <atomic>
-#include <chrono>
-#include <list>
-#include <memory>
-
-// MAME headers
-#include "emu.h"
-#include "uiinput.h"
-#include "ui/uimain.h"
-
-// MAMEOS headers
-#include "winmain.h"
-#include "window.h"
-#include "video.h"
-#include "winutf8.h"
-
-#include "winutil.h"
-
-#include "modules/monitor/monitor_common.h"
-
-#include <agile.h>
-using namespace Windows::UI::Core;
-
-#include "modules/render/drawbgfx.h"
-#include "modules/render/drawnone.h"
-
-#define NOT_ALREADY_DOWN(x) (x & 0x40000000) == 0
-#define SCAN_CODE(x) ((x >> 16) & 0xff)
-#define IS_EXTENDED(x) (0x01000000 & x)
-#define MAKE_DI_SCAN(scan, isextended) (scan & 0x7f) | (isextended ? 0x80 : 0x00)
-#define WINOSD(machine) downcast<windows_osd_interface*>(&machine.osd())
-
-//============================================================
-// PARAMETERS
-//============================================================
-
-// window styles
-#define WINDOW_STYLE WS_OVERLAPPEDWINDOW
-#define WINDOW_STYLE_EX 0
-
-// debugger window styles
-#define DEBUG_WINDOW_STYLE WS_OVERLAPPED
-#define DEBUG_WINDOW_STYLE_EX 0
-
-// full screen window styles
-#define FULLSCREEN_STYLE WS_POPUP
-#define FULLSCREEN_STYLE_EX WS_EX_TOPMOST
-
-// minimum window dimension
-#define MIN_WINDOW_DIM 200
-
-// custom window messages
-#define WM_USER_REDRAW (WM_USER + 2)
-#define WM_USER_SET_FULLSCREEN (WM_USER + 3)
-#define WM_USER_SET_MAXSIZE (WM_USER + 4)
-#define WM_USER_SET_MINSIZE (WM_USER + 5)
-
-
-
-//============================================================
-// GLOBAL VARIABLES
-//============================================================
-
-static DWORD main_threadid;
-
-// actual physical resolution
-static int win_physical_width;
-static int win_physical_height;
-
-
-
-//============================================================
-// LOCAL VARIABLES
-//============================================================
-
-// event handling
-static std::chrono::system_clock::time_point last_event_check;
-
-// debugger
-static int in_background;
-
-static int ui_temp_pause;
-static int ui_temp_was_paused;
-
-static HANDLE window_thread;
-static DWORD window_threadid;
-
-static std::chrono::time_point<std::chrono::high_resolution_clock> last_update_time;
-
-static HANDLE ui_pause_event;
-
-//============================================================
-// window_init
-// (main thread)
-//============================================================
-
-bool windows_osd_interface::window_init()
-{
- // get the main thread ID before anything else
- main_threadid = GetCurrentThreadId();
-
- // create an event to signal UI pausing
- ui_pause_event = CreateEvent(nullptr, TRUE, FALSE, nullptr);
- if (!ui_pause_event)
- fatalerror("Failed to create pause event\n");
-
- window_thread = GetCurrentThread();
- window_threadid = main_threadid;
-
- const int fallbacks[VIDEO_MODE_COUNT] = {
- -1, // NONE -> no fallback
- VIDEO_MODE_NONE, // GDI -> NONE
- -1 // No SOFT on Windows OSD
- };
-
- int current_mode = video_config.mode;
- while (current_mode != VIDEO_MODE_NONE)
- {
- bool error = false;
- switch(current_mode)
- {
- case VIDEO_MODE_NONE:
- error = renderer_none::init(machine());
- break;
- case VIDEO_MODE_BGFX:
- error = renderer_bgfx::init(machine());
- break;
- default:
- fatalerror("Unknown video mode.");
- break;
- }
- if (error)
- {
- current_mode = fallbacks[current_mode];
- }
- else
- {
- break;
- }
- }
- video_config.mode = current_mode;
-
- return true;
-}
-
-void windows_osd_interface::update_slider_list()
-{
- for (auto window : osd_common_t::s_window_list)
- {
- // check if any window has dirty sliders
- if (window->has_renderer() && window->renderer().sliders_dirty())
- {
- build_slider_list();
- return;
- }
- }
-}
-
-int windows_osd_interface::window_count()
-{
- return osd_common_t::s_window_list.size();
-}
-
-void windows_osd_interface::build_slider_list()
-{
- m_sliders.clear();
-
- for (auto window : osd_common_t::s_window_list)
- {
- if (window->has_renderer())
- {
- // take the sliders of the first window
- std::vector<ui::menu_item> window_sliders = window->renderer().get_slider_list();
- m_sliders.insert(m_sliders.end(), window_sliders.begin(), window_sliders.end());
- }
- }
-}
-
-void windows_osd_interface::add_audio_to_recording(const int16_t *buffer, int samples_this_frame)
-{
- auto window = osd_common_t::s_window_list.front(); // We only record on the first window
- if (window != nullptr)
- {
- window->renderer().add_audio_to_recording(buffer, samples_this_frame);
- }
-}
-
-//============================================================
-// winwindow_exit
-// (main thread)
-//============================================================
-
-void windows_osd_interface::window_exit()
-{
- assert(GetCurrentThreadId() == main_threadid);
-
- // if we hid the cursor during the emulation, show it
- if (!osd_common_t::s_window_list.empty())
- osd_common_t::s_window_list.front()->show_pointer();
-
- // free all the windows
- while (!osd_common_t::s_window_list.empty())
- {
- auto window = osd_common_t::s_window_list.front();
-
- // Destroy removes it from the list also
- window->destroy();
- }
-
- switch(video_config.mode)
- {
- case VIDEO_MODE_NONE:
- renderer_none::exit();
- break;
- case VIDEO_MODE_BGFX:
- renderer_bgfx::exit();
- break;
- default:
- break;
- }
-
- // kill the UI pause event
- if (ui_pause_event)
- CloseHandle(ui_pause_event);
-}
-
-uwp_window_info::uwp_window_info(
- running_machine &machine,
- int index,
- std::shared_ptr<osd_monitor_info> monitor,
- const osd_window_config *config) : osd_window_t(*config),
- m_next(nullptr),
- m_init_state(0),
- m_startmaximized(0),
- m_isminimized(0),
- m_ismaximized(0),
- m_monitor(monitor),
- m_fullscreen(!video_config.windowed),
- m_fullscreen_safe(0),
- m_aspect(0),
- m_target(nullptr),
- m_targetview(0),
- m_targetorient(0),
- m_lastclicktime(std::chrono::system_clock::time_point::min()),
- m_lastclickx(0),
- m_lastclicky(0),
- m_machine(machine)
-{
- memset(m_title,0,sizeof(m_title));
- m_non_fullscreen_bounds.left = 0;
- m_non_fullscreen_bounds.top = 0;
- m_non_fullscreen_bounds.right = 0;
- m_non_fullscreen_bounds.bottom = 0;
- m_prescale = video_config.prescale;
-}
-
-POINT uwp_window_info::s_saved_cursor_pos = { -1, -1 };
-
-CoreCursor^ uwp_window_info::s_cursor = nullptr;
-
-void uwp_window_info::capture_pointer()
-{
- platform_window()->SetPointerCapture();
-}
-
-void uwp_window_info::release_pointer()
-{
- platform_window()->ReleasePointerCapture();
-}
-
-void uwp_window_info::hide_pointer()
-{
- auto window = platform_window();
- uwp_window_info::s_cursor = window->PointerCursor;
- window->PointerCursor = nullptr;
-}
-
-void uwp_window_info::show_pointer()
-{
- auto window = platform_window();
- window->PointerCursor = uwp_window_info::s_cursor;
-}
-
-//============================================================
-// winwindow_process_events_periodic
-// (main thread)
-//============================================================
-
-void winwindow_process_events_periodic(running_machine &machine)
-{
- auto currticks = std::chrono::system_clock::now();
-
- assert(GetCurrentThreadId() == main_threadid);
-
- // update once every 1/8th of a second
- if (currticks - last_event_check < std::chrono::milliseconds(1000 / 8))
- return;
- winwindow_process_events(machine, true, false);
-}
-
-//============================================================
-// winwindow_has_focus
-// (main or window thread)
-//============================================================
-
-bool winwindow_has_focus(void)
-{
- // For now always act like we have focus
- return true;
-}
-
-//============================================================
-// winwindow_process_events
-// (main thread)
-//============================================================
-
-void winwindow_process_events(running_machine &machine, bool ingame, bool nodispatch)
-{
-// MSG message;
-
- assert(GetCurrentThreadId() == main_threadid);
-
- // remember the last time we did this
- last_event_check = std::chrono::system_clock::now();
-
- try
- {
- CoreWindow^ window = CoreWindow::GetForCurrentThread();
- window->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
- }
- catch (Platform::DisconnectedException^)
- {
- // This can get thrown when the window is being destroyed
- }
-}
-
-
-//============================================================
-// winwindow_video_window_create
-// (main thread)
-//============================================================
-
-void uwp_window_info::create(running_machine &machine, int index, std::shared_ptr<osd_monitor_info> monitor, const osd_window_config *config)
-{
- assert(GetCurrentThreadId() == main_threadid);
-
- // allocate a new window object
- auto window = std::make_shared<uwp_window_info>(machine, index, monitor, config);
-
- // set main window
- if (window->m_index > 0)
- {
- for (auto w : osd_common_t::s_window_list)
- {
- if (w->m_index == 0)
- {
- window->set_main_window(std::static_pointer_cast<osd_window>(w));
- break;
- }
- }
- }
- else
- {
- // We must be the main window
- window->set_main_window(window);
- }
-
- // see if we are safe for fullscreen
- window->m_fullscreen_safe = TRUE;
- for (auto win : osd_common_t::s_window_list)
- if (win->monitor() == monitor.get())
- window->m_fullscreen_safe = FALSE;
-
- // add us to the list
- osd_common_t::s_window_list.push_back(window);
-
- // load the layout
- window->m_target = machine.render().target_alloc();
-
- // set the specific view
- windows_options &options = downcast<windows_options &>(machine.options());
-
- const char *defview = options.view();
- window->set_starting_view(index, defview, options.view(index));
-
- // remember the current values in case they change
- window->m_targetview = window->m_target->view();
- window->m_targetorient = window->m_target->orientation();
- window->m_targetlayerconfig = window->m_target->layer_config();
-
- // make the window title
- if (video_config.numscreens == 1)
- sprintf(window->m_title, "%s: %s [%s]", emulator_info::get_appname(), machine.system().type.fullname(), machine.system().name);
- else
- sprintf(window->m_title, "%s: %s [%s] - Screen %d", emulator_info::get_appname(), machine.system().type.fullname(), machine.system().name, index);
-
- // set the initial maximized state
- window->m_startmaximized = options.maximize();
-
- window->m_init_state = window->complete_create() ? -1 : 1;
-
- // handle error conditions
- if (window->m_init_state == -1)
- fatalerror("Unable to complete window creation\n");
-}
-
-std::shared_ptr<osd_monitor_info> uwp_window_info::monitor_from_rect(const osd_rect* proposed) const
-{
- std::shared_ptr<osd_monitor_info> monitor;
-
- // in window mode, find the nearest
- if (!fullscreen())
- {
- if (proposed != nullptr)
- {
- monitor = m_monitor->module().monitor_from_rect(*proposed);
- }
- else
- monitor = m_monitor->module().monitor_from_window(*this);
- }
- else
- {
- // in full screen, just use the configured monitor
- monitor = m_monitor;
- }
-
- return monitor;
-}
-
-//============================================================
-// winwindow_video_window_destroy
-// (main thread)
-//============================================================
-
-void uwp_window_info::destroy()
-{
- assert(GetCurrentThreadId() == main_threadid);
-
- // remove us from the list
- osd_common_t::s_window_list.remove(shared_from_this());
-
- // destroy the window
-// if (platform_window<HWND>() != nullptr)
- // DestroyWindow(platform_window<HWND>());
-
- // free the render target
- machine().render().target_free(m_target);
-}
-
-
-
-//============================================================
-// winwindow_video_window_update
-// (main thread)
-//============================================================
-
-void uwp_window_info::update()
-{
- int targetview, targetorient;
- render_layer_config targetlayerconfig;
-
- assert(GetCurrentThreadId() == main_threadid);
-
- // see if the target has changed significantly in window mode
- targetview = m_target->view();
- targetorient = m_target->orientation();
- targetlayerconfig = m_target->layer_config();
- if (targetview != m_targetview || targetorient != m_targetorient || targetlayerconfig != m_targetlayerconfig)
- {
- m_targetview = targetview;
- m_targetorient = targetorient;
- m_targetlayerconfig = targetlayerconfig;
-
- // in window mode, reminimize/maximize
- if (!fullscreen())
- {
- //if (m_isminimized)
- //SendMessage(platform_window<HWND>(), WM_USER_SET_MINSIZE, 0, 0);
- //if (m_ismaximized)
-// SendMessage(platform_window<HWND>(), WM_USER_SET_MAXSIZE, 0, 0);
- }
- }
-
- // if we're visible and running and not in the middle of a resize, draw
- if (platform_window() != nullptr && m_target != nullptr && has_renderer())
- {
- bool got_lock = true;
- auto clock = std::chrono::high_resolution_clock();
-
- // only block if we're throttled
- if (machine().video().throttled() || clock.now() - last_update_time > std::chrono::milliseconds(250))
- m_render_lock.lock();
- else
- got_lock = m_render_lock.try_lock();
-
- // only render if we were able to get the lock
- if (got_lock)
- {
- render_primitive_list *primlist;
-
- // don't hold the lock; we just used it to see if rendering was still happening
- m_render_lock.unlock();
-
- // ensure the target bounds are up-to-date, and then get the primitives
- primlist = renderer().get_primitives();
-
- // post a redraw request with the primitive list as a parameter
- last_update_time = clock.now();
-
- // Actually perform the redraw
- m_primlist = primlist;
- draw_video_contents(false);
- }
- }
-}
-
-//============================================================
-// draw_video_contents
-// (window thread)
-//============================================================
-
-void uwp_window_info::draw_video_contents(bool update)
-{
- assert(GetCurrentThreadId() == window_threadid);
-
- std::lock_guard<std::mutex> lock(m_render_lock);
-
- // if we're iconic, don't bother
- if (platform_window() != nullptr)
- {
- // if no bitmap, just fill
- if (m_primlist == nullptr)
- {
- // For now do nothing, eventually we need to clear the window
- }
-
- // otherwise, render with our drawing system
- else
- {
- renderer().draw(update);
- }
- }
-}
-
-
-//============================================================
-// set_starting_view
-// (main thread)
-//============================================================
-
-void uwp_window_info::set_starting_view(int index, const char *defview, const char *view)
-{
- int viewindex;
-
- assert(GetCurrentThreadId() == main_threadid);
-
- // choose non-auto over auto
- if (strcmp(view, "auto") == 0 && strcmp(defview, "auto") != 0)
- view = defview;
-
- // query the video system to help us pick a view
- viewindex = target()->configured_view(view, index, video_config.numscreens);
-
- // set the view
- target()->set_view(viewindex);
-}
-
-
-//============================================================
-// winwindow_ui_pause
-// (main thread)
-//============================================================
-
-void winwindow_ui_pause(running_machine &machine, int pause)
-{
- int old_temp_pause = ui_temp_pause;
-
- assert(GetCurrentThreadId() == main_threadid);
-
- // if we're pausing, increment the pause counter
- if (pause)
- {
- // if we're the first to pause, we have to actually initiate it
- if (ui_temp_pause++ == 0)
- {
- // only call mame_pause if we weren't already paused due to some external reason
- ui_temp_was_paused = machine.paused();
- if (!ui_temp_was_paused)
- machine.pause();
-
- SetEvent(ui_pause_event);
- }
- }
-
- // if we're resuming, decrement the pause counter
- else
- {
- // if we're the last to resume, unpause MAME
- if (--ui_temp_pause == 0)
- {
- // but only do it if we were the ones who initiated it
- if (!ui_temp_was_paused)
- machine.resume();
-
- ResetEvent(ui_pause_event);
- }
- }
-
- if (LOG_TEMP_PAUSE)
- osd_printf_verbose("winwindow_ui_pause(): %d --> %d\n", old_temp_pause, ui_temp_pause);
-}
-
-
-
-//============================================================
-// winwindow_ui_is_paused
-//============================================================
-
-int winwindow_ui_is_paused(running_machine &machine)
-{
- return machine.paused() && ui_temp_was_paused;
-}
-
-
-
-//============================================================
-// wnd_extra_width
-// (window thread)
-//============================================================
-
-int uwp_window_info::wnd_extra_width()
-{
- RECT temprect = { 100, 100, 200, 200 };
- if (fullscreen())
- return 0;
- //AdjustWindowRectEx(&temprect, WINDOW_STYLE, win_has_menu(), WINDOW_STYLE_EX);
- return rect_width(&temprect) - 100;
-}
-
-
-
-//============================================================
-// wnd_extra_height
-// (window thread)
-//============================================================
-
-int uwp_window_info::wnd_extra_height()
-{
- RECT temprect = { 100, 100, 200, 200 };
- if (fullscreen())
- return 0;
- //AdjustWindowRectEx(&temprect, WINDOW_STYLE, win_has_menu(), WINDOW_STYLE_EX);
- return rect_height(&temprect) - 100;
-}
-
-
-//============================================================
-// complete_create
-// (window thread)
-//============================================================
-
-int uwp_window_info::complete_create()
-{
- int tempwidth, tempheight;
-
- assert(GetCurrentThreadId() == window_threadid);
-
- // get the monitor bounds
- osd_rect monitorbounds = m_monitor->position_size();
-
- auto coreWindow = Platform::Agile<CoreWindow>(CoreWindow::GetForCurrentThread());
- set_platform_window(coreWindow);
-
- // skip the positioning stuff for -video none */
- if (video_config.mode == VIDEO_MODE_NONE)
- {
- set_renderer(osd_renderer::make_for_type(video_config.mode, shared_from_this()));
- renderer().create();
- return 0;
- }
-
- // adjust the window position to the initial width/height
- tempwidth = (m_win_config.width != 0) ? m_win_config.width : 640;
- tempheight = (m_win_config.height != 0) ? m_win_config.height : 480;
-
- // maximum or minimize as appropriate
- if (m_startmaximized)
- maximize_window();
- else
- minimize_window();
- adjust_window_position_after_major_change();
-
- // show the window
- if (!fullscreen() || m_fullscreen_safe)
- {
- set_renderer(osd_renderer::make_for_type(video_config.mode, shared_from_this()));
- if (renderer().create())
- return 1;
-
- }
-
- return 0;
-}
-
-
-//============================================================
-// constrain_to_aspect_ratio
-// (window thread)
-//============================================================
-
-osd_rect uwp_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int adjustment)
-{
- assert(GetCurrentThreadId() == window_threadid);
-
- int32_t extrawidth = wnd_extra_width();
- int32_t extraheight = wnd_extra_height();
- int32_t propwidth, propheight;
- int32_t minwidth, minheight;
- int32_t maxwidth, maxheight;
- int32_t viswidth, visheight;
- int32_t adjwidth, adjheight;
- float pixel_aspect;
-
- auto monitor = monitor_from_rect(&rect);
-
- // Sometimes this gets called when monitors have already been torn down
- // In that the case, just return the unmodified rect
- if (monitor == nullptr)
- return rect;
-
- // do not constrain aspect ratio for integer scaled views
- if (m_target->scale_mode() != SCALE_FRACTIONAL)
- return rect;
-
- // get the pixel aspect ratio for the target monitor
- pixel_aspect = monitor->pixel_aspect();
-
- // determine the proposed width/height
- propwidth = rect.width() - extrawidth;
- propheight = rect.height() - extraheight;
-
- // based on which edge we are adjusting, take either the width, height, or both as gospel
- // and scale to fit using that as our parameter
- switch (adjustment)
- {
- case WMSZ_BOTTOM:
- case WMSZ_TOP:
- m_target->compute_visible_area(10000, propheight, pixel_aspect, m_target->orientation(), propwidth, propheight);
- break;
-
- case WMSZ_LEFT:
- case WMSZ_RIGHT:
- m_target->compute_visible_area(propwidth, 10000, pixel_aspect, m_target->orientation(), propwidth, propheight);
- break;
-
- default:
- m_target->compute_visible_area(propwidth, propheight, pixel_aspect, m_target->orientation(), propwidth, propheight);
- break;
- }
-
- // get the minimum width/height for the current layout
- m_target->compute_minimum_size(minwidth, minheight);
-
- // clamp against the absolute minimum
- propwidth = std::max(propwidth, MIN_WINDOW_DIM);
- propheight = std::max(propheight, MIN_WINDOW_DIM);
-
- // clamp against the minimum width and height
- propwidth = std::max(propwidth, minwidth);
- propheight = std::max(propheight, minheight);
-
- // clamp against the maximum (fit on one screen for full screen mode)
- if (fullscreen())
- {
- maxwidth = monitor->position_size().width() - extrawidth;
- maxheight = monitor->position_size().height() - extraheight;
- }
- else
- {
- maxwidth = monitor->usuable_position_size().width() - extrawidth;
- maxheight = monitor->usuable_position_size().height() - extraheight;
-
- // further clamp to the maximum width/height in the window
- if (m_win_config.width != 0)
- maxwidth = std::min(maxwidth, m_win_config.width + extrawidth);
- if (m_win_config.height != 0)
- maxheight = std::min(maxheight, m_win_config.height + extraheight);
- }
-
- // clamp to the maximum
- propwidth = std::min(propwidth, maxwidth);
- propheight = std::min(propheight, maxheight);
-
- // compute the visible area based on the proposed rectangle
- m_target->compute_visible_area(propwidth, propheight, pixel_aspect, m_target->orientation(), viswidth, visheight);
-
- // compute the adjustments we need to make
- adjwidth = (viswidth + extrawidth) - rect.width();
- adjheight = (visheight + extraheight) - rect.height();
-
- // based on which corner we're adjusting, constrain in different ways
- osd_rect ret(rect);
-
- switch (adjustment)
- {
- case WMSZ_BOTTOM:
- case WMSZ_BOTTOMRIGHT:
- case WMSZ_RIGHT:
- ret = rect.resize(rect.width() + adjwidth, rect.height() + adjheight);
- break;
-
- case WMSZ_BOTTOMLEFT:
- ret = rect.move_by(-adjwidth, 0).resize(rect.width() + adjwidth, rect.height() + adjheight);
- break;
-
- case WMSZ_LEFT:
- case WMSZ_TOPLEFT:
- case WMSZ_TOP:
- ret = rect.move_by(-adjwidth, -adjheight).resize(rect.width() + adjwidth, rect.height() + adjheight);
- break;
-
- case WMSZ_TOPRIGHT:
- ret = rect.move_by(0, -adjheight).resize(rect.width() + adjwidth, rect.height() + adjheight);
- break;
- }
- return ret;
-}
-
-
-
-//============================================================
-// get_min_bounds
-// (window thread)
-//============================================================
-
-osd_dim uwp_window_info::get_min_bounds(int constrain)
-{
- int32_t minwidth, minheight;
-
- //assert(GetCurrentThreadId() == window_threadid);
-
- // get the minimum target size
- m_target->compute_minimum_size(minwidth, minheight);
-
- // expand to our minimum dimensions
- if (minwidth < MIN_WINDOW_DIM)
- minwidth = MIN_WINDOW_DIM;
- if (minheight < MIN_WINDOW_DIM)
- minheight = MIN_WINDOW_DIM;
-
- // account for extra window stuff
- minwidth += wnd_extra_width();
- minheight += wnd_extra_height();
-
- // if we want it constrained, figure out which one is larger
- if (constrain && m_target->scale_mode() == SCALE_FRACTIONAL)
- {
- // first constrain with no height limit
- osd_rect test1(0,0,minwidth,10000);
- test1 = constrain_to_aspect_ratio(test1, WMSZ_BOTTOMRIGHT);
-
- // then constrain with no width limit
- osd_rect test2(0,0,10000,minheight);
- test2 = constrain_to_aspect_ratio(test2, WMSZ_BOTTOMRIGHT);
-
- // pick the larger
- if (test1.width() > test2.width())
- {
- minwidth = test1.width();
- minheight = test1.height();
- }
- else
- {
- minwidth = test2.width();
- minheight = test2.height();
- }
- }
-
- return osd_dim(minwidth, minheight);
-}
-
-
-
-//============================================================
-// get_max_bounds
-// (window thread)
-//============================================================
-
-osd_dim uwp_window_info::get_max_bounds(int constrain)
-{
- //assert(GetCurrentThreadId() == window_threadid);
-
- // compute the maximum client area
- //m_monitor->refresh();
- osd_rect maximum = m_monitor->usuable_position_size();
-
- // clamp to the window's max
- int tempw = maximum.width();
- int temph = maximum.height();
- if (m_win_config.width != 0)
- {
- int temp = m_win_config.width + wnd_extra_width();
- if (temp < maximum.width())
- tempw = temp;
- }
- if (m_win_config.height != 0)
- {
- int temp = m_win_config.height + wnd_extra_height();
- if (temp < maximum.height())
- temph = temp;
- }
-
- maximum = maximum.resize(tempw, temph);
-
- // constrain to fit
- if (constrain && m_target->scale_mode() == SCALE_FRACTIONAL)
- maximum = constrain_to_aspect_ratio(maximum, WMSZ_BOTTOMRIGHT);
-
- return maximum.dim();
-}
-
-
-
-//============================================================
-// update_minmax_state
-// (window thread)
-//============================================================
-
-void uwp_window_info::update_minmax_state()
-{
- assert(GetCurrentThreadId() == window_threadid);
-
- if (!fullscreen())
- {
- RECT bounds;
-
- // compare the maximum bounds versus the current bounds
- osd_dim minbounds = get_min_bounds(video_config.keepaspect);
- osd_dim maxbounds = get_max_bounds(video_config.keepaspect);
- //GetWindowRect(platform_window<HWND>(), &bounds);
-
- // if either the width or height matches, we were maximized
- m_isminimized = (rect_width(&bounds) == minbounds.width()) ||
- (rect_height(&bounds) == minbounds.height());
- m_ismaximized = (rect_width(&bounds) == maxbounds.width()) ||
- (rect_height(&bounds) == maxbounds.height());
- }
- else
- {
- m_isminimized = FALSE;
- m_ismaximized = TRUE;
- }
-}
-
-
-
-//============================================================
-// minimize_window
-// (window thread)
-//============================================================
-
-void uwp_window_info::minimize_window()
-{
- assert(GetCurrentThreadId() == window_threadid);
-
- osd_dim newsize = get_min_bounds(video_config.keepaspect);
-
- // get the window rect
- //RECT bounds;
- //GetWindowRect(platform_window<HWND>(), &bounds);
-
- //osd_rect newrect(bounds.left, bounds.top, newsize );
-
-
- //SetWindowPos(platform_window<HWND>(), nullptr, newrect.left(), newrect.top(), newrect.width(), newrect.height(), SWP_NOZORDER);
-}
-
-//============================================================
-// maximize_window
-// (window thread)
-//============================================================
-
-void uwp_window_info::maximize_window()
-{
- assert(GetCurrentThreadId() == window_threadid);
-
- osd_dim newsize = get_max_bounds(video_config.keepaspect);
-
- // center within the work area
- osd_rect work = m_monitor->usuable_position_size();
- osd_rect newrect = osd_rect(work.left() + (work.width() - newsize.width()) / 2,
- work.top() + (work.height() - newsize.height()) / 2,
- newsize);
-
- //SetWindowPos(platform_window<HWND>(), nullptr, newrect.left(), newrect.top(), newrect.width(), newrect.height(), SWP_NOZORDER);
-}
-
-
-
-//============================================================
-// adjust_window_position_after_major_change
-// (window thread)
-//============================================================
-
-void uwp_window_info::adjust_window_position_after_major_change()
-{
- RECT oldrect;
-
- assert(GetCurrentThreadId() == window_threadid);
-
- // get the current size
- //GetWindowRect(platform_window<HWND>(), &oldrect);
- osd_rect newrect = RECT_to_osd_rect(oldrect);
-
- // adjust the window size so the client area is what we want
- if (!fullscreen())
- {
- // constrain the existing size to the aspect ratio
- if (video_config.keepaspect)
- newrect = constrain_to_aspect_ratio(newrect, WMSZ_BOTTOMRIGHT);
- }
-
- // in full screen, make sure it covers the primary display
- else
- {
- std::shared_ptr<osd_monitor_info> monitor = monitor_from_rect(nullptr);
- newrect = monitor->position_size();
- }
-
- // adjust the position if different
- if (oldrect.left != newrect.left() || oldrect.top != newrect.top() ||
- oldrect.right != newrect.right() || oldrect.bottom != newrect.bottom())
- //SetWindowPos(platform_window<HWND>(), fullscreen() ? HWND_TOPMOST : HWND_TOP,
- // newrect.left(), newrect.top(),
- //newrect.width(), newrect.height(), 0);
-
- // take note of physical window size (used for lightgun coordinate calculation)
- if (m_index == 0)
- {
- win_physical_width = newrect.width();
- win_physical_height = newrect.height();
- osd_printf_verbose("Physical width %d, height %d\n",win_physical_width,win_physical_height);
- }
-}
-
-
-//============================================================
-// set_fullscreen
-// (window thread)
-//============================================================
-
-void uwp_window_info::set_fullscreen(int fullscreen)
-{
- assert(GetCurrentThreadId() == window_threadid);
-
- // if we're in the right state, punt
- if (this->fullscreen() == fullscreen)
- return;
- m_fullscreen = fullscreen;
-
- // reset UI to main menu
- machine().ui().menu_reset();
-
- // kill off the drawers
- renderer_reset();
-
- // hide ourself
- //ShowWindow(platform_window<HWND>(), SW_HIDE);
-
- // configure the window if non-fullscreen
- if (!fullscreen)
- {
- // adjust the style
- //SetWindowLong(platform_window<HWND>(), GWL_STYLE, WINDOW_STYLE);
- //SetWindowLong(platform_window<HWND>(), GWL_EXSTYLE, WINDOW_STYLE_EX);
- //SetWindowPos(platform_window<HWND>(), nullptr, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
-
- // force to the bottom, then back on top
- //SetWindowPos(platform_window<HWND>(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
- //SetWindowPos(platform_window<HWND>(), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
-
- //// if we have previous non-fullscreen bounds, use those
- //if (m_non_fullscreen_bounds.right != m_non_fullscreen_bounds.left)
- //{
- // SetWindowPos(platform_window<HWND>(), HWND_TOP, m_non_fullscreen_bounds.left, m_non_fullscreen_bounds.top,
- // rect_width(&m_non_fullscreen_bounds), rect_height(&m_non_fullscreen_bounds),
- // SWP_NOZORDER);
- //}
- //
- //// otherwise, set a small size and maximize from there
- //else
- //{
- // SetWindowPos(platform_window<HWND>(), HWND_TOP, 0, 0, MIN_WINDOW_DIM, MIN_WINDOW_DIM, SWP_NOZORDER);
- // maximize_window();
- //}
- }
-
- // configure the window if fullscreen
- else
- {
- // save the bounds
- //GetWindowRect(platform_window<HWND>(), &m_non_fullscreen_bounds);
- //
- //// adjust the style
- //SetWindowLong(platform_window<HWND>(), GWL_STYLE, FULLSCREEN_STYLE);
- //SetWindowLong(platform_window<HWND>(), GWL_EXSTYLE, FULLSCREEN_STYLE_EX);
- //SetWindowPos(platform_window<HWND>(), nullptr, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
- //
- //// set topmost
- //SetWindowPos(platform_window<HWND>(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
- }
-
- // adjust the window to compensate for the change
- adjust_window_position_after_major_change();
-
- // show ourself
- if (!this->fullscreen() || m_fullscreen_safe)
- {
- //if (video_config.mode != VIDEO_MODE_NONE)
- //ShowWindow(platform_window<HWND>(), SW_SHOW);
-
- set_renderer(osd_renderer::make_for_type(video_config.mode, shared_from_this()));
- if (renderer().create())
- exit(1);
- }
-
- // ensure we're still adjusted correctly
- adjust_window_position_after_major_change();
-}
-
diff --git a/src/osd/uwp/window.h b/src/osd/uwp/window.h
deleted file mode 100644
index 21948028343..00000000000
--- a/src/osd/uwp/window.h
+++ /dev/null
@@ -1,166 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Aaron Giles, Brad Hughes
-//============================================================
-//
-// window.h - UWP window handling
-//
-//============================================================
-
-#ifndef __UWP_WINDOW__
-#define __UWP_WINDOW__
-
-// standard windows headers
-#include <windows.h>
-#include <windowsx.h>
-#include <mmsystem.h>
-#include <inspectable.h>
-#include <agile.h>
-
-#include <chrono>
-#include <mutex>
-#include <memory>
-#include <list>
-
-#include "render.h"
-
-#include "modules/osdwindow.h"
-
-//============================================================
-// PARAMETERS
-//============================================================
-
-
-//============================================================
-// CONSTANTS
-//============================================================
-
-#define RESIZE_STATE_NORMAL 0
-#define RESIZE_STATE_RESIZING 1
-#define RESIZE_STATE_PENDING 2
-
-
-
-//============================================================
-// TYPE DEFINITIONS
-//============================================================
-
-class uwp_window_info : public osd_window_t<Platform::Agile<Windows::UI::Core::CoreWindow>>
-{
-public:
- uwp_window_info(running_machine &machine, int index, std::shared_ptr<osd_monitor_info> monitor, const osd_window_config *config);
-
- running_machine &machine() const override { return m_machine; }
-
- virtual render_target *target() override { return m_target; }
- int fullscreen() const override { return m_fullscreen; }
-
- void update() override;
-
- virtual osd_dim get_size() override
- {
- auto bounds = platform_window()->Bounds;
- return osd_dim(bounds.Width, bounds.Height);
- }
-
- bool win_has_menu() override
- {
- return false;
- }
-
- void capture_pointer() override;
- void release_pointer() override;
- void show_pointer() override;
- void hide_pointer() override;
-
- virtual osd_monitor_info *monitor() const override { return m_monitor.get(); }
-
- void destroy() override;
-
- // static
-
- static void create(running_machine &machine, int index, std::shared_ptr<osd_monitor_info> monitor, const osd_window_config *config);
-
- // member variables
-
- uwp_window_info * m_next;
- volatile int m_init_state;
-
- // window handle and info
- char m_title[256];
- RECT m_non_fullscreen_bounds;
- int m_startmaximized;
- int m_isminimized;
- int m_ismaximized;
-
- // monitor info
- std::shared_ptr<osd_monitor_info> m_monitor;
- int m_fullscreen;
- int m_fullscreen_safe;
- float m_aspect;
-
- // rendering info
- std::mutex m_render_lock;
- render_target * m_target;
- int m_targetview;
- int m_targetorient;
- render_layer_config m_targetlayerconfig;
-
- // input info
- std::chrono::system_clock::time_point m_lastclicktime;
- int m_lastclickx;
- int m_lastclicky;
-
-private:
- int complete_create();
- void draw_video_contents(bool update);
- void set_starting_view(int index, const char *defview, const char *view);
- int wnd_extra_width();
- int wnd_extra_height();
- osd_rect constrain_to_aspect_ratio(const osd_rect &rect, int adjustment);
- osd_dim get_min_bounds(int constrain);
- osd_dim get_max_bounds(int constrain);
- void update_minmax_state();
- void minimize_window();
- void maximize_window();
- void adjust_window_position_after_major_change();
- void set_fullscreen(int fullscreen);
- std::shared_ptr<osd_monitor_info> monitor_from_rect(const osd_rect* proposed) const;
-
- static POINT s_saved_cursor_pos;
-
- static Windows::UI::Core::CoreCursor^ s_cursor;
-
- running_machine & m_machine;
-};
-
-struct osd_draw_callbacks
-{
- osd_renderer *(*create)(osd_window *window);
- void (*exit)(void);
-};
-
-
-//============================================================
-// PROTOTYPES
-//============================================================
-
-bool winwindow_has_focus(void);
-void winwindow_process_events(running_machine &machine, bool ingame, bool nodispatch);
-void winwindow_process_events_periodic(running_machine &machine);
-
-//============================================================
-// rect_width / rect_height
-//============================================================
-
-static inline int rect_width(const RECT *rect)
-{
- return rect->right - rect->left;
-}
-
-
-static inline int rect_height(const RECT *rect)
-{
- return rect->bottom - rect->top;
-}
-
-#endif
diff --git a/src/osd/watchdog.cpp b/src/osd/watchdog.cpp
index 09f720b7fcc..4e5177cd300 100644
--- a/src/osd/watchdog.cpp
+++ b/src/osd/watchdog.cpp
@@ -43,7 +43,7 @@ void osd_watchdog::setTimeout(int timeout)
void *osd_watchdog::watchdog_thread(void *param)
{
- osd_watchdog *const thiz(reinterpret_cast<osd_watchdog *>(param));
+ auto *const thiz(reinterpret_cast<osd_watchdog *>(param));
while (true)
{
diff --git a/src/osd/windows/ledutil.cpp b/src/osd/windows/ledutil.cpp
index 8f2a781b427..f1976cd41bc 100644
--- a/src/osd/windows/ledutil.cpp
+++ b/src/osd/windows/ledutil.cpp
@@ -34,9 +34,9 @@
// standard C headers
#include <conio.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
// MAME output header file
typedef int running_machine;
diff --git a/src/osd/windows/main.cpp b/src/osd/windows/main.cpp
deleted file mode 100644
index 6d81d824f02..00000000000
--- a/src/osd/windows/main.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
-//============================================================
-//
-// main.cpp - Win32 main program
-//
-//============================================================
-
-// standard windows headers
-#ifdef OSD_SDL
-#define _WIN32_WINNT 0x0501
-#endif
-#include <windows.h>
-#include <tchar.h>
-#include <stdlib.h>
-#include <vector>
-#include <string>
-
-#include "strconv.h"
-
-#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-
-#include "winmain.h"
-
-// The main function is only used to initialize our IFrameworkView class.
-[Platform::MTAThread]
-int main(Platform::Array<Platform::String^>^)
-{
- auto app_source = ref new MameViewSource();
- Windows::ApplicationModel::Core::CoreApplication::Run(app_source);
- return 0;
-}
-
-#endif
diff --git a/src/osd/windows/video.cpp b/src/osd/windows/video.cpp
index 889e76caa6b..439f0019f69 100644
--- a/src/osd/windows/video.cpp
+++ b/src/osd/windows/video.cpp
@@ -6,12 +6,14 @@
//
//============================================================
-// standard windows headers
-#include <windows.h>
+#include "modules/osdwindow.h"
+#include "modules/monitor/monitor_module.h"
+#include "modules/render/render_module.h"
// MAME headers
#include "emu.h"
#include "emuopts.h"
+#include "main.h"
#include "render.h"
#include "uiinput.h"
@@ -20,7 +22,8 @@
#include "window.h"
#include "strconv.h"
-#include "modules/osdwindow.h"
+// standard windows headers
+#include <windows.h>
//============================================================
// CONSTANTS
@@ -57,14 +60,20 @@ bool windows_osd_interface::video_init()
window_init();
// create the windows
- windows_options &options = downcast<windows_options &>(machine().options());
+ auto &options = downcast<windows_options &>(machine().options());
for (int index = 0; index < video_config.numscreens; index++)
{
- win_window_info::create(machine(), index, m_monitor_module->pick_monitor(options, index), &windows[index]);
+ auto window = win_window_info::create(
+ machine(),
+ *m_render,
+ index,
+ m_monitor_module->pick_monitor(options, index),
+ &windows[index]);
+ s_window_list.emplace_back(std::move(window));
}
- if (video_config.mode != VIDEO_MODE_NONE)
- SetForegroundWindow(std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window());
+ if (m_render->is_interactive())
+ SetForegroundWindow(dynamic_cast<win_window_info &>(*osd_common_t::s_window_list.front()).platform_window());
return true;
}
@@ -90,15 +99,11 @@ void windows_osd_interface::update(bool skip_redraw)
if (!skip_redraw)
{
// profiler_mark(PROFILER_BLIT);
- for (auto window : osd_common_t::s_window_list)
+ for (const auto &window : osd_common_t::s_window_list)
window->update();
// profiler_mark(PROFILER_END);
}
- // poll the joystick values here
- winwindow_process_events(machine(), true, false);
- poll_input(machine());
- check_osd_inputs();
// if we're running, disable some parts of the debugger
if ((machine().debug_flags & DEBUG_FLAG_OSD_ENABLED) != 0)
debugger_update();
@@ -106,6 +111,17 @@ void windows_osd_interface::update(bool skip_redraw)
//============================================================
+// input_update
+//============================================================
+
+void windows_osd_interface::input_update(bool relative_reset)
+{
+ // poll the joystick values here
+ process_events(true, false);
+ poll_input_modules(relative_reset);
+}
+
+//============================================================
// check_osd_inputs
//============================================================
@@ -136,13 +152,10 @@ void windows_osd_interface::check_osd_inputs()
void windows_osd_interface::extract_video_config()
{
- const char *stemp;
-
// global options: extract the data
video_config.windowed = options().window();
video_config.prescale = options().prescale();
video_config.filter = options().filter();
- video_config.keepaspect = options().keep_aspect();
video_config.numscreens = options().numscreens();
// if we are in debug mode, never go full screen
@@ -156,100 +169,16 @@ void windows_osd_interface::extract_video_config()
get_resolution(default_resolution, options().resolution(2), &windows[2], TRUE);
get_resolution(default_resolution, options().resolution(3), &windows[3], TRUE);
- // video options: extract the data
- stemp = options().video();
- if (strcmp(stemp, "d3d") == 0)
- video_config.mode = VIDEO_MODE_D3D;
- else if (strcmp(stemp, "auto") == 0)
- video_config.mode = VIDEO_MODE_D3D;
- else if (strcmp(stemp, "gdi") == 0)
- video_config.mode = VIDEO_MODE_GDI;
- else if (strcmp(stemp, "bgfx") == 0)
- video_config.mode = VIDEO_MODE_BGFX;
- else if (strcmp(stemp, "none") == 0)
- {
- video_config.mode = VIDEO_MODE_NONE;
- if (!emulator_info::standalone() && options().seconds_to_run() == 0)
- osd_printf_warning("Warning: -video none doesn't make much sense without -seconds_to_run\n");
- }
-#if (USE_OPENGL)
- else if (strcmp(stemp, "opengl") == 0)
- video_config.mode = VIDEO_MODE_OPENGL;
-#endif
- else
- {
- osd_printf_warning("Invalid video value %s; reverting to gdi\n", stemp);
- video_config.mode = VIDEO_MODE_GDI;
- }
video_config.waitvsync = options().wait_vsync();
video_config.syncrefresh = options().sync_refresh();
video_config.triplebuf = options().triple_buffer();
video_config.switchres = options().switch_res();
- if (video_config.prescale < 1 || video_config.prescale > 3)
+ if (video_config.prescale < 1 || video_config.prescale > 20)
{
osd_printf_warning("Invalid prescale option, reverting to '1'\n");
video_config.prescale = 1;
}
- #if (USE_OPENGL)
- // default to working video please
- video_config.forcepow2texture = options().gl_force_pow2_texture();
- video_config.allowtexturerect = !(options().gl_no_texture_rect());
- video_config.vbo = options().gl_vbo();
- video_config.pbo = options().gl_pbo();
- video_config.glsl = options().gl_glsl();
- if ( video_config.glsl )
- {
- int i;
-
- video_config.glsl_filter = options().glsl_filter();
-
- video_config.glsl_shader_mamebm_num=0;
-
- for(i=0; i<GLSL_SHADER_MAX; i++)
- {
- stemp = options().shader_mame(i);
- if (stemp && strcmp(stemp, OSDOPTVAL_NONE) != 0 && strlen(stemp)>0)
- {
- video_config.glsl_shader_mamebm[i] = (char *) malloc(strlen(stemp)+1);
- strcpy(video_config.glsl_shader_mamebm[i], stemp);
- video_config.glsl_shader_mamebm_num++;
- } else {
- video_config.glsl_shader_mamebm[i] = nullptr;
- }
- }
-
- video_config.glsl_shader_scrn_num=0;
-
- for(i=0; i<GLSL_SHADER_MAX; i++)
- {
- stemp = options().shader_screen(i);
- if (stemp && strcmp(stemp, OSDOPTVAL_NONE) != 0 && strlen(stemp)>0)
- {
- video_config.glsl_shader_scrn[i] = (char *) malloc(strlen(stemp)+1);
- strcpy(video_config.glsl_shader_scrn[i], stemp);
- video_config.glsl_shader_scrn_num++;
- } else {
- video_config.glsl_shader_scrn[i] = nullptr;
- }
- }
- } else {
- int i;
- video_config.glsl_filter = 0;
- video_config.glsl_shader_mamebm_num=0;
- for(i=0; i<GLSL_SHADER_MAX; i++)
- {
- video_config.glsl_shader_mamebm[i] = nullptr;
- }
- video_config.glsl_shader_scrn_num=0;
- for(i=0; i<GLSL_SHADER_MAX; i++)
- {
- video_config.glsl_shader_scrn[i] = nullptr;
- }
- }
-
- #endif /* USE_OPENGL */
-
}
diff --git a/src/osd/windows/window.cpp b/src/osd/windows/window.cpp
index 3794e79cd14..2759b32227f 100644
--- a/src/osd/windows/window.cpp
+++ b/src/osd/windows/window.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Aaron Giles, Vas Crabb
//============================================================
//
// window.cpp - Win32 window handling
@@ -8,17 +8,12 @@
#define LOG_TEMP_PAUSE 0
-// Needed for RAW Input
-#define WM_INPUT 0x00FF
-
// standard C headers
#include <process.h>
+#include <algorithm>
#include <atomic>
#include <cstring>
-#include <chrono>
-#include <list>
-#include <memory>
// MAME headers
#include "emu.h"
@@ -36,23 +31,10 @@
#include "modules/monitor/monitor_common.h"
-#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-#include <agile.h>
-using namespace Windows::UI::Core;
-#endif
-
-#include "modules/render/drawbgfx.h"
-#include "modules/render/drawnone.h"
-#include "modules/render/drawd3d.h"
-#include "modules/render/drawgdi.h"
-#if (USE_OPENGL)
-#include "modules/render/drawogl.h"
-#endif
-
-#define NOT_ALREADY_DOWN(x) (x & 0x40000000) == 0
+#define NOT_ALREADY_DOWN(x) ((x & 0x40000000) == 0)
#define SCAN_CODE(x) ((x >> 16) & 0xff)
-#define IS_EXTENDED(x) (0x01000000 & x)
-#define MAKE_DI_SCAN(scan, isextended) (scan & 0x7f) | (isextended ? 0x80 : 0x00)
+#define IS_EXTENDED(x) ((x >> 24) & 0x01)
+#define MAKE_DI_SCAN(scan, isextended) ((scan & 0x7f) | (isextended ? 0x80 : 0x00))
#define WINOSD(machine) downcast<windows_osd_interface*>(&machine.osd())
//============================================================
@@ -72,7 +54,8 @@ using namespace Windows::UI::Core;
#define FULLSCREEN_STYLE_EX WS_EX_TOPMOST
// minimum window dimension
-#define MIN_WINDOW_DIM 200
+#define MIN_WINDOW_DIMX 200
+#define MIN_WINDOW_DIMY 50
// custom window messages
#define WM_USER_REDRAW (WM_USER + 2)
@@ -81,6 +64,34 @@ using namespace Windows::UI::Core;
#define WM_USER_SET_MINSIZE (WM_USER + 5)
+namespace {
+
+// If legacy mouse to pointer event translation is enabled, translated
+// WM_POINTER* events have pointer ID zero. Assume this will never be
+// seen for "real" pointer events.
+constexpr WORD MOUSE_POINTER_ID = 0;
+
+constexpr unsigned get_pointer_buttons(WPARAM wparam)
+{
+ return
+ (IS_POINTER_FIRSTBUTTON_WPARAM(wparam) ? 0x01 : 0x00) |
+ (IS_POINTER_SECONDBUTTON_WPARAM(wparam) ? 0x02 : 0x00) |
+ (IS_POINTER_THIRDBUTTON_WPARAM(wparam) ? 0x04 : 0x00) |
+ (IS_POINTER_FOURTHBUTTON_WPARAM(wparam) ? 0x08 : 0x00) |
+ (IS_POINTER_FIFTHBUTTON_WPARAM(wparam) ? 0x10 : 0x00);
+}
+
+constexpr osd::ui_event_handler::pointer convert_pointer_type(POINTER_INPUT_TYPE type)
+{
+ // PT_POINTER isn't a real type, and we'll leave PT_TOUCHPAD as unknown for now
+ return
+ (PT_TOUCH == type) ? osd::ui_event_handler::pointer::TOUCH :
+ (PT_PEN == type) ? osd::ui_event_handler::pointer::PEN :
+ (PT_MOUSE == type) ? osd::ui_event_handler::pointer::MOUSE :
+ osd::ui_event_handler::pointer::UNKNOWN;
+}
+
+} // anonymous namespace
//============================================================
// GLOBAL VARIABLES
@@ -95,8 +106,6 @@ static DWORD main_threadid;
//============================================================
// event handling
-static std::chrono::system_clock::time_point last_event_check;
-
static int ui_temp_pause;
static int ui_temp_was_paused;
@@ -116,7 +125,7 @@ static bool s_aggressive_focus;
//============================================================
-static void create_window_class(void);
+static void create_window_class();
//============================================================
// window_init
@@ -139,111 +148,23 @@ bool windows_osd_interface::window_init()
window_thread = GetCurrentThread();
window_threadid = main_threadid;
- const int fallbacks[VIDEO_MODE_COUNT] = {
- -1, // NONE -> no fallback
- VIDEO_MODE_NONE, // GDI -> NONE
- VIDEO_MODE_D3D, // BGFX -> D3D
-#if (USE_OPENGL)
- VIDEO_MODE_GDI, // OPENGL -> GDI
-#endif
- -1, // No SDL2ACCEL on Windows OSD
-#if (USE_OPENGL)
- VIDEO_MODE_OPENGL, // D3D -> OPENGL
-#else
- VIDEO_MODE_GDI, // D3D -> GDI
-#endif
- -1 // No SOFT on Windows OSD
- };
-
- int current_mode = video_config.mode;
- while (current_mode != VIDEO_MODE_NONE)
- {
- bool error = false;
- switch(current_mode)
- {
- case VIDEO_MODE_NONE:
- error = renderer_none::init(machine());
- break;
- case VIDEO_MODE_GDI:
- error = renderer_gdi::init(machine());
- break;
- case VIDEO_MODE_BGFX:
- error = renderer_bgfx::init(machine());
- break;
-#if (USE_OPENGL)
- case VIDEO_MODE_OPENGL:
- renderer_ogl::init(machine());
- break;
-#endif
- case VIDEO_MODE_SDL2ACCEL:
- fatalerror("SDL2-Accel renderer unavailable on Windows OSD.");
- break;
- case VIDEO_MODE_D3D:
- error = renderer_d3d9::init(machine());
- break;
- case VIDEO_MODE_SOFT:
- fatalerror("SDL1 renderer unavailable on Windows OSD.");
- break;
- default:
- fatalerror("Unknown video mode.");
- break;
- }
- if (error)
- {
- current_mode = fallbacks[current_mode];
- }
- else
- {
- break;
- }
- }
- video_config.mode = current_mode;
-
return true;
}
-void windows_osd_interface::update_slider_list()
-{
- for (auto window : osd_common_t::s_window_list)
- {
- // check if any window has dirty sliders
- if (window->has_renderer() && window->renderer().sliders_dirty())
- {
- build_slider_list();
- return;
- }
- }
-}
int windows_osd_interface::window_count()
{
- return osd_common_t::s_window_list.size();
-}
-
-void windows_osd_interface::build_slider_list()
-{
- m_sliders.clear();
-
- for (auto window : osd_common_t::s_window_list)
- {
- if (window->has_renderer())
- {
- // take the sliders of the first window
- std::vector<ui::menu_item> window_sliders = window->renderer().get_slider_list();
- m_sliders.insert(m_sliders.end(), window_sliders.begin(), window_sliders.end());
- }
- }
+ return osd_common_t::window_list().size();
}
void windows_osd_interface::add_audio_to_recording(const int16_t *buffer, int samples_this_frame)
{
- auto window = osd_common_t::s_window_list.front(); // We only record on the first window
- if (window != nullptr)
- {
+ auto const &window = osd_common_t::window_list().front(); // We only record on the first window
+ if (window)
window->renderer().add_audio_to_recording(buffer, samples_this_frame);
- }
}
+
//============================================================
// winwindow_exit
// (main thread)
@@ -260,76 +181,71 @@ void windows_osd_interface::window_exit()
// free all the windows
while (!osd_common_t::s_window_list.empty())
{
- auto window = osd_common_t::s_window_list.front();
-
- // Destroy removes it from the list also
+ auto window = std::move(osd_common_t::s_window_list.back());
+ s_window_list.pop_back();
window->destroy();
}
- switch(video_config.mode)
- {
- case VIDEO_MODE_NONE:
- renderer_none::exit();
- break;
- case VIDEO_MODE_GDI:
- renderer_gdi::exit();
- break;
- case VIDEO_MODE_BGFX:
- renderer_bgfx::exit();
- break;
-#if (USE_OPENGL)
- case VIDEO_MODE_OPENGL:
- renderer_ogl::exit();
- break;
-#endif
- case VIDEO_MODE_D3D:
- renderer_d3d9::exit();
- break;
- default:
- break;
- }
-
// kill the UI pause event
if (ui_pause_event)
CloseHandle(ui_pause_event);
}
+
+inline win_window_info::win_pointer_info::win_pointer_info(WORD p, POINTER_INPUT_TYPE t, unsigned i, unsigned d)
+ : pointer_info(i, d)
+ , ptrid(p)
+ , type(t)
+{
+}
+
+
win_window_info::win_window_info(
- running_machine &machine,
- int index,
- std::shared_ptr<osd_monitor_info> monitor,
- const osd_window_config *config) : osd_window_t(*config),
- m_next(nullptr),
- m_init_state(0),
- m_startmaximized(0),
- m_isminimized(0),
- m_ismaximized(0),
- m_monitor(monitor),
- m_fullscreen(!video_config.windowed),
- m_fullscreen_safe(0),
- m_aspect(0),
- m_target(nullptr),
- m_targetview(0),
- m_targetorient(0),
- m_lastclicktime(std::chrono::system_clock::time_point::min()),
- m_lastclickx(0),
- m_lastclicky(0),
- m_machine(machine),
- m_attached_mode(false)
+ running_machine &machine,
+ render_module &renderprovider,
+ int index,
+ const std::shared_ptr<osd_monitor_info> &monitor,
+ const osd_window_config *config)
+ : osd_window_t(machine, renderprovider, index, std::move(monitor), *config)
+ , m_init_state(0)
+ , m_startmaximized(0)
+ , m_isminimized(0)
+ , m_ismaximized(0)
+ , m_fullscreen_safe(0)
+ , m_aspect(0)
+ , m_targetview(0)
+ , m_targetorient(0)
+ , m_targetvismask(0)
+ , m_targetscalemode(0)
+ , m_targetkeepaspect(machine.options().keep_aspect())
+ , m_lastclicktime(std::chrono::steady_clock::time_point::min())
+ , m_lastclickx(0)
+ , m_lastclicky(0)
+ , m_last_surrogate(0)
+ , m_dc(nullptr)
+ , m_resize_state(RESIZE_STATE_NORMAL)
+ , m_main(nullptr)
+ , m_attached_mode(false)
+ , m_pointer_mask(0)
+ , m_next_pointer(0)
+ , m_next_ptrdev(0)
+ , m_tracking_mouse(false)
{
- memset(m_title,0,sizeof(m_title));
m_non_fullscreen_bounds.left = 0;
m_non_fullscreen_bounds.top = 0;
m_non_fullscreen_bounds.right = 0;
m_non_fullscreen_bounds.bottom = 0;
+
+ m_fullscreen = !video_config.windowed;
m_prescale = video_config.prescale;
- m_index = index;
+
+ m_ptrdev_map.reserve(8);
+ m_ptrdev_info.reserve(1);
+ m_active_pointers.reserve(16);
}
POINT win_window_info::s_saved_cursor_pos = { -1, -1 };
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-
void win_window_info::capture_pointer()
{
RECT bounds;
@@ -348,7 +264,7 @@ void win_window_info::hide_pointer()
{
GetCursorPos(&s_saved_cursor_pos);
- while (ShowCursor(FALSE) >= -1) {};
+ while (ShowCursor(FALSE) >= -1) { }
ShowCursor(TRUE);
}
@@ -360,95 +276,104 @@ void win_window_info::show_pointer()
s_saved_cursor_pos.x = s_saved_cursor_pos.y = -1;
}
- while (ShowCursor(TRUE) < 1) {};
+ while (ShowCursor(TRUE) < 1) { }
ShowCursor(FALSE);
}
-#else
-CoreCursor^ win_window_info::s_cursor = nullptr;
-
-void win_window_info::capture_pointer()
+bool windows_osd_interface::has_focus() const
{
- platform_window<Platform::Agile<CoreWindow^>>()->SetPointerCapture();
+ return winwindow_has_focus();
}
-void win_window_info::release_pointer()
-{
- platform_window<Platform::Agile<CoreWindow^>>()->ReleasePointerCapture();
-}
-
-void win_window_info::hide_pointer()
-{
- auto window = platform_window<Platform::Agile<CoreWindow^>>();
- win_window_info::s_cursor = window->PointerCursor;
- window->PointerCursor = nullptr;
-}
-
-void win_window_info::show_pointer()
-{
- auto window = platform_window<Platform::Agile<CoreWindow^>>();
- window->PointerCursor = win_window_info::s_cursor;
-}
-
-#endif
//============================================================
// winwindow_process_events_periodic
// (main thread)
//============================================================
-void winwindow_process_events_periodic(running_machine &machine)
+void windows_osd_interface::process_events()
{
- auto currticks = std::chrono::system_clock::now();
-
assert(GetCurrentThreadId() == main_threadid);
+ auto const currticks = std::chrono::steady_clock::now();
+
// update once every 1/8th of a second
- if (currticks - last_event_check < std::chrono::milliseconds(1000 / 8))
+ if (currticks < (m_last_event_check + std::chrono::milliseconds(1000 / 8)))
return;
- winwindow_process_events(machine, true, false);
+
+ process_events(true, false);
}
//============================================================
+// winwindow_video_window_proc_ui
+// (window thread)
+//============================================================
+
+static LRESULT CALLBACK winwindow_video_window_proc_ui(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam)
+{
+ return win_window_info::video_window_proc(wnd, message, wparam, lparam);
+}
+
+//============================================================
// is_mame_window
//============================================================
-static bool is_mame_window(HWND hwnd)
+inline bool is_mame_window(HWND hwnd)
{
- for (auto window : osd_common_t::s_window_list)
- if (std::static_pointer_cast<win_window_info>(window)->platform_window() == hwnd)
+ for (const auto &window : osd_common_t::window_list())
+ if (dynamic_cast<win_window_info &>(*window).platform_window() == hwnd)
return true;
return false;
}
-inline static BOOL handle_mouse_button(windows_osd_interface *osd, int button, int down, int x, int y)
+inline BOOL handle_mouse_button(windows_osd_interface &osd, int button, int down, LPARAM lparam)
{
- MouseButtonEventArgs args;
- args.button = button;
- args.keydown = down;
- args.xpos = x;
- args.ypos = y;
+ MouseUpdateEventArgs args;
+ args.pressed = (down ? 1 : 0) << button;
+ args.released = (down ? 0 : 1) << button;
+ args.vdelta = 0;
+ args.hdelta = 0;
+ args.xpos = GET_X_LPARAM(lparam);
+ args.ypos = GET_Y_LPARAM(lparam);
- bool handled = osd->handle_input_event(INPUT_EVENT_MOUSE_BUTTON, &args);
+ bool const handled = osd.handle_input_event(INPUT_EVENT_MOUSE_BUTTON, &args);
// When in lightgun mode or mouse mode, the mouse click may be routed to the input system
// because the mouse interactions in the UI are routed from the video_window_proc below
// we need to make sure they aren't suppressed in these cases.
- return handled && !osd->options().lightgun() && !osd->options().mouse();
+ return handled && !osd.options().lightgun() && !osd.options().mouse();
}
-inline static BOOL handle_keypress(windows_osd_interface *osd, int vkey, int down, int scancode, BOOL extended_key)
+inline BOOL handle_mouse_wheel(windows_osd_interface &osd, int v, int h, LPARAM lparam)
+{
+ MouseUpdateEventArgs args;
+ args.pressed = 0;
+ args.released = 0;
+ args.vdelta = v;
+ args.hdelta = h;
+ args.xpos = GET_X_LPARAM(lparam);
+ args.ypos = GET_Y_LPARAM(lparam);
+
+ bool const handled = osd.handle_input_event(INPUT_EVENT_MOUSE_WHEEL, &args);
+
+ // When in lightgun mode or mouse mode, the mouse wheel may be routed to the input system
+ // because the mouse interactions in the UI are routed from the video_window_proc below
+ // we need to make sure they aren't suppressed in these cases.
+ return handled && !osd.options().lightgun() && !osd.options().mouse();
+}
+
+inline BOOL handle_keypress(windows_osd_interface &osd, int vkey, int down, LPARAM lparam)
{
KeyPressEventArgs args;
args.event_id = down ? INPUT_EVENT_KEYDOWN : INPUT_EVENT_KEYUP;
- args.scancode = MAKE_DI_SCAN(scancode, extended_key);
+ args.scancode = MAKE_DI_SCAN(SCAN_CODE(lparam), IS_EXTENDED(lparam));
args.vkey = vkey;
- return osd->handle_input_event(args.event_id, &args);
+ return osd.handle_input_event(args.event_id, &args);
}
//============================================================
@@ -456,14 +381,12 @@ inline static BOOL handle_keypress(windows_osd_interface *osd, int vkey, int dow
// (main thread)
//============================================================
-void winwindow_process_events(running_machine &machine, bool ingame, bool nodispatch)
+void windows_osd_interface::process_events(bool ingame, bool nodispatch)
{
- MSG message;
-
assert(GetCurrentThreadId() == main_threadid);
// remember the last time we did this
- last_event_check = std::chrono::system_clock::now();
+ m_last_event_check = std::chrono::steady_clock::now();
do
{
@@ -472,75 +395,87 @@ void winwindow_process_events(running_machine &machine, bool ingame, bool nodisp
WaitMessage();
// loop over all messages in the queue
+ MSG message;
while (PeekMessage(&message, nullptr, 0, 0, PM_REMOVE))
{
// prevent debugger windows from getting messages during reset
- int dispatch = TRUE && !nodispatch;
+ bool dispatch = !nodispatch;
- if (message.hwnd == nullptr || is_mame_window(message.hwnd))
+ if (!message.hwnd || is_mame_window(message.hwnd))
{
- dispatch = TRUE;
+ dispatch = true;
switch (message.message)
{
// ignore keyboard messages
case WM_SYSKEYUP:
case WM_SYSKEYDOWN:
- dispatch = FALSE;
+ dispatch = false;
break;
// forward mouse button downs to the input system
case WM_LBUTTONDOWN:
- dispatch = !handle_mouse_button(WINOSD(machine), 0, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
+ dispatch = !handle_mouse_button(*this, 0, TRUE, message.lParam);
break;
case WM_RBUTTONDOWN:
- dispatch = !handle_mouse_button(WINOSD(machine), 1, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
+ dispatch = !handle_mouse_button(*this, 1, TRUE, message.lParam);
break;
case WM_MBUTTONDOWN:
- dispatch = !handle_mouse_button(WINOSD(machine), 2, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
+ dispatch = !handle_mouse_button(*this, 2, TRUE, message.lParam);
break;
case WM_XBUTTONDOWN:
- dispatch = !handle_mouse_button(WINOSD(machine), 3, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
+ dispatch = !handle_mouse_button(*this, (GET_XBUTTON_WPARAM(message.wParam) == XBUTTON1) ? 3 : 4, TRUE, message.lParam);
break;
// forward mouse button ups to the input system
case WM_LBUTTONUP:
- dispatch = !handle_mouse_button(WINOSD(machine), 0, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
+ dispatch = !handle_mouse_button(*this, 0, FALSE, message.lParam);
break;
case WM_RBUTTONUP:
- dispatch = !handle_mouse_button(WINOSD(machine), 1, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
+ dispatch = !handle_mouse_button(*this, 1, FALSE, message.lParam);
break;
case WM_MBUTTONUP:
- dispatch = !handle_mouse_button(WINOSD(machine), 2, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
+ dispatch = !handle_mouse_button(*this, 2, FALSE, message.lParam);
break;
case WM_XBUTTONUP:
- dispatch = !handle_mouse_button(WINOSD(machine), 3, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
+ dispatch = !handle_mouse_button(*this, (GET_XBUTTON_WPARAM(message.wParam) == XBUTTON1) ? 3 : 4, FALSE, message.lParam);
+ break;
+
+ // forward mouse wheel movement to the input system
+ case WM_MOUSEWHEEL:
+ dispatch = !handle_mouse_wheel(*this, GET_WHEEL_DELTA_WPARAM(message.wParam), 0, message.lParam);
break;
+ case WM_MOUSEHWHEEL:
+ dispatch = !handle_mouse_wheel(*this, 0, GET_WHEEL_DELTA_WPARAM(message.wParam), message.lParam);
+ break;
+
+ // forward keystrokes to the input system
case WM_KEYDOWN:
if (NOT_ALREADY_DOWN(message.lParam))
- dispatch = !handle_keypress(WINOSD(machine), message.wParam, TRUE, SCAN_CODE(message.lParam), IS_EXTENDED(message.lParam));
+ dispatch = !handle_keypress(*this, message.wParam, TRUE, message.lParam);
break;
case WM_KEYUP:
- dispatch = !handle_keypress(WINOSD(machine), message.wParam, FALSE, SCAN_CODE(message.lParam), IS_EXTENDED(message.lParam));
+ dispatch = !handle_keypress(*this, message.wParam, FALSE, message.lParam);
break;
}
}
// dispatch if necessary
if (dispatch)
- winwindow_dispatch_message(machine, &message);
+ winwindow_dispatch_message(machine(), message);
}
- } while (ui_temp_pause > 0);
+ }
+ while (ui_temp_pause > 0);
// update the cursor state after processing events
- winwindow_update_cursor_state(machine);
+ winwindow_update_cursor_state(machine());
}
@@ -550,12 +485,12 @@ void winwindow_process_events(running_machine &machine, bool ingame, bool nodisp
// (main thread)
//============================================================
-void winwindow_dispatch_message(running_machine &machine, MSG *message)
+void winwindow_dispatch_message(running_machine &machine, MSG const &message)
{
assert(GetCurrentThreadId() == main_threadid);
// dispatch our special communication messages
- switch (message->message)
+ switch (message.message)
{
// special case for quit
case WM_QUIT:
@@ -564,8 +499,8 @@ void winwindow_dispatch_message(running_machine &machine, MSG *message)
// everything else dispatches normally
default:
- TranslateMessage(message);
- DispatchMessage(message);
+ TranslateMessage(&message);
+ DispatchMessage(&message);
break;
}
}
@@ -577,15 +512,13 @@ void winwindow_dispatch_message(running_machine &machine, MSG *message)
// (main thread)
//============================================================
-void winwindow_take_snap(void)
+void winwindow_take_snap()
{
assert(GetCurrentThreadId() == main_threadid);
// iterate over windows and request a snap
- for (auto window : osd_common_t::s_window_list)
- {
+ for (const auto &window : osd_common_t::window_list())
window->renderer().save();
- }
}
@@ -595,15 +528,13 @@ void winwindow_take_snap(void)
// (main thread)
//============================================================
-void winwindow_toggle_fsfx(void)
+void winwindow_toggle_fsfx()
{
assert(GetCurrentThreadId() == main_threadid);
// iterate over windows and request a snap
- for (auto window : osd_common_t::s_window_list)
- {
+ for (const auto &window : osd_common_t::window_list())
window->renderer().toggle_fsfx();
- }
}
@@ -613,15 +544,13 @@ void winwindow_toggle_fsfx(void)
// (main thread)
//============================================================
-void winwindow_take_video(void)
+void winwindow_take_video()
{
assert(GetCurrentThreadId() == main_threadid);
// iterate over windows and request a snap
- for (auto window : osd_common_t::s_window_list)
- {
+ for (const auto &window : osd_common_t::window_list())
window->renderer().record();
- }
}
@@ -631,24 +560,36 @@ void winwindow_take_video(void)
// (main thread)
//============================================================
-void winwindow_toggle_full_screen(void)
+void winwindow_toggle_full_screen()
{
assert(GetCurrentThreadId() == main_threadid);
// if we are in debug mode, never go full screen
- for (auto window : osd_common_t::s_window_list)
+ for (const auto &window : osd_common_t::window_list())
+ {
if (window->machine().debug_flags & DEBUG_FLAG_OSD_ENABLED)
return;
+ }
// toggle the window mode
video_config.windowed = !video_config.windowed;
+ // destroy the renderers first so that the render module can bounce if it depends on having a window handle
+ for (auto it = osd_common_t::window_list().rbegin(); osd_common_t::window_list().rend() != it; ++it)
+ (*it)->renderer_reset();
+
// iterate over windows and toggle their fullscreen state
- for (auto window : osd_common_t::s_window_list)
- SendMessage(std::static_pointer_cast<win_window_info>(window)->platform_window(), WM_USER_SET_FULLSCREEN, !video_config.windowed, 0);
+ for (const auto &window : osd_common_t::window_list())
+ {
+ SendMessage(
+ dynamic_cast<win_window_info &>(*window).platform_window(),
+ WM_USER_SET_FULLSCREEN,
+ !video_config.windowed,
+ 0);
+ }
// Set the first window as foreground
- SetForegroundWindow(std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window());
+ SetForegroundWindow(dynamic_cast<win_window_info &>(*osd_common_t::window_list().front()).platform_window());
}
@@ -658,12 +599,12 @@ void winwindow_toggle_full_screen(void)
// (main or window thread)
//============================================================
-bool winwindow_has_focus(void)
+bool winwindow_has_focus()
{
// see if one of the video windows has focus
- for (auto window : osd_common_t::s_window_list)
+ for (const auto &window : osd_common_t::window_list())
{
- switch (std::static_pointer_cast<win_window_info>(window)->focus())
+ switch (dynamic_cast<win_window_info &>(*window).focus())
{
case win_window_focus::NONE:
break;
@@ -704,34 +645,34 @@ void winwindow_update_cursor_state(running_machine &machine)
assert(GetCurrentThreadId() == main_threadid);
// If no windows, just return
- if (osd_common_t::s_window_list.empty())
+ if (osd_common_t::window_list().empty())
return;
- auto window = osd_common_t::s_window_list.front();
+ auto &window = static_cast<win_window_info &>(*osd_common_t::window_list().front());
// if we should hide the mouse cursor, then do it
// rules are:
// 1. we must have focus before hiding the cursor
- // 2. we also hide the cursor in full screen mode and when tshe window doesn't have a menu
+ // 2. we also hide the cursor in full screen mode and when the window doesn't have a menu
// 3. we also hide the cursor in windowed mode if we're not paused and
// the input system requests it
if (winwindow_has_focus() && (
- (window->fullscreen() && !window->win_has_menu())
+ (window.fullscreen() && !GetMenu(window.platform_window()))
|| (!machine.paused() && WINOSD(machine)->should_hide_mouse())))
{
// hide cursor
- window->hide_pointer();
+ window.hide_pointer();
// clip pointer to game video window
- window->capture_pointer();
+ window.capture_pointer();
}
else
{
// show cursor
- window->show_pointer();
+ window.show_pointer();
// allow cursor to move freely
- window->release_pointer();
+ window.release_pointer();
}
}
@@ -742,21 +683,26 @@ void winwindow_update_cursor_state(running_machine &machine)
// (main thread)
//============================================================
-void win_window_info::create(running_machine &machine, int index, std::shared_ptr<osd_monitor_info> monitor, const osd_window_config *config)
+std::unique_ptr<win_window_info> win_window_info::create(
+ running_machine &machine,
+ render_module &renderprovider,
+ int index,
+ const std::shared_ptr<osd_monitor_info> &monitor,
+ const osd_window_config *config)
{
assert(GetCurrentThreadId() == main_threadid);
// allocate a new window object
- auto window = std::make_shared<win_window_info>(machine, index, monitor, config);
+ auto window = std::make_unique<win_window_info>(machine, renderprovider, index, monitor, config);
// set main window
- if (window->m_index > 0)
+ if (window->index() > 0)
{
- for (auto w : osd_common_t::s_window_list)
+ for (const auto &w : osd_common_t::window_list())
{
- if (w->m_index == 0)
+ if (w->index() == 0)
{
- window->set_main_window(std::static_pointer_cast<osd_window>(w));
+ window->set_main_window(dynamic_cast<win_window_info &>(*w));
break;
}
}
@@ -764,69 +710,33 @@ void win_window_info::create(running_machine &machine, int index, std::shared_pt
else
{
// We must be the main window
- window->set_main_window(window);
+ window->set_main_window(*window);
}
// see if we are safe for fullscreen
window->m_fullscreen_safe = TRUE;
- for (auto win : osd_common_t::s_window_list)
+ for (const auto &win : osd_common_t::window_list())
if (win->monitor() == monitor.get())
window->m_fullscreen_safe = FALSE;
- // add us to the list
- osd_common_t::s_window_list.push_back(window);
-
- // load the layout
- window->m_target = machine.render().target_alloc();
-
- // set the specific view
- windows_options &options = downcast<windows_options &>(machine.options());
-
- const char *defview = options.view();
- window->set_starting_view(index, defview, options.view(index));
+ window->create_target();
// remember the current values in case they change
- window->m_targetview = window->m_target->view();
- window->m_targetorient = window->m_target->orientation();
- window->m_targetlayerconfig = window->m_target->layer_config();
-
- // make the window title
- if (video_config.numscreens == 1)
- sprintf(window->m_title, "%s: %s [%s]", emulator_info::get_appname(), machine.system().type.fullname(), machine.system().name);
- else
- sprintf(window->m_title, "%s: %s [%s] - Screen %d", emulator_info::get_appname(), machine.system().type.fullname(), machine.system().name, index);
+ window->m_targetview = window->target()->view();
+ window->m_targetorient = window->target()->orientation();
+ window->m_targetlayerconfig = window->target()->layer_config();
+ window->m_targetvismask = window->target()->visibility_mask();
// set the initial maximized state
- window->m_startmaximized = options.maximize();
+ window->m_startmaximized = downcast<windows_options &>(machine.options()).maximize();
window->m_init_state = window->complete_create() ? -1 : 1;
// handle error conditions
if (window->m_init_state == -1)
fatalerror("Unable to complete window creation\n");
-}
-
-std::shared_ptr<osd_monitor_info> win_window_info::monitor_from_rect(const osd_rect* proposed) const
-{
- std::shared_ptr<osd_monitor_info> monitor;
- // in window mode, find the nearest
- if (!fullscreen())
- {
- if (proposed != nullptr)
- {
- monitor = m_monitor->module().monitor_from_rect(*proposed);
- }
- else
- monitor = m_monitor->module().monitor_from_window(*this);
- }
- else
- {
- // in full screen, just use the configured monitor
- monitor = m_monitor;
- }
-
- return monitor;
+ return window;
}
//============================================================
@@ -834,19 +744,13 @@ std::shared_ptr<osd_monitor_info> win_window_info::monitor_from_rect(const osd_r
// (main thread)
//============================================================
-void win_window_info::destroy()
+void win_window_info::complete_destroy()
{
assert(GetCurrentThreadId() == main_threadid);
- // remove us from the list
- osd_common_t::s_window_list.remove(shared_from_this());
-
// destroy the window
if (platform_window() != nullptr)
DestroyWindow(platform_window());
-
- // free the render target
- machine().render().target_free(m_target);
}
@@ -858,20 +762,24 @@ void win_window_info::destroy()
void win_window_info::update()
{
- int targetview, targetorient;
- render_layer_config targetlayerconfig;
-
assert(GetCurrentThreadId() == main_threadid);
// see if the target has changed significantly in window mode
- targetview = m_target->view();
- targetorient = m_target->orientation();
- targetlayerconfig = m_target->layer_config();
- if (targetview != m_targetview || targetorient != m_targetorient || targetlayerconfig != m_targetlayerconfig)
+ unsigned const targetview = target()->view();
+ int const targetorient = target()->orientation();
+ render_layer_config const targetlayerconfig = target()->layer_config();
+ u32 const targetvismask = target()->visibility_mask();
+ int const targetscalemode = target()->scale_mode();
+ bool const targetkeepaspect = target()->keepaspect();
+ if (targetview != m_targetview || targetorient != m_targetorient || targetlayerconfig != m_targetlayerconfig || targetvismask != m_targetvismask ||
+ targetscalemode != m_targetscalemode || targetkeepaspect != m_targetkeepaspect)
{
m_targetview = targetview;
m_targetorient = targetorient;
m_targetlayerconfig = targetlayerconfig;
+ m_targetvismask = targetvismask;
+ m_targetscalemode = targetscalemode;
+ m_targetkeepaspect = targetkeepaspect;
// in window mode, reminimize/maximize
if (!fullscreen())
@@ -884,7 +792,7 @@ void win_window_info::update()
}
// if we're visible and running and not in the middle of a resize, draw
- if (platform_window() != nullptr && m_target != nullptr && has_renderer())
+ if (platform_window() != nullptr && target() != nullptr && has_renderer())
{
bool got_lock = true;
@@ -930,7 +838,7 @@ void win_window_info::update()
// (main thread)
//============================================================
-static void create_window_class(void)
+static void create_window_class()
{
static int classes_created = FALSE;
@@ -959,29 +867,6 @@ static void create_window_class(void)
//============================================================
-// set_starting_view
-// (main thread)
-//============================================================
-
-void win_window_info::set_starting_view(int index, const char *defview, const char *view)
-{
- int viewindex;
-
- assert(GetCurrentThreadId() == main_threadid);
-
- // choose non-auto over auto
- if (strcmp(view, "auto") == 0 && strcmp(defview, "auto") != 0)
- view = defview;
-
- // query the video system to help us pick a view
- viewindex = target()->configured_view(view, index, video_config.numscreens);
-
- // set the view
- target()->set_view(viewindex);
-}
-
-
-//============================================================
// winwindow_ui_pause
// (main thread)
//============================================================
@@ -992,9 +877,10 @@ void winwindow_ui_pause(running_machine &machine, int pause)
assert(GetCurrentThreadId() == main_threadid);
- // if we're pausing, increment the pause counter
if (pause)
{
+ // if we're pausing, increment the pause counter
+
// if we're the first to pause, we have to actually initiate it
if (ui_temp_pause++ == 0)
{
@@ -1006,10 +892,10 @@ void winwindow_ui_pause(running_machine &machine, int pause)
SetEvent(ui_pause_event);
}
}
-
- // if we're resuming, decrement the pause counter
else
{
+ // if we're resuming, decrement the pause counter
+
// if we're the last to resume, unpause MAME
if (--ui_temp_pause == 0)
{
@@ -1048,7 +934,7 @@ int win_window_info::wnd_extra_width()
RECT temprect = { 100, 100, 200, 200 };
if (fullscreen())
return 0;
- AdjustWindowRectEx(&temprect, WINDOW_STYLE, win_has_menu(), WINDOW_STYLE_EX);
+ AdjustWindowRectEx(&temprect, WINDOW_STYLE, GetMenu(platform_window()) ? true : false, WINDOW_STYLE_EX);
return rect_width(&temprect) - 100;
}
@@ -1064,7 +950,7 @@ int win_window_info::wnd_extra_height()
RECT temprect = { 100, 100, 200, 200 };
if (fullscreen())
return 0;
- AdjustWindowRectEx(&temprect, WINDOW_STYLE, win_has_menu(), WINDOW_STYLE_EX);
+ AdjustWindowRectEx(&temprect, WINDOW_STYLE, GetMenu(platform_window()) ? true : false, WINDOW_STYLE_EX);
return rect_height(&temprect) - 100;
}
@@ -1078,20 +964,12 @@ int win_window_info::complete_create()
{
RECT client;
int tempwidth, tempheight;
- HMENU menu = nullptr;
HDC dc;
assert(GetCurrentThreadId() == window_threadid);
// get the monitor bounds
- osd_rect monitorbounds = m_monitor->position_size();
-
- // create the window menu if needed
- if (downcast<windows_options &>(machine().options()).menu())
- {
- if (win_create_menu(machine(), &menu))
- return 1;
- }
+ osd_rect monitorbounds = monitor()->position_size();
// are we in worker UI mode?
HWND hwnd;
@@ -1108,16 +986,16 @@ int win_window_info::complete_create()
{
// create the window, but don't show it yet
hwnd = win_create_window_ex_utf8(
- fullscreen() ? FULLSCREEN_STYLE_EX : WINDOW_STYLE_EX,
- "MAME",
- m_title,
- fullscreen() ? FULLSCREEN_STYLE : WINDOW_STYLE,
- monitorbounds.left() + 20, monitorbounds.top() + 20,
- monitorbounds.left() + 100, monitorbounds.top() + 100,
- nullptr,//(osd_common_t::s_window_list != nullptr) ? osd_common_t::s_window_list->m_hwnd : nullptr,
- menu,
- GetModuleHandleUni(),
- nullptr);
+ fullscreen() ? FULLSCREEN_STYLE_EX : WINDOW_STYLE_EX,
+ "MAME",
+ title().c_str(),
+ fullscreen() ? FULLSCREEN_STYLE : WINDOW_STYLE,
+ monitorbounds.left() + 20, monitorbounds.top() + 20,
+ monitorbounds.left() + 100, monitorbounds.top() + 100,
+ nullptr,//(osd_common_t::s_window_list != nullptr) ? osd_common_t::s_window_list->m_hwnd : nullptr,
+ nullptr,
+ GetModuleHandleUni(),
+ nullptr);
}
if (hwnd == nullptr)
@@ -1130,10 +1008,11 @@ int win_window_info::complete_create()
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
// skip the positioning stuff for '-video none' or '-attach_window'
- if (video_config.mode == VIDEO_MODE_NONE || attached_mode())
+ if (!renderer_interactive() || attached_mode())
{
- set_renderer(osd_renderer::make_for_type(video_config.mode, shared_from_this()));
- renderer().create();
+ renderer_create();
+ if (renderer().create())
+ return 1;
return 0;
}
@@ -1155,7 +1034,7 @@ int win_window_info::complete_create()
// show the window
if (!fullscreen() || m_fullscreen_safe)
{
- set_renderer(osd_renderer::make_for_type(video_config.mode, shared_from_this()));
+ renderer_create();
if (renderer().create())
return 1;
@@ -1180,10 +1059,10 @@ int win_window_info::complete_create()
LRESULT CALLBACK win_window_info::video_window_proc(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam)
{
LONG_PTR ptr = GetWindowLongPtr(wnd, GWLP_USERDATA);
- win_window_info *window = (win_window_info *)ptr;
+ auto *window = (win_window_info *)ptr;
// we may get called before SetWindowLongPtr is called
- if (window != nullptr)
+ if (window)
{
assert(GetCurrentThreadId() == window_threadid);
window->update_minmax_state();
@@ -1192,118 +1071,178 @@ LRESULT CALLBACK win_window_info::video_window_proc(HWND wnd, UINT message, WPAR
// handle a few messages
switch (message)
{
- // paint: redraw the last bitmap
- case WM_PAINT:
+ // paint: redraw the last bitmap
+ case WM_PAINT:
{
PAINTSTRUCT pstruct;
HDC hdc = BeginPaint(wnd, &pstruct);
window->draw_video_contents(hdc, true);
- if (window->win_has_menu())
+ if (GetMenu(window->platform_window()))
DrawMenuBar(window->platform_window());
EndPaint(wnd, &pstruct);
- break;
}
+ break;
- // non-client paint: punt if full screen
- case WM_NCPAINT:
- if (!window->fullscreen() || window->win_has_menu())
- return DefWindowProc(wnd, message, wparam, lparam);
- break;
+ // non-client paint: punt if full screen
+ case WM_NCPAINT:
+ if (!window->fullscreen() || GetMenu(window->platform_window()))
+ return DefWindowProc(wnd, message, wparam, lparam);
+ break;
- // input: handle the raw input
- case WM_INPUT:
- downcast<windows_osd_interface&>(window->machine().osd()).handle_input_event(INPUT_EVENT_RAWINPUT, &lparam);
+ // input device change: handle RawInput device connection/disconnection
+ case WM_INPUT_DEVICE_CHANGE:
+ switch (wparam)
+ {
+ case GIDC_ARRIVAL:
+ downcast<windows_osd_interface&>(window->machine().osd()).handle_input_event(INPUT_EVENT_ARRIVAL, &lparam);
break;
-
- // syskeys - ignore
- case WM_SYSKEYUP:
- case WM_SYSKEYDOWN:
+ case GIDC_REMOVAL:
+ downcast<windows_osd_interface&>(window->machine().osd()).handle_input_event(INPUT_EVENT_REMOVAL, &lparam);
break;
+ default:
+ return DefWindowProc(wnd, message, wparam, lparam);
+ }
+ break;
- // input events
- case WM_MOUSEMOVE:
- window->machine().ui_input().push_mouse_move_event(window->m_target, GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam));
- break;
+ // input: handle the raw input
+ case WM_INPUT:
+ downcast<windows_osd_interface&>(window->machine().osd()).handle_input_event(INPUT_EVENT_RAWINPUT, &lparam);
+ break;
- case WM_MOUSELEAVE:
- window->machine().ui_input().push_mouse_leave_event(window->m_target);
- break;
+ // syskeys - ignore
+ case WM_SYSKEYUP:
+ case WM_SYSKEYDOWN:
+ break;
- case WM_LBUTTONDOWN:
+ // text input events
+ case WM_CHAR:
{
- auto ticks = std::chrono::system_clock::now();
- window->machine().ui_input().push_mouse_down_event(window->m_target, GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam));
-
- // check for a double-click
- if (ticks - window->m_lastclicktime < std::chrono::milliseconds(GetDoubleClickTime()) &&
- GET_X_LPARAM(lparam) >= window->m_lastclickx - 4 && GET_X_LPARAM(lparam) <= window->m_lastclickx + 4 &&
- GET_Y_LPARAM(lparam) >= window->m_lastclicky - 4 && GET_Y_LPARAM(lparam) <= window->m_lastclicky + 4)
+ char16_t const ch = char16_t(wparam);
+ if ((0xd800 <= ch) && (0xdbff >= ch))
{
- window->m_lastclicktime = std::chrono::system_clock::time_point::min();
- window->machine().ui_input().push_mouse_double_click_event(window->m_target, GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam));
+ window->m_last_surrogate = ch;
+ }
+ else if ((0xdc00 <= ch) && (0xdfff >= ch))
+ {
+ if (window->m_last_surrogate)
+ {
+ char32_t const uch = 0x10000 + ((ch & 0x03ff) | ((window->m_last_surrogate & 0x03ff) << 10));
+ window->machine().ui_input().push_char_event(window->target(), uch);
+ }
+ window->m_last_surrogate = 0;
}
else
{
- window->m_lastclicktime = ticks;
- window->m_lastclickx = GET_X_LPARAM(lparam);
- window->m_lastclicky = GET_Y_LPARAM(lparam);
+ window->machine().ui_input().push_char_event(window->target(), char32_t(ch));
+ window->m_last_surrogate = 0;
}
- break;
}
+ break;
- case WM_LBUTTONUP:
- window->machine().ui_input().push_mouse_up_event(window->m_target, GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam));
- break;
-
- case WM_RBUTTONDOWN:
- window->machine().ui_input().push_mouse_rdown_event(window->m_target, GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam));
- break;
-
- case WM_RBUTTONUP:
- window->machine().ui_input().push_mouse_rup_event(window->m_target, GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam));
- break;
-
- case WM_CHAR:
- window->machine().ui_input().push_char_event(window->m_target, (char32_t) wparam);
- break;
-
- case WM_MOUSEWHEEL:
+ case WM_UNICHAR:
+ if (UNICODE_NOCHAR == wparam)
+ return TRUE;
+ else
+ window->machine().ui_input().push_char_event(window->target(), char32_t(wparam));
+ break;
+
+ // legacy mouse events
+ case WM_MOUSEMOVE:
+ window->mouse_updated(wparam, lparam);
+ break;
+
+ case WM_MOUSELEAVE:
+ window->mouse_left(wparam, lparam);
+ break;
+
+ case WM_LBUTTONDOWN:
+ window->mouse_updated(wparam, lparam);
+ break;
+
+ case WM_LBUTTONUP:
+ window->mouse_updated(wparam, lparam);
+ break;
+
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONUP:
+ case WM_MBUTTONDOWN:
+ case WM_MBUTTONUP:
+ window->mouse_updated(wparam, lparam);
+ break;
+
+ case WM_XBUTTONDOWN:
+ case WM_XBUTTONUP:
+ window->mouse_updated(wparam, lparam);
+ return TRUE;
+
+ case WM_MOUSEWHEEL:
{
+ POINT where{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) };
+ ScreenToClient(wnd, &where);
UINT ucNumLines = 3; // default
SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &ucNumLines, 0);
- window->machine().ui_input().push_mouse_wheel_event(window->m_target, GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam), GET_WHEEL_DELTA_WPARAM(wparam), ucNumLines);
- break;
+ window->machine().ui_input().push_mouse_wheel_event(window->target(), where.x, where.y, GET_WHEEL_DELTA_WPARAM(wparam), ucNumLines);
}
-
- // pause the system when we start a menu or resize
- case WM_ENTERSIZEMOVE:
- window->m_resize_state = RESIZE_STATE_RESIZING;
- case WM_ENTERMENULOOP:
- winwindow_ui_pause(window->machine(), TRUE);
- break;
-
- // unpause the system when we stop a menu or resize and force a redraw
- case WM_EXITSIZEMOVE:
- window->m_resize_state = RESIZE_STATE_PENDING;
- case WM_EXITMENULOOP:
- winwindow_ui_pause(window->machine(), FALSE);
- InvalidateRect(wnd, nullptr, FALSE);
- break;
-
- // get min/max info: set the minimum window size
- case WM_GETMINMAXINFO:
+ break;
+
+ // new-style pointer handling (mouse/pen/touch)
+ case WM_POINTERENTER:
+ window->pointer_entered(wparam, lparam);
+ break;
+ case WM_POINTERLEAVE:
+ window->pointer_left(wparam, lparam);
+ break;
+ case WM_POINTERDOWN:
+ case WM_POINTERUP:
+ case WM_POINTERUPDATE:
+ window->pointer_updated(wparam, lparam);
+ break;
+ case WM_POINTERCAPTURECHANGED:
+ window->pointer_capture_changed(wparam, lparam);
+ break;
+ // TODO: other pointer events?
+ //case WM_POINTERACTIVATE:
+ //case WM_POINTERDEVICECHANGE:
+ //case WM_POINTERDEVICEINRANGE:
+ //case WM_POINTERDEVICEOUTOFRANGE:
+ //case WM_POINTERROUTEDAWAY:
+ //case WM_POINTERROUTEDRELEASED:
+ //case WM_POINTERROUTEDTO:
+ //case WM_POINTERWHEEL:
+ //case WM_POINTERHWHEEL:
+
+ // pause the system when we start a menu or resize
+ case WM_ENTERSIZEMOVE:
+ window->m_resize_state = RESIZE_STATE_RESIZING;
+ [[fallthrough]];
+ case WM_ENTERMENULOOP:
+ winwindow_ui_pause(window->machine(), TRUE);
+ break;
+
+ // unpause the system when we stop a menu or resize and force a redraw
+ case WM_EXITSIZEMOVE:
+ window->m_resize_state = RESIZE_STATE_PENDING;
+ [[fallthrough]];
+ case WM_EXITMENULOOP:
+ winwindow_ui_pause(window->machine(), FALSE);
+ InvalidateRect(wnd, nullptr, FALSE);
+ break;
+
+ // get min/max info: set the minimum window size
+ case WM_GETMINMAXINFO:
{
- MINMAXINFO *minmax = (MINMAXINFO *)lparam;
- minmax->ptMinTrackSize.x = MIN_WINDOW_DIM;
- minmax->ptMinTrackSize.y = MIN_WINDOW_DIM;
+ auto *minmax = (MINMAXINFO *)lparam;
+ minmax->ptMinTrackSize.x = MIN_WINDOW_DIMX;
+ minmax->ptMinTrackSize.y = MIN_WINDOW_DIMY;
break;
}
+ break;
- // sizing: constrain to the aspect ratio unless control key is held down
- case WM_SIZING:
+ // sizing: constrain to the aspect ratio unless control key is held down
+ case WM_SIZING:
{
RECT *rect = (RECT *)lparam;
- if (video_config.keepaspect && !(GetAsyncKeyState(VK_CONTROL) & 0x8000))
+ if (window->keepaspect() && (window->target()->scale_mode() == SCALE_FRACTIONAL) && !(GetAsyncKeyState(VK_CONTROL) & 0x8000))
{
osd_rect r = window->constrain_to_aspect_ratio(RECT_to_osd_rect(*rect), wparam);
rect->top = r.top();
@@ -1312,11 +1251,11 @@ LRESULT CALLBACK win_window_info::video_window_proc(HWND wnd, UINT message, WPAR
rect->right = r.right();
}
InvalidateRect(wnd, nullptr, FALSE);
- break;
}
+ break;
- // syscommands: catch win_start_maximized
- case WM_SYSCOMMAND:
+ // syscommands: catch win_start_maximized
+ case WM_SYSCOMMAND:
{
uint16_t cmd = wparam & 0xfff0;
@@ -1337,22 +1276,46 @@ LRESULT CALLBACK win_window_info::video_window_proc(HWND wnd, UINT message, WPAR
window->maximize_window();
break;
}
- return DefWindowProc(wnd, message, wparam, lparam);
}
+ return DefWindowProc(wnd, message, wparam, lparam);
- // close: cause MAME to exit
- case WM_CLOSE:
- window->machine().schedule_exit();
- break;
+ case WM_ACTIVATE:
+ if (window->has_renderer())
+ {
+ if (window->fullscreen())
+ {
+ if ((wparam == WA_ACTIVE) || (wparam == WA_CLICKACTIVE))
+ {
+ for (const auto &w : osd_common_t::window_list())
+ ShowWindow(dynamic_cast<win_window_info &>(*w).platform_window(), SW_RESTORE);
+ }
+ else if ((wparam == WA_INACTIVE) && !is_mame_window(HWND(lparam)))
+ {
+ for (const auto &w : osd_common_t::window_list())
+ ShowWindow(dynamic_cast<win_window_info &>(*w).platform_window(), SW_MINIMIZE);
+ }
+ }
- // destroy: clean up all attached rendering bits and nullptr out our hwnd
- case WM_DESTROY:
- window->renderer_reset();
- window->set_platform_window(nullptr);
- return DefWindowProc(wnd, message, wparam, lparam);
+ if ((wparam == WA_ACTIVE) || (wparam == WA_CLICKACTIVE))
+ window->machine().ui_input().push_window_focus_event(window->target());
+ else if (wparam == WA_INACTIVE)
+ window->machine().ui_input().push_window_defocus_event(window->target());
+ }
+ return DefWindowProc(wnd, message, wparam, lparam);
+
+ // close: cause MAME to exit
+ case WM_CLOSE:
+ window->machine().schedule_exit();
+ break;
- // self redraw: draw ourself in a non-painty way
- case WM_USER_REDRAW:
+ // destroy: clean up all attached rendering bits and nullptr out our hwnd
+ case WM_DESTROY:
+ window->renderer_reset();
+ window->set_platform_window(nullptr);
+ return DefWindowProc(wnd, message, wparam, lparam);
+
+ // self redraw: draw ourself in a non-painty way
+ case WM_USER_REDRAW:
{
HDC hdc = GetDC(wnd);
@@ -1360,46 +1323,46 @@ LRESULT CALLBACK win_window_info::video_window_proc(HWND wnd, UINT message, WPAR
window->draw_video_contents(hdc, false);
ReleaseDC(wnd, hdc);
- break;
}
-
- // fullscreen set
- case WM_USER_SET_FULLSCREEN:
- window->set_fullscreen(wparam);
- break;
-
- // minimum size set
- case WM_USER_SET_MINSIZE:
- window->minimize_window();
- break;
-
- // maximum size set
- case WM_USER_SET_MAXSIZE:
- window->maximize_window();
- break;
-
- // maximum size set
- case WM_DISPLAYCHANGE:
- /* FIXME: The current codebase has an issue with setting aspect
- * ratios correctly after display change. set_aspect should
- * be set_forced_aspect and on a refresh this forced aspect should
- * be preserved if set. If not, the standard aspect calculation
- * should be used.
- */
- window->m_monitor->refresh();
- window->m_monitor->update_resolution(LOWORD(lparam), HIWORD(lparam));
- break;
-
- // set focus: if we're not the primary window, switch back
- // commented out ATM because this prevents us from resizing secondary windows
-// case WM_SETFOCUS:
-// if (window != osd_common_t::s_window_list && osd_common_t::s_window_list != nullptr)
-// SetFocus(osd_common_t::s_window_list->m_hwnd);
-// break;
-
- // everything else: defaults
- default:
- return DefWindowProc(wnd, message, wparam, lparam);
+ break;
+
+ // fullscreen set
+ case WM_USER_SET_FULLSCREEN:
+ window->set_fullscreen(wparam);
+ break;
+
+ // minimum size set
+ case WM_USER_SET_MINSIZE:
+ window->minimize_window();
+ break;
+
+ // maximum size set
+ case WM_USER_SET_MAXSIZE:
+ window->maximize_window();
+ break;
+
+ // maximum size set
+ case WM_DISPLAYCHANGE:
+ /* FIXME: The current codebase has an issue with setting aspect
+ * ratios correctly after display change. set_aspect should
+ * be set_forced_aspect and on a refresh this forced aspect should
+ * be preserved if set. If not, the standard aspect calculation
+ * should be used.
+ */
+ window->monitor()->refresh();
+ window->monitor()->update_resolution(LOWORD(lparam), HIWORD(lparam));
+ break;
+
+ // set focus: if we're not the primary window, switch back
+ // commented out ATM because this prevents us from resizing secondary windows
+// case WM_SETFOCUS:
+// if (window != osd_common_t::s_window_list && osd_common_t::s_window_list != nullptr)
+// SetFocus(osd_common_t::s_window_list->m_hwnd);
+// break;
+
+ // everything else: defaults
+ default:
+ return DefWindowProc(wnd, message, wparam, lparam);
}
return 0;
@@ -1434,7 +1397,10 @@ void win_window_info::draw_video_contents(HDC dc, bool update)
{
// update DC
m_dc = dc;
- renderer().draw(update);
+ if (has_renderer())
+ {
+ renderer().draw(update);
+ }
}
}
}
@@ -1465,10 +1431,6 @@ osd_rect win_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int ad
if (monitor == nullptr)
return rect;
- // do not constrain aspect ratio for integer scaled views
- if (m_target->scale_mode() != SCALE_FRACTIONAL)
- return rect;
-
// get the pixel aspect ratio for the target monitor
pixel_aspect = monitor->pixel_aspect();
@@ -1482,29 +1444,21 @@ osd_rect win_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int ad
{
case WMSZ_BOTTOM:
case WMSZ_TOP:
- m_target->compute_visible_area(10000, propheight, pixel_aspect, m_target->orientation(), propwidth, propheight);
+ target()->compute_visible_area(10000, propheight, pixel_aspect, target()->orientation(), propwidth, propheight);
break;
case WMSZ_LEFT:
case WMSZ_RIGHT:
- m_target->compute_visible_area(propwidth, 10000, pixel_aspect, m_target->orientation(), propwidth, propheight);
+ target()->compute_visible_area(propwidth, 10000, pixel_aspect, target()->orientation(), propwidth, propheight);
break;
default:
- m_target->compute_visible_area(propwidth, propheight, pixel_aspect, m_target->orientation(), propwidth, propheight);
+ target()->compute_visible_area(propwidth, propheight, pixel_aspect, target()->orientation(), propwidth, propheight);
break;
}
// get the minimum width/height for the current layout
- m_target->compute_minimum_size(minwidth, minheight);
-
- // clamp against the absolute minimum
- propwidth = std::max(propwidth, MIN_WINDOW_DIM);
- propheight = std::max(propheight, MIN_WINDOW_DIM);
-
- // clamp against the minimum width and height
- propwidth = std::max(propwidth, minwidth);
- propheight = std::max(propheight, minheight);
+ target()->compute_minimum_size(minwidth, minheight);
// clamp against the maximum (fit on one screen for full screen mode)
if (fullscreen())
@@ -1517,19 +1471,35 @@ osd_rect win_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int ad
maxwidth = monitor->usuable_position_size().width() - extrawidth;
maxheight = monitor->usuable_position_size().height() - extraheight;
- // further clamp to the maximum width/height in the window
+ // clamp minimum against half of maximum to allow resizing very large targets (eg. SVG screen)
+ minwidth = std::min(minwidth, maxwidth / 2);
+ minheight = std::min(minheight, maxheight / 2);
+
+ // clamp maximum to the maximum width/height in the window
if (m_win_config.width != 0)
maxwidth = std::min(maxwidth, m_win_config.width + extrawidth);
if (m_win_config.height != 0)
maxheight = std::min(maxheight, m_win_config.height + extraheight);
}
+ // clamp against the absolute minimum
+ propwidth = std::max(propwidth, MIN_WINDOW_DIMX);
+ propheight = std::max(propheight, MIN_WINDOW_DIMY);
+
+ // clamp against the minimum width and height
+ propwidth = std::max(propwidth, minwidth);
+ propheight = std::max(propheight, minheight);
+
// clamp to the maximum
propwidth = std::min(propwidth, maxwidth);
propheight = std::min(propheight, maxheight);
// compute the visible area based on the proposed rectangle
- m_target->compute_visible_area(propwidth, propheight, pixel_aspect, m_target->orientation(), viswidth, visheight);
+ target()->compute_visible_area(propwidth, propheight, pixel_aspect, target()->orientation(), viswidth, visheight);
+
+ // clamp visable area to the proposed rectangle
+ viswidth = std::min(viswidth, propwidth);
+ visheight = std::min(visheight, propheight);
// compute the adjustments we need to make
adjwidth = (viswidth + extrawidth) - rect.width();
@@ -1577,20 +1547,26 @@ osd_dim win_window_info::get_min_bounds(int constrain)
//assert(GetCurrentThreadId() == window_threadid);
// get the minimum target size
- m_target->compute_minimum_size(minwidth, minheight);
+ target()->compute_minimum_size(minwidth, minheight);
+
+ // check if visible area is bigger
+ int32_t viswidth, visheight;
+ target()->compute_visible_area(minwidth, minheight, monitor()->aspect(), target()->orientation(), viswidth, visheight);
+ minwidth = std::max(viswidth, minwidth);
+ minheight = std::max(visheight, minheight);
// expand to our minimum dimensions
- if (minwidth < MIN_WINDOW_DIM)
- minwidth = MIN_WINDOW_DIM;
- if (minheight < MIN_WINDOW_DIM)
- minheight = MIN_WINDOW_DIM;
+ if (minwidth < MIN_WINDOW_DIMX)
+ minwidth = MIN_WINDOW_DIMX;
+ if (minheight < MIN_WINDOW_DIMY)
+ minheight = MIN_WINDOW_DIMY;
// account for extra window stuff
minwidth += wnd_extra_width();
minheight += wnd_extra_height();
// if we want it constrained, figure out which one is larger
- if (constrain && m_target->scale_mode() == SCALE_FRACTIONAL)
+ if (constrain)
{
// first constrain with no height limit
osd_rect test1(0,0,minwidth,10000);
@@ -1628,8 +1604,8 @@ osd_dim win_window_info::get_max_bounds(int constrain)
//assert(GetCurrentThreadId() == window_threadid);
// compute the maximum client area
- //m_monitor->refresh();
- osd_rect maximum = m_monitor->usuable_position_size();
+ //monitor()->refresh();
+ osd_rect maximum = monitor()->usuable_position_size();
// clamp to the window's max
int tempw = maximum.width();
@@ -1650,7 +1626,7 @@ osd_dim win_window_info::get_max_bounds(int constrain)
maximum = maximum.resize(tempw, temph);
// constrain to fit
- if (constrain && m_target->scale_mode() == SCALE_FRACTIONAL)
+ if (constrain)
maximum = constrain_to_aspect_ratio(maximum, WMSZ_BOTTOMRIGHT);
return maximum.dim();
@@ -1672,8 +1648,9 @@ void win_window_info::update_minmax_state()
RECT bounds;
// compare the maximum bounds versus the current bounds
- osd_dim minbounds = get_min_bounds(video_config.keepaspect);
- osd_dim maxbounds = get_max_bounds(video_config.keepaspect);
+ const bool keep_aspect = keepaspect();
+ osd_dim minbounds = get_min_bounds(keep_aspect);
+ osd_dim maxbounds = get_max_bounds(keep_aspect);
GetWindowRect(platform_window(), &bounds);
// if either the width or height matches, we were maximized
@@ -1681,6 +1658,10 @@ void win_window_info::update_minmax_state()
(rect_height(&bounds) == minbounds.height());
m_ismaximized = (rect_width(&bounds) == maxbounds.width()) ||
(rect_height(&bounds) == maxbounds.height());
+
+ // We can't be maximized and minimized simultaneously
+ if (m_ismaximized)
+ m_isminimized = FALSE;
}
else
{
@@ -1700,7 +1681,7 @@ void win_window_info::minimize_window()
{
assert(GetCurrentThreadId() == window_threadid);
- osd_dim newsize = get_min_bounds(video_config.keepaspect);
+ osd_dim newsize = get_min_bounds(keepaspect());
// get the window rect
RECT bounds;
@@ -1723,10 +1704,10 @@ void win_window_info::maximize_window()
{
assert(GetCurrentThreadId() == window_threadid);
- osd_dim newsize = get_max_bounds(video_config.keepaspect);
+ osd_dim newsize = get_max_bounds(keepaspect());
// center within the work area
- osd_rect work = m_monitor->usuable_position_size();
+ osd_rect work = monitor()->usuable_position_size();
osd_rect newrect = osd_rect(work.left() + (work.width() - newsize.width()) / 2,
work.top() + (work.height() - newsize.height()) / 2,
newsize);
@@ -1755,8 +1736,28 @@ void win_window_info::adjust_window_position_after_major_change()
if (!fullscreen())
{
// constrain the existing size to the aspect ratio
- if (video_config.keepaspect)
+ if (keepaspect())
newrect = constrain_to_aspect_ratio(newrect, WMSZ_BOTTOMRIGHT);
+
+ // restrict the window to one monitor and avoid toolbars if possible
+ HMONITOR const nearest_monitor = MonitorFromWindow(platform_window(), MONITOR_DEFAULTTONEAREST);
+ if (NULL != nearest_monitor)
+ {
+ MONITORINFO info;
+ std::memset(&info, 0, sizeof(info));
+ info.cbSize = sizeof(info);
+ if (GetMonitorInfo(nearest_monitor, &info))
+ {
+ if (newrect.right() > info.rcWork.right)
+ newrect = newrect.move_by(info.rcWork.right - newrect.right(), 0);
+ if (newrect.bottom() > info.rcWork.bottom)
+ newrect = newrect.move_by(0, info.rcWork.bottom - newrect.bottom());
+ if (newrect.left() < info.rcWork.left)
+ newrect = newrect.move_by(info.rcWork.left - newrect.left(), 0);
+ if (newrect.top() < info.rcWork.top)
+ newrect = newrect.move_by(0, info.rcWork.top - newrect.top());
+ }
+ }
}
else
{
@@ -1765,26 +1766,6 @@ void win_window_info::adjust_window_position_after_major_change()
newrect = monitor->position_size();
}
- // restrict the window to one monitor and avoid toolbars if possible
- HMONITOR const nearest_monitor = MonitorFromWindow(platform_window(), MONITOR_DEFAULTTONEAREST);
- if (NULL != nearest_monitor)
- {
- MONITORINFO info;
- std::memset(&info, 0, sizeof(info));
- info.cbSize = sizeof(info);
- if (GetMonitorInfo(nearest_monitor, &info))
- {
- if (newrect.right() > info.rcWork.right)
- newrect = newrect.move_by(info.rcWork.right - newrect.right(), 0);
- if (newrect.bottom() > info.rcWork.bottom)
- newrect = newrect.move_by(0, info.rcWork.bottom - newrect.bottom());
- if (newrect.left() < info.rcWork.left)
- newrect = newrect.move_by(info.rcWork.left - newrect.left(), 0);
- if (newrect.top() < info.rcWork.top)
- newrect = newrect.move_by(0, info.rcWork.top - newrect.top());
- }
- }
-
// adjust the position if different
if (RECT_to_osd_rect(oldrect) != newrect)
SetWindowPos(platform_window(), fullscreen() ? HWND_TOPMOST : HWND_TOP,
@@ -1792,7 +1773,7 @@ void win_window_info::adjust_window_position_after_major_change()
newrect.width(), newrect.height(), 0);
// take note of physical window size (used for lightgun coordinate calculation)
- if (m_index == 0)
+ if (index() == 0)
osd_printf_verbose("Physical width %d, height %d\n", newrect.width(), newrect.height());
}
@@ -1811,18 +1792,16 @@ void win_window_info::set_fullscreen(int fullscreen)
return;
m_fullscreen = fullscreen;
- // reset UI to main menu
- machine().ui().menu_reset();
-
- // kill off the drawers
+ // kill off the renderer
renderer_reset();
// hide ourself
ShowWindow(platform_window(), SW_HIDE);
- // configure the window if non-fullscreen
if (!fullscreen)
{
+ // configure the window if non-fullscreen
+
// adjust the style
SetWindowLong(platform_window(), GWL_STYLE, WINDOW_STYLE);
SetWindowLong(platform_window(), GWL_EXSTYLE, WINDOW_STYLE_EX);
@@ -1843,14 +1822,14 @@ void win_window_info::set_fullscreen(int fullscreen)
// otherwise, set a small size and maximize from there
else
{
- SetWindowPos(platform_window(), HWND_TOP, 0, 0, MIN_WINDOW_DIM, MIN_WINDOW_DIM, SWP_NOZORDER);
+ SetWindowPos(platform_window(), HWND_TOP, 0, 0, MIN_WINDOW_DIMX, MIN_WINDOW_DIMY, SWP_NOZORDER);
maximize_window();
}
}
-
- // configure the window if fullscreen
else
{
+ // configure the window if fullscreen
+
// save the bounds
GetWindowRect(platform_window(), &m_non_fullscreen_bounds);
@@ -1869,12 +1848,12 @@ void win_window_info::set_fullscreen(int fullscreen)
// show ourself
if (!this->fullscreen() || m_fullscreen_safe)
{
- if (video_config.mode != VIDEO_MODE_NONE)
+ if (renderer_interactive())
ShowWindow(platform_window(), SW_SHOW);
- set_renderer(osd_renderer::make_for_type(video_config.mode, shared_from_this()));
+ renderer_create();
if (renderer().create())
- exit(1);
+ exit(1); // FIXME: better error handling than just silently exiting on failure
}
// ensure we're still adjusted correctly
@@ -1918,24 +1897,412 @@ win_window_focus win_window_info::focus() const
}
+void win_window_info::pointer_entered(WPARAM wparam, LPARAM lparam)
+{
+ assert(!IS_POINTER_CANCELED_WPARAM(wparam));
+ auto const info(map_pointer(wparam));
+ if (m_active_pointers.end() != info)
+ {
+ POINT where{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) };
+ ScreenToClient(platform_window(), &where);
+ info->x = where.x;
+ info->y = where.y;
+ machine().ui_input().push_pointer_update(
+ target(),
+ convert_pointer_type(info->type),
+ info->index,
+ info->device,
+ where.x, where.y,
+ 0U, 0U, 0U, 0U);
+ }
+}
+
+void win_window_info::pointer_left(WPARAM wparam, LPARAM lparam)
+{
+ auto const info(find_pointer(wparam));
+ if (m_active_pointers.end() != info)
+ {
+ bool const canceled(IS_POINTER_CANCELED_WPARAM(wparam));
+ POINT where{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) };
+ ScreenToClient(platform_window(), &where);
+ expire_pointer(info, where, canceled);
+ }
+}
+
+void win_window_info::pointer_updated(WPARAM wparam, LPARAM lparam)
+{
+ bool const canceled(IS_POINTER_CANCELED_WPARAM(wparam));
+ auto const info(canceled ? find_pointer(wparam) : map_pointer(wparam));
+ if (m_active_pointers.end() != info)
+ {
+ POINT where{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) };
+ ScreenToClient(platform_window(), &where);
+ unsigned const buttons(canceled ? 0 : get_pointer_buttons(wparam));
+ update_pointer(*info, where, buttons, canceled);
+ }
+}
+
+void win_window_info::pointer_capture_changed(WPARAM wparam, LPARAM lparam)
+{
+ auto const info(find_pointer(wparam));
+ if (m_active_pointers.end() != info)
+ {
+ // treat this as the pointer being stolen - fail any gestures
+ if (BIT(info->buttons, 0) && (0 < info->clickcnt))
+ info->clickcnt = -info->clickcnt;
+
+ // push to UI manager and dump pointer data
+ machine().ui_input().push_pointer_abort(
+ target(),
+ convert_pointer_type(info->type),
+ info->index,
+ info->device,
+ info->x, info->y,
+ info->buttons, info->clickcnt);
+ m_pointer_mask &= ~(decltype(m_pointer_mask)(1) << info->index);
+ if (info->index < m_next_pointer)
+ m_next_pointer = info->index;
+ m_active_pointers.erase(info);
+ }
+}
+
+void win_window_info::mouse_left(WPARAM wparam, LPARAM lparam)
+{
+ m_tracking_mouse = false;
+ auto const info(find_mouse_pointer());
+ if (m_active_pointers.end() != info)
+ {
+ POINT where{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) };
+ expire_pointer(info, where, false);
+ }
+}
+
+void win_window_info::mouse_updated(WPARAM wparam, LPARAM lparam)
+{
+ auto const info(map_mouse_pointer());
+ if (m_active_pointers.end() == info)
+ return;
+
+ POINT const where{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) };
+ unsigned const buttons(
+ ((MK_LBUTTON & wparam) ? 0x01 : 0x00) |
+ ((MK_RBUTTON & wparam) ? 0x02 : 0x00) |
+ ((MK_MBUTTON & wparam) ? 0x04 : 0x00) |
+ ((MK_XBUTTON1 & wparam) ? 0x08 : 0x00) |
+ ((MK_XBUTTON2 & wparam) ? 0x10 : 0x00));
+
+ // continue to track the mouse outside the window if buttons are down
+ if (buttons && !info->buttons)
+ {
+ SetCapture(platform_window());
+
+ TRACKMOUSEEVENT tm;
+ std::memset(&tm, 0, sizeof(tm));
+ tm.cbSize = sizeof(tm);
+ tm.dwFlags = TME_CANCEL | TME_LEAVE;
+ tm.hwndTrack = platform_window();
+ TrackMouseEvent(&tm);
+ m_tracking_mouse = false;
+ }
+ else
+ {
+ if (!buttons && info->buttons)
+ {
+ if (GetCapture() == platform_window())
+ ReleaseCapture();
+ }
+
+ if (!m_tracking_mouse)
+ {
+ TRACKMOUSEEVENT tm;
+ std::memset(&tm, 0, sizeof(tm));
+ tm.cbSize = sizeof(tm);
+ tm.dwFlags = TME_LEAVE;
+ tm.hwndTrack = platform_window();
+ TrackMouseEvent(&tm);
+ m_tracking_mouse = true;
+ }
+ }
+
+ update_pointer(*info, where, buttons, false);
+}
+
+void win_window_info::expire_pointer(std::vector<win_pointer_info>::iterator info, POINT const &where, bool canceled)
+{
+ // leaving implicitly releases buttons, so check hold/drag if necessary
+ if (BIT(info->buttons, 0) && (0 < info->clickcnt))
+ {
+ if (!canceled)
+ {
+ auto const now(std::chrono::steady_clock::now());
+ auto const exp(std::chrono::milliseconds(GetDoubleClickTime()) + info->pressed);
+ int const dx(where.x - info->pressedx);
+ int const dy(where.y - info->pressedy);
+ int const distance((dx * dx) + (dy * dy));
+ int const tolerance((PT_TOUCH == info->type) ? TAP_DISTANCE : CLICK_DISTANCE);
+ if ((exp < now) || (tolerance < distance))
+ info->clickcnt = -info->clickcnt;
+ }
+ else
+ {
+ info->clickcnt = -info->clickcnt;
+ }
+ }
+
+ // need to remember touches to recognise multi-tap gestures
+ if (!canceled && (PT_TOUCH == info->type) && (0 < info->clickcnt))
+ {
+ auto const now(std::chrono::steady_clock::now());
+ auto const time = std::chrono::milliseconds(GetDoubleClickTime());
+ if ((time + info->pressed) >= now)
+ {
+ try
+ {
+ unsigned i(0);
+ if (m_ptrdev_info.size() > info->device)
+ i = m_ptrdev_info[info->device].clear_expired_touches(now, time);
+ else
+ m_ptrdev_info.resize(info->device + 1);
+
+ if (std::size(m_ptrdev_info[info->device].touches) > i)
+ {
+ m_ptrdev_info[info->device].touches[i].when = info->pressed;
+ m_ptrdev_info[info->device].touches[i].x = info->pressedx;
+ m_ptrdev_info[info->device].touches[i].y = info->pressedy;
+ m_ptrdev_info[info->device].touches[i].cnt = info->clickcnt;
+ }
+ }
+ catch (std::bad_alloc const &)
+ {
+ osd_printf_error("win_window_info: error allocating pointer data\n");
+ }
+ }
+ }
+
+ // push to UI manager and dump pointer data
+ if (!canceled)
+ {
+ machine().ui_input().push_pointer_leave(
+ target(),
+ convert_pointer_type(info->type),
+ info->index,
+ info->device,
+ where.x, where.y,
+ info->buttons, info->clickcnt);
+ }
+ else
+ {
+ machine().ui_input().push_pointer_abort(
+ target(),
+ convert_pointer_type(info->type),
+ info->index,
+ info->device,
+ where.x, where.y,
+ info->buttons, info->clickcnt);
+ }
+ m_pointer_mask &= ~(decltype(m_pointer_mask)(1) << info->index);
+ if (info->index < m_next_pointer)
+ m_next_pointer = info->index;
+ m_active_pointers.erase(info);
+}
+
+void win_window_info::update_pointer(win_pointer_info &info, POINT const &where, unsigned buttons, bool canceled)
+{
+ if (!canceled && (where.x == info.x) && (where.y == info.y) && (buttons == info.buttons))
+ return;
+
+ // detect multi-click actions
+ unsigned const pressed(canceled ? 0 : (buttons & ~info.buttons));
+ unsigned const released(canceled ? ~info.buttons : (~buttons & info.buttons));
+ if (BIT(pressed, 0))
+ {
+ info.primary_down(
+ where.x, where.y,
+ std::chrono::milliseconds(GetDoubleClickTime()),
+ (PT_TOUCH == info.type) ? TAP_DISTANCE : CLICK_DISTANCE,
+ PT_TOUCH == info.type,
+ m_ptrdev_info);
+ }
+ else if (BIT(info.buttons, 0))
+ {
+ info.check_primary_hold_drag(
+ where.x, where.y,
+ std::chrono::milliseconds(GetDoubleClickTime()),
+ (PT_TOUCH == info.type) ? TAP_DISTANCE : CLICK_DISTANCE);
+ }
+
+ // update info and push to UI manager
+ info.x = where.x;
+ info.y = where.y;
+ info.buttons = buttons;
+ if (!canceled)
+ {
+ machine().ui_input().push_pointer_update(
+ target(),
+ convert_pointer_type(info.type),
+ info.index,
+ info.device,
+ where.x, where.y,
+ buttons, pressed, released, info.clickcnt);
+ }
+ else
+ {
+ machine().ui_input().push_pointer_abort(
+ target(),
+ convert_pointer_type(info.type),
+ info.index,
+ info.device,
+ where.x, where.y,
+ released, info.clickcnt);
+ }
+}
+
+std::vector<win_window_info::win_pointer_info>::iterator win_window_info::map_pointer(WPARAM wparam)
+{
+ WORD const ptrid(GET_POINTERID_WPARAM(wparam));
+ auto found(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), ptrid, &win_pointer_info::compare));
+ if ((m_active_pointers.end() != found) && (found->ptrid == ptrid))
+ return found;
+
+ if ((sizeof(m_next_pointer) * 8) <= m_next_pointer)
+ {
+ assert(~decltype(m_pointer_mask)(0) == m_pointer_mask);
+ osd_printf_warning("win_window_info: exceeded maximum number of active pointers\n");
+ return m_active_pointers.end();
+ }
+ assert(!BIT(m_pointer_mask, m_next_pointer));
+
+ POINTER_INFO info = { 0 };
+ if (!OSD_DYNAMIC_CALL(GetPointerInfo, ptrid, &info))
+ {
+ osd_printf_error("win_window_info: failed to get info for pointer ID %u\n", ptrid);
+ return m_active_pointers.end();
+ }
+
+ auto devpos(std::lower_bound(
+ m_ptrdev_map.begin(),
+ m_ptrdev_map.end(),
+ info.sourceDevice,
+ [] (std::pair<HANDLE, unsigned> const &mapping, HANDLE device)
+ {
+ return mapping.first < device;
+ }));
+
+ try
+ {
+ if ((m_ptrdev_map.end() == devpos) || (devpos->first != info.sourceDevice))
+ {
+ devpos = m_ptrdev_map.emplace(devpos, info.sourceDevice, m_next_ptrdev);
+ ++m_next_ptrdev;
+ }
+
+ found = m_active_pointers.emplace(
+ found,
+ win_pointer_info(ptrid, info.pointerType, m_next_pointer, devpos->second));
+ m_pointer_mask |= decltype(m_pointer_mask)(1) << m_next_pointer;
+ do
+ {
+ ++m_next_pointer;
+ }
+ while (((sizeof(m_next_pointer) * 8) > m_next_pointer) && BIT(m_pointer_mask, m_next_pointer));
+
+ return found;
+ }
+ catch (std::bad_alloc const &)
+ {
+ osd_printf_error("win_window_info: error allocating pointer data\n");
+ return m_active_pointers.end();
+ }
+}
+
+std::vector<win_window_info::win_pointer_info>::iterator win_window_info::find_pointer(WPARAM wparam)
+{
+ WORD const ptrid(GET_POINTERID_WPARAM(wparam));
+ auto const found(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), ptrid, &win_pointer_info::compare));
+ if ((m_active_pointers.end() != found) && (found->ptrid == ptrid))
+ return found;
+ else
+ return m_active_pointers.end();
+}
+
+std::vector<win_window_info::win_pointer_info>::iterator win_window_info::map_mouse_pointer()
+{
+ auto found(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), MOUSE_POINTER_ID, &win_pointer_info::compare));
+ if ((m_active_pointers.end() != found) && (found->ptrid == MOUSE_POINTER_ID))
+ return found;
+
+ if ((sizeof(m_next_pointer) * 8) <= m_next_pointer)
+ {
+ assert(~decltype(m_pointer_mask)(0) == m_pointer_mask);
+ osd_printf_warning("win_window_info: exceeded maximum number of active pointers\n");
+ return m_active_pointers.end();
+ }
+ assert(!BIT(m_pointer_mask, m_next_pointer));
+
+ auto devpos(std::lower_bound(
+ m_ptrdev_map.begin(),
+ m_ptrdev_map.end(),
+ INVALID_HANDLE_VALUE,
+ [] (std::pair<HANDLE, unsigned> const &mapping, HANDLE device)
+ {
+ return mapping.first < device;
+ }));
+
+ try
+ {
+ if ((m_ptrdev_map.end() == devpos) || (devpos->first != INVALID_HANDLE_VALUE))
+ {
+ devpos = m_ptrdev_map.emplace(devpos, INVALID_HANDLE_VALUE, m_next_ptrdev);
+ ++m_next_ptrdev;
+ }
+
+ found = m_active_pointers.emplace(
+ found,
+ win_pointer_info(MOUSE_POINTER_ID, PT_MOUSE, m_next_pointer, devpos->second));
+ m_pointer_mask |= decltype(m_pointer_mask)(1) << m_next_pointer;
+ do
+ {
+ ++m_next_pointer;
+ }
+ while (((sizeof(m_next_pointer) * 8) > m_next_pointer) && BIT(m_pointer_mask, m_next_pointer));
+
+ return found;
+ }
+ catch (std::bad_alloc const &)
+ {
+ osd_printf_error("win_window_info: error allocating pointer data\n");
+ return m_active_pointers.end();
+ }
+}
+
+std::vector<win_window_info::win_pointer_info>::iterator win_window_info::find_mouse_pointer()
+{
+ auto const found(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), MOUSE_POINTER_ID, &win_pointer_info::compare));
+ if ((m_active_pointers.end() != found) && (found->ptrid == MOUSE_POINTER_ID))
+ return found;
+ else
+ return m_active_pointers.end();
+}
+
+
+#if (USE_QTDEBUG)
//============================================================
// winwindow_qt_filter
//============================================================
-#if (USE_QTDEBUG)
bool winwindow_qt_filter(void *message)
{
- MSG *msg = (MSG *)message;
+ MSG *const msg = reinterpret_cast<MSG *>(message);
- if(is_mame_window(msg->hwnd) || (!msg->hwnd && (msg->message >= WM_USER)))
+ if (is_mame_window(msg->hwnd) || (!msg->hwnd && (msg->message >= WM_USER)))
{
LONG_PTR ptr;
- if(msg->hwnd) // get the machine associated with this window
+ if (msg->hwnd) // get the machine associated with this window
ptr = GetWindowLongPtr(msg->hwnd, GWLP_USERDATA);
else // any one will have to do
- ptr = (LONG_PTR)osd_common_t::s_window_list.front().get();
+ ptr = (LONG_PTR)osd_common_t::window_list().front().get();
- winwindow_dispatch_message(((win_window_info *)ptr)->machine(), msg);
+ winwindow_dispatch_message(reinterpret_cast<win_window_info *>(ptr)->machine(), *msg);
return true;
}
return false;
diff --git a/src/osd/windows/window.h b/src/osd/windows/window.h
index b04e35aa110..ada71f1cba7 100644
--- a/src/osd/windows/window.h
+++ b/src/osd/windows/window.h
@@ -1,40 +1,38 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Aaron Giles, Vas Crabb
//============================================================
//
// window.h - Win32 window handling
//
//============================================================
+#ifndef MAME_OSD_WINDOWS_WINDOW_H
+#define MAME_OSD_WINDOWS_WINDOW_H
-#ifndef __WIN_WINDOW__
-#define __WIN_WINDOW__
-
-// standard windows headers
-#include <windows.h>
-#include <windowsx.h>
-#include <mmsystem.h>
-
-#include <chrono>
-#include <mutex>
-#include <memory>
-#include <list>
+#pragma once
+#include "emucore.h"
#include "render.h"
#include "modules/osdwindow.h"
+#include "modules/lib/osdlib.h"
-//============================================================
-// PARAMETERS
-//============================================================
+#include <chrono>
+#include <list>
+#include <memory>
+#include <mutex>
+#include <utility>
+#include <vector>
+
+// standard windows headers
+#include <windows.h>
+#include <windowsx.h>
+#include <mmsystem.h>
//============================================================
// CONSTANTS
//============================================================
-#define RESIZE_STATE_NORMAL 0
-#define RESIZE_STATE_RESIZING 1
-#define RESIZE_STATE_PENDING 2
@@ -53,49 +51,45 @@ enum class win_window_focus
class win_window_info : public osd_window_t<HWND>
{
public:
- win_window_info(running_machine &machine, int index, std::shared_ptr<osd_monitor_info> monitor, const osd_window_config *config);
+ enum
+ {
+ RESIZE_STATE_NORMAL,
+ RESIZE_STATE_RESIZING,
+ RESIZE_STATE_PENDING
+ };
- running_machine &machine() const override { return m_machine; }
+ win_window_info(running_machine &machine, render_module &renderprovider, int index, const std::shared_ptr<osd_monitor_info> &monitor, const osd_window_config *config);
- virtual render_target *target() override { return m_target; }
- int fullscreen() const override { return m_fullscreen; }
bool attached_mode() const { return m_attached_mode; }
win_window_focus focus() const;
void update() override;
- virtual bool win_has_menu() override
- {
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
- return GetMenu(platform_window()) ? true : false;
-#else
- return false;
-#endif
- }
-
virtual osd_dim get_size() override
{
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
RECT client;
GetClientRect(platform_window(), &client);
return osd_dim(client.right - client.left, client.bottom - client.top);
-#else
- throw ref new Platform::NotImplementedException();
-#endif
}
+ win_window_info *main_window() const { return m_main; }
+ void set_main_window(win_window_info &main) { m_main = &main; }
+
void capture_pointer() override;
void release_pointer() override;
void show_pointer() override;
void hide_pointer() override;
- virtual osd_monitor_info *monitor() const override { return m_monitor.get(); }
-
- void destroy() override;
+ void complete_destroy() override;
// static
- static void create(running_machine &machine, int index, std::shared_ptr<osd_monitor_info> monitor, const osd_window_config *config);
+ static std::unique_ptr<win_window_info> create(
+ running_machine &machine,
+ render_module &renderprovider,
+ int index,
+ const std::shared_ptr<osd_monitor_info> &monitor,
+ const osd_window_config *config);
// static callbacks
@@ -103,38 +97,54 @@ public:
// member variables
- win_window_info * m_next;
volatile int m_init_state;
// window handle and info
- char m_title[256];
RECT m_non_fullscreen_bounds;
int m_startmaximized;
int m_isminimized;
int m_ismaximized;
// monitor info
- std::shared_ptr<osd_monitor_info> m_monitor;
- int m_fullscreen;
- int m_fullscreen_safe;
- float m_aspect;
+ int m_fullscreen_safe;
+ float m_aspect;
// rendering info
std::mutex m_render_lock;
- render_target * m_target;
- int m_targetview;
+ unsigned m_targetview;
int m_targetorient;
render_layer_config m_targetlayerconfig;
+ u32 m_targetvismask;
+ int m_targetscalemode;
+ bool m_targetkeepaspect;
// input info
- std::chrono::system_clock::time_point m_lastclicktime;
- int m_lastclickx;
- int m_lastclicky;
+ std::chrono::steady_clock::time_point m_lastclicktime;
+ int m_lastclickx;
+ int m_lastclicky;
+ char16_t m_last_surrogate;
+
+ HDC m_dc; // only used by GDI renderer!
+ int m_resize_state;
private:
+ struct win_pointer_info : public pointer_info
+ {
+ static constexpr bool compare(win_pointer_info const &info, WORD ptrid) { return info.ptrid < ptrid; }
+
+ win_pointer_info(win_pointer_info const &) = default;
+ win_pointer_info(win_pointer_info &&) = default;
+ win_pointer_info &operator=(win_pointer_info const &) = default;
+ win_pointer_info &operator=(win_pointer_info &&) = default;
+
+ win_pointer_info(WORD p, POINTER_INPUT_TYPE t, unsigned i, unsigned d);
+
+ WORD ptrid;
+ POINTER_INPUT_TYPE type;
+ };
+
void draw_video_contents(HDC dc, bool update);
int complete_create();
- void set_starting_view(int index, const char *defview, const char *view);
int wnd_extra_width();
int wnd_extra_height();
osd_rect constrain_to_aspect_ratio(const osd_rect &rect, int adjustment);
@@ -145,22 +155,40 @@ private:
void maximize_window();
void adjust_window_position_after_major_change();
void set_fullscreen(int fullscreen);
- std::shared_ptr<osd_monitor_info> monitor_from_rect(const osd_rect* proposed) const;
- static POINT s_saved_cursor_pos;
-
-#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
- static Windows::UI::Core::CoreCursor^ s_cursor;
-#endif
-
- running_machine & m_machine;
+ // pointer handling helpers
+ void pointer_entered(WPARAM wparam, LPARAM lparam);
+ void pointer_left(WPARAM wparam, LPARAM lparam);
+ void pointer_updated(WPARAM wparam, LPARAM lparam);
+ void pointer_capture_changed(WPARAM wparam, LPARAM lparam);
+ void mouse_left(WPARAM wparam, LPARAM lparam);
+ void mouse_updated(WPARAM wparam, LPARAM lparam);
+ void expire_pointer(std::vector<win_pointer_info>::iterator info, POINT const &where, bool canceled);
+ void update_pointer(win_pointer_info &info, POINT const &where, unsigned buttons, bool canceled);
+ std::vector<win_pointer_info>::iterator map_pointer(WPARAM wparam);
+ std::vector<win_pointer_info>::iterator find_pointer(WPARAM wparam);
+ std::vector<win_pointer_info>::iterator map_mouse_pointer();
+ std::vector<win_pointer_info>::iterator find_mouse_pointer();
+
+ win_window_info * m_main;
bool m_attached_mode;
-};
-struct osd_draw_callbacks
-{
- osd_renderer *(*create)(osd_window *window);
- void (*exit)(void);
+ // these functions first appear in Windows 8/Server 2012
+ OSD_DYNAMIC_API(user32, "User32.dll", "User32.dll");
+ OSD_DYNAMIC_API_FN(user32, BOOL, WINAPI, GetPointerType, UINT32, POINTER_INPUT_TYPE *);
+ OSD_DYNAMIC_API_FN(user32, BOOL, WINAPI, GetPointerInfo, UINT32, POINTER_INFO *);
+ OSD_DYNAMIC_API_FN(user32, BOOL, WINAPI, GetPointerPenInfo, UINT32, POINTER_PEN_INFO *);
+ OSD_DYNAMIC_API_FN(user32, BOOL, WINAPI, GetPointerTouchInfo, UINT32, POINTER_TOUCH_INFO *);
+
+ // info on currently active pointers - 64 pointers ought to be enough for anyone
+ uint64_t m_pointer_mask;
+ unsigned m_next_pointer, m_next_ptrdev;
+ bool m_tracking_mouse;
+ std::vector<std::pair<HANDLE, unsigned> > m_ptrdev_map;
+ std::vector<pointer_dev_info> m_ptrdev_info;
+ std::vector<win_pointer_info> m_active_pointers;
+
+ static POINT s_saved_cursor_pos;
};
@@ -171,22 +199,15 @@ struct osd_draw_callbacks
bool winwindow_has_focus(void);
void winwindow_update_cursor_state(running_machine &machine);
-extern LRESULT CALLBACK winwindow_video_window_proc_ui(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam);
-
void winwindow_toggle_full_screen(void);
void winwindow_take_snap(void);
void winwindow_take_video(void);
void winwindow_toggle_fsfx(void);
-void winwindow_process_events_periodic(running_machine &machine);
-void winwindow_process_events(running_machine &machine, bool ingame, bool nodispatch);
-
void winwindow_ui_pause(running_machine &machine, int pause);
int winwindow_ui_is_paused(running_machine &machine);
-void winwindow_dispatch_message(running_machine &machine, MSG *message);
-
-extern int win_create_menu(running_machine &machine, HMENU *menus);
+void winwindow_dispatch_message(running_machine &machine, MSG const &message);
@@ -205,4 +226,4 @@ static inline int rect_height(const RECT *rect)
return rect->bottom - rect->top;
}
-#endif
+#endif // MAME_OSD_WINDOWS_WINDOW_H
diff --git a/src/osd/windows/winmain.cpp b/src/osd/windows/winmain.cpp
index 721407a777a..2f7df659f44 100644
--- a/src/osd/windows/winmain.cpp
+++ b/src/osd/windows/winmain.cpp
@@ -6,41 +6,42 @@
//
//============================================================
+#include "winmain.h"
+
+#include "window.h"
+#include "winopts.h"
+
// MAME headers
#include "emu.h"
-#include "emuopts.h"
-#include "strconv.h"
+#include "main.h"
// MAMEOS headers
-#include "winmain.h"
-#include "window.h"
+#include "strconv.h"
#include "winutf8.h"
#include "winutil.h"
#include "winfile.h"
#include "modules/diagnostics/diagnostics_module.h"
+#include "modules/lib/osdlib.h"
#include "modules/monitor/monitor_common.h"
// standard C headers
-#include <ctype.h>
-#include <stdarg.h>
-#include <stdio.h>
+#include <cctype>
+#include <clocale>
+#include <cstdarg>
+#include <cstdio>
+#include <mutex>
+#include <optional>
+#include <sstream>
+#include <thread>
// standard windows headers
#include <windows.h>
#include <commctrl.h>
#include <mmsystem.h>
+#include <objbase.h>
#include <tchar.h>
#include <io.h>
-#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-#include <wrl/client.h>
-using namespace Windows::Storage;
-using namespace Platform;
-using namespace Windows::ApplicationModel;
-using namespace Windows::ApplicationModel::Core;
-using namespace Windows::UI::Popups;
-#endif
-
#define DEBUG_SLOW_LOCKS 0
//**************************************************************************
@@ -57,72 +58,85 @@ using namespace Windows::UI::Popups;
// TYPE DEFINITIONS
//**************************************************************************
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-
//============================================================
// winui_output_error
//============================================================
class winui_output_error : public osd_output
{
-public:
- virtual void output_callback(osd_output_channel channel, const char *msg, va_list args) override
+private:
+ struct ui_state
{
- if (channel == OSD_OUTPUT_CHANNEL_ERROR)
+ ~ui_state()
{
- char buffer[1024];
-
- // if we are in fullscreen mode, go to windowed mode
- if ((video_config.windowed == 0) && !osd_common_t::s_window_list.empty())
- winwindow_toggle_full_screen();
-
- vsnprintf(buffer, ARRAY_LENGTH(buffer), msg, args);
- win_message_box_utf8(!osd_common_t::s_window_list.empty() ? std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window() : nullptr, buffer, emulator_info::get_appname(), MB_OK);
+ if (thread)
+ thread->join();
}
- else
- chain_output(channel, msg, args);
- }
-};
-#else
+ std::ostringstream buffer;
+ std::optional<std::thread> thread;
+ std::mutex mutex;
+ bool active;
+ };
-//============================================================
-// winuniversal_output_error
-//============================================================
+ static ui_state &get_state()
+ {
+ static ui_state state;
+ return state;
+ }
-class winuniversal_output_error : public osd_output
-{
public:
- virtual void output_callback(osd_output_channel channel, const char *msg, va_list args) override
+ virtual void output_callback(osd_output_channel channel, const util::format_argument_pack<char> &args) override
{
- char buffer[2048];
if (channel == OSD_OUTPUT_CHANNEL_ERROR)
{
- vsnprintf(buffer, ARRAY_LENGTH(buffer), msg, args);
-
- std::wstring wcbuffer(osd::text::to_wstring(buffer));
- std::wstring wcappname(osd::text::to_wstring(emulator_info::get_appname()));
+ // if we are in fullscreen mode, go to windowed mode
+ if ((video_config.windowed == 0) && !osd_common_t::window_list().empty())
+ winwindow_toggle_full_screen();
- auto dlg = ref new MessageDialog(ref new Platform::String(wcbuffer.data()), ref new Platform::String(wcbuffer.data()));
- dlg->ShowAsync();
+ auto &state(get_state());
+ std::lock_guard<std::mutex> guard(state.mutex);
+ util::stream_format(state.buffer, args);
+ if (!state.active)
+ {
+ if (state.thread)
+ {
+ state.thread->join();
+ state.thread = std::nullopt;
+ }
+ state.thread.emplace(
+ [] ()
+ {
+ auto &state(get_state());
+ std::string message;
+ while (true)
+ {
+ {
+ std::lock_guard<std::mutex> guard(state.mutex);
+ message = std::move(state.buffer).str();
+ if (message.empty())
+ {
+ state.active = false;
+ return;
+ }
+ state.buffer.str(std::string());
+ }
+ // Don't hold any locks lock while calling MessageBox.
+ // Parent window isn't set because MAME could destroy
+ // the window out from under us on a fatal error.
+ win_message_box_utf8(nullptr, message.c_str(), emulator_info::get_appname(), MB_OK);
+ }
+ });
+ state.active = true;
+ }
}
- else if (channel == OSD_OUTPUT_CHANNEL_VERBOSE)
+ else
{
- vsnprintf(buffer, ARRAY_LENGTH(buffer), msg, args);
- std::wstring wcbuffer = osd::text::to_wstring(buffer);
- OutputDebugString(wcbuffer.c_str());
-
- // Chain to next anyway
- chain_output(channel, msg, args);
+ chain_output(channel, args);
}
- else
- chain_output(channel, msg, args);
}
};
-#endif
-
-
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
@@ -134,10 +148,8 @@ int _CRT_glob = 0;
// LOCAL VARIABLES
//**************************************************************************
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
static int timeresult = !TIMERR_NOERROR;
static TIMECAPS timecaps;
-#endif
static running_machine *g_current_machine;
@@ -151,142 +163,16 @@ static int is_double_click_start(int argc);
//**************************************************************************
-// OPTIONS
-//**************************************************************************
-
-// struct definitions
-const options_entry windows_options::s_option_entries[] =
-{
- // performance options
- { nullptr, nullptr, OPTION_HEADER, "WINDOWS PERFORMANCE OPTIONS" },
- { WINOPTION_PRIORITY "(-15-1)", "0", OPTION_INTEGER, "thread priority for the main game thread; range from -15 to 1" },
- { WINOPTION_PROFILE, "0", OPTION_INTEGER, "enables profiling, specifying the stack depth to track" },
-
- // video options
- { nullptr, nullptr, OPTION_HEADER, "WINDOWS VIDEO OPTIONS" },
- { WINOPTION_MENU, "0", OPTION_BOOLEAN, "enables menu bar if available by UI implementation" },
- { WINOPTION_ATTACH_WINDOW, "", OPTION_STRING, "attach to arbitrary window" },
-
- // post-processing options
- { nullptr, nullptr, OPTION_HEADER, "DIRECT3D POST-PROCESSING OPTIONS" },
- { WINOPTION_HLSLPATH, "hlsl", OPTION_STRING, "path to HLSL support files" },
- { WINOPTION_HLSL_ENABLE";hlsl", "0", OPTION_BOOLEAN, "enable HLSL post-processing (PS3.0 required)" },
- { WINOPTION_HLSL_OVERSAMPLING, "0", OPTION_BOOLEAN, "enable HLSL oversampling" },
- { WINOPTION_HLSL_WRITE, OSDOPTVAL_AUTO, OPTION_STRING, "enable HLSL AVI writing (huge disk bandwidth suggested)" },
- { WINOPTION_HLSL_SNAP_WIDTH, "2048", OPTION_STRING, "HLSL upscaled-snapshot width" },
- { WINOPTION_HLSL_SNAP_HEIGHT, "1536", OPTION_STRING, "HLSL upscaled-snapshot height" },
- { WINOPTION_SHADOW_MASK_TILE_MODE, "0", OPTION_INTEGER, "shadow mask tile mode (0 for screen based, 1 for source based)" },
- { WINOPTION_SHADOW_MASK_ALPHA";fs_shadwa(0.0-1.0)", "0.0", OPTION_FLOAT, "shadow mask alpha-blend value (1.0 is fully blended, 0.0 is no mask)" },
- { WINOPTION_SHADOW_MASK_TEXTURE";fs_shadwt(0.0-1.0)", "shadow-mask.png", OPTION_STRING, "shadow mask texture name" },
- { WINOPTION_SHADOW_MASK_COUNT_X";fs_shadww", "6", OPTION_INTEGER, "shadow mask tile width, in screen dimensions" },
- { WINOPTION_SHADOW_MASK_COUNT_Y";fs_shadwh", "4", OPTION_INTEGER, "shadow mask tile height, in screen dimensions" },
- { WINOPTION_SHADOW_MASK_USIZE";fs_shadwu(0.0-1.0)", "0.1875", OPTION_FLOAT, "shadow mask texture width, in U/V dimensions" },
- { WINOPTION_SHADOW_MASK_VSIZE";fs_shadwv(0.0-1.0)", "0.25", OPTION_FLOAT, "shadow mask texture height, in U/V dimensions" },
- { WINOPTION_SHADOW_MASK_UOFFSET";fs_shadwou(-1.0-1.0)", "0.0", OPTION_FLOAT, "shadow mask texture offset, in U direction" },
- { WINOPTION_SHADOW_MASK_VOFFSET";fs_shadwov(-1.0-1.0)", "0.0", OPTION_FLOAT, "shadow mask texture offset, in V direction" },
- { WINOPTION_DISTORTION";fs_dist(-1.0-1.0)", "0.0", OPTION_FLOAT, "screen distortion amount" },
- { WINOPTION_CUBIC_DISTORTION";fs_cubedist(-1.0-1.0)", "0.0", OPTION_FLOAT, "screen cubic distortion amount" },
- { WINOPTION_DISTORT_CORNER";fs_distc(0.0-1.0)", "0.0", OPTION_FLOAT, "screen distort corner amount" },
- { WINOPTION_ROUND_CORNER";fs_rndc(0.0-1.0)", "0.0", OPTION_FLOAT, "screen round corner amount" },
- { WINOPTION_SMOOTH_BORDER";fs_smob(0.0-1.0)", "0.0", OPTION_FLOAT, "screen smooth border amount" },
- { WINOPTION_REFLECTION";fs_ref(0.0-1.0)", "0.0", OPTION_FLOAT, "screen reflection amount" },
- { WINOPTION_VIGNETTING";fs_vig(0.0-1.0)", "0.0", OPTION_FLOAT, "image vignetting amount" },
- /* Beam-related values below this line*/
- { WINOPTION_SCANLINE_AMOUNT";fs_scanam(0.0-4.0)", "0.0", OPTION_FLOAT, "overall alpha scaling value for scanlines" },
- { WINOPTION_SCANLINE_SCALE";fs_scansc(0.0-4.0)", "1.0", OPTION_FLOAT, "overall height scaling value for scanlines" },
- { WINOPTION_SCANLINE_HEIGHT";fs_scanh(0.0-4.0)", "1.0", OPTION_FLOAT, "individual height scaling value for scanlines" },
- { WINOPTION_SCANLINE_VARIATION";fs_scanv(0.0-4.0)", "1.0", OPTION_FLOAT, "individual height varying value for scanlines" },
- { WINOPTION_SCANLINE_BRIGHT_SCALE";fs_scanbs(0.0-2.0)", "1.0", OPTION_FLOAT, "overall brightness scaling value for scanlines (multiplicative)" },
- { WINOPTION_SCANLINE_BRIGHT_OFFSET";fs_scanbo(0.0-1.0)", "0.0", OPTION_FLOAT, "overall brightness offset value for scanlines (additive)" },
- { WINOPTION_SCANLINE_JITTER";fs_scanjt(0.0-4.0)", "0.0", OPTION_FLOAT, "overall interlace jitter scaling value for scanlines" },
- { WINOPTION_HUM_BAR_ALPHA";fs_humba(0.0-1.0)", "0.0", OPTION_FLOAT, "overall alpha scaling value for hum bar" },
- { WINOPTION_DEFOCUS";fs_focus", "0.0,0.0", OPTION_STRING, "overall defocus value in screen-relative coords" },
- { WINOPTION_CONVERGE_X";fs_convx", "0.0,0.0,0.0", OPTION_STRING, "convergence in screen-relative X direction" },
- { WINOPTION_CONVERGE_Y";fs_convy", "0.0,0.0,0.0", OPTION_STRING, "convergence in screen-relative Y direction" },
- { WINOPTION_RADIAL_CONVERGE_X";fs_rconvx", "0.0,0.0,0.0", OPTION_STRING, "radial convergence in screen-relative X direction" },
- { WINOPTION_RADIAL_CONVERGE_Y";fs_rconvy", "0.0,0.0,0.0", OPTION_STRING, "radial convergence in screen-relative Y direction" },
- /* RGB colorspace convolution below this line */
- { WINOPTION_RED_RATIO";fs_redratio", "1.0,0.0,0.0", OPTION_STRING, "red output signal generated by input signal" },
- { WINOPTION_GRN_RATIO";fs_grnratio", "0.0,1.0,0.0", OPTION_STRING, "green output signal generated by input signal" },
- { WINOPTION_BLU_RATIO";fs_bluratio", "0.0,0.0,1.0", OPTION_STRING, "blue output signal generated by input signal" },
- { WINOPTION_SATURATION";fs_sat(0.0-4.0)", "1.0", OPTION_FLOAT, "saturation scaling value" },
- { WINOPTION_OFFSET";fs_offset", "0.0,0.0,0.0", OPTION_STRING, "signal offset value (additive)" },
- { WINOPTION_SCALE";fs_scale", "1.0,1.0,1.0", OPTION_STRING, "signal scaling value (multiplicative)" },
- { WINOPTION_POWER";fs_power", "1.0,1.0,1.0", OPTION_STRING, "signal power value (exponential)" },
- { WINOPTION_FLOOR";fs_floor", "0.0,0.0,0.0", OPTION_STRING, "signal floor level" },
- { WINOPTION_PHOSPHOR";fs_phosphor", "0.0,0.0,0.0", OPTION_STRING, "phosphorescence decay rate (0.0 is instant, 1.0 is forever)" },
- { WINOPTION_CHROMA_MODE, "3", OPTION_INTEGER, "number of phosphors to use: 1 - monochrome, 2 - dichrome, 3 - trichrome (color)" },
- { WINOPTION_CHROMA_CONVERSION_GAIN, "0.299,0.587,0.114", OPTION_STRING, "gain to be applied when summing RGB signal for monochrome and dichrome modes" },
- { WINOPTION_CHROMA_A, "0.64,0.33", OPTION_STRING, "chromaticity coordinate for first phosphor" },
- { WINOPTION_CHROMA_B, "0.30,0.60", OPTION_STRING, "chromaticity coordinate for second phosphor" },
- { WINOPTION_CHROMA_C, "0.15,0.06", OPTION_STRING, "chromaticity coordinate for third phosphor" },
- { WINOPTION_CHROMA_Y_GAIN, "0.2126,0.7152,0.0722", OPTION_STRING, "gain to be applied for each phosphor" },
- /* NTSC simulation below this line */
- { nullptr, nullptr, OPTION_HEADER, "NTSC POST-PROCESSING OPTIONS" },
- { WINOPTION_YIQ_ENABLE";yiq", "0", OPTION_BOOLEAN, "enable YIQ-space HLSL post-processing" },
- { WINOPTION_YIQ_JITTER";yiqj", "0.0", OPTION_FLOAT, "jitter for the NTSC signal processing" },
- { WINOPTION_YIQ_CCVALUE";yiqcc", "3.57954545", OPTION_FLOAT, "color carrier frequency for NTSC signal processing" },
- { WINOPTION_YIQ_AVALUE";yiqa", "0.5", OPTION_FLOAT, "A value for NTSC signal processing" },
- { WINOPTION_YIQ_BVALUE";yiqb", "0.5", OPTION_FLOAT, "B value for NTSC signal processing" },
- { WINOPTION_YIQ_OVALUE";yiqo", "0.0", OPTION_FLOAT, "outgoing Color Carrier phase offset for NTSC signal processing" },
- { WINOPTION_YIQ_PVALUE";yiqp", "1.0", OPTION_FLOAT, "incoming Pixel Clock scaling value for NTSC signal processing" },
- { WINOPTION_YIQ_NVALUE";yiqn", "1.0", OPTION_FLOAT, "Y filter notch width for NTSC signal processing" },
- { WINOPTION_YIQ_YVALUE";yiqy", "6.0", OPTION_FLOAT, "Y filter cutoff frequency for NTSC signal processing" },
- { WINOPTION_YIQ_IVALUE";yiqi", "1.2", OPTION_FLOAT, "I filter cutoff frequency for NTSC signal processing" },
- { WINOPTION_YIQ_QVALUE";yiqq", "0.6", OPTION_FLOAT, "Q filter cutoff frequency for NTSC signal processing" },
- { WINOPTION_YIQ_SCAN_TIME";yiqsc", "52.6", OPTION_FLOAT, "horizontal scanline duration for NTSC signal processing (microseconds)" },
- { WINOPTION_YIQ_PHASE_COUNT";yiqpc", "2", OPTION_INTEGER, "phase count value for NTSC signal processing" },
- /* Vector simulation below this line */
- { nullptr, nullptr, OPTION_HEADER, "VECTOR POST-PROCESSING OPTIONS" },
- { WINOPTION_VECTOR_BEAM_SMOOTH";vecsmooth", "0.0", OPTION_FLOAT, "vector beam smoothness" },
- { WINOPTION_VECTOR_LENGTH_SCALE";vecscale", "0.5", OPTION_FLOAT, "maximum vector attenuation" },
- { WINOPTION_VECTOR_LENGTH_RATIO";vecratio", "0.5", OPTION_FLOAT, "minimum vector length affected by attenuation (vector length to screen size ratio)" },
- /* Bloom below this line */
- { nullptr, nullptr, OPTION_HEADER, "BLOOM POST-PROCESSING OPTIONS" },
- { WINOPTION_BLOOM_BLEND_MODE, "0", OPTION_INTEGER, "bloom blend mode (0 for brighten, 1 for darken)" },
- { WINOPTION_BLOOM_SCALE, "0.0", OPTION_FLOAT, "intensity factor for bloom" },
- { WINOPTION_BLOOM_OVERDRIVE, "1.0,1.0,1.0", OPTION_STRING, "overdrive factor for bloom" },
- { WINOPTION_BLOOM_LEVEL0_WEIGHT, "1.0", OPTION_FLOAT, "bloom level 0 weight (full-size target)" },
- { WINOPTION_BLOOM_LEVEL1_WEIGHT, "0.64", OPTION_FLOAT, "bloom level 1 weight (1/4 smaller that level 0 target)" },
- { WINOPTION_BLOOM_LEVEL2_WEIGHT, "0.32", OPTION_FLOAT, "bloom level 2 weight (1/4 smaller that level 1 target)" },
- { WINOPTION_BLOOM_LEVEL3_WEIGHT, "0.16", OPTION_FLOAT, "bloom level 3 weight (1/4 smaller that level 2 target)" },
- { WINOPTION_BLOOM_LEVEL4_WEIGHT, "0.08", OPTION_FLOAT, "bloom level 4 weight (1/4 smaller that level 3 target)" },
- { WINOPTION_BLOOM_LEVEL5_WEIGHT, "0.06", OPTION_FLOAT, "bloom level 5 weight (1/4 smaller that level 4 target)" },
- { WINOPTION_BLOOM_LEVEL6_WEIGHT, "0.04", OPTION_FLOAT, "bloom level 6 weight (1/4 smaller that level 5 target)" },
- { WINOPTION_BLOOM_LEVEL7_WEIGHT, "0.02", OPTION_FLOAT, "bloom level 7 weight (1/4 smaller that level 6 target)" },
- { WINOPTION_BLOOM_LEVEL8_WEIGHT, "0.01", OPTION_FLOAT, "bloom level 8 weight (1/4 smaller that level 7 target)" },
- { WINOPTION_LUT_TEXTURE, "", OPTION_STRING, "3D LUT texture filename for screen, PNG format" },
- { WINOPTION_LUT_ENABLE, "0", OPTION_BOOLEAN, "Enables 3D LUT to be applied to screen after post-processing" },
- { WINOPTION_UI_LUT_TEXTURE, "", OPTION_STRING, "3D LUT texture filename of UI, PNG format" },
- { WINOPTION_UI_LUT_ENABLE, "0", OPTION_BOOLEAN, "enable 3D LUT to be applied to UI and artwork after post-processing" },
-
- // full screen options
- { nullptr, nullptr, OPTION_HEADER, "FULL SCREEN OPTIONS" },
- { WINOPTION_TRIPLEBUFFER ";tb", "0", OPTION_BOOLEAN, "enable triple buffering" },
- { WINOPTION_FULLSCREENBRIGHTNESS ";fsb(0.1-2.0)", "1.0", OPTION_FLOAT, "brightness value in full screen mode" },
- { WINOPTION_FULLSCREENCONTRAST ";fsc(0.1-2.0)", "1.0", OPTION_FLOAT, "contrast value in full screen mode" },
- { WINOPTION_FULLSCREENGAMMA ";fsg(0.1-3.0)", "1.0", OPTION_FLOAT, "gamma value in full screen mode" },
-
- // input options
- { nullptr, nullptr, OPTION_HEADER, "INPUT DEVICE OPTIONS" },
- { WINOPTION_GLOBAL_INPUTS, "0", OPTION_BOOLEAN, "enable global inputs" },
- { WINOPTION_DUAL_LIGHTGUN ";dual", "0", OPTION_BOOLEAN, "enable dual lightgun input" },
-
- { nullptr }
-};
-
-//**************************************************************************
// MAIN ENTRY POINT
//**************************************************************************
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-
//============================================================
// main
//============================================================
int main(int argc, char *argv[])
{
+ std::setlocale(LC_ALL, "");
std::vector<std::string> args = osd_get_command_line(argc, argv);
// use small output buffers on non-TTYs (i.e. pipes)
@@ -295,6 +181,17 @@ int main(int argc, char *argv[])
if (!isatty(fileno(stderr)))
setvbuf(stderr, (char *) nullptr, _IOFBF, 64);
+ {
+ // Disable legacy mouse to pointer event translation - it's broken:
+ // * No WM_POINTERLEAVE event when mouse pointer moves directly to an
+ // overlapping window from the same process.
+ // * Still receive occasional WM_MOUSEMOVE events.
+ OSD_DYNAMIC_API(user32, "User32.dll", "User32.dll");
+ OSD_DYNAMIC_API_FN(user32, BOOL, WINAPI, EnableMouseInPointer, BOOL);
+ if (OSD_DYNAMIC_API_TEST(EnableMouseInPointer))
+ OSD_DYNAMIC_CALL(EnableMouseInPointer, FALSE);
+ }
+
// initialize common controls
InitCommonControls();
@@ -364,107 +261,6 @@ static BOOL WINAPI control_handler(DWORD type)
return TRUE;
}
-#else
-
-// The main function is only used to initialize our IFrameworkView class.
-[Platform::MTAThread]
-int main(Platform::Array<Platform::String^>^ args)
-{
- auto direct3DApplicationSource = ref new MameViewSource();
- CoreApplication::Run(direct3DApplicationSource);
- return 0;
-}
-
-MameMainApp::MameMainApp()
-{
- // Turn off application view scaling so XBOX gets full screen
- Windows::UI::ViewManagement::ApplicationViewScaling::TrySetDisableLayoutScaling(true);
-}
-
-void MameMainApp::Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView)
-{
- // Register event handlers for app lifecycle.
-}
-
-// Called when the CoreWindow object is created (or re-created).
-void MameMainApp::SetWindow(Windows::UI::Core::CoreWindow^ window)
-{
- // Attach event handlers on the window for input, etc.
-}
-
-// Initializes scene resources, or loads a previously saved app state.
-void MameMainApp::Load(Platform::String^ entryPoint)
-{
-}
-
-void MameMainApp::Run()
-{
- // use small output buffers on non-TTYs (i.e. pipes)
- if (!isatty(fileno(stdout)))
- setvbuf(stdout, (char *) nullptr, _IOFBF, 64);
- if (!isatty(fileno(stderr)))
- setvbuf(stderr, (char *) nullptr, _IOFBF, 64);
-
- // parse config and cmdline options
- m_options = std::make_unique<windows_options>();
- m_osd = std::make_unique<windows_osd_interface>(*m_options.get());
-
- // Since we're a GUI app, out errors to message boxes
- // Initialize this after the osd interface so that we are first in the
- // output order
- winuniversal_output_error winerror;
- osd_output::push(&winerror);
-
- m_osd->register_options();
-
- // To satisfy the latter things, pass in the module path name
- char exe_path[MAX_PATH];
- GetModuleFileNameA(nullptr, exe_path, MAX_PATH);
- char* args[3] = { exe_path, (char*)"-verbose", (char*)"-mouse" };
-
- DWORD result = emulator_info::start_frontend(*m_options.get(), *m_osd.get(), ARRAY_LENGTH(args), args);
- osd_output::pop(&winerror);
-}
-
-// Required for IFrameworkView.
-void MameMainApp::Uninitialize()
-{
- // Terminate events do not cause Uninitialize to be called. It will be called if your IFrameworkView
- // class is torn down while the app is in the foreground.
-}
-
-IFrameworkView^ MameViewSource::CreateView()
-{
- return ref new MameMainApp();
-}
-
-#endif
-
-
-//============================================================
-// windows_options
-//============================================================
-
-windows_options::windows_options()
-: osd_options()
-{
- add_entries(s_option_entries);
-#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
- String^ path = ApplicationData::Current->LocalFolder->Path + L"\\";
- set_default_value(OPTION_INIPATH, (osd::text::from_wstring((LPCWSTR)path->Data()) + ";" + ini_path()).c_str());
- set_default_value(OPTION_CFG_DIRECTORY, (osd::text::from_wstring((LPCWSTR)path->Data()) + cfg_directory()).c_str());
- set_default_value(OPTION_NVRAM_DIRECTORY, (osd::text::from_wstring((LPCWSTR)path->Data()) + nvram_directory()).c_str());
- set_default_value(OPTION_INPUT_DIRECTORY, (osd::text::from_wstring((LPCWSTR)path->Data()) + input_directory()).c_str());
- set_default_value(OPTION_STATE_DIRECTORY, (osd::text::from_wstring((LPCWSTR)path->Data()) + state_directory()).c_str());
- set_default_value(OPTION_SNAPSHOT_DIRECTORY, (osd::text::from_wstring((LPCWSTR)path->Data()) + snapshot_directory()).c_str());
- set_default_value(OPTION_DIFF_DIRECTORY, (osd::text::from_wstring((LPCWSTR)path->Data()) + diff_directory()).c_str());
- set_default_value(OPTION_COMMENT_DIRECTORY, (osd::text::from_wstring((LPCWSTR)path->Data()) + comment_directory()).c_str());
-
- set_default_value(OPTION_HOMEPATH, osd::text::from_wstring((LPCWSTR)path->Data()).c_str());
- set_default_value(OPTION_MEDIAPATH, (osd::text::from_wstring((LPCWSTR)path->Data()) + media_path()).c_str());
-#endif
-}
-
//============================================================
// output_oslog
@@ -486,6 +282,8 @@ void windows_osd_interface::output_oslog(const char *buffer)
windows_osd_interface::windows_osd_interface(windows_options &options)
: osd_common_t(options)
, m_options(options)
+ , m_com_status(SUCCEEDED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED)))
+ , m_last_event_check(std::chrono::steady_clock::time_point::min())
{
}
@@ -496,25 +294,12 @@ windows_osd_interface::windows_osd_interface(windows_options &options)
windows_osd_interface::~windows_osd_interface()
{
+ if (m_com_status)
+ CoUninitialize();
}
//============================================================
-// video_register
-//============================================================
-
-void windows_osd_interface::video_register()
-{
- video_options_add("gdi", nullptr);
- video_options_add("d3d", nullptr);
-#if USE_OPENGL
- video_options_add("opengl", nullptr);
-#endif
- video_options_add("bgfx", nullptr);
- //video_options_add("auto", nullptr); // making d3d video default one
-}
-
-//============================================================
// init
//============================================================
@@ -524,12 +309,13 @@ void windows_osd_interface::init(running_machine &machine)
osd_common_t::init(machine);
const char *stemp;
- windows_options &options = downcast<windows_options &>(machine.options());
+ auto &options = downcast<windows_options &>(machine.options());
// determine if we are benchmarking, and adjust options appropriately
int bench = options.bench();
if (bench > 0)
{
+ options.set_value(OPTION_SLEEP, false, OPTION_PRIORITY_MAXIMUM);
options.set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM);
options.set_value(OSDOPTION_SOUND, "none", OPTION_PRIORITY_MAXIMUM);
options.set_value(OSDOPTION_VIDEO, "none", OPTION_PRIORITY_MAXIMUM);
@@ -566,23 +352,15 @@ void windows_osd_interface::init(running_machine &machine)
// initialize the subsystems
osd_common_t::init_subsystems();
- // notify listeners of screen configuration
- for (auto info : osd_common_t::s_window_list)
- {
- machine.output().set_value(string_format("Orientation(%s)", info->monitor()->devicename()).c_str(), std::static_pointer_cast<win_window_info>(info)->m_targetorient);
- }
-
// hook up the debugger log
if (options.oslog())
machine.add_logerror_callback(&windows_osd_interface::output_oslog);
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
// crank up the multimedia timer resolution to its max
// this gives the system much finer timeslices
timeresult = timeGetDevCaps(&timecaps, sizeof(timecaps));
if (timeresult == TIMERR_NOERROR)
timeBeginPeriod(timecaps.wPeriodMin);
-#endif
// create and start the profiler
if (profile > 0)
@@ -616,30 +394,15 @@ void windows_osd_interface::osd_exit()
diagnostics_module::get_instance()->stop_profiler();
diagnostics_module::get_instance()->print_profiler_results();
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
// restore the timer resolution
if (timeresult == TIMERR_NOERROR)
timeEndPeriod(timecaps.wPeriodMin);
-#endif
// one last pass at events
- winwindow_process_events(machine(), false, false);
-}
-
-
-//============================================================
-// osd_setup_osd_specific_emu_options
-//============================================================
-
-void osd_setup_osd_specific_emu_options(emu_options &opts)
-{
- opts.add_entries(osd_options::s_option_entries);
- opts.add_entries(windows_options::s_option_entries);
+ process_events(false, false);
}
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-
//============================================================
// check_for_double_click_start
//============================================================
@@ -654,5 +417,3 @@ static int is_double_click_start(int argc)
// try to determine if MAME was simply double-clicked
return (argc <= 1 && startup_info.dwFlags && !(startup_info.dwFlags & STARTF_USESTDHANDLES));
}
-
-#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
diff --git a/src/osd/windows/winmain.h b/src/osd/windows/winmain.h
index 21e1b9d2044..5b8e992be6b 100644
--- a/src/osd/windows/winmain.h
+++ b/src/osd/windows/winmain.h
@@ -5,235 +5,19 @@
// winmain.h - Win32 main program and core headers
//
//============================================================
+#ifndef MAME_OSD_WINDOWS_WINMAIN_H
+#define MAME_OSD_WINDOWS_WINMAIN_H
-#ifndef __WINDOWS_WINMAIN_H__
-#define __WINDOWS_WINMAIN_H__
+#pragma once
-#include <winapifamily.h>
-#include "osdepend.h"
-#include "modules/lib/osdobj_common.h"
-
-
-//============================================================
-// CONSTANTS
-//============================================================
-
-// performance options
-#define WINOPTION_PRIORITY "priority"
-#define WINOPTION_PROFILE "profile"
-
-// video options
-#define WINOPTION_MENU "menu"
-#define WINOPTION_ATTACH_WINDOW "attach_window"
-
-// core post-processing options
-#define WINOPTION_HLSLPATH "hlslpath"
-#define WINOPTION_HLSL_ENABLE "hlsl_enable"
-#define WINOPTION_HLSL_OVERSAMPLING "hlsl_oversampling"
-#define WINOPTION_HLSL_WRITE "hlsl_write"
-#define WINOPTION_HLSL_SNAP_WIDTH "hlsl_snap_width"
-#define WINOPTION_HLSL_SNAP_HEIGHT "hlsl_snap_height"
-#define WINOPTION_SHADOW_MASK_TILE_MODE "shadow_mask_tile_mode"
-#define WINOPTION_SHADOW_MASK_ALPHA "shadow_mask_alpha"
-#define WINOPTION_SHADOW_MASK_TEXTURE "shadow_mask_texture"
-#define WINOPTION_SHADOW_MASK_COUNT_X "shadow_mask_x_count"
-#define WINOPTION_SHADOW_MASK_COUNT_Y "shadow_mask_y_count"
-#define WINOPTION_SHADOW_MASK_USIZE "shadow_mask_usize"
-#define WINOPTION_SHADOW_MASK_VSIZE "shadow_mask_vsize"
-#define WINOPTION_SHADOW_MASK_UOFFSET "shadow_mask_uoffset"
-#define WINOPTION_SHADOW_MASK_VOFFSET "shadow_mask_voffset"
-#define WINOPTION_REFLECTION "reflection"
-#define WINOPTION_DISTORTION "distortion"
-#define WINOPTION_CUBIC_DISTORTION "cubic_distortion"
-#define WINOPTION_DISTORT_CORNER "distort_corner"
-#define WINOPTION_ROUND_CORNER "round_corner"
-#define WINOPTION_SMOOTH_BORDER "smooth_border"
-#define WINOPTION_VIGNETTING "vignetting"
-#define WINOPTION_SCANLINE_AMOUNT "scanline_alpha"
-#define WINOPTION_SCANLINE_SCALE "scanline_size"
-#define WINOPTION_SCANLINE_HEIGHT "scanline_height"
-#define WINOPTION_SCANLINE_VARIATION "scanline_variation"
-#define WINOPTION_SCANLINE_BRIGHT_SCALE "scanline_bright_scale"
-#define WINOPTION_SCANLINE_BRIGHT_OFFSET "scanline_bright_offset"
-#define WINOPTION_SCANLINE_JITTER "scanline_jitter"
-#define WINOPTION_HUM_BAR_ALPHA "hum_bar_alpha"
-#define WINOPTION_DEFOCUS "defocus"
-#define WINOPTION_CONVERGE_X "converge_x"
-#define WINOPTION_CONVERGE_Y "converge_y"
-#define WINOPTION_RADIAL_CONVERGE_X "radial_converge_x"
-#define WINOPTION_RADIAL_CONVERGE_Y "radial_converge_y"
-#define WINOPTION_RED_RATIO "red_ratio"
-#define WINOPTION_GRN_RATIO "grn_ratio"
-#define WINOPTION_BLU_RATIO "blu_ratio"
-#define WINOPTION_OFFSET "offset"
-#define WINOPTION_SCALE "scale"
-#define WINOPTION_POWER "power"
-#define WINOPTION_FLOOR "floor"
-#define WINOPTION_PHOSPHOR "phosphor_life"
-#define WINOPTION_SATURATION "saturation"
-#define WINOPTION_CHROMA_MODE "chroma_mode"
-#define WINOPTION_CHROMA_CONVERSION_GAIN "chroma_conversion_gain"
-#define WINOPTION_CHROMA_A "chroma_a"
-#define WINOPTION_CHROMA_B "chroma_b"
-#define WINOPTION_CHROMA_C "chroma_c"
-#define WINOPTION_CHROMA_Y_GAIN "chroma_y_gain"
-#define WINOPTION_YIQ_ENABLE "yiq_enable"
-#define WINOPTION_YIQ_JITTER "yiq_jitter"
-#define WINOPTION_YIQ_CCVALUE "yiq_cc"
-#define WINOPTION_YIQ_AVALUE "yiq_a"
-#define WINOPTION_YIQ_BVALUE "yiq_b"
-#define WINOPTION_YIQ_OVALUE "yiq_o"
-#define WINOPTION_YIQ_PVALUE "yiq_p"
-#define WINOPTION_YIQ_NVALUE "yiq_n"
-#define WINOPTION_YIQ_YVALUE "yiq_y"
-#define WINOPTION_YIQ_IVALUE "yiq_i"
-#define WINOPTION_YIQ_QVALUE "yiq_q"
-#define WINOPTION_YIQ_SCAN_TIME "yiq_scan_time"
-#define WINOPTION_YIQ_PHASE_COUNT "yiq_phase_count"
-#define WINOPTION_VECTOR_BEAM_SMOOTH "vector_beam_smooth"
-#define WINOPTION_VECTOR_LENGTH_SCALE "vector_length_scale"
-#define WINOPTION_VECTOR_LENGTH_RATIO "vector_length_ratio"
-#define WINOPTION_BLOOM_BLEND_MODE "bloom_blend_mode"
-#define WINOPTION_BLOOM_SCALE "bloom_scale"
-#define WINOPTION_BLOOM_OVERDRIVE "bloom_overdrive"
-#define WINOPTION_BLOOM_LEVEL0_WEIGHT "bloom_lvl0_weight"
-#define WINOPTION_BLOOM_LEVEL1_WEIGHT "bloom_lvl1_weight"
-#define WINOPTION_BLOOM_LEVEL2_WEIGHT "bloom_lvl2_weight"
-#define WINOPTION_BLOOM_LEVEL3_WEIGHT "bloom_lvl3_weight"
-#define WINOPTION_BLOOM_LEVEL4_WEIGHT "bloom_lvl4_weight"
-#define WINOPTION_BLOOM_LEVEL5_WEIGHT "bloom_lvl5_weight"
-#define WINOPTION_BLOOM_LEVEL6_WEIGHT "bloom_lvl6_weight"
-#define WINOPTION_BLOOM_LEVEL7_WEIGHT "bloom_lvl7_weight"
-#define WINOPTION_BLOOM_LEVEL8_WEIGHT "bloom_lvl8_weight"
-#define WINOPTION_LUT_TEXTURE "lut_texture"
-#define WINOPTION_LUT_ENABLE "lut_enable"
-#define WINOPTION_UI_LUT_TEXTURE "ui_lut_texture"
-#define WINOPTION_UI_LUT_ENABLE "ui_lut_enable"
-
-// full screen options
-#define WINOPTION_TRIPLEBUFFER "triplebuffer"
-#define WINOPTION_FULLSCREENBRIGHTNESS "full_screen_brightness"
-#define WINOPTION_FULLSCREENCONTRAST "full_screen_contrast"
-#define WINOPTION_FULLSCREENGAMMA "full_screen_gamma"
-
-// input options
-#define WINOPTION_GLOBAL_INPUTS "global_inputs"
-#define WINOPTION_DUAL_LIGHTGUN "dual_lightgun"
-
-//============================================================
-// TYPE DEFINITIONS
-//============================================================
-
-class windows_options : public osd_options
-{
-public:
- // construction/destruction
- windows_options();
-
- // performance options
- int priority() const { return int_value(WINOPTION_PRIORITY); }
- int profile() const { return int_value(WINOPTION_PROFILE); }
-
- // video options
- bool menu() const { return bool_value(WINOPTION_MENU); }
- const char *attach_window() const { return value(WINOPTION_ATTACH_WINDOW); }
+#include "winopts.h"
- // core post-processing options
- const char *screen_post_fx_dir() const { return value(WINOPTION_HLSLPATH); }
- bool d3d_hlsl_enable() const { return bool_value(WINOPTION_HLSL_ENABLE); }
- bool d3d_hlsl_oversampling() const { return bool_value(WINOPTION_HLSL_OVERSAMPLING); }
- const char *d3d_hlsl_write() const { return value(WINOPTION_HLSL_WRITE); }
- int d3d_snap_width() const { return int_value(WINOPTION_HLSL_SNAP_WIDTH); }
- int d3d_snap_height() const { return int_value(WINOPTION_HLSL_SNAP_HEIGHT); }
- int screen_shadow_mask_tile_mode() const { return int_value(WINOPTION_SHADOW_MASK_TILE_MODE); }
- float screen_shadow_mask_alpha() const { return float_value(WINOPTION_SHADOW_MASK_ALPHA); }
- const char *screen_shadow_mask_texture() const { return value(WINOPTION_SHADOW_MASK_TEXTURE); }
- int screen_shadow_mask_count_x() const { return int_value(WINOPTION_SHADOW_MASK_COUNT_X); }
- int screen_shadow_mask_count_y() const { return int_value(WINOPTION_SHADOW_MASK_COUNT_Y); }
- float screen_shadow_mask_u_size() const { return float_value(WINOPTION_SHADOW_MASK_USIZE); }
- float screen_shadow_mask_v_size() const { return float_value(WINOPTION_SHADOW_MASK_VSIZE); }
- float screen_shadow_mask_u_offset() const { return float_value(WINOPTION_SHADOW_MASK_UOFFSET); }
- float screen_shadow_mask_v_offset() const { return float_value(WINOPTION_SHADOW_MASK_VOFFSET); }
- float screen_scanline_amount() const { return float_value(WINOPTION_SCANLINE_AMOUNT); }
- float screen_scanline_scale() const { return float_value(WINOPTION_SCANLINE_SCALE); }
- float screen_scanline_height() const { return float_value(WINOPTION_SCANLINE_HEIGHT); }
- float screen_scanline_variation() const { return float_value(WINOPTION_SCANLINE_VARIATION); }
- float screen_scanline_bright_scale() const { return float_value(WINOPTION_SCANLINE_BRIGHT_SCALE); }
- float screen_scanline_bright_offset() const { return float_value(WINOPTION_SCANLINE_BRIGHT_OFFSET); }
- float screen_scanline_jitter() const { return float_value(WINOPTION_SCANLINE_JITTER); }
- float screen_hum_bar_alpha() const { return float_value(WINOPTION_HUM_BAR_ALPHA); }
- float screen_reflection() const { return float_value(WINOPTION_REFLECTION); }
- float screen_distortion() const { return float_value(WINOPTION_DISTORTION); }
- float screen_cubic_distortion() const { return float_value(WINOPTION_CUBIC_DISTORTION); }
- float screen_distort_corner() const { return float_value(WINOPTION_DISTORT_CORNER); }
- float screen_round_corner() const { return float_value(WINOPTION_ROUND_CORNER); }
- float screen_smooth_border() const { return float_value(WINOPTION_SMOOTH_BORDER); }
- float screen_vignetting() const { return float_value(WINOPTION_VIGNETTING); }
- const char *screen_defocus() const { return value(WINOPTION_DEFOCUS); }
- const char *screen_converge_x() const { return value(WINOPTION_CONVERGE_X); }
- const char *screen_converge_y() const { return value(WINOPTION_CONVERGE_Y); }
- const char *screen_radial_converge_x() const { return value(WINOPTION_RADIAL_CONVERGE_X); }
- const char *screen_radial_converge_y() const { return value(WINOPTION_RADIAL_CONVERGE_Y); }
- const char *screen_red_ratio() const { return value(WINOPTION_RED_RATIO); }
- const char *screen_grn_ratio() const { return value(WINOPTION_GRN_RATIO); }
- const char *screen_blu_ratio() const { return value(WINOPTION_BLU_RATIO); }
- bool screen_yiq_enable() const { return bool_value(WINOPTION_YIQ_ENABLE); }
- float screen_yiq_jitter() const { return float_value(WINOPTION_YIQ_JITTER); }
- float screen_yiq_cc() const { return float_value(WINOPTION_YIQ_CCVALUE); }
- float screen_yiq_a() const { return float_value(WINOPTION_YIQ_AVALUE); }
- float screen_yiq_b() const { return float_value(WINOPTION_YIQ_BVALUE); }
- float screen_yiq_o() const { return float_value(WINOPTION_YIQ_OVALUE); }
- float screen_yiq_p() const { return float_value(WINOPTION_YIQ_PVALUE); }
- float screen_yiq_n() const { return float_value(WINOPTION_YIQ_NVALUE); }
- float screen_yiq_y() const { return float_value(WINOPTION_YIQ_YVALUE); }
- float screen_yiq_i() const { return float_value(WINOPTION_YIQ_IVALUE); }
- float screen_yiq_q() const { return float_value(WINOPTION_YIQ_QVALUE); }
- float screen_yiq_scan_time() const { return float_value(WINOPTION_YIQ_SCAN_TIME); }
- int screen_yiq_phase_count() const { return int_value(WINOPTION_YIQ_PHASE_COUNT); }
- float screen_vector_beam_smooth() const { return float_value(WINOPTION_VECTOR_BEAM_SMOOTH); }
- float screen_vector_length_scale() const { return float_value(WINOPTION_VECTOR_LENGTH_SCALE); }
- float screen_vector_length_ratio() const { return float_value(WINOPTION_VECTOR_LENGTH_RATIO); }
- int screen_bloom_blend_mode() const { return int_value(WINOPTION_BLOOM_BLEND_MODE); }
- float screen_bloom_scale() const { return float_value(WINOPTION_BLOOM_SCALE); }
- const char *screen_bloom_overdrive() const { return value(WINOPTION_BLOOM_OVERDRIVE); }
- float screen_bloom_lvl0_weight() const { return float_value(WINOPTION_BLOOM_LEVEL0_WEIGHT); }
- float screen_bloom_lvl1_weight() const { return float_value(WINOPTION_BLOOM_LEVEL1_WEIGHT); }
- float screen_bloom_lvl2_weight() const { return float_value(WINOPTION_BLOOM_LEVEL2_WEIGHT); }
- float screen_bloom_lvl3_weight() const { return float_value(WINOPTION_BLOOM_LEVEL3_WEIGHT); }
- float screen_bloom_lvl4_weight() const { return float_value(WINOPTION_BLOOM_LEVEL4_WEIGHT); }
- float screen_bloom_lvl5_weight() const { return float_value(WINOPTION_BLOOM_LEVEL5_WEIGHT); }
- float screen_bloom_lvl6_weight() const { return float_value(WINOPTION_BLOOM_LEVEL6_WEIGHT); }
- float screen_bloom_lvl7_weight() const { return float_value(WINOPTION_BLOOM_LEVEL7_WEIGHT); }
- float screen_bloom_lvl8_weight() const { return float_value(WINOPTION_BLOOM_LEVEL8_WEIGHT); }
- const char *screen_offset() const { return value(WINOPTION_OFFSET); }
- const char *screen_scale() const { return value(WINOPTION_SCALE); }
- const char *screen_power() const { return value(WINOPTION_POWER); }
- const char *screen_floor() const { return value(WINOPTION_FLOOR); }
- const char *screen_phosphor() const { return value(WINOPTION_PHOSPHOR); }
- float screen_saturation() const { return float_value(WINOPTION_SATURATION); }
- int screen_chroma_mode() const { return int_value(WINOPTION_CHROMA_MODE); }
- const char *screen_chroma_a() const { return value(WINOPTION_CHROMA_A); }
- const char *screen_chroma_b() const { return value(WINOPTION_CHROMA_B); }
- const char *screen_chroma_c() const { return value(WINOPTION_CHROMA_C); }
- const char *screen_chroma_conversion_gain() const { return value(WINOPTION_CHROMA_CONVERSION_GAIN); }
- const char *screen_chroma_y_gain() const { return value(WINOPTION_CHROMA_Y_GAIN); }
- const char *screen_lut_texture() const { return value(WINOPTION_LUT_TEXTURE); }
- bool screen_lut_enable() const { return bool_value(WINOPTION_LUT_ENABLE); }
- const char *ui_lut_texture() const { return value(WINOPTION_UI_LUT_TEXTURE); }
- bool ui_lut_enable() const { return bool_value(WINOPTION_UI_LUT_ENABLE); }
-
- // full screen options
- bool triple_buffer() const { return bool_value(WINOPTION_TRIPLEBUFFER); }
- float full_screen_brightness() const { return float_value(WINOPTION_FULLSCREENBRIGHTNESS); }
- float full_screen_contrast() const { return float_value(WINOPTION_FULLSCREENCONTRAST); }
- float full_screen_gamma() const { return float_value(WINOPTION_FULLSCREENGAMMA); }
+#include "modules/lib/osdobj_common.h"
+#include "osdepend.h"
- // input options
- bool global_inputs() const { return bool_value(WINOPTION_GLOBAL_INPUTS); }
- bool dual_lightgun() const { return bool_value(WINOPTION_DUAL_LIGHTGUN); }
+#include <chrono>
+#include <vector>
- static const options_entry s_option_entries[];
-};
//============================================================
// TYPE DEFINITIONS
@@ -244,7 +28,10 @@ enum input_event
INPUT_EVENT_KEYDOWN,
INPUT_EVENT_KEYUP,
INPUT_EVENT_RAWINPUT,
- INPUT_EVENT_MOUSE_BUTTON
+ INPUT_EVENT_ARRIVAL,
+ INPUT_EVENT_REMOVAL,
+ INPUT_EVENT_MOUSE_BUTTON,
+ INPUT_EVENT_MOUSE_WHEEL
};
struct KeyPressEventArgs
@@ -254,24 +41,19 @@ struct KeyPressEventArgs
uint8_t scancode;
};
-struct MouseButtonEventArgs
+struct MouseUpdateEventArgs
{
- int button;
- int keydown;
+ unsigned pressed;
+ unsigned released;
+ int vdelta;
+ int hdelta;
int xpos;
int ypos;
};
-// Forward declarations
-struct _EXCEPTION_POINTERS;
class windows_osd_interface : public osd_common_t
{
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
- // Access to exception filter static method
- friend int main(int argc, char *argv[]);
-#endif
-
public:
// construction/destruction
windows_osd_interface(windows_options &options);
@@ -280,15 +62,15 @@ public:
// general overridables
virtual void init(running_machine &machine) override;
virtual void update(bool skip_redraw) override;
+ virtual void input_update(bool relative_reset) override;
+ virtual void check_osd_inputs() override;
// input overrideables
- virtual void customize_input_type_list(simple_list<input_type_entry> &typelist) override;
+ virtual void customize_input_type_list(std::vector<input_type_entry> &typelist) override;
// video overridables
virtual void add_audio_to_recording(const int16_t *buffer, int samples_this_frame) override;
- virtual void video_register() override;
-
virtual bool video_init() override;
virtual bool window_init() override;
@@ -297,65 +79,38 @@ public:
void extract_video_config();
- // windows osd specific
- bool handle_input_event(input_event eventid, void *eventdata) const;
+ // windows OSD specific
+ bool handle_input_event(input_event eventid, const void *eventdata) const;
bool should_hide_mouse() const;
- void poll_input(running_machine &machine) const;
+
+ virtual bool has_focus() const override;
+ virtual void process_events() override;
virtual windows_options &options() override { return m_options; }
int window_count();
-protected:
- virtual void build_slider_list() override;
- virtual void update_slider_list() override;
-
- void check_osd_inputs();
+ using osd_common_t::poll_input_modules; // Win32 debugger calls this directly, which it shouldn't
private:
+ void process_events(bool ingame, bool nodispatch);
virtual void osd_exit() override;
static void output_oslog(const char *buffer);
- windows_options & m_options;
+ windows_options &m_options;
+ bool const m_com_status;
- static const int DEFAULT_FONT_HEIGHT = 200;
-};
+ std::chrono::steady_clock::time_point m_last_event_check;
-#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-
-ref class MameMainApp sealed : public Windows::ApplicationModel::Core::IFrameworkView
-{
-private:
- std::unique_ptr<windows_options> m_options;
- std::unique_ptr<windows_osd_interface> m_osd;
-
-public:
- MameMainApp();
-
- // IFrameworkView Methods.
- virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView);
- virtual void SetWindow(Windows::UI::Core::CoreWindow^ window);
- virtual void Load(Platform::String^ entryPoint);
- virtual void Run();
- virtual void Uninitialize();
-};
-
-ref class MameViewSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource
-{
-public:
- virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView();
+ static inline constexpr int DEFAULT_FONT_HEIGHT = 200;
};
-#endif
//============================================================
// GLOBAL VARIABLES
//============================================================
-extern const options_entry mame_win_options[];
-
// defined in winwork.c
extern int osd_num_processors;
-
-#endif
+#endif // MAME_OSD_WINDOWS_WINMAIN_H
diff --git a/src/osd/windows/winmenu.cpp b/src/osd/windows/winmenu.cpp
deleted file mode 100644
index d55bd3e3a79..00000000000
--- a/src/osd/windows/winmenu.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
-//============================================================
-//
-// winmenu.cpp - Win32 OSD core dummy menu implementation
-//
-//============================================================
-
-// standard windows headers
-#include <windows.h>
-
-#include "emu.h"
-
-#include "window.h"
-
-//============================================================
-// winwindow_video_window_proc_ui
-// (window thread)
-//============================================================
-
-LRESULT CALLBACK winwindow_video_window_proc_ui(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam)
-{
- return win_window_info::video_window_proc(wnd, message, wparam, lparam);
-}
-
-//============================================================
-// win_create_menu
-//============================================================
-
-int win_create_menu(running_machine &machine, HMENU *menus)
-{
- return 0;
-}
diff --git a/src/osd/windows/winopts.cpp b/src/osd/windows/winopts.cpp
new file mode 100644
index 00000000000..0408593dda3
--- /dev/null
+++ b/src/osd/windows/winopts.cpp
@@ -0,0 +1,157 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+//============================================================
+//
+// winopts.cpp - Win32 options
+//
+//============================================================
+
+#include "winopts.h"
+
+
+namespace {
+
+//**************************************************************************
+// OPTIONS
+//**************************************************************************
+
+options_entry const f_win_option_entries[] =
+{
+ // performance options
+ { nullptr, nullptr, core_options::option_type::HEADER, "WINDOWS PERFORMANCE OPTIONS" },
+ { WINOPTION_PRIORITY "(-15-1)", "0", core_options::option_type::INTEGER, "thread priority for the main game thread; range from -15 to 1" },
+ { WINOPTION_PROFILE, "0", core_options::option_type::INTEGER, "enables profiling, specifying the stack depth to track" },
+
+ // video options
+ { nullptr, nullptr, core_options::option_type::HEADER, "WINDOWS VIDEO OPTIONS" },
+ { WINOPTION_ATTACH_WINDOW, "", core_options::option_type::STRING, "attach to arbitrary window" },
+
+ // post-processing options
+ { nullptr, nullptr, core_options::option_type::HEADER, "DIRECT3D POST-PROCESSING OPTIONS" },
+ { WINOPTION_HLSLPATH, "hlsl", core_options::option_type::PATH, "path to HLSL support files" },
+ { WINOPTION_HLSL_ENABLE";hlsl", "0", core_options::option_type::BOOLEAN, "enable HLSL post-processing (PS3.0 required)" },
+ { WINOPTION_HLSL_OVERSAMPLING, "0", core_options::option_type::BOOLEAN, "enable HLSL oversampling" },
+ { WINOPTION_HLSL_WRITE, OSDOPTVAL_AUTO, core_options::option_type::PATH, "enable HLSL AVI writing (huge disk bandwidth suggested)" },
+ { WINOPTION_HLSL_SNAP_WIDTH, "2048", core_options::option_type::STRING, "HLSL upscaled-snapshot width" },
+ { WINOPTION_HLSL_SNAP_HEIGHT, "1536", core_options::option_type::STRING, "HLSL upscaled-snapshot height" },
+ { WINOPTION_SHADOW_MASK_TILE_MODE, "0", core_options::option_type::INTEGER, "shadow mask tile mode (0 for screen based, 1 for source based)" },
+ { WINOPTION_SHADOW_MASK_ALPHA ";fs_shadwa(0.0-1.0)", "0.0", core_options::option_type::FLOAT, "shadow mask alpha-blend value (1.0 is fully blended, 0.0 is no mask)" },
+ { WINOPTION_SHADOW_MASK_TEXTURE ";fs_shadwt(0.0-1.0)", "shadow-mask.png", core_options::option_type::STRING, "shadow mask texture name" },
+ { WINOPTION_SHADOW_MASK_COUNT_X ";fs_shadww", "6", core_options::option_type::INTEGER, "shadow mask tile width, in screen dimensions" },
+ { WINOPTION_SHADOW_MASK_COUNT_Y ";fs_shadwh", "4", core_options::option_type::INTEGER, "shadow mask tile height, in screen dimensions" },
+ { WINOPTION_SHADOW_MASK_USIZE ";fs_shadwu(0.0-1.0)", "0.1875", core_options::option_type::FLOAT, "shadow mask texture width, in U/V dimensions" },
+ { WINOPTION_SHADOW_MASK_VSIZE ";fs_shadwv(0.0-1.0)", "0.25", core_options::option_type::FLOAT, "shadow mask texture height, in U/V dimensions" },
+ { WINOPTION_SHADOW_MASK_UOFFSET ";fs_shadwou(-1.0-1.0)", "0.0", core_options::option_type::FLOAT, "shadow mask texture offset, in U direction" },
+ { WINOPTION_SHADOW_MASK_VOFFSET ";fs_shadwov(-1.0-1.0)", "0.0", core_options::option_type::FLOAT, "shadow mask texture offset, in V direction" },
+ { WINOPTION_DISTORTION ";fs_dist(-1.0-1.0)", "0.0", core_options::option_type::FLOAT, "screen distortion amount" },
+ { WINOPTION_CUBIC_DISTORTION ";fs_cubedist(-1.0-1.0)", "0.0", core_options::option_type::FLOAT, "screen cubic distortion amount" },
+ { WINOPTION_DISTORT_CORNER ";fs_distc(0.0-1.0)", "0.0", core_options::option_type::FLOAT, "screen distort corner amount" },
+ { WINOPTION_ROUND_CORNER ";fs_rndc(0.0-1.0)", "0.0", core_options::option_type::FLOAT, "screen round corner amount" },
+ { WINOPTION_SMOOTH_BORDER ";fs_smob(0.0-1.0)", "0.0", core_options::option_type::FLOAT, "screen smooth border amount" },
+ { WINOPTION_REFLECTION ";fs_ref(0.0-1.0)", "0.0", core_options::option_type::FLOAT, "screen reflection amount" },
+ { WINOPTION_VIGNETTING ";fs_vig(0.0-1.0)", "0.0", core_options::option_type::FLOAT, "image vignetting amount" },
+ // Beam-related values below this line
+ { WINOPTION_SCANLINE_AMOUNT ";fs_scanam(0.0-4.0)", "0.0", core_options::option_type::FLOAT, "overall alpha scaling value for scanlines" },
+ { WINOPTION_SCANLINE_SCALE ";fs_scansc(0.0-4.0)", "1.0", core_options::option_type::FLOAT, "overall height scaling value for scanlines" },
+ { WINOPTION_SCANLINE_HEIGHT ";fs_scanh(0.0-4.0)", "1.0", core_options::option_type::FLOAT, "individual height scaling value for scanlines" },
+ { WINOPTION_SCANLINE_VARIATION ";fs_scanv(0.0-4.0)", "1.0", core_options::option_type::FLOAT, "individual height varying value for scanlines" },
+ { WINOPTION_SCANLINE_BRIGHT_SCALE ";fs_scanbs(0.0-2.0)", "1.0", core_options::option_type::FLOAT, "overall brightness scaling value for scanlines (multiplicative)" },
+ { WINOPTION_SCANLINE_BRIGHT_OFFSET ";fs_scanbo(0.0-1.0)", "0.0", core_options::option_type::FLOAT, "overall brightness offset value for scanlines (additive)" },
+ { WINOPTION_SCANLINE_JITTER ";fs_scanjt(0.0-4.0)", "0.0", core_options::option_type::FLOAT, "overall interlace jitter scaling value for scanlines" },
+ { WINOPTION_HUM_BAR_ALPHA ";fs_humba(0.0-1.0)", "0.0", core_options::option_type::FLOAT, "overall alpha scaling value for hum bar" },
+ { WINOPTION_DEFOCUS ";fs_focus", "0.0,0.0", core_options::option_type::STRING, "overall defocus value in screen-relative coords" },
+ { WINOPTION_CONVERGE_X ";fs_convx", "0.0,0.0,0.0", core_options::option_type::STRING, "convergence in screen-relative X direction" },
+ { WINOPTION_CONVERGE_Y ";fs_convy", "0.0,0.0,0.0", core_options::option_type::STRING, "convergence in screen-relative Y direction" },
+ { WINOPTION_RADIAL_CONVERGE_X ";fs_rconvx", "0.0,0.0,0.0", core_options::option_type::STRING, "radial convergence in screen-relative X direction" },
+ { WINOPTION_RADIAL_CONVERGE_Y ";fs_rconvy", "0.0,0.0,0.0", core_options::option_type::STRING, "radial convergence in screen-relative Y direction" },
+ // RGB colorspace convolution below this line
+ { WINOPTION_RED_RATIO ";fs_redratio", "1.0,0.0,0.0", core_options::option_type::STRING, "red output signal generated by input signal" },
+ { WINOPTION_GRN_RATIO ";fs_grnratio", "0.0,1.0,0.0", core_options::option_type::STRING, "green output signal generated by input signal" },
+ { WINOPTION_BLU_RATIO ";fs_bluratio", "0.0,0.0,1.0", core_options::option_type::STRING, "blue output signal generated by input signal" },
+ { WINOPTION_SATURATION ";fs_sat(0.0-4.0)", "1.0", core_options::option_type::FLOAT, "saturation scaling value" },
+ { WINOPTION_OFFSET ";fs_offset", "0.0,0.0,0.0", core_options::option_type::STRING, "signal offset value (additive)" },
+ { WINOPTION_SCALE ";fs_scale", "1.0,1.0,1.0", core_options::option_type::STRING, "signal scaling value (multiplicative)" },
+ { WINOPTION_POWER ";fs_power", "1.0,1.0,1.0", core_options::option_type::STRING, "signal power value (exponential)" },
+ { WINOPTION_FLOOR ";fs_floor", "0.0,0.0,0.0", core_options::option_type::STRING, "signal floor level" },
+ { WINOPTION_PHOSPHOR";fs_phosphor", "0.0,0.0,0.0", core_options::option_type::STRING, "phosphorescence decay rate (0.0 is instant, 1.0 is forever)" },
+ { WINOPTION_CHROMA_MODE, "3", core_options::option_type::INTEGER, "number of phosphors to use: 1 - monochrome, 2 - dichrome, 3 - trichrome (color)" },
+ { WINOPTION_CHROMA_CONVERSION_GAIN, "0.299,0.587,0.114", core_options::option_type::STRING, "gain to be applied when summing RGB signal for monochrome and dichrome modes" },
+ { WINOPTION_CHROMA_A, "0.64,0.33", core_options::option_type::STRING, "chromaticity coordinate for first phosphor" },
+ { WINOPTION_CHROMA_B, "0.30,0.60", core_options::option_type::STRING, "chromaticity coordinate for second phosphor" },
+ { WINOPTION_CHROMA_C, "0.15,0.06", core_options::option_type::STRING, "chromaticity coordinate for third phosphor" },
+ { WINOPTION_CHROMA_Y_GAIN, "0.2126,0.7152,0.0722", core_options::option_type::STRING, "gain to be applied for each phosphor" },
+ // NTSC simulation below this line
+ { nullptr, nullptr, core_options::option_type::HEADER, "NTSC POST-PROCESSING OPTIONS" },
+ { WINOPTION_YIQ_ENABLE ";yiq", "0", core_options::option_type::BOOLEAN, "enable YIQ-space HLSL post-processing" },
+ { WINOPTION_YIQ_JITTER ";yiqj", "0.0", core_options::option_type::FLOAT, "jitter for the NTSC signal processing" },
+ { WINOPTION_YIQ_CCVALUE ";yiqcc", "3.57954545", core_options::option_type::FLOAT, "color carrier frequency for NTSC signal processing" },
+ { WINOPTION_YIQ_AVALUE ";yiqa", "0.5", core_options::option_type::FLOAT, "A value for NTSC signal processing" },
+ { WINOPTION_YIQ_BVALUE ";yiqb", "0.5", core_options::option_type::FLOAT, "B value for NTSC signal processing" },
+ { WINOPTION_YIQ_OVALUE ";yiqo", "0.0", core_options::option_type::FLOAT, "outgoing Color Carrier phase offset for NTSC signal processing" },
+ { WINOPTION_YIQ_PVALUE ";yiqp", "1.0", core_options::option_type::FLOAT, "incoming Pixel Clock scaling value for NTSC signal processing" },
+ { WINOPTION_YIQ_NVALUE ";yiqn", "1.0", core_options::option_type::FLOAT, "Y filter notch width for NTSC signal processing" },
+ { WINOPTION_YIQ_YVALUE ";yiqy", "6.0", core_options::option_type::FLOAT, "Y filter cutoff frequency for NTSC signal processing" },
+ { WINOPTION_YIQ_IVALUE ";yiqi", "1.2", core_options::option_type::FLOAT, "I filter cutoff frequency for NTSC signal processing" },
+ { WINOPTION_YIQ_QVALUE ";yiqq", "0.6", core_options::option_type::FLOAT, "Q filter cutoff frequency for NTSC signal processing" },
+ { WINOPTION_YIQ_SCAN_TIME ";yiqsc", "52.6", core_options::option_type::FLOAT, "horizontal scanline duration for NTSC signal processing (microseconds)" },
+ { WINOPTION_YIQ_PHASE_COUNT ";yiqpc", "2", core_options::option_type::INTEGER, "phase count value for NTSC signal processing" },
+ // Vector simulation below this line
+ { nullptr, nullptr, core_options::option_type::HEADER, "VECTOR POST-PROCESSING OPTIONS" },
+ { WINOPTION_VECTOR_BEAM_SMOOTH ";vecsmooth", "0.0", core_options::option_type::FLOAT, "vector beam smoothness" },
+ { WINOPTION_VECTOR_LENGTH_SCALE ";vecscale", "0.5", core_options::option_type::FLOAT, "maximum vector attenuation" },
+ { WINOPTION_VECTOR_LENGTH_RATIO ";vecratio", "0.5", core_options::option_type::FLOAT, "minimum vector length affected by attenuation (vector length to screen size ratio)" },
+ // Bloom below this line
+ { nullptr, nullptr, core_options::option_type::HEADER, "BLOOM POST-PROCESSING OPTIONS" },
+ { WINOPTION_BLOOM_BLEND_MODE, "0", core_options::option_type::INTEGER, "bloom blend mode (0 for brighten, 1 for darken)" },
+ { WINOPTION_BLOOM_SCALE, "0.0", core_options::option_type::FLOAT, "intensity factor for bloom" },
+ { WINOPTION_BLOOM_OVERDRIVE, "1.0,1.0,1.0", core_options::option_type::STRING, "overdrive factor for bloom" },
+ { WINOPTION_BLOOM_LEVEL0_WEIGHT, "1.0", core_options::option_type::FLOAT, "bloom level 0 weight (full-size target)" },
+ { WINOPTION_BLOOM_LEVEL1_WEIGHT, "0.64", core_options::option_type::FLOAT, "bloom level 1 weight (1/4 smaller that level 0 target)" },
+ { WINOPTION_BLOOM_LEVEL2_WEIGHT, "0.32", core_options::option_type::FLOAT, "bloom level 2 weight (1/4 smaller that level 1 target)" },
+ { WINOPTION_BLOOM_LEVEL3_WEIGHT, "0.16", core_options::option_type::FLOAT, "bloom level 3 weight (1/4 smaller that level 2 target)" },
+ { WINOPTION_BLOOM_LEVEL4_WEIGHT, "0.08", core_options::option_type::FLOAT, "bloom level 4 weight (1/4 smaller that level 3 target)" },
+ { WINOPTION_BLOOM_LEVEL5_WEIGHT, "0.06", core_options::option_type::FLOAT, "bloom level 5 weight (1/4 smaller that level 4 target)" },
+ { WINOPTION_BLOOM_LEVEL6_WEIGHT, "0.04", core_options::option_type::FLOAT, "bloom level 6 weight (1/4 smaller that level 5 target)" },
+ { WINOPTION_BLOOM_LEVEL7_WEIGHT, "0.02", core_options::option_type::FLOAT, "bloom level 7 weight (1/4 smaller that level 6 target)" },
+ { WINOPTION_BLOOM_LEVEL8_WEIGHT, "0.01", core_options::option_type::FLOAT, "bloom level 8 weight (1/4 smaller that level 7 target)" },
+ { WINOPTION_LUT_TEXTURE, "lut-default.png", core_options::option_type::PATH, "3D LUT texture filename for screen, PNG format" },
+ { WINOPTION_LUT_ENABLE, "0", core_options::option_type::BOOLEAN, "Enables 3D LUT to be applied to screen after post-processing" },
+ { WINOPTION_UI_LUT_TEXTURE, "lut-default.png", core_options::option_type::PATH, "3D LUT texture filename of UI, PNG format" },
+ { WINOPTION_UI_LUT_ENABLE, "0", core_options::option_type::BOOLEAN, "enable 3D LUT to be applied to UI and artwork after post-processing" },
+
+ // full screen options
+ { nullptr, nullptr, core_options::option_type::HEADER, "FULL SCREEN OPTIONS" },
+ { WINOPTION_TRIPLEBUFFER ";tb", "0", core_options::option_type::BOOLEAN, "enable triple buffering" },
+ { WINOPTION_FULLSCREENBRIGHTNESS ";fsb(0.1-2.0)", "1.0", core_options::option_type::FLOAT, "brightness value in full screen mode" },
+ { WINOPTION_FULLSCREENCONTRAST ";fsc(0.1-2.0)", "1.0", core_options::option_type::FLOAT, "contrast value in full screen mode" },
+ { WINOPTION_FULLSCREENGAMMA ";fsg(0.1-3.0)", "1.0", core_options::option_type::FLOAT, "gamma value in full screen mode" },
+
+ // input options
+ { nullptr, nullptr, core_options::option_type::HEADER, "INPUT DEVICE OPTIONS" },
+ { WINOPTION_DUAL_LIGHTGUN ";dual", "0", core_options::option_type::BOOLEAN, "enable dual lightgun input" },
+
+ { nullptr }
+};
+
+} // anonymous namespace
+
+
+//============================================================
+// windows_options
+//============================================================
+
+windows_options::windows_options() : osd_options()
+{
+ add_entries(f_win_option_entries);
+}
+
+
+//============================================================
+// osd_setup_osd_specific_emu_options
+//============================================================
+
+void osd_setup_osd_specific_emu_options(emu_options &opts)
+{
+ opts.add_entries(osd_options::s_option_entries);
+ opts.add_entries(f_win_option_entries);
+}
diff --git a/src/osd/windows/winopts.h b/src/osd/windows/winopts.h
new file mode 100644
index 00000000000..44936f2d192
--- /dev/null
+++ b/src/osd/windows/winopts.h
@@ -0,0 +1,232 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+//============================================================
+//
+// winopts.h - Win32 options
+//
+//============================================================
+#ifndef MAME_OSD_WINDOWS_WINOPTS_H
+#define MAME_OSD_WINDOWS_WINOPTS_H
+
+#pragma once
+
+#include "modules/lib/osdobj_common.h"
+
+
+//============================================================
+// Option identifiers
+//============================================================
+
+// performance options
+#define WINOPTION_PRIORITY "priority"
+#define WINOPTION_PROFILE "profile"
+
+// video options
+#define WINOPTION_ATTACH_WINDOW "attach_window"
+
+// core post-processing options
+#define WINOPTION_HLSLPATH "hlslpath"
+#define WINOPTION_HLSL_ENABLE "hlsl_enable"
+#define WINOPTION_HLSL_OVERSAMPLING "hlsl_oversampling"
+#define WINOPTION_HLSL_WRITE "hlsl_write"
+#define WINOPTION_HLSL_SNAP_WIDTH "hlsl_snap_width"
+#define WINOPTION_HLSL_SNAP_HEIGHT "hlsl_snap_height"
+#define WINOPTION_SHADOW_MASK_TILE_MODE "shadow_mask_tile_mode"
+#define WINOPTION_SHADOW_MASK_ALPHA "shadow_mask_alpha"
+#define WINOPTION_SHADOW_MASK_TEXTURE "shadow_mask_texture"
+#define WINOPTION_SHADOW_MASK_COUNT_X "shadow_mask_x_count"
+#define WINOPTION_SHADOW_MASK_COUNT_Y "shadow_mask_y_count"
+#define WINOPTION_SHADOW_MASK_USIZE "shadow_mask_usize"
+#define WINOPTION_SHADOW_MASK_VSIZE "shadow_mask_vsize"
+#define WINOPTION_SHADOW_MASK_UOFFSET "shadow_mask_uoffset"
+#define WINOPTION_SHADOW_MASK_VOFFSET "shadow_mask_voffset"
+#define WINOPTION_REFLECTION "reflection"
+#define WINOPTION_DISTORTION "distortion"
+#define WINOPTION_CUBIC_DISTORTION "cubic_distortion"
+#define WINOPTION_DISTORT_CORNER "distort_corner"
+#define WINOPTION_ROUND_CORNER "round_corner"
+#define WINOPTION_SMOOTH_BORDER "smooth_border"
+#define WINOPTION_VIGNETTING "vignetting"
+#define WINOPTION_SCANLINE_AMOUNT "scanline_alpha"
+#define WINOPTION_SCANLINE_SCALE "scanline_size"
+#define WINOPTION_SCANLINE_HEIGHT "scanline_height"
+#define WINOPTION_SCANLINE_VARIATION "scanline_variation"
+#define WINOPTION_SCANLINE_BRIGHT_SCALE "scanline_bright_scale"
+#define WINOPTION_SCANLINE_BRIGHT_OFFSET "scanline_bright_offset"
+#define WINOPTION_SCANLINE_JITTER "scanline_jitter"
+#define WINOPTION_HUM_BAR_ALPHA "hum_bar_alpha"
+#define WINOPTION_DEFOCUS "defocus"
+#define WINOPTION_CONVERGE_X "converge_x"
+#define WINOPTION_CONVERGE_Y "converge_y"
+#define WINOPTION_RADIAL_CONVERGE_X "radial_converge_x"
+#define WINOPTION_RADIAL_CONVERGE_Y "radial_converge_y"
+#define WINOPTION_RED_RATIO "red_ratio"
+#define WINOPTION_GRN_RATIO "grn_ratio"
+#define WINOPTION_BLU_RATIO "blu_ratio"
+#define WINOPTION_OFFSET "offset"
+#define WINOPTION_SCALE "scale"
+#define WINOPTION_POWER "power"
+#define WINOPTION_FLOOR "floor"
+#define WINOPTION_PHOSPHOR "phosphor_life"
+#define WINOPTION_SATURATION "saturation"
+#define WINOPTION_CHROMA_MODE "chroma_mode"
+#define WINOPTION_CHROMA_CONVERSION_GAIN "chroma_conversion_gain"
+#define WINOPTION_CHROMA_A "chroma_a"
+#define WINOPTION_CHROMA_B "chroma_b"
+#define WINOPTION_CHROMA_C "chroma_c"
+#define WINOPTION_CHROMA_Y_GAIN "chroma_y_gain"
+#define WINOPTION_YIQ_ENABLE "yiq_enable"
+#define WINOPTION_YIQ_JITTER "yiq_jitter"
+#define WINOPTION_YIQ_CCVALUE "yiq_cc"
+#define WINOPTION_YIQ_AVALUE "yiq_a"
+#define WINOPTION_YIQ_BVALUE "yiq_b"
+#define WINOPTION_YIQ_OVALUE "yiq_o"
+#define WINOPTION_YIQ_PVALUE "yiq_p"
+#define WINOPTION_YIQ_NVALUE "yiq_n"
+#define WINOPTION_YIQ_YVALUE "yiq_y"
+#define WINOPTION_YIQ_IVALUE "yiq_i"
+#define WINOPTION_YIQ_QVALUE "yiq_q"
+#define WINOPTION_YIQ_SCAN_TIME "yiq_scan_time"
+#define WINOPTION_YIQ_PHASE_COUNT "yiq_phase_count"
+#define WINOPTION_VECTOR_BEAM_SMOOTH "vector_beam_smooth"
+#define WINOPTION_VECTOR_LENGTH_SCALE "vector_length_scale"
+#define WINOPTION_VECTOR_LENGTH_RATIO "vector_length_ratio"
+#define WINOPTION_BLOOM_BLEND_MODE "bloom_blend_mode"
+#define WINOPTION_BLOOM_SCALE "bloom_scale"
+#define WINOPTION_BLOOM_OVERDRIVE "bloom_overdrive"
+#define WINOPTION_BLOOM_LEVEL0_WEIGHT "bloom_lvl0_weight"
+#define WINOPTION_BLOOM_LEVEL1_WEIGHT "bloom_lvl1_weight"
+#define WINOPTION_BLOOM_LEVEL2_WEIGHT "bloom_lvl2_weight"
+#define WINOPTION_BLOOM_LEVEL3_WEIGHT "bloom_lvl3_weight"
+#define WINOPTION_BLOOM_LEVEL4_WEIGHT "bloom_lvl4_weight"
+#define WINOPTION_BLOOM_LEVEL5_WEIGHT "bloom_lvl5_weight"
+#define WINOPTION_BLOOM_LEVEL6_WEIGHT "bloom_lvl6_weight"
+#define WINOPTION_BLOOM_LEVEL7_WEIGHT "bloom_lvl7_weight"
+#define WINOPTION_BLOOM_LEVEL8_WEIGHT "bloom_lvl8_weight"
+#define WINOPTION_LUT_TEXTURE "lut_texture"
+#define WINOPTION_LUT_ENABLE "lut_enable"
+#define WINOPTION_UI_LUT_TEXTURE "ui_lut_texture"
+#define WINOPTION_UI_LUT_ENABLE "ui_lut_enable"
+
+// full screen options
+#define WINOPTION_TRIPLEBUFFER "triplebuffer"
+#define WINOPTION_FULLSCREENBRIGHTNESS "full_screen_brightness"
+#define WINOPTION_FULLSCREENCONTRAST "full_screen_contrast"
+#define WINOPTION_FULLSCREENGAMMA "full_screen_gamma"
+
+// input options
+#define WINOPTION_DUAL_LIGHTGUN "dual_lightgun"
+
+
+//============================================================
+// TYPE DEFINITIONS
+//============================================================
+
+class windows_options : public osd_options
+{
+public:
+ // construction/destruction
+ windows_options();
+
+ // performance options
+ int priority() const { return int_value(WINOPTION_PRIORITY); }
+ int profile() const { return int_value(WINOPTION_PROFILE); }
+
+ // video options
+ const char *attach_window() const { return value(WINOPTION_ATTACH_WINDOW); }
+
+ // core post-processing options
+ const char *screen_post_fx_dir() const { return value(WINOPTION_HLSLPATH); }
+ bool d3d_hlsl_enable() const { return bool_value(WINOPTION_HLSL_ENABLE); }
+ bool d3d_hlsl_oversampling() const { return bool_value(WINOPTION_HLSL_OVERSAMPLING); }
+ const char *d3d_hlsl_write() const { return value(WINOPTION_HLSL_WRITE); }
+ int d3d_snap_width() const { return int_value(WINOPTION_HLSL_SNAP_WIDTH); }
+ int d3d_snap_height() const { return int_value(WINOPTION_HLSL_SNAP_HEIGHT); }
+ int screen_shadow_mask_tile_mode() const { return int_value(WINOPTION_SHADOW_MASK_TILE_MODE); }
+ float screen_shadow_mask_alpha() const { return float_value(WINOPTION_SHADOW_MASK_ALPHA); }
+ const char *screen_shadow_mask_texture() const { return value(WINOPTION_SHADOW_MASK_TEXTURE); }
+ int screen_shadow_mask_count_x() const { return int_value(WINOPTION_SHADOW_MASK_COUNT_X); }
+ int screen_shadow_mask_count_y() const { return int_value(WINOPTION_SHADOW_MASK_COUNT_Y); }
+ float screen_shadow_mask_u_size() const { return float_value(WINOPTION_SHADOW_MASK_USIZE); }
+ float screen_shadow_mask_v_size() const { return float_value(WINOPTION_SHADOW_MASK_VSIZE); }
+ float screen_shadow_mask_u_offset() const { return float_value(WINOPTION_SHADOW_MASK_UOFFSET); }
+ float screen_shadow_mask_v_offset() const { return float_value(WINOPTION_SHADOW_MASK_VOFFSET); }
+ float screen_scanline_amount() const { return float_value(WINOPTION_SCANLINE_AMOUNT); }
+ float screen_scanline_scale() const { return float_value(WINOPTION_SCANLINE_SCALE); }
+ float screen_scanline_height() const { return float_value(WINOPTION_SCANLINE_HEIGHT); }
+ float screen_scanline_variation() const { return float_value(WINOPTION_SCANLINE_VARIATION); }
+ float screen_scanline_bright_scale() const { return float_value(WINOPTION_SCANLINE_BRIGHT_SCALE); }
+ float screen_scanline_bright_offset() const { return float_value(WINOPTION_SCANLINE_BRIGHT_OFFSET); }
+ float screen_scanline_jitter() const { return float_value(WINOPTION_SCANLINE_JITTER); }
+ float screen_hum_bar_alpha() const { return float_value(WINOPTION_HUM_BAR_ALPHA); }
+ float screen_reflection() const { return float_value(WINOPTION_REFLECTION); }
+ float screen_distortion() const { return float_value(WINOPTION_DISTORTION); }
+ float screen_cubic_distortion() const { return float_value(WINOPTION_CUBIC_DISTORTION); }
+ float screen_distort_corner() const { return float_value(WINOPTION_DISTORT_CORNER); }
+ float screen_round_corner() const { return float_value(WINOPTION_ROUND_CORNER); }
+ float screen_smooth_border() const { return float_value(WINOPTION_SMOOTH_BORDER); }
+ float screen_vignetting() const { return float_value(WINOPTION_VIGNETTING); }
+ const char *screen_defocus() const { return value(WINOPTION_DEFOCUS); }
+ const char *screen_converge_x() const { return value(WINOPTION_CONVERGE_X); }
+ const char *screen_converge_y() const { return value(WINOPTION_CONVERGE_Y); }
+ const char *screen_radial_converge_x() const { return value(WINOPTION_RADIAL_CONVERGE_X); }
+ const char *screen_radial_converge_y() const { return value(WINOPTION_RADIAL_CONVERGE_Y); }
+ const char *screen_red_ratio() const { return value(WINOPTION_RED_RATIO); }
+ const char *screen_grn_ratio() const { return value(WINOPTION_GRN_RATIO); }
+ const char *screen_blu_ratio() const { return value(WINOPTION_BLU_RATIO); }
+ bool screen_yiq_enable() const { return bool_value(WINOPTION_YIQ_ENABLE); }
+ float screen_yiq_jitter() const { return float_value(WINOPTION_YIQ_JITTER); }
+ float screen_yiq_cc() const { return float_value(WINOPTION_YIQ_CCVALUE); }
+ float screen_yiq_a() const { return float_value(WINOPTION_YIQ_AVALUE); }
+ float screen_yiq_b() const { return float_value(WINOPTION_YIQ_BVALUE); }
+ float screen_yiq_o() const { return float_value(WINOPTION_YIQ_OVALUE); }
+ float screen_yiq_p() const { return float_value(WINOPTION_YIQ_PVALUE); }
+ float screen_yiq_n() const { return float_value(WINOPTION_YIQ_NVALUE); }
+ float screen_yiq_y() const { return float_value(WINOPTION_YIQ_YVALUE); }
+ float screen_yiq_i() const { return float_value(WINOPTION_YIQ_IVALUE); }
+ float screen_yiq_q() const { return float_value(WINOPTION_YIQ_QVALUE); }
+ float screen_yiq_scan_time() const { return float_value(WINOPTION_YIQ_SCAN_TIME); }
+ int screen_yiq_phase_count() const { return int_value(WINOPTION_YIQ_PHASE_COUNT); }
+ float screen_vector_beam_smooth() const { return float_value(WINOPTION_VECTOR_BEAM_SMOOTH); }
+ float screen_vector_length_scale() const { return float_value(WINOPTION_VECTOR_LENGTH_SCALE); }
+ float screen_vector_length_ratio() const { return float_value(WINOPTION_VECTOR_LENGTH_RATIO); }
+ int screen_bloom_blend_mode() const { return int_value(WINOPTION_BLOOM_BLEND_MODE); }
+ float screen_bloom_scale() const { return float_value(WINOPTION_BLOOM_SCALE); }
+ const char *screen_bloom_overdrive() const { return value(WINOPTION_BLOOM_OVERDRIVE); }
+ float screen_bloom_lvl0_weight() const { return float_value(WINOPTION_BLOOM_LEVEL0_WEIGHT); }
+ float screen_bloom_lvl1_weight() const { return float_value(WINOPTION_BLOOM_LEVEL1_WEIGHT); }
+ float screen_bloom_lvl2_weight() const { return float_value(WINOPTION_BLOOM_LEVEL2_WEIGHT); }
+ float screen_bloom_lvl3_weight() const { return float_value(WINOPTION_BLOOM_LEVEL3_WEIGHT); }
+ float screen_bloom_lvl4_weight() const { return float_value(WINOPTION_BLOOM_LEVEL4_WEIGHT); }
+ float screen_bloom_lvl5_weight() const { return float_value(WINOPTION_BLOOM_LEVEL5_WEIGHT); }
+ float screen_bloom_lvl6_weight() const { return float_value(WINOPTION_BLOOM_LEVEL6_WEIGHT); }
+ float screen_bloom_lvl7_weight() const { return float_value(WINOPTION_BLOOM_LEVEL7_WEIGHT); }
+ float screen_bloom_lvl8_weight() const { return float_value(WINOPTION_BLOOM_LEVEL8_WEIGHT); }
+ const char *screen_offset() const { return value(WINOPTION_OFFSET); }
+ const char *screen_scale() const { return value(WINOPTION_SCALE); }
+ const char *screen_power() const { return value(WINOPTION_POWER); }
+ const char *screen_floor() const { return value(WINOPTION_FLOOR); }
+ const char *screen_phosphor() const { return value(WINOPTION_PHOSPHOR); }
+ float screen_saturation() const { return float_value(WINOPTION_SATURATION); }
+ int screen_chroma_mode() const { return int_value(WINOPTION_CHROMA_MODE); }
+ const char *screen_chroma_a() const { return value(WINOPTION_CHROMA_A); }
+ const char *screen_chroma_b() const { return value(WINOPTION_CHROMA_B); }
+ const char *screen_chroma_c() const { return value(WINOPTION_CHROMA_C); }
+ const char *screen_chroma_conversion_gain() const { return value(WINOPTION_CHROMA_CONVERSION_GAIN); }
+ const char *screen_chroma_y_gain() const { return value(WINOPTION_CHROMA_Y_GAIN); }
+ const char *screen_lut_texture() const { return value(WINOPTION_LUT_TEXTURE); }
+ bool screen_lut_enable() const { return bool_value(WINOPTION_LUT_ENABLE); }
+ const char *ui_lut_texture() const { return value(WINOPTION_UI_LUT_TEXTURE); }
+ bool ui_lut_enable() const { return bool_value(WINOPTION_UI_LUT_ENABLE); }
+
+ // full screen options
+ bool triple_buffer() const { return bool_value(WINOPTION_TRIPLEBUFFER); }
+ float full_screen_brightness() const { return float_value(WINOPTION_FULLSCREENBRIGHTNESS); }
+ float full_screen_contrast() const { return float_value(WINOPTION_FULLSCREENCONTRAST); }
+ float full_screen_gamma() const { return float_value(WINOPTION_FULLSCREENGAMMA); }
+
+ // input options
+ bool dual_lightgun() const { return bool_value(WINOPTION_DUAL_LIGHTGUN); }
+};
+
+#endif // MAME_OSD_WINDOWS_WINOPTS_H
diff --git a/src/osd/windows/winutf8.cpp b/src/osd/windows/winutf8.cpp
index a860aeb55cc..cdb0e87a86b 100644
--- a/src/osd/windows/winutf8.cpp
+++ b/src/osd/windows/winutf8.cpp
@@ -10,7 +10,7 @@
#include "winutf8.h"
#include "strconv.h"
-#include <stdlib.h>
+#include <cstdlib>
// standard windows headers
#include <shellapi.h>
@@ -27,8 +27,6 @@ void win_output_debug_string_utf8(const char *string)
}
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-
//============================================================
// win_message_box_utf8
//============================================================
@@ -55,9 +53,6 @@ int win_message_box_utf8(HWND window, const char *text, const char *caption, UIN
return MessageBox(window, t_text, t_caption, type);
}
-#endif
-
-
//============================================================
// win_set_window_text_utf8
@@ -75,13 +70,7 @@ BOOL win_set_window_text_utf8(HWND window, const char *text)
t_text = ts_text.c_str();
}
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
result = SetWindowText(window, t_text);
-#else
- Windows::UI::ViewManagement::ApplicationView::GetForCurrentView()->Title = ref new Platform::String(t_text);
- result = TRUE;
-#endif
-
return result;
}
@@ -93,30 +82,17 @@ BOOL win_set_window_text_utf8(HWND window, const char *text)
std::string win_get_window_text_utf8(HWND window)
{
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
- {
- // invoke the core Win32 API
- int length = GetWindowTextLength(window);
- if (length <= 0)
- return std::string();
-
- TCHAR *buffer = (TCHAR *) alloca((length + 1) * sizeof(TCHAR));
- GetWindowText(window, buffer, length + 1);
- return osd::text::from_tstring(buffer);
- }
-#else
- {
- TCHAR t_buffer[256];
- auto title = Windows::UI::ViewManagement::ApplicationView::GetForCurrentView()->Title;
- wcsncpy(t_buffer, title->Data(), ARRAY_LENGTH(t_buffer));
- return osd::text::from_tstring(t_buffer);
- }
-#endif
+ // invoke the core Win32 API
+ int length = GetWindowTextLength(window);
+ if (length <= 0)
+ return std::string();
+
+ auto *buffer = (TCHAR *) alloca((length + 1) * sizeof(TCHAR));
+ GetWindowText(window, buffer, length + 1);
+ return osd::text::from_tstring(buffer);
}
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-
//============================================================
// win_create_window_ex_utf8
//============================================================
@@ -138,5 +114,3 @@ HWND win_create_window_ex_utf8(DWORD exstyle, const char* classname, const char*
return CreateWindowEx(exstyle, ts_classname.c_str(), t_windowname, style, x, y, width, height, parent,
menu, instance, param);
}
-
-#endif
diff --git a/src/osd/windows/winutil.cpp b/src/osd/windows/winutil.cpp
index c06b4d2eee2..55b11f27522 100644
--- a/src/osd/windows/winutil.cpp
+++ b/src/osd/windows/winutil.cpp
@@ -6,17 +6,17 @@
//
//============================================================
-// standard windows headers
-#include <windows.h>
-#include <direct.h>
+#include "winutil.h"
-// MAME headers
-#include "emu.h"
+// lib/util
+#include "timeconv.h"
-// MAMEOS headers
-#include "winutil.h"
+// osd
#include "strconv.h"
-#include "timeconv.h"
+
+// standard windows headers
+#include <windows.h>
+#include <direct.h>
//============================================================
@@ -51,7 +51,7 @@ std::chrono::system_clock::time_point win_time_point_from_filetime(LPFILETIME fi
// win_is_gui_application
//============================================================
-BOOL win_is_gui_application(void)
+BOOL win_is_gui_application()
{
static BOOL is_gui_frontend;
static BOOL is_first_time = TRUE;
@@ -101,17 +101,22 @@ BOOL win_is_gui_application(void)
//============================================================
// osd_subst_env
//============================================================
-void osd_subst_env(std::string &dst, const std::string &src)
+std::string osd_subst_env(std::string_view src)
{
- TCHAR buffer[MAX_PATH];
-
- osd::text::tstring t_src = osd::text::to_tstring(src);
-#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)
- ExpandEnvironmentStrings(t_src.c_str(), buffer, ARRAY_LENGTH(buffer));
-#else
- wcsncpy(buffer, t_src.c_str(), ARRAY_LENGTH(buffer));
-#endif
- osd::text::from_tstring(dst, buffer);
+ std::wstring const w_src = osd::text::to_wstring(src);
+ std::vector<wchar_t> buffer(w_src.size() + 2);
+ DWORD length(ExpandEnvironmentStringsW(w_src.c_str(), &buffer[0], buffer.size()));
+ while (length && (buffer.size() < length))
+ {
+ buffer.clear();
+ buffer.resize(length + 1);
+ length = ExpandEnvironmentStringsW(w_src.c_str(), &buffer[0], buffer.size());
+ }
+
+ std::string dst;
+ if (length)
+ osd::text::from_wstring(dst, &buffer[0]);
+ return dst;
}
//-------------------------------------------------
@@ -120,7 +125,75 @@ void osd_subst_env(std::string &dst, const std::string &src)
HMODULE WINAPI GetModuleHandleUni()
{
- MEMORY_BASIC_INFORMATION mbi;
- VirtualQuery((LPCVOID)GetModuleHandleUni, &mbi, sizeof(mbi));
- return (HMODULE)mbi.AllocationBase;
+ HMODULE result = nullptr;
+ BOOL const succeeded = GetModuleHandleEx(
+ GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+ LPCWSTR(uintptr_t(&GetModuleHandleUni)),
+ &result);
+ return succeeded ? result : nullptr;
+}
+
+
+//============================================================
+// win_error_to_error_condition
+//============================================================
+
+std::error_condition win_error_to_error_condition(DWORD error) noexcept
+{
+ // TODO: work out if there's a better way to do this
+ switch (error)
+ {
+ case ERROR_SUCCESS:
+ return std::error_condition();
+
+ case ERROR_INVALID_HANDLE:
+ return std::errc::bad_file_descriptor;
+
+ case ERROR_OUTOFMEMORY:
+ return std::errc::not_enough_memory;
+
+ case ERROR_NOT_SUPPORTED:
+ return std::errc::not_supported;
+
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ case ERROR_INVALID_NAME:
+ return std::errc::no_such_file_or_directory;
+
+ case ERROR_FILENAME_EXCED_RANGE:
+ return std::errc::filename_too_long;
+
+ case ERROR_ACCESS_DENIED:
+ case ERROR_SHARING_VIOLATION:
+ return std::errc::permission_denied;
+
+ case ERROR_ALREADY_EXISTS:
+ return std::errc::file_exists;
+
+ case ERROR_TOO_MANY_OPEN_FILES:
+ return std::errc::too_many_files_open;
+
+ case ERROR_WRITE_FAULT:
+ case ERROR_READ_FAULT:
+ return std::errc::io_error;
+
+ case ERROR_HANDLE_DISK_FULL:
+ case ERROR_DISK_FULL:
+ return std::errc::no_space_on_device;
+
+ case ERROR_PATH_BUSY:
+ case ERROR_BUSY:
+ return std::errc::device_or_resource_busy;
+
+ case ERROR_FILE_TOO_LARGE:
+ return std::errc::file_too_large;
+
+ case ERROR_INVALID_ACCESS:
+ case ERROR_NEGATIVE_SEEK:
+ case ERROR_BAD_ARGUMENTS:
+ return std::errc::invalid_argument;
+
+ default:
+ return std::error_condition(error, std::system_category());
+ }
}
diff --git a/src/osd/windows/winutil.h b/src/osd/windows/winutil.h
index 57470bf1372..85393b6b930 100644
--- a/src/osd/windows/winutil.h
+++ b/src/osd/windows/winutil.h
@@ -6,18 +6,25 @@
//
//============================================================
-#ifndef __WINUTIL__
-#define __WINUTIL__
+#ifndef MAME_OSD_WINDOWS_WINUTIL_H
+#define MAME_OSD_WINDOWS_WINUTIL_H
+
+#pragma once
+
+#include "osdfile.h"
-#include "osdcore.h"
-#include <string>
-#include <vector>
#include <chrono>
+#include <system_error>
+
+#include <windows.h>
+
// Shared code
osd::directory::entry::entry_type win_attributes_to_entry_type(DWORD attributes);
std::chrono::system_clock::time_point win_time_point_from_filetime(LPFILETIME file_time);
-BOOL win_is_gui_application(void);
+BOOL win_is_gui_application();
HMODULE WINAPI GetModuleHandleUni();
-#endif // __WINUTIL__
+std::error_condition win_error_to_error_condition(DWORD error) noexcept;
+
+#endif // MAME_OSD_WINDOWS_WINUTIL_H