Compare commits

..

97 Commits

Author SHA1 Message Date
Nekotekina d7e72797a8 Version 0.0.3 2017-07-20 18:05:34 +03:00
Nekotekina 0dfd2eadc1 Travis: do not zip 2017-07-20 18:02:26 +03:00
Nekotekina 291ec1eeb2 SPU recompiler: minor optimization 2017-07-20 17:22:09 +03:00
Nekotekina b24eb621ae Use RTM instructions (skylake+) 2017-07-20 17:22:09 +03:00
Nekotekina 0fa148e65e Improve CPU feature check
Damn exit on SSSE3 failure
Check AVX for Intel processors
2017-07-20 17:22:09 +03:00
Talkashie 3f6b24d33a Correct typo
No classes or names or any of that poop are being changed here, only a text string.
2017-07-20 15:43:24 +03:00
Danila Malyutin 9fee2ebeb5 Enable optimizations on travis 2017-07-20 01:17:51 +03:00
kd-11 99828a8f15 spu: Clean up asmjit - avoid touching the shared db whenever possible
- Gets around the locking issues when fetching from the shared db
2017-07-19 23:28:33 +03:00
kd-11 2526626646 rsx: Surface cache bug fixes
- Properly handle data 'transfer' when recycling frame buffer images
- Clear 'recycled' surfaces before use
2017-07-19 23:28:33 +03:00
kd-11 582913dc31 spu: Simplify watchdog design (PC is purely HLE and occupies SPU code kernel space only, max 256K) 2017-07-19 23:28:33 +03:00
kd-11 94c1b74a17 fix build; restore asmjit reader_lock for now 2017-07-19 23:28:33 +03:00
kd-11 cbd1b28d0d spu: Add polling loop detection and clean up channel access contention code
- spus run a tight gpu-style kernel with no multitasking on the cores themselves
-- this does not map well to PC processor cores because they never sleep even when doing nothing
-- the poll detection hack tries to find a good place to insert a scheduler yield
-- RdDec is a good spot as it signifies the spu kernel is waiting on a timer
2017-07-19 23:28:33 +03:00
kd-11 05ffb50037 vk/rsx: Bug fixes and improvements
- Improvements to framebuffer usage; Avoid creating new resources every frame
- Handle null fragment program properly
- Collect vertex upload statistics

- vk: Pre-initialize 'unused' varying registers in the vertex shader in case it gets matched with a fs that consumes it
 -- Fixes a crash about fog_c not being declared

gl/dx12/vk: Handle null fragment program

- cleanup - use yield semantic instead of sleep(0) as yield is more cross-platform
 -- sleep(0) is a windows specific scheduler hint
2017-07-19 23:28:33 +03:00
kd-11 72e13ddeb2 spu: Implement concurrent instruction execution watchdog for wrch
- Delays threads by a predetermined amount to 'desync' spurs kernels.
  Largely reduces lock contention issues as well as making spurs kernels
  play nice with reservations
