diff --git a/src/spice2x/games/popn/popn.cpp b/src/spice2x/games/popn/popn.cpp index 42dd926..14f4dba 100644 --- a/src/spice2x/games/popn/popn.cpp +++ b/src/spice2x/games/popn/popn.cpp @@ -9,14 +9,85 @@ #include "util/utils.h" #include "cfg/button.h" #include "cfg/api.h" +#include "hooks/setupapihook.h" #include "hooks/sleephook.h" #include "launcher/launcher.h" #include "launcher/logger.h" #include "misc/eamuse.h" +#include "util/sysutils.h" #include "io.h" namespace games::popn { +#if SPICE64 && !SPICE_XP + + static decltype(DisplayConfigGetDeviceInfo) *DisplayConfigGetDeviceInfo_orig = nullptr; + + static + LONG + WINAPI + DisplayConfigGetDeviceInfo_hook(DISPLAYCONFIG_DEVICE_INFO_HEADER* requestPacket) + { + if (requestPacket == nullptr) { + return DisplayConfigGetDeviceInfo_orig(requestPacket); + } + const auto ret = DisplayConfigGetDeviceInfo_orig(requestPacket); + log_misc( + "popn", + "DisplayConfigGetDeviceInfo returned {}, type={}, size={}, id={}, luid={}/{}", + ret, + static_cast(requestPacket->type), + requestPacket->size, + requestPacket->id, + requestPacket->adapterId.HighPart, + requestPacket->adapterId.LowPart); + if (ret == ERROR_SUCCESS) { + if (requestPacket->type == DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME) { + const auto sourceName = reinterpret_cast(requestPacket); + log_misc( + "popn", + "... name={}", + ws2s(sourceName->viewGdiDeviceName)); + } else if (requestPacket->type == DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME) { + const auto targetName = reinterpret_cast(requestPacket); + log_misc( + "popn", + "... flags={}, outputTechnology: {}, connectorInstance={}, friendlyname={} path={}", + targetName->flags.value, + static_cast(targetName->outputTechnology), + targetName->connectorInstance, + ws2s(targetName->monitorFriendlyDeviceName), + ws2s(targetName->monitorDevicePath)); + + // need to fix up some values for the primary monitor... + const auto monitors = sysutils::enumerate_monitors(); + for (const auto& monitor : monitors) { + if (monitor.id == targetName->header.id && + monitor.adapter_id_HighPart == targetName->header.adapterId.HighPart && + monitor.adapter_id_LowPart == targetName->header.adapterId.LowPart) { + + if (monitor.is_primary) { + targetName->outputTechnology = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL; + targetName->connectorInstance = 2; + log_info( + "popn", + "... overriding primary monitor ({}) to pretend to be DP port #2", + monitor.display_name); + } else { + // TODO: is this what the game expects for subscreen? + // TODO: what if there are 3+ monitors? + targetName->outputTechnology = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI; + } + break; + } + } + } + } + return ret; + } + +#endif + static int __cdecl usbCheckAlive() { return 1; } @@ -320,5 +391,29 @@ namespace games::popn { detour::inline_hook((void *) usbWdtStartDone, libutils::try_proc(ezusb, "?usbWdtStartDone@@YAHXZ")); } + +#if SPICE64 && !SPICE_XP + + if (is_pikapika_model()) { + // monitor hook + DisplayConfigGetDeviceInfo_orig = detour::iat_try("DisplayConfigGetDeviceInfo", DisplayConfigGetDeviceInfo_hook, avs::game::DLL_INSTANCE); + + // TODO: io emulation + SETUPAPI_SETTINGS settings{}; + settings.class_guid[0] = 0x86E0D1E0; + settings.class_guid[1] = 0x11D08089; + settings.class_guid[2] = 0x0008E49C; + settings.class_guid[3] = 0x731F303E; + const char property[] = "1CCF(8050)_000"; + const char property_hardwareid[] = "USB\\VID_1CCF&PID_8050&MI_00\\000"; + memcpy(settings.property_devicedesc, property, sizeof(property)); + memcpy(settings.property_hardwareid, property_hardwareid, sizeof(property_hardwareid)); + setupapihook_init(avs::game::DLL_INSTANCE); + setupapihook_add(settings); + } + + +#endif + } } diff --git a/src/spice2x/hooks/graphics/backends/d3d9/d3d9_backend.cpp b/src/spice2x/hooks/graphics/backends/d3d9/d3d9_backend.cpp index 9b7ac7b..23e3246 100644 --- a/src/spice2x/hooks/graphics/backends/d3d9/d3d9_backend.cpp +++ b/src/spice2x/hooks/graphics/backends/d3d9/d3d9_backend.cpp @@ -1139,8 +1139,6 @@ static void graphics_d3d9_ldj_init_sub_screen(IDirect3DDevice9Ex *device, D3DPRE */ if (GRAPHICS_WINDOWED) { - log_info("graphics::d3d9", "creating additional swap chain"); - present_params->Windowed = true; present_params->FullScreen_RefreshRateInHz = 0; @@ -1149,18 +1147,23 @@ static void graphics_d3d9_ldj_init_sub_screen(IDirect3DDevice9Ex *device, D3DPRE hr = device->CreateAdditionalSwapChain(present_params, &SUB_SWAP_CHAIN); if (FAILED(hr)) { log_warning("graphics::d3d9", "failed to create additional swap chain, hr={}", FMT_HRESULT(hr)); + } else { + log_info("graphics::d3d9", "created additional swap chain for windowed mode"); } } else { hr = device->GetSwapChain(1, &SUB_SWAP_CHAIN); if (FAILED(hr)) { log_warning("graphics::d3d9", "failed to acquire fullscreen sub swap chain, hr={}", FMT_HRESULT(hr)); } else { + log_info("graphics::d3d9", "acquired fullscreen sub swap chain"); return; } hr = device->CreateAdditionalSwapChain(present_params, &SUB_SWAP_CHAIN); if (FAILED(hr)) { log_warning("graphics::d3d9", "failed to get additional swap chain, hr={}", FMT_HRESULT(hr)); + } else { + log_info("graphics::d3d9", "created additional swap chain for fullscreen mode"); } } } diff --git a/src/spice2x/hooks/graphics/backends/d3d9/d3d9_device.cpp b/src/spice2x/hooks/graphics/backends/d3d9/d3d9_device.cpp index 4870ba3..40e6800 100644 --- a/src/spice2x/hooks/graphics/backends/d3d9/d3d9_device.cpp +++ b/src/spice2x/hooks/graphics/backends/d3d9/d3d9_device.cpp @@ -263,7 +263,6 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3DDevice9::CreateAdditionalSwapChain( if (SUCCEEDED(hr) && !sub_swapchain) { sub_swapchain = new WrappedIDirect3DSwapChain9(this, *ppSwapChain); sub_swapchain->should_run_hooks = false; - log_info("graphics::d3d9", "created additional swap chain"); } else if (FAILED(hr) && !fake_sub_swapchain) { log_warning("graphics::d3d9", "failed to create sub swap chain, hr={}, using fake swap chain", diff --git a/src/spice2x/overlay/windows/config.cpp b/src/spice2x/overlay/windows/config.cpp index b44e3f3..1ff8bca 100644 --- a/src/spice2x/overlay/windows/config.cpp +++ b/src/spice2x/overlay/windows/config.cpp @@ -4540,9 +4540,11 @@ namespace overlay::windows { for (const auto &monitor : monitors) { const bool is_selected = option.value == monitor.display_name; auto friendly = wchar_to_u8(monitor.friendly_name.c_str()); - if (ImGui::Selectable( - fmt::format("{} ({})", monitor.display_name, friendly).c_str(), - is_selected)) { + auto str = fmt::format("{} ({})", monitor.display_name, friendly); + if (monitor.is_primary) { + str += " [Primary]"; + } + if (ImGui::Selectable(str.c_str(), is_selected)) { option.value = monitor.display_name; } } diff --git a/src/spice2x/util/sysutils.cpp b/src/spice2x/util/sysutils.cpp index 41e7abf..6daf40e 100644 --- a/src/spice2x/util/sysutils.cpp +++ b/src/spice2x/util/sysutils.cpp @@ -409,7 +409,26 @@ namespace sysutils { std::vector result; for (const auto& path : paths) { - MonitorEntry entry; + MonitorEntry entry = {}; + entry.adapter_id_LowPart = path.targetInfo.adapterId.LowPart; + entry.adapter_id_HighPart = path.targetInfo.adapterId.HighPart; + entry.id = path.targetInfo.id; + + // primary monitor? + for (const auto& mode : modes) { + if (mode.infoType != DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE) { + continue; + } + + if (mode.adapterId.HighPart == path.sourceInfo.adapterId.HighPart && + mode.adapterId.LowPart == path.sourceInfo.adapterId.LowPart && + mode.id == path.sourceInfo.id) { + if (mode.sourceMode.position.x == 0 && mode.sourceMode.position.y == 0) { + entry.is_primary = true; + } + break; + } + } // device ID (\\.\DISPLAYn) DISPLAYCONFIG_SOURCE_DEVICE_NAME source_name = {}; diff --git a/src/spice2x/util/sysutils.h b/src/spice2x/util/sysutils.h index 164c025..343504f 100644 --- a/src/spice2x/util/sysutils.h +++ b/src/spice2x/util/sysutils.h @@ -12,6 +12,10 @@ namespace sysutils { struct MonitorEntry { std::string display_name; // \\.\DISPLAY1 std::wstring friendly_name; // Dell S2204T; wstring so that it can be converted to utf8 or string + bool is_primary; + uint32_t adapter_id_LowPart; + int32_t adapter_id_HighPart; + uint32_t id; }; const std::vector &enumerate_monitors();