mirror of
https://github.com/Mrsuss60/bloodborne_pc_windows_port.git
synced 2026-11-07 05:56:20 -10:00
Port upstream improvements from deadinside28/bloodborne_pc (commit 8185b88): 1. Launcher GPU Selection & Complete 21-Language Support (#249): - Added `--gpus` CLI argument to `tools/gpu_capabilities.c` to enumerate all available Vulkan physical devices with vendor ID, device type, name, and default ranking. - Added a "GPU Adapter" dropdown under "Draw Prep Workers" in the launcher UI to allow explicit device selection on multi-GPU systems and laptops. - Expanded the launcher's Game Text Language selector to include all 21 localized PS4 text languages supported by Bloodborne. - Choices persist in configuration and pass `BB_GPU_ID` and `BB_LANGUAGE` to the engine runtime. 2. Crash 0xa0020007 (Code 23) Blur Kernel Clamp: - Implemented `raise_exception` in `src/runtime_kernel.c` bound to NIDs `OMDRKKAZ8I4#p#J` and `zE-wXIZjLoM#p#J`. - Filtered out non-fatal blur-kernel assertions (`code == 0xa0020007u`) from Yebis at call ranges 0xbbc3e0..0xbbc700 and 0xc33000..0xc34200 unless explicitly stopped with `BB_GAME_ASSERT_STOP=1`. - Added entry hook at `image + 0xbbc3e0` (`GPUTexUtil_GetRecursiveSampleParameters`) in `src/probe.c` to clamp sample count `edi >= 3`, preventing black screens and assertion trips during recursive texture sampling. Upstream credits: - deadinside28/bloodborne_pc@8185b88 Closes #126
160 lines
7.3 KiB
C
160 lines
7.3 KiB
C
/* Check whether native-size depth/stencil images can be blitted to reduced
|
|
* renderer targets. The renderer needs both directions for live presets. */
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <vulkan/vulkan.h>
|
|
|
|
static VkDeviceSize largest_local_heap(VkPhysicalDevice device) {
|
|
VkPhysicalDeviceMemoryProperties memory;
|
|
vkGetPhysicalDeviceMemoryProperties(device, &memory);
|
|
VkDeviceSize largest = 0;
|
|
for (uint32_t i = 0; i < memory.memoryHeapCount; ++i) {
|
|
if ((memory.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) &&
|
|
memory.memoryHeaps[i].size > largest) {
|
|
largest = memory.memoryHeaps[i].size;
|
|
}
|
|
}
|
|
return largest;
|
|
}
|
|
|
|
static int better_device(VkPhysicalDevice candidate, VkPhysicalDevice current) {
|
|
VkPhysicalDeviceProperties next, old;
|
|
vkGetPhysicalDeviceProperties(candidate, &next);
|
|
vkGetPhysicalDeviceProperties(current, &old);
|
|
const int next_api = next.apiVersion >= VK_API_VERSION_1_3;
|
|
const int old_api = old.apiVersion >= VK_API_VERSION_1_3;
|
|
if (next_api != old_api) return next_api;
|
|
const int next_discrete = next.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
|
|
const int old_discrete = old.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
|
|
if (next_discrete != old_discrete) return next_discrete;
|
|
const int next_cpu = next.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU;
|
|
const int old_cpu = old.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU;
|
|
if (next_cpu != old_cpu) return !next_cpu;
|
|
return largest_local_heap(candidate) > largest_local_heap(current);
|
|
}
|
|
|
|
/* --live-resolution: prints 1 when live resolution changes suit the GPU (run.sh, setting
|
|
* live_resolution=auto), else 0. Live scaling keeps the game's post-processing at 1080p and
|
|
* copies scene targets every frame: fine on a strong discrete GPU, 7-8 FPS on the Steam Deck
|
|
* and a GTX 1060. Rule: discrete, at least 8 GB of device memory, and not an NVIDIA GPU older
|
|
* than Turing (no fragment shader barycentrics; its depth/stencil copies take nine draws). */
|
|
static int has_extension(VkPhysicalDevice device, const char *name) {
|
|
uint32_t count = 0;
|
|
if (vkEnumerateDeviceExtensionProperties(device, NULL, &count, NULL) != VK_SUCCESS) return 0;
|
|
VkExtensionProperties *list = calloc(count ? count : 1, sizeof(*list));
|
|
int found = 0;
|
|
if (list && vkEnumerateDeviceExtensionProperties(device, NULL, &count, list) == VK_SUCCESS)
|
|
for (uint32_t i = 0; i < count && !found; ++i) found = !strcmp(list[i].extensionName, name);
|
|
free(list);
|
|
return found;
|
|
}
|
|
|
|
static int live_resolution_suits(VkPhysicalDevice device) {
|
|
VkPhysicalDeviceProperties props;
|
|
vkGetPhysicalDeviceProperties(device, &props);
|
|
const int discrete = props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
|
|
const VkDeviceSize memory = largest_local_heap(device);
|
|
const int old_nvidia = props.vendorID == 0x10de &&
|
|
!has_extension(device, "VK_KHR_fragment_shader_barycentric");
|
|
const int suits = discrete && memory >= (VkDeviceSize)7680 << 20 && !old_nvidia;
|
|
fprintf(stderr, "GPU: %s, %s, %llu MiB: live resolution changes %s\n", props.deviceName,
|
|
discrete ? "discrete" : "integrated or other", (unsigned long long)(memory >> 20),
|
|
suits ? "on" : "off (startup resolution patch)");
|
|
return suits;
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
const int live_mode = argc > 1 && !strcmp(argv[1], "--live-resolution");
|
|
const VkApplicationInfo app = {
|
|
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
|
.pApplicationName = "bbport scene scaling probe",
|
|
.apiVersion = VK_API_VERSION_1_3,
|
|
};
|
|
const VkInstanceCreateInfo create = {
|
|
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
|
.pApplicationInfo = &app,
|
|
};
|
|
VkInstance instance = VK_NULL_HANDLE;
|
|
if (vkCreateInstance(&create, NULL, &instance) != VK_SUCCESS) {
|
|
fputs("GPU scene scaling: cannot create Vulkan instance\n", stderr);
|
|
return 1;
|
|
}
|
|
uint32_t count = 0;
|
|
if (vkEnumeratePhysicalDevices(instance, &count, NULL) != VK_SUCCESS || !count) {
|
|
fputs("GPU scene scaling: no Vulkan device\n", stderr);
|
|
vkDestroyInstance(instance, NULL);
|
|
return 1;
|
|
}
|
|
VkPhysicalDevice *devices = calloc(count, sizeof(*devices));
|
|
if (!devices || vkEnumeratePhysicalDevices(instance, &count, devices) != VK_SUCCESS) {
|
|
fputs("GPU scene scaling: cannot enumerate Vulkan devices\n", stderr);
|
|
free(devices);
|
|
vkDestroyInstance(instance, NULL);
|
|
return 1;
|
|
}
|
|
if (argc > 1 && !strcmp(argv[1], "--gpus")) {
|
|
VkPhysicalDevice best = devices[0];
|
|
for (uint32_t i = 1; i < count; ++i)
|
|
if (better_device(devices[i], best)) best = devices[i];
|
|
static const char *const types[] = {"other", "integrated", "discrete", "virtual", "cpu"};
|
|
for (uint32_t i = 0; i < count; ++i) {
|
|
VkPhysicalDeviceProperties props;
|
|
vkGetPhysicalDeviceProperties(devices[i], &props);
|
|
const unsigned type = props.deviceType <= VK_PHYSICAL_DEVICE_TYPE_CPU ? props.deviceType : 0;
|
|
printf("%u\t%#06x\t%s\t%s\t%d\n", i, props.vendorID, types[type], props.deviceName,
|
|
devices[i] == best);
|
|
}
|
|
free(devices);
|
|
vkDestroyInstance(instance, NULL);
|
|
return 0;
|
|
}
|
|
/* Match vk_instance.cpp's default ranking or its explicit BB_GPU_ID index. */
|
|
VkPhysicalDevice selected = devices[0];
|
|
const char *gpu_id = getenv("BB_GPU_ID");
|
|
if (gpu_id && atoi(gpu_id) >= 0) {
|
|
const unsigned long index = strtoul(gpu_id, NULL, 10);
|
|
if (index >= count) {
|
|
fputs("GPU scene scaling: BB_GPU_ID is outside the device list\n", stderr);
|
|
free(devices);
|
|
vkDestroyInstance(instance, NULL);
|
|
return 1;
|
|
}
|
|
selected = devices[index];
|
|
} else {
|
|
for (uint32_t i = 1; i < count; ++i)
|
|
if (better_device(devices[i], selected)) selected = devices[i];
|
|
}
|
|
if (live_mode) {
|
|
printf("%d\n", live_resolution_suits(selected));
|
|
free(devices);
|
|
vkDestroyInstance(instance, NULL);
|
|
return 0;
|
|
}
|
|
VkPhysicalDeviceProperties props;
|
|
vkGetPhysicalDeviceProperties(selected, &props);
|
|
const struct { VkFormat format; const char *name; } formats[] = {
|
|
{VK_FORMAT_R8G8B8A8_UNORM, "RGBA8"},
|
|
{VK_FORMAT_R8G8B8A8_SRGB, "RGBA8 sRGB"},
|
|
{VK_FORMAT_B10G11R11_UFLOAT_PACK32, "B10G11R11"},
|
|
{VK_FORMAT_R16G16B16A16_SFLOAT, "RGBA16F"},
|
|
{VK_FORMAT_D32_SFLOAT_S8_UINT, "D32S8"},
|
|
};
|
|
int supported = 1;
|
|
for (size_t i = 0; i < sizeof(formats) / sizeof(formats[0]); ++i) {
|
|
VkFormatProperties features;
|
|
vkGetPhysicalDeviceFormatProperties(selected, formats[i].format, &features);
|
|
const VkFormatFeatureFlags required = VK_FORMAT_FEATURE_BLIT_SRC_BIT |
|
|
VK_FORMAT_FEATURE_BLIT_DST_BIT;
|
|
if ((features.optimalTilingFeatures & required) != required) {
|
|
fprintf(stderr, "GPU scene scaling: %s lacks blit support for %s\n",
|
|
props.deviceName, formats[i].name);
|
|
supported = 0;
|
|
}
|
|
}
|
|
if (supported) fprintf(stderr, "GPU scene scaling: %s supports live presets\n", props.deviceName);
|
|
free(devices);
|
|
vkDestroyInstance(instance, NULL);
|
|
return supported ? 0 : 1;
|
|
}
|