Merge branch 'hrydgard:master' into compat-openxr-3rdbirthday

This commit is contained in:
Luboš Vonásek 2023-01-06 16:54:00 +01:00 committed by GitHub
commit cd3ed86152
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
113 changed files with 8348 additions and 1351 deletions

2
.gitmodules vendored
View File

@ -12,7 +12,7 @@
url = https://github.com/Kingcom/armips.git
[submodule "ext/glslang"]
path = ext/glslang
url = https://github.com/hrydgard/glslang.git
url = https://github.com/KhronosGroup/glslang.git
[submodule "ext/SPIRV-Cross"]
path = ext/SPIRV-Cross
url = https://github.com/KhronosGroup/SPIRV-Cross.git

View File

@ -472,6 +472,7 @@ set(CommonARM64
Common/Arm64Emitter.cpp
Common/ArmEmitter.h
Common/ArmEmitter.cpp
Core/Util/DisArm64.h
Core/Util/DisArm64.cpp
)
source_group(ARM64 FILES ${CommonARM64})
@ -2032,6 +2033,9 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/Util/PPGeDraw.h
${GPU_SOURCES}
ext/disarm.cpp
ext/disarm.h
ext/riscv-disas.cpp
ext/riscv-disas.h
${CMAKE_CURRENT_BINARY_DIR}/git-version.cpp
)

View File

