early-access version 4084

This commit is contained in:
pineappleEA 2024-01-22 23:12:09 +01:00
parent 9b38babf6f
commit 9ee9c111ff
14 changed files with 167 additions and 36 deletions

View file

@ -1,7 +1,7 @@
yuzu emulator early access yuzu emulator early access
============= =============
This is the source code for early-access 4083. This is the source code for early-access 4084.
## Legal Notice ## Legal Notice

View file

@ -106,6 +106,7 @@ add_library(common STATIC
precompiled_headers.h precompiled_headers.h
quaternion.h quaternion.h
range_map.h range_map.h
range_mutex.h
reader_writer_queue.h reader_writer_queue.h
ring_buffer.h ring_buffer.h
${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp ${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp

93
src/common/range_mutex.h Executable file
View file

@ -0,0 +1,93 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <condition_variable>
#include <mutex>
#include "common/intrusive_list.h"
namespace Common {
class ScopedRangeLock;
class RangeMutex {
public:
explicit RangeMutex() = default;
~RangeMutex() = default;
private:
friend class ScopedRangeLock;
void Lock(ScopedRangeLock& l);
void Unlock(ScopedRangeLock& l);
bool HasIntersectionLocked(ScopedRangeLock& l);
private:
std::mutex m_mutex;
std::condition_variable m_cv;
using LockList = Common::IntrusiveListBaseTraits<ScopedRangeLock>::ListType;
LockList m_list;
};
class ScopedRangeLock : public Common::IntrusiveListBaseNode<ScopedRangeLock> {
public:
explicit ScopedRangeLock(RangeMutex& mutex, u64 address, u64 size)
: m_mutex(mutex), m_address(address), m_size(size) {
if (m_size > 0) {
m_mutex.Lock(*this);
}
}
~ScopedRangeLock() {
if (m_size > 0) {
m_mutex.Unlock(*this);
}
}
u64 GetAddress() const {
return m_address;
}
u64 GetSize() const {
return m_size;
}
private:
RangeMutex& m_mutex;
const u64 m_address{};
const u64 m_size{};
};
inline void RangeMutex::Lock(ScopedRangeLock& l) {
std::unique_lock lk{m_mutex};
m_cv.wait(lk, [&] { return !HasIntersectionLocked(l); });
m_list.push_back(l);
}
inline void RangeMutex::Unlock(ScopedRangeLock& l) {
{
std::scoped_lock lk{m_mutex};
m_list.erase(m_list.iterator_to(l));
}
m_cv.notify_all();
}
inline bool RangeMutex::HasIntersectionLocked(ScopedRangeLock& l) {
const auto cur_begin = l.GetAddress();
const auto cur_last = l.GetAddress() + l.GetSize() - 1;
for (const auto& other : m_list) {
const auto other_begin = other.GetAddress();
const auto other_last = other.GetAddress() + other.GetSize() - 1;
if (cur_begin <= other_last && other_begin <= cur_last) {
return true;
}
}
return false;
}
} // namespace Common

View file

@ -420,8 +420,15 @@ struct Values {
SwitchableSetting<s64> custom_rtc{ SwitchableSetting<s64> custom_rtc{
linkage, 0, "custom_rtc", Category::System, Specialization::Time, linkage, 0, "custom_rtc", Category::System, Specialization::Time,
false, true, &custom_rtc_enabled}; false, true, &custom_rtc_enabled};
SwitchableSetting<s64, false> custom_rtc_offset{ SwitchableSetting<s64, true> custom_rtc_offset{linkage,
linkage, 0, "custom_rtc_offset", Category::System, Specialization::Countable, true, true}; 0,
std::numeric_limits<int>::min(),
std::numeric_limits<int>::max(),
"custom_rtc_offset",
Category::System,
Specialization::Countable,
true,
true};
SwitchableSetting<bool> rng_seed_enabled{ SwitchableSetting<bool> rng_seed_enabled{
linkage, false, "rng_seed_enabled", Category::System, Specialization::Paired, true, true}; linkage, false, "rng_seed_enabled", Category::System, Specialization::Paired, true, true};
SwitchableSetting<u32> rng_seed{ SwitchableSetting<u32> rng_seed{

View file

@ -10,6 +10,7 @@
#include <mutex> #include <mutex>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/range_mutex.h"
#include "common/scratch_buffer.h" #include "common/scratch_buffer.h"
#include "common/virtual_buffer.h" #include "common/virtual_buffer.h"
@ -204,7 +205,7 @@ private:
(1ULL << (device_virtual_bits - page_bits)) / subentries; (1ULL << (device_virtual_bits - page_bits)) / subentries;
using CachedPages = std::array<CounterEntry, num_counter_entries>; using CachedPages = std::array<CounterEntry, num_counter_entries>;
std::unique_ptr<CachedPages> cached_pages; std::unique_ptr<CachedPages> cached_pages;
std::mutex counter_guard; Common::RangeMutex counter_guard;
std::mutex mapping_guard; std::mutex mapping_guard;
}; };

View file

@ -31,9 +31,8 @@ public:
buffer.resize(0); buffer.resize(0);
size_t index = 0; size_t index = 0;
const auto add_value = [&](u32 value) { const auto add_value = [&](u32 value) {
buffer[index] = value; buffer.resize(index + 1);
index++; buffer[index++] = value;
buffer.resize(index);
}; };
u32 iter_entry = start_entry; u32 iter_entry = start_entry;
@ -509,12 +508,7 @@ void DeviceMemoryManager<Traits>::UnregisterProcess(Asid asid) {
template <typename Traits> template <typename Traits>
void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) { void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) {
std::unique_lock<std::mutex> lk(counter_guard, std::defer_lock); Common::ScopedRangeLock lk(counter_guard, addr, size);
const auto Lock = [&] {
if (!lk) {
lk.lock();
}
};
u64 uncache_begin = 0; u64 uncache_begin = 0;
u64 cache_begin = 0; u64 cache_begin = 0;
u64 uncache_bytes = 0; u64 uncache_bytes = 0;
@ -549,7 +543,6 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
} }
uncache_bytes += Memory::YUZU_PAGESIZE; uncache_bytes += Memory::YUZU_PAGESIZE;
} else if (uncache_bytes > 0) { } else if (uncache_bytes > 0) {
Lock();
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
uncache_bytes, false); uncache_bytes, false);
uncache_bytes = 0; uncache_bytes = 0;
@ -560,7 +553,6 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
} }
cache_bytes += Memory::YUZU_PAGESIZE; cache_bytes += Memory::YUZU_PAGESIZE;
} else if (cache_bytes > 0) { } else if (cache_bytes > 0) {
Lock();
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes,
true); true);
cache_bytes = 0; cache_bytes = 0;
@ -568,12 +560,10 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
vpage++; vpage++;
} }
if (uncache_bytes > 0) { if (uncache_bytes > 0) {
Lock();
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes, MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes,
false); false);
} }
if (cache_bytes > 0) { if (cache_bytes > 0) {
Lock();
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes,
true); true);
} }

