summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/citra_qt/game_list.cpp16
-rw-r--r--src/common/file_util.cpp72
-rw-r--r--src/common/file_util.h31
-rw-r--r--src/core/arm/skyeye_common/armstate.h22
-rw-r--r--src/core/core.h2
-rw-r--r--src/core/hle/function_wrappers.h8
-rw-r--r--src/core/hle/kernel/memory.cpp2
-rw-r--r--src/core/hle/kernel/memory.h1
-rw-r--r--src/core/hle/kernel/process.cpp6
-rw-r--r--src/core/hle/kernel/thread.cpp3
-rw-r--r--src/core/hle/service/csnd_snd.cpp25
-rw-r--r--src/core/hle/service/ssl_c.cpp53
-rw-r--r--src/core/hle/svc.cpp47
-rw-r--r--src/core/hle/svc.h29
-rw-r--r--src/video_core/rasterizer.cpp13
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp9
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h7
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp26
18 files changed, 260 insertions, 112 deletions
diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp
index e925f08a7..1f8d69a03 100644
--- a/src/citra_qt/game_list.cpp
+++ b/src/citra_qt/game_list.cpp
@@ -119,13 +119,14 @@ void GameList::LoadInterfaceLayout(QSettings& settings)
void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, bool deep_scan)
{
- const auto callback = [&](const std::string& directory,
- const std::string& virtual_name) -> int {
+ const auto callback = [&](unsigned* num_entries_out,
+ const std::string& directory,
+ const std::string& virtual_name) -> bool {
std::string physical_name = directory + DIR_SEP + virtual_name;
if (stop_processing)
- return -1; // A negative return value breaks the callback loop.
+ return false; // Breaks the callback loop.
if (deep_scan && FileUtil::IsDirectory(physical_name)) {
AddFstEntriesToGameList(physical_name, true);
@@ -135,11 +136,11 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, bool d
Loader::FileType guessed_filetype = Loader::GuessFromExtension(filename_extension);
if (guessed_filetype == Loader::FileType::Unknown)
- return 0;
+ return true;
Loader::FileType filetype = Loader::IdentifyFile(physical_name);
if (filetype == Loader::FileType::Unknown) {
LOG_WARNING(Frontend, "File %s is of indeterminate type and is possibly corrupted.", physical_name.c_str());
- return 0;
+ return true;
}
if (guessed_filetype != filetype) {
LOG_WARNING(Frontend, "Filetype and extension of file %s do not match.", physical_name.c_str());
@@ -152,9 +153,10 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, bool d
});
}
- return 0; // We don't care about the found entries
+ return true;
};
- FileUtil::ScanDirectoryTreeAndCallback(dir_path, callback);
+
+ FileUtil::ForeachDirectoryEntry(nullptr, dir_path, callback);
}
void GameListWorker::run()
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 1e0d33313..4c7113390 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -420,11 +420,13 @@ bool CreateEmptyFile(const std::string &filename)
}
-int ScanDirectoryTreeAndCallback(const std::string &directory, std::function<int(const std::string&, const std::string&)> callback)
+bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directory, DirectoryEntryCallable callback)
{
LOG_TRACE(Common_Filesystem, "directory %s", directory.c_str());
+
// How many files + directories we found
- int found_entries = 0;
+ unsigned found_entries = 0;
+
#ifdef _WIN32
// Find the first file in the directory.
WIN32_FIND_DATA ffd;
@@ -432,7 +434,7 @@ int ScanDirectoryTreeAndCallback(const std::string &directory, std::function<int
HANDLE handle_find = FindFirstFile(Common::UTF8ToTStr(directory + "\\*").c_str(), &ffd);
if (handle_find == INVALID_HANDLE_VALUE) {
FindClose(handle_find);
- return found_entries;
+ return false;
}
// windows loop
do {
@@ -442,25 +444,20 @@ int ScanDirectoryTreeAndCallback(const std::string &directory, std::function<int
DIR *dirp = opendir(directory.c_str());
if (!dirp)
- return 0;
+ return false;
// non windows loop
while (!readdir_r(dirp, &dirent, &result) && result) {
const std::string virtual_name(result->d_name);
#endif
- // check for "." and ".."
- if (((virtual_name[0] == '.') && (virtual_name[1] == '\0')) ||
- ((virtual_name[0] == '.') && (virtual_name[1] == '.') &&
- (virtual_name[2] == '\0')))
+
+ if (virtual_name == "." || virtual_name == "..")
continue;
- int ret = callback(directory, virtual_name);
- if (ret < 0) {
- if (ret != -1)
- found_entries = ret;
+ unsigned ret_entries;
+ if (!callback(&ret_entries, directory, virtual_name))
break;
- }
- found_entries += ret;
+ found_entries += ret_entries;
#ifdef _WIN32
} while (FindNextFile(handle_find, &ffd) != 0);
@@ -469,16 +466,18 @@ int ScanDirectoryTreeAndCallback(const std::string &directory, std::function<int
}
closedir(dirp);
#endif
- // Return number of entries found.
- return found_entries;
+
+ // num_entries_out is allowed to be specified nullptr, in which case we shouldn't try to set it
+ if (num_entries_out != nullptr)
+ *num_entries_out = found_entries;
}
-int ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry)
+unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry)
{
- const auto callback = [&parent_entry](const std::string& directory,
- const std::string& virtual_name) -> int {
+ const auto callback = [&parent_entry](unsigned* num_entries_out,
+ const std::string& directory,
+ const std::string& virtual_name) -> bool {
FSTEntry entry;
- int found_entries = 0;
entry.virtualName = virtual_name;
entry.physicalName = directory + DIR_SEP + virtual_name;
@@ -486,41 +485,40 @@ int ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry)
entry.isDirectory = true;
// is a directory, lets go inside
entry.size = ScanDirectoryTree(entry.physicalName, entry);
- found_entries += (int)entry.size;
+ *num_entries_out += (int)entry.size;
} else { // is a file
entry.isDirectory = false;
entry.size = GetSize(entry.physicalName);
}
- ++found_entries;
+ (*num_entries_out)++;
+
// Push into the tree
parent_entry.children.push_back(entry);
- return found_entries;
+ return true;
};
- return ScanDirectoryTreeAndCallback(directory, callback);
+ unsigned num_entries;
+ return ForeachDirectoryEntry(&num_entries, directory, callback) ? num_entries : 0;
}
bool DeleteDirRecursively(const std::string &directory)
{
- const static auto callback = [](const std::string& directory,
- const std::string& virtual_name) -> int {
+ const static auto callback = [](unsigned* num_entries_out,
+ const std::string& directory,
+ const std::string& virtual_name) -> bool {
std::string new_path = directory + DIR_SEP_CHR + virtual_name;
- if (IsDirectory(new_path)) {
- if (!DeleteDirRecursively(new_path)) {
- return -2;
- }
- } else if (!Delete(new_path)) {
- return -2;
- }
- return 0;
+ if (IsDirectory(new_path))
+ return DeleteDirRecursively(new_path);
+
+ return Delete(new_path);
};
- if (ScanDirectoryTreeAndCallback(directory, callback) == -2) {
+ if (!ForeachDirectoryEntry(nullptr, directory, callback))
return false;
- }
- FileUtil::DeleteDir(directory);
+ // Delete the outermost directory
+ FileUtil::DeleteDir(directory);
return true;
}
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 3d617f573..a85121aa6 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -98,19 +98,24 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename);
bool CreateEmptyFile(const std::string &filename);
/**
- * Scans the directory tree, calling the callback for each file/directory found.
- * The callback must return the number of files and directories which the provided path contains.
- * If the callback's return value is -1, the callback loop is broken immediately.
- * If the callback's return value is otherwise negative, the callback loop is broken immediately
- * and the callback's return value is returned from this function (to allow for error handling).
- * @param directory the parent directory to start scanning from
- * @param callback The callback which will be called for each file/directory. It is called
- * with the arguments (const std::string& directory, const std::string& virtual_name).
- * The `directory `parameter is the path to the directory which contains the file/directory.
- * The `virtual_name` parameter is the incomplete file path, without any directory info.
- * @return the total number of files/directories found
+ * @param num_entries_out to be assigned by the callable with the number of iterated directory entries, never null
+ * @param directory the path to the enclosing directory
+ * @param virtual_name the entry name, without any preceding directory info
+ * @return whether handling the entry succeeded
+ */
+using DirectoryEntryCallable = std::function<bool(unsigned* num_entries_out,
+ const std::string& directory,
+ const std::string& virtual_name)>;
+
+/**
+ * Scans a directory, calling the callback for each file/directory contained within.
+ * If the callback returns failure, scanning halts and this function returns failure as well
+ * @param num_entries_out assigned by the function with the number of iterated directory entries, can be null
+ * @param directory the directory to scan
+ * @param callback The callback which will be called for each entry
+ * @return whether scanning the directory succeeded
*/
-int ScanDirectoryTreeAndCallback(const std::string &directory, std::function<int(const std::string&, const std::string&)> callback);
+bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directory, DirectoryEntryCallable callback);
/**
* Scans the directory tree, storing the results.
@@ -118,7 +123,7 @@ int ScanDirectoryTreeAndCallback(const std::string &directory, std::function<int
* @param parent_entry FSTEntry where the filesystem tree results will be stored.
* @return the total number of files/directories found
*/
-int ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry);
+unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry);
// deletes the given directory and anything under it. Returns true on success.
bool DeleteDirRecursively(const std::string &directory);
diff --git a/src/core/arm/skyeye_common/armstate.h b/src/core/arm/skyeye_common/armstate.h
index 98dad9b1f..d42ff2669 100644
--- a/src/core/arm/skyeye_common/armstate.h
+++ b/src/core/arm/skyeye_common/armstate.h
@@ -193,23 +193,23 @@ public:
return TFlag ? 2 : 4;
}
- std::array<u32, 16> Reg; // The current register file
- std::array<u32, 2> Reg_usr;
- std::array<u32, 2> Reg_svc; // R13_SVC R14_SVC
- std::array<u32, 2> Reg_abort; // R13_ABORT R14_ABORT
- std::array<u32, 2> Reg_undef; // R13 UNDEF R14 UNDEF
- std::array<u32, 2> Reg_irq; // R13_IRQ R14_IRQ
- std::array<u32, 7> Reg_firq; // R8---R14 FIRQ
- std::array<u32, 7> Spsr; // The exception psr's
- std::array<u32, CP15_REGISTER_COUNT> CP15;
+ std::array<u32, 16> Reg{}; // The current register file
+ std::array<u32, 2> Reg_usr{};
+ std::array<u32, 2> Reg_svc{}; // R13_SVC R14_SVC
+ std::array<u32, 2> Reg_abort{}; // R13_ABORT R14_ABORT
+ std::array<u32, 2> Reg_undef{}; // R13 UNDEF R14 UNDEF
+ std::array<u32, 2> Reg_irq{}; // R13_IRQ R14_IRQ
+ std::array<u32, 7> Reg_firq{}; // R8---R14 FIRQ
+ std::array<u32, 7> Spsr{}; // The exception psr's
+ std::array<u32, CP15_REGISTER_COUNT> CP15{};
// FPSID, FPSCR, and FPEXC
- std::array<u32, VFP_SYSTEM_REGISTER_COUNT> VFP;
+ std::array<u32, VFP_SYSTEM_REGISTER_COUNT> VFP{};
// VFPv2 and VFPv3-D16 has 16 doubleword registers (D0-D16 or S0-S31).
// VFPv3-D32/ASIMD may have up to 32 doubleword registers (D0-D31),
// and only 32 singleword registers are accessible (S0-S31).
- std::array<u32, 64> ExtReg;
+ std::array<u32, 64> ExtReg{};
u32 Emulate; // To start and stop emulation
u32 Cpsr; // The current PSR
diff --git a/src/core/core.h b/src/core/core.h
index 278f0f1cc..491230a74 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -18,7 +18,7 @@ struct ThreadContext {
u32 lr;
u32 pc;
u32 cpsr;
- u32 fpu_registers[32];
+ u32 fpu_registers[64];
u32 fpscr;
u32 fpexc;
};
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 5846a161b..3501e45db 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -159,6 +159,14 @@ template<ResultCode func(s32*, u32, s32)> void Wrap() {
FuncReturn(retval);
}
+template<ResultCode func(s64*, u32, s32)> void Wrap() {
+ s64 param_1 = 0;
+ u32 retval = func(&param_1, PARAM(1), PARAM(2)).raw;
+ Core::g_app_core->SetReg(1, (u32)param_1);
+ Core::g_app_core->SetReg(2, (u32)(param_1 >> 32));
+ FuncReturn(retval);
+}
+
template<ResultCode func(u32*, u32, u32, u32, u32)> void Wrap() {
u32 param_1 = 0;
u32 retval = func(&param_1, PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw;
diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp
index e4fc5f3c4..0cfb43fc7 100644
--- a/src/core/hle/kernel/memory.cpp
+++ b/src/core/hle/kernel/memory.cpp
@@ -51,6 +51,7 @@ void MemoryInit(u32 mem_type) {
for (int i = 0; i < 3; ++i) {
memory_regions[i].base = base;
memory_regions[i].size = memory_region_sizes[mem_type][i];
+ memory_regions[i].used = 0;
memory_regions[i].linear_heap_memory = std::make_shared<std::vector<u8>>();
base += memory_regions[i].size;
@@ -72,6 +73,7 @@ void MemoryShutdown() {
for (auto& region : memory_regions) {
region.base = 0;
region.size = 0;
+ region.used = 0;
region.linear_heap_memory = nullptr;
}
}
diff --git a/src/core/hle/kernel/memory.h b/src/core/hle/kernel/memory.h
index 36690b091..091c1f89f 100644
--- a/src/core/hle/kernel/memory.h
+++ b/src/core/hle/kernel/memory.h
@@ -17,6 +17,7 @@ class VMManager;
struct MemoryRegionInfo {
u32 base; // Not an address, but offset from start of FCRAM
u32 size;
+ u32 used;
std::shared_ptr<std::vector<u8>> linear_heap_memory;
};
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index c2b4963d4..d148efde2 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -111,6 +111,7 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) {
segment.offset, segment.size, memory_state).Unwrap();
vm_manager.Reprotect(vma, permissions);
misc_memory_used += segment.size;
+ memory_region->used += segment.size;
};
// Map CodeSet segments
@@ -123,6 +124,7 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) {
std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size, MemoryState::Locked
).Unwrap();
misc_memory_used += stack_size;
+ memory_region->used += stack_size;
vm_manager.LogLayout(Log::Level::Debug);
Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority);
@@ -165,6 +167,7 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission per
vm_manager.Reprotect(vma, perms);
heap_used += size;
+ memory_region->used += size;
return MakeResult<VAddr>(heap_end - size);
}
@@ -182,6 +185,7 @@ ResultCode Process::HeapFree(VAddr target, u32 size) {
if (result.IsError()) return result;
heap_used -= size;
+ memory_region->used -= size;
return RESULT_SUCCESS;
}
@@ -217,6 +221,7 @@ ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission p
vm_manager.Reprotect(vma, perms);
linear_heap_used += size;
+ memory_region->used += size;
return MakeResult<VAddr>(target);
}
@@ -243,6 +248,7 @@ ResultCode Process::LinearFree(VAddr target, u32 size) {
if (result.IsError()) return result;
linear_heap_used -= size;
+ memory_region->used -= size;
if (target + size == heap_end) {
// End of linear heap has been freed, so check what's the last allocated block in it and
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 00fa995f6..c08fc1c7a 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -20,6 +20,7 @@
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/thread.h"
+#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/result.h"
#include "core/memory.h"
@@ -118,6 +119,7 @@ void Thread::Stop() {
Kernel::g_current_process->used_tls_slots[tls_index] = false;
g_current_process->misc_memory_used -= Memory::TLS_ENTRY_SIZE;
+ g_current_process->memory_region->used -= Memory::TLS_ENTRY_SIZE;
HLE::Reschedule(__func__);
}
@@ -416,6 +418,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
ASSERT_MSG(thread->tls_index != -1, "Out of TLS space");
g_current_process->misc_memory_used += Memory::TLS_ENTRY_SIZE;
+ g_current_process->memory_region->used += Memory::TLS_ENTRY_SIZE;
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
// to initialize the context
diff --git a/src/core/hle/service/csnd_snd.cpp b/src/core/hle/service/csnd_snd.cpp
index ce2877f57..669659510 100644
--- a/src/core/hle/service/csnd_snd.cpp
+++ b/src/core/hle/service/csnd_snd.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstring>
#include "core/hle/hle.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/shared_memory.h"
@@ -52,19 +53,19 @@ void Initialize(Service::Interface* self) {
}
void ExecuteType0Commands(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32* const cmd_buff = Kernel::GetCommandBuffer();
+ u8* const ptr = shared_memory->GetPointer(cmd_buff[1]);
+
+ if (shared_memory != nullptr && ptr != nullptr) {
+ Type0Command command;
+ std::memcpy(&command, ptr, sizeof(Type0Command));
+
+ LOG_WARNING(Service, "(STUBBED) CSND_SND::ExecuteType0Commands");
+ command.finished |= 1;
+ cmd_buff[1] = 0;
- if (shared_memory != nullptr) {
- struct Type0Command* command = reinterpret_cast<struct Type0Command*>(
- shared_memory->GetPointer(cmd_buff[1]));
- if (command == nullptr) {
- cmd_buff[1] = 1;
- }else{
- LOG_WARNING(Service, "(STUBBED) CSND_SND::ExecuteType0Commands");
- command->finished |= 1;
- cmd_buff[1] = 0;
- }
- }else{
+ std::memcpy(ptr, &command, sizeof(Type0Command));
+ } else {
cmd_buff[1] = 1;
}
}
diff --git a/src/core/hle/service/ssl_c.cpp b/src/core/hle/service/ssl_c.cpp
index 04ab194e6..cabd18c80 100644
--- a/src/core/hle/service/ssl_c.cpp
+++ b/src/core/hle/service/ssl_c.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <random>
+
#include "core/hle/hle.h"
#include "core/hle/service/ssl_c.h"
@@ -10,11 +12,58 @@
namespace SSL_C {
+// TODO: Implement a proper CSPRNG in the future when actual security is needed
+static std::mt19937 rand_gen;
+
+static void Initialize(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ // Seed random number generator when the SSL service is initialized
+ std::random_device rand_device;
+ rand_gen.seed(rand_device());
+
+ // Stub, return success
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+}
+
+static void GenerateRandomData(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u32 size = cmd_buff[1];
+ VAddr address = cmd_buff[3];
+ u8* output_buff = Memory::GetPointer(address);
+
+ // Fill the output buffer with random data.
+ u32 data = 0;
+ u32 i = 0;
+ while (i < size) {
+ if ((i % 4) == 0) {
+ // The random number generator returns 4 bytes worth of data, so generate new random data when i == 0 and when i is divisible by 4
+ data = rand_gen();
+ }
+
+ if (size > 4) {
+ // Use up the entire 4 bytes of the random data for as long as possible
+ *(u32*)(output_buff + i) = data;
+ i += 4;
+ } else if (size == 2) {
+ *(u16*)(output_buff + i) = (u16)(data & 0xffff);
+ i += 2;
+ } else {
+ *(u8*)(output_buff + i) = (u8)(data & 0xff);
+ i++;
+ }
+ }
+
+ // Stub, return success
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+}
+
const Interface::FunctionInfo FunctionTable[] = {
- {0x00010002, nullptr, "Initialize"},
+ {0x00010002, Initialize, "Initialize"},
{0x000200C2, nullptr, "CreateContext"},
{0x00050082, nullptr, "AddTrustedRootCA"},
- {0x00110042, nullptr, "GenerateRandomData"},
+ {0x00110042, GenerateRandomData, "GenerateRandomData"},
{0x00150082, nullptr, "Read"},
{0x00170082, nullptr, "Write"},
};
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 45d5f3c5d..7f63ff505 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -778,6 +778,51 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32
return RESULT_SUCCESS;
}
+static ResultCode GetSystemInfo(s64* out, u32 type, s32 param) {
+ using Kernel::MemoryRegion;
+
+ LOG_TRACE(Kernel_SVC, "called process=0x%08X type=%u param=%d", process_handle, type, param);
+
+ switch ((SystemInfoType)type) {
+ case SystemInfoType::REGION_MEMORY_USAGE:
+ switch ((SystemInfoMemUsageRegion)param) {
+ case SystemInfoMemUsageRegion::ALL:
+ *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::APPLICATION)->used
+ + Kernel::GetMemoryRegion(Kernel::MemoryRegion::SYSTEM)->used
+ + Kernel::GetMemoryRegion(Kernel::MemoryRegion::BASE)->used;
+ break;
+ case SystemInfoMemUsageRegion::APPLICATION:
+ *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::APPLICATION)->used;
+ break;
+ case SystemInfoMemUsageRegion::SYSTEM:
+ *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::SYSTEM)->used;
+ break;
+ case SystemInfoMemUsageRegion::BASE:
+ *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::BASE)->used;
+ break;
+ default:
+ LOG_ERROR(Kernel_SVC, "unknown GetSystemInfo type=0 region: param=%d", param);
+ *out = 0;
+ break;
+ }
+ break;
+ case SystemInfoType::KERNEL_ALLOCATED_PAGES:
+ LOG_ERROR(Kernel_SVC, "unimplemented GetSystemInfo type=2 param=%d", type, param);
+ *out = 0;
+ break;
+ case SystemInfoType::KERNEL_SPAWNED_PIDS:
+ *out = 5;
+ break;
+ default:
+ LOG_ERROR(Kernel_SVC, "unknown GetSystemInfo type=%u param=%d", type, param);
+ *out = 0;
+ break;
+ }
+
+ // This function never returns an error, even if invalid parameters were passed.
+ return RESULT_SUCCESS;
+}
+
static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) {
LOG_TRACE(Kernel_SVC, "called process=0x%08X type=%u", process_handle, type);
@@ -877,7 +922,7 @@ static const FunctionDef SVC_Table[] = {
{0x27, HLE::Wrap<DuplicateHandle>, "DuplicateHandle"},
{0x28, HLE::Wrap<GetSystemTick>, "GetSystemTick"},
{0x29, nullptr, "GetHandleInfo"},
- {0x2A, nullptr, "GetSystemInfo"},
+ {0x2A, HLE::Wrap<GetSystemInfo>, "GetSystemInfo"},
{0x2B, HLE::Wrap<GetProcessInfo>, "GetProcessInfo"},
{0x2C, nullptr, "GetThreadInfo"},
{0x2D, HLE::Wrap<ConnectToPort>, "ConnectToPort"},
diff --git a/src/core/hle/svc.h b/src/core/hle/svc.h
index 12de9ffbe..4b9c71e06 100644
--- a/src/core/hle/svc.h
+++ b/src/core/hle/svc.h
@@ -41,6 +41,35 @@ enum ArbitrationType {
namespace SVC {
+/// Values accepted by svcGetSystemInfo's type parameter.
+enum class SystemInfoType {
+ /**
+ * Reports total used memory for all regions or a specific one, according to the extra
+ * parameter. See `SystemInfoMemUsageRegion`.
+ */
+ REGION_MEMORY_USAGE = 0,
+ /**
+ * Returns the memory usage for certain allocations done internally by the kernel.
+ */
+ KERNEL_ALLOCATED_PAGES = 2,
+ /**
+ * "This returns the total number of processes which were launched directly by the kernel.
+ * For the ARM11 NATIVE_FIRM kernel, this is 5, for processes sm, fs, pm, loader, and pxi."
+ */
+ KERNEL_SPAWNED_PIDS = 26,
+};
+
+/**
+ * Accepted by svcGetSystemInfo param with REGION_MEMORY_USAGE type. Selects a region to query
+ * memory usage of.
+ */
+enum class SystemInfoMemUsageRegion {
+ ALL = 0,
+ APPLICATION = 1,
+ SYSTEM = 2,
+ BASE = 3,
+};
+
void CallSVC(u32 immediate);
} // namespace
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index 226fad783..ecfdbc9e8 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -498,7 +498,8 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0,
// with some basic arithmetic. Alpha combiners can be configured separately but work
// analogously.
Math::Vec4<u8> combiner_output;
- Math::Vec4<u8> combiner_buffer = {
+ Math::Vec4<u8> combiner_buffer = {0, 0, 0, 0};
+ Math::Vec4<u8> next_combiner_buffer = {
regs.tev_combiner_buffer_color.r, regs.tev_combiner_buffer_color.g,
regs.tev_combiner_buffer_color.b, regs.tev_combiner_buffer_color.a
};
@@ -747,14 +748,16 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0,
combiner_output[2] = std::min((unsigned)255, color_output.b() * tev_stage.GetColorMultiplier());
combiner_output[3] = std::min((unsigned)255, alpha_output * tev_stage.GetAlphaMultiplier());
+ combiner_buffer = next_combiner_buffer;
+
if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_index)) {
- combiner_buffer.r() = combiner_output.r();
- combiner_buffer.g() = combiner_output.g();
- combiner_buffer.b() = combiner_output.b();
+ next_combiner_buffer.r() = combiner_output.r();
+ next_combiner_buffer.g() = combiner_output.g();
+ next_combiner_buffer.b() = combiner_output.b();
}
if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_index)) {
- combiner_buffer.a() = combiner_output.a();
+ next_combiner_buffer.a() = combiner_output.a();
}
}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 9b4bddabd..822739088 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -492,9 +492,12 @@ void RasterizerOpenGL::SetShader() {
state.Apply();
// Set the texture samplers to correspond to different texture units
- glUniform1i(PicaShader::Uniform::Texture0, 0);
- glUniform1i(PicaShader::Uniform::Texture1, 1);
- glUniform1i(PicaShader::Uniform::Texture2, 2);
+ GLuint uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[0]");
+ if (uniform_tex != -1) { glUniform1i(uniform_tex, 0); }
+ uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[1]");
+ if (uniform_tex != -1) { glUniform1i(uniform_tex, 1); }
+ uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[2]");
+ if (uniform_tex != -1) { glUniform1i(uniform_tex, 2); }
current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get();
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 071051dbc..5ba898189 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -138,13 +138,6 @@ public:
struct PicaShader {
/// OpenGL shader resource
OGLShader shader;
-
- /// Fragment shader uniforms
- enum Uniform : GLuint {
- Texture0 = 0,
- Texture1 = 1,
- Texture2 = 2,
- };
};
private:
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index 3f1cf7a6f..498c506e7 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -311,18 +311,18 @@ static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsi
"clamp(alpha_output_" + index_name + " * " + std::to_string(stage.GetAlphaMultiplier()) + ".0, 0.0, 1.0));\n";
}
+ out += "combiner_buffer = next_combiner_buffer;\n";
+
if (config.TevStageUpdatesCombinerBufferColor(index))
- out += "combiner_buffer.rgb = last_tex_env_out.rgb;\n";
+ out += "next_combiner_buffer.rgb = last_tex_env_out.rgb;\n";
if (config.TevStageUpdatesCombinerBufferAlpha(index))
- out += "combiner_buffer.a = last_tex_env_out.a;\n";
+ out += "next_combiner_buffer.a = last_tex_env_out.a;\n";
}
std::string GenerateFragmentShader(const PicaShaderConfig& config) {
std::string out = R"(
-#version 330
-#extension GL_ARB_explicit_uniform_location : require
-
+#version 330 core
#define NUM_TEV_STAGES 6
in vec4 primary_color;
@@ -336,14 +336,10 @@ layout (std140) uniform shader_data {
int alphatest_ref;
};
-)";
+uniform sampler2D tex[3];
- using Uniform = RasterizerOpenGL::PicaShader::Uniform;
- out += "layout(location = " + std::to_string((int)Uniform::Texture0) + ") uniform sampler2D tex[3];\n";
-
- out += "void main() {\n";
- out += "vec4 combiner_buffer = tev_combiner_buffer_color;\n";
- out += "vec4 last_tex_env_out = vec4(0.0);\n";
+void main() {
+)";
// Do not do any sort of processing if it's obvious we're not going to pass the alpha test
if (config.alpha_test_func == Regs::CompareFunc::Never) {
@@ -351,6 +347,10 @@ layout (std140) uniform shader_data {
return out;
}
+ out += "vec4 combiner_buffer = vec4(0.0);\n";
+ out += "vec4 next_combiner_buffer = tev_combiner_buffer_color;\n";
+ out += "vec4 last_tex_env_out = vec4(0.0);\n";
+
for (size_t index = 0; index < config.tev_stages.size(); ++index)
WriteTevStage(out, config, (unsigned)index);
@@ -366,7 +366,7 @@ layout (std140) uniform shader_data {
}
std::string GenerateVertexShader() {
- std::string out = "#version 330\n";
+ std::string out = "#version 330 core\n";
out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) + ") in vec4 vert_position;\n";
out += "layout(location = " + std::to_string((int)ATTRIBUTE_COLOR) + ") in vec4 vert_color;\n";
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0) + ") in vec2 vert_texcoord0;\n";