dx11: fix modifier volumes, rotation. sdl: on-screen keyboard support

dx11: Back face stencil ops need to be set
dx11: Rotate CCW instead of CW
dx11: Present with NO_WAIT when fast forwarding
sdl: support for on-screen keyboard. Delay keys up by one frame to allow quick key presses.
ui: better fix to wait for future on UWP
This commit is contained in:
flyinghead 2021-11-28 16:19:03 +01:00
parent 3d7455316f
commit d071adea9a
7 changed files with 110 additions and 60 deletions

View File

@ -72,11 +72,11 @@ public:
desc.DepthWriteMask = depthWrite ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
desc.DepthFunc = Zfunction[depthFunc];
desc.StencilEnable = stencil;
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE;
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
desc.BackFace = desc.FrontFace;
desc.StencilWriteMask = 0xFF;
desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE;
theDX11Context.getDevice()->CreateDepthStencilState(&desc, &state.get());
}
return state;

View File

@ -287,7 +287,7 @@ VertexOut main(in VertexIn vin)
#if ROTATE == 0
vo.pos = float4(vin.pos, 0.f, 1.f);
#else
vo.pos = float4(vin.pos.y, -vin.pos.x, 0.f, 1.f);
vo.pos = float4(-vin.pos.y, vin.pos.x, 0.f, 1.f);
#endif
vo.uv = vin.uv;

View File

@ -179,13 +179,13 @@ void DX11Context::Present()
return;
frameRendered = false;
bool swapOnVSync = !settings.input.fastForwardMode && config::VSync;
HRESULT hr = swapchain->Present(swapOnVSync ? 1 : 0, 0);
HRESULT hr = swapchain->Present(swapOnVSync ? 1 : 0, !swapOnVSync ? DXGI_PRESENT_DO_NOT_WAIT : 0);
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
{
WARN_LOG(RENDERER, "Present failed: device removed/reset");
handleDeviceLost();
}
else if (FAILED(hr))
else if (hr != DXGI_ERROR_WAS_STILL_DRAWING && FAILED(hr))
WARN_LOG(RENDERER, "Present failed %x", hr);
}

View File

@ -63,6 +63,8 @@ static bool error_msg_shown;
static std::string osd_message;
static double osd_message_end;
static std::mutex osd_message_mutex;
static void (*showOnScreenKeyboard)(bool show);
static bool keysUpNextFrame[512];
static int map_system = 0;
static void reset_vmus();
@ -278,6 +280,11 @@ void gui_keyboard_key(u8 keyCode, bool pressed, u8 modifiers)
if (!inited)
return;
ImGuiIO& io = ImGui::GetIO();
if (!pressed && io.KeysDown[keyCode])
{
keysUpNextFrame[keyCode] = true;
return;
}
io.KeyCtrl = (modifiers & (0x01 | 0x10)) != 0;
io.KeyShift = (modifiers & (0x02 | 0x20)) != 0;
io.KeysDown[keyCode] = pressed;
@ -314,7 +321,7 @@ void gui_set_mouse_wheel(float delta)
mouseWheel += delta;
}
static void ImGui_Impl_NewFrame()
static void gui_newFrame()
{
imguiDriver->newFrame();
ImGui::GetIO().DisplaySize.x = settings.display.width;
@ -367,6 +374,30 @@ static void ImGui_Impl_NewFrame()
io.NavInputs[ImGuiNavInput_LStickDown] = 0.f;
ImGui::GetStyle().Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f);
if (showOnScreenKeyboard != nullptr)
showOnScreenKeyboard(io.WantTextInput);
}
static void delayedKeysUp()
{
ImGuiIO& io = ImGui::GetIO();
for (int i = 0; i < ARRAY_SIZE(keysUpNextFrame); i++)
if (keysUpNextFrame[i])
io.KeysDown[i] = false;
memset(keysUpNextFrame, 0, sizeof(keysUpNextFrame));
}
static void gui_endFrame()
{
ImGui::Render();
imguiDriver->renderDrawData(ImGui::GetDrawData());
delayedKeysUp();
}
void gui_setOnScreenKeyboardCallback(void (*callback)(bool show))
{
showOnScreenKeyboard = callback;
}
void gui_set_insets(int left, int right, int top, int bottom)
@ -2275,23 +2306,25 @@ static void gui_network_start()
if (networkStatus.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready)
{
try {
if (networkStatus.get())
{
gui_state = GuiState::Closed;
ImGui::Text("Starting...");
}
else
{
gui_state = GuiState::Main;
ImGui::Text("Starting...");
gui_deAsync([] {
try {
if (networkStatus.get())
{
gui_state = GuiState::Closed;
}
else
{
emu.unloadGame();
gui_state = GuiState::Main;
}
} catch (const FlycastException& e) {
NetworkHandshake::instance->stop();
emu.unloadGame();
gui_error(e.what());
gui_state = GuiState::Main;
}
} catch (const FlycastException& e) {
NetworkHandshake::instance->stop();
gui_state = GuiState::Main;
emu.unloadGame();
gui_error(e.what());
}
});
}
else
{
@ -2307,9 +2340,7 @@ static void gui_network_start()
if (ImGui::Button("Cancel", ImVec2(100.f * scaling, 0.f)))
{
NetworkHandshake::instance->stop();
#ifdef TARGET_UWP
static std::future<void> f;
f = std::async(std::launch::async, [] {
gui_deAsync([] {
try {
networkStatus.get();
}
@ -2318,14 +2349,6 @@ static void gui_network_start()
emu.unloadGame();
gui_state = GuiState::Main;
});
#else
try {
networkStatus.get();
} catch (const FlycastException& e) {
}
gui_state = GuiState::Main;
emu.unloadGame();
#endif
}
ImGui::PopStyleVar();
@ -2405,7 +2428,7 @@ void gui_display_ui()
}
}
ImGui_Impl_NewFrame();
gui_newFrame();
ImGui::NewFrame();
error_msg_shown = false;
@ -2450,8 +2473,7 @@ void gui_display_ui()
break;
}
error_popup();
ImGui::Render();
imguiDriver->renderDrawData(ImGui::GetDrawData());
gui_endFrame();
if (gui_state == GuiState::Closed)
emu.start();
@ -2491,7 +2513,7 @@ void gui_display_osd()
// if (!message.empty() || config::FloatVMUs || crosshairsNeeded() || (ggpo::active() && config::NetworkStats))
{
ImGui_Impl_NewFrame();
gui_newFrame();
ImGui::NewFrame();
if (!message.empty())
@ -2518,8 +2540,7 @@ void gui_display_osd()
}
lua::overlay();
ImGui::Render();
imguiDriver->renderDrawData(ImGui::GetDrawData());
gui_endFrame();
}
}

