Merge branch 'master' into TemporaryHackishBranch

This commit is contained in:
LunaMoo committed 2018-09-09 17:59:05 +02:00
commit 5952984457
98 files changed
+1152 -527

No files matched your search

+6 -4
View File
@@ -1194,10 +1194,6 @@ if (NOT MOBILE_DEVICE)
Core/WaveFile.h)
endif()
if(ARMV7)
set(CORE_NEON Core/Util/AudioFormatNEON.cpp Core/Util/AudioFormatNEON.h)
endif()
set(GPU_GLES
GPU/GLES/DepalettizeShaderGLES.cpp
GPU/GLES/DepalettizeShaderGLES.h
@@ -1357,6 +1353,8 @@ set(GPU_SOURCES
GPU/Common/SplineCommon.h
GPU/Debugger/Breakpoints.cpp
GPU/Debugger/Breakpoints.h
GPU/Debugger/Debugger.cpp
GPU/Debugger/Debugger.h
GPU/Debugger/Record.cpp
GPU/Debugger/Record.h
GPU/Debugger/Stepping.cpp
@@ -1430,6 +1428,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/Debugger/WebSocket/GameSubscriber.h
Core/Debugger/WebSocket/GPUBufferSubscriber.cpp
Core/Debugger/WebSocket/GPUBufferSubscriber.h
Core/Debugger/WebSocket/GPURecordSubscriber.cpp
Core/Debugger/WebSocket/GPURecordSubscriber.h
Core/Debugger/WebSocket/HLESubscriber.cpp
Core/Debugger/WebSocket/HLESubscriber.h
Core/Debugger/WebSocket/LogBroadcaster.cpp
@@ -1709,6 +1709,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/TextureReplacer.h
Core/Util/AudioFormat.cpp
Core/Util/AudioFormat.h
Core/Util/AudioFormatNEON.cpp
Core/Util/AudioFormatNEON.h
Core/Util/GameManager.cpp
Core/Util/GameManager.h
Core/Util/BlockAllocator.cpp
+1 -1
View File
@@ -643,7 +643,7 @@ Convert16bppTo16bppFunc ConvertRGB565ToBGR565 = &ConvertRGB565ToBGR565Basic;
#endif
void SetupColorConv() {
#if PPSSPP_ARCH(ARMV7) && PPSSPP_ARCH(ARM_NEON)
#if PPSSPP_ARCH(ARM_NEON) && !PPSSPP_ARCH(ARM64)
if (cpu_info.bNEON) {
ConvertRGBA4444ToABGR4444 = &ConvertRGBA4444ToABGR4444NEON;
ConvertRGBA5551ToABGR1555 = &ConvertRGBA5551ToABGR1555NEON;
+10 -6
View File
@@ -269,9 +269,11 @@ bool Delete(const std::string &filename) {
// Returns true if successful, or path already exists.
bool CreateDir(const std::string &path)
{
DEBUG_LOG(COMMON, "CreateDir('%s')", path.c_str());
std::string fn = path;
StripTailDirSlashes(fn);
DEBUG_LOG(COMMON, "CreateDir('%s')", fn.c_str());
#ifdef _WIN32
if (::CreateDirectory(ConvertUTF8ToWString(path).c_str(), NULL))
if (::CreateDirectory(ConvertUTF8ToWString(fn).c_str(), NULL))
return true;
DWORD error = GetLastError();
if (error == ERROR_ALREADY_EXISTS)
@@ -282,25 +284,27 @@ bool CreateDir(const std::string &path)
ERROR_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: %i", path.c_str(), error);
return false;
#else
if (mkdir(path.c_str(), 0755) == 0)
if (mkdir(fn.c_str(), 0755) == 0)
return true;
int err = errno;
if (err == EEXIST)
{
WARN_LOG(COMMON, "CreateDir: mkdir failed on %s: already exists", path.c_str());
WARN_LOG(COMMON, "CreateDir: mkdir failed on %s: already exists", fn.c_str());
return true;
}
ERROR_LOG(COMMON, "CreateDir: mkdir failed on %s: %s", path.c_str(), strerror(err));
ERROR_LOG(COMMON, "CreateDir: mkdir failed on %s: %s", fn.c_str(), strerror(err));
return false;
#endif
}
// Creates the full path of fullPath returns true on success
bool CreateFullPath(const std::string &fullPath)
bool CreateFullPath(const std::string &path)
{
std::string fullPath = path;
StripTailDirSlashes(fullPath);
int panicCounter = 100;
VERBOSE_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str());
+8 -2
View File
@@ -1040,6 +1040,8 @@ bool GLSLtoSPV(const VkShaderStageFlagBits shader_type,
glslang::TProgram program;
const char *shaderStrings[1];
EProfile profile = ECoreProfile;
int defaultVersion = 450;
TBuiltInResource Resources;
init_resources(Resources);
@@ -1052,7 +1054,7 @@ bool GLSLtoSPV(const VkShaderStageFlagBits shader_type,
shaderStrings[0] = pshader;
shader.setStrings(shaderStrings, 1);
if (!shader.parse(&Resources, 100, false, messages)) {
if (!shader.parse(&Resources, defaultVersion, profile, false, true, messages)) {
puts(shader.getInfoLog());
puts(shader.getInfoDebugLog());
if (errorMessage) {
@@ -1076,7 +1078,11 @@ bool GLSLtoSPV(const VkShaderStageFlagBits shader_type,
}
// Can't fail, parsing worked, "linking" worked.
glslang::GlslangToSpv(*program.getIntermediate(stage), spirv);
glslang::SpvOptions options;
options.disableOptimizer = false;
options.optimizeSize = false;
options.generateDebugInfo = false;
glslang::GlslangToSpv(*program.getIntermediate(stage), spirv, &options);
return true;
}
+49 -1
View File
@@ -19,6 +19,7 @@
#include <cstdlib>
#include <ctime>
#include <functional>
#include <set>
#include "base/display.h"
#include "base/NativeApp.h"
@@ -551,6 +552,49 @@ static int DefaultGPUBackend() {
return (int)GPUBackend::OPENGL;
}
int Config::NextValidBackend() {
std::vector<std::string> split;
std::set<int> failed;
SplitString(sFailedGPUBackends, ',', split);
for (const auto &str : split) {
if (!str.empty() && str != "ALL") {
failed.insert(atoi(str.c_str()));
}
}
if (failed.count(iGPUBackend)) {
ERROR_LOG(LOADER, "Graphics backend failed for %d, trying another", iGPUBackend);
#if (PPSSPP_PLATFORM(WINDOWS) || PPSSPP_PLATFORM(ANDROID)) && !PPSSPP_PLATFORM(UWP)
if (VulkanMayBeAvailable() && !failed.count((int)GPUBackend::VULKAN)) {
return (int)GPUBackend::VULKAN;
}
#endif
#if PPSSPP_PLATFORM(WINDOWS)
if (DoesVersionMatchWindows(6, 1, 0, 0, true) && !failed.count((int)GPUBackend::DIRECT3D11)) {
return (int)GPUBackend::DIRECT3D11;
}
#endif
#if !PPSSPP_PLATFORM(UWP)
if (!failed.count((int)GPUBackend::OPENGL)) {
return (int)GPUBackend::OPENGL;
}
#endif
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
if (!failed.count((int)GPUBackend::DIRECT3D9)) {
return (int)GPUBackend::DIRECT3D9;
}
#endif
// They've all failed. Let them try the default.
sFailedGPUBackends += ",ALL";
ERROR_LOG(LOADER, "All graphics backends failed");
return DefaultGPUBackend();
}
return iGPUBackend;
}
static bool DefaultVertexCache() {
return DefaultGPUBackend() == (int)GPUBackend::OPENGL;
}
@@ -562,6 +606,7 @@ static ConfigSetting graphicsSettings[] = {
ConfigSetting("CardboardYShift", &g_Config.iCardboardXShift, 0, true, true),
ConfigSetting("ShowFPSCounter", &g_Config.iShowFPSCounter, 0, true, true),
ReportedConfigSetting("GraphicsBackend", &g_Config.iGPUBackend, &DefaultGPUBackend),
ConfigSetting("FailedGraphicsBackends", &g_Config.sFailedGPUBackends, ""),
ConfigSetting("VulkanDevice", &g_Config.sVulkanDevice, "", true, false),
#ifdef _WIN32
ConfigSetting("D3D11Device", &g_Config.sD3D11Device, "", true, false),
@@ -1008,7 +1053,10 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
auto pinnedPaths = iniFile.GetOrCreateSection("PinnedPaths")->ToMap();
vPinnedPaths.clear();
for (auto it = pinnedPaths.begin(), end = pinnedPaths.end(); it != end; ++it) {
vPinnedPaths.push_back(it->second);
// Unpin paths that are deleted automatically.
if (File::Exists(it->second)) {
vPinnedPaths.push_back(File::ResolvePath(it->second));
}
}
// This caps the exponent 4 (so 16x.)
+2
View File
@@ -128,6 +128,7 @@ public:
// GFX
int iGPUBackend;
std::string sFailedGPUBackends;
// We have separate device parameters for each backend so it doesn't get erased if you switch backends.
// If not set, will use the "best" device.
std::string sVulkanDevice;
@@ -454,6 +455,7 @@ public:
void GetReportingInfo(UrlEncoder &data);
bool IsPortrait() const;
int NextValidBackend();
protected:
void LoadStandardControllerIni();
+2
View File
@@ -188,6 +188,7 @@
<ClCompile Include="Debugger\WebSocket\GameBroadcaster.cpp" />
<ClCompile Include="Debugger\WebSocket\GameSubscriber.cpp" />
<ClCompile Include="Debugger\WebSocket\GPUBufferSubscriber.cpp" />
<ClCompile Include="Debugger\WebSocket\GPURecordSubscriber.cpp" />
<ClCompile Include="Debugger\WebSocket\HLESubscriber.cpp" />
<ClCompile Include="Debugger\WebSocket\LogBroadcaster.cpp" />
<ClCompile Include="Debugger\WebSocket\DisasmSubscriber.cpp" />
@@ -549,6 +550,7 @@
<ClInclude Include="Debugger\WebSocket\GameSubscriber.h" />
<ClInclude Include="Debugger\WebSocket\DisasmSubscriber.h" />
<ClInclude Include="Debugger\WebSocket\GPUBufferSubscriber.h" />
<ClInclude Include="Debugger\WebSocket\GPURecordSubscriber.h" />
<ClInclude Include="Debugger\WebSocket\HLESubscriber.h" />
<ClInclude Include="Debugger\WebSocket\SteppingSubscriber.h" />
<ClInclude Include="Debugger\WebSocket\WebSocketUtils.h" />
+6
View File
@@ -734,6 +734,9 @@
<ClCompile Include="HLE\sceUsbAcc.cpp">
<Filter>HLE\Libraries</Filter>
</ClCompile>
<ClCompile Include="Debugger\WebSocket\GPURecordSubscriber.cpp">
<Filter>Debugger\WebSocket</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ELF\ElfReader.h">
@@ -1361,6 +1364,9 @@
<ClInclude Include="HLE\sceUsbAcc.h">
<Filter>HLE\Libraries</Filter>
</ClInclude>
<ClInclude Include="Debugger\WebSocket\GPURecordSubscriber.h">
<Filter>Debugger\WebSocket</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />
+21 -23
View File
@@ -53,24 +53,20 @@
#include "Core/Debugger/WebSocket/DisasmSubscriber.h"
#include "Core/Debugger/WebSocket/GameSubscriber.h"
#include "Core/Debugger/WebSocket/GPUBufferSubscriber.h"
#include "Core/Debugger/WebSocket/GPURecordSubscriber.h"
#include "Core/Debugger/WebSocket/HLESubscriber.h"
#include "Core/Debugger/WebSocket/SteppingSubscriber.h"
typedef void *(*SubscriberInit)(DebuggerEventHandlerMap &map);
typedef void (*Subscribershutdown)(void *p);
struct SubscriberInfo {
SubscriberInit init;
Subscribershutdown shutdown;
};
static const std::vector<SubscriberInfo> subscribers({
{ &WebSocketBreakpointInit, nullptr },
{ &WebSocketCPUCoreInit, nullptr },
{ &WebSocketDisasmInit, &WebSocketDisasmShutdown },
{ &WebSocketGameInit, nullptr },
{ &WebSocketGPUBufferInit, nullptr },
{ &WebSocketHLEInit, nullptr },
{ &WebSocketSteppingInit, &WebSocketSteppingShutdown },
typedef DebuggerSubscriber *(*SubscriberInit)(DebuggerEventHandlerMap &map);
static const std::vector<SubscriberInit> subscribers({
&WebSocketBreakpointInit,
&WebSocketCPUCoreInit,
&WebSocketDisasmInit,
&WebSocketGameInit,
&WebSocketGPUBufferInit,
&WebSocketGPURecordInit,
&WebSocketHLEInit,
&WebSocketSteppingInit,
});
// To handle webserver restart, keep track of how many running.
@@ -132,10 +128,10 @@ void HandleDebuggerRequest(const http::Request &request) {
SteppingBroadcaster stepping;
std::unordered_map<std::string, DebuggerEventHandler> eventHandlers;
std::vector<void *> subscriberData;
for (auto info : subscribers) {
std::vector<DebuggerSubscriber *> subscriberData;
for (auto init : subscribers) {
std::lock_guard<std::mutex> guard(lifecycleLock);
subscriberData.push_back(info.init(eventHandlers));
subscriberData.push_back(init(eventHandlers));
}
// There's a tradeoff between responsiveness to incoming events, and polling for changes.
@@ -178,6 +174,12 @@ void HandleDebuggerRequest(const http::Request &request) {
game.Broadcast(ws);
stepping.Broadcast(ws);
for (size_t i = 0; i < subscribers.size(); ++i) {
if (subscriberData[i]) {
subscriberData[i]->Broadcast(ws);
}
}
if (stopRequested) {
ws->Close(net::WebSocketClose::GOING_AWAY);
}
@@ -188,11 +190,7 @@ void HandleDebuggerRequest(const http::Request &request) {
std::lock_guard<std::mutex> guard(lifecycleLock);
for (size_t i = 0; i < subscribers.size(); ++i) {
if (subscribers[i].shutdown) {
subscribers[i].shutdown(subscriberData[i]);
} else {
assert(!subscriberData[i]);
}
delete subscriberData[i];
}
delete ws;
@@ -23,7 +23,7 @@
#include "Core/Debugger/WebSocket/WebSocketUtils.h"
#include "Core/MIPS/MIPSDebugInterface.h"
void *WebSocketBreakpointInit(DebuggerEventHandlerMap &map) {
DebuggerSubscriber *WebSocketBreakpointInit(DebuggerEventHandlerMap &map) {
// No need to bind or alloc state, these are all global.
map["cpu.breakpoint.add"] = &WebSocketCPUBreakpointAdd;
map["cpu.breakpoint.update"] = &WebSocketCPUBreakpointUpdate;
@@ -19,7 +19,7 @@
#include "Core/Debugger/WebSocket/WebSocketUtils.h"
void *WebSocketBreakpointInit(DebuggerEventHandlerMap &map);
DebuggerSubscriber *WebSocketBreakpointInit(DebuggerEventHandlerMap &map);
void WebSocketCPUBreakpointAdd(DebuggerRequest &req);
void WebSocketCPUBreakpointUpdate(DebuggerRequest &req);
@@ -25,7 +25,7 @@
#include "Core/MIPS/MIPS.h"
#include "Core/MIPS/MIPSDebugInterface.h"
void *WebSocketCPUCoreInit(DebuggerEventHandlerMap &map) {
DebuggerSubscriber *WebSocketCPUCoreInit(DebuggerEventHandlerMap &map) {
// No need to bind or alloc state, these are all global.
map["cpu.stepping"] = &WebSocketCPUStepping;
map["cpu.resume"] = &WebSocketCPUResume;
+1 -1
View File
@@ -19,7 +19,7 @@
#include "Core/Debugger/WebSocket/WebSocketUtils.h"
void *WebSocketCPUCoreInit(DebuggerEventHandlerMap &map);
DebuggerSubscriber *WebSocketCPUCoreInit(DebuggerEventHandlerMap &map);
void WebSocketCPUStepping(DebuggerRequest &req);
void WebSocketCPUResume(DebuggerRequest &req);
+4 -7
View File
@@ -28,11 +28,12 @@
#include "Core/MIPS/MIPSAsm.h"
#include "Core/MIPS/MIPSDebugInterface.h"
struct WebSocketDisasmState {
class WebSocketDisasmState : public DebuggerSubscriber {
public:
WebSocketDisasmState() {
disasm_.setCpu(currentDebugMIPS);
}
~WebSocketDisasmState() {
~WebSocketDisasmState() override {
disasm_.clear();
}
@@ -49,7 +50,7 @@ protected:
DisassemblyManager disasm_;
};
void *WebSocketDisasmInit(DebuggerEventHandlerMap &map) {
DebuggerSubscriber *WebSocketDisasmInit(DebuggerEventHandlerMap &map) {
auto p = new WebSocketDisasmState();
map["memory.base"] = std::bind(&WebSocketDisasmState::Base, p, std::placeholders::_1);
map["memory.disasm"] = std::bind(&WebSocketDisasmState::Disasm, p, std::placeholders::_1);
@@ -59,10 +60,6 @@ void *WebSocketDisasmInit(DebuggerEventHandlerMap &map) {
return p;
}
void WebSocketDisasmShutdown(void *p) {
delete static_cast<WebSocketDisasmState *>(p);
}
static DebugInterface *CPUFromRequest(DebuggerRequest &req) {
if (!req.HasParam("thread"))
return currentDebugMIPS;
+1 -2
View File
@@ -19,5 +19,4 @@
#include "Core/Debugger/WebSocket/WebSocketUtils.h"
void *WebSocketDisasmInit(DebuggerEventHandlerMap &map);
void WebSocketDisasmShutdown(void *p);
DebuggerSubscriber *WebSocketDisasmInit(DebuggerEventHandlerMap &map);
@@ -28,7 +28,7 @@
#include "Core/Screenshot.h"
#include "GPU/Debugger/Stepping.h"
void *WebSocketGPUBufferInit(DebuggerEventHandlerMap &map) {
DebuggerSubscriber *WebSocketGPUBufferInit(DebuggerEventHandlerMap &map) {
// No need to bind or alloc state, these are all global.
map["gpu.buffer.screenshot"] = &WebSocketGPUBufferScreenshot;
map["gpu.buffer.renderColor"] = &WebSocketGPUBufferRenderColor;
@@ -19,7 +19,7 @@
#include "Core/Debugger/WebSocket/WebSocketUtils.h"
void *WebSocketGPUBufferInit(DebuggerEventHandlerMap &map);
DebuggerSubscriber *WebSocketGPUBufferInit(DebuggerEventHandlerMap &map);
void WebSocketGPUBufferScreenshot(DebuggerRequest &req);
void WebSocketGPUBufferRenderColor(DebuggerRequest &req);
@@ -0,0 +1,107 @@
// Copyright (c) 2018- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "data/base64.h"
#include "Common/FileUtil.h"
#include "Core/Debugger/WebSocket/GPURecordSubscriber.h"
#include "Core/Debugger/WebSocket/WebSocketUtils.h"
#include "Core/System.h"
#include "GPU/Debugger/Record.h"
struct WebSocketGPURecordState : public DebuggerSubscriber {
~WebSocketGPURecordState() override;
void Dump(DebuggerRequest &req);
void Broadcast(net::WebSocketServer *ws) override;
protected:
bool pending_ = false;
std::string lastTicket_;
std::string lastFilename_;
};
DebuggerSubscriber *WebSocketGPURecordInit(DebuggerEventHandlerMap &map) {
auto p = new WebSocketGPURecordState();
map["gpu.record.dump"] = std::bind(&WebSocketGPURecordState::Dump, p, std::placeholders::_1);
return p;
}
WebSocketGPURecordState::~WebSocketGPURecordState() {
// Clear the callback to hopefully avoid a crash.
if (pending_)
GPURecord::SetCallback(nullptr);
}
// Begin recording (gpu.record.dump)
//
// No parameters.
//
// Response (same event name):
// - uri: data: URI containing debug dump data.
//
// Note: recording may take a moment.
void WebSocketGPURecordState::Dump(DebuggerRequest &req) {
if (!PSP_IsInited())
return req.Fail("CPU not started");
if (!GPURecord::Activate())
return req.Fail("Recording already in progress");
pending_ = true;
GPURecord::SetCallback([=](const std::string &filename) {
lastFilename_ = filename;
pending_ = false;
});
const JsonNode *value = req.data.get("ticket");
lastTicket_ = value ? json_stringify(value) : "";
}
// This handles the asynchronous gpu.record.dump response.
void WebSocketGPURecordState::Broadcast(net::WebSocketServer *ws) {
if (!lastFilename_.empty()) {
FILE *fp = File::OpenCFile(lastFilename_, "rb");
if (!fp) {
lastFilename_.clear();
return;
}
// We write directly to the stream since this is a large chunk of data.
ws->AddFragment(false, R"({"event":"gpu.record.dump")");
if (!lastTicket_.empty()) {
ws->AddFragment(false, R"(,"ticket":)");
ws->AddFragment(false, lastTicket_);
}
ws->AddFragment(false, R"(,"uri":"data:application/octet-stream;base64,)");
// Divisible by 3 for base64 reasons.
const size_t BUF_SIZE = 16383;
std::vector<uint8_t> buf;
buf.resize(BUF_SIZE);
while (!feof(fp)) {
size_t bytes = fread(&buf[0], 1, BUF_SIZE, fp);
ws->AddFragment(false, Base64Encode(&buf[0], bytes));
}
fclose(fp);
ws->AddFragment(true, R"("})");
lastFilename_.clear();
lastTicket_.clear();
}
}
@@ -0,0 +1,22 @@
// Copyright (c) 2018- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include "Core/Debugger/WebSocket/WebSocketUtils.h"
DebuggerSubscriber *WebSocketGPURecordInit(DebuggerEventHandlerMap &map);
+1 -1
View File
@@ -20,7 +20,7 @@
#include "Core/ELF/ParamSFO.h"
#include "Core/System.h"
void *WebSocketGameInit(DebuggerEventHandlerMap &map) {
DebuggerSubscriber *WebSocketGameInit(DebuggerEventHandlerMap &map) {
map["game.status"] = &WebSocketGameStatus;
map["version"] = &WebSocketVersion;
+1 -1
View File
@@ -19,7 +19,7 @@
#include "Core/Debugger/WebSocket/WebSocketUtils.h"
void *WebSocketGameInit(DebuggerEventHandlerMap &map);
DebuggerSubscriber *WebSocketGameInit(DebuggerEventHandlerMap &map);
void WebSocketGameStatus(DebuggerRequest &req);
void WebSocketVersion(DebuggerRequest &req);
+1 -1
View File
@@ -27,7 +27,7 @@
#include "Core/MIPS/MIPSStackWalk.h"
#include "Core/HLE/sceKernelThread.h"
void *WebSocketHLEInit(DebuggerEventHandlerMap &map) {
DebuggerSubscriber *WebSocketHLEInit(DebuggerEventHandlerMap &map) {
map["hle.thread.list"] = &WebSocketHLEThreadList;
map["hle.thread.wake"] = &WebSocketHLEThreadWake;
map["hle.thread.stop"] = &WebSocketHLEThreadStop;
+1 -1
View File
@@ -19,7 +19,7 @@
#include "Core/Debugger/WebSocket/WebSocketUtils.h"
void *WebSocketHLEInit(DebuggerEventHandlerMap &map);
DebuggerSubscriber *WebSocketHLEInit(DebuggerEventHandlerMap &map);
void WebSocketHLEThreadList(DebuggerRequest &req);
void WebSocketHLEThreadWake(DebuggerRequest &req);
@@ -28,11 +28,11 @@
using namespace MIPSAnalyst;
struct WebSocketSteppingState {
struct WebSocketSteppingState : public DebuggerSubscriber {
WebSocketSteppingState() {
disasm_.setCpu(currentDebugMIPS);
}
~WebSocketSteppingState() {
~WebSocketSteppingState() override {
disasm_.clear();
}
@@ -51,7 +51,7 @@ protected:
DisassemblyManager disasm_;
};
void *WebSocketSteppingInit(DebuggerEventHandlerMap &map) {
DebuggerSubscriber *WebSocketSteppingInit(DebuggerEventHandlerMap &map) {
auto p = new WebSocketSteppingState();
map["cpu.stepInto"] = std::bind(&WebSocketSteppingState::Into, p, std::placeholders::_1);
map["cpu.stepOver"] = std::bind(&WebSocketSteppingState::Over, p, std::placeholders::_1);
@@ -62,10 +62,6 @@ void *WebSocketSteppingInit(DebuggerEventHandlerMap &map) {
return p;
}
void WebSocketSteppingShutdown(void *p) {
delete static_cast<WebSocketSteppingState *>(p);
}
static DebugInterface *CPUFromRequest(DebuggerRequest &req, uint32_t *threadID = nullptr) {
if (!req.HasParam("thread")) {
if (threadID)
+1 -2
View File
@@ -19,5 +19,4 @@
#include "Core/Debugger/WebSocket/WebSocketUtils.h"
void *WebSocketSteppingInit(DebuggerEventHandlerMap &map);
void WebSocketSteppingShutdown(void *p);
DebuggerSubscriber *WebSocketSteppingInit(DebuggerEventHandlerMap &map);
+8
View File
@@ -98,5 +98,13 @@ private:
bool responsePartial_ = false;
};
class DebuggerSubscriber {
public:
virtual ~DebuggerSubscriber() {}
// Subscribers can also broadcast if they have simple cases to.
virtual void Broadcast(net::WebSocketServer *ws) {}
};
typedef std::function<void(DebuggerRequest &req)> DebuggerEventHandler;
typedef std::unordered_map<std::string, DebuggerEventHandler> DebuggerEventHandlerMap;
+12 -12
View File
@@ -362,13 +362,13 @@ void PSPSaveDialog::DisplaySaveList(bool canMove) {
}
}
void PSPSaveDialog::DisplaySaveIcon()
void PSPSaveDialog::DisplaySaveIcon(bool checkExists)
{
std::lock_guard<std::mutex> guard(paramLock);
int textureColor = CalcFadedColor(0xFFFFFFFF);
auto curSave = param.GetFileInfo(currentSelectedSave);
if (curSave.size == 0)
if (curSave.size == 0 && checkExists)
textureColor = CalcFadedColor(0xFF777777);
// Calc save image position on screen
@@ -652,7 +652,7 @@ int PSPSaveDialog::Update(int animSpeed)
case DS_SAVE_CONFIRM:
StartDraw();
DisplaySaveIcon();
DisplaySaveIcon(false);
DisplaySaveDataInfo2(true);
DisplayMessage(di->T("Confirm Save", "Do you want to save this data?"), true);
@@ -673,7 +673,7 @@ int PSPSaveDialog::Update(int animSpeed)
case DS_SAVE_CONFIRM_OVERWRITE:
StartDraw();
DisplaySaveIcon();
DisplaySaveIcon(true);
DisplaySaveDataInfo2();
DisplayMessage(di->T("Confirm Overwrite","Do you want to overwrite the data?"), true);
@@ -702,7 +702,7 @@ int PSPSaveDialog::Update(int animSpeed)
StartDraw();
DisplaySaveIcon();
DisplaySaveIcon(true);
DisplaySaveDataInfo2(true);
DisplayMessage(di->T("Saving","Saving\nPlease Wait..."));
@@ -715,7 +715,7 @@ int PSPSaveDialog::Update(int animSpeed)
JoinIOThread();
StartDraw();
DisplaySaveIcon();
DisplaySaveIcon(true);
DisplaySaveDataInfo2(true);
DisplayMessage(di->T("SavingFailed", "Unable to save data."));
@@ -742,7 +742,7 @@ int PSPSaveDialog::Update(int animSpeed)
}
StartDraw();
DisplaySaveIcon();
DisplaySaveIcon(true);
DisplaySaveDataInfo2(true);
DisplayMessage(di->T("Save completed"));
@@ -782,7 +782,7 @@ int PSPSaveDialog::Update(int animSpeed)
case DS_LOAD_CONFIRM:
StartDraw();
DisplaySaveIcon();
DisplaySaveIcon(true);
DisplaySaveDataInfo2();
DisplayMessage(di->T("ConfirmLoad", "Load this data?"), true);
@@ -807,7 +807,7 @@ int PSPSaveDialog::Update(int animSpeed)
StartDraw();
DisplaySaveIcon();
DisplaySaveIcon(true);
DisplaySaveDataInfo2();
DisplayMessage(di->T("Loading","Loading\nPlease Wait..."));
@@ -820,7 +820,7 @@ int PSPSaveDialog::Update(int animSpeed)
JoinIOThread();
StartDraw();
DisplaySaveIcon();
DisplaySaveIcon(true);
DisplaySaveDataInfo2();
DisplayMessage(di->T("LoadingFailed", "Unable to load data."));
@@ -844,7 +844,7 @@ int PSPSaveDialog::Update(int animSpeed)
JoinIOThread();
StartDraw();
DisplaySaveIcon();
DisplaySaveIcon(true);
DisplaySaveDataInfo2();
DisplayMessage(di->T("Load completed"));
@@ -902,7 +902,7 @@ int PSPSaveDialog::Update(int animSpeed)
case DS_DELETE_CONFIRM:
StartDraw();
DisplaySaveIcon();
DisplaySaveIcon(true);
DisplaySaveDataInfo2();
DisplayMessage(di->T("DeleteConfirm",
+1 -1
View File
@@ -90,7 +90,7 @@ private:
void DisplayBanner(int which);
void DisplaySaveList(bool canMove = true);
void DisplaySaveIcon();
void DisplaySaveIcon(bool checkExists);
void DisplaySaveDataInfo1();
void DisplaySaveDataInfo2(bool showNewData = false);
void DisplayMessage(std::string text, bool hasYesNo = false);
+2 -1
View File
@@ -55,6 +55,7 @@
#include "GPU/GPUInterface.h"
#include "GPU/Common/FramebufferCommon.h"
#include "GPU/Common/PostShader.h"
#include "GPU/Debugger/Record.h"
struct FrameBufferState {
u32 topaddr;
@@ -737,7 +738,7 @@ void __DisplayFlip(int cyclesLate) {
// 4 here means 1 drawn, 4 skipped - so 12 fps minimum.
maxFrameskip = g_Config.iFrameSkip;
}
if (numSkippedFrames >= maxFrameskip) {
if (numSkippedFrames >= maxFrameskip || GPURecord::IsActivePending()) {
skipFrame = false;
}
+13 -12
View File
@@ -299,7 +299,8 @@ static u32 getMpegVersion(u32 mpegRawVersion) {
default: return -1;
}
}
static void AnalyzeMpeg(u8 *buffer, MpegContext *ctx) {
static void AnalyzeMpeg(u8 *buffer, u32 validSize, MpegContext *ctx) {
ctx->mpegMagic = *(u32_le*)buffer;
ctx->mpegRawVersion = *(u32_le*)(buffer + PSMF_STREAM_VERSION_OFFSET);
ctx->mpegVersion = getMpegVersion(ctx->mpegRawVersion);
@@ -329,7 +330,7 @@ static void AnalyzeMpeg(u8 *buffer, MpegContext *ctx) {
return;
}
if (ctx->mediaengine && (ctx->mpegStreamSize > 0) && !ctx->isAnalyzed) {
if (!ctx->isAnalyzed && ctx->mediaengine && ctx->mpegStreamSize > 0 && validSize >= ctx->mpegOffset) {
// init mediaEngine
auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ctx->mpegRingbufferAddr);
if (ringbuffer.IsValid()) {
@@ -338,16 +339,16 @@ static void AnalyzeMpeg(u8 *buffer, MpegContext *ctx) {
// TODO: Does this make any sense?
ctx->mediaengine->loadStream(buffer, ctx->mpegOffset, 0);
}
// When used with scePsmf, some applications attempt to use sceMpegQueryStreamOffset
// and sceMpegQueryStreamSize, which forces a packet overwrite in the Media Engine and in
// the MPEG ringbuffer.
// Mark the current MPEG as analyzed to filter this, and restore it at sceMpegFinish.
ctx->isAnalyzed = true;
}
// When used with scePsmf, some applications attempt to use sceMpegQueryStreamOffset
// and sceMpegQueryStreamSize, which forces a packet overwrite in the Media Engine and in
// the MPEG ringbuffer.
// Mark the current MPEG as analyzed to filter this, and restore it at sceMpegFinish.
ctx->isAnalyzed = true;
// copy header struct to mpeg header.
memcpy(ctx->mpegheader, buffer, 2048);
memcpy(ctx->mpegheader, buffer, validSize >= 2048 ? 2048 : validSize);
*(u32_le*)(ctx->mpegheader + PSMF_STREAM_OFFSET_OFFSET) = 0x80000;
INFO_LOG(ME, "Stream offset: %d, Stream size: 0x%X", ctx->mpegOffset, ctx->mpegStreamSize);
@@ -601,7 +602,7 @@ static int sceMpegQueryStreamOffset(u32 mpeg, u32 bufferAddr, u32 offsetAddr)
DEBUG_LOG(ME, "sceMpegQueryStreamOffset(%08x, %08x, %08x)", mpeg, bufferAddr, offsetAddr);
// Kinda destructive, no?
AnalyzeMpeg(Memory::GetPointer(bufferAddr), ctx);
AnalyzeMpeg(Memory::GetPointer(bufferAddr), Memory::ValidSize(bufferAddr, 32768), ctx);
if (ctx->mpegMagic != PSMF_MAGIC) {
ERROR_LOG(ME, "sceMpegQueryStreamOffset: Bad PSMF magic");
@@ -633,7 +634,7 @@ static u32 sceMpegQueryStreamSize(u32 bufferAddr, u32 sizeAddr)
MpegContext ctx;
ctx.mediaengine = 0;
AnalyzeMpeg(Memory::GetPointer(bufferAddr), &ctx);
AnalyzeMpeg(Memory::GetPointer(bufferAddr), Memory::ValidSize(bufferAddr, 32768), &ctx);
if (ctx.mpegMagic != PSMF_MAGIC) {
ERROR_LOG(ME, "sceMpegQueryStreamSize: Bad PSMF magic");
@@ -1465,7 +1466,7 @@ void PostPutAction::run(MipsCall &call) {
if (ringbuffer->packetsRead == 0 && ctx->mediaengine && packetsAdded > 0) {
// init mediaEngine
AnalyzeMpeg(ctx->mpegheader, ctx);
AnalyzeMpeg(ctx->mpegheader, 2048, ctx);
ctx->mediaengine->loadStream(ctx->mpegheader, 2048, ringbuffer->packets * ringbuffer->packetSize);
}
if (packetsAdded > 0) {
-7
View File
@@ -50,13 +50,6 @@ public:
virtual void SaveSymbolMap() {}
virtual void SetWindowTitle(const char *message) {}
// While debugging is active, it's perfectly fine for these to block.
virtual bool GPUDebuggingActive() { return false; }
virtual void GPUNotifyCommand(u32 pc) {}
virtual void GPUNotifyDisplay(u32 framebuf, u32 stride, int format) {}
virtual void GPUNotifyDraw() {}
virtual void GPUNotifyTextureAttachment(u32 addr) {}
virtual bool CanCreateShortcut() {return false;}
virtual bool CreateDesktopShortcut(std::string argumentPath, std::string title) {return false;}
+3 -8
View File
@@ -411,13 +411,8 @@ namespace SaveState
}
fullDiscId = StringFromFormat("%s_%s", discId.c_str(), discVer.c_str());
std::string temp = StringFromFormat("ms0:/PSP/PPSSPP_STATE/%s_%d.%s", fullDiscId.c_str(), slot, extension);
std::string hostPath;
if (pspFileSystem.GetHostPath(temp, hostPath)) {
return hostPath;
} else {
return "";
}
std::string filename = StringFromFormat("%s_%d.%s", fullDiscId.c_str(), slot, extension);
return GetSysDirectory(DIRECTORY_SAVESTATE) + filename;
}
int GetCurrentSlot()
@@ -883,7 +878,7 @@ namespace SaveState
void Init()
{
// Make sure there's a directory for save slots
pspFileSystem.MkDir("ms0:/PSP/PPSSPP_STATE");
File::CreateFullPath(GetSysDirectory(DIRECTORY_SAVESTATE));
std::lock_guard<std::mutex> guard(mutex);
rewindStates.Clear();
+3 -3
View File
@@ -596,9 +596,9 @@ void InitSysDirectories() {
// expect a standard environment. Skipping THEME though, that's pointless.
File::CreateDir(g_Config.memStickDirectory + "PSP");
File::CreateDir(g_Config.memStickDirectory + "PSP/COMMON");
File::CreateDir(g_Config.memStickDirectory + "PSP/GAME");
File::CreateDir(g_Config.memStickDirectory + "PSP/SAVEDATA");
File::CreateDir(g_Config.memStickDirectory + "PSP/PPSSPP_STATE");
File::CreateDir(GetSysDirectory(DIRECTORY_GAME));
File::CreateDir(GetSysDirectory(DIRECTORY_SAVEDATA));
File::CreateDir(GetSysDirectory(DIRECTORY_SAVESTATE));
if (g_Config.currentDirectory.empty()) {
g_Config.currentDirectory = GetSysDirectory(DIRECTORY_GAME);
+12 -15
View File
@@ -58,6 +58,7 @@ void TextureReplacer::NotifyConfigChanged() {
// If we're saving, auto-create the directory.
if (g_Config.bSaveNewTextures && !File::Exists(basePath_ + NEW_TEXTURE_DIR)) {
File::CreateFullPath(basePath_ + NEW_TEXTURE_DIR);
File::CreateEmptyFile(basePath_ + NEW_TEXTURE_DIR + "/.nomedia");
}
enabled_ = File::Exists(basePath_) && File::IsDirectory(basePath_);
@@ -111,29 +112,24 @@ bool TextureReplacer::LoadIni() {
ERROR_LOG(G3D, "Unsupported texture replacement version %d, trying anyway", version);
}
std::vector<std::string> hashNames;
if (ini.GetKeys("hashes", hashNames)) {
auto hashes = ini.GetOrCreateSection("hashes");
if (ini.HasSection("hashes")) {
auto hashes = ini.GetOrCreateSection("hashes")->ToMap();
// Format: hashname = filename.png
for (std::string hashName : hashNames) {
for (const auto &item : hashes) {
ReplacementAliasKey key(0, 0, 0);
if (sscanf(hashName.c_str(), "%16llx%8x_%d", &key.cachekey, &key.hash, &key.level) >= 1) {
hashes->Get(hashName.c_str(), &aliases_[key], "");
if (sscanf(item.first.c_str(), "%16llx%8x_%d", &key.cachekey, &key.hash, &key.level) >= 1) {
aliases_[key] = item.second;
} else {
ERROR_LOG(G3D, "Unsupported syntax under [hashes]: %s", hashName.c_str());
ERROR_LOG(G3D, "Unsupported syntax under [hashes]: %s", item.first.c_str());
}
}
}
std::vector<std::string> hashrangeKeys;
if (ini.GetKeys("hashranges", hashrangeKeys)) {
auto hashranges = ini.GetOrCreateSection("hashranges");
if (ini.HasSection("hashranges")) {
auto hashranges = ini.GetOrCreateSection("hashranges")->ToMap();
// Format: addr,w,h = newW,newH
for (const std::string &key : hashrangeKeys) {
std::string value;
if (hashranges->Get(key.c_str(), &value, "")) {
ParseHashRange(key, value);
}
for (const auto &item : hashranges) {
ParseHashRange(item.first, item.second);
}
}
}
@@ -400,6 +396,7 @@ void TextureReplacer::NotifyTextureDecoded(const ReplacedTextureDecodeInfo &repl
const std::string saveDirectory = basePath_ + NEW_TEXTURE_DIR + hashfile.substr(0, slash);
if (!File::Exists(saveDirectory)) {
File::CreateFullPath(saveDirectory);
File::CreateEmptyFile(saveDirectory + "/.nomedia");
}
}
+2 -2
View File
@@ -110,12 +110,12 @@ void ConvertS16ToF32(float *out, const s16 *in, size_t size) {
}
}
#ifndef _M_SSE
#if !defined(_M_SSE) && !PPSSPP_ARCH(ARM64)
AdjustVolumeBlockFunc AdjustVolumeBlock = &AdjustVolumeBlockStandard;
// This has to be done after CPUDetect has done its magic.
void SetupAudioFormats() {
#if PPSSPP_ARCH(ARMV7) && PPSSPP_ARCH(ARM_NEON)
#if PPSSPP_ARCH(ARM_NEON) && !PPSSPP_ARCH(ARM64)
if (cpu_info.bNEON) {
AdjustVolumeBlock = &AdjustVolumeBlockNEON;
}
+3
View File
@@ -20,6 +20,7 @@
#include "ppsspp_config.h"
#include "Common/Common.h"
#include "Common/CommonTypes.h"
#include "Core/Util/AudioFormatNEON.h"
#define IS_LITTLE_ENDIAN (*(const u16 *)"\0\xff" >= 0x100)
@@ -71,6 +72,8 @@ void ConvertS16ToF32(float *ou, const s16 *in, size_t size);
#ifdef _M_SSE
#define AdjustVolumeBlock AdjustVolumeBlockStandard
#elif PPSSPP_ARCH(ARM64)
#define AdjustVolumeBlock AdjustVolumeBlockNEON
#else
typedef void (*AdjustVolumeBlockFunc)(s16 *out, s16 *in, size_t size, int leftVol, int rightVol);
extern AdjustVolumeBlockFunc AdjustVolumeBlock;
+1 -1
View File
@@ -23,7 +23,7 @@
#include "Core/Util/AudioFormat.h"
#include "Core/Util/AudioFormatNEON.h"
#if !defined(ARM) && !defined(ARM64)
#if !PPSSPP_ARCH(ARM) && !PPSSPP_ARCH(ARM64)
#error Should not be compiled on non-ARM.
#endif
+27 -4
View File
@@ -21,7 +21,6 @@
#include "Common/MemoryUtil.h"
#include "Common/StringUtils.h"
#include "Core/Config.h"
#include "Core/Host.h"
#include "Core/Reporting.h"
#include "Core/System.h"
#include "GPU/Common/FramebufferCommon.h"
@@ -29,6 +28,7 @@
#include "GPU/Common/TextureDecoder.h"
#include "GPU/Common/ShaderId.h"
#include "GPU/Common/GPUStateUtils.h"
#include "GPU/Debugger/Debugger.h"
#include "GPU/GPUState.h"
#include "GPU/GPUInterface.h"
@@ -262,6 +262,19 @@ void TextureCacheCommon::UpdateSamplingParams(TexCacheEntry &entry, SamplerCache
void TextureCacheCommon::UpdateMaxSeenV(TexCacheEntry *entry, bool throughMode) {
// If the texture is >= 512 pixels tall...
if (entry->dim >= 0x900) {
if (entry->cluthash != 0 && entry->maxSeenV == 0) {
const u64 cachekeyMin = (u64)(entry->addr & 0x3FFFFFFF) << 32;
const u64 cachekeyMax = cachekeyMin + (1ULL << 32);
for (auto it = cache_.lower_bound(cachekeyMin), end = cache_.upper_bound(cachekeyMax); it != end; ++it) {
// They should all be the same, just make sure we take any that has already increased.
// This is for a new texture.
if (it->second->maxSeenV != 0) {
entry->maxSeenV = it->second->maxSeenV;
break;
}
}
}
// Texture scale/offset and gen modes don't apply in through.
// So we can optimize how much of the texture we look at.
if (throughMode) {
@@ -279,6 +292,16 @@ void TextureCacheCommon::UpdateMaxSeenV(TexCacheEntry *entry, bool throughMode)
// TODO: We could tell for texcoord UV gen, and apply scale to max?
entry->maxSeenV = 512;
}
// We need to keep all CLUT variants in sync so we detect changes properly.
// See HandleTextureChange / STATUS_CLUT_RECHECK.
if (entry->cluthash != 0) {
const u64 cachekeyMin = (u64)(entry->addr & 0x3FFFFFFF) << 32;
const u64 cachekeyMax = cachekeyMin + (1ULL << 32);
for (auto it = cache_.lower_bound(cachekeyMin), end = cache_.upper_bound(cachekeyMax); it != end; ++it) {
it->second->maxSeenV = entry->maxSeenV;
}
}
}
}
@@ -692,7 +715,7 @@ void TextureCacheCommon::AttachFramebufferValid(TexCacheEntry *entry, VirtualFra
entry->maxLevel = 0;
fbTexInfo_[cachekey] = fbInfo;
framebuffer->last_frame_attached = gpuStats.numFlips;
host->GPUNotifyTextureAttachment(entry->addr);
GPUDebug::NotifyTextureAttachment(entry->addr);
} else if (entry->framebuffer == framebuffer) {
framebuffer->last_frame_attached = gpuStats.numFlips;
}
@@ -711,7 +734,7 @@ void TextureCacheCommon::AttachFramebufferInvalid(TexCacheEntry *entry, VirtualF
entry->status &= ~TexCacheEntry::STATUS_DEPALETTIZE;
entry->maxLevel = 0;
fbTexInfo_[cachekey] = fbInfo;
host->GPUNotifyTextureAttachment(entry->addr);
GPUDebug::NotifyTextureAttachment(entry->addr);
}
}
@@ -724,7 +747,7 @@ void TextureCacheCommon::DetachFramebuffer(TexCacheEntry *entry, u32 address, Vi
// Otherwise we never recreate the texture.
entry->hash ^= 1;
fbTexInfo_.erase(cachekey);
host->GPUNotifyTextureAttachment(entry->addr);
GPUDebug::NotifyTextureAttachment(entry->addr);
}
}
+169 -117
View File
@@ -203,51 +203,54 @@ void DoSwizzleTex16(const u32 *ysrcp, u8 *texptr, int bxc, int byc, u32 pitch) {
// ysrcp is in 32-bits, so this is convenient.
const u32 pitchBy32 = pitch >> 2;
#ifdef _M_SSE
__m128i *dest = (__m128i *)texptr;
// The pitch parameter is in bytes, so shift down for 128-bit.
// Note: it's always aligned to 16 bytes, so this is safe.
const u32 pitchBy128 = pitch >> 4;
for (int by = 0; by < byc; by++) {
const __m128i *xsrc = (const __m128i *)ysrcp;
for (int bx = 0; bx < bxc; bx++) {
const __m128i *src = xsrc;
for (int n = 0; n < 2; n++) {
// Textures are always 16-byte aligned so this is fine.
__m128i temp1 = _mm_load_si128(src);
src += pitchBy128;
__m128i temp2 = _mm_load_si128(src);
src += pitchBy128;
__m128i temp3 = _mm_load_si128(src);
src += pitchBy128;
__m128i temp4 = _mm_load_si128(src);
src += pitchBy128;
if (((uintptr_t)ysrcp & 0xF) == 0 && (pitch & 0xF) == 0) {
__m128i *dest = (__m128i *)texptr;
// The pitch parameter is in bytes, so shift down for 128-bit.
// Note: it's always aligned to 16 bytes, so this is safe.
const u32 pitchBy128 = pitch >> 4;
for (int by = 0; by < byc; by++) {
const __m128i *xsrc = (const __m128i *)ysrcp;
for (int bx = 0; bx < bxc; bx++) {
const __m128i *src = xsrc;
for (int n = 0; n < 2; n++) {
// Textures are always 16-byte aligned so this is fine.
__m128i temp1 = _mm_load_si128(src);
src += pitchBy128;
__m128i temp2 = _mm_load_si128(src);
src += pitchBy128;
__m128i temp3 = _mm_load_si128(src);
src += pitchBy128;
__m128i temp4 = _mm_load_si128(src);
src += pitchBy128;
_mm_store_si128(dest, temp1);
_mm_store_si128(dest + 1, temp2);
_mm_store_si128(dest + 2, temp3);
_mm_store_si128(dest + 3, temp4);
dest += 4;
_mm_store_si128(dest, temp1);
_mm_store_si128(dest + 1, temp2);
_mm_store_si128(dest + 2, temp3);
_mm_store_si128(dest + 3, temp4);
dest += 4;
}
xsrc++;
}
xsrc++;
ysrcp += pitchBy32 * 8;
}
ysrcp += pitchBy32 * 8;
}
#else
u32 *dest = (u32 *)texptr;
for (int by = 0; by < byc; by++) {
const u32 *xsrc = ysrcp;
for (int bx = 0; bx < bxc; bx++) {
const u32 *src = xsrc;
for (int n = 0; n < 8; n++) {
memcpy(dest, src, 16);
src += pitchBy32;
dest += 4;
}
xsrc += 4;
}
ysrcp += pitchBy32 * 8;
}
} else
#endif
{
u32 *dest = (u32 *)texptr;
for (int by = 0; by < byc; by++) {
const u32 *xsrc = ysrcp;
for (int bx = 0; bx < bxc; bx++) {
const u32 *src = xsrc;
for (int n = 0; n < 8; n++) {
memcpy(dest, src, 16);
src += pitchBy32;
dest += 4;
}
xsrc += 4;
}
ysrcp += pitchBy32 * 8;
}
}
}
void DoUnswizzleTex16Basic(const u8 *texptr, u32 *ydestp, int bxc, int byc, u32 pitch) {
@@ -255,7 +258,7 @@ void DoUnswizzleTex16Basic(const u8 *texptr, u32 *ydestp, int bxc, int byc, u32
const u32 pitchBy32 = pitch >> 2;
#ifdef _M_SSE
if (((uintptr_t)ydestp & 0xF) == 0) {
if (((uintptr_t)ydestp & 0xF) == 0 && (pitch & 0xF) == 0) {
const __m128i *src = (const __m128i *)texptr;
// The pitch parameter is in bytes, so shift down for 128-bit.
// Note: it's always aligned to 16 bytes, so this is safe.
@@ -327,16 +330,33 @@ void SetupTextureDecoder() {
#endif
}
// S3TC / DXT Decoder
class DXTDecoder {
public:
inline void DecodeColors(const DXT1Block *src, bool ignore1bitAlpha);
inline void DecodeAlphaDXT5(const DXT5Block *src);
inline void WriteColorsDXT1(u32 *dst, const DXT1Block *src, int pitch, int height);
inline void WriteColorsDXT3(u32 *dst, const DXT3Block *src, int pitch, int height);
inline void WriteColorsDXT5(u32 *dst, const DXT5Block *src, int pitch, int height);
protected:
u32 colors_[4];
u8 alpha_[8];
};
static inline u32 makecol(int r, int g, int b, int a) {
return (a << 24) | (r << 16) | (g << 8) | b;
}
static inline int mul_3_8(int c) {
// This is 3/8 * c = 4/8 * c - 1/8 * c.
return (c >> 1) - (c >> 3);
}
// This could probably be done faster by decoding two or four blocks at a time with SSE/NEON.
void DecodeDXT1Block(u32 *dst, const DXT1Block *src, int pitch, int height, bool ignore1bitAlpha) {
// S3TC Decoder
// Needs more speed and debugging.
u16 c1 = (src->color1);
u16 c2 = (src->color2);
void DXTDecoder::DecodeColors(const DXT1Block *src, bool ignore1bitAlpha) {
u16 c1 = src->color1;
u16 c2 = src->color2;
int red1 = Convert5To8(c1 & 0x1F);
int red2 = Convert5To8(c2 & 0x1F);
int green1 = Convert6To8((c1 >> 5) & 0x3F);
@@ -344,89 +364,121 @@ void DecodeDXT1Block(u32 *dst, const DXT1Block *src, int pitch, int height, bool
int blue1 = Convert5To8((c1 >> 11) & 0x1F);
int blue2 = Convert5To8((c2 >> 11) & 0x1F);
u32 colors[4];
colors[0] = makecol(red1, green1, blue1, 255);
colors[1] = makecol(red2, green2, blue2, 255);
// Keep alpha zero for non-DXT1 to skip masking the colors.
int alpha = ignore1bitAlpha ? 0 : 255;
colors_[0] = makecol(red1, green1, blue1, alpha);
colors_[1] = makecol(red2, green2, blue2, alpha);
if (c1 > c2 || ignore1bitAlpha) {
int blue3 = ((blue2 - blue1) >> 1) - ((blue2 - blue1) >> 3);
int green3 = ((green2 - green1) >> 1) - ((green2 - green1) >> 3);
int red3 = ((red2 - red1) >> 1) - ((red2 - red1) >> 3);
colors[2] = makecol(red1 + red3, green1 + green3, blue1 + blue3, 255);
colors[3] = makecol(red2 - red3, green2 - green3, blue2 - blue3, 255);
int red3 = mul_3_8(red2 - red1);
int green3 = mul_3_8(green2 - green1);
int blue3 = mul_3_8(blue2 - blue1);
colors_[2] = makecol(red1 + red3, green1 + green3, blue1 + blue3, alpha);
colors_[3] = makecol(red2 - red3, green2 - green3, blue2 - blue3, alpha);
} else {
colors[2] = makecol((red1 + red2 + 1) / 2, // Average
(green1 + green2 + 1) / 2,
(blue1 + blue2 + 1) / 2, 255);
colors[3] = makecol(red2, green2, blue2, 0); // Color2 but transparent
}
for (int y = 0; y < height; y++) {
int val = src->lines[y];
for (int x = 0; x < 4; x++) {
dst[x] = colors[val & 3];
val >>= 2;
}
dst += pitch;
}
}
void DecodeDXT3Block(u32 *dst, const DXT3Block *src, int pitch, int height)
{
DecodeDXT1Block(dst, &src->color, pitch, height, true);
for (int y = 0; y < height; y++) {
u32 line = src->alphaLines[y];
for (int x = 0; x < 4; x++) {
const u8 a4 = line & 0xF;
dst[x] = (dst[x] & 0xFFFFFF) | (a4 << 24) | (a4 << 28);
line >>= 4;
}
dst += pitch;
// Average
int red3 = (red1 + red2 + 1) / 2;
int green3 = (green1 + green2 + 1) / 2;
int blue3 = (blue1 + blue2 + 1) / 2;
colors_[2] = makecol(red3, green3, blue3, 255);
// Color2 but transparent
colors_[3] = makecol(red2, green2, blue2, 0);
}
}
static inline u8 lerp8(const DXT5Block *src, int n) {
float d = n / 7.0f;
return (u8)(src->alpha1 + (src->alpha2 - src->alpha1) * d);
// These weights translate alpha1/alpha2 to fixed 8.8 point, pre-divided by 7.
int weight1 = ((7 - n) << 8) / 7;
int weight2 = (n << 8) / 7;
return (u8)((src->alpha1 * weight1 + src->alpha2 * weight2) >> 8);
}
static inline u8 lerp6(const DXT5Block *src, int n) {
float d = n / 5.0f;
return (u8)(src->alpha1 + (src->alpha2 - src->alpha1) * d);
int weight1 = ((5 - n) << 8) / 5;
int weight2 = (n << 8) / 5;
return (u8)((src->alpha1 * weight1 + src->alpha2 * weight2) >> 8);
}
void DXTDecoder::DecodeAlphaDXT5(const DXT5Block *src) {
// TODO: Check if alpha is still not 100% correct.
alpha_[0] = src->alpha1;
alpha_[1] = src->alpha2;
if (alpha_[0] > alpha_[1]) {
alpha_[2] = lerp8(src, 1);
alpha_[3] = lerp8(src, 2);
alpha_[4] = lerp8(src, 3);
alpha_[5] = lerp8(src, 4);
alpha_[6] = lerp8(src, 5);
alpha_[7] = lerp8(src, 6);
} else {
alpha_[2] = lerp6(src, 1);
alpha_[3] = lerp6(src, 2);
alpha_[4] = lerp6(src, 3);
alpha_[5] = lerp6(src, 4);
alpha_[6] = 0;
alpha_[7] = 255;
}
}
void DXTDecoder::WriteColorsDXT1(u32 *dst, const DXT1Block *src, int pitch, int height) {
for (int y = 0; y < height; y++) {
int colordata = src->lines[y];
for (int x = 0; x < 4; x++) {
dst[x] = colors_[colordata & 3];
colordata >>= 2;
}
dst += pitch;
}
}
void DXTDecoder::WriteColorsDXT3(u32 *dst, const DXT3Block *src, int pitch, int height) {
for (int y = 0; y < height; y++) {
int colordata = src->color.lines[y];
u32 alphadata = src->alphaLines[y];
for (int x = 0; x < 4; x++) {
const u8 a4 = alphadata & 0xF;
dst[x] = colors_[colordata & 3] | (a4 << 24) | (a4 << 28);
colordata >>= 2;
alphadata >>= 4;
}
dst += pitch;
}
}
void DXTDecoder::WriteColorsDXT5(u32 *dst, const DXT5Block *src, int pitch, int height) {
// 48 bits, 3 bit index per pixel, 12 bits per line.
u64 alphadata = ((u64)(u16)src->alphadata1 << 32) | (u32)src->alphadata2;
for (int y = 0; y < height; y++) {
int colordata = src->color.lines[y];
for (int x = 0; x < 4; x++) {
dst[x] = colors_[colordata & 3] | (alpha_[alphadata & 7] << 24);
colordata >>= 2;
alphadata >>= 3;
}
dst += pitch;
}
}
// This could probably be done faster by decoding two or four blocks at a time with SSE/NEON.
void DecodeDXT1Block(u32 *dst, const DXT1Block *src, int pitch, int height, bool ignore1bitAlpha) {
DXTDecoder dxt;
dxt.DecodeColors(src, ignore1bitAlpha);
dxt.WriteColorsDXT1(dst, src, pitch, height);
}
void DecodeDXT3Block(u32 *dst, const DXT3Block *src, int pitch, int height) {
DXTDecoder dxt;
dxt.DecodeColors(&src->color, true);
dxt.WriteColorsDXT3(dst, src, pitch, height);
}
// The alpha channel is not 100% correct
void DecodeDXT5Block(u32 *dst, const DXT5Block *src, int pitch, int height) {
DecodeDXT1Block(dst, &src->color, pitch, height, true);
u8 alpha[8];
alpha[0] = src->alpha1;
alpha[1] = src->alpha2;
if (alpha[0] > alpha[1]) {
alpha[2] = lerp8(src, 1);
alpha[3] = lerp8(src, 2);
alpha[4] = lerp8(src, 3);
alpha[5] = lerp8(src, 4);
alpha[6] = lerp8(src, 5);
alpha[7] = lerp8(src, 6);
} else {
alpha[2] = lerp6(src, 1);
alpha[3] = lerp6(src, 2);
alpha[4] = lerp6(src, 3);
alpha[5] = lerp6(src, 4);
alpha[6] = 0;
alpha[7] = 255;
}
u64 data = ((u64)(u16)src->alphadata1 << 32) | (u32)src->alphadata2;
for (int y = 0; y < height; y++) {
for (int x = 0; x < 4; x++) {
dst[x] = (dst[x] & 0xFFFFFF) | (alpha[data & 7] << 24);
data >>= 3;
}
dst += pitch;
}
DXTDecoder dxt;
dxt.DecodeColors(&src->color, true);
dxt.DecodeAlphaDXT5(src);
dxt.WriteColorsDXT5(dst, src, pitch, height);
}
#ifdef _M_SSE
+1 -1
View File
@@ -41,7 +41,7 @@ u32 QuickTexHashSSE2(const void *checkp, u32 size);
#define DoQuickTexHash QuickTexHashSSE2
#define StableQuickTexHash QuickTexHashSSE2
// Pitch must be aligned to 16 bits (as is the case on a PSP)
// Pitch must be aligned to 16 bytes (as is the case on a PSP)
void DoUnswizzleTex16Basic(const u8 *texptr, u32 *ydestp, int bxc, int byc, u32 pitch);
#define DoUnswizzleTex16 DoUnswizzleTex16Basic
+2 -6
View File
@@ -22,7 +22,6 @@
#include "Common/MemoryUtil.h"
#include "Core/MemMap.h"
#include "Core/Host.h"
#include "Core/System.h"
#include "Core/Reporting.h"
#include "Core/Config.h"
@@ -34,10 +33,10 @@
#include "GPU/Common/TextureDecoder.h"
#include "GPU/Common/SplineCommon.h"
#include "GPU/Common/TransformCommon.h"
#include "GPU/Common/VertexDecoderCommon.h"
#include "GPU/Common/SoftwareTransformCommon.h"
#include "GPU/Debugger/Debugger.h"
#include "GPU/D3D11/FramebufferManagerD3D11.h"
#include "GPU/D3D11/TextureCacheD3D11.h"
#include "GPU/D3D11/DrawEngineD3D11.h"
@@ -690,10 +689,7 @@ rotateVBO:
gstate_c.vertBounds.maxU = 0;
gstate_c.vertBounds.maxV = 0;
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
// We only support GPU debugging on Windows, and that's the only use case for this.
host->GPUNotifyDraw();
#endif
GPUDebug::NotifyDraw();
}
void DrawEngineD3D11::TessellationDataTransferD3D11::PrepareBuffers(float *&pos, float *&tex, float *&col, int &posStride, int &texStride, int &colStride, int size, bool hasColor, bool hasTexCoords) {
+30 -8
View File
@@ -129,6 +129,21 @@ FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw)
vb.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
ASSERT_SUCCESS(device_->CreateBuffer(&vb, nullptr, &postConstants_));
D3D11_TEXTURE2D_DESC desc{};
desc.CPUAccessFlags = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.ArraySize = 1;
desc.SampleDesc.Count = 1;
desc.Width = 1;
desc.Height = 1;
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.MipLevels = 1;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
ASSERT_SUCCESS(device_->CreateTexture2D(&desc, nullptr, &nullTexture_));
ASSERT_SUCCESS(device_->CreateShaderResourceView(nullTexture_, nullptr, &nullTextureView_));
uint32_t nullData[1]{};
context_->UpdateSubresource(nullTexture_, 0, nullptr, nullData, 1, 0);
ShaderTranslationInit();
CompilePostShader();
@@ -178,6 +193,11 @@ FramebufferManagerD3D11::~FramebufferManagerD3D11() {
stencilUploadInputLayout_->Release();
if (stencilValueBuffer_)
stencilValueBuffer_->Release();
if (nullTextureView_)
nullTextureView_->Release();
if (nullTexture_)
nullTexture_->Release();
}
void FramebufferManagerD3D11::SetTextureCache(TextureCacheD3D11 *tc) {
@@ -437,31 +457,33 @@ void FramebufferManagerD3D11::ReformatFramebufferFrom(VirtualFramebuffer *vfb, G
// Technically, we should at this point re-interpret the bytes of the old format to the new.
// That might get tricky, and could cause unnecessary slowness in some games.
// For now, we just clear alpha/stencil from 565, which fixes shadow issues in Kingdom Hearts.
// (it uses 565 to write zeros to the buffer, than 4444 to actually render the shadow.)
// (it uses 565 to write zeros to the buffer, then 4444 to actually render the shadow.)
//
// The best way to do this may ultimately be to create a new FBO (combine with any resize?)
// and blit with a shader to that, then replace the FBO on vfb. Stencil would still be complex
// to exactly reproduce in 4444 and 8888 formats.
if (old == GE_FORMAT_565) {
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::KEEP, Draw::RPAction::KEEP });
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR });
// TODO: There's no way this does anything useful :(
context_->OMSetDepthStencilState(stockD3D11.depthDisabledStencilWrite, 0xFF);
context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0], nullptr, 0xFFFFFFFF);
context_->OMSetDepthStencilState(stockD3D11.depthStencilDisabled, 0xFF);
context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[D3D11_COLOR_WRITE_ENABLE_ALPHA], nullptr, 0xFFFFFFFF);
context_->RSSetState(stockD3D11.rasterStateNoCull);
context_->IASetInputLayout(quadInputLayout_);
context_->PSSetShader(quadPixelShader_, nullptr, 0);
context_->VSSetShader(quadVertexShader_, nullptr, 0);
context_->IASetVertexBuffers(0, 1, &fsQuadBuffer_, &quadStride_, &quadOffset_);
context_->PSSetSamplers(0, 1, &stockD3D11.samplerPoint2DClamp);
context_->PSSetShaderResources(0, 1, &nullTextureView_);
shaderManagerD3D11_->DirtyLastShader();
D3D11_VIEWPORT vp{ 0.0f, 0.0f, (float)vfb->renderWidth, (float)vfb->renderHeight, 0.0f, 1.0f };
context_->RSSetViewports(1, &vp);
context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
context_->Draw(4, 0);
}
RebindFramebuffer();
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE);
textureCache_->ForgetLastTexture();
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE);
}
}
static void CopyPixelDepthOnly(u32 *dstp, const u32 *srcp, size_t c) {
+3
View File
@@ -107,6 +107,9 @@ private:
ID3D11Buffer *stencilValueBuffer_ = nullptr;
ID3D11DepthStencilState *stencilMaskStates_[256]{};
ID3D11Texture2D *nullTexture_ = nullptr;
ID3D11ShaderResourceView *nullTextureView_ = nullptr;
TextureCacheD3D11 *textureCacheD3D11_;
ShaderManagerD3D11 *shaderManagerD3D11_;
DrawEngineD3D11 *drawEngineD3D11_;
+2 -2
View File
@@ -45,7 +45,6 @@
#include "Core/Debugger/Breakpoints.h"
#include "Core/MemMapHelpers.h"
#include "Core/MIPS/MIPS.h"
#include "Core/Host.h"
#include "Core/Config.h"
#include "Core/Reporting.h"
#include "Core/System.h"
@@ -55,6 +54,7 @@
#include "GPU/GeDisasm.h"
#include "GPU/Common/FramebufferCommon.h"
#include "GPU/Debugger/Debugger.h"
#include "GPU/D3D11/ShaderManagerD3D11.h"
#include "GPU/D3D11/GPU_D3D11.h"
#include "GPU/D3D11/FramebufferManagerD3D11.h"
@@ -254,7 +254,7 @@ void GPU_D3D11::BeginFrame() {
void GPU_D3D11::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) {
// TODO: Some games like Spongebob - Yellow Avenger, never change framebuffer, they blit to it.
// So breaking on frames doesn't work. Might want to move this to sceDisplay vsync.
host->GPUNotifyDisplay(framebuf, stride, format);
GPUDebug::NotifyDisplay(framebuf, stride, format);
framebufferManagerD3D11_->SetDisplayFramebuffer(framebuf, stride, format);
}
+1 -1
View File
@@ -705,7 +705,7 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &
mapData = (u32 *)AllocateAlignedMemory(sizeof(u32) * (w * scaleFactor) * (h * scaleFactor), 16);
mapRowPitch = w * scaleFactor * 4;
} else {
mapRowPitch = std::max(bufw, w) * bpp;
mapRowPitch = std::max(w * bpp, 16);
size_t bufSize = sizeof(u32) * (mapRowPitch / bpp) * h;
mapData = (u32 *)AllocateAlignedMemory(bufSize, 16);
if (!mapData) {
+100
View File
@@ -0,0 +1,100 @@
// Copyright (c) 2018- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "GPU/GPU.h"
#include "GPU/Debugger/Breakpoints.h"
#include "GPU/Debugger/Debugger.h"
#include "GPU/Debugger/Stepping.h"
namespace GPUDebug {
static bool active = false;
static bool inited = false;
static BreakNext breakNext = BreakNext::NONE;
static void Init() {
if (!inited) {
GPUBreakpoints::Init();
Core_ListenStopRequest(&GPUStepping::ForceUnpause);
inited = true;
}
}
void SetActive(bool flag) {
Init();
active = flag;
if (!active) {
breakNext = BreakNext::NONE;
GPUStepping::ResumeFromStepping();
}
}
bool IsActive() {
return active;
}
void SetBreakNext(BreakNext next) {
SetActive(true);
breakNext = next;
if (next == BreakNext::TEX) {
GPUBreakpoints::AddTextureChangeTempBreakpoint();
} else if (next == BreakNext::PRIM) {
GPUBreakpoints::AddCmdBreakpoint(GE_CMD_PRIM, true);
GPUBreakpoints::AddCmdBreakpoint(GE_CMD_BEZIER, true);
GPUBreakpoints::AddCmdBreakpoint(GE_CMD_SPLINE, true);
}
GPUStepping::ResumeFromStepping();
}
void NotifyCommand(u32 pc) {
if (!active)
return;
u32 op = Memory::ReadUnchecked_U32(pc);
if (breakNext == BreakNext::OP || GPUBreakpoints::IsBreakpoint(pc, op)) {
GPUBreakpoints::ClearTempBreakpoints();
auto info = gpuDebug->DissassembleOp(pc);
NOTICE_LOG(G3D, "Waiting at %08x, %s", pc, info.desc.c_str());
GPUStepping::EnterStepping();
}
}
void NotifyDraw() {
if (!active)
return;
if (breakNext == BreakNext::DRAW) {
NOTICE_LOG(G3D, "Waiting at a draw");
GPUStepping::EnterStepping();
}
}
void NotifyDisplay(u32 framebuf, u32 stride, int format) {
if (!active)
return;
if (breakNext == BreakNext::FRAME) {
// This should work fine, start stepping at the first op of the new frame.
breakNext = BreakNext::OP;
}
}
void NotifyTextureAttachment(u32 texaddr) {
if (!active)
return;
}
}
+45
View File
@@ -0,0 +1,45 @@
// Copyright (c) 2018- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include "Common/CommonTypes.h"
namespace GPUDebug {
enum class BreakNext {
NONE,
OP,
DRAW,
TEX,
NONTEX,
FRAME,
PRIM,
};
void SetActive(bool flag);
bool IsActive();
void SetBreakNext(BreakNext next);
// While debugging is active, these may block.
void NotifyCommand(u32 pc);
void NotifyDraw();
void NotifyDisplay(u32 framebuf, u32 stride, int format);
void NotifyTextureAttachment(u32 texaddr);
}
+36 -13
View File
@@ -48,6 +48,7 @@ static const int VERSION = 2;
static bool active = false;
static bool nextFrame = false;
static bool writePending = false;
static std::function<void(const std::string &)> writeCallback;
enum class CommandType : u8 {
INIT = 0,
@@ -409,7 +410,7 @@ static void WriteCompressed(FILE *fp, const void *p, size_t sz) {
delete [] compressed;
}
static void WriteRecording() {
static std::string WriteRecording() {
FlushRegisters();
EmitDisplayBuf();
@@ -430,6 +431,8 @@ static void WriteRecording() {
WriteCompressed(fp, pushbuf.data(), bufsz);
fclose(fp);
return filename;
}
static void GetVertDataSizes(int vcount, const void *indices, u32 &vbytes, u32 &ibytes) {
@@ -637,8 +640,35 @@ bool IsActive() {
return active;
}
void Activate() {
nextFrame = true;
bool IsActivePending() {
return nextFrame || active;
}
bool Activate() {
if (!nextFrame) {
nextFrame = true;
return true;
}
return false;
}
void SetCallback(const std::function<void(const std::string &)> callback) {
writeCallback = callback;
}
static void FinishRecording() {
// We're done - this was just to write the result out.
std::string filename = WriteRecording();
commands.clear();
pushbuf.clear();
NOTICE_LOG(SYSTEM, "Recording finished");
writePending = false;
active = false;
if (writeCallback)
writeCallback(filename);
writeCallback = nullptr;
}
void NotifyCommand(u32 pc) {
@@ -646,14 +676,7 @@ void NotifyCommand(u32 pc) {
return;
}
if (writePending) {
WriteRecording();
commands.clear();
pushbuf.clear();
writePending = false;
// We're done - this was just to write the result out.
NOTICE_LOG(SYSTEM, "Recording finished");
active = false;
FinishRecording();
return;
}
@@ -749,12 +772,12 @@ void NotifyUpload(u32 dest, u32 sz) {
}
void NotifyFrame() {
if (active && !writePending) {
if (active && !writePending && !commands.empty()) {
// Delay write until the first command of the next frame, so we get the right display buf.
NOTICE_LOG(SYSTEM, "Recording complete - waiting to get display buffer");
writePending = true;
}
if (nextFrame) {
if (nextFrame && (gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME) == 0) {
NOTICE_LOG(SYSTEM, "Recording starting...");
active = true;
nextFrame = false;
+5 -1
View File
@@ -17,13 +17,17 @@
#pragma once
#include <functional>
#include <string>
#include "Common/CommonTypes.h"
namespace GPURecord {
bool IsActive();
void Activate();
bool IsActivePending();
bool Activate();
// Call only if Activate() returns true.
void SetCallback(const std::function<void(const std::string &)> callback);
void NotifyCommand(u32 pc);
void NotifyMemcpy(u32 dest, u32 src, u32 sz);
+7 -3
View File
@@ -38,6 +38,7 @@ enum PauseAction {
};
static bool isStepping;
static int stepCounter = 0;
static std::mutex pauseLock;
static std::condition_variable pauseWait;
@@ -149,7 +150,7 @@ bool SingleStep() {
return true;
}
bool EnterStepping(std::function<void()> callback) {
bool EnterStepping() {
std::unique_lock<std::mutex> guard(pauseLock);
if (coreState != CORE_RUNNING && coreState != CORE_NEXTFRAME) {
// Shutting down, don't try to step.
@@ -170,8 +171,7 @@ bool EnterStepping(std::function<void()> callback) {
pauseAction = PAUSE_BREAK;
}
isStepping = true;
callback();
stepCounter++;
do {
RunPauseAction();
@@ -187,6 +187,10 @@ bool IsStepping() {
return isStepping;
}
int GetSteppingCounter() {
return stepCounter;
}
static bool GetBuffer(const GPUDebugBuffer *&buffer, PauseAction type, const GPUDebugBuffer &resultBuffer) {
if (!isStepping && coreState != CORE_STEPPING) {
return false;
+4 -4
View File
@@ -24,12 +24,12 @@
#include "GPU/Common/GPUDebugInterface.h"
namespace GPUStepping {
// Should be called from the GPU thread.
// Begins stepping and calls callback while inside a lock preparing stepping.
// This would be a good place to deliver a message to code that stepping is ready.
bool EnterStepping(std::function<void()> callback);
// Should be called from the emu thread.
// Begins stepping and increments the stepping counter while inside a lock.
bool EnterStepping();
bool SingleStep();
bool IsStepping();
int GetSteppingCounter();
bool GPU_GetOutputFramebuffer(const GPUDebugBuffer *&buffer);
bool GPU_GetCurrentFramebuffer(const GPUDebugBuffer *&buffer, GPUDebugFramebufferType type);
+2 -2
View File
@@ -20,7 +20,6 @@
#include "Common/MemoryUtil.h"
#include "Core/MemMap.h"
#include "Core/Host.h"
#include "Core/System.h"
#include "Core/Reporting.h"
#include "Core/Config.h"
@@ -36,6 +35,7 @@
#include "GPU/Common/TransformCommon.h"
#include "GPU/Common/VertexDecoderCommon.h"
#include "GPU/Common/SoftwareTransformCommon.h"
#include "GPU/Debugger/Debugger.h"
#include "GPU/Directx9/TextureCacheDX9.h"
#include "GPU/Directx9/DrawEngineDX9.h"
#include "GPU/Directx9/ShaderManagerDX9.h"
@@ -621,7 +621,7 @@ rotateVBO:
gstate_c.vertBounds.maxU = 0;
gstate_c.vertBounds.maxV = 0;
host->GPUNotifyDraw();
GPUDebug::NotifyDraw();
}
void DrawEngineDX9::TessellationDataTransferDX9::SendDataToShader(const float * pos, const float * tex, const float * col, int size, bool hasColor, bool hasTexCoords)
+22 -7
View File
@@ -100,6 +100,19 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
}
device_->CreateVertexDeclaration(g_FramebufferVertexElements, &pFramebufferVertexDecl);
int usage = 0;
D3DPOOL pool = D3DPOOL_MANAGED;
if (deviceEx_) {
pool = D3DPOOL_DEFAULT;
usage = D3DUSAGE_DYNAMIC;
}
HRESULT hr = device_->CreateTexture(1, 1, 1, usage, D3DFMT_A8R8G8B8, pool, &nullTex_, nullptr);
D3DLOCKED_RECT rect;
nullTex_->LockRect(0, &rect, nullptr, D3DLOCK_DISCARD);
memset(rect.pBits, 0, 4);
nullTex_->UnlockRect(0);
}
FramebufferManagerDX9::~FramebufferManagerDX9() {
@@ -125,6 +138,8 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
if (stencilUploadVS_) {
stencilUploadVS_->Release();
}
if (nullTex_)
nullTex_->Release();
}
void FramebufferManagerDX9::SetTextureCache(TextureCacheDX9 *tc) {
@@ -307,24 +322,24 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
return;
}
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::KEEP, Draw::RPAction::KEEP });
// Technically, we should at this point re-interpret the bytes of the old format to the new.
// That might get tricky, and could cause unnecessary slowness in some games.
// For now, we just clear alpha/stencil from 565, which fixes shadow issues in Kingdom Hearts.
// (it uses 565 to write zeros to the buffer, than 4444 to actually render the shadow.)
// (it uses 565 to write zeros to the buffer, then 4444 to actually render the shadow.)
//
// The best way to do this may ultimately be to create a new FBO (combine with any resize?)
// and blit with a shader to that, then replace the FBO on vfb. Stencil would still be complex
// to exactly reproduce in 4444 and 8888 formats.
if (old == GE_FORMAT_565) {
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR });
dxstate.scissorTest.disable();
dxstate.depthWrite.set(FALSE);
dxstate.colorMask.set(false, false, false, true);
dxstate.stencilFunc.set(D3DCMP_ALWAYS, 0, 0);
dxstate.stencilMask.set(0xFF);
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE);
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_PARAMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE);
float coord[20] = {
-1.0f,-1.0f,0, 0,0,
@@ -338,7 +353,7 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
device_->SetPixelShader(pFramebufferPixelShader);
device_->SetVertexShader(pFramebufferVertexShader);
shaderManagerDX9_->DirtyLastShader();
device_->SetTexture(0, nullptr);
device_->SetTexture(0, nullTex_);
D3DVIEWPORT9 vp{ 0, 0, (DWORD)vfb->renderWidth, (DWORD)vfb->renderHeight, 0.0f, 1.0f };
device_->SetViewport(&vp);
@@ -349,9 +364,9 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
ERROR_LOG_REPORT(G3D, "ReformatFramebufferFrom() failed: %08x", hr);
}
dxstate.viewport.restore();
}
RebindFramebuffer();
textureCache_->ForgetLastTexture();
}
}
static void CopyPixelDepthOnly(u32 *dstp, const u32 *srcp, size_t c) {
+2
View File
@@ -104,6 +104,8 @@ private:
LPDIRECT3DVERTEXSHADER9 stencilUploadVS_ = nullptr;
bool stencilUploadFailed_ = false;
LPDIRECT3DTEXTURE9 nullTex_ = nullptr;
TextureCacheDX9 *textureCacheDX9_;
ShaderManagerDX9 *shaderManagerDX9_;
DrawEngineDX9 *drawEngineD3D9_;
+2 -1
View File
@@ -39,6 +39,7 @@
#include "GPU/GeDisasm.h"
#include "GPU/Common/FramebufferCommon.h"
#include "GPU/Debugger/Debugger.h"
#include "GPU/Directx9/ShaderManagerDX9.h"
#include "GPU/Directx9/GPU_DX9.h"
#include "GPU/Directx9/FramebufferDX9.h"
@@ -230,7 +231,7 @@ void GPU_DX9::BeginFrame() {
}
void GPU_DX9::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) {
host->GPUNotifyDisplay(framebuf, stride, format);
GPUDebug::NotifyDisplay(framebuf, stride, format);
framebufferManagerDX9_->SetDisplayFramebuffer(framebuf, stride, format);
}
+8 -3
View File
@@ -307,6 +307,7 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, char* scalerC
if (lang == HLSL_D3D11) {
WRITE(p, " if ((roundAndScaleTo255i(v.a) & u_alphacolormask.a) %s u_alphacolorref.a) discard;\n", alphaTestFuncs[alphaTestFunc]);
} else {
// TODO: Use a texture to lookup bitwise ops?
WRITE(p, " if (roundAndScaleTo255f(v.a) %s u_alphacolorref.a) clip(-1);\n", alphaTestFuncs[alphaTestFunc]);
}
} else {
@@ -332,13 +333,17 @@ bool GenerateFragmentShaderHLSL(const FShaderID &id, char *buffer, char* scalerC
} else {
const char *colorTestFuncs[] = { "#", "#", " != ", " == " }; // never/always don't make sense
if (colorTestFuncs[colorTestFunc][0] != '#') {
const char * test = colorTestFuncs[colorTestFunc];
const char *test = colorTestFuncs[colorTestFunc];
if (lang == HLSL_D3D11) {
WRITE(p, " uint3 v_scaled = roundAndScaleTo255iv(v.rgb);\n");
WRITE(p, " if ((v_scaled & u_alphacolormask.rgb) %s (u_alphacolorref.rgb & u_alphacolormask.rgb)) discard;\n", colorTestFuncs[colorTestFunc]);
WRITE(p, " uint3 v_masked = v_scaled & u_alphacolormask.rgb;\n");
WRITE(p, " uint3 colorTestRef = u_alphacolorref.rgb & u_alphacolormask.rgb;\n");
// We have to test the components separately, or we get incorrect results. See #10629.
WRITE(p, " if (v_masked.r %s colorTestRef.r && v_masked.g %s colorTestRef.g && v_masked.b %s colorTestRef.b) discard;\n", test, test, test);
} else {
// TODO: Use a texture to lookup bitwise ops instead?
WRITE(p, " float3 colortest = roundAndScaleTo255v(v.rgb);\n");
WRITE(p, " if ((colortest.r %s u_alphacolorref.r) && (colortest.g %s u_alphacolorref.g) && (colortest.b %s u_alphacolorref.b )) clip(-1);\n", test, test, test);
WRITE(p, " if ((colortest.r %s u_alphacolorref.r) && (colortest.g %s u_alphacolorref.g) && (colortest.b %s u_alphacolorref.b)) clip(-1);\n", test, test, test);
}
}
else {
+3 -3
View File
@@ -59,7 +59,7 @@ PSShader::PSShader(LPDIRECT3DDEVICE9 device, FShaderID id, const char *code) : i
ERROR_LOG(G3D, "Error in shader compilation!");
}
ERROR_LOG(G3D, "Messages: %s", errorMessage.c_str());
ERROR_LOG(G3D, "Shader source:\n%s", code);
ERROR_LOG(G3D, "Shader source:\n%s", LineNumberString(code).c_str());
OutputDebugStringUTF8("Messages:\n");
OutputDebugStringUTF8(errorMessage.c_str());
Reporting::ReportMessage("D3D error in shader compilation: info: %s / code: %s", errorMessage.c_str(), code);
@@ -266,10 +266,10 @@ void ShaderManagerDX9::PSUpdateUniforms(u64 dirtyUniforms) {
PSSetColorUniform3(CONST_PS_TEXENV, gstate.texenvcolor);
}
if (dirtyUniforms & DIRTY_ALPHACOLORREF) {
PSSetColorUniform3Alpha255(CONST_PS_ALPHACOLORREF, gstate.getColorTestRef(), gstate.getAlphaTestRef());
PSSetColorUniform3Alpha255(CONST_PS_ALPHACOLORREF, gstate.getColorTestRef(), gstate.getAlphaTestRef() & gstate.getAlphaTestMask());
}
if (dirtyUniforms & DIRTY_ALPHACOLORMASK) {
PSSetColorUniform3(CONST_PS_ALPHACOLORMASK, gstate.colortestmask);
PSSetColorUniform3Alpha255(CONST_PS_ALPHACOLORMASK, gstate.colortestmask, gstate.getAlphaTestMask());
}
if (dirtyUniforms & DIRTY_FOGCOLOR) {
PSSetColorUniform3(CONST_PS_FOGCOLOR, gstate.fogcolor);
+2 -4
View File
@@ -20,7 +20,6 @@
#include "Common/MemoryUtil.h"
#include "Core/MemMap.h"
#include "Core/Host.h"
#include "Core/System.h"
#include "Core/Reporting.h"
#include "Core/Config.h"
@@ -37,6 +36,7 @@
#include "GPU/Common/SplineCommon.h"
#include "GPU/Common/VertexDecoderCommon.h"
#include "GPU/Common/SoftwareTransformCommon.h"
#include "GPU/Debugger/Debugger.h"
#include "GPU/GLES/FragmentTestCacheGLES.h"
#include "GPU/GLES/StateMappingGLES.h"
#include "GPU/GLES/TextureCacheGLES.h"
@@ -648,9 +648,7 @@ rotateVBO:
gstate_c.vertBounds.maxU = 0;
gstate_c.vertBounds.maxV = 0;
#ifndef MOBILE_DEVICE
host->GPUNotifyDraw();
#endif
GPUDebug::NotifyDraw();
}
bool DrawEngineGLES::IsCodePtrVertexDecoder(const u8 *ptr) const {
+4 -7
View File
@@ -466,20 +466,17 @@ void FramebufferManagerGLES::ReformatFramebufferFrom(VirtualFramebuffer *vfb, GE
// Technically, we should at this point re-interpret the bytes of the old format to the new.
// That might get tricky, and could cause unnecessary slowness in some games.
// For now, we just clear alpha/stencil from 565, which fixes shadow issues in Kingdom Hearts.
// (it uses 565 to write zeros to the buffer, than 4444 to actually render the shadow.)
// (it uses 565 to write zeros to the buffer, then 4444 to actually render the shadow.)
//
// The best way to do this may ultimately be to create a new FBO (combine with any resize?)
// and blit with a shader to that, then replace the FBO on vfb. Stencil would still be complex
// to exactly reproduce in 4444 and 8888 formats.
if (old == GE_FORMAT_565) {
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR });
gstate_c.Dirty(DIRTY_BLEND_STATE);
} else {
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP });
// Clear alpha and stencil.
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR });
render_->Clear(0, 0.0f, 0, GL_COLOR_BUFFER_BIT, 0x8, 0, 0, 0, 0);
}
RebindFramebuffer();
}
void FramebufferManagerGLES::BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) {
+2 -2
View File
@@ -35,7 +35,7 @@
#include "GPU/ge_constants.h"
#include "GPU/GeDisasm.h"
#include "GPU/Common/FramebufferCommon.h"
#include "GPU/Debugger/Debugger.h"
#include "GPU/GLES/ShaderManagerGLES.h"
#include "GPU/GLES/GPU_GLES.h"
#include "GPU/GLES/FramebufferManagerGLES.h"
@@ -443,7 +443,7 @@ void GPU_GLES::BeginFrame() {
}
void GPU_GLES::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) {
host->GPUNotifyDisplay(framebuf, stride, format);
GPUDebug::NotifyDisplay(framebuf, stride, format);
framebufferManagerGL_->SetDisplayFramebuffer(framebuf, stride, format);
}
+9 -15
View File
@@ -753,11 +753,8 @@ TexCacheEntry::TexStatus TextureCacheGLES::CheckAlpha(const uint8_t *pixelData,
void TextureCacheGLES::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &replaced, int level, int scaleFactor, GLenum dstFmt) {
int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level);
bool useUnpack = false;
uint8_t *pixelData;
// TODO: only do this once
u32 texByteAlign = 1;
int decPitch = 0;
gpuStats.numTexturesDecoded++;
@@ -765,13 +762,12 @@ void TextureCacheGLES::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &r
PROFILE_THIS_SCOPE("replacetex");
int bpp = replaced.Format(level) == ReplacedTextureFormat::F_8888 ? 4 : 2;
uint8_t *rearrange = (uint8_t *)AllocateAlignedMemory(w * h * bpp, 16);
replaced.Load(level, rearrange, bpp * w);
decPitch = w * bpp;
uint8_t *rearrange = (uint8_t *)AllocateAlignedMemory(decPitch * h, 16);
replaced.Load(level, rearrange, decPitch);
pixelData = rearrange;
dstFmt = ToGLESFormat(replaced.Format(level));
texByteAlign = bpp;
} else {
PROFILE_THIS_SCOPE("decodetex");
@@ -780,14 +776,15 @@ void TextureCacheGLES::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &r
int bufw = GetTextureBufw(level, texaddr, GETextureFormat(entry.format));
int pixelSize = dstFmt == GL_UNSIGNED_BYTE ? 4 : 2;
int decPitch = w * pixelSize;
// We leave GL_UNPACK_ALIGNMENT at 4, so this must be at least 4.
decPitch = std::max(w * pixelSize, 4);
pixelData = (uint8_t *)AllocateAlignedMemory(decPitch * h * pixelSize, 16);
DecodeTextureLevel(pixelData, decPitch, GETextureFormat(entry.format), clutformat, texaddr, level, bufw, true, false, false);
// We check before scaling since scaling shouldn't invent alpha from a full alpha texture.
if ((entry.status & TexCacheEntry::STATUS_CHANGE_FREQUENT) == 0) {
TexCacheEntry::TexStatus alphaStatus = CheckAlpha(pixelData, dstFmt, useUnpack ? bufw : w, w, h);
TexCacheEntry::TexStatus alphaStatus = CheckAlpha(pixelData, dstFmt, decPitch / pixelSize, w, h);
entry.SetAlphaStatus(alphaStatus, level);
} else {
entry.SetAlphaStatus(TexCacheEntry::STATUS_ALPHA_UNKNOWN);
@@ -798,11 +795,9 @@ void TextureCacheGLES::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &r
scaler.ScaleAlways((u32 *)rearrange, (u32 *)pixelData, dstFmt, w, h, scaleFactor);
FreeAlignedMemory(pixelData);
pixelData = rearrange;
decPitch = w * 4;
}
// Textures are always aligned to 16 bytes bufw, so this could safely be 4 always.
texByteAlign = dstFmt == GL_UNSIGNED_BYTE ? 4 : 2;
if (replacer_.Enabled()) {
ReplacedTextureDecodeInfo replacedInfo;
replacedInfo.cachekey = entry.CacheKey();
@@ -813,8 +808,7 @@ void TextureCacheGLES::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &r
replacedInfo.scaleFactor = scaleFactor;
replacedInfo.fmt = FromGLESFormat(dstFmt);
int bpp = dstFmt == GL_UNSIGNED_BYTE ? 4 : 2;
replacer_.NotifyTextureDecoded(replacedInfo, pixelData, (useUnpack ? bufw : w) * bpp, level, w, h);
replacer_.NotifyTextureDecoded(replacedInfo, pixelData, decPitch, level, w, h);
}
}
+2
View File
@@ -217,6 +217,7 @@
<ClInclude Include="D3D11\TextureScalerD3D11.h" />
<ClInclude Include="D3D11\VertexShaderGeneratorD3D11.h" />
<ClInclude Include="Debugger\Breakpoints.h" />
<ClInclude Include="Debugger\Debugger.h" />
<ClInclude Include="Debugger\Record.h" />
<ClInclude Include="Debugger\Stepping.h" />
<ClInclude Include="Directx9\DepalettizeShaderDX9.h" />
@@ -320,6 +321,7 @@
<ClCompile Include="D3D11\TextureScalerD3D11.cpp" />
<ClCompile Include="D3D11\VertexShaderGeneratorD3D11.cpp" />
<ClCompile Include="Debugger\Breakpoints.cpp" />
<ClCompile Include="Debugger\Debugger.cpp" />
<ClCompile Include="Debugger\Record.cpp" />
<ClCompile Include="Debugger\Stepping.cpp" />
<ClCompile Include="Directx9\DepalettizeShaderDX9.cpp" />
+6
View File
@@ -273,6 +273,9 @@
<ClInclude Include="Vulkan\DebugVisVulkan.h">
<Filter>Vulkan</Filter>
</ClInclude>
<ClInclude Include="Debugger\Debugger.h">
<Filter>Debugger</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Math3D.cpp">
@@ -542,5 +545,8 @@
<ClCompile Include="Vulkan\DebugVisVulkan.cpp">
<Filter>Vulkan</Filter>
</ClCompile>
<ClCompile Include="Debugger\Debugger.cpp">
<Filter>Debugger</Filter>
</ClCompile>
</ItemGroup>
</Project>
+4 -5
View File
@@ -28,6 +28,7 @@
#include "GPU/Common/FramebufferCommon.h"
#include "GPU/Common/SplineCommon.h"
#include "GPU/Common/TextureCacheCommon.h"
#include "GPU/Debugger/Debugger.h"
#include "GPU/Debugger/Record.h"
const CommonCommandTableEntry commonCommandTable[] = {
@@ -936,7 +937,7 @@ bool GPUCommon::InterpretList(DisplayList &list) {
gpuState = list.pc == list.stall ? GPUSTATE_STALL : GPUSTATE_RUNNING;
debugRecording_ = GPURecord::IsActive();
const bool useDebugger = host->GPUDebuggingActive() || debugRecording_;
const bool useDebugger = GPUDebug::IsActive() || debugRecording_;
const bool useFastRunLoop = !dumpThisFrame_ && !useDebugger;
while (gpuState == GPUSTATE_RUNNING) {
{
@@ -1041,7 +1042,7 @@ void GPUCommon::SlowRunLoop(DisplayList &list)
const bool dumpThisFrame = dumpThisFrame_;
while (downcount > 0)
{
host->GPUNotifyCommand(list.pc);
GPUDebug::NotifyCommand(list.pc);
GPURecord::NotifyCommand(list.pc);
u32 op = Memory::ReadUnchecked_U32(list.pc);
u32 cmd = op >> 24;
@@ -1593,10 +1594,8 @@ void GPUCommon::Execute_Prim(u32 op, u32 diff) {
if (!g_Config.bSoftwareSkinning)
vtypeCheckMask = 0xFFFFFFFF;
#ifndef MOBILE_DEVICE
if (debugRecording_ || host->GPUDebuggingActive())
if (debugRecording_ || GPUDebug::IsActive())
goto bail;
#endif
while (src != stall) {
uint32_t data = *src;
+8 -5
View File
@@ -1764,17 +1764,20 @@ bool GetCurrentTexture(GPUDebugBuffer &buffer, int level)
return false;
}
int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level);
buffer.Allocate(w, h, GE_FORMAT_8888, false);
GETextureFormat texfmt = gstate.getTextureFormat();
u32 texaddr = gstate.getTextureAddress(level);
int texbufw = GetTextureBufw(level, texaddr, texfmt);
u8 *texptr = Memory::GetPointer(texaddr);
int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level);
if (!texaddr || !Memory::IsValidRange(texaddr, (textureBitsPerPixel[texfmt] * texbufw * h) / 8))
return false;
buffer.Allocate(w, h, GE_FORMAT_8888, false);
Sampler::Funcs sampler = Sampler::GetFuncs();
u8 *texptr = Memory::GetPointer(texaddr);
u32 *row = (u32 *)buffer.GetData();
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
+2 -2
View File
@@ -23,7 +23,6 @@
#include "Core/Config.h"
#include "Core/ConfigValues.h"
#include "Core/Debugger/Breakpoints.h"
#include "Core/Host.h"
#include "Core/MemMap.h"
#include "Core/HLE/sceKernelInterrupt.h"
#include "Core/HLE/sceGe.h"
@@ -39,6 +38,7 @@
#include "GPU/Software/TransformUnit.h"
#include "GPU/Common/DrawEngineCommon.h"
#include "GPU/Common/FramebufferCommon.h"
#include "GPU/Debugger/Debugger.h"
#include "GPU/Debugger/Record.h"
const int FB_WIDTH = 480;
@@ -141,7 +141,7 @@ void SoftGPU::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat for
displayFramebuf_ = (framebuf & 0xFF000000) == 0 ? 0x44000000 | framebuf : framebuf;
displayStride_ = stride;
displayFormat_ = format;
host->GPUNotifyDisplay(framebuf, stride, format);
GPUDebug::NotifyDisplay(framebuf, stride, format);
}
// Copies RGBA8 data from RAM to the currently bound render target.
+2 -3
View File
@@ -16,13 +16,12 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Common/MemoryUtil.h"
#include "Core/Host.h"
#include "Core/Config.h"
#include "GPU/GPUState.h"
#include "GPU/Common/DrawEngineCommon.h"
#include "GPU/Common/VertexDecoderCommon.h"
#include "GPU/Common/SplineCommon.h"
#include "GPU/Debugger/Debugger.h"
#include "GPU/Software/TransformUnit.h"
#include "GPU/Software/Clipper.h"
#include "GPU/Software/Lighting.h"
@@ -490,7 +489,7 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy
break;
}
host->GPUNotifyDraw();
GPUDebug::NotifyDraw();
}
// TODO: This probably is not the best interface.
+2 -2
View File
@@ -25,7 +25,6 @@
#include "Common/MemoryUtil.h"
#include "Core/MemMap.h"
#include "Core/Host.h"
#include "Core/System.h"
#include "Core/Reporting.h"
#include "Core/Config.h"
@@ -44,6 +43,7 @@
#include "GPU/Common/VertexDecoderCommon.h"
#include "GPU/Common/SoftwareTransformCommon.h"
#include "GPU/Common/DrawEngineCommon.h"
#include "GPU/Debugger/Debugger.h"
#include "GPU/Vulkan/DrawEngineVulkan.h"
#include "GPU/Vulkan/TextureCacheVulkan.h"
#include "GPU/Vulkan/ShaderManagerVulkan.h"
@@ -976,7 +976,7 @@ void DrawEngineVulkan::DoFlush() {
gstate_c.vertBounds.maxU = 0;
gstate_c.vertBounds.maxV = 0;
host->GPUNotifyDraw();
GPUDebug::NotifyDraw();
}
void DrawEngineVulkan::UpdateUBOs(FrameData *frame) {
+4 -4
View File
@@ -364,16 +364,16 @@ void FramebufferManagerVulkan::ReformatFramebufferFrom(VirtualFramebuffer *vfb,
// Technically, we should at this point re-interpret the bytes of the old format to the new.
// That might get tricky, and could cause unnecessary slowness in some games.
// For now, we just clear alpha/stencil from 565, which fixes shadow issues in Kingdom Hearts.
// (it uses 565 to write zeros to the buffer, than 4444 to actually render the shadow.)
// (it uses 565 to write zeros to the buffer, then 4444 to actually render the shadow.)
//
// The best way to do this may ultimately be to create a new FBO (combine with any resize?)
// and blit with a shader to that, then replace the FBO on vfb. Stencil would still be complex
// to exactly reproduce in 4444 and 8888 formats.
if (old == GE_FORMAT_565) {
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR });
} else {
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP });
// TODO: To match other backends, would be ideal to clear alpha only and not color.
// But probably doesn't matter that much...
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::KEEP, Draw::RPAction::CLEAR });
}
}
+2 -3
View File
@@ -26,7 +26,6 @@
#include "Core/Config.h"
#include "Core/Debugger/Breakpoints.h"
#include "Core/MemMapHelpers.h"
#include "Core/Host.h"
#include "Core/Config.h"
#include "Core/Reporting.h"
#include "Core/System.h"
@@ -36,7 +35,7 @@
#include "GPU/ge_constants.h"
#include "GPU/GeDisasm.h"
#include "GPU/Common/FramebufferCommon.h"
#include "GPU/Debugger/Debugger.h"
#include "GPU/Vulkan/ShaderManagerVulkan.h"
#include "GPU/Vulkan/GPU_Vulkan.h"
#include "GPU/Vulkan/FramebufferVulkan.h"
@@ -405,7 +404,7 @@ void GPU_Vulkan::UpdateVsyncInterval(bool force) {
}
void GPU_Vulkan::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) {
host->GPUNotifyDisplay(framebuf, stride, format);
GPUDebug::NotifyDisplay(framebuf, stride, format);
framebufferManager_->SetDisplayFramebuffer(framebuf, stride, format);
}
-3
View File
@@ -90,9 +90,6 @@ public:
NativeMessageReceived(message.c_str(), value.c_str());
}
bool GPUDebuggingActive() override {
return false;
}
private:
const char* SymbolMapFilename(std::string currentFilename);
MainWindow* mainWindow;
+84 -2
View File
@@ -19,6 +19,7 @@ SDLJoystick *joystick = NULL;
#include <cassert>
#include <cmath>
#include <thread>
#include <locale>
#include "base/display.h"
#include "base/logging.h"
@@ -187,8 +188,23 @@ std::string System_GetProperty(SystemProperty prop) {
#else
return "SDL:";
#endif
case SYSPROP_LANGREGION:
case SYSPROP_LANGREGION: {
// Get user-preferred locale from OS
setlocale(LC_ALL, "");
std::string locale(setlocale(LC_ALL, NULL));
// Set c and c++ strings back to POSIX
std::locale::global(std::locale("POSIX"));
if (!locale.empty()) {
if (locale.find("_", 0) != std::string::npos) {
if (locale.find(".", 0) != std::string::npos) {
return locale.substr(0, locale.find(".",0));
} else {
return locale;
}
}
}
return "en_US";
}
default:
return "";
}
@@ -339,6 +355,7 @@ int main(int argc, char *argv[]) {
int set_xres = -1;
int set_yres = -1;
int w = 0, h = 0;
bool portrait = false;
bool set_ipad = false;
float set_dpi = 1.0f;
@@ -585,7 +602,7 @@ int main(int argc, char *argv[]) {
while (true) {
double startTime = time_now_d();
SDL_Event event;
SDL_Event event, touchEvent;
while (SDL_PollEvent(&event)) {
float mx = event.motion.x * g_dpi_scale_x;
float my = event.motion.y * g_dpi_scale_y;
@@ -665,6 +682,71 @@ int main(int argc, char *argv[]) {
NativeKey(key);
break;
}
case SDL_FINGERMOTION:
{
if (!g_Config.bFullScreen) { break; }
SDL_GetWindowSize(window, &w, &h);
touchEvent.type = SDL_MOUSEMOTION;
touchEvent.motion.type = SDL_MOUSEMOTION;
touchEvent.motion.timestamp = event.tfinger.timestamp;
touchEvent.motion.windowID = SDL_GetWindowID(window);
touchEvent.motion.which = SDL_TOUCH_MOUSEID;
touchEvent.motion.state = SDL_GetMouseState(NULL, NULL);
touchEvent.motion.x = event.tfinger.x * w;
touchEvent.motion.y = event.tfinger.y * h;
SDL_WarpMouseInWindow(window, event.tfinger.x * w, event.tfinger.y * h);
SDL_PushEvent(&touchEvent);
break;
}
case SDL_FINGERDOWN:
{
if (!g_Config.bFullScreen) { break; }
SDL_GetWindowSize(window, &w, &h);
touchEvent.type = SDL_MOUSEBUTTONDOWN;
touchEvent.button.type = SDL_MOUSEBUTTONDOWN;
touchEvent.button.timestamp = SDL_GetTicks();
touchEvent.button.windowID = SDL_GetWindowID(window);
touchEvent.button.which = SDL_TOUCH_MOUSEID;
touchEvent.button.button = SDL_BUTTON_LEFT;
touchEvent.button.state = SDL_PRESSED;
touchEvent.button.clicks = 1;
touchEvent.button.x = event.tfinger.x * w;
touchEvent.button.y = event.tfinger.y * h;
touchEvent.motion.type = SDL_MOUSEMOTION;
touchEvent.motion.timestamp = SDL_GetTicks();
touchEvent.motion.windowID = SDL_GetWindowID(window);
touchEvent.motion.which = SDL_TOUCH_MOUSEID;
touchEvent.motion.x = event.tfinger.x * w;
touchEvent.motion.y = event.tfinger.y * h;
// Any real mouse cursor should also move
SDL_WarpMouseInWindow(window, event.tfinger.x * w, event.tfinger.y * h);
// First finger down event also has to be a motion to that position
SDL_PushEvent(&touchEvent);
touchEvent.motion.type = SDL_MOUSEBUTTONDOWN;
// Now we push the mouse button event
SDL_PushEvent(&touchEvent);
break;
}
case SDL_FINGERUP:
{
if(!g_Config.bFullScreen) { break; }
SDL_GetWindowSize(window, &w, &h);
touchEvent.type = SDL_MOUSEBUTTONUP;
touchEvent.button.type = SDL_MOUSEBUTTONUP;
touchEvent.button.timestamp = SDL_GetTicks();
touchEvent.button.windowID = SDL_GetWindowID(window);
touchEvent.button.which = SDL_TOUCH_MOUSEID;
touchEvent.button.button = SDL_BUTTON_LEFT;
touchEvent.button.state = SDL_RELEASED;
touchEvent.button.clicks = 1;
touchEvent.button.x = event.tfinger.x * w;
touchEvent.button.y = event.tfinger.y * h;
SDL_PushEvent(&touchEvent);
break;
}
case SDL_MOUSEBUTTONDOWN:
switch (event.button.button) {
case SDL_BUTTON_LEFT:
+8 -6
View File
@@ -121,6 +121,8 @@ static std::string PostShaderTranslateName(const char *value) {
}
void GameSettingsScreen::CreateViews() {
ReloadAllPostShaderInfo();
if (editThenRestore_) {
g_Config.loadGameConfig(gameID_);
}
@@ -1333,6 +1335,12 @@ void DeveloperToolsScreen::CreateViews() {
cpuTests->SetEnabled(TestsAvailable());
#endif
allowDebugger_ = !WebServerStopped(WebServerFlags::DEBUGGER);
canAllowDebugger_ = !WebServerStopping(WebServerFlags::DEBUGGER);
CheckBox *allowDebugger = new CheckBox(&allowDebugger_, dev->T("Allow remote debugger"));
list->Add(allowDebugger)->OnClick.Handle(this, &DeveloperToolsScreen::OnRemoteDebugger);
allowDebugger->SetEnabledPtr(&canAllowDebugger_);
list->Add(new CheckBox(&g_Config.bEnableLogging, dev->T("Enable Logging")))->OnClick.Handle(this, &DeveloperToolsScreen::OnLoggingChanged);
list->Add(new CheckBox(&g_Config.bLogFrameDrops, dev->T("Log Dropped Frame Statistics")));
list->Add(new Choice(dev->T("Logging Channels")))->OnClick.Handle(this, &DeveloperToolsScreen::OnLogConfig);
@@ -1349,12 +1357,6 @@ void DeveloperToolsScreen::CreateViews() {
createTextureIni->SetEnabled(false);
}
#endif
allowDebugger_ = !WebServerStopped(WebServerFlags::DEBUGGER);
canAllowDebugger_ = !WebServerStopping(WebServerFlags::DEBUGGER);
CheckBox *allowDebugger = new CheckBox(&allowDebugger_, dev->T("Allow remote debugger"));
list->Add(allowDebugger)->OnClick.Handle(this, &DeveloperToolsScreen::OnRemoteDebugger);
allowDebugger->SetEnabledPtr(&canAllowDebugger_);
}
void DeveloperToolsScreen::onFinish(DialogResult result) {
+5 -4
View File
@@ -495,10 +495,11 @@ UI::EventReturn GameBrowser::HomeClick(UI::EventParams &e) {
UI::EventReturn GameBrowser::PinToggleClick(UI::EventParams &e) {
auto &pinnedPaths = g_Config.vPinnedPaths;
const std::string path = File::ResolvePath(path_.GetPath());
if (IsCurrentPathPinned()) {
pinnedPaths.erase(std::remove(pinnedPaths.begin(), pinnedPaths.end(), path_.GetPath()), pinnedPaths.end());
pinnedPaths.erase(std::remove(pinnedPaths.begin(), pinnedPaths.end(), path), pinnedPaths.end());
} else {
pinnedPaths.push_back(path_.GetPath());
pinnedPaths.push_back(path);
}
Refresh();
return UI::EVENT_DONE;
@@ -662,7 +663,7 @@ void GameBrowser::Refresh() {
bool GameBrowser::IsCurrentPathPinned() {
const auto paths = g_Config.vPinnedPaths;
return std::find(paths.begin(), paths.end(), path_.GetPath()) != paths.end();
return std::find(paths.begin(), paths.end(), File::ResolvePath(path_.GetPath())) != paths.end();
}
const std::vector<std::string> GameBrowser::GetPinnedPaths() {
@@ -672,7 +673,7 @@ const std::vector<std::string> GameBrowser::GetPinnedPaths() {
static const std::string sepChars = "/\\";
#endif
const std::string currentPath = path_.GetPath();
const std::string currentPath = File::ResolvePath(path_.GetPath());
const std::vector<std::string> paths = g_Config.vPinnedPaths;
std::vector<std::string> results;
for (size_t i = 0; i < paths.size(); ++i) {
+1 -1
View File
@@ -398,7 +398,7 @@ void NewLanguageScreen::OnCompleted(DialogResult result) {
bool iniLoadedSuccessfully = false;
// Allow the lang directory to be overridden for testing purposes (e.g. Android, where it's hard to
// test new languages without recompiling the entire app, which is a hassle).
const std::string langOverridePath = g_Config.memStickDirectory + "PSP/SYSTEM/lang/";
const std::string langOverridePath = GetSysDirectory(DIRECTORY_SYSTEM) + "lang/";
// If we run into the unlikely case that "lang" is actually a file, just use the built-in translations.
if (!File::Exists(langOverridePath) || !File::IsDirectory(langOverridePath))
+79 -14
View File
@@ -29,13 +29,10 @@
// in NativeShutdown.
#include <locale.h>
// Linux doesn't like using std::find with std::vector<int> without this :/
#if !defined(MOBILE_DEVICE)
#include <algorithm>
#endif
#include <memory>
#include <thread>
#include <mutex>
#include <thread>
#if defined(_WIN32)
#include "Windows/DSoundStream.h"
@@ -145,6 +142,7 @@ static bool resized = false;
static bool restarting = false;
static bool askedForStoragePermission = false;
static int renderCounter = 0;
struct PendingMessage {
std::string msg;
@@ -323,7 +321,7 @@ static void PostLoadConfig() {
// Allow the lang directory to be overridden for testing purposes (e.g. Android, where it's hard to
// test new languages without recompiling the entire app, which is a hassle).
const std::string langOverridePath = g_Config.memStickDirectory + "PSP/SYSTEM/lang/";
const std::string langOverridePath = GetSysDirectory(DIRECTORY_SYSTEM) + "lang/";
// If we run into the unlikely case that "lang" is actually a file, just use the built-in translations.
if (!File::Exists(langOverridePath) || !File::IsDirectory(langOverridePath))
@@ -336,15 +334,75 @@ void CreateDirectoriesAndroid() {
// On Android, create a PSP directory tree in the external_dir,
// to hopefully reduce confusion a bit.
ILOG("Creating %s", (g_Config.memStickDirectory + "PSP").c_str());
File::CreateDir(g_Config.memStickDirectory + "PSP");
File::CreateDir(g_Config.memStickDirectory + "PSP/SAVEDATA");
File::CreateDir(g_Config.memStickDirectory + "PSP/PPSSPP_STATE");
File::CreateDir(g_Config.memStickDirectory + "PSP/GAME");
File::CreateDir(g_Config.memStickDirectory + "PSP/SYSTEM");
File::CreateFullPath(g_Config.memStickDirectory + "PSP");
File::CreateFullPath(GetSysDirectory(DIRECTORY_SAVEDATA));
File::CreateFullPath(GetSysDirectory(DIRECTORY_SAVESTATE));
File::CreateFullPath(GetSysDirectory(DIRECTORY_GAME));
File::CreateFullPath(GetSysDirectory(DIRECTORY_SYSTEM));
// Avoid media scanners in PPSSPP_STATE and SAVEDATA directories
File::CreateEmptyFile(g_Config.memStickDirectory + "PSP/PPSSPP_STATE/.nomedia");
File::CreateEmptyFile(g_Config.memStickDirectory + "PSP/SAVEDATA/.nomedia");
File::CreateEmptyFile(GetSysDirectory(DIRECTORY_SAVESTATE) + ".nomedia");
File::CreateEmptyFile(GetSysDirectory(DIRECTORY_SAVEDATA) + ".nomedia");
File::CreateEmptyFile(GetSysDirectory(DIRECTORY_SYSTEM) + ".nomedia");
}
static void CheckFailedGPUBackends() {
// We only want to do this once per process run and backend, to detect process crashes.
// If NativeShutdown is called before we finish, we might call this multiple times.
static int lastBackend = -1;
if (lastBackend == g_Config.iGPUBackend) {
return;
}
lastBackend = g_Config.iGPUBackend;
std::string cache = GetSysDirectory(DIRECTORY_APP_CACHE) + "/FailedGraphicsBackends.txt";
if (System_GetPropertyBool(SYSPROP_SUPPORTS_PERMISSIONS)) {
std::string data;
if (readFileToString(true, cache.c_str(), data))
g_Config.sFailedGPUBackends = data;
}
// Use this if you want to debug a graphics crash...
if (g_Config.sFailedGPUBackends == "IGNORE")
return;
else if (!g_Config.sFailedGPUBackends.empty())
ERROR_LOG(LOADER, "Failed graphics backends: %s", g_Config.sFailedGPUBackends.c_str());
// Okay, let's not try a backend in the failed list.
g_Config.iGPUBackend = g_Config.NextValidBackend();
if (lastBackend != g_Config.iGPUBackend)
WARN_LOG(LOADER, "Failed graphics backend switched from %d to %d", lastBackend, g_Config.iGPUBackend);
// And then let's - for now - add the current to the failed list.
if (g_Config.sFailedGPUBackends.empty()) {
g_Config.sFailedGPUBackends = StringFromFormat("%d", g_Config.iGPUBackend);
} else if (g_Config.sFailedGPUBackends.find("ALL") == std::string::npos) {
g_Config.sFailedGPUBackends += StringFromFormat(",%d", g_Config.iGPUBackend);
}
if (System_GetPropertyBool(SYSPROP_SUPPORTS_PERMISSIONS)) {
// Let's try to create, in case it doesn't exist.
if (!File::Exists(GetSysDirectory(DIRECTORY_APP_CACHE)))
File::CreateDir(GetSysDirectory(DIRECTORY_APP_CACHE));
writeStringToFile(true, g_Config.sFailedGPUBackends, cache.c_str());
} else {
// Just save immediately, since we have storage.
g_Config.Save();
}
}
static void ClearFailedGPUBackends() {
if (g_Config.sFailedGPUBackends == "IGNORE")
return;
// We've successfully started graphics without crashing, hurray.
// In case they update drivers and have totally different problems much later, clear the failed list.
g_Config.sFailedGPUBackends.clear();
if (System_GetPropertyBool(SYSPROP_SUPPORTS_PERMISSIONS)) {
File::Delete(GetSysDirectory(DIRECTORY_APP_CACHE) + "/FailedGraphicsBackends.txt");
} else {
g_Config.Save();
}
}
void NativeInit(int argc, const char *argv[], const char *savegame_dir, const char *external_dir, const char *cache_dir) {
@@ -420,8 +478,8 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
#ifndef _WIN32
g_Config.AddSearchPath(user_data_path);
g_Config.AddSearchPath(g_Config.memStickDirectory + "PSP/SYSTEM/");
g_Config.SetDefaultPath(g_Config.memStickDirectory + "PSP/SYSTEM/");
g_Config.AddSearchPath(GetSysDirectory(DIRECTORY_SYSTEM));
g_Config.SetDefaultPath(GetSysDirectory(DIRECTORY_SYSTEM));
// Note that if we don't have storage permission here, loading the config will
// fail and it will be set to the default. Later, we load again when we get permission.
@@ -630,7 +688,9 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
// We do this here, instead of in NativeInitGraphics, because the display may be reset.
// When it's reset we don't want to forget all our managed things.
CheckFailedGPUBackends();
SetGPUBackend((GPUBackend) g_Config.iGPUBackend);
renderCounter = 0;
// Must be done restarting by now.
restarting = false;
@@ -951,6 +1011,11 @@ void NativeRender(GraphicsContext *graphicsContext) {
ui_draw2d.PopDrawMatrix();
ui_draw2d_front.PopDrawMatrix();
if (renderCounter < 10 && ++renderCounter == 10) {
// We're rendering fine, clear out failure info.
ClearFailedGPUBackends();
}
}
void HandleGlobalMessage(const std::string &msg, const std::string &value) {
+7 -4
View File
@@ -138,12 +138,15 @@ public:
}
protected:
virtual bool FillVertical() const override { return false; }
bool FillVertical() const override { return false; }
UI::Size PopupWidth() const override { return 500; }
bool ShowButtons() const override { return true; }
virtual void CreatePopupContents(UI::ViewGroup *parent) override {
// TODO: Find an appropriate size for the image view
parent->Add(new AsyncImageFileView(filename_, UI::IS_DEFAULT, NULL, new UI::LayoutParams(480, 272)))->SetCanBeFocused(false);
void CreatePopupContents(UI::ViewGroup *parent) override {
UI::LinearLayout *content = new UI::LinearLayout(UI::ORIENT_VERTICAL);
parent->Add(content);
UI::Margins contentMargins(10, 0);
content->Add(new AsyncImageFileView(filename_, UI::IS_DEFAULT, nullptr, new UI::LinearLayoutParams(480, 272, contentMargins)))->SetCanBeFocused(false);
}
private:
+2
View File
@@ -332,6 +332,7 @@
<ClInclude Include="..\..\GPU\D3D11\TextureScalerD3D11.h" />
<ClInclude Include="..\..\GPU\D3D11\VertexShaderGeneratorD3D11.h" />
<ClInclude Include="..\..\GPU\Debugger\Breakpoints.h" />
<ClInclude Include="..\..\GPU\Debugger\Debugger.h" />
<ClInclude Include="..\..\GPU\Debugger\Record.h" />
<ClInclude Include="..\..\GPU\Debugger\Stepping.h" />
<ClInclude Include="..\..\GPU\Directx9\PixelShaderGeneratorDX9.h" />
@@ -390,6 +391,7 @@
<ClCompile Include="..\..\GPU\D3D11\TextureScalerD3D11.cpp" />
<ClCompile Include="..\..\GPU\D3D11\VertexShaderGeneratorD3D11.cpp" />
<ClCompile Include="..\..\GPU\Debugger\Breakpoints.cpp" />
<ClCompile Include="..\..\GPU\Debugger\Debugger.cpp" />
<ClCompile Include="..\..\GPU\Debugger\Record.cpp" />
<ClCompile Include="..\..\GPU\Debugger\Stepping.cpp" />
<ClCompile Include="..\..\GPU\Directx9\PixelShaderGeneratorDX9.cpp" />
+12 -2
View File
@@ -150,13 +150,18 @@
<ClCompile Include="..\..\GPU\Debugger\Breakpoints.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="..\..\GPU\Debugger\Debugger.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="..\..\GPU\Debugger\Stepping.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="..\..\GPU\Common\ShaderCommon.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="..\..\GPU\Software\Sampler.cpp" />
<ClCompile Include="..\..\GPU\Software\Sampler.cpp">
<Filter>Software</Filter>
</ClInclude>
<ClCompile Include="..\..\GPU\Debugger\Record.cpp">
<Filter>Debugger</Filter>
</ClCompile>
@@ -291,10 +296,15 @@
<ClInclude Include="..\..\GPU\Debugger\Breakpoints.h">
<Filter>Debugger</Filter>
</ClInclude>
<ClInclude Include="..\..\GPU\Debugger\Debugger.h">
<Filter>Debugger</Filter>
</ClInclude>
<ClInclude Include="..\..\GPU\Debugger\Stepping.h">
<Filter>Debugger</Filter>
</ClInclude>
<ClInclude Include="..\..\GPU\Software\Sampler.h" />
<ClInclude Include="..\..\GPU\Software\Sampler.h">
<Filter>Software</Filter>
</ClInclude>
<ClInclude Include="..\..\GPU\Debugger\Record.h">
<Filter>Debugger</Filter>
</ClInclude>
-5
View File
@@ -32,11 +32,6 @@ public:
void SaveSymbolMap() override;
void SetWindowTitle(const char *message) override;
bool GPUDebuggingActive() override { return false; }
void GPUNotifyCommand(u32 pc) override {}
void GPUNotifyDisplay(u32 framebuf, u32 stride, int format) override {}
void GPUNotifyDraw() override {}
void GPUNotifyTextureAttachment(u32 addr) override {}
void ToggleDebugConsoleVisibility() override;
bool CanCreateShortcut() override;
+14
View File
@@ -132,6 +132,18 @@ void MainThreadFunc() {
bool performingRestart = NativeIsRestarting();
NativeInit(static_cast<int>(args.size()), &args[0], "1234", "1234", nullptr);
if (g_Config.sFailedGPUBackends.find("ALL") != std::string::npos) {
Reporting::ReportMessage("Graphics init error: %s", "ALL");
I18NCategory *err = GetI18NCategory("Error");
const char *defaultErrorAll = "Failed initializing any graphics. Try upgrading your graphics drivers.";
const char *genericError = err->T("GenericAllGraphicsError", defaultErrorAll);
std::wstring title = ConvertUTF8ToWString(err->T("GenericGraphicsError", "Graphics Error"));
MessageBox(0, ConvertUTF8ToWString(genericError).c_str(), title.c_str(), MB_OK);
// Let's continue (and probably crash) just so they have a way to keep trying.
}
host->UpdateUI();
std::string error_string;
@@ -182,6 +194,8 @@ void MainThreadFunc() {
if (yes) {
// Change the config to the alternative and restart.
g_Config.iGPUBackend = (int)nextBackend;
// Clear this to ensure we try their selection.
g_Config.sFailedGPUBackends.clear();
g_Config.Save();
W32Util::ExitAndRestart();
+39 -101
View File
@@ -31,7 +31,6 @@
#include "Windows/GEDebugger/TabVertices.h"
#include "Windows/W32Util/ShellUtil.h"
#include "Windows/InputBox.h"
#include "Windows/WindowsHost.h"
#include "Windows/MainWindow.h"
#include "Windows/main.h"
#include "GPU/GPUInterface.h"
@@ -39,6 +38,7 @@
#include "GPU/Common/GPUStateUtils.h"
#include "GPU/GPUState.h"
#include "GPU/Debugger/Breakpoints.h"
#include "GPU/Debugger/Debugger.h"
#include "GPU/Debugger/Record.h"
#include "GPU/Debugger/Stepping.h"
#include <windowsx.h>
@@ -47,12 +47,9 @@
const int POPUP_SUBMENU_ID_GEDBG_PREVIEW = 10;
using namespace GPUBreakpoints;
using namespace GPUDebug;
using namespace GPUStepping;
static bool attached = false;
static BreakNextType breakNext = BREAK_NONE;
enum PrimaryDisplayType {
PRIMARY_FRAMEBUF,
PRIMARY_DEPTHBUF,
@@ -66,9 +63,6 @@ void CGEDebugger::Init() {
CGEDebugger::CGEDebugger(HINSTANCE _hInstance, HWND _hParent)
: Dialog((LPCSTR)IDD_GEDEBUGGER, _hInstance, _hParent) {
GPUBreakpoints::Init();
Core_ListenStopRequest(ForceUnpause);
// minimum size = a little more than the default
RECT windowRect;
GetWindowRect(m_hDlg, &windowRect);
@@ -129,6 +123,8 @@ CGEDebugger::CGEDebugger(HINSTANCE _hInstance, HWND _hParent)
int h = g_Config.iGEWindowH == -1 ? minHeight_ : g_Config.iGEWindowH;
MoveWindow(m_hDlg,x,y,w,h,FALSE);
SetTimer(m_hDlg, 1, USER_TIMER_MINIMUM, nullptr);
UpdateTextureLevel(textureLevel_);
}
@@ -331,6 +327,8 @@ void CGEDebugger::UpdatePrimaryPreview(const GPUgstate &state) {
bool bufferResult = false;
u32 flags = SimpleGLWindow::ALPHA_IGNORE | SimpleGLWindow::RESIZE_SHRINK_CENTER;
SetupPreviews();
primaryBuffer_ = nullptr;
if (showClut_) {
bufferResult = GPU_GetCurrentTexture(primaryBuffer_, textureLevel_);
@@ -375,6 +373,8 @@ void CGEDebugger::UpdatePrimaryPreview(const GPUgstate &state) {
void CGEDebugger::UpdateSecondPreview(const GPUgstate &state) {
bool bufferResult = false;
SetupPreviews();
secondBuffer_ = nullptr;
if (showClut_) {
bufferResult = GPU_GetCurrentClut(secondBuffer_);
@@ -417,6 +417,8 @@ void CGEDebugger::PrimaryPreviewHover(int x, int y) {
return;
}
SetupPreviews();
wchar_t desc[256] = {0};
if (!primaryWindow->HasTex()) {
@@ -639,14 +641,6 @@ void CGEDebugger::SavePosition()
}
}
void CGEDebugger::SetBreakNext(BreakNextType type) {
attached = true;
SetupPreviews();
breakNext = type;
ResumeFromStepping();
}
BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_INITDIALOG:
@@ -670,9 +664,7 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
return TRUE;
case WM_CLOSE:
attached = false;
ResumeFromStepping();
breakNext = BREAK_NONE;
GPUDebug::SetActive(false);
Show(false);
return TRUE;
@@ -687,6 +679,16 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
}
break;
case WM_TIMER:
if (GPUStepping::IsStepping()) {
static int lastCounter = 0;
if (lastCounter != GPUStepping::GetSteppingCounter()) {
UpdatePreviews();
lastCounter = GPUStepping::GetSteppingCounter();
}
}
break;
case WM_NOTIFY:
switch (wParam)
{
@@ -698,7 +700,7 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
break;
case IDC_GEDBG_FBTABS:
fbTabs->HandleNotify(lParam);
if (attached && gpuDebug != nullptr) {
if (GPUDebug::IsActive() && gpuDebug != nullptr) {
UpdatePreviews();
}
break;
@@ -708,32 +710,28 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDC_GEDBG_STEPDRAW:
SetBreakNext(BREAK_NEXT_DRAW);
SetBreakNext(BreakNext::DRAW);
break;
case IDC_GEDBG_STEP:
SetBreakNext(BREAK_NEXT_OP);
SetBreakNext(BreakNext::OP);
break;
case IDC_GEDBG_STEPTEX:
AddTextureChangeTempBreakpoint();
SetBreakNext(BREAK_NEXT_TEX);
SetBreakNext(BreakNext::TEX);
break;
case IDC_GEDBG_STEPFRAME:
SetBreakNext(BREAK_NEXT_FRAME);
SetBreakNext(BreakNext::FRAME);
break;
case IDC_GEDBG_STEPPRIM:
AddCmdBreakpoint(GE_CMD_PRIM, true);
AddCmdBreakpoint(GE_CMD_BEZIER, true);
AddCmdBreakpoint(GE_CMD_SPLINE, true);
SetBreakNext(BREAK_NEXT_PRIM);
SetBreakNext(BreakNext::PRIM);
break;
case IDC_GEDBG_BREAKTEX:
{
attached = true;
GPUDebug::SetActive(true);
if (!gpuDebug) {
break;
}
@@ -752,7 +750,7 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
case IDC_GEDBG_BREAKTARGET:
{
attached = true;
GPUDebug::SetActive(true);
if (!gpuDebug) {
break;
}
@@ -771,26 +769,26 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
case IDC_GEDBG_TEXLEVELDOWN:
UpdateTextureLevel(textureLevel_ - 1);
if (attached && gpuDebug != nullptr) {
if (GPUDebug::IsActive() && gpuDebug != nullptr) {
UpdatePreviews();
}
break;
case IDC_GEDBG_TEXLEVELUP:
UpdateTextureLevel(textureLevel_ + 1);
if (attached && gpuDebug != nullptr) {
if (GPUDebug::IsActive() && gpuDebug != nullptr) {
UpdatePreviews();
}
break;
case IDC_GEDBG_RESUME:
SetupPreviews();
primaryWindow->Clear();
secondWindow->Clear();
SetDlgItemText(m_hDlg, IDC_GEDBG_FRAMEBUFADDR, L"");
SetDlgItemText(m_hDlg, IDC_GEDBG_TEXADDR, L"");
ResumeFromStepping();
breakNext = BREAK_NONE;
SetBreakNext(BreakNext::NONE);
break;
case IDC_GEDBG_RECORD:
@@ -798,14 +796,14 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
break;
case IDC_GEDBG_FORCEOPAQUE:
if (attached && gpuDebug != nullptr) {
if (GPUDebug::IsActive() && gpuDebug != nullptr) {
forceOpaque_ = SendMessage(GetDlgItem(m_hDlg, IDC_GEDBG_FORCEOPAQUE), BM_GETCHECK, 0, 0) != 0;
UpdatePreviews();
}
break;
case IDC_GEDBG_SHOWCLUT:
if (attached && gpuDebug != nullptr) {
if (GPUDebug::IsActive() && gpuDebug != nullptr) {
showClut_ = SendMessage(GetDlgItem(m_hDlg, IDC_GEDBG_SHOWCLUT), BM_GETCHECK, 0, 0) != 0;
UpdatePreviews();
}
@@ -813,30 +811,13 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
}
break;
case WM_GEDBG_BREAK_CMD:
{
u32 pc = (u32)wParam;
ClearTempBreakpoints();
auto info = gpuDebug->DissassembleOp(pc);
NOTICE_LOG(G3D, "Waiting at %08x, %s", pc, info.desc.c_str());
UpdatePreviews();
}
break;
case WM_GEDBG_BREAK_DRAW:
{
NOTICE_LOG(G3D, "Waiting at a draw");
UpdatePreviews();
}
break;
case WM_GEDBG_STEPDISPLAYLIST:
SetBreakNext(BREAK_NEXT_OP);
SetBreakNext(BreakNext::OP);
break;
case WM_GEDBG_TOGGLEPCBREAKPOINT:
{
attached = true;
GPUDebug::SetActive(true);
u32 pc = (u32)wParam;
bool temp;
bool isBreak = IsAddressBreakpoint(pc, temp);
@@ -850,7 +831,7 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
case WM_GEDBG_RUNTOWPARAM:
{
attached = true;
GPUDebug::SetActive(true);
u32 pc = (u32)wParam;
AddAddressBreakpoint(pc, true);
SendMessage(m_hDlg,WM_COMMAND,IDC_GEDBG_RESUME,0);
@@ -858,9 +839,7 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
break;
case WM_GEDBG_SETCMDWPARAM:
{
GPU_SetCmdValue((u32)wParam);
}
GPU_SetCmdValue((u32)wParam);
break;
case WM_GEDBG_UPDATE_WATCH:
@@ -872,44 +851,3 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
return FALSE;
}
// The below WindowsHost methods are called on the GPU thread.
bool WindowsHost::GPUDebuggingActive() {
return attached;
}
static void DeliverMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
PostMessage(geDebuggerWindow->GetDlgHandle(), msg, wParam, lParam);
}
static void PauseWithMessage(UINT msg, WPARAM wParam = NULL, LPARAM lParam = NULL) {
if (attached) {
EnterStepping(std::bind(&DeliverMessage, msg, wParam, lParam));
}
}
void WindowsHost::GPUNotifyCommand(u32 pc) {
u32 op = Memory::ReadUnchecked_U32(pc);
u8 cmd = op >> 24;
if (breakNext == BREAK_NEXT_OP || IsBreakpoint(pc, op)) {
PauseWithMessage(WM_GEDBG_BREAK_CMD, (WPARAM) pc);
}
}
void WindowsHost::GPUNotifyDisplay(u32 framebuf, u32 stride, int format) {
if (breakNext == BREAK_NEXT_FRAME) {
// This should work fine, start stepping at the first op of the new frame.
breakNext = BREAK_NEXT_OP;
}
}
void WindowsHost::GPUNotifyDraw() {
if (breakNext == BREAK_NEXT_DRAW) {
PauseWithMessage(WM_GEDBG_BREAK_DRAW);
}
}
void WindowsHost::GPUNotifyTextureAttachment(u32 addr) {
}
+2 -14
View File
@@ -19,31 +19,20 @@
#include "Common/CommonWindows.h"
#include "GPU/Common/GPUDebugInterface.h"
#include "GPU/Debugger/Debugger.h"
#include "Windows/resource.h"
#include "Windows/W32Util/DialogManager.h"
#include "Windows/W32Util/TabControl.h"
#include "Windows/GEDebugger/SimpleGLWindow.h"
enum {
WM_GEDBG_BREAK_CMD = WM_USER + 200,
WM_GEDBG_BREAK_DRAW,
WM_GEDBG_STEPDISPLAYLIST,
WM_GEDBG_STEPDISPLAYLIST = WM_USER + 200,
WM_GEDBG_TOGGLEPCBREAKPOINT,
WM_GEDBG_RUNTOWPARAM,
WM_GEDBG_SETCMDWPARAM,
WM_GEDBG_UPDATE_WATCH,
};
enum BreakNextType {
BREAK_NONE,
BREAK_NEXT_OP,
BREAK_NEXT_DRAW,
BREAK_NEXT_TEX,
BREAK_NEXT_NONTEX,
BREAK_NEXT_FRAME,
BREAK_NEXT_PRIM,
};
class CtrlDisplayListView;
class TabDisplayLists;
class TabStateFlags;
@@ -76,7 +65,6 @@ private:
void HandleRedraw(int which);
void UpdateSize(WORD width, WORD height);
void SavePosition();
void SetBreakNext(BreakNextType type);
void UpdateTextureLevel(int level);
void DescribePrimaryPreview(const GPUgstate &state, wchar_t desc[256]);
void DescribeSecondPreview(const GPUgstate &state, wchar_t desc[256]);
+1
View File
@@ -145,6 +145,7 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) {
if (yes) {
// Change the config to D3D and restart.
g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D9;
g_Config.sFailedGPUBackends.clear();
g_Config.Save();
W32Util::ExitAndRestart();
+1
View File
@@ -267,6 +267,7 @@ bool WindowsGLContext::InitFromRenderThread(std::string *error_message) {
std::wstring whichD3D9 = ConvertUTF8ToWString(err->T("D3D9or11", d3d9Or11));
bool d3d9 = IDYES == MessageBox(hWnd_, whichD3D9.c_str(), title.c_str(), MB_YESNO);
g_Config.iGPUBackend = d3d9 ? (int)GPUBackend::DIRECT3D9 : (int)GPUBackend::DIRECT3D11;
g_Config.sFailedGPUBackends.clear();
g_Config.Save();
W32Util::ExitAndRestart();
+24
View File
@@ -345,6 +345,18 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\Qt\QtHost.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\UWP\UWPHost.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GPU\D3D11Context.cpp" />
<ClCompile Include="GPU\D3D9Context.cpp" />
<ClCompile Include="Debugger\BreakpointWindow.cpp" />
@@ -439,6 +451,18 @@
<ClInclude Include="..\android\jni\TestRunner.h" />
<ClInclude Include="..\ios\ViewController.h" />
<ClInclude Include="..\Qt\mainwindow.h" />
<ClInclude Include="..\Qt\QtHost.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="..\UWP\UWPHost.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="GPU\D3D11Context.h" />
<ClInclude Include="GPU\D3D9Context.h" />
<ClInclude Include="Debugger\BreakpointWindow.h" />
+12
View File
@@ -182,6 +182,12 @@
<ClCompile Include="..\android\jni\AndroidVulkanContext.cpp">
<Filter>Other Platforms</Filter>
</ClCompile>
<ClCompile Include="..\Qt\QtHost.cpp">
<Filter>Other Platforms\Qt</Filter>
</ClCompile>
<ClCompile Include="..\UWP\UWPHost.cpp">
<Filter>Other Platforms</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Debugger\CtrlDisAsmView.h">
@@ -335,6 +341,12 @@
<ClInclude Include="..\android\jni\AndroidVulkanContext.h">
<Filter>Other Platforms</Filter>
</ClInclude>
<ClInclude Include="..\Qt\QtHost.h">
<Filter>Other Platforms\Qt</Filter>
</ClInclude>
<ClInclude Include="..\UWP\UWPHost.h">
<Filter>Other Platforms</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="icon1.ico">
-5
View File
@@ -55,11 +55,6 @@ public:
void SaveSymbolMap() override;
void SetWindowTitle(const char *message) override;
bool GPUDebuggingActive() override;
void GPUNotifyCommand(u32 pc) override;
void GPUNotifyDisplay(u32 framebuf, u32 stride, int format) override;
void GPUNotifyDraw() override;
void GPUNotifyTextureAttachment(u32 addr) override;
void ToggleDebugConsoleVisibility() override;
bool CanCreateShortcut() override;
+2
View File
@@ -242,6 +242,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/GPU/Common/PostShader.cpp \
$(SRC)/GPU/Common/ShaderUniforms.cpp \
$(SRC)/GPU/Debugger/Breakpoints.cpp \
$(SRC)/GPU/Debugger/Debugger.cpp \
$(SRC)/GPU/Debugger/Record.cpp \
$(SRC)/GPU/Debugger/Stepping.cpp \
$(SRC)/GPU/GLES/FramebufferManagerGLES.cpp \
@@ -309,6 +310,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Core/Debugger/WebSocket/GameBroadcaster.cpp \
$(SRC)/Core/Debugger/WebSocket/GameSubscriber.cpp \
$(SRC)/Core/Debugger/WebSocket/GPUBufferSubscriber.cpp \
$(SRC)/Core/Debugger/WebSocket/GPURecordSubscriber.cpp \
$(SRC)/Core/Debugger/WebSocket/HLESubscriber.cpp \
$(SRC)/Core/Debugger/WebSocket/LogBroadcaster.cpp \
$(SRC)/Core/Debugger/WebSocket/SteppingBroadcaster.cpp \
@@ -54,6 +54,12 @@ public class TextRenderer {
total.x = Math.max(sz.x, total.x);
}
total.y = (int) (p.descent() - p.ascent()) * lines.length + 2;
// Returning a 0 size can create problems when the caller
// uses the measurement to create a texture.
if (total.x < 1)
total.x = 1;
if (total.y < 1)
total.y = 1;
return total;
}
@@ -67,10 +73,6 @@ public class TextRenderer {
int w = s.x;
int h = s.y;
if (w == 0)
w = 1;
if (h == 0)
h = 1;
Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
+11
View File
@@ -418,10 +418,20 @@ void CheckGLExtensions() {
} else {
g_all_egl_extensions = "";
}
#elif defined(USING_GLES2) && defined(__linux__)
const char *eglString = eglQueryString(NULL, EGL_EXTENSIONS);
if (eglString) {
g_all_egl_extensions = std::string(eglString);
g_all_egl_extensions.append(" ");
g_all_egl_extensions.append(eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS));
} else {
g_all_egl_extensions = "";
}
#endif
glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &gl_extensions.maxVertexTextureUnits);
#ifdef GL_LOW_FLOAT
// This is probably a waste of time, implementations lie.
if (gl_extensions.IsGLES || strstr(extString, "GL_ARB_ES2_compatibility") || gl_extensions.VersionGEThan(4, 1)) {
const GLint precisions[6] = {
@@ -437,6 +447,7 @@ void CheckGLExtensions() {
}
}
}
#endif
gl_extensions.ARB_framebuffer_object = strstr(extString, "GL_ARB_framebuffer_object") != 0;
gl_extensions.EXT_framebuffer_object = strstr(extString, "GL_EXT_framebuffer_object") != 0;
+1 -1
View File
@@ -5,7 +5,7 @@
void InitFastMath(int enableNEON) {
// Every architecture has its own define. This needs to be added to.
if (enableNEON) {
#if defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7S__)
#if PPSSPP_ARCH(ARM_NEON) && !PPSSPP_ARCH(ARM64)
fast_matrix_mul_4x4 = &fast_matrix_mul_4x4_neon;
#endif
}
+2
View File
@@ -18,6 +18,8 @@ extern void fast_matrix_mul_4x4_sse(float *dest, const float *a, const float *b)
#if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
// Hard link to SSE implementations on x86/amd64
#define fast_matrix_mul_4x4 fast_matrix_mul_4x4_sse
#elif PPSSPP_ARCH(ARM64)
#define fast_matrix_mul_4x4 fast_matrix_mul_4x4_c
#else
extern fptr_fast_matrix_mul_4x4 fast_matrix_mul_4x4;
#endif
+1 -1
View File
@@ -1,5 +1,5 @@
#include "ppsspp_config.h"
#if PPSSPP_ARCH(ARM) && PPSSPP_ARCH(ARM_NEON)
#if PPSSPP_ARCH(ARM_NEON) && !PPSSPP_ARCH(ARM64)
.syntax unified // Allow both ARM and Thumb-2 instructions
.text
+1 -1
View File
@@ -1166,7 +1166,7 @@ void GLQueueRunner::PerformReadbackImage(const GLRStep &pass) {
int pixelStride = pass.readback_image.srcRect.w;
glPixelStorei(GL_PACK_ALIGNMENT, 4);
GLRect2D rect = pass.readback.srcRect;
GLRect2D rect = pass.readback_image.srcRect;
int size = 4 * rect.w * rect.h;
if (size > readbackBufferSize_) {
+1 -1
View File
@@ -176,7 +176,7 @@ public:
data.draw.vbuffer = vbuffer;
data.draw.voffset = voffset;
data.draw.numUboOffsets = numUboOffsets;
assert(numUboOffsets <= ARRAY_SIZE(data.drawIndexed.uboOffsets));
assert(numUboOffsets <= ARRAY_SIZE(data.draw.uboOffsets));
for (int i = 0; i < numUboOffsets; i++)
data.draw.uboOffsets[i] = uboOffsets[i];
curRenderStep_->commands.push_back(data);
+1 -2
View File
@@ -1078,12 +1078,11 @@ InputLayout *VKContext::CreateInputLayout(const InputLayoutDesc &desc) {
}
Texture *VKContext::CreateTexture(const TextureDesc &desc) {
if (!push_) {
if (!push_ || !renderManager_.GetInitCmd()) {
// Too early! Fail.
ELOG("Can't create textures before the first frame has started.");
return nullptr;
}
_assert_(renderManager_.GetInitCmd());
return new VKTexture(vulkan_, renderManager_.GetInitCmd(), push_, desc, allocator_);
}
+2 -1
View File
@@ -168,8 +168,9 @@ SOURCES_CXX += \
$(GPUCOMMONDIR)/PostShader.cpp \
$(COMMONDIR)/ColorConv.cpp \
$(GPUDIR)/Debugger/Breakpoints.cpp \
$(GPUDIR)/Debugger/Stepping.cpp \
$(GPUDIR)/Debugger/Debugger.cpp \
$(GPUDIR)/Debugger/Record.cpp \
$(GPUDIR)/Debugger/Stepping.cpp \
$(GPUDIR)/Common/TextureCacheCommon.cpp \
$(GPUDIR)/Common/TextureScalerCommon.cpp \
$(GPUDIR)/Common/SoftwareTransformCommon.cpp \