summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt8
-rw-r--r--appveyor.yml10
-rw-r--r--src/audio_core/audio_renderer.cpp4
-rw-r--r--src/audio_core/audio_renderer.h1
-rw-r--r--src/audio_core/stream.cpp5
-rw-r--r--src/audio_core/stream.h3
-rw-r--r--src/audio_core/time_stretch.cpp2
-rw-r--r--src/common/logging/backend.cpp1
-rw-r--r--src/common/logging/log.h1
-rw-r--r--src/common/thread.h8
-rw-r--r--src/core/hle/kernel/process.cpp87
-rw-r--r--src/core/hle/kernel/process.h55
-rw-r--r--src/core/hle/kernel/svc.cpp46
-rw-r--r--src/core/hle/kernel/thread.cpp58
-rw-r--r--src/core/hle/kernel/thread.h13
-rw-r--r--src/core/hle/service/audio/audren_u.cpp9
-rw-r--r--src/core/hle/service/fatal/fatal.cpp141
-rw-r--r--src/core/hle/service/fatal/fatal.h1
-rw-r--r--src/core/hle/service/fatal/fatal_u.cpp2
-rw-r--r--src/core/hle/service/hid/irs.cpp158
-rw-r--r--src/core/hle/service/hid/irs.h27
-rw-r--r--src/core/hle/service/ssl/ssl.cpp6
-rw-r--r--src/video_core/engines/shader_bytecode.h27
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp7
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h21
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_state.h4
-rw-r--r--src/video_core/utils.h22
-rw-r--r--src/yuzu/game_list_p.h2
-rw-r--r--src/yuzu_cmd/config.cpp2
31 files changed, 574 insertions, 160 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 30642edd7..25c5cb112 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -440,8 +440,12 @@ enable_testing()
add_subdirectory(externals)
add_subdirectory(src)
-# Set yuzu project as default StartUp Project in Visual Studio
-set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT yuzu)
+# Set yuzu project or yuzu-cmd project as default StartUp Project in Visual Studio depending on whether QT is enabled or not
+if(ENABLE_QT)
+ set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT yuzu)
+else()
+ set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT yuzu-cmd)
+endif()
# Installation instructions
diff --git a/appveyor.yml b/appveyor.yml
index 2a003ca5e..d475816ab 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -163,3 +163,13 @@ artifacts:
name: build
type: zip
+deploy:
+ provider: GitHub
+ release: $(appveyor_repo_tag_name)
+ auth_token:
+ secure: QqePPnXbkzmXct5c8hZ2X5AbsthbI6cS1Sr+VBzcD8oUOIjfWJJKXVAQGUbQAbb0
+ artifact: update,build
+ draft: false
+ prerelease: false
+ on:
+ appveyor_repo_tag: true
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index 83b75e61f..521b19ff7 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -79,6 +79,10 @@ u32 AudioRenderer::GetMixBufferCount() const {
return worker_params.mix_buffer_count;
}
+u32 AudioRenderer::GetState() const {
+ return stream->GetState();
+}
+
std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params) {
// Copy UpdateDataHeader struct
UpdateDataHeader config{};
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index 2c4f5ab75..be923ee65 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -170,6 +170,7 @@ public:
u32 GetSampleRate() const;
u32 GetSampleCount() const;
u32 GetMixBufferCount() const;
+ u32 GetState() const;
private:
class VoiceState;
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index 449db2416..ee4aa98af 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -49,9 +49,14 @@ void Stream::Play() {
}
void Stream::Stop() {
+ state = State::Stopped;
ASSERT_MSG(false, "Unimplemented");
}
+u32 Stream::GetState() const {
+ return static_cast<u32>(state);
+}
+
s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const {
const std::size_t num_samples{buffer.GetSamples().size() / GetNumChannels()};
return CoreTiming::usToCycles((static_cast<u64>(num_samples) * 1000000) / sample_rate);
diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h
index 27db1112f..43eca74e1 100644
--- a/src/audio_core/stream.h
+++ b/src/audio_core/stream.h
@@ -72,6 +72,9 @@ public:
/// Gets the number of channels
u32 GetNumChannels() const;
+ /// Get the state
+ u32 GetState() const;
+
private:
/// Current state of the stream
enum class State {
diff --git a/src/audio_core/time_stretch.cpp b/src/audio_core/time_stretch.cpp
index fc14151da..d72d67994 100644
--- a/src/audio_core/time_stretch.cpp
+++ b/src/audio_core/time_stretch.cpp
@@ -59,7 +59,7 @@ std::size_t TimeStretcher::Process(const s16* in, std::size_t num_in, s16* out,
m_stretch_ratio = std::max(m_stretch_ratio, 0.05);
m_sound_touch.setTempo(m_stretch_ratio);
- LOG_DEBUG(Audio, "{:5}/{:5} ratio:{:0.6f} backlog:{:0.6f}", num_in, num_out, m_stretch_ratio,
+ LOG_TRACE(Audio, "{:5}/{:5} ratio:{:0.6f} backlog:{:0.6f}", num_in, num_out, m_stretch_ratio,
backlog_fullness);
m_sound_touch.putSamples(in, static_cast<u32>(num_in));
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index efd776db6..9f5918851 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -183,6 +183,7 @@ void FileBackend::Write(const Entry& entry) {
SUB(Service, FS) \
SUB(Service, GRC) \
SUB(Service, HID) \
+ SUB(Service, IRS) \
SUB(Service, LBL) \
SUB(Service, LDN) \
SUB(Service, LDR) \
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index 4d577524f..abbd056ee 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -70,6 +70,7 @@ enum class Class : ClassType {
Service_FS, ///< The FS (Filesystem) service
Service_GRC, ///< The game recording service
Service_HID, ///< The HID (Human interface device) service
+ Service_IRS, ///< The IRS service
Service_LBL, ///< The LBL (LCD backlight) service
Service_LDN, ///< The LDN (Local domain network) service
Service_LDR, ///< The loader service
diff --git a/src/common/thread.h b/src/common/thread.h
index 12a1c095c..6cbdb96a3 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -87,14 +87,6 @@ private:
void SleepCurrentThread(int ms);
void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms
-
-// Use this function during a spin-wait to make the current thread
-// relax while another thread is working. This may be more efficient
-// than using events because event functions use kernel calls.
-inline void YieldCPU() {
- std::this_thread::yield();
-}
-
void SetCurrentThreadName(const char* name);
} // namespace Common
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 914bbe0a1..121f741fd 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -7,10 +7,12 @@
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/logging/log.h"
+#include "core/core.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
+#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/memory.h"
@@ -128,6 +130,91 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, *this);
}
+void Process::PrepareForTermination() {
+ status = ProcessStatus::Exited;
+
+ const auto stop_threads = [this](const std::vector<SharedPtr<Thread>>& thread_list) {
+ for (auto& thread : thread_list) {
+ if (thread->owner_process != this)
+ continue;
+
+ if (thread == GetCurrentThread())
+ continue;
+
+ // TODO(Subv): When are the other running/ready threads terminated?
+ ASSERT_MSG(thread->status == ThreadStatus::WaitSynchAny ||
+ thread->status == ThreadStatus::WaitSynchAll,
+ "Exiting processes with non-waiting threads is currently unimplemented");
+
+ thread->Stop();
+ }
+ };
+
+ auto& system = Core::System::GetInstance();
+ stop_threads(system.Scheduler(0)->GetThreadList());
+ stop_threads(system.Scheduler(1)->GetThreadList());
+ stop_threads(system.Scheduler(2)->GetThreadList());
+ stop_threads(system.Scheduler(3)->GetThreadList());
+}
+
+/**
+ * Finds a free location for the TLS section of a thread.
+ * @param tls_slots The TLS page array of the thread's owner process.
+ * Returns a tuple of (page, slot, alloc_needed) where:
+ * page: The index of the first allocated TLS page that has free slots.
+ * slot: The index of the first free slot in the indicated page.
+ * alloc_needed: Whether there's a need to allocate a new TLS page (All pages are full).
+ */
+static std::tuple<std::size_t, std::size_t, bool> FindFreeThreadLocalSlot(
+ const std::vector<std::bitset<8>>& tls_slots) {
+ // Iterate over all the allocated pages, and try to find one where not all slots are used.
+ for (std::size_t page = 0; page < tls_slots.size(); ++page) {
+ const auto& page_tls_slots = tls_slots[page];
+ if (!page_tls_slots.all()) {
+ // We found a page with at least one free slot, find which slot it is
+ for (std::size_t slot = 0; slot < page_tls_slots.size(); ++slot) {
+ if (!page_tls_slots.test(slot)) {
+ return std::make_tuple(page, slot, false);
+ }
+ }
+ }
+ }
+
+ return std::make_tuple(0, 0, true);
+}
+
+VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) {
+ auto [available_page, available_slot, needs_allocation] = FindFreeThreadLocalSlot(tls_slots);
+
+ if (needs_allocation) {
+ tls_slots.emplace_back(0); // The page is completely available at the start
+ available_page = tls_slots.size() - 1;
+ available_slot = 0; // Use the first slot in the new page
+
+ // Allocate some memory from the end of the linear heap for this region.
+ auto& tls_memory = thread.GetTLSMemory();
+ tls_memory->insert(tls_memory->end(), Memory::PAGE_SIZE, 0);
+
+ vm_manager.RefreshMemoryBlockMappings(tls_memory.get());
+
+ vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
+ tls_memory, 0, Memory::PAGE_SIZE, MemoryState::ThreadLocal);
+ }
+
+ tls_slots[available_page].set(available_slot);
+
+ return Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
+ available_slot * Memory::TLS_ENTRY_SIZE;
+}
+
+void Process::FreeTLSSlot(VAddr tls_address) {
+ const VAddr tls_base = tls_address - Memory::TLS_AREA_VADDR;
+ const VAddr tls_page = tls_base / Memory::PAGE_SIZE;
+ const VAddr tls_slot = (tls_base % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
+
+ tls_slots[tls_page].reset(tls_slot);
+}
+
void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
const auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions,
MemoryState memory_state) {
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 81538f70c..04d74e572 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -131,6 +131,16 @@ public:
return HANDLE_TYPE;
}
+ /// Gets the current status of the process
+ ProcessStatus GetStatus() const {
+ return status;
+ }
+
+ /// Gets the unique ID that identifies this particular process.
+ u32 GetProcessID() const {
+ return process_id;
+ }
+
/// Title ID corresponding to the process
u64 program_id;
@@ -154,11 +164,6 @@ public:
u32 allowed_processor_mask = THREADPROCESSORID_DEFAULT_MASK;
u32 allowed_thread_priority_mask = 0xFFFFFFFF;
u32 is_virtual_address_memory_enabled = 0;
- /// Current status of the process
- ProcessStatus status;
-
- /// The ID of this process
- u32 process_id = 0;
/**
* Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them
@@ -171,13 +176,42 @@ public:
*/
void Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size);
+ /**
+ * Prepares a process for termination by stopping all of its threads
+ * and clearing any other resources.
+ */
+ void PrepareForTermination();
+
void LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr);
///////////////////////////////////////////////////////////////////////////////////////////////
// Memory Management
+ // Marks the next available region as used and returns the address of the slot.
+ VAddr MarkNextAvailableTLSSlotAsUsed(Thread& thread);
+
+ // Frees a used TLS slot identified by the given address
+ void FreeTLSSlot(VAddr tls_address);
+
+ ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
+ ResultCode HeapFree(VAddr target, u32 size);
+
+ ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size);
+
+ ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
+
VMManager vm_manager;
+private:
+ explicit Process(KernelCore& kernel);
+ ~Process() override;
+
+ /// Current status of the process
+ ProcessStatus status;
+
+ /// The ID of this process
+ u32 process_id = 0;
+
// Memory used to back the allocations in the regular heap. A single vector is used to cover
// the entire virtual address space extents that bound the allocations, including any holes.
// This makes deallocation and reallocation of holes fast and keeps process memory contiguous
@@ -197,17 +231,6 @@ public:
std::vector<std::bitset<8>> tls_slots;
std::string name;
-
- ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
- ResultCode HeapFree(VAddr target, u32 size);
-
- ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size);
-
- ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
-
-private:
- explicit Process(KernelCore& kernel);
- ~Process() override;
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 371fc439e..c9d212a4c 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -169,7 +169,7 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
return ERR_INVALID_HANDLE;
}
- *process_id = process->process_id;
+ *process_id = process->GetProcessID();
return RESULT_SUCCESS;
}
@@ -530,35 +530,13 @@ static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, VAdd
/// Exits the current process
static void ExitProcess() {
- LOG_INFO(Kernel_SVC, "Process {} exiting", Core::CurrentProcess()->process_id);
+ auto& current_process = Core::CurrentProcess();
- ASSERT_MSG(Core::CurrentProcess()->status == ProcessStatus::Running,
+ LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID());
+ ASSERT_MSG(current_process->GetStatus() == ProcessStatus::Running,
"Process has already exited");
- Core::CurrentProcess()->status = ProcessStatus::Exited;
-
- auto stop_threads = [](const std::vector<SharedPtr<Thread>>& thread_list) {
- for (auto& thread : thread_list) {
- if (thread->owner_process != Core::CurrentProcess())
- continue;
-
- if (thread == GetCurrentThread())
- continue;
-
- // TODO(Subv): When are the other running/ready threads terminated?
- ASSERT_MSG(thread->status == ThreadStatus::WaitSynchAny ||
- thread->status == ThreadStatus::WaitSynchAll,
- "Exiting processes with non-waiting threads is currently unimplemented");
-
- thread->Stop();
- }
- };
-
- auto& system = Core::System::GetInstance();
- stop_threads(system.Scheduler(0)->GetThreadList());
- stop_threads(system.Scheduler(1)->GetThreadList());
- stop_threads(system.Scheduler(2)->GetThreadList());
- stop_threads(system.Scheduler(3)->GetThreadList());
+ current_process->PrepareForTermination();
// Kill the current thread
GetCurrentThread()->Stop();
@@ -1039,7 +1017,7 @@ static const FunctionDef SVC_Table[] = {
{0x2B, nullptr, "FlushDataCache"},
{0x2C, nullptr, "MapPhysicalMemory"},
{0x2D, nullptr, "UnmapPhysicalMemory"},
- {0x2E, nullptr, "GetNextThreadInfo"},
+ {0x2E, nullptr, "GetFutureThreadInfo"},
{0x2F, nullptr, "GetLastThreadInfo"},
{0x30, nullptr, "GetResourceLimitLimitValue"},
{0x31, nullptr, "GetResourceLimitCurrentValue"},
@@ -1065,11 +1043,11 @@ static const FunctionDef SVC_Table[] = {
{0x45, nullptr, "CreateEvent"},
{0x46, nullptr, "Unknown"},
{0x47, nullptr, "Unknown"},
- {0x48, nullptr, "AllocateUnsafeMemory"},
- {0x49, nullptr, "FreeUnsafeMemory"},
- {0x4A, nullptr, "SetUnsafeAllocationLimit"},
- {0x4B, nullptr, "CreateJitMemory"},
- {0x4C, nullptr, "MapJitMemory"},
+ {0x48, nullptr, "MapPhysicalMemoryUnsafe"},
+ {0x49, nullptr, "UnmapPhysicalMemoryUnsafe"},
+ {0x4A, nullptr, "SetUnsafeLimit"},
+ {0x4B, nullptr, "CreateCodeMemory"},
+ {0x4C, nullptr, "ControlCodeMemory"},
{0x4D, nullptr, "SleepSystem"},
{0x4E, nullptr, "ReadWriteRegister"},
{0x4F, nullptr, "SetProcessActivity"},
@@ -1104,7 +1082,7 @@ static const FunctionDef SVC_Table[] = {
{0x6C, nullptr, "SetHardwareBreakPoint"},
{0x6D, nullptr, "GetDebugThreadParam"},
{0x6E, nullptr, "Unknown"},
- {0x6F, nullptr, "GetMemoryInfo"},
+ {0x6F, nullptr, "GetSystemInfo"},
{0x70, nullptr, "CreatePort"},
{0x71, nullptr, "ManageNamedPort"},
{0x72, nullptr, "ConnectToPort"},
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index c2d7535c9..315f65338 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -65,10 +65,7 @@ void Thread::Stop() {
wait_objects.clear();
// Mark the TLS slot in the thread's page as free.
- const u64 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE;
- const u64 tls_slot =
- ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
- Core::CurrentProcess()->tls_slots[tls_page].reset(tls_slot);
+ owner_process->FreeTLSSlot(tls_address);
}
void WaitCurrentThread_Sleep() {
@@ -178,32 +175,6 @@ void Thread::ResumeFromWait() {
}
/**
- * Finds a free location for the TLS section of a thread.
- * @param tls_slots The TLS page array of the thread's owner process.
- * Returns a tuple of (page, slot, alloc_needed) where:
- * page: The index of the first allocated TLS page that has free slots.
- * slot: The index of the first free slot in the indicated page.
- * alloc_needed: Whether there's a need to allocate a new TLS page (All pages are full).
- */
-static std::tuple<std::size_t, std::size_t, bool> GetFreeThreadLocalSlot(
- const std::vector<std::bitset<8>>& tls_slots) {
- // Iterate over all the allocated pages, and try to find one where not all slots are used.
- for (std::size_t page = 0; page < tls_slots.size(); ++page) {
- const auto& page_tls_slots = tls_slots[page];
- if (!page_tls_slots.all()) {
- // We found a page with at least one free slot, find which slot it is
- for (std::size_t slot = 0; slot < page_tls_slots.size(); ++slot) {
- if (!page_tls_slots.test(slot)) {
- return std::make_tuple(page, slot, false);
- }
- }
- }
- }
-
- return std::make_tuple(0, 0, true);
-}
-
-/**
* Resets a thread context, making it ready to be scheduled and run by the CPU
* @param context Thread context to reset
* @param stack_top Address of the top of the stack
@@ -264,32 +235,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
thread->owner_process = owner_process;
thread->scheduler = Core::System::GetInstance().Scheduler(processor_id);
thread->scheduler->AddThread(thread, priority);
-
- // Find the next available TLS index, and mark it as used
- auto& tls_slots = owner_process->tls_slots;
-
- auto [available_page, available_slot, needs_allocation] = GetFreeThreadLocalSlot(tls_slots);
- if (needs_allocation) {
- tls_slots.emplace_back(0); // The page is completely available at the start
- available_page = tls_slots.size() - 1;
- available_slot = 0; // Use the first slot in the new page
-
- // Allocate some memory from the end of the linear heap for this region.
- const std::size_t offset = thread->tls_memory->size();
- thread->tls_memory->insert(thread->tls_memory->end(), Memory::PAGE_SIZE, 0);
-
- auto& vm_manager = owner_process->vm_manager;
- vm_manager.RefreshMemoryBlockMappings(thread->tls_memory.get());
-
- vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
- thread->tls_memory, 0, Memory::PAGE_SIZE,
- MemoryState::ThreadLocal);
- }
-
- // Mark the slot as used
- tls_slots[available_page].set(available_slot);
- thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
- available_slot * Memory::TLS_ENTRY_SIZE;
+ thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread);
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
// to initialize the context
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 91e9b79ec..4250144c3 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -62,6 +62,9 @@ enum class ThreadWakeupReason {
class Thread final : public WaitObject {
public:
+ using TLSMemory = std::vector<u8>;
+ using TLSMemoryPtr = std::shared_ptr<TLSMemory>;
+
/**
* Creates and returns a new thread. The new thread is immediately scheduled
* @param kernel The kernel instance this thread will be created under.
@@ -134,6 +137,14 @@ public:
return thread_id;
}
+ TLSMemoryPtr& GetTLSMemory() {
+ return tls_memory;
+ }
+
+ const TLSMemoryPtr& GetTLSMemory() const {
+ return tls_memory;
+ }
+
/**
* Resumes a thread from waiting
*/
@@ -269,7 +280,7 @@ private:
explicit Thread(KernelCore& kernel);
~Thread() override;
- std::shared_ptr<std::vector<u8>> tls_memory = std::make_shared<std::vector<u8>>();
+ TLSMemoryPtr tls_memory = std::make_shared<TLSMemory>();
};
/**
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 06ac6372d..80ed4b152 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -25,7 +25,7 @@ public:
{0, &IAudioRenderer::GetAudioRendererSampleRate, "GetAudioRendererSampleRate"},
{1, &IAudioRenderer::GetAudioRendererSampleCount, "GetAudioRendererSampleCount"},
{2, &IAudioRenderer::GetAudioRendererMixBufferCount, "GetAudioRendererMixBufferCount"},
- {3, nullptr, "GetAudioRendererState"},
+ {3, &IAudioRenderer::GetAudioRendererState, "GetAudioRendererState"},
{4, &IAudioRenderer::RequestUpdateAudioRenderer, "RequestUpdateAudioRenderer"},
{5, &IAudioRenderer::StartAudioRenderer, "StartAudioRenderer"},
{6, &IAudioRenderer::StopAudioRenderer, "StopAudioRenderer"},
@@ -62,6 +62,13 @@ private:
LOG_DEBUG(Service_Audio, "called");
}
+ void GetAudioRendererState(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(renderer->GetState());
+ LOG_DEBUG(Service_Audio, "called");
+ }
+
void GetAudioRendererMixBufferCount(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp
index b436ce4e6..6de7edf9e 100644
--- a/src/core/hle/service/fatal/fatal.cpp
+++ b/src/core/hle/service/fatal/fatal.cpp
@@ -2,8 +2,17 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <array>
+#include <cstring>
+#include <ctime>
+#include <fmt/time.h>
+#include "common/common_paths.h"
+#include "common/file_util.h"
#include "common/logging/log.h"
+#include "common/scm_rev.h"
+#include "common/swap.h"
#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/service/fatal/fatal.h"
#include "core/hle/service/fatal/fatal_p.h"
#include "core/hle/service/fatal/fatal_u.h"
@@ -15,16 +24,142 @@ Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
Module::Interface::~Interface() = default;
+struct FatalInfo {
+ std::array<u64_le, 31> registers{}; // TODO(ogniK): See if this actually is registers or
+ // not(find a game which has non zero valeus)
+ u64_le unk0{};
+ u64_le unk1{};
+ u64_le unk2{};
+ u64_le unk3{};
+ u64_le unk4{};
+ u64_le unk5{};
+ u64_le unk6{};
+
+ std::array<u64_le, 32> backtrace{};
+ u64_le unk7{};
+ u64_le unk8{};
+ u32_le backtrace_size{};
+ u32_le unk9{};
+ u32_le unk10{}; // TODO(ogniK): Is this even used or is it just padding?
+};
+static_assert(sizeof(FatalInfo) == 0x250, "FatalInfo is an invalid size");
+
+enum class FatalType : u32 {
+ ErrorReportAndScreen = 0,
+ ErrorReport = 1,
+ ErrorScreen = 2,
+};
+
+static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) {
+ const auto title_id = Core::CurrentProcess()->program_id;
+ std::string crash_report =
+ fmt::format("Yuzu {}-{} crash report\n"
+ "Title ID: {:016x}\n"
+ "Result: 0x{:X} ({:04}-{:04d})\n"
+ "\n",
+ Common::g_scm_branch, Common::g_scm_desc, title_id, error_code.raw,
+ 2000 + static_cast<u32>(error_code.module.Value()),
+ static_cast<u32>(error_code.description.Value()), info.unk8, info.unk7);
+ if (info.backtrace_size != 0x0) {
+ crash_report += "Registers:\n";
+ // TODO(ogniK): This is just a guess, find a game which actually has non zero values
+ for (size_t i = 0; i < info.registers.size(); i++) {
+ crash_report +=
+ fmt::format(" X[{:02d}]: {:016x}\n", i, info.registers[i]);
+ }
+ crash_report += fmt::format(" Unknown 0: {:016x}\n", info.unk0);
+ crash_report += fmt::format(" Unknown 1: {:016x}\n", info.unk1);
+ crash_report += fmt::format(" Unknown 2: {:016x}\n", info.unk2);
+ crash_report += fmt::format(" Unknown 3: {:016x}\n", info.unk3);
+ crash_report += fmt::format(" Unknown 4: {:016x}\n", info.unk4);
+ crash_report += fmt::format(" Unknown 5: {:016x}\n", info.unk5);
+ crash_report += fmt::format(" Unknown 6: {:016x}\n", info.unk6);
+ crash_report += "\nBacktrace:\n";
+ for (size_t i = 0; i < info.backtrace_size; i++) {
+ crash_report +=
+ fmt::format(" Backtrace[{:02d}]: {:016x}\n", i, info.backtrace[i]);
+ }
+ crash_report += fmt::format("\nUnknown 7: 0x{:016x}\n", info.unk7);
+ crash_report += fmt::format("Unknown 8: 0x{:016x}\n", info.unk8);
+ crash_report += fmt::format("Unknown 9: 0x{:016x}\n", info.unk9);
+ crash_report += fmt::format("Unknown 10: 0x{:016x}\n", info.unk10);
+ }
+
+ LOG_ERROR(Service_Fatal, "{}", crash_report);
+
+ const std::string crashreport_dir =
+ FileUtil::GetUserPath(FileUtil::UserPath::LogDir) + "crash_logs";
+
+ if (!FileUtil::CreateFullPath(crashreport_dir)) {
+ LOG_ERROR(
+ Service_Fatal,
+ "Unable to create crash report directory. Possible log directory permissions issue.");
+ return;
+ }
+
+ const std::time_t t = std::time(nullptr);
+ const std::string crashreport_filename =
+ fmt::format("{}/{:016x}-{:%F-%H%M%S}.log", crashreport_dir, title_id, *std::localtime(&t));
+
+ auto file = FileUtil::IOFile(crashreport_filename, "wb");
+ if (file.IsOpen()) {
+ file.WriteString(crash_report);
+ LOG_ERROR(Service_Fatal, "Saving error report to {}", crashreport_filename);
+ } else {
+ LOG_ERROR(Service_Fatal, "Failed to save error report to {}", crashreport_filename);
+ }
+}
+
+static void ThrowFatalError(ResultCode error_code, FatalType fatal_type, const FatalInfo& info) {
+ LOG_ERROR(Service_Fatal, "Threw fatal error type {}", static_cast<u32>(fatal_type));
+ switch (fatal_type) {
+ case FatalType::ErrorReportAndScreen:
+ GenerateErrorReport(error_code, info);
+ [[fallthrough]];
+ case FatalType::ErrorScreen:
+ // Since we have no fatal:u error screen. We should just kill execution instead
+ ASSERT(false);
+ break;
+ // Should not throw a fatal screen but should generate an error report
+ case FatalType::ErrorReport:
+ GenerateErrorReport(error_code, info);
+ break;
+ };
+}
+
+void Module::Interface::ThrowFatal(Kernel::HLERequestContext& ctx) {
+ LOG_ERROR(Service_Fatal, "called");
+ IPC::RequestParser rp{ctx};
+ auto error_code = rp.Pop<ResultCode>();
+
+ ThrowFatalError(error_code, FatalType::ErrorScreen, {});
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
void Module::Interface::ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx) {
+ LOG_ERROR(Service_Fatal, "called");
IPC::RequestParser rp(ctx);
- u32 error_code = rp.Pop<u32>();
- LOG_WARNING(Service_Fatal, "(STUBBED) called, error_code=0x{:X}", error_code);
+ auto error_code = rp.Pop<ResultCode>();
+ auto fatal_type = rp.PopEnum<FatalType>();
+
+ ThrowFatalError(error_code, fatal_type, {}); // No info is passed with ThrowFatalWithPolicy
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void Module::Interface::ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_Fatal, "(STUBBED) called");
+ LOG_ERROR(Service_Fatal, "called");
+ IPC::RequestParser rp(ctx);
+ auto error_code = rp.Pop<ResultCode>();
+ auto fatal_type = rp.PopEnum<FatalType>();
+ auto fatal_info = ctx.ReadBuffer();
+ FatalInfo info{};
+
+ ASSERT_MSG(fatal_info.size() == sizeof(FatalInfo), "Invalid fatal info buffer size!");
+ std::memcpy(&info, fatal_info.data(), sizeof(FatalInfo));
+
+ ThrowFatalError(error_code, fatal_type, info);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
diff --git a/src/core/hle/service/fatal/fatal.h b/src/core/hle/service/fatal/fatal.h
index 4d9a5be52..09371ff7f 100644
--- a/src/core/hle/service/fatal/fatal.h
+++ b/src/core/hle/service/fatal/fatal.h
@@ -15,6 +15,7 @@ public:
explicit Interface(std::shared_ptr<Module> module, const char* name);
~Interface() override;
+ void ThrowFatal(Kernel::HLERequestContext& ctx);
void ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx);
void ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/fatal/fatal_u.cpp b/src/core/hle/service/fatal/fatal_u.cpp
index befc307cf..1572a2051 100644
--- a/src/core/hle/service/fatal/fatal_u.cpp
+++ b/src/core/hle/service/fatal/fatal_u.cpp
@@ -8,7 +8,7 @@ namespace Service::Fatal {
Fatal_U::Fatal_U(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "fatal:u") {
static const FunctionInfo functions[] = {
- {0, nullptr, "ThrowFatal"},
+ {0, &Fatal_U::ThrowFatal, "ThrowFatal"},
{1, &Fatal_U::ThrowFatalWithPolicy, "ThrowFatalWithPolicy"},
{2, &Fatal_U::ThrowFatalWithCpuContext, "ThrowFatalWithCpuContext"},
};
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp
index e587ad0d8..872e3c344 100644
--- a/src/core/hle/service/hid/irs.cpp
+++ b/src/core/hle/service/hid/irs.cpp
@@ -2,6 +2,11 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/swap.h"
+#include "core/core.h"
+#include "core/core_timing.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/shared_memory.h"
#include "core/hle/service/hid/irs.h"
namespace Service::HID {
@@ -9,28 +14,145 @@ namespace Service::HID {
IRS::IRS() : ServiceFramework{"irs"} {
// clang-format off
static const FunctionInfo functions[] = {
- {302, nullptr, "ActivateIrsensor"},
- {303, nullptr, "DeactivateIrsensor"},
- {304, nullptr, "GetIrsensorSharedMemoryHandle"},
- {305, nullptr, "StopImageProcessor"},
- {306, nullptr, "RunMomentProcessor"},
- {307, nullptr, "RunClusteringProcessor"},
- {308, nullptr, "RunImageTransferProcessor"},
- {309, nullptr, "GetImageTransferProcessorState"},
- {310, nullptr, "RunTeraPluginProcessor"},
- {311, nullptr, "GetNpadIrCameraHandle"},
- {312, nullptr, "RunPointingProcessor"},
- {313, nullptr, "SuspendImageProcessor"},
- {314, nullptr, "CheckFirmwareVersion"},
- {315, nullptr, "SetFunctionLevel"},
- {316, nullptr, "RunImageTransferExProcessor"},
- {317, nullptr, "RunIrLedProcessor"},
- {318, nullptr, "StopImageProcessorAsync"},
- {319, nullptr, "ActivateIrsensorWithFunctionLevel"},
+ {302, &IRS::ActivateIrsensor, "ActivateIrsensor"},
+ {303, &IRS::DeactivateIrsensor, "DeactivateIrsensor"},
+ {304, &IRS::GetIrsensorSharedMemoryHandle, "GetIrsensorSharedMemoryHandle"},
+ {305, &IRS::StopImageProcessor, "StopImageProcessor"},
+ {306, &IRS::RunMomentProcessor, "RunMomentProcessor"},
+ {307, &IRS::RunClusteringProcessor, "RunClusteringProcessor"},
+ {308, &IRS::RunImageTransferProcessor, "RunImageTransferProcessor"},
+ {309, &IRS::GetImageTransferProcessorState, "GetImageTransferProcessorState"},
+ {310, &IRS::RunTeraPluginProcessor, "RunTeraPluginProcessor"},
+ {311, &IRS::GetNpadIrCameraHandle, "GetNpadIrCameraHandle"},
+ {312, &IRS::RunPointingProcessor, "RunPointingProcessor"},
+ {313, &IRS::SuspendImageProcessor, "SuspendImageProcessor"},
+ {314, &IRS::CheckFirmwareVersion, "CheckFirmwareVersion"},
+ {315, &IRS::SetFunctionLevel, "SetFunctionLevel"},
+ {316, &IRS::RunImageTransferExProcessor, "RunImageTransferExProcessor"},
+ {317, &IRS::RunIrLedProcessor, "RunIrLedProcessor"},
+ {318, &IRS::StopImageProcessorAsync, "StopImageProcessorAsync"},
+ {319, &IRS::ActivateIrsensorWithFunctionLevel, "ActivateIrsensorWithFunctionLevel"},
};
// clang-format on
RegisterHandlers(functions);
+
+ auto& kernel = Core::System::GetInstance().Kernel();
+ shared_mem = Kernel::SharedMemory::Create(
+ kernel, nullptr, 0x8000, Kernel::MemoryPermission::ReadWrite,
+ Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "IRS:SharedMemory");
+}
+
+void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(shared_mem);
+ LOG_DEBUG(Service_IRS, "called");
+}
+
+void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 5};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw<u64>(CoreTiming::GetTicks());
+ rb.PushRaw<u32>(0);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw<u32>(device_handle);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+}
+
+void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
}
IRS::~IRS() = default;
diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h
index 6fb16b45d..12de6bfb3 100644
--- a/src/core/hle/service/hid/irs.h
+++ b/src/core/hle/service/hid/irs.h
@@ -4,14 +4,41 @@
#pragma once
+#include "core/hle/kernel/object.h"
#include "core/hle/service/service.h"
+namespace Kernel {
+class SharedMemory;
+}
+
namespace Service::HID {
class IRS final : public ServiceFramework<IRS> {
public:
explicit IRS();
~IRS() override;
+
+private:
+ void ActivateIrsensor(Kernel::HLERequestContext& ctx);
+ void DeactivateIrsensor(Kernel::HLERequestContext& ctx);
+ void GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx);
+ void StopImageProcessor(Kernel::HLERequestContext& ctx);
+ void RunMomentProcessor(Kernel::HLERequestContext& ctx);
+ void RunClusteringProcessor(Kernel::HLERequestContext& ctx);
+ void RunImageTransferProcessor(Kernel::HLERequestContext& ctx);
+ void GetImageTransferProcessorState(Kernel::HLERequestContext& ctx);
+ void RunTeraPluginProcessor(Kernel::HLERequestContext& ctx);
+ void GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx);
+ void RunPointingProcessor(Kernel::HLERequestContext& ctx);
+ void SuspendImageProcessor(Kernel::HLERequestContext& ctx);
+ void CheckFirmwareVersion(Kernel::HLERequestContext& ctx);
+ void SetFunctionLevel(Kernel::HLERequestContext& ctx);
+ void RunImageTransferExProcessor(Kernel::HLERequestContext& ctx);
+ void RunIrLedProcessor(Kernel::HLERequestContext& ctx);
+ void StopImageProcessorAsync(Kernel::HLERequestContext& ctx);
+ void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx);
+ Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
+ const u32 device_handle{0xABCD};
};
class IRS_SYS final : public ServiceFramework<IRS_SYS> {
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index fe0a318ee..bc4f7a437 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -103,6 +103,7 @@ public:
}
private:
+ u32 ssl_version{};
void CreateContext(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_SSL, "(STUBBED) called");
@@ -112,10 +113,9 @@ private:
}
void SetInterfaceVersion(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_SSL, "(STUBBED) called");
+ LOG_DEBUG(Service_SSL, "called");
IPC::RequestParser rp{ctx};
- u32 unk1 = rp.Pop<u32>(); // Probably minor/major?
- u32 unk2 = rp.Pop<u32>(); // TODO(ogniK): Figure out what this does
+ ssl_version = rp.Pop<u32>();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 7e1de0fa1..b1f137b9c 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -5,9 +5,8 @@
#pragma once
#include <bitset>
-#include <cstring>
-#include <map>
#include <string>
+#include <tuple>
#include <vector>
#include <boost/optional.hpp>
@@ -315,17 +314,29 @@ enum class TextureMiscMode : u64 {
PTP,
};
-enum class IpaInterpMode : u64 { Linear = 0, Perspective = 1, Flat = 2, Sc = 3 };
-enum class IpaSampleMode : u64 { Default = 0, Centroid = 1, Offset = 2 };
+enum class IpaInterpMode : u64 {
+ Linear = 0,
+ Perspective = 1,
+ Flat = 2,
+ Sc = 3,
+};
+
+enum class IpaSampleMode : u64 {
+ Default = 0,
+ Centroid = 1,
+ Offset = 2,
+};
struct IpaMode {
IpaInterpMode interpolation_mode;
IpaSampleMode sampling_mode;
- inline bool operator==(const IpaMode& a) {
- return (a.interpolation_mode == interpolation_mode) && (a.sampling_mode == sampling_mode);
+
+ bool operator==(const IpaMode& a) const {
+ return std::tie(interpolation_mode, sampling_mode) ==
+ std::tie(a.interpolation_mode, a.sampling_mode);
}
- inline bool operator!=(const IpaMode& a) {
- return !((*this) == a);
+ bool operator!=(const IpaMode& a) const {
+ return !operator==(a);
}
};
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 86682d7cb..24a540258 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -141,8 +141,8 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
{GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
true}, // BC7U
{GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8,
- ComponentType::UNorm, true}, // BC6H_UF16
- {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
+ ComponentType::Float, true}, // BC6H_UF16
+ {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float,
true}, // BC6H_SF16
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4
{GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8U
@@ -501,6 +501,9 @@ CachedSurface::CachedSurface(const SurfaceParams& params)
glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ VideoCore::LabelGLObject(GL_TEXTURE, texture.handle, params.addr,
+ SurfaceParams::SurfaceTargetName(params.target));
}
static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index d7a4bc37f..80c5f324b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -137,6 +137,27 @@ struct SurfaceParams {
}
}
+ static std::string SurfaceTargetName(SurfaceTarget target) {
+ switch (target) {
+ case SurfaceTarget::Texture1D:
+ return "Texture1D";
+ case SurfaceTarget::Texture2D:
+ return "Texture2D";
+ case SurfaceTarget::Texture3D:
+ return "Texture3D";
+ case SurfaceTarget::Texture1DArray:
+ return "Texture1DArray";
+ case SurfaceTarget::Texture2DArray:
+ return "Texture2DArray";
+ case SurfaceTarget::TextureCubemap:
+ return "TextureCubemap";
+ default:
+ LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
+ UNREACHABLE();
+ return fmt::format("TextureUnknown({})", static_cast<u32>(target));
+ }
+ }
+
/**
* Gets the compression factor for the specified PixelFormat. This applies to just the
* "compressed width" and "compressed height", not the overall compression factor of a
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 894fe6eae..7cd8f91e4 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -8,6 +8,7 @@
#include "video_core/engines/maxwell_3d.h"
#include "video_core/renderer_opengl/gl_shader_cache.h"
#include "video_core/renderer_opengl/gl_shader_manager.h"
+#include "video_core/utils.h"
namespace OpenGL {
@@ -83,6 +84,7 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
shader.Create(program_result.first.c_str(), gl_type);
program.Create(true, shader.handle);
SetShaderUniformBlockBindings(program.handle);
+ VideoCore::LabelGLObject(GL_PROGRAM, program.handle, addr);
}
GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer) {
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index af99132ba..e5173e20a 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -4,6 +4,7 @@
#include <iterator>
#include <glad/glad.h>
+#include "common/assert.h"
#include "common/logging/log.h"
#include "video_core/renderer_opengl/gl_state.h"
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index e3e24b9e7..9a93029d8 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -7,12 +7,8 @@
#include <array>
#include <glad/glad.h>
-#include "video_core/engines/maxwell_3d.h"
-
namespace OpenGL {
-using Regs = Tegra::Engines::Maxwell3D::Regs;
-
namespace TextureUnits {
struct TextureUnit {
diff --git a/src/video_core/utils.h b/src/video_core/utils.h
index e0a14d48f..681919ae3 100644
--- a/src/video_core/utils.h
+++ b/src/video_core/utils.h
@@ -161,4 +161,26 @@ static inline void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixe
}
}
+static void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr,
+ std::string extra_info = "") {
+ if (!GLAD_GL_KHR_debug) {
+ return; // We don't need to throw an error as this is just for debugging
+ }
+ const std::string nice_addr = fmt::format("0x{:016x}", addr);
+ std::string object_label;
+
+ switch (identifier) {
+ case GL_TEXTURE:
+ object_label = extra_info + "@" + nice_addr;
+ break;
+ case GL_PROGRAM:
+ object_label = "ShaderProgram@" + nice_addr;
+ break;
+ default:
+ object_label = fmt::format("Object(0x{:x})@{}", identifier, nice_addr);
+ break;
+ }
+ glObjectLabel(identifier, handle, -1, static_cast<const GLchar*>(object_label.c_str()));
+}
+
} // namespace VideoCore
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h
index b6272d536..cee109730 100644
--- a/src/yuzu/game_list_p.h
+++ b/src/yuzu/game_list_p.h
@@ -68,7 +68,7 @@ public:
if (!picture.loadFromData(picture_data.data(), static_cast<u32>(picture_data.size()))) {
picture = GetDefaultIcon(size);
}
- picture = picture.scaled(size, size);
+ picture = picture.scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
setData(picture, Qt::DecorationRole);
}
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 7ec1f5110..a478b0a56 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -120,7 +120,7 @@ void Config::ReadValues() {
sdl2_config->Get("Data Storage", "nand_directory",
FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)));
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir,
- sdl2_config->Get("Data Storage", "nand_directory",
+ sdl2_config->Get("Data Storage", "sdmc_directory",
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)));
// System