mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 21:39:52 +00:00
Merge branch 'hrydgard:master' into compat-openxr-3rdbirthday
This commit is contained in:
commit
cd3ed86152
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -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
|
||||
|
@ -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
|
||||
)
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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_;
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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];
|
||||
|
@ -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.
|
||||
|
@ -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" />
|
||||
|
@ -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" />
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -1210,6 +1210,8 @@ void PSPSaveDialog::JoinIOThread() {
|
||||
|
||||
static void DoExecuteIOAction(PSPSaveDialog *dialog) {
|
||||
SetCurrentThreadName("SaveIO");
|
||||
|
||||
AndroidJNIThreadContext jniContext;
|
||||
dialog->ExecuteIOAction();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
@ -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)));
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
void Update();
|
||||
|
||||
GameManagerState GetState() {
|
||||
if (installInProgress_)
|
||||
if (installInProgress_ || installDonePending_)
|
||||
return GameManagerState::INSTALLING;
|
||||
if (curDownload_)
|
||||
return GameManagerState::DOWNLOADING;
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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" });
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 =
|
||||
|
@ -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();
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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" />
|
||||
|
@ -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>
|
||||
|
@ -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" />
|
||||
|
@ -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>
|
@ -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();
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -28,3 +28,4 @@ public:
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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 \
|
||||
|
62
ext/glslang-build/glslang/build_info.h
Normal file
62
ext/glslang-build/glslang/build_info.h
Normal 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
|
@ -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" />
|
||||
|
@ -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
2415
ext/riscv-disas.cpp
Normal file
File diff suppressed because it is too large
Load Diff
554
ext/riscv-disas.h
Normal file
554
ext/riscv-disas.h
Normal 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
|
@ -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
Loading…
Reference in New Issue
Block a user