- Also reduces number of lost notifications (SPU_EVENT_LR)
2017-07-19 23:28:33 +03:00
kd-11 78f09d7645 asmjit: Minimal locking when reading, also only lock when actually writing to the db 2017-07-19 23:28:33 +03:00
kd-11 f69121116a rsx/vk: Optimize framebuffer lifetime management
- Significant gains due to avoiding aggressive create-delete cycles every frame
2017-07-19 23:28:33 +03:00
RipleyTom 0136215ef1 Minor sceNpBasicGetEvent Fix 2017-07-19 21:41:37 +03:00
Megamouse ab534ac55d main_window fixerinno
remove sinful toolbar sorcery
2017-07-19 21:16:13 +03:00
Megamouse 67bbd59924 debugger_frame fixerinno
delete zombie dialog
clear breakpoints properly
2017-07-19 21:16:13 +03:00
RipleyTom f0b1a587aa Implements deadzone for xinput 2017-07-19 20:35:12 +03:00
Megamouse ae8f858c56 settings_dialog: get rid of string duplication
use enum to dictate button id
2017-07-19 17:40:27 +03:00
Dangles91 7426eb285f Fixes for save_op_get_list_item
Only return data for dir and bind where requested. Some games like Akiba's Trip call this function but don't ask for any data back.
2017-07-18 15:22:49 +03:00
Nekotekina f91f2e3e6d Patch: add floating point support
Also count applied entries
2017-07-17 18:36:54 +03:00
Nekotekina e39ee10105 Patch system improved
SPU patch rewritten
PPU patch implemented
2017-07-17 16:49:46 +03:00
Nekotekina 2ef2f0f63b PPU LLVM: simplify module loading 2017-07-17 16:49:46 +03:00
Nekotekina e875c91121 Restore timeBeginPeriod 2017-07-17 16:49:46 +03:00
Dangles 6610abcd5f Minor changes for save data utility (#3005) 2017-07-16 19:10:45 +03:00
Megamouse aed9b31294 add system_info.h (#2985)
add system info to log
add SSSE3 Error message to main_window
2017-07-16 17:36:38 +03:00
Zion Nimchuk 6597eb27c7 Fix PIE being on by default 2017-07-16 16:59:46 +03:00
Megamouse 035a39a9a8 GUI: minor figgcess (#3010)
* emulator tab: minor layout adjustment

* tool bar: adjust size dynamically for hidpi

* gamelist tool bar: adjust size dynamically for hidpi

* gamelist search bar: adjust style

* move game_list.h into rpcs3qt

* hide game data by default
2017-07-15 21:22:24 +03:00
Learath2 9c547d5eef Fix bug with std::stof being locale-dependant (#3012) 2017-07-15 03:38:10 +03:00
Learath2 504fa5ffda Add version to install firmware dialog (#2958) 2017-07-14 18:34:05 +03:00
Megamouse ad66dbfd0b Add game window resize on boot (#3000) 2017-07-14 18:10:38 +03:00
Megamouse 0adb579736 rename controls to keyboard 2017-07-14 17:45:47 +03:00
Megamouse d4c83e5dd2 Settings: fix cameraBox 2017-07-14 17:45:47 +03:00
Megamouse 821a8c6e65 settings_dialog: add icon hints to color buttons 2017-07-14 17:20:41 +03:00
Megamouse ef60809219 move colorizedIcon to gui_settings 2017-07-14 17:20:41 +03:00
Megamouse a21ed06d27 Icons (blue): fix inconsistent colors 2017-07-14 17:20:41 +03:00
Megamouse 97f59405aa game_list_frame: repaint tool icons 2017-07-14 17:20:41 +03:00
Megamouse b586bd3b10 gui_settings: add gamelist tool icon color 2017-07-14 17:20:41 +03:00
Megamouse c617b17037 settings_dialog: add color picker for gamelist tool icons 2017-07-14 17:20:41 +03:00
Megamouse 73bbfcb246 main_window: repaint tool icons 2017-07-14 17:20:41 +03:00
Megamouse cfa7d04c49 settings_dialog: add color picker for main window tool icons 2017-07-14 17:20:41 +03:00
Megamouse fb191693d1 gui_settings: add tool icon color 2017-07-14 17:20:41 +03:00
Megamouse 743a19027a game_list_frame: add method colorizedIcons 2017-07-14 17:20:41 +03:00
Robbie ced539579e Murdering a wx zombie 2017-07-14 14:20:07 +03:00
Robbie 225af34ce9 For the Neko 2017-07-14 14:20:07 +03:00
Robbie eb80b7ec34 Small main_window refactoring. Fixed one of the guiconfig crashes too somehow. 2017-07-14 14:20:07 +03:00
Talkashie 3df960bb52 Fix various typos and capitalisation inconsistencies.
also Jarves please implement sysutils
2017-07-14 13:54:13 +03:00
Nekotekina 25fcde9507 Rearrange /dev_bdvd mounting logic
Prevent booting patches without /dev_bdvd
Prevent booting with foreign /dev_bdvd
2017-07-14 03:39:22 +03:00
Nekotekina d8abe75526 Improved sprx boot (for devs only) 2017-07-14 01:47:00 +03:00
Nekotekina 15fe8f1c51 Fix cmdline start 2017-07-14 01:47:00 +03:00
scribam ce7b55871b Add sceNp2* functions 2017-07-14 01:46:07 +03:00
scribam 9d8fa28dd9 Add sceNp* functions 2017-07-14 01:46:07 +03:00
scribam 3a3e9770f3 Add cellHttp* functions 2017-07-14 01:46:07 +03:00
scribam 2d037fa130 Remove "#pragma once" directive in a cpp file 2017-07-14 01:46:07 +03:00
Robbie ab595d2b95 Improve Save Manager (#2951)
* Add the save icons to the save data entry and manager.

* Simplify code slightly since I have an else now so no need for == false

* Move the icon to the top of the list because it looks better.  Remove redundant settitle.

* Fix size.  It's a bit forced but there wasn't any better way as far as I could see on stack overflow.

Also, add an error dialog if you have no entries.

Simplify the logic slightly for the selected since with the no data case handled, I can make more assumptions about the return value.

* save_data_utility: fix dialog sizes

* CELL_OK

* Retcon dialog to instead be error in log.

* Dangle92 and I had some fun. Everything should be good now.

* In dangle's code he disabled the icon, in mine I hide it if there is nothing. Having both isn't needed.  Yay merges resulting in doing stupid things.

* Fix leek

* Default size to zero for sanity. Shared pointer is fine handling null (tested with disgaea and renaming icon file)

* Simplifying. Thanks for review and advice all
2017-07-13 18:38:13 +03:00
Megamouse e8ba5876ce clean up some unused / redundant includes 2017-07-13 16:38:50 +03:00
Megamouse 2cd5f63284 game_list: enable deselection + fix entry selection 2017-07-13 16:38:50 +03:00
RipleyTom d410494a7d Fixes pkg overwriting files without the PKG_FILE_ENTRY_OVERWRITE flag 2017-07-13 15:43:13 +03:00
Robbie dcfe8e1abd fixz (#2996)
Patch crash regression in game grid
2017-07-13 04:05:29 +01:00
Nekotekina 7702eb2fa7 PPU: clean linkage info 2017-07-12 21:29:09 +03:00
Megamouse bb563b3eb7 minor menu fix 2017-07-12 21:00:13 +03:00
Nekotekina 4913cac24f Refresh game list after booting 2017-07-12 19:41:33 +03:00
Nekotekina 113b937263 Fix moving game dir 2017-07-12 19:35:46 +03:00
Nekotekina a5c431c2b7 _lv2prx mutex implemented 2017-07-12 19:11:51 +03:00
Nekotekina 5ba23ac4c4 sys_lwmutex_locker aux class 2017-07-12 19:09:53 +03:00
Nekotekina f7472d59aa GUI: fix recent entry duplication 2017-07-12 18:16:09 +03:00
Nekotekina 3cd4256b9e Fill game list from all locations 2017-07-12 18:16:09 +03:00
Nekotekina 08e9400870 Improve booting disc games
Store disc locations for disc games
Create /dev_hdd0/disc/ directory
Move disc games from /dev_hdd0/game/ to /disc/ automatically
Load disc game patches automatically
2017-07-12 16:38:19 +03:00
Nekotekina 420bfef214 Cleaning after PoorRequest 2017-07-12 14:07:38 +03:00
Nekotekina ae265f7586 GUI: Disable poorly designed limitations 2017-07-12 14:00:38 +03:00
Nekotekina ff53ff3bbf Force HLE for net-related libraries 2017-07-12 14:00:38 +03:00
Nekotekina 4a512694d9 Implemented _sys_memchr 2017-07-12 14:00:38 +03:00
Nekotekina 8202352452 Do not load sprx twice 2017-07-12 14:00:38 +03:00
Nekotekina 73a2a937c4 PPU LLVM: reuse loaded executables 2017-07-12 14:00:38 +03:00
Nekotekina a51f82c949 GUI: add supporters 2017-07-12 14:00:38 +03:00
Nekotekina 3278062c29 PPU: load only libsysmodule.sprx 2017-07-12 14:00:38 +03:00
Nekotekina 74f2be7307 PPU: free prx segments 2017-07-12 14:00:38 +03:00
Nekotekina 0ee454f44b vm: decommit by exec_addr 2017-07-12 14:00:38 +03:00
Nekotekina 9a38d63661 Store sys_spu_image value 2017-07-12 14:00:38 +03:00
Nekotekina bab537c7e2 PPU LLVM: unuse FP_SAT_OP 2017-07-12 14:00:38 +03:00
Robbie a426d32a36 Search for threads. 2017-07-12 04:56:07 +03:00
Robbie 9403948ce3 Disable remove custom config if no custom config exists. 2017-07-12 03:19:24 +03:00
Robbie 0405b860c6 Add $(EmulatorDir) to VFS dialog 2017-07-12 03:19:24 +03:00
Robbie 83df572604 Fix a couple crashes 2017-07-12 03:19:24 +03:00
Robbie 0698136c63 Add ui_*.h to gitignore 2017-07-12 03:19:24 +03:00
Megamouse 67f1fa086d debugger_frame: transfer capture button from main_window menu
and clean up some unused actions in main_window.ui
2017-07-12 00:56:53 +01:00
Megamouse 06f6ac66fa debugger_frame: remove pause button
and move its functionality to run button
2017-07-12 00:56:53 +01:00
RipleyTom 34709eb399 Fix Stswi instruction 2017-07-10 18:42:02 +03:00
scribam 5c60a99cc4 Check if the pth is a valid directory before to look for icons. 2017-07-10 17:39:45 +03:00
Robbie cea0ff4598 Fix VFS default button (#2975) 2017-07-10 14:43:57 +01:00
Megamouse b7aed7bbde Dagimon super mega level
add stretchToDisplayArea to settingsdialog

fix color picker and toolbar background

settingsdialog adjustments

fix tooltips + .pup

fix adapter box
2017-07-10 16:15:57 +03:00
Megamouse 1a4e1919fc Dagimon mega level
ani fixes

add color options for toolbar and game icons
2017-07-10 16:15:57 +03:00
Megamouse 457c2d364f Dagimon ultra level
gui new design: hidpi fixes

settings_dialog fix glitch

welcome dialog hdpi adjustments

about dialog hdpi adjustments

about dialog fix size

pad dialog hdpi adjustments

settings_dialog: remove SetActiveTab
2017-07-10 16:15:57 +03:00
Megamouse c9e9fcd0a3 Dagimon champion level 2017-07-10 16:15:57 +03:00
Megamouse 9f8eb88a9f Dagimon rookie level
fix lib stuff

fix build

add slider amd searchbar

disable gamelist toolbar per default

Dagimon rookie level
2017-07-10 16:15:57 +03:00
145 changed files with 2761 additions and 1365 deletions
+1 -2
View File
@@ -41,7 +41,6 @@
/Vulkan/Vulkan-build
/Vulkan/glslang-build
/wxWidgets/lib
/bin/rpcs3.ini
/bin/rpcs3.ipdb
/bin/rpcs3.iobj
@@ -56,7 +55,6 @@ rpcs3/git-version.h
# Visual Studio Files
.vs/*
*.ipch
*.vspx
*.psess
*.VC.*
@@ -93,3 +91,4 @@ rpcs3/rpcs3_*_cotire.cmake
moc_*.cpp
qrc_resources.cpp
rpcs3_automoc.cpp
ui_*.h
+3 -2
View File
@@ -8,6 +8,7 @@
[submodule "llvm"]
path = llvm
url = https://github.com/llvm-mirror/llvm
branch = release_40
[submodule "rsx_program_decompiler"]
path = rsx_program_decompiler
url = https://github.com/RPCS3/rsx_program_decompiler
@@ -16,7 +17,7 @@
url = https://github.com/Microsoft/GSL.git
[submodule "libpng"]
path = 3rdparty/libpng
url = https://github.com/Zangetsu38/libpng
url = https://github.com/RPCS3/libpng
ignore = dirty
[submodule "Vulkan/glslang"]
path = Vulkan/glslang
@@ -41,5 +42,5 @@
url = https://github.com/madler/zlib
[submodule "3rdparty/hidapi"]
path = 3rdparty/hidapi
url = https://github.com/Zangetsu38/hidapi
url = https://github.com/RPCS3/hidapi
branch = master
+1 -2
View File
@@ -87,11 +87,10 @@ before_script:
./linuxdeployqt*.AppImage ./appdir/usr/share/applications/*.desktop -bundle-non-qt-libs ;
./linuxdeployqt*.AppImage ./appdir/usr/share/applications/*.desktop -appimage ;
find ./appdir -executable -type f -exec ldd {} \; | grep " => /usr" | cut -d " " -f 2-3 | sort | uniq ;
zip -r9 rpcs3.zip ./RPCS3*.AppImage;
if [ -z "$WITHOUT_LLVM" ]; then
export LLVM="-LLVM";
fi;
curl ${UPLOAD_URL}${TRAVIS_COMMIT:0:7}-${TRAVIS_BUILD_NUMBER}${LLVM}_linux64 --upload-file rpcs3.zip;
curl ${UPLOAD_URL}${TRAVIS_COMMIT:0:7}-${TRAVIS_BUILD_NUMBER}${LLVM}_linux64 --upload-file ./RPCS3*.AppImage;
fi;
script:
+1 -1
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 2.8.12)
cmake_minimum_required(VERSION 3.0.2)
option(WITH_GDB "WITH_GDB" OFF)
option(WITHOUT_LLVM "WITHOUT_LLVM" OFF)
+6 -6
View File
@@ -21,15 +21,15 @@ If you want to contribute please take a look at the [Coding Style](https://githu
## Dependencies
### Windows
* [Visual Studio 2017](https://www.visualstudio.com/downloads/)
* [Visual C++ Redistributable Packages for Visual Studio 2017](https://go.microsoft.com/fwlink/?LinkId=746572)
* [Visual Studio 2015](https://www.visualstudio.com/en-us/downloads/download-visual-studio-vs.aspx)
* [Visual C++ Redistributable Packages for Visual Studio 2015](http://www.microsoft.com/en-us/download/details.aspx?id=48145)
* [Cmake 3.1.0+](https://www.cmake.org/download/) (required; add to PATH)
* [Python 3.3+](https://www.python.org/downloads/) (required; add to PATH)
* [Qt 5.9+](https://www.qt.io/download-open-source/) (required; add QTDIR `<QtInstallFolder>\5.9\msvc2015_64\` environment variable if you do not want to use the Visual Studio Qt Plugin)
* [Qt 5.7+](https://www.qt.io/download-open-source/) (required; add QTDIR `<QtInstallFolder>\5.7\msvc2015_64\` environment variable if you do not want to use the Visual Studio Qt Plugin)
* [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2015) (optional; see above)
### Linux
* [Qt 5.9+](https://www.qt.io/download-open-source/)
* [Qt 5.7+](https://www.qt.io/download-open-source/)
* GCC 5.1+ or Clang 3.5.0+ ([not GCC 6.1](https://github.com/RPCS3/rpcs3/issues/1691))
* Debian & Ubuntu: `sudo apt-get install cmake build-essential libasound2-dev libopenal-dev libglew-dev zlib1g-dev libedit-dev libvulkan-dev libudev-dev git qt5-default`
* Arch: `sudo pacman -S glew openal cmake llvm qt5-base`
@@ -47,10 +47,10 @@ To initialize the repository don't forget to execute `git submodule update --ini
### Configuring Qt
*If you're using Visual Studio 2017 without Qt plugin support (or simply dont want to use it):*
1) Add `QTDIR` environment variable and set it to `<QtInstallFolder>\5.9\msvc2017_64\` </br>
1) Add `QTDIR` environment variable and set it to `<QtInstallFolder>\5.7\msvc2015_64\` </br>
*If you wish to use the Visual Studio plugin for Qt:* </br>
1) Go to the Qt5 menu and edit Qt5 options. Add the path to your Qt installation with compiler e.g. `C:\Qt\5.8\msvc2015_64`. </br>
1) Go to the Qt5 menu and edit Qt5 options. Add the path to your Qt installation with compiler e.g. `C:\Qt\5.7\msvc2015_64`. </br>
2) While selecting the rpcs3qt project, go to Qt5->Project Setting and select the version you added.
### Building the projects
+39 -11
View File
@@ -12,6 +12,7 @@
#include "File.h"
#include "Log.h"
#include "mutex.h"
#include "sysinfo.h"
#include "VirtualMemory.h"
#ifdef _MSC_VER
@@ -257,11 +258,11 @@ struct MemoryManager : llvm::RTDyldMemoryManager
return RTDyldMemoryManager::registerEHFrames(addr, load_addr, size);
}
virtual void deregisterEHFrames() override
virtual void deregisterEHFrames(u8* addr, u64 load_addr, std::size_t size) override
{
LOG_ERROR(GENERAL, "deregisterEHFrames() called"); // Not expected
return RTDyldMemoryManager::deregisterEHFrames();
return RTDyldMemoryManager::deregisterEHFrames(addr, load_addr, size);
}
};
@@ -343,22 +344,30 @@ public:
LOG_SUCCESS(GENERAL, "LLVM: Created module: %s", module->getName().data());
}
std::unique_ptr<llvm::MemoryBuffer> getObject(const llvm::Module* module) override
static std::unique_ptr<llvm::MemoryBuffer> load(const std::string& path)
{
std::string name = m_path;
name.append(module->getName());
if (fs::file cached{name, fs::read})
if (fs::file cached{path, fs::read})
{
auto buf = llvm::MemoryBuffer::getNewUninitMemBuffer(cached.size());
cached.read(const_cast<char*>(buf->getBufferStart()), buf->getBufferSize());
return buf;
}
return nullptr;
}
std::unique_ptr<llvm::MemoryBuffer> getObject(const llvm::Module* module) override
{
std::string path = m_path;
path.append(module->getName());
if (auto buf = load(path))
{
LOG_SUCCESS(GENERAL, "LLVM: Loaded module: %s", module->getName().data());
return buf;
}
else
{
return nullptr;
}
return nullptr;
}
};
@@ -369,6 +378,20 @@ jit_compiler::jit_compiler(const std::unordered_map<std::string, std::uintptr_t>
if (m_cpu.empty())
{
m_cpu = llvm::sys::getHostCPUName();
if (m_cpu == "sandybridge" ||
m_cpu == "ivybridge" ||
m_cpu == "haswell" ||
m_cpu == "broadwell" ||
m_cpu == "skylake" ||
m_cpu == "skylake-avx512" ||
m_cpu == "cannonlake")
{
if (!utils::has_avx())
{
m_cpu = "nehalem";
}
}
}
std::string result;
@@ -430,6 +453,11 @@ void jit_compiler::add(std::unique_ptr<llvm::Module> module, const std::string&
}
}
void jit_compiler::add(const std::string& path)
{
m_engine->addObjectFile(std::move(llvm::object::ObjectFile::createObjectFile(*ObjectCache::load(path)).get()));
}
void jit_compiler::fin()
{
m_engine->finalizeObject();
+4 -1
View File
@@ -49,9 +49,12 @@ public:
return m_context;
}
// Add module
// Add module (path to obj cache dir)
void add(std::unique_ptr<llvm::Module> module, const std::string& path);
// Add object (path to obj file)
void add(const std::string& path);
// Finalize
void fin();
+35 -4
View File
@@ -14,9 +14,13 @@ void fmt_class_string<patch_type>::format(std::string& out, u64 arg)
case patch_type::le16: return "le16";
case patch_type::le32: return "le32";
case patch_type::le64: return "le64";
case patch_type::bef32: return "bef32";
case patch_type::bef64: return "bef64";
case patch_type::be16: return "be16";
case patch_type::be32: return "be32";
case patch_type::be64: return "be64";
case patch_type::lef32: return "lef32";
case patch_type::lef64: return "lef64";
}
return unknown;
@@ -39,23 +43,44 @@ void patch_engine::append(const std::string& patch)
u64 type64 = 0;
cfg::try_to_enum_value(&type64, &fmt_class_string<patch_type>::format, patch[0].Scalar());
struct patch info;
struct patch info{};
info.type = static_cast<patch_type>(type64);
info.offset = patch[1].as<u32>();
info.value = patch[2].as<u64>();
switch (info.type)
{
case patch_type::bef32:
case patch_type::lef32:
{
info.value_as<f32>() = patch[2].as<f32>();
break;
}
case patch_type::bef64:
case patch_type::lef64:
{
info.value_as<f64>() = patch[2].as<f64>();
break;
}
default:
{
info.value = patch[2].as<u64>();
break;
}
}
data.emplace_back(info);
}
}
}
}
void patch_engine::apply(const std::string& name, u8* dst) const
std::size_t patch_engine::apply(const std::string& name, u8* dst) const
{
const auto found = m_map.find(name);
if (found == m_map.cend())
{
return;
return 0;
}
// Apply modifications sequentially
@@ -76,11 +101,13 @@ void patch_engine::apply(const std::string& name, u8* dst) const
break;
}
case patch_type::le32:
case patch_type::lef32:
{
*reinterpret_cast<le_t<u32, 1>*>(ptr) = static_cast<u32>(p.value);
break;
}
case patch_type::le64:
case patch_type::lef64:
{
*reinterpret_cast<le_t<u64, 1>*>(ptr) = static_cast<u64>(p.value);
break;
@@ -91,15 +118,19 @@ void patch_engine::apply(const std::string& name, u8* dst) const
break;
}
case patch_type::be32:
case patch_type::bef32:
{
*reinterpret_cast<be_t<u32, 1>*>(ptr) = static_cast<u32>(p.value);
break;
}
case patch_type::be64:
case patch_type::bef64:
{
*reinterpret_cast<be_t<u64, 1>*>(ptr) = static_cast<u64>(p.value);
break;
}
}
}
return found->second.size();
}
+12 -2
View File
@@ -11,9 +11,13 @@ enum class patch_type
le16,
le32,
le64,
lef32,
lef64,
be16,
be32,
be64,
bef32,
bef64,
};
class patch_engine
@@ -23,6 +27,12 @@ class patch_engine
patch_type type;
u32 offset;
u64 value;
template <typename T>
T& value_as()
{
return *reinterpret_cast<T*>(reinterpret_cast<char*>(&value));
}
};
// Database
@@ -32,6 +42,6 @@ public:
// Load from file
void append(const std::string& path);
// Apply patch
void apply(const std::string& name, u8* dst) const;
// Apply patch (returns the number of entries applied)
std::size_t apply(const std::string& name, u8* dst) const;
};
+61
View File
@@ -0,0 +1,61 @@
#include "sysinfo.h"
#include "StrFmt.h"
#ifdef _WIN32
#include "windows.h"
#else
#include <unistd.h>
#endif
std::string utils::get_system_info()
{
std::string result;
std::string brand;
if (get_cpuid(0x80000000, 0)[0] >= 0x80000004)
{
for (u32 i = 0; i < 3; i++)
{
brand.append(reinterpret_cast<const char*>(get_cpuid(0x80000002 + i, 0).data()), 16);
}
}
else
{
brand = "Unknown CPU";
}
brand.erase(0, brand.find_first_not_of(' '));
brand.erase(brand.find_last_not_of(' ') + 1);
while (auto found = brand.find(" ") + 1)
{
brand.erase(brand.begin() + found);
}
#ifdef _WIN32
::SYSTEM_INFO sysInfo;
::GetNativeSystemInfo(&sysInfo);
::MEMORYSTATUSEX memInfo;
memInfo.dwLength = sizeof(memInfo);
::GlobalMemoryStatusEx(&memInfo);
const u32 num_proc = sysInfo.dwNumberOfProcessors;
const u64 mem_total = memInfo.ullTotalPhys;
#else
const u32 num_proc = ::sysconf(_SC_NPROCESSORS_ONLN);
const u64 mem_total = ::sysconf(_SC_PHYS_PAGES) * ::sysconf(_SC_PAGE_SIZE);
#endif
fmt::append(result, "%s | %d Threads | %.2f GiB RAM", brand, num_proc, mem_total / (1024.0f * 1024 * 1024));
if (has_avx())
{
result += " | AVX";
}
if (has_rtm())
{
result += " | TSX";
}
return result;
}
+54
View File
@@ -0,0 +1,54 @@
#pragma once
#include "types.h"
#include <string>
namespace utils
{
inline std::array<u32, 4> get_cpuid(u32 func, u32 subfunc)
{
int regs[4];
#ifdef _MSC_VER
__cpuidex(regs, func, subfunc);
#else
__asm__ volatile("cpuid" : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3]) : "a" (func), "c" (subfunc));
#endif
return {0u+regs[0], 0u+regs[1], 0u+regs[2], 0u+regs[3]};
}
inline bool has_ssse3()
{
return get_cpuid(0, 0)[0] >= 0x1 && get_cpuid(1, 0)[2] & 0x200;
}
inline bool has_avx()
{
return get_cpuid(0, 0)[0] >= 0x1 && get_cpuid(1, 0)[2] & 0x10000000;
}
inline bool has_rtm()
{
// Check RTM and MPX extensions in order to filter out TSX on Haswell CPUs
return get_cpuid(0, 0)[0] >= 0x7 && (get_cpuid(7, 0)[1] & 0x4800) == 0x4800;
}
inline bool transaction_enter()
{
while (true)
{
const auto status = _xbegin();
if (status == _XBEGIN_STARTED)
{
return true;
}
if (!(status & _XABORT_RETRY))
{
return false;
}
}
}
std::string get_system_info();
}
+1 -1
View File
@@ -19,7 +19,7 @@
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
+8 -8
View File
@@ -19,12 +19,12 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -39,20 +39,20 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<NMakeBuildCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
<NMakeBuildCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Release /m</NMakeBuildCommandLine>
<NMakeCleanCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
<NMakeCleanCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Release /m</NMakeCleanCommandLine>
<NMakeReBuildCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
<NMakeReBuildCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Release /m
</NMakeReBuildCommandLine>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<NMakeBuildCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
<NMakeBuildCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Debug /m</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
<NMakeReBuildCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Debug /m</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
<NMakeCleanCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Debug /m</NMakeCleanCommandLine>
</PropertyGroup>
<ItemDefinitionGroup>
+8 -8
View File
@@ -19,12 +19,12 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -39,24 +39,24 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<NMakeBuildCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
<NMakeBuildCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Release /m</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
<NMakeReBuildCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Release /m</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
<NMakeCleanCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Release /m</NMakeCleanCommandLine>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<NMakeBuildCommandLine>
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Debug /m
</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Debug /m
</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Debug /m
</NMakeCleanCommandLine>
</PropertyGroup>
+7 -7
View File
@@ -1,6 +1,6 @@
version: '0.0.2-{build}'
version: '0.0.3-{build}'
os: Visual Studio 2017
os: Visual Studio 2015
platform: x64
clone_folder: C:\rpcs3
clone_depth: 3
@@ -15,8 +15,8 @@ before_build:
- git submodule update --init 3rdparty/ffmpeg 3rdparty/pugixml asmjit 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers Utilities/yaml-cpp 3rdparty/cereal 3rdparty/zlib 3rdparty/hidapi
- 7z x zlib.7z -aos -oC:\rpcs3\ > null
- 7z x vulkan.7z -aos -oC:\rpcs3\Vulkan > null
- if %configuration%==Release (cmake -G "Visual Studio 15 Win64" -DZLIB_ROOT=C:/rpcs3/zlib/ -DVULKAN_PREBUILT=ON)
else (7z x llvmlibs.7z -aos -oC:\rpcs3 > null && cmake -G "Visual Studio 15 Win64" -DLLVM_DIR=C:/rpcs3/llvm_build/lib/cmake/llvm -DZLIB_ROOT=C:/rpcs3/zlib/ -DVULKAN_PREBUILT=ON)
- if %configuration%==Release (cmake -G "Visual Studio 14 Win64" -DZLIB_ROOT=C:/rpcs3/zlib/ -DVULKAN_PREBUILT=ON)
else (7z x llvmlibs.7z -aos -oC:\rpcs3 > null && cmake -G "Visual Studio 14 Win64" -DLLVM_DIR=C:/rpcs3/llvm_build/lib/cmake/llvm -DZLIB_ROOT=C:/rpcs3/zlib/ -DVULKAN_PREBUILT=ON)
build_script:
- cmake --build . --config Release -- /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
@@ -25,14 +25,14 @@ install:
- if not exist llvmlibs.7z appveyor DownloadFile "https://drive.google.com/uc?export=download&id=0B8A6NaxhQAGRY2k3Q2Yya05lcm8" -FileName llvmlibs.7z
- if not exist vulkan.7z appveyor DownloadFile "https://drive.google.com/uc?export=download&id=0B8A6NaxhQAGRaHYxV3VOS2d0a0U" -FileName vulkan.7z
- if not exist zlib.7z appveyor DownloadFile "https://drive.google.com/uc?export=download&id=0B-HVE3xvheVFX05lRFdnZlh5aUU" -FileName zlib.7z
- set QTDIR=C:\Qt\5.9\msvc2017_64
- set QTDIR=C:\Qt\5.8\msvc2015_64
- set OPENALDIR=C:\rpcs3\3rdparty\OpenAL
- set PATH=C:\Program Files (x86)\MSBuild\15.0\Bin;%QTDIR%;%PATH%
- set PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;%QTDIR%;%PATH%
- set COMMIT_SHA=%APPVEYOR_REPO_COMMIT:~0,8%
artifacts:
- path: bin
name: 'rpcs3-v0.0.2-$(Date)-$(COMMIT_SHA)_win64'
name: 'rpcs3-v0.0.3-$(Date)-$(COMMIT_SHA)_win64'
type: zip
cache:
+1 -1
View File
@@ -93,7 +93,7 @@
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
Submodule llvm updated: 80e0f20bde...4423e35117
+8 -8
View File
@@ -18,12 +18,12 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -39,30 +39,30 @@
<NMakePreprocessorDefinitions>
</NMakePreprocessorDefinitions>
<NMakeBuildCommandLine>
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Debug /m
</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Debug /m
</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Debug /m
</NMakeCleanCommandLine>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<NMakePreprocessorDefinitions />
<NMakeBuildCommandLine>
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Release /m
</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Release /m
</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Release /m
</NMakeCleanCommandLine>
</PropertyGroup>
+2 -2
View File
@@ -20,14 +20,14 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
+2 -2
View File
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.13
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asmjit", "asmjitsrc\asmjit.vcxproj", "{AC40FF01-426E-4838-A317-66354CEFAE88}"
EndProject
+19 -12
View File
@@ -3,9 +3,10 @@ cmake_minimum_required(VERSION 3.0.2)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake_modules")
set(RES_FILES "")
set(CMAKE_CXX_STANDARD 14)
include(CheckCCompilerFlag)
# Qt section
find_package(Qt5 5.9 COMPONENTS Widgets)
find_package(Qt5 5.7 COMPONENTS Widgets)
if (WIN32)
find_package(Qt5WinExtras REQUIRED)
set(RPCS3_QT_LIBS Qt5::Widgets Qt5::WinExtras)
@@ -17,8 +18,8 @@ endif()
# Let's make sure we have Qt before we continue
if (NOT Qt5Widgets_FOUND)
if (Qt5Widgets_VERSION VERSION_LESS 5.9.0)
message("Minimum supported Qt5 version is 5.9! You have version ${Qt5Widgets_VERSION} installed, please upgrade!")
if (Qt5Widgets_VERSION VERSION_LESS 5.7.0)
message("Minimum supported Qt5 version is 5.7! You have version ${Qt5Widgets_VERSION} installed, please upgrade!")
if ("${CMAKE_SYSTEM}" MATCHES "Linux")
message(FATAL_ERROR "Most distros do not provide an up-to-date version of Qt.
If you're on Ubuntu or Linux Mint, there are PPAs you can use to install an up-to-date qt5 version.
@@ -37,7 +38,7 @@ before re-running cmake")
message("CMake was unable to find Qt5!")
if (WIN32)
message(FATAL_ERROR "Make sure the QTDIR env variable has been set properly. (for example C:\\Qt\\5.9\\msvc2017_64\\)")
message(FATAL_ERROR "Make sure the QTDIR env variable has been set properly. (for example C:\\Qt\\5.8\\msvc2017_64\\)")
elseif("${CMAKE_SYSTEM}" MATCHES "Linux")
message(FATAL_ERROR "Make sure to install your distro's qt5 package!")
else()
@@ -84,9 +85,6 @@ else()
endif()
if(NOT MSVC)
if($ENV{CI})
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O1") # fix for travis gcc OoM crash. Might be fixed with the move to containers.
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions")
if(WIN32)
set(CMAKE_RC_COMPILER_INIT windres)
@@ -97,13 +95,24 @@ if(NOT MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--allow-multiple-definition")
endif()
add_compile_options(-msse -msse2 -mcx16 -mssse3)
add_compile_options(-msse -msse2 -mcx16 -mssse3 -mrtm)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# This fixes 'some' of the st11range issues. See issue #2516
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -image-base=0x10000")
endif()
# Some distros have the compilers set to use PIE by default, but RPCS3 doesn't work with PIE, so we need to disable it.
CHECK_C_COMPILER_FLAG("-no-pie" HAS_NO_PIE)
if(HAS_NO_PIE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie")
else()
CHECK_C_COMPILER_FLAG("-nopie" HAS_NO_PIE)
if(HAS_NO_PIE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -nopie")
endif()
endif()
find_package(GLEW REQUIRED)
find_package(ZLIB REQUIRED)
else()
@@ -268,12 +277,10 @@ if(NOT WIN32 AND NOT "${CMAKE_SYSTEM}" MATCHES "Linux")
set (EXCLUDE_FILES "/RSX/VK/")
endif()
# The Gui folder contains wxWidgets stuff, which we no longer want.
set (EXCLUDE_FILES ${EXCLUDE_FILES} "/Gui/")
# Ignore autogenerated moc_* files if present
set (EXCLUDE_FILES ${EXCLUDE_FILES} "moc_")
set (EXCLUDE_FILES ${EXCLUDE_FILES} "rpcs3_automoc")
set (EXCLUDE_FILES ${EXCLUDE_FILES} "qrc_resources.cpp")
foreach (TMP_PATH ${RPCS3_SRC})
foreach (EXCLUDE_PATH ${EXCLUDE_FILES})
@@ -285,7 +292,7 @@ foreach (TMP_PATH ${RPCS3_SRC})
endforeach(TMP_PATH)
# Remove the Qt moc files as part of clean, they are compiled when generating automoc
file(GLOB_RECURSE TMP_MOC "${RPCS3_SRC_DIR}/moc_*.cpp" "${RPCS3_SRC_DIR}/rpcs3_automoc.cpp")
file(GLOB_RECURSE TMP_MOC "${RPCS3_SRC_DIR}/moc_*.cpp" "${RPCS3_SRC_DIR}/rpcs3_automoc.cpp" "${RPCS3_SRC_DIR}/qrc_resources.cpp")
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${TMP_MOC}")
if (WIN32)
+6
View File
@@ -228,6 +228,12 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
const bool did_overwrite = fs::is_file(path);
if (did_overwrite && (entry.type&PKG_FILE_ENTRY_OVERWRITE) == 0)
{
LOG_NOTICE(LOADER, "Didn't overwrite %s", name);
break;
}
if (fs::file out{ path, fs::rewrite })
{
for (u64 pos = 0; pos < entry.file_size; pos += BUF_SIZE)
+1 -1
View File
@@ -31,7 +31,7 @@
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
+22 -4
View File
@@ -1,9 +1,12 @@
#include "stdafx.h"
#include "Utilities/sysinfo.h"
#include "Emu/Memory/vm.h"
#include "Emu/Cell/SPUThread.h"
#include "Emu/Cell/lv2/sys_sync.h"
#include "MFC.h"
const bool s_use_rtm = utils::has_rtm();
template <>
void fmt_class_string<MFC>::format(std::string& out, u64 arg)
{
@@ -145,10 +148,25 @@ void mfc_thread::cpu_task()
vm::reservation_acquire(cmd.eal, 128);
// Store unconditionally
vm::writer_lock lock(0);
data = to_write;
vm::reservation_update(cmd.eal, 128);
vm::notify(cmd.eal, 128);
if (s_use_rtm && utils::transaction_enter())
{
if (!vm::reader_lock{vm::try_to_lock})
{
_xabort(0);
}
data = to_write;
vm::reservation_update(cmd.eal, 128);
vm::notify(cmd.eal, 128);
_xend();
}
else
{
vm::writer_lock lock(0);
data = to_write;
vm::reservation_update(cmd.eal, 128);
vm::notify(cmd.eal, 128);
}
}
else if (cmd.cmd & MFC_LIST_MASK)
{
+35
View File
@@ -317,6 +317,24 @@ s32 cellHttpClientSetConnectionWaitStatus()
return CELL_OK;
}
s32 cellHttpClientGetConnectionWaitStatus()
{
UNIMPLEMENTED_FUNC(cellHttp);
return CELL_OK;
}
s32 cellHttpClientSetConnectionWaitTimeout()
{
UNIMPLEMENTED_FUNC(cellHttp);
return CELL_OK;
}
s32 cellHttpClientGetConnectionWaitTimeout()
{
UNIMPLEMENTED_FUNC(cellHttp);
return CELL_OK;
}
s32 cellHttpClientSetRecvTimeout()
{
UNIMPLEMENTED_FUNC(cellHttp);
@@ -641,6 +659,18 @@ s32 cellHttpTransactionGetSslId()
return CELL_OK;
}
s32 cellHttpClientSetMinSslVersion()
{
UNIMPLEMENTED_FUNC(cellHttp);
return CELL_OK;
}
s32 cellHttpClientGetMinSslVersion()
{
UNIMPLEMENTED_FUNC(cellHttp);
return CELL_OK;
}
s32 cellHttpClientSetSslVersion()
{
UNIMPLEMENTED_FUNC(cellHttp);
@@ -719,7 +749,10 @@ DECLARE(ppu_module_manager::cellHttp)("cellHttp", []()
REG_FUNC(cellHttp, cellHttpClientPollConnections);
REG_FUNC(cellHttp, cellHttpClientSetConnectionStateCallback);
REG_FUNC(cellHttp, cellHttpClientGetConnectionWaitStatus);
REG_FUNC(cellHttp, cellHttpClientSetConnectionWaitStatus);
REG_FUNC(cellHttp, cellHttpClientGetConnectionWaitTimeout);
REG_FUNC(cellHttp, cellHttpClientSetConnectionWaitTimeout);
REG_FUNC(cellHttp, cellHttpClientSetRecvTimeout);
REG_FUNC(cellHttp, cellHttpClientGetRecvTimeout);
REG_FUNC(cellHttp, cellHttpClientSetSendTimeout);
@@ -781,6 +814,8 @@ DECLARE(ppu_module_manager::cellHttp)("cellHttp", []()
REG_FUNC(cellHttp, cellHttpTransactionGetSslVersion);
REG_FUNC(cellHttp, cellHttpTransactionGetSslId);
REG_FUNC(cellHttp, cellHttpClientSetMinSslVersion);
REG_FUNC(cellHttp, cellHttpClientGetMinSslVersion);
REG_FUNC(cellHttp, cellHttpClientSetSslVersion);
REG_FUNC(cellHttp, cellHttpClientGetSslVersion);
REG_FUNC(cellHttp, cellHttpClientSetSslIdDestroyCallback);
+132 -64
View File
@@ -1,6 +1,7 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/Modules/cellSysutil.h"
#include "cellSaveData.h"
@@ -63,7 +64,6 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
PFuncFile funcFile, u32 container, u32 unknown, vm::ptr<void> userdata, u32 userId, PFuncDone funcDone)
{
// TODO: check arguments
std::unique_lock<std::mutex> lock(g_savedata_mutex, std::try_to_lock);
if (!lock)
@@ -82,6 +82,8 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
vm::ptr<CellSaveDataFileGet> fileGet = g_savedata_context.ptr(&savedata_context::fileGet);
vm::ptr<CellSaveDataFileSet> fileSet = g_savedata_context.ptr(&savedata_context::fileSet);
//TODO: get current user ID
// userId(0) = CELL_SYSUTIL_USERID_CURRENT
// path of the specified user (00000001 by default)
const std::string& base_dir = vfs::get(fmt::format("/dev_hdd0/home/%08u/savedata/", userId ? userId : 1u));
@@ -100,6 +102,7 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
const auto prefix_list = fmt::split(setList->dirNamePrefix.get_ptr(), { "|" });
// get the saves matching the supplied prefix
for (const auto& entry : fs::dir(base_dir))
{
if (!entry.is_directory)
@@ -141,11 +144,16 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
save_entry2.atime = entry.atime;
save_entry2.mtime = entry.mtime;
save_entry2.ctime = entry.ctime;
//save_entry2.iconBuf = NULL; // TODO: Here should be the PNG buffer
//save_entry2.iconBufSize = 0; // TODO: Size of the PNG file
if (fs::is_file(base_dir + entry.name + "/ICON0.PNG"))
{
fs::file icon = fs::file(base_dir + entry.name + "/ICON0.PNG");
u32 iconSize = icon.size();
std::vector<uchar> iconData;
icon.read(iconData, iconSize);
save_entry2.iconBuf = iconData;
}
save_entry2.isNew = false;
save_entries.push_back(save_entry2);
save_entries.emplace_back(save_entry2);
}
break;
@@ -206,10 +214,19 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
if (result->result < 0)
{
//TODO: display dialog
cellSaveData.warning("savedata_op(): funcList returned < 0.");
return CELL_SAVEDATA_ERROR_CBRESULT;
}
// if the callback has returned ok, lets return OK.
// typically used at game launch when no list is actually required.
// CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM is only valid for funcFile and funcDone
if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST)
{
return CELL_OK;
}
// Clean save data list
save_entries.erase(std::remove_if(save_entries.begin(), save_entries.end(), [&listSet](const SaveDataEntry& entry) -> bool
{
@@ -224,6 +241,16 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
return true;
}), save_entries.end());
// Add any new data (not currently supported by the UI)
//if (listSet->newData)
//{
// SaveDataEntry *_saveDataEntry = new SaveDataEntry();
// _saveDataEntry->dirName = listSet->newData->dirName.get_ptr();
// save_entry.dirName = listSet->newData->dirName.get_ptr();
// save_entries.emplace_back(*_saveDataEntry);
//}
// Focus save data
s32 focused = -1;
@@ -284,6 +311,8 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
}
case CELL_SAVEDATA_FOCUSPOS_NEWDATA:
{
//TODO: If adding the new data to the save_entries vector
// to be displayed in the save mangaer UI, it should be focused here
break;
}
default:
@@ -293,10 +322,9 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
}
}
// Display Save Data List but do so asynchronously in the GUI thread. For, qTimers only work using main UI thread.
// Display Save Data List but do so asynchronously in the GUI thread.
bool hasNewData = (bool)listSet->newData; // newData
atomic_t<bool> dlg_result(false);
bool hasNewData = (bool) listSet->newData; // Are we saving?
Emu.CallAfter([&]()
{
@@ -309,28 +337,18 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
thread_ctrl::wait_for(1000);
}
// UI returns -1 for new save games
if (selected == -1)
{
if (hasNewData)
{
save_entry.dirName = listSet->newData->dirName.get_ptr();
}
else
{
// This happens if someone tries to load but there is no data selected. Some games will throw errors (Akiba) if cell_ok is returned
return CELL_CANCEL;
}
save_entry.dirName = listSet->newData->dirName.get_ptr();
}
// Cancel selected in UI
else if (selected == -2)
if (selected == -2)
{
return CELL_CANCEL;
}
if ((result->result == CELL_SAVEDATA_CBRESULT_OK_LAST) || (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM))
{
return CELL_OK;
}
}
if (funcFixed)
@@ -338,8 +356,19 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
// Fixed Callback
funcFixed(ppu, result, listGet, fixedSet);
// skip all following steps if OK_LAST
if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST)
{
return CELL_OK;
}
if (result->result < 0)
{
//TODO: Show msgDialog if required
// depends on fixedSet->option
// 0 = none
// 1 = skip confirmation dialog
cellSaveData.warning("savedata_op(): funcFixed returned < 0.");
return CELL_SAVEDATA_ERROR_CBRESULT;
}
@@ -362,10 +391,7 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
{
save_entry.dirName = fixedSet->dirName.get_ptr();
}
if ((result->result == CELL_SAVEDATA_CBRESULT_OK_LAST) || (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM))
{
return CELL_OK;
}
}
if (selected >= 0)
@@ -478,6 +504,11 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
return CELL_SAVEDATA_ERROR_CBRESULT;
}
if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST)
{
return CELL_OK;
}
if (statSet->setParam)
{
// Update PARAM.SFO
@@ -497,18 +528,20 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
{ "TITLE", psf::string(128, statSet->setParam->title) },
});
}
else if (psf.empty())
{
// setParam is NULL for new savedata: abort operation
return CELL_OK;
}
//else if (psf.empty())
//{
// // setParam is specified if something required updating.
// // Do not exit. Recreate mode will handle the rest
// //return CELL_OK;
//}
switch (const u32 mode = statSet->reCreateMode & 0xffff)
{
case CELL_SAVEDATA_RECREATE_NO:
{
cellSaveData.error("Savedata %s considered broken", save_entry.dirName);
//CELL_SAVEDATA_RECREATE_NO = overwrite and let the user know, not data is corrupt.
//cellSaveData.error("Savedata %s considered broken", save_entry.dirName);
//TODO: if this is a save, and it's not auto, then show a dialog
// fallthrough
}
@@ -520,7 +553,8 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
case CELL_SAVEDATA_RECREATE_YES:
case CELL_SAVEDATA_RECREATE_YES_RESET_OWNER:
{
// TODO?
// TODO: Only delete data, not owner info
for (const auto& entry : fs::dir(dir_path))
{
if (!entry.is_directory)
@@ -529,12 +563,13 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
}
}
//TODO: probably not deleting owner info
if (!statSet->setParam)
{
// Savedata deleted and setParam is NULL: delete directory and abort operation
if (fs::remove_dir(dir_path)) cellSaveData.error("savedata_op(): savedata directory %s deleted", save_entry.dirName);
return CELL_OK;
//return CELL_OK;
}
break;
@@ -548,16 +583,13 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
}
}
if ((result->result == CELL_SAVEDATA_CBRESULT_OK_LAST) || (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM))
{
return CELL_OK;
}
// Create save directory if necessary
if (psf.size() && save_entry.isNew && !fs::create_dir(dir_path))
{
// Let's ignore this error for now
{
cellSaveData.warning("savedata_op(): failed to create %s", dir_path);
return CELL_SAVEDATA_ERROR_ACCESS_ERROR;
}
// Enter the loop where the save files are read/created/deleted
@@ -577,9 +609,13 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST || result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM)
{
//todo: display user prompt
break;
}
//TODO: Show progress
// if it's not an auto load/save
std::string file_path;
switch (const u32 type = fileSet->fileType)
@@ -680,6 +716,57 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version,
return CELL_OK;
}
s32 static NEVER_INLINE save_op_get_list_item(vm::cptr<char> dirName, vm::ptr<CellSaveDataDirStat> dir, vm::ptr<CellSaveDataSystemFileParam> sysFileParam, vm::ptr<u32> bind, vm::ptr<u32> sizeKB, u32 userId)
{
//TODO: accurately get the current user
if (userId == 0)
{
userId = 1u;
}
std::string save_path = vfs::get(fmt::format("/dev_hdd0/home/%08u/savedata/%s/", userId, dirName.get_ptr()));
std::string sfo = save_path + "param.sfo";
if (!fs::is_dir(save_path) && !fs::is_file(sfo))
{
cellSaveData.error("cellSaveDataGetListItem(): Savedata at %s does not exist", dirName);
return CELL_SAVEDATA_ERROR_NODATA;
}
auto psf = psf::load_object(fs::file(sfo));
if (sysFileParam)
{
strcpy_trunc(sysFileParam->listParam, psf.at("SAVEDATA_LIST_PARAM").as_string());
strcpy_trunc(sysFileParam->title, psf.at("TITLE").as_string());
strcpy_trunc(sysFileParam->subTitle, psf.at("SUB_TITLE").as_string());
strcpy_trunc(sysFileParam->detail, psf.at("DETAIL").as_string());
}
if (dir)
{
fs::stat_t dir_info{};
if (!fs::stat(save_path, dir_info))
{
return CELL_SAVEDATA_ERROR_INTERNAL;
}
// get file stats, namely directory
strcpy_trunc(dir->dirName, dirName.get_ptr());
dir->atime = dir_info.atime;
dir->ctime = dir_info.ctime;
dir->mtime = dir_info.mtime;
}
if (bind)
{
//TODO: Set bind in accordance to any problems
*bind = 0;
}
return CELL_OK;
}
// Functions
s32 cellSaveDataListSave2(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList,
PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
@@ -948,27 +1035,8 @@ s32 cellSaveDataFixedExport(ppu_thread& ppu, vm::cptr<char> dirName, u32 maxSize
s32 cellSaveDataGetListItem(vm::cptr<char> dirName, vm::ptr<CellSaveDataDirStat> dir, vm::ptr<CellSaveDataSystemFileParam> sysFileParam, vm::ptr<u32> bind, vm::ptr<u32> sizeKB)
{
cellSaveData.warning("cellSavaDataGetListItem(dirName=%s, dir=*0x%x, sysFileParam=*0x%x, bind=*0x%x, sizeKB=*0x%x)", dirName, dir, sysFileParam, bind, sizeKB);
std::string save_path = vfs::get(fmt::format("/dev_hdd0/home/00000001/savedata/%s/", dirName.get_ptr()));
std::string sfo = save_path + "param.sfo";
if (!fs::is_dir(save_path) && !fs::is_file(sfo))
{
cellSaveData.error("cellSaveDataGetListItem(): Savedata at %s does not exist", dirName);
return CELL_SAVEDATA_ERROR_NODATA;
}
auto psf = psf::load_object(fs::file(sfo));
if (sysFileParam)
{
strcpy_trunc(sysFileParam->listParam, psf.at("SAVEDATA_LIST_PARAM").as_string());
strcpy_trunc(sysFileParam->title, psf.at("TITLE").as_string());
strcpy_trunc(sysFileParam->subTitle, psf.at("SUB_TITLE").as_string());
strcpy_trunc(sysFileParam->detail, psf.at("DETAIL").as_string());
}
return CELL_OK;
return save_op_get_list_item(dirName, dir, sysFileParam, bind, sizeKB, 0);
}
s32 cellSaveDataUserListDelete(ppu_thread& ppu, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
@@ -1008,9 +1076,9 @@ s32 cellSaveDataUserFixedExport(ppu_thread& ppu, u32 userId, vm::cptr<char> dirN
s32 cellSaveDataUserGetListItem(u32 userId, vm::cptr<char> dirName, vm::ptr<CellSaveDataDirStat> dir, vm::ptr<CellSaveDataSystemFileParam> sysFileParam, vm::ptr<u32> bind, vm::ptr<u32> sizeKB)
{
UNIMPLEMENTED_FUNC(cellSaveData);
cellSaveData.warning("cellSavaDataGetListItem(dirName=%s, dir=*0x%x, sysFileParam=*0x%x, bind=*0x%x, sizeKB=*0x%x, userID=*0x%x)", dirName, dir, sysFileParam, bind, sizeKB, userId);
return CELL_OK;
return save_op_get_list_item(dirName, dir, sysFileParam, bind, sizeKB, userId);
}
void cellSysutil_SaveData_init()
+2 -3
View File
@@ -1,4 +1,4 @@
#pragma once
#pragma once
namespace vm { using namespace ps3; }
@@ -282,8 +282,7 @@ struct SaveDataEntry
s64 atime;
s64 mtime;
s64 ctime;
//void* iconBuf;
//u32 iconBufSize;
std::vector<uchar> iconBuf;
bool isNew;
};
+2 -2
View File
@@ -880,7 +880,7 @@ s32 _spurs::stop_event_helper(ppu_thread& ppu, vm::ptr<CellSpurs> spurs)
return CELL_SPURS_CORE_ERROR_STAT;
}
if (sys_event_port_send(spurs->eventPort, 0, 1, 0) != CELL_OK)
if (sys_event_port_send(ppu, spurs->eventPort, 0, 1, 0) != CELL_OK)
{
return CELL_SPURS_CORE_ERROR_STAT;
}
@@ -2794,7 +2794,7 @@ s32 cellSpursEventFlagSet(ppu_thread& ppu, vm::ptr<CellSpursEventFlag> eventFlag
// Signal the PPU thread to be woken up
eventFlag->pendingRecvTaskEvents[ppuWaitSlot] = ppuEvents;
CHECK_SUCCESS(sys_event_port_send(eventFlag->eventPortId, 0, 0, 0));
CHECK_SUCCESS(sys_event_port_send(ppu, eventFlag->eventPortId, 0, 0, 0));
}
if (pendingRecv)
+1 -1
View File
@@ -1,4 +1,4 @@
#pragma once
#pragma once
namespace vm { using namespace ps3; }
+20 -10
View File
@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/Cell/PPUModule.h"
@@ -511,9 +511,9 @@ s32 sceNpBasicGetEvent(vm::ptr<s32> event, vm::ptr<SceNpUserInfo> from, vm::ptr<
sceNp.warning("sceNpBasicGetEvent(event=*0x%x, from=*0x%x, data=*0x%x, size=*0x%x)", event, from, data, size);
// TODO: Check for other error and pass other events
*event = SCE_NP_BASIC_EVENT_OFFLINE;
//*event = SCE_NP_BASIC_EVENT_OFFLINE; // This event only indicates a contact is offline, not the current status of the connection
return CELL_OK;
return SCE_NP_BASIC_ERROR_NO_EVENT;
}
s32 sceNpCommerceCreateCtx()
@@ -911,10 +911,6 @@ s32 sceNpManagerRegisterCallback(vm::ptr<SceNpManagerCallback> callback, vm::ptr
{
return SCE_NP_ERROR_INVALID_ARGUMENT;
}
else
{
return SCE_NP_ERROR_NOT_INITIALIZED;
}
return CELL_OK;
}
@@ -1721,6 +1717,18 @@ s32 sceNpSignalingGetPeerNetInfoResult()
return CELL_OK;
}
s32 sceNpUtilCanonicalizeNpIdForPs3()
{
UNIMPLEMENTED_FUNC(sceNp);
return CELL_OK;
}
s32 sceNpUtilCanonicalizeNpIdForPsp()
{
UNIMPLEMENTED_FUNC(sceNp);
return CELL_OK;
}
s32 sceNpUtilCmpNpId(vm::ptr<SceNpId> id1, vm::ptr<SceNpId> id2)
{
sceNp.warning("sceNpUtilCmpNpId(id1=*0x%x, id2=*0x%x)", id1, id2);
@@ -2036,11 +2044,13 @@ DECLARE(ppu_module_manager::sceNp)("sceNp", []()
REG_FUNC(sceNp, sceNpSignalingGetPeerNetInfo);
REG_FUNC(sceNp, sceNpSignalingCancelPeerNetInfo);
REG_FUNC(sceNp, sceNpSignalingGetPeerNetInfoResult);
REG_FUNC(sceNp, sceNpUtilCanonicalizeNpIdForPs3);
REG_FUNC(sceNp, sceNpUtilCanonicalizeNpIdForPsp);
REG_FUNC(sceNp, sceNpUtilCmpNpId);
REG_FUNC(sceNp, sceNpUtilCmpNpIdInOrder);
REG_FUNC(sceNp, sceNpUtilCmpOnlineId); // 0x8C760B52
REG_FUNC(sceNp, sceNpUtilGetPlatformType); // 0xC611029A
REG_FUNC(sceNp, sceNpUtilSetPlatformType); // 0xAFC62605
REG_FUNC(sceNp, sceNpUtilCmpOnlineId);
REG_FUNC(sceNp, sceNpUtilGetPlatformType);
REG_FUNC(sceNp, sceNpUtilSetPlatformType);
REG_FUNC(sceNp, _sceNpSysutilClientMalloc);
REG_FUNC(sceNp, _sceNpSysutilClientFree);
REG_FUNC(sceNp, _Z33_sce_np_sysutil_send_empty_packetiPN16sysutil_cxmlutil11FixedMemoryEPKcS3_);
+27
View File
@@ -445,6 +445,29 @@ s32 sceNpMatching2RegisterRoomMessageCallback()
return CELL_OK;
}
s32 sceNpMatching2SignalingCancelPeerNetInfo()
{
UNIMPLEMENTED_FUNC(sceNp2);
return CELL_OK;
}
s32 sceNpMatching2SignalingGetLocalNetInfo()
{
UNIMPLEMENTED_FUNC(sceNp2);
return CELL_OK;
}
s32 sceNpMatching2SignalingGetPeerNetInfo()
{
UNIMPLEMENTED_FUNC(sceNp2);
return CELL_OK;
}
s32 sceNpMatching2SignalingGetPeerNetInfoResult()
{
UNIMPLEMENTED_FUNC(sceNp2);
return CELL_OK;
}
DECLARE(ppu_module_manager::sceNp2)("sceNp2", []()
{
@@ -517,4 +540,8 @@ DECLARE(ppu_module_manager::sceNp2)("sceNp2", []()
REG_FUNC(sceNp2, sceNpMatching2Init2);
REG_FUNC(sceNp2, sceNpMatching2SetLobbyMemberDataInternal);
REG_FUNC(sceNp2, sceNpMatching2RegisterRoomMessageCallback);
REG_FUNC(sceNp2, sceNpMatching2SignalingCancelPeerNetInfo);
REG_FUNC(sceNp2, sceNpMatching2SignalingGetLocalNetInfo);
REG_FUNC(sceNp2, sceNpMatching2SignalingGetPeerNetInfo);
REG_FUNC(sceNp2, sceNpMatching2SignalingGetPeerNetInfoResult);
});
+18
View File
@@ -24,6 +24,24 @@ s32 sys_lwmutex_trylock(ppu_thread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
s32 sys_lwmutex_unlock(ppu_thread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
s32 sys_lwmutex_destroy(ppu_thread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
struct sys_lwmutex_locker
{
ppu_thread& ppu;
vm::ptr<sys_lwmutex_t> mutex;
sys_lwmutex_locker(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> mutex)
: ppu(ppu)
, mutex(mutex)
{
verify(HERE), sys_lwmutex_lock(ppu, mutex, 0) == CELL_OK;
}
~sys_lwmutex_locker() noexcept(false)
{
verify(HERE), sys_lwmutex_unlock(ppu, mutex) == CELL_OK;
}
};
struct sys_lwcond_t;
struct sys_lwcond_attribute_t;
+20 -2
View File
@@ -97,9 +97,27 @@ s32 _sys_memcmp(vm::cptr<void> buf1, vm::cptr<void> buf2, u32 size)
return std::memcmp(buf1.get_ptr(), buf2.get_ptr(), size);
}
s32 _sys_memchr()
vm::ptr<u8> _sys_memchr(vm::ptr<u8> buf, u8 ch, s32 size)
{
fmt::throw_exception("Unimplemented" HERE);
sysPrxForUser.trace("_sys_memchr(buf=*0x%x, ch=0x%x, size=0x%x)", buf, ch, size);
if (!buf)
{
return vm::null;
}
while (size > 0)
{
if (*buf == ch)
{
return buf;
}
buf++;
size--;
}
return vm::null;
}
vm::ptr<void> _sys_memmove(vm::ptr<void> dst, vm::cptr<void> src, u32 size)
+12 -9
View File
@@ -14,6 +14,7 @@ extern logs::channel sysPrxForUser;
vm::gvar<sys_lwmutex_t> g_ppu_atexit_lwm;
vm::gvar<vm::ptr<void()>[8]> g_ppu_atexit;
vm::gvar<u32> g_ppu_once_mutex;
vm::gvar<sys_lwmutex_t> g_ppu_prx_lwm;
static u32 s_tls_addr = 0; // TLS image address
static u32 s_tls_file = 0; // TLS image size
@@ -110,6 +111,12 @@ void sys_initialize_tls(ppu_thread& ppu, u64 main_thread_id, u32 tls_seg_addr, u
attr->flags = 0;
attr->name_u64 = "_lv2ppu\0"_u64;
sys_mutex_create(g_ppu_once_mutex, attr);
lwa->protocol = SYS_SYNC_PRIORITY;
lwa->recursive = SYS_SYNC_RECURSIVE;
lwa->name_u64 = "_lv2prx\0"_u64;
sys_lwmutex_create(g_ppu_prx_lwm, lwa);
// TODO: missing prx initialization
}
error_code sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, u32 entry, u64 arg, s32 prio, u32 stacksize, u64 flags, vm::cptr<char> threadname)
@@ -182,13 +189,12 @@ error_code sys_ppu_thread_register_atexit(ppu_thread& ppu, vm::ptr<void()> func)
{
sysPrxForUser.notice("sys_ppu_thread_register_atexit(ptr=*0x%x)", func);
verify(HERE), !sys_lwmutex_lock(ppu, g_ppu_atexit_lwm, 0);
sys_lwmutex_locker lock(ppu, g_ppu_atexit_lwm);
for (auto ptr : *g_ppu_atexit)
{
if (ptr == func)
{
verify(HERE), !sys_lwmutex_unlock(ppu, g_ppu_atexit_lwm);
return CELL_EPERM;
}
}
@@ -198,12 +204,10 @@ error_code sys_ppu_thread_register_atexit(ppu_thread& ppu, vm::ptr<void()> func)
if (pp == vm::null)
{
pp = func;
verify(HERE), !sys_lwmutex_unlock(ppu, g_ppu_atexit_lwm);
return CELL_OK;
}
}
verify(HERE), !sys_lwmutex_unlock(ppu, g_ppu_atexit_lwm);
return CELL_ENOMEM;
}
@@ -211,19 +215,17 @@ error_code sys_ppu_thread_unregister_atexit(ppu_thread& ppu, vm::ptr<void()> fun
{
sysPrxForUser.notice("sys_ppu_thread_unregister_atexit(ptr=*0x%x)", func);
verify(HERE), !sys_lwmutex_lock(ppu, g_ppu_atexit_lwm, 0);
sys_lwmutex_locker lock(ppu, g_ppu_atexit_lwm);
for (auto& pp : *g_ppu_atexit)
{
if (pp == func)
{
pp = vm::null;
verify(HERE), !sys_lwmutex_unlock(ppu, g_ppu_atexit_lwm);
return CELL_OK;
}
}
verify(HERE), !sys_lwmutex_unlock(ppu, g_ppu_atexit_lwm);
return CELL_ESRCH;
}
@@ -231,7 +233,7 @@ void sys_ppu_thread_once(ppu_thread& ppu, vm::ptr<s32> once_ctrl, vm::ptr<void()
{
sysPrxForUser.notice("sys_ppu_thread_once(once_ctrl=*0x%x, init=*0x%x)", once_ctrl, init);
verify(HERE), !sys_mutex_lock(ppu, *g_ppu_once_mutex, 0);
verify(HERE), sys_mutex_lock(ppu, *g_ppu_once_mutex, 0) == CELL_OK;
if (*once_ctrl == SYS_PPU_THREAD_ONCE_INIT)
{
@@ -240,7 +242,7 @@ void sys_ppu_thread_once(ppu_thread& ppu, vm::ptr<s32> once_ctrl, vm::ptr<void()
*once_ctrl = SYS_PPU_THREAD_DONE_INIT;
}
verify(HERE), !sys_mutex_unlock(ppu, *g_ppu_once_mutex);
verify(HERE), sys_mutex_unlock(ppu, *g_ppu_once_mutex) == CELL_OK;
}
error_code sys_interrupt_thread_disestablish(ppu_thread& ppu, u32 ih)
@@ -267,6 +269,7 @@ void sysPrxForUser_sys_ppu_thread_init()
REG_VNID(sysPrxForUser, 0x00000000u, g_ppu_atexit_lwm);
REG_VNID(sysPrxForUser, 0x00000001u, g_ppu_once_mutex);
REG_VNID(sysPrxForUser, 0x00000002u, g_ppu_atexit);
REG_VNID(sysPrxForUser, 0x00000003u, g_ppu_prx_lwm);
REG_FUNC(sysPrxForUser, sys_initialize_tls);
REG_FUNC(sysPrxForUser, sys_ppu_thread_create);
+31 -20
View File
@@ -7,6 +7,8 @@
extern logs::channel sysPrxForUser;
extern vm::gvar<sys_lwmutex_t> g_ppu_prx_lwm;
// Convert the array of 32-bit pointers to 64-bit pointers using stack allocation
static auto convert_path_list(vm::cpptr<char> path_list, s32 count)
{
@@ -36,51 +38,57 @@ static void entryx(ppu_thread& ppu, vm::ptr<sys_prx_start_stop_module_option_t>
}
}
error_code sys_prx_load_module(vm::cptr<char> path, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
error_code sys_prx_load_module(ppu_thread& ppu, vm::cptr<char> path, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
{
sysPrxForUser.warning("sys_prx_load_module(path=%s, flags=0x%x, pOpt=*0x%x)", path, flags, pOpt);
// TODO
sys_lwmutex_locker(ppu, g_ppu_prx_lwm);
return _sys_prx_load_module(path, flags, pOpt);
}
error_code sys_prx_load_module_by_fd(s32 fd, u64 offset, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
error_code sys_prx_load_module_by_fd(ppu_thread& ppu, s32 fd, u64 offset, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
{
sysPrxForUser.warning("sys_prx_load_module_by_fd(fd=%d, offset=0x%x, flags=0x%x, pOpt=*0x%x)", fd, offset, flags, pOpt);
// TODO
sys_lwmutex_locker(ppu, g_ppu_prx_lwm);
return _sys_prx_load_module_by_fd(fd, offset, flags, pOpt);
}
error_code sys_prx_load_module_on_memcontainer(vm::cptr<char> path, u32 mem_ct, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
error_code sys_prx_load_module_on_memcontainer(ppu_thread& ppu, vm::cptr<char> path, u32 mem_ct, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
{
sysPrxForUser.warning("sys_prx_load_module_on_memcontainer(path=%s, mem_ct=0x%x, flags=0x%x, pOpt=*0x%x)", path, mem_ct, flags, pOpt);
// TODO
sys_lwmutex_locker(ppu, g_ppu_prx_lwm);
return _sys_prx_load_module_on_memcontainer(path, mem_ct, flags, pOpt);
}
error_code sys_prx_load_module_on_memcontainer_by_fd(s32 fd, u64 offset, u32 mem_ct, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
error_code sys_prx_load_module_on_memcontainer_by_fd(ppu_thread& ppu, s32 fd, u64 offset, u32 mem_ct, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
{
sysPrxForUser.warning("sys_prx_load_module_on_memcontainer_by_fd(fd=%d, offset=0x%x, mem_ct=0x%x, flags=0x%x, pOpt=*0x%x)", fd, offset, mem_ct, flags, pOpt);
// TODO
sys_lwmutex_locker(ppu, g_ppu_prx_lwm);
return _sys_prx_load_module_on_memcontainer_by_fd(fd, offset, mem_ct, flags, pOpt);
}
error_code sys_prx_load_module_list(s32 count, vm::cpptr<char> path_list, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt, vm::ptr<u32> id_list)
error_code sys_prx_load_module_list(ppu_thread& ppu, s32 count, vm::cpptr<char> path_list, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt, vm::ptr<u32> id_list)
{
sysPrxForUser.todo("sys_prx_load_module_list(count=%d, path_list=**0x%x, flags=0x%x, pOpt=*0x%x, id_list=*0x%x)", count, path_list, flags, pOpt, id_list);
// TODO
sys_lwmutex_locker(ppu, g_ppu_prx_lwm);
return _sys_prx_load_module_list(count, convert_path_list(path_list, count), flags, pOpt, id_list);
}
error_code sys_prx_load_module_list_on_memcontainer(s32 count, vm::cpptr<char> path_list, u32 mem_ct, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt, vm::ptr<u32> id_list)
error_code sys_prx_load_module_list_on_memcontainer(ppu_thread& ppu, s32 count, vm::cpptr<char> path_list, u32 mem_ct, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt, vm::ptr<u32> id_list)
{
sysPrxForUser.todo("sys_prx_load_module_list_on_memcontainer(count=%d, path_list=**0x%x, mem_ct=0x%x, flags=0x%x, pOpt=*0x%x, id_list=*0x%x)", count, path_list, mem_ct, flags, pOpt, id_list);
// TODO
sys_lwmutex_locker(ppu, g_ppu_prx_lwm);
return _sys_prx_load_module_list_on_memcontainer(count, convert_path_list(path_list, count), mem_ct, flags, pOpt, id_list);
}
@@ -93,7 +101,7 @@ error_code sys_prx_start_module(ppu_thread& ppu, u32 id, u32 args, vm::ptr<void>
return CELL_EINVAL;
}
// TODO
sys_lwmutex_locker(ppu, g_ppu_prx_lwm);
vm::var<sys_prx_start_stop_module_option_t> opt;
opt->size = opt.size();
@@ -126,7 +134,7 @@ error_code sys_prx_stop_module(ppu_thread& ppu, u32 id, u32 args, vm::ptr<void>
return CELL_EINVAL;
}
// TODO
sys_lwmutex_locker(ppu, g_ppu_prx_lwm);
vm::var<sys_prx_start_stop_module_option_t> opt;
opt->size = opt.size();
@@ -150,27 +158,30 @@ error_code sys_prx_stop_module(ppu_thread& ppu, u32 id, u32 args, vm::ptr<void>
return CELL_OK;
}
error_code sys_prx_unload_module(u32 id, u64 flags, vm::ptr<sys_prx_unload_module_option_t> pOpt)
error_code sys_prx_unload_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr<sys_prx_unload_module_option_t> pOpt)
{
sysPrxForUser.warning("sys_prx_unload_module(id=0x%x, flags=0x%x, pOpt=*0x%x)", id, flags, pOpt);
// TODO
sys_lwmutex_locker(ppu, g_ppu_prx_lwm);
return _sys_prx_unload_module(id, flags, pOpt);
}
error_code sys_prx_register_library(vm::ptr<void> lib_entry)
error_code sys_prx_register_library(ppu_thread& ppu, vm::ptr<void> lib_entry)
{
sysPrxForUser.warning("sys_prx_register_library(lib_entry=*0x%x)", lib_entry);
// TODO
sys_lwmutex_locker(ppu, g_ppu_prx_lwm);
return _sys_prx_register_library(lib_entry);
}
error_code sys_prx_unregister_library(vm::ptr<void> lib_entry)
error_code sys_prx_unregister_library(ppu_thread& ppu, vm::ptr<void> lib_entry)
{
sysPrxForUser.warning("sys_prx_unregister_library(lib_entry=*0x%x)", lib_entry);
// TODO
sys_lwmutex_locker(ppu, g_ppu_prx_lwm);
return _sys_prx_unregister_library(lib_entry);
}
+85 -7
View File
@@ -1,5 +1,6 @@
#include "stdafx.h"
#include "Utilities/VirtualMemory.h"
#include "Utilities/bin_patch.h"
#include "Crypto/sha1.h"
#include "Crypto/unself.h"
#include "Loader/ELF.h"
@@ -119,6 +120,7 @@ struct ppu_linkage_info
std::unordered_map<u32, info, value_hash<u32>> functions;
std::unordered_map<u32, info, value_hash<u32>> variables;
// Obsolete
bool imported = false;
};
@@ -129,6 +131,11 @@ struct ppu_linkage_info
// Initialize static modules.
static void ppu_initialize_modules(const std::shared_ptr<ppu_linkage_info>& link)
{
if (!link->modules.empty())
{
return;
}
ppu_initialize_syscalls();
const std::initializer_list<const ppu_static_module*> registered
@@ -578,8 +585,10 @@ static auto ppu_load_exports(const std::shared_ptr<ppu_linkage_info>& link, u32
return result;
}
static void ppu_load_imports(std::vector<ppu_reloc>& relocs, const std::shared_ptr<ppu_linkage_info>& link, u32 imports_start, u32 imports_end)
static auto ppu_load_imports(std::vector<ppu_reloc>& relocs, const std::shared_ptr<ppu_linkage_info>& link, u32 imports_start, u32 imports_end)
{
std::unordered_map<u32, void*> result;
for (u32 addr = imports_start; addr < imports_end;)
{
const auto& lib = vm::_ref<const ppu_prx_module_info>(addr);
@@ -613,6 +622,7 @@ static void ppu_load_imports(std::vector<ppu_reloc>& relocs, const std::shared_p
auto& flink = link->modules[module_name].functions[fnid];
// Add new import
result.emplace(faddr, &flink);
flink.imports.emplace(faddr);
mlink.imported = true;
@@ -625,6 +635,7 @@ static void ppu_load_imports(std::vector<ppu_reloc>& relocs, const std::shared_p
// Patch refs if necessary (0x2000 seems to be correct flag indicating the presence of additional info)
if (const u32 frefs = (lib.attributes & 0x2000) ? +fnids[i + lib.num_func] : 0)
{
result.emplace(frefs, &flink);
flink.frefss.emplace(frefs);
ppu_patch_refs(&relocs, frefs, link_addr);
}
@@ -645,6 +656,7 @@ static void ppu_load_imports(std::vector<ppu_reloc>& relocs, const std::shared_p
auto& vlink = link->modules[module_name].variables[vnid];
// Add new import
result.emplace(vref, &vlink);
vlink.imports.emplace(vref);
mlink.imported = true;
@@ -656,6 +668,8 @@ static void ppu_load_imports(std::vector<ppu_reloc>& relocs, const std::shared_p
addr += lib.size ? lib.size : sizeof(ppu_prx_module_info);
}
return result;
}
std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::string& path)
@@ -666,6 +680,9 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
// Access linkage information object
const auto link = fxm::get_always<ppu_linkage_info>();
// Initialize HLE modules
ppu_initialize_modules(link);
for (const auto& prog : elf.progs)
{
LOG_NOTICE(LOADER, "** Segment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, flags=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_flags);
@@ -870,8 +887,7 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
LOG_WARNING(LOADER, "Library %s (rtoc=0x%x):", lib_name, lib_info->toc);
prx->specials = ppu_load_exports(link, lib_info->exports_start, lib_info->exports_end);
ppu_load_imports(prx->relocs, link, lib_info->imports_start, lib_info->imports_end);
prx->imports = ppu_load_imports(prx->relocs, link, lib_info->imports_start, lib_info->imports_end);
prx->analyse(lib_info->toc, 0);
}
@@ -887,9 +903,34 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
prx->epilogue.set(prx->specials[0x330F7005]);
prx->name = path.substr(path.find_last_of('/') + 1);
prx->path = path;
if (Emu.IsReady() && fxm::import<ppu_module>([&] { return prx; }))
{
// Special loading mode
auto ppu = idm::make_ptr<ppu_thread>("test_thread", 0, 0x100000);
ppu->cmd_push({ppu_cmd::initialize, 0});
}
return prx;
}
void ppu_unload_prx(const lv2_prx& prx)
{
// Clean linkage info
for (auto& imp : prx.imports)
{
auto pinfo = static_cast<ppu_linkage_info::module::info*>(imp.second);
pinfo->frefss.erase(imp.first);
pinfo->imports.erase(imp.first);
}
for (auto& seg : prx.segs)
{
vm::dealloc(seg.addr, vm::main);
}
}
void ppu_load_exec(const ppu_exec_object& elf)
{
if (g_cfg.core.hook_functions)
@@ -914,6 +955,11 @@ void ppu_load_exec(const ppu_exec_object& elf)
u32 primary_stacksize = 0x100000;
u32 malloc_pagesize = 0x100000;
// Executable hash
sha1_context sha;
sha1_starts(&sha);
u8 sha1_hash[20];
// Allocate memory at fixed positions
for (const auto& prog : elf.progs)
{
@@ -924,7 +970,11 @@ void ppu_load_exec(const ppu_exec_object& elf)
const u32 size = _seg.size = ::narrow<u32>(prog.p_memsz, "p_memsz" HERE);
const u32 type = _seg.type = prog.p_type;
const u32 flag = _seg.flags = prog.p_flags;
// Hash big-endian values
sha1_update(&sha, (uchar*)&prog.p_type, sizeof(prog.p_type));
sha1_update(&sha, (uchar*)&prog.p_flags, sizeof(prog.p_flags));
if (type == 0x1 /* LOAD */ && prog.p_memsz)
{
if (prog.bin.size() > size || prog.bin.size() != prog.p_filesz)
@@ -933,8 +983,11 @@ void ppu_load_exec(const ppu_exec_object& elf)
if (!vm::falloc(addr, size, vm::main))
fmt::throw_exception("vm::falloc() failed (addr=0x%x, memsz=0x%x)", addr, size);
// Copy segment data
// Copy segment data, hash it
std::memcpy(vm::base(addr), prog.bin.data(), prog.bin.size());
sha1_update(&sha, (uchar*)&prog.p_vaddr, sizeof(prog.p_vaddr));
sha1_update(&sha, (uchar*)&prog.p_memsz, sizeof(prog.p_memsz));
sha1_update(&sha, prog.bin.data(), prog.bin.size());
// Initialize executable code if necessary
if (prog.p_flags & 0x1)
@@ -964,6 +1017,28 @@ void ppu_load_exec(const ppu_exec_object& elf)
}
}
sha1_finish(&sha, sha1_hash);
// Format patch name
std::string hash("PPU-0000000000000000000000000000000000000000");
for (u32 i = 0; i < sizeof(sha1_hash); i++)
{
constexpr auto pal = "0123456789abcdef";
hash[4 + i * 2] = pal[sha1_hash[i] >> 4];
hash[5 + i * 2] = pal[sha1_hash[i] & 15];
}
// Apply the patch
auto applied = fxm::check_unlocked<patch_engine>()->apply(hash, vm::g_base_addr);
if (!Emu.GetTitleID().empty())
{
// Alternative patch
applied += fxm::check_unlocked<patch_engine>()->apply(Emu.GetTitleID() + '-' + hash, vm::g_base_addr);
}
LOG_NOTICE(LOADER, "PPU executable hash: %s (<- %u)", hash, applied);
// Initialize HLE modules
ppu_initialize_modules(link);
@@ -1089,6 +1164,11 @@ void ppu_load_exec(const ppu_exec_object& elf)
}
if (g_cfg.core.lib_loading == lib_loading_type::automatic || g_cfg.core.lib_loading == lib_loading_type::both)
{
// Load only libsysmodule.sprx
load_libs.emplace("libsysmodule.sprx");
}
else if (0)
{
// Load recommended set of modules: Module name -> SPRX
std::unordered_multimap<std::string, std::string> sprx_map
@@ -1123,7 +1203,6 @@ void ppu_load_exec(const ppu_exec_object& elf)
{ "cellFont", "libfont.sprx" },
{ "cellFontFT", "libfontFT.sprx" },
{ "cellFontFT", "libfreetype.sprx" },
{ "cellGcmSys", "libgcm_sys.sprx"},
{ "cellGifDec", "libgifdec.sprx" },
{ "cellGifDec", "libsre.sprx" },
{ "cellJpgDec", "libjpgdec.sprx" },
@@ -1198,7 +1277,6 @@ void ppu_load_exec(const ppu_exec_object& elf)
}
}
// TODO: recursively scan all SPRX files in /app_home/ for imports
for (const auto& pair : link->modules)
{
if (!pair.second.imported)
+142 -46
View File
@@ -1,5 +1,6 @@
#include "stdafx.h"
#include "Utilities/VirtualMemory.h"
#include "Utilities/sysinfo.h"
#include "Crypto/sha1.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
@@ -53,6 +54,8 @@
#include <cfenv>
#include "Utilities/GSL.h"
const bool s_use_rtm = utils::has_rtm();
extern u64 get_system_time();
namespace vm { using namespace ps3; }
@@ -825,6 +828,26 @@ extern bool ppu_stwcx(ppu_thread& ppu, u32 addr, u32 reg_value)
return false;
}
if (s_use_rtm && utils::transaction_enter())
{
if (!vm::reader_lock{vm::try_to_lock})
{
_xabort(0);
}
const bool result = ppu.rtime == vm::reservation_acquire(addr, sizeof(u32)) && data.compare_and_swap_test(static_cast<u32>(ppu.rdata), reg_value);
if (result)
{
vm::reservation_update(addr, sizeof(u32));
vm::notify(addr, sizeof(u32));
}
_xend();
ppu.raddr = 0;
return result;
}
vm::writer_lock lock(0);
const bool result = ppu.rtime == vm::reservation_acquire(addr, sizeof(u32)) && data.compare_and_swap_test(static_cast<u32>(ppu.rdata), reg_value);
@@ -849,6 +872,26 @@ extern bool ppu_stdcx(ppu_thread& ppu, u32 addr, u64 reg_value)
return false;
}
if (s_use_rtm && utils::transaction_enter())
{
if (!vm::reader_lock{vm::try_to_lock})
{
_xabort(0);
}
const bool result = ppu.rtime == vm::reservation_acquire(addr, sizeof(u64)) && data.compare_and_swap_test(ppu.rdata, reg_value);
if (result)
{
vm::reservation_update(addr, sizeof(u64));
vm::notify(addr, sizeof(u64));
}
_xend();
ppu.raddr = 0;
return result;
}
vm::writer_lock lock(0);
const bool result = ppu.rtime == vm::reservation_acquire(addr, sizeof(u64)) && data.compare_and_swap_test(ppu.rdata, reg_value);
@@ -963,9 +1006,43 @@ extern void ppu_initialize(const ppu_module& info)
return link_table;
}();
// Get cache path for this executable
std::string cache_path;
if (info.name.empty())
{
cache_path = Emu.GetCachePath();
}
else
{
cache_path = vfs::get("/dev_flash/");
if (info.path.compare(0, cache_path.size(), cache_path) == 0)
{
// Remove prefix for dev_flash files
cache_path.clear();
}
else
{
cache_path = Emu.GetTitleID();
}
cache_path = fs::get_data_dir(cache_path, info.path);
}
#ifdef LLVM_AVAILABLE
// Initialize compiler
jit_compiler jit(s_link_table, g_cfg.core.llvm_cpu);
// Compiled PPU module info
struct jit_module
{
std::vector<u64*> vars;
std::vector<ppu_function_t> funcs;
};
// Permanently loaded compiled PPU modules (name -> data)
jit_module& jit_mod = fxm::get_always<std::unordered_map<std::string, jit_module>>()->emplace(cache_path + info.name, jit_module{}).first->second;
// Compiler instance (deferred initialization)
std::unique_ptr<jit_compiler> jit;
// Compiler mutex
semaphore<> jmutex;
@@ -991,8 +1068,11 @@ extern void ppu_initialize(const ppu_module& info)
// Difference between function name and current location
const u32 reloc = info.name.empty() ? 0 : info.segs.at(0).addr;
while (fpos < info.funcs.size())
while (jit_mod.vars.empty() && fpos < info.funcs.size())
{
// Initialize compiler instance
if (!jit) jit = std::make_unique<jit_compiler>(s_link_table, g_cfg.core.llvm_cpu);
// First function in current module part
const auto fstart = fpos;
@@ -1084,7 +1164,7 @@ extern void ppu_initialize(const ppu_module& info)
}
sha1_finish(&ctx, output);
fmt::append(obj_name, "-%016X-%s.obj", reinterpret_cast<be_t<u64>&>(output), jit.cpu());
fmt::append(obj_name, "-%016X-%s.obj", reinterpret_cast<be_t<u64>&>(output), jit->cpu());
}
if (Emu.IsStopped())
@@ -1101,40 +1181,17 @@ extern void ppu_initialize(const ppu_module& info)
globals.emplace_back(fmt::format("__seg%u_%x", i, suffix), info.segs[i].addr);
}
// Get cache path for this executable
std::string cache_path;
if (info.name.empty())
{
cache_path = Emu.GetCachePath();
}
else
{
cache_path = vfs::get("/dev_flash/");
if (info.path.compare(0, cache_path.size(), cache_path) == 0)
{
// Remove prefix for dev_flash files
cache_path.clear();
}
else
{
cache_path = Emu.GetTitleID();
}
cache_path = fs::get_data_dir(cache_path, info.path);
}
// Check object file
if (fs::is_file(cache_path + obj_name))
{
semaphore_lock lock(jmutex);
ppu_initialize2(jit, part, cache_path, obj_name);
jit->add(cache_path + obj_name);
LOG_SUCCESS(PPU, "LLVM: Loaded module %s", obj_name);
continue;
}
// Create worker thread for compilation
jthreads.emplace_back([&jit, &jmutex, &jcores, obj_name = obj_name, part = std::move(part), cache_path = std::move(cache_path)]()
jthreads.emplace_back([&jit, &jmutex, &jcores, obj_name = obj_name, part = std::move(part), &cache_path]()
{
// Set low priority
thread_ctrl::set_native_priority(-1);
@@ -1160,7 +1217,7 @@ extern void ppu_initialize(const ppu_module& info)
// Proceed with original JIT instance
semaphore_lock lock(jmutex);
ppu_initialize2(jit, part, cache_path, obj_name);
jit->add(cache_path + obj_name);
});
}
@@ -1175,28 +1232,69 @@ extern void ppu_initialize(const ppu_module& info)
return;
}
jit.fin();
// Get and install function addresses
for (const auto& func : info.funcs)
if (jit_mod.vars.empty())
{
if (!func.size) continue;
jit->fin();
for (const auto& block : func.blocks)
// Get and install function addresses
for (const auto& func : info.funcs)
{
if (block.second)
if (!func.size) continue;
for (const auto& block : func.blocks)
{
ppu_ref(block.first) = ::narrow<u32>(jit.get(fmt::format("__0x%x", block.first - reloc)));
if (block.second)
{
const u64 addr = jit->get(fmt::format("__0x%x", block.first - reloc));
jit_mod.funcs.emplace_back(reinterpret_cast<ppu_function_t>(addr));
ppu_ref(block.first) = ::narrow<u32>(addr);
}
}
}
// Initialize global variables
for (auto& var : globals)
{
const u64 addr = jit->get(var.first);
jit_mod.vars.emplace_back(reinterpret_cast<u64*>(addr));
if (addr)
{
*reinterpret_cast<u64*>(addr) = var.second;
}
}
}
// Initialize global variables
for (auto& var : globals)
else
{
if (u64 addr = jit.get(var.first))
std::size_t index = 0;
// Locate existing functions
for (const auto& func : info.funcs)
{
*reinterpret_cast<u64*>(addr) = var.second;
if (!func.size) continue;
for (const auto& block : func.blocks)
{
if (block.second)
{
ppu_ref(block.first) = ::narrow<u32>(reinterpret_cast<uptr>(jit_mod.funcs[index++]));
}
}
}
index = 0;
// Rewrite global variables
while (index < jit_mod.vars.size())
{
*jit_mod.vars[index++] = (u64)vm::g_base_addr;
*jit_mod.vars[index++] = (u64)vm::g_exec_addr;
for (const auto& seg : info.segs)
{
*jit_mod.vars[index++] = seg.addr;
}
}
}
#endif
@@ -1232,8 +1330,6 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module& module_part, co
std::shared_ptr<MsgDialogBase> dlg;
// Check cached file
if (!fs::is_file(cache_path + obj_name))
{
legacy::FunctionPassManager pm(module.get());
+12 -8
View File
@@ -16,7 +16,7 @@ PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, const ppu_mod
, m_module(module)
, m_is_be(false)
, m_info(info)
, m_pure_attr(AttributeList::get(m_context,AttributeList::FunctionIndex, AttrBuilder().addAttribute(Attribute::NoUnwind).addAttribute(Attribute::ReadNone)))
, m_pure_attr(AttributeSet::get(m_context, AttributeSet::FunctionIndex, {Attribute::NoUnwind, Attribute::ReadNone}))
{
// There is no weak linkage on JIT, so let's create variables with different names for each module part
const u32 gsuffix = m_info.name.empty() ? info.funcs[0].addr : info.funcs[0].addr - m_info.segs[0].addr;
@@ -133,7 +133,7 @@ Function* PPUTranslator::Translate(const ppu_function& info)
const u64 base = m_reloc ? m_reloc->addr : 0;
m_addr = info.addr - base;
m_thread = &*m_function->arg_begin();
m_thread = &*m_function->getArgumentList().begin();
m_base_loaded = m_ir->CreateLoad(m_base);
m_body = BasicBlock::Create(m_context, "__body", m_function);
@@ -818,16 +818,19 @@ void PPUTranslator::VCMPGTUW(ppu_opcode_t op)
if (op.oe) SetCrField(6, IsOnes(result), m_ir->getFalse(), IsZero(result), m_ir->getFalse());
}
// TODO: remove this (wrong casts)
#define FP_SAT_OP(fcmp, value) m_ir->CreateSelect(fcmp, cast<Constant>(cast<FCmpInst>(fcmp)->getOperand(1)), value)
void PPUTranslator::VCTSXS(ppu_opcode_t op)
{
const auto b = GetVr(op.vb, VrType::vf);
const auto scaled = Scale(b, op.vuimm);
//const auto is_nan = m_ir->CreateFCmpUNO(b, ConstantVector::getSplat(4, ConstantFP::get(GetType<f32>(), 0.0))); // NaN -> 0.0
const auto sat_l = m_ir->CreateFCmpOLT(scaled, ConstantVector::getSplat(4, ConstantFP::get(GetType<f32>(), -std::pow(2, 31)))); // TODO ???
//const auto const0 = ConstantVector::getSplat(4, ConstantFP::get(GetType<f32>(), 0.0));
const auto const1 = ConstantVector::getSplat(4, ConstantFP::get(GetType<f32>(), -std::pow(2, 31)));
//const auto is_nan = m_ir->CreateFCmpUNO(b, const0); // NaN -> 0.0
const auto sat_l = m_ir->CreateFCmpOLT(scaled, const1); // TODO ???
const auto sat_h = m_ir->CreateFCmpOGE(scaled, ConstantVector::getSplat(4, ConstantFP::get(GetType<f32>(), std::pow(2, 31))));
const auto converted = m_ir->CreateFPToSI(FP_SAT_OP(sat_l, scaled), GetType<s32[4]>());
const auto converted = m_ir->CreateFPToSI(m_ir->CreateSelect(sat_l, const1, scaled), GetType<s32[4]>());
SetVr(op.vd, m_ir->CreateSelect(sat_h, ConstantVector::getSplat(4, m_ir->getInt32(0x7fffffff)), converted));
SetSat(IsNotZero(m_ir->CreateOr(sat_l, sat_h)));
}
@@ -836,10 +839,11 @@ void PPUTranslator::VCTUXS(ppu_opcode_t op)
{
const auto b = GetVr(op.vb, VrType::vf);
const auto scaled = Scale(b, op.vuimm);
//const auto is_nan = m_ir->CreateFCmpUNO(b, ConstantVector::getSplat(4, ConstantFP::get(GetType<f32>(), 0.0))); // NaN -> 0.0
const auto sat_l = m_ir->CreateFCmpOLT(scaled, ConstantVector::getSplat(4, ConstantFP::get(GetType<f32>(), 0.0)));
const auto const0 = ConstantVector::getSplat(4, ConstantFP::get(GetType<f32>(), 0.0));
//const auto is_nan = m_ir->CreateFCmpUNO(b, const0); // NaN -> 0.0
const auto sat_l = m_ir->CreateFCmpOLT(scaled, const0);
const auto sat_h = m_ir->CreateFCmpOGE(scaled, ConstantVector::getSplat(4, ConstantFP::get(GetType<f32>(), std::pow(2, 32)))); // TODO ???
const auto converted = m_ir->CreateFPToUI(FP_SAT_OP(sat_l, scaled), GetType<u32[4]>());
const auto converted = m_ir->CreateFPToUI(m_ir->CreateSelect(sat_l, const0, scaled), GetType<u32[4]>());
SetVr(op.vd, m_ir->CreateSelect(sat_h, ConstantVector::getSplat(4, m_ir->getInt32(0xffffffff)), converted));
SetSat(IsNotZero(m_ir->CreateOr(sat_l, sat_h)));
}
+3 -3
View File
@@ -120,7 +120,7 @@ class PPUTranslator final //: public CPUTranslator
std::map<u64, const ppu_reloc*> m_relocs;
// Attributes for function calls which are "pure" and may be optimized away if their results are unused
const llvm::AttributeList m_pure_attr;
const llvm::AttributeSet m_pure_attr;
// IR builder
llvm::IRBuilder<>* m_ir;
@@ -404,7 +404,7 @@ public:
// Call a function with attribute list
template<typename... Args>
llvm::CallInst* Call(llvm::Type* ret, llvm::AttributeList attr, llvm::StringRef name, Args... args)
llvm::CallInst* Call(llvm::Type* ret, llvm::AttributeSet attr, llvm::StringRef name, Args... args)
{
// Call the function
return m_ir->CreateCall(m_module->getOrInsertFunction(name, llvm::FunctionType::get(ret, {args->getType()...}, false), attr), {args...});
@@ -414,7 +414,7 @@ public:
template<typename... Args>
llvm::CallInst* Call(llvm::Type* ret, llvm::StringRef name, Args... args)
{
return Call(ret, llvm::AttributeList{}, name, args...);
return Call(ret, llvm::AttributeSet{}, name, args...);
}
// Handle compilation errors
+27 -13
View File
@@ -43,23 +43,27 @@ std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 en
// Key for multimap
const u64 key = entry | u64{ ls[entry / 4] } << 32;
const be_t<u32>* base = ls + entry / 4;
const u32 block_sz = max_limit - entry;
{
reader_lock lock(m_mutex);
// Try to find existing function in the database
if (auto func = find(ls + entry / 4, key, max_limit - entry))
if (auto func = find(base, key, block_sz))
{
return func;
}
}
writer_lock lock(m_mutex);
// Double-check
if (auto func = find(ls + entry / 4, key, max_limit - entry))
{
return func;
writer_lock lock(m_mutex);
// Double-check
if (auto func = find(base, key, block_sz))
{
return func;
}
}
// Initialize block entries with the function entry point
@@ -81,11 +85,15 @@ std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 en
const auto type = s_spu_itype.decode(op.opcode);
// Find existing function
if (pos != entry && find(ls + pos / 4, pos | u64{ op.opcode } << 32, limit - pos))
{
limit = pos;
break;
reader_lock lock(m_mutex);
// Find existing function
if (pos != entry && find(ls + pos / 4, pos | u64{ op.opcode } << 32, limit - pos))
{
limit = pos;
break;
}
}
// Additional analysis at the beginning of the block
@@ -311,10 +319,16 @@ std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 en
// Set whether the function can reset stack
func->does_reset_stack = ila_sp_pos < limit;
// Add function to the database
m_db.emplace(key, func);
// Lock here just before we write to the db
// Its is unlikely that the second check will pass anyway so we delay this step since compiling functions is very fast
{
writer_lock lock(m_mutex);
LOG_SUCCESS(SPU, "Function detected [0x%05x-0x%05x] (size=0x%x)", func->addr, func->addr + func->size, func->size);
// Add function to the database
m_db.emplace(key, func);
}
LOG_NOTICE(SPU, "Function detected [0x%05x-0x%05x] (size=0x%x)", func->addr, func->addr + func->size, func->size);
return func;
}
+11 -2
View File
@@ -5,6 +5,7 @@
#include "SPUThread.h"
#include "SPURecompiler.h"
#include "SPUASMJITRecompiler.h"
#include <algorithm>
extern u64 get_system_time();
@@ -22,8 +23,15 @@ void spu_recompiler_base::enter(SPUThread& spu)
// Get SPU LS pointer
const auto _ls = vm::ps3::_ptr<u32>(spu.offset);
// Always validate (TODO)
const auto func = spu.spu_db->analyse(_ls, spu.pc);
// Search if cached data matches
auto func = spu.compiled_cache[spu.pc / 4];
// Check shared db if we dont have a match
if (!func || !std::equal(func->data.begin(), func->data.end(), _ls + spu.pc / 4, [](const be_t<u32>& l, const be_t<u32>& r) { return *(u32*)(u8*)&l == *(u32*)(u8*)&r; }))
{
func = spu.spu_db->analyse(_ls, spu.pc).get();
spu.compiled_cache[spu.pc / 4] = func;
}
// Reset callstack if necessary
if ((func->does_reset_stack && spu.recursion_level) || spu.recursion_level >= 128)
@@ -32,6 +40,7 @@ void spu_recompiler_base::enter(SPUThread& spu)
return;
}
// Compile if needed
if (!func->compiled)
{
if (!spu.spu_rec)
+129 -10
View File
@@ -1,5 +1,6 @@
#include "stdafx.h"
#include "Utilities/lockless.h"
#include "Utilities/sysinfo.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
@@ -22,6 +23,8 @@
#include <atomic>
#include <thread>
const bool s_use_rtm = utils::has_rtm();
#ifdef _MSC_VER
bool operator ==(const u128& lhs, const u128& rhs)
{
@@ -55,6 +58,65 @@ void fmt_class_string<spu_decoder_type>::format(std::string& out, u64 arg)
});
}
namespace spu
{
namespace scheduler
{
std::array<std::atomic<u8>, 65536> atomic_instruction_table = {};
constexpr u32 native_jiffy_duration_us = 2000000;
void acquire_pc_address(u32 pc, u32 timeout_ms = 3)
{
const u8 max_concurrent_instructions = (u8)g_cfg.core.preferred_spu_threads;
const u32 pc_offset = pc >> 2;
if (timeout_ms > 0)
{
while (timeout_ms--)
{
if (atomic_instruction_table[pc_offset].load(std::memory_order_consume) >= max_concurrent_instructions)
std::this_thread::sleep_for(1ms);
}
}
else
{
std::this_thread::yield();
}
atomic_instruction_table[pc_offset]++;
}
void release_pc_address(u32 pc)
{
const u32 pc_offset = pc >> 2;
atomic_instruction_table[pc_offset]--;
}
struct concurrent_execution_watchdog
{
u32 pc = 0;
bool active = false;
concurrent_execution_watchdog(SPUThread& spu)
:pc(spu.pc)
{
if (g_cfg.core.preferred_spu_threads > 0)
{
acquire_pc_address(pc, (u32)g_cfg.core.spu_delay_penalty);
active = true;
}
}
~concurrent_execution_watchdog()
{
if (active)
release_pc_address(pc);
}
};
}
}
void spu_int_ctrl_t::set(u64 ints)
{
// leave only enabled interrupts
@@ -483,6 +545,7 @@ void SPUThread::do_dma_transfer(const spu_mfc_cmd& args, bool from_mfc)
void SPUThread::process_mfc_cmd()
{
spu::scheduler::concurrent_execution_watchdog watchdog(*this);
LOG_TRACE(SPU, "DMAC: cmd=%s, lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x", ch_mfc_cmd.cmd, ch_mfc_cmd.lsa, ch_mfc_cmd.eal, ch_mfc_cmd.tag, ch_mfc_cmd.size);
const auto mfc = fxm::check_unlocked<mfc_thread>();
@@ -499,7 +562,7 @@ void SPUThread::process_mfc_cmd()
}
// TODO: investigate lost notifications
std::this_thread::sleep_for(0us);
std::this_thread::yield();
_mm_lfence();
}
};
@@ -544,9 +607,22 @@ void SPUThread::process_mfc_cmd()
thread_ctrl::wait_for(100);
}
}
else if (s_use_rtm && utils::transaction_enter())
{
if (!vm::reader_lock{vm::try_to_lock})
{
_xabort(0);
}
rtime = vm::reservation_acquire(raddr, 128);
rdata = data;
_xend();
_ref<decltype(rdata)>(ch_mfc_cmd.lsa & 0x3ffff) = rdata;
return ch_atomic_stat.set_value(MFC_GETLLAR_SUCCESS);
}
else
{
// Fast path
rdata = data;
_mm_lfence();
}
@@ -577,15 +653,36 @@ void SPUThread::process_mfc_cmd()
if (raddr == ch_mfc_cmd.eal && rtime == vm::reservation_acquire(raddr, 128) && rdata == data)
{
// TODO: vm::check_addr
vm::writer_lock lock;
if (rtime == vm::reservation_acquire(raddr, 128) && rdata == data)
if (s_use_rtm && utils::transaction_enter())
{
data = to_write;
result = true;
if (!vm::reader_lock{vm::try_to_lock})
{
_xabort(0);
}
vm::reservation_update(raddr, 128);
vm::notify(raddr, 128);
if (rtime == vm::reservation_acquire(raddr, 128) && rdata == data)
{
data = to_write;
result = true;
vm::reservation_update(raddr, 128);
vm::notify(raddr, 128);
}
_xend();
}
else
{
vm::writer_lock lock;
if (rtime == vm::reservation_acquire(raddr, 128) && rdata == data)
{
data = to_write;
result = true;
vm::reservation_update(raddr, 128);
vm::notify(raddr, 128);
}
}
}
@@ -621,6 +718,23 @@ void SPUThread::process_mfc_cmd()
// Store unconditionally
// TODO: vm::check_addr
if (s_use_rtm && utils::transaction_enter())
{
if (!vm::reader_lock{vm::try_to_lock})
{
_xabort(0);
}
data = to_write;
vm::reservation_update(ch_mfc_cmd.eal, 128);
vm::notify(ch_mfc_cmd.eal, 128);
_xend();
ch_atomic_stat.set_value(MFC_PUTLLUC_SUCCESS);
return;
}
vm::writer_lock lock(0);
data = to_write;
vm::reservation_update(ch_mfc_cmd.eal, 128);
@@ -897,7 +1011,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
if (ctr > 10000)
{
ctr = 0;
std::this_thread::sleep_for(0us);
std::this_thread::yield();
}
else
{
@@ -978,6 +1092,11 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
case SPU_RdDec:
{
out = ch_dec_value - (u32)(get_timebased_time() - ch_dec_start_timestamp);
//Polling: We might as well hint to the scheduler to slot in another thread since this one is counting down
if (g_cfg.core.spu_loop_detection && out > spu::scheduler::native_jiffy_duration_us)
std::this_thread::yield();
return true;
}
+1
View File
@@ -582,6 +582,7 @@ public:
std::exception_ptr pending_exception;
std::array<struct spu_function_t*, 65536> compiled_cache{};
std::shared_ptr<class SPUDatabase> spu_db;
std::shared_ptr<class spu_recompiler_base> spu_rec;
u32 recursion_level = 0;
+1 -1
View File
@@ -414,7 +414,7 @@ error_code sys_event_port_disconnect(u32 eport_id)
return CELL_OK;
}
error_code sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3)
error_code sys_event_port_send(ppu_thread& ppu, u32 eport_id, u64 data1, u64 data2, u64 data3)
{
sys_event.trace("sys_event_port_send(eport_id=0x%x, data1=0x%llx, data2=0x%llx, data3=0x%llx)", eport_id, data1, data2, data3);
+1 -1
View File
@@ -137,4 +137,4 @@ error_code sys_event_port_create(vm::ps3::ptr<u32> eport_id, s32 port_type, u64
error_code sys_event_port_destroy(u32 eport_id);
error_code sys_event_port_connect_local(u32 event_port_id, u32 event_queue_id);
error_code sys_event_port_disconnect(u32 eport_id);
error_code sys_event_port_send(u32 event_port_id, u64 data1, u64 data2, u64 data3);
error_code sys_event_port_send(ppu_thread& ppu, u32 event_port_id, u64 data1, u64 data2, u64 data3);
+25 -3
View File
@@ -12,6 +12,7 @@
namespace vm { using namespace ps3; }
extern std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object&, const std::string&);
extern void ppu_unload_prx(const lv2_prx& prx);
extern void ppu_initialize(const ppu_module&);
logs::channel sys_prx("sys_prx");
@@ -24,13 +25,16 @@ static const std::unordered_map<std::string, int> s_prx_ignore
{ "/dev_flash/sys/external/libaudio.sprx", 0 },
{ "/dev_flash/sys/external/libbeisobmf.sprx", 0 },
{ "/dev_flash/sys/external/libcamera.sprx", 0 },
//{ "/dev_flash/sys/external/libgcm_sys.sprx", 0 },
{ "/dev_flash/sys/external/libgcm_sys.sprx", 0 },
{ "/dev_flash/sys/external/libgem.sprx", 0 },
{ "/dev_flash/sys/external/libhttp.sprx", 0 },
{ "/dev_flash/sys/external/libio.sprx", 0 },
{ "/dev_flash/sys/external/libmedi.sprx", 0 },
{ "/dev_flash/sys/external/libmic.sprx", 0 },
{ "/dev_flash/sys/external/libnet.sprx", 0 },
{ "/dev_flash/sys/external/libnetctl.sprx", 0 },
{ "/dev_flash/sys/external/librudp.sprx", 0 },
{ "/dev_flash/sys/external/libssl.sprx", 0 },
{ "/dev_flash/sys/external/libsysutil.sprx", 0 },
{ "/dev_flash/sys/external/libsysutil_ap.sprx", 0 },
{ "/dev_flash/sys/external/libsysutil_authdialog.sprx", 0 },
@@ -89,13 +93,31 @@ static const std::unordered_map<std::string, int> s_prx_ignore
error_code prx_load_module(std::string path, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt)
{
const auto name = path.substr(path.find_last_of('/') + 1);
const auto existing = idm::select<lv2_obj, lv2_prx>([&](u32, lv2_prx& prx)
{
if (prx.name == name && prx.path == path)
{
return true;
}
return false;
});
if (existing)
{
return CELL_PRX_ERROR_LIBRARY_FOUND;
}
if (s_prx_ignore.count(path))
{
sys_prx.warning("Ignored module: %s", path);
const auto prx = idm::make_ptr<lv2_obj, lv2_prx>();
prx->name = path.substr(path.find_last_of('/') + 1);
prx->name = name;
prx->path = path;
return not_an_error(idm::last_id());
}
@@ -233,7 +255,7 @@ error_code _sys_prx_unload_module(u32 id, u64 flags, vm::ptr<sys_prx_unload_modu
return CELL_ESRCH;
}
//Memory.Free(prx->address);
ppu_unload_prx(*prx);
//s32 result = prx->exit ? prx->exit() : CELL_OK;
+1
View File
@@ -115,6 +115,7 @@ struct lv2_prx final : lv2_obj, ppu_module
bool is_started = false;
std::unordered_map<u32, u32> specials;
std::unordered_map<u32, void*> imports;
vm::ps3::ptr<s32(u32 argc, vm::ps3::ptr<void> argv)> start = vm::null;
vm::ps3::ptr<s32(u32 argc, vm::ps3::ptr<void> argv)> stop = vm::null;
+31 -305
View File
@@ -1,108 +1,14 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/RSX/GSRender.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/ErrorCodes.h"
#include "sys_rsx.h"
#include "sys_event.h"
namespace vm { using namespace ps3; }
logs::channel sys_rsx("sys_rsx");
struct RsxDriverInfo {
be_t<u32> version_driver; // 0x0
be_t<u32> version_gpu; // 0x4
be_t<u32> memory_size; // 0x8
be_t<u32> hardware_channel; // 0xC
be_t<u32> nvcore_frequency; // 0x10
be_t<u32> memory_frequency; // 0x14
be_t<u32> unk1[4]; // 0x18 - 0x24
be_t<u32> unk2; // 0x28 -- pgraph stuff
be_t<u32> reportsNotifyOffset;// 0x2C offset to notify memory
be_t<u32> reportsOffset; // 0x30 offset to reports memory
be_t<u32> reportsReportOffset;// 0x34 offset to reports in reports memory
be_t<u32> unk3[6]; // 0x38-0x54
be_t<u32> systemModeFlags; // 0x54
u8 unk4[0x1064]; // 0x10B8
struct Head {
be_t<u64> lastFlip; // 0x0 last flip time
be_t<u32> flipFlags; // 0x8 flags to handle flip/queue
be_t<u32> unk1; // 0xC
be_t<u32> flipBufferId; // 0x10
be_t<u32> queuedBufferId; // 0x14 todo: this is definately not this variable but its 'unused' so im using it for queueId to pass to flip handler
be_t<u32> unk3; // 0x18
be_t<u32> unk6; // 0x18 possible low bits of time stamp? used in getlastVBlankTime
be_t<u64> lastSecondVTime; // 0x20 last time for second vhandler freq
be_t<u64> unk4; // 0x28
be_t<u64> vBlankCount; // 0x30
be_t<u32> unk; // 0x38 possible u32, 'flip field', top/bottom for interlaced
be_t<u32> unk5; // 0x3C possible high bits of time stamp? used in getlastVBlankTime
} head[8]; // size = 0x40, 0x200
be_t<u32> unk7; // 0x12B8
be_t<u32> unk8; // 0x12BC
be_t<u32> handlers; // 0x12C0 -- flags showing which handlers are set
be_t<u32> unk9; // 0x12C4
be_t<u32> unk10; // 0x12C8
be_t<u32> userCmdParam; // 0x12CC
be_t<u32> handler_queue; // 0x12D0
be_t<u32> unk11; // 0x12D4
be_t<u32> unk12; // 0x12D8
be_t<u32> unk13; // 0x12DC
be_t<u32> unk14; // 0x12E0
be_t<u32> unk15; // 0x12E4
be_t<u32> unk16; // 0x12E8
be_t<u32> unk17; // 0x12F0
be_t<u32> lastError; // 0x12F4 error param for cellGcmSetGraphicsHandler
// todo: theres more to this
};
template <size_t S> class Sizer { };
Sizer<sizeof(RsxDriverInfo)> foo;
static_assert(sizeof(RsxDriverInfo) == 0x12F8, "rsxSizeTest");
static_assert(sizeof(RsxDriverInfo::Head) == 0x40, "rsxHeadSizeTest");
struct RsxDmaControl {
u8 resv[0x40];
be_t<u32> put;
be_t<u32> get;
be_t<u32> ref;
be_t<u32> unk[2];
be_t<u32> unk1;
};
struct RsxSemaphore {
be_t<u32> val;
be_t<u32> pad;
be_t<u64> timestamp;
};
struct RsxNotify {
be_t<u64> timestamp;
be_t<u64> zero;
};
struct RsxReport {
be_t<u64> timestamp;
be_t<u32> val;
be_t<u32> pad;
};
struct RsxReports {
RsxSemaphore semaphore[0x100];
RsxNotify notify[64];
RsxReport report[2048];
};
be_t<u32> g_rsx_event_port{ 0 };
u32 g_driverInfo{ 0 };
// this timestamp is a complete guess, it seems 'roughly' right for now so im just leaving it
u64 rsxTimeStamp() {
return (get_system_time() / 1000000 * 0x5F5E100);
}
s32 sys_rsx_device_open()
{
sys_rsx.todo("sys_rsx_device_open()");
@@ -131,9 +37,6 @@ s32 sys_rsx_memory_allocate(vm::ptr<u32> mem_handle, vm::ptr<u64> mem_addr, u32
{
sys_rsx.todo("sys_rsx_memory_allocate(mem_handle=*0x%x, mem_addr=*0x%x, size=0x%x, flags=0x%llx, a5=0x%llx, a6=0x%llx, a7=0x%llx)", mem_handle, mem_addr, size, flags, a5, a6, a7);
*mem_handle = 1;
*mem_addr = vm::falloc(0xC0000000, size, vm::video);
return CELL_OK;
}
@@ -157,89 +60,10 @@ s32 sys_rsx_memory_free(u32 mem_handle)
* @param mem_ctx (IN): mem_ctx given by sys_rsx_memory_allocate
* @param system_mode (IN):
*/
s32 sys_rsx_context_allocate(vm::ptr<u32> context_id, vm::ptr<u64> lpar_dma_control, vm::ptr<u64> lpar_driver_info, vm::ptr<u64> lpar_reports, u64 mem_ctx, u64 system_mode)
s32 sys_rsx_context_allocate(vm::ptr<u32> context_id, vm::ptr<u32> lpar_dma_control, vm::ptr<u32> lpar_driver_info, vm::ptr<u32> lpar_reports, u64 mem_ctx, u64 system_mode)
{
sys_rsx.todo("sys_rsx_context_allocate(context_id=*0x%x, lpar_dma_control=*0x%x, lpar_driver_info=*0x%x, lpar_reports=*0x%x, mem_ctx=0x%llx, system_mode=0x%llx)",
context_id, lpar_dma_control, lpar_driver_info, lpar_reports, mem_ctx, system_mode);
vm::falloc(0x40000000, 0x10000000, vm::rsx_context);
*context_id = 0x55555555;
*lpar_dma_control = 0x40100000;
*lpar_driver_info = 0x40200000;
*lpar_reports = 0x40300000;
auto &reports = vm::_ref<RsxReports>(*lpar_reports);
std::memset(&reports, 0, sizeof(RsxReports));
for (int i = 0; i < 64; ++i)
reports.notify[i].timestamp = (u64)-1;
for (int i = 0; i < 256; ++i) {
reports.semaphore[i].val = 0x1337C0D3;
reports.semaphore[i].pad = 0x1337BABE;
reports.semaphore[i].timestamp = (u64)-1; // technically different but should be fine
}
for (int i = 0; i < 2048; ++i)
reports.report[i].timestamp = (u64)-1;
auto &sysReports = vm::_ref<RsxSemaphore>(0x40000030);
// slight hack for testing....
sysReports.val = 1;
auto &driverInfo = vm::_ref<RsxDriverInfo>(*lpar_driver_info);
std::memset(&driverInfo, 0, sizeof(RsxDriverInfo));
driverInfo.version_driver = 0x211;
driverInfo.version_gpu = 0x5c;
driverInfo.memory_size = 0xFE00000;
driverInfo.nvcore_frequency = 500000000; // 0x1DCD6500
driverInfo.memory_frequency = 650000000; // 0x26BE3680
driverInfo.reportsNotifyOffset = 0x1000;
driverInfo.reportsOffset = 0;
driverInfo.reportsReportOffset = 0x1400;
driverInfo.systemModeFlags = system_mode;
driverInfo.hardware_channel = 1; // * i think* this 1 for games, 0 for vsh
g_driverInfo = *lpar_driver_info;
auto &dmaControl = vm::_ref<RsxDmaControl>(*lpar_dma_control);
dmaControl.get = 0;
dmaControl.put = 0;
dmaControl.ref = 0xFFFFFFFF;
if (false/*system_mode == CELL_GCM_SYSTEM_MODE_IOMAP_512MB*/)
RSXIOMem.SetRange(0, 0x20000000 /*512MB*/);
else
RSXIOMem.SetRange(0, 0x10000000 /*256MB*/);
sys_event_queue_attribute_t attr;
attr.protocol = SYS_SYNC_PRIORITY;
attr.type = SYS_PPU_QUEUE;
auto queueId = vm::make_var<u32>(0);
sys_event_queue_create(queueId, vm::make_var(attr), 0, 0x20);
driverInfo.handler_queue = queueId->value();
sys_event_port_create(queueId, SYS_EVENT_PORT_LOCAL, 0);
sys_event_port_connect_local(queueId->value(), driverInfo.handler_queue);
g_rsx_event_port = queueId->value();
const auto render = fxm::get<GSRender>();
render->ctrl = vm::_ptr<CellGcmControl>(*lpar_dma_control);
//render->intr_thread = idm::make_ptr<ppu_thread>("_gcm_intr_thread", 1, 0x4000);
//render->intr_thread->run();
//render->ctxt_addr = 0;
render->gcm_buffers.set((vm::alloc(sizeof(CellGcmDisplayInfo) * 8, vm::main)));
render->zculls_addr = vm::alloc(sizeof(CellGcmZcullInfo) * 8, vm::main);
render->gcm_buffers_count = 0;
render->gcm_current_buffer = 0;
render->main_mem_addr = 0;
render->label_addr = *lpar_reports;
render->init(0x30100000, 0x200000, *lpar_dma_control, 0xC0000000);
sys_rsx.todo("sys_rsx_context_allocate(context_id=*0x%x, lpar_dma_control=*0x%x, lpar_driver_info=*0x%x, lpar_reports=*0x%x, mem_ctx=0x%llx, system_mode=0x%llx)",
context_id, lpar_dma_control, lpar_driver_info, lpar_reports, mem_ctx, system_mode);
return CELL_OK;
}
@@ -266,10 +90,8 @@ s32 sys_rsx_context_free(u32 context_id)
s32 sys_rsx_context_iomap(u32 context_id, u32 io, u32 ea, u32 size, u64 flags)
{
sys_rsx.todo("sys_rsx_context_iomap(context_id=0x%x, io=0x%x, ea=0x%x, size=0x%x, flags=0x%llx)", context_id, io, ea, size, flags);
if (RSXIOMem.Map(ea, size, io))
return CELL_OK;
LOG_ERROR(RSX, "rsx_iomap failed");
return CELL_EINVAL;
return CELL_OK;
}
/*
@@ -279,13 +101,11 @@ s32 sys_rsx_context_iomap(u32 context_id, u32 io, u32 ea, u32 size, u64 flags)
* @param io_addr (IN): IO address. E.g. 0x00600000 (Start page 6)
* @param size (IN): Size to unmap in byte. E.g. 0x00200000
*/
s32 sys_rsx_context_iounmap(u32 context_id, u32 io_addr, u32 a3, u32 size)
s32 sys_rsx_context_iounmap(u32 context_id, u32 a2, u32 io_addr, u32 size)
{
sys_rsx.todo("sys_rsx_context_iounmap(context_id=0x%x, io_addr=0x%x, a3=0x%x, size=0x%x)", context_id, io_addr, a3, size);
if (RSXIOMem.UnmapAddress(io_addr, size))
return CELL_OK;
LOG_ERROR(RSX, "rsx_iounmap failed");
return CELL_EINVAL;
sys_rsx.todo("sys_rsx_context_iounmap(context_id=0x%x, a2=0x%x, io_addr=0x%x, size=0x%x)", context_id, a2, io_addr, size);
return CELL_OK;
}
/*
@@ -299,113 +119,40 @@ s32 sys_rsx_context_iounmap(u32 context_id, u32 io_addr, u32 a3, u32 size)
*/
s32 sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 a4, u64 a5, u64 a6)
{
if (package_id != 0xFED)
sys_rsx.todo("sys_rsx_context_attribute(context_id=0x%x, package_id=0x%x, a3=0x%llx, a4=0x%llx, a5=0x%llx, a6=0x%llx)", context_id, package_id, a3, a4, a5, a6);
// hle/lle protection
if (g_driverInfo == 0)
return CELL_OK;
// todo: these event ports probly 'shouldnt' be here as i think its supposed to be interrupts that are sent from rsx somewhere in lv1
const auto render = fxm::get<GSRender>();
auto &driverInfo = vm::_ref<RsxDriverInfo>(g_driverInfo);
switch(package_id)
{
case 0x001: // FIFO
render->ctrl->get = a3;
render->ctrl->put = a4;
break;
case 0x100: // Display mode set
break;
case 0x101: // Display sync set, cellGcmSetFlipMode
break;
break;
case 0x101: // Display sync
break;
case 0x102: // Display flip
driverInfo.head[a3].flipFlags |= 0x80000000;
driverInfo.head[a3].lastFlip = rsxTimeStamp(); // should rsxthread set this?
// lets give this a shot for giving bufferid back to gcm
driverInfo.head[a3].flipBufferId = driverInfo.head[a3].queuedBufferId;
// seems gcmSysWaitLabel uses this offset, so lets set it to 0 every flip
vm::_ref<u32>(0x40300010) = 0;
if (a3 == 0)
sys_event_port_send(g_rsx_event_port, 0, (1 << 3), 0);
if (a3 == 1)
sys_event_port_send(g_rsx_event_port, 0, (1 << 4), 0);
break;
case 0x103: // Display Queue
driverInfo.head[a3].queuedBufferId = a4;
driverInfo.head[a3].flipFlags |= 0x40000000 | (1 << a4);
if (a3 == 0)
sys_event_port_send(g_rsx_event_port, 0, (1 << 5), 0);
if (a3 == 1)
sys_event_port_send(g_rsx_event_port, 0, (1 << 6), 0);
case 0x103: // ?
break;
case 0x104: // Display buffer
{
u8 id = a3 & 0xFF;
u32 width = (a4 >> 32) & 0xFFFFFFFF;
u32 height = a4 & 0xFFFFFFFF;
u32 pitch = (a5 >> 32) & 0xFFFFFFFF;
u32 offset = a5 & 0xFFFFFFFF;
if (id > 7)
return -17;
render->gcm_buffers[id].width = width;
render->gcm_buffers[id].height = height;
render->gcm_buffers[id].pitch = pitch;
render->gcm_buffers[id].offset = offset;
if (id + 1 > render->gcm_buffers_count)
render->gcm_buffers_count = id + 1;
}
break;
case 0x105: // destroy buffer?
break;
break;
case 0x106: // ? (Used by cellGcmInitPerfMon)
break;
case 0x108: // ? set interrupt freq?
break;
case 0x10a: // ? Involved in managing flip status through cellGcmResetFlipStatus
{
if (a3 > 7)
return -17;
u32 flipStatus = driverInfo.head[a3].flipFlags;
flipStatus = (flipStatus & a4) | a5;
driverInfo.head[a3].flipFlags = flipStatus;
}
break;
case 0x10D: // Called by cellGcmInitCursor
break;
case 0x10a: // ?
break;
case 0x300: // Tiles
{
//a4 high bits = ret.tile = (location + 1) | (bank << 4) | ((offset / 0x10000) << 16) | (location << 31);
//a4 low bits = ret.limit = ((offset + size - 1) / 0x10000) << 16 | (location << 31);
//a5 high bits = ret.pitch = (pitch / 0x100) << 8;
//a5 low bits = ret.format = base | ((base + ((size - 1) / 0x10000)) << 13) | (comp << 26) | (1 << 30);
auto& tile = render->tiles[a3];
tile.location = ((a4 >> 32) & 0xF) - 1;
tile.offset = ((((a4 >> 32) & 0xFFFFFFFF) >> 16) * 0x10000);
tile.size = ((((a4 & 0x7FFFFFFF) >> 16) + 1) * 0x10000) - tile.offset; // size is wrong,
tile.pitch = (((a5 >> 32) & 0xFFFFFFFF) >> 8) * 0x100;
tile.comp = ((a5 & 0xFFFFFFFF) >> 26) & 0xF;
tile.base = (a5 & 0xFFFFFFFF) & 0x7FF;
tile.bank = (((a4 >> 32) & 0xFFFFFFFF) >> 4) & 0xF;
tile.binded = a5 != 0;
sys_rsx.error("package 0x300 tile, index=%d, location=%d, offset=%d, size=%d, pitch=%d, comp=%d, base=%d, bank=%d",
a3, tile.location, tile.offset, tile.size, tile.pitch, tile.comp, tile.base, tile.bank);
}
break;
break;
case 0x301: // Depth-buffer (Z-cull)
break;
case 0x302: // something with zcull
break;
case 0x600: // Framebuffer setup
break;
@@ -415,24 +162,6 @@ s32 sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 a4, u6
case 0x602: // Framebuffer blit sync
break;
case 0x603: // Framebuffer close
break;
case 0xFED: // hack: vblank command
// todo: this is wrong and should be 'second' vblank handler and freq
// although gcmSys seems just hardcoded at 1, so w/e
driverInfo.head[a3].vBlankCount++;
driverInfo.head[a3].lastSecondVTime = rsxTimeStamp();
sys_event_port_send(g_rsx_event_port, 0, (1 << 1), 0);
sys_event_port_send(g_rsx_event_port, 0, (1 << 11), 0); // second vhandler
break;
case 0xFEF: // hack: user command
// 'custom' invalid package id for now
// as i think we need custom lv1 interrupts to handle this accurately
// this also should probly be set by rsxthread
driverInfo.userCmdParam = a4;
sys_event_port_send(g_rsx_event_port, 0, (1 << 7), 0);
break;
default:
return CELL_EINVAL;
}
@@ -446,19 +175,19 @@ s32 sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 a4, u6
* @param a2 (OUT): Unused?
* @param dev_id (IN): An immediate value and always 8. (cellGcmInitPerfMon uses 11, 10, 9, 7, 12 successively).
*/
s32 sys_rsx_device_map(vm::ptr<u64> addr, vm::ptr<u64> a2, u32 dev_id)
s32 sys_rsx_device_map(vm::ptr<u32> addr, vm::ptr<u32> a2, u32 dev_id)
{
sys_rsx.todo("sys_rsx_device_map(addr=*0x%x, a2=*0x%x, dev_id=0x%x)", addr, a2, dev_id);
if (dev_id != 8) {
// TODO: lv1 related
fmt::throw_exception("sys_rsx_device_map: Invalid dev_id %d", dev_id);
if (dev_id > 15) {
// TODO: Throw RSX error
return CELL_EINVAL;
}
// a2 seems to not be referenced in cellGcmSys
*a2 = 0;
*addr = 0x40000000;
if (dev_id == 0 || dev_id > 8) {
// TODO: lv1 related so we may ignore it.
// if (something) { return CELL_EPERM; }
}
return CELL_OK;
}
@@ -474,12 +203,9 @@ s32 sys_rsx_device_unmap(u32 dev_id)
return CELL_OK;
}
/*
* lv2 SysCall 677 (0x2A5): sys_rsx_attribute
*/
s32 sys_rsx_attribute(u32 packageId, u32 a2, u32 a3, u32 a4, u32 a5)
s32 sys_rsx_attribute(u32 a1, u32 a2, u32 a3, u32 a4, u32 a5)
{
sys_rsx.todo("sys_rsx_attribute(packageId=0x%x, a2=0x%x, a3=0x%x, a4=0x%x, a5=0x%x)", packageId, a2, a3, a4, a5);
sys_rsx.todo("sys_rsx_attribute(a1=0x%x, a2=0x%x, a3=0x%x, a4=0x%x, a5=0x%x)", a1, a2, a3, a4, a5);
return CELL_OK;
}
+2 -2
View File
@@ -5,11 +5,11 @@ s32 sys_rsx_device_open();
s32 sys_rsx_device_close();
s32 sys_rsx_memory_allocate(vm::ps3::ptr<u32> mem_handle, vm::ps3::ptr<u64> mem_addr, u32 size, u64 flags, u64 a5, u64 a6, u64 a7);
s32 sys_rsx_memory_free(u32 mem_handle);
s32 sys_rsx_context_allocate(vm::ps3::ptr<u32> context_id, vm::ps3::ptr<u64> lpar_dma_control, vm::ps3::ptr<u64> lpar_driver_info, vm::ps3::ptr<u64> lpar_reports, u64 mem_ctx, u64 system_mode);
s32 sys_rsx_context_allocate(vm::ps3::ptr<u32> context_id, vm::ps3::ptr<u32> lpar_dma_control, vm::ps3::ptr<u32> lpar_driver_info, vm::ps3::ptr<u32> lpar_reports, u64 mem_ctx, u64 system_mode);
s32 sys_rsx_context_free(u32 context_id);
s32 sys_rsx_context_iomap(u32 context_id, u32 io, u32 ea, u32 size, u64 flags);
s32 sys_rsx_context_iounmap(u32 context_id, u32 a2, u32 io_addr, u32 size);
s32 sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 a4, u64 a5, u64 a6);
s32 sys_rsx_device_map(vm::ps3::ptr<u64> addr, vm::ps3::ptr<u64> a2, u32 dev_id);
s32 sys_rsx_device_map(vm::ps3::ptr<u32> addr, vm::ps3::ptr<u32> a2, u32 dev_id);
s32 sys_rsx_device_unmap(u32 dev_id);
s32 sys_rsx_attribute(u32 a1, u32 a2, u32 a3, u32 a4, u32 a5);
+42 -31
View File
@@ -34,24 +34,13 @@ void sys_spu_image::load(const fs::file& stream)
const u32 addr = this->segs.addr() + 4096;
sha1_context ctx;
u8 output[20];
sha1_starts(&ctx);
sha1_update(&ctx, reinterpret_cast<const u8*>(&obj.header), sizeof(obj.header));
for (const auto& shdr : obj.shdrs)
{
sha1_update(&ctx, reinterpret_cast<const u8*>(&shdr), sizeof(spu_exec_object::shdr_t));
LOG_NOTICE(SPU, "** Section: sh_type=0x%x, addr=0x%llx, size=0x%llx, flags=0x%x", shdr.sh_type, shdr.sh_addr, shdr.sh_size, shdr.sh_flags);
}
for (const auto& prog : obj.progs)
{
sha1_update(&ctx, reinterpret_cast<const u8*>(&prog), sizeof(spu_exec_object::phdr_t));
sha1_update(&ctx, reinterpret_cast<const u8*>(prog.bin.data()), prog.bin.size());
LOG_NOTICE(SPU, "** Segment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, flags=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_flags);
if (prog.p_type == SYS_SPU_SEGMENT_TYPE_COPY)
@@ -85,22 +74,6 @@ void sys_spu_image::load(const fs::file& stream)
LOG_ERROR(SPU, "Unknown program type (0x%x)", prog.p_type);
}
}
sha1_finish(&ctx, output);
// Format patch name
std::string hash("spu-");
for (u8 x : output) fmt::append(hash, "%02x", x);
LOG_NOTICE(LOADER, "Loaded SPU image: %s", hash);
// Apply the patch
fxm::check_unlocked<patch_engine>()->apply(hash, vm::g_base_addr + addr);
if (!Emu.GetTitleID().empty())
{
// Alternative patch
fxm::check_unlocked<patch_engine>()->apply(Emu.GetTitleID() + '-' + hash, vm::g_base_addr + addr);
}
}
void sys_spu_image::free()
@@ -113,15 +86,29 @@ void sys_spu_image::free()
void sys_spu_image::deploy(u32 loc)
{
// Segment info dump
std::string dump;
// Executable hash
sha1_context sha;
sha1_starts(&sha);
u8 sha1_hash[20];
for (int i = 0; i < nsegs; i++)
{
auto& seg = segs[i];
LOG_NOTICE(SPU, "*** Deploy: t=0x%x, ls=0x%x, size=0x%x, addr=0x%x", seg.type, seg.ls, seg.size, seg.addr);
fmt::append(dump, "\n\t[%d] t=0x%x, ls=0x%x, size=0x%x, addr=0x%x", i, seg.type, seg.ls, seg.size, seg.addr);
// Hash big-endian values
sha1_update(&sha, (uchar*)&seg.type, sizeof(seg.type));
sha1_update(&sha, (uchar*)&seg.size, sizeof(seg.size));
if (seg.type == SYS_SPU_SEGMENT_TYPE_COPY)
{
std::memcpy(vm::base(loc + seg.ls), vm::base(seg.addr), seg.size);
sha1_update(&sha, (uchar*)&seg.ls, sizeof(seg.ls));
sha1_update(&sha, vm::g_base_addr + seg.addr, seg.size);
}
else if (seg.type == SYS_SPU_SEGMENT_TYPE_FILL)
{
@@ -131,8 +118,32 @@ void sys_spu_image::deploy(u32 loc)
}
std::fill_n(vm::_ptr<u32>(loc + seg.ls), seg.size / 4, seg.addr);
sha1_update(&sha, (uchar*)&seg.ls, sizeof(seg.ls));
sha1_update(&sha, (uchar*)&seg.addr, sizeof(seg.addr));
}
}
sha1_finish(&sha, sha1_hash);
// Format patch name
std::string hash("SPU-0000000000000000000000000000000000000000");
for (u32 i = 0; i < sizeof(sha1_hash); i++)
{
constexpr auto pal = "0123456789abcdef";
hash[4 + i * 2] = pal[sha1_hash[i] >> 4];
hash[5 + i * 2] = pal[sha1_hash[i] & 15];
}
// Apply the patch
auto applied = fxm::check_unlocked<patch_engine>()->apply(hash, vm::g_base_addr + loc);
if (!Emu.GetTitleID().empty())
{
// Alternative patch
applied += fxm::check_unlocked<patch_engine>()->apply(Emu.GetTitleID() + '-' + hash, vm::g_base_addr + loc);
}
LOG_NOTICE(LOADER, "Loaded SPU image: %s (<- %u)%s", hash, applied, dump);
}
error_code sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu)
@@ -203,7 +214,7 @@ error_code sys_spu_thread_initialize(vm::ptr<u32> thread, u32 group_id, u32 spu_
group->threads[spu_num] = std::move(spu);
group->args[spu_num] = {arg->arg1, arg->arg2, arg->arg3, arg->arg4};
group->imgs[spu_num] = img;
group->imgs[spu_num] = *img;
if (++group->init == group->num)
{
@@ -345,9 +356,9 @@ error_code sys_spu_thread_group_start(ppu_thread& ppu, u32 id)
auto& args = group->args[thread->index];
auto& img = group->imgs[thread->index];
img->deploy(thread->offset);
img.deploy(thread->offset);
thread->pc = img->entry_point;
thread->pc = img.entry_point;
thread->cpu_init();
thread->gpr[3] = v128::from64(0, args[0]);
thread->gpr[4] = v128::from64(0, args[1]);
+1 -1
View File
@@ -153,7 +153,7 @@ struct lv2_spu_group
cond_variable cv; // used to signal waiting PPU thread
std::array<std::shared_ptr<SPUThread>, 256> threads; // SPU Threads
std::array<vm::ps3::ptr<sys_spu_image>, 256> imgs; // SPU Images
std::array<sys_spu_image, 256> imgs; // SPU Images
std::array<std::array<u64, 4>, 256> args; // SPU Thread Arguments
std::weak_ptr<lv2_event_queue> ep_run; // port for SYS_SPU_THREAD_GROUP_EVENT_RUN events
+2 -2
View File
@@ -2,7 +2,7 @@
struct GameInfo
{
std::string root;
std::string path;
std::string icon_path;
std::string name;
@@ -24,7 +24,7 @@ struct GameInfo
void Reset()
{
root = "";
path = "";
name = "Unknown";
serial = "Unknown";
+2 -2
View File
@@ -55,13 +55,13 @@ bool VirtualMemoryBlock::Map(u32 realaddr, u32 size, u32 addr)
return false;
}
/*for (u32 i = 0; i<m_mapped_memory.size(); ++i)
for (u32 i = 0; i<m_mapped_memory.size(); ++i)
{
if (addr >= m_mapped_memory[i].addr && addr + size - 1 <= m_mapped_memory[i].addr + m_mapped_memory[i].size - 1)
{
return false;
}
}*/
}
m_mapped_memory.emplace_back(addr, realaddr, size);
return true;
+4 -3
View File
@@ -27,9 +27,9 @@
namespace vm
{
static u8* memory_reserve_4GiB(std::uintptr_t addr = 0)
static u8* memory_reserve_4GiB(std::uintptr_t _addr = 0)
{
for (u64 addr = 0x100000000;; addr += 0x100000000)
for (u64 addr = _addr + 0x100000000;; addr += 0x100000000)
{
if (auto ptr = utils::memory_reserve(0x100000000, (void*)addr))
{
@@ -461,8 +461,10 @@ namespace vm
#ifdef _WIN32
verify(__func__), ::VirtualFree(real_addr, size, MEM_DECOMMIT);
verify(__func__), ::VirtualFree(exec_addr, size, MEM_DECOMMIT);
#else
verify(__func__), ::mmap(real_addr, size, PROT_NONE, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
verify(__func__), ::mmap(exec_addr, size, PROT_NONE, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
#endif
}
@@ -781,7 +783,6 @@ namespace vm
{
std::make_shared<block_t>(0x00010000, 0x1FFF0000), // main
std::make_shared<block_t>(0x20000000, 0x10000000), // user
std::make_shared<block_t>(0x40000000, 0x30000000), // rsx contexts
std::make_shared<block_t>(0xC0000000, 0x10000000), // video
std::make_shared<block_t>(0xD0000000, 0x10000000), // stack
std::make_shared<block_t>(0xE0000000, 0x20000000), // SPU reserved
-1
View File
@@ -16,7 +16,6 @@ namespace vm
{
main,
user_space,
rsx_context,
video,
stack,
+29 -5
View File
@@ -1,10 +1,13 @@
#include "stdafx.h"
#include "Utilities/sysinfo.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "ARMv7Thread.h"
#include "ARMv7Interpreter.h"
const bool s_use_rtm = utils::has_rtm();
using namespace arm_code::arm_encoding_alias;
#define ARG(arg, ...) const u32 arg = args::arg::extract(__VA_ARGS__);
@@ -2091,13 +2094,34 @@ void arm_interpreter::STREX(ARMv7Thread& cpu, const u32 op, const u32 cond)
return;
}
vm::writer_lock lock(0);
bool result;
const bool result = cpu.rtime == vm::reservation_acquire(addr, cpu.rtime) && data.compare_and_swap_test(cpu.rdata, value);
if (result)
if (s_use_rtm && utils::transaction_enter())
{
vm::reservation_update(addr, sizeof(u32));
if (!vm::reader_lock{vm::try_to_lock})
{
_xabort(0);
}
result = cpu.rtime == vm::reservation_acquire(addr, sizeof(u32)) && data.compare_and_swap_test(cpu.rdata, value);
if (result)
{
vm::reservation_update(addr, sizeof(u32));
}
_xend();
}
else
{
vm::writer_lock lock(0);
result = cpu.rtime == vm::reservation_acquire(addr, sizeof(u32)) && data.compare_and_swap_test(cpu.rdata, value);
if (result)
{
vm::reservation_update(addr, sizeof(u32));
}
}
cpu.raddr = 0;
+79 -5
View File
@@ -93,7 +93,12 @@ namespace rsx
auto It = m_render_targets_storage.find(address);
// TODO: Fix corner cases
// This doesn't take overlapping surface(s) into account.
surface_storage_type old_surface_storage;
surface_storage_type new_surface_storage;
surface_type old_surface = nullptr;
surface_type new_surface = nullptr;
if (It != m_render_targets_storage.end())
{
surface_storage_type &rtt = It->second;
@@ -104,10 +109,43 @@ namespace rsx
}
old_surface = Traits::get(rtt);
invalidated_resources.push_back(std::move(rtt));
old_surface_storage = std::move(rtt);
m_render_targets_storage.erase(address);
}
//Search invalidated resources for a suitable surface
for (auto It = invalidated_resources.begin(); It != invalidated_resources.end(); It++)
{
auto &rtt = *It;
if (Traits::rtt_has_format_width_height(rtt, color_format, width, height, true))
{
new_surface_storage = std::move(rtt);
if (old_surface)
//Exchange this surface with the invalidated one
rtt = std::move(old_surface_storage);
else
//rtt is now empty - erase it
invalidated_resources.erase(It);
new_surface = Traits::get(new_surface_storage);
Traits::invalidate_rtt_surface_contents(command_list, new_surface, old_surface, true);
Traits::prepare_rtt_for_drawing(command_list, new_surface);
break;
}
}
if (old_surface != nullptr && new_surface == nullptr)
//This was already determined to be invalid and is excluded from testing above
invalidated_resources.push_back(std::move(old_surface_storage));
if (new_surface != nullptr)
{
//New surface was found among existing surfaces
m_render_targets_storage[address] = std::move(new_surface_storage);
return new_surface;
}
m_render_targets_storage[address] = Traits::create_new_surface(address, color_format, width, height, old_surface, std::forward<Args>(extra_params)...);
return Traits::get(m_render_targets_storage[address]);
}
@@ -119,7 +157,11 @@ namespace rsx
surface_depth_format depth_format, size_t width, size_t height,
Args&&... extra_params)
{
surface_storage_type old_surface_storage;
surface_storage_type new_surface_storage;
surface_type old_surface = nullptr;
surface_type new_surface = nullptr;
auto It = m_depth_stencil_storage.find(address);
if (It != m_depth_stencil_storage.end())
{
@@ -131,10 +173,42 @@ namespace rsx
}
old_surface = Traits::get(ds);
invalidated_resources.push_back(std::move(ds));
old_surface_storage = std::move(ds);
m_depth_stencil_storage.erase(address);
}
//Search invalidated resources for a suitable surface
for (auto It = invalidated_resources.begin(); It != invalidated_resources.end(); It++)
{
auto &ds = *It;
if (Traits::ds_has_format_width_height(ds, depth_format, width, height, true))
{
new_surface_storage = std::move(ds);
if (old_surface)
//Exchange this surface with the invalidated one
ds = std::move(old_surface_storage);
else
invalidated_resources.erase(It);
new_surface = Traits::get(new_surface_storage);
Traits::prepare_ds_for_drawing(command_list, new_surface);
Traits::invalidate_depth_surface_contents(command_list, new_surface, old_surface, true);
break;
}
}
if (old_surface != nullptr && new_surface == nullptr)
//This was already determined to be invalid and is excluded from testing above
invalidated_resources.push_back(std::move(old_surface_storage));
if (new_surface != nullptr)
{
//New surface was found among existing surfaces
m_depth_stencil_storage[address] = std::move(new_surface_storage);
return new_surface;
}
m_depth_stencil_storage[address] = Traits::create_new_surface(address, depth_format, width, height, old_surface, std::forward<Args>(extra_params)...);
return Traits::get(m_depth_stencil_storage[address]);
}
@@ -358,10 +432,10 @@ namespace rsx
void invalidate_surface_cache_data(command_list_type command_list)
{
for (auto &rtt : m_render_targets_storage)
Traits::invalidate_rtt_surface_contents(command_list, Traits::get(std::get<1>(rtt)));
Traits::invalidate_rtt_surface_contents(command_list, Traits::get(std::get<1>(rtt)), nullptr, false);
for (auto &ds : m_depth_stencil_storage)
Traits::invalidate_depth_surface_contents(command_list, Traits::get(std::get<1>(ds)));
Traits::invalidate_depth_surface_contents(command_list, Traits::get(std::get<1>(ds)), nullptr, true);
}
};
}
}
+3 -4
View File
@@ -223,9 +223,8 @@ namespace
const std::vector<std::pair<u32, u32>>& vertex_ranges, d3d12_data_heap& m_buffer_data)
{
size_t index_count = std::accumulate(
vertex_ranges.begin(), vertex_ranges.end(), 0, [](size_t acc, const auto& pair) {
return acc + get_index_count(
rsx::method_registers.current_draw_clause.primitive, pair.second);
vertex_ranges.begin(), vertex_ranges.end(), 0ll, [](size_t acc, const auto& pair) {
return acc + get_index_count(rsx::method_registers.current_draw_clause.primitive, pair.second);
});
// Alloc
@@ -236,7 +235,7 @@ namespace
void* mapped_buffer =
m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
size_t vertex_count = 0;
u32 vertex_count = 0;
for (const auto& pair : vertex_ranges)
vertex_count += pair.second;
+11 -5
View File
@@ -324,6 +324,17 @@ void D3D12GSRender::end()
{
std::chrono::time_point<steady_clock> start_duration = steady_clock::now();
std::chrono::time_point<steady_clock> program_load_start = steady_clock::now();
load_program();
std::chrono::time_point<steady_clock> program_load_end = steady_clock::now();
m_timers.program_load_duration += std::chrono::duration_cast<std::chrono::microseconds>(program_load_end - program_load_start).count();
if (!m_fragment_program.valid)
{
rsx::thread::end();
return;
}
std::chrono::time_point<steady_clock> rtt_duration_start = steady_clock::now();
prepare_render_targets(get_current_resource_storage().command_list.Get());
@@ -344,11 +355,6 @@ void D3D12GSRender::end()
std::chrono::time_point<steady_clock> vertex_index_duration_end = steady_clock::now();
m_timers.vertex_index_duration += std::chrono::duration_cast<std::chrono::microseconds>(vertex_index_duration_end - vertex_index_duration_start).count();
std::chrono::time_point<steady_clock> program_load_start = steady_clock::now();
load_program();
std::chrono::time_point<steady_clock> program_load_end = steady_clock::now();
m_timers.program_load_duration += std::chrono::duration_cast<std::chrono::microseconds>(program_load_end - program_load_start).count();
get_current_resource_storage().command_list->SetGraphicsRootSignature(m_shared_root_signature.Get());
get_current_resource_storage().command_list->OMSetStencilRef(rsx::method_registers.stencil_func_ref());
@@ -56,6 +56,9 @@ void D3D12GSRender::load_program()
m_vertex_program = get_current_vertex_program();
m_fragment_program = get_current_fragment_program(rtt_lookup_func);
if (!m_fragment_program.valid)
return;
D3D12PipelineProperties prop = {};
prop.Topology = get_primitive_topology_type(rsx::method_registers.current_draw_clause.primitive);
@@ -175,16 +175,9 @@ void D3D12GSRender::prepare_render_targets(ID3D12GraphicsCommandList *copycmdlis
rsx::method_registers.clear_color_b() / 255.f,
rsx::method_registers.clear_color_a() / 255.f,
};
u32 clip_width = rsx::method_registers.surface_clip_width();
u32 clip_height = rsx::method_registers.surface_clip_height();
if (clip_height == 0 || clip_width == 0)
return;
m_rtts.prepare_render_target(copycmdlist,
rsx::method_registers.surface_color(), rsx::method_registers.surface_depth_fmt(),
clip_width, clip_height,
rsx::method_registers.surface_clip_width(), rsx::method_registers.surface_clip_height(),
rsx::method_registers.surface_color_target(),
get_color_surface_addresses(), get_zeta_surface_address(),
m_device.Get(), clear_color, 1.f, 0);
+6 -4
View File
@@ -116,28 +116,30 @@ struct render_target_traits
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(ds, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_GENERIC_READ));
}
static
void invalidate_rtt_surface_contents(
gsl::not_null<ID3D12GraphicsCommandList*>,
ID3D12Resource*)
ID3D12Resource*, ID3D12Resource*, bool)
{}
static
void invalidate_depth_surface_contents(
gsl::not_null<ID3D12GraphicsCommandList*>,
ID3D12Resource*)
ID3D12Resource*, ID3D12Resource*, bool)
{
//TODO
}
static
bool rtt_has_format_width_height(const ComPtr<ID3D12Resource> &rtt, surface_color_format surface_color_format, size_t width, size_t height)
bool rtt_has_format_width_height(const ComPtr<ID3D12Resource> &rtt, surface_color_format surface_color_format, size_t width, size_t height, bool=false)
{
DXGI_FORMAT dxgi_format = get_color_surface_format(surface_color_format);
return rtt->GetDesc().Format == dxgi_format && rtt->GetDesc().Width == width && rtt->GetDesc().Height == height;
}
static
bool ds_has_format_width_height(const ComPtr<ID3D12Resource> &rtt, surface_depth_format, size_t width, size_t height)
bool ds_has_format_width_height(const ComPtr<ID3D12Resource> &rtt, surface_depth_format, size_t width, size_t height, bool=false)
{
//TODO: Check format
return rtt->GetDesc().Width == width && rtt->GetDesc().Height == height;
+3 -13
View File
@@ -7,21 +7,11 @@
struct CellGcmControl
{
u8 resv[0x40];
atomic_be_t<u32> put;
atomic_be_t<u32> get;
atomic_be_t<u32> ref;
be_t<u32> unk[2];
be_t<u32> unk1;
atomic_be_t<u32> put;
atomic_be_t<u32> get;
atomic_be_t<u32> ref;
};
/*struct CellGcmControl
{
atomic_be_t<u32> put;
atomic_be_t<u32> get;
atomic_be_t<u32> ref;
};*/
struct CellGcmConfig
{
be_t<u32> localAddress;
+57 -22
View File
@@ -322,17 +322,15 @@ namespace
void GLGSRender::end()
{
if (skip_frame || !framebuffer_status_valid)
std::chrono::time_point<steady_clock> program_start = steady_clock::now();
//Load program here since it is dependent on vertex state
if (skip_frame || !framebuffer_status_valid || !load_program())
{
rsx::thread::end();
return;
}
std::chrono::time_point<steady_clock> program_start = steady_clock::now();
//Load program here since it is dependent on vertex state
load_program();
std::chrono::time_point<steady_clock> program_stop = steady_clock::now();
m_begin_time += (u32)std::chrono::duration_cast<std::chrono::microseconds>(program_stop - program_start).count();
@@ -364,44 +362,80 @@ void GLGSRender::end()
surface->old_contents = nullptr;
};
//Check if we have any 'recycled' surfaces in memory and if so, clear them
std::vector<int> buffers_to_clear;
bool clear_all_color = true;
bool clear_depth = false;
for (int index = 0; index < 4; index++)
{
if (std::get<0>(m_rtts.m_bound_render_targets[index]) != 0)
{
if (std::get<1>(m_rtts.m_bound_render_targets[index])->cleared())
clear_all_color = false;
else
buffers_to_clear.push_back(index);
}
}
gl::render_target *ds = std::get<1>(m_rtts.m_bound_depth_stencil);
if (ds && !ds->cleared())
{
//Temporarily disable pixel tests
glDisable(GL_SCISSOR_TEST);
glDepthMask(GL_TRUE);
glClearDepth(1.0);
glClearStencil(255);
clear_depth = true;
}
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//Temporarily disable pixel tests
glDisable(GL_SCISSOR_TEST);
if (g_cfg.video.strict_rendering_mode)
if (clear_depth || buffers_to_clear.size() > 0)
{
GLenum mask = 0;
if (clear_depth)
{
//Copy previous data if any
if (ds->old_contents != nullptr)
copy_rtt_contents(ds);
glDepthMask(GL_TRUE);
glClearDepth(1.0);
glClearStencil(255);
mask |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
}
glDepthMask(rsx::method_registers.depth_write_enabled());
glEnable(GL_SCISSOR_TEST);
if (clear_all_color)
mask |= GL_COLOR_BUFFER_BIT;
glClear(mask);
if (buffers_to_clear.size() > 0 && !clear_all_color)
{
GLfloat colors[] = { 0.f, 0.f, 0.f, 0.f };
//It is impossible for the render target to be typa A or B here (clear all would have been flagged)
for (auto &i: buffers_to_clear)
glClearBufferfv(draw_fbo.id(), i, colors);
}
if (clear_depth)
glDepthMask(rsx::method_registers.depth_write_enabled());
ds->set_cleared();
}
if (g_cfg.video.strict_rendering_mode)
{
if (ds->old_contents != nullptr)
copy_rtt_contents(ds);
for (auto &rtt : m_rtts.m_bound_render_targets)
{
if (std::get<0>(rtt) != 0)
{
auto surface = std::get<1>(rtt);
if (!surface->cleared() && surface->old_contents != nullptr)
if (surface->old_contents != nullptr)
copy_rtt_contents(surface);
}
}
}
glEnable(GL_SCISSOR_TEST);
std::chrono::time_point<steady_clock> textures_start = steady_clock::now();
//Setup textures
@@ -463,7 +497,6 @@ void GLGSRender::end()
}
else
{
//LOG_ERROR(RSX, "No work is needed for this draw call! Muhahahahahahaha");
skip_upload = true;
}
@@ -841,8 +874,10 @@ bool GLGSRender::load_program()
return std::make_tuple(true, surface->get_native_pitch());
};
RSXVertexProgram vertex_program = get_current_vertex_program();
RSXFragmentProgram fragment_program = get_current_fragment_program(rtt_lookup_func);
if (!fragment_program.valid) return false;
RSXVertexProgram vertex_program = get_current_vertex_program();
u32 unnormalized_rtts = 0;
+2
View File
@@ -173,6 +173,8 @@ OPENGL_PROC(PFNGLMULTIDRAWARRAYSPROC, MultiDrawArrays);
OPENGL_PROC(PFNGLGETTEXTUREIMAGEEXTPROC, GetTextureImageEXT);
OPENGL_PROC(PFNGLGETTEXTUREIMAGEPROC, GetTextureImage);
OPENGL_PROC(PFNGLCLEARBUFFERFVPROC, ClearBufferfv);
//Sampler Objects
OPENGL_PROC(PFNGLGENSAMPLERSPROC, GenSamplers);
OPENGL_PROC(PFNGLDELETESAMPLERSPROC, DeleteSamplers);
+11 -4
View File
@@ -192,6 +192,7 @@ struct gl_render_target_traits
if (old_surface != nullptr && old_surface->get_compatible_internal_format() == internal_fmt)
result->old_contents = old_surface;
result->set_cleared();
return result;
}
@@ -240,19 +241,25 @@ struct gl_render_target_traits
static void prepare_ds_for_drawing(void *, gl::render_target*) {}
static void prepare_ds_for_sampling(void *, gl::render_target*) {}
static void invalidate_rtt_surface_contents(void *, gl::render_target*) {}
static void invalidate_depth_surface_contents(void *, gl::render_target *ds) { ds->set_cleared(false); }
static void invalidate_rtt_surface_contents(void *, gl::render_target *rtt, gl::render_target* /*old*/, bool forced) { if (forced) rtt->set_cleared(false); }
static void invalidate_depth_surface_contents(void *, gl::render_target *ds, gl::render_target* /*old*/, bool) { ds->set_cleared(false); }
static
bool rtt_has_format_width_height(const std::unique_ptr<gl::render_target> &rtt, rsx::surface_color_format format, size_t width, size_t height)
bool rtt_has_format_width_height(const std::unique_ptr<gl::render_target> &rtt, rsx::surface_color_format format, size_t width, size_t height, bool check_refs=false)
{
if (check_refs) //TODO
return false;
auto internal_fmt = rsx::internals::sized_internal_format(format);
return rtt->get_compatible_internal_format() == internal_fmt && rtt->width() == width && rtt->height() == height;
}
static
bool ds_has_format_width_height(const std::unique_ptr<gl::render_target> &rtt, rsx::surface_depth_format, size_t width, size_t height)
bool ds_has_format_width_height(const std::unique_ptr<gl::render_target> &rtt, rsx::surface_depth_format, size_t width, size_t height, bool check_refs=false)
{
if (check_refs) //TODO
return false;
// TODO: check format
return rtt->width() == width && rtt->height() == height;
}
-3
View File
@@ -1,7 +1,4 @@
#pragma once
#include "stdafx.h"
#include "GLGSRender.h"
#include "GLTextureCache.h"
+3
View File
@@ -239,6 +239,8 @@ struct RSXFragmentProgram
u8 textures_alpha_kill[16];
u32 textures_zfunc[16];
bool valid;
rsx::texture_dimension_extended get_texture_dimension(u8 id) const
{
return (rsx::texture_dimension_extended)((texture_dimensions >> (id * 2)) & 0x3);
@@ -263,6 +265,7 @@ struct RSXFragmentProgram
, ctrl(0)
, unnormalized_coords(0)
, texture_dimensions(0)
, valid(false)
{
}
};
+27 -40
View File
@@ -5,7 +5,6 @@
#include "RSXThread.h"
#include "Emu/Cell/PPUCallback.h"
#include "Emu/Cell/lv2/sys_rsx.h"
#include "Common/BufferUtils.h"
#include "rsx_methods.h"
@@ -58,24 +57,11 @@ namespace rsx
//}
}
case CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_LOCAL:
return 0x40301400 + offset; // not sure if this should be 0x40300000 or offset to the actual reports, lets try reports for now
//return 0x100000 + offset; // TODO: Properly implement
case CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_REPORT:
return 0x100000 + offset; // TODO: Properly implement
case CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_MAIN:
{
if (u32 result = RSXIOMem.RealAddr(0x0e000000 + offset))
{
return result;
}
fmt::throw_exception("GetAddress(offset=0x%x, location=0x%x): RSXIO memory not mapped" HERE, offset, location);
//if (fxm::get<GSRender>()->strict_ordering[offset >> 20])
//{
// _mm_mfence(); // probably doesn't have any effect on current implementation
//}
}
return 0x800 + offset; // TODO: Properly implement
case CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_NOTIFY0:
return 0x40 + offset; // TODO: Properly implement
@@ -85,16 +71,13 @@ namespace rsx
case CELL_GCM_CONTEXT_DMA_SEMAPHORE_RW:
case CELL_GCM_CONTEXT_DMA_SEMAPHORE_R:
return 0x40300000 + offset; // this offset also doesnt seem like its right, but it works for now so w/e
//return 0x100 + offset; // TODO: Properly implement
return 0x100 + offset; // TODO: Properly implement
case CELL_GCM_CONTEXT_DMA_DEVICE_RW:
return 0x40000000 + offset;
//fmt::throw_exception("Unimplemented CELL_GCM_CONTEXT_DMA_DEVICE_RW (offset=0x%x, location=0x%x)" HERE, offset, location);
fmt::throw_exception("Unimplemented CELL_GCM_CONTEXT_DMA_DEVICE_RW (offset=0x%x, location=0x%x)" HERE, offset, location);
case CELL_GCM_CONTEXT_DMA_DEVICE_R:
return 0x40000000 + offset;
//fmt::throw_exception("Unimplemented CELL_GCM_CONTEXT_DMA_DEVICE_R (offset=0x%x, location=0x%x)" HERE, offset, location);
fmt::throw_exception("Unimplemented CELL_GCM_CONTEXT_DMA_DEVICE_R (offset=0x%x, location=0x%x)" HERE, offset, location);
default:
fmt::throw_exception("Invalid location (offset=0x%x, location=0x%x)" HERE, offset, location);
@@ -403,7 +386,7 @@ namespace rsx
if (get_system_time() - start_time > vblank_count * 1000000 / 60)
{
vblank_count++;
sys_rsx_context_attribute(0x55555555, 0xFED, 1, 0, 0, 0);
if (vblank_handler)
{
intr_thread->cmd_list
@@ -418,8 +401,6 @@ namespace rsx
continue;
}
while (Emu.IsPaused())
std::this_thread::sleep_for(10ms);
std::this_thread::sleep_for(1ms); // hack
}
@@ -519,7 +500,7 @@ namespace rsx
u32 reg = ((cmd & RSX_METHOD_NON_INCREMENT_CMD_MASK) == RSX_METHOD_NON_INCREMENT_CMD) ? first_cmd : first_cmd + i;
u32 value = args[i];
//LOG_WARNING(RSX, "%s(0x%x) = 0x%x", get_method_name(reg).c_str(), reg, value);
//LOG_NOTICE(RSX, "%s(0x%x) = 0x%x", get_method_name(reg).c_str(), reg, value);
method_registers.decode(reg, value);
@@ -993,9 +974,17 @@ namespace rsx
RSXFragmentProgram thread::get_current_fragment_program(std::function<std::tuple<bool, u16>(u32, fragment_texture&, bool)> get_surface_info) const
{
RSXFragmentProgram result = {};
u32 shader_program = rsx::method_registers.shader_program_address();
result.offset = shader_program & ~0x3;
result.addr = vm::base(rsx::get_address(result.offset, (shader_program & 0x3) - 1));
const u32 shader_program = rsx::method_registers.shader_program_address();
if (shader_program == 0)
return result;
const u32 program_location = (shader_program & 0x3) - 1;
const u32 program_offset = (shader_program & ~0x3);
result.offset = program_offset;
result.addr = vm::base(rsx::get_address(program_offset, program_location));
result.valid = true;
result.ctrl = rsx::method_registers.shader_control();
result.unnormalized_coords = 0;
result.front_back_color_enabled = !rsx::method_registers.two_side_light_en();
@@ -1193,26 +1182,26 @@ namespace rsx
if (packet.post_upload_func)
packet.post_upload_func(packet.dst_span.data(), packet.type, (u8)packet.vector_width, task.vertex_count);
_mm_sfence();
task.remaining_packets--;
current_job += step;
_mm_sfence();
}
_mm_mfence();
while (task.remaining_packets > 0 && !Emu.IsStopped())
{
std::this_thread::yield();
_mm_lfence();
std::this_thread::sleep_for(0us);
}
_mm_sfence();
task.ready_threads++;
_mm_sfence();
}
else
std::this_thread::sleep_for(0us);
//thread_ctrl::wait();
//busy_wait();
{
std::this_thread::yield();
}
}
});
}
@@ -1220,8 +1209,7 @@ namespace rsx
while (m_vertex_streaming_task.ready_threads != 0 && !Emu.IsStopped())
{
_mm_lfence();
busy_wait();
_mm_pause();
}
m_vertex_streaming_task.vertex_count = vertex_count;
@@ -1233,8 +1221,7 @@ namespace rsx
{
while (m_vertex_streaming_task.remaining_packets > 0 && !Emu.IsStopped())
{
_mm_lfence();
busy_wait();
_mm_pause();
}
m_vertex_streaming_task.packets.resize(0);
-2
View File
@@ -142,8 +142,6 @@ namespace rsx
u32 gcm_current_buffer;
u32 ctxt_addr;
u32 label_addr;
u32 nv406e_semaphore_addr;
u32 nv4097_semaphore_index;
u32 local_mem_addr, main_mem_addr;
bool strict_ordering[0x1000];
+226 -63
View File
@@ -677,6 +677,7 @@ VKGSRender::~VKGSRender()
m_buffer_view_to_clean.clear();
m_sampler_to_clean.clear();
m_framebuffer_to_clean.clear();
m_draw_fbo.reset();
//Render passes
for (auto &render_pass : m_render_passes)
@@ -874,17 +875,17 @@ void VKGSRender::begin_render_pass()
size_t idx = vk::get_render_pass_location(
vk::get_compatible_surface_format(rsx::method_registers.surface_color()).first,
vk::get_compatible_depth_surface_format(m_optimal_tiling_supported_formats, rsx::method_registers.surface_depth_fmt()),
(u8)vk::get_draw_buffers(rsx::method_registers.surface_color_target()).size());
(u8)m_draw_buffers_count);
VkRenderPass current_render_pass = m_render_passes[idx];
VkRenderPassBeginInfo rp_begin = {};
rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
rp_begin.renderPass = current_render_pass;
rp_begin.framebuffer = m_framebuffer_to_clean.back()->value;
rp_begin.framebuffer = m_draw_fbo->value;
rp_begin.renderArea.offset.x = 0;
rp_begin.renderArea.offset.y = 0;
rp_begin.renderArea.extent.width = m_framebuffer_to_clean.back()->width();
rp_begin.renderArea.extent.height = m_framebuffer_to_clean.back()->height();
rp_begin.renderArea.extent.width = m_draw_fbo->width();
rp_begin.renderArea.extent.height = m_draw_fbo->height();
vkCmdBeginRenderPass(*m_current_command_buffer, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
render_pass_open = true;
@@ -941,10 +942,15 @@ void VKGSRender::end()
}
//Load program here since it is dependent on vertex state
load_program(is_instanced);
if (!load_program(is_instanced))
{
LOG_ERROR(RSX, "No valid program bound to pipeline. Skipping draw");
rsx::thread::end();
return;
}
std::chrono::time_point<steady_clock> program_stop = steady_clock::now();
m_setup_time += (u32)std::chrono::duration_cast<std::chrono::microseconds>(program_stop - program_start).count();
//m_setup_time += std::chrono::duration_cast<std::chrono::microseconds>(program_stop - program_start).count();
if (is_instanced)
{
@@ -999,14 +1005,14 @@ void VKGSRender::end()
{
auto surface = std::get<1>(rtt);
if (surface->dirty && surface->old_contents != nullptr)
if (surface->old_contents != nullptr)
copy_rtt_contents(surface);
}
}
if (auto ds = std::get<1>(m_rtts.m_bound_depth_stencil))
{
if (ds->dirty && ds->old_contents != nullptr)
if (ds->old_contents != nullptr)
copy_rtt_contents(ds);
}
}
@@ -1114,6 +1120,11 @@ void VKGSRender::end()
vkCmdBindPipeline(*m_current_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_program->pipeline);
vkCmdBindDescriptorSets(*m_current_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_sets, 0, nullptr);
//Clear any 'dirty' surfaces - possible is a recycled cache surface is used
std::vector<VkClearAttachment> buffers_to_clear;
buffers_to_clear.reserve(4);
const auto targets = vk::get_draw_buffers(rsx::method_registers.surface_color_target());
if (auto ds = std::get<1>(m_rtts.m_bound_depth_stencil))
{
if (ds->dirty)
@@ -1123,28 +1134,41 @@ void VKGSRender::end()
depth_clear_value.depthStencil.depth = 1.f;
depth_clear_value.depthStencil.stencil = 255;
VkClearRect clear_rect = { 0, 0, m_framebuffer_to_clean.back()->width(), m_framebuffer_to_clean.back()->height(), 0, 1 };
VkClearAttachment clear_desc = { ds->attachment_aspect_flag, 0, depth_clear_value };
vkCmdClearAttachments(*m_current_command_buffer, 1, &clear_desc, 1, &clear_rect);
buffers_to_clear.push_back(clear_desc);
ds->dirty = false;
}
}
std::optional<std::tuple<VkDeviceSize, VkIndexType> > index_info = std::get<2>(upload_info);
if (m_attrib_ring_info.mapped)
for (int index = 0; index < targets.size(); ++index)
{
wait_for_vertex_upload_task();
m_attrib_ring_info.unmap();
if (std::get<0>(m_rtts.m_bound_render_targets[index]) != 0 && std::get<1>(m_rtts.m_bound_render_targets[index])->dirty)
{
const u32 real_index = (index == 1 && targets.size() == 1) ? 0 : static_cast<u32>(index);
buffers_to_clear.push_back({ VK_IMAGE_ASPECT_COLOR_BIT, real_index, {} });
std::get<1>(m_rtts.m_bound_render_targets[index])->dirty = false;
}
}
if (buffers_to_clear.size() > 0)
{
VkClearRect clear_rect = { 0, 0, m_draw_fbo->width(), m_draw_fbo->height(), 0, 1 };
vkCmdClearAttachments(*m_current_command_buffer, static_cast<u32>(buffers_to_clear.size()), buffers_to_clear.data(), 1, &clear_rect);
}
std::optional<std::tuple<VkDeviceSize, VkIndexType> > index_info = std::get<2>(upload_info);
std::chrono::time_point<steady_clock> vertex_end = steady_clock::now();
m_vertex_upload_time += std::chrono::duration_cast<std::chrono::microseconds>(vertex_end - textures_end).count();
if (!index_info)
{
vkCmdDraw(*m_current_command_buffer, std::get<1>(upload_info), 1, 0, 0);
const auto vertex_count = std::get<1>(upload_info);
vkCmdDraw(*m_current_command_buffer, vertex_count, 1, 0, 0);
m_last_vertex_count = vertex_count;
m_last_draw_indexed = false;
}
else
@@ -1175,6 +1199,22 @@ void VKGSRender::end()
copy_render_targets_to_dma_location();
m_draw_calls++;
if (g_cfg.video.overlay)
{
if (m_last_vertex_count < 1024)
m_uploads_small++;
else if (m_last_vertex_count < 2048)
m_uploads_1k++;
else if (m_last_vertex_count < 4096)
m_uploads_2k++;
else if (m_last_vertex_count < 8192)
m_uploads_4k++;
else if (m_last_vertex_count < 16384)
m_uploads_8k++;
else
m_uploads_16k++;
}
rsx::thread::end();
}
@@ -1251,8 +1291,6 @@ void VKGSRender::clear_surface(u32 mask)
u32 depth_stencil_mask = 0;
std::vector<VkClearAttachment> clear_descriptors;
std::vector<VkClearRect> clear_regions;
VkClearValue depth_stencil_clear_values, color_clear_values;
u16 scissor_x = rsx::method_registers.scissor_origin_x();
@@ -1260,8 +1298,8 @@ void VKGSRender::clear_surface(u32 mask)
u16 scissor_y = rsx::method_registers.scissor_origin_y();
u16 scissor_h = rsx::method_registers.scissor_height();
const u32 fb_width = m_framebuffer_to_clean.back()->width();
const u32 fb_height = m_framebuffer_to_clean.back()->height();
const u32 fb_width = m_draw_fbo->width();
const u32 fb_height = m_draw_fbo->height();
//clip region
std::tie(scissor_x, scissor_y, scissor_w, scissor_h) = rsx::clip_region<u16>(fb_width, fb_height, scissor_x, scissor_y, scissor_w, scissor_h, true);
@@ -1309,8 +1347,8 @@ void VKGSRender::clear_surface(u32 mask)
for (int index = 0; index < targets.size(); ++index)
{
clear_descriptors.push_back({ VK_IMAGE_ASPECT_COLOR_BIT, (uint32_t)index, color_clear_values });
clear_regions.push_back(region);
const u32 real_index = (index == 1 && targets.size() == 1) ? 0 : static_cast<u32>(index);
clear_descriptors.push_back({ VK_IMAGE_ASPECT_COLOR_BIT, real_index, color_clear_values });
}
for (auto &rtt : m_rtts.m_bound_render_targets)
@@ -1324,13 +1362,10 @@ void VKGSRender::clear_surface(u32 mask)
}
if (mask & 0x3)
{
clear_descriptors.push_back({ (VkImageAspectFlags)depth_stencil_mask, 0, depth_stencil_clear_values });
clear_regions.push_back(region);
}
begin_render_pass();
vkCmdClearAttachments(*m_current_command_buffer, (u32)clear_descriptors.size(), clear_descriptors.data(), (u32)clear_regions.size(), clear_regions.data());
vkCmdClearAttachments(*m_current_command_buffer, (u32)clear_descriptors.size(), clear_descriptors.data(), 1, &region);
if (mask & 0x3)
{
@@ -1392,6 +1427,12 @@ void VKGSRender::copy_render_targets_to_dma_location()
void VKGSRender::flush_command_queue(bool hard_sync)
{
if (m_attrib_ring_info.mapped)
{
wait_for_vertex_upload_task();
m_attrib_ring_info.unmap();
}
close_render_pass();
close_and_submit_command_buffer({}, m_current_command_buffer->submit_fence);
@@ -1472,7 +1513,7 @@ void VKGSRender::process_swap_request()
//Feed back damaged resources to the main texture cache for management...
//m_texture_cache.merge_dirty_textures(m_rtts.invalidated_resources);
m_rtts.invalidated_resources.clear();
m_rtts.free_invalidated();
m_texture_cache.flush();
if (g_cfg.video.invalidate_surface_cache_every_frame)
@@ -1480,7 +1521,13 @@ void VKGSRender::process_swap_request()
m_buffer_view_to_clean.clear();
m_sampler_to_clean.clear();
m_framebuffer_to_clean.clear();
m_framebuffer_to_clean.remove_if([](std::unique_ptr<vk::framebuffer_holder>& fbo)
{
if (fbo->deref_count >= 2) return true;
fbo->deref_count++;
return false;
});
if (g_cfg.video.overlay)
{
@@ -1545,8 +1592,10 @@ bool VKGSRender::load_program(bool fast_update)
return std::make_tuple(true, surface->native_pitch);
};
vertex_program = get_current_vertex_program();
fragment_program = get_current_fragment_program(rtt_lookup_func);
if (!fragment_program.valid) return false;
vertex_program = get_current_vertex_program();
vk::pipeline_props properties = {};
@@ -1691,7 +1740,7 @@ bool VKGSRender::load_program(bool fast_update)
size_t idx = vk::get_render_pass_location(
vk::get_compatible_surface_format(rsx::method_registers.surface_color()).first,
vk::get_compatible_depth_surface_format(m_optimal_tiling_supported_formats, rsx::method_registers.surface_depth_fmt()),
(u8)vk::get_draw_buffers(rsx::method_registers.surface_color_target()).size());
(u8)m_draw_buffers_count);
properties.render_pass = m_render_passes[idx];
@@ -1853,6 +1902,7 @@ void VKGSRender::prepare_rtts()
{
LOG_ERROR(RSX, "Invalid framebuffer setup, w=%d, h=%d", clip_width, clip_height);
framebuffer_status_valid = false;
return;
}
framebuffer_status_valid = true;
@@ -1863,6 +1913,35 @@ void VKGSRender::prepare_rtts()
const u32 surface_pitchs[] = { rsx::method_registers.surface_a_pitch(), rsx::method_registers.surface_b_pitch(),
rsx::method_registers.surface_c_pitch(), rsx::method_registers.surface_d_pitch() };
if (m_draw_fbo)
{
const u32 fb_width = m_draw_fbo->width();
const u32 fb_height = m_draw_fbo->height();
bool really_changed = false;
if (fb_width == clip_width && fb_height == clip_height)
{
for (u8 i = 0; i < rsx::limits::color_buffers_count; ++i)
{
if (m_surface_info[i].address != surface_addresses[i])
{
really_changed = true;
break;
}
}
if (!really_changed)
{
if (zeta_address == m_depth_surface_info.address)
{
//Nothing has changed, we're still using the same framebuffer
return;
}
}
}
}
m_rtts.prepare_render_target(&*m_current_command_buffer,
rsx::method_registers.surface_color(), rsx::method_registers.surface_depth_fmt(),
clip_width, clip_height,
@@ -1886,20 +1965,16 @@ void VKGSRender::prepare_rtts()
//Bind created rtts as current fbo...
std::vector<u8> draw_buffers = vk::get_draw_buffers(rsx::method_registers.surface_color_target());
std::vector<std::unique_ptr<vk::image_view>> fbo_images;
//Search old framebuffers for this same configuration
bool framebuffer_found = false;
std::vector<vk::image*> bound_images;
bound_images.reserve(5);
for (u8 index : draw_buffers)
{
vk::image *raw = std::get<1>(m_rtts.m_bound_render_targets[index]);
VkImageSubresourceRange subres = {};
subres.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subres.baseArrayLayer = 0;
subres.baseMipLevel = 0;
subres.layerCount = 1;
subres.levelCount = 1;
fbo_images.push_back(std::make_unique<vk::image_view>(*m_device, raw->value, VK_IMAGE_VIEW_TYPE_2D, raw->info.format, vk::default_component_map(), subres));
bound_images.push_back(std::get<1>(m_rtts.m_bound_render_targets[index]));
m_surface_info[index].address = surface_addresses[index];
m_surface_info[index].pitch = surface_pitchs[index];
@@ -1912,20 +1987,9 @@ void VKGSRender::prepare_rtts()
}
}
m_draw_buffers_count = static_cast<u32>(fbo_images.size());
if (std::get<1>(m_rtts.m_bound_depth_stencil) != nullptr)
if (std::get<0>(m_rtts.m_bound_depth_stencil) != 0)
{
vk::image *raw = (std::get<1>(m_rtts.m_bound_depth_stencil));
VkImageSubresourceRange subres = {};
subres.aspectMask = (rsx::method_registers.surface_depth_fmt() == rsx::surface_depth_format::z24s8) ? (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) : VK_IMAGE_ASPECT_DEPTH_BIT;
subres.baseArrayLayer = 0;
subres.baseMipLevel = 0;
subres.layerCount = 1;
subres.levelCount = 1;
fbo_images.push_back(std::make_unique<vk::image_view>(*m_device, raw->value, VK_IMAGE_VIEW_TYPE_2D, raw->info.format, vk::default_component_map(), subres));
bound_images.push_back(std::get<1>(m_rtts.m_bound_depth_stencil));
m_depth_surface_info.address = zeta_address;
m_depth_surface_info.pitch = rsx::method_registers.surface_z_pitch();
@@ -1934,6 +1998,8 @@ void VKGSRender::prepare_rtts()
m_depth_surface_info.pitch = 0;
}
m_draw_buffers_count = static_cast<u32>(draw_buffers.size());
if (g_cfg.video.write_color_buffers)
{
for (u8 index : draw_buffers)
@@ -1942,7 +2008,7 @@ void VKGSRender::prepare_rtts()
const u32 range = m_surface_info[index].pitch * m_surface_info[index].height;
m_texture_cache.lock_memory_region(std::get<1>(m_rtts.m_bound_render_targets[index]), m_surface_info[index].address, range,
m_surface_info[index].width, m_surface_info[index].height);
m_surface_info[index].width, m_surface_info[index].height);
}
}
@@ -1959,10 +2025,59 @@ void VKGSRender::prepare_rtts()
}
}
size_t idx = vk::get_render_pass_location(vk::get_compatible_surface_format(rsx::method_registers.surface_color()).first, vk::get_compatible_depth_surface_format(m_optimal_tiling_supported_formats, rsx::method_registers.surface_depth_fmt()), (u8)draw_buffers.size());
VkRenderPass current_render_pass = m_render_passes[idx];
for (auto &fbo : m_framebuffer_to_clean)
{
if (fbo->matches(bound_images, clip_width, clip_height))
{
m_draw_fbo.swap(fbo);
m_draw_fbo->reset_refs();
framebuffer_found = true;
//LOG_ERROR(RSX, "Matching framebuffer exists, using that instead");
break;
}
}
m_framebuffer_to_clean.push_back(std::make_unique<vk::framebuffer>(*m_device, current_render_pass, clip_width, clip_height, std::move(fbo_images)));
if (!framebuffer_found)
{
std::vector<std::unique_ptr<vk::image_view>> fbo_images;
fbo_images.reserve(5);
for (u8 index : draw_buffers)
{
vk::image *raw = std::get<1>(m_rtts.m_bound_render_targets[index]);
VkImageSubresourceRange subres = {};
subres.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subres.baseArrayLayer = 0;
subres.baseMipLevel = 0;
subres.layerCount = 1;
subres.levelCount = 1;
fbo_images.push_back(std::make_unique<vk::image_view>(*m_device, raw->value, VK_IMAGE_VIEW_TYPE_2D, raw->info.format, vk::default_component_map(), subres));
}
if (std::get<1>(m_rtts.m_bound_depth_stencil) != nullptr)
{
vk::image *raw = (std::get<1>(m_rtts.m_bound_depth_stencil));
VkImageSubresourceRange subres = {};
subres.aspectMask = (rsx::method_registers.surface_depth_fmt() == rsx::surface_depth_format::z24s8) ? (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) : VK_IMAGE_ASPECT_DEPTH_BIT;
subres.baseArrayLayer = 0;
subres.baseMipLevel = 0;
subres.layerCount = 1;
subres.levelCount = 1;
fbo_images.push_back(std::make_unique<vk::image_view>(*m_device, raw->value, VK_IMAGE_VIEW_TYPE_2D, raw->info.format, vk::default_component_map(), subres));
}
size_t idx = vk::get_render_pass_location(vk::get_compatible_surface_format(rsx::method_registers.surface_color()).first, vk::get_compatible_depth_surface_format(m_optimal_tiling_supported_formats, rsx::method_registers.surface_depth_fmt()), (u8)draw_buffers.size());
VkRenderPass current_render_pass = m_render_passes[idx];
if (m_draw_fbo)
m_framebuffer_to_clean.push_back(std::move(m_draw_fbo));
m_draw_fbo.reset(new vk::framebuffer_holder(*m_device, current_render_pass, clip_width, clip_height, std::move(fbo_images)));
}
}
@@ -1981,6 +2096,13 @@ void VKGSRender::flip(int buffer)
m_setup_time = 0;
m_vertex_upload_time = 0;
m_textures_upload_time = 0;
m_uploads_small = 0;
m_uploads_1k = 0;
m_uploads_2k = 0;
m_uploads_4k = 0;
m_uploads_8k = 0;
m_uploads_16k = 0;
}
return;
@@ -2060,7 +2182,7 @@ void VKGSRender::flip(int buffer)
vk::change_image_layout(*m_current_command_buffer, m_swap_chain->get_swap_chain_image(m_current_present_image), VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, range);
}
std::unique_ptr<vk::framebuffer> direct_fbo;
std::unique_ptr<vk::framebuffer_holder> direct_fbo;
std::vector<std::unique_ptr<vk::image_view>> swap_image_view;
if (g_cfg.video.overlay)
{
@@ -2082,9 +2204,24 @@ void VKGSRender::flip(int buffer)
size_t idx = vk::get_render_pass_location(m_swap_chain->get_surface_format(), VK_FORMAT_UNDEFINED, 1);
VkRenderPass single_target_pass = m_render_passes[idx];
swap_image_view.push_back(std::make_unique<vk::image_view>(*m_device, target_image, VK_IMAGE_VIEW_TYPE_2D, m_swap_chain->get_surface_format(), vk::default_component_map(), subres));
direct_fbo.reset(new vk::framebuffer(*m_device, single_target_pass, m_client_width, m_client_height, std::move(swap_image_view)));
for (auto It = m_framebuffer_to_clean.begin(); It != m_framebuffer_to_clean.end(); It++)
{
auto &fbo = *It;
if (fbo->attachments[0]->info.image == target_image)
{
direct_fbo.swap(fbo);
direct_fbo->reset_refs();
m_framebuffer_to_clean.erase(It);
break;
}
}
if (!direct_fbo)
{
swap_image_view.push_back(std::make_unique<vk::image_view>(*m_device, target_image, VK_IMAGE_VIEW_TYPE_2D, m_swap_chain->get_surface_format(), vk::default_component_map(), subres));
direct_fbo.reset(new vk::framebuffer_holder(*m_device, single_target_pass, m_client_width, m_client_height, std::move(swap_image_view)));
}
m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 0, direct_fbo->width(), direct_fbo->height(), "draw calls: " + std::to_string(m_draw_calls) + ", instanced repeats: " + std::to_string(m_instanced_draws));
m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 18, direct_fbo->width(), direct_fbo->height(), "draw call setup: " + std::to_string(m_setup_time) + "us");
m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 36, direct_fbo->width(), direct_fbo->height(), "vertex upload time: " + std::to_string(m_vertex_upload_time) + "us");
@@ -2092,10 +2229,29 @@ void VKGSRender::flip(int buffer)
m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 72, direct_fbo->width(), direct_fbo->height(), "draw call execution: " + std::to_string(m_draw_time) + "us");
m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 90, direct_fbo->width(), direct_fbo->height(), "submit and flip: " + std::to_string(m_flip_time) + "us");
//Vertex upload statistics
u32 _small, _1k, _2k, _4k, _8k, _16k;
if (m_draw_calls > 0)
{
_small = m_uploads_small * 100 / m_draw_calls;
_1k = m_uploads_1k * 100 / m_draw_calls;
_2k = m_uploads_2k * 100 / m_draw_calls;
_4k = m_uploads_4k * 100 / m_draw_calls;
_8k = m_uploads_8k * 100 / m_draw_calls;
_16k = m_uploads_16k * 100 / m_draw_calls;
}
else
{
_small = _1k = _2k = _4k = _8k = _16k = 0;
}
std::string message = fmt::format("Vertex sizes: < 1k: %d%%, 1k+: %d%%, 2k+: %d%%, 4k+: %d%%, 8k+: %d%%, 16k+: %d%%", _small, _1k, _2k, _4k, _8k, _16k);
m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 108, direct_fbo->width(), direct_fbo->height(), message);
vk::change_image_layout(*m_current_command_buffer, target_image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, subres);
m_framebuffer_to_clean.push_back(std::move(direct_fbo));
}
m_framebuffer_to_clean.push_back(std::move(direct_fbo));
queue_swap_request();
}
else
@@ -2193,4 +2349,11 @@ void VKGSRender::flip(int buffer)
m_setup_time = 0;
m_vertex_upload_time = 0;
m_textures_upload_time = 0;
m_uploads_small = 0;
m_uploads_1k = 0;
m_uploads_2k = 0;
m_uploads_4k = 0;
m_uploads_8k = 0;
m_uploads_16k = 0;
}
+12 -1
View File
@@ -149,15 +149,26 @@ private:
vk::descriptor_pool descriptor_pool;
std::vector<std::unique_ptr<vk::buffer_view> > m_buffer_view_to_clean;
std::vector<std::unique_ptr<vk::framebuffer> > m_framebuffer_to_clean;
std::vector<std::unique_ptr<vk::sampler> > m_sampler_to_clean;
std::list<std::unique_ptr<vk::framebuffer_holder> > m_framebuffer_to_clean;
std::unique_ptr<vk::framebuffer_holder> m_draw_fbo;
u32 m_client_width = 0;
u32 m_client_height = 0;
// Draw call stats
u32 m_draw_calls = 0;
u32 m_instanced_draws = 0;
// Vertex buffer usage stats
u32 m_uploads_small = 0;
u32 m_uploads_1k = 0;
u32 m_uploads_2k = 0;
u32 m_uploads_4k = 0;
u32 m_uploads_8k = 0;
u32 m_uploads_16k = 0;
// Timers
s64 m_setup_time = 0;
s64 m_vertex_upload_time = 0;
s64 m_textures_upload_time = 0;
+22 -4
View File
@@ -650,17 +650,17 @@ namespace vk
{
VkFramebuffer value;
VkFramebufferCreateInfo info = {};
std::vector<std::unique_ptr<vk::image_view>> attachements;
std::vector<std::unique_ptr<vk::image_view>> attachments;
u32 m_width = 0;
u32 m_height = 0;
public:
framebuffer(VkDevice dev, VkRenderPass pass, u32 width, u32 height, std::vector<std::unique_ptr<vk::image_view>> &&atts)
: m_device(dev), attachements(std::move(atts))
: m_device(dev), attachments(std::move(atts))
{
std::vector<VkImageView> image_view_array(attachements.size());
std::vector<VkImageView> image_view_array(attachments.size());
size_t i = 0;
for (const auto &att : attachements)
for (const auto &att : attachments)
{
image_view_array[i++] = att->value;
}
@@ -694,6 +694,24 @@ namespace vk
return m_height;
}
bool matches(std::vector<vk::image*> fbo_images, u32 width, u32 height)
{
if (m_width != width || m_height != height)
return false;
if (fbo_images.size() != attachments.size())
return false;
for (int n = 0; n < fbo_images.size(); ++n)
{
if (attachments[n]->info.image != fbo_images[n]->value ||
attachments[n]->info.format != fbo_images[n]->info.format)
return false;
}
return true;
}
framebuffer(const framebuffer&) = delete;
framebuffer(framebuffer&&) = delete;
+65 -10
View File
@@ -7,9 +7,16 @@
#include "../Common/TextureUtils.h"
#include "VKFormats.h"
struct ref_counted
{
u8 deref_count = 0;
void reset_refs() { deref_count = 0; }
};
namespace vk
{
struct render_target : public image
struct render_target : public image, public ref_counted
{
bool dirty = false;
u16 native_pitch = 0;
@@ -34,6 +41,17 @@ namespace vk
mipmaps, layers, samples, initial_layout, tiling, usage, image_flags)
{}
};
struct framebuffer_holder: public vk::framebuffer, public ref_counted
{
framebuffer_holder(VkDevice dev,
VkRenderPass pass,
u32 width, u32 height,
std::vector<std::unique_ptr<vk::image_view>> &&atts)
: framebuffer(dev, pass, width, height, std::move(atts))
{}
};
}
namespace rsx
@@ -147,6 +165,9 @@ namespace rsx
{
VkImageSubresourceRange range = vk::get_image_subresource_range(0, 0, 1, 1, surface->attachment_aspect_flag);
change_image_layout(*pcmd, surface, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, range);
//Reset deref count
surface->deref_count = 0;
}
static void prepare_rtt_for_sampling(vk::command_buffer* pcmd, vk::render_target *surface)
@@ -159,6 +180,9 @@ namespace rsx
{
VkImageSubresourceRange range = vk::get_image_subresource_range(0, 0, 1, 1, surface->attachment_aspect_flag);
change_image_layout(*pcmd, surface, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, range);
//Reset deref count
surface->deref_count = 0;
}
static void prepare_ds_for_sampling(vk::command_buffer* pcmd, vk::render_target *surface)
@@ -167,15 +191,26 @@ namespace rsx
change_image_layout(*pcmd, surface, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, range);
}
static void invalidate_rtt_surface_contents(vk::command_buffer*, vk::render_target*) {}
static void invalidate_rtt_surface_contents(vk::command_buffer* pcmd, vk::render_target *rtt, vk::render_target *old_surface, bool forced)
{
if (forced)
{
rtt->old_contents = old_surface;
rtt->dirty = true;
}
}
static void invalidate_depth_surface_contents(vk::command_buffer* /*pcmd*/, vk::render_target *ds)
static void invalidate_depth_surface_contents(vk::command_buffer* /*pcmd*/, vk::render_target *ds, vk::render_target *old_surface, bool /*forced*/)
{
ds->dirty = true;
ds->old_contents = old_surface;
}
static bool rtt_has_format_width_height(const std::unique_ptr<vk::render_target> &rtt, surface_color_format format, size_t width, size_t height)
static bool rtt_has_format_width_height(const std::unique_ptr<vk::render_target> &rtt, surface_color_format format, size_t width, size_t height, bool check_refs=false)
{
if (check_refs && rtt->deref_count == 0) //Surface may still have read refs from data 'copy'
return false;
VkFormat fmt = vk::get_compatible_surface_format(format).first;
if (rtt->info.format == fmt &&
@@ -186,15 +221,24 @@ namespace rsx
return false;
}
static bool ds_has_format_width_height(const std::unique_ptr<vk::render_target> &ds, surface_depth_format, size_t width, size_t height)
static bool ds_has_format_width_height(const std::unique_ptr<vk::render_target> &ds, surface_depth_format format, size_t width, size_t height, bool check_refs=false)
{
// TODO: check format
//VkFormat fmt = vk::get_compatible_depth_surface_format(format);
if (check_refs && ds->deref_count == 0) //Surface may still have read refs from data 'copy'
return false;
if (//tex.get_format() == fmt &&
ds->info.extent.width == width &&
if (ds->info.extent.width == width &&
ds->info.extent.height == height)
return true;
{
//Check format
switch (ds->info.format)
{
case VK_FORMAT_D16_UNORM:
return format == surface_depth_format::z16;
case VK_FORMAT_D24_UNORM_S8_UINT:
case VK_FORMAT_D32_SFLOAT_S8_UINT:
return format == surface_depth_format::z24s8;
}
}
return false;
}
@@ -237,5 +281,16 @@ namespace rsx
m_depth_stencil_storage.clear();
invalidated_resources.clear();
}
void free_invalidated()
{
invalidated_resources.remove_if([](std::unique_ptr<vk::render_target> &rtt)
{
if (rtt->deref_count >= 2) return true;
rtt->deref_count++;
return false;
});
}
};
}
+1 -1
View File
@@ -477,7 +477,7 @@ namespace
{
const auto &vbo = vertex_buffers[i];
if (vbo.which() == 0 && vertex_count > 128 && vertex_buffers.size() > 2 && rsxthr->vertex_upload_task_ready())
if (vbo.which() == 0 && vertex_count >= (u32)g_cfg.video.mt_vertex_upload_threshold && vertex_buffers.size() > 1 && rsxthr->vertex_upload_task_ready())
{
//vertex array buffer. We can thread this thing heavily
const auto& v = vbo.get<rsx::vertex_array_buffer>();
+22 -11
View File
@@ -146,8 +146,9 @@ void VKVertexDecompilerThread::insertConstants(std::stringstream & OS, const std
static const vertex_reg_info reg_table[] =
{
{ "gl_Position", false, "dst_reg0", "", false },
{ "back_diff_color", true, "dst_reg1", "", false },
{ "back_spec_color", true, "dst_reg2", "", false },
//Technically these two are for both back and front
{ "back_diff_color", true, "dst_reg1", "", false, "", "", "", false, CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTDIFFUSE },
{ "back_spec_color", true, "dst_reg2", "", false, "", "", "", false, CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTSPECULAR },
{ "front_diff_color", true, "dst_reg3", "", false },
{ "front_spec_color", true, "dst_reg4", "", false },
{ "fog_c", true, "dst_reg5", ".xxxx", true, "", "", "", true, CELL_GCM_ATTRIB_OUTPUT_MASK_FOG },
@@ -159,15 +160,15 @@ static const vertex_reg_info reg_table[] =
{ "gl_ClipDistance[3]", false, "dst_reg6", ".y * userClipFactor[0].w", false, "userClipEnabled[0].w > 0", "0.5", "", true, CELL_GCM_ATTRIB_OUTPUT_MASK_UC3 },
{ "gl_ClipDistance[4]", false, "dst_reg6", ".z * userClipFactor[1].x", false, "userClipEnabled[1].x > 0", "0.5", "", true, CELL_GCM_ATTRIB_OUTPUT_MASK_UC4 },
{ "gl_ClipDistance[5]", false, "dst_reg6", ".w * userClipFactor[1].y", false, "userClipEnabled[1].y > 0", "0.5", "", true, CELL_GCM_ATTRIB_OUTPUT_MASK_UC5 },
{ "tc0", true, "dst_reg7", "", false },
{ "tc1", true, "dst_reg8", "", false },
{ "tc2", true, "dst_reg9", "", false },
{ "tc3", true, "dst_reg10", "", false },
{ "tc4", true, "dst_reg11", "", false },
{ "tc5", true, "dst_reg12", "", false },
{ "tc6", true, "dst_reg13", "", false },
{ "tc7", true, "dst_reg14", "", false },
{ "tc8", true, "dst_reg15", "", false },
{ "tc0", true, "dst_reg7", "", false, "", "", "", false, CELL_GCM_ATTRIB_OUTPUT_MASK_TEX0 },
{ "tc1", true, "dst_reg8", "", false, "", "", "", false, CELL_GCM_ATTRIB_OUTPUT_MASK_TEX1 },
{ "tc2", true, "dst_reg9", "", false, "", "", "", false, CELL_GCM_ATTRIB_OUTPUT_MASK_TEX2 },
{ "tc3", true, "dst_reg10", "", false, "", "", "", false, CELL_GCM_ATTRIB_OUTPUT_MASK_TEX3 },
{ "tc4", true, "dst_reg11", "", false, "", "", "", false, CELL_GCM_ATTRIB_OUTPUT_MASK_TEX4 },
{ "tc5", true, "dst_reg12", "", false, "", "", "", false, CELL_GCM_ATTRIB_OUTPUT_MASK_TEX5 },
{ "tc6", true, "dst_reg13", "", false, "", "", "", false, CELL_GCM_ATTRIB_OUTPUT_MASK_TEX6 },
{ "tc7", true, "dst_reg14", "", false, "", "", "", false, CELL_GCM_ATTRIB_OUTPUT_MASK_TEX7 },
{ "tc8", true, "dst_reg15", "", false, "", "", "", false, CELL_GCM_ATTRIB_OUTPUT_MASK_TEX8 },
{ "tc9", true, "dst_reg6", "", false, "", "", "", true, CELL_GCM_ATTRIB_OUTPUT_MASK_TEX9 } // In this line, dst_reg6 is correct since dst_reg goes from 0 to 15.
};
@@ -195,6 +196,16 @@ void VKVertexDecompilerThread::insertOutputs(std::stringstream & OS, const std::
const vk::varying_register_t &reg = vk::get_varying_register(i.name);
OS << "layout(location=" << reg.reg_location << ") out vec4 " << i.name << ";\n";
}
else
{
//Force some outputs to be declared even if unused so we can set default values
//NOTE: Registers that can be skept will not have their check_mask_value set
if (i.need_declare && (rsx_vertex_program.output_mask & i.check_mask_value) > 0)
{
const vk::varying_register_t &reg = vk::get_varying_register(i.name);
OS << "layout(location=" << reg.reg_location << ") out vec4 " << i.name << ";\n";
}
}
}
if (insert_back_diffuse && insert_front_diffuse)
+1 -1
View File
@@ -968,7 +968,7 @@ rsx::blit_engine::context_dma rsx::blit_engine::to_context_dma(u32 in)
{
switch (in)
{
case CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_LOCAL: return rsx::blit_engine::context_dma::to_memory_get_report;
case CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_REPORT: return rsx::blit_engine::context_dma::to_memory_get_report;
case CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_MAIN: return rsx::blit_engine::context_dma::report_location_main;
case CELL_GCM_CONTEXT_DMA_MEMORY_HOST_BUFFER: return rsx::blit_engine::context_dma::memory_host_buffer;
}
+1 -1
View File
@@ -704,7 +704,7 @@ enum
{
CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER = 0xFEED0000, // Local memory
CELL_GCM_CONTEXT_DMA_MEMORY_HOST_BUFFER = 0xFEED0001, // Main memory
CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_LOCAL = 0x66626660,
CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_REPORT = 0x66626660,
CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_MAIN = 0xBAD68000,
CELL_GCM_CONTEXT_DMA_NOTIFY_MAIN_0 = 0x6660420F,
+31 -137
View File
@@ -6,7 +6,6 @@
#include "rsx_utils.h"
#include "rsx_decode.h"
#include "Emu/Cell/PPUCallback.h"
#include "Emu/Cell/lv2/sys_rsx.h"
#include <sstream>
#include <cereal/archives/binary.hpp>
@@ -59,25 +58,11 @@ namespace rsx
rsx->ctrl->ref.exchange(arg);
}
void set_context_dma_semaphore(thread* rsx, u32 _reg, u32 arg)
{
LOG_ERROR(RSX, "dmaSemaphore: 0x%x", arg);
rsx->nv406e_semaphore_addr = arg;
}
void semaphore_acquire(thread* rsx, u32 _reg, u32 arg)
{
//TODO: dma
//while (vm::ps3::read32(rsx->label_addr + method_registers.semaphore_offset_406e()) != arg)
const u32 addr = get_address(method_registers.semaphore_offset_406e(), rsx->nv406e_semaphore_addr);
//todo: make me atomic
while (vm::ps3::read32(addr) != arg)
while (vm::ps3::read32(rsx->label_addr + method_registers.semaphore_offset_406e()) != arg)
{
//if (rsx->nv406e_semaphore_addr == CELL_GCM_CONTEXT_DMA_DEVICE_R || rsx->nv406e_semaphore_addr == CELL_GCM_CONTEXT_DMA_DEVICE_RW)
// todo: why does this one keep hanging? is it vsh system semaphore? whats actually pushing this to the command buffer?!
if (addr == 0x40000030)
break;
if (Emu.IsStopped())
break;
@@ -88,35 +73,10 @@ namespace rsx
void semaphore_release(thread* rsx, u32 _reg, u32 arg)
{
//TODO: dma
//vm::ps3::write32(rsx->label_addr + method_registers.semaphore_offset_406e(), arg);
const u32 addr = get_address(method_registers.semaphore_offset_406e(), rsx->nv406e_semaphore_addr);
vm::ps3::write32(addr, arg);
vm::ps3::write32(rsx->label_addr + method_registers.semaphore_offset_406e(), arg);
}
}
struct RsxSemaphore {
be_t<u32> val;
be_t<u32> pad;
be_t<u64> timestamp;
};
struct RsxNotify {
be_t<u64> timestamp;
be_t<u64> zero;
};
struct RsxReport {
be_t<u64> timestamp;
be_t<u32> val;
be_t<u32> pad;
};
struct RsxReports {
RsxSemaphore semaphore[0x100];
RsxNotify notify[64];
RsxReport report[2048];
};
namespace nv4097
{
void clear(thread* rsx, u32 _reg, u32 arg)
@@ -133,11 +93,6 @@ namespace rsx
}
}
/*void set_context_dma_semaphore(thread* rsx, u32 _reg, u32 arg)
{
rsx->nv4097_semaphore_index = arg >> 4;
}*/
void texture_read_semaphore_release(thread* rsx, u32 _reg, u32 arg)
{
if (!rsx->do_method(NV4097_TEXTURE_READ_SEMAPHORE_RELEASE, arg))
@@ -146,15 +101,7 @@ namespace rsx
}
//TODO: dma
//vm::ps3::write32(rsx->label_addr + method_registers.semaphore_offset_4097(), arg);
//const u32 addr = get_address(method_registers.semaphore_offset_4097(), rsx->nv4097_semaphore_index);
//vm::ps3::write32(addr, arg);
const u32 index = method_registers.semaphore_offset_4097() >> 4;
//LOG_ERROR(RSX, "readrelease: 0x%x, 0x%x, addr:0x%x", arg, index, rsx->label_addr);
auto& sema = vm::ps3::_ref<RsxReports>(rsx->label_addr);
sema.semaphore[index].val = arg;
sema.semaphore[index].pad = 0;
sema.semaphore[index].timestamp = rsx->timestamp();
vm::ps3::write32(rsx->label_addr + method_registers.semaphore_offset_4097(), arg);
}
void back_end_write_semaphore_release(thread* rsx, u32 _reg, u32 arg)
@@ -165,18 +112,8 @@ namespace rsx
}
//TODO: dma
//vm::ps3::write32(rsx->label_addr + method_registers.semaphore_offset_4097(),
// (arg & 0xff00ff00) | ((arg & 0xff) << 16) | ((arg >> 16) & 0xff));
//const u32 addr = get_address(method_registers.semaphore_offset_4097(), rsx->nv4097_semaphore_addr);
//vm::ps3::write32(addr, (arg & 0xff00ff00) | ((arg & 0xff) << 16) | ((arg >> 16) & 0xff));
const u32 index = method_registers.semaphore_offset_4097() >> 4;
u32 val = (arg & 0xff00ff00) | ((arg & 0xff) << 16) | ((arg >> 16) & 0xff);
//LOG_ERROR(RSX, "wriuterelease: 0x%x, 0x%x, addr:0x%x", val, index, rsx->label_addr);
auto& sema = vm::ps3::_ref<RsxReports>(rsx->label_addr);
sema.semaphore[index].val = val;
sema.semaphore[index].pad = 0;
sema.semaphore[index].timestamp = rsx->timestamp();
vm::ps3::write32(rsx->label_addr + method_registers.semaphore_offset_4097(),
(arg & 0xff00ff00) | ((arg & 0xff) << 16) | ((arg >> 16) & 0xff));
}
template<u32 id, u32 index, int count, typename type>
@@ -386,10 +323,10 @@ namespace rsx
switch (report_dma)
{
case blit_engine::context_dma::to_memory_get_report: location = CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_LOCAL; break;
case blit_engine::context_dma::report_location_main: location = CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_MAIN; break;
case blit_engine::context_dma::memory_host_buffer: location = CELL_GCM_CONTEXT_DMA_MEMORY_HOST_BUFFER; break;
//location = CELL_GCM_LOCATION_MAIN; break;
case blit_engine::context_dma::to_memory_get_report: location = CELL_GCM_LOCATION_LOCAL; break;
case blit_engine::context_dma::report_location_main:
case blit_engine::context_dma::memory_host_buffer:
location = CELL_GCM_LOCATION_MAIN; break;
default:
LOG_WARNING(RSX, "nv4097::get_report: bad report dma: 0x%x", (u8)report_dma);
return;
@@ -416,7 +353,7 @@ namespace rsx
break;
}
result->padding = 0;
//result->padding = 0;
}
void clear_report_value(thread* rsx, u32 _reg, u32 arg)
@@ -535,7 +472,6 @@ namespace rsx
if (in_origin != blit_engine::transfer_origin::corner)
{
LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown origin (%d)", (u8)in_origin);
return;
}
if (operation != rsx::blit_engine::transfer_operation::srccopy)
@@ -909,14 +845,31 @@ namespace rsx
}
Emu.Pause();
}
double limit = 0.;
switch (g_cfg.video.frame_limit)
{
case frame_limit_type::none: limit = 0.; break;
case frame_limit_type::_59_94: limit = 59.94; break;
case frame_limit_type::_50: limit = 50.; break;
case frame_limit_type::_60: limit = 60.; break;
case frame_limit_type::_30: limit = 30.; break;
case frame_limit_type::_auto: limit = rsx->fps_limit; break; // TODO
}
if (limit)
{
std::this_thread::sleep_for(std::chrono::milliseconds((s64)(1000.0 / limit - rsx->timer_sync.GetElapsedTimeInMilliSec())));
rsx->timer_sync.Start();
}
rsx->gcm_current_buffer = arg;
rsx->flip(arg);
// After each flip PS3 system is executing a routine that changes registers value to some default.
// Some game use this default state (SH3).
//rsx->reset(); // moved to 'actual' rsx flip command
rsx->reset();
rsx->last_flip_time = get_system_time() - 1000000;
rsx->gcm_current_buffer = arg;
rsx->flip_status = CELL_GCM_DISPLAY_FLIP_STATUS_DONE;
if (rsx->flip_handler)
@@ -934,7 +887,6 @@ namespace rsx
void user_command(thread* rsx, u32, u32 arg)
{
sys_rsx_context_attribute(0x55555555, 0xFEF, 0, arg, 0, 0);
if (rsx->user_handler)
{
rsx->intr_thread->cmd_list
@@ -948,47 +900,6 @@ namespace rsx
}
}
namespace gcm
{
// not entirely sure which one should actually do the flip, or if these should be handled seperately,
// so for now lets flip in queue and just let the driver deal with it
template<u32 index>
struct driver_flip
{
static void impl(thread* rsx, u32 _reg, u32 arg)
{
double limit = 0.;
switch (g_cfg.video.frame_limit)
{
case frame_limit_type::none: limit = 0.; break;
case frame_limit_type::_59_94: limit = 59.94; break;
case frame_limit_type::_50: limit = 50.; break;
case frame_limit_type::_60: limit = 60.; break;
case frame_limit_type::_30: limit = 30.; break;
case frame_limit_type::_auto: limit = rsx->fps_limit; break; // TODO
}
if (limit)
{
std::this_thread::sleep_for(std::chrono::milliseconds((s64)(1000.0 / limit - rsx->timer_sync.GetElapsedTimeInMilliSec())));
rsx->timer_sync.Start();
}
rsx->reset(); // fixes kh, so lets leave it here and see what happens
sys_rsx_context_attribute(0x55555555, 0x102, index, arg, 0, 0);
}
};
template<u32 index>
struct queue_flip
{
static void impl(thread* rsx, u32 _reg, u32 arg)
{
flip_command(rsx, _reg, arg);
sys_rsx_context_attribute(0x55555555, 0x103, index, arg, 0, 0);
}
};
}
void rsx_state::reset()
{
//setup method registers
@@ -1060,7 +971,7 @@ namespace rsx
registers[NV4097_SET_SURFACE_FORMAT] = (8 << 0) | (2 << 5) | (0 << 12) | (1 << 16) | (1 << 24);
// rsx dma initial values
registers[NV4097_SET_CONTEXT_DMA_REPORT] = CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_LOCAL;
registers[NV4097_SET_CONTEXT_DMA_REPORT] = CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_REPORT;
registers[NV406E_SET_CONTEXT_DMA_SEMAPHORE] = CELL_GCM_CONTEXT_DMA_SEMAPHORE_RW;
registers[NV3062_SET_CONTEXT_DMA_IMAGE_DESTIN] = CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER;
registers[NV309E_SET_CONTEXT_DMA_IMAGE] = CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER;
@@ -1170,17 +1081,10 @@ namespace rsx
methods[NV4097_SET_SURFACE_COLOR_BOFFSET] = nullptr;
methods[NV4097_SET_SURFACE_PITCH_B] = nullptr;
methods[NV4097_SET_SURFACE_COLOR_TARGET] = nullptr;
methods[0x224 >> 2] = nullptr;
methods[0x228 >> 2] = nullptr;
methods[0x230 >> 2] = nullptr;
methods[NV4097_SET_SURFACE_PITCH_Z] = nullptr;
methods[NV4097_INVALIDATE_ZCULL] = nullptr;
methods[NV4097_SET_CYLINDRICAL_WRAP] = nullptr;
methods[NV4097_SET_CYLINDRICAL_WRAP1] = nullptr;
methods[0x240 >> 2] = nullptr;
methods[0x244 >> 2] = nullptr;
methods[0x248 >> 2] = nullptr;
methods[0x24C >> 2] = nullptr;
methods[NV4097_SET_SURFACE_PITCH_C] = nullptr;
methods[NV4097_SET_SURFACE_PITCH_D] = nullptr;
methods[NV4097_SET_SURFACE_COLOR_COFFSET] = nullptr;
@@ -1249,7 +1153,6 @@ namespace rsx
methods[NV4097_SET_FOG_MODE] = nullptr;
methods[NV4097_SET_FOG_PARAMS] = nullptr;
methods[NV4097_SET_FOG_PARAMS + 1] = nullptr;
methods[0x8d8 >> 2] = nullptr;
methods[NV4097_SET_SHADER_PROGRAM] = nullptr;
methods[NV4097_SET_VERTEX_TEXTURE_OFFSET] = nullptr;
methods[NV4097_SET_VERTEX_TEXTURE_FORMAT] = nullptr;
@@ -1333,7 +1236,6 @@ namespace rsx
methods[NV4097_SET_TEXTURE_BORDER_COLOR] = nullptr;
methods[NV4097_SET_VERTEX_DATA4F_M] = nullptr;
methods[NV4097_SET_COLOR_KEY_COLOR] = nullptr;
methods[0x1d04 >> 2] = nullptr;
methods[NV4097_SET_SHADER_CONTROL] = nullptr;
methods[NV4097_SET_INDEXED_CONSTANT_READ_LIMITS] = nullptr;
methods[NV4097_SET_SEMAPHORE_OFFSET] = nullptr;
@@ -1460,8 +1362,6 @@ namespace rsx
bind_array<GCM_FLIP_HEAD, 1, 2, nullptr>();
bind_array<GCM_DRIVER_QUEUE, 1, 8, nullptr>();
bind_array<(0x400 >> 2), 1, 0x10, nullptr>();
bind_array<(0x440 >> 2), 1, 0x20, nullptr>();
bind_array<NV4097_SET_ANISO_SPREAD, 1, 16, nullptr>();
bind_array<NV4097_SET_VERTEX_TEXTURE_OFFSET, 1, 8 * 4, nullptr>();
bind_array<NV4097_SET_VERTEX_DATA_SCALED4S_M, 1, 32, nullptr>();
@@ -1484,7 +1384,6 @@ namespace rsx
// NV406E
bind<NV406E_SET_REFERENCE, nv406e::set_reference>();
bind<NV406E_SET_CONTEXT_DMA_SEMAPHORE, nv406e::set_context_dma_semaphore>();
bind<NV406E_SEMAPHORE_ACQUIRE, nv406e::semaphore_acquire>();
bind<NV406E_SEMAPHORE_RELEASE, nv406e::semaphore_release>();
@@ -1499,7 +1398,6 @@ namespace rsx
*/
// NV4097
//bind<NV4097_SET_CONTEXT_DMA_SEMAPHORE, nv4097::set_context_dma_semaphore>();
bind<NV4097_TEXTURE_READ_SEMAPHORE_RELEASE, nv4097::texture_read_semaphore_release>();
bind<NV4097_BACK_END_WRITE_SEMAPHORE_RELEASE, nv4097::back_end_write_semaphore_release>();
bind<NV4097_SET_BEGIN_END, nv4097::set_begin_end>();
@@ -1557,13 +1455,9 @@ namespace rsx
//NV0039
bind<NV0039_BUFFER_NOTIFY, nv0039::buffer_notify>();
// lv1 hypervisor
// custom methods
bind<GCM_FLIP_COMMAND, flip_command>();
bind_array<GCM_SET_USER_COMMAND, 1, 2, user_command>();
bind_range<GCM_FLIP_HEAD, 1, 2, gcm::driver_flip>();
bind_range<GCM_DRIVER_QUEUE, 1, 8, gcm::queue_flip>();
// custom
bind<GCM_FLIP_COMMAND, flip_command>();
return true;
}();
+118 -24
View File
@@ -21,6 +21,7 @@
#include "Utilities/StrUtil.h"
#include "../Crypto/unself.h"
#include "yaml-cpp/yaml.h"
#include <thread>
@@ -206,6 +207,7 @@ void Emulator::Init()
fs::create_dir(dev_hdd0 + "home/00000001/savedata/");
fs::create_dir(dev_hdd0 + "home/00000001/trophy/");
fs::write_file(dev_hdd0 + "home/00000001/localusername", fs::create + fs::excl + fs::write, "User"s);
fs::create_dir(dev_hdd0 + "disc/");
fs::create_dir(dev_hdd1 + "cache/");
fs::create_dir(dev_hdd1 + "game/");
fs::create_path(dev_hdd1);
@@ -258,12 +260,12 @@ bool Emulator::BootGame(const std::string& path, bool direct)
return false;
}
std::string Emulator::GetGameDir()
std::string Emulator::GetHddDir()
{
const std::string& emu_dir_ = g_cfg.vfs.emulator_dir;
const std::string& emu_dir = emu_dir_.empty() ? fs::get_config_dir() : emu_dir_;
return fmt::replace_all(g_cfg.vfs.dev_hdd0, "$(EmulatorDir)", emu_dir) + "game/";
return fmt::replace_all(g_cfg.vfs.dev_hdd0, "$(EmulatorDir)", emu_dir);
}
std::string Emulator::GetLibDir()
@@ -282,25 +284,33 @@ void Emulator::Load()
{
Init();
// Open SELF or ELF
fs::file elf_file(m_path);
// Load game list (maps ABCD12345 IDs to /dev_bdvd/ locations)
YAML::Node games = YAML::Load(fs::file{fs::get_config_dir() + "/games.yml", fs::read + fs::create}.to_string());
if (!elf_file)
if (!games.IsMap())
{
LOG_ERROR(LOADER, "Failed to open file: %s", m_path);
return;
games.reset();
}
LOG_NOTICE(LOADER, "Path: %s", m_path);
const std::string elf_dir = fs::get_parent_dir(m_path);
const fs::file sfov(elf_dir + "/sce_sys/param.sfo");
const fs::file sfo1(elf_dir + "/../PARAM.SFO");
// Load PARAM.SFO (TODO)
const auto _psf = psf::load_object(sfov ? sfov : sfo1);
const auto _psf = psf::load_object([&]
{
if (fs::file sfov{elf_dir + "/sce_sys/param.sfo"})
{
return sfov;
}
else
{
return fs::file(elf_dir + "/../PARAM.SFO");
}
}());
m_title = psf::get_string(_psf, "TITLE", m_path);
m_title_id = psf::get_string(_psf, "TITLE_ID");
const auto _cat = psf::get_string(_psf, "CATEGORY");
LOG_NOTICE(LOADER, "Title: %s", GetTitle());
LOG_NOTICE(LOADER, "Serial: %s", GetTitleID());
@@ -349,19 +359,94 @@ void Emulator::Load()
vfs::mount("dev_usb000", fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir));
vfs::mount("app_home", home_dir.empty() ? elf_dir + '/' : fmt::replace_all(home_dir, "$(EmulatorDir)", emu_dir));
// Mount /dev_bdvd/ if necessary
if (bdvd_dir.empty())
// Detect boot location
const std::string hdd0_game = vfs::get("/dev_hdd0/game/");
const std::string hdd0_disc = vfs::get("/dev_hdd0/disc/");
if (_cat == "DG" && m_path.find(hdd0_game + m_title_id + '/') != -1)
{
size_t pos = elf_dir.rfind("PS3_GAME");
std::string temp = elf_dir.substr(0, pos);
if ((pos != std::string::npos) && fs::is_file(temp + "/PS3_DISC.SFB")) {
bdvd_dir = temp;
// Booting disc game from wrong location
LOG_ERROR(LOADER, "Disc game found at invalid location: /dev_hdd0/game/%s/", m_title_id);
// Move and retry from correct location
if (fs::rename(hdd0_game + m_title_id, hdd0_disc + m_title_id))
{
LOG_SUCCESS(LOADER, "Disc game moved to special location: /dev_hdd0/disc/%s/", m_title_id);
return SetPath(hdd0_disc + m_path.substr(hdd0_game.size())), Load();
}
else
{
LOG_ERROR(LOADER, "Failed to move disc game to /dev_hdd0/disc/%s/ (%s)", m_title_id, fs::g_tls_error);
return;
}
}
// Booting disc game
if (_cat == "DG" && bdvd_dir.empty())
{
// Mount /dev_bdvd/ if necessary
if (auto pos = elf_dir.rfind("/PS3_GAME") + 1)
{
bdvd_dir = elf_dir.substr(0, pos);
}
}
// Booting patch data
if (_cat == "GD" && bdvd_dir.empty())
{
// Load /dev_bdvd/ from game list if available
if (auto node = games[m_title_id])
{
bdvd_dir = node.Scalar();
}
else
{
LOG_FATAL(LOADER, "Disc directory not found. Try to run the game from the actual game disc directory.");
}
}
// Check /dev_bdvd/
if (!bdvd_dir.empty() && fs::is_dir(bdvd_dir))
{
vfs::mount("dev_bdvd", fmt::replace_all(bdvd_dir, "$(EmulatorDir)", emu_dir));
fs::file sfb_file;
vfs::mount("dev_bdvd", bdvd_dir);
LOG_NOTICE(LOADER, "Disc: %s", vfs::get("/dev_bdvd"));
if (!sfb_file.open(vfs::get("/dev_bdvd/PS3_DISC.SFB")) || sfb_file.size() < 4 || sfb_file.read<u32>() != ".SFB"_u32)
{
LOG_ERROR(LOADER, "Invalid disc directory for the disc game %s", m_title_id);
return;
}
const std::string bdvd_title_id = psf::get_string(psf::load_object(fs::file{vfs::get("/dev_bdvd/PS3_GAME/PARAM.SFO")}), "TITLE_ID");
if (bdvd_title_id != m_title_id)
{
LOG_ERROR(LOADER, "Unexpected disc directory for the disc game %s (found %s)", m_title_id, bdvd_title_id);
return;
}
// Store /dev_bdvd/ location
games[m_title_id] = bdvd_dir;
YAML::Emitter out;
out << games;
fs::file(fs::get_config_dir() + "/games.yml", fs::rewrite).write(out.c_str(), out.size());
}
else if (_cat == "DG" || _cat == "GD")
{
LOG_ERROR(LOADER, "Failed to mount disc directory for the disc game %s", m_title_id);
return;
}
// Check game updates
const std::string hdd0_boot = hdd0_game + m_title_id + "/USRDIR/EBOOT.BIN";
if (_cat == "DG" && fs::is_file(hdd0_boot))
{
// Booting game update
LOG_SUCCESS(LOADER, "Updates found at /dev_hdd0/game/%s/!", m_title_id);
return SetPath(hdd0_boot), Load();
}
// Mount /host_root/ if necessary
@@ -370,6 +455,15 @@ void Emulator::Load()
vfs::mount("host_root", {});
}
// Open SELF or ELF
fs::file elf_file(m_path);
if (!elf_file)
{
LOG_ERROR(LOADER, "Failed to open executable: %s", m_path);
return;
}
// Check SELF header
if (elf_file.size() >= 4 && elf_file.read<u32>() == "SCE\0"_u32)
{
@@ -422,16 +516,16 @@ void Emulator::Load()
if (m_elf_path.empty())
{
if (!bdvd_dir.empty() && fs::is_dir(bdvd_dir))
if (m_path.find(hdd0_game) != -1)
{
m_elf_path = "/dev_hdd0/game/" + m_path.substr(hdd0_game.size());
}
else if (!bdvd_dir.empty() && fs::is_dir(bdvd_dir))
{
//Disc games are on /dev_bdvd/
size_t pos = m_path.rfind("PS3_GAME");
m_elf_path = "/dev_bdvd/" + m_path.substr(pos);
}
else if (m_path.find(vfs::get("/dev_hdd0/game/")) != -1)
{
m_elf_path = "/dev_hdd0/game/" + m_path.substr(vfs::get("/dev_hdd0/game/").size());
}
else
{
//For homebrew
@@ -452,7 +546,7 @@ void Emulator::Load()
m_state = system_state::ready;
GetCallbacks().on_ready();
vm::ps3::init();
ppu_load_prx(ppu_prx, "");
ppu_load_prx(ppu_prx, m_path);
}
else if (spu_exec.open(elf_file) == elf_error::ok)
{
@@ -724,7 +818,7 @@ s32 error_code::error_report(const fmt_type_info* sup, u64 arg)
if (ppu.last_function)
{
func = ppu.last_function;
}
}
}
if (g_system == system_type::psv)
+14 -5
View File
@@ -210,6 +210,11 @@ public:
return m_elf_path;
}
const std::string& GetBoot() const
{
return m_path;
}
const std::string& GetTitleID() const
{
return m_title_id;
@@ -232,7 +237,7 @@ public:
bool BootGame(const std::string& path, bool direct = false);
static std::string GetGameDir();
static std::string GetHddDir();
static std::string GetLibDir();
void Load();
@@ -267,6 +272,9 @@ struct cfg_root : cfg::node
cfg::_bool lower_spu_priority{this, "Lower SPU thread priority"};
cfg::_bool spu_debug{this, "SPU Debug"};
cfg::_int<32, 16384> max_spu_immediate_write_size{this, "Maximum immediate DMA write size", 16384}; // Maximum size that an SPU thread can write directly without posting to MFC
cfg::_int<0, 6> preferred_spu_threads{this, "Preferred SPU Threads", 0}; //Numnber of hardware threads dedicated to heavy simultaneous spu tasks
cfg::_int<0, 16> spu_delay_penalty{this, "SPU delay penalty", 3}; //Number of milliseconds to block a thread if a virtual 'core' isn't free
cfg::_bool spu_loop_detection{this, "SPU loop detection", false}; //Try to detect wait loops and trigger thread yield
cfg::_enum<lib_loading_type> lib_loading{this, "Lib Loader", lib_loading_type::automatic};
cfg::_bool hook_functions{this, "Hook static functions"};
@@ -315,12 +323,13 @@ struct cfg_root : cfg::node
cfg::_bool invalidate_surface_cache_every_frame{this, "Invalidate Cache Every Frame", true};
cfg::_bool strict_rendering_mode{this, "Strict Rendering Mode"};
cfg::_bool batch_instanced_geometry{this, "Batch Instanced Geometry", false};
cfg::_int<1, 16> vertex_upload_threads{ this, "Vertex Upload Threads", 1 };
cfg::_bool batch_instanced_geometry{this, "Batch Instanced Geometry", false}; //Avoid re-uploading geometry if the same draw command is repeated
cfg::_int<1, 16> vertex_upload_threads{ this, "Vertex Upload Threads", 1 }; //Max number of threads to use for parallel vertex processing
cfg::_int<32, 65536> mt_vertex_upload_threshold{ this, "Multithreaded Vertex Upload Threshold", 4096}; //Minimum vertex count to parallelize
cfg::_bool frame_skip_enabled{this, "Enable Frame Skip"};
cfg::_int<1, 8> consequtive_frames_to_draw{this, "Consequtive Frames Drawn", 1};
cfg::_int<1, 8> consequtive_frames_to_skip{this, "Consequtive Frames Skept", 1};
cfg::_int<1, 8> consequtive_frames_to_draw{this, "Consecutive Frames Drawn", 1};
cfg::_int<1, 8> consequtive_frames_to_skip{this, "Consecutive Frames Skept", 1};
struct node_d3d12 : cfg::node
{
+2 -2
View File
@@ -31,7 +31,7 @@
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -95,4 +95,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Some files were not shown because too many files have changed in this diff Show More