Compare commits

..

1 Commits

Author SHA1 Message Date
FernandoS27 e0ea2f5f6e Fixed Layered Textures Loading and Cubemaps 2018-10-23 14:27:36 -04:00
40 changed files with 551 additions and 724 deletions
+5 -1
View File
@@ -170,7 +170,7 @@ endif()
# On modern Unixes, this is typically already the case. The lone exception is
# glibc, which may default to 32 bits. glibc allows this to be configured
# by setting _FILE_OFFSET_BITS.
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR MINGW)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_definitions(-D_FILE_OFFSET_BITS=64)
endif()
@@ -178,6 +178,10 @@ endif()
set_property(DIRECTORY APPEND PROPERTY
COMPILE_DEFINITIONS $<$<CONFIG:Debug>:_DEBUG> $<$<NOT:$<CONFIG:Debug>>:NDEBUG>)
math(EXPR EMU_ARCH_BITS ${CMAKE_SIZEOF_VOID_P}*8)
add_definitions(-DEMU_ARCH_BITS=${EMU_ARCH_BITS})
# System imported libraries
# ======================
+2
View File
@@ -64,6 +64,8 @@ add_library(common STATIC
logging/text_formatter.cpp
logging/text_formatter.h
math_util.h
memory_util.cpp
memory_util.h
microprofile.cpp
microprofile.h
microprofileui.h
+5 -8
View File
@@ -15,24 +15,21 @@
#ifdef _WIN32
#include <windows.h>
// windows.h needs to be included before other windows headers
#include <direct.h> // getcwd
#include <commdlg.h> // for GetSaveFileName
#include <direct.h> // getcwd
#include <io.h>
#include <shellapi.h>
#include <shlobj.h> // for SHGetFolderPath
#include <tchar.h>
#include "common/string_util.h"
#ifdef _MSC_VER
// 64 bit offsets for MSVC
// 64 bit offsets for windows
#define fseeko _fseeki64
#define ftello _ftelli64
#define fileno _fileno
#endif
// 64 bit offsets for MSVC and MinGW. MinGW also needs this for using _wstat64
#define atoll _atoi64
#define stat _stat64
#define fstat _fstat64
#define fileno _fileno
#else
#ifdef __APPLE__
#include <sys/param.h>
-1
View File
@@ -91,7 +91,6 @@ enum class Class : ClassType {
Service_PM, ///< The PM service
Service_PREPO, ///< The PREPO (Play report) service
Service_PSC, ///< The PSC service
Service_PSM, ///< The PSM service
Service_SET, ///< The SET (Settings) service
Service_SM, ///< The SM (Service manager) service
Service_SPL, ///< The SPL service
+177
View File
@@ -0,0 +1,177 @@
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/logging/log.h"
#include "common/memory_util.h"
#ifdef _WIN32
#include <windows.h>
// Windows.h needs to be included before psapi.h
#include <psapi.h>
#include "common/common_funcs.h"
#include "common/string_util.h"
#else
#include <cstdlib>
#include <sys/mman.h>
#endif
#if !defined(_WIN32) && defined(ARCHITECTURE_x86_64) && !defined(MAP_32BIT)
#include <unistd.h>
#define PAGE_MASK (getpagesize() - 1)
#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK))
#endif
// This is purposely not a full wrapper for virtualalloc/mmap, but it
// provides exactly the primitive operations that Dolphin needs.
void* AllocateExecutableMemory(std::size_t size, bool low) {
#if defined(_WIN32)
void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
#else
static char* map_hint = nullptr;
#if defined(ARCHITECTURE_x86_64) && !defined(MAP_32BIT)
// This OS has no flag to enforce allocation below the 4 GB boundary,
// but if we hint that we want a low address it is very likely we will
// get one.
// An older version of this code used MAP_FIXED, but that has the side
// effect of discarding already mapped pages that happen to be in the
// requested virtual memory range (such as the emulated RAM, sometimes).
if (low && (!map_hint))
map_hint = (char*)round_page(512 * 1024 * 1024); /* 0.5 GB rounded up to the next page */
#endif
void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_ANON | MAP_PRIVATE
#if defined(ARCHITECTURE_x86_64) && defined(MAP_32BIT)
| (low ? MAP_32BIT : 0)
#endif
,
-1, 0);
#endif /* defined(_WIN32) */
#ifdef _WIN32
if (ptr == nullptr) {
#else
if (ptr == MAP_FAILED) {
ptr = nullptr;
#endif
LOG_ERROR(Common_Memory, "Failed to allocate executable memory");
}
#if !defined(_WIN32) && defined(ARCHITECTURE_x86_64) && !defined(MAP_32BIT)
else {
if (low) {
map_hint += size;
map_hint = (char*)round_page(map_hint); /* round up to the next page */
}
}
#endif
#if EMU_ARCH_BITS == 64
if ((u64)ptr >= 0x80000000 && low == true)
LOG_ERROR(Common_Memory, "Executable memory ended up above 2GB!");
#endif
return ptr;
}
void* AllocateMemoryPages(std::size_t size) {
#ifdef _WIN32
void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE);
#else
void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
if (ptr == MAP_FAILED)
ptr = nullptr;
#endif
if (ptr == nullptr)
LOG_ERROR(Common_Memory, "Failed to allocate raw memory");
return ptr;
}
void* AllocateAlignedMemory(std::size_t size, std::size_t alignment) {
#ifdef _WIN32
void* ptr = _aligned_malloc(size, alignment);
#else
void* ptr = nullptr;
#ifdef ANDROID
ptr = memalign(alignment, size);
#else
if (posix_memalign(&ptr, alignment, size) != 0)
LOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
#endif
#endif
if (ptr == nullptr)
LOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
return ptr;
}
void FreeMemoryPages(void* ptr, std::size_t size) {
if (ptr) {
#ifdef _WIN32
if (!VirtualFree(ptr, 0, MEM_RELEASE))
LOG_ERROR(Common_Memory, "FreeMemoryPages failed!\n{}", GetLastErrorMsg());
#else
munmap(ptr, size);
#endif
}
}
void FreeAlignedMemory(void* ptr) {
if (ptr) {
#ifdef _WIN32
_aligned_free(ptr);
#else
free(ptr);
#endif
}
}
void WriteProtectMemory(void* ptr, std::size_t size, bool allowExecute) {
#ifdef _WIN32
DWORD oldValue;
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue))
LOG_ERROR(Common_Memory, "WriteProtectMemory failed!\n{}", GetLastErrorMsg());
#else
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ);
#endif
}
void UnWriteProtectMemory(void* ptr, std::size_t size, bool allowExecute) {
#ifdef _WIN32
DWORD oldValue;
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE,
&oldValue))
LOG_ERROR(Common_Memory, "UnWriteProtectMemory failed!\n{}", GetLastErrorMsg());
#else
mprotect(ptr, size,
allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ);
#endif
}
std::string MemUsage() {
#ifdef _WIN32
#pragma comment(lib, "psapi")
DWORD processID = GetCurrentProcessId();
HANDLE hProcess;
PROCESS_MEMORY_COUNTERS pmc;
std::string Ret;
// Print information about the memory usage of the process.
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
if (nullptr == hProcess)
return "MemUsage Error";
if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
Ret = fmt::format("{} K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7));
CloseHandle(hProcess);
return Ret;
#else
return "";
#endif
}
+21
View File
@@ -0,0 +1,21 @@
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <cstddef>
#include <string>
void* AllocateExecutableMemory(std::size_t size, bool low = true);
void* AllocateMemoryPages(std::size_t size);
void FreeMemoryPages(void* ptr, std::size_t size);
void* AllocateAlignedMemory(std::size_t size, std::size_t alignment);
void FreeAlignedMemory(void* ptr);
void WriteProtectMemory(void* ptr, std::size_t size, bool executable = false);
void UnWriteProtectMemory(void* ptr, std::size_t size, bool allowExecute = false);
std::string MemUsage();
inline int GetPageSize() {
return 4096;
}
-6
View File
@@ -156,8 +156,6 @@ add_library(core STATIC
hle/service/am/omm.h
hle/service/am/spsm.cpp
hle/service/am/spsm.h
hle/service/am/tcap.cpp
hle/service/am/tcap.h
hle/service/aoc/aoc_u.cpp
hle/service/aoc/aoc_u.h
hle/service/apm/apm.cpp
@@ -282,8 +280,6 @@ add_library(core STATIC
hle/service/nifm/nifm.h
hle/service/nim/nim.cpp
hle/service/nim/nim.h
hle/service/npns/npns.cpp
hle/service/npns/npns.h
hle/service/ns/ns.cpp
hle/service/ns/ns.h
hle/service/ns/pl_u.cpp
@@ -331,8 +327,6 @@ add_library(core STATIC
hle/service/prepo/prepo.h
hle/service/psc/psc.cpp
hle/service/psc/psc.h
hle/service/ptm/psm.cpp
hle/service/ptm/psm.h
hle/service/service.cpp
hle/service/service.h
hle/service/set/set.cpp
+1 -1
View File
@@ -654,7 +654,7 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i
}
auto vma = process->VMManager().FindVMA(addr);
memory_info->attributes = 0;
if (vma == process->VMManager().vma_map.end()) {
if (vma == Core::CurrentProcess()->VMManager().vma_map.end()) {
memory_info->base_address = 0;
memory_info->permission = static_cast<u32>(VMAPermission::None);
memory_info->size = 0;
+12 -52
View File
@@ -15,7 +15,6 @@
#include "core/hle/service/am/idle.h"
#include "core/hle/service/am/omm.h"
#include "core/hle/service/am/spsm.h"
#include "core/hle/service/am/tcap.h"
#include "core/hle/service/apm/apm.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/nvflinger/nvflinger.h"
@@ -27,18 +26,13 @@
namespace Service::AM {
IWindowController::IWindowController() : ServiceFramework("IWindowController") {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "CreateWindow"},
{1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"},
{10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"},
{11, nullptr, "ReleaseForegroundRights"},
{12, nullptr, "RejectToChangeIntoBackground"},
{20, nullptr, "SetAppletWindowVisibility"},
{21, nullptr, "SetAppletGpuTimeSlice"},
};
// clang-format on
RegisterHandlers(functions);
}
@@ -93,7 +87,6 @@ void IAudioController::GetLibraryAppletExpectedMasterVolume(Kernel::HLERequestCo
}
IDisplayController::IDisplayController() : ServiceFramework("IDisplayController") {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetLastForegroundCaptureImage"},
{1, nullptr, "UpdateLastForegroundCaptureImage"},
@@ -124,11 +117,7 @@ IDisplayController::IDisplayController() : ServiceFramework("IDisplayController"
{25, nullptr, "ReleaseLastForegroundCaptureSharedBuffer"},
{26, nullptr, "AcquireCallerAppletCaptureSharedBuffer"},
{27, nullptr, "ReleaseCallerAppletCaptureSharedBuffer"},
// 6.0.0+
{28, nullptr, "TakeScreenShotOfOwnLayerEx"},
};
// clang-format on
RegisterHandlers(functions);
}
@@ -139,7 +128,6 @@ IDebugFunctions::~IDebugFunctions() = default;
ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
: ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "Exit"},
{1, &ISelfController::LockExit, "LockExit"},
@@ -148,8 +136,10 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
{4, nullptr, "LeaveFatalSection"},
{9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"},
{10, &ISelfController::SetScreenShotPermission, "SetScreenShotPermission"},
{11, &ISelfController::SetOperationModeChangedNotification, "SetOperationModeChangedNotification"},
{12, &ISelfController::SetPerformanceModeChangedNotification, "SetPerformanceModeChangedNotification"},
{11, &ISelfController::SetOperationModeChangedNotification,
"SetOperationModeChangedNotification"},
{12, &ISelfController::SetPerformanceModeChangedNotification,
"SetPerformanceModeChangedNotification"},
{13, &ISelfController::SetFocusHandlingMode, "SetFocusHandlingMode"},
{14, &ISelfController::SetRestartMessageEnabled, "SetRestartMessageEnabled"},
{15, nullptr, "SetScreenShotAppletIdentityInfo"},
@@ -175,12 +165,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
{69, nullptr, "IsAutoSleepDisabled"},
{70, nullptr, "ReportMultimediaError"},
{80, nullptr, "SetWirelessPriorityMode"},
{90, nullptr, "GetAccumulatedSuspendedTickValue"},
{91, nullptr, "GetAccumulatedSuspendedTickChangedEvent"},
{1000, nullptr, "GetDebugStorageChannel"},
};
// clang-format on
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
@@ -327,7 +312,6 @@ void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& c
}
ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter") {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
{1, &ICommonStateGetter::ReceiveMessage, "ReceiveMessage"},
@@ -352,12 +336,11 @@ ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter"
{52, nullptr, "SwitchLcdBacklight"},
{55, nullptr, "IsInControllerFirmwareUpdateSection"},
{60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"},
{61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"},
{61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent,
"GetDefaultDisplayResolutionChangeEvent"},
{62, nullptr, "GetHdcpAuthenticationState"},
{63, nullptr, "GetHdcpAuthenticationStateChangeEvent"},
};
// clang-format on
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
@@ -449,14 +432,11 @@ class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
public:
explicit IStorageAccessor(std::vector<u8> buffer)
: ServiceFramework("IStorageAccessor"), buffer(std::move(buffer)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IStorageAccessor::GetSize, "GetSize"},
{10, &IStorageAccessor::Write, "Write"},
{11, &IStorageAccessor::Read, "Read"},
};
// clang-format on
RegisterHandlers(functions);
}
@@ -509,13 +489,10 @@ class IStorage final : public ServiceFramework<IStorage> {
public:
explicit IStorage(std::vector<u8> buffer)
: ServiceFramework("IStorage"), buffer(std::move(buffer)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IStorage::Open, "Open"},
{1, nullptr, "OpenTransferStorage"},
};
// clang-format on
RegisterHandlers(functions);
}
@@ -535,7 +512,6 @@ private:
class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
public:
explicit ILibraryAppletAccessor() : ServiceFramework("ILibraryAppletAccessor") {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
{1, nullptr, "IsCompleted"},
@@ -556,8 +532,6 @@ public:
{150, nullptr, "RequestForAppletToGetForeground"},
{160, nullptr, "GetIndirectLayerConsumerHandle"},
};
// clang-format on
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
@@ -650,13 +624,13 @@ void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
}
IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") {
// clang-format off
static const FunctionInfo functions[] = {
{1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"},
{10, nullptr, "CreateApplicationAndPushAndRequestToStart"},
{11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"},
{12, nullptr, "CreateApplicationAndRequestToStart"},
{13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest, "CreateApplicationAndRequestToStartForQuest"},
{13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest,
"CreateApplicationAndRequestToStartForQuest"},
{20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"},
{21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"},
{22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"},
@@ -664,8 +638,10 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
{24, nullptr, "GetLaunchStorageInfoForDebug"},
{25, nullptr, "ExtendSaveData"},
{26, nullptr, "GetSaveDataSize"},
{30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"},
{31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"},
{30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed,
"BeginBlockingHomeButtonShortAndLongPressed"},
{31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed,
"EndBlockingHomeButtonShortAndLongPressed"},
{32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"},
{33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"},
{40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"},
@@ -690,8 +666,6 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
{1000, nullptr, "CreateMovieMaker"},
{1001, nullptr, "PrepareForJit"},
};
// clang-format on
RegisterHandlers(functions);
}
@@ -830,11 +804,9 @@ void InstallInterfaces(SM::ServiceManager& service_manager,
std::make_shared<IdleSys>()->InstallAsService(service_manager);
std::make_shared<OMM>()->InstallAsService(service_manager);
std::make_shared<SPSM>()->InstallAsService(service_manager);
std::make_shared<TCAP>()->InstallAsService(service_manager);
}
IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions") {
// clang-format off
static const FunctionInfo functions[] = {
{10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"},
{11, nullptr, "LockForeground"},
@@ -843,10 +815,7 @@ IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions"
{21, nullptr, "GetPopFromGeneralChannelEvent"},
{30, nullptr, "GetHomeButtonWriterLockAccessor"},
{31, nullptr, "GetWriterLockAccessorEx"},
{100, nullptr, "PopRequestLaunchApplicationForDebug"},
};
// clang-format on
RegisterHandlers(functions);
}
@@ -859,7 +828,6 @@ void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx)
}
IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "RequestToEnterSleep"},
{1, nullptr, "EnterSleep"},
@@ -873,23 +841,18 @@ IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStat
{14, nullptr, "ShouldSleepOnBoot"},
{15, nullptr, "GetHdcpAuthenticationFailedEvent"},
};
// clang-format on
RegisterHandlers(functions);
}
IGlobalStateController::~IGlobalStateController() = default;
IApplicationCreator::IApplicationCreator() : ServiceFramework("IApplicationCreator") {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "CreateApplication"},
{1, nullptr, "PopLaunchRequestedApplication"},
{10, nullptr, "CreateSystemApplication"},
{100, nullptr, "PopFloatingApplicationForDevelopment"},
};
// clang-format on
RegisterHandlers(functions);
}
@@ -897,7 +860,6 @@ IApplicationCreator::~IApplicationCreator() = default;
IProcessWindingController::IProcessWindingController()
: ServiceFramework("IProcessWindingController") {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetLaunchReason"},
{11, nullptr, "OpenCallingLibraryApplet"},
@@ -908,8 +870,6 @@ IProcessWindingController::IProcessWindingController()
{40, nullptr, "ReserveToStartAndWaitAndUnwindThis"},
{41, nullptr, "ReserveToStartAndWait"},
};
// clang-format on
RegisterHandlers(functions);
}
-4
View File
@@ -211,7 +211,6 @@ void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
: ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)) {
// clang-format off
static const FunctionInfo functions[] = {
{100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"},
{200, &AppletAE::OpenLibraryAppletProxyOld, "OpenLibraryAppletProxyOld"},
@@ -219,10 +218,7 @@ AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
{300, nullptr, "OpenOverlayAppletProxy"},
{350, nullptr, "OpenSystemApplicationProxy"},
{400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"},
{401, nullptr, "GetSystemAppletControllerForDebug"},
};
// clang-format on
RegisterHandlers(functions);
}
-3
View File
@@ -14,7 +14,6 @@ class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
public:
explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
: ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
{1, &IApplicationProxy::GetSelfController, "GetSelfController"},
@@ -26,8 +25,6 @@ public:
{20, &IApplicationProxy::GetApplicationFunctions, "GetApplicationFunctions"},
{1000, &IApplicationProxy::GetDebugFunctions, "GetDebugFunctions"},
};
// clang-format on
RegisterHandlers(functions);
}
+3 -3
View File
@@ -12,9 +12,9 @@ IdleSys::IdleSys() : ServiceFramework{"idle:sys"} {
{0, nullptr, "GetAutoPowerDownEvent"},
{1, nullptr, "Unknown1"},
{2, nullptr, "Unknown2"},
{3, nullptr, "SetHandlingContext"},
{4, nullptr, "LoadAndApplySettings"},
{5, nullptr, "ReportUserIsActive"},
{3, nullptr, "Unknown3"},
{4, nullptr, "Unknown4"},
{5, nullptr, "Unknown5"},
};
// clang-format on
-23
View File
@@ -1,23 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/hle/service/am/tcap.h"
namespace Service::AM {
TCAP::TCAP() : ServiceFramework{"tcap"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetContinuousHighSkinTemperatureEvent"},
{1, nullptr, "SetOperationMode"},
{2, nullptr, "LoadAndApplySettings"},
};
// clang-format on
RegisterHandlers(functions);
}
TCAP::~TCAP() = default;
} // namespace Service::AM
-17
View File
@@ -1,17 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/service/service.h"
namespace Service::AM {
class TCAP final : public ServiceFramework<TCAP> {
public:
explicit TCAP();
~TCAP() override;
};
} // namespace Service::AM
-1
View File
@@ -827,7 +827,6 @@ public:
{11, nullptr, "EnableJoyPollingReceiveMode"},
{12, nullptr, "DisableJoyPollingReceiveMode"},
{13, nullptr, "GetPollingData"},
{14, nullptr, "SetStatusManagerType"},
};
// clang-format on
+28 -28
View File
@@ -18,35 +18,35 @@ public:
explicit LBL() : ServiceFramework{"lbl"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "SaveCurrentSetting"},
{1, nullptr, "LoadCurrentSetting"},
{2, nullptr, "SetCurrentBrightnessSetting"},
{3, nullptr, "GetCurrentBrightnessSetting"},
{4, nullptr, "ApplyCurrentBrightnessSettingToBacklight"},
{5, nullptr, "GetBrightnessSettingAppliedToBacklight"},
{6, nullptr, "SwitchBacklightOn"},
{7, nullptr, "SwitchBacklightOff"},
{8, nullptr, "GetBacklightSwitchStatus"},
{9, nullptr, "EnableDimming"},
{10, nullptr, "DisableDimming"},
{11, nullptr, "IsDimmingEnabled"},
{12, nullptr, "EnableAutoBrightnessControl"},
{13, nullptr, "DisableAutoBrightnessControl"},
{14, nullptr, "IsAutoBrightnessControlEnabled"},
{15, nullptr, "SetAmbientLightSensorValue"},
{16, nullptr, "GetAmbientLightSensorValue"},
{17, nullptr, "SetBrightnessReflectionDelayLevel"},
{18, nullptr, "GetBrightnessReflectionDelayLevel"},
{19, nullptr, "SetCurrentBrightnessMapping"},
{20, nullptr, "GetCurrentBrightnessMapping"},
{21, nullptr, "SetCurrentAmbientLightSensorMapping"},
{22, nullptr, "GetCurrentAmbientLightSensorMapping"},
{23, nullptr, "IsAmbientLightSensorAvailable"},
{24, nullptr, "SetCurrentBrightnessSettingForVrMode"},
{25, nullptr, "GetCurrentBrightnessSettingForVrMode"},
{0, nullptr, "Unknown1"},
{1, nullptr, "Unknown2"},
{2, nullptr, "Unknown3"},
{3, nullptr, "GetCurrentBacklightLevel"},
{4, nullptr, "Unknown4"},
{5, nullptr, "GetAlsComputedBacklightLevel"},
{6, nullptr, "TurnOffBacklight"},
{7, nullptr, "TurnOnBacklight"},
{8, nullptr, "GetBacklightStatus"},
{9, nullptr, "Unknown5"},
{10, nullptr, "Unknown6"},
{11, nullptr, "Unknown7"},
{12, nullptr, "Unknown8"},
{13, nullptr, "Unknown9"},
{14, nullptr, "Unknown10"},
{15, nullptr, "GetAutoBrightnessSetting"},
{16, nullptr, "ReadRawLightSensor"},
{17, nullptr, "Unknown11"},
{18, nullptr, "Unknown12"},
{19, nullptr, "Unknown13"},
{20, nullptr, "Unknown14"},
{21, nullptr, "Unknown15"},
{22, nullptr, "Unknown16"},
{23, nullptr, "Unknown17"},
{24, nullptr, "Unknown18"},
{25, nullptr, "Unknown19"},
{26, &LBL::EnableVrMode, "EnableVrMode"},
{27, &LBL::DisableVrMode, "DisableVrMode"},
{28, &LBL::IsVrModeEnabled, "IsVrModeEnabled"},
{28, &LBL::GetVrMode, "GetVrMode"},
};
// clang-format on
@@ -72,7 +72,7 @@ private:
LOG_DEBUG(Service_LBL, "called");
}
void IsVrModeEnabled(Kernel::HLERequestContext& ctx) {
void GetVrMode(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(vr_mode_enabled);
-88
View File
@@ -1,88 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <memory>
#include "core/hle/service/npns/npns.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
namespace Service::NPNS {
class NPNS_S final : public ServiceFramework<NPNS_S> {
public:
explicit NPNS_S() : ServiceFramework{"npns:s"} {
// clang-format off
static const FunctionInfo functions[] = {
{1, nullptr, "ListenAll"},
{2, nullptr, "ListenTo"},
{3, nullptr, "Receive"},
{4, nullptr, "ReceiveRaw"},
{5, nullptr, "GetReceiveEvent"},
{6, nullptr, "ListenUndelivered"},
{7, nullptr, "GetStateChangeEVent"},
{11, nullptr, "SubscribeTopic"},
{12, nullptr, "UnsubscribeTopic"},
{13, nullptr, "QueryIsTopicExist"},
{21, nullptr, "CreateToken"},
{22, nullptr, "CreateTokenWithApplicationId"},
{23, nullptr, "DestroyToken"},
{24, nullptr, "DestroyTokenWithApplicationId"},
{25, nullptr, "QueryIsTokenValid"},
{31, nullptr, "UploadTokenToBaaS"},
{32, nullptr, "DestroyTokenForBaaS"},
{33, nullptr, "CreateTokenForBaaS"},
{34, nullptr, "SetBaaSDeviceAccountIdList"},
{101, nullptr, "Suspend"},
{102, nullptr, "Resume"},
{103, nullptr, "GetState"},
{104, nullptr, "GetStatistics"},
{105, nullptr, "GetPlayReportRequestEvent"},
{111, nullptr, "GetJid"},
{112, nullptr, "CreateJid"},
{113, nullptr, "DestroyJid"},
{114, nullptr, "AttachJid"},
{115, nullptr, "DetachJid"},
{201, nullptr, "RequestChangeStateForceTimed"},
{102, nullptr, "RequestChangeStateForceAsync"},
};
// clang-format on
RegisterHandlers(functions);
}
};
class NPNS_U final : public ServiceFramework<NPNS_U> {
public:
explicit NPNS_U() : ServiceFramework{"npns:u"} {
// clang-format off
static const FunctionInfo functions[] = {
{1, nullptr, "ListenAll"},
{2, nullptr, "ListenTo"},
{3, nullptr, "Receive"},
{4, nullptr, "ReceiveRaw"},
{5, nullptr, "GetReceiveEvent"},
{7, nullptr, "GetStateChangeEVent"},
{21, nullptr, "CreateToken"},
{23, nullptr, "DestroyToken"},
{25, nullptr, "QueryIsTokenValid"},
{26, nullptr, "ListenToMyApplicationId"},
{101, nullptr, "Suspend"},
{102, nullptr, "Resume"},
{103, nullptr, "GetState"},
{104, nullptr, "GetStatistics"},
{111, nullptr, "GetJid"},
};
// clang-format on
RegisterHandlers(functions);
}
};
void InstallInterfaces(SM::ServiceManager& sm) {
std::make_shared<NPNS_S>()->InstallAsService(sm);
std::make_shared<NPNS_U>()->InstallAsService(sm);
}
} // namespace Service::NPNS
-15
View File
@@ -1,15 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
namespace Service::SM {
class ServiceManager;
}
namespace Service::NPNS {
void InstallInterfaces(SM::ServiceManager& sm);
} // namespace Service::NPNS
+8 -13
View File
@@ -14,24 +14,20 @@ public:
explicit PlayReport(const char* name) : ServiceFramework{name} {
// clang-format off
static const FunctionInfo functions[] = {
{10100, nullptr, "SaveReportOld"},
{10101, &PlayReport::SaveReportWithUserOld, "SaveReportWithUserOld"},
{10102, nullptr, "SaveReport"},
{10103, nullptr, "SaveReportWithUser"},
{10100, nullptr, "SaveReport"},
{10101, &PlayReport::SaveReportWithUser, "SaveReportWithUser"},
{10200, nullptr, "RequestImmediateTransmission"},
{10300, nullptr, "GetTransmissionStatus"},
{20100, nullptr, "SaveSystemReport"},
{20101, nullptr, "SaveSystemReportWithUser"},
{20200, nullptr, "SetOperationMode"},
{20101, nullptr, "SaveSystemReportWithUser"},
{30100, nullptr, "ClearStorage"},
{30200, nullptr, "ClearStatistics"},
{30300, nullptr, "GetStorageUsage"},
{30400, nullptr, "GetStatistics"},
{30401, nullptr, "GetThroughputHistory"},
{30500, nullptr, "GetLastUploadError"},
{40100, nullptr, "IsUserAgreementCheckEnabled"},
{40101, nullptr, "SetUserAgreementCheckEnabled"},
{90100, nullptr, "ReadAllReportFiles"},
{90100, nullptr, "GetStorageUsage"},
{90200, nullptr, "GetStatistics"},
{90201, nullptr, "GetThroughputHistory"},
{90300, nullptr, "GetLastUploadError"},
};
// clang-format on
@@ -39,7 +35,7 @@ public:
}
private:
void SaveReportWithUserOld(Kernel::HLERequestContext& ctx) {
void SaveReportWithUser(Kernel::HLERequestContext& ctx) {
// TODO(ogniK): Do we want to add play report?
LOG_WARNING(Service_PREPO, "(STUBBED) called");
@@ -50,7 +46,6 @@ private:
void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<PlayReport>("prepo:a")->InstallAsService(service_manager);
std::make_shared<PlayReport>("prepo:a2")->InstallAsService(service_manager);
std::make_shared<PlayReport>("prepo:m")->InstallAsService(service_manager);
std::make_shared<PlayReport>("prepo:s")->InstallAsService(service_manager);
std::make_shared<PlayReport>("prepo:u")->InstallAsService(service_manager);
-71
View File
@@ -1,71 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <memory>
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/ptm/psm.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
namespace Service::PSM {
constexpr u32 BATTERY_FULLY_CHARGED = 100; // 100% Full
constexpr u32 BATTERY_CURRENTLY_CHARGING = 1; // Plugged into an official dock
class PSM final : public ServiceFramework<PSM> {
public:
explicit PSM() : ServiceFramework{"psm"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &PSM::GetBatteryChargePercentage, "GetBatteryChargePercentage"},
{1, &PSM::GetChargerType, "GetChargerType"},
{2, nullptr, "EnableBatteryCharging"},
{3, nullptr, "DisableBatteryCharging"},
{4, nullptr, "IsBatteryChargingEnabled"},
{5, nullptr, "AcquireControllerPowerSupply"},
{6, nullptr, "ReleaseControllerPowerSupply"},
{7, nullptr, "OpenSession"},
{8, nullptr, "EnableEnoughPowerChargeEmulation"},
{9, nullptr, "DisableEnoughPowerChargeEmulation"},
{10, nullptr, "EnableFastBatteryCharging"},
{11, nullptr, "DisableFastBatteryCharging"},
{12, nullptr, "GetBatteryVoltageState"},
{13, nullptr, "GetRawBatteryChargePercentage"},
{14, nullptr, "IsEnoughPowerSupplied"},
{15, nullptr, "GetBatteryAgePercentage"},
{16, nullptr, "GetBatteryChargeInfoEvent"},
{17, nullptr, "GetBatteryChargeInfoFields"},
};
// clang-format on
RegisterHandlers(functions);
}
~PSM() override = default;
private:
void GetBatteryChargePercentage(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_PSM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(BATTERY_FULLY_CHARGED);
}
void GetChargerType(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_PSM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(BATTERY_CURRENTLY_CHARGING);
}
};
void InstallInterfaces(SM::ServiceManager& sm) {
std::make_shared<PSM>()->InstallAsService(sm);
}
} // namespace Service::PSM
-15
View File
@@ -1,15 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
namespace Service::SM {
class ServiceManager;
}
namespace Service::PSM {
void InstallInterfaces(SM::ServiceManager& sm);
} // namespace Service::PSM
+2 -6
View File
@@ -22,7 +22,7 @@
#include "core/hle/service/apm/apm.h"
#include "core/hle/service/arp/arp.h"
#include "core/hle/service/audio/audio.h"
#include "core/hle/service/bcat/module.h"
#include "core/hle/service/bcat/bcat.h"
#include "core/hle/service/bpc/bpc.h"
#include "core/hle/service/btdrv/btdrv.h"
#include "core/hle/service/btm/btm.h"
@@ -48,17 +48,15 @@
#include "core/hle/service/nfp/nfp.h"
#include "core/hle/service/nifm/nifm.h"
#include "core/hle/service/nim/nim.h"
#include "core/hle/service/npns/npns.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/nvflinger/nvflinger.h"
#include "core/hle/service/pcie/pcie.h"
#include "core/hle/service/pctl/module.h"
#include "core/hle/service/pctl/pctl.h"
#include "core/hle/service/pcv/pcv.h"
#include "core/hle/service/pm/pm.h"
#include "core/hle/service/prepo/prepo.h"
#include "core/hle/service/psc/psc.h"
#include "core/hle/service/ptm/psm.h"
#include "core/hle/service/service.h"
#include "core/hle/service/set/settings.h"
#include "core/hle/service/sm/sm.h"
@@ -238,7 +236,6 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, FileSys::VfsFilesystem& vfs)
NFP::InstallInterfaces(*sm);
NIFM::InstallInterfaces(*sm);
NIM::InstallInterfaces(*sm);
NPNS::InstallInterfaces(*sm);
NS::InstallInterfaces(*sm);
Nvidia::InstallInterfaces(*sm, *nv_flinger);
PCIe::InstallInterfaces(*sm);
@@ -247,7 +244,6 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, FileSys::VfsFilesystem& vfs)
PlayReport::InstallInterfaces(*sm);
PM::InstallInterfaces(*sm);
PSC::InstallInterfaces(*sm);
PSM::InstallInterfaces(*sm);
Set::InstallInterfaces(*sm);
Sockets::InstallInterfaces(*sm);
SPL::InstallInterfaces(*sm);
+4 -2
View File
@@ -13,7 +13,8 @@
#include "video_core/renderer_base.h"
#include "video_core/textures/texture.h"
namespace Tegra::Engines {
namespace Tegra {
namespace Engines {
/// First register id that is actually a Macro call.
constexpr u32 MacroRegistersStart = 0xE00;
@@ -407,4 +408,5 @@ void Maxwell3D::ProcessClearBuffers() {
rasterizer.Clear();
}
} // namespace Tegra::Engines
} // namespace Engines
} // namespace Tegra
+1 -3
View File
@@ -643,10 +643,8 @@ public:
u32 d3d_cull_mode;
ComparisonOp depth_test_func;
float alpha_test_ref;
ComparisonOp alpha_test_func;
INSERT_PADDING_WORDS(0x9);
INSERT_PADDING_WORDS(0xB);
struct {
u32 separate_alpha;
+4 -2
View File
@@ -6,7 +6,8 @@
#include "core/core.h"
#include "video_core/engines/maxwell_compute.h"
namespace Tegra::Engines {
namespace Tegra {
namespace Engines {
void MaxwellCompute::WriteReg(u32 method, u32 value) {
ASSERT_MSG(method < Regs::NUM_REGS,
@@ -25,4 +26,5 @@ void MaxwellCompute::WriteReg(u32 method, u32 value) {
}
}
} // namespace Tegra::Engines
} // namespace Engines
} // namespace Tegra
+11 -6
View File
@@ -7,7 +7,8 @@
#include "video_core/rasterizer_interface.h"
#include "video_core/textures/decoders.h"
namespace Tegra::Engines {
namespace Tegra {
namespace Engines {
MaxwellDMA::MaxwellDMA(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager)
: memory_manager(memory_manager), rasterizer{rasterizer} {}
@@ -77,9 +78,9 @@ void MaxwellDMA::HandleCopy() {
ASSERT(regs.exec.enable_2d == 1);
const std::size_t copy_size = regs.x_count * regs.y_count;
std::size_t copy_size = regs.x_count * regs.y_count;
const auto FlushAndInvalidate = [&](u32 src_size, u64 dst_size) {
const auto FlushAndInvalidate = [&](u32 src_size, u32 dst_size) {
// TODO(Subv): For now, manually flush the regions until we implement GPU-accelerated
// copying.
rasterizer.FlushRegion(source_cpu, src_size);
@@ -90,11 +91,14 @@ void MaxwellDMA::HandleCopy() {
rasterizer.InvalidateRegion(dest_cpu, dst_size);
};
u8* src_buffer = Memory::GetPointer(source_cpu);
u8* dst_buffer = Memory::GetPointer(dest_cpu);
if (regs.exec.is_dst_linear && !regs.exec.is_src_linear) {
ASSERT(regs.src_params.size_z == 1);
// If the input is tiled and the output is linear, deswizzle the input and copy it over.
const u32 src_bytes_per_pixel = regs.src_pitch / regs.src_params.size_x;
u32 src_bytes_per_pixel = regs.src_pitch / regs.src_params.size_x;
FlushAndInvalidate(regs.src_pitch * regs.src_params.size_y,
copy_size * src_bytes_per_pixel);
@@ -107,7 +111,7 @@ void MaxwellDMA::HandleCopy() {
ASSERT(regs.dst_params.size_z == 1);
ASSERT(regs.src_pitch == regs.x_count);
const u32 src_bpp = regs.src_pitch / regs.x_count;
u32 src_bpp = regs.src_pitch / regs.x_count;
FlushAndInvalidate(regs.src_pitch * regs.y_count,
regs.dst_params.size_x * regs.dst_params.size_y * src_bpp);
@@ -118,4 +122,5 @@ void MaxwellDMA::HandleCopy() {
}
}
} // namespace Tegra::Engines
} // namespace Engines
} // namespace Tegra
+8 -26
View File
@@ -214,7 +214,7 @@ enum class IMinMaxExchange : u64 {
XHi = 3,
};
enum class VideoType : u64 {
enum class VmadType : u64 {
Size16_Low = 0,
Size16_High = 1,
Size32 = 2,
@@ -563,10 +563,6 @@ union Instruction {
BitField<48, 1, u64> negate_b;
} fmul;
union {
BitField<55, 1, u64> saturate;
} fmul32;
union {
BitField<48, 1, u64> is_signed;
} shift;
@@ -757,6 +753,7 @@ union Instruction {
BitField<45, 2, PredOperation> op;
BitField<47, 1, u64> ftz;
BitField<48, 4, PredCondition> cond;
BitField<56, 1, u64> neg_b;
} fsetp;
union {
@@ -782,14 +779,6 @@ union Instruction {
BitField<45, 2, PredOperation> op;
} psetp;
union {
BitField<43, 4, PredCondition> cond;
BitField<45, 2, PredOperation> op;
BitField<3, 3, u64> pred3;
BitField<0, 3, u64> pred0;
BitField<39, 3, u64> pred39;
} vsetp;
union {
BitField<12, 3, u64> pred12;
BitField<15, 1, u64> neg_pred12;
@@ -839,6 +828,7 @@ union Instruction {
BitField<53, 1, u64> neg_b;
BitField<54, 1, u64> abs_a;
BitField<55, 1, u64> ftz;
BitField<56, 1, u64> neg_imm;
} fset;
union {
@@ -1162,17 +1152,15 @@ union Instruction {
union {
BitField<48, 1, u64> signed_a;
BitField<38, 1, u64> is_byte_chunk_a;
BitField<36, 2, VideoType> type_a;
BitField<36, 2, VmadType> type_a;
BitField<36, 2, u64> byte_height_a;
BitField<49, 1, u64> signed_b;
BitField<50, 1, u64> use_register_b;
BitField<30, 1, u64> is_byte_chunk_b;
BitField<28, 2, VideoType> type_b;
BitField<28, 2, VmadType> type_b;
BitField<28, 2, u64> byte_height_b;
} video;
union {
BitField<51, 2, VmadShr> shr;
BitField<55, 1, u64> saturate; // Saturates the result (a * b + c)
BitField<47, 1, u64> cc;
@@ -1223,13 +1211,11 @@ public:
KIL,
SSY,
SYNC,
BRK,
DEPBAR,
BFE_C,
BFE_R,
BFE_IMM,
BRA,
PBK,
LD_A,
LD_C,
ST_A,
@@ -1248,7 +1234,6 @@ public:
OUT_R, // Emit vertex/primitive
ISBERD,
VMAD,
VSETP,
FFMA_IMM, // Fused Multiply and Add
FFMA_CR,
FFMA_RC,
@@ -1387,7 +1372,7 @@ public:
/// conditionally executed).
static bool IsPredicatedInstruction(Id opcode) {
// TODO(Subv): Add the rest of unpredicated instructions.
return opcode != Id::SSY && opcode != Id::PBK;
return opcode != Id::SSY;
}
class Matcher {
@@ -1483,11 +1468,9 @@ private:
#define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name)
INST("111000110011----", Id::KIL, Type::Flow, "KIL"),
INST("111000101001----", Id::SSY, Type::Flow, "SSY"),
INST("111000101010----", Id::PBK, Type::Flow, "PBK"),
INST("111000100100----", Id::BRA, Type::Flow, "BRA"),
INST("1111000011111---", Id::SYNC, Type::Flow, "SYNC"),
INST("111000110100---", Id::BRK, Type::Flow, "BRK"),
INST("1111000011110---", Id::DEPBAR, Type::Synch, "DEPBAR"),
INST("1111000011111---", Id::SYNC, Type::Synch, "SYNC"),
INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"),
INST("1110111110010---", Id::LD_C, Type::Memory, "LD_C"),
INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"),
@@ -1506,7 +1489,6 @@ private:
INST("1111101111100---", Id::OUT_R, Type::Trivial, "OUT_R"),
INST("1110111111010---", Id::ISBERD, Type::Trivial, "ISBERD"),
INST("01011111--------", Id::VMAD, Type::Trivial, "VMAD"),
INST("0101000011110---", Id::VSETP, Type::Trivial, "VSETP"),
INST("0011001-1-------", Id::FFMA_IMM, Type::Ffma, "FFMA_IMM"),
INST("010010011-------", Id::FFMA_CR, Type::Ffma, "FFMA_CR"),
INST("010100011-------", Id::FFMA_RC, Type::Ffma, "FFMA_RC"),
@@ -1626,4 +1608,4 @@ private:
}
};
} // namespace Tegra::Shader
} // namespace Tegra::Shader
@@ -570,11 +570,10 @@ void RasterizerOpenGL::DrawArrays() {
SyncBlendState();
SyncLogicOpState();
SyncCullMode();
SyncAlphaTest();
SyncScissorTest();
// Alpha Testing is synced on shaders.
SyncTransformFeedback();
SyncPointState();
CheckAlphaTests();
// TODO(bunnei): Sync framebuffer_scale uniform here
// TODO(bunnei): Sync scissorbox uniform(s) here
@@ -1008,6 +1007,17 @@ void RasterizerOpenGL::SyncLogicOpState() {
state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation);
}
void RasterizerOpenGL::SyncAlphaTest() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
// TODO(Rodrigo): Alpha testing is a legacy OpenGL feature, but it can be
// implemented with a test+discard in fragment shaders.
if (regs.alpha_test_enabled != 0) {
LOG_CRITICAL(Render_OpenGL, "Alpha testing is not implemented");
UNREACHABLE();
}
}
void RasterizerOpenGL::SyncScissorTest() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
@@ -1042,15 +1052,4 @@ void RasterizerOpenGL::SyncPointState() {
state.point.size = regs.point_size == 0 ? 1 : regs.point_size;
}
void RasterizerOpenGL::CheckAlphaTests() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
if (regs.alpha_test_enabled != 0 && regs.rt_control.count > 1) {
LOG_CRITICAL(
Render_OpenGL,
"Alpha Testing is enabled with Multiple Render Targets, this behavior is undefined.");
UNREACHABLE();
}
}
} // namespace OpenGL
@@ -162,6 +162,9 @@ private:
/// Syncs the LogicOp state to match the guest state
void SyncLogicOpState();
/// Syncs the alpha test state to match the guest state
void SyncAlphaTest();
/// Syncs the scissor test state to match the guest state
void SyncScissorTest();
@@ -171,9 +174,6 @@ private:
/// Syncs the point state to match the guest state
void SyncPointState();
/// Check asserts for alpha testing.
void CheckAlphaTests();
bool has_ARB_direct_state_access = false;
bool has_ARB_multi_bind = false;
bool has_ARB_separate_shader_objects = false;
@@ -78,6 +78,29 @@ void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
}
}
std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const {
const u32 compression_factor{GetCompressionFactor(pixel_format)};
const u32 bytes_per_pixel{GetBytesPerPixel(pixel_format)};
u32 m_depth = (layer_only ? 1U : depth);
u32 m_width = std::max(1U, width / compression_factor);
u32 m_height = std::max(1U, height / compression_factor);
std::size_t size = Tegra::Texture::CalculateSize(is_tiled, bytes_per_pixel, m_width, m_height,
m_depth, block_height, block_depth);
u32 m_block_height = block_height;
u32 m_block_depth = block_depth;
std::size_t block_size_bytes = 512 * block_height * block_depth; // 512 is GOB size
for (u32 i = 1; i < max_mip_level; i++) {
m_width = std::max(1U, m_width / 2);
m_height = std::max(1U, m_height / 2);
m_depth = std::max(1U, m_depth / 2);
m_block_height = std::max(1U, m_block_height / 2);
m_block_depth = std::max(1U, m_block_depth / 2);
size += Tegra::Texture::CalculateSize(is_tiled, bytes_per_pixel, m_width, m_height, m_depth,
m_block_height, m_block_depth);
}
return is_tiled ? Common::AlignUp(size, block_size_bytes) : size;
}
/*static*/ SurfaceParams SurfaceParams::CreateForTexture(
const Tegra::Texture::FullTextureInfo& config, const GLShader::SamplerEntry& entry) {
SurfaceParams params{};
@@ -124,6 +147,7 @@ void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
break;
}
params.is_layered = SurfaceTargetIsLayered(params.target);
params.max_mip_level = config.tic.max_mip_level + 1;
params.rt = {};
@@ -150,6 +174,7 @@ void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
params.target = SurfaceTarget::Texture2D;
params.depth = 1;
params.max_mip_level = 0;
params.is_layered = false;
// Render target specific parameters, not used for caching
params.rt.index = static_cast<u32>(index);
@@ -182,6 +207,7 @@ void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
params.target = SurfaceTarget::Texture2D;
params.depth = 1;
params.max_mip_level = 0;
params.is_layered = false;
params.rt = {};
params.InitCacheParameters(zeta_address);
@@ -361,10 +387,11 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 d
}
}
static constexpr std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr),
SurfaceParams::MaxPixelFormat>
morton_to_gl_fns = {
// clang-format off
using GLConversionArray = std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr),
SurfaceParams::MaxPixelFormat>;
static constexpr GLConversionArray morton_to_gl_fns = {
// clang-format off
MortonCopy<true, PixelFormat::ABGR8U>,
MortonCopy<true, PixelFormat::ABGR8S>,
MortonCopy<true, PixelFormat::ABGR8UI>,
@@ -418,13 +445,11 @@ static constexpr std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t,
MortonCopy<true, PixelFormat::Z24S8>,
MortonCopy<true, PixelFormat::S8Z24>,
MortonCopy<true, PixelFormat::Z32FS8>,
// clang-format on
// clang-format on
};
static constexpr std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr),
SurfaceParams::MaxPixelFormat>
gl_to_morton_fns = {
// clang-format off
static constexpr GLConversionArray gl_to_morton_fns = {
// clang-format off
MortonCopy<false, PixelFormat::ABGR8U>,
MortonCopy<false, PixelFormat::ABGR8S>,
MortonCopy<false, PixelFormat::ABGR8UI>,
@@ -479,9 +504,35 @@ static constexpr std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t,
MortonCopy<false, PixelFormat::Z24S8>,
MortonCopy<false, PixelFormat::S8Z24>,
MortonCopy<false, PixelFormat::Z32FS8>,
// clang-format on
// clang-format on
};
void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params,
std::vector<u8>& gl_buffer) {
u32 depth = params.depth;
if (params.target == SurfaceParams::SurfaceTarget::Texture2D) {
// TODO(Blinkhawk): Eliminate this condition once all texture types are implemented.
depth = 1U;
}
if (params.is_layered) {
u64 offset = 0;
u64 offset_gl = 0;
u64 layer_size = params.LayerMemorySize();
u64 gl_size = params.LayerSizeGL();
for (u32 i = 0; i < depth; i++) {
functions[static_cast<std::size_t>(params.pixel_format)](
params.width, params.block_height, params.height, params.block_depth, 1,
gl_buffer.data() + offset_gl, gl_size, params.addr + offset);
offset += layer_size;
offset_gl += gl_size;
}
} else {
functions[static_cast<std::size_t>(params.pixel_format)](
params.width, params.block_height, params.height, params.block_depth, depth,
gl_buffer.data(), gl_buffer.size(), params.addr);
}
}
static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
GLuint read_fb_handle, GLuint draw_fb_handle, GLenum src_attachment = 0,
GLenum dst_attachment = 0, std::size_t cubemap_face = 0) {
@@ -881,21 +932,10 @@ void CachedSurface::LoadGLBuffer() {
gl_buffer.resize(params.size_in_bytes_gl);
if (params.is_tiled) {
u32 depth = params.depth;
u32 block_depth = params.block_depth;
ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}",
params.block_width, static_cast<u32>(params.target));
if (params.target == SurfaceParams::SurfaceTarget::Texture2D) {
// TODO(Blinkhawk): Eliminate this condition once all texture types are implemented.
depth = 1U;
block_depth = 1U;
}
morton_to_gl_fns[static_cast<std::size_t>(params.pixel_format)](
params.width, params.block_height, params.height, block_depth, depth, gl_buffer.data(),
gl_buffer.size(), params.addr);
SwizzleFunc(morton_to_gl_fns, params, gl_buffer);
} else {
const auto texture_src_data{Memory::GetPointer(params.addr)};
const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl};
@@ -929,19 +969,10 @@ void CachedSurface::FlushGLBuffer() {
const u8* const texture_src_data = Memory::GetPointer(params.addr);
ASSERT(texture_src_data);
if (params.is_tiled) {
u32 depth = params.depth;
u32 block_depth = params.block_depth;
ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}",
params.block_width, static_cast<u32>(params.target));
if (params.target == SurfaceParams::SurfaceTarget::Texture2D) {
// TODO(Blinkhawk): Eliminate this condition once all texture types are implemented.
depth = 1U;
}
gl_to_morton_fns[static_cast<size_t>(params.pixel_format)](
params.width, params.block_height, params.height, block_depth, depth, gl_buffer.data(),
gl_buffer.size(), GetAddr());
SwizzleFunc(gl_to_morton_fns, params, gl_buffer);
} else {
std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer.data(), GetSizeInBytes());
}
@@ -1179,7 +1210,7 @@ void RasterizerCacheOpenGL::AccurateCopySurface(const Surface& src_surface,
const Surface& dst_surface) {
const auto& src_params{src_surface->GetSurfaceParams()};
const auto& dst_params{dst_surface->GetSurfaceParams()};
FlushRegion(src_params.addr, dst_params.size_in_bytes);
FlushRegion(src_params.addr, dst_params.MemorySize());
LoadSurface(dst_surface);
}
@@ -1221,44 +1252,10 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
CopySurface(old_surface, new_surface, copy_pbo.handle);
}
break;
case SurfaceParams::SurfaceTarget::TextureCubemap:
case SurfaceParams::SurfaceTarget::Texture3D:
AccurateCopySurface(old_surface, new_surface);
break;
case SurfaceParams::SurfaceTarget::TextureCubemap: {
if (old_params.rt.array_mode != 1) {
// TODO(bunnei): This is used by Breath of the Wild, I'm not sure how to implement this
// yet (array rendering used as a cubemap texture).
LOG_CRITICAL(HW_GPU, "Unhandled rendertarget array_mode {}", old_params.rt.array_mode);
UNREACHABLE();
return new_surface;
}
// This seems to be used for render-to-cubemap texture
ASSERT_MSG(old_params.target == SurfaceParams::SurfaceTarget::Texture2D, "Unexpected");
ASSERT_MSG(old_params.pixel_format == new_params.pixel_format, "Unexpected");
ASSERT_MSG(old_params.rt.base_layer == 0, "Unimplemented");
// TODO(bunnei): Verify the below - this stride seems to be in 32-bit words, not pixels.
// Tested with Splatoon 2, Super Mario Odyssey, and Breath of the Wild.
const std::size_t byte_stride{old_params.rt.layer_stride * sizeof(u32)};
for (std::size_t index = 0; index < new_params.depth; ++index) {
Surface face_surface{TryGetReservedSurface(old_params)};
ASSERT_MSG(face_surface, "Unexpected");
if (is_blit) {
BlitSurface(face_surface, new_surface, read_framebuffer.handle,
draw_framebuffer.handle, face_surface->GetSurfaceParams().rt.index,
new_params.rt.index, index);
} else {
CopySurface(face_surface, new_surface, copy_pbo.handle,
face_surface->GetSurfaceParams().rt.index, new_params.rt.index, index);
}
old_params.addr += byte_stride;
}
break;
}
default:
LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
static_cast<u32>(new_params.target));
@@ -1266,7 +1263,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
}
return new_surface;
}
} // namespace OpenGL
Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(VAddr addr) const {
return TryGet(addr);
@@ -168,6 +168,23 @@ struct SurfaceParams {
}
}
static bool SurfaceTargetIsLayered(SurfaceTarget target) {
switch (target) {
case SurfaceTarget::Texture1D:
case SurfaceTarget::Texture2D:
case SurfaceTarget::Texture3D:
return false;
case SurfaceTarget::Texture1DArray:
case SurfaceTarget::Texture2DArray:
case SurfaceTarget::TextureCubemap:
return true;
default:
LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
UNREACHABLE();
return false;
}
}
/**
* 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
@@ -742,6 +759,25 @@ struct SurfaceParams {
return size_in_bytes_gl / 6;
}
/// Returns the exact size of memory occupied by the texture in VRAM, including mipmaps.
std::size_t MemorySize() const {
std::size_t size = InnerMemorySize(is_layered);
if (is_layered)
return size * depth;
return size;
}
/// Returns the exact size of the memory occupied by a layer in a texture in VRAM, including
/// mipmaps.
std::size_t LayerMemorySize() const {
return InnerMemorySize(true);
}
/// Returns the size of a layer of this surface in OpenGL.
std::size_t LayerSizeGL() const {
return SizeInBytesRaw(true) / depth;
}
/// Creates SurfaceParams from a texture configuration
static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config,
const GLShader::SamplerEntry& entry);
@@ -782,6 +818,7 @@ struct SurfaceParams {
u32 unaligned_height;
SurfaceTarget target;
u32 max_mip_level;
bool is_layered;
// Parameters used for caching
VAddr addr;
@@ -797,6 +834,9 @@ struct SurfaceParams {
u32 layer_stride;
u32 base_layer;
} rt;
private:
std::size_t InnerMemorySize(bool layer_only = false) const;
};
}; // namespace OpenGL
@@ -163,11 +163,10 @@ private:
const ExitMethod jmp = Scan(target, end, labels);
return exit_method = ParallelExit(no_jmp, jmp);
}
case OpCode::Id::SSY:
case OpCode::Id::PBK: {
// The SSY and PBK use a similar encoding as the BRA instruction.
case OpCode::Id::SSY: {
// The SSY instruction uses a similar encoding as the BRA instruction.
ASSERT_MSG(instr.bra.constant_buffer == 0,
"Constant buffer branching is not supported");
"Constant buffer SSY is not supported");
const u32 target = offset + instr.bra.GetBranchTarget();
labels.insert(target);
// Continue scanning for an exit method.
@@ -379,8 +378,8 @@ public:
* @param reg The destination register to use.
* @param elem The element to use for the operation.
* @param value The code representing the value to assign. Type has to be half float.
* @param merge Half float kind of assignment.
* @param dest_num_components Number of components in the destination.
* @param type Half float kind of assignment.
* @param dest_num_components Number of components in the destionation.
* @param value_num_components Number of components in the value.
* @param is_saturated Optional, when True, saturates the provided value.
* @param dest_elem Optional, the destination element to use for the operation.
@@ -423,7 +422,6 @@ public:
* @param reg The destination register to use.
* @param elem The element to use for the operation.
* @param attribute The input attribute to use as the source value.
* @param input_mode The input mode.
* @param vertex The register that decides which vertex to read from (used in GS).
*/
void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute,
@@ -953,7 +951,7 @@ private:
// Can't assign to the constant predicate.
ASSERT(pred != static_cast<u64>(Pred::UnusedIndex));
std::string variable = 'p' + std::to_string(pred) + '_' + suffix;
const std::string variable = 'p' + std::to_string(pred) + '_' + suffix;
shader.AddLine(variable + " = " + value + ';');
declr_predicates.insert(std::move(variable));
}
@@ -1060,7 +1058,7 @@ private:
/*
* Transforms the input string GLSL operand into an unpacked half float pair.
* @note This function returns a float type pair instead of a half float pair. This is because
* real half floats are not standardized in GLSL but unpackHalf2x16 (which returns a vec2) is.
* real half floats are not standarized in GLSL but unpackHalf2x16 (which returns a vec2) is.
* @param operand Input operand. It has to be an unsigned integer.
* @param type How to unpack the unsigned integer to a half float pair.
* @param abs Get the absolute value of unpacked half floats.
@@ -1234,27 +1232,27 @@ private:
}
/*
* Emits code to push the input target address to the flow address stack, incrementing the stack
* Emits code to push the input target address to the SSY address stack, incrementing the stack
* top.
*/
void EmitPushToFlowStack(u32 target) {
void EmitPushToSSYStack(u32 target) {
shader.AddLine('{');
++shader.scope;
shader.AddLine("flow_stack[flow_stack_top] = " + std::to_string(target) + "u;");
shader.AddLine("flow_stack_top++;");
shader.AddLine("ssy_stack[ssy_stack_top] = " + std::to_string(target) + "u;");
shader.AddLine("ssy_stack_top++;");
--shader.scope;
shader.AddLine('}');
}
/*
* Emits code to pop an address from the flow address stack, setting the jump address to the
* Emits code to pop an address from the SSY address stack, setting the jump address to the
* popped address and decrementing the stack top.
*/
void EmitPopFromFlowStack() {
void EmitPopFromSSYStack() {
shader.AddLine('{');
++shader.scope;
shader.AddLine("flow_stack_top--;");
shader.AddLine("jmp_to = flow_stack[flow_stack_top];");
shader.AddLine("ssy_stack_top--;");
shader.AddLine("jmp_to = ssy_stack[ssy_stack_top];");
shader.AddLine("break;");
--shader.scope;
shader.AddLine('}');
@@ -1266,29 +1264,9 @@ private:
ASSERT_MSG(header.ps.omap.sample_mask == 0, "Samplemask write is unimplemented");
shader.AddLine("if (alpha_test[0] != 0) {");
++shader.scope;
// We start on the register containing the alpha value in the first RT.
u32 current_reg = 3;
for (u32 render_target = 0; render_target < Maxwell3D::Regs::NumRenderTargets;
++render_target) {
// TODO(Blinkhawk): verify the behavior of alpha testing on hardware when
// multiple render targets are used.
if (header.ps.IsColorComponentOutputEnabled(render_target, 0) ||
header.ps.IsColorComponentOutputEnabled(render_target, 1) ||
header.ps.IsColorComponentOutputEnabled(render_target, 2) ||
header.ps.IsColorComponentOutputEnabled(render_target, 3)) {
shader.AddLine(fmt::format("if (!AlphaFunc({})) discard;",
regs.GetRegisterAsFloat(current_reg)));
current_reg += 4;
}
}
--shader.scope;
shader.AddLine('}');
// Write the color outputs using the data in the shader registers, disabled
// rendertargets/components are skipped in the register assignment.
current_reg = 0;
u32 current_reg = 0;
for (u32 render_target = 0; render_target < Maxwell3D::Regs::NumRenderTargets;
++render_target) {
// TODO(Subv): Figure out how dual-source blending is configured in the Switch.
@@ -1312,63 +1290,6 @@ private:
}
}
/// Unpacks a video instruction operand (e.g. VMAD).
std::string GetVideoOperand(const std::string& op, bool is_chunk, bool is_signed,
Tegra::Shader::VideoType type, u64 byte_height) {
const std::string value = [&]() {
if (!is_chunk) {
const auto offset = static_cast<u32>(byte_height * 8);
return "((" + op + " >> " + std::to_string(offset) + ") & 0xff)";
}
const std::string zero = "0";
switch (type) {
case Tegra::Shader::VideoType::Size16_Low:
return '(' + op + " & 0xffff)";
case Tegra::Shader::VideoType::Size16_High:
return '(' + op + " >> 16)";
case Tegra::Shader::VideoType::Size32:
// TODO(Rodrigo): From my hardware tests it becomes a bit "mad" when
// this type is used (1 * 1 + 0 == 0x5b800000). Until a better
// explanation is found: assert.
UNIMPLEMENTED();
return zero;
case Tegra::Shader::VideoType::Invalid:
UNREACHABLE_MSG("Invalid instruction encoding");
return zero;
default:
UNREACHABLE();
return zero;
}
}();
if (is_signed) {
return "int(" + value + ')';
}
return value;
};
/// Gets the A operand for a video instruction.
std::string GetVideoOperandA(Instruction instr) {
return GetVideoOperand(regs.GetRegisterAsInteger(instr.gpr8, 0, false),
instr.video.is_byte_chunk_a != 0, instr.video.signed_a,
instr.video.type_a, instr.video.byte_height_a);
}
/// Gets the B operand for a video instruction.
std::string GetVideoOperandB(Instruction instr) {
if (instr.video.use_register_b) {
return GetVideoOperand(regs.GetRegisterAsInteger(instr.gpr20, 0, false),
instr.video.is_byte_chunk_b != 0, instr.video.signed_b,
instr.video.type_b, instr.video.byte_height_b);
} else {
return '(' +
std::to_string(instr.video.signed_b ? static_cast<s16>(instr.alu.GetImm20_16())
: instr.alu.GetImm20_16()) +
')';
}
}
/**
* Compiles a single instruction from Tegra to GLSL.
* @param offset the offset of the Tegra shader instruction.
@@ -1538,10 +1459,9 @@ private:
break;
}
case OpCode::Id::FMUL32_IMM: {
regs.SetRegisterToFloat(instr.gpr0, 0,
regs.GetRegisterAsFloat(instr.gpr8) + " * " +
GetImmediate32(instr),
1, 1, instr.fmul32.saturate);
regs.SetRegisterToFloat(
instr.gpr0, 0,
regs.GetRegisterAsFloat(instr.gpr8) + " * " + GetImmediate32(instr), 1, 1);
break;
}
case OpCode::Id::FADD32I: {
@@ -2816,13 +2736,20 @@ private:
break;
}
case OpCode::Type::FloatSetPredicate: {
const std::string op_a =
GetOperandAbsNeg(regs.GetRegisterAsFloat(instr.gpr8), instr.fsetp.abs_a != 0,
instr.fsetp.neg_a != 0);
std::string op_a = instr.fsetp.neg_a ? "-" : "";
op_a += regs.GetRegisterAsFloat(instr.gpr8);
std::string op_b;
if (instr.fsetp.abs_a) {
op_a = "abs(" + op_a + ')';
}
std::string op_b{};
if (instr.is_b_imm) {
if (instr.fsetp.neg_b) {
// Only the immediate version of fsetp has a neg_b bit.
op_b += '-';
}
op_b += '(' + GetImmediate19(instr) + ')';
} else {
if (instr.is_b_gpr) {
@@ -3018,24 +2945,33 @@ private:
break;
}
case OpCode::Type::FloatSet: {
const std::string op_a = GetOperandAbsNeg(regs.GetRegisterAsFloat(instr.gpr8),
instr.fset.abs_a != 0, instr.fset.neg_a != 0);
std::string op_a = instr.fset.neg_a ? "-" : "";
op_a += regs.GetRegisterAsFloat(instr.gpr8);
std::string op_b;
if (instr.fset.abs_a) {
op_a = "abs(" + op_a + ')';
}
std::string op_b = instr.fset.neg_b ? "-" : "";
if (instr.is_b_imm) {
const std::string imm = GetImmediate19(instr);
op_b = imm;
if (instr.fset.neg_imm)
op_b += "(-" + imm + ')';
else
op_b += imm;
} else {
if (instr.is_b_gpr) {
op_b = regs.GetRegisterAsFloat(instr.gpr20);
op_b += regs.GetRegisterAsFloat(instr.gpr20);
} else {
op_b = regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset,
GLSLRegister::Type::Float);
op_b += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset,
GLSLRegister::Type::Float);
}
}
op_b = GetOperandAbsNeg(op_b, instr.fset.abs_b != 0, instr.fset.neg_b != 0);
if (instr.fset.abs_b) {
op_b = "abs(" + op_b + ')';
}
// The fset instruction sets a register to 1.0 or -1 (depending on the bf bit) if the
// condition is true, and to 0 otherwise.
@@ -3343,32 +3279,16 @@ private:
// The SSY opcode tells the GPU where to re-converge divergent execution paths, it
// sets the target of the jump that the SYNC instruction will make. The SSY opcode
// has a similar structure to the BRA opcode.
ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer flow is not supported");
ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer SSY is not supported");
const u32 target = offset + instr.bra.GetBranchTarget();
EmitPushToFlowStack(target);
break;
}
case OpCode::Id::PBK: {
// PBK pushes to a stack the address where BRK will jump to. This shares stack with
// SSY but using SYNC on a PBK address will kill the shader execution. We don't
// emulate this because it's very unlikely a driver will emit such invalid shader.
ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer PBK is not supported");
const u32 target = offset + instr.bra.GetBranchTarget();
EmitPushToFlowStack(target);
EmitPushToSSYStack(target);
break;
}
case OpCode::Id::SYNC: {
// The SYNC opcode jumps to the address previously set by the SSY opcode
ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
EmitPopFromFlowStack();
break;
}
case OpCode::Id::BRK: {
// The BRK opcode jumps to the address previously set by the PBK opcode
ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
EmitPopFromFlowStack();
EmitPopFromSSYStack();
break;
}
case OpCode::Id::DEPBAR: {
@@ -3378,51 +3298,87 @@ private:
break;
}
case OpCode::Id::VMAD: {
const bool result_signed = instr.video.signed_a == 1 || instr.video.signed_b == 1;
const std::string op_a = GetVideoOperandA(instr);
const std::string op_b = GetVideoOperandB(instr);
const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39, 0, result_signed);
const bool signed_a = instr.vmad.signed_a == 1;
const bool signed_b = instr.vmad.signed_b == 1;
const bool result_signed = signed_a || signed_b;
boost::optional<std::string> forced_result;
std::string result = '(' + op_a + " * " + op_b + " + " + op_c + ')';
auto Unpack = [&](const std::string& op, bool is_chunk, bool is_signed,
Tegra::Shader::VmadType type, u64 byte_height) {
const std::string value = [&]() {
if (!is_chunk) {
const auto offset = static_cast<u32>(byte_height * 8);
return "((" + op + " >> " + std::to_string(offset) + ") & 0xff)";
}
const std::string zero = "0";
switch (instr.vmad.shr) {
case Tegra::Shader::VmadShr::Shr7:
result = '(' + result + " >> 7)";
break;
case Tegra::Shader::VmadShr::Shr15:
result = '(' + result + " >> 15)";
break;
switch (type) {
case Tegra::Shader::VmadType::Size16_Low:
return '(' + op + " & 0xffff)";
case Tegra::Shader::VmadType::Size16_High:
return '(' + op + " >> 16)";
case Tegra::Shader::VmadType::Size32:
// TODO(Rodrigo): From my hardware tests it becomes a bit "mad" when
// this type is used (1 * 1 + 0 == 0x5b800000). Until a better
// explanation is found: assert.
UNREACHABLE_MSG("Unimplemented");
return zero;
case Tegra::Shader::VmadType::Invalid:
// Note(Rodrigo): This flag is invalid according to nvdisasm. From my
// testing (even though it's invalid) this makes the whole instruction
// assign zero to target register.
forced_result = boost::make_optional(zero);
return zero;
default:
UNREACHABLE();
return zero;
}
}();
if (is_signed) {
return "int(" + value + ')';
}
return value;
};
const std::string op_a = Unpack(regs.GetRegisterAsInteger(instr.gpr8, 0, false),
instr.vmad.is_byte_chunk_a != 0, signed_a,
instr.vmad.type_a, instr.vmad.byte_height_a);
std::string op_b;
if (instr.vmad.use_register_b) {
op_b = Unpack(regs.GetRegisterAsInteger(instr.gpr20, 0, false),
instr.vmad.is_byte_chunk_b != 0, signed_b, instr.vmad.type_b,
instr.vmad.byte_height_b);
} else {
op_b = '(' +
std::to_string(signed_b ? static_cast<s16>(instr.alu.GetImm20_16())
: instr.alu.GetImm20_16()) +
')';
}
const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39, 0, result_signed);
std::string result;
if (forced_result) {
result = *forced_result;
} else {
result = '(' + op_a + " * " + op_b + " + " + op_c + ')';
switch (instr.vmad.shr) {
case Tegra::Shader::VmadShr::Shr7:
result = '(' + result + " >> 7)";
break;
case Tegra::Shader::VmadShr::Shr15:
result = '(' + result + " >> 15)";
break;
}
}
regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1,
instr.vmad.saturate == 1, 0, Register::Size::Word,
instr.vmad.cc);
break;
}
case OpCode::Id::VSETP: {
const std::string op_a = GetVideoOperandA(instr);
const std::string op_b = GetVideoOperandB(instr);
// We can't use the constant predicate as destination.
ASSERT(instr.vsetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
const std::string second_pred = GetPredicateCondition(instr.vsetp.pred39, false);
const std::string combiner = GetPredicateCombiner(instr.vsetp.op);
const std::string predicate = GetPredicateComparison(instr.vsetp.cond, op_a, op_b);
// Set the primary predicate to the result of Predicate OP SecondPredicate
SetPredicate(instr.vsetp.pred3,
'(' + predicate + ") " + combiner + " (" + second_pred + ')');
if (instr.vsetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
// Set the secondary predicate to the result of !Predicate OP SecondPredicate,
// if enabled
SetPredicate(instr.vsetp.pred0,
"!(" + predicate + ") " + combiner + " (" + second_pred + ')');
}
break;
}
default: {
LOG_CRITICAL(HW_GPU, "Unhandled instruction: {}", opcode->GetName());
UNREACHABLE();
@@ -3486,11 +3442,11 @@ private:
labels.insert(subroutine.begin);
shader.AddLine("uint jmp_to = " + std::to_string(subroutine.begin) + "u;");
// TODO(Subv): Figure out the actual depth of the flow stack, for now it seems
// unlikely that shaders will use 20 nested SSYs and PBKs.
constexpr u32 FLOW_STACK_SIZE = 20;
shader.AddLine("uint flow_stack[" + std::to_string(FLOW_STACK_SIZE) + "];");
shader.AddLine("uint flow_stack_top = 0u;");
// TODO(Subv): Figure out the actual depth of the SSY stack, for now it seems
// unlikely that shaders will use 20 nested SSYs.
constexpr u32 SSY_STACK_SIZE = 20;
shader.AddLine("uint ssy_stack[" + std::to_string(SSY_STACK_SIZE) + "];");
shader.AddLine("uint ssy_stack_top = 0u;");
shader.AddLine("while (true) {");
++shader.scope;
@@ -3557,7 +3513,7 @@ private:
// Declarations
std::set<std::string> declr_predicates;
}; // namespace OpenGL::GLShader::Decompiler
}; // namespace Decompiler
std::string GetCommonDeclarations() {
return fmt::format("#define MAX_CONSTBUFFER_ELEMENTS {}\n",
@@ -29,7 +29,6 @@ layout(std140) uniform vs_config {
vec4 viewport_flip;
uvec4 instance_id;
uvec4 flip_stage;
uvec4 alpha_test;
};
)";
@@ -106,7 +105,6 @@ layout (std140) uniform gs_config {
vec4 viewport_flip;
uvec4 instance_id;
uvec4 flip_stage;
uvec4 alpha_test;
};
void main() {
@@ -144,33 +142,8 @@ layout (std140) uniform fs_config {
vec4 viewport_flip;
uvec4 instance_id;
uvec4 flip_stage;
uvec4 alpha_test;
};
bool AlphaFunc(in float value) {
float ref = uintBitsToFloat(alpha_test[2]);
switch (alpha_test[1]) {
case 1:
return false;
case 2:
return value < ref;
case 3:
return value == ref;
case 4:
return value <= ref;
case 5:
return value > ref;
case 6:
return value != ref;
case 7:
return value >= ref;
case 8:
return true;
default:
return false;
}
}
void main() {
exec_fragment();
}
@@ -179,4 +152,4 @@ void main() {
out += program.first;
return {out, program.second};
}
} // namespace OpenGL::GLShader
} // namespace OpenGL::GLShader
@@ -16,17 +16,6 @@ void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& sh
viewport_flip[0] = regs.viewport_transform[0].scale_x < 0.0 ? -1.0f : 1.0f;
viewport_flip[1] = regs.viewport_transform[0].scale_y < 0.0 ? -1.0f : 1.0f;
u32 func = static_cast<u32>(regs.alpha_test_func);
// Normalize the gl variants of opCompare to be the same as the normal variants
u32 op_gl_variant_base = static_cast<u32>(Tegra::Engines::Maxwell3D::Regs::ComparisonOp::Never);
if (func >= op_gl_variant_base) {
func = func - op_gl_variant_base + 1U;
}
alpha_test.enabled = regs.alpha_test_enabled;
alpha_test.func = func;
alpha_test.ref = regs.alpha_test_ref;
// We only assign the instance to the first component of the vector, the rest is just padding.
instance_id[0] = state.current_instance;
@@ -22,14 +22,8 @@ struct MaxwellUniformData {
alignas(16) GLvec4 viewport_flip;
alignas(16) GLuvec4 instance_id;
alignas(16) GLuvec4 flip_stage;
struct alignas(16) {
GLuint enabled;
GLuint func;
GLfloat ref;
GLuint padding;
} alpha_test;
};
static_assert(sizeof(MaxwellUniformData) == 64, "MaxwellUniformData structure size is incorrect");
static_assert(sizeof(MaxwellUniformData) == 48, "MaxwellUniformData structure size is incorrect");
static_assert(sizeof(MaxwellUniformData) < 16384,
"MaxwellUniformData structure must be less than 16kb as per the OpenGL spec");
+2 -14
View File
@@ -82,20 +82,8 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
return {};
}
case Maxwell::VertexAttribute::Type::Float: {
switch (attrib.size) {
case Maxwell::VertexAttribute::Size::Size_16:
case Maxwell::VertexAttribute::Size::Size_16_16:
case Maxwell::VertexAttribute::Size::Size_16_16_16:
case Maxwell::VertexAttribute::Size::Size_16_16_16_16:
return GL_HALF_FLOAT;
case Maxwell::VertexAttribute::Size::Size_32:
case Maxwell::VertexAttribute::Size::Size_32_32:
case Maxwell::VertexAttribute::Size::Size_32_32_32:
case Maxwell::VertexAttribute::Size::Size_32_32_32_32:
return GL_FLOAT;
}
}
case Maxwell::VertexAttribute::Type::Float:
return GL_FLOAT;
}
LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex type={}", attrib.TypeString());
+3 -3
View File
@@ -320,13 +320,13 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat
std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
u32 block_height, u32 block_depth) {
if (tiled) {
const u32 gobs_in_x = 64 / bytes_per_pixel;
const u32 gobs_in_x = 64;
const u32 gobs_in_y = 8;
const u32 gobs_in_z = 1;
const u32 aligned_width = Common::AlignUp(width, gobs_in_x);
const u32 aligned_width = Common::AlignUp(width * bytes_per_pixel, gobs_in_x);
const u32 aligned_height = Common::AlignUp(height, gobs_in_y * block_height);
const u32 aligned_depth = Common::AlignUp(depth, gobs_in_z * block_depth);
return aligned_width * aligned_height * aligned_depth * bytes_per_pixel;
return aligned_width * aligned_height * aligned_depth;
} else {
return width * height * depth * bytes_per_pixel;
}
+1 -1
View File
@@ -12,5 +12,5 @@ create_target_directory_groups(web_service)
get_directory_property(OPENSSL_LIBS
DIRECTORY ${CMAKE_SOURCE_DIR}/externals/libressl
DEFINITION OPENSSL_LIBS)
target_compile_definitions(web_service PRIVATE -DCPPHTTPLIB_OPENSSL_SUPPORT)
target_compile_definitions(web_service PUBLIC -DCPPHTTPLIB_OPENSSL_SUPPORT)
target_link_libraries(web_service PRIVATE common json-headers ${OPENSSL_LIBS} httplib lurlparser)
+1 -1
View File
@@ -121,7 +121,7 @@ target_link_libraries(yuzu PRIVATE Boost::boost glad Qt5::OpenGL Qt5::Widgets)
target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
if (YUZU_ENABLE_COMPATIBILITY_REPORTING)
target_compile_definitions(yuzu PRIVATE -DYUZU_ENABLE_COMPATIBILITY_REPORTING)
add_definitions(-DYUZU_ENABLE_COMPATIBILITY_REPORTING)
endif()
if (USE_DISCORD_PRESENCE)
+1 -7
View File
@@ -97,24 +97,18 @@
<addaction name="action_Show_Status_Bar"/>
<addaction name="menu_View_Debugging"/>
</widget>
<widget class ="QMenu" name="menu_Tools">
<property name="title">
<string>Tools</string>
</property>
<addaction name="action_Rederive" />
</widget>
<widget class="QMenu" name="menu_Help">
<property name="title">
<string>&amp;Help</string>
</property>
<addaction name="action_Report_Compatibility"/>
<addaction name="separator"/>
<addaction name="action_Rederive"/>
<addaction name="action_About"/>
</widget>
<addaction name="menu_File"/>
<addaction name="menu_Emulation"/>
<addaction name="menu_View"/>
<addaction name="menu_Tools" />
<addaction name="menu_Help"/>
</widget>
<action name="action_Install_File_NAND">