View File

@ -43,6 +43,7 @@ void gui_set_insets(int left, int right, int top, int bottom);
void gui_stop_game(const std::string& message = "");
void gui_start_game(const std::string& path);
void gui_error(const std::string& what);
void gui_setOnScreenKeyboardCallback(void (*callback)(bool show));
extern int screen_dpi;
extern float scaling;

View File

@ -25,6 +25,7 @@
#include "imgui/imgui_internal.h"
#include "gui.h"
#include "emulator.h"
#include "stdclass.h"
typedef bool (*StringCallback)(bool cancelled, std::string selection);
@ -66,6 +67,30 @@ static inline bool operator!=(const ImVec2& l, const ImVec2& r)
void fullScreenWindow(bool modal);
void windowDragScroll();
// UWP doesn't allow the UI thread to wait on a future
template<typename F>
void gui_deAsync(F f)
{
#ifdef TARGET_UWP
static cResetEvent event;
static std::future<void> future;
event.Reset();
future = std::async(std::launch::async, [&f] {
try {
f();
event.Set();
} catch (...) {
event.Set();
throw;
}
});
event.Wait();
#else
f();
#endif
}
class BackgroundGameLoader
{
public:
@ -80,30 +105,13 @@ public:
void cancel()
{
progress.cancelled = true;
#ifdef TARGET_UWP
if (future.valid())
{
if (progress.cancelled)
return;
static std::future<void> f;
f = std::async(std::launch::async, [this] {
gui_deAsync([this] {
if (future.valid())
try {
future.get();
} catch (const FlycastException& e) {
}
catch (const FlycastException& e) {
}
emu.unloadGame();
gui_state = GuiState::Main;
});
return;
}
#else
if (future.valid())
try {
future.get();
} catch (const FlycastException& e) {
}
#endif
});
emu.unloadGame();
gui_state = GuiState::Main;
}
@ -114,7 +122,9 @@ public:
return true;
if (future.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
{
future.get();
gui_deAsync([this] {
future.get();
});
return true;
}
return false;

View File

@ -195,6 +195,22 @@ void input_sdl_init()
for (int joy = 0; joy < 4; joy++)
sdl_open_joystick(joy);
#endif
if (SDL_HasScreenKeyboardSupport())
{
NOTICE_LOG(INPUT, "On-screen keyboard supported");
gui_setOnScreenKeyboardCallback([](bool show) {
// We should be able to use SDL_IsScreenKeyboardShown() but it doesn't seem to work on Xbox
static bool visible;
if (window != nullptr && visible != show)
{
visible = show;
if (show)
SDL_StartTextInput();
else
SDL_StopTextInput();
}
});
}
}
inline void SDLMouse::setAbsPos(int x, int y) {
@ -248,9 +264,11 @@ void input_sdl_handle()
}
}
break;
case SDL_TEXTINPUT:
gui_keyboard_inputUTF8(event.text.text);
break;
case SDL_WINDOWEVENT:
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED
|| event.window.event == SDL_WINDOWEVENT_RESTORED