mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 05:19:56 +00:00
Merge pull request #19561 from hrydgard/more-misc-fixes
Some checks are pending
Build / build-windows (ARM64) (push) Waiting to run
Build / build-windows (x64) (push) Waiting to run
Build / build-uwp (push) Waiting to run
Build / test-windows (push) Blocked by required conditions
Build / build (./b.sh --headless --unittest --fat --no-png --no-sdl2, clang, clang++, test, macos, macos-latest) (push) Waiting to run
Build / build (./b.sh --headless --unittest, clang, clang++, test, clang-normal, ubuntu-latest) (push) Waiting to run
Build / build (./b.sh --headless --unittest, gcc, g++, gcc-normal, ubuntu-latest) (push) Waiting to run
Build / build (./b.sh --ios, clang, clang++, ios, ios, macos-latest) (push) Waiting to run
Build / build (./b.sh --libretro_android ppsspp_libretro, clang, clang++, android, android-libretro, ubuntu-latest) (push) Waiting to run
Build / build (./b.sh --qt, gcc, g++, qt, qt, ubuntu-latest) (push) Waiting to run
Build / build (cd android && ./ab.sh -j2 APP_ABI=arm64-v8a OPENXR=1, clang, clang++, android, android-vr, ubuntu-latest) (push) Waiting to run
Build / build (cd android && ./ab.sh -j2 APP_ABI=arm64-v8a UNITTEST=1 HEADLESS=1, clang, clang++, android, android-arm64, ubuntu-latest) (push) Waiting to run
Build / build (cd android && ./ab.sh -j2 APP_ABI=armeabi-v7a UNITTEST=1 HEADLESS=1, clang, clang++, android, android-arm32, ubuntu-latest) (push) Waiting to run
Build / build (cd android && ./ab.sh -j2 APP_ABI=x86_64 UNITTEST=1 HEADLESS=1, clang, clang++, android, android-x86_64, ubuntu-latest) (push) Waiting to run
Build / build (make -C libretro -f Makefile -j2, clang, clang++, libretro, clang-libretro, ubuntu-latest) (push) Waiting to run
Build / build (make -C libretro -f Makefile -j2, gcc, g++, libretro, gcc-libretro, ubuntu-latest) (push) Waiting to run
Build / test (macos-latest) (push) Blocked by required conditions
Build / test (ubuntu-latest) (push) Blocked by required conditions
Build / build_test_headless_alpine (push) Waiting to run
Generate Docker Layer / build (push) Waiting to run
Some checks are pending
Build / build-windows (ARM64) (push) Waiting to run
Build / build-windows (x64) (push) Waiting to run
Build / build-uwp (push) Waiting to run
Build / test-windows (push) Blocked by required conditions
Build / build (./b.sh --headless --unittest --fat --no-png --no-sdl2, clang, clang++, test, macos, macos-latest) (push) Waiting to run
Build / build (./b.sh --headless --unittest, clang, clang++, test, clang-normal, ubuntu-latest) (push) Waiting to run
Build / build (./b.sh --headless --unittest, gcc, g++, gcc-normal, ubuntu-latest) (push) Waiting to run
Build / build (./b.sh --ios, clang, clang++, ios, ios, macos-latest) (push) Waiting to run
Build / build (./b.sh --libretro_android ppsspp_libretro, clang, clang++, android, android-libretro, ubuntu-latest) (push) Waiting to run
Build / build (./b.sh --qt, gcc, g++, qt, qt, ubuntu-latest) (push) Waiting to run
Build / build (cd android && ./ab.sh -j2 APP_ABI=arm64-v8a OPENXR=1, clang, clang++, android, android-vr, ubuntu-latest) (push) Waiting to run
Build / build (cd android && ./ab.sh -j2 APP_ABI=arm64-v8a UNITTEST=1 HEADLESS=1, clang, clang++, android, android-arm64, ubuntu-latest) (push) Waiting to run
Build / build (cd android && ./ab.sh -j2 APP_ABI=armeabi-v7a UNITTEST=1 HEADLESS=1, clang, clang++, android, android-arm32, ubuntu-latest) (push) Waiting to run
Build / build (cd android && ./ab.sh -j2 APP_ABI=x86_64 UNITTEST=1 HEADLESS=1, clang, clang++, android, android-x86_64, ubuntu-latest) (push) Waiting to run
Build / build (make -C libretro -f Makefile -j2, clang, clang++, libretro, clang-libretro, ubuntu-latest) (push) Waiting to run
Build / build (make -C libretro -f Makefile -j2, gcc, g++, libretro, gcc-libretro, ubuntu-latest) (push) Waiting to run
Build / test (macos-latest) (push) Blocked by required conditions
Build / test (ubuntu-latest) (push) Blocked by required conditions
Build / build_test_headless_alpine (push) Waiting to run
Generate Docker Layer / build (push) Waiting to run
Simplify reporting code (removing two threads), other minor fixes
This commit is contained in:
commit
ffb3e61ca6
@ -290,22 +290,26 @@ VFSOpenFile *ZipFileReader::OpenFileForRead(VFSFileReference *vfsReference, size
|
||||
}
|
||||
|
||||
void ZipFileReader::Rewind(VFSOpenFile *vfsOpenFile) {
|
||||
ZipFileReaderOpenFile *openFile = (ZipFileReaderOpenFile *)vfsOpenFile;
|
||||
// Close and re-open.
|
||||
zip_fclose(openFile->zf);
|
||||
openFile->zf = zip_fopen_index(zip_file_, openFile->reference->zi, 0);
|
||||
ZipFileReaderOpenFile *file = (ZipFileReaderOpenFile *)vfsOpenFile;
|
||||
_assert_(file);
|
||||
_dbg_assert_(file->zf != nullptr);
|
||||
zip_fseek(file->zf, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
size_t ZipFileReader::Read(VFSOpenFile *vfsOpenFile, void *buffer, size_t length) {
|
||||
ZipFileReaderOpenFile *file = (ZipFileReaderOpenFile *)vfsOpenFile;
|
||||
_assert_(file);
|
||||
_dbg_assert_(file->zf != nullptr);
|
||||
return zip_fread(file->zf, buffer, length);
|
||||
}
|
||||
|
||||
void ZipFileReader::CloseFile(VFSOpenFile *vfsOpenFile) {
|
||||
ZipFileReaderOpenFile *file = (ZipFileReaderOpenFile *)vfsOpenFile;
|
||||
_assert_(file);
|
||||
_dbg_assert_(file->zf != nullptr);
|
||||
zip_fclose(file->zf);
|
||||
file->zf = nullptr;
|
||||
vfsOpenFile = nullptr;
|
||||
lock_.unlock();
|
||||
delete file;
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ void ReportMessage(const char *message, ...) {
|
||||
return;
|
||||
|
||||
const int MESSAGE_BUFFER_SIZE = 65536;
|
||||
char temp[MESSAGE_BUFFER_SIZE];
|
||||
char *temp = new char [MESSAGE_BUFFER_SIZE];
|
||||
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
@ -76,6 +76,8 @@ void ReportMessage(const char *message, ...) {
|
||||
va_end(args);
|
||||
|
||||
messageCallback(message, temp);
|
||||
|
||||
delete[] temp;
|
||||
}
|
||||
|
||||
void ReportMessageFormatted(const char *message, const char *formatted) {
|
||||
|
@ -9,7 +9,8 @@
|
||||
|
||||
namespace http {
|
||||
|
||||
Request::Request(RequestMethod method, const std::string &url, std::string_view name, bool *cancelled, ProgressBarMode mode) : method_(method), url_(url), name_(name), progress_(cancelled), progressBarMode_(mode) {
|
||||
Request::Request(RequestMethod method, const std::string &url, std::string_view name, bool *cancelled, ProgressBarMode mode)
|
||||
: method_(method), url_(url), name_(name), progress_(cancelled), progressBarMode_(mode) {
|
||||
INFO_LOG(Log::HTTP, "HTTP %s request: %s (%.*s)", RequestMethodToString(method), url.c_str(), (int)name.size(), name.data());
|
||||
|
||||
progress_.callback = [=](int64_t bytes, int64_t contentLength, bool done) {
|
||||
|
@ -71,6 +71,7 @@ void Shutdown()
|
||||
#endif
|
||||
}
|
||||
|
||||
// NOTE: Due to the nature of getaddrinfo, this can block indefinitely. Not good.
|
||||
bool DNSResolve(const std::string &host, const std::string &service, addrinfo **res, std::string &error, DNSType type) {
|
||||
#if PPSSPP_PLATFORM(SWITCH)
|
||||
// Force IPv4 lookups.
|
||||
|
@ -164,7 +164,8 @@ bool ElfReader::LoadRelocations(const Elf32_Rel *rels, int numRelocs) {
|
||||
// It appears the PSP takes any relocation that is not a HI16.
|
||||
if (t_type != R_MIPS_LO16) {
|
||||
if (t_type != R_MIPS_16) {
|
||||
// Let's play it safe for now and skip. We've only seen this type.
|
||||
// Let's play it safe for now and skip. We've only seen this type.
|
||||
// These exists in some popular games like Assassin's Creed: Bloodlines and GTA: VCS: (https://report.ppsspp.org/logs/kind/1187)
|
||||
ERROR_LOG_REPORT(Log::Loader, "ELF relocation HI16/%d pair (instead of LO16) at %08x / %08x", t_type, addr, corrLoAddr);
|
||||
continue;
|
||||
} else {
|
||||
|
@ -91,8 +91,8 @@ bool JitBlock::ContainsAddress(u32 em_address) const {
|
||||
}
|
||||
|
||||
bool JitBlockCache::IsFull() const {
|
||||
// -10 to safely leave space for some proxy blocks, which we don't check before we allocate (not ideal, but should work).
|
||||
return num_blocks_ >= MAX_NUM_BLOCKS - 10;
|
||||
// Subtract some amount to safely leave space for some proxy blocks, which we don't check before we allocate (not ideal, but should be enough).
|
||||
return num_blocks_ >= MAX_NUM_BLOCKS - 512;
|
||||
}
|
||||
|
||||
void JitBlockCache::Init() {
|
||||
@ -218,7 +218,6 @@ void JitBlockCache::ProxyBlock(u32 rootAddress, u32 startAddress, u32 size, cons
|
||||
void JitBlockCache::AddBlockMap(int block_num) {
|
||||
const JitBlock &b = blocks_[block_num];
|
||||
// Convert the logical address to a physical address for the block map
|
||||
// Yeah, this'll work fine for PSP too I think.
|
||||
u32 pAddr = b.originalAddress & 0x1FFFFFFF;
|
||||
block_map_[std::make_pair(pAddr + 4 * b.originalSize, pAddr)] = block_num;
|
||||
}
|
||||
|
@ -227,7 +227,8 @@ private:
|
||||
std::pair<u32, u32> blockMemRanges_[3];
|
||||
|
||||
enum {
|
||||
MAX_NUM_BLOCKS = 65536*2
|
||||
// Where does this number come from?
|
||||
MAX_NUM_BLOCKS = 65536 * 4
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -101,7 +101,7 @@ namespace MIPSInt
|
||||
int func = (op >> 16) & 0x1F;
|
||||
|
||||
// Let's only report this once per run to be safe from impacting perf.
|
||||
static bool reportedAlignment = false;
|
||||
static bool loggedAlignment = false;
|
||||
|
||||
// It appears that a cache line is 0x40 (64) bytes, loops in games
|
||||
// issue the cache instruction at that interval.
|
||||
@ -120,9 +120,10 @@ namespace MIPSInt
|
||||
int size = 0x40 + (addr & 0x3F);
|
||||
MIPSComp::jit->InvalidateCacheAt(alignedAddr, size);
|
||||
// Using a bool to avoid locking/etc. in case it's slow.
|
||||
if (!reportedAlignment && (addr & 0x3F) != 0) {
|
||||
WARN_LOG_REPORT(Log::JIT, "Unaligned icache invalidation of %08x (%08x + %d) at PC=%08x", addr, R(rs), imm, PC);
|
||||
reportedAlignment = true;
|
||||
if (!loggedAlignment && (addr & 0x3F) != 0) {
|
||||
// These are seen exclusively in Lego games, and are really no big deal. Reporting removed.
|
||||
WARN_LOG(Log::JIT, "Unaligned icache invalidation of %08x (%08x + %d) at PC=%08x", addr, R(rs), imm, PC);
|
||||
loggedAlignment = true;
|
||||
}
|
||||
if (alignedAddr <= PC + 4 && alignedAddr + size >= PC - 4) {
|
||||
// This is probably rare so we don't use a static bool.
|
||||
|
@ -68,9 +68,6 @@ namespace Reporting
|
||||
|
||||
// Internal limiter on number of requests per instance.
|
||||
static u32 spamProtectionCount = 0;
|
||||
// Temporarily stores a reference to the hostname.
|
||||
static std::string lastHostname;
|
||||
|
||||
// Keeps track of whether a harmful setting was ever used.
|
||||
static bool everUnsupported = false;
|
||||
// Support is cached here to avoid checking it on every single request.
|
||||
@ -84,22 +81,13 @@ namespace Reporting
|
||||
static int lastModuleVersion;
|
||||
static uint32_t lastModuleCrc;
|
||||
|
||||
static std::mutex pendingMessageLock;
|
||||
static std::condition_variable pendingMessageCond;
|
||||
static std::deque<int> pendingMessages;
|
||||
static bool pendingMessagesDone = false;
|
||||
static std::thread messageThread;
|
||||
static std::thread compatThread;
|
||||
|
||||
enum class RequestType
|
||||
{
|
||||
enum class RequestType {
|
||||
NONE,
|
||||
MESSAGE,
|
||||
COMPAT,
|
||||
};
|
||||
|
||||
struct Payload
|
||||
{
|
||||
struct Payload {
|
||||
RequestType type;
|
||||
std::string string1;
|
||||
std::string string2;
|
||||
@ -107,8 +95,6 @@ namespace Reporting
|
||||
int int2;
|
||||
int int3;
|
||||
};
|
||||
static Payload payloadBuffer[PAYLOAD_BUFFER_SIZE];
|
||||
static int payloadBufferPos = 0;
|
||||
|
||||
static std::mutex crcLock;
|
||||
static std::condition_variable crcCond;
|
||||
@ -240,10 +226,9 @@ namespace Reporting
|
||||
}
|
||||
|
||||
// Returns the full host (e.g. report.ppsspp.org:80.)
|
||||
std::string ServerHost()
|
||||
{
|
||||
std::string ServerHost() {
|
||||
if (g_Config.sReportHost.compare("default") == 0)
|
||||
return "";
|
||||
return "report.ppsspp.org";
|
||||
return g_Config.sReportHost;
|
||||
}
|
||||
|
||||
@ -267,20 +252,18 @@ namespace Reporting
|
||||
}
|
||||
|
||||
// Returns only the hostname part (e.g. "report.ppsspp.org".)
|
||||
static const char *ServerHostname()
|
||||
{
|
||||
static std::string ServerHostname() {
|
||||
if (!IsEnabled())
|
||||
return NULL;
|
||||
return "";
|
||||
|
||||
std::string host = ServerHost();
|
||||
size_t length = ServerHostnameLength();
|
||||
|
||||
// This means there's no port number - it's already the hostname.
|
||||
if (length == host.npos)
|
||||
lastHostname = host;
|
||||
return host;
|
||||
else
|
||||
lastHostname = host.substr(0, length);
|
||||
return lastHostname.c_str();
|
||||
return host.substr(0, length);
|
||||
}
|
||||
|
||||
// Returns only the port part (e.g. 80) as an int.
|
||||
@ -306,36 +289,15 @@ namespace Reporting
|
||||
return ++spamProtectionCount >= SPAM_LIMIT;
|
||||
}
|
||||
|
||||
bool SendReportRequest(const char *uri, const std::string &data, const std::string &mimeType, Buffer *output = NULL)
|
||||
{
|
||||
http::Client http;
|
||||
net::RequestProgress progress(&pendingMessagesDone);
|
||||
Buffer theVoid = Buffer::Void();
|
||||
|
||||
http.SetUserAgent(StringFromFormat("PPSSPP/%s", PPSSPP_GIT_VERSION));
|
||||
|
||||
if (output == nullptr)
|
||||
output = &theVoid;
|
||||
|
||||
const char *serverHost = ServerHostname();
|
||||
if (!serverHost)
|
||||
return false;
|
||||
|
||||
if (http.Resolve(serverHost, ServerPort())) {
|
||||
int result = -1;
|
||||
if (http.Connect()) {
|
||||
result = http.POST(http::RequestParams(uri), data, mimeType, output, &progress);
|
||||
http.Disconnect();
|
||||
}
|
||||
|
||||
return result >= 200 && result < 300;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
static void SendReportRequest(const char *uri, const std::string &data, const std::string &mimeType, std::function<void(http::Request &)> callback) {
|
||||
char url[1024];
|
||||
std::string hostname = ServerHostname();
|
||||
int port = ServerPort();
|
||||
snprintf(url, sizeof(url), "http://%s:%d%s", hostname.c_str(), port, uri);
|
||||
g_DownloadManager.AsyncPostWithCallback(url, data, mimeType, http::ProgressBarMode::NONE, callback);
|
||||
}
|
||||
|
||||
std::string StripTrailingNull(const std::string &str)
|
||||
{
|
||||
std::string StripTrailingNull(const std::string &str) {
|
||||
size_t pos = str.find_first_of('\0');
|
||||
if (pos != str.npos)
|
||||
return str.substr(0, pos);
|
||||
@ -385,14 +347,12 @@ namespace Reporting
|
||||
bool MessageAllowed();
|
||||
void SendReportMessage(const char *message, const char *formatted);
|
||||
|
||||
void Init()
|
||||
{
|
||||
void Init() {
|
||||
// New game, clean slate.
|
||||
spamProtectionCount = 0;
|
||||
ResetCounts();
|
||||
everUnsupported = false;
|
||||
currentSupported = IsSupported();
|
||||
pendingMessagesDone = false;
|
||||
Reporting::SetupCallbacks(&MessageAllowed, &SendReportMessage);
|
||||
|
||||
lastModuleName.clear();
|
||||
@ -400,24 +360,14 @@ namespace Reporting
|
||||
lastModuleCrc = 0;
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
pendingMessageLock.lock();
|
||||
pendingMessagesDone = true;
|
||||
pendingMessageCond.notify_one();
|
||||
pendingMessageLock.unlock();
|
||||
if (compatThread.joinable())
|
||||
compatThread.join();
|
||||
if (messageThread.joinable())
|
||||
messageThread.join();
|
||||
void Shutdown() {
|
||||
PurgeCRC();
|
||||
|
||||
// Just so it can be enabled in the menu again.
|
||||
Init();
|
||||
}
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
void DoState(PointerWrap &p) {
|
||||
const int LATEST_VERSION = 1;
|
||||
auto s = p.Section("Reporting", 0, LATEST_VERSION);
|
||||
if (!s || s < LATEST_VERSION) {
|
||||
@ -429,8 +379,7 @@ namespace Reporting
|
||||
Do(p, everUnsupported);
|
||||
}
|
||||
|
||||
void UpdateConfig()
|
||||
{
|
||||
void UpdateConfig() {
|
||||
currentSupported = IsSupported();
|
||||
if (!currentSupported && PSP_IsInited())
|
||||
everUnsupported = true;
|
||||
@ -514,13 +463,7 @@ namespace Reporting
|
||||
}
|
||||
}
|
||||
|
||||
int Process(int pos)
|
||||
{
|
||||
SetCurrentThreadName("Report");
|
||||
|
||||
AndroidJNIThreadContext jniContext; // destructor detaches
|
||||
|
||||
Payload &payload = payloadBuffer[pos];
|
||||
int Process(const Payload &payload) {
|
||||
Buffer output;
|
||||
|
||||
MultipartFormDataEncoder postdata;
|
||||
@ -529,21 +472,18 @@ namespace Reporting
|
||||
AddConfigInfo(postdata);
|
||||
AddGameplayInfo(postdata);
|
||||
|
||||
switch (payload.type)
|
||||
{
|
||||
switch (payload.type) {
|
||||
case RequestType::MESSAGE:
|
||||
// TODO: Add CRC?
|
||||
postdata.Add("message", payload.string1);
|
||||
postdata.Add("value", payload.string2);
|
||||
// We tend to get corrupted data, this acts as a very primitive verification check.
|
||||
postdata.Add("verify", payload.string1 + payload.string2);
|
||||
payload.string1.clear();
|
||||
payload.string2.clear();
|
||||
|
||||
postdata.Finish();
|
||||
serverWorking = true;
|
||||
if (!SendReportRequest("/report/message", postdata.ToString(), postdata.GetMimeType()))
|
||||
serverWorking = false;
|
||||
SendReportRequest("/report/message", postdata.ToString(), postdata.GetMimeType(), [=](http::Request &req) {
|
||||
serverWorking = !req.Failed();
|
||||
});
|
||||
break;
|
||||
|
||||
case RequestType::COMPAT:
|
||||
@ -556,31 +496,28 @@ namespace Reporting
|
||||
postdata.Add("crc", StringFromFormat("%08x", RetrieveCRCUnlessPowerSaving(PSP_CoreParameter().fileToStart)));
|
||||
postdata.Add("suggestions", payload.string1 != "perfect" && payload.string1 != "playable" ? "1" : "0");
|
||||
AddScreenshotData(postdata, Path(payload.string2));
|
||||
payload.string1.clear();
|
||||
payload.string2.clear();
|
||||
|
||||
postdata.Finish();
|
||||
serverWorking = true;
|
||||
if (!SendReportRequest("/report/compat", postdata.ToString(), postdata.GetMimeType(), &output)) {
|
||||
serverWorking = false;
|
||||
} else {
|
||||
std::string result;
|
||||
output.TakeAll(&result);
|
||||
SendReportRequest("/report/compat", postdata.ToString(), postdata.GetMimeType(), [=](http::Request &req) {
|
||||
if (req.Failed()) {
|
||||
serverWorking = false;
|
||||
return;
|
||||
}
|
||||
serverWorking = true;
|
||||
|
||||
std::string result;
|
||||
req.buffer().TakeAll(&result);
|
||||
lastCompatResult.clear();
|
||||
if (result.empty() || result[0] == '0')
|
||||
serverWorking = false;
|
||||
else if (result[0] != '1')
|
||||
SplitString(result, '\n', lastCompatResult);
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case RequestType::NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
payload.type = RequestType::NONE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -643,56 +580,12 @@ namespace Reporting
|
||||
g_Config.sReportHost = "default";
|
||||
}
|
||||
|
||||
ReportStatus GetStatus()
|
||||
{
|
||||
ReportStatus GetStatus() {
|
||||
if (!serverWorking)
|
||||
return ReportStatus::FAILING;
|
||||
|
||||
for (int pos = 0; pos < PAYLOAD_BUFFER_SIZE; ++pos)
|
||||
{
|
||||
if (payloadBuffer[pos].type != RequestType::NONE)
|
||||
return ReportStatus::BUSY;
|
||||
}
|
||||
|
||||
return ReportStatus::WORKING;
|
||||
}
|
||||
|
||||
int NextFreePos()
|
||||
{
|
||||
int start = payloadBufferPos % PAYLOAD_BUFFER_SIZE;
|
||||
do
|
||||
{
|
||||
int pos = payloadBufferPos++ % PAYLOAD_BUFFER_SIZE;
|
||||
if (payloadBuffer[pos].type == RequestType::NONE)
|
||||
return pos;
|
||||
}
|
||||
while (payloadBufferPos != start);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ProcessPending() {
|
||||
SetCurrentThreadName("Report");
|
||||
|
||||
std::unique_lock<std::mutex> guard(pendingMessageLock);
|
||||
while (!pendingMessagesDone) {
|
||||
while (!pendingMessages.empty() && !pendingMessagesDone) {
|
||||
int pos = pendingMessages.front();
|
||||
pendingMessages.pop_front();
|
||||
|
||||
guard.unlock();
|
||||
Process(pos);
|
||||
guard.lock();
|
||||
}
|
||||
if (pendingMessagesDone) {
|
||||
break;
|
||||
}
|
||||
pendingMessageCond.wait(guard);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool MessageAllowed() {
|
||||
if (!IsEnabled() || CheckSpamLimited())
|
||||
return false;
|
||||
@ -700,33 +593,20 @@ namespace Reporting
|
||||
}
|
||||
|
||||
void SendReportMessage(const char *message, const char *formatted) {
|
||||
int pos = NextFreePos();
|
||||
if (pos == -1)
|
||||
return;
|
||||
// MessageAllowed is checked first.
|
||||
|
||||
Payload &payload = payloadBuffer[pos];
|
||||
Payload payload{};
|
||||
payload.type = RequestType::MESSAGE;
|
||||
payload.string1 = message;
|
||||
payload.string2 = formatted;
|
||||
|
||||
std::lock_guard<std::mutex> guard(pendingMessageLock);
|
||||
pendingMessages.push_back(pos);
|
||||
pendingMessageCond.notify_one();
|
||||
|
||||
if (!messageThread.joinable()) {
|
||||
messageThread = std::thread(ProcessPending);
|
||||
}
|
||||
Process(payload);
|
||||
}
|
||||
|
||||
void ReportCompatibility(const char *compat, int graphics, int speed, int gameplay, const std::string &screenshotFilename)
|
||||
{
|
||||
void ReportCompatibility(const char *compat, int graphics, int speed, int gameplay, const std::string &screenshotFilename) {
|
||||
if (!IsEnabled())
|
||||
return;
|
||||
int pos = NextFreePos();
|
||||
if (pos == -1)
|
||||
return;
|
||||
|
||||
Payload &payload = payloadBuffer[pos];
|
||||
Payload payload{};
|
||||
payload.type = RequestType::COMPAT;
|
||||
payload.string1 = compat;
|
||||
payload.string2 = screenshotFilename;
|
||||
@ -734,9 +614,7 @@ namespace Reporting
|
||||
payload.int2 = speed;
|
||||
payload.int3 = gameplay;
|
||||
|
||||
if (compatThread.joinable())
|
||||
compatThread.join();
|
||||
compatThread = std::thread(Process, pos);
|
||||
Process(payload);
|
||||
}
|
||||
|
||||
std::vector<std::string> CompatibilitySuggestions() {
|
||||
|
@ -1523,7 +1523,7 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G
|
||||
return tex;
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::DrawFramebufferToOutput(const u8 *srcPixels, int srcStride, GEBufferFormat srcPixelFormat) {
|
||||
bool FramebufferManagerCommon::DrawFramebufferToOutput(const u8 *srcPixels, int srcStride, GEBufferFormat srcPixelFormat) {
|
||||
textureCache_->ForgetLastTexture();
|
||||
shaderManager_->DirtyLastShader();
|
||||
|
||||
@ -1531,7 +1531,7 @@ void FramebufferManagerCommon::DrawFramebufferToOutput(const u8 *srcPixels, int
|
||||
float v0 = 0.0f, v1 = 1.0f;
|
||||
Draw::Texture *pixelsTex = MakePixelTexture(srcPixels, srcPixelFormat, srcStride, 512, 272);
|
||||
if (!pixelsTex)
|
||||
return;
|
||||
return false;
|
||||
|
||||
int uvRotation = useBufferedRendering_ ? g_Config.iInternalScreenRotation : ROTATION_LOCKED_HORIZONTAL;
|
||||
OutputFlags flags = g_Config.iDisplayFilter == SCALE_LINEAR ? OutputFlags::LINEAR : OutputFlags::NEAREST;
|
||||
@ -1552,6 +1552,8 @@ void FramebufferManagerCommon::DrawFramebufferToOutput(const u8 *srcPixels, int
|
||||
|
||||
DiscardFramebufferCopy();
|
||||
currentRenderVfb_ = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::SetViewport2D(int x, int y, int w, int h) {
|
||||
@ -1633,8 +1635,14 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) {
|
||||
if (!vfb) {
|
||||
if (Memory::IsValidAddress(fbaddr)) {
|
||||
// The game is displaying something directly from RAM. In GTA, it's decoded video.
|
||||
DrawFramebufferToOutput(Memory::GetPointerUnchecked(fbaddr), displayStride_, displayFormat_);
|
||||
// This effectively calls presentation_->NotifyPresent();
|
||||
// If successful, this effectively calls presentation_->NotifyPresent();
|
||||
if (!DrawFramebufferToOutput(Memory::GetPointerUnchecked(fbaddr), displayStride_, displayFormat_)) {
|
||||
if (useBufferedRendering_) {
|
||||
// Bind and clear the backbuffer. This should be the first time during the frame that it's bound.
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "CopyDisplayToOutput_DrawError");
|
||||
}
|
||||
presentation_->NotifyPresent();
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
DEBUG_LOG(Log::FrameBuf, "Found no FBO to display! displayFBPtr = %08x", fbaddr);
|
||||
|
@ -356,7 +356,7 @@ public:
|
||||
void ReadFramebufferToMemory(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel, Draw::ReadbackMode mode);
|
||||
|
||||
void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes);
|
||||
void DrawFramebufferToOutput(const u8 *srcPixels, int srcStride, GEBufferFormat srcPixelFormat);
|
||||
bool DrawFramebufferToOutput(const u8 *srcPixels, int srcStride, GEBufferFormat srcPixelFormat);
|
||||
|
||||
void DrawPixels(VirtualFramebuffer *vfb, int dstX, int dstY, const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height, RasterChannel channel, const char *tag);
|
||||
|
||||
|
@ -1349,8 +1349,7 @@ void GPUCommon::FlushImm() {
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_Unknown(u32 op, u32 diff) {
|
||||
if ((op & 0xFFFFFF) != 0)
|
||||
WARN_LOG_REPORT_ONCE(unknowncmd, Log::G3D, "Unknown GE command : %08x ", op);
|
||||
// Do nothing. We used to report here, but we're confident we have them all so no need to report unknown.
|
||||
}
|
||||
|
||||
void GPUCommon::FastLoadBoneMatrix(u32 target) {
|
||||
|
@ -535,6 +535,7 @@ void GPUCommonHW::CopyDisplayToOutput(bool reallyDirty) {
|
||||
|
||||
shaderManager_->DirtyLastShader();
|
||||
|
||||
// after this, render pass is active.
|
||||
framebufferManager_->CopyDisplayToOutput(reallyDirty);
|
||||
|
||||
gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
|
||||
|
@ -9,6 +9,7 @@ public:
|
||||
GPUCommonHW(GraphicsContext *gfxCtx, Draw::DrawContext *draw);
|
||||
~GPUCommonHW();
|
||||
|
||||
// This can fail, and if so no render pass is active.
|
||||
void CopyDisplayToOutput(bool reallyDirty) override;
|
||||
void DoState(PointerWrap &p) override;
|
||||
void DeviceLost() override;
|
||||
|
@ -1397,7 +1397,9 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
|
||||
}
|
||||
|
||||
Draw::BackendState state = draw->GetCurrentBackendState();
|
||||
_assert_msg_(!state.valid || state.passes >= 1, "skipB: %d sw: %d mode: %d back: %d tag: %s", (int)skipBufferEffects, (int)g_Config.bSoftwareRendering, (int)mode, (int)g_Config.iGPUBackend, screenManager()->topScreen()->tag());
|
||||
if (state.valid) {
|
||||
_assert_msg_(state.passes >= 1, "skipB: %d sw: %d mode: %d back: %d tag: %s", (int)skipBufferEffects, (int)g_Config.bSoftwareRendering, (int)mode, (int)g_Config.iGPUBackend, screenManager()->topScreen()->tag());
|
||||
}
|
||||
|
||||
// Need to make sure the UI texture is available, for "darken".
|
||||
screenManager()->getUIContext()->BeginFrame();
|
||||
@ -1523,8 +1525,10 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
|
||||
|
||||
Draw::BackendState state = draw->GetCurrentBackendState();
|
||||
|
||||
// We allow if !state.valid, that means it's not the Vulkan backend.
|
||||
_assert_msg_(!state.valid || state.passes >= 1, "skipB: %d sw: %d mode: %d back: %d bound: %d", (int)skipBufferEffects, (int)g_Config.bSoftwareRendering, (int)mode, (int)g_Config.iGPUBackend, (int)framebufferBound);
|
||||
// State.valid just states whether the passes parameter has a meaningful value.
|
||||
if (state.valid) {
|
||||
_assert_msg_(state.passes >= 1, "skipB: %d sw: %d mode: %d back: %d bound: %d", (int)skipBufferEffects, (int)g_Config.bSoftwareRendering, (int)mode, (int)g_Config.iGPUBackend, (int)framebufferBound);
|
||||
}
|
||||
|
||||
screenManager()->getUIContext()->BeginFrame();
|
||||
|
||||
|
@ -168,7 +168,7 @@ ReportScreen::ReportScreen(const Path &gamePath) // unused gamePath, after remo
|
||||
|
||||
ScreenRenderFlags ReportScreen::render(ScreenRenderMode mode) {
|
||||
_dbg_assert_(mode & ScreenRenderMode::FIRST);
|
||||
_dbg_assert_(mode & ScreenRenderMode::TOP);
|
||||
// _dbg_assert_(mode & ScreenRenderMode::TOP);
|
||||
|
||||
if (mode & ScreenRenderMode::TOP) {
|
||||
// We do this after render because we need it to be within the frame (so the screenshot works).
|
||||
|
Loading…
Reference in New Issue
Block a user