View file

@ -67,25 +67,29 @@ constexpr std::array<SystemArchiveDescriptor, SYSTEM_ARCHIVE_COUNT> SYSTEM_ARCHI
}}; }};
VirtualFile SynthesizeSystemArchive(const u64 title_id) { VirtualFile SynthesizeSystemArchive(const u64 title_id) {
if (title_id < SYSTEM_ARCHIVES.front().title_id || title_id > SYSTEM_ARCHIVES.back().title_id) if (title_id < SYSTEM_ARCHIVES.front().title_id || title_id > SYSTEM_ARCHIVES.back().title_id) {
return nullptr; return nullptr;
}
const auto& desc = SYSTEM_ARCHIVES[title_id - SYSTEM_ARCHIVE_BASE_TITLE_ID]; const auto& desc = SYSTEM_ARCHIVES[title_id - SYSTEM_ARCHIVE_BASE_TITLE_ID];
LOG_INFO(Service_FS, "Synthesizing system archive '{}' (0x{:016X}).", desc.name, desc.title_id); LOG_INFO(Service_FS, "Synthesizing system archive '{}' (0x{:016X}).", desc.name, desc.title_id);
if (desc.supplier == nullptr) if (desc.supplier == nullptr) {
return nullptr; return nullptr;
}
const auto dir = desc.supplier(); const auto dir = desc.supplier();
if (dir == nullptr) if (dir == nullptr) {
return nullptr; return nullptr;
}
const auto romfs = CreateRomFS(dir); const auto romfs = CreateRomFS(dir);
if (romfs == nullptr) if (romfs == nullptr) {
return nullptr; return nullptr;
}
LOG_INFO(Service_FS, " - System archive generation successful!"); LOG_INFO(Service_FS, " - System archive generation successful!");
return romfs; return romfs;

View file

@ -89,7 +89,8 @@ Service::PSC::Time::LocationName GetTimeZoneString(Service::PSC::Time::LocationN
std::min(configured_name.name.size(), configured_zone.size())); std::min(configured_name.name.size(), configured_zone.size()));
} }
ASSERT_MSG(IsTimeZoneBinaryValid(configured_name), "Invalid time zone!"); ASSERT_MSG(IsTimeZoneBinaryValid(configured_name), "Invalid time zone {}!",
configured_name.name.data());
return configured_name; return configured_name;
} }

