mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-31 10:36:56 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cfb243159d | |||
| 106a61c943 |
+15
-3
@@ -23,8 +23,20 @@ include(CMakeDependentOption)
|
|||||||
include(CTest)
|
include(CTest)
|
||||||
include(CPMUtil)
|
include(CPMUtil)
|
||||||
|
|
||||||
if (CXX_GCC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "14.0")
|
if (NOT DEFINED ARCHITECTURE)
|
||||||
message(FATAL_ERROR "GCC versions older than 14.0 are not supported. Update your system, or use clang/clang++ instead.")
|
message(FATAL_ERROR "Architecture didn't make it out of scope, did you delete DetectArchitecture.cmake?")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Needed for FFmpeg w/ VAAPI and DRM
|
||||||
|
if (OPENBSD)
|
||||||
|
# OpenBSD 7.8 broke libcxx when upgrading, so we must define the PSTL backend manually
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R6/include -D_LIBCPP_PSTL_BACKEND_SERIAL=1")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R6/include -D_LIBCPP_PSTL_BACKEND_SERIAL=1")
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_SYSROOT}/usr/X11R6/lib")
|
||||||
|
elseif (NETBSD)
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R7/include -I${CMAKE_SYSROOT}/usr/pkg/include/c++/v1")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R7/include -I${CMAKE_SYSROOT}/usr/pkg/include/c++/v1")
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_SYSROOT}/usr/X11R7/lib")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# NetBSD: Fun for the whole family!
|
# NetBSD: Fun for the whole family!
|
||||||
@@ -608,7 +620,7 @@ if (ENABLE_QT)
|
|||||||
|
|
||||||
# Best practice is to ask for all components at once, so they are from the same version
|
# Best practice is to ask for all components at once, so they are from the same version
|
||||||
set(YUZU_QT_COMPONENTS Core Widgets Charts Concurrent Gui)
|
set(YUZU_QT_COMPONENTS Core Widgets Charts Concurrent Gui)
|
||||||
if (NOT WIN32 AND NOT APPLE)
|
if (LINUX OR FREEBSD)
|
||||||
list(APPEND YUZU_QT_COMPONENTS DBus)
|
list(APPEND YUZU_QT_COMPONENTS DBus)
|
||||||
# yes Qt, we get it
|
# yes Qt, we get it
|
||||||
set(QT_NO_PRIVATE_MODULE_WARNING ON)
|
set(QT_NO_PRIVATE_MODULE_WARNING ON)
|
||||||
|
|||||||
+1
-3
@@ -71,7 +71,7 @@ export LIBGL_ALWAYS_SOFTWARE=1
|
|||||||
|
|
||||||
Install `developer/gcc14` on OmniOS using pkgsrc.
|
Install `developer/gcc14` on OmniOS using pkgsrc.
|
||||||
|
|
||||||
Since so many dependencies are missing on `OmniOS`, you may wish to use `-DCPMUTIL_FORCE_BUNDLED=ON` and `-DYUZU_USE_BUNDLED_OPENSSL=OFF`.
|
Since so many dependencies are missing on `OmniOS`, you may wish to use `-DCPMUTIL_FORCE_BUNDLED=ON`
|
||||||
|
|
||||||
For OmniOS you are required to build glslang yourself:
|
For OmniOS you are required to build glslang yourself:
|
||||||
```sh
|
```sh
|
||||||
@@ -92,8 +92,6 @@ You may also need to install `gmake` in order to properly build FFmpeg, this is
|
|||||||
|
|
||||||
If it wasn't obvious already, you require a X11 server to properly run the emulator within OmniOS, [this guide](https://web.archive.org/web/20260424200928/https://geekblood.wordpress.com/2017/10/26/installing-x11-and-a-desktop-environment-on-omnios/) is a great starting point for that, the links to pkgsrc are outdated so follow [this exemplar](https://pkgsrc.smartos.org/install-on-illumos/) as well:
|
If it wasn't obvious already, you require a X11 server to properly run the emulator within OmniOS, [this guide](https://web.archive.org/web/20260424200928/https://geekblood.wordpress.com/2017/10/26/installing-x11-and-a-desktop-environment-on-omnios/) is a great starting point for that, the links to pkgsrc are outdated so follow [this exemplar](https://pkgsrc.smartos.org/install-on-illumos/) as well:
|
||||||
|
|
||||||
For Solaris based OSes, `${CMAKE_SYSTEM_NAME}` isn't properly set on CMake (it's set to i686 on AMD64), you may find issues when building OpenSSL from `openssl-cmake`.
|
|
||||||
|
|
||||||
## HaikuOS
|
## HaikuOS
|
||||||
|
|
||||||
It's recommended to do a `pkgman full-sync` before installing. See [HaikuOS: Installing applications](https://www.haiku-os.org/guides/daily-tasks/install-applications/). Sometimes the process may be interrupted by an error like "Interrupted syscall". Simply firing the command again fixes the issue. By default `g++` is included on the default installation.
|
It's recommended to do a `pkgman full-sync` before installing. See [HaikuOS: Installing applications](https://www.haiku-os.org/guides/daily-tasks/install-applications/). Sometimes the process may be interrupted by an error like "Interrupted syscall". Simply firing the command again fixes the issue. By default `g++` is included on the default installation.
|
||||||
|
|||||||
+1
-1
@@ -273,7 +273,7 @@ If using FreeBSD 12 or prior, use `devel/pkg-config` instead.
|
|||||||
For NetBSD +10.1:
|
For NetBSD +10.1:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
pkgin install git cmake boost fmtlib SDL3 catch2 libjwt spirv-headers spirv-tools ffmpeg7 libva nlohmann-json jq libopus qt6-qtbase qt6-qtcharts qt6-qtmultimedia qt6-qttools cpp-httplib lz4 vulkan-headers nasm autoconf enet pkg-config libusb1 libcxx frozen
|
pkgin install git cmake boost fmtlib SDL3 catch2 libjwt spirv-headers spirv-tools ffmpeg7 libva nlohmann-json jq libopus qt6 cpp-httplib lz4 vulkan-headers nasm autoconf enet pkg-config libusb1 libcxx frozen
|
||||||
```
|
```
|
||||||
|
|
||||||
[Caveats](./Caveats.md#netbsd).
|
[Caveats](./Caveats.md#netbsd).
|
||||||
|
|||||||
@@ -123,11 +123,13 @@ static IPSwitchRecord EscapeStringSequences(std::string_view sv) {
|
|||||||
for (auto it = sv.cbegin(); it != sv.cend(); ) {
|
for (auto it = sv.cbegin(); it != sv.cend(); ) {
|
||||||
if (*it == '\\' && it + 1 < sv.cend()) {
|
if (*it == '\\' && it + 1 < sv.cend()) {
|
||||||
switch (it[1]) {
|
switch (it[1]) {
|
||||||
case 'n': r.data[r.count] = '\n'; break;
|
case 'a': r.data[r.count] = '\a'; break;
|
||||||
case 't': r.data[r.count] = '\t'; break;
|
|
||||||
case 'b': r.data[r.count] = '\b'; break;
|
case 'b': r.data[r.count] = '\b'; break;
|
||||||
case 'r': r.data[r.count] = '\r'; break;
|
|
||||||
case 'e': r.data[r.count] = '\e'; break;
|
case 'e': r.data[r.count] = '\e'; break;
|
||||||
|
case 'f': r.data[r.count] = '\f'; break;
|
||||||
|
case 'n': r.data[r.count] = '\n'; break;
|
||||||
|
case 'r': r.data[r.count] = '\r'; break;
|
||||||
|
case 't': r.data[r.count] = '\t'; break;
|
||||||
case 'v': r.data[r.count] = '\v'; break;
|
case 'v': r.data[r.count] = '\v'; break;
|
||||||
case '?': r.data[r.count] = '\?'; break;
|
case '?': r.data[r.count] = '\?'; break;
|
||||||
default: r.data[r.count] = it[1]; break;
|
default: r.data[r.count] = it[1]; break;
|
||||||
@@ -142,40 +144,60 @@ static IPSwitchRecord EscapeStringSequences(std::string_view sv) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] static inline std::array<u8, 32> ReadNSOBuildId(std::string_view const s) {
|
|
||||||
std::array<u8, 32> r{};
|
|
||||||
for (std::size_t i = 0; i < s.size(); ++i)
|
|
||||||
r[i / 2] |= u8(u8(Common::ToHexNibble(s[i])) << u8((i % 2) * 4));
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IPSwitchCompiler::Parse(std::span<u8 const> bytes) {
|
void IPSwitchCompiler::Parse(std::span<u8 const> bytes) {
|
||||||
LOG_INFO(Loader, "IPSwitchCompiler: '{}'", patch_text->GetName());
|
LOG_INFO(Loader, "IPSwitchCompiler: '{}'", patch_text->GetName());
|
||||||
bool is_little_endian = false;
|
bool is_little_endian = true;
|
||||||
s64 offset_shift = 0;
|
s64 offset_shift = 0;
|
||||||
//bool print_values = false;
|
//bool print_values = false;
|
||||||
|
|
||||||
auto const parse_line = [&](std::string_view const line) {
|
auto const parse_line = [&](std::string_view const line) {
|
||||||
// Keep in mind lines have trimmed spaces (at the end & start)!
|
// Keep in mind lines have trimmed spaces (at the end & start)!
|
||||||
LOG_INFO(Loader, "<{}>", line);
|
LOG_INFO(Loader, "<{}>", line);
|
||||||
if (line.starts_with("@stop")) {
|
// IPSwitch is case insensitive
|
||||||
return false; // Force stop
|
// Yes this is how the logic goes for the main reference parsers!
|
||||||
} else if (line.starts_with("@nsobid-")) { // NSO Build ID Specifier
|
if (line.size() > 2 && line[0] == '@') {
|
||||||
nso_build_id = ReadNSOBuildId(line.substr(8));
|
switch (line[1]) {
|
||||||
} else if (line.starts_with("@enabled")) {
|
// yes, @nsobid too -- NSO Build ID Specifier
|
||||||
patches.push_back({{}, true}); //enabled patch
|
case 'n':
|
||||||
} else if (line.starts_with("@disabled")) {
|
case 'N':
|
||||||
patches.push_back({{}, false}); //disabled patch
|
nso_build_id = Common::HexStringToArray<0x20>(fmt::format("{:0<64}", line.substr(8)));
|
||||||
} else if (line.starts_with("@flag offset_shift ")) {
|
break;
|
||||||
offset_shift = std::strtoll(line.data() + 19, nullptr, 0); // Offset Shift Flag
|
// @stop
|
||||||
} else if (line.starts_with("@little-endian")) {
|
case 's':
|
||||||
is_little_endian = true; // Set values to read as little endian
|
case 'S':
|
||||||
} else if (line.starts_with("@big-endian")) {
|
return false;
|
||||||
is_little_endian = false; // Set values to read as big endian
|
// @enabled
|
||||||
} else if (line.starts_with("@flag print_values")) {
|
case 'e':
|
||||||
//print_values = true; // Force printing of applied values
|
case 'E':
|
||||||
} else if (line.starts_with("@")) {
|
patches.push_back({{}, true});
|
||||||
LOG_WARNING(Loader, "Unknown flag {}", line);
|
break;
|
||||||
|
// @disabled
|
||||||
|
case 'd':
|
||||||
|
case 'D':
|
||||||
|
patches.push_back({{}, false});
|
||||||
|
break;
|
||||||
|
// @flag
|
||||||
|
case 'f':
|
||||||
|
case 'F': {
|
||||||
|
if (line.starts_with("@flag offset_shift")) {
|
||||||
|
offset_shift = std::strtoll(line.data() + 19, nullptr, 0); // Offset Shift Flag
|
||||||
|
} else if (line.starts_with("@flag print_values")) {
|
||||||
|
//print_values = true; // Force printing of applied values
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'l':
|
||||||
|
case 'L':
|
||||||
|
is_little_endian = true;
|
||||||
|
break;
|
||||||
|
// IPS parsers dont support big endian no more, we do due to backcompat
|
||||||
|
case 'b':
|
||||||
|
case 'B':
|
||||||
|
is_little_endian = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_WARNING(Loader, "Unknown flag {}", line);
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
size_t offset = size_t(std::strtoul(line.data(), nullptr, 16));
|
size_t offset = size_t(std::strtoul(line.data(), nullptr, 16));
|
||||||
offset += size_t(offset_shift);
|
offset += size_t(offset_shift);
|
||||||
@@ -197,6 +219,7 @@ void IPSwitchCompiler::Parse(std::span<u8 const> bytes) {
|
|||||||
auto const start = line.cbegin() + first_space + 1;
|
auto const start = line.cbegin() + first_space + 1;
|
||||||
auto const end = line.cend();
|
auto const end = line.cend();
|
||||||
if (start <= line.cend() && end <= line.cend()) {
|
if (start <= line.cend() && end <= line.cend()) {
|
||||||
|
// Actually IPS wants ordering from {lsb, ..., msb} -- so LE and BE are inverted, fun!
|
||||||
auto const hs = Common::HexStringToVector({start, end}, is_little_endian);
|
auto const hs = Common::HexStringToVector({start, end}, is_little_endian);
|
||||||
std::memcpy(r.data.data(), hs.data(), hs.size());
|
std::memcpy(r.data.data(), hs.data(), hs.size());
|
||||||
r.count = hs.size();
|
r.count = hs.size();
|
||||||
@@ -231,7 +254,8 @@ void IPSwitchCompiler::Parse(std::span<u8 const> bytes) {
|
|||||||
char quote = '\0';
|
char quote = '\0';
|
||||||
auto const sline_start = p;
|
auto const sline_start = p;
|
||||||
for (; p < sline.cend(); ) {
|
for (; p < sline.cend(); ) {
|
||||||
if ((!quote && p + 1 < sline.cend() && p[0] == '/' && p[1] == '/')
|
// we dont check for "//", IPS checks for '/' only...
|
||||||
|
if ((!quote && p[0] == '/')
|
||||||
|| (!quote && p[0] == '#')) {
|
|| (!quote && p[0] == '#')) {
|
||||||
break;
|
break;
|
||||||
} else if (p[0] == '\"' || p[0] == '\'') {
|
} else if (p[0] == '\"' || p[0] == '\'') {
|
||||||
@@ -266,6 +290,8 @@ VirtualFile IPSwitchCompiler::Apply(const VirtualFile& in) const {
|
|||||||
if (record.first + replace_size > in_data.size())
|
if (record.first + replace_size > in_data.size())
|
||||||
replace_size = in_data.size() - record.first;
|
replace_size = in_data.size() - record.first;
|
||||||
std::memcpy(in_data.data() + record.first, record.second.data.data(), replace_size);
|
std::memcpy(in_data.data() + record.first, record.second.data.data(), replace_size);
|
||||||
|
} else {
|
||||||
|
LOG_WARNING(Loader, "record offs={:x},size={:x}", record.first, record.second.data.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,9 @@
|
|||||||
#else
|
#else
|
||||||
# define CTX_SP (_UC_MACHINE_SP(ucontext))
|
# define CTX_SP (_UC_MACHINE_SP(ucontext))
|
||||||
#endif
|
#endif
|
||||||
#elif defined(ARCHITECTURE_arm64)
|
#endif
|
||||||
|
|
||||||
|
#if defined(ARCHITECTURE_arm64)
|
||||||
# if defined(__APPLE__)
|
# if defined(__APPLE__)
|
||||||
# define CTX_PC (mctx->__ss.__pc)
|
# define CTX_PC (mctx->__ss.__pc)
|
||||||
# define CTX_SP (mctx->__ss.__sp)
|
# define CTX_SP (mctx->__ss.__sp)
|
||||||
|
|||||||
@@ -440,7 +440,8 @@ 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.SupportsSubgroupStage(ctx.stage)) {
|
profile.support_vote &&
|
||||||
|
(ctx.stage != Stage::Geometry || profile.support_subgroup_in_geometry_stage)) {
|
||||||
ctx.AddCapability(spv::Capability::GroupNonUniformBallot);
|
ctx.AddCapability(spv::Capability::GroupNonUniformBallot);
|
||||||
ctx.AddCapability(spv::Capability::GroupNonUniformShuffle);
|
ctx.AddCapability(spv::Capability::GroupNonUniformShuffle);
|
||||||
if (!profile.warp_size_potentially_larger_than_guest) {
|
if (!profile.warp_size_potentially_larger_than_guest) {
|
||||||
|
|||||||
@@ -13,6 +13,18 @@ Id SubgroupScope(EmitContext& ctx) {
|
|||||||
return ctx.Const(static_cast<u32>(spv::Scope::Subgroup));
|
return ctx.Const(static_cast<u32>(spv::Scope::Subgroup));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Some mobile GPUs (e.g. Adreno/Turnip) only advertise subgroup ballot/shuffle support for the
|
||||||
|
// fragment and compute stages (VkPhysicalDeviceSubgroupProperties::supportedStages), even though
|
||||||
|
// they support these operations elsewhere. Guest shaders that use VOTE/SHFL in a geometry program
|
||||||
|
// would otherwise emit GroupNonUniform* SPIR-V the driver never declared support for in that
|
||||||
|
// stage. There is no barrier in the geometry stage, so a real cross-invocation emulation can't be
|
||||||
|
// made correct; instead, treat the current invocation as if it were alone in its subgroup. This is
|
||||||
|
// semantically wrong for guest code that relies on genuine cross-lane communication, but it is
|
||||||
|
// well-defined, valid SPIR-V that doesn't depend on unsupported hardware capabilities.
|
||||||
|
bool NeedsGeometrySubgroupFallback(EmitContext& ctx) {
|
||||||
|
return ctx.stage == Stage::Geometry && !ctx.profile.support_subgroup_in_geometry_stage;
|
||||||
|
}
|
||||||
|
|
||||||
bool StageSupportsSubgroups(EmitContext& ctx) {
|
bool StageSupportsSubgroups(EmitContext& ctx) {
|
||||||
return ctx.profile.SupportsSubgroupStage(ctx.stage);
|
return ctx.profile.SupportsSubgroupStage(ctx.stage);
|
||||||
}
|
}
|
||||||
@@ -94,6 +106,9 @@ Id AddPartitionBase(EmitContext& ctx, Id thread_id) {
|
|||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
Id EmitLaneId(EmitContext& ctx) {
|
Id EmitLaneId(EmitContext& ctx) {
|
||||||
|
if (NeedsGeometrySubgroupFallback(ctx)) {
|
||||||
|
return ctx.u32_zero_value;
|
||||||
|
}
|
||||||
const Id id{GetThreadId(ctx)};
|
const Id id{GetThreadId(ctx)};
|
||||||
if (!ctx.profile.warp_size_potentially_larger_than_guest) {
|
if (!ctx.profile.warp_size_potentially_larger_than_guest) {
|
||||||
return id;
|
return id;
|
||||||
@@ -102,6 +117,9 @@ Id EmitLaneId(EmitContext& ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitVoteAll(EmitContext& ctx, Id pred) {
|
Id EmitVoteAll(EmitContext& ctx, Id pred) {
|
||||||
|
if (NeedsGeometrySubgroupFallback(ctx)) {
|
||||||
|
return pred;
|
||||||
|
}
|
||||||
if (!StageSupportsSubgroups(ctx)) {
|
if (!StageSupportsSubgroups(ctx)) {
|
||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
@@ -118,6 +136,9 @@ Id EmitVoteAll(EmitContext& ctx, Id pred) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitVoteAny(EmitContext& ctx, Id pred) {
|
Id EmitVoteAny(EmitContext& ctx, Id pred) {
|
||||||
|
if (NeedsGeometrySubgroupFallback(ctx)) {
|
||||||
|
return pred;
|
||||||
|
}
|
||||||
if (!StageSupportsSubgroups(ctx)) {
|
if (!StageSupportsSubgroups(ctx)) {
|
||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
@@ -134,6 +155,9 @@ Id EmitVoteAny(EmitContext& ctx, Id pred) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitVoteEqual(EmitContext& ctx, Id pred) {
|
Id EmitVoteEqual(EmitContext& ctx, Id pred) {
|
||||||
|
if (NeedsGeometrySubgroupFallback(ctx)) {
|
||||||
|
return ctx.true_value;
|
||||||
|
}
|
||||||
if (!StageSupportsSubgroups(ctx)) {
|
if (!StageSupportsSubgroups(ctx)) {
|
||||||
return ctx.true_value;
|
return ctx.true_value;
|
||||||
}
|
}
|
||||||
@@ -151,6 +175,16 @@ Id EmitVoteEqual(EmitContext& ctx, Id pred) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSubgroupBallot(EmitContext& ctx, Id pred) {
|
Id EmitSubgroupBallot(EmitContext& ctx, Id pred) {
|
||||||
|
if (NeedsGeometrySubgroupFallback(ctx)) {
|
||||||
|
// Reflect only this invocation's own predicate. There is no way to observe other
|
||||||
|
// invocations' predicates without real subgroup hardware support in this stage, so this
|
||||||
|
// is a best-effort approximation: it keeps any branch gated on "did anyone match" live
|
||||||
|
// (rather than letting the SPIR-V optimizer prove it dead, which previously caused
|
||||||
|
// indirect draws fed by this shader to see indexCount=instanceCount=0), but any downstream
|
||||||
|
// math that assumes a real cross-lane population count (e.g. popcount-based compaction
|
||||||
|
// offsets) will not be correct.
|
||||||
|
return ctx.OpSelect(ctx.U32[1], pred, ctx.Const(1U), ctx.u32_zero_value);
|
||||||
|
}
|
||||||
if (!StageSupportsSubgroups(ctx)) {
|
if (!StageSupportsSubgroups(ctx)) {
|
||||||
return ctx.OpSelect(ctx.U32[1], pred, ctx.Const(1u), ctx.u32_zero_value);
|
return ctx.OpSelect(ctx.U32[1], pred, ctx.Const(1u), ctx.u32_zero_value);
|
||||||
}
|
}
|
||||||
@@ -162,6 +196,9 @@ Id EmitSubgroupBallot(EmitContext& ctx, Id pred) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSubgroupEqMask(EmitContext& ctx) {
|
Id EmitSubgroupEqMask(EmitContext& ctx) {
|
||||||
|
if (NeedsGeometrySubgroupFallback(ctx)) {
|
||||||
|
return ctx.Const(1U);
|
||||||
|
}
|
||||||
if (!StageSupportsSubgroups(ctx)) {
|
if (!StageSupportsSubgroups(ctx)) {
|
||||||
return ctx.Const(1u);
|
return ctx.Const(1u);
|
||||||
}
|
}
|
||||||
@@ -169,6 +206,9 @@ Id EmitSubgroupEqMask(EmitContext& ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSubgroupLtMask(EmitContext& ctx) {
|
Id EmitSubgroupLtMask(EmitContext& ctx) {
|
||||||
|
if (NeedsGeometrySubgroupFallback(ctx)) {
|
||||||
|
return ctx.u32_zero_value;
|
||||||
|
}
|
||||||
if (!StageSupportsSubgroups(ctx)) {
|
if (!StageSupportsSubgroups(ctx)) {
|
||||||
return ctx.u32_zero_value;
|
return ctx.u32_zero_value;
|
||||||
}
|
}
|
||||||
@@ -176,6 +216,9 @@ Id EmitSubgroupLtMask(EmitContext& ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSubgroupLeMask(EmitContext& ctx) {
|
Id EmitSubgroupLeMask(EmitContext& ctx) {
|
||||||
|
if (NeedsGeometrySubgroupFallback(ctx)) {
|
||||||
|
return ctx.Const(1U);
|
||||||
|
}
|
||||||
if (!StageSupportsSubgroups(ctx)) {
|
if (!StageSupportsSubgroups(ctx)) {
|
||||||
return ctx.Const(1u);
|
return ctx.Const(1u);
|
||||||
}
|
}
|
||||||
@@ -183,6 +226,9 @@ Id EmitSubgroupLeMask(EmitContext& ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSubgroupGtMask(EmitContext& ctx) {
|
Id EmitSubgroupGtMask(EmitContext& ctx) {
|
||||||
|
if (NeedsGeometrySubgroupFallback(ctx)) {
|
||||||
|
return ctx.u32_zero_value;
|
||||||
|
}
|
||||||
if (!StageSupportsSubgroups(ctx)) {
|
if (!StageSupportsSubgroups(ctx)) {
|
||||||
return ctx.u32_zero_value;
|
return ctx.u32_zero_value;
|
||||||
}
|
}
|
||||||
@@ -190,6 +236,9 @@ Id EmitSubgroupGtMask(EmitContext& ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSubgroupGeMask(EmitContext& ctx) {
|
Id EmitSubgroupGeMask(EmitContext& ctx) {
|
||||||
|
if (NeedsGeometrySubgroupFallback(ctx)) {
|
||||||
|
return ctx.Const(1U);
|
||||||
|
}
|
||||||
if (!StageSupportsSubgroups(ctx)) {
|
if (!StageSupportsSubgroups(ctx)) {
|
||||||
return ctx.Const(1u);
|
return ctx.Const(1u);
|
||||||
}
|
}
|
||||||
@@ -198,6 +247,10 @@ Id EmitSubgroupGeMask(EmitContext& ctx) {
|
|||||||
|
|
||||||
Id EmitShuffleIndex(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp,
|
Id EmitShuffleIndex(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp,
|
||||||
Id segmentation_mask) {
|
Id segmentation_mask) {
|
||||||
|
if (NeedsGeometrySubgroupFallback(ctx)) {
|
||||||
|
SetInBoundsFlag(inst, ctx.false_value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
const Id not_seg_mask{ctx.OpNot(ctx.U32[1], segmentation_mask)};
|
const Id not_seg_mask{ctx.OpNot(ctx.U32[1], segmentation_mask)};
|
||||||
const Id thread_id{EmitLaneId(ctx)};
|
const Id thread_id{EmitLaneId(ctx)};
|
||||||
const Id min_thread_id{ComputeMinThreadId(ctx, thread_id, segmentation_mask)};
|
const Id min_thread_id{ComputeMinThreadId(ctx, thread_id, segmentation_mask)};
|
||||||
@@ -217,6 +270,10 @@ Id EmitShuffleIndex(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id cla
|
|||||||
|
|
||||||
Id EmitShuffleUp(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp,
|
Id EmitShuffleUp(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp,
|
||||||
Id segmentation_mask) {
|
Id segmentation_mask) {
|
||||||
|
if (NeedsGeometrySubgroupFallback(ctx)) {
|
||||||
|
SetInBoundsFlag(inst, ctx.false_value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
const Id thread_id{EmitLaneId(ctx)};
|
const Id thread_id{EmitLaneId(ctx)};
|
||||||
const Id max_thread_id{GetMaxThreadId(ctx, thread_id, clamp, segmentation_mask)};
|
const Id max_thread_id{GetMaxThreadId(ctx, thread_id, clamp, segmentation_mask)};
|
||||||
Id src_thread_id{ctx.OpISub(ctx.U32[1], thread_id, index)};
|
Id src_thread_id{ctx.OpISub(ctx.U32[1], thread_id, index)};
|
||||||
@@ -232,6 +289,10 @@ Id EmitShuffleUp(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp,
|
|||||||
|
|
||||||
Id EmitShuffleDown(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp,
|
Id EmitShuffleDown(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp,
|
||||||
Id segmentation_mask) {
|
Id segmentation_mask) {
|
||||||
|
if (NeedsGeometrySubgroupFallback(ctx)) {
|
||||||
|
SetInBoundsFlag(inst, ctx.false_value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
const Id thread_id{EmitLaneId(ctx)};
|
const Id thread_id{EmitLaneId(ctx)};
|
||||||
const Id max_thread_id{GetMaxThreadId(ctx, thread_id, clamp, segmentation_mask)};
|
const Id max_thread_id{GetMaxThreadId(ctx, thread_id, clamp, segmentation_mask)};
|
||||||
Id src_thread_id{ctx.OpIAdd(ctx.U32[1], thread_id, index)};
|
Id src_thread_id{ctx.OpIAdd(ctx.U32[1], thread_id, index)};
|
||||||
@@ -247,6 +308,10 @@ Id EmitShuffleDown(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clam
|
|||||||
|
|
||||||
Id EmitShuffleButterfly(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp,
|
Id EmitShuffleButterfly(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp,
|
||||||
Id segmentation_mask) {
|
Id segmentation_mask) {
|
||||||
|
if (NeedsGeometrySubgroupFallback(ctx)) {
|
||||||
|
SetInBoundsFlag(inst, ctx.false_value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
const Id thread_id{EmitLaneId(ctx)};
|
const Id thread_id{EmitLaneId(ctx)};
|
||||||
const Id max_thread_id{GetMaxThreadId(ctx, thread_id, clamp, segmentation_mask)};
|
const Id max_thread_id{GetMaxThreadId(ctx, thread_id, clamp, segmentation_mask)};
|
||||||
Id src_thread_id{ctx.OpBitwiseXor(ctx.U32[1], thread_id, index)};
|
Id src_thread_id{ctx.OpBitwiseXor(ctx.U32[1], thread_id, index)};
|
||||||
|
|||||||
@@ -1455,13 +1455,14 @@ void EmitContext::DefineInputs(const IR::Program& program) {
|
|||||||
if (info.uses_is_helper_invocation) {
|
if (info.uses_is_helper_invocation) {
|
||||||
is_helper_invocation = DefineInput(*this, U1, false, spv::BuiltIn::HelperInvocation);
|
is_helper_invocation = DefineInput(*this, U1, false, spv::BuiltIn::HelperInvocation);
|
||||||
}
|
}
|
||||||
if (info.uses_subgroup_mask && profile.SupportsSubgroupStage(stage)) {
|
if (info.uses_subgroup_mask &&
|
||||||
|
(stage != Stage::Geometry || profile.support_subgroup_in_geometry_stage)) {
|
||||||
subgroup_mask_eq = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupEqMaskKHR);
|
subgroup_mask_eq = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupEqMaskKHR);
|
||||||
subgroup_mask_lt = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupLtMaskKHR);
|
subgroup_mask_lt = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupLtMaskKHR);
|
||||||
subgroup_mask_le = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupLeMaskKHR);
|
subgroup_mask_le = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupLeMaskKHR);
|
||||||
subgroup_mask_gt = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupGtMaskKHR);
|
subgroup_mask_gt = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupGtMaskKHR);
|
||||||
subgroup_mask_ge = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupGeMaskKHR);
|
subgroup_mask_ge = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupGeMaskKHR);
|
||||||
if (stage == Stage::Fragment) {
|
if (profile.support_explicit_workgroup_layout) {
|
||||||
Decorate(subgroup_mask_eq, spv::Decoration::Flat);
|
Decorate(subgroup_mask_eq, spv::Decoration::Flat);
|
||||||
Decorate(subgroup_mask_lt, spv::Decoration::Flat);
|
Decorate(subgroup_mask_lt, spv::Decoration::Flat);
|
||||||
Decorate(subgroup_mask_le, spv::Decoration::Flat);
|
Decorate(subgroup_mask_le, spv::Decoration::Flat);
|
||||||
@@ -1469,10 +1470,11 @@ void EmitContext::DefineInputs(const IR::Program& program) {
|
|||||||
Decorate(subgroup_mask_ge, spv::Decoration::Flat);
|
Decorate(subgroup_mask_ge, spv::Decoration::Flat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((info.uses_fswzadd || info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles ||
|
if (info.uses_fswzadd ||
|
||||||
(profile.warp_size_potentially_larger_than_guest &&
|
((info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles ||
|
||||||
(info.uses_subgroup_vote || info.uses_subgroup_mask))) &&
|
(profile.warp_size_potentially_larger_than_guest &&
|
||||||
profile.SupportsSubgroupStage(stage)) {
|
(info.uses_subgroup_vote || info.uses_subgroup_mask))) &&
|
||||||
|
(stage != Stage::Geometry || profile.support_subgroup_in_geometry_stage))) {
|
||||||
AddCapability(spv::Capability::GroupNonUniform);
|
AddCapability(spv::Capability::GroupNonUniform);
|
||||||
subgroup_local_invocation_id =
|
subgroup_local_invocation_id =
|
||||||
DefineInput(*this, U32[1], false, spv::BuiltIn::SubgroupLocalInvocationId);
|
DefineInput(*this, U32[1], false, spv::BuiltIn::SubgroupLocalInvocationId);
|
||||||
|
|||||||
@@ -41,6 +41,12 @@ struct Profile {
|
|||||||
bool support_quad_shuffles{};
|
bool support_quad_shuffles{};
|
||||||
bool support_vote{};
|
bool support_vote{};
|
||||||
u32 supported_subgroup_stages{0x7F};
|
u32 supported_subgroup_stages{0x7F};
|
||||||
|
bool support_subgroup_in_geometry_stage{}; ///< True when the device advertises subgroup
|
||||||
|
///< ballot/shuffle support for VK_SHADER_STAGE_GEOMETRY_BIT
|
||||||
|
///< (VkPhysicalDeviceSubgroupProperties::supportedStages).
|
||||||
|
///< Many mobile GPUs support subgroup ops only in
|
||||||
|
///< fragment/compute; guest shaders using VOTE/SHFL in a
|
||||||
|
///< geometry program need a non-subgroup fallback there.
|
||||||
bool support_viewport_index_layer_non_geometry{};
|
bool support_viewport_index_layer_non_geometry{};
|
||||||
bool support_viewport_mask{};
|
bool support_viewport_mask{};
|
||||||
bool support_typeless_image_loads{};
|
bool support_typeless_image_loads{};
|
||||||
|
|||||||
@@ -410,6 +410,11 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
|||||||
.support_quad_shuffles = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_QUAD_BIT),
|
.support_quad_shuffles = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_QUAD_BIT),
|
||||||
.support_vote = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_VOTE_BIT),
|
.support_vote = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_VOTE_BIT),
|
||||||
.supported_subgroup_stages = supported_subgroup_stages,
|
.supported_subgroup_stages = supported_subgroup_stages,
|
||||||
|
.support_subgroup_in_geometry_stage =
|
||||||
|
device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_VOTE_BIT) &&
|
||||||
|
device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_BALLOT_BIT) &&
|
||||||
|
device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_SHUFFLE_BIT) &&
|
||||||
|
device.IsSubgroupFeatureSupportedInStage(VK_SHADER_STAGE_GEOMETRY_BIT),
|
||||||
.support_viewport_index_layer_non_geometry =
|
.support_viewport_index_layer_non_geometry =
|
||||||
device.IsExtShaderViewportIndexLayerSupported(),
|
device.IsExtShaderViewportIndexLayerSupported(),
|
||||||
.support_viewport_mask = device.IsNvViewportArray2Supported(),
|
.support_viewport_mask = device.IsNvViewportArray2Supported(),
|
||||||
|
|||||||
@@ -479,6 +479,11 @@ FN_MAX_LIMIT_LIST
|
|||||||
return properties.subgroup_properties.supportedStages;
|
return properties.subgroup_properties.supportedStages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the device supports subgroup ballot/shuffle in the given shader stage.
|
||||||
|
bool IsSubgroupFeatureSupportedInStage(VkShaderStageFlagBits stage) const {
|
||||||
|
return properties.subgroup_properties.supportedStages & stage;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the maximum number of push descriptors.
|
/// Returns the maximum number of push descriptors.
|
||||||
u32 MaxPushDescriptors() const {
|
u32 MaxPushDescriptors() const {
|
||||||
return properties.push_descriptor.maxPushDescriptors;
|
return properties.push_descriptor.maxPushDescriptors;
|
||||||
|
|||||||
@@ -43,32 +43,26 @@ namespace {
|
|||||||
switch (window_type) {
|
switch (window_type) {
|
||||||
case Core::Frontend::WindowSystemType::Headless:
|
case Core::Frontend::WindowSystemType::Headless:
|
||||||
break;
|
break;
|
||||||
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
#ifdef _WIN32
|
||||||
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(VK_USE_PLATFORM_METAL_EXT)
|
|
||||||
case Core::Frontend::WindowSystemType::Cocoa:
|
case Core::Frontend::WindowSystemType::Cocoa:
|
||||||
extensions.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
|
extensions.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
|
||||||
break;
|
break;
|
||||||
#endif
|
#elif defined(__ANDROID__)
|
||||||
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
|
||||||
case Core::Frontend::WindowSystemType::Android:
|
case Core::Frontend::WindowSystemType::Android:
|
||||||
extensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
|
extensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
|
||||||
break;
|
break;
|
||||||
#endif
|
#elif defined(__HAIKU__)
|
||||||
#if defined(VK_USE_PLATFORM_XCB_KHR)
|
|
||||||
case Core::Frontend::WindowSystemType::Xcb:
|
case Core::Frontend::WindowSystemType::Xcb:
|
||||||
extensions.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
|
extensions.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
|
||||||
break;
|
break;
|
||||||
#endif
|
#else
|
||||||
#if defined(VK_USE_PLATFORM_XLIB_KHR)
|
|
||||||
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;
|
||||||
#endif
|
|
||||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
|
||||||
case Core::Frontend::WindowSystemType::Wayland:
|
case Core::Frontend::WindowSystemType::Wayland:
|
||||||
extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
|
extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
#include "video_core/vulkan_common/vulkan_surface.h"
|
#include "video_core/vulkan_common/vulkan_surface.h"
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
#include "video_core/vulkan_common/vulkan.h"
|
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
@@ -18,7 +17,7 @@ vk::SurfaceKHR CreateSurface(
|
|||||||
[[maybe_unused]] const vk::InstanceDispatch& dld = instance.Dispatch();
|
[[maybe_unused]] const vk::InstanceDispatch& dld = instance.Dispatch();
|
||||||
VkSurfaceKHR unsafe_surface = VkSurfaceKHR{};
|
VkSurfaceKHR unsafe_surface = VkSurfaceKHR{};
|
||||||
|
|
||||||
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
#ifdef _WIN32
|
||||||
if (window_info.type == Core::Frontend::WindowSystemType::Windows) {
|
if (window_info.type == Core::Frontend::WindowSystemType::Windows) {
|
||||||
const HWND hWnd = static_cast<HWND>(window_info.render_surface);
|
const HWND hWnd = static_cast<HWND>(window_info.render_surface);
|
||||||
const VkWin32SurfaceCreateInfoKHR win32_ci{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
|
const VkWin32SurfaceCreateInfoKHR win32_ci{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
|
||||||
@@ -31,8 +30,7 @@ vk::SurfaceKHR CreateSurface(
|
|||||||
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#elif defined(__APPLE__)
|
||||||
#if defined(VK_USE_PLATFORM_METAL_EXT)
|
|
||||||
if (window_info.type == Core::Frontend::WindowSystemType::Cocoa) {
|
if (window_info.type == Core::Frontend::WindowSystemType::Cocoa) {
|
||||||
const VkMetalSurfaceCreateInfoEXT metal_ci = {
|
const VkMetalSurfaceCreateInfoEXT metal_ci = {
|
||||||
.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT,
|
.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT,
|
||||||
@@ -47,8 +45,7 @@ vk::SurfaceKHR CreateSurface(
|
|||||||
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#elif defined(__ANDROID__)
|
||||||
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
|
||||||
if (window_info.type == Core::Frontend::WindowSystemType::Android) {
|
if (window_info.type == Core::Frontend::WindowSystemType::Android) {
|
||||||
const VkAndroidSurfaceCreateInfoKHR android_ci{
|
const VkAndroidSurfaceCreateInfoKHR android_ci{
|
||||||
VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, nullptr, 0,
|
VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, nullptr, 0,
|
||||||
@@ -62,8 +59,7 @@ vk::SurfaceKHR CreateSurface(
|
|||||||
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#elif defined(__HAIKU__)
|
||||||
#if defined(VK_USE_PLATFORM_XCB_KHR)
|
|
||||||
if (window_info.type == Core::Frontend::WindowSystemType::Xcb) {
|
if (window_info.type == Core::Frontend::WindowSystemType::Xcb) {
|
||||||
const VkXcbSurfaceCreateInfoKHR xcb_ci{
|
const VkXcbSurfaceCreateInfoKHR xcb_ci{
|
||||||
.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,
|
.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,
|
||||||
@@ -80,8 +76,7 @@ vk::SurfaceKHR CreateSurface(
|
|||||||
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#else
|
||||||
#if defined(VK_USE_PLATFORM_XLIB_KHR)
|
|
||||||
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,
|
||||||
@@ -95,8 +90,6 @@ vk::SurfaceKHR CreateSurface(
|
|||||||
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
|
||||||
if (window_info.type == Core::Frontend::WindowSystemType::Wayland) {
|
if (window_info.type == Core::Frontend::WindowSystemType::Wayland) {
|
||||||
const VkWaylandSurfaceCreateInfoKHR wayland_ci{
|
const VkWaylandSurfaceCreateInfoKHR wayland_ci{
|
||||||
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, nullptr, 0,
|
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, nullptr, 0,
|
||||||
@@ -112,6 +105,7 @@ vk::SurfaceKHR CreateSurface(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#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);
|
||||||
|
|||||||
Reference in New Issue
Block a user