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