diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4b0206f664..25505d597c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -588,8 +588,10 @@ add_library(Common STATIC
Common/Data/Random/Rng.h
Common/File/VFS/VFS.h
Common/File/VFS/VFS.cpp
- Common/File/VFS/AssetReader.cpp
- Common/File/VFS/AssetReader.h
+ Common/File/VFS/ZipFileReader.cpp
+ Common/File/VFS/ZipFileReader.h
+ Common/File/VFS/DirectoryReader.cpp
+ Common/File/VFS/DirectoryReader.h
Common/File/AndroidStorage.h
Common/File/AndroidStorage.cpp
Common/File/DiskFree.h
@@ -1150,7 +1152,7 @@ elseif(IOS AND NOT LIBRETRO)
UI/DarwinFileSystemServices.h
Common/Battery/AppleBatteryClient.m
)
-
+
set(nativeExtraLibs ${nativeExtraLibs} "-framework Foundation -framework MediaPlayer -framework AudioToolbox -framework CoreGraphics -framework QuartzCore -framework UIKit -framework GLKit -framework OpenAL -framework AVFoundation -framework CoreLocation -framework CoreVideo -framework CoreMedia -framework CoreServices" )
if(EXISTS "${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks/GameController.framework")
set(nativeExtraLibs ${nativeExtraLibs} "-weak_framework GameController")
@@ -1188,7 +1190,15 @@ elseif(USING_QT_UI)
if(USING_GLES2)
add_definitions(-DQT_OPENGL_ES -DQT_OPENGL_ES_2)
endif()
-
+ if(APPLE)
+ list(APPEND NativeAppSource
+ UI/DarwinFileSystemServices.mm
+ UI/DarwinFileSystemServices.h
+ Common/Battery/AppleBatteryClient.m)
+ set_source_files_properties(Common/Battery/AppleBatteryClient.m PROPERTIES COMPILE_FLAGS -fobjc-arc)
+ set_source_files_properties(UI/DarwinFileSystemServices.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
+ set(nativeExtraLibs ${nativeExtraLibs} ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${IOKIT_LIBRARY})
+ endif()
include_directories(Qt)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
set(nativeExtraLibs ${nativeExtraLibs} Qt5::OpenGL Qt5::Gui Qt5::Core Qt5::Multimedia)
@@ -1346,7 +1356,7 @@ if(LINUX AND NOT ANDROID)
endif()
set(ATOMIC_LIB)
-if(ANDROID OR (LINUX AND ARM_DEVICE))
+if(ANDROID OR (LINUX AND ARM_DEVICE) OR (LINUX AND RISCV64))
set(ATOMIC_LIB atomic)
endif()
@@ -1629,6 +1639,10 @@ set(GPU_SOURCES
GPU/Common/TextureScalerCommon.h
GPU/Common/PostShader.cpp
GPU/Common/PostShader.h
+ GPU/Common/TextureReplacer.cpp
+ GPU/Common/TextureReplacer.h
+ GPU/Common/ReplacedTexture.cpp
+ GPU/Common/ReplacedTexture.h
GPU/Debugger/Breakpoints.cpp
GPU/Debugger/Breakpoints.h
GPU/Debugger/Debugger.cpp
@@ -1651,6 +1665,8 @@ set(GPU_SOURCES
GPU/GPU.h
GPU/GPUCommon.cpp
GPU/GPUCommon.h
+ GPU/GPUCommonHW.cpp
+ GPU/GPUCommonHW.h
GPU/GPUState.cpp
GPU/GPUState.h
GPU/Math3D.cpp
@@ -2035,8 +2051,6 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/Screenshot.h
Core/System.cpp
Core/System.h
- Core/TextureReplacer.cpp
- Core/TextureReplacer.h
Core/ThreadPools.cpp
Core/ThreadPools.h
Core/Util/AudioFormat.cpp
diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj
index 451e8dd426..8557f133d3 100644
--- a/Common/Common.vcxproj
+++ b/Common/Common.vcxproj
@@ -425,8 +425,9 @@
+
-
+
@@ -861,8 +862,9 @@
+
-
+
diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters
index 3c0a310aff..0f40093153 100644
--- a/Common/Common.vcxproj.filters
+++ b/Common/Common.vcxproj.filters
@@ -176,9 +176,6 @@
File\VFS
-
- File\VFS
-
Data\Format
@@ -467,6 +464,12 @@
GPU\OpenGL
+
+ File\VFS
+
+
+ File\VFS
+
@@ -628,9 +631,6 @@
File\VFS
-
- File\VFS
-
Data\Format
@@ -884,6 +884,12 @@
GPU\OpenGL
+
+ File\VFS
+
+
+ File\VFS
+
diff --git a/Common/Data/Format/IniFile.cpp b/Common/Data/Format/IniFile.cpp
index 72aeee6f89..91c042d5b4 100644
--- a/Common/Data/Format/IniFile.cpp
+++ b/Common/Data/Format/IniFile.cpp
@@ -567,9 +567,9 @@ bool IniFile::Load(const Path &path)
return success;
}
-bool IniFile::LoadFromVFS(const std::string &filename) {
+bool IniFile::LoadFromVFS(VFSInterface &vfs, const std::string &filename) {
size_t size;
- uint8_t *data = VFSReadFile(filename.c_str(), &size);
+ uint8_t *data = vfs.ReadFile(filename.c_str(), &size);
if (!data)
return false;
std::string str((const char*)data, size);
@@ -582,10 +582,10 @@ bool IniFile::LoadFromVFS(const std::string &filename) {
bool IniFile::Load(std::istream &in) {
// Maximum number of letters in a line
static const int MAX_BYTES = 1024*32;
+ char *templine = new char[MAX_BYTES]; // avoid using up massive stack space
while (!(in.eof() || in.fail()))
{
- char templine[MAX_BYTES];
in.getline(templine, MAX_BYTES);
std::string line = templine;
@@ -624,6 +624,7 @@ bool IniFile::Load(std::istream &in) {
}
}
+ delete[] templine;
return true;
}
diff --git a/Common/Data/Format/IniFile.h b/Common/Data/Format/IniFile.h
index 707f0ab3eb..1008fff5df 100644
--- a/Common/Data/Format/IniFile.h
+++ b/Common/Data/Format/IniFile.h
@@ -11,6 +11,8 @@
#include "Common/File/Path.h"
+class VFSInterface;
+
class Section {
friend class IniFile;
@@ -86,7 +88,7 @@ public:
bool Load(const Path &path);
bool Load(const std::string &filename) { return Load(Path(filename)); }
bool Load(std::istream &istream);
- bool LoadFromVFS(const std::string &filename);
+ bool LoadFromVFS(VFSInterface &vfs, const std::string &filename);
bool Save(const Path &path);
bool Save(const std::string &filename) { return Save(Path(filename)); }
diff --git a/Common/Data/Format/JSONReader.cpp b/Common/Data/Format/JSONReader.cpp
index 9c2128e6ef..b65381d986 100644
--- a/Common/Data/Format/JSONReader.cpp
+++ b/Common/Data/Format/JSONReader.cpp
@@ -8,7 +8,7 @@ namespace json {
JsonReader::JsonReader(const std::string &filename) {
size_t buf_size;
- buffer_ = (char *)VFSReadFile(filename.c_str(), &buf_size);
+ buffer_ = (char *)g_VFS.ReadFile(filename.c_str(), &buf_size);
if (buffer_) {
parse();
} else {
diff --git a/Common/Data/Format/PNGLoad.cpp b/Common/Data/Format/PNGLoad.cpp
index 0174b156fe..b2ed18f99b 100644
--- a/Common/Data/Format/PNGLoad.cpp
+++ b/Common/Data/Format/PNGLoad.cpp
@@ -59,3 +59,14 @@ int pngLoadPtr(const unsigned char *input_ptr, size_t input_len, int *pwidth, in
png_image_finish_read(&png, NULL, *image_data_ptr, stride, NULL);
return 1;
}
+
+bool PNGHeaderPeek::IsValidPNGHeader() const {
+ if (magic != 0x474e5089 || ihdrTag != 0x52444849) {
+ return false;
+ }
+ // Reject crazy sized images, too.
+ if (Width() > 32768 && Height() > 32768) {
+ return false;
+ }
+ return true;
+}
diff --git a/Common/Data/Format/PNGLoad.h b/Common/Data/Format/PNGLoad.h
index 48eaf6a1db..76ab04ee9e 100644
--- a/Common/Data/Format/PNGLoad.h
+++ b/Common/Data/Format/PNGLoad.h
@@ -1,5 +1,8 @@
-#ifndef _PNG_LOAD_H
-#define _PNG_LOAD_H
+#pragma once
+
+#include
+
+#include "Common/BitSet.h"
// *image_data_ptr should be deleted with free()
// return value of 1 == success.
@@ -9,4 +12,22 @@ int pngLoad(const char *file, int *pwidth,
int pngLoadPtr(const unsigned char *input_ptr, size_t input_len, int *pwidth,
int *pheight, unsigned char **image_data_ptr);
-#endif // _PNG_LOAD_H
+// PNG peeker - just read the start of a PNG straight into this struct, in order to
+// look at basic parameters like width and height. Note that while PNG is a chunk-based
+// format, the IHDR chunk is REQUIRED to be the first one, so this will work.
+// Does not handle Apple's weirdo extension CgBI. http://iphonedevwiki.net/index.php/CgBI_file_format
+// That should not be an issue.
+struct PNGHeaderPeek {
+ uint32_t magic;
+ uint32_t ignore0;
+ uint32_t ignore1;
+ uint32_t ihdrTag;
+ uint32_t be_width; // big endian
+ uint32_t be_height;
+ uint8_t bitDepth; // bits per channel, can be 1, 2, 4, 8, 16
+ uint8_t colorType; // really, pixel format. 0 = grayscale, 2 = rgb, 3 = palette index, 4 = gray+alpha, 6 = rgba
+
+ bool IsValidPNGHeader() const;
+ int Width() const { return swap32(be_width); }
+ int Height() const { return swap32(be_height); }
+};
diff --git a/Common/Data/Format/ZIMLoad.cpp b/Common/Data/Format/ZIMLoad.cpp
index 3fd759e92c..9a145afbe1 100644
--- a/Common/Data/Format/ZIMLoad.cpp
+++ b/Common/Data/Format/ZIMLoad.cpp
@@ -126,7 +126,7 @@ int LoadZIMPtr(const uint8_t *zim, size_t datasize, int *width, int *height, int
int LoadZIM(const char *filename, int *width, int *height, int *format, uint8_t **image) {
size_t size;
- uint8_t *buffer = VFSReadFile(filename, &size);
+ uint8_t *buffer = g_VFS.ReadFile(filename, &size);
if (!buffer) {
ERROR_LOG(IO, "Couldn't read data for '%s'", filename);
return 0;
diff --git a/Common/Data/Text/I18n.cpp b/Common/Data/Text/I18n.cpp
index 9c222da8b8..ab5509dcbd 100644
--- a/Common/Data/Text/I18n.cpp
+++ b/Common/Data/Text/I18n.cpp
@@ -73,7 +73,7 @@ Path I18NRepo::GetIniPath(const std::string &languageID) const {
bool I18NRepo::IniExists(const std::string &languageID) const {
File::FileInfo info;
- if (!VFSGetFileInfo(GetIniPath(languageID).ToString().c_str(), &info))
+ if (!g_VFS.GetFileInfo(GetIniPath(languageID).ToString().c_str(), &info))
return false;
if (!info.exists)
return false;
@@ -91,7 +91,7 @@ bool I18NRepo::LoadIni(const std::string &languageID, const Path &overridePath)
iniPath = GetIniPath(languageID);
}
- if (!ini.LoadFromVFS(iniPath.ToString()))
+ if (!ini.LoadFromVFS(g_VFS, iniPath.ToString()))
return false;
Clear();
@@ -127,7 +127,7 @@ I18NCategory *I18NRepo::LoadSection(const Section *section, const char *name) {
return cat;
}
-// This is a very light touched save variant - it won't overwrite
+// This is a very light touched save variant - it won't overwrite
// anything, only create new entries.
void I18NRepo::SaveIni(const std::string &languageID) {
IniFile ini;
diff --git a/Common/File/AndroidStorage.cpp b/Common/File/AndroidStorage.cpp
index ec8248947b..c4ddcc73c1 100644
--- a/Common/File/AndroidStorage.cpp
+++ b/Common/File/AndroidStorage.cpp
@@ -1,3 +1,5 @@
+#include
+
#include "Common/File/AndroidStorage.h"
#include "Common/StringUtils.h"
#include "Common/Log.h"
diff --git a/Common/File/DirListing.h b/Common/File/DirListing.h
index c53d420588..4ad9ce0c3e 100644
--- a/Common/File/DirListing.h
+++ b/Common/File/DirListing.h
@@ -2,10 +2,8 @@
#include
#include
-
#include
-
-#include
+#include
#include "Common/File/Path.h"
diff --git a/Common/File/VFS/AssetReader.cpp b/Common/File/VFS/AssetReader.cpp
deleted file mode 100644
index 306cd0c5e0..0000000000
--- a/Common/File/VFS/AssetReader.cpp
+++ /dev/null
@@ -1,204 +0,0 @@
-#include
-#include
-#include
-#include
-
-#ifdef __ANDROID__
-#include
-#endif
-
-#include "Common/Common.h"
-#include "Common/Log.h"
-#include "Common/File/VFS/AssetReader.h"
-
-#ifdef __ANDROID__
-uint8_t *ReadFromZip(zip *archive, const char* filename, size_t *size) {
- // Figure out the file size first.
- struct zip_stat zstat;
- zip_file *file = zip_fopen(archive, filename, ZIP_FL_NOCASE|ZIP_FL_UNCHANGED);
- if (!file) {
- ERROR_LOG(IO, "Error opening %s from ZIP", filename);
- return 0;
- }
- zip_stat(archive, filename, ZIP_FL_NOCASE|ZIP_FL_UNCHANGED, &zstat);
-
- uint8_t *contents = new uint8_t[zstat.size + 1];
- zip_fread(file, contents, zstat.size);
- zip_fclose(file);
- contents[zstat.size] = 0;
-
- *size = zstat.size;
- return contents;
-}
-
-#endif
-
-#ifdef __ANDROID__
-
-ZipAssetReader::ZipAssetReader(const char *zip_file, const char *in_zip_path) {
- zip_file_ = zip_open(zip_file, 0, NULL);
- strcpy(in_zip_path_, in_zip_path);
- if (!zip_file_) {
- ERROR_LOG(IO, "Failed to open %s as a zip file", zip_file);
- }
-
- std::vector info;
- GetFileListing("assets", &info, 0);
- for (size_t i = 0; i < info.size(); i++) {
- if (info[i].isDirectory) {
- DEBUG_LOG(IO, "Directory: %s", info[i].name.c_str());
- } else {
- DEBUG_LOG(IO, "File: %s", info[i].name.c_str());
- }
- }
-}
-
-ZipAssetReader::~ZipAssetReader() {
- std::lock_guard guard(lock_);
- zip_close(zip_file_);
-}
-
-uint8_t *ZipAssetReader::ReadAsset(const char *path, size_t *size) {
- char temp_path[1024];
- strcpy(temp_path, in_zip_path_);
- strcat(temp_path, path);
-
- std::lock_guard guard(lock_);
- return ReadFromZip(zip_file_, temp_path, size);
-}
-
-bool ZipAssetReader::GetFileListing(const char *orig_path, std::vector *listing, const char *filter = 0) {
- char path[1024];
- strcpy(path, in_zip_path_);
- strcat(path, orig_path);
-
- std::set filters;
- std::string tmp;
- if (filter) {
- while (*filter) {
- if (*filter == ':') {
- filters.insert("." + tmp);
- tmp.clear();
- } else {
- tmp.push_back(*filter);
- }
- filter++;
- }
- }
- if (tmp.size())
- filters.insert("." + tmp);
-
- // We just loop through the whole ZIP file and deduce what files are in this directory, and what subdirectories there are.
- std::set files;
- std::set directories;
- GetZipListings(path, files, directories);
-
- for (auto diter = directories.begin(); diter != directories.end(); ++diter) {
- File::FileInfo info;
- info.name = *diter;
-
- // Remove the "inzip" part of the fullname.
- info.fullName = Path(std::string(path).substr(strlen(in_zip_path_))) / *diter;
- info.exists = true;
- info.isWritable = false;
- info.isDirectory = true;
- listing->push_back(info);
- }
-
- for (auto fiter = files.begin(); fiter != files.end(); ++fiter) {
- std::string fpath = path;
- File::FileInfo info;
- info.name = *fiter;
- info.fullName = Path(std::string(path).substr(strlen(in_zip_path_))) / *fiter;
- info.exists = true;
- info.isWritable = false;
- info.isDirectory = false;
- std::string ext = info.fullName.GetFileExtension();
- if (filter) {
- if (filters.find(ext) == filters.end()) {
- continue;
- }
- }
- listing->push_back(info);
- }
-
- std::sort(listing->begin(), listing->end());
- return true;
-}
-
-void ZipAssetReader::GetZipListings(const char *path, std::set &files, std::set &directories) {
- size_t pathlen = strlen(path);
- if (path[pathlen - 1] == '/')
- pathlen--;
-
- std::lock_guard guard(lock_);
- int numFiles = zip_get_num_files(zip_file_);
- for (int i = 0; i < numFiles; i++) {
- const char* name = zip_get_name(zip_file_, i, 0);
- if (!name)
- continue;
- if (!memcmp(name, path, pathlen)) {
- // The prefix is right. Let's see if this is a file or path.
- const char *slashPos = strchr(name + pathlen + 1, '/');
- if (slashPos != 0) {
- // A directory.
- std::string dirName = std::string(name + pathlen + 1, slashPos - (name + pathlen + 1));
- directories.insert(dirName);
- } else if (name[pathlen] == '/') {
- const char *fn = name + pathlen + 1;
- files.insert(std::string(fn));
- } // else, it was a file with the same prefix as the path. like langregion.ini next to lang/.
- }
- }
-}
-
-bool ZipAssetReader::GetFileInfo(const char *path, File::FileInfo *info) {
- struct zip_stat zstat;
- char temp_path[1024];
- strcpy(temp_path, in_zip_path_);
- strcat(temp_path, path);
- if (0 != zip_stat(zip_file_, temp_path, ZIP_FL_NOCASE|ZIP_FL_UNCHANGED, &zstat)) {
- // ZIP files do not have real directories, so we'll end up here if we
- // try to stat one. For now that's fine.
- info->exists = false;
- info->size = 0;
- return false;
- }
-
- info->fullName = Path(path);
- info->exists = true; // TODO
- info->isWritable = false;
- info->isDirectory = false; // TODO
- info->size = zstat.size;
- return true;
-}
-
-#endif
-
-DirectoryAssetReader::DirectoryAssetReader(const Path &path) {
- path_ = path;
-}
-
-uint8_t *DirectoryAssetReader::ReadAsset(const char *path, size_t *size) {
- Path new_path = Path(path).StartsWith(path_) ? Path(path) : path_ / path;
- return File::ReadLocalFile(new_path, size);
-}
-
-bool DirectoryAssetReader::GetFileListing(const char *path, std::vector *listing, const char *filter = nullptr) {
- Path new_path = Path(path).StartsWith(path_) ? Path(path) : path_ / path;
-
- File::FileInfo info;
- if (!File::GetFileInfo(new_path, &info))
- return false;
-
- if (info.isDirectory) {
- File::GetFilesInDir(new_path, listing, filter);
- return true;
- }
- return false;
-}
-
-bool DirectoryAssetReader::GetFileInfo(const char *path, File::FileInfo *info) {
- Path new_path = Path(path).StartsWith(path_) ? Path(path) : path_ / path;
- return File::GetFileInfo(new_path, info);
-}
diff --git a/Common/File/VFS/AssetReader.h b/Common/File/VFS/AssetReader.h
deleted file mode 100644
index 8352f8eea8..0000000000
--- a/Common/File/VFS/AssetReader.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// TODO: Move much of this code to vfs.cpp
-#pragma once
-
-#ifdef __ANDROID__
-#include
-#endif
-
-#include
-#include
-#include
-#include
-
-#include "Common/File/VFS/VFS.h"
-#include "Common/File/FileUtil.h"
-#include "Common/File/Path.h"
-
-class AssetReader {
-public:
- virtual ~AssetReader() {}
- // use delete[]
- virtual uint8_t *ReadAsset(const char *path, size_t *size) = 0;
- // Filter support is optional but nice to have
- virtual bool GetFileListing(const char *path, std::vector *listing, const char *filter = 0) = 0;
- virtual bool GetFileInfo(const char *path, File::FileInfo *info) = 0;
- virtual std::string toString() const = 0;
-};
-
-#ifdef __ANDROID__
-uint8_t *ReadFromZip(zip *archive, const char* filename, size_t *size);
-class ZipAssetReader : public AssetReader {
-public:
- ZipAssetReader(const char *zip_file, const char *in_zip_path);
- ~ZipAssetReader();
- // use delete[]
- uint8_t *ReadAsset(const char *path, size_t *size) override;
- bool GetFileListing(const char *path, std::vector *listing, const char *filter) override;
- bool GetFileInfo(const char *path, File::FileInfo *info) override;
- std::string toString() const override {
- return in_zip_path_;
- }
-
-private:
- void GetZipListings(const char *path, std::set &files, std::set &directories);
-
- zip *zip_file_;
- std::mutex lock_;
- char in_zip_path_[256];
-};
-#endif
-
-class DirectoryAssetReader : public AssetReader {
-public:
- explicit DirectoryAssetReader(const Path &path);
- // use delete[]
- uint8_t *ReadAsset(const char *path, size_t *size) override;
- bool GetFileListing(const char *path, std::vector *listing, const char *filter) override;
- bool GetFileInfo(const char *path, File::FileInfo *info) override;
- std::string toString() const override {
- return path_.ToString();
- }
-
-private:
- Path path_;
-};
-
diff --git a/Common/File/VFS/DirectoryReader.cpp b/Common/File/VFS/DirectoryReader.cpp
new file mode 100644
index 0000000000..981dff905b
--- /dev/null
+++ b/Common/File/VFS/DirectoryReader.cpp
@@ -0,0 +1,99 @@
+#include
+
+#include "Common/Common.h"
+#include "Common/Log.h"
+#include "Common/File/VFS/DirectoryReader.h"
+
+DirectoryReader::DirectoryReader(const Path &path) {
+ path_ = path;
+}
+
+uint8_t *DirectoryReader::ReadFile(const char *path, size_t *size) {
+ Path new_path = Path(path).StartsWith(path_) ? Path(path) : path_ / path;
+ return File::ReadLocalFile(new_path, size);
+}
+
+bool DirectoryReader::GetFileListing(const char *path, std::vector *listing, const char *filter = nullptr) {
+ Path new_path = Path(path).StartsWith(path_) ? Path(path) : path_ / path;
+
+ File::FileInfo info;
+ if (!File::GetFileInfo(new_path, &info))
+ return false;
+
+ if (info.isDirectory) {
+ File::GetFilesInDir(new_path, listing, filter);
+ return true;
+ }
+ return false;
+}
+
+bool DirectoryReader::GetFileInfo(const char *path, File::FileInfo *info) {
+ Path new_path = Path(path).StartsWith(path_) ? Path(path) : path_ / path;
+ return File::GetFileInfo(new_path, info);
+}
+
+class DirectoryReaderFileReference : public VFSFileReference {
+public:
+ Path path;
+};
+
+class DirectoryReaderOpenFile : public VFSOpenFile {
+public:
+ ~DirectoryReaderOpenFile() {
+ _dbg_assert_(file == nullptr);
+ }
+ FILE *file = nullptr;
+};
+
+VFSFileReference *DirectoryReader::GetFile(const char *path) {
+ Path filePath = path_ / path;
+ if (!File::Exists(filePath)) {
+ return nullptr;
+ }
+
+ DirectoryReaderFileReference *reference = new DirectoryReaderFileReference();
+ reference->path = filePath;
+ return reference;
+}
+
+bool DirectoryReader::GetFileInfo(VFSFileReference *vfsReference, File::FileInfo *fileInfo) {
+ DirectoryReaderFileReference *reference = (DirectoryReaderFileReference *)vfsReference;
+ return File::GetFileInfo(reference->path, fileInfo);
+}
+
+void DirectoryReader::ReleaseFile(VFSFileReference *vfsReference) {
+ DirectoryReaderFileReference *reference = (DirectoryReaderFileReference *)vfsReference;
+ delete reference;
+}
+
+VFSOpenFile *DirectoryReader::OpenFileForRead(VFSFileReference *vfsReference, size_t *size) {
+ DirectoryReaderFileReference *reference = (DirectoryReaderFileReference *)vfsReference;
+ FILE *file = File::OpenCFile(reference->path, "rb");
+ if (!file) {
+ return nullptr;
+ }
+ fseek(file, 0, SEEK_END);
+ *size = ftell(file);
+ fseek(file, 0, SEEK_SET);
+ DirectoryReaderOpenFile *openFile = new DirectoryReaderOpenFile();
+ openFile->file = file;
+ return openFile;
+}
+
+void DirectoryReader::Rewind(VFSOpenFile *vfsOpenFile) {
+ DirectoryReaderOpenFile *openFile = (DirectoryReaderOpenFile *)vfsOpenFile;
+ fseek(openFile->file, 0, SEEK_SET);
+}
+
+size_t DirectoryReader::Read(VFSOpenFile *vfsOpenFile, void *buffer, size_t length) {
+ DirectoryReaderOpenFile *openFile = (DirectoryReaderOpenFile *)vfsOpenFile;
+ return fread(buffer, 1, length, openFile->file);
+}
+
+void DirectoryReader::CloseFile(VFSOpenFile *vfsOpenFile) {
+ DirectoryReaderOpenFile *openFile = (DirectoryReaderOpenFile *)vfsOpenFile;
+ _dbg_assert_(openFile->file != nullptr);
+ fclose(openFile->file);
+ openFile->file = nullptr;
+ delete openFile;
+}
diff --git a/Common/File/VFS/DirectoryReader.h b/Common/File/VFS/DirectoryReader.h
new file mode 100644
index 0000000000..f742c6b3da
--- /dev/null
+++ b/Common/File/VFS/DirectoryReader.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include "Common/File/VFS/VFS.h"
+#include "Common/File/FileUtil.h"
+#include "Common/File/Path.h"
+
+class DirectoryReader : public VFSBackend {
+public:
+ explicit DirectoryReader(const Path &path);
+ // use delete[] on the returned value.
+ uint8_t *ReadFile(const char *path, size_t *size) override;
+
+ VFSFileReference *GetFile(const char *path) override;
+ bool GetFileInfo(VFSFileReference *vfsReference, File::FileInfo *fileInfo) override;
+ void ReleaseFile(VFSFileReference *vfsReference) override;
+
+ VFSOpenFile *OpenFileForRead(VFSFileReference *vfsReference, size_t *size) override;
+ void Rewind(VFSOpenFile *vfsOpenFile) override;
+ size_t Read(VFSOpenFile *vfsOpenFile, void *buffer, size_t length) override;
+ void CloseFile(VFSOpenFile *vfsOpenFile) override;
+
+ bool GetFileListing(const char *path, std::vector *listing, const char *filter) override;
+ bool GetFileInfo(const char *path, File::FileInfo *info) override;
+ std::string toString() const override {
+ return path_.ToString();
+ }
+
+private:
+ Path path_;
+};
diff --git a/Common/File/VFS/VFS.cpp b/Common/File/VFS/VFS.cpp
index cf347dcf44..260a6b007a 100644
--- a/Common/File/VFS/VFS.cpp
+++ b/Common/File/VFS/VFS.cpp
@@ -1,28 +1,26 @@
+#include
+
#include "Common/Log.h"
#include "Common/File/VFS/VFS.h"
-#include "Common/File/VFS/AssetReader.h"
+#include "Common/File/FileUtil.h"
#include "Common/File/AndroidStorage.h"
-struct VFSEntry {
- const char *prefix;
- AssetReader *reader;
-};
+VFS g_VFS;
-static VFSEntry entries[16];
-static int num_entries = 0;
-
-void VFSRegister(const char *prefix, AssetReader *reader) {
- entries[num_entries].prefix = prefix;
- entries[num_entries].reader = reader;
- DEBUG_LOG(IO, "Registered VFS for prefix %s: %s", prefix, reader->toString().c_str());
- num_entries++;
+void VFS::Register(const char *prefix, VFSBackend *reader) {
+ if (reader) {
+ entries_.push_back(VFSEntry{ prefix, reader });
+ DEBUG_LOG(IO, "Registered VFS for prefix %s: %s", prefix, reader->toString().c_str());
+ } else {
+ ERROR_LOG(IO, "Trying to register null VFS backend for prefix %s", prefix);
+ }
}
-void VFSShutdown() {
- for (int i = 0; i < num_entries; i++) {
- delete entries[i].reader;
+void VFS::Clear() {
+ for (auto &entry : entries_) {
+ delete entry.reader;
}
- num_entries = 0;
+ entries_.clear();
}
// TODO: Use Path more.
@@ -38,7 +36,7 @@ static bool IsLocalAbsolutePath(const char *path) {
}
// The returned data should be free'd with delete[].
-uint8_t *VFSReadFile(const char *filename, size_t *size) {
+uint8_t *VFS::ReadFile(const char *filename, size_t *size) {
if (IsLocalAbsolutePath(filename)) {
// Local path, not VFS.
// INFO_LOG(IO, "Not a VFS path: %s . Reading local file.", filename);
@@ -47,13 +45,13 @@ uint8_t *VFSReadFile(const char *filename, size_t *size) {
int fn_len = (int)strlen(filename);
bool fileSystemFound = false;
- for (int i = 0; i < num_entries; i++) {
- int prefix_len = (int)strlen(entries[i].prefix);
+ for (const auto &entry : entries_) {
+ int prefix_len = (int)strlen(entry.prefix);
if (prefix_len >= fn_len) continue;
- if (0 == memcmp(filename, entries[i].prefix, prefix_len)) {
+ if (0 == memcmp(filename, entry.prefix, prefix_len)) {
fileSystemFound = true;
// INFO_LOG(IO, "Prefix match: %s (%s) -> %s", entries[i].prefix, filename, filename + prefix_len);
- uint8_t *data = entries[i].reader->ReadAsset(filename + prefix_len, size);
+ uint8_t *data = entry.reader->ReadFile(filename + prefix_len, size);
if (data)
return data;
else
@@ -67,7 +65,7 @@ uint8_t *VFSReadFile(const char *filename, size_t *size) {
return 0;
}
-bool VFSGetFileListing(const char *path, std::vector *listing, const char *filter) {
+bool VFS::GetFileListing(const char *path, std::vector *listing, const char *filter) {
if (IsLocalAbsolutePath(path)) {
// Local path, not VFS.
// INFO_LOG(IO, "Not a VFS path: %s . Reading local directory.", path);
@@ -77,12 +75,12 @@ bool VFSGetFileListing(const char *path, std::vector *listing, c
int fn_len = (int)strlen(path);
bool fileSystemFound = false;
- for (int i = 0; i < num_entries; i++) {
- int prefix_len = (int)strlen(entries[i].prefix);
+ for (const auto &entry : entries_) {
+ int prefix_len = (int)strlen(entry.prefix);
if (prefix_len >= fn_len) continue;
- if (0 == memcmp(path, entries[i].prefix, prefix_len)) {
+ if (0 == memcmp(path, entry.prefix, prefix_len)) {
fileSystemFound = true;
- if (entries[i].reader->GetFileListing(path + prefix_len, listing, filter)) {
+ if (entry.reader->GetFileListing(path + prefix_len, listing, filter)) {
return true;
}
}
@@ -94,7 +92,7 @@ bool VFSGetFileListing(const char *path, std::vector *listing, c
return false;
}
-bool VFSGetFileInfo(const char *path, File::FileInfo *info) {
+bool VFS::GetFileInfo(const char *path, File::FileInfo *info) {
if (IsLocalAbsolutePath(path)) {
// Local path, not VFS.
// INFO_LOG(IO, "Not a VFS path: %s . Getting local file info.", path);
@@ -103,19 +101,19 @@ bool VFSGetFileInfo(const char *path, File::FileInfo *info) {
bool fileSystemFound = false;
int fn_len = (int)strlen(path);
- for (int i = 0; i < num_entries; i++) {
- int prefix_len = (int)strlen(entries[i].prefix);
+ for (const auto &entry : entries_) {
+ int prefix_len = (int)strlen(entry.prefix);
if (prefix_len >= fn_len) continue;
- if (0 == memcmp(path, entries[i].prefix, prefix_len)) {
+ if (0 == memcmp(path, entry.prefix, prefix_len)) {
fileSystemFound = true;
- if (entries[i].reader->GetFileInfo(path + prefix_len, info))
+ if (entry.reader->GetFileInfo(path + prefix_len, info))
return true;
else
continue;
}
}
if (!fileSystemFound) {
- ERROR_LOG(IO, "Missing filesystem for %s", path);
+ ERROR_LOG(IO, "Missing filesystem for '%s'", path);
} // Otherwise, the file was just missing. No need to log.
return false;
}
diff --git a/Common/File/VFS/VFS.h b/Common/File/VFS/VFS.h
index 0f7e03c3fa..5d585e309e 100644
--- a/Common/File/VFS/VFS.h
+++ b/Common/File/VFS/VFS.h
@@ -1,21 +1,82 @@
#pragma once
#include
+#include
#include "Common/File/DirListing.h"
-// Basic virtual file system. Used to manage assets on Android, where we have to
+// Basic read-only virtual file system. Used to manage assets on Android, where we have to
// read them manually out of the APK zipfile, while being able to run on other
// platforms as well with the appropriate directory set-up.
-class AssetReader;
+// Note that this is kinda similar in concept to Core/MetaFileSystem.h, but that one
+// is specifically for operations done by the emulated PSP, while this is for operations
+// on the system level, like loading assets, and maybe texture packs. Also, as mentioned,
+// this one is read-only, so a bit smaller and simpler.
-void VFSRegister(const char *prefix, AssetReader *reader);
-void VFSShutdown();
+// VFSBackend instances can be used on their own, without the VFS, to serve as an abstraction of
+// a single directory or ZIP file.
-// Use delete [] to release the returned memory.
-// Always allocates an extra zero byte at the end, so that it
-// can be used for text like shader sources.
-uint8_t *VFSReadFile(const char *filename, size_t *size);
-bool VFSGetFileListing(const char *path, std::vector *listing, const char *filter = 0);
-bool VFSGetFileInfo(const char *filename, File::FileInfo *fileInfo);
+// The VFSFileReference level of abstraction is there to hold things like zip file indices,
+// for fast re-open etc.
+
+class VFSFileReference {
+public:
+ virtual ~VFSFileReference() {}
+};
+
+class VFSOpenFile {
+public:
+ virtual ~VFSOpenFile() {}
+};
+
+// Common interface parts between VFSBackend and VFS.
+// Sometimes you don't need the VFS multiplexing and only have a VFSBackend *, sometimes you do need it,
+// and it would be cool to be able to use the same interface, like when loading INI files.
+class VFSInterface {
+public:
+ virtual ~VFSInterface() {}
+ virtual uint8_t *ReadFile(const char *path, size_t *size) = 0;
+ virtual bool GetFileListing(const char *path, std::vector *listing, const char *filter = nullptr) = 0;
+};
+
+class VFSBackend : public VFSInterface {
+public:
+ virtual VFSFileReference *GetFile(const char *path) = 0;
+ virtual bool GetFileInfo(VFSFileReference *vfsReference, File::FileInfo *fileInfo) = 0;
+ virtual void ReleaseFile(VFSFileReference *vfsReference) = 0;
+
+ // Must write the size of the file to *size. Both backends can do this efficiently here,
+ // avoiding a call to GetFileInfo.
+ virtual VFSOpenFile *OpenFileForRead(VFSFileReference *vfsReference, size_t *size) = 0;
+ virtual void Rewind(VFSOpenFile *vfsOpenFile) = 0;
+ virtual size_t Read(VFSOpenFile *vfsOpenFile, void *buffer, size_t length) = 0;
+ virtual void CloseFile(VFSOpenFile *vfsOpenFile) = 0;
+
+ // Filter support is optional but nice to have
+ virtual bool GetFileInfo(const char *path, File::FileInfo *info) = 0;
+ virtual std::string toString() const = 0;
+};
+
+class VFS : public VFSInterface {
+public:
+ ~VFS() { Clear(); }
+ void Register(const char *prefix, VFSBackend *reader);
+ void Clear();
+
+ // Use delete [] to release the returned memory.
+ // Always allocates an extra zero byte at the end, so that it
+ // can be used for text like shader sources.
+ uint8_t *ReadFile(const char *filename, size_t *size) override;
+ bool GetFileInfo(const char *filename, File::FileInfo *fileInfo);
+ bool GetFileListing(const char *path, std::vector *listing, const char *filter = nullptr) override;
+
+private:
+ struct VFSEntry {
+ const char *prefix;
+ VFSBackend *reader;
+ };
+ std::vector entries_;
+};
+
+extern VFS g_VFS;
diff --git a/Common/File/VFS/ZipFileReader.cpp b/Common/File/VFS/ZipFileReader.cpp
new file mode 100644
index 0000000000..d4e4f69e66
--- /dev/null
+++ b/Common/File/VFS/ZipFileReader.cpp
@@ -0,0 +1,281 @@
+#include
+#include
+#include
+#include
+#include
+
+#ifdef SHARED_LIBZIP
+#include
+#else
+#include "ext/libzip/zip.h"
+#endif
+
+#include "Common/Common.h"
+#include "Common/Log.h"
+#include "Common/File/VFS/ZipFileReader.h"
+#include "Common/StringUtils.h"
+
+ZipFileReader *ZipFileReader::Create(const Path &zipFile, const char *inZipPath) {
+ int error = 0;
+ zip *zip_file;
+ if (zipFile.Type() == PathType::CONTENT_URI) {
+ int fd = File::OpenFD(zipFile, File::OPEN_READ);
+ if (!fd) {
+ ERROR_LOG(IO, "Failed to open FD for %s as zip file", zipFile.c_str());
+ return nullptr;
+ }
+ zip_file = zip_fdopen(fd, 0, &error);
+ } else {
+ zip_file = zip_open(zipFile.c_str(), 0, &error);
+ }
+
+ if (!zip_file) {
+ ERROR_LOG(IO, "Failed to open %s as a zip file", zipFile.c_str());
+ return nullptr;
+ }
+
+ ZipFileReader *reader = new ZipFileReader();
+ reader->zip_file_ = zip_file;
+ truncate_cpy(reader->inZipPath_, inZipPath);
+ return reader;
+}
+
+ZipFileReader::~ZipFileReader() {
+ std::lock_guard guard(lock_);
+ zip_close(zip_file_);
+}
+
+uint8_t *ZipFileReader::ReadFile(const char *path, size_t *size) {
+ char temp_path[2048];
+ snprintf(temp_path, sizeof(temp_path), "%s%s", inZipPath_, path);
+
+ std::lock_guard guard(lock_);
+ // Figure out the file size first.
+ struct zip_stat zstat;
+ zip_stat(zip_file_, temp_path, ZIP_FL_NOCASE | ZIP_FL_UNCHANGED, &zstat);
+ zip_file *file = zip_fopen(zip_file_, temp_path, ZIP_FL_NOCASE | ZIP_FL_UNCHANGED);
+ if (!file) {
+ ERROR_LOG(IO, "Error opening %s from ZIP", temp_path);
+ return 0;
+ }
+ uint8_t *contents = new uint8_t[zstat.size + 1];
+ zip_fread(file, contents, zstat.size);
+ zip_fclose(file);
+ contents[zstat.size] = 0;
+
+ *size = zstat.size;
+ return contents;
+}
+
+bool ZipFileReader::GetFileListing(const char *orig_path, std::vector *listing, const char *filter = 0) {
+ char path[2048];
+ snprintf(path, sizeof(path), "%s%s", inZipPath_, orig_path);
+
+ std::set filters;
+ std::string tmp;
+ if (filter) {
+ while (*filter) {
+ if (*filter == ':') {
+ filters.insert("." + tmp);
+ tmp.clear();
+ } else {
+ tmp.push_back(*filter);
+ }
+ filter++;
+ }
+ }
+
+ if (tmp.size())
+ filters.insert("." + tmp);
+
+ // We just loop through the whole ZIP file and deduce what files are in this directory, and what subdirectories there are.
+ std::set files;
+ std::set directories;
+ GetZipListings(path, files, directories);
+
+ for (auto diter = directories.begin(); diter != directories.end(); ++diter) {
+ File::FileInfo info;
+ info.name = *diter;
+
+ // Remove the "inzip" part of the fullname.
+ info.fullName = Path(std::string(path).substr(strlen(inZipPath_))) / *diter;
+ info.exists = true;
+ info.isWritable = false;
+ info.isDirectory = true;
+ listing->push_back(info);
+ }
+
+ for (auto fiter = files.begin(); fiter != files.end(); ++fiter) {
+ std::string fpath = path;
+ File::FileInfo info;
+ info.name = *fiter;
+ info.fullName = Path(std::string(path).substr(strlen(inZipPath_))) / *fiter;
+ info.exists = true;
+ info.isWritable = false;
+ info.isDirectory = false;
+ std::string ext = info.fullName.GetFileExtension();
+ if (filter) {
+ if (filters.find(ext) == filters.end()) {
+ continue;
+ }
+ }
+ listing->push_back(info);
+ }
+
+ std::sort(listing->begin(), listing->end());
+ return true;
+}
+
+void ZipFileReader::GetZipListings(const char *path, std::set &files, std::set &directories) {
+ size_t pathlen = strlen(path);
+ if (path[pathlen - 1] == '/')
+ pathlen--;
+
+ std::lock_guard guard(lock_);
+ int numFiles = zip_get_num_files(zip_file_);
+ for (int i = 0; i < numFiles; i++) {
+ const char* name = zip_get_name(zip_file_, i, 0);
+ if (!name)
+ continue;
+ if (!memcmp(name, path, pathlen)) {
+ // The prefix is right. Let's see if this is a file or path.
+ const char *slashPos = strchr(name + pathlen + 1, '/');
+ if (slashPos != 0) {
+ // A directory.
+ std::string dirName = std::string(name + pathlen + 1, slashPos - (name + pathlen + 1));
+ directories.insert(dirName);
+ } else if (name[pathlen] == '/') {
+ const char *fn = name + pathlen + 1;
+ files.insert(std::string(fn));
+ } // else, it was a file with the same prefix as the path. like langregion.ini next to lang/.
+ }
+ }
+}
+
+bool ZipFileReader::GetFileInfo(const char *path, File::FileInfo *info) {
+ struct zip_stat zstat;
+ char temp_path[1024];
+ snprintf(temp_path, sizeof(temp_path), "%s%s", inZipPath_, path);
+
+ // Clear some things to start.
+ info->isDirectory = false;
+ info->isWritable = false;
+ info->size = 0;
+
+ {
+ std::lock_guard guard(lock_);
+ if (0 != zip_stat(zip_file_, temp_path, ZIP_FL_NOCASE | ZIP_FL_UNCHANGED, &zstat)) {
+ // ZIP files do not have real directories, so we'll end up here if we
+ // try to stat one. For now that's fine.
+ info->exists = false;
+ return false;
+ }
+ }
+
+ // Zips usually don't contain directory entries, but they may.
+ if ((zstat.valid & ZIP_STAT_NAME) != 0 && zstat.name) {
+ info->isDirectory = zstat.name[strlen(zstat.name) - 1] == '/';
+ }
+ if ((zstat.valid & ZIP_STAT_SIZE) != 0) {
+ info->size = zstat.size;
+ }
+
+ info->fullName = Path(path);
+ info->exists = true;
+ return true;
+}
+
+class ZipFileReaderFileReference : public VFSFileReference {
+public:
+ int zi;
+};
+
+class ZipFileReaderOpenFile : public VFSOpenFile {
+public:
+ ~ZipFileReaderOpenFile() {
+ // Needs to be closed properly and unlocked.
+ _dbg_assert_(zf == nullptr);
+ }
+ ZipFileReaderFileReference *reference;
+ zip_file_t *zf = nullptr;
+};
+
+VFSFileReference *ZipFileReader::GetFile(const char *path) {
+ std::lock_guard guard(lock_);
+ int zi = zip_name_locate(zip_file_, path, ZIP_FL_NOCASE);
+ if (zi < 0) {
+ // Not found.
+ return nullptr;
+ }
+ ZipFileReaderFileReference *ref = new ZipFileReaderFileReference();
+ ref->zi = zi;
+ return ref;
+}
+
+bool ZipFileReader::GetFileInfo(VFSFileReference *vfsReference, File::FileInfo *fileInfo) {
+ ZipFileReaderFileReference *reference = (ZipFileReaderFileReference *)vfsReference;
+ // If you crash here, you called this while having the lock held by having the file open.
+ // Don't do that, check the info before you open the file.
+ std::lock_guard guard(lock_);
+ zip_stat_t zstat;
+ if (zip_stat_index(zip_file_, reference->zi, 0, &zstat) != 0)
+ return false;
+ *fileInfo = File::FileInfo{};
+ fileInfo->size = 0;
+ if (zstat.valid & ZIP_STAT_SIZE)
+ fileInfo->size = zstat.size;
+ return zstat.size;
+}
+
+void ZipFileReader::ReleaseFile(VFSFileReference *vfsReference) {
+ ZipFileReaderFileReference *reference = (ZipFileReaderFileReference *)vfsReference;
+ // Don't do anything other than deleting it.
+ delete reference;
+}
+
+VFSOpenFile *ZipFileReader::OpenFileForRead(VFSFileReference *vfsReference, size_t *size) {
+ ZipFileReaderFileReference *reference = (ZipFileReaderFileReference *)vfsReference;
+ ZipFileReaderOpenFile *openFile = new ZipFileReaderOpenFile();
+ openFile->reference = reference;
+ *size = 0;
+ // We only allow one file to be open for read concurrently. It's possible that this can be improved,
+ // especially if we only access by index like this.
+ lock_.lock();
+ zip_stat_t zstat;
+ if (zip_stat_index(zip_file_, reference->zi, 0, &zstat) != 0) {
+ lock_.unlock();
+ return nullptr;
+ }
+
+ openFile->zf = zip_fopen_index(zip_file_, reference->zi, 0);
+ if (!openFile->zf) {
+ WARN_LOG(G3D, "File with index %d not found in zip", reference->zi);
+ lock_.unlock();
+ return nullptr;
+ }
+
+ *size = zstat.size;
+ // Intentionally leaving the mutex locked, will be closed in CloseFile.
+ return openFile;
+}
+
+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);
+}
+
+size_t ZipFileReader::Read(VFSOpenFile *vfsOpenFile, void *buffer, size_t length) {
+ ZipFileReaderOpenFile *file = (ZipFileReaderOpenFile *)vfsOpenFile;
+ return zip_fread(file->zf, buffer, length);
+}
+
+void ZipFileReader::CloseFile(VFSOpenFile *vfsOpenFile) {
+ ZipFileReaderOpenFile *file = (ZipFileReaderOpenFile *)vfsOpenFile;
+ _dbg_assert_(file->zf != nullptr);
+ zip_fclose(file->zf);
+ file->zf = nullptr;
+ lock_.unlock();
+ delete file;
+}
diff --git a/Common/File/VFS/ZipFileReader.h b/Common/File/VFS/ZipFileReader.h
new file mode 100644
index 0000000000..f39058beed
--- /dev/null
+++ b/Common/File/VFS/ZipFileReader.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#ifdef SHARED_LIBZIP
+#include
+#else
+#include "ext/libzip/zip.h"
+#endif
+
+#include
+#include
+#include
+
+#include "Common/File/VFS/VFS.h"
+#include "Common/File/FileUtil.h"
+#include "Common/File/Path.h"
+
+class ZipFileReader : public VFSBackend {
+public:
+ static ZipFileReader *Create(const Path &zipFile, const char *inZipPath);
+ ~ZipFileReader();
+
+ bool IsValid() const { return zip_file_ != nullptr; }
+
+ // use delete[] on the returned value.
+ uint8_t *ReadFile(const char *path, size_t *size) override;
+
+ VFSFileReference *GetFile(const char *path) override;
+ bool GetFileInfo(VFSFileReference *vfsReference, File::FileInfo *fileInfo) override;
+ void ReleaseFile(VFSFileReference *vfsReference) override;
+
+ VFSOpenFile *OpenFileForRead(VFSFileReference *vfsReference, size_t *size) override;
+ void Rewind(VFSOpenFile *vfsOpenFile) override;
+ size_t Read(VFSOpenFile *vfsOpenFile, void *buffer, size_t length) override;
+ void CloseFile(VFSOpenFile *vfsOpenFile) override;
+
+ bool GetFileListing(const char *path, std::vector *listing, const char *filter) override;
+ bool GetFileInfo(const char *path, File::FileInfo *info) override;
+ std::string toString() const override {
+ return inZipPath_;
+ }
+
+private:
+ void GetZipListings(const char *path, std::set &files, std::set &directories);
+
+ zip *zip_file_ = nullptr;
+ std::mutex lock_;
+ char inZipPath_[256];
+};
diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp
index c0fcb9afbb..120f8db5ea 100644
--- a/Common/GPU/D3D11/thin3d_d3d11.cpp
+++ b/Common/GPU/D3D11/thin3d_d3d11.cpp
@@ -112,7 +112,7 @@ public:
// Raster state
void SetScissorRect(int left, int top, int width, int height) override;
- void SetViewports(int count, Viewport *viewports) override;
+ void SetViewport(const Viewport &viewport) override;
void SetBlendFactor(float color[4]) override {
if (memcmp(blendFactor_, color, sizeof(float) * 4)) {
memcpy(blendFactor_, color, sizeof(float) * 4);
@@ -420,20 +420,18 @@ void D3D11DrawContext::EndFrame() {
curPipeline_ = nullptr;
}
-void D3D11DrawContext::SetViewports(int count, Viewport *viewports) {
- D3D11_VIEWPORT vp[4];
- for (int i = 0; i < count; i++) {
- DisplayRect rc{ viewports[i].TopLeftX , viewports[i].TopLeftY, viewports[i].Width, viewports[i].Height };
- if (curRenderTargetView_ == bbRenderTargetView_) // Only the backbuffer is actually rotated wrong!
- RotateRectToDisplay(rc, curRTWidth_, curRTHeight_);
- vp[i].TopLeftX = rc.x;
- vp[i].TopLeftY = rc.y;
- vp[i].Width = rc.w;
- vp[i].Height = rc.h;
- vp[i].MinDepth = viewports[i].MinDepth;
- vp[i].MaxDepth = viewports[i].MaxDepth;
- }
- context_->RSSetViewports(count, vp);
+void D3D11DrawContext::SetViewport(const Viewport &viewport) {
+ DisplayRect rc{ viewport.TopLeftX , viewport.TopLeftY, viewport.Width, viewport.Height };
+ if (curRenderTargetView_ == bbRenderTargetView_) // Only the backbuffer is actually rotated wrong!
+ RotateRectToDisplay(rc, curRTWidth_, curRTHeight_);
+ D3D11_VIEWPORT vp;
+ vp.TopLeftX = rc.x;
+ vp.TopLeftY = rc.y;
+ vp.Width = rc.w;
+ vp.Height = rc.h;
+ vp.MinDepth = viewport.MinDepth;
+ vp.MaxDepth = viewport.MaxDepth;
+ context_->RSSetViewports(1, &vp);
}
void D3D11DrawContext::SetScissorRect(int left, int top, int width, int height) {
diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp
index b0116c875a..b130aae436 100644
--- a/Common/GPU/D3D9/thin3d_d3d9.cpp
+++ b/Common/GPU/D3D9/thin3d_d3d9.cpp
@@ -573,7 +573,7 @@ public:
// Raster state
void SetScissorRect(int left, int top, int width, int height) override;
- void SetViewports(int count, Viewport *viewports) override;
+ void SetViewport(const Viewport &viewport) override;
void SetBlendFactor(float color[4]) override;
void SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) override;
@@ -1173,12 +1173,12 @@ void D3D9Context::SetScissorRect(int left, int top, int width, int height) {
dxstate.scissorTest.set(true);
}
-void D3D9Context::SetViewports(int count, Viewport *viewports) {
- int x = (int)viewports[0].TopLeftX;
- int y = (int)viewports[0].TopLeftY;
- int w = (int)viewports[0].Width;
- int h = (int)viewports[0].Height;
- dxstate.viewport.set(x, y, w, h, viewports[0].MinDepth, viewports[0].MaxDepth);
+void D3D9Context::SetViewport(const Viewport &viewport) {
+ int x = (int)viewport.TopLeftX;
+ int y = (int)viewport.TopLeftY;
+ int w = (int)viewport.Width;
+ int h = (int)viewport.Height;
+ dxstate.viewport.set(x, y, w, h, viewport.MinDepth, viewport.MaxDepth);
}
void D3D9Context::SetBlendFactor(float color[4]) {
diff --git a/Common/GPU/OpenGL/GLSLProgram.cpp b/Common/GPU/OpenGL/GLSLProgram.cpp
index 45b098d714..fc5698085e 100644
--- a/Common/GPU/OpenGL/GLSLProgram.cpp
+++ b/Common/GPU/OpenGL/GLSLProgram.cpp
@@ -102,7 +102,7 @@ bool glsl_recompile(GLSLProgram *program, std::string *error_message) {
if (!program->vshader_source && !vsh_src) {
size_t sz;
- vsh_src.reset((char *)VFSReadFile(program->vshader_filename, &sz));
+ vsh_src.reset((char *)g_VFS.ReadFile(program->vshader_filename, &sz));
}
if (!program->vshader_source && !vsh_src) {
ERROR_LOG(G3D, "File missing: %s", program->vshader_filename);
@@ -113,7 +113,7 @@ bool glsl_recompile(GLSLProgram *program, std::string *error_message) {
}
if (!program->fshader_source && !fsh_src) {
size_t sz;
- fsh_src.reset((char *)VFSReadFile(program->fshader_filename, &sz));
+ fsh_src.reset((char *)g_VFS.ReadFile(program->fshader_filename, &sz));
}
if (!program->fshader_source && !fsh_src) {
ERROR_LOG(G3D, "File missing: %s", program->fshader_filename);
diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp
index ca539f1f17..5cb85ac9c7 100644
--- a/Common/GPU/OpenGL/thin3d_gl.cpp
+++ b/Common/GPU/OpenGL/thin3d_gl.cpp
@@ -385,9 +385,9 @@ public:
renderManager_.SetScissor({ left, top, width, height });
}
- void SetViewports(int count, Viewport *viewports) override {
+ void SetViewport(const Viewport &viewport) override {
// Same structure, different name.
- renderManager_.SetViewport((GLRViewport &)*viewports);
+ renderManager_.SetViewport((GLRViewport &)viewport);
}
void SetBlendFactor(float color[4]) override {
diff --git a/Common/GPU/Vulkan/VulkanContext.cpp b/Common/GPU/Vulkan/VulkanContext.cpp
index 6768602852..032fc128f6 100644
--- a/Common/GPU/Vulkan/VulkanContext.cpp
+++ b/Common/GPU/Vulkan/VulkanContext.cpp
@@ -535,7 +535,7 @@ int VulkanContext::GetBestPhysicalDevice() {
void VulkanContext::ChooseDevice(int physical_device) {
physical_device_ = physical_device;
- INFO_LOG(G3D, "Chose physical device %d: %p", physical_device, physical_devices_[physical_device]);
+ INFO_LOG(G3D, "Chose physical device %d: %s", physical_device, physicalDeviceProperties_[physical_device].properties.deviceName);
GetDeviceLayerProperties();
if (!CheckLayers(device_layer_properties_, device_layer_names_)) {
@@ -711,7 +711,9 @@ VkResult VulkanContext::CreateDevice() {
} else {
VulkanLoadDeviceFunctions(device_, extensionsLookup_);
}
- INFO_LOG(G3D, "Vulkan Device created");
+ INFO_LOG(G3D, "Vulkan Device created: %s", physicalDeviceProperties_[physical_device_].properties.deviceName);
+
+ // Since we successfully created a device (however we got here, might be interesting in debug), we force the choice to be visible in the menu.
VulkanSetAvailable(true);
VmaAllocatorCreateInfo allocatorInfo = {};
@@ -1288,8 +1290,8 @@ bool VulkanContext::InitSwapchain() {
VkSurfaceTransformFlagBitsKHR preTransform;
std::string supportedTransforms = surface_transforms_to_string(surfCapabilities_.supportedTransforms);
std::string currentTransform = surface_transforms_to_string(surfCapabilities_.currentTransform);
- g_display_rotation = DisplayRotation::ROTATE_0;
- g_display_rot_matrix.setIdentity();
+ g_display.rotation = DisplayRotation::ROTATE_0;
+ g_display.rot_matrix.setIdentity();
uint32_t allowedRotations = VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR;
// Hack: Don't allow 270 degrees pretransform (inverse landscape), it creates bizarre issues on some devices (see #15773).
@@ -1300,20 +1302,20 @@ bool VulkanContext::InitSwapchain() {
} else if (surfCapabilities_.currentTransform & allowedRotations) {
// Normal, sensible rotations. Let's handle it.
preTransform = surfCapabilities_.currentTransform;
- g_display_rot_matrix.setIdentity();
+ g_display.rot_matrix.setIdentity();
switch (surfCapabilities_.currentTransform) {
case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
- g_display_rotation = DisplayRotation::ROTATE_90;
- g_display_rot_matrix.setRotationZ90();
+ g_display.rotation = DisplayRotation::ROTATE_90;
+ g_display.rot_matrix.setRotationZ90();
std::swap(swapChainExtent_.width, swapChainExtent_.height);
break;
case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
- g_display_rotation = DisplayRotation::ROTATE_180;
- g_display_rot_matrix.setRotationZ180();
+ g_display.rotation = DisplayRotation::ROTATE_180;
+ g_display.rot_matrix.setRotationZ180();
break;
case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
- g_display_rotation = DisplayRotation::ROTATE_270;
- g_display_rot_matrix.setRotationZ270();
+ g_display.rotation = DisplayRotation::ROTATE_270;
+ g_display.rot_matrix.setRotationZ270();
std::swap(swapChainExtent_.width, swapChainExtent_.height);
break;
default:
diff --git a/Common/GPU/Vulkan/VulkanContext.h b/Common/GPU/Vulkan/VulkanContext.h
index 4cc097b758..21dbaad08e 100644
--- a/Common/GPU/Vulkan/VulkanContext.h
+++ b/Common/GPU/Vulkan/VulkanContext.h
@@ -222,7 +222,8 @@ public:
// Simple workaround for the casting warning.
template
void SetDebugName(T handle, VkObjectType type, const char *name) {
- if (extensionsLookup_.EXT_debug_utils) {
+ if (extensionsLookup_.EXT_debug_utils && handle != VK_NULL_HANDLE) {
+ _dbg_assert_(handle != VK_NULL_HANDLE);
SetDebugNameImpl((uint64_t)handle, type, name);
}
}
diff --git a/Common/GPU/Vulkan/VulkanDebug.cpp b/Common/GPU/Vulkan/VulkanDebug.cpp
index 4daf41bdf7..29a71cf61e 100644
--- a/Common/GPU/Vulkan/VulkanDebug.cpp
+++ b/Common/GPU/Vulkan/VulkanDebug.cpp
@@ -62,6 +62,12 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugUtilsCallback(
// See https://github.com/hrydgard/ppsspp/pull/16354
return false;
}
+ if (messageCode == -375211665) {
+ // VUID-vkAllocateMemory-pAllocateInfo-01713
+ // Can happen when VMA aggressively tries to allocate aperture memory for upload. It gracefully
+ // falls back to regular video memory, so we just ignore this. I'd argue this is a VMA bug, actually.
+ return false;
+ }
int count;
{
diff --git a/Common/GPU/Vulkan/VulkanLoader.cpp b/Common/GPU/Vulkan/VulkanLoader.cpp
index 2a00ed9622..5dd7baf4f6 100644
--- a/Common/GPU/Vulkan/VulkanLoader.cpp
+++ b/Common/GPU/Vulkan/VulkanLoader.cpp
@@ -310,6 +310,7 @@ static void VulkanFreeLibrary(VulkanLibraryHandle &h) {
}
void VulkanSetAvailable(bool available) {
+ INFO_LOG(G3D, "Forcing Vulkan availability to true");
g_vulkanAvailabilityChecked = true;
g_vulkanMayBeAvailable = available;
}
@@ -470,6 +471,7 @@ bool VulkanMayBeAvailable() {
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
anyGood = true;
+ INFO_LOG(G3D, "VulkanMayBeAvailable: Eligible device found: '%s'", props.deviceName);
break;
default:
INFO_LOG(G3D, "VulkanMayBeAvailable: Ineligible device found and ignored: '%s'", props.deviceName);
@@ -494,8 +496,9 @@ bail:
}
if (lib) {
VulkanFreeLibrary(lib);
- } else {
- ERROR_LOG(G3D, "Vulkan with working device not detected.");
+ }
+ if (!g_vulkanMayBeAvailable) {
+ WARN_LOG(G3D, "Vulkan with working device not detected.");
}
return g_vulkanMayBeAvailable;
}
diff --git a/Common/GPU/Vulkan/VulkanLoader.h b/Common/GPU/Vulkan/VulkanLoader.h
index 85b4bb5510..f85a09f558 100644
--- a/Common/GPU/Vulkan/VulkanLoader.h
+++ b/Common/GPU/Vulkan/VulkanLoader.h
@@ -33,6 +33,11 @@
#include "ext/vulkan/vulkan.h"
+// Hacky X11 header workaround
+#ifdef Opposite
+#undef Opposite
+#endif
+
namespace PPSSPP_VK {
// Putting our own Vulkan function pointers in a namespace ensures that ppsspp_libretro.so doesn't collide with libvulkan.so.
extern PFN_vkCreateInstance vkCreateInstance;
diff --git a/Common/GPU/Vulkan/VulkanMemory.cpp b/Common/GPU/Vulkan/VulkanMemory.cpp
index d8184098a5..9a25e5cbb0 100644
--- a/Common/GPU/Vulkan/VulkanMemory.cpp
+++ b/Common/GPU/Vulkan/VulkanMemory.cpp
@@ -18,6 +18,9 @@
// Additionally, Common/Vulkan/* , including this file, are also licensed
// under the public domain.
+#include
+#include
+
#include "Common/Math/math_util.h"
#include "Common/Log.h"
@@ -26,17 +29,41 @@
using namespace PPSSPP_VK;
+// Global push buffer tracker for vulkan memory profiling.
+// Don't want to manually dig up all the active push buffers.
+static std::mutex g_pushBufferListMutex;
+static std::set g_pushBuffers;
+
VulkanPushBuffer::VulkanPushBuffer(VulkanContext *vulkan, const char *name, size_t size, VkBufferUsageFlags usage, PushBufferType type)
: vulkan_(vulkan), name_(name), size_(size), usage_(usage), type_(type) {
+ {
+ std::lock_guard guard(g_pushBufferListMutex);
+ g_pushBuffers.insert(this);
+ }
+
bool res = AddBuffer();
_assert_(res);
}
VulkanPushBuffer::~VulkanPushBuffer() {
+ {
+ std::lock_guard guard(g_pushBufferListMutex);
+ g_pushBuffers.erase(this);
+ }
+
_dbg_assert_(!writePtr_);
_assert_(buffers_.empty());
}
+std::vector VulkanPushBuffer::GetAllActive() {
+ std::vector buffers;
+ std::lock_guard guard(g_pushBufferListMutex);
+ for (auto iter : g_pushBuffers) {
+ buffers.push_back(iter);
+ }
+ return buffers;
+}
+
bool VulkanPushBuffer::AddBuffer() {
BufInfo info;
VkDevice device = vulkan_->GetDevice();
@@ -122,6 +149,10 @@ size_t VulkanPushBuffer::GetTotalSize() const {
return sum;
}
+size_t VulkanPushBuffer::GetTotalCapacity() const {
+ return size_ * buffers_.size();
+}
+
void VulkanPushBuffer::Map() {
_dbg_assert_(!writePtr_);
VkResult res = vmaMapMemory(vulkan_->Allocator(), buffers_[buf_].allocation, (void **)(&writePtr_));
diff --git a/Common/GPU/Vulkan/VulkanMemory.h b/Common/GPU/Vulkan/VulkanMemory.h
index 275ca4bb78..863e4f965e 100644
--- a/Common/GPU/Vulkan/VulkanMemory.h
+++ b/Common/GPU/Vulkan/VulkanMemory.h
@@ -131,7 +131,10 @@ public:
info->range = sizeof(T);
}
- size_t GetTotalSize() const;
+ size_t GetTotalSize() const; // Used size
+ size_t GetTotalCapacity() const;
+
+ static std::vector GetAllActive();
private:
bool AddBuffer();
@@ -173,7 +176,7 @@ private:
const char *tag_;
VulkanContext *vulkan_ = nullptr;
VkDescriptorPool descPool_ = VK_NULL_HANDLE;
- VkDescriptorPoolCreateInfo info_;
+ VkDescriptorPoolCreateInfo info_{};
std::vector sizes_;
std::function clear_;
uint32_t usage_ = 0;
diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp
index 55298b3be4..7ab778d8c2 100644
--- a/Common/GPU/Vulkan/VulkanRenderManager.cpp
+++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp
@@ -884,7 +884,8 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR
} else {
curWidthRaw_ = vulkan_->GetBackbufferWidth();
curHeightRaw_ = vulkan_->GetBackbufferHeight();
- if (g_display_rotation == DisplayRotation::ROTATE_90 || g_display_rotation == DisplayRotation::ROTATE_270) {
+ if (g_display.rotation == DisplayRotation::ROTATE_90 ||
+ g_display.rotation == DisplayRotation::ROTATE_270) {
curWidth_ = curHeightRaw_;
curHeight_ = curWidthRaw_;
} else {
diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h
index 812128b906..3cad859e8d 100644
--- a/Common/GPU/Vulkan/VulkanRenderManager.h
+++ b/Common/GPU/Vulkan/VulkanRenderManager.h
@@ -416,8 +416,10 @@ public:
// These can be useful both when inspecting in RenderDoc, and when manually inspecting recorded commands
// in the debugger.
void DebugAnnotate(const char *annotation) {
+ _dbg_assert_(curRenderStep_);
VkRenderData data{ VKRRenderCommand::DEBUG_ANNOTATION };
data.debugAnnotation.annotation = annotation;
+ curRenderStep_->commands.push_back(data);
}
VkCommandBuffer GetInitCmd();
diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp
index 14c1c0e502..2d58bebdc8 100644
--- a/Common/GPU/Vulkan/thin3d_vulkan.cpp
+++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp
@@ -425,7 +425,7 @@ public:
void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override;
void SetScissorRect(int left, int top, int width, int height) override;
- void SetViewports(int count, Viewport *viewports) override;
+ void SetViewport(const Viewport &viewport) override;
void SetBlendFactor(float color[4]) override;
void SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) override;
@@ -742,7 +742,9 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const Textur
usageBits |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
}
- if (!vkTex_->CreateDirect(cmd, width_, height_, 1, mipLevels_, vulkanFormat, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, usageBits)) {
+ VkComponentMapping r8AsAlpha[4] = { VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_R };
+
+ if (!vkTex_->CreateDirect(cmd, width_, height_, 1, mipLevels_, vulkanFormat, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, usageBits, desc.swizzle == TextureSwizzle::R8_AS_ALPHA ? r8AsAlpha : nullptr)) {
ERROR_LOG(G3D, "Failed to create VulkanTexture: %dx%dx%d fmt %d, %d levels", width_, height_, depth_, (int)vulkanFormat, mipLevels_);
return false;
}
@@ -1237,18 +1239,16 @@ void VKContext::SetScissorRect(int left, int top, int width, int height) {
renderManager_.SetScissor(left, top, width, height);
}
-void VKContext::SetViewports(int count, Viewport *viewports) {
- if (count > 0) {
- // Ignore viewports more than the first.
- VkViewport viewport;
- viewport.x = viewports[0].TopLeftX;
- viewport.y = viewports[0].TopLeftY;
- viewport.width = viewports[0].Width;
- viewport.height = viewports[0].Height;
- viewport.minDepth = viewports[0].MinDepth;
- viewport.maxDepth = viewports[0].MaxDepth;
- renderManager_.SetViewport(viewport);
- }
+void VKContext::SetViewport(const Viewport &viewport) {
+ // Ignore viewports more than the first.
+ VkViewport vkViewport;
+ vkViewport.x = viewport.TopLeftX;
+ vkViewport.y = viewport.TopLeftY;
+ vkViewport.width = viewport.Width;
+ vkViewport.height = viewport.Height;
+ vkViewport.minDepth = viewport.MinDepth;
+ vkViewport.maxDepth = viewport.MaxDepth;
+ renderManager_.SetViewport(vkViewport);
}
void VKContext::SetBlendFactor(float color[4]) {
diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h
index 3db2d7b8db..3013470e95 100644
--- a/Common/GPU/thin3d.h
+++ b/Common/GPU/thin3d.h
@@ -598,6 +598,11 @@ struct DeviceCaps {
// Important: only write to the provided pointer, don't read from it.
typedef std::function TextureCallback;
+enum class TextureSwizzle {
+ DEFAULT,
+ R8_AS_ALPHA,
+};
+
struct TextureDesc {
TextureType type;
DataFormat format;
@@ -607,6 +612,7 @@ struct TextureDesc {
int depth;
int mipLevels;
bool generateMips;
+ TextureSwizzle swizzle;
// Optional, for tracking memory usage and graphcis debuggers.
const char *tag;
// Does not take ownership over pointed-to data.
@@ -733,7 +739,7 @@ public:
// Dynamic state
virtual void SetScissorRect(int left, int top, int width, int height) = 0;
- virtual void SetViewports(int count, Viewport *viewports) = 0;
+ virtual void SetViewport(const Viewport &viewport) = 0;
virtual void SetBlendFactor(float color[4]) = 0;
virtual void SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) = 0;
diff --git a/Common/Math/math_util.h b/Common/Math/math_util.h
index fd47662b54..b76e1f3937 100644
--- a/Common/Math/math_util.h
+++ b/Common/Math/math_util.h
@@ -40,6 +40,10 @@ inline uint32_t RoundUpToPowerOf2(uint32_t v) {
return v;
}
+inline uint32_t RoundUpToPowerOf2(uint32_t v, uint32_t power) {
+ return (v + power - 1) & ~(power - 1);
+}
+
inline uint32_t log2i(uint32_t val) {
unsigned int ret = -1;
while (val != 0) {
diff --git a/Common/Render/DrawBuffer.cpp b/Common/Render/DrawBuffer.cpp
index bf49bc4774..73c0f30a68 100644
--- a/Common/Render/DrawBuffer.cpp
+++ b/Common/Render/DrawBuffer.cpp
@@ -111,14 +111,14 @@ void DrawBuffer::Rect(float x, float y, float w, float h, uint32_t color, int al
void DrawBuffer::hLine(float x1, float y, float x2, uint32_t color) {
// Round Y to the closest full pixel, since we're making it 1-pixel-thin.
- y -= fmodf(y, pixel_in_dps_y);
- Rect(x1, y, x2 - x1, pixel_in_dps_y, color);
+ y -= fmodf(y, g_display.pixel_in_dps_y);
+ Rect(x1, y, x2 - x1, g_display.pixel_in_dps_y, color);
}
void DrawBuffer::vLine(float x, float y1, float y2, uint32_t color) {
// Round X to the closest full pixel, since we're making it 1-pixel-thin.
- x -= fmodf(x, pixel_in_dps_x);
- Rect(x, y1, pixel_in_dps_x, y2 - y1, color);
+ x -= fmodf(x, g_display.pixel_in_dps_x);
+ Rect(x, y1, g_display.pixel_in_dps_x, y2 - y1, color);
}
void DrawBuffer::RectVGradient(float x, float y, float w, float h, uint32_t colorTop, uint32_t colorBottom) {
@@ -131,11 +131,11 @@ void DrawBuffer::RectVGradient(float x, float y, float w, float h, uint32_t colo
}
void DrawBuffer::RectOutline(float x, float y, float w, float h, uint32_t color, int align) {
- hLine(x, y, x + w + pixel_in_dps_x, color);
- hLine(x, y + h, x + w + pixel_in_dps_x, color);
+ hLine(x, y, x + w + g_display.pixel_in_dps_x, color);
+ hLine(x, y + h, x + w + g_display.pixel_in_dps_x, color);
- vLine(x, y, y + h + pixel_in_dps_y, color);
- vLine(x + w, y, y + h + pixel_in_dps_y, color);
+ vLine(x, y, y + h + g_display.pixel_in_dps_y, color);
+ vLine(x + w, y, y + h + g_display.pixel_in_dps_y, color);
}
void DrawBuffer::MultiVGradient(float x, float y, float w, float h, const GradientStop *stops, int numStops) {
diff --git a/Common/Render/ManagedTexture.cpp b/Common/Render/ManagedTexture.cpp
index 771d4f8a92..dce43253c2 100644
--- a/Common/Render/ManagedTexture.cpp
+++ b/Common/Render/ManagedTexture.cpp
@@ -148,7 +148,7 @@ bool ManagedTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, Imag
bool ManagedTexture::LoadFromFile(const std::string &filename, ImageFileType type, bool generateMips) {
generateMips_ = generateMips;
size_t fileSize;
- uint8_t *buffer = VFSReadFile(filename.c_str(), &fileSize);
+ uint8_t *buffer = g_VFS.ReadFile(filename.c_str(), &fileSize);
if (!buffer) {
filename_.clear();
ERROR_LOG(IO, "Failed to read file '%s'", filename.c_str());
diff --git a/Common/Render/Text/draw_text.cpp b/Common/Render/Text/draw_text.cpp
index e236065483..4d4b58e7f9 100644
--- a/Common/Render/Text/draw_text.cpp
+++ b/Common/Render/Text/draw_text.cpp
@@ -38,7 +38,7 @@ void TextDrawer::SetFontScale(float xscale, float yscale) {
float TextDrawer::CalculateDPIScale() {
if (ignoreGlobalDpi_)
return dpiScale_;
- float scale = g_dpi_scale_y;
+ float scale = g_display.dpi_scale_y;
if (scale >= 1.0f) {
scale = 1.0f;
}
diff --git a/Common/Render/Text/draw_text_android.cpp b/Common/Render/Text/draw_text_android.cpp
index b6ada98a94..1cc3dc9d1e 100644
--- a/Common/Render/Text/draw_text_android.cpp
+++ b/Common/Render/Text/draw_text_android.cpp
@@ -27,7 +27,10 @@ TextDrawerAndroid::TextDrawerAndroid(Draw::DrawContext *draw) : TextDrawer(draw)
ERROR_LOG(G3D, "Failed to find class: '%s'", textRendererClassName);
}
dpiScale_ = CalculateDPIScale();
- INFO_LOG(G3D, "Initializing TextDrawerAndroid with DPI scale %f", dpiScale_);
+
+ use4444Format_ = (draw->GetDataFormatSupport(Draw::DataFormat::R4G4B4A4_UNORM_PACK16) & Draw::FMT_TEXTURE) != 0;
+
+ INFO_LOG(G3D, "Initializing TextDrawerAndroid with DPI scale %f, use4444=%d", dpiScale_, (int)use4444Format_);
}
TextDrawerAndroid::~TextDrawerAndroid() {
@@ -244,7 +247,8 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
entry = iter->second.get();
entry->lastUsedFrame = frameCount_;
} else {
- DataFormat texFormat = Draw::DataFormat::R4G4B4A4_UNORM_PACK16;
+ // Actually, I don't know why we don't always use R8_UNORM..
+ DataFormat texFormat = use4444Format_ ? Draw::DataFormat::R4G4B4A4_UNORM_PACK16 : Draw::DataFormat::R8_UNORM;
entry = new TextStringEntry();
@@ -260,6 +264,7 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
desc.depth = 1;
desc.mipLevels = 1;
desc.generateMips = false;
+ desc.swizzle = use4444Format_ ? Draw::TextureSwizzle::DEFAULT : Draw::TextureSwizzle::R8_AS_ALPHA,
desc.tag = "TextDrawer";
entry->texture = draw_->CreateTexture(desc);
cache_[key] = std::unique_ptr(entry);
diff --git a/Common/Render/Text/draw_text_android.h b/Common/Render/Text/draw_text_android.h
index 4b95bdeb75..f4b7e431e6 100644
--- a/Common/Render/Text/draw_text_android.h
+++ b/Common/Render/Text/draw_text_android.h
@@ -40,6 +40,7 @@ private:
jmethodID method_renderText;
uint32_t fontHash_;
+ bool use4444Format_ = false;
std::map fontMap_;
diff --git a/Common/RiscVCPUDetect.cpp b/Common/RiscVCPUDetect.cpp
index f05203488a..b4f8b608d8 100644
--- a/Common/RiscVCPUDetect.cpp
+++ b/Common/RiscVCPUDetect.cpp
@@ -40,6 +40,7 @@
const char procfile[] = "/proc/cpuinfo";
// https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-devices-system-cpu
const char syscpupresentfile[] = "/sys/devices/system/cpu/present";
+const char firmwarefile[] = "/sys/firmware/devicetree/base/compatible";
class RiscVCPUInfoParser {
public:
@@ -49,9 +50,12 @@ public:
int TotalLogicalCount();
std::string ISAString();
+ bool FirmwareMatchesCompatible(const std::string &str);
private:
std::vector> cores_;
+ std::vector firmware_;
+ bool firmwareLoaded_ = false;
};
RiscVCPUInfoParser::RiscVCPUInfoParser() {
@@ -126,6 +130,25 @@ std::string RiscVCPUInfoParser::ISAString() {
return "Unknown";
}
+
+bool RiscVCPUInfoParser::FirmwareMatchesCompatible(const std::string &str) {
+ if (!firmwareLoaded_) {
+ firmwareLoaded_ = true;
+
+ std::string data;
+ if (!File::ReadFileToString(true, Path(firmwarefile), data))
+ return false;
+
+ SplitString(data, '\0', firmware_);
+ }
+
+ for (auto compatible : firmware_) {
+ if (compatible == str)
+ return true;
+ }
+
+ return false;
+}
#endif
static bool ExtensionSupported(unsigned long v, char c) {
@@ -170,6 +193,12 @@ void CPUInfo::Detect()
logical_cpu_count = 1;
truncate_cpy(cpu_string, parser.ISAString().c_str());
+
+ // A number of CPUs support a limited set of B. It's not all U74, so we use SOC for now...
+ if (parser.FirmwareMatchesCompatible("starfive,jh7110")) {
+ RiscV_Zba = true;
+ RiscV_Zbb = true;
+ }
#endif
unsigned long hwcap = getauxval(AT_HWCAP);
@@ -183,12 +212,6 @@ void CPUInfo::Detect()
// Let's assume for now...
RiscV_Zicsr = RiscV_M && RiscV_A && RiscV_F && RiscV_D;
- // A number of CPUs support a limited set of B.
- if (!strcmp(brand_string, "sifive,u74-mc")) {
- RiscV_Zba = true;
- RiscV_Zbb = true;
- }
-
#ifdef USE_CPU_FEATURES
cpu_features::RiscvInfo info = cpu_features::GetRiscvInfo();
CPU64bit = info.features.RV64I;
diff --git a/Common/System/Display.cpp b/Common/System/Display.cpp
index 0e9c1ffb62..15af7de4e3 100644
--- a/Common/System/Display.cpp
+++ b/Common/System/Display.cpp
@@ -1,27 +1,13 @@
+#include
+
#include "Common/System/Display.h"
#include "Common/Math/math_util.h"
-int dp_xres;
-int dp_yres;
-
-int pixel_xres;
-int pixel_yres;
-
-float g_dpi = 1.0f; // will be overwritten with a value that makes sense.
-float g_dpi_scale_x = 1.0f;
-float g_dpi_scale_y = 1.0f;
-float g_dpi_scale_real_x = 1.0f;
-float g_dpi_scale_real_y = 1.0f;
-float pixel_in_dps_x = 1.0f;
-float pixel_in_dps_y = 1.0f;
-float display_hz = 60.0f;
-
-DisplayRotation g_display_rotation;
-Lin::Matrix4x4 g_display_rot_matrix = Lin::Matrix4x4::identity();
+DisplayProperties g_display;
template
void RotateRectToDisplayImpl(DisplayRect &rect, T curRTWidth, T curRTHeight) {
- switch (g_display_rotation) {
+ switch (g_display.rotation) {
case DisplayRotation::ROTATE_180:
rect.x = curRTWidth - rect.w - rect.x;
rect.y = curRTHeight - rect.h - rect.y;
@@ -62,3 +48,21 @@ void RotateRectToDisplay(DisplayRect &rect, int curRTWidth, int curRTHeight
void RotateRectToDisplay(DisplayRect &rect, float curRTWidth, float curRTHeight) {
RotateRectToDisplayImpl(rect, curRTWidth, curRTHeight);
}
+
+DisplayProperties::DisplayProperties() {
+ rot_matrix.setIdentity();
+}
+
+void DisplayProperties::Print() {
+ printf("dp_xres/yres: %d, %d\n", dp_xres, dp_yres);
+ printf("pixel_xres/yres: %d, %d\n", pixel_xres, pixel_yres);
+
+ printf("dpi, x, y: %f, %f, %f\n", dpi, dpi_scale_x, dpi_scale_y);
+ printf("pixel_in_dps: %f, %f\n", pixel_in_dps_x, pixel_in_dps_y);
+
+ printf("dpi_real: %f, %f\n", dpi_scale_real_x, dpi_scale_real_y);
+ printf("display_hz: %f\n", display_hz);
+
+ printf("rotation: %d\n", (int)rotation);
+ rot_matrix.print();
+}
diff --git a/Common/System/Display.h b/Common/System/Display.h
index 586c346f77..0bea49542a 100644
--- a/Common/System/Display.h
+++ b/Common/System/Display.h
@@ -5,20 +5,6 @@
// This is meant to be a framework for handling DPI scaling etc.
// For now, it just consists of these ugly globals.
-extern int dp_xres;
-extern int dp_yres;
-extern int pixel_xres;
-extern int pixel_yres;
-
-extern float g_dpi;
-extern float g_dpi_scale_x;
-extern float g_dpi_scale_y;
-extern float g_dpi_scale_real_x;
-extern float g_dpi_scale_real_y;
-extern float pixel_in_dps_x;
-extern float pixel_in_dps_y;
-extern float display_hz;
-
// On some platforms (currently only Windows UWP) we need to manually rotate
// our rendered output to match the display. Use these to do so.
enum class DisplayRotation {
@@ -28,8 +14,34 @@ enum class DisplayRotation {
ROTATE_270,
};
-extern DisplayRotation g_display_rotation;
-extern Lin::Matrix4x4 g_display_rot_matrix;
+struct DisplayProperties {
+ int dp_xres;
+ int dp_yres;
+ int pixel_xres;
+ int pixel_yres;
+
+ float dpi = 1.0f; // will be overwritten with a value that makes sense.
+ float dpi_scale_x = 1.0f;
+ float dpi_scale_y = 1.0f;
+
+ // pixel_xres/yres in dps
+ float pixel_in_dps_x = 1.0f;
+ float pixel_in_dps_y = 1.0f;
+
+ // If DPI is overridden (like in small window mode), these are still the original DPI.
+ float dpi_scale_real_x = 1.0f;
+ float dpi_scale_real_y = 1.0f;
+
+ float display_hz = 60.0f;
+
+ DisplayRotation rotation;
+ Lin::Matrix4x4 rot_matrix;
+
+ DisplayProperties();
+ void Print();
+};
+
+extern DisplayProperties g_display;
template
struct DisplayRect {
diff --git a/Common/UI/Context.cpp b/Common/UI/Context.cpp
index 70202f44a3..cb62571bf0 100644
--- a/Common/UI/Context.cpp
+++ b/Common/UI/Context.cpp
@@ -15,7 +15,7 @@
UIContext::UIContext() {
fontStyle_ = new UI::FontStyle();
- bounds_ = Bounds(0, 0, dp_xres, dp_yres);
+ bounds_ = Bounds(0, 0, g_display.dp_xres, g_display.dp_yres);
}
UIContext::~UIContext() {
@@ -163,22 +163,22 @@ Bounds UIContext::GetLayoutBounds() const {
void UIContext::ActivateTopScissor() {
Bounds bounds;
if (scissorStack_.size()) {
- float scale_x = pixel_in_dps_x;
- float scale_y = pixel_in_dps_y;
+ float scale_x = g_display.pixel_in_dps_x;
+ float scale_y = g_display.pixel_in_dps_y;
bounds = scissorStack_.back();
int x = floorf(scale_x * bounds.x);
int y = floorf(scale_y * bounds.y);
int w = std::max(0.0f, ceilf(scale_x * bounds.w));
int h = std::max(0.0f, ceilf(scale_y * bounds.h));
- if (x < 0 || y < 0 || x + w > pixel_xres || y + h > pixel_yres) {
+ if (x < 0 || y < 0 || x + w > g_display.pixel_xres || y + h > g_display.pixel_yres) {
// This won't actually report outside a game, but we can try.
- DEBUG_LOG(G3D, "UI scissor out of bounds in %sScreen: %d,%d-%d,%d / %d,%d", screenTag_ ? screenTag_ : "N/A", x, y, w, h, pixel_xres, pixel_yres);
+ DEBUG_LOG(G3D, "UI scissor out of bounds in %sScreen: %d,%d-%d,%d / %d,%d", screenTag_ ? screenTag_ : "N/A", x, y, w, h, g_display.pixel_xres, g_display.pixel_yres);
if (x < 0) { w += x; x = 0; }
if (y < 0) { h += y; y = 0; }
- if (x >= pixel_xres) { x = pixel_xres - 1; }
- if (y >= pixel_yres) { y = pixel_yres - 1; }
- if (x + w > pixel_xres) { w = std::min(w, pixel_xres - x); }
- if (y + w > pixel_yres) { h = std::min(h, pixel_yres - y); }
+ if (x >= g_display.pixel_xres) { x = g_display.pixel_xres - 1; }
+ if (y >= g_display.pixel_yres) { y = g_display.pixel_yres - 1; }
+ if (x + w > g_display.pixel_xres) { w = std::min(w, g_display.pixel_xres - x); }
+ if (y + w > g_display.pixel_yres) { h = std::min(h, g_display.pixel_yres - y); }
if (w == 0) w = 1;
if (h == 0) h = 1;
draw_->SetScissorRect(x, y, w, h);
@@ -190,7 +190,7 @@ void UIContext::ActivateTopScissor() {
}
} else {
// Avoid rounding errors
- draw_->SetScissorRect(0, 0, pixel_xres, pixel_yres);
+ draw_->SetScissorRect(0, 0, g_display.pixel_xres, g_display.pixel_yres);
}
}
@@ -351,8 +351,8 @@ Bounds UIContext::TransformBounds(const Bounds &bounds) {
Bounds translated = bounds.Offset(t.translate.x, t.translate.y);
// Scale around the center as the origin.
- float scaledX = (translated.x - dp_xres * 0.5f) * t.scale.x + dp_xres * 0.5f;
- float scaledY = (translated.y - dp_yres * 0.5f) * t.scale.y + dp_yres * 0.5f;
+ float scaledX = (translated.x - g_display.dp_xres * 0.5f) * t.scale.x + g_display.dp_xres * 0.5f;
+ float scaledY = (translated.y - g_display.dp_yres * 0.5f) * t.scale.y + g_display.dp_yres * 0.5f;
return Bounds(scaledX, scaledY, translated.w * t.scale.x, translated.h * t.scale.y);
}
diff --git a/Common/UI/Screen.cpp b/Common/UI/Screen.cpp
index 59ea6a320b..047ec04483 100644
--- a/Common/UI/Screen.cpp
+++ b/Common/UI/Screen.cpp
@@ -138,7 +138,7 @@ void ScreenManager::deviceRestored() {
}
void ScreenManager::resized() {
- INFO_LOG(SYSTEM, "ScreenManager::resized(dp: %dx%d)", dp_xres, dp_yres);
+ INFO_LOG(SYSTEM, "ScreenManager::resized(dp: %dx%d)", g_display.dp_xres, g_display.dp_yres);
std::lock_guard guard(inputLock_);
// Have to notify the whole stack, otherwise there will be problems when going back
// to non-top screens.
diff --git a/Common/UI/UIScreen.cpp b/Common/UI/UIScreen.cpp
index 768fc88b16..a412df9abb 100644
--- a/Common/UI/UIScreen.cpp
+++ b/Common/UI/UIScreen.cpp
@@ -24,7 +24,7 @@ UIScreen::~UIScreen() {
}
bool UIScreen::UseVerticalLayout() const {
- return dp_yres > dp_xres * 1.1f;
+ return g_display.dp_yres > g_display.dp_xres * 1.1f;
}
void UIScreen::DoRecreateViews() {
@@ -98,12 +98,12 @@ void UIScreen::preRender() {
Draw::Viewport viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
- viewport.Width = pixel_xres;
- viewport.Height = pixel_yres;
+ viewport.Width = g_display.pixel_xres;
+ viewport.Height = g_display.pixel_yres;
viewport.MaxDepth = 1.0;
viewport.MinDepth = 0.0;
- draw->SetViewports(1, &viewport);
- draw->SetTargetSize(pixel_xres, pixel_yres);
+ draw->SetViewport(viewport);
+ draw->SetTargetSize(g_display.pixel_xres, g_display.pixel_yres);
}
void UIScreen::postRender() {
@@ -141,8 +141,8 @@ TouchInput UIScreen::transformTouch(const TouchInput &touch) {
float x = touch.x - translation_.x;
float y = touch.y - translation_.y;
// Scale around the center as the origin.
- updated.x = (x - dp_xres * 0.5f) / scale_.x + dp_xres * 0.5f;
- updated.y = (y - dp_yres * 0.5f) / scale_.y + dp_yres * 0.5f;
+ updated.x = (x - g_display.dp_xres * 0.5f) / scale_.x + g_display.dp_xres * 0.5f;
+ updated.y = (y - g_display.dp_yres * 0.5f) / scale_.y + g_display.dp_yres * 0.5f;
return updated;
}
@@ -280,14 +280,14 @@ void PopupScreen::update() {
scale_.y = 0.9f + animatePos * 0.1f;
if (hasPopupOrigin_) {
- float xoff = popupOrigin_.x - dp_xres / 2;
- float yoff = popupOrigin_.y - dp_yres / 2;
+ float xoff = popupOrigin_.x - g_display.dp_xres / 2;
+ float yoff = popupOrigin_.y - g_display.dp_yres / 2;
// Pull toward the origin a bit.
translation_.x = xoff * (1.0f - animatePos) * 0.2f;
translation_.y = yoff * (1.0f - animatePos) * 0.2f;
} else {
- translation_.y = -dp_yres * (1.0f - animatePos) * 0.2f;
+ translation_.y = -g_display.dp_yres * (1.0f - animatePos) * 0.2f;
}
} else {
alpha_ = 1.0f;
@@ -333,7 +333,7 @@ void PopupScreen::CreateViews() {
box_->SetBG(dc.theme->popupStyle.background);
box_->SetHasDropShadow(hasDropShadow_);
// Since we scale a bit, make the dropshadow bleed past the edges.
- box_->SetDropShadowExpand(std::max(dp_xres, dp_yres));
+ box_->SetDropShadowExpand(std::max(g_display.dp_xres, g_display.dp_yres));
box_->SetSpacing(0.0f);
View *title = new PopupHeader(title_);
diff --git a/Common/VR/PPSSPPVR.cpp b/Common/VR/PPSSPPVR.cpp
index 20a54ab678..f39f1bcc1d 100644
--- a/Common/VR/PPSSPPVR.cpp
+++ b/Common/VR/PPSSPPVR.cpp
@@ -150,10 +150,11 @@ void InitVROnAndroid(void* vm, void* activity, const char* system, int version,
//Set platform flags
if (strcmp(vendor, "PICO") == 0) {
VR_SetPlatformFLag(VR_PLATFORM_CONTROLLER_PICO, true);
- VR_SetPlatformFLag(VR_PLATFORM_INSTANCE_EXT, true);
+ VR_SetPlatformFLag(VR_PLATFORM_EXTENSION_INSTANCE, true);
} else if ((strcmp(vendor, "META") == 0) || (strcmp(vendor, "OCULUS") == 0)) {
VR_SetPlatformFLag(VR_PLATFORM_CONTROLLER_QUEST, true);
- VR_SetPlatformFLag(VR_PLATFORM_PERFORMANCE_EXT, true);
+ VR_SetPlatformFLag(VR_PLATFORM_EXTENSION_FOVEATION, true);
+ VR_SetPlatformFLag(VR_PLATFORM_EXTENSION_PERFORMANCE, true);
}
VR_SetPlatformFLag(VR_PLATFORM_RENDERER_VULKAN, (GPUBackend)g_Config.iGPUBackend == GPUBackend::VULKAN);
@@ -315,7 +316,7 @@ void UpdateVRInput(bool haptics, float dp_xscale, float dp_yscale) {
}
// Head control
- if (g_Config.iHeadRotation) {
+ if (g_Config.bHeadRotationEnabled) {
float pitch = -VR_GetHMDAngles().x;
float yaw = -VR_GetHMDAngles().y;
bool disable = vrFlatForced || appMode == VR_MENU_MODE;
@@ -342,25 +343,6 @@ void UpdateVRInput(bool haptics, float dp_xscale, float dp_yscale) {
float limit = isVR ? g_Config.fHeadRotationScale : 20;
keyInput.deviceId = DEVICE_ID_XR_HMD;
- // vertical rotations
- if (g_Config.iHeadRotation == 2) {
- //up
- activate = !disable && pitch > limit;
- keyInput.flags = activate ? KEY_DOWN : KEY_UP;
- keyInput.keyCode = NKCODE_EXT_ROTATION_UP;
- if (hmdMotion[0] != activate) NativeKey(keyInput);
- if (isVR && activate) hmdMotionDiff[0] -= limit;
- hmdMotion[0] = activate;
-
- //down
- activate = !disable && pitch < -limit;
- keyInput.flags = activate ? KEY_DOWN : KEY_UP;
- keyInput.keyCode = NKCODE_EXT_ROTATION_DOWN;
- if (hmdMotion[1] != activate) NativeKey(keyInput);
- if (isVR && activate) hmdMotionDiff[0] += limit;
- hmdMotion[1] = activate;
- }
-
//left
activate = !disable && yaw < -limit;
keyInput.flags = activate ? KEY_DOWN : KEY_UP;
@@ -690,8 +672,7 @@ bool StartVRRender() {
float mRoll = mz * ToRadians(rotation.z);
// use in-game camera interpolated rotation
- if (g_Config.iHeadRotation >= 2) mPitch = -mx * ToRadians(hmdMotionDiffLast[0]); // vertical
- if (g_Config.iHeadRotation >= 1) mYaw = -my * ToRadians(hmdMotionDiffLast[1]); // horizontal
+ if (g_Config.bHeadRotationEnabled) mYaw = -my * ToRadians(hmdMotionDiffLast[1]); // horizontal
// create updated quaternion
XrQuaternionf pitch = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, mPitch);
diff --git a/Common/VR/VRBase.cpp b/Common/VR/VRBase.cpp
index 284c33aaff..715ea6644e 100644
--- a/Common/VR/VRBase.cpp
+++ b/Common/VR/VRBase.cpp
@@ -49,10 +49,19 @@ void VR_Init( void* system, const char* name, int version ) {
}
extensions.push_back(XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME);
#ifdef ANDROID
- if (VR_GetPlatformFlag(VR_PLATFORM_INSTANCE_EXT)) {
+ if (VR_GetPlatformFlag(VR_PLATFORM_EXTENSION_FOVEATION)) {
+ extensions.push_back(XR_FB_SWAPCHAIN_UPDATE_STATE_EXTENSION_NAME);
+ extensions.push_back(XR_FB_SWAPCHAIN_UPDATE_STATE_OPENGL_ES_EXTENSION_NAME);
+ extensions.push_back(XR_FB_FOVEATION_EXTENSION_NAME);
+ extensions.push_back(XR_FB_FOVEATION_CONFIGURATION_EXTENSION_NAME);
+ if (VR_GetPlatformFlag(VR_PLATFORM_RENDERER_VULKAN)) {
+ extensions.push_back(XR_FB_SWAPCHAIN_UPDATE_STATE_VULKAN_EXTENSION_NAME);
+ }
+ }
+ if (VR_GetPlatformFlag(VR_PLATFORM_EXTENSION_INSTANCE)) {
extensions.push_back(XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME);
}
- if (VR_GetPlatformFlag(VR_PLATFORM_PERFORMANCE_EXT)) {
+ if (VR_GetPlatformFlag(VR_PLATFORM_EXTENSION_PERFORMANCE)) {
extensions.push_back(XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME);
extensions.push_back(XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME);
}
@@ -80,7 +89,7 @@ void VR_Init( void* system, const char* name, int version ) {
#ifdef ANDROID
XrInstanceCreateInfoAndroidKHR instanceCreateInfoAndroid = {XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR};
- if (VR_GetPlatformFlag(VR_PLATFORM_INSTANCE_EXT)) {
+ if (VR_GetPlatformFlag(VR_PLATFORM_EXTENSION_INSTANCE)) {
ovrJava* java = (ovrJava*)system;
instanceCreateInfoAndroid.applicationVM = java->Vm;
instanceCreateInfoAndroid.applicationActivity = java->ActivityObject;
@@ -182,7 +191,7 @@ void VR_EnterVR( engine_t* engine, XrGraphicsBindingVulkanKHR* graphicsBindingVu
graphicsBindingGL.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR;
graphicsBindingGL.next = NULL;
graphicsBindingGL.display = eglGetCurrentDisplay();
- graphicsBindingGL.config = eglGetCurrentSurface(EGL_DRAW);
+ graphicsBindingGL.config = NULL;
graphicsBindingGL.context = eglGetCurrentContext();
sessionCreateInfo.next = &graphicsBindingGL;
#else
diff --git a/Common/VR/VRBase.h b/Common/VR/VRBase.h
index 7ed105c846..2d3405f8a7 100644
--- a/Common/VR/VRBase.h
+++ b/Common/VR/VRBase.h
@@ -120,8 +120,9 @@ typedef struct {
enum VRPlatformFlag {
VR_PLATFORM_CONTROLLER_PICO,
VR_PLATFORM_CONTROLLER_QUEST,
- VR_PLATFORM_INSTANCE_EXT,
- VR_PLATFORM_PERFORMANCE_EXT,
+ VR_PLATFORM_EXTENSION_FOVEATION,
+ VR_PLATFORM_EXTENSION_INSTANCE,
+ VR_PLATFORM_EXTENSION_PERFORMANCE,
VR_PLATFORM_RENDERER_VULKAN,
VR_PLATFORM_TRACKING_FLOOR,
VR_PLATFORM_MAX
diff --git a/Common/VR/VRFramebuffer.cpp b/Common/VR/VRFramebuffer.cpp
index 6d8b94177a..4f53b9eb25 100644
--- a/Common/VR/VRFramebuffer.cpp
+++ b/Common/VR/VRFramebuffer.cpp
@@ -105,6 +105,15 @@ static bool ovrFramebuffer_CreateGLES(XrSession session, ovrFramebuffer* frameBu
swapChainCreateInfo.mipCount = 1;
swapChainCreateInfo.arraySize = multiview ? 2 : 1;
+#ifdef ANDROID
+ if (VR_GetPlatformFlag(VR_PLATFORM_EXTENSION_FOVEATION)) {
+ XrSwapchainCreateInfoFoveationFB swapChainFoveationCreateInfo;
+ memset(&swapChainFoveationCreateInfo, 0, sizeof(swapChainFoveationCreateInfo));
+ swapChainFoveationCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB;
+ swapChainCreateInfo.next = &swapChainFoveationCreateInfo;
+ }
+#endif
+
frameBuffer->ColorSwapChain.Width = swapChainCreateInfo.width;
frameBuffer->ColorSwapChain.Height = swapChainCreateInfo.height;
@@ -198,6 +207,15 @@ static bool ovrFramebuffer_CreateVK(XrSession session, ovrFramebuffer* frameBuff
swapChainCreateInfo.mipCount = 1;
swapChainCreateInfo.arraySize = multiview ? 2 : 1;
+#ifdef ANDROID
+ if (VR_GetPlatformFlag(VR_PLATFORM_EXTENSION_FOVEATION)) {
+ XrSwapchainCreateInfoFoveationFB swapChainFoveationCreateInfo;
+ memset(&swapChainFoveationCreateInfo, 0, sizeof(swapChainFoveationCreateInfo));
+ swapChainFoveationCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB;
+ swapChainCreateInfo.next = &swapChainFoveationCreateInfo;
+ }
+#endif
+
frameBuffer->ColorSwapChain.Width = swapChainCreateInfo.width;
frameBuffer->ColorSwapChain.Height = swapChainCreateInfo.height;
@@ -407,6 +425,47 @@ void ovrRenderer_MouseCursor(ovrRenderer* renderer, int x, int y, int sx, int sy
}
}
+#ifdef ANDROID
+void ovrRenderer_SetFoveation(XrInstance* instance, XrSession* session, ovrRenderer* renderer, XrFoveationLevelFB level, float verticalOffset, XrFoveationDynamicFB dynamic) {
+ PFN_xrCreateFoveationProfileFB pfnCreateFoveationProfileFB;
+ OXR(xrGetInstanceProcAddr(*instance, "xrCreateFoveationProfileFB", (PFN_xrVoidFunction*)(&pfnCreateFoveationProfileFB)));
+
+ PFN_xrDestroyFoveationProfileFB pfnDestroyFoveationProfileFB;
+ OXR(xrGetInstanceProcAddr(*instance, "xrDestroyFoveationProfileFB", (PFN_xrVoidFunction*)(&pfnDestroyFoveationProfileFB)));
+
+ PFN_xrUpdateSwapchainFB pfnUpdateSwapchainFB;
+ OXR(xrGetInstanceProcAddr(*instance, "xrUpdateSwapchainFB", (PFN_xrVoidFunction*)(&pfnUpdateSwapchainFB)));
+
+ int instances = renderer->Multiview ? 1 : ovrMaxNumEyes;
+ for (int eye = 0; eye < instances; eye++) {
+ XrFoveationLevelProfileCreateInfoFB levelProfileCreateInfo;
+ memset(&levelProfileCreateInfo, 0, sizeof(levelProfileCreateInfo));
+ levelProfileCreateInfo.type = XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB;
+ levelProfileCreateInfo.level = level;
+ levelProfileCreateInfo.verticalOffset = verticalOffset;
+ levelProfileCreateInfo.dynamic = dynamic;
+
+ XrFoveationProfileCreateInfoFB profileCreateInfo;
+ memset(&profileCreateInfo, 0, sizeof(profileCreateInfo));
+ profileCreateInfo.type = XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB;
+ profileCreateInfo.next = &levelProfileCreateInfo;
+
+ XrFoveationProfileFB foveationProfile;
+
+ pfnCreateFoveationProfileFB(*session, &profileCreateInfo, &foveationProfile);
+
+ XrSwapchainStateFoveationFB foveationUpdateState;
+ memset(&foveationUpdateState, 0, sizeof(foveationUpdateState));
+ foveationUpdateState.type = XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB;
+ foveationUpdateState.profile = foveationProfile;
+
+ pfnUpdateSwapchainFB(renderer->FrameBuffer[eye].ColorSwapChain.Handle, (XrSwapchainStateBaseHeaderFB*)(&foveationUpdateState));
+
+ pfnDestroyFoveationProfileFB(foveationProfile);
+ }
+}
+#endif
+
/*
================================================================================
@@ -456,7 +515,7 @@ void ovrApp_HandleSessionStateChanges(ovrApp* app, XrSessionState state) {
app->SessionActive = (result == XR_SUCCESS);
#ifdef ANDROID
- if (app->SessionActive && VR_GetPlatformFlag(VR_PLATFORM_PERFORMANCE_EXT)) {
+ if (app->SessionActive && VR_GetPlatformFlag(VR_PLATFORM_EXTENSION_PERFORMANCE)) {
XrPerfSettingsLevelEXT cpuPerfLevel = XR_PERF_SETTINGS_LEVEL_PERFORMANCE_MAX_EXT;
XrPerfSettingsLevelEXT gpuPerfLevel = XR_PERF_SETTINGS_LEVEL_PERFORMANCE_MAX_EXT;
diff --git a/Common/VR/VRFramebuffer.h b/Common/VR/VRFramebuffer.h
index 07a5c19834..49f7484c99 100644
--- a/Common/VR/VRFramebuffer.h
+++ b/Common/VR/VRFramebuffer.h
@@ -13,3 +13,6 @@ void* ovrFramebuffer_SetCurrent(ovrFramebuffer* frameBuffer);
void ovrRenderer_Create(XrSession session, ovrRenderer* renderer, int width, int height, bool multiview, void* vulkanContext);
void ovrRenderer_Destroy(ovrRenderer* renderer);
void ovrRenderer_MouseCursor(ovrRenderer* renderer, int x, int y, int sx, int sy);
+#ifdef ANDROID
+void ovrRenderer_SetFoveation(XrInstance* instance, XrSession* session, ovrRenderer* renderer, XrFoveationLevelFB level, float verticalOffset, XrFoveationDynamicFB dynamic);
+#endif
diff --git a/Common/VR/VRRenderer.cpp b/Common/VR/VRRenderer.cpp
index 8a3cc8ef90..5a9a208926 100644
--- a/Common/VR/VRRenderer.cpp
+++ b/Common/VR/VRRenderer.cpp
@@ -216,6 +216,11 @@ void VR_InitRenderer( engine_t* engine, bool multiview ) {
engine->appState.ViewConfigurationView[0].recommendedImageRectWidth,
engine->appState.ViewConfigurationView[0].recommendedImageRectHeight,
multiview, vulkanContext);
+#ifdef ANDROID
+ if (VR_GetPlatformFlag(VR_PLATFORM_EXTENSION_FOVEATION)) {
+ ovrRenderer_SetFoveation(&engine->appState.Instance, &engine->appState.Session, &engine->appState.Renderer, XR_FOVEATION_LEVEL_HIGH_TOP_FB, 0, XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB);
+ }
+#endif
initialized = true;
}
diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp
index f6cf4a644c..bf4d1a564d 100644
--- a/Core/Compatibility.cpp
+++ b/Core/Compatibility.cpp
@@ -19,6 +19,7 @@
#include "Common/Log.h"
#include "Common/Data/Format/IniFile.h"
+#include "Common/File/VFS/VFS.h"
#include "Common/StringUtils.h"
#include "Core/Compatibility.h"
#include "Core/Config.h"
@@ -38,7 +39,7 @@ void Compatibility::Load(const std::string &gameID) {
{
IniFile compat;
// This loads from assets.
- if (compat.LoadFromVFS("compat.ini")) {
+ if (compat.LoadFromVFS(g_VFS, "compat.ini")) {
CheckSettings(compat, gameID);
}
}
@@ -55,7 +56,7 @@ void Compatibility::Load(const std::string &gameID) {
{
IniFile compat;
// This loads from assets.
- if (compat.LoadFromVFS("compatvr.ini")) {
+ if (compat.LoadFromVFS(g_VFS, "compatvr.ini")) {
CheckVRSettings(compat, gameID);
}
}
@@ -127,6 +128,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) {
CheckSetting(iniFile, gameID, "RockmanDash2SoundFix", &flags_.RockmanDash2SoundFix);
CheckSetting(iniFile, gameID, "ReadbackDepth", &flags_.ReadbackDepth);
CheckSetting(iniFile, gameID, "BlockTransferDepth", &flags_.BlockTransferDepth);
+ CheckSetting(iniFile, gameID, "DaxterRotatedAnalogStick", &flags_.DaxterRotatedAnalogStick);
}
void Compatibility::CheckVRSettings(IniFile &iniFile, const std::string &gameID) {
diff --git a/Core/Compatibility.h b/Core/Compatibility.h
index d34722f4fa..021518ddf6 100644
--- a/Core/Compatibility.h
+++ b/Core/Compatibility.h
@@ -98,6 +98,7 @@ struct CompatFlags {
bool RockmanDash2SoundFix;
bool ReadbackDepth;
bool BlockTransferDepth;
+ bool DaxterRotatedAnalogStick;
};
struct VRCompat {
diff --git a/Core/Config.cpp b/Core/Config.cpp
index 3cf4d788b6..cce0b9d7cb 100644
--- a/Core/Config.cpp
+++ b/Core/Config.cpp
@@ -39,6 +39,7 @@
#include "Common/Data/Text/Parsers.h"
#include "Common/CPUDetect.h"
#include "Common/File/FileUtil.h"
+#include "Common/File/VFS/VFS.h"
#include "Common/LogManager.h"
#include "Common/OSVersion.h"
#include "Common/System/Display.h"
@@ -436,7 +437,7 @@ const char *DefaultLangRegion() {
} else if (langRegion.length() >= 3) {
// Don't give up. Let's try a fuzzy match - so nl_BE can match nl_NL.
IniFile mapping;
- mapping.LoadFromVFS("langregion.ini");
+ mapping.LoadFromVFS(g_VFS, "langregion.ini");
std::vector keys;
mapping.GetKeys("LangRegionNames", keys);
@@ -876,7 +877,6 @@ static const ConfigSetting graphicsSettings[] = {
ReportedConfigSetting("ReplaceTextures", &g_Config.bReplaceTextures, true, true, true),
ReportedConfigSetting("SaveNewTextures", &g_Config.bSaveNewTextures, false, true, true),
ConfigSetting("IgnoreTextureFilenames", &g_Config.bIgnoreTextureFilenames, false, true, true),
- ConfigSetting("ReplaceTexturesAllowLate", &g_Config.bReplaceTexturesAllowLate, true, true, true),
ReportedConfigSetting("TexScalingLevel", &g_Config.iTexScalingLevel, 1, true, true),
ReportedConfigSetting("TexScalingType", &g_Config.iTexScalingType, 0, true, true),
@@ -1152,8 +1152,8 @@ static const ConfigSetting vrSettings[] = {
ConfigSetting("VRHeadUpDisplayScale", &g_Config.fHeadUpDisplayScale, 0.3f),
ConfigSetting("VRMotionLength", &g_Config.fMotionLength, 0.5f),
ConfigSetting("VRHeadRotationScale", &g_Config.fHeadRotationScale, 5.0f),
+ ConfigSetting("VRHeadRotationEnabled", &g_Config.bHeadRotationEnabled, false),
ConfigSetting("VRHeadRotationSmoothing", &g_Config.bHeadRotationSmoothing, false),
- ConfigSetting("VRHeadRotation", &g_Config.iHeadRotation, 0),
};
struct ConfigSectionSettings {
@@ -1222,7 +1222,7 @@ Config::~Config() {
void Config::LoadLangValuesMapping() {
IniFile mapping;
- mapping.LoadFromVFS("langregion.ini");
+ mapping.LoadFromVFS(g_VFS, "langregion.ini");
std::vector keys;
mapping.GetKeys("LangRegionNames", keys);
@@ -1558,8 +1558,8 @@ bool Config::Save(const char *saveReason) {
void Config::PostLoadCleanup(bool gameSpecific) {
// Override ppsspp.ini JIT value to prevent crashing
- if (DefaultCpuCore() != (int)CPUCore::JIT && g_Config.iCpuCore == (int)CPUCore::JIT) {
- jitForcedOff = true;
+ jitForcedOff = DefaultCpuCore() != (int)CPUCore::JIT && g_Config.iCpuCore == (int)CPUCore::JIT;
+ if (jitForcedOff) {
g_Config.iCpuCore = (int)CPUCore::IR_JIT;
}
@@ -1589,19 +1589,27 @@ void Config::PostLoadCleanup(bool gameSpecific) {
void Config::PreSaveCleanup(bool gameSpecific) {
if (jitForcedOff) {
- // if JIT has been forced off, we don't want to screw up the user's ppsspp.ini
- g_Config.iCpuCore = (int)CPUCore::JIT;
+ // If we forced jit off and it's still set to IR, change it back to jit.
+ if (g_Config.iCpuCore == (int)CPUCore::IR_JIT)
+ g_Config.iCpuCore = (int)CPUCore::JIT;
}
}
void Config::PostSaveCleanup(bool gameSpecific) {
if (jitForcedOff) {
- // force JIT off again just in case Config::Save() is called without exiting PPSSPP
- if (g_Config.iCpuCore != (int)CPUCore::INTERPRETER)
+ // Force JIT off again just in case Config::Save() is called without exiting PPSSPP.
+ if (g_Config.iCpuCore == (int)CPUCore::JIT)
g_Config.iCpuCore = (int)CPUCore::IR_JIT;
}
}
+void Config::NotifyUpdatedCpuCore() {
+ if (jitForcedOff && g_Config.iCpuCore == (int)CPUCore::IR_JIT) {
+ // No longer forced off, the user set it to IR jit.
+ jitForcedOff = false;
+ }
+}
+
// Use for debugging the version check without messing with the server
#if 0
#define PPSSPP_GIT_VERSION "v0.0.1-gaaaaaaaaa"
@@ -1924,8 +1932,8 @@ bool Config::loadGameConfig(const std::string &pGameId, const std::string &title
});
KeyMap::LoadFromIni(iniFile);
-
- if (!appendedConfigFileName_.ToString().empty() &&
+
+ if (!appendedConfigFileName_.ToString().empty() &&
std::find(appendedConfigUpdatedGames_.begin(), appendedConfigUpdatedGames_.end(), pGameId) == appendedConfigUpdatedGames_.end()) {
LoadAppendedConfig();
diff --git a/Core/Config.h b/Core/Config.h
index a87fbc005d..38f90902a0 100644
--- a/Core/Config.h
+++ b/Core/Config.h
@@ -213,7 +213,6 @@ public:
bool bReplaceTextures;
bool bSaveNewTextures;
bool bIgnoreTextureFilenames;
- bool bReplaceTexturesAllowLate;
int iTexScalingLevel; // 0 = auto, 1 = off, 2 = 2x, ..., 5 = 5x
int iTexScalingType; // 0 = xBRZ, 1 = Hybrid
bool bTexDeposterize;
@@ -471,8 +470,8 @@ public:
float fHeadUpDisplayScale;
float fMotionLength;
float fHeadRotationScale;
+ bool bHeadRotationEnabled;
bool bHeadRotationSmoothing;
- int iHeadRotation;
// Debugger
int iDisasmWindowX;
@@ -568,6 +567,8 @@ public:
bool LoadAppendedConfig();
void SetAppendedConfigIni(const Path &path);
+ void NotifyUpdatedCpuCore();
+
protected:
void LoadStandardControllerIni();
void LoadLangValuesMapping();
diff --git a/Core/Core.cpp b/Core/Core.cpp
index 611dad8457..95864b197a 100644
--- a/Core/Core.cpp
+++ b/Core/Core.cpp
@@ -154,8 +154,8 @@ bool Core_GetPowerSaving() {
static bool IsWindowSmall(int pixelWidth, int pixelHeight) {
// Can't take this from config as it will not be set if windows is maximized.
- int w = (int)(pixelWidth * g_dpi_scale_x);
- int h = (int)(pixelHeight * g_dpi_scale_y);
+ int w = (int)(pixelWidth * g_display.dpi_scale_x);
+ int h = (int)(pixelHeight * g_display.dpi_scale_y);
return g_Config.IsPortrait() ? (h < 480 + 80) : (w < 480 + 80);
}
@@ -163,42 +163,42 @@ static bool IsWindowSmall(int pixelWidth, int pixelHeight) {
bool UpdateScreenScale(int width, int height) {
bool smallWindow;
#if defined(USING_QT_UI)
- g_dpi = System_GetPropertyFloat(SYSPROP_DISPLAY_DPI);
+ g_display.dpi = System_GetPropertyFloat(SYSPROP_DISPLAY_DPI);
float g_logical_dpi = System_GetPropertyFloat(SYSPROP_DISPLAY_LOGICAL_DPI);
- g_dpi_scale_x = g_logical_dpi / g_dpi;
- g_dpi_scale_y = g_logical_dpi / g_dpi;
+ g_display.dpi_scale_x = g_logical_dpi / g_display.dpi;
+ g_display.dpi_scale_y = g_logical_dpi / g_display.dpi;
#elif PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
- g_dpi = System_GetPropertyFloat(SYSPROP_DISPLAY_DPI);
- g_dpi_scale_x = 96.0f / g_dpi;
- g_dpi_scale_y = 96.0f / g_dpi;
+ g_display.dpi = System_GetPropertyFloat(SYSPROP_DISPLAY_DPI);
+ g_display.dpi_scale_x = 96.0f / g_display.dpi;
+ g_display.dpi_scale_y = 96.0f / g_display.dpi;
#else
- g_dpi = 96.0f;
- g_dpi_scale_x = 1.0f;
- g_dpi_scale_y = 1.0f;
+ g_display.dpi = 96.0f;
+ g_display.dpi_scale_x = 1.0f;
+ g_display.dpi_scale_y = 1.0f;
#endif
- g_dpi_scale_real_x = g_dpi_scale_x;
- g_dpi_scale_real_y = g_dpi_scale_y;
+ g_display.dpi_scale_real_x = g_display.dpi_scale_x;
+ g_display.dpi_scale_real_y = g_display.dpi_scale_y;
smallWindow = IsWindowSmall(width, height);
if (smallWindow) {
- g_dpi /= 2.0f;
- g_dpi_scale_x *= 2.0f;
- g_dpi_scale_y *= 2.0f;
+ g_display.dpi /= 2.0f;
+ g_display.dpi_scale_x *= 2.0f;
+ g_display.dpi_scale_y *= 2.0f;
}
- pixel_in_dps_x = 1.0f / g_dpi_scale_x;
- pixel_in_dps_y = 1.0f / g_dpi_scale_y;
+ g_display.pixel_in_dps_x = 1.0f / g_display.dpi_scale_x;
+ g_display.pixel_in_dps_y = 1.0f / g_display.dpi_scale_y;
- int new_dp_xres = (int)(width * g_dpi_scale_x);
- int new_dp_yres = (int)(height * g_dpi_scale_y);
+ int new_dp_xres = (int)(width * g_display.dpi_scale_x);
+ int new_dp_yres = (int)(height * g_display.dpi_scale_y);
- bool dp_changed = new_dp_xres != dp_xres || new_dp_yres != dp_yres;
- bool px_changed = pixel_xres != width || pixel_yres != height;
+ bool dp_changed = new_dp_xres != g_display.dp_xres || new_dp_yres != g_display.dp_yres;
+ bool px_changed = g_display.pixel_xres != width || g_display.pixel_yres != height;
if (dp_changed || px_changed) {
- dp_xres = new_dp_xres;
- dp_yres = new_dp_yres;
- pixel_xres = width;
- pixel_yres = height;
+ g_display.dp_xres = new_dp_xres;
+ g_display.dp_yres = new_dp_yres;
+ g_display.pixel_xres = width;
+ g_display.pixel_yres = height;
NativeResized();
return true;
}
diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index 0ad2df793f..0fad6b30a7 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -591,7 +591,6 @@
-
@@ -1157,7 +1156,6 @@
-
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index 1fe06c2b6e..4b2b04de05 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -652,9 +652,6 @@
FileLoaders
-
- Core
-
MIPS\IR
@@ -1737,9 +1734,6 @@
FileLoaders
-
- Core
-
MIPS\IR
diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp
index 27abc90564..b4fc833452 100644
--- a/Core/FileSystems/DirectoryFileSystem.cpp
+++ b/Core/FileSystems/DirectoryFileSystem.cpp
@@ -980,7 +980,7 @@ int VFSFileSystem::OpenFile(std::string filename, FileAccess access, const char
VERBOSE_LOG(FILESYS, "VFSFileSystem actually opening %s (%s)", fullNameC, filename.c_str());
size_t size;
- u8 *data = VFSReadFile(fullNameC, &size);
+ u8 *data = g_VFS.ReadFile(fullNameC, &size);
if (!data) {
ERROR_LOG(FILESYS, "VFSFileSystem failed to open %s", filename.c_str());
return SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND;
@@ -1001,7 +1001,7 @@ PSPFileInfo VFSFileSystem::GetFileInfo(std::string filename) {
std::string fullName = GetLocalPath(filename);
File::FileInfo fo;
- if (VFSGetFileInfo(fullName.c_str(), &fo)) {
+ if (g_VFS.GetFileInfo(fullName.c_str(), &fo)) {
x.exists = fo.exists;
if (x.exists) {
x.size = fo.size;
diff --git a/Core/HLE/sceCtrl.cpp b/Core/HLE/sceCtrl.cpp
index ab9d15bf9d..898ba6e37b 100644
--- a/Core/HLE/sceCtrl.cpp
+++ b/Core/HLE/sceCtrl.cpp
@@ -20,6 +20,7 @@
#include "Common/Serialize/Serializer.h"
#include "Common/Serialize/SerializeFuncs.h"
+#include "Common/Math/math_util.h"
#include "Core/CoreTiming.h"
#include "Core/HLE/HLE.h"
#include "Core/HLE/FunctionWrappers.h"
@@ -28,6 +29,7 @@
#include "Core/HLE/sceKernelThread.h"
#include "Core/HLE/sceKernelInterrupt.h"
#include "Core/HW/Display.h"
+#include "Core/System.h"
#include "Core/MemMapHelpers.h"
#include "Core/MIPS/MIPS.h"
#include "Core/Replay.h"
@@ -118,6 +120,20 @@ static void __CtrlUpdateLatch()
// Copy in the current data to the current buffer.
ctrlBufs[ctrlBuf] = ctrlCurrent;
+
+ if (PSP_CoreParameter().compat.flags().DaxterRotatedAnalogStick) {
+ // For some reason, Daxter rotates the analog input. See #17015
+ float angle = (15.0f / 360.0f) * (2.0f * M_PI);
+ float cosAngle = cosf(angle);
+ float sinAngle = sinf(angle);
+ float x = ctrlBufs[ctrlBuf].analog[0][0] - 128;
+ float y = ctrlBufs[ctrlBuf].analog[0][1] - 128;
+ float rX = x * cosAngle - y * sinAngle;
+ float rY = x * sinAngle + y * cosAngle;
+ ctrlBufs[ctrlBuf].analog[0][0] = (u8)Clamp(rX + 128, 0.0f, 255.0f);
+ ctrlBufs[ctrlBuf].analog[0][1] = (u8)Clamp(rY + 128, 0.0f, 255.0f);
+ }
+
ctrlBufs[ctrlBuf].buttons = buttons;
u32 changed = buttons ^ ctrlOldButtons;
diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp
index 342d522627..953c2ab460 100644
--- a/Core/HLE/sceDisplay.cpp
+++ b/Core/HLE/sceDisplay.cpp
@@ -285,10 +285,6 @@ void __DisplayDoState(PointerWrap &p) {
if (p.mode == p.MODE_READ) {
gpu->ReapplyGfxState();
-
- if (hasSetMode) {
- gpu->InitClear();
- }
gpu->SetDisplayFramebuffer(framebuf.topaddr, framebuf.stride, framebuf.fmt);
}
}
@@ -749,10 +745,7 @@ static u32 sceDisplaySetMode(int displayMode, int displayWidth, int displayHeigh
return hleLogWarning(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid size");
}
- if (!hasSetMode) {
- gpu->InitClear();
- hasSetMode = true;
- }
+ hasSetMode = true;
mode = displayMode;
width = displayWidth;
height = displayHeight;
diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp
index 9eb3a678b0..ade4158218 100644
--- a/Core/HLE/sceIo.cpp
+++ b/Core/HLE/sceIo.cpp
@@ -2055,7 +2055,7 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o
// I have a planned further refactoring.
float ar;
if (g_Config.bDisplayStretch) {
- ar = (float)dp_xres / (float)dp_yres;
+ ar = (float)g_display.dp_xres / (float)g_display.dp_yres;
} else {
ar = g_Config.fDisplayAspectRatio * (480.0f / 272.0f);
}
@@ -2066,7 +2066,7 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o
if (Memory::IsValidAddress(outPtr)) {
// TODO: Maybe do something more sophisticated taking the longest side and screen rotation
// into account, etc.
- float scale = float(dp_xres) * g_Config.fDisplayScale / 480.0f;
+ float scale = (float)g_display.dp_xres * g_Config.fDisplayScale / 480.0f;
Memory::Write_Float(scale, outPtr);
}
return 0;
diff --git a/Core/Reporting.cpp b/Core/Reporting.cpp
index d85533d670..946285dfea 100644
--- a/Core/Reporting.cpp
+++ b/Core/Reporting.cpp
@@ -569,7 +569,7 @@ namespace Reporting
return false;
#else
File::FileInfo fo;
- if (!VFSGetFileInfo("flash0/font/jpn0.pgf", &fo))
+ if (!g_VFS.GetFileInfo("flash0/font/jpn0.pgf", &fo))
return false;
#endif
diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp
index 2715d897b0..3f51aebbc6 100644
--- a/Core/SaveState.cpp
+++ b/Core/SaveState.cpp
@@ -291,10 +291,10 @@ namespace SaveState
}
private:
- static const int BLOCK_SIZE = 8192;
- static const int REWIND_NUM_STATES = 20;
+ const int BLOCK_SIZE = 8192;
+ const int REWIND_NUM_STATES = 20;
// TODO: Instead, based on size of compressed state?
- static const int BASE_USAGE_INTERVAL = 15;
+ const int BASE_USAGE_INTERVAL = 15;
typedef std::vector StateBuffer;
diff --git a/Core/Screenshot.cpp b/Core/Screenshot.cpp
index 6ad9de9316..492ffab35c 100644
--- a/Core/Screenshot.cpp
+++ b/Core/Screenshot.cpp
@@ -344,11 +344,11 @@ bool TakeGameScreenshot(const Path &filename, ScreenshotFormat fmt, ScreenshotTy
// Only crop to the top left when using a render screenshot.
w = maxRes > 0 ? 480 * maxRes : PSP_CoreParameter().renderWidth;
h = maxRes > 0 ? 272 * maxRes : PSP_CoreParameter().renderHeight;
- } else if (g_display_rotation != DisplayRotation::ROTATE_0) {
+ } else if (g_display.rotation != DisplayRotation::ROTATE_0) {
GPUDebugBuffer temp;
success = gpuDebug->GetOutputFramebuffer(temp);
if (success) {
- buf = ApplyRotation(temp, g_display_rotation);
+ buf = ApplyRotation(temp, g_display.rotation);
}
} else {
success = gpuDebug->GetOutputFramebuffer(buf);
diff --git a/Core/TextureReplacer.h b/Core/TextureReplacer.h
deleted file mode 100644
index cc9e4abed1..0000000000
--- a/Core/TextureReplacer.h
+++ /dev/null
@@ -1,311 +0,0 @@
-// Copyright (c) 2016- 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 "ppsspp_config.h"
-#include
-#include
-#include
-#include
-
-#include "Common/CommonFuncs.h"
-#include "Common/CommonTypes.h"
-#include "Common/MemoryUtil.h"
-#include "Common/File/Path.h"
-#include "Common/GPU/DataFormat.h"
-
-#include "GPU/Common/TextureDecoder.h"
-#include "GPU/ge_constants.h"
-
-class IniFile;
-class TextureCacheCommon;
-class TextureReplacer;
-class ReplacedTextureTask;
-class LimitedWaitable;
-struct zip;
-
-// These must match the constants in TextureCacheCommon.
-enum class ReplacedTextureAlpha {
- UNKNOWN = 0x04,
- FULL = 0x00,
-};
-
-// For forward comatibility, we specify the hash.
-enum class ReplacedTextureHash {
- QUICK,
- XXH32,
- XXH64,
-};
-
-struct ReplacerZipInfo {
- zip *z = nullptr;
- std::mutex lock;
-
- void Close();
-};
-
-struct ReplacedTextureLevel {
- int w;
- int h;
- Draw::DataFormat fmt; // NOTE: Right now, the only supported format is Draw::DataFormat::R8G8B8A8_UNORM.
- Path file;
- // Can be ignored for hashing/equal, since file has all uniqueness.
- // To be able to reload, we need to be able to reopen, unfortunate we can't use zip_file_t.
- ReplacerZipInfo *zinfo = nullptr;
- int64_t zi = -1;
-
- bool operator ==(const ReplacedTextureLevel &other) const {
- if (w != other.w || h != other.h || fmt != other.fmt)
- return false;
- return file == other.file;
- }
-};
-
-namespace std {
- template <>
- struct hash {
- std::size_t operator()(const ReplacedTextureLevel &k) const {
-#if PPSSPP_ARCH(64BIT)
- uint64_t v = (uint64_t)k.w | ((uint64_t)k.h << 32);
- v = __rotl64(v ^ (uint64_t)k.fmt, 13);
-#else
- uint32_t v = k.w ^ (uint32_t)k.fmt;
- v = __rotl(__rotl(v, 13) ^ k.h, 13);
-#endif
- return v ^ hash()(k.file.ToString());
- }
- };
-}
-
-struct ReplacedLevelCache {
- std::mutex lock;
- std::vector data;
- double lastUsed = 0.0;
-};
-
-struct ReplacementCacheKey {
- u64 cachekey;
- u32 hash;
-
- ReplacementCacheKey(u64 c, u32 h) : cachekey(c), hash(h) { }
-
- bool operator ==(const ReplacementCacheKey &k) const {
- return k.cachekey == cachekey && k.hash == hash;
- }
-
- bool operator <(const ReplacementCacheKey &k) const {
- if (k.cachekey == cachekey) {
- return k.hash < hash;
- }
- return k.cachekey < cachekey;
- }
-};
-
-struct ReplacementAliasKey {
- u64 cachekey;
- union {
- u64 hashAndLevel;
- struct {
- u32 level;
- u32 hash;
- };
- };
-
- ReplacementAliasKey(u64 c, u32 h, u32 l) : cachekey(c), level(l), hash(h) { }
-
- bool operator ==(const ReplacementAliasKey &k) const {
- return k.cachekey == cachekey && k.hashAndLevel == hashAndLevel;
- }
-
- bool operator <(const ReplacementAliasKey &k) const {
- if (k.cachekey == cachekey) {
- return k.hashAndLevel < hashAndLevel;
- }
- return k.cachekey < cachekey;
- }
-};
-
-namespace std {
- template <>
- struct hash {
- size_t operator()(const ReplacementCacheKey &k) const {
- return std::hash()(k.cachekey ^ ((u64)k.hash << 32));
- }
- };
-
- template <>
- struct hash {
- size_t operator()(const ReplacementAliasKey &k) const {
- return std::hash()(k.cachekey ^ k.hashAndLevel);
- }
- };
-}
-
-struct ReplacedTexture {
- ~ReplacedTexture();
-
- inline bool Valid() const {
- if (!initDone_)
- return false;
- return !levels_.empty();
- }
-
- inline bool IsInvalid() const {
- if (!initDone_)
- return false;
- return levels_.empty();
- }
-
- bool GetSize(int level, int &w, int &h) const {
- if (!initDone_)
- return false;
- if ((size_t)level < levels_.size()) {
- w = levels_[level].w;
- h = levels_[level].h;
- return true;
- }
- return false;
- }
-
- int NumLevels() const {
- if (!initDone_)
- return 0;
- return (int)levels_.size();
- }
-
- Draw::DataFormat Format(int level) const {
- if (initDone_) {
- if ((size_t)level < levels_.size()) {
- return levels_[level].fmt;
- }
- }
- return Draw::DataFormat::R8G8B8A8_UNORM;
- }
-
- u8 AlphaStatus() const {
- return (u8)alphaStatus_;
- }
-
- bool IsReady(double budget);
-
- bool Load(int level, void *out, int rowPitch);
-
-protected:
- void Prepare();
- void PrepareData(int level);
- void PurgeIfOlder(double t);
-
- std::vector levels_;
- std::vector levelData_;
- ReplacedTextureAlpha alphaStatus_ = ReplacedTextureAlpha::UNKNOWN;
- double lastUsed_ = 0.0;
- LimitedWaitable *threadWaitable_ = nullptr;
- std::mutex mutex_;
- bool cancelPrepare_ = false;
- bool initDone_ = false;
- bool prepareDone_ = false;
-
- friend TextureReplacer;
- friend ReplacedTextureTask;
-};
-
-struct ReplacedTextureDecodeInfo {
- u64 cachekey;
- u32 hash;
- u32 addr;
- bool isVideo;
- bool isFinal;
- int scaleFactor;
- Draw::DataFormat fmt;
-};
-
-enum class ReplacerDecimateMode {
- NEW_FRAME,
- FORCE_PRESSURE,
- ALL,
-};
-
-class TextureReplacer {
-public:
- TextureReplacer();
- ~TextureReplacer();
-
- void Init();
- void NotifyConfigChanged();
-
- inline bool Enabled() {
- return enabled_;
- }
-
- u32 ComputeHash(u32 addr, int bufw, int w, int h, GETextureFormat fmt, u16 maxSeenV);
-
- ReplacedTexture &FindReplacement(u64 cachekey, u32 hash, int w, int h, double budget);
- bool FindFiltering(u64 cachekey, u32 hash, TextureFiltering *forceFiltering);
- ReplacedTexture &FindNone() {
- return none_;
- }
-
- // Check if a NotifyTextureDecoded for this texture is desired (used to avoid reads from write-combined memory.)
- bool WillSave(const ReplacedTextureDecodeInfo &replacedInfo);
-
- // Notify that a new texture was decoded. May already be upscaled, saves the data passed.
- void NotifyTextureDecoded(const ReplacedTextureDecodeInfo &replacedInfo, const void *data, int pitch, int level, int w, int h);
-
- void Decimate(ReplacerDecimateMode mode);
-
- static bool GenerateIni(const std::string &gameID, Path &generatedFilename);
- static bool IniExists(const std::string &gameID);
-
-protected:
- bool LoadIni();
- bool LoadIniValues(IniFile &ini, bool isOverride = false);
- void ParseHashRange(const std::string &key, const std::string &value);
- void ParseFiltering(const std::string &key, const std::string &value);
- void ParseReduceHashRange(const std::string& key, const std::string& value);
- bool LookupHashRange(u32 addr, int &w, int &h);
- float LookupReduceHashRange(int& w, int& h);
- std::string LookupHashFile(u64 cachekey, u32 hash, int level);
- std::string HashName(u64 cachekey, u32 hash, int level);
- void PopulateReplacement(ReplacedTexture *result, u64 cachekey, u32 hash, int w, int h);
- bool PopulateLevelFromPath(ReplacedTextureLevel &level, bool ignoreError);
- bool PopulateLevelFromZip(ReplacedTextureLevel &level, bool ignoreError);
-
- bool enabled_ = false;
- bool allowVideo_ = false;
- bool ignoreAddress_ = false;
- bool reduceHash_ = false;
- float reduceHashSize = 1.0; // default value with reduceHash to false
- float reduceHashGlobalValue = 0.5; // Global value for textures dump pngs of all sizes, 0.5 by default but can be set in textures.ini
- double lastTextureCacheSizeGB_ = 0.0;
- bool ignoreMipmap_ = false;
- std::string gameID_;
- Path basePath_;
- ReplacedTextureHash hash_ = ReplacedTextureHash::QUICK;
- ReplacerZipInfo zip_;
-
- typedef std::pair WidthHeightPair;
- std::unordered_map hashranges_;
- std::unordered_map reducehashranges_;
- std::unordered_map aliases_;
- std::unordered_map filtering_;
-
- ReplacedTexture none_;
- std::unordered_map cache_;
- std::unordered_map> savedCache_;
- std::unordered_map levelCache_;
-};
diff --git a/Core/Util/PPGeDraw.cpp b/Core/Util/PPGeDraw.cpp
index 525937a512..12dc1e86a9 100644
--- a/Core/Util/PPGeDraw.cpp
+++ b/Core/Util/PPGeDraw.cpp
@@ -252,7 +252,7 @@ void __PPGeInit() {
if (loadedZIM) {
size_t atlas_data_size;
if (!g_ppge_atlas.IsMetadataLoaded()) {
- uint8_t *atlas_data = VFSReadFile("ppge_atlas.meta", &atlas_data_size);
+ uint8_t *atlas_data = g_VFS.ReadFile("ppge_atlas.meta", &atlas_data_size);
if (atlas_data)
g_ppge_atlas.Load(atlas_data, atlas_data_size);
delete[] atlas_data;
diff --git a/Core/WebServer.cpp b/Core/WebServer.cpp
index 3de0fabc7b..5784827021 100644
--- a/Core/WebServer.cpp
+++ b/Core/WebServer.cpp
@@ -237,7 +237,7 @@ static bool ServeDebuggerFile(const http::Request &request) {
return false;
size_t size;
- uint8_t *data = VFSReadFile(filename, &size);
+ uint8_t *data = g_VFS.ReadFile(filename, &size);
if (!data)
return false;
diff --git a/GPU/Common/DepthBufferCommon.cpp b/GPU/Common/DepthBufferCommon.cpp
index 3c78362352..a29c995775 100644
--- a/GPU/Common/DepthBufferCommon.cpp
+++ b/GPU/Common/DepthBufferCommon.cpp
@@ -204,10 +204,10 @@ bool FramebufferManagerCommon::ReadbackDepthbuffer(Draw::Framebuffer *fbo, int x
}
shaderManager_->DirtyLastShader();
- auto *blitFBO = GetTempFBO(TempFBO::COPY, fbo->Width() * scaleX, fbo->Height() * scaleY);
+ auto *blitFBO = GetTempFBO(TempFBO::Z_COPY, fbo->Width() * scaleX, fbo->Height() * scaleY);
draw_->BindFramebufferAsRenderTarget(blitFBO, { RPAction::DONT_CARE, RPAction::DONT_CARE, RPAction::DONT_CARE }, "ReadbackDepthbufferSync");
Draw::Viewport viewport = { 0.0f, 0.0f, (float)destW, (float)destH, 0.0f, 1.0f };
- draw_->SetViewports(1, &viewport);
+ draw_->SetViewport(viewport);
draw_->SetScissorRect(0, 0, fbo->Width() * scaleX, fbo->Height() * scaleY);
draw_->BindFramebufferAsTexture(fbo, TEX_SLOT_PSP_TEXTURE, FB_DEPTH_BIT, 0);
diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp
index 139d47613c..59083f5352 100644
--- a/GPU/Common/DrawEngineCommon.cpp
+++ b/GPU/Common/DrawEngineCommon.cpp
@@ -36,7 +36,9 @@ enum {
};
DrawEngineCommon::DrawEngineCommon() : decoderMap_(16) {
- decJitCache_ = new VertexDecoderJitCache();
+ if (g_Config.bVertexDecoderJit && g_Config.iCpuCore == (int)CPUCore::JIT) {
+ decJitCache_ = new VertexDecoderJitCache();
+ }
transformed = (TransformedVertex *)AllocateMemoryPages(TRANSFORMED_VERTEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE);
transformedExpanded = (TransformedVertex *)AllocateMemoryPages(3 * TRANSFORMED_VERTEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE);
}
@@ -169,7 +171,8 @@ static Vec3f ScreenToDrawing(const Vec3f& coords) {
}
void DrawEngineCommon::NotifyConfigChanged() {
- decJitCache_->Clear();
+ if (decJitCache_)
+ decJitCache_->Clear();
lastVType_ = -1;
dec_ = nullptr;
decoderMap_.Iterate([&](const uint32_t vtype, VertexDecoder *decoder) {
diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h
index 3e2891c4a3..94ce1f35e7 100644
--- a/GPU/Common/DrawEngineCommon.h
+++ b/GPU/Common/DrawEngineCommon.h
@@ -74,6 +74,8 @@ public:
virtual ~DrawEngineCommon();
void Init();
+ virtual void DeviceLost() = 0;
+ virtual void DeviceRestore(Draw::DrawContext *draw) = 0;
bool GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices);
@@ -115,7 +117,9 @@ public:
}
bool IsCodePtrVertexDecoder(const u8 *ptr) const {
- return decJitCache_->IsInSpace(ptr);
+ if (decJitCache_)
+ return decJitCache_->IsInSpace(ptr);
+ return false;
}
int GetNumDrawCalls() const {
return numDrawCalls;
@@ -123,9 +127,10 @@ public:
VertexDecoder *GetVertexDecoder(u32 vtype);
+ virtual void ClearTrackedVertexArrays() {}
+
protected:
virtual bool UpdateUseHWTessellation(bool enabled) { return enabled; }
- virtual void ClearTrackedVertexArrays() {}
int ComputeNumVertsToDecode() const;
void DecodeVerts(u8 *dest);
diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp
index a126bb7fb2..e21bc35e93 100644
--- a/GPU/Common/FramebufferManagerCommon.cpp
+++ b/GPU/Common/FramebufferManagerCommon.cpp
@@ -546,6 +546,8 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(Framebuffer
// TODO: Is it worth trying to upload the depth buffer (only if it wasn't copied above..?)
}
+ DiscardFramebufferCopy();
+
// We already have it!
} else if (vfb != currentRenderVfb_) {
// Use it as a render target.
@@ -562,6 +564,8 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(Framebuffer
NotifyRenderFramebufferSwitched(prev, vfb, params.isClearingDepth);
CopyToColorFromOverlappingFramebuffers(vfb);
gstate_c.usingDepth = false; // reset depth buffer tracking
+
+ DiscardFramebufferCopy();
} else {
// Something changed, but we still got the same framebuffer we were already rendering to.
// Might not be a lot to do here, we check in NotifyRenderFramebufferUpdated
@@ -928,6 +932,7 @@ void FramebufferManagerCommon::DestroyFramebuf(VirtualFramebuffer *v) {
}
// Wipe some pointers
+ DiscardFramebufferCopy();
if (currentRenderVfb_ == v)
currentRenderVfb_ = nullptr;
if (displayFramebuf_ == v)
@@ -1205,8 +1210,8 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int
// TODO: Replace with draw2D_.Blit() directly.
DrawActiveTexture(dstX, dstY, width, height,
- vfb ? vfb->bufferWidth : pixel_xres,
- vfb ? vfb->bufferHeight : pixel_yres,
+ vfb ? vfb->bufferWidth : g_display.pixel_xres,
+ vfb ? vfb->bufferHeight : g_display.pixel_yres,
u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags);
gpuStats.numUploads++;
@@ -1233,13 +1238,27 @@ bool FramebufferManagerCommon::BindFramebufferAsColorTexture(int stage, VirtualF
// Self-texturing, need a copy currently (some backends can potentially support it though).
WARN_LOG_ONCE(selfTextureCopy, G3D, "Attempting to texture from current render target (src=%08x / target=%08x / flags=%d), making a copy", framebuffer->fb_address, currentRenderVfb_->fb_address, flags);
// TODO: Maybe merge with bvfbs_? Not sure if those could be packing, and they're created at a different size.
+ if (currentFramebufferCopy_) {
+ // We have a copy already that hasn't been invalidated, let's keep using it.
+ draw_->BindFramebufferAsTexture(currentFramebufferCopy_, stage, Draw::FB_COLOR_BIT, layer);
+ return true;
+ }
+
Draw::Framebuffer *renderCopy = GetTempFBO(TempFBO::COPY, framebuffer->renderWidth, framebuffer->renderHeight);
if (renderCopy) {
VirtualFramebuffer copyInfo = *framebuffer;
copyInfo.fbo = renderCopy;
- CopyFramebufferForColorTexture(©Info, framebuffer, flags, layer);
+
+ bool partial = false;
+ CopyFramebufferForColorTexture(©Info, framebuffer, flags, layer, &partial);
RebindFramebuffer("After BindFramebufferAsColorTexture");
draw_->BindFramebufferAsTexture(renderCopy, stage, Draw::FB_COLOR_BIT, layer);
+
+ // Only cache the copy if it wasn't a partial copy.
+ // TODO: Improve on this.
+ if (!partial) {
+ currentFramebufferCopy_ = renderCopy;
+ }
gpuStats.numCopiesForSelfTex++;
} else {
// Failed to get temp FBO? Weird.
@@ -1262,14 +1281,17 @@ bool FramebufferManagerCommon::BindFramebufferAsColorTexture(int stage, VirtualF
}
}
-void FramebufferManagerCommon::CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags, int layer) {
+void FramebufferManagerCommon::CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags, int layer, bool *partial) {
int x = 0;
int y = 0;
int w = src->drawnWidth;
int h = src->drawnHeight;
+ *partial = false;
+
// If max is not > min, we probably could not detect it. Skip.
// See the vertex decoder, where this is updated.
+ // TODO: We're currently not hitting this path in Dante. See #17032
if ((flags & BINDFBCOLOR_MAY_COPY_WITH_UV) == BINDFBCOLOR_MAY_COPY_WITH_UV && gstate_c.vertBounds.maxU > gstate_c.vertBounds.minU) {
x = std::max(gstate_c.vertBounds.minU, (u16)0);
y = std::max(gstate_c.vertBounds.minV, (u16)0);
@@ -1287,6 +1309,9 @@ void FramebufferManagerCommon::CopyFramebufferForColorTexture(VirtualFramebuffer
}
if (x < src->drawnWidth && y < src->drawnHeight && w > 0 && h > 0) {
+ if (x != 0 || y != 0 || w < src->drawnWidth || h < src->drawnHeight) {
+ *partial = true;
+ }
BlitFramebuffer(dst, x, y, src, x, y, w, h, 0, RASTER_COLOR, "CopyFBForColorTexture");
}
}
@@ -1384,6 +1409,7 @@ Draw::Texture *FramebufferManagerCommon::MakePixelTexture(const u8 *srcPixels, G
1,
1,
false,
+ Draw::TextureSwizzle::DEFAULT,
"DrawPixels",
{ (uint8_t *)srcPixels },
generateTexture,
@@ -1425,12 +1451,13 @@ void FramebufferManagerCommon::DrawFramebufferToOutput(const u8 *srcPixels, int
// PresentationCommon sets all kinds of state, we can't rely on anything.
gstate_c.Dirty(DIRTY_ALL);
+ DiscardFramebufferCopy();
currentRenderVfb_ = nullptr;
}
void FramebufferManagerCommon::SetViewport2D(int x, int y, int w, int h) {
- Draw::Viewport vp{ (float)x, (float)y, (float)w, (float)h, 0.0f, 1.0f };
- draw_->SetViewports(1, &vp);
+ Draw::Viewport viewport{ (float)x, (float)y, (float)w, (float)h, 0.0f, 1.0f };
+ draw_->SetViewport(viewport);
}
void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) {
@@ -1582,10 +1609,12 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) {
// This may get called mid-draw if the game uses an immediate flip.
// PresentationCommon sets all kinds of state, we can't rely on anything.
gstate_c.Dirty(DIRTY_ALL);
+ DiscardFramebufferCopy();
currentRenderVfb_ = nullptr;
}
void FramebufferManagerCommon::DecimateFBOs() {
+ DiscardFramebufferCopy();
currentRenderVfb_ = nullptr;
for (auto iter : fbosToDelete_) {
@@ -1742,6 +1771,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w,
} else {
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "ResizeFramebufFBO");
}
+ DiscardFramebufferCopy();
currentRenderVfb_ = vfb;
if (!vfb->fbo) {
@@ -2543,6 +2573,7 @@ void FramebufferManagerCommon::NotifyConfigChanged() {
}
void FramebufferManagerCommon::DestroyAllFBOs() {
+ DiscardFramebufferCopy();
currentRenderVfb_ = nullptr;
displayFramebuf_ = nullptr;
prevDisplayFramebuf_ = nullptr;
@@ -3081,11 +3112,11 @@ void FramebufferManagerCommon::DrawActiveTexture(float x, float y, float w, floa
coord[i].y = coord[i].y * invDestH - 1.0f;
}
- if ((flags & DRAWTEX_TO_BACKBUFFER) && g_display_rotation != DisplayRotation::ROTATE_0) {
+ if ((flags & DRAWTEX_TO_BACKBUFFER) && g_display.rotation != DisplayRotation::ROTATE_0) {
for (int i = 0; i < 4; i++) {
// backwards notation, should fix that...
Lin::Vec3 pos = Lin::Vec3(coord[i].x, coord[i].y, 0.0);
- pos = pos * g_display_rot_matrix;
+ pos = pos * g_display.rot_matrix;
coord[i].x = pos.x;
coord[i].y = pos.y;
}
@@ -3235,8 +3266,8 @@ void FramebufferManagerCommon::BlitUsingRaster(
draw_->InvalidateFramebuffer(Draw::FB_INVALIDATION_LOAD, pipeline->info.writeChannel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT);
}
- Draw::Viewport vp{ 0.0f, 0.0f, (float)dest->Width(), (float)dest->Height(), 0.0f, 1.0f };
- draw_->SetViewports(1, &vp);
+ Draw::Viewport viewport{ 0.0f, 0.0f, (float)dest->Width(), (float)dest->Height(), 0.0f, 1.0f };
+ draw_->SetViewport(viewport);
draw_->SetScissorRect(0, 0, (int)dest->Width(), (int)dest->Height());
draw2D_.Blit(pipeline, srcX1, srcY1, srcX2, srcY2, destX1, destY1, destX2, destY2, (float)srcW, (float)srcH, (float)destW, (float)destH, linearFilter, scaleFactor);
diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h
index 672130f7aa..d0c83b4d6c 100644
--- a/GPU/Common/FramebufferManagerCommon.h
+++ b/GPU/Common/FramebufferManagerCommon.h
@@ -217,6 +217,8 @@ enum class TempFBO {
BLIT,
// For copies of framebuffers (e.g. shader blending.)
COPY,
+ // Used for copies when setting color to depth.
+ Z_COPY,
// Used to copy stencil data, means we need a stencil backing.
STENCIL,
};
@@ -466,6 +468,10 @@ public:
return msaaLevel_;
}
+ void DiscardFramebufferCopy() {
+ currentFramebufferCopy_ = nullptr;
+ }
+
protected:
virtual void ReadbackFramebuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel, Draw::ReadbackMode mode);
// Used for when a shader is required, such as GLES.
@@ -486,7 +492,7 @@ protected:
// Used by ReadFramebufferToMemory and later framebuffer block copies
void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, RasterChannel channel, const char *tag);
- void CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags, int layer);
+ void CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags, int layer, bool *partial);
void EstimateDrawingSize(u32 fb_address, int fb_stride, GEBufferFormat fb_format, int viewport_width, int viewport_height, int region_width, int region_height, int scissor_width, int scissor_height, int &drawing_width, int &drawing_height);
@@ -552,6 +558,8 @@ protected:
VirtualFramebuffer *currentRenderVfb_ = nullptr;
+ Draw::Framebuffer *currentFramebufferCopy_ = nullptr;
+
// The range of PSP memory that may contain FBOs. So we can skip iterating.
u32 framebufRangeEnd_ = 0;
diff --git a/GPU/Common/PostShader.cpp b/GPU/Common/PostShader.cpp
index 831bc1bf85..51864c903c 100644
--- a/GPU/Common/PostShader.cpp
+++ b/GPU/Common/PostShader.cpp
@@ -70,7 +70,7 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct
for (size_t d = 0; d < directories.size(); d++) {
std::vector fileInfo;
- VFSGetFileListing(directories[d].c_str(), &fileInfo, "ini:");
+ g_VFS.GetFileListing(directories[d].c_str(), &fileInfo, "ini:");
if (fileInfo.empty()) {
File::GetFilesInDir(directories[d], &fileInfo, "ini:");
@@ -90,7 +90,7 @@ void LoadPostShaderInfo(Draw::DrawContext *draw, const std::vector &direct
if (path.ToString().substr(0, 7) == "assets/")
path = Path(path.ToString().substr(7));
- if (ini.LoadFromVFS(name.ToString()) || ini.Load(fileInfo[f].fullName)) {
+ if (ini.LoadFromVFS(g_VFS, name.ToString()) || ini.Load(fileInfo[f].fullName)) {
success = true;
// vsh load. meh.
}
diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp
index 4341961214..3da9c795f9 100644
--- a/GPU/Common/PresentationCommon.cpp
+++ b/GPU/Common/PresentationCommon.cpp
@@ -55,10 +55,10 @@ FRect GetScreenFrame(float pixelWidth, float pixelHeight) {
if (applyInset) {
// Remove the DPI scale to get back to pixels.
- float left = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT) / g_dpi_scale_x;
- float right = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_RIGHT) / g_dpi_scale_x;
- float top = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP) / g_dpi_scale_y;
- float bottom = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_BOTTOM) / g_dpi_scale_y;
+ float left = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT) / g_display.dpi_scale_x;
+ float right = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_RIGHT) / g_display.dpi_scale_x;
+ float top = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP) / g_display.dpi_scale_y;
+ float bottom = System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_BOTTOM) / g_display.dpi_scale_y;
// Adjust left edge to compensate for cutouts (notches) if any.
rc.x += left;
@@ -100,8 +100,8 @@ void CenterDisplayOutputRect(FRect *rc, float origW, float origH, const FRect &f
if (stretch) {
// Automatically set aspect ratio to match the display, IF the rotation matches the output display ratio! Otherwise, just
// sets standard aspect ratio because actually stretching will just look silly.
- bool globalRotated = g_display_rotation == DisplayRotation::ROTATE_90 || g_display_rotation == DisplayRotation::ROTATE_270;
- if (rotated == dp_yres > dp_xres) {
+ bool globalRotated = g_display.rotation == DisplayRotation::ROTATE_90 || g_display.rotation == DisplayRotation::ROTATE_270;
+ if (rotated == g_display.dp_yres > g_display.dp_xres) {
origRatio = frameRatio;
} else {
origRatio *= aspectRatioAdjust;
@@ -212,7 +212,7 @@ void PresentationCommon::CalculatePostShaderUniforms(int bufferWidth, int buffer
static std::string ReadShaderSrc(const Path &filename) {
size_t sz = 0;
- char *data = (char *)VFSReadFile(filename.c_str(), &sz);
+ char *data = (char *)g_VFS.ReadFile(filename.c_str(), &sz);
if (!data) {
return "";
}
@@ -699,11 +699,11 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u
if (isFinalAtOutputResolution || useStereo) {
// In this mode, we ignore the g_display_rot_matrix. Apply manually.
- if (g_display_rotation != DisplayRotation::ROTATE_0) {
+ if (g_display.rotation != DisplayRotation::ROTATE_0) {
for (int i = 0; i < 4; i++) {
Lin::Vec3 v(verts[i].x, verts[i].y, verts[i].z);
// Backwards notation, should fix that...
- v = v * g_display_rot_matrix;
+ v = v * g_display.rot_matrix;
verts[i].x = v.x;
verts[i].y = v.y;
}
@@ -734,7 +734,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u
int nextWidth, nextHeight;
draw_->GetFramebufferDimensions(postShaderFramebuffer, &nextWidth, &nextHeight);
Draw::Viewport viewport{ 0, 0, (float)nextWidth, (float)nextHeight, 0.0f, 1.0f };
- draw_->SetViewports(1, &viewport);
+ draw_->SetViewport(viewport);
draw_->SetScissorRect(0, 0, nextWidth, nextHeight);
CalculatePostShaderUniforms(lastWidth, lastHeight, nextWidth, nextHeight, shaderInfo, &uniforms);
@@ -840,7 +840,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u
draw_->UpdateDynamicUniformBuffer(&uniforms, sizeof(uniforms));
} else {
Draw::VsTexColUB ub{};
- memcpy(ub.WorldViewProj, g_display_rot_matrix.m, sizeof(float) * 16);
+ memcpy(ub.WorldViewProj, g_display.rot_matrix.m, sizeof(float) * 16);
draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub));
}
@@ -853,7 +853,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u
auto setViewport = [&](float x, float y, float w, float h) {
Draw::Viewport viewport{ x, y, w, h, 0.0f, 1.0f };
- draw_->SetViewports(1, &viewport);
+ draw_->SetViewport(viewport);
};
CardboardSettings cardboardSettings;
diff --git a/GPU/Common/ReplacedTexture.cpp b/GPU/Common/ReplacedTexture.cpp
new file mode 100644
index 0000000000..8265f19e82
--- /dev/null
+++ b/GPU/Common/ReplacedTexture.cpp
@@ -0,0 +1,442 @@
+// Copyright (c) 2016- 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 "ppsspp_config.h"
+
+#include
+
+#include "GPU/Common/ReplacedTexture.h"
+#include "GPU/Common/TextureReplacer.h"
+
+#include "Common/Data/Format/IniFile.h"
+#include "Common/Data/Format/ZIMLoad.h"
+#include "Common/Data/Format/PNGLoad.h"
+#include "Common/Thread/ParallelLoop.h"
+#include "Common/Thread/Waitable.h"
+#include "Common/Thread/ThreadManager.h"
+#include "Common/Log.h"
+#include "Common/TimeUtil.h"
+
+class ReplacedTextureTask : public Task {
+public:
+ ReplacedTextureTask(VFSBackend *vfs, ReplacedTexture &tex, LimitedWaitable *w) : vfs_(vfs), tex_(tex), waitable_(w) {}
+
+ TaskType Type() const override {
+ return TaskType::IO_BLOCKING;
+ }
+
+ TaskPriority Priority() const override {
+ return TaskPriority::NORMAL;
+ }
+
+ void Run() override {
+ tex_.Prepare(vfs_);
+ waitable_->Notify();
+ }
+
+private:
+ VFSBackend *vfs_;
+ ReplacedTexture &tex_;
+ LimitedWaitable *waitable_;
+};
+
+// This can only return true if ACTIVE or NOT_FOUND.
+bool ReplacedTexture::IsReady(double budget) {
+ _assert_(vfs_ != nullptr);
+
+ switch (State()) {
+ case ReplacementState::ACTIVE:
+ case ReplacementState::NOT_FOUND:
+ if (threadWaitable_) {
+ if (!threadWaitable_->WaitFor(budget)) {
+ return false;
+ }
+ // Successfully waited! Can get rid of it.
+ threadWaitable_->WaitAndRelease();
+ threadWaitable_ = nullptr;
+ }
+ lastUsed_ = time_now_d();
+ return true;
+ case ReplacementState::UNINITIALIZED:
+ // _dbg_assert_(false);
+ return false;
+ case ReplacementState::CANCEL_INIT:
+ case ReplacementState::PENDING:
+ return false;
+ case ReplacementState::POPULATED:
+ // We're gonna need to spawn a task.
+ break;
+ }
+
+ lastUsed_ = time_now_d();
+
+ // Let's not even start a new texture if we're already behind.
+ if (budget < 0.0)
+ return false;
+
+ _assert_(!threadWaitable_);
+ threadWaitable_ = new LimitedWaitable();
+ g_threadManager.EnqueueTask(new ReplacedTextureTask(vfs_, *this, threadWaitable_));
+ if (threadWaitable_->WaitFor(budget)) {
+ // If we successfully wait here, we're done. The thread will set state accordingly.
+ _assert_(State() == ReplacementState::ACTIVE || State() == ReplacementState::NOT_FOUND || State() == ReplacementState::CANCEL_INIT);
+ return true;
+ }
+ SetState(ReplacementState::PENDING);
+ // Still pending on thread.
+ return false;
+}
+
+void ReplacedTexture::FinishPopulate(const ReplacementDesc &desc) {
+ logId_ = desc.logId;
+ levelData_ = desc.cache;
+
+ // TODO: The rest can be done on the thread.
+
+ for (int i = 0; i < std::min(MAX_REPLACEMENT_MIP_LEVELS, (int)desc.filenames.size()); ++i) {
+ if (desc.filenames[i].empty()) {
+ // Out of valid mip levels. Bail out.
+ break;
+ }
+
+ const Path filename = desc.basePath / desc.filenames[i];
+
+ VFSFileReference *fileRef = vfs_->GetFile(desc.filenames[i].c_str());
+ if (!fileRef) {
+ // If the file doesn't exist, let's just bail immediately here.
+ break;
+ }
+
+ // TODO: Here, if we find a file with multiple built-in mipmap levels,
+ // we'll have to change a bit how things work...
+ ReplacedTextureLevel level;
+ level.file = filename;
+
+ if (i == 0) {
+ fmt = Draw::DataFormat::R8G8B8A8_UNORM;
+ }
+
+ bool good;
+
+ level.fileRef = fileRef;
+ good = PopulateLevel(level, false);
+
+ // We pad files that have been hashrange'd so they are the same texture size.
+ level.w = (level.w * desc.w) / desc.newW;
+ level.h = (level.h * desc.h) / desc.newH;
+
+ if (good && i != 0) {
+ // Check that the mipmap size is correct. Can't load mips of the wrong size.
+ if (level.w != (levels_[0].w >> i) || level.h != (levels_[0].h >> i)) {
+ WARN_LOG(G3D, "Replacement mipmap invalid: size=%dx%d, expected=%dx%d (level %d, '%s')", level.w, level.h, levels_[0].w >> i, levels_[0].h >> i, i, filename.c_str());
+ good = false;
+ }
+ }
+
+ if (good)
+ levels_.push_back(level);
+ // Otherwise, we're done loading mips (bad PNG or bad size, either way.)
+ else
+ break;
+ }
+
+ if (levels_.empty()) {
+ // Bad.
+ SetState(ReplacementState::NOT_FOUND);
+ levelData_ = nullptr;
+ return;
+ }
+
+ // Populate the data pointer.
+ SetState(ReplacementState::POPULATED);
+}
+
+bool ReplacedTexture::PopulateLevel(ReplacedTextureLevel &level, bool ignoreError) {
+ bool good = false;
+
+ if (!level.fileRef) {
+ if (!ignoreError)
+ ERROR_LOG(G3D, "Error opening replacement texture file '%s' in textures.zip", level.file.c_str());
+ return false;
+ }
+
+ size_t fileSize;
+ VFSOpenFile *file = vfs_->OpenFileForRead(level.fileRef, &fileSize);
+ if (!file) {
+ return false;
+ }
+
+ std::string magic;
+ auto imageType = Identify(vfs_, file, &magic);
+
+ if (imageType == ReplacedImageType::ZIM) {
+ uint32_t ignore = 0;
+ struct ZimHeader {
+ uint32_t magic;
+ uint32_t w;
+ uint32_t h;
+ uint32_t flags;
+ } header;
+ good = vfs_->Read(file, &header, sizeof(header)) == sizeof(header);
+ level.w = header.w;
+ level.h = header.h;
+ good = (header.flags & ZIM_FORMAT_MASK) == ZIM_RGBA8888;
+ } else if (imageType == ReplacedImageType::PNG) {
+ PNGHeaderPeek headerPeek;
+ good = vfs_->Read(file, &headerPeek, sizeof(headerPeek)) == sizeof(headerPeek);
+ if (good && headerPeek.IsValidPNGHeader()) {
+ level.w = headerPeek.Width();
+ level.h = headerPeek.Height();
+ good = true;
+ } else {
+ ERROR_LOG(G3D, "Could not get PNG dimensions: %s (zip)", level.file.ToVisualString().c_str());
+ good = false;
+ }
+ } else {
+ ERROR_LOG(G3D, "Could not load texture replacement info: %s - unsupported format %s", level.file.ToVisualString().c_str(), magic.c_str());
+ }
+ vfs_->CloseFile(file);
+
+ return good;
+}
+
+void ReplacedTexture::Prepare(VFSBackend *vfs) {
+ std::unique_lock lock(mutex_);
+ this->vfs_ = vfs;
+
+ if (State() == ReplacementState::CANCEL_INIT) {
+ return;
+ }
+
+ for (int i = 0; i < (int)levels_.size(); ++i) {
+ if (State() == ReplacementState::CANCEL_INIT)
+ break;
+ PrepareData(i);
+ }
+
+ if (threadWaitable_)
+ threadWaitable_->Notify();
+}
+
+void ReplacedTexture::PrepareData(int level) {
+ _assert_msg_((size_t)level < levels_.size(), "Invalid miplevel");
+ _assert_msg_(levelData_ != nullptr, "Level cache not set");
+
+ // We must lock around access to levelData_ in case two textures try to load it at once.
+ std::lock_guard guard(levelData_->lock);
+
+ const ReplacedTextureLevel &info = levels_[level];
+
+ if (levelData_->data.size() <= level) {
+ levelData_->data.resize(level + 1);
+ }
+
+ std::vector &out = levelData_->data[level];
+
+ // Already populated from cache.
+ if (!out.empty()) {
+ SetState(ReplacementState::ACTIVE);
+ return;
+ }
+
+ ReplacedImageType imageType;
+
+ size_t fileSize;
+ VFSOpenFile *openFile = vfs_->OpenFileForRead(info.fileRef, &fileSize);
+
+ std::string magic;
+ imageType = Identify(vfs_, openFile, &magic);
+
+ auto cleanup = [&] {
+ vfs_->CloseFile(openFile);
+ };
+
+ if (imageType == ReplacedImageType::ZIM) {
+ std::unique_ptr zim(new uint8_t[fileSize]);
+ if (!zim) {
+ ERROR_LOG(G3D, "Failed to allocate memory for texture replacement");
+ SetState(ReplacementState::NOT_FOUND);
+ cleanup();
+ return;
+ }
+
+ if (vfs_->Read(openFile, &zim[0], fileSize) != fileSize) {
+ ERROR_LOG(G3D, "Could not load texture replacement: %s - failed to read ZIM", info.file.c_str());
+ SetState(ReplacementState::NOT_FOUND);
+ cleanup();
+ return;
+ }
+
+ int w, h, f;
+ uint8_t *image;
+ if (LoadZIMPtr(&zim[0], fileSize, &w, &h, &f, &image)) {
+ if (w > info.w || h > info.h) {
+ ERROR_LOG(G3D, "Texture replacement changed since header read: %s", info.file.c_str());
+ SetState(ReplacementState::NOT_FOUND);
+ cleanup();
+ return;
+ }
+
+ out.resize(info.w * info.h * 4);
+ if (w == info.w) {
+ memcpy(&out[0], image, info.w * 4 * info.h);
+ } else {
+ for (int y = 0; y < h; ++y) {
+ memcpy(&out[info.w * 4 * y], image + w * 4 * y, w * 4);
+ }
+ }
+ free(image);
+ }
+
+ CheckAlphaResult res = CheckAlpha32Rect((u32 *)&out[0], info.w, w, h, 0xFF000000);
+ if (res == CHECKALPHA_ANY || level == 0) {
+ alphaStatus_ = ReplacedTextureAlpha(res);
+ }
+ } else if (imageType == ReplacedImageType::PNG) {
+ png_image png = {};
+ png.version = PNG_IMAGE_VERSION;
+
+ std::string pngdata;
+ pngdata.resize(fileSize);
+ pngdata.resize(vfs_->Read(openFile, &pngdata[0], fileSize));
+ if (!png_image_begin_read_from_memory(&png, &pngdata[0], pngdata.size())) {
+ ERROR_LOG(G3D, "Could not load texture replacement info: %s - %s (zip)", info.file.c_str(), png.message);
+ SetState(ReplacementState::NOT_FOUND);
+ cleanup();
+ return;
+ }
+ if (png.width > (uint32_t)info.w || png.height > (uint32_t)info.h) {
+ ERROR_LOG(G3D, "Texture replacement changed since header read: %s", info.file.c_str());
+ SetState(ReplacementState::NOT_FOUND);
+ cleanup();
+ return;
+ }
+
+ bool checkedAlpha = false;
+ if ((png.format & PNG_FORMAT_FLAG_ALPHA) == 0) {
+ // Well, we know for sure it doesn't have alpha.
+ if (level == 0) {
+ alphaStatus_ = ReplacedTextureAlpha::FULL;
+ }
+ checkedAlpha = true;
+ }
+ png.format = PNG_FORMAT_RGBA;
+
+ out.resize(info.w * info.h * 4);
+ if (!png_image_finish_read(&png, nullptr, &out[0], info.w * 4, nullptr)) {
+ ERROR_LOG(G3D, "Could not load texture replacement: %s - %s", info.file.c_str(), png.message);
+ SetState(ReplacementState::NOT_FOUND);
+ cleanup();
+ out.resize(0);
+ return;
+ }
+ png_image_free(&png);
+
+ if (!checkedAlpha) {
+ // This will only check the hashed bits.
+ CheckAlphaResult res = CheckAlpha32Rect((u32 *)&out[0], info.w, png.width, png.height, 0xFF000000);
+ if (res == CHECKALPHA_ANY || level == 0) {
+ alphaStatus_ = ReplacedTextureAlpha(res);
+ }
+ }
+ }
+
+ SetState(ReplacementState::ACTIVE);
+ cleanup();
+}
+
+void ReplacedTexture::PurgeIfOlder(double t) {
+ if (threadWaitable_ && !threadWaitable_->WaitFor(0.0))
+ return;
+ if (lastUsed_ >= t)
+ return;
+
+ if (levelData_->lastUsed < t) {
+ // We have to lock since multiple textures might reference this same data.
+ std::lock_guard guard(levelData_->lock);
+ levelData_->data.clear();
+ // This means we have to reload. If we never purge any, there's no need.
+ SetState(ReplacementState::POPULATED);
+ }
+}
+
+ReplacedTexture::~ReplacedTexture() {
+ if (threadWaitable_) {
+ SetState(ReplacementState::CANCEL_INIT);
+
+ std::unique_lock lock(mutex_);
+ threadWaitable_->WaitAndRelease();
+ threadWaitable_ = nullptr;
+ }
+
+ for (auto &level : levels_) {
+ vfs_->ReleaseFile(level.fileRef);
+ level.fileRef = nullptr;
+ }
+}
+
+bool ReplacedTexture::CopyLevelTo(int level, void *out, int rowPitch) {
+ _assert_msg_((size_t)level < levels_.size(), "Invalid miplevel");
+ _assert_msg_(out != nullptr && rowPitch > 0, "Invalid out/pitch");
+
+ if (State() != ReplacementState::ACTIVE) {
+ WARN_LOG(G3D, "Init not done yet");
+ return false;
+ }
+
+ // We probably could avoid this lock, but better to play it safe.
+ std::lock_guard guard(levelData_->lock);
+
+ const ReplacedTextureLevel &info = levels_[level];
+ const std::vector &data = levelData_->data[level];
+
+ if (data.empty()) {
+ WARN_LOG(G3D, "Level %d is empty", level);
+ return false;
+ }
+
+ if (rowPitch < info.w * 4) {
+ ERROR_LOG(G3D, "Replacement rowPitch=%d, but w=%d (level=%d)", rowPitch, info.w * 4, level);
+ return false;
+ }
+ _assert_msg_(data.size() == info.w * info.h * 4, "Data has wrong size");
+
+ if (rowPitch == info.w * 4) {
+ ParallelMemcpy(&g_threadManager, out, &data[0], info.w * 4 * info.h);
+ } else {
+ const int MIN_LINES_PER_THREAD = 4;
+ ParallelRangeLoop(&g_threadManager, [&](int l, int h) {
+ for (int y = l; y < h; ++y) {
+ memcpy((uint8_t *)out + rowPitch * y, &data[0] + info.w * 4 * y, info.w * 4);
+ }
+ }, 0, info.h, MIN_LINES_PER_THREAD);
+ }
+
+ return true;
+}
+
+const char *StateString(ReplacementState state) {
+ switch (state) {
+ case ReplacementState::UNINITIALIZED: return "UNINITIALIZED";
+ case ReplacementState::POPULATED: return "PREPARED";
+ case ReplacementState::PENDING: return "PENDING";
+ case ReplacementState::NOT_FOUND: return "NOT_FOUND";
+ case ReplacementState::ACTIVE: return "ACTIVE";
+ case ReplacementState::CANCEL_INIT: return "CANCEL_INIT";
+ default: return "N/A";
+ }
+}
diff --git a/GPU/Common/ReplacedTexture.h b/GPU/Common/ReplacedTexture.h
new file mode 100644
index 0000000000..2911c5fef1
--- /dev/null
+++ b/GPU/Common/ReplacedTexture.h
@@ -0,0 +1,157 @@
+// Copyright (c) 2016- 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
+#include
+
+#include "Common/File/VFS/VFS.h"
+#include "Common/GPU/thin3d.h"
+#include "Common/Log.h"
+
+struct ReplacedLevelsCache;
+class TextureReplacer;
+class LimitedWaitable;
+
+// These must match the constants in TextureCacheCommon.
+enum class ReplacedTextureAlpha {
+ UNKNOWN = 0x04,
+ FULL = 0x00,
+};
+
+// For forward compatibility, we specify the hash.
+enum class ReplacedTextureHash {
+ QUICK,
+ XXH32,
+ XXH64,
+};
+
+enum class ReplacedImageType {
+ PNG,
+ ZIM,
+ INVALID,
+};
+
+static const int MAX_REPLACEMENT_MIP_LEVELS = 12; // 12 should be plenty, 8 is the max mip levels supported by the PSP.
+
+// Metadata about a given texture level.
+struct ReplacedTextureLevel {
+ int w = 0;
+ int h = 0;
+ Path file;
+
+ // To be able to reload, we need to be able to reopen, unfortunate we can't use zip_file_t.
+ // TODO: This really belongs on the level in the cache, not in the individual ReplacedTextureLevel objects.
+ VFSFileReference *fileRef = nullptr;
+};
+
+ReplacedImageType Identify(VFSBackend *vfs, VFSOpenFile *openFile, std::string *outMagic);
+
+enum class ReplacementState : uint32_t {
+ UNINITIALIZED,
+ POPULATED, // We located the texture files but have not started the thread.
+ PENDING,
+ NOT_FOUND, // Also used on error loading the images.
+ ACTIVE,
+ CANCEL_INIT,
+};
+
+const char *StateString(ReplacementState state);
+
+struct ReplacementDesc {
+ int newW;
+ int newH;
+ uint64_t cachekey;
+ uint32_t hash;
+ int w;
+ int h;
+ std::string hashfiles;
+ Path basePath;
+ bool foundAlias;
+ std::vector filenames;
+ std::string logId;
+ ReplacedLevelsCache *cache;
+};
+
+// These aren't actually all replaced, they can also represent a placeholder for a not-found
+// replacement (state_ == NOT_FOUND).
+struct ReplacedTexture {
+ ~ReplacedTexture();
+
+ inline ReplacementState State() const {
+ return state_;
+ }
+
+ void SetState(ReplacementState state) {
+ _dbg_assert_(state != state_);
+#ifdef _DEBUG
+ // WARN_LOG(G3D, "Texture %s changed state from %s to %s", logId_.c_str(), StateString(state_), StateString(state));
+#endif
+ state_ = state;
+ }
+
+ void GetSize(int level, int *w, int *h) const {
+ _dbg_assert_(State() == ReplacementState::ACTIVE);
+ _dbg_assert_(level < levels_.size());
+ *w = levels_[level].w;
+ *h = levels_[level].h;
+ }
+
+ int NumLevels() const {
+ _dbg_assert_(State() == ReplacementState::ACTIVE);
+ return (int)levels_.size();
+ }
+
+ Draw::DataFormat Format() const {
+ _dbg_assert_(State() == ReplacementState::ACTIVE);
+ return fmt;
+ }
+
+ u8 AlphaStatus() const {
+ return (u8)alphaStatus_;
+ }
+
+ bool IsReady(double budget);
+ bool CopyLevelTo(int level, void *out, int rowPitch);
+
+ void FinishPopulate(const ReplacementDesc &desc);
+ std::string logId_;
+
+private:
+ void Prepare(VFSBackend *vfs);
+ void PrepareData(int level);
+ void PurgeIfOlder(double t);
+
+ bool PopulateLevel(ReplacedTextureLevel & level, bool ignoreError);
+
+ std::vector levels_;
+ ReplacedLevelsCache *levelData_ = nullptr;
+
+ ReplacedTextureAlpha alphaStatus_ = ReplacedTextureAlpha::UNKNOWN;
+ double lastUsed_ = 0.0;
+ LimitedWaitable *threadWaitable_ = nullptr;
+ std::mutex mutex_;
+ Draw::DataFormat fmt = Draw::DataFormat::UNDEFINED; // NOTE: Right now, the only supported format is Draw::DataFormat::R8G8B8A8_UNORM.
+
+ ReplacementState state_ = ReplacementState::UNINITIALIZED;
+
+ VFSBackend *vfs_ = nullptr;
+
+ friend class TextureReplacer;
+ friend class ReplacedTextureTask;
+};
diff --git a/GPU/Common/ShaderCommon.h b/GPU/Common/ShaderCommon.h
index 73f748003e..380a9e240a 100644
--- a/GPU/Common/ShaderCommon.h
+++ b/GPU/Common/ShaderCommon.h
@@ -18,6 +18,8 @@
#pragma once
#include
+#include
+#include
namespace Draw {
class DrawContext;
@@ -126,8 +128,15 @@ public:
ShaderManagerCommon(Draw::DrawContext *draw) : draw_(draw) {}
virtual ~ShaderManagerCommon() {}
+ virtual void ClearShaders() = 0;
virtual void DirtyLastShader() = 0;
+ virtual void DeviceLost() = 0;
+ virtual void DeviceRestore(Draw::DrawContext *draw) = 0; // must set draw_ to draw
+
+ virtual std::vector DebugGetShaderIDs(DebugShaderType type) = 0;
+ virtual std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) = 0;
+
protected:
Draw::DrawContext *draw_ = nullptr;
};
diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp
index 011d09a49b..173574fadd 100644
--- a/GPU/Common/ShaderUniforms.cpp
+++ b/GPU/Common/ShaderUniforms.cpp
@@ -135,12 +135,12 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView
ConvertProjMatrixToVulkan(flippedMatrix);
}
- if (!useBufferedRendering && g_display_rotation != DisplayRotation::ROTATE_0) {
- flippedMatrix = flippedMatrix * g_display_rot_matrix;
+ if (!useBufferedRendering && g_display.rotation != DisplayRotation::ROTATE_0) {
+ flippedMatrix = flippedMatrix * g_display.rot_matrix;
}
CopyMatrix4x4(ub->proj, flippedMatrix.getReadPtr());
- ub->rotation = useBufferedRendering ? 0 : (float)g_display_rotation;
+ ub->rotation = useBufferedRendering ? 0 : (float)g_display.rotation;
}
if (dirtyUniforms & DIRTY_PROJTHROUGHMATRIX) {
@@ -150,8 +150,8 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView
} else {
proj_through.setOrthoVulkan(0.0f, gstate_c.curRTWidth, 0, gstate_c.curRTHeight, 0, 1);
}
- if (!useBufferedRendering && g_display_rotation != DisplayRotation::ROTATE_0) {
- proj_through = proj_through * g_display_rot_matrix;
+ if (!useBufferedRendering && g_display.rotation != DisplayRotation::ROTATE_0) {
+ proj_through = proj_through * g_display.rot_matrix;
}
// Negative RT offsets come from split framebuffers (Killzone)
@@ -252,6 +252,7 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView
// These are just the reverse of the formulas in GPUStateUtils.
float halfActualZRange = gstate_c.vpDepthScale != 0.0f ? vpZScale / gstate_c.vpDepthScale : 0.0f;
+ float inverseDepthScale = gstate_c.vpDepthScale != 0.0f ? 1.0f / gstate_c.vpDepthScale : 0.0f;
float minz = -((gstate_c.vpZOffset * halfActualZRange) - vpZCenter) - halfActualZRange;
float viewZScale = halfActualZRange * 2.0f;
float viewZCenter = minz;
@@ -259,7 +260,7 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView
ub->depthRange[0] = viewZScale;
ub->depthRange[1] = viewZCenter;
ub->depthRange[2] = gstate_c.vpZOffset * 0.5f + 0.5f;
- ub->depthRange[3] = 2.0f * (1.0f / gstate_c.vpDepthScale);
+ ub->depthRange[3] = 2.0f * inverseDepthScale;
}
if (dirtyUniforms & DIRTY_CULLRANGE) {
diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp
index 9bf141756c..00e81b19d1 100644
--- a/GPU/Common/StencilCommon.cpp
+++ b/GPU/Common/StencilCommon.cpp
@@ -304,7 +304,7 @@ bool FramebufferManagerCommon::PerformWriteStencilFromMemory(u32 addr, int size,
}
Draw::Viewport viewport = { 0.0f, 0.0f, (float)w, (float)h, 0.0f, 1.0f };
- draw_->SetViewports(1, &viewport);
+ draw_->SetViewport(viewport);
// TODO: Switch the format to a single channel format?
Draw::Texture *tex = MakePixelTexture(src, dstBuffer->fb_format, dstBuffer->fb_stride, dstBuffer->width, dstBuffer->height);
diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp
index e6c29e8264..5c056eb87f 100644
--- a/GPU/Common/TextureCacheCommon.cpp
+++ b/GPU/Common/TextureCacheCommon.cpp
@@ -107,7 +107,7 @@ inline int dimHeight(u16 dim) {
}
TextureCacheCommon::TextureCacheCommon(Draw::DrawContext *draw, Draw2D *draw2D)
- : draw_(draw), draw2D_(draw2D) {
+ : draw_(draw), draw2D_(draw2D), replacer_(draw) {
decimationCounter_ = TEXCACHE_DECIMATION_INTERVAL;
// It's only possible to have 1KB of palette entries, although we allow 2KB in a hack.
@@ -138,6 +138,30 @@ TextureCacheCommon::~TextureCacheCommon() {
FreeAlignedMemory(expandClut_);
}
+void TextureCacheCommon::StartFrame() {
+ ForgetLastTexture();
+ textureShaderCache_->Decimate();
+ timesInvalidatedAllThisFrame_ = 0;
+ replacementTimeThisFrame_ = 0.0;
+
+ if (g_Config.bShowDebugStats) {
+ gpuStats.numReplacerTrackedTex = replacer_.GetNumTrackedTextures();
+ gpuStats.numCachedReplacedTextures = replacer_.GetNumCachedReplacedTextures();
+ }
+
+ if (texelsScaledThisFrame_) {
+ VERBOSE_LOG(G3D, "Scaled %d texels", texelsScaledThisFrame_);
+ }
+ texelsScaledThisFrame_ = 0;
+
+ if (clearCacheNextFrame_) {
+ Clear(true);
+ clearCacheNextFrame_ = false;
+ } else {
+ Decimate(false);
+ }
+}
+
// Produces a signed 1.23.8 value.
static int TexLog2(float delta) {
union FloatBits {
@@ -509,17 +533,31 @@ TexCacheEntry *TextureCacheCommon::SetTexture() {
int w0 = gstate.getTextureWidth(0);
int h0 = gstate.getTextureHeight(0);
int d0 = 1;
- ReplacedTexture &replaced = FindReplacement(entry, w0, h0, d0);
- if (replaced.IsInvalid()) {
- entry->status &= ~TexCacheEntry::STATUS_TO_REPLACE;
- if (g_Config.bSaveNewTextures) {
- // Load once more to actually save.
+ ReplacedTexture *replaced = FindReplacement(entry, w0, h0, d0);
+ if (replaced) {
+ // This texture is pending a replacement load.
+ // So check the replacer if it's reached a conclusion.
+ switch (replaced->State()) {
+ case ReplacementState::NOT_FOUND:
+ // Didn't find a replacement, so stop looking.
+ WARN_LOG(G3D, "No replacement for texture %dx%d", w0, h0);
+ entry->status &= ~TexCacheEntry::STATUS_TO_REPLACE;
+ if (g_Config.bSaveNewTextures) {
+ // Load it once more to actually save it. Since we don't set STATUS_TO_REPLACE, we won't end up looping.
+ match = false;
+ reason = "replacing";
+ }
+ break;
+ case ReplacementState::ACTIVE:
+ // There is now replacement data available!
+ // Just reload the texture to process the replacement.
match = false;
reason = "replacing";
+ break;
+ default:
+ // We'll just wait for a result.
+ break;
}
- } else {
- match = false;
- reason = "replacing";
}
}
@@ -817,7 +855,7 @@ void TextureCacheCommon::HandleTextureChange(TexCacheEntry *const entry, const c
gpuStats.numTextureInvalidations++;
DEBUG_LOG(G3D, "Texture different or overwritten, reloading at %08x: %s", entry->addr, reason);
if (doDelete) {
- InvalidateLastTexture();
+ ForgetLastTexture();
ReleaseTexture(entry, true);
entry->status &= ~TexCacheEntry::STATUS_IS_SCALED;
}
@@ -1463,17 +1501,21 @@ u32 TextureCacheCommon::EstimateTexMemoryUsage(const TexCacheEntry *entry) {
return pixelSize << (dimW + dimH);
}
-ReplacedTexture &TextureCacheCommon::FindReplacement(TexCacheEntry *entry, int &w, int &h, int &d) {
+ReplacedTexture *TextureCacheCommon::FindReplacement(TexCacheEntry *entry, int &w, int &h, int &d) {
if (d != 1) {
// We don't yet support replacing 3D textures.
- return replacer_.FindNone();
+ return nullptr;
}
// Short circuit the non-enabled case.
// Otherwise, due to bReplaceTexturesAllowLate, we'll still spawn tasks looking for replacements
// that then won't be used.
if (!replacer_.Enabled()) {
- return replacer_.FindNone();
+ return nullptr;
+ }
+
+ if ((entry->status & TexCacheEntry::STATUS_VIDEO) && replacer_.AllowVideo()) {
+ return nullptr;
}
// Allow some delay to reduce pop-in.
@@ -1482,17 +1524,32 @@ ReplacedTexture &TextureCacheCommon::FindReplacement(TexCacheEntry *entry, int &
double replaceStart = time_now_d();
double budget = std::min(MAX_BUDGET_PER_TEX, replacementFrameBudget_ - replacementTimeThisFrame_);
u64 cachekey = replacer_.Enabled() ? entry->CacheKey() : 0;
- ReplacedTexture &replaced = replacer_.FindReplacement(cachekey, entry->fullhash, w, h, budget);
- if (replaced.IsReady(budget)) {
- if (replaced.GetSize(0, w, h)) {
- // Consider it already "scaled."
+ ReplacedTexture *replaced = replacer_.FindReplacement(cachekey, entry->fullhash, w, h, budget);
+ if (!replaced) {
+ // TODO: Remove the flag here?
+ // entry->status &= ~TexCacheEntry::STATUS_TO_REPLACE;
+ replacementTimeThisFrame_ += time_now_d() - replaceStart;
+ return nullptr;
+ }
+
+ if (replaced->IsReady(budget)) {
+ if (replaced->State() == ReplacementState::ACTIVE) {
+ replaced->GetSize(0, &w, &h);
+ // Consider it already "scaled.".
entry->status |= TexCacheEntry::STATUS_IS_SCALED;
}
// Remove the flag, even if it was invalid.
entry->status &= ~TexCacheEntry::STATUS_TO_REPLACE;
- } else if (!replaced.IsInvalid()) {
+ }
+
+ switch (replaced->State()) {
+ case ReplacementState::POPULATED:
+ case ReplacementState::PENDING:
+ case ReplacementState::UNINITIALIZED:
+ // Make sure we keep polling.
entry->status |= TexCacheEntry::STATUS_TO_REPLACE;
+ break;
}
replacementTimeThisFrame_ += time_now_d() - replaceStart;
return replaced;
@@ -1990,7 +2047,7 @@ void TextureCacheCommon::ApplyTexture() {
TexCacheEntry *entry = nextTexture_;
if (!entry) {
// Maybe we bound a framebuffer?
- InvalidateLastTexture();
+ ForgetLastTexture();
if (failedTexture_) {
// Backends should handle this by binding a black texture with 0 alpha.
BindTexture(nullptr);
@@ -2013,7 +2070,7 @@ void TextureCacheCommon::ApplyTexture() {
// Regardless of hash fails or otherwise, if this is a video, mark it frequently changing.
// This prevents temporary scaling perf hits on the first second of video.
if (IsVideo(entry->addr)) {
- entry->status |= TexCacheEntry::STATUS_CHANGE_FREQUENT;
+ entry->status |= TexCacheEntry::STATUS_CHANGE_FREQUENT | TexCacheEntry::STATUS_VIDEO;
}
if (nextNeedsRehash_) {
@@ -2050,7 +2107,7 @@ void TextureCacheCommon::ApplyTexture() {
if (nextNeedsRebuild_) {
_assert_(!entry->texturePtr);
BuildTexture(entry);
- InvalidateLastTexture();
+ ForgetLastTexture();
}
if (entry->status & TexCacheEntry::STATUS_CLUT_GPU) {
@@ -2205,7 +2262,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer
gstate_c.SetTextureFullAlpha(alphaStatus == CHECKALPHA_FULL);
draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE);
- InvalidateLastTexture();
+ ForgetLastTexture();
return;
}
@@ -2247,8 +2304,8 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer
draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Depal");
draw_->InvalidateFramebuffer(Draw::FB_INVALIDATION_STORE, Draw::FB_DEPTH_BIT | Draw::FB_STENCIL_BIT);
draw_->SetScissorRect(u1, v1, u2 - u1, v2 - v1);
- Draw::Viewport vp{ 0.0f, 0.0f, (float)depalWidth, (float)framebuffer->renderHeight, 0.0f, 1.0f };
- draw_->SetViewports(1, &vp);
+ Draw::Viewport viewport{ 0.0f, 0.0f, (float)depalWidth, (float)framebuffer->renderHeight, 0.0f, 1.0f };
+ draw_->SetViewport(viewport);
draw_->BindFramebufferAsTexture(framebuffer->fbo, 0, depth ? Draw::FB_DEPTH_BIT : Draw::FB_COLOR_BIT, Draw::ALL_LAYERS);
if (clutRenderAddress_ == 0xFFFFFFFF) {
@@ -2352,8 +2409,8 @@ void TextureCacheCommon::ApplyTextureDepal(TexCacheEntry *entry) {
draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Depal");
draw_->InvalidateFramebuffer(Draw::FB_INVALIDATION_STORE, Draw::FB_DEPTH_BIT | Draw::FB_STENCIL_BIT);
draw_->SetScissorRect(u1, v1, u2 - u1, v2 - v1);
- Draw::Viewport vp{ 0.0f, 0.0f, (float)texWidth, (float)texHeight, 0.0f, 1.0f };
- draw_->SetViewports(1, &vp);
+ Draw::Viewport viewport{ 0.0f, 0.0f, (float)texWidth, (float)texHeight, 0.0f, 1.0f };
+ draw_->SetViewport(viewport);
draw_->BindNativeTexture(0, GetNativeTextureView(entry));
draw_->BindFramebufferAsTexture(dynamicClutFbo_, 1, Draw::FB_COLOR_BIT, 0);
@@ -2759,10 +2816,10 @@ bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEnt
}
if (canReplace) {
- plan.replaced = &FindReplacement(entry, plan.w, plan.h, plan.depth);
- plan.replaceValid = plan.replaced->Valid();
+ plan.replaced = FindReplacement(entry, plan.w, plan.h, plan.depth);
+ plan.replaceValid = plan.replaced ? plan.replaced->State() == ReplacementState::ACTIVE : false;
} else {
- plan.replaced = &replacer_.FindNone();
+ plan.replaced = nullptr;
plan.replaceValid = false;
}
@@ -2776,7 +2833,7 @@ bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEnt
plan.levelsToCreate = std::min(plan.levelsToLoad, plan.levelsToCreate);
plan.badMipSizes = false;
// But, we still need to create the texture at a larger size.
- plan.replaced->GetSize(0, plan.createW, plan.createH);
+ plan.replaced->GetSize(0, &plan.createW, &plan.createH);
} else {
if (replacer_.Enabled() && !plan.replaceValid && plan.depth == 1 && canReplace) {
ReplacedTextureDecodeInfo replacedInfo;
@@ -2784,9 +2841,9 @@ bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEnt
replacedInfo.cachekey = entry->CacheKey();
replacedInfo.hash = entry->fullhash;
replacedInfo.addr = entry->addr;
- replacedInfo.isVideo = plan.isVideo;
replacedInfo.isFinal = (entry->status & TexCacheEntry::STATUS_TO_SCALE) == 0;
replacedInfo.scaleFactor = plan.scaleFactor;
+ replacedInfo.isVideo = plan.isVideo;
replacedInfo.fmt = Draw::DataFormat::R8G8B8A8_UNORM;
plan.saveTexture = replacer_.WillSave(replacedInfo);
}
@@ -2828,9 +2885,10 @@ void TextureCacheCommon::LoadTextureLevel(TexCacheEntry &entry, uint8_t *data, i
PROFILE_THIS_SCOPE("decodetex");
- if (plan.replaceValid && plan.replaced->GetSize(srcLevel, w, h)) {
+ if (plan.replaceValid) {
+ plan.replaced->GetSize(srcLevel, &w, &h);
double replaceStart = time_now_d();
- plan.replaced->Load(srcLevel, data, stride);
+ plan.replaced->CopyLevelTo(srcLevel, data, stride);
replacementTimeThisFrame_ += time_now_d() - replaceStart;
} else {
GETextureFormat tfmt = (GETextureFormat)entry.format;
@@ -2877,7 +2935,7 @@ void TextureCacheCommon::LoadTextureLevel(TexCacheEntry &entry, uint8_t *data, i
}
}
- if (replacer_.Enabled() && plan.replaced->IsInvalid()) {
+ if (plan.saveTexture && !lowMemoryMode_) {
ReplacedTextureDecodeInfo replacedInfo;
replacedInfo.cachekey = entry.CacheKey();
replacedInfo.hash = entry.fullhash;
@@ -2906,7 +2964,3 @@ CheckAlphaResult TextureCacheCommon::CheckCLUTAlpha(const uint8_t *pixelData, GE
return CheckAlpha32((const u32 *)pixelData, w, 0xFF000000);
}
}
-
-void TextureCacheCommon::StartFrame() {
- textureShaderCache_->Decimate();
-}
diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h
index 6d3fcd604f..ff44e35664 100644
--- a/GPU/Common/TextureCacheCommon.h
+++ b/GPU/Common/TextureCacheCommon.h
@@ -23,13 +23,13 @@
#include "Common/CommonTypes.h"
#include "Common/MemoryUtil.h"
-#include "Core/TextureReplacer.h"
#include "Core/System.h"
#include "GPU/GPU.h"
#include "GPU/Common/GPUDebugInterface.h"
#include "GPU/Common/TextureDecoder.h"
#include "GPU/Common/TextureScalerCommon.h"
#include "GPU/Common/TextureShaderCommon.h"
+#include "GPU/Common/TextureReplacer.h"
class Draw2D;
@@ -149,10 +149,12 @@ struct TexCacheEntry {
STATUS_3D = 0x4000,
STATUS_CLUT_GPU = 0x8000,
+
+ STATUS_VIDEO = 0x10000,
};
- // Status, but int so we can zero initialize.
- int status;
+ // TexStatus enum flag combination.
+ u32 status;
u32 addr;
u32 minihash;
@@ -290,7 +292,8 @@ struct BuildTexturePlan {
bool decodeToClut8;
void GetMipSize(int level, int *w, int *h) const {
- if (replaceValid && replaced->GetSize(level, *w, *h)) {
+ if (replaceValid) {
+ replaced->GetSize(level, w, h);
return;
}
if (depth == 1) {
@@ -329,7 +332,6 @@ public:
TextureShaderCache *GetTextureShaderCache() { return textureShaderCache_; }
virtual void ForgetLastTexture() = 0;
- virtual void InvalidateLastTexture() = 0;
virtual void Clear(bool delete_them);
virtual void NotifyConfigChanged();
virtual void ApplySamplingParams(const SamplerCacheKey &key) = 0;
@@ -351,6 +353,11 @@ public:
}
virtual bool GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level, bool *isFramebuffer) { return false; }
+ virtual void StartFrame();
+
+ virtual void DeviceLost() = 0;
+ virtual void DeviceRestore(Draw::DrawContext *draw) = 0;
+
protected:
virtual void *GetNativeTextureView(const TexCacheEntry *entry) = 0;
bool PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEntry *entry);
@@ -374,7 +381,7 @@ protected:
CheckAlphaResult DecodeTextureLevel(u8 *out, int outPitch, GETextureFormat format, GEPaletteFormat clutformat, uint32_t texaddr, int level, int bufw, TexDecodeFlags flags);
void UnswizzleFromMem(u32 *dest, u32 destPitch, const u8 *texptr, u32 bufw, u32 height, u32 bytesPerPixel);
CheckAlphaResult ReadIndexedTex(u8 *out, int outPitch, int level, const u8 *texptr, int bytesPerIndex, int bufw, bool reverseColors, bool expandTo32Bit);
- ReplacedTexture &FindReplacement(TexCacheEntry *entry, int &w, int &h, int &d);
+ ReplacedTexture *FindReplacement(TexCacheEntry *entry, int &w, int &h, int &d);
// Return value is mapData normally, but could be another buffer allocated with AllocateAlignedMemory.
void LoadTextureLevel(TexCacheEntry &entry, uint8_t *mapData, int mapRowPitch, BuildTexturePlan &plan, int srcLevel, Draw::DataFormat dstFmt, TexDecodeFlags texDecFlags);
@@ -404,8 +411,6 @@ protected:
virtual void BoundFramebufferTexture() {}
- virtual void StartFrame();
-
void DecimateVideos();
bool IsVideo(u32 texaddr) const;
diff --git a/Core/TextureReplacer.cpp b/GPU/Common/TextureReplacer.cpp
similarity index 51%
rename from Core/TextureReplacer.cpp
rename to GPU/Common/TextureReplacer.cpp
index ef6f20e27c..ebe7bb4f25 100644
--- a/Core/TextureReplacer.cpp
+++ b/GPU/Common/TextureReplacer.cpp
@@ -16,25 +16,24 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "ppsspp_config.h"
+
#include
-#include
#include
#include
#include
-#ifdef SHARED_LIBZIP
-#include
-#else
-#include "ext/libzip/zip.h"
-#endif
#include "ext/xxhash.h"
#include "Common/Data/Convert/ColorConv.h"
#include "Common/Data/Format/IniFile.h"
#include "Common/Data/Format/ZIMLoad.h"
+#include "Common/Data/Format/PNGLoad.h"
#include "Common/Data/Text/I18n.h"
#include "Common/Data/Text/Parsers.h"
+#include "Common/File/VFS/DirectoryReader.h"
+#include "Common/File/VFS/ZipFileReader.h"
#include "Common/File/FileUtil.h"
+#include "Common/File/VFS/VFS.h"
#include "Common/LogReporting.h"
#include "Common/StringUtils.h"
#include "Common/Thread/ParallelLoop.h"
@@ -44,34 +43,52 @@
#include "Core/Config.h"
#include "Core/Host.h"
#include "Core/System.h"
-#include "Core/TextureReplacer.h"
#include "Core/ThreadPools.h"
#include "Core/ELF/ParamSFO.h"
+#include "GPU/Common/TextureReplacer.h"
#include "GPU/Common/TextureDecoder.h"
static const std::string INI_FILENAME = "textures.ini";
static const std::string ZIP_FILENAME = "textures.zip";
static const std::string NEW_TEXTURE_DIR = "new/";
static const int VERSION = 1;
-static const int MAX_MIP_LEVELS = 12; // 12 should be plenty, 8 is the max mip levels supported by the PSP.
static const double MAX_CACHE_SIZE = 4.0;
-TextureReplacer::TextureReplacer() {
- none_.initDone_ = true;
- none_.prepareDone_ = true;
+static inline ReplacedImageType IdentifyMagic(const uint8_t magic[4]) {
+ if (strncmp((const char *)magic, "ZIMG", 4) == 0)
+ return ReplacedImageType::ZIM;
+ if (magic[0] == 0x89 && strncmp((const char *)&magic[1], "PNG", 3) == 0)
+ return ReplacedImageType::PNG;
+ return ReplacedImageType::INVALID;
}
-void ReplacerZipInfo::Close() {
- if (!z)
- return;
+ReplacedImageType Identify(VFSBackend *vfs, VFSOpenFile *openFile, std::string *outMagic) {
+ uint8_t magic[4];
+ if (vfs->Read(openFile, magic, 4) != 4) {
+ *outMagic = "FAIL";
+ return ReplacedImageType::INVALID;
+ }
+ // Turn the signature into a readable string that we can display in an error message.
+ *outMagic = std::string((const char *)magic, 4);
+ for (int i = 0; i < outMagic->size(); i++) {
+ if ((s8)(*outMagic)[i] < 32) {
+ (*outMagic)[i] = '_';
+ }
+ }
+ vfs->Rewind(openFile);
+ return IdentifyMagic(magic);
+}
- std::lock_guard guard(lock);
- zip_close(z);
- z = nullptr;
+TextureReplacer::TextureReplacer(Draw::DrawContext *draw) {
+ // TODO: Check draw for supported texture formats.
}
TextureReplacer::~TextureReplacer() {
- zip_.Close();
+ for (auto &iter : cache_) {
+ delete iter.second;
+ }
+
+ delete vfs_;
}
void TextureReplacer::Init() {
@@ -86,17 +103,18 @@ void TextureReplacer::NotifyConfigChanged() {
if (enabled_) {
basePath_ = GetSysDirectory(DIRECTORY_TEXTURES) / gameID_;
- Path newTextureDir = basePath_ / NEW_TEXTURE_DIR;
+ newTextureDir_ = basePath_ / NEW_TEXTURE_DIR;
// If we're saving, auto-create the directory.
- if (g_Config.bSaveNewTextures && !File::Exists(newTextureDir)) {
- File::CreateFullPath(newTextureDir);
- File::CreateEmptyFile(newTextureDir / ".nomedia");
+ if (g_Config.bSaveNewTextures && !File::Exists(newTextureDir_)) {
+ File::CreateFullPath(newTextureDir_);
+ File::CreateEmptyFile(newTextureDir_ / ".nomedia");
}
enabled_ = File::IsDirectory(basePath_);
} else if (wasEnabled) {
- zip_.Close();
+ delete vfs_;
+ vfs_ = nullptr;
Decimate(ReplacerDecimateMode::ALL);
}
@@ -105,46 +123,7 @@ void TextureReplacer::NotifyConfigChanged() {
}
}
-static struct zip *ZipOpenPath(Path fileName) {
- int error = 0;
- if (fileName.Type() == PathType::CONTENT_URI) {
- int fd = File::OpenFD(fileName, File::OPEN_READ);
- return zip_fdopen(fd, 0, &error);
- }
- return zip_open(fileName.c_str(), 0, &error);
-}
-
-static constexpr zip_uint64_t INVALID_ZIP_SIZE = 0xFFFFFFFFFFFFFFFFULL;
-static zip_uint64_t ZipFileSize(zip *z, zip_int64_t i) {
- zip_stat_t zstat;
- if (zip_stat_index(z, i, 0, &zstat) != 0)
- return INVALID_ZIP_SIZE;
- if ((zstat.valid & ZIP_STAT_SIZE) == 0)
- return INVALID_ZIP_SIZE;
- return zstat.size;
-}
-
-static bool LoadIniZip(IniFile &ini, zip *z, const std::string &filename) {
- zip_int64_t i = zip_name_locate(z, filename.c_str(), ZIP_FL_NOCASE);
- if (i < 0)
- return false;
-
- std::string inistr;
- zip_uint64_t sz = ZipFileSize(z, i);
- if (sz == INVALID_ZIP_SIZE)
- return false;
- inistr.resize(sz);
-
- zip_file_t *zf = zip_fopen_index(z, i, 0);
- inistr.resize(zip_fread(zf, &inistr[0], inistr.size()));
- zip_fclose(zf);
-
- std::stringstream sstream(inistr);
- return ini.Load(sstream);
-}
-
bool TextureReplacer::LoadIni() {
- // TODO: Use crc32c?
hash_ = ReplacedTextureHash::QUICK;
aliases_.clear();
hashranges_.clear();
@@ -158,32 +137,24 @@ bool TextureReplacer::LoadIni() {
// Prevents dumping the mipmaps.
ignoreMipmap_ = false;
- zip_.Close();
-
- IniFile ini;
- bool iniLoaded = false;
+ delete vfs_;
+ vfs_ = nullptr;
// First, check for textures.zip, which is used to reduce IO.
- zip *z = ZipOpenPath(basePath_ / ZIP_FILENAME);
- if (z) {
- iniLoaded = LoadIniZip(ini, z, INI_FILENAME);
- // Require the zip have textures.ini to use it.
- if (iniLoaded) {
- iniLoaded = true;
- std::lock_guard guard(zip_.lock);
- zip_.z = z;
- } else {
- zip_close(z);
- z = nullptr;
- }
+ VFSBackend *dir = ZipFileReader::Create(basePath_ / ZIP_FILENAME, "");
+ if (!dir) {
+ vfsIsZip_ = false;
+ dir = new DirectoryReader(basePath_);
+ } else {
+ vfsIsZip_ = true;
}
- if (!iniLoaded) {
- iniLoaded = ini.LoadFromVFS((basePath_ / INI_FILENAME).ToString());
- }
+ IniFile ini;
+ bool iniLoaded = ini.LoadFromVFS(g_VFS, (basePath_ / INI_FILENAME).ToString());
if (iniLoaded) {
if (!LoadIniValues(ini)) {
+ delete dir;
return false;
}
@@ -192,26 +163,37 @@ bool TextureReplacer::LoadIni() {
if (ini.GetOrCreateSection("games")->Get(gameID_.c_str(), &overrideFilename, "")) {
if (!overrideFilename.empty() && overrideFilename != INI_FILENAME) {
IniFile overrideIni;
- if (zip_.z) {
- std::lock_guard guard(zip_.lock);
- iniLoaded = LoadIniZip(overrideIni, zip_.z, overrideFilename);
- } else {
- iniLoaded = overrideIni.LoadFromVFS((basePath_ / overrideFilename).ToString());
- }
+ iniLoaded = overrideIni.LoadFromVFS(*dir, overrideFilename);
if (!iniLoaded) {
ERROR_LOG(G3D, "Failed to load extra texture ini: %s", overrideFilename.c_str());
+ // Since this error is most likely to occure for texture pack creators, let's just bail here
+ // so that the creator is more likely to look in the logs for what happened.
+ delete dir;
return false;
}
INFO_LOG(G3D, "Loading extra texture ini: %s", overrideFilename.c_str());
if (!LoadIniValues(overrideIni, true)) {
+ delete dir;
return false;
}
}
}
+ } else {
+ if (vfsIsZip_) {
+ // We don't accept zip files without inis.
+ ERROR_LOG(G3D, "Texture pack lacking ini file: %s", basePath_.c_str());
+ delete dir;
+ return false;
+ } else {
+ WARN_LOG(G3D, "Texture pack lacking ini file: %s", basePath_.c_str());
+ }
}
- // The ini doesn't have to exist for it to be valid.
+ vfs_ = dir;
+ INFO_LOG(G3D, "Texture pack activated from '%s'", basePath_.c_str());
+
+ // The ini doesn't have to exist for the texture directory or zip to be valid.
return true;
}
@@ -219,7 +201,6 @@ bool TextureReplacer::LoadIniValues(IniFile &ini, bool isOverride) {
auto options = ini.GetOrCreateSection("options");
std::string hash;
options->Get("hash", &hash, "");
- // TODO: crc32c.
if (strcasecmp(hash.c_str(), "quick") == 0) {
hash_ = ReplacedTextureHash::QUICK;
} else if (strcasecmp(hash.c_str(), "xxh32") == 0) {
@@ -253,18 +234,24 @@ bool TextureReplacer::LoadIniValues(IniFile &ini, bool isOverride) {
bool filenameWarning = false;
if (ini.HasSection("hashes")) {
+ aliases_.clear();
+
auto hashes = ini.GetOrCreateSection("hashes")->ToMap();
// Format: hashname = filename.png
- bool checkFilenames = g_Config.bSaveNewTextures && !g_Config.bIgnoreTextureFilenames;
+ bool checkFilenames = g_Config.bSaveNewTextures && !g_Config.bIgnoreTextureFilenames && !vfsIsZip_;
+
+ std::map> filenameMap;
+
for (const auto &item : hashes) {
- ReplacementAliasKey key(0, 0, 0);
- if (sscanf(item.first.c_str(), "%16llx%8x_%d", &key.cachekey, &key.hash, &key.level) >= 1) {
- aliases_[key] = item.second;
+ ReplacementCacheKey key(0, 0);
+ int level = 0; // sscanf might fail to pluck the level, but that's ok, we default to 0.
+ if (sscanf(item.first.c_str(), "%16llx%8x_%d", &key.cachekey, &key.hash, &level) >= 1) {
+ filenameMap[key][level] = item.second;
if (checkFilenames) {
#if PPSSPP_PLATFORM(WINDOWS)
// Uppercase probably means the filenames don't match.
// Avoiding an actual check of the filenames to avoid performance impact.
- filenameWarning = filenameWarning || item.second.find_first_of("\\ABCDEFGHIJKLMNOPQRSTUVWXYZ") != std::string::npos;
+ filenameWarning = filenameWarning || item.second.find_first_of("\\ABCDEFGHIJKLMNOPQRSTUVWXYZ:<>|?*") != std::string::npos;
#else
filenameWarning = filenameWarning || item.second.find_first_of("\\:<>|?*") != std::string::npos;
#endif
@@ -273,11 +260,30 @@ bool TextureReplacer::LoadIniValues(IniFile &ini, bool isOverride) {
ERROR_LOG(G3D, "Unsupported syntax under [hashes]: %s", item.first.c_str());
}
}
+
+ // Now, translate the filenameMap to the final aliasMap.
+ for (auto &pair : filenameMap) {
+ std::string alias;
+ int mipIndex = 0;
+ for (auto &level : pair.second) {
+ if (level.first == mipIndex) {
+ alias += level.second + "|";
+ mipIndex++;
+ } else {
+ WARN_LOG(G3D, "Non-sequential mip index %d, breaking. filenames=%s", level.first, level.second.c_str());
+ break;
+ }
+ }
+ if (alias == "|") {
+ alias = ""; // marker for no replacement
+ }
+ aliases_[pair.first] = alias;
+ }
}
if (filenameWarning) {
auto err = GetI18NCategory("Error");
- host->NotifyUserMessage(err->T("textures.ini filenames may not be cross-platform"), 6.0f);
+ host->NotifyUserMessage(err->T("textures.ini filenames may not be cross-platform (banned characters)"), 6.0f);
}
if (ini.HasSection("hashranges")) {
@@ -298,7 +304,7 @@ bool TextureReplacer::LoadIniValues(IniFile &ini, bool isOverride) {
if (ini.HasSection("reducehashranges")) {
auto reducehashranges = ini.GetOrCreateSection("reducehashranges")->ToMap();
- // Format: w,h = reducehashvalues
+ // Format: w,h = reducehashvalues
for (const auto& item : reducehashranges) {
ParseReduceHashRange(item.first, item.second);
}
@@ -390,7 +396,7 @@ void TextureReplacer::ParseReduceHashRange(const std::string& key, const std::st
const u64 reducerangeKey = ((u64)forW << 16) | forH;
reducehashranges_[reducerangeKey] = rhashvalue;
-}
+}
u32 TextureReplacer::ComputeHash(u32 addr, int bufw, int w, int h, GETextureFormat fmt, u16 maxSeenV) {
_dbg_assert_msg_(enabled_, "Replacement not enabled");
@@ -461,216 +467,81 @@ u32 TextureReplacer::ComputeHash(u32 addr, int bufw, int w, int h, GETextureForm
}
}
-ReplacedTexture &TextureReplacer::FindReplacement(u64 cachekey, u32 hash, int w, int h, double budget) {
+ReplacedTexture *TextureReplacer::FindReplacement(u64 cachekey, u32 hash, int w, int h, double budget) {
// Only actually replace if we're replacing. We might just be saving.
if (!Enabled() || !g_Config.bReplaceTextures) {
- return none_;
+ return nullptr;
}
ReplacementCacheKey replacementKey(cachekey, hash);
auto it = cache_.find(replacementKey);
if (it != cache_.end()) {
- if (!it->second.prepareDone_ && budget > 0.0) {
+ if (it->second->State() == ReplacementState::UNINITIALIZED && budget > 0.0) {
// We don't do this on a thread, but we only do it while within budget.
- PopulateReplacement(&it->second, cachekey, hash, w, h);
+ PopulateReplacement(it->second, cachekey, hash, w, h);
}
return it->second;
}
// Okay, let's construct the result.
- ReplacedTexture &result = cache_[replacementKey];
- if (!g_Config.bReplaceTexturesAllowLate || budget > 0.0) {
- PopulateReplacement(&result, cachekey, hash, w, h);
+
+ ReplacedTexture *result = new ReplacedTexture();
+ result->vfs_ = this->vfs_;
+ if (budget > 0.0) {
+ _dbg_assert_(result->State() == ReplacementState::UNINITIALIZED);
+ PopulateReplacement(result, cachekey, hash, w, h);
+ } else {
+ // WARN_LOG(G3D, "Postponing preparing texture (%dx%d)", w, h);
}
+ cache_[replacementKey] = result;
return result;
}
-void TextureReplacer::PopulateReplacement(ReplacedTexture *result, u64 cachekey, u32 hash, int w, int h) {
- int newW = w;
- int newH = h;
- LookupHashRange(cachekey >> 32, newW, newH);
+void TextureReplacer::PopulateReplacement(ReplacedTexture *texture, u64 cachekey, u32 hash, int w, int h) {
+ ReplacementDesc desc;
+ desc.newW = w;
+ desc.newH = h;
+ desc.w = w;
+ desc.h = h;
+ desc.cachekey = cachekey;
+ desc.hash = hash;
+ desc.basePath = basePath_;
+ LookupHashRange(cachekey >> 32, desc.newW, desc.newH);
if (ignoreAddress_) {
cachekey = cachekey & 0xFFFFFFFFULL;
}
- for (int i = 0; i < MAX_MIP_LEVELS; ++i) {
- const std::string hashfile = LookupHashFile(cachekey, hash, i);
- const Path filename = basePath_ / hashfile;
- if (hashfile.empty()) {
- // Out of valid mip levels. Bail out.
- break;
- }
+ desc.foundAlias = false;
+ bool ignored = false;
+ desc.hashfiles = LookupHashFile(cachekey, hash, &desc.foundAlias, &ignored);
- ReplacedTextureLevel level;
- level.fmt = Draw::DataFormat::R8G8B8A8_UNORM;
- level.file = filename;
-
- bool good;
- bool logError = hashfile != HashName(cachekey, hash, i) + ".png";
- if (zip_.z) {
- level.zinfo = &zip_;
-
- std::lock_guard guard(zip_.lock);
- level.zi = zip_name_locate(zip_.z, hashfile.c_str(), ZIP_FL_NOCASE);
- good = PopulateLevelFromZip(level, !logError);
- } else {
- good = PopulateLevelFromPath(level, !logError);
- }
-
- // We pad files that have been hashrange'd so they are the same texture size.
- level.w = (level.w * w) / newW;
- level.h = (level.h * h) / newH;
-
- if (good && i != 0) {
- // Check that the mipmap size is correct. Can't load mips of the wrong size.
- if (level.w != (result->levels_[0].w >> i) || level.h != (result->levels_[0].h >> i)) {
- WARN_LOG(G3D, "Replacement mipmap invalid: size=%dx%d, expected=%dx%d (level %d, '%s')", level.w, level.h, result->levels_[0].w >> i, result->levels_[0].h >> i, i, filename.c_str());
- good = false;
- }
- }
-
- if (good)
- result->levels_.push_back(level);
- // Otherwise, we're done loading mips (bad PNG or bad size, either way.)
- else
- break;
+ // Early-out for ignored textures, let's not bother even starting a thread task.
+ if (ignored) {
+ // WARN_LOG(G3D, "Not found/ignored: %s (%d, %d)", hashfiles.c_str(), (int)foundReplacement, (int)ignored);
+ // nothing to do?
+ texture->SetState(ReplacementState::NOT_FOUND);
+ return;
}
- // Populate the level data pointers for each level.
- result->levelData_.resize(result->levels_.size());
- for (size_t i = 0; i < result->levels_.size(); ++i) {
- result->levelData_[i] = &levelCache_[result->levels_[i]];
- }
-
- result->prepareDone_ = true;
-}
-
-enum class ReplacedImageType {
- PNG,
- ZIM,
- INVALID,
-};
-
-static ReplacedImageType Identify(const uint8_t magic[4]) {
- if (strncmp((const char *)magic, "ZIMG", 4) == 0)
- return ReplacedImageType::ZIM;
- if (magic[0] == 0x89 && strncmp((const char *)&magic[1], "PNG", 3) == 0)
- return ReplacedImageType::PNG;
- return ReplacedImageType::INVALID;
-}
-
-static ReplacedImageType Identify(FILE *fp) {
- uint8_t magic[4];
- if (fread(magic, 1, 4, fp) != 4)
- return ReplacedImageType::INVALID;
- rewind(fp);
-
- return Identify(magic);
-}
-
-static ReplacedImageType Identify(zip_file_t *zf) {
- uint8_t magic[4];
- if (zip_fread(zf, magic, 4) != 4)
- return ReplacedImageType::INVALID;
-
- return Identify(magic);
-}
-
-bool TextureReplacer::PopulateLevelFromPath(ReplacedTextureLevel &level, bool ignoreError) {
- bool good = false;
-
- FILE *fp = File::OpenCFile(level.file, "rb");
- if (!fp) {
- if (!ignoreError)
- ERROR_LOG(G3D, "Error opening replacement texture file '%s'", level.file.c_str());
- return false;
- }
-
- auto imageType = Identify(fp);
- if (imageType == ReplacedImageType::ZIM) {
- fseek(fp, 4, SEEK_SET);
- good = fread(&level.w, 4, 1, fp) == 1;
- good = good && fread(&level.h, 4, 1, fp) == 1;
- int flags;
- if (good && fread(&flags, 4, 1, fp) == 1) {
- good = (flags & ZIM_FORMAT_MASK) == ZIM_RGBA8888;
+ if (!desc.foundAlias) {
+ // We'll just need to generate the names for each level.
+ // By default, we look for png since that's also what's dumped.
+ // For other file formats, use the ini to create aliases.
+ desc.filenames.resize(MAX_REPLACEMENT_MIP_LEVELS);
+ for (int level = 0; level < desc.filenames.size(); level++) {
+ desc.filenames[level] = TextureReplacer::HashName(desc.cachekey, desc.hash, level) + ".png";
}
- } else if (imageType == ReplacedImageType::PNG) {
- png_image png = {};
- png.version = PNG_IMAGE_VERSION;
- if (png_image_begin_read_from_stdio(&png, fp)) {
- // We pad files that have been hashrange'd so they are the same texture size.
- level.w = png.width;
- level.h = png.height;
- good = true;
- } else {
- ERROR_LOG(G3D, "Could not load texture replacement info: %s - %s", level.file.ToVisualString().c_str(), png.message);
- }
- png_image_free(&png);
+ desc.logId = desc.filenames[0];
+ desc.hashfiles = desc.filenames[0]; // This is used as the key in the data cache.
} else {
- ERROR_LOG(G3D, "Could not load texture replacement info: %s - unsupported format", level.file.ToVisualString().c_str());
- }
- fclose(fp);
-
- return good;
-}
-
-bool TextureReplacer::PopulateLevelFromZip(ReplacedTextureLevel &level, bool ignoreError) {
- bool good = false;
-
- // Everything in here is within a lock, so we don't need to relock.
- if (!level.zinfo || !level.zinfo->z || level.zi < 0) {
- if (!ignoreError)
- ERROR_LOG(G3D, "Error opening replacement texture file '%s' in textures.zip", level.file.c_str());
- return false;
+ desc.logId = desc.hashfiles;
+ SplitString(desc.hashfiles, '|', desc.filenames);
}
- zip_file_t *zf = zip_fopen_index(level.zinfo->z, level.zi, 0);
- if (!zf)
- return false;
+ desc.cache = &levelCache_[desc.hashfiles];
- auto imageType = Identify(zf);
- zip_fclose(zf);
-
- zf = zip_fopen_index(level.zinfo->z, level.zi, 0);
- if (imageType == ReplacedImageType::ZIM) {
- uint32_t ignore = 0;
- good = zip_fread(zf, &ignore, 4) == 4;
- good = good && zip_fread(zf, &level.w, 4) == 4;
- good = good && zip_fread(zf, &level.h, 4) == 4;
- int flags;
- if (good && zip_fread(zf, &flags, 4) == 4) {
- good = (flags & ZIM_FORMAT_MASK) == ZIM_RGBA8888;
- }
- } else if (imageType == ReplacedImageType::PNG) {
- png_image png = {};
- png.version = PNG_IMAGE_VERSION;
-
- // TODO: Use some way to stream data into libpng. Better than the IO lookups on Android...
- zip_uint64_t zsize = ZipFileSize(level.zinfo->z, level.zi);
- std::string pngdata;
- if (zsize != INVALID_ZIP_SIZE)
- pngdata.resize(zsize);
- if (!pngdata.empty()) {
- pngdata.resize(zip_fread(zf, &pngdata[0], pngdata.size()));
- }
-
- if (png_image_begin_read_from_memory(&png, &pngdata[0], pngdata.size())) {
- // We pad files that have been hashrange'd so they are the same texture size.
- level.w = png.width;
- level.h = png.height;
- good = true;
- } else {
- ERROR_LOG(G3D, "Could not load texture replacement info: %s - %s (zip)", level.file.ToVisualString().c_str(), png.message);
- }
- png_image_free(&png);
- } else {
- ERROR_LOG(G3D, "Could not load texture replacement info: %s - unsupported format (zip)", level.file.ToVisualString().c_str());
- }
- zip_fclose(zf);
-
- return good;
+ texture->FinishPopulate(desc);
}
static bool WriteTextureToPNG(png_imagep image, const Path &filename, int convert_to_8bit, const void *buffer, png_int_32 row_stride, const void *colormap) {
@@ -691,24 +562,28 @@ static bool WriteTextureToPNG(png_imagep image, const Path &filename, int conver
}
}
-class TextureSaveTask : public Task {
+// We save textures on threadpool tasks since it's a fire-and-forget task, and both I/O and png compression
+// can be pretty slow.
+class SaveTextureTask : public Task {
public:
- // Could probably just use a vector.
- SimpleBuf data;
+ std::vector rgbaData;
int w = 0;
int h = 0;
int pitch = 0; // bytes
- Path basePath;
- std::string hashfile;
- u32 replacedInfoHash;
+ Path filename;
+ Path saveFilename;
+ bool createSaveDirectory = false;
+ Path saveDirectory;
+
+ u32 replacedInfoHash = 0;
bool skipIfExists = false;
- TextureSaveTask(SimpleBuf _data) : data(std::move(_data)) {}
+ SaveTextureTask(std::vector &&_rgbaData) : rgbaData(std::move(_rgbaData)) {}
- // This must be IO blocking because of Android storage, despite being CPU heavy.
+ // This must be set to I/O blocking because of Android storage (so we attach the thread to JNI), while being CPU heavy too.
TaskType Type() const override { return TaskType::IO_BLOCKING; }
TaskPriority Priority() const override {
@@ -716,31 +591,18 @@ public:
}
void Run() override {
- const Path filename = basePath / hashfile;
- const Path saveFilename = basePath / NEW_TEXTURE_DIR / hashfile;
-
// Should we skip writing if the newly saved data already exists?
- // We do this on the thread due to slow IO.
- if (skipIfExists && File::Exists(saveFilename))
+ if (skipIfExists && File::Exists(saveFilename)) {
return;
+ }
// And we always skip if the replace file already exists.
if (File::Exists(filename))
return;
- // Create subfolder as needed.
-#ifdef _WIN32
- size_t slash = hashfile.find_last_of("/\\");
-#else
- size_t slash = hashfile.find_last_of("/");
-#endif
- if (slash != hashfile.npos) {
- // Create any directory structure as needed.
- const Path saveDirectory = basePath / NEW_TEXTURE_DIR / hashfile.substr(0, slash);
- if (!File::Exists(saveDirectory)) {
- File::CreateFullPath(saveDirectory);
- File::CreateEmptyFile(saveDirectory / ".nomedia");
- }
+ if (createSaveDirectory && !File::Exists(saveDirectory)) {
+ File::CreateFullPath(saveDirectory);
+ File::CreateEmptyFile(saveDirectory / ".nomedia");
}
png_image png{};
@@ -748,12 +610,14 @@ public:
png.format = PNG_FORMAT_RGBA;
png.width = w;
png.height = h;
- bool success = WriteTextureToPNG(&png, saveFilename, 0, data.data(), pitch, nullptr);
+ bool success = WriteTextureToPNG(&png, saveFilename, 0, rgbaData.data(), pitch, nullptr);
png_image_free(&png);
if (png.warning_or_error >= 2) {
- ERROR_LOG(COMMON, "Saving screenshot to PNG produced errors.");
+ ERROR_LOG(G3D, "Saving screenshot to PNG produced errors.");
} else if (success) {
NOTICE_LOG(G3D, "Saving texture for replacement: %08x / %dx%d in '%s'", replacedInfoHash, w, h, saveFilename.ToVisualString().c_str());
+ } else {
+ ERROR_LOG(G3D, "Failed to write '%s'", saveFilename.c_str());
}
}
};
@@ -786,27 +650,30 @@ void TextureReplacer::NotifyTextureDecoded(const ReplacedTextureDecodeInfo &repl
cachekey = cachekey & 0xFFFFFFFFULL;
}
- std::string hashfile = LookupHashFile(cachekey, replacedInfo.hash, level);
- const Path filename = basePath_ / hashfile;
+ bool foundAlias = false, ignored = false;
+ std::string hashfile = LookupHashFile(cachekey, replacedInfo.hash, &foundAlias, &ignored);
// If it's empty, it's an ignored hash, we intentionally don't save.
- if (hashfile.empty()) {
+ if (foundAlias || ignored) {
// If it exists, must've been decoded and saved as a new texture already.
return;
}
+ // Generate a new PNG filename, complete with level.
+ hashfile = HashName(cachekey, replacedInfo.hash, level) + ".png";
+
ReplacementCacheKey replacementKey(cachekey, replacedInfo.hash);
auto it = savedCache_.find(replacementKey);
bool skipIfExists = false;
double now = time_now_d();
if (it != savedCache_.end()) {
// We've already saved this texture. Let's only save if it's bigger (e.g. scaled now.)
- if (it->second.first.w >= w && it->second.first.h >= h) {
+ // This check isn't backwards, it's just to check if we should *skip* saving, a bit confusing.
+ if (it->second.levelW[level] >= w && it->second.levelH[level] >= h) {
// If it's been more than 5 seconds, we'll check again. Maybe they deleted.
- double age = now - it->second.second;
+ double age = now - it->second.lastTimeSaved;
if (age < 5.0)
return;
-
skipIfExists = true;
}
}
@@ -819,35 +686,49 @@ void TextureReplacer::NotifyTextureDecoded(const ReplacedTextureDecodeInfo &repl
h = lookupH * replacedInfo.scaleFactor;
}
- SimpleBuf saveBuf;
+ std::vector saveBuf;
// Copy data to a buffer so we can send it to the thread. Might as well compact-away the pitch
// while we're at it.
- saveBuf.resize(w * h);
+ saveBuf.resize(w * h * 4);
for (int y = 0; y < h; y++) {
memcpy((u8 *)saveBuf.data() + y * w * 4, (const u8 *)data + y * pitch, w * sizeof(u32));
}
pitch = w * 4;
- TextureSaveTask *task = new TextureSaveTask(std::move(saveBuf));
- // Should probably do a proper move constructor but this'll work.
+ SaveTextureTask *task = new SaveTextureTask(std::move(saveBuf));
+
+ task->filename = basePath_ / hashfile;
+ task->saveFilename = newTextureDir_ / hashfile;
+ task->createSaveDirectory = false;
+
+ // Create subfolder as needed.
+#ifdef _WIN32
+ size_t slash = hashfile.find_last_of("/\\");
+#else
+ size_t slash = hashfile.find_last_of("/");
+#endif
+ if (slash != hashfile.npos) {
+ // Does this ever happen?
+ // Create any directory structure as needed.
+ task->saveDirectory = newTextureDir_ / hashfile.substr(0, slash);
+ task->createSaveDirectory = true;
+ }
+
task->w = w;
task->h = h;
task->pitch = pitch;
- task->basePath = basePath_;
- task->hashfile = hashfile;
task->replacedInfoHash = replacedInfo.hash;
task->skipIfExists = skipIfExists;
g_threadManager.EnqueueTask(task); // We don't care about waiting for the task. It'll be fine.
// Remember that we've saved this for next time.
// Should be OK that the actual disk write may not be finished yet.
- ReplacedTextureLevel saved;
- saved.fmt = Draw::DataFormat::R8G8B8A8_UNORM;
- saved.file = filename;
- saved.w = w;
- saved.h = h;
- savedCache_[replacementKey] = std::make_pair(saved, now);
+ SavedTextureCacheData &saveData = savedCache_[replacementKey];
+ saveData.levelW[level] = w;
+ saveData.levelH[level] = h;
+ saveData.levelSaved[level] = true;
+ saveData.lastTimeSaved = now;
}
void TextureReplacer::Decimate(ReplacerDecimateMode mode) {
@@ -865,7 +746,8 @@ void TextureReplacer::Decimate(ReplacerDecimateMode mode) {
const double threshold = time_now_d() - age;
for (auto &item : cache_) {
- item.second.PurgeIfOlder(threshold);
+ item.second->PurgeIfOlder(threshold);
+ // don't actually delete the items here, just clean out the data.
}
size_t totalSize = 0;
@@ -946,15 +828,18 @@ bool TextureReplacer::FindFiltering(u64 cachekey, u32 hash, TextureFiltering *fo
return false;
}
-std::string TextureReplacer::LookupHashFile(u64 cachekey, u32 hash, int level) {
- ReplacementAliasKey key(cachekey, hash, level);
+std::string TextureReplacer::LookupHashFile(u64 cachekey, u32 hash, bool *foundAlias, bool *ignored) {
+ ReplacementCacheKey key(cachekey, hash);
auto alias = LookupWildcard(aliases_, key, cachekey, hash, ignoreAddress_);
if (alias != aliases_.end()) {
// Note: this will be blank if explicitly ignored.
+ *foundAlias = true;
+ *ignored = alias->second.empty();
return alias->second;
}
-
- return HashName(cachekey, hash, level) + ".png";
+ *foundAlias = false;
+ *ignored = false;
+ return "";
}
std::string TextureReplacer::HashName(u64 cachekey, u32 hash, int level) {
@@ -993,322 +878,6 @@ float TextureReplacer::LookupReduceHashRange(int& w, int& h) {
}
}
-class ReplacedTextureTask : public Task {
-public:
- ReplacedTextureTask(ReplacedTexture &tex, LimitedWaitable *w) : tex_(tex), waitable_(w) {}
-
- TaskType Type() const override {
- return TaskType::IO_BLOCKING;
- }
-
- TaskPriority Priority() const override {
- return TaskPriority::NORMAL;
- }
-
- void Run() override {
- tex_.Prepare();
- waitable_->Notify();
- }
-
-private:
- ReplacedTexture &tex_;
- LimitedWaitable *waitable_;
-};
-
-bool ReplacedTexture::IsReady(double budget) {
- lastUsed_ = time_now_d();
- if (threadWaitable_ && !threadWaitable_->WaitFor(budget)) {
- return false;
- }
-
- // Loaded already, or not yet on a thread?
- if (initDone_ && !levelData_.empty()) {
- for (auto &l : levelData_)
- l->lastUsed = lastUsed_;
- return true;
- }
- // Let's not even start a new texture if we're already behind.
- if (budget < 0.0)
- return false;
- if (!prepareDone_)
- return false;
-
- if (g_Config.bReplaceTexturesAllowLate) {
- if (threadWaitable_)
- delete threadWaitable_;
- threadWaitable_ = new LimitedWaitable();
- g_threadManager.EnqueueTask(new ReplacedTextureTask(*this, threadWaitable_));
-
- if (threadWaitable_->WaitFor(budget)) {
- // If we finished all the levels, we're done.
- return initDone_ && !levelData_.empty();
- }
- } else {
- Prepare();
- _assert_(initDone_);
- return true;
- }
-
- // Still pending on thread.
- return false;
-}
-
-void ReplacedTexture::Prepare() {
- std::unique_lock lock(mutex_);
- if (cancelPrepare_) {
- initDone_ = true;
- return;
- }
-
- for (int i = 0; i < (int)levels_.size(); ++i) {
- if (cancelPrepare_)
- break;
- PrepareData(i);
- }
-
- initDone_ = true;
- if (!cancelPrepare_ && threadWaitable_)
- threadWaitable_->Notify();
-}
-
-void ReplacedTexture::PrepareData(int level) {
- _assert_msg_((size_t)level < levels_.size(), "Invalid miplevel");
- _assert_msg_(levelData_[level] != nullptr, "Level cache not set for miplevel");
-
- // We must lock around access to levelData_ in case two textures try to load it at once.
- std::lock_guard guard(levelData_[level]->lock);
-
- const ReplacedTextureLevel &info = levels_[level];
- std::vector &out = levelData_[level]->data;
-
- // Already populated from cache.
- if (!out.empty())
- return;
-
- FILE *fp = nullptr;
- zip_file_t *zf = nullptr;
- ReplacedImageType imageType;
- std::unique_lock zguard;
- if (info.zinfo && info.zinfo->z) {
- zguard = std::unique_lock(info.zinfo->lock);
- zf = zip_fopen_index(info.zinfo->z, info.zi, 0);
- if (!zf)
- return;
-
- imageType = Identify(zf);
- // Can't assume we can seek. Reopen.
- zip_fclose(zf);
- zf = zip_fopen_index(info.zinfo->z, info.zi, 0);
- } else {
- fp = File::OpenCFile(info.file, "rb");
- if (!fp) {
- // Leaving the data sized at zero means failure.
- return;
- }
-
- imageType = Identify(fp);
- }
-
- auto cleanup = [&] {
- if (zf)
- zip_fclose(zf);
- if (fp)
- fclose(fp);
- };
-
- if (imageType == ReplacedImageType::ZIM) {
- size_t zimSize = 0;
- if (fp) {
- zimSize = File::GetFileSize(fp);
- } else if (zf) {
- zip_uint64_t zsize = ZipFileSize(info.zinfo->z, info.zi);
- zimSize = zsize == INVALID_ZIP_SIZE ? 0 : (size_t)zsize;
- } else {
- _assert_(false);
- }
- std::unique_ptr zim(new uint8_t[zimSize]);
- if (!zim) {
- ERROR_LOG(G3D, "Failed to allocate memory for texture replacement");
- cleanup();
- return;
- }
-
- if (fp) {
- if (fread(&zim[0], 1, zimSize, fp) != zimSize) {
- ERROR_LOG(G3D, "Could not load texture replacement: %s - failed to read ZIM", info.file.c_str());
- cleanup();
- return;
- }
- } else if (zf) {
- if (zip_fread(zf, &zim[0], zimSize) != zimSize) {
- ERROR_LOG(G3D, "Could not load texture replacement: %s - failed to read ZIM (zip)", info.file.c_str());
- cleanup();
- return;
- }
- // Try to unlock early to prevent blocking threads.
- zguard.unlock();
- } else {
- _assert_(false);
- }
-
- int w, h, f;
- uint8_t *image;
-
- if (LoadZIMPtr(&zim[0], zimSize, &w, &h, &f, &image)) {
- if (w > info.w || h > info.h) {
- ERROR_LOG(G3D, "Texture replacement changed since header read: %s", info.file.c_str());
- cleanup();
- return;
- }
-
- out.resize(info.w * info.h * 4);
- if (w == info.w) {
- memcpy(&out[0], image, info.w * 4 * info.h);
- } else {
- for (int y = 0; y < h; ++y) {
- memcpy(&out[info.w * 4 * y], image + w * 4 * y, w * 4);
- }
- }
- free(image);
- }
-
- CheckAlphaResult res = CheckAlpha32Rect((u32 *)&out[0], info.w, w, h, 0xFF000000);
- if (res == CHECKALPHA_ANY || level == 0) {
- alphaStatus_ = ReplacedTextureAlpha(res);
- }
- } else if (imageType == ReplacedImageType::PNG) {
- png_image png = {};
- png.version = PNG_IMAGE_VERSION;
-
- // Needs to survive for a little while, used for zip only.
- std::string pngdata;
- if (fp) {
- if (!png_image_begin_read_from_stdio(&png, fp)) {
- ERROR_LOG(G3D, "Could not load texture replacement info: %s - %s", info.file.c_str(), png.message);
- cleanup();
- return;
- }
- } else if (zf) {
- zip_uint64_t zsize = ZipFileSize(info.zinfo->z, info.zi);
- if (zsize != INVALID_ZIP_SIZE)
- pngdata.resize(zsize);
- if (!pngdata.empty()) {
- pngdata.resize(zip_fread(zf, &pngdata[0], pngdata.size()));
- }
- // Try to unlock early to prevent blocking threads.
- zguard.unlock();
-
- if (!png_image_begin_read_from_memory(&png, &pngdata[0], pngdata.size())) {
- ERROR_LOG(G3D, "Could not load texture replacement info: %s - %s (zip)", info.file.c_str(), png.message);
- cleanup();
- return;
- }
- } else {
- _assert_(false);
- }
- if (png.width > (uint32_t)info.w || png.height > (uint32_t)info.h) {
- ERROR_LOG(G3D, "Texture replacement changed since header read: %s", info.file.c_str());
- cleanup();
- return;
- }
-
- bool checkedAlpha = false;
- if ((png.format & PNG_FORMAT_FLAG_ALPHA) == 0) {
- // Well, we know for sure it doesn't have alpha.
- if (level == 0) {
- alphaStatus_ = ReplacedTextureAlpha::FULL;
- }
- checkedAlpha = true;
- }
- png.format = PNG_FORMAT_RGBA;
-
- out.resize(info.w * info.h * 4);
- if (!png_image_finish_read(&png, nullptr, &out[0], info.w * 4, nullptr)) {
- ERROR_LOG(G3D, "Could not load texture replacement: %s - %s", info.file.c_str(), png.message);
- cleanup();
- out.resize(0);
- return;
- }
- png_image_free(&png);
-
- if (!checkedAlpha) {
- // This will only check the hashed bits.
- CheckAlphaResult res = CheckAlpha32Rect((u32 *)&out[0], info.w, png.width, png.height, 0xFF000000);
- if (res == CHECKALPHA_ANY || level == 0) {
- alphaStatus_ = ReplacedTextureAlpha(res);
- }
- }
- }
-
- cleanup();
-}
-
-void ReplacedTexture::PurgeIfOlder(double t) {
- if (threadWaitable_ && !threadWaitable_->WaitFor(0.0))
- return;
- if (lastUsed_ >= t)
- return;
-
- for (auto &l : levelData_) {
- if (l->lastUsed < t) {
- // We have to lock since multiple textures might reference this same data.
- std::lock_guard guard(l->lock);
- l->data.clear();
- // This means we have to reload. If we never purge any, there's no need.
- initDone_ = false;
- }
- }
-}
-
-ReplacedTexture::~ReplacedTexture() {
- if (threadWaitable_) {
- cancelPrepare_ = true;
-
- std::unique_lock lock(mutex_);
- threadWaitable_->WaitAndRelease();
- threadWaitable_ = nullptr;
- }
-}
-
-bool ReplacedTexture::Load(int level, void *out, int rowPitch) {
- _assert_msg_((size_t)level < levels_.size(), "Invalid miplevel");
- _assert_msg_(out != nullptr && rowPitch > 0, "Invalid out/pitch");
-
- if (!initDone_)
- return false;
- if (levelData_.empty())
- return false;
-
- _assert_msg_(levelData_[level] != nullptr, "Level cache not set for miplevel");
-
- // We probably could avoid this lock, but better to play it safe.
- std::lock_guard guard(levelData_[level]->lock);
-
- const ReplacedTextureLevel &info = levels_[level];
- const std::vector &data = levelData_[level]->data;
-
- if (data.empty())
- return false;
- if (rowPitch < info.w * 4) {
- ERROR_LOG_REPORT(G3D, "Replacement rowPitch=%d, but w=%d (level=%d)", rowPitch, info.w * 4, level);
- return false;
- }
- _assert_msg_(data.size() == info.w * info.h * 4, "Data has wrong size");
-
- if (rowPitch == info.w * 4) {
- ParallelMemcpy(&g_threadManager, out, &data[0], info.w * 4 * info.h);
- } else {
- const int MIN_LINES_PER_THREAD = 4;
- ParallelRangeLoop(&g_threadManager, [&](int l, int h) {
- for (int y = l; y < h; ++y) {
- memcpy((uint8_t *)out + rowPitch * y, &data[0] + info.w * 4 * y, info.w * 4);
- }
- }, 0, info.h, MIN_LINES_PER_THREAD);
- }
-
- return true;
-}
-
bool TextureReplacer::IniExists(const std::string &gameID) {
if (gameID.empty())
return false;
@@ -1333,31 +902,33 @@ bool TextureReplacer::GenerateIni(const std::string &gameID, Path &generatedFile
FILE *f = File::OpenCFile(generatedFilename, "wb");
if (f) {
+ // Unicode byte order mark
fwrite("\xEF\xBB\xBF", 1, 3, f);
// Let's also write some defaults.
- fprintf(f, "# This file is optional and describes your textures.\n");
- fprintf(f, "# Some information on syntax available here:\n");
- fprintf(f, "# https://github.com/hrydgard/ppsspp/wiki/Texture-replacement-ini-syntax \n");
- fprintf(f, "[options]\n");
- fprintf(f, "version = 1\n");
- fprintf(f, "hash = quick\n");
- fprintf(f, "ignoreMipmap = false\n");
- fprintf(f, "\n");
- fprintf(f, "[games]\n");
- fprintf(f, "# Used to make it easier to install, and override settings for other regions.\n");
- fprintf(f, "# Files still have to be copied to each TEXTURES folder.");
- fprintf(f, "%s = %s\n", gameID.c_str(), INI_FILENAME.c_str());
- fprintf(f, "\n");
- fprintf(f, "[hashes]\n");
- fprintf(f, "# Use / for folders not \\, avoid special characters, and stick to lowercase.\n");
- fprintf(f, "# See wiki for more info.\n");
- fprintf(f, "\n");
- fprintf(f, "[hashranges]\n");
- fprintf(f, "\n");
- fprintf(f, "[filtering]\n");
- fprintf(f, "\n");
- fprintf(f, "[reducehashranges]\n");
+ fprintf(f, R"(# This file is optional and describes your textures.
+# Some information on syntax available here:
+# https://github.com/hrydgard/ppsspp/wiki/Texture-replacement-ini-syntax
+[options]
+version = 1
+hash = quick
+ignoreMipmap = false
+
+[games]
+# Used to make it easier to install, and override settings for other regions.
+# Files still have to be copied to each TEXTURES folder.
+%s = %s
+
+[hashes]
+# Use / for folders not \\, avoid special characters, and stick to lowercase.
+# See wiki for more info.
+
+[hashranges]
+
+[filtering]
+
+[reducehashranges]
+)", gameID.c_str(), INI_FILENAME.c_str());
fclose(f);
}
return File::Exists(generatedFilename);
diff --git a/GPU/Common/TextureReplacer.h b/GPU/Common/TextureReplacer.h
new file mode 100644
index 0000000000..ed0df878c9
--- /dev/null
+++ b/GPU/Common/TextureReplacer.h
@@ -0,0 +1,173 @@
+// Copyright (c) 2016- 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 "ppsspp_config.h"
+#include
+#include
+#include
+#include
+
+#include "Common/CommonFuncs.h"
+#include "Common/CommonTypes.h"
+#include "Common/MemoryUtil.h"
+#include "Common/File/Path.h"
+#include "Common/File/VFS/VFS.h"
+#include "Common/GPU/DataFormat.h"
+
+#include "GPU/Common/TextureDecoder.h"
+#include "GPU/Common/ReplacedTexture.h"
+#include "GPU/ge_constants.h"
+
+class IniFile;
+class TextureCacheCommon;
+class TextureReplacer;
+class ReplacedTextureTask;
+class LimitedWaitable;
+class VFSBackend;
+
+struct SavedTextureCacheData {
+ int levelW[8]{};
+ int levelH[8]{};
+ bool levelSaved[8]{};
+ double lastTimeSaved = 0.0;
+};
+
+struct ReplacedLevelsCache {
+ std::mutex lock;
+ std::vector> data;
+ double lastUsed = 0.0;
+};
+
+struct ReplacementCacheKey {
+ u64 cachekey;
+ u32 hash;
+
+ ReplacementCacheKey(u64 c, u32 h) : cachekey(c), hash(h) { }
+
+ bool operator ==(const ReplacementCacheKey &k) const {
+ return k.cachekey == cachekey && k.hash == hash;
+ }
+
+ bool operator <(const ReplacementCacheKey &k) const {
+ if (k.cachekey == cachekey) {
+ return k.hash < hash;
+ }
+ return k.cachekey < cachekey;
+ }
+};
+
+namespace std {
+ template <>
+ struct hash {
+ size_t operator()(const ReplacementCacheKey &k) const {
+ return std::hash()(k.cachekey ^ ((u64)k.hash << 32));
+ }
+ };
+}
+
+struct ReplacedTextureDecodeInfo {
+ u64 cachekey;
+ u32 hash;
+ u32 addr;
+ bool isVideo;
+ bool isFinal;
+ int scaleFactor;
+ Draw::DataFormat fmt;
+};
+
+enum class ReplacerDecimateMode {
+ NEW_FRAME,
+ FORCE_PRESSURE,
+ ALL,
+};
+
+class TextureReplacer {
+public:
+ // The draw context will be checked for supported texture formats.
+ TextureReplacer(Draw::DrawContext *draw);
+ ~TextureReplacer();
+
+ void Init();
+ void NotifyConfigChanged();
+
+ bool Enabled() const { return enabled_; }
+ bool AllowVideo() const { return allowVideo_; }
+
+ u32 ComputeHash(u32 addr, int bufw, int w, int h, GETextureFormat fmt, u16 maxSeenV);
+
+ // Returns nullptr if not found.
+ ReplacedTexture *FindReplacement(u64 cachekey, u32 hash, int w, int h, double budget);
+ bool FindFiltering(u64 cachekey, u32 hash, TextureFiltering *forceFiltering);
+
+ // Check if a NotifyTextureDecoded for this texture is desired (used to avoid reads from write-combined memory.)
+ bool WillSave(const ReplacedTextureDecodeInfo &replacedInfo);
+
+ // Notify that a new texture was decoded. May already be upscaled, saves the data passed.
+ void NotifyTextureDecoded(const ReplacedTextureDecodeInfo &replacedInfo, const void *data, int pitch, int level, int w, int h);
+
+ void Decimate(ReplacerDecimateMode mode);
+
+ static bool GenerateIni(const std::string &gameID, Path &generatedFilename);
+ static bool IniExists(const std::string &gameID);
+
+ int GetNumTrackedTextures() const { return (int)cache_.size(); }
+ int GetNumCachedReplacedTextures() const { return (int)levelCache_.size(); }
+
+ static std::string HashName(u64 cachekey, u32 hash, int level);
+
+protected:
+ bool LoadIni();
+ bool LoadIniValues(IniFile &ini, bool isOverride = false);
+ void ParseHashRange(const std::string &key, const std::string &value);
+ void ParseFiltering(const std::string &key, const std::string &value);
+ void ParseReduceHashRange(const std::string& key, const std::string& value);
+ bool LookupHashRange(u32 addr, int &w, int &h);
+ float LookupReduceHashRange(int& w, int& h);
+ std::string LookupHashFile(u64 cachekey, u32 hash, bool *foundAlias, bool *ignored);
+ void PopulateReplacement(ReplacedTexture *result, u64 cachekey, u32 hash, int w, int h);
+
+ bool enabled_ = false;
+ bool allowVideo_ = false;
+ bool ignoreAddress_ = false;
+ bool reduceHash_ = false;
+ float reduceHashSize = 1.0f; // default value with reduceHash to false
+ float reduceHashGlobalValue = 0.5f; // Global value for textures dump pngs of all sizes, 0.5 by default but can be set in textures.ini
+
+ double lastTextureCacheSizeGB_ = 0.0;
+ bool ignoreMipmap_ = false;
+ std::string gameID_;
+ Path basePath_;
+ Path newTextureDir_;
+ ReplacedTextureHash hash_ = ReplacedTextureHash::QUICK;
+
+ VFSBackend *vfs_ = nullptr;
+ bool vfsIsZip_ = false;
+
+ typedef std::pair WidthHeightPair;
+ std::unordered_map hashranges_;
+ std::unordered_map reducehashranges_;
+ std::unordered_map aliases_;
+ std::unordered_map filtering_;
+
+ std::unordered_map cache_;
+ std::unordered_map savedCache_;
+
+ // the key is from aliases_. It's a |-separated sequence of texture filenames of the levels of a texture.
+ std::unordered_map levelCache_;
+};
diff --git a/GPU/Common/VertexDecoderCommon.cpp b/GPU/Common/VertexDecoderCommon.cpp
index 488c1736e9..21b3e76a6f 100644
--- a/GPU/Common/VertexDecoderCommon.cpp
+++ b/GPU/Common/VertexDecoderCommon.cpp
@@ -1274,7 +1274,7 @@ void VertexDecoder::SetVertexType(u32 fmt, const VertexDecoderOptions &options,
// Attempt to JIT as well. But only do that if the main CPU JIT is enabled, in order to aid
// debugging attempts - if the main JIT doesn't work, this one won't do any better, probably.
- if (jitCache && g_Config.bVertexDecoderJit && g_Config.iCpuCore == (int)CPUCore::JIT) {
+ if (jitCache) {
jitted_ = jitCache->Compile(*this, &jittedSize_);
if (!jitted_) {
WARN_LOG(G3D, "Vertex decoder JIT failed! fmt = %08x (%s)", fmt_, GetString(SHADER_STRING_SHORT_DESC).c_str());
diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp
index 7da56ed7a0..4404ec254b 100644
--- a/GPU/Common/VertexShaderGenerator.cpp
+++ b/GPU/Common/VertexShaderGenerator.cpp
@@ -1350,7 +1350,8 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
}
if (gstate_c.Use(GPU_USE_CULL_DISTANCE)) {
// Cull any triangle fully outside in the same direction when depth clamp enabled.
- WRITE(p, " if (u_cullRangeMin.w > 0.0) {\n");
+ // We check u_depthRange in case depthScale was zero - in that case we can't work out the cull distance.
+ WRITE(p, " if (u_cullRangeMin.w > 0.0 && u_depthRange.w != 0.0f) {\n");
WRITE(p, " %sgl_CullDistance%s = projPos.z - u_cullRangeMin.z;\n", compat.vsOutPrefix, cull0);
WRITE(p, " %sgl_CullDistance%s = u_cullRangeMax.z - projPos.z;\n", compat.vsOutPrefix, cull1);
WRITE(p, " } else {\n");
diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp
index 81692d3ec5..df5eeb0284 100644
--- a/GPU/D3D11/DrawEngineD3D11.cpp
+++ b/GPU/D3D11/DrawEngineD3D11.cpp
@@ -634,8 +634,8 @@ rotateVBO:
swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result);
// Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values.
// Games sometimes expect exact matches (see #12626, for example) for equal comparisons.
- if (result.action == SW_NOT_READY && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f)
- result.action = SW_DRAW_PRIMITIVES;
+ if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f)
+ result.action = SW_NOT_READY;
if (result.action == SW_NOT_READY) {
swTransform.DetectOffsetTexture(maxIndex);
}
diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h
index 2703828516..7c9b46ac5e 100644
--- a/GPU/D3D11/DrawEngineD3D11.h
+++ b/GPU/D3D11/DrawEngineD3D11.h
@@ -119,6 +119,9 @@ public:
DrawEngineD3D11(Draw::DrawContext *draw, ID3D11Device *device, ID3D11DeviceContext *context);
~DrawEngineD3D11();
+ void DeviceLost() override { draw_ = nullptr; }
+ void DeviceRestore(Draw::DrawContext *draw) override { draw_ = draw; }
+
void SetShaderManager(ShaderManagerD3D11 *shaderManager) {
shaderManager_ = shaderManager;
}
diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp
index f05bc499fe..3e4b5c949c 100644
--- a/GPU/D3D11/FramebufferManagerD3D11.cpp
+++ b/GPU/D3D11/FramebufferManagerD3D11.cpp
@@ -15,10 +15,6 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
-#include
-#include
-#include
-
#include "Common/Common.h"
#include "Common/GPU/thin3d.h"
diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h
index fc280e9de6..c105e16682 100644
--- a/GPU/D3D11/FramebufferManagerD3D11.h
+++ b/GPU/D3D11/FramebufferManagerD3D11.h
@@ -17,20 +17,13 @@
#pragma once
-#include
-
// Keeps track of allocated FBOs.
// Also provides facilities for drawing and later converting raw
// pixel data.
-#include "GPU/GPUCommon.h"
#include "GPU/Common/FramebufferManagerCommon.h"
#include "Common/GPU/thin3d.h"
-class TextureCacheD3D11;
-class DrawEngineD3D11;
-class ShaderManagerD3D11;
-
class FramebufferManagerD3D11 : public FramebufferManagerCommon {
public:
FramebufferManagerD3D11(Draw::DrawContext *draw);
diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp
index 5706c45fca..c92b8ad2f5 100644
--- a/GPU/D3D11/GPU_D3D11.cpp
+++ b/GPU/D3D11/GPU_D3D11.cpp
@@ -15,7 +15,7 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
-#include
+#include
#include "Common/Log.h"
#include "Common/Serialize/Serializer.h"
@@ -42,7 +42,7 @@
#include "GPU/D3D11/D3D11Util.h"
GPU_D3D11::GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
- : GPUCommon(gfxCtx, draw), drawEngine_(draw,
+ : GPUCommonHW(gfxCtx, draw), drawEngine_(draw,
(ID3D11Device *)draw->GetNativeObject(Draw::NativeObject::DEVICE),
(ID3D11DeviceContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT)) {
device_ = (ID3D11Device *)draw->GetNativeObject(Draw::NativeObject::DEVICE);
@@ -87,16 +87,11 @@ GPU_D3D11::GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
}
GPU_D3D11::~GPU_D3D11() {
- framebufferManagerD3D11_->DestroyAllFBOs();
- delete framebufferManagerD3D11_;
- shaderManagerD3D11_->ClearShaders();
- delete shaderManagerD3D11_;
- delete textureCacheD3D11_;
stockD3D11.Destroy();
}
u32 GPU_D3D11::CheckGPUFeatures() const {
- u32 features = GPUCommon::CheckGPUFeatures();
+ u32 features = GPUCommonHW::CheckGPUFeatures();
// Accurate depth is required because the Direct3D API does not support inverse Z.
// So we cannot incorrectly use the viewport transform as the depth range on Direct3D.
@@ -116,102 +111,49 @@ u32 GPU_D3D11::CheckGPUFeatures() const {
return CheckGPUFeaturesLate(features);
}
-// Needs to be called on GPU thread, not reporting thread.
-void GPU_D3D11::BuildReportingInfo() {
- using namespace Draw;
- DrawContext *thin3d = gfxCtx_->GetDrawContext();
-
- reportingPrimaryInfo_ = thin3d->GetInfoString(InfoField::VENDORSTRING);
- reportingFullInfo_ = reportingPrimaryInfo_ + " - " + System_GetProperty(SYSPROP_GPUDRIVER_VERSION) + " - " + thin3d->GetInfoString(InfoField::SHADELANGVERSION);
-}
-
void GPU_D3D11::DeviceLost() {
draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE);
// Simply drop all caches and textures.
// FBOs appear to survive? Or no?
- shaderManagerD3D11_->ClearShaders();
+ shaderManager_->ClearShaders();
drawEngine_.ClearInputLayoutMap();
- textureCacheD3D11_->Clear(false);
+ textureCache_->Clear(false);
- GPUCommon::DeviceLost();
+ GPUCommonHW::DeviceLost();
}
-void GPU_D3D11::DeviceRestore() {
- GPUCommon::DeviceRestore();
+void GPU_D3D11::DeviceRestore(Draw::DrawContext *draw) {
+ GPUCommonHW::DeviceRestore(draw);
// Nothing needed.
}
-void GPU_D3D11::InitClear() {
- if (!framebufferManager_->UseBufferedRendering()) {
- // device_->Clear(0, NULL, D3DCLEAR_STENCIL | D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.f, 0);
- }
-}
-
void GPU_D3D11::BeginFrame() {
- GPUCommon::BeginFrame();
+ GPUCommonHW::BeginFrame();
- textureCacheD3D11_->StartFrame();
+ textureCache_->StartFrame();
drawEngine_.BeginFrame();
- shaderManagerD3D11_->DirtyLastShader();
+ shaderManager_->DirtyLastShader();
- framebufferManagerD3D11_->BeginFrame();
+ framebufferManager_->BeginFrame();
gstate_c.Dirty(DIRTY_PROJTHROUGHMATRIX);
if (gstate_c.useFlagsChanged) {
// TODO: It'd be better to recompile them in the background, probably?
// This most likely means that saw equal depth changed.
WARN_LOG(G3D, "Shader use flags changed, clearing all shaders and depth buffers");
- shaderManagerD3D11_->ClearShaders();
+ shaderManager_->ClearShaders();
framebufferManager_->ClearAllDepthBuffers();
drawEngine_.ClearInputLayoutMap();
gstate_c.useFlagsChanged = false;
}
}
-void GPU_D3D11::CopyDisplayToOutput(bool reallyDirty) {
- // Flush anything left over.
- drawEngine_.Flush();
-
- shaderManager_->DirtyLastShader();
-
- framebufferManagerD3D11_->CopyDisplayToOutput(reallyDirty);
-
- gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
-}
-
void GPU_D3D11::FinishDeferred() {
// This finishes reading any vertex data that is pending.
drawEngine_.FinishDeferred();
}
-inline void GPU_D3D11::CheckFlushOp(int cmd, u32 diff) {
- const u8 cmdFlags = cmdInfo_[cmd].flags;
- if (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)) {
- if (dumpThisFrame_) {
- NOTICE_LOG(G3D, "================ FLUSH ================");
- }
- drawEngine_.Flush();
- }
-}
-
-void GPU_D3D11::PreExecuteOp(u32 op, u32 diff) {
- CheckFlushOp(op >> 24, diff);
-}
-
-void GPU_D3D11::ExecuteOp(u32 op, u32 diff) {
- const u8 cmd = op >> 24;
- const CommandInfo info = cmdInfo_[cmd];
- const u8 cmdFlags = info.flags;
- if ((cmdFlags & FLAG_EXECUTE) || (diff && (cmdFlags & FLAG_EXECUTEONCHANGE))) {
- (this->*info.func)(op, diff);
- } else if (diff) {
- uint64_t dirty = info.flags >> 8;
- if (dirty)
- gstate_c.Dirty(dirty);
- }
-}
-
void GPU_D3D11::GetStats(char *buffer, size_t bufsize) {
size_t offset = FormatGPUStatsCommon(buffer, bufsize);
buffer += offset;
@@ -224,39 +166,3 @@ void GPU_D3D11::GetStats(char *buffer, size_t bufsize) {
shaderManagerD3D11_->GetNumFragmentShaders()
);
}
-
-void GPU_D3D11::DoState(PointerWrap &p) {
- GPUCommon::DoState(p);
-
- // TODO: Some of these things may not be necessary.
- // None of these are necessary when saving.
- if (p.mode == p.MODE_READ && !PSP_CoreParameter().frozen) {
- textureCache_->Clear(true);
- drawEngine_.ClearTrackedVertexArrays();
-
- gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
- framebufferManager_->DestroyAllFBOs();
- }
-}
-
-std::vector GPU_D3D11::DebugGetShaderIDs(DebugShaderType type) {
- switch (type) {
- case SHADER_TYPE_VERTEXLOADER:
- return drawEngine_.DebugGetVertexLoaderIDs();
- case SHADER_TYPE_TEXTURE:
- return textureCache_->GetTextureShaderCache()->DebugGetShaderIDs(type);
- default:
- return shaderManagerD3D11_->DebugGetShaderIDs(type);
- }
-}
-
-std::string GPU_D3D11::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {
- switch (type) {
- case SHADER_TYPE_VERTEXLOADER:
- return drawEngine_.DebugGetVertexLoaderString(id, stringType);
- case SHADER_TYPE_TEXTURE:
- return textureCache_->GetTextureShaderCache()->DebugGetShaderString(id, type, stringType);
- default:
- return shaderManagerD3D11_->DebugGetShaderString(id, type, stringType);
- }
-}
diff --git a/GPU/D3D11/GPU_D3D11.h b/GPU/D3D11/GPU_D3D11.h
index 0fece6f431..a2e374c6f0 100644
--- a/GPU/D3D11/GPU_D3D11.h
+++ b/GPU/D3D11/GPU_D3D11.h
@@ -21,46 +21,30 @@
#include
#include
-#include "GPU/GPUCommon.h"
+#include "GPU/GPUCommonHW.h"
#include "GPU/D3D11/DrawEngineD3D11.h"
-#include "GPU/Common/TextureShaderCommon.h"
#include "GPU/Common/VertexDecoderCommon.h"
class FramebufferManagerD3D11;
class ShaderManagerD3D11;
-class LinkedShaderD3D11;
class TextureCacheD3D11;
-class GPU_D3D11 : public GPUCommon {
+class GPU_D3D11 : public GPUCommonHW {
public:
GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw);
~GPU_D3D11();
u32 CheckGPUFeatures() const override;
- void PreExecuteOp(u32 op, u32 diff) override;
- void ExecuteOp(u32 op, u32 diff) override;
void GetStats(char *buffer, size_t bufsize) override;
void DeviceLost() override; // Only happens on Android. Drop all textures and shaders.
- void DeviceRestore() override;
-
- void DoState(PointerWrap &p) override;
-
- // Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend.
- std::vector DebugGetShaderIDs(DebugShaderType shader) override;
- std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override;
+ void DeviceRestore(Draw::DrawContext *draw) override;
protected:
void FinishDeferred() override;
private:
- // void ApplyDrawState(int prim);
- void CheckFlushOp(int cmd, u32 diff);
- void BuildReportingInfo() override;
-
- void InitClear() override;
void BeginFrame() override;
- void CopyDisplayToOutput(bool reallyDirty) override;
ID3D11Device *device_;
ID3D11DeviceContext *context_;
diff --git a/GPU/D3D11/ShaderManagerD3D11.h b/GPU/D3D11/ShaderManagerD3D11.h
index 75203f9533..ffdd65ffe7 100644
--- a/GPU/D3D11/ShaderManagerD3D11.h
+++ b/GPU/D3D11/ShaderManagerD3D11.h
@@ -86,14 +86,16 @@ public:
~ShaderManagerD3D11();
void GetShaders(int prim, VertexDecoder *decoder, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode);
- void ClearShaders();
+ void ClearShaders() override;
void DirtyLastShader() override;
+ void DeviceLost() override { draw_ = nullptr; }
+ void DeviceRestore(Draw::DrawContext *draw) override { draw_ = draw; }
int GetNumVertexShaders() const { return (int)vsCache_.size(); }
int GetNumFragmentShaders() const { return (int)fsCache_.size(); }
- std::vector DebugGetShaderIDs(DebugShaderType type);
- std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType);
+ std::vector DebugGetShaderIDs(DebugShaderType type) override;
+ std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) override;
uint64_t UpdateUniforms(bool useBufferedRendering);
void BindUniforms();
diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp
index ac80c9627a..1d00bfb46d 100644
--- a/GPU/D3D11/StateMappingD3D11.cpp
+++ b/GPU/D3D11/StateMappingD3D11.cpp
@@ -442,7 +442,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) {
void DrawEngineD3D11::ApplyDrawStateLate(bool applyStencilRef, uint8_t stencilRef) {
// we go through Draw here because it automatically handles screen rotation, as needed in UWP on mobiles.
if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) {
- draw_->SetViewports(1, &dynState_.viewport);
+ draw_->SetViewport(dynState_.viewport);
draw_->SetScissorRect(dynState_.scissor.left, dynState_.scissor.top, dynState_.scissor.right - dynState_.scissor.left, dynState_.scissor.bottom - dynState_.scissor.top);
}
if (gstate_c.IsDirty(DIRTY_RASTER_STATE)) {
diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp
index 31433016ee..90d1927898 100644
--- a/GPU/D3D11/TextureCacheD3D11.cpp
+++ b/GPU/D3D11/TextureCacheD3D11.cpp
@@ -179,35 +179,12 @@ void TextureCacheD3D11::ReleaseTexture(TexCacheEntry *entry, bool delete_them) {
}
void TextureCacheD3D11::ForgetLastTexture() {
- InvalidateLastTexture();
+ lastBoundTexture = INVALID_TEX;
ID3D11ShaderResourceView *nullTex[4]{};
context_->PSSetShaderResources(0, 4, nullTex);
}
-void TextureCacheD3D11::InvalidateLastTexture() {
- lastBoundTexture = INVALID_TEX;
-}
-
-void TextureCacheD3D11::StartFrame() {
- TextureCacheCommon::StartFrame();
-
- InvalidateLastTexture();
- timesInvalidatedAllThisFrame_ = 0;
- replacementTimeThisFrame_ = 0.0;
-
- if (texelsScaledThisFrame_) {
- // INFO_LOG(G3D, "Scaled %i texels", texelsScaledThisFrame_);
- }
- texelsScaledThisFrame_ = 0;
- if (clearCacheNextFrame_) {
- Clear(true);
- clearCacheNextFrame_ = false;
- } else {
- Decimate();
- }
-}
-
void TextureCacheD3D11::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) {
const u32 clutBaseBytes = clutBase * (clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16));
// Technically, these extra bytes weren't loaded, but hopefully it was loaded earlier.
@@ -268,9 +245,7 @@ void TextureCacheD3D11::ApplySamplingParams(const SamplerCacheKey &key) {
}
void TextureCacheD3D11::Unbind() {
- ID3D11ShaderResourceView *nullView = nullptr;
- context_->PSSetShaderResources(0, 1, &nullView);
- InvalidateLastTexture();
+ ForgetLastTexture();
}
void TextureCacheD3D11::BindAsClutTexture(Draw::Texture *tex, bool smooth) {
@@ -288,7 +263,7 @@ void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry) {
DXGI_FORMAT dstFmt = GetDestFormat(GETextureFormat(entry->format), gstate.getClutPaletteFormat());
if (plan.replaceValid) {
- dstFmt = ToDXGIFormat(plan.replaced->Format(plan.baseLevelSrc));
+ dstFmt = ToDXGIFormat(plan.replaced->Format());
} else if (plan.scaleFactor > 1 || plan.saveTexture) {
dstFmt = DXGI_FORMAT_B8G8R8A8_UNORM;
} else if (plan.decodeToClut8) {
@@ -309,45 +284,16 @@ void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry) {
if (th > 16384)
th = 16384;
+ // The PSP only supports 8 mip levels, but we support 12 in the texture replacer (4k textures down to 1).
+ D3D11_SUBRESOURCE_DATA subresData[12]{};
+
if (plan.depth == 1) {
// We don't yet have mip generation, so clamp the number of levels to the ones we can load directly.
levels = std::min(plan.levelsToCreate, plan.levelsToLoad);
-
- ID3D11Texture2D *tex = nullptr;
- D3D11_TEXTURE2D_DESC desc{};
- desc.CPUAccessFlags = 0;
- desc.Usage = D3D11_USAGE_DEFAULT;
- desc.ArraySize = 1;
- desc.SampleDesc.Count = 1;
- desc.Width = tw;
- desc.Height = th;
- desc.Format = dstFmt;
- desc.MipLevels = levels;
- desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
-
- ASSERT_SUCCESS(device_->CreateTexture2D(&desc, nullptr, &tex));
- texture = tex;
} else {
- ID3D11Texture3D *tex = nullptr;
- D3D11_TEXTURE3D_DESC desc{};
- desc.CPUAccessFlags = 0;
- desc.Usage = D3D11_USAGE_DEFAULT;
- desc.Width = tw;
- desc.Height = th;
- desc.Depth = plan.depth;
- desc.Format = dstFmt;
- desc.MipLevels = 1;
- desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
- ASSERT_SUCCESS(device_->CreateTexture3D(&desc, nullptr, &tex));
- texture = tex;
-
levels = plan.depth;
}
- ASSERT_SUCCESS(device_->CreateShaderResourceView(texture, nullptr, &view));
- entry->texturePtr = texture;
- entry->textureView = view;
-
Draw::DataFormat texFmt = FromD3D11Format(dstFmt);
for (int i = 0; i < levels; i++) {
@@ -364,7 +310,7 @@ void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry) {
// For UpdateSubresource, we can't decode directly into the texture so we allocate a buffer :(
// NOTE: Could reuse it between levels or textures!
if (plan.replaceValid) {
- bpp = (int)Draw::DataFormatSizeInBytes(plan.replaced->Format(srcLevel));
+ bpp = (int)Draw::DataFormatSizeInBytes(plan.replaced->Format());
} else {
if (plan.scaleFactor > 1) {
bpp = 4;
@@ -374,7 +320,20 @@ void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry) {
}
stride = std::max(mipWidth * bpp, 16);
- data = (u8 *)AllocateAlignedMemory(stride * mipHeight, 16);
+
+ if (plan.depth == 1) {
+ data = (u8 *)AllocateAlignedMemory(stride * mipHeight, 16);
+ subresData[i].pSysMem = data;
+ subresData[i].SysMemPitch = stride;
+ subresData[i].SysMemSlicePitch = 0;
+ } else {
+ if (i == 0) {
+ subresData[0].pSysMem = AllocateAlignedMemory(stride * mipHeight * plan.depth, 16);
+ subresData[0].SysMemPitch = stride;
+ subresData[0].SysMemSlicePitch = stride * mipHeight;
+ }
+ data = (uint8_t *)subresData[0].pSysMem + stride * mipHeight * i;
+ }
if (!data) {
ERROR_LOG(G3D, "Ran out of RAM trying to allocate a temporary texture upload buffer (%dx%d)", mipWidth, mipHeight);
@@ -382,17 +341,51 @@ void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry) {
}
LoadTextureLevel(*entry, data, stride, plan, srcLevel, texFmt, TexDecodeFlags{});
- if (plan.depth == 1) {
- context_->UpdateSubresource(texture, i, nullptr, data, stride, 0);
- } else {
- D3D11_BOX box{};
- box.front = i;
- box.back = i + 1;
- box.right = mipWidth;
- box.bottom = mipHeight;
- context_->UpdateSubresource(texture, 0, &box, data, stride, 0);
+ }
+
+ if (plan.depth == 1) {
+ // We don't yet have mip generation, so clamp the number of levels to the ones we can load directly.
+ levels = std::min(plan.levelsToCreate, plan.levelsToLoad);
+
+ ID3D11Texture2D *tex = nullptr;
+ D3D11_TEXTURE2D_DESC desc{};
+ desc.CPUAccessFlags = 0;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.ArraySize = 1;
+ desc.SampleDesc.Count = 1;
+ desc.Width = tw;
+ desc.Height = th;
+ desc.Format = dstFmt;
+ desc.MipLevels = levels;
+ desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+
+ ASSERT_SUCCESS(device_->CreateTexture2D(&desc, subresData, &tex));
+ texture = tex;
+ } else {
+ ID3D11Texture3D *tex = nullptr;
+ D3D11_TEXTURE3D_DESC desc{};
+ desc.CPUAccessFlags = 0;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.Width = tw;
+ desc.Height = th;
+ desc.Depth = plan.depth;
+ desc.Format = dstFmt;
+ desc.MipLevels = 1;
+ desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ ASSERT_SUCCESS(device_->CreateTexture3D(&desc, subresData, &tex));
+ texture = tex;
+
+ levels = plan.depth;
+ }
+
+ ASSERT_SUCCESS(device_->CreateShaderResourceView(texture, nullptr, &view));
+ entry->texturePtr = texture;
+ entry->textureView = view;
+
+ for (int i = 0; i < 12; i++) {
+ if (subresData[i].pSysMem) {
+ FreeAlignedMemory((void *)subresData[i].pSysMem);
}
- FreeAlignedMemory(data);
}
// Signal that we support depth textures so use it as one.
diff --git a/GPU/D3D11/TextureCacheD3D11.h b/GPU/D3D11/TextureCacheD3D11.h
index 20d84d6d48..53c150a9e4 100644
--- a/GPU/D3D11/TextureCacheD3D11.h
+++ b/GPU/D3D11/TextureCacheD3D11.h
@@ -46,15 +46,15 @@ public:
TextureCacheD3D11(Draw::DrawContext *draw, Draw2D *draw2D);
~TextureCacheD3D11();
- void StartFrame() override;
-
void SetFramebufferManager(FramebufferManagerD3D11 *fbManager);
void ForgetLastTexture() override;
- void InvalidateLastTexture() override;
bool GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level, bool *isFramebuffer) override;
+ void DeviceLost() override { draw_ = nullptr; }
+ void DeviceRestore(Draw::DrawContext *draw) override { draw_ = draw; }
+
protected:
void BindTexture(TexCacheEntry *entry) override;
void Unbind() override;
diff --git a/GPU/Directx9/DrawEngineDX9.h b/GPU/Directx9/DrawEngineDX9.h
index e8bb1fbf42..1cea91376b 100644
--- a/GPU/Directx9/DrawEngineDX9.h
+++ b/GPU/Directx9/DrawEngineDX9.h
@@ -107,6 +107,9 @@ public:
DrawEngineDX9(Draw::DrawContext *draw);
~DrawEngineDX9();
+ void DeviceLost() override { draw_ = nullptr; }
+ void DeviceRestore(Draw::DrawContext *draw) override { draw_ = draw; }
+
void SetShaderManager(ShaderManagerDX9 *shaderManager) {
shaderManager_ = shaderManager;
}
diff --git a/GPU/Directx9/FramebufferManagerDX9.cpp b/GPU/Directx9/FramebufferManagerDX9.cpp
index 58d92756f0..e0eda00207 100644
--- a/GPU/Directx9/FramebufferManagerDX9.cpp
+++ b/GPU/Directx9/FramebufferManagerDX9.cpp
@@ -15,34 +15,16 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+#include
+
#include "Common/Common.h"
-#include "Common/Data/Convert/ColorConv.h"
#include "Common/GPU/thin3d.h"
-#include "Common/Math/lin/matrix4x4.h"
-#include "Core/MemMap.h"
-#include "Core/Config.h"
-#include "Core/ConfigValues.h"
-#include "Core/System.h"
-#include "GPU/ge_constants.h"
-#include "GPU/GPUState.h"
-#include "GPU/Debugger/Stepping.h"
-#include "Common/GPU/D3D9/D3D9StateCache.h"
#include "GPU/Common/FramebufferManagerCommon.h"
+#include "GPU/Common/GPUStateUtils.h"
#include "GPU/Common/PresentationCommon.h"
#include "GPU/Common/TextureDecoder.h"
#include "GPU/Directx9/FramebufferManagerDX9.h"
-#include "GPU/Directx9/ShaderManagerDX9.h"
-#include "GPU/Directx9/TextureCacheDX9.h"
-#include "GPU/Directx9/DrawEngineDX9.h"
-
-#include "Common/GPU/thin3d.h"
-
-#include
-
-#ifdef _M_SSE
-#include
-#endif
FramebufferManagerDX9::FramebufferManagerDX9(Draw::DrawContext *draw)
: FramebufferManagerCommon(draw) {
diff --git a/GPU/Directx9/FramebufferManagerDX9.h b/GPU/Directx9/FramebufferManagerDX9.h
index 37458526fd..5a76d05944 100644
--- a/GPU/Directx9/FramebufferManagerDX9.h
+++ b/GPU/Directx9/FramebufferManagerDX9.h
@@ -17,17 +17,9 @@
#pragma once
-#include
-
-#include
-
#include "GPU/GPUCommon.h"
#include "GPU/Common/FramebufferManagerCommon.h"
-class TextureCacheDX9;
-class DrawEngineDX9;
-class ShaderManagerDX9;
-
class FramebufferManagerDX9 : public FramebufferManagerCommon {
public:
FramebufferManagerDX9(Draw::DrawContext *draw);
diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp
index af8d80e327..cc099aa52a 100644
--- a/GPU/Directx9/GPU_DX9.cpp
+++ b/GPU/Directx9/GPU_DX9.cpp
@@ -15,7 +15,7 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
-#include
+#include
#include "Common/Serialize/Serializer.h"
#include "Common/GraphicsContext.h"
@@ -44,7 +44,7 @@
#include "GPU/Directx9/TextureCacheDX9.h"
GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
- : GPUCommon(gfxCtx, draw),
+ : GPUCommonHW(gfxCtx, draw),
drawEngine_(draw) {
device_ = (LPDIRECT3DDEVICE9)draw->GetNativeObject(Draw::NativeObject::DEVICE);
deviceEx_ = (LPDIRECT3DDEVICE9EX)draw->GetNativeObject(Draw::NativeObject::DEVICE_EX);
@@ -94,7 +94,7 @@ GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
}
u32 GPU_DX9::CheckGPUFeatures() const {
- u32 features = GPUCommon::CheckGPUFeatures();
+ u32 features = GPUCommonHW::CheckGPUFeatures();
features |= GPU_USE_16BIT_FORMATS;
features |= GPU_USE_TEXTURE_LOD_CONTROL;
@@ -105,53 +105,24 @@ u32 GPU_DX9::CheckGPUFeatures() const {
return CheckGPUFeaturesLate(features);
}
-GPU_DX9::~GPU_DX9() {
- framebufferManagerDX9_->DestroyAllFBOs();
- delete framebufferManagerDX9_;
- delete textureCache_;
- shaderManagerDX9_->ClearCache(true);
- delete shaderManagerDX9_;
-}
-
-// Needs to be called on GPU thread, not reporting thread.
-void GPU_DX9::BuildReportingInfo() {
- using namespace Draw;
- DrawContext *thin3d = gfxCtx_->GetDrawContext();
-
- reportingPrimaryInfo_ = thin3d->GetInfoString(InfoField::VENDORSTRING);
- reportingFullInfo_ = reportingPrimaryInfo_ + " - " + System_GetProperty(SYSPROP_GPUDRIVER_VERSION) + " - " + thin3d->GetInfoString(InfoField::SHADELANGVERSION);
-}
-
void GPU_DX9::DeviceLost() {
- // Simply drop all caches and textures.
- shaderManagerDX9_->ClearCache(false);
- textureCacheDX9_->Clear(false);
- GPUCommon::DeviceLost();
+ GPUCommonHW::DeviceLost();
}
-void GPU_DX9::DeviceRestore() {
- GPUCommon::DeviceRestore();
- // Nothing needed.
-}
-
-void GPU_DX9::InitClear() {
- if (!framebufferManager_->UseBufferedRendering()) {
- dxstate.depthWrite.set(true);
- dxstate.colorMask.set(0xF);
- device_->Clear(0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.f, 0);
- }
+void GPU_DX9::DeviceRestore(Draw::DrawContext *draw) {
+ GPUCommonHW::DeviceRestore(draw);
}
void GPU_DX9::ReapplyGfxState() {
dxstate.Restore();
- GPUCommon::ReapplyGfxState();
+ GPUCommonHW::ReapplyGfxState();
}
void GPU_DX9::BeginFrame() {
- textureCacheDX9_->StartFrame();
+ textureCache_->StartFrame();
drawEngine_.BeginFrame();
- GPUCommon::BeginFrame();
+ GPUCommonHW::BeginFrame();
shaderManagerDX9_->DirtyShader();
framebufferManager_->BeginFrame();
@@ -160,54 +131,17 @@ void GPU_DX9::BeginFrame() {
// TODO: It'd be better to recompile them in the background, probably?
// This most likely means that saw equal depth changed.
WARN_LOG(G3D, "Shader use flags changed, clearing all shaders and depth buffers");
- shaderManagerDX9_->ClearCache(true);
+ shaderManager_->ClearShaders();
framebufferManager_->ClearAllDepthBuffers();
gstate_c.useFlagsChanged = false;
}
}
-void GPU_DX9::CopyDisplayToOutput(bool reallyDirty) {
- drawEngine_.Flush();
-
- shaderManager_->DirtyLastShader();
-
- framebufferManagerDX9_->CopyDisplayToOutput(reallyDirty);
-
- gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
-}
-
void GPU_DX9::FinishDeferred() {
// This finishes reading any vertex data that is pending.
drawEngine_.FinishDeferred();
}
-inline void GPU_DX9::CheckFlushOp(int cmd, u32 diff) {
- const u8 cmdFlags = cmdInfo_[cmd].flags;
- if (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)) {
- if (dumpThisFrame_) {
- NOTICE_LOG(G3D, "================ FLUSH ================");
- }
- drawEngine_.Flush();
- }
-}
-
-void GPU_DX9::PreExecuteOp(u32 op, u32 diff) {
- CheckFlushOp(op >> 24, diff);
-}
-
-void GPU_DX9::ExecuteOp(u32 op, u32 diff) {
- const u8 cmd = op >> 24;
- const CommandInfo info = cmdInfo_[cmd];
- const u8 cmdFlags = info.flags;
- if ((cmdFlags & FLAG_EXECUTE) || (diff && (cmdFlags & FLAG_EXECUTEONCHANGE))) {
- (this->*info.func)(op, diff);
- } else if (diff) {
- uint64_t dirty = info.flags >> 8;
- if (dirty)
- gstate_c.Dirty(dirty);
- }
-}
-
void GPU_DX9::GetStats(char *buffer, size_t bufsize) {
size_t offset = FormatGPUStatsCommon(buffer, bufsize);
buffer += offset;
@@ -220,39 +154,3 @@ void GPU_DX9::GetStats(char *buffer, size_t bufsize) {
shaderManagerDX9_->GetNumFragmentShaders()
);
}
-
-void GPU_DX9::DoState(PointerWrap &p) {
- GPUCommon::DoState(p);
-
- // TODO: Some of these things may not be necessary.
- // None of these are necessary when saving.
- if (p.mode == p.MODE_READ && !PSP_CoreParameter().frozen) {
- textureCache_->Clear(true);
- drawEngine_.ClearTrackedVertexArrays();
-
- gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
- framebufferManager_->DestroyAllFBOs();
- }
-}
-
-std::vector GPU_DX9::DebugGetShaderIDs(DebugShaderType type) {
- switch (type) {
- case SHADER_TYPE_VERTEXLOADER:
- return drawEngine_.DebugGetVertexLoaderIDs();
- case SHADER_TYPE_TEXTURE:
- return textureCache_->GetTextureShaderCache()->DebugGetShaderIDs(type);
- default:
- return shaderManagerDX9_->DebugGetShaderIDs(type);
- }
-}
-
-std::string GPU_DX9::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {
- switch (type) {
- case SHADER_TYPE_VERTEXLOADER:
- return drawEngine_.DebugGetVertexLoaderString(id, stringType);
- case SHADER_TYPE_TEXTURE:
- return textureCache_->GetTextureShaderCache()->DebugGetShaderString(id, type, stringType);
- default:
- return shaderManagerDX9_->DebugGetShaderString(id, type, stringType);
- }
-}
diff --git a/GPU/Directx9/GPU_DX9.h b/GPU/Directx9/GPU_DX9.h
index 621ad79857..f18ffeb77e 100644
--- a/GPU/Directx9/GPU_DX9.h
+++ b/GPU/Directx9/GPU_DX9.h
@@ -20,7 +20,7 @@
#include
#include
-#include "GPU/GPUCommon.h"
+#include "GPU/GPUCommonHW.h"
#include "GPU/Directx9/FramebufferManagerDX9.h"
#include "GPU/Directx9/DrawEngineDX9.h"
#include "GPU/Common/TextureShaderCommon.h"
@@ -30,36 +30,23 @@ class ShaderManagerDX9;
class LinkedShaderDX9;
class TextureCacheDX9;
-class GPU_DX9 : public GPUCommon {
+class GPU_DX9 : public GPUCommonHW {
public:
GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw);
- ~GPU_DX9();
u32 CheckGPUFeatures() const override;
- void PreExecuteOp(u32 op, u32 diff) override;
- void ExecuteOp(u32 op, u32 diff) override;
+
+ void DeviceLost() override;
+ void DeviceRestore(Draw::DrawContext *draw) override;
void ReapplyGfxState() override;
void GetStats(char *buffer, size_t bufsize) override;
- void DeviceLost() override; // Only happens on Android. Drop all textures and shaders.
- void DeviceRestore() override;
-
- void DoState(PointerWrap &p) override;
-
- // Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend.
- std::vector DebugGetShaderIDs(DebugShaderType shader) override;
- std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override;
protected:
void FinishDeferred() override;
private:
- void CheckFlushOp(int cmd, u32 diff);
- void BuildReportingInfo() override;
-
- void InitClear() override;
void BeginFrame() override;
- void CopyDisplayToOutput(bool reallyDirty) override;
LPDIRECT3DDEVICE9 device_;
LPDIRECT3DDEVICE9EX deviceEx_;
diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp
index 1571d517bd..374d66fb24 100644
--- a/GPU/Directx9/ShaderManagerDX9.cpp
+++ b/GPU/Directx9/ShaderManagerDX9.cpp
@@ -466,7 +466,7 @@ void ShaderManagerDX9::VSUpdateUniforms(u64 dirtyUniforms) {
float minz = -((gstate_c.vpZOffset * halfActualZRange) - vpZCenter) - halfActualZRange;
float viewZScale = halfActualZRange * 2.0f;
float viewZCenter = minz;
- float reverseScale = 2.0f * (1.0f / gstate_c.vpDepthScale);
+ float reverseScale = gstate_c.vpDepthScale != 0.0f ? 2.0f * (1.0f / gstate_c.vpDepthScale) : 0.0f;
float reverseTranslate = gstate_c.vpZOffset * 0.5f + 0.5f;
float data[4] = { viewZScale, viewZCenter, reverseTranslate, reverseScale };
@@ -540,11 +540,10 @@ void ShaderManagerDX9::Clear() {
DirtyShader();
}
-void ShaderManagerDX9::ClearCache(bool deleteThem) {
+void ShaderManagerDX9::ClearShaders() {
Clear();
}
-
void ShaderManagerDX9::DirtyShader() {
// Forget the last shader ID
lastFSID_.set_invalid();
@@ -554,7 +553,7 @@ void ShaderManagerDX9::DirtyShader() {
gstate_c.Dirty(DIRTY_ALL_UNIFORMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE);
}
-void ShaderManagerDX9::DirtyLastShader() { // disables vertex arrays
+void ShaderManagerDX9::DirtyLastShader() {
lastVShader_ = nullptr;
lastPShader_ = nullptr;
}
diff --git a/GPU/Directx9/ShaderManagerDX9.h b/GPU/Directx9/ShaderManagerDX9.h
index 299eb677d2..68337503b4 100644
--- a/GPU/Directx9/ShaderManagerDX9.h
+++ b/GPU/Directx9/ShaderManagerDX9.h
@@ -77,7 +77,7 @@ public:
ShaderManagerDX9(Draw::DrawContext *draw, LPDIRECT3DDEVICE9 device);
~ShaderManagerDX9();
- void ClearCache(bool deleteThem); // TODO: deleteThem currently not respected
+ void ClearShaders() override;
VSShader *ApplyShader(bool useHWTransform, bool useHWTessellation, VertexDecoder *decoder, bool weightsAsFloat, bool useSkinInDecode, const ComputedPipelineState &pipelineState);
void DirtyShader();
void DirtyLastShader() override;
@@ -85,8 +85,11 @@ public:
int GetNumVertexShaders() const { return (int)vsCache_.size(); }
int GetNumFragmentShaders() const { return (int)fsCache_.size(); }
- std::vector DebugGetShaderIDs(DebugShaderType type);
- std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType);
+ void DeviceLost() override { draw_ = nullptr; }
+ void DeviceRestore(Draw::DrawContext *draw) override { draw_ = draw; }
+
+ std::vector DebugGetShaderIDs(DebugShaderType type) override;
+ std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) override;
private:
void PSUpdateUniforms(u64 dirtyUniforms);
diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp
index 591dc3f85c..dc1ed423d6 100644
--- a/GPU/Directx9/TextureCacheDX9.cpp
+++ b/GPU/Directx9/TextureCacheDX9.cpp
@@ -111,7 +111,7 @@ void TextureCacheDX9::ReleaseTexture(TexCacheEntry *entry, bool delete_them) {
}
}
-void TextureCacheDX9::InvalidateLastTexture() {
+void TextureCacheDX9::ForgetLastTexture() {
lastBoundTexture = INVALID_TEX;
}
@@ -154,22 +154,8 @@ void TextureCacheDX9::ApplySamplingParams(const SamplerCacheKey &key) {
void TextureCacheDX9::StartFrame() {
TextureCacheCommon::StartFrame();
- InvalidateLastTexture();
- timesInvalidatedAllThisFrame_ = 0;
- replacementTimeThisFrame_ = 0.0;
-
- if (texelsScaledThisFrame_) {
- VERBOSE_LOG(G3D, "Scaled %i texels", texelsScaledThisFrame_);
- }
- texelsScaledThisFrame_ = 0;
- if (clearCacheNextFrame_) {
- Clear(true);
- clearCacheNextFrame_ = false;
- } else {
- Decimate();
- }
-
if (gstate_c.Use(GPU_USE_ANISOTROPY)) {
+ // Just take the opportunity to set the global aniso level here, once per frame.
DWORD aniso = 1 << g_Config.iAnisotropyLevel;
DWORD anisotropyLevel = aniso > maxAnisotropyLevel ? maxAnisotropyLevel : aniso;
device_->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, anisotropyLevel);
@@ -229,7 +215,7 @@ void TextureCacheDX9::BindTexture(TexCacheEntry *entry) {
void TextureCacheDX9::Unbind() {
device_->SetTexture(0, nullptr);
- InvalidateLastTexture();
+ ForgetLastTexture();
}
void TextureCacheDX9::BindAsClutTexture(Draw::Texture *tex, bool smooth) {
@@ -249,7 +235,7 @@ void TextureCacheDX9::BuildTexture(TexCacheEntry *const entry) {
D3DFORMAT dstFmt = GetDestFormat(GETextureFormat(entry->format), gstate.getClutPaletteFormat());
if (plan.replaceValid) {
- dstFmt = ToD3D9Format(plan.replaced->Format(plan.baseLevelSrc));
+ dstFmt = ToD3D9Format(plan.replaced->Format());
} else if (plan.scaleFactor > 1 || plan.saveTexture) {
dstFmt = D3DFMT_A8R8G8B8;
} else if (plan.decodeToClut8) {
diff --git a/GPU/Directx9/TextureCacheDX9.h b/GPU/Directx9/TextureCacheDX9.h
index 23c2e0163b..0b41c92a71 100644
--- a/GPU/Directx9/TextureCacheDX9.h
+++ b/GPU/Directx9/TextureCacheDX9.h
@@ -38,13 +38,13 @@ public:
void SetFramebufferManager(FramebufferManagerDX9 *fbManager);
- void ForgetLastTexture() override {
- InvalidateLastTexture();
- }
- void InvalidateLastTexture() override;
+ void ForgetLastTexture() override;
bool GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level, bool *isFramebuffer) override;
+ void DeviceLost() override { draw_ = nullptr; }
+ void DeviceRestore(Draw::DrawContext *draw) override { draw_ = draw; }
+
protected:
void BindTexture(TexCacheEntry *entry) override;
void Unbind() override;
diff --git a/GPU/GLES/DrawEngineGLES.h b/GPU/GLES/DrawEngineGLES.h
index 9352291c29..17f773c0b2 100644
--- a/GPU/GLES/DrawEngineGLES.h
+++ b/GPU/GLES/DrawEngineGLES.h
@@ -76,8 +76,8 @@ public:
fragmentTestCache_ = testCache;
}
- void DeviceLost();
- void DeviceRestore(Draw::DrawContext *draw);
+ void DeviceLost() override;
+ void DeviceRestore(Draw::DrawContext *draw) override;
void ClearTrackedVertexArrays() override {}
diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp
index d88800873e..b226e9a5ce 100644
--- a/GPU/GLES/FramebufferManagerGLES.cpp
+++ b/GPU/GLES/FramebufferManagerGLES.cpp
@@ -15,28 +15,14 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
-#include
-
-#include "Common/Data/Convert/ColorConv.h"
-#include "Common/Profiler/Profiler.h"
-#include "Common/GPU/OpenGL/GLCommon.h"
-#include "Common/GPU/OpenGL/GLDebugLog.h"
-#include "Common/GPU/OpenGL/GLSLProgram.h"
+#include "Common/GPU/OpenGL/GLFeatures.h"
+#include "Common/GPU/OpenGL/GLRenderManager.h"
#include "Common/GPU/thin3d.h"
-#include "Core/MemMap.h"
-#include "Core/Config.h"
-#include "Core/ConfigValues.h"
#include "Core/System.h"
-#include "Core/Reporting.h"
-#include "GPU/ge_constants.h"
-#include "GPU/GPUState.h"
#include "GPU/Common/FramebufferManagerCommon.h"
#include "GPU/Common/PresentationCommon.h"
#include "GPU/Common/TextureDecoder.h"
-#include "GPU/Debugger/Stepping.h"
#include "GPU/GLES/FramebufferManagerGLES.h"
-#include "GPU/GLES/TextureCacheGLES.h"
-#include "GPU/GLES/ShaderManagerGLES.h"
FramebufferManagerGLES::FramebufferManagerGLES(Draw::DrawContext *draw) :
FramebufferManagerCommon(draw)
diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h
index bdfaa27e8d..1cbe825d60 100644
--- a/GPU/GLES/FramebufferManagerGLES.h
+++ b/GPU/GLES/FramebufferManagerGLES.h
@@ -18,13 +18,8 @@
#pragma once
#include "Common/GPU/thin3d.h"
-#include "GPU/GPUCommon.h"
#include "GPU/Common/FramebufferManagerCommon.h"
-
-class TextureCacheGLES;
-class DrawEngineGLES;
-class ShaderManagerGLES;
-class GLRProgram;
+#include "GPU/Common/GPUDebugInterface.h"
class FramebufferManagerGLES : public FramebufferManagerCommon {
public:
diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp
index 3646fc802c..20ac03129b 100644
--- a/GPU/GLES/GPU_GLES.cpp
+++ b/GPU/GLES/GPU_GLES.cpp
@@ -48,7 +48,7 @@
#endif
GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
- : GPUCommon(gfxCtx, draw), drawEngine_(draw), fragmentTestCache_(draw) {
+ : GPUCommonHW(gfxCtx, draw), drawEngine_(draw), fragmentTestCache_(draw) {
UpdateVsyncInterval(true);
gstate_c.SetUseFlags(CheckGPUFeatures());
@@ -138,25 +138,14 @@ GPU_GLES::~GPU_GLES() {
INFO_LOG(G3D, "Shader cache disabled. Not saving.");
}
}
-
- framebufferManagerGL_->DestroyAllFBOs();
- shaderManagerGL_->ClearCache(true);
fragmentTestCache_.Clear();
-
- delete shaderManagerGL_;
- shaderManagerGL_ = nullptr;
- delete framebufferManagerGL_;
- delete textureCacheGL_;
-
- // Clear features so they're not visible in system info.
- gstate_c.SetUseFlags(0);
}
// Take the raw GL extension and versioning data and turn into feature flags.
// TODO: This should use DrawContext::GetDeviceCaps() more and more, and eventually
// this can be shared between all the backends.
u32 GPU_GLES::CheckGPUFeatures() const {
- u32 features = GPUCommon::CheckGPUFeatures();
+ u32 features = GPUCommonHW::CheckGPUFeatures();
features |= GPU_USE_16BIT_FORMATS;
@@ -249,42 +238,27 @@ void GPU_GLES::DeviceLost() {
// FBOs appear to survive? Or no?
// TransformDraw has registered as a GfxResourceHolder.
CancelReady();
- shaderManagerGL_->DeviceLost();
- textureCacheGL_->DeviceLost();
fragmentTestCache_.DeviceLost();
- drawEngine_.DeviceLost();
- GPUCommon::DeviceLost();
+ GPUCommonHW::DeviceLost();
}
-void GPU_GLES::DeviceRestore() {
- GPUCommon::DeviceRestore();
+void GPU_GLES::DeviceRestore(Draw::DrawContext *draw) {
+ GPUCommonHW::DeviceRestore(draw);
- UpdateCmdInfo();
- UpdateVsyncInterval(true);
-
- shaderManagerGL_->DeviceRestore(draw_);
- textureCacheGL_->DeviceRestore(draw_);
- drawEngine_.DeviceRestore(draw_);
fragmentTestCache_.DeviceRestore(draw_);
-}
-
-void GPU_GLES::Reinitialize() {
- GPUCommon::Reinitialize();
-}
-
-void GPU_GLES::InitClear() {
+ UpdateVsyncInterval(true);
}
void GPU_GLES::BeginHostFrame() {
- GPUCommon::BeginHostFrame();
+ GPUCommonHW::BeginHostFrame();
drawEngine_.BeginFrame();
if (gstate_c.useFlagsChanged) {
// TODO: It'd be better to recompile them in the background, probably?
// This most likely means that saw equal depth changed.
WARN_LOG(G3D, "Shader use flags changed, clearing all shaders and depth buffers");
- shaderManagerGL_->ClearCache(true);
+ shaderManager_->ClearShaders();
framebufferManager_->ClearAllDepthBuffers();
gstate_c.useFlagsChanged = false;
}
@@ -294,39 +268,23 @@ void GPU_GLES::EndHostFrame() {
drawEngine_.EndFrame();
}
-void GPU_GLES::ReapplyGfxState() {
- GPUCommon::ReapplyGfxState();
-}
-
void GPU_GLES::BeginFrame() {
- textureCacheGL_->StartFrame();
- fragmentTestCache_.Decimate();
+ GPUCommonHW::BeginFrame();
- GPUCommon::BeginFrame();
+ textureCache_->StartFrame();
// Save the cache from time to time. TODO: How often? We save on exit, so shouldn't need to do this all that often.
if (shaderCachePath_.Valid() && (gpuStats.numFlips & 4095) == 0) {
shaderManagerGL_->SaveCache(shaderCachePath_, &drawEngine_);
}
-
shaderManagerGL_->DirtyShader();
// Not sure if this is really needed.
gstate_c.Dirty(DIRTY_ALL_UNIFORMS);
- framebufferManagerGL_->BeginFrame();
-}
+ framebufferManager_->BeginFrame();
-void GPU_GLES::CopyDisplayToOutput(bool reallyDirty) {
- // Flush anything left over.
- framebufferManagerGL_->RebindFramebuffer("RebindFramebuffer - CopyDisplayToOutput");
- drawEngine_.Flush();
-
- shaderManagerGL_->DirtyLastShader();
-
- framebufferManagerGL_->CopyDisplayToOutput(reallyDirty);
-
- gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
+ fragmentTestCache_.Decimate();
}
void GPU_GLES::FinishDeferred() {
@@ -334,33 +292,6 @@ void GPU_GLES::FinishDeferred() {
drawEngine_.FinishDeferred();
}
-inline void GPU_GLES::CheckFlushOp(int cmd, u32 diff) {
- const u8 cmdFlags = cmdInfo_[cmd].flags;
- if (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)) {
- if (dumpThisFrame_) {
- NOTICE_LOG(G3D, "================ FLUSH ================");
- }
- drawEngine_.Flush();
- }
-}
-
-void GPU_GLES::PreExecuteOp(u32 op, u32 diff) {
- CheckFlushOp(op >> 24, diff);
-}
-
-void GPU_GLES::ExecuteOp(u32 op, u32 diff) {
- const u8 cmd = op >> 24;
- const CommandInfo info = cmdInfo_[cmd];
- const u8 cmdFlags = info.flags;
- if ((cmdFlags & FLAG_EXECUTE) || (diff && (cmdFlags & FLAG_EXECUTEONCHANGE))) {
- (this->*info.func)(op, diff);
- } else if (diff) {
- uint64_t dirty = info.flags >> 8;
- if (dirty)
- gstate_c.Dirty(dirty);
- }
-}
-
void GPU_GLES::GetStats(char *buffer, size_t bufsize) {
size_t offset = FormatGPUStatsCommon(buffer, bufsize);
buffer += offset;
@@ -374,40 +305,3 @@ void GPU_GLES::GetStats(char *buffer, size_t bufsize) {
shaderManagerGL_->GetNumPrograms()
);
}
-
-void GPU_GLES::DoState(PointerWrap &p) {
- GPUCommon::DoState(p);
-
- // TODO: Some of these things may not be necessary.
- // None of these are necessary when saving.
- // In Freeze-Frame mode, we don't want to do any of this.
- if (p.mode == p.MODE_READ && !PSP_CoreParameter().frozen) {
- textureCache_->Clear(true);
- drawEngine_.ClearTrackedVertexArrays();
-
- gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
- framebufferManager_->DestroyAllFBOs();
- }
-}
-
-std::vector GPU_GLES::DebugGetShaderIDs(DebugShaderType type) {
- switch (type) {
- case SHADER_TYPE_VERTEXLOADER:
- return drawEngine_.DebugGetVertexLoaderIDs();
- case SHADER_TYPE_TEXTURE:
- return textureCache_->GetTextureShaderCache()->DebugGetShaderIDs(type);
- default:
- return shaderManagerGL_->DebugGetShaderIDs(type);
- }
-}
-
-std::string GPU_GLES::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {
- switch (type) {
- case SHADER_TYPE_VERTEXLOADER:
- return drawEngine_.DebugGetVertexLoaderString(id, stringType);
- case SHADER_TYPE_TEXTURE:
- return textureCache_->GetTextureShaderCache()->DebugGetShaderString(id, type, stringType);
- default:
- return shaderManagerGL_->DebugGetShaderString(id, type, stringType);
- }
-}
diff --git a/GPU/GLES/GPU_GLES.h b/GPU/GLES/GPU_GLES.h
index ce2b363149..9e03285ee9 100644
--- a/GPU/GLES/GPU_GLES.h
+++ b/GPU/GLES/GPU_GLES.h
@@ -22,7 +22,7 @@
#include "Common/File/Path.h"
-#include "GPU/GPUCommon.h"
+#include "GPU/GPUCommonHW.h"
#include "GPU/Common/TextureShaderCommon.h"
#include "GPU/GLES/FramebufferManagerGLES.h"
#include "GPU/GLES/DrawEngineGLES.h"
@@ -32,7 +32,7 @@ class ShaderManagerGLES;
class TextureCacheGLES;
class LinkedShader;
-class GPU_GLES : public GPUCommon {
+class GPU_GLES : public GPUCommonHW {
public:
GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw);
~GPU_GLES();
@@ -43,20 +43,10 @@ public:
bool IsReady() override;
void CancelReady() override;
- void PreExecuteOp(u32 op, u32 diff) override;
- void ExecuteOp(u32 op, u32 diff) override;
-
- void ReapplyGfxState() override;
void GetStats(char *buffer, size_t bufsize) override;
void DeviceLost() override; // Only happens on Android. Drop all textures and shaders.
- void DeviceRestore() override;
-
- void DoState(PointerWrap &p) override;
-
- // Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend.
- std::vector DebugGetShaderIDs(DebugShaderType shader) override;
- std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override;
+ void DeviceRestore(Draw::DrawContext *draw) override;
void BeginHostFrame() override;
void EndHostFrame() override;
@@ -65,13 +55,9 @@ protected:
void FinishDeferred() override;
private:
- void CheckFlushOp(int cmd, u32 diff);
void BuildReportingInfo() override;
- void InitClear() override;
void BeginFrame() override;
- void CopyDisplayToOutput(bool reallyDirty) override;
- void Reinitialize() override;
FramebufferManagerGLES *framebufferManagerGL_;
TextureCacheGLES *textureCacheGL_;
diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp
index 9df5b7f28d..8007b31f46 100644
--- a/GPU/GLES/ShaderManagerGLES.cpp
+++ b/GPU/GLES/ShaderManagerGLES.cpp
@@ -443,7 +443,7 @@ void LinkedShader::UpdateUniforms(const ShaderID &vsid, bool useBufferedRenderin
ScaleProjMatrix(flippedMatrix, useBufferedRendering);
render_->SetUniformM4x4(&u_proj, flippedMatrix.m);
- render_->SetUniformF1(&u_rotation, useBufferedRendering ? 0 : (float)g_display_rotation);
+ render_->SetUniformF1(&u_rotation, useBufferedRendering ? 0 : (float)g_display.rotation);
}
if (dirty & DIRTY_PROJTHROUGHMATRIX) {
Matrix4x4 proj_through;
@@ -589,6 +589,7 @@ void LinkedShader::UpdateUniforms(const ShaderID &vsid, bool useBufferedRenderin
// These are just the reverse of the formulas in GPUStateUtils.
float halfActualZRange = gstate_c.vpDepthScale != 0.0f ? vpZScale / gstate_c.vpDepthScale : 0.0f;
+ float inverseDepthScale = gstate_c.vpDepthScale != 0.0f ? 1.0f / gstate_c.vpDepthScale : 0.0f;
float minz = -((gstate_c.vpZOffset * halfActualZRange) - vpZCenter) - halfActualZRange;
float viewZScale = halfActualZRange;
float viewZCenter = minz + halfActualZRange;
@@ -598,7 +599,7 @@ void LinkedShader::UpdateUniforms(const ShaderID &vsid, bool useBufferedRenderin
viewZCenter = vpZCenter;
}
- float data[4] = { viewZScale, viewZCenter, gstate_c.vpZOffset, 1.0f / gstate_c.vpDepthScale };
+ float data[4] = { viewZScale, viewZCenter, gstate_c.vpZOffset, inverseDepthScale };
SetFloatUniform4(render_, &u_depthRange, data);
}
if (dirty & DIRTY_CULLRANGE) {
@@ -715,7 +716,7 @@ void ShaderManagerGLES::Clear() {
DirtyShader();
}
-void ShaderManagerGLES::ClearCache(bool deleteThem) {
+void ShaderManagerGLES::ClearShaders() {
// TODO: Recreate all from the diskcache when we come back.
Clear();
}
diff --git a/GPU/GLES/ShaderManagerGLES.h b/GPU/GLES/ShaderManagerGLES.h
index b37604ba5d..027c7def9f 100644
--- a/GPU/GLES/ShaderManagerGLES.h
+++ b/GPU/GLES/ShaderManagerGLES.h
@@ -165,15 +165,15 @@ public:
ShaderManagerGLES(Draw::DrawContext *draw);
~ShaderManagerGLES();
- void ClearCache(bool deleteThem); // TODO: deleteThem currently not respected
+ void ClearShaders() override;
// This is the old ApplyShader split into two parts, because of annoying information dependencies.
// If you call ApplyVertexShader, you MUST call ApplyFragmentShader soon afterwards.
Shader *ApplyVertexShader(bool useHWTransform, bool useHWTessellation, VertexDecoder *vertexDecoder, bool weightsAsFloat, bool useSkinInDecode, VShaderID *VSID);
LinkedShader *ApplyFragmentShader(VShaderID VSID, Shader *vs, const ComputedPipelineState &pipelineState, bool useBufferedRendering);
- void DeviceLost();
- void DeviceRestore(Draw::DrawContext *draw);
+ void DeviceLost() override;
+ void DeviceRestore(Draw::DrawContext *draw) override;
void DirtyShader();
void DirtyLastShader() override;
@@ -182,8 +182,8 @@ public:
int GetNumFragmentShaders() const { return (int)fsCache_.size(); }
int GetNumPrograms() const { return (int)linkedShaderCache_.size(); }
- std::vector DebugGetShaderIDs(DebugShaderType type);
- std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType);
+ std::vector DebugGetShaderIDs(DebugShaderType type) override;
+ std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) override;
bool LoadCacheFlags(File::IOFile &f, DrawEngineGLES *drawEngine);
bool LoadCache(File::IOFile &f);
diff --git a/GPU/GLES/StencilBufferGLES.cpp b/GPU/GLES/StencilBufferGLES.cpp
index 110d2d94f7..845cd2b3ac 100644
--- a/GPU/GLES/StencilBufferGLES.cpp
+++ b/GPU/GLES/StencilBufferGLES.cpp
@@ -130,10 +130,10 @@ bool FramebufferManagerGLES::ReadbackStencilbuffer(Draw::Framebuffer *fbo, int x
}
shaderManager_->DirtyLastShader();
- auto *blitFBO = GetTempFBO(TempFBO::COPY, fbo->Width(), fbo->Height());
+ auto *blitFBO = GetTempFBO(TempFBO::Z_COPY, fbo->Width(), fbo->Height());
draw_->BindFramebufferAsRenderTarget(blitFBO, { RPAction::DONT_CARE, RPAction::DONT_CARE, RPAction::DONT_CARE }, "ReadbackStencilbufferSync");
Draw::Viewport viewport = { 0.0f, 0.0f, (float)fbo->Width(), (float)fbo->Height(), 0.0f, 1.0f };
- draw_->SetViewports(1, &viewport);
+ draw_->SetViewport(viewport);
draw_->BindFramebufferAsTexture(fbo, TEX_SLOT_PSP_TEXTURE, FB_STENCIL_BIT, 0);
draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, &stencilReadbackSampler_);
diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp
index 36ce7837d9..d44a883bcc 100644
--- a/GPU/GLES/TextureCacheGLES.cpp
+++ b/GPU/GLES/TextureCacheGLES.cpp
@@ -143,10 +143,6 @@ static void ConvertColors(void *dstBuf, const void *srcBuf, Draw::DataFormat dst
void TextureCacheGLES::StartFrame() {
TextureCacheCommon::StartFrame();
- InvalidateLastTexture();
- timesInvalidatedAllThisFrame_ = 0;
- replacementTimeThisFrame_ = 0.0;
-
GLRenderManager *renderManager = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
if (!lowMemoryMode_ && renderManager->SawOutOfMemory()) {
lowMemoryMode_ = true;
@@ -159,17 +155,6 @@ void TextureCacheGLES::StartFrame() {
host->NotifyUserMessage(err->T("Warning: Video memory FULL, switching to slow caching mode"), 2.0f);
}
}
-
- if (texelsScaledThisFrame_) {
- VERBOSE_LOG(G3D, "Scaled %i texels", texelsScaledThisFrame_);
- }
- texelsScaledThisFrame_ = 0;
- if (clearCacheNextFrame_) {
- Clear(true);
- clearCacheNextFrame_ = false;
- } else {
- Decimate();
- }
}
void TextureCacheGLES::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) {
@@ -234,7 +219,7 @@ void TextureCacheGLES::BindTexture(TexCacheEntry *entry) {
void TextureCacheGLES::Unbind() {
render_->BindTexture(TEX_SLOT_PSP_TEXTURE, nullptr);
- InvalidateLastTexture();
+ ForgetLastTexture();
}
void TextureCacheGLES::BindAsClutTexture(Draw::Texture *tex, bool smooth) {
@@ -261,8 +246,9 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry) {
int th = plan.createH;
Draw::DataFormat dstFmt = GetDestFormat(GETextureFormat(entry->format), gstate.getClutPaletteFormat());
- if (plan.replaced->GetSize(plan.baseLevelSrc, tw, th)) {
- dstFmt = plan.replaced->Format(plan.baseLevelSrc);
+ if (plan.replaceValid) {
+ plan.replaced->GetSize(plan.baseLevelSrc, &tw, &th);
+ dstFmt = plan.replaced->Format();
} else if (plan.scaleFactor > 1 || plan.saveTexture) {
dstFmt = Draw::DataFormat::R8G8B8A8_UNORM;
} else if (plan.decodeToClut8) {
@@ -309,7 +295,7 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry) {
int bpp;
if (plan.replaceValid) {
- bpp = (int)Draw::DataFormatSizeInBytes(plan.replaced->Format(srcLevel));
+ bpp = (int)Draw::DataFormatSizeInBytes(plan.replaced->Format());
} else {
if (plan.scaleFactor > 1) {
bpp = 4;
@@ -385,7 +371,7 @@ Draw::DataFormat TextureCacheGLES::GetDestFormat(GETextureFormat format, GEPalet
}
bool TextureCacheGLES::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level, bool *isFramebuffer) {
- InvalidateLastTexture();
+ ForgetLastTexture();
SetTexture();
if (!nextTexture_) {
return GetCurrentFramebufferTextureDebug(buffer, isFramebuffer);
diff --git a/GPU/GLES/TextureCacheGLES.h b/GPU/GLES/TextureCacheGLES.h
index 8f9517371b..6f90475ed1 100644
--- a/GPU/GLES/TextureCacheGLES.h
+++ b/GPU/GLES/TextureCacheGLES.h
@@ -51,14 +51,11 @@ public:
void ForgetLastTexture() override {
lastBoundTexture = nullptr;
}
- void InvalidateLastTexture() override {
- lastBoundTexture = nullptr;
- }
bool GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level, bool *isFramebuffer) override;
- void DeviceLost();
- void DeviceRestore(Draw::DrawContext *draw);
+ void DeviceLost() override;
+ void DeviceRestore(Draw::DrawContext *draw) override;
protected:
void BindTexture(TexCacheEntry *entry) override;
diff --git a/GPU/GPU.h b/GPU/GPU.h
index 12274e51fb..c44749cb63 100644
--- a/GPU/GPU.h
+++ b/GPU/GPU.h
@@ -100,6 +100,8 @@ struct GPUStatistics {
numColorCopies = 0;
numCopiesForShaderBlend = 0;
numCopiesForSelfTex = 0;
+ numReplacerTrackedTex = 0;
+ numCachedReplacedTextures = 0;
msProcessingDisplayLists = 0;
vertexGPUCycles = 0;
otherGPUCycles = 0;
@@ -133,6 +135,8 @@ struct GPUStatistics {
int numColorCopies;
int numCopiesForShaderBlend;
int numCopiesForSelfTex;
+ int numReplacerTrackedTex;
+ int numCachedReplacedTextures;
double msProcessingDisplayLists;
int vertexGPUCycles;
int otherGPUCycles;
diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj
index 625bfb112c..3b6f07c66f 100644
--- a/GPU/GPU.vcxproj
+++ b/GPU/GPU.vcxproj
@@ -164,7 +164,7 @@
Level3
- ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang;../ext/zstd/lib
+ ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang;../ext/zstd/lib;../ext/libpng17
_CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_32=1;_M_IX86=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions)
StreamingSIMDExtensions2
Precise
@@ -182,7 +182,7 @@
Level3
- ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang;../ext/zstd/lib
+ ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang;../ext/zstd/lib;../ext/libpng17
NotSet
Precise
false
@@ -202,7 +202,7 @@
Level3
- ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang;../ext/zstd/lib
+ ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang;../ext/zstd/lib;../ext/libpng17
NotSet
Precise
false
@@ -221,7 +221,7 @@
Level3
- ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang;../ext/zstd/lib
+ ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang;../ext/zstd/lib;../ext/libpng17
NotSet
Precise
false
@@ -244,7 +244,7 @@
MaxSpeed
true
true
- ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang;../ext/zstd/lib
+ ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang;../ext/zstd/lib;../ext/libpng17
false
StreamingSIMDExtensions2
Precise
@@ -267,7 +267,7 @@
MaxSpeed
true
true
- ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang;../ext/zstd/lib
+ ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang;../ext/zstd/lib;../ext/libpng17
false
NotSet
Precise
@@ -292,7 +292,7 @@
MaxSpeed
true
true
- ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang;../ext/zstd/lib
+ ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang;../ext/zstd/lib;../ext/libpng17
false
NotSet
Precise
@@ -317,7 +317,7 @@
MaxSpeed
true
true
- ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang;../ext/zstd/lib
+ ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/glew;../ext/snappy;../ext/glslang;../ext/zstd/lib;../ext/libpng17
false
NotSet
Precise
@@ -338,6 +338,8 @@
+
+
@@ -427,6 +429,7 @@
+
@@ -455,6 +458,8 @@
+
+
@@ -572,6 +577,7 @@
+
diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters
index e30366acb3..6b35f8f33a 100644
--- a/GPU/GPU.vcxproj.filters
+++ b/GPU/GPU.vcxproj.filters
@@ -264,6 +264,15 @@
Common
+
+ Common
+
+
+ Common
+
+
+ Common
+
@@ -524,6 +533,15 @@
Common
+
+ Common
+
+
+ Common
+
+
+ Common
+
diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp
index 836af1236d..802219472c 100644
--- a/GPU/GPUCommon.cpp
+++ b/GPU/GPUCommon.cpp
@@ -12,12 +12,9 @@
#endif
#include
-#include
-#include
#include "Common/Profiler/Profiler.h"
-#include "Common/Data/Convert/ColorConv.h"
#include "Common/GraphicsContext.h"
#include "Common/LogReporting.h"
#include "Common/Serialize/Serializer.h"
@@ -40,341 +37,14 @@
#include "Core/HLE/sceKernelThread.h"
#include "Core/HLE/sceGe.h"
#include "Core/HW/Display.h"
-#include "Core/MemMapHelpers.h"
#include "Core/Util/PPGeDraw.h"
+#include "Core/MemMapHelpers.h"
#include "GPU/Common/DrawEngineCommon.h"
#include "GPU/Common/FramebufferManagerCommon.h"
-#include "GPU/Common/SplineCommon.h"
#include "GPU/Common/TextureCacheCommon.h"
#include "GPU/Debugger/Debugger.h"
#include "GPU/Debugger/Record.h"
-const CommonCommandTableEntry commonCommandTable[] = {
- // From Common. No flushing but definitely need execute.
- { GE_CMD_OFFSETADDR, FLAG_EXECUTE, 0, &GPUCommon::Execute_OffsetAddr },
- { GE_CMD_ORIGIN, FLAG_EXECUTE | FLAG_READS_PC, 0, &GPUCommon::Execute_Origin },
- { GE_CMD_JUMP, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_Jump },
- { GE_CMD_CALL, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_Call },
- { GE_CMD_RET, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_Ret },
- { GE_CMD_END, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_End },
- { GE_CMD_VADDR, FLAG_EXECUTE, 0, &GPUCommon::Execute_Vaddr },
- { GE_CMD_IADDR, FLAG_EXECUTE, 0, &GPUCommon::Execute_Iaddr },
- { GE_CMD_BJUMP, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_BJump }, // EXECUTE
- { GE_CMD_BOUNDINGBOX, FLAG_EXECUTE, 0, &GPUCommon::Execute_BoundingBox }, // Shouldn't need to FLUSHBEFORE.
-
- { GE_CMD_PRIM, FLAG_EXECUTE, 0, &GPUCommon::Execute_Prim },
- { GE_CMD_BEZIER, FLAG_EXECUTE, 0, &GPUCommon::Execute_Bezier },
- { GE_CMD_SPLINE, FLAG_EXECUTE, 0, &GPUCommon::Execute_Spline },
-
- // Changing the vertex type requires us to flush.
- { GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_VertexType },
-
- { GE_CMD_LOADCLUT, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPUCommon::Execute_LoadClut },
-
- // These two are actually processed in CMD_END.
- { GE_CMD_SIGNAL },
- { GE_CMD_FINISH },
-
- // Changes that dirty the framebuffer
- { GE_CMD_FRAMEBUFPTR, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS },
- { GE_CMD_FRAMEBUFWIDTH, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE },
- { GE_CMD_FRAMEBUFPIXFORMAT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_FRAGMENTSHADER_STATE },
- { GE_CMD_ZBUFPTR, FLAG_FLUSHBEFOREONCHANGE },
- { GE_CMD_ZBUFWIDTH, FLAG_FLUSHBEFOREONCHANGE },
-
- { GE_CMD_FOGCOLOR, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FOGCOLOR },
- { GE_CMD_FOG1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FOGCOEFENABLE },
- { GE_CMD_FOG2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FOGCOEFENABLE },
-
- // These affect the fragment shader so need flushing.
- { GE_CMD_CLEARMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE },
- { GE_CMD_TEXTUREMAPENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE },
- { GE_CMD_FOGENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FOGCOEFENABLE },
- { GE_CMD_TEXMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS | DIRTY_FRAGMENTSHADER_STATE },
- { GE_CMD_TEXSHADELS, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
- // Raster state for Direct3D 9, uncommon.
- { GE_CMD_SHADEMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_RASTER_STATE },
- { GE_CMD_TEXFUNC, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAGMENTSHADER_STATE | DIRTY_TEX_ALPHA_MUL },
- { GE_CMD_COLORTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAGMENTSHADER_STATE },
- { GE_CMD_ALPHATESTENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAGMENTSHADER_STATE },
- { GE_CMD_COLORTESTENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAGMENTSHADER_STATE },
- { GE_CMD_COLORTESTMASK, FLAG_FLUSHBEFOREONCHANGE, DIRTY_ALPHACOLORMASK | DIRTY_FRAGMENTSHADER_STATE },
-
- // These change the vertex shader so need flushing.
- { GE_CMD_REVERSENORMAL, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
- { GE_CMD_LIGHTINGENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE },
- { GE_CMD_LIGHTENABLE0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
- { GE_CMD_LIGHTENABLE1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
- { GE_CMD_LIGHTENABLE2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
- { GE_CMD_LIGHTENABLE3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
- { GE_CMD_LIGHTTYPE0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_LIGHT0 },
- { GE_CMD_LIGHTTYPE1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_LIGHT1 },
- { GE_CMD_LIGHTTYPE2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_LIGHT2 },
- { GE_CMD_LIGHTTYPE3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_LIGHT3 },
- { GE_CMD_MATERIALUPDATE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
-
- // These change vertex shaders (in non uber shader mode) so need flushing.
- { GE_CMD_LIGHTMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
-
- { GE_CMD_TEXFILTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXWRAP, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS | DIRTY_FRAGMENTSHADER_STATE },
-
- // Uniform changes. though the fragmentshader optimizes based on these sometimes.
- { GE_CMD_ALPHATEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_ALPHACOLORREF | DIRTY_ALPHACOLORMASK | DIRTY_FRAGMENTSHADER_STATE },
- { GE_CMD_COLORREF, FLAG_FLUSHBEFOREONCHANGE, DIRTY_ALPHACOLORREF | DIRTY_FRAGMENTSHADER_STATE },
- { GE_CMD_TEXENVCOLOR, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXENV },
-
- // Simple render state changes. Handled in StateMapping.cpp.
- { GE_CMD_CULL, FLAG_FLUSHBEFOREONCHANGE, DIRTY_RASTER_STATE },
- { GE_CMD_CULLFACEENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_RASTER_STATE },
- { GE_CMD_DITHERENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_RASTER_STATE },
- { GE_CMD_STENCILOP, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_FRAGMENTSHADER_STATE },
- { GE_CMD_STENCILTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_STENCILREPLACEVALUE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE },
- { GE_CMD_STENCILTESTENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_FRAGMENTSHADER_STATE },
- { GE_CMD_ALPHABLENDENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE },
- { GE_CMD_BLENDMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE },
- { GE_CMD_BLENDFIXEDA, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE },
- { GE_CMD_BLENDFIXEDB, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE },
- { GE_CMD_MASKRGB, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_COLORWRITEMASK },
- { GE_CMD_MASKALPHA, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_COLORWRITEMASK },
- { GE_CMD_ZTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHSTENCIL_STATE },
- { GE_CMD_ZTESTENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHSTENCIL_STATE | DIRTY_FRAGMENTSHADER_STATE },
- { GE_CMD_ZWRITEDISABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHSTENCIL_STATE | DIRTY_FRAGMENTSHADER_STATE },
- { GE_CMD_LOGICOP, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE },
- { GE_CMD_LOGICOPENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE },
-
- { GE_CMD_TEXMAPMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE },
-
- // These are read on every SubmitPrim, no need for dirtying or flushing.
- { GE_CMD_TEXSCALEU },
- { GE_CMD_TEXSCALEV },
- { GE_CMD_TEXOFFSETU },
- { GE_CMD_TEXOFFSETV },
-
- { GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPUCommon::Execute_TexSize0 },
- { GE_CMD_TEXSIZE1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXSIZE2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXSIZE3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXSIZE4, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXSIZE5, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXSIZE6, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXSIZE7, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXFORMAT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE },
- { GE_CMD_TEXLEVEL, FLAG_EXECUTEONCHANGE, DIRTY_TEXTURE_PARAMS, &GPUCommon::Execute_TexLevel },
- { GE_CMD_TEXLODSLOPE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXADDR0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE | DIRTY_UVSCALEOFFSET },
- { GE_CMD_TEXADDR1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXADDR2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXADDR3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXADDR4, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXADDR5, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXADDR6, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXADDR7, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXBUFWIDTH0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE },
- { GE_CMD_TEXBUFWIDTH1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXBUFWIDTH2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXBUFWIDTH3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXBUFWIDTH4, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXBUFWIDTH5, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXBUFWIDTH6, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
- { GE_CMD_TEXBUFWIDTH7, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
-
- // These must flush on change, so that LoadClut doesn't have to always flush.
- { GE_CMD_CLUTADDR, FLAG_FLUSHBEFOREONCHANGE },
- { GE_CMD_CLUTADDRUPPER, FLAG_FLUSHBEFOREONCHANGE },
- { GE_CMD_CLUTFORMAT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS | DIRTY_DEPAL },
-
- // Morph weights. TODO: Remove precomputation?
- { GE_CMD_MORPHWEIGHT0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight },
- { GE_CMD_MORPHWEIGHT1, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight },
- { GE_CMD_MORPHWEIGHT2, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight },
- { GE_CMD_MORPHWEIGHT3, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight },
- { GE_CMD_MORPHWEIGHT4, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight },
- { GE_CMD_MORPHWEIGHT5, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight },
- { GE_CMD_MORPHWEIGHT6, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight },
- { GE_CMD_MORPHWEIGHT7, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight },
-
- // Control spline/bezier patches. Don't really require flushing as such, but meh.
- { GE_CMD_PATCHDIVISION, FLAG_FLUSHBEFOREONCHANGE },
- { GE_CMD_PATCHPRIMITIVE, FLAG_FLUSHBEFOREONCHANGE },
- { GE_CMD_PATCHFACING, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
- { GE_CMD_PATCHCULLENABLE, FLAG_FLUSHBEFOREONCHANGE },
-
- // Can probably ignore this one as we don't support AA lines.
- { GE_CMD_ANTIALIASENABLE, FLAG_FLUSHBEFOREONCHANGE },
-
- // Viewport.
- { GE_CMD_OFFSETX, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE },
- { GE_CMD_OFFSETY, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE },
- { GE_CMD_VIEWPORTXSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE },
- { GE_CMD_VIEWPORTYSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE },
- { GE_CMD_VIEWPORTXCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE },
- { GE_CMD_VIEWPORTYCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE },
- { GE_CMD_VIEWPORTZSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_DEPTHRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE },
- { GE_CMD_VIEWPORTZCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_DEPTHRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE },
- { GE_CMD_DEPTHCLAMPENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE | DIRTY_RASTER_STATE },
-
- // Z clip
- { GE_CMD_MINZ, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHRANGE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE },
- { GE_CMD_MAXZ, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHRANGE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE },
-
- // Region
- { GE_CMD_REGION1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE },
- { GE_CMD_REGION2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE },
-
- // Scissor
- { GE_CMD_SCISSOR1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE },
- { GE_CMD_SCISSOR2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE },
-
- // Lighting base colors
- { GE_CMD_AMBIENTCOLOR, FLAG_FLUSHBEFOREONCHANGE, DIRTY_AMBIENT },
- { GE_CMD_AMBIENTALPHA, FLAG_FLUSHBEFOREONCHANGE, DIRTY_AMBIENT },
- { GE_CMD_MATERIALDIFFUSE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_MATDIFFUSE },
- { GE_CMD_MATERIALEMISSIVE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_MATEMISSIVE },
- { GE_CMD_MATERIALAMBIENT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_MATAMBIENTALPHA },
- { GE_CMD_MATERIALALPHA, FLAG_FLUSHBEFOREONCHANGE, DIRTY_MATAMBIENTALPHA },
- { GE_CMD_MATERIALSPECULAR, FLAG_FLUSHBEFOREONCHANGE, DIRTY_MATSPECULAR },
- { GE_CMD_MATERIALSPECULARCOEF, FLAG_FLUSHBEFOREONCHANGE, DIRTY_MATSPECULAR },
-
- // Light parameters
- { GE_CMD_LX0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
- { GE_CMD_LY0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
- { GE_CMD_LZ0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
- { GE_CMD_LX1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
- { GE_CMD_LY1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
- { GE_CMD_LZ1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
- { GE_CMD_LX2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
- { GE_CMD_LY2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
- { GE_CMD_LZ2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
- { GE_CMD_LX3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
- { GE_CMD_LY3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
- { GE_CMD_LZ3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
-
- { GE_CMD_LDX0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
- { GE_CMD_LDY0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
- { GE_CMD_LDZ0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
- { GE_CMD_LDX1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
- { GE_CMD_LDY1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
- { GE_CMD_LDZ1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
- { GE_CMD_LDX2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
- { GE_CMD_LDY2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
- { GE_CMD_LDZ2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
- { GE_CMD_LDX3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
- { GE_CMD_LDY3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
- { GE_CMD_LDZ3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
-
- { GE_CMD_LKA0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
- { GE_CMD_LKB0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
- { GE_CMD_LKC0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
- { GE_CMD_LKA1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
- { GE_CMD_LKB1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
- { GE_CMD_LKC1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
- { GE_CMD_LKA2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
- { GE_CMD_LKB2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
- { GE_CMD_LKC2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
- { GE_CMD_LKA3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
- { GE_CMD_LKB3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
- { GE_CMD_LKC3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
-
- { GE_CMD_LKS0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
- { GE_CMD_LKS1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
- { GE_CMD_LKS2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
- { GE_CMD_LKS3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
-
- { GE_CMD_LKO0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
- { GE_CMD_LKO1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
- { GE_CMD_LKO2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
- { GE_CMD_LKO3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
-
- { GE_CMD_LAC0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
- { GE_CMD_LDC0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
- { GE_CMD_LSC0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
- { GE_CMD_LAC1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
- { GE_CMD_LDC1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
- { GE_CMD_LSC1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
- { GE_CMD_LAC2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
- { GE_CMD_LDC2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
- { GE_CMD_LSC2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
- { GE_CMD_LAC3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
- { GE_CMD_LDC3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
- { GE_CMD_LSC3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
-
- // Ignored commands
- { GE_CMD_TEXFLUSH, 0 },
- { GE_CMD_TEXSYNC, 0 },
-
- // These are just nop or part of other later commands.
- { GE_CMD_NOP, 0 },
- { GE_CMD_BASE, 0 },
- { GE_CMD_TRANSFERSRC, 0 },
- { GE_CMD_TRANSFERSRCW, 0 },
- { GE_CMD_TRANSFERDST, 0 },
- { GE_CMD_TRANSFERDSTW, 0 },
- { GE_CMD_TRANSFERSRCPOS, 0 },
- { GE_CMD_TRANSFERDSTPOS, 0 },
- { GE_CMD_TRANSFERSIZE, 0 },
- { GE_CMD_TRANSFERSTART, FLAG_EXECUTE | FLAG_READS_PC, 0, &GPUCommon::Execute_BlockTransferStart },
-
- // We don't use the dither table.
- { GE_CMD_DITH0 },
- { GE_CMD_DITH1 },
- { GE_CMD_DITH2 },
- { GE_CMD_DITH3 },
-
- // These handle their own flushing.
- { GE_CMD_WORLDMATRIXNUMBER, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_WorldMtxNum },
- { GE_CMD_WORLDMATRIXDATA, FLAG_EXECUTE, 0, &GPUCommon::Execute_WorldMtxData },
- { GE_CMD_VIEWMATRIXNUMBER, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_ViewMtxNum },
- { GE_CMD_VIEWMATRIXDATA, FLAG_EXECUTE, 0, &GPUCommon::Execute_ViewMtxData },
- { GE_CMD_PROJMATRIXNUMBER, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_ProjMtxNum },
- { GE_CMD_PROJMATRIXDATA, FLAG_EXECUTE, 0, &GPUCommon::Execute_ProjMtxData },
- { GE_CMD_TGENMATRIXNUMBER, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_TgenMtxNum },
- { GE_CMD_TGENMATRIXDATA, FLAG_EXECUTE, 0, &GPUCommon::Execute_TgenMtxData },
- { GE_CMD_BONEMATRIXNUMBER, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_BoneMtxNum },
- { GE_CMD_BONEMATRIXDATA, FLAG_EXECUTE, 0, &GPUCommon::Execute_BoneMtxData },
-
- // Vertex Screen/Texture/Color
- { GE_CMD_VSCX },
- { GE_CMD_VSCY },
- { GE_CMD_VSCZ },
- { GE_CMD_VTCS },
- { GE_CMD_VTCT },
- { GE_CMD_VTCQ },
- { GE_CMD_VCV },
- { GE_CMD_VAP, FLAG_EXECUTE, 0, &GPUCommon::Execute_ImmVertexAlphaPrim },
- { GE_CMD_VFC },
- { GE_CMD_VSCV },
-
- // "Missing" commands (gaps in the sequence)
- { GE_CMD_UNKNOWN_03, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_0D, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_11, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_29, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_34, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_35, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_39, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_4E, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_4F, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_52, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_59, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_5A, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_B6, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_B7, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_D1, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_ED, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_EF, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_FA, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_FB, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_FC, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_FD, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- { GE_CMD_UNKNOWN_FE, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
- // Appears to be debugging related or something? Hit a lot in GoW.
- { GE_CMD_NOP_FF, 0 },
-};
-
-// TODO: Make class member?
-GPUCommon::CommandInfo GPUCommon::cmdInfo_[256];
-
void GPUCommon::Flush() {
drawEngineCommon_->DispatchFlush();
}
@@ -398,86 +68,9 @@ GPUCommon::GPUCommon(GraphicsContext *gfxCtx, Draw::DrawContext *draw) :
gstate_c.Reset();
gpuStats.Reset();
- memset(cmdInfo_, 0, sizeof(cmdInfo_));
-
- // Convert the command table to a faster format, and check for dupes.
- std::set dupeCheck;
- for (size_t i = 0; i < ARRAY_SIZE(commonCommandTable); i++) {
- const u8 cmd = commonCommandTable[i].cmd;
- if (dupeCheck.find(cmd) != dupeCheck.end()) {
- ERROR_LOG(G3D, "Command table Dupe: %02x (%i)", (int)cmd, (int)cmd);
- } else {
- dupeCheck.insert(cmd);
- }
- cmdInfo_[cmd].flags |= (uint64_t)commonCommandTable[i].flags | (commonCommandTable[i].dirty << 8);
- cmdInfo_[cmd].func = commonCommandTable[i].func;
- if ((cmdInfo_[cmd].flags & (FLAG_EXECUTE | FLAG_EXECUTEONCHANGE)) && !cmdInfo_[cmd].func) {
- // Can't have FLAG_EXECUTE commands without a function pointer to execute.
- Crash();
- }
- }
- // Find commands missing from the table.
- for (int i = 0; i < 0xEF; i++) {
- if (dupeCheck.find((u8)i) == dupeCheck.end()) {
- ERROR_LOG(G3D, "Command missing from table: %02x (%i)", i, i);
- }
- }
-
- UpdateCmdInfo();
UpdateVsyncInterval(true);
- ResetMatrices();
-
PPGeSetDrawContext(draw);
-
- UpdateMSAALevel(draw);
-}
-
-GPUCommon::~GPUCommon() {
- // Probably not necessary.
- PPGeSetDrawContext(nullptr);
-}
-
-void GPUCommon::UpdateCmdInfo() {
- if (g_Config.bSoftwareSkinning) {
- cmdInfo_[GE_CMD_VERTEXTYPE].flags &= ~FLAG_FLUSHBEFOREONCHANGE;
- cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommon::Execute_VertexTypeSkinning;
- } else {
- cmdInfo_[GE_CMD_VERTEXTYPE].flags |= FLAG_FLUSHBEFOREONCHANGE;
- cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommon::Execute_VertexType;
- }
-
- if (g_Config.bFastMemory) {
- cmdInfo_[GE_CMD_JUMP].func = &GPUCommon::Execute_JumpFast;
- cmdInfo_[GE_CMD_CALL].func = &GPUCommon::Execute_CallFast;
- } else {
- cmdInfo_[GE_CMD_JUMP].func = &GPUCommon::Execute_Jump;
- cmdInfo_[GE_CMD_CALL].func = &GPUCommon::Execute_Call;
- }
-
- // Reconfigure for light ubershader or not.
- for (int i = 0; i < 4; i++) {
- if (gstate_c.Use(GPU_USE_LIGHT_UBERSHADER)) {
- cmdInfo_[GE_CMD_LIGHTENABLE0 + i].RemoveDirty(DIRTY_VERTEXSHADER_STATE);
- cmdInfo_[GE_CMD_LIGHTENABLE0 + i].AddDirty(DIRTY_LIGHT_CONTROL);
- cmdInfo_[GE_CMD_LIGHTTYPE0 + i].RemoveDirty(DIRTY_VERTEXSHADER_STATE);
- cmdInfo_[GE_CMD_LIGHTTYPE0 + i].AddDirty(DIRTY_LIGHT_CONTROL);
- } else {
- cmdInfo_[GE_CMD_LIGHTENABLE0 + i].RemoveDirty(DIRTY_LIGHT_CONTROL);
- cmdInfo_[GE_CMD_LIGHTENABLE0 + i].AddDirty(DIRTY_VERTEXSHADER_STATE);
- cmdInfo_[GE_CMD_LIGHTTYPE0 + i].RemoveDirty(DIRTY_LIGHT_CONTROL);
- cmdInfo_[GE_CMD_LIGHTTYPE0 + i].AddDirty(DIRTY_VERTEXSHADER_STATE);
- }
- }
-
- if (gstate_c.Use(GPU_USE_LIGHT_UBERSHADER)) {
- cmdInfo_[GE_CMD_MATERIALUPDATE].RemoveDirty(DIRTY_VERTEXSHADER_STATE);
- cmdInfo_[GE_CMD_MATERIALUPDATE].AddDirty(DIRTY_LIGHT_CONTROL);
- cmdInfo_[GE_CMD_LIGHTMODE].AddDirty(DIRTY_LIGHT_CONTROL);
- } else {
- cmdInfo_[GE_CMD_MATERIALUPDATE].RemoveDirty(DIRTY_LIGHT_CONTROL);
- cmdInfo_[GE_CMD_MATERIALUPDATE].AddDirty(DIRTY_VERTEXSHADER_STATE);
- cmdInfo_[GE_CMD_LIGHTMODE].RemoveDirty(DIRTY_LIGHT_CONTROL);
- }
+ ResetMatrices();
}
void GPUCommon::BeginHostFrame() {
@@ -523,19 +116,6 @@ void GPUCommon::Reinitialize() {
framebufferManager_->DestroyAllFBOs();
}
-// Call at the END of the GPU implementation's DeviceLost
-void GPUCommon::DeviceLost() {
- framebufferManager_->DeviceLost();
- draw_ = nullptr;
-}
-
-// Call at the start of the GPU implementation's DeviceRestore
-void GPUCommon::DeviceRestore() {
- draw_ = (Draw::DrawContext *)PSP_CoreParameter().graphicsContext->GetDrawContext();
- framebufferManager_->DeviceRestore(draw_);
- PPGeSetDrawContext(draw_);
-}
-
void GPUCommon::UpdateVsyncInterval(bool force) {
#if !(PPSSPP_PLATFORM(ANDROID) || defined(USING_QT_UI) || PPSSPP_PLATFORM(UWP) || PPSSPP_PLATFORM(IOS))
int desiredVSyncInterval = g_Config.bVSync ? 1 : 0;
@@ -633,10 +213,6 @@ void GPUCommon::NotifyDisplayResized() {
displayResized_ = true;
}
-void GPUCommon::ClearCacheNextFrame() {
- textureCache_->ClearNextFrame();
-}
-
// Called once per frame. Might also get called during the pause screen
// if "transparent".
void GPUCommon::CheckConfigChanged() {
@@ -663,13 +239,6 @@ void GPUCommon::CheckDisplayResized() {
}
}
-void GPUCommon::CheckRenderResized() {
- if (renderResized_) {
- framebufferManager_->NotifyRenderResized(msaaLevel_);
- renderResized_ = false;
- }
-}
-
void GPUCommon::DumpNextFrame() {
dumpNextFrame_ = true;
}
@@ -796,6 +365,7 @@ int GPUCommon::GetStack(int index, u32 stackPtr) {
}
static void CopyMatrix24(u32_le *result, const float *mtx, u32 count, u32 cmdbits) {
+ // Screams out for simple SIMD, but probably not called often enough to be worth it.
for (u32 i = 0; i < count; ++i) {
result[i] = toFloat24(mtx[i]) | cmdbits;
}
@@ -1200,53 +770,6 @@ bool GPUCommon::InterpretList(DisplayList &list) {
return gpuState == GPUSTATE_DONE || gpuState == GPUSTATE_ERROR;
}
-// Maybe should write this in ASM...
-void GPUCommon::FastRunLoop(DisplayList &list) {
- PROFILE_THIS_SCOPE("gpuloop");
-
- if (!Memory::IsValidAddress(list.pc)) {
- // We're having some serious problems here, just bail and try to limp along and not crash the app.
- downcount = 0;
- return;
- }
-
- const CommandInfo *cmdInfo = cmdInfo_;
- int dc = downcount;
- for (; dc > 0; --dc) {
- // We know that display list PCs have the upper nibble == 0 - no need to mask the pointer
- const u32 op = *(const u32_le *)(Memory::base + list.pc);
- const u32 cmd = op >> 24;
- const CommandInfo &info = cmdInfo[cmd];
- const u32 diff = op ^ gstate.cmdmem[cmd];
- if (diff == 0) {
- if (info.flags & FLAG_EXECUTE) {
- downcount = dc;
- (this->*info.func)(op, diff);
- dc = downcount;
- }
- } else {
- uint64_t flags = info.flags;
- if (flags & FLAG_FLUSHBEFOREONCHANGE) {
- if (drawEngineCommon_->GetNumDrawCalls()) {
- drawEngineCommon_->DispatchFlush();
- }
- }
- gstate.cmdmem[cmd] = op;
- if (flags & (FLAG_EXECUTE | FLAG_EXECUTEONCHANGE)) {
- downcount = dc;
- (this->*info.func)(op, diff);
- dc = downcount;
- } else {
- uint64_t dirty = flags >> 8;
- if (dirty)
- gstate_c.Dirty(dirty);
- }
- }
- list.pc += 4;
- }
- downcount = 0;
-}
-
void GPUCommon::BeginFrame() {
immCount_ = 0;
if (dumpNextFrame_) {
@@ -1258,18 +781,11 @@ void GPUCommon::BeginFrame() {
}
GPUDebug::NotifyBeginFrame();
GPURecord::NotifyBeginFrame();
-
- if (drawEngineCommon_->EverUsedExactEqualDepth() && !sawExactEqualDepth_) {
- sawExactEqualDepth_ = true;
- gstate_c.SetUseFlags(CheckGPUFeatures());
- }
}
-void GPUCommon::SlowRunLoop(DisplayList &list)
-{
+void GPUCommon::SlowRunLoop(DisplayList &list) {
const bool dumpThisFrame = dumpThisFrame_;
- while (downcount > 0)
- {
+ while (downcount > 0) {
bool process = GPUDebug::NotifyCommand(list.pc);
if (process) {
GPURecord::NotifyCommand(list.pc);
@@ -1410,10 +926,6 @@ void GPUCommon::ProcessDLQueue() {
// Since the event is in CoreTiming, we're in sync. Just set 0 now.
}
-void GPUCommon::PreExecuteOp(u32 op, u32 diff) {
- // Nothing to do
-}
-
void GPUCommon::Execute_OffsetAddr(u32 op, u32 diff) {
gstate_c.offsetAddr = op << 8;
}
@@ -1719,513 +1231,6 @@ void GPUCommon::Execute_End(u32 op, u32 diff) {
}
}
-void GPUCommon::Execute_TexLevel(u32 op, u32 diff) {
- // TODO: If you change the rules here, don't forget to update the inner interpreter in Execute_Prim.
- if (diff == 0xFFFFFFFF)
- return;
-
- gstate.texlevel ^= diff;
-
- if (diff & 0xFF0000) {
- // Piggyback on this flag for 3D textures.
- gstate_c.Dirty(DIRTY_MIPBIAS);
- }
- if (gstate.getTexLevelMode() != GE_TEXLEVEL_MODE_AUTO && (0x00FF0000 & gstate.texlevel) != 0) {
- Flush();
- }
-
- gstate.texlevel ^= diff;
-
- gstate_c.Dirty(DIRTY_TEXTURE_PARAMS | DIRTY_FRAGMENTSHADER_STATE);
-}
-
-void GPUCommon::Execute_TexSize0(u32 op, u32 diff) {
- // Render to texture may have overridden the width/height.
- // Don't reset it unless the size is different / the texture has changed.
- if (diff || gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS)) {
- gstate_c.curTextureWidth = gstate.getTextureWidth(0);
- gstate_c.curTextureHeight = gstate.getTextureHeight(0);
- gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
- // We will need to reset the texture now.
- gstate_c.Dirty(DIRTY_TEXTURE_PARAMS);
- }
-}
-
-void GPUCommon::Execute_VertexType(u32 op, u32 diff) {
- if (diff)
- gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
- if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK)) {
- gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
- // Switching between through and non-through, we need to invalidate a bunch of stuff.
- if (diff & GE_VTYPE_THROUGH_MASK)
- gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE | DIRTY_CULLRANGE | DIRTY_FOGCOEFENABLE);
- }
-}
-
-void GPUCommon::Execute_LoadClut(u32 op, u32 diff) {
- gstate_c.Dirty(DIRTY_TEXTURE_PARAMS);
- textureCache_->LoadClut(gstate.getClutAddress(), gstate.getClutLoadBytes());
-}
-
-void GPUCommon::Execute_VertexTypeSkinning(u32 op, u32 diff) {
- // Don't flush when weight count changes.
- if (diff & ~GE_VTYPE_WEIGHTCOUNT_MASK) {
- // Restore and flush
- gstate.vertType ^= diff;
- Flush();
- gstate.vertType ^= diff;
- if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK))
- gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
- // In this case, we may be doing weights and morphs.
- // Update any bone matrix uniforms so it uses them correctly.
- if ((op & GE_VTYPE_MORPHCOUNT_MASK) != 0) {
- gstate_c.Dirty(gstate_c.deferredVertTypeDirty);
- gstate_c.deferredVertTypeDirty = 0;
- }
- gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
- }
- if (diff & GE_VTYPE_THROUGH_MASK)
- gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE | DIRTY_CULLRANGE | DIRTY_FOGCOEFENABLE);
-}
-
-void GPUCommon::CheckDepthUsage(VirtualFramebuffer *vfb) {
- if (!gstate_c.usingDepth) {
- bool isReadingDepth = false;
- bool isClearingDepth = false;
- bool isWritingDepth = false;
- if (gstate.isModeClear()) {
- isClearingDepth = gstate.isClearModeDepthMask();
- isWritingDepth = isClearingDepth;
- } else if (gstate.isDepthTestEnabled()) {
- isWritingDepth = gstate.isDepthWriteEnabled();
- isReadingDepth = gstate.getDepthTestFunction() > GE_COMP_ALWAYS;
- }
-
- if (isWritingDepth || isReadingDepth) {
- gstate_c.usingDepth = true;
- gstate_c.clearingDepth = isClearingDepth;
- vfb->last_frame_depth_render = gpuStats.numFlips;
- if (isWritingDepth) {
- vfb->last_frame_depth_updated = gpuStats.numFlips;
- }
- framebufferManager_->SetDepthFrameBuffer(isClearingDepth);
- }
- }
-}
-
-void GPUCommon::Execute_Prim(u32 op, u32 diff) {
- // This drives all drawing. All other state we just buffer up, then we apply it only
- // when it's time to draw. As most PSP games set state redundantly ALL THE TIME, this is a huge optimization.
-
- PROFILE_THIS_SCOPE("execprim");
-
- u32 data = op & 0xFFFFFF;
- u32 count = data & 0xFFFF;
- if (count == 0)
- return;
- FlushImm();
-
- // Upper bits are ignored.
- GEPrimitiveType prim = static_cast((data >> 16) & 7);
- SetDrawType(DRAW_PRIM, prim);
-
- // Discard AA lines as we can't do anything that makes sense with these anyway. The SW plugin might, though.
- if (gstate.isAntiAliasEnabled()) {
- // Heuristic derived from discussions in #6483 and #12588.
- // Discard AA lines in Persona 3 Portable, DOA Paradise and Summon Night 5, while still keeping AA lines in Echochrome.
- if ((prim == GE_PRIM_LINE_STRIP || prim == GE_PRIM_LINES) && gstate.getTextureFunction() == GE_TEXFUNC_REPLACE)
- return;
- }
-
- // Update cached framebuffer format.
- // We store it in the cache so it can be modified for blue-to-alpha, next.
- gstate_c.framebufFormat = gstate.FrameBufFormat();
-
- if (!Memory::IsValidAddress(gstate_c.vertexAddr)) {
- ERROR_LOG(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr);
- return;
- }
-
- // See the documentation for gstate_c.blueToAlpha.
- bool blueToAlpha = false;
- if (PSP_CoreParameter().compat.flags().BlueToAlpha) {
- if (gstate_c.framebufFormat == GEBufferFormat::GE_FORMAT_565 && gstate.getColorMask() == 0x0FFFFF && !gstate.isLogicOpEnabled()) {
- blueToAlpha = true;
- gstate_c.framebufFormat = GEBufferFormat::GE_FORMAT_4444;
- }
- if (blueToAlpha != gstate_c.blueToAlpha) {
- gstate_c.blueToAlpha = blueToAlpha;
- gstate_c.Dirty(DIRTY_FRAMEBUF | DIRTY_FRAGMENTSHADER_STATE | DIRTY_BLEND_STATE);
- }
- }
-
- if (PSP_CoreParameter().compat.flags().SplitFramebufferMargin) {
- switch (gstate.vertType & 0xFFFFFF) {
- case 0x00800102: // through, u16 uv, u16 pos (used for the framebuffer effect in-game)
- case 0x0080011c: // through, 8888 color, s16 pos (used for clearing in the margin of the title screen)
- case 0x00000183: // float uv, float pos (used for drawing in the margin of the title screen)
- // Need to re-check the framebuffer every one of these draws, to update the split if needed.
- gstate_c.Dirty(DIRTY_FRAMEBUF);
- }
- }
-
- // This also makes skipping drawing very effective.
- VirtualFramebuffer *vfb = framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
- if (blueToAlpha) {
- vfb->usageFlags |= FB_USAGE_BLUE_TO_ALPHA;
- }
-
- // Must check this after SetRenderFrameBuffer so we know SKIPDRAW_NON_DISPLAYED_FB.
- if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
- // Rough estimate, not sure what's correct.
- cyclesExecuted += EstimatePerVertexCost() * count;
- if (gstate.isModeClear()) {
- gpuStats.numClears++;
- }
- return;
- }
-
- CheckDepthUsage(vfb);
-
- const void *verts = Memory::GetPointerUnchecked(gstate_c.vertexAddr);
- const void *inds = nullptr;
- u32 vertexType = gstate.vertType;
- if ((vertexType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
- u32 indexAddr = gstate_c.indexAddr;
- if (!Memory::IsValidAddress(indexAddr)) {
- ERROR_LOG(G3D, "Bad index address %08x!", indexAddr);
- return;
- }
- inds = Memory::GetPointerUnchecked(indexAddr);
- }
-
- if (gstate_c.dirty & DIRTY_VERTEXSHADER_STATE) {
- vertexCost_ = EstimatePerVertexCost();
- }
-
- int bytesRead = 0;
- UpdateUVScaleOffset();
-
- // cull mode
- int cullMode = gstate.getCullMode();
-
- uint32_t vertTypeID = GetVertTypeID(vertexType, gstate.getUVGenMode(), g_Config.bSoftwareSkinning);
- drawEngineCommon_->SubmitPrim(verts, inds, prim, count, vertTypeID, cullMode, &bytesRead);
- // After drawing, we advance the vertexAddr (when non indexed) or indexAddr (when indexed).
- // Some games rely on this, they don't bother reloading VADDR and IADDR.
- // The VADDR/IADDR registers are NOT updated.
- AdvanceVerts(vertexType, count, bytesRead);
- int totalVertCount = count;
-
- // PRIMs are often followed by more PRIMs. Save some work and submit them immediately.
- const u32_le *src = (const u32_le *)Memory::GetPointerUnchecked(currentList->pc + 4);
- const u32_le *stall = currentList->stall ? (const u32_le *)Memory::GetPointerUnchecked(currentList->stall) : 0;
- int cmdCount = 0;
-
- // Optimized submission of sequences of PRIM. Allows us to avoid going through all the mess
- // above for each one. This can be expanded to support additional games that intersperse
- // PRIM commands with other commands. A special case is Earth Defence Force 2 that changes culling mode
- // between each prim, we just change the triangle winding right here to still be able to join draw calls.
-
- uint32_t vtypeCheckMask = ~GE_VTYPE_WEIGHTCOUNT_MASK;
- if (!g_Config.bSoftwareSkinning)
- vtypeCheckMask = 0xFFFFFFFF;
-
- if (debugRecording_)
- goto bail;
-
- while (src != stall) {
- uint32_t data = *src;
- switch (data >> 24) {
- case GE_CMD_PRIM:
- {
- u32 count = data & 0xFFFF;
- if (count == 0) {
- // Ignore.
- break;
- }
-
- GEPrimitiveType newPrim = static_cast((data >> 16) & 7);
- SetDrawType(DRAW_PRIM, newPrim);
- // TODO: more efficient updating of verts/inds
- verts = Memory::GetPointerUnchecked(gstate_c.vertexAddr);
- inds = nullptr;
- if ((vertexType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
- inds = Memory::GetPointerUnchecked(gstate_c.indexAddr);
- }
-
- drawEngineCommon_->SubmitPrim(verts, inds, newPrim, count, vertTypeID, cullMode, &bytesRead);
- AdvanceVerts(vertexType, count, bytesRead);
- totalVertCount += count;
- break;
- }
- case GE_CMD_VERTEXTYPE:
- {
- uint32_t diff = data ^ vertexType;
- // don't mask upper bits, vertexType is unmasked
- if (diff & vtypeCheckMask) {
- goto bail;
- } else {
- vertexType = data;
- vertTypeID = GetVertTypeID(vertexType, gstate.getUVGenMode(), g_Config.bSoftwareSkinning);
- }
- break;
- }
- case GE_CMD_VADDR:
- gstate.cmdmem[GE_CMD_VADDR] = data;
- gstate_c.vertexAddr = gstate_c.getRelativeAddress(data & 0x00FFFFFF);
- break;
- case GE_CMD_IADDR:
- gstate.cmdmem[GE_CMD_IADDR] = data;
- gstate_c.indexAddr = gstate_c.getRelativeAddress(data & 0x00FFFFFF);
- break;
- case GE_CMD_OFFSETADDR:
- gstate.cmdmem[GE_CMD_OFFSETADDR] = data;
- gstate_c.offsetAddr = data << 8;
- break;
- case GE_CMD_BASE:
- gstate.cmdmem[GE_CMD_BASE] = data;
- break;
- case GE_CMD_CULLFACEENABLE:
- // Earth Defence Force 2
- if (gstate.cmdmem[GE_CMD_CULLFACEENABLE] != data) {
- goto bail;
- }
- break;
- case GE_CMD_CULL:
- // flip face by indices for triangles
- cullMode = data & 1;
- break;
- case GE_CMD_TEXFLUSH:
- case GE_CMD_NOP:
- case GE_CMD_NOP_FF:
- gstate.cmdmem[data >> 24] = data;
- break;
- case GE_CMD_BONEMATRIXNUMBER:
- gstate.cmdmem[GE_CMD_BONEMATRIXNUMBER] = data;
- break;
- case GE_CMD_TEXSCALEU:
- gstate.cmdmem[GE_CMD_TEXSCALEU] = data;
- gstate_c.uv.uScale = getFloat24(data);
- break;
- case GE_CMD_TEXSCALEV:
- gstate.cmdmem[GE_CMD_TEXSCALEV] = data;
- gstate_c.uv.vScale = getFloat24(data);
- break;
- case GE_CMD_TEXOFFSETU:
- gstate.cmdmem[GE_CMD_TEXOFFSETU] = data;
- gstate_c.uv.uOff = getFloat24(data);
- break;
- case GE_CMD_TEXOFFSETV:
- gstate.cmdmem[GE_CMD_TEXOFFSETV] = data;
- gstate_c.uv.vOff = getFloat24(data);
- break;
- case GE_CMD_TEXLEVEL:
- // Same Gran Turismo hack from Execute_TexLevel
- if ((data & 3) != GE_TEXLEVEL_MODE_AUTO && (0x00FF0000 & data) != 0) {
- goto bail;
- }
- gstate.cmdmem[GE_CMD_TEXLEVEL] = data;
- break;
- case GE_CMD_CALL:
- {
- // A bone matrix probably. If not we bail.
- const u32 target = gstate_c.getRelativeAddress(data & 0x00FFFFFC);
- if ((Memory::ReadUnchecked_U32(target) >> 24) == GE_CMD_BONEMATRIXDATA &&
- (Memory::ReadUnchecked_U32(target + 11 * 4) >> 24) == GE_CMD_BONEMATRIXDATA &&
- (Memory::ReadUnchecked_U32(target + 12 * 4) >> 24) == GE_CMD_RET &&
- (target > currentList->stall || target + 12 * 4 < currentList->stall) &&
- (gstate.boneMatrixNumber & 0x00FFFFFF) <= 96 - 12) {
- FastLoadBoneMatrix(target);
- } else {
- goto bail;
- }
- break;
- }
-
- case GE_CMD_TEXBUFWIDTH0:
- case GE_CMD_TEXADDR0:
- if (data != gstate.cmdmem[data >> 24])
- goto bail;
- break;
-
- default:
- // All other commands might need a flush or something, stop this inner loop.
- goto bail;
- }
- cmdCount++;
- src++;
- }
-
-bail:
- gstate.cmdmem[GE_CMD_VERTEXTYPE] = vertexType;
- // Skip over the commands we just read out manually.
- if (cmdCount > 0) {
- UpdatePC(currentList->pc, currentList->pc + cmdCount * 4);
- currentList->pc += cmdCount * 4;
- // flush back cull mode
- if (cullMode != gstate.getCullMode()) {
- // We rewrote everything to the old cull mode, so flush first.
- drawEngineCommon_->DispatchFlush();
-
- // Now update things for next time.
- gstate.cmdmem[GE_CMD_CULL] ^= 1;
- gstate_c.Dirty(DIRTY_RASTER_STATE);
- }
- }
-
- gpuStats.vertexGPUCycles += vertexCost_ * totalVertCount;
- cyclesExecuted += vertexCost_ * totalVertCount;
-}
-
-void GPUCommon::Execute_Bezier(u32 op, u32 diff) {
- // We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
- gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
-
- gstate_c.framebufFormat = gstate.FrameBufFormat();
-
- // This also make skipping drawing very effective.
- VirtualFramebuffer *vfb = framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
- if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
- // TODO: Should this eat some cycles? Probably yes. Not sure if important.
- return;
- }
-
- CheckDepthUsage(vfb);
-
- if (!Memory::IsValidAddress(gstate_c.vertexAddr)) {
- ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr);
- return;
- }
-
- const void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr);
- const void *indices = NULL;
- if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
- if (!Memory::IsValidAddress(gstate_c.indexAddr)) {
- ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr);
- return;
- }
- indices = Memory::GetPointerUnchecked(gstate_c.indexAddr);
- }
-
- if (vertTypeIsSkinningEnabled(gstate.vertType)) {
- DEBUG_LOG_REPORT(G3D, "Unusual bezier/spline vtype: %08x, morph: %d, bones: %d", gstate.vertType, (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT, vertTypeGetNumBoneWeights(gstate.vertType));
- }
-
- // Can't flush after setting gstate_c.submitType below since it'll be a mess - it must be done already.
- if (flushOnParams_)
- drawEngineCommon_->DispatchFlush();
-
- Spline::BezierSurface surface;
- surface.tess_u = gstate.getPatchDivisionU();
- surface.tess_v = gstate.getPatchDivisionV();
- surface.num_points_u = op & 0xFF;
- surface.num_points_v = (op >> 8) & 0xFF;
- surface.num_patches_u = (surface.num_points_u - 1) / 3;
- surface.num_patches_v = (surface.num_points_v - 1) / 3;
- surface.primType = gstate.getPatchPrimitiveType();
- surface.patchFacing = gstate.patchfacing & 1;
-
- SetDrawType(DRAW_BEZIER, PatchPrimToPrim(surface.primType));
-
- gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
- if (drawEngineCommon_->CanUseHardwareTessellation(surface.primType)) {
- gstate_c.submitType = SubmitType::HW_BEZIER;
- if (gstate_c.spline_num_points_u != surface.num_points_u) {
- gstate_c.Dirty(DIRTY_BEZIERSPLINE);
- gstate_c.spline_num_points_u = surface.num_points_u;
- }
- } else {
- gstate_c.submitType = SubmitType::BEZIER;
- }
-
- int bytesRead = 0;
- UpdateUVScaleOffset();
- drawEngineCommon_->SubmitCurve(control_points, indices, surface, gstate.vertType, &bytesRead, "bezier");
-
- gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
- gstate_c.submitType = SubmitType::DRAW;
-
- // After drawing, we advance pointers - see SubmitPrim which does the same.
- int count = surface.num_points_u * surface.num_points_v;
- AdvanceVerts(gstate.vertType, count, bytesRead);
-}
-
-void GPUCommon::Execute_Spline(u32 op, u32 diff) {
- // We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
- gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
-
- gstate_c.framebufFormat = gstate.FrameBufFormat();
-
- // This also make skipping drawing very effective.
- VirtualFramebuffer *vfb = framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
- if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
- // TODO: Should this eat some cycles? Probably yes. Not sure if important.
- return;
- }
-
- CheckDepthUsage(vfb);
-
- if (!Memory::IsValidAddress(gstate_c.vertexAddr)) {
- ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr);
- return;
- }
-
- const void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr);
- const void *indices = NULL;
- if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
- if (!Memory::IsValidAddress(gstate_c.indexAddr)) {
- ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr);
- return;
- }
- indices = Memory::GetPointerUnchecked(gstate_c.indexAddr);
- }
-
- if (vertTypeIsSkinningEnabled(gstate.vertType)) {
- DEBUG_LOG_REPORT(G3D, "Unusual bezier/spline vtype: %08x, morph: %d, bones: %d", gstate.vertType, (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT, vertTypeGetNumBoneWeights(gstate.vertType));
- }
-
- // Can't flush after setting gstate_c.submitType below since it'll be a mess - it must be done already.
- if (flushOnParams_)
- drawEngineCommon_->DispatchFlush();
-
- Spline::SplineSurface surface;
- surface.tess_u = gstate.getPatchDivisionU();
- surface.tess_v = gstate.getPatchDivisionV();
- surface.type_u = (op >> 16) & 0x3;
- surface.type_v = (op >> 18) & 0x3;
- surface.num_points_u = op & 0xFF;
- surface.num_points_v = (op >> 8) & 0xFF;
- surface.num_patches_u = surface.num_points_u - 3;
- surface.num_patches_v = surface.num_points_v - 3;
- surface.primType = gstate.getPatchPrimitiveType();
- surface.patchFacing = gstate.patchfacing & 1;
-
- SetDrawType(DRAW_SPLINE, PatchPrimToPrim(surface.primType));
-
- gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
- if (drawEngineCommon_->CanUseHardwareTessellation(surface.primType)) {
- gstate_c.submitType = SubmitType::HW_SPLINE;
- if (gstate_c.spline_num_points_u != surface.num_points_u) {
- gstate_c.Dirty(DIRTY_BEZIERSPLINE);
- gstate_c.spline_num_points_u = surface.num_points_u;
- }
- } else {
- gstate_c.submitType = SubmitType::SPLINE;
- }
-
- int bytesRead = 0;
- UpdateUVScaleOffset();
- drawEngineCommon_->SubmitCurve(control_points, indices, surface, gstate.vertType, &bytesRead, "spline");
-
- gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
- gstate_c.submitType = SubmitType::DRAW;
-
- // After drawing, we advance pointers - see SubmitPrim which does the same.
- int count = surface.num_points_u * surface.num_points_v;
- AdvanceVerts(gstate.vertType, count, bytesRead);
-}
-
void GPUCommon::Execute_BoundingBox(u32 op, u32 diff) {
// Just resetting, nothing to check bounds for.
const u32 count = op & 0xFFFF;
@@ -2280,311 +1285,6 @@ void GPUCommon::Execute_BoundingBox(u32 op, u32 diff) {
}
}
-void GPUCommon::Execute_BlockTransferStart(u32 op, u32 diff) {
- Flush();
-
- PROFILE_THIS_SCOPE("block"); // don't include the flush in the profile, would be misleading.
-
- gstate_c.framebufFormat = gstate.FrameBufFormat();
-
- // and take appropriate action. This is a block transfer between RAM and VRAM, or vice versa.
- // Can we skip this on SkipDraw?
- DoBlockTransfer(gstate_c.skipDrawReason);
-}
-
-void GPUCommon::Execute_WorldMtxNum(u32 op, u32 diff) {
- if (!currentList) {
- gstate.worldmtxnum = (GE_CMD_WORLDMATRIXNUMBER << 24) | (op & 0xF);
- return;
- }
-
- // This is almost always followed by GE_CMD_WORLDMATRIXDATA.
- const u32_le *src = (const u32_le *)Memory::GetPointerUnchecked(currentList->pc + 4);
- u32 *dst = (u32 *)(gstate.worldMatrix + (op & 0xF));
- const int end = 12 - (op & 0xF);
- int i = 0;
-
- // We must record the individual data commands while debugRecording_.
- bool fastLoad = !debugRecording_ && end > 0;
- // Stalling in the middle of a matrix would be stupid, I doubt this check is necessary.
- if (currentList->pc < currentList->stall && currentList->pc + end * 4 >= currentList->stall) {
- fastLoad = false;
- }
-
- if (fastLoad) {
- while ((src[i] >> 24) == GE_CMD_WORLDMATRIXDATA) {
- const u32 newVal = src[i] << 8;
- if (dst[i] != newVal) {
- Flush();
- dst[i] = newVal;
- gstate_c.Dirty(DIRTY_WORLDMATRIX);
- }
- if (++i >= end) {
- break;
- }
- }
- }
-
- const int count = i;
- gstate.worldmtxnum = (GE_CMD_WORLDMATRIXNUMBER << 24) | ((op & 0xF) + count);
-
- // Skip over the loaded data, it's done now.
- UpdatePC(currentList->pc, currentList->pc + count * 4);
- currentList->pc += count * 4;
-}
-
-void GPUCommon::Execute_WorldMtxData(u32 op, u32 diff) {
- // Note: it's uncommon to get here now, see above.
- int num = gstate.worldmtxnum & 0x00FFFFFF;
- u32 newVal = op << 8;
- if (num < 12 && newVal != ((const u32 *)gstate.worldMatrix)[num]) {
- Flush();
- ((u32 *)gstate.worldMatrix)[num] = newVal;
- gstate_c.Dirty(DIRTY_WORLDMATRIX);
- }
- num++;
- gstate.worldmtxnum = (GE_CMD_WORLDMATRIXNUMBER << 24) | (num & 0x00FFFFFF);
- gstate.worldmtxdata = GE_CMD_WORLDMATRIXDATA << 24;
-}
-
-void GPUCommon::Execute_ViewMtxNum(u32 op, u32 diff) {
- if (!currentList) {
- gstate.viewmtxnum = (GE_CMD_VIEWMATRIXNUMBER << 24) | (op & 0xF);
- return;
- }
-
- // This is almost always followed by GE_CMD_VIEWMATRIXDATA.
- const u32_le *src = (const u32_le *)Memory::GetPointerUnchecked(currentList->pc + 4);
- u32 *dst = (u32 *)(gstate.viewMatrix + (op & 0xF));
- const int end = 12 - (op & 0xF);
- int i = 0;
-
- bool fastLoad = !debugRecording_ && end > 0;
- if (currentList->pc < currentList->stall && currentList->pc + end * 4 >= currentList->stall) {
- fastLoad = false;
- }
-
- if (fastLoad) {
- while ((src[i] >> 24) == GE_CMD_VIEWMATRIXDATA) {
- const u32 newVal = src[i] << 8;
- if (dst[i] != newVal) {
- Flush();
- dst[i] = newVal;
- gstate_c.Dirty(DIRTY_VIEWMATRIX);
- }
- if (++i >= end) {
- break;
- }
- }
- }
-
- const int count = i;
- gstate.viewmtxnum = (GE_CMD_VIEWMATRIXNUMBER << 24) | ((op & 0xF) + count);
-
- // Skip over the loaded data, it's done now.
- UpdatePC(currentList->pc, currentList->pc + count * 4);
- currentList->pc += count * 4;
-}
-
-void GPUCommon::Execute_ViewMtxData(u32 op, u32 diff) {
- // Note: it's uncommon to get here now, see above.
- int num = gstate.viewmtxnum & 0x00FFFFFF;
- u32 newVal = op << 8;
- if (num < 12 && newVal != ((const u32 *)gstate.viewMatrix)[num]) {
- Flush();
- ((u32 *)gstate.viewMatrix)[num] = newVal;
- gstate_c.Dirty(DIRTY_VIEWMATRIX);
- }
- num++;
- gstate.viewmtxnum = (GE_CMD_VIEWMATRIXNUMBER << 24) | (num & 0x00FFFFFF);
- gstate.viewmtxdata = GE_CMD_VIEWMATRIXDATA << 24;
-}
-
-void GPUCommon::Execute_ProjMtxNum(u32 op, u32 diff) {
- if (!currentList) {
- gstate.projmtxnum = (GE_CMD_PROJMATRIXNUMBER << 24) | (op & 0xF);
- return;
- }
-
- // This is almost always followed by GE_CMD_PROJMATRIXDATA.
- const u32_le *src = (const u32_le *)Memory::GetPointerUnchecked(currentList->pc + 4);
- u32 *dst = (u32 *)(gstate.projMatrix + (op & 0xF));
- const int end = 16 - (op & 0xF);
- int i = 0;
-
- bool fastLoad = !debugRecording_;
- if (currentList->pc < currentList->stall && currentList->pc + end * 4 >= currentList->stall) {
- fastLoad = false;
- }
-
- if (fastLoad) {
- while ((src[i] >> 24) == GE_CMD_PROJMATRIXDATA) {
- const u32 newVal = src[i] << 8;
- if (dst[i] != newVal) {
- Flush();
- dst[i] = newVal;
- gstate_c.Dirty(DIRTY_PROJMATRIX);
- }
- if (++i >= end) {
- break;
- }
- }
- }
-
- const int count = i;
- gstate.projmtxnum = (GE_CMD_PROJMATRIXNUMBER << 24) | ((op & 0xF) + count);
-
- // Skip over the loaded data, it's done now.
- UpdatePC(currentList->pc, currentList->pc + count * 4);
- currentList->pc += count * 4;
-}
-
-void GPUCommon::Execute_ProjMtxData(u32 op, u32 diff) {
- // Note: it's uncommon to get here now, see above.
- int num = gstate.projmtxnum & 0x00FFFFFF;
- u32 newVal = op << 8;
- if (num < 16 && newVal != ((const u32 *)gstate.projMatrix)[num]) {
- Flush();
- ((u32 *)gstate.projMatrix)[num] = newVal;
- gstate_c.Dirty(DIRTY_PROJMATRIX);
- }
- num++;
- if (num <= 16)
- gstate.projmtxnum = (GE_CMD_PROJMATRIXNUMBER << 24) | (num & 0x00FFFFFF);
- gstate.projmtxdata = GE_CMD_PROJMATRIXDATA << 24;
-}
-
-void GPUCommon::Execute_TgenMtxNum(u32 op, u32 diff) {
- if (!currentList) {
- gstate.texmtxnum = (GE_CMD_TGENMATRIXNUMBER << 24) | (op & 0xF);
- return;
- }
-
- // This is almost always followed by GE_CMD_TGENMATRIXDATA.
- const u32_le *src = (const u32_le *)Memory::GetPointerUnchecked(currentList->pc + 4);
- u32 *dst = (u32 *)(gstate.tgenMatrix + (op & 0xF));
- const int end = 12 - (op & 0xF);
- int i = 0;
-
- bool fastLoad = !debugRecording_ && end > 0;
- if (currentList->pc < currentList->stall && currentList->pc + end * 4 >= currentList->stall) {
- fastLoad = false;
- }
-
- if (fastLoad) {
- while ((src[i] >> 24) == GE_CMD_TGENMATRIXDATA) {
- const u32 newVal = src[i] << 8;
- if (dst[i] != newVal) {
- Flush();
- dst[i] = newVal;
- // We check the matrix to see if we need projection.
- gstate_c.Dirty(DIRTY_TEXMATRIX | DIRTY_FRAGMENTSHADER_STATE);
- }
- if (++i >= end) {
- break;
- }
- }
- }
-
- const int count = i;
- gstate.texmtxnum = (GE_CMD_TGENMATRIXNUMBER << 24) | ((op & 0xF) + count);
-
- // Skip over the loaded data, it's done now.
- UpdatePC(currentList->pc, currentList->pc + count * 4);
- currentList->pc += count * 4;
-}
-
-void GPUCommon::Execute_TgenMtxData(u32 op, u32 diff) {
- // Note: it's uncommon to get here now, see above.
- int num = gstate.texmtxnum & 0x00FFFFFF;
- u32 newVal = op << 8;
- if (num < 12 && newVal != ((const u32 *)gstate.tgenMatrix)[num]) {
- Flush();
- ((u32 *)gstate.tgenMatrix)[num] = newVal;
- gstate_c.Dirty(DIRTY_TEXMATRIX | DIRTY_FRAGMENTSHADER_STATE); // We check the matrix to see if we need projection
- }
- num++;
- gstate.texmtxnum = (GE_CMD_TGENMATRIXNUMBER << 24) | (num & 0x00FFFFFF);
- gstate.texmtxdata = GE_CMD_TGENMATRIXDATA << 24;
-}
-
-void GPUCommon::Execute_BoneMtxNum(u32 op, u32 diff) {
- if (!currentList) {
- gstate.boneMatrixNumber = (GE_CMD_BONEMATRIXNUMBER << 24) | (op & 0x7F);
- return;
- }
-
- // This is almost always followed by GE_CMD_BONEMATRIXDATA.
- const u32_le *src = (const u32_le *)Memory::GetPointerUnchecked(currentList->pc + 4);
- u32 *dst = (u32 *)(gstate.boneMatrix + (op & 0x7F));
- const int end = 12 * 8 - (op & 0x7F);
- int i = 0;
-
- bool fastLoad = !debugRecording_ && end > 0;
- if (currentList->pc < currentList->stall && currentList->pc + end * 4 >= currentList->stall) {
- fastLoad = false;
- }
-
- if (fastLoad) {
- // If we can't use software skinning, we have to flush and dirty.
- if (!g_Config.bSoftwareSkinning) {
- while ((src[i] >> 24) == GE_CMD_BONEMATRIXDATA) {
- const u32 newVal = src[i] << 8;
- if (dst[i] != newVal) {
- Flush();
- dst[i] = newVal;
- }
- if (++i >= end) {
- break;
- }
- }
-
- const unsigned int numPlusCount = (op & 0x7F) + i;
- for (unsigned int num = op & 0x7F; num < numPlusCount; num += 12) {
- gstate_c.Dirty(DIRTY_BONEMATRIX0 << (num / 12));
- }
- } else {
- while ((src[i] >> 24) == GE_CMD_BONEMATRIXDATA) {
- dst[i] = src[i] << 8;
- if (++i >= end) {
- break;
- }
- }
-
- const unsigned int numPlusCount = (op & 0x7F) + i;
- for (unsigned int num = op & 0x7F; num < numPlusCount; num += 12) {
- gstate_c.deferredVertTypeDirty |= DIRTY_BONEMATRIX0 << (num / 12);
- }
- }
- }
-
- const int count = i;
- gstate.boneMatrixNumber = (GE_CMD_BONEMATRIXNUMBER << 24) | ((op & 0x7F) + count);
-
- // Skip over the loaded data, it's done now.
- UpdatePC(currentList->pc, currentList->pc + count * 4);
- currentList->pc += count * 4;
-}
-
-void GPUCommon::Execute_BoneMtxData(u32 op, u32 diff) {
- // Note: it's uncommon to get here now, see above.
- int num = gstate.boneMatrixNumber & 0x00FFFFFF;
- u32 newVal = op << 8;
- if (num < 96 && newVal != ((const u32 *)gstate.boneMatrix)[num]) {
- // Bone matrices should NOT flush when software skinning is enabled!
- if (!g_Config.bSoftwareSkinning) {
- Flush();
- gstate_c.Dirty(DIRTY_BONEMATRIX0 << (num / 12));
- } else {
- gstate_c.deferredVertTypeDirty |= DIRTY_BONEMATRIX0 << (num / 12);
- }
- ((u32 *)gstate.boneMatrix)[num] = newVal;
- }
- num++;
- gstate.boneMatrixNumber = (GE_CMD_BONEMATRIXNUMBER << 24) | (num & 0x00FFFFFF);
- gstate.boneMatrixData = GE_CMD_BONEMATRIXDATA << 24;
-}
-
void GPUCommon::Execute_MorphWeight(u32 op, u32 diff) {
gstate_c.morphWeights[(op >> 24) - GE_CMD_MORPHWEIGHT0] = getFloat24(op);
}
@@ -2706,53 +1406,6 @@ void GPUCommon::FlushImm() {
}
}
-void GPUCommon::ExecuteOp(u32 op, u32 diff) {
- const u32 cmd = op >> 24;
-
- // Handle control and drawing commands here directly. The others we delegate.
- switch (cmd) {
- case GE_CMD_NOP:
- break;
-
- case GE_CMD_OFFSETADDR:
- Execute_OffsetAddr(op, diff);
- break;
-
- case GE_CMD_ORIGIN:
- Execute_Origin(op, diff);
- break;
-
- case GE_CMD_JUMP:
- Execute_Jump(op, diff);
- break;
-
- case GE_CMD_BJUMP:
- Execute_BJump(op, diff);
- break;
-
- case GE_CMD_CALL:
- Execute_Call(op, diff);
- break;
-
- case GE_CMD_RET:
- Execute_Ret(op, diff);
- break;
-
- case GE_CMD_SIGNAL:
- case GE_CMD_FINISH:
- // Processed in GE_END.
- break;
-
- case GE_CMD_END:
- Execute_End(op, diff);
- break;
-
- default:
- DEBUG_LOG(G3D, "DL Unknown: %08x @ %08x", op, currentList == NULL ? 0 : currentList->pc);
- break;
- }
-}
-
void GPUCommon::Execute_Unknown(u32 op, u32 diff) {
if ((op & 0xFFFFFF) != 0)
WARN_LOG_REPORT_ONCE(unknowncmd, G3D, "Unknown GE command : %08x ", op);
@@ -3061,10 +1714,6 @@ void GPUCommon::SetCmdValue(u32 op) {
downcount = 0;
}
-void GPUCommon::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) {
- framebufferManager_->SetDisplayFramebuffer(framebuf, stride, format);
-}
-
void GPUCommon::DoBlockTransfer(u32 skipDrawReason) {
u32 srcBasePtr = gstate.getTransferSrcAddress();
u32 srcStride = gstate.getTransferSrcStride();
@@ -3338,21 +1987,6 @@ bool GPUCommon::PerformWriteColorFromMemory(u32 dest, int size) {
return false;
}
-void GPUCommon::InvalidateCache(u32 addr, int size, GPUInvalidationType type) {
- if (size > 0)
- textureCache_->Invalidate(addr, size, type);
- else
- textureCache_->InvalidateAll(type);
-
- if (type != GPU_INVALIDATE_ALL && framebufferManager_->MayIntersectFramebuffer(addr)) {
- // Vempire invalidates (with writeback) after drawing, but before blitting.
- // TODO: Investigate whether we can get this to work some other way.
- if (type == GPU_INVALIDATE_SAFE) {
- framebufferManager_->UpdateFromMemory(addr, size);
- }
- }
-}
-
void GPUCommon::PerformWriteFormattedFromMemory(u32 addr, int size, int frameWidth, GEBufferFormat format) {
if (Memory::IsVRAMAddress(addr)) {
framebufferManager_->PerformWriteFormattedFromMemory(addr, size, frameWidth, format);
@@ -3369,56 +2003,11 @@ bool GPUCommon::PerformWriteStencilFromMemory(u32 dest, int size, WriteStencil f
return false;
}
-bool GPUCommon::GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) {
- u32 fb_address = type == GPU_DBG_FRAMEBUF_RENDER ? (gstate.getFrameBufRawAddress() | 0x04000000) : framebufferManager_->DisplayFramebufAddr();
- int fb_stride = type == GPU_DBG_FRAMEBUF_RENDER ? gstate.FrameBufStride() : framebufferManager_->DisplayFramebufStride();
- GEBufferFormat format = type == GPU_DBG_FRAMEBUF_RENDER ? gstate_c.framebufFormat : framebufferManager_->DisplayFramebufFormat();
- return framebufferManager_->GetFramebuffer(fb_address, fb_stride, format, buffer, maxRes);
-}
-
-bool GPUCommon::GetCurrentDepthbuffer(GPUDebugBuffer &buffer) {
- u32 fb_address = gstate.getFrameBufRawAddress() | 0x04000000;
- int fb_stride = gstate.FrameBufStride();
-
- u32 z_address = gstate.getDepthBufRawAddress() | 0x04000000;
- int z_stride = gstate.DepthBufStride();
-
- return framebufferManager_->GetDepthbuffer(fb_address, fb_stride, z_address, z_stride, buffer);
-}
-
-bool GPUCommon::GetCurrentStencilbuffer(GPUDebugBuffer &buffer) {
- u32 fb_address = gstate.getFrameBufRawAddress() | 0x04000000;
- int fb_stride = gstate.FrameBufStride();
-
- return framebufferManager_->GetStencilbuffer(fb_address, fb_stride, buffer);
-}
-
-bool GPUCommon::GetOutputFramebuffer(GPUDebugBuffer &buffer) {
- // framebufferManager_ can be null here when taking screens in software rendering mode.
- // TODO: Actually grab the framebuffer anyway.
- return framebufferManager_ ? framebufferManager_->GetOutputFramebuffer(buffer) : false;
-}
-
-std::vector GPUCommon::GetFramebufferList() const {
- return framebufferManager_->GetFramebufferList();
-}
-
bool GPUCommon::GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices) {
UpdateUVScaleOffset();
return drawEngineCommon_->GetCurrentSimpleVertices(count, vertices, indices);
}
-bool GPUCommon::GetCurrentClut(GPUDebugBuffer &buffer) {
- return textureCache_->GetCurrentClutBuffer(buffer);
-}
-
-bool GPUCommon::GetCurrentTexture(GPUDebugBuffer &buffer, int level, bool *isFramebuffer) {
- if (!gstate.isTextureMapEnabled()) {
- return false;
- }
- return textureCache_->GetCurrentTextureDebug(buffer, level, isFramebuffer);
-}
-
bool GPUCommon::DescribeCodePtr(const u8 *ptr, std::string &name) {
if (drawEngineCommon_->IsCodePtrVertexDecoder(ptr)) {
name = "VertexDecoderJit";
@@ -3427,26 +2016,6 @@ bool GPUCommon::DescribeCodePtr(const u8 *ptr, std::string &name) {
return false;
}
-bool GPUCommon::FramebufferDirty() {
- VirtualFramebuffer *vfb = framebufferManager_->GetDisplayVFB();
- if (vfb) {
- bool dirty = vfb->dirtyAfterDisplay;
- vfb->dirtyAfterDisplay = false;
- return dirty;
- }
- return true;
-}
-
-bool GPUCommon::FramebufferReallyDirty() {
- VirtualFramebuffer *vfb = framebufferManager_->GetDisplayVFB();
- if (vfb) {
- bool dirty = vfb->reallyDirtyAfterDisplay;
- vfb->reallyDirtyAfterDisplay = false;
- return dirty;
- }
- return true;
-}
-
void GPUCommon::UpdateUVScaleOffset() {
#ifdef _M_SSE
__m128i values = _mm_slli_epi32(_mm_load_si128((const __m128i *) & gstate.texscaleu), 8);
@@ -3461,151 +2030,3 @@ void GPUCommon::UpdateUVScaleOffset() {
gstate_c.uv.vOff = getFloat24(gstate.texoffsetv);
#endif
}
-
-size_t GPUCommon::FormatGPUStatsCommon(char *buffer, size_t size) {
- float vertexAverageCycles = gpuStats.numVertsSubmitted > 0 ? (float)gpuStats.vertexGPUCycles / (float)gpuStats.numVertsSubmitted : 0.0f;
- return snprintf(buffer, size,
- "DL processing time: %0.2f ms, %d drawsync, %d listsync\n"
- "Draw calls: %d, flushes %d, clears %d (cached: %d)\n"
- "Num Tracked Vertex Arrays: %d\n"
- "Vertices: %d cached: %d uncached: %d\n"
- "FBOs active: %d (evaluations: %d)\n"
- "Textures: %d, dec: %d, invalidated: %d, hashed: %d kB\n"
- "readbacks %d (%d non-block), uploads %d, depal %d\n"
- "Copies: depth %d, color %d, reint %d, blend %d, selftex %d\n"
- "GPU cycles executed: %d (%f per vertex)\n",
- gpuStats.msProcessingDisplayLists * 1000.0f,
- gpuStats.numDrawSyncs,
- gpuStats.numListSyncs,
- gpuStats.numDrawCalls,
- gpuStats.numFlushes,
- gpuStats.numClears,
- gpuStats.numCachedDrawCalls,
- gpuStats.numTrackedVertexArrays,
- gpuStats.numVertsSubmitted,
- gpuStats.numCachedVertsDrawn,
- gpuStats.numUncachedVertsDrawn,
- (int)framebufferManager_->NumVFBs(),
- gpuStats.numFramebufferEvaluations,
- (int)textureCache_->NumLoadedTextures(),
- gpuStats.numTexturesDecoded,
- gpuStats.numTextureInvalidations,
- gpuStats.numTextureDataBytesHashed / 1024,
- gpuStats.numBlockingReadbacks,
- gpuStats.numReadbacks,
- gpuStats.numUploads,
- gpuStats.numDepal,
- gpuStats.numDepthCopies,
- gpuStats.numColorCopies,
- gpuStats.numReinterpretCopies,
- gpuStats.numCopiesForShaderBlend,
- gpuStats.numCopiesForSelfTex,
- gpuStats.vertexGPUCycles + gpuStats.otherGPUCycles,
- vertexAverageCycles
- );
-}
-
-u32 GPUCommon::CheckGPUFeatures() const {
- u32 features = 0;
- if (draw_->GetDeviceCaps().logicOpSupported) {
- features |= GPU_USE_LOGIC_OP;
- }
- if (draw_->GetDeviceCaps().anisoSupported) {
- features |= GPU_USE_ANISOTROPY;
- }
- if (draw_->GetDeviceCaps().textureNPOTFullySupported) {
- features |= GPU_USE_TEXTURE_NPOT;
- }
- if (draw_->GetDeviceCaps().dualSourceBlend) {
- if (!g_Config.bVendorBugChecksEnabled || !draw_->GetBugs().Has(Draw::Bugs::DUAL_SOURCE_BLENDING_BROKEN)) {
- features |= GPU_USE_DUALSOURCE_BLEND;
- }
- }
- if (draw_->GetDeviceCaps().blendMinMaxSupported) {
- features |= GPU_USE_BLEND_MINMAX;
- }
-
- if (draw_->GetDeviceCaps().clipDistanceSupported) {
- features |= GPU_USE_CLIP_DISTANCE;
- }
-
- if (draw_->GetDeviceCaps().cullDistanceSupported) {
- features |= GPU_USE_CULL_DISTANCE;
- }
-
- if (draw_->GetDeviceCaps().textureDepthSupported) {
- features |= GPU_USE_DEPTH_TEXTURE;
- }
-
- if (draw_->GetDeviceCaps().depthClampSupported) {
- // Some backends always do GPU_USE_ACCURATE_DEPTH, but it's required for depth clamp.
- features |= GPU_USE_DEPTH_CLAMP | GPU_USE_ACCURATE_DEPTH;
- }
-
- bool canClipOrCull = draw_->GetDeviceCaps().clipDistanceSupported || draw_->GetDeviceCaps().cullDistanceSupported;
- bool canDiscardVertex = !draw_->GetBugs().Has(Draw::Bugs::BROKEN_NAN_IN_CONDITIONAL);
- if (canClipOrCull || canDiscardVertex) {
- // We'll dynamically use the parts that are supported, to reduce artifacts as much as possible.
- features |= GPU_USE_VS_RANGE_CULLING;
- }
-
- if (draw_->GetDeviceCaps().framebufferFetchSupported) {
- features |= GPU_USE_FRAMEBUFFER_FETCH;
- }
-
- if (draw_->GetShaderLanguageDesc().bitwiseOps) {
- features |= GPU_USE_LIGHT_UBERSHADER;
- }
-
- if (PSP_CoreParameter().compat.flags().ClearToRAM) {
- features |= GPU_USE_CLEAR_RAM_HACK;
- }
-
- // Even without depth clamp, force accurate depth on for some games that break without it.
- if (PSP_CoreParameter().compat.flags().DepthRangeHack) {
- features |= GPU_USE_ACCURATE_DEPTH;
- }
-
- return features;
-}
-
-u32 GPUCommon::CheckGPUFeaturesLate(u32 features) const {
- // If we already have a 16-bit depth buffer, we don't need to round.
- bool prefer24 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D24_S8;
- bool prefer16 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D16;
- if (!prefer16) {
- if (sawExactEqualDepth_ && (features & GPU_USE_ACCURATE_DEPTH) != 0) {
- // Exact equal tests tend to have issues unless we use the PSP's depth range.
- // We use 24-bit depth virtually everwhere, the fallback is just for safety.
- if (prefer24)
- features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT;
- else
- features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT;
- } else if (!g_Config.bHighQualityDepth && (features & GPU_USE_ACCURATE_DEPTH) != 0) {
- features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT;
- } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) {
- if (prefer24 && (features & GPU_USE_ACCURATE_DEPTH) != 0) {
- // Here we can simulate a 16 bit depth buffer by scaling.
- // Note that the depth buffer is fixed point, not floating, so dividing by 256 is pretty good.
- features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT;
- } else {
- // Use fragment rounding on where available otherwise.
- features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT;
- }
- } else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) {
- features |= GPU_ROUND_DEPTH_TO_16BIT;
- }
- }
-
- return features;
-}
-
-void GPUCommon::UpdateMSAALevel(Draw::DrawContext *draw) {
- int level = g_Config.iMultiSampleLevel;
- if (draw && draw->GetDeviceCaps().multiSampleLevelsMask & (1 << level)) {
- msaaLevel_ = level;
- } else {
- // Didn't support the configured level, so revert to 0.
- msaaLevel_ = 0;
- }
-}
diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h
index 9529be025e..367da7c85b 100644
--- a/GPU/GPUCommon.h
+++ b/GPU/GPUCommon.h
@@ -60,7 +60,6 @@ struct TransformedVertex {
u32 color1_32;
};
-
void CopyFromWithOffset(const TransformedVertex &other, float xoff, float yoff) {
this->x = other.x + xoff;
this->y = other.y + yoff;
@@ -71,17 +70,16 @@ struct TransformedVertex {
class GPUCommon : public GPUInterface, public GPUDebugInterface {
public:
GPUCommon(GraphicsContext *gfxCtx, Draw::DrawContext *draw);
- ~GPUCommon();
Draw::DrawContext *GetDrawContext() override {
return draw_;
}
- virtual u32 CheckGPUFeatures() const;
+ virtual u32 CheckGPUFeatures() const = 0;
void CheckDisplayResized() override;
void CheckConfigChanged() override;
- void UpdateCmdInfo();
+ virtual void UpdateCmdInfo() = 0;
bool IsReady() override {
return true;
@@ -108,8 +106,7 @@ public:
void DumpNextFrame() override;
- void ExecuteOp(u32 op, u32 diff) override;
- void PreExecuteOp(u32 op, u32 diff) override;
+ virtual void PreExecuteOp(u32 op, u32 diff) {}
bool InterpretList(DisplayList &list);
void ProcessDLQueue();
@@ -129,15 +126,12 @@ public:
uint32_t SetAddrTranslation(uint32_t value) override;
uint32_t GetAddrTranslation() override;
- void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override;
void CopyDisplayToOutput(bool reallyDirty) override = 0;
- void InitClear() override = 0;
bool PerformMemoryCopy(u32 dest, u32 src, int size, GPUCopyFlag flags = GPUCopyFlag::NONE) override;
bool PerformMemorySet(u32 dest, u8 v, int size) override;
bool PerformReadbackToMemory(u32 dest, int size) override;
bool PerformWriteColorFromMemory(u32 dest, int size) override;
- void InvalidateCache(u32 addr, int size, GPUInvalidationType type) override;
void PerformWriteFormattedFromMemory(u32 addr, int size, int width, GEBufferFormat format) override;
bool PerformWriteStencilFromMemory(u32 dest, int size, WriteStencil flags) override;
@@ -153,30 +147,7 @@ public:
void Execute_Ret(u32 op, u32 diff);
void Execute_End(u32 op, u32 diff);
- void Execute_VertexType(u32 op, u32 diff);
- void Execute_VertexTypeSkinning(u32 op, u32 diff);
-
- void Execute_Prim(u32 op, u32 diff);
- void Execute_Bezier(u32 op, u32 diff);
- void Execute_Spline(u32 op, u32 diff);
void Execute_BoundingBox(u32 op, u32 diff);
- void Execute_BlockTransferStart(u32 op, u32 diff);
-
- void Execute_LoadClut(u32 op, u32 diff);
-
- void Execute_TexSize0(u32 op, u32 diff);
- void Execute_TexLevel(u32 op, u32 diff);
-
- void Execute_WorldMtxNum(u32 op, u32 diff);
- void Execute_WorldMtxData(u32 op, u32 diff);
- void Execute_ViewMtxNum(u32 op, u32 diff);
- void Execute_ViewMtxData(u32 op, u32 diff);
- void Execute_ProjMtxNum(u32 op, u32 diff);
- void Execute_ProjMtxData(u32 op, u32 diff);
- void Execute_TgenMtxNum(u32 op, u32 diff);
- void Execute_TgenMtxData(u32 op, u32 diff);
- void Execute_BoneMtxNum(u32 op, u32 diff);
- void Execute_BoneMtxData(u32 op, u32 diff);
void Execute_MorphWeight(u32 op, u32 diff);
@@ -205,13 +176,7 @@ public:
// From GPUDebugInterface.
bool GetCurrentDisplayList(DisplayList &list) override;
- bool GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) override;
- bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer) override;
- bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer) override;
- bool GetCurrentTexture(GPUDebugBuffer &buffer, int level, bool *isFramebuffer) override;
- bool GetCurrentClut(GPUDebugBuffer &buffer) override;
bool GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices) override;
- bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override;
std::vector DebugGetShaderIDs(DebugShaderType shader) override { return std::vector(); };
std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override {
@@ -245,7 +210,6 @@ public:
const std::list& GetDisplayLists() override {
return dlQueue;
}
- std::vector GetFramebufferList() const override;
s64 GetListTicks(int listid) const override {
if (listid >= 0 && listid < DisplayListMaxCount) {
@@ -254,30 +218,15 @@ public:
return -1;
}
- bool FramebufferDirty() override;
- bool FramebufferReallyDirty() override;
-
- typedef void (GPUCommon::*CmdFunc)(u32 op, u32 diff);
-
void GetReportingInfo(std::string &primaryInfo, std::string &fullInfo) override {
primaryInfo = reportingPrimaryInfo_;
fullInfo = reportingFullInfo_;
}
- int MSAALevel() const {
- return msaaLevel_;
- }
-
protected:
- void DeviceLost() override;
- void DeviceRestore() override;
+ void ClearCacheNextFrame() override {}
- void ClearCacheNextFrame() override;
-
- virtual void CheckRenderResized();
-
- // Add additional common features dependent on other features, which may be backend-determined.
- u32 CheckGPUFeaturesLate(u32 features) const;
+ virtual void CheckRenderResized() {}
inline bool IsTrianglePrim(GEPrimitiveType prim) const {
return prim != GE_PRIM_RECTANGLES && prim > GE_PRIM_LINE_STRIP;
@@ -301,7 +250,7 @@ protected:
void BeginFrame() override;
void UpdateVsyncInterval(bool force);
- virtual void FastRunLoop(DisplayList &list);
+ virtual void FastRunLoop(DisplayList &list) = 0;
void SlowRunLoop(DisplayList &list);
void UpdatePC(u32 currentPC, u32 newPC);
@@ -310,7 +259,7 @@ protected:
void FlushImm();
void DoBlockTransfer(u32 skipDrawReason);
- // TODO: Unify this.
+ // TODO: Unify this. The only backend that differs is Vulkan.
virtual void FinishDeferred() {}
void AdvanceVerts(u32 vertType, int count, int bytesRead) {
@@ -322,36 +271,21 @@ protected:
}
}
- size_t FormatGPUStatsCommon(char *buf, size_t size);
-
virtual void BuildReportingInfo() = 0;
- void UpdateMSAALevel(Draw::DrawContext *draw);
+ virtual void UpdateMSAALevel(Draw::DrawContext *draw) {}
+ DrawEngineCommon *drawEngineCommon_ = nullptr;
+
+ // TODO: These should live in GPUCommonHW.
FramebufferManagerCommon *framebufferManager_ = nullptr;
TextureCacheCommon *textureCache_ = nullptr;
- DrawEngineCommon *drawEngineCommon_ = nullptr;
- ShaderManagerCommon *shaderManager_ = nullptr;
+
bool flushOnParams_ = true;
GraphicsContext *gfxCtx_;
Draw::DrawContext *draw_;
- struct CommandInfo {
- uint64_t flags;
- GPUCommon::CmdFunc func;
-
- // Dirty flags are mashed into the regular flags by a left shift of 8.
- void AddDirty(u64 dirty) {
- flags |= dirty << 8;
- }
- void RemoveDirty(u64 dirty) {
- flags &= ~(dirty << 8);
- }
- };
-
- static CommandInfo cmdInfo_[256];
-
typedef std::list DisplayListQueue;
int nextListID;
@@ -377,7 +311,6 @@ protected:
bool displayResized_ = false;
bool renderResized_ = false;
bool configChanged_ = false;
- bool sawExactEqualDepth_ = false;
DrawType lastDraw_ = DRAW_UNKNOWN;
GEPrimitiveType lastPrim_ = GE_PRIM_INVALID;
@@ -396,7 +329,7 @@ protected:
uint32_t edramTranslation_ = 0x400;
- // Whe matrix data overflows, the CPU visible values wrap and bleed between matrices.
+ // When matrix data overflows, the CPU visible values wrap and bleed between matrices.
// But this doesn't actually change the values used by rendering.
// The CPU visible values affect the GPU when list contexts are restored.
// Note: not maintained by all backends, here for save stating.
@@ -414,10 +347,7 @@ protected:
std::string reportingPrimaryInfo_;
std::string reportingFullInfo_;
- int msaaLevel_ = 0;
-
private:
- void CheckDepthUsage(VirtualFramebuffer *vfb);
void DoExecuteCall(u32 target);
void PopDLQueue();
void CheckDrawSync();
@@ -429,10 +359,3 @@ private:
int lastVsync_ = -1;
};
-
-struct CommonCommandTableEntry {
- uint8_t cmd;
- uint8_t flags;
- uint64_t dirty;
- GPUCommon::CmdFunc func;
-};
diff --git a/GPU/GPUCommonHW.cpp b/GPU/GPUCommonHW.cpp
new file mode 100644
index 0000000000..e5fd62a0ae
--- /dev/null
+++ b/GPU/GPUCommonHW.cpp
@@ -0,0 +1,1673 @@
+#include "Common/Profiler/Profiler.h"
+
+#include "Common/GPU/thin3d.h"
+#include "Common/Serialize/Serializer.h"
+#include "Common/System/System.h"
+
+#include "Core/System.h"
+#include "Core/Config.h"
+#include "Core/Util/PPGeDraw.h"
+
+#include "GPU/GPUCommonHW.h"
+#include "GPU/Common/SplineCommon.h"
+#include "GPU/Common/DrawEngineCommon.h"
+#include "GPU/Common/TextureCacheCommon.h"
+#include "GPU/Common/FramebufferManagerCommon.h"
+
+struct CommonCommandTableEntry {
+ uint8_t cmd;
+ uint8_t flags;
+ uint64_t dirty;
+ GPUCommonHW::CmdFunc func;
+};
+
+struct CommandInfo {
+ uint64_t flags;
+ GPUCommonHW::CmdFunc func;
+
+ // Dirty flags are mashed into the regular flags by a left shift of 8.
+ void AddDirty(u64 dirty) {
+ flags |= dirty << 8;
+ }
+ void RemoveDirty(u64 dirty) {
+ flags &= ~(dirty << 8);
+ }
+};
+
+static CommandInfo cmdInfo_[256];
+
+const CommonCommandTableEntry commonCommandTable[] = {
+ // From Common. No flushing but definitely need execute.
+ { GE_CMD_OFFSETADDR, FLAG_EXECUTE, 0, &GPUCommon::Execute_OffsetAddr },
+ { GE_CMD_ORIGIN, FLAG_EXECUTE | FLAG_READS_PC, 0, &GPUCommon::Execute_Origin },
+ { GE_CMD_JUMP, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_Jump },
+ { GE_CMD_CALL, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_Call },
+ { GE_CMD_RET, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_Ret },
+ { GE_CMD_END, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_End },
+ { GE_CMD_VADDR, FLAG_EXECUTE, 0, &GPUCommon::Execute_Vaddr },
+ { GE_CMD_IADDR, FLAG_EXECUTE, 0, &GPUCommon::Execute_Iaddr },
+ { GE_CMD_BJUMP, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_BJump }, // EXECUTE
+ { GE_CMD_BOUNDINGBOX, FLAG_EXECUTE, 0, &GPUCommonHW::Execute_BoundingBox }, // Shouldn't need to FLUSHBEFORE.
+
+ { GE_CMD_PRIM, FLAG_EXECUTE, 0, &GPUCommonHW::Execute_Prim },
+ { GE_CMD_BEZIER, FLAG_EXECUTE, 0, &GPUCommonHW::Execute_Bezier },
+ { GE_CMD_SPLINE, FLAG_EXECUTE, 0, &GPUCommonHW::Execute_Spline },
+
+ // Changing the vertex type requires us to flush.
+ { GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommonHW::Execute_VertexType },
+
+ { GE_CMD_LOADCLUT, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPUCommonHW::Execute_LoadClut},
+
+ // These two are actually processed in CMD_END.
+ { GE_CMD_SIGNAL },
+ { GE_CMD_FINISH },
+
+ // Changes that dirty the framebuffer
+ { GE_CMD_FRAMEBUFPTR, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_FRAMEBUFWIDTH, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE },
+ { GE_CMD_FRAMEBUFPIXFORMAT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_FRAGMENTSHADER_STATE },
+ { GE_CMD_ZBUFPTR, FLAG_FLUSHBEFOREONCHANGE },
+ { GE_CMD_ZBUFWIDTH, FLAG_FLUSHBEFOREONCHANGE },
+
+ { GE_CMD_FOGCOLOR, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FOGCOLOR },
+ { GE_CMD_FOG1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FOGCOEFENABLE },
+ { GE_CMD_FOG2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FOGCOEFENABLE },
+
+ // These affect the fragment shader so need flushing.
+ { GE_CMD_CLEARMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE },
+ { GE_CMD_TEXTUREMAPENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE },
+ { GE_CMD_FOGENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FOGCOEFENABLE },
+ { GE_CMD_TEXMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS | DIRTY_FRAGMENTSHADER_STATE },
+ { GE_CMD_TEXSHADELS, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
+ // Raster state for Direct3D 9, uncommon.
+ { GE_CMD_SHADEMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_RASTER_STATE },
+ { GE_CMD_TEXFUNC, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAGMENTSHADER_STATE | DIRTY_TEX_ALPHA_MUL },
+ { GE_CMD_COLORTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAGMENTSHADER_STATE },
+ { GE_CMD_ALPHATESTENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAGMENTSHADER_STATE },
+ { GE_CMD_COLORTESTENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAGMENTSHADER_STATE },
+ { GE_CMD_COLORTESTMASK, FLAG_FLUSHBEFOREONCHANGE, DIRTY_ALPHACOLORMASK | DIRTY_FRAGMENTSHADER_STATE },
+
+ // These change the vertex shader so need flushing.
+ { GE_CMD_REVERSENORMAL, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
+ { GE_CMD_LIGHTINGENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE },
+ { GE_CMD_LIGHTENABLE0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
+ { GE_CMD_LIGHTENABLE1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
+ { GE_CMD_LIGHTENABLE2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
+ { GE_CMD_LIGHTENABLE3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
+ { GE_CMD_LIGHTTYPE0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_LIGHT0 },
+ { GE_CMD_LIGHTTYPE1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_LIGHT1 },
+ { GE_CMD_LIGHTTYPE2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_LIGHT2 },
+ { GE_CMD_LIGHTTYPE3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_LIGHT3 },
+ { GE_CMD_MATERIALUPDATE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
+
+ // These change vertex shaders (in non uber shader mode) so need flushing.
+ { GE_CMD_LIGHTMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
+
+ { GE_CMD_TEXFILTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXWRAP, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS | DIRTY_FRAGMENTSHADER_STATE },
+
+ // Uniform changes. though the fragmentshader optimizes based on these sometimes.
+ { GE_CMD_ALPHATEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_ALPHACOLORREF | DIRTY_ALPHACOLORMASK | DIRTY_FRAGMENTSHADER_STATE },
+ { GE_CMD_COLORREF, FLAG_FLUSHBEFOREONCHANGE, DIRTY_ALPHACOLORREF | DIRTY_FRAGMENTSHADER_STATE },
+ { GE_CMD_TEXENVCOLOR, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXENV },
+
+ // Simple render state changes. Handled in StateMapping.cpp.
+ { GE_CMD_CULL, FLAG_FLUSHBEFOREONCHANGE, DIRTY_RASTER_STATE },
+ { GE_CMD_CULLFACEENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_RASTER_STATE },
+ { GE_CMD_DITHERENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_RASTER_STATE },
+ { GE_CMD_STENCILOP, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_FRAGMENTSHADER_STATE },
+ { GE_CMD_STENCILTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_STENCILREPLACEVALUE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE },
+ { GE_CMD_STENCILTESTENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_FRAGMENTSHADER_STATE },
+ { GE_CMD_ALPHABLENDENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE },
+ { GE_CMD_BLENDMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE },
+ { GE_CMD_BLENDFIXEDA, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE },
+ { GE_CMD_BLENDFIXEDB, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE },
+ { GE_CMD_MASKRGB, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_COLORWRITEMASK },
+ { GE_CMD_MASKALPHA, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_COLORWRITEMASK },
+ { GE_CMD_ZTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHSTENCIL_STATE },
+ { GE_CMD_ZTESTENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHSTENCIL_STATE | DIRTY_FRAGMENTSHADER_STATE },
+ { GE_CMD_ZWRITEDISABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHSTENCIL_STATE | DIRTY_FRAGMENTSHADER_STATE },
+ { GE_CMD_LOGICOP, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE },
+ { GE_CMD_LOGICOPENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE },
+
+ { GE_CMD_TEXMAPMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE },
+
+ // These are read on every SubmitPrim, no need for dirtying or flushing.
+ { GE_CMD_TEXSCALEU },
+ { GE_CMD_TEXSCALEV },
+ { GE_CMD_TEXOFFSETU },
+ { GE_CMD_TEXOFFSETV },
+
+ { GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPUCommonHW::Execute_TexSize0 },
+ { GE_CMD_TEXSIZE1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXSIZE2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXSIZE3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXSIZE4, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXSIZE5, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXSIZE6, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXSIZE7, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXFORMAT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE },
+ { GE_CMD_TEXLEVEL, FLAG_EXECUTEONCHANGE, DIRTY_TEXTURE_PARAMS, &GPUCommonHW::Execute_TexLevel },
+ { GE_CMD_TEXLODSLOPE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXADDR0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE | DIRTY_UVSCALEOFFSET },
+ { GE_CMD_TEXADDR1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXADDR2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXADDR3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXADDR4, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXADDR5, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXADDR6, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXADDR7, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXBUFWIDTH0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE },
+ { GE_CMD_TEXBUFWIDTH1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXBUFWIDTH2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXBUFWIDTH3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXBUFWIDTH4, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXBUFWIDTH5, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXBUFWIDTH6, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+ { GE_CMD_TEXBUFWIDTH7, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS },
+
+ // These must flush on change, so that LoadClut doesn't have to always flush.
+ { GE_CMD_CLUTADDR, FLAG_FLUSHBEFOREONCHANGE },
+ { GE_CMD_CLUTADDRUPPER, FLAG_FLUSHBEFOREONCHANGE },
+ { GE_CMD_CLUTFORMAT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS | DIRTY_DEPAL },
+
+ // Morph weights. TODO: Remove precomputation?
+ { GE_CMD_MORPHWEIGHT0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight },
+ { GE_CMD_MORPHWEIGHT1, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight },
+ { GE_CMD_MORPHWEIGHT2, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight },
+ { GE_CMD_MORPHWEIGHT3, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight },
+ { GE_CMD_MORPHWEIGHT4, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight },
+ { GE_CMD_MORPHWEIGHT5, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight },
+ { GE_CMD_MORPHWEIGHT6, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight },
+ { GE_CMD_MORPHWEIGHT7, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight },
+
+ // Control spline/bezier patches. Don't really require flushing as such, but meh.
+ { GE_CMD_PATCHDIVISION, FLAG_FLUSHBEFOREONCHANGE },
+ { GE_CMD_PATCHPRIMITIVE, FLAG_FLUSHBEFOREONCHANGE },
+ { GE_CMD_PATCHFACING, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VERTEXSHADER_STATE },
+ { GE_CMD_PATCHCULLENABLE, FLAG_FLUSHBEFOREONCHANGE },
+
+ // Can probably ignore this one as we don't support AA lines.
+ { GE_CMD_ANTIALIASENABLE, FLAG_FLUSHBEFOREONCHANGE },
+
+ // Viewport.
+ { GE_CMD_OFFSETX, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE },
+ { GE_CMD_OFFSETY, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE },
+ { GE_CMD_VIEWPORTXSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE },
+ { GE_CMD_VIEWPORTYSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE },
+ { GE_CMD_VIEWPORTXCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE },
+ { GE_CMD_VIEWPORTYCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE },
+ { GE_CMD_VIEWPORTZSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_DEPTHRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE },
+ { GE_CMD_VIEWPORTZCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_DEPTHRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE },
+ { GE_CMD_DEPTHCLAMPENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE | DIRTY_RASTER_STATE },
+
+ // Z clip
+ { GE_CMD_MINZ, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHRANGE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE },
+ { GE_CMD_MAXZ, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHRANGE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE },
+
+ // Region
+ { GE_CMD_REGION1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE },
+ { GE_CMD_REGION2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE },
+
+ // Scissor
+ { GE_CMD_SCISSOR1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE },
+ { GE_CMD_SCISSOR2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE },
+
+ // Lighting base colors
+ { GE_CMD_AMBIENTCOLOR, FLAG_FLUSHBEFOREONCHANGE, DIRTY_AMBIENT },
+ { GE_CMD_AMBIENTALPHA, FLAG_FLUSHBEFOREONCHANGE, DIRTY_AMBIENT },
+ { GE_CMD_MATERIALDIFFUSE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_MATDIFFUSE },
+ { GE_CMD_MATERIALEMISSIVE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_MATEMISSIVE },
+ { GE_CMD_MATERIALAMBIENT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_MATAMBIENTALPHA },
+ { GE_CMD_MATERIALALPHA, FLAG_FLUSHBEFOREONCHANGE, DIRTY_MATAMBIENTALPHA },
+ { GE_CMD_MATERIALSPECULAR, FLAG_FLUSHBEFOREONCHANGE, DIRTY_MATSPECULAR },
+ { GE_CMD_MATERIALSPECULARCOEF, FLAG_FLUSHBEFOREONCHANGE, DIRTY_MATSPECULAR },
+
+ // Light parameters
+ { GE_CMD_LX0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
+ { GE_CMD_LY0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
+ { GE_CMD_LZ0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
+ { GE_CMD_LX1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
+ { GE_CMD_LY1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
+ { GE_CMD_LZ1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
+ { GE_CMD_LX2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
+ { GE_CMD_LY2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
+ { GE_CMD_LZ2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
+ { GE_CMD_LX3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
+ { GE_CMD_LY3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
+ { GE_CMD_LZ3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
+
+ { GE_CMD_LDX0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
+ { GE_CMD_LDY0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
+ { GE_CMD_LDZ0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
+ { GE_CMD_LDX1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
+ { GE_CMD_LDY1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
+ { GE_CMD_LDZ1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
+ { GE_CMD_LDX2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
+ { GE_CMD_LDY2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
+ { GE_CMD_LDZ2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
+ { GE_CMD_LDX3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
+ { GE_CMD_LDY3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
+ { GE_CMD_LDZ3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
+
+ { GE_CMD_LKA0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
+ { GE_CMD_LKB0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
+ { GE_CMD_LKC0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
+ { GE_CMD_LKA1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
+ { GE_CMD_LKB1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
+ { GE_CMD_LKC1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
+ { GE_CMD_LKA2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
+ { GE_CMD_LKB2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
+ { GE_CMD_LKC2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
+ { GE_CMD_LKA3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
+ { GE_CMD_LKB3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
+ { GE_CMD_LKC3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
+
+ { GE_CMD_LKS0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
+ { GE_CMD_LKS1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
+ { GE_CMD_LKS2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
+ { GE_CMD_LKS3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
+
+ { GE_CMD_LKO0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
+ { GE_CMD_LKO1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
+ { GE_CMD_LKO2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
+ { GE_CMD_LKO3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
+
+ { GE_CMD_LAC0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
+ { GE_CMD_LDC0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
+ { GE_CMD_LSC0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 },
+ { GE_CMD_LAC1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
+ { GE_CMD_LDC1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
+ { GE_CMD_LSC1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 },
+ { GE_CMD_LAC2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
+ { GE_CMD_LDC2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
+ { GE_CMD_LSC2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 },
+ { GE_CMD_LAC3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
+ { GE_CMD_LDC3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
+ { GE_CMD_LSC3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 },
+
+ // Ignored commands
+ { GE_CMD_TEXFLUSH, FLAG_EXECUTE, 0, &GPUCommonHW::Execute_TexFlush },
+ { GE_CMD_TEXSYNC, 0 },
+
+ // These are just nop or part of other later commands.
+ { GE_CMD_NOP, 0 },
+ { GE_CMD_BASE, 0 },
+ { GE_CMD_TRANSFERSRC, 0 },
+ { GE_CMD_TRANSFERSRCW, 0 },
+ { GE_CMD_TRANSFERDST, 0 },
+ { GE_CMD_TRANSFERDSTW, 0 },
+ { GE_CMD_TRANSFERSRCPOS, 0 },
+ { GE_CMD_TRANSFERDSTPOS, 0 },
+ { GE_CMD_TRANSFERSIZE, 0 },
+ { GE_CMD_TRANSFERSTART, FLAG_EXECUTE | FLAG_READS_PC, 0, &GPUCommonHW::Execute_BlockTransferStart },
+
+ // We don't use the dither table.
+ { GE_CMD_DITH0 },
+ { GE_CMD_DITH1 },
+ { GE_CMD_DITH2 },
+ { GE_CMD_DITH3 },
+
+ // These handle their own flushing.
+ { GE_CMD_WORLDMATRIXNUMBER, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommonHW::Execute_WorldMtxNum },
+ { GE_CMD_WORLDMATRIXDATA, FLAG_EXECUTE, 0, &GPUCommonHW::Execute_WorldMtxData },
+ { GE_CMD_VIEWMATRIXNUMBER, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommonHW::Execute_ViewMtxNum },
+ { GE_CMD_VIEWMATRIXDATA, FLAG_EXECUTE, 0, &GPUCommonHW::Execute_ViewMtxData },
+ { GE_CMD_PROJMATRIXNUMBER, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommonHW::Execute_ProjMtxNum },
+ { GE_CMD_PROJMATRIXDATA, FLAG_EXECUTE, 0, &GPUCommonHW::Execute_ProjMtxData },
+ { GE_CMD_TGENMATRIXNUMBER, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommonHW::Execute_TgenMtxNum },
+ { GE_CMD_TGENMATRIXDATA, FLAG_EXECUTE, 0, &GPUCommonHW::Execute_TgenMtxData },
+ { GE_CMD_BONEMATRIXNUMBER, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommonHW::Execute_BoneMtxNum },
+ { GE_CMD_BONEMATRIXDATA, FLAG_EXECUTE, 0, &GPUCommonHW::Execute_BoneMtxData },
+
+ // Vertex Screen/Texture/Color
+ { GE_CMD_VSCX },
+ { GE_CMD_VSCY },
+ { GE_CMD_VSCZ },
+ { GE_CMD_VTCS },
+ { GE_CMD_VTCT },
+ { GE_CMD_VTCQ },
+ { GE_CMD_VCV },
+ { GE_CMD_VAP, FLAG_EXECUTE, 0, &GPUCommon::Execute_ImmVertexAlphaPrim },
+ { GE_CMD_VFC },
+ { GE_CMD_VSCV },
+
+ // "Missing" commands (gaps in the sequence)
+ { GE_CMD_UNKNOWN_03, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_0D, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_11, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_29, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_34, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_35, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_39, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_4E, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_4F, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_52, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_59, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_5A, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_B6, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_B7, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_D1, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_ED, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_EF, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_FA, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_FB, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_FC, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_FD, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ { GE_CMD_UNKNOWN_FE, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown },
+ // Appears to be debugging related or something? Hit a lot in GoW.
+ { GE_CMD_NOP_FF, 0 },
+};
+
+GPUCommonHW::GPUCommonHW(GraphicsContext *gfxCtx, Draw::DrawContext *draw) : GPUCommon(gfxCtx, draw) {
+ memset(cmdInfo_, 0, sizeof(cmdInfo_));
+
+ // Convert the command table to a faster format, and check for dupes.
+ std::set dupeCheck;
+ for (size_t i = 0; i < ARRAY_SIZE(commonCommandTable); i++) {
+ const u8 cmd = commonCommandTable[i].cmd;
+ if (dupeCheck.find(cmd) != dupeCheck.end()) {
+ ERROR_LOG(G3D, "Command table Dupe: %02x (%i)", (int)cmd, (int)cmd);
+ } else {
+ dupeCheck.insert(cmd);
+ }
+ cmdInfo_[cmd].flags |= (uint64_t)commonCommandTable[i].flags | (commonCommandTable[i].dirty << 8);
+ cmdInfo_[cmd].func = commonCommandTable[i].func;
+ if ((cmdInfo_[cmd].flags & (FLAG_EXECUTE | FLAG_EXECUTEONCHANGE)) && !cmdInfo_[cmd].func) {
+ // Can't have FLAG_EXECUTE commands without a function pointer to execute.
+ Crash();
+ }
+ }
+ // Find commands missing from the table.
+ for (int i = 0; i < 0xEF; i++) {
+ if (dupeCheck.find((u8)i) == dupeCheck.end()) {
+ ERROR_LOG(G3D, "Command missing from table: %02x (%i)", i, i);
+ }
+ }
+
+ UpdateCmdInfo();
+ UpdateMSAALevel(draw);
+}
+
+GPUCommonHW::~GPUCommonHW() {
+ // Clear features so they're not visible in system info.
+ gstate_c.SetUseFlags(0);
+
+ // Delete the various common managers.
+ framebufferManager_->DestroyAllFBOs();
+ delete framebufferManager_;
+ delete textureCache_;
+ shaderManager_->ClearShaders();
+ delete shaderManager_;
+}
+
+void GPUCommonHW::CheckRenderResized() {
+ if (renderResized_) {
+ framebufferManager_->NotifyRenderResized(msaaLevel_);
+ renderResized_ = false;
+ }
+}
+
+// Call at the END of the GPU implementation's DeviceLost
+void GPUCommonHW::DeviceLost() {
+ framebufferManager_->DeviceLost();
+ draw_ = nullptr;
+ textureCache_->Clear(false);
+ textureCache_->DeviceLost();
+ shaderManager_->DeviceLost();
+ drawEngineCommon_->DeviceLost();
+}
+
+// Call at the start of the GPU implementation's DeviceRestore
+void GPUCommonHW::DeviceRestore(Draw::DrawContext *draw) {
+ draw_ = draw;
+ framebufferManager_->DeviceRestore(draw_);
+ textureCache_->DeviceRestore(draw_);
+ shaderManager_->DeviceRestore(draw_);
+ drawEngineCommon_->DeviceRestore(draw_);
+
+ PPGeSetDrawContext(draw_);
+
+ gstate_c.SetUseFlags(CheckGPUFeatures());
+ BuildReportingInfo();
+ UpdateCmdInfo();
+}
+
+void GPUCommonHW::UpdateCmdInfo() {
+ if (g_Config.bSoftwareSkinning) {
+ cmdInfo_[GE_CMD_VERTEXTYPE].flags &= ~FLAG_FLUSHBEFOREONCHANGE;
+ cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommonHW::Execute_VertexTypeSkinning;
+ } else {
+ cmdInfo_[GE_CMD_VERTEXTYPE].flags |= FLAG_FLUSHBEFOREONCHANGE;
+ cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommonHW::Execute_VertexType;
+ }
+
+ if (g_Config.bFastMemory) {
+ cmdInfo_[GE_CMD_JUMP].func = &GPUCommon::Execute_JumpFast;
+ cmdInfo_[GE_CMD_CALL].func = &GPUCommon::Execute_CallFast;
+ } else {
+ cmdInfo_[GE_CMD_JUMP].func = &GPUCommon::Execute_Jump;
+ cmdInfo_[GE_CMD_CALL].func = &GPUCommon::Execute_Call;
+ }
+
+ // Reconfigure for light ubershader or not.
+ for (int i = 0; i < 4; i++) {
+ if (gstate_c.Use(GPU_USE_LIGHT_UBERSHADER)) {
+ cmdInfo_[GE_CMD_LIGHTENABLE0 + i].RemoveDirty(DIRTY_VERTEXSHADER_STATE);
+ cmdInfo_[GE_CMD_LIGHTENABLE0 + i].AddDirty(DIRTY_LIGHT_CONTROL);
+ cmdInfo_[GE_CMD_LIGHTTYPE0 + i].RemoveDirty(DIRTY_VERTEXSHADER_STATE);
+ cmdInfo_[GE_CMD_LIGHTTYPE0 + i].AddDirty(DIRTY_LIGHT_CONTROL);
+ } else {
+ cmdInfo_[GE_CMD_LIGHTENABLE0 + i].RemoveDirty(DIRTY_LIGHT_CONTROL);
+ cmdInfo_[GE_CMD_LIGHTENABLE0 + i].AddDirty(DIRTY_VERTEXSHADER_STATE);
+ cmdInfo_[GE_CMD_LIGHTTYPE0 + i].RemoveDirty(DIRTY_LIGHT_CONTROL);
+ cmdInfo_[GE_CMD_LIGHTTYPE0 + i].AddDirty(DIRTY_VERTEXSHADER_STATE);
+ }
+ }
+
+ if (gstate_c.Use(GPU_USE_LIGHT_UBERSHADER)) {
+ cmdInfo_[GE_CMD_MATERIALUPDATE].RemoveDirty(DIRTY_VERTEXSHADER_STATE);
+ cmdInfo_[GE_CMD_MATERIALUPDATE].AddDirty(DIRTY_LIGHT_CONTROL);
+ cmdInfo_[GE_CMD_LIGHTMODE].AddDirty(DIRTY_LIGHT_CONTROL);
+ } else {
+ cmdInfo_[GE_CMD_MATERIALUPDATE].RemoveDirty(DIRTY_LIGHT_CONTROL);
+ cmdInfo_[GE_CMD_MATERIALUPDATE].AddDirty(DIRTY_VERTEXSHADER_STATE);
+ cmdInfo_[GE_CMD_LIGHTMODE].RemoveDirty(DIRTY_LIGHT_CONTROL);
+ }
+}
+
+void GPUCommonHW::BeginFrame() {
+ GPUCommon::BeginFrame();
+
+ if (drawEngineCommon_->EverUsedExactEqualDepth() && !sawExactEqualDepth_) {
+ sawExactEqualDepth_ = true;
+ gstate_c.SetUseFlags(CheckGPUFeatures());
+ }
+}
+
+void GPUCommonHW::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) {
+ framebufferManager_->SetDisplayFramebuffer(framebuf, stride, format);
+}
+
+void GPUCommonHW::CheckFlushOp(int cmd, u32 diff) {
+ const u8 cmdFlags = cmdInfo_[cmd].flags;
+ if (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)) {
+ if (dumpThisFrame_) {
+ NOTICE_LOG(G3D, "================ FLUSH ================");
+ }
+ drawEngineCommon_->DispatchFlush();
+ }
+}
+
+void GPUCommonHW::PreExecuteOp(u32 op, u32 diff) {
+ CheckFlushOp(op >> 24, diff);
+}
+
+void GPUCommonHW::CopyDisplayToOutput(bool reallyDirty) {
+ // Flush anything left over.
+ drawEngineCommon_->DispatchFlush();
+
+ shaderManager_->DirtyLastShader();
+
+ framebufferManager_->CopyDisplayToOutput(reallyDirty);
+
+ gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
+}
+
+void GPUCommonHW::DoState(PointerWrap &p) {
+ GPUCommon::DoState(p);
+
+ // TODO: Some of these things may not be necessary.
+ // None of these are necessary when saving.
+ if (p.mode == p.MODE_READ && !PSP_CoreParameter().frozen) {
+ textureCache_->Clear(true);
+ drawEngineCommon_->ClearTrackedVertexArrays();
+
+ gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
+ framebufferManager_->DestroyAllFBOs();
+ }
+}
+
+void GPUCommonHW::ClearCacheNextFrame() {
+ textureCache_->ClearNextFrame();
+}
+
+// Needs to be called on GPU thread, not reporting thread.
+void GPUCommonHW::BuildReportingInfo() {
+ using namespace Draw;
+
+ reportingPrimaryInfo_ = draw_->GetInfoString(InfoField::VENDORSTRING);
+ reportingFullInfo_ = reportingPrimaryInfo_ + " - " + System_GetProperty(SYSPROP_GPUDRIVER_VERSION) + " - " + draw_->GetInfoString(InfoField::SHADELANGVERSION);
+}
+
+u32 GPUCommonHW::CheckGPUFeatures() const {
+ u32 features = 0;
+ if (draw_->GetDeviceCaps().logicOpSupported) {
+ features |= GPU_USE_LOGIC_OP;
+ }
+ if (draw_->GetDeviceCaps().anisoSupported) {
+ features |= GPU_USE_ANISOTROPY;
+ }
+ if (draw_->GetDeviceCaps().textureNPOTFullySupported) {
+ features |= GPU_USE_TEXTURE_NPOT;
+ }
+ if (draw_->GetDeviceCaps().dualSourceBlend) {
+ if (!g_Config.bVendorBugChecksEnabled || !draw_->GetBugs().Has(Draw::Bugs::DUAL_SOURCE_BLENDING_BROKEN)) {
+ features |= GPU_USE_DUALSOURCE_BLEND;
+ }
+ }
+ if (draw_->GetDeviceCaps().blendMinMaxSupported) {
+ features |= GPU_USE_BLEND_MINMAX;
+ }
+
+ if (draw_->GetDeviceCaps().clipDistanceSupported) {
+ features |= GPU_USE_CLIP_DISTANCE;
+ }
+
+ if (draw_->GetDeviceCaps().cullDistanceSupported) {
+ features |= GPU_USE_CULL_DISTANCE;
+ }
+
+ if (draw_->GetDeviceCaps().textureDepthSupported) {
+ features |= GPU_USE_DEPTH_TEXTURE;
+ }
+
+ if (draw_->GetDeviceCaps().depthClampSupported) {
+ // Some backends always do GPU_USE_ACCURATE_DEPTH, but it's required for depth clamp.
+ features |= GPU_USE_DEPTH_CLAMP | GPU_USE_ACCURATE_DEPTH;
+ }
+
+ bool canClipOrCull = draw_->GetDeviceCaps().clipDistanceSupported || draw_->GetDeviceCaps().cullDistanceSupported;
+ bool canDiscardVertex = !draw_->GetBugs().Has(Draw::Bugs::BROKEN_NAN_IN_CONDITIONAL);
+ if (canClipOrCull || canDiscardVertex) {
+ // We'll dynamically use the parts that are supported, to reduce artifacts as much as possible.
+ features |= GPU_USE_VS_RANGE_CULLING;
+ }
+
+ if (draw_->GetDeviceCaps().framebufferFetchSupported) {
+ features |= GPU_USE_FRAMEBUFFER_FETCH;
+ }
+
+ if (draw_->GetShaderLanguageDesc().bitwiseOps) {
+ features |= GPU_USE_LIGHT_UBERSHADER;
+ }
+
+ if (PSP_CoreParameter().compat.flags().ClearToRAM) {
+ features |= GPU_USE_CLEAR_RAM_HACK;
+ }
+
+ // Even without depth clamp, force accurate depth on for some games that break without it.
+ if (PSP_CoreParameter().compat.flags().DepthRangeHack) {
+ features |= GPU_USE_ACCURATE_DEPTH;
+ }
+
+ return features;
+}
+
+u32 GPUCommonHW::CheckGPUFeaturesLate(u32 features) const {
+ // If we already have a 16-bit depth buffer, we don't need to round.
+ bool prefer24 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D24_S8;
+ bool prefer16 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D16;
+ if (!prefer16) {
+ if (sawExactEqualDepth_ && (features & GPU_USE_ACCURATE_DEPTH) != 0) {
+ // Exact equal tests tend to have issues unless we use the PSP's depth range.
+ // We use 24-bit depth virtually everwhere, the fallback is just for safety.
+ if (prefer24)
+ features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT;
+ else
+ features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT;
+ } else if (!g_Config.bHighQualityDepth && (features & GPU_USE_ACCURATE_DEPTH) != 0) {
+ features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT;
+ } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) {
+ if (prefer24 && (features & GPU_USE_ACCURATE_DEPTH) != 0) {
+ // Here we can simulate a 16 bit depth buffer by scaling.
+ // Note that the depth buffer is fixed point, not floating, so dividing by 256 is pretty good.
+ features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT;
+ } else {
+ // Use fragment rounding on where available otherwise.
+ features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT;
+ }
+ } else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) {
+ features |= GPU_ROUND_DEPTH_TO_16BIT;
+ }
+ }
+
+ return features;
+}
+
+void GPUCommonHW::UpdateMSAALevel(Draw::DrawContext *draw) {
+ int level = g_Config.iMultiSampleLevel;
+ if (draw && draw->GetDeviceCaps().multiSampleLevelsMask & (1 << level)) {
+ msaaLevel_ = level;
+ } else {
+ // Didn't support the configured level, so revert to 0.
+ msaaLevel_ = 0;
+ }
+}
+
+std::vector GPUCommonHW::DebugGetShaderIDs(DebugShaderType type) {
+ switch (type) {
+ case SHADER_TYPE_VERTEXLOADER:
+ return drawEngineCommon_->DebugGetVertexLoaderIDs();
+ case SHADER_TYPE_TEXTURE:
+ return textureCache_->GetTextureShaderCache()->DebugGetShaderIDs(type);
+ default:
+ return shaderManager_->DebugGetShaderIDs(type);
+ }
+}
+
+std::string GPUCommonHW::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {
+ switch (type) {
+ case SHADER_TYPE_VERTEXLOADER:
+ return drawEngineCommon_->DebugGetVertexLoaderString(id, stringType);
+ case SHADER_TYPE_TEXTURE:
+ return textureCache_->GetTextureShaderCache()->DebugGetShaderString(id, type, stringType);
+ default:
+ return shaderManager_->DebugGetShaderString(id, type, stringType);
+ }
+}
+
+bool GPUCommonHW::GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) {
+ u32 fb_address = type == GPU_DBG_FRAMEBUF_RENDER ? (gstate.getFrameBufRawAddress() | 0x04000000) : framebufferManager_->DisplayFramebufAddr();
+ int fb_stride = type == GPU_DBG_FRAMEBUF_RENDER ? gstate.FrameBufStride() : framebufferManager_->DisplayFramebufStride();
+ GEBufferFormat format = type == GPU_DBG_FRAMEBUF_RENDER ? gstate_c.framebufFormat : framebufferManager_->DisplayFramebufFormat();
+ return framebufferManager_->GetFramebuffer(fb_address, fb_stride, format, buffer, maxRes);
+}
+
+bool GPUCommonHW::GetCurrentDepthbuffer(GPUDebugBuffer &buffer) {
+ u32 fb_address = gstate.getFrameBufRawAddress() | 0x04000000;
+ int fb_stride = gstate.FrameBufStride();
+
+ u32 z_address = gstate.getDepthBufRawAddress() | 0x04000000;
+ int z_stride = gstate.DepthBufStride();
+
+ return framebufferManager_->GetDepthbuffer(fb_address, fb_stride, z_address, z_stride, buffer);
+}
+
+bool GPUCommonHW::GetCurrentStencilbuffer(GPUDebugBuffer &buffer) {
+ u32 fb_address = gstate.getFrameBufRawAddress() | 0x04000000;
+ int fb_stride = gstate.FrameBufStride();
+
+ return framebufferManager_->GetStencilbuffer(fb_address, fb_stride, buffer);
+}
+
+bool GPUCommonHW::GetOutputFramebuffer(GPUDebugBuffer &buffer) {
+ // framebufferManager_ can be null here when taking screens in software rendering mode.
+ // TODO: Actually grab the framebuffer anyway.
+ return framebufferManager_ ? framebufferManager_->GetOutputFramebuffer(buffer) : false;
+}
+
+std::vector GPUCommonHW::GetFramebufferList() const {
+ return framebufferManager_->GetFramebufferList();
+}
+
+bool GPUCommonHW::GetCurrentClut(GPUDebugBuffer &buffer) {
+ return textureCache_->GetCurrentClutBuffer(buffer);
+}
+
+bool GPUCommonHW::GetCurrentTexture(GPUDebugBuffer &buffer, int level, bool *isFramebuffer) {
+ if (!gstate.isTextureMapEnabled()) {
+ return false;
+ }
+ return textureCache_->GetCurrentTextureDebug(buffer, level, isFramebuffer);
+}
+
+void GPUCommonHW::CheckDepthUsage(VirtualFramebuffer *vfb) {
+ if (!gstate_c.usingDepth) {
+ bool isReadingDepth = false;
+ bool isClearingDepth = false;
+ bool isWritingDepth = false;
+ if (gstate.isModeClear()) {
+ isClearingDepth = gstate.isClearModeDepthMask();
+ isWritingDepth = isClearingDepth;
+ } else if (gstate.isDepthTestEnabled()) {
+ isWritingDepth = gstate.isDepthWriteEnabled();
+ isReadingDepth = gstate.getDepthTestFunction() > GE_COMP_ALWAYS;
+ }
+
+ if (isWritingDepth || isReadingDepth) {
+ gstate_c.usingDepth = true;
+ gstate_c.clearingDepth = isClearingDepth;
+ vfb->last_frame_depth_render = gpuStats.numFlips;
+ if (isWritingDepth) {
+ vfb->last_frame_depth_updated = gpuStats.numFlips;
+ }
+ framebufferManager_->SetDepthFrameBuffer(isClearingDepth);
+ }
+ }
+}
+
+void GPUCommonHW::InvalidateCache(u32 addr, int size, GPUInvalidationType type) {
+ if (size > 0)
+ textureCache_->Invalidate(addr, size, type);
+ else
+ textureCache_->InvalidateAll(type);
+
+ if (type != GPU_INVALIDATE_ALL && framebufferManager_->MayIntersectFramebuffer(addr)) {
+ // Vempire invalidates (with writeback) after drawing, but before blitting.
+ // TODO: Investigate whether we can get this to work some other way.
+ if (type == GPU_INVALIDATE_SAFE) {
+ framebufferManager_->UpdateFromMemory(addr, size);
+ }
+ }
+}
+
+bool GPUCommonHW::FramebufferDirty() {
+ VirtualFramebuffer *vfb = framebufferManager_->GetDisplayVFB();
+ if (vfb) {
+ bool dirty = vfb->dirtyAfterDisplay;
+ vfb->dirtyAfterDisplay = false;
+ return dirty;
+ }
+ return true;
+}
+
+bool GPUCommonHW::FramebufferReallyDirty() {
+ VirtualFramebuffer *vfb = framebufferManager_->GetDisplayVFB();
+ if (vfb) {
+ bool dirty = vfb->reallyDirtyAfterDisplay;
+ vfb->reallyDirtyAfterDisplay = false;
+ return dirty;
+ }
+ return true;
+}
+
+void GPUCommonHW::ExecuteOp(u32 op, u32 diff) {
+ const u8 cmd = op >> 24;
+ const CommandInfo info = cmdInfo_[cmd];
+ const u8 cmdFlags = info.flags;
+ if ((cmdFlags & FLAG_EXECUTE) || (diff && (cmdFlags & FLAG_EXECUTEONCHANGE))) {
+ (this->*info.func)(op, diff);
+ } else if (diff) {
+ uint64_t dirty = info.flags >> 8;
+ if (dirty)
+ gstate_c.Dirty(dirty);
+ }
+}
+
+void GPUCommonHW::FastRunLoop(DisplayList &list) {
+ PROFILE_THIS_SCOPE("gpuloop");
+
+ if (!Memory::IsValidAddress(list.pc)) {
+ // We're having some serious problems here, just bail and try to limp along and not crash the app.
+ downcount = 0;
+ return;
+ }
+
+ const CommandInfo *cmdInfo = cmdInfo_;
+ int dc = downcount;
+ for (; dc > 0; --dc) {
+ // We know that display list PCs have the upper nibble == 0 - no need to mask the pointer
+ const u32 op = *(const u32_le *)(Memory::base + list.pc);
+ const u32 cmd = op >> 24;
+ const CommandInfo &info = cmdInfo[cmd];
+ const u32 diff = op ^ gstate.cmdmem[cmd];
+ if (diff == 0) {
+ if (info.flags & FLAG_EXECUTE) {
+ downcount = dc;
+ (this->*info.func)(op, diff);
+ dc = downcount;
+ }
+ } else {
+ uint64_t flags = info.flags;
+ if (flags & FLAG_FLUSHBEFOREONCHANGE) {
+ if (drawEngineCommon_->GetNumDrawCalls()) {
+ drawEngineCommon_->DispatchFlush();
+ }
+ }
+ gstate.cmdmem[cmd] = op;
+ if (flags & (FLAG_EXECUTE | FLAG_EXECUTEONCHANGE)) {
+ downcount = dc;
+ (this->*info.func)(op, diff);
+ dc = downcount;
+ } else {
+ uint64_t dirty = flags >> 8;
+ if (dirty)
+ gstate_c.Dirty(dirty);
+ }
+ }
+ list.pc += 4;
+ }
+ downcount = 0;
+}
+
+void GPUCommonHW::Execute_VertexType(u32 op, u32 diff) {
+ if (diff)
+ gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
+ if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK)) {
+ gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
+ // Switching between through and non-through, we need to invalidate a bunch of stuff.
+ if (diff & GE_VTYPE_THROUGH_MASK)
+ gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE | DIRTY_CULLRANGE | DIRTY_FOGCOEFENABLE);
+ }
+}
+
+void GPUCommonHW::Execute_VertexTypeSkinning(u32 op, u32 diff) {
+ // Don't flush when weight count changes.
+ if (diff & ~GE_VTYPE_WEIGHTCOUNT_MASK) {
+ // Restore and flush
+ gstate.vertType ^= diff;
+ Flush();
+ gstate.vertType ^= diff;
+ if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK))
+ gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
+ // In this case, we may be doing weights and morphs.
+ // Update any bone matrix uniforms so it uses them correctly.
+ if ((op & GE_VTYPE_MORPHCOUNT_MASK) != 0) {
+ gstate_c.Dirty(gstate_c.deferredVertTypeDirty);
+ gstate_c.deferredVertTypeDirty = 0;
+ }
+ gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
+ }
+ if (diff & GE_VTYPE_THROUGH_MASK)
+ gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE | DIRTY_CULLRANGE | DIRTY_FOGCOEFENABLE);
+}
+
+void GPUCommonHW::Execute_Prim(u32 op, u32 diff) {
+ // This drives all drawing. All other state we just buffer up, then we apply it only
+ // when it's time to draw. As most PSP games set state redundantly ALL THE TIME, this is a huge optimization.
+
+ PROFILE_THIS_SCOPE("execprim");
+
+ u32 data = op & 0xFFFFFF;
+ u32 count = data & 0xFFFF;
+ if (count == 0)
+ return;
+ FlushImm();
+
+ // Upper bits are ignored.
+ GEPrimitiveType prim = static_cast((data >> 16) & 7);
+ SetDrawType(DRAW_PRIM, prim);
+
+ // Discard AA lines as we can't do anything that makes sense with these anyway. The SW plugin might, though.
+ if (gstate.isAntiAliasEnabled()) {
+ // Heuristic derived from discussions in #6483 and #12588.
+ // Discard AA lines in Persona 3 Portable, DOA Paradise and Summon Night 5, while still keeping AA lines in Echochrome.
+ if ((prim == GE_PRIM_LINE_STRIP || prim == GE_PRIM_LINES) && gstate.getTextureFunction() == GE_TEXFUNC_REPLACE)
+ return;
+ }
+
+ // Update cached framebuffer format.
+ // We store it in the cache so it can be modified for blue-to-alpha, next.
+ gstate_c.framebufFormat = gstate.FrameBufFormat();
+
+ if (!Memory::IsValidAddress(gstate_c.vertexAddr)) {
+ ERROR_LOG(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr);
+ return;
+ }
+
+ // See the documentation for gstate_c.blueToAlpha.
+ bool blueToAlpha = false;
+ if (PSP_CoreParameter().compat.flags().BlueToAlpha) {
+ if (gstate_c.framebufFormat == GEBufferFormat::GE_FORMAT_565 && gstate.getColorMask() == 0x0FFFFF && !gstate.isLogicOpEnabled()) {
+ blueToAlpha = true;
+ gstate_c.framebufFormat = GEBufferFormat::GE_FORMAT_4444;
+ }
+ if (blueToAlpha != gstate_c.blueToAlpha) {
+ gstate_c.blueToAlpha = blueToAlpha;
+ gstate_c.Dirty(DIRTY_FRAMEBUF | DIRTY_FRAGMENTSHADER_STATE | DIRTY_BLEND_STATE);
+ }
+ }
+
+ if (PSP_CoreParameter().compat.flags().SplitFramebufferMargin) {
+ switch (gstate.vertType & 0xFFFFFF) {
+ case 0x00800102: // through, u16 uv, u16 pos (used for the framebuffer effect in-game)
+ case 0x0080011c: // through, 8888 color, s16 pos (used for clearing in the margin of the title screen)
+ case 0x00000183: // float uv, float pos (used for drawing in the margin of the title screen)
+ // Need to re-check the framebuffer every one of these draws, to update the split if needed.
+ gstate_c.Dirty(DIRTY_FRAMEBUF);
+ }
+ }
+
+ // This also makes skipping drawing very effective.
+ VirtualFramebuffer *vfb = framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
+ if (blueToAlpha) {
+ vfb->usageFlags |= FB_USAGE_BLUE_TO_ALPHA;
+ }
+
+ // Must check this after SetRenderFrameBuffer so we know SKIPDRAW_NON_DISPLAYED_FB.
+ if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
+ // Rough estimate, not sure what's correct.
+ cyclesExecuted += EstimatePerVertexCost() * count;
+ if (gstate.isModeClear()) {
+ gpuStats.numClears++;
+ }
+ return;
+ }
+
+ CheckDepthUsage(vfb);
+
+ const void *verts = Memory::GetPointerUnchecked(gstate_c.vertexAddr);
+ const void *inds = nullptr;
+ u32 vertexType = gstate.vertType;
+ if ((vertexType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
+ u32 indexAddr = gstate_c.indexAddr;
+ if (!Memory::IsValidAddress(indexAddr)) {
+ ERROR_LOG(G3D, "Bad index address %08x!", indexAddr);
+ return;
+ }
+ inds = Memory::GetPointerUnchecked(indexAddr);
+ }
+
+ if (gstate_c.dirty & DIRTY_VERTEXSHADER_STATE) {
+ vertexCost_ = EstimatePerVertexCost();
+ }
+
+ int bytesRead = 0;
+ UpdateUVScaleOffset();
+
+ // cull mode
+ int cullMode = gstate.getCullMode();
+
+ uint32_t vertTypeID = GetVertTypeID(vertexType, gstate.getUVGenMode(), g_Config.bSoftwareSkinning);
+ drawEngineCommon_->SubmitPrim(verts, inds, prim, count, vertTypeID, cullMode, &bytesRead);
+ // After drawing, we advance the vertexAddr (when non indexed) or indexAddr (when indexed).
+ // Some games rely on this, they don't bother reloading VADDR and IADDR.
+ // The VADDR/IADDR registers are NOT updated.
+ AdvanceVerts(vertexType, count, bytesRead);
+ int totalVertCount = count;
+
+ // PRIMs are often followed by more PRIMs. Save some work and submit them immediately.
+ const u32_le *src = (const u32_le *)Memory::GetPointerUnchecked(currentList->pc + 4);
+ const u32_le *stall = currentList->stall ? (const u32_le *)Memory::GetPointerUnchecked(currentList->stall) : 0;
+ int cmdCount = 0;
+
+ // Optimized submission of sequences of PRIM. Allows us to avoid going through all the mess
+ // above for each one. This can be expanded to support additional games that intersperse
+ // PRIM commands with other commands. A special case is Earth Defence Force 2 that changes culling mode
+ // between each prim, we just change the triangle winding right here to still be able to join draw calls.
+
+ uint32_t vtypeCheckMask = ~GE_VTYPE_WEIGHTCOUNT_MASK;
+ if (!g_Config.bSoftwareSkinning)
+ vtypeCheckMask = 0xFFFFFFFF;
+
+ if (debugRecording_)
+ goto bail;
+
+ while (src != stall) {
+ uint32_t data = *src;
+ switch (data >> 24) {
+ case GE_CMD_PRIM:
+ {
+ u32 count = data & 0xFFFF;
+ if (count == 0) {
+ // Ignore.
+ break;
+ }
+
+ GEPrimitiveType newPrim = static_cast((data >> 16) & 7);
+ SetDrawType(DRAW_PRIM, newPrim);
+ // TODO: more efficient updating of verts/inds
+ verts = Memory::GetPointerUnchecked(gstate_c.vertexAddr);
+ inds = nullptr;
+ if ((vertexType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
+ inds = Memory::GetPointerUnchecked(gstate_c.indexAddr);
+ }
+
+ drawEngineCommon_->SubmitPrim(verts, inds, newPrim, count, vertTypeID, cullMode, &bytesRead);
+ AdvanceVerts(vertexType, count, bytesRead);
+ totalVertCount += count;
+ break;
+ }
+ case GE_CMD_VERTEXTYPE:
+ {
+ uint32_t diff = data ^ vertexType;
+ // don't mask upper bits, vertexType is unmasked
+ if (diff & vtypeCheckMask) {
+ goto bail;
+ } else {
+ vertexType = data;
+ vertTypeID = GetVertTypeID(vertexType, gstate.getUVGenMode(), g_Config.bSoftwareSkinning);
+ }
+ break;
+ }
+ case GE_CMD_VADDR:
+ gstate.cmdmem[GE_CMD_VADDR] = data;
+ gstate_c.vertexAddr = gstate_c.getRelativeAddress(data & 0x00FFFFFF);
+ break;
+ case GE_CMD_IADDR:
+ gstate.cmdmem[GE_CMD_IADDR] = data;
+ gstate_c.indexAddr = gstate_c.getRelativeAddress(data & 0x00FFFFFF);
+ break;
+ case GE_CMD_OFFSETADDR:
+ gstate.cmdmem[GE_CMD_OFFSETADDR] = data;
+ gstate_c.offsetAddr = data << 8;
+ break;
+ case GE_CMD_BASE:
+ gstate.cmdmem[GE_CMD_BASE] = data;
+ break;
+ case GE_CMD_CULLFACEENABLE:
+ // Earth Defence Force 2
+ if (gstate.cmdmem[GE_CMD_CULLFACEENABLE] != data) {
+ goto bail;
+ }
+ break;
+ case GE_CMD_CULL:
+ // flip face by indices for triangles
+ cullMode = data & 1;
+ break;
+ case GE_CMD_TEXFLUSH:
+ case GE_CMD_NOP:
+ case GE_CMD_NOP_FF:
+ gstate.cmdmem[data >> 24] = data;
+ break;
+ case GE_CMD_BONEMATRIXNUMBER:
+ gstate.cmdmem[GE_CMD_BONEMATRIXNUMBER] = data;
+ break;
+ case GE_CMD_TEXSCALEU:
+ gstate.cmdmem[GE_CMD_TEXSCALEU] = data;
+ gstate_c.uv.uScale = getFloat24(data);
+ break;
+ case GE_CMD_TEXSCALEV:
+ gstate.cmdmem[GE_CMD_TEXSCALEV] = data;
+ gstate_c.uv.vScale = getFloat24(data);
+ break;
+ case GE_CMD_TEXOFFSETU:
+ gstate.cmdmem[GE_CMD_TEXOFFSETU] = data;
+ gstate_c.uv.uOff = getFloat24(data);
+ break;
+ case GE_CMD_TEXOFFSETV:
+ gstate.cmdmem[GE_CMD_TEXOFFSETV] = data;
+ gstate_c.uv.vOff = getFloat24(data);
+ break;
+ case GE_CMD_TEXLEVEL:
+ // Same Gran Turismo hack from Execute_TexLevel
+ if ((data & 3) != GE_TEXLEVEL_MODE_AUTO && (0x00FF0000 & data) != 0) {
+ goto bail;
+ }
+ gstate.cmdmem[GE_CMD_TEXLEVEL] = data;
+ break;
+ case GE_CMD_CALL:
+ {
+ // A bone matrix probably. If not we bail.
+ const u32 target = gstate_c.getRelativeAddress(data & 0x00FFFFFC);
+ if ((Memory::ReadUnchecked_U32(target) >> 24) == GE_CMD_BONEMATRIXDATA &&
+ (Memory::ReadUnchecked_U32(target + 11 * 4) >> 24) == GE_CMD_BONEMATRIXDATA &&
+ (Memory::ReadUnchecked_U32(target + 12 * 4) >> 24) == GE_CMD_RET &&
+ (target > currentList->stall || target + 12 * 4 < currentList->stall) &&
+ (gstate.boneMatrixNumber & 0x00FFFFFF) <= 96 - 12) {
+ FastLoadBoneMatrix(target);
+ } else {
+ goto bail;
+ }
+ break;
+ }
+
+ case GE_CMD_TEXBUFWIDTH0:
+ case GE_CMD_TEXADDR0:
+ if (data != gstate.cmdmem[data >> 24])
+ goto bail;
+ break;
+
+ default:
+ // All other commands might need a flush or something, stop this inner loop.
+ goto bail;
+ }
+ cmdCount++;
+ src++;
+ }
+
+bail:
+ gstate.cmdmem[GE_CMD_VERTEXTYPE] = vertexType;
+ // Skip over the commands we just read out manually.
+ if (cmdCount > 0) {
+ UpdatePC(currentList->pc, currentList->pc + cmdCount * 4);
+ currentList->pc += cmdCount * 4;
+ // flush back cull mode
+ if (cullMode != gstate.getCullMode()) {
+ // We rewrote everything to the old cull mode, so flush first.
+ drawEngineCommon_->DispatchFlush();
+
+ // Now update things for next time.
+ gstate.cmdmem[GE_CMD_CULL] ^= 1;
+ gstate_c.Dirty(DIRTY_RASTER_STATE);
+ }
+ }
+
+ gpuStats.vertexGPUCycles += vertexCost_ * totalVertCount;
+ cyclesExecuted += vertexCost_ * totalVertCount;
+}
+
+void GPUCommonHW::Execute_Bezier(u32 op, u32 diff) {
+ // We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
+ gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
+
+ gstate_c.framebufFormat = gstate.FrameBufFormat();
+
+ // This also make skipping drawing very effective.
+ VirtualFramebuffer *vfb = framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
+ if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
+ // TODO: Should this eat some cycles? Probably yes. Not sure if important.
+ return;
+ }
+
+ CheckDepthUsage(vfb);
+
+ if (!Memory::IsValidAddress(gstate_c.vertexAddr)) {
+ ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr);
+ return;
+ }
+
+ const void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr);
+ const void *indices = NULL;
+ if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
+ if (!Memory::IsValidAddress(gstate_c.indexAddr)) {
+ ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr);
+ return;
+ }
+ indices = Memory::GetPointerUnchecked(gstate_c.indexAddr);
+ }
+
+ if (vertTypeIsSkinningEnabled(gstate.vertType)) {
+ DEBUG_LOG_REPORT(G3D, "Unusual bezier/spline vtype: %08x, morph: %d, bones: %d", gstate.vertType, (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT, vertTypeGetNumBoneWeights(gstate.vertType));
+ }
+
+ // Can't flush after setting gstate_c.submitType below since it'll be a mess - it must be done already.
+ if (flushOnParams_)
+ drawEngineCommon_->DispatchFlush();
+
+ Spline::BezierSurface surface;
+ surface.tess_u = gstate.getPatchDivisionU();
+ surface.tess_v = gstate.getPatchDivisionV();
+ surface.num_points_u = op & 0xFF;
+ surface.num_points_v = (op >> 8) & 0xFF;
+ surface.num_patches_u = (surface.num_points_u - 1) / 3;
+ surface.num_patches_v = (surface.num_points_v - 1) / 3;
+ surface.primType = gstate.getPatchPrimitiveType();
+ surface.patchFacing = gstate.patchfacing & 1;
+
+ SetDrawType(DRAW_BEZIER, PatchPrimToPrim(surface.primType));
+
+ gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
+ if (drawEngineCommon_->CanUseHardwareTessellation(surface.primType)) {
+ gstate_c.submitType = SubmitType::HW_BEZIER;
+ if (gstate_c.spline_num_points_u != surface.num_points_u) {
+ gstate_c.Dirty(DIRTY_BEZIERSPLINE);
+ gstate_c.spline_num_points_u = surface.num_points_u;
+ }
+ } else {
+ gstate_c.submitType = SubmitType::BEZIER;
+ }
+
+ int bytesRead = 0;
+ UpdateUVScaleOffset();
+ drawEngineCommon_->SubmitCurve(control_points, indices, surface, gstate.vertType, &bytesRead, "bezier");
+
+ gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
+ gstate_c.submitType = SubmitType::DRAW;
+
+ // After drawing, we advance pointers - see SubmitPrim which does the same.
+ int count = surface.num_points_u * surface.num_points_v;
+ AdvanceVerts(gstate.vertType, count, bytesRead);
+}
+
+void GPUCommonHW::Execute_Spline(u32 op, u32 diff) {
+ // We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
+ gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
+
+ gstate_c.framebufFormat = gstate.FrameBufFormat();
+
+ // This also make skipping drawing very effective.
+ VirtualFramebuffer *vfb = framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
+ if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
+ // TODO: Should this eat some cycles? Probably yes. Not sure if important.
+ return;
+ }
+
+ CheckDepthUsage(vfb);
+
+ if (!Memory::IsValidAddress(gstate_c.vertexAddr)) {
+ ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr);
+ return;
+ }
+
+ const void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr);
+ const void *indices = NULL;
+ if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
+ if (!Memory::IsValidAddress(gstate_c.indexAddr)) {
+ ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr);
+ return;
+ }
+ indices = Memory::GetPointerUnchecked(gstate_c.indexAddr);
+ }
+
+ if (vertTypeIsSkinningEnabled(gstate.vertType)) {
+ DEBUG_LOG_REPORT(G3D, "Unusual bezier/spline vtype: %08x, morph: %d, bones: %d", gstate.vertType, (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT, vertTypeGetNumBoneWeights(gstate.vertType));
+ }
+
+ // Can't flush after setting gstate_c.submitType below since it'll be a mess - it must be done already.
+ if (flushOnParams_)
+ drawEngineCommon_->DispatchFlush();
+
+ Spline::SplineSurface surface;
+ surface.tess_u = gstate.getPatchDivisionU();
+ surface.tess_v = gstate.getPatchDivisionV();
+ surface.type_u = (op >> 16) & 0x3;
+ surface.type_v = (op >> 18) & 0x3;
+ surface.num_points_u = op & 0xFF;
+ surface.num_points_v = (op >> 8) & 0xFF;
+ surface.num_patches_u = surface.num_points_u - 3;
+ surface.num_patches_v = surface.num_points_v - 3;
+ surface.primType = gstate.getPatchPrimitiveType();
+ surface.patchFacing = gstate.patchfacing & 1;
+
+ SetDrawType(DRAW_SPLINE, PatchPrimToPrim(surface.primType));
+
+ gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
+ if (drawEngineCommon_->CanUseHardwareTessellation(surface.primType)) {
+ gstate_c.submitType = SubmitType::HW_SPLINE;
+ if (gstate_c.spline_num_points_u != surface.num_points_u) {
+ gstate_c.Dirty(DIRTY_BEZIERSPLINE);
+ gstate_c.spline_num_points_u = surface.num_points_u;
+ }
+ } else {
+ gstate_c.submitType = SubmitType::SPLINE;
+ }
+
+ int bytesRead = 0;
+ UpdateUVScaleOffset();
+ drawEngineCommon_->SubmitCurve(control_points, indices, surface, gstate.vertType, &bytesRead, "spline");
+
+ gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
+ gstate_c.submitType = SubmitType::DRAW;
+
+ // After drawing, we advance pointers - see SubmitPrim which does the same.
+ int count = surface.num_points_u * surface.num_points_v;
+ AdvanceVerts(gstate.vertType, count, bytesRead);
+}
+
+void GPUCommonHW::Execute_BlockTransferStart(u32 op, u32 diff) {
+ Flush();
+
+ PROFILE_THIS_SCOPE("block"); // don't include the flush in the profile, would be misleading.
+
+ gstate_c.framebufFormat = gstate.FrameBufFormat();
+
+ // and take appropriate action. This is a block transfer between RAM and VRAM, or vice versa.
+ // Can we skip this on SkipDraw?
+ DoBlockTransfer(gstate_c.skipDrawReason);
+}
+
+void GPUCommonHW::Execute_TexSize0(u32 op, u32 diff) {
+ // Render to texture may have overridden the width/height.
+ // Don't reset it unless the size is different / the texture has changed.
+ if (diff || gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS)) {
+ gstate_c.curTextureWidth = gstate.getTextureWidth(0);
+ gstate_c.curTextureHeight = gstate.getTextureHeight(0);
+ gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
+ // We will need to reset the texture now.
+ gstate_c.Dirty(DIRTY_TEXTURE_PARAMS);
+ }
+}
+
+void GPUCommonHW::Execute_TexLevel(u32 op, u32 diff) {
+ // TODO: If you change the rules here, don't forget to update the inner interpreter in Execute_Prim.
+ if (diff == 0xFFFFFFFF)
+ return;
+
+ gstate.texlevel ^= diff;
+
+ if (diff & 0xFF0000) {
+ // Piggyback on this flag for 3D textures.
+ gstate_c.Dirty(DIRTY_MIPBIAS);
+ }
+ if (gstate.getTexLevelMode() != GE_TEXLEVEL_MODE_AUTO && (0x00FF0000 & gstate.texlevel) != 0) {
+ Flush();
+ }
+
+ gstate.texlevel ^= diff;
+
+ gstate_c.Dirty(DIRTY_TEXTURE_PARAMS | DIRTY_FRAGMENTSHADER_STATE);
+}
+
+void GPUCommonHW::Execute_LoadClut(u32 op, u32 diff) {
+ gstate_c.Dirty(DIRTY_TEXTURE_PARAMS);
+ textureCache_->LoadClut(gstate.getClutAddress(), gstate.getClutLoadBytes());
+}
+
+
+void GPUCommonHW::Execute_WorldMtxNum(u32 op, u32 diff) {
+ if (!currentList) {
+ gstate.worldmtxnum = (GE_CMD_WORLDMATRIXNUMBER << 24) | (op & 0xF);
+ return;
+ }
+
+ // This is almost always followed by GE_CMD_WORLDMATRIXDATA.
+ const u32_le *src = (const u32_le *)Memory::GetPointerUnchecked(currentList->pc + 4);
+ u32 *dst = (u32 *)(gstate.worldMatrix + (op & 0xF));
+ const int end = 12 - (op & 0xF);
+ int i = 0;
+
+ // We must record the individual data commands while debugRecording_.
+ bool fastLoad = !debugRecording_ && end > 0;
+ // Stalling in the middle of a matrix would be stupid, I doubt this check is necessary.
+ if (currentList->pc < currentList->stall && currentList->pc + end * 4 >= currentList->stall) {
+ fastLoad = false;
+ }
+
+ if (fastLoad) {
+ while ((src[i] >> 24) == GE_CMD_WORLDMATRIXDATA) {
+ const u32 newVal = src[i] << 8;
+ if (dst[i] != newVal) {
+ Flush();
+ dst[i] = newVal;
+ gstate_c.Dirty(DIRTY_WORLDMATRIX);
+ }
+ if (++i >= end) {
+ break;
+ }
+ }
+ }
+
+ const int count = i;
+ gstate.worldmtxnum = (GE_CMD_WORLDMATRIXNUMBER << 24) | ((op & 0xF) + count);
+
+ // Skip over the loaded data, it's done now.
+ UpdatePC(currentList->pc, currentList->pc + count * 4);
+ currentList->pc += count * 4;
+}
+
+void GPUCommonHW::Execute_WorldMtxData(u32 op, u32 diff) {
+ // Note: it's uncommon to get here now, see above.
+ int num = gstate.worldmtxnum & 0x00FFFFFF;
+ u32 newVal = op << 8;
+ if (num < 12 && newVal != ((const u32 *)gstate.worldMatrix)[num]) {
+ Flush();
+ ((u32 *)gstate.worldMatrix)[num] = newVal;
+ gstate_c.Dirty(DIRTY_WORLDMATRIX);
+ }
+ num++;
+ gstate.worldmtxnum = (GE_CMD_WORLDMATRIXNUMBER << 24) | (num & 0x00FFFFFF);
+ gstate.worldmtxdata = GE_CMD_WORLDMATRIXDATA << 24;
+}
+
+void GPUCommonHW::Execute_ViewMtxNum(u32 op, u32 diff) {
+ if (!currentList) {
+ gstate.viewmtxnum = (GE_CMD_VIEWMATRIXNUMBER << 24) | (op & 0xF);
+ return;
+ }
+
+ // This is almost always followed by GE_CMD_VIEWMATRIXDATA.
+ const u32_le *src = (const u32_le *)Memory::GetPointerUnchecked(currentList->pc + 4);
+ u32 *dst = (u32 *)(gstate.viewMatrix + (op & 0xF));
+ const int end = 12 - (op & 0xF);
+ int i = 0;
+
+ bool fastLoad = !debugRecording_ && end > 0;
+ if (currentList->pc < currentList->stall && currentList->pc + end * 4 >= currentList->stall) {
+ fastLoad = false;
+ }
+
+ if (fastLoad) {
+ while ((src[i] >> 24) == GE_CMD_VIEWMATRIXDATA) {
+ const u32 newVal = src[i] << 8;
+ if (dst[i] != newVal) {
+ Flush();
+ dst[i] = newVal;
+ gstate_c.Dirty(DIRTY_VIEWMATRIX);
+ }
+ if (++i >= end) {
+ break;
+ }
+ }
+ }
+
+ const int count = i;
+ gstate.viewmtxnum = (GE_CMD_VIEWMATRIXNUMBER << 24) | ((op & 0xF) + count);
+
+ // Skip over the loaded data, it's done now.
+ UpdatePC(currentList->pc, currentList->pc + count * 4);
+ currentList->pc += count * 4;
+}
+
+void GPUCommonHW::Execute_ViewMtxData(u32 op, u32 diff) {
+ // Note: it's uncommon to get here now, see above.
+ int num = gstate.viewmtxnum & 0x00FFFFFF;
+ u32 newVal = op << 8;
+ if (num < 12 && newVal != ((const u32 *)gstate.viewMatrix)[num]) {
+ Flush();
+ ((u32 *)gstate.viewMatrix)[num] = newVal;
+ gstate_c.Dirty(DIRTY_VIEWMATRIX);
+ }
+ num++;
+ gstate.viewmtxnum = (GE_CMD_VIEWMATRIXNUMBER << 24) | (num & 0x00FFFFFF);
+ gstate.viewmtxdata = GE_CMD_VIEWMATRIXDATA << 24;
+}
+
+void GPUCommonHW::Execute_ProjMtxNum(u32 op, u32 diff) {
+ if (!currentList) {
+ gstate.projmtxnum = (GE_CMD_PROJMATRIXNUMBER << 24) | (op & 0xF);
+ return;
+ }
+
+ // This is almost always followed by GE_CMD_PROJMATRIXDATA.
+ const u32_le *src = (const u32_le *)Memory::GetPointerUnchecked(currentList->pc + 4);
+ u32 *dst = (u32 *)(gstate.projMatrix + (op & 0xF));
+ const int end = 16 - (op & 0xF);
+ int i = 0;
+
+ bool fastLoad = !debugRecording_;
+ if (currentList->pc < currentList->stall && currentList->pc + end * 4 >= currentList->stall) {
+ fastLoad = false;
+ }
+
+ if (fastLoad) {
+ while ((src[i] >> 24) == GE_CMD_PROJMATRIXDATA) {
+ const u32 newVal = src[i] << 8;
+ if (dst[i] != newVal) {
+ Flush();
+ dst[i] = newVal;
+ gstate_c.Dirty(DIRTY_PROJMATRIX);
+ }
+ if (++i >= end) {
+ break;
+ }
+ }
+ }
+
+ const int count = i;
+ gstate.projmtxnum = (GE_CMD_PROJMATRIXNUMBER << 24) | ((op & 0xF) + count);
+
+ // Skip over the loaded data, it's done now.
+ UpdatePC(currentList->pc, currentList->pc + count * 4);
+ currentList->pc += count * 4;
+}
+
+void GPUCommonHW::Execute_ProjMtxData(u32 op, u32 diff) {
+ // Note: it's uncommon to get here now, see above.
+ int num = gstate.projmtxnum & 0x00FFFFFF;
+ u32 newVal = op << 8;
+ if (num < 16 && newVal != ((const u32 *)gstate.projMatrix)[num]) {
+ Flush();
+ ((u32 *)gstate.projMatrix)[num] = newVal;
+ gstate_c.Dirty(DIRTY_PROJMATRIX);
+ }
+ num++;
+ if (num <= 16)
+ gstate.projmtxnum = (GE_CMD_PROJMATRIXNUMBER << 24) | (num & 0x00FFFFFF);
+ gstate.projmtxdata = GE_CMD_PROJMATRIXDATA << 24;
+}
+
+void GPUCommonHW::Execute_TgenMtxNum(u32 op, u32 diff) {
+ if (!currentList) {
+ gstate.texmtxnum = (GE_CMD_TGENMATRIXNUMBER << 24) | (op & 0xF);
+ return;
+ }
+
+ // This is almost always followed by GE_CMD_TGENMATRIXDATA.
+ const u32_le *src = (const u32_le *)Memory::GetPointerUnchecked(currentList->pc + 4);
+ u32 *dst = (u32 *)(gstate.tgenMatrix + (op & 0xF));
+ const int end = 12 - (op & 0xF);
+ int i = 0;
+
+ bool fastLoad = !debugRecording_ && end > 0;
+ if (currentList->pc < currentList->stall && currentList->pc + end * 4 >= currentList->stall) {
+ fastLoad = false;
+ }
+
+ if (fastLoad) {
+ while ((src[i] >> 24) == GE_CMD_TGENMATRIXDATA) {
+ const u32 newVal = src[i] << 8;
+ if (dst[i] != newVal) {
+ Flush();
+ dst[i] = newVal;
+ // We check the matrix to see if we need projection.
+ gstate_c.Dirty(DIRTY_TEXMATRIX | DIRTY_FRAGMENTSHADER_STATE);
+ }
+ if (++i >= end) {
+ break;
+ }
+ }
+ }
+
+ const int count = i;
+ gstate.texmtxnum = (GE_CMD_TGENMATRIXNUMBER << 24) | ((op & 0xF) + count);
+
+ // Skip over the loaded data, it's done now.
+ UpdatePC(currentList->pc, currentList->pc + count * 4);
+ currentList->pc += count * 4;
+}
+
+void GPUCommonHW::Execute_TgenMtxData(u32 op, u32 diff) {
+ // Note: it's uncommon to get here now, see above.
+ int num = gstate.texmtxnum & 0x00FFFFFF;
+ u32 newVal = op << 8;
+ if (num < 12 && newVal != ((const u32 *)gstate.tgenMatrix)[num]) {
+ Flush();
+ ((u32 *)gstate.tgenMatrix)[num] = newVal;
+ gstate_c.Dirty(DIRTY_TEXMATRIX | DIRTY_FRAGMENTSHADER_STATE); // We check the matrix to see if we need projection
+ }
+ num++;
+ gstate.texmtxnum = (GE_CMD_TGENMATRIXNUMBER << 24) | (num & 0x00FFFFFF);
+ gstate.texmtxdata = GE_CMD_TGENMATRIXDATA << 24;
+}
+
+void GPUCommonHW::Execute_BoneMtxNum(u32 op, u32 diff) {
+ if (!currentList) {
+ gstate.boneMatrixNumber = (GE_CMD_BONEMATRIXNUMBER << 24) | (op & 0x7F);
+ return;
+ }
+
+ // This is almost always followed by GE_CMD_BONEMATRIXDATA.
+ const u32_le *src = (const u32_le *)Memory::GetPointerUnchecked(currentList->pc + 4);
+ u32 *dst = (u32 *)(gstate.boneMatrix + (op & 0x7F));
+ const int end = 12 * 8 - (op & 0x7F);
+ int i = 0;
+
+ bool fastLoad = !debugRecording_ && end > 0;
+ if (currentList->pc < currentList->stall && currentList->pc + end * 4 >= currentList->stall) {
+ fastLoad = false;
+ }
+
+ if (fastLoad) {
+ // If we can't use software skinning, we have to flush and dirty.
+ if (!g_Config.bSoftwareSkinning) {
+ while ((src[i] >> 24) == GE_CMD_BONEMATRIXDATA) {
+ const u32 newVal = src[i] << 8;
+ if (dst[i] != newVal) {
+ Flush();
+ dst[i] = newVal;
+ }
+ if (++i >= end) {
+ break;
+ }
+ }
+
+ const unsigned int numPlusCount = (op & 0x7F) + i;
+ for (unsigned int num = op & 0x7F; num < numPlusCount; num += 12) {
+ gstate_c.Dirty(DIRTY_BONEMATRIX0 << (num / 12));
+ }
+ } else {
+ while ((src[i] >> 24) == GE_CMD_BONEMATRIXDATA) {
+ dst[i] = src[i] << 8;
+ if (++i >= end) {
+ break;
+ }
+ }
+
+ const unsigned int numPlusCount = (op & 0x7F) + i;
+ for (unsigned int num = op & 0x7F; num < numPlusCount; num += 12) {
+ gstate_c.deferredVertTypeDirty |= DIRTY_BONEMATRIX0 << (num / 12);
+ }
+ }
+ }
+
+ const int count = i;
+ gstate.boneMatrixNumber = (GE_CMD_BONEMATRIXNUMBER << 24) | ((op & 0x7F) + count);
+
+ // Skip over the loaded data, it's done now.
+ UpdatePC(currentList->pc, currentList->pc + count * 4);
+ currentList->pc += count * 4;
+}
+
+void GPUCommonHW::Execute_BoneMtxData(u32 op, u32 diff) {
+ // Note: it's uncommon to get here now, see above.
+ int num = gstate.boneMatrixNumber & 0x00FFFFFF;
+ u32 newVal = op << 8;
+ if (num < 96 && newVal != ((const u32 *)gstate.boneMatrix)[num]) {
+ // Bone matrices should NOT flush when software skinning is enabled!
+ if (!g_Config.bSoftwareSkinning) {
+ Flush();
+ gstate_c.Dirty(DIRTY_BONEMATRIX0 << (num / 12));
+ } else {
+ gstate_c.deferredVertTypeDirty |= DIRTY_BONEMATRIX0 << (num / 12);
+ }
+ ((u32 *)gstate.boneMatrix)[num] = newVal;
+ }
+ num++;
+ gstate.boneMatrixNumber = (GE_CMD_BONEMATRIXNUMBER << 24) | (num & 0x00FFFFFF);
+ gstate.boneMatrixData = GE_CMD_BONEMATRIXDATA << 24;
+}
+
+void GPUCommonHW::Execute_TexFlush(u32 op, u32 diff) {
+ // Games call this when they need the effect of drawing to be visible to texturing.
+ // And for a bunch of other reasons, but either way, this is what we need to do.
+ // It's possible we could also use this as a hint for the texture cache somehow.
+ framebufferManager_->DiscardFramebufferCopy();
+}
+
+size_t GPUCommonHW::FormatGPUStatsCommon(char *buffer, size_t size) {
+ float vertexAverageCycles = gpuStats.numVertsSubmitted > 0 ? (float)gpuStats.vertexGPUCycles / (float)gpuStats.numVertsSubmitted : 0.0f;
+ return snprintf(buffer, size,
+ "DL processing time: %0.2f ms, %d drawsync, %d listsync\n"
+ "Draw calls: %d, flushes %d, clears %d (cached: %d)\n"
+ "Num Tracked Vertex Arrays: %d\n"
+ "Vertices: %d cached: %d uncached: %d\n"
+ "FBOs active: %d (evaluations: %d)\n"
+ "Textures: %d, dec: %d, invalidated: %d, hashed: %d kB\n"
+ "readbacks %d (%d non-block), uploads %d, depal %d\n"
+ "replacer: tracks %d textures, %d unique loaded\n"
+ "Copies: depth %d, color %d, reint %d, blend %d, selftex %d\n"
+ "GPU cycles executed: %d (%f per vertex)\n",
+ gpuStats.msProcessingDisplayLists * 1000.0f,
+ gpuStats.numDrawSyncs,
+ gpuStats.numListSyncs,
+ gpuStats.numDrawCalls,
+ gpuStats.numFlushes,
+ gpuStats.numClears,
+ gpuStats.numCachedDrawCalls,
+ gpuStats.numTrackedVertexArrays,
+ gpuStats.numVertsSubmitted,
+ gpuStats.numCachedVertsDrawn,
+ gpuStats.numUncachedVertsDrawn,
+ (int)framebufferManager_->NumVFBs(),
+ gpuStats.numFramebufferEvaluations,
+ (int)textureCache_->NumLoadedTextures(),
+ gpuStats.numTexturesDecoded,
+ gpuStats.numTextureInvalidations,
+ gpuStats.numTextureDataBytesHashed / 1024,
+ gpuStats.numBlockingReadbacks,
+ gpuStats.numReadbacks,
+ gpuStats.numUploads,
+ gpuStats.numDepal,
+ gpuStats.numReplacerTrackedTex,
+ gpuStats.numCachedReplacedTextures,
+ gpuStats.numDepthCopies,
+ gpuStats.numColorCopies,
+ gpuStats.numReinterpretCopies,
+ gpuStats.numCopiesForShaderBlend,
+ gpuStats.numCopiesForSelfTex,
+ gpuStats.vertexGPUCycles + gpuStats.otherGPUCycles,
+ vertexAverageCycles
+ );
+}
diff --git a/GPU/GPUCommonHW.h b/GPU/GPUCommonHW.h
new file mode 100644
index 0000000000..000993be79
--- /dev/null
+++ b/GPU/GPUCommonHW.h
@@ -0,0 +1,91 @@
+#pragma once
+
+#include "GPUCommon.h"
+
+// Shared GPUCommon implementation for the HW backends.
+// Things that are irrelevant for SoftGPU should live here.
+class GPUCommonHW : public GPUCommon {
+public:
+ GPUCommonHW(GraphicsContext *gfxCtx, Draw::DrawContext *draw);
+ ~GPUCommonHW();
+
+ void CopyDisplayToOutput(bool reallyDirty) override;
+ void DoState(PointerWrap &p) override;
+ void DeviceLost() override;
+ void DeviceRestore(Draw::DrawContext *draw) override;
+
+ void BeginFrame() override;
+
+ u32 CheckGPUFeatures() const override;
+
+ // From GPUDebugInterface.
+ bool GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) override;
+ bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer) override;
+ bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer) override;
+ bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override;
+ std::vector GetFramebufferList() const override;
+ bool GetCurrentTexture(GPUDebugBuffer &buffer, int level, bool *isFramebuffer) override;
+ bool GetCurrentClut(GPUDebugBuffer &buffer) override;
+
+ // Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend.
+ std::vector DebugGetShaderIDs(DebugShaderType shader) override;
+ std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override;
+
+ void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override;
+ void InvalidateCache(u32 addr, int size, GPUInvalidationType type) override;
+
+ bool FramebufferDirty() override;
+ bool FramebufferReallyDirty() override;
+
+ void Execute_VertexType(u32 op, u32 diff);
+ void Execute_VertexTypeSkinning(u32 op, u32 diff);
+
+ void Execute_Prim(u32 op, u32 diff);
+ void Execute_Bezier(u32 op, u32 diff);
+ void Execute_Spline(u32 op, u32 diff);
+ void Execute_BlockTransferStart(u32 op, u32 diff);
+
+ void Execute_TexSize0(u32 op, u32 diff);
+ void Execute_TexLevel(u32 op, u32 diff);
+ void Execute_LoadClut(u32 op, u32 diff);
+
+ void Execute_WorldMtxNum(u32 op, u32 diff);
+ void Execute_WorldMtxData(u32 op, u32 diff);
+ void Execute_ViewMtxNum(u32 op, u32 diff);
+ void Execute_ViewMtxData(u32 op, u32 diff);
+ void Execute_ProjMtxNum(u32 op, u32 diff);
+ void Execute_ProjMtxData(u32 op, u32 diff);
+ void Execute_TgenMtxNum(u32 op, u32 diff);
+ void Execute_TgenMtxData(u32 op, u32 diff);
+ void Execute_BoneMtxNum(u32 op, u32 diff);
+ void Execute_BoneMtxData(u32 op, u32 diff);
+
+ void Execute_TexFlush(u32 op, u32 diff);
+
+ typedef void (GPUCommonHW::*CmdFunc)(u32 op, u32 diff);
+
+ void FastRunLoop(DisplayList &list) override;
+ void ExecuteOp(u32 op, u32 diff) override;
+
+private:
+ void CheckDepthUsage(VirtualFramebuffer *vfb);
+ void CheckFlushOp(int cmd, u32 diff);
+
+protected:
+ size_t FormatGPUStatsCommon(char *buf, size_t size);
+ void UpdateCmdInfo() override;
+
+ void PreExecuteOp(u32 op, u32 diff) override;
+ void ClearCacheNextFrame() override;
+
+ // Needs to be called on GPU thread, not reporting thread.
+ void BuildReportingInfo() override;
+ void UpdateMSAALevel(Draw::DrawContext *draw) override;
+
+ void CheckRenderResized() override;
+ u32 CheckGPUFeaturesLate(u32 features) const;
+
+ int msaaLevel_ = 0;
+ bool sawExactEqualDepth_ = false;
+ ShaderManagerCommon *shaderManager_ = nullptr;
+};
diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h
index 2e1af82a66..6788e595d7 100644
--- a/GPU/GPUInterface.h
+++ b/GPU/GPUInterface.h
@@ -192,7 +192,6 @@ public:
virtual bool IsReady() = 0;
virtual void CancelReady() = 0;
virtual bool IsStarted() = 0;
- virtual void InitClear() = 0;
virtual void Reinitialize() = 0;
// Frame managment
@@ -221,7 +220,6 @@ public:
virtual void InterruptEnd(int listid) = 0;
virtual void SyncEnd(GPUSyncType waitType, int listid, bool wokeThreads) = 0;
- virtual void PreExecuteOp(u32 op, u32 diff) = 0;
virtual void ExecuteOp(u32 op, u32 diff) = 0;
// Framebuffer management
@@ -253,7 +251,7 @@ public:
virtual void EnableInterrupts(bool enable) = 0;
virtual void DeviceLost() = 0;
- virtual void DeviceRestore() = 0;
+ virtual void DeviceRestore(Draw::DrawContext *draw) = 0;
virtual void ReapplyGfxState() = 0;
virtual void DoState(PointerWrap &p) = 0;
diff --git a/GPU/Software/DrawPixel.cpp b/GPU/Software/DrawPixel.cpp
index 72b6e2a91a..eda04b0b41 100644
--- a/GPU/Software/DrawPixel.cpp
+++ b/GPU/Software/DrawPixel.cpp
@@ -802,10 +802,12 @@ SingleFunc PixelJitCache::GenericSingle(const PixelFuncID &id) {
}
thread_local PixelJitCache::LastCache PixelJitCache::lastSingle_;
+int PixelJitCache::clearGen_ = 0;
// 256k should be plenty of space for plenty of variations.
PixelJitCache::PixelJitCache() : CodeBlock(1024 * 64 * 4), cache_(64) {
lastSingle_.gen = -1;
+ clearGen_++;
}
void PixelJitCache::Clear() {
diff --git a/GPU/Software/DrawPixel.h b/GPU/Software/DrawPixel.h
index d72c04a744..b0eae46ac6 100644
--- a/GPU/Software/DrawPixel.h
+++ b/GPU/Software/DrawPixel.h
@@ -128,7 +128,7 @@ private:
DenseHashMap cache_;
std::unordered_map addresses_;
std::unordered_set compileQueue_;
- int clearGen_ = 0;
+ static int clearGen_;
static thread_local LastCache lastSingle_;
const u8 *constBlendHalf_11_4s_ = nullptr;
diff --git a/GPU/Software/Sampler.cpp b/GPU/Software/Sampler.cpp
index dd022c5efd..eef759344f 100644
--- a/GPU/Software/Sampler.cpp
+++ b/GPU/Software/Sampler.cpp
@@ -109,12 +109,14 @@ FetchFunc GetFetchFunc(SamplerID id, BinManager *binner) {
thread_local SamplerJitCache::LastCache SamplerJitCache::lastFetch_;
thread_local SamplerJitCache::LastCache SamplerJitCache::lastNearest_;
thread_local SamplerJitCache::LastCache SamplerJitCache::lastLinear_;
+int SamplerJitCache::clearGen_ = 0;
// 256k should be enough.
SamplerJitCache::SamplerJitCache() : Rasterizer::CodeBlock(1024 * 64 * 4), cache_(64) {
lastFetch_.gen = -1;
lastNearest_.gen = -1;
lastLinear_.gen = -1;
+ clearGen_++;
}
void SamplerJitCache::Clear() {
diff --git a/GPU/Software/Sampler.h b/GPU/Software/Sampler.h
index fbe606b110..ec8d4c2638 100644
--- a/GPU/Software/Sampler.h
+++ b/GPU/Software/Sampler.h
@@ -147,7 +147,7 @@ private:
DenseHashMap cache_;
std::unordered_map addresses_;
std::unordered_set compileQueue_;
- int clearGen_ = 0;
+ static int clearGen_;
static thread_local LastCache lastFetch_;
static thread_local LastCache lastNearest_;
static thread_local LastCache lastLinear_;
diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp
index 56e9a3b60a..7fe082b859 100644
--- a/GPU/Software/SoftGpu.cpp
+++ b/GPU/Software/SoftGpu.cpp
@@ -466,9 +466,8 @@ void SoftGPU::DeviceLost() {
}
}
-void SoftGPU::DeviceRestore() {
- if (PSP_CoreParameter().graphicsContext)
- draw_ = (Draw::DrawContext *)PSP_CoreParameter().graphicsContext->GetDrawContext();
+void SoftGPU::DeviceRestore(Draw::DrawContext *draw) {
+ draw_ = draw;
if (presentation_)
presentation_->DeviceRestore(draw_);
PPGeSetDrawContext(draw_);
@@ -671,6 +670,9 @@ void SoftGPU::MarkDirty(uint32_t addr, uint32_t bytes, SoftGPUVRAMDirty value) {
uint32_t start = ((addr - PSP_GetVidMemBase()) & 0x001FFFFF) >> 10;
uint32_t end = start + ((bytes + 1023) >> 10);
+ if (end > sizeof(vramDirty_)) {
+ end = sizeof(vramDirty_);
+ }
if (value == SoftGPUVRAMDirty::CLEAR || value == (SoftGPUVRAMDirty::DIRTY | SoftGPUVRAMDirty::REALLY_DIRTY)) {
memset(vramDirty_ + start, (uint8_t)value, end - start);
} else {
diff --git a/GPU/Software/SoftGpu.h b/GPU/Software/SoftGpu.h
index 2496c7b474..0377ca7c1b 100644
--- a/GPU/Software/SoftGpu.h
+++ b/GPU/Software/SoftGpu.h
@@ -129,15 +129,16 @@ public:
u32 CheckGPUFeatures() const override { return 0; }
bool IsStarted() override;
- void InitClear() override {}
void ExecuteOp(u32 op, u32 diff) override;
void FinishDeferred() override;
int ListSync(int listid, int mode) override;
u32 DrawSync(int mode) override;
+ void UpdateCmdInfo() override {}
void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override;
void CopyDisplayToOutput(bool reallyDirty) override;
void GetStats(char *buffer, size_t bufsize) override;
+ std::vector GetFramebufferList() const override { return std::vector(); }
void InvalidateCache(u32 addr, int size, GPUInvalidationType type) override;
void PerformWriteFormattedFromMemory(u32 addr, int size, int width, GEBufferFormat format) override;
bool PerformMemoryCopy(u32 dest, u32 src, int size, GPUCopyFlag flags = GPUCopyFlag::NONE) override;
@@ -145,10 +146,9 @@ public:
bool PerformReadbackToMemory(u32 dest, int size) override;
bool PerformWriteColorFromMemory(u32 dest, int size) override;
bool PerformWriteStencilFromMemory(u32 dest, int size, WriteStencil flags) override;
- void ClearCacheNextFrame() override {}
void DeviceLost() override;
- void DeviceRestore() override;
+ void DeviceRestore(Draw::DrawContext *draw) override;
void NotifyRenderResized() override;
void NotifyDisplayResized() override;
diff --git a/GPU/Software/TransformUnit.h b/GPU/Software/TransformUnit.h
index b1dd318540..895c023a92 100644
--- a/GPU/Software/TransformUnit.h
+++ b/GPU/Software/TransformUnit.h
@@ -173,6 +173,9 @@ public:
SoftwareDrawEngine();
~SoftwareDrawEngine();
+ void DeviceLost() override {}
+ void DeviceRestore(Draw::DrawContext *draw) override {}
+
void NotifyConfigChanged() override;
void DispatchFlush() override;
void DispatchSubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int cullMode, int *bytesRead) override;
diff --git a/GPU/Vulkan/DebugVisVulkan.cpp b/GPU/Vulkan/DebugVisVulkan.cpp
index 82acb8c0fd..ff03218efd 100644
--- a/GPU/Vulkan/DebugVisVulkan.cpp
+++ b/GPU/Vulkan/DebugVisVulkan.cpp
@@ -15,24 +15,84 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+#include
+#include
+#include
+
#include "Common/Render/DrawBuffer.h"
#include "Common/GPU/thin3d.h"
+#include "Common/GPU/Vulkan/VulkanContext.h"
#include "Common/UI/Context.h"
#include "Common/UI/View.h"
#include "Common/System/Display.h"
#include "Common/System/System.h"
+#include "ext/vma/vk_mem_alloc.h"
+
#include "DebugVisVulkan.h"
#include "Common/GPU/Vulkan/VulkanMemory.h"
#include "Common/GPU/Vulkan/VulkanImage.h"
+#include "Common/Data/Text/Parsers.h"
#include "GPU/Vulkan/GPU_Vulkan.h"
#include "GPU/Vulkan/VulkanUtil.h"
#include "GPU/Vulkan/TextureCacheVulkan.h"
#undef DrawText
+bool comparePushBufferNames(const VulkanPushBuffer *a, const VulkanPushBuffer *b) {
+ return strcmp(a->Name(), b->Name()) < 0;
+}
+
void DrawAllocatorVis(UIContext *ui, GPUInterface *gpu) {
- // TODO: Make a new allocator visualizer for VMA.
+ // This one will simply display stats.
+ Draw::DrawContext *draw = ui->GetDrawContext();
+
+ VulkanContext *vulkan = (VulkanContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT);
+ if (!vulkan) {
+ return;
+ }
+
+ VmaTotalStatistics vmaStats;
+ vmaCalculateStatistics(vulkan->Allocator(), &vmaStats);
+
+ std::vector budgets;
+ budgets.resize(vulkan->GetMemoryProperties().memoryHeapCount);
+ vmaGetHeapBudgets(vulkan->Allocator(), &budgets[0]);
+
+ size_t totalBudget = 0;
+ size_t totalUsedBytes = 0;
+ for (auto &budget : budgets) {
+ totalBudget += budget.budget;
+ totalUsedBytes += budget.usage;
+ }
+
+ std::stringstream str;
+ str << vulkan->GetPhysicalDeviceProperties().properties.deviceName << std::endl;
+ str << "Allocated " << NiceSizeFormat(vmaStats.total.statistics.allocationBytes) << " in " << vmaStats.total.statistics.allocationCount << " allocs" << std::endl;
+ // Note: The overall number includes stuff like descriptor sets pools and other things that are not directly visible as allocations.
+ str << "Overall " << NiceSizeFormat(totalUsedBytes) << " used out of " << NiceSizeFormat(totalBudget) << " available" << std::endl;
+
+ str << "Push buffers:" << std::endl;
+
+ // Now list the various push buffers.
+ auto pushBuffers = VulkanPushBuffer::GetAllActive();
+ std::sort(pushBuffers.begin(), pushBuffers.end(), comparePushBufferNames);
+
+ for (auto push : pushBuffers) {
+ str << " " << push->Name() << " "
+ << NiceSizeFormat(push->GetTotalCapacity()) << ", used: "
+ << NiceSizeFormat(push->GetTotalSize()) << std::endl;
+ }
+
+ const int padding = 10 + System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_LEFT);
+ const int starty = 50 + System_GetPropertyFloat(SYSPROP_DISPLAY_SAFE_INSET_TOP);
+ int x = padding;
+ int y = starty;
+
+ ui->SetFontScale(0.7f, 0.7f);
+ ui->DrawTextShadow(str.str().c_str(), x, y, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
+ ui->SetFontScale(1.0f, 1.0f);
+ ui->Flush();
}
void DrawGPUProfilerVis(UIContext *ui, GPUInterface *gpu) {
diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp
index c4a3be72de..11907c13b7 100644
--- a/GPU/Vulkan/DrawEngineVulkan.cpp
+++ b/GPU/Vulkan/DrawEngineVulkan.cpp
@@ -287,7 +287,6 @@ void DrawEngineVulkan::DeviceLost() {
void DrawEngineVulkan::DeviceRestore(Draw::DrawContext *draw) {
draw_ = draw;
-
InitDeviceObjects();
}
@@ -983,11 +982,21 @@ void DrawEngineVulkan::DoFlush() {
}
} else if (result.action == SW_CLEAR) {
// Note: we won't get here if the clear is alpha but not color, or color but not alpha.
-
- // We let the framebuffer manager handle the clear. It can use renderpasses to optimize on tilers.
- // If non-buffered though, it'll just do a plain clear.
- framebufferManager_->NotifyClear(gstate.isClearModeColorMask(), gstate.isClearModeAlphaMask(), gstate.isClearModeDepthMask(), result.color, result.depth);
-
+ bool clearColor = gstate.isClearModeColorMask();
+ bool clearAlpha = gstate.isClearModeAlphaMask(); // and stencil
+ bool clearDepth = gstate.isClearModeDepthMask();
+ int mask = 0;
+ // The Clear detection takes care of doing a regular draw instead if separate masking
+ // of color and alpha is needed, so we can just treat them as the same.
+ if (clearColor || clearAlpha) mask |= Draw::FBChannel::FB_COLOR_BIT;
+ if (clearDepth) mask |= Draw::FBChannel::FB_DEPTH_BIT;
+ if (clearAlpha) mask |= Draw::FBChannel::FB_STENCIL_BIT;
+ // Note that since the alpha channel and the stencil channel are shared on the PSP,
+ // when we clear alpha, we also clear stencil to the same value.
+ draw_->Clear(mask, result.color, result.depth, result.color >> 24);
+ if (clearColor || clearAlpha) {
+ framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);
+ }
if (gstate_c.Use(GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate.FrameBufFormat() == GE_FORMAT_565)) {
int scissorX1 = gstate.getScissorX1();
int scissorY1 = gstate.getScissorY1();
diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h
index 6c21b7609d..b0e99a7c24 100644
--- a/GPU/Vulkan/DrawEngineVulkan.h
+++ b/GPU/Vulkan/DrawEngineVulkan.h
@@ -158,8 +158,8 @@ public:
framebufferManager_ = fbManager;
}
- void DeviceLost();
- void DeviceRestore(Draw::DrawContext *draw);
+ void DeviceLost() override;
+ void DeviceRestore(Draw::DrawContext *draw) override;
// So that this can be inlined
void Flush() {
diff --git a/GPU/Vulkan/FramebufferManagerVulkan.cpp b/GPU/Vulkan/FramebufferManagerVulkan.cpp
index 7d47fda518..0cc7c5c9ac 100644
--- a/GPU/Vulkan/FramebufferManagerVulkan.cpp
+++ b/GPU/Vulkan/FramebufferManagerVulkan.cpp
@@ -15,35 +15,9 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
-#include
-
-#include "Common/Profiler/Profiler.h"
-
-#include "Common/System/Display.h"
-#include "Common/Math/lin/matrix4x4.h"
-#include "Common/Data/Convert/ColorConv.h"
-#include "Common/Data/Convert/SmallDataConvert.h"
-#include "Common/GPU/thin3d.h"
-
-#include "Common/GPU/Vulkan/VulkanContext.h"
-#include "Common/GPU/Vulkan/VulkanMemory.h"
-#include "Common/GPU/Vulkan/VulkanImage.h"
-#include "Common/GPU/Vulkan/VulkanRenderManager.h"
-#include "Core/MemMap.h"
-#include "Core/Config.h"
-#include "Core/ConfigValues.h"
-#include "Core/System.h"
-#include "GPU/ge_constants.h"
-#include "GPU/GPUInterface.h"
#include "GPU/GPUState.h"
-#include "GPU/Common/TextureDecoder.h"
-#include "GPU/Common/FramebufferManagerCommon.h"
-#include "GPU/Debugger/Stepping.h"
#include "GPU/Vulkan/FramebufferManagerVulkan.h"
-#include "GPU/Vulkan/DrawEngineVulkan.h"
-#include "GPU/Vulkan/TextureCacheVulkan.h"
-#include "GPU/Vulkan/ShaderManagerVulkan.h"
#include "GPU/Vulkan/VulkanUtil.h"
using namespace PPSSPP_VK;
@@ -52,26 +26,3 @@ FramebufferManagerVulkan::FramebufferManagerVulkan(Draw::DrawContext *draw) :
FramebufferManagerCommon(draw) {
presentation_->SetLanguage(GLSL_VULKAN);
}
-
-FramebufferManagerVulkan::~FramebufferManagerVulkan() {
- DeviceLost();
-}
-
-void FramebufferManagerVulkan::NotifyClear(bool clearColor, bool clearAlpha, bool clearDepth, uint32_t color, float depth) {
- int mask = 0;
- // The Clear detection takes care of doing a regular draw instead if separate masking
- // of color and alpha is needed, so we can just treat them as the same.
- if (clearColor || clearAlpha)
- mask |= Draw::FBChannel::FB_COLOR_BIT;
- if (clearDepth)
- mask |= Draw::FBChannel::FB_DEPTH_BIT;
- if (clearAlpha)
- mask |= Draw::FBChannel::FB_STENCIL_BIT;
-
- // Note that since the alpha channel and the stencil channel are shared on the PSP,
- // when we clear alpha, we also clear stencil to the same value.
- draw_->Clear(mask, color, depth, color >> 24);
- if (clearColor || clearAlpha) {
- SetColorUpdated(gstate_c.skipDrawReason);
- }
-}
diff --git a/GPU/Vulkan/FramebufferManagerVulkan.h b/GPU/Vulkan/FramebufferManagerVulkan.h
index d3370fafb7..2abb6008ce 100644
--- a/GPU/Vulkan/FramebufferManagerVulkan.h
+++ b/GPU/Vulkan/FramebufferManagerVulkan.h
@@ -17,26 +17,12 @@
#pragma once
-#include "Common/GPU/Vulkan/VulkanLoader.h"
-#include "GPU/GPUInterface.h"
-#include "GPU/Common/FramebufferManagerCommon.h"
-#include "GPU/Common/GPUDebugInterface.h"
-#include "GPU/Common/PresentationCommon.h"
-#include "GPU/Vulkan/VulkanUtil.h"
+#include "Common/GPU/thin3d.h"
-class TextureCacheVulkan;
-class DrawEngineVulkan;
-class VulkanContext;
-class ShaderManagerVulkan;
-class VulkanTexture;
-class VulkanPushBuffer;
+#include "GPU/Common/FramebufferManagerCommon.h"
+#include "GPU/Common/PresentationCommon.h"
class FramebufferManagerVulkan : public FramebufferManagerCommon {
public:
explicit FramebufferManagerVulkan(Draw::DrawContext *draw);
- ~FramebufferManagerVulkan();
-
- // If within a render pass, this will just issue a regular clear. If beginning a new render pass,
- // do that.
- void NotifyClear(bool clearColor, bool clearAlpha, bool clearDepth, uint32_t color, float depth);
};
diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp
index 8e1ad1e2d1..065dc5b1c5 100644
--- a/GPU/Vulkan/GPU_Vulkan.cpp
+++ b/GPU/Vulkan/GPU_Vulkan.cpp
@@ -46,7 +46,7 @@
#include "Common/GPU/Vulkan/VulkanQueueRunner.h"
GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
- : GPUCommon(gfxCtx, draw), drawEngine_(draw) {
+ : GPUCommonHW(gfxCtx, draw), drawEngine_(draw) {
gstate_c.SetUseFlags(CheckGPUFeatures());
drawEngine_.InitDeviceObjects();
@@ -185,16 +185,15 @@ GPU_Vulkan::~GPU_Vulkan() {
SaveCache(shaderCachePath_);
// Note: We save the cache in DeviceLost
DestroyDeviceObjects();
- framebufferManagerVulkan_->DestroyAllFBOs();
drawEngine_.DeviceLost();
- delete textureCacheVulkan_;
+ shaderManager_->ClearShaders();
+
delete pipelineManager_;
- delete shaderManagerVulkan_;
- delete framebufferManagerVulkan_;
+ // other managers are deleted in ~GPUCommonHW.
}
u32 GPU_Vulkan::CheckGPUFeatures() const {
- uint32_t features = GPUCommon::CheckGPUFeatures();
+ uint32_t features = GPUCommonHW::CheckGPUFeatures();
VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT);
switch (vulkan->GetPhysicalDeviceProperties().properties.vendorID) {
@@ -289,10 +288,10 @@ u32 GPU_Vulkan::CheckGPUFeatures() const {
}
void GPU_Vulkan::BeginHostFrame() {
- GPUCommon::BeginHostFrame();
+ GPUCommonHW::BeginHostFrame();
drawEngine_.BeginFrame();
- textureCacheVulkan_->StartFrame();
+ textureCache_->StartFrame();
VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT);
int curFrame = vulkan->GetCurFrame();
@@ -301,7 +300,7 @@ void GPU_Vulkan::BeginHostFrame() {
frame.push_->Reset();
frame.push_->Begin(vulkan);
- framebufferManagerVulkan_->BeginFrame();
+ framebufferManager_->BeginFrame();
textureCacheVulkan_->SetPushBuffer(frameData_[curFrame].push_);
shaderManagerVulkan_->DirtyShader();
@@ -313,7 +312,7 @@ void GPU_Vulkan::BeginHostFrame() {
WARN_LOG(G3D, "Shader use flags changed, clearing all shaders and depth buffers");
// TODO: Not all shaders need to be recompiled. In fact, quite few? Of course, depends on
// the use flag change.. This is a major frame rate hitch in the start of a race in Outrun.
- shaderManagerVulkan_->ClearShaders();
+ shaderManager_->ClearShaders();
pipelineManager_->Clear();
framebufferManager_->ClearAllDepthBuffers();
gstate_c.useFlagsChanged = false;
@@ -335,9 +334,8 @@ void GPU_Vulkan::EndHostFrame() {
frame.push_->End();
drawEngine_.EndFrame();
- textureCacheVulkan_->EndFrame();
- GPUCommon::EndHostFrame();
+ GPUCommonHW::EndHostFrame();
}
// Needs to be called on GPU thread, not reporting thread.
@@ -391,58 +389,10 @@ void GPU_Vulkan::BuildReportingInfo() {
Reporting::UpdateConfig();
}
-void GPU_Vulkan::Reinitialize() {
- GPUCommon::Reinitialize();
-}
-
-void GPU_Vulkan::InitClear() {
- if (!framebufferManager_->UseBufferedRendering()) {
- // TODO?
- }
-}
-
-void GPU_Vulkan::CopyDisplayToOutput(bool reallyDirty) {
- // Flush anything left over.
- drawEngine_.Flush();
-
- shaderManagerVulkan_->DirtyLastShader();
-
- framebufferManagerVulkan_->CopyDisplayToOutput(reallyDirty);
-
- gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
-}
-
void GPU_Vulkan::FinishDeferred() {
drawEngine_.FinishDeferred();
}
-inline void GPU_Vulkan::CheckFlushOp(int cmd, u32 diff) {
- const u8 cmdFlags = cmdInfo_[cmd].flags;
- if (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)) {
- if (dumpThisFrame_) {
- NOTICE_LOG(G3D, "================ FLUSH ================");
- }
- drawEngine_.Flush();
- }
-}
-
-void GPU_Vulkan::PreExecuteOp(u32 op, u32 diff) {
- CheckFlushOp(op >> 24, diff);
-}
-
-void GPU_Vulkan::ExecuteOp(u32 op, u32 diff) {
- const u8 cmd = op >> 24;
- const CommandInfo info = cmdInfo_[cmd];
- const u8 cmdFlags = info.flags;
- if ((cmdFlags & FLAG_EXECUTE) || (diff && (cmdFlags & FLAG_EXECUTEONCHANGE))) {
- (this->*info.func)(op, diff);
- } else if (diff) {
- uint64_t dirty = info.flags >> 8;
- if (dirty)
- gstate_c.Dirty(dirty);
- }
-}
-
void GPU_Vulkan::InitDeviceObjects() {
INFO_LOG(G3D, "GPU_Vulkan::InitDeviceObjects");
VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT);
@@ -489,7 +439,7 @@ void GPU_Vulkan::DestroyDeviceObjects() {
void GPU_Vulkan::CheckRenderResized() {
if (renderResized_) {
- GPUCommon::CheckRenderResized();
+ GPUCommonHW::CheckRenderResized();
pipelineManager_->InvalidateMSAAPipelines();
framebufferManager_->ReleasePipelines();
}
@@ -504,27 +454,18 @@ void GPU_Vulkan::DeviceLost() {
SaveCache(shaderCachePath_);
}
DestroyDeviceObjects();
- drawEngine_.DeviceLost();
pipelineManager_->DeviceLost();
- textureCacheVulkan_->DeviceLost();
- shaderManagerVulkan_->DeviceLost();
- GPUCommon::DeviceLost();
+ GPUCommonHW::DeviceLost();
}
-void GPU_Vulkan::DeviceRestore() {
- GPUCommon::DeviceRestore();
- InitDeviceObjects();
-
- gstate_c.SetUseFlags(CheckGPUFeatures());
- BuildReportingInfo();
- UpdateCmdInfo();
+void GPU_Vulkan::DeviceRestore(Draw::DrawContext *draw) {
+ GPUCommonHW::DeviceRestore(draw);
VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT);
- drawEngine_.DeviceRestore(draw_);
pipelineManager_->DeviceRestore(vulkan);
- textureCacheVulkan_->DeviceRestore(draw_);
- shaderManagerVulkan_->DeviceRestore(draw_);
+
+ InitDeviceObjects();
}
void GPU_Vulkan::GetStats(char *buffer, size_t bufsize) {
@@ -550,49 +491,25 @@ void GPU_Vulkan::GetStats(char *buffer, size_t bufsize) {
);
}
-void GPU_Vulkan::DoState(PointerWrap &p) {
- GPUCommon::DoState(p);
-
- // TODO: Some of these things may not be necessary.
- // None of these are necessary when saving.
- // In Freeze-Frame mode, we don't want to do any of this.
- if (p.mode == p.MODE_READ && !PSP_CoreParameter().frozen) {
- textureCache_->Clear(true);
-
- gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
- framebufferManager_->DestroyAllFBOs();
- }
-}
-
std::vector GPU_Vulkan::DebugGetShaderIDs(DebugShaderType type) {
- if (type == SHADER_TYPE_VERTEXLOADER) {
- return drawEngine_.DebugGetVertexLoaderIDs();
- } else if (type == SHADER_TYPE_PIPELINE) {
+ switch (type) {
+ case SHADER_TYPE_PIPELINE:
return pipelineManager_->DebugGetObjectIDs(type);
- } else if (type == SHADER_TYPE_TEXTURE) {
- return textureCache_->GetTextureShaderCache()->DebugGetShaderIDs(type);
- } else if (type == SHADER_TYPE_VERTEX || type == SHADER_TYPE_FRAGMENT || type == SHADER_TYPE_GEOMETRY) {
- return shaderManagerVulkan_->DebugGetShaderIDs(type);
- } else if (type == SHADER_TYPE_SAMPLER) {
+ case SHADER_TYPE_SAMPLER:
return textureCacheVulkan_->DebugGetSamplerIDs();
- } else {
- return std::vector();
+ default:
+ return GPUCommonHW::DebugGetShaderIDs(type);
}
}
std::string GPU_Vulkan::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {
- if (type == SHADER_TYPE_VERTEXLOADER) {
- return drawEngine_.DebugGetVertexLoaderString(id, stringType);
- } else if (type == SHADER_TYPE_PIPELINE) {
+ switch (type) {
+ case SHADER_TYPE_PIPELINE:
return pipelineManager_->DebugGetObjectString(id, type, stringType, shaderManagerVulkan_);
- } else if (type == SHADER_TYPE_TEXTURE) {
- return textureCache_->GetTextureShaderCache()->DebugGetShaderString(id, type, stringType);
- } else if (type == SHADER_TYPE_SAMPLER) {
+ case SHADER_TYPE_SAMPLER:
return textureCacheVulkan_->DebugGetSamplerString(id, stringType);
- } else if (type == SHADER_TYPE_VERTEX || type == SHADER_TYPE_FRAGMENT || type == SHADER_TYPE_GEOMETRY) {
- return shaderManagerVulkan_->DebugGetShaderString(id, type, stringType);
- } else {
- return std::string();
+ default:
+ return GPUCommonHW::DebugGetShaderString(id, type, stringType);
}
}
diff --git a/GPU/Vulkan/GPU_Vulkan.h b/GPU/Vulkan/GPU_Vulkan.h
index 67f8301e00..1fad919ab1 100644
--- a/GPU/Vulkan/GPU_Vulkan.h
+++ b/GPU/Vulkan/GPU_Vulkan.h
@@ -22,7 +22,7 @@
#include "Common/File/Path.h"
-#include "GPU/GPUCommon.h"
+#include "GPU/GPUCommonHW.h"
#include "GPU/Vulkan/DrawEngineVulkan.h"
#include "GPU/Vulkan/PipelineManagerVulkan.h"
#include "GPU/Common/TextureShaderCommon.h"
@@ -32,7 +32,7 @@ class ShaderManagerVulkan;
class LinkedShader;
class TextureCacheVulkan;
-class GPU_Vulkan : public GPUCommon {
+class GPU_Vulkan : public GPUCommonHW {
public:
GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw);
~GPU_Vulkan();
@@ -47,14 +47,9 @@ public:
void BeginHostFrame() override;
void EndHostFrame() override;
- void PreExecuteOp(u32 op, u32 diff) override;
- void ExecuteOp(u32 op, u32 diff) override;
-
void GetStats(char *buffer, size_t bufsize) override;
void DeviceLost() override; // Only happens on Android. Drop all textures and shaders.
- void DeviceRestore() override;
-
- void DoState(PointerWrap &p) override;
+ void DeviceRestore(Draw::DrawContext *draw) override;
// Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend.
std::vector DebugGetShaderIDs(DebugShaderType shader) override;
@@ -71,11 +66,7 @@ protected:
void CheckRenderResized() override;
private:
- void CheckFlushOp(int cmd, u32 diff);
void BuildReportingInfo() override;
- void InitClear() override;
- void CopyDisplayToOutput(bool reallyDirty) override;
- void Reinitialize() override;
void InitDeviceObjects();
void DestroyDeviceObjects();
diff --git a/GPU/Vulkan/ShaderManagerVulkan.h b/GPU/Vulkan/ShaderManagerVulkan.h
index 91544124f3..38b4b2e1e1 100644
--- a/GPU/Vulkan/ShaderManagerVulkan.h
+++ b/GPU/Vulkan/ShaderManagerVulkan.h
@@ -114,11 +114,11 @@ public:
ShaderManagerVulkan(Draw::DrawContext *draw);
~ShaderManagerVulkan();
- void DeviceLost();
- void DeviceRestore(Draw::DrawContext *draw);
+ void DeviceLost() override;
+ void DeviceRestore(Draw::DrawContext *draw) override;
void GetShaders(int prim, VertexDecoder *decoder, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, VulkanGeometryShader **gshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode);
- void ClearShaders();
+ void ClearShaders() override;
void DirtyShader();
void DirtyLastShader() override;
@@ -134,8 +134,8 @@ public:
VulkanFragmentShader *GetFragmentShaderFromModule(VkShaderModule module);
VulkanGeometryShader *GetGeometryShaderFromModule(VkShaderModule module);
- std::vector DebugGetShaderIDs(DebugShaderType type);
- std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType);
+ std::vector DebugGetShaderIDs(DebugShaderType type) override;
+ std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) override;
uint64_t UpdateUniforms(bool useBufferedRendering);
diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp
index 1e43f8d355..2ec829f511 100644
--- a/GPU/Vulkan/TextureCacheVulkan.cpp
+++ b/GPU/Vulkan/TextureCacheVulkan.cpp
@@ -217,7 +217,6 @@ void TextureCacheVulkan::DeviceLost() {
Clear(true);
samplerCache_.DeviceLost();
-
if (samplerNearest_)
vulkan->Delete().QueueDeleteSampler(samplerNearest_);
@@ -261,7 +260,7 @@ void TextureCacheVulkan::NotifyConfigChanged() {
static std::string ReadShaderSrc(const Path &filename) {
size_t sz = 0;
- char *data = (char *)VFSReadFile(filename.c_str(), &sz);
+ char *data = (char *)g_VFS.ReadFile(filename.c_str(), &sz);
if (!data)
return std::string();
@@ -328,39 +327,11 @@ static const VkFilter MagFiltVK[2] = {
void TextureCacheVulkan::StartFrame() {
TextureCacheCommon::StartFrame();
-
- InvalidateLastTexture();
- textureShaderCache_->Decimate();
-
- timesInvalidatedAllThisFrame_ = 0;
- texelsScaledThisFrame_ = 0;
- replacementTimeThisFrame_ = 0.0;
-
- if (clearCacheNextFrame_) {
- Clear(true);
- clearCacheNextFrame_ = false;
- } else {
- int slabPressureLimit = TEXCACHE_SLAB_PRESSURE;
- if (g_Config.iTexScalingLevel > 1) {
- // Since textures are 2D maybe we should square this, but might get too non-aggressive.
- slabPressureLimit *= g_Config.iTexScalingLevel;
- }
- // TODO: Use some indication from VMA.
- // Maybe see https://gpuopen-librariesandsdks.github.io/VulkanMemoryAllocator/html/staying_within_budget.html#staying_within_budget_querying_for_budget .
- Decimate(false);
- }
-
+ // TODO: For low memory detection, maybe use some indication from VMA.
+ // Maybe see https://gpuopen-librariesandsdks.github.io/VulkanMemoryAllocator/html/staying_within_budget.html#staying_within_budget_querying_for_budget .
computeShaderManager_.BeginFrame();
}
-void TextureCacheVulkan::EndFrame() {
- computeShaderManager_.EndFrame();
-
- if (texelsScaledThisFrame_) {
- VERBOSE_LOG(G3D, "Scaled %i texels", texelsScaledThisFrame_);
- }
-}
-
void TextureCacheVulkan::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) {
const u32 clutBaseBytes = clutFormat == GE_CMODE_32BIT_ABGR8888 ? (clutBase * sizeof(u32)) : (clutBase * sizeof(u16));
// Technically, these extra bytes weren't loaded, but hopefully it was loaded earlier.
@@ -419,7 +390,6 @@ void TextureCacheVulkan::ApplySamplingParams(const SamplerCacheKey &key) {
void TextureCacheVulkan::Unbind() {
imageView_ = VK_NULL_HANDLE;
curSampler_ = VK_NULL_HANDLE;
- InvalidateLastTexture();
}
void TextureCacheVulkan::BindAsClutTexture(Draw::Texture *tex, bool smooth) {
@@ -473,7 +443,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
// Any texture scaling is gonna move away from the original 16-bit format, if any.
VkFormat actualFmt = plan.scaleFactor > 1 ? VULKAN_8888_FORMAT : dstFmt;
if (plan.replaceValid) {
- actualFmt = ToVulkanFormat(plan.replaced->Format(plan.baseLevelSrc));
+ actualFmt = ToVulkanFormat(plan.replaced->Format());
}
bool computeUpload = false;
@@ -531,7 +501,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
}
// Turn off texture replacement for this texture.
- plan.replaced = &replacer_.FindNone();
+ plan.replaced = nullptr;
plan.createW /= plan.scaleFactor;
plan.createH /= plan.scaleFactor;
@@ -562,6 +532,8 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
levels = plan.levelsToLoad;
}
+ VulkanPushBuffer *pushBuffer = drawEngine_->GetPushBufferForTextureData();
+
for (int i = 0; i < levels; i++) {
int mipUnscaledWidth = gstate.getTextureWidth(i);
int mipUnscaledHeight = gstate.getTextureHeight(i);
@@ -571,8 +543,10 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
plan.GetMipSize(i, &mipWidth, &mipHeight);
int bpp = VkFormatBytesPerPixel(actualFmt);
- int stride = (mipWidth * bpp + 15) & ~15; // output stride
- int uploadSize = stride * mipHeight;
+ int optimalStrideAlignment = std::max(4, (int)vulkan->GetPhysicalDeviceProperties().properties.limits.optimalBufferCopyRowPitchAlignment);
+ int byteStride = RoundUpToPowerOf2(mipWidth * bpp, optimalStrideAlignment); // output stride
+ int pixelStride = byteStride / bpp;
+ int uploadSize = byteStride * mipHeight;
uint32_t bufferOffset;
VkBuffer texBuf;
@@ -581,34 +555,38 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
void *data;
std::vector saveData;
+ // Simple wrapper to avoid reading back from VRAM (very, very expensive).
auto loadLevel = [&](int sz, int srcLevel, int lstride, int lfactor) {
if (plan.saveTexture) {
saveData.resize(sz);
data = &saveData[0];
} else {
- data = drawEngine_->GetPushBufferForTextureData()->PushAligned(sz, &bufferOffset, &texBuf, pushAlignment);
+ data = pushBuffer->PushAligned(sz, &bufferOffset, &texBuf, pushAlignment);
}
LoadVulkanTextureLevel(*entry, (uint8_t *)data, lstride, srcLevel, lfactor, actualFmt);
if (plan.saveTexture)
- bufferOffset = drawEngine_->GetPushBufferForTextureData()->PushAligned(&saveData[0], sz, pushAlignment, &texBuf);
+ bufferOffset = pushBuffer->PushAligned(&saveData[0], sz, pushAlignment, &texBuf);
};
bool dataScaled = true;
if (plan.replaceValid) {
// Directly load the replaced image.
- data = drawEngine_->GetPushBufferForTextureData()->PushAligned(uploadSize, &bufferOffset, &texBuf, pushAlignment);
+ data = pushBuffer->PushAligned(uploadSize, &bufferOffset, &texBuf, pushAlignment);
double replaceStart = time_now_d();
- plan.replaced->Load(plan.baseLevelSrc + i, data, stride); // if it fails, it'll just be garbage data... OK for now.
+ if (!plan.replaced->CopyLevelTo(plan.baseLevelSrc + i, data, byteStride)) { // If plan.replaceValid, this shouldn't fail.
+ WARN_LOG(G3D, "Failed to copy replaced texture level");
+ // TODO: Fill with some pattern?
+ }
replacementTimeThisFrame_ += time_now_d() - replaceStart;
VK_PROFILE_BEGIN(vulkan, cmdInit, VK_PIPELINE_STAGE_TRANSFER_BIT,
"Copy Upload (replaced): %dx%d", mipWidth, mipHeight);
- entry->vkTex->UploadMip(cmdInit, i, mipWidth, mipHeight, 0, texBuf, bufferOffset, stride / bpp);
+ entry->vkTex->UploadMip(cmdInit, i, mipWidth, mipHeight, 0, texBuf, bufferOffset, pixelStride);
VK_PROFILE_END(vulkan, cmdInit, VK_PIPELINE_STAGE_TRANSFER_BIT);
} else {
if (plan.depth != 1) {
// 3D texturing.
- loadLevel(uploadSize, i, stride, plan.scaleFactor);
- entry->vkTex->UploadMip(cmdInit, 0, mipWidth, mipHeight, i, texBuf, bufferOffset, stride / bpp);
+ loadLevel(uploadSize, i, byteStride, plan.scaleFactor);
+ entry->vkTex->UploadMip(cmdInit, 0, mipWidth, mipHeight, i, texBuf, bufferOffset, pixelStride);
} else if (computeUpload) {
int srcBpp = VkFormatBytesPerPixel(dstFmt);
int srcStride = mipUnscaledWidth * srcBpp;
@@ -629,14 +607,14 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
VK_PROFILE_END(vulkan, cmdInit, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
vulkan->Delete().QueueDeleteImageView(view);
} else {
- loadLevel(uploadSize, i == 0 ? plan.baseLevelSrc : i, stride, plan.scaleFactor);
+ loadLevel(uploadSize, i == 0 ? plan.baseLevelSrc : i, byteStride, plan.scaleFactor);
VK_PROFILE_BEGIN(vulkan, cmdInit, VK_PIPELINE_STAGE_TRANSFER_BIT,
"Copy Upload: %dx%d", mipWidth, mipHeight);
- entry->vkTex->UploadMip(cmdInit, i, mipWidth, mipHeight, 0, texBuf, bufferOffset, stride / bpp);
+ entry->vkTex->UploadMip(cmdInit, i, mipWidth, mipHeight, 0, texBuf, bufferOffset, pixelStride);
VK_PROFILE_END(vulkan, cmdInit, VK_PIPELINE_STAGE_TRANSFER_BIT);
}
// Format might be wrong in lowMemoryMode_, so don't save.
- if (replacer_.Enabled() && plan.replaced->IsInvalid() && !lowMemoryMode_) {
+ if (plan.saveTexture && !lowMemoryMode_) {
// When hardware texture scaling is enabled, this saves the original.
int w = dataScaled ? mipWidth : mipUnscaledWidth;
int h = dataScaled ? mipHeight : mipUnscaledHeight;
@@ -650,7 +628,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
replacedInfo.scaleFactor = plan.scaleFactor;
replacedInfo.fmt = FromVulkanFormat(actualFmt);
- replacer_.NotifyTextureDecoded(replacedInfo, data, stride, plan.baseLevelSrc + i, w, h);
+ replacer_.NotifyTextureDecoded(replacedInfo, data, byteStride, plan.baseLevelSrc + i, w, h);
}
}
}
diff --git a/GPU/Vulkan/TextureCacheVulkan.h b/GPU/Vulkan/TextureCacheVulkan.h
index 2c16d02a03..2a6fb5d2a9 100644
--- a/GPU/Vulkan/TextureCacheVulkan.h
+++ b/GPU/Vulkan/TextureCacheVulkan.h
@@ -58,10 +58,9 @@ public:
~TextureCacheVulkan();
void StartFrame() override;
- void EndFrame();
- void DeviceLost();
- void DeviceRestore(Draw::DrawContext *draw);
+ void DeviceLost() override;
+ void DeviceRestore(Draw::DrawContext *draw) override;
void SetFramebufferManager(FramebufferManagerVulkan *fbManager);
void SetDrawEngine(DrawEngineVulkan *td) {
@@ -72,8 +71,6 @@ public:
}
void ForgetLastTexture() override {}
- void InvalidateLastTexture() override {}
-
void NotifyConfigChanged() override;
void GetVulkanHandles(VkImageView &imageView, VkSampler &sampler) {
diff --git a/GPU/Vulkan/VulkanUtil.cpp b/GPU/Vulkan/VulkanUtil.cpp
index c47fd21d9c..d10749b187 100644
--- a/GPU/Vulkan/VulkanUtil.cpp
+++ b/GPU/Vulkan/VulkanUtil.cpp
@@ -52,8 +52,7 @@ VkShaderModule CompileShaderModule(VulkanContext *vulkan, VkShaderStageFlagBits
}
}
-VulkanComputeShaderManager::VulkanComputeShaderManager(VulkanContext *vulkan) : vulkan_(vulkan), pipelines_(8) {
-}
+VulkanComputeShaderManager::VulkanComputeShaderManager(VulkanContext *vulkan) : vulkan_(vulkan), pipelines_(8) {}
VulkanComputeShaderManager::~VulkanComputeShaderManager() {}
void VulkanComputeShaderManager::InitDeviceObjects(Draw::DrawContext *draw) {
@@ -96,6 +95,7 @@ void VulkanComputeShaderManager::InitDeviceObjects(Draw::DrawContext *draw) {
for (int i = 0; i < ARRAY_SIZE(frameData_); i++) {
frameData_[i].descPool.Create(vulkan_, dp, dpTypes);
+ frameData_[i].descPoolUsed = false;
}
VkPushConstantRange push = {};
@@ -137,6 +137,7 @@ void VulkanComputeShaderManager::DestroyDeviceObjects() {
VkDescriptorSet VulkanComputeShaderManager::GetDescriptorSet(VkImageView image, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range, VkBuffer buffer2, VkDeviceSize offset2, VkDeviceSize range2) {
int curFrame = vulkan_->GetCurFrame();
FrameData &frameData = frameData_[curFrame];
+ frameData.descPoolUsed = true;
VkDescriptorSet desc = frameData.descPool.Allocate(1, &descriptorSetLayout_, "compute_descset");
_assert_(desc != VK_NULL_HANDLE);
@@ -206,8 +207,8 @@ VkPipeline VulkanComputeShaderManager::GetPipeline(VkShaderModule cs) {
void VulkanComputeShaderManager::BeginFrame() {
int curFrame = vulkan_->GetCurFrame();
FrameData &frame = frameData_[curFrame];
- frame.descPool.Reset();
-}
-
-void VulkanComputeShaderManager::EndFrame() {
+ if (frame.descPoolUsed) {
+ frame.descPool.Reset();
+ frame.descPoolUsed = false;
+ }
}
diff --git a/GPU/Vulkan/VulkanUtil.h b/GPU/Vulkan/VulkanUtil.h
index 8663d3ce1e..75ed153ad3 100644
--- a/GPU/Vulkan/VulkanUtil.h
+++ b/GPU/Vulkan/VulkanUtil.h
@@ -61,7 +61,6 @@ public:
VkPipelineLayout GetPipelineLayout() const { return pipelineLayout_; }
void BeginFrame();
- void EndFrame();
private:
void InitDeviceObjects(Draw::DrawContext *draw);
@@ -78,6 +77,7 @@ private:
}
VulkanDescSetPool descPool;
+ bool descPoolUsed = false;
};
FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES];
diff --git a/Qt/QtMain.cpp b/Qt/QtMain.cpp
index 2baf523f8e..6809e9fec9 100644
--- a/Qt/QtMain.cpp
+++ b/Qt/QtMain.cpp
@@ -423,8 +423,8 @@ void MainUI::resizeGL(int w, int h) {
xscale = w / this->width();
yscale = h / this->height();
- PSP_CoreParameter().pixelWidth = pixel_xres;
- PSP_CoreParameter().pixelHeight = pixel_yres;
+ PSP_CoreParameter().pixelWidth = g_display.pixel_xres;
+ PSP_CoreParameter().pixelHeight = g_display.pixel_yres;
}
void MainUI::timerEvent(QTimerEvent *) {
@@ -453,15 +453,15 @@ bool MainUI::event(QEvent *e) {
break;
case Qt::TouchPointPressed:
case Qt::TouchPointReleased:
- input.x = touchPoint.pos().x() * g_dpi_scale_x * xscale;
- input.y = touchPoint.pos().y() * g_dpi_scale_y * yscale;
+ input.x = touchPoint.pos().x() * g_display.dpi_scale_x * xscale;
+ input.y = touchPoint.pos().y() * g_display.dpi_scale_y * yscale;
input.flags = (touchPoint.state() == Qt::TouchPointPressed) ? TOUCH_DOWN : TOUCH_UP;
input.id = touchPoint.id();
NativeTouch(input);
break;
case Qt::TouchPointMoved:
- input.x = touchPoint.pos().x() * g_dpi_scale_x * xscale;
- input.y = touchPoint.pos().y() * g_dpi_scale_y * yscale;
+ input.x = touchPoint.pos().x() * g_display.dpi_scale_x * xscale;
+ input.y = touchPoint.pos().y() * g_display.dpi_scale_y * yscale;
input.flags = TOUCH_MOVE;
input.id = touchPoint.id();
NativeTouch(input);
@@ -479,8 +479,8 @@ bool MainUI::event(QEvent *e) {
case QEvent::MouseButtonRelease:
switch(((QMouseEvent*)e)->button()) {
case Qt::LeftButton:
- input.x = ((QMouseEvent*)e)->pos().x() * g_dpi_scale_x * xscale;
- input.y = ((QMouseEvent*)e)->pos().y() * g_dpi_scale_y * yscale;
+ input.x = ((QMouseEvent*)e)->pos().x() * g_display.dpi_scale_x * xscale;
+ input.y = ((QMouseEvent*)e)->pos().y() * g_display.dpi_scale_y * yscale;
input.flags = (e->type() == QEvent::MouseButtonPress) ? TOUCH_DOWN : TOUCH_UP;
input.id = 0;
NativeTouch(input);
@@ -502,8 +502,8 @@ bool MainUI::event(QEvent *e) {
}
break;
case QEvent::MouseMove:
- input.x = ((QMouseEvent*)e)->pos().x() * g_dpi_scale_x * xscale;
- input.y = ((QMouseEvent*)e)->pos().y() * g_dpi_scale_y * yscale;
+ input.x = ((QMouseEvent*)e)->pos().x() * g_display.dpi_scale_x * xscale;
+ input.y = ((QMouseEvent*)e)->pos().y() * g_display.dpi_scale_y * yscale;
input.flags = TOUCH_MOVE;
input.id = 0;
NativeTouch(input);
@@ -738,15 +738,15 @@ int main(int argc, char *argv[])
if (res.width() < res.height())
res.transpose();
- pixel_xres = res.width();
- pixel_yres = res.height();
+ g_display.pixel_xres = res.width();
+ g_display.pixel_yres = res.height();
- g_dpi_scale_x = screen->logicalDotsPerInchX() / screen->physicalDotsPerInchX();
- g_dpi_scale_y = screen->logicalDotsPerInchY() / screen->physicalDotsPerInchY();
- g_dpi_scale_real_x = g_dpi_scale_x;
- g_dpi_scale_real_y = g_dpi_scale_y;
- dp_xres = (int)(pixel_xres * g_dpi_scale_x);
- dp_yres = (int)(pixel_yres * g_dpi_scale_y);
+ g_display.dpi_scale_x = screen->logicalDotsPerInchX() / screen->physicalDotsPerInchX();
+ g_display.dpi_scale_y = screen->logicalDotsPerInchY() / screen->physicalDotsPerInchY();
+ g_display.dpi_scale_real_x = g_display.dpi_scale_x;
+ g_display.dpi_scale_real_y = g_display.dpi_scale_y;
+ g_display.dp_xres = (int)(g_display.pixel_xres * g_display.dpi_scale_x);
+ g_display.dp_yres = (int)(g_display.pixel_yres * g_display.dpi_scale_y);
refreshRate = screen->refreshRate();
diff --git a/Qt/QtMain.h b/Qt/QtMain.h
index 0177ca9292..639806bcf5 100644
--- a/Qt/QtMain.h
+++ b/Qt/QtMain.h
@@ -25,7 +25,7 @@ QTM_USE_NAMESPACE
#include "Common/System/Display.h"
#include "Common/TimeUtil.h"
#include "Common/File/VFS/VFS.h"
-#include "Common/File/VFS/AssetReader.h"
+#include "Common/File/VFS/DirectoryReader.h"
#include "Common/GPU/OpenGL/GLCommon.h"
#include "Common/GPU/OpenGL/GLFeatures.h"
#include "Common/Input/InputState.h"
@@ -191,4 +191,3 @@ private:
#endif //SDL
#endif
-
diff --git a/Qt/mainwindow.cpp b/Qt/mainwindow.cpp
index 3ab5f4ac37..593fe5a0ec 100644
--- a/Qt/mainwindow.cpp
+++ b/Qt/mainwindow.cpp
@@ -375,7 +375,7 @@ void MainWindow::SetFullScreen(bool fullscreen) {
#endif
showFullScreen();
- InitPadLayout(dp_xres, dp_yres);
+ InitPadLayout(g_display.dp_xres, g_display.dp_yres);
if (GetUIState() == UISTATE_INGAME && !g_Config.bShowTouchControls)
QApplication::setOverrideCursor(QCursor(Qt::BlankCursor));
@@ -387,7 +387,7 @@ void MainWindow::SetFullScreen(bool fullscreen) {
showNormal();
SetWindowScale(-1);
- InitPadLayout(dp_xres, dp_yres);
+ InitPadLayout(g_display.dp_xres, g_display.dp_yres);
if (GetUIState() == UISTATE_INGAME && QApplication::overrideCursor())
QApplication::restoreOverrideCursor();
diff --git a/SDL/SDLGLGraphicsContext.cpp b/SDL/SDLGLGraphicsContext.cpp
index 62fba14b81..b1906ac7d4 100644
--- a/SDL/SDLGLGraphicsContext.cpp
+++ b/SDL/SDLGLGraphicsContext.cpp
@@ -333,7 +333,7 @@ int SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std:
SetGLCoreContext(true);
#endif
- window = SDL_CreateWindow("PPSSPP", x, y, pixel_xres, pixel_yres, mode);
+ window = SDL_CreateWindow("PPSSPP", x, y, g_display.pixel_xres, g_display.pixel_yres, mode);
if (!window) {
// Definitely don't shutdown here: we'll keep trying more GL versions.
fprintf(stderr, "SDL_CreateWindow failed for GL %d.%d: %s\n", ver.major, ver.minor, SDL_GetError());
@@ -358,7 +358,7 @@ int SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std:
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SetGLCoreContext(false);
- window = SDL_CreateWindow("PPSSPP", x, y, pixel_xres, pixel_yres, mode);
+ window = SDL_CreateWindow("PPSSPP", x, y, g_display.pixel_xres, g_display.pixel_yres, mode);
if (window == nullptr) {
NativeShutdown();
fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError());
diff --git a/SDL/SDLJoystick.cpp b/SDL/SDLJoystick.cpp
index 0a53ef80b7..59906f4a3e 100644
--- a/SDL/SDLJoystick.cpp
+++ b/SDL/SDLJoystick.cpp
@@ -29,7 +29,7 @@ SDLJoystick::SDLJoystick(bool init_SDL ) : registeredAsEventHandler(false) {
cout << "loading control pad mappings from " << dbPath << ": ";
size_t size;
- u8 *mappingData = VFSReadFile(dbPath, &size);
+ u8 *mappingData = g_VFS.ReadFile(dbPath, &size);
if (mappingData) {
SDL_RWops *rw = SDL_RWFromConstMem(mappingData, size);
// 1 to free the rw after use
@@ -191,7 +191,7 @@ void SDLJoystick::ProcessInput(SDL_Event &event){
NativeAxis(axis);
break;
case SDL_CONTROLLERDEVICEREMOVED:
- // for removal events, "which" is the instance ID for SDL_CONTROLLERDEVICEREMOVED
+ // for removal events, "which" is the instance ID for SDL_CONTROLLERDEVICEREMOVED
for (auto it = controllers.begin(); it != controllers.end(); ++it) {
if (SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(*it)) == event.cdevice.which) {
SDL_GameControllerClose(*it);
diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp
index 406f303a73..1acd96e77a 100644
--- a/SDL/SDLMain.cpp
+++ b/SDL/SDLMain.cpp
@@ -670,16 +670,16 @@ int main(int argc, char *argv[]) {
#endif
if (mode & SDL_WINDOW_FULLSCREEN_DESKTOP) {
- pixel_xres = g_DesktopWidth;
- pixel_yres = g_DesktopHeight;
+ g_display.pixel_xres = g_DesktopWidth;
+ g_display.pixel_yres = g_DesktopHeight;
if (g_Config.iForceFullScreen == -1)
g_Config.bFullScreen = true;
} else {
// set a sensible default resolution (2x)
- pixel_xres = 480 * 2 * set_scale;
- pixel_yres = 272 * 2 * set_scale;
+ g_display.pixel_xres = 480 * 2 * set_scale;
+ g_display.pixel_yres = 272 * 2 * set_scale;
if (portrait) {
- std::swap(pixel_xres, pixel_yres);
+ std::swap(g_display.pixel_xres, g_display.pixel_yres);
}
if (g_Config.iForceFullScreen == -1)
g_Config.bFullScreen = false;
@@ -688,26 +688,26 @@ int main(int argc, char *argv[]) {
set_dpi = 1.0f / set_dpi;
if (set_ipad) {
- pixel_xres = 1024;
- pixel_yres = 768;
+ g_display.pixel_xres = 1024;
+ g_display.pixel_yres = 768;
}
if (!landscape) {
- std::swap(pixel_xres, pixel_yres);
+ std::swap(g_display.pixel_xres, g_display.pixel_yres);
}
if (set_xres > 0) {
- pixel_xres = set_xres;
+ g_display.pixel_xres = set_xres;
}
if (set_yres > 0) {
- pixel_yres = set_yres;
+ g_display.pixel_yres = set_yres;
}
float dpi_scale = 1.0f;
if (set_dpi > 0) {
dpi_scale = set_dpi;
}
- dp_xres = (float)pixel_xres * dpi_scale;
- dp_yres = (float)pixel_yres * dpi_scale;
+ g_display.dp_xres = (float)g_display.pixel_xres * dpi_scale;
+ g_display.dp_yres = (float)g_display.pixel_yres * dpi_scale;
// Mac / Linux
char path[2048];
@@ -745,15 +745,13 @@ int main(int argc, char *argv[]) {
int x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(getDisplayNumber());
int y = SDL_WINDOWPOS_UNDEFINED;
- pixel_in_dps_x = (float)pixel_xres / dp_xres;
- pixel_in_dps_y = (float)pixel_yres / dp_yres;
- g_dpi_scale_x = dp_xres / (float)pixel_xres;
- g_dpi_scale_y = dp_yres / (float)pixel_yres;
- g_dpi_scale_real_x = g_dpi_scale_x;
- g_dpi_scale_real_y = g_dpi_scale_y;
-
- printf("Pixels: %i x %i\n", pixel_xres, pixel_yres);
- printf("Virtual pixels: %i x %i\n", dp_xres, dp_yres);
+ g_display.pixel_in_dps_x = (float)g_display.pixel_xres / g_display.dp_xres;
+ g_display.pixel_in_dps_y = (float)g_display.pixel_yres / g_display.dp_yres;
+ g_display.dpi_scale_x = g_display.dp_xres / (float)g_display.pixel_xres;
+ g_display.dpi_scale_y = g_display.dp_yres / (float)g_display.pixel_yres;
+ g_display.dpi_scale_real_x = g_display.dpi_scale_x;
+ g_display.dpi_scale_real_y = g_display.dpi_scale_y;
+ g_display.Print();
GraphicsContext *graphicsContext = nullptr;
SDL_Window *window = nullptr;
@@ -873,8 +871,8 @@ int main(int argc, char *argv[]) {
}
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;
+ float mx = event.motion.x * g_display.dpi_scale_x;
+ float my = event.motion.y * g_display.dpi_scale_y;
switch (event.type) {
case SDL_QUIT:
@@ -1182,8 +1180,8 @@ int main(int argc, char *argv[]) {
// Disabled by default, needs a workaround to map to psp keys.
if (g_Config.bMouseControl) {
- float scaleFactor_x = g_dpi_scale_x * 0.1 * g_Config.fMouseSensitivity;
- float scaleFactor_y = g_dpi_scale_y * 0.1 * g_Config.fMouseSensitivity;
+ float scaleFactor_x = g_display.dpi_scale_x * 0.1 * g_Config.fMouseSensitivity;
+ float scaleFactor_y = g_display.dpi_scale_y * 0.1 * g_Config.fMouseSensitivity;
AxisInput axisX, axisY;
axisX.axisId = JOYSTICK_AXIS_MOUSE_REL_X;
diff --git a/SDL/SDLVulkanGraphicsContext.cpp b/SDL/SDLVulkanGraphicsContext.cpp
index b01571b626..21108d18b3 100644
--- a/SDL/SDLVulkanGraphicsContext.cpp
+++ b/SDL/SDLVulkanGraphicsContext.cpp
@@ -33,7 +33,7 @@ static uint32_t FlagsFromConfig() {
}
bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message) {
- window = SDL_CreateWindow("Initializing Vulkan...", x, y, pixel_xres, pixel_yres, mode);
+ window = SDL_CreateWindow("Initializing Vulkan...", x, y, g_display.pixel_xres, g_display.pixel_yres, mode);
if (!window) {
fprintf(stderr, "Error creating SDL window: %s\n", SDL_GetError());
exit(1);
diff --git a/UI/BackgroundAudio.cpp b/UI/BackgroundAudio.cpp
index ff83abcfc5..e9f13a4837 100644
--- a/UI/BackgroundAudio.cpp
+++ b/UI/BackgroundAudio.cpp
@@ -257,7 +257,7 @@ BackgroundAudio::~BackgroundAudio() {
BackgroundAudio::Sample *BackgroundAudio::LoadSample(const std::string &path) {
size_t bytes;
- uint8_t *data = VFSReadFile(path.c_str(), &bytes);
+ uint8_t *data = g_VFS.ReadFile(path.c_str(), &bytes);
if (!data) {
return nullptr;
}
diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp
index a639d29b26..bfcb9e662c 100644
--- a/UI/ControlMappingScreen.cpp
+++ b/UI/ControlMappingScreen.cpp
@@ -684,7 +684,7 @@ void TouchTestScreen::render() {
if (touches_[i].id != -1) {
ui_context->Draw()->Circle(touches_[i].x, touches_[i].y, 100.0, 3.0, 80, 0.0f, 0xFFFFFFFF, 1.0);
snprintf(buffer, sizeof(buffer), "%0.1fx%0.1f", touches_[i].x, touches_[i].y);
- ui_context->DrawText(buffer, touches_[i].x, touches_[i].y + (touches_[i].y > dp_yres - 100.0f ? -135.0f : 95.0f), 0xFFFFFFFF, ALIGN_HCENTER | FLAG_DYNAMIC_ASCII);
+ ui_context->DrawText(buffer, touches_[i].x, touches_[i].y + (touches_[i].y > g_display.dp_yres - 100.0f ? -135.0f : 95.0f), 0xFFFFFFFF, ALIGN_HCENTER | FLAG_DYNAMIC_ASCII);
}
}
@@ -704,11 +704,11 @@ void TouchTestScreen::render() {
#if PPSSPP_PLATFORM(ANDROID)
display_xres, display_yres,
#endif
- dp_xres, dp_yres,
- pixel_xres, pixel_yres,
- g_dpi,
- g_dpi_scale_x, g_dpi_scale_y,
- g_dpi_scale_real_x, g_dpi_scale_real_y, extra_debug);
+ g_display.dp_xres, g_display.dp_yres,
+ g_display.pixel_xres, g_display.pixel_yres,
+ g_display.dpi,
+ g_display.dpi_scale_x, g_display.dpi_scale_y,
+ g_display.dpi_scale_real_x, g_display.dpi_scale_real_y, extra_debug);
// On Android, also add joystick debug data.
diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp
index d9fc09d7de..82cb3c159e 100644
--- a/UI/DevScreens.cpp
+++ b/UI/DevScreens.cpp
@@ -101,8 +101,7 @@ void DevMenuScreen::CreatePopupContents(UI::ViewGroup *parent) {
items->Add(new Choice(dev->T("Jit Compare")))->OnClick.Handle(this, &DevMenuScreen::OnJitCompare);
items->Add(new Choice(dev->T("Shader Viewer")))->OnClick.Handle(this, &DevMenuScreen::OnShaderView);
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN) {
- // TODO: Make a new allocator visualizer for VMA.
- // items->Add(new CheckBox(&g_Config.bShowAllocatorDebug, dev->T("Allocator Viewer")));
+ items->Add(new CheckBox(&g_Config.bShowAllocatorDebug, dev->T("Allocator Viewer")));
items->Add(new CheckBox(&g_Config.bShowGpuProfile, dev->T("GPU Profile")));
}
items->Add(new Choice(dev->T("Toggle Freeze")))->OnClick.Handle(this, &DevMenuScreen::OnFreezeFrame);
@@ -585,10 +584,10 @@ void SystemInfoScreen::CreateViews() {
System_GetPropertyInt(SYSPROP_DISPLAY_XRES),
System_GetPropertyInt(SYSPROP_DISPLAY_YRES))));
deviceSpecs->Add(new InfoItem(si->T("UI Resolution"), StringFromFormat("%dx%d (%s: %0.2f)",
- dp_xres,
- dp_yres,
+ g_display.dp_xres,
+ g_display.dp_yres,
si->T("DPI"),
- g_dpi)));
+ g_display.dpi)));
#endif
#if !PPSSPP_PLATFORM(WINDOWS)
diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp
index 2c661d2965..791dc8c414 100644
--- a/UI/DisplayLayoutScreen.cpp
+++ b/UI/DisplayLayoutScreen.cpp
@@ -50,10 +50,10 @@ enum Mode {
static Bounds FRectToBounds(FRect rc) {
Bounds b;
- b.x = rc.x * g_dpi_scale_x;
- b.y = rc.y * g_dpi_scale_y;
- b.w = rc.w * g_dpi_scale_x;
- b.h = rc.h * g_dpi_scale_y;
+ b.x = rc.x * g_display.dpi_scale_x;
+ b.y = rc.y * g_display.dpi_scale_y;
+ b.w = rc.w * g_display.dpi_scale_x;
+ b.h = rc.h * g_display.dpi_scale_y;
return b;
}
@@ -132,7 +132,7 @@ void DisplayLayoutScreen::DrawBackground(UIContext &dc) {
// we have to draw a substitute ourselves.
// TODO: Clean this up a bit, this GetScreenFrame/CenterDisplay combo is too common.
- FRect screenFrame = GetScreenFrame(pixel_xres, pixel_yres);
+ FRect screenFrame = GetScreenFrame(g_display.pixel_xres, g_display.pixel_yres);
FRect rc;
CenterDisplayOutputRect(&rc, 480.0f, 272.0f, screenFrame, g_Config.iInternalScreenRotation);
diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp
index 28287cc786..a86a460acb 100644
--- a/UI/EmuScreen.cpp
+++ b/UI/EmuScreen.cpp
@@ -311,16 +311,16 @@ void EmuScreen::bootGame(const Path &filename) {
coreParam.headLess = false;
if (g_Config.iInternalResolution == 0) {
- coreParam.renderWidth = pixel_xres;
- coreParam.renderHeight = pixel_yres;
+ coreParam.renderWidth = g_display.pixel_xres;
+ coreParam.renderHeight = g_display.pixel_yres;
} else {
if (g_Config.iInternalResolution < 0)
g_Config.iInternalResolution = 1;
coreParam.renderWidth = 480 * g_Config.iInternalResolution;
coreParam.renderHeight = 272 * g_Config.iInternalResolution;
}
- coreParam.pixelWidth = pixel_xres;
- coreParam.pixelHeight = pixel_yres;
+ coreParam.pixelWidth = g_display.pixel_xres;
+ coreParam.pixelHeight = g_display.pixel_yres;
std::string error_string;
if (!PSP_InitStart(coreParam, &error_string)) {
@@ -1027,8 +1027,8 @@ void EmuScreen::update() {
#ifndef _WIN32
const Bounds &bounds = screenManager()->getUIContext()->GetBounds();
- PSP_CoreParameter().pixelWidth = pixel_xres * bounds.w / dp_xres;
- PSP_CoreParameter().pixelHeight = pixel_yres * bounds.h / dp_yres;
+ PSP_CoreParameter().pixelWidth = g_display.pixel_xres * bounds.w / g_display.dp_xres;
+ PSP_CoreParameter().pixelHeight = g_display.pixel_yres * bounds.h / g_display.dp_yres;
#endif
if (!invalid_) {
@@ -1371,13 +1371,13 @@ void EmuScreen::preRender() {
Viewport viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
- viewport.Width = pixel_xres;
- viewport.Height = pixel_yres;
+ viewport.Width = g_display.pixel_xres;
+ viewport.Height = g_display.pixel_yres;
viewport.MaxDepth = 1.0;
viewport.MinDepth = 0.0;
- draw->SetViewports(1, &viewport);
+ draw->SetViewport(viewport);
}
- draw->SetTargetSize(pixel_xres, pixel_yres);
+ draw->SetTargetSize(g_display.pixel_xres, g_display.pixel_yres);
}
void EmuScreen::postRender() {
@@ -1519,11 +1519,11 @@ void EmuScreen::renderUI() {
Viewport viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
- viewport.Width = pixel_xres;
- viewport.Height = pixel_yres;
+ viewport.Width = g_display.pixel_xres;
+ viewport.Height = g_display.pixel_yres;
viewport.MaxDepth = 1.0;
viewport.MinDepth = 0.0;
- thin3d->SetViewports(1, &viewport);
+ thin3d->SetViewport(viewport);
if (root_) {
UI::LayoutViewHierarchy(*ctx, root_, false);
diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp
index c71e5e6fc4..ceef80cedd 100644
--- a/UI/GameInfoCache.cpp
+++ b/UI/GameInfoCache.cpp
@@ -314,7 +314,7 @@ static bool ReadFileToString(IFileSystem *fs, const char *filename, std::string
static bool ReadVFSToString(const char *filename, std::string *contents, std::mutex *mtx) {
size_t sz;
- uint8_t *data = VFSReadFile(filename, &sz);
+ uint8_t *data = g_VFS.ReadFile(filename, &sz);
if (data) {
if (mtx) {
std::lock_guard lock(*mtx);
diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp
index 9e4bb43a6f..0ef3060135 100644
--- a/UI/GameSettingsScreen.cpp
+++ b/UI/GameSettingsScreen.cpp
@@ -66,10 +66,10 @@
#include "Core/Instance.h"
#include "Core/System.h"
#include "Core/Reporting.h"
-#include "Core/TextureReplacer.h"
#include "Core/WebServer.h"
#include "Core/HLE/sceUsbCam.h"
#include "Core/HLE/sceUsbMic.h"
+#include "GPU/Common/TextureReplacer.h"
#include "GPU/Common/PostShader.h"
#include "android/jni/TestRunner.h"
#include "GPU/GPUInterface.h"
@@ -237,8 +237,10 @@ void GameSettingsScreen::CreateViews() {
if (!vertical) {
leftSide += 200.0f;
}
- settingInfo_ = new SettingInfoMessage(ALIGN_CENTER | FLAG_WRAP_TEXT, new AnchorLayoutParams(dp_xres - leftSide - 40.0f, WRAP_CONTENT, leftSide, dp_yres - 80.0f - 40.0f, NONE, NONE));
- settingInfo_->SetBottomCutoff(dp_yres - 200.0f);
+ settingInfo_ = new SettingInfoMessage(ALIGN_CENTER | FLAG_WRAP_TEXT, new AnchorLayoutParams(
+ g_display.dp_xres - leftSide - 40.0f, WRAP_CONTENT,
+ leftSide, g_display.dp_yres - 80.0f - 40.0f, NONE, NONE));
+ settingInfo_->SetBottomCutoff(g_display.dp_yres - 200.0f);
root_->Add(settingInfo_);
// Show it again if we recreated the view
@@ -273,7 +275,7 @@ void GameSettingsScreen::CreateViews() {
#if !defined(MOBILE_DEVICE) || PPSSPP_PLATFORM(ANDROID)
// Hide search if screen is too small.
- if (dp_xres < dp_yres || dp_yres >= 500) {
+ if (g_display.dp_xres < g_display.dp_yres || g_display.dp_yres >= 500) {
auto se = GetI18NCategory("Search");
// Search
LinearLayout *searchSettings = AddTab("GameSettingsSearch", ms->T("Search"), true);
@@ -1141,12 +1143,11 @@ void GameSettingsScreen::CreateVRSettings(UI::ViewGroup *vrSettings) {
vrSettings->Add(new ItemHeader(vr->T("Experts only")));
vrSettings->Add(new CheckBox(&g_Config.bManualForceVR, vr->T("Manual switching between flat screen and VR using SCREEN key")));
- static const char *vrHeadRotations[] = { vr->T("Disabled"), vr->T("Horizontal only"), vr->T("Horizontal and vertical") };
- vrSettings->Add(new PopupMultiChoice(&g_Config.iHeadRotation, vr->T("Map HMD rotations on keys instead of VR camera"), vrHeadRotations, 0, ARRAY_SIZE(vrHeadRotations), vr->GetName(), screenManager()));
+ vrSettings->Add(new CheckBox(&g_Config.bHeadRotationEnabled, vr->T("Map HMD rotations on keys instead of VR camera")));
PopupSliderChoiceFloat *vrHeadRotationScale = vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fHeadRotationScale, 0.1f, 10.0f, vr->T("Game camera rotation step per frame"), 0.1f, screenManager(), "°"));
- vrHeadRotationScale->SetEnabledFunc([&] { return g_Config.iHeadRotation > 0; });
+ vrHeadRotationScale->SetEnabledPtr(&g_Config.bHeadRotationEnabled);
CheckBox *vrHeadRotationSmoothing = vrSettings->Add(new CheckBox(&g_Config.bHeadRotationSmoothing, vr->T("Game camera uses rotation smoothing")));
- vrHeadRotationSmoothing->SetEnabledFunc([&] { return g_Config.iHeadRotation > 0; });
+ vrHeadRotationSmoothing->SetEnabledPtr(&g_Config.bHeadRotationEnabled);
vrSettings->Add(new CheckBox(&g_Config.bEnableMotions, vr->T("Map controller movements to keys")));
PopupSliderChoiceFloat *vrMotions = vrSettings->Add(new PopupSliderChoiceFloat(&g_Config.fMotionLength, 0.3f, 1.0f, vr->T("Motion needed to generate action"), 0.1f, screenManager(), vr->T("m")));
vrMotions->SetEnabledPtr(&g_Config.bEnableMotions);
@@ -1772,6 +1773,10 @@ void DeveloperToolsScreen::CreateViews() {
static const char *cpuCores[] = {"Interpreter", "Dynarec (JIT)", "IR Interpreter"};
PopupMultiChoice *core = list->Add(new PopupMultiChoice(&g_Config.iCpuCore, gr->T("CPU Core"), cpuCores, 0, ARRAY_SIZE(cpuCores), sy->GetName(), screenManager()));
core->OnChoice.Handle(this, &DeveloperToolsScreen::OnJitAffectingSetting);
+ core->OnChoice.Add([](UI::EventParams &) {
+ g_Config.NotifyUpdatedCpuCore();
+ return UI::EVENT_DONE;
+ });
if (!canUseJit) {
core->HideChoice(1);
}
diff --git a/UI/GamepadEmu.cpp b/UI/GamepadEmu.cpp
index efb5b6bc3a..5f997fca42 100644
--- a/UI/GamepadEmu.cpp
+++ b/UI/GamepadEmu.cpp
@@ -711,7 +711,7 @@ void InitPadLayout(float xres, float yres, float globalScale) {
//select, start, throttle--------------------------------------------
//space between the bottom keys (space between select, start and un-throttle)
float bottom_key_spacing = 100;
- if (dp_xres < 750) {
+ if (g_display.dp_xres < 750) {
bottom_key_spacing *= 0.8f;
}
@@ -956,8 +956,8 @@ bool GestureGamepad::Touch(const TouchInput &input) {
void GestureGamepad::Update() {
const float th = 1.0f;
- float dx = deltaX_ * g_dpi_scale_x * g_Config.fSwipeSensitivity;
- float dy = deltaY_ * g_dpi_scale_y * g_Config.fSwipeSensitivity;
+ float dx = deltaX_ * g_display.dpi_scale_x * g_Config.fSwipeSensitivity;
+ float dy = deltaY_ * g_display.dpi_scale_y * g_Config.fSwipeSensitivity;
if (g_Config.iSwipeRight != 0) {
if (dx > th) {
controlMapper_->pspKey(DEVICE_ID_TOUCH, GestureKey::keyList[g_Config.iSwipeRight-1], KEY_DOWN);
diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp
index c1bb989b01..b9e93d7ab0 100644
--- a/UI/MiscScreens.cpp
+++ b/UI/MiscScreens.cpp
@@ -134,7 +134,7 @@ public:
dc.BeginNoTex();
// Be sure to not overflow our vertex buffer
- const float step = ceil(24*bounds.w/pixel_in_dps_x) > MAX_VERTS ? 24*bounds.w/(MAX_VERTS-48) : pixel_in_dps_x;
+ const float step = ceilf(24*bounds.w/ g_display.pixel_in_dps_x) > MAX_VERTS ? 24*bounds.w/(MAX_VERTS-48) : g_display.pixel_in_dps_x;
t *= speed;
for (float x = 0; x < bounds.w; x += step) {
@@ -146,8 +146,8 @@ public:
dc.Draw()->RectVGradient(x, wave1*bounds.h, step, (1.0-wave1)*bounds.h, color, 0x00000000);
// Add some "antialiasing"
- dc.Draw()->RectVGradient(x, wave0*bounds.h-3*pixel_in_dps_y, step, 3*pixel_in_dps_y, 0x00000000, color);
- dc.Draw()->RectVGradient(x, wave1*bounds.h-3*pixel_in_dps_y, step, 3*pixel_in_dps_y, 0x00000000, color);
+ dc.Draw()->RectVGradient(x, wave0*bounds.h-3.0f * g_display.pixel_in_dps_y, step, 3.0f * g_display.pixel_in_dps_y, 0x00000000, color);
+ dc.Draw()->RectVGradient(x, wave1*bounds.h-3.0f * g_display.pixel_in_dps_y, step, 3.0f * g_display.pixel_in_dps_y, 0x00000000, color);
}
dc.Flush();
@@ -371,11 +371,11 @@ void DrawGameBackground(UIContext &dc, const Path &gamePath, float x, float y, f
Viewport viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
- viewport.Width = pixel_xres;
- viewport.Height = pixel_yres;
+ viewport.Width = g_display.pixel_xres;
+ viewport.Height = g_display.pixel_yres;
viewport.MaxDepth = 1.0;
viewport.MinDepth = 0.0;
- draw->SetViewports(1, &viewport);
+ draw->SetViewport(viewport);
dc.BeginFrame();
dc.RebindTexture();
dc.Begin();
@@ -590,7 +590,7 @@ NewLanguageScreen::NewLanguageScreen(const std::string &title) : ListPopupScreen
auto &langValuesMapping = g_Config.GetLangValuesMapping();
std::vector tempLangs;
- VFSGetFileListing("lang", &tempLangs, "ini");
+ g_VFS.GetFileListing("lang", &tempLangs, "ini");
std::vector listing;
int selected = -1;
int counter = 0;
@@ -1080,7 +1080,7 @@ void SettingInfoMessage::Show(const std::string &text, const UI::View *refView)
if (b.y >= cutOffY_) {
ReplaceLayoutParams(new UI::AnchorLayoutParams(lp->width, lp->height, lp->left, 80.0f, lp->right, lp->bottom, lp->center));
} else {
- ReplaceLayoutParams(new UI::AnchorLayoutParams(lp->width, lp->height, lp->left, dp_yres - 80.0f - 40.0f, lp->right, lp->bottom, lp->center));
+ ReplaceLayoutParams(new UI::AnchorLayoutParams(lp->width, lp->height, lp->left, g_display.dp_yres - 80.0f - 40.0f, lp->right, lp->bottom, lp->center));
}
}
text_->SetText(text);
diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp
index 50aa992c8b..e482eca117 100644
--- a/UI/NativeApp.cpp
+++ b/UI/NativeApp.cpp
@@ -67,7 +67,8 @@
#include "Common/Profiler/Profiler.h"
#include "Common/Data/Encoding/Utf8.h"
#include "Common/File/VFS/VFS.h"
-#include "Common/File/VFS/AssetReader.h"
+#include "Common/File/VFS/ZipFileReader.h"
+#include "Common/File/VFS/DirectoryReader.h"
#include "Common/CPUDetect.h"
#include "Common/File/FileUtil.h"
#include "Common/TimeUtil.h"
@@ -467,27 +468,27 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
// We want this to be FIRST.
#if PPSSPP_PLATFORM(IOS) || PPSSPP_PLATFORM(MAC)
// Packed assets are included in app
- VFSRegister("", new DirectoryAssetReader(Path(external_dir)));
+ g_VFS.Register("", new DirectoryReader(Path(external_dir)));
#endif
#if defined(ASSETS_DIR)
- VFSRegister("", new DirectoryAssetReader(Path(ASSETS_DIR)));
+ g_VFS.Register("", new DirectoryReader(Path(ASSETS_DIR)));
#endif
#if !defined(MOBILE_DEVICE) && !defined(_WIN32) && !PPSSPP_PLATFORM(SWITCH)
- VFSRegister("", new DirectoryAssetReader(File::GetExeDirectory() / "assets"));
- VFSRegister("", new DirectoryAssetReader(File::GetExeDirectory()));
- VFSRegister("", new DirectoryAssetReader(Path("/usr/local/share/ppsspp/assets")));
- VFSRegister("", new DirectoryAssetReader(Path("/usr/local/share/games/ppsspp/assets")));
- VFSRegister("", new DirectoryAssetReader(Path("/usr/share/ppsspp/assets")));
- VFSRegister("", new DirectoryAssetReader(Path("/usr/share/games/ppsspp/assets")));
+ g_VFS.Register("", new DirectoryReader(File::GetExeDirectory() / "assets"));
+ g_VFS.Register("", new DirectoryReader(File::GetExeDirectory()));
+ g_VFS.Register("", new DirectoryReader(Path("/usr/local/share/ppsspp/assets")));
+ g_VFS.Register("", new DirectoryReader(Path("/usr/local/share/games/ppsspp/assets")));
+ g_VFS.Register("", new DirectoryReader(Path("/usr/share/ppsspp/assets")));
+ g_VFS.Register("", new DirectoryReader(Path("/usr/share/games/ppsspp/assets")));
#endif
#if PPSSPP_PLATFORM(SWITCH)
Path assetPath = Path(user_data_path) / "assets";
- VFSRegister("", new DirectoryAssetReader(assetPath));
+ g_VFS.Register("", new DirectoryReader(assetPath));
#else
- VFSRegister("", new DirectoryAssetReader(Path("assets")));
+ g_VFS.Register("", new DirectoryReader(Path("assets")));
#endif
- VFSRegister("", new DirectoryAssetReader(Path(savegame_dir)));
+ g_VFS.Register("", new DirectoryReader(Path(savegame_dir)));
#if (defined(MOBILE_DEVICE) || !defined(USING_QT_UI)) && !PPSSPP_PLATFORM(UWP)
if (host == nullptr) {
@@ -777,7 +778,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
}
#elif defined(USING_QT_UI)
size_t fontSize = 0;
- uint8_t *fontData = VFSReadFile("Roboto-Condensed.ttf", &fontSize);
+ uint8_t *fontData = g_VFS.ReadFile("Roboto-Condensed.ttf", &fontSize);
if (fontData) {
int fontID = QFontDatabase::addApplicationFontFromData(QByteArray((const char *)fontData, fontSize));
delete [] fontData;
@@ -914,7 +915,7 @@ bool NativeInitGraphics(GraphicsContext *graphicsContext) {
g_gameInfoCache = new GameInfoCache();
if (gpu) {
- gpu->DeviceRestore();
+ gpu->DeviceRestore(g_draw);
}
INFO_LOG(SYSTEM, "NativeInitGraphics completed");
@@ -1095,8 +1096,8 @@ void NativeRender(GraphicsContext *graphicsContext) {
g_BackgroundAudio.Update();
}
- float xres = dp_xres;
- float yres = dp_yres;
+ float xres = g_display.dp_xres;
+ float yres = g_display.dp_yres;
// Apply the UIContext bounds as a 2D transformation matrix.
// TODO: This should be moved into the draw context...
@@ -1109,7 +1110,9 @@ void NativeRender(GraphicsContext *graphicsContext) {
ortho.setOrthoD3D(0.0f, xres, yres, 0.0f, -1.0f, 1.0f);
Matrix4x4 translation;
// Account for the small window adjustment.
- translation.setTranslation(Vec3(-0.5f * g_dpi_scale_x / g_dpi_scale_real_x, -0.5f * g_dpi_scale_y / g_dpi_scale_real_y, 0.0f));
+ translation.setTranslation(Vec3(
+ -0.5f * g_display.dpi_scale_x / g_display.dpi_scale_real_x,
+ -0.5f * g_display.dpi_scale_y / g_display.dpi_scale_real_y, 0.0f));
ortho = translation * ortho;
break;
case GPUBackend::DIRECT3D11:
@@ -1122,8 +1125,8 @@ void NativeRender(GraphicsContext *graphicsContext) {
}
// Compensate for rotated display if needed.
- if (g_display_rotation != DisplayRotation::ROTATE_0) {
- ortho = ortho * g_display_rot_matrix;
+ if (g_display.rotation != DisplayRotation::ROTATE_0) {
+ ortho = ortho * g_display.rot_matrix;
}
ui_draw2d.PushDrawMatrix(ortho);
@@ -1151,13 +1154,13 @@ void NativeRender(GraphicsContext *graphicsContext) {
if (uiContext) {
// Modifying the bounds here can be used to "inset" the whole image to gain borders for TV overscan etc.
// The UI now supports any offset but not the EmuScreen yet.
- uiContext->SetBounds(Bounds(0, 0, dp_xres, dp_yres));
+ uiContext->SetBounds(Bounds(0, 0, g_display.dp_xres, g_display.dp_yres));
// OSX 10.6 and SDL 1.2 bug.
#if defined(__APPLE__) && !defined(USING_QT_UI)
- static int dp_xres_old = dp_xres;
- if (dp_xres != dp_xres_old) {
- dp_xres_old = dp_xres;
+ static int dp_xres_old = g_display.dp_xres;
+ if (g_display.dp_xres != dp_xres_old) {
+ dp_xres_old = g_display.dp_xres;
}
#endif
}
@@ -1167,8 +1170,8 @@ void NativeRender(GraphicsContext *graphicsContext) {
// TODO: Move this to the GraphicsContext objects for each backend.
#if !PPSSPP_PLATFORM(WINDOWS) && !defined(ANDROID)
- PSP_CoreParameter().pixelWidth = pixel_xres;
- PSP_CoreParameter().pixelHeight = pixel_yres;
+ PSP_CoreParameter().pixelWidth = g_display.pixel_xres;
+ PSP_CoreParameter().pixelHeight = g_display.pixel_yres;
NativeMessageReceived("gpu_displayResized", "");
#endif
} else {
@@ -1402,7 +1405,7 @@ void NativeAxis(const AxisInput &axis) {
// sent with respect to the portrait coordinate system, while we
// take all events in landscape.
// see [http://developer.android.com/guide/topics/sensors/sensors_overview.html] for details
- bool landscape = dp_yres < dp_xres;
+ bool landscape = g_display.dp_yres < g_display.dp_xres;
// now transform out current tilt to the calibrated coordinate system
ProcessTilt(landscape, tiltBaseAngleY, tiltX, tiltY, tiltZ,
g_Config.bInvertTiltX, g_Config.bInvertTiltY,
diff --git a/UI/ReportScreen.cpp b/UI/ReportScreen.cpp
index c192a021a5..7bd0815de5 100644
--- a/UI/ReportScreen.cpp
+++ b/UI/ReportScreen.cpp
@@ -253,7 +253,7 @@ void ReportScreen::CreateViews() {
Margins actionMenuMargins(0, 20, 15, 0);
Margins contentMargins(0, 20, 5, 5);
- float leftColumnWidth = dp_xres - actionMenuMargins.horiz() - contentMargins.horiz() - 300.0f;
+ float leftColumnWidth = g_display.dp_xres - actionMenuMargins.horiz() - contentMargins.horiz() - 300.0f;
ViewGroup *leftColumn = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(WRAP_CONTENT, FILL_PARENT, 0.4f, contentMargins));
LinearLayout *leftColumnItems = new LinearLayout(ORIENT_VERTICAL, new LayoutParams(WRAP_CONTENT, FILL_PARENT));
ViewGroup *rightColumn = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(300, FILL_PARENT, actionMenuMargins));
diff --git a/UI/Theme.cpp b/UI/Theme.cpp
index 59be83522a..9119259e7c 100644
--- a/UI/Theme.cpp
+++ b/UI/Theme.cpp
@@ -84,7 +84,7 @@ static void LoadThemeInfo(const std::vector &directories) {
for (size_t d = 0; d < directories.size(); d++) {
std::vector fileInfo;
- VFSGetFileListing(directories[d].c_str(), &fileInfo, "ini:");
+ g_VFS.GetFileListing(directories[d].c_str(), &fileInfo, "ini:");
if (fileInfo.empty()) {
File::GetFilesInDir(directories[d], &fileInfo, "ini:");
@@ -104,7 +104,7 @@ static void LoadThemeInfo(const std::vector &directories) {
if (path.ToString().substr(0, 7) == "assets/")
path = Path(path.ToString().substr(7));
- if (ini.LoadFromVFS(name.ToString()) || ini.Load(fileInfo[f].fullName)) {
+ if (ini.LoadFromVFS(g_VFS, name.ToString()) || ini.Load(fileInfo[f].fullName)) {
success = true;
}
@@ -138,7 +138,7 @@ static void LoadThemeInfo(const std::vector &directories) {
tmpPath = (path / tmpPath).ToString();
File::FileInfo tmpInfo;
- if (VFSGetFileInfo((tmpPath+".meta").c_str(), &tmpInfo) && VFSGetFileInfo((tmpPath+".zim").c_str(), &tmpInfo)) {
+ if (g_VFS.GetFileInfo((tmpPath + ".meta").c_str(), &tmpInfo) && g_VFS.GetFileInfo((tmpPath + ".zim").c_str(), &tmpInfo)) {
info.sUIAtlas = tmpPath;
}
}
@@ -158,7 +158,7 @@ static UI::Style MakeStyle(uint32_t fg, uint32_t bg) {
static void LoadAtlasMetadata(Atlas &metadata, const char *filename, bool required) {
size_t atlas_data_size = 0;
- const uint8_t *atlas_data = VFSReadFile(filename, &atlas_data_size);
+ const uint8_t *atlas_data = g_VFS.ReadFile(filename, &atlas_data_size);
bool load_success = atlas_data != nullptr && metadata.Load(atlas_data, atlas_data_size);
if (!load_success) {
if (required)
diff --git a/UI/TouchControlLayoutScreen.cpp b/UI/TouchControlLayoutScreen.cpp
index d3c85b63dc..32b230c93d 100644
--- a/UI/TouchControlLayoutScreen.cpp
+++ b/UI/TouchControlLayoutScreen.cpp
@@ -318,8 +318,8 @@ public:
float xOffset = bounds_.x;
float yOffset = bounds_.y;
- dc.Draw()->Rect((x1+x2)/2 + xOffset - pixel_in_dps_x, y1 + yOffset, 3.0*pixel_in_dps_x, y2-y1, col);
- dc.Draw()->Rect(x1 + xOffset, (y1+y2)/2 + yOffset - pixel_in_dps_y, x2-x1, 3.0*pixel_in_dps_y, col);
+ dc.Draw()->Rect((x1+x2)/2 + xOffset - g_display.pixel_in_dps_x, y1 + yOffset, 3.0f * g_display.pixel_in_dps_x, y2-y1, col);
+ dc.Draw()->Rect(x1 + xOffset, (y1+y2)/2 + yOffset - g_display.pixel_in_dps_y, x2-x1, 3.0f * g_display.pixel_in_dps_y, col);
for (int x = x1 + (x1+x2)/2 % g_Config.iTouchSnapGridSize; x < x2; x += g_Config.iTouchSnapGridSize)
dc.Draw()->vLine(x + xOffset, y1 + yOffset, y2 + yOffset, col);
diff --git a/UI/UI.vcxproj b/UI/UI.vcxproj
index be370e4ef1..f4c85a7185 100644
--- a/UI/UI.vcxproj
+++ b/UI/UI.vcxproj
@@ -302,6 +302,7 @@
MultiThreaded
$(EXTERNAL_COMPILE_OPTIONS)
ProgramDatabase
+ StreamingSIMDExtensions2
Windows
diff --git a/UWP/Armips_UWP/Armips_UWP.vcxproj b/UWP/Armips_UWP/Armips_UWP.vcxproj
index 4610681d23..330b730cd1 100644
--- a/UWP/Armips_UWP/Armips_UWP.vcxproj
+++ b/UWP/Armips_UWP/Armips_UWP.vcxproj
@@ -42,43 +42,16 @@
14.0
true
Windows Store
- 10.0.17763.0
- 10.0.15063.0
+ 10.0
+ 10.0.19041.0
10.0
-
+
StaticLibrary
true
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
+
StaticLibrary
false
true
@@ -88,61 +61,11 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
- false
- $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips;$(ProjectDir)..\..\ext\armips\ext\filesystem\include;$(ProjectDir)..\..\ext\armips\ext\tinyformat;
-
-
- false
- $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips;$(ProjectDir)..\..\ext\armips\ext\filesystem\include;$(ProjectDir)..\..\ext\armips\ext\tinyformat;
-
-
- false
- $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips;$(ProjectDir)..\..\ext\armips\ext\filesystem\include;$(ProjectDir)..\..\ext\armips\ext\tinyformat;
-
-
- false
- $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips;$(ProjectDir)..\..\ext\armips\ext\filesystem\include;$(ProjectDir)..\..\ext\armips\ext\tinyformat;
-
-
- false
- $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips;$(ProjectDir)..\..\ext\armips\ext\filesystem\include;$(ProjectDir)..\..\ext\armips\ext\tinyformat;
-
-
- false
- $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips;$(ProjectDir)..\..\ext\armips\ext\filesystem\include;$(ProjectDir)..\..\ext\armips\ext\tinyformat;
-
-
- false
- $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips;$(ProjectDir)..\..\ext\armips\ext\filesystem\include;$(ProjectDir)..\..\ext\armips\ext\tinyformat;
-
-
+
false
$(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips;$(ProjectDir)..\..\ext\armips\ext\filesystem\include;$(ProjectDir)..\..\ext\armips\ext\tinyformat;
@@ -373,17 +296,8 @@
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
-
+ Create
+
diff --git a/UWP/CommonUWP/CommonUWP.vcxproj b/UWP/CommonUWP/CommonUWP.vcxproj
index 99e542cc99..6160d923d6 100644
--- a/UWP/CommonUWP/CommonUWP.vcxproj
+++ b/UWP/CommonUWP/CommonUWP.vcxproj
@@ -58,144 +58,30 @@
14.0
true
Windows Store
- 10.0.15063.0
+ 10.0.19041.0
10.0
- 10.0.17763.0
+ 10.0
-
+
StaticLibrary
true
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
+
StaticLibrary
false
false
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
+
false
@@ -420,7 +306,8 @@
-
+
+
@@ -557,7 +444,8 @@
-
+
+
diff --git a/UWP/CommonUWP/CommonUWP.vcxproj.filters b/UWP/CommonUWP/CommonUWP.vcxproj.filters
index f8e8679432..40b8f80da4 100644
--- a/UWP/CommonUWP/CommonUWP.vcxproj.filters
+++ b/UWP/CommonUWP/CommonUWP.vcxproj.filters
@@ -252,7 +252,10 @@
Data\Format
-
+
+ File\VFS
+
+
File\VFS
@@ -589,7 +592,10 @@
Data\Format
-
+
+ File\VFS
+
+
File\VFS
diff --git a/UWP/CoreUWP/CoreUWP.vcxproj b/UWP/CoreUWP/CoreUWP.vcxproj
index 2d89c268b3..6fe4ea1320 100644
--- a/UWP/CoreUWP/CoreUWP.vcxproj
+++ b/UWP/CoreUWP/CoreUWP.vcxproj
@@ -58,144 +58,30 @@
14.0
true
Windows Store
- 10.0.15063.0
+ 10.0.19041.0
10.0
- 10.0.17763.0
+ 10.0
-
+
StaticLibrary
true
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
+
StaticLibrary
false
false
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
+
false
@@ -204,7 +90,7 @@
false
false
pch.h
- ../../ffmpeg/Windows10/x86/include;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../../ffmpeg/Windows10/x86/include;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
USE_FFMPEG;WITH_UPNP;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;ARMIPS_USE_STD_FILESYSTEM;%(PreprocessorDefinitions)
stdcpp17
@@ -220,7 +106,7 @@
false
false
pch.h
- ../../ffmpeg/Windows10/x86/include;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../../ffmpeg/Windows10/x86/include;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
USE_FFMPEG;WITH_UPNP;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;ARMIPS_USE_STD_FILESYSTEM;%(PreprocessorDefinitions)
stdcpp17
@@ -236,7 +122,7 @@
false
false
pch.h
- ../../ffmpeg/Windows10/x86/include;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../../ffmpeg/Windows10/x86/include;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
USE_FFMPEG;WITH_UPNP;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;ARMIPS_USE_STD_FILESYSTEM;%(PreprocessorDefinitions)
stdcpp17
@@ -252,7 +138,7 @@
false
false
pch.h
- ../../ffmpeg/Windows10/ARM/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../../ffmpeg/Windows10/ARM/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
USE_FFMPEG;WITH_UPNP;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;ARMIPS_USE_STD_FILESYSTEM;%(ClCompile.PreprocessorDefinitions)
stdcpp17
@@ -268,7 +154,7 @@
false
false
pch.h
- ../../ffmpeg/Windows10/ARM64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../../ffmpeg/Windows10/ARM64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
USE_FFMPEG;WITH_UPNP;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;ARMIPS_USE_STD_FILESYSTEM;%(ClCompile.PreprocessorDefinitions)
stdcpp17
@@ -284,7 +170,8 @@
false
false
pch.h
- ../../ffmpeg/Windows10/ARM/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../../ffmpeg/Windows10/ARM/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../../ffmpeg/Windows10/ARM64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
USE_FFMPEG;WITH_UPNP;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;ARMIPS_USE_STD_FILESYSTEM;%(ClCompile.PreprocessorDefinitions)
stdcpp17
@@ -300,7 +187,7 @@
false
false
pch.h
- ../../ffmpeg/Windows10/ARM64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../../ffmpeg/Windows10/ARM64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
USE_FFMPEG;WITH_UPNP;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;ARMIPS_USE_STD_FILESYSTEM;%(ClCompile.PreprocessorDefinitions)
stdcpp17
@@ -316,7 +203,7 @@
false
false
pch.h
- ../../ffmpeg/Windows10/ARM/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../../ffmpeg/Windows10/ARM/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
USE_FFMPEG;WITH_UPNP;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;ARMIPS_USE_STD_FILESYSTEM;%(ClCompile.PreprocessorDefinitions)
stdcpp17
@@ -332,7 +219,7 @@
false
false
pch.h
- ../../ffmpeg/Windows10/ARM64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../../ffmpeg/Windows10/ARM64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
USE_FFMPEG;WITH_UPNP;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;ARMIPS_USE_STD_FILESYSTEM;%(ClCompile.PreprocessorDefinitions)
stdcpp17
@@ -348,7 +235,7 @@
false
false
pch.h
- ../../ffmpeg/Windows10/x64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../../ffmpeg/Windows10/x64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
USE_FFMPEG;WITH_UPNP;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;ARMIPS_USE_STD_FILESYSTEM;%(PreprocessorDefinitions)
stdcpp17
@@ -364,7 +251,7 @@
false
false
pch.h
- ../../ffmpeg/Windows10/x64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../../ffmpeg/Windows10/x64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
USE_FFMPEG;WITH_UPNP;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;ARMIPS_USE_STD_FILESYSTEM;%(PreprocessorDefinitions)
stdcpp17
@@ -380,7 +267,7 @@
false
false
pch.h
- ../../ffmpeg/Windows10/x64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../../ffmpeg/Windows10/x64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
USE_FFMPEG;WITH_UPNP;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;ARMIPS_USE_STD_FILESYSTEM;%(PreprocessorDefinitions)
stdcpp17
@@ -589,7 +476,6 @@
-
@@ -642,20 +528,7 @@
-
- ../../ffmpeg/Windows10/x86/include;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/x86/include;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/x86/include;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/ARM/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/ARM64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/ARM/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/ARM64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/ARM/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/ARM64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/x64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/x64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/x64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
-
+
@@ -836,20 +709,7 @@
-
- ../../ffmpeg/Windows10/x86/include;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/x86/include;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/x86/include;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/ARM/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/ARM64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/ARM/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/ARM64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/ARM/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/ARM64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/x64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/x64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
- ../../ffmpeg/Windows10/x64/include;../../ffmpeg/WindowsInclude;../..;../../ext/native;../../ext/snappy;../../ext/libpng17;../../Common;../../ext/zlib;../../ext/zstd/lib;../../ext;../../ext/armips/;../../ext/armips/ext/filesystem/include/;../../ext/armips/ext/tinyformat/;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
-
+
@@ -878,7 +738,6 @@
-
@@ -896,4467 +755,606 @@
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ NotUsing
+
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
+ NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
+ NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
+ NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
+ NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
+ NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
+ NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
+ NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
+ NotUsing
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
+ Create
diff --git a/UWP/CoreUWP/CoreUWP.vcxproj.filters b/UWP/CoreUWP/CoreUWP.vcxproj.filters
index 119c2d0936..7fead01f06 100644
--- a/UWP/CoreUWP/CoreUWP.vcxproj.filters
+++ b/UWP/CoreUWP/CoreUWP.vcxproj.filters
@@ -108,7 +108,6 @@
-
MIPS\ARM
@@ -1150,7 +1149,6 @@
-
diff --git a/UWP/GPU_UWP/GPU_UWP.vcxproj b/UWP/GPU_UWP/GPU_UWP.vcxproj
index 369a75da72..0548c117a6 100644
--- a/UWP/GPU_UWP/GPU_UWP.vcxproj
+++ b/UWP/GPU_UWP/GPU_UWP.vcxproj
@@ -58,144 +58,30 @@
14.0
true
Windows Store
- 10.0.15063.0
+ 10.0.19041.0
10.0
- 10.0.17763.0
+ 10.0
-
+
StaticLibrary
true
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
+
StaticLibrary
false
false
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
+
false
@@ -204,7 +90,7 @@
false
false
pch.h
- ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
_CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions)
@@ -219,7 +105,7 @@
false
false
pch.h
- ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
_CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions)
@@ -234,7 +120,7 @@
false
false
pch.h
- ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
_CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions)
@@ -249,7 +135,7 @@
false
false
pch.h
- ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
_CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions)
@@ -264,7 +150,7 @@
false
false
pch.h
- ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
_CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions)
@@ -279,7 +165,7 @@
false
false
pch.h
- ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
_CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions)
@@ -294,7 +180,7 @@
false
false
pch.h
- ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
_CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions)
@@ -309,7 +195,7 @@
false
false
pch.h
- ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
_CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions)
@@ -324,7 +210,7 @@
false
false
pch.h
- ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
_CRT_SECURE_NO_WARNINGS;NOMINMAX;_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions)
@@ -339,7 +225,7 @@
false
false
pch.h
- ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
_CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions)
@@ -354,7 +240,7 @@
false
false
pch.h
- ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
_CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions)
@@ -369,7 +255,7 @@
false
false
pch.h
- ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
+ ../..;../../ext/snappy;../../ext/native;../../Common;../../ext;../../ext/glslang;../../ext/zstd/lib;../../ext/libpng17;$(ProjectDir);$(GeneratedFilesDir);$(IntDir);%(AdditionalIncludeDirectories)
_CRT_SECURE_NO_WARNINGS;NOMINMAX;_UNICODE;UNICODE;%(PreprocessorDefinitions)
@@ -379,6 +265,8 @@
+
+
@@ -423,6 +311,7 @@
+
@@ -442,6 +331,8 @@
+
+
@@ -487,6 +378,7 @@
+
@@ -501,18 +393,7 @@
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
+ Create
diff --git a/UWP/GPU_UWP/GPU_UWP.vcxproj.filters b/UWP/GPU_UWP/GPU_UWP.vcxproj.filters
index 2481c765c9..314574f863 100644
--- a/UWP/GPU_UWP/GPU_UWP.vcxproj.filters
+++ b/UWP/GPU_UWP/GPU_UWP.vcxproj.filters
@@ -61,6 +61,9 @@
+
+
+
@@ -123,5 +126,8 @@
+
+
+
\ No newline at end of file
diff --git a/UWP/PPSSPP_UWP.sln b/UWP/PPSSPP_UWP.sln
index 8fe54683af..e54559c70a 100644
--- a/UWP/PPSSPP_UWP.sln
+++ b/UWP/PPSSPP_UWP.sln
@@ -2,6 +2,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28803.202
MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PPSSPP_UWP", "UWP.vcxproj", "{01D7D581-09A3-4A26-94BD-A7C529B29329}"
+ ProjectSection(ProjectDependencies) = postProject
+ {D31FD4F0-53EB-477C-9DC7-149796F628E2} = {D31FD4F0-53EB-477C-9DC7-149796F628E2}
+ EndProjectSection
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonUWP", "CommonUWP\CommonUWP.vcxproj", "{ACB316CA-3ECB-48E5-BE0A-91E72D5B0F12}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CoreUWP", "CoreUWP\CoreUWP.vcxproj", "{40B76674-02DE-40EF-889B-FAD1489685E7}"
@@ -17,11 +22,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libkirk_UWP", "libkirk_UWP\
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib_UWP", "zlib_UWP\zlib_UWP.vcxproj", "{DDF90203-0AAE-4F38-B589-2E9637658CE6}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PPSSPP_UWP", "UWP.vcxproj", "{01D7D581-09A3-4A26-94BD-A7C529B29329}"
- ProjectSection(ProjectDependencies) = postProject
- {D31FD4F0-53EB-477C-9DC7-149796F628E2} = {D31FD4F0-53EB-477C-9DC7-149796F628E2}
- EndProjectSection
-EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glslang_UWP", "glslang_UWP\glslang_UWP.vcxproj", "{D326891E-ECE4-4B94-B5E7-8AA0A8E8ECBC}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SPIRVCross_UWP", "SPIRVCross_UWP\SPIRVCross_UWP.vcxproj", "{2B2D16BD-1D37-46AF-A3F8-552900951B26}"
diff --git a/UWP/PPSSPP_UWPMain.cpp b/UWP/PPSSPP_UWPMain.cpp
index b734f6e3d2..5fabe3a4e1 100644
--- a/UWP/PPSSPP_UWPMain.cpp
+++ b/UWP/PPSSPP_UWPMain.cpp
@@ -11,7 +11,7 @@
#include "Common/Common.h"
#include "Common/Input/InputState.h"
#include "Common/File/VFS/VFS.h"
-#include "Common/File/VFS/AssetReader.h"
+#include "Common/File/VFS/DirectoryReader.h"
#include "Common/Thread/ThreadUtil.h"
#include "Common/Data/Encoding/Utf8.h"
#include "Common/DirectXHelper.h"
@@ -76,8 +76,8 @@ PPSSPP_UWPMain::PPSSPP_UWPMain(App ^app, const std::shared_ptrGetDrawContext()->HandleEvent(Draw::Event::LOST_BACKBUFFER, 0, 0, nullptr);
NativeShutdownGraphics();
NativeShutdown();
+ g_VFS.Clear();
// Deregister device notification
m_deviceResources->RegisterDeviceNotify(nullptr);
@@ -167,39 +168,39 @@ bool PPSSPP_UWPMain::Render() {
auto context = m_deviceResources->GetD3DDeviceContext();
switch (m_deviceResources->ComputeDisplayRotation()) {
- case DXGI_MODE_ROTATION_IDENTITY: g_display_rotation = DisplayRotation::ROTATE_0; break;
- case DXGI_MODE_ROTATION_ROTATE90: g_display_rotation = DisplayRotation::ROTATE_90; break;
- case DXGI_MODE_ROTATION_ROTATE180: g_display_rotation = DisplayRotation::ROTATE_180; break;
- case DXGI_MODE_ROTATION_ROTATE270: g_display_rotation = DisplayRotation::ROTATE_270; break;
+ case DXGI_MODE_ROTATION_IDENTITY: g_display.rotation = DisplayRotation::ROTATE_0; break;
+ case DXGI_MODE_ROTATION_ROTATE90: g_display.rotation = DisplayRotation::ROTATE_90; break;
+ case DXGI_MODE_ROTATION_ROTATE180: g_display.rotation = DisplayRotation::ROTATE_180; break;
+ case DXGI_MODE_ROTATION_ROTATE270: g_display.rotation = DisplayRotation::ROTATE_270; break;
}
// Not super elegant but hey.
- memcpy(&g_display_rot_matrix, &m_deviceResources->GetOrientationTransform3D(), sizeof(float) * 16);
+ memcpy(&g_display.rot_matrix, &m_deviceResources->GetOrientationTransform3D(), sizeof(float) * 16);
// Reset the viewport to target the whole screen.
auto viewport = m_deviceResources->GetScreenViewport();
- pixel_xres = viewport.Width;
- pixel_yres = viewport.Height;
+ g_display.pixel_xres = viewport.Width;
+ g_display.pixel_yres = viewport.Height;
- if (g_display_rotation == DisplayRotation::ROTATE_90 || g_display_rotation == DisplayRotation::ROTATE_270) {
+ if (g_display.rotation == DisplayRotation::ROTATE_90 || g_display.rotation == DisplayRotation::ROTATE_270) {
// We need to swap our width/height.
- std::swap(pixel_xres, pixel_yres);
+ std::swap(g_display.pixel_xres, g_display.pixel_yres);
}
- g_dpi = m_deviceResources->GetActualDpi();
+ g_display.dpi = m_deviceResources->GetActualDpi();
if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_MOBILE) {
// Boost DPI a bit to look better.
- g_dpi *= 96.0f / 136.0f;
+ g_display.dpi *= 96.0f / 136.0f;
}
- g_dpi_scale_x = 96.0f / g_dpi;
- g_dpi_scale_y = 96.0f / g_dpi;
+ g_display.dpi_scale_x = 96.0f / g_display.dpi;
+ g_display.dpi_scale_y = 96.0f / g_display.dpi;
- pixel_in_dps_x = 1.0f / g_dpi_scale_x;
- pixel_in_dps_y = 1.0f / g_dpi_scale_y;
+ g_display.pixel_in_dps_x = 1.0f / g_display.dpi_scale_x;
+ g_display.pixel_in_dps_y = 1.0f / g_display.dpi_scale_y;
- dp_xres = pixel_xres * g_dpi_scale_x;
- dp_yres = pixel_yres * g_dpi_scale_y;
+ g_display.dp_xres = g_display.pixel_xres * g_display.dpi_scale_x;
+ g_display.dp_yres = g_display.pixel_yres * g_display.dpi_scale_y;
context->RSSetViewports(1, &viewport);
@@ -274,8 +275,8 @@ void PPSSPP_UWPMain::OnTouchEvent(int touchEvent, int touchId, float x, float y,
// and then apply our own "dpi".
float dpiFactor_x = m_deviceResources->GetActualDpi() / 96.0f;
float dpiFactor_y = dpiFactor_x;
- dpiFactor_x /= pixel_in_dps_x;
- dpiFactor_y /= pixel_in_dps_y;
+ dpiFactor_x /= g_display.pixel_in_dps_x;
+ dpiFactor_y /= g_display.pixel_in_dps_y;
TouchInput input{};
input.id = touchId;
diff --git a/UWP/PPSSPP_UWP_TemporaryKey.pfx b/UWP/PPSSPP_UWP_TemporaryKey.pfx
index 0d737acfe6..bbae735015 100644
Binary files a/UWP/PPSSPP_UWP_TemporaryKey.pfx and b/UWP/PPSSPP_UWP_TemporaryKey.pfx differ
diff --git a/UWP/Package.appxmanifest b/UWP/Package.appxmanifest
index 68b9c930d7..967c48e26c 100644
--- a/UWP/Package.appxmanifest
+++ b/UWP/Package.appxmanifest
@@ -1,6 +1,6 @@
-
+
PPSSPP - PSP emulator
@@ -31,5 +31,6 @@
+
diff --git a/UWP/PackageGold.appxmanifest b/UWP/PackageGold.appxmanifest
index d428bcd738..384fa2d9d7 100644
--- a/UWP/PackageGold.appxmanifest
+++ b/UWP/PackageGold.appxmanifest
@@ -1,6 +1,6 @@
-
+
PPSSPP Gold - PSP emulator
@@ -35,5 +35,6 @@
+
diff --git a/UWP/PackageNormal.appxmanifest b/UWP/PackageNormal.appxmanifest
index ef79928e4c..cc6f628a24 100644
--- a/UWP/PackageNormal.appxmanifest
+++ b/UWP/PackageNormal.appxmanifest
@@ -1,6 +1,6 @@
-
+
PPSSPP - PSP emulator
@@ -31,5 +31,6 @@
+
diff --git a/UWP/SPIRVCross_UWP/SPIRVCross_UWP.vcxproj b/UWP/SPIRVCross_UWP/SPIRVCross_UWP.vcxproj
index b27d1659aa..4b0eeb4236 100644
--- a/UWP/SPIRVCross_UWP/SPIRVCross_UWP.vcxproj
+++ b/UWP/SPIRVCross_UWP/SPIRVCross_UWP.vcxproj
@@ -58,63 +58,16 @@
14.0
true
Windows Store
- 10.0.15063.0
+ 10.0.19041.0
10.0
- 10.0.17763.0
+ 10.0
-
+
StaticLibrary
true
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- true
-
-
+
StaticLibrary
false
true
@@ -124,85 +77,18 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
+
false
Use
false
- true
+ false
pch.h
_UNICODE;UNICODE;%(PreprocessorDefinitions);NOMINMAX
@@ -244,7 +130,7 @@
Use
false
- true
+ false
pch.h
_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions);NOMINMAX
@@ -258,7 +144,7 @@
Use
false
- true
+ false
pch.h
_ARM64_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1;%(ClCompile.PreprocessorDefinitions);NOMINMAX
@@ -328,7 +214,7 @@
Use
false
- true
+ false
pch.h
_UNICODE;UNICODE;%(PreprocessorDefinitions);NOMINMAX
@@ -392,18 +278,7 @@
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
+ Create
diff --git a/UWP/UI_UWP/UI_UWP.vcxproj b/UWP/UI_UWP/UI_UWP.vcxproj
index eda2c2c994..9e892566ca 100644
--- a/UWP/UI_UWP/UI_UWP.vcxproj
+++ b/UWP/UI_UWP/UI_UWP.vcxproj
@@ -58,144 +58,30 @@
14.0
true
Windows Store
- 10.0.15063.0
+ 10.0.19041.0
10.0
- 10.0.17763.0
+ 10.0
-
+
StaticLibrary
true
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
+
StaticLibrary
false
false
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
+
false
@@ -446,18 +332,7 @@
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
+ Create
diff --git a/UWP/UWP.vcxproj b/UWP/UWP.vcxproj
index 5fcdbecf25..7a89e3c9f4 100644
--- a/UWP/UWP.vcxproj
+++ b/UWP/UWP.vcxproj
@@ -58,127 +58,29 @@
14.0
true
Windows Store
- 10.0.15063.0
+ 10.0.19041.0
10.0
PPSSPP_UWP
- 10.0.17763.0
+ 10.0
-
+
Application
true
-
- Application
- true
-
-
- Application
- true
-
-
- Application
- true
-
-
- Application
- false
- true
- true
-
-
- Application
- false
- true
- true
-
-
+
Application
false
false
true
-
- Application
- false
- false
- true
-
-
- Application
- false
- false
- true
-
-
- Application
- false
- false
- true
-
-
- Application
- false
- true
- true
-
-
- Application
- false
- true
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -187,11 +89,12 @@
True
False
Never
- 169879A9D7A20F22B0DD435921035E3E6D5996A4
+ C8DEB388B9BC89D1DC61324E4E9D9FE6A796B7AA
False
1
OnApplicationRun
True
+ PPSSPP_UWP_TemporaryKey.pfx
@@ -212,10 +115,10 @@
copy PackageNormal.appxmanifest Package.appxmanifest /Y
mkdir Assets
copy AssetsNormal\*.* Assets /Y
- robocopy "..\Assets\." "Content\." /xf *.vsh /E /R:0 /W:0
+ robocopy "..\Assets\." "Content\." /xd "mime" /E /R:0 /W:0
../Windows/git-version-gen.cmd
EXIT 0
-
+
@@ -237,10 +140,10 @@
copy PackageNormal.appxmanifest Package.appxmanifest /Y
mkdir Assets
copy AssetsNormal\*.* Assets /Y
- robocopy "..\Assets\." "Content\." /xf *.vsh /E /R:0 /W:0
+ robocopy "..\Assets\." "Content\." /xd "mime" /E /R:0 /W:0
../Windows/git-version-gen.cmd
EXIT 0
-
+
@@ -262,10 +165,10 @@
copy PackageNormal.appxmanifest Package.appxmanifest /Y
mkdir Assets
copy AssetsNormal\*.* Assets /Y
- robocopy "..\Assets\." "Content\." /xf *.vsh /E /R:0 /W:0
+ robocopy "..\Assets\." "Content\." /xd "mime" /E /R:0 /W:0
../Windows/git-version-gen.cmd
EXIT 0
-
+
@@ -287,10 +190,10 @@
copy PackageNormal.appxmanifest Package.appxmanifest /Y
mkdir Assets
copy AssetsNormal\*.* Assets /Y
- robocopy "..\Assets\." "Content\." /xf *.vsh /E /R:0 /W:0
+ robocopy "..\Assets\." "Content\." /xd "mime" /E /R:0 /W:0
../Windows/git-version-gen.cmd
EXIT 0
-
+
@@ -312,10 +215,10 @@
copy PackageGold.appxmanifest Package.appxmanifest /Y
mkdir Assets
copy AssetsGold\*.* Assets /Y
- robocopy "..\Assets\." "Content\." /xf *.vsh /E /R:0 /W:0
+ robocopy "..\Assets\." "Content\." /xd "mime" /E /R:0 /W:0
../Windows/git-version-gen.cmd
EXIT 0
-
+
@@ -337,10 +240,10 @@
copy PackageGold.appxmanifest Package.appxmanifest /Y
mkdir Assets
copy AssetsGold\*.* Assets /Y
- robocopy "..\Assets\." "Content\." /xf *.vsh /E /R:0 /W:0
+ robocopy "..\Assets\." "Content\." /xd "mime" /E /R:0 /W:0
../Windows/git-version-gen.cmd
EXIT 0
-
+
@@ -362,10 +265,10 @@
copy PackageNormal.appxmanifest Package.appxmanifest /Y
mkdir Assets
copy AssetsNormal\*.* Assets /Y
- robocopy "..\Assets\." "Content\." /xf *.vsh /E /R:0 /W:0
+ robocopy "..\Assets\." "Content\." /xd "mime" /E /R:0 /W:0
../Windows/git-version-gen.cmd
EXIT 0
-
+
@@ -387,10 +290,10 @@
copy PackageNormal.appxmanifest Package.appxmanifest /Y
mkdir Assets
copy AssetsNormal\*.* Assets /Y
- robocopy "..\Assets\." "Content\." /xf *.vsh /E /R:0 /W:0
+ robocopy "..\Assets\." "Content\." /xd "mime" /E /R:0 /W:0
../Windows/git-version-gen.cmd
EXIT 0
-
+
@@ -412,10 +315,10 @@
copy PackageGold.appxmanifest Package.appxmanifest /Y
mkdir Assets
copy AssetsGold\*.* Assets /Y
- robocopy "..\Assets\." "Content\." /xf *.vsh /E /R:0 /W:0
+ robocopy "..\Assets\." "Content\." /xd "mime" /E /R:0 /W:0
../Windows/git-version-gen.cmd
EXIT 0
-
+
@@ -437,10 +340,10 @@
copy PackageNormal.appxmanifest Package.appxmanifest /Y
mkdir Assets
copy AssetsNormal\*.* Assets /Y
- robocopy "..\Assets\." "Content\." /xf *.vsh /E /R:0 /W:0
+ robocopy "..\Assets\." "Content\." /xd "mime" /E /R:0 /W:0
../Windows/git-version-gen.cmd
EXIT 0
-
+
@@ -462,10 +365,10 @@
copy PackageNormal.appxmanifest Package.appxmanifest /Y
mkdir Assets
copy AssetsNormal\*.* Assets /Y
- robocopy "..\Assets\." "Content\." /xf *.vsh /E /R:0 /W:0
+ robocopy "..\Assets\." "Content\." /xd "mime" /E /R:0 /W:0
../Windows/git-version-gen.cmd
EXIT 0
-
+
@@ -487,10 +390,10 @@
copy PackageGold.appxmanifest Package.appxmanifest /Y
mkdir Assets
copy AssetsGold\*.* Assets /Y
- robocopy "..\Assets\." "Content\." /xf *.vsh /E /R:0 /W:0
+ robocopy "..\Assets\." "Content\." /xd "mime" /E /R:0 /W:0
../Windows/git-version-gen.cmd
EXIT 0
-
+
@@ -521,6 +424,9 @@
true
+
+ true
+
true
@@ -544,18 +450,7 @@
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
- NotUsing
+ NotUsing
@@ -564,18 +459,7 @@
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
+ Create
@@ -596,283 +480,128 @@
true
Document
+
+ true
+ Document
+
true
-
+
true
-
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+
+ true
-
+
+ true
+
+
+ true
+
+
+ true
+ Content\debugger\static\css\%(Filename)%(Extension)
+
+
+ true
+ Content\debugger\static\css\%(Filename)%(Extension)
+
+
+ true
+ Content\debugger\static\js\%(Filename)%(Extension)
+
+
+ true
+ Content\debugger\static\js\%(Filename)%(Extension)
+
+
+ true
+ Content\debugger\static\media\%(Filename)%(Extension)
+
+
+ true
+
+
+ true
+
+
+ true
+
+
true
true
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
true
@@ -881,819 +610,247 @@
true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
+
+
+ true
+
+
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
-
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
+
+
+ true
+
+
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
+
+
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
+
+
+ true
+
+
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
+
+
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
+
+
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
+
+
+ true
+
+
+ true
+
+
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
+
+
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
- true
+ true
@@ -1730,13 +887,14 @@
+
+ true
+ Content\debugger\static\js\%(Filename)%(Extension)
+
true
-
-
-
@@ -1746,4 +904,4 @@
-
+
\ No newline at end of file
diff --git a/UWP/UWP.vcxproj.filters b/UWP/UWP.vcxproj.filters
index 15c471b062..b03d9592a8 100644
--- a/UWP/UWP.vcxproj.filters
+++ b/UWP/UWP.vcxproj.filters
@@ -53,6 +53,21 @@
{da2113a6-e616-4fc9-8be3-ff75b963664b}
+
+ {55147387-68fc-487e-abed-7a763f850ef1}
+
+
+ {e5d2759b-3511-4ab9-a9ca-070dd9715f3b}
+
+
+ {0fb972a9-20a9-4eba-be70-c408f9306939}
+
+
+ {47d54a48-ca53-4d57-8bfd-9c86fd97d84b}
+
+
+ {83476056-57b8-409f-b729-754d6401e3d5}
+
@@ -102,6 +117,12 @@
Content
+
+ Content
+
+
+ Content\debugger
+
@@ -171,9 +192,15 @@
Content\lang
+
+ Content\lang
+
Content\lang
+
+ Content\lang
+
Content\lang
@@ -246,21 +273,33 @@
Content\shaders
+
+ Content\shaders
+
Content\shaders
-
+
Content\shaders
Content\shaders
+
+ Content\shaders
+
Content\shaders
Content\shaders
+
+ Content\shaders
+
+
+ Content\shaders
+
Content\shaders
@@ -270,9 +309,72 @@
Content\shaders
+
+ Content\shaders
+
Content\shaders
+
+ Content\shaders
+
+
+ Content\shaders
+
+
+ Content\shaders
+
+
+ Content\shaders
+
+
+ Content\shaders
+
+
+ Content\shaders
+
+
+ Content\shaders
+
+
+ Content\shaders
+
+
+ Content\shaders
+
+
+ Content\shaders
+
+
+ Content\shaders
+
+
+ Content\shaders
+
+
+ Content\shaders
+
+
+ Content\shaders
+
+
+ Content\shaders
+
+
+ Content\shaders
+
+
+ Content\shaders
+
+
+ Content\shaders
+
+
+ Content\shaders
+
+
+ Content\shaders
+
Content\flash0\font
@@ -327,48 +429,81 @@
Content\flash0\font
-
- Content\shaders
-
-
- Content\shaders
-
-
- Content\shaders
-
-
- Content\shaders
-
-
- Content\shaders
-
-
- Content\shaders
-
-
- Content\shaders
-
-
+
Content
-
+
Content
-
+
Content\themes
Content
+
+ Content
+
+
+ Content
+
+
+ Content
+
+
+ Content
+
+
+ Content
+
+
+ Content
+
+
+ Content\shaders
+
+
+ Content\shaders
+
+
+ Content\debugger
+
+
+ Content\debugger
+
+
+ Content\debugger
+
+
+ Content\debugger
+
+
+ Content\debugger\static\css
+
+
+ Content\debugger\static\css
+
+
+ Content\debugger\static\js
+
+
+ Content\debugger\static\js
+
+
+ Content\debugger\static\media
+
Content
+
+ Content\debugger\static\js
+
Content
-
+
\ No newline at end of file
diff --git a/UWP/cpu_features_UWP/cpu_features_UWP.vcxproj b/UWP/cpu_features_UWP/cpu_features_UWP.vcxproj
index f4d225d3b3..6dcea065c8 100644
--- a/UWP/cpu_features_UWP/cpu_features_UWP.vcxproj
+++ b/UWP/cpu_features_UWP/cpu_features_UWP.vcxproj
@@ -58,144 +58,30 @@
14.0
true
Windows Store
- 10.0.15063.0
+ 10.0.19041.0
10.0
- 10.0.17763.0
+ 10.0
-
+
StaticLibrary
true
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
+
StaticLibrary
false
false
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
+
false
@@ -398,7 +284,7 @@
-
+
@@ -422,21 +308,10 @@
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
+ Create
-
+
\ No newline at end of file
diff --git a/UWP/cpu_features_UWP/cpu_features_UWP.vcxproj.filters b/UWP/cpu_features_UWP/cpu_features_UWP.vcxproj.filters
index 0fad65bc31..d0acee9d45 100644
--- a/UWP/cpu_features_UWP/cpu_features_UWP.vcxproj.filters
+++ b/UWP/cpu_features_UWP/cpu_features_UWP.vcxproj.filters
@@ -66,11 +66,6 @@
Header Files\internal
-
-
- Resource Files
-
-
Source Files
@@ -87,6 +82,7 @@
Source Files
+
@@ -130,4 +126,4 @@
Source Files
-
+
\ No newline at end of file
diff --git a/UWP/glslang_UWP/glslang_UWP.vcxproj b/UWP/glslang_UWP/glslang_UWP.vcxproj
index 2242d14f57..1be05c7670 100644
--- a/UWP/glslang_UWP/glslang_UWP.vcxproj
+++ b/UWP/glslang_UWP/glslang_UWP.vcxproj
@@ -58,144 +58,31 @@
14.0
true
Windows Store
- 10.0.15063.0
+ 10.0.19041.0
10.0
- 10.0.17763.0
+ 10.0
-
+
StaticLibrary
true
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
+
StaticLibrary
false
false
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
+
false
@@ -491,21 +378,10 @@
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
+ Create
-
+
\ No newline at end of file
diff --git a/UWP/glslang_UWP/glslang_UWP.vcxproj.filters b/UWP/glslang_UWP/glslang_UWP.vcxproj.filters
index dc0cd80fc3..bff8201bc4 100644
--- a/UWP/glslang_UWP/glslang_UWP.vcxproj.filters
+++ b/UWP/glslang_UWP/glslang_UWP.vcxproj.filters
@@ -170,6 +170,7 @@
hlsl
+
@@ -348,5 +349,6 @@
glslang
+
\ No newline at end of file
diff --git a/UWP/libkirk_UWP/libkirk_UWP.vcxproj b/UWP/libkirk_UWP/libkirk_UWP.vcxproj
index 510ff09681..045f0b48f2 100644
--- a/UWP/libkirk_UWP/libkirk_UWP.vcxproj
+++ b/UWP/libkirk_UWP/libkirk_UWP.vcxproj
@@ -58,144 +58,30 @@
14.0
true
Windows Store
- 10.0.15063.0
+ 10.0.19041.0
10.0
- 10.0.17763.0
+ 10.0
-
+
StaticLibrary
true
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
+
StaticLibrary
false
false
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
+
false
@@ -396,4 +282,4 @@
-
+
\ No newline at end of file
diff --git a/UWP/libzstd_UWP/libzstd_UWP.vcxproj b/UWP/libzstd_UWP/libzstd_UWP.vcxproj
index 78101ed883..09cbd21e9b 100644
--- a/UWP/libzstd_UWP/libzstd_UWP.vcxproj
+++ b/UWP/libzstd_UWP/libzstd_UWP.vcxproj
@@ -42,43 +42,16 @@
14.0
true
Windows Store
- 10.0.17763.0
- 10.0.15063.0
+ 10.0
+ 10.0.19041.0
10.0
-
+
StaticLibrary
true
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
+
StaticLibrary
false
true
@@ -88,61 +61,11 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
- false
- $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips;
-
-
- false
- $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips;
-
-
- false
- $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips;
-
-
- false
- $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips;
-
-
- false
- $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips;
-
-
- false
- $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips;
-
-
- false
- $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips;
-
-
+
false
$(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)..\..\ext\armips;
@@ -299,16 +222,7 @@
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
+ Create
diff --git a/UWP/miniupnpc_UWP/miniupnpc_UWP.vcxproj b/UWP/miniupnpc_UWP/miniupnpc_UWP.vcxproj
index 5e42ecf2a4..cc9ce92352 100644
--- a/UWP/miniupnpc_UWP/miniupnpc_UWP.vcxproj
+++ b/UWP/miniupnpc_UWP/miniupnpc_UWP.vcxproj
@@ -58,144 +58,30 @@
14.0
true
Windows Store
- 10.0.15063.0
+ 10.0.19041.0
10.0
- 10.0.17763.0
+ 10.0
-
+
StaticLibrary
true
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
+
StaticLibrary
false
false
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
+
false
@@ -469,18 +355,7 @@ cd ..\..\..\..\UWP\miniupnpc_UWP
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
- Create
+ Create
diff --git a/UWP/zlib_UWP/zlib_UWP.vcxproj b/UWP/zlib_UWP/zlib_UWP.vcxproj
index 5ac9ab5c08..f60d2aa01a 100644
--- a/UWP/zlib_UWP/zlib_UWP.vcxproj
+++ b/UWP/zlib_UWP/zlib_UWP.vcxproj
@@ -58,144 +58,30 @@
14.0
true
Windows Store
- 10.0.15063.0
+ 10.0.19041.0
10.0
- 10.0.17763.0
+ 10.0
-
+
StaticLibrary
true
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- true
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
+
StaticLibrary
false
false
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- false
-
-
- StaticLibrary
- false
- true
-
-
- StaticLibrary
- false
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
+
false
@@ -396,4 +282,4 @@
-
+
\ No newline at end of file
diff --git a/Windows/.gitignore b/Windows/.gitignore
index 653ef6879e..8d4dba11ef 100644
--- a/Windows/.gitignore
+++ b/Windows/.gitignore
@@ -1,3 +1,4 @@
*.VC.VC.opendb
*.VC.db
+*.txt
enc_temp_folder
diff --git a/Windows/Debugger/CtrlDisAsmView.cpp b/Windows/Debugger/CtrlDisAsmView.cpp
index a179749ecf..7b46ae2402 100644
--- a/Windows/Debugger/CtrlDisAsmView.cpp
+++ b/Windows/Debugger/CtrlDisAsmView.cpp
@@ -172,7 +172,7 @@ CtrlDisAsmView::CtrlDisAsmView(HWND _wnd)
SetWindowLong(wnd, GWL_STYLE, GetWindowLong(wnd,GWL_STYLE) | WS_VSCROLL);
SetScrollRange(wnd, SB_VERT, -1, 1, TRUE);
- const float fontScale = 1.0f / g_dpi_scale_real_y;
+ const float fontScale = 1.0f / g_display.dpi_scale_real_y;
charWidth = g_Config.iFontWidth * fontScale;
rowHeight = (g_Config.iFontHeight + 2) * fontScale;
int scaledFontHeight = g_Config.iFontHeight * fontScale;
@@ -206,7 +206,7 @@ CtrlDisAsmView::~CtrlDisAsmView()
manager.clear();
}
-COLORREF scaleColor(COLORREF color, float factor)
+static COLORREF scaleColor(COLORREF color, float factor)
{
unsigned char r = color & 0xFF;
unsigned char g = (color >> 8) & 0xFF;
@@ -315,7 +315,7 @@ void CtrlDisAsmView::assembleOpcode(u32 address, std::string defaultText)
// try to assemble the input if it failed
}
- result = MIPSAsm::MipsAssembleOpcode(op.c_str(),debugger,address);
+ result = MIPSAsm::MipsAssembleOpcode(op.c_str(), debugger, address);
Reporting::NotifyDebugger();
if (result == true)
{
@@ -331,7 +331,6 @@ void CtrlDisAsmView::assembleOpcode(u32 address, std::string defaultText)
}
}
-
void CtrlDisAsmView::drawBranchLine(HDC hdc, std::map &addressPositions, const BranchLine &line) {
HPEN pen;
u32 windowEnd = manager.getNthNextAddress(windowStart,visibleRows);
@@ -725,7 +724,7 @@ void CtrlDisAsmView::onKeyDown(WPARAM wParam, LPARAM lParam)
break;
case 'c':
case VK_INSERT:
- copyInstructions(selectRangeStart, selectRangeEnd, true);
+ CopyInstructions(selectRangeStart, selectRangeEnd, CopyInstructionsMode::DISASM);
break;
case 'x':
disassembleToFile();
@@ -906,10 +905,8 @@ void CtrlDisAsmView::onMouseDown(WPARAM wParam, LPARAM lParam, int button)
redraw();
}
-void CtrlDisAsmView::copyInstructions(u32 startAddr, u32 endAddr, bool withDisasm)
-{
- if (withDisasm == false)
- {
+void CtrlDisAsmView::CopyInstructions(u32 startAddr, u32 endAddr, CopyInstructionsMode mode) {
+ if (mode != CopyInstructionsMode::DISASM) {
int instructionSize = debugger->getInstructionSize(0);
int count = (endAddr - startAddr) / instructionSize;
int space = count * 32;
@@ -918,7 +915,8 @@ void CtrlDisAsmView::copyInstructions(u32 startAddr, u32 endAddr, bool withDisas
char *p = temp, *end = temp + space;
for (u32 pos = startAddr; pos < endAddr && p < end; pos += instructionSize)
{
- p += snprintf(p, end - p, "%08X", debugger->readMemory(pos));
+ u32 data = mode == CopyInstructionsMode::OPCODES ? debugger->readMemory(pos) : pos;
+ p += snprintf(p, end - p, "%08X", data);
// Don't leave a trailing newline.
if (pos + instructionSize < endAddr && p < end)
@@ -926,13 +924,22 @@ void CtrlDisAsmView::copyInstructions(u32 startAddr, u32 endAddr, bool withDisas
}
W32Util::CopyTextToClipboard(wnd, temp);
delete [] temp;
- } else
- {
+ } else {
std::string disassembly = disassembleRange(startAddr,endAddr-startAddr);
W32Util::CopyTextToClipboard(wnd, disassembly.c_str());
}
}
+void CtrlDisAsmView::NopInstructions(u32 selectRangeStart, u32 selectRangeEnd) {
+ for (u32 addr = selectRangeStart; addr < selectRangeEnd; addr += 4) {
+ Memory::Write_U32(0, addr);
+ }
+
+ if (currentMIPS) {
+ currentMIPS->InvalidateICache(selectRangeStart, selectRangeEnd - selectRangeStart);
+ }
+}
+
void CtrlDisAsmView::onMouseUp(WPARAM wParam, LPARAM lParam, int button)
{
if (button == 1)
@@ -956,14 +963,17 @@ void CtrlDisAsmView::onMouseUp(WPARAM wParam, LPARAM lParam, int button)
assembleOpcode(curAddress,"");
break;
case ID_DISASM_COPYINSTRUCTIONDISASM:
- copyInstructions(selectRangeStart, selectRangeEnd, true);
+ CopyInstructions(selectRangeStart, selectRangeEnd, CopyInstructionsMode::DISASM);
break;
case ID_DISASM_COPYADDRESS:
- {
- char temp[16];
- sprintf(temp,"%08X",curAddress);
- W32Util::CopyTextToClipboard(wnd, temp);
- }
+ CopyInstructions(selectRangeStart, selectRangeEnd, CopyInstructionsMode::ADDRESSES);
+ break;
+ case ID_DISASM_COPYINSTRUCTIONHEX:
+ CopyInstructions(selectRangeStart, selectRangeEnd, CopyInstructionsMode::OPCODES);
+ break;
+ case ID_DISASM_NOPINSTRUCTION:
+ NopInstructions(selectRangeStart, selectRangeEnd);
+ redraw();
break;
case ID_DISASM_SETPCTOHERE:
debugger->setPC(curAddress);
@@ -972,9 +982,6 @@ void CtrlDisAsmView::onMouseUp(WPARAM wParam, LPARAM lParam, int button)
case ID_DISASM_FOLLOWBRANCH:
followBranch();
break;
- case ID_DISASM_COPYINSTRUCTIONHEX:
- copyInstructions(selectRangeStart, selectRangeEnd, false);
- break;
case ID_DISASM_RUNTOHERE:
{
SendMessage(GetParent(wnd), WM_COMMAND, ID_DEBUG_RUNTOLINE, 0);
diff --git a/Windows/Debugger/CtrlDisAsmView.h b/Windows/Debugger/CtrlDisAsmView.h
index 2930e41544..c67306a76c 100644
--- a/Windows/Debugger/CtrlDisAsmView.h
+++ b/Windows/Debugger/CtrlDisAsmView.h
@@ -64,6 +64,12 @@ class CtrlDisAsmView
bool dontRedraw;
bool keyTaken;
+ enum class CopyInstructionsMode {
+ OPCODES,
+ DISASM,
+ ADDRESSES,
+ };
+
void assembleOpcode(u32 address, std::string defaultText);
std::string disassembleRange(u32 start, u32 size);
void disassembleToFile();
@@ -73,7 +79,8 @@ class CtrlDisAsmView
bool getDisasmAddressText(u32 address, char* dest, bool abbreviateLabels, bool showData);
void updateStatusBarText();
void drawBranchLine(HDC hdc, std::map &addressPositions, const BranchLine &line);
- void copyInstructions(u32 startAddr, u32 endAddr, bool withDisasm);
+ void CopyInstructions(u32 startAddr, u32 endAddr, CopyInstructionsMode mode);
+ void NopInstructions(u32 startAddr, u32 endAddr);
std::set getSelectedLineArguments();
void drawArguments(HDC hdc, const DisassemblyLineInfo &line, int x, int y, int textColor, const std::set ¤tArguments);
diff --git a/Windows/Debugger/CtrlMemView.cpp b/Windows/Debugger/CtrlMemView.cpp
index 598763df85..f4eb61df2e 100644
--- a/Windows/Debugger/CtrlMemView.cpp
+++ b/Windows/Debugger/CtrlMemView.cpp
@@ -34,7 +34,7 @@ CtrlMemView::CtrlMemView(HWND _wnd) {
SetWindowLong(wnd, GWL_STYLE, GetWindowLong(wnd,GWL_STYLE) | WS_VSCROLL);
SetScrollRange(wnd, SB_VERT, -1,1,TRUE);
- const float fontScale = 1.0f / g_dpi_scale_real_y;
+ const float fontScale = 1.0f / g_display.dpi_scale_real_y;
charWidth_ = g_Config.iFontWidth * fontScale;
rowHeight_ = g_Config.iFontHeight * fontScale;
offsetPositionY_ = offsetLine * rowHeight_;
diff --git a/Windows/Debugger/CtrlRegisterList.cpp b/Windows/Debugger/CtrlRegisterList.cpp
index 8df25e6429..6fcf215b76 100644
--- a/Windows/Debugger/CtrlRegisterList.cpp
+++ b/Windows/Debugger/CtrlRegisterList.cpp
@@ -133,7 +133,7 @@ CtrlRegisterList::CtrlRegisterList(HWND _wnd)
: wnd(_wnd) {
SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)this);
- const float fontScale = 1.0f / g_dpi_scale_real_y;
+ const float fontScale = 1.0f / g_display.dpi_scale_real_y;
rowHeight = g_Config.iFontHeight * fontScale;
int charWidth = g_Config.iFontWidth * fontScale;
font = CreateFont(rowHeight, charWidth, 0, 0,
diff --git a/Windows/Debugger/Debugger_Disasm.cpp b/Windows/Debugger/Debugger_Disasm.cpp
index 584533703d..580166e407 100644
--- a/Windows/Debugger/Debugger_Disasm.cpp
+++ b/Windows/Debugger/Debugger_Disasm.cpp
@@ -291,11 +291,10 @@ void CDisasm::stepOver()
UpdateDialog();
}
-void CDisasm::stepOut()
-{
- if (!PSP_IsInited()) {
+void CDisasm::stepOut() {
+ auto memLock = Memory::Lock();
+ if (!PSP_IsInited())
return;
- }
auto threads = GetThreadsInfo();
diff --git a/Windows/Debugger/Debugger_Lists.cpp b/Windows/Debugger/Debugger_Lists.cpp
index 97be390f59..0c76c4d936 100644
--- a/Windows/Debugger/Debugger_Lists.cpp
+++ b/Windows/Debugger/Debugger_Lists.cpp
@@ -700,8 +700,11 @@ void CtrlStackTraceView::OnDoubleClick(int itemIndex, int column)
SendMessage(GetParent(GetHandle()),WM_DEB_GOTOWPARAM,frames[itemIndex].pc,0);
}
-void CtrlStackTraceView::loadStackTrace()
-{
+void CtrlStackTraceView::loadStackTrace() {
+ auto memLock = Memory::Lock();
+ if (!PSP_IsInited())
+ return;
+
auto threads = GetThreadsInfo();
u32 entry = 0, stackTop = 0;
diff --git a/Windows/Debugger/Debugger_MemoryDlg.cpp b/Windows/Debugger/Debugger_MemoryDlg.cpp
index d016afaafa..5382a69b71 100644
--- a/Windows/Debugger/Debugger_MemoryDlg.cpp
+++ b/Windows/Debugger/Debugger_MemoryDlg.cpp
@@ -257,7 +257,7 @@ void CMemoryDlg::Goto(u32 addr)
void CMemoryDlg::Size()
{
- const float fontScale = 1.0f / g_dpi_scale_real_y;
+ const float fontScale = 1.0f / g_display.dpi_scale_real_y;
GetClientRect(m_hDlg,&winRect);
int dlg_w = winRect.right - winRect.left;
diff --git a/Windows/GEDebugger/CtrlDisplayListView.cpp b/Windows/GEDebugger/CtrlDisplayListView.cpp
index eaaa8577f8..4c341c7e4b 100644
--- a/Windows/GEDebugger/CtrlDisplayListView.cpp
+++ b/Windows/GEDebugger/CtrlDisplayListView.cpp
@@ -45,7 +45,7 @@ CtrlDisplayListView::CtrlDisplayListView(HWND _wnd)
instructionSize = 4;
// In small window mode, g_dpi_scale may have been adjusted.
- const float fontScale = 1.0f / g_dpi_scale_real_y;
+ const float fontScale = 1.0f / g_display.dpi_scale_real_y;
int fontHeight = g_Config.iFontHeight * fontScale;
int charWidth = g_Config.iFontWidth * fontScale;
diff --git a/Windows/GPU/D3D11Context.cpp b/Windows/GPU/D3D11Context.cpp
index 6207b8fd75..6d04c24b0c 100644
--- a/Windows/GPU/D3D11Context.cpp
+++ b/Windows/GPU/D3D11Context.cpp
@@ -51,8 +51,8 @@ void D3D11Context::SwapInterval(int interval) {
HRESULT D3D11Context::CreateTheDevice(IDXGIAdapter *adapter) {
bool windowed = true;
// D3D11 has no need for display rotation.
- g_display_rotation = DisplayRotation::ROTATE_0;
- g_display_rot_matrix.setIdentity();
+ g_display.rotation = DisplayRotation::ROTATE_0;
+ g_display.rot_matrix.setIdentity();
#if defined(_DEBUG) && !PPSSPP_ARCH(ARM) && !PPSSPP_ARCH(ARM64)
UINT createDeviceFlags = D3D11_CREATE_DEVICE_DEBUG;
#else
diff --git a/Windows/GPU/D3D9Context.cpp b/Windows/GPU/D3D9Context.cpp
index dc02dade21..7ffe7f79f0 100644
--- a/Windows/GPU/D3D9Context.cpp
+++ b/Windows/GPU/D3D9Context.cpp
@@ -51,8 +51,8 @@ bool D3D9Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) {
hWnd_ = wnd;
// D3D9 has no need for display rotation.
- g_display_rotation = DisplayRotation::ROTATE_0;
- g_display_rot_matrix.setIdentity();
+ g_display.rotation = DisplayRotation::ROTATE_0;
+ g_display.rot_matrix.setIdentity();
DIRECT3DCREATE9EX g_pfnCreate9ex;
diff --git a/Windows/MainWindow.cpp b/Windows/MainWindow.cpp
index 6c30fa9d71..f02d1e4f79 100644
--- a/Windows/MainWindow.cpp
+++ b/Windows/MainWindow.cpp
@@ -643,8 +643,8 @@ namespace MainWindow
// Hack: Take the opportunity to show the cursor.
mouseButtonDown = true;
- float x = GET_X_LPARAM(lParam) * g_dpi_scale_x;
- float y = GET_Y_LPARAM(lParam) * g_dpi_scale_y;
+ float x = GET_X_LPARAM(lParam) * g_display.dpi_scale_x;
+ float y = GET_Y_LPARAM(lParam) * g_display.dpi_scale_y;
WindowsRawInput::SetMousePos(x, y);
TouchInput touch;
@@ -684,8 +684,8 @@ namespace MainWindow
prevCursorX = cursorX;
prevCursorY = cursorY;
- float x = (float)cursorX * g_dpi_scale_x;
- float y = (float)cursorY * g_dpi_scale_y;
+ float x = (float)cursorX * g_display.dpi_scale_x;
+ float y = (float)cursorY * g_display.dpi_scale_y;
WindowsRawInput::SetMousePos(x, y);
if (wParam & MK_LBUTTON) {
@@ -706,8 +706,8 @@ namespace MainWindow
// Hack: Take the opportunity to hide the cursor.
mouseButtonDown = false;
- float x = (float)GET_X_LPARAM(lParam) * g_dpi_scale_x;
- float y = (float)GET_Y_LPARAM(lParam) * g_dpi_scale_y;
+ float x = (float)GET_X_LPARAM(lParam) * g_display.dpi_scale_x;
+ float y = (float)GET_Y_LPARAM(lParam) * g_display.dpi_scale_y;
WindowsRawInput::SetMousePos(x, y);
TouchInput touch;
diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp
index ee15fab63b..022e1e70cc 100644
--- a/Windows/MainWindowMenu.cpp
+++ b/Windows/MainWindowMenu.cpp
@@ -91,6 +91,7 @@ namespace MainWindow {
EnableMenuItem(menu, ID_DEBUG_TAKESCREENSHOT, menuEnable);
EnableMenuItem(menu, ID_DEBUG_SHOWDEBUGSTATISTICS, menuInGameEnable);
EnableMenuItem(menu, ID_DEBUG_EXTRACTFILE, menuEnable);
+ EnableMenuItem(menu, ID_DEBUG_MEMORYBASE, menuInGameEnable);
// While playing, this pop up doesn't work - and probably doesn't make sense.
EnableMenuItem(menu, ID_OPTIONS_LANGUAGE, state == UISTATE_INGAME ? MF_GRAYED : MF_ENABLED);
@@ -221,6 +222,7 @@ namespace MainWindow {
TranslateMenuItem(menu, ID_DEBUG_GEDEBUGGER, g_Config.bSystemControls ? L"\tCtrl+G" : L"");
TranslateMenuItem(menu, ID_DEBUG_EXTRACTFILE);
TranslateMenuItem(menu, ID_DEBUG_LOG, g_Config.bSystemControls ? L"\tCtrl+L" : L"");
+ TranslateMenuItem(menu, ID_DEBUG_MEMORYBASE);
TranslateMenuItem(menu, ID_DEBUG_MEMORYVIEW, g_Config.bSystemControls ? L"\tCtrl+M" : L"");
// Options menu
@@ -822,6 +824,12 @@ namespace MainWindow {
memoryWindow->Show(true);
break;
+ case ID_DEBUG_MEMORYBASE:
+ {
+ W32Util::CopyTextToClipboard(hWnd, ConvertUTF8ToWString(StringFromFormat("%016llx", (uintptr_t)Memory::base)));
+ break;
+ }
+
case ID_DEBUG_EXTRACTFILE:
{
std::string filename;
diff --git a/Windows/TouchInputHandler.cpp b/Windows/TouchInputHandler.cpp
index d0f00e59f6..63b25934de 100644
--- a/Windows/TouchInputHandler.cpp
+++ b/Windows/TouchInputHandler.cpp
@@ -54,8 +54,8 @@ bool TouchInputHandler::GetTouchPoint(HWND hWnd, const TOUCHINPUT &input, float
point.x = (LONG)(TOUCH_COORD_TO_PIXEL(input.x));
point.y = (LONG)(TOUCH_COORD_TO_PIXEL(input.y));
if (ScreenToClient(hWnd, &point)) {
- x = point.x * g_dpi_scale_x;
- y = point.y * g_dpi_scale_y;
+ x = point.x * g_display.dpi_scale_x;
+ y = point.y * g_display.dpi_scale_y;
return true;
}
diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp
index b6cd28286c..5f194bcd88 100644
--- a/Windows/WindowsHost.cpp
+++ b/Windows/WindowsHost.cpp
@@ -238,8 +238,8 @@ void WindowsHost::PollControllers() {
// Disabled by default, needs a workaround to map to psp keys.
if (g_Config.bMouseControl) {
- float scaleFactor_x = g_dpi_scale_x * 0.1 * g_Config.fMouseSensitivity;
- float scaleFactor_y = g_dpi_scale_y * 0.1 * g_Config.fMouseSensitivity;
+ float scaleFactor_x = g_display.dpi_scale_x * 0.1 * g_Config.fMouseSensitivity;
+ float scaleFactor_y = g_display.dpi_scale_y * 0.1 * g_Config.fMouseSensitivity;
float mx = std::max(-1.0f, std::min(1.0f, g_mouseDeltaX * scaleFactor_x));
float my = std::max(-1.0f, std::min(1.0f, g_mouseDeltaY * scaleFactor_y));
diff --git a/Windows/main.cpp b/Windows/main.cpp
index d14b654f9e..973243a070 100644
--- a/Windows/main.cpp
+++ b/Windows/main.cpp
@@ -36,7 +36,7 @@
#include "Common/System/System.h"
#include "Common/File/FileUtil.h"
#include "Common/File/VFS/VFS.h"
-#include "Common/File/VFS/AssetReader.h"
+#include "Common/File/VFS/DirectoryReader.h"
#include "Common/Data/Text/I18n.h"
#include "Common/Profiler/Profiler.h"
#include "Common/Thread/ThreadUtil.h"
@@ -583,8 +583,8 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
#endif
const Path &exePath = File::GetExeDirectory();
- VFSRegister("", new DirectoryAssetReader(exePath / "assets"));
- VFSRegister("", new DirectoryAssetReader(exePath));
+ g_VFS.Register("", new DirectoryReader(exePath / "assets"));
+ g_VFS.Register("", new DirectoryReader(exePath));
langRegion = GetDefaultLangRegion();
osName = GetWindowsVersion() + " " + GetWindowsSystemArchitecture();
@@ -796,7 +796,7 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
}
}
- VFSShutdown();
+ g_VFS.Clear();
MainWindow::DestroyDebugWindows();
DialogManager::DestroyAll();
diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc
index b547443913..d2a2c921d9 100644
--- a/Windows/ppsspp.rc
+++ b/Windows/ppsspp.rc
@@ -537,6 +537,7 @@ BEGIN
MENUITEM "GE Debugger...", ID_DEBUG_GEDEBUGGER
MENUITEM "Extract File...", ID_DEBUG_EXTRACTFILE
MENUITEM "Log Console", ID_DEBUG_LOG
+ MENUITEM "Copy PSP memory base pointer", ID_DEBUG_MEMORYBASE
MENUITEM "Memory View...", ID_DEBUG_MEMORYVIEW
END
@@ -720,6 +721,7 @@ BEGIN
MENUITEM "Rename Function...", ID_DISASM_RENAMEFUNCTION
MENUITEM "Remove Function", ID_DISASM_REMOVEFUNCTION
MENUITEM "Add Function Here", ID_DISASM_ADDFUNCTION
+ MENUITEM "NOP instruction(s)", ID_DISASM_NOPINSTRUCTION
END
POPUP "reglist"
BEGIN
diff --git a/Windows/resource.h b/Windows/resource.h
index 66ec982d23..ffe653d58a 100644
--- a/Windows/resource.h
+++ b/Windows/resource.h
@@ -18,6 +18,7 @@
#define ID_DEBUG_DISASSEMBLY 119
#define WHEEL_DELTA 120
#define ID_DEBUG_LOG 121
+#define ID_DEBUG_MEMORYBASE 122
#define ID_FILE_OPEN_NEW_INSTANCE 123
#define ID_FILE_LOADSTATEFILE 126
#define ID_FILE_SAVESTATEFILE 127
@@ -333,6 +334,7 @@
#define ID_GEDBG_COPY_IMAGE_ALPHA 40225
#define ID_GEDBG_TRACK_PIXEL 40226
#define ID_GEDBG_TRACK_PIXEL_STOP 40227
+#define ID_DISASM_NOPINSTRUCTION 40228
// Dummy option to let the buffered rendering hotkey cycle through all the options.
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index ab8cf74a3b..0d67ad89e4 100644
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -1,7 +1,6 @@
@@ -43,7 +42,7 @@
= 14000000) {
// Start using automatic Android version numbers from version 1.4.
- println "Overriding Android Version Name, Code: " + androidGitVersion.name() + " " + androidGitVersion.code();
+ println "Overriding Android Version Name, Code: " + androidGitVersion.name() + " " + androidGitVersion.code()
versionName androidGitVersion.name()
versionCode androidGitVersion.code()
} else {
- println "(not using these:) Android Version Name, Code: " + androidGitVersion.name() + " " + androidGitVersion.code();
+ println "(not using these:) Android Version Name, Code: " + androidGitVersion.name() + " " + androidGitVersion.code()
}
new File("versionname.txt").write(androidGitVersion.name())
@@ -92,7 +92,9 @@ android {
}
}
packagingOptions {
- exclude 'lib/arm64-v8a/libopenxr_loader.so'
+ jniLibs {
+ excludes += ['lib/arm64-v8a/libopenxr_loader.so']
+ }
}
sourceSets {
main {
diff --git a/android/gold/res/mipmap-anydpi-v26/ic_launcher.xml b/android/gold/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000000..036d09bc5f
--- /dev/null
+++ b/android/gold/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/gold/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/gold/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000000..036d09bc5f
--- /dev/null
+++ b/android/gold/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/gold/res/mipmap-hdpi/ic_launcher.png b/android/gold/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000000..3b6eb44875
Binary files /dev/null and b/android/gold/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/android/gold/res/mipmap-hdpi/ic_launcher_foreground.png b/android/gold/res/mipmap-hdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..ddd85887cd
Binary files /dev/null and b/android/gold/res/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/android/gold/res/mipmap-hdpi/ic_launcher_round.png b/android/gold/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..0bab70e86d
Binary files /dev/null and b/android/gold/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/android/gold/res/mipmap-mdpi/ic_launcher.png b/android/gold/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000000..defe49449a
Binary files /dev/null and b/android/gold/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/android/gold/res/mipmap-mdpi/ic_launcher_foreground.png b/android/gold/res/mipmap-mdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..da83c7f7aa
Binary files /dev/null and b/android/gold/res/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/android/gold/res/mipmap-mdpi/ic_launcher_round.png b/android/gold/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..59ac6fd565
Binary files /dev/null and b/android/gold/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/android/gold/res/mipmap-xhdpi/ic_launcher.png b/android/gold/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000000..1ac24a1742
Binary files /dev/null and b/android/gold/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/android/gold/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/gold/res/mipmap-xhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..1b164184ef
Binary files /dev/null and b/android/gold/res/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/android/gold/res/mipmap-xhdpi/ic_launcher_round.png b/android/gold/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..545f37de12
Binary files /dev/null and b/android/gold/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/android/gold/res/mipmap-xxhdpi/ic_launcher.png b/android/gold/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000000..b9595acf2a
Binary files /dev/null and b/android/gold/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/gold/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/gold/res/mipmap-xxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..9aad451c46
Binary files /dev/null and b/android/gold/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/android/gold/res/mipmap-xxhdpi/ic_launcher_round.png b/android/gold/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..0b0f5e6485
Binary files /dev/null and b/android/gold/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/android/gold/res/mipmap-xxxhdpi/ic_launcher.png b/android/gold/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000000..61c0d3398f
Binary files /dev/null and b/android/gold/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android/gold/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/gold/res/mipmap-xxxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..c11c07b095
Binary files /dev/null and b/android/gold/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/android/gold/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/gold/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..45b8242868
Binary files /dev/null and b/android/gold/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/android/gold/res/values/ic_launcher_background.xml b/android/gold/res/values/ic_launcher_background.xml
new file mode 100644
index 0000000000..41d3129698
--- /dev/null
+++ b/android/gold/res/values/ic_launcher_background.xml
@@ -0,0 +1,4 @@
+
+
+ #53482D
+
\ No newline at end of file
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index 9c7912881b..57b695f3e5 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -175,7 +175,8 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Common/Data/Text/WrapText.cpp \
$(SRC)/Common/File/AndroidStorage.cpp \
$(SRC)/Common/File/VFS/VFS.cpp \
- $(SRC)/Common/File/VFS/AssetReader.cpp \
+ $(SRC)/Common/File/VFS/ZipFileReader.cpp \
+ $(SRC)/Common/File/VFS/DirectoryReader.cpp \
$(SRC)/Common/File/DiskFree.cpp \
$(SRC)/Common/File/Path.cpp \
$(SRC)/Common/File/PathBrowser.cpp \
@@ -358,6 +359,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/GPU/Math3D.cpp \
$(SRC)/GPU/GPU.cpp \
$(SRC)/GPU/GPUCommon.cpp \
+ $(SRC)/GPU/GPUCommonHW.cpp \
$(SRC)/GPU/GPUState.cpp \
$(SRC)/GPU/GeConstants.cpp \
$(SRC)/GPU/GeDisasm.cpp \
@@ -387,6 +389,8 @@ EXEC_AND_LIB_FILES := \
$(SRC)/GPU/Common/ShaderUniforms.cpp \
$(SRC)/GPU/Common/VertexShaderGenerator.cpp \
$(SRC)/GPU/Common/GeometryShaderGenerator.cpp \
+ $(SRC)/GPU/Common/TextureReplacer.cpp \
+ $(SRC)/GPU/Common/ReplacedTexture.cpp \
$(SRC)/GPU/Debugger/Breakpoints.cpp \
$(SRC)/GPU/Debugger/Debugger.cpp \
$(SRC)/GPU/Debugger/GECommandTable.cpp \
@@ -454,7 +458,6 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Core/SaveState.cpp \
$(SRC)/Core/Screenshot.cpp \
$(SRC)/Core/System.cpp \
- $(SRC)/Core/TextureReplacer.cpp \
$(SRC)/Core/TiltEventProcessor.cpp \
$(SRC)/Core/ThreadPools.cpp \
$(SRC)/Core/WebServer.cpp \
diff --git a/android/jni/AndroidJavaGLContext.cpp b/android/jni/AndroidJavaGLContext.cpp
index ebf22b143c..a2cada60f5 100644
--- a/android/jni/AndroidJavaGLContext.cpp
+++ b/android/jni/AndroidJavaGLContext.cpp
@@ -19,8 +19,8 @@ bool AndroidJavaEGLGraphicsContext::InitFromRenderThread(ANativeWindow *wnd, int
}
// OpenGL handles rotated rendering in the driver.
- g_display_rotation = DisplayRotation::ROTATE_0;
- g_display_rot_matrix.setIdentity();
+ g_display.rotation = DisplayRotation::ROTATE_0;
+ g_display.rot_matrix.setIdentity();
draw_ = Draw::T3DCreateGLContext(); // Can't fail
renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
diff --git a/android/jni/TestRunner.cpp b/android/jni/TestRunner.cpp
index 64e6f7761c..1b9a8acb52 100644
--- a/android/jni/TestRunner.cpp
+++ b/android/jni/TestRunner.cpp
@@ -119,8 +119,8 @@ bool RunTests() {
output.clear();
if (!PSP_Init(coreParam, &error_string)) {
ERROR_LOG(SYSTEM, "Failed to init unittest %s : %s", testsToRun[i], error_string.c_str());
- PSP_CoreParameter().pixelWidth = pixel_xres;
- PSP_CoreParameter().pixelHeight = pixel_yres;
+ PSP_CoreParameter().pixelWidth = g_display.pixel_xres;
+ PSP_CoreParameter().pixelHeight = g_display.pixel_yres;
return false;
}
@@ -176,8 +176,8 @@ bool RunTests() {
}
PSP_Shutdown();
}
- PSP_CoreParameter().pixelWidth = pixel_xres;
- PSP_CoreParameter().pixelHeight = pixel_yres;
+ PSP_CoreParameter().pixelWidth = g_display.pixel_xres;
+ PSP_CoreParameter().pixelHeight = g_display.pixel_yres;
PSP_CoreParameter().headLess = false;
PSP_CoreParameter().graphicsContext = tempCtx;
diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp
index b510942036..d7ac20ec4b 100644
--- a/android/jni/app-android.cpp
+++ b/android/jni/app-android.cpp
@@ -65,7 +65,8 @@ struct JNIEnv {};
#include "Common/File/Path.h"
#include "Common/File/DirListing.h"
#include "Common/File/VFS/VFS.h"
-#include "Common/File/VFS/AssetReader.h"
+#include "Common/File/VFS/DirectoryReader.h"
+#include "Common/File/VFS/ZipFileReader.h"
#include "Common/File/AndroidStorage.h"
#include "Common/Input/InputState.h"
#include "Common/Input/KeyCodes.h"
@@ -73,6 +74,7 @@ struct JNIEnv {};
#include "Common/Math/math_util.h"
#include "Common/Data/Text/Parsers.h"
#include "Common/VR/PPSSPPVR.h"
+#include "Common/GPU/Vulkan/VulkanLoader.h"
#include "Common/GraphicsContext.h"
#include "Common/StringUtils.h"
@@ -461,7 +463,7 @@ int System_GetPropertyInt(SystemProperty prop) {
float System_GetPropertyFloat(SystemProperty prop) {
switch (prop) {
case SYSPROP_DISPLAY_REFRESH_RATE:
- return display_hz;
+ return g_display.display_hz;
case SYSPROP_DISPLAY_SAFE_INSET_LEFT:
return g_safeInsetLeft;
case SYSPROP_DISPLAY_SAFE_INSET_RIGHT:
@@ -677,9 +679,9 @@ static void parse_args(std::vector &args, const std::string value)
#define EARLY_LOG(...) __android_log_print(ANDROID_LOG_INFO, "PPSSPP", __VA_ARGS__)
extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init
- (JNIEnv *env, jclass, jstring jmodel, jint jdeviceType, jstring jlangRegion, jstring japkpath,
- jstring jdataDir, jstring jexternalStorageDir, jstring jexternalFilesDir, jstring jadditionalStorageDirs, jstring jcacheDir, jstring jshortcutParam,
- jint jAndroidVersion, jstring jboard) {
+(JNIEnv * env, jclass, jstring jmodel, jint jdeviceType, jstring jlangRegion, jstring japkpath,
+ jstring jdataDir, jstring jexternalStorageDir, jstring jexternalFilesDir, jstring jadditionalStorageDirs, jstring jcacheDir, jstring jshortcutParam,
+ jint jAndroidVersion, jstring jboard) {
SetCurrentThreadName("androidInit");
// Makes sure we get early permission grants.
@@ -693,8 +695,8 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init
androidVersion = jAndroidVersion;
deviceType = jdeviceType;
- std::string apkPath = GetJavaString(env, japkpath);
- VFSRegister("", new ZipAssetReader(apkPath.c_str(), "assets/"));
+ Path apkPath(GetJavaString(env, japkpath));
+ g_VFS.Register("", ZipFileReader::Create(apkPath, "assets/"));
systemName = GetJavaString(env, jmodel);
langRegion = GetJavaString(env, jlangRegion);
@@ -754,6 +756,15 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init
NativeInit((int)args.size(), &args[0], user_data_path.c_str(), externalStorageDir.c_str(), cacheDir.c_str());
+ // In debug mode, don't allow creating software Vulkan devices (reject by VulkaMaybeAvailable).
+ // Needed for #16931.
+#ifdef NDEBUG
+ if (!VulkanMayBeAvailable()) {
+ // If VulkanLoader decided on no viable backend, let's force Vulkan off in release builds at least.
+ g_Config.iGPUBackend = 0;
+ }
+#endif
+
// No need to use EARLY_LOG anymore.
retry:
@@ -897,7 +908,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_shutdown(JNIEnv *, jclass) {
std::lock_guard guard(renderLock);
inputBoxCallbacks.clear();
NativeShutdown();
- VFSShutdown();
+ g_VFS.Clear();
}
{
@@ -977,35 +988,35 @@ extern "C" bool Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env,
}
static void recalculateDpi() {
- g_dpi = display_dpi_x;
- g_dpi_scale_x = 240.0f / display_dpi_x;
- g_dpi_scale_y = 240.0f / display_dpi_y;
- g_dpi_scale_real_x = g_dpi_scale_x;
- g_dpi_scale_real_y = g_dpi_scale_y;
+ g_display.dpi = display_dpi_x;
+ g_display.dpi_scale_x = 240.0f / display_dpi_x;
+ g_display.dpi_scale_y = 240.0f / display_dpi_y;
+ g_display.dpi_scale_real_x = g_display.dpi_scale_x;
+ g_display.dpi_scale_real_y = g_display.dpi_scale_y;
- dp_xres = display_xres * g_dpi_scale_x;
- dp_yres = display_yres * g_dpi_scale_y;
+ g_display.dp_xres = display_xres * g_display.dpi_scale_x;
+ g_display.dp_yres = display_yres * g_display.dpi_scale_y;
- pixel_in_dps_x = (float)pixel_xres / dp_xres;
- pixel_in_dps_y = (float)pixel_yres / dp_yres;
+ g_display.pixel_in_dps_x = (float)g_display.pixel_xres / g_display.dp_xres;
+ g_display.pixel_in_dps_y = (float)g_display.pixel_yres / g_display.dp_yres;
- INFO_LOG(G3D, "RecalcDPI: display_xres=%d display_yres=%d pixel_xres=%d pixel_yres=%d", display_xres, display_yres, pixel_xres, pixel_yres);
- INFO_LOG(G3D, "RecalcDPI: g_dpi=%f g_dpi_scale_x=%f g_dpi_scale_y=%f dp_xres=%d dp_yres=%d", g_dpi, g_dpi_scale_x, g_dpi_scale_y, dp_xres, dp_yres);
+ INFO_LOG(G3D, "RecalcDPI: display_xres=%d display_yres=%d pixel_xres=%d pixel_yres=%d", display_xres, display_yres, g_display.pixel_xres, g_display.pixel_yres);
+ INFO_LOG(G3D, "RecalcDPI: g_dpi=%f g_dpi_scale_x=%f g_dpi_scale_y=%f dp_xres=%d dp_yres=%d", g_display.dpi, g_display.dpi_scale_x, g_display.dpi_scale_y, g_display.dp_xres, g_display.dp_yres);
}
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv *, jclass, jint bufw, jint bufh, jint format) {
INFO_LOG(SYSTEM, "NativeApp.backbufferResize(%d x %d)", bufw, bufh);
- bool new_size = pixel_xres != bufw || pixel_yres != bufh;
- int old_w = pixel_xres;
- int old_h = pixel_yres;
+ bool new_size = g_display.pixel_xres != bufw || g_display.pixel_yres != bufh;
+ int old_w = g_display.pixel_xres;
+ int old_h = g_display.pixel_yres;
// pixel_*res is the backbuffer resolution.
- pixel_xres = bufw;
- pixel_yres = bufh;
+ g_display.pixel_xres = bufw;
+ g_display.pixel_yres = bufh;
backbuffer_format = format;
if (IsVREnabled()) {
- GetVRResolutionPerEye(&pixel_xres, &pixel_yres);
+ GetVRResolutionPerEye(&g_display.pixel_xres, &g_display.pixel_yres);
}
recalculateDpi();
@@ -1093,7 +1104,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayRender(JNIEnv *env,
}
if (IsVREnabled()) {
- UpdateVRInput(g_Config.bHapticFeedback, g_dpi_scale_x, g_dpi_scale_y);
+ UpdateVRInput(g_Config.bHapticFeedback, g_display.dpi_scale_x, g_display.dpi_scale_y);
FinishVRRender();
}
}
@@ -1117,8 +1128,8 @@ PermissionStatus System_GetPermissionStatus(SystemPermission permission) {
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_touch
(JNIEnv *, jclass, float x, float y, int code, int pointerId) {
- float scaledX = x * g_dpi_scale_x;
- float scaledY = y * g_dpi_scale_y;
+ float scaledX = x * g_display.dpi_scale_x;
+ float scaledY = y * g_display.dpi_scale_y;
TouchInput touch;
touch.id = pointerId;
@@ -1215,10 +1226,10 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendMessage(JNIEnv *env
// We don't bother with supporting exact rectangular regions. Safe insets are good enough.
int left, right, top, bottom;
if (4 == sscanf(prm.c_str(), "%d:%d:%d:%d", &left, &right, &top, &bottom)) {
- g_safeInsetLeft = (float)left * g_dpi_scale_x;
- g_safeInsetRight = (float)right * g_dpi_scale_x;
- g_safeInsetTop = (float)top * g_dpi_scale_y;
- g_safeInsetBottom = (float)bottom * g_dpi_scale_y;
+ g_safeInsetLeft = (float)left * g_display.dpi_scale_x;
+ g_safeInsetRight = (float)right * g_display.dpi_scale_x;
+ g_safeInsetTop = (float)top * g_display.dpi_scale_y;
+ g_safeInsetBottom = (float)bottom * g_display.dpi_scale_y;
}
}
@@ -1251,14 +1262,14 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_setDisplayParameters(JN
bool changed = false;
changed = changed || display_xres != xres || display_yres != yres;
changed = changed || display_dpi_x != dpi || display_dpi_y != dpi;
- changed = changed || display_hz != refreshRate;
+ changed = changed || g_display.display_hz != refreshRate;
if (changed) {
display_xres = xres;
display_yres = yres;
display_dpi_x = dpi;
display_dpi_y = dpi;
- display_hz = refreshRate;
+ g_display.display_hz = refreshRate;
recalculateDpi();
NativeResized();
diff --git a/android/res/mipmap-anydpi-v26/ic_launcher.xml b/android/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000000..036d09bc5f
--- /dev/null
+++ b/android/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000000..036d09bc5f
--- /dev/null
+++ b/android/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/mipmap-hdpi/ic_launcher.png b/android/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000000..e4861f3566
Binary files /dev/null and b/android/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/android/res/mipmap-hdpi/ic_launcher_foreground.png b/android/res/mipmap-hdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..dfd4b7ebad
Binary files /dev/null and b/android/res/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/android/res/mipmap-hdpi/ic_launcher_round.png b/android/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..33e11da647
Binary files /dev/null and b/android/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/android/res/mipmap-mdpi/ic_launcher.png b/android/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000000..78762e0a13
Binary files /dev/null and b/android/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/android/res/mipmap-mdpi/ic_launcher_foreground.png b/android/res/mipmap-mdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..00db9645c0
Binary files /dev/null and b/android/res/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/android/res/mipmap-mdpi/ic_launcher_round.png b/android/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..20aa16737d
Binary files /dev/null and b/android/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/android/res/mipmap-xhdpi/ic_launcher.png b/android/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000000..f86cb15b8a
Binary files /dev/null and b/android/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/android/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/res/mipmap-xhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..1711f0f7b9
Binary files /dev/null and b/android/res/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/android/res/mipmap-xhdpi/ic_launcher_round.png b/android/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..0fb5a8c0d7
Binary files /dev/null and b/android/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/android/res/mipmap-xxhdpi/ic_launcher.png b/android/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000000..5c08e8fe6d
Binary files /dev/null and b/android/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/res/mipmap-xxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..b623f90e42
Binary files /dev/null and b/android/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/android/res/mipmap-xxhdpi/ic_launcher_round.png b/android/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..792f90ca0a
Binary files /dev/null and b/android/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/android/res/mipmap-xxxhdpi/ic_launcher.png b/android/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000000..dc6461c734
Binary files /dev/null and b/android/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/res/mipmap-xxxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000000..25516d315d
Binary files /dev/null and b/android/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/android/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000..7c3741b281
Binary files /dev/null and b/android/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/android/res/values/ic_launcher_background.xml b/android/res/values/ic_launcher_background.xml
new file mode 100644
index 0000000000..eceed3d93c
--- /dev/null
+++ b/android/res/values/ic_launcher_background.xml
@@ -0,0 +1,4 @@
+
+
+ #2D4553
+
\ No newline at end of file
diff --git a/assets/compat.ini b/assets/compat.ini
index 91b673fb7a..58dff15e54 100644
--- a/assets/compat.ini
+++ b/assets/compat.ini
@@ -328,9 +328,11 @@ UCED00971 = true
UCUS98713 = true
# Daxter
UCUS98618 = true
+UCUS98654 = true
UCES00044 = true
NPUG80329 = true
NPEG00025 = true
+UCKS45025 = true
# Ys Seven
ULUS10551 = true
ULJM05475 = true
@@ -1479,3 +1481,45 @@ NPEG00004 = true
ULES01070 = true
ULES01071 = true
ULUS10347 = true
+
+[DaxterRotatedAnalogStick]
+# Daxter (see issue #17015)
+UCUS98618 = true
+UCUS98654 = true
+UCES00044 = true
+NPUG80329 = true
+NPEG00025 = true
+UCKS45025 = true
+
+# GOW : Ghost of Sparta
+UCUS98737 = true
+UCAS40323 = true
+NPHG00092 = true
+NPEG00044 = true
+NPEG00045 = true
+NPJG00120 = true
+NPUG80508 = true
+UCJS10114 = true
+UCES01401 = true
+UCES01473 = true
+# GOW : Ghost of Sparta Demo
+NPJG90095 = true
+NPEG90035 = true
+NPUG70125 = true
+# GOW : Chains Of Olympus
+UCAS40198 = true
+UCUS98653 = true
+UCES00842 = true
+ULJM05438 = true
+ULJM05348 = true
+UCKS45084 = true
+NPUG80325 = true
+NPEG00023 = true
+NPHG00027 = true
+NPHG00028 = true
+NPJH50170 = true
+UCET00844 = true
+# GOW: Chains of Olympus Demo
+UCUS98705 = true
+UCED00971 = true
+UCUS98713 = true
diff --git a/assets/lang/pt_BR.ini b/assets/lang/pt_BR.ini
index 61a97a6d42..f7963e1dff 100644
--- a/assets/lang/pt_BR.ini
+++ b/assets/lang/pt_BR.ini
@@ -114,11 +114,11 @@ Swipe = Deslizar
Swipe sensitivity = Sensibilidade do deslizar
Swipe smoothing = Suavidade do deslizar
Thin borders = Bordas finas
-Tilt control setup = Personalizar inclinação...
+Tilt control setup = Configuração do controle da inclinação
Tilt Input Type = Controle da entrada da inclinação
Tilt Sensitivity along X axis = Sensibilidade da inclinação junto ao eixo X
Tilt Sensitivity along Y axis = Sensibilidade da inclinação junto ao eixo Y
-To Calibrate = Segure o dispositivo em seu ângulo preferido e pressione "Calibrar".
+To Calibrate = Mantenha o dispositivo no seu ângulo preferido e pressione "Calibrar".
Toggle mode = Alternar modo
Repeat mode = Modo de repetição
Touch Control Visibility = Visibilidade do controle de toque
@@ -243,7 +243,7 @@ Backspace = Backspace
Block address = Bloquear endereço
By Address = Pelo endereço
Copy savestates to memstick root = Copiar os save states pra raiz do cartão de memória
-Create/Open textures.ini file for current game = Criar/abrir o arquivo textures.ini pro jogo atual
+Create/Open textures.ini file for current game = Criar/Abrir o arquivo textures.ini pro jogo atual
Current = Atual
Dev Tools = Ferramentas de desenvolvimento
DevMenu = Menu do DEV
@@ -262,7 +262,7 @@ GPU Profile = Perfil da GPU
GPU log profiler = Criador do perfil do registro da GPU
Jit Compare = Comparar JIT
JIT debug tools = Ferramentas de debug do JIT
-Log Dropped Frame Statistics = Pôr no registro as estátisticas da queda dos frames
+Log Dropped Frame Statistics = Registrar as estátisticas da queda dos frames
Log Level = Nível do registro
Log View = Visualização do registro
Logging Channels = Canais do registro
@@ -273,7 +273,7 @@ Random = Aleatório
Replace textures = Substituir texturas
Reset = Resetar
Reset limited logging = Resetar o registro limitado
-RestoreDefaultSettings = Você tem certeza que você quer restaurar todas as configurações de volta aos padrões delas?\n\nVocê não pode desfazer isto.\nPor favor reinicie o PPSSPP para as mudanças terem efeito.
+RestoreDefaultSettings = Restaurar estas configurações aos padrões delas?\nVocê não pode desfazer isto.\nPor favor reinicie o PPSSPP após restaurar as configurações.
RestoreGameDefaultSettings = Você tem certeza que você quer restaurar as configurações específicas do jogo\nde volta para os padrões do PPSSPP?
Resume = Resumo
Run CPU Tests = Executar testes da CPU
@@ -372,11 +372,11 @@ Zoom = Zoom
A PSP game couldn't be found on the disc. = Um jogo de PSP não pôde ser achado no disco.
Cannot boot ELF located outside mountRoot. = Não pôde dar boot no ELF localizado fora do mountRoot.
Could not save screenshot file = Não pôde salvar o arquivo da screenshot.
-D3D9or11 = Direct3D 9? (ou "não" pro Direct3D 11)
+D3D9or11 = Direct3D 9? (Ou "não" pro Direct3D 11)
D3D11CompilerMissing = O D3DCompiler_47.dll não foi achado. Por favor instale-o. Ou pressione Sim pra tentar de novo usando o Direct3D 9 ao invés disto.
D3D11InitializationError = Erro de inicialização do Direct3D 11
-D3D11Missing = Sua versão do sistema operacional não inclui o D3D11. Por favor execute o Windows Update.\n\nPressione Sim pra tentar de novo usando o Direct3D 9 ao invés disto.
-D3D11NotSupported = Sua GPU não aparenta suportar o Direct3D 11.\n\nVocê gostaria de tentar de novo usando o Direct3D 9 ao invés disto?
+D3D11Missing = Sua versão do sistema operacional não inclui o D3D11. Por favor execute o Windows Update.\n\nPressione Sim pra tentar de novo usando o Direct3D 9 ao invés deste.
+D3D11NotSupported = Sua GPU não aparenta suportar o Direct3D 11.\n\nVocê gostaria de tentar de novo usando o Direct3D 9 ao invés deste?
Disk full while writing data = O disco ficou cheio enquanto gravava os dados.
ELF file truncated - can't load = Arquivo ELF truncado - não pôde carregar
Error loading file = Não pôde carregar o arquivo.
@@ -405,7 +405,7 @@ OpenGLDriverError = Erro do driver do OpenGL
PPSSPP doesn't support UMD Music. = O PPSSPP não suporta a música do UMD.
PPSSPP doesn't support UMD Video. = O PPSSPP não suporta o vídeo do UMD.
PPSSPP plays PSP games, not PlayStation 1 or 2 games. = O PPSSPP roda jogos de PSP, não jogos de PlayStation 1 ou 2.
-PPSSPPDoesNotSupportInternet = O PPSSPP atualmente não suporta conexão com a Internet pra DLC, PSN ou atualizações de jogos.
+PPSSPPDoesNotSupportInternet = O PPSSPP atualmente não suporta conexão com a Internet pro DLC, PSN ou atualizações de jogos.
PS1 EBOOTs are not supported by PPSSPP. = OS EBOOTS do PS1 não são suportados pelo PPSSPP.
PSX game image detected. = O arquivo é uma imagem do MODE2. O PPSSPP não suporta jogos de PS1.
RAR file detected (Require UnRAR) = O arquivo está comprimido (RAR).\nPor favor descomprima-o primeiro (tente o UnRAR).
@@ -482,7 +482,7 @@ Aspect Ratio = Proporção do Aspecto
Auto = Auto
Auto (1:1) = Auto (1:1)
Auto (same as Rendering) = Auto (a mesma que a da resolução de renderização)
-Auto FrameSkip = Auto-pulo dos frames
+Auto FrameSkip = Auto frameskip
Auto Max Quality = Auto-maximizar a qualidade
Auto Scaling = Auto-redimensionamento
Backend = Backend
@@ -517,7 +517,7 @@ Frame Skipping = Pulo dos frames
Frame Skipping Type = Tipo de pulo dos frames
FullScreen = Tela cheia
Geometry shader culling = Abate do shader da geometria
-Hack Settings = Configurações dos hacks (pode causar erros gráficos)
+Hack Settings = Configurações dos hacks (pode causar erros gráficos)
Hardware Tessellation = Tesselação por hardware
Hardware Transform = Transformação por hardware
hardware transform error - falling back to software = Erro de transformação pelo hardware, retrocedendo pro software.
@@ -541,8 +541,8 @@ Must Restart = Você deve reiniciar o PPSSPP pra esta mudança ter efeito.
Native device resolution = Resolução nativa do dispositivo
Nearest = Mais próximo
No buffer = Sem buffer
-Show Battery % = Show Battery %
-Show Speed = Show Speed
+Show Battery % = Mostrar Bateria %
+Show Speed = Mostrar Velocidade
Skip Buffer Effects = Ignorar efeitos do buffer
None = Nenhum
Number of Frames = Número de frames
@@ -564,7 +564,7 @@ Safe = Seguro
Screen Scaling Filter = Filtro do dimensionamento da tela
Show Debug Statistics = Mostrar estatísticas do debug
Show FPS Counter = Mostrar contador de FPS
-Skip GPU Readbacks = Ignorar Leituras da GPU
+Skip GPU Readbacks = Ignorar leituras da GPU
Software Rendering = Renderização por software (lento)
Software Skinning = Skinning via software
SoftwareSkinning Tip = Combina os desenhos dos modelos de skinning na CPU, mais rápido na maioria dos jogos
@@ -599,7 +599,7 @@ Install game from ZIP file? = Instalar o jogo do arquivo ZIP?
Install textures from ZIP file? = Instalar as texturas do arquivo ZIP?
Installed! = Instalado!
Texture pack doesn't support install = O pacote das texturas não suporta a instalação
-Zip archive corrupt = Arquivo ZIP compactado corrompido
+Zip archive corrupt = Arquivo ZIP corrompido
Zip file does not contain PSP software = O arquivo ZIP não contém software do PSP
[KeyMapping]
@@ -696,15 +696,15 @@ R = R
RapidFire = Fogo rápido
Record = Gravar
Remote hold = Segurar remoto
-Rewind = Rebobinar
+Rewind = Retroceder
Right = Direcional Direito
Right Analog Stick = Direcional Análogico Direito
RightAn.Down = Analógico Direito pra Baixo
RightAn.Left = Analógico Direito a Esquerda
RightAn.Right = Analógico Direito a Direita
RightAn.Up = Analógico Direito pra Cima
-Rotate Analog (CCW) = Rotação do analógico (Anti-horário)
-Rotate Analog (CW) = Rotação do analógico (sentido horário)
+Rotate Analog (CCW) = Rotação do analógico (Sentido anti-horário)
+Rotate Analog (CW) = Rotação do analógico (Sentido horário)
Save State = Salvar state
Screen = Tela
Screenshot = Screenshot
@@ -807,7 +807,7 @@ Delete Game Config = Apagar configuração do jogo
Exit to menu = Sair pro menu
Game Settings = Configurações do jogo
Load State = Carregar state
-Rewind = Rebobinar
+Rewind = Retroceder
Save State = Salvar state
Settings = Configurações
Switch UMD = Trocar UMD
@@ -886,10 +886,10 @@ tools = Ferramentas grátis usadas:
# Leave extra lines blank. 4 contributors per line seems to look best.
translators1 = Papel, gabrielmop, Efraim Lopes, AkiraJkr
translators2 = Felipe
-translators3 =
-translators4 =
-translators5 =
-translators6 =
+translators3 =
+translators4 =
+translators5 =
+translators6 =
Twitter @PPSSPP_emu = Twitter @PPSSPP_emu
website = Verifique o site da web:
written = Escrito em C++ pela velocidade e portabilidade
@@ -932,7 +932,7 @@ Remote Port = Porta remota
Remote Server = Servidor remoto
Remote Subdirectory = Sub-diretório remoto
RemoteISODesc = Os jogos na sua lista de "Recentes" serão compartilhados
-RemoteISOLoading = Conectado, carregando a lista de jogos...
+RemoteISOLoading = Conectado, carregando a lista dos jogos...
RemoteISOScanning = Escaneando... Cliqme em "compartilhar jogos" no dispositivo do seu servidor
RemoteISOScanningTimeout = Escaneando... Verifique suas configurações do firewall na área de trabalho
RemoteISOWifi = Nota: Conecte os dois dispositivos na mesma rede Wi-Fi
@@ -1062,7 +1062,7 @@ Debugger Present = Debugger presente
Depth buffer format = Formato do buffer de profundidade
Device Info = Informação do dispositivo
Directories = Diretórios
-Display Information = Informação da tela
+Display Information = Exibir informação
DPI = DPI
Driver bugs = Bugs do driver
Driver Version = Versão do driver
@@ -1143,13 +1143,13 @@ Fast (lag on slow storage) = Rápido (atraso na armazenagem lenta)
Fast Memory = Memória rápida (instável)
Floating symbols = Símbolos flutuantes
Force real clock sync (slower, less lag) = Forçar sincronização com o relógio real (mais lento, menos atrasos)
-seconds, 0:off = seconds, 0 = Desligado
+seconds, 0:off = segundos, 0 = Desligado
Game crashed = O jogo teve um crash
Games list settings = Configurações da lista de jogos
General = Geral
Grid icon size = Tamanho do ícone da grade
Help the PPSSPP team = Ajude o time do PPSSPP
-Host (bugs, less lag) = Hospedeiro (bugs, menos atrasos)
+Host (bugs, less lag) = Hospedeiro (tem bugs, menos atrasos)
Ignore bad memory accesses = Ignorar acessos ruins da memória
Increase size = Aumentar tamanho
Interpreter = Interpretador
@@ -1177,13 +1177,13 @@ Record Audio = Gravar áudio
Record Display = Gravar tela
Reset Recording on Save/Load State = Resetar a gravação ao salvar/carregar o state
Restore Default Settings = Restaurar as configurações do PPSSPP para os padrões
-Rewind Snapshot Frequency = Retroceder a frequência dos snapshots (consome memória)
+Rewind Snapshot Frequency = Retroceder a frequência dos snapshots (consome muita memória)
Save path in installed.txt = Caminho do save em installed.txt
Save path in My Documents = Caminho do save em Meus Documentos
Savestate Slot = Slot do state salvo
Savestate slot backups = Backups dos slots dos states salvos
Screenshots as PNG = Salvar as screenshots no formato PNG
-Set Memory Stick folder = Set Memory Stick folder
+Set Memory Stick folder = Definir a pasta do cartão de memória
Set UI background... = Definir o cenário de fundo da interface do usuário...
Show ID = Mostrar ID
Show region flag = Mostrar a bandeira da região
@@ -1255,9 +1255,9 @@ Screen representation = Representação da tela
% of native FoV = % do campo de visão nativo
6DoF movement = Movimentação do 6DoF
Distance to 2D menus and scenes = Distância até os menus e cenas 2D
-Field of view scale = Campo da escala de visualização
+Field of view scale = Escala do campo de visualização
Force 72Hz update = Forçar atualização em 72 Hz
-Heads-up display scale = Aviso da escala de exibição
+Heads-up display scale = Escala do aviso antecipado da exibição
Map controller movements to keys = Mapear os movimentos do controle nas teclas
Motion needed to generate action = Movimento necessário pra gerar ação
Stereoscopic vision (Experimental) = Visão estereoscópica (Experimental)
diff --git a/assets/lang/zh_CN.ini b/assets/lang/zh_CN.ini
index 12b0227052..0c6796ad2d 100644
--- a/assets/lang/zh_CN.ini
+++ b/assets/lang/zh_CN.ini
@@ -91,11 +91,11 @@ Swipe = 滑动
Swipe sensitivity = 滑动灵敏度
Swipe smoothing = 滑动平滑度
Thin borders = 细边框
-Tilt control setup = 倾斜控制设置…
-Tilt Input Type = 倾斜输入类型
+Tilt control setup = 设置重力感应…
+Tilt Input Type = 重力操作模式
Tilt Sensitivity along X axis = 沿X轴倾斜灵敏度
Tilt Sensitivity along Y axis = 沿Y轴倾斜灵敏度
-To Calibrate = 以您喜欢的角度握住设备,然后按“校准”。
+To Calibrate = 以喜欢的角度握住设备,然后按“校准”。
Toggle mode = 开关模式(只需按一次)
Touch Control Visibility = 显示的按键
Use custom right analog = 自定义右摇杆用途
@@ -1089,6 +1089,7 @@ AVI Dump started. = AVI转储开始
AVI Dump stopped. = AVI转储停止
Cache ISO in RAM = 在内存中缓存完整ISO
Change CPU Clock = 修改PSP的CPU频率(不稳定)
+Rewind Snapshot Interval = 倒带快照间隔
Color Tint = 颜色色调
Color Saturation = 饱和度
Error: load undo state is from a different game = 错误:撤回的即时存档是来自不同游戏的
@@ -1124,7 +1125,7 @@ Failed to save state. Error in the file system. = 无法保存即时存档。文
Fast (lag on slow storage) = 快速模式(存储低速时有延迟)
Fast Memory = 快速内存(不稳定)
Force real clock sync (slower, less lag) = 强制同步实际时钟(降低延迟,很慢)
-seconds, 0:off = 秒, 0=关
+seconds, 0:off = 每n秒,0=不回档
Games list settings = 游戏列表设置
General = 常规设置
Grid icon size = 图标方格尺寸
@@ -1146,17 +1147,17 @@ Not a PSP game = 这不是一个PSP游戏
Off = 关闭
Oldest Save = 最旧的即时存档
Path does not exist! = 路径不存在!
-PSP Memory Stick = PSP储存
-PSP Model = PSP机型
-PSP Settings = PSP设置
+PSP Memory Stick = PSP 储存
+PSP Model = PSP 机型
+PSP Settings = PSP 设置
PSP-1000 = PSP-1000
PSP-2000/3000 = PSP-2000/3000
Recent games = 最近的游戏
Record Audio = 录制音频
Record Display = 录制视频
Reset Recording on Save/Load State = 保存/载入存档时重置录制
-Restore Default Settings = 恢复默认PPSSPP设置
-Rewind Snapshot Frequency = 倒带存档频率
+Restore Default Settings = 恢复默认 PPSSPP 设置
+Rewind Snapshot Frequency = 倒带快照频率
Save path in installed.txt = 记忆棒目录使用"installed.txt"
Save path in My Documents = 记忆棒目录使用"我的文档"
Savestate Slot = 即时存档插槽
diff --git a/build.gradle b/build.gradle
index d9fc3ebd95..4bf0701175 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,7 @@ buildscript {
mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:7.3.1'
+ classpath 'com.android.tools.build:gradle:7.4.2'
}
}
diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt
index 8205fe4054..e2b0f44a80 100644
--- a/ext/CMakeLists.txt
+++ b/ext/CMakeLists.txt
@@ -22,7 +22,7 @@ endif()
# This works around a bug in cpu_features when ${CMAKE_BINARY_DIR} != ${CMAKE_CURRENT_BINRARY_DIR}.
# We also disable the list_cpu_features binary.
-add_subdirectory(cmake/cpu_features)
+add_subdirectory(cmake/cpu_features EXCLUDE_FROM_ALL)
set(SKIP_GLSLANG_INSTALL ON CACHE BOOL "" FORCE)
set(ENABLE_GLSLANG_INSTALL OFF)
diff --git a/ext/SPIRV-Cross b/ext/SPIRV-Cross
index c77b09b57c..4212eef67e 160000
--- a/ext/SPIRV-Cross
+++ b/ext/SPIRV-Cross
@@ -1 +1 @@
-Subproject commit c77b09b57c27837dc2d41aa371ed3d236ce9ce47
+Subproject commit 4212eef67ed0ca048cb726a6767185504e7695e5
diff --git a/ext/SPIRV-Cross.vcxproj b/ext/SPIRV-Cross.vcxproj
index b6369489d7..467cb84cf1 100644
--- a/ext/SPIRV-Cross.vcxproj
+++ b/ext/SPIRV-Cross.vcxproj
@@ -240,6 +240,7 @@
false
true
ProgramDatabase
+ StreamingSIMDExtensions2
Windows
diff --git a/ext/cpu_features.vcxproj b/ext/cpu_features.vcxproj
index 0588cb55a9..a0eddbd869 100644
--- a/ext/cpu_features.vcxproj
+++ b/ext/cpu_features.vcxproj
@@ -190,7 +190,7 @@
Level3
- MaxSpeed
+ MinSpace
true
true
MultiThreaded
@@ -198,6 +198,9 @@
stdcpp17
cpu_features/include
STACK_LINE_READER_BUFFER_SIZE=1024;%(PreprocessorDefinitions)
+ false
+ Size
+ true
Windows
@@ -208,7 +211,7 @@
Level3
- MaxSpeed
+ MinSpace
true
true
MultiThreaded
@@ -216,6 +219,9 @@
stdcpp17
cpu_features/include
STACK_LINE_READER_BUFFER_SIZE=1024;%(PreprocessorDefinitions)
+ false
+ Size
+ true
Windows
@@ -226,7 +232,7 @@
Level3
- MaxSpeed
+ MinSpace
true
true
MultiThreaded
@@ -234,6 +240,9 @@
stdcpp17
cpu_features/include
STACK_LINE_READER_BUFFER_SIZE=1024;%(PreprocessorDefinitions)
+ false
+ Size
+ true
Windows
@@ -300,7 +309,7 @@
Level3
- MaxSpeed
+ MinSpace
true
true
MultiThreaded
@@ -308,6 +317,10 @@
stdcpp17
cpu_features/include
STACK_LINE_READER_BUFFER_SIZE=1024;%(PreprocessorDefinitions)
+ false
+ Size
+ StreamingSIMDExtensions2
+ true
Windows
diff --git a/ext/discord-rpc-build/discord-rpc.vcxproj b/ext/discord-rpc-build/discord-rpc.vcxproj
index 5fc9b0f697..e1b7c7d435 100644
--- a/ext/discord-rpc-build/discord-rpc.vcxproj
+++ b/ext/discord-rpc-build/discord-rpc.vcxproj
@@ -178,7 +178,7 @@
Level3
- MaxSpeed
+ MinSpace
true
true
NDEBUG;_LIB;%(PreprocessorDefinitions)
@@ -189,6 +189,7 @@
false
false
ProgramDatabase
+ Size
Windows
@@ -200,7 +201,7 @@
Level3
- MaxSpeed
+ MinSpace
true
true
NDEBUG;_LIB;%(PreprocessorDefinitions)
@@ -211,6 +212,7 @@
false
false
ProgramDatabase
+ Size
Windows
@@ -222,7 +224,7 @@
Level3
- MaxSpeed
+ MinSpace
true
true
NDEBUG;_LIB;%(PreprocessorDefinitions)
@@ -233,6 +235,7 @@
false
false
ProgramDatabase
+ Size
Windows
@@ -308,7 +311,7 @@
Level3
- MaxSpeed
+ MinSpace
true
true
WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
@@ -318,6 +321,8 @@
true
false
ProgramDatabase
+ Size
+ StreamingSIMDExtensions2
Windows
diff --git a/ext/glslang.vcxproj b/ext/glslang.vcxproj
index 6d8e742a70..2accb51d6e 100644
--- a/ext/glslang.vcxproj
+++ b/ext/glslang.vcxproj
@@ -222,6 +222,8 @@
false
true
ProgramDatabase
+ true
+ StreamingSIMDExtensions2
Windows
@@ -245,6 +247,7 @@
true
false
ProgramDatabase
+ true
Windows
@@ -268,6 +271,7 @@
true
false
ProgramDatabase
+ true
Windows
@@ -291,6 +295,7 @@
true
false
ProgramDatabase
+ true
Windows
diff --git a/ext/libarmips.vcxproj b/ext/libarmips.vcxproj
index fa5fa59c2c..47ed57ae3c 100644
--- a/ext/libarmips.vcxproj
+++ b/ext/libarmips.vcxproj
@@ -395,7 +395,7 @@
Level3
- MaxSpeed
+ MinSpace
true
true
WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;ARMIPS_USE_STD_FILESYSTEM;%(PreprocessorDefinitions)
@@ -405,6 +405,8 @@
false
ProgramDatabase
stdcpp17
+ Size
+ StreamingSIMDExtensions2
Windows
@@ -416,7 +418,7 @@
Level3
- MaxSpeed
+ MinSpace
true
true
WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;ARMIPS_USE_STD_FILESYSTEM;%(PreprocessorDefinitions)
@@ -428,6 +430,7 @@
false
ProgramDatabase
stdcpp17
+ Size
Windows
@@ -439,7 +442,7 @@
Level3
- MaxSpeed
+ MinSpace
true
true
WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;ARMIPS_USE_STD_FILESYSTEM;%(PreprocessorDefinitions)
@@ -451,6 +454,7 @@
false
ProgramDatabase
stdcpp17
+ Size
Windows
@@ -462,7 +466,7 @@
Level3
- MaxSpeed
+ MinSpace
true
true
WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;ARMIPS_USE_STD_FILESYSTEM;%(PreprocessorDefinitions)
@@ -474,6 +478,7 @@
false
ProgramDatabase
stdcpp17
+ Size
Windows
diff --git a/ext/libzstd.vcxproj b/ext/libzstd.vcxproj
index 68dadeded9..bb93a9b3f8 100644
--- a/ext/libzstd.vcxproj
+++ b/ext/libzstd.vcxproj
@@ -313,6 +313,7 @@
Speed
true
false
+ StreamingSIMDExtensions2
Windows
diff --git a/ext/miniupnpc.vcxproj b/ext/miniupnpc.vcxproj
index ee83b4495c..f69e726242 100644
--- a/ext/miniupnpc.vcxproj
+++ b/ext/miniupnpc.vcxproj
@@ -287,6 +287,7 @@ cd..\..\..
true
false
MultiThreaded
+ StreamingSIMDExtensions2
Windows
@@ -320,6 +321,7 @@ cd..\..\..
MultiThreaded
false
false
+ false
Windows
@@ -412,6 +414,7 @@ cd..\..\..
true
false
false
+ true
iphlpapi.lib
diff --git a/ext/openxr/openxr.h b/ext/openxr/openxr.h
index 2e4dec9fe1..0e38fbc331 100644
--- a/ext/openxr/openxr.h
+++ b/ext/openxr/openxr.h
@@ -3476,6 +3476,7 @@ typedef enum XrFoveationLevelFB {
XR_FOVEATION_LEVEL_LOW_FB = 1,
XR_FOVEATION_LEVEL_MEDIUM_FB = 2,
XR_FOVEATION_LEVEL_HIGH_FB = 3,
+ XR_FOVEATION_LEVEL_HIGH_TOP_FB = 4,
XR_FOVEATION_LEVEL_MAX_ENUM_FB = 0x7FFFFFFF
} XrFoveationLevelFB;
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 86463708b7..b9eead5b1f 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,6 +3,6 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
android.useAndroidX=true
android.enableJetifier=true
diff --git a/headless/Headless.cpp b/headless/Headless.cpp
index fa63a489e1..9f9da25825 100644
--- a/headless/Headless.cpp
+++ b/headless/Headless.cpp
@@ -24,7 +24,8 @@
#endif
#include "Common/CPUDetect.h"
#include "Common/File/VFS/VFS.h"
-#include "Common/File/VFS/AssetReader.h"
+#include "Common/File/VFS/ZipFileReader.h"
+#include "Common/File/VFS/DirectoryReader.h"
#include "Common/File/FileUtil.h"
#include "Common/GraphicsContext.h"
#include "Common/TimeUtil.h"
@@ -103,7 +104,7 @@ int System_GetPropertyInt(SystemProperty prop) {
return -1;
}
float System_GetPropertyFloat(SystemProperty prop) { return -1.0f; }
-bool System_GetPropertyBool(SystemProperty prop) {
+bool System_GetPropertyBool(SystemProperty prop) {
switch (prop) {
case SYSPROP_CAN_JIT:
return true;
@@ -482,13 +483,13 @@ int main(int argc, const char* argv[])
#if PPSSPP_PLATFORM(ANDROID)
// For some reason the debugger installs it with this name?
if (File::Exists(Path("/data/app/org.ppsspp.ppsspp-2.apk"))) {
- VFSRegister("", new ZipAssetReader("/data/app/org.ppsspp.ppsspp-2.apk", "assets/"));
+ g_VFS.Register("", ZipFileReader::Create(Path("/data/app/org.ppsspp.ppsspp-2.apk"), "assets/"));
}
if (File::Exists(Path("/data/app/org.ppsspp.ppsspp.apk"))) {
- VFSRegister("", new ZipAssetReader("/data/app/org.ppsspp.ppsspp.apk", "assets/"));
+ g_VFS.Register("", ZipFileReader::Create(Path("/data/app/org.ppsspp.ppsspp.apk"), "assets/"));
}
#elif !PPSSPP_PLATFORM(WINDOWS)
- VFSRegister("", new DirectoryAssetReader(g_Config.flash0Directory / ".."));
+ g_VFS.Register("", new DirectoryReader(g_Config.flash0Directory / ".."));
#endif
UpdateUIState(UISTATE_INGAME);
@@ -557,7 +558,7 @@ int main(int argc, const char* argv[])
host = nullptr;
headlessHost = nullptr;
- VFSShutdown();
+ g_VFS.Clear();
LogManager::Shutdown();
delete printfLogger;
diff --git a/headless/SDLHeadlessHost.cpp b/headless/SDLHeadlessHost.cpp
index 9960b01364..cd81eb2dd2 100644
--- a/headless/SDLHeadlessHost.cpp
+++ b/headless/SDLHeadlessHost.cpp
@@ -26,7 +26,7 @@
#include "Common/GPU/thin3d_create.h"
#include "Common/GPU/OpenGL/GLRenderManager.h"
#include "Common/File/VFS/VFS.h"
-#include "Common/File/VFS/AssetReader.h"
+#include "Common/File/VFS/DirectoryReader.h"
#include "Common/GraphicsContext.h"
#include "Common/TimeUtil.h"
#include "Core/Config.h"
@@ -100,9 +100,9 @@ private:
};
void SDLHeadlessHost::LoadNativeAssets() {
- VFSRegister("", new DirectoryAssetReader(Path("assets")));
- VFSRegister("", new DirectoryAssetReader(Path("")));
- VFSRegister("", new DirectoryAssetReader(Path("..")));
+ g_VFS.Register("", new DirectoryReader(Path("assets")));
+ g_VFS.Register("", new DirectoryReader(Path("")));
+ g_VFS.Register("", new DirectoryReader(Path("..")));
}
bool GLDummyGraphicsContext::InitFromRenderThread(std::string *errorMessage) {
diff --git a/headless/WindowsHeadlessHost.cpp b/headless/WindowsHeadlessHost.cpp
index 32624f000d..406f234d7d 100644
--- a/headless/WindowsHeadlessHost.cpp
+++ b/headless/WindowsHeadlessHost.cpp
@@ -23,7 +23,7 @@
#include "Common/GPU/OpenGL/GLCommon.h"
#include "Common/GPU/OpenGL/GLFeatures.h"
#include "Common/File/VFS/VFS.h"
-#include "Common/File/VFS/AssetReader.h"
+#include "Common/File/VFS/DirectoryReader.h"
#include "Common/CommonWindows.h"
#include "Common/Log.h"
@@ -68,11 +68,11 @@ HWND CreateHiddenWindow() {
void WindowsHeadlessHost::LoadNativeAssets()
{
- VFSRegister("", new DirectoryAssetReader(Path("assets")));
- VFSRegister("", new DirectoryAssetReader(Path("")));
- VFSRegister("", new DirectoryAssetReader(Path("..")));
- VFSRegister("", new DirectoryAssetReader(Path("../Windows/assets")));
- VFSRegister("", new DirectoryAssetReader(Path("../Windows")));
+ g_VFS.Register("", new DirectoryReader(Path("assets")));
+ g_VFS.Register("", new DirectoryReader(Path("")));
+ g_VFS.Register("", new DirectoryReader(Path("..")));
+ g_VFS.Register("", new DirectoryReader(Path("../Windows/assets")));
+ g_VFS.Register("", new DirectoryReader(Path("../Windows")));
}
void WindowsHeadlessHost::SendDebugOutput(const std::string &output)
diff --git a/ios/DisplayManager.mm b/ios/DisplayManager.mm
index 19f828d380..ba369e64e1 100644
--- a/ios/DisplayManager.mm
+++ b/ios/DisplayManager.mm
@@ -148,33 +148,33 @@
}
if (screen == [UIScreen mainScreen]) {
- g_dpi = (IS_IPAD() ? 200.0f : 150.0f) * scale;
+ g_display.dpi = (IS_IPAD() ? 200.0f : 150.0f) * scale;
} else {
float diagonal = sqrt(size.height * size.height + size.width * size.width);
- g_dpi = diagonal * scale * 0.1f;
+ g_display.dpi = diagonal * scale * 0.1f;
}
- g_dpi_scale_x = 240.0f / g_dpi;
- g_dpi_scale_y = 240.0f / g_dpi;
- g_dpi_scale_real_x = g_dpi_scale_x;
- g_dpi_scale_real_y = g_dpi_scale_y;
- pixel_xres = size.width * scale;
- pixel_yres = size.height * scale;
+ g_display.dpi_scale_x = 240.0f / g_display.dpi;
+ g_display.dpi_scale_y = 240.0f / g_display.dpi;
+ g_display.dpi_scale_real_x = g_display.dpi_scale_x;
+ g_display.dpi_scale_real_y = g_display.dpi_scale_y;
+ g_display.pixel_xres = size.width * scale;
+ g_display.pixel_yres = size.height * scale;
- dp_xres = pixel_xres * g_dpi_scale_x;
- dp_yres = pixel_yres * g_dpi_scale_y;
+ g_display.dp_xres = g_display.pixel_xres * g_display.dpi_scale_x;
+ g_display.dp_yres = g_display.pixel_yres * g_display.dpi_scale_y;
- pixel_in_dps_x = (float)pixel_xres / (float)dp_xres;
- pixel_in_dps_y = (float)pixel_yres / (float)dp_yres;
+ g_display.pixel_in_dps_x = (float)g_display.pixel_xres / (float)g_display.dp_xres;
+ g_display.pixel_in_dps_y = (float)g_display.pixel_yres / (float)g_display.dp_yres;
[[sharedViewController view] setContentScaleFactor:scale];
// PSP native resize
- PSP_CoreParameter().pixelWidth = pixel_xres;
- PSP_CoreParameter().pixelHeight = pixel_yres;
+ PSP_CoreParameter().pixelWidth = g_display.pixel_xres;
+ PSP_CoreParameter().pixelHeight = g_display.pixel_yres;
NativeResized();
- NSLog(@"Updated display resolution: (%d, %d) @%.1fx", pixel_xres, pixel_yres, scale);
+ NSLog(@"Updated display resolution: (%d, %d) @%.1fx", g_display.pixel_xres, g_display.pixel_yres, scale);
}
@end
diff --git a/ios/PPSSPP-Info.plist b/ios/PPSSPP-Info.plist
index 55d219357c..6e72de13ff 100644
--- a/ios/PPSSPP-Info.plist
+++ b/ios/PPSSPP-Info.plist
@@ -10,8 +10,6 @@
Your camera may be used to emulate Go!Cam, a camera accessory
NSMicrophoneUsageDescription
Your microphone may be used to emulate Go!Cam/Talkman, a microphone accessory
- CFBundleDevelopmentRegion
- en
CFBundleDisplayName
PPSSPP
CFBundleExecutable
@@ -36,7 +34,7 @@
UIRequiredDeviceCapabilities
- armv7
+ arm64
UIStatusBarHidden
diff --git a/ios/PPSSPPUIApplication.mm b/ios/PPSSPPUIApplication.mm
index 2166da2406..1a25db20e1 100644
--- a/ios/PPSSPPUIApplication.mm
+++ b/ios/PPSSPPUIApplication.mm
@@ -17,7 +17,7 @@
#include "Common/System/NativeApp.h"
#include "Common/TimeUtil.h"
#include "Common/File/VFS/VFS.h"
-#include "Common/File/VFS/AssetReader.h"
+#include "Common/File/VFS/DirectoryReader.h"
#include "Common/Input/InputState.h"
#include "Common/Net/Resolve.h"
#include "Common/UI/Screen.h"
@@ -66,9 +66,9 @@
- (void)decodeKeyEvent:(NSInteger *)eventMem {
NSInteger eventType = eventMem[GSEVENT_TYPE];
NSInteger eventScanCode = eventMem[GSEVENTKEY_KEYCODE];
-
+
//NSLog(@"Got key: %d", (int)eventScanCode);
-
+
if (eventType == GSEVENT_TYPE_KEYUP) {
struct KeyInput key;
key.flags = KEY_UP;
@@ -82,13 +82,13 @@
key.deviceId = DEVICE_ID_KEYBOARD;
NativeKey(key);
}
-
+
}
- (void)handleKeyUIEvent:(UIEvent *) event {
if ([event respondsToSelector:@selector(_gsEvent)]) {
NSInteger *eventMem;
-
+
eventMem = (NSInteger *) (__bridge void*)[event performSelector:@selector(_gsEvent)];
if (eventMem) {
[self decodeKeyEvent:eventMem];
@@ -100,7 +100,7 @@
[super sendEvent:event];
if ([event respondsToSelector:@selector(_gsEvent)]) {
NSInteger *eventMem;
-
+
eventMem = (NSInteger *) (__bridge void*)[event performSelector:@selector(_gsEvent)];
if (eventMem) {
[self decodeKeyEvent:eventMem];
diff --git a/ios/ViewController.mm b/ios/ViewController.mm
index 74852291d4..8e30578dec 100644
--- a/ios/ViewController.mm
+++ b/ios/ViewController.mm
@@ -200,8 +200,8 @@ static LocationHelper *locationHelper;
graphicsContext->ThreadStart();
- dp_xscale = (float)dp_xres / (float)pixel_xres;
- dp_yscale = (float)dp_yres / (float)pixel_yres;
+ dp_xscale = (float)g_display.dp_xres / (float)g_display.pixel_xres;
+ dp_yscale = (float)g_display.dp_yres / (float)g_display.pixel_yres;
/*self.iCadeView = [[iCadeReaderView alloc] init];
[self.view addSubview:self.iCadeView];
diff --git a/libretro/LibretroGraphicsContext.cpp b/libretro/LibretroGraphicsContext.cpp
index ca11400491..afd93be889 100644
--- a/libretro/LibretroGraphicsContext.cpp
+++ b/libretro/LibretroGraphicsContext.cpp
@@ -58,7 +58,7 @@ void LibretroHWRenderContext::ContextReset() {
GotBackbuffer();
if (gpu) {
- gpu->DeviceRestore();
+ gpu->DeviceRestore(draw_);
}
}
diff --git a/libretro/Makefile.common b/libretro/Makefile.common
index e734a43415..67149d94d4 100644
--- a/libretro/Makefile.common
+++ b/libretro/Makefile.common
@@ -269,7 +269,8 @@ SOURCES_CXX += \
$(COMMONDIR)/Data/Text/Parsers.cpp \
$(COMMONDIR)/Data/Text/WrapText.cpp \
$(COMMONDIR)/File/VFS/VFS.cpp \
- $(COMMONDIR)/File/VFS/AssetReader.cpp \
+ $(COMMONDIR)/File/VFS/DirectoryReader.cpp \
+ $(COMMONDIR)/File/VFS/ZipFileReader.cpp \
$(COMMONDIR)/File/AndroidStorage.cpp \
$(COMMONDIR)/File/DiskFree.cpp \
$(COMMONDIR)/File/Path.cpp \
@@ -385,6 +386,8 @@ SOURCES_CXX += \
$(GPUCOMMONDIR)/IndexGenerator.cpp \
$(GPUCOMMONDIR)/TextureDecoder.cpp \
$(GPUCOMMONDIR)/PostShader.cpp \
+ $(GPUCOMMONDIR)/TextureReplacer.cpp \
+ $(GPUCOMMONDIR)/ReplacedTexture.cpp \
$(COMMONDIR)/Data/Convert/ColorConv.cpp \
$(GPUDIR)/Debugger/Breakpoints.cpp \
$(GPUDIR)/Debugger/Debugger.cpp \
@@ -406,6 +409,7 @@ SOURCES_CXX += \
$(GPUDIR)/GeConstants.cpp \
$(GPUDIR)/GeDisasm.cpp \
$(GPUDIR)/GPUCommon.cpp \
+ $(GPUDIR)/GPUCommonHW.cpp \
$(GPUDIR)/GPU.cpp \
$(GPUDIR)/GPUState.cpp \
$(GPUDIR)/Math3D.cpp \
@@ -493,7 +497,6 @@ SOURCES_CXX += \
$(COREDIR)/AVIDump.cpp \
$(COREDIR)/Config.cpp \
$(COREDIR)/ControlMapper.cpp \
- $(COREDIR)/TextureReplacer.cpp \
$(COREDIR)/Core.cpp \
$(COREDIR)/WaveFile.cpp \
$(COREDIR)/KeyMap.cpp \
@@ -817,7 +820,7 @@ SOURCES_CXX += \
$(COMMONDIR)/GPU/D3D9/thin3d_d3d9.cpp \
$(COMMONDIR)/GPU/D3D11/D3D11Loader.cpp \
$(COMMONDIR)/GPU/D3D11/thin3d_d3d11.cpp
-
+
INCFLAGS += -I$(CORE_DIR)/dx9sdk/Include -I$(CORE_DIR)/dx9sdk/Include/DX11
endif
diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp
index a5909da4ae..6bc6de0804 100644
--- a/libretro/libretro.cpp
+++ b/libretro/libretro.cpp
@@ -21,7 +21,7 @@
#include "Common/Thread/ThreadUtil.h"
#include "Common/Thread/ThreadManager.h"
#include "Common/File/VFS/VFS.h"
-#include "Common/File/VFS/AssetReader.h"
+#include "Common/File/VFS/DirectoryReader.h"
#include "Common/Data/Text/I18n.h"
#include "Common/StringUtils.h"
@@ -1284,7 +1284,7 @@ void retro_init(void)
g_Config.bEnableNetworkChat = false;
g_Config.bDiscordPresence = false;
- VFSRegister("", new DirectoryAssetReader(retro_base_dir));
+ g_VFS.Register("", new DirectoryReader(retro_base_dir));
host = new LibretroHost();
}
@@ -1486,7 +1486,7 @@ void retro_unload_game(void)
Libretro::EmuThreadStop();
PSP_Shutdown();
- VFSShutdown();
+ g_VFS.Clear();
delete ctx;
ctx = nullptr;
@@ -1561,14 +1561,14 @@ static void retro_input(void)
float y_left = input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y) / -32767.0f;
float x_right = input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X) / 32767.0f;
float y_right = input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y) / -32767.0f;
-
+
__CtrlSetAnalogXY(CTRL_STICK_LEFT, x_left, y_left);
__CtrlSetAnalogXY(CTRL_STICK_RIGHT, x_right, y_right);
-
+
// Analog circle vs square gate compensation
// copied from ControlMapper.cpp's ConvertAnalogStick function
const bool isCircular = g_Config.bAnalogIsCircular;
-
+
float norm = std::max(fabsf(x_left), fabsf(y_left));
if (norm == 0.0f)
@@ -1585,7 +1585,7 @@ static void retro_input(void)
float mappedNorm = norm;
x_left = std::clamp(x_left / norm * mappedNorm, -1.0f, 1.0f);
y_left = std::clamp(y_left / norm * mappedNorm, -1.0f, 1.0f);
-
+
__CtrlSetAnalogXY(CTRL_STICK_LEFT, x_left, y_left);
__CtrlSetAnalogXY(CTRL_STICK_RIGHT, x_right, y_right);
}
diff --git a/unittest/TestVertexJit.cpp b/unittest/TestVertexJit.cpp
index 12dad2f5aa..e759d64444 100644
--- a/unittest/TestVertexJit.cpp
+++ b/unittest/TestVertexJit.cpp
@@ -38,9 +38,6 @@ public:
dst_ = new u8[BUFFER_SIZE];
cache_ = new VertexDecoderJitCache();
- g_Config.bVertexDecoderJit = true;
- // Required for jit to be enabled.
- g_Config.iCpuCore = (int)CPUCore::JIT;
gstate_c.uv.uScale = 1.0f;
gstate_c.uv.vScale = 1.0f;
}
diff --git a/unittest/UnitTests.vcxproj b/unittest/UnitTests.vcxproj
index 057c5fe52b..bd29c69cd0 100644
--- a/unittest/UnitTests.vcxproj
+++ b/unittest/UnitTests.vcxproj
@@ -271,6 +271,7 @@
false
MultiThreaded
ProgramDatabase
+ StreamingSIMDExtensions2
Console