mirror of
https://github.com/ayozetr/bloodborne_linux.git
synced 2026-11-08 08:03:07 -10:00
Name entry on screen and with a controller; AMD command buffer fixes (1.4)
- The game's text dialog (the character name) was only shown in the window title and took only the keyboard: in fullscreen or with a controller the character creation screen looked frozen. It is now a box on screen (overlay), starts with the launcher's player name or "Hunter", and Cross/Circle accept or cancel it. The game gets neutral input while it is open and until the buttons are released. - ExtraSharpen (sharpness above 1) and an FSR 4 rebuild (preset or output change) called Scheduler::Finish(), which submits the command buffer the caller is recording, and then kept recording into it: NVIDIA tolerates that, AMD's driver crashes. They now wait for the submitted work only (Scheduler::WaitSubmitted). Same issue as IFreemz's fix in shadPS4-Bloodborne-DLSS-FSR (3a02269).
This commit is contained in:
1 parent
edfe859f31
commit
1d34202b73
10 files changed
+97
-15
No files matched your search
@@ -79,11 +79,17 @@ struct Fsr4Upscaler::Impl {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void Destroy() {
|
||||
/// `recording`: called while a frame's command buffer is being recorded; it is left open
|
||||
/// (Finish() would submit it under the caller).
|
||||
void Destroy(bool recording = false) {
|
||||
if (!backend_ok && !context_ok) {
|
||||
return;
|
||||
}
|
||||
scheduler.Finish();
|
||||
if (recording) {
|
||||
scheduler.WaitSubmitted();
|
||||
} else {
|
||||
scheduler.Finish();
|
||||
}
|
||||
if (context_ok) {
|
||||
ffxFsr4V07DestroyContext(&context, nullptr);
|
||||
context_ok = false;
|
||||
@@ -283,9 +289,9 @@ struct Fsr4Upscaler::Impl {
|
||||
const int preset = std::clamp(f.preset, 0, 4);
|
||||
if (!context_ok || preset != model || f.output.width != out_width ||
|
||||
f.output.height != out_height) {
|
||||
Destroy();
|
||||
Destroy(true);
|
||||
if (!CreateBackend(preset, f.output.width, f.output.height)) {
|
||||
Destroy();
|
||||
Destroy(true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,6 +332,13 @@ void Scheduler::Finish() {
|
||||
Wait(presubmit_tick);
|
||||
}
|
||||
|
||||
void Scheduler::WaitSubmitted() {
|
||||
const u64 tick = CurrentTick();
|
||||
if (tick > 1) {
|
||||
Wait(tick - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Scheduler::Wait(u64 tick) {
|
||||
if (tick >= work_semaphore.CurrentTick()) {
|
||||
// Make sure we are not waiting for the current tick without signalling
|
||||
|
||||
@@ -682,6 +682,11 @@ public:
|
||||
/// Sends the current execution context to the GPU and waits for it to complete.
|
||||
void Finish();
|
||||
|
||||
/// bbport: waits for the work submitted so far but leaves the command buffer being
|
||||
/// recorded open, so a CommandBuffer() the caller holds stays valid (Finish() submits it:
|
||||
/// recording into a submitted buffer crashes AMD's driver).
|
||||
void WaitSubmitted();
|
||||
|
||||
/// Waits for the given tick to trigger on the GPU.
|
||||
void Wait(u64 tick);
|
||||
|
||||
|
||||
@@ -728,8 +728,8 @@ void TemporalUpscaler::ExtraSharpen(vk::CommandBuffer cmdbuf, vk::Image target,
|
||||
}
|
||||
const auto device = instance.GetDevice();
|
||||
if (extra_sharpen_width != w || extra_sharpen_height != h) {
|
||||
// Retired command buffers may still read the old copy.
|
||||
scheduler.Finish();
|
||||
// Retired command buffers may still read the old copy. `cmdbuf` stays open.
|
||||
scheduler.WaitSubmitted();
|
||||
extra_sharpen_view.reset();
|
||||
extra_sharpen_image = VideoCore::UniqueImage(device, instance.GetAllocator());
|
||||
extra_sharpen_image.Create(vk::ImageCreateInfo{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "bbport_overlay.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cfloat>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
@@ -51,6 +52,9 @@ bool initialized = false;
|
||||
std::atomic<bool> menu_open{false};
|
||||
bool l3_down = false, r3_down = false;
|
||||
bool dirty = false; // settings changed while open: saved on close
|
||||
// The game's text dialog (SetTextEntry), guarded by imgui_mutex.
|
||||
bool text_entry_active = false;
|
||||
std::string text_entry_prompt, text_entry_text;
|
||||
float base_scale = 1.0f;
|
||||
|
||||
// Present rate for the FPS counter.
|
||||
@@ -389,6 +393,30 @@ void Menu() {
|
||||
}
|
||||
}
|
||||
|
||||
// The game's text dialog: what is typed, and how to finish (keyboard or controller).
|
||||
void TextEntryBox() {
|
||||
const ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
ImGui::SetNextWindowPos(ImVec2(viewport->WorkPos.x + viewport->WorkSize.x * 0.5f,
|
||||
viewport->WorkPos.y + viewport->WorkSize.y * 0.42f),
|
||||
ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(viewport->WorkSize.x * 0.32f, 0.0f),
|
||||
ImVec2(viewport->WorkSize.x * 0.8f, FLT_MAX));
|
||||
ImGui::SetNextWindowBgAlpha(0.92f);
|
||||
ImGui::Begin("##text_entry", nullptr,
|
||||
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize |
|
||||
ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoNav |
|
||||
ImGuiWindowFlags_NoFocusOnAppearing);
|
||||
ImGui::TextColored(ImVec4(0.85f, 0.72f, 0.45f, 1.0f), "%s", text_entry_prompt.c_str());
|
||||
ImGui::Separator();
|
||||
ImGui::SetWindowFontScale(1.4f);
|
||||
ImGui::Text("%s_", text_entry_text.c_str());
|
||||
ImGui::SetWindowFontScale(1.0f);
|
||||
ImGui::Separator();
|
||||
ImGui::TextDisabled("Keyboard: type, Backspace to erase, Enter = OK, Esc = cancel");
|
||||
ImGui::TextDisabled("Controller: Cross (A) = OK, Circle (B) = cancel");
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void FpsCounter() {
|
||||
const ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
const float pad = 12.0f * base_scale;
|
||||
@@ -579,11 +607,18 @@ bool HandleEvent(const SDL_Event& event) {
|
||||
}
|
||||
|
||||
bool Visible() {
|
||||
return initialized && (menu_open || BbSettings::Get().show_fps);
|
||||
return initialized && (menu_open || text_entry_active || BbSettings::Get().show_fps);
|
||||
}
|
||||
|
||||
bool CapturesInput() {
|
||||
return menu_open;
|
||||
return menu_open || text_entry_active;
|
||||
}
|
||||
|
||||
void SetTextEntry(bool active, const std::string& prompt, const std::string& text) {
|
||||
std::scoped_lock lock{imgui_mutex};
|
||||
text_entry_active = active;
|
||||
text_entry_prompt = prompt;
|
||||
text_entry_text = text;
|
||||
}
|
||||
|
||||
void Render(vk::CommandBuffer cmdbuf, vk::ImageView view, vk::Extent2D extent) {
|
||||
@@ -618,6 +653,9 @@ void Render(vk::CommandBuffer cmdbuf, vk::ImageView view, vk::Extent2D extent) {
|
||||
if (BbSettings::Get().show_fps && !menu_open) {
|
||||
FpsCounter();
|
||||
}
|
||||
if (text_entry_active) {
|
||||
TextEntryBox();
|
||||
}
|
||||
ImGui::Render();
|
||||
|
||||
const vk::RenderingAttachmentInfo attachment{
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "common/types.h"
|
||||
#include "video_core/renderer_vulkan/vk_common.h"
|
||||
|
||||
@@ -31,7 +32,11 @@ bool Visible();
|
||||
/// Present thread: draws into `view` (layout ColorAttachmentOptimal).
|
||||
void Render(vk::CommandBuffer cmdbuf, vk::ImageView view, vk::Extent2D extent);
|
||||
|
||||
/// The menu is open: the game's input is held neutral.
|
||||
/// The menu is open or a text entry is shown: the game's input is held neutral.
|
||||
bool CapturesInput();
|
||||
|
||||
/// Window thread: the game's text dialog (sceImeDialog). Shown as a box on screen until
|
||||
/// `active` is false; typing goes to the window (sdl_window), the box only displays it.
|
||||
void SetTextEntry(bool active, const std::string& prompt, const std::string& text);
|
||||
|
||||
} // namespace BbOverlay
|
||||
@@ -77,6 +77,7 @@ void WindowSDL::UpdateTextTitle() {
|
||||
const std::string title = text_active ? base_title + " \u2014 " + text_prompt + ": " + text + "_ (Enter = OK, Esc = cancel)"
|
||||
: base_title;
|
||||
SDL_SetWindowTitle(window, title.c_str());
|
||||
BbOverlay::SetTextEntry(text_active, text_prompt, text);
|
||||
}
|
||||
|
||||
bool WindowSDL::PollEvents() {
|
||||
@@ -110,6 +111,17 @@ bool WindowSDL::PollEvents() {
|
||||
UpdateTextTitle();
|
||||
continue;
|
||||
}
|
||||
// The controller finishes the text dialog too: Cross (A) accepts, Circle (B) cancels.
|
||||
if (text_active && event.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN &&
|
||||
(event.gbutton.button == SDL_GAMEPAD_BUTTON_SOUTH ||
|
||||
event.gbutton.button == SDL_GAMEPAD_BUTTON_EAST)) {
|
||||
std::scoped_lock lock{text_mutex};
|
||||
text_state = event.gbutton.button == SDL_GAMEPAD_BUTTON_SOUTH ? 1 : 2;
|
||||
text_active = false;
|
||||
SDL_StopTextInput(window);
|
||||
UpdateTextTitle();
|
||||
continue;
|
||||
}
|
||||
if (BbOverlay::HandleEvent(event)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ PATCH_VERSION = '01.09'
|
||||
MAX_LOG_LINES = 6000
|
||||
NO_WINDOW = getattr(subprocess, 'CREATE_NO_WINDOW', 0)
|
||||
# This build; GitHub release tags are windows-v<VERSION>.
|
||||
VERSION = '1.3'
|
||||
VERSION = '1.4'
|
||||
RELEASES_API = 'https://api.github.com/repos/Supermedo/bloodborne_pc/releases/latest'
|
||||
RELEASES_PAGE = 'https://github.com/Supermedo/bloodborne_pc/releases/latest'
|
||||
UPDATE_DIR = Path(tempfile.gettempdir()) / 'bbport-update'
|
||||
|
||||
+8
-1
@@ -270,9 +270,12 @@ static void replay_sample(PadData *d) {
|
||||
d->left_x=s->axes[0]; d->left_y=s->axes[1]; d->right_x=s->axes[2]; d->right_y=s->axes[3];
|
||||
d->l2=s->l2; d->r2=s->r2;
|
||||
}
|
||||
/* After the menu or the text dialog closes, buttons still held (the Cross that accepted a
|
||||
* name) stay hidden until released: the game would take them as a new press. */
|
||||
static int hold_after_capture;
|
||||
static void sample(PadData *d) {
|
||||
sample_host(d);
|
||||
if (bbgpu_overlay_captures_input()) return;
|
||||
if (bbgpu_overlay_captures_input()) { hold_after_capture=1; return; }
|
||||
record_sample(d);
|
||||
read_inject();
|
||||
replay_sample(d);
|
||||
@@ -283,6 +286,10 @@ static void sample(PadData *d) {
|
||||
if (injected.buttons & BTN_R2) d->r2=255;
|
||||
uint8_t *axes[4]={&d->left_x,&d->left_y,&d->right_x,&d->right_y};
|
||||
for (int i=0;i<4;++i) if (injected.stick[i]>=0) *axes[i]=(uint8_t)injected.stick[i];
|
||||
if (hold_after_capture) {
|
||||
if (d->buttons) d->buttons=0;
|
||||
else hold_after_capture=0;
|
||||
}
|
||||
}
|
||||
|
||||
static ABI int32_t pad_init(void) { pthread_mutex_lock(&lock); initialized=1; pthread_mutex_unlock(&lock); return 0; }
|
||||
|
||||
@@ -258,10 +258,12 @@ static ABI int32_t ime_init(const ImeParam *param, const void *extended) {
|
||||
utf16_to_utf8(param->title,128,prompt,sizeof(prompt));
|
||||
const char *preset=getenv("BB_IME_TEXT");
|
||||
if (preset) { ime_complete(0,preset); return 0; }
|
||||
if (!bbgpu_text_input_begin(initial,prompt[0] ? prompt : "Text")) {
|
||||
const char *name=getenv("BB_USER_NAME");
|
||||
ime_complete(0,name ? name : initial[0] ? initial : "Hunter");
|
||||
} else printf("Runtime: ImeDialog opened: type in the game window, Enter to confirm, Esc to cancel\n");
|
||||
/* An empty field starts with the player name (launcher) or "Hunter": a controller alone
|
||||
* can accept it (the port has no on-screen keyboard). */
|
||||
const char *name=getenv("BB_USER_NAME");
|
||||
const char *start=initial[0] ? initial : name && *name ? name : "Hunter";
|
||||
if (!bbgpu_text_input_begin(start,prompt[0] ? prompt : "Text")) ime_complete(0,start);
|
||||
else printf("Runtime: ImeDialog opened: shown on screen; keyboard Enter or Cross accepts, Esc or Circle cancels\n");
|
||||
return 0;
|
||||
}
|
||||
static ABI int32_t ime_status(void) {
|
||||
|
||||
Reference in new issue
Block a user