mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-15 13:16:43 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 79b1f923b3 |
@@ -262,13 +262,6 @@ void AndroidConfig::SavePathValues() {
|
||||
}
|
||||
EndArray();
|
||||
|
||||
BeginArray(std::string("blocked_domains"));
|
||||
for (size_t i = 0; i < Settings::values.blocked_domains.size(); ++i) {
|
||||
SetArrayIndex(i);
|
||||
WriteStringSetting(std::string("domain"), Settings::values.blocked_domains[i]);
|
||||
}
|
||||
EndArray();
|
||||
|
||||
// Save custom NAND directory
|
||||
const auto nand_path = Common::FS::GetEdenPathString(Common::FS::EdenPath::NANDDir);
|
||||
WriteStringSetting(std::string("nand_directory"), nand_path,
|
||||
|
||||
@@ -219,6 +219,11 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bool ClearBackingRegion(size_t physical_offset, size_t length) {
|
||||
// TODO: This does not seem to be possible on Windows.
|
||||
return false;
|
||||
}
|
||||
|
||||
void EnableDirectMappedAddress() {
|
||||
// TODO
|
||||
UNREACHABLE();
|
||||
@@ -612,6 +617,24 @@ public:
|
||||
ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno));
|
||||
}
|
||||
|
||||
bool ClearBackingRegion(size_t physical_offset, size_t length) {
|
||||
#ifdef __linux__
|
||||
// Only incur syscall cost IF memset would be slower (theshold = 16MiB)
|
||||
// TODO(lizzie): Smarter way to dynamically get this threshold (broadwell != raptor lake) for example
|
||||
if (length >= 2097152UL * 8) {
|
||||
// Set MADV_REMOVE on backing map to destroy it instantly.
|
||||
// This also deletes the area from the backing file.
|
||||
int ret = madvise(backing_base + physical_offset, length, MADV_REMOVE);
|
||||
ASSERT_MSG(ret == 0, "madvise failed: {}", strerror(errno));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void EnableDirectMappedAddress() {
|
||||
virtual_base = nullptr;
|
||||
}
|
||||
@@ -725,7 +748,9 @@ void HostMemory::Protect(size_t virtual_offset, size_t length, MemoryPermission
|
||||
}
|
||||
|
||||
void HostMemory::ClearBackingRegion(size_t physical_offset, size_t length, u32 fill_value) {
|
||||
std::memset(backing_base + physical_offset, fill_value, length);
|
||||
if (!impl || fill_value != 0 || !impl->ClearBackingRegion(physical_offset, length)) {
|
||||
std::memset(backing_base + physical_offset, fill_value, length);
|
||||
}
|
||||
}
|
||||
|
||||
void HostMemory::EnableDirectMappedAddress() {
|
||||
|
||||
@@ -803,16 +803,9 @@ struct Values {
|
||||
Setting<bool> first_launch{linkage, true, "first_launch", Category::Miscellaneous};
|
||||
|
||||
// Network
|
||||
Setting<std::string> network_interface{linkage, std::string(), "network_interface", Category::Network};
|
||||
Setting<std::string> network_interface{linkage, std::string(), "network_interface",
|
||||
Category::Network};
|
||||
SwitchableSetting<bool> airplane_mode{linkage, false, "airplane_mode", Category::Network};
|
||||
std::vector<std::string> blocked_domains = {
|
||||
"srv.nintendo.net",
|
||||
"battle.net",
|
||||
"microsoft.com",
|
||||
"mojang.com",
|
||||
"xboxlive.com",
|
||||
"minecraftservices.com"
|
||||
};
|
||||
|
||||
// WebService
|
||||
Setting<std::string> web_api_url{linkage, "api.ynet-fun.xyz", "web_api_url",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "common/string_util.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/core.h"
|
||||
@@ -54,11 +53,17 @@ enum class NetDbError : s32 {
|
||||
NoData = 4,
|
||||
};
|
||||
|
||||
static const constexpr std::array blockedDomains = {"srv.nintendo.net",
|
||||
"battle.net",
|
||||
"microsoft.com",
|
||||
"mojang.com",
|
||||
"xboxlive.com",
|
||||
"minecraftservices.com"};
|
||||
|
||||
static bool IsBlockedHost(const std::string& host) {
|
||||
auto const& v = Settings::values.blocked_domains;
|
||||
return std::any_of(v.begin(), v.end(), [&host](const std::string& domain) {
|
||||
return host.find(domain) != std::string::npos;
|
||||
});
|
||||
return std::any_of(
|
||||
blockedDomains.begin(), blockedDomains.end(),
|
||||
[&host](const std::string& domain) { return host.find(domain) != std::string::npos; });
|
||||
}
|
||||
|
||||
static NetDbError GetAddrInfoErrorToNetDbError(GetAddrInfoError result) {
|
||||
@@ -158,17 +163,7 @@ static std::pair<u32, GetAddrInfoError> GetHostByNameRequestImpl(HLERequestConte
|
||||
parameters.use_nsd_resolve, parameters.cancel_handle, parameters.process_id);
|
||||
|
||||
const auto host_buffer = ctx.ReadBuffer(0);
|
||||
|
||||
std::string host = Common::StringFromBuffer(host_buffer);
|
||||
if (parameters.use_nsd_resolve) {
|
||||
// TODO: how its actually done?
|
||||
if (auto const pos = host.find('%'); pos != std::string::npos) {
|
||||
host[pos] = 'l';
|
||||
host.insert(pos, "p1");
|
||||
}
|
||||
LOG_WARNING(Service, "nsd resolve={}", host);
|
||||
}
|
||||
|
||||
const std::string host = Common::StringFromBuffer(host_buffer);
|
||||
// For now, ignore options, which are in input buffer 1 for GetHostByNameRequestWithOptions.
|
||||
|
||||
// Prevent resolution of Nintendo servers
|
||||
|
||||
@@ -105,6 +105,9 @@ add_library(dynarmic STATIC
|
||||
frontend/A32/decoder/thumb32.inc
|
||||
frontend/A32/decoder/vfp.h
|
||||
frontend/A32/decoder/vfp.inc
|
||||
frontend/A32/disassembler/disassembler.h
|
||||
frontend/A32/disassembler/disassembler_arm.cpp
|
||||
frontend/A32/disassembler/disassembler_thumb.cpp
|
||||
frontend/A32/FPSCR.h
|
||||
frontend/A32/ITState.h
|
||||
frontend/A32/PSR.h
|
||||
@@ -119,6 +122,7 @@ add_library(dynarmic STATIC
|
||||
interface/A32/config.h
|
||||
interface/A32/coprocessor.h
|
||||
interface/A32/coprocessor_util.h
|
||||
interface/A32/disassembler.h
|
||||
# A64
|
||||
frontend/A64/a64_ir_emitter.cpp
|
||||
frontend/A64/a64_ir_emitter.h
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2016 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "dynarmic/common/common_types.h"
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
std::string DisassembleArm(u32 instruction);
|
||||
std::string DisassembleThumb16(u16 instruction);
|
||||
|
||||
} // namespace Dynarmic::A32
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,397 @@
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2016 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <fmt/ostream.h>
|
||||
#include <mcl/bit/bit_field.hpp>
|
||||
|
||||
#include "dynarmic/common/string_util.h"
|
||||
#include "dynarmic/frontend/A32/a32_types.h"
|
||||
#include "dynarmic/frontend/A32/decoder/thumb16.h"
|
||||
#include "dynarmic/frontend/A32/disassembler/disassembler.h"
|
||||
#include "dynarmic/frontend/imm.h"
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
class DisassemblerVisitor {
|
||||
public:
|
||||
using instruction_return_type = std::string;
|
||||
|
||||
std::string thumb16_LSL_imm(Imm<5> imm5, Reg m, Reg d) {
|
||||
return fmt::format("lsls {}, {}, #{}", d, m, imm5.ZeroExtend());
|
||||
}
|
||||
|
||||
std::string thumb16_LSR_imm(Imm<5> imm5, Reg m, Reg d) {
|
||||
const u32 shift = imm5 != 0 ? imm5.ZeroExtend() : 32U;
|
||||
return fmt::format("lsrs {}, {}, #{}", d, m, shift);
|
||||
}
|
||||
|
||||
std::string thumb16_ASR_imm(Imm<5> imm5, Reg m, Reg d) {
|
||||
const u32 shift = imm5 != 0 ? imm5.ZeroExtend() : 32U;
|
||||
return fmt::format("asrs {}, {}, #{}", d, m, shift);
|
||||
}
|
||||
|
||||
std::string thumb16_ADD_reg_t1(Reg m, Reg n, Reg d) {
|
||||
return fmt::format("adds {}, {}, {}", d, n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_SUB_reg(Reg m, Reg n, Reg d) {
|
||||
return fmt::format("subs {}, {}, {}", d, n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_ADD_imm_t1(Imm<3> imm3, Reg n, Reg d) {
|
||||
return fmt::format("adds {}, {}, #{}", d, n, imm3.ZeroExtend());
|
||||
}
|
||||
|
||||
std::string thumb16_SUB_imm_t1(Imm<3> imm3, Reg n, Reg d) {
|
||||
return fmt::format("subs {}, {}, #{}", d, n, imm3.ZeroExtend());
|
||||
}
|
||||
|
||||
std::string thumb16_MOV_imm(Reg d, Imm<8> imm8) {
|
||||
return fmt::format("movs {}, #{}", d, imm8.ZeroExtend());
|
||||
}
|
||||
|
||||
std::string thumb16_CMP_imm(Reg n, Imm<8> imm8) {
|
||||
return fmt::format("cmp {}, #{}", n, imm8.ZeroExtend());
|
||||
}
|
||||
|
||||
std::string thumb16_ADD_imm_t2(Reg d_n, Imm<8> imm8) {
|
||||
return fmt::format("adds {}, #{}", d_n, imm8.ZeroExtend());
|
||||
}
|
||||
|
||||
std::string thumb16_SUB_imm_t2(Reg d_n, Imm<8> imm8) {
|
||||
return fmt::format("subs {}, #{}", d_n, imm8.ZeroExtend());
|
||||
}
|
||||
|
||||
std::string thumb16_AND_reg(Reg m, Reg d_n) {
|
||||
return fmt::format("ands {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_EOR_reg(Reg m, Reg d_n) {
|
||||
return fmt::format("eors {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_LSL_reg(Reg m, Reg d_n) {
|
||||
return fmt::format("lsls {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_LSR_reg(Reg m, Reg d_n) {
|
||||
return fmt::format("lsrs {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_ASR_reg(Reg m, Reg d_n) {
|
||||
return fmt::format("asrs {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_ADC_reg(Reg m, Reg d_n) {
|
||||
return fmt::format("adcs {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_SBC_reg(Reg m, Reg d_n) {
|
||||
return fmt::format("sbcs {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_ROR_reg(Reg m, Reg d_n) {
|
||||
return fmt::format("rors {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_TST_reg(Reg m, Reg n) {
|
||||
return fmt::format("tst {}, {}", n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_RSB_imm(Reg n, Reg d) {
|
||||
// Pre-UAL syntax: NEGS <Rd>, <Rn>
|
||||
return fmt::format("rsbs {}, {}, #0", d, n);
|
||||
}
|
||||
|
||||
std::string thumb16_CMP_reg_t1(Reg m, Reg n) {
|
||||
return fmt::format("cmp {}, {}", n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_CMN_reg(Reg m, Reg n) {
|
||||
return fmt::format("cmn {}, {}", n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_ORR_reg(Reg m, Reg d_n) {
|
||||
return fmt::format("orrs {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_MUL_reg(Reg n, Reg d_m) {
|
||||
return fmt::format("muls {}, {}, {}", d_m, n, d_m);
|
||||
}
|
||||
|
||||
std::string thumb16_BIC_reg(Reg m, Reg d_n) {
|
||||
return fmt::format("bics {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_MVN_reg(Reg m, Reg d) {
|
||||
return fmt::format("mvns {}, {}", d, m);
|
||||
}
|
||||
|
||||
std::string thumb16_ADD_reg_t2(bool d_n_hi, Reg m, Reg d_n_lo) {
|
||||
const Reg d_n = d_n_hi ? (d_n_lo + 8) : d_n_lo;
|
||||
return fmt::format("add {}, {}", d_n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_CMP_reg_t2(bool n_hi, Reg m, Reg n_lo) {
|
||||
const Reg n = n_hi ? (n_lo + 8) : n_lo;
|
||||
return fmt::format("cmp {}, {}", n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_MOV_reg(bool d_hi, Reg m, Reg d_lo) {
|
||||
const Reg d = d_hi ? (d_lo + 8) : d_lo;
|
||||
return fmt::format("mov {}, {}", d, m);
|
||||
}
|
||||
|
||||
std::string thumb16_LDR_literal(Reg t, Imm<8> imm8) {
|
||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
||||
return fmt::format("ldr {}, [pc, #{}]", t, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_STR_reg(Reg m, Reg n, Reg t) {
|
||||
return fmt::format("str {}, [{}, {}]", t, n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_STRH_reg(Reg m, Reg n, Reg t) {
|
||||
return fmt::format("strh {}, [{}, {}]", t, n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_STRB_reg(Reg m, Reg n, Reg t) {
|
||||
return fmt::format("strb {}, [{}, {}]", t, n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_LDRSB_reg(Reg m, Reg n, Reg t) {
|
||||
return fmt::format("ldrsb {}, [{}, {}]", t, n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_LDR_reg(Reg m, Reg n, Reg t) {
|
||||
return fmt::format("ldr {}, [{}, {}]", t, n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_LDRH_reg(Reg m, Reg n, Reg t) {
|
||||
return fmt::format("ldrh {}, [%s, %s]", t, n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_LDRB_reg(Reg m, Reg n, Reg t) {
|
||||
return fmt::format("ldrb {}, [{}, {}]", t, n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_LDRSH_reg(Reg m, Reg n, Reg t) {
|
||||
return fmt::format("ldrsh {}, [{}, {}]", t, n, m);
|
||||
}
|
||||
|
||||
std::string thumb16_STR_imm_t1(Imm<5> imm5, Reg n, Reg t) {
|
||||
const u32 imm32 = imm5.ZeroExtend() << 2;
|
||||
return fmt::format("str {}, [{}, #{}]", t, n, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_LDR_imm_t1(Imm<5> imm5, Reg n, Reg t) {
|
||||
const u32 imm32 = imm5.ZeroExtend() << 2;
|
||||
return fmt::format("ldr {}, [{}, #{}]", t, n, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_STRB_imm(Imm<5> imm5, Reg n, Reg t) {
|
||||
const u32 imm32 = imm5.ZeroExtend();
|
||||
return fmt::format("strb {}, [{}, #{}]", t, n, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_LDRB_imm(Imm<5> imm5, Reg n, Reg t) {
|
||||
const u32 imm32 = imm5.ZeroExtend();
|
||||
return fmt::format("ldrb {}, [{}, #{}]", t, n, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_STRH_imm(Imm<5> imm5, Reg n, Reg t) {
|
||||
const u32 imm32 = imm5.ZeroExtend() << 1;
|
||||
return fmt::format("strh {}, [{}, #{}]", t, n, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_LDRH_imm(Imm<5> imm5, Reg n, Reg t) {
|
||||
const u32 imm32 = imm5.ZeroExtend() << 1;
|
||||
return fmt::format("ldrh {}, [{}, #{}]", t, n, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_STR_imm_t2(Reg t, Imm<8> imm8) {
|
||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
||||
return fmt::format("str {}, [sp, #{}]", t, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_LDR_imm_t2(Reg t, Imm<8> imm8) {
|
||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
||||
return fmt::format("ldr {}, [sp, #{}]", t, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_ADR(Reg d, Imm<8> imm8) {
|
||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
||||
return fmt::format("adr {}, +#{}", d, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_ADD_sp_t1(Reg d, Imm<8> imm8) {
|
||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
||||
return fmt::format("add {}, sp, #{}", d, imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_ADD_sp_t2(Imm<7> imm7) {
|
||||
const u32 imm32 = imm7.ZeroExtend() << 2;
|
||||
return fmt::format("add sp, sp, #{}", imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_SUB_sp(Imm<7> imm7) {
|
||||
const u32 imm32 = imm7.ZeroExtend() << 2;
|
||||
return fmt::format("sub sp, sp, #{}", imm32);
|
||||
}
|
||||
|
||||
std::string thumb16_NOP() {
|
||||
return "nop";
|
||||
}
|
||||
|
||||
std::string thumb16_SEV() {
|
||||
return "sev";
|
||||
}
|
||||
|
||||
std::string thumb16_SEVL() {
|
||||
return "sevl";
|
||||
}
|
||||
|
||||
std::string thumb16_WFE() {
|
||||
return "wfe";
|
||||
}
|
||||
|
||||
std::string thumb16_WFI() {
|
||||
return "wfi";
|
||||
}
|
||||
|
||||
std::string thumb16_YIELD() {
|
||||
return "yield";
|
||||
}
|
||||
|
||||
std::string thumb16_IT(Imm<8> imm8) {
|
||||
const Cond firstcond = imm8.Bits<4, 7, Cond>();
|
||||
const bool firstcond0 = imm8.Bit<4>();
|
||||
const auto [x, y, z] = [&] {
|
||||
if (imm8.Bits<0, 3>() == 0b1000) {
|
||||
return std::make_tuple("", "", "");
|
||||
}
|
||||
if (imm8.Bits<0, 2>() == 0b100) {
|
||||
return std::make_tuple(imm8.Bit<3>() == firstcond0 ? "t" : "e", "", "");
|
||||
}
|
||||
if (imm8.Bits<0, 1>() == 0b10) {
|
||||
return std::make_tuple(imm8.Bit<3>() == firstcond0 ? "t" : "e", imm8.Bit<2>() == firstcond0 ? "t" : "e", "");
|
||||
}
|
||||
// Sanity note: Here imm8.Bit<0>() is guaranteed to be == 1. (imm8 can never be 0bxxxx0000)
|
||||
return std::make_tuple(imm8.Bit<3>() == firstcond0 ? "t" : "e", imm8.Bit<2>() == firstcond0 ? "t" : "e", imm8.Bit<1>() == firstcond0 ? "t" : "e");
|
||||
}();
|
||||
return fmt::format("it{}{}{} {}", x, y, z, CondToString(firstcond));
|
||||
}
|
||||
|
||||
std::string thumb16_SXTH(Reg m, Reg d) {
|
||||
return fmt::format("sxth {}, {}", d, m);
|
||||
}
|
||||
|
||||
std::string thumb16_SXTB(Reg m, Reg d) {
|
||||
return fmt::format("sxtb {}, {}", d, m);
|
||||
}
|
||||
|
||||
std::string thumb16_UXTH(Reg m, Reg d) {
|
||||
return fmt::format("uxth {}, {}", d, m);
|
||||
}
|
||||
|
||||
std::string thumb16_UXTB(Reg m, Reg d) {
|
||||
return fmt::format("uxtb {}, {}", d, m);
|
||||
}
|
||||
|
||||
std::string thumb16_PUSH(bool M, RegList reg_list) {
|
||||
if (M)
|
||||
reg_list |= 1 << 14;
|
||||
return fmt::format("push {{{}}}", RegListToString(reg_list));
|
||||
}
|
||||
|
||||
std::string thumb16_POP(bool P, RegList reg_list) {
|
||||
if (P)
|
||||
reg_list |= 1 << 15;
|
||||
return fmt::format("pop {{{}}}", RegListToString(reg_list));
|
||||
}
|
||||
|
||||
std::string thumb16_SETEND(bool E) {
|
||||
return fmt::format("setend {}", E ? "BE" : "LE");
|
||||
}
|
||||
|
||||
std::string thumb16_CPS(bool im, bool a, bool i, bool f) {
|
||||
return fmt::format("cps{} {}{}{}", im ? "id" : "ie", a ? "a" : "", i ? "i" : "", f ? "f" : "");
|
||||
}
|
||||
|
||||
std::string thumb16_REV(Reg m, Reg d) {
|
||||
return fmt::format("rev {}, {}", d, m);
|
||||
}
|
||||
|
||||
std::string thumb16_REV16(Reg m, Reg d) {
|
||||
return fmt::format("rev16 {}, {}", d, m);
|
||||
}
|
||||
|
||||
std::string thumb16_REVSH(Reg m, Reg d) {
|
||||
return fmt::format("revsh {}, {}", d, m);
|
||||
}
|
||||
|
||||
std::string thumb16_BKPT(Imm<8> imm8) {
|
||||
return fmt::format("bkpt #{}", imm8.ZeroExtend());
|
||||
}
|
||||
|
||||
std::string thumb16_STMIA(Reg n, RegList reg_list) {
|
||||
return fmt::format("stm {}!, {{{}}}", n, RegListToString(reg_list));
|
||||
}
|
||||
|
||||
std::string thumb16_LDMIA(Reg n, RegList reg_list) {
|
||||
const bool write_back = !mcl::bit::get_bit(static_cast<size_t>(n), reg_list);
|
||||
return fmt::format("ldm {}{}, {{{}}}", n, write_back ? "!" : "", RegListToString(reg_list));
|
||||
}
|
||||
|
||||
std::string thumb16_BX(Reg m) {
|
||||
return fmt::format("bx {}", m);
|
||||
}
|
||||
|
||||
std::string thumb16_BLX_reg(Reg m) {
|
||||
return fmt::format("blx {}", m);
|
||||
}
|
||||
|
||||
std::string thumb16_CBZ_CBNZ(bool nonzero, Imm<1> i, Imm<5> imm5, Reg n) {
|
||||
const char* const name = nonzero ? "cbnz" : "cbz";
|
||||
const u32 imm = concatenate(i, imm5, Imm<1>{0}).ZeroExtend();
|
||||
|
||||
return fmt::format("{} {}, #{}", name, n, imm);
|
||||
}
|
||||
|
||||
std::string thumb16_UDF() {
|
||||
return fmt::format("udf");
|
||||
}
|
||||
|
||||
std::string thumb16_SVC(Imm<8> imm8) {
|
||||
return fmt::format("svc #{}", imm8.ZeroExtend());
|
||||
}
|
||||
|
||||
std::string thumb16_B_t1(Cond cond, Imm<8> imm8) {
|
||||
const s32 imm32 = static_cast<s32>((imm8.SignExtend<u32>() << 1) + 4);
|
||||
return fmt::format("b{} {}#{}",
|
||||
CondToString(cond),
|
||||
Common::SignToChar(imm32),
|
||||
abs(imm32));
|
||||
}
|
||||
|
||||
std::string thumb16_B_t2(Imm<11> imm11) {
|
||||
const s32 imm32 = static_cast<s32>((imm11.SignExtend<u32>() << 1) + 4);
|
||||
return fmt::format("b {}#{}",
|
||||
Common::SignToChar(imm32),
|
||||
abs(imm32));
|
||||
}
|
||||
};
|
||||
|
||||
std::string DisassembleThumb16(u16 instruction) {
|
||||
DisassemblerVisitor visitor;
|
||||
auto decoder = DecodeThumb16<DisassemblerVisitor>(instruction);
|
||||
return !decoder ? fmt::format("UNKNOWN: {:x}", instruction) : decoder->get().call(visitor, instruction);
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::A32
|
||||
@@ -0,0 +1,18 @@
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2016 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace A32 {
|
||||
|
||||
std::string DisassembleArm(std::uint32_t instruction);
|
||||
std::string DisassembleThumb16(std::uint16_t instruction);
|
||||
|
||||
} // namespace A32
|
||||
} // namespace Dynarmic
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "dynarmic/frontend/A32/FPSCR.h"
|
||||
#include "dynarmic/frontend/A32/PSR.h"
|
||||
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
||||
#include "dynarmic/frontend/A32/disassembler/disassembler.h"
|
||||
#include "dynarmic/frontend/A32/translate/a32_translate.h"
|
||||
#include "dynarmic/interface/A32/a32.h"
|
||||
#include "dynarmic/ir/basic_block.h"
|
||||
|
||||
@@ -0,0 +1,381 @@
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2016 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "dynarmic/frontend/A32/disassembler/disassembler.h"
|
||||
|
||||
using Dynarmic::A32::DisassembleArm;
|
||||
|
||||
TEST_CASE("Disassemble branch instructions", "[arm][disassembler]") {
|
||||
REQUIRE(DisassembleArm(0xEAFFFFFE) == "b +#0");
|
||||
REQUIRE(DisassembleArm(0xEB000008) == "bl +#40");
|
||||
REQUIRE(DisassembleArm(0xFBFFFFFE) == "blx +#2");
|
||||
REQUIRE(DisassembleArm(0xFAFFFFFF) == "blx +#4");
|
||||
REQUIRE(DisassembleArm(0xFBE1E7FE) == "blx -#7888894");
|
||||
REQUIRE(DisassembleArm(0xE12FFF3D) == "blx sp");
|
||||
REQUIRE(DisassembleArm(0x312FFF13) == "bxcc r3");
|
||||
REQUIRE(DisassembleArm(0x012FFF29) == "bxjeq r9");
|
||||
}
|
||||
|
||||
TEST_CASE("Disassemble data processing instructions", "[arm][disassembler]") {
|
||||
REQUIRE(DisassembleArm(0xE2A21004) == "adc r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0A21143) == "adc r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0A21103) == "adc r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0A21123) == "adc r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0A21163) == "adc r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0A21003) == "adc r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0A21063) == "adc r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE0A21453) == "adc r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0A21413) == "adc r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0A21433) == "adc r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0A21473) == "adc r1, r2, r3, ror r4");
|
||||
REQUIRE(DisassembleArm(0xE2B21004) == "adcs r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0B21143) == "adcs r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0B21103) == "adcs r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0B21123) == "adcs r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0B21163) == "adcs r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0B21003) == "adcs r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0B21063) == "adcs r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE0B21453) == "adcs r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0B21413) == "adcs r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0B21433) == "adcs r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0B21473) == "adcs r1, r2, r3, ror r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE2853004) == "add r3, r5, #4");
|
||||
REQUIRE(DisassembleArm(0xE0821143) == "add r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0821103) == "add r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0821123) == "add r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0821163) == "add r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0821003) == "add r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0821453) == "add r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0821413) == "add r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0821433) == "add r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0821473) == "add r1, r2, r3, ror r4");
|
||||
REQUIRE(DisassembleArm(0xE0821063) == "add r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE2953004) == "adds r3, r5, #4");
|
||||
REQUIRE(DisassembleArm(0xE0921143) == "adds r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0921103) == "adds r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0921123) == "adds r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0921163) == "adds r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0921003) == "adds r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0921063) == "adds r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE0921453) == "adds r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0921413) == "adds r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0921433) == "adds r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0921473) == "adds r1, r2, r3, ror r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE2021004) == "and r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0021143) == "and r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0021103) == "and r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0021123) == "and r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0021163) == "and r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0021003) == "and r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0021453) == "and r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0021413) == "and r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0021433) == "and r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0021473) == "and r1, r2, r3, ror r4");
|
||||
REQUIRE(DisassembleArm(0xE0021063) == "and r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE2121004) == "ands r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0121143) == "ands r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0121103) == "ands r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0121123) == "ands r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0121163) == "ands r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0121003) == "ands r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0121063) == "ands r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE0121453) == "ands r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0121413) == "ands r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0121433) == "ands r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0121473) == "ands r1, r2, r3, ror r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE3C21004) == "bic r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE1C21143) == "bic r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1C21103) == "bic r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1C21123) == "bic r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1C21163) == "bic r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1C21003) == "bic r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE1C21453) == "bic r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE1C21413) == "bic r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE1C21433) == "bic r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE1C21473) == "bic r1, r2, r3, ror r4");
|
||||
REQUIRE(DisassembleArm(0xE1C21063) == "bic r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE3D21004) == "bics r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE1D21143) == "bics r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1D21103) == "bics r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1D21123) == "bics r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1D21163) == "bics r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1D21003) == "bics r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE1D21063) == "bics r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE1D21453) == "bics r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE1D21413) == "bics r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE1D21433) == "bics r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE1D21473) == "bics r1, r2, r3, ror r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE3710004) == "cmn r1, #4");
|
||||
REQUIRE(DisassembleArm(0xE1710142) == "cmn r1, r2, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1710102) == "cmn r1, r2, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1710122) == "cmn r1, r2, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1710162) == "cmn r1, r2, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1710002) == "cmn r1, r2");
|
||||
REQUIRE(DisassembleArm(0xE1710062) == "cmn r1, r2, rrx");
|
||||
REQUIRE(DisassembleArm(0xE1710352) == "cmn r1, r2, asr r3");
|
||||
REQUIRE(DisassembleArm(0xE1710312) == "cmn r1, r2, lsl r3");
|
||||
REQUIRE(DisassembleArm(0xE1710332) == "cmn r1, r2, lsr r3");
|
||||
REQUIRE(DisassembleArm(0xE1710372) == "cmn r1, r2, ror r3");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE3510004) == "cmp r1, #4");
|
||||
REQUIRE(DisassembleArm(0xE1510142) == "cmp r1, r2, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1510102) == "cmp r1, r2, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1510122) == "cmp r1, r2, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1510162) == "cmp r1, r2, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1510002) == "cmp r1, r2");
|
||||
REQUIRE(DisassembleArm(0xE1510062) == "cmp r1, r2, rrx");
|
||||
REQUIRE(DisassembleArm(0xE1510352) == "cmp r1, r2, asr r3");
|
||||
REQUIRE(DisassembleArm(0xE1510312) == "cmp r1, r2, lsl r3");
|
||||
REQUIRE(DisassembleArm(0xE1510332) == "cmp r1, r2, lsr r3");
|
||||
REQUIRE(DisassembleArm(0xE1510372) == "cmp r1, r2, ror r3");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE2221004) == "eor r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0221243) == "eor r1, r2, r3, asr #4");
|
||||
REQUIRE(DisassembleArm(0xE0221203) == "eor r1, r2, r3, lsl #4");
|
||||
REQUIRE(DisassembleArm(0xE0221223) == "eor r1, r2, r3, lsr #4");
|
||||
REQUIRE(DisassembleArm(0xE0221263) == "eor r1, r2, r3, ror #4");
|
||||
REQUIRE(DisassembleArm(0xE0221003) == "eor r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0221453) == "eor r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0221413) == "eor r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0221433) == "eor r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0221473) == "eor r1, r2, r3, ror r4");
|
||||
REQUIRE(DisassembleArm(0xE0221063) == "eor r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE2321004) == "eors r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0321243) == "eors r1, r2, r3, asr #4");
|
||||
REQUIRE(DisassembleArm(0xE0321203) == "eors r1, r2, r3, lsl #4");
|
||||
REQUIRE(DisassembleArm(0xE0321223) == "eors r1, r2, r3, lsr #4");
|
||||
REQUIRE(DisassembleArm(0xE0321263) == "eors r1, r2, r3, ror #4");
|
||||
REQUIRE(DisassembleArm(0xE0321003) == "eors r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0321453) == "eors r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0321413) == "eors r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0321433) == "eors r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0321473) == "eors r1, r2, r3, ror r4");
|
||||
REQUIRE(DisassembleArm(0xE0321063) == "eors r1, r2, r3, rrx");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE3A010FF) == "mov r1, #255");
|
||||
REQUIRE(DisassembleArm(0xE1A01142) == "mov r1, r2, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1A01102) == "mov r1, r2, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1A01122) == "mov r1, r2, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1A01162) == "mov r1, r2, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1A01062) == "mov r1, r2, rrx");
|
||||
REQUIRE(DisassembleArm(0xE1A0E00F) == "mov lr, pc");
|
||||
REQUIRE(DisassembleArm(0xE3B010FF) == "movs r1, #255");
|
||||
REQUIRE(DisassembleArm(0xE1B0E00F) == "movs lr, pc");
|
||||
REQUIRE(DisassembleArm(0xE1B01142) == "movs r1, r2, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1B01102) == "movs r1, r2, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1B01122) == "movs r1, r2, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1B01162) == "movs r1, r2, ror #2");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE3E01004) == "mvn r1, #4");
|
||||
REQUIRE(DisassembleArm(0xE1E01142) == "mvn r1, r2, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1E01102) == "mvn r1, r2, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1E01122) == "mvn r1, r2, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1E01162) == "mvn r1, r2, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1E01062) == "mvn r1, r2, rrx");
|
||||
REQUIRE(DisassembleArm(0xE1E01002) == "mvn r1, r2");
|
||||
REQUIRE(DisassembleArm(0xE1E01352) == "mvn r1, r2, asr r3");
|
||||
REQUIRE(DisassembleArm(0xE1E01312) == "mvn r1, r2, lsl r3");
|
||||
REQUIRE(DisassembleArm(0xE1E01332) == "mvn r1, r2, lsr r3");
|
||||
REQUIRE(DisassembleArm(0xE1E01372) == "mvn r1, r2, ror r3");
|
||||
REQUIRE(DisassembleArm(0xE3F01004) == "mvns r1, #4");
|
||||
REQUIRE(DisassembleArm(0xE1F01142) == "mvns r1, r2, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1F01102) == "mvns r1, r2, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1F01122) == "mvns r1, r2, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1F01162) == "mvns r1, r2, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1F01062) == "mvns r1, r2, rrx");
|
||||
REQUIRE(DisassembleArm(0xE1F01002) == "mvns r1, r2");
|
||||
REQUIRE(DisassembleArm(0xE1F01352) == "mvns r1, r2, asr r3");
|
||||
REQUIRE(DisassembleArm(0xE1F01312) == "mvns r1, r2, lsl r3");
|
||||
REQUIRE(DisassembleArm(0xE1F01332) == "mvns r1, r2, lsr r3");
|
||||
REQUIRE(DisassembleArm(0xE1F01372) == "mvns r1, r2, ror r3");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE3821004) == "orr r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE1821143) == "orr r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1821103) == "orr r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1821123) == "orr r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1821163) == "orr r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1821063) == "orr r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE1821003) == "orr r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE1821453) == "orr r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE1821413) == "orr r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE1821433) == "orr r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE1821473) == "orr r1, r2, r3, ror r4");
|
||||
REQUIRE(DisassembleArm(0xE3921004) == "orrs r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE1921143) == "orrs r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1921103) == "orrs r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1921123) == "orrs r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1921163) == "orrs r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1921063) == "orrs r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE1921003) == "orrs r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE1921453) == "orrs r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE1921413) == "orrs r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE1921433) == "orrs r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE1921473) == "orrs r1, r2, r3, ror r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE2621004) == "rsb r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0621143) == "rsb r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0621103) == "rsb r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0621123) == "rsb r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0621163) == "rsb r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0621063) == "rsb r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE0621003) == "rsb r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0621453) == "rsb r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0621413) == "rsb r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0621433) == "rsb r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0621473) == "rsb r1, r2, r3, ror r4");
|
||||
REQUIRE(DisassembleArm(0xE2721004) == "rsbs r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0721143) == "rsbs r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0721103) == "rsbs r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0721123) == "rsbs r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0721163) == "rsbs r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0721063) == "rsbs r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE0721003) == "rsbs r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0721453) == "rsbs r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0721413) == "rsbs r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0721433) == "rsbs r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0721473) == "rsbs r1, r2, r3, ror r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE2E21004) == "rsc r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0E21143) == "rsc r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0E21103) == "rsc r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0E21123) == "rsc r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0E21163) == "rsc r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0E21063) == "rsc r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE0E21003) == "rsc r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0E21453) == "rsc r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0E21413) == "rsc r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0E21433) == "rsc r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0E21473) == "rsc r1, r2, r3, ror r4");
|
||||
REQUIRE(DisassembleArm(0xE2F21004) == "rscs r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0F21143) == "rscs r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0F21103) == "rscs r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0F21123) == "rscs r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0F21163) == "rscs r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0F21063) == "rscs r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE0F21003) == "rscs r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0F21453) == "rscs r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0F21413) == "rscs r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0F21433) == "rscs r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0F21473) == "rscs r1, r2, r3, ror r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE2C21004) == "sbc r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0C21143) == "sbc r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0C21103) == "sbc r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0C21123) == "sbc r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0C21163) == "sbc r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0C21063) == "sbc r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE0C21003) == "sbc r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0C21453) == "sbc r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0C21413) == "sbc r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0C21433) == "sbc r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0C21473) == "sbc r1, r2, r3, ror r4");
|
||||
REQUIRE(DisassembleArm(0xE2D21004) == "sbcs r1, r2, #4");
|
||||
REQUIRE(DisassembleArm(0xE0D21143) == "sbcs r1, r2, r3, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE0D21103) == "sbcs r1, r2, r3, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE0D21123) == "sbcs r1, r2, r3, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE0D21163) == "sbcs r1, r2, r3, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE0D21063) == "sbcs r1, r2, r3, rrx");
|
||||
REQUIRE(DisassembleArm(0xE0D21003) == "sbcs r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0D21453) == "sbcs r1, r2, r3, asr r4");
|
||||
REQUIRE(DisassembleArm(0xE0D21413) == "sbcs r1, r2, r3, lsl r4");
|
||||
REQUIRE(DisassembleArm(0xE0D21433) == "sbcs r1, r2, r3, lsr r4");
|
||||
REQUIRE(DisassembleArm(0xE0D21473) == "sbcs r1, r2, r3, ror r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE3310004) == "teq r1, #4");
|
||||
REQUIRE(DisassembleArm(0xE1310142) == "teq r1, r2, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1310102) == "teq r1, r2, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1310122) == "teq r1, r2, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1310162) == "teq r1, r2, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1310002) == "teq r1, r2");
|
||||
REQUIRE(DisassembleArm(0xE1310062) == "teq r1, r2, rrx");
|
||||
REQUIRE(DisassembleArm(0xE1310352) == "teq r1, r2, asr r3");
|
||||
REQUIRE(DisassembleArm(0xE1310312) == "teq r1, r2, lsl r3");
|
||||
REQUIRE(DisassembleArm(0xE1310332) == "teq r1, r2, lsr r3");
|
||||
REQUIRE(DisassembleArm(0xE1310372) == "teq r1, r2, ror r3");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE3110004) == "tst r1, #4");
|
||||
REQUIRE(DisassembleArm(0xE1110142) == "tst r1, r2, asr #2");
|
||||
REQUIRE(DisassembleArm(0xE1110102) == "tst r1, r2, lsl #2");
|
||||
REQUIRE(DisassembleArm(0xE1110122) == "tst r1, r2, lsr #2");
|
||||
REQUIRE(DisassembleArm(0xE1110162) == "tst r1, r2, ror #2");
|
||||
REQUIRE(DisassembleArm(0xE1110002) == "tst r1, r2");
|
||||
REQUIRE(DisassembleArm(0xE1110062) == "tst r1, r2, rrx");
|
||||
REQUIRE(DisassembleArm(0xE1110352) == "tst r1, r2, asr r3");
|
||||
REQUIRE(DisassembleArm(0xE1110312) == "tst r1, r2, lsl r3");
|
||||
REQUIRE(DisassembleArm(0xE1110332) == "tst r1, r2, lsr r3");
|
||||
REQUIRE(DisassembleArm(0xE1110372) == "tst r1, r2, ror r3");
|
||||
}
|
||||
|
||||
TEST_CASE("Disassemble half-word multiply and multiply accumulate instructions", "[arm][disassembler]") {
|
||||
REQUIRE(DisassembleArm(0xE1003281) == "smlabb r0, r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE10032C1) == "smlabt r0, r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE10032A1) == "smlatb r0, r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE10032E1) == "smlatt r0, r1, r2, r3");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE1203281) == "smlawb r0, r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE12032C1) == "smlawt r0, r1, r2, r3");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE12002A1) == "smulwb r0, r1, r2");
|
||||
REQUIRE(DisassembleArm(0xE12002E1) == "smulwt r0, r1, r2");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE1410382) == "smlalbb r0, r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE14103C2) == "smlalbt r0, r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE14103A2) == "smlaltb r0, r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE14103E2) == "smlaltt r0, r1, r2, r3");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE1600281) == "smulbb r0, r1, r2");
|
||||
REQUIRE(DisassembleArm(0xE16002C1) == "smulbt r0, r1, r2");
|
||||
REQUIRE(DisassembleArm(0xE16002A1) == "smultb r0, r1, r2");
|
||||
REQUIRE(DisassembleArm(0xE16002E1) == "smultt r0, r1, r2");
|
||||
}
|
||||
|
||||
TEST_CASE("Disassemble multiply and multiply accumulate instructions", "[arm][disassembler]") {
|
||||
REQUIRE(DisassembleArm(0xE0214392) == "mla r1, r2, r3, r4");
|
||||
REQUIRE(DisassembleArm(0xE0314392) == "mlas r1, r2, r3, r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE0010392) == "mul r1, r2, r3");
|
||||
REQUIRE(DisassembleArm(0xE0110392) == "muls r1, r2, r3");
|
||||
|
||||
// TODO: MLS should be here whenever it's supported.
|
||||
|
||||
REQUIRE(DisassembleArm(0xE0E21493) == "smlal r1, r2, r3, r4");
|
||||
REQUIRE(DisassembleArm(0xE0F21493) == "smlals r1, r2, r3, r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE0C21493) == "smull r1, r2, r3, r4");
|
||||
REQUIRE(DisassembleArm(0xE0D21493) == "smulls r1, r2, r3, r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE0421493) == "umaal r1, r2, r3, r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE0A21493) == "umlal r1, r2, r3, r4");
|
||||
REQUIRE(DisassembleArm(0xE0B21493) == "umlals r1, r2, r3, r4");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE0821493) == "umull r1, r2, r3, r4");
|
||||
REQUIRE(DisassembleArm(0xE0921493) == "umulls r1, r2, r3, r4");
|
||||
}
|
||||
|
||||
TEST_CASE("Disassemble synchronization primitive instructions", "[arm][disassembler]") {
|
||||
REQUIRE(DisassembleArm(0xE1921F9F) == "ldrex r1, [r2]");
|
||||
REQUIRE(DisassembleArm(0xE1D21F9F) == "ldrexb r1, [r2]");
|
||||
REQUIRE(DisassembleArm(0xE1B31F9F) == "ldrexd r1, r2, [r3]");
|
||||
REQUIRE(DisassembleArm(0xE1F21F9F) == "ldrexh r1, [r2]");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE1831F92) == "strex r1, r2, [r3]");
|
||||
REQUIRE(DisassembleArm(0xE1C31F92) == "strexb r1, r2, [r3]");
|
||||
REQUIRE(DisassembleArm(0xE1A41F92) == "strexd r1, r2, r3, [r4]");
|
||||
REQUIRE(DisassembleArm(0xE1E31F92) == "strexh r1, r2, [r3]");
|
||||
|
||||
REQUIRE(DisassembleArm(0xE1031092) == "swp r1, r2, [r3]");
|
||||
REQUIRE(DisassembleArm(0xE1431092) == "swpb r1, r2, [r3]");
|
||||
}
|
||||
|
||||
TEST_CASE("Disassemble load / store multiple instructions", "[arm][disassembler]") {
|
||||
REQUIRE(DisassembleArm(0xE92D500F) == "stmdb sp!, {r0, r1, r2, r3, r12, lr}");
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
include(TargetArchitectureSpecificSources)
|
||||
|
||||
@@ -9,6 +9,7 @@ add_executable(dynarmic_tests
|
||||
fp/unpacked_tests.cpp
|
||||
rand_int.h
|
||||
# A32
|
||||
A32/test_arm_disassembler.cpp
|
||||
A32/test_arm_instructions.cpp
|
||||
A32/test_coprocessor.cpp
|
||||
A32/test_svc.cpp
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "dynarmic/frontend/A64/translate/impl/impl.h"
|
||||
#include "dynarmic/interface/A32/a32.h"
|
||||
#include "dynarmic/interface/A32/config.h"
|
||||
#include "dynarmic/interface/A32/disassembler.h"
|
||||
#include "dynarmic/ir/basic_block.h"
|
||||
#include "dynarmic/ir/opt_passes.h"
|
||||
|
||||
|
||||
@@ -241,16 +241,6 @@ void QtConfig::ReadPathValues() {
|
||||
}
|
||||
EndArray();
|
||||
|
||||
Settings::values.blocked_domains.clear();
|
||||
const int blocked_domains_size = BeginArray(std::string("blocked_domains"));
|
||||
for (int i = 0; i < blocked_domains_size; ++i) {
|
||||
SetArrayIndex(i);
|
||||
if (auto s = ReadStringSetting(std::string("domain")); !s.empty()) {
|
||||
Settings::values.blocked_domains.push_back(s);
|
||||
}
|
||||
}
|
||||
EndArray();
|
||||
|
||||
ReadCategory(Settings::Category::Paths);
|
||||
|
||||
EndGroup();
|
||||
@@ -473,13 +463,6 @@ void QtConfig::SavePathValues() {
|
||||
}
|
||||
EndArray();
|
||||
|
||||
BeginArray(std::string("blocked_domains"));
|
||||
for (int i = 0; i < static_cast<int>(Settings::values.blocked_domains.size()); ++i) {
|
||||
SetArrayIndex(i);
|
||||
WriteStringSetting(std::string("domain"), Settings::values.blocked_domains[i]);
|
||||
}
|
||||
EndArray();
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
|
||||
@@ -83,6 +83,12 @@ int result_index = 0;
|
||||
uint result_vector_max_index;
|
||||
bool result_limit_reached = false;
|
||||
|
||||
// avoid intermediate result_vector storage during color decode phase
|
||||
bool write_color_values = false;
|
||||
uint color_values_direct[32];
|
||||
uint color_out_index = 0;
|
||||
uint color_num_values = 0;
|
||||
|
||||
// EncodingData helpers
|
||||
uint Encoding(EncodingData val) {
|
||||
return bitfieldExtract(val.data, 0, 8);
|
||||
@@ -114,9 +120,110 @@ EncodingData CreateEncodingData(uint encoding, uint num_bits, uint bit_val, uint
|
||||
return EncodingData(((encoding) << 0u) | ((num_bits) << 8u) |
|
||||
((bit_val) << 16u) | ((quint_trit_val) << 24u));
|
||||
}
|
||||
uint ReplicateBitTo9(uint bit);
|
||||
uint FastReplicateTo8(uint value, uint num_bits);
|
||||
|
||||
void EmitColorValue(EncodingData val) {
|
||||
// write directly to color_values_direct[]
|
||||
const uint encoding = Encoding(val);
|
||||
const uint bitlen = NumBits(val);
|
||||
const uint bitval = BitValue(val);
|
||||
|
||||
if (encoding == JUST_BITS) {
|
||||
color_values_direct[++color_out_index] = FastReplicateTo8(bitval, bitlen);
|
||||
return;
|
||||
}
|
||||
|
||||
uint A = ReplicateBitTo9((bitval & 1));
|
||||
uint B = 0, C = 0, D = QuintTritValue(val);
|
||||
|
||||
if (encoding == TRIT) {
|
||||
switch (bitlen) {
|
||||
case 1:
|
||||
C = 204;
|
||||
break;
|
||||
case 2: {
|
||||
C = 93;
|
||||
const uint b = (bitval >> 1) & 1;
|
||||
B = (b << 8) | (b << 4) | (b << 2) | (b << 1);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
C = 44;
|
||||
const uint cb = (bitval >> 1) & 3;
|
||||
B = (cb << 7) | (cb << 2) | cb;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
C = 22;
|
||||
const uint dcb = (bitval >> 1) & 7;
|
||||
B = (dcb << 6) | dcb;
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
C = 11;
|
||||
const uint edcb = (bitval >> 1) & 0xF;
|
||||
B = (edcb << 5) | (edcb >> 2);
|
||||
break;
|
||||
}
|
||||
case 6: {
|
||||
C = 5;
|
||||
const uint fedcb = (bitval >> 1) & 0x1F;
|
||||
B = (fedcb << 4) | (fedcb >> 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else { // QUINT
|
||||
switch (bitlen) {
|
||||
case 1:
|
||||
C = 113;
|
||||
break;
|
||||
case 2: {
|
||||
C = 54;
|
||||
const uint b = (bitval >> 1) & 1;
|
||||
B = (b << 8) | (b << 3) | (b << 2);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
C = 26;
|
||||
const uint cb = (bitval >> 1) & 3;
|
||||
B = (cb << 7) | (cb << 1) | (cb >> 1);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
C = 13;
|
||||
const uint dcb = (bitval >> 1) & 7;
|
||||
B = (dcb << 6) | (dcb >> 1);
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
C = 6;
|
||||
const uint edcb = (bitval >> 1) & 0xF;
|
||||
B = (edcb << 5) | (edcb >> 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint T = (D * C) + B;
|
||||
T ^= A;
|
||||
T = (A & 0x80) | (T >> 2);
|
||||
color_values_direct[++color_out_index] = T;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ResultEmplaceBack(EncodingData val) {
|
||||
if (write_color_values) {
|
||||
if (color_out_index >= color_num_values) {
|
||||
// avoid decoding more than needed by this phase
|
||||
result_limit_reached = true;
|
||||
return;
|
||||
}
|
||||
EmitColorValue(val);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result_index >= result_vector_max_index) {
|
||||
// Alert callers to avoid decoding more than needed by this phase
|
||||
result_limit_reached = true;
|
||||
@@ -457,7 +564,7 @@ void DecodeIntegerSequence(uint max_range, uint num_values) {
|
||||
}
|
||||
}
|
||||
|
||||
void DecodeColorValues(uvec4 modes, uint num_partitions, uint color_data_bits, out uint color_values[32]) {
|
||||
void DecodeColorValues(uvec4 modes, uint num_partitions, uint color_data_bits) {
|
||||
uint num_values = 0;
|
||||
for (uint i = 0; i < num_partitions; i++) {
|
||||
num_values += ((modes[i] >> 2) + 1) << 1;
|
||||
@@ -471,104 +578,21 @@ void DecodeColorValues(uvec4 modes, uint num_partitions, uint color_data_bits, o
|
||||
break;
|
||||
}
|
||||
}
|
||||
DecodeIntegerSequence(range - 1, num_values);
|
||||
uint out_index = 0;
|
||||
for (int itr = 0; itr < result_index; ++itr) {
|
||||
if (out_index >= num_values) {
|
||||
break;
|
||||
}
|
||||
const EncodingData val = GetEncodingFromVector(itr);
|
||||
const uint encoding = Encoding(val);
|
||||
const uint bitlen = NumBits(val);
|
||||
const uint bitval = BitValue(val);
|
||||
uint A = 0, B = 0, C = 0, D = 0;
|
||||
A = ReplicateBitTo9((bitval & 1));
|
||||
switch (encoding) {
|
||||
case JUST_BITS:
|
||||
color_values[++out_index] = FastReplicateTo8(bitval, bitlen);
|
||||
break;
|
||||
case TRIT: {
|
||||
D = QuintTritValue(val);
|
||||
switch (bitlen) {
|
||||
case 1:
|
||||
C = 204;
|
||||
break;
|
||||
case 2: {
|
||||
C = 93;
|
||||
const uint b = (bitval >> 1) & 1;
|
||||
B = (b << 8) | (b << 4) | (b << 2) | (b << 1);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
C = 44;
|
||||
const uint cb = (bitval >> 1) & 3;
|
||||
B = (cb << 7) | (cb << 2) | cb;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
C = 22;
|
||||
const uint dcb = (bitval >> 1) & 7;
|
||||
B = (dcb << 6) | dcb;
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
C = 11;
|
||||
const uint edcb = (bitval >> 1) & 0xF;
|
||||
B = (edcb << 5) | (edcb >> 2);
|
||||
break;
|
||||
}
|
||||
case 6: {
|
||||
C = 5;
|
||||
const uint fedcb = (bitval >> 1) & 0x1F;
|
||||
B = (fedcb << 4) | (fedcb >> 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QUINT: {
|
||||
D = QuintTritValue(val);
|
||||
switch (bitlen) {
|
||||
case 1:
|
||||
C = 113;
|
||||
break;
|
||||
case 2: {
|
||||
C = 54;
|
||||
const uint b = (bitval >> 1) & 1;
|
||||
B = (b << 8) | (b << 3) | (b << 2);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
C = 26;
|
||||
const uint cb = (bitval >> 1) & 3;
|
||||
B = (cb << 7) | (cb << 1) | (cb >> 1);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
C = 13;
|
||||
const uint dcb = (bitval >> 1) & 7;
|
||||
B = (dcb << 6) | (dcb >> 1);
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
C = 6;
|
||||
const uint edcb = (bitval >> 1) & 0xF;
|
||||
B = (edcb << 5) | (edcb >> 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (encoding != JUST_BITS) {
|
||||
uint T = (D * C) + B;
|
||||
T ^= A;
|
||||
T = (A & 0x80) | (T >> 2);
|
||||
color_values[++out_index] = T;
|
||||
}
|
||||
// Decode directly into color_values_direct[]
|
||||
write_color_values = true;
|
||||
color_out_index = 0;
|
||||
color_num_values = num_values;
|
||||
for (uint i = 0; i < 32; ++i) {
|
||||
color_values_direct[i] = 0;
|
||||
}
|
||||
|
||||
DecodeIntegerSequence(range - 1, num_values);
|
||||
|
||||
write_color_values = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ivec2 BitTransferSigned(int a, int b) {
|
||||
ivec2 transferred;
|
||||
transferred.y = b >> 1;
|
||||
@@ -1069,13 +1093,12 @@ void DecompressBlock(ivec3 coord) {
|
||||
uvec4 endpoints0[4];
|
||||
uvec4 endpoints1[4];
|
||||
{
|
||||
// This decode phase should at most push 32 elements into the vector
|
||||
result_vector_max_index = 32;
|
||||
uint color_values[32];
|
||||
// Decode directly into color_values_direct[] (no intermediate result_vector storage)
|
||||
result_limit_reached = false;
|
||||
uint colvals_index = 0;
|
||||
DecodeColorValues(color_endpoint_mode, num_partitions, color_data_bits, color_values);
|
||||
DecodeColorValues(color_endpoint_mode, num_partitions, color_data_bits);
|
||||
for (uint i = 0; i < num_partitions; i++) {
|
||||
ComputeEndpoints(endpoints0[i], endpoints1[i], color_endpoint_mode[i], color_values,
|
||||
ComputeEndpoints(endpoints0[i], endpoints1[i], color_endpoint_mode[i], color_values_direct,
|
||||
colvals_index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,7 +436,23 @@ void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayo
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// Blit image barrier - transition can happen at any stage
|
||||
// Using specific stages for better parallelism, but keeping broad since this is a general utility
|
||||
const VkPipelineStageFlags src_stages_blit =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
const VkPipelineStageFlags dst_stages_blit =
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_blit, dst_stages_blit,
|
||||
0, barrier);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
@@ -68,7 +68,16 @@ void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayo
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// Present path - use specific stages for better parallelism on tile-based GPUs
|
||||
const VkPipelineStageFlags src_stages =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
const VkPipelineStageFlags dst_stages =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages, dst_stages,
|
||||
0, barrier);
|
||||
}
|
||||
|
||||
@@ -151,11 +160,12 @@ void DownloadColorImage(vk::CommandBuffer& cmdbuf, VkImage image, VkBuffer buffe
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
// Host will read the downloaded data
|
||||
static constexpr VkMemoryBarrier memory_write_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_HOST_READ_BIT,
|
||||
};
|
||||
const VkBufferImageCopy copy{
|
||||
.bufferOffset = 0,
|
||||
@@ -170,10 +180,20 @@ void DownloadColorImage(vk::CommandBuffer& cmdbuf, VkImage image, VkBuffer buffe
|
||||
.imageOffset{.x = 0, .y = 0, .z = 0},
|
||||
.imageExtent{extent},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||
const VkPipelineStageFlags src_stages_copy =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_copy, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||
read_barrier);
|
||||
cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, copy);
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0,
|
||||
const VkPipelineStageFlags dst_stages_copy =
|
||||
VK_PIPELINE_STAGE_HOST_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_copy, 0,
|
||||
memory_write_barrier, nullptr, image_write_barrier);
|
||||
}
|
||||
|
||||
|
||||
@@ -436,13 +436,27 @@ void BufferCacheRuntime::CopyBuffer(VkBuffer dst_buffer, VkBuffer src_buffer,
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([src_buffer, dst_buffer, vk_copies, barrier](vk::CommandBuffer cmdbuf) {
|
||||
if (barrier) {
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// Buffer writes can come from vertex input, shaders, or compute
|
||||
const VkPipelineStageFlags src_stages =
|
||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, READ_BARRIER);
|
||||
}
|
||||
cmdbuf.CopyBuffer(src_buffer, dst_buffer, VideoCommon::FixSmallVectorADL(vk_copies));
|
||||
if (barrier) {
|
||||
// Buffer reads can go to vertex input, shaders, or compute
|
||||
const VkPipelineStageFlags dst_stages =
|
||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, WRITE_BARRIER);
|
||||
dst_stages, 0, WRITE_BARRIER);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -456,21 +470,36 @@ void BufferCacheRuntime::PreCopyBarrier() {
|
||||
};
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
const VkPipelineStageFlags src_stages =
|
||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, READ_BARRIER);
|
||||
});
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::PostCopyBarrier() {
|
||||
// Specific access flags for buffer destinations: vertex input, uniforms, storage, index
|
||||
static constexpr VkMemoryBarrier WRITE_BARRIER{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDEX_READ_BIT |
|
||||
VK_ACCESS_UNIFORM_READ_BIT | VK_ACCESS_SHADER_READ_BIT |
|
||||
VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
|
||||
};
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
const VkPipelineStageFlags dst_stages =
|
||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages,
|
||||
0, WRITE_BARRIER);
|
||||
});
|
||||
}
|
||||
@@ -494,10 +523,24 @@ void BufferCacheRuntime::ClearBuffer(VkBuffer dest_buffer, u32 offset, size_t si
|
||||
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([dest_buffer, offset, size, value](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
// Buffer writes can come from vertex input, shaders, or compute
|
||||
const VkPipelineStageFlags src_stages_clear =
|
||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_clear, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, READ_BARRIER);
|
||||
cmdbuf.FillBuffer(dest_buffer, offset, size, value);
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// Buffer reads can go to vertex input, shaders, or compute
|
||||
const VkPipelineStageFlags dst_stages_clear =
|
||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_clear,
|
||||
0, WRITE_BARRIER);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -446,13 +446,26 @@ void ConditionalRenderingResolvePass::Resolve(VkBuffer dst_buffer, VkBuffer src_
|
||||
const VkDescriptorSet set = descriptor_allocator.Commit();
|
||||
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
|
||||
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// Memory writes can come from graphics or compute stages
|
||||
const VkPipelineStageFlags src_stages_compute =
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_compute,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, read_barrier);
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
|
||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
|
||||
cmdbuf.Dispatch(1, 1, 1);
|
||||
// Conditional rendering result used by draw indirect or conditional rendering
|
||||
const VkPipelineStageFlags dst_stages_cond =
|
||||
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT |
|
||||
VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT |
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, write_barrier);
|
||||
dst_stages_cond, 0, write_barrier);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -520,14 +533,29 @@ void QueriesPrefixScanPass::Run(VkBuffer accumulation_buffer, VkBuffer dst_buffe
|
||||
const VkDescriptorSet set = descriptor_allocator.Commit();
|
||||
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
|
||||
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// Memory writes can come from graphics or compute stages
|
||||
const VkPipelineStageFlags src_stages_scan =
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_scan,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, read_barrier);
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
|
||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
|
||||
cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, uniforms);
|
||||
cmdbuf.Dispatch(1, 1, 1);
|
||||
// Query prefix scan results used by draw indirect, conditional rendering, or shaders
|
||||
const VkPipelineStageFlags dst_stages_scan =
|
||||
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT |
|
||||
VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT |
|
||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, write_barrier);
|
||||
dst_stages_scan, 0, write_barrier);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -579,8 +607,15 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(is_initialized ? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
|
||||
: VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
// If initialized, memory writes can come from graphics or compute stages
|
||||
const VkPipelineStageFlags src_stages_astc = is_initialized ?
|
||||
(VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT) :
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_astc,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, image_barrier);
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, vk_pipeline);
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
@@ -441,7 +441,13 @@ void PresentManager::CopyToSwapchainImpl(Frame* frame) {
|
||||
},
|
||||
};
|
||||
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, {},
|
||||
// Previous operations that might have written to the frame image
|
||||
const VkPipelineStageFlags src_stages_present =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_present, VK_PIPELINE_STAGE_TRANSFER_BIT, {},
|
||||
{}, {}, pre_barriers);
|
||||
|
||||
if (blit_supported) {
|
||||
|
||||
@@ -809,12 +809,19 @@ public:
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_SHADER_READ_BIT,
|
||||
};
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([](vk::CommandBuffer cmdbuf) {
|
||||
// After transfer, results may be read by host or used in subsequent operations
|
||||
const VkPipelineStageFlags dst_stages_query =
|
||||
VK_PIPELINE_STAGE_HOST_BIT |
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, WRITE_BARRIER);
|
||||
dst_stages_query, 0, WRITE_BARRIER);
|
||||
});
|
||||
|
||||
std::scoped_lock lk(flush_guard);
|
||||
@@ -942,7 +949,7 @@ private:
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
|
||||
};
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([dst_buffer = current_bank->GetBuffer(),
|
||||
@@ -1475,22 +1482,40 @@ void QueryCacheRuntime::Barriers(bool is_prebarrier) {
|
||||
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
};
|
||||
// Query results may be read by host or used in shaders/indirect commands
|
||||
static constexpr VkMemoryBarrier WRITE_BARRIER{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_SHADER_READ_BIT |
|
||||
VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
|
||||
};
|
||||
impl->scheduler.RequestOutsideRenderPassOperationContext();
|
||||
if (is_prebarrier) {
|
||||
impl->scheduler.Record([](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// Query data can be written by graphics or compute stages
|
||||
const VkPipelineStageFlags src_stages_query =
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_query,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, READ_BARRIER);
|
||||
});
|
||||
} else {
|
||||
impl->scheduler.Record([](vk::CommandBuffer cmdbuf) {
|
||||
// Query results may be read by host or used in shaders/indirect commands
|
||||
const VkPipelineStageFlags dst_stages_query =
|
||||
VK_PIPELINE_STAGE_HOST_BIT |
|
||||
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT |
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, WRITE_BARRIER);
|
||||
dst_stages_query, 0, WRITE_BARRIER);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,14 +586,23 @@ void RasterizerVulkan::DispatchCompute() {
|
||||
}
|
||||
const std::array<u32, 3> dim{qmd.grid_dim_x, qmd.grid_dim_y, qmd.grid_dim_z};
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
// Compute shader reads from storage buffers, uniforms, and images
|
||||
static constexpr VkMemoryBarrier READ_BARRIER{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
|
||||
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_UNIFORM_READ_BIT,
|
||||
};
|
||||
scheduler.Record([](vk::CommandBuffer cmdbuf) { cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
0, READ_BARRIER); });
|
||||
scheduler.Record([](vk::CommandBuffer cmdbuf) {
|
||||
// Memory writes can come from graphics or compute stages
|
||||
const VkPipelineStageFlags src_stages =
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
0, READ_BARRIER);
|
||||
});
|
||||
scheduler.Record([dim](vk::CommandBuffer cmdbuf) { cmdbuf.Dispatch(dim[0], dim[1], dim[2]); });
|
||||
|
||||
// Log compute dispatch
|
||||
|
||||
@@ -44,13 +44,19 @@ using VideoCore::Surface::SurfaceType;
|
||||
}
|
||||
|
||||
VkAttachmentDescription AttachmentDescription(const Device& device, PixelFormat format,
|
||||
VkSampleCountFlagBits samples) {
|
||||
VkSampleCountFlagBits samples,
|
||||
bool is_depth_stencil) {
|
||||
using MaxwellToVK::SurfaceFormat;
|
||||
|
||||
const SurfaceType surface_type = GetSurfaceType(format);
|
||||
const bool has_stencil = surface_type == SurfaceType::DepthStencil ||
|
||||
surface_type == SurfaceType::Stencil;
|
||||
|
||||
// Use optimal layouts for attachments - this allows drivers to optimize tiling and access patterns
|
||||
const VkImageLayout attachment_layout = is_depth_stencil
|
||||
? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
|
||||
: VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
return {
|
||||
.flags = {},
|
||||
.format = SurfaceFormat(device, FormatType::Optimal, true, format).format,
|
||||
@@ -61,8 +67,8 @@ using VideoCore::Surface::SurfaceType;
|
||||
: VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||
.stencilStoreOp = has_stencil ? VK_ATTACHMENT_STORE_OP_STORE
|
||||
: VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.finalLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.initialLayout = attachment_layout,
|
||||
.finalLayout = attachment_layout,
|
||||
};
|
||||
}
|
||||
} // Anonymous namespace
|
||||
@@ -84,10 +90,10 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
|
||||
const bool is_valid{format != PixelFormat::Invalid};
|
||||
references[index] = VkAttachmentReference{
|
||||
.attachment = is_valid ? num_colors : VK_ATTACHMENT_UNUSED,
|
||||
.layout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
if (is_valid) {
|
||||
descriptions.push_back(AttachmentDescription(*device, format, key.samples));
|
||||
descriptions.push_back(AttachmentDescription(*device, format, key.samples, false));
|
||||
num_attachments = static_cast<u32>(index + 1);
|
||||
++num_colors;
|
||||
}
|
||||
@@ -97,9 +103,9 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
|
||||
if (key.depth_format != PixelFormat::Invalid) {
|
||||
depth_reference = VkAttachmentReference{
|
||||
.attachment = num_colors,
|
||||
.layout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
descriptions.push_back(AttachmentDescription(*device, key.depth_format, key.samples));
|
||||
descriptions.push_back(AttachmentDescription(*device, key.depth_format, key.samples, true));
|
||||
}
|
||||
const VkSubpassDescription subpass{
|
||||
.flags = 0,
|
||||
|
||||
@@ -264,14 +264,26 @@ u64 Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_se
|
||||
const u64 signal_value = master_semaphore->NextTick();
|
||||
RecordWithUploadBuffer([signal_semaphore, wait_semaphore, signal_value,
|
||||
this](vk::CommandBuffer cmdbuf, vk::CommandBuffer upload_cmdbuf) {
|
||||
// Specific access flags for upload destinations: vertex input, uniforms, storage, index, textures
|
||||
static constexpr VkMemoryBarrier WRITE_BARRIER{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDEX_READ_BIT |
|
||||
VK_ACCESS_UNIFORM_READ_BIT | VK_ACCESS_SHADER_READ_BIT |
|
||||
VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
|
||||
};
|
||||
// Specify exact stages that need the transfer results instead of ALL_COMMANDS_BIT
|
||||
upload_cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, WRITE_BARRIER);
|
||||
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
0, WRITE_BARRIER);
|
||||
upload_cmdbuf.End();
|
||||
cmdbuf.End();
|
||||
|
||||
@@ -332,11 +344,11 @@ void Scheduler::EndRenderPass()
|
||||
|
||||
query_cache->CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, false);
|
||||
query_cache->NotifySegment(false);
|
||||
|
||||
Record([num_images = num_renderpass_images,
|
||||
images = renderpass_images,
|
||||
ranges = renderpass_image_ranges](vk::CommandBuffer cmdbuf) {
|
||||
std::array<VkImageMemoryBarrier, 9> barriers;
|
||||
VkPipelineStageFlags src_stages = 0;
|
||||
for (size_t i = 0; i < num_images; ++i) {
|
||||
const VkImageSubresourceRange& range = ranges[i];
|
||||
const bool is_color = (range.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0;
|
||||
@@ -344,38 +356,76 @@ void Scheduler::EndRenderPass()
|
||||
& (VK_IMAGE_ASPECT_DEPTH_BIT
|
||||
| VK_IMAGE_ASPECT_STENCIL_BIT)) !=0;
|
||||
|
||||
// Determine optimal destination layout based on image usage
|
||||
// After render pass, images may be used as shader resources or as attachments again
|
||||
// Use optimal layouts to allow driver optimizations
|
||||
VkAccessFlags src_access = 0;
|
||||
VkAccessFlags dst_access = 0;
|
||||
VkPipelineStageFlags this_stage = 0;
|
||||
VkImageLayout new_layout;
|
||||
|
||||
if (is_color)
|
||||
src_access |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
else if (is_depth_stencil)
|
||||
src_access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
else
|
||||
src_access |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
|
||||
if (is_color) {
|
||||
// Color attachments can be read as textures or used as attachments again
|
||||
src_access = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
this_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
new_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
dst_access = VK_ACCESS_SHADER_READ_BIT
|
||||
| VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
|
||||
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
} else if (is_depth_stencil) {
|
||||
// Depth attachments can be read as textures or used as attachments again
|
||||
src_access = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
this_stage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
|
||||
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
new_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
dst_access = VK_ACCESS_SHADER_READ_BIT
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
} else {
|
||||
// Fallback to GENERAL for unknown usage
|
||||
src_access = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
this_stage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
|
||||
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
|
||||
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
new_layout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
dst_access = VK_ACCESS_SHADER_READ_BIT
|
||||
| VK_ACCESS_SHADER_WRITE_BIT
|
||||
| VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
|
||||
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
}
|
||||
src_stages |= this_stage;
|
||||
barriers[i] = VkImageMemoryBarrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = src_access,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT
|
||||
| VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
|
||||
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.dstAccessMask = dst_access,
|
||||
.oldLayout = is_color ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
||||
: (is_depth_stencil ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
|
||||
: VK_IMAGE_LAYOUT_GENERAL),
|
||||
.newLayout = new_layout,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = images[i],
|
||||
.subresourceRange = range,
|
||||
};
|
||||
}
|
||||
|
||||
cmdbuf.EndRenderPass();
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
|
||||
// Use specific pipeline stages instead of ALL_COMMANDS_BIT for better parallelism
|
||||
// The destination stages depend on how the images will be used next
|
||||
const VkPipelineStageFlags dst_stages =
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
|
||||
cmdbuf.PipelineBarrier(src_stages,
|
||||
dst_stages,
|
||||
0,
|
||||
nullptr,
|
||||
nullptr,
|
||||
|
||||
@@ -810,7 +810,8 @@ void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = 0,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT | VK_ACCESS_MEMORY_READ_BIT,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
@@ -822,7 +823,8 @@ void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT | VK_ACCESS_MEMORY_READ_BIT,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
@@ -831,11 +833,26 @@ void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const
|
||||
.subresourceRange = subresource_range,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
// Use specific pipeline stages for better parallelism
|
||||
const VkPipelineStageFlags src_stages =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, nullptr, nullptr, read_barriers);
|
||||
cmdbuf.BlitImage(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, regions, vk_filter);
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// After transfer, images may be used in graphics, compute, or as attachments
|
||||
const VkPipelineStageFlags dst_stages =
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages,
|
||||
0, nullptr, nullptr, write_barriers);
|
||||
});
|
||||
}
|
||||
@@ -1023,11 +1040,12 @@ void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src,
|
||||
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
};
|
||||
// After reinterpret, buffers used as transfer source, uniforms, or storage
|
||||
static constexpr VkMemoryBarrier WRITE_BARRIER{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT,
|
||||
};
|
||||
const std::array pre_barriers{
|
||||
VkImageMemoryBarrier{
|
||||
@@ -1094,18 +1112,39 @@ void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src,
|
||||
.subresourceRange = dst_range.SubresourceRange(dst_aspect_mask),
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
const VkPipelineStageFlags src_stages_transfer =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_transfer, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, {}, {}, pre_barriers);
|
||||
|
||||
cmdbuf.CopyImageToBuffer(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, copy_buffer,
|
||||
vk_in_copies);
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
const VkPipelineStageFlags dst_stages_transfer =
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_transfer,
|
||||
0, WRITE_BARRIER, nullptr, middle_in_barrier);
|
||||
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
cmdbuf.PipelineBarrier(src_stages_transfer, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, READ_BARRIER, {}, middle_out_barrier);
|
||||
cmdbuf.CopyBufferToImage(copy_buffer, dst_image, VK_IMAGE_LAYOUT_GENERAL, vk_out_copies);
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// After reinterpret copy, image may be used in shaders or as attachment
|
||||
const VkPipelineStageFlags dst_stages_post =
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_post,
|
||||
0, {}, {}, post_barriers);
|
||||
});
|
||||
}
|
||||
@@ -1232,7 +1271,12 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
const VkPipelineStageFlags src_stages_resolve =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_resolve, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, nullptr, nullptr, read_barriers);
|
||||
if (is_resolve) {
|
||||
cmdbuf.ResolveImage(src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image,
|
||||
@@ -1245,7 +1289,14 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
|
||||
src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
MakeImageBlit(dst_region, src_region, dst_layers, src_layers), vk_filter);
|
||||
}
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// After blit/resolve, image may be used in shaders or as attachment
|
||||
const VkPipelineStageFlags dst_stages_blit =
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_blit,
|
||||
0, write_barrier);
|
||||
});
|
||||
}
|
||||
@@ -1823,7 +1874,14 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
const VkPipelineStageFlags src_stages_download =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_download, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, read_barrier);
|
||||
|
||||
for (size_t index = 0; index < buffers.size(); index++) {
|
||||
@@ -1831,17 +1889,20 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
|
||||
vk_copies[index]);
|
||||
}
|
||||
|
||||
// Host will read the downloaded data
|
||||
const VkMemoryBarrier memory_write_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_HOST_READ_BIT,
|
||||
};
|
||||
// Image will be used for shaders or as attachment
|
||||
const VkImageMemoryBarrier image_write_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = 0,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
@@ -1855,7 +1916,13 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
const VkPipelineStageFlags dst_stages_download =
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_download,
|
||||
0, memory_write_barrier, nullptr, image_write_barrier);
|
||||
});
|
||||
return;
|
||||
@@ -1890,7 +1957,15 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
// Image writes can come from graphics or compute stages
|
||||
const VkPipelineStageFlags src_stages_img =
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(src_stages_img, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, read_barrier);
|
||||
|
||||
for (size_t index = 0; index < buffers.size(); index++) {
|
||||
@@ -1922,7 +1997,14 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
// After download, image may be used in shaders or as attachment
|
||||
const VkPipelineStageFlags dst_stages_img =
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stages_img,
|
||||
0, memory_write_barrier, nullptr, image_write_barrier);
|
||||
});
|
||||
}
|
||||
@@ -2484,7 +2566,9 @@ void TextureCacheRuntime::TransitionImageLayout(Image& image) {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_NONE,
|
||||
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
@@ -2500,8 +2584,16 @@ void TextureCacheRuntime::TransitionImageLayout(Image& image) {
|
||||
};
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([barrier](vk::CommandBuffer cmdbuf) {
|
||||
// After layout transition, image may be used in shaders or as attachment
|
||||
const VkPipelineStageFlags dst_stages_layout =
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, barrier);
|
||||
dst_stages_layout, 0, barrier);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "core/internal_network/network_interface.h"
|
||||
#include "ui_configure_network.h"
|
||||
#include "yuzu/configuration/configure_network.h"
|
||||
#include "yuzu/util/limitable_input_dialog.h"
|
||||
|
||||
ConfigureNetwork::ConfigureNetwork(const Core::System& system_, QWidget* parent)
|
||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureNetwork>()), system{system_} {
|
||||
@@ -21,26 +20,6 @@ ConfigureNetwork::ConfigureNetwork(const Core::System& system_, QWidget* parent)
|
||||
ui->network_interface->addItem(QString::fromStdString(iface.name));
|
||||
}
|
||||
|
||||
ui->blocked_domains_list->clear();
|
||||
for (const auto& s : Settings::values.blocked_domains) {
|
||||
ui->blocked_domains_list->addItem(QString::fromStdString(s));
|
||||
}
|
||||
|
||||
connect(ui->add_blocked_domains_button, &QPushButton::pressed, this, [this, parent] {
|
||||
if (const QString s = LimitableInputDialog::GetText(parent, tr("Add blocked domain"), tr("Input DNS match rule"), 0, 64); !s.isEmpty()) {
|
||||
ui->blocked_domains_list->addItem(s);
|
||||
}
|
||||
});
|
||||
connect(ui->remove_blocked_domains_button, &QPushButton::pressed, this, [this] {
|
||||
auto selected = ui->blocked_domains_list->selectedItems();
|
||||
if (!selected.isEmpty()) {
|
||||
qDeleteAll(ui->blocked_domains_list->selectedItems());
|
||||
}
|
||||
});
|
||||
connect(ui->blocked_domains_list, &QListWidget::itemSelectionChanged, this, [this] {
|
||||
ui->remove_blocked_domains_button->setEnabled(!ui->blocked_domains_list->selectedItems().isEmpty());
|
||||
});
|
||||
|
||||
this->SetConfiguration();
|
||||
}
|
||||
|
||||
@@ -49,24 +28,8 @@ ConfigureNetwork::~ConfigureNetwork() = default;
|
||||
void ConfigureNetwork::ApplyConfiguration() {
|
||||
Settings::values.network_interface = ui->network_interface->currentText().toStdString();
|
||||
Settings::values.airplane_mode = ui->airplane_mode->isChecked();
|
||||
|
||||
std::vector<std::string> new_dirs;
|
||||
new_dirs.reserve(ui->blocked_domains_list->count());
|
||||
for (int i = 0; i < ui->blocked_domains_list->count(); ++i) {
|
||||
new_dirs.push_back(ui->blocked_domains_list->item(i)->text().toStdString());
|
||||
}
|
||||
if (new_dirs != Settings::values.blocked_domains) {
|
||||
Settings::values.blocked_domains = std::move(new_dirs);
|
||||
}
|
||||
}
|
||||
|
||||
// void ConfigureGeneral::UpdateExternalContentList() {
|
||||
// ui->blocked_domains_list->clear();
|
||||
// for (const auto& dir : Settings::values.blocked_domains) {
|
||||
// ui->blocked_domains_list->addItem(QString::fromStdString(dir));
|
||||
// }
|
||||
// }
|
||||
|
||||
void ConfigureNetwork::changeEvent(QEvent* event) {
|
||||
if (event->type() == QEvent::LanguageChange) {
|
||||
RetranslateUI();
|
||||
|
||||
@@ -45,66 +45,6 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_blocked_domains">
|
||||
<property name="title">
|
||||
<string>Blocked Domains Content</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_blocked_domains">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_blocked_domains_desc">
|
||||
<property name="text">
|
||||
<string>Add domains to filter out on DNS resolutions</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="blocked_domains_list">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_blocked_domains_buttons">
|
||||
<item>
|
||||
<widget class="QPushButton" name="add_blocked_domains_button">
|
||||
<property name="text">
|
||||
<string>Add Domain</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="remove_blocked_domains_button">
|
||||
<property name="text">
|
||||
<string>Remove Selected</string>
|
||||
</property>
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_blocked_domains">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
|
||||
Reference in New Issue
Block a user