Compare commits
5 Commits
android-17
...
android-17
Author | SHA1 | Date | |
---|---|---|---|
ab2af23e47 | |||
52d3d87d09 | |||
30f76ed9c2 | |||
c85f87ffa4 | |||
7778f1906d |
@ -1,7 +1,9 @@
|
||||
| Pull Request | Commit | Title | Author | Merged? |
|
||||
|----|----|----|----|----|
|
||||
| [12466](https://github.com/yuzu-emu/yuzu//pull/12466) | [`ddda76f9b`](https://github.com/yuzu-emu/yuzu//pull/12466/files) | core: track separate heap allocation for linux | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||
| [12479](https://github.com/yuzu-emu/yuzu//pull/12479) | [`20e040723`](https://github.com/yuzu-emu/yuzu//pull/12479/files) | video_core: Fix buffer_row_length for linear compressed textures | [GPUCode](https://github.com/GPUCode/) | Yes |
|
||||
| [12448](https://github.com/yuzu-emu/yuzu//pull/12448) | [`b1d4804c0`](https://github.com/yuzu-emu/yuzu//pull/12448/files) | renderer_vulkan: demote format assert to error log | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||
| [12449](https://github.com/yuzu-emu/yuzu//pull/12449) | [`6a1ddc502`](https://github.com/yuzu-emu/yuzu//pull/12449/files) | renderer_vulkan: skip SetObjectNameEXT on unsupported driver | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||
| [12466](https://github.com/yuzu-emu/yuzu//pull/12466) | [`5f3720138`](https://github.com/yuzu-emu/yuzu//pull/12466/files) | core: track separate heap allocation for linux | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||
| [12467](https://github.com/yuzu-emu/yuzu//pull/12467) | [`cfc6c5f8f`](https://github.com/yuzu-emu/yuzu//pull/12467/files) | Revert " shader_recompiler: use minimal clip distance array " | [liamwhite](https://github.com/liamwhite/) | Yes |
|
||||
|
||||
|
||||
End of merge log. You can find the original README.md below the break.
|
||||
|
@ -3,19 +3,16 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/logging/backend.h"
|
||||
|
||||
#include "common/settings.h"
|
||||
|
||||
void assert_fail_impl() {
|
||||
if (Settings::values.use_debug_asserts) {
|
||||
Common::Log::Stop();
|
||||
Crash();
|
||||
}
|
||||
}
|
||||
|
||||
[[noreturn]] void unreachable_impl() {
|
||||
Common::Log::Stop();
|
||||
Crash();
|
||||
throw std::runtime_error("Unreachable code");
|
||||
}
|
||||
|
@ -1,17 +1,14 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/heap_tracker.h"
|
||||
#include "common/logging/log.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr s64 MaxResidentMapCount = 0x8000;
|
||||
constexpr size_t MaxResidentMapCount = 0x8000;
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -30,17 +27,17 @@ void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
||||
// We are mapping part of a separate heap.
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
auto* const map = new SeparateHeapMap{
|
||||
auto* map = new SeparateHeapMap{
|
||||
.vaddr = virtual_offset,
|
||||
.paddr = host_offset,
|
||||
.size = length,
|
||||
.map_id = m_next_map_id++,
|
||||
.tick = m_tick++,
|
||||
.perm = perm,
|
||||
.is_resident = false,
|
||||
};
|
||||
|
||||
// Insert into mappings.
|
||||
m_map_count++;
|
||||
m_mappings.insert(*map);
|
||||
}
|
||||
|
||||
@ -51,10 +48,11 @@ void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
||||
void HeapTracker::Unmap(size_t virtual_offset, size_t size, bool is_separate_heap) {
|
||||
// If this is a separate heap...
|
||||
if (is_separate_heap) {
|
||||
std::scoped_lock lk{m_lock};
|
||||
std::scoped_lock lk{m_rebuild_lock, m_lock};
|
||||
|
||||
const SeparateHeapMap key{
|
||||
.vaddr = virtual_offset,
|
||||
.size = size,
|
||||
};
|
||||
|
||||
// Split at the boundaries of the region we are removing.
|
||||
@ -64,18 +62,20 @@ void HeapTracker::Unmap(size_t virtual_offset, size_t size, bool is_separate_hea
|
||||
// Erase all mappings in range.
|
||||
auto it = m_mappings.find(key);
|
||||
while (it != m_mappings.end() && it->vaddr < virtual_offset + size) {
|
||||
// Get underlying item.
|
||||
auto* const item = std::addressof(*it);
|
||||
// Get pointer to item.
|
||||
SeparateHeapMap* const item = std::addressof(*it);
|
||||
|
||||
// If resident, erase from resident map.
|
||||
if (item->is_resident) {
|
||||
ASSERT(--m_resident_map_count >= 0);
|
||||
// Unlink from resident tree.
|
||||
m_resident_mappings.erase(m_resident_mappings.iterator_to(*item));
|
||||
|
||||
// Decrease reference count.
|
||||
const auto count_it = m_resident_map_counts.find(item->map_id);
|
||||
this->RemoveReferenceLocked(count_it, 1);
|
||||
}
|
||||
|
||||
// Erase from map.
|
||||
// Unlink from mapping tree and advance.
|
||||
it = m_mappings.erase(it);
|
||||
ASSERT(--m_map_count >= 0);
|
||||
|
||||
// Free the item.
|
||||
delete item;
|
||||
@ -109,7 +109,7 @@ void HeapTracker::Protect(size_t virtual_offset, size_t size, MemoryPermission p
|
||||
};
|
||||
|
||||
// Try to get the next mapping corresponding to this address.
|
||||
const auto it = m_mappings.nfind(key);
|
||||
const auto it = m_mappings.nfind_key(key);
|
||||
|
||||
if (it == m_mappings.end()) {
|
||||
// There are no separate heap mappings remaining.
|
||||
@ -152,61 +152,106 @@ bool HeapTracker::DeferredMapSeparateHeap(u8* fault_address) {
|
||||
}
|
||||
|
||||
bool HeapTracker::DeferredMapSeparateHeap(size_t virtual_offset) {
|
||||
bool rebuild_required = false;
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
{
|
||||
std::scoped_lock lk{m_lock};
|
||||
while (this->IsEvictRequiredLocked()) {
|
||||
// Unlock before we rebuild to ensure proper lock ordering.
|
||||
m_lock.unlock();
|
||||
|
||||
// Check to ensure this was a non-resident separate heap mapping.
|
||||
const auto it = this->GetNearestHeapMapLocked(virtual_offset);
|
||||
if (it == m_mappings.end() || it->is_resident) {
|
||||
return false;
|
||||
// Evict four maps.
|
||||
for (size_t i = 0; i < 4; /* ... */) {
|
||||
i += this->EvictSingleSeparateHeapMap();
|
||||
}
|
||||
|
||||
// Update tick before possible rebuild.
|
||||
it->tick = m_tick++;
|
||||
|
||||
// Check if we need to rebuild.
|
||||
if (m_resident_map_count > MaxResidentMapCount) {
|
||||
rebuild_required = true;
|
||||
}
|
||||
|
||||
// Map the area.
|
||||
m_buffer.Map(it->vaddr, it->paddr, it->size, it->perm, false);
|
||||
|
||||
// This map is now resident.
|
||||
it->is_resident = true;
|
||||
m_resident_map_count++;
|
||||
m_resident_mappings.insert(*it);
|
||||
// Lock again.
|
||||
m_lock.lock();
|
||||
}
|
||||
|
||||
if (rebuild_required) {
|
||||
// A rebuild was required, so perform it now.
|
||||
this->RebuildSeparateHeapAddressSpace();
|
||||
// Check to ensure this was a non-resident separate heap mapping.
|
||||
const auto it = this->GetNearestHeapMapLocked(virtual_offset);
|
||||
if (it == m_mappings.end()) {
|
||||
// Not in any separate heap.
|
||||
return false;
|
||||
}
|
||||
if (it->is_resident) {
|
||||
// Already mapped and shouldn't be considered again.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Map the area.
|
||||
m_buffer.Map(it->vaddr, it->paddr, it->size, it->perm, false);
|
||||
|
||||
// This map is now resident.
|
||||
this->AddReferenceLocked(it->map_id, 1);
|
||||
it->is_resident = true;
|
||||
it->tick = m_tick++;
|
||||
|
||||
// Insert into resident maps.
|
||||
m_resident_mappings.insert(*it);
|
||||
|
||||
// We succeeded.
|
||||
return true;
|
||||
}
|
||||
|
||||
void HeapTracker::RebuildSeparateHeapAddressSpace() {
|
||||
bool HeapTracker::EvictSingleSeparateHeapMap() {
|
||||
std::scoped_lock lk{m_rebuild_lock, m_lock};
|
||||
|
||||
ASSERT(!m_resident_mappings.empty());
|
||||
|
||||
// Unmap so we have at least 4 maps available.
|
||||
const size_t desired_count = std::min(m_resident_map_count, MaxResidentMapCount - 4);
|
||||
const size_t evict_count = m_resident_map_count - desired_count;
|
||||
auto it = m_resident_mappings.begin();
|
||||
// Select the item with the lowest tick to evict.
|
||||
auto* const item = std::addressof(*m_resident_mappings.begin());
|
||||
auto it = m_mappings.iterator_to(*item);
|
||||
|
||||
for (size_t i = 0; i < evict_count && it != m_resident_mappings.end(); i++) {
|
||||
// Unmark and unmap.
|
||||
it->is_resident = false;
|
||||
m_buffer.Unmap(it->vaddr, it->size, false);
|
||||
// Track the map ID.
|
||||
const size_t map_id = it->map_id;
|
||||
|
||||
// Walk backwards until we find the first entry.
|
||||
while (it != m_mappings.begin()) {
|
||||
// If the previous element does not have the same map ID, stop.
|
||||
const auto prev = std::prev(it);
|
||||
if (prev->map_id != map_id) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Continue.
|
||||
it = prev;
|
||||
}
|
||||
|
||||
// Track the begin and end address.
|
||||
const VAddr begin_vaddr = it->vaddr;
|
||||
VAddr end_vaddr = begin_vaddr;
|
||||
|
||||
// Get the count iterator.
|
||||
const auto count_it = m_resident_map_counts.find(map_id);
|
||||
|
||||
// Declare whether we have erased an underlying mapping.
|
||||
bool was_erased = false;
|
||||
|
||||
// Unmark and merge everything in range.
|
||||
while (it != m_mappings.end() && it->map_id == map_id) {
|
||||
if (it->is_resident) {
|
||||
// Remove from resident tree.
|
||||
m_resident_mappings.erase(m_resident_mappings.iterator_to(*it));
|
||||
it->is_resident = false;
|
||||
|
||||
// Remove reference count.
|
||||
was_erased |= this->RemoveReferenceLocked(count_it, 1);
|
||||
}
|
||||
|
||||
// Update the end address.
|
||||
end_vaddr = it->vaddr + it->size;
|
||||
|
||||
// Advance.
|
||||
ASSERT(--m_resident_map_count >= 0);
|
||||
it = m_resident_mappings.erase(it);
|
||||
it = this->MergeHeapMapForEvictLocked(it);
|
||||
}
|
||||
|
||||
// Finally, unmap.
|
||||
ASSERT(end_vaddr >= begin_vaddr);
|
||||
m_buffer.Unmap(begin_vaddr, end_vaddr - begin_vaddr, false);
|
||||
|
||||
// Return whether we actually removed a mapping.
|
||||
// This will be true if there were no holes, which is likely.
|
||||
return was_erased;
|
||||
}
|
||||
|
||||
void HeapTracker::SplitHeapMap(VAddr offset, size_t size) {
|
||||
@ -223,9 +268,11 @@ void HeapTracker::SplitHeapMapLocked(VAddr offset) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache the original values.
|
||||
// Get the underlying item as the left.
|
||||
auto* const left = std::addressof(*it);
|
||||
const size_t orig_size = left->size;
|
||||
|
||||
// Cache the original size values.
|
||||
const size_t size = left->size;
|
||||
|
||||
// Adjust the left map.
|
||||
const size_t left_size = offset - left->vaddr;
|
||||
@ -235,21 +282,74 @@ void HeapTracker::SplitHeapMapLocked(VAddr offset) {
|
||||
auto* const right = new SeparateHeapMap{
|
||||
.vaddr = left->vaddr + left_size,
|
||||
.paddr = left->paddr + left_size,
|
||||
.size = orig_size - left_size,
|
||||
.size = size - left_size,
|
||||
.map_id = left->map_id,
|
||||
.tick = left->tick,
|
||||
.perm = left->perm,
|
||||
.is_resident = left->is_resident,
|
||||
};
|
||||
|
||||
// Insert the new right map.
|
||||
m_map_count++;
|
||||
m_mappings.insert(*right);
|
||||
|
||||
// If resident, also insert into resident map.
|
||||
if (right->is_resident) {
|
||||
m_resident_mappings.insert(*right);
|
||||
m_resident_map_count++;
|
||||
// If the original map was not resident, we are done.
|
||||
if (!left->is_resident) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update reference count.
|
||||
this->AddReferenceLocked(left->map_id, 1);
|
||||
|
||||
// Insert right into resident map.
|
||||
m_resident_mappings.insert(*right);
|
||||
}
|
||||
|
||||
HeapTracker::AddrTree::iterator HeapTracker::MergeHeapMapForEvictLocked(AddrTree::iterator it) {
|
||||
if (it == m_mappings.end()) {
|
||||
// Not contained.
|
||||
return it;
|
||||
}
|
||||
|
||||
if (it == m_mappings.begin()) {
|
||||
// Nothing to merge with.
|
||||
return std::next(it);
|
||||
}
|
||||
|
||||
// Get the left and right items.
|
||||
auto* const right = std::addressof(*it);
|
||||
auto* const left = std::addressof(*std::prev(it));
|
||||
|
||||
if (left->vaddr + left->size != right->vaddr) {
|
||||
// Virtual range not contiguous, cannot merge.
|
||||
return std::next(it);
|
||||
}
|
||||
|
||||
if (left->paddr + left->size != right->paddr) {
|
||||
// Physical range not contiguous, cannot merge.
|
||||
return std::next(it);
|
||||
}
|
||||
|
||||
if (left->perm != right->perm) {
|
||||
// Permissions mismatch, cannot merge.
|
||||
return std::next(it);
|
||||
}
|
||||
|
||||
if (left->map_id != right->map_id) {
|
||||
// Map ID mismatch, cannot merge.
|
||||
return std::next(it);
|
||||
}
|
||||
|
||||
// Merge size to the left.
|
||||
left->size += right->size;
|
||||
|
||||
// Erase the right element.
|
||||
const auto next_it = m_mappings.erase(it);
|
||||
|
||||
// Free the right element.
|
||||
delete right;
|
||||
|
||||
// Return the iterator to the next position.
|
||||
return next_it;
|
||||
}
|
||||
|
||||
HeapTracker::AddrTree::iterator HeapTracker::GetNearestHeapMapLocked(VAddr offset) {
|
||||
@ -260,4 +360,26 @@ HeapTracker::AddrTree::iterator HeapTracker::GetNearestHeapMapLocked(VAddr offse
|
||||
return m_mappings.find(key);
|
||||
}
|
||||
|
||||
void HeapTracker::AddReferenceLocked(size_t map_id, size_t inc) {
|
||||
m_resident_map_counts[map_id]++;
|
||||
}
|
||||
|
||||
bool HeapTracker::RemoveReferenceLocked(MapCountTree::iterator it, size_t dec) {
|
||||
ASSERT(it != m_resident_map_counts.end());
|
||||
|
||||
const auto new_value = it->second -= dec;
|
||||
ASSERT(new_value >= 0);
|
||||
|
||||
if (new_value <= 0) {
|
||||
m_resident_map_counts.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HeapTracker::IsEvictRequiredLocked() {
|
||||
return m_resident_map_counts.size() > MaxResidentMapCount;
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
@ -3,9 +3,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <shared_mutex>
|
||||
|
||||
#include "common/host_memory.h"
|
||||
@ -19,6 +18,7 @@ struct SeparateHeapMap {
|
||||
VAddr vaddr{};
|
||||
PAddr paddr{};
|
||||
size_t size{};
|
||||
size_t map_id{};
|
||||
size_t tick{};
|
||||
MemoryPermission perm{};
|
||||
bool is_resident{};
|
||||
@ -64,6 +64,14 @@ public:
|
||||
bool DeferredMapSeparateHeap(u8* fault_address);
|
||||
bool DeferredMapSeparateHeap(size_t virtual_offset);
|
||||
|
||||
private:
|
||||
Common::HostMemory& m_buffer;
|
||||
|
||||
std::shared_mutex m_rebuild_lock{};
|
||||
std::mutex m_lock{};
|
||||
size_t m_next_map_id{};
|
||||
size_t m_tick{};
|
||||
|
||||
private:
|
||||
using AddrTreeTraits =
|
||||
Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::addr_node>;
|
||||
@ -72,7 +80,9 @@ private:
|
||||
using TickTreeTraits =
|
||||
Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::tick_node>;
|
||||
using TickTree = TickTreeTraits::TreeType<SeparateHeapMapTickComparator>;
|
||||
using MapCountTree = std::map<size_t, s64>;
|
||||
|
||||
MapCountTree m_resident_map_counts{};
|
||||
AddrTree m_mappings{};
|
||||
TickTree m_resident_mappings{};
|
||||
|
||||
@ -80,18 +90,14 @@ private:
|
||||
void SplitHeapMap(VAddr offset, size_t size);
|
||||
void SplitHeapMapLocked(VAddr offset);
|
||||
|
||||
AddrTree::iterator MergeHeapMapForEvictLocked(AddrTree::iterator cur);
|
||||
AddrTree::iterator GetNearestHeapMapLocked(VAddr offset);
|
||||
|
||||
void RebuildSeparateHeapAddressSpace();
|
||||
bool EvictSingleSeparateHeapMap();
|
||||
|
||||
private:
|
||||
Common::HostMemory& m_buffer;
|
||||
|
||||
std::shared_mutex m_rebuild_lock{};
|
||||
std::mutex m_lock{};
|
||||
s64 m_map_count{};
|
||||
s64 m_resident_map_count{};
|
||||
size_t m_tick{};
|
||||
void AddReferenceLocked(size_t map_id, size_t inc);
|
||||
bool RemoveReferenceLocked(MapCountTree::iterator map_id, size_t dec);
|
||||
bool IsEvictRequiredLocked();
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
|
@ -208,10 +208,6 @@ public:
|
||||
instance->StartBackendThread();
|
||||
}
|
||||
|
||||
static void Stop() {
|
||||
instance->StopBackendThread();
|
||||
}
|
||||
|
||||
Impl(const Impl&) = delete;
|
||||
Impl& operator=(const Impl&) = delete;
|
||||
|
||||
@ -263,15 +259,6 @@ private:
|
||||
});
|
||||
}
|
||||
|
||||
void StopBackendThread() {
|
||||
backend_thread.request_stop();
|
||||
if (backend_thread.joinable()) {
|
||||
backend_thread.join();
|
||||
}
|
||||
|
||||
ForEachBackend([](Backend& backend) { backend.Flush(); });
|
||||
}
|
||||
|
||||
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
|
||||
const char* function, std::string&& message) const {
|
||||
using std::chrono::duration_cast;
|
||||
@ -326,10 +313,6 @@ void Start() {
|
||||
Impl::Start();
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
Impl::Stop();
|
||||
}
|
||||
|
||||
void DisableLoggingInTests() {
|
||||
initialization_in_progress_suppress_logging = true;
|
||||
}
|
||||
|
@ -14,9 +14,6 @@ void Initialize();
|
||||
|
||||
void Start();
|
||||
|
||||
/// Explicitly stops the logger thread and flushes the buffers
|
||||
void Stop();
|
||||
|
||||
void DisableLoggingInTests();
|
||||
|
||||
/**
|
||||
|
@ -103,7 +103,7 @@ private:
|
||||
// Having them on the same cache-line would result in false-sharing between them.
|
||||
// TODO: Remove this ifdef whenever clang and GCC support
|
||||
// std::hardware_destructive_interference_size.
|
||||
#ifdef __cpp_lib_hardware_interference_size
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1911
|
||||
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_read_index{0};
|
||||
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_write_index{0};
|
||||
#else
|
||||
|
@ -8,22 +8,19 @@
|
||||
namespace Kernel {
|
||||
|
||||
void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) {
|
||||
// KScopedInterruptDisable di;
|
||||
KScopedSpinLock lk(m_lock);
|
||||
KScopedLightLock lk(m_lock);
|
||||
|
||||
m_object_list.insert_unique(*obj);
|
||||
}
|
||||
|
||||
void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) {
|
||||
// KScopedInterruptDisable di;
|
||||
KScopedSpinLock lk(m_lock);
|
||||
KScopedLightLock lk(m_lock);
|
||||
|
||||
m_object_list.erase(*obj);
|
||||
}
|
||||
|
||||
size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) {
|
||||
// KScopedInterruptDisable di;
|
||||
KScopedSpinLock lk(m_lock);
|
||||
KScopedLightLock lk(m_lock);
|
||||
|
||||
return std::count_if(m_object_list.begin(), m_object_list.end(),
|
||||
[&](const auto& obj) { return obj.GetOwner() == owner; });
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "core/hle/kernel/k_auto_object.h"
|
||||
#include "core/hle/kernel/k_spin_lock.h"
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
@ -21,7 +21,32 @@ public:
|
||||
|
||||
using ListType = boost::intrusive::rbtree<KAutoObjectWithList>;
|
||||
|
||||
KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(), m_object_list() {}
|
||||
class ListAccessor : public KScopedLightLock {
|
||||
public:
|
||||
explicit ListAccessor(KAutoObjectWithListContainer* container)
|
||||
: KScopedLightLock(container->m_lock), m_list(container->m_object_list) {}
|
||||
explicit ListAccessor(KAutoObjectWithListContainer& container)
|
||||
: KScopedLightLock(container.m_lock), m_list(container.m_object_list) {}
|
||||
|
||||
typename ListType::iterator begin() const {
|
||||
return m_list.begin();
|
||||
}
|
||||
|
||||
typename ListType::iterator end() const {
|
||||
return m_list.end();
|
||||
}
|
||||
|
||||
typename ListType::iterator find(typename ListType::const_reference ref) const {
|
||||
return m_list.find(ref);
|
||||
}
|
||||
|
||||
private:
|
||||
ListType& m_list;
|
||||
};
|
||||
|
||||
friend class ListAccessor;
|
||||
|
||||
KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(kernel), m_object_list() {}
|
||||
|
||||
void Initialize() {}
|
||||
void Finalize() {}
|
||||
@ -31,7 +56,7 @@ public:
|
||||
size_t GetOwnedCount(KProcess* owner);
|
||||
|
||||
private:
|
||||
KSpinLock m_lock;
|
||||
KLightLock m_lock;
|
||||
ListType m_object_list;
|
||||
};
|
||||
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
public:
|
||||
explicit KHandleTable(KernelCore& kernel) : m_kernel(kernel) {}
|
||||
|
||||
Result Initialize(s32 size) {
|
||||
Result Initialize(KProcess* owner, s32 size) {
|
||||
// Check that the table size is valid.
|
||||
R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory);
|
||||
|
||||
@ -44,6 +44,7 @@ public:
|
||||
m_next_linear_id = MinLinearId;
|
||||
m_count = 0;
|
||||
m_free_head_index = -1;
|
||||
m_owner = owner;
|
||||
|
||||
// Free all entries.
|
||||
for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) {
|
||||
@ -90,7 +91,8 @@ public:
|
||||
// Handle pseudo-handles.
|
||||
if constexpr (std::derived_from<KProcess, T>) {
|
||||
if (handle == Svc::PseudoHandle::CurrentProcess) {
|
||||
auto* const cur_process = GetCurrentProcessPointer(m_kernel);
|
||||
// TODO: this should be the current process
|
||||
auto* const cur_process = m_owner;
|
||||
ASSERT(cur_process != nullptr);
|
||||
return cur_process;
|
||||
}
|
||||
@ -300,6 +302,7 @@ private:
|
||||
|
||||
private:
|
||||
KernelCore& m_kernel;
|
||||
KProcess* m_owner{};
|
||||
std::array<EntryInfo, MaxTableSize> m_entry_infos{};
|
||||
std::array<KAutoObject*, MaxTableSize> m_objects{};
|
||||
mutable KSpinLock m_lock;
|
||||
|
@ -552,7 +552,7 @@ private:
|
||||
|
||||
Result InitializeHandleTable(s32 size) {
|
||||
// Try to initialize the handle table.
|
||||
R_TRY(m_handle_table.Initialize(size));
|
||||
R_TRY(m_handle_table.Initialize(this, size));
|
||||
|
||||
// We succeeded, so note that we did.
|
||||
m_is_handle_table_initialized = true;
|
||||
|
@ -1147,7 +1147,8 @@ Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server
|
||||
*out_context =
|
||||
std::make_shared<Service::HLERequestContext>(m_kernel, memory, this, client_thread);
|
||||
(*out_context)->SetSessionRequestManager(manager);
|
||||
(*out_context)->PopulateFromIncomingCommandBuffer(cmd_buf);
|
||||
(*out_context)
|
||||
->PopulateFromIncomingCommandBuffer(*client_thread->GetOwnerProcess(), cmd_buf);
|
||||
// We succeeded.
|
||||
R_SUCCEED();
|
||||
} else {
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
#include "core/hle/kernel/k_page_group.h"
|
||||
#include "core/hle/kernel/slab_helpers.h"
|
||||
#include "core/hle/kernel/svc_types.h"
|
||||
|
@ -1513,7 +1513,8 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx)
|
||||
return;
|
||||
}
|
||||
|
||||
auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
|
||||
auto transfer_mem =
|
||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
|
||||
|
||||
if (transfer_mem.IsNull()) {
|
||||
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
|
||||
@ -1523,7 +1524,8 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx)
|
||||
}
|
||||
|
||||
std::vector<u8> memory(transfer_mem->GetSize());
|
||||
ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size());
|
||||
system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(),
|
||||
memory.size());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
@ -1545,7 +1547,8 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
|
||||
auto transfer_mem =
|
||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
|
||||
|
||||
if (transfer_mem.IsNull()) {
|
||||
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
|
||||
@ -1555,7 +1558,8 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
std::vector<u8> memory(transfer_mem->GetSize());
|
||||
ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size());
|
||||
system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(),
|
||||
memory.size());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
|
@ -454,8 +454,10 @@ void AudRenU::OpenAudioRenderer(HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle)};
|
||||
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||
const auto& handle_table{system.ApplicationProcess()->GetHandleTable()};
|
||||
auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)};
|
||||
auto transfer_memory{
|
||||
process->GetHandleTable().GetObject<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||
|
||||
const auto session_id{impl->GetSessionId()};
|
||||
if (session_id == -1) {
|
||||
|
@ -278,7 +278,9 @@ void HwOpus::OpenHardwareOpusDecoder(HLERequestContext& ctx) {
|
||||
auto params = rp.PopRaw<OpusParameters>();
|
||||
auto transfer_memory_size{rp.Pop<u32>()};
|
||||
auto transfer_memory_handle{ctx.GetCopyHandle(0)};
|
||||
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||
auto transfer_memory{
|
||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
transfer_memory_handle)};
|
||||
|
||||
LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
|
||||
params.sample_rate, params.channel_count, transfer_memory_size);
|
||||
@ -321,7 +323,9 @@ void HwOpus::OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx) {
|
||||
|
||||
auto transfer_memory_size{rp.Pop<u32>()};
|
||||
auto transfer_memory_handle{ctx.GetCopyHandle(0)};
|
||||
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||
auto transfer_memory{
|
||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
transfer_memory_handle)};
|
||||
|
||||
LOG_DEBUG(Service_Audio,
|
||||
"sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
|
||||
@ -370,7 +374,9 @@ void HwOpus::OpenHardwareOpusDecoderEx(HLERequestContext& ctx) {
|
||||
auto params = rp.PopRaw<OpusParametersEx>();
|
||||
auto transfer_memory_size{rp.Pop<u32>()};
|
||||
auto transfer_memory_handle{ctx.GetCopyHandle(0)};
|
||||
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||
auto transfer_memory{
|
||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
transfer_memory_handle)};
|
||||
|
||||
LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
|
||||
params.sample_rate, params.channel_count, transfer_memory_size);
|
||||
@ -408,7 +414,9 @@ void HwOpus::OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx) {
|
||||
|
||||
auto transfer_memory_size{rp.Pop<u32>()};
|
||||
auto transfer_memory_handle{ctx.GetCopyHandle(0)};
|
||||
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
|
||||
auto transfer_memory{
|
||||
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
transfer_memory_handle)};
|
||||
|
||||
LOG_DEBUG(Service_Audio,
|
||||
"sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
|
||||
|
@ -1850,7 +1850,8 @@ void IHidServer::InitializeSevenSixAxisSensor(HLERequestContext& ctx) {
|
||||
ASSERT_MSG(t_mem_1_size == 0x1000, "t_mem_1_size is not 0x1000 bytes");
|
||||
ASSERT_MSG(t_mem_2_size == 0x7F000, "t_mem_2_size is not 0x7F000 bytes");
|
||||
|
||||
auto t_mem_1 = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_1_handle);
|
||||
auto t_mem_1 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
t_mem_1_handle);
|
||||
|
||||
if (t_mem_1.IsNull()) {
|
||||
LOG_ERROR(Service_HID, "t_mem_1 is a nullptr for handle=0x{:08X}", t_mem_1_handle);
|
||||
@ -1859,7 +1860,8 @@ void IHidServer::InitializeSevenSixAxisSensor(HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto t_mem_2 = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_2_handle);
|
||||
auto t_mem_2 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
t_mem_2_handle);
|
||||
|
||||
if (t_mem_2.IsNull()) {
|
||||
LOG_ERROR(Service_HID, "t_mem_2 is a nullptr for handle=0x{:08X}", t_mem_2_handle);
|
||||
@ -2140,7 +2142,8 @@ void IHidServer::WritePalmaWaveEntry(HLERequestContext& ctx) {
|
||||
|
||||
ASSERT_MSG(t_mem_size == 0x3000, "t_mem_size is not 0x3000 bytes");
|
||||
|
||||
auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
|
||||
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
t_mem_handle);
|
||||
|
||||
if (t_mem.IsNull()) {
|
||||
LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
|
||||
|
@ -448,7 +448,8 @@ void HidBus::EnableJoyPollingReceiveMode(HLERequestContext& ctx) {
|
||||
|
||||
ASSERT_MSG(t_mem_size == 0x1000, "t_mem_size is not 0x1000 bytes");
|
||||
|
||||
auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
|
||||
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
t_mem_handle);
|
||||
|
||||
if (t_mem.IsNull()) {
|
||||
LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
|
||||
|
@ -197,7 +197,8 @@ void IRS::RunImageTransferProcessor(HLERequestContext& ctx) {
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
const auto t_mem_handle{ctx.GetCopyHandle(0)};
|
||||
|
||||
auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
|
||||
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
t_mem_handle);
|
||||
|
||||
if (t_mem.IsNull()) {
|
||||
LOG_ERROR(Service_IRS, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
|
||||
@ -443,7 +444,8 @@ void IRS::RunImageTransferExProcessor(HLERequestContext& ctx) {
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
const auto t_mem_handle{ctx.GetCopyHandle(0)};
|
||||
|
||||
auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
|
||||
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
|
||||
t_mem_handle);
|
||||
|
||||
LOG_INFO(Service_IRS,
|
||||
"called, npad_type={}, npad_id={}, transfer_memory_size={}, "
|
||||
|
@ -146,7 +146,10 @@ HLERequestContext::HLERequestContext(Kernel::KernelCore& kernel_, Core::Memory::
|
||||
|
||||
HLERequestContext::~HLERequestContext() = default;
|
||||
|
||||
void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
|
||||
void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf,
|
||||
bool incoming) {
|
||||
client_handle_table = &process.GetHandleTable();
|
||||
|
||||
IPC::RequestParser rp(src_cmdbuf);
|
||||
command_header = rp.PopRaw<IPC::CommandHeader>();
|
||||
|
||||
@ -159,7 +162,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
|
||||
if (command_header->enable_handle_descriptor) {
|
||||
handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>();
|
||||
if (handle_descriptor_header->send_current_pid) {
|
||||
pid = thread->GetOwnerProcess()->GetProcessId();
|
||||
pid = process.GetProcessId();
|
||||
rp.Skip(2, false);
|
||||
}
|
||||
if (incoming) {
|
||||
@ -267,10 +270,9 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
|
||||
rp.Skip(1, false); // The command is actually an u64, but we don't use the high part.
|
||||
}
|
||||
|
||||
Result HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf) {
|
||||
client_handle_table = &thread->GetOwnerProcess()->GetHandleTable();
|
||||
|
||||
ParseCommandBuffer(src_cmdbuf, true);
|
||||
Result HLERequestContext::PopulateFromIncomingCommandBuffer(Kernel::KProcess& process,
|
||||
u32_le* src_cmdbuf) {
|
||||
ParseCommandBuffer(process, src_cmdbuf, true);
|
||||
|
||||
if (command_header->IsCloseCommand()) {
|
||||
// Close does not populate the rest of the IPC header
|
||||
@ -282,9 +284,9 @@ Result HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf)
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result HLERequestContext::WriteToOutgoingCommandBuffer() {
|
||||
Result HLERequestContext::WriteToOutgoingCommandBuffer(Kernel::KThread& requesting_thread) {
|
||||
auto current_offset = handles_offset;
|
||||
auto& owner_process = *thread->GetOwnerProcess();
|
||||
auto& owner_process = *requesting_thread.GetOwnerProcess();
|
||||
auto& handle_table = owner_process.GetHandleTable();
|
||||
|
||||
for (auto& object : outgoing_copy_objects) {
|
||||
@ -317,7 +319,7 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer() {
|
||||
}
|
||||
|
||||
// Copy the translated command buffer back into the thread's command buffer area.
|
||||
memory.WriteBlock(thread->GetTlsAddress(), cmd_buf.data(), write_size * sizeof(u32));
|
||||
memory.WriteBlock(requesting_thread.GetTlsAddress(), cmd_buf.data(), write_size * sizeof(u32));
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include "common/concepts.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/hle/ipc.h"
|
||||
#include "core/hle/kernel/k_handle_table.h"
|
||||
#include "core/hle/kernel/svc_common.h"
|
||||
|
||||
union Result;
|
||||
@ -197,10 +196,10 @@ public:
|
||||
}
|
||||
|
||||
/// Populates this context with data from the requesting process/thread.
|
||||
Result PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf);
|
||||
Result PopulateFromIncomingCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf);
|
||||
|
||||
/// Writes data from this context back to the requesting process/thread.
|
||||
Result WriteToOutgoingCommandBuffer();
|
||||
Result WriteToOutgoingCommandBuffer(Kernel::KThread& requesting_thread);
|
||||
|
||||
[[nodiscard]] u32_le GetHipcCommand() const {
|
||||
return command;
|
||||
@ -360,17 +359,8 @@ public:
|
||||
return *thread;
|
||||
}
|
||||
|
||||
[[nodiscard]] Core::Memory::Memory& GetMemory() const {
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Kernel::KScopedAutoObject<T> GetObjectFromHandle(u32 handle) {
|
||||
auto obj = client_handle_table->GetObjectForIpc(handle, thread);
|
||||
if (obj.IsNotNull()) {
|
||||
return obj->DynamicCast<T*>();
|
||||
}
|
||||
return nullptr;
|
||||
Kernel::KHandleTable& GetClientHandleTable() {
|
||||
return *client_handle_table;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::shared_ptr<SessionRequestManager> GetManager() const {
|
||||
@ -388,7 +378,7 @@ public:
|
||||
private:
|
||||
friend class IPC::ResponseBuilder;
|
||||
|
||||
void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming);
|
||||
void ParseCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf, bool incoming);
|
||||
|
||||
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
||||
Kernel::KServerSession* server_session{};
|
||||
|
@ -26,7 +26,7 @@ public:
|
||||
explicit IJitEnvironment(Core::System& system_, Kernel::KProcess& process_, CodeRange user_rx,
|
||||
CodeRange user_ro)
|
||||
: ServiceFramework{system_, "IJitEnvironment"}, process{&process_},
|
||||
context{process->GetMemory()} {
|
||||
context{system_.ApplicationMemory()} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IJitEnvironment::GenerateCode, "GenerateCode"},
|
||||
@ -188,7 +188,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
auto tmem{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(tmem_handle)};
|
||||
auto tmem{process->GetHandleTable().GetObject<Kernel::KTransferMemory>(tmem_handle)};
|
||||
if (tmem.IsNull()) {
|
||||
LOG_ERROR(Service_JIT, "attempted to load plugin with invalid transfer memory handle");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@ -356,7 +356,11 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle)};
|
||||
// Fetch using the handle table for the application process here,
|
||||
// since we are not multiprocess yet.
|
||||
const auto& handle_table{system.ApplicationProcess()->GetHandleTable()};
|
||||
|
||||
auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)};
|
||||
if (process.IsNull()) {
|
||||
LOG_ERROR(Service_JIT, "process is null for handle=0x{:08X}", process_handle);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@ -364,7 +368,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
auto rx_mem{ctx.GetObjectFromHandle<Kernel::KCodeMemory>(rx_mem_handle)};
|
||||
auto rx_mem{handle_table.GetObject<Kernel::KCodeMemory>(rx_mem_handle)};
|
||||
if (rx_mem.IsNull()) {
|
||||
LOG_ERROR(Service_JIT, "rx_mem is null for handle=0x{:08X}", rx_mem_handle);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@ -372,7 +376,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
auto ro_mem{ctx.GetObjectFromHandle<Kernel::KCodeMemory>(ro_mem_handle)};
|
||||
auto ro_mem{handle_table.GetObject<Kernel::KCodeMemory>(ro_mem_handle)};
|
||||
if (ro_mem.IsNull()) {
|
||||
LOG_ERROR(Service_JIT, "ro_mem is null for handle=0x{:08X}", ro_mem_handle);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
|
@ -651,9 +651,10 @@ private:
|
||||
void RegisterProcessHandle(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_LDR, "(called)");
|
||||
|
||||
auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0));
|
||||
auto process_h = ctx.GetClientHandleTable().GetObject(ctx.GetCopyHandle(0));
|
||||
auto client_pid = ctx.GetPID();
|
||||
auto result = interface.RegisterProcessHandle(client_pid, process.GetPointerUnsafe());
|
||||
auto result = interface.RegisterProcessHandle(client_pid,
|
||||
process_h->DynamicCast<Kernel::KProcess*>());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
@ -670,11 +671,12 @@ private:
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto params = rp.PopRaw<InputParameters>();
|
||||
auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0));
|
||||
auto process_h = ctx.GetClientHandleTable().GetObject(ctx.GetCopyHandle(0));
|
||||
|
||||
auto client_pid = ctx.GetPID();
|
||||
auto result = interface.RegisterProcessModuleInfo(
|
||||
client_pid, params.nrr_address, params.nrr_size, process.GetPointerUnsafe());
|
||||
auto result =
|
||||
interface.RegisterProcessModuleInfo(client_pid, params.nrr_address, params.nrr_size,
|
||||
process_h->DynamicCast<Kernel::KProcess*>());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
|
@ -203,7 +203,7 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
|
||||
// If emulation was shutdown, we are closing service threads, do not write the response back to
|
||||
// memory that may be shutting down as well.
|
||||
if (system.IsPoweredOn()) {
|
||||
ctx.WriteToOutgoingCommandBuffer();
|
||||
ctx.WriteToOutgoingCommandBuffer(ctx.GetThread());
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -730,6 +730,17 @@ struct Memory::Impl {
|
||||
GetInteger(vaddr), []() {}, []() {});
|
||||
}
|
||||
|
||||
void FixPageProtection(u64 vaddr) {
|
||||
vaddr = Common::AlignDown(vaddr, YUZU_PAGESIZE);
|
||||
|
||||
if (!AddressSpaceContains(*current_page_table, vaddr, 1)) [[unlikely]] {
|
||||
return;
|
||||
}
|
||||
|
||||
ProtectRegion(*current_page_table, vaddr, YUZU_PAGESIZE,
|
||||
Common::MemoryPermission::ReadWrite);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a particular data type out of memory at the given virtual address.
|
||||
*
|
||||
@ -1083,13 +1094,18 @@ bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) {
|
||||
rasterizer = true;
|
||||
});
|
||||
|
||||
const bool mapping_exists = mapped && ptr != nullptr;
|
||||
|
||||
#ifdef __linux__
|
||||
if (!rasterizer && mapped) {
|
||||
impl->buffer->DeferredMapSeparateHeap(GetInteger(vaddr));
|
||||
if (mapping_exists && !rasterizer) {
|
||||
if (!impl->buffer->DeferredMapSeparateHeap(GetInteger(vaddr))) {
|
||||
// GPU may have raced reprotecting this page, try to fix it.
|
||||
impl->FixPageProtection(GetInteger(vaddr));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return mapped && ptr != nullptr;
|
||||
return mapping_exists;
|
||||
}
|
||||
|
||||
bool Memory::InvalidateSeparateHeap(void* fault_address) {
|
||||
|
@ -74,11 +74,6 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
|
||||
case IR::Attribute::ClipDistance7: {
|
||||
const u32 base{static_cast<u32>(IR::Attribute::ClipDistance0)};
|
||||
const u32 index{static_cast<u32>(attr) - base};
|
||||
if (index >= ctx.profile.max_user_clip_distances) {
|
||||
LOG_WARNING(Shader, "Ignoring clip distance store {} >= {} supported", index,
|
||||
ctx.profile.max_user_clip_distances);
|
||||
return std::nullopt;
|
||||
}
|
||||
const Id clip_num{ctx.Const(index)};
|
||||
return OutputAccessChain(ctx, ctx.output_f32, ctx.clip_distances, clip_num);
|
||||
}
|
||||
|
@ -1532,8 +1532,7 @@ void EmitContext::DefineOutputs(const IR::Program& program) {
|
||||
if (stage == Stage::Fragment) {
|
||||
throw NotImplementedException("Storing ClipDistance in fragment stage");
|
||||
}
|
||||
const Id type{TypeArray(
|
||||
F32[1], Const(std::min(info.used_clip_distances, profile.max_user_clip_distances)))};
|
||||
const Id type{TypeArray(F32[1], Const(8U))};
|
||||
clip_distances = DefineOutput(*this, type, invocations, spv::BuiltIn::ClipDistance);
|
||||
}
|
||||
if (info.stores[IR::Attribute::Layer] &&
|
||||
|
@ -913,11 +913,7 @@ void GatherInfoFromHeader(Environment& env, Info& info) {
|
||||
}
|
||||
for (size_t index = 0; index < 8; ++index) {
|
||||
const u16 mask{header.vtg.omap_systemc.clip_distances};
|
||||
const bool used{((mask >> index) & 1) != 0};
|
||||
info.stores.Set(IR::Attribute::ClipDistance0 + index, used);
|
||||
if (used) {
|
||||
info.used_clip_distances = static_cast<u32>(index) + 1;
|
||||
}
|
||||
info.stores.Set(IR::Attribute::ClipDistance0 + index, ((mask >> index) & 1) != 0);
|
||||
}
|
||||
info.stores.Set(IR::Attribute::PrimitiveId,
|
||||
header.vtg.omap_systemb.primitive_array_id != 0);
|
||||
|
@ -87,8 +87,6 @@ struct Profile {
|
||||
bool has_broken_robust{};
|
||||
|
||||
u64 min_ssbo_alignment{};
|
||||
|
||||
u32 max_user_clip_distances{};
|
||||
};
|
||||
|
||||
} // namespace Shader
|
||||
|
@ -324,8 +324,6 @@ struct Info {
|
||||
bool requires_layer_emulation{};
|
||||
IR::Attribute emulated_layer{};
|
||||
|
||||
u32 used_clip_distances{};
|
||||
|
||||
boost::container::static_vector<ConstantBufferDescriptor, MAX_CBUFS>
|
||||
constant_buffer_descriptors;
|
||||
boost::container::static_vector<StorageBufferDescriptor, MAX_SSBOS> storage_buffers_descriptors;
|
||||
|
@ -327,13 +327,12 @@ public:
|
||||
explicit HLE_DrawIndirectByteCount(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
|
||||
|
||||
void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
|
||||
const bool force = maxwell3d.Rasterizer().HasDrawTransformFeedback();
|
||||
|
||||
auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0xFFFFU);
|
||||
if (!force && (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology))) {
|
||||
if (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology)) {
|
||||
Fallback(parameters);
|
||||
return;
|
||||
}
|
||||
|
||||
auto& params = maxwell3d.draw_manager->GetIndirectParams();
|
||||
params.is_byte_count = true;
|
||||
params.is_indexed = false;
|
||||
@ -504,8 +503,6 @@ public:
|
||||
maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(launch_dma)), 0x1011, true);
|
||||
maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(inline_data)),
|
||||
regs.transform_feedback.controls[0].stride, true);
|
||||
|
||||
maxwell3d.Rasterizer().RegisterTransformFeedback(regs.upload.dest.Address());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -173,13 +173,5 @@ public:
|
||||
virtual void BindChannel(Tegra::Control::ChannelState& channel) {}
|
||||
|
||||
virtual void ReleaseChannel(s32 channel_id) {}
|
||||
|
||||
/// Register the address as a Transform Feedback Object
|
||||
virtual void RegisterTransformFeedback(GPUVAddr tfb_object_addr) {}
|
||||
|
||||
/// Returns true when the rasterizer has Draw Transform Feedback capabilities
|
||||
virtual bool HasDrawTransformFeedback() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
} // namespace VideoCore
|
||||
|
@ -376,15 +376,4 @@ void BufferCacheRuntime::BindImageBuffer(Buffer& buffer, u32 offset, u32 size, P
|
||||
*image_handles++ = buffer.View(offset, size, format);
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::BindTransformFeedbackObject(GPUVAddr tfb_object_addr) {
|
||||
OGLTransformFeedback& tfb_object = tfb_objects[tfb_object_addr];
|
||||
tfb_object.Create();
|
||||
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfb_object.handle);
|
||||
}
|
||||
|
||||
GLuint BufferCacheRuntime::GetTransformFeedbackObject(GPUVAddr tfb_object_addr) {
|
||||
ASSERT(tfb_objects.contains(tfb_object_addr));
|
||||
return tfb_objects[tfb_object_addr].handle;
|
||||
}
|
||||
|
||||
} // namespace OpenGL
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
#include <array>
|
||||
#include <span>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/buffer_cache/buffer_cache_base.h"
|
||||
@ -122,9 +121,6 @@ public:
|
||||
void BindImageBuffer(Buffer& buffer, u32 offset, u32 size,
|
||||
VideoCore::Surface::PixelFormat format);
|
||||
|
||||
void BindTransformFeedbackObject(GPUVAddr tfb_object_addr);
|
||||
GLuint GetTransformFeedbackObject(GPUVAddr tfb_object_addr);
|
||||
|
||||
u64 GetDeviceMemoryUsage() const;
|
||||
|
||||
void BindFastUniformBuffer(size_t stage, u32 binding_index, u32 size) {
|
||||
@ -237,7 +233,6 @@ private:
|
||||
u32 index_buffer_offset = 0;
|
||||
|
||||
u64 device_access_memory;
|
||||
std::unordered_map<GPUVAddr, OGLTransformFeedback> tfb_objects;
|
||||
};
|
||||
|
||||
struct BufferCacheParams {
|
||||
|
@ -309,13 +309,6 @@ void RasterizerOpenGL::DrawIndirect() {
|
||||
const auto& params = maxwell3d->draw_manager->GetIndirectParams();
|
||||
buffer_cache.SetDrawIndirect(¶ms);
|
||||
PrepareDraw(params.is_indexed, [this, ¶ms](GLenum primitive_mode) {
|
||||
if (params.is_byte_count) {
|
||||
const GPUVAddr tfb_object_base_addr = params.indirect_start_address - 4U;
|
||||
const GLuint tfb_object =
|
||||
buffer_cache_runtime.GetTransformFeedbackObject(tfb_object_base_addr);
|
||||
glDrawTransformFeedback(primitive_mode, tfb_object);
|
||||
return;
|
||||
}
|
||||
const auto [buffer, offset] = buffer_cache.GetDrawIndirectBuffer();
|
||||
const GLvoid* const gl_offset =
|
||||
reinterpret_cast<const GLvoid*>(static_cast<uintptr_t>(offset));
|
||||
@ -1378,10 +1371,6 @@ void RasterizerOpenGL::ReleaseChannel(s32 channel_id) {
|
||||
query_cache.EraseChannel(channel_id);
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::RegisterTransformFeedback(GPUVAddr tfb_object_addr) {
|
||||
buffer_cache_runtime.BindTransformFeedbackObject(tfb_object_addr);
|
||||
}
|
||||
|
||||
AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_, TextureCache& texture_cache_)
|
||||
: buffer_cache{buffer_cache_}, texture_cache{texture_cache_} {}
|
||||
|
||||
|
@ -139,12 +139,6 @@ public:
|
||||
|
||||
void ReleaseChannel(s32 channel_id) override;
|
||||
|
||||
void RegisterTransformFeedback(GPUVAddr tfb_object_addr) override;
|
||||
|
||||
bool HasDrawTransformFeedback() override {
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr size_t MAX_TEXTURES = 192;
|
||||
static constexpr size_t MAX_IMAGES = 48;
|
||||
|
@ -207,21 +207,4 @@ void OGLQuery::Release() {
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
void OGLTransformFeedback::Create() {
|
||||
if (handle != 0)
|
||||
return;
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
|
||||
glCreateTransformFeedbacks(1, &handle);
|
||||
}
|
||||
|
||||
void OGLTransformFeedback::Release() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
|
||||
glDeleteTransformFeedbacks(1, &handle);
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
} // namespace OpenGL
|
||||
|
@ -323,31 +323,4 @@ public:
|
||||
GLuint handle = 0;
|
||||
};
|
||||
|
||||
class OGLTransformFeedback final {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(OGLTransformFeedback);
|
||||
|
||||
OGLTransformFeedback() = default;
|
||||
|
||||
OGLTransformFeedback(OGLTransformFeedback&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
||||
|
||||
~OGLTransformFeedback() {
|
||||
Release();
|
||||
}
|
||||
|
||||
OGLTransformFeedback& operator=(OGLTransformFeedback&& o) noexcept {
|
||||
Release();
|
||||
handle = std::exchange(o.handle, 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Creates a new internal OpenGL resource and stores the handle
|
||||
void Create();
|
||||
|
||||
/// Deletes the internal OpenGL resource
|
||||
void Release();
|
||||
|
||||
GLuint handle = 0;
|
||||
};
|
||||
|
||||
} // namespace OpenGL
|
||||
|
@ -233,7 +233,6 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo
|
||||
.ignore_nan_fp_comparisons = true,
|
||||
.gl_max_compute_smem_size = device.GetMaxComputeSharedMemorySize(),
|
||||
.min_ssbo_alignment = device.GetShaderStorageBufferAlignment(),
|
||||
.max_user_clip_distances = 8,
|
||||
},
|
||||
host_info{
|
||||
.support_float64 = true,
|
||||
|
@ -374,7 +374,6 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
|
||||
.has_broken_robust =
|
||||
device.IsNvidia() && device.GetNvidiaArch() <= NvidiaArchitecture::Arch_Pascal,
|
||||
.min_ssbo_alignment = device.GetStorageBufferAlignment(),
|
||||
.max_user_clip_distances = device.GetMaxUserClipDistances(),
|
||||
};
|
||||
|
||||
host_info = Shader::HostTranslateInfo{
|
||||
|
@ -60,72 +60,66 @@ u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format) {
|
||||
}
|
||||
|
||||
template <auto decompress, PixelFormat pixel_format>
|
||||
void DecompressBlocks(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy,
|
||||
void DecompressBlocks(std::span<const u8> input, std::span<u8> output, Extent3D extent,
|
||||
bool is_signed = false) {
|
||||
const u32 out_bpp = ConvertedBytesPerBlock(pixel_format);
|
||||
const u32 block_size = BlockSize(pixel_format);
|
||||
const u32 width = copy.image_extent.width;
|
||||
const u32 height = copy.image_extent.height * copy.image_subresource.num_layers;
|
||||
const u32 depth = copy.image_extent.depth;
|
||||
const u32 block_width = std::min(width, BLOCK_SIZE);
|
||||
const u32 block_height = std::min(height, BLOCK_SIZE);
|
||||
const u32 pitch = width * out_bpp;
|
||||
const u32 block_width = std::min(extent.width, BLOCK_SIZE);
|
||||
const u32 block_height = std::min(extent.height, BLOCK_SIZE);
|
||||
const u32 pitch = extent.width * out_bpp;
|
||||
size_t input_offset = 0;
|
||||
size_t output_offset = 0;
|
||||
for (u32 slice = 0; slice < depth; ++slice) {
|
||||
for (u32 y = 0; y < height; y += block_height) {
|
||||
size_t src_offset = input_offset;
|
||||
size_t dst_offset = output_offset;
|
||||
for (u32 x = 0; x < width; x += block_width) {
|
||||
const u8* src = input.data() + src_offset;
|
||||
u8* const dst = output.data() + dst_offset;
|
||||
for (u32 slice = 0; slice < extent.depth; ++slice) {
|
||||
for (u32 y = 0; y < extent.height; y += block_height) {
|
||||
size_t row_offset = 0;
|
||||
for (u32 x = 0; x < extent.width;
|
||||
x += block_width, row_offset += block_width * out_bpp) {
|
||||
const u8* src = input.data() + input_offset;
|
||||
u8* const dst = output.data() + output_offset + row_offset;
|
||||
if constexpr (IsSigned(pixel_format)) {
|
||||
decompress(src, dst, x, y, width, height, is_signed);
|
||||
decompress(src, dst, x, y, extent.width, extent.height, is_signed);
|
||||
} else {
|
||||
decompress(src, dst, x, y, width, height);
|
||||
decompress(src, dst, x, y, extent.width, extent.height);
|
||||
}
|
||||
src_offset += block_size;
|
||||
dst_offset += block_width * out_bpp;
|
||||
input_offset += BlockSize(pixel_format);
|
||||
}
|
||||
input_offset += copy.buffer_row_length * block_size / block_width;
|
||||
output_offset += block_height * pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DecompressBCn(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy,
|
||||
void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent,
|
||||
VideoCore::Surface::PixelFormat pixel_format) {
|
||||
switch (pixel_format) {
|
||||
case PixelFormat::BC1_RGBA_UNORM:
|
||||
case PixelFormat::BC1_RGBA_SRGB:
|
||||
DecompressBlocks<bcn::DecodeBc1, PixelFormat::BC1_RGBA_UNORM>(input, output, copy);
|
||||
DecompressBlocks<bcn::DecodeBc1, PixelFormat::BC1_RGBA_UNORM>(input, output, extent);
|
||||
break;
|
||||
case PixelFormat::BC2_UNORM:
|
||||
case PixelFormat::BC2_SRGB:
|
||||
DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, copy);
|
||||
DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, extent);
|
||||
break;
|
||||
case PixelFormat::BC3_UNORM:
|
||||
case PixelFormat::BC3_SRGB:
|
||||
DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, copy);
|
||||
DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, extent);
|
||||
break;
|
||||
case PixelFormat::BC4_SNORM:
|
||||
case PixelFormat::BC4_UNORM:
|
||||
DecompressBlocks<bcn::DecodeBc4, PixelFormat::BC4_UNORM>(
|
||||
input, output, copy, pixel_format == PixelFormat::BC4_SNORM);
|
||||
input, output, extent, pixel_format == PixelFormat::BC4_SNORM);
|
||||
break;
|
||||
case PixelFormat::BC5_SNORM:
|
||||
case PixelFormat::BC5_UNORM:
|
||||
DecompressBlocks<bcn::DecodeBc5, PixelFormat::BC5_UNORM>(
|
||||
input, output, copy, pixel_format == PixelFormat::BC5_SNORM);
|
||||
input, output, extent, pixel_format == PixelFormat::BC5_SNORM);
|
||||
break;
|
||||
case PixelFormat::BC6H_SFLOAT:
|
||||
case PixelFormat::BC6H_UFLOAT:
|
||||
DecompressBlocks<bcn::DecodeBc6, PixelFormat::BC6H_UFLOAT>(
|
||||
input, output, copy, pixel_format == PixelFormat::BC6H_SFLOAT);
|
||||
input, output, extent, pixel_format == PixelFormat::BC6H_SFLOAT);
|
||||
break;
|
||||
case PixelFormat::BC7_SRGB:
|
||||
case PixelFormat::BC7_UNORM:
|
||||
DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, copy);
|
||||
DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, extent);
|
||||
break;
|
||||
default:
|
||||
LOG_WARNING(HW_GPU, "Unimplemented BCn decompression {}", pixel_format);
|
||||
|
@ -13,7 +13,7 @@ namespace VideoCommon {
|
||||
|
||||
[[nodiscard]] u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format);
|
||||
|
||||
void DecompressBCn(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy,
|
||||
void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent,
|
||||
VideoCore::Surface::PixelFormat pixel_format);
|
||||
|
||||
} // namespace VideoCommon
|
||||
|
@ -837,7 +837,6 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
|
||||
std::span<u8> output) {
|
||||
const size_t guest_size_bytes = input.size_bytes();
|
||||
const u32 bpp_log2 = BytesPerBlockLog2(info.format);
|
||||
const Extent2D tile_size = DefaultBlockSize(info.format);
|
||||
const Extent3D size = info.size;
|
||||
|
||||
if (info.type == ImageType::Linear) {
|
||||
@ -848,7 +847,7 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
|
||||
return {{
|
||||
.buffer_offset = 0,
|
||||
.buffer_size = guest_size_bytes,
|
||||
.buffer_row_length = info.pitch * tile_size.width >> bpp_log2,
|
||||
.buffer_row_length = info.pitch >> bpp_log2,
|
||||
.buffer_image_height = size.height,
|
||||
.image_subresource =
|
||||
{
|
||||
@ -863,6 +862,7 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
|
||||
const LevelInfo level_info = MakeLevelInfo(info);
|
||||
const s32 num_layers = info.resources.layers;
|
||||
const s32 num_levels = info.resources.levels;
|
||||
const Extent2D tile_size = DefaultBlockSize(info.format);
|
||||
const std::array level_sizes = CalculateLevelSizes(level_info, num_levels);
|
||||
const Extent2D gob = GobSize(bpp_log2, info.block.height, info.tile_width_spacing);
|
||||
const u32 layer_size = CalculateLevelBytes(level_sizes, num_levels);
|
||||
@ -926,6 +926,8 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
|
||||
|
||||
const auto input_offset = input.subspan(copy.buffer_offset);
|
||||
copy.buffer_offset = output_offset;
|
||||
copy.buffer_row_length = mip_size.width;
|
||||
copy.buffer_image_height = mip_size.height;
|
||||
|
||||
const auto recompression_setting = Settings::values.astc_recompression.GetValue();
|
||||
const bool astc = IsPixelFormatASTC(info.format);
|
||||
@ -970,14 +972,16 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
|
||||
bpp_div;
|
||||
output_offset += static_cast<u32>(copy.buffer_size);
|
||||
} else {
|
||||
DecompressBCn(input_offset, output.subspan(output_offset), copy, info.format);
|
||||
const Extent3D image_extent{
|
||||
.width = copy.image_extent.width,
|
||||
.height = copy.image_extent.height * copy.image_subresource.num_layers,
|
||||
.depth = copy.image_extent.depth,
|
||||
};
|
||||
DecompressBCn(input_offset, output.subspan(output_offset), image_extent, info.format);
|
||||
output_offset += copy.image_extent.width * copy.image_extent.height *
|
||||
copy.image_subresource.num_layers *
|
||||
ConvertedBytesPerBlock(info.format);
|
||||
}
|
||||
|
||||
copy.buffer_row_length = mip_size.width;
|
||||
copy.buffer_image_height = mip_size.height;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -665,10 +665,6 @@ public:
|
||||
return properties.properties.limits.maxViewports;
|
||||
}
|
||||
|
||||
u32 GetMaxUserClipDistances() const {
|
||||
return properties.properties.limits.maxClipDistances;
|
||||
}
|
||||
|
||||
bool SupportsConditionalBarriers() const {
|
||||
return supports_conditional_barriers;
|
||||
}
|
||||
|
@ -168,6 +168,14 @@ class GMainWindow : public QMainWindow {
|
||||
/// Max number of recently loaded items to keep track of
|
||||
static const int max_recent_files_item = 10;
|
||||
|
||||
// TODO: Make use of this!
|
||||
enum {
|
||||
UI_IDLE,
|
||||
UI_EMU_BOOTING,
|
||||
UI_EMU_RUNNING,
|
||||
UI_EMU_STOPPING,
|
||||
};
|
||||
|
||||
enum {
|
||||
CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES,
|
||||
CREATE_SHORTCUT_MSGBOX_SUCCESS,
|
||||
|
Reference in New Issue
Block a user