Merge pull request #2174 from RadWolfie/add-imgui

Add Basic ImGui Support
This commit is contained in:
PatrickvL 2021-04-04 21:08:09 +02:00 committed by GitHub
commit 52c88d7462
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 964 additions and 140 deletions

4
.gitmodules vendored
View File

@ -31,3 +31,7 @@
url = https://github.com/Cyan4973/xxHash.git
branch = release
shallow = true
[submodule "import/imgui"]
path = import/imgui
url = https://github.com/ocornut/imgui.git
shadow = true

View File

@ -35,8 +35,12 @@ add_custom_target(misc-batch
WORKING_DIRECTORY ${CXBXR_ROOT_DIR}
)
# Custom CMake projects since some import libraries doesn't have it.
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/projects/libtom")
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/projects/imgui")
# Split the files into group for which project is likely
# going to be used for both header and source files.
# Then move only specific project files into their
@ -109,6 +113,11 @@ file (GLOB CXBXR_HEADER_GUIv1
)
# Emulator (module)
file (GLOB CXBXR_HEADER_EMU_IMPORT
"${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_dx9.h"
"${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_opengl3.h"
"${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_win32.h"
)
file (GLOB CXBXR_HEADER_EMU
"${CXBXR_ROOT_DIR}/src/common/AddressRanges.h"
"${CXBXR_ROOT_DIR}/src/common/audio/converter.hpp"
@ -116,6 +125,11 @@ file (GLOB CXBXR_HEADER_EMU
"${CXBXR_ROOT_DIR}/src/common/util/gloffscreen/gloffscreen.h"
"${CXBXR_ROOT_DIR}/src/common/audio/XADPCM.h"
"${CXBXR_ROOT_DIR}/src/common/xbox/Logging.hpp"
"${CXBXR_ROOT_DIR}/src/core/common/imgui/audio.hpp"
"${CXBXR_ROOT_DIR}/src/core/common/imgui/ui.hpp"
"${CXBXR_ROOT_DIR}/src/core/common/imgui/settings.h"
"${CXBXR_ROOT_DIR}/src/core/common/imgui/video.hpp"
"${CXBXR_ROOT_DIR}/src/core/common/video/RenderBase.hpp"
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/CxbxVertexShaderTemplate.hlsl"
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/Direct3D9.h"
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/FixedFunctionVertexShader.hlsl"
@ -260,6 +274,11 @@ file (GLOB CXBXR_SOURCE_GUIv1
file (GLOB CXBXR_KRNL_CPP
"${CXBXR_ROOT_DIR}/src/core/kernel/init/CxbxKrnl.cpp"
)
file (GLOB CXBXR_SOURCE_EMU_IMPORT
"${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_dx9.cpp"
"${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_opengl3.cpp"
"${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_win32.cpp"
)
file (GLOB CXBXR_SOURCE_EMU
"${CXBXR_KRNL_CPP}"
"${CXBXR_ROOT_DIR}/src/common/AddressRanges.cpp"
@ -268,6 +287,10 @@ file (GLOB CXBXR_SOURCE_EMU
"${CXBXR_ROOT_DIR}/src/common/util/gloffscreen/gloffscreen_common.cpp"
"${CXBXR_ROOT_DIR}/src/common/util/gloffscreen/gloffscreen_wgl.cpp"
"${CXBXR_ROOT_DIR}/src/common/xbox/Logging.cpp"
"${CXBXR_ROOT_DIR}/src/core/common/imgui/audio.cpp"
"${CXBXR_ROOT_DIR}/src/core/common/imgui/ui.cpp"
"${CXBXR_ROOT_DIR}/src/core/common/imgui/video.cpp"
"${CXBXR_ROOT_DIR}/src/core/common/video/RenderBase.cpp"
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp"
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/RenderStates.cpp"
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/TextureStates.cpp"
@ -385,7 +408,7 @@ add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/projects/cxbxr-emu")
set(cxbxr_INSTALL_files "COPYING" "README.md")
# Cxbx-Reloaded project with third-party libraries
set_target_properties(cxbx cxbxr-ldr cxbxr-emu misc-batch subhook libXbSymbolDatabase libtommath libtomcrypt
set_target_properties(cxbx cxbxr-ldr cxbxr-emu misc-batch subhook libXbSymbolDatabase libtommath libtomcrypt imgui
PROPERTIES FOLDER Cxbx-Reloaded
)

1
import/imgui vendored Submodule

@ -0,0 +1 @@
Subproject commit 35b1148efb839381b84de9290d9caf0b66ad7d03

View File

@ -77,12 +77,20 @@ file (GLOB RESOURCES
"${CXBXR_ROOT_DIR}/src/.editorconfig"
)
source_group(TREE ${CXBXR_ROOT_DIR}/import PREFIX import FILES
${CXBXR_HEADER_EMU_IMPORT}
)
source_group(TREE ${CXBXR_ROOT_DIR}/src PREFIX header FILES
${CXBXR_HEADER_GUIv1}
${CXBXR_HEADER_COMMON}
${CXBXR_HEADER_EMU}
)
source_group(TREE ${CXBXR_ROOT_DIR}/import PREFIX import FILES
${CXBXR_SOURCE_EMU_IMPORT}
)
source_group(TREE ${CXBXR_ROOT_DIR}/src PREFIX source FILES
${CXBXR_SOURCE_GUIv1}
${CXBXR_SOURCE_COMMON}
@ -94,9 +102,11 @@ source_group(TREE ${CXBXR_ROOT_DIR} FILES ${RESOURCES})
add_executable(cxbx WIN32 ${RESOURCES}
${CXBXR_HEADER_GUIv1}
${CXBXR_HEADER_COMMON}
${CXBXR_HEADER_EMU_IMPORT}
${CXBXR_HEADER_EMU}
${CXBXR_SOURCE_GUIv1}
${CXBXR_SOURCE_COMMON}
${CXBXR_SOURCE_EMU_IMPORT}
${CXBXR_SOURCE_EMU}
${CXBXR_GIT_VERSION_H}
)
@ -181,6 +191,7 @@ target_link_libraries(cxbx
subhook
libtomcrypt
SDL2
imgui
${WINS_LIB}
)

View File

@ -68,6 +68,10 @@ file (GLOB RESOURCES
"${CXBXR_ROOT_DIR}/README.md"
)
source_group(TREE ${CXBXR_ROOT_DIR}/import PREFIX import FILES
${CXBXR_HEADER_EMU_IMPORT}
)
source_group(TREE ${CXBXR_ROOT_DIR}/src PREFIX header FILES
${CXBXR_HEADER_GUIv1}
${CXBXR_HEADER_COMMON}
@ -75,7 +79,11 @@ source_group(TREE ${CXBXR_ROOT_DIR}/src PREFIX header FILES
"${CXBXR_ROOT_DIR}/src/emulator/targetver.h"
)
source_group(TREE ${CXBXR_ROOT_DIR}/src PREFIX source FILES
source_group(TREE ${CXBXR_ROOT_DIR}/import PREFIX import FILES
${CXBXR_SOURCE_EMU_IMPORT}
)
source_group(TREE ${CXBXR_ROOT_DIR}/src PREFIX source FILES
${CXBXR_SOURCE_GUIv1}
${CXBXR_SOURCE_COMMON}
${CXBXR_SOURCE_EMU}
@ -87,9 +95,11 @@ source_group(TREE ${CXBXR_ROOT_DIR} FILES ${RESOURCES})
add_library(cxbxr-emu SHARED ${RESOURCES}
${CXBXR_HEADER_COMMON}
${CXBXR_HEADER_EMU_IMPORT}
${CXBXR_HEADER_EMU}
"${CXBXR_ROOT_DIR}/src/emulator/targetver.h"
${CXBXR_SOURCE_COMMON}
${CXBXR_SOURCE_EMU_IMPORT}
${CXBXR_SOURCE_EMU}
${CXBXR_GIT_VERSION_H}
"${CXBXR_ROOT_DIR}/src/emulator/cxbxr-emu.cpp"
@ -157,6 +167,7 @@ target_link_libraries(cxbxr-emu
subhook
libtomcrypt
SDL2
imgui
${WINS_LIB}
)

View File

@ -0,0 +1,42 @@
cmake_minimum_required (VERSION 3.8)
project(imgui LANGUAGES CXX)
# Since imgui doesn't have CMake, we'll make an interface project here.
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
add_compile_definitions(
_CRT_SECURE_NO_WARNINGS
_CRT_NONSTDC_NO_DEPRECATE
)
endif()
# Add any defines from imconfig.h file in here without need to edit import file directly.
add_compile_definitions(
IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
)
file (GLOB HEADERS
"${CXBXR_ROOT_DIR}/import/imgui/imconfig.h"
"${CXBXR_ROOT_DIR}/import/imgui/imgui.h"
"${CXBXR_ROOT_DIR}/import/imgui/imgui_internal.h"
"${CXBXR_ROOT_DIR}/import/imgui/imstb_rectpack.h"
"${CXBXR_ROOT_DIR}/import/imgui/imstb_textedit.h"
"${CXBXR_ROOT_DIR}/import/imgui/imstb_truetype.h"
)
file (GLOB SOURCES
"${CXBXR_ROOT_DIR}/import/imgui/imgui.cpp"
"${CXBXR_ROOT_DIR}/import/imgui/imgui_draw.cpp"
"${CXBXR_ROOT_DIR}/import/imgui/imgui_tables.cpp"
"${CXBXR_ROOT_DIR}/import/imgui/imgui_widgets.cpp"
)
source_group(TREE ${CXBXR_ROOT_DIR}/import/imgui PREFIX header FILES ${HEADERS})
source_group(TREE ${CXBXR_ROOT_DIR}/import/imgui PREFIX source FILES ${SOURCES})
add_library(${PROJECT_NAME} ${HEADERS} ${SOURCES})
target_include_directories(${PROJECT_NAME}
PUBLIC "${CXBXR_ROOT_DIR}/import/imgui"
)

View File

@ -38,6 +38,7 @@ typedef enum class _IPC_UPDATE_GUI {
, XBOX_LED_COLOUR
, LOG_ENABLED
, KRNL_IS_READY
, OVERLAY
} IPC_UPDATE_GUI;
void ipc_send_gui_update(IPC_UPDATE_GUI command, const unsigned int value);

View File

@ -112,6 +112,12 @@ static struct {
const char* RenderResolution = "RenderResolution";
} sect_video_keys;
static const char* section_overlay = "overlay";
static struct {
const char* FPS = "FPS";
const char* hle_lle_stats = "HLE/LLE Stats";
} sect_overlay_keys;
static const char* section_audio = "audio";
static struct {
const char* adapter = "adapter";
@ -452,7 +458,7 @@ bool Settings::LoadConfig()
m_input_general.MoAxisRange = m_si.GetLongValue(section_input_general, sect_input_general.mo_axis_range, MO_AXIS_DEFAULT_RANGE);
m_input_general.MoWheelRange = m_si.GetLongValue(section_input_general, sect_input_general.mo_wheel_range, MO_WHEEL_DEFAULT_RANGE);
m_input_general.IgnoreKbMoUnfocus = m_si.GetLongValue(section_input_general, sect_input_general.ignore_kbmo_unfocus, 1);
m_input_general.IgnoreKbMoUnfocus = m_si.GetBoolValue(section_input_general, sect_input_general.ignore_kbmo_unfocus, true);
// ==== Input General End ==============
@ -523,6 +529,13 @@ bool Settings::LoadConfig()
// ==== Input Profile End ======
// ==== Overlay Begin =========
m_overlay.fps = m_si.GetBoolValue(section_overlay, sect_overlay_keys.FPS, true);
m_overlay.hle_lle_stats = m_si.SetBoolValue(section_overlay, sect_overlay_keys.hle_lle_stats, true);
// ==== Overlay End ===========
return true;
}
@ -588,6 +601,7 @@ bool Settings::Save(std::string file_path)
m_si.SetBoolValue(section_video, sect_video_keys.FullScreen, m_video.bFullScreen, nullptr, true);
m_si.SetBoolValue(section_video, sect_video_keys.MaintainAspect, m_video.bMaintainAspect, nullptr, true);
m_si.SetLongValue(section_video, sect_video_keys.RenderResolution, m_video.renderScaleFactor, nullptr, false, true);
// ==== Video End ===========
// ==== Audio Begin =========
@ -617,7 +631,7 @@ bool Settings::Save(std::string file_path)
m_si.SetLongValue(section_input_general, sect_input_general.mo_axis_range, m_input_general.MoAxisRange, nullptr, false, true);
m_si.SetLongValue(section_input_general, sect_input_general.mo_wheel_range, m_input_general.MoWheelRange, nullptr, false, true);
m_si.SetLongValue(section_input_general, sect_input_general.ignore_kbmo_unfocus, m_input_general.IgnoreKbMoUnfocus, nullptr, false, true);
m_si.SetBoolValue(section_input_general, sect_input_general.ignore_kbmo_unfocus, m_input_general.IgnoreKbMoUnfocus, nullptr, true);
// ==== Input General End =========
@ -700,6 +714,13 @@ bool Settings::Save(std::string file_path)
// ==== Input Profile End ======
// ==== Overlay Begin =======
m_si.SetBoolValue(section_overlay, sect_overlay_keys.FPS, m_overlay.fps, nullptr, true);
m_si.SetBoolValue(section_overlay, sect_overlay_keys.hle_lle_stats, m_overlay.hle_lle_stats, nullptr, true);
// ==== Overlay End =========
// ==== Hack Begin ==========
m_si.SetBoolValue(section_hack, sect_hack_keys.DisablePixelShaders, m_hacks.DisablePixelShaders, nullptr, true);
@ -737,6 +758,7 @@ void Settings::SyncToEmulator()
// register Video settings
g_EmuShared->SetVideoSettings(&m_video);
g_EmuShared->SetOverlaySettings(&m_overlay);
// register Audio settings
g_EmuShared->SetAudioSettings(&m_audio);
@ -744,7 +766,7 @@ void Settings::SyncToEmulator()
// register Network settings
g_EmuShared->SetNetworkSettings(&m_network);
// register Input settings
// register xbox device input settings
for (int i = 0; i < 4; i++) {
g_EmuShared->SetInputDevTypeSettings(&m_input_port[i].Type, i);
if (m_input_port[i].Type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) {
@ -766,9 +788,8 @@ void Settings::SyncToEmulator()
}
}
g_EmuShared->SetInputMoAxisSettings(m_input_general.MoAxisRange);
g_EmuShared->SetInputMoWheelSettings(m_input_general.MoWheelRange);
g_EmuShared->SetInputKbMoUnfocusSettings(m_input_general.IgnoreKbMoUnfocus);
// register Input general settings
g_EmuShared->SetInputGeneralSettings(&m_input_general);
// register Hacks settings
g_EmuShared->SetHackSettings(&m_hacks);

View File

@ -34,6 +34,8 @@
#include <string>
#include <array>
#include "core/common/imgui/settings.h"
extern std::string g_exec_filepath;
// Individual library version
@ -134,12 +136,14 @@ public:
} m_audio;
static_assert(sizeof(s_audio) == 0x4C, assert_check_shared_memory(s_audio));
// Input general settings
struct s_input_general {
long MoAxisRange;
long MoWheelRange;
bool IgnoreKbMoUnfocus;
};
s_input_general m_input_general;
bool Reserved1[3];
} m_input_general;
static_assert(sizeof(s_input_general) == 0xC, assert_check_shared_memory(s_input_general));
struct s_input_port {
int Type;
@ -179,6 +183,8 @@ public:
} m_hacks;
static_assert(sizeof(s_hack) == 0x28, assert_check_shared_memory(s_hack));
overlay_settings m_overlay;
private:
void RemoveLegacyConfigs(unsigned int CurrentRevision);
std::string m_file_path = "";

View File

@ -45,6 +45,7 @@
#include "core\kernel\exports\EmuKrnl.h" // For EmuLog
#include "EmuShared.h"
#include "devices\usb\OHCI.h"
#include "core/common/video/RenderBase.hpp"
// hle input specific
#include "core\hle\XAPI\Xapi.h"
@ -360,8 +361,9 @@ bool InputDeviceManager::UpdateXboxPortInput(int usb_port, void* Buffer, int Dir
xid_type < to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX));
bool has_changed = false;
// First check if ImGui is focus, then ignore any input update occur.
// If somebody else is currently holding the lock, we won't wait and instead report no input changes
if (m_Mtx.try_lock()) {
if (static_cast<uint8_t>(!g_renderbase->IsImGuiFocus()) & static_cast<uint8_t>(m_Mtx.try_lock())) {
for (auto &dev_ptr : m_Devices) {
if (dev_ptr->GetPort(usb_port)) {
switch (xid_type)
@ -706,16 +708,13 @@ std::shared_ptr<InputDevice> InputDeviceManager::FindDevice(int usb_port, int du
void InputDeviceManager::UpdateOpt(bool is_gui)
{
if (!is_gui) {
long axis_range, wheel_range;
bool ignore_kbmo;
g_EmuShared->GetInputMoAxisSettings(&axis_range);
g_EmuShared->GetInputMoWheelSettings(&wheel_range);
g_EmuShared->GetInputKbMoUnfocusSettings(&ignore_kbmo);
DInput::mo_axis_range_pos = axis_range;
DInput::mo_wheel_range_pos = wheel_range;
DInput::mo_axis_range_neg = -(axis_range);
DInput::mo_wheel_range_neg = -(wheel_range);
DInput::IgnoreKbMoUnfocus = ignore_kbmo;
Settings::s_input_general input_general;
g_EmuShared->GetInputGeneralSettings(&input_general);
DInput::mo_axis_range_pos = input_general.MoAxisRange;
DInput::mo_wheel_range_pos = input_general.MoWheelRange;
DInput::mo_axis_range_neg = -(input_general.MoAxisRange);
DInput::mo_wheel_range_neg = -(input_general.MoWheelRange);
DInput::IgnoreKbMoUnfocus = input_general.IgnoreKbMoUnfocus;
}
else {
DInput::mo_axis_range_pos = g_Settings->m_input_general.MoAxisRange;

View File

@ -152,7 +152,6 @@ EmuShared::EmuShared()
m_bEmulating_status = false;
m_bFirstLaunch = false;
m_bClipCursor = false;
m_bIgnoreKbMoUnfocus = true;
// Reserve space (default to 0)
m_bReserved4 = false;
@ -162,6 +161,10 @@ EmuShared::EmuShared()
std::memset(m_Reserved99, 0, sizeof(m_Reserved99));
std::memset(m_DeviceControlNames, '\0', sizeof(m_DeviceControlNames));
std::memset(m_DeviceName, '\0', sizeof(m_DeviceName));
m_imgui_general.ini_size = IMGUI_INI_SIZE_MAX;
std::memset(&m_imgui_general.ini_settings, 0, sizeof(m_imgui_general.ini_settings));
std::memset(&m_imgui_audio_windows, 0, sizeof(m_imgui_audio_windows));
std::memset(&m_imgui_video_windows, 0, sizeof(m_imgui_video_windows));
for (auto& i : m_DeviceType) {
i = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID);
}

View File

@ -30,6 +30,7 @@
#include "Mutex.h"
#include "common\IPCHybrid.hpp"
#include "common\input\Button.h"
#include "core/common/imgui/settings.h"
#include <memory.h>
@ -152,12 +153,8 @@ class EmuShared : public Mutex
// ******************************************************************
// * Input option Accessors
// ******************************************************************
void GetInputMoAxisSettings(long *axis) { Lock(); *axis = m_MoAxisRange; Unlock(); }
void SetInputMoAxisSettings(const long axis) { Lock(); m_MoAxisRange = axis; Unlock(); }
void GetInputMoWheelSettings(long *wheel) { Lock(); *wheel = m_MoWheelRange; Unlock(); }
void SetInputMoWheelSettings(const long wheel) { Lock(); m_MoWheelRange = wheel; Unlock(); }
void GetInputKbMoUnfocusSettings(bool *flag) { Lock(); *flag = m_bIgnoreKbMoUnfocus; Unlock(); }
void SetInputKbMoUnfocusSettings(const bool flag) { Lock(); m_bIgnoreKbMoUnfocus = flag; Unlock(); }
void GetInputGeneralSettings(Settings::s_input_general *input_general) { Lock(); *input_general = m_input_general; Unlock(); }
void SetInputGeneralSettings(const Settings::s_input_general *input_general) { Lock(); m_input_general = *input_general; Unlock(); }
// ******************************************************************
// * LLE Flags Accessors
@ -200,7 +197,7 @@ class EmuShared : public Mutex
// * Debugging flag Accessors
// ******************************************************************
void GetDebuggingFlag(bool *value) { Lock(); *value = m_bDebugging; Unlock(); }
void SetDebuggingFlag(const bool *value) { Lock(); m_bDebugging = *value; Unlock(); }
void SetDebuggingFlag(const bool value) { Lock(); m_bDebugging = value; Unlock(); }
#ifndef CXBX_LOADER // Temporary usage for cxbx.exe's emu
// ******************************************************************
// * Previous Memory Layout value Accessors
@ -250,7 +247,44 @@ class EmuShared : public Mutex
// * ClipCursor flag Accessors
// ******************************************************************
void GetClipCursorFlag(bool *value) { Lock(); *value = m_bClipCursor; Unlock(); }
void SetClipCursorFlag(const bool *value) { Lock(); m_bClipCursor = *value; Unlock(); }
void SetClipCursorFlag(const bool value) { Lock(); m_bClipCursor = value; Unlock(); }
// ******************************************************************
// * ImGui Accessors
// ******************************************************************
void GetImGuiFocusFlag(bool *value) { Lock(); *value = m_imgui_general.is_focus; Unlock(); }
void SetImGuiFocusFlag(const bool value) { Lock(); m_imgui_general.is_focus = value; Unlock(); }
void GetImGuiIniSettings(char value[IMGUI_INI_SIZE_MAX]) {
Lock();
if (m_imgui_general.ini_size < IMGUI_INI_SIZE_MAX) {
value = '\0';
return;
}
strcpy_s(value, IMGUI_INI_SIZE_MAX, m_imgui_general.ini_settings);
Unlock();
}
void SetImGuiIniSettings(const char value[IMGUI_INI_SIZE_MAX]) {
Lock();
// Do not save if external size is less than internal limit
if (m_imgui_general.ini_size < IMGUI_INI_SIZE_MAX) {
return;
}
strcpy_s(m_imgui_general.ini_settings, IMGUI_INI_SIZE_MAX, value);
Unlock();
}
void GetImGuiAudioWindows(imgui_audio_windows *value) { Lock(); *value = m_imgui_audio_windows; Unlock(); }
void SetImGuiAudioWindows(const imgui_audio_windows* value) { Lock(); m_imgui_audio_windows = *value; Unlock(); }
void GetImGuiVideoWindows(imgui_video_windows*value) { Lock(); *value = m_imgui_video_windows; Unlock(); }
void SetImGuiVideoWindows(const imgui_video_windows* value) { Lock(); m_imgui_video_windows = *value; Unlock(); }
// ******************************************************************
// * Overlay Accessors
// ******************************************************************
void GetOverlaySettings(overlay_settings *value) { Lock(); *value = m_imgui_overlay_settings; Unlock(); }
void SetOverlaySettings(const overlay_settings* value) { Lock(); m_imgui_overlay_settings = *value; Unlock(); }
// ******************************************************************
// * Reset specific variables to default for kernel mode.
@ -301,15 +335,13 @@ class EmuShared : public Mutex
#endif
bool m_bFirstLaunch;
bool m_bClipCursor;
bool m_bIgnoreKbMoUnfocus;
bool m_bReserved3;
bool m_bReserved4;
unsigned int m_dwKrnlProcID; // Only used for kernel mode level.
int m_DeviceType[4];
char m_DeviceControlNames[4][HIGHEST_NUM_BUTTONS][HOST_BUTTON_NAME_LENGTH];
char m_DeviceName[4][50];
long m_MoAxisRange;
long m_MoWheelRange;
int m_Reserved99[26]; // Reserve space
int m_Reserved99[28]; // Reserve space
// Settings class in memory should not be tampered by third-party.
// Third-party program should only be allow to edit settings.ini file.
@ -317,7 +349,12 @@ class EmuShared : public Mutex
Settings::s_video m_video;
Settings::s_audio m_audio;
Settings::s_network m_network;
Settings::s_input_general m_input_general;
Settings::s_hack m_hacks;
imgui_general m_imgui_general;
overlay_settings m_imgui_overlay_settings;
imgui_audio_windows m_imgui_audio_windows;
imgui_video_windows m_imgui_video_windows;
};
// ******************************************************************

View File

@ -65,6 +65,10 @@ void ipc_send_gui_update(IPC_UPDATE_GUI command, const unsigned int value)
cmdParam = ID_GUI_STATUS_KRNL_IS_READY;
break;
case IPC_UPDATE_GUI::OVERLAY:
cmdParam = ID_GUI_STATUS_OVERLAY;
break;
default:
cmdParam = 0;
break;

View File

@ -0,0 +1,37 @@
// Copyright 2021 Cxbx-Reloaded Project
// Licensed under GPLv2+
// Refer to the COPYING file included.
#define LOG_PREFIX CXBXR_MODULE::GUI
#include <thread>
#include "audio.hpp"
#include "EmuShared.h"
bool ImGuiAudio::Initialize()
{
g_EmuShared->GetImGuiAudioWindows(&m_windows);
return true;
}
void ImGuiAudio::Shutdown()
{
g_EmuShared->SetImGuiAudioWindows(&m_windows);
}
void ImGuiAudio::DrawMenu()
{
if (ImGui::BeginMenu("Audio")) {
ImGui::MenuItem("Debug General Cache Stats", NULL, &m_windows.cache_stats_general);
ImGui::EndMenu();
}
}
void ImGuiAudio::DrawWidgets(bool is_focus, ImGuiWindowFlags input_handler)
{
//TODO: In need of make interface class to return generic info in some way.
extern void DSound_PrintStats(bool, ImGuiWindowFlags, bool m_show_audio_stats);
DSound_PrintStats(is_focus, input_handler, m_windows.cache_stats_general);
}

View File

@ -0,0 +1,24 @@
// Copyright 2021 Cxbx-Reloaded Project
// Licensed under GPLv2+
// Refer to the COPYING file included.
#pragma once
#include <imgui.h>
#include "settings.h"
class ImGuiAudio
{
public:
ImGuiAudio() = default;
virtual ~ImGuiAudio() = default;
bool Initialize();
void Shutdown();
void DrawMenu();
void DrawWidgets(bool is_focus, ImGuiWindowFlags input_handler);
protected:
imgui_audio_windows m_windows;
};

View File

@ -0,0 +1,53 @@
// ******************************************************************
// *
// * This file is part of the Cxbx-Reloaded project.
// *
// * Cxbx and Cxbe are free software; you can redistribute them
// * and/or modify them under the terms of the GNU General Public
// * License as published by the Free Software Foundation; either
// * version 2 of the license, or (at your option) any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// * GNU General Public License for more details.
// *
// * You should have recieved a copy of the GNU General Public License
// * along with this program; see the file COPYING.
// * If not, write to the Free Software Foundation, Inc.,
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
// *
// * (c) 2021 RadWolfie
// *
// * All rights reserved
// *
// ******************************************************************
#pragma once
// Intended to store as permanent settings
typedef struct {
bool fps;
bool hle_lle_stats;
} overlay_settings;
// Intended for EmuShared only below
const int IMGUI_INI_SIZE_MAX = 1024;
typedef struct {
bool is_focus;
bool Reserved[3];
int ini_size; // Cannot be touch anywhere except EmuShared's constructor.
char ini_settings[IMGUI_INI_SIZE_MAX];
} imgui_general;
typedef struct {
bool cache_stats_general;
bool Reserved[3];
} imgui_audio_windows;
typedef struct {
bool cache_stats_vertex;
bool Reserved[3];
} imgui_video_windows;

View File

@ -0,0 +1,160 @@
// Copyright 2021 Cxbx-Reloaded Project
// Licensed under GPLv2+
// Refer to the COPYING file included.
//
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the COPYING file included.
#define LOG_PREFIX CXBXR_MODULE::GUI
#include <thread>
#include "ui.hpp"
#include "EmuShared.h"
#include "core/kernel/init/CxbxKrnl.h"
bool ImGuiUI::Initialize()
{
IMGUI_CHECKVERSION();
m_imgui_context = ImGui::CreateContext();
if (!m_imgui_context) {
CxbxKrnlCleanup("Unable to create ImGui context!");
return false;
}
ImGuiIO& io = ImGui::GetIO();
#if 0 // TODO: Currently most voted for memory, so this block of code is disabled. And may will add an option between file vs memory.
// May be best ideal to do manual update call than ImGui's internal auto update.
g_EmuShared->GetStorageLocation(m_file_path);
if (m_file_path[0] == '\0') {
return false;
}
strcat_s(m_file_path, "/imgui.ini");
io.IniFilename = m_file_path;
#else
io.IniFilename = nullptr;
char temp_ini_settings[IMGUI_INI_SIZE_MAX];
g_EmuShared->GetImGuiIniSettings(temp_ini_settings);
ImGui::LoadIniSettingsFromMemory(temp_ini_settings, IMGUI_INI_SIZE_MAX);
#endif
ImGui::StyleColorsDark();
g_EmuShared->GetImGuiFocusFlag(&m_is_focus);
g_EmuShared->GetOverlaySettings(&m_settings);
g_EmuShared->GetFlagsLLE(&m_lle_flags);
m_audio.Initialize();
m_video.Initialize();
return true;
}
void ImGuiUI::Shutdown()
{
size_t ini_size = IMGUI_INI_SIZE_MAX;
const char* temp_ini_settings = ImGui::SaveIniSettingsToMemory(&ini_size);
if (ini_size > IMGUI_INI_SIZE_MAX) {
CxbxKrnlCleanup("ImGui ini settings is too large: %d > %d (IMGUI_INI_SIZE_MAX)", ini_size, IMGUI_INI_SIZE_MAX);
}
g_EmuShared->SetImGuiIniSettings(temp_ini_settings);
g_EmuShared->SetOverlaySettings(&m_settings);
m_audio.Shutdown();
m_video.Shutdown();
ImGui::DestroyContext(m_imgui_context);
}
bool ImGuiUI::IsImGuiFocus()
{
return m_is_focus;
}
void ImGuiUI::ToggleImGui()
{
m_is_focus = !m_is_focus;
g_EmuShared->SetImGuiFocusFlag(m_is_focus);
}
void ImGuiUI::DrawMenu()
{
if (!m_is_focus) {
return;
}
if (ImGui::BeginMainMenuBar()) {
if (ImGui::BeginMenu("Settings")) {
if (ImGui::BeginMenu("Overlay")) {
bool bChanged = false;
bChanged |= ImGui::MenuItem("Show FPS", NULL, &m_settings.fps);
bChanged |= ImGui::MenuItem("Show HLE/LLE Stats", NULL, &m_settings.hle_lle_stats);
if (bChanged) {
g_EmuShared->SetOverlaySettings(&m_settings);
ipc_send_gui_update(IPC_UPDATE_GUI::OVERLAY, 1);
}
ImGui::EndMenu();
}
ImGui::EndMenu();
}
m_video.DrawMenu();
m_audio.DrawMenu();
ImGui::EndMainMenuBar();
}
}
void ImGuiUI::DrawWidgets()
{
if (m_settings.fps || m_settings.hle_lle_stats) {
ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x - (IMGUI_MIN_DIST_SIDE/* * m_backbuffer_scale*/),
IMGUI_MIN_DIST_TOP/* * m_backbuffer_scale*/), ImGuiCond_Always, ImVec2(1.0f, 0.0f));
ImGui::SetNextWindowSize(ImVec2(200.0f/* * m_backbuffer_scale*/, 0.0f));
ImGui::SetNextWindowBgAlpha(0.5f);
if (ImGui::Begin("overlay_stats", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoNav |
ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoScrollbar |
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing)) {
if (m_settings.fps) {
float fps_counter;
g_EmuShared->GetCurrentFPS(&fps_counter);
ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "FPS: %.2f MS / F : %.2f", fps_counter, (float)(1000.0 / fps_counter));
}
if (m_settings.hle_lle_stats) {
std::string flagString = "LLE-";
// TODO: Need improvement in upstream for all of bLLE_xxx globals
// Set LLE flags string based on selected LLE flags
if (m_lle_flags & LLE_APU) {
flagString.append("A");
}
if (m_lle_flags & LLE_GPU) {
flagString.append("G");
}
if (m_lle_flags & LLE_USB) {
flagString.append("U");
}
if (m_lle_flags & LLE_JIT) {
flagString.append("J");
}
if (m_lle_flags == 0) {
flagString = "HLE";
}
// Align text to the right
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetWindowWidth() - ImGui::CalcTextSize(flagString.c_str()).x
- ImGui::GetScrollX() - 2 * ImGui::GetStyle().ItemSpacing.x);
ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), flagString.c_str());
}
ImGui::End();
}
}
ImGuiWindowFlags input_handler = m_is_focus ? ImGuiWindowFlags_None : ImGuiWindowFlags_NoInputs;
m_video.DrawWidgets(m_is_focus, input_handler);
m_audio.DrawWidgets(m_is_focus, input_handler);
}

View File

@ -0,0 +1,67 @@
// Copyright 2021 Cxbx-Reloaded Project
// Licensed under GPLv2+
// Refer to the COPYING file included.
//
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the COPYING file included.
#pragma once
#include <imgui.h>
#include <mutex>
#include <functional>
#include "settings.h"
#include "audio.hpp"
#include "video.hpp"
constexpr float IMGUI_MIN_DIST_TOP = 20.0f;
constexpr float IMGUI_MIN_DIST_SIDE = 1.0f;
class ImGuiUI
{
public:
ImGuiUI() = default;
virtual ~ImGuiUI() = default;
void ToggleImGui();
bool IsImGuiFocus();
void DrawMenu();
void DrawWidgets();
protected:
bool Initialize();
void Shutdown();
template<class C, class T>
void Render(C callback, T arg)
{
// Some games seem to call Swap concurrently, so we need to ensure only one thread
// at a time can render ImGui
std::unique_lock lock(m_imgui_mutex, std::try_to_lock);
if (!lock) return;
callback(this, arg);
}
std::mutex m_imgui_mutex;
ImGuiContext* m_imgui_context;
char m_file_path[FILENAME_MAX+1];
bool m_is_focus;
// Using as their own member than integrate may be helpful to bind different plugin at latter change?
ImGuiAudio m_audio;
ImGuiVideo m_video;
overlay_settings m_settings;
unsigned int m_lle_flags;
// Make them as settings storage.
/*bool m_show_fps;
bool m_show_LLE_stats;
// Make them as memory storage.
bool m_show_vertex_stats;
bool m_show_audio_stats;
*/
};

View File

@ -0,0 +1,49 @@
// Copyright 2021 Cxbx-Reloaded Project
// Licensed under GPLv2+
// Refer to the COPYING file included.
#define LOG_PREFIX CXBXR_MODULE::GUI
#include <thread>
#include "video.hpp"
#include "ui.hpp"
#include "EmuShared.h"
#include "core/kernel/init/CxbxKrnl.h"
#include "core/hle/D3D8/XbVertexBuffer.h"
bool ImGuiVideo::Initialize()
{
g_EmuShared->GetImGuiVideoWindows(&m_windows);
return true;
}
void ImGuiVideo::Shutdown()
{
g_EmuShared->SetImGuiVideoWindows(&m_windows);
}
void ImGuiVideo::DrawMenu()
{
if (ImGui::BeginMenu("Video")) {
ImGui::MenuItem("Debug Vertex Buffer Cache Stats", NULL, &m_windows.cache_stats_vertex);
ImGui::EndMenu();
}
}
void ImGuiVideo::DrawWidgets(bool is_focus, ImGuiWindowFlags input_handler)
{
// Render vertex buffer cache stats
if (m_windows.cache_stats_vertex) {
ImGui::SetNextWindowPos(ImVec2(IMGUI_MIN_DIST_SIDE, IMGUI_MIN_DIST_TOP), ImGuiCond_FirstUseEver, ImVec2(0.0f, 0.0f));
ImGui::SetNextWindowSize(ImVec2(200, 275), ImGuiCond_FirstUseEver);
if (ImGui::Begin("Debugging stats", nullptr, input_handler | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
if (ImGui::CollapsingHeader("Vertex Buffer Cache", ImGuiTreeNodeFlags_DefaultOpen)) {
VertexBufferConverter.DrawCacheStats();
}
ImGui::End();
}
}
}

View File

@ -0,0 +1,23 @@
// Copyright 2021 Cxbx-Reloaded Project
// Licensed under GPLv2+
// Refer to the COPYING file included.
#pragma once
#include <imgui.h>
#include "settings.h"
class ImGuiVideo
{
public:
ImGuiVideo() = default;
virtual ~ImGuiVideo() = default;
bool Initialize();
void Shutdown();
void DrawMenu();
void DrawWidgets(bool is_focus, ImGuiWindowFlags input_handler);
protected:
imgui_video_windows m_windows;
};

View File

@ -0,0 +1,35 @@
// Copyright 2021 Cxbx-Reloaded Project
// Licensed under GPLv2+
// Refer to the COPYING file included.
//
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the COPYING file included.
//#define LOG_PREFIX CXBXR_MODULE::GUI
#include <thread>
#include "RenderBase.hpp"
//#include "core/kernel/init/CxbxKrnl.h"
std::unique_ptr<RenderBase> g_renderbase;
bool RenderBase::Initialize()
{
if (!ImGuiUI::Initialize()) {
return false;
}
return true;
}
void RenderBase::Shutdown()
{
DeviceRelease();
m_device_release = std::function<void()>{};
WindowRelease();
m_window_release = std::function<void()>{};
ImGuiUI::Shutdown();
}

View File

@ -0,0 +1,51 @@
// Copyright 2021 Cxbx-Reloaded Project
// Licensed under GPLv2+
// Refer to the COPYING file included.
//
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the COPYING file included.
#pragma once
#include "../imgui/ui.hpp"
class RenderBase : public ImGuiUI
{
public:
RenderBase() = default;
virtual ~RenderBase() = default;
virtual bool Initialize();
virtual void Shutdown();
template<class C, class T>
void Render(std::function<void(C, T)> callback, T arg)
{
ImGuiUI::Render(callback, arg);
}
// When video backends has its own class, make DeviceRelease call as virtual requirement for parent class usage.
void SetDeviceRelease(const std::function<void()>& func_register) {
m_device_release = func_register;
}
void DeviceRelease() {
m_device_release();
}
void SetWindowRelease(const std::function<void()>& func_register) {
m_window_release = func_register;
}
void WindowRelease() {
m_window_release();
}
protected:
std::function<void()> m_device_release;
std::function<void()> m_window_release;
};
extern std::unique_ptr<RenderBase> g_renderbase;

View File

@ -61,6 +61,11 @@
#include "common/util/strConverter.hpp" // for utf8_to_utf16
#include "VertexShaderSource.h"
#include <imgui.h>
#include <backends/imgui_impl_dx9.h>
#include <backends/imgui_impl_win32.h>
#include "core/common/video/RenderBase.hpp"
#include <assert.h>
#include <process.h>
#include <clocale>
@ -123,8 +128,6 @@ static size_t g_QuadToTriangleHostIndexBuffer_Size = 0; //
static INDEX16 *g_pQuadToTriangleIndexData = nullptr;
static size_t g_QuadToTriangleIndexData_Size = 0; // = NrOfQuadIndices
static CxbxVertexBufferConverter VertexBufferConverter = {};
struct {
xbox::X_D3DSurface Surface;
RECT SrcRect;
@ -181,6 +184,31 @@ float g_Xbox_BackbufferScaleY = 1;
static constexpr size_t INDEX_BUFFER_CACHE_SIZE = 10000;
static void CxbxImGui_RenderD3D9(ImGuiUI* m_imgui, IDirect3DSurface9* renderTarget)
{
ImGui_ImplDX9_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
m_imgui->DrawMenu();
m_imgui->DrawWidgets();
ImGui::EndFrame();
ImGui::Render();
ImDrawData* drawData = ImGui::GetDrawData();
if (drawData->TotalVtxCount > 0) {
IDirect3DSurface9* pExistingRenderTarget = nullptr;
if (SUCCEEDED(g_pD3DDevice->GetRenderTarget(0, &pExistingRenderTarget))) {
g_pD3DDevice->SetRenderTarget(0, renderTarget);
ImGui_ImplDX9_RenderDrawData(drawData);
g_pD3DDevice->SetRenderTarget(0, pExistingRenderTarget);
pExistingRenderTarget->Release();
}
}
}
/* Unused :
static xbox::dword_xt *g_Xbox_D3DDevice; // TODO: This should be a D3DDevice structure
*/
@ -633,6 +661,13 @@ void CxbxInitWindow(bool bFullInit)
}
SetFocus(g_hEmuWindow);
g_renderbase = std::unique_ptr<RenderBase>(new RenderBase());
g_renderbase->Initialize();
ImGui_ImplWin32_Init(g_hEmuWindow);
g_renderbase->SetWindowRelease([] {
ImGui_ImplWin32_Shutdown();
});
}
void DrawUEM(HWND hWnd)
@ -709,6 +744,27 @@ void CxbxReleaseCursor()
ClipCursor(nullptr);
}
static void CxbxUpdateCursor(bool forceShow = false) {
// Getting cursor info is a requirement in order to prevent a bug occur with ShowCursor redundant calls.
CURSORINFO cursorInfo;
cursorInfo.cbSize = sizeof(cursorInfo);
if (!GetCursorInfo(&cursorInfo)) {
// If cursor info is not available, then ignore the cursor update.
return;
}
if (g_renderbase->IsImGuiFocus() || forceShow) {
if (cursorInfo.flags == 0) {
ShowCursor(TRUE);
}
}
else {
if ((cursorInfo.flags & CURSOR_SHOWING) != 0) {
ShowCursor(FALSE);
}
}
}
inline DWORD GetXboxCommonResourceType(const xbox::dword_xt XboxResource_Common)
{
DWORD dwCommonType = XboxResource_Common & X_D3DCOMMON_TYPE_MASK;
@ -1804,11 +1860,16 @@ void ToggleFauxFullscreen(HWND hWnd)
g_bIsFauxFullscreen = !g_bIsFauxFullscreen;
}
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
// rendering window message procedure
static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static bool bAutoPaused = false;
const LRESULT imguiResult = ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam);
if (imguiResult != 0) return imguiResult;
switch(msg)
{
case WM_DESTROY:
@ -1900,10 +1961,8 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar
}
else if (wParam == VK_F1)
{
VertexBufferConverter.PrintStats();
extern void DSound_PrintStats(); //TODO: move into plugin class usage.
DSound_PrintStats();
g_renderbase->ToggleImGui();
CxbxUpdateCursor();
}
else if (wParam == VK_F2)
{
@ -1912,7 +1971,7 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar
else if (wParam == VK_F3)
{
g_bClipCursor = !g_bClipCursor;
g_EmuShared->SetClipCursorFlag(&g_bClipCursor);
g_EmuShared->SetClipCursorFlag(g_bClipCursor);
if (g_bClipCursor) {
CxbxClipCursor(hWnd);
@ -2007,7 +2066,7 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar
DInput::mo_leave_wnd = true;
g_bIsTrackingMoLeave = false;
g_bIsTrackingMoMove = true;
ShowCursor(TRUE);
CxbxUpdateCursor(true);
}
break;
@ -2024,7 +2083,7 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar
tme.dwFlags = TME_LEAVE;
TrackMouseEvent(&tme);
g_bIsTrackingMoLeave = true;
ShowCursor(FALSE);
CxbxUpdateCursor();
if (g_bIsTrackingMoMove) {
DInput::mo_leave_wnd = false;
@ -2037,7 +2096,7 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar
case WM_CLOSE:
CxbxReleaseCursor();
DestroyWindow(hWnd);
CxbxKrnlShutDown();
CxbxKrnlShutDown();
break;
case WM_SETFOCUS:
@ -2056,7 +2115,6 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar
SetCursor(NULL);
return S_OK; // = Is not part of D3D8 handling.
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
break;
@ -2351,7 +2409,8 @@ static void CreateDefaultD3D9Device
// Final release of IDirect3DDevice9 must be called from the window message thread
// See https://docs.microsoft.com/en-us/windows/win32/direct3d9/multithreading-issues
RunOnWndMsgThread([] {
g_pD3DDevice->Release();
// We only need to call bundled device release once here.
g_renderbase->DeviceRelease();
});
}
@ -2449,6 +2508,13 @@ static void CreateDefaultD3D9Device
// Set up cache
g_VertexShaderSource.ResetD3DDevice(g_pD3DDevice);
// Set up ImGui's render backend
ImGui_ImplDX9_Init(g_pD3DDevice);
g_renderbase->SetDeviceRelease([] {
ImGui_ImplDX9_Shutdown();
g_pD3DDevice->Release();
});
}
@ -5348,6 +5414,10 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(D3DDevice_Swap)
}
}
// Render ImGui
static std::function<void(ImGuiUI*, IDirect3DSurface*)> internal_render = &CxbxImGui_RenderD3D9;
g_renderbase->Render(internal_render, pCurrentHostBackBuffer);
pCurrentHostBackBuffer->Release();
}

View File

@ -1,7 +1,7 @@
#ifndef WALKINDEXBUFFER_H
#define WALKINDEXBUFFER_H
#include "core\kernel\support\Emu.h"
#include "core/hle/D3D8/XbD3D8Types.h"
extern void(*WalkIndexBuffer)
(

View File

@ -83,6 +83,8 @@
#define IDirect3DSwapChain IDirect3DSwapChain9
#define IDirect3DQuery IDirect3DQuery9
typedef xbox::word_xt INDEX16; // TODO: Move INDEX16 into xbox namespace
namespace xbox {
// TODO : Declare these aliasses as Xbox type

View File

@ -38,12 +38,16 @@
#include "core\hle\D3D8\XbVertexBuffer.h"
#include "core\hle\D3D8\XbConvert.h"
#include <imgui.h>
#include <ctime>
#include <chrono>
#include <algorithm>
#define MAX_STREAM_NOT_USED_TIME (2 * CLOCKS_PER_SEC) // TODO: Trim the not used time
CxbxVertexBufferConverter VertexBufferConverter = {};
// Inline vertex buffer emulation
xbox::X_D3DPRIMITIVETYPE g_InlineVertexBuffer_PrimitiveType = xbox::X_D3DPT_INVALID;
uint32_t g_InlineVertexBuffer_WrittenRegisters = 0; // A bitmask, indicating which registers have been set in g_InlineVertexBuffer_Table
@ -191,6 +195,7 @@ CxbxPatchedStream& CxbxVertexBufferConverter::GetPatchedStream(uint64_t dataKey,
auto it = m_PatchedStreams.find(key);
if (it != m_PatchedStreams.end()) {
m_TotalLookupSuccesses++;
m_PatchedStreamUsageList.splice(m_PatchedStreamUsageList.begin(), m_PatchedStreamUsageList, it->second);
return *it->second;
}
@ -215,12 +220,18 @@ CxbxPatchedStream& CxbxVertexBufferConverter::GetPatchedStream(uint64_t dataKey,
return stream;
}
void CxbxVertexBufferConverter::PrintStats()
void CxbxVertexBufferConverter::DrawCacheStats()
{
printf("Vertex Buffer Cache Status: \n");
printf("- Cache Size: %d\n", m_PatchedStreams.size());
printf("- Hits: %d\n", m_TotalCacheHits);
printf("- Misses: %d\n", m_TotalCacheMisses);
const ULONG falsePositives = std::exchange(m_TotalLookupSuccesses, 0) - m_TotalCacheHits;
const ULONG totalMisses = m_VertexStreamHashMisses + m_DataNotInCacheMisses;
ImGui::Text("Cache Size: %u", m_PatchedStreams.size());
ImGui::Text("Hits: %u", std::exchange(m_TotalCacheHits, 0));
ImGui::Text("Total misses: %u", totalMisses);
ImGui::Separator();
ImGui::TextUnformatted("Cache miss details:");
ImGui::TextWrapped("Vertex stream hash miss: %u", std::exchange(m_VertexStreamHashMisses, 0));
ImGui::TextWrapped("Data not in cache: %u", std::exchange(m_DataNotInCacheMisses, 0));
}
void CxbxVertexBufferConverter::ConvertStream
@ -339,7 +350,11 @@ void CxbxVertexBufferConverter::ConvertStream
return;
}
m_TotalCacheMisses++;
// Gather stats
if (patchedStream.uiVertexStreamInformationHash != pVertexShaderSteamInfoHash)
m_VertexStreamHashMisses++;
else
m_DataNotInCacheMisses++;
// If execution reaches here, the cached vertex buffer was not valid and we must reconvert the data
// Free the existing buffers

View File

@ -40,7 +40,7 @@ typedef struct _CxbxDrawContext
IN DWORD dwStartVertex; // Only D3DDevice_DrawVertices sets this (potentially higher than default 0)
IN PWORD pXboxIndexData; // Set by D3DDevice_DrawIndexedVertices, D3DDevice_DrawIndexedVerticesUP and HLE_draw_inline_elements
IN DWORD dwBaseVertexIndex; // Set to g_Xbox_BaseVertexIndex in D3DDevice_DrawIndexedVertices
IN INDEX16 LowIndex, HighIndex; // Set when pXboxIndexData is set
IN INDEX16 LowIndex, HighIndex; // Set when pXboxIndexData is set
IN UINT NumVerticesToUse; // Set by CxbxVertexBufferConverter::Apply
// Data if Draw...UP call
IN PVOID pXboxVertexStreamZeroData;
@ -78,7 +78,7 @@ class CxbxVertexBufferConverter
public:
CxbxVertexBufferConverter() = default;
void Apply(CxbxDrawContext *pPatchDesc);
void PrintStats();
void DrawCacheStats();
private:
struct StreamKey
{
@ -99,7 +99,9 @@ class CxbxVertexBufferConverter
// Stack tracking
ULONG m_TotalCacheHits = 0;
ULONG m_TotalCacheMisses = 0;
ULONG m_TotalLookupSuccesses = 0;
ULONG m_VertexStreamHashMisses = 0;
ULONG m_DataNotInCacheMisses = 0;
const UINT m_MaxCacheSize = 10000; // Maximum number of entries in the cache
const UINT m_CacheElasticity = 200; // Cache is allowed to grow this much more than maximum before being purged to maximum
@ -114,6 +116,8 @@ class CxbxVertexBufferConverter
void ConvertStream(CxbxDrawContext *pPatchDesc, CxbxVertexDeclaration* pCxbxVertexDeclaration, UINT uiStream);
};
extern CxbxVertexBufferConverter VertexBufferConverter;
// Inline vertex buffer emulation
extern xbox::X_D3DPRIMITIVETYPE g_InlineVertexBuffer_PrimitiveType;

View File

@ -26,6 +26,9 @@
// ******************************************************************
#define LOG_PREFIX CXBXR_MODULE::DSOUND
#include <imgui.h>
#include "core/common/imgui/ui.hpp"
#include <core\kernel\exports\xboxkrnl.h>
#include <dsound.h>
#include "DirectSoundGlobal.hpp"
@ -51,83 +54,102 @@ DWORD g_dwXbMemAllocated = 0;
DWORD g_dwFree2DBuffers = 0;
DWORD g_dwFree3DBuffers = 0;
void DSound_PrintStats()
void DSound_PrintStats(bool is_focus, ImGuiWindowFlags input_handler, bool m_show_audio_stats)
{
DSoundMutexGuardLock;
std::stringstream ss;
ss << "Stats:"
"\n--DirectSound Cache--";
ss << "\n\tTotal DSBuffer cache = " << g_pDSoundBufferCache.size();
ss << "\n\tTotal DSStream cache = " << g_pDSoundStreamCache.size();
if (m_show_audio_stats) {
// Generate DSBuffer stats
ImGui::SetNextWindowPos(ImVec2(IMGUI_MIN_DIST_SIDE, IMGUI_MIN_DIST_TOP), ImGuiCond_FirstUseEver, ImVec2(0.0f, 0.0f));
ImGui::SetNextWindowSize(ImVec2(200, 275), ImGuiCond_FirstUseEver);
if (ImGui::Begin("Debugging stats", nullptr, input_handler | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
if (ImGui::CollapsingHeader("Audio Buffers", ImGuiTreeNodeFlags_DefaultOpen)) {
DWORD dwStatus;
HRESULT hRet;
unsigned index = 0, isActive = 0;
ImGui::Text("DirectSound Cache:");
ImGui::BulletText("Total DSBuffer cache = %u", g_pDSoundBufferCache.size());
ImGui::BulletText("Total DSStream cache = %u", g_pDSoundStreamCache.size());
ImGui::Separator();
ss << "\nActive DSBuffer cache:";
// Generate DSBuffer stats
for (const auto& i : g_pDSoundBufferCache) {
const auto& buffer = i->emuDSBuffer;
hRet = buffer->EmuDirectSoundBuffer8->GetStatus(&dwStatus);
if (hRet == DS_OK && (dwStatus & DSBSTATUS_PLAYING) != 0) {
isActive++;
ss << "\n\tDSBufferCache[" << index << "] = " << reinterpret_cast<void*>(i);
ss << "\n\t\tstatus = ";
if ((dwStatus & DSBSTATUS_LOOPING) != 0) {
ss << "looping";
}
else {
ss << "play once";
}
ss << "\n\t\tX_BufferCacheSize = " << buffer->X_BufferCacheSize;
ss << "\n\t\tEmuFlags = " << buffer->EmuFlags;
ss << "\n\t\tEmuRegionToggle = " << buffer->EmuBufferToggle;
if (buffer->EmuBufferToggle == xbox::X_DSB_TOGGLE_PLAY) {
ss << "\n\t\t\tEmuRegionPlayStartOffset = " << buffer->EmuRegionPlayStartOffset;
ss << "\n\t\t\tEmuRegionPlayLength = " << buffer->EmuRegionPlayLength;
}
else if (buffer->EmuBufferToggle == xbox::X_DSB_TOGGLE_LOOP) {
ss << "\n\t\t\tEmuRegionLoopStartOffset = " << buffer->EmuRegionLoopStartOffset;
ss << "\n\t\t\tEmuRegionLoopLength = " << buffer->EmuRegionLoopLength;
DWORD dwStatus;
HRESULT hRet;
unsigned index = 0, isActive = 0;
if (ImGui::CollapsingHeader("Active DSBuffer cache")) {
for (const auto& i : g_pDSoundBufferCache) {
const auto& buffer = i->emuDSBuffer;
hRet = buffer->EmuDirectSoundBuffer8->GetStatus(&dwStatus);
if (hRet == DS_OK && (dwStatus & DSBSTATUS_PLAYING) != 0) {
if (isActive) {
ImGui::Separator();
}
isActive++;
ImGui::BulletText("DSBufferCache[%u] = 0x%p", index, reinterpret_cast<void*>(i));
ImGui::Indent();
ImGui::BulletText("status = %s", ((dwStatus & DSBSTATUS_LOOPING) != 0) ? "looping" : "play once");
ImGui::BulletText("X_BufferCacheSize = 0x%u", buffer->X_BufferCacheSize);
ImGui::BulletText("EmuFlags = %X", buffer->EmuFlags);
ImGui::BulletText("EmuRegionToggle = 0x%X", buffer->EmuBufferToggle);
if (buffer->EmuBufferToggle == xbox::X_DSB_TOGGLE_PLAY) {
ImGui::Indent();
ImGui::BulletText("EmuRegionPlayStartOffset = 0x%X", buffer->EmuRegionPlayStartOffset);
ImGui::BulletText("EmuRegionPlayLength = 0x%X", buffer->EmuRegionPlayLength);
ImGui::Unindent();
}
else if (buffer->EmuBufferToggle == xbox::X_DSB_TOGGLE_LOOP) {
ImGui::Indent();
ImGui::BulletText("EmuRegionLoopStartOffset = 0x%X", buffer->EmuRegionLoopStartOffset);
ImGui::BulletText("EmuRegionLoopLength = 0x%X", buffer->EmuRegionLoopLength);
ImGui::Unindent();
}
ImGui::Unindent();
}
index++;
}
if (isActive == 0) {
ImGui::BulletText("(none)");
}
ImGui::Text("Total active DSBuffer = %u", isActive);
}
// Generate DSStream stats
index = 0;
isActive = 0;
if (ImGui::CollapsingHeader("Active DSStream cache")) {
for (const auto& i : g_pDSoundStreamCache) {
hRet = i->EmuDirectSoundBuffer8->GetStatus(&dwStatus);
if (hRet == DS_OK && (dwStatus & DSBSTATUS_PLAYING) != 0) {
if (isActive) {
ImGui::Separator();
}
isActive++;
ImGui::BulletText("DSStreamCache[%u] = 0x%p", index, reinterpret_cast<void*>(i));
ImGui::Indent();
ImGui::BulletText("Max packets allow = %u", i->X_MaxAttachedPackets);
ImGui::BulletText("Total packets = %u", i->Host_BufferPacketArray.size());
ImGui::BulletText("is processing = %d", i->Host_isProcessing);
ImGui::BulletText("EmuFlags = %X", i->EmuFlags);
ImGui::BulletText("Xb_Status = %X", i->Xb_Status);
ImGui::Unindent();
}
index++;
}
if (isActive == 0) {
ImGui::BulletText("(none)");
}
ImGui::Text("Total active DSStream = %u", isActive);
}
}
ImGui::End();
}
index++;
}
if (isActive == 0) {
ss << "\n\t(none)";
}
ss << "\nTotal active DSBuffer = " << isActive;
// Generate DSStream stats
index = 0;
isActive = 0;
ss << "\nActive DSStream cache:";
for (const auto& i : g_pDSoundStreamCache) {
hRet = i->EmuDirectSoundBuffer8->GetStatus(&dwStatus);
if (hRet == DS_OK && (dwStatus & DSBSTATUS_PLAYING) != 0) {
isActive++;
ss << "\n\tDSStreamCache[" << index << "] = " << reinterpret_cast<void*>(i);
ss << "\n\t\tMax packets allow = " << i->X_MaxAttachedPackets;
ss << "\n\t\tTotal packets = " << i->Host_BufferPacketArray.size();
ss << "\n\t\tis processing = " << i->Host_isProcessing;
ss << "\n\t\tEmuFlags = " << i->EmuFlags;
ss << "\n\t\tXb_Status = " << i->Xb_Status;
}
index++;
}
if (isActive == 0) {
ss << "\n\t(none)";
}
ss << "\nTotal active DSStream = " << isActive;
EmuLog(LOG_LEVEL::INFO, ss.str().c_str());
}

View File

@ -488,13 +488,17 @@ XBSYSAPI EXPORTNUM(49) xbox::void_xt DECLSPEC_NORETURN NTAPI xbox::HalReturnToFi
{
LOG_FUNC_ONE_ARG(Routine);
bool is_reboot = false;
switch (Routine) {
case ReturnFirmwareHalt:
CxbxKrnlCleanup("Emulated Xbox is halted");
break;
case ReturnFirmwareReboot:
LOG_UNIMPLEMENTED(); // fall through
LOG_UNIMPLEMENTED();
[[fallthrough]];
case ReturnFirmwareQuickReboot:
{
if (xbox::LaunchDataPage == NULL)
@ -585,6 +589,7 @@ XBSYSAPI EXPORTNUM(49) xbox::void_xt DECLSPEC_NORETURN NTAPI xbox::HalReturnToFi
g_EmuShared->GetBootFlags(&QuickReboot);
QuickReboot |= BOOT_QUICK_REBOOT;
g_EmuShared->SetBootFlags(&QuickReboot);
is_reboot = true;
g_VMManager.SavePersistentMemory();
@ -665,7 +670,7 @@ XBSYSAPI EXPORTNUM(49) xbox::void_xt DECLSPEC_NORETURN NTAPI xbox::HalReturnToFi
LOG_UNIMPLEMENTED();
}
EmuShared::Cleanup();
CxbxKrnlShutDown(is_reboot);
TerminateProcess(GetCurrentProcess(), EXIT_SUCCESS);
}

View File

@ -53,6 +53,7 @@
#include "common/ReserveAddressRanges.h"
#include "common/xbox/Types.hpp"
#include "common/win32/WineEnv.h"
#include "core/common/video/RenderBase.hpp"
#include <clocale>
#include <process.h>
@ -1753,11 +1754,13 @@ void CxbxKrnlResume()
g_bEmuSuspended = false;
}
void CxbxKrnlShutDown()
void CxbxKrnlShutDown(bool is_reboot)
{
// Clear all kernel boot flags. These (together with the shared memory) persist until Cxbx-Reloaded is closed otherwise.
int BootFlags = 0;
g_EmuShared->SetBootFlags(&BootFlags);
if (!is_reboot) {
// Clear all kernel boot flags. These (together with the shared memory) persist until Cxbx-Reloaded is closed otherwise.
int BootFlags = 0;
g_EmuShared->SetBootFlags(&BootFlags);
}
// NOTE: This causes a hang when exiting while NV2A is processing
// This is okay for now: It won't leak memory or resources since TerminateProcess will free everything
@ -1769,9 +1772,14 @@ void CxbxKrnlShutDown()
// Shutdown the memory manager
g_VMManager.Shutdown();
// Shutdown the render manager
g_renderbase->Shutdown();
g_renderbase.release();
g_renderbase = nullptr;
CxbxUnlockFilePath();
if (CxbxKrnl_hEmuParent != NULL) {
if (CxbxKrnl_hEmuParent != NULL && !is_reboot) {
SendMessage(CxbxKrnl_hEmuParent, WM_PARENTNOTIFY, WM_DESTROY, 0);
}

View File

@ -166,7 +166,7 @@ void CxbxKrnlSuspend();
void CxbxKrnlResume();
/*! terminate gracefully the emulation */
void CxbxKrnlShutDown();
void CxbxKrnlShutDown(bool is_reboot = false);
/*! display the fatal error message*/
void CxbxKrnlPrintUEM(ULONG ErrorCode);

View File

@ -87,8 +87,6 @@ typedef struct DUMMY_KERNEL
IMAGE_SECTION_HEADER SectionHeader;
} *PDUMMY_KERNEL;
typedef WORD INDEX16;
extern bool g_DisablePixelShaders;
extern bool g_UseAllCores;
extern bool g_SkipRdtscPatching;

View File

@ -705,6 +705,23 @@ void OpenGL_draw_inline_elements(NV2AState *d)
OpenGL_draw_end(d);
}
static void CxbxImGui_RenderOpenGL(ImGuiUI* m_imgui, std::nullptr_t unused)
{
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
m_imgui->DrawMenu();
m_imgui->DrawWidgets();
ImGui::Render();
ImDrawData* drawData = ImGui::GetDrawData();
if (drawData->TotalVtxCount > 0) {
ImGui_ImplOpenGL3_RenderDrawData(drawData);
}
}
void OpenGL_draw_state_update(NV2AState *d)
{
PGRAPHState *pg = &d->pgraph;
@ -893,6 +910,10 @@ void OpenGL_draw_state_update(NV2AState *d)
pg->gl_zpass_pixel_count_query_count - 1] = gl_query;
glBeginQuery(GL_SAMPLES_PASSED, gl_query);
}
// Render ImGui
static std::function<void(ImGuiUI*, std::nullptr_t)> internal_render = &CxbxImGui_RenderOpenGL;
g_renderbase->Render(internal_render, nullptr);
}
void OpenGL_draw_end(NV2AState *d)
@ -2989,6 +3010,13 @@ void pgraph_init(NV2AState *d)
glextensions_init();
// Set up ImGui's render backend
//ImGui_ImplSDL2_InitForOpenGL(window, pg->gl_context);
ImGui_ImplOpenGL3_Init();
g_renderbase->SetDeviceRelease([] {
ImGui_ImplOpenGL3_Shutdown();
});
/* DXT textures */
assert(glo_check_extension("GL_EXT_texture_compression_s3tc"));
/* Internal RGB565 texture format */

View File

@ -37,7 +37,6 @@
#define LOG_PREFIX CXBXR_MODULE::NV2A
#include <core/kernel/exports/xboxkrnl.h> // For PKINTERRUPT, etc.
#ifdef _MSC_VER // Check if MS Visual C compiler
@ -53,6 +52,9 @@
#include "core\kernel\init\CxbxKrnl.h" // For XBOX_MEMORY_SIZE, DWORD, etc
#include "core\kernel\support\Emu.h"
#include "core\kernel\exports\EmuKrnl.h"
#include <backends/imgui_impl_win32.h>
#include <backends/imgui_impl_opengl3.h>
#include "core/common/video/RenderBase.hpp"
#include "core\hle\Intercept.hpp"
#include "common/win32/Threads.h"
#include "Logging.h"
@ -1157,6 +1159,9 @@ NV2ADevice::NV2ADevice()
NV2ADevice::~NV2ADevice()
{
Reset(); // TODO : Review this
g_renderbase->DeviceRelease();
delete m_nv2a_state;
}

View File

@ -74,9 +74,7 @@ void SyncInputSettings(int port_num, int dev_type, bool is_opt)
}
}
else {
g_EmuShared->SetInputMoAxisSettings(g_Settings->m_input_general.MoAxisRange);
g_EmuShared->SetInputMoWheelSettings(g_Settings->m_input_general.MoWheelRange);
g_EmuShared->SetInputKbMoUnfocusSettings(g_Settings->m_input_general.IgnoreKbMoUnfocus);
g_EmuShared->SetInputGeneralSettings(&g_Settings->m_input_general);
port_num = PORT_INVALID;
}
#if 0 // lle usb

View File

@ -360,6 +360,8 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP
DrawLedBitmap(hwnd, true);
}
}
break;
case WM_COMMAND:
{
switch (HIWORD(wParam)) {
@ -387,6 +389,10 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP
g_EmuShared->SetIsReady(true);
}
break;
case ID_GUI_STATUS_OVERLAY:
g_EmuShared->GetOverlaySettings(&g_Settings->m_overlay);
break;
}
}
break;
@ -2330,7 +2336,7 @@ void WndMain::StartEmulation(HWND hwndParent, DebuggerState LocalDebuggerState /
}
bool AttachLocalDebugger = (LocalDebuggerState == debuggerOn);
g_EmuShared->SetDebuggingFlag(&AttachLocalDebugger);
g_EmuShared->SetDebuggingFlag(AttachLocalDebugger);
/* Main process to generate emulation command line begin. */
// If we are adding more arguments, this is the place to do so.

View File

@ -196,6 +196,7 @@
#define ID_GUI_STATUS_LOG_ENABLED 1099
#define IDC_AC_MUTE_WHEN_UNFOCUS 1100
#define IDC_IGNORE_KBMO_UNFOCUS 1101
#define ID_GUI_STATUS_OVERLAY 1102
#define IDC_XBOX_PORT_0 1158
#define IDC_XBOX_PORT_1 1166
#define IDC_XBOX_PORT_2 1174