early-access version 3174
This commit is contained in:
parent
37e45db751
commit
0015e8db31
14 changed files with 193 additions and 103 deletions
|
@ -1,7 +1,7 @@
|
||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 3173.
|
This is the source code for early-access 3174.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@ enum class WindowSystemType {
|
||||||
Windows,
|
Windows,
|
||||||
X11,
|
X11,
|
||||||
Wayland,
|
Wayland,
|
||||||
|
Cocoa,
|
||||||
|
Android,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -402,8 +402,10 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
|
||||||
ctx.AddCapability(spv::Capability::SparseResidency);
|
ctx.AddCapability(spv::Capability::SparseResidency);
|
||||||
}
|
}
|
||||||
if (info.uses_demote_to_helper_invocation && profile.support_demote_to_helper_invocation) {
|
if (info.uses_demote_to_helper_invocation && profile.support_demote_to_helper_invocation) {
|
||||||
ctx.AddExtension("SPV_EXT_demote_to_helper_invocation");
|
if (profile.supported_spirv < 0x00010600) {
|
||||||
ctx.AddCapability(spv::Capability::DemoteToHelperInvocationEXT);
|
ctx.AddExtension("SPV_EXT_demote_to_helper_invocation");
|
||||||
|
}
|
||||||
|
ctx.AddCapability(spv::Capability::DemoteToHelperInvocation);
|
||||||
}
|
}
|
||||||
if (info.stores[IR::Attribute::ViewportIndex]) {
|
if (info.stores[IR::Attribute::ViewportIndex]) {
|
||||||
ctx.AddCapability(spv::Capability::MultiViewport);
|
ctx.AddCapability(spv::Capability::MultiViewport);
|
||||||
|
@ -426,12 +428,11 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
|
||||||
if ((info.uses_subgroup_vote || info.uses_subgroup_invocation_id ||
|
if ((info.uses_subgroup_vote || info.uses_subgroup_invocation_id ||
|
||||||
info.uses_subgroup_shuffles) &&
|
info.uses_subgroup_shuffles) &&
|
||||||
profile.support_vote) {
|
profile.support_vote) {
|
||||||
ctx.AddExtension("SPV_KHR_shader_ballot");
|
ctx.AddCapability(spv::Capability::GroupNonUniformBallot);
|
||||||
ctx.AddCapability(spv::Capability::SubgroupBallotKHR);
|
ctx.AddCapability(spv::Capability::GroupNonUniformShuffle);
|
||||||
if (!profile.warp_size_potentially_larger_than_guest) {
|
if (!profile.warp_size_potentially_larger_than_guest) {
|
||||||
// vote ops are only used when not taking the long path
|
// vote ops are only used when not taking the long path
|
||||||
ctx.AddExtension("SPV_KHR_subgroup_vote");
|
ctx.AddCapability(spv::Capability::GroupNonUniformVote);
|
||||||
ctx.AddCapability(spv::Capability::SubgroupVoteKHR);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (info.uses_int64_bit_atomics && profile.support_int64_atomics) {
|
if (info.uses_int64_bit_atomics && profile.support_int64_atomics) {
|
||||||
|
|
|
@ -12,7 +12,7 @@ void EmitJoin(EmitContext&) {
|
||||||
|
|
||||||
void EmitDemoteToHelperInvocation(EmitContext& ctx) {
|
void EmitDemoteToHelperInvocation(EmitContext& ctx) {
|
||||||
if (ctx.profile.support_demote_to_helper_invocation) {
|
if (ctx.profile.support_demote_to_helper_invocation) {
|
||||||
ctx.OpDemoteToHelperInvocationEXT();
|
ctx.OpDemoteToHelperInvocation();
|
||||||
} else {
|
} else {
|
||||||
const Id kill_label{ctx.OpLabel()};
|
const Id kill_label{ctx.OpLabel()};
|
||||||
const Id impossible_label{ctx.OpLabel()};
|
const Id impossible_label{ctx.OpLabel()};
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
|
|
||||||
namespace Shader::Backend::SPIRV {
|
namespace Shader::Backend::SPIRV {
|
||||||
namespace {
|
namespace {
|
||||||
|
Id SubgroupScope(EmitContext& ctx) {
|
||||||
|
return ctx.Const(static_cast<u32>(spv::Scope::Subgroup));
|
||||||
|
}
|
||||||
|
|
||||||
Id GetThreadId(EmitContext& ctx) {
|
Id GetThreadId(EmitContext& ctx) {
|
||||||
return ctx.OpLoad(ctx.U32[1], ctx.subgroup_local_invocation_id);
|
return ctx.OpLoad(ctx.U32[1], ctx.subgroup_local_invocation_id);
|
||||||
}
|
}
|
||||||
|
@ -49,8 +53,9 @@ Id GetMaxThreadId(EmitContext& ctx, Id thread_id, Id clamp, Id segmentation_mask
|
||||||
}
|
}
|
||||||
|
|
||||||
Id SelectValue(EmitContext& ctx, Id in_range, Id value, Id src_thread_id) {
|
Id SelectValue(EmitContext& ctx, Id in_range, Id value, Id src_thread_id) {
|
||||||
return ctx.OpSelect(ctx.U32[1], in_range,
|
return ctx.OpSelect(
|
||||||
ctx.OpSubgroupReadInvocationKHR(ctx.U32[1], value, src_thread_id), value);
|
ctx.U32[1], in_range,
|
||||||
|
ctx.OpGroupNonUniformShuffle(ctx.U32[1], SubgroupScope(ctx), value, src_thread_id), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Id GetUpperClamp(EmitContext& ctx, Id invocation_id, Id clamp) {
|
Id GetUpperClamp(EmitContext& ctx, Id invocation_id, Id clamp) {
|
||||||
|
@ -71,40 +76,46 @@ Id EmitLaneId(EmitContext& ctx) {
|
||||||
|
|
||||||
Id EmitVoteAll(EmitContext& ctx, Id pred) {
|
Id EmitVoteAll(EmitContext& ctx, Id pred) {
|
||||||
if (!ctx.profile.warp_size_potentially_larger_than_guest) {
|
if (!ctx.profile.warp_size_potentially_larger_than_guest) {
|
||||||
return ctx.OpSubgroupAllKHR(ctx.U1, pred);
|
return ctx.OpGroupNonUniformAll(ctx.U1, SubgroupScope(ctx), pred);
|
||||||
}
|
}
|
||||||
const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)};
|
const Id mask_ballot{
|
||||||
|
ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)};
|
||||||
const Id active_mask{WarpExtract(ctx, mask_ballot)};
|
const Id active_mask{WarpExtract(ctx, mask_ballot)};
|
||||||
const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))};
|
const Id ballot{
|
||||||
|
WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))};
|
||||||
const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)};
|
const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)};
|
||||||
return ctx.OpIEqual(ctx.U1, lhs, active_mask);
|
return ctx.OpIEqual(ctx.U1, lhs, active_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitVoteAny(EmitContext& ctx, Id pred) {
|
Id EmitVoteAny(EmitContext& ctx, Id pred) {
|
||||||
if (!ctx.profile.warp_size_potentially_larger_than_guest) {
|
if (!ctx.profile.warp_size_potentially_larger_than_guest) {
|
||||||
return ctx.OpSubgroupAnyKHR(ctx.U1, pred);
|
return ctx.OpGroupNonUniformAny(ctx.U1, SubgroupScope(ctx), pred);
|
||||||
}
|
}
|
||||||
const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)};
|
const Id mask_ballot{
|
||||||
|
ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)};
|
||||||
const Id active_mask{WarpExtract(ctx, mask_ballot)};
|
const Id active_mask{WarpExtract(ctx, mask_ballot)};
|
||||||
const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))};
|
const Id ballot{
|
||||||
|
WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))};
|
||||||
const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)};
|
const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)};
|
||||||
return ctx.OpINotEqual(ctx.U1, lhs, ctx.u32_zero_value);
|
return ctx.OpINotEqual(ctx.U1, lhs, ctx.u32_zero_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitVoteEqual(EmitContext& ctx, Id pred) {
|
Id EmitVoteEqual(EmitContext& ctx, Id pred) {
|
||||||
if (!ctx.profile.warp_size_potentially_larger_than_guest) {
|
if (!ctx.profile.warp_size_potentially_larger_than_guest) {
|
||||||
return ctx.OpSubgroupAllEqualKHR(ctx.U1, pred);
|
return ctx.OpGroupNonUniformAllEqual(ctx.U1, SubgroupScope(ctx), pred);
|
||||||
}
|
}
|
||||||
const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)};
|
const Id mask_ballot{
|
||||||
|
ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)};
|
||||||
const Id active_mask{WarpExtract(ctx, mask_ballot)};
|
const Id active_mask{WarpExtract(ctx, mask_ballot)};
|
||||||
const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))};
|
const Id ballot{
|
||||||
|
WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))};
|
||||||
const Id lhs{ctx.OpBitwiseXor(ctx.U32[1], ballot, active_mask)};
|
const Id lhs{ctx.OpBitwiseXor(ctx.U32[1], ballot, active_mask)};
|
||||||
return ctx.OpLogicalOr(ctx.U1, ctx.OpIEqual(ctx.U1, lhs, ctx.u32_zero_value),
|
return ctx.OpLogicalOr(ctx.U1, ctx.OpIEqual(ctx.U1, lhs, ctx.u32_zero_value),
|
||||||
ctx.OpIEqual(ctx.U1, lhs, active_mask));
|
ctx.OpIEqual(ctx.U1, lhs, active_mask));
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSubgroupBallot(EmitContext& ctx, Id pred) {
|
Id EmitSubgroupBallot(EmitContext& ctx, Id pred) {
|
||||||
const Id ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], pred)};
|
const Id ballot{ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred)};
|
||||||
if (!ctx.profile.warp_size_potentially_larger_than_guest) {
|
if (!ctx.profile.warp_size_potentially_larger_than_guest) {
|
||||||
return ctx.OpCompositeExtract(ctx.U32[1], ballot, 0U);
|
return ctx.OpCompositeExtract(ctx.U32[1], ballot, 0U);
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ using VideoCommon::FileEnvironment;
|
||||||
using VideoCommon::GenericEnvironment;
|
using VideoCommon::GenericEnvironment;
|
||||||
using VideoCommon::GraphicsEnvironment;
|
using VideoCommon::GraphicsEnvironment;
|
||||||
|
|
||||||
constexpr u32 CACHE_VERSION = 7;
|
constexpr u32 CACHE_VERSION = 8;
|
||||||
|
|
||||||
template <typename Container>
|
template <typename Container>
|
||||||
auto MakeSpan(Container& container) {
|
auto MakeSpan(Container& container) {
|
||||||
|
@ -289,7 +289,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
|
||||||
const auto& float_control{device.FloatControlProperties()};
|
const auto& float_control{device.FloatControlProperties()};
|
||||||
const VkDriverIdKHR driver_id{device.GetDriverID()};
|
const VkDriverIdKHR driver_id{device.GetDriverID()};
|
||||||
profile = Shader::Profile{
|
profile = Shader::Profile{
|
||||||
.supported_spirv = device.IsKhrSpirv1_4Supported() ? 0x00010400U : 0x00010000U,
|
.supported_spirv = device.SupportedSpirvVersion(),
|
||||||
.unified_descriptor_binding = true,
|
.unified_descriptor_binding = true,
|
||||||
.support_descriptor_aliasing = true,
|
.support_descriptor_aliasing = true,
|
||||||
.support_int8 = device.IsInt8Supported(),
|
.support_int8 = device.IsInt8Supported(),
|
||||||
|
|
|
@ -75,23 +75,14 @@ enum class NvidiaArchitecture {
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr std::array REQUIRED_EXTENSIONS{
|
constexpr std::array REQUIRED_EXTENSIONS{
|
||||||
VK_KHR_MAINTENANCE1_EXTENSION_NAME,
|
|
||||||
VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME,
|
|
||||||
VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME,
|
|
||||||
VK_KHR_16BIT_STORAGE_EXTENSION_NAME,
|
|
||||||
VK_KHR_8BIT_STORAGE_EXTENSION_NAME,
|
|
||||||
VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME,
|
|
||||||
VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME,
|
|
||||||
VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME,
|
|
||||||
VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME,
|
|
||||||
VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME,
|
|
||||||
VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME,
|
|
||||||
VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME,
|
VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME,
|
||||||
VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME,
|
|
||||||
VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME,
|
|
||||||
VK_EXT_ROBUSTNESS_2_EXTENSION_NAME,
|
VK_EXT_ROBUSTNESS_2_EXTENSION_NAME,
|
||||||
|
|
||||||
|
// Core in 1.2, but required due to use of extension methods,
|
||||||
|
// and well-supported by drivers
|
||||||
|
VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME,
|
||||||
|
VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME,
|
||||||
VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME,
|
VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME,
|
||||||
VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME,
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
|
VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
|
||||||
#endif
|
#endif
|
||||||
|
@ -100,6 +91,17 @@ constexpr std::array REQUIRED_EXTENSIONS{
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr std::array REQUIRED_EXTENSIONS_BEFORE_1_2{
|
||||||
|
VK_KHR_8BIT_STORAGE_EXTENSION_NAME,
|
||||||
|
VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME,
|
||||||
|
VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME,
|
||||||
|
VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr std::array REQUIRED_EXTENSIONS_BEFORE_1_3{
|
||||||
|
VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME,
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void SetNext(void**& next, T& data) {
|
void SetNext(void**& next, T& data) {
|
||||||
*next = &data;
|
*next = &data;
|
||||||
|
@ -328,7 +330,8 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,
|
||||||
Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface,
|
Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface,
|
||||||
const vk::InstanceDispatch& dld_)
|
const vk::InstanceDispatch& dld_)
|
||||||
: instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()},
|
: instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()},
|
||||||
supported_extensions{GetSupportedExtensions(physical)},
|
instance_version{properties.apiVersion}, supported_extensions{GetSupportedExtensions(
|
||||||
|
physical)},
|
||||||
format_properties(GetFormatProperties(physical)) {
|
format_properties(GetFormatProperties(physical)) {
|
||||||
CheckSuitability(surface != nullptr);
|
CheckSuitability(surface != nullptr);
|
||||||
SetupFamilies(surface);
|
SetupFamilies(surface);
|
||||||
|
@ -452,8 +455,8 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||||
};
|
};
|
||||||
SetNext(next, variable_pointers);
|
SetNext(next, variable_pointers);
|
||||||
|
|
||||||
VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT demote{
|
VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures demote{
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT,
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
.shaderDemoteToHelperInvocation = true,
|
.shaderDemoteToHelperInvocation = true,
|
||||||
};
|
};
|
||||||
|
@ -897,28 +900,51 @@ std::string Device::GetDriverName() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<const char*> ExtensionsRequiredForInstanceVersion(u32 available_version) {
|
||||||
|
std::vector<const char*> extensions{REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end()};
|
||||||
|
|
||||||
|
if (available_version < VK_API_VERSION_1_2) {
|
||||||
|
extensions.insert(extensions.end(), REQUIRED_EXTENSIONS_BEFORE_1_2.begin(),
|
||||||
|
REQUIRED_EXTENSIONS_BEFORE_1_2.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (available_version < VK_API_VERSION_1_3) {
|
||||||
|
extensions.insert(extensions.end(), REQUIRED_EXTENSIONS_BEFORE_1_3.begin(),
|
||||||
|
REQUIRED_EXTENSIONS_BEFORE_1_3.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
return extensions;
|
||||||
|
}
|
||||||
|
|
||||||
void Device::CheckSuitability(bool requires_swapchain) const {
|
void Device::CheckSuitability(bool requires_swapchain) const {
|
||||||
std::bitset<REQUIRED_EXTENSIONS.size()> available_extensions;
|
std::vector<const char*> required_extensions =
|
||||||
bool has_swapchain = false;
|
ExtensionsRequiredForInstanceVersion(instance_version);
|
||||||
for (const VkExtensionProperties& property : physical.EnumerateDeviceExtensionProperties()) {
|
std::vector<const char*> available_extensions;
|
||||||
const std::string_view name{property.extensionName};
|
|
||||||
for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) {
|
if (requires_swapchain) {
|
||||||
if (available_extensions[i]) {
|
required_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
available_extensions[i] = name == REQUIRED_EXTENSIONS[i];
|
|
||||||
}
|
|
||||||
has_swapchain = has_swapchain || name == VK_KHR_SWAPCHAIN_EXTENSION_NAME;
|
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) {
|
|
||||||
if (available_extensions[i]) {
|
auto extension_properties = physical.EnumerateDeviceExtensionProperties();
|
||||||
continue;
|
|
||||||
}
|
for (const VkExtensionProperties& property : extension_properties) {
|
||||||
LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]);
|
available_extensions.push_back(property.extensionName);
|
||||||
throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
|
|
||||||
}
|
}
|
||||||
if (requires_swapchain && !has_swapchain) {
|
|
||||||
LOG_ERROR(Render_Vulkan, "Missing required extension: VK_KHR_swapchain");
|
bool has_all_required_extensions = true;
|
||||||
|
for (const char* requirement_name : required_extensions) {
|
||||||
|
const bool found =
|
||||||
|
std::ranges::any_of(available_extensions, [&](const char* extension_name) {
|
||||||
|
return std::strcmp(requirement_name, extension_name) == 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Missing required extension: {}", requirement_name);
|
||||||
|
has_all_required_extensions = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!has_all_required_extensions) {
|
||||||
throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
|
throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -941,9 +967,8 @@ void Device::CheckSuitability(bool requires_swapchain) const {
|
||||||
throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
|
throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT demote{};
|
VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures demote{};
|
||||||
demote.sType =
|
demote.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES;
|
||||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT;
|
|
||||||
demote.pNext = nullptr;
|
demote.pNext = nullptr;
|
||||||
|
|
||||||
VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointers{};
|
VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointers{};
|
||||||
|
@ -961,7 +986,7 @@ void Device::CheckSuitability(bool requires_swapchain) const {
|
||||||
physical.GetFeatures2KHR(features2);
|
physical.GetFeatures2KHR(features2);
|
||||||
|
|
||||||
const VkPhysicalDeviceFeatures& features{features2.features};
|
const VkPhysicalDeviceFeatures& features{features2.features};
|
||||||
const std::array feature_report{
|
std::vector feature_report{
|
||||||
std::make_pair(features.robustBufferAccess, "robustBufferAccess"),
|
std::make_pair(features.robustBufferAccess, "robustBufferAccess"),
|
||||||
std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"),
|
std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"),
|
||||||
std::make_pair(features.imageCubeArray, "imageCubeArray"),
|
std::make_pair(features.imageCubeArray, "imageCubeArray"),
|
||||||
|
@ -984,27 +1009,30 @@ void Device::CheckSuitability(bool requires_swapchain) const {
|
||||||
"shaderStorageImageWriteWithoutFormat"),
|
"shaderStorageImageWriteWithoutFormat"),
|
||||||
std::make_pair(features.shaderClipDistance, "shaderClipDistance"),
|
std::make_pair(features.shaderClipDistance, "shaderClipDistance"),
|
||||||
std::make_pair(features.shaderCullDistance, "shaderCullDistance"),
|
std::make_pair(features.shaderCullDistance, "shaderCullDistance"),
|
||||||
std::make_pair(demote.shaderDemoteToHelperInvocation, "shaderDemoteToHelperInvocation"),
|
|
||||||
std::make_pair(variable_pointers.variablePointers, "variablePointers"),
|
std::make_pair(variable_pointers.variablePointers, "variablePointers"),
|
||||||
std::make_pair(variable_pointers.variablePointersStorageBuffer,
|
std::make_pair(variable_pointers.variablePointersStorageBuffer,
|
||||||
"variablePointersStorageBuffer"),
|
"variablePointersStorageBuffer"),
|
||||||
std::make_pair(robustness2.robustBufferAccess2, "robustBufferAccess2"),
|
std::make_pair(robustness2.robustBufferAccess2, "robustBufferAccess2"),
|
||||||
std::make_pair(robustness2.robustImageAccess2, "robustImageAccess2"),
|
std::make_pair(robustness2.robustImageAccess2, "robustImageAccess2"),
|
||||||
std::make_pair(robustness2.nullDescriptor, "nullDescriptor"),
|
std::make_pair(robustness2.nullDescriptor, "nullDescriptor"),
|
||||||
|
std::make_pair(demote.shaderDemoteToHelperInvocation, "shaderDemoteToHelperInvocation"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool has_all_required_features = true;
|
||||||
for (const auto& [is_supported, name] : feature_report) {
|
for (const auto& [is_supported, name] : feature_report) {
|
||||||
if (is_supported) {
|
if (!is_supported) {
|
||||||
continue;
|
LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name);
|
||||||
|
has_all_required_features = false;
|
||||||
}
|
}
|
||||||
LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name);
|
}
|
||||||
|
|
||||||
|
if (!has_all_required_features) {
|
||||||
throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
|
throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
|
std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
|
||||||
std::vector<const char*> extensions;
|
std::vector<const char*> extensions = ExtensionsRequiredForInstanceVersion(instance_version);
|
||||||
extensions.reserve(8 + REQUIRED_EXTENSIONS.size());
|
|
||||||
extensions.insert(extensions.begin(), REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end());
|
|
||||||
if (requires_surface) {
|
if (requires_surface) {
|
||||||
extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,11 +211,6 @@ public:
|
||||||
return khr_uniform_buffer_standard_layout;
|
return khr_uniform_buffer_standard_layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the device supports VK_KHR_spirv_1_4.
|
|
||||||
bool IsKhrSpirv1_4Supported() const {
|
|
||||||
return khr_spirv_1_4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if the device supports VK_KHR_push_descriptor.
|
/// Returns true if the device supports VK_KHR_push_descriptor.
|
||||||
bool IsKhrPushDescriptorSupported() const {
|
bool IsKhrPushDescriptorSupported() const {
|
||||||
return khr_push_descriptor;
|
return khr_push_descriptor;
|
||||||
|
@ -316,6 +311,17 @@ public:
|
||||||
return ext_shader_atomic_int64;
|
return ext_shader_atomic_int64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the minimum supported version of SPIR-V.
|
||||||
|
u32 SupportedSpirvVersion() const {
|
||||||
|
if (instance_version >= VK_API_VERSION_1_3) {
|
||||||
|
return 0x00010600U;
|
||||||
|
}
|
||||||
|
if (khr_spirv_1_4) {
|
||||||
|
return 0x00010400U;
|
||||||
|
}
|
||||||
|
return 0x00010000U;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true when a known debugging tool is attached.
|
/// Returns true when a known debugging tool is attached.
|
||||||
bool HasDebuggingToolAttached() const {
|
bool HasDebuggingToolAttached() const {
|
||||||
return has_renderdoc || has_nsight_graphics;
|
return has_renderdoc || has_nsight_graphics;
|
||||||
|
|
|
@ -15,13 +15,15 @@
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
||||||
// Include these late to avoid polluting previous headers
|
// Include these late to avoid polluting previous headers
|
||||||
#ifdef _WIN32
|
#if defined(_WIN32)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
// ensure include order
|
// ensure include order
|
||||||
#include <vulkan/vulkan_win32.h>
|
#include <vulkan/vulkan_win32.h>
|
||||||
#endif
|
#elif defined(__APPLE__)
|
||||||
|
#include <vulkan/vulkan_macos.h>
|
||||||
#if !defined(_WIN32) && !defined(__APPLE__)
|
#elif defined(__ANDROID__)
|
||||||
|
#include <vulkan/vulkan_android.h>
|
||||||
|
#else
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <vulkan/vulkan_wayland.h>
|
#include <vulkan/vulkan_wayland.h>
|
||||||
#include <vulkan/vulkan_xlib.h>
|
#include <vulkan/vulkan_xlib.h>
|
||||||
|
@ -40,8 +42,15 @@ namespace {
|
||||||
case Core::Frontend::WindowSystemType::Windows:
|
case Core::Frontend::WindowSystemType::Windows:
|
||||||
extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
break;
|
break;
|
||||||
#endif
|
#elif defined(__APPLE__)
|
||||||
#if !defined(_WIN32) && !defined(__APPLE__)
|
case Core::Frontend::WindowSystemType::Cocoa:
|
||||||
|
extensions.push_back(VK_MVK_MACOS_SURFACE_EXTENSION_NAME);
|
||||||
|
break;
|
||||||
|
#elif defined(__ANDROID__)
|
||||||
|
case Core::Frontend::WindowSystemType::Android:
|
||||||
|
extensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
|
||||||
|
break;
|
||||||
|
#else
|
||||||
case Core::Frontend::WindowSystemType::X11:
|
case Core::Frontend::WindowSystemType::X11:
|
||||||
extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
break;
|
break;
|
||||||
|
@ -60,6 +69,10 @@ namespace {
|
||||||
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
}
|
}
|
||||||
extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
|
extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
|
||||||
|
#endif
|
||||||
return extensions;
|
return extensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +154,7 @@ vk::Instance CreateInstance(const Common::DynamicLibrary& library, vk::InstanceD
|
||||||
}
|
}
|
||||||
vk::Instance instance =
|
vk::Instance instance =
|
||||||
std::async([&] {
|
std::async([&] {
|
||||||
return vk::Instance::Create(required_version, layers, extensions, dld);
|
return vk::Instance::Create(available_version, layers, extensions, dld);
|
||||||
}).get();
|
}).get();
|
||||||
if (!vk::Load(*instance, dld)) {
|
if (!vk::Load(*instance, dld)) {
|
||||||
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers");
|
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers");
|
||||||
|
|
|
@ -11,9 +11,11 @@
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
// ensure include order
|
// ensure include order
|
||||||
#include <vulkan/vulkan_win32.h>
|
#include <vulkan/vulkan_win32.h>
|
||||||
#endif
|
#elif defined(__APPLE__)
|
||||||
|
#include <vulkan/vulkan_macos.h>
|
||||||
#if !defined(_WIN32) && !defined(__APPLE__)
|
#elif defined(__ANDROID__)
|
||||||
|
#include <vulkan/vulkan_android.h>
|
||||||
|
#else
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <vulkan/vulkan_wayland.h>
|
#include <vulkan/vulkan_wayland.h>
|
||||||
#include <vulkan/vulkan_xlib.h>
|
#include <vulkan/vulkan_xlib.h>
|
||||||
|
@ -40,8 +42,33 @@ vk::SurfaceKHR CreateSurface(const vk::Instance& instance,
|
||||||
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#elif defined(__APPLE__)
|
||||||
#if !defined(_WIN32) && !defined(__APPLE__)
|
if (window_info.type == Core::Frontend::WindowSystemType::Cocoa) {
|
||||||
|
const VkMacOSSurfaceCreateInfoMVK mvk_ci{VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK,
|
||||||
|
nullptr, 0, window_info.render_surface};
|
||||||
|
const auto vkCreateMacOSSurfaceMVK = reinterpret_cast<PFN_vkCreateMacOSSurfaceMVK>(
|
||||||
|
dld.vkGetInstanceProcAddr(*instance, "vkCreateMacOSSurfaceMVK"));
|
||||||
|
if (!vkCreateMacOSSurfaceMVK ||
|
||||||
|
vkCreateMacOSSurfaceMVK(*instance, &mvk_ci, nullptr, &unsafe_surface) != VK_SUCCESS) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Failed to initialize Metal surface");
|
||||||
|
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif defined(__ANDROID__)
|
||||||
|
if (window_info.type == Core::Frontend::WindowSystemType::Android) {
|
||||||
|
const VkAndroidSurfaceCreateInfoKHR android_ci{
|
||||||
|
VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, nullptr, 0,
|
||||||
|
reinterpret_cast<ANativeWindow*>(window_info.render_surface)};
|
||||||
|
const auto vkCreateAndroidSurfaceKHR = reinterpret_cast<PFN_vkCreateAndroidSurfaceKHR>(
|
||||||
|
dld.vkGetInstanceProcAddr(*instance, "vkCreateAndroidSurfaceKHR"));
|
||||||
|
if (!vkCreateAndroidSurfaceKHR ||
|
||||||
|
vkCreateAndroidSurfaceKHR(*instance, &android_ci, nullptr, &unsafe_surface) !=
|
||||||
|
VK_SUCCESS) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Failed to initialize Android surface");
|
||||||
|
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
if (window_info.type == Core::Frontend::WindowSystemType::X11) {
|
if (window_info.type == Core::Frontend::WindowSystemType::X11) {
|
||||||
const VkXlibSurfaceCreateInfoKHR xlib_ci{
|
const VkXlibSurfaceCreateInfoKHR xlib_ci{
|
||||||
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0,
|
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0,
|
||||||
|
@ -70,6 +97,7 @@ vk::SurfaceKHR CreateSurface(const vk::Instance& instance,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!unsafe_surface) {
|
if (!unsafe_surface) {
|
||||||
LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform");
|
LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform");
|
||||||
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
||||||
|
|
|
@ -267,6 +267,10 @@ static Core::Frontend::WindowSystemType GetWindowSystemType() {
|
||||||
return Core::Frontend::WindowSystemType::X11;
|
return Core::Frontend::WindowSystemType::X11;
|
||||||
else if (platform_name == QStringLiteral("wayland"))
|
else if (platform_name == QStringLiteral("wayland"))
|
||||||
return Core::Frontend::WindowSystemType::Wayland;
|
return Core::Frontend::WindowSystemType::Wayland;
|
||||||
|
else if (platform_name == QStringLiteral("cocoa"))
|
||||||
|
return Core::Frontend::WindowSystemType::Cocoa;
|
||||||
|
else if (platform_name == QStringLiteral("android"))
|
||||||
|
return Core::Frontend::WindowSystemType::Android;
|
||||||
|
|
||||||
LOG_CRITICAL(Frontend, "Unknown Qt platform!");
|
LOG_CRITICAL(Frontend, "Unknown Qt platform!");
|
||||||
return Core::Frontend::WindowSystemType::Windows;
|
return Core::Frontend::WindowSystemType::Windows;
|
||||||
|
|
|
@ -360,7 +360,7 @@ void ConfigureGraphics::RetrieveVulkanDevices() try {
|
||||||
|
|
||||||
vk::InstanceDispatch dld;
|
vk::InstanceDispatch dld;
|
||||||
const Common::DynamicLibrary library = OpenLibrary();
|
const Common::DynamicLibrary library = OpenLibrary();
|
||||||
const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_0);
|
const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_1);
|
||||||
const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices();
|
const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices();
|
||||||
|
|
||||||
vulkan_devices.clear();
|
vulkan_devices.clear();
|
||||||
|
|
|
@ -27,7 +27,7 @@ void CheckVulkan() {
|
||||||
Vulkan::vk::InstanceDispatch dld;
|
Vulkan::vk::InstanceDispatch dld;
|
||||||
const Common::DynamicLibrary library = Vulkan::OpenLibrary();
|
const Common::DynamicLibrary library = Vulkan::OpenLibrary();
|
||||||
const Vulkan::vk::Instance instance =
|
const Vulkan::vk::Instance instance =
|
||||||
Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_0);
|
Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_1);
|
||||||
|
|
||||||
} catch (const Vulkan::vk::Exception& exception) {
|
} catch (const Vulkan::vk::Exception& exception) {
|
||||||
fmt::print(stderr, "Failed to initialize Vulkan: {}\n", exception.what());
|
fmt::print(stderr, "Failed to initialize Vulkan: {}\n", exception.what());
|
||||||
|
|
|
@ -51,11 +51,6 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste
|
||||||
window_info.type = Core::Frontend::WindowSystemType::Windows;
|
window_info.type = Core::Frontend::WindowSystemType::Windows;
|
||||||
window_info.render_surface = reinterpret_cast<void*>(wm.info.win.window);
|
window_info.render_surface = reinterpret_cast<void*>(wm.info.win.window);
|
||||||
break;
|
break;
|
||||||
#else
|
|
||||||
case SDL_SYSWM_TYPE::SDL_SYSWM_WINDOWS:
|
|
||||||
LOG_CRITICAL(Frontend, "Window manager subsystem Windows not compiled");
|
|
||||||
std::exit(EXIT_FAILURE);
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef SDL_VIDEO_DRIVER_X11
|
#ifdef SDL_VIDEO_DRIVER_X11
|
||||||
case SDL_SYSWM_TYPE::SDL_SYSWM_X11:
|
case SDL_SYSWM_TYPE::SDL_SYSWM_X11:
|
||||||
|
@ -63,11 +58,6 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste
|
||||||
window_info.display_connection = wm.info.x11.display;
|
window_info.display_connection = wm.info.x11.display;
|
||||||
window_info.render_surface = reinterpret_cast<void*>(wm.info.x11.window);
|
window_info.render_surface = reinterpret_cast<void*>(wm.info.x11.window);
|
||||||
break;
|
break;
|
||||||
#else
|
|
||||||
case SDL_SYSWM_TYPE::SDL_SYSWM_X11:
|
|
||||||
LOG_CRITICAL(Frontend, "Window manager subsystem X11 not compiled");
|
|
||||||
std::exit(EXIT_FAILURE);
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND
|
#ifdef SDL_VIDEO_DRIVER_WAYLAND
|
||||||
case SDL_SYSWM_TYPE::SDL_SYSWM_WAYLAND:
|
case SDL_SYSWM_TYPE::SDL_SYSWM_WAYLAND:
|
||||||
|
@ -75,14 +65,21 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste
|
||||||
window_info.display_connection = wm.info.wl.display;
|
window_info.display_connection = wm.info.wl.display;
|
||||||
window_info.render_surface = wm.info.wl.surface;
|
window_info.render_surface = wm.info.wl.surface;
|
||||||
break;
|
break;
|
||||||
#else
|
#endif
|
||||||
case SDL_SYSWM_TYPE::SDL_SYSWM_WAYLAND:
|
#ifdef SDL_VIDEO_DRIVER_COCOA
|
||||||
LOG_CRITICAL(Frontend, "Window manager subsystem Wayland not compiled");
|
case SDL_SYSWM_TYPE::SDL_SYSWM_COCOA:
|
||||||
std::exit(EXIT_FAILURE);
|
window_info.type = Core::Frontend::WindowSystemType::Cocoa;
|
||||||
|
window_info.render_surface = SDL_Metal_CreateView(render_window);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_ANDROID
|
||||||
|
case SDL_SYSWM_TYPE::SDL_SYSWM_ANDROID:
|
||||||
|
window_info.type = Core::Frontend::WindowSystemType::Android;
|
||||||
|
window_info.render_surface = reinterpret_cast<void*>(wm.info.android.window);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
LOG_CRITICAL(Frontend, "Window manager subsystem not implemented");
|
LOG_CRITICAL(Frontend, "Window manager subsystem {} not implemented", wm.subsystem);
|
||||||
std::exit(EXIT_FAILURE);
|
std::exit(EXIT_FAILURE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue