Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allows LUS to set the screen dimensions programmatically. #785

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 38 additions & 4 deletions src/graphic/Fast3D/Fast3dWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ void Fast3dWindow::Init() {
uint32_t width, height;
int32_t posX, posY;

isFullscreen = Ship::Context::GetInstance()->GetConfig()->GetBool("Window.Fullscreen.Enabled", false) || gameMode;
isFullscreen = Ship::Context::GetInstance()->GetConfig()->GetBool("Window.Fullscreen.Enabled", 0) || gameMode;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the plan to standardize on 0 instead of false for GetBool?

posX = Ship::Context::GetInstance()->GetConfig()->GetInt("Window.PositionX", 100);
posY = Ship::Context::GetInstance()->GetConfig()->GetInt("Window.PositionY", 100);

if (isFullscreen) {
width = Ship::Context::GetInstance()->GetConfig()->GetInt("Window.Fullscreen.Width", gameMode ? 1280 : 1920);
height = Ship::Context::GetInstance()->GetConfig()->GetInt("Window.Fullscreen.Height", gameMode ? 800 : 1080);
width = Ship::Context::GetInstance()->GetConfig()->GetInt("Window.Fullscreen.Width", 1920);
Copy link
Collaborator

@briaguya-ai briaguya-ai Jan 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to test this in gamescope. i still don't like that we have resolution tied to gamescope, just because someone is using gamescope doesn't mean they're on a steam deck, but seeing what breaks and if we have ways around it with the other changes in this PR will be good

edit: looks like we're looking for steamdeck in the release variant id so it's not just gamescope we're checking for, but still feels a bit tacked on

height = Ship::Context::GetInstance()->GetConfig()->GetInt("Window.Fullscreen.Height", 1080);
} else {
width = Ship::Context::GetInstance()->GetConfig()->GetInt("Window.Width", 640);
height = Ship::Context::GetInstance()->GetConfig()->GetInt("Window.Height", 480);
Expand Down Expand Up @@ -172,6 +172,40 @@ uint32_t Fast3dWindow::GetHeight() {
return height;
}

void Fast3dWindow::SetCurrentDimensions(uint32_t width, uint32_t height, int32_t posX, int32_t posY) {
mWindowManagerApi->set_dimensions(width, height, posX, posY);
SaveWindowToConfig();
}

void Fast3dWindow::SetCurrentDimensions(uint32_t width, uint32_t height) {
SetCurrentDimensions(width, height, GetPosX(), GetPosY());
}

void Fast3dWindow::SetCurrentDimensions(bool isFullscreen, uint32_t width, uint32_t height, int32_t posX,
int32_t posY) {
auto conf = Ship::Context::GetInstance()->GetConfig();
if (!isFullscreen) {
conf->SetInt("Window.Width", (int32_t)width);
conf->SetInt("Window.Height", (int32_t)height);
conf->SetInt("Window.PositionX", posX);
conf->SetInt("Window.PositionY", posY);
} else {
conf->SetInt("Window.Fullscreen.Width", (int32_t)width);
conf->SetInt("Window.Fullscreen.Height", (int32_t)height);
}
mWindowManagerApi->set_fullscreen(isFullscreen);
mWindowManagerApi->set_dimensions(width, height, posX, posY);
SaveWindowToConfig();
}

void Fast3dWindow::SetCurrentDimensions(bool isFullscreen, uint32_t width, uint32_t height) {
SetCurrentDimensions(isFullscreen, width, height, GetPosX(), GetPosY());
}

Ship::WindowRect Fast3dWindow::GetPrimaryMonitorRect() {
return mWindowManagerApi->get_primary_monitor_rect();
}

int32_t Fast3dWindow::GetPosX() {
uint32_t width, height;
int32_t posX, posY;
Expand Down Expand Up @@ -248,8 +282,8 @@ void Fast3dWindow::SetMsaaLevel(uint32_t value) {
}

void Fast3dWindow::SetFullscreen(bool isFullscreen) {
SaveWindowToConfig();
mWindowManagerApi->set_fullscreen(isFullscreen);
SaveWindowToConfig();
}

bool Fast3dWindow::IsFullscreen() {
Expand Down
5 changes: 5 additions & 0 deletions src/graphic/Fast3D/Fast3dWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ class Fast3dWindow : public Ship::Window {
void SetCursorVisibility(bool visible) override;
uint32_t GetWidth() override;
uint32_t GetHeight() override;
void SetCurrentDimensions(uint32_t width, uint32_t height) override;
void SetCurrentDimensions(uint32_t width, uint32_t height, int32_t posX, int32_t posY) override;
void SetCurrentDimensions(bool isFullscreen, uint32_t width, uint32_t height) override;
void SetCurrentDimensions(bool isFullscreen, uint32_t width, uint32_t height, int32_t posX, int32_t posY) override;
Ship::WindowRect GetPrimaryMonitorRect() override;
int32_t GetPosX() override;
int32_t GetPosY() override;
void SetMousePos(Ship::Coords pos) override;
Expand Down
126 changes: 79 additions & 47 deletions src/graphic/Fast3D/gfx_dxgi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ static struct {
bool dropped_frame;
std::tuple<HMONITOR, RECT, BOOL> h_Monitor; // 0: Handle, 1: Display Monitor Rect, 2: Is_Primary
std::vector<std::tuple<HMONITOR, RECT, BOOL>> monitor_list;
std::vector<Ship::WindowRect> monitor_rects;
size_t primary_monitor_index;
bool zero_latency;
double detected_hz;
double display_period; // (1000 / dxgi.detected_hz) in ms
Expand Down Expand Up @@ -128,37 +130,43 @@ static void apply_maximum_frame_latency(bool first) {
dxgi.applied_maximum_frame_latency = dxgi.maximum_frame_latency;
}

std::vector<std::tuple<HMONITOR, RECT, BOOL>> GetMonitorList() {
std::vector<std::tuple<HMONITOR, RECT, BOOL>> monitors;
void UpdateMonitorList() {
dxgi.monitor_list.clear();
dxgi.monitor_rects.clear();
EnumDisplayMonitors(
nullptr, nullptr,
[](HMONITOR hmon, HDC hdc, LPRECT rc, LPARAM lp) {
UNREFERENCED_PARAMETER(hdc);
UNREFERENCED_PARAMETER(rc);
UNREFERENCED_PARAMETER(lp);

bool isPrimary;
MONITORINFOEX mi = {};
mi.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(hmon, &mi);
auto monitors = (std::vector<std::tuple<HMONITOR, RECT, BOOL>>*)lp;
if (mi.dwFlags == MONITORINFOF_PRIMARY) {
isPrimary = TRUE;
} else {
isPrimary = FALSE;
}
monitors->push_back({ hmon, mi.rcMonitor, isPrimary });

dxgi.monitor_list.push_back({ hmon, mi.rcMonitor, isPrimary });
dxgi.monitor_rects.push_back(
{ mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom });
if (isPrimary) {
dxgi.primary_monitor_index = dxgi.monitor_rects.size() - 1;
}

return TRUE;
},
(LPARAM)&monitors);
return monitors;
(LPARAM) nullptr);
}

// Uses coordinates to get a Monitor handle from a list
bool GetMonitorAtCoords(std::vector<std::tuple<HMONITOR, RECT, BOOL>> MonitorList, int x, int y, UINT cx, UINT cy,
std::tuple<HMONITOR, RECT, BOOL>& MonitorInfo) {
bool GetMonitorAtCoords(int x, int y, UINT cx, UINT cy, std::tuple<HMONITOR, RECT, BOOL>& MonitorInfo) {
RECT wr = { x, y, (x + cx), (y + cy) };
std::tuple<HMONITOR, RECT, BOOL> primary;
for (std::tuple<HMONITOR, RECT, BOOL> i : MonitorList) {
for (std::tuple<HMONITOR, RECT, BOOL> i : dxgi.monitor_list) {
if (PtInRect(&get<1>(i), POINT((x + (cx / 2)), (y + (cy / 2))))) {
MonitorInfo = i;
return true;
Expand All @@ -171,7 +179,7 @@ bool GetMonitorAtCoords(std::vector<std::tuple<HMONITOR, RECT, BOOL>> MonitorLis
LONG area;
LONG lastArea = 0;
std::tuple<HMONITOR, RECT, BOOL> biggest;
for (std::tuple<HMONITOR, RECT, BOOL> i : MonitorList) {
for (std::tuple<HMONITOR, RECT, BOOL> i : dxgi.monitor_list) {
if (IntersectRect(&intersection, &get<1>(i), &wr)) {
area = (intersection.right - intersection.left) * (intersection.bottom - intersection.top);
if (area > lastArea) {
Expand All @@ -188,6 +196,34 @@ bool GetMonitorAtCoords(std::vector<std::tuple<HMONITOR, RECT, BOOL>> MonitorLis
return false;
}

static void apply_window_dimensions() {
RECT wr = { dxgi.posX, dxgi.posY, dxgi.posX + static_cast<int32_t>(dxgi.current_width),
dxgi.posY + static_cast<int32_t>(dxgi.current_height) };
if (!dxgi.is_full_screen) {
// Set in window mode with the last saved position and size
SetWindowLongPtr(dxgi.h_wnd, GWL_STYLE, WS_VISIBLE | WS_OVERLAPPEDWINDOW);

if (dxgi.last_maximized_state) {
SetWindowPos(dxgi.h_wnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
ShowWindow(dxgi.h_wnd, SW_MAXIMIZE);
} else {
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
SetWindowPos(dxgi.h_wnd, NULL, wr.left, wr.top, wr.right - wr.left, wr.bottom - wr.top, SWP_FRAMECHANGED);
ShowWindow(dxgi.h_wnd, SW_RESTORE);
}
} else {
// Save if window is maximized or not
WINDOWPLACEMENT window_placement;
window_placement.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(dxgi.h_wnd, &window_placement);
dxgi.last_maximized_state = window_placement.showCmd == SW_SHOWMAXIMIZED;

// Set borderless full screen to that monitor
SetWindowLongPtr(dxgi.h_wnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
SetWindowPos(dxgi.h_wnd, HWND_TOP, wr.left, wr.top, wr.right - wr.left, wr.bottom - wr.top, SWP_FRAMECHANGED);
}
}

static void toggle_borderless_window_full_screen(bool enable, bool call_callback) {
// Windows 7 + flip mode + waitable object can't go to exclusive fullscreen,
// so do borderless instead. If DWM is enabled, this means we get one monitor
Expand All @@ -198,52 +234,37 @@ static void toggle_borderless_window_full_screen(bool enable, bool call_callback
return;
}

if (!enable) {
// Set in window mode with the last saved position and size
SetWindowLongPtr(dxgi.h_wnd, GWL_STYLE, WS_VISIBLE | WS_OVERLAPPEDWINDOW);
auto conf = Ship::Context::GetInstance()->GetConfig();

if (dxgi.last_maximized_state) {
SetWindowPos(dxgi.h_wnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
ShowWindow(dxgi.h_wnd, SW_MAXIMIZE);
} else {
if (!enable) {
if (!dxgi.last_maximized_state) {
std::tuple<HMONITOR, RECT, BOOL> Monitor;
auto conf = Ship::Context::GetInstance()->GetConfig();
dxgi.current_width = conf->GetInt("Window.Width", 640);
dxgi.current_height = conf->GetInt("Window.Height", 480);
dxgi.posX = conf->GetInt("Window.PositionX", 100);
dxgi.posY = conf->GetInt("Window.PositionY", 100);
if (!GetMonitorAtCoords(dxgi.monitor_list, dxgi.posX, dxgi.posY, dxgi.current_width, dxgi.current_height,
if (!GetMonitorAtCoords(dxgi.posX, dxgi.posY, dxgi.current_width, dxgi.current_height,
Monitor)) { // Fallback to default when out of bounds.
dxgi.posX = 100;
dxgi.posY = 100;
}
RECT wr = { dxgi.posX, dxgi.posY, dxgi.posX + static_cast<int32_t>(dxgi.current_width),
dxgi.posY + static_cast<int32_t>(dxgi.current_height) };
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
SetWindowPos(dxgi.h_wnd, NULL, wr.left, wr.top, wr.right - wr.left, wr.bottom - wr.top, SWP_FRAMECHANGED);
ShowWindow(dxgi.h_wnd, SW_RESTORE);
}

dxgi.is_full_screen = false;
} else {
dxgi.current_width = conf->GetInt("Window.Fullscreen.Width", 1920);
dxgi.current_height = conf->GetInt("Window.Fullscreen.Height", 1080);
dxgi.posX = 0;
dxgi.posY = 0;

// Save if window is maximized or not
WINDOWPLACEMENT window_placement;
window_placement.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(dxgi.h_wnd, &window_placement);
dxgi.last_maximized_state = window_placement.showCmd == SW_SHOWMAXIMIZED;
}

// We already know on what monitor we are (gets it on init or move)
// Get info from that monitor
RECT r = get<1>(dxgi.h_Monitor);
dxgi.is_full_screen = enable;

// Set borderless full screen to that monitor
SetWindowLongPtr(dxgi.h_wnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
// OTRTODO: This should be setting the resolution from config.
dxgi.current_width = r.right - r.left;
dxgi.current_height = r.bottom - r.top;
SetWindowPos(dxgi.h_wnd, HWND_TOP, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_FRAMECHANGED);
dxgi.is_full_screen = true;
}
apply_window_dimensions();

if (dxgi.on_fullscreen_changed != nullptr && call_callback) {
dxgi.on_fullscreen_changed(enable);
Expand Down Expand Up @@ -344,8 +365,7 @@ static LRESULT CALLBACK gfx_dxgi_wnd_proc(HWND h_wnd, UINT message, WPARAM w_par
case WM_SIZE:
dxgi.current_width = LOWORD(l_param);
dxgi.current_height = HIWORD(l_param);
GetMonitorAtCoords(dxgi.monitor_list, dxgi.posX, dxgi.posY, dxgi.current_width, dxgi.current_height,
newMonitor);
GetMonitorAtCoords(dxgi.posX, dxgi.posY, dxgi.current_width, dxgi.current_height, newMonitor);
if (get<0>(newMonitor) != get<0>(dxgi.h_Monitor)) {
dxgi.h_Monitor = newMonitor;
GetMonitorHzPeriod(dxgi.h_Monitor, dxgi.detected_hz, dxgi.display_period);
Expand All @@ -354,8 +374,7 @@ static LRESULT CALLBACK gfx_dxgi_wnd_proc(HWND h_wnd, UINT message, WPARAM w_par
case WM_MOVE:
dxgi.posX = GET_X_LPARAM(l_param);
dxgi.posY = GET_Y_LPARAM(l_param);
GetMonitorAtCoords(dxgi.monitor_list, dxgi.posX, dxgi.posY, dxgi.current_width, dxgi.current_height,
newMonitor);
GetMonitorAtCoords(dxgi.posX, dxgi.posY, dxgi.current_width, dxgi.current_height, newMonitor);
if (get<0>(newMonitor) != get<0>(dxgi.h_Monitor)) {
dxgi.h_Monitor = newMonitor;
GetMonitorHzPeriod(dxgi.h_Monitor, dxgi.detected_hz, dxgi.display_period);
Expand Down Expand Up @@ -433,9 +452,8 @@ static LRESULT CALLBACK gfx_dxgi_wnd_proc(HWND h_wnd, UINT message, WPARAM w_par

break;
case WM_DISPLAYCHANGE:
dxgi.monitor_list = GetMonitorList();
GetMonitorAtCoords(dxgi.monitor_list, dxgi.posX, dxgi.posY, dxgi.current_width, dxgi.current_height,
dxgi.h_Monitor);
UpdateMonitorList();
GetMonitorAtCoords(dxgi.posX, dxgi.posY, dxgi.current_width, dxgi.current_height, dxgi.h_Monitor);
GetMonitorHzPeriod(dxgi.h_Monitor, dxgi.detected_hz, dxgi.display_period);
break;
case WM_SETFOCUS:
Expand Down Expand Up @@ -502,11 +520,10 @@ void gfx_dxgi_init(const char* game_name, const char* gfx_api_name, bool start_i
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
dxgi.current_width = wr.right - wr.left;
dxgi.current_height = wr.bottom - wr.top;
dxgi.monitor_list = GetMonitorList();
UpdateMonitorList();
dxgi.posX = posX;
dxgi.posY = posY;
if (!GetMonitorAtCoords(dxgi.monitor_list, dxgi.posX, dxgi.posY, dxgi.current_width, dxgi.current_height,
dxgi.h_Monitor)) {
if (!GetMonitorAtCoords(dxgi.posX, dxgi.posY, dxgi.current_width, dxgi.current_height, dxgi.h_Monitor)) {
dxgi.posX = 100;
dxgi.posY = 100;
}
Expand Down Expand Up @@ -643,6 +660,19 @@ static void gfx_dxgi_get_dimensions(uint32_t* width, uint32_t* height, int32_t*
*posY = dxgi.posY;
}

static void gfx_dxgi_set_dimensions(uint32_t width, uint32_t height, int32_t posX, int32_t posY) {
dxgi.current_width = width;
dxgi.current_height = height;
dxgi.posX = posX;
dxgi.posY = posY;

apply_window_dimensions();
}

static Ship::WindowRect gfx_dxgi_get_primary_monitor_rect() {
return dxgi.monitor_rects[dxgi.primary_monitor_index];
}

static void gfx_dxgi_handle_events() {
MSG msg;
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
Expand Down Expand Up @@ -1057,6 +1087,8 @@ extern "C" struct GfxWindowManagerAPI gfx_dxgi_api = { gfx_dxgi_init,
gfx_dxgi_set_mouse_capture,
gfx_dxgi_is_mouse_captured,
gfx_dxgi_get_dimensions,
gfx_dxgi_set_dimensions,
gfx_dxgi_get_primary_monitor_rect,
gfx_dxgi_handle_events,
gfx_dxgi_start_frame,
gfx_dxgi_swap_buffers_begin,
Expand Down
Loading
Loading