code: Add clang-format target and CI workflow (#82)
* code: Add clang format target, rules and CI workflow * code: Run clang format on sources
This commit is contained in:
parent
32a5ff15bb
commit
6f4c6ae0bb
|
@ -0,0 +1,37 @@
|
||||||
|
#!/bin/bash -ex
|
||||||
|
|
||||||
|
if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .ci* dist/*.desktop \
|
||||||
|
dist/*.svg dist/*.xml; then
|
||||||
|
echo Trailing whitespace found, aborting
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Default clang-format points to default 3.5 version one
|
||||||
|
CLANG_FORMAT=clang-format-15
|
||||||
|
$CLANG_FORMAT --version
|
||||||
|
|
||||||
|
if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
|
||||||
|
# Get list of every file modified in this pull request
|
||||||
|
files_to_lint="$(git diff --name-only --diff-filter=ACMRTUXB $COMMIT_RANGE | grep '^src/[^.]*[.]\(cpp\|h\)$' || true)"
|
||||||
|
else
|
||||||
|
# Check everything for branch pushes
|
||||||
|
files_to_lint="$(find src/ -name '*.cpp' -or -name '*.h')"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Turn off tracing for this because it's too verbose
|
||||||
|
set +x
|
||||||
|
|
||||||
|
for f in $files_to_lint; do
|
||||||
|
d=$(diff -u "$f" <($CLANG_FORMAT "$f") || true)
|
||||||
|
if ! [ -z "$d" ]; then
|
||||||
|
echo "!!! $f not compliant to coding style, here is the fix:"
|
||||||
|
echo "$d"
|
||||||
|
fail=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
set -x
|
||||||
|
|
||||||
|
if [ "$fail" = 1 ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
|
@ -0,0 +1,21 @@
|
||||||
|
name: Clang Format
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "*" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
clang-format:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Install
|
||||||
|
run: sudo apt-get install clang-format-15
|
||||||
|
- name: Build
|
||||||
|
env:
|
||||||
|
COMMIT_RANGE: ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}
|
||||||
|
run: ./.ci/clang-format.sh
|
|
@ -27,6 +27,57 @@ function(create_target_directory_groups target_name)
|
||||||
endforeach()
|
endforeach()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
|
||||||
|
# Setup a custom clang-format target (if clang-format can be found) that will run
|
||||||
|
# against all the src files. This should be used before making a pull request.
|
||||||
|
# =======================================================================
|
||||||
|
|
||||||
|
set(CLANG_FORMAT_POSTFIX "-15")
|
||||||
|
find_program(CLANG_FORMAT
|
||||||
|
NAMES clang-format${CLANG_FORMAT_POSTFIX}
|
||||||
|
clang-format
|
||||||
|
PATHS ${PROJECT_BINARY_DIR}/externals)
|
||||||
|
# if find_program doesn't find it, try to download from externals
|
||||||
|
if (NOT CLANG_FORMAT)
|
||||||
|
if (WIN32)
|
||||||
|
message(STATUS "Clang format not found! Downloading...")
|
||||||
|
set(CLANG_FORMAT "${PROJECT_BINARY_DIR}/externals/clang-format${CLANG_FORMAT_POSTFIX}.exe")
|
||||||
|
file(DOWNLOAD
|
||||||
|
https://github.com/citra-emu/ext-windows-bin/raw/master/clang-format${CLANG_FORMAT_POSTFIX}.exe
|
||||||
|
"${CLANG_FORMAT}" SHOW_PROGRESS
|
||||||
|
STATUS DOWNLOAD_SUCCESS)
|
||||||
|
if (NOT DOWNLOAD_SUCCESS EQUAL 0)
|
||||||
|
message(WARNING "Could not download clang format! Disabling the clang format target")
|
||||||
|
file(REMOVE ${CLANG_FORMAT})
|
||||||
|
unset(CLANG_FORMAT)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message(WARNING "Clang format not found! Disabling the clang format target")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (CLANG_FORMAT)
|
||||||
|
set(SRCS ${PROJECT_SOURCE_DIR}/src)
|
||||||
|
set(CCOMMENT "Running clang format against all the .h and .cpp files in src/")
|
||||||
|
if (WIN32)
|
||||||
|
if(MINGW)
|
||||||
|
add_custom_target(clang-format
|
||||||
|
COMMAND find `cygpath -u ${SRCS}` -iname *.h -o -iname *.cpp -o -iname *.mm | xargs `cygpath -u ${CLANG_FORMAT}` -i
|
||||||
|
COMMENT ${CCOMMENT})
|
||||||
|
else()
|
||||||
|
add_custom_target(clang-format
|
||||||
|
COMMAND powershell.exe -Command "Get-ChildItem '${SRCS}/*' -Include *.cpp,*.h,*.mm -Recurse | Foreach {&'${CLANG_FORMAT}' -i $_.fullname}"
|
||||||
|
COMMENT ${CCOMMENT})
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
add_custom_target(clang-format
|
||||||
|
COMMAND find ${SRCS} -iname *.h -o -iname *.cpp -o -iname *.mm | xargs ${CLANG_FORMAT} -i
|
||||||
|
COMMENT ${CCOMMENT})
|
||||||
|
endif()
|
||||||
|
unset(SRCS)
|
||||||
|
unset(CCOMMENT)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_subdirectory(third-party)
|
add_subdirectory(third-party)
|
||||||
include_directories(src)
|
include_directories(src)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,256 @@
|
||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
# BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
AlignEscapedNewlinesLeft: false
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: true
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BraceWrapping:
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: false
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
ColumnLimit: 100
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^\<[^Q][^/.>]*\>'
|
||||||
|
Priority: -2
|
||||||
|
- Regex: '^\<'
|
||||||
|
Priority: -1
|
||||||
|
- Regex: '^\"'
|
||||||
|
Priority: 0
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentWidth: 4
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBlockIndentWidth: 2
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyExcessCharacter: 1000000
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 150
|
||||||
|
PointerAlignment: Left
|
||||||
|
ReflowComments: true
|
||||||
|
SortIncludes: true
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Cpp11
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
||||||
|
---
|
||||||
|
Language: Java
|
||||||
|
# BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
AlignEscapedNewlinesLeft: false
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: true
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BraceWrapping:
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: false
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
ColumnLimit: 100
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^\<[^Q][^/.>]*\>'
|
||||||
|
Priority: -2
|
||||||
|
- Regex: '^\<'
|
||||||
|
Priority: -1
|
||||||
|
- Regex: '^\"'
|
||||||
|
Priority: 0
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentWidth: 4
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBlockIndentWidth: 2
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyExcessCharacter: 1000000
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 150
|
||||||
|
PointerAlignment: Left
|
||||||
|
ReflowComments: true
|
||||||
|
SortIncludes: true
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
||||||
|
---
|
||||||
|
Language: ObjC
|
||||||
|
# BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
AlignEscapedNewlinesLeft: false
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: true
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BraceWrapping:
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: false
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
ColumnLimit: 100
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^\<[^Q][^/.>]*\>'
|
||||||
|
Priority: -2
|
||||||
|
- Regex: '^\<'
|
||||||
|
Priority: -1
|
||||||
|
- Regex: '^\"'
|
||||||
|
Priority: 0
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentWidth: 4
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBlockIndentWidth: 2
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyExcessCharacter: 1000000
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 150
|
||||||
|
PointerAlignment: Left
|
||||||
|
ReflowComments: true
|
||||||
|
SortIncludes: true
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
||||||
|
...
|
|
@ -1,8 +1,9 @@
|
||||||
#include "controller.h"
|
|
||||||
#include <core/hle/libraries/libkernel/time_management.h>
|
#include <core/hle/libraries/libkernel/time_management.h>
|
||||||
|
#include "controller.h"
|
||||||
|
|
||||||
namespace Emulator::Host::Controller {
|
namespace Emulator::Host::Controller {
|
||||||
GameController::GameController() { m_states_num = 0;
|
GameController::GameController() {
|
||||||
|
m_states_num = 0;
|
||||||
m_last_state = State();
|
m_last_state = State();
|
||||||
}
|
}
|
||||||
void GameController::readState(State* state, bool* isConnected, int* connectedCount) {
|
void GameController::readState(State* state, bool* isConnected, int* connectedCount) {
|
||||||
|
@ -50,4 +51,4 @@ void GameController::checKButton(int id, u32 button, bool isPressed) {
|
||||||
addState(state);
|
addState(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Emulator::Host::Controller
|
} // namespace Emulator::Host::Controller
|
|
@ -1,17 +1,17 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "common/types.h"
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include "common/types.h"
|
||||||
|
|
||||||
namespace Emulator::Host::Controller {
|
namespace Emulator::Host::Controller {
|
||||||
struct State {
|
struct State {
|
||||||
u32 buttonsState =0;
|
u32 buttonsState = 0;
|
||||||
u64 time = 0;
|
u64 time = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr u32 MAX_STATES = 64;
|
constexpr u32 MAX_STATES = 64;
|
||||||
|
|
||||||
class GameController {
|
class GameController {
|
||||||
public:
|
public:
|
||||||
GameController();
|
GameController();
|
||||||
virtual ~GameController() = default;
|
virtual ~GameController() = default;
|
||||||
|
|
||||||
|
@ -20,8 +20,7 @@ class GameController {
|
||||||
void checKButton(int id, u32 button, bool isPressed);
|
void checKButton(int id, u32 button, bool isPressed);
|
||||||
void addState(const State& state);
|
void addState(const State& state);
|
||||||
|
|
||||||
|
private:
|
||||||
private:
|
|
||||||
std::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
bool m_connected = false;
|
bool m_connected = false;
|
||||||
State m_last_state;
|
State m_last_state;
|
||||||
|
@ -31,4 +30,4 @@ class GameController {
|
||||||
State m_states[MAX_STATES];
|
State m_states[MAX_STATES];
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Emulator::HLE::Libraries::Controller
|
} // namespace Emulator::Host::Controller
|
|
@ -1,5 +1,5 @@
|
||||||
#include "core/loader/elf.h"
|
|
||||||
#include "GUI/ElfViewer.h"
|
#include "GUI/ElfViewer.h"
|
||||||
|
#include "core/loader/elf.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
||||||
ElfViewer::ElfViewer(Core::Loader::Elf* elf) {
|
ElfViewer::ElfViewer(Core::Loader::Elf* elf) {
|
||||||
|
@ -15,82 +15,81 @@ void ElfViewer::Display(bool enabled) {
|
||||||
static int selected = -1;
|
static int selected = -1;
|
||||||
ImGui::Begin("Self/Elf Viewer", &enabled);
|
ImGui::Begin("Self/Elf Viewer", &enabled);
|
||||||
|
|
||||||
ImGui::BeginChild("Left Tree pane", ImVec2(300, 0), false);//left tree
|
ImGui::BeginChild("Left Tree pane", ImVec2(300, 0), false); // left tree
|
||||||
if (elf->isSelfFile())
|
if (elf->isSelfFile()) {
|
||||||
{
|
if (ImGui::TreeNode("Self")) {
|
||||||
if (ImGui::TreeNode("Self"))
|
if (ImGui::TreeNodeEx("Self Header",
|
||||||
{
|
ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen,
|
||||||
if (ImGui::TreeNodeEx("Self Header", ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen, "Self Header"))
|
"Self Header")) {
|
||||||
{
|
|
||||||
if (ImGui::IsItemClicked())
|
if (ImGui::IsItemClicked())
|
||||||
selected = SELF_HEADER;
|
selected = SELF_HEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::TreeNode("Self Segment Header"))
|
if (ImGui::TreeNode("Self Segment Header")) {
|
||||||
{
|
|
||||||
const auto self = elf->GetSElfHeader();
|
const auto self = elf->GetSElfHeader();
|
||||||
for (u16 i = 0; i < self.segment_count; i++)
|
for (u16 i = 0; i < self.segment_count; i++) {
|
||||||
{
|
if (ImGui::TreeNodeEx((void*)(intptr_t)i,
|
||||||
if (ImGui::TreeNodeEx((void*)(intptr_t)i, ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen, "%d", i))
|
ImGuiTreeNodeFlags_Leaf |
|
||||||
{
|
ImGuiTreeNodeFlags_NoTreePushOnOpen,
|
||||||
|
"%d", i)) {
|
||||||
if (ImGui::IsItemClicked())
|
if (ImGui::IsItemClicked())
|
||||||
selected = SEG_HEADER_START+i;
|
selected = SEG_HEADER_START + i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
ImGui::TreeNodeEx("Self Id Header", ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen, "Self Id Header");
|
ImGui::TreeNodeEx("Self Id Header",
|
||||||
|
ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen,
|
||||||
|
"Self Id Header");
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ImGui::TreeNode("Elf"))
|
if (ImGui::TreeNode("Elf")) {
|
||||||
{
|
|
||||||
const auto elf_header = elf->GetElfHeader();
|
const auto elf_header = elf->GetElfHeader();
|
||||||
if (ImGui::TreeNodeEx("Elf Header", ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen, "Elf Header"))
|
if (ImGui::TreeNodeEx("Elf Header",
|
||||||
{
|
ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen,
|
||||||
|
"Elf Header")) {
|
||||||
if (ImGui::IsItemClicked())
|
if (ImGui::IsItemClicked())
|
||||||
selected = ELF_HEADER;
|
selected = ELF_HEADER;
|
||||||
}
|
}
|
||||||
if (ImGui::TreeNode("Elf Program Headers"))
|
if (ImGui::TreeNode("Elf Program Headers")) {
|
||||||
{
|
|
||||||
const auto pheader = elf->GetProgramHeader();
|
const auto pheader = elf->GetProgramHeader();
|
||||||
for (u16 i = 0; i < elf_header.e_phnum; i++)
|
for (u16 i = 0; i < elf_header.e_phnum; i++) {
|
||||||
{
|
std::string ProgramInfo = elf->ElfPheaderFlagsStr(pheader[i].p_flags) + " " +
|
||||||
std::string ProgramInfo = elf->ElfPheaderFlagsStr(pheader[i].p_flags) + " " + elf->ElfPheaderTypeStr(pheader[i].p_type);
|
elf->ElfPheaderTypeStr(pheader[i].p_type);
|
||||||
if (ImGui::TreeNodeEx((void*)(intptr_t)i,ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen, "%d - %s", i,ProgramInfo.c_str()))
|
if (ImGui::TreeNodeEx((void*)(intptr_t)i,
|
||||||
{
|
ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen,
|
||||||
|
"%d - %s", i, ProgramInfo.c_str())) {
|
||||||
if (ImGui::IsItemClicked())
|
if (ImGui::IsItemClicked())
|
||||||
selected = ELF_PROGRAM_HEADER_START + i;
|
selected = ELF_PROGRAM_HEADER_START + i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
if (elf_header.e_shnum != 0)
|
if (elf_header.e_shnum != 0) {
|
||||||
{
|
if (ImGui::TreeNode("Elf Section Headers")) {
|
||||||
if (ImGui::TreeNode("Elf Section Headers"))
|
|
||||||
{
|
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
ImGui::EndChild();//end of left tree
|
ImGui::EndChild(); // end of left tree
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
ImGui::BeginChild("Table View", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us
|
ImGui::BeginChild(
|
||||||
|
"Table View",
|
||||||
|
ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us
|
||||||
if (selected == SELF_HEADER) {
|
if (selected == SELF_HEADER) {
|
||||||
ImGui::TextWrapped("%s", elf->SElfHeaderStr().c_str());
|
ImGui::TextWrapped("%s", elf->SElfHeaderStr().c_str());
|
||||||
}
|
}
|
||||||
if (selected >= 100 && selected < 200)
|
if (selected >= 100 && selected < 200) {
|
||||||
{
|
ImGui::TextWrapped("%s", elf->SELFSegHeader(selected - 100).c_str());
|
||||||
ImGui::TextWrapped("%s", elf->SELFSegHeader(selected-100).c_str());
|
|
||||||
}
|
}
|
||||||
if (selected == ELF_HEADER) {
|
if (selected == ELF_HEADER) {
|
||||||
ImGui::TextWrapped("%s", elf->ElfHeaderStr().c_str());
|
ImGui::TextWrapped("%s", elf->ElfHeaderStr().c_str());
|
||||||
}
|
}
|
||||||
if (selected >= 200 && selected < 300)
|
if (selected >= 200 && selected < 300) {
|
||||||
{
|
|
||||||
ImGui::TextWrapped("%s", elf->ElfPHeaderStr(selected - 200).c_str());
|
ImGui::TextWrapped("%s", elf->ElfPHeaderStr(selected - 200).c_str());
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
|
|
@ -10,12 +10,20 @@ namespace Config {
|
||||||
bool isNeo = false;
|
bool isNeo = false;
|
||||||
u32 screenWidth = 1280;
|
u32 screenWidth = 1280;
|
||||||
u32 screenHeight = 720;
|
u32 screenHeight = 720;
|
||||||
u32 logLevel = 0; // TRACE = 0 , DEBUG = 1 , INFO = 2 , WARN = 3 , ERROR = 4 , CRITICAL = 5, OFF = 6
|
u32 logLevel = 0; // TRACE = 0 , DEBUG = 1 , INFO = 2 , WARN = 3 , ERROR = 4 , CRITICAL = 5, OFF = 6
|
||||||
|
|
||||||
bool isNeoMode() { return isNeo; }
|
bool isNeoMode() {
|
||||||
u32 getScreenWidth() { return screenWidth; }
|
return isNeo;
|
||||||
u32 getScreenHeight() { return screenHeight; }
|
}
|
||||||
u32 getLogLevel() { return logLevel; }
|
u32 getScreenWidth() {
|
||||||
|
return screenWidth;
|
||||||
|
}
|
||||||
|
u32 getScreenHeight() {
|
||||||
|
return screenHeight;
|
||||||
|
}
|
||||||
|
u32 getLogLevel() {
|
||||||
|
return logLevel;
|
||||||
|
}
|
||||||
|
|
||||||
void load(const std::filesystem::path& path) {
|
void load(const std::filesystem::path& path) {
|
||||||
// If the configuration file does not exist, create it and return
|
// If the configuration file does not exist, create it and return
|
||||||
|
@ -67,7 +75,8 @@ void save(const std::filesystem::path& path) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (error) {
|
if (error) {
|
||||||
fmt::print("Filesystem error accessing {} (error: {})\n", path.string(), error.message().c_str());
|
fmt::print("Filesystem error accessing {} (error: {})\n", path.string(),
|
||||||
|
error.message().c_str());
|
||||||
}
|
}
|
||||||
fmt::print("Saving new configuration file {}\n", path.string());
|
fmt::print("Saving new configuration file {}\n", path.string());
|
||||||
}
|
}
|
||||||
|
@ -81,4 +90,4 @@ void save(const std::filesystem::path& path) {
|
||||||
file << data;
|
file << data;
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
} // namespace Config
|
} // namespace Config
|
||||||
|
|
|
@ -12,4 +12,4 @@ u32 getLogLevel();
|
||||||
u32 getScreenWidth();
|
u32 getScreenWidth();
|
||||||
u32 getScreenHeight();
|
u32 getScreenHeight();
|
||||||
|
|
||||||
}; // namespace Config
|
}; // namespace Config
|
||||||
|
|
|
@ -1,31 +1,32 @@
|
||||||
#include "common/disassembler.h"
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
#include "common/disassembler.h"
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
Disassembler::Disassembler() {
|
Disassembler::Disassembler() {
|
||||||
ZydisDecoderInit(&m_decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64);
|
ZydisDecoderInit(&m_decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64);
|
||||||
ZydisFormatterInit(&m_formatter, ZYDIS_FORMATTER_STYLE_INTEL);
|
ZydisFormatterInit(&m_formatter, ZYDIS_FORMATTER_STYLE_INTEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
Disassembler::~Disassembler() = default;
|
Disassembler::~Disassembler() = default;
|
||||||
|
|
||||||
void Disassembler::printInstruction(void* code, u64 address) {
|
void Disassembler::printInstruction(void* code, u64 address) {
|
||||||
ZydisDecodedInstruction instruction;
|
ZydisDecodedInstruction instruction;
|
||||||
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT_VISIBLE];
|
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT_VISIBLE];
|
||||||
ZyanStatus status = ZydisDecoderDecodeFull(&m_decoder, code, sizeof(code),
|
ZyanStatus status =
|
||||||
&instruction, operands);
|
ZydisDecoderDecodeFull(&m_decoder, code, sizeof(code), &instruction, operands);
|
||||||
if (!ZYAN_SUCCESS(status)) {
|
if (!ZYAN_SUCCESS(status)) {
|
||||||
fmt::print("decode instruction failed at {}\n", fmt::ptr(code));
|
fmt::print("decode instruction failed at {}\n", fmt::ptr(code));
|
||||||
} else {
|
} else {
|
||||||
printInst(instruction, operands,address);
|
printInst(instruction, operands, address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Disassembler::printInst(ZydisDecodedInstruction& inst, ZydisDecodedOperand* operands, u64 address) {
|
void Disassembler::printInst(ZydisDecodedInstruction& inst, ZydisDecodedOperand* operands,
|
||||||
const int bufLen = 256;
|
u64 address) {
|
||||||
char szBuffer[bufLen];
|
const int bufLen = 256;
|
||||||
ZydisFormatterFormatInstruction(&m_formatter, &inst, operands,inst.operand_count_visible,
|
char szBuffer[bufLen];
|
||||||
|
ZydisFormatterFormatInstruction(&m_formatter, &inst, operands, inst.operand_count_visible,
|
||||||
szBuffer, sizeof(szBuffer), address, ZYAN_NULL);
|
szBuffer, sizeof(szBuffer), address, ZYAN_NULL);
|
||||||
fmt::print("instruction: {}\n", szBuffer);
|
fmt::print("instruction: {}\n", szBuffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,15 +7,15 @@ namespace Common {
|
||||||
|
|
||||||
class Disassembler {
|
class Disassembler {
|
||||||
public:
|
public:
|
||||||
Disassembler();
|
Disassembler();
|
||||||
~Disassembler();
|
~Disassembler();
|
||||||
|
|
||||||
void printInst(ZydisDecodedInstruction& inst, ZydisDecodedOperand* operands, u64 address);
|
void printInst(ZydisDecodedInstruction& inst, ZydisDecodedOperand* operands, u64 address);
|
||||||
void printInstruction(void* code, u64 address);
|
void printInstruction(void* code, u64 address);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ZydisDecoder m_decoder;
|
ZydisDecoder m_decoder;
|
||||||
ZydisFormatter m_formatter;
|
ZydisFormatter m_formatter;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Common
|
} // namespace Common
|
||||||
|
|
|
@ -4,34 +4,34 @@
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
void Discord::RPC::init() {
|
void Discord::RPC::init() {
|
||||||
DiscordEventHandlers handlers{};
|
DiscordEventHandlers handlers{};
|
||||||
Discord_Initialize("1139939140494971051", &handlers, 1, nullptr);
|
Discord_Initialize("1139939140494971051", &handlers, 1, nullptr);
|
||||||
|
|
||||||
startTimestamp = time(nullptr);
|
startTimestamp = time(nullptr);
|
||||||
enabled = true;
|
enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Discord::RPC::update(Discord::RPCStatus status, const std::string& game) {
|
void Discord::RPC::update(Discord::RPCStatus status, const std::string& game) {
|
||||||
DiscordRichPresence rpc{};
|
DiscordRichPresence rpc{};
|
||||||
|
|
||||||
if (status == Discord::RPCStatus::Playing) {
|
if (status == Discord::RPCStatus::Playing) {
|
||||||
rpc.details = "Playing a game";
|
rpc.details = "Playing a game";
|
||||||
rpc.state = game.c_str();
|
rpc.state = game.c_str();
|
||||||
} else {
|
} else {
|
||||||
rpc.details = "Idle";
|
rpc.details = "Idle";
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc.largeImageKey = "shadps4";
|
rpc.largeImageKey = "shadps4";
|
||||||
rpc.largeImageText = "ShadPS4 is a PS4 emulator";
|
rpc.largeImageText = "ShadPS4 is a PS4 emulator";
|
||||||
rpc.startTimestamp = startTimestamp;
|
rpc.startTimestamp = startTimestamp;
|
||||||
|
|
||||||
Discord_UpdatePresence(&rpc);
|
Discord_UpdatePresence(&rpc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Discord::RPC::stop() {
|
void Discord::RPC::stop() {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
enabled = false;
|
enabled = false;
|
||||||
Discord_ClearPresence();
|
Discord_ClearPresence();
|
||||||
Discord_Shutdown();
|
Discord_Shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <discord_rpc.h>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <discord_rpc.h>
|
||||||
|
|
||||||
namespace Discord {
|
namespace Discord {
|
||||||
enum class RPCStatus { Idling, Playing };
|
enum class RPCStatus { Idling, Playing };
|
||||||
|
|
||||||
class RPC {
|
class RPC {
|
||||||
std::uint64_t startTimestamp;
|
std::uint64_t startTimestamp;
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void init();
|
void init();
|
||||||
void update(RPCStatus status, const std::string& title);
|
void update(RPCStatus status, const std::string& title);
|
||||||
void stop();
|
void stop();
|
||||||
};
|
};
|
||||||
} // namespace Discord
|
} // namespace Discord
|
||||||
|
|
|
@ -24,8 +24,8 @@ bool File::open(const std::string& path, OpenMode mode) {
|
||||||
|
|
||||||
bool File::close() {
|
bool File::close() {
|
||||||
if (!isOpen() || std::fclose(m_file) != 0) [[unlikely]] {
|
if (!isOpen() || std::fclose(m_file) != 0) [[unlikely]] {
|
||||||
m_file = nullptr;
|
m_file = nullptr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_file = nullptr;
|
m_file = nullptr;
|
||||||
|
@ -56,9 +56,9 @@ bool File::seek(s64 offset, SeekMode mode) {
|
||||||
u64 File::tell() const {
|
u64 File::tell() const {
|
||||||
if (isOpen()) [[likely]] {
|
if (isOpen()) [[likely]] {
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
return _ftelli64(m_file);
|
return _ftelli64(m_file);
|
||||||
#else
|
#else
|
||||||
return ftello64(m_file);
|
return ftello64(m_file);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,22 +69,22 @@ u64 File::getFileSize() {
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
const u64 pos = _ftelli64(m_file);
|
const u64 pos = _ftelli64(m_file);
|
||||||
if (_fseeki64(m_file, 0, SEEK_END) != 0) {
|
if (_fseeki64(m_file, 0, SEEK_END) != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u64 size = _ftelli64(m_file);
|
const u64 size = _ftelli64(m_file);
|
||||||
if (_fseeki64(m_file, pos, SEEK_SET) != 0) {
|
if (_fseeki64(m_file, pos, SEEK_SET) != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
const u64 pos = ftello64(m_file);
|
const u64 pos = ftello64(m_file);
|
||||||
if (fseeko64(m_file, 0, SEEK_END) != 0) {
|
if (fseeko64(m_file, 0, SEEK_END) != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u64 size = ftello64(m_file);
|
const u64 size = ftello64(m_file);
|
||||||
if (fseeko64(m_file, pos, SEEK_SET) != 0) {
|
if (fseeko64(m_file, pos, SEEK_SET) != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return size;
|
return size;
|
||||||
|
|
|
@ -2,19 +2,15 @@
|
||||||
|
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <string>
|
|
||||||
#include <span>
|
#include <span>
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
||||||
namespace Common::FS {
|
namespace Common::FS {
|
||||||
|
|
||||||
enum class OpenMode : u32 {
|
enum class OpenMode : u32 { Read = 0x1, Write = 0x2, ReadWrite = Read | Write };
|
||||||
Read = 0x1,
|
|
||||||
Write = 0x2,
|
|
||||||
ReadWrite = Read | Write
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class SeekMode : u32 {
|
enum class SeekMode : u32 {
|
||||||
Set,
|
Set,
|
||||||
|
@ -23,7 +19,7 @@ enum class SeekMode : u32 {
|
||||||
};
|
};
|
||||||
|
|
||||||
class File {
|
class File {
|
||||||
public:
|
public:
|
||||||
File();
|
File();
|
||||||
explicit File(const std::string& path, OpenMode mode = OpenMode::Read);
|
explicit File(const std::string& path, OpenMode mode = OpenMode::Read);
|
||||||
~File();
|
~File();
|
||||||
|
@ -52,27 +48,27 @@ class File {
|
||||||
|
|
||||||
const char* getOpenMode(OpenMode mode) const {
|
const char* getOpenMode(OpenMode mode) const {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case OpenMode::Read:
|
case OpenMode::Read:
|
||||||
return "rb";
|
return "rb";
|
||||||
case OpenMode::Write:
|
case OpenMode::Write:
|
||||||
return "wb";
|
return "wb";
|
||||||
case OpenMode::ReadWrite:
|
case OpenMode::ReadWrite:
|
||||||
return "r+b";
|
return "r+b";
|
||||||
default:
|
default:
|
||||||
return "r";
|
return "r";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int getSeekMode(SeekMode mode) const {
|
int getSeekMode(SeekMode mode) const {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case SeekMode::Set:
|
case SeekMode::Set:
|
||||||
return SEEK_SET;
|
return SEEK_SET;
|
||||||
case SeekMode::Cur:
|
case SeekMode::Cur:
|
||||||
return SEEK_CUR;
|
return SEEK_CUR;
|
||||||
case SeekMode::End:
|
case SeekMode::End:
|
||||||
return SEEK_END;
|
return SEEK_END;
|
||||||
default:
|
default:
|
||||||
return SEEK_SET;
|
return SEEK_SET;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +76,7 @@ class File {
|
||||||
return m_file;
|
return m_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::FILE* m_file{};
|
std::FILE* m_file{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "io_file.h"
|
#include "io_file.h"
|
||||||
|
|
||||||
//#include "helpers.hpp"
|
// #include "helpers.hpp"
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
// 64 bit offsets for MSVC
|
// 64 bit offsets for MSVC
|
||||||
|
@ -118,8 +118,8 @@ FILE* IOFile::getHandle() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void IOFile::setAppDataDir(const std::filesystem::path& dir) {
|
void IOFile::setAppDataDir(const std::filesystem::path& dir) {
|
||||||
//if (dir == "")
|
// if (dir == "")
|
||||||
// Helpers::panic("Failed to set app data directory");
|
// Helpers::panic("Failed to set app data directory");
|
||||||
appData = dir;
|
appData = dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
|
|
||||||
class IOFile {
|
class IOFile {
|
||||||
FILE* handle = nullptr;
|
FILE* handle = nullptr;
|
||||||
static inline std::filesystem::path appData =""; // Directory for holding app data. AppData on Windows
|
static inline std::filesystem::path appData =
|
||||||
|
""; // Directory for holding app data. AppData on Windows
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IOFile() : handle(nullptr) {}
|
IOFile() : handle(nullptr) {}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
#include <vector>
|
||||||
|
#include <Util/config.h>
|
||||||
#include <spdlog/common.h>
|
#include <spdlog/common.h>
|
||||||
#include <spdlog/pattern_formatter.h>
|
#include <spdlog/pattern_formatter.h>
|
||||||
#include <spdlog/sinks/basic_file_sink.h>
|
#include <spdlog/sinks/basic_file_sink.h>
|
||||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
#include <vector>
|
|
||||||
#include <Util/config.h>
|
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
@ -30,19 +30,20 @@ uint64_t tls_access(int64_t tls_offset) {
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
static LONG WINAPI ExceptionHandler(PEXCEPTION_POINTERS pExp) noexcept {
|
static LONG WINAPI ExceptionHandler(PEXCEPTION_POINTERS pExp) noexcept {
|
||||||
auto orig_rip = pExp->ContextRecord->Rip;
|
auto orig_rip = pExp->ContextRecord->Rip;
|
||||||
while (*(uint8_t *)pExp->ContextRecord->Rip == 0x66) pExp->ContextRecord->Rip++;
|
while (*(uint8_t*)pExp->ContextRecord->Rip == 0x66)
|
||||||
|
pExp->ContextRecord->Rip++;
|
||||||
|
|
||||||
if (*(uint8_t *)pExp->ContextRecord->Rip == 0xcd) {
|
if (*(uint8_t*)pExp->ContextRecord->Rip == 0xcd) {
|
||||||
int reg = *(uint8_t *)(pExp->ContextRecord->Rip + 1) - 0x80;
|
int reg = *(uint8_t*)(pExp->ContextRecord->Rip + 1) - 0x80;
|
||||||
int sizes = *(uint8_t *)(pExp->ContextRecord->Rip + 2);
|
int sizes = *(uint8_t*)(pExp->ContextRecord->Rip + 2);
|
||||||
int pattern_size = sizes & 0xF;
|
int pattern_size = sizes & 0xF;
|
||||||
int imm_size = sizes >> 4;
|
int imm_size = sizes >> 4;
|
||||||
|
|
||||||
int64_t tls_offset;
|
int64_t tls_offset;
|
||||||
if (imm_size == 4)
|
if (imm_size == 4)
|
||||||
tls_offset = *(int32_t *)(pExp->ContextRecord->Rip + pattern_size);
|
tls_offset = *(int32_t*)(pExp->ContextRecord->Rip + pattern_size);
|
||||||
else
|
else
|
||||||
tls_offset = *(int64_t *)(pExp->ContextRecord->Rip + pattern_size);
|
tls_offset = *(int64_t*)(pExp->ContextRecord->Rip + pattern_size);
|
||||||
|
|
||||||
(&pExp->ContextRecord->Rax)[reg] = tls_access(tls_offset); /* TLS_ACCESS */
|
(&pExp->ContextRecord->Rax)[reg] = tls_access(tls_offset); /* TLS_ACCESS */
|
||||||
pExp->ContextRecord->Rip += pattern_size + imm_size;
|
pExp->ContextRecord->Rip += pattern_size + imm_size;
|
||||||
|
@ -53,57 +54,61 @@ static LONG WINAPI ExceptionHandler(PEXCEPTION_POINTERS pExp) noexcept {
|
||||||
pExp->ContextRecord->Rip = orig_rip;
|
pExp->ContextRecord->Rip = orig_rip;
|
||||||
const u32 ec = pExp->ExceptionRecord->ExceptionCode;
|
const u32 ec = pExp->ExceptionRecord->ExceptionCode;
|
||||||
switch (ec) {
|
switch (ec) {
|
||||||
case EXCEPTION_ACCESS_VIOLATION: {
|
case EXCEPTION_ACCESS_VIOLATION: {
|
||||||
LOG_CRITICAL_IF(log_file_exceptions, "Exception EXCEPTION_ACCESS_VIOLATION ({:#x}). ", ec);
|
LOG_CRITICAL_IF(log_file_exceptions, "Exception EXCEPTION_ACCESS_VIOLATION ({:#x}). ", ec);
|
||||||
const auto info = pExp->ExceptionRecord->ExceptionInformation;
|
const auto info = pExp->ExceptionRecord->ExceptionInformation;
|
||||||
switch (info[0]) {
|
switch (info[0]) {
|
||||||
case 0:
|
case 0:
|
||||||
LOG_CRITICAL_IF(log_file_exceptions, "Read violation at address {:#x}.", info[1]);
|
LOG_CRITICAL_IF(log_file_exceptions, "Read violation at address {:#x}.", info[1]);
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
LOG_CRITICAL_IF(log_file_exceptions, "Write violation at address {:#x}.", info[1]);
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
LOG_CRITICAL_IF(log_file_exceptions, "DEP violation at address {:#x}.", info[1]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
case 1:
|
||||||
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
LOG_CRITICAL_IF(log_file_exceptions, "Write violation at address {:#x}.", info[1]);
|
||||||
LOG_CRITICAL_IF(log_file_exceptions, "Exception EXCEPTION_ARRAY_BOUNDS_EXCEEDED ({:#x}). ", ec);
|
|
||||||
break;
|
break;
|
||||||
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
case 8:
|
||||||
LOG_CRITICAL_IF(log_file_exceptions, "Exception EXCEPTION_DATATYPE_MISALIGNMENT ({:#x}). ", ec);
|
LOG_CRITICAL_IF(log_file_exceptions, "DEP violation at address {:#x}.", info[1]);
|
||||||
break;
|
|
||||||
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
|
||||||
LOG_CRITICAL_IF(log_file_exceptions, "Exception EXCEPTION_FLT_DIVIDE_BY_ZERO ({:#x}). ", ec);
|
|
||||||
break;
|
|
||||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
|
||||||
LOG_CRITICAL_IF(log_file_exceptions, "Exception EXCEPTION_ILLEGAL_INSTRUCTION ({:#x}). ", ec);
|
|
||||||
break;
|
|
||||||
case EXCEPTION_IN_PAGE_ERROR:
|
|
||||||
LOG_CRITICAL_IF(log_file_exceptions, "Exception EXCEPTION_IN_PAGE_ERROR ({:#x}). ", ec);
|
|
||||||
break;
|
|
||||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
|
||||||
LOG_CRITICAL_IF(log_file_exceptions, "Exception EXCEPTION_INT_DIVIDE_BY_ZERO ({:#x}). ", ec);
|
|
||||||
break;
|
|
||||||
case EXCEPTION_PRIV_INSTRUCTION:
|
|
||||||
LOG_CRITICAL_IF(log_file_exceptions, "Exception EXCEPTION_PRIV_INSTRUCTION ({:#x}). ", ec);
|
|
||||||
break;
|
|
||||||
case EXCEPTION_STACK_OVERFLOW:
|
|
||||||
LOG_CRITICAL_IF(log_file_exceptions, "Exception EXCEPTION_STACK_OVERFLOW ({:#x}). ", ec);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
||||||
|
LOG_CRITICAL_IF(log_file_exceptions, "Exception EXCEPTION_ARRAY_BOUNDS_EXCEEDED ({:#x}). ",
|
||||||
|
ec);
|
||||||
|
break;
|
||||||
|
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
||||||
|
LOG_CRITICAL_IF(log_file_exceptions, "Exception EXCEPTION_DATATYPE_MISALIGNMENT ({:#x}). ",
|
||||||
|
ec);
|
||||||
|
break;
|
||||||
|
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
||||||
|
LOG_CRITICAL_IF(log_file_exceptions, "Exception EXCEPTION_FLT_DIVIDE_BY_ZERO ({:#x}). ",
|
||||||
|
ec);
|
||||||
|
break;
|
||||||
|
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||||
|
LOG_CRITICAL_IF(log_file_exceptions, "Exception EXCEPTION_ILLEGAL_INSTRUCTION ({:#x}). ",
|
||||||
|
ec);
|
||||||
|
break;
|
||||||
|
case EXCEPTION_IN_PAGE_ERROR:
|
||||||
|
LOG_CRITICAL_IF(log_file_exceptions, "Exception EXCEPTION_IN_PAGE_ERROR ({:#x}). ", ec);
|
||||||
|
break;
|
||||||
|
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||||
|
LOG_CRITICAL_IF(log_file_exceptions, "Exception EXCEPTION_INT_DIVIDE_BY_ZERO ({:#x}). ",
|
||||||
|
ec);
|
||||||
|
break;
|
||||||
|
case EXCEPTION_PRIV_INSTRUCTION:
|
||||||
|
LOG_CRITICAL_IF(log_file_exceptions, "Exception EXCEPTION_PRIV_INSTRUCTION ({:#x}). ", ec);
|
||||||
|
break;
|
||||||
|
case EXCEPTION_STACK_OVERFLOW:
|
||||||
|
LOG_CRITICAL_IF(log_file_exceptions, "Exception EXCEPTION_STACK_OVERFLOW ({:#x}). ", ec);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
Flush();
|
Flush();
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int Init(bool use_stdout) {
|
int Init(bool use_stdout) {
|
||||||
sinks.clear();
|
sinks.clear();
|
||||||
if (use_stdout) {
|
if (use_stdout) {
|
||||||
|
@ -114,8 +119,10 @@ int Init(bool use_stdout) {
|
||||||
#else
|
#else
|
||||||
sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>("shadps4.txt", true));
|
sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>("shadps4.txt", true));
|
||||||
#endif
|
#endif
|
||||||
spdlog::set_default_logger(std::make_shared<spdlog::logger>("shadps4 logger", begin(sinks), end(sinks)));
|
spdlog::set_default_logger(
|
||||||
auto f = std::make_unique<spdlog::pattern_formatter>("%^|%L|: %v%$", spdlog::pattern_time_type::local, std::string("")); // disable eol
|
std::make_shared<spdlog::logger>("shadps4 logger", begin(sinks), end(sinks)));
|
||||||
|
auto f = std::make_unique<spdlog::pattern_formatter>(
|
||||||
|
"%^|%L|: %v%$", spdlog::pattern_time_type::local, std::string("")); // disable eol
|
||||||
spdlog::set_formatter(std::move(f));
|
spdlog::set_formatter(std::move(f));
|
||||||
spdlog::set_level(static_cast<spdlog::level::level_enum>(Config::getLogLevel()));
|
spdlog::set_level(static_cast<spdlog::level::level_enum>(Config::getLogLevel()));
|
||||||
|
|
||||||
|
@ -129,13 +136,14 @@ int Init(bool use_stdout) {
|
||||||
old_terminate = std::set_terminate([]() {
|
old_terminate = std::set_terminate([]() {
|
||||||
try {
|
try {
|
||||||
std::rethrow_exception(std::current_exception());
|
std::rethrow_exception(std::current_exception());
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception& e) {
|
||||||
LOG_CRITICAL_IF(log_file_exceptions, "Unhandled C++ exception. {}", e.what());
|
LOG_CRITICAL_IF(log_file_exceptions, "Unhandled C++ exception. {}", e.what());
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
LOG_CRITICAL_IF(log_file_exceptions, "Unhandled C++ exception. UNKNOWN");
|
LOG_CRITICAL_IF(log_file_exceptions, "Unhandled C++ exception. UNKNOWN");
|
||||||
}
|
}
|
||||||
Flush();
|
Flush();
|
||||||
if (old_terminate) old_terminate();
|
if (old_terminate)
|
||||||
|
old_terminate();
|
||||||
});
|
});
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -145,4 +153,4 @@ void SetLevel(spdlog::level::level_enum log_level) {
|
||||||
spdlog::set_level(log_level);
|
spdlog::set_level(log_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Common::Log
|
} // namespace Common::Log
|
||||||
|
|
|
@ -13,18 +13,24 @@ namespace Common::Log {
|
||||||
#define LOG_ERROR SPDLOG_ERROR
|
#define LOG_ERROR SPDLOG_ERROR
|
||||||
#define LOG_CRITICAL SPDLOG_CRITICAL
|
#define LOG_CRITICAL SPDLOG_CRITICAL
|
||||||
|
|
||||||
#define LOG_TRACE_IF(flag, ...) \
|
#define LOG_TRACE_IF(flag, ...) \
|
||||||
if (flag) LOG_TRACE(__VA_ARGS__)
|
if (flag) \
|
||||||
#define LOG_DEBUG_IF(flag, ...) \
|
LOG_TRACE(__VA_ARGS__)
|
||||||
if (flag) LOG_DEBUG(__VA_ARGS__)
|
#define LOG_DEBUG_IF(flag, ...) \
|
||||||
#define LOG_INFO_IF(flag, ...) \
|
if (flag) \
|
||||||
if (flag) LOG_INFO(__VA_ARGS__)
|
LOG_DEBUG(__VA_ARGS__)
|
||||||
#define LOG_WARN_IF(flag, ...) \
|
#define LOG_INFO_IF(flag, ...) \
|
||||||
if (flag) LOG_WARN(__VA_ARGS__)
|
if (flag) \
|
||||||
#define LOG_ERROR_IF(flag, ...) \
|
LOG_INFO(__VA_ARGS__)
|
||||||
if (flag) LOG_ERROR(__VA_ARGS__)
|
#define LOG_WARN_IF(flag, ...) \
|
||||||
#define LOG_CRITICAL_IF(flag, ...) \
|
if (flag) \
|
||||||
if (flag) LOG_CRITICAL(__VA_ARGS__)
|
LOG_WARN(__VA_ARGS__)
|
||||||
|
#define LOG_ERROR_IF(flag, ...) \
|
||||||
|
if (flag) \
|
||||||
|
LOG_ERROR(__VA_ARGS__)
|
||||||
|
#define LOG_CRITICAL_IF(flag, ...) \
|
||||||
|
if (flag) \
|
||||||
|
LOG_CRITICAL(__VA_ARGS__)
|
||||||
|
|
||||||
int Init(bool use_stdout);
|
int Init(bool use_stdout);
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "common/uint128.h"
|
|
||||||
#include "common/native_clock.h"
|
#include "common/native_clock.h"
|
||||||
#include "common/rdtsc.h"
|
#include "common/rdtsc.h"
|
||||||
|
#include "common/uint128.h"
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
#include <pthread_time.h>
|
#include <pthread_time.h>
|
||||||
#else
|
#else
|
||||||
|
@ -13,8 +13,8 @@
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
NativeClock::NativeClock()
|
NativeClock::NativeClock()
|
||||||
: rdtsc_frequency{EstimateRDTSCFrequency()}, ns_rdtsc_factor{GetFixedPoint64Factor(std::nano::den,
|
: rdtsc_frequency{EstimateRDTSCFrequency()}, ns_rdtsc_factor{GetFixedPoint64Factor(
|
||||||
rdtsc_frequency)},
|
std::nano::den, rdtsc_frequency)},
|
||||||
us_rdtsc_factor{GetFixedPoint64Factor(std::micro::den, rdtsc_frequency)},
|
us_rdtsc_factor{GetFixedPoint64Factor(std::micro::den, rdtsc_frequency)},
|
||||||
ms_rdtsc_factor{GetFixedPoint64Factor(std::milli::den, rdtsc_frequency)} {}
|
ms_rdtsc_factor{GetFixedPoint64Factor(std::milli::den, rdtsc_frequency)} {}
|
||||||
|
|
||||||
|
@ -40,4 +40,4 @@ u64 NativeClock::GetProcessTimeUS() const {
|
||||||
return ret.tv_nsec / 1000 + ret.tv_sec * 1000000;
|
return ret.tv_nsec / 1000 + ret.tv_sec * 1000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Common::X64
|
} // namespace Common
|
||||||
|
|
|
@ -28,7 +28,7 @@ static u64 GetTimeNs() {
|
||||||
FILETIME filetime;
|
FILETIME filetime;
|
||||||
GetSystemTimePreciseAsFileTime(&filetime);
|
GetSystemTimePreciseAsFileTime(&filetime);
|
||||||
return Multiplier * ((static_cast<u64>(filetime.dwHighDateTime) << 32) +
|
return Multiplier * ((static_cast<u64>(filetime.dwHighDateTime) << 32) +
|
||||||
static_cast<u64>(filetime.dwLowDateTime) - WindowsEpochToUnixEpoch);
|
static_cast<u64>(filetime.dwLowDateTime) - WindowsEpochToUnixEpoch);
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
return clock_gettime_nsec_np(CLOCK_REALTIME);
|
return clock_gettime_nsec_np(CLOCK_REALTIME);
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
std::vector<std::string> SplitString(const std::string &str, char delimiter) {
|
std::vector<std::string> SplitString(const std::string& str, char delimiter) {
|
||||||
std::istringstream iss(str);
|
std::istringstream iss(str);
|
||||||
std::vector<std::string> output(1);
|
std::vector<std::string> output(1);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,12 @@ static_assert(sizeof(u128) == 16, "u128 must be 128 bits wide");
|
||||||
#define PS4_SYSV_ABI __attribute__((sysv_abi))
|
#define PS4_SYSV_ABI __attribute__((sysv_abi))
|
||||||
|
|
||||||
// UDLs for memory size values
|
// UDLs for memory size values
|
||||||
constexpr unsigned long long operator""_KB(unsigned long long x) { return 1024ULL * x; }
|
constexpr unsigned long long operator""_KB(unsigned long long x) {
|
||||||
constexpr unsigned long long operator""_MB(unsigned long long x) { return 1024_KB * x; }
|
return 1024ULL * x;
|
||||||
constexpr unsigned long long operator""_GB(unsigned long long x) { return 1024_MB * x; }
|
}
|
||||||
|
constexpr unsigned long long operator""_MB(unsigned long long x) {
|
||||||
|
return 1024_KB * x;
|
||||||
|
}
|
||||||
|
constexpr unsigned long long operator""_GB(unsigned long long x) {
|
||||||
|
return 1024_MB * x;
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
#include "gpu_memory.h"
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <xxh3.h>
|
#include <xxh3.h>
|
||||||
|
#include "gpu_memory.h"
|
||||||
|
|
||||||
#include "common/singleton.h"
|
#include "common/singleton.h"
|
||||||
|
|
||||||
void* GPU::memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, void* todo /*CommandBuffer?*/, u64 virtual_addr, u64 size,
|
void* GPU::memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
|
void* todo /*CommandBuffer?*/, u64 virtual_addr, u64 size,
|
||||||
const GPUObject& info) {
|
const GPUObject& info) {
|
||||||
auto* gpumemory = Common::Singleton<GPUMemory>::Instance();
|
auto* gpumemory = Common::Singleton<GPUMemory>::Instance();
|
||||||
|
|
||||||
|
@ -23,9 +24,12 @@ void GPU::memorySetAllocArea(u64 virtual_addr, u64 size) {
|
||||||
gpumemory->m_heaps.push_back(h);
|
gpumemory->m_heaps.push_back(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 GPU::calculate_hash(const u08* buf, u64 size) { return (size > 0 && buf != nullptr ? XXH3_64bits(buf, size) : 0); }
|
u64 GPU::calculate_hash(const u08* buf, u64 size) {
|
||||||
|
return (size > 0 && buf != nullptr ? XXH3_64bits(buf, size) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
bool GPU::vulkanAllocateMemory(HLE::Libs::Graphics::GraphicCtx* ctx, HLE::Libs::Graphics::VulkanMemory* mem) {
|
bool GPU::vulkanAllocateMemory(HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
|
HLE::Libs::Graphics::VulkanMemory* mem) {
|
||||||
static std::atomic_uint64_t unique_id = 0;
|
static std::atomic_uint64_t unique_id = 0;
|
||||||
|
|
||||||
VkPhysicalDeviceMemoryProperties memory_properties{};
|
VkPhysicalDeviceMemoryProperties memory_properties{};
|
||||||
|
@ -66,7 +70,8 @@ void GPU::flushGarlic(HLE::Libs::Graphics::GraphicCtx* ctx) {
|
||||||
int GPU::GPUMemory::getHeapId(u64 virtual_addr, u64 size) {
|
int GPU::GPUMemory::getHeapId(u64 virtual_addr, u64 size) {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (const auto& heap : m_heaps) {
|
for (const auto& heap : m_heaps) {
|
||||||
if ((virtual_addr >= heap.allocated_virtual_addr && virtual_addr < heap.allocated_virtual_addr + heap.allocated_size) ||
|
if ((virtual_addr >= heap.allocated_virtual_addr &&
|
||||||
|
virtual_addr < heap.allocated_virtual_addr + heap.allocated_size) ||
|
||||||
((virtual_addr + size - 1) >= heap.allocated_virtual_addr &&
|
((virtual_addr + size - 1) >= heap.allocated_virtual_addr &&
|
||||||
(virtual_addr + size - 1) < heap.allocated_virtual_addr + heap.allocated_size)) {
|
(virtual_addr + size - 1) < heap.allocated_virtual_addr + heap.allocated_size)) {
|
||||||
return index;
|
return index;
|
||||||
|
@ -76,7 +81,8 @@ int GPU::GPUMemory::getHeapId(u64 virtual_addr, u64 size) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* GPU::GPUMemory::memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, void* todo, const u64* virtual_addr, const u64* size,
|
void* GPU::GPUMemory::memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
|
void* todo, const u64* virtual_addr, const u64* size,
|
||||||
int virtual_addr_num, const GPUObject& info) {
|
int virtual_addr_num, const GPUObject& info) {
|
||||||
auto* gpumemory = Common::Singleton<GPUMemory>::Instance();
|
auto* gpumemory = Common::Singleton<GPUMemory>::Instance();
|
||||||
|
|
||||||
|
@ -101,7 +107,8 @@ void* GPU::GPUMemory::memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::Graphi
|
||||||
|
|
||||||
for (int h = 0; h < virtual_addr_num; h++) {
|
for (int h = 0; h < virtual_addr_num; h++) {
|
||||||
if (info.check_hash) {
|
if (info.check_hash) {
|
||||||
objInfo.hash[h] = GPU::calculate_hash(reinterpret_cast<const u08*>(virtual_addr[h]), size[h]);
|
objInfo.hash[h] =
|
||||||
|
GPU::calculate_hash(reinterpret_cast<const u08*>(virtual_addr[h]), size[h]);
|
||||||
} else {
|
} else {
|
||||||
objInfo.hash[h] = 0;
|
objInfo.hash[h] = 0;
|
||||||
}
|
}
|
||||||
|
@ -109,7 +116,8 @@ void* GPU::GPUMemory::memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::Graphi
|
||||||
objInfo.submit_id = submit_id;
|
objInfo.submit_id = submit_id;
|
||||||
objInfo.check_hash = info.check_hash;
|
objInfo.check_hash = info.check_hash;
|
||||||
|
|
||||||
objInfo.gpu_object.obj = info.getCreateFunc()(ctx, objInfo.obj_params, virtual_addr, size, virtual_addr_num, &objInfo.mem);
|
objInfo.gpu_object.obj = info.getCreateFunc()(ctx, objInfo.obj_params, virtual_addr, size,
|
||||||
|
virtual_addr_num, &objInfo.mem);
|
||||||
|
|
||||||
objInfo.update_func = info.getUpdateFunc();
|
objInfo.update_func = info.getUpdateFunc();
|
||||||
int index = static_cast<int>(heap.objects.size());
|
int index = static_cast<int>(heap.objects.size());
|
||||||
|
@ -123,7 +131,8 @@ void* GPU::GPUMemory::memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::Graphi
|
||||||
return objInfo.gpu_object.obj;
|
return objInfo.gpu_object.obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
GPU::HeapBlock GPU::GPUMemory::createHeapBlock(const u64* virtual_addr, const u64* size, int virtual_addr_num, int heap_id, int obj_id) {
|
GPU::HeapBlock GPU::GPUMemory::createHeapBlock(const u64* virtual_addr, const u64* size,
|
||||||
|
int virtual_addr_num, int heap_id, int obj_id) {
|
||||||
auto& heap = m_heaps[heap_id];
|
auto& heap = m_heaps[heap_id];
|
||||||
|
|
||||||
GPU::HeapBlock heapBlock{};
|
GPU::HeapBlock heapBlock{};
|
||||||
|
@ -135,7 +144,8 @@ GPU::HeapBlock GPU::GPUMemory::createHeapBlock(const u64* virtual_addr, const u6
|
||||||
return heapBlock;
|
return heapBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU::GPUMemory::update(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, int heap_id, int obj_id) {
|
void GPU::GPUMemory::update(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, int heap_id,
|
||||||
|
int obj_id) {
|
||||||
auto& heap = m_heaps[heap_id];
|
auto& heap = m_heaps[heap_id];
|
||||||
|
|
||||||
auto& heapObj = heap.objects[obj_id];
|
auto& heapObj = heap.objects[obj_id];
|
||||||
|
@ -147,7 +157,9 @@ void GPU::GPUMemory::update(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
|
|
||||||
for (int i = 0; i < heapObj.block.virtual_addr_num; i++) {
|
for (int i = 0; i < heapObj.block.virtual_addr_num; i++) {
|
||||||
if (objInfo.check_hash) {
|
if (objInfo.check_hash) {
|
||||||
hash[i] = GPU::calculate_hash(reinterpret_cast<const uint8_t*>(heapObj.block.virtual_addr[i]), heapObj.block.size[i]);
|
hash[i] = GPU::calculate_hash(
|
||||||
|
reinterpret_cast<const uint8_t*>(heapObj.block.virtual_addr[i]),
|
||||||
|
heapObj.block.size[i]);
|
||||||
} else {
|
} else {
|
||||||
hash[i] = 0;
|
hash[i] = 0;
|
||||||
}
|
}
|
||||||
|
@ -166,7 +178,8 @@ void GPU::GPUMemory::update(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (need_update) {
|
if (need_update) {
|
||||||
objInfo.update_func(ctx, objInfo.obj_params, objInfo.gpu_object.obj, heapObj.block.virtual_addr, heapObj.block.size,
|
objInfo.update_func(ctx, objInfo.obj_params, objInfo.gpu_object.obj,
|
||||||
|
heapObj.block.virtual_addr, heapObj.block.size,
|
||||||
heapObj.block.virtual_addr_num);
|
heapObj.block.virtual_addr_num);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <core/PS4/HLE/Graphics/graphics_ctx.h>
|
|
||||||
#include "common/types.h"
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <core/PS4/HLE/Graphics/graphics_ctx.h>
|
||||||
|
#include "common/types.h"
|
||||||
|
|
||||||
namespace GPU {
|
namespace GPU {
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ struct HeapBlock {
|
||||||
};
|
};
|
||||||
|
|
||||||
class GPUObject {
|
class GPUObject {
|
||||||
public:
|
public:
|
||||||
GPUObject() = default;
|
GPUObject() = default;
|
||||||
virtual ~GPUObject() = default;
|
virtual ~GPUObject() = default;
|
||||||
u64 obj_params[8] = {};
|
u64 obj_params[8] = {};
|
||||||
|
@ -32,9 +32,11 @@ class GPUObject {
|
||||||
bool isReadOnly = false;
|
bool isReadOnly = false;
|
||||||
MemoryObjectType objectType = MemoryObjectType::InvalidObj;
|
MemoryObjectType objectType = MemoryObjectType::InvalidObj;
|
||||||
|
|
||||||
using create_func_t = void* (*)(HLE::Libs::Graphics::GraphicCtx* ctx, const u64* params, const u64* virtual_addr, const u64* size, int virtual_addr_num,
|
using create_func_t = void* (*)(HLE::Libs::Graphics::GraphicCtx* ctx, const u64* params,
|
||||||
|
const u64* virtual_addr, const u64* size, int virtual_addr_num,
|
||||||
HLE::Libs::Graphics::VulkanMemory* mem);
|
HLE::Libs::Graphics::VulkanMemory* mem);
|
||||||
using update_func_t = void (*)(HLE::Libs::Graphics::GraphicCtx* ctx, const u64* params, void* obj, const u64* virtual_addr, const u64* size,
|
using update_func_t = void (*)(HLE::Libs::Graphics::GraphicCtx* ctx, const u64* params,
|
||||||
|
void* obj, const u64* virtual_addr, const u64* size,
|
||||||
int virtual_addr_num);
|
int virtual_addr_num);
|
||||||
|
|
||||||
virtual create_func_t getCreateFunc() const = 0;
|
virtual create_func_t getCreateFunc() const = 0;
|
||||||
|
@ -63,23 +65,27 @@ struct MemoryHeap {
|
||||||
};
|
};
|
||||||
|
|
||||||
class GPUMemory {
|
class GPUMemory {
|
||||||
public:
|
public:
|
||||||
GPUMemory() {}
|
GPUMemory() {}
|
||||||
virtual ~GPUMemory() {}
|
virtual ~GPUMemory() {}
|
||||||
int getHeapId(u64 vaddr, u64 size);
|
int getHeapId(u64 vaddr, u64 size);
|
||||||
std::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
std::vector<MemoryHeap> m_heaps;
|
std::vector<MemoryHeap> m_heaps;
|
||||||
void* memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, /*CommandBuffer* buffer*/ void* todo, const u64* virtual_addr,
|
void* memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
|
/*CommandBuffer* buffer*/ void* todo, const u64* virtual_addr,
|
||||||
const u64* size, int virtual_addr_num, const GPUObject& info);
|
const u64* size, int virtual_addr_num, const GPUObject& info);
|
||||||
HeapBlock createHeapBlock(const u64* virtual_addr, const u64* size, int virtual_addr_num, int heap_id, int obj_id);
|
HeapBlock createHeapBlock(const u64* virtual_addr, const u64* size, int virtual_addr_num,
|
||||||
|
int heap_id, int obj_id);
|
||||||
void update(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, int heap_id, int obj_id);
|
void update(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, int heap_id, int obj_id);
|
||||||
void flushAllHeaps(HLE::Libs::Graphics::GraphicCtx* ctx);
|
void flushAllHeaps(HLE::Libs::Graphics::GraphicCtx* ctx);
|
||||||
};
|
};
|
||||||
|
|
||||||
void memorySetAllocArea(u64 virtual_addr, u64 size);
|
void memorySetAllocArea(u64 virtual_addr, u64 size);
|
||||||
void* memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, /*CommandBuffer* buffer*/ void* todo, u64 virtual_addr, u64 size,
|
void* memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
|
/*CommandBuffer* buffer*/ void* todo, u64 virtual_addr, u64 size,
|
||||||
const GPUObject& info);
|
const GPUObject& info);
|
||||||
u64 calculate_hash(const u08* buf, u64 size);
|
u64 calculate_hash(const u08* buf, u64 size);
|
||||||
bool vulkanAllocateMemory(HLE::Libs::Graphics::GraphicCtx* ctx, HLE::Libs::Graphics::VulkanMemory* mem);
|
bool vulkanAllocateMemory(HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
|
HLE::Libs::Graphics::VulkanMemory* mem);
|
||||||
void flushGarlic(HLE::Libs::Graphics::GraphicCtx* ctx);
|
void flushGarlic(HLE::Libs::Graphics::GraphicCtx* ctx);
|
||||||
} // namespace GPU
|
} // namespace GPU
|
|
@ -1,20 +1,22 @@
|
||||||
#include "tile_manager.h"
|
|
||||||
#include "common/singleton.h"
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include "common/singleton.h"
|
||||||
|
#include "tile_manager.h"
|
||||||
|
|
||||||
namespace GPU {
|
namespace GPU {
|
||||||
|
|
||||||
static u32 IntLog2(u32 i) { return 31 - __builtin_clz(i | 1u); }
|
static u32 IntLog2(u32 i) {
|
||||||
|
return 31 - __builtin_clz(i | 1u);
|
||||||
|
}
|
||||||
|
|
||||||
class TileManager {
|
class TileManager {
|
||||||
public:
|
public:
|
||||||
TileManager(){}
|
TileManager() {}
|
||||||
virtual ~TileManager() { }
|
virtual ~TileManager() {}
|
||||||
std::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TileManager32 {
|
class TileManager32 {
|
||||||
public:
|
public:
|
||||||
u32 m_macro_tile_height = 0;
|
u32 m_macro_tile_height = 0;
|
||||||
u32 m_bank_height = 0;
|
u32 m_bank_height = 0;
|
||||||
u32 m_num_banks = 0;
|
u32 m_num_banks = 0;
|
||||||
|
@ -69,25 +71,26 @@ class TileManager32 {
|
||||||
return pipe;
|
return pipe;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 getBankIdx(u32 x, u32 y, u32 bank_width, u32 bank_height, u32 num_banks, u32 num_pipes) {
|
static u32 getBankIdx(u32 x, u32 y, u32 bank_width, u32 bank_height, u32 num_banks,
|
||||||
|
u32 num_pipes) {
|
||||||
const u32 x_shift_offset = IntLog2(bank_width * num_pipes);
|
const u32 x_shift_offset = IntLog2(bank_width * num_pipes);
|
||||||
const u32 y_shift_offset = IntLog2(bank_height);
|
const u32 y_shift_offset = IntLog2(bank_height);
|
||||||
const u32 xs = x >> x_shift_offset;
|
const u32 xs = x >> x_shift_offset;
|
||||||
const u32 ys = y >> y_shift_offset;
|
const u32 ys = y >> y_shift_offset;
|
||||||
u32 bank = 0;
|
u32 bank = 0;
|
||||||
switch (num_banks) {
|
switch (num_banks) {
|
||||||
case 8:
|
case 8:
|
||||||
bank |= (((xs >> 3u) ^ (ys >> 5u)) & 0x1u) << 0u;
|
bank |= (((xs >> 3u) ^ (ys >> 5u)) & 0x1u) << 0u;
|
||||||
bank |= (((xs >> 4u) ^ (ys >> 4u) ^ (ys >> 5u)) & 0x1u) << 1u;
|
bank |= (((xs >> 4u) ^ (ys >> 4u) ^ (ys >> 5u)) & 0x1u) << 1u;
|
||||||
bank |= (((xs >> 5u) ^ (ys >> 3u)) & 0x1u) << 2u;
|
bank |= (((xs >> 5u) ^ (ys >> 3u)) & 0x1u) << 2u;
|
||||||
break;
|
break;
|
||||||
case 16:
|
case 16:
|
||||||
bank |= (((xs >> 3u) ^ (ys >> 6u)) & 0x1u) << 0u;
|
bank |= (((xs >> 3u) ^ (ys >> 6u)) & 0x1u) << 0u;
|
||||||
bank |= (((xs >> 4u) ^ (ys >> 5u) ^ (ys >> 6u)) & 0x1u) << 1u;
|
bank |= (((xs >> 4u) ^ (ys >> 5u) ^ (ys >> 6u)) & 0x1u) << 1u;
|
||||||
bank |= (((xs >> 5u) ^ (ys >> 4u)) & 0x1u) << 2u;
|
bank |= (((xs >> 5u) ^ (ys >> 4u)) & 0x1u) << 2u;
|
||||||
bank |= (((xs >> 6u) ^ (ys >> 3u)) & 0x1u) << 3u;
|
bank |= (((xs >> 6u) ^ (ys >> 3u)) & 0x1u) << 3u;
|
||||||
break;
|
break;
|
||||||
default:;
|
default:;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bank;
|
return bank;
|
||||||
|
@ -110,11 +113,13 @@ class TileManager32 {
|
||||||
tile_bytes = 512;
|
tile_bytes = 512;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 macro_tile_bytes = (128 / 8) * (m_macro_tile_height / 8) * tile_bytes / (m_num_pipes * m_num_banks);
|
u64 macro_tile_bytes =
|
||||||
|
(128 / 8) * (m_macro_tile_height / 8) * tile_bytes / (m_num_pipes * m_num_banks);
|
||||||
u64 macro_tiles_per_row = m_padded_width / 128;
|
u64 macro_tiles_per_row = m_padded_width / 128;
|
||||||
u64 macro_tile_row_index = y / m_macro_tile_height;
|
u64 macro_tile_row_index = y / m_macro_tile_height;
|
||||||
u64 macro_tile_column_index = x / 128;
|
u64 macro_tile_column_index = x / 128;
|
||||||
u64 macro_tile_index = (macro_tile_row_index * macro_tiles_per_row) + macro_tile_column_index;
|
u64 macro_tile_index =
|
||||||
|
(macro_tile_row_index * macro_tiles_per_row) + macro_tile_column_index;
|
||||||
u64 macro_tile_offset = macro_tile_index * macro_tile_bytes;
|
u64 macro_tile_offset = macro_tile_index * macro_tile_bytes;
|
||||||
u64 macro_tiles_per_slice = macro_tiles_per_row * (m_padded_height / m_macro_tile_height);
|
u64 macro_tiles_per_slice = macro_tiles_per_row * (m_padded_height / m_macro_tile_height);
|
||||||
u64 slice_bytes = macro_tiles_per_slice * macro_tile_bytes;
|
u64 slice_bytes = macro_tiles_per_slice * macro_tile_bytes;
|
||||||
|
@ -133,13 +138,14 @@ class TileManager32 {
|
||||||
|
|
||||||
u64 pipe_interleave_offset = total_offset & 0xffu;
|
u64 pipe_interleave_offset = total_offset & 0xffu;
|
||||||
u64 offset = total_offset >> 8u;
|
u64 offset = total_offset >> 8u;
|
||||||
u64 byte_offset = pipe_interleave_offset | (pipe << (8u)) | (bank << (8u + m_pipe_bits)) | (offset << (8u + m_pipe_bits + m_bank_bits));
|
u64 byte_offset = pipe_interleave_offset | (pipe << (8u)) | (bank << (8u + m_pipe_bits)) |
|
||||||
|
(offset << (8u + m_pipe_bits + m_bank_bits));
|
||||||
|
|
||||||
return ((byte_offset << 3u) | bit_offset) / 8;
|
return ((byte_offset << 3u) | bit_offset) / 8;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void convertTileToLinear(void* dst, const void* src,u32 width, u32 height, bool is_neo) {
|
void convertTileToLinear(void* dst, const void* src, u32 width, u32 height, bool is_neo) {
|
||||||
TileManager32 t;
|
TileManager32 t;
|
||||||
t.Init(width, height, is_neo);
|
t.Init(width, height, is_neo);
|
||||||
|
|
||||||
|
@ -166,4 +172,4 @@ void convertTileToLinear(void* dst, const void* src,u32 width, u32 height, bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace GPU
|
} // namespace GPU
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
|
|
||||||
#include "common/debug.h"
|
|
||||||
#include <vulkan_util.h>
|
#include <vulkan_util.h>
|
||||||
|
#include "common/debug.h"
|
||||||
#include "tile_manager.h"
|
#include "tile_manager.h"
|
||||||
|
|
||||||
constexpr bool log_file_videoOutBuffer = true; // disable it to disable logging
|
constexpr bool log_file_videoOutBuffer = true; // disable it to disable logging
|
||||||
|
|
||||||
static void update_func(HLE::Libs::Graphics::GraphicCtx* ctx, const u64* params, void* obj, const u64* virtual_addr, const u64* size,
|
static void update_func(HLE::Libs::Graphics::GraphicCtx* ctx, const u64* params, void* obj,
|
||||||
int virtual_addr_num) {
|
const u64* virtual_addr, const u64* size, int virtual_addr_num) {
|
||||||
|
|
||||||
auto pitch = params[GPU::VideoOutBufferObj::PITCH_PARAM];
|
auto pitch = params[GPU::VideoOutBufferObj::PITCH_PARAM];
|
||||||
bool tiled = (params[GPU::VideoOutBufferObj::IS_TILE_PARAM] != 0);
|
bool tiled = (params[GPU::VideoOutBufferObj::IS_TILE_PARAM] != 0);
|
||||||
|
@ -21,19 +21,22 @@ static void update_func(HLE::Libs::Graphics::GraphicCtx* ctx, const u64* params,
|
||||||
|
|
||||||
vk_obj->layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
vk_obj->layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
|
||||||
if (tiled)
|
if (tiled) {
|
||||||
{
|
|
||||||
std::vector<u08> tempbuff(*size);
|
std::vector<u08> tempbuff(*size);
|
||||||
GPU::convertTileToLinear(tempbuff.data(), reinterpret_cast<void*>(*virtual_addr), width, height, neo);
|
GPU::convertTileToLinear(tempbuff.data(), reinterpret_cast<void*>(*virtual_addr), width,
|
||||||
Graphics::Vulkan::vulkanFillImage(ctx, vk_obj, tempbuff.data(), *size, pitch, static_cast<u64>(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
|
height, neo);
|
||||||
|
Graphics::Vulkan::vulkanFillImage(
|
||||||
|
ctx, vk_obj, tempbuff.data(), *size, pitch,
|
||||||
|
static_cast<u64>(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
|
||||||
} else {
|
} else {
|
||||||
Graphics::Vulkan::vulkanFillImage(ctx, vk_obj, reinterpret_cast<void*>(*virtual_addr), *size, pitch,
|
Graphics::Vulkan::vulkanFillImage(
|
||||||
static_cast<u64>(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
|
ctx, vk_obj, reinterpret_cast<void*>(*virtual_addr), *size, pitch,
|
||||||
|
static_cast<u64>(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* create_func(HLE::Libs::Graphics::GraphicCtx* ctx, const u64* params, const u64* virtual_addr, const u64* size, int virtual_addr_num,
|
static void* create_func(HLE::Libs::Graphics::GraphicCtx* ctx, const u64* params,
|
||||||
|
const u64* virtual_addr, const u64* size, int virtual_addr_num,
|
||||||
HLE::Libs::Graphics::VulkanMemory* mem) {
|
HLE::Libs::Graphics::VulkanMemory* mem) {
|
||||||
auto pixel_format = params[GPU::VideoOutBufferObj::PIXEL_FORMAT_PARAM];
|
auto pixel_format = params[GPU::VideoOutBufferObj::PIXEL_FORMAT_PARAM];
|
||||||
auto width = params[GPU::VideoOutBufferObj::WIDTH_PARAM];
|
auto width = params[GPU::VideoOutBufferObj::WIDTH_PARAM];
|
||||||
|
@ -44,9 +47,15 @@ static void* create_func(HLE::Libs::Graphics::GraphicCtx* ctx, const u64* params
|
||||||
VkFormat vk_format = VK_FORMAT_UNDEFINED;
|
VkFormat vk_format = VK_FORMAT_UNDEFINED;
|
||||||
|
|
||||||
switch (pixel_format) {
|
switch (pixel_format) {
|
||||||
case static_cast<uint64_t>(GPU::VideoOutBufferFormat::R8G8B8A8Srgb): vk_format = VK_FORMAT_R8G8B8A8_SRGB; break;
|
case static_cast<uint64_t>(GPU::VideoOutBufferFormat::R8G8B8A8Srgb):
|
||||||
case static_cast<uint64_t>(GPU::VideoOutBufferFormat::B8G8R8A8Srgb): vk_format = VK_FORMAT_B8G8R8A8_SRGB; break;
|
vk_format = VK_FORMAT_R8G8B8A8_SRGB;
|
||||||
default: LOG_CRITICAL_IF(log_file_videoOutBuffer, "unknown pixelFormat = {}\n", pixel_format); std::exit(0);
|
break;
|
||||||
|
case static_cast<uint64_t>(GPU::VideoOutBufferFormat::B8G8R8A8Srgb):
|
||||||
|
vk_format = VK_FORMAT_B8G8R8A8_SRGB;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL_IF(log_file_videoOutBuffer, "unknown pixelFormat = {}\n", pixel_format);
|
||||||
|
std::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
vk_obj->extent.width = width;
|
vk_obj->extent.width = width;
|
||||||
|
@ -72,8 +81,9 @@ static void* create_func(HLE::Libs::Graphics::GraphicCtx* ctx, const u64* params
|
||||||
image_info.format = vk_obj->format;
|
image_info.format = vk_obj->format;
|
||||||
image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||||
image_info.initialLayout = vk_obj->layout;
|
image_info.initialLayout = vk_obj->layout;
|
||||||
image_info.usage =
|
image_info.usage = static_cast<VkImageUsageFlags>(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
|
||||||
static_cast<VkImageUsageFlags>(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT) | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
VK_IMAGE_USAGE_TRANSFER_SRC_BIT) |
|
||||||
|
VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||||
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
|
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
|
||||||
|
@ -124,7 +134,8 @@ static void* create_func(HLE::Libs::Graphics::GraphicCtx* ctx, const u64* params
|
||||||
create_info.subresourceRange.layerCount = 1;
|
create_info.subresourceRange.layerCount = 1;
|
||||||
create_info.subresourceRange.levelCount = 1;
|
create_info.subresourceRange.levelCount = 1;
|
||||||
|
|
||||||
vkCreateImageView(ctx->m_device, &create_info, nullptr, &vk_obj->image_view[HLE::Libs::Graphics::VulkanImage::VIEW_DEFAULT]);
|
vkCreateImageView(ctx->m_device, &create_info, nullptr,
|
||||||
|
&vk_obj->image_view[HLE::Libs::Graphics::VulkanImage::VIEW_DEFAULT]);
|
||||||
|
|
||||||
if (vk_obj->image_view[HLE::Libs::Graphics::VulkanImage::VIEW_DEFAULT] == nullptr) {
|
if (vk_obj->image_view[HLE::Libs::Graphics::VulkanImage::VIEW_DEFAULT] == nullptr) {
|
||||||
LOG_CRITICAL_IF(log_file_videoOutBuffer, "vk_obj->image_view is null\n");
|
LOG_CRITICAL_IF(log_file_videoOutBuffer, "vk_obj->image_view is null\n");
|
||||||
|
@ -134,6 +145,10 @@ static void* create_func(HLE::Libs::Graphics::GraphicCtx* ctx, const u64* params
|
||||||
return vk_obj;
|
return vk_obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
GPU::GPUObject::create_func_t GPU::VideoOutBufferObj::getCreateFunc() const { return create_func; }
|
GPU::GPUObject::create_func_t GPU::VideoOutBufferObj::getCreateFunc() const {
|
||||||
|
return create_func;
|
||||||
|
}
|
||||||
|
|
||||||
GPU::GPUObject::update_func_t GPU::VideoOutBufferObj::getUpdateFunc() const { return update_func; }
|
GPU::GPUObject::update_func_t GPU::VideoOutBufferObj::getUpdateFunc() const {
|
||||||
|
return update_func;
|
||||||
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ enum class VideoOutBufferFormat : u64 {
|
||||||
};
|
};
|
||||||
|
|
||||||
class VideoOutBufferObj : public GPUObject {
|
class VideoOutBufferObj : public GPUObject {
|
||||||
public:
|
public:
|
||||||
static constexpr int PIXEL_FORMAT_PARAM = 0;
|
static constexpr int PIXEL_FORMAT_PARAM = 0;
|
||||||
static constexpr int WIDTH_PARAM = 1;
|
static constexpr int WIDTH_PARAM = 1;
|
||||||
static constexpr int HEIGHT_PARAM = 2;
|
static constexpr int HEIGHT_PARAM = 2;
|
||||||
|
@ -21,7 +21,8 @@ class VideoOutBufferObj : public GPUObject {
|
||||||
static constexpr int IS_NEO_PARAM = 4;
|
static constexpr int IS_NEO_PARAM = 4;
|
||||||
static constexpr int PITCH_PARAM = 5;
|
static constexpr int PITCH_PARAM = 5;
|
||||||
|
|
||||||
explicit VideoOutBufferObj(VideoOutBufferFormat pixel_format, u32 width, u32 height, bool is_tiled, bool is_neo, u32 pitch) {
|
explicit VideoOutBufferObj(VideoOutBufferFormat pixel_format, u32 width, u32 height,
|
||||||
|
bool is_tiled, bool is_neo, u32 pitch) {
|
||||||
obj_params[PIXEL_FORMAT_PARAM] = static_cast<uint64_t>(pixel_format);
|
obj_params[PIXEL_FORMAT_PARAM] = static_cast<uint64_t>(pixel_format);
|
||||||
obj_params[WIDTH_PARAM] = width;
|
obj_params[WIDTH_PARAM] = width;
|
||||||
obj_params[HEIGHT_PARAM] = height;
|
obj_params[HEIGHT_PARAM] = height;
|
||||||
|
@ -35,4 +36,4 @@ class VideoOutBufferObj : public GPUObject {
|
||||||
create_func_t getCreateFunc() const override;
|
create_func_t getCreateFunc() const override;
|
||||||
update_func_t getUpdateFunc() const override;
|
update_func_t getUpdateFunc() const override;
|
||||||
};
|
};
|
||||||
} // namespace GPU
|
} // namespace GPU
|
||||||
|
|
|
@ -17,7 +17,7 @@ int VideoOutCtx::Open() {
|
||||||
int handle = -1;
|
int handle = -1;
|
||||||
|
|
||||||
if (!m_video_out_ctx.isOpened) {
|
if (!m_video_out_ctx.isOpened) {
|
||||||
handle = 1; // positive return , should be more than 1 ?
|
handle = 1; // positive return , should be more than 1 ?
|
||||||
}
|
}
|
||||||
|
|
||||||
m_video_out_ctx.isOpened = true;
|
m_video_out_ctx.isOpened = true;
|
||||||
|
@ -35,7 +35,7 @@ void VideoOutCtx::Close(s32 handle) {
|
||||||
m_video_out_ctx.isOpened = false;
|
m_video_out_ctx.isOpened = false;
|
||||||
|
|
||||||
if (m_video_out_ctx.m_flip_evtEq.size() > 0) {
|
if (m_video_out_ctx.m_flip_evtEq.size() > 0) {
|
||||||
BREAKPOINT(); // we need to clear all events if they have been created
|
BREAKPOINT(); // we need to clear all events if they have been created
|
||||||
}
|
}
|
||||||
|
|
||||||
m_video_out_ctx.m_flip_rate = 0;
|
m_video_out_ctx.m_flip_rate = 0;
|
||||||
|
@ -57,7 +57,7 @@ VideoConfigInternal* VideoOutCtx::getCtx(int handle) {
|
||||||
if (handle != 1) [[unlikely]] {
|
if (handle != 1) [[unlikely]] {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return &m_video_out_ctx; // assuming that it's the only ctx TODO check if we need more
|
return &m_video_out_ctx; // assuming that it's the only ctx TODO check if we need more
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlipQueue::getFlipStatus(VideoConfigInternal* cfg, SceVideoOutFlipStatus* out) {
|
void FlipQueue::getFlipStatus(VideoConfigInternal* cfg, SceVideoOutFlipStatus* out) {
|
||||||
|
@ -91,11 +91,12 @@ bool FlipQueue::submitFlip(VideoConfigInternal* cfg, s32 index, s64 flip_arg) {
|
||||||
bool FlipQueue::flip(u32 micros) {
|
bool FlipQueue::flip(u32 micros) {
|
||||||
const auto request = [&]() -> Request* {
|
const auto request = [&]() -> Request* {
|
||||||
std::unique_lock lock{m_mutex};
|
std::unique_lock lock{m_mutex};
|
||||||
m_submit_cond.wait_for(lock, std::chrono::microseconds(micros), [&] { return !m_requests.empty(); });
|
m_submit_cond.wait_for(lock, std::chrono::microseconds(micros),
|
||||||
|
[&] { return !m_requests.empty(); });
|
||||||
if (m_requests.empty()) {
|
if (m_requests.empty()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return &m_requests.at(0); // Process first request
|
return &m_requests.at(0); // Process first request
|
||||||
}();
|
}();
|
||||||
|
|
||||||
if (!request) {
|
if (!request) {
|
||||||
|
@ -111,7 +112,8 @@ bool FlipQueue::flip(u32 micros) {
|
||||||
std::scoped_lock cfg_lock{request->cfg->m_mutex};
|
std::scoped_lock cfg_lock{request->cfg->m_mutex};
|
||||||
for (auto& flip_eq : request->cfg->m_flip_evtEq) {
|
for (auto& flip_eq : request->cfg->m_flip_evtEq) {
|
||||||
if (flip_eq != nullptr) {
|
if (flip_eq != nullptr) {
|
||||||
flip_eq->triggerEvent(SCE_VIDEO_OUT_EVENT_FLIP, Core::Kernel::EVFILT_VIDEO_OUT, reinterpret_cast<void*>(request->flip_arg));
|
flip_eq->triggerEvent(SCE_VIDEO_OUT_EVENT_FLIP, Core::Kernel::EVFILT_VIDEO_OUT,
|
||||||
|
reinterpret_cast<void*>(request->flip_arg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <core/PS4/HLE/Graphics/video_out.h>
|
|
||||||
#include <core/PS4/HLE/Graphics/graphics_ctx.h>
|
#include <core/PS4/HLE/Graphics/graphics_ctx.h>
|
||||||
|
#include <core/PS4/HLE/Graphics/video_out.h>
|
||||||
#include <emulator.h>
|
#include <emulator.h>
|
||||||
|
|
||||||
using namespace HLE::Libs::Graphics::VideoOut;
|
using namespace HLE::Libs::Graphics::VideoOut;
|
||||||
|
@ -32,14 +32,15 @@ struct VideoConfigInternal {
|
||||||
};
|
};
|
||||||
|
|
||||||
class FlipQueue {
|
class FlipQueue {
|
||||||
public:
|
public:
|
||||||
FlipQueue() {}
|
FlipQueue() {}
|
||||||
virtual ~FlipQueue() {}
|
virtual ~FlipQueue() {}
|
||||||
|
|
||||||
void getFlipStatus(VideoConfigInternal* cfg, SceVideoOutFlipStatus* out);
|
void getFlipStatus(VideoConfigInternal* cfg, SceVideoOutFlipStatus* out);
|
||||||
bool submitFlip(VideoConfigInternal* cfg, s32 index, s64 flip_arg);
|
bool submitFlip(VideoConfigInternal* cfg, s32 index, s64 flip_arg);
|
||||||
bool flip(u32 micros);
|
bool flip(u32 micros);
|
||||||
private:
|
|
||||||
|
private:
|
||||||
struct Request {
|
struct Request {
|
||||||
VideoConfigInternal* cfg;
|
VideoConfigInternal* cfg;
|
||||||
int index;
|
int index;
|
||||||
|
@ -55,14 +56,16 @@ class FlipQueue {
|
||||||
|
|
||||||
class VideoOutCtx {
|
class VideoOutCtx {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VideoOutCtx() {}
|
VideoOutCtx() {}
|
||||||
virtual ~VideoOutCtx() {}
|
virtual ~VideoOutCtx() {}
|
||||||
void Init(u32 width, u32 height);
|
void Init(u32 width, u32 height);
|
||||||
int Open();
|
int Open();
|
||||||
void Close(s32 handle);
|
void Close(s32 handle);
|
||||||
VideoConfigInternal* getCtx(int handle);
|
VideoConfigInternal* getCtx(int handle);
|
||||||
FlipQueue& getFlipQueue() { return m_flip_queue; }
|
FlipQueue& getFlipQueue() {
|
||||||
|
return m_flip_queue;
|
||||||
|
}
|
||||||
HLE::Libs::Graphics::GraphicCtx* getGraphicCtx() {
|
HLE::Libs::Graphics::GraphicCtx* getGraphicCtx() {
|
||||||
std::scoped_lock lock{m_mutex};
|
std::scoped_lock lock{m_mutex};
|
||||||
|
|
||||||
|
@ -72,7 +75,8 @@ class VideoOutCtx {
|
||||||
|
|
||||||
return m_graphic_ctx;
|
return m_graphic_ctx;
|
||||||
}
|
}
|
||||||
private:
|
|
||||||
|
private:
|
||||||
std::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
VideoConfigInternal m_video_out_ctx;
|
VideoConfigInternal m_video_out_ctx;
|
||||||
FlipQueue m_flip_queue;
|
FlipQueue m_flip_queue;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/types.h"
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
#include <mutex>
|
#include "common/types.h"
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace HLE::Libs::Graphics {
|
namespace HLE::Libs::Graphics {
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ struct GraphicCtx {
|
||||||
VkInstance m_instance = nullptr;
|
VkInstance m_instance = nullptr;
|
||||||
VkPhysicalDevice m_physical_device = nullptr;
|
VkPhysicalDevice m_physical_device = nullptr;
|
||||||
VkDevice m_device = nullptr;
|
VkDevice m_device = nullptr;
|
||||||
VulkanQueueInfo queues[11]; // VULKAN_QUEUES_NUM
|
VulkanQueueInfo queues[11]; // VULKAN_QUEUES_NUM
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class VulkanImageType { Unknown, VideoOut };
|
enum class VulkanImageType { Unknown, VideoOut };
|
||||||
|
@ -71,4 +71,4 @@ struct VideoOutVulkanImage : public VulkanImage {
|
||||||
VideoOutVulkanImage() : VulkanImage(VulkanImageType::VideoOut) {}
|
VideoOutVulkanImage() : VulkanImage(VulkanImageType::VideoOut) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace HLE::Libs::Graphics
|
} // namespace HLE::Libs::Graphics
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "graphics_render.h"
|
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include "common/singleton.h"
|
#include "common/singleton.h"
|
||||||
#include "emulator.h"
|
#include "emulator.h"
|
||||||
|
#include "graphics_render.h"
|
||||||
|
|
||||||
static thread_local GPU::CommandPool g_command_pool;
|
static thread_local GPU::CommandPool g_command_pool;
|
||||||
|
|
||||||
|
@ -155,7 +155,8 @@ void GPU::CommandPool::createPool(int id) {
|
||||||
alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
alloc_info.commandBufferCount = m_pool[id].buffers_count;
|
alloc_info.commandBufferCount = m_pool[id].buffers_count;
|
||||||
|
|
||||||
if (vkAllocateCommandBuffers(ctx->m_device, &alloc_info, m_pool[id].buffers.data()) != VK_SUCCESS) {
|
if (vkAllocateCommandBuffers(ctx->m_device, &alloc_info, m_pool[id].buffers.data()) !=
|
||||||
|
VK_SUCCESS) {
|
||||||
fmt::print("Can't allocate command buffers\n");
|
fmt::print("Can't allocate command buffers\n");
|
||||||
std::exit(0);
|
std::exit(0);
|
||||||
}
|
}
|
||||||
|
@ -168,7 +169,8 @@ void GPU::CommandPool::createPool(int id) {
|
||||||
fence_info.pNext = nullptr;
|
fence_info.pNext = nullptr;
|
||||||
fence_info.flags = 0;
|
fence_info.flags = 0;
|
||||||
|
|
||||||
if (vkCreateFence(ctx->m_device, &fence_info, nullptr, &m_pool[id].fences[i]) != VK_SUCCESS) {
|
if (vkCreateFence(ctx->m_device, &fence_info, nullptr, &m_pool[id].fences[i]) !=
|
||||||
|
VK_SUCCESS) {
|
||||||
fmt::print("Can't create fence\n");
|
fmt::print("Can't create fence\n");
|
||||||
std::exit(0);
|
std::exit(0);
|
||||||
}
|
}
|
||||||
|
@ -178,7 +180,8 @@ void GPU::CommandPool::createPool(int id) {
|
||||||
semaphore_info.pNext = nullptr;
|
semaphore_info.pNext = nullptr;
|
||||||
semaphore_info.flags = 0;
|
semaphore_info.flags = 0;
|
||||||
|
|
||||||
if (vkCreateSemaphore(ctx->m_device, &semaphore_info, nullptr, &m_pool[id].semaphores[i]) != VK_SUCCESS) {
|
if (vkCreateSemaphore(ctx->m_device, &semaphore_info, nullptr, &m_pool[id].semaphores[i]) !=
|
||||||
|
VK_SUCCESS) {
|
||||||
fmt::print("Can't create semas\n");
|
fmt::print("Can't create semas\n");
|
||||||
std::exit(0);
|
std::exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
namespace GPU {
|
namespace GPU {
|
||||||
|
|
||||||
class CommandPool {
|
class CommandPool {
|
||||||
public:
|
public:
|
||||||
CommandPool() = default;
|
CommandPool() = default;
|
||||||
~CommandPool() {}
|
~CommandPool() {}
|
||||||
|
|
||||||
|
@ -17,16 +17,20 @@ class CommandPool {
|
||||||
return &m_pool[id];
|
return &m_pool[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createPool(int id);
|
void createPool(int id);
|
||||||
void deleteAllPool();
|
void deleteAllPool();
|
||||||
|
|
||||||
std::array<HLE::Libs::Graphics::VulkanCommandPool, 11> m_pool{};
|
std::array<HLE::Libs::Graphics::VulkanCommandPool, 11> m_pool{};
|
||||||
};
|
};
|
||||||
class CommandBuffer {
|
class CommandBuffer {
|
||||||
public:
|
public:
|
||||||
explicit CommandBuffer(int queue) : m_queue(queue) { allocateBuffer(); }
|
explicit CommandBuffer(int queue) : m_queue(queue) {
|
||||||
virtual ~CommandBuffer() { freeBuffer(); }
|
allocateBuffer();
|
||||||
|
}
|
||||||
|
virtual ~CommandBuffer() {
|
||||||
|
freeBuffer();
|
||||||
|
}
|
||||||
void allocateBuffer();
|
void allocateBuffer();
|
||||||
void freeBuffer();
|
void freeBuffer();
|
||||||
void waitForFence();
|
void waitForFence();
|
||||||
|
@ -34,9 +38,14 @@ class CommandBuffer {
|
||||||
void end() const;
|
void end() const;
|
||||||
void executeWithSemaphore();
|
void executeWithSemaphore();
|
||||||
void execute();
|
void execute();
|
||||||
u32 getIndex() const { return m_index; }
|
u32 getIndex() const {
|
||||||
HLE::Libs::Graphics::VulkanCommandPool* getPool() { return m_pool; }
|
return m_index;
|
||||||
private:
|
}
|
||||||
|
HLE::Libs::Graphics::VulkanCommandPool* getPool() {
|
||||||
|
return m_pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
int m_queue = -1;
|
int m_queue = -1;
|
||||||
u32 m_index = static_cast<u32>(-1);
|
u32 m_index = static_cast<u32>(-1);
|
||||||
HLE::Libs::Graphics::VulkanCommandPool* m_pool = nullptr;
|
HLE::Libs::Graphics::VulkanCommandPool* m_pool = nullptr;
|
||||||
|
@ -44,22 +53,26 @@ class CommandBuffer {
|
||||||
};
|
};
|
||||||
|
|
||||||
class Framebuffer {
|
class Framebuffer {
|
||||||
public:
|
public:
|
||||||
Framebuffer() {}
|
Framebuffer() {}
|
||||||
virtual ~Framebuffer() {}
|
virtual ~Framebuffer() {}
|
||||||
};
|
};
|
||||||
class RenderCtx {
|
class RenderCtx {
|
||||||
public:
|
public:
|
||||||
RenderCtx() = default;
|
RenderCtx() = default;
|
||||||
|
|
||||||
virtual ~RenderCtx() {}
|
virtual ~RenderCtx() {}
|
||||||
void setGraphicCtx(HLE::Libs::Graphics::GraphicCtx* ctx) { m_graphic_ctx = ctx; }
|
void setGraphicCtx(HLE::Libs::Graphics::GraphicCtx* ctx) {
|
||||||
HLE::Libs::Graphics::GraphicCtx* getGraphicCtx() { return m_graphic_ctx; }
|
m_graphic_ctx = ctx;
|
||||||
|
}
|
||||||
|
HLE::Libs::Graphics::GraphicCtx* getGraphicCtx() {
|
||||||
|
return m_graphic_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Framebuffer m_framebuffer{};
|
Framebuffer m_framebuffer{};
|
||||||
HLE::Libs::Graphics::GraphicCtx* m_graphic_ctx = nullptr;
|
HLE::Libs::Graphics::GraphicCtx* m_graphic_ctx = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
void renderCreateCtx();
|
void renderCreateCtx();
|
||||||
}; // namespace GPU
|
}; // namespace GPU
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <magic_enum.hpp>
|
#include <magic_enum.hpp>
|
||||||
#include "common/log.h"
|
#include "Objects/video_out_ctx.h"
|
||||||
|
#include "Util/config.h"
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "core/loader/symbols_resolver.h"
|
#include "common/log.h"
|
||||||
#include "core/PS4/HLE/Graphics/video_out.h"
|
#include "common/singleton.h"
|
||||||
#include "core/PS4/GPU/gpu_memory.h"
|
#include "core/PS4/GPU/gpu_memory.h"
|
||||||
#include "core/PS4/GPU/video_out_buffer.h"
|
#include "core/PS4/GPU/video_out_buffer.h"
|
||||||
|
#include "core/PS4/HLE/Graphics/video_out.h"
|
||||||
#include "core/hle/error_codes.h"
|
#include "core/hle/error_codes.h"
|
||||||
#include "core/hle/libraries/libscegnmdriver/libscegnmdriver.h"
|
|
||||||
#include "core/hle/libraries/libs.h"
|
#include "core/hle/libraries/libs.h"
|
||||||
|
#include "core/hle/libraries/libscegnmdriver/libscegnmdriver.h"
|
||||||
#include "core/hle/libraries/libuserservice/usr_mng_codes.h"
|
#include "core/hle/libraries/libuserservice/usr_mng_codes.h"
|
||||||
#include "Util/config.h"
|
#include "core/loader/symbols_resolver.h"
|
||||||
#include "Objects/video_out_ctx.h"
|
|
||||||
#include "common/singleton.h"
|
|
||||||
#include "emulator.h"
|
#include "emulator.h"
|
||||||
#include "graphics_render.h"
|
#include "graphics_render.h"
|
||||||
|
|
||||||
namespace HLE::Libs::Graphics::VideoOut {
|
namespace HLE::Libs::Graphics::VideoOut {
|
||||||
|
|
||||||
constexpr bool log_file_videoout = true; // disable it to disable logging
|
constexpr bool log_file_videoout = true; // disable it to disable logging
|
||||||
|
|
||||||
void videoOutInit(u32 width, u32 height) {
|
void videoOutInit(u32 width, u32 height) {
|
||||||
auto* videoOut = Common::Singleton<HLE::Graphics::Objects::VideoOutCtx>::Instance();
|
auto* videoOut = Common::Singleton<HLE::Graphics::Objects::VideoOutCtx>::Instance();
|
||||||
|
@ -33,19 +33,28 @@ bool videoOutFlip(u32 micros) {
|
||||||
|
|
||||||
std::string getPixelFormatString(s32 format) {
|
std::string getPixelFormatString(s32 format) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case SCE_VIDEO_OUT_PIXEL_FORMAT_A8R8G8B8_SRGB: return "PIXEL_FORMAT_A8R8G8B8_SRGB";
|
case SCE_VIDEO_OUT_PIXEL_FORMAT_A8R8G8B8_SRGB:
|
||||||
case SCE_VIDEO_OUT_PIXEL_FORMAT_A8B8G8R8_SRGB: return "PIXEL_FORMAT_A8B8G8R8_SRGB";
|
return "PIXEL_FORMAT_A8R8G8B8_SRGB";
|
||||||
case SCE_VIDEO_OUT_PIXEL_FORMAT_A2R10G10B10: return "PIXEL_FORMAT_A2R10G10B10";
|
case SCE_VIDEO_OUT_PIXEL_FORMAT_A8B8G8R8_SRGB:
|
||||||
case SCE_VIDEO_OUT_PIXEL_FORMAT_A2R10G10B10_SRGB: return "PIXEL_FORMAT_A2R10G10B10_SRGB";
|
return "PIXEL_FORMAT_A8B8G8R8_SRGB";
|
||||||
case SCE_VIDEO_OUT_PIXEL_FORMAT_A2R10G10B10_BT2020_PQ: return "PIXEL_FORMAT_A2R10G10B10_BT2020_PQ";
|
case SCE_VIDEO_OUT_PIXEL_FORMAT_A2R10G10B10:
|
||||||
case SCE_VIDEO_OUT_PIXEL_FORMAT_A16R16G16B16_FLOAT: return "PIXEL_FORMAT_A16R16G16B16_FLOAT";
|
return "PIXEL_FORMAT_A2R10G10B10";
|
||||||
case SCE_VIDEO_OUT_PIXEL_FORMAT_YCBCR420_BT709: return "PIXEL_FORMAT_YCBCR420_BT709";
|
case SCE_VIDEO_OUT_PIXEL_FORMAT_A2R10G10B10_SRGB:
|
||||||
default: return "Unknown pixel format";
|
return "PIXEL_FORMAT_A2R10G10B10_SRGB";
|
||||||
|
case SCE_VIDEO_OUT_PIXEL_FORMAT_A2R10G10B10_BT2020_PQ:
|
||||||
|
return "PIXEL_FORMAT_A2R10G10B10_BT2020_PQ";
|
||||||
|
case SCE_VIDEO_OUT_PIXEL_FORMAT_A16R16G16B16_FLOAT:
|
||||||
|
return "PIXEL_FORMAT_A16R16G16B16_FLOAT";
|
||||||
|
case SCE_VIDEO_OUT_PIXEL_FORMAT_YCBCR420_BT709:
|
||||||
|
return "PIXEL_FORMAT_YCBCR420_BT709";
|
||||||
|
default:
|
||||||
|
return "Unknown pixel format";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PS4_SYSV_ABI sceVideoOutSetBufferAttribute(SceVideoOutBufferAttribute* attribute, u32 pixelFormat, u32 tilingMode, u32 aspectRatio, u32 width,
|
void PS4_SYSV_ABI sceVideoOutSetBufferAttribute(SceVideoOutBufferAttribute* attribute,
|
||||||
u32 height, u32 pitchInPixel) {
|
u32 pixelFormat, u32 tilingMode, u32 aspectRatio,
|
||||||
|
u32 width, u32 height, u32 pitchInPixel) {
|
||||||
PRINT_FUNCTION_NAME();
|
PRINT_FUNCTION_NAME();
|
||||||
|
|
||||||
auto tileMode = magic_enum::enum_cast<SceVideoOutTilingMode>(tilingMode);
|
auto tileMode = magic_enum::enum_cast<SceVideoOutTilingMode>(tilingMode);
|
||||||
|
@ -81,11 +90,13 @@ static void flip_trigger_event_func(Core::Kernel::EqueueEvent* event, void* trig
|
||||||
event->event.data = reinterpret_cast<intptr_t>(trigger_data);
|
event->event.data = reinterpret_cast<intptr_t>(trigger_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flip_delete_event_func(Core::Kernel::SceKernelEqueue eq, Core::Kernel::EqueueEvent* event) {
|
static void flip_delete_event_func(Core::Kernel::SceKernelEqueue eq,
|
||||||
BREAKPOINT(); // TODO
|
Core::Kernel::EqueueEvent* event) {
|
||||||
|
BREAKPOINT(); // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Core::Kernel::SceKernelEqueue eq, s32 handle, void* udata) {
|
s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Core::Kernel::SceKernelEqueue eq, s32 handle,
|
||||||
|
void* udata) {
|
||||||
PRINT_FUNCTION_NAME();
|
PRINT_FUNCTION_NAME();
|
||||||
auto* videoOut = Common::Singleton<HLE::Graphics::Objects::VideoOutCtx>::Instance();
|
auto* videoOut = Common::Singleton<HLE::Graphics::Objects::VideoOutCtx>::Instance();
|
||||||
|
|
||||||
|
@ -119,13 +130,14 @@ s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Core::Kernel::SceKernelEqueue eq, s32 h
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* const* addresses, s32 bufferNum,
|
s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* const* addresses,
|
||||||
|
s32 bufferNum,
|
||||||
const SceVideoOutBufferAttribute* attribute) {
|
const SceVideoOutBufferAttribute* attribute) {
|
||||||
PRINT_FUNCTION_NAME();
|
PRINT_FUNCTION_NAME();
|
||||||
auto* videoOut = Common::Singleton<HLE::Graphics::Objects::VideoOutCtx>::Instance();
|
auto* videoOut = Common::Singleton<HLE::Graphics::Objects::VideoOutCtx>::Instance();
|
||||||
auto* ctx = videoOut->getCtx(handle);
|
auto* ctx = videoOut->getCtx(handle);
|
||||||
|
|
||||||
if (handle == 1) { // main port
|
if (handle == 1) { // main port
|
||||||
if (startIndex < 0 || startIndex > 15) {
|
if (startIndex < 0 || startIndex > 15) {
|
||||||
LOG_TRACE_IF(log_file_videoout, "invalid startIndex = {}\n", startIndex);
|
LOG_TRACE_IF(log_file_videoout, "invalid startIndex = {}\n", startIndex);
|
||||||
return SCE_VIDEO_OUT_ERROR_INVALID_VALUE;
|
return SCE_VIDEO_OUT_ERROR_INVALID_VALUE;
|
||||||
|
@ -168,7 +180,7 @@ s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* co
|
||||||
GPU::renderCreateCtx();
|
GPU::renderCreateCtx();
|
||||||
|
|
||||||
// try to calculate buffer size
|
// try to calculate buffer size
|
||||||
u64 buffer_size = 0; // still calculation is probably partial or wrong :D
|
u64 buffer_size = 0; // still calculation is probably partial or wrong :D
|
||||||
if (attribute->tilingMode == 0) {
|
if (attribute->tilingMode == 0) {
|
||||||
buffer_size = 1920 * 1088 * 4;
|
buffer_size = 1920 * 1088 * 4;
|
||||||
} else {
|
} else {
|
||||||
|
@ -193,7 +205,9 @@ s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* co
|
||||||
format = GPU::VideoOutBufferFormat::R8G8B8A8Srgb;
|
format = GPU::VideoOutBufferFormat::R8G8B8A8Srgb;
|
||||||
}
|
}
|
||||||
|
|
||||||
GPU::VideoOutBufferObj buffer_info(format, attribute->width, attribute->height, attribute->tilingMode == 0, Config::isNeoMode(), buffer_pitch);
|
GPU::VideoOutBufferObj buffer_info(format, attribute->width, attribute->height,
|
||||||
|
attribute->tilingMode == 0, Config::isNeoMode(),
|
||||||
|
buffer_pitch);
|
||||||
|
|
||||||
for (int i = 0; i < bufferNum; i++) {
|
for (int i = 0; i < bufferNum; i++) {
|
||||||
if (ctx->buffers[i + startIndex].buffer != nullptr) {
|
if (ctx->buffers[i + startIndex].buffer != nullptr) {
|
||||||
|
@ -205,10 +219,13 @@ s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* co
|
||||||
ctx->buffers[i + startIndex].buffer = addresses[i];
|
ctx->buffers[i + startIndex].buffer = addresses[i];
|
||||||
ctx->buffers[i + startIndex].buffer_size = buffer_size;
|
ctx->buffers[i + startIndex].buffer_size = buffer_size;
|
||||||
ctx->buffers[i + startIndex].buffer_pitch = buffer_pitch;
|
ctx->buffers[i + startIndex].buffer_pitch = buffer_pitch;
|
||||||
ctx->buffers[i + startIndex].buffer_render = static_cast<Graphics::VideoOutVulkanImage*>(
|
ctx->buffers[i + startIndex].buffer_render =
|
||||||
GPU::memoryCreateObj(0, videoOut->getGraphicCtx(), nullptr, reinterpret_cast<uint64_t>(addresses[i]), buffer_size, buffer_info));
|
static_cast<Graphics::VideoOutVulkanImage*>(GPU::memoryCreateObj(
|
||||||
|
0, videoOut->getGraphicCtx(), nullptr, reinterpret_cast<uint64_t>(addresses[i]),
|
||||||
|
buffer_size, buffer_info));
|
||||||
|
|
||||||
LOG_INFO_IF(log_file_videoout, "buffers[{}] = {:#x}\n", i + startIndex, reinterpret_cast<u64>(addresses[i]));
|
LOG_INFO_IF(log_file_videoout, "buffers[{}] = {:#x}\n", i + startIndex,
|
||||||
|
reinterpret_cast<u64>(addresses[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return registration_index;
|
return registration_index;
|
||||||
|
@ -234,14 +251,16 @@ s32 PS4_SYSV_ABI sceVideoOutSubmitFlip(s32 handle, s32 bufferIndex, s32 flipMode
|
||||||
auto* ctx = videoOut->getCtx(handle);
|
auto* ctx = videoOut->getCtx(handle);
|
||||||
|
|
||||||
if (flipMode != 1) {
|
if (flipMode != 1) {
|
||||||
// BREAKPOINT(); // only flipmode==1 is supported
|
// BREAKPOINT(); // only flipmode==1 is supported
|
||||||
LOG_TRACE_IF(log_file_videoout, "sceVideoOutSubmitFlip flipmode {}\n", bufferIndex);//openBOR needs 2 but seems to work
|
LOG_TRACE_IF(log_file_videoout, "sceVideoOutSubmitFlip flipmode {}\n",
|
||||||
|
bufferIndex); // openBOR needs 2 but seems to work
|
||||||
}
|
}
|
||||||
if (bufferIndex == -1) {
|
if (bufferIndex == -1) {
|
||||||
BREAKPOINT(); // blank output not supported
|
BREAKPOINT(); // blank output not supported
|
||||||
}
|
}
|
||||||
if (bufferIndex < -1 || bufferIndex > 15) {
|
if (bufferIndex < -1 || bufferIndex > 15) {
|
||||||
LOG_TRACE_IF(log_file_videoout, "sceVideoOutSubmitFlip invalid bufferIndex {}\n", bufferIndex);
|
LOG_TRACE_IF(log_file_videoout, "sceVideoOutSubmitFlip invalid bufferIndex {}\n",
|
||||||
|
bufferIndex);
|
||||||
return SCE_VIDEO_OUT_ERROR_INVALID_INDEX;
|
return SCE_VIDEO_OUT_ERROR_INVALID_INDEX;
|
||||||
}
|
}
|
||||||
LOG_INFO_IF(log_file_videoout, "bufferIndex = {}\n", bufferIndex);
|
LOG_INFO_IF(log_file_videoout, "bufferIndex = {}\n", bufferIndex);
|
||||||
|
@ -252,7 +271,8 @@ s32 PS4_SYSV_ABI sceVideoOutSubmitFlip(s32 handle, s32 bufferIndex, s32 flipMode
|
||||||
LOG_TRACE_IF(log_file_videoout, "sceVideoOutSubmitFlip flip queue is full\n");
|
LOG_TRACE_IF(log_file_videoout, "sceVideoOutSubmitFlip flip queue is full\n");
|
||||||
return SCE_VIDEO_OUT_ERROR_FLIP_QUEUE_FULL;
|
return SCE_VIDEO_OUT_ERROR_FLIP_QUEUE_FULL;
|
||||||
}
|
}
|
||||||
Core::Libraries::LibSceGnmDriver::sceGnmFlushGarlic(); // hackish should be done that neccesary for niko's homebrew
|
Core::Libraries::LibSceGnmDriver::sceGnmFlushGarlic(); // hackish should be done that neccesary
|
||||||
|
// for niko's homebrew
|
||||||
return SCE_OK;
|
return SCE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,7 +300,8 @@ s32 PS4_SYSV_ABI sceVideoOutGetResolutionStatus(s32 handle, SceVideoOutResolutio
|
||||||
return SCE_OK;
|
return SCE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceVideoOutOpen(SceUserServiceUserId userId, s32 busType, s32 index, const void* param) {
|
s32 PS4_SYSV_ABI sceVideoOutOpen(SceUserServiceUserId userId, s32 busType, s32 index,
|
||||||
|
const void* param) {
|
||||||
PRINT_FUNCTION_NAME();
|
PRINT_FUNCTION_NAME();
|
||||||
if (userId != SCE_USER_SERVICE_USER_ID_SYSTEM && userId != 0) {
|
if (userId != SCE_USER_SERVICE_USER_ID_SYSTEM && userId != 0) {
|
||||||
BREAKPOINT();
|
BREAKPOINT();
|
||||||
|
@ -300,7 +321,7 @@ s32 PS4_SYSV_ABI sceVideoOutOpen(SceUserServiceUserId userId, s32 busType, s32 i
|
||||||
|
|
||||||
if (handle < 0) {
|
if (handle < 0) {
|
||||||
LOG_TRACE_IF(log_file_videoout, "sceVideoOutOpen all available handles are open\n");
|
LOG_TRACE_IF(log_file_videoout, "sceVideoOutOpen all available handles are open\n");
|
||||||
return SCE_VIDEO_OUT_ERROR_RESOURCE_BUSY; // it is alreadyOpened
|
return SCE_VIDEO_OUT_ERROR_RESOURCE_BUSY; // it is alreadyOpened
|
||||||
}
|
}
|
||||||
|
|
||||||
return handle;
|
return handle;
|
||||||
|
@ -319,25 +340,38 @@ s32 PS4_SYSV_ABI sceVideoOutUnregisterBuffers(s32 handle, s32 attributeIndex) {
|
||||||
|
|
||||||
void videoOutRegisterLib(Core::Loader::SymbolsResolver* sym) {
|
void videoOutRegisterLib(Core::Loader::SymbolsResolver* sym) {
|
||||||
using namespace Core;
|
using namespace Core;
|
||||||
LIB_FUNCTION("SbU3dwp80lQ", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutGetFlipStatus);
|
LIB_FUNCTION("SbU3dwp80lQ", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||||
|
sceVideoOutGetFlipStatus);
|
||||||
LIB_FUNCTION("U46NwOiJpys", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutSubmitFlip);
|
LIB_FUNCTION("U46NwOiJpys", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutSubmitFlip);
|
||||||
LIB_FUNCTION("w3BY+tAEiQY", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutRegisterBuffers);
|
LIB_FUNCTION("w3BY+tAEiQY", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||||
LIB_FUNCTION("HXzjK9yI30k", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutAddFlipEvent);
|
sceVideoOutRegisterBuffers);
|
||||||
LIB_FUNCTION("CBiu4mCE1DA", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutSetFlipRate);
|
LIB_FUNCTION("HXzjK9yI30k", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||||
LIB_FUNCTION("i6-sR91Wt-4", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutSetBufferAttribute);
|
sceVideoOutAddFlipEvent);
|
||||||
LIB_FUNCTION("6kPnj51T62Y", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutGetResolutionStatus);
|
LIB_FUNCTION("CBiu4mCE1DA", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||||
|
sceVideoOutSetFlipRate);
|
||||||
|
LIB_FUNCTION("i6-sR91Wt-4", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||||
|
sceVideoOutSetBufferAttribute);
|
||||||
|
LIB_FUNCTION("6kPnj51T62Y", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||||
|
sceVideoOutGetResolutionStatus);
|
||||||
LIB_FUNCTION("Up36PTk687E", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutOpen);
|
LIB_FUNCTION("Up36PTk687E", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutOpen);
|
||||||
LIB_FUNCTION("zgXifHT9ErY", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutIsFlipPending);
|
LIB_FUNCTION("zgXifHT9ErY", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||||
LIB_FUNCTION("N5KDtkIjjJ4", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutUnregisterBuffers);
|
sceVideoOutIsFlipPending);
|
||||||
|
LIB_FUNCTION("N5KDtkIjjJ4", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||||
|
sceVideoOutUnregisterBuffers);
|
||||||
LIB_FUNCTION("uquVH4-Du78", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutClose);
|
LIB_FUNCTION("uquVH4-Du78", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutClose);
|
||||||
|
|
||||||
// openOrbis appears to have libSceVideoOut_v1 module libSceVideoOut_v1.1
|
// openOrbis appears to have libSceVideoOut_v1 module libSceVideoOut_v1.1
|
||||||
LIB_FUNCTION("Up36PTk687E", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutOpen);
|
LIB_FUNCTION("Up36PTk687E", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutOpen);
|
||||||
LIB_FUNCTION("CBiu4mCE1DA", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutSetFlipRate);
|
LIB_FUNCTION("CBiu4mCE1DA", "libSceVideoOut", 1, "libSceVideoOut", 1, 1,
|
||||||
LIB_FUNCTION("HXzjK9yI30k", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutAddFlipEvent);
|
sceVideoOutSetFlipRate);
|
||||||
LIB_FUNCTION("i6-sR91Wt-4", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutSetBufferAttribute);
|
LIB_FUNCTION("HXzjK9yI30k", "libSceVideoOut", 1, "libSceVideoOut", 1, 1,
|
||||||
LIB_FUNCTION("w3BY+tAEiQY", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutRegisterBuffers);
|
sceVideoOutAddFlipEvent);
|
||||||
|
LIB_FUNCTION("i6-sR91Wt-4", "libSceVideoOut", 1, "libSceVideoOut", 1, 1,
|
||||||
|
sceVideoOutSetBufferAttribute);
|
||||||
|
LIB_FUNCTION("w3BY+tAEiQY", "libSceVideoOut", 1, "libSceVideoOut", 1, 1,
|
||||||
|
sceVideoOutRegisterBuffers);
|
||||||
LIB_FUNCTION("U46NwOiJpys", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutSubmitFlip);
|
LIB_FUNCTION("U46NwOiJpys", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutSubmitFlip);
|
||||||
LIB_FUNCTION("SbU3dwp80lQ", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutGetFlipStatus);
|
LIB_FUNCTION("SbU3dwp80lQ", "libSceVideoOut", 1, "libSceVideoOut", 1, 1,
|
||||||
|
sceVideoOutGetFlipStatus);
|
||||||
}
|
}
|
||||||
} // namespace HLE::Libs::Graphics::VideoOut
|
} // namespace HLE::Libs::Graphics::VideoOut
|
||||||
|
|
|
@ -9,12 +9,12 @@ class SymbolsResolver;
|
||||||
|
|
||||||
namespace HLE::Libs::Graphics::VideoOut {
|
namespace HLE::Libs::Graphics::VideoOut {
|
||||||
|
|
||||||
using SceUserServiceUserId = s32; // TODO move it to proper place
|
using SceUserServiceUserId = s32; // TODO move it to proper place
|
||||||
|
|
||||||
// SceVideoOutBusType
|
// SceVideoOutBusType
|
||||||
constexpr int SCE_VIDEO_OUT_BUS_TYPE_MAIN = 0; // Main output
|
constexpr int SCE_VIDEO_OUT_BUS_TYPE_MAIN = 0; // Main output
|
||||||
constexpr int SCE_VIDEO_OUT_BUS_TYPE_AUX_SOCIAL_SCREEN = 5; // Aux output for social
|
constexpr int SCE_VIDEO_OUT_BUS_TYPE_AUX_SOCIAL_SCREEN = 5; // Aux output for social
|
||||||
constexpr int SCE_VIDEO_OUT_BUS_TYPE_AUX_GAME_LIVE_STREAMING = 6; // Aux output for screaming
|
constexpr int SCE_VIDEO_OUT_BUS_TYPE_AUX_GAME_LIVE_STREAMING = 6; // Aux output for screaming
|
||||||
|
|
||||||
// SceVideoOutRefreshRate
|
// SceVideoOutRefreshRate
|
||||||
constexpr int SCE_VIDEO_OUT_REFRESH_RATE_UNKNOWN = 0;
|
constexpr int SCE_VIDEO_OUT_REFRESH_RATE_UNKNOWN = 0;
|
||||||
|
@ -37,9 +37,16 @@ constexpr int SCE_VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_NONE = 0;
|
||||||
constexpr int SCE_VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_VR = 7;
|
constexpr int SCE_VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_VR = 7;
|
||||||
constexpr int SCE_VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_STRICT_COLORIMETRY = 8;
|
constexpr int SCE_VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_STRICT_COLORIMETRY = 8;
|
||||||
|
|
||||||
enum SceVideoOutEventId : s16 { SCE_VIDEO_OUT_EVENT_FLIP = 0, SCE_VIDEO_OUT_EVENT_VBLANK = 1, SCE_VIDEO_OUT_EVENT_PRE_VBLANK_START = 2 };
|
enum SceVideoOutEventId : s16 {
|
||||||
|
SCE_VIDEO_OUT_EVENT_FLIP = 0,
|
||||||
|
SCE_VIDEO_OUT_EVENT_VBLANK = 1,
|
||||||
|
SCE_VIDEO_OUT_EVENT_PRE_VBLANK_START = 2
|
||||||
|
};
|
||||||
|
|
||||||
enum SceVideoOutTilingMode : s32 { SCE_VIDEO_OUT_TILING_MODE_TILE = 0, SCE_VIDEO_OUT_TILING_MODE_LINEAR = 1 };
|
enum SceVideoOutTilingMode : s32 {
|
||||||
|
SCE_VIDEO_OUT_TILING_MODE_TILE = 0,
|
||||||
|
SCE_VIDEO_OUT_TILING_MODE_LINEAR = 1
|
||||||
|
};
|
||||||
|
|
||||||
enum AspectRatioMode : s32 { SCE_VIDEO_OUT_ASPECT_RATIO_16_9 = 0 };
|
enum AspectRatioMode : s32 { SCE_VIDEO_OUT_ASPECT_RATIO_16_9 = 0 };
|
||||||
|
|
||||||
|
@ -101,17 +108,20 @@ std::string getPixelFormatString(s32 format);
|
||||||
void videoOutRegisterLib(Core::Loader::SymbolsResolver* sym);
|
void videoOutRegisterLib(Core::Loader::SymbolsResolver* sym);
|
||||||
bool videoOutFlip(u32 micros);
|
bool videoOutFlip(u32 micros);
|
||||||
|
|
||||||
void PS4_SYSV_ABI sceVideoOutSetBufferAttribute(SceVideoOutBufferAttribute* attribute, u32 pixelFormat, u32 tilingMode, u32 aspectRatio, u32 width,
|
void PS4_SYSV_ABI sceVideoOutSetBufferAttribute(SceVideoOutBufferAttribute* attribute,
|
||||||
u32 height, u32 pitchInPixel);
|
u32 pixelFormat, u32 tilingMode, u32 aspectRatio,
|
||||||
|
u32 width, u32 height, u32 pitchInPixel);
|
||||||
s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Core::Kernel::SceKernelEqueue eq, s32 handle, void* udata);
|
s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Core::Kernel::SceKernelEqueue eq, s32 handle, void* udata);
|
||||||
s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* const* addresses, s32 bufferNum,
|
s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* const* addresses,
|
||||||
|
s32 bufferNum,
|
||||||
const SceVideoOutBufferAttribute* attribute);
|
const SceVideoOutBufferAttribute* attribute);
|
||||||
s32 PS4_SYSV_ABI sceVideoOutSetFlipRate(s32 handle, s32 rate);
|
s32 PS4_SYSV_ABI sceVideoOutSetFlipRate(s32 handle, s32 rate);
|
||||||
s32 PS4_SYSV_ABI sceVideoOutIsFlipPending(s32 handle);
|
s32 PS4_SYSV_ABI sceVideoOutIsFlipPending(s32 handle);
|
||||||
s32 PS4_SYSV_ABI sceVideoOutSubmitFlip(s32 handle, s32 bufferIndex, s32 flipMode, s64 flipArg);
|
s32 PS4_SYSV_ABI sceVideoOutSubmitFlip(s32 handle, s32 bufferIndex, s32 flipMode, s64 flipArg);
|
||||||
s32 PS4_SYSV_ABI sceVideoOutGetFlipStatus(s32 handle, SceVideoOutFlipStatus* status);
|
s32 PS4_SYSV_ABI sceVideoOutGetFlipStatus(s32 handle, SceVideoOutFlipStatus* status);
|
||||||
s32 PS4_SYSV_ABI sceVideoOutGetResolutionStatus(s32 handle, SceVideoOutResolutionStatus* status);
|
s32 PS4_SYSV_ABI sceVideoOutGetResolutionStatus(s32 handle, SceVideoOutResolutionStatus* status);
|
||||||
s32 PS4_SYSV_ABI sceVideoOutOpen(SceUserServiceUserId userId, s32 busType, s32 index, const void* param);
|
s32 PS4_SYSV_ABI sceVideoOutOpen(SceUserServiceUserId userId, s32 busType, s32 index,
|
||||||
|
const void* param);
|
||||||
s32 PS4_SYSV_ABI sceVideoOutClose(s32 handle);
|
s32 PS4_SYSV_ABI sceVideoOutClose(s32 handle);
|
||||||
|
|
||||||
} // namespace HLE::Libs::Graphics::VideoOut
|
} // namespace HLE::Libs::Graphics::VideoOut
|
||||||
|
|
|
@ -6,8 +6,7 @@ namespace Core::AeroLib {
|
||||||
|
|
||||||
// Use a direct table here + binary search as contents are static
|
// Use a direct table here + binary search as contents are static
|
||||||
static constexpr NidEntry NIDS[] = {
|
static constexpr NidEntry NIDS[] = {
|
||||||
#define STUB(nid, name) \
|
#define STUB(nid, name) {nid, #name},
|
||||||
{ nid, #name },
|
|
||||||
#include "aerolib.inl"
|
#include "aerolib.inl"
|
||||||
#undef STUB
|
#undef STUB
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,11 +24,11 @@ u64 UnresolvedStub() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static u64 UnknownStub() {
|
static u64 UnknownStub() {
|
||||||
LOG_ERROR("Stub: Unknown (nid: Unknown) called, returning zero to {}\n", __builtin_return_address(0));
|
LOG_ERROR("Stub: Unknown (nid: Unknown) called, returning zero to {}\n",
|
||||||
|
__builtin_return_address(0));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const NidEntry* stub_nids[MAX_STUBS];
|
static const NidEntry* stub_nids[MAX_STUBS];
|
||||||
static std::string stub_nids_unknown[MAX_STUBS];
|
static std::string stub_nids_unknown[MAX_STUBS];
|
||||||
|
|
||||||
|
@ -36,17 +36,18 @@ template <int stub_index>
|
||||||
static u64 CommonStub() {
|
static u64 CommonStub() {
|
||||||
auto entry = stub_nids[stub_index];
|
auto entry = stub_nids[stub_index];
|
||||||
if (entry) {
|
if (entry) {
|
||||||
LOG_ERROR("Stub: {} (nid: {}) called, returning zero to {}\n", entry->name, entry->nid, __builtin_return_address(0));
|
LOG_ERROR("Stub: {} (nid: {}) called, returning zero to {}\n", entry->name, entry->nid,
|
||||||
|
__builtin_return_address(0));
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("Stub: Unknown (nid: {}) called, returning zero to {}\n", stub_nids_unknown[stub_index], __builtin_return_address(0));
|
LOG_ERROR("Stub: Unknown (nid: {}) called, returning zero to {}\n",
|
||||||
|
stub_nids_unknown[stub_index], __builtin_return_address(0));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 UsedStubEntries;
|
static u32 UsedStubEntries;
|
||||||
|
|
||||||
#define XREP_1(x) \
|
#define XREP_1(x) &CommonStub<x>,
|
||||||
&CommonStub<x>,
|
|
||||||
|
|
||||||
#define XREP_2(x) XREP_1(x) XREP_1(x + 1)
|
#define XREP_2(x) XREP_1(x) XREP_1(x + 1)
|
||||||
#define XREP_4(x) XREP_2(x) XREP_2(x + 2)
|
#define XREP_4(x) XREP_2(x) XREP_2(x + 2)
|
||||||
|
@ -60,9 +61,7 @@ static u32 UsedStubEntries;
|
||||||
|
|
||||||
#define STUBS_LIST XREP_128(0)
|
#define STUBS_LIST XREP_128(0)
|
||||||
|
|
||||||
static u64 (*stub_handlers[MAX_STUBS])() = {
|
static u64 (*stub_handlers[MAX_STUBS])() = {STUBS_LIST};
|
||||||
STUBS_LIST
|
|
||||||
};
|
|
||||||
|
|
||||||
u64 GetStub(const char* nid) {
|
u64 GetStub(const char* nid) {
|
||||||
if (UsedStubEntries >= MAX_STUBS) {
|
if (UsedStubEntries >= MAX_STUBS) {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
namespace Core::FileSys {
|
namespace Core::FileSys {
|
||||||
|
|
||||||
constexpr int RESERVED_HANDLES = 3; // First 3 handles are stdin,stdout,stderr
|
constexpr int RESERVED_HANDLES = 3; // First 3 handles are stdin,stdout,stderr
|
||||||
|
|
||||||
void MntPoints::mount(const std::string& host_folder, const std::string& guest_folder) {
|
void MntPoints::mount(const std::string& host_folder, const std::string& guest_folder) {
|
||||||
std::scoped_lock lock{m_mutex};
|
std::scoped_lock lock{m_mutex};
|
||||||
|
@ -15,7 +15,7 @@ void MntPoints::mount(const std::string& host_folder, const std::string& guest_f
|
||||||
|
|
||||||
m_mnt_pairs.push_back(pair);
|
m_mnt_pairs.push_back(pair);
|
||||||
}
|
}
|
||||||
void MntPoints::unmount(const std::string& path) {} // TODO!
|
void MntPoints::unmount(const std::string& path) {} // TODO!
|
||||||
void MntPoints::unmountAll() {
|
void MntPoints::unmountAll() {
|
||||||
std::scoped_lock lock{m_mutex};
|
std::scoped_lock lock{m_mutex};
|
||||||
m_mnt_pairs.clear();
|
m_mnt_pairs.clear();
|
||||||
|
@ -40,10 +40,10 @@ std::string MntPoints::getHostFile(const std::string& guest_file) {
|
||||||
std::scoped_lock lock{m_mutex};
|
std::scoped_lock lock{m_mutex};
|
||||||
|
|
||||||
for (auto& pair : m_mnt_pairs) {
|
for (auto& pair : m_mnt_pairs) {
|
||||||
//horrible code but it works :D
|
// horrible code but it works :D
|
||||||
int find = guest_file.find(pair.guest_path);
|
int find = guest_file.find(pair.guest_path);
|
||||||
if (find == 0) {
|
if (find == 0) {
|
||||||
std::string npath = guest_file.substr(pair.guest_path.size(), guest_file.size()-1);
|
std::string npath = guest_file.substr(pair.guest_path.size(), guest_file.size() - 1);
|
||||||
std::replace(pair.host_path.begin(), pair.host_path.end(), '\\', '/');
|
std::replace(pair.host_path.begin(), pair.host_path.end(), '\\', '/');
|
||||||
return pair.host_path + npath;
|
return pair.host_path + npath;
|
||||||
}
|
}
|
||||||
|
@ -88,4 +88,4 @@ File* HandleTable::getFile(const std::string& host_name) {
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
} // namespace Core::FileSys
|
} // namespace Core::FileSys
|
|
@ -5,16 +5,16 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/fs_file.h"
|
|
||||||
#include <common/io_file.h>
|
#include <common/io_file.h>
|
||||||
|
#include "common/fs_file.h"
|
||||||
|
|
||||||
namespace Core::FileSys {
|
namespace Core::FileSys {
|
||||||
|
|
||||||
class MntPoints {
|
class MntPoints {
|
||||||
public:
|
public:
|
||||||
struct MntPair {
|
struct MntPair {
|
||||||
std::string host_path;
|
std::string host_path;
|
||||||
std::string guest_path; // e.g /app0/
|
std::string guest_path; // e.g /app0/
|
||||||
};
|
};
|
||||||
|
|
||||||
MntPoints() = default;
|
MntPoints() = default;
|
||||||
|
@ -25,7 +25,7 @@ class MntPoints {
|
||||||
std::string getHostDirectory(const std::string& guest_directory);
|
std::string getHostDirectory(const std::string& guest_directory);
|
||||||
std::string getHostFile(const std::string& guest_file);
|
std::string getHostFile(const std::string& guest_file);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<MntPair> m_mnt_pairs;
|
std::vector<MntPair> m_mnt_pairs;
|
||||||
std::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
};
|
};
|
||||||
|
@ -36,12 +36,12 @@ struct File {
|
||||||
std::string m_host_name;
|
std::string m_host_name;
|
||||||
std::string m_guest_name;
|
std::string m_guest_name;
|
||||||
IOFile f;
|
IOFile f;
|
||||||
//std::vector<Common::FS::DirEntry> dirents;
|
// std::vector<Common::FS::DirEntry> dirents;
|
||||||
u32 dirents_index;
|
u32 dirents_index;
|
||||||
std::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
};
|
};
|
||||||
class HandleTable {
|
class HandleTable {
|
||||||
public:
|
public:
|
||||||
HandleTable() {}
|
HandleTable() {}
|
||||||
virtual ~HandleTable() {}
|
virtual ~HandleTable() {}
|
||||||
int createHandle();
|
int createHandle();
|
||||||
|
@ -49,9 +49,9 @@ class HandleTable {
|
||||||
File* getFile(int d);
|
File* getFile(int d);
|
||||||
File* getFile(const std::string& host_name);
|
File* getFile(const std::string& host_name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<File*> m_files;
|
std::vector<File*> m_files;
|
||||||
std::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Core::FileSys
|
} // namespace Core::FileSys
|
||||||
|
|
|
@ -231,14 +231,14 @@ constexpr int SCE_KERNEL_ERROR_ESTART = 0x80020064;
|
||||||
constexpr int SCE_KERNEL_ERROR_ESTOP = 0x80020065;
|
constexpr int SCE_KERNEL_ERROR_ESTOP = 0x80020065;
|
||||||
|
|
||||||
// videoOut
|
// videoOut
|
||||||
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_VALUE = 0x80290001; // invalid argument
|
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_VALUE = 0x80290001; // invalid argument
|
||||||
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_ADDRESS = 0x80290002; // invalid addresses
|
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_ADDRESS = 0x80290002; // invalid addresses
|
||||||
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_TILING_MODE = 0x80290007; // invalid tiling mode
|
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_TILING_MODE = 0x80290007; // invalid tiling mode
|
||||||
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_ASPECT_RATIO = 0x80290008; // invalid aspect ration
|
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_ASPECT_RATIO = 0x80290008; // invalid aspect ration
|
||||||
constexpr int SCE_VIDEO_OUT_ERROR_RESOURCE_BUSY = 0x80290009; // already opened
|
constexpr int SCE_VIDEO_OUT_ERROR_RESOURCE_BUSY = 0x80290009; // already opened
|
||||||
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_INDEX = 0x8029000A; // invalid buffer index
|
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_INDEX = 0x8029000A; // invalid buffer index
|
||||||
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_HANDLE = 0x8029000B; // invalid handle
|
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_HANDLE = 0x8029000B; // invalid handle
|
||||||
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE = 0x8029000C; // Invalid event queue
|
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE = 0x8029000C; // Invalid event queue
|
||||||
constexpr int SCE_VIDEO_OUT_ERROR_SLOT_OCCUPIED = 0x80290010; // slot already used
|
constexpr int SCE_VIDEO_OUT_ERROR_SLOT_OCCUPIED = 0x80290010; // slot already used
|
||||||
constexpr int SCE_VIDEO_OUT_ERROR_FLIP_QUEUE_FULL = 0x80290012; // flip queue is full
|
constexpr int SCE_VIDEO_OUT_ERROR_FLIP_QUEUE_FULL = 0x80290012; // flip queue is full
|
||||||
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_OPTION = 0x8029001A; // Invalid buffer attribute option
|
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_OPTION = 0x8029001A; // Invalid buffer attribute option
|
||||||
|
|
|
@ -15,7 +15,7 @@ int EqueueInternal::addEvent(const EqueueEvent& event) {
|
||||||
m_events.push_back(event);
|
m_events.push_back(event);
|
||||||
|
|
||||||
if (event.isTriggered) {
|
if (event.isTriggered) {
|
||||||
BREAKPOINT(); // we don't support that either yet
|
BREAKPOINT(); // we don't support that either yet
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -42,7 +42,7 @@ bool EqueueInternal::triggerEvent(u64 ident, s16 filter, void* trigger_data) {
|
||||||
std::scoped_lock lock{m_mutex};
|
std::scoped_lock lock{m_mutex};
|
||||||
|
|
||||||
if (m_events.size() > 1) {
|
if (m_events.size() > 1) {
|
||||||
BREAKPOINT(); // we currently support one event
|
BREAKPOINT(); // we currently support one event
|
||||||
}
|
}
|
||||||
auto& event = m_events[0];
|
auto& event = m_events[0];
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ int EqueueInternal::getTriggeredEvents(SceKernelEvent* ev, int num) {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (m_events.size() > 1) {
|
if (m_events.size() > 1) {
|
||||||
BREAKPOINT(); // we currently support one event
|
BREAKPOINT(); // we currently support one event
|
||||||
}
|
}
|
||||||
auto& event = m_events[0];
|
auto& event = m_events[0];
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <condition_variable>
|
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
||||||
namespace Core::Kernel {
|
namespace Core::Kernel {
|
||||||
|
|
||||||
constexpr s16 EVFILT_READ = -1;
|
constexpr s16 EVFILT_READ = -1;
|
||||||
constexpr s16 EVFILT_WRITE = -2;
|
constexpr s16 EVFILT_WRITE = -2;
|
||||||
constexpr s16 EVFILT_AIO = -3; // attached to aio requests
|
constexpr s16 EVFILT_AIO = -3; // attached to aio requests
|
||||||
constexpr s16 EVFILT_VNODE = -4; // attached to vnodes
|
constexpr s16 EVFILT_VNODE = -4; // attached to vnodes
|
||||||
constexpr s16 EVFILT_PROC = -5; // attached to struct proc
|
constexpr s16 EVFILT_PROC = -5; // attached to struct proc
|
||||||
constexpr s16 EVFILT_SIGNAL = -6; // attached to struct proc
|
constexpr s16 EVFILT_SIGNAL = -6; // attached to struct proc
|
||||||
constexpr s16 EVFILT_TIMER = -7; // timers
|
constexpr s16 EVFILT_TIMER = -7; // timers
|
||||||
constexpr s16 EVFILT_FS = -9; // filesystem events
|
constexpr s16 EVFILT_FS = -9; // filesystem events
|
||||||
constexpr s16 EVFILT_LIO = -10; // attached to lio requests
|
constexpr s16 EVFILT_LIO = -10; // attached to lio requests
|
||||||
constexpr s16 EVFILT_USER = -11; // User events
|
constexpr s16 EVFILT_USER = -11; // User events
|
||||||
constexpr s16 EVFILT_POLLING = -12;
|
constexpr s16 EVFILT_POLLING = -12;
|
||||||
constexpr s16 EVFILT_VIDEO_OUT = -13;
|
constexpr s16 EVFILT_VIDEO_OUT = -13;
|
||||||
constexpr s16 EVFILT_GRAPHICS_CORE = -14;
|
constexpr s16 EVFILT_GRAPHICS_CORE = -14;
|
||||||
|
@ -61,15 +61,18 @@ struct EqueueEvent {
|
||||||
};
|
};
|
||||||
|
|
||||||
class EqueueInternal {
|
class EqueueInternal {
|
||||||
public:
|
public:
|
||||||
EqueueInternal() = default;
|
EqueueInternal() = default;
|
||||||
virtual ~EqueueInternal();
|
virtual ~EqueueInternal();
|
||||||
void setName(const std::string& m_name) { this->m_name = m_name; }
|
void setName(const std::string& m_name) {
|
||||||
|
this->m_name = m_name;
|
||||||
|
}
|
||||||
int addEvent(const EqueueEvent& event);
|
int addEvent(const EqueueEvent& event);
|
||||||
int waitForEvents(SceKernelEvent* ev, int num, u32 micros);
|
int waitForEvents(SceKernelEvent* ev, int num, u32 micros);
|
||||||
bool triggerEvent(u64 ident, s16 filter, void* trigger_data);
|
bool triggerEvent(u64 ident, s16 filter, void* trigger_data);
|
||||||
int getTriggeredEvents(SceKernelEvent* ev, int num);
|
int getTriggeredEvents(SceKernelEvent* ev, int num);
|
||||||
private:
|
|
||||||
|
private:
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
std::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
std::vector<EqueueEvent> m_events;
|
std::vector<EqueueEvent> m_events;
|
||||||
|
|
|
@ -6,8 +6,8 @@ static u64 AlignUp(u64 pos, u64 align) {
|
||||||
return (align != 0 ? (pos + (align - 1)) & ~(align - 1) : pos);
|
return (align != 0 ? (pos + (align - 1)) & ~(align - 1) : pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhysicalMemory::Alloc(u64 searchStart, u64 searchEnd, u64 len, u64 alignment,
|
bool PhysicalMemory::Alloc(u64 searchStart, u64 searchEnd, u64 len, u64 alignment, u64* physAddrOut,
|
||||||
u64* physAddrOut, int memoryType) {
|
int memoryType) {
|
||||||
std::scoped_lock lock{m_mutex};
|
std::scoped_lock lock{m_mutex};
|
||||||
u64 find_free_pos = 0;
|
u64 find_free_pos = 0;
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,13 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
#include "core/virtual_memory.h"
|
|
||||||
#include "core/PS4/GPU/gpu_memory.h"
|
#include "core/PS4/GPU/gpu_memory.h"
|
||||||
|
#include "core/virtual_memory.h"
|
||||||
|
|
||||||
namespace Core::Kernel {
|
namespace Core::Kernel {
|
||||||
|
|
||||||
class PhysicalMemory {
|
class PhysicalMemory {
|
||||||
public:
|
public:
|
||||||
struct AllocatedBlock {
|
struct AllocatedBlock {
|
||||||
u64 start_addr;
|
u64 start_addr;
|
||||||
u64 size;
|
u64 size;
|
||||||
|
@ -24,11 +24,13 @@ class PhysicalMemory {
|
||||||
PhysicalMemory() {}
|
PhysicalMemory() {}
|
||||||
virtual ~PhysicalMemory() {}
|
virtual ~PhysicalMemory() {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool Alloc(u64 searchStart, u64 searchEnd, u64 len, u64 alignment, u64* physAddrOut, int memoryType);
|
bool Alloc(u64 searchStart, u64 searchEnd, u64 len, u64 alignment, u64* physAddrOut,
|
||||||
bool Map(u64 virtual_addr, u64 phys_addr, u64 len, int prot, VirtualMemory::MemoryMode cpu_mode, GPU::MemoryMode gpu_mode);
|
int memoryType);
|
||||||
|
bool Map(u64 virtual_addr, u64 phys_addr, u64 len, int prot, VirtualMemory::MemoryMode cpu_mode,
|
||||||
|
GPU::MemoryMode gpu_mode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<AllocatedBlock> m_allocatedBlocks;
|
std::vector<AllocatedBlock> m_allocatedBlocks;
|
||||||
std::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
#include "Util/config.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
#include "core/hle/kernel/cpu_management.h"
|
#include "core/hle/kernel/cpu_management.h"
|
||||||
#include "core/hle/libraries/libs.h"
|
#include "core/hle/libraries/libs.h"
|
||||||
#include "Util/config.h"
|
|
||||||
|
|
||||||
namespace Core::Kernel {
|
namespace Core::Kernel {
|
||||||
|
|
||||||
|
|
|
@ -1,31 +1,36 @@
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
#include "core/hle/kernel/event_queues.h"
|
|
||||||
#include "core/hle/error_codes.h"
|
#include "core/hle/error_codes.h"
|
||||||
|
#include "core/hle/kernel/event_queues.h"
|
||||||
#include "core/hle/libraries/libs.h"
|
#include "core/hle/libraries/libs.h"
|
||||||
|
|
||||||
namespace Core::Kernel {
|
namespace Core::Kernel {
|
||||||
|
|
||||||
constexpr bool log_file_equeues = true; // disable it to disable logging
|
constexpr bool log_file_equeues = true; // disable it to disable logging
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelCreateEqueue(SceKernelEqueue* eq, const char* name) {
|
int PS4_SYSV_ABI sceKernelCreateEqueue(SceKernelEqueue* eq, const char* name) {
|
||||||
PRINT_FUNCTION_NAME();
|
PRINT_FUNCTION_NAME();
|
||||||
|
|
||||||
if (eq == nullptr) {
|
if (eq == nullptr) {
|
||||||
LOG_TRACE_IF(log_file_equeues, "sceKernelCreateEqueue returned SCE_KERNEL_ERROR_EINVAL eq invalid\n");
|
LOG_TRACE_IF(log_file_equeues,
|
||||||
|
"sceKernelCreateEqueue returned SCE_KERNEL_ERROR_EINVAL eq invalid\n");
|
||||||
return SCE_KERNEL_ERROR_EINVAL;
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
if (name == nullptr) {
|
if (name == nullptr) {
|
||||||
LOG_TRACE_IF(log_file_equeues, "sceKernelCreateEqueue returned SCE_KERNEL_ERROR_EFAULT name invalid\n");
|
LOG_TRACE_IF(log_file_equeues,
|
||||||
|
"sceKernelCreateEqueue returned SCE_KERNEL_ERROR_EFAULT name invalid\n");
|
||||||
return SCE_KERNEL_ERROR_EFAULT;
|
return SCE_KERNEL_ERROR_EFAULT;
|
||||||
}
|
}
|
||||||
if (name == NULL) {
|
if (name == NULL) {
|
||||||
LOG_TRACE_IF(log_file_equeues, "sceKernelCreateEqueue returned SCE_KERNEL_ERROR_EINVAL name is null\n");
|
LOG_TRACE_IF(log_file_equeues,
|
||||||
|
"sceKernelCreateEqueue returned SCE_KERNEL_ERROR_EINVAL name is null\n");
|
||||||
return SCE_KERNEL_ERROR_EINVAL;
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(name) > 31) { // max is 32 including null terminator
|
if (strlen(name) > 31) { // max is 32 including null terminator
|
||||||
LOG_TRACE_IF(log_file_equeues, "sceKernelCreateEqueue returned SCE_KERNEL_ERROR_ENAMETOOLONG name size exceeds 32 bytes\n");
|
LOG_TRACE_IF(log_file_equeues,
|
||||||
|
"sceKernelCreateEqueue returned SCE_KERNEL_ERROR_ENAMETOOLONG name size "
|
||||||
|
"exceeds 32 bytes\n");
|
||||||
return SCE_KERNEL_ERROR_ENAMETOOLONG;
|
return SCE_KERNEL_ERROR_ENAMETOOLONG;
|
||||||
}
|
}
|
||||||
*eq = new EqueueInternal;
|
*eq = new EqueueInternal;
|
||||||
|
@ -35,8 +40,8 @@ int PS4_SYSV_ABI sceKernelCreateEqueue(SceKernelEqueue* eq, const char* name) {
|
||||||
return SCE_OK;
|
return SCE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev,
|
int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int num, int* out,
|
||||||
int num, int* out, SceKernelUseconds* timo) {
|
SceKernelUseconds* timo) {
|
||||||
PRINT_FUNCTION_NAME();
|
PRINT_FUNCTION_NAME();
|
||||||
|
|
||||||
if (eq == nullptr) {
|
if (eq == nullptr) {
|
||||||
|
@ -51,7 +56,7 @@ int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev,
|
||||||
return SCE_KERNEL_ERROR_EINVAL;
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timo == nullptr) { // wait until an event arrives without timing out
|
if (timo == nullptr) { // wait until an event arrives without timing out
|
||||||
*out = eq->waitForEvents(ev, num, 0);
|
*out = eq->waitForEvents(ev, num, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ using SceKernelUseconds = u32;
|
||||||
using SceKernelEqueue = EqueueInternal*;
|
using SceKernelEqueue = EqueueInternal*;
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelCreateEqueue(SceKernelEqueue* eq, const char* name);
|
int PS4_SYSV_ABI sceKernelCreateEqueue(SceKernelEqueue* eq, const char* name);
|
||||||
int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev,
|
int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int num, int* out,
|
||||||
int num, int* out, SceKernelUseconds *timo);
|
SceKernelUseconds* timo);
|
||||||
|
|
||||||
} // namespace Core::Kernel
|
} // namespace Core::Kernel
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <magic_enum.hpp>
|
|
||||||
#include <core/PS4/GPU/gpu_memory.h>
|
#include <core/PS4/GPU/gpu_memory.h>
|
||||||
#include <core/virtual_memory.h>
|
#include <core/virtual_memory.h>
|
||||||
#include "common/log.h"
|
#include <magic_enum.hpp>
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
|
#include "common/log.h"
|
||||||
#include "common/singleton.h"
|
#include "common/singleton.h"
|
||||||
|
#include "core/hle/error_codes.h"
|
||||||
|
#include "core/hle/kernel/Objects/physical_memory.h"
|
||||||
#include "core/hle/kernel/memory_management.h"
|
#include "core/hle/kernel/memory_management.h"
|
||||||
#include "core/hle/libraries/libs.h"
|
#include "core/hle/libraries/libs.h"
|
||||||
#include "core/hle/kernel/Objects/physical_memory.h"
|
|
||||||
#include "core/hle/error_codes.h"
|
|
||||||
|
|
||||||
namespace Core::Kernel {
|
namespace Core::Kernel {
|
||||||
|
|
||||||
constexpr bool log_file_memory = true; // disable it to disable logging
|
constexpr bool log_file_memory = true; // disable it to disable logging
|
||||||
|
|
||||||
bool is16KBAligned(u64 n) {
|
bool is16KBAligned(u64 n) {
|
||||||
return ((n % (16ull * 1024) == 0));
|
return ((n % (16ull * 1024) == 0));
|
||||||
|
@ -23,24 +23,31 @@ u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize() {
|
||||||
return SCE_KERNEL_MAIN_DMEM_SIZE;
|
return SCE_KERNEL_MAIN_DMEM_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len, u64 alignment, int memoryType, s64* physAddrOut) {
|
int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len,
|
||||||
|
u64 alignment, int memoryType, s64* physAddrOut) {
|
||||||
PRINT_FUNCTION_NAME();
|
PRINT_FUNCTION_NAME();
|
||||||
|
|
||||||
if (searchStart < 0 || searchEnd <= searchStart) {
|
if (searchStart < 0 || searchEnd <= searchStart) {
|
||||||
LOG_TRACE_IF(log_file_memory, "sceKernelAllocateDirectMemory returned SCE_KERNEL_ERROR_EINVAL searchStart,searchEnd invalid\n");
|
LOG_TRACE_IF(log_file_memory, "sceKernelAllocateDirectMemory returned "
|
||||||
|
"SCE_KERNEL_ERROR_EINVAL searchStart,searchEnd invalid\n");
|
||||||
return SCE_KERNEL_ERROR_EINVAL;
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
bool isInRange = (searchStart < len && searchEnd > len);
|
bool isInRange = (searchStart < len && searchEnd > len);
|
||||||
if (len <= 0 || !is16KBAligned(len) || !isInRange) {
|
if (len <= 0 || !is16KBAligned(len) || !isInRange) {
|
||||||
LOG_TRACE_IF(log_file_memory, "sceKernelAllocateDirectMemory returned SCE_KERNEL_ERROR_EINVAL memory range invalid\n");
|
LOG_TRACE_IF(log_file_memory, "sceKernelAllocateDirectMemory returned "
|
||||||
|
"SCE_KERNEL_ERROR_EINVAL memory range invalid\n");
|
||||||
return SCE_KERNEL_ERROR_EINVAL;
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
if ((alignment != 0 || is16KBAligned(alignment)) && !std::has_single_bit(alignment)) {
|
if ((alignment != 0 || is16KBAligned(alignment)) && !std::has_single_bit(alignment)) {
|
||||||
LOG_TRACE_IF(log_file_memory, "sceKernelAllocateDirectMemory returned SCE_KERNEL_ERROR_EINVAL alignment invalid\n");
|
LOG_TRACE_IF(
|
||||||
|
log_file_memory,
|
||||||
|
"sceKernelAllocateDirectMemory returned SCE_KERNEL_ERROR_EINVAL alignment invalid\n");
|
||||||
return SCE_KERNEL_ERROR_EINVAL;
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
if (physAddrOut == nullptr) {
|
if (physAddrOut == nullptr) {
|
||||||
LOG_TRACE_IF(log_file_memory, "sceKernelAllocateDirectMemory returned SCE_KERNEL_ERROR_EINVAL physAddrOut is null\n");
|
LOG_TRACE_IF(
|
||||||
|
log_file_memory,
|
||||||
|
"sceKernelAllocateDirectMemory returned SCE_KERNEL_ERROR_EINVAL physAddrOut is null\n");
|
||||||
return SCE_KERNEL_ERROR_EINVAL;
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
auto memtype = magic_enum::enum_cast<MemoryTypes>(memoryType);
|
auto memtype = magic_enum::enum_cast<MemoryTypes>(memoryType);
|
||||||
|
@ -53,8 +60,10 @@ int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u
|
||||||
|
|
||||||
u64 physical_addr = 0;
|
u64 physical_addr = 0;
|
||||||
auto* physical_memory = Common::Singleton<PhysicalMemory>::Instance();
|
auto* physical_memory = Common::Singleton<PhysicalMemory>::Instance();
|
||||||
if (!physical_memory->Alloc(searchStart, searchEnd, len, alignment, &physical_addr, memoryType)) {
|
if (!physical_memory->Alloc(searchStart, searchEnd, len, alignment, &physical_addr,
|
||||||
LOG_TRACE_IF(log_file_memory, "sceKernelAllocateDirectMemory returned SCE_KERNEL_ERROR_EAGAIN can't allocate physical memory\n");
|
memoryType)) {
|
||||||
|
LOG_TRACE_IF(log_file_memory, "sceKernelAllocateDirectMemory returned "
|
||||||
|
"SCE_KERNEL_ERROR_EAGAIN can't allocate physical memory\n");
|
||||||
return SCE_KERNEL_ERROR_EAGAIN;
|
return SCE_KERNEL_ERROR_EAGAIN;
|
||||||
}
|
}
|
||||||
*physAddrOut = static_cast<s64>(physical_addr);
|
*physAddrOut = static_cast<s64>(physical_addr);
|
||||||
|
@ -62,19 +71,24 @@ int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u
|
||||||
return SCE_OK;
|
return SCE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int flags, s64 directMemoryStart, u64 alignment) {
|
int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int flags,
|
||||||
|
s64 directMemoryStart, u64 alignment) {
|
||||||
PRINT_FUNCTION_NAME();
|
PRINT_FUNCTION_NAME();
|
||||||
if (len == 0 || !is16KBAligned(len)) {
|
if (len == 0 || !is16KBAligned(len)) {
|
||||||
LOG_TRACE_IF(log_file_memory, "sceKernelMapDirectMemory returned SCE_KERNEL_ERROR_EINVAL len invalid\n");
|
LOG_TRACE_IF(log_file_memory,
|
||||||
|
"sceKernelMapDirectMemory returned SCE_KERNEL_ERROR_EINVAL len invalid\n");
|
||||||
return SCE_KERNEL_ERROR_EINVAL;
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
if (!is16KBAligned(directMemoryStart)) {
|
if (!is16KBAligned(directMemoryStart)) {
|
||||||
LOG_TRACE_IF(log_file_memory, "sceKernelMapDirectMemory returned SCE_KERNEL_ERROR_EINVAL directMemoryStart invalid\n");
|
LOG_TRACE_IF(log_file_memory, "sceKernelMapDirectMemory returned SCE_KERNEL_ERROR_EINVAL "
|
||||||
|
"directMemoryStart invalid\n");
|
||||||
return SCE_KERNEL_ERROR_EINVAL;
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
if (alignment != 0) {
|
if (alignment != 0) {
|
||||||
if ((!std::has_single_bit(alignment) && !is16KBAligned(alignment))) {
|
if ((!std::has_single_bit(alignment) && !is16KBAligned(alignment))) {
|
||||||
LOG_TRACE_IF(log_file_memory, "sceKernelMapDirectMemory returned SCE_KERNEL_ERROR_EINVAL alignment invalid\n");
|
LOG_TRACE_IF(
|
||||||
|
log_file_memory,
|
||||||
|
"sceKernelMapDirectMemory returned SCE_KERNEL_ERROR_EINVAL alignment invalid\n");
|
||||||
return SCE_KERNEL_ERROR_EINVAL;
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,12 +103,13 @@ int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int fl
|
||||||
GPU::MemoryMode gpu_mode = GPU::MemoryMode::NoAccess;
|
GPU::MemoryMode gpu_mode = GPU::MemoryMode::NoAccess;
|
||||||
|
|
||||||
switch (prot) {
|
switch (prot) {
|
||||||
case 0x32:
|
case 0x32:
|
||||||
case 0x33: // SCE_KERNEL_PROT_CPU_READ|SCE_KERNEL_PROT_CPU_WRITE|SCE_KERNEL_PROT_GPU_READ|SCE_KERNEL_PROT_GPU_ALL
|
case 0x33: // SCE_KERNEL_PROT_CPU_READ|SCE_KERNEL_PROT_CPU_WRITE|SCE_KERNEL_PROT_GPU_READ|SCE_KERNEL_PROT_GPU_ALL
|
||||||
cpu_mode = VirtualMemory::MemoryMode::ReadWrite;
|
cpu_mode = VirtualMemory::MemoryMode::ReadWrite;
|
||||||
gpu_mode = GPU::MemoryMode::ReadWrite;
|
gpu_mode = GPU::MemoryMode::ReadWrite;
|
||||||
break;
|
break;
|
||||||
default: BREAKPOINT();
|
default:
|
||||||
|
BREAKPOINT();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto in_addr = reinterpret_cast<u64>(*addr);
|
auto in_addr = reinterpret_cast<u64>(*addr);
|
||||||
|
@ -106,7 +121,7 @@ int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int fl
|
||||||
LOG_INFO_IF(log_file_memory, "in_addr = {:#x}\n", in_addr);
|
LOG_INFO_IF(log_file_memory, "in_addr = {:#x}\n", in_addr);
|
||||||
LOG_INFO_IF(log_file_memory, "out_addr = {:#x}\n", out_addr);
|
LOG_INFO_IF(log_file_memory, "out_addr = {:#x}\n", out_addr);
|
||||||
|
|
||||||
*addr = reinterpret_cast<void*>(out_addr); // return out_addr to first functions parameter
|
*addr = reinterpret_cast<void*>(out_addr); // return out_addr to first functions parameter
|
||||||
|
|
||||||
if (out_addr == 0) {
|
if (out_addr == 0) {
|
||||||
return SCE_KERNEL_ERROR_ENOMEM;
|
return SCE_KERNEL_ERROR_ENOMEM;
|
||||||
|
|
|
@ -2,33 +2,35 @@
|
||||||
|
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
||||||
constexpr u64 SCE_KERNEL_MAIN_DMEM_SIZE = 5376_MB; // ~ 6GB
|
constexpr u64 SCE_KERNEL_MAIN_DMEM_SIZE = 5376_MB; // ~ 6GB
|
||||||
|
|
||||||
namespace Core::Kernel {
|
namespace Core::Kernel {
|
||||||
|
|
||||||
enum MemoryTypes : u32 {
|
enum MemoryTypes : u32 {
|
||||||
SCE_KERNEL_WB_ONION = 0, // write - back mode (Onion bus)
|
SCE_KERNEL_WB_ONION = 0, // write - back mode (Onion bus)
|
||||||
SCE_KERNEL_WC_GARLIC = 3, // write - combining mode (Garlic bus)
|
SCE_KERNEL_WC_GARLIC = 3, // write - combining mode (Garlic bus)
|
||||||
SCE_KERNEL_WB_GARLIC = 10 // write - back mode (Garlic bus)
|
SCE_KERNEL_WB_GARLIC = 10 // write - back mode (Garlic bus)
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MemoryFlags : u32 {
|
enum MemoryFlags : u32 {
|
||||||
SCE_KERNEL_MAP_FIXED = 0x0010, // Fixed
|
SCE_KERNEL_MAP_FIXED = 0x0010, // Fixed
|
||||||
SCE_KERNEL_MAP_NO_OVERWRITE = 0x0080,
|
SCE_KERNEL_MAP_NO_OVERWRITE = 0x0080,
|
||||||
SCE_KERNEL_MAP_NO_COALESCE = 0x400000
|
SCE_KERNEL_MAP_NO_COALESCE = 0x400000
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MemoryProtection : u32 {
|
enum MemoryProtection : u32 {
|
||||||
SCE_KERNEL_PROT_CPU_READ = 0x01, // Permit reads from the CPU
|
SCE_KERNEL_PROT_CPU_READ = 0x01, // Permit reads from the CPU
|
||||||
SCE_KERNEL_PROT_CPU_RW = 0x02, // Permit reads/writes from the CPU
|
SCE_KERNEL_PROT_CPU_RW = 0x02, // Permit reads/writes from the CPU
|
||||||
SCE_KERNEL_PROT_CPU_WRITE = 0x02, // Permit reads/writes from the CPU (same)
|
SCE_KERNEL_PROT_CPU_WRITE = 0x02, // Permit reads/writes from the CPU (same)
|
||||||
SCE_KERNEL_PROT_GPU_READ = 0x10, // Permit reads from the GPU
|
SCE_KERNEL_PROT_GPU_READ = 0x10, // Permit reads from the GPU
|
||||||
SCE_KERNEL_PROT_GPU_WRITE = 0x20, // Permit writes from the GPU
|
SCE_KERNEL_PROT_GPU_WRITE = 0x20, // Permit writes from the GPU
|
||||||
SCE_KERNEL_PROT_GPU_RW = 0x30 // Permit reads/writes from the GPU
|
SCE_KERNEL_PROT_GPU_RW = 0x30 // Permit reads/writes from the GPU
|
||||||
};
|
};
|
||||||
|
|
||||||
u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize();
|
u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize();
|
||||||
int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len, u64 alignment, int memoryType, s64* physAddrOut);
|
int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len,
|
||||||
int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int flags, s64 directMemoryStart, u64 alignment);
|
u64 alignment, int memoryType, s64* physAddrOut);
|
||||||
|
int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int flags,
|
||||||
|
s64 directMemoryStart, u64 alignment);
|
||||||
|
|
||||||
} // namespace Core::Kernel
|
} // namespace Core::Kernel
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "common/singleton.h"
|
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
|
#include "common/singleton.h"
|
||||||
#include "core/hle/libraries/libc/libc.h"
|
#include "core/hle/libraries/libc/libc.h"
|
||||||
#include "core/hle/libraries/libc/libc_cxa.h"
|
#include "core/hle/libraries/libc/libc_cxa.h"
|
||||||
#include "core/hle/libraries/libc/libc_math.h"
|
#include "core/hle/libraries/libc/libc_math.h"
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
namespace Core::Libraries::LibC {
|
namespace Core::Libraries::LibC {
|
||||||
|
|
||||||
constexpr bool log_file_libc = true; // disable it to disable logging
|
constexpr bool log_file_libc = true; // disable it to disable logging
|
||||||
static u32 g_need_sceLibc = 1;
|
static u32 g_need_sceLibc = 1;
|
||||||
|
|
||||||
using cxa_destructor_func_t = void (*)(void*);
|
using cxa_destructor_func_t = void (*)(void*);
|
||||||
|
@ -82,55 +82,73 @@ PS4_SYSV_ABI void* ps4__Znwm(u64 count) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr u16 lowercaseTable[256] = {
|
static constexpr u16 lowercaseTable[256] = {
|
||||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011,
|
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B,
|
||||||
0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020, 0x0021, 0x0022, 0x0023,
|
0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
|
||||||
0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035,
|
0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020, 0x0021, 0x0022, 0x0023,
|
||||||
0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
|
0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
|
||||||
0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079,
|
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B,
|
||||||
0x007A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B,
|
0x003C, 0x003D, 0x003E, 0x003F, 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
|
||||||
0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D,
|
0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x0073,
|
||||||
0x007E, 0x007F, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
|
0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
|
||||||
0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, 0x00A0, 0x00A1,
|
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B,
|
||||||
0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3,
|
0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
|
||||||
0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5,
|
0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, 0x0080, 0x0081, 0x0082, 0x0083,
|
||||||
0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
|
0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
|
||||||
0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9,
|
0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B,
|
||||||
0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB,
|
0x009C, 0x009D, 0x009E, 0x009F, 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
|
||||||
|
0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3,
|
||||||
|
0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
|
||||||
|
0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB,
|
||||||
|
0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
|
||||||
|
0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0, 0x00E1, 0x00E2, 0x00E3,
|
||||||
|
0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
|
||||||
|
0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB,
|
||||||
0x00FC, 0x00FD, 0x00FE, 0x00FF,
|
0x00FC, 0x00FD, 0x00FE, 0x00FF,
|
||||||
};
|
};
|
||||||
|
|
||||||
const PS4_SYSV_ABI u16* ps4__Getptolower() { return &lowercaseTable[0]; }
|
const PS4_SYSV_ABI u16* ps4__Getptolower() {
|
||||||
|
return &lowercaseTable[0];
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr u16 uppercaseTable[256] = {
|
static constexpr u16 uppercaseTable[256] = {
|
||||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011,
|
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B,
|
||||||
0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020, 0x0021, 0x0022, 0x0023,
|
0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
|
||||||
0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035,
|
0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020, 0x0021, 0x0022, 0x0023,
|
||||||
0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
|
0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
|
||||||
0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059,
|
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B,
|
||||||
0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B,
|
0x003C, 0x003D, 0x003E, 0x003F, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
|
||||||
0x004C, 0x004D, 0x004E, 0x004F, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x007B, 0x007C, 0x007D,
|
0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, 0x0051, 0x0052, 0x0053,
|
||||||
0x007E, 0x007F, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
|
0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
|
||||||
0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, 0x00A0, 0x00A1,
|
0x0060, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B,
|
||||||
0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3,
|
0x004C, 0x004D, 0x004E, 0x004F, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
|
||||||
0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5,
|
0x0058, 0x0059, 0x005A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, 0x0080, 0x0081, 0x0082, 0x0083,
|
||||||
0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
|
0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
|
||||||
0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9,
|
0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B,
|
||||||
0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB,
|
0x009C, 0x009D, 0x009E, 0x009F, 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
|
||||||
|
0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3,
|
||||||
|
0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
|
||||||
|
0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB,
|
||||||
|
0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
|
||||||
|
0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0, 0x00E1, 0x00E2, 0x00E3,
|
||||||
|
0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
|
||||||
|
0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB,
|
||||||
0x00FC, 0x00FD, 0x00FE, 0x00FF,
|
0x00FC, 0x00FD, 0x00FE, 0x00FF,
|
||||||
};
|
};
|
||||||
|
|
||||||
const PS4_SYSV_ABI u16* ps4__Getptoupper() { return &uppercaseTable[0]; }
|
const PS4_SYSV_ABI u16* ps4__Getptoupper() {
|
||||||
|
return &uppercaseTable[0];
|
||||||
|
}
|
||||||
|
|
||||||
namespace CharacterType {
|
namespace CharacterType {
|
||||||
enum : u16 {
|
enum : u16 {
|
||||||
HexDigit = 0x1, // '0'-'9', 'A'-'F', 'a'-'f'
|
HexDigit = 0x1, // '0'-'9', 'A'-'F', 'a'-'f'
|
||||||
Uppercase = 0x2, // 'A'-'Z'
|
Uppercase = 0x2, // 'A'-'Z'
|
||||||
Space = 0x4,
|
Space = 0x4,
|
||||||
Punctuation = 0x08,
|
Punctuation = 0x08,
|
||||||
Lowercase = 0x10, // 'a'-'z'
|
Lowercase = 0x10, // 'a'-'z'
|
||||||
DecimalDigit = 0x20, // '0'-'9'
|
DecimalDigit = 0x20, // '0'-'9'
|
||||||
Control = 0x40, // CR, FF, HT, NL, VT
|
Control = 0x40, // CR, FF, HT, NL, VT
|
||||||
Control2 = 0x80, // BEL, BS, etc
|
Control2 = 0x80, // BEL, BS, etc
|
||||||
ExtraSpace = 0x100,
|
ExtraSpace = 0x100,
|
||||||
ExtraAlphabetic = 0x200,
|
ExtraAlphabetic = 0x200,
|
||||||
ExtraBlank = 0x400
|
ExtraBlank = 0x400
|
||||||
|
@ -170,101 +188,101 @@ static constexpr u16 characterTypeTable[256] = {
|
||||||
CharacterType::Control2,
|
CharacterType::Control2,
|
||||||
CharacterType::Control2,
|
CharacterType::Control2,
|
||||||
CharacterType::Control2,
|
CharacterType::Control2,
|
||||||
CharacterType::Space, //
|
CharacterType::Space, //
|
||||||
CharacterType::Punctuation, // !
|
CharacterType::Punctuation, // !
|
||||||
CharacterType::Punctuation, // "
|
CharacterType::Punctuation, // "
|
||||||
CharacterType::Punctuation, // #
|
CharacterType::Punctuation, // #
|
||||||
CharacterType::Punctuation, // $
|
CharacterType::Punctuation, // $
|
||||||
CharacterType::Punctuation, // %
|
CharacterType::Punctuation, // %
|
||||||
CharacterType::Punctuation, // &
|
CharacterType::Punctuation, // &
|
||||||
CharacterType::Punctuation, // '
|
CharacterType::Punctuation, // '
|
||||||
CharacterType::Punctuation, // (
|
CharacterType::Punctuation, // (
|
||||||
CharacterType::Punctuation, // )
|
CharacterType::Punctuation, // )
|
||||||
CharacterType::Punctuation, // *
|
CharacterType::Punctuation, // *
|
||||||
CharacterType::Punctuation, // +
|
CharacterType::Punctuation, // +
|
||||||
CharacterType::Punctuation, // ,
|
CharacterType::Punctuation, // ,
|
||||||
CharacterType::Punctuation, // -
|
CharacterType::Punctuation, // -
|
||||||
CharacterType::Punctuation, // .
|
CharacterType::Punctuation, // .
|
||||||
CharacterType::Punctuation, // /
|
CharacterType::Punctuation, // /
|
||||||
CharacterType::HexDigit | CharacterType::DecimalDigit, // 0
|
CharacterType::HexDigit | CharacterType::DecimalDigit, // 0
|
||||||
CharacterType::HexDigit | CharacterType::DecimalDigit, // 1
|
CharacterType::HexDigit | CharacterType::DecimalDigit, // 1
|
||||||
CharacterType::HexDigit | CharacterType::DecimalDigit, // 2
|
CharacterType::HexDigit | CharacterType::DecimalDigit, // 2
|
||||||
CharacterType::HexDigit | CharacterType::DecimalDigit, // 3
|
CharacterType::HexDigit | CharacterType::DecimalDigit, // 3
|
||||||
CharacterType::HexDigit | CharacterType::DecimalDigit, // 4
|
CharacterType::HexDigit | CharacterType::DecimalDigit, // 4
|
||||||
CharacterType::HexDigit | CharacterType::DecimalDigit, // 5
|
CharacterType::HexDigit | CharacterType::DecimalDigit, // 5
|
||||||
CharacterType::HexDigit | CharacterType::DecimalDigit, // 6
|
CharacterType::HexDigit | CharacterType::DecimalDigit, // 6
|
||||||
CharacterType::HexDigit | CharacterType::DecimalDigit, // 7
|
CharacterType::HexDigit | CharacterType::DecimalDigit, // 7
|
||||||
CharacterType::HexDigit | CharacterType::DecimalDigit, // 8
|
CharacterType::HexDigit | CharacterType::DecimalDigit, // 8
|
||||||
CharacterType::HexDigit | CharacterType::DecimalDigit, // 9
|
CharacterType::HexDigit | CharacterType::DecimalDigit, // 9
|
||||||
CharacterType::Punctuation, // :
|
CharacterType::Punctuation, // :
|
||||||
CharacterType::Punctuation, // ;
|
CharacterType::Punctuation, // ;
|
||||||
CharacterType::Punctuation, // <
|
CharacterType::Punctuation, // <
|
||||||
CharacterType::Punctuation, // =
|
CharacterType::Punctuation, // =
|
||||||
CharacterType::Punctuation, // >
|
CharacterType::Punctuation, // >
|
||||||
CharacterType::Punctuation, // ?
|
CharacterType::Punctuation, // ?
|
||||||
CharacterType::Punctuation, // @
|
CharacterType::Punctuation, // @
|
||||||
CharacterType::HexDigit | CharacterType::Uppercase, // A
|
CharacterType::HexDigit | CharacterType::Uppercase, // A
|
||||||
CharacterType::HexDigit | CharacterType::Uppercase, // B
|
CharacterType::HexDigit | CharacterType::Uppercase, // B
|
||||||
CharacterType::HexDigit | CharacterType::Uppercase, // C
|
CharacterType::HexDigit | CharacterType::Uppercase, // C
|
||||||
CharacterType::HexDigit | CharacterType::Uppercase, // D
|
CharacterType::HexDigit | CharacterType::Uppercase, // D
|
||||||
CharacterType::HexDigit | CharacterType::Uppercase, // E
|
CharacterType::HexDigit | CharacterType::Uppercase, // E
|
||||||
CharacterType::HexDigit | CharacterType::Uppercase, // F
|
CharacterType::HexDigit | CharacterType::Uppercase, // F
|
||||||
CharacterType::Uppercase, // G
|
CharacterType::Uppercase, // G
|
||||||
CharacterType::Uppercase, // H
|
CharacterType::Uppercase, // H
|
||||||
CharacterType::Uppercase, // I
|
CharacterType::Uppercase, // I
|
||||||
CharacterType::Uppercase, // J
|
CharacterType::Uppercase, // J
|
||||||
CharacterType::Uppercase, // K
|
CharacterType::Uppercase, // K
|
||||||
CharacterType::Uppercase, // L
|
CharacterType::Uppercase, // L
|
||||||
CharacterType::Uppercase, // M
|
CharacterType::Uppercase, // M
|
||||||
CharacterType::Uppercase, // N
|
CharacterType::Uppercase, // N
|
||||||
CharacterType::Uppercase, // O
|
CharacterType::Uppercase, // O
|
||||||
CharacterType::Uppercase, // P
|
CharacterType::Uppercase, // P
|
||||||
CharacterType::Uppercase, // Q
|
CharacterType::Uppercase, // Q
|
||||||
CharacterType::Uppercase, // R
|
CharacterType::Uppercase, // R
|
||||||
CharacterType::Uppercase, // S
|
CharacterType::Uppercase, // S
|
||||||
CharacterType::Uppercase, // T
|
CharacterType::Uppercase, // T
|
||||||
CharacterType::Uppercase, // U
|
CharacterType::Uppercase, // U
|
||||||
CharacterType::Uppercase, // V
|
CharacterType::Uppercase, // V
|
||||||
CharacterType::Uppercase, // W
|
CharacterType::Uppercase, // W
|
||||||
CharacterType::Uppercase, // X
|
CharacterType::Uppercase, // X
|
||||||
CharacterType::Uppercase, // Y
|
CharacterType::Uppercase, // Y
|
||||||
CharacterType::Uppercase, // Z
|
CharacterType::Uppercase, // Z
|
||||||
CharacterType::Punctuation, // [
|
CharacterType::Punctuation, // [
|
||||||
CharacterType::Punctuation, //
|
CharacterType::Punctuation, //
|
||||||
CharacterType::Punctuation, // ]
|
CharacterType::Punctuation, // ]
|
||||||
CharacterType::Punctuation, // ^
|
CharacterType::Punctuation, // ^
|
||||||
CharacterType::Punctuation, // _
|
CharacterType::Punctuation, // _
|
||||||
CharacterType::Punctuation, // `
|
CharacterType::Punctuation, // `
|
||||||
CharacterType::HexDigit | CharacterType::Lowercase, // a
|
CharacterType::HexDigit | CharacterType::Lowercase, // a
|
||||||
CharacterType::HexDigit | CharacterType::Lowercase, // b
|
CharacterType::HexDigit | CharacterType::Lowercase, // b
|
||||||
CharacterType::HexDigit | CharacterType::Lowercase, // c
|
CharacterType::HexDigit | CharacterType::Lowercase, // c
|
||||||
CharacterType::HexDigit | CharacterType::Lowercase, // d
|
CharacterType::HexDigit | CharacterType::Lowercase, // d
|
||||||
CharacterType::HexDigit | CharacterType::Lowercase, // e
|
CharacterType::HexDigit | CharacterType::Lowercase, // e
|
||||||
CharacterType::HexDigit | CharacterType::Lowercase, // f
|
CharacterType::HexDigit | CharacterType::Lowercase, // f
|
||||||
CharacterType::Lowercase, // g
|
CharacterType::Lowercase, // g
|
||||||
CharacterType::Lowercase, // h
|
CharacterType::Lowercase, // h
|
||||||
CharacterType::Lowercase, // i
|
CharacterType::Lowercase, // i
|
||||||
CharacterType::Lowercase, // j
|
CharacterType::Lowercase, // j
|
||||||
CharacterType::Lowercase, // k
|
CharacterType::Lowercase, // k
|
||||||
CharacterType::Lowercase, // l
|
CharacterType::Lowercase, // l
|
||||||
CharacterType::Lowercase, // m
|
CharacterType::Lowercase, // m
|
||||||
CharacterType::Lowercase, // n
|
CharacterType::Lowercase, // n
|
||||||
CharacterType::Lowercase, // o
|
CharacterType::Lowercase, // o
|
||||||
CharacterType::Lowercase, // p
|
CharacterType::Lowercase, // p
|
||||||
CharacterType::Lowercase, // q
|
CharacterType::Lowercase, // q
|
||||||
CharacterType::Lowercase, // r
|
CharacterType::Lowercase, // r
|
||||||
CharacterType::Lowercase, // s
|
CharacterType::Lowercase, // s
|
||||||
CharacterType::Lowercase, // t
|
CharacterType::Lowercase, // t
|
||||||
CharacterType::Lowercase, // u
|
CharacterType::Lowercase, // u
|
||||||
CharacterType::Lowercase, // v
|
CharacterType::Lowercase, // v
|
||||||
CharacterType::Lowercase, // w
|
CharacterType::Lowercase, // w
|
||||||
CharacterType::Lowercase, // x
|
CharacterType::Lowercase, // x
|
||||||
CharacterType::Lowercase, // y
|
CharacterType::Lowercase, // y
|
||||||
CharacterType::Lowercase, // z
|
CharacterType::Lowercase, // z
|
||||||
CharacterType::Punctuation, // {
|
CharacterType::Punctuation, // {
|
||||||
CharacterType::Punctuation, // |
|
CharacterType::Punctuation, // |
|
||||||
CharacterType::Punctuation, // }
|
CharacterType::Punctuation, // }
|
||||||
CharacterType::Punctuation, // ~
|
CharacterType::Punctuation, // ~
|
||||||
CharacterType::Control2,
|
CharacterType::Control2,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
@ -396,7 +414,9 @@ static constexpr u16 characterTypeTable[256] = {
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const PS4_SYSV_ABI u16* ps4__Getpctype() { return &characterTypeTable[0]; }
|
const PS4_SYSV_ABI u16* ps4__Getpctype() {
|
||||||
|
return &characterTypeTable[0];
|
||||||
|
}
|
||||||
|
|
||||||
void libcSymbolsRegister(Loader::SymbolsResolver* sym) {
|
void libcSymbolsRegister(Loader::SymbolsResolver* sym) {
|
||||||
// cxa functions
|
// cxa functions
|
||||||
|
@ -441,7 +461,7 @@ void libcSymbolsRegister(Loader::SymbolsResolver* sym) {
|
||||||
|
|
||||||
// misc
|
// misc
|
||||||
LIB_OBJ("P330P3dFF68", "libc", 1, "libc", 1, 1, &g_need_sceLibc);
|
LIB_OBJ("P330P3dFF68", "libc", 1, "libc", 1, 1, &g_need_sceLibc);
|
||||||
LIB_OBJ("2sWzhYqFH4E","libc", 1, "libc", 1, 1,stdout);
|
LIB_OBJ("2sWzhYqFH4E", "libc", 1, "libc", 1, 1, stdout);
|
||||||
LIB_OBJ("H8AprKeZtNg", "libc", 1, "libc", 1, 1, stderr);
|
LIB_OBJ("H8AprKeZtNg", "libc", 1, "libc", 1, 1, stderr);
|
||||||
LIB_FUNCTION("bzQExy189ZI", "libc", 1, "libc", 1, 1, ps4_init_env);
|
LIB_FUNCTION("bzQExy189ZI", "libc", 1, "libc", 1, 1, ps4_init_env);
|
||||||
LIB_FUNCTION("XKRegsFpEpk", "libc", 1, "libc", 1, 1, ps4_catchReturnFromMain);
|
LIB_FUNCTION("XKRegsFpEpk", "libc", 1, "libc", 1, 1, ps4_catchReturnFromMain);
|
||||||
|
@ -458,4 +478,4 @@ void libcSymbolsRegister(Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("sUP1hBaouOw", "libc", 1, "libc", 1, 1, ps4__Getpctype);
|
LIB_FUNCTION("sUP1hBaouOw", "libc", 1, "libc", 1, 1, ps4__Getpctype);
|
||||||
}
|
}
|
||||||
|
|
||||||
}; // namespace Core::Libraries::LibC
|
}; // namespace Core::Libraries::LibC
|
||||||
|
|
|
@ -8,4 +8,4 @@ namespace Core::Libraries::LibC {
|
||||||
|
|
||||||
void libcSymbolsRegister(Loader::SymbolsResolver* sym);
|
void libcSymbolsRegister(Loader::SymbolsResolver* sym);
|
||||||
|
|
||||||
} // namespace Core::Libraries::LibC
|
} // namespace Core::Libraries::LibC
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
#include "libc_cxa.h"
|
#include "libc_cxa.h"
|
||||||
|
|
||||||
#include "common/log.h"
|
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
|
#include "common/log.h"
|
||||||
|
|
||||||
// adapted from https://opensource.apple.com/source/libcppabi/libcppabi-14/src/cxa_guard.cxx.auto.html
|
// adapted from
|
||||||
|
// https://opensource.apple.com/source/libcppabi/libcppabi-14/src/cxa_guard.cxx.auto.html
|
||||||
|
|
||||||
namespace Core::Libraries::LibC {
|
namespace Core::Libraries::LibC {
|
||||||
|
|
||||||
constexpr bool log_file_cxa = true; // disable it to disable logging
|
constexpr bool log_file_cxa = true; // disable it to disable logging
|
||||||
|
|
||||||
// This file implements the __cxa_guard_* functions as defined at:
|
// This file implements the __cxa_guard_* functions as defined at:
|
||||||
// http://www.codesourcery.com/public/cxx-abi/abi.html
|
// http://www.codesourcery.com/public/cxx-abi/abi.html
|
||||||
|
@ -55,15 +56,25 @@ __attribute__((noinline)) static pthread_mutex_t* guard_mutex() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper functions for getting/setting flags in guard_object
|
// helper functions for getting/setting flags in guard_object
|
||||||
static bool initializerHasRun(u64* guard_object) { return (*((u08*)guard_object) != 0); }
|
static bool initializerHasRun(u64* guard_object) {
|
||||||
|
return (*((u08*)guard_object) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void setInitializerHasRun(u64* guard_object) { *((u08*)guard_object) = 1; }
|
static void setInitializerHasRun(u64* guard_object) {
|
||||||
|
*((u08*)guard_object) = 1;
|
||||||
|
}
|
||||||
|
|
||||||
static bool inUse(u64* guard_object) { return (((u08*)guard_object)[1] != 0); }
|
static bool inUse(u64* guard_object) {
|
||||||
|
return (((u08*)guard_object)[1] != 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void setInUse(u64* guard_object) { ((u08*)guard_object)[1] = 1; }
|
static void setInUse(u64* guard_object) {
|
||||||
|
((u08*)guard_object)[1] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void setNotInUse(u64* guard_object) { ((u08*)guard_object)[1] = 0; }
|
static void setNotInUse(u64* guard_object) {
|
||||||
|
((u08*)guard_object)[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Returns 1 if the caller needs to run the initializer and then either
|
// Returns 1 if the caller needs to run the initializer and then either
|
||||||
|
@ -75,7 +86,8 @@ static void setNotInUse(u64* guard_object) { ((u08*)guard_object)[1] = 0; }
|
||||||
//
|
//
|
||||||
int PS4_SYSV_ABI ps4___cxa_guard_acquire(u64* guard_object) {
|
int PS4_SYSV_ABI ps4___cxa_guard_acquire(u64* guard_object) {
|
||||||
// Double check that the initializer has not already been run
|
// Double check that the initializer has not already been run
|
||||||
if (initializerHasRun(guard_object)) return 0;
|
if (initializerHasRun(guard_object))
|
||||||
|
return 0;
|
||||||
|
|
||||||
// We now need to acquire a lock that allows only one thread
|
// We now need to acquire a lock that allows only one thread
|
||||||
// to run the initializer. If a different thread calls
|
// to run the initializer. If a different thread calls
|
||||||
|
@ -89,7 +101,8 @@ int PS4_SYSV_ABI ps4___cxa_guard_acquire(u64* guard_object) {
|
||||||
|
|
||||||
int result = ::pthread_mutex_lock(guard_mutex());
|
int result = ::pthread_mutex_lock(guard_mutex());
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
LOG_TRACE_IF(log_file_cxa, "__cxa_guard_acquire(): pthread_mutex_lock failed with {}\n", result);
|
LOG_TRACE_IF(log_file_cxa, "__cxa_guard_acquire(): pthread_mutex_lock failed with {}\n",
|
||||||
|
result);
|
||||||
}
|
}
|
||||||
// At this point all other threads will block in __cxa_guard_acquire()
|
// At this point all other threads will block in __cxa_guard_acquire()
|
||||||
|
|
||||||
|
@ -97,7 +110,8 @@ int PS4_SYSV_ABI ps4___cxa_guard_acquire(u64* guard_object) {
|
||||||
if (initializerHasRun(guard_object)) {
|
if (initializerHasRun(guard_object)) {
|
||||||
int result = ::pthread_mutex_unlock(guard_mutex());
|
int result = ::pthread_mutex_unlock(guard_mutex());
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
LOG_TRACE_IF(log_file_cxa, "__cxa_guard_acquire(): pthread_mutex_unlock failed with {}\n", result);
|
LOG_TRACE_IF(log_file_cxa,
|
||||||
|
"__cxa_guard_acquire(): pthread_mutex_unlock failed with {}\n", result);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -107,7 +121,8 @@ int PS4_SYSV_ABI ps4___cxa_guard_acquire(u64* guard_object) {
|
||||||
// But if the same thread can call __cxa_guard_acquire() on the
|
// But if the same thread can call __cxa_guard_acquire() on the
|
||||||
// *same* guard object again, we call abort();
|
// *same* guard object again, we call abort();
|
||||||
if (inUse(guard_object)) {
|
if (inUse(guard_object)) {
|
||||||
LOG_TRACE_IF(log_file_cxa, "__cxa_guard_acquire(): initializer for function local static variable called enclosing function\n");
|
LOG_TRACE_IF(log_file_cxa, "__cxa_guard_acquire(): initializer for function local static "
|
||||||
|
"variable called enclosing function\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark this guard object as being in use
|
// mark this guard object as being in use
|
||||||
|
@ -129,7 +144,8 @@ void PS4_SYSV_ABI ps4___cxa_guard_release(u64* guard_object) {
|
||||||
// release global mutex
|
// release global mutex
|
||||||
int result = ::pthread_mutex_unlock(guard_mutex());
|
int result = ::pthread_mutex_unlock(guard_mutex());
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
LOG_TRACE_IF(log_file_cxa, "__cxa_guard_acquire(): pthread_mutex_unlock failed with {}\n", result);
|
LOG_TRACE_IF(log_file_cxa, "__cxa_guard_acquire(): pthread_mutex_unlock failed with {}\n",
|
||||||
|
result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,11 +155,12 @@ void PS4_SYSV_ABI ps4___cxa_guard_release(u64* guard_object) {
|
||||||
void PS4_SYSV_ABI ps4___cxa_guard_abort(u64* guard_object) {
|
void PS4_SYSV_ABI ps4___cxa_guard_abort(u64* guard_object) {
|
||||||
int result = ::pthread_mutex_unlock(guard_mutex());
|
int result = ::pthread_mutex_unlock(guard_mutex());
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
LOG_TRACE_IF(log_file_cxa, "__cxa_guard_abort(): pthread_mutex_unlock failed with {}\n", result);
|
LOG_TRACE_IF(log_file_cxa, "__cxa_guard_abort(): pthread_mutex_unlock failed with {}\n",
|
||||||
|
result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// now reset state, so possible to try to initialize again
|
// now reset state, so possible to try to initialize again
|
||||||
setNotInUse(guard_object);
|
setNotInUse(guard_object);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core::Libraries::LibC
|
} // namespace Core::Libraries::LibC
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
namespace Core::Libraries::LibC {
|
namespace Core::Libraries::LibC {
|
||||||
|
|
||||||
constexpr bool log_file_libc = true; // disable it to disable logging
|
constexpr bool log_file_libc = true; // disable it to disable logging
|
||||||
|
|
||||||
int PS4_SYSV_ABI ps4_printf(VA_ARGS) {
|
int PS4_SYSV_ABI ps4_printf(VA_ARGS) {
|
||||||
VA_CTX(ctx);
|
VA_CTX(ctx);
|
||||||
|
@ -13,7 +13,7 @@ int PS4_SYSV_ABI ps4_printf(VA_ARGS) {
|
||||||
|
|
||||||
int PS4_SYSV_ABI ps4_fprintf(FILE* file, VA_ARGS) {
|
int PS4_SYSV_ABI ps4_fprintf(FILE* file, VA_ARGS) {
|
||||||
int fd = fileno(file);
|
int fd = fileno(file);
|
||||||
if (fd == 1 || fd == 2) { // output stdout and stderr to console
|
if (fd == 1 || fd == 2) { // output stdout and stderr to console
|
||||||
VA_CTX(ctx);
|
VA_CTX(ctx);
|
||||||
return printf_ctx(&ctx);
|
return printf_ctx(&ctx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include "common/log.h"
|
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
|
#include "common/log.h"
|
||||||
#include "core/hle/libraries/libc/libc_stdlib.h"
|
#include "core/hle/libraries/libc/libc_stdlib.h"
|
||||||
|
|
||||||
namespace Core::Libraries::LibC {
|
namespace Core::Libraries::LibC {
|
||||||
|
|
||||||
constexpr bool log_file_libc = true; // disable it to disable logging
|
constexpr bool log_file_libc = true; // disable it to disable logging
|
||||||
|
|
||||||
void PS4_SYSV_ABI ps4_exit(int code) {
|
void PS4_SYSV_ABI ps4_exit(int code) {
|
||||||
std::exit(code);
|
std::exit(code);
|
||||||
|
@ -35,7 +35,8 @@ int qsort_compair(const void* arg1, const void* arg2) {
|
||||||
return compair_ps4(arg1, arg2);
|
return compair_ps4(arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PS4_SYSV_ABI ps4_qsort(void* ptr, size_t count, size_t size, int(PS4_SYSV_ABI* comp)(const void*, const void*)) {
|
void PS4_SYSV_ABI ps4_qsort(void* ptr, size_t count, size_t size,
|
||||||
|
int(PS4_SYSV_ABI* comp)(const void*, const void*)) {
|
||||||
compair_ps4 = comp;
|
compair_ps4 = comp;
|
||||||
std::qsort(ptr, count, size, qsort_compair);
|
std::qsort(ptr, count, size, qsort_compair);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,8 @@ void PS4_SYSV_ABI ps4_exit(int code);
|
||||||
int PS4_SYSV_ABI ps4_atexit(void (*func)());
|
int PS4_SYSV_ABI ps4_atexit(void (*func)());
|
||||||
void* PS4_SYSV_ABI ps4_malloc(size_t size);
|
void* PS4_SYSV_ABI ps4_malloc(size_t size);
|
||||||
void PS4_SYSV_ABI ps4_free(void* ptr);
|
void PS4_SYSV_ABI ps4_free(void* ptr);
|
||||||
void PS4_SYSV_ABI ps4_qsort(void* ptr, size_t count, size_t size, int(PS4_SYSV_ABI* comp)(const void*, const void*));
|
void PS4_SYSV_ABI ps4_qsort(void* ptr, size_t count, size_t size,
|
||||||
|
int(PS4_SYSV_ABI* comp)(const void*, const void*));
|
||||||
int PS4_SYSV_ABI ps4_rand();
|
int PS4_SYSV_ABI ps4_rand();
|
||||||
|
|
||||||
} // namespace Core::Libraries::LibC
|
} // namespace Core::Libraries::LibC
|
||||||
|
|
|
@ -140,7 +140,9 @@ static inline unsigned int _strlen(const char* str) {
|
||||||
|
|
||||||
// internal test if char is a digit (0-9)
|
// internal test if char is a digit (0-9)
|
||||||
// \return true if char is a digit
|
// \return true if char is a digit
|
||||||
static inline bool _is_digit(char ch) { return (ch >= '0') && (ch <= '9'); }
|
static inline bool _is_digit(char ch) {
|
||||||
|
return (ch >= '0') && (ch <= '9');
|
||||||
|
}
|
||||||
|
|
||||||
// internal ASCII string to unsigned int conversion
|
// internal ASCII string to unsigned int conversion
|
||||||
static inline unsigned int _atoi(const char** str) {
|
static inline unsigned int _atoi(const char** str) {
|
||||||
|
@ -152,7 +154,8 @@ static inline unsigned int _atoi(const char** str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// internal itoa format
|
// internal itoa format
|
||||||
static inline size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base,
|
static inline size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen,
|
||||||
|
char* buf, size_t len, bool negative, unsigned int base,
|
||||||
unsigned int prec, unsigned int width, unsigned int flags) {
|
unsigned int prec, unsigned int width, unsigned int flags) {
|
||||||
const size_t start_idx = idx;
|
const size_t start_idx = idx;
|
||||||
|
|
||||||
|
@ -160,7 +163,8 @@ static inline size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, si
|
||||||
while (!(flags & FLAGS_LEFT) && (len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
while (!(flags & FLAGS_LEFT) && (len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||||
buf[len++] = '0';
|
buf[len++] = '0';
|
||||||
}
|
}
|
||||||
while (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
|
while (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD) && (len < width) &&
|
||||||
|
(len < PRINTF_NTOA_BUFFER_SIZE)) {
|
||||||
buf[len++] = '0';
|
buf[len++] = '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +195,7 @@ static inline size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, si
|
||||||
if (negative) {
|
if (negative) {
|
||||||
buf[len++] = '-';
|
buf[len++] = '-';
|
||||||
} else if (flags & FLAGS_PLUS) {
|
} else if (flags & FLAGS_PLUS) {
|
||||||
buf[len++] = '+'; // ignore the space if the '+' exists
|
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||||
} else if (flags & FLAGS_SPACE) {
|
} else if (flags & FLAGS_SPACE) {
|
||||||
buf[len++] = ' ';
|
buf[len++] = ' ';
|
||||||
}
|
}
|
||||||
|
@ -220,7 +224,8 @@ static inline size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, si
|
||||||
}
|
}
|
||||||
|
|
||||||
// internal itoa for 'long' type
|
// internal itoa for 'long' type
|
||||||
static inline size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base,
|
static inline size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen,
|
||||||
|
unsigned long value, bool negative, unsigned long base,
|
||||||
unsigned int prec, unsigned int width, unsigned int flags) {
|
unsigned int prec, unsigned int width, unsigned int flags) {
|
||||||
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||||
size_t len = 0U;
|
size_t len = 0U;
|
||||||
|
@ -229,18 +234,22 @@ static inline size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size
|
||||||
if (!(flags & FLAGS_PRECISION) || value) {
|
if (!(flags & FLAGS_PRECISION) || value) {
|
||||||
do {
|
do {
|
||||||
const char digit = (char)(value % base);
|
const char digit = (char)(value % base);
|
||||||
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
buf[len++] =
|
||||||
|
digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||||
value /= base;
|
value /= base;
|
||||||
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
|
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec,
|
||||||
|
width, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
// internal itoa for 'long long' type
|
// internal itoa for 'long long' type
|
||||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||||
static inline size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative,
|
static inline size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen,
|
||||||
unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) {
|
unsigned long long value, bool negative,
|
||||||
|
unsigned long long base, unsigned int prec, unsigned int width,
|
||||||
|
unsigned int flags) {
|
||||||
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
char buf[PRINTF_NTOA_BUFFER_SIZE];
|
||||||
size_t len = 0U;
|
size_t len = 0U;
|
||||||
|
|
||||||
|
@ -248,18 +257,20 @@ static inline size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx,
|
||||||
if (!(flags & FLAGS_PRECISION) || value) {
|
if (!(flags & FLAGS_PRECISION) || value) {
|
||||||
do {
|
do {
|
||||||
const char digit = (char)(value % base);
|
const char digit = (char)(value % base);
|
||||||
buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
buf[len++] =
|
||||||
|
digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
|
||||||
value /= base;
|
value /= base;
|
||||||
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
|
return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec,
|
||||||
|
width, flags);
|
||||||
}
|
}
|
||||||
#endif // PRINTF_SUPPORT_LONG_LONG
|
#endif // PRINTF_SUPPORT_LONG_LONG
|
||||||
|
|
||||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||||
static inline size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width,
|
static inline size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value,
|
||||||
unsigned int flags) {
|
unsigned int prec, unsigned int width, unsigned int flags) {
|
||||||
char buf[PRINTF_FTOA_BUFFER_SIZE];
|
char buf[PRINTF_FTOA_BUFFER_SIZE];
|
||||||
size_t len = 0U;
|
size_t len = 0U;
|
||||||
double diff = 0.0;
|
double diff = 0.0;
|
||||||
|
@ -268,7 +279,8 @@ static inline size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t ma
|
||||||
const double thres_max = (double)0x7FFFFFFF;
|
const double thres_max = (double)0x7FFFFFFF;
|
||||||
|
|
||||||
// powers of 10
|
// powers of 10
|
||||||
static const double pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
|
static const double pow10[] = {1, 10, 100, 1000, 10000,
|
||||||
|
100000, 1000000, 10000000, 100000000, 1000000000};
|
||||||
|
|
||||||
// test for negative
|
// test for negative
|
||||||
bool negative = false;
|
bool negative = false;
|
||||||
|
@ -304,8 +316,9 @@ static inline size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t ma
|
||||||
++frac;
|
++frac;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TBD: for very large numbers switch back to native sprintf for exponentials. Anyone want to write code to replace this?
|
// TBD: for very large numbers switch back to native sprintf for exponentials. Anyone want to
|
||||||
// Normal printf behavior is to print EVERY whole number digit which can be 100s of characters overflowing your buffers == bad
|
// write code to replace this? Normal printf behavior is to print EVERY whole number digit which
|
||||||
|
// can be 100s of characters overflowing your buffers == bad
|
||||||
if (value > thres_max) {
|
if (value > thres_max) {
|
||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
@ -349,7 +362,8 @@ static inline size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t ma
|
||||||
}
|
}
|
||||||
|
|
||||||
// pad leading zeros
|
// pad leading zeros
|
||||||
while (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
|
while (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD) && (len < width) &&
|
||||||
|
(len < PRINTF_FTOA_BUFFER_SIZE)) {
|
||||||
buf[len++] = '0';
|
buf[len++] = '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,7 +375,7 @@ static inline size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t ma
|
||||||
if (negative) {
|
if (negative) {
|
||||||
buf[len++] = '-';
|
buf[len++] = '-';
|
||||||
} else if (flags & FLAGS_PLUS) {
|
} else if (flags & FLAGS_PLUS) {
|
||||||
buf[len++] = '+'; // ignore the space if the '+' exists
|
buf[len++] = '+'; // ignore the space if the '+' exists
|
||||||
} else if (flags & FLAGS_SPACE) {
|
} else if (flags & FLAGS_SPACE) {
|
||||||
buf[len++] = ' ';
|
buf[len++] = ' ';
|
||||||
}
|
}
|
||||||
|
@ -388,7 +402,7 @@ static inline size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t ma
|
||||||
|
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
#endif // PRINTF_SUPPORT_FLOAT
|
#endif // PRINTF_SUPPORT_FLOAT
|
||||||
|
|
||||||
// internal vsnprintf
|
// internal vsnprintf
|
||||||
static inline int _vsnprintf(out_fct_type out, char* buffer, const char* format, VaList* va_list) {
|
static inline int _vsnprintf(out_fct_type out, char* buffer, const char* format, VaList* va_list) {
|
||||||
|
@ -417,32 +431,34 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const char* format,
|
||||||
flags = 0U;
|
flags = 0U;
|
||||||
do {
|
do {
|
||||||
switch (*format) {
|
switch (*format) {
|
||||||
case '0':
|
case '0':
|
||||||
flags |= FLAGS_ZEROPAD;
|
flags |= FLAGS_ZEROPAD;
|
||||||
format++;
|
format++;
|
||||||
n = 1U;
|
n = 1U;
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
flags |= FLAGS_LEFT;
|
flags |= FLAGS_LEFT;
|
||||||
format++;
|
format++;
|
||||||
n = 1U;
|
n = 1U;
|
||||||
break;
|
break;
|
||||||
case '+':
|
case '+':
|
||||||
flags |= FLAGS_PLUS;
|
flags |= FLAGS_PLUS;
|
||||||
format++;
|
format++;
|
||||||
n = 1U;
|
n = 1U;
|
||||||
break;
|
break;
|
||||||
case ' ':
|
case ' ':
|
||||||
flags |= FLAGS_SPACE;
|
flags |= FLAGS_SPACE;
|
||||||
format++;
|
format++;
|
||||||
n = 1U;
|
n = 1U;
|
||||||
break;
|
break;
|
||||||
case '#':
|
case '#':
|
||||||
flags |= FLAGS_HASH;
|
flags |= FLAGS_HASH;
|
||||||
format++;
|
format++;
|
||||||
n = 1U;
|
n = 1U;
|
||||||
break;
|
break;
|
||||||
default: n = 0U; break;
|
default:
|
||||||
|
n = 0U;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} while (n);
|
} while (n);
|
||||||
|
|
||||||
|
@ -451,10 +467,10 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const char* format,
|
||||||
if (_is_digit(*format)) {
|
if (_is_digit(*format)) {
|
||||||
width = _atoi(&format);
|
width = _atoi(&format);
|
||||||
} else if (*format == '*') {
|
} else if (*format == '*') {
|
||||||
const int w = vaArgInteger(va_list); // const int w = va.next<int>(cpu, mem);
|
const int w = vaArgInteger(va_list); // const int w = va.next<int>(cpu, mem);
|
||||||
|
|
||||||
if (w < 0) {
|
if (w < 0) {
|
||||||
flags |= FLAGS_LEFT; // reverse padding
|
flags |= FLAGS_LEFT; // reverse padding
|
||||||
width = (unsigned int)-w;
|
width = (unsigned int)-w;
|
||||||
} else {
|
} else {
|
||||||
width = (unsigned int)w;
|
width = (unsigned int)w;
|
||||||
|
@ -470,212 +486,234 @@ static inline int _vsnprintf(out_fct_type out, char* buffer, const char* format,
|
||||||
if (_is_digit(*format)) {
|
if (_is_digit(*format)) {
|
||||||
precision = _atoi(&format);
|
precision = _atoi(&format);
|
||||||
} else if (*format == '*') {
|
} else if (*format == '*') {
|
||||||
precision = vaArgInteger(va_list); // precision = (unsigned int)va.next<int>(cpu, mem);
|
precision =
|
||||||
|
vaArgInteger(va_list); // precision = (unsigned int)va.next<int>(cpu, mem);
|
||||||
format++;
|
format++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// evaluate length field
|
// evaluate length field
|
||||||
switch (*format) {
|
switch (*format) {
|
||||||
case 'l':
|
case 'l':
|
||||||
flags |= FLAGS_LONG;
|
flags |= FLAGS_LONG;
|
||||||
|
format++;
|
||||||
|
if (*format == 'l') {
|
||||||
|
flags |= FLAGS_LONG_LONG;
|
||||||
format++;
|
format++;
|
||||||
if (*format == 'l') {
|
}
|
||||||
flags |= FLAGS_LONG_LONG;
|
break;
|
||||||
format++;
|
case 'h':
|
||||||
}
|
flags |= FLAGS_SHORT;
|
||||||
break;
|
format++;
|
||||||
case 'h':
|
if (*format == 'h') {
|
||||||
flags |= FLAGS_SHORT;
|
flags |= FLAGS_CHAR;
|
||||||
format++;
|
format++;
|
||||||
if (*format == 'h') {
|
}
|
||||||
flags |= FLAGS_CHAR;
|
break;
|
||||||
format++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#if defined(PRINTF_SUPPORT_PTRDIFF_T)
|
#if defined(PRINTF_SUPPORT_PTRDIFF_T)
|
||||||
case 't':
|
case 't':
|
||||||
flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||||
format++;
|
format++;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case 'j':
|
case 'j':
|
||||||
flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||||
format++;
|
format++;
|
||||||
break;
|
break;
|
||||||
case 'z':
|
case 'z':
|
||||||
flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
|
||||||
format++;
|
format++;
|
||||||
break;
|
break;
|
||||||
default: break;
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// evaluate specifier
|
// evaluate specifier
|
||||||
switch (*format) {
|
switch (*format) {
|
||||||
case 'd':
|
case 'd':
|
||||||
case 'i':
|
case 'i':
|
||||||
case 'u':
|
case 'u':
|
||||||
case 'x':
|
case 'x':
|
||||||
case 'X':
|
case 'X':
|
||||||
case 'o':
|
case 'o':
|
||||||
case 'b': {
|
case 'b': {
|
||||||
// set the base
|
// set the base
|
||||||
unsigned int base;
|
unsigned int base;
|
||||||
if (*format == 'x' || *format == 'X') {
|
if (*format == 'x' || *format == 'X') {
|
||||||
base = 16U;
|
base = 16U;
|
||||||
} else if (*format == 'o') {
|
} else if (*format == 'o') {
|
||||||
base = 8U;
|
base = 8U;
|
||||||
} else if (*format == 'b') {
|
} else if (*format == 'b') {
|
||||||
base = 2U;
|
base = 2U;
|
||||||
flags &= ~FLAGS_HASH; // no hash for bin format
|
flags &= ~FLAGS_HASH; // no hash for bin format
|
||||||
} else {
|
} else {
|
||||||
base = 10U;
|
base = 10U;
|
||||||
flags &= ~FLAGS_HASH; // no hash for dec format
|
flags &= ~FLAGS_HASH; // no hash for dec format
|
||||||
}
|
|
||||||
// uppercase
|
|
||||||
if (*format == 'X') {
|
|
||||||
flags |= FLAGS_UPPERCASE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no plus or space flag for u, x, X, o, b
|
|
||||||
if ((*format != 'i') && (*format != 'd')) {
|
|
||||||
flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert the integer
|
|
||||||
if ((*format == 'i') || (*format == 'd')) {
|
|
||||||
// signed
|
|
||||||
if (flags & FLAGS_LONG_LONG) {
|
|
||||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
|
||||||
auto value = vaArgLongLong(va_list); // const long long value = va.next<long long>(cpu, mem);
|
|
||||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base,
|
|
||||||
precision, width, flags);
|
|
||||||
#endif
|
|
||||||
} else if (flags & FLAGS_LONG) {
|
|
||||||
auto value = vaArgLong(va_list); // const long value = va.next<long>(cpu, mem);
|
|
||||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width,
|
|
||||||
flags);
|
|
||||||
} else {
|
|
||||||
// const int value = (flags & FLAGS_CHAR) ? (char)va.next<int>(cpu, mem) : (flags & FLAGS_SHORT) ? (short
|
|
||||||
// int)va.next<int>(cpu, mem): va.next<int>(cpu, mem);
|
|
||||||
const int value = (flags & FLAGS_CHAR) ? static_cast<char>(vaArgInteger(va_list))
|
|
||||||
: (flags & FLAGS_SHORT) ? static_cast<int16_t>(vaArgInteger(va_list))
|
|
||||||
: vaArgInteger(va_list);
|
|
||||||
idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width,
|
|
||||||
flags);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// unsigned
|
|
||||||
if (flags & FLAGS_LONG_LONG) {
|
|
||||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
|
||||||
// idx = _ntoa_long_long(out, buffer, idx, maxlen, va.next<unsigned long long>(cpu, mem), false, base, precision, width,
|
|
||||||
// flags);
|
|
||||||
idx =
|
|
||||||
_ntoa_long_long(out, buffer, idx, maxlen, static_cast<u64>(vaArgLongLong(va_list)), false, base, precision, width, flags);
|
|
||||||
#endif
|
|
||||||
} else if (flags & FLAGS_LONG) {
|
|
||||||
// idx = _ntoa_long(out, buffer, idx, maxlen, va.next<unsigned long>(cpu, mem), false, base, precision, width, flags);
|
|
||||||
idx = _ntoa_long(out, buffer, idx, maxlen, static_cast<u32>(vaArgLong(va_list)), false, base, precision, width, flags);
|
|
||||||
} else {
|
|
||||||
// const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va.next<unsigned int>(cpu, mem) : (flags & FLAGS_SHORT) ?
|
|
||||||
// (unsigned short int)va.next<unsigned int>(cpu, mem) : va.next<unsigned int>(cpu, mem);
|
|
||||||
const unsigned int value = (flags & FLAGS_CHAR) ? static_cast<u08>(vaArgInteger(va_list))
|
|
||||||
: (flags & FLAGS_SHORT) ? static_cast<u16>(vaArgInteger(va_list))
|
|
||||||
: static_cast<u32>(vaArgInteger(va_list));
|
|
||||||
idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
format++;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
// uppercase
|
||||||
|
if (*format == 'X') {
|
||||||
|
flags |= FLAGS_UPPERCASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no plus or space flag for u, x, X, o, b
|
||||||
|
if ((*format != 'i') && (*format != 'd')) {
|
||||||
|
flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert the integer
|
||||||
|
if ((*format == 'i') || (*format == 'd')) {
|
||||||
|
// signed
|
||||||
|
if (flags & FLAGS_LONG_LONG) {
|
||||||
|
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||||
|
auto value = vaArgLongLong(
|
||||||
|
va_list); // const long long value = va.next<long long>(cpu, mem);
|
||||||
|
idx = _ntoa_long_long(out, buffer, idx, maxlen,
|
||||||
|
(unsigned long long)(value > 0 ? value : 0 - value),
|
||||||
|
value < 0, base, precision, width, flags);
|
||||||
|
#endif
|
||||||
|
} else if (flags & FLAGS_LONG) {
|
||||||
|
auto value = vaArgLong(va_list); // const long value = va.next<long>(cpu, mem);
|
||||||
|
idx = _ntoa_long(out, buffer, idx, maxlen,
|
||||||
|
(unsigned long)(value > 0 ? value : 0 - value), value < 0,
|
||||||
|
base, precision, width, flags);
|
||||||
|
} else {
|
||||||
|
// const int value = (flags & FLAGS_CHAR) ? (char)va.next<int>(cpu, mem) :
|
||||||
|
// (flags & FLAGS_SHORT) ? (short int)va.next<int>(cpu, mem): va.next<int>(cpu,
|
||||||
|
// mem);
|
||||||
|
const int value =
|
||||||
|
(flags & FLAGS_CHAR) ? static_cast<char>(vaArgInteger(va_list))
|
||||||
|
: (flags & FLAGS_SHORT) ? static_cast<int16_t>(vaArgInteger(va_list))
|
||||||
|
: vaArgInteger(va_list);
|
||||||
|
idx = _ntoa_long(out, buffer, idx, maxlen,
|
||||||
|
(unsigned int)(value > 0 ? value : 0 - value), value < 0, base,
|
||||||
|
precision, width, flags);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// unsigned
|
||||||
|
if (flags & FLAGS_LONG_LONG) {
|
||||||
|
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||||
|
// idx = _ntoa_long_long(out, buffer, idx, maxlen, va.next<unsigned long
|
||||||
|
// long>(cpu, mem), false, base, precision, width, flags);
|
||||||
|
idx = _ntoa_long_long(out, buffer, idx, maxlen,
|
||||||
|
static_cast<u64>(vaArgLongLong(va_list)), false, base,
|
||||||
|
precision, width, flags);
|
||||||
|
#endif
|
||||||
|
} else if (flags & FLAGS_LONG) {
|
||||||
|
// idx = _ntoa_long(out, buffer, idx, maxlen, va.next<unsigned long>(cpu, mem),
|
||||||
|
// false, base, precision, width, flags);
|
||||||
|
idx = _ntoa_long(out, buffer, idx, maxlen, static_cast<u32>(vaArgLong(va_list)),
|
||||||
|
false, base, precision, width, flags);
|
||||||
|
} else {
|
||||||
|
// const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned
|
||||||
|
// char)va.next<unsigned int>(cpu, mem) : (flags & FLAGS_SHORT) ?
|
||||||
|
// (unsigned short int)va.next<unsigned int>(cpu, mem) : va.next<unsigned
|
||||||
|
// int>(cpu, mem);
|
||||||
|
const unsigned int value =
|
||||||
|
(flags & FLAGS_CHAR) ? static_cast<u08>(vaArgInteger(va_list))
|
||||||
|
: (flags & FLAGS_SHORT) ? static_cast<u16>(vaArgInteger(va_list))
|
||||||
|
: static_cast<u32>(vaArgInteger(va_list));
|
||||||
|
idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width,
|
||||||
|
flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
#if defined(PRINTF_SUPPORT_FLOAT)
|
#if defined(PRINTF_SUPPORT_FLOAT)
|
||||||
case 'f':
|
case 'f':
|
||||||
case 'F':
|
case 'F':
|
||||||
// idx = _ftoa(out, buffer, idx, maxlen, va.next<double>(cpu, mem), precision, width, flags);
|
// idx = _ftoa(out, buffer, idx, maxlen, va.next<double>(cpu, mem), precision, width,
|
||||||
idx = _ftoa(out, buffer, idx, maxlen, vaArgDouble(va_list), precision, width, flags);
|
// flags);
|
||||||
format++;
|
idx = _ftoa(out, buffer, idx, maxlen, vaArgDouble(va_list), precision, width, flags);
|
||||||
break;
|
format++;
|
||||||
#endif // PRINTF_SUPPORT_FLOAT
|
break;
|
||||||
case 'c': {
|
#endif // PRINTF_SUPPORT_FLOAT
|
||||||
unsigned int l = 1U;
|
case 'c': {
|
||||||
// pre padding
|
unsigned int l = 1U;
|
||||||
if (!(flags & FLAGS_LEFT)) {
|
// pre padding
|
||||||
while (l++ < width) {
|
if (!(flags & FLAGS_LEFT)) {
|
||||||
out(' ', buffer, idx++, maxlen);
|
while (l++ < width) {
|
||||||
}
|
out(' ', buffer, idx++, maxlen);
|
||||||
}
|
}
|
||||||
// char output
|
|
||||||
// out((char)va.next<int>(cpu, mem), buffer, idx++, maxlen);
|
|
||||||
out(static_cast<char>(vaArgInteger(va_list)), buffer, idx++, maxlen);
|
|
||||||
// post padding
|
|
||||||
if (flags & FLAGS_LEFT) {
|
|
||||||
while (l++ < width) {
|
|
||||||
out(' ', buffer, idx++, maxlen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
format++;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
// char output
|
||||||
case 's': {
|
// out((char)va.next<int>(cpu, mem), buffer, idx++, maxlen);
|
||||||
const char* p = vaArgPtr<const char>(va_list); // const char *p = va.next<Ptr<char>>(cpu, mem).get(mem);
|
out(static_cast<char>(vaArgInteger(va_list)), buffer, idx++, maxlen);
|
||||||
p = p != nullptr ? p : "(null)";
|
// post padding
|
||||||
unsigned int l = _strlen(p);
|
if (flags & FLAGS_LEFT) {
|
||||||
// pre padding
|
while (l++ < width) {
|
||||||
if (flags & FLAGS_PRECISION) {
|
out(' ', buffer, idx++, maxlen);
|
||||||
l = (l < precision ? l : precision);
|
|
||||||
}
|
}
|
||||||
if (!(flags & FLAGS_LEFT)) {
|
|
||||||
while (l++ < width) {
|
|
||||||
out(' ', buffer, idx++, maxlen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// string output
|
|
||||||
while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
|
|
||||||
out(*(p++), buffer, idx++, maxlen);
|
|
||||||
}
|
|
||||||
// post padding
|
|
||||||
if (flags & FLAGS_LEFT) {
|
|
||||||
while (l++ < width) {
|
|
||||||
out(' ', buffer, idx++, maxlen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
format++;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'p': {
|
case 's': {
|
||||||
width = sizeof(void*) * 2U;
|
const char* p = vaArgPtr<const char>(
|
||||||
flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
|
va_list); // const char *p = va.next<Ptr<char>>(cpu, mem).get(mem);
|
||||||
|
p = p != nullptr ? p : "(null)";
|
||||||
|
unsigned int l = _strlen(p);
|
||||||
|
// pre padding
|
||||||
|
if (flags & FLAGS_PRECISION) {
|
||||||
|
l = (l < precision ? l : precision);
|
||||||
|
}
|
||||||
|
if (!(flags & FLAGS_LEFT)) {
|
||||||
|
while (l++ < width) {
|
||||||
|
out(' ', buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// string output
|
||||||
|
while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
|
||||||
|
out(*(p++), buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
// post padding
|
||||||
|
if (flags & FLAGS_LEFT) {
|
||||||
|
while (l++ < width) {
|
||||||
|
out(' ', buffer, idx++, maxlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'p': {
|
||||||
|
width = sizeof(void*) * 2U;
|
||||||
|
flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
|
||||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||||
const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
|
const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
|
||||||
if (is_ll) {
|
if (is_ll) {
|
||||||
// idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va.next<Ptr<void>>(cpu, mem).address(), false, 16U, precision,
|
// idx = _ntoa_long_long(out, buffer, idx, maxlen,
|
||||||
// width, flags);
|
// (uintptr_t)va.next<Ptr<void>>(cpu, mem).address(), false, 16U, precision, width,
|
||||||
idx = _ntoa_long_long(out, buffer, idx, maxlen, reinterpret_cast<uintptr_t>(vaArgPtr<void>(va_list)), false, 16U, precision,
|
// flags);
|
||||||
width, flags);
|
idx = _ntoa_long_long(out, buffer, idx, maxlen,
|
||||||
} else {
|
reinterpret_cast<uintptr_t>(vaArgPtr<void>(va_list)), false,
|
||||||
|
16U, precision, width, flags);
|
||||||
|
} else {
|
||||||
#endif
|
#endif
|
||||||
// idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va.next<Ptr<void>>(cpu, mem).address()), false, 16U,
|
// idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned
|
||||||
// precision, width, flags);
|
// long)((uintptr_t)va.next<Ptr<void>>(cpu, mem).address()), false, 16U, precision,
|
||||||
idx = _ntoa_long(out, buffer, idx, maxlen, static_cast<uint32_t>(reinterpret_cast<uintptr_t>(vaArgPtr<void>(va_list))), false,
|
// width, flags);
|
||||||
16U, precision, width, flags);
|
idx = _ntoa_long(
|
||||||
|
out, buffer, idx, maxlen,
|
||||||
|
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(vaArgPtr<void>(va_list))),
|
||||||
|
false, 16U, precision, width, flags);
|
||||||
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
#if defined(PRINTF_SUPPORT_LONG_LONG)
|
||||||
}
|
|
||||||
#endif
|
|
||||||
format++;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case '%':
|
case '%':
|
||||||
out('%', buffer, idx++, maxlen);
|
out('%', buffer, idx++, maxlen);
|
||||||
format++;
|
format++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
out(*format, buffer, idx++, maxlen);
|
out(*format, buffer, idx++, maxlen);
|
||||||
format++;
|
format++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -700,4 +738,4 @@ static int vsnprintf_ctx(char* s, size_t n, const char* format, VaList* arg) {
|
||||||
std::strcpy(s, buffer);
|
std::strcpy(s, buffer);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
} // namespace Core::Libraries::LibC
|
} // namespace Core::Libraries::LibC
|
||||||
|
|
|
@ -1,29 +1,30 @@
|
||||||
#include "common/types.h"
|
|
||||||
#include <xmmintrin.h>
|
#include <xmmintrin.h>
|
||||||
|
#include "common/types.h"
|
||||||
|
|
||||||
#define VA_ARGS \
|
#define VA_ARGS \
|
||||||
uint64_t rdi, uint64_t rsi, uint64_t rdx, uint64_t rcx, uint64_t r8, uint64_t r9, uint64_t overflow_arg_area, __m128 xmm0, __m128 xmm1, \
|
uint64_t rdi, uint64_t rsi, uint64_t rdx, uint64_t rcx, uint64_t r8, uint64_t r9, \
|
||||||
__m128 xmm2, __m128 xmm3, __m128 xmm4, __m128 xmm5, __m128 xmm6, __m128 xmm7, ...
|
uint64_t overflow_arg_area, __m128 xmm0, __m128 xmm1, __m128 xmm2, __m128 xmm3, \
|
||||||
|
__m128 xmm4, __m128 xmm5, __m128 xmm6, __m128 xmm7, ...
|
||||||
|
|
||||||
#define VA_CTX(ctx) \
|
#define VA_CTX(ctx) \
|
||||||
alignas(16) VaCtx ctx; \
|
alignas(16) VaCtx ctx; \
|
||||||
(ctx).reg_save_area.gp[0] = rdi; \
|
(ctx).reg_save_area.gp[0] = rdi; \
|
||||||
(ctx).reg_save_area.gp[1] = rsi; \
|
(ctx).reg_save_area.gp[1] = rsi; \
|
||||||
(ctx).reg_save_area.gp[2] = rdx; \
|
(ctx).reg_save_area.gp[2] = rdx; \
|
||||||
(ctx).reg_save_area.gp[3] = rcx; \
|
(ctx).reg_save_area.gp[3] = rcx; \
|
||||||
(ctx).reg_save_area.gp[4] = r8; \
|
(ctx).reg_save_area.gp[4] = r8; \
|
||||||
(ctx).reg_save_area.gp[5] = r9; \
|
(ctx).reg_save_area.gp[5] = r9; \
|
||||||
(ctx).reg_save_area.fp[0] = xmm0; \
|
(ctx).reg_save_area.fp[0] = xmm0; \
|
||||||
(ctx).reg_save_area.fp[1] = xmm1; \
|
(ctx).reg_save_area.fp[1] = xmm1; \
|
||||||
(ctx).reg_save_area.fp[2] = xmm2; \
|
(ctx).reg_save_area.fp[2] = xmm2; \
|
||||||
(ctx).reg_save_area.fp[3] = xmm3; \
|
(ctx).reg_save_area.fp[3] = xmm3; \
|
||||||
(ctx).reg_save_area.fp[4] = xmm4; \
|
(ctx).reg_save_area.fp[4] = xmm4; \
|
||||||
(ctx).reg_save_area.fp[5] = xmm5; \
|
(ctx).reg_save_area.fp[5] = xmm5; \
|
||||||
(ctx).reg_save_area.fp[6] = xmm6; \
|
(ctx).reg_save_area.fp[6] = xmm6; \
|
||||||
(ctx).reg_save_area.fp[7] = xmm7; \
|
(ctx).reg_save_area.fp[7] = xmm7; \
|
||||||
(ctx).va_list.reg_save_area = &(ctx).reg_save_area; \
|
(ctx).va_list.reg_save_area = &(ctx).reg_save_area; \
|
||||||
(ctx).va_list.gp_offset = offsetof(VaRegSave, gp); \
|
(ctx).va_list.gp_offset = offsetof(VaRegSave, gp); \
|
||||||
(ctx).va_list.fp_offset = offsetof(VaRegSave, fp); \
|
(ctx).va_list.fp_offset = offsetof(VaRegSave, fp); \
|
||||||
(ctx).va_list.overflow_arg_area = &overflow_arg_area;
|
(ctx).va_list.overflow_arg_area = &overflow_arg_area;
|
||||||
|
|
||||||
namespace Core::Libraries::LibC {
|
namespace Core::Libraries::LibC {
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
#include "common/log.h"
|
#include <common/singleton.h>
|
||||||
|
#include <core/file_sys/fs.h>
|
||||||
|
#include <core/hle/error_codes.h>
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
|
#include "common/log.h"
|
||||||
#include "core/hle/libraries/libkernel/file_system.h"
|
#include "core/hle/libraries/libkernel/file_system.h"
|
||||||
#include "core/hle/libraries/libs.h"
|
#include "core/hle/libraries/libs.h"
|
||||||
#include <core/file_sys/fs.h>
|
|
||||||
#include <common/singleton.h>
|
|
||||||
#include <core/hle/error_codes.h>
|
|
||||||
|
|
||||||
namespace Core::Libraries::LibKernel {
|
namespace Core::Libraries::LibKernel {
|
||||||
|
|
||||||
constexpr bool log_file_fs = true; // disable it to disable logging
|
constexpr bool log_file_fs = true; // disable it to disable logging
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) {
|
int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) {
|
||||||
LOG_INFO_IF(log_file_fs, "sceKernelOpen path = {} flags = {:#x} mode = {:#x}\n", path, flags, mode);
|
LOG_INFO_IF(log_file_fs, "sceKernelOpen path = {} flags = {:#x} mode = {:#x}\n", path, flags,
|
||||||
|
mode);
|
||||||
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||||
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||||
|
|
||||||
|
@ -34,7 +35,7 @@ int PS4_SYSV_ABI posix_open(const char* path, int flags, /* SceKernelMode*/ u16
|
||||||
LOG_INFO_IF(log_file_fs, "posix open redirect to sceKernelOpen\n");
|
LOG_INFO_IF(log_file_fs, "posix open redirect to sceKernelOpen\n");
|
||||||
int result = sceKernelOpen(path, flags, mode);
|
int result = sceKernelOpen(path, flags, mode);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
BREAKPOINT(); // posix calls different only for their return values
|
BREAKPOINT(); // posix calls different only for their return values
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +46,7 @@ size_t PS4_SYSV_ABI _readv(int d, const SceKernelIovec* iov, int iovcnt) {
|
||||||
size_t total_read = 0;
|
size_t total_read = 0;
|
||||||
file->m_mutex.lock();
|
file->m_mutex.lock();
|
||||||
for (int i = 0; i < iovcnt; i++) {
|
for (int i = 0; i < iovcnt; i++) {
|
||||||
total_read += file->f.readBytes(iov[i].iov_base,iov[i].iov_len).second;
|
total_read += file->f.readBytes(iov[i].iov_base, iov[i].iov_len).second;
|
||||||
}
|
}
|
||||||
file->m_mutex.unlock();
|
file->m_mutex.unlock();
|
||||||
return total_read;
|
return total_read;
|
||||||
|
@ -57,7 +58,8 @@ void fileSystemSymbolsRegister(Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("+WRlkKjZvag", "libkernel", 1, "libkernel", 1, 1, _readv);
|
LIB_FUNCTION("+WRlkKjZvag", "libkernel", 1, "libkernel", 1, 1, _readv);
|
||||||
|
|
||||||
// openOrbis (to check if it is valid out of OpenOrbis
|
// openOrbis (to check if it is valid out of OpenOrbis
|
||||||
LIB_FUNCTION("6c3rCVE-fTU", "libkernel", 1, "libkernel", 1, 1, posix_open); // _open shoudld be equal to open function
|
LIB_FUNCTION("6c3rCVE-fTU", "libkernel", 1, "libkernel", 1, 1,
|
||||||
|
posix_open); // _open shoudld be equal to open function
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core::Libraries::LibKernel
|
} // namespace Core::Libraries::LibKernel
|
||||||
|
|
|
@ -9,14 +9,14 @@ class SymbolsResolver;
|
||||||
namespace Core::Libraries::LibKernel {
|
namespace Core::Libraries::LibKernel {
|
||||||
|
|
||||||
struct SceKernelIovec {
|
struct SceKernelIovec {
|
||||||
void *iov_base;
|
void* iov_base;
|
||||||
size_t iov_len;
|
size_t iov_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelOpen(const char *path, int flags, /* SceKernelMode*/ u16 mode);
|
int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, /* SceKernelMode*/ u16 mode);
|
||||||
|
|
||||||
int PS4_SYSV_ABI posix_open(const char *path, int flags, /* SceKernelMode*/ u16 mode);
|
int PS4_SYSV_ABI posix_open(const char* path, int flags, /* SceKernelMode*/ u16 mode);
|
||||||
|
|
||||||
void fileSystemSymbolsRegister(Loader::SymbolsResolver *sym);
|
void fileSystemSymbolsRegister(Loader::SymbolsResolver* sym);
|
||||||
|
|
||||||
} // namespace Core::Libraries::LibKernel
|
} // namespace Core::Libraries::LibKernel
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
#include "core/loader/elf.h"
|
#include "core/loader/elf.h"
|
||||||
|
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
#include <windows.h>
|
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
|
#include <windows.h>
|
||||||
#else
|
#else
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -22,20 +22,26 @@
|
||||||
|
|
||||||
namespace Core::Libraries::LibKernel {
|
namespace Core::Libraries::LibKernel {
|
||||||
|
|
||||||
constexpr bool log_libkernel_file = true; // disable it to disable logging
|
constexpr bool log_libkernel_file = true; // disable it to disable logging
|
||||||
|
|
||||||
static u64 g_stack_chk_guard = 0xDEADBEEF54321ABC; // dummy return
|
static u64 g_stack_chk_guard = 0xDEADBEEF54321ABC; // dummy return
|
||||||
|
|
||||||
int32_t PS4_SYSV_ABI sceKernelReleaseDirectMemory(off_t start, size_t len) {
|
int32_t PS4_SYSV_ABI sceKernelReleaseDirectMemory(off_t start, size_t len) {
|
||||||
BREAKPOINT();
|
BREAKPOINT();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PS4_SYSV_ABI void stack_chk_fail() { BREAKPOINT(); }
|
static PS4_SYSV_ABI void stack_chk_fail() {
|
||||||
|
BREAKPOINT();
|
||||||
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len) { BREAKPOINT(); }
|
int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len) {
|
||||||
|
BREAKPOINT();
|
||||||
|
}
|
||||||
|
|
||||||
void PS4_SYSV_ABI sceKernelUsleep(unsigned int microseconds) { std::this_thread::sleep_for(std::chrono::microseconds(microseconds)); }
|
void PS4_SYSV_ABI sceKernelUsleep(unsigned int microseconds) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::microseconds(microseconds));
|
||||||
|
}
|
||||||
|
|
||||||
struct iovec {
|
struct iovec {
|
||||||
void* iov_base; /* Base address. */
|
void* iov_base; /* Base address. */
|
||||||
|
@ -43,7 +49,8 @@ struct iovec {
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t PS4_SYSV_ABI _writev(int fd, const struct iovec* iov, int iovcn) {
|
size_t PS4_SYSV_ABI _writev(int fd, const struct iovec* iov, int iovcn) {
|
||||||
// weird it gives fd ==0 and writes to stdout , i am not sure if it that is valid (found in openorbis)
|
// weird it gives fd ==0 and writes to stdout , i am not sure if it that is valid (found in
|
||||||
|
// openorbis)
|
||||||
size_t total_written = 0;
|
size_t total_written = 0;
|
||||||
for (int i = 0; i < iovcn; i++) {
|
for (int i = 0; i < iovcn; i++) {
|
||||||
total_written += ::fwrite(iov[i].iov_base, 1, iov[i].iov_len, stdout);
|
total_written += ::fwrite(iov[i].iov_base, 1, iov[i].iov_len, stdout);
|
||||||
|
@ -52,15 +59,18 @@ size_t PS4_SYSV_ABI _writev(int fd, const struct iovec* iov, int iovcn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static thread_local int libc_error;
|
static thread_local int libc_error;
|
||||||
int* PS4_SYSV_ABI __Error() { return &libc_error; }
|
int* PS4_SYSV_ABI __Error() {
|
||||||
|
return &libc_error;
|
||||||
|
}
|
||||||
|
|
||||||
#define PROT_READ 0x1
|
#define PROT_READ 0x1
|
||||||
#define PROT_WRITE 0x2
|
#define PROT_WRITE 0x2
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd, off_t offset, void** res) {
|
int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd, off_t offset,
|
||||||
|
void** res) {
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
PRINT_FUNCTION_NAME();
|
PRINT_FUNCTION_NAME();
|
||||||
if (prot > 3) // READ,WRITE or bitwise READ | WRITE supported
|
if (prot > 3) // READ,WRITE or bitwise READ | WRITE supported
|
||||||
{
|
{
|
||||||
LOG_ERROR_IF(log_libkernel_file, "sceKernelMmap prot ={} not supported\n", prot);
|
LOG_ERROR_IF(log_libkernel_file, "sceKernelMmap prot ={} not supported\n", prot);
|
||||||
}
|
}
|
||||||
|
@ -76,7 +86,8 @@ int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd,
|
||||||
mmap_fd = (HANDLE)_get_osfhandle(fd);
|
mmap_fd = (HANDLE)_get_osfhandle(fd);
|
||||||
h = CreateFileMapping(mmap_fd, NULL, flProtect, 0, end, NULL);
|
h = CreateFileMapping(mmap_fd, NULL, flProtect, 0, end, NULL);
|
||||||
int k = GetLastError();
|
int k = GetLastError();
|
||||||
if (NULL == h) return -1;
|
if (NULL == h)
|
||||||
|
return -1;
|
||||||
DWORD dwDesiredAccess;
|
DWORD dwDesiredAccess;
|
||||||
if (prot & PROT_WRITE)
|
if (prot & PROT_WRITE)
|
||||||
dwDesiredAccess = FILE_MAP_WRITE;
|
dwDesiredAccess = FILE_MAP_WRITE;
|
||||||
|
@ -102,7 +113,8 @@ int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd,
|
||||||
PS4_SYSV_ABI void* posix_mmap(void* addr, u64 len, int prot, int flags, int fd, u64 offset) {
|
PS4_SYSV_ABI void* posix_mmap(void* addr, u64 len, int prot, int flags, int fd, u64 offset) {
|
||||||
void* ptr;
|
void* ptr;
|
||||||
LOG_INFO_IF(log_libkernel_file, "posix mmap redirect to sceKernelMmap\n");
|
LOG_INFO_IF(log_libkernel_file, "posix mmap redirect to sceKernelMmap\n");
|
||||||
// posix call the difference is that there is a different behaviour when it doesn't return 0 or SCE_OK
|
// posix call the difference is that there is a different behaviour when it doesn't return 0 or
|
||||||
|
// SCE_OK
|
||||||
int result = sceKernelMmap(addr, len, prot, flags, fd, offset, &ptr);
|
int result = sceKernelMmap(addr, len, prot, flags, fd, offset, &ptr);
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
BREAKPOINT();
|
BREAKPOINT();
|
||||||
|
@ -114,9 +126,12 @@ void LibKernel_Register(Loader::SymbolsResolver* sym) {
|
||||||
// obj
|
// obj
|
||||||
LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard);
|
LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard);
|
||||||
// memory
|
// memory
|
||||||
LIB_FUNCTION("rTXw65xmLIA", "libkernel", 1, "libkernel", 1, 1, Kernel::sceKernelAllocateDirectMemory);
|
LIB_FUNCTION("rTXw65xmLIA", "libkernel", 1, "libkernel", 1, 1,
|
||||||
LIB_FUNCTION("pO96TwzOm5E", "libkernel", 1, "libkernel", 1, 1, Kernel::sceKernelGetDirectMemorySize);
|
Kernel::sceKernelAllocateDirectMemory);
|
||||||
LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1, Kernel::sceKernelMapDirectMemory);
|
LIB_FUNCTION("pO96TwzOm5E", "libkernel", 1, "libkernel", 1, 1,
|
||||||
|
Kernel::sceKernelGetDirectMemorySize);
|
||||||
|
LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1,
|
||||||
|
Kernel::sceKernelMapDirectMemory);
|
||||||
LIB_FUNCTION("MBuItvba6z8", "libkernel", 1, "libkernel", 1, 1, sceKernelReleaseDirectMemory);
|
LIB_FUNCTION("MBuItvba6z8", "libkernel", 1, "libkernel", 1, 1, sceKernelReleaseDirectMemory);
|
||||||
LIB_FUNCTION("cQke9UuBQOk", "libkernel", 1, "libkernel", 1, 1, sceKernelMunmap);
|
LIB_FUNCTION("cQke9UuBQOk", "libkernel", 1, "libkernel", 1, 1, sceKernelMunmap);
|
||||||
// equeue
|
// equeue
|
||||||
|
@ -135,4 +150,4 @@ void LibKernel_Register(Loader::SymbolsResolver* sym) {
|
||||||
Core::Libraries::LibKernel::pthreadSymbolsRegister(sym);
|
Core::Libraries::LibKernel::pthreadSymbolsRegister(sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core::Libraries::LibKernel
|
} // namespace Core::Libraries::LibKernel
|
||||||
|
|
|
@ -15,4 +15,4 @@ int* PS4_SYSV_ABI __Error();
|
||||||
|
|
||||||
void LibKernel_Register(Loader::SymbolsResolver* sym);
|
void LibKernel_Register(Loader::SymbolsResolver* sym);
|
||||||
|
|
||||||
} // namespace Core::Libraries::LibKernel
|
} // namespace Core::Libraries::LibKernel
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace Core::Libraries::LibKernel {
|
||||||
thread_local ScePthread g_pthread_self{};
|
thread_local ScePthread g_pthread_self{};
|
||||||
PThreadCxt* g_pthread_cxt = nullptr;
|
PThreadCxt* g_pthread_cxt = nullptr;
|
||||||
|
|
||||||
constexpr bool log_pthread_file = true; // disable it to disable logging
|
constexpr bool log_pthread_file = true; // disable it to disable logging
|
||||||
|
|
||||||
void init_pthreads() {
|
void init_pthreads() {
|
||||||
g_pthread_cxt = new PThreadCxt{};
|
g_pthread_cxt = new PThreadCxt{};
|
||||||
|
@ -49,9 +49,12 @@ int PS4_SYSV_ABI scePthreadAttrInit(ScePthreadAttr* attr) {
|
||||||
result = (result == 0 ? scePthreadAttrSetdetachstate(attr, PTHREAD_CREATE_JOINABLE) : result);
|
result = (result == 0 ? scePthreadAttrSetdetachstate(attr, PTHREAD_CREATE_JOINABLE) : result);
|
||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case 0: return SCE_OK;
|
case 0:
|
||||||
case ENOMEM: return SCE_KERNEL_ERROR_ENOMEM;
|
return SCE_OK;
|
||||||
default: return SCE_KERNEL_ERROR_EINVAL;
|
case ENOMEM:
|
||||||
|
return SCE_KERNEL_ERROR_ENOMEM;
|
||||||
|
default:
|
||||||
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,12 +65,20 @@ int PS4_SYSV_ABI scePthreadAttrSetdetachstate(ScePthreadAttr* attr, int detachst
|
||||||
|
|
||||||
int pstate = PTHREAD_CREATE_JOINABLE;
|
int pstate = PTHREAD_CREATE_JOINABLE;
|
||||||
switch (detachstate) {
|
switch (detachstate) {
|
||||||
case 0: pstate = PTHREAD_CREATE_JOINABLE; break;
|
case 0:
|
||||||
case 1: pstate = PTHREAD_CREATE_DETACHED; break;
|
pstate = PTHREAD_CREATE_JOINABLE;
|
||||||
default: LOG_TRACE_IF(log_pthread_file, "scePthreadAttrSetdetachstate invalid detachstate: {}\n", detachstate); std::exit(0);
|
break;
|
||||||
|
case 1:
|
||||||
|
pstate = PTHREAD_CREATE_DETACHED;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_TRACE_IF(log_pthread_file, "scePthreadAttrSetdetachstate invalid detachstate: {}\n",
|
||||||
|
detachstate);
|
||||||
|
std::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// int result = pthread_attr_setdetachstate(&(*attr)->pth_attr, pstate); doesn't seem to work correctly
|
// int result = pthread_attr_setdetachstate(&(*attr)->pth_attr, pstate); doesn't seem to work
|
||||||
|
// correctly
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
(*attr)->detached = (pstate == PTHREAD_CREATE_DETACHED);
|
(*attr)->detached = (pstate == PTHREAD_CREATE_DETACHED);
|
||||||
|
@ -82,9 +93,16 @@ int PS4_SYSV_ABI scePthreadAttrSetinheritsched(ScePthreadAttr* attr, int inherit
|
||||||
|
|
||||||
int pinherit_sched = PTHREAD_INHERIT_SCHED;
|
int pinherit_sched = PTHREAD_INHERIT_SCHED;
|
||||||
switch (inheritSched) {
|
switch (inheritSched) {
|
||||||
case 0: pinherit_sched = PTHREAD_EXPLICIT_SCHED; break;
|
case 0:
|
||||||
case 4: pinherit_sched = PTHREAD_INHERIT_SCHED; break;
|
pinherit_sched = PTHREAD_EXPLICIT_SCHED;
|
||||||
default: LOG_TRACE_IF(log_pthread_file, "scePthreadAttrSetinheritsched invalid inheritSched: {}\n", inheritSched); std::exit(0);
|
break;
|
||||||
|
case 4:
|
||||||
|
pinherit_sched = PTHREAD_INHERIT_SCHED;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_TRACE_IF(log_pthread_file, "scePthreadAttrSetinheritsched invalid inheritSched: {}\n",
|
||||||
|
inheritSched);
|
||||||
|
std::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = pthread_attr_setinheritsched(&(*attr)->pth_attr, pinherit_sched);
|
int result = pthread_attr_setinheritsched(&(*attr)->pth_attr, pinherit_sched);
|
||||||
|
@ -92,7 +110,8 @@ int PS4_SYSV_ABI scePthreadAttrSetinheritsched(ScePthreadAttr* attr, int inherit
|
||||||
return result == 0 ? SCE_OK : SCE_KERNEL_ERROR_EINVAL;
|
return result == 0 ? SCE_OK : SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI scePthreadAttrSetschedparam(ScePthreadAttr* attr, const SceKernelSchedParam* param) {
|
int PS4_SYSV_ABI scePthreadAttrSetschedparam(ScePthreadAttr* attr,
|
||||||
|
const SceKernelSchedParam* param) {
|
||||||
if (param == nullptr || attr == nullptr || *attr == nullptr) {
|
if (param == nullptr || attr == nullptr || *attr == nullptr) {
|
||||||
return SCE_KERNEL_ERROR_EINVAL;
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -116,9 +135,11 @@ int PS4_SYSV_ABI scePthreadAttrSetschedpolicy(ScePthreadAttr* attr, int policy)
|
||||||
return SCE_KERNEL_ERROR_EINVAL;
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ppolicy = SCHED_OTHER; // winpthreads only supports SCHED_OTHER
|
int ppolicy = SCHED_OTHER; // winpthreads only supports SCHED_OTHER
|
||||||
if (policy != SCHED_OTHER) {
|
if (policy != SCHED_OTHER) {
|
||||||
LOG_TRACE_IF(log_pthread_file, "scePthreadAttrSetschedpolicy policy={} not supported by winpthreads\n", policy);
|
LOG_TRACE_IF(log_pthread_file,
|
||||||
|
"scePthreadAttrSetschedpolicy policy={} not supported by winpthreads\n",
|
||||||
|
policy);
|
||||||
}
|
}
|
||||||
(*attr)->policy = policy;
|
(*attr)->policy = policy;
|
||||||
|
|
||||||
|
@ -126,9 +147,12 @@ int PS4_SYSV_ABI scePthreadAttrSetschedpolicy(ScePthreadAttr* attr, int policy)
|
||||||
|
|
||||||
return result == 0 ? SCE_OK : SCE_KERNEL_ERROR_EINVAL;
|
return result == 0 ? SCE_OK : SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
ScePthread PS4_SYSV_ABI scePthreadSelf() { return g_pthread_self; }
|
ScePthread PS4_SYSV_ABI scePthreadSelf() {
|
||||||
|
return g_pthread_self;
|
||||||
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI scePthreadAttrSetaffinity(ScePthreadAttr* pattr, const /*SceKernelCpumask*/ u64 mask) {
|
int PS4_SYSV_ABI scePthreadAttrSetaffinity(ScePthreadAttr* pattr,
|
||||||
|
const /*SceKernelCpumask*/ u64 mask) {
|
||||||
PRINT_FUNCTION_NAME();
|
PRINT_FUNCTION_NAME();
|
||||||
|
|
||||||
if (pattr == nullptr || *pattr == nullptr) {
|
if (pattr == nullptr || *pattr == nullptr) {
|
||||||
|
@ -151,7 +175,8 @@ int PS4_SYSV_ABI scePthreadSetaffinity(ScePthread thread, const /*SceKernelCpuma
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
int PS4_SYSV_ABI scePthreadCreate(ScePthread* thread, const ScePthreadAttr* attr, pthreadEntryFunc start_routine, void* arg, const char* name) {
|
int PS4_SYSV_ABI scePthreadCreate(ScePthread* thread, const ScePthreadAttr* attr,
|
||||||
|
pthreadEntryFunc start_routine, void* arg, const char* name) {
|
||||||
PRINT_DUMMY_FUNCTION_NAME();
|
PRINT_DUMMY_FUNCTION_NAME();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -169,7 +194,8 @@ void* createMutex(void* addr) {
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI scePthreadMutexInit(ScePthreadMutex* mutex, const ScePthreadMutexattr* attr, const char* name) {
|
int PS4_SYSV_ABI scePthreadMutexInit(ScePthreadMutex* mutex, const ScePthreadMutexattr* attr,
|
||||||
|
const char* name) {
|
||||||
PRINT_FUNCTION_NAME();
|
PRINT_FUNCTION_NAME();
|
||||||
if (mutex == nullptr) {
|
if (mutex == nullptr) {
|
||||||
return SCE_KERNEL_ERROR_EINVAL;
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
|
@ -192,11 +218,16 @@ int PS4_SYSV_ABI scePthreadMutexInit(ScePthreadMutex* mutex, const ScePthreadMut
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case 0: return SCE_OK;
|
case 0:
|
||||||
case EAGAIN: return SCE_KERNEL_ERROR_EAGAIN;
|
return SCE_OK;
|
||||||
case EINVAL: return SCE_KERNEL_ERROR_EINVAL;
|
case EAGAIN:
|
||||||
case ENOMEM: return SCE_KERNEL_ERROR_ENOMEM;
|
return SCE_KERNEL_ERROR_EAGAIN;
|
||||||
default: return SCE_KERNEL_ERROR_EINVAL;
|
case EINVAL:
|
||||||
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
|
case ENOMEM:
|
||||||
|
return SCE_KERNEL_ERROR_ENOMEM;
|
||||||
|
default:
|
||||||
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,20 +240,31 @@ int PS4_SYSV_ABI scePthreadMutexattrInit(ScePthreadMutexattr* attr) {
|
||||||
result = (result == 0 ? scePthreadMutexattrSetprotocol(attr, 0) : result);
|
result = (result == 0 ? scePthreadMutexattrSetprotocol(attr, 0) : result);
|
||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case 0: return SCE_OK;
|
case 0:
|
||||||
case ENOMEM: return SCE_KERNEL_ERROR_ENOMEM;
|
return SCE_OK;
|
||||||
default: return SCE_KERNEL_ERROR_EINVAL;
|
case ENOMEM:
|
||||||
|
return SCE_KERNEL_ERROR_ENOMEM;
|
||||||
|
default:
|
||||||
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI scePthreadMutexattrSettype(ScePthreadMutexattr* attr, int type) {
|
int PS4_SYSV_ABI scePthreadMutexattrSettype(ScePthreadMutexattr* attr, int type) {
|
||||||
int ptype = PTHREAD_MUTEX_DEFAULT;
|
int ptype = PTHREAD_MUTEX_DEFAULT;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 1: ptype = PTHREAD_MUTEX_ERRORCHECK; break;
|
case 1:
|
||||||
case 2: ptype = PTHREAD_MUTEX_RECURSIVE; break;
|
ptype = PTHREAD_MUTEX_ERRORCHECK;
|
||||||
case 3:
|
break;
|
||||||
case 4: ptype = PTHREAD_MUTEX_NORMAL; break;
|
case 2:
|
||||||
default: LOG_TRACE_IF(log_pthread_file, "scePthreadMutexattrSettype invalid type: {}\n", type); std::exit(0);
|
ptype = PTHREAD_MUTEX_RECURSIVE;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
ptype = PTHREAD_MUTEX_NORMAL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_TRACE_IF(log_pthread_file, "scePthreadMutexattrSettype invalid type: {}\n", type);
|
||||||
|
std::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = pthread_mutexattr_settype(&(*attr)->pth_mutex_attr, ptype);
|
int result = pthread_mutexattr_settype(&(*attr)->pth_mutex_attr, ptype);
|
||||||
|
@ -233,13 +275,23 @@ int PS4_SYSV_ABI scePthreadMutexattrSettype(ScePthreadMutexattr* attr, int type)
|
||||||
int PS4_SYSV_ABI scePthreadMutexattrSetprotocol(ScePthreadMutexattr* attr, int protocol) {
|
int PS4_SYSV_ABI scePthreadMutexattrSetprotocol(ScePthreadMutexattr* attr, int protocol) {
|
||||||
int pprotocol = PTHREAD_PRIO_NONE;
|
int pprotocol = PTHREAD_PRIO_NONE;
|
||||||
switch (protocol) {
|
switch (protocol) {
|
||||||
case 0: pprotocol = PTHREAD_PRIO_NONE; break;
|
case 0:
|
||||||
case 1: pprotocol = PTHREAD_PRIO_INHERIT; break;
|
pprotocol = PTHREAD_PRIO_NONE;
|
||||||
case 2: pprotocol = PTHREAD_PRIO_PROTECT; break;
|
break;
|
||||||
default: LOG_TRACE_IF(log_pthread_file, "scePthreadMutexattrSetprotocol invalid protocol: {}\n", protocol); std::exit(0);
|
case 1:
|
||||||
|
pprotocol = PTHREAD_PRIO_INHERIT;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
pprotocol = PTHREAD_PRIO_PROTECT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_TRACE_IF(log_pthread_file, "scePthreadMutexattrSetprotocol invalid protocol: {}\n",
|
||||||
|
protocol);
|
||||||
|
std::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = 0; // pthread_mutexattr_setprotocol(&(*attr)->p, pprotocol); //it appears that pprotocol has issues in winpthreads
|
int result = 0; // pthread_mutexattr_setprotocol(&(*attr)->p, pprotocol); //it appears that
|
||||||
|
// pprotocol has issues in winpthreads
|
||||||
(*attr)->pprotocol = pprotocol;
|
(*attr)->pprotocol = pprotocol;
|
||||||
|
|
||||||
return result == 0 ? SCE_OK : SCE_KERNEL_ERROR_EINVAL;
|
return result == 0 ? SCE_OK : SCE_KERNEL_ERROR_EINVAL;
|
||||||
|
@ -253,13 +305,19 @@ int PS4_SYSV_ABI scePthreadMutexLock(ScePthreadMutex* mutex) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = pthread_mutex_lock(&(*mutex)->pth_mutex);
|
int result = pthread_mutex_lock(&(*mutex)->pth_mutex);
|
||||||
LOG_INFO_IF(log_pthread_file, "scePthreadMutexLock name={} result={}\n", (*mutex)->name, result);
|
LOG_INFO_IF(log_pthread_file, "scePthreadMutexLock name={} result={}\n", (*mutex)->name,
|
||||||
|
result);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case 0: return SCE_OK;
|
case 0:
|
||||||
case EAGAIN: return SCE_KERNEL_ERROR_EAGAIN;
|
return SCE_OK;
|
||||||
case EINVAL: return SCE_KERNEL_ERROR_EINVAL;
|
case EAGAIN:
|
||||||
case EDEADLK: return SCE_KERNEL_ERROR_EDEADLK;
|
return SCE_KERNEL_ERROR_EAGAIN;
|
||||||
default: return SCE_KERNEL_ERROR_EINVAL;
|
case EINVAL:
|
||||||
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
|
case EDEADLK:
|
||||||
|
return SCE_KERNEL_ERROR_EDEADLK;
|
||||||
|
default:
|
||||||
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int PS4_SYSV_ABI scePthreadMutexUnlock(ScePthreadMutex* mutex) {
|
int PS4_SYSV_ABI scePthreadMutexUnlock(ScePthreadMutex* mutex) {
|
||||||
|
@ -270,13 +328,18 @@ int PS4_SYSV_ABI scePthreadMutexUnlock(ScePthreadMutex* mutex) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = pthread_mutex_unlock(&(*mutex)->pth_mutex);
|
int result = pthread_mutex_unlock(&(*mutex)->pth_mutex);
|
||||||
LOG_INFO_IF(log_pthread_file, "scePthreadMutexUnlock name={} result={}\n", (*mutex)->name, result);
|
LOG_INFO_IF(log_pthread_file, "scePthreadMutexUnlock name={} result={}\n", (*mutex)->name,
|
||||||
|
result);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case 0: return SCE_OK;
|
case 0:
|
||||||
|
return SCE_OK;
|
||||||
|
|
||||||
case EINVAL: return SCE_KERNEL_ERROR_EINVAL;
|
case EINVAL:
|
||||||
case EPERM: return SCE_KERNEL_ERROR_EPERM;
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
default: return SCE_KERNEL_ERROR_EINVAL;
|
case EPERM:
|
||||||
|
return SCE_KERNEL_ERROR_EPERM;
|
||||||
|
default:
|
||||||
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,7 +357,8 @@ void* createCond(void* addr) {
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI scePthreadCondInit(ScePthreadCond* cond, const ScePthreadCondattr* attr, const char* name) {
|
int PS4_SYSV_ABI scePthreadCondInit(ScePthreadCond* cond, const ScePthreadCondattr* attr,
|
||||||
|
const char* name) {
|
||||||
if (cond == nullptr) {
|
if (cond == nullptr) {
|
||||||
return SCE_KERNEL_ERROR_EINVAL;
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -318,11 +382,16 @@ int PS4_SYSV_ABI scePthreadCondInit(ScePthreadCond* cond, const ScePthreadCondat
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case 0: return SCE_OK;
|
case 0:
|
||||||
case EAGAIN: return SCE_KERNEL_ERROR_EAGAIN;
|
return SCE_OK;
|
||||||
case EINVAL: return SCE_KERNEL_ERROR_EINVAL;
|
case EAGAIN:
|
||||||
case ENOMEM: return SCE_KERNEL_ERROR_ENOMEM;
|
return SCE_KERNEL_ERROR_EAGAIN;
|
||||||
default: return SCE_KERNEL_ERROR_EINVAL;
|
case EINVAL:
|
||||||
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
|
case ENOMEM:
|
||||||
|
return SCE_KERNEL_ERROR_ENOMEM;
|
||||||
|
default:
|
||||||
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,9 +401,12 @@ int PS4_SYSV_ABI scePthreadCondattrInit(ScePthreadCondattr* attr) {
|
||||||
int result = pthread_condattr_init(&(*attr)->cond_attr);
|
int result = pthread_condattr_init(&(*attr)->cond_attr);
|
||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case 0: return SCE_OK;
|
case 0:
|
||||||
case ENOMEM: return SCE_KERNEL_ERROR_ENOMEM;
|
return SCE_OK;
|
||||||
default: return SCE_KERNEL_ERROR_EINVAL;
|
case ENOMEM:
|
||||||
|
return SCE_KERNEL_ERROR_ENOMEM;
|
||||||
|
default:
|
||||||
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,7 +431,9 @@ int PS4_SYSV_ABI posix_pthread_mutex_init(ScePthreadMutex* mutex, const ScePthre
|
||||||
LOG_INFO_IF(log_pthread_file, "posix pthread_mutex_init redirect to scePthreadMutexInit\n");
|
LOG_INFO_IF(log_pthread_file, "posix pthread_mutex_init redirect to scePthreadMutexInit\n");
|
||||||
int result = scePthreadMutexInit(mutex, attr, nullptr);
|
int result = scePthreadMutexInit(mutex, attr, nullptr);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
int rt = result > SCE_KERNEL_ERROR_UNKNOWN && result <= SCE_KERNEL_ERROR_ESTOP ? result + -SCE_KERNEL_ERROR_UNKNOWN : POSIX_EOTHER;
|
int rt = result > SCE_KERNEL_ERROR_UNKNOWN && result <= SCE_KERNEL_ERROR_ESTOP
|
||||||
|
? result + -SCE_KERNEL_ERROR_UNKNOWN
|
||||||
|
: POSIX_EOTHER;
|
||||||
return rt;
|
return rt;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -369,7 +443,9 @@ int PS4_SYSV_ABI posix_pthread_mutex_lock(ScePthreadMutex* mutex) {
|
||||||
LOG_INFO_IF(log_pthread_file, "posix pthread_mutex_lock redirect to scePthreadMutexLock\n");
|
LOG_INFO_IF(log_pthread_file, "posix pthread_mutex_lock redirect to scePthreadMutexLock\n");
|
||||||
int result = scePthreadMutexLock(mutex);
|
int result = scePthreadMutexLock(mutex);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
int rt = result > SCE_KERNEL_ERROR_UNKNOWN && result <= SCE_KERNEL_ERROR_ESTOP ? result + -SCE_KERNEL_ERROR_UNKNOWN : POSIX_EOTHER;
|
int rt = result > SCE_KERNEL_ERROR_UNKNOWN && result <= SCE_KERNEL_ERROR_ESTOP
|
||||||
|
? result + -SCE_KERNEL_ERROR_UNKNOWN
|
||||||
|
: POSIX_EOTHER;
|
||||||
return rt;
|
return rt;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -379,17 +455,22 @@ int PS4_SYSV_ABI posix_pthread_mutex_unlock(ScePthreadMutex* mutex) {
|
||||||
LOG_INFO_IF(log_pthread_file, "posix pthread_mutex_unlock redirect to scePthreadMutexUnlock\n");
|
LOG_INFO_IF(log_pthread_file, "posix pthread_mutex_unlock redirect to scePthreadMutexUnlock\n");
|
||||||
int result = scePthreadMutexUnlock(mutex);
|
int result = scePthreadMutexUnlock(mutex);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
int rt = result > SCE_KERNEL_ERROR_UNKNOWN && result <= SCE_KERNEL_ERROR_ESTOP ? result + -SCE_KERNEL_ERROR_UNKNOWN : POSIX_EOTHER;
|
int rt = result > SCE_KERNEL_ERROR_UNKNOWN && result <= SCE_KERNEL_ERROR_ESTOP
|
||||||
|
? result + -SCE_KERNEL_ERROR_UNKNOWN
|
||||||
|
: POSIX_EOTHER;
|
||||||
return rt;
|
return rt;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI posix_pthread_cond_broadcast(ScePthreadCond* cond) {
|
int PS4_SYSV_ABI posix_pthread_cond_broadcast(ScePthreadCond* cond) {
|
||||||
LOG_INFO_IF(log_pthread_file, "posix posix_pthread_cond_broadcast redirect to scePthreadCondBroadcast\n");
|
LOG_INFO_IF(log_pthread_file,
|
||||||
|
"posix posix_pthread_cond_broadcast redirect to scePthreadCondBroadcast\n");
|
||||||
int result = scePthreadCondBroadcast(cond);
|
int result = scePthreadCondBroadcast(cond);
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
int rt = result > SCE_KERNEL_ERROR_UNKNOWN && result <= SCE_KERNEL_ERROR_ESTOP ? result + -SCE_KERNEL_ERROR_UNKNOWN : POSIX_EOTHER;
|
int rt = result > SCE_KERNEL_ERROR_UNKNOWN && result <= SCE_KERNEL_ERROR_ESTOP
|
||||||
|
? result + -SCE_KERNEL_ERROR_UNKNOWN
|
||||||
|
: POSIX_EOTHER;
|
||||||
return rt;
|
return rt;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -412,7 +493,7 @@ void pthreadSymbolsRegister(Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("1FGvU0i9saQ", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexattrSetprotocol);
|
LIB_FUNCTION("1FGvU0i9saQ", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexattrSetprotocol);
|
||||||
LIB_FUNCTION("9UK1vLZQft4", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexLock);
|
LIB_FUNCTION("9UK1vLZQft4", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexLock);
|
||||||
LIB_FUNCTION("tn3VlD0hG60", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexUnlock);
|
LIB_FUNCTION("tn3VlD0hG60", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexUnlock);
|
||||||
//cond calls
|
// cond calls
|
||||||
LIB_FUNCTION("2Tb92quprl0", "libkernel", 1, "libkernel", 1, 1, scePthreadCondInit);
|
LIB_FUNCTION("2Tb92quprl0", "libkernel", 1, "libkernel", 1, 1, scePthreadCondInit);
|
||||||
LIB_FUNCTION("m5-2bsNfv7s", "libkernel", 1, "libkernel", 1, 1, scePthreadCondattrInit);
|
LIB_FUNCTION("m5-2bsNfv7s", "libkernel", 1, "libkernel", 1, 1, scePthreadCondattrInit);
|
||||||
LIB_FUNCTION("JGgj7Uvrl+A", "libkernel", 1, "libkernel", 1, 1, scePthreadCondBroadcast);
|
LIB_FUNCTION("JGgj7Uvrl+A", "libkernel", 1, "libkernel", 1, 1, scePthreadCondBroadcast);
|
||||||
|
@ -428,4 +509,4 @@ void pthreadSymbolsRegister(Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("mkx2fVhNMsg", "libkernel", 1, "libkernel", 1, 1, posix_pthread_cond_broadcast);
|
LIB_FUNCTION("mkx2fVhNMsg", "libkernel", 1, "libkernel", 1, 1, posix_pthread_cond_broadcast);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core::Libraries::LibKernel
|
} // namespace Core::Libraries::LibKernel
|
|
@ -71,13 +71,21 @@ struct PthreadCondAttrInternal {
|
||||||
};
|
};
|
||||||
|
|
||||||
class PThreadCxt {
|
class PThreadCxt {
|
||||||
public:
|
public:
|
||||||
ScePthreadMutexattr* getDefaultMutexattr() { return &m_default_mutexattr; }
|
ScePthreadMutexattr* getDefaultMutexattr() {
|
||||||
void setDefaultMutexattr(ScePthreadMutexattr attr) { m_default_mutexattr = attr; }
|
return &m_default_mutexattr;
|
||||||
ScePthreadCondattr* getDefaultCondattr() { return &m_default_condattr; }
|
}
|
||||||
void setDefaultCondattr(ScePthreadCondattr attr) { m_default_condattr = attr; }
|
void setDefaultMutexattr(ScePthreadMutexattr attr) {
|
||||||
|
m_default_mutexattr = attr;
|
||||||
|
}
|
||||||
|
ScePthreadCondattr* getDefaultCondattr() {
|
||||||
|
return &m_default_condattr;
|
||||||
|
}
|
||||||
|
void setDefaultCondattr(ScePthreadCondattr attr) {
|
||||||
|
m_default_condattr = attr;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ScePthreadMutexattr m_default_mutexattr = nullptr;
|
ScePthreadMutexattr m_default_mutexattr = nullptr;
|
||||||
ScePthreadCondattr m_default_condattr = nullptr;
|
ScePthreadCondattr m_default_condattr = nullptr;
|
||||||
};
|
};
|
||||||
|
@ -88,17 +96,21 @@ void pthreadInitSelfMainThread();
|
||||||
int PS4_SYSV_ABI scePthreadAttrInit(ScePthreadAttr* attr);
|
int PS4_SYSV_ABI scePthreadAttrInit(ScePthreadAttr* attr);
|
||||||
int PS4_SYSV_ABI scePthreadAttrSetdetachstate(ScePthreadAttr* attr, int detachstate);
|
int PS4_SYSV_ABI scePthreadAttrSetdetachstate(ScePthreadAttr* attr, int detachstate);
|
||||||
int PS4_SYSV_ABI scePthreadAttrSetinheritsched(ScePthreadAttr* attr, int inheritSched);
|
int PS4_SYSV_ABI scePthreadAttrSetinheritsched(ScePthreadAttr* attr, int inheritSched);
|
||||||
int PS4_SYSV_ABI scePthreadAttrSetschedparam(ScePthreadAttr* attr, const SceKernelSchedParam* param);
|
int PS4_SYSV_ABI scePthreadAttrSetschedparam(ScePthreadAttr* attr,
|
||||||
|
const SceKernelSchedParam* param);
|
||||||
int PS4_SYSV_ABI scePthreadAttrSetschedpolicy(ScePthreadAttr* attr, int policy);
|
int PS4_SYSV_ABI scePthreadAttrSetschedpolicy(ScePthreadAttr* attr, int policy);
|
||||||
ScePthread PS4_SYSV_ABI scePthreadSelf();
|
ScePthread PS4_SYSV_ABI scePthreadSelf();
|
||||||
int PS4_SYSV_ABI scePthreadAttrSetaffinity(ScePthreadAttr* pattr, const /*SceKernelCpumask*/ u64 mask);
|
int PS4_SYSV_ABI scePthreadAttrSetaffinity(ScePthreadAttr* pattr,
|
||||||
|
const /*SceKernelCpumask*/ u64 mask);
|
||||||
int PS4_SYSV_ABI scePthreadSetaffinity(ScePthread thread, const /*SceKernelCpumask*/ u64 mask);
|
int PS4_SYSV_ABI scePthreadSetaffinity(ScePthread thread, const /*SceKernelCpumask*/ u64 mask);
|
||||||
int PS4_SYSV_ABI scePthreadCreate(ScePthread* thread, const ScePthreadAttr* attr, pthreadEntryFunc start_routine, void* arg, const char* name);
|
int PS4_SYSV_ABI scePthreadCreate(ScePthread* thread, const ScePthreadAttr* attr,
|
||||||
|
pthreadEntryFunc start_routine, void* arg, const char* name);
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* Mutex calls
|
* Mutex calls
|
||||||
*/
|
*/
|
||||||
int PS4_SYSV_ABI scePthreadMutexInit(ScePthreadMutex* mutex, const ScePthreadMutexattr* attr, const char* name);
|
int PS4_SYSV_ABI scePthreadMutexInit(ScePthreadMutex* mutex, const ScePthreadMutexattr* attr,
|
||||||
|
const char* name);
|
||||||
int PS4_SYSV_ABI scePthreadMutexattrInit(ScePthreadMutexattr* attr);
|
int PS4_SYSV_ABI scePthreadMutexattrInit(ScePthreadMutexattr* attr);
|
||||||
int PS4_SYSV_ABI scePthreadMutexattrSettype(ScePthreadMutexattr* attr, int type);
|
int PS4_SYSV_ABI scePthreadMutexattrSettype(ScePthreadMutexattr* attr, int type);
|
||||||
int PS4_SYSV_ABI scePthreadMutexattrSetprotocol(ScePthreadMutexattr* attr, int protocol);
|
int PS4_SYSV_ABI scePthreadMutexattrSetprotocol(ScePthreadMutexattr* attr, int protocol);
|
||||||
|
@ -107,10 +119,11 @@ int PS4_SYSV_ABI scePthreadMutexUnlock(ScePthreadMutex* mutex);
|
||||||
/****
|
/****
|
||||||
* Cond calls
|
* Cond calls
|
||||||
*/
|
*/
|
||||||
int PS4_SYSV_ABI scePthreadCondInit(ScePthreadCond* cond, const ScePthreadCondattr* attr, const char* name);
|
int PS4_SYSV_ABI scePthreadCondInit(ScePthreadCond* cond, const ScePthreadCondattr* attr,
|
||||||
|
const char* name);
|
||||||
int PS4_SYSV_ABI scePthreadCondattrInit(ScePthreadCondattr* attr);
|
int PS4_SYSV_ABI scePthreadCondattrInit(ScePthreadCondattr* attr);
|
||||||
int PS4_SYSV_ABI scePthreadCondBroadcast(ScePthreadCond* cond);
|
int PS4_SYSV_ABI scePthreadCondBroadcast(ScePthreadCond* cond);
|
||||||
/****
|
/****
|
||||||
* Posix calls
|
* Posix calls
|
||||||
*/
|
*/
|
||||||
int PS4_SYSV_ABI posix_pthread_mutex_init(ScePthreadMutex* mutex, const ScePthreadMutexattr* attr);
|
int PS4_SYSV_ABI posix_pthread_mutex_init(ScePthreadMutex* mutex, const ScePthreadMutexattr* attr);
|
||||||
|
@ -119,4 +132,4 @@ int PS4_SYSV_ABI posix_pthread_mutex_unlock(ScePthreadMutex* mutex);
|
||||||
int PS4_SYSV_ABI posix_pthread_cond_broadcast(ScePthreadCond* cond);
|
int PS4_SYSV_ABI posix_pthread_cond_broadcast(ScePthreadCond* cond);
|
||||||
|
|
||||||
void pthreadSymbolsRegister(Loader::SymbolsResolver* sym);
|
void pthreadSymbolsRegister(Loader::SymbolsResolver* sym);
|
||||||
} // namespace Core::Libraries::LibKernel
|
} // namespace Core::Libraries::LibKernel
|
|
@ -28,8 +28,9 @@ void timeSymbolsRegister(Loader::SymbolsResolver* sym) {
|
||||||
initial_ptc = clock->GetUptime();
|
initial_ptc = clock->GetUptime();
|
||||||
LIB_FUNCTION("4J2sUJmuHZQ", "libkernel", 1, "libkernel", 1, 1, sceKernelGetProcessTime);
|
LIB_FUNCTION("4J2sUJmuHZQ", "libkernel", 1, "libkernel", 1, 1, sceKernelGetProcessTime);
|
||||||
LIB_FUNCTION("fgxnMeTNUtY", "libkernel", 1, "libkernel", 1, 1, sceKernelGetProcessTimeCounter);
|
LIB_FUNCTION("fgxnMeTNUtY", "libkernel", 1, "libkernel", 1, 1, sceKernelGetProcessTimeCounter);
|
||||||
LIB_FUNCTION("BNowx2l588E", "libkernel", 1, "libkernel", 1, 1, sceKernelGetProcessTimeCounterFrequency);
|
LIB_FUNCTION("BNowx2l588E", "libkernel", 1, "libkernel", 1, 1,
|
||||||
|
sceKernelGetProcessTimeCounterFrequency);
|
||||||
LIB_FUNCTION("-2IRUCO--PM", "libkernel", 1, "libkernel", 1, 1, sceKernelReadTsc);
|
LIB_FUNCTION("-2IRUCO--PM", "libkernel", 1, "libkernel", 1, 1, sceKernelReadTsc);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core::Libraries::LibKernel
|
} // namespace Core::Libraries::LibKernel
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
|
#include "Emulator/Host/controller.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
#include "common/singleton.h"
|
#include "common/singleton.h"
|
||||||
#include "core/hle/libraries/libpad/pad.h"
|
|
||||||
#include "core/hle/error_codes.h"
|
#include "core/hle/error_codes.h"
|
||||||
|
#include "core/hle/libraries/libpad/pad.h"
|
||||||
#include "core/hle/libraries/libs.h"
|
#include "core/hle/libraries/libs.h"
|
||||||
#include "Emulator/Host/controller.h"
|
|
||||||
|
|
||||||
namespace Core::Libraries::LibPad {
|
namespace Core::Libraries::LibPad {
|
||||||
|
|
||||||
constexpr bool log_file_pad = true; // disable it to disable logging
|
constexpr bool log_file_pad = true; // disable it to disable logging
|
||||||
|
|
||||||
int PS4_SYSV_ABI scePadInit() {
|
int PS4_SYSV_ABI scePadInit() {
|
||||||
return SCE_OK;
|
return SCE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI scePadOpen(Core::Libraries::LibUserService::SceUserServiceUserId userId, s32 type, s32 index,
|
int PS4_SYSV_ABI scePadOpen(Core::Libraries::LibUserService::SceUserServiceUserId userId, s32 type,
|
||||||
const ScePadOpenParam* pParam) {
|
s32 index, const ScePadOpenParam* pParam) {
|
||||||
LOG_INFO_IF(log_file_pad, "scePadOpen userid = {} type = {} index = {}\n", userId, type, index);
|
LOG_INFO_IF(log_file_pad, "scePadOpen userid = {} type = {} index = {}\n", userId, type, index);
|
||||||
return 1; // dummy
|
return 1; // dummy
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI scePadReadState(int32_t handle, ScePadData* pData) {
|
int PS4_SYSV_ABI scePadReadState(int32_t handle, ScePadData* pData) {
|
||||||
|
@ -28,19 +28,19 @@ int PS4_SYSV_ABI scePadReadState(int32_t handle, ScePadData* pData) {
|
||||||
|
|
||||||
controller->readState(&state, &isConnected, &connectedCount);
|
controller->readState(&state, &isConnected, &connectedCount);
|
||||||
pData->buttons = state.buttonsState;
|
pData->buttons = state.buttonsState;
|
||||||
pData->leftStick.x = 128; // dummy
|
pData->leftStick.x = 128; // dummy
|
||||||
pData->leftStick.y = 128; // dummy
|
pData->leftStick.y = 128; // dummy
|
||||||
pData->rightStick.x = 0; // dummy
|
pData->rightStick.x = 0; // dummy
|
||||||
pData->rightStick.y = 0; // dummy
|
pData->rightStick.y = 0; // dummy
|
||||||
pData->analogButtons.r2 = 0;//dummy
|
pData->analogButtons.r2 = 0; // dummy
|
||||||
pData->analogButtons.l2 = 0;//dummy
|
pData->analogButtons.l2 = 0; // dummy
|
||||||
pData->orientation.x = 0;
|
pData->orientation.x = 0;
|
||||||
pData->orientation.y = 0;
|
pData->orientation.y = 0;
|
||||||
pData->orientation.z = 0;
|
pData->orientation.z = 0;
|
||||||
pData->orientation.w = 0;
|
pData->orientation.w = 0;
|
||||||
pData->timestamp = state.time;
|
pData->timestamp = state.time;
|
||||||
pData->connected = true; // isConnected; //TODO fix me proper
|
pData->connected = true; // isConnected; //TODO fix me proper
|
||||||
pData->connectedCount = 1;//connectedCount;
|
pData->connectedCount = 1; // connectedCount;
|
||||||
pData->deviceUniqueDataLen = 0;
|
pData->deviceUniqueDataLen = 0;
|
||||||
|
|
||||||
return SCE_OK;
|
return SCE_OK;
|
||||||
|
@ -52,4 +52,4 @@ void padSymbolsRegister(Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("YndgXqQVV7c", "libScePad", 1, "libScePad", 1, 1, scePadReadState);
|
LIB_FUNCTION("YndgXqQVV7c", "libScePad", 1, "libScePad", 1, 1, scePadReadState);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Emulator::HLE::Libraries::LibPad
|
} // namespace Core::Libraries::LibPad
|
||||||
|
|
|
@ -95,4 +95,4 @@ int PS4_SYSV_ABI scePadReadState(int32_t handle, ScePadData* pData);
|
||||||
|
|
||||||
void padSymbolsRegister(Loader::SymbolsResolver* sym);
|
void padSymbolsRegister(Loader::SymbolsResolver* sym);
|
||||||
|
|
||||||
}; // namespace Core::Libraries::LibPad
|
}; // namespace Core::Libraries::LibPad
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#include "core/hle/libraries/libs.h"
|
|
||||||
#include "core/PS4/HLE/Graphics/video_out.h"
|
#include "core/PS4/HLE/Graphics/video_out.h"
|
||||||
#include "core/hle/libraries/libkernel/libkernel.h"
|
|
||||||
#include "core/hle/libraries/libscegnmdriver/libscegnmdriver.h"
|
|
||||||
#include "core/hle/libraries/libuserservice/libuserservice.h"
|
|
||||||
#include "core/hle/libraries/libpad/pad.h"
|
|
||||||
#include "core/hle/libraries/libsystemservice/system_service.h"
|
|
||||||
#include "core/hle/libraries/libc/libc.h"
|
#include "core/hle/libraries/libc/libc.h"
|
||||||
|
#include "core/hle/libraries/libkernel/libkernel.h"
|
||||||
|
#include "core/hle/libraries/libpad/pad.h"
|
||||||
|
#include "core/hle/libraries/libs.h"
|
||||||
|
#include "core/hle/libraries/libscegnmdriver/libscegnmdriver.h"
|
||||||
|
#include "core/hle/libraries/libsystemservice/system_service.h"
|
||||||
|
#include "core/hle/libraries/libuserservice/libuserservice.h"
|
||||||
|
|
||||||
namespace Core::Libraries {
|
namespace Core::Libraries {
|
||||||
|
|
||||||
|
@ -19,4 +19,4 @@ void InitHLELibs(Loader::SymbolsResolver* sym) {
|
||||||
LibC::libcSymbolsRegister(sym);
|
LibC::libcSymbolsRegister(sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core::Libraries
|
} // namespace Core::Libraries
|
||||||
|
|
|
@ -3,40 +3,38 @@
|
||||||
#include "core/loader/elf.h"
|
#include "core/loader/elf.h"
|
||||||
#include "core/loader/symbols_resolver.h"
|
#include "core/loader/symbols_resolver.h"
|
||||||
|
|
||||||
#define LIB_FUNCTION(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \
|
#define LIB_FUNCTION(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \
|
||||||
{\
|
{ \
|
||||||
Loader::SymbolRes sr{}; \
|
Loader::SymbolRes sr{}; \
|
||||||
sr.name = nid; \
|
sr.name = nid; \
|
||||||
sr.library = lib; \
|
sr.library = lib; \
|
||||||
sr.library_version = libversion;\
|
sr.library_version = libversion; \
|
||||||
sr.module = mod;\
|
sr.module = mod; \
|
||||||
sr.module_version_major = moduleVersionMajor;\
|
sr.module_version_major = moduleVersionMajor; \
|
||||||
sr.module_version_minor = moduleVersionMinor;\
|
sr.module_version_minor = moduleVersionMinor; \
|
||||||
sr.type = STT_FUN;\
|
sr.type = STT_FUN; \
|
||||||
auto func = reinterpret_cast<u64>(function);\
|
auto func = reinterpret_cast<u64>(function); \
|
||||||
sym->AddSymbol(sr, func);\
|
sym->AddSymbol(sr, func); \
|
||||||
}
|
|
||||||
|
|
||||||
#define LIB_OBJ(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \
|
|
||||||
{ \
|
|
||||||
Loader::SymbolRes sr{}; \
|
|
||||||
sr.name = nid; \
|
|
||||||
sr.library = lib; \
|
|
||||||
sr.library_version = libversion; \
|
|
||||||
sr.module = mod; \
|
|
||||||
sr.module_version_major = moduleVersionMajor; \
|
|
||||||
sr.module_version_minor = moduleVersionMinor; \
|
|
||||||
sr.type = STT_OBJECT; \
|
|
||||||
auto func = reinterpret_cast<u64>(function); \
|
|
||||||
sym->AddSymbol(sr, func); \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PRINT_FUNCTION_NAME() \
|
#define LIB_OBJ(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \
|
||||||
{ \
|
{ \
|
||||||
LOG_INFO_IF(true, "{}()\n", __func__); \
|
Loader::SymbolRes sr{}; \
|
||||||
|
sr.name = nid; \
|
||||||
|
sr.library = lib; \
|
||||||
|
sr.library_version = libversion; \
|
||||||
|
sr.module = mod; \
|
||||||
|
sr.module_version_major = moduleVersionMajor; \
|
||||||
|
sr.module_version_minor = moduleVersionMinor; \
|
||||||
|
sr.type = STT_OBJECT; \
|
||||||
|
auto func = reinterpret_cast<u64>(function); \
|
||||||
|
sym->AddSymbol(sr, func); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PRINT_DUMMY_FUNCTION_NAME() \
|
#define PRINT_FUNCTION_NAME() \
|
||||||
|
{ LOG_INFO_IF(true, "{}()\n", __func__); }
|
||||||
|
|
||||||
|
#define PRINT_DUMMY_FUNCTION_NAME() \
|
||||||
{ LOG_WARN_IF(true, "dummy {}()\n", __func__); }
|
{ LOG_WARN_IF(true, "dummy {}()\n", __func__); }
|
||||||
|
|
||||||
namespace Core::Libraries {
|
namespace Core::Libraries {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
#include "core/PS4/GPU/gpu_memory.h"
|
#include "core/PS4/GPU/gpu_memory.h"
|
||||||
#include "core/hle/libraries/libscegnmdriver/libscegnmdriver.h"
|
|
||||||
#include "core/hle/libraries/libs.h"
|
#include "core/hle/libraries/libs.h"
|
||||||
|
#include "core/hle/libraries/libscegnmdriver/libscegnmdriver.h"
|
||||||
#include "emulator.h"
|
#include "emulator.h"
|
||||||
|
|
||||||
namespace Core::Libraries::LibSceGnmDriver {
|
namespace Core::Libraries::LibSceGnmDriver {
|
||||||
|
@ -21,4 +21,4 @@ void LibSceGnmDriver_Register(Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("iBt3Oe00Kvc", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmFlushGarlic);
|
LIB_FUNCTION("iBt3Oe00Kvc", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmFlushGarlic);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
}; // namespace Core::Libraries::LibSceGnmDriver
|
||||||
|
|
|
@ -24,8 +24,10 @@ s32 PS4_SYSV_ABI sceSystemServiceGetStatus(SceSystemServiceStatus* status) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void systemServiceSymbolsRegister(Loader::SymbolsResolver* sym) {
|
void systemServiceSymbolsRegister(Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("Vo5V8KAwCmk", "libSceSystemService", 1, "libSceSystemService", 1, 1, sceSystemServiceHideSplashScreen);
|
LIB_FUNCTION("Vo5V8KAwCmk", "libSceSystemService", 1, "libSceSystemService", 1, 1,
|
||||||
LIB_FUNCTION("rPo6tV8D9bM", "libSceSystemService", 1, "libSceSystemService", 1, 1, sceSystemServiceGetStatus);
|
sceSystemServiceHideSplashScreen);
|
||||||
|
LIB_FUNCTION("rPo6tV8D9bM", "libSceSystemService", 1, "libSceSystemService", 1, 1,
|
||||||
|
sceSystemServiceGetStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
}; // namespace Core::Libraries::LibSystemService
|
}; // namespace Core::Libraries::LibSystemService
|
||||||
|
|
|
@ -23,4 +23,4 @@ s32 PS4_SYSV_ABI sceSystemServiceGetStatus(SceSystemServiceStatus* status);
|
||||||
|
|
||||||
void systemServiceSymbolsRegister(Loader::SymbolsResolver* sym);
|
void systemServiceSymbolsRegister(Loader::SymbolsResolver* sym);
|
||||||
|
|
||||||
}; // namespace Core::Libraries::LibSystemService
|
}; // namespace Core::Libraries::LibSystemService
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
#include "core/hle/libraries/libuserservice/libuserservice.h"
|
|
||||||
#include "core/hle/error_codes.h"
|
#include "core/hle/error_codes.h"
|
||||||
#include "core/hle/libraries/libs.h"
|
#include "core/hle/libraries/libs.h"
|
||||||
|
#include "core/hle/libraries/libuserservice/libuserservice.h"
|
||||||
|
|
||||||
namespace Core::Libraries::LibUserService {
|
namespace Core::Libraries::LibUserService {
|
||||||
|
|
||||||
|
@ -21,8 +21,10 @@ s32 PS4_SYSV_ABI sceUserServiceGetLoginUserIdList(SceUserServiceLoginUserIdList*
|
||||||
}
|
}
|
||||||
|
|
||||||
void userServiceSymbolsRegister(Loader::SymbolsResolver* sym) {
|
void userServiceSymbolsRegister(Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("j3YMu1MVNNo", "libSceUserService", 1, "libSceUserService", 1, 1, sceUserServiceInitialize);
|
LIB_FUNCTION("j3YMu1MVNNo", "libSceUserService", 1, "libSceUserService", 1, 1,
|
||||||
LIB_FUNCTION("fPhymKNvK-A", "libSceUserService", 1, "libSceUserService", 1, 1, sceUserServiceGetLoginUserIdList);
|
sceUserServiceInitialize);
|
||||||
|
LIB_FUNCTION("fPhymKNvK-A", "libSceUserService", 1, "libSceUserService", 1, 1,
|
||||||
|
sceUserServiceGetLoginUserIdList);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core::Libraries::LibUserService
|
} // namespace Core::Libraries::LibUserService
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
//constants
|
// constants
|
||||||
|
|
||||||
constexpr int SCE_USER_SERVICE_MAX_LOGIN_USERS = 4; //max users logged in at once
|
|
||||||
constexpr int SCE_USER_SERVICE_MAX_USER_NAME_LENGTH = 16;//Max length for user name
|
|
||||||
|
|
||||||
constexpr int SCE_USER_SERVICE_USER_ID_INVALID = -1;//invalid user ID
|
|
||||||
constexpr int SCE_USER_SERVICE_USER_ID_SYSTEM = 255; //generic id for device
|
|
||||||
constexpr int SCE_USER_SERVICE_USER_ID_EVERYONE = 254; // generic id for user (mostly used in common dialogs)
|
|
||||||
|
|
||||||
|
constexpr int SCE_USER_SERVICE_MAX_LOGIN_USERS = 4; // max users logged in at once
|
||||||
|
constexpr int SCE_USER_SERVICE_MAX_USER_NAME_LENGTH = 16; // Max length for user name
|
||||||
|
|
||||||
|
constexpr int SCE_USER_SERVICE_USER_ID_INVALID = -1; // invalid user ID
|
||||||
|
constexpr int SCE_USER_SERVICE_USER_ID_SYSTEM = 255; // generic id for device
|
||||||
|
constexpr int SCE_USER_SERVICE_USER_ID_EVERYONE =
|
||||||
|
254; // generic id for user (mostly used in common dialogs)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <vector>
|
||||||
#include "core/loader/elf.h"
|
#include "core/loader/elf.h"
|
||||||
#include "core/loader/symbols_resolver.h"
|
#include "core/loader/symbols_resolver.h"
|
||||||
|
|
||||||
|
@ -17,30 +17,30 @@ struct EntryParams {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ModuleInfo {
|
struct ModuleInfo {
|
||||||
std::string name;
|
std::string name;
|
||||||
union {
|
union {
|
||||||
u64 value;
|
u64 value;
|
||||||
struct {
|
struct {
|
||||||
u32 name_offset;
|
u32 name_offset;
|
||||||
u08 version_minor;
|
u08 version_minor;
|
||||||
u08 version_major;
|
u08 version_major;
|
||||||
u16 id;
|
u16 id;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
std::string enc_id;
|
std::string enc_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LibraryInfo {
|
struct LibraryInfo {
|
||||||
std::string name;
|
std::string name;
|
||||||
union {
|
union {
|
||||||
u64 value;
|
u64 value;
|
||||||
struct {
|
struct {
|
||||||
u32 name_offset;
|
u32 name_offset;
|
||||||
u16 version;
|
u16 version;
|
||||||
u16 id;
|
u16 id;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
std::string enc_id;
|
std::string enc_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PS4ThreadLocal {
|
struct PS4ThreadLocal {
|
||||||
|
@ -110,22 +110,25 @@ struct Module {
|
||||||
|
|
||||||
class Linker {
|
class Linker {
|
||||||
public:
|
public:
|
||||||
Linker();
|
Linker();
|
||||||
virtual ~Linker();
|
virtual ~Linker();
|
||||||
|
|
||||||
Module* LoadModule(const std::string& elf_name);
|
Module* LoadModule(const std::string& elf_name);
|
||||||
Module* FindModule(/*u32 id*/);
|
Module* FindModule(/*u32 id*/);
|
||||||
void LoadModuleToMemory(Module* m);
|
void LoadModuleToMemory(Module* m);
|
||||||
void LoadDynamicInfo(Module* m);
|
void LoadDynamicInfo(Module* m);
|
||||||
void LoadSymbols(Module* m);
|
void LoadSymbols(Module* m);
|
||||||
Loader::SymbolsResolver& getHLESymbols() { return m_hle_symbols; }
|
Loader::SymbolsResolver& getHLESymbols() {
|
||||||
void Relocate(Module* m);
|
return m_hle_symbols;
|
||||||
void Resolve(const std::string& name, int Symtype, Module* m, Loader::SymbolRecord* return_info);
|
}
|
||||||
|
void Relocate(Module* m);
|
||||||
|
void Resolve(const std::string& name, int Symtype, Module* m,
|
||||||
|
Loader::SymbolRecord* return_info);
|
||||||
void Execute();
|
void Execute();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const ModuleInfo* FindModule(const Module& m, const std::string& id);
|
const ModuleInfo* FindModule(const Module& m, const std::string& id);
|
||||||
const LibraryInfo* FindLibrary(const Module& program, const std::string& id);
|
const LibraryInfo* FindLibrary(const Module& program, const std::string& id);
|
||||||
|
|
||||||
std::vector<Module> m_modules;
|
std::vector<Module> m_modules;
|
||||||
Loader::SymbolsResolver m_hle_symbols{};
|
Loader::SymbolsResolver m_hle_symbols{};
|
||||||
|
|
|
@ -1,120 +1,185 @@
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include "common/log.h"
|
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
|
#include "common/log.h"
|
||||||
#include "core/loader/elf.h"
|
#include "core/loader/elf.h"
|
||||||
|
|
||||||
namespace Core::Loader {
|
namespace Core::Loader {
|
||||||
|
|
||||||
constexpr bool log_file_loader = false; // disable it to disable logging
|
constexpr bool log_file_loader = false; // disable it to disable logging
|
||||||
|
|
||||||
static std::string_view getProgramTypeName(program_type_es type) {
|
static std::string_view getProgramTypeName(program_type_es type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case PT_FAKE: return "PT_FAKE";
|
case PT_FAKE:
|
||||||
case PT_NPDRM_EXEC: return "PT_NPDRM_EXEC";
|
return "PT_FAKE";
|
||||||
case PT_NPDRM_DYNLIB: return "PT_NPDRM_DYNLIB";
|
case PT_NPDRM_EXEC:
|
||||||
case PT_SYSTEM_EXEC: return "PT_SYSTEM_EXEC";
|
return "PT_NPDRM_EXEC";
|
||||||
case PT_SYSTEM_DYNLIB: return "PT_SYSTEM_DYNLIB";
|
case PT_NPDRM_DYNLIB:
|
||||||
case PT_HOST_KERNEL: return "PT_HOST_KERNEL";
|
return "PT_NPDRM_DYNLIB";
|
||||||
case PT_SECURE_MODULE: return "PT_SECURE_MODULE";
|
case PT_SYSTEM_EXEC:
|
||||||
case PT_SECURE_KERNEL: return "PT_SECURE_KERNEL";
|
return "PT_SYSTEM_EXEC";
|
||||||
default: return "INVALID";
|
case PT_SYSTEM_DYNLIB:
|
||||||
|
return "PT_SYSTEM_DYNLIB";
|
||||||
|
case PT_HOST_KERNEL:
|
||||||
|
return "PT_HOST_KERNEL";
|
||||||
|
case PT_SECURE_MODULE:
|
||||||
|
return "PT_SECURE_MODULE";
|
||||||
|
case PT_SECURE_KERNEL:
|
||||||
|
return "PT_SECURE_KERNEL";
|
||||||
|
default:
|
||||||
|
return "INVALID";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string_view getIdentClassName(ident_class_es elf_class) {
|
static std::string_view getIdentClassName(ident_class_es elf_class) {
|
||||||
switch (elf_class) {
|
switch (elf_class) {
|
||||||
case ELF_CLASS_NONE: return "ELF_CLASS_NONE";
|
case ELF_CLASS_NONE:
|
||||||
case ELF_CLASS_32: return "ELF_CLASS_32";
|
return "ELF_CLASS_NONE";
|
||||||
case ELF_CLASS_64: return "ELF_CLASS_64";
|
case ELF_CLASS_32:
|
||||||
case ELF_CLASS_NUM: return "ELF_CLASS_NUM";
|
return "ELF_CLASS_32";
|
||||||
default: return "INVALID";
|
case ELF_CLASS_64:
|
||||||
|
return "ELF_CLASS_64";
|
||||||
|
case ELF_CLASS_NUM:
|
||||||
|
return "ELF_CLASS_NUM";
|
||||||
|
default:
|
||||||
|
return "INVALID";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string_view getIdentEndianName(ident_endian_es endian) {
|
static std::string_view getIdentEndianName(ident_endian_es endian) {
|
||||||
switch (endian) {
|
switch (endian) {
|
||||||
case ELF_DATA_NONE: return "ELF_DATA_NONE";
|
case ELF_DATA_NONE:
|
||||||
case ELF_DATA_2LSB: return "ELF_DATA_2LSB";
|
return "ELF_DATA_NONE";
|
||||||
case ELF_DATA_2MSB: return "ELF_DATA_2MSB";
|
case ELF_DATA_2LSB:
|
||||||
case ELF_DATA_NUM: return "ELF_DATA_NUM";
|
return "ELF_DATA_2LSB";
|
||||||
default: return "INVALID";
|
case ELF_DATA_2MSB:
|
||||||
|
return "ELF_DATA_2MSB";
|
||||||
|
case ELF_DATA_NUM:
|
||||||
|
return "ELF_DATA_NUM";
|
||||||
|
default:
|
||||||
|
return "INVALID";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string_view getIdentVersionName(ident_version_es version) {
|
static std::string_view getIdentVersionName(ident_version_es version) {
|
||||||
switch (version) {
|
switch (version) {
|
||||||
case ELF_VERSION_NONE: return "ELF_VERSION_NONE";
|
case ELF_VERSION_NONE:
|
||||||
case ELF_VERSION_CURRENT: return "ELF_VERSION_CURRENT";
|
return "ELF_VERSION_NONE";
|
||||||
case ELF_VERSION_NUM: return "ELF_VERSION_NUM";
|
case ELF_VERSION_CURRENT:
|
||||||
default: return "INVALID";
|
return "ELF_VERSION_CURRENT";
|
||||||
|
case ELF_VERSION_NUM:
|
||||||
|
return "ELF_VERSION_NUM";
|
||||||
|
default:
|
||||||
|
return "INVALID";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string_view getIdentOsabiName(ident_osabi_es osabi) {
|
static std::string_view getIdentOsabiName(ident_osabi_es osabi) {
|
||||||
switch (osabi) {
|
switch (osabi) {
|
||||||
case ELF_OSABI_NONE: return "ELF_OSABI_NONE";
|
case ELF_OSABI_NONE:
|
||||||
case ELF_OSABI_HPUX: return "ELF_OSABI_HPUX";
|
return "ELF_OSABI_NONE";
|
||||||
case ELF_OSABI_NETBSD: return "ELF_OSABI_NETBSD";
|
case ELF_OSABI_HPUX:
|
||||||
case ELF_OSABI_LINUX: return "ELF_OSABI_LINUX";
|
return "ELF_OSABI_HPUX";
|
||||||
case ELF_OSABI_SOLARIS: return "ELF_OSABI_SOLARIS";
|
case ELF_OSABI_NETBSD:
|
||||||
case ELF_OSABI_AIX: return "ELF_OSABI_AIX";
|
return "ELF_OSABI_NETBSD";
|
||||||
case ELF_OSABI_IRIX: return "ELF_OSABI_IRIX";
|
case ELF_OSABI_LINUX:
|
||||||
case ELF_OSABI_FREEBSD: return "ELF_OSABI_FREEBSD";
|
return "ELF_OSABI_LINUX";
|
||||||
case ELF_OSABI_TRU64: return "ELF_OSABI_TRU64";
|
case ELF_OSABI_SOLARIS:
|
||||||
case ELF_OSABI_MODESTO: return "ELF_OSABI_MODESTO";
|
return "ELF_OSABI_SOLARIS";
|
||||||
case ELF_OSABI_OPENBSD: return "ELF_OSABI_OPENBSD";
|
case ELF_OSABI_AIX:
|
||||||
case ELF_OSABI_OPENVMS: return "ELF_OSABI_OPENVMS";
|
return "ELF_OSABI_AIX";
|
||||||
case ELF_OSABI_NSK: return "ELF_OSABI_NSK";
|
case ELF_OSABI_IRIX:
|
||||||
case ELF_OSABI_AROS: return "ELF_OSABI_AROS";
|
return "ELF_OSABI_IRIX";
|
||||||
case ELF_OSABI_ARM_AEABI: return "ELF_OSABI_ARM_AEABI";
|
case ELF_OSABI_FREEBSD:
|
||||||
case ELF_OSABI_ARM: return "ELF_OSABI_ARM";
|
return "ELF_OSABI_FREEBSD";
|
||||||
case ELF_OSABI_STANDALONE: return "ELF_OSABI_STANDALONE";
|
case ELF_OSABI_TRU64:
|
||||||
default: return "INVALID";
|
return "ELF_OSABI_TRU64";
|
||||||
|
case ELF_OSABI_MODESTO:
|
||||||
|
return "ELF_OSABI_MODESTO";
|
||||||
|
case ELF_OSABI_OPENBSD:
|
||||||
|
return "ELF_OSABI_OPENBSD";
|
||||||
|
case ELF_OSABI_OPENVMS:
|
||||||
|
return "ELF_OSABI_OPENVMS";
|
||||||
|
case ELF_OSABI_NSK:
|
||||||
|
return "ELF_OSABI_NSK";
|
||||||
|
case ELF_OSABI_AROS:
|
||||||
|
return "ELF_OSABI_AROS";
|
||||||
|
case ELF_OSABI_ARM_AEABI:
|
||||||
|
return "ELF_OSABI_ARM_AEABI";
|
||||||
|
case ELF_OSABI_ARM:
|
||||||
|
return "ELF_OSABI_ARM";
|
||||||
|
case ELF_OSABI_STANDALONE:
|
||||||
|
return "ELF_OSABI_STANDALONE";
|
||||||
|
default:
|
||||||
|
return "INVALID";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string_view getIdentAbiversionName(ident_abiversion_es version) {
|
static std::string_view getIdentAbiversionName(ident_abiversion_es version) {
|
||||||
switch (version) {
|
switch (version) {
|
||||||
case ELF_ABI_VERSION_AMDGPU_HSA_V2: return "ELF_ABI_VERSION_AMDGPU_HSA_V2";
|
case ELF_ABI_VERSION_AMDGPU_HSA_V2:
|
||||||
case ELF_ABI_VERSION_AMDGPU_HSA_V3: return "ELF_ABI_VERSION_AMDGPU_HSA_V3";
|
return "ELF_ABI_VERSION_AMDGPU_HSA_V2";
|
||||||
case ELF_ABI_VERSION_AMDGPU_HSA_V4: return "ELF_ABI_VERSION_AMDGPU_HSA_V4";
|
case ELF_ABI_VERSION_AMDGPU_HSA_V3:
|
||||||
case ELF_ABI_VERSION_AMDGPU_HSA_V5: return "ELF_ABI_VERSION_AMDGPU_HSA_V5";
|
return "ELF_ABI_VERSION_AMDGPU_HSA_V3";
|
||||||
default: return "INVALID";
|
case ELF_ABI_VERSION_AMDGPU_HSA_V4:
|
||||||
|
return "ELF_ABI_VERSION_AMDGPU_HSA_V4";
|
||||||
|
case ELF_ABI_VERSION_AMDGPU_HSA_V5:
|
||||||
|
return "ELF_ABI_VERSION_AMDGPU_HSA_V5";
|
||||||
|
default:
|
||||||
|
return "INVALID";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static std::string_view getVersion(e_version_es version) {
|
static std::string_view getVersion(e_version_es version) {
|
||||||
switch (version) {
|
switch (version) {
|
||||||
case EV_NONE: return "EV_NONE";
|
case EV_NONE:
|
||||||
case EV_CURRENT: return "EV_CURRENT";
|
return "EV_NONE";
|
||||||
default: return "INVALID";
|
case EV_CURRENT:
|
||||||
|
return "EV_CURRENT";
|
||||||
|
default:
|
||||||
|
return "INVALID";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string_view getType(e_type_s type) {
|
static std::string_view getType(e_type_s type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ET_NONE: return "ET_NONE";
|
case ET_NONE:
|
||||||
case ET_REL: return "ET_REL";
|
return "ET_NONE";
|
||||||
case ET_EXEC: return "ET_EXEC";
|
case ET_REL:
|
||||||
case ET_DYN: return "ET_DYN";
|
return "ET_REL";
|
||||||
case ET_CORE: return "ET_CORE";
|
case ET_EXEC:
|
||||||
case ET_SCE_EXEC: return "ET_SCE_EXEC";
|
return "ET_EXEC";
|
||||||
case ET_SCE_STUBLIB: return "ET_SCE_STUBLIB";
|
case ET_DYN:
|
||||||
case ET_SCE_DYNEXEC: return "ET_SCE_DYNEXEC";
|
return "ET_DYN";
|
||||||
case ET_SCE_DYNAMIC: return "ET_SCE_DYNAMIC";
|
case ET_CORE:
|
||||||
default: return "INVALID";
|
return "ET_CORE";
|
||||||
|
case ET_SCE_EXEC:
|
||||||
|
return "ET_SCE_EXEC";
|
||||||
|
case ET_SCE_STUBLIB:
|
||||||
|
return "ET_SCE_STUBLIB";
|
||||||
|
case ET_SCE_DYNEXEC:
|
||||||
|
return "ET_SCE_DYNEXEC";
|
||||||
|
case ET_SCE_DYNAMIC:
|
||||||
|
return "ET_SCE_DYNAMIC";
|
||||||
|
default:
|
||||||
|
return "INVALID";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string_view getMachine(e_machine_es machine) {
|
static std::string_view getMachine(e_machine_es machine) {
|
||||||
switch (machine) {
|
switch (machine) {
|
||||||
case EM_X86_64: return "EM_X86_64";
|
case EM_X86_64:
|
||||||
default: return "INVALID";
|
return "EM_X86_64";
|
||||||
|
default:
|
||||||
|
return "INVALID";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Elf::~Elf() { Reset(); }
|
Elf::~Elf() {
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
void Elf::Reset() { m_f.close(); }
|
void Elf::Reset() {
|
||||||
|
m_f.close();
|
||||||
|
}
|
||||||
|
|
||||||
void Elf::Open(const std::string& file_name) {
|
void Elf::Open(const std::string& file_name) {
|
||||||
Reset();
|
Reset();
|
||||||
|
@ -156,7 +221,7 @@ void Elf::Open(const std::string& file_name) {
|
||||||
header_size += m_elf_header.e_phnum * m_elf_header.e_phentsize;
|
header_size += m_elf_header.e_phnum * m_elf_header.e_phentsize;
|
||||||
header_size += m_elf_header.e_shnum * m_elf_header.e_shentsize;
|
header_size += m_elf_header.e_shnum * m_elf_header.e_shentsize;
|
||||||
header_size += 15;
|
header_size += 15;
|
||||||
header_size &= ~15; // Align
|
header_size &= ~15; // Align
|
||||||
|
|
||||||
if (m_elf_header.e_ehsize - header_size >= sizeof(elf_program_id_header)) {
|
if (m_elf_header.e_ehsize - header_size >= sizeof(elf_program_id_header)) {
|
||||||
m_f.seek(header_size, Common::FS::SeekMode::Set);
|
m_f.seek(header_size, Common::FS::SeekMode::Set);
|
||||||
|
@ -169,12 +234,14 @@ void Elf::Open(const std::string& file_name) {
|
||||||
|
|
||||||
bool Elf::isSelfFile() const {
|
bool Elf::isSelfFile() const {
|
||||||
if (m_self.magic != self_header::signature) [[unlikely]] {
|
if (m_self.magic != self_header::signature) [[unlikely]] {
|
||||||
LOG_ERROR_IF(log_file_loader, "Not a SELF file.Magic file mismatched !current = {:#x} required = {:#x}\n ", m_self.magic,
|
LOG_ERROR_IF(log_file_loader,
|
||||||
self_header::signature);
|
"Not a SELF file.Magic file mismatched !current = {:#x} required = {:#x}\n ",
|
||||||
|
m_self.magic, self_header::signature);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_self.version != 0x00 || m_self.mode != 0x01 || m_self.endian != 0x01 || m_self.attributes != 0x12) [[unlikely]] {
|
if (m_self.version != 0x00 || m_self.mode != 0x01 || m_self.endian != 0x01 ||
|
||||||
|
m_self.attributes != 0x12) [[unlikely]] {
|
||||||
LOG_ERROR_IF(log_file_loader, "Unknown SELF file\n");
|
LOG_ERROR_IF(log_file_loader, "Unknown SELF file\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -188,60 +255,74 @@ bool Elf::isSelfFile() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Elf::isElfFile() const {
|
bool Elf::isElfFile() const {
|
||||||
if (m_elf_header.e_ident.magic[EI_MAG0] != ELFMAG0 || m_elf_header.e_ident.magic[EI_MAG1] != ELFMAG1 ||
|
if (m_elf_header.e_ident.magic[EI_MAG0] != ELFMAG0 ||
|
||||||
m_elf_header.e_ident.magic[EI_MAG2] != ELFMAG2 || m_elf_header.e_ident.magic[EI_MAG3] != ELFMAG3) {
|
m_elf_header.e_ident.magic[EI_MAG1] != ELFMAG1 ||
|
||||||
|
m_elf_header.e_ident.magic[EI_MAG2] != ELFMAG2 ||
|
||||||
|
m_elf_header.e_ident.magic[EI_MAG3] != ELFMAG3) {
|
||||||
LOG_ERROR_IF(log_file_loader, "Not an ELF file magic is wrong!\n");
|
LOG_ERROR_IF(log_file_loader, "Not an ELF file magic is wrong!\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (m_elf_header.e_ident.ei_class != ELF_CLASS_64) {
|
if (m_elf_header.e_ident.ei_class != ELF_CLASS_64) {
|
||||||
LOG_ERROR_IF(log_file_loader, "e_ident[EI_CLASS] expected 0x02 is ({:#x})\n", static_cast<u32>(m_elf_header.e_ident.ei_class));
|
LOG_ERROR_IF(log_file_loader, "e_ident[EI_CLASS] expected 0x02 is ({:#x})\n",
|
||||||
|
static_cast<u32>(m_elf_header.e_ident.ei_class));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_elf_header.e_ident.ei_data != ELF_DATA_2LSB) {
|
if (m_elf_header.e_ident.ei_data != ELF_DATA_2LSB) {
|
||||||
LOG_ERROR_IF(log_file_loader, "e_ident[EI_DATA] expected 0x01 is ({:#x})\n", static_cast<u32>(m_elf_header.e_ident.ei_data));
|
LOG_ERROR_IF(log_file_loader, "e_ident[EI_DATA] expected 0x01 is ({:#x})\n",
|
||||||
|
static_cast<u32>(m_elf_header.e_ident.ei_data));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_elf_header.e_ident.ei_version != ELF_VERSION_CURRENT) {
|
if (m_elf_header.e_ident.ei_version != ELF_VERSION_CURRENT) {
|
||||||
LOG_ERROR_IF(log_file_loader, "e_ident[EI_VERSION] expected 0x01 is ({:#x})\n", static_cast<u32>(m_elf_header.e_ident.ei_version));
|
LOG_ERROR_IF(log_file_loader, "e_ident[EI_VERSION] expected 0x01 is ({:#x})\n",
|
||||||
|
static_cast<u32>(m_elf_header.e_ident.ei_version));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_elf_header.e_ident.ei_osabi != ELF_OSABI_FREEBSD) {
|
if (m_elf_header.e_ident.ei_osabi != ELF_OSABI_FREEBSD) {
|
||||||
LOG_ERROR_IF(log_file_loader, "e_ident[EI_OSABI] expected 0x09 is ({:#x})\n", static_cast<u32>(m_elf_header.e_ident.ei_osabi));
|
LOG_ERROR_IF(log_file_loader, "e_ident[EI_OSABI] expected 0x09 is ({:#x})\n",
|
||||||
|
static_cast<u32>(m_elf_header.e_ident.ei_osabi));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_elf_header.e_ident.ei_abiversion != ELF_ABI_VERSION_AMDGPU_HSA_V2) {
|
if (m_elf_header.e_ident.ei_abiversion != ELF_ABI_VERSION_AMDGPU_HSA_V2) {
|
||||||
LOG_ERROR_IF(log_file_loader, "e_ident[EI_ABIVERSION] expected 0x00 is ({:#x})\n", static_cast<u32>(m_elf_header.e_ident.ei_abiversion));
|
LOG_ERROR_IF(log_file_loader, "e_ident[EI_ABIVERSION] expected 0x00 is ({:#x})\n",
|
||||||
|
static_cast<u32>(m_elf_header.e_ident.ei_abiversion));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_elf_header.e_type != ET_SCE_DYNEXEC && m_elf_header.e_type != ET_SCE_DYNAMIC && m_elf_header.e_type != ET_SCE_EXEC) {
|
if (m_elf_header.e_type != ET_SCE_DYNEXEC && m_elf_header.e_type != ET_SCE_DYNAMIC &&
|
||||||
LOG_ERROR_IF(log_file_loader, "e_type expected 0xFE10 OR 0xFE18 OR 0xfe00 is ({:#x})\n", static_cast<u32>(m_elf_header.e_type));
|
m_elf_header.e_type != ET_SCE_EXEC) {
|
||||||
|
LOG_ERROR_IF(log_file_loader, "e_type expected 0xFE10 OR 0xFE18 OR 0xfe00 is ({:#x})\n",
|
||||||
|
static_cast<u32>(m_elf_header.e_type));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_elf_header.e_machine != EM_X86_64) {
|
if (m_elf_header.e_machine != EM_X86_64) {
|
||||||
LOG_ERROR_IF(log_file_loader, "e_machine expected 0x3E is ({:#x})\n", static_cast<u32>(m_elf_header.e_machine));
|
LOG_ERROR_IF(log_file_loader, "e_machine expected 0x3E is ({:#x})\n",
|
||||||
|
static_cast<u32>(m_elf_header.e_machine));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_elf_header.e_version != EV_CURRENT) {
|
if (m_elf_header.e_version != EV_CURRENT) {
|
||||||
LOG_ERROR_IF(log_file_loader, "m_elf_header.e_version expected 0x01 is ({:#x})\n", static_cast<u32>(m_elf_header.e_version));
|
LOG_ERROR_IF(log_file_loader, "m_elf_header.e_version expected 0x01 is ({:#x})\n",
|
||||||
|
static_cast<u32>(m_elf_header.e_version));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_elf_header.e_phentsize != sizeof(elf_program_header)) {
|
if (m_elf_header.e_phentsize != sizeof(elf_program_header)) {
|
||||||
LOG_ERROR_IF(log_file_loader, "e_phentsize ({}) != sizeof(elf_program_header)\n", static_cast<u32>(m_elf_header.e_phentsize));
|
LOG_ERROR_IF(log_file_loader, "e_phentsize ({}) != sizeof(elf_program_header)\n",
|
||||||
|
static_cast<u32>(m_elf_header.e_phentsize));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_elf_header.e_shentsize > 0 &&
|
if (m_elf_header.e_shentsize > 0 &&
|
||||||
m_elf_header.e_shentsize != sizeof(elf_section_header)) // Commercial games doesn't appear to have section headers
|
m_elf_header.e_shentsize !=
|
||||||
|
sizeof(elf_section_header)) // Commercial games doesn't appear to have section headers
|
||||||
{
|
{
|
||||||
LOG_ERROR_IF(log_file_loader, "e_shentsize ({}) != sizeof(elf_section_header)\n", m_elf_header.e_shentsize);
|
LOG_ERROR_IF(log_file_loader, "e_shentsize ({}) != sizeof(elf_section_header)\n",
|
||||||
|
m_elf_header.e_shentsize);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +330,7 @@ bool Elf::isElfFile() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Elf::DebugDump() {
|
void Elf::DebugDump() {
|
||||||
if (is_self) { // If we load elf instead
|
if (is_self) { // If we load elf instead
|
||||||
LOG_INFO_IF(log_file_loader, (SElfHeaderStr()));
|
LOG_INFO_IF(log_file_loader, (SElfHeaderStr()));
|
||||||
for (u16 i = 0; i < m_self.segment_count; i++) {
|
for (u16 i = 0; i < m_self.segment_count; i++) {
|
||||||
LOG_INFO_IF(log_file_loader, SELFSegHeader(i));
|
LOG_INFO_IF(log_file_loader, SELFSegHeader(i));
|
||||||
|
@ -276,7 +357,8 @@ void Elf::DebugDump() {
|
||||||
LOG_INFO_IF(log_file_loader, "sh_size ........: {:#018x}\n", m_elf_shdr[i].sh_size);
|
LOG_INFO_IF(log_file_loader, "sh_size ........: {:#018x}\n", m_elf_shdr[i].sh_size);
|
||||||
LOG_INFO_IF(log_file_loader, "sh_link ........: {:#010x}\n", m_elf_shdr[i].sh_link);
|
LOG_INFO_IF(log_file_loader, "sh_link ........: {:#010x}\n", m_elf_shdr[i].sh_link);
|
||||||
LOG_INFO_IF(log_file_loader, "sh_info ........: {:#010x}\n", m_elf_shdr[i].sh_info);
|
LOG_INFO_IF(log_file_loader, "sh_info ........: {:#010x}\n", m_elf_shdr[i].sh_info);
|
||||||
LOG_INFO_IF(log_file_loader, "sh_addralign ...: {:#018x}\n", m_elf_shdr[i].sh_addralign);
|
LOG_INFO_IF(log_file_loader, "sh_addralign ...: {:#018x}\n",
|
||||||
|
m_elf_shdr[i].sh_addralign);
|
||||||
LOG_INFO_IF(log_file_loader, "sh_entsize .....: {:#018x}\n", m_elf_shdr[i].sh_entsize);
|
LOG_INFO_IF(log_file_loader, "sh_entsize .....: {:#018x}\n", m_elf_shdr[i].sh_entsize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -284,7 +366,8 @@ void Elf::DebugDump() {
|
||||||
if (is_self) {
|
if (is_self) {
|
||||||
LOG_INFO_IF(log_file_loader, "SELF info:\n");
|
LOG_INFO_IF(log_file_loader, "SELF info:\n");
|
||||||
LOG_INFO_IF(log_file_loader, "auth id ............: {:#018x}\n", m_self_id_header.authid);
|
LOG_INFO_IF(log_file_loader, "auth id ............: {:#018x}\n", m_self_id_header.authid);
|
||||||
LOG_INFO_IF(log_file_loader, "program type .......: {}\n", getProgramTypeName(m_self_id_header.program_type));
|
LOG_INFO_IF(log_file_loader, "program type .......: {}\n",
|
||||||
|
getProgramTypeName(m_self_id_header.program_type));
|
||||||
LOG_INFO_IF(log_file_loader, "app version ........: {:#018x}\n", m_self_id_header.appver);
|
LOG_INFO_IF(log_file_loader, "app version ........: {:#018x}\n", m_self_id_header.appver);
|
||||||
LOG_INFO_IF(log_file_loader, "fw version .........: {:#018x}\n", m_self_id_header.firmver);
|
LOG_INFO_IF(log_file_loader, "fw version .........: {:#018x}\n", m_self_id_header.firmver);
|
||||||
std::string digest;
|
std::string digest;
|
||||||
|
@ -333,11 +416,16 @@ std::string Elf::ElfHeaderStr() {
|
||||||
}
|
}
|
||||||
header += fmt::format("\n");
|
header += fmt::format("\n");
|
||||||
|
|
||||||
header += fmt::format("ident class.......: {}\n", getIdentClassName(m_elf_header.e_ident.ei_class));
|
header +=
|
||||||
header += fmt::format("ident data .......: {}\n", getIdentEndianName(m_elf_header.e_ident.ei_data));
|
fmt::format("ident class.......: {}\n", getIdentClassName(m_elf_header.e_ident.ei_class));
|
||||||
header += fmt::format("ident version.....: {}\n", getIdentVersionName(m_elf_header.e_ident.ei_version));
|
header +=
|
||||||
header += fmt::format("ident osabi .....: {}\n", getIdentOsabiName(m_elf_header.e_ident.ei_osabi));
|
fmt::format("ident data .......: {}\n", getIdentEndianName(m_elf_header.e_ident.ei_data));
|
||||||
header += fmt::format("ident abiversion..: {}\n", getIdentAbiversionName(m_elf_header.e_ident.ei_abiversion));
|
header += fmt::format("ident version.....: {}\n",
|
||||||
|
getIdentVersionName(m_elf_header.e_ident.ei_version));
|
||||||
|
header +=
|
||||||
|
fmt::format("ident osabi .....: {}\n", getIdentOsabiName(m_elf_header.e_ident.ei_osabi));
|
||||||
|
header += fmt::format("ident abiversion..: {}\n",
|
||||||
|
getIdentAbiversionName(m_elf_header.e_ident.ei_abiversion));
|
||||||
|
|
||||||
header += fmt::format("ident UNK ........: 0x");
|
header += fmt::format("ident UNK ........: 0x");
|
||||||
for (auto i : m_elf_header.e_ident.pad) {
|
for (auto i : m_elf_header.e_ident.pad) {
|
||||||
|
@ -363,26 +451,46 @@ std::string Elf::ElfHeaderStr() {
|
||||||
|
|
||||||
std::string Elf::ElfPheaderTypeStr(u32 type) {
|
std::string Elf::ElfPheaderTypeStr(u32 type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case PT_NULL: return "Null";
|
case PT_NULL:
|
||||||
case PT_LOAD: return "Loadable";
|
return "Null";
|
||||||
case PT_DYNAMIC: return "Dynamic";
|
case PT_LOAD:
|
||||||
case PT_INTERP: return "Interpreter Path";
|
return "Loadable";
|
||||||
case PT_NOTE: return "Note";
|
case PT_DYNAMIC:
|
||||||
case PT_SHLIB: return "Section Header Library";
|
return "Dynamic";
|
||||||
case PT_PHDR: return "Program Header";
|
case PT_INTERP:
|
||||||
case PT_TLS: return "Thread-Local Storage";
|
return "Interpreter Path";
|
||||||
case PT_NUM: return "Defined Sections Number";
|
case PT_NOTE:
|
||||||
case PT_SCE_RELA: return "SCE Relative";
|
return "Note";
|
||||||
case PT_SCE_DYNLIBDATA: return "SCE Dynamic Library Data";
|
case PT_SHLIB:
|
||||||
case PT_SCE_PROCPARAM: return "SCE Processor Parameters";
|
return "Section Header Library";
|
||||||
case PT_SCE_MODULE_PARAM: return "SCE Module Parameters";
|
case PT_PHDR:
|
||||||
case PT_SCE_RELRO: return "SCE Read-Only After Relocation";
|
return "Program Header";
|
||||||
case PT_GNU_EH_FRAME: return "GNU Entry Header Frame";
|
case PT_TLS:
|
||||||
case PT_GNU_STACK: return "GNU Stack (executability)";
|
return "Thread-Local Storage";
|
||||||
case PT_GNU_RELRO: return "GNU Read-Only After Relocation";
|
case PT_NUM:
|
||||||
case PT_SCE_COMMENT: return "SCE Comment";
|
return "Defined Sections Number";
|
||||||
case PT_SCE_LIBVERSION: return "SCE Library Version";
|
case PT_SCE_RELA:
|
||||||
default: return "Unknown Section";
|
return "SCE Relative";
|
||||||
|
case PT_SCE_DYNLIBDATA:
|
||||||
|
return "SCE Dynamic Library Data";
|
||||||
|
case PT_SCE_PROCPARAM:
|
||||||
|
return "SCE Processor Parameters";
|
||||||
|
case PT_SCE_MODULE_PARAM:
|
||||||
|
return "SCE Module Parameters";
|
||||||
|
case PT_SCE_RELRO:
|
||||||
|
return "SCE Read-Only After Relocation";
|
||||||
|
case PT_GNU_EH_FRAME:
|
||||||
|
return "GNU Entry Header Frame";
|
||||||
|
case PT_GNU_STACK:
|
||||||
|
return "GNU Stack (executability)";
|
||||||
|
case PT_GNU_RELRO:
|
||||||
|
return "GNU Read-Only After Relocation";
|
||||||
|
case PT_SCE_COMMENT:
|
||||||
|
return "SCE Comment";
|
||||||
|
case PT_SCE_LIBVERSION:
|
||||||
|
return "SCE Library Version";
|
||||||
|
default:
|
||||||
|
return "Unknown Section";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,7 +539,7 @@ void Elf::LoadSegment(u64 virtual_addr, u64 file_offset, u64 size) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BREAKPOINT(); // Hmm we didn't return something...
|
BREAKPOINT(); // Hmm we didn't return something...
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core::Loader
|
} // namespace Core::Loader
|
||||||
|
|
|
@ -14,7 +14,7 @@ struct self_header {
|
||||||
u32 magic;
|
u32 magic;
|
||||||
u08 version;
|
u08 version;
|
||||||
u08 mode;
|
u08 mode;
|
||||||
u08 endian; // 1 is little endian
|
u08 endian; // 1 is little endian
|
||||||
u08 attributes;
|
u08 attributes;
|
||||||
u08 category;
|
u08 category;
|
||||||
u08 program_type;
|
u08 program_type;
|
||||||
|
@ -24,31 +24,33 @@ struct self_header {
|
||||||
u32 file_size;
|
u32 file_size;
|
||||||
u32 padding2;
|
u32 padding2;
|
||||||
u16 segment_count;
|
u16 segment_count;
|
||||||
u16 unknown1A; // always 0x22
|
u16 unknown1A; // always 0x22
|
||||||
u32 padding3;
|
u32 padding3;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct self_segment_header {
|
struct self_segment_header {
|
||||||
bool IsBlocked() const {
|
bool IsBlocked() const {
|
||||||
return (flags & 0x800) != 0; // 0 or 0x800
|
return (flags & 0x800) != 0; // 0 or 0x800
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GetId() const { return (flags >> 20u) & 0xFFFu; }
|
u32 GetId() const {
|
||||||
|
return (flags >> 20u) & 0xFFFu;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsOrdered() const {
|
bool IsOrdered() const {
|
||||||
return (flags & 1) != 0; // 0 or 1
|
return (flags & 1) != 0; // 0 or 1
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsEncrypted() const {
|
bool IsEncrypted() const {
|
||||||
return (flags & 2) != 0; // 0 or 2
|
return (flags & 2) != 0; // 0 or 2
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsSigned() const {
|
bool IsSigned() const {
|
||||||
return (flags & 4) != 0; // 0 or 4
|
return (flags & 4) != 0; // 0 or 4
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsCompressed() const {
|
bool IsCompressed() const {
|
||||||
return (flags & 8) != 0; // 0 or 8
|
return (flags & 8) != 0; // 0 or 8
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 flags;
|
u64 flags;
|
||||||
|
@ -181,11 +183,25 @@ typedef enum : u16 {
|
||||||
|
|
||||||
typedef enum : u32 { EV_NONE = 0x0, EV_CURRENT = 0x1 } e_version_es;
|
typedef enum : u32 { EV_NONE = 0x0, EV_CURRENT = 0x1 } e_version_es;
|
||||||
|
|
||||||
typedef enum : u08 { ELF_CLASS_NONE = 0x0, ELF_CLASS_32 = 0x1, ELF_CLASS_64 = 0x2, ELF_CLASS_NUM = 0x3 } ident_class_es;
|
typedef enum : u08 {
|
||||||
|
ELF_CLASS_NONE = 0x0,
|
||||||
|
ELF_CLASS_32 = 0x1,
|
||||||
|
ELF_CLASS_64 = 0x2,
|
||||||
|
ELF_CLASS_NUM = 0x3
|
||||||
|
} ident_class_es;
|
||||||
|
|
||||||
typedef enum : u08 { ELF_DATA_NONE = 0x0, ELF_DATA_2LSB = 0x1, ELF_DATA_2MSB = 0x2, ELF_DATA_NUM = 0x3 } ident_endian_es;
|
typedef enum : u08 {
|
||||||
|
ELF_DATA_NONE = 0x0,
|
||||||
|
ELF_DATA_2LSB = 0x1,
|
||||||
|
ELF_DATA_2MSB = 0x2,
|
||||||
|
ELF_DATA_NUM = 0x3
|
||||||
|
} ident_endian_es;
|
||||||
|
|
||||||
typedef enum : u08 { ELF_VERSION_NONE = 0x0, ELF_VERSION_CURRENT = 0x1, ELF_VERSION_NUM = 0x2 } ident_version_es;
|
typedef enum : u08 {
|
||||||
|
ELF_VERSION_NONE = 0x0,
|
||||||
|
ELF_VERSION_CURRENT = 0x1,
|
||||||
|
ELF_VERSION_NUM = 0x2
|
||||||
|
} ident_version_es;
|
||||||
|
|
||||||
typedef enum : u08 {
|
typedef enum : u08 {
|
||||||
ELF_OSABI_NONE = 0x0, /* No extensions or unspecified */
|
ELF_OSABI_NONE = 0x0, /* No extensions or unspecified */
|
||||||
|
@ -383,7 +399,7 @@ constexpr u08 STT_FILE = 4;
|
||||||
constexpr u08 STT_COMMON = 5;
|
constexpr u08 STT_COMMON = 5;
|
||||||
constexpr u08 STT_TLS = 6;
|
constexpr u08 STT_TLS = 6;
|
||||||
constexpr u08 STT_LOOS = 10;
|
constexpr u08 STT_LOOS = 10;
|
||||||
constexpr u08 STT_SCE = 11; // module_start/module_stop
|
constexpr u08 STT_SCE = 11; // module_start/module_stop
|
||||||
constexpr u08 STT_HIOS = 12;
|
constexpr u08 STT_HIOS = 12;
|
||||||
constexpr u08 STT_LOPRO = 13;
|
constexpr u08 STT_LOPRO = 13;
|
||||||
constexpr u08 STT_SPARC_REGISTER = 13;
|
constexpr u08 STT_SPARC_REGISTER = 13;
|
||||||
|
@ -395,9 +411,15 @@ constexpr u08 STV_HIDDEN = 2;
|
||||||
constexpr u08 STV_PROTECTED = 3;
|
constexpr u08 STV_PROTECTED = 3;
|
||||||
|
|
||||||
struct elf_symbol {
|
struct elf_symbol {
|
||||||
u08 GetBind() const { return st_info >> 4u; }
|
u08 GetBind() const {
|
||||||
u08 GetType() const { return st_info & 0xfu; }
|
return st_info >> 4u;
|
||||||
u08 GetVisibility() const { return st_other & 3u; }
|
}
|
||||||
|
u08 GetType() const {
|
||||||
|
return st_info & 0xfu;
|
||||||
|
}
|
||||||
|
u08 GetVisibility() const {
|
||||||
|
return st_other & 3u;
|
||||||
|
}
|
||||||
|
|
||||||
u32 st_name;
|
u32 st_name;
|
||||||
u08 st_info;
|
u08 st_info;
|
||||||
|
@ -408,23 +430,27 @@ struct elf_symbol {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct elf_relocation {
|
struct elf_relocation {
|
||||||
u32 GetSymbol() const { return static_cast<u32>(rel_info >> 32u); }
|
u32 GetSymbol() const {
|
||||||
u32 GetType() const { return static_cast<u32>(rel_info & 0xffffffff); }
|
return static_cast<u32>(rel_info >> 32u);
|
||||||
|
}
|
||||||
|
u32 GetType() const {
|
||||||
|
return static_cast<u32>(rel_info & 0xffffffff);
|
||||||
|
}
|
||||||
|
|
||||||
u64 rel_offset;
|
u64 rel_offset;
|
||||||
u64 rel_info;
|
u64 rel_info;
|
||||||
s64 rel_addend;
|
s64 rel_addend;
|
||||||
};
|
};
|
||||||
constexpr u32 R_X86_64_64 = 1; // Direct 64 bit
|
constexpr u32 R_X86_64_64 = 1; // Direct 64 bit
|
||||||
constexpr u32 R_X86_64_GLOB_DAT = 6;
|
constexpr u32 R_X86_64_GLOB_DAT = 6;
|
||||||
constexpr u32 R_X86_64_JUMP_SLOT = 7; // Create PLT entry
|
constexpr u32 R_X86_64_JUMP_SLOT = 7; // Create PLT entry
|
||||||
constexpr u32 R_X86_64_RELATIVE = 8; // Adjust by program base
|
constexpr u32 R_X86_64_RELATIVE = 8; // Adjust by program base
|
||||||
constexpr u32 R_X86_64_DTPMOD64 = 16;
|
constexpr u32 R_X86_64_DTPMOD64 = 16;
|
||||||
|
|
||||||
namespace Core::Loader {
|
namespace Core::Loader {
|
||||||
|
|
||||||
class Elf {
|
class Elf {
|
||||||
public:
|
public:
|
||||||
Elf() = default;
|
Elf() = default;
|
||||||
virtual ~Elf();
|
virtual ~Elf();
|
||||||
|
|
||||||
|
@ -433,15 +459,25 @@ class Elf {
|
||||||
bool isElfFile() const;
|
bool isElfFile() const;
|
||||||
void DebugDump();
|
void DebugDump();
|
||||||
|
|
||||||
[[nodiscard]] self_header GetSElfHeader() const { return m_self; }
|
[[nodiscard]] self_header GetSElfHeader() const {
|
||||||
|
return m_self;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] elf_header GetElfHeader() const { return m_elf_header; }
|
[[nodiscard]] elf_header GetElfHeader() const {
|
||||||
|
return m_elf_header;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::span<const elf_program_header> GetProgramHeader() const { return m_elf_phdr; }
|
[[nodiscard]] std::span<const elf_program_header> GetProgramHeader() const {
|
||||||
|
return m_elf_phdr;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::span<const self_segment_header> GetSegmentHeader() const { return m_self_segments; }
|
[[nodiscard]] std::span<const self_segment_header> GetSegmentHeader() const {
|
||||||
|
return m_self_segments;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] u64 GetElfEntry() const { return m_elf_header.e_entry; }
|
[[nodiscard]] u64 GetElfEntry() const {
|
||||||
|
return m_elf_header.e_entry;
|
||||||
|
}
|
||||||
|
|
||||||
std::string SElfHeaderStr();
|
std::string SElfHeaderStr();
|
||||||
std::string SELFSegHeader(u16 no);
|
std::string SELFSegHeader(u16 no);
|
||||||
|
@ -452,10 +488,10 @@ class Elf {
|
||||||
|
|
||||||
void LoadSegment(u64 virtual_addr, u64 file_offset, u64 size);
|
void LoadSegment(u64 virtual_addr, u64 file_offset, u64 size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Common::FS::File m_f{};
|
Common::FS::File m_f{};
|
||||||
bool is_self{};
|
bool is_self{};
|
||||||
self_header m_self{};
|
self_header m_self{};
|
||||||
|
@ -466,4 +502,4 @@ class Elf {
|
||||||
elf_program_id_header m_self_id_header{};
|
elf_program_id_header m_self_id_header{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Core::Loader
|
} // namespace Core::Loader
|
||||||
|
|
|
@ -5,20 +5,19 @@
|
||||||
namespace Core::Loader {
|
namespace Core::Loader {
|
||||||
|
|
||||||
void SymbolsResolver::AddSymbol(const SymbolRes& s, u64 virtual_addr) {
|
void SymbolsResolver::AddSymbol(const SymbolRes& s, u64 virtual_addr) {
|
||||||
SymbolRecord r{};
|
SymbolRecord r{};
|
||||||
r.name = GenerateName(s);
|
r.name = GenerateName(s);
|
||||||
r.virtual_address = virtual_addr;
|
r.virtual_address = virtual_addr;
|
||||||
m_symbols.push_back(r);
|
m_symbols.push_back(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SymbolsResolver::GenerateName(const SymbolRes& s) {
|
std::string SymbolsResolver::GenerateName(const SymbolRes& s) {
|
||||||
return fmt::format("{} lib[{}_v{}]mod[{}_v{}.{}]",
|
return fmt::format("{} lib[{}_v{}]mod[{}_v{}.{}]", s.name, s.library, s.library_version,
|
||||||
s.name, s.library, s.library_version,
|
|
||||||
s.module, s.module_version_major, s.module_version_minor);
|
s.module, s.module_version_major, s.module_version_minor);
|
||||||
}
|
}
|
||||||
|
|
||||||
const SymbolRecord* SymbolsResolver::FindSymbol(const SymbolRes& s) const {
|
const SymbolRecord* SymbolsResolver::FindSymbol(const SymbolRes& s) const {
|
||||||
const std::string name = GenerateName(s);
|
const std::string name = GenerateName(s);
|
||||||
for (u32 i = 0; i < m_symbols.size(); i++) {
|
for (u32 i = 0; i < m_symbols.size(); i++) {
|
||||||
if (m_symbols[i].name.compare(name) == 0) {
|
if (m_symbols[i].name.compare(name) == 0) {
|
||||||
return &m_symbols[i];
|
return &m_symbols[i];
|
||||||
|
@ -26,7 +25,7 @@ const SymbolRecord* SymbolsResolver::FindSymbol(const SymbolRes& s) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO("Unresolved! {}\n", name);
|
LOG_INFO("Unresolved! {}\n", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core::Loader
|
} // namespace Core::Loader
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
||||||
namespace Core::Loader {
|
namespace Core::Loader {
|
||||||
|
|
||||||
struct SymbolRecord {
|
struct SymbolRecord {
|
||||||
std::string name;
|
std::string name;
|
||||||
u64 virtual_address;
|
u64 virtual_address;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SymbolRes {
|
struct SymbolRes {
|
||||||
|
@ -25,10 +25,10 @@ struct SymbolRes {
|
||||||
|
|
||||||
class SymbolsResolver {
|
class SymbolsResolver {
|
||||||
public:
|
public:
|
||||||
SymbolsResolver() = default;
|
SymbolsResolver() = default;
|
||||||
virtual ~SymbolsResolver() = default;
|
virtual ~SymbolsResolver() = default;
|
||||||
|
|
||||||
void AddSymbol(const SymbolRes& s, u64 virtual_addr);
|
void AddSymbol(const SymbolRes& s, u64 virtual_addr);
|
||||||
const SymbolRecord* FindSymbol(const SymbolRes& s) const;
|
const SymbolRecord* FindSymbol(const SymbolRes& s) const;
|
||||||
|
|
||||||
static std::string GenerateName(const SymbolRes& s);
|
static std::string GenerateName(const SymbolRes& s);
|
||||||
|
|
|
@ -22,35 +22,50 @@ enum PosixPageProtection {
|
||||||
namespace VirtualMemory {
|
namespace VirtualMemory {
|
||||||
static u32 convertMemoryMode(MemoryMode mode) {
|
static u32 convertMemoryMode(MemoryMode mode) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case MemoryMode::Read: return PAGE_READONLY;
|
case MemoryMode::Read:
|
||||||
case MemoryMode::Write:
|
return PAGE_READONLY;
|
||||||
case MemoryMode::ReadWrite: return PAGE_READWRITE;
|
case MemoryMode::Write:
|
||||||
|
case MemoryMode::ReadWrite:
|
||||||
|
return PAGE_READWRITE;
|
||||||
|
|
||||||
case MemoryMode::Execute: return PAGE_EXECUTE;
|
case MemoryMode::Execute:
|
||||||
case MemoryMode::ExecuteRead: return PAGE_EXECUTE_READ;
|
return PAGE_EXECUTE;
|
||||||
case MemoryMode::ExecuteWrite:
|
case MemoryMode::ExecuteRead:
|
||||||
case MemoryMode::ExecuteReadWrite: return PAGE_EXECUTE_READWRITE;
|
return PAGE_EXECUTE_READ;
|
||||||
|
case MemoryMode::ExecuteWrite:
|
||||||
|
case MemoryMode::ExecuteReadWrite:
|
||||||
|
return PAGE_EXECUTE_READWRITE;
|
||||||
|
|
||||||
case MemoryMode::NoAccess: return PAGE_NOACCESS;
|
case MemoryMode::NoAccess:
|
||||||
default: return PAGE_NOACCESS;
|
return PAGE_NOACCESS;
|
||||||
|
default:
|
||||||
|
return PAGE_NOACCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static MemoryMode convertMemoryMode(u32 mode) {
|
static MemoryMode convertMemoryMode(u32 mode) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case PAGE_NOACCESS: return MemoryMode::NoAccess;
|
case PAGE_NOACCESS:
|
||||||
case PAGE_READONLY: return MemoryMode::Read;
|
return MemoryMode::NoAccess;
|
||||||
case PAGE_READWRITE: return MemoryMode::ReadWrite;
|
case PAGE_READONLY:
|
||||||
case PAGE_EXECUTE: return MemoryMode::Execute;
|
return MemoryMode::Read;
|
||||||
case PAGE_EXECUTE_READ: return MemoryMode::ExecuteRead;
|
case PAGE_READWRITE:
|
||||||
case PAGE_EXECUTE_READWRITE: return MemoryMode::ExecuteReadWrite;
|
return MemoryMode::ReadWrite;
|
||||||
default: return MemoryMode::NoAccess;
|
case PAGE_EXECUTE:
|
||||||
|
return MemoryMode::Execute;
|
||||||
|
case PAGE_EXECUTE_READ:
|
||||||
|
return MemoryMode::ExecuteRead;
|
||||||
|
case PAGE_EXECUTE_READWRITE:
|
||||||
|
return MemoryMode::ExecuteReadWrite;
|
||||||
|
default:
|
||||||
|
return MemoryMode::NoAccess;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 memory_alloc(u64 address, u64 size, MemoryMode mode) {
|
u64 memory_alloc(u64 address, u64 size, MemoryMode mode) {
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
auto ptr = reinterpret_cast<uintptr_t>(VirtualAlloc(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
|
auto ptr = reinterpret_cast<uintptr_t>(VirtualAlloc(
|
||||||
static_cast<DWORD>(MEM_COMMIT) | static_cast<DWORD>(MEM_RESERVE), convertMemoryMode(mode)));
|
reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
|
||||||
|
static_cast<DWORD>(MEM_COMMIT) | static_cast<DWORD>(MEM_RESERVE), convertMemoryMode(mode)));
|
||||||
|
|
||||||
if (ptr == 0) {
|
if (ptr == 0) {
|
||||||
auto err = static_cast<u32>(GetLastError());
|
auto err = static_cast<u32>(GetLastError());
|
||||||
|
@ -58,7 +73,8 @@ u64 memory_alloc(u64 address, u64 size, MemoryMode mode) {
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
auto ptr = reinterpret_cast<uintptr_t>(
|
auto ptr = reinterpret_cast<uintptr_t>(
|
||||||
mmap(reinterpret_cast<void*>(static_cast<uintptr_t>(address)), size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
|
mmap(reinterpret_cast<void*>(static_cast<uintptr_t>(address)), size,
|
||||||
|
PROT_EXEC | PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
|
||||||
|
|
||||||
if (ptr == reinterpret_cast<uintptr_t> MAP_FAILED) {
|
if (ptr == reinterpret_cast<uintptr_t> MAP_FAILED) {
|
||||||
LOG_ERROR_IF(true, "mmap() failed: {}\n", std::strerror(errno));
|
LOG_ERROR_IF(true, "mmap() failed: {}\n", std::strerror(errno));
|
||||||
|
@ -69,7 +85,8 @@ u64 memory_alloc(u64 address, u64 size, MemoryMode mode) {
|
||||||
bool memory_protect(u64 address, u64 size, MemoryMode mode, MemoryMode* old_mode) {
|
bool memory_protect(u64 address, u64 size, MemoryMode mode, MemoryMode* old_mode) {
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
DWORD old_protect = 0;
|
DWORD old_protect = 0;
|
||||||
if (VirtualProtect(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size, convertMemoryMode(mode), &old_protect) == 0) {
|
if (VirtualProtect(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
|
||||||
|
convertMemoryMode(mode), &old_protect) == 0) {
|
||||||
auto err = static_cast<u32>(GetLastError());
|
auto err = static_cast<u32>(GetLastError());
|
||||||
LOG_ERROR_IF(true, "VirtualProtect() failed: 0x{:X}\n", err);
|
LOG_ERROR_IF(true, "VirtualProtect() failed: 0x{:X}\n", err);
|
||||||
return false;
|
return false;
|
||||||
|
@ -86,13 +103,15 @@ bool memory_protect(u64 address, u64 size, MemoryMode mode, MemoryMode* old_mode
|
||||||
|
|
||||||
bool memory_flush(u64 address, u64 size) {
|
bool memory_flush(u64 address, u64 size) {
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
if (::FlushInstructionCache(GetCurrentProcess(), reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size) == 0) {
|
if (::FlushInstructionCache(GetCurrentProcess(),
|
||||||
|
reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)),
|
||||||
|
size) == 0) {
|
||||||
auto err = static_cast<u32>(GetLastError());
|
auto err = static_cast<u32>(GetLastError());
|
||||||
LOG_ERROR_IF(true, "FlushInstructionCache() failed: 0x{:X}\n", err);
|
LOG_ERROR_IF(true, "FlushInstructionCache() failed: 0x{:X}\n", err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
#else // linux probably doesn't have something similar
|
#else // linux probably doesn't have something similar
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -115,21 +134,27 @@ bool memory_patch(u64 vaddr, u64 value) {
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
static u64 AlignUp(u64 pos, u64 align) { return (align != 0 ? (pos + (align - 1)) & ~(align - 1) : pos); }
|
static u64 AlignUp(u64 pos, u64 align) {
|
||||||
|
return (align != 0 ? (pos + (align - 1)) & ~(align - 1) : pos);
|
||||||
|
}
|
||||||
|
|
||||||
u64 memory_alloc_aligned(u64 address, u64 size, MemoryMode mode, u64 alignment) {
|
u64 memory_alloc_aligned(u64 address, u64 size, MemoryMode mode, u64 alignment) {
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
// try allocate aligned address inside user area
|
// try allocate aligned address inside user area
|
||||||
MEM_ADDRESS_REQUIREMENTS req{};
|
MEM_ADDRESS_REQUIREMENTS req{};
|
||||||
MEM_EXTENDED_PARAMETER param{};
|
MEM_EXTENDED_PARAMETER param{};
|
||||||
req.LowestStartingAddress = (address == 0 ? reinterpret_cast<PVOID>(USER_MIN) : reinterpret_cast<PVOID>(AlignUp(address, alignment)));
|
req.LowestStartingAddress =
|
||||||
|
(address == 0 ? reinterpret_cast<PVOID>(USER_MIN)
|
||||||
|
: reinterpret_cast<PVOID>(AlignUp(address, alignment)));
|
||||||
req.HighestEndingAddress = reinterpret_cast<PVOID>(USER_MAX);
|
req.HighestEndingAddress = reinterpret_cast<PVOID>(USER_MAX);
|
||||||
req.Alignment = alignment;
|
req.Alignment = alignment;
|
||||||
param.Type = MemExtendedParameterAddressRequirements;
|
param.Type = MemExtendedParameterAddressRequirements;
|
||||||
param.Pointer = &req;
|
param.Pointer = &req;
|
||||||
|
|
||||||
auto ptr = reinterpret_cast<uintptr_t>(VirtualAlloc2(
|
auto ptr = reinterpret_cast<uintptr_t>(
|
||||||
GetCurrentProcess(), nullptr, size, static_cast<DWORD>(MEM_COMMIT) | static_cast<DWORD>(MEM_RESERVE), convertMemoryMode(mode), ¶m, 1));
|
VirtualAlloc2(GetCurrentProcess(), nullptr, size,
|
||||||
|
static_cast<DWORD>(MEM_COMMIT) | static_cast<DWORD>(MEM_RESERVE),
|
||||||
|
convertMemoryMode(mode), ¶m, 1));
|
||||||
|
|
||||||
if (ptr == 0) {
|
if (ptr == 0) {
|
||||||
auto err = static_cast<u32>(GetLastError());
|
auto err = static_cast<u32>(GetLastError());
|
||||||
|
@ -145,4 +170,4 @@ u64 memory_alloc_aligned(u64 address, u64 size, MemoryMode mode, u64 alignment)
|
||||||
return reinterpret_cast<u64>(ptr);
|
return reinterpret_cast<u64>(ptr);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
} // namespace VirtualMemory
|
} // namespace VirtualMemory
|
||||||
|
|
|
@ -27,12 +27,17 @@ bool memory_patch(u64 vaddr, u64 value);
|
||||||
|
|
||||||
inline bool containsExecuteMode(MemoryMode mode) {
|
inline bool containsExecuteMode(MemoryMode mode) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case MemoryMode::Execute: return true;
|
case MemoryMode::Execute:
|
||||||
case MemoryMode::ExecuteRead: return true;
|
return true;
|
||||||
case MemoryMode::ExecuteWrite: return true;
|
case MemoryMode::ExecuteRead:
|
||||||
case MemoryMode::ExecuteReadWrite: return true;
|
return true;
|
||||||
default: return false;
|
case MemoryMode::ExecuteWrite:
|
||||||
|
return true;
|
||||||
|
case MemoryMode::ExecuteReadWrite:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace VirtualMemory
|
} // namespace VirtualMemory
|
146
src/emulator.cpp
146
src/emulator.cpp
|
@ -1,12 +1,12 @@
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <vulkan_util.h>
|
#include <vulkan_util.h>
|
||||||
|
#include "Emulator/Host/controller.h"
|
||||||
#include "common/singleton.h"
|
#include "common/singleton.h"
|
||||||
#include "common/version.h"
|
#include "common/version.h"
|
||||||
#include "emulator.h"
|
|
||||||
#include "core/PS4/HLE/Graphics/graphics_render.h"
|
#include "core/PS4/HLE/Graphics/graphics_render.h"
|
||||||
#include "Emulator/Host/controller.h"
|
|
||||||
#include "core/PS4/HLE/Graphics/video_out.h"
|
#include "core/PS4/HLE/Graphics/video_out.h"
|
||||||
#include "core/hle/libraries/libpad/pad.h"
|
#include "core/hle/libraries/libpad/pad.h"
|
||||||
|
#include "emulator.h"
|
||||||
|
|
||||||
namespace Emu {
|
namespace Emu {
|
||||||
|
|
||||||
|
@ -46,17 +46,19 @@ static void CreateSdlWindow(WindowCtx* ctx) {
|
||||||
std::exit(0);
|
std::exit(0);
|
||||||
}
|
}
|
||||||
std::string title = "shadps4 v" + std::string(Common::VERSION);
|
std::string title = "shadps4 v" + std::string(Common::VERSION);
|
||||||
ctx->m_window = SDL_CreateWindowWithPosition(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height,
|
ctx->m_window = SDL_CreateWindowWithPosition(
|
||||||
(static_cast<uint32_t>(SDL_WINDOW_HIDDEN) | static_cast<uint32_t>(SDL_WINDOW_VULKAN)));
|
title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height,
|
||||||
|
(static_cast<uint32_t>(SDL_WINDOW_HIDDEN) | static_cast<uint32_t>(SDL_WINDOW_VULKAN)));
|
||||||
|
|
||||||
ctx->is_window_hidden = true; // hide window until we need to show something (should draw something in buffers)
|
ctx->is_window_hidden =
|
||||||
|
true; // hide window until we need to show something (should draw something in buffers)
|
||||||
|
|
||||||
if (ctx->m_window == nullptr) {
|
if (ctx->m_window == nullptr) {
|
||||||
fmt::print("{}\n", SDL_GetError());
|
fmt::print("{}\n", SDL_GetError());
|
||||||
std::exit(0);
|
std::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_SetWindowResizable(ctx->m_window, SDL_FALSE); // we don't support resizable atm
|
SDL_SetWindowResizable(ctx->m_window, SDL_FALSE); // we don't support resizable atm
|
||||||
}
|
}
|
||||||
static void update() {
|
static void update() {
|
||||||
static double lag = 0.0;
|
static double lag = 0.0;
|
||||||
|
@ -83,7 +85,8 @@ static void calculateFps(double game_time_s) {
|
||||||
|
|
||||||
m_fps_frames_num++;
|
m_fps_frames_num++;
|
||||||
if (m_current_time_seconds - m_fps_start_time > 0.25f) {
|
if (m_current_time_seconds - m_fps_start_time > 0.25f) {
|
||||||
m_current_fps = static_cast<double>(m_fps_frames_num) / (m_current_time_seconds - m_fps_start_time);
|
m_current_fps =
|
||||||
|
static_cast<double>(m_fps_frames_num) / (m_current_time_seconds - m_fps_start_time);
|
||||||
m_fps_frames_num = 0;
|
m_fps_frames_num = 0;
|
||||||
m_fps_start_time = m_current_time_seconds;
|
m_fps_start_time = m_current_time_seconds;
|
||||||
}
|
}
|
||||||
|
@ -110,27 +113,35 @@ void emuRun() {
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
if (SDL_PollEvent(&event) != 0) {
|
if (SDL_PollEvent(&event) != 0) {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SDL_EVENT_QUIT: m_emu_needs_exit = true; break;
|
case SDL_EVENT_QUIT:
|
||||||
|
m_emu_needs_exit = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_TERMINATING: m_emu_needs_exit = true; break;
|
case SDL_EVENT_TERMINATING:
|
||||||
|
m_emu_needs_exit = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_WILL_ENTER_BACKGROUND: break;
|
case SDL_EVENT_WILL_ENTER_BACKGROUND:
|
||||||
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_DID_ENTER_BACKGROUND: break;
|
case SDL_EVENT_DID_ENTER_BACKGROUND:
|
||||||
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_WILL_ENTER_FOREGROUND: break;
|
case SDL_EVENT_WILL_ENTER_FOREGROUND:
|
||||||
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_DID_ENTER_FOREGROUND: break;
|
case SDL_EVENT_DID_ENTER_FOREGROUND:
|
||||||
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_KEY_DOWN:
|
case SDL_EVENT_KEY_DOWN:
|
||||||
case SDL_EVENT_KEY_UP:
|
case SDL_EVENT_KEY_UP:
|
||||||
if (event.type == SDL_EVENT_KEY_DOWN){
|
if (event.type == SDL_EVENT_KEY_DOWN) {
|
||||||
if (event.key.keysym.sym == SDLK_p) {
|
if (event.key.keysym.sym == SDLK_p) {
|
||||||
m_game_is_paused = !m_game_is_paused;
|
m_game_is_paused = !m_game_is_paused;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
keyboardEvent(&event);
|
}
|
||||||
break;
|
keyboardEvent(&event);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -138,27 +149,35 @@ void emuRun() {
|
||||||
SDL_WaitEvent(&event);
|
SDL_WaitEvent(&event);
|
||||||
|
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SDL_EVENT_QUIT: m_emu_needs_exit = true; break;
|
case SDL_EVENT_QUIT:
|
||||||
|
m_emu_needs_exit = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_TERMINATING: m_emu_needs_exit = true; break;
|
case SDL_EVENT_TERMINATING:
|
||||||
|
m_emu_needs_exit = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_WILL_ENTER_BACKGROUND: break;
|
case SDL_EVENT_WILL_ENTER_BACKGROUND:
|
||||||
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_DID_ENTER_BACKGROUND: break;
|
case SDL_EVENT_DID_ENTER_BACKGROUND:
|
||||||
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_WILL_ENTER_FOREGROUND: break;
|
case SDL_EVENT_WILL_ENTER_FOREGROUND:
|
||||||
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_DID_ENTER_FOREGROUND: break;
|
case SDL_EVENT_DID_ENTER_FOREGROUND:
|
||||||
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_KEY_DOWN:
|
case SDL_EVENT_KEY_DOWN:
|
||||||
case SDL_EVENT_KEY_UP:
|
case SDL_EVENT_KEY_UP:
|
||||||
if (event.type == SDL_EVENT_KEY_DOWN) {
|
if (event.type == SDL_EVENT_KEY_DOWN) {
|
||||||
if (event.key.keysym.sym == SDLK_p) {
|
if (event.key.keysym.sym == SDLK_p) {
|
||||||
m_game_is_paused = !m_game_is_paused;
|
m_game_is_paused = !m_game_is_paused;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
keyboardEvent(&event);
|
}
|
||||||
break;
|
keyboardEvent(&event);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
exit_loop = m_emu_needs_exit;
|
exit_loop = m_emu_needs_exit;
|
||||||
continue;
|
continue;
|
||||||
|
@ -169,8 +188,8 @@ void emuRun() {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
if (!exit_loop) {
|
if (!exit_loop) {
|
||||||
if (HLE::Libs::Graphics::VideoOut::videoOutFlip(100000)) { // flip every 0.1 sec
|
if (HLE::Libs::Graphics::VideoOut::videoOutFlip(100000)) { // flip every 0.1 sec
|
||||||
calculateFps(0); // TODO: Proper fps
|
calculateFps(0); // TODO: Proper fps
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -199,7 +218,8 @@ void DrawBuffer(HLE::Libs::Graphics::VideoOutVulkanImage* image) {
|
||||||
|
|
||||||
window_ctx->swapchain.current_index = static_cast<u32>(-1);
|
window_ctx->swapchain.current_index = static_cast<u32>(-1);
|
||||||
|
|
||||||
auto result = vkAcquireNextImageKHR(window_ctx->m_graphic_ctx.m_device, window_ctx->swapchain.swapchain, UINT64_MAX, nullptr,
|
auto result = vkAcquireNextImageKHR(window_ctx->m_graphic_ctx.m_device,
|
||||||
|
window_ctx->swapchain.swapchain, UINT64_MAX, nullptr,
|
||||||
VK_NULL_HANDLE, &window_ctx->swapchain.current_index);
|
VK_NULL_HANDLE, &window_ctx->swapchain.current_index);
|
||||||
|
|
||||||
if (result != VK_SUCCESS) {
|
if (result != VK_SUCCESS) {
|
||||||
|
@ -241,8 +261,10 @@ void DrawBuffer(HLE::Libs::Graphics::VideoOutVulkanImage* image) {
|
||||||
pre_present_barrier.subresourceRange.levelCount = 1;
|
pre_present_barrier.subresourceRange.levelCount = 1;
|
||||||
pre_present_barrier.subresourceRange.baseArrayLayer = 0;
|
pre_present_barrier.subresourceRange.baseArrayLayer = 0;
|
||||||
pre_present_barrier.subresourceRange.layerCount = 1;
|
pre_present_barrier.subresourceRange.layerCount = 1;
|
||||||
pre_present_barrier.image = window_ctx->swapchain.swapchain_images[window_ctx->swapchain.current_index];
|
pre_present_barrier.image =
|
||||||
vkCmdPipelineBarrier(vk_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1,
|
window_ctx->swapchain.swapchain_images[window_ctx->swapchain.current_index];
|
||||||
|
vkCmdPipelineBarrier(vk_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||||
|
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1,
|
||||||
&pre_present_barrier);
|
&pre_present_barrier);
|
||||||
|
|
||||||
buffer.end();
|
buffer.end();
|
||||||
|
@ -280,22 +302,42 @@ void keyboardEvent(SDL_Event* event) {
|
||||||
if (event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_KEY_UP) {
|
if (event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_KEY_UP) {
|
||||||
u32 button = 0;
|
u32 button = 0;
|
||||||
switch (event->key.keysym.sym) {
|
switch (event->key.keysym.sym) {
|
||||||
case SDLK_UP: button = ScePadButton::UP; break;
|
case SDLK_UP:
|
||||||
case SDLK_DOWN: button = ScePadButton::DOWN; break;
|
button = ScePadButton::UP;
|
||||||
case SDLK_LEFT: button = ScePadButton::LEFT; break;
|
break;
|
||||||
case SDLK_RIGHT: button = ScePadButton::RIGHT; break;
|
case SDLK_DOWN:
|
||||||
case SDLK_KP_8: button = ScePadButton ::TRIANGLE; break;
|
button = ScePadButton::DOWN;
|
||||||
case SDLK_KP_6: button = ScePadButton ::CIRCLE; break;
|
break;
|
||||||
case SDLK_KP_2: button = ScePadButton ::CROSS; break;
|
case SDLK_LEFT:
|
||||||
case SDLK_KP_4: button = ScePadButton ::SQUARE; break;
|
button = ScePadButton::LEFT;
|
||||||
case SDLK_RETURN: button = ScePadButton ::OPTIONS; break;
|
break;
|
||||||
default: break;
|
case SDLK_RIGHT:
|
||||||
|
button = ScePadButton::RIGHT;
|
||||||
|
break;
|
||||||
|
case SDLK_KP_8:
|
||||||
|
button = ScePadButton ::TRIANGLE;
|
||||||
|
break;
|
||||||
|
case SDLK_KP_6:
|
||||||
|
button = ScePadButton ::CIRCLE;
|
||||||
|
break;
|
||||||
|
case SDLK_KP_2:
|
||||||
|
button = ScePadButton ::CROSS;
|
||||||
|
break;
|
||||||
|
case SDLK_KP_4:
|
||||||
|
button = ScePadButton ::SQUARE;
|
||||||
|
break;
|
||||||
|
case SDLK_RETURN:
|
||||||
|
button = ScePadButton ::OPTIONS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (button != 0) {
|
if (button != 0) {
|
||||||
auto* controller = Common::Singleton<Emulator::Host::Controller::GameController>::Instance();
|
auto* controller =
|
||||||
|
Common::Singleton<Emulator::Host::Controller::GameController>::Instance();
|
||||||
controller->checKButton(0, button, event->type == SDL_EVENT_KEY_DOWN);
|
controller->checKButton(0, button, event->type == SDL_EVENT_KEY_DOWN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Emu
|
} // namespace Emu
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <core/PS4/HLE/Graphics/graphics_ctx.h>
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
#include <core/PS4/HLE/Graphics/graphics_ctx.h>
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace Emu {
|
namespace Emu {
|
||||||
|
@ -85,4 +85,4 @@ void checkAndWaitForGraphicsInit();
|
||||||
HLE::Libs::Graphics::GraphicCtx* getGraphicCtx();
|
HLE::Libs::Graphics::GraphicCtx* getGraphicCtx();
|
||||||
void DrawBuffer(HLE::Libs::Graphics::VideoOutVulkanImage* image);
|
void DrawBuffer(HLE::Libs::Graphics::VideoOutVulkanImage* image);
|
||||||
void keyboardEvent(SDL_Event* event);
|
void keyboardEvent(SDL_Event* event);
|
||||||
} // namespace Emulator
|
} // namespace Emu
|
||||||
|
|
|
@ -6,17 +6,17 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
#include <core/hle/libraries/libkernel/thread_management.h>
|
||||||
#include "Util/config.h"
|
#include "Util/config.h"
|
||||||
#include "common/discord.h"
|
#include "common/discord.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
#include "common/singleton.h"
|
#include "common/singleton.h"
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
#include "core/PS4/HLE/Graphics/video_out.h"
|
#include "core/PS4/HLE/Graphics/video_out.h"
|
||||||
|
#include "core/file_sys/fs.h"
|
||||||
#include "core/hle/libraries/libs.h"
|
#include "core/hle/libraries/libs.h"
|
||||||
#include "core/linker.h"
|
#include "core/linker.h"
|
||||||
#include "emulator.h"
|
#include "emulator.h"
|
||||||
#include <core/hle/libraries/libkernel/thread_management.h>
|
|
||||||
#include "core/file_sys/fs.h"
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
|
@ -41,7 +41,8 @@ int main(int argc, char* argv[]) {
|
||||||
auto linker = Common::Singleton<Core::Linker>::Instance();
|
auto linker = Common::Singleton<Core::Linker>::Instance();
|
||||||
Core::Libraries::InitHLELibs(&linker->getHLESymbols());
|
Core::Libraries::InitHLELibs(&linker->getHLESymbols());
|
||||||
linker->LoadModule(path);
|
linker->LoadModule(path);
|
||||||
std::jthread mainthread([linker](std::stop_token stop_token, void*) { linker->Execute(); }, nullptr);
|
std::jthread mainthread([linker](std::stop_token stop_token, void*) { linker->Execute(); },
|
||||||
|
nullptr);
|
||||||
Discord::RPC discordRPC;
|
Discord::RPC discordRPC;
|
||||||
discordRPC.init();
|
discordRPC.init();
|
||||||
discordRPC.update(Discord::RPCStatus::Idling, "");
|
discordRPC.update(Discord::RPCStatus::Idling, "");
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
#include "gpu_memory.h"
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <xxh3.h>
|
#include <xxh3.h>
|
||||||
|
#include "gpu_memory.h"
|
||||||
|
|
||||||
#include "common/singleton.h"
|
#include "common/singleton.h"
|
||||||
|
|
||||||
void* GPU::memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, void* todo /*CommandBuffer?*/, u64 virtual_addr, u64 size,
|
void* GPU::memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
|
void* todo /*CommandBuffer?*/, u64 virtual_addr, u64 size,
|
||||||
const GPUObject& info) {
|
const GPUObject& info) {
|
||||||
auto* gpumemory = Common::Singleton<GPUMemory>::Instance();
|
auto* gpumemory = Common::Singleton<GPUMemory>::Instance();
|
||||||
|
|
||||||
|
@ -23,9 +24,12 @@ void GPU::memorySetAllocArea(u64 virtual_addr, u64 size) {
|
||||||
gpumemory->m_heaps.push_back(h);
|
gpumemory->m_heaps.push_back(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 GPU::calculate_hash(const u08* buf, u64 size) { return (size > 0 && buf != nullptr ? XXH3_64bits(buf, size) : 0); }
|
u64 GPU::calculate_hash(const u08* buf, u64 size) {
|
||||||
|
return (size > 0 && buf != nullptr ? XXH3_64bits(buf, size) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
bool GPU::vulkanAllocateMemory(HLE::Libs::Graphics::GraphicCtx* ctx, HLE::Libs::Graphics::VulkanMemory* mem) {
|
bool GPU::vulkanAllocateMemory(HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
|
HLE::Libs::Graphics::VulkanMemory* mem) {
|
||||||
static std::atomic_uint64_t unique_id = 0;
|
static std::atomic_uint64_t unique_id = 0;
|
||||||
|
|
||||||
VkPhysicalDeviceMemoryProperties memory_properties{};
|
VkPhysicalDeviceMemoryProperties memory_properties{};
|
||||||
|
@ -66,7 +70,8 @@ void GPU::flushGarlic(HLE::Libs::Graphics::GraphicCtx* ctx) {
|
||||||
int GPU::GPUMemory::getHeapId(u64 virtual_addr, u64 size) {
|
int GPU::GPUMemory::getHeapId(u64 virtual_addr, u64 size) {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (const auto& heap : m_heaps) {
|
for (const auto& heap : m_heaps) {
|
||||||
if ((virtual_addr >= heap.allocated_virtual_addr && virtual_addr < heap.allocated_virtual_addr + heap.allocated_size) ||
|
if ((virtual_addr >= heap.allocated_virtual_addr &&
|
||||||
|
virtual_addr < heap.allocated_virtual_addr + heap.allocated_size) ||
|
||||||
((virtual_addr + size - 1) >= heap.allocated_virtual_addr &&
|
((virtual_addr + size - 1) >= heap.allocated_virtual_addr &&
|
||||||
(virtual_addr + size - 1) < heap.allocated_virtual_addr + heap.allocated_size)) {
|
(virtual_addr + size - 1) < heap.allocated_virtual_addr + heap.allocated_size)) {
|
||||||
return index;
|
return index;
|
||||||
|
@ -76,7 +81,8 @@ int GPU::GPUMemory::getHeapId(u64 virtual_addr, u64 size) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* GPU::GPUMemory::memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, void* todo, const u64* virtual_addr, const u64* size,
|
void* GPU::GPUMemory::memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
|
void* todo, const u64* virtual_addr, const u64* size,
|
||||||
int virtual_addr_num, const GPUObject& info) {
|
int virtual_addr_num, const GPUObject& info) {
|
||||||
auto* gpumemory = Common::Singleton<GPUMemory>::Instance();
|
auto* gpumemory = Common::Singleton<GPUMemory>::Instance();
|
||||||
|
|
||||||
|
@ -101,7 +107,8 @@ void* GPU::GPUMemory::memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::Graphi
|
||||||
|
|
||||||
for (int h = 0; h < virtual_addr_num; h++) {
|
for (int h = 0; h < virtual_addr_num; h++) {
|
||||||
if (info.check_hash) {
|
if (info.check_hash) {
|
||||||
objInfo.hash[h] = GPU::calculate_hash(reinterpret_cast<const u08*>(virtual_addr[h]), size[h]);
|
objInfo.hash[h] =
|
||||||
|
GPU::calculate_hash(reinterpret_cast<const u08*>(virtual_addr[h]), size[h]);
|
||||||
} else {
|
} else {
|
||||||
objInfo.hash[h] = 0;
|
objInfo.hash[h] = 0;
|
||||||
}
|
}
|
||||||
|
@ -109,7 +116,8 @@ void* GPU::GPUMemory::memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::Graphi
|
||||||
objInfo.submit_id = submit_id;
|
objInfo.submit_id = submit_id;
|
||||||
objInfo.check_hash = info.check_hash;
|
objInfo.check_hash = info.check_hash;
|
||||||
|
|
||||||
objInfo.gpu_object.obj = info.getCreateFunc()(ctx, objInfo.obj_params, virtual_addr, size, virtual_addr_num, &objInfo.mem);
|
objInfo.gpu_object.obj = info.getCreateFunc()(ctx, objInfo.obj_params, virtual_addr, size,
|
||||||
|
virtual_addr_num, &objInfo.mem);
|
||||||
|
|
||||||
objInfo.update_func = info.getUpdateFunc();
|
objInfo.update_func = info.getUpdateFunc();
|
||||||
int index = static_cast<int>(heap.objects.size());
|
int index = static_cast<int>(heap.objects.size());
|
||||||
|
@ -123,7 +131,8 @@ void* GPU::GPUMemory::memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::Graphi
|
||||||
return objInfo.gpu_object.obj;
|
return objInfo.gpu_object.obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
GPU::HeapBlock GPU::GPUMemory::createHeapBlock(const u64* virtual_addr, const u64* size, int virtual_addr_num, int heap_id, int obj_id) {
|
GPU::HeapBlock GPU::GPUMemory::createHeapBlock(const u64* virtual_addr, const u64* size,
|
||||||
|
int virtual_addr_num, int heap_id, int obj_id) {
|
||||||
auto& heap = m_heaps[heap_id];
|
auto& heap = m_heaps[heap_id];
|
||||||
|
|
||||||
GPU::HeapBlock heapBlock{};
|
GPU::HeapBlock heapBlock{};
|
||||||
|
@ -135,7 +144,8 @@ GPU::HeapBlock GPU::GPUMemory::createHeapBlock(const u64* virtual_addr, const u6
|
||||||
return heapBlock;
|
return heapBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU::GPUMemory::update(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, int heap_id, int obj_id) {
|
void GPU::GPUMemory::update(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, int heap_id,
|
||||||
|
int obj_id) {
|
||||||
auto& heap = m_heaps[heap_id];
|
auto& heap = m_heaps[heap_id];
|
||||||
|
|
||||||
auto& heapObj = heap.objects[obj_id];
|
auto& heapObj = heap.objects[obj_id];
|
||||||
|
@ -147,7 +157,9 @@ void GPU::GPUMemory::update(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
|
|
||||||
for (int i = 0; i < heapObj.block.virtual_addr_num; i++) {
|
for (int i = 0; i < heapObj.block.virtual_addr_num; i++) {
|
||||||
if (objInfo.check_hash) {
|
if (objInfo.check_hash) {
|
||||||
hash[i] = GPU::calculate_hash(reinterpret_cast<const uint8_t*>(heapObj.block.virtual_addr[i]), heapObj.block.size[i]);
|
hash[i] = GPU::calculate_hash(
|
||||||
|
reinterpret_cast<const uint8_t*>(heapObj.block.virtual_addr[i]),
|
||||||
|
heapObj.block.size[i]);
|
||||||
} else {
|
} else {
|
||||||
hash[i] = 0;
|
hash[i] = 0;
|
||||||
}
|
}
|
||||||
|
@ -166,7 +178,8 @@ void GPU::GPUMemory::update(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (need_update) {
|
if (need_update) {
|
||||||
objInfo.update_func(ctx, objInfo.obj_params, objInfo.gpu_object.obj, heapObj.block.virtual_addr, heapObj.block.size,
|
objInfo.update_func(ctx, objInfo.obj_params, objInfo.gpu_object.obj,
|
||||||
|
heapObj.block.virtual_addr, heapObj.block.size,
|
||||||
heapObj.block.virtual_addr_num);
|
heapObj.block.virtual_addr_num);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/types.h"
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include "common/types.h"
|
||||||
|
|
||||||
namespace VideoCore {
|
namespace VideoCore {
|
||||||
|
|
||||||
|
@ -65,9 +65,11 @@ public:
|
||||||
GPUMemory() {}
|
GPUMemory() {}
|
||||||
virtual ~GPUMemory() {}
|
virtual ~GPUMemory() {}
|
||||||
int getHeapId(u64 vaddr, u64 size);
|
int getHeapId(u64 vaddr, u64 size);
|
||||||
void* memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, /*CommandBuffer* buffer*/ void* todo, const u64* virtual_addr,
|
void* memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
|
/*CommandBuffer* buffer*/ void* todo, const u64* virtual_addr,
|
||||||
const u64* size, int virtual_addr_num, const GPUObject& info);
|
const u64* size, int virtual_addr_num, const GPUObject& info);
|
||||||
HeapBlock createHeapBlock(const u64* virtual_addr, const u64* size, int virtual_addr_num, int heap_id, int obj_id);
|
HeapBlock createHeapBlock(const u64* virtual_addr, const u64* size, int virtual_addr_num,
|
||||||
|
int heap_id, int obj_id);
|
||||||
void update(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, int heap_id, int obj_id);
|
void update(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, int heap_id, int obj_id);
|
||||||
void flushAllHeaps(HLE::Libs::Graphics::GraphicCtx* ctx);
|
void flushAllHeaps(HLE::Libs::Graphics::GraphicCtx* ctx);
|
||||||
|
|
||||||
|
@ -77,10 +79,12 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
void memorySetAllocArea(u64 virtual_addr, u64 size);
|
void memorySetAllocArea(u64 virtual_addr, u64 size);
|
||||||
void* memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, /*CommandBuffer* buffer*/ void* todo, u64 virtual_addr, u64 size,
|
void* memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
|
/*CommandBuffer* buffer*/ void* todo, u64 virtual_addr, u64 size,
|
||||||
const GPUObject& info);
|
const GPUObject& info);
|
||||||
u64 calculate_hash(const u08* buf, u64 size);
|
u64 calculate_hash(const u08* buf, u64 size);
|
||||||
bool vulkanAllocateMemory(HLE::Libs::Graphics::GraphicCtx* ctx, HLE::Libs::Graphics::VulkanMemory* mem);
|
bool vulkanAllocateMemory(HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
|
HLE::Libs::Graphics::VulkanMemory* mem);
|
||||||
void flushGarlic(HLE::Libs::Graphics::GraphicCtx* ctx);
|
void flushGarlic(HLE::Libs::Graphics::GraphicCtx* ctx);
|
||||||
|
|
||||||
} // namespace VideoCore
|
} // namespace VideoCore
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
namespace VideoCore {
|
namespace VideoCore {
|
||||||
|
|
||||||
class TileManager32 {
|
class TileManager32 {
|
||||||
public:
|
public:
|
||||||
u32 m_macro_tile_height = 0;
|
u32 m_macro_tile_height = 0;
|
||||||
u32 m_bank_height = 0;
|
u32 m_bank_height = 0;
|
||||||
u32 m_num_banks = 0;
|
u32 m_num_banks = 0;
|
||||||
|
@ -60,25 +60,26 @@ class TileManager32 {
|
||||||
return pipe;
|
return pipe;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 GetBankIndex(u32 x, u32 y, u32 bank_width, u32 bank_height, u32 num_banks, u32 num_pipes) {
|
static u32 GetBankIndex(u32 x, u32 y, u32 bank_width, u32 bank_height, u32 num_banks,
|
||||||
|
u32 num_pipes) {
|
||||||
const u32 x_shift_offset = std::bit_width(bank_width * num_pipes);
|
const u32 x_shift_offset = std::bit_width(bank_width * num_pipes);
|
||||||
const u32 y_shift_offset = std::bit_width(bank_height);
|
const u32 y_shift_offset = std::bit_width(bank_height);
|
||||||
const u32 xs = x >> x_shift_offset;
|
const u32 xs = x >> x_shift_offset;
|
||||||
const u32 ys = y >> y_shift_offset;
|
const u32 ys = y >> y_shift_offset;
|
||||||
u32 bank = 0;
|
u32 bank = 0;
|
||||||
switch (num_banks) {
|
switch (num_banks) {
|
||||||
case 8:
|
case 8:
|
||||||
bank |= (((xs >> 3u) ^ (ys >> 5u)) & 0x1u) << 0u;
|
bank |= (((xs >> 3u) ^ (ys >> 5u)) & 0x1u) << 0u;
|
||||||
bank |= (((xs >> 4u) ^ (ys >> 4u) ^ (ys >> 5u)) & 0x1u) << 1u;
|
bank |= (((xs >> 4u) ^ (ys >> 4u) ^ (ys >> 5u)) & 0x1u) << 1u;
|
||||||
bank |= (((xs >> 5u) ^ (ys >> 3u)) & 0x1u) << 2u;
|
bank |= (((xs >> 5u) ^ (ys >> 3u)) & 0x1u) << 2u;
|
||||||
break;
|
break;
|
||||||
case 16:
|
case 16:
|
||||||
bank |= (((xs >> 3u) ^ (ys >> 6u)) & 0x1u) << 0u;
|
bank |= (((xs >> 3u) ^ (ys >> 6u)) & 0x1u) << 0u;
|
||||||
bank |= (((xs >> 4u) ^ (ys >> 5u) ^ (ys >> 6u)) & 0x1u) << 1u;
|
bank |= (((xs >> 4u) ^ (ys >> 5u) ^ (ys >> 6u)) & 0x1u) << 1u;
|
||||||
bank |= (((xs >> 5u) ^ (ys >> 4u)) & 0x1u) << 2u;
|
bank |= (((xs >> 5u) ^ (ys >> 4u)) & 0x1u) << 2u;
|
||||||
bank |= (((xs >> 6u) ^ (ys >> 3u)) & 0x1u) << 3u;
|
bank |= (((xs >> 6u) ^ (ys >> 3u)) & 0x1u) << 3u;
|
||||||
break;
|
break;
|
||||||
default:;
|
default:;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bank;
|
return bank;
|
||||||
|
@ -101,11 +102,13 @@ class TileManager32 {
|
||||||
tile_bytes = 512;
|
tile_bytes = 512;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 macro_tile_bytes = (128 / 8) * (m_macro_tile_height / 8) * tile_bytes / (m_num_pipes * m_num_banks);
|
u64 macro_tile_bytes =
|
||||||
|
(128 / 8) * (m_macro_tile_height / 8) * tile_bytes / (m_num_pipes * m_num_banks);
|
||||||
u64 macro_tiles_per_row = m_padded_width / 128;
|
u64 macro_tiles_per_row = m_padded_width / 128;
|
||||||
u64 macro_tile_row_index = y / m_macro_tile_height;
|
u64 macro_tile_row_index = y / m_macro_tile_height;
|
||||||
u64 macro_tile_column_index = x / 128;
|
u64 macro_tile_column_index = x / 128;
|
||||||
u64 macro_tile_index = (macro_tile_row_index * macro_tiles_per_row) + macro_tile_column_index;
|
u64 macro_tile_index =
|
||||||
|
(macro_tile_row_index * macro_tiles_per_row) + macro_tile_column_index;
|
||||||
u64 macro_tile_offset = macro_tile_index * macro_tile_bytes;
|
u64 macro_tile_offset = macro_tile_index * macro_tile_bytes;
|
||||||
u64 macro_tiles_per_slice = macro_tiles_per_row * (m_padded_height / m_macro_tile_height);
|
u64 macro_tiles_per_slice = macro_tiles_per_row * (m_padded_height / m_macro_tile_height);
|
||||||
u64 slice_bytes = macro_tiles_per_slice * macro_tile_bytes;
|
u64 slice_bytes = macro_tiles_per_slice * macro_tile_bytes;
|
||||||
|
@ -124,13 +127,14 @@ class TileManager32 {
|
||||||
|
|
||||||
u64 pipe_interleave_offset = total_offset & 0xffu;
|
u64 pipe_interleave_offset = total_offset & 0xffu;
|
||||||
u64 offset = total_offset >> 8u;
|
u64 offset = total_offset >> 8u;
|
||||||
u64 byte_offset = pipe_interleave_offset | (pipe << (8u)) | (bank << (8u + m_pipe_bits)) | (offset << (8u + m_pipe_bits + m_bank_bits));
|
u64 byte_offset = pipe_interleave_offset | (pipe << (8u)) | (bank << (8u + m_pipe_bits)) |
|
||||||
|
(offset << (8u + m_pipe_bits + m_bank_bits));
|
||||||
|
|
||||||
return ((byte_offset << 3u) | bit_offset) / 8;
|
return ((byte_offset << 3u) | bit_offset) / 8;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void ConvertTileToLinear(u08* dst, const u08* src,u32 width, u32 height, bool is_neo) {
|
void ConvertTileToLinear(u08* dst, const u08* src, u32 width, u32 height, bool is_neo) {
|
||||||
const TileManager32 t{width, height, is_neo};
|
const TileManager32 t{width, height, is_neo};
|
||||||
for (u32 y = 0; y < height; y++) {
|
for (u32 y = 0; y < height; y++) {
|
||||||
u32 x = 0;
|
u32 x = 0;
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
#include "vulkan_util.h"
|
|
||||||
#include <fmt/core.h>
|
|
||||||
#include <core/PS4/GPU/gpu_memory.h>
|
|
||||||
#include <SDL_vulkan.h>
|
#include <SDL_vulkan.h>
|
||||||
#include "common/singleton.h"
|
#include <core/PS4/GPU/gpu_memory.h>
|
||||||
#include "common/log.h"
|
#include <fmt/core.h>
|
||||||
#include "common/debug.h"
|
|
||||||
#include <vulkan/vk_enum_string_helper.h>
|
#include <vulkan/vk_enum_string_helper.h>
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
#include "common/debug.h"
|
||||||
|
#include "common/log.h"
|
||||||
|
#include "common/singleton.h"
|
||||||
|
#include "vulkan_util.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
constexpr bool log_file_vulkanutil = true; // disable it to disable logging
|
constexpr bool log_file_vulkanutil = true; // disable it to disable logging
|
||||||
|
|
||||||
void Graphics::Vulkan::vulkanCreate(Emu::WindowCtx* ctx) {
|
void Graphics::Vulkan::vulkanCreate(Emu::WindowCtx* ctx) {
|
||||||
Emu::VulkanExt ext;
|
Emu::VulkanExt ext;
|
||||||
|
@ -44,18 +44,21 @@ void Graphics::Vulkan::vulkanCreate(Emu::WindowCtx* ctx) {
|
||||||
std::exit(0);
|
std::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SDL_Vulkan_CreateSurface(ctx->m_window, ctx->m_graphic_ctx.m_instance, &ctx->m_surface) == SDL_FALSE) {
|
if (SDL_Vulkan_CreateSurface(ctx->m_window, ctx->m_graphic_ctx.m_instance, &ctx->m_surface) ==
|
||||||
|
SDL_FALSE) {
|
||||||
LOG_CRITICAL_IF(log_file_vulkanutil, "Can't create an vulkan surface\n");
|
LOG_CRITICAL_IF(log_file_vulkanutil, "Can't create an vulkan surface\n");
|
||||||
std::exit(0);
|
std::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO i am not sure if it's that it is neccesary or if it needs more
|
// TODO i am not sure if it's that it is neccesary or if it needs more
|
||||||
std::vector<const char*> device_extensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME,
|
std::vector<const char*> device_extensions = {
|
||||||
VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME, "VK_KHR_maintenance1"};
|
VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME,
|
||||||
|
VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME, "VK_KHR_maintenance1"};
|
||||||
|
|
||||||
Emu::VulkanQueues queues;
|
Emu::VulkanQueues queues;
|
||||||
|
|
||||||
vulkanFindCompatiblePhysicalDevice(ctx->m_graphic_ctx.m_instance, ctx->m_surface, device_extensions, &ctx->m_surface_capabilities,
|
vulkanFindCompatiblePhysicalDevice(ctx->m_graphic_ctx.m_instance, ctx->m_surface,
|
||||||
|
device_extensions, &ctx->m_surface_capabilities,
|
||||||
&ctx->m_graphic_ctx.m_physical_device, &queues);
|
&ctx->m_graphic_ctx.m_physical_device, &queues);
|
||||||
|
|
||||||
if (ctx->m_graphic_ctx.m_physical_device == nullptr) {
|
if (ctx->m_graphic_ctx.m_physical_device == nullptr) {
|
||||||
|
@ -68,7 +71,8 @@ void Graphics::Vulkan::vulkanCreate(Emu::WindowCtx* ctx) {
|
||||||
|
|
||||||
LOG_INFO_IF(log_file_vulkanutil, "GFX device to be used : {}\n", device_properties.deviceName);
|
LOG_INFO_IF(log_file_vulkanutil, "GFX device to be used : {}\n", device_properties.deviceName);
|
||||||
|
|
||||||
ctx->m_graphic_ctx.m_device = vulkanCreateDevice(ctx->m_graphic_ctx.m_physical_device, ctx->m_surface, &ext, queues, device_extensions);
|
ctx->m_graphic_ctx.m_device = vulkanCreateDevice(
|
||||||
|
ctx->m_graphic_ctx.m_physical_device, ctx->m_surface, &ext, queues, device_extensions);
|
||||||
if (ctx->m_graphic_ctx.m_device == nullptr) {
|
if (ctx->m_graphic_ctx.m_device == nullptr) {
|
||||||
LOG_CRITICAL_IF(log_file_vulkanutil, "Can't create vulkan device\n");
|
LOG_CRITICAL_IF(log_file_vulkanutil, "Can't create vulkan device\n");
|
||||||
std::exit(0);
|
std::exit(0);
|
||||||
|
@ -78,7 +82,8 @@ void Graphics::Vulkan::vulkanCreate(Emu::WindowCtx* ctx) {
|
||||||
ctx->swapchain = vulkanCreateSwapchain(&ctx->m_graphic_ctx, 2);
|
ctx->swapchain = vulkanCreateSwapchain(&ctx->m_graphic_ctx, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
Emu::VulkanSwapchain Graphics::Vulkan::vulkanCreateSwapchain(HLE::Libs::Graphics::GraphicCtx* ctx, u32 image_count) {
|
Emu::VulkanSwapchain Graphics::Vulkan::vulkanCreateSwapchain(HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
|
u32 image_count) {
|
||||||
auto window_ctx = Common::Singleton<Emu::WindowCtx>::Instance();
|
auto window_ctx = Common::Singleton<Emu::WindowCtx>::Instance();
|
||||||
const auto& capabilities = window_ctx->m_surface_capabilities.capabilities;
|
const auto& capabilities = window_ctx->m_surface_capabilities.capabilities;
|
||||||
Emu::VulkanSwapchain s{};
|
Emu::VulkanSwapchain s{};
|
||||||
|
@ -128,7 +133,8 @@ Emu::VulkanSwapchain Graphics::Vulkan::vulkanCreateSwapchain(HLE::Libs::Graphics
|
||||||
vkGetSwapchainImagesKHR(ctx->m_device, s.swapchain, &s.swapchain_images_count, nullptr);
|
vkGetSwapchainImagesKHR(ctx->m_device, s.swapchain, &s.swapchain_images_count, nullptr);
|
||||||
|
|
||||||
s.swapchain_images.resize(s.swapchain_images_count);
|
s.swapchain_images.resize(s.swapchain_images_count);
|
||||||
vkGetSwapchainImagesKHR(ctx->m_device, s.swapchain, &s.swapchain_images_count, s.swapchain_images.data());
|
vkGetSwapchainImagesKHR(ctx->m_device, s.swapchain, &s.swapchain_images_count,
|
||||||
|
s.swapchain_images.data());
|
||||||
|
|
||||||
s.swapchain_image_views.resize(s.swapchain_images_count);
|
s.swapchain_image_views.resize(s.swapchain_images_count);
|
||||||
for (uint32_t i = 0; i < s.swapchain_images_count; i++) {
|
for (uint32_t i = 0; i < s.swapchain_images_count; i++) {
|
||||||
|
@ -163,7 +169,8 @@ Emu::VulkanSwapchain Graphics::Vulkan::vulkanCreateSwapchain(HLE::Libs::Graphics
|
||||||
present_complete_info.pNext = nullptr;
|
present_complete_info.pNext = nullptr;
|
||||||
present_complete_info.flags = 0;
|
present_complete_info.flags = 0;
|
||||||
|
|
||||||
auto result = vkCreateSemaphore(ctx->m_device, &present_complete_info, nullptr, &s.present_complete_semaphore);
|
auto result = vkCreateSemaphore(ctx->m_device, &present_complete_info, nullptr,
|
||||||
|
&s.present_complete_semaphore);
|
||||||
|
|
||||||
VkFenceCreateInfo fence_info{};
|
VkFenceCreateInfo fence_info{};
|
||||||
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||||
|
@ -179,11 +186,13 @@ Emu::VulkanSwapchain Graphics::Vulkan::vulkanCreateSwapchain(HLE::Libs::Graphics
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::Vulkan::vulkanCreateQueues(HLE::Libs::Graphics::GraphicCtx* ctx, const Emu::VulkanQueues& queues) {
|
void Graphics::Vulkan::vulkanCreateQueues(HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
|
const Emu::VulkanQueues& queues) {
|
||||||
auto get_queue = [ctx](int id, const Emu::VulkanQueueInfo& info, bool with_mutex = false) {
|
auto get_queue = [ctx](int id, const Emu::VulkanQueueInfo& info, bool with_mutex = false) {
|
||||||
ctx->queues[id].family = info.family;
|
ctx->queues[id].family = info.family;
|
||||||
ctx->queues[id].index = info.index;
|
ctx->queues[id].index = info.index;
|
||||||
vkGetDeviceQueue(ctx->m_device, ctx->queues[id].family, ctx->queues[id].index, &ctx->queues[id].vk_queue);
|
vkGetDeviceQueue(ctx->m_device, ctx->queues[id].family, ctx->queues[id].index,
|
||||||
|
&ctx->queues[id].vk_queue);
|
||||||
if (with_mutex) {
|
if (with_mutex) {
|
||||||
ctx->queues[id].mutex = std::make_unique<std::mutex>();
|
ctx->queues[id].mutex = std::make_unique<std::mutex>();
|
||||||
}
|
}
|
||||||
|
@ -199,8 +208,10 @@ void Graphics::Vulkan::vulkanCreateQueues(HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDevice Graphics::Vulkan::vulkanCreateDevice(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const Emu::VulkanExt* r,
|
VkDevice Graphics::Vulkan::vulkanCreateDevice(VkPhysicalDevice physical_device,
|
||||||
const Emu::VulkanQueues& queues, const std::vector<const char*>& device_extensions) {
|
VkSurfaceKHR surface, const Emu::VulkanExt* r,
|
||||||
|
const Emu::VulkanQueues& queues,
|
||||||
|
const std::vector<const char*>& device_extensions) {
|
||||||
std::vector<VkDeviceQueueCreateInfo> queue_create_info(queues.family_count);
|
std::vector<VkDeviceQueueCreateInfo> queue_create_info(queues.family_count);
|
||||||
std::vector<std::vector<float>> queue_priority(queues.family_count);
|
std::vector<std::vector<float>> queue_priority(queues.family_count);
|
||||||
uint32_t queue_create_info_num = 0;
|
uint32_t queue_create_info_num = 0;
|
||||||
|
@ -211,12 +222,14 @@ VkDevice Graphics::Vulkan::vulkanCreateDevice(VkPhysicalDevice physical_device,
|
||||||
queue_priority[queue_create_info_num].push_back(1.0f);
|
queue_priority[queue_create_info_num].push_back(1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
queue_create_info[queue_create_info_num].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
queue_create_info[queue_create_info_num].sType =
|
||||||
|
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||||
queue_create_info[queue_create_info_num].pNext = nullptr;
|
queue_create_info[queue_create_info_num].pNext = nullptr;
|
||||||
queue_create_info[queue_create_info_num].flags = 0;
|
queue_create_info[queue_create_info_num].flags = 0;
|
||||||
queue_create_info[queue_create_info_num].queueFamilyIndex = i;
|
queue_create_info[queue_create_info_num].queueFamilyIndex = i;
|
||||||
queue_create_info[queue_create_info_num].queueCount = queues.family_used[i];
|
queue_create_info[queue_create_info_num].queueCount = queues.family_used[i];
|
||||||
queue_create_info[queue_create_info_num].pQueuePriorities = queue_priority[queue_create_info_num].data();
|
queue_create_info[queue_create_info_num].pQueuePriorities =
|
||||||
|
queue_priority[queue_create_info_num].data();
|
||||||
|
|
||||||
queue_create_info_num++;
|
queue_create_info_num++;
|
||||||
}
|
}
|
||||||
|
@ -251,13 +264,15 @@ void Graphics::Vulkan::vulkanGetInstanceExtensions(Emu::VulkanExt* ext) {
|
||||||
|
|
||||||
ext->required_extensions = std::vector<const char*>(required_extensions_count);
|
ext->required_extensions = std::vector<const char*>(required_extensions_count);
|
||||||
|
|
||||||
result = SDL_Vulkan_GetInstanceExtensions(&required_extensions_count, ext->required_extensions.data());
|
result = SDL_Vulkan_GetInstanceExtensions(&required_extensions_count,
|
||||||
|
ext->required_extensions.data());
|
||||||
|
|
||||||
vkEnumerateInstanceExtensionProperties(nullptr, &available_extensions_count, nullptr);
|
vkEnumerateInstanceExtensionProperties(nullptr, &available_extensions_count, nullptr);
|
||||||
|
|
||||||
ext->available_extensions = std::vector<VkExtensionProperties>(available_extensions_count);
|
ext->available_extensions = std::vector<VkExtensionProperties>(available_extensions_count);
|
||||||
|
|
||||||
vkEnumerateInstanceExtensionProperties(nullptr, &available_extensions_count, ext->available_extensions.data());
|
vkEnumerateInstanceExtensionProperties(nullptr, &available_extensions_count,
|
||||||
|
ext->available_extensions.data());
|
||||||
|
|
||||||
vkEnumerateInstanceLayerProperties(&available_layers_count, nullptr);
|
vkEnumerateInstanceLayerProperties(&available_layers_count, nullptr);
|
||||||
ext->available_layers = std::vector<VkLayerProperties>(available_layers_count);
|
ext->available_layers = std::vector<VkLayerProperties>(available_layers_count);
|
||||||
|
@ -268,19 +283,21 @@ void Graphics::Vulkan::vulkanGetInstanceExtensions(Emu::VulkanExt* ext) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& ext : ext->available_extensions) {
|
for (const auto& ext : ext->available_extensions) {
|
||||||
LOG_INFO_IF(log_file_vulkanutil, "Vulkan available extension: {}, version = {}\n", ext.extensionName, ext.specVersion);
|
LOG_INFO_IF(log_file_vulkanutil, "Vulkan available extension: {}, version = {}\n",
|
||||||
|
ext.extensionName, ext.specVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& l : ext->available_layers) {
|
for (const auto& l : ext->available_layers) {
|
||||||
LOG_INFO_IF(log_file_vulkanutil, "Vulkan available layer: {}, specVersion = {}, implVersion = {}, {}\n", l.layerName, l.specVersion,
|
LOG_INFO_IF(log_file_vulkanutil,
|
||||||
l.implementationVersion, l.description);
|
"Vulkan available layer: {}, specVersion = {}, implVersion = {}, {}\n",
|
||||||
|
l.layerName, l.specVersion, l.implementationVersion, l.description);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::Vulkan::vulkanFindCompatiblePhysicalDevice(VkInstance instance, VkSurfaceKHR surface,
|
void Graphics::Vulkan::vulkanFindCompatiblePhysicalDevice(
|
||||||
const std::vector<const char*>& device_extensions,
|
VkInstance instance, VkSurfaceKHR surface, const std::vector<const char*>& device_extensions,
|
||||||
Emu::VulkanSurfaceCapabilities* out_capabilities, VkPhysicalDevice* out_device,
|
Emu::VulkanSurfaceCapabilities* out_capabilities, VkPhysicalDevice* out_device,
|
||||||
Emu::VulkanQueues* out_queues) {
|
Emu::VulkanQueues* out_queues) {
|
||||||
u32 count_devices = 0;
|
u32 count_devices = 0;
|
||||||
vkEnumeratePhysicalDevices(instance, &count_devices, nullptr);
|
vkEnumeratePhysicalDevices(instance, &count_devices, nullptr);
|
||||||
|
|
||||||
|
@ -297,7 +314,8 @@ void Graphics::Vulkan::vulkanFindCompatiblePhysicalDevice(VkInstance instance, V
|
||||||
vkGetPhysicalDeviceProperties(device, &device_properties);
|
vkGetPhysicalDeviceProperties(device, &device_properties);
|
||||||
vkGetPhysicalDeviceFeatures2(device, &device_features2);
|
vkGetPhysicalDeviceFeatures2(device, &device_features2);
|
||||||
if (device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) {
|
if (device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) {
|
||||||
continue; // we don't want integrated gpu for now .Later we will check the requirements and see what we can support (TODO fix me)
|
continue; // we don't want integrated gpu for now .Later we will check the requirements
|
||||||
|
// and see what we can support (TODO fix me)
|
||||||
}
|
}
|
||||||
LOG_INFO_IF(log_file_vulkanutil, "Vulkan device: {}\n", device_properties.deviceName);
|
LOG_INFO_IF(log_file_vulkanutil, "Vulkan device: {}\n", device_properties.deviceName);
|
||||||
|
|
||||||
|
@ -312,7 +330,8 @@ void Graphics::Vulkan::vulkanFindCompatiblePhysicalDevice(VkInstance instance, V
|
||||||
*out_queues = found_best_queues;
|
*out_queues = found_best_queues;
|
||||||
}
|
}
|
||||||
|
|
||||||
Emu::VulkanQueues Graphics::Vulkan::vulkanFindQueues(VkPhysicalDevice device, VkSurfaceKHR surface) {
|
Emu::VulkanQueues Graphics::Vulkan::vulkanFindQueues(VkPhysicalDevice device,
|
||||||
|
VkSurfaceKHR surface) {
|
||||||
Emu::VulkanQueues qs;
|
Emu::VulkanQueues qs;
|
||||||
|
|
||||||
u32 queue_family_count = 0;
|
u32 queue_family_count = 0;
|
||||||
|
@ -327,7 +346,8 @@ Emu::VulkanQueues Graphics::Vulkan::vulkanFindQueues(VkPhysicalDevice device, Vk
|
||||||
VkBool32 presentation_supported = VK_FALSE;
|
VkBool32 presentation_supported = VK_FALSE;
|
||||||
vkGetPhysicalDeviceSurfaceSupportKHR(device, family, surface, &presentation_supported);
|
vkGetPhysicalDeviceSurfaceSupportKHR(device, family, surface, &presentation_supported);
|
||||||
|
|
||||||
LOG_INFO_IF(log_file_vulkanutil, "queue family: {}, count = {}, present = {}\n", string_VkQueueFlags(f.queueFlags).c_str(), f.queueCount,
|
LOG_INFO_IF(log_file_vulkanutil, "queue family: {}, count = {}, present = {}\n",
|
||||||
|
string_VkQueueFlags(f.queueFlags).c_str(), f.queueCount,
|
||||||
(presentation_supported == VK_TRUE ? "true" : "false"));
|
(presentation_supported == VK_TRUE ? "true" : "false"));
|
||||||
for (uint32_t i = 0; i < f.queueCount; i++) {
|
for (uint32_t i = 0; i < f.queueCount; i++) {
|
||||||
Emu::VulkanQueueInfo info;
|
Emu::VulkanQueueInfo info;
|
||||||
|
@ -396,7 +416,8 @@ Emu::VulkanQueues Graphics::Vulkan::vulkanFindQueues(VkPhysicalDevice device, Vk
|
||||||
return qs;
|
return qs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::Vulkan::vulkanGetSurfaceCapabilities(VkPhysicalDevice physical_device, VkSurfaceKHR surface,
|
void Graphics::Vulkan::vulkanGetSurfaceCapabilities(VkPhysicalDevice physical_device,
|
||||||
|
VkSurfaceKHR surface,
|
||||||
Emu::VulkanSurfaceCapabilities* surfaceCap) {
|
Emu::VulkanSurfaceCapabilities* surfaceCap) {
|
||||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &surfaceCap->capabilities);
|
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &surfaceCap->capabilities);
|
||||||
|
|
||||||
|
@ -404,28 +425,34 @@ void Graphics::Vulkan::vulkanGetSurfaceCapabilities(VkPhysicalDevice physical_de
|
||||||
vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &formats_count, nullptr);
|
vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &formats_count, nullptr);
|
||||||
|
|
||||||
surfaceCap->formats = std::vector<VkSurfaceFormatKHR>(formats_count);
|
surfaceCap->formats = std::vector<VkSurfaceFormatKHR>(formats_count);
|
||||||
vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &formats_count, surfaceCap->formats.data());
|
vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &formats_count,
|
||||||
|
surfaceCap->formats.data());
|
||||||
|
|
||||||
uint32_t present_modes_count = 0;
|
uint32_t present_modes_count = 0;
|
||||||
vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &present_modes_count, nullptr);
|
vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &present_modes_count,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
surfaceCap->present_modes = std::vector<VkPresentModeKHR>(present_modes_count);
|
surfaceCap->present_modes = std::vector<VkPresentModeKHR>(present_modes_count);
|
||||||
vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &present_modes_count, surfaceCap->present_modes.data());
|
vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &present_modes_count,
|
||||||
|
surfaceCap->present_modes.data());
|
||||||
|
|
||||||
for (const auto& f : surfaceCap->formats) {
|
for (const auto& f : surfaceCap->formats) {
|
||||||
if (f.format == VK_FORMAT_B8G8R8A8_SRGB && f.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
if (f.format == VK_FORMAT_B8G8R8A8_SRGB &&
|
||||||
|
f.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
||||||
surfaceCap->is_format_srgb_bgra32 = true;
|
surfaceCap->is_format_srgb_bgra32 = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (f.format == VK_FORMAT_B8G8R8A8_UNORM && f.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
if (f.format == VK_FORMAT_B8G8R8A8_UNORM &&
|
||||||
|
f.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
||||||
surfaceCap->is_format_unorm_bgra32 = true;
|
surfaceCap->is_format_unorm_bgra32 = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_image_layout(VkCommandBuffer buffer, HLE::Libs::Graphics::VulkanImage* dst_image, uint32_t base_level, uint32_t levels,
|
static void set_image_layout(VkCommandBuffer buffer, HLE::Libs::Graphics::VulkanImage* dst_image,
|
||||||
VkImageAspectFlags aspect_mask, VkImageLayout old_image_layout, VkImageLayout new_image_layout) {
|
uint32_t base_level, uint32_t levels, VkImageAspectFlags aspect_mask,
|
||||||
|
VkImageLayout old_image_layout, VkImageLayout new_image_layout) {
|
||||||
VkImageMemoryBarrier imageMemoryBarrier{};
|
VkImageMemoryBarrier imageMemoryBarrier{};
|
||||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
imageMemoryBarrier.pNext = nullptr;
|
imageMemoryBarrier.pNext = nullptr;
|
||||||
|
@ -478,12 +505,14 @@ static void set_image_layout(VkCommandBuffer buffer, HLE::Libs::Graphics::Vulkan
|
||||||
VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
|
||||||
vkCmdPipelineBarrier(buffer, src_stages, dest_stages, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
|
vkCmdPipelineBarrier(buffer, src_stages, dest_stages, 0, 0, nullptr, 0, nullptr, 1,
|
||||||
|
&imageMemoryBarrier);
|
||||||
|
|
||||||
dst_image->layout = new_image_layout;
|
dst_image->layout = new_image_layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::Vulkan::vulkanBlitImage(GPU::CommandBuffer* buffer, HLE::Libs::Graphics::VulkanImage* src_image,
|
void Graphics::Vulkan::vulkanBlitImage(GPU::CommandBuffer* buffer,
|
||||||
|
HLE::Libs::Graphics::VulkanImage* src_image,
|
||||||
Emu::VulkanSwapchain* dst_swapchain) {
|
Emu::VulkanSwapchain* dst_swapchain) {
|
||||||
auto* vk_buffer = buffer->getPool()->buffers[buffer->getIndex()];
|
auto* vk_buffer = buffer->getPool()->buffers[buffer->getIndex()];
|
||||||
|
|
||||||
|
@ -492,9 +521,11 @@ void Graphics::Vulkan::vulkanBlitImage(GPU::CommandBuffer* buffer, HLE::Libs::Gr
|
||||||
swapchain_image.image = dst_swapchain->swapchain_images[dst_swapchain->current_index];
|
swapchain_image.image = dst_swapchain->swapchain_images[dst_swapchain->current_index];
|
||||||
swapchain_image.layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
swapchain_image.layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
|
||||||
set_image_layout(vk_buffer, src_image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
set_image_layout(vk_buffer, src_image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
|
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||||
set_image_layout(vk_buffer, &swapchain_image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
set_image_layout(vk_buffer, &swapchain_image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
|
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
|
|
||||||
VkImageBlit region{};
|
VkImageBlit region{};
|
||||||
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
@ -518,22 +549,28 @@ void Graphics::Vulkan::vulkanBlitImage(GPU::CommandBuffer* buffer, HLE::Libs::Gr
|
||||||
region.dstOffsets[1].y = static_cast<int>(dst_swapchain->swapchain_extent.height);
|
region.dstOffsets[1].y = static_cast<int>(dst_swapchain->swapchain_extent.height);
|
||||||
region.dstOffsets[1].z = 1;
|
region.dstOffsets[1].z = 1;
|
||||||
|
|
||||||
vkCmdBlitImage(vk_buffer, src_image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, swapchain_image.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
|
vkCmdBlitImage(vk_buffer, src_image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
®ion, VK_FILTER_LINEAR);
|
swapchain_image.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion,
|
||||||
|
VK_FILTER_LINEAR);
|
||||||
|
|
||||||
set_image_layout(vk_buffer, src_image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
set_image_layout(vk_buffer, src_image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::Vulkan::vulkanFillImage(HLE::Libs::Graphics::GraphicCtx* ctx, HLE::Libs::Graphics::VulkanImage* dst_image, const void* src_data,
|
void Graphics::Vulkan::vulkanFillImage(HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
u64 size, u32 src_pitch, u64 dst_layout) {
|
HLE::Libs::Graphics::VulkanImage* dst_image,
|
||||||
|
const void* src_data, u64 size, u32 src_pitch,
|
||||||
|
u64 dst_layout) {
|
||||||
HLE::Libs::Graphics::VulkanBuffer staging_buffer{};
|
HLE::Libs::Graphics::VulkanBuffer staging_buffer{};
|
||||||
staging_buffer.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
staging_buffer.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||||
staging_buffer.memory.property = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
staging_buffer.memory.property =
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||||
vulkanCreateBuffer(ctx, size, &staging_buffer);
|
vulkanCreateBuffer(ctx, size, &staging_buffer);
|
||||||
|
|
||||||
void* data = nullptr;
|
void* data = nullptr;
|
||||||
vkMapMemory(ctx->m_device, staging_buffer.memory.memory, staging_buffer.memory.offset, staging_buffer.memory.requirements.size, 0, &data);
|
vkMapMemory(ctx->m_device, staging_buffer.memory.memory, staging_buffer.memory.offset,
|
||||||
|
staging_buffer.memory.requirements.size, 0, &data);
|
||||||
std::memcpy(data, src_data, size);
|
std::memcpy(data, src_data, size);
|
||||||
vkUnmapMemory(ctx->m_device, staging_buffer.memory.memory);
|
vkUnmapMemory(ctx->m_device, staging_buffer.memory.memory);
|
||||||
|
|
||||||
|
@ -548,11 +585,15 @@ void Graphics::Vulkan::vulkanFillImage(HLE::Libs::Graphics::GraphicCtx* ctx, HLE
|
||||||
vulkanDeleteBuffer(ctx, &staging_buffer);
|
vulkanDeleteBuffer(ctx, &staging_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::Vulkan::vulkanBufferToImage(GPU::CommandBuffer* buffer, HLE::Libs::Graphics::VulkanBuffer* src_buffer, u32 src_pitch,
|
void Graphics::Vulkan::vulkanBufferToImage(GPU::CommandBuffer* buffer,
|
||||||
HLE::Libs::Graphics::VulkanImage* dst_image, u64 dst_layout) {
|
HLE::Libs::Graphics::VulkanBuffer* src_buffer,
|
||||||
|
u32 src_pitch,
|
||||||
|
HLE::Libs::Graphics::VulkanImage* dst_image,
|
||||||
|
u64 dst_layout) {
|
||||||
auto* vk_buffer = buffer->getPool()->buffers[buffer->getIndex()];
|
auto* vk_buffer = buffer->getPool()->buffers[buffer->getIndex()];
|
||||||
|
|
||||||
set_image_layout(vk_buffer, dst_image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
set_image_layout(vk_buffer, dst_image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
|
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
|
|
||||||
VkBufferImageCopy region{};
|
VkBufferImageCopy region{};
|
||||||
region.bufferOffset = 0;
|
region.bufferOffset = 0;
|
||||||
|
@ -567,13 +608,15 @@ void Graphics::Vulkan::vulkanBufferToImage(GPU::CommandBuffer* buffer, HLE::Libs
|
||||||
region.imageOffset = {0, 0, 0};
|
region.imageOffset = {0, 0, 0};
|
||||||
region.imageExtent = {dst_image->extent.width, dst_image->extent.height, 1};
|
region.imageExtent = {dst_image->extent.width, dst_image->extent.height, 1};
|
||||||
|
|
||||||
vkCmdCopyBufferToImage(vk_buffer, src_buffer->buffer, dst_image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
vkCmdCopyBufferToImage(vk_buffer, src_buffer->buffer, dst_image->image,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||||
|
|
||||||
set_image_layout(vk_buffer, dst_image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
set_image_layout(vk_buffer, dst_image, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
static_cast<VkImageLayout>(dst_layout));
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, static_cast<VkImageLayout>(dst_layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::Vulkan::vulkanCreateBuffer(HLE::Libs::Graphics::GraphicCtx* ctx, u64 size, HLE::Libs::Graphics::VulkanBuffer* buffer) {
|
void Graphics::Vulkan::vulkanCreateBuffer(HLE::Libs::Graphics::GraphicCtx* ctx, u64 size,
|
||||||
|
HLE::Libs::Graphics::VulkanBuffer* buffer) {
|
||||||
VkBufferCreateInfo buffer_info{};
|
VkBufferCreateInfo buffer_info{};
|
||||||
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
buffer_info.size = size;
|
buffer_info.size = size;
|
||||||
|
@ -592,7 +635,8 @@ void Graphics::Vulkan::vulkanCreateBuffer(HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
vkBindBufferMemory(ctx->m_device, buffer->buffer, buffer->memory.memory, buffer->memory.offset);
|
vkBindBufferMemory(ctx->m_device, buffer->buffer, buffer->memory.memory, buffer->memory.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::Vulkan::vulkanDeleteBuffer(HLE::Libs::Graphics::GraphicCtx* ctx, HLE::Libs::Graphics::VulkanBuffer* buffer) {
|
void Graphics::Vulkan::vulkanDeleteBuffer(HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
|
HLE::Libs::Graphics::VulkanBuffer* buffer) {
|
||||||
vkDestroyBuffer(ctx->m_device, buffer->buffer, nullptr);
|
vkDestroyBuffer(ctx->m_device, buffer->buffer, nullptr);
|
||||||
vkFreeMemory(ctx->m_device, buffer->memory.memory, nullptr);
|
vkFreeMemory(ctx->m_device, buffer->memory.memory, nullptr);
|
||||||
buffer->memory.memory = nullptr;
|
buffer->memory.memory = nullptr;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <core/PS4/HLE/Graphics/graphics_render.h>
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
#include <core/PS4/HLE/Graphics/graphics_render.h>
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
namespace Graphics::Vulkan {
|
namespace Graphics::Vulkan {
|
||||||
|
|
||||||
constexpr int VULKAN_QUEUES_NUM = 11; // Total of the above
|
constexpr int VULKAN_QUEUES_NUM = 11; // Total of the above
|
||||||
constexpr int VULKAN_QUEUE_GRAPHICS_NUM = 1;
|
constexpr int VULKAN_QUEUE_GRAPHICS_NUM = 1;
|
||||||
constexpr int VULKAN_QUEUE_TRANSFER_NUM = 1;
|
constexpr int VULKAN_QUEUE_TRANSFER_NUM = 1;
|
||||||
constexpr int VULKAN_QUEUE_PRESENT_NUM = 1;
|
constexpr int VULKAN_QUEUE_PRESENT_NUM = 1;
|
||||||
|
@ -21,20 +21,29 @@ constexpr int VULKAN_QUEUE_PRESENT = 10;
|
||||||
|
|
||||||
void vulkanCreate(Emu::WindowCtx* ctx);
|
void vulkanCreate(Emu::WindowCtx* ctx);
|
||||||
void vulkanGetInstanceExtensions(Emu::VulkanExt* ext);
|
void vulkanGetInstanceExtensions(Emu::VulkanExt* ext);
|
||||||
void vulkanFindCompatiblePhysicalDevice(VkInstance instance, VkSurfaceKHR surface, const std::vector<const char*>& device_extensions,
|
void vulkanFindCompatiblePhysicalDevice(VkInstance instance, VkSurfaceKHR surface,
|
||||||
Emu::VulkanSurfaceCapabilities* out_capabilities, VkPhysicalDevice* out_device,
|
const std::vector<const char*>& device_extensions,
|
||||||
|
Emu::VulkanSurfaceCapabilities* out_capabilities,
|
||||||
|
VkPhysicalDevice* out_device,
|
||||||
Emu::VulkanQueues* out_queues);
|
Emu::VulkanQueues* out_queues);
|
||||||
VkDevice vulkanCreateDevice(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const Emu::VulkanExt* r,
|
VkDevice vulkanCreateDevice(VkPhysicalDevice physical_device, VkSurfaceKHR surface,
|
||||||
const Emu::VulkanQueues& queues, const std::vector<const char*>& device_extensions);
|
const Emu::VulkanExt* r, const Emu::VulkanQueues& queues,
|
||||||
|
const std::vector<const char*>& device_extensions);
|
||||||
Emu::VulkanQueues vulkanFindQueues(VkPhysicalDevice device, VkSurfaceKHR surface);
|
Emu::VulkanQueues vulkanFindQueues(VkPhysicalDevice device, VkSurfaceKHR surface);
|
||||||
void vulkanGetSurfaceCapabilities(VkPhysicalDevice physical_device, VkSurfaceKHR surface, Emu::VulkanSurfaceCapabilities* surfaceCap);
|
void vulkanGetSurfaceCapabilities(VkPhysicalDevice physical_device, VkSurfaceKHR surface,
|
||||||
|
Emu::VulkanSurfaceCapabilities* surfaceCap);
|
||||||
void vulkanCreateQueues(HLE::Libs::Graphics::GraphicCtx* ctx, const Emu::VulkanQueues& queues);
|
void vulkanCreateQueues(HLE::Libs::Graphics::GraphicCtx* ctx, const Emu::VulkanQueues& queues);
|
||||||
Emu::VulkanSwapchain vulkanCreateSwapchain(HLE::Libs::Graphics::GraphicCtx* ctx, u32 image_count);
|
Emu::VulkanSwapchain vulkanCreateSwapchain(HLE::Libs::Graphics::GraphicCtx* ctx, u32 image_count);
|
||||||
void vulkanBlitImage(GPU::CommandBuffer* buffer, HLE::Libs::Graphics::VulkanImage* src_image, Emu::VulkanSwapchain* dst_swapchain);
|
void vulkanBlitImage(GPU::CommandBuffer* buffer, HLE::Libs::Graphics::VulkanImage* src_image,
|
||||||
void vulkanFillImage(HLE::Libs::Graphics::GraphicCtx* ctx, HLE::Libs::Graphics::VulkanImage* dst_image, const void* src_data, u64 size, u32 src_pitch,
|
Emu::VulkanSwapchain* dst_swapchain);
|
||||||
u64 dst_layout);
|
void vulkanFillImage(HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
void vulkanBufferToImage(GPU::CommandBuffer* buffer, HLE::Libs::Graphics::VulkanBuffer* src_buffer, u32 src_pitch,
|
HLE::Libs::Graphics::VulkanImage* dst_image, const void* src_data, u64 size,
|
||||||
HLE::Libs::Graphics::VulkanImage* dst_image, u64 dst_layout);
|
u32 src_pitch, u64 dst_layout);
|
||||||
void vulkanCreateBuffer(HLE::Libs::Graphics::GraphicCtx* ctx, u64 size, HLE::Libs::Graphics::VulkanBuffer* buffer);
|
void vulkanBufferToImage(GPU::CommandBuffer* buffer, HLE::Libs::Graphics::VulkanBuffer* src_buffer,
|
||||||
void vulkanDeleteBuffer(HLE::Libs::Graphics::GraphicCtx* ctx, HLE::Libs::Graphics::VulkanBuffer* buffer);
|
u32 src_pitch, HLE::Libs::Graphics::VulkanImage* dst_image,
|
||||||
}; // namespace Graphics::Vulkan
|
u64 dst_layout);
|
||||||
|
void vulkanCreateBuffer(HLE::Libs::Graphics::GraphicCtx* ctx, u64 size,
|
||||||
|
HLE::Libs::Graphics::VulkanBuffer* buffer);
|
||||||
|
void vulkanDeleteBuffer(HLE::Libs::Graphics::GraphicCtx* ctx,
|
||||||
|
HLE::Libs::Graphics::VulkanBuffer* buffer);
|
||||||
|
}; // namespace Graphics::Vulkan
|
||||||
|
|
Loading…
Reference in New Issue