mirror of
https://github.com/Swordpdf/ProsperoEden.git
synced 2026-10-19 04:09:47 -05:00
87 lines
4.1 KiB
C++
87 lines
4.1 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
#include "core/frontend/emu_window.h"
|
|
#include "video_core/vulkan_common/vulkan_surface.h"
|
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
|
#include "display_refresh.h"
|
|
#include <vector>
|
|
#include <cstdio>
|
|
|
|
namespace Vulkan {
|
|
vk::SurfaceKHR CreateSurface(const vk::Instance& instance,
|
|
const Core::Frontend::EmuWindow::WindowSystemInfo& window_info) {
|
|
if (window_info.type != Core::Frontend::WindowSystemType::PS5)
|
|
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
|
std::fprintf(stderr, "[ProsperoEden] Vulkan instance ready; creating native surface\n");
|
|
const auto& dispatch = instance.Dispatch();
|
|
const auto proc = [&](const char* name) {
|
|
auto function = dispatch.vkGetInstanceProcAddr(*instance, name);
|
|
if (!function) throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
|
|
return function;
|
|
};
|
|
const auto check = [](VkResult result, int line = __builtin_LINE()) {
|
|
std::fprintf(stderr, "[ProsperoEden] Vulkan surface line=%d result=%d\n", line, static_cast<int>(result));
|
|
if (result != VK_SUCCESS) throw vk::Exception(result);
|
|
};
|
|
// ponytail: the native driver exposes one GPU/display/plane; enumerate all
|
|
// and select explicitly if a future driver supports multiple outputs.
|
|
uint32_t count = 1;
|
|
VkPhysicalDevice physical{};
|
|
check(reinterpret_cast<PFN_vkEnumeratePhysicalDevices>(proc("vkEnumeratePhysicalDevices"))(
|
|
*instance, &count, &physical));
|
|
if (count != 1) {
|
|
std::fprintf(stderr, "[ProsperoEden] Vulkan surface enumeration count=%u\n", count);
|
|
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
|
}
|
|
VkDisplayPropertiesKHR display{};
|
|
count = 1;
|
|
check(reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPropertiesKHR>(
|
|
proc("vkGetPhysicalDeviceDisplayPropertiesKHR"))(physical, &count, &display));
|
|
if (count != 1) {
|
|
std::fprintf(stderr, "[ProsperoEden] Vulkan surface enumeration count=%u\n", count);
|
|
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
|
}
|
|
const auto get_modes = reinterpret_cast<PFN_vkGetDisplayModePropertiesKHR>(
|
|
proc("vkGetDisplayModePropertiesKHR"));
|
|
std::vector<VkDisplayModePropertiesKHR> modes;
|
|
VkResult result;
|
|
do {
|
|
count = 0;
|
|
check(get_modes(physical, display.display, &count, nullptr));
|
|
if (!count) throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
|
modes.resize(count);
|
|
result = get_modes(physical, display.display, &count, modes.data());
|
|
} while (result == VK_INCOMPLETE);
|
|
check(result);
|
|
if (!count) throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
|
modes.resize(count);
|
|
// The driver lists 120 Hz first when the output took it (display_refresh.h). A session that
|
|
// asked for it takes that mode; any other keeps the 60 Hz one.
|
|
const bool fast = Eden::Display::requested_hz.load() >= 120;
|
|
auto mode = modes.front();
|
|
for (const auto& candidate : modes) {
|
|
if ((candidate.parameters.refreshRate >= 119000) == fast) {
|
|
mode = candidate;
|
|
break;
|
|
}
|
|
}
|
|
Eden::Display::output_millihertz.store(static_cast<int>(mode.parameters.refreshRate));
|
|
if (mode.parameters.refreshRate >= 119000) Eden::Display::settle.store(true);
|
|
std::fprintf(stderr, "[ProsperoEden] Vulkan display: %u modes, asked for %d Hz, using %.2f Hz\n", count,
|
|
Eden::Display::requested_hz.load(), mode.parameters.refreshRate / 1000.0);
|
|
const VkDisplaySurfaceCreateInfoKHR info{
|
|
.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR,
|
|
.displayMode = mode.displayMode,
|
|
.planeIndex = 0,
|
|
.planeStackIndex = 0,
|
|
.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
|
|
.globalAlpha = 1.0f,
|
|
.alphaMode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR,
|
|
.imageExtent = mode.parameters.visibleRegion,
|
|
};
|
|
VkSurfaceKHR surface{};
|
|
check(reinterpret_cast<PFN_vkCreateDisplayPlaneSurfaceKHR>(proc("vkCreateDisplayPlaneSurfaceKHR"))(
|
|
*instance, &info, nullptr, &surface));
|
|
return vk::SurfaceKHR(surface, *instance, dispatch);
|
|
}
|
|
} // namespace Vulkan
|