View file

@ -61,6 +61,16 @@ Result MountTimeZoneBinary(Core::System& system) {
g_time_zone_binary_romfs = FileSys::ExtractRomFS(nca->GetRomFS()); g_time_zone_binary_romfs = FileSys::ExtractRomFS(nca->GetRomFS());
} }
if (g_time_zone_binary_romfs) {
// Validate that the romfs is readable, using invalid firmware keys can cause this to get
// set but the files to be garbage. In that case, we want to hit the next path and
// synthesise them instead.
Service::PSC::Time::LocationName name{"Etc/GMT"};
if (!IsTimeZoneBinaryValid(name)) {
ResetTimeZoneBinary();
}
}
if (!g_time_zone_binary_romfs) { if (!g_time_zone_binary_romfs) {
g_time_zone_binary_romfs = FileSys::ExtractRomFS( g_time_zone_binary_romfs = FileSys::ExtractRomFS(
FileSys::SystemArchive::SynthesizeSystemArchive(TimeZoneBinaryId)); FileSys::SystemArchive::SynthesizeSystemArchive(TimeZoneBinaryId));
@ -102,6 +112,7 @@ bool IsTimeZoneBinaryValid(Service::PSC::Time::LocationName& name) {
auto vfs_file{g_time_zone_binary_romfs->GetFileRelative(path)}; auto vfs_file{g_time_zone_binary_romfs->GetFileRelative(path)};
if (!vfs_file) { if (!vfs_file) {
LOG_INFO(Service_Time, "Could not find timezone file {}", path);
return false; return false;
} }
return vfs_file->GetSize() != 0; return vfs_file->GetSize() != 0;

View file

@ -1093,6 +1093,20 @@ bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) {
[&] { rasterizer = true; }); [&] { rasterizer = true; });
if (rasterizer) { if (rasterizer) {
impl->InvalidateGPUMemory(ptr, size); impl->InvalidateGPUMemory(ptr, size);
const auto type = impl->current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Type();
if (type == Common::PageType::RasterizerCachedMemory) {
// Check if device mapped. If not, this bugged and we can unmark.
DAddr addr{};
Common::ScratchBuffer<u32> buffer;
impl->gpu_device_memory->ApplyOpOnPointer(ptr, buffer,
[&](DAddr address) { addr = address; });
if (addr == 0) {
LOG_ERROR(HW_Memory, "Fixing unmapped cached region {:#x}", GetInteger(vaddr));
impl->RasterizerMarkRegionCached(GetInteger(vaddr), size, false);
}
}
} }
#ifdef __linux__ #ifdef __linux__

View file

@ -1546,7 +1546,10 @@ void BufferCache<P>::ImmediateUploadMemory([[maybe_unused]] Buffer& buffer,
std::span<const u8> upload_span; std::span<const u8> upload_span;
const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset; const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
if (IsRangeGranular(device_addr, copy.size)) { if (IsRangeGranular(device_addr, copy.size)) {
upload_span = std::span(device_memory.GetPointer<u8>(device_addr), copy.size); auto* const ptr = device_memory.GetPointer<u8>(device_addr);
if (ptr != nullptr) {
upload_span = std::span(ptr, copy.size);
}
} else { } else {
if (immediate_buffer.empty()) { if (immediate_buffer.empty()) {
immediate_buffer = ImmediateBuffer(largest_copy); immediate_buffer = ImmediateBuffer(largest_copy);

View file

@ -243,10 +243,12 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
const u64 size_in_bytes{Tegra::Texture::CalculateSize( const u64 size_in_bytes{Tegra::Texture::CalculateSize(
true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)}; true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)};
const u8* const host_ptr{device_memory.GetPointer<u8>(framebuffer_addr)}; const u8* const host_ptr{device_memory.GetPointer<u8>(framebuffer_addr)};
if (host_ptr != nullptr) {
const std::span<const u8> input_data(host_ptr, size_in_bytes); const std::span<const u8> input_data(host_ptr, size_in_bytes);
Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel, Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel,
framebuffer.width, framebuffer.height, 1, block_height_log2, framebuffer.width, framebuffer.height, 1,
0); block_height_log2, 0);
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride)); glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride));

View file

@ -230,9 +230,11 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
const u64 tiled_size{Tegra::Texture::CalculateSize(true, bytes_per_pixel, const u64 tiled_size{Tegra::Texture::CalculateSize(true, bytes_per_pixel,
framebuffer.stride, framebuffer.height, framebuffer.stride, framebuffer.height,
1, block_height_log2, 0)}; 1, block_height_log2, 0)};
if (host_ptr != nullptr) {
Tegra::Texture::UnswizzleTexture( Tegra::Texture::UnswizzleTexture(
mapped_span.subspan(image_offset, linear_size), std::span(host_ptr, tiled_size), mapped_span.subspan(image_offset, linear_size), std::span(host_ptr, tiled_size),
bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0); bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0);
}
const VkBufferImageCopy copy{ const VkBufferImageCopy copy{
.bufferOffset = image_offset, .bufferOffset = image_offset,

View file

@ -1064,8 +1064,6 @@ public:
} }
}); });
} }
auto* ptr = device_memory.GetPointer<u8>(new_query->dependant_address);
ASSERT(ptr != nullptr);
new_query->dependant_manage = must_manage_dependance; new_query->dependant_manage = must_manage_dependance;
pending_flush_queries.push_back(index); pending_flush_queries.push_back(index);
@ -1104,10 +1102,12 @@ public:
tfb_streamer.Free(query->dependant_index); tfb_streamer.Free(query->dependant_index);
} else { } else {
u8* pointer = device_memory.GetPointer<u8>(query->dependant_address); u8* pointer = device_memory.GetPointer<u8>(query->dependant_address);
if (pointer != nullptr) {
u32 result; u32 result;
std::memcpy(&result, pointer, sizeof(u32)); std::memcpy(&result, pointer, sizeof(u32));
num_vertices = static_cast<u64>(result) / query->stride; num_vertices = static_cast<u64>(result) / query->stride;
} }
}
query->value = [&]() -> u64 { query->value = [&]() -> u64 {
switch (query->topology) { switch (query->topology) {
case Maxwell3D::Regs::PrimitiveTopology::Points: case Maxwell3D::Regs::PrimitiveTopology::Points:
@ -1360,7 +1360,9 @@ bool QueryCacheRuntime::HostConditionalRenderingCompareValues(VideoCommon::Looku
const auto check_value = [&](DAddr address) { const auto check_value = [&](DAddr address) {
u8* ptr = impl->device_memory.GetPointer<u8>(address); u8* ptr = impl->device_memory.GetPointer<u8>(address);
u64 value{}; u64 value{};
if (ptr != nullptr) {
std::memcpy(&value, ptr, sizeof(value)); std::memcpy(&value, ptr, sizeof(value));
}
return value == 0; return value == 0;
}; };
std::array<VideoCommon::LookupData*, 2> objects{&object_1, &object_2}; std::array<VideoCommon::LookupData*, 2> objects{&object_1, &object_2};