@ -141,6 +141,8 @@ void PathBrowser::HandlePath() {
pendingThread_ = std::thread([&] {
SetCurrentThreadName("PathBrowser");
AndroidJNIThreadContext jniContext; // destructor detaches
std::unique_lock<std::mutex> guard(pendingLock_);
std::vector<File::FileInfo> results;
Path lastPath("NONSENSE THAT WONT EQUAL A PATH");

View File

@ -1678,6 +1678,10 @@ void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const Ren
if (curRenderTargetView_ == fb->colorRTView && curDepthStencilView_ == fb->depthStencilRTView) {
// No need to switch, but let's fallthrough to clear!
} else {
// It's not uncommon that the first slot happens to have the new render target bound as a texture,
// so unbind to make the validation layers happy.
ID3D11ShaderResourceView *empty[1] = {};
context_->PSSetShaderResources(0, ARRAY_SIZE(empty), empty);
context_->OMSetRenderTargets(1, &fb->colorRTView, fb->depthStencilRTView);
curRenderTargetView_ = fb->colorRTView;
curDepthStencilView_ = fb->depthStencilRTView;

View File

@ -1454,18 +1454,21 @@ bool D3D9Context::CopyFramebufferToMemorySync(Framebuffer *src, int channelBits,
LPDIRECT3DSURFACE9 offscreen = nullptr;
HRESULT hr = E_UNEXPECTED;
_assert_(fb != nullptr);
if (channelBits == FB_COLOR_BIT) {
fb->tex->GetLevelDesc(0, &desc);
if (fb)
fb->tex->GetLevelDesc(0, &desc);
else
deviceRTsurf->GetDesc(&desc);
hr = device_->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &offscreen, nullptr);
if (SUCCEEDED(hr)) {
hr = device_->GetRenderTargetData(fb->surf, offscreen);
hr = device_->GetRenderTargetData(fb ? fb->surf : deviceRTsurf, offscreen);
if (SUCCEEDED(hr)) {
hr = offscreen->LockRect(&locked, &rect, D3DLOCK_READONLY);
}
}
} else {
_assert_(fb->depthstenciltex != nullptr);
fb->depthstenciltex->GetLevelDesc(0, &desc);
hr = fb->depthstenciltex->LockRect(0, &locked, &rect, D3DLOCK_READONLY);
}

View File

@ -121,9 +121,9 @@ bool VKRGraphicsPipeline::Create(VulkanContext *vulkan, VkRenderPass compatibleR
double taken_ms = (time_now_d() - start) * 1000.0;
if (taken_ms < 0.1) {
DEBUG_LOG(G3D, "Pipeline creation time: %0.2f ms (fast) rpType: %08x sampleBits: %d\n(%s)", taken_ms, (u32)rpType, (u32)sampleCount, tag_.c_str());
DEBUG_LOG(G3D, "Pipeline creation time: %0.2f ms (fast) rpType: %08x sampleBits: %d (%s)", taken_ms, (u32)rpType, (u32)sampleCount, tag_.c_str());
} else {
INFO_LOG(G3D, "Pipeline creation time: %0.2f ms rpType: %08x sampleBits: %d\n(%s)", taken_ms, (u32)rpType, (u32)sampleCount, tag_.c_str());
INFO_LOG(G3D, "Pipeline creation time: %0.2f ms rpType: %08x sampleBits: %d (%s)", taken_ms, (u32)rpType, (u32)sampleCount, tag_.c_str());
}
bool success = true;

View File

@ -526,6 +526,9 @@ std::string Download::RedirectLocation(const std::string &baseUrl) {
void Download::Do() {
SetCurrentThreadName("Downloader::Do");
AndroidJNIThreadContext jniContext;
resultCode_ = 0;
std::string downloadURL = url_;

View File

@ -44,6 +44,7 @@ struct ThreadContext {
std::atomic<bool> cancelled;
std::atomic<Task *> private_single;
std::deque<Task *> private_queue;
char name[16];
};
ThreadManager::ThreadManager() : global_(new GlobalThreadContext()) {
@ -124,14 +125,17 @@ bool ThreadManager::TeardownTask(Task *task, bool enqueue) {
}
static void WorkerThreadFunc(GlobalThreadContext *global, ThreadContext *thread) {
char threadName[16];
if (thread->type == TaskType::CPU_COMPUTE) {
snprintf(threadName, sizeof(threadName), "PoolWorker %d", thread->index);
snprintf(thread->name, sizeof(thread->name), "PoolWorker %d", thread->index);
} else {
_assert_(thread->type == TaskType::IO_BLOCKING);
snprintf(threadName, sizeof(threadName), "PoolWorkerIO %d", thread->index);
snprintf(thread->name, sizeof(thread->name), "PoolWorkerIO %d", thread->index);
}
SetCurrentThreadName(thread->name);
if (thread->type == TaskType::IO_BLOCKING) {
AttachThreadToJNI();
}
SetCurrentThreadName(threadName);
const bool isCompute = thread->type == TaskType::CPU_COMPUTE;
const auto global_queue_size = [isCompute, &global]() -> int {
@ -185,6 +189,11 @@ static void WorkerThreadFunc(GlobalThreadContext *global, ThreadContext *thread)
thread->queue_size--;
}
}
// In case it got attached to JNI, detach it. Don't think this has any side effects if called redundantly.
if (thread->type == TaskType::IO_BLOCKING) {
DetachThreadFromJNI();
}
}
void ThreadManager::Init(int numRealCores, int numLogicalCoresPerCpu) {

View File

@ -12,10 +12,15 @@
#elif defined(__ANDROID__)
#include "android/jni/app-android.h"
#define TLS_SUPPORTED
#endif
// TODO: Many other platforms also support TLS, in fact probably nearly all that we support
// these days.
#include <cstring>
#include <cstdint>
@ -23,6 +28,27 @@
#include "Common/Thread/ThreadUtil.h"
#include "Common/Data/Encoding/Utf8.h"
AttachDetachFunc g_attach;
AttachDetachFunc g_detach;
void AttachThreadToJNI() {
if (g_attach) {
g_attach();
}
}
void DetachThreadFromJNI() {
if (g_detach) {
g_detach();
}
}
void RegisterAttachDetach(AttachDetachFunc attach, AttachDetachFunc detach) {
g_attach = attach;
g_detach = detach;
}
#if (PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(LINUX)) && !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
@ -62,7 +88,6 @@ static EXCEPTION_DISPOSITION NTAPI ignore_handler(EXCEPTION_RECORD *rec,
}
#endif
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
typedef HRESULT (WINAPI *TSetThreadDescription)(HANDLE, PCWSTR);
@ -90,7 +115,15 @@ static void InitializeSetThreadDescription() {
void SetCurrentThreadNameThroughException(const char *threadName);
#endif
void SetCurrentThreadName(const char* threadName) {
const char *GetCurrentThreadName() {
#ifdef TLS_SUPPORTED
return curThreadName;
#else
return "";
#endif
}
void SetCurrentThreadName(const char *threadName) {
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
InitializeSetThreadDescription();
if (g_pSetThreadDescription) {

View File

@ -2,11 +2,37 @@
#include <mutex>
// Note that name must be a global string that lives until the end of the process,
// Note that the string pointed to must have a lifetime until the end of the thread,
// for AssertCurrentThreadName to work.
void SetCurrentThreadName(const char *threadName);
void AssertCurrentThreadName(const char *threadName);
// If TLS is not supported, this will return an empty string.
const char *GetCurrentThreadName();
// Just gets a cheap thread identifier so that you can see different threads in debug output,
// exactly what it is is badly specified and not useful for anything.
int GetCurrentThreadIdForDebug();
typedef void (*AttachDetachFunc)();
void RegisterAttachDetach(AttachDetachFunc attach, AttachDetachFunc detach);
// When you know that a thread potentially will make JNI calls, call this after setting its name.
void AttachThreadToJNI();
// Call when leaving threads. On Android, calls DetachCurrentThread.
// Threads that use scoped storage I/O end up attached as JNI threads, and will thus
// need this in order to follow the rules correctly. Some devices seem to enforce this.
void DetachThreadFromJNI();
// Utility to call the above two functions.
class AndroidJNIThreadContext {
public:
AndroidJNIThreadContext() {
AttachThreadToJNI();
}
~AndroidJNIThreadContext() {
DetachThreadFromJNI();
}
};

View File

@ -866,6 +866,11 @@ bool ScrollView::Key(const KeyInput &input) {
}
if (input.flags & KEY_DOWN) {
if ((input.keyCode == NKCODE_EXT_MOUSEWHEEL_UP || input.keyCode == NKCODE_EXT_MOUSEWHEEL_DOWN) &&
(input.flags & KEY_HASWHEELDELTA)) {
scrollSpeed = (float)(short)(input.flags >> 16) * 1.25f; // Fudge factor
}
switch (input.keyCode) {
case NKCODE_EXT_MOUSEWHEEL_UP:
ScrollRelative(-scrollSpeed);

View File

@ -32,6 +32,7 @@
#include "Common/Log.h"
#include "Common/TimeUtil.h"
#include "Common/Thread/ThreadUtil.h"
#include "Common/Data/Format/IniFile.h"
#include "Common/Data/Format/JSONReader.h"
#include "Common/Data/Text/I18n.h"
@ -43,6 +44,7 @@
#include "Common/System/Display.h"
#include "Common/System/System.h"
#include "Common/StringUtils.h"
#include "Common/Thread/ThreadUtil.h"
#include "Common/GPU/Vulkan/VulkanLoader.h"
#include "Common/VR/PPSSPPVR.h"
#include "Core/Config.h"
@ -1733,6 +1735,10 @@ void Config::RemoveRecent(const std::string &file) {
void Config::CleanRecent() {
private_->SetRecentIsosThread([this] {
SetCurrentThreadName("RecentISOs");
AndroidJNIThreadContext jniContext; // destructor detaches
double startTime = time_now_d();
std::lock_guard<std::mutex> guard(private_->recentIsosLock);

View File

@ -223,6 +223,8 @@ void KeepScreenAwake() {
}
void Core_RunLoop(GraphicsContext *ctx) {
float refreshRate = System_GetPropertyFloat(SYSPROP_DISPLAY_REFRESH_RATE);
graphicsContext = ctx;
while ((GetUIState() != UISTATE_INGAME || !PSP_IsInited()) && GetUIState() != UISTATE_EXIT) {
// In case it was pending, we're not in game anymore. We won't get to Core_Run().
@ -232,7 +234,7 @@ void Core_RunLoop(GraphicsContext *ctx) {
// Simple throttling to not burn the GPU in the menu.
double diffTime = time_now_d() - startTime;
int sleepTime = (int)(1000.0 / 60.0) - (int)(diffTime * 1000.0);
int sleepTime = (int)(1000.0 / refreshRate) - (int)(diffTime * 1000.0);
if (sleepTime > 0)
sleep_ms(sleepTime);
if (!windowHidden) {
@ -434,13 +436,13 @@ const char *ExecExceptionTypeAsString(ExecExceptionType type) {
}
}
void Core_MemoryException(u32 address, u32 pc, MemoryExceptionType type) {
void Core_MemoryException(u32 address, u32 accessSize, u32 pc, MemoryExceptionType type) {
const char *desc = MemoryExceptionTypeAsString(type);
// In jit, we only flush PC when bIgnoreBadMemAccess is off.
if (g_Config.iCpuCore == (int)CPUCore::JIT && g_Config.bIgnoreBadMemAccess) {
WARN_LOG(MEMMAP, "%s: Invalid address %08x", desc, address);
WARN_LOG(MEMMAP, "%s: Invalid access at %08x (size %08x)", desc, address, accessSize);
} else {
WARN_LOG(MEMMAP, "%s: Invalid address %08x PC %08x LR %08x", desc, address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]);
WARN_LOG(MEMMAP, "%s: Invalid access at %08x (size %08x) PC %08x LR %08x", desc, address, accessSize, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]);
}
if (!g_Config.bIgnoreBadMemAccess) {
@ -450,18 +452,19 @@ void Core_MemoryException(u32 address, u32 pc, MemoryExceptionType type) {
e.info.clear();
e.memory_type = type;
e.address = address;
e.accessSize = accessSize;
e.pc = pc;
Core_EnableStepping(true, "memory.exception", address);
}
}
void Core_MemoryExceptionInfo(u32 address, u32 pc, MemoryExceptionType type, std::string additionalInfo, bool forceReport) {
void Core_MemoryExceptionInfo(u32 address, u32 pc, u32 accessSize, MemoryExceptionType type, std::string additionalInfo, bool forceReport) {
const char *desc = MemoryExceptionTypeAsString(type);
// In jit, we only flush PC when bIgnoreBadMemAccess is off.
if (g_Config.iCpuCore == (int)CPUCore::JIT && g_Config.bIgnoreBadMemAccess) {
WARN_LOG(MEMMAP, "%s: Invalid address %08x. %s", desc, address, additionalInfo.c_str());
WARN_LOG(MEMMAP, "%s: Invalid access at %08x (size %08x). %s", desc, address, accessSize, additionalInfo.c_str());
} else {
WARN_LOG(MEMMAP, "%s: Invalid address %08x PC %08x LR %08x %s", desc, address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA], additionalInfo.c_str());
WARN_LOG(MEMMAP, "%s: Invalid access at %08x (size %08x) PC %08x LR %08x %s", desc, address, accessSize, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA], additionalInfo.c_str());
}
if (!g_Config.bIgnoreBadMemAccess || forceReport) {
@ -479,7 +482,7 @@ void Core_MemoryExceptionInfo(u32 address, u32 pc, MemoryExceptionType type, std
// Can't be ignored
void Core_ExecException(u32 address, u32 pc, ExecExceptionType type) {
const char *desc = ExecExceptionTypeAsString(type);
WARN_LOG(MEMMAP, "%s: Invalid destination %08x PC %08x LR %08x", desc, address, pc, currentMIPS->r[MIPS_REG_RA]);
WARN_LOG(MEMMAP, "%s: Invalid exec address %08x PC %08x LR %08x", desc, address, pc, currentMIPS->r[MIPS_REG_RA]);
ExceptionInfo &e = g_exceptionInfo;
e = {};
@ -487,6 +490,7 @@ void Core_ExecException(u32 address, u32 pc, ExecExceptionType type) {
e.info.clear();
e.exec_type = type;
e.address = address;
e.accessSize = 4; // size of an instruction
e.pc = pc;
// This just records the closest value that could be useful as reference.
e.ra = currentMIPS->r[MIPS_REG_RA];

View File

@ -101,9 +101,9 @@ enum class ExecExceptionType {
};
// Separate one for without info, to avoid having to allocate a string
void Core_MemoryException(u32 address, u32 pc, MemoryExceptionType type);
void Core_MemoryException(u32 address, u32 accessSize, u32 pc, MemoryExceptionType type);
void Core_MemoryExceptionInfo(u32 address, u32 pc, MemoryExceptionType type, std::string additionalInfo, bool forceReport);
void Core_MemoryExceptionInfo(u32 address, u32 accessSize, u32 pc, MemoryExceptionType type, std::string additionalInfo, bool forceReport);
void Core_ExecException(u32 address, u32 pc, ExecExceptionType type);
void Core_Break(u32 pc);
@ -125,6 +125,7 @@ struct ExceptionInfo {
MemoryExceptionType memory_type;
uint32_t pc;
uint32_t address;
uint32_t accessSize;
uint32_t ra = 0;
// Reuses pc and address from memory type, where address is the failed destination.

View File

@ -526,6 +526,7 @@
<ClCompile Include="..\ext\libzip\zip_unchange_archive.c" />
<ClCompile Include="..\ext\libzip\zip_unchange_data.c" />
<ClCompile Include="..\ext\libzip\zip_utf-8.c" />
<ClCompile Include="..\ext\riscv-disas.cpp" />
<ClCompile Include="..\ext\sfmt19937\SFMT.c" />
<ClCompile Include="..\ext\sha1\sha1.cpp" />
<ClCompile Include="..\ext\snappy\snappy-c.cpp" />
@ -1091,6 +1092,7 @@
<ClInclude Include="..\ext\libzip\zip_source_file.h" />
<ClInclude Include="..\ext\libzip\zip_source_file_stdio.h" />
<ClInclude Include="..\ext\libzip\zip_source_file_win32.h" />
<ClInclude Include="..\ext\riscv-disas.h" />
<ClInclude Include="..\ext\sfmt19937\SFMT-common.h" />
<ClInclude Include="..\ext\sfmt19937\SFMT-params.h" />
<ClInclude Include="..\ext\sfmt19937\SFMT-params19937.h" />

View File

@ -1192,6 +1192,9 @@
<ClCompile Include="WaveFile.cpp">
<Filter>Core</Filter>
</ClCompile>
<ClCompile Include="..\ext\riscv-disas.cpp">
<Filter>Ext</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ELF\ElfReader.h">
@ -1926,6 +1929,9 @@
<ClInclude Include="WaveFile.h">
<Filter>Core</Filter>
</ClInclude>
<ClInclude Include="..\ext\riscv-disas.h">
<Filter>Ext</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\LICENSE.TXT" />

View File

@ -409,7 +409,10 @@ std::vector<CheatFileInfo> CWCheatEngine::FileInfo() {
}
void CWCheatEngine::InvalidateICache(u32 addr, int size) {
currentMIPS->InvalidateICache(addr & ~3, size);
// Round start down and size up to the nearest word.
u32 aligned = addr & ~3;
int alignedSize = (addr + size - aligned + 3) & ~3;
currentMIPS->InvalidateICache(aligned, alignedSize);
}
enum class CheatOp {
@ -800,8 +803,8 @@ CheatOperation CWCheatEngine::InterpretNextOp(const CheatCode &cheat, size_t &i)
}
void CWCheatEngine::ApplyMemoryOperator(const CheatOperation &op, uint32_t(*oper)(uint32_t, uint32_t)) {
if (Memory::IsValidAddress(op.addr)) {
InvalidateICache(op.addr, 4);
if (Memory::IsValidRange(op.addr, op.sz)) {
InvalidateICache(op.addr, op.sz);
if (op.sz == 1)
Memory::Write_U8((u8)oper(Memory::Read_U8(op.addr), op.val), op.addr);
else if (op.sz == 2)
@ -812,8 +815,8 @@ void CWCheatEngine::ApplyMemoryOperator(const CheatOperation &op, uint32_t(*oper
}
bool CWCheatEngine::TestIf(const CheatOperation &op, bool(*oper)(int, int)) {
if (Memory::IsValidAddress(op.addr)) {
InvalidateICache(op.addr, 4);
if (Memory::IsValidRange(op.addr, op.sz)) {
InvalidateICache(op.addr, op.sz);
int memoryValue = 0;
if (op.sz == 1)
@ -829,8 +832,9 @@ bool CWCheatEngine::TestIf(const CheatOperation &op, bool(*oper)(int, int)) {
}
bool CWCheatEngine::TestIfAddr(const CheatOperation &op, bool(*oper)(int, int)) {
if (Memory::IsValidAddress(op.addr)) {
InvalidateICache(op.addr, 4);
if (Memory::IsValidRange(op.addr, op.sz) && Memory::IsValidRange(op.ifAddrTypes.compareAddr, op.sz)) {
InvalidateICache(op.addr, op.sz);
InvalidateICache(op.addr, op.ifAddrTypes.compareAddr);
int memoryValue1 = 0;
int memoryValue2 = 0;
@ -860,8 +864,8 @@ void CWCheatEngine::ExecuteOp(const CheatOperation &op, const CheatCode &cheat,
break;
case CheatOp::Write:
if (Memory::IsValidAddress(op.addr)) {
InvalidateICache(op.addr, 4);
if (Memory::IsValidRange(op.addr, op.sz)) {
InvalidateICache(op.addr, op.sz);
if (op.sz == 1)
Memory::Write_U8((u8)op.val, op.addr);
else if (op.sz == 2)
@ -943,7 +947,7 @@ void CWCheatEngine::ExecuteOp(const CheatOperation &op, const CheatCode &cheat,
break;
case CheatOp::VibrationFromMemory:
if (Memory::IsValidAddress(op.addr) && Memory::IsValidAddress(op.addr + 0x4)) {
if (Memory::IsValidRange(op.addr, 8)) {
uint16_t checkLeftVibration = Memory::Read_U16(op.addr);
uint16_t checkRightVibration = Memory::Read_U16(op.addr + 0x2);
if (checkLeftVibration > 0) {
@ -970,7 +974,7 @@ void CWCheatEngine::ExecuteOp(const CheatOperation &op, const CheatCode &cheat,
case CheatOp::PostShaderFromMemory:
{
auto shaderChain = GetFullPostShadersChain(g_Config.vPostShaderNames);
if (Memory::IsValidAddress(op.addr) && op.PostShaderUniform.shader < shaderChain.size()) {
if (Memory::IsValidRange(op.addr, 4) && op.PostShaderUniform.shader < shaderChain.size()) {
union {
float f;
uint32_t u;
@ -1000,7 +1004,7 @@ void CWCheatEngine::ExecuteOp(const CheatOperation &op, const CheatCode &cheat,
break;
case CheatOp::Assert:
if (Memory::IsValidAddress(op.addr)) {
if (Memory::IsValidRange(op.addr, 4)) {
InvalidateICache(op.addr, 4);
if (Memory::Read_U32(op.addr) != op.val) {
i = cheat.lines.size();
@ -1153,11 +1157,11 @@ void CWCheatEngine::ExecuteOp(const CheatOperation &op, const CheatCode &cheat,
switch (type) {
case 0: // 8 bit write
InvalidateICache(base + op.pointerCommands.offset, 4);
InvalidateICache(base + op.pointerCommands.offset, 1);
Memory::Write_U8((u8)val, base + op.pointerCommands.offset);
break;
case 1: // 16-bit write
InvalidateICache(base + op.pointerCommands.offset, 4);
InvalidateICache(base + op.pointerCommands.offset, 2);
Memory::Write_U16((u16)val, base + op.pointerCommands.offset);
break;
case 2: // 32-bit write
@ -1165,11 +1169,11 @@ void CWCheatEngine::ExecuteOp(const CheatOperation &op, const CheatCode &cheat,
Memory::Write_U32((u32)val, base + op.pointerCommands.offset);
break;
case 3: // 8 bit inverse write
InvalidateICache(base - op.pointerCommands.offset, 4);
InvalidateICache(base - op.pointerCommands.offset, 1);
Memory::Write_U8((u8)val, base - op.pointerCommands.offset);
break;
case 4: // 16-bit inverse write
InvalidateICache(base - op.pointerCommands.offset, 4);
InvalidateICache(base - op.pointerCommands.offset, 2);
Memory::Write_U16((u16)val, base - op.pointerCommands.offset);
break;
case 5: // 32-bit inverse write

View File

@ -45,6 +45,10 @@ DebuggerSubscriber *WebSocketMemoryInit(DebuggerEventHandlerMap &map) {
}
struct AutoDisabledReplacements {
AutoDisabledReplacements() {}
AutoDisabledReplacements(AutoDisabledReplacements &&other);
AutoDisabledReplacements(const AutoDisabledReplacements &) = delete;
AutoDisabledReplacements &operator =(const AutoDisabledReplacements &) = delete;
~AutoDisabledReplacements();
Memory::MemoryInitedLock *lock = nullptr;
@ -76,6 +80,17 @@ static AutoDisabledReplacements LockMemoryAndCPU(uint32_t addr, bool keepReplace
return result;
}
AutoDisabledReplacements::AutoDisabledReplacements(AutoDisabledReplacements &&other) {
lock = other.lock;
other.lock = nullptr;
replacements = std::move(other.replacements);
emuhacks = std::move(emuhacks);
saved = other.saved;
other.saved = false;
wasStepping = other.wasStepping;
other.wasStepping = true;
}
AutoDisabledReplacements::~AutoDisabledReplacements() {
if (saved) {
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);

View File

@ -1210,6 +1210,8 @@ void PSPSaveDialog::JoinIOThread() {
static void DoExecuteIOAction(PSPSaveDialog *dialog) {
SetCurrentThreadName("SaveIO");
AndroidJNIThreadContext jniContext;
dialog->ExecuteIOAction();
}

View File

@ -269,6 +269,8 @@ void CachingFileLoader::StartReadAhead(s64 pos) {
aheadThread_ = std::thread([this, pos] {
SetCurrentThreadName("FileLoaderReadAhead");
AndroidJNIThreadContext jniContext;
std::unique_lock<std::recursive_mutex> guard(blocksMutex_);
s64 cacheStartPos = pos >> BLOCK_SHIFT;
s64 cacheEndPos = cacheStartPos + BLOCK_READAHEAD - 1;

View File

@ -227,6 +227,8 @@ void RamCachingFileLoader::StartReadAhead(s64 pos) {
aheadThread_ = std::thread([this] {
SetCurrentThreadName("FileLoaderReadAhead");
AndroidJNIThreadContext jniContext;
while (aheadRemaining_ != 0 && !aheadCancel_) {
// Where should we look?
const u32 cacheStartPos = NextAheadBlock();

View File

@ -317,7 +317,8 @@ public:
int numInternalFonts = (int)internalFonts.size();
Do(p, numInternalFonts);
if (numInternalFonts != (int)internalFonts.size()) {
// It's okay if numInternalFonts was zero and we've now loaded them.
if (numInternalFonts != (int)internalFonts.size() && numInternalFonts != 0) {
ERROR_LOG(SCEFONT, "Unable to load state: different internal font count.");
p.SetError(p.ERROR_FAILURE);
return;
@ -329,6 +330,11 @@ public:
if (internalFont == -1) {
Do(p, font_);
} else if (p.mode == p.MODE_READ) {
if (internalFont < 0 || internalFont >= (int)internalFonts.size()) {
ERROR_LOG(SCEFONT, "Unable to load state: unexpected internal font index.");
p.SetError(p.ERROR_FAILURE);
return;
}
font_ = internalFonts[internalFont];
}
Do(p, handle_);
@ -947,11 +953,18 @@ void __FontShutdown() {
}
void __FontDoState(PointerWrap &p) {
auto s = p.Section("sceFont", 1, 2);
auto s = p.Section("sceFont", 1, 3);
if (!s)
return;
__LoadInternalFonts();
bool needInternalFonts = true;
if (s >= 3) {
// If we loaded internal fonts, we need to load them when loading the state.
needInternalFonts = !internalFonts.empty();
Do(p, needInternalFonts);
}
if (needInternalFonts)
__LoadInternalFonts();
Do(p, fontLibList);
Do(p, fontLibMap);

View File

@ -579,6 +579,7 @@ static void __IoAsyncEndCallback(SceUID threadID, SceUID prevCallbackId) {
static void __IoManagerThread() {
SetCurrentThreadName("IO");
AndroidJNIThreadContext jniContext;
while (ioManagerThreadEnabled && coreState != CORE_BOOT_ERROR && coreState != CORE_RUNTIME_ERROR && coreState != CORE_POWERDOWN) {
ioManager.RunEventsUntil(CoreTiming::GetTicks() + msToCycles(1000));
}

View File

@ -285,7 +285,7 @@ public:
void DoState(PointerWrap &p) override
{
auto s = p.Section("Module", 1, 5);
auto s = p.Section("Module", 1, 6);
if (!s)
return;
@ -301,6 +301,9 @@ public:
memcpy(((uint8_t *)pnm) + 0x30, ((uint8_t *)ptemp) + 0x2C, 0xC0 - 0x2C);
}
if (s >= 6)
Do(p, crc);
Do(p, memoryBlockAddr);
Do(p, memoryBlockSize);
Do(p, isFake);
@ -458,6 +461,7 @@ public:
u32 memoryBlockAddr = 0;
u32 memoryBlockSize = 0;
u32 crc = 0;
PSPPointer<NativeModule> modulePtr;
bool isFake = false;
};
@ -1144,12 +1148,12 @@ static int gzipDecompress(u8 *OutBuffer, int OutBufferLength, u8 *InBuffer) {
}
static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 loadAddress, bool fromTop, std::string *error_string, u32 *magic, u32 &error) {
u32 crc = crc32(0, ptr, (uInt)elfSize);
PSPModule *module = new PSPModule();
kernelObjects.Create(module);
loadedModules.insert(module->GetUID());
memset(&module->nm, 0, sizeof(module->nm));
module->crc = crc32(0, ptr, (uInt)elfSize);
module->nm.modid = module->GetUID();
bool reportedModule = false;
@ -1173,14 +1177,14 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load
if (IsHLEVersionedModule(head->modname)) {
int ver = (head->module_ver_hi << 8) | head->module_ver_lo;
INFO_LOG(SCEMODULE, "Loading module %s with version %04x, devkit %08x, crc %x", head->modname, ver, head->devkitversion, crc);
INFO_LOG(SCEMODULE, "Loading module %s with version %04x, devkit %08x, crc %x", head->modname, ver, head->devkitversion, module->crc);
reportedModule = true;
if (!strcmp(head->modname, "sceMpeg_library")) {
__MpegLoadModule(ver, crc);
__MpegLoadModule(ver, module->crc);
}
if (!strcmp(head->modname, "scePsmfP_library") || !strcmp(head->modname, "scePsmfPlayer")) {
__PsmfPlayerLoadModule(head->devkitversion, crc);
__PsmfPlayerLoadModule(head->devkitversion, module->crc);
}
}
@ -1614,10 +1618,10 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load
INFO_LOG(SCEMODULE, "Loading module %s with version %04x, devkit %08x", modinfo->name, modinfo->moduleVersion, devkitVersion);
if (!strcmp(modinfo->name, "sceMpeg_library")) {
__MpegLoadModule(modinfo->moduleVersion, crc);
__MpegLoadModule(modinfo->moduleVersion, module->crc);
}
if (!strcmp(modinfo->name, "scePsmfP_library") || !strcmp(modinfo->name, "scePsmfPlayer")) {
__PsmfPlayerLoadModule(devkitVersion, crc);
__PsmfPlayerLoadModule(devkitVersion, module->crc);
}
}
@ -1827,9 +1831,14 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str
host->NotifySymbolMapUpdated();
char moduleName[29] = { 0 };
int moduleVersion = module->nm.version[0] | (module->nm.version[1] << 8);
truncate_cpy(moduleName, module->nm.name);
Reporting::NotifyExecModule(moduleName, moduleVersion, module->crc);
mipsr4k.pc = module->nm.entry_addr;
INFO_LOG(LOADER, "Module entry: %08x", mipsr4k.pc);
INFO_LOG(LOADER, "Module entry: %08x (%s %04x)", mipsr4k.pc, moduleName, moduleVersion);
SceKernelSMOption option;
option.size = sizeof(SceKernelSMOption);

View File

@ -19,8 +19,10 @@
#include <condition_variable>
#include <mutex>
#include <thread>
#include "Common/Serialize/Serializer.h"
#include "Common/Serialize/SerializeFuncs.h"
#include "Common/Thread/ThreadUtil.h"
#include "Core/Config.h"
#include "Core/CoreTiming.h"
#include "Core/Compatibility.h"
@ -97,6 +99,10 @@ static void MemoryStick_CalcInitialFree() {
std::unique_lock<std::mutex> guard(freeCalcMutex);
freeCalcStatus = FreeCalcStatus::RUNNING;
freeCalcThread = std::thread([] {
SetCurrentThreadName("CalcInitialFree");
AndroidJNIThreadContext jniContext;
memstickInitialFree = pspFileSystem.FreeSpace("ms0:/") + pspFileSystem.ComputeRecursiveDirectorySize("ms0:/PSP/SAVEDATA/");
std::unique_lock<std::mutex> guard(freeCalcMutex);

View File

@ -82,7 +82,7 @@ u32 RunMemCheck(u32 pc, u32 addr) {
template <uint32_t alignment>
u32 RunValidateAddress(u32 pc, u32 addr, u32 isWrite) {
const auto toss = [&](MemoryExceptionType t) {
Core_MemoryException(addr, pc, t);
Core_MemoryException(addr, alignment, pc, t);
return coreState != CORE_RUNNING ? 1 : 0;
};

View File

@ -639,6 +639,9 @@ int JitBlockCache::GetBlockExitSize() {
#elif PPSSPP_ARCH(ARM64)
// Will depend on the sequence found to encode the destination address.
return 0;
#elif PPSSPP_ARCH(RISCV64)
// Will depend on the sequence found to encode the destination address.
return 0;
#else
#warning GetBlockExitSize unimplemented
return 0;
@ -690,6 +693,8 @@ JitBlockDebugInfo JitBlockCache::GetBlockDebugInfo(int blockNum) const {
debugInfo.targetDisasm = DisassembleArm64(block->normalEntry, block->codeSize);
#elif PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
debugInfo.targetDisasm = DisassembleX86(block->normalEntry, block->codeSize);
#elif PPSSPP_ARCH(ARM64)
debugInfo.targetDisasm = DisassembleRV64(block->normalEntry, block->codeSize);
#endif
return debugInfo;

View File

@ -20,6 +20,7 @@
#include <mutex>
#include "ext/disarm.h"
#include "ext/riscv-disas.h"
#include "ext/udis86/udis86.h"
#include "Common/LogReporting.h"
@ -306,3 +307,40 @@ std::vector<std::string> DisassembleX86(const u8 *data, int size) {
}
#endif
#if PPSSPP_ARCH(RISCV64) || defined(DISASM_ALL)
std::vector<std::string> DisassembleRV64(const u8 *data, int size) {
std::vector<std::string> lines;
int invalid_count = 0;
auto invalid_flush = [&]() {
if (invalid_count != 0) {
lines.push_back(StringFromFormat("(%d invalid bytes)", invalid_count));
invalid_count = 0;
}
};
char temp[512];
rv_inst inst;
size_t len;
for (int i = 0; i < size; ) {
riscv_inst_fetch(data + i, &inst, &len);
if (len == 0) {
// Force align in case we're somehow unaligned.
len = 2 - ((uintptr_t)data & 1);
invalid_count += (int)len;
i +=(int) len;
continue;
}
invalid_flush();
riscv_disasm_inst(temp, sizeof(temp), rv64, i * 4, inst);
lines.push_back(ReplaceAll(temp, "\t", " "));
i += (int)len;
}
invalid_flush();
return lines;
}
#endif

View File

@ -28,6 +28,7 @@
std::vector<std::string> DisassembleArm2(const u8 *data, int size);
std::vector<std::string> DisassembleArm64(const u8 *data, int size);
std::vector<std::string> DisassembleX86(const u8 *data, int size);
std::vector<std::string> DisassembleRV64(const u8 *data, int size);
struct JitBlock;
class JitBlockCache;

View File

@ -112,7 +112,7 @@ namespace MIPSInt
// Invalidate the instruction cache at this address.
// We assume the CPU won't be reset during this, so no locking.
if (MIPSComp::jit) {
MIPSComp::jit->InvalidateCacheAt(addr, 0x40);
MIPSComp::jit->InvalidateCacheAt(addr & ~0x3F, 0x40);
}
break;

View File

@ -84,6 +84,12 @@ static bool DisassembleNativeAt(const uint8_t *codePtr, int instructionSize, std
*dest = lines[0];
return true;
}
#elif PPSSPP_ARCH(RISCV64)
auto lines = DisassembleRV64(codePtr, instructionSize);
if (!lines.empty()) {
*dest = lines[0];
return true;
}
#endif
return false;
}
@ -282,7 +288,9 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) {
// Either bIgnoreBadMemAccess is off, or we failed recovery analysis.
// We can't ignore this memory access.
uint32_t approximatePC = currentMIPS->pc;
Core_MemoryExceptionInfo(guestAddress, approximatePC, type, infoString, true);
// TODO: Determine access size from the disassembled native instruction. We have some partial info already,
// just need to clean it up.
Core_MemoryExceptionInfo(guestAddress, 0, approximatePC, type, infoString, true);
// There's a small chance we can resume from this type of crash.
g_lastCrashAddress = codePtr;

View File

@ -289,7 +289,7 @@ inline void MemcpyUnchecked(const u32 to_address, const void *from_data, const u
}
inline void MemcpyUnchecked(const u32 to_address, const u32 from_address, const u32 len) {
MemcpyUnchecked(GetPointerWrite(to_address), from_address, len);
MemcpyUnchecked(GetPointerWriteUnchecked(to_address), from_address, len);
}
inline bool IsValidAddress(const u32 address) {

View File

@ -40,7 +40,9 @@ u8 *GetPointerWrite(const u32 address) {
Reporting::ReportMessage("Unknown GetPointerWrite %08x PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]);
reported = true;
}
Core_MemoryException(address, currentMIPS->pc, MemoryExceptionType::WRITE_BLOCK);
// Size is not known, we pass 0 to signal that.
Core_MemoryException(address, 0, currentMIPS->pc, MemoryExceptionType::WRITE_BLOCK);
return nullptr;
}
}
@ -57,7 +59,8 @@ const u8 *GetPointer(const u32 address) {
Reporting::ReportMessage("Unknown GetPointer %08x PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]);
reported = true;
}
Core_MemoryException(address, currentMIPS->pc, MemoryExceptionType::READ_BLOCK);
// Size is not known, we pass 0 to signal that.
Core_MemoryException(address, 0, currentMIPS->pc, MemoryExceptionType::READ_BLOCK);
return nullptr;
}
}
@ -67,7 +70,7 @@ u8 *GetPointerWriteRange(const u32 address, const u32 size) {
if (ptr) {
if (ValidSize(address, size) != size) {
// That's a memory exception! TODO: Adjust reported address to the end of the range?
Core_MemoryException(address, currentMIPS->pc, MemoryExceptionType::WRITE_BLOCK);
Core_MemoryException(address, size, currentMIPS->pc, MemoryExceptionType::WRITE_BLOCK);
return nullptr;
} else {
return ptr;
@ -83,7 +86,7 @@ const u8 *GetPointerRange(const u32 address, const u32 size) {
if (ptr) {
if (ValidSize(address, size) != size) {
// That's a memory exception! TODO: Adjust reported address to the end of the range?
Core_MemoryException(address, currentMIPS->pc, MemoryExceptionType::READ_BLOCK);
Core_MemoryException(address, size, currentMIPS->pc, MemoryExceptionType::READ_BLOCK);
return nullptr;
} else {
return ptr;
@ -115,7 +118,7 @@ inline void ReadFromHardware(T &var, const u32 address) {
Reporting::ReportMessage("ReadFromHardware: Invalid address %08x near PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]);
reported = true;
}
Core_MemoryException(address, currentMIPS->pc, MemoryExceptionType::READ_WORD);
Core_MemoryException(address, sizeof(T), currentMIPS->pc, MemoryExceptionType::READ_WORD);
var = 0;
}
}
@ -140,7 +143,7 @@ inline void WriteToHardware(u32 address, const T data) {
Reporting::ReportMessage("WriteToHardware: Invalid address %08x near PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]);
reported = true;
}
Core_MemoryException(address, currentMIPS->pc, MemoryExceptionType::WRITE_WORD);
Core_MemoryException(address, sizeof(T), currentMIPS->pc, MemoryExceptionType::WRITE_WORD);
}
}

View File

@ -307,7 +307,7 @@ bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string) {
//in case we didn't go through EmuScreen::boot
g_Config.loadGameConfig(id, g_paramSFO.GetValueString("TITLE"));
host->SendUIMessage("config_loaded", "");
INFO_LOG(LOADER,"Loading %s...", bootpath.c_str());
INFO_LOG(LOADER, "Loading %s...", bootpath.c_str());
PSPLoaders_Shutdown();
// Note: this thread reads the game binary, loads caches, and links HLE while UI spins.
@ -319,6 +319,8 @@ bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string) {
if (coreState != CORE_POWERUP)
return;
AndroidJNIThreadContext jniContext;
PSP_SetLoading("Loading executable...");
// TODO: We can't use the initial error_string pointer.
bool success = __KernelLoadExec(bootpath.c_str(), 0, &PSP_CoreParameter().errorString);
@ -455,6 +457,8 @@ bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string) {
if (coreState != CORE_POWERUP)
return;
AndroidJNIThreadContext jniContext;
bool success = __KernelLoadExec(finalName.c_str(), 0, &PSP_CoreParameter().errorString);
if (success && coreState == CORE_POWERUP) {
coreState = PSP_CoreParameter().startBreak ? CORE_STEPPING : CORE_RUNNING;
@ -479,6 +483,8 @@ bool Load_PSP_GE_Dump(FileLoader *fileLoader, std::string *error_string) {
if (coreState != CORE_POWERUP)
return;
AndroidJNIThreadContext jniContext;
bool success = __KernelLoadGEDump("disc0:/data.ppdmp", &PSP_CoreParameter().errorString);
if (success && coreState == CORE_POWERUP) {
coreState = PSP_CoreParameter().startBreak ? CORE_STEPPING : CORE_RUNNING;

View File

@ -70,6 +70,10 @@ namespace Reporting
// The latest compatibility result from the server.
static std::vector<std::string> lastCompatResult;
static std::string lastModuleName;
static int lastModuleVersion;
static uint32_t lastModuleCrc;
static std::mutex pendingMessageLock;
static std::condition_variable pendingMessageCond;
static std::deque<int> pendingMessages;
@ -107,6 +111,8 @@ namespace Reporting
static int CalculateCRCThread() {
SetCurrentThreadName("ReportCRC");
AndroidJNIThreadContext jniContext;
FileLoader *fileLoader = ResolveFileLoaderTarget(ConstructFileLoader(crcFilename));
BlockDevice *blockDevice = constructBlockDevice(fileLoader);
@ -352,6 +358,10 @@ namespace Reporting
currentSupported = IsSupported();
pendingMessagesDone = false;
Reporting::SetupCallbacks(&MessageAllowed, &SendReportMessage);
lastModuleName.clear();
lastModuleVersion = 0;
lastModuleCrc = 0;
}
void Shutdown()
@ -395,6 +405,12 @@ namespace Reporting
everUnsupported = true;
}
void NotifyExecModule(const char *name, int ver, uint32_t crc) {
lastModuleName = name;
lastModuleVersion = ver;
lastModuleCrc = crc;
}
std::string CurrentGameID()
{
// TODO: Maybe ParamSFOData shouldn't include nulls in std::strings? Don't work to break savedata, though...
@ -408,6 +424,9 @@ namespace Reporting
postdata.Add("game", CurrentGameID());
postdata.Add("game_title", StripTrailingNull(g_paramSFO.GetValueString("TITLE")));
postdata.Add("sdkver", sceKernelGetCompiledSdkVersion());
postdata.Add("module_name", lastModuleName);
postdata.Add("module_ver", lastModuleVersion);
postdata.Add("module_crc", lastModuleCrc);
}
void AddSystemInfo(UrlEncoder &postdata)

View File

@ -41,6 +41,9 @@ namespace Reporting
// Should be called when debugging APIs are used in a way that could make the game crash.
void NotifyDebugger();
// Should be called for each LoadExec, with parameters of the module executed.
void NotifyExecModule(const char *name, int ver, uint32_t crc);
// Returns whether or not the reporting system is currently enabled.
bool IsEnabled();

View File

@ -164,6 +164,8 @@ namespace SaveState
compressThread_.join();
compressThread_ = std::thread([=]{
SetCurrentThreadName("SaveStateCompress");
// Should do no I/O, so no JNI thread context needed.
Compress(*result, *state, *base);
});
}

View File

@ -38,6 +38,7 @@
#include "Common/Log.h"
#include "Common/File/FileUtil.h"
#include "Common/StringUtils.h"
#include "Common/Thread/ThreadUtil.h"
#include "Core/Config.h"
#include "Core/Loaders.h"
#include "Core/ELF/ParamSFO.h"
@ -278,11 +279,15 @@ ZipFileContents DetectZipFileContents(struct zip *z, ZipFileInfo *info) {
// Parameters need to be by value, since this is a thread func.
bool GameManager::InstallGame(Path url, Path fileName, bool deleteAfter) {
if (installInProgress_) {
SetCurrentThreadName("InstallGame");
if (installInProgress_ || installDonePending_) {
ERROR_LOG(HLE, "Cannot have two installs in progress at the same time");
return false;
}
AndroidJNIThreadContext context; // Destructor detaches.
if (!File::Exists(fileName)) {
ERROR_LOG(HLE, "Game file '%s' doesn't exist", fileName.c_str());
return false;
@ -445,6 +450,7 @@ std::string GameManager::GetISOGameID(FileLoader *loader) const {
if (!bd) {
return "";
}
ISOFileSystem umd(&handles, bd);
PSPFileInfo info = umd.GetFileInfo("/PSP_GAME/PARAM.SFO");
@ -708,7 +714,7 @@ bool GameManager::InstallZippedISO(struct zip *z, int isoFileIndex, const Path &
}
bool GameManager::InstallGameOnThread(const Path &url, const Path &fileName, bool deleteAfter) {
if (installInProgress_) {
if (installInProgress_ || installDonePending_) {
return false;
}
installThread_.reset(new std::thread(std::bind(&GameManager::InstallGame, this, url, fileName, deleteAfter)));

View File

@ -58,7 +58,7 @@ public:
void Update();
GameManagerState GetState() {
if (installInProgress_)
if (installInProgress_ || installDonePending_)
return GameManagerState::INSTALLING;
if (curDownload_)
return GameManagerState::DOWNLOADING;

View File

@ -212,6 +212,8 @@ static void DiscHandler(const http::Request &request, const Path &filename) {
}
static void HandleListing(const http::Request &request) {
AndroidJNIThreadContext jniContext;
request.WriteHttpResponseHeader("1.0", 200, -1, "text/plain");
request.Out()->Printf("/\n");
if (serverFlags & (int)WebServerFlags::DISCS) {
@ -269,6 +271,8 @@ static void RedirectToDebugger(const http::Request &request) {
}
static void HandleFallback(const http::Request &request) {
AndroidJNIThreadContext jniContext;
if (serverFlags & (int)WebServerFlags::DISCS) {
Path filename = LocalFromRemotePath(request.resource());
if (!filename.empty()) {
@ -293,6 +297,8 @@ static void HandleFallback(const http::Request &request) {
}
static void ForwardDebuggerRequest(const http::Request &request) {
AndroidJNIThreadContext jniContext;
if (serverFlags & (int)WebServerFlags::DEBUGGER) {
// Check if this is a websocket request...
std::string upgrade;
@ -314,6 +320,8 @@ static void ForwardDebuggerRequest(const http::Request &request) {
static void ExecuteWebServer() {
SetCurrentThreadName("HTTPServer");
AndroidJNIThreadContext context; // Destructor detaches.
auto http = new http::Server(new NewThreadExecutor());
http->RegisterHandler("/", &HandleListing);
// This lists all the (current) recent ISOs.

View File

@ -110,6 +110,9 @@ public:
bool EverUsedExactEqualDepth() const {
return everUsedExactEqualDepth_;
}
void SetEverUsedExactEqualDepth(bool v) {
everUsedExactEqualDepth_ = v;
}
bool IsCodePtrVertexDecoder(const u8 *ptr) const {
return decJitCache_->IsInSpace(ptr);
@ -181,7 +184,7 @@ protected:
u16 *decIndex = nullptr;
// Cached vertex decoders
u32 lastVType_ = -1;
u32 lastVType_ = -1; // corresponds to dec_. Could really just pick it out of dec_...
DenseHashMap<u32, VertexDecoder *, nullptr> decoderMap_;
VertexDecoder *dec_ = nullptr;
VertexDecoderJitCache *decJitCache_ = nullptr;

View File

@ -96,9 +96,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
p.ApplySamplerMetadata(arrayTexture ? samplersStereo : samplersMono);
bool lmode = id.Bit(FS_BIT_LMODE);
bool doTexture = id.Bit(FS_BIT_DO_TEXTURE);
bool enableFog = id.Bit(FS_BIT_ENABLE_FOG);
bool enableAlphaTest = id.Bit(FS_BIT_ALPHA_TEST);
bool alphaTestAgainstZero = id.Bit(FS_BIT_ALPHA_AGAINST_ZERO);
@ -209,8 +207,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
// Note: the precision qualifiers must match the vertex shader!
WRITE(p, "layout (location = 1) %s in lowp vec4 v_color0;\n", shading);
if (lmode)
WRITE(p, "layout (location = 2) %s in lowp vec3 v_color1;\n", shading);
WRITE(p, "layout (location = 2) %s in lowp vec3 v_color1;\n", shading);
WRITE(p, "layout (location = 3) in highp float v_fogdepth;\n");
if (doTexture) {
WRITE(p, "layout (location = 0) in highp vec3 v_texcoord;\n");
@ -263,9 +260,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
if (doTexture && texFunc == GE_TEXFUNC_BLEND) {
WRITE(p, "float3 u_texenv : register(c%i);\n", CONST_PS_TEXENV);
}
if (enableFog) {
WRITE(p, "float3 u_fogcolor : register(c%i);\n", CONST_PS_FOGCOLOR);
}
WRITE(p, "float3 u_fogcolor : register(c%i);\n", CONST_PS_FOGCOLOR);
if (texture3D) {
WRITE(p, "float u_mipBias : register(c%i);\n", CONST_PS_MIPBIAS);
}
@ -313,9 +308,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
}
const char *colorInterpolation = doFlatShading && compat.shaderLanguage == HLSL_D3D11 ? "nointerpolation " : "";
WRITE(p, " %svec4 v_color0: COLOR0;\n", colorInterpolation);
if (lmode) {
WRITE(p, " vec3 v_color1: COLOR1;\n");
}
WRITE(p, " vec3 v_color1: COLOR1;\n");
WRITE(p, " float v_fogdepth: TEXCOORD1;\n");
if (needFragCoord) {
if (compat.shaderLanguage == HLSL_D3D11) {
@ -428,12 +421,9 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
}
WRITE(p, "%s %s lowp vec4 v_color0;\n", shading, compat.varying_fs);
if (lmode)
WRITE(p, "%s %s lowp vec3 v_color1;\n", shading, compat.varying_fs);
if (enableFog) {
*uniformMask |= DIRTY_FOGCOLOR;
WRITE(p, "uniform vec3 u_fogcolor;\n");
}
WRITE(p, "%s %s lowp vec3 v_color1;\n", shading, compat.varying_fs);
*uniformMask |= DIRTY_FOGCOLOR;
WRITE(p, "uniform vec3 u_fogcolor;\n");
WRITE(p, "%s %s float v_fogdepth;\n", compat.varying_fs, highpFog ? "highp" : "mediump");
if (doTexture) {
WRITE(p, "%s %s vec3 v_texcoord;\n", compat.varying_fs, highpTexcoord ? "highp" : "mediump");
@ -539,11 +529,8 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
if (compat.shaderLanguage == HLSL_D3D11 || compat.shaderLanguage == HLSL_D3D9) {
WRITE(p, " vec4 v_color0 = In.v_color0;\n");
if (lmode)
WRITE(p, " vec3 v_color1 = In.v_color1;\n");
if (enableFog) {
WRITE(p, " float v_fogdepth = In.v_fogdepth;\n");
}
WRITE(p, " vec3 v_color1 = In.v_color1;\n");
WRITE(p, " float v_fogdepth = In.v_fogdepth;\n");
if (doTexture) {
WRITE(p, " vec3 v_texcoord = In.v_texcoord;\n");
}
@ -578,14 +565,8 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
// Clear mode does not allow any fancy shading.
WRITE(p, " vec4 v = v_color0;\n");
} else {
const char *secondary = "";
// Secondary color for specular on top of texture
if (lmode) {
WRITE(p, " vec4 s = vec4(v_color1, 0.0);\n");
secondary = " + s";
} else {
secondary = "";
}
WRITE(p, " vec4 s = vec4(v_color1, 0.0);\n");
if (doTexture) {
char texcoord[64] = "v_texcoord";
@ -842,26 +823,26 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
if (doTextureAlpha) { // texfmt == RGBA
switch (texFunc) {
case GE_TEXFUNC_MODULATE:
WRITE(p, " vec4 v = p * t%s;\n", secondary);
WRITE(p, " vec4 v = p * t + s\n;");
break;
case GE_TEXFUNC_DECAL:
WRITE(p, " vec4 v = vec4(mix(p.rgb, t.rgb, t.a), p.a)%s;\n", secondary);
WRITE(p, " vec4 v = vec4(mix(p.rgb, t.rgb, t.a), p.a) + s;\n");
break;
case GE_TEXFUNC_BLEND:
WRITE(p, " vec4 v = vec4(mix(p.rgb, u_texenv.rgb, t.rgb), p.a * t.a)%s;\n", secondary);
WRITE(p, " vec4 v = vec4(mix(p.rgb, u_texenv.rgb, t.rgb), p.a * t.a) + s;\n");
break;
case GE_TEXFUNC_REPLACE:
WRITE(p, " vec4 v = t%s;\n", secondary);
WRITE(p, " vec4 v = t + s;\n");
break;
case GE_TEXFUNC_ADD:
case GE_TEXFUNC_UNKNOWN1:
case GE_TEXFUNC_UNKNOWN2:
case GE_TEXFUNC_UNKNOWN3:
WRITE(p, " vec4 v = vec4(p.rgb + t.rgb, p.a * t.a)%s;\n", secondary);
WRITE(p, " vec4 v = vec4(p.rgb + t.rgb, p.a * t.a) + s;\n");
break;
default:
WRITE(p, " vec4 v = p;\n"); break;
@ -869,26 +850,26 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
} else { // texfmt == RGB
switch (texFunc) {
case GE_TEXFUNC_MODULATE:
WRITE(p, " vec4 v = vec4(t.rgb * p.rgb, p.a)%s;\n", secondary);
WRITE(p, " vec4 v = vec4(t.rgb * p.rgb, p.a) + s;\n");
break;
case GE_TEXFUNC_DECAL:
WRITE(p, " vec4 v = vec4(t.rgb, p.a)%s;\n", secondary);
WRITE(p, " vec4 v = vec4(t.rgb, p.a) + s;\n");
break;
case GE_TEXFUNC_BLEND:
WRITE(p, " vec4 v = vec4(mix(p.rgb, u_texenv.rgb, t.rgb), p.a)%s;\n", secondary);
WRITE(p, " vec4 v = vec4(mix(p.rgb, u_texenv.rgb, t.rgb), p.a) + s;\n");
break;
case GE_TEXFUNC_REPLACE:
WRITE(p, " vec4 v = vec4(t.rgb, p.a)%s;\n", secondary);
WRITE(p, " vec4 v = vec4(t.rgb, p.a) + s;\n");
break;
case GE_TEXFUNC_ADD:
case GE_TEXFUNC_UNKNOWN1:
case GE_TEXFUNC_UNKNOWN2:
case GE_TEXFUNC_UNKNOWN3:
WRITE(p, " vec4 v = vec4(p.rgb + t.rgb, p.a)%s;\n", secondary); break;
WRITE(p, " vec4 v = vec4(p.rgb + t.rgb, p.a) + s;\n"); break;
default:
WRITE(p, " vec4 v = p;\n"); break;
}
@ -900,13 +881,11 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
}
} else {
// No texture mapping
WRITE(p, " vec4 v = v_color0 %s;\n", secondary);
WRITE(p, " vec4 v = v_color0 + s;\n");
}
if (enableFog) {
WRITE(p, " float fogCoef = clamp(v_fogdepth, 0.0, 1.0);\n");
WRITE(p, " v = mix(vec4(u_fogcolor, v.a), v, fogCoef);\n");
}
WRITE(p, " float fogCoef = clamp(v_fogdepth, 0.0, 1.0);\n");
WRITE(p, " v = mix(vec4(u_fogcolor, v.a), v, fogCoef);\n");
// Texture access is at half texels [0.5/256, 255.5/256], but colors are normalized [0, 255].
// So we have to scale to account for the difference.

View File

@ -453,10 +453,12 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(Framebuffer
}
if (vfb) {
bool resized = false;
if ((drawing_width != vfb->bufferWidth || drawing_height != vfb->bufferHeight)) {
// Even if it's not newly wrong, if this is larger we need to resize up.
if (vfb->width > vfb->bufferWidth || vfb->height > vfb->bufferHeight) {
ResizeFramebufFBO(vfb, vfb->width, vfb->height);
resized = true;
} else if (vfb->newWidth != drawing_width || vfb->newHeight != drawing_height) {
// If it's newly wrong, or changing every frame, just keep track.
vfb->newWidth = drawing_width;
@ -470,6 +472,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(Framebuffer
needsRecreate = needsRecreate || vfb->newHeight > vfb->bufferHeight || vfb->newHeight * 2 < vfb->bufferHeight;
if (needsRecreate) {
ResizeFramebufFBO(vfb, vfb->width, vfb->height, true);
resized = true;
// Let's discard this information, might be wrong now.
vfb->safeWidth = 0;
vfb->safeHeight = 0;
@ -483,6 +486,14 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(Framebuffer
// It's not different, let's keep track of that too.
vfb->lastFrameNewSize = gpuStats.numFlips;
}
if (!resized && renderScaleFactor_ != 1 && vfb->renderScaleFactor == 1) {
// Might be time to change this framebuffer - have we used depth?
if (vfb->usageFlags & FB_USAGE_COLOR_MIXED_DEPTH) {
ResizeFramebufFBO(vfb, vfb->width, vfb->height, true);
_assert_(vfb->renderScaleFactor != 1);
}
}
}
// None found? Create one.
@ -692,6 +703,8 @@ void FramebufferManagerCommon::CopyToDepthFromOverlappingFramebuffers(VirtualFra
}
gpuStats.numReinterpretCopies++;
src->usageFlags |= FB_USAGE_COLOR_MIXED_DEPTH;
dest->usageFlags |= FB_USAGE_COLOR_MIXED_DEPTH;
// Copying color to depth.
BlitUsingRaster(
@ -1140,6 +1153,8 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int
if (channel == RASTER_DEPTH) {
_dbg_assert_(srcPixelFormat == GE_FORMAT_DEPTH16);
flags = flags | DRAWTEX_DEPTH;
if (vfb)
vfb->usageFlags |= FB_USAGE_COLOR_MIXED_DEPTH;
}
Draw::Texture *pixelsTex = MakePixelTexture(srcPixels, srcPixelFormat, srcStride, width, height);
@ -1628,6 +1643,9 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w,
break;
}
if (vfb->usageFlags & FB_USAGE_COLOR_MIXED_DEPTH) {
force1x = false;
}
if (PSP_CoreParameter().compat.flags().Force04154000Download && vfb->fb_address == 0x04154000) {
force1x = true;
}
@ -1824,7 +1842,11 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
}
if (dstBuffer) {
dstBuffer->last_frame_used = gpuStats.numFlips;
if (channel == RASTER_DEPTH && !srcBuffer)
dstBuffer->usageFlags |= FB_USAGE_COLOR_MIXED_DEPTH;
}
if (srcBuffer && channel == RASTER_DEPTH && !dstBuffer)
srcBuffer->usageFlags |= FB_USAGE_COLOR_MIXED_DEPTH;
if (dstBuffer && srcBuffer) {
if (srcBuffer == dstBuffer) {

View File

@ -45,6 +45,7 @@ enum {
FB_USAGE_BLUE_TO_ALPHA = 64,
FB_USAGE_FIRST_FRAME_SAVED = 128,
FB_USAGE_RENDER_DEPTH = 256,
FB_USAGE_COLOR_MIXED_DEPTH = 512,
};
enum {

View File

@ -74,10 +74,8 @@ bool GenerateGeometryShader(const GShaderID &id, char *buffer, const ShaderLangu
}
varyings.push_back(VaryingDef{ "vec4", "v_color0", Draw::SEM_COLOR0, 1, "lowp" });
outVaryings.push_back(VaryingDef{ "vec4", "v_color0Out", Draw::SEM_COLOR0, 1, "lowp" });
if (id.Bit(GS_BIT_LMODE)) {
varyings.push_back(VaryingDef{ "vec3", "v_color1", Draw::SEM_COLOR1, 2, "lowp" });
outVaryings.push_back(VaryingDef{ "vec3", "v_color1Out", Draw::SEM_COLOR1, 2, "lowp" });
}
varyings.push_back(VaryingDef{ "vec3", "v_color1", Draw::SEM_COLOR1, 2, "lowp" });
outVaryings.push_back(VaryingDef{ "vec3", "v_color1Out", Draw::SEM_COLOR1, 2, "lowp" });
varyings.push_back(VaryingDef{ "float", "v_fogdepth", Draw::SEM_TEXCOORD1, 3, "highp" });
outVaryings.push_back(VaryingDef{ "float", "v_fogdepthOut", Draw::SEM_TEXCOORD1, 3, "highp" });

View File

@ -27,19 +27,19 @@ Draw2DPipelineInfo GenerateReinterpretFragmentShader(ShaderWriter &writer, GEBuf
switch (from) {
case GE_FORMAT_4444:
writer.C("uint packColor(vec4 val) {\n");
writer.C(" return uint(val.r * 15.99) | (uint(val.g * 15.99) << 4u) | (uint(val.b * 15.99) << 8u) | (uint(val.a * 15.99) << 12u);\n");
writer.C(" return uint(val.r * 15.99) | (uint(val.g * 15.99) << 0x4u) | (uint(val.b * 15.99) << 0x8u) | (uint(val.a * 15.99) << 0xCu);\n");
writer.C("}\n");
break;
case GE_FORMAT_5551:
writer.C("uint packColor(vec4 val) {\n");
writer.C(" uint color = uint(val.r * 31.99) | (uint(val.g * 31.99) << 5u) | (uint(val.b * 31.99) << 10u);\n");
writer.C(" uint color = uint(val.r * 31.99) | (uint(val.g * 31.99) << 0x5u) | (uint(val.b * 31.99) << 0xAu);\n");
writer.C(" if (val.a >= 0.5) color |= 0x8000U;\n");
writer.C(" return color;\n");
writer.C("}\n");
break;
case GE_FORMAT_565:
writer.C("uint packColor(vec4 val) {\n");
writer.C(" return uint(val.r * 31.99) | (uint(val.g * 63.99) << 5u) | (uint(val.b * 31.99) << 11u);\n");
writer.C(" return uint(val.r * 31.99) | (uint(val.g * 63.99) << 0x5u) | (uint(val.b * 31.99) << 0xBu);\n");
writer.C("}\n");
break;
case GE_FORMAT_8888:
@ -86,22 +86,22 @@ Draw2DPipelineInfo GenerateReinterpretFragmentShader(ShaderWriter &writer, GEBuf
switch (to) {
case GE_FORMAT_4444:
writer.C("vec4 unpackColor(uint color) {\n");
writer.C(" vec4 outColor = vec4(float(color & 0xFU), float((color >> 4u) & 0xFU), float((color >> 8u) & 0xFU), float((color >> 12u) & 0xFU));\n");
writer.C(" vec4 outColor = vec4(float(color & 0xFu), float((color >> 0x4u) & 0xFu), float((color >> 0x8u) & 0xFu), float((color >> 0xCu) & 0xFu));\n");
writer.C(" outColor *= 1.0 / 15.0;\n");
writer.C(" return outColor;\n");
writer.C("}\n");
break;
case GE_FORMAT_5551:
writer.C("vec4 unpackColor(uint color) {\n");
writer.C(" vec4 outColor = vec4(float(color & 0x1FU), float((color >> 5u) & 0x1FU), float((color >> 10u) & 0x1FU), 0.0);\n");
writer.C(" vec4 outColor = vec4(float(color & 0x1Fu), float((color >> 0x5u) & 0x1Fu), float((color >> 0xAu) & 0x1Fu), 0.0);\n");
writer.C(" outColor.rgb *= 1.0 / 31.0;\n");
writer.C(" outColor.a = float(color >> 15);\n");
writer.C(" outColor.a = float(color >> 0xFu);\n");
writer.C(" return outColor;\n");
writer.C("}\n");
break;
case GE_FORMAT_565:
writer.C("vec4 unpackColor(uint color) {\n");
writer.C(" vec4 outColor = vec4(float(color & 0x1FU), float((color >> 5u) & 0x3FU), float((color >> 11u) & 0x1FU), 1.0);\n");
writer.C(" vec4 outColor = vec4(float(color & 0x1Fu), float((color >> 0x5u) & 0x3Fu), float((color >> 0xBu) & 0x1Fu), 1.0);\n");
writer.C(" outColor.rb *= 1.0 / 31.0;\n");
writer.C(" outColor.g *= 1.0 / 63.0;\n");
writer.C(" return outColor;\n");
@ -109,8 +109,8 @@ Draw2DPipelineInfo GenerateReinterpretFragmentShader(ShaderWriter &writer, GEBuf
break;
case GE_FORMAT_8888:
writer.C("vec4 unpackColor(uint colorLeft, uint colorRight) {\n");
writer.C(" vec4 outColor = vec4(float(colorLeft & 0xFFu), float((colorLeft >> 8u) & 0xFFu),\n");
writer.C(" float(colorRight & 0xFFu), float((colorRight >> 8u) & 0xFFu));\n");
writer.C(" vec4 outColor = vec4(float(colorLeft & 0xFFu), float((colorLeft >> 0x8u) & 0xFFu),\n");
writer.C(" float(colorRight & 0xFFu), float((colorRight >> 0x8u) & 0xFFu));\n");
writer.C(" outColor *= 1.0 / 255.0;\n");
writer.C(" return outColor;\n");
writer.C("}\n");

View File

@ -45,7 +45,7 @@ enum : uint64_t {
DIRTY_PROJMATRIX = 1ULL << 0,
DIRTY_PROJTHROUGHMATRIX = 1ULL << 1,
DIRTY_FOGCOLOR = 1ULL << 2,
DIRTY_FOGCOEF = 1ULL << 3,
DIRTY_FOGCOEFENABLE = 1ULL << 3,
DIRTY_TEXENV = 1ULL << 4,
DIRTY_ALPHACOLORREF = 1ULL << 5,

View File

@ -67,21 +67,23 @@ std::string VertexShaderDesc(const VShaderID &id) {
return desc.str();
}
void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) {
void ComputeVertexShaderID(VShaderID *id_out, VertexDecoder *vertexDecoder, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) {
u32 vertType = vertexDecoder->VertexType();
bool isModeThrough = (vertType & GE_VTYPE_THROUGH) != 0;
bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear();
bool doShadeMapping = doTexture && (gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP);
bool doFlatShading = gstate.getShadeMode() == GE_SHADE_FLAT && !gstate.isModeClear();
bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0;
bool hasNormal = (vertType & GE_VTYPE_NRM_MASK) != 0;
bool hasTexcoord = (vertType & GE_VTYPE_TC_MASK) != 0;
bool vtypeHasColor = (vertType & GE_VTYPE_COL_MASK) != 0;
bool vtypeHasNormal = (vertType & GE_VTYPE_NRM_MASK) != 0;
bool vtypeHasTexcoord = (vertType & GE_VTYPE_TC_MASK) != 0;
bool doBezier = gstate_c.submitType == SubmitType::HW_BEZIER;
bool doSpline = gstate_c.submitType == SubmitType::HW_SPLINE;
if (doBezier || doSpline) {
_assert_(hasNormal);
_assert_(vtypeHasNormal);
}
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !isModeThrough && !gstate.isModeClear();
@ -89,9 +91,8 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform,
!isModeThrough && gstate_c.submitType == SubmitType::DRAW; // neither hw nor sw spline/bezier. See #11692
VShaderID id;
id.SetBit(VS_BIT_LMODE, lmode);
id.SetBit(VS_BIT_IS_THROUGH, isModeThrough);
id.SetBit(VS_BIT_HAS_COLOR, hasColor);
id.SetBit(VS_BIT_HAS_COLOR, vtypeHasColor);
id.SetBit(VS_BIT_VERTEX_RANGE_CULLING, vertexRangeCulling);
if (!isModeThrough && gstate_c.Use(GPU_USE_SINGLE_PASS_STEREO)) {
@ -107,7 +108,7 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform,
if (useHWTransform) {
id.SetBit(VS_BIT_USE_HW_TRANSFORM);
id.SetBit(VS_BIT_HAS_NORMAL, hasNormal);
id.SetBit(VS_BIT_HAS_NORMAL, vtypeHasNormal);
// The next bits are used differently depending on UVgen mode
if (gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX) {
@ -118,6 +119,7 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform,
}
// Bones.
u32 vertType = vertexDecoder->VertexType();
bool enableBones = !useSkinInDecode && vertTypeIsSkinningEnabled(vertType);
id.SetBit(VS_BIT_ENABLE_BONES, enableBones);
if (enableBones) {
@ -131,6 +133,7 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform,
// doShadeMapping is stored as UVGenMode, and light type doesn't matter for shade mapping.
id.SetBit(VS_BIT_LIGHTING_ENABLE);
if (gstate_c.Use(GPU_USE_LIGHT_UBERSHADER)) {
lmode = false; // handled dynamically.
id.SetBit(VS_BIT_LIGHT_UBERSHADER);
} else {
id.SetBits(VS_BIT_MATERIAL_UPDATE, 3, gstate.getMaterialUpdate());
@ -147,7 +150,7 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform,
}
id.SetBit(VS_BIT_NORM_REVERSE, gstate.areNormalsReversed());
id.SetBit(VS_BIT_HAS_TEXCOORD, hasTexcoord);
id.SetBit(VS_BIT_HAS_TEXCOORD, vtypeHasTexcoord);
if (useHWTessellation) {
id.SetBit(VS_BIT_BEZIER, doBezier);
@ -162,6 +165,7 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform,
}
}
id.SetBit(VS_BIT_LMODE, lmode);
id.SetBit(VS_BIT_FLATSHADE, doFlatShading);
// These two bits cannot be combined, otherwise havoc occurs. We get reports that indicate this happened somehow... "ERROR: 0:14: 'u_proj' : undeclared identifier"
@ -171,7 +175,11 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform,
}
static const char *alphaTestFuncs[] = { "NEVER", "ALWAYS", "==", "!=", "<", "<=", ">", ">=" };
static const char * const alphaTestFuncs[] = { "NEVER", "ALWAYS", "==", "!=", "<", "<=", ">", ">=" };
static const char * const logicFuncs[] = {
"CLEAR", "AND", "AND_REV", "COPY", "AND_INV", "NOOP", "XOR", "OR",
"NOR", "EQUIV", "INVERTED", "OR_REV", "COPY_INV", "OR_INV", "NAND", "SET",
};
static bool MatrixNeedsProjection(const float m[12], GETexProjMapMode mode) {
// For GE_PROJMAP_UV, we can ignore m[8] since it multiplies to zero.
@ -186,8 +194,6 @@ std::string FragmentShaderDesc(const FShaderID &id) {
if (id.Bit(FS_BIT_DO_TEXTURE_PROJ)) desc << "TexProj ";
if (id.Bit(FS_BIT_TEXALPHA)) desc << "TexAlpha ";
if (id.Bit(FS_BIT_TEXTURE_AT_OFFSET)) desc << "TexOffs ";
if (id.Bit(FS_BIT_LMODE)) desc << "LM ";
if (id.Bit(FS_BIT_ENABLE_FOG)) desc << "Fog ";
if (id.Bit(FS_BIT_COLOR_DOUBLE)) desc << "2x ";
if (id.Bit(FS_BIT_FLATSHADE)) desc << "Flat ";
if (id.Bit(FS_BIT_BGRA_TEXTURE)) desc << "BGRA ";
@ -257,7 +263,8 @@ std::string FragmentShaderDesc(const FShaderID &id) {
else if (id.Bit(FS_BIT_COLOR_TEST)) desc << "ColorTest " << alphaTestFuncs[id.Bits(FS_BIT_COLOR_TEST_FUNC, 2)] << " "; // first 4 match
if (id.Bit(FS_BIT_TEST_DISCARD_TO_ZERO)) desc << "TestDiscardToZero ";
if (id.Bit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL)) desc << "StencilDiscardWorkaround ";
if ((id.Bits(FS_BIT_REPLACE_LOGIC_OP, 4) != GE_LOGIC_COPY) && !id.Bit(FS_BIT_CLEARMODE)) desc << "ReplaceLogic ";
int logicMode = id.Bits(FS_BIT_REPLACE_LOGIC_OP, 4);
if ((logicMode != GE_LOGIC_COPY) && !id.Bit(FS_BIT_CLEARMODE)) desc << "RLogic(" << logicFuncs[logicMode] << ")";
if (id.Bit(FS_BIT_SAMPLE_ARRAY_TEXTURE)) desc << "TexArray ";
if (id.Bit(FS_BIT_STEREO)) desc << "Stereo ";
if (id.Bit(FS_BIT_USE_FRAMEBUFFER_FETCH)) desc << "(fetch)";
@ -279,7 +286,6 @@ void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pip
id.SetBit(FS_BIT_CLEARMODE);
} else {
bool isModeThrough = gstate.isModeThrough();
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !isModeThrough;
bool enableFog = gstate.isFogEnabled() && !isModeThrough;
bool enableAlphaTest = gstate.isAlphaTestEnabled() && !IsAlphaTestTriviallyTrue();
bool enableColorTest = gstate.isColorTestEnabled() && !IsColorTestTriviallyTrue();
@ -320,7 +326,6 @@ void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pip
id.SetBit(FS_BIT_3D_TEXTURE, gstate_c.curTextureIs3D);
}
id.SetBit(FS_BIT_LMODE, lmode);
if (enableAlphaTest) {
// 5 bits total.
id.SetBit(FS_BIT_ALPHA_TEST);
@ -337,7 +342,6 @@ void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pip
id.SetBit(FS_BIT_TEST_DISCARD_TO_ZERO, !NeedsTestDiscard());
}
id.SetBit(FS_BIT_ENABLE_FOG, enableFog);
id.SetBit(FS_BIT_DO_TEXTURE_PROJ, doTextureProjection);
id.SetBit(FS_BIT_COLOR_DOUBLE, enableColorDoubling);
@ -404,7 +408,6 @@ std::string GeometryShaderDesc(const GShaderID &id) {
desc << StringFromFormat("%08x:%08x ", id.d[1], id.d[0]);
if (id.Bit(GS_BIT_ENABLED)) desc << "ENABLED ";
if (id.Bit(GS_BIT_DO_TEXTURE)) desc << "TEX ";
if (id.Bit(GS_BIT_LMODE)) desc << "LMODE ";
return desc.str();
}
@ -436,9 +439,6 @@ void ComputeGeometryShaderID(GShaderID *id_out, const Draw::Bugs &bugs, int prim
if (gstate.isModeClear()) {
// No attribute bits.
} else {
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled() && !isModeThrough;
id.SetBit(GS_BIT_LMODE, lmode);
if (gstate.isTextureMapEnabled()) {
id.SetBit(GS_BIT_DO_TEXTURE);
}

View File

@ -74,14 +74,14 @@ enum FShaderBit : uint8_t {
FS_BIT_CLAMP_S = 8,
FS_BIT_CLAMP_T = 9,
FS_BIT_TEXTURE_AT_OFFSET = 10,
FS_BIT_LMODE = 11,
// 1 bit free
FS_BIT_ALPHA_TEST = 12,
FS_BIT_ALPHA_TEST_FUNC = 13, // 3 bits
FS_BIT_ALPHA_AGAINST_ZERO = 16,
FS_BIT_COLOR_TEST = 17,
FS_BIT_COLOR_TEST_FUNC = 18, // 2 bits
FS_BIT_COLOR_AGAINST_ZERO = 20,
FS_BIT_ENABLE_FOG = 21,
// 1 free bit
FS_BIT_DO_TEXTURE_PROJ = 22,
FS_BIT_COLOR_DOUBLE = 23,
FS_BIT_STENCIL_TO_ALPHA = 24, // 2 bits
@ -111,8 +111,7 @@ static inline FShaderBit operator +(FShaderBit bit, int i) {
enum GShaderBit : uint8_t {
GS_BIT_ENABLED = 0, // If not set, we don't use a geo shader.
GS_BIT_DO_TEXTURE = 1, // presence of texcoords
GS_BIT_LMODE = 2, // presence of specular color (regular color always present)
GS_BIT_CURVE = 3, // curve, which means don't do range culling.
GS_BIT_CURVE = 2, // curve, which means don't do range culling.
};
static inline GShaderBit operator +(GShaderBit bit, int i) {
@ -278,7 +277,9 @@ namespace Draw {
class Bugs;
}
void ComputeVertexShaderID(VShaderID *id, uint32_t vertexType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode);
class VertexDecoder;
void ComputeVertexShaderID(VShaderID *id, VertexDecoder *vertexDecoder, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode);
// Generates a compact string that describes the shader. Useful in a list to get an overview
// of the current flora of shaders.
std::string VertexShaderDesc(const VShaderID &id);

View File

@ -174,21 +174,28 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView
ConvertMatrix4x3To3x4Transposed(ub->tex, gstate.tgenMatrix);
}
if (dirtyUniforms & DIRTY_FOGCOEF) {
float fogcoef[2] = {
getFloat24(gstate.fog1),
getFloat24(gstate.fog2),
};
// The PSP just ignores infnan here (ignoring IEEE), so take it down to a valid float.
// Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988
if (my_isnanorinf(fogcoef[0])) {
// Not really sure what a sensible value might be, but let's try 64k.
fogcoef[0] = std::signbit(fogcoef[0]) ? -65535.0f : 65535.0f;
if (dirtyUniforms & DIRTY_FOGCOEFENABLE) {
if (gstate.isFogEnabled() && !gstate.isModeThrough()) {
float fogcoef[2] = {
getFloat24(gstate.fog1),
getFloat24(gstate.fog2),
};
// The PSP just ignores infnan here (ignoring IEEE), so take it down to a valid float.
// Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988
if (my_isnanorinf(fogcoef[0])) {
// Not really sure what a sensible value might be, but let's try 64k.
fogcoef[0] = std::signbit(fogcoef[0]) ? -65535.0f : 65535.0f;
}
if (my_isnanorinf(fogcoef[1])) {
fogcoef[1] = std::signbit(fogcoef[1]) ? -65535.0f : 65535.0f;
}
CopyFloat2(ub->fogCoef, fogcoef);
} else {
// not very useful values, use as marker for disabled fog.
// could also burn one extra uniform.
ub->fogCoef[0] = -65536.0f;
ub->fogCoef[1] = -65536.0f;
}
if (my_isnanorinf(fogcoef[1])) {
fogcoef[1] = std::signbit(fogcoef[1]) ? -65535.0f : 65535.0f;
}
CopyFloat2(ub->fogCoef, fogcoef);
}
if (dirtyUniforms & DIRTY_STENCILREPLACEVALUE) {
@ -267,6 +274,7 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView
}
}
// For "light ubershader" bits.
uint32_t PackLightControlBits() {
// Bit organization
// Bottom 4 bits are enable bits for each light.
@ -285,8 +293,10 @@ uint32_t PackLightControlBits() {
lightControl |= type << (4 + i * 4 + 2);
}
// Material update is 3 bits.
lightControl |= gstate.getMaterialUpdate() << 20;
// LMODE is 1 bit.
lightControl |= gstate.isUsingSecondaryColor() << 23;
return lightControl;
}

View File

@ -9,7 +9,7 @@
enum : uint64_t {
DIRTY_BASE_UNIFORMS =
DIRTY_WORLDMATRIX | DIRTY_PROJTHROUGHMATRIX | DIRTY_VIEWMATRIX | DIRTY_TEXMATRIX | DIRTY_ALPHACOLORREF |
DIRTY_PROJMATRIX | DIRTY_FOGCOLOR | DIRTY_FOGCOEF | DIRTY_TEXENV | DIRTY_STENCILREPLACEVALUE |
DIRTY_PROJMATRIX | DIRTY_FOGCOLOR | DIRTY_FOGCOEFENABLE | DIRTY_TEXENV | DIRTY_STENCILREPLACEVALUE |
DIRTY_ALPHACOLORMASK | DIRTY_SHADERBLEND | DIRTY_COLORWRITEMASK | DIRTY_UVSCALEOFFSET | DIRTY_TEXCLAMP | DIRTY_DEPTHRANGE | DIRTY_MATAMBIENTALPHA |
DIRTY_BEZIERSPLINE | DIRTY_DEPAL,
DIRTY_LIGHT_UNIFORMS =

View File

@ -241,9 +241,11 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt
// Ignore color1 and fog, never used in throughmode anyway.
// The w of uv is also never used (hardcoded to 1.0.)
vert.fog = 1.0;
}
} else {
const Vec4f materialAmbientRGBA = Vec4f::FromRGBA(gstate.getMaterialAmbientRGBA());
bool fogEnabled = gstate.isFogEnabled();
// Okay, need to actually perform the full transform.
for (int index = 0; index < maxIndex; index++) {
reader.Goto(index);
@ -252,7 +254,6 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt
Vec4f c0 = Vec4f(1, 1, 1, 1);
Vec4f c1 = Vec4f(0, 0, 0, 0);
float uv[3] = {0, 0, 1};
float fogCoef = 1.0f;
float out[3];
float pos[3];
@ -414,11 +415,10 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt
// Transform the coord by the view matrix.
Vec3ByMatrix43(v, out, gstate.viewMatrix);
fogCoef = (v[2] + fog_end) * fog_slope;
// TODO: Write to a flexible buffer, we don't always need all four components.
Vec3ByMatrix44(transformed[index].pos, v, projMatrix_.m);
transformed[index].fog = fogCoef;
transformed[index].fog = fogEnabled ? (v[2] + fog_end) * fog_slope : 1.0f;
memcpy(&transformed[index].uv, uv, 3 * sizeof(float));
transformed[index].color0_32 = c0.ToRGBA();
transformed[index].color1_32 = c1.ToRGBA();

View File

@ -1100,6 +1100,9 @@ void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate)
if (gstate_c.curTextureXOffset != 0 || gstate_c.curTextureYOffset != 0) {
gstate_c.SetNeedShaderTexclamp(true);
}
if (channel == RASTER_DEPTH) {
framebuffer->usageFlags |= FB_USAGE_COLOR_MIXED_DEPTH;
}
if (channel == RASTER_DEPTH && !gstate_c.Use(GPU_USE_DEPTH_TEXTURE)) {
WARN_LOG_ONCE(ndepthtex, G3D, "Depth textures not supported, not binding");

View File

@ -1359,6 +1359,8 @@ std::string VertexDecoder::GetString(DebugShaderStringType stringType) {
lines = DisassembleArm2((const u8 *)jitted_, jittedSize_);
#elif PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
lines = DisassembleX86((const u8 *)jitted_, jittedSize_);
#elif PPSSPP_ARCH(RISCV64)
lines = DisassembleRV64((const u8 *)jitted_, jittedSize_);
#else
// No disassembler defined
#endif

View File

@ -337,8 +337,6 @@ public:
void DecodeVerts(u8 *decoded, const void *verts, int indexLowerBound, int indexUpperBound) const;
bool hasColor() const { return col != 0; }
bool hasTexcoord() const { return tc != 0; }
int VertexSize() const { return size; } // PSP format size
std::string GetString(DebugShaderStringType stringType);

View File

@ -285,9 +285,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
}
WRITE(p, "layout (location = 1) %sout lowp vec4 v_color0;\n", shading);
if (lmode) {
WRITE(p, "layout (location = 2) %sout lowp vec3 v_color1;\n", shading);
}
WRITE(p, "layout (location = 2) %sout lowp vec3 v_color1;\n", shading);
if (doTexture) {
WRITE(p, "layout (location = 0) out highp vec3 v_texcoord;\n");
@ -423,8 +421,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
}
const char *colorInterpolation = doFlatShading && compat.shaderLanguage == HLSL_D3D11 ? "nointerpolation " : "";
WRITE(p, " %svec4 v_color0 : COLOR0;\n", colorInterpolation);
if (lmode)
WRITE(p, " vec3 v_color1 : COLOR1;\n");
WRITE(p, " vec3 v_color1 : COLOR1;\n");
WRITE(p, " float v_fogdepth : TEXCOORD1;\n");
if (compat.shaderLanguage == HLSL_D3D9) {
@ -585,7 +582,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
*uniformMask |= DIRTY_MATAMBIENTALPHA;
}
WRITE(p, "uniform highp vec2 u_fogcoef;\n");
*uniformMask |= DIRTY_FOGCOEF;
*uniformMask |= DIRTY_FOGCOEFENABLE;
if (!isModeThrough) {
WRITE(p, "uniform highp vec4 u_depthRange;\n");
@ -595,9 +592,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
}
WRITE(p, "%s%s lowp vec4 v_color0;\n", shading, compat.varying_vs);
if (lmode) {
WRITE(p, "%s%s lowp vec3 v_color1;\n", shading, compat.varying_vs);
}
WRITE(p, "%s%s lowp vec3 v_color1;\n", shading, compat.varying_vs);
if (doTexture) {
WRITE(p, "%s %s vec3 v_texcoord;\n", compat.varying_vs, highpTexcoord ? "highp" : "mediump");
@ -838,10 +833,11 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, " %sv_color0 = color0;\n", compat.vsOutPrefix);
if (lmode)
WRITE(p, " %sv_color1 = color1;\n", compat.vsOutPrefix);
else
WRITE(p, " %sv_color1 = splat3(0.0);\n", compat.vsOutPrefix);
} else {
WRITE(p, " %sv_color0 = u_matambientalpha;\n", compat.vsOutPrefix);
if (lmode)
WRITE(p, " %sv_color1 = splat3(0.0);\n", compat.vsOutPrefix);
WRITE(p, " %sv_color1 = splat3(0.0);\n", compat.vsOutPrefix);
}
WRITE(p, " %sv_fogdepth = fog;\n", compat.vsOutPrefix);
if (isModeThrough) {
@ -1156,20 +1152,29 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
}
if (enableLighting) {
// Sum up ambient, emissive here.
if (lmode) {
WRITE(p, " %sv_color0 = clamp(lightSum0, 0.0, 1.0);\n", compat.vsOutPrefix);
// v_color1 only exists when lmode = 1.
if (specularIsZero) {
WRITE(p, " %sv_color1 = splat3(0.0);\n", compat.vsOutPrefix);
} else {
WRITE(p, " %sv_color1 = clamp(lightSum1, 0.0, 1.0);\n", compat.vsOutPrefix);
}
WRITE(p, " lightSum0 = clamp(lightSum0, 0.0, 1.0);\n");
if (specularIsZero) {
WRITE(p, " %sv_color0 = lightSum0;\n", compat.vsOutPrefix);
WRITE(p, " %sv_color1 = splat3(0.0);\n", compat.vsOutPrefix);
} else {
if (specularIsZero) {
WRITE(p, " %sv_color0 = clamp(lightSum0, 0.0, 1.0);\n", compat.vsOutPrefix);
if (lightUberShader) {
p.C(" bool lmode = (u_lightControl & (0x1u << 0x17u)) != 0x0u;\n");
p.C(" if (lmode) {");
p.F(" %sv_color0 = lightSum0;\n", compat.vsOutPrefix);
p.F(" %sv_color1 = clamp(lightSum1, 0.0, 1.0);\n", compat.vsOutPrefix);
p.C(" } else {");
p.F(" %sv_color0 = clamp(lightSum0 + vec4(lightSum1, 0.0), 0.0, 1.0);\n", compat.vsOutPrefix);
p.F(" %sv_color1 = splat3(0.0);\n", compat.vsOutPrefix);
p.C(" }");
} else {
WRITE(p, " %sv_color0 = clamp(clamp(lightSum0, 0.0, 1.0) + vec4(lightSum1, 0.0), 0.0, 1.0);\n", compat.vsOutPrefix);
if (lmode) {
WRITE(p, " %sv_color0 = lightSum0;\n", compat.vsOutPrefix);
// v_color1 only exists when lmode = 1.
WRITE(p, " %sv_color1 = clamp(lightSum1, 0.0, 1.0);\n", compat.vsOutPrefix);
} else {
WRITE(p, " %sv_color0 = clamp(lightSum0 + vec4(lightSum1, 0.0), 0.0, 1.0);\n", compat.vsOutPrefix);
WRITE(p, " %sv_color1 = splat3(0.0);\n", compat.vsOutPrefix);
}
}
}
} else {
@ -1185,8 +1190,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, " %sv_color0.r += 0.000001;\n", compat.vsOutPrefix);
}
}
if (lmode)
WRITE(p, " %sv_color1 = splat3(0.0);\n", compat.vsOutPrefix);
WRITE(p, " %sv_color1 = splat3(0.0);\n", compat.vsOutPrefix);
}
bool scaleUV = !isModeThrough && (uvGenMode == GE_TEXMAP_TEXTURE_COORDS || uvGenMode == GE_TEXMAP_UNKNOWN);
@ -1277,7 +1281,11 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
}
// Compute fogdepth
WRITE(p, " %sv_fogdepth = (viewPos.z + u_fogcoef.x) * u_fogcoef.y;\n", compat.vsOutPrefix);
WRITE(p, " if (u_fogcoef.x <= -65535.0 && u_fogcoef.y <= -65535.0) {\n");
WRITE(p, " %sv_fogdepth = 1.0;\n", compat.vsOutPrefix);
WRITE(p, " } else {\n");
WRITE(p, " %sv_fogdepth = (viewPos.z + u_fogcoef.x) * u_fogcoef.y;\n", compat.vsOutPrefix);
WRITE(p, " }\n");
}
if (clipClampedDepth) {

View File

@ -334,8 +334,6 @@ void DrawEngineD3D11::Invalidate(InvalidationCallbackFlags flags) {
// The inline wrapper in the header checks for numDrawCalls == 0
void DrawEngineD3D11::DoFlush() {
gpuStats.numFlushes++;
bool textureNeedsApply = false;
if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {
textureCache_->SetTexture();
@ -539,7 +537,7 @@ rotateVBO:
D3D11VertexShader *vshader;
D3D11FragmentShader *fshader;
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, pipelineState_, useHWTransform, useHWTessellation_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode);
shaderManager_->GetShaders(prim, dec_, &vshader, &fshader, pipelineState_, useHWTransform, useHWTessellation_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode);
ID3D11InputLayout *inputLayout = SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType());
context_->PSSetShader(fshader->GetShader(), nullptr, 0);
context_->VSSetShader(vshader->GetShader(), nullptr, 0);
@ -658,7 +656,7 @@ rotateVBO:
if (result.action == SW_DRAW_PRIMITIVES) {
D3D11VertexShader *vshader;
D3D11FragmentShader *fshader;
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true);
shaderManager_->GetShaders(prim, dec_, &vshader, &fshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true);
context_->PSSetShader(fshader->GetShader(), nullptr, 0);
context_->VSSetShader(vshader->GetShader(), nullptr, 0);
shaderManager_->UpdateUniforms(framebufferManager_->UseBufferedRendering());
@ -722,6 +720,7 @@ rotateVBO:
decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning;
}
gpuStats.numFlushes++;
gpuStats.numDrawCalls += numDrawCalls;
gpuStats.numVertsSubmitted += vertexCountInDrawCalls_;

View File

@ -157,6 +157,14 @@ void GPU_D3D11::BeginFrame() {
framebufferManagerD3D11_->BeginFrame();
gstate_c.Dirty(DIRTY_PROJTHROUGHMATRIX);
if (gstate_c.useFlagsChanged) {
// TODO: It'd be better to recompile them in the background, probably?
// This most likely means that saw equal depth changed.
WARN_LOG(G3D, "Shader use flags changed, clearing all shaders");
shaderManagerD3D11_->ClearShaders();
gstate_c.useFlagsChanged = false;
}
}
void GPU_D3D11::CopyDisplayToOutput(bool reallyDirty) {

View File

@ -62,7 +62,7 @@ std::string D3D11FragmentShader::GetShaderString(DebugShaderStringType type) con
}
}
D3D11VertexShader::D3D11VertexShader(ID3D11Device *device, D3D_FEATURE_LEVEL featureLevel, VShaderID id, const char *code, int vertType, bool useHWTransform)
D3D11VertexShader::D3D11VertexShader(ID3D11Device *device, D3D_FEATURE_LEVEL featureLevel, VShaderID id, const char *code, bool useHWTransform)
: device_(device), useHWTransform_(useHWTransform), id_(id) {
source_ = code;
@ -178,13 +178,13 @@ void ShaderManagerD3D11::BindUniforms() {
context_->PSSetConstantBuffers(0, 1, ps_cbs);
}
void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) {
void ShaderManagerD3D11::GetShaders(int prim, VertexDecoder *decoder, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) {
VShaderID VSID;
FShaderID FSID;
if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {
gstate_c.Clean(DIRTY_VERTEXSHADER_STATE);
ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode);
ComputeVertexShaderID(&VSID, decoder, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode);
} else {
VSID = lastVSID_;
}
@ -214,7 +214,7 @@ void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader **
VertexShaderFlags flags;
GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &genErrorString);
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_));
vs = new D3D11VertexShader(device_, featureLevel_, VSID, codeBuffer_, vertType, useHWTransform);
vs = new D3D11VertexShader(device_, featureLevel_, VSID, codeBuffer_, useHWTransform);
vsCache_[VSID] = vs;
} else {
vs = vsIter->second;

View File

@ -55,7 +55,7 @@ protected:
class D3D11VertexShader {
public:
D3D11VertexShader(ID3D11Device *device, D3D_FEATURE_LEVEL featureLevel, VShaderID id, const char *code, int vertType, bool useHWTransform);
D3D11VertexShader(ID3D11Device *device, D3D_FEATURE_LEVEL featureLevel, VShaderID id, const char *code, bool useHWTransform);
~D3D11VertexShader();
const std::string &source() const { return source_; }
@ -85,7 +85,7 @@ public:
ShaderManagerD3D11(Draw::DrawContext *draw, ID3D11Device *device, ID3D11DeviceContext *context, D3D_FEATURE_LEVEL featureLevel);
~ShaderManagerD3D11();
void GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode);
void GetShaders(int prim, VertexDecoder *decoder, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode);
void ClearShaders();
void DirtyLastShader() override;

View File

@ -319,8 +319,6 @@ void DrawEngineDX9::Invalidate(InvalidationCallbackFlags flags) {
// The inline wrapper in the header checks for numDrawCalls == 0
void DrawEngineDX9::DoFlush() {
gpuStats.numFlushes++;
bool textureNeedsApply = false;
if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {
textureCache_->SetTexture();
@ -521,7 +519,7 @@ rotateVBO:
ApplyDrawState(prim);
ApplyDrawStateLate();
VSShader *vshader = shaderManager_->ApplyShader(true, useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode, pipelineState_);
VSShader *vshader = shaderManager_->ApplyShader(true, useHWTessellation_, dec_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode, pipelineState_);
IDirect3DVertexDeclaration9 *pHardwareVertexDecl = SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType());
if (pHardwareVertexDecl) {
@ -621,7 +619,7 @@ rotateVBO:
ApplyDrawStateLate();
VSShader *vshader = shaderManager_->ApplyShader(false, false, lastVType_, decOptions_.expandAllWeightsToFloat, true, pipelineState_);
VSShader *vshader = shaderManager_->ApplyShader(false, false, dec_, decOptions_.expandAllWeightsToFloat, true, pipelineState_);
if (result.action == SW_DRAW_PRIMITIVES) {
if (result.setStencil) {
@ -664,6 +662,7 @@ rotateVBO:
decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning;
}
gpuStats.numFlushes++;
gpuStats.numDrawCalls += numDrawCalls;
gpuStats.numVertsSubmitted += vertexCountInDrawCalls_;

View File

@ -155,6 +155,14 @@ void GPU_DX9::BeginFrame() {
shaderManagerDX9_->DirtyShader();
framebufferManager_->BeginFrame();
if (gstate_c.useFlagsChanged) {
// TODO: It'd be better to recompile them in the background, probably?
// This most likely means that saw equal depth changed.
WARN_LOG(G3D, "Shader use flags changed, clearing all shaders");
shaderManagerDX9_->ClearCache(true);
gstate_c.useFlagsChanged = false;
}
}
void GPU_DX9::CopyDisplayToOutput(bool reallyDirty) {

View File

@ -324,7 +324,7 @@ void ShaderManagerDX9::PSUpdateUniforms(u64 dirtyUniforms) {
}
const uint64_t vsUniforms = DIRTY_PROJMATRIX | DIRTY_PROJTHROUGHMATRIX | DIRTY_WORLDMATRIX | DIRTY_VIEWMATRIX | DIRTY_TEXMATRIX |
DIRTY_FOGCOEF | DIRTY_BONE_UNIFORMS | DIRTY_UVSCALEOFFSET | DIRTY_DEPTHRANGE | DIRTY_CULLRANGE |
DIRTY_FOGCOEFENABLE | DIRTY_BONE_UNIFORMS | DIRTY_UVSCALEOFFSET | DIRTY_DEPTHRANGE | DIRTY_CULLRANGE |
DIRTY_AMBIENT | DIRTY_MATAMBIENTALPHA | DIRTY_MATSPECULAR | DIRTY_MATDIFFUSE | DIRTY_MATEMISSIVE | DIRTY_LIGHT0 | DIRTY_LIGHT1 | DIRTY_LIGHT2 | DIRTY_LIGHT3;
void ShaderManagerDX9::VSUpdateUniforms(u64 dirtyUniforms) {
@ -371,21 +371,27 @@ void ShaderManagerDX9::VSUpdateUniforms(u64 dirtyUniforms) {
if (dirtyUniforms & DIRTY_TEXMATRIX) {
VSSetMatrix4x3_3(CONST_VS_TEXMTX, gstate.tgenMatrix);
}
if (dirtyUniforms & DIRTY_FOGCOEF) {
float fogcoef[2] = {
getFloat24(gstate.fog1),
getFloat24(gstate.fog2),
};
// The PSP just ignores infnan here (ignoring IEEE), so take it down to a valid float.
// Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988
if (my_isnanorinf(fogcoef[0])) {
// Not really sure what a sensible value might be, but let's try 64k.
fogcoef[0] = std::signbit(fogcoef[0]) ? -65535.0f : 65535.0f;
if (dirtyUniforms & DIRTY_FOGCOEFENABLE) {
if (gstate.isFogEnabled() && !gstate.isModeThrough()) {
float fogcoef[2] = {
getFloat24(gstate.fog1),
getFloat24(gstate.fog2),
};
// The PSP just ignores infnan here (ignoring IEEE), so take it down to a valid float.
// Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988
if (my_isnanorinf(fogcoef[0])) {
// Not really sure what a sensible value might be, but let's try 64k.
fogcoef[0] = std::signbit(fogcoef[0]) ? -65535.0f : 65535.0f;
}
if (my_isnanorinf(fogcoef[1])) {
fogcoef[1] = std::signbit(fogcoef[1]) ? -65535.0f : 65535.0f;
}
VSSetFloatArray(CONST_VS_FOGCOEF, fogcoef, 2);
} else {
// not very useful values, use as marker for disabled fog.
float fogcoef[2] = { -65536.0f, -65536.0f };
VSSetFloatArray(CONST_VS_FOGCOEF, fogcoef, 2);
}
if (my_isnanorinf(fogcoef[1])) {
fogcoef[1] = std::signbit(fogcoef[1]) ? -65535.0f : 65535.0f;
}
VSSetFloatArray(CONST_VS_FOGCOEF, fogcoef, 2);
}
// TODO: Could even set all bones in one go if they're all dirty.
#ifdef USE_BONE_ARRAY
@ -550,11 +556,11 @@ void ShaderManagerDX9::DirtyLastShader() { // disables vertex arrays
lastPShader_ = nullptr;
}
VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, bool useSkinInDecode, const ComputedPipelineState &pipelineState) {
VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellation, VertexDecoder *decoder, bool weightsAsFloat, bool useSkinInDecode, const ComputedPipelineState &pipelineState) {
VShaderID VSID;
if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {
gstate_c.Clean(DIRTY_VERTEXSHADER_STATE);
ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode);
ComputeVertexShaderID(&VSID, decoder, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode);
} else {
VSID = lastVSID_;
}
@ -604,7 +610,7 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat
}
delete vs;
ComputeVertexShaderID(&VSID, vertType, false, false, weightsAsFloat, useSkinInDecode);
ComputeVertexShaderID(&VSID, decoder, false, false, weightsAsFloat, useSkinInDecode);
// TODO: Look for existing shader with the appropriate ID, use that instead of generating a new one - however, need to make sure
// that that shader ID is not used when computing the linked shader ID below, because then IDs won't match

View File

@ -78,7 +78,7 @@ public:
~ShaderManagerDX9();
void ClearCache(bool deleteThem); // TODO: deleteThem currently not respected
VSShader *ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, bool useSkinInDecode, const ComputedPipelineState &pipelineState);
VSShader *ApplyShader(bool useHWTransform, bool useHWTessellation, VertexDecoder *decoder, bool weightsAsFloat, bool useSkinInDecode, const ComputedPipelineState &pipelineState);
void DirtyShader();
void DirtyLastShader() override;

View File

@ -258,8 +258,6 @@ void DrawEngineGLES::DoFlush() {
PROFILE_THIS_SCOPE("flush");
FrameData &frameData = frameData_[render_->GetCurFrame()];
gpuStats.numFlushes++;
bool textureNeedsApply = false;
if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {
textureCache_->SetTexture();
@ -273,7 +271,7 @@ void DrawEngineGLES::DoFlush() {
GEPrimitiveType prim = prevPrim_;
VShaderID vsid;
Shader *vshader = shaderManager_->ApplyVertexShader(CanUseHardwareTransform(prim), useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode || !CanUseHardwareTransform(prim), &vsid);
Shader *vshader = shaderManager_->ApplyVertexShader(CanUseHardwareTransform(prim), useHWTessellation_, dec_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode || !CanUseHardwareTransform(prim), &vsid);
GLRBuffer *vertexBuffer = nullptr;
GLRBuffer *indexBuffer = nullptr;
@ -321,7 +319,7 @@ void DrawEngineGLES::DoFlush() {
ApplyDrawState(prim);
ApplyDrawStateLate(false, 0);
LinkedShader *program = shaderManager_->ApplyFragmentShader(vsid, vshader, pipelineState_, lastVType_, framebufferManager_->UseBufferedRendering());
LinkedShader *program = shaderManager_->ApplyFragmentShader(vsid, vshader, pipelineState_, framebufferManager_->UseBufferedRendering());
GLRInputLayout *inputLayout = SetupDecFmtForDraw(program, dec_->GetDecVtxFmt());
render_->BindVertexBuffer(inputLayout, vertexBuffer, vertexBufferOffset);
if (useElements) {
@ -421,7 +419,7 @@ void DrawEngineGLES::DoFlush() {
ApplyDrawStateLate(result.setStencil, result.stencilValue);
shaderManager_->ApplyFragmentShader(vsid, vshader, pipelineState_, lastVType_, framebufferManager_->UseBufferedRendering());
shaderManager_->ApplyFragmentShader(vsid, vshader, pipelineState_, framebufferManager_->UseBufferedRendering());
if (result.action == SW_DRAW_PRIMITIVES) {
if (result.drawIndexed) {
@ -465,6 +463,7 @@ void DrawEngineGLES::DoFlush() {
decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning;
}
gpuStats.numFlushes++;
gpuStats.numDrawCalls += numDrawCalls;
gpuStats.numVertsSubmitted += vertexCountInDrawCalls_;

View File

@ -98,7 +98,20 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
File::CreateFullPath(GetSysDirectory(DIRECTORY_APP_CACHE));
shaderCachePath_ = GetSysDirectory(DIRECTORY_APP_CACHE) / (discID + ".glshadercache");
// Actually precompiled by IsReady() since we're single-threaded.
shaderManagerGL_->Load(shaderCachePath_);
File::IOFile f(shaderCachePath_, "rb");
if (f.IsOpen()) {
if (shaderManagerGL_->LoadCacheFlags(f, &drawEngine_)) {
if (drawEngineCommon_->EverUsedExactEqualDepth()) {
sawExactEqualDepth_ = true;
}
gstate_c.SetUseFlags(CheckGPUFeatures());
// We're compiling now, clear if they changed.
gstate_c.useFlagsChanged = false;
if (shaderManagerGL_->LoadCache(f))
NOTICE_LOG(G3D, "Precompiling the shader cache from '%s'", shaderCachePath_.c_str());
}
}
} else {
INFO_LOG(G3D, "Shader cache disabled. Not loading.");
}
@ -125,7 +138,7 @@ GPU_GLES::~GPU_GLES() {
if (shaderCachePath_.Valid() && draw_) {
if (g_Config.bShaderCache) {
shaderManagerGL_->Save(shaderCachePath_);
shaderManagerGL_->SaveCache(shaderCachePath_, &drawEngine_);
} else {
INFO_LOG(G3D, "Shader cache disabled. Not saving.");
}
@ -271,6 +284,14 @@ void GPU_GLES::InitClear() {
void GPU_GLES::BeginHostFrame() {
GPUCommon::BeginHostFrame();
drawEngine_.BeginFrame();
if (gstate_c.useFlagsChanged) {
// TODO: It'd be better to recompile them in the background, probably?
// This most likely means that saw equal depth changed.
WARN_LOG(G3D, "Shader use flags changed, clearing all shaders");
shaderManagerGL_->ClearCache(true);
gstate_c.useFlagsChanged = false;
}
}
void GPU_GLES::EndHostFrame() {
@ -289,7 +310,7 @@ void GPU_GLES::BeginFrame() {
// Save the cache from time to time. TODO: How often? We save on exit, so shouldn't need to do this all that often.
if (shaderCachePath_.Valid() && (gpuStats.numFlips & 4095) == 0) {
shaderManagerGL_->Save(shaderCachePath_);
shaderManagerGL_->SaveCache(shaderCachePath_, &drawEngine_);
}
shaderManagerGL_->DirtyShader();

View File

@ -361,7 +361,7 @@ void LinkedShader::use(const ShaderID &VSID) {
// Note that we no longer track attr masks here - we do it for the input layouts instead.
}
void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBufferedRendering, const ShaderLanguageDesc &shaderLanguage) {
void LinkedShader::UpdateUniforms(const ShaderID &vsid, bool useBufferedRendering, const ShaderLanguageDesc &shaderLanguage) {
u64 dirty = dirtyUniforms & availableUniforms;
dirtyUniforms = 0;
@ -459,21 +459,26 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu
SetVRCompat(VR_COMPAT_FOG_COLOR, gstate.fogcolor);
}
}
if (dirty & DIRTY_FOGCOEF) {
float fogcoef[2] = {
getFloat24(gstate.fog1),
getFloat24(gstate.fog2),
};
// The PSP just ignores infnan here (ignoring IEEE), so take it down to a valid float.
// Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988
if (my_isnanorinf(fogcoef[0])) {
// Not really sure what a sensible value might be, but let's try 64k.
fogcoef[0] = std::signbit(fogcoef[0]) ? -65535.0f : 65535.0f;
if (dirty & DIRTY_FOGCOEFENABLE) {
if (gstate.isFogEnabled() && !gstate.isModeThrough()) {
float fogcoef[2] = {
getFloat24(gstate.fog1),
getFloat24(gstate.fog2),
};
// The PSP just ignores infnan here (ignoring IEEE), so take it down to a valid float.
// Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988
if (my_isnanorinf(fogcoef[0])) {
// Not really sure what a sensible value might be, but let's try 64k.
fogcoef[0] = std::signbit(fogcoef[0]) ? -65535.0f : 65535.0f;
}
if (my_isnanorinf(fogcoef[1])) {
fogcoef[1] = std::signbit(fogcoef[1]) ? -65535.0f : 65535.0f;
}
render_->SetUniformF(&u_fogcoef, 2, fogcoef);
} else {
float fogcoef[2] = { -65536.0f, -65536.0f };
render_->SetUniformF(&u_fogcoef, 2, fogcoef);
}
if (my_isnanorinf(fogcoef[1])) {
fogcoef[1] = std::signbit(fogcoef[1]) ? -65535.0f : 65535.0f;
}
render_->SetUniformF(&u_fogcoef, 2, fogcoef);
}
if (dirty & DIRTY_UVSCALEOFFSET) {
const float invW = 1.0f / (float)gstate_c.curTextureWidth;
@ -755,10 +760,10 @@ Shader *ShaderManagerGLES::CompileVertexShader(VShaderID VSID) {
return new Shader(render_, codeBuffer_, desc, params);
}
Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, bool useSkinInDecode, VShaderID *VSID) {
Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTessellation, VertexDecoder *decoder, bool weightsAsFloat, bool useSkinInDecode, VShaderID *VSID) {
if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {
gstate_c.Clean(DIRTY_VERTEXSHADER_STATE);
ComputeVertexShaderID(VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode);
ComputeVertexShaderID(VSID, decoder, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode);
} else {
*VSID = lastVSID_;
}
@ -789,7 +794,7 @@ Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTess
// Can still work with software transform.
VShaderID vsidTemp;
ComputeVertexShaderID(&vsidTemp, vertType, false, false, weightsAsFloat, true);
ComputeVertexShaderID(&vsidTemp, decoder, false, false, weightsAsFloat, true);
vs = CompileVertexShader(vsidTemp);
}
@ -799,7 +804,7 @@ Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTess
return vs;
}
LinkedShader *ShaderManagerGLES::ApplyFragmentShader(VShaderID VSID, Shader *vs, const ComputedPipelineState &pipelineState, u32 vertType, bool useBufferedRendering) {
LinkedShader *ShaderManagerGLES::ApplyFragmentShader(VShaderID VSID, Shader *vs, const ComputedPipelineState &pipelineState, bool useBufferedRendering) {
uint64_t dirty = gstate_c.GetDirtyUniforms();
if (dirty) {
if (lastShader_)
@ -817,7 +822,7 @@ LinkedShader *ShaderManagerGLES::ApplyFragmentShader(VShaderID VSID, Shader *vs,
}
if (lastVShaderSame_ && FSID == lastFSID_) {
lastShader_->UpdateUniforms(vertType, VSID, useBufferedRendering, draw_->GetShaderLanguageDesc());
lastShader_->UpdateUniforms(VSID, useBufferedRendering, draw_->GetShaderLanguageDesc());
return lastShader_;
}
@ -848,7 +853,6 @@ LinkedShader *ShaderManagerGLES::ApplyFragmentShader(VShaderID VSID, Shader *vs,
shaderSwitchDirtyUniforms_ = 0;
if (ls == nullptr) {
_dbg_assert_(FSID.Bit(FS_BIT_LMODE) == VSID.Bit(VS_BIT_LMODE));
_dbg_assert_(FSID.Bit(FS_BIT_DO_TEXTURE) == VSID.Bit(VS_BIT_DO_TEXTURE));
_dbg_assert_(FSID.Bit(FS_BIT_FLATSHADE) == VSID.Bit(VS_BIT_FLATSHADE));
@ -860,7 +864,7 @@ LinkedShader *ShaderManagerGLES::ApplyFragmentShader(VShaderID VSID, Shader *vs,
} else {
ls->use(VSID);
}
ls->UpdateUniforms(vertType, VSID, useBufferedRendering, draw_->GetShaderLanguageDesc());
ls->UpdateUniforms(VSID, useBufferedRendering, draw_->GetShaderLanguageDesc());
lastShader_ = ls;
return ls;
@ -936,30 +940,48 @@ std::string ShaderManagerGLES::DebugGetShaderString(std::string id, DebugShaderT
// If things like GPU supported features have changed since the last time, we discard the cache
// as sometimes these features might have an effect on the ID bits.
enum class CacheDetectFlags {
EQUAL_DEPTH = 1,
};
#define CACHE_HEADER_MAGIC 0x83277592
#define CACHE_VERSION 17
#define CACHE_VERSION 21
struct CacheHeader {
uint32_t magic;
uint32_t version;
uint32_t useFlags;
uint32_t reserved;
uint32_t detectFlags;
int numVertexShaders;
int numFragmentShaders;
int numLinkedPrograms;
};
void ShaderManagerGLES::Load(const Path &filename) {
File::IOFile f(filename, "rb");
u64 sz = f.GetSize();
if (!f.IsOpen()) {
return;
}
bool ShaderManagerGLES::LoadCacheFlags(File::IOFile &f, DrawEngineGLES *drawEngine) {
CacheHeader header;
if (!f.ReadArray(&header, 1)) {
return;
return false;
}
if (header.magic != CACHE_HEADER_MAGIC || header.version != CACHE_VERSION || header.useFlags != gstate_c.GetUseFlags()) {
return;
if (header.magic != CACHE_HEADER_MAGIC || header.version != CACHE_VERSION) {
return false;
}
if ((header.detectFlags & (uint32_t)CacheDetectFlags::EQUAL_DEPTH) != 0) {
drawEngine->SetEverUsedExactEqualDepth(true);
}
return true;
}
bool ShaderManagerGLES::LoadCache(File::IOFile &f) {
u64 sz = f.GetSize();
f.Seek(0, SEEK_SET);
CacheHeader header;
if (!f.ReadArray(&header, 1)) {
return false;
}
// We don't recheck the version, done in LoadCacheFlags().
if (header.useFlags != gstate_c.GetUseFlags()) {
return false;
}
diskCachePending_.start = time_now_d();
diskCachePending_.Clear();
@ -967,7 +989,7 @@ void ShaderManagerGLES::Load(const Path &filename) {
// Sanity check the file contents
if (header.numFragmentShaders > 1000 || header.numVertexShaders > 1000 || header.numLinkedPrograms > 1000) {
ERROR_LOG(G3D, "Corrupt shader cache file header, aborting.");
return;
return false;
}
// Also make sure the size makes sense, in case there's corruption.
@ -977,37 +999,37 @@ void ShaderManagerGLES::Load(const Path &filename) {
expectedSize += header.numLinkedPrograms * (sizeof(VShaderID) + sizeof(FShaderID));
if (sz != expectedSize) {
ERROR_LOG(G3D, "Shader cache file is wrong size: %lld instead of %lld", sz, expectedSize);
return;
return false;
}
diskCachePending_.vert.resize(header.numVertexShaders);
if (!f.ReadArray(&diskCachePending_.vert[0], header.numVertexShaders)) {
diskCachePending_.vert.clear();
return;
return false;
}
diskCachePending_.frag.resize(header.numFragmentShaders);
if (!f.ReadArray(&diskCachePending_.frag[0], header.numFragmentShaders)) {
diskCachePending_.vert.clear();
diskCachePending_.frag.clear();
return;
return false;
}
for (int i = 0; i < header.numLinkedPrograms; i++) {
VShaderID vsid;
FShaderID fsid;
if (!f.ReadArray(&vsid, 1)) {
return;
return false;
}
if (!f.ReadArray(&fsid, 1)) {
return;
return false;
}
diskCachePending_.link.emplace_back(vsid, fsid);
}
// Actual compilation happens in ContinuePrecompile(), called by GPU_GLES's IsReady.
NOTICE_LOG(G3D, "Precompiling the shader cache from '%s'", filename.c_str());
diskCacheDirty_ = false;
return true;
}
bool ShaderManagerGLES::ContinuePrecompile(float sliceTime) {
@ -1096,7 +1118,7 @@ void ShaderManagerGLES::CancelPrecompile() {
diskCachePending_.Clear();
}
void ShaderManagerGLES::Save(const Path &filename) {
void ShaderManagerGLES::SaveCache(const Path &filename, DrawEngineGLES *drawEngine) {
if (!diskCacheDirty_) {
return;
}
@ -1113,7 +1135,9 @@ void ShaderManagerGLES::Save(const Path &filename) {
CacheHeader header;
header.magic = CACHE_HEADER_MAGIC;
header.version = CACHE_VERSION;
header.reserved = 0;
header.detectFlags = 0;
if (drawEngine->EverUsedExactEqualDepth())
header.detectFlags |= (uint32_t)CacheDetectFlags::EQUAL_DEPTH;
header.useFlags = gstate_c.GetUseFlags();
header.numVertexShaders = GetNumVertexShaders();
header.numFragmentShaders = GetNumFragmentShaders();

View File

@ -27,16 +27,21 @@
#include "GPU/Common/VertexShaderGenerator.h"
#include "GPU/Common/FragmentShaderGenerator.h"
class DrawEngineGLES;
class Shader;
struct ShaderLanguageDesc;
namespace File {
class IOFile;
}
class LinkedShader {
public:
LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, FShaderID FSID, Shader *fs, bool useHWTransform, bool preloading = false);
~LinkedShader();
void use(const ShaderID &VSID);
void UpdateUniforms(u32 vertType, const ShaderID &VSID, bool useBufferedRendering, const ShaderLanguageDesc &shaderLanguage);
void UpdateUniforms(const ShaderID &VSID, bool useBufferedRendering, const ShaderLanguageDesc &shaderLanguage);
GLRenderManager *render_;
Shader *vs_;
@ -161,8 +166,8 @@ public:
// This is the old ApplyShader split into two parts, because of annoying information dependencies.
// If you call ApplyVertexShader, you MUST call ApplyFragmentShader soon afterwards.
Shader *ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, bool useSkinInDecode, VShaderID *VSID);
LinkedShader *ApplyFragmentShader(VShaderID VSID, Shader *vs, const ComputedPipelineState &pipelineState, u32 vertType, bool useBufferedRendering);
Shader *ApplyVertexShader(bool useHWTransform, bool useHWTessellation, VertexDecoder *vertexDecoder, bool weightsAsFloat, bool useSkinInDecode, VShaderID *VSID);
LinkedShader *ApplyFragmentShader(VShaderID VSID, Shader *vs, const ComputedPipelineState &pipelineState, bool useBufferedRendering);
void DeviceLost();
void DeviceRestore(Draw::DrawContext *draw);
@ -177,10 +182,11 @@ public:
std::vector<std::string> DebugGetShaderIDs(DebugShaderType type);
std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType);
void Load(const Path &filename);
bool LoadCacheFlags(File::IOFile &f, DrawEngineGLES *drawEngine);
bool LoadCache(File::IOFile &f);
bool ContinuePrecompile(float sliceTime = 1.0f / 60.0f);
void CancelPrecompile();
void Save(const Path &filename);
void SaveCache(const Path &filename, DrawEngineGLES *drawEngine);
private:
void Clear();

View File

@ -100,7 +100,6 @@ struct GPUStatistics {
msProcessingDisplayLists = 0;
vertexGPUCycles = 0;
otherGPUCycles = 0;
memset(gpuCommandsAtCallLevel, 0, sizeof(gpuCommandsAtCallLevel));
}
// Per frame statistics
@ -131,7 +130,6 @@ struct GPUStatistics {
double msProcessingDisplayLists;
int vertexGPUCycles;
int otherGPUCycles;
int gpuCommandsAtCallLevel[4];
// Flip count. Doesn't really belong here.
int numFlips;

View File

@ -83,13 +83,13 @@ const CommonCommandTableEntry commonCommandTable[] = {
{ GE_CMD_ZBUFWIDTH, FLAG_FLUSHBEFOREONCHANGE },
{ GE_CMD_FOGCOLOR, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FOGCOLOR },
{ GE_CMD_FOG1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FOGCOEF },
{ GE_CMD_FOG2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FOGCOEF },
{ GE_CMD_FOG1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FOGCOEFENABLE },
{ GE_CMD_FOG2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FOGCOEFENABLE },
// These affect the fragment shader so need flushing.
{ GE_CMD_CLEARMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE },
{ GE_CMD_TEXTUREMAPENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE },
{ GE_CMD_FOGENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAGMENTSHADER_STATE },
{ GE_CMD_FOGENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FOGCOEFENABLE },
{ GE_CMD_TEXMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS | DIRTY_FRAGMENTSHADER_STATE },
{ GE_CMD_TEXSHADELS, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
// Raster state for Direct3D 9, uncommon.
@ -113,8 +113,8 @@ const CommonCommandTableEntry commonCommandTable[] = {
{ GE_CMD_LIGHTTYPE3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_LIGHT3 },
{ GE_CMD_MATERIALUPDATE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
// These change both shaders so need flushing.
{ GE_CMD_LIGHTMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE },
// These change vertex shaders (in non uber shader mode) so need flushing.
{ GE_CMD_LIGHTMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
{ GE_CMD_TEXFILTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
{ GE_CMD_TEXWRAP, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS | DIRTY_FRAGMENTSHADER_STATE },
@ -472,9 +472,11 @@ void GPUCommon::UpdateCmdInfo() {
if (gstate_c.Use(GPU_USE_LIGHT_UBERSHADER)) {
cmdInfo_[GE_CMD_MATERIALUPDATE].RemoveDirty(DIRTY_VERTEXSHADER_STATE);
cmdInfo_[GE_CMD_MATERIALUPDATE].AddDirty(DIRTY_LIGHT_CONTROL);
cmdInfo_[GE_CMD_LIGHTMODE].AddDirty(DIRTY_LIGHT_CONTROL);
} else {
cmdInfo_[GE_CMD_MATERIALUPDATE].RemoveDirty(DIRTY_LIGHT_CONTROL);
cmdInfo_[GE_CMD_MATERIALUPDATE].AddDirty(DIRTY_VERTEXSHADER_STATE);
cmdInfo_[GE_CMD_LIGHTMODE].RemoveDirty(DIRTY_LIGHT_CONTROL);
}
}
@ -1300,11 +1302,6 @@ void GPUCommon::UpdatePC(u32 currentPC, u32 newPC) {
cyclesExecuted += 2 * executed;
cycleLastPC = newPC;
if (coreCollectDebugStats) {
gpuStats.otherGPUCycles += 2 * executed;
gpuStats.gpuCommandsAtCallLevel[std::min(currentList->stackptr, 3)] += executed;
}
// Exit the runloop and recalculate things. This happens a lot in some games.
if (currentList)
downcount = currentList->stall == 0 ? 0x0FFFFFFF : (currentList->stall - newPC) / 4;
@ -1399,6 +1396,10 @@ void GPUCommon::ProcessDLQueue() {
currentList = nullptr;
if (coreCollectDebugStats) {
gpuStats.otherGPUCycles += cyclesExecuted;
}
drawCompleteTicks = startingTicks + cyclesExecuted;
busyTicks = std::max(busyTicks, drawCompleteTicks);
__GeTriggerSync(GPU_SYNC_DRAW, 1, drawCompleteTicks);
@ -1751,8 +1752,9 @@ void GPUCommon::Execute_VertexType(u32 op, u32 diff) {
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK)) {
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
// Switching between through and non-through, we need to invalidate a bunch of stuff.
if (diff & GE_VTYPE_THROUGH_MASK)
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE | DIRTY_CULLRANGE);
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE | DIRTY_CULLRANGE | DIRTY_FOGCOEFENABLE);
}
}
@ -1779,7 +1781,7 @@ void GPUCommon::Execute_VertexTypeSkinning(u32 op, u32 diff) {
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
}
if (diff & GE_VTYPE_THROUGH_MASK)
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE | DIRTY_CULLRANGE);
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE | DIRTY_CULLRANGE | DIRTY_FOGCOEFENABLE);
}
void GPUCommon::CheckDepthUsage(VirtualFramebuffer *vfb) {
@ -2769,6 +2771,12 @@ void GPUCommon::FastLoadBoneMatrix(u32 target) {
gstate_c.deferredVertTypeDirty |= uniformsToDirty;
}
gstate.FastLoadBoneMatrix(target);
cyclesExecuted += 2 * 14; // one to reset the counter, 12 to load the matrix, and a return.
if (coreCollectDebugStats) {
gpuStats.otherGPUCycles += 2 * 14;
}
}
struct DisplayList_v1 {
@ -3456,7 +3464,6 @@ size_t GPUCommon::FormatGPUStatsCommon(char *buffer, size_t size) {
"DL processing time: %0.2f ms\n"
"Draw calls: %d, flushes %d, clears %d (cached: %d)\n"
"Num Tracked Vertex Arrays: %d\n"
"Commands per call level: %i %i %i %i\n"
"Vertices: %d cached: %d uncached: %d\n"
"FBOs active: %d (evaluations: %d)\n"
"Textures: %d, dec: %d, invalidated: %d, hashed: %d kB\n"
@ -3469,7 +3476,6 @@ size_t GPUCommon::FormatGPUStatsCommon(char *buffer, size_t size) {
gpuStats.numClears,
gpuStats.numCachedDrawCalls,
gpuStats.numTrackedVertexArrays,
gpuStats.gpuCommandsAtCallLevel[0], gpuStats.gpuCommandsAtCallLevel[1], gpuStats.gpuCommandsAtCallLevel[2], gpuStats.gpuCommandsAtCallLevel[3],
gpuStats.numVertsSubmitted,
gpuStats.numCachedVertsDrawn,
gpuStats.numUncachedVertsDrawn,

View File

@ -580,8 +580,9 @@ struct GPUStateCache {
}
void SetUseFlags(u32 newFlags) {
if (newFlags != useFlags_) {
if (useFlags_ != 0)
useFlagsChanged = true;
useFlags_ = newFlags;
// Recompile shaders and stuff?
}
}
@ -612,6 +613,7 @@ public:
bool bgraTexture;
bool needShaderTexClamp;
bool arrayTexture;
bool useFlagsChanged;
float morphWeights[8];
u32 deferredVertTypeDirty;

View File

@ -562,8 +562,6 @@ void DrawEngineVulkan::DoFlush() {
PROFILE_THIS_SCOPE("Flush");
FrameData &frameData = GetCurFrame();
gpuStats.numFlushes++;
bool tess = gstate_c.submitType == SubmitType::HW_BEZIER || gstate_c.submitType == SubmitType::HW_SPLINE;
bool textureNeedsApply = false;
@ -778,7 +776,7 @@ void DrawEngineVulkan::DoFlush() {
VulkanFragmentShader *fshader = nullptr;
VulkanGeometryShader *gshader = nullptr;
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, true, useHWTessellation_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode);
shaderManager_->GetShaders(prim, dec_, &vshader, &fshader, &gshader, pipelineState_, true, useHWTessellation_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode);
if (!vshader) {
// We're screwed.
return;
@ -912,7 +910,7 @@ void DrawEngineVulkan::DoFlush() {
VulkanFragmentShader *fshader = nullptr;
VulkanGeometryShader *gshader = nullptr;
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, &gshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true);
shaderManager_->GetShaders(prim, dec_, &vshader, &fshader, &gshader, pipelineState_, false, false, decOptions_.expandAllWeightsToFloat, true);
_dbg_assert_msg_(!vshader->UseHWTransform(), "Bad vshader");
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(renderManager, pipelineLayout_, pipelineKey_, &dec_->decFmt, vshader, fshader, gshader, false, 0, framebufferManager_->GetMSAALevel());
if (!pipeline || !pipeline->pipeline) {
@ -981,6 +979,7 @@ void DrawEngineVulkan::DoFlush() {
decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning;
}
gpuStats.numFlushes++;
gpuStats.numDrawCalls += numDrawCalls;
gpuStats.numVertsSubmitted += vertexCountInDrawCalls_;

View File

@ -129,9 +129,20 @@ void GPU_Vulkan::LoadCache(const Path &filename) {
// First compile shaders to SPIR-V, then load the pipeline cache and recreate the pipelines.
// It's when recreating the pipelines that the pipeline cache is useful - in the ideal case,
// it can just memcpy the finished shader binaries out of the pipeline cache file.
bool result = shaderManagerVulkan_->LoadCache(f);
bool result = shaderManagerVulkan_->LoadCacheFlags(f, &drawEngine_);
if (!result) {
WARN_LOG(G3D, "ShaderManagerVulkan failed to load cache.");
WARN_LOG(G3D, "ShaderManagerVulkan failed to load cache header.");
}
if (result) {
// Reload use flags in case LoadCacheFlags() changed them.
if (drawEngineCommon_->EverUsedExactEqualDepth()) {
sawExactEqualDepth_ = true;
}
gstate_c.SetUseFlags(CheckGPUFeatures());
result = shaderManagerVulkan_->LoadCache(f);
if (!result) {
WARN_LOG(G3D, "ShaderManagerVulkan failed to load cache.");
}
}
if (result) {
// WARNING: See comment in LoadPipelineCache if you are tempted to flip the second parameter to true.
@ -163,7 +174,7 @@ void GPU_Vulkan::SaveCache(const Path &filename) {
FILE *f = File::OpenCFile(filename, "wb");
if (!f)
return;
shaderManagerVulkan_->SaveCache(f);
shaderManagerVulkan_->SaveCache(f, &drawEngine_);
// WARNING: See comment in LoadCache if you are tempted to flip the second parameter to true.
pipelineManager_->SavePipelineCache(f, false, shaderManagerVulkan_, draw_);
INFO_LOG(G3D, "Saved Vulkan pipeline cache");
@ -296,6 +307,14 @@ void GPU_Vulkan::BeginHostFrame() {
shaderManagerVulkan_->DirtyShader();
gstate_c.Dirty(DIRTY_ALL);
if (gstate_c.useFlagsChanged) {
// TODO: It'd be better to recompile them in the background, probably?
// This most likely means that saw equal depth changed.
WARN_LOG(G3D, "Shader use flags changed, clearing all shaders");
shaderManagerVulkan_->ClearShaders();
gstate_c.useFlagsChanged = false;
}
if (dumpNextFrame_) {
NOTICE_LOG(G3D, "DUMPING THIS FRAME");
dumpThisFrame_ = true;

View File

@ -295,11 +295,11 @@ uint64_t ShaderManagerVulkan::UpdateUniforms(bool useBufferedRendering) {
return dirty;
}
void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) {
void ShaderManagerVulkan::GetShaders(int prim, VertexDecoder *decoder, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) {
VShaderID VSID;
if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {
gstate_c.Clean(DIRTY_VERTEXSHADER_STATE);
ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode);
ComputeVertexShaderID(&VSID, decoder, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode);
} else {
VSID = lastVSID_;
}
@ -320,12 +320,10 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader
GSID = lastGSID_;
}
_dbg_assert_(FSID.Bit(FS_BIT_LMODE) == VSID.Bit(VS_BIT_LMODE));
_dbg_assert_(FSID.Bit(FS_BIT_DO_TEXTURE) == VSID.Bit(VS_BIT_DO_TEXTURE));
_dbg_assert_(FSID.Bit(FS_BIT_FLATSHADE) == VSID.Bit(VS_BIT_FLATSHADE));
if (GSID.Bit(GS_BIT_ENABLED)) {
_dbg_assert_(GSID.Bit(GS_BIT_LMODE) == VSID.Bit(VS_BIT_LMODE));
_dbg_assert_(GSID.Bit(GS_BIT_DO_TEXTURE) == VSID.Bit(VS_BIT_DO_TEXTURE));
}
@ -350,8 +348,13 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader
bool success = GenerateVertexShader(VSID, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &flags, &genErrorString);
_assert_msg_(success, "VS gen error: %s", genErrorString.c_str());
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_));
vs = new VulkanVertexShader(vulkan, VSID, flags, codeBuffer_, useHWTransform);
vsCache_.Insert(VSID, vs);
std::lock_guard<std::mutex> guard(cacheLock_);
vs = vsCache_.Get(VSID);
if (!vs) {
vs = new VulkanVertexShader(vulkan, VSID, flags, codeBuffer_, useHWTransform);
vsCache_.Insert(VSID, vs);
}
}
VulkanFragmentShader *fs = fsCache_.Get(FSID);
@ -363,8 +366,13 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader
bool success = GenerateFragmentShader(FSID, codeBuffer_, compat_, draw_->GetBugs(), &uniformMask, &flags, &genErrorString);
_assert_msg_(success, "FS gen error: %s", genErrorString.c_str());
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_));
fs = new VulkanFragmentShader(vulkan, FSID, flags, codeBuffer_);
fsCache_.Insert(FSID, fs);
std::lock_guard<std::mutex> guard(cacheLock_);
fs = fsCache_.Get(FSID);
if (!fs) {
fs = new VulkanFragmentShader(vulkan, FSID, flags, codeBuffer_);
fsCache_.Insert(FSID, fs);
}
}
VulkanGeometryShader *gs;
@ -376,8 +384,13 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader
bool success = GenerateGeometryShader(GSID, codeBuffer_, compat_, draw_->GetBugs(), &genErrorString);
_assert_msg_(success, "GS gen error: %s", genErrorString.c_str());
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "GS length error: %d", (int)strlen(codeBuffer_));
gs = new VulkanGeometryShader(vulkan, GSID, codeBuffer_);
gsCache_.Insert(GSID, gs);
std::lock_guard<std::mutex> guard(cacheLock_);
gs = gsCache_.Get(GSID);
if (!gs) {
gs = new VulkanGeometryShader(vulkan, GSID, codeBuffer_);
gsCache_.Insert(GSID, gs);
}
}
} else {
gs = nullptr;
@ -498,21 +511,28 @@ VulkanGeometryShader *ShaderManagerVulkan::GetGeometryShaderFromModule(VkShaderM
// pipelines compiled from SPIR-V matching these shaders, pipeline creation will be practically
// instantaneous.
enum class VulkanCacheDetectFlags {
EQUAL_DEPTH = 1,
};
#define CACHE_HEADER_MAGIC 0xff51f420
#define CACHE_VERSION 32
#define CACHE_VERSION 35
struct VulkanCacheHeader {
uint32_t magic;
uint32_t version;
uint32_t useFlags;
uint32_t reserved;
uint32_t detectFlags;
int numVertexShaders;
int numFragmentShaders;
int numGeometryShaders;
};
bool ShaderManagerVulkan::LoadCache(FILE *f) {
bool ShaderManagerVulkan::LoadCacheFlags(FILE *f, DrawEngineVulkan *drawEngine) {
VulkanCacheHeader header{};
long pos = ftell(f);
bool success = fread(&header, sizeof(header), 1, f) == 1;
// We'll read it again later, this is just to check the flags.
success = success && fseek(f, pos, SEEK_SET) == 0;
if (!success || header.magic != CACHE_HEADER_MAGIC) {
WARN_LOG(G3D, "Shader cache magic mismatch");
return false;
@ -522,10 +542,25 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) {
return false;
}
if ((header.detectFlags & (uint32_t)VulkanCacheDetectFlags::EQUAL_DEPTH) != 0) {
drawEngine->SetEverUsedExactEqualDepth(true);
}
return true;
}
bool ShaderManagerVulkan::LoadCache(FILE *f) {
VulkanCacheHeader header{};
bool success = fread(&header, sizeof(header), 1, f) == 1;
// We don't need to validate magic/version again, done in LoadCacheFlags().
if (header.useFlags != gstate_c.GetUseFlags()) {
// This can simply be a result of sawExactEqualDepth_ having been flipped to true in the previous run.
// Let's just keep going.
WARN_LOG(G3D, "Shader cache useFlags mismatch, %08x, expected %08x", header.useFlags, gstate_c.GetUseFlags());
} else {
// We're compiling shaders now, so they haven't changed anymore.
gstate_c.useFlagsChanged = false;
}
int failCount = 0;
@ -550,6 +585,13 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) {
}
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_));
VulkanVertexShader *vs = new VulkanVertexShader(vulkan, id, flags, codeBuffer_, useHWTransform);
// Remove first, just to be safe (we are loading on a background thread.)
std::lock_guard<std::mutex> guard(cacheLock_);
VulkanVertexShader *old = vsCache_.Get(id);
if (old) {
vsCache_.Remove(id);
delete old;
}
vsCache_.Insert(id, vs);
}
uint32_t vendorID = vulkan->GetPhysicalDeviceProperties().properties.vendorID;
@ -571,6 +613,12 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) {
}
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_));
VulkanFragmentShader *fs = new VulkanFragmentShader(vulkan, id, flags, codeBuffer_);
std::lock_guard<std::mutex> guard(cacheLock_);
VulkanFragmentShader *old = fsCache_.Get(id);
if (old) {
fsCache_.Remove(id);
delete old;
}
fsCache_.Insert(id, fs);
}
@ -589,6 +637,12 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) {
}
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "GS length error: %d", (int)strlen(codeBuffer_));
VulkanGeometryShader *gs = new VulkanGeometryShader(vulkan, id, codeBuffer_);
std::lock_guard<std::mutex> guard(cacheLock_);
VulkanGeometryShader *old = gsCache_.Get(id);
if (old) {
gsCache_.Remove(id);
delete old;
}
gsCache_.Insert(id, gs);
}
@ -596,12 +650,14 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) {
return true;
}
void ShaderManagerVulkan::SaveCache(FILE *f) {
void ShaderManagerVulkan::SaveCache(FILE *f, DrawEngineVulkan *drawEngine) {
VulkanCacheHeader header{};
header.magic = CACHE_HEADER_MAGIC;
header.version = CACHE_VERSION;
header.useFlags = gstate_c.GetUseFlags();
header.reserved = 0;
header.detectFlags = 0;
if (drawEngine->EverUsedExactEqualDepth())
header.detectFlags |= (uint32_t)VulkanCacheDetectFlags::EQUAL_DEPTH;
header.numVertexShaders = (int)vsCache_.size();
header.numFragmentShaders = (int)fsCache_.size();
header.numGeometryShaders = (int)gsCache_.size();

View File

@ -19,6 +19,7 @@
#include <cstdio>
#include <cstdint>
#include <mutex>
#include "Common/Thread/Promise.h"
#include "Common/Data/Collections/Hashmaps.h"
@ -32,6 +33,7 @@
#include "GPU/Common/ShaderUniforms.h"
class VulkanContext;
class DrawEngineVulkan;
class VulkanPushBuffer;
class VulkanFragmentShader {
@ -115,7 +117,7 @@ public:
void DeviceLost();
void DeviceRestore(Draw::DrawContext *draw);
void GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode);
void GetShaders(int prim, VertexDecoder *decoder, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode);
void ClearShaders();
void DirtyShader();
void DirtyLastShader() override;
@ -154,8 +156,9 @@ public:
return dest->PushAligned(&ub_bones, sizeof(ub_bones), uboAlignment_, buf);
}
bool LoadCacheFlags(FILE *f, DrawEngineVulkan *drawEngine);
bool LoadCache(FILE *f);
void SaveCache(FILE *f);
void SaveCache(FILE *f, DrawEngineVulkan *drawEngine);
private:
void Clear();
@ -172,6 +175,7 @@ private:
GSCache gsCache_;
char *codeBuffer_;
std::mutex cacheLock_;
uint64_t uboAlignment_;
// Uniform block scratchpad. These (the relevant ones) are copied to the current pushbuffer at draw time.

View File

@ -1219,11 +1219,12 @@ static void DrawCrashDump(UIContext *ctx) {
if (info.type == ExceptionType::MEMORY) {
snprintf(statbuf, sizeof(statbuf), R"(
Access: %s at %08x
Access: %s at %08x (sz: %d)
PC: %08x
%s)",
MemoryExceptionTypeAsString(info.memory_type),
info.address,
info.accessSize,
info.pc,
info.info.c_str());
ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF);

View File

@ -30,6 +30,7 @@
#include "Common/Net/HTTPClient.h"
#include "Common/Net/Resolve.h"
#include "Common/Net/URL.h"
#include "Common/Thread/ThreadUtil.h"
#include "Common/File/PathBrowser.h"
#include "Common/Data/Format/JSONReader.h"
@ -366,6 +367,7 @@ RemoteISOConnectScreen::RemoteISOConnectScreen() {
scanAborted = false;
scanThread_ = new std::thread([](RemoteISOConnectScreen *thiz) {
SetCurrentThreadName("RemoteISOScan");
thiz->ExecuteScan();
}, this);
}

View File

@ -603,6 +603,7 @@
<ClInclude Include="..\..\ext\cityhash\city.h" />
<ClInclude Include="..\..\ext\cityhash\citycrc.h" />
<ClInclude Include="..\..\ext\disarm.h" />
<ClInclude Include="..\..\ext\riscv-disas.h" />
<ClInclude Include="..\..\ext\gason\gason.h" />
<ClInclude Include="..\..\ext\jpge\jpgd.h" />
<ClInclude Include="..\..\ext\jpge\jpge.h" />
@ -888,6 +889,7 @@
<ClCompile Include="..\..\Core\WaveFile.cpp" />
<ClCompile Include="..\..\ext\cityhash\city.cpp" />
<ClCompile Include="..\..\ext\disarm.cpp" />
<ClCompile Include="..\..\ext\riscv-disas.cpp" />
<ClCompile Include="..\..\ext\gason\gason.cpp" />
<ClCompile Include="..\..\ext\jpge\jpgd.cpp" />
<ClCompile Include="..\..\ext\jpge\jpge.cpp" />

View File

@ -62,6 +62,9 @@
<Filter Include="Ext\disarm">
<UniqueIdentifier>{e0604f48-5522-43e8-ba22-6d08bc2ccacd}</UniqueIdentifier>
</Filter>
<Filter Include="Ext\riscv-disas">
<UniqueIdentifier>{e0604f48-5522-43e8-ba22-6d08bc2ccaee}</UniqueIdentifier>
</Filter>
<Filter Include="MIPS\IR">
<UniqueIdentifier>{9c6552c2-9858-41da-a920-31ea5628d417}</UniqueIdentifier>
</Filter>
@ -608,6 +611,9 @@
<ClCompile Include="..\..\ext\disarm.cpp">
<Filter>Ext\disarm</Filter>
</ClCompile>
<ClCompile Include="..\..\ext\riscv-disas.cpp">
<Filter>Ext\riscv-disas</Filter>
</ClCompile>
<ClCompile Include="..\..\ext\xxhash.c">
<Filter>Ext</Filter>
</ClCompile>
@ -1638,6 +1644,9 @@
<ClInclude Include="..\..\ext\disarm.h">
<Filter>Ext\disarm</Filter>
</ClInclude>
<ClInclude Include="..\..\ext\riscv-disas.h">
<Filter>Ext\riscv-disas</Filter>
</ClInclude>
<ClInclude Include="..\..\ext\xxhash.h">
<Filter>Ext</Filter>
</ClInclude>

View File

@ -205,7 +205,7 @@
<SDLCheck>true</SDLCheck>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;ENABLE_HLSL;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../ext/glslang;../../ext/glslang-build;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -220,7 +220,7 @@
<SDLCheck>true</SDLCheck>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;ENABLE_HLSL;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../ext/glslang;../../ext/glslang-build;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -235,7 +235,7 @@
<SDLCheck>true</SDLCheck>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;ENABLE_HLSL;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../ext/glslang;../../ext/glslang-build;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -250,7 +250,7 @@
<SDLCheck>true</SDLCheck>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;ENABLE_HLSL;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../ext/glslang;../../ext/glslang-build;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -265,7 +265,7 @@
<SDLCheck>true</SDLCheck>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;ENABLE_HLSL;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../ext/glslang;../../ext/glslang-build;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -280,7 +280,7 @@
<SDLCheck>true</SDLCheck>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;ENABLE_HLSL;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../ext/glslang;../../ext/glslang-build;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -295,7 +295,7 @@
<SDLCheck>true</SDLCheck>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;ENABLE_HLSL;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../ext/glslang;../../ext/glslang-build;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -310,7 +310,7 @@
<SDLCheck>true</SDLCheck>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;ENABLE_HLSL;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../ext/glslang;../../ext/glslang-build;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -325,7 +325,7 @@
<SDLCheck>true</SDLCheck>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;ENABLE_HLSL;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../ext/glslang;../../ext/glslang-build;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -340,7 +340,7 @@
<SDLCheck>true</SDLCheck>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;ENABLE_HLSL;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../ext/glslang;../../ext/glslang-build;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -355,7 +355,7 @@
<SDLCheck>true</SDLCheck>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;ENABLE_HLSL;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../ext/glslang;../../ext/glslang-build;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -370,7 +370,7 @@
<SDLCheck>true</SDLCheck>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;ENABLE_HLSL;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../ext/glslang;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../ext/glslang;../../ext/glslang-build;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -379,7 +379,6 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\ext\glslang\glslang\build_info.h" />
<ClInclude Include="..\..\ext\glslang\glslang\HLSL\pch.h" />
<ClInclude Include="..\..\ext\glslang\glslang\MachineIndependent\pch.h" />
<ClInclude Include="..\..\ext\glslang\SPIRV\GLSL.ext.EXT.h" />
@ -397,6 +396,7 @@
<ClInclude Include="..\..\ext\glslang\glslang\Include\revision.h" />
<ClInclude Include="..\..\ext\glslang\glslang\Include\ShHandle.h" />
<ClInclude Include="..\..\ext\glslang\glslang\Include\Types.h" />
<ClInclude Include="..\..\ext\glslang\glslang\Include\SpirvIntrinsics.h" />
<ClInclude Include="..\..\ext\glslang\glslang\MachineIndependent\attribute.h" />
<ClInclude Include="..\..\ext\glslang\glslang\MachineIndependent\glslang_tab.cpp.h" />
<ClInclude Include="..\..\ext\glslang\glslang\MachineIndependent\gl_types.h" />
@ -470,6 +470,7 @@
<ClCompile Include="..\..\ext\glslang\glslang\MachineIndependent\RemoveTree.cpp" />
<ClCompile Include="..\..\ext\glslang\glslang\MachineIndependent\Scan.cpp" />
<ClCompile Include="..\..\ext\glslang\glslang\MachineIndependent\ShaderLang.cpp" />
<ClCompile Include="..\..\ext\glslang\glslang\MachineIndependent\SpirvIntrinsics.cpp" />
<ClCompile Include="..\..\ext\glslang\glslang\MachineIndependent\SymbolTable.cpp" />
<ClCompile Include="..\..\ext\glslang\glslang\MachineIndependent\Versions.cpp" />
<ClCompile Include="..\..\ext\glslang\glslang\OSDependent\Windows\ossource.cpp" />

View File

@ -348,8 +348,5 @@
<ClInclude Include="..\..\ext\glslang\glslang\MachineIndependent\pch.h">
<Filter>glslang</Filter>
</ClInclude>
<ClInclude Include="..\..\ext\glslang\glslang\build_info.h">
<Filter>glslang</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -28,53 +28,43 @@ static constexpr UINT REDRAW_DELAY = 1000 / 60;
static constexpr UINT_PTR IDT_REDRAW_AUTO = 0xC0DE0002;
static constexpr UINT REDRAW_INTERVAL = 1000;
CtrlMemView::CtrlMemView(HWND _wnd)
{
CtrlMemView::CtrlMemView(HWND _wnd) {
wnd=_wnd;
SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)this);
SetWindowLong(wnd, GWL_STYLE, GetWindowLong(wnd,GWL_STYLE) | WS_VSCROLL);
SetScrollRange(wnd, SB_VERT, -1,1,TRUE);
const float fontScale = 1.0f / g_dpi_scale_real_y;
rowHeight = g_Config.iFontHeight * fontScale;
charWidth = g_Config.iFontWidth * fontScale;
offsetPositionY = offsetLine * rowHeight;
charWidth_ = g_Config.iFontWidth * fontScale;
rowHeight_ = g_Config.iFontHeight * fontScale;
offsetPositionY_ = offsetLine * rowHeight_;
font = CreateFont(rowHeight, charWidth, 0, 0,
font = CreateFont(rowHeight_, charWidth_, 0, 0,
FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH,
L"Lucida Console");
underlineFont = CreateFont(rowHeight, charWidth, 0, 0,
underlineFont = CreateFont(rowHeight_, charWidth_, 0, 0,
FW_DONTCARE, FALSE, TRUE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH,
L"Lucida Console");
curAddress = 0;
debugger = 0;
searchQuery.clear();
matchAddress = -1;
searching = false;
hasFocus = false;
windowStart = curAddress;
asciiSelected = false;
windowStart_ = curAddress_;
selectRangeStart_ = curAddress_;
selectRangeEnd_ = curAddress_ + 1;
lastSelectReset_ = curAddress_;
selectedNibble = 0;
rowSize = 16;
addressStart = charWidth;
hexStart = addressStart + 9*charWidth;
asciiStart = hexStart + (rowSize*3+1)*charWidth;
addressStartX_ = charWidth_;
hexStartX_ = addressStartX_ + 9 * charWidth_;
asciiStartX_ = hexStartX_ + (rowSize_ * 3 + 1) * charWidth_;
// set redraw timer
SetTimer(wnd, IDT_REDRAW_AUTO, REDRAW_INTERVAL, nullptr);
}
CtrlMemView::~CtrlMemView()
{
CtrlMemView::~CtrlMemView() {
DeleteObject(font);
DeleteObject(underlineFont);
}
void CtrlMemView::init()
{
void CtrlMemView::init() {
WNDCLASSEX wc;
wc.cbSize = sizeof(wc);
@ -94,19 +84,16 @@ void CtrlMemView::init()
RegisterClassEx(&wc);
}
void CtrlMemView::deinit()
{
void CtrlMemView::deinit() {
//UnregisterClass(szClassName, hInst)
}
LRESULT CALLBACK CtrlMemView::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
LRESULT CALLBACK CtrlMemView::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
CtrlMemView *ccp = CtrlMemView::getFrom(hwnd);
static bool lmbDown=false,rmbDown=false;
switch(msg)
{
switch(msg) {
case WM_NCCREATE:
// Allocate a new CustCtrl structure for this window.
ccp = new CtrlMemView(hwnd);
@ -130,11 +117,10 @@ LRESULT CALLBACK CtrlMemView::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM
ccp->onVScroll(wParam,lParam);
break;
case WM_MOUSEWHEEL:
if (GET_WHEEL_DELTA_WPARAM(wParam) > 0)
{
ccp->scrollWindow(-3);
if (GET_WHEEL_DELTA_WPARAM(wParam) > 0) {
ccp->ScrollWindow(-3, GotoModeFromModifiers(false));
} else if (GET_WHEEL_DELTA_WPARAM(wParam) < 0) {
ccp->scrollWindow(3);
ccp->ScrollWindow(3, GotoModeFromModifiers(false));
}
break;
case WM_ERASEBKGND:
@ -154,11 +140,11 @@ LRESULT CALLBACK CtrlMemView::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM
case WM_RBUTTONUP: rmbDown=false; ccp->onMouseUp(wParam,lParam,2); break;
case WM_SETFOCUS:
SetFocus(hwnd);
ccp->hasFocus=true;
ccp->hasFocus_ = true;
ccp->redraw();
break;
case WM_KILLFOCUS:
ccp->hasFocus=false;
ccp->hasFocus_ = false;
ccp->redraw();
break;
case WM_GETDLGCODE: // we want to process the arrow keys and all characters ourselves
@ -184,8 +170,7 @@ LRESULT CALLBACK CtrlMemView::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM
}
CtrlMemView *CtrlMemView::getFrom(HWND hwnd)
{
CtrlMemView *CtrlMemView::getFrom(HWND hwnd) {
return (CtrlMemView *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
}
@ -197,7 +182,7 @@ void CtrlMemView::onPaint(WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT ps;
HDC actualHdc = BeginPaint(wnd, &ps);
HDC hdc = CreateCompatibleDC(actualHdc);
HBITMAP hBM = CreateCompatibleBitmap(actualHdc, rect.right-rect.left, rect.bottom-rect.top);
HBITMAP hBM = CreateCompatibleBitmap(actualHdc, rect_.right - rect_.left, rect_.bottom - rect_.top);
SelectObject(hdc, hBM);
SetBkMode(hdc,OPAQUE);
@ -212,12 +197,12 @@ void CtrlMemView::onPaint(WPARAM wParam, LPARAM lParam) {
// white background
SelectObject(hdc,standardPen);
SelectObject(hdc,standardBrush);
Rectangle(hdc,0,0,rect.right,rect.bottom);
Rectangle(hdc, 0, 0, rect_.right, rect_.bottom);
if (displayOffsetScale)
if (displayOffsetScale_)
drawOffsetScale(hdc);
std::vector<MemBlockInfo> memRangeInfo = FindMemInfoByFlag(highlightFlags_, windowStart, (visibleRows + 1) * rowSize);
std::vector<MemBlockInfo> memRangeInfo = FindMemInfoByFlag(highlightFlags_, windowStart_, (visibleRows_ + 1) * rowSize_);
COLORREF lastTextCol = 0x000000;
COLORREF lastBGCol = standardBG;
@ -233,29 +218,29 @@ void CtrlMemView::onPaint(WPARAM wParam, LPARAM lParam) {
};
// draw one extra row that may be partially visible
for (int i = 0; i < visibleRows + 1; i++) {
int rowY = rowHeight * i;
for (int i = 0; i < visibleRows_ + 1; i++) {
int rowY = rowHeight_ * i;
// Skip the first X rows to make space for the offsets.
if (displayOffsetScale)
rowY += rowHeight * offsetSpace;
if (displayOffsetScale_)
rowY += rowHeight_ * offsetSpace;
char temp[32];
uint32_t address = windowStart + i * rowSize;
uint32_t address = windowStart_ + i * rowSize_;
sprintf(temp, "%08X", address);
setTextColors(0x600000, standardBG);
TextOutA(hdc, addressStart, rowY, temp, (int)strlen(temp));
TextOutA(hdc, addressStartX_, rowY, temp, (int)strlen(temp));
union {
uint32_t words[4];
uint8_t bytes[16];
} memory;
bool valid = debugger != nullptr && debugger->isAlive() && Memory::IsValidAddress(address);
bool valid = debugger_ != nullptr && debugger_->isAlive() && Memory::IsValidAddress(address);
for (int i = 0; valid && i < 4; ++i) {
memory.words[i] = debugger->readMemory(address + i * 4);
memory.words[i] = debugger_->readMemory(address + i * 4);
}
for (int j = 0; j < rowSize; j++) {
for (int j = 0; j < rowSize_; j++) {
const uint32_t byteAddress = (address + j) & ~0xC0000000;
std::string tag;
bool tagContinues = false;
@ -266,9 +251,9 @@ void CtrlMemView::onPaint(WPARAM wParam, LPARAM lParam) {
}
}
int hexX = hexStart + j * 3 * charWidth;
int hexX = hexStartX_ + j * 3 * charWidth_;
int hexLen = 2;
int asciiX = asciiStart + j * (charWidth + 2);
int asciiX = asciiStartX_ + j * (charWidth_ + 2);
char c;
if (valid) {
@ -288,18 +273,19 @@ void CtrlMemView::onPaint(WPARAM wParam, LPARAM lParam) {
COLORREF asciiTextCol = 0x000000;
int underline = -1;
if (address + j == curAddress && searching == false) {
if (asciiSelected) {
if (address + j >= selectRangeStart_ && address + j < selectRangeEnd_ && !searching_) {
if (asciiSelected_) {
hexBGCol = 0xC0C0C0;
hexTextCol = 0x000000;
asciiBGCol = hasFocus ? 0xFF9933 : 0xC0C0C0;
asciiTextCol = hasFocus ? 0xFFFFFF : 0x000000;
asciiBGCol = hasFocus_ ? 0xFF9933 : 0xC0C0C0;
asciiTextCol = hasFocus_ ? 0xFFFFFF : 0x000000;
} else {
hexBGCol = hasFocus ? 0xFF9933 : 0xC0C0C0;
hexTextCol = hasFocus ? 0xFFFFFF : 0x000000;
hexBGCol = hasFocus_ ? 0xFF9933 : 0xC0C0C0;
hexTextCol = hasFocus_ ? 0xFFFFFF : 0x000000;
asciiBGCol = 0xC0C0C0;
asciiTextCol = 0x000000;
underline = selectedNibble;
if (address + j == curAddress_)
underline = selectedNibble_;
}
if (!tag.empty() && tagContinues) {
continueBGCol = pickTagColor(tag);
@ -316,16 +302,22 @@ void CtrlMemView::onPaint(WPARAM wParam, LPARAM lParam) {
SelectObject(hdc, underline == 0 ? (HGDIOBJ)underlineFont : (HGDIOBJ)font);
TextOutA(hdc, hexX, rowY, &temp[0], 1);
SelectObject(hdc, underline == 0 ? (HGDIOBJ)font : (HGDIOBJ)underlineFont);
TextOutA(hdc, hexX + charWidth, rowY, &temp[1], 1);
TextOutA(hdc, hexX + charWidth_, rowY, &temp[1], 1);
SelectObject(hdc, (HGDIOBJ)font);
// If the tag keeps going, draw the BG too.
if (continueBGCol != standardBG) {
setTextColors(0x000000, continueBGCol);
TextOutA(hdc, hexX + charWidth * 2, rowY, &temp[2], 1);
TextOutA(hdc, hexX + charWidth_ * 2, rowY, &temp[2], 1);
}
} else {
TextOutA(hdc, hexX, rowY, temp, hexLen);
if (continueBGCol != hexBGCol) {
TextOutA(hdc, hexX, rowY, temp, 2);
setTextColors(0x000000, continueBGCol);
TextOutA(hdc, hexX + charWidth_ * 2, rowY, &temp[2], 1);
} else {
TextOutA(hdc, hexX, rowY, temp, hexLen);
}
}
setTextColors(asciiTextCol, asciiBGCol);
@ -339,7 +331,7 @@ void CtrlMemView::onPaint(WPARAM wParam, LPARAM lParam) {
SelectObject(hdc,oldBrush);
// copy bitmap to the actual hdc
BitBlt(actualHdc,0,0,rect.right,rect.bottom,hdc,0,0,SRCCOPY);
BitBlt(actualHdc, 0, 0, rect_.right, rect_.bottom, hdc, 0, 0, SRCCOPY);
DeleteObject(hBM);
DeleteDC(hdc);
@ -349,37 +341,33 @@ void CtrlMemView::onPaint(WPARAM wParam, LPARAM lParam) {
EndPaint(wnd, &ps);
}
void CtrlMemView::onVScroll(WPARAM wParam, LPARAM lParam)
{
switch (wParam & 0xFFFF)
{
void CtrlMemView::onVScroll(WPARAM wParam, LPARAM lParam) {
switch (wParam & 0xFFFF) {
case SB_LINEDOWN:
scrollWindow(1);
ScrollWindow(1, GotoModeFromModifiers(false));
break;
case SB_LINEUP:
scrollWindow(-1);
ScrollWindow(-1, GotoModeFromModifiers(false));
break;
case SB_PAGEDOWN:
scrollWindow(visibleRows);
ScrollWindow(visibleRows_, GotoModeFromModifiers(false));
break;
case SB_PAGEUP:
scrollWindow(-visibleRows);
ScrollWindow(-visibleRows_, GotoModeFromModifiers(false));
break;
default:
return;
}
}
void CtrlMemView::onKeyDown(WPARAM wParam, LPARAM lParam)
{
if (KeyDownAsync(VK_CONTROL))
{
switch (tolower(wParam & 0xFFFF))
{
void CtrlMemView::onKeyDown(WPARAM wParam, LPARAM lParam) {
if (KeyDownAsync(VK_CONTROL)) {
switch (tolower(wParam & 0xFFFF)) {
case 'g':
{
u32 addr;
if (executeExpressionWindow(wnd,debugger,addr) == false) return;
if (executeExpressionWindow(wnd, debugger_, addr) == false)
return;
gotoAddr(addr);
return;
}
@ -394,25 +382,24 @@ void CtrlMemView::onKeyDown(WPARAM wParam, LPARAM lParam)
}
}
switch (wParam & 0xFFFF)
{
switch (wParam & 0xFFFF) {
case VK_DOWN:
scrollCursor(rowSize);
ScrollCursor(rowSize_, GotoModeFromModifiers(false));
break;
case VK_UP:
scrollCursor(-rowSize);
ScrollCursor(-rowSize_, GotoModeFromModifiers(false));
break;
case VK_LEFT:
scrollCursor(-1);
ScrollCursor(-1, GotoModeFromModifiers(false));
break;
case VK_RIGHT:
scrollCursor(1);
ScrollCursor(1, GotoModeFromModifiers(false));
break;
case VK_NEXT:
scrollWindow(visibleRows);
ScrollWindow(visibleRows_, GotoModeFromModifiers(false));
break;
case VK_PRIOR:
scrollWindow(-visibleRows);
ScrollWindow(-visibleRows_, GotoModeFromModifiers(false));
break;
case VK_TAB:
SendMessage(GetParent(wnd),WM_DEB_TABPRESSED,0,0);
@ -422,28 +409,26 @@ void CtrlMemView::onKeyDown(WPARAM wParam, LPARAM lParam)
}
}
void CtrlMemView::onChar(WPARAM wParam, LPARAM lParam)
{
void CtrlMemView::onChar(WPARAM wParam, LPARAM lParam) {
auto memLock = Memory::Lock();
if (!PSP_IsInited())
return;
if (KeyDownAsync(VK_CONTROL) || wParam == VK_TAB) return;
if (KeyDownAsync(VK_CONTROL) || wParam == VK_TAB)
return;
if (!Memory::IsValidAddress(curAddress))
{
scrollCursor(1);
if (!Memory::IsValidAddress(curAddress_)) {
ScrollCursor(1, GotoMode::RESET);
return;
}
bool active = Core_IsActive();
if (active) Core_EnableStepping(true, "memory.access", curAddress);
if (active)
Core_EnableStepping(true, "memory.access", curAddress_);
if (asciiSelected)
{
u8 newValue = wParam;
Memory::WriteUnchecked_U8(newValue,curAddress);
scrollCursor(1);
if (asciiSelected_) {
Memory::WriteUnchecked_U8((u8)wParam, curAddress_);
ScrollCursor(1, GotoMode::RESET);
} else {
wParam = tolower(wParam);
int inputValue = -1;
@ -451,29 +436,29 @@ void CtrlMemView::onChar(WPARAM wParam, LPARAM lParam)
if (wParam >= '0' && wParam <= '9') inputValue = wParam - '0';
if (wParam >= 'a' && wParam <= 'f') inputValue = wParam -'a' + 10;
if (inputValue >= 0)
{
int shiftAmount = (1-selectedNibble)*4;
if (inputValue >= 0) {
int shiftAmount = (1 - selectedNibble_) * 4;
u8 oldValue = Memory::ReadUnchecked_U8(curAddress);
u8 oldValue = Memory::ReadUnchecked_U8(curAddress_);
oldValue &= ~(0xF << shiftAmount);
u8 newValue = oldValue | (inputValue << shiftAmount);
Memory::WriteUnchecked_U8(newValue,curAddress);
scrollCursor(1);
Memory::WriteUnchecked_U8(newValue, curAddress_);
ScrollCursor(1, GotoMode::RESET);
}
}
Reporting::NotifyDebugger();
if (active) Core_EnableStepping(false);
if (active)
Core_EnableStepping(false);
}
void CtrlMemView::redraw()
{
GetClientRect(wnd, &rect);
visibleRows = (rect.bottom/rowHeight);
void CtrlMemView::redraw() {
GetClientRect(wnd, &rect_);
visibleRows_ = rect_.bottom / rowHeight_;
if (displayOffsetScale) {
visibleRows -= offsetSpace; // visibleRows is calculated based on the size of the control, but X rows have already been used for the offsets and are no longer usable
if (displayOffsetScale_) {
// visibleRows_ is calculated based on the size of the control, but X rows have already been used for the offsets and are no longer usable
visibleRows_ -= offsetSpace;
}
if (!redrawScheduled_) {
@ -482,30 +467,40 @@ void CtrlMemView::redraw()
}
}
void CtrlMemView::onMouseDown(WPARAM wParam, LPARAM lParam, int button)
{
CtrlMemView::GotoMode CtrlMemView::GotoModeFromModifiers(bool isRightClick) {
GotoMode mode = GotoMode::RESET;
if (isRightClick) {
mode = GotoMode::RESET_IF_OUTSIDE;
} else if (KeyDownAsync(VK_SHIFT)) {
if (KeyDownAsync(VK_CONTROL))
mode = GotoMode::EXTEND;
else
mode = GotoMode::FROM_CUR;
}
return mode;
}
void CtrlMemView::onMouseDown(WPARAM wParam, LPARAM lParam, int button) {
int x = LOWORD(lParam);
int y = HIWORD(lParam);
gotoPoint(x,y);
GotoPoint(x, y, GotoModeFromModifiers(button == 2));
}
void CtrlMemView::onMouseUp(WPARAM wParam, LPARAM lParam, int button)
{
if (button==2)
{
bool enable16 = !asciiSelected && (curAddress % 2) == 0;
bool enable32 = !asciiSelected && (curAddress % 4) == 0;
void CtrlMemView::onMouseUp(WPARAM wParam, LPARAM lParam, int button) {
if (button == 2) {
int32_t selectedSize = selectRangeEnd_ - selectRangeStart_;
bool enable16 = !asciiSelected_ && (selectedSize == 1 || (selectedSize & 1) == 0);
bool enable32 = !asciiSelected_ && (selectedSize == 1 || (selectedSize & 3) == 0);
HMENU menu = GetContextMenu(ContextMenuID::MEMVIEW);
EnableMenuItem(menu,ID_MEMVIEW_COPYVALUE_16,enable16 ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(menu,ID_MEMVIEW_COPYVALUE_32,enable32 ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(menu, ID_MEMVIEW_COPYVALUE_16, enable16 ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(menu, ID_MEMVIEW_COPYVALUE_32, enable32 ? MF_ENABLED : MF_GRAYED);
switch (TriggerContextMenu(ContextMenuID::MEMVIEW, wnd, ContextPoint::FromEvent(lParam)))
{
switch (TriggerContextMenu(ContextMenuID::MEMVIEW, wnd, ContextPoint::FromEvent(lParam))) {
case ID_MEMVIEW_DUMP:
{
DumpMemoryWindow dump(wnd, debugger);
DumpMemoryWindow dump(wnd, debugger_);
dump.exec();
break;
}
@ -513,45 +508,79 @@ void CtrlMemView::onMouseUp(WPARAM wParam, LPARAM lParam, int button)
case ID_MEMVIEW_COPYVALUE_8:
{
auto memLock = Memory::Lock();
char temp[24];
size_t tempSize = 3 * selectedSize + 1;
char *temp = new char[tempSize];
memset(temp, 0, tempSize);
// it's admittedly not really useful like this
if (asciiSelected)
{
unsigned char c = Memory::IsValidAddress(curAddress) ? Memory::Read_U8(curAddress) : '.';
if (c < 32|| c >= 128) c = '.';
sprintf(temp,"%c",c);
if (asciiSelected_) {
for (uint32_t p = selectRangeStart_; p != selectRangeEnd_; ++p) {
uint8_t c = Memory::IsValidAddress(p) ? Memory::ReadUnchecked_U8(p) : '.';
if (c < 32 || c >= 128)
c = '.';
temp[p - selectRangeStart_] = c;
}
} else {
sprintf(temp,"%02X",Memory::IsValidAddress(curAddress) ? Memory::Read_U8(curAddress) : 0xFF);
char *pos = temp;
for (uint32_t p = selectRangeStart_; p != selectRangeEnd_; ++p) {
uint8_t c = Memory::IsValidAddress(p) ? Memory::ReadUnchecked_U8(p) : 0xFF;
pos += snprintf(pos, tempSize - (pos - temp + 1), "%02X ", c);
}
// Clear the last space.
if (pos > temp)
*(pos - 1) = '\0';
}
W32Util::CopyTextToClipboard(wnd,temp);
W32Util::CopyTextToClipboard(wnd, temp);
delete[] temp;
}
break;
case ID_MEMVIEW_COPYVALUE_16:
{
auto memLock = Memory::Lock();
char temp[24];
size_t tempSize = 5 * ((selectedSize + 1) / 2) + 1;
char *temp = new char[tempSize];
memset(temp, 0, tempSize);
sprintf(temp,"%04X",Memory::IsValidAddress(curAddress) ? Memory::Read_U16(curAddress) : 0xFFFF);
W32Util::CopyTextToClipboard(wnd,temp);
char *pos = temp;
for (uint32_t p = selectRangeStart_; p < selectRangeEnd_; p += 2) {
uint16_t c = Memory::IsValidRange(p, 2) ? Memory::ReadUnchecked_U16(p) : 0xFFFF;
pos += snprintf(pos, tempSize - (pos - temp + 1), "%04X ", c);
}
// Clear the last space.
if (pos > temp)
*(pos - 1) = '\0';
W32Util::CopyTextToClipboard(wnd, temp);
delete[] temp;
}
break;
case ID_MEMVIEW_COPYVALUE_32:
{
auto memLock = Memory::Lock();
char temp[24];
size_t tempSize = 9 * ((selectedSize + 3) / 4) + 1;
char *temp = new char[tempSize];
memset(temp, 0, tempSize);
sprintf(temp,"%08X",Memory::IsValidAddress(curAddress) ? Memory::Read_U32(curAddress) : 0xFFFFFFFF);
W32Util::CopyTextToClipboard(wnd,temp);
char *pos = temp;
for (uint32_t p = selectRangeStart_; p < selectRangeEnd_; p += 4) {
uint32_t c = Memory::IsValidRange(p, 4) ? Memory::ReadUnchecked_U32(p) : 0xFFFFFFFF;
pos += snprintf(pos, tempSize - (pos - temp + 1), "%08X ", c);
}
// Clear the last space.
if (pos > temp)
*(pos - 1) = '\0';
W32Util::CopyTextToClipboard(wnd, temp);
delete[] temp;
}
break;
case ID_MEMVIEW_EXTENTBEGIN:
{
std::vector<MemBlockInfo> memRangeInfo = FindMemInfoByFlag(highlightFlags_, curAddress, 1);
uint32_t addr = curAddress;
std::vector<MemBlockInfo> memRangeInfo = FindMemInfoByFlag(highlightFlags_, curAddress_, 1);
uint32_t addr = curAddress_;
for (MemBlockInfo info : memRangeInfo) {
addr = info.start;
}
@ -561,8 +590,8 @@ void CtrlMemView::onMouseUp(WPARAM wParam, LPARAM lParam, int button)
case ID_MEMVIEW_EXTENTEND:
{
std::vector<MemBlockInfo> memRangeInfo = FindMemInfoByFlag(highlightFlags_, curAddress, 1);
uint32_t addr = curAddress;
std::vector<MemBlockInfo> memRangeInfo = FindMemInfoByFlag(highlightFlags_, curAddress_, 1);
uint32_t addr = curAddress_;
for (MemBlockInfo info : memRangeInfo) {
addr = info.start + info.size - 1;
}
@ -573,14 +602,14 @@ void CtrlMemView::onMouseUp(WPARAM wParam, LPARAM lParam, int button)
case ID_MEMVIEW_COPYADDRESS:
{
char temp[24];
sprintf(temp,"0x%08X",curAddress);
W32Util::CopyTextToClipboard(wnd,temp);
sprintf(temp, "0x%08X", curAddress_);
W32Util::CopyTextToClipboard(wnd, temp);
}
break;
case ID_MEMVIEW_GOTOINDISASM:
if (disasmWindow) {
disasmWindow->Goto(curAddress);
disasmWindow->Goto(curAddress_);
disasmWindow->Show(true);
}
break;
@ -591,128 +620,168 @@ void CtrlMemView::onMouseUp(WPARAM wParam, LPARAM lParam, int button)
int x = LOWORD(lParam);
int y = HIWORD(lParam);
ReleaseCapture();
gotoPoint(x,y);
GotoPoint(x, y, GotoModeFromModifiers(button == 2));
}
void CtrlMemView::onMouseMove(WPARAM wParam, LPARAM lParam, int button)
{
void CtrlMemView::onMouseMove(WPARAM wParam, LPARAM lParam, int button) {
int x = LOWORD(lParam);
int y = HIWORD(lParam);
}
if (button & 1) {
GotoPoint(x, y, GotoModeFromModifiers(button == 2));
}
}
void CtrlMemView::updateStatusBarText() {
std::vector<MemBlockInfo> memRangeInfo = FindMemInfoByFlag(highlightFlags_, curAddress, 1);
std::vector<MemBlockInfo> memRangeInfo = FindMemInfoByFlag(highlightFlags_, curAddress_, 1);
char text[512];
snprintf(text, sizeof(text), "%08X", curAddress);
snprintf(text, sizeof(text), "%08X", curAddress_);
// There should only be one.
for (MemBlockInfo info : memRangeInfo) {
snprintf(text, sizeof(text), "%08X - %s %08X-%08X (at PC %08X / %lld ticks)", curAddress, info.tag.c_str(), info.start, info.start + info.size, info.pc, info.ticks);
snprintf(text, sizeof(text), "%08X - %s %08X-%08X (at PC %08X / %lld ticks)", curAddress_, info.tag.c_str(), info.start, info.start + info.size, info.pc, info.ticks);
}
SendMessage(GetParent(wnd), WM_DEB_SETSTATUSBARTEXT, 0, (LPARAM)text);
}
void CtrlMemView::gotoPoint(int x, int y)
{
int line = y/rowHeight;
int lineAddress = windowStart+line*rowSize;
void CtrlMemView::UpdateSelectRange(uint32_t target, GotoMode mode) {
if (mode == GotoMode::FROM_CUR && lastSelectReset_ == 0) {
lastSelectReset_ = curAddress_;
}
if (displayOffsetScale)
{
if (line < offsetSpace) // ignore clicks on the offset space
{
switch (mode) {
case GotoMode::RESET:
selectRangeStart_ = target;
selectRangeEnd_ = target + 1;
lastSelectReset_ = target;
break;
case GotoMode::RESET_IF_OUTSIDE:
if (target < selectRangeStart_ || target >= selectRangeEnd_) {
selectRangeStart_ = target;
selectRangeEnd_ = target + 1;
lastSelectReset_ = target;
}
break;
case GotoMode::FROM_CUR:
selectRangeStart_ = lastSelectReset_ > target ? target : lastSelectReset_;
selectRangeEnd_ = selectRangeStart_ == lastSelectReset_ ? target + 1 : lastSelectReset_ + 1;
break;
case GotoMode::EXTEND:
if (target < selectRangeStart_)
selectRangeStart_ = target;
if (target > selectRangeEnd_)
selectRangeEnd_ = target;
break;
}
curAddress_ = target;
}
void CtrlMemView::GotoPoint(int x, int y, GotoMode mode) {
int line = y / rowHeight_;
int lineAddress = windowStart_ + line * rowSize_;
if (displayOffsetScale_) {
// ignore clicks on the offset space
if (line < offsetSpace) {
updateStatusBarText();
redraw();
return;
}
lineAddress -= (rowSize * offsetSpace); // since each row has been written X rows down from where the window expected it to be written the target of the clicks must be adjusted
// since each row has been written X rows down from where the window expected it to be written the target of the clicks must be adjusted
lineAddress -= rowSize_ * offsetSpace;
}
if (x >= asciiStart)
{
int col = (x-asciiStart) / (charWidth+2);
if (col >= rowSize) return;
uint32_t target = curAddress_;
uint32_t targetNibble = selectedNibble_;
bool targetAscii = asciiSelected_;
if (x >= asciiStartX_) {
int col = (x - asciiStartX_) / (charWidth_ + 2);
if (col >= rowSize_)
return;
asciiSelected = true;
curAddress = lineAddress+col;
selectedNibble = 0;
updateStatusBarText();
redraw();
} else if (x >= hexStart)
{
int col = (x-hexStart) / charWidth;
if ((col/3) >= rowSize) return;
targetAscii = true;
target = lineAddress + col;
targetNibble = 0;
} else if (x >= hexStartX_) {
int col = (x - hexStartX_) / charWidth_;
if ((col/3) >= rowSize_)
return;
switch (col % 3)
{
case 0: selectedNibble = 0; break;
case 1: selectedNibble = 1; break;
switch (col % 3) {
case 0: targetNibble = 0; break;
case 1: targetNibble = 1; break;
case 2: return; // don't change position when clicking on the space
}
asciiSelected = false;
curAddress = lineAddress+col/3;
targetAscii = false;
target = lineAddress + col / 3;
}
if (target != curAddress_ || targetNibble != selectedNibble_ || targetAscii != asciiSelected_) {
selectedNibble_ = targetNibble;
asciiSelected_ = targetAscii;
UpdateSelectRange(target, mode);
updateStatusBarText();
redraw();
}
}
void CtrlMemView::gotoAddr(unsigned int addr)
{
int lines=(rect.bottom/rowHeight);
u32 windowEnd = windowStart+lines*rowSize;
void CtrlMemView::gotoAddr(unsigned int addr) {
int lines = rect_.bottom / rowHeight_;
u32 windowEnd = windowStart_ + lines * rowSize_;
curAddress = addr;
selectedNibble = 0;
curAddress_ = addr;
lastSelectReset_ = curAddress_;
selectRangeStart_ = curAddress_;
selectRangeEnd_ = curAddress_ + 1;
selectedNibble_ = 0;
if (curAddress < windowStart || curAddress >= windowEnd)
{
windowStart = curAddress & ~15;
if (curAddress_ < windowStart_ || curAddress_ >= windowEnd) {
windowStart_ = curAddress_ & ~15;
}
updateStatusBarText();
redraw();
}
void CtrlMemView::scrollWindow(int lines)
{
windowStart += lines*rowSize;
curAddress += lines*rowSize;
void CtrlMemView::ScrollWindow(int lines, GotoMode mode) {
windowStart_ += lines * rowSize_;
UpdateSelectRange(curAddress_ + lines * rowSize_, mode);
updateStatusBarText();
redraw();
}
void CtrlMemView::scrollCursor(int bytes)
{
if (!asciiSelected && bytes == 1)
{
if (selectedNibble == 0)
{
selectedNibble = 1;
void CtrlMemView::ScrollCursor(int bytes, GotoMode mode) {
if (!asciiSelected_ && bytes == 1) {
if (selectedNibble_ == 0) {
selectedNibble_ = 1;
bytes = 0;
} else {
selectedNibble = 0;
selectedNibble_ = 0;
}
} else if (!asciiSelected && bytes == -1)
{
if (selectedNibble == 0)
{
selectedNibble = 1;
} else if (!asciiSelected_ && bytes == -1) {
if (selectedNibble_ == 0) {
selectedNibble_ = 1;
} else {
selectedNibble = 0;
selectedNibble_ = 0;
bytes = 0;
}
}
curAddress += bytes;
UpdateSelectRange(curAddress_ + bytes, mode);
u32 windowEnd = windowStart+visibleRows*rowSize;
if (curAddress < windowStart)
{
windowStart = curAddress & ~15;
} else if (curAddress >= windowEnd)
{
windowStart = (curAddress-(visibleRows-1)*rowSize) & ~15;
u32 windowEnd = windowStart_ + visibleRows_ * rowSize_;
if (curAddress_ < windowStart_) {
windowStart_ = curAddress_ & ~15;
} else if (curAddress_ >= windowEnd) {
windowStart_ = (curAddress_ - (visibleRows_ - 1) * rowSize_) & ~15;
}
updateStatusBarText();
@ -792,8 +861,7 @@ std::vector<u32> CtrlMemView::searchString(const std::string &searchQuery) {
return searchResAddrs;
};
void CtrlMemView::search(bool continueSearch)
{
void CtrlMemView::search(bool continueSearch) {
auto memLock = Memory::Lock();
if (!PSP_IsInited())
return;
@ -801,22 +869,19 @@ void CtrlMemView::search(bool continueSearch)
u32 searchAddress = 0;
u32 segmentStart = 0;
u32 segmentEnd = 0;
const u8* dataPointer = 0;
if (continueSearch == false || searchQuery.empty())
{
if (InputBox_GetString(GetModuleHandle(NULL), wnd, L"Search for", searchQuery, searchQuery) == false)
{
if (continueSearch == false || searchQuery_.empty()) {
if (InputBox_GetString(GetModuleHandle(NULL), wnd, L"Search for", searchQuery_, searchQuery_) == false) {
SetFocus(wnd);
return;
}
SetFocus(wnd);
searchAddress = curAddress+1;
searchAddress = curAddress_ + 1;
} else {
searchAddress = matchAddress+1;
searchAddress = matchAddress_ + 1;
}
std::vector<u8> searchData;
if (!ParseSearchString(searchQuery, !asciiSelected, searchData)) {
if (!ParseSearchString(searchQuery_, !asciiSelected_, searchData)) {
MessageBox(wnd, L"Invalid search text.", L"Error", MB_OK);
return;
}
@ -828,18 +893,22 @@ void CtrlMemView::search(bool continueSearch)
memoryAreas.emplace_back(PSP_GetKernelMemoryBase(), PSP_GetUserMemoryEnd());
memoryAreas.emplace_back(PSP_GetScratchpadMemoryBase(), PSP_GetScratchpadMemoryEnd());
searching = true;
searching_ = true;
redraw(); // so the cursor is disabled
for (size_t i = 0; i < memoryAreas.size(); i++) {
segmentStart = memoryAreas[i].first;
segmentEnd = memoryAreas[i].second;
dataPointer = Memory::GetPointer(segmentStart);
if (dataPointer == NULL) continue; // better safe than sorry, I guess
// better safe than sorry, I guess
if (Memory::IsValidAddress(segmentStart))
continue;
const u8 *dataPointer = Memory::GetPointerUnchecked(segmentStart);
if (searchAddress < segmentStart) searchAddress = segmentStart;
if (searchAddress >= segmentEnd) continue;
if (searchAddress < segmentStart)
searchAddress = segmentStart;
if (searchAddress >= segmentEnd)
continue;
int index = searchAddress-segmentStart;
int endIndex = segmentEnd-segmentStart - (int)searchData.size();
@ -847,48 +916,46 @@ void CtrlMemView::search(bool continueSearch)
while (index < endIndex) {
// cancel search
if ((index % 256) == 0 && KeyDownAsync(VK_ESCAPE)) {
searching = false;
searching_ = false;
return;
}
if (memcmp(&dataPointer[index], searchData.data(), searchData.size()) == 0) {
matchAddress = index+segmentStart;
searching = false;
gotoAddr(matchAddress);
matchAddress_ = index + segmentStart;
searching_ = false;
gotoAddr(matchAddress_);
return;
}
index++;
}
}
MessageBox(wnd,L"Not found",L"Search",MB_OK);
searching = false;
MessageBox(wnd, L"Not found", L"Search", MB_OK);
searching_ = false;
redraw();
}
void CtrlMemView::drawOffsetScale(HDC hdc)
{
int currentX = addressStart;
void CtrlMemView::drawOffsetScale(HDC hdc) {
int currentX = addressStartX_;
SetTextColor(hdc, 0x600000);
TextOutA(hdc, currentX, offsetPositionY, "Offset", 6);
TextOutA(hdc, currentX, offsetPositionY_, "Offset", 6);
currentX = addressStart + ((8 + 1)*charWidth); // the start offset, the size of the hex addresses and one space
// the start offset, the size of the hex addresses and one space
currentX = addressStartX_ + ((8 + 1) * charWidth_);
char temp[64];
for (int i = 0; i < 16; i++)
{
for (int i = 0; i < 16; i++) {
sprintf(temp, "%02X", i);
TextOutA(hdc, currentX, offsetPositionY, temp, 2);
currentX += 3 * charWidth; // hex and space
TextOutA(hdc, currentX, offsetPositionY_, temp, 2);
currentX += 3 * charWidth_; // hex and space
}
}
void CtrlMemView::toggleOffsetScale(CommonToggles toggle)
{
void CtrlMemView::toggleOffsetScale(CommonToggles toggle) {
if (toggle == On)
displayOffsetScale = true;
displayOffsetScale_ = true;
else if (toggle == Off)
displayOffsetScale = false;
displayOffsetScale_ = false;
updateStatusBarText();
redraw();

View File

@ -34,58 +34,19 @@ enum CommonToggles {
class CtrlMemView
{
HWND wnd;
HFONT font;
HFONT underlineFont;
RECT rect;
unsigned int curAddress;
unsigned int windowStart;
int rowHeight;
int rowSize;
int offsetPositionY;
int addressStart;
int charWidth;
int hexStart;
int asciiStart;
bool asciiSelected;
int selectedNibble;
bool displayOffsetScale = false;
int visibleRows;
std::string searchQuery;
int matchAddress;
bool searching;
bool hasFocus;
static wchar_t szClassName[];
DebugInterface *debugger;
MemBlockFlags highlightFlags_ = MemBlockFlags::ALLOC;
void updateStatusBarText();
void search(bool continueSearch);
uint32_t pickTagColor(const std::string &tag);
public:
CtrlMemView(HWND _wnd);
~CtrlMemView();
static void init();
static void deinit();
static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
static CtrlMemView * getFrom(HWND wnd);
static CtrlMemView *getFrom(HWND wnd);
void setDebugger(DebugInterface *deb)
{
debugger=deb;
void setDebugger(DebugInterface *deb) {
debugger_ = deb;
}
DebugInterface *getDebugger()
{
return debugger;
DebugInterface *getDebugger() {
return debugger_;
}
std::vector<u32> searchString(const std::string &searchQuery);
void onPaint(WPARAM wParam, LPARAM lParam);
@ -96,19 +57,82 @@ public:
void onMouseUp(WPARAM wParam, LPARAM lParam, int button);
void onMouseMove(WPARAM wParam, LPARAM lParam, int button);
void redraw();
void gotoPoint(int x, int y);
void gotoAddr(unsigned int addr);
void scrollWindow(int lines);
void scrollCursor(int bytes);
void drawOffsetScale(HDC hdc);
void toggleOffsetScale(CommonToggles toggle);
void toggleStringSearch(CommonToggles toggle);
void setHighlightType(MemBlockFlags flags);
private:
bool ParseSearchString(const std::string &query, bool asHex, std::vector<uint8_t> &data);
void updateStatusBarText();
void search(bool continueSearch);
uint32_t pickTagColor(const std::string &tag);
enum class GotoMode {
RESET,
RESET_IF_OUTSIDE,
FROM_CUR,
EXTEND,
};
static GotoMode GotoModeFromModifiers(bool isRightClick);
void UpdateSelectRange(uint32_t target, GotoMode mode);
void GotoPoint(int x, int y, GotoMode mode);
void ScrollWindow(int lines, GotoMode mdoe);
void ScrollCursor(int bytes, GotoMode mdoe);
static wchar_t szClassName[];
DebugInterface *debugger_ = nullptr;
HWND wnd;
HFONT font;
HFONT underlineFont;
bool redrawScheduled_ = false;
// Whether to draw things using focused styles.
bool hasFocus_ = false;
MemBlockFlags highlightFlags_ = MemBlockFlags::ALLOC;
// Current cursor position.
uint32_t curAddress_ = 0;
// Selected range, which should always be around the cursor.
uint32_t selectRangeStart_ = 0;
uint32_t selectRangeEnd_ = 0;
// Last select reset position, for selecting ranges.
uint32_t lastSelectReset_ = 0;
// Address of the first displayed byte.
uint32_t windowStart_ = 0;
// Number of bytes displayed per row.
int rowSize_ = 16;
// Width of one monospace character (to maintain grid.)
int charWidth_ = 0;
// Height of one row of bytes.
int rowHeight_ = 0;
// Y position of offset header (at top.)
int offsetPositionY_;
// X position of addresses (at left.)
int addressStartX_ = 0;
// X position of hex display.
int hexStartX_ = 0;
// X position of text display.
int asciiStartX_ = 0;
// Whether cursor is within text display or hex display.
bool asciiSelected_ = false;
// Which nibble is selected, if in hex display. 0 means leftmost, i.e. most significant.
int selectedNibble_ = 0;
bool displayOffsetScale_ = false;
// Number of rows visible as of last redraw.
int visibleRows_ = 0;
// Position and size as of last redraw.
RECT rect_;
// Last used search query, used when continuing a search.
std::string searchQuery_;
// Address of last match when continuing search.
uint32_t matchAddress_ = 0xFFFFFFFF;
// Whether a search is in progress.
bool searching_ = false;
};

View File

@ -280,6 +280,23 @@ static int ScreenDPI() {
#endif
#endif
static int ScreenRefreshRateHz() {
DEVMODE lpDevMode;
memset(&lpDevMode, 0, sizeof(DEVMODE));
lpDevMode.dmSize = sizeof(DEVMODE);
lpDevMode.dmDriverExtra = 0;
if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &lpDevMode) == 0) {
return 60; // default value
} else {
if (lpDevMode.dmFields & DM_DISPLAYFREQUENCY) {
return lpDevMode.dmDisplayFrequency > 15 ? lpDevMode.dmDisplayFrequency : 60;
} else {
return 60;
}
}
}
int System_GetPropertyInt(SystemProperty prop) {
switch (prop) {
case SYSPROP_AUDIO_SAMPLE_RATE:
@ -311,7 +328,7 @@ int System_GetPropertyInt(SystemProperty prop) {
float System_GetPropertyFloat(SystemProperty prop) {
switch (prop) {
case SYSPROP_DISPLAY_REFRESH_RATE:
return 60.f;
return (float)ScreenRefreshRateHz();
case SYSPROP_DISPLAY_DPI:
return (float)ScreenDPI();
case SYSPROP_DISPLAY_SAFE_INSET_LEFT:

View File

@ -1,6 +1,20 @@
================================================================
NOTE: These are legacy instructions for building using ndk-build.
We mostly only use this on CI because it's faster than gradle.
There might also be some holdouts around still using eclipse.
================================================================
First, build the C++ static library:
> cd android
> ./ab.sh
Or
> ./ab.cmd
as appropriate.
Start Eclipse, import the android directory as an existing project
You need to also load the "native" project into your eclipse workspace

View File

@ -772,6 +772,7 @@ ifeq ($(UNITTEST),1)
$(SRC)/Core/MIPS/ARM/ArmRegCacheFPU.cpp \
$(SRC)/Core/Util/DisArm64.cpp \
$(SRC)/ext/disarm.cpp \
$(SRC)/ext/riscv-disas.cpp \
$(SRC)/unittest/TestArmEmitter.cpp \
$(SRC)/unittest/TestArm64Emitter.cpp \
$(SRC)/unittest/TestRiscVEmitter.cpp \

View File

@ -50,6 +50,9 @@ struct JNIEnv {};
#define JNI_VERSION_1_6 16
#endif
#include "Common/Log.h"
#include "Common/LogReporting.h"
#include "Common/Net/Resolve.h"
#include "android/jni/AndroidAudio.h"
#include "Common/GPU/OpenGL/GLCommon.h"
@ -71,7 +74,6 @@ struct JNIEnv {};
#include "Common/Data/Text/Parsers.h"
#include "Common/VR/PPSSPPVR.h"
#include "Common/Log.h"
#include "Common/GraphicsContext.h"
#include "Common/StringUtils.h"
#include "Common/TimeUtil.h"
@ -236,12 +238,7 @@ void AndroidLogger::Log(const LogMessage &message) {
JNIEnv* getEnv() {
JNIEnv *env;
int status = gJvm->GetEnv((void**)&env, JNI_VERSION_1_6);
if (status < 0) {
status = gJvm->AttachCurrentThread(&env, NULL);
if (status < 0) {
return nullptr;
}
}
_assert_msg_(status >= 0, "'%s': Can only call getEnv if you've attached the thread already!", GetCurrentThreadName());
return env;
}
@ -249,6 +246,33 @@ jclass findClass(const char* name) {
return static_cast<jclass>(getEnv()->CallObjectMethod(gClassLoader, gFindClassMethod, getEnv()->NewStringUTF(name)));
}
void Android_AttachThreadToJNI() {
JNIEnv *env;
int status = gJvm->GetEnv((void **)&env, JNI_VERSION_1_6);
if (status < 0) {
INFO_LOG(SYSTEM, "Attaching thread '%s' (not already attached) to JNI.", GetCurrentThreadName());
JavaVMAttachArgs args{};
args.version = JNI_VERSION_1_6;
args.name = GetCurrentThreadName();
status = gJvm->AttachCurrentThread(&env, &args);
if (status < 0) {
// bad, but what can we do other than report..
ERROR_LOG_REPORT_ONCE(threadAttachFail, SYSTEM, "Failed to attach thread %s to JNI.", GetCurrentThreadName());
}
} else {
WARN_LOG(SYSTEM, "Thread %s was already attached to JNI.", GetCurrentThreadName());
}
}
void Android_DetachThreadFromJNI() {
if (gJvm->DetachCurrentThread() == JNI_OK) {
INFO_LOG(SYSTEM, "Detached thread from JNI: '%s'", GetCurrentThreadName());
} else {
WARN_LOG(SYSTEM, "Failed to detach thread '%s' from JNI - never attached?", GetCurrentThreadName());
}
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *pjvm, void *reserved) {
INFO_LOG(SYSTEM, "JNI_OnLoad");
gJvm = pjvm; // cache the JavaVM pointer
@ -262,6 +286,8 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *pjvm, void *reserved) {
gClassLoader = env->NewGlobalRef(env->CallObjectMethod(randomClass, getClassLoaderMethod));
gFindClassMethod = env->GetMethodID(classLoaderClass, "findClass",
"(Ljava/lang/String;)Ljava/lang/Class;");
RegisterAttachDetach(&Android_AttachThreadToJNI, &Android_DetachThreadFromJNI);
return JNI_VERSION_1_6;
}

View File

@ -28,3 +28,4 @@ public:
#endif
#endif

View File

@ -644,6 +644,18 @@ ULJM05564 = true
NPJH50148 = true
ULAS42189 = true
# Toca Race Driver 3 / DTM Race Driver 3 / V8 Supercars Shootout 3
# Avoids readback.
ULES00613 = true
ULES00615 = true
ULES00614 = true
# Toca Race Driver 2 / DTM Race Driver 2
# Avoids readback.
ULES00040 = true
ULES00041 = true
ULJM05160 = true
[IntraVRAMBlockTransferAllowCreateFB]
# Final Fantasy - Type 0
ULJM05900 = true

View File

@ -137,7 +137,7 @@ Direct3D9 = Direct3D 9 (&9)
Direct3D11 = Direct3D11 (&11)
Disassembly = 反汇编 (&D)...
Discord = Discord
Display Layout && Effects = 屏幕布局/滤镜编辑...
Display Layout && Effects = 屏幕布局滤镜编辑...
Display Rotation = 显示旋转
Dump Next Frame to Log = 转储下一帧到日志 (&U)
Emulation = 模拟 (&E)
@ -313,8 +313,8 @@ Load completed = 已载入。
Loading = 载入中\n请稍候...
LoadingFailed = 无法载入存档。
Move = 移动
Move Down = Move Down
Move Up = Move Up
Move Down = 移至下层
Move Up = 移至上层
Network Connection = 网络连接
NEW DATA = 新建存档
No =
@ -322,7 +322,7 @@ ObtainingIP = 获取IP地址.\n请稍候...
OK = 确定
Old savedata detected = 检测到旧版本的存档数据
Options = 选项
Remove = Remove
Remove = 删除
Reset = 重置
Resize = 调整大小
Retry = 重试
@ -458,7 +458,7 @@ Aggressive = 激进
Alternative Speed = 自定义速度
Alternative Speed 2 = 自定义速度2
Anisotropic Filtering = 各向异性过滤
Antialiasing (MSAA) = Antialiasing (MSAA)
Antialiasing (MSAA) = 抗锯齿 (MSAA)
Aspect Ratio = 宽高比
Auto = 自动
Auto (1:1) = 自动(1:1)
@ -488,7 +488,7 @@ Device = 设备
Direct3D 9 = Direct3D 9
Direct3D 11 = Direct3D 11
Disabled = 禁用
Display Layout && Effects = 屏幕布局/滤镜
Display Layout && Effects = 屏幕布局滤镜
Display Resolution (HW scaler) = 屏幕分辨率
Enable Cardboard VR = 启用Cardboard VR
FPS = 每秒帧数 (FPS)
@ -496,8 +496,8 @@ Frame Rate Control = 帧率控制
Frame Skipping = 跳帧
Frame Skipping Type = 跳帧方式
FullScreen = 全屏幕
Geometry shader culling = Geometry shader culling
GPUReadbackRequired = 警告: 此游戏需要"跳过GPU回读"设置为关闭
Geometry shader culling = 几何着色器剔除
GPUReadbackRequired = 警告: 此游戏需要"跳过 GPU 回读"设置为关闭
Hack Settings = 渲染修正(可能引发故障)
Hardware Tessellation = 硬件曲面细分
Hardware Transform = 硬件几何变换
@ -506,7 +506,7 @@ HardwareTessellation Tip = 使用硬件绘制曲线, 使用固定的质量
High =
Hybrid = 混合
Hybrid + Bicubic = 混合+双三次
Ignore camera notch when centering = 居中时忽略摄像头缺口
Ignore camera notch when centering = 忽略摄像头挖孔
Internal Resolution = 内部分辨率
Lazy texture caching = 减少缓存存取(提速)
Lazy texture caching Tip = 更快, 在一些游戏里引起文字渲染错误
@ -543,14 +543,14 @@ Safe = 安全
Screen Scaling Filter = 缩放方法
Show Debug Statistics = 显示调试信息
Show FPS Counter = 显示FPS计数器
Skip GPU Readbacks = 跳过GPU回读
Skip GPU Readbacks = 跳过 GPU 回读
Software Rendering = 软件渲染(慢)
Software Skinning = 软件蒙皮
SoftwareSkinning Tip = 合并CPU中已经蒙皮的模型绘制,在部分游戏中更快
Speed = 运行速度
Speed Hacks = 提速修正 (引起不稳定性)
Stereo display shader = Stereo display shader
Stereo rendering = Stereo rendering
Stereo display shader = 立体显示效果
Stereo rendering = 立体渲染
Stretch = 拉伸
Texture Filter = 纹理过滤方法
Texture Filtering = 纹理过滤
@ -825,9 +825,9 @@ Undo last save = 撤销保存
[PostShaders]
(duplicated setting, previous slider will be used) = (设置重复, 将使用上面滑块的值)
4xHqGLSL = 4xHQ pixel art upscaler
5xBR = 5xBR pixel art upscaler
5xBR-lv2 = 5xBR-lv2 pixel art upscaler
4xHqGLSL = 4xHQ 像素风缩放
5xBR = 5xBR 像素风缩放
5xBR-lv2 = 5xBR-lv2 像素风缩放
AAColor = AA-Color
Amount = 数量
Animation speed (0 -> disable) = 动画速度(0->禁用)
@ -836,24 +836,24 @@ Bloom = 泛光
Brightness = 亮度
Cartoon = 卡通
ColorCorrection = 颜色修正
ColorPreservation = Color preservation
ColorPreservation = 颜色保留
Contrast = 对比度
CRT = CRT 扫描线
FXAA = FXAA(快速近似抗锯齿)
Gamma = 伽马值
GreenLevel = Green level
GreenLevel = 绿色等级
Intensity = 强度
LCDPersistence = LCD图像残留
LCDPersistence = LCD拖影
Natural = 自然色
NaturalA = 自然色(无模糊)
Off = 关闭
Power = 效果强度
PSPColor = PSP色彩
RedBlue = 红蓝眼镜
RedBlue = 红蓝渲染
Saturation = 色彩
Scanlines = 扫描线(CRT)
Sharpen = 锐化
SideBySide = 并存(SBS)
SideBySide = 双目渲染
SSAA(Gauss) = 超级采样抗锯齿(高斯)
Tex4xBRZ = 4xBRZ
TexMMPX = MMPX
@ -1039,13 +1039,13 @@ CPU Name = CPU 名称
D3DCompiler Version = D3DCompiler版本
Debug = 调试
Debugger Present = 调试器已连接
Depth buffer format = Depth buffer format
Depth buffer format = 深度缓冲区格式
Device Info = 设备信息
Directories = 路径
Display Color Formats = 显示颜色格式
Display Information = 显示信息
DPI = DPI
Driver Version = 驱动程序版本
Driver Version = 驱动版本
EGL Extensions = EGL扩展
Frames per buffer = 每缓冲区帧数
GPU Information = GPU信息
@ -1063,7 +1063,7 @@ Optimal sample rate = 最佳采样率
OS Information = OS信息
PPSSPP build = PPSSPP编译版本
Refresh rate = 刷新率
Release = 发布
Release = 发布
RW/RX exclusive = RW/RX独占
Sample rate = 采样率
Shading Language = 着色语言
@ -1073,9 +1073,9 @@ System Information = 系统信息
System Name = 系统名称
System Version = 系统版本
Threads = 线程数
UI Resolution = UI Resolution
Vendor = 供应商
Vendor (detected) = 供应商(检测到的)
UI Resolution = UI 分辨率
Vendor = 型号
Vendor (detected) = 型号(检测到的)
Version Information = 版本信息
Vulkan Extensions = Vulkan扩展
Vulkan Features = Vulkan特性
@ -1097,7 +1097,7 @@ Color Saturation = 颜色饱和度
Error: load undo state is from a different game = 错误:撤回的即时存档是来自不同游戏的
Failed to load state for load undo. Error in the file system. = 无法撤回加载即时存档。文件系统有错误。
Floating symbols = 飘浮的按键
Game crashed = Game crashed
Game crashed = 游戏发生崩溃。
Language = 语言设置
Memory Stick folder = 记忆棒文件夹
Memory Stick size = 记忆棒大小(GB)
@ -1159,7 +1159,7 @@ Record Audio = 录制音频
Record Display = 录制视频
Reset Recording on Save/Load State = 保存/载入存档时重置录制
Restore Default Settings = 恢复默认PPSSPP设置
Rewind Snapshot Frequency = 倒带自动即时存档频率
Rewind Snapshot Frequency = 倒带存档频率
Save path in installed.txt = 存档路径在installed.txt
Save path in My Documents = 存档路径在我的文档
Savestate Slot = 即时存档插槽
@ -1215,7 +1215,7 @@ Default = 默认
Choices: = 选择:
List: = 列表:
Progress: %1% = 进度: %1%
Screen representation = 屏幕表现
Screen representation = 屏幕显示
[Upgrade]
Details = 详细内容

@ -1 +1 @@
Subproject commit 9acb9ec31f5a8ef80ea6b994bb77be787b08d3d1
Subproject commit c77b09b57c27837dc2d41aa371ed3d236ce9ce47

@ -1 +1 @@
Subproject commit dc11adde23c455a24e13dd54de9b4ede8bdd7db8
Subproject commit 77551c429f86c0e077f26552b7c1c0f12a9f235e

View File

@ -29,6 +29,7 @@ LOCAL_SRC_FILES := \
../glslang/glslang/MachineIndependent/RemoveTree.cpp \
../glslang/glslang/MachineIndependent/Scan.cpp \
../glslang/glslang/MachineIndependent/ShaderLang.cpp \
../glslang/glslang/MachineIndependent/SpirvIntrinsics.cpp \
../glslang/glslang/MachineIndependent/SymbolTable.cpp \
../glslang/glslang/MachineIndependent/Versions.cpp \
../glslang/glslang/MachineIndependent/preprocessor/Pp.cpp \

View File

@ -0,0 +1,62 @@
// Copyright (C) 2020 The Khronos Group Inc.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// Neither the name of The Khronos Group Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#ifndef GLSLANG_BUILD_INFO
#define GLSLANG_BUILD_INFO
#define GLSLANG_VERSION_MAJOR 11
#define GLSLANG_VERSION_MINOR 13
#define GLSLANG_VERSION_PATCH 0
#define GLSLANG_VERSION_FLAVOR ""
#define GLSLANG_VERSION_GREATER_THAN(major, minor, patch) \
((GLSLANG_VERSION_MAJOR) > (major) || ((major) == GLSLANG_VERSION_MAJOR && \
((GLSLANG_VERSION_MINOR) > (minor) || ((minor) == GLSLANG_VERSION_MINOR && \
(GLSLANG_VERSION_PATCH) > (patch)))))
#define GLSLANG_VERSION_GREATER_OR_EQUAL_TO(major, minor, patch) \
((GLSLANG_VERSION_MAJOR) > (major) || ((major) == GLSLANG_VERSION_MAJOR && \
((GLSLANG_VERSION_MINOR) > (minor) || ((minor) == GLSLANG_VERSION_MINOR && \
(GLSLANG_VERSION_PATCH >= (patch))))))
#define GLSLANG_VERSION_LESS_THAN(major, minor, patch) \
((GLSLANG_VERSION_MAJOR) < (major) || ((major) == GLSLANG_VERSION_MAJOR && \
((GLSLANG_VERSION_MINOR) < (minor) || ((minor) == GLSLANG_VERSION_MINOR && \
(GLSLANG_VERSION_PATCH) < (patch)))))
#define GLSLANG_VERSION_LESS_OR_EQUAL_TO(major, minor, patch) \
((GLSLANG_VERSION_MAJOR) < (major) || ((major) == GLSLANG_VERSION_MAJOR && \
((GLSLANG_VERSION_MINOR) < (minor) || ((minor) == GLSLANG_VERSION_MINOR && \
(GLSLANG_VERSION_PATCH <= (patch))))))
#endif // GLSLANG_BUILD_INFO

View File

@ -142,7 +142,7 @@
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<AdditionalIncludeDirectories>glslang/glslang/OSDependent/Windows;glslang/glslang/MachineIndependent;glslang</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>glslang/glslang/OSDependent/Windows;glslang/glslang/MachineIndependent;glslang;glslang-build</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
@ -158,7 +158,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>ENABLE_HLSL;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>glslang/glslang/OSDependent/Windows;glslang/glslang/MachineIndependent;glslang</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>glslang/glslang/OSDependent/Windows;glslang/glslang/MachineIndependent;glslang;glslang-build</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
@ -177,7 +177,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>ENABLE_HLSL;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>glslang/glslang/OSDependent/Windows;glslang/glslang/MachineIndependent;glslang</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>glslang/glslang/OSDependent/Windows;glslang/glslang/MachineIndependent;glslang;glslang-build</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
@ -196,7 +196,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>ENABLE_HLSL;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>glslang/glslang/OSDependent/Windows;glslang/glslang/MachineIndependent;glslang</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>glslang/glslang/OSDependent/Windows;glslang/glslang/MachineIndependent;glslang;glslang-build</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
@ -217,7 +217,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>ENABLE_HLSL;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>glslang/glslang/OSDependent/Windows;glslang/glslang/MachineIndependent;glslang</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>glslang/glslang/OSDependent/Windows;glslang/glslang/MachineIndependent;glslang;glslang-build</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
@ -239,7 +239,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>ENABLE_HLSL;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>glslang/glslang/OSDependent/Windows;glslang/glslang/MachineIndependent;glslang</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>glslang/glslang/OSDependent/Windows;glslang/glslang/MachineIndependent;glslang;glslang-build</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
@ -262,7 +262,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>ENABLE_HLSL;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>glslang/glslang/OSDependent/Windows;glslang/glslang/MachineIndependent;glslang</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>glslang/glslang/OSDependent/Windows;glslang/glslang/MachineIndependent;glslang;glslang-build</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
@ -285,7 +285,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>ENABLE_HLSL;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>glslang/glslang/OSDependent/Windows;glslang/glslang/MachineIndependent;glslang</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>glslang/glslang/OSDependent/Windows;glslang/glslang/MachineIndependent;glslang;glslang-build</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
@ -300,6 +300,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="glslang\glslang\MachineIndependent\SpirvIntrinsics.cpp" />
<ClCompile Include="glslang\SPIRV\SpvTools.cpp" />
<ClCompile Include="glslang\glslang\GenericCodeGen\CodeGen.cpp" />
<ClCompile Include="glslang\glslang\GenericCodeGen\Link.cpp" />
@ -349,8 +350,8 @@
<ClCompile Include="glslang\SPIRV\SPVRemapper.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="glslang\glslang\build_info.h" />
<ClInclude Include="glslang\glslang\HLSL\pch.h" />
<ClInclude Include="glslang\glslang\Include\SpirvIntrinsics.h" />
<ClInclude Include="glslang\glslang\MachineIndependent\pch.h" />
<ClInclude Include="glslang\SPIRV\GLSL.ext.EXT.h" />
<ClInclude Include="glslang\SPIRV\GLSL.ext.NV.h" />

View File

@ -149,6 +149,9 @@
<ClCompile Include="glslang\SPIRV\SpvTools.cpp">
<Filter>SPIRV</Filter>
</ClCompile>
<ClCompile Include="glslang\glslang\MachineIndependent\SpirvIntrinsics.cpp">
<Filter>glslang</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="glslang\SPIRV\disassemble.h">
@ -326,7 +329,7 @@
<ClInclude Include="glslang\glslang\MachineIndependent\pch.h">
<Filter>glslang</Filter>
</ClInclude>
<ClInclude Include="glslang\glslang\build_info.h">
<ClInclude Include="glslang\glslang\Include\SpirvIntrinsics.h">
<Filter>glslang</Filter>
</ClInclude>
</ItemGroup>

2415
ext/riscv-disas.cpp Normal file

File diff suppressed because it is too large Load Diff

554
ext/riscv-disas.h Normal file
View File

@ -0,0 +1,554 @@
/*
* RISC-V Disassembler
*
* Copyright (c) 2016-2017 Michael Clark <michaeljclark@mac.com>
* Copyright (c) 2017-2018 SiFive, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef RISCV_DISASSEMBLER_H
#define RISCV_DISASSEMBLER_H
#include <cstdint>
/* types */
typedef uint64_t rv_inst;
typedef uint16_t rv_opcode;
/* enums */
typedef enum {
rv32,
rv64,
rv128
} rv_isa;
typedef enum {
rv_rm_rne = 0,
rv_rm_rtz = 1,
rv_rm_rdn = 2,
rv_rm_rup = 3,
rv_rm_rmm = 4,
rv_rm_dyn = 7,
} rv_rm;
typedef enum {
rv_fence_i = 8,
rv_fence_o = 4,
rv_fence_r = 2,
rv_fence_w = 1,
} rv_fence;
typedef enum {
rv_ireg_zero,
rv_ireg_ra,
rv_ireg_sp,
rv_ireg_gp,
rv_ireg_tp,
rv_ireg_t0,
rv_ireg_t1,
rv_ireg_t2,
rv_ireg_s0,
rv_ireg_s1,
rv_ireg_a0,
rv_ireg_a1,
rv_ireg_a2,
rv_ireg_a3,
rv_ireg_a4,
rv_ireg_a5,
rv_ireg_a6,
rv_ireg_a7,
rv_ireg_s2,
rv_ireg_s3,
rv_ireg_s4,
rv_ireg_s5,
rv_ireg_s6,
rv_ireg_s7,
rv_ireg_s8,
rv_ireg_s9,
rv_ireg_s10,
rv_ireg_s11,
rv_ireg_t3,
rv_ireg_t4,
rv_ireg_t5,
rv_ireg_t6,
} rv_ireg;
typedef enum {
rvc_end,
rvc_rd_eq_ra,
rvc_rd_eq_x0,
rvc_rs1_eq_x0,
rvc_rs2_eq_x0,
rvc_rs2_eq_rs1,
rvc_rs1_eq_ra,
rvc_imm_eq_zero,
rvc_imm_eq_n1,
rvc_imm_eq_p1,
rvc_csr_eq_0x001,
rvc_csr_eq_0x002,
rvc_csr_eq_0x003,
rvc_csr_eq_0xc00,
rvc_csr_eq_0xc01,
rvc_csr_eq_0xc02,
rvc_csr_eq_0xc80,
rvc_csr_eq_0xc81,
rvc_csr_eq_0xc82,
} rvc_constraint;
typedef enum {
rv_codec_illegal,
rv_codec_none,
rv_codec_u,
rv_codec_uj,
rv_codec_i,
rv_codec_i_sh5,
rv_codec_i_sh6,
rv_codec_i_sh7,
rv_codec_i_csr,
rv_codec_s,
rv_codec_sb,
rv_codec_r,
rv_codec_r_m,
rv_codec_r4_m,
rv_codec_r_a,
rv_codec_r_l,
rv_codec_r_f,
rv_codec_cb,
rv_codec_cb_imm,
rv_codec_cb_sh5,
rv_codec_cb_sh6,
rv_codec_ci,
rv_codec_ci_sh5,
rv_codec_ci_sh6,
rv_codec_ci_16sp,
rv_codec_ci_lwsp,
rv_codec_ci_ldsp,
rv_codec_ci_lqsp,
rv_codec_ci_li,
rv_codec_ci_lui,
rv_codec_ci_none,
rv_codec_ciw_4spn,
rv_codec_cj,
rv_codec_cj_jal,
rv_codec_cl_lw,
rv_codec_cl_ld,
rv_codec_cl_lq,
rv_codec_cr,
rv_codec_cr_mv,
rv_codec_cr_jalr,
rv_codec_cr_jr,
rv_codec_cs,
rv_codec_cs_sw,
rv_codec_cs_sd,
rv_codec_cs_sq,
rv_codec_css_swsp,
rv_codec_css_sdsp,
rv_codec_css_sqsp,
} rv_codec;
typedef enum {
rv_op_illegal,
rv_op_lui,
rv_op_auipc,
rv_op_jal,
rv_op_jalr,
rv_op_beq,
rv_op_bne,
rv_op_blt,
rv_op_bge,
rv_op_bltu,
rv_op_bgeu,
rv_op_lb,
rv_op_lh,
rv_op_lw,
rv_op_lbu,
rv_op_lhu,
rv_op_sb,
rv_op_sh,
rv_op_sw,
rv_op_addi,
rv_op_slti,
rv_op_sltiu,
rv_op_xori,
rv_op_ori,
rv_op_andi,
rv_op_slli,
rv_op_srli,
rv_op_srai,
rv_op_add,
rv_op_sub,
rv_op_sll,
rv_op_slt,
rv_op_sltu,
rv_op_xor,
rv_op_srl,
rv_op_sra,
rv_op_or,
rv_op_and,
rv_op_fence,
rv_op_fence_i,
rv_op_lwu,
rv_op_ld,
rv_op_sd,
rv_op_addiw,
rv_op_slliw,
rv_op_srliw,
rv_op_sraiw,
rv_op_addw,
rv_op_subw,
rv_op_sllw,
rv_op_srlw,
rv_op_sraw,
rv_op_ldu,
rv_op_lq,
rv_op_sq,
rv_op_addid,
rv_op_sllid,
rv_op_srlid,
rv_op_sraid,
rv_op_addd,
rv_op_subd,
rv_op_slld,
rv_op_srld,
rv_op_srad,
rv_op_mul,
rv_op_mulh,
rv_op_mulhsu,
rv_op_mulhu,
rv_op_div,
rv_op_divu,
rv_op_rem,
rv_op_remu,
rv_op_mulw,
rv_op_divw,
rv_op_divuw,
rv_op_remw,
rv_op_remuw,
rv_op_muld,
rv_op_divd,
rv_op_divud,
rv_op_remd,
rv_op_remud,
rv_op_lr_w,
rv_op_sc_w,
rv_op_amoswap_w,
rv_op_amoadd_w,
rv_op_amoxor_w,
rv_op_amoor_w,
rv_op_amoand_w,
rv_op_amomin_w,
rv_op_amomax_w,
rv_op_amominu_w,
rv_op_amomaxu_w,
rv_op_lr_d,
rv_op_sc_d,
rv_op_amoswap_d,
rv_op_amoadd_d,
rv_op_amoxor_d,
rv_op_amoor_d,
rv_op_amoand_d,
rv_op_amomin_d,
rv_op_amomax_d,
rv_op_amominu_d,
rv_op_amomaxu_d,
rv_op_lr_q,
rv_op_sc_q,
rv_op_amoswap_q,
rv_op_amoadd_q,
rv_op_amoxor_q,
rv_op_amoor_q,
rv_op_amoand_q,
rv_op_amomin_q,
rv_op_amomax_q,
rv_op_amominu_q,
rv_op_amomaxu_q,
rv_op_ecall,
rv_op_ebreak,
rv_op_uret,
rv_op_sret,
rv_op_hret,
rv_op_mret,
rv_op_dret,
rv_op_sfence_vm,
rv_op_sfence_vma,
rv_op_wfi,
rv_op_csrrw,
rv_op_csrrs,
rv_op_csrrc,
rv_op_csrrwi,
rv_op_csrrsi,
rv_op_csrrci,
rv_op_flh,
rv_op_fsh,
rv_op_fmadd_h,
rv_op_fmsub_h,
rv_op_fnmsub_h,
rv_op_fnmadd_h,
rv_op_fadd_h,
rv_op_fsub_h,
rv_op_fmul_h,
rv_op_fdiv_h,
rv_op_fsgnj_h,
rv_op_fsgnjn_h,
rv_op_fsgnjx_h,
rv_op_fmin_h,
rv_op_fmax_h,
rv_op_fsqrt_h,
rv_op_fle_h,
rv_op_flt_h,
rv_op_feq_h,
rv_op_fcvt_w_h,
rv_op_fcvt_wu_h,
rv_op_fcvt_h_w,
rv_op_fcvt_h_wu,
rv_op_fclass_h,
rv_op_fcvt_l_h,
rv_op_fcvt_lu_h,
rv_op_fmv_x_h,
rv_op_fcvt_h_l,
rv_op_fcvt_h_lu,
rv_op_fmv_h_x,
rv_op_fcvt_s_h,
rv_op_fcvt_h_s,
rv_op_fcvt_d_h,
rv_op_fcvt_h_d,
rv_op_fcvt_q_h,
rv_op_fcvt_h_q,
rv_op_fmv_h,
rv_op_fabs_h,
rv_op_fneg_h,
rv_op_flw,
rv_op_fsw,
rv_op_fmadd_s,
rv_op_fmsub_s,
rv_op_fnmsub_s,
rv_op_fnmadd_s,
rv_op_fadd_s,
rv_op_fsub_s,
rv_op_fmul_s,
rv_op_fdiv_s,
rv_op_fsgnj_s,
rv_op_fsgnjn_s,
rv_op_fsgnjx_s,
rv_op_fmin_s,
rv_op_fmax_s,
rv_op_fsqrt_s,
rv_op_fle_s,
rv_op_flt_s,
rv_op_feq_s,
rv_op_fcvt_w_s,
rv_op_fcvt_wu_s,
rv_op_fcvt_s_w,
rv_op_fcvt_s_wu,
rv_op_fmv_x_s,
rv_op_fclass_s,
rv_op_fmv_s_x,
rv_op_fcvt_l_s,
rv_op_fcvt_lu_s,
rv_op_fcvt_s_l,
rv_op_fcvt_s_lu,
rv_op_fld,
rv_op_fsd,
rv_op_fmadd_d,
rv_op_fmsub_d,
rv_op_fnmsub_d,
rv_op_fnmadd_d,
rv_op_fadd_d,
rv_op_fsub_d,
rv_op_fmul_d,
rv_op_fdiv_d,
rv_op_fsgnj_d,
rv_op_fsgnjn_d,
rv_op_fsgnjx_d,
rv_op_fmin_d,
rv_op_fmax_d,
rv_op_fcvt_s_d,
rv_op_fcvt_d_s,
rv_op_fsqrt_d,
rv_op_fle_d,
rv_op_flt_d,
rv_op_feq_d,
rv_op_fcvt_w_d,
rv_op_fcvt_wu_d,
rv_op_fcvt_d_w,
rv_op_fcvt_d_wu,
rv_op_fclass_d,
rv_op_fcvt_l_d,
rv_op_fcvt_lu_d,
rv_op_fmv_x_d,
rv_op_fcvt_d_l,
rv_op_fcvt_d_lu,
rv_op_fmv_d_x,
rv_op_flq,
rv_op_fsq,
rv_op_fmadd_q,
rv_op_fmsub_q,
rv_op_fnmsub_q,
rv_op_fnmadd_q,
rv_op_fadd_q,
rv_op_fsub_q,
rv_op_fmul_q,
rv_op_fdiv_q,
rv_op_fsgnj_q,
rv_op_fsgnjn_q,
rv_op_fsgnjx_q,
rv_op_fmin_q,
rv_op_fmax_q,
rv_op_fcvt_s_q,
rv_op_fcvt_q_s,
rv_op_fcvt_d_q,
rv_op_fcvt_q_d,
rv_op_fsqrt_q,
rv_op_fle_q,
rv_op_flt_q,
rv_op_feq_q,
rv_op_fcvt_w_q,
rv_op_fcvt_wu_q,
rv_op_fcvt_q_w,
rv_op_fcvt_q_wu,
rv_op_fclass_q,
rv_op_fcvt_l_q,
rv_op_fcvt_lu_q,
rv_op_fcvt_q_l,
rv_op_fcvt_q_lu,
rv_op_fmv_x_q,
rv_op_fmv_q_x,
rv_op_c_addi4spn,
rv_op_c_fld,
rv_op_c_lw,
rv_op_c_flw,
rv_op_c_fsd,
rv_op_c_sw,
rv_op_c_fsw,
rv_op_c_nop,
rv_op_c_addi,
rv_op_c_jal,
rv_op_c_li,
rv_op_c_addi16sp,
rv_op_c_lui,
rv_op_c_srli,
rv_op_c_srai,
rv_op_c_andi,
rv_op_c_sub,
rv_op_c_xor,
rv_op_c_or,
rv_op_c_and,
rv_op_c_subw,
rv_op_c_addw,
rv_op_c_j,
rv_op_c_beqz,
rv_op_c_bnez,
rv_op_c_slli,
rv_op_c_fldsp,
rv_op_c_lwsp,
rv_op_c_flwsp,
rv_op_c_jr,
rv_op_c_mv,
rv_op_c_ebreak,
rv_op_c_jalr,
rv_op_c_add,
rv_op_c_fsdsp,
rv_op_c_swsp,
rv_op_c_fswsp,
rv_op_c_ld,
rv_op_c_sd,
rv_op_c_addiw,
rv_op_c_ldsp,
rv_op_c_sdsp,
rv_op_c_lq,
rv_op_c_sq,
rv_op_c_lqsp,
rv_op_c_sqsp,
rv_op_nop,
rv_op_mv,
rv_op_not,
rv_op_neg,
rv_op_negw,
rv_op_sext_w,
rv_op_seqz,
rv_op_snez,
rv_op_sltz,
rv_op_sgtz,
rv_op_fmv_s,
rv_op_fabs_s,
rv_op_fneg_s,
rv_op_fmv_d,
rv_op_fabs_d,
rv_op_fneg_d,
rv_op_fmv_q,
rv_op_fabs_q,
rv_op_fneg_q,
rv_op_beqz,
rv_op_bnez,
rv_op_blez,
rv_op_bgez,
rv_op_bltz,
rv_op_bgtz,
rv_op_ble,
rv_op_bleu,
rv_op_bgt,
rv_op_bgtu,
rv_op_j,
rv_op_ret,
rv_op_jr,
rv_op_rdcycle,
rv_op_rdtime,
rv_op_rdinstret,
rv_op_rdcycleh,
rv_op_rdtimeh,
rv_op_rdinstreth,
rv_op_frcsr,
rv_op_frrm,
rv_op_frflags,
rv_op_fscsr,
rv_op_fsrm,
rv_op_fsflags,
rv_op_fsrmi,
rv_op_fsflagsi,
} rv_op;
/* structures */
typedef struct {
uint64_t pc;
uint64_t inst;
int32_t imm;
uint16_t op;
uint8_t codec;
uint8_t rd;
uint8_t rs1;
uint8_t rs2;
uint8_t rs3;
uint8_t rm;
uint8_t pred;
uint8_t succ;
uint8_t aq;
uint8_t rl;
} rv_decode;
/* functions */
size_t riscv_inst_length(rv_inst inst);
void riscv_inst_fetch(const uint8_t *data, rv_inst *instp, size_t *length);
void riscv_disasm_inst(char *buf, size_t buflen, rv_isa isa, uint64_t pc, rv_inst inst);
#endif

View File

@ -1 +1 @@
libvulkan.so.1.2.198
libvulkan.so.1.2.236

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More