diff --git a/src/graphic/Fast3D/Fast3dWindow.cpp b/src/graphic/Fast3D/Fast3dWindow.cpp index 44ba7a416..74960255f 100644 --- a/src/graphic/Fast3D/Fast3dWindow.cpp +++ b/src/graphic/Fast3D/Fast3dWindow.cpp @@ -152,6 +152,38 @@ void Fast3dWindow::StartFrame() { } void Fast3dWindow::EndFrame() { + gfx_end_frame(); +} + +bool Fast3dWindow::IsFrameReady() { + return mWindowManagerApi->is_frame_ready(); +} + +bool Fast3dWindow::DrawAndRunGraphicsCommands(Gfx* commands, const std::unordered_map& mtxReplacements) { + std::shared_ptr wnd = Ship::Context::GetInstance()->GetWindow(); + + // Skip dropped frames + if (!wnd->IsFrameReady()) { + return false; + } + + auto gui = wnd->GetGui(); + // Setup of the backend frames and draw initial Window and GUI menus + gui->StartDraw(); + // Setup game framebuffers to match available window space + gfx_start_frame(); + // Execute the games gfx commands + gfx_run(commands, mtxReplacements); + // Renders the game frame buffer to the final window and finishes the GUI + gui->EndDraw(); + // Finalize swap buffers + gfx_end_frame(); + + return true; +} + +void Fast3dWindow::HandleEvents() { + mWindowManagerApi->handle_events(); } void Fast3dWindow::SetCursorVisibility(bool visible) { diff --git a/src/graphic/Fast3D/Fast3dWindow.h b/src/graphic/Fast3D/Fast3dWindow.h index 86676cf9d..5e99e5630 100644 --- a/src/graphic/Fast3D/Fast3dWindow.h +++ b/src/graphic/Fast3D/Fast3dWindow.h @@ -5,6 +5,8 @@ #include "public/bridge/gfxbridge.h" #include "controller/controldevice/controller/mapping/keyboard/KeyboardScancodes.h" +union Gfx; + namespace Fast { class Fast3dWindow : public Ship::Window { public: @@ -16,6 +18,8 @@ class Fast3dWindow : public Ship::Window { void Close() override; void StartFrame() override; void EndFrame() override; + bool IsFrameReady() override; + void HandleEvents() override; void SetCursorVisibility(bool visible) override; uint32_t GetWidth() override; uint32_t GetHeight() override; @@ -46,6 +50,7 @@ class Fast3dWindow : public Ship::Window { void SetTextureFilter(FilteringMode filteringMode); void SetRendererUCode(UcodeHandlers ucode); void EnableSRGBMode(); + bool DrawAndRunGraphicsCommands(Gfx* commands, const std::unordered_map& mtxReplacements); protected: static bool KeyDown(int32_t scancode); diff --git a/src/graphic/Fast3D/gfx_dxgi.cpp b/src/graphic/Fast3D/gfx_dxgi.cpp index b607bffc5..9efba684f 100644 --- a/src/graphic/Fast3D/gfx_dxgi.cpp +++ b/src/graphic/Fast3D/gfx_dxgi.cpp @@ -664,7 +664,7 @@ static uint64_t qpc_to_100ns(uint64_t qpc) { qpc % dxgi.qpc_freq * _100NANOSECONDS_IN_SECOND / dxgi.qpc_freq; } -static bool gfx_dxgi_start_frame() { +static bool gfx_dxgi_is_frame_ready() { DXGI_FRAME_STATISTICS stats; if (dxgi.swap_chain->GetFrameStatistics(&stats) == S_OK && (stats.SyncRefreshCount != 0 || stats.SyncQPCTime.QuadPart != 0ULL)) { @@ -1058,7 +1058,7 @@ extern "C" struct GfxWindowManagerAPI gfx_dxgi_api = { gfx_dxgi_init, gfx_dxgi_is_mouse_captured, gfx_dxgi_get_dimensions, gfx_dxgi_handle_events, - gfx_dxgi_start_frame, + gfx_dxgi_is_frame_ready, gfx_dxgi_swap_buffers_begin, gfx_dxgi_swap_buffers_end, gfx_dxgi_get_time, diff --git a/src/graphic/Fast3D/gfx_metal.cpp b/src/graphic/Fast3D/gfx_metal.cpp index d8c972a70..62a1238cf 100644 --- a/src/graphic/Fast3D/gfx_metal.cpp +++ b/src/graphic/Fast3D/gfx_metal.cpp @@ -234,13 +234,11 @@ bool Metal_Init(SDL_Renderer* renderer) { static void gfx_metal_setup_screen_framebuffer(uint32_t width, uint32_t height); -void Metal_SetupFrame(SDL_Renderer* renderer) { +void Metal_NewFrame(SDL_Renderer* renderer) { int width, height; SDL_GetRendererOutputSize(renderer, &width, &height); gfx_metal_setup_screen_framebuffer(width, height); -} -void Metal_NewFrame(SDL_Renderer* renderer) { MTL::RenderPassDescriptor* current_render_pass = mctx.framebuffers[0].render_pass_descriptor; ImGui_ImplMetal_NewFrame(current_render_pass); } diff --git a/src/graphic/Fast3D/gfx_metal.h b/src/graphic/Fast3D/gfx_metal.h index c014b234e..b8cea7d78 100644 --- a/src/graphic/Fast3D/gfx_metal.h +++ b/src/graphic/Fast3D/gfx_metal.h @@ -20,7 +20,6 @@ ImTextureID gfx_metal_get_texture_by_id(int id); bool Metal_IsSupported(); bool Metal_Init(SDL_Renderer* renderer); -void Metal_SetupFrame(SDL_Renderer* renderer); void Metal_NewFrame(SDL_Renderer* renderer); void Metal_SetupFloatingFrame(); void Metal_RenderDrawData(ImDrawData* draw_data); diff --git a/src/graphic/Fast3D/gfx_pc.cpp b/src/graphic/Fast3D/gfx_pc.cpp index 4b6fcb3e0..87fd5964b 100644 --- a/src/graphic/Fast3D/gfx_pc.cpp +++ b/src/graphic/Fast3D/gfx_pc.cpp @@ -113,8 +113,6 @@ static int game_framebuffer_msaa_resolved; uint32_t gfx_msaa_level = 1; -static bool dropped_frame; - static const std::unordered_map* current_mtx_replacements; static float buf_vbo[MAX_BUFFERED * (32 * 3)]; // 3 vertices in a triangle and 32 floats per vtx @@ -4123,8 +4121,15 @@ struct GfxRenderingAPI* gfx_get_current_rendering_api() { return gfx_rapi; } -void gfx_start_frame() { +void gfx_handle_window_events() { gfx_wapi->handle_events(); +} + +bool gfx_is_frame_ready() { + return gfx_wapi->is_frame_ready(); +} + +void gfx_start_frame() { gfx_wapi->get_dimensions(&gfx_current_window_dimensions.width, &gfx_current_window_dimensions.height, &gfx_current_window_position_x, &gfx_current_window_position_y); if (gfx_current_dimensions.height == 0) { @@ -4184,20 +4189,11 @@ void gfx_start_frame() { GfxExecStack g_exec_stack = {}; void gfx_run(Gfx* commands, const std::unordered_map& mtx_replacements) { - Ship::Context::GetInstance()->GetWindow()->GetGui()->SetupRendererFrame(); - gfx_sp_reset(); get_pixel_depth_pending.clear(); get_pixel_depth_cached.clear(); - if (!gfx_wapi->start_frame()) { - dropped_frame = true; - Ship::Context::GetInstance()->GetWindow()->GetGui()->Draw(); - return; - } - dropped_frame = false; - current_mtx_replacements = &mtx_replacements; gfx_rapi->update_framebuffer_parameters(0, gfx_current_window_dimensions.width, @@ -4261,16 +4257,13 @@ void gfx_run(Gfx* commands, const std::unordered_map& mtx_replacemen assert(0 && "active framebuffer was never reset back to original"); } - Ship::Context::GetInstance()->GetWindow()->GetGui()->Draw(); - gfx_rapi->end_frame(); - gfx_wapi->swap_buffers_begin(); } void gfx_end_frame() { - if (!dropped_frame) { - gfx_rapi->finish_render(); - gfx_wapi->swap_buffers_end(); - } + gfx_rapi->end_frame(); + gfx_wapi->swap_buffers_begin(); + gfx_rapi->finish_render(); + gfx_wapi->swap_buffers_end(); } void gfx_set_target_ucode(UcodeHandlers ucode) { diff --git a/src/graphic/Fast3D/gfx_pc.h b/src/graphic/Fast3D/gfx_pc.h index 38fab091b..ef08c428b 100644 --- a/src/graphic/Fast3D/gfx_pc.h +++ b/src/graphic/Fast3D/gfx_pc.h @@ -235,6 +235,8 @@ void gfx_start_frame(); // Since this function is "exposted" to the games, it needs to take a normal Gfx void gfx_run(Gfx* commands, const std::unordered_map& mtx_replacements); +void gfx_handle_window_events(); +bool gfx_is_frame_ready(); void gfx_end_frame(); void gfx_set_target_ucode(UcodeHandlers ucode); void gfx_set_target_fps(int); diff --git a/src/graphic/Fast3D/gfx_sdl2.cpp b/src/graphic/Fast3D/gfx_sdl2.cpp index a4027d647..228dc8ecc 100644 --- a/src/graphic/Fast3D/gfx_sdl2.cpp +++ b/src/graphic/Fast3D/gfx_sdl2.cpp @@ -600,7 +600,7 @@ static void gfx_sdl_handle_events() { } } -static bool gfx_sdl_start_frame() { +static bool gfx_sdl_is_frame_ready() { return true; } @@ -709,7 +709,7 @@ struct GfxWindowManagerAPI gfx_sdl = { gfx_sdl_init, gfx_sdl_is_mouse_captured, gfx_sdl_get_dimensions, gfx_sdl_handle_events, - gfx_sdl_start_frame, + gfx_sdl_is_frame_ready, gfx_sdl_swap_buffers_begin, gfx_sdl_swap_buffers_end, gfx_sdl_get_time, diff --git a/src/graphic/Fast3D/gfx_window_manager_api.h b/src/graphic/Fast3D/gfx_window_manager_api.h index 9fd3555db..3cc99c174 100644 --- a/src/graphic/Fast3D/gfx_window_manager_api.h +++ b/src/graphic/Fast3D/gfx_window_manager_api.h @@ -24,7 +24,7 @@ struct GfxWindowManagerAPI { bool (*is_mouse_captured)(); void (*get_dimensions)(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY); void (*handle_events)(); - bool (*start_frame)(); + bool (*is_frame_ready)(); void (*swap_buffers_begin)(); void (*swap_buffers_end)(); double (*get_time)(); // For debug diff --git a/src/window/Window.h b/src/window/Window.h index 708b29bfe..5a1c83d17 100644 --- a/src/window/Window.h +++ b/src/window/Window.h @@ -36,6 +36,8 @@ class Window { virtual void Close() = 0; virtual void StartFrame() = 0; virtual void EndFrame() = 0; + virtual bool IsFrameReady() = 0; + virtual void HandleEvents() = 0; virtual void SetCursorVisibility(bool visible) = 0; virtual uint32_t GetWidth() = 0; virtual uint32_t GetHeight() = 0; diff --git a/src/window/gui/Gui.cpp b/src/window/gui/Gui.cpp index 281dadad6..fad42a985 100644 --- a/src/window/gui/Gui.cpp +++ b/src/window/gui/Gui.cpp @@ -566,7 +566,7 @@ void Gui::EndFrame() { ImGui::EndFrame(); } -void Gui::DrawGame() { +void Gui::CalculateGameViewport() { ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_ChildBorderSize, 0.0f); @@ -617,10 +617,25 @@ void Gui::DrawGame() { } } + ImGui::End(); +} + +void Gui::DrawGame() { + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_ChildBorderSize, 0.0f); + ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); + ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground; + + ImGui::Begin("Main Game", nullptr, flags); + ImGui::PopStyleVar(3); + ImGui::PopStyleColor(); + GetGameOverlay()->Draw(); - mainPos = ImGui::GetWindowPos(); - size = ImGui::GetContentRegionAvail(); + ImVec2 mainPos = ImGui::GetWindowPos(); + ImVec2 size = ImGui::GetContentRegionAvail(); ImVec2 pos = ImVec2(0, 0); if (CVarGetInteger(CVAR_LOW_RES_MODE, 0) == 1) { // N64 Mode takes priority const float sw = size.y * 320.0f / 240.0f; @@ -695,11 +710,16 @@ void Gui::CheckSaveCvars() { } } -void Gui::Draw() { +void Gui::StartDraw() { // Initialize the frame. StartFrame(); // Draw the gui menus DrawMenu(); + // Calculate the available space the game can render to + CalculateGameViewport(); +} + +void Gui::EndDraw() { // Draw the game framebuffer into ImGui DrawGame(); // End the frame @@ -710,18 +730,6 @@ void Gui::Draw() { CheckSaveCvars(); } -void Gui::SetupRendererFrame() { - switch (Context::GetInstance()->GetWindow()->GetWindowBackend()) { -#ifdef __APPLE__ - case WindowBackend::FAST3D_SDL_METAL: - Metal_SetupFrame(mImpl.Metal.Renderer); - break; -#endif - default: - break; - } -} - ImTextureID Gui::GetTextureById(int32_t id) { #ifdef ENABLE_DX11 if (Context::GetInstance()->GetWindow()->GetWindowBackend() == WindowBackend::FAST3D_DXGI_DX11) { diff --git a/src/window/gui/Gui.h b/src/window/gui/Gui.h index 10d09c865..2b017b07c 100644 --- a/src/window/gui/Gui.h +++ b/src/window/gui/Gui.h @@ -72,9 +72,9 @@ class Gui { ~Gui(); void Init(GuiWindowInitData windowImpl); - void Draw(); + void StartDraw(); + void EndDraw(); void HandleWindowEvents(WindowEvent event); - void SetupRendererFrame(); void SaveConsoleVariablesNextFrame(); bool SupportsViewports(); ImGuiID GetMainGameWindowID(); @@ -112,6 +112,7 @@ class Gui { void DrawFloatingWindows(); void DrawMenu(); void DrawGame(); + void CalculateGameViewport(); void ImGuiBackendNewFrame(); void ImGuiWMNewFrame();