mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-21 15:28:19 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3e54fb4c33 | |||
| f8689fb451 | |||
| 00d745e4e5 | |||
| f0685cc0c9 | |||
| d69bd86183 | |||
| c172abfb53 | |||
| d33dc16820 | |||
| 8cdaf19a83 | |||
| f088f5bd45 | |||
| cbeea5b954 | |||
| 1590e7c061 |
Vendored
+2
-2
@@ -208,8 +208,8 @@
|
||||
},
|
||||
"ffmpeg": {
|
||||
"repo": "FFmpeg/FFmpeg",
|
||||
"sha": "e717604a29",
|
||||
"hash": "403390865aa3c0a947679ec2f24076383c72d308dda66918e64526ddc585e652dfda66b724fc04b1625a28c89d428b13d50ae2c19c7a7f16bd5e50904266f302",
|
||||
"sha": "c7b5f1537d",
|
||||
"hash": "ed177621176b3961bdcaa339187d3a7688c1c8b060b79c4bb0257cbc67ad7021ae5d5adca5303b45625abbbe3d9aafdd87ce777b8690ac295290d744c875489a",
|
||||
"bundled": true
|
||||
},
|
||||
"ffmpeg-ci": {
|
||||
|
||||
Vendored
+1
-1
@@ -244,7 +244,7 @@ else()
|
||||
set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES})
|
||||
|
||||
# BSD make or Solaris make don't support ffmpeg make-j8
|
||||
if (DEFINED SYSTEM_THREADS AND (PLATFORM_LINUX OR ANDROID OR APPLE OR WIN32 OR PLATFORM_FREEBSD))
|
||||
if (PLATFORM_LINUX OR ANDROID OR APPLE OR WIN32 OR PLATFORM_FREEBSD)
|
||||
set(FFmpeg_MAKE_ARGS -j${SYSTEM_THREADS})
|
||||
else()
|
||||
set(FFmpeg_MAKE_ARGS "")
|
||||
|
||||
@@ -13,13 +13,13 @@
|
||||
namespace Common {
|
||||
|
||||
template <typename BaseAddr>
|
||||
MultiLevelPageTable<BaseAddr>::MultiLevelPageTable(std::size_t address_space_bits_,
|
||||
std::size_t first_level_bits_,
|
||||
std::size_t page_bits_)
|
||||
: address_space_bits{address_space_bits_},
|
||||
first_level_bits{first_level_bits_}, page_bits{page_bits_} {
|
||||
MultiLevelPageTable<BaseAddr>::MultiLevelPageTable(std::size_t address_space_bits_, std::size_t first_level_bits_, std::size_t page_bits_)
|
||||
: address_space_bits{address_space_bits_}
|
||||
, first_level_bits{first_level_bits_}
|
||||
, page_bits{page_bits_}
|
||||
{
|
||||
if (page_bits == 0) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
first_level_shift = address_space_bits - first_level_bits;
|
||||
first_level_chunk_size = (1ULL << (first_level_shift - page_bits)) * sizeof(BaseAddr);
|
||||
@@ -30,12 +30,9 @@ MultiLevelPageTable<BaseAddr>::MultiLevelPageTable(std::size_t address_space_bit
|
||||
void* base{VirtualAlloc(nullptr, alloc_size, MEM_RESERVE, PAGE_READWRITE)};
|
||||
#else
|
||||
void* base{mmap(nullptr, alloc_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)};
|
||||
|
||||
if (base == MAP_FAILED) {
|
||||
if (base == MAP_FAILED)
|
||||
base = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
ASSERT(base);
|
||||
base_ptr = reinterpret_cast<BaseAddr*>(base);
|
||||
}
|
||||
@@ -56,29 +53,21 @@ template <typename BaseAddr>
|
||||
void MultiLevelPageTable<BaseAddr>::ReserveRange(u64 start, std::size_t size) {
|
||||
const u64 new_start = start >> first_level_shift;
|
||||
const u64 new_end = (start + size) >> first_level_shift;
|
||||
for (u64 i = new_start; i <= new_end; i++) {
|
||||
if (!first_level_map[i]) {
|
||||
for (u64 i = new_start; i <= new_end; i++)
|
||||
if (!first_level_map[i])
|
||||
AllocateLevel(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BaseAddr>
|
||||
void MultiLevelPageTable<BaseAddr>::AllocateLevel(u64 level) {
|
||||
void* ptr = reinterpret_cast<char *>(base_ptr) + level * first_level_chunk_size;
|
||||
void MultiLevelPageTable<BaseAddr>::AllocateLevel(u64 index) {
|
||||
void* ptr = reinterpret_cast<char *>(base_ptr) + index * first_level_chunk_size;
|
||||
#ifdef _WIN32
|
||||
void* base{VirtualAlloc(ptr, first_level_chunk_size, MEM_COMMIT, PAGE_READWRITE)};
|
||||
#else
|
||||
void* base{mmap(ptr, first_level_chunk_size, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)};
|
||||
|
||||
if (base == MAP_FAILED) {
|
||||
base = nullptr;
|
||||
}
|
||||
#endif
|
||||
void* base = VirtualAlloc(ptr, first_level_chunk_size, MEM_COMMIT, PAGE_READWRITE);
|
||||
ASSERT(base);
|
||||
|
||||
first_level_map[level] = base;
|
||||
#else
|
||||
void* base = ptr;
|
||||
#endif
|
||||
first_level_map[index] = base;
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -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 2019 yuzu Emulator Project
|
||||
@@ -142,10 +142,8 @@ struct PageTable {
|
||||
VirtualBuffer<PageEntryData> entries;
|
||||
static_assert(sizeof(PageEntryData) == 32);
|
||||
|
||||
std::size_t current_address_space_width_in_bits{};
|
||||
|
||||
u8* fastmem_arena{};
|
||||
|
||||
std::size_t current_address_space_width_in_bits{};
|
||||
std::size_t page_size{};
|
||||
};
|
||||
|
||||
|
||||
+18
-17
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -21,7 +24,9 @@ public:
|
||||
// "with the current allocator");
|
||||
|
||||
constexpr VirtualBuffer() = default;
|
||||
explicit VirtualBuffer(std::size_t count) : alloc_size{count * sizeof(T)} {
|
||||
explicit VirtualBuffer(std::size_t count) noexcept
|
||||
: alloc_size{count * sizeof(T)}
|
||||
{
|
||||
base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
|
||||
}
|
||||
|
||||
@@ -33,8 +38,8 @@ public:
|
||||
VirtualBuffer& operator=(const VirtualBuffer&) = delete;
|
||||
|
||||
VirtualBuffer(VirtualBuffer&& other) noexcept
|
||||
: alloc_size{std::exchange(other.alloc_size, 0)}, base_ptr{std::exchange(other.base_ptr),
|
||||
nullptr} {}
|
||||
: alloc_size{std::exchange(other.alloc_size, 0)}, base_ptr{std::exchange(other.base_ptr), nullptr}
|
||||
{}
|
||||
|
||||
VirtualBuffer& operator=(VirtualBuffer&& other) noexcept {
|
||||
alloc_size = std::exchange(other.alloc_size, 0);
|
||||
@@ -42,35 +47,31 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
void resize(std::size_t count) {
|
||||
const auto new_size = count * sizeof(T);
|
||||
if (new_size == alloc_size) {
|
||||
return;
|
||||
void resize(std::size_t count) noexcept {
|
||||
if (auto const new_size = count * sizeof(T); new_size != alloc_size) {
|
||||
FreeMemoryPages(base_ptr, alloc_size);
|
||||
alloc_size = new_size;
|
||||
base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
|
||||
}
|
||||
|
||||
FreeMemoryPages(base_ptr, alloc_size);
|
||||
|
||||
alloc_size = new_size;
|
||||
base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const T& operator[](std::size_t index) const {
|
||||
[[nodiscard]] constexpr const T& operator[](std::size_t index) const noexcept {
|
||||
return base_ptr[index];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T& operator[](std::size_t index) {
|
||||
[[nodiscard]] constexpr T& operator[](std::size_t index) noexcept {
|
||||
return base_ptr[index];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T* data() {
|
||||
[[nodiscard]] constexpr T* data() noexcept {
|
||||
return base_ptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const T* data() const {
|
||||
[[nodiscard]] constexpr const T* data() const noexcept {
|
||||
return base_ptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t size() const {
|
||||
[[nodiscard]] constexpr std::size_t size() const noexcept {
|
||||
return alloc_size / sizeof(T);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 2022 yuzu Emulator Project
|
||||
@@ -283,7 +283,7 @@ std::string_view GDBStubA32::GetTargetXML() const {
|
||||
<reg name="r11" bitsize="32" type="uint32"/>
|
||||
<reg name="r12" bitsize="32" type="uint32"/>
|
||||
<reg name="sp" bitsize="32" type="data_ptr"/>
|
||||
<reg name="lr" bitsize="32" type="code_ptr"/>
|
||||
<reg name="lr" bitsize="32"/>
|
||||
<reg name="pc" bitsize="32" type="code_ptr"/>
|
||||
<!-- The CPSR is register 25, rather than register 16, because
|
||||
the FPA registers historically were placed between the PC
|
||||
|
||||
@@ -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
|
||||
@@ -191,8 +191,7 @@ Result KPageTableBase::InitializeForKernel(bool is_64_bit, KVirtualAddress start
|
||||
m_cached_physical_heap_region = nullptr;
|
||||
|
||||
// Initialize our implementation.
|
||||
m_impl = std::make_unique<Common::PageTable>();
|
||||
m_impl->Resize(m_address_space_width, PageBits);
|
||||
m_impl.Resize(m_address_space_width, PageBits);
|
||||
|
||||
// Set the tracking memory.
|
||||
m_memory = std::addressof(memory);
|
||||
@@ -202,13 +201,7 @@ Result KPageTableBase::InitializeForKernel(bool is_64_bit, KVirtualAddress start
|
||||
m_memory_block_slab_manager));
|
||||
}
|
||||
|
||||
Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool enable_aslr,
|
||||
bool enable_das_merge, bool from_back,
|
||||
KMemoryManager::Pool pool, KProcessAddress code_address,
|
||||
size_t code_size, KSystemResource* system_resource,
|
||||
KResourceLimit* resource_limit,
|
||||
Core::Memory::Memory& memory,
|
||||
KProcessAddress aslr_space_start) {
|
||||
Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource* system_resource, KResourceLimit* resource_limit, Core::Memory::Memory& memory, KProcessAddress aslr_space_start) {
|
||||
// Calculate region extents.
|
||||
const size_t as_width = GetAddressSpaceWidth(as_type);
|
||||
const KProcessAddress start = 0;
|
||||
@@ -319,14 +312,10 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool
|
||||
// Determine random placements for each region.
|
||||
size_t alias_rnd = 0, heap_rnd = 0, stack_rnd = 0, kmap_rnd = 0;
|
||||
if (enable_aslr) {
|
||||
alias_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
|
||||
RegionAlignment;
|
||||
heap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
|
||||
RegionAlignment;
|
||||
stack_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
|
||||
RegionAlignment;
|
||||
kmap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
|
||||
RegionAlignment;
|
||||
alias_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * RegionAlignment;
|
||||
heap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * RegionAlignment;
|
||||
stack_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * RegionAlignment;
|
||||
kmap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * RegionAlignment;
|
||||
}
|
||||
|
||||
// Setup heap and alias regions.
|
||||
@@ -445,15 +434,13 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool
|
||||
ASSERT(heap_last < kmap_start || kmap_last < heap_start);
|
||||
|
||||
// Initialize our implementation.
|
||||
m_impl = std::make_unique<Common::PageTable>();
|
||||
m_impl->Resize(m_address_space_width, PageBits);
|
||||
m_impl.Resize(m_address_space_width, PageBits);
|
||||
|
||||
// Set the tracking memory.
|
||||
m_memory = std::addressof(memory);
|
||||
|
||||
// Initialize our memory block manager.
|
||||
R_RETURN(m_memory_block_manager.Initialize(m_address_space_start, m_address_space_end,
|
||||
m_memory_block_slab_manager));
|
||||
R_RETURN(m_memory_block_manager.Initialize(m_address_space_start, m_address_space_end, m_memory_block_slab_manager));
|
||||
}
|
||||
|
||||
Result KPageTableBase::FinalizeProcess() {
|
||||
@@ -476,7 +463,7 @@ void KPageTableBase::Finalize() {
|
||||
this->FinalizeProcess();
|
||||
|
||||
auto BlockCallback = [&](KProcessAddress addr, u64 size) {
|
||||
if (m_impl->fastmem_arena) {
|
||||
if (m_impl.fastmem_arena) {
|
||||
m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false);
|
||||
}
|
||||
|
||||
@@ -514,9 +501,6 @@ void KPageTableBase::Finalize() {
|
||||
m_resource_limit->Release(Svc::LimitableResource::PhysicalMemoryMax,
|
||||
m_mapped_ipc_server_memory);
|
||||
}
|
||||
|
||||
// Close the backing page table, as the destructor is not called for guest objects.
|
||||
m_impl.reset();
|
||||
}
|
||||
|
||||
KProcessAddress KPageTableBase::GetRegionAddress(Svc::MemoryState state) const {
|
||||
@@ -2349,7 +2333,7 @@ Result KPageTableBase::QueryPhysicalAddress(Svc::lp64::PhysicalMemoryInfo* out,
|
||||
TraversalContext context;
|
||||
TraversalEntry next_entry;
|
||||
bool traverse_valid =
|
||||
m_impl->BeginTraversal(std::addressof(next_entry), std::addressof(context), virt_addr);
|
||||
m_impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), virt_addr);
|
||||
R_UNLESS(traverse_valid, ResultInvalidCurrentMemory);
|
||||
|
||||
// Set tracking variables.
|
||||
@@ -2360,7 +2344,7 @@ Result KPageTableBase::QueryPhysicalAddress(Svc::lp64::PhysicalMemoryInfo* out,
|
||||
while (true) {
|
||||
// Continue the traversal.
|
||||
traverse_valid =
|
||||
m_impl->ContinueTraversal(std::addressof(next_entry), std::addressof(context));
|
||||
m_impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context));
|
||||
if (!traverse_valid) {
|
||||
break;
|
||||
}
|
||||
@@ -5730,14 +5714,14 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
||||
this->MakePageGroup(pages_to_close, virt_addr, num_pages);
|
||||
|
||||
// Unmap.
|
||||
m_memory->UnmapRegion(*m_impl, virt_addr, num_pages * PageSize, separate_heap);
|
||||
m_memory->UnmapRegion(m_impl, virt_addr, num_pages * PageSize, separate_heap);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
case OperationType::Map: {
|
||||
ASSERT(virt_addr != 0);
|
||||
ASSERT(Common::IsAligned(GetInteger(virt_addr), PageSize));
|
||||
m_memory->MapMemoryRegion(*m_impl, virt_addr, num_pages * PageSize, phys_addr,
|
||||
m_memory->MapMemoryRegion(m_impl, virt_addr, num_pages * PageSize, phys_addr,
|
||||
ConvertToMemoryPermission(properties.perm), false);
|
||||
|
||||
// Open references to pages, if we should.
|
||||
@@ -5754,7 +5738,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
||||
case OperationType::ChangePermissions:
|
||||
case OperationType::ChangePermissionsAndRefresh:
|
||||
case OperationType::ChangePermissionsAndRefreshAndFlush: {
|
||||
m_memory->ProtectRegion(*m_impl, virt_addr, num_pages * PageSize,
|
||||
m_memory->ProtectRegion(m_impl, virt_addr, num_pages * PageSize,
|
||||
ConvertToMemoryPermission(properties.perm));
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -5788,7 +5772,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
||||
const size_t size{node.GetNumPages() * PageSize};
|
||||
|
||||
// Map the pages.
|
||||
m_memory->MapMemoryRegion(*m_impl, virt_addr, size, node.GetAddress(),
|
||||
m_memory->MapMemoryRegion(m_impl, virt_addr, size, node.GetAddress(),
|
||||
ConvertToMemoryPermission(properties.perm), separate_heap);
|
||||
|
||||
virt_addr += size;
|
||||
|
||||
@@ -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
|
||||
@@ -215,7 +215,7 @@ private:
|
||||
mutable KLightLock m_general_lock;
|
||||
mutable KLightLock m_map_physical_memory_lock;
|
||||
KLightLock m_device_map_lock;
|
||||
std::unique_ptr<Common::PageTable> m_impl{};
|
||||
Common::PageTable m_impl{};
|
||||
Core::Memory::Memory* m_memory{};
|
||||
KMemoryBlockManager m_memory_block_manager{};
|
||||
u32 m_allocate_option{};
|
||||
@@ -300,26 +300,11 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
Core::Memory::Memory& GetMemory() {
|
||||
return *m_memory;
|
||||
}
|
||||
|
||||
Core::Memory::Memory& GetMemory() const {
|
||||
return *m_memory;
|
||||
}
|
||||
|
||||
Common::PageTable& GetImpl() {
|
||||
return *m_impl;
|
||||
}
|
||||
|
||||
Common::PageTable& GetImpl() const {
|
||||
return *m_impl;
|
||||
}
|
||||
|
||||
size_t GetNumGuardPages() const {
|
||||
return this->IsKernel() ? 1 : 4;
|
||||
}
|
||||
|
||||
[[nodiscard]] Core::Memory::Memory& GetMemory() noexcept { return *m_memory; }
|
||||
[[nodiscard]] Core::Memory::Memory const& GetMemory() const noexcept { return *m_memory; }
|
||||
[[nodiscard]] Common::PageTable& GetImpl() noexcept { return m_impl; }
|
||||
[[nodiscard]] Common::PageTable const& GetImpl() const noexcept { return m_impl; }
|
||||
[[nodiscard]] size_t GetNumGuardPages() const noexcept { return this->IsKernel() ? 1 : 4; }
|
||||
protected:
|
||||
// NOTE: These three functions (Operate, Operate, FinalizeUpdate) are virtual functions
|
||||
// in Nintendo's kernel. We devirtualize them, since KPageTable is the only derived
|
||||
|
||||
@@ -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
|
||||
@@ -33,21 +33,10 @@ public:
|
||||
m_page_table.Finalize();
|
||||
}
|
||||
|
||||
Core::Memory::Memory& GetMemory() {
|
||||
return m_page_table.GetMemory();
|
||||
}
|
||||
|
||||
Core::Memory::Memory& GetMemory() const {
|
||||
return m_page_table.GetMemory();
|
||||
}
|
||||
|
||||
Common::PageTable& GetImpl() {
|
||||
return m_page_table.GetImpl();
|
||||
}
|
||||
|
||||
Common::PageTable& GetImpl() const {
|
||||
return m_page_table.GetImpl();
|
||||
}
|
||||
[[nodiscard]] Core::Memory::Memory& GetMemory() noexcept { return m_page_table.GetMemory(); }
|
||||
[[nodiscard]] Core::Memory::Memory const& GetMemory() const noexcept { return m_page_table.GetMemory(); }
|
||||
[[nodiscard]] Common::PageTable& GetImpl() noexcept { return m_page_table.GetImpl(); }
|
||||
[[nodiscard]] Common::PageTable const& GetImpl() const noexcept { return m_page_table.GetImpl(); }
|
||||
|
||||
size_t GetNumGuardPages() const {
|
||||
return m_page_table.GetNumGuardPages();
|
||||
|
||||
@@ -50,6 +50,14 @@ void PhysicalCore::RunThread(Kernel::KThread* thread) {
|
||||
};
|
||||
|
||||
const auto ExitContext = [&]() {
|
||||
// Save the JIT context back to the thread so the debugger can
|
||||
// read the current register state. Debug halt paths (step,
|
||||
// breakpoint, watchpoint) return from RunThread without going
|
||||
// through the scheduler's Unload/SaveContext.
|
||||
if (system.DebuggerEnabled()) {
|
||||
interface->GetContext(thread->GetContext());
|
||||
}
|
||||
|
||||
// Unlock the thread.
|
||||
interface->UnlockThread(thread);
|
||||
|
||||
@@ -97,11 +105,16 @@ void PhysicalCore::RunThread(Kernel::KThread* thread) {
|
||||
}
|
||||
|
||||
// Determine why we stopped.
|
||||
const bool supervisor_call = True(hr & Core::HaltReason::SupervisorCall);
|
||||
const bool prefetch_abort = True(hr & Core::HaltReason::PrefetchAbort);
|
||||
const bool breakpoint = True(hr & Core::HaltReason::InstructionBreakpoint);
|
||||
const bool data_abort = True(hr & Core::HaltReason::DataAbort);
|
||||
const bool interrupt = True(hr & Core::HaltReason::BreakLoop);
|
||||
// If a step completed successfully, skip other halt reason handlers —
|
||||
// the step takes priority (e.g. step may also set InstructionBreakpoint
|
||||
// if the next instruction happens to be a breakpoint).
|
||||
const bool step_completed = True(hr & Core::HaltReason::StepThread)
|
||||
&& thread->GetStepState() == StepState::StepPerformed;
|
||||
const bool supervisor_call = !step_completed && True(hr & Core::HaltReason::SupervisorCall);
|
||||
const bool prefetch_abort = !step_completed && True(hr & Core::HaltReason::PrefetchAbort);
|
||||
const bool breakpoint = !step_completed && True(hr & Core::HaltReason::InstructionBreakpoint);
|
||||
const bool data_abort = !step_completed && True(hr & Core::HaltReason::DataAbort);
|
||||
const bool interrupt = !step_completed && True(hr & Core::HaltReason::BreakLoop);
|
||||
|
||||
// Since scheduling may occur here, we cannot use any cached
|
||||
// state after returning from calls we make.
|
||||
@@ -111,6 +124,11 @@ void PhysicalCore::RunThread(Kernel::KThread* thread) {
|
||||
if (breakpoint || prefetch_abort) {
|
||||
if (breakpoint) {
|
||||
interface->RewindBreakpointInstruction();
|
||||
// RewindBreakpointInstruction sets the JIT state to the
|
||||
// saved breakpoint context. Update the thread context to
|
||||
// match, since ExitContext already saved the post-execution
|
||||
// state.
|
||||
interface->GetContext(thread->GetContext());
|
||||
}
|
||||
if (system.DebuggerEnabled()) {
|
||||
system.GetDebugger().NotifyThreadStopped(thread);
|
||||
|
||||
@@ -228,9 +228,8 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
|
||||
code_size += patch_ctx.GetTotalPatchSize();
|
||||
|
||||
// TODO: this is bad form of ASLR, it sucks
|
||||
size_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
|
||||
? ::Settings::values.rng_seed.GetValue()
|
||||
: Common::Random::Random64(0)) * 0x734287f27) & 0xfff000;
|
||||
std::uintptr_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
|
||||
? ::Settings::values.rng_seed.GetValue() : Common::Random::Random64(0)) << 12) & 0xfff000;
|
||||
|
||||
// Setup the process code layout
|
||||
if (process.LoadFromMetadata(metadata, code_size, fastmem_base, aslr_offset, is_hbl).IsError()) {
|
||||
|
||||
@@ -89,9 +89,8 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
|
||||
codeset.DataSegment().size += kip->GetBSSSize();
|
||||
|
||||
// TODO: this is bad form of ASLR, it sucks
|
||||
size_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
|
||||
? ::Settings::values.rng_seed.GetValue()
|
||||
: Common::Random::Random64(0)) * 0x734287f27) & 0xfff000;
|
||||
std::uintptr_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
|
||||
? ::Settings::values.rng_seed.GetValue() : Common::Random::Random64(0)) << 12) & 0xfff000;
|
||||
|
||||
// Setup the process code layout
|
||||
if (process.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), codeset.memory.size(), 0, aslr_offset, false).IsError()) {
|
||||
|
||||
@@ -242,9 +242,8 @@ static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
|
||||
}();
|
||||
|
||||
// TODO: this is bad form of ASLR, it sucks
|
||||
size_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
|
||||
? ::Settings::values.rng_seed.GetValue()
|
||||
: Common::Random::Random64(0)) * 0x734287f27) & 0xfff000;
|
||||
std::uintptr_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
|
||||
? ::Settings::values.rng_seed.GetValue() : Common::Random::Random64(0)) << 12) & 0xfff000;
|
||||
|
||||
// Setup the process code layout
|
||||
if (process
|
||||
|
||||
@@ -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
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
@@ -39,7 +39,7 @@ bool TranslatorVisitor::BL(Imm<26> imm26) {
|
||||
ir.PushRSB(ir.current_location->AdvancePC(4));
|
||||
|
||||
const u64 target = ir.PC() + offset;
|
||||
ir.SetTerm(IR::Term::LinkBlock{ir.current_location->SetPC(target)});
|
||||
ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location->SetPC(target)});
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -157,11 +157,14 @@ void NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t c
|
||||
if (!controller.device->IsConnected()) {
|
||||
return;
|
||||
}
|
||||
auto* shared_memory = controller.shared_memory;
|
||||
const auto& battery_level = controller.device->GetBattery();
|
||||
shared_memory->battery_level_dual = battery_level.dual.battery_level;
|
||||
shared_memory->battery_level_left = battery_level.left.battery_level;
|
||||
shared_memory->battery_level_right = battery_level.right.battery_level;
|
||||
if (auto* shared_memory = controller.shared_memory; shared_memory) {
|
||||
const auto& battery_level = controller.device->GetBattery();
|
||||
shared_memory->battery_level_dual = battery_level.dual.battery_level;
|
||||
shared_memory->battery_level_left = battery_level.left.battery_level;
|
||||
shared_memory->battery_level_right = battery_level.right.battery_level;
|
||||
} else {
|
||||
LOG_WARNING(Service_HID, "shared_memory is null {}", controller_idx);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -180,6 +183,10 @@ void NPad::InitNewlyAddedController(u64 aruid, Core::HID::NpadIdType npad_id) {
|
||||
const auto& body_colors = controller.device->GetColors();
|
||||
const auto& battery_level = controller.device->GetBattery();
|
||||
auto* shared_memory = controller.shared_memory;
|
||||
if (!shared_memory) {
|
||||
LOG_WARNING(Service_HID, "shared_memory is null for npad_id={}", npad_id);
|
||||
return;
|
||||
}
|
||||
if (controller_type == Core::HID::NpadStyleIndex::None) {
|
||||
npad_resource.SignalStyleSetUpdateEvent(aruid, npad_id);
|
||||
return;
|
||||
@@ -801,7 +808,7 @@ Result NPad::DisconnectNpad(u64 aruid, Core::HID::NpadIdType npad_id) {
|
||||
|
||||
auto* shared_memory = controller.shared_memory;
|
||||
if (!shared_memory) {
|
||||
LOG_WARNING(Service_HID, "DisconnectNpad: shared_memory is null for npad_id={}", npad_id);
|
||||
LOG_WARNING(Service_HID, "shared_memory is null for npad_id={}", npad_id);
|
||||
return ResultSuccess;
|
||||
}
|
||||
// Don't reset shared_memory->assignment_mode this value is persistent
|
||||
@@ -1195,11 +1202,10 @@ const Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties(
|
||||
|
||||
AppletDetailedUiType NPad::GetAppletDetailedUiType(Core::HID::NpadIdType npad_id) {
|
||||
const auto aruid = applet_resource_holder.applet_resource->GetActiveAruid();
|
||||
const auto& shared_memory = GetControllerFromNpadIdType(aruid, npad_id).shared_memory;
|
||||
|
||||
const auto* shared_memory = GetControllerFromNpadIdType(aruid, npad_id).shared_memory;
|
||||
return {
|
||||
.ui_variant = 0,
|
||||
.footer = shared_memory->applet_footer_type,
|
||||
.footer = shared_memory ? shared_memory->applet_footer_type : AppletFooterUiType::None,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -30,8 +30,9 @@ struct TextureInst {
|
||||
|
||||
using TextureInstVector = boost::container::small_vector<TextureInst, 24>;
|
||||
|
||||
constexpr u32 DESCRIPTOR_SIZE = 8;
|
||||
constexpr u32 DESCRIPTOR_SIZE_SHIFT = static_cast<u32>(std::countr_zero(DESCRIPTOR_SIZE));
|
||||
// TODO: We need to implement scatter/gather CBuf stuff
|
||||
constexpr u32 DESCRIPTOR_SIZE = 1024;
|
||||
constexpr u32 DESCRIPTOR_SIZE_SHIFT = u32(std::countr_zero(u32(8)));
|
||||
|
||||
IR::Opcode IndexedInstruction(const IR::Inst& inst) {
|
||||
switch (inst.GetOpcode()) {
|
||||
@@ -362,7 +363,7 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environme
|
||||
.secondary_offset = 0,
|
||||
.secondary_shift_left = 0,
|
||||
.dynamic_offset = dynamic_offset,
|
||||
.count = 8,
|
||||
.count = DESCRIPTOR_SIZE,
|
||||
.has_secondary = false,
|
||||
};
|
||||
}
|
||||
@@ -406,15 +407,15 @@ u32 GetTextureHandle(Environment& env, const ConstBufferAddr& cbuf) {
|
||||
return lhs_raw | rhs_raw;
|
||||
}
|
||||
|
||||
[[maybe_unused]]TextureType ReadTextureType(Environment& env, const ConstBufferAddr& cbuf) {
|
||||
[[maybe_unused]]TextureType ReadTextureType(Environment& env, const ConstBufferAddr& cbuf) {
|
||||
return env.ReadTextureType(GetTextureHandle(env, cbuf));
|
||||
}
|
||||
|
||||
[[maybe_unused]]TexturePixelFormat ReadTexturePixelFormat(Environment& env, const ConstBufferAddr& cbuf) {
|
||||
[[maybe_unused]]TexturePixelFormat ReadTexturePixelFormat(Environment& env, const ConstBufferAddr& cbuf) {
|
||||
return env.ReadTexturePixelFormat(GetTextureHandle(env, cbuf));
|
||||
}
|
||||
|
||||
[[maybe_unused]]bool IsTexturePixelFormatInteger(Environment& env, const ConstBufferAddr& cbuf) {
|
||||
[[maybe_unused]]bool IsTexturePixelFormatInteger(Environment& env, const ConstBufferAddr& cbuf) {
|
||||
return env.IsTexturePixelFormatInteger(GetTextureHandle(env, cbuf));
|
||||
}
|
||||
|
||||
@@ -716,8 +717,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
|
||||
const auto insert_point{IR::Block::InstructionList::s_iterator_to(*inst)};
|
||||
IR::IREmitter ir{*texture_inst.block, insert_point};
|
||||
const IR::U32 shift{ir.Imm32(DESCRIPTOR_SIZE_SHIFT)};
|
||||
inst->SetArg(0, ir.UMin(ir.ShiftRightLogical(cbuf.dynamic_offset, shift),
|
||||
ir.Imm32(DESCRIPTOR_SIZE - 1)));
|
||||
inst->SetArg(0, ir.UMin(ir.ShiftRightLogical(cbuf.dynamic_offset, shift), ir.Imm32(DESCRIPTOR_SIZE - 1)));
|
||||
} else {
|
||||
inst->SetArg(0, IR::Value{});
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -15,53 +18,37 @@ public:
|
||||
InvalidationAccumulator() = default;
|
||||
~InvalidationAccumulator() = default;
|
||||
|
||||
void Add(GPUVAddr address, size_t size) {
|
||||
const auto reset_values = [&]() {
|
||||
if (has_collected) {
|
||||
void Add(GPUVAddr address, size_t size) noexcept {
|
||||
auto const end_address = start_address + accumulated_size;
|
||||
if (!(address >= start_address && address + size <= end_address)) {
|
||||
size = ((address + size + atomicity_size_mask) & atomicity_mask) - address;
|
||||
address = address & atomicity_mask;
|
||||
if (start_address == 0) {
|
||||
start_address = address;
|
||||
accumulated_size = size;
|
||||
// will now have collected as this point
|
||||
} else if (address != end_address) {
|
||||
buffer.emplace_back(start_address, accumulated_size);
|
||||
start_address = address;
|
||||
accumulated_size = size;
|
||||
} else {
|
||||
accumulated_size += size;
|
||||
}
|
||||
start_address = address;
|
||||
accumulated_size = size;
|
||||
last_collection = start_address + size;
|
||||
};
|
||||
if (address >= start_address && address + size <= last_collection) [[likely]] {
|
||||
return;
|
||||
}
|
||||
size = ((address + size + atomicity_size_mask) & atomicity_mask) - address;
|
||||
address = address & atomicity_mask;
|
||||
if (!has_collected) [[unlikely]] {
|
||||
reset_values();
|
||||
has_collected = true;
|
||||
return;
|
||||
}
|
||||
if (address != last_collection) [[unlikely]] {
|
||||
reset_values();
|
||||
return;
|
||||
}
|
||||
accumulated_size += size;
|
||||
last_collection += size;
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
buffer.clear();
|
||||
start_address = 0;
|
||||
last_collection = 0;
|
||||
has_collected = false;
|
||||
}
|
||||
|
||||
bool AnyAccumulated() const {
|
||||
return has_collected;
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
void Callback(Func&& func) {
|
||||
if (!has_collected) {
|
||||
return;
|
||||
}
|
||||
buffer.emplace_back(start_address, accumulated_size);
|
||||
for (auto& [address, size] : buffer) {
|
||||
func(address, size);
|
||||
template <typename F>
|
||||
[[nodiscard]] bool InvalidateAll(F&& f) noexcept {
|
||||
if (start_address > 0) {
|
||||
for (auto [address, size] : buffer)
|
||||
f(address, size);
|
||||
f(start_address, accumulated_size);
|
||||
buffer.clear();
|
||||
start_address = 0;
|
||||
accumulated_size = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -69,11 +56,9 @@ private:
|
||||
static constexpr size_t atomicity_size = 1ULL << atomicity_bits;
|
||||
static constexpr size_t atomicity_size_mask = atomicity_size - 1;
|
||||
static constexpr size_t atomicity_mask = ~atomicity_size_mask;
|
||||
GPUVAddr start_address{};
|
||||
GPUVAddr last_collection{};
|
||||
size_t accumulated_size{};
|
||||
bool has_collected{};
|
||||
std::vector<std::pair<VAddr, size_t>> buffer;
|
||||
GPUVAddr start_address = 0;
|
||||
size_t accumulated_size = 0;
|
||||
};
|
||||
|
||||
} // namespace VideoCommon
|
||||
|
||||
@@ -26,16 +26,14 @@ using Tegra::Memory::GuestMemoryFlags;
|
||||
|
||||
std::atomic<size_t> MemoryManager::unique_identifier_generator{};
|
||||
|
||||
MemoryManager::MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager& memory_,
|
||||
u64 address_space_bits_, GPUVAddr split_address_, u64 big_page_bits_,
|
||||
u64 page_bits_)
|
||||
: system{system_}, memory{memory_}, address_space_bits{address_space_bits_},
|
||||
split_address{split_address_}, page_bits{page_bits_}, big_page_bits{big_page_bits_},
|
||||
entries{}, big_entries{}, page_table{address_space_bits, address_space_bits + page_bits - 38,
|
||||
page_bits != big_page_bits ? page_bits : 0},
|
||||
kind_map{PTEKind::INVALID}, unique_identifier{unique_identifier_generator.fetch_add(
|
||||
1, std::memory_order_acq_rel)},
|
||||
accumulator{std::make_unique<VideoCommon::InvalidationAccumulator>()} {
|
||||
MemoryManager::MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager& memory_, u64 address_space_bits_, GPUVAddr split_address_, u64 big_page_bits_, u64 page_bits_)
|
||||
: system{system_}, memory{memory_}, address_space_bits{address_space_bits_}
|
||||
, split_address{split_address_}, page_bits{page_bits_}, big_page_bits{big_page_bits_}
|
||||
, entries{}, big_entries{}
|
||||
, page_table{address_space_bits, address_space_bits + page_bits - 38, page_bits != big_page_bits ? page_bits : 0}
|
||||
, kind_map{PTEKind::INVALID}, unique_identifier{unique_identifier_generator.fetch_add(1, std::memory_order_acq_rel)}
|
||||
, accumulator{}
|
||||
{
|
||||
address_space_size = 1ULL << address_space_bits;
|
||||
page_size = 1ULL << page_bits;
|
||||
page_mask = page_size - 1ULL;
|
||||
@@ -54,10 +52,9 @@ MemoryManager::MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager&
|
||||
entries.resize(page_table_size / 32, 0);
|
||||
}
|
||||
|
||||
MemoryManager::MemoryManager(Core::System& system_, u64 address_space_bits_,
|
||||
GPUVAddr split_address_, u64 big_page_bits_, u64 page_bits_)
|
||||
: MemoryManager(system_, system_.Host1x().MemoryManager(), address_space_bits_, split_address_,
|
||||
big_page_bits_, page_bits_) {}
|
||||
MemoryManager::MemoryManager(Core::System& system_, u64 address_space_bits_, GPUVAddr split_address_, u64 big_page_bits_, u64 page_bits_)
|
||||
: MemoryManager(system_, system_.Host1x().MemoryManager(), address_space_bits_, split_address_, big_page_bits_, page_bits_)
|
||||
{}
|
||||
|
||||
MemoryManager::~MemoryManager() = default;
|
||||
|
||||
@@ -469,10 +466,9 @@ void MemoryManager::WriteBlockUnsafe(GPUVAddr gpu_dest_addr, const void* src_buf
|
||||
WriteBlockImpl<false>(gpu_dest_addr, src_buffer, size, VideoCommon::CacheType::None);
|
||||
}
|
||||
|
||||
void MemoryManager::WriteBlockCached(GPUVAddr gpu_dest_addr, const void* src_buffer,
|
||||
std::size_t size) {
|
||||
void MemoryManager::WriteBlockCached(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size) {
|
||||
WriteBlockImpl<false>(gpu_dest_addr, src_buffer, size, VideoCommon::CacheType::None);
|
||||
accumulator->Add(gpu_dest_addr, size);
|
||||
accumulator.Add(gpu_dest_addr, size);
|
||||
}
|
||||
|
||||
void MemoryManager::FlushRegion(GPUVAddr gpu_addr, size_t size,
|
||||
@@ -756,15 +752,13 @@ void MemoryManager::GetSubmappedRangeImpl(
|
||||
}
|
||||
|
||||
void MemoryManager::FlushCaching() {
|
||||
if (!accumulator->AnyAccumulated()) {
|
||||
return;
|
||||
}
|
||||
accumulator->Callback([this](GPUVAddr addr, size_t size) {
|
||||
// Flush from the invalidate accumulator
|
||||
if (accumulator.InvalidateAll([this](GPUVAddr addr, size_t size) {
|
||||
GetSubmappedRangeImpl<false>(addr, size, page_stash2);
|
||||
});
|
||||
rasterizer->InnerInvalidation(VideoCommon::FixSmallVectorADL(page_stash2));
|
||||
page_stash2.clear();
|
||||
accumulator->Clear();
|
||||
})) {
|
||||
rasterizer->InnerInvalidation(VideoCommon::FixSmallVectorADL(page_stash2));
|
||||
page_stash2.clear();
|
||||
}
|
||||
}
|
||||
|
||||
const u8* MemoryManager::GetSpan(const GPUVAddr src_addr, const std::size_t size) const {
|
||||
|
||||
@@ -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 2018 yuzu Emulator Project
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "common/range_map.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
#include "common/virtual_buffer.h"
|
||||
#include "video_core/invalidation_accumulator.h"
|
||||
#include "video_core/cache_types.h"
|
||||
#include "video_core/host1x/gpu_device_memory_manager.h"
|
||||
#include "video_core/pte_kind.h"
|
||||
@@ -26,10 +27,6 @@ namespace VideoCore {
|
||||
class RasterizerInterface;
|
||||
}
|
||||
|
||||
namespace VideoCommon {
|
||||
class InvalidationAccumulator;
|
||||
}
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
} // namespace Core
|
||||
@@ -249,7 +246,7 @@ private:
|
||||
static constexpr size_t continuous_bits = 64;
|
||||
|
||||
const size_t unique_identifier;
|
||||
std::unique_ptr<VideoCommon::InvalidationAccumulator> accumulator;
|
||||
VideoCommon::InvalidationAccumulator accumulator;
|
||||
|
||||
static std::atomic<size_t> unique_identifier_generator;
|
||||
|
||||
|
||||
@@ -127,9 +127,8 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
|
||||
|
||||
texture_cache.SynchronizeComputeDescriptors();
|
||||
|
||||
static constexpr size_t max_elements = 64;
|
||||
boost::container::static_vector<VideoCommon::ImageViewInOut, max_elements> views;
|
||||
boost::container::static_vector<VideoCommon::SamplerId, max_elements> samplers;
|
||||
boost::container::small_vector<VideoCommon::ImageViewInOut, 64> views;
|
||||
boost::container::small_vector<VideoCommon::SamplerId, 64> samplers;
|
||||
|
||||
const auto& qmd{kepler_compute.launch_description};
|
||||
const auto& cbufs{qmd.const_buffer_config};
|
||||
|
||||
Reference in New Issue
Block a user