Merge branch 'main' into avplayer-improvements
21
.github/ISSUE_TEMPLATE/app-bug-report.yaml
vendored
|
@ -53,3 +53,24 @@ body:
|
|||
placeholder: "Example: Windows 11, Arch Linux, MacOS 15"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: cpu
|
||||
attributes:
|
||||
label: CPU
|
||||
placeholder: "Example: Intel Core i7-8700"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: gpu
|
||||
attributes:
|
||||
label: GPU
|
||||
placeholder: "Example: nVidia GTX 1650"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: ram
|
||||
attributes:
|
||||
label: Amount of RAM in GB
|
||||
placeholder: "Example: 16 GB"
|
||||
validations:
|
||||
required: true
|
||||
|
|
|
@ -10,7 +10,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
|
|||
if(APPLE)
|
||||
list(APPEND ADDITIONAL_LANGUAGES OBJC)
|
||||
# Starting with 15.4, Rosetta 2 has support for all the necessary instruction sets.
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 15.4)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 15.4 CACHE STRING "")
|
||||
endif()
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
|
@ -54,8 +54,9 @@ else()
|
|||
endif()
|
||||
|
||||
if (ARCHITECTURE STREQUAL "x86_64")
|
||||
# Target the same x86_64 feature set as the PS4 CPU to match requirements.
|
||||
add_compile_options(-march=btver2 -mno-sse4a)
|
||||
# Target the same CPU architecture as the PS4, to maintain the same level of compatibility.
|
||||
# Exclude SSE4a as it is only available on AMD CPUs.
|
||||
add_compile_options(-march=btver2 -mtune=generic -mno-sse4a)
|
||||
endif()
|
||||
|
||||
if (APPLE AND ARCHITECTURE STREQUAL "x86_64" AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64")
|
||||
|
@ -104,11 +105,8 @@ if (CLANG_FORMAT)
|
|||
unset(CCOMMENT)
|
||||
endif()
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
# generate git revision information
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules/")
|
||||
include(GetGitRevisionDescription)
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules/GetGitRevisionDescription.cmake")
|
||||
get_git_head_revision(GIT_REF_SPEC GIT_REV)
|
||||
git_describe(GIT_DESC --always --long --dirty)
|
||||
git_branch_name(GIT_BRANCH)
|
||||
|
@ -208,6 +206,7 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_
|
|||
|
||||
message("end git things, remote: ${GIT_REMOTE_NAME}, branch: ${GIT_BRANCH}")
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
find_package(Boost 1.84.0 CONFIG)
|
||||
find_package(FFmpeg 5.1.2 MODULE)
|
||||
find_package(fmt 10.2.0 CONFIG)
|
||||
|
@ -228,10 +227,10 @@ find_package(ZLIB 1.3 MODULE)
|
|||
find_package(Zydis 5.0.0 CONFIG)
|
||||
find_package(pugixml 1.14 CONFIG)
|
||||
find_package(libusb 1.0.27 MODULE)
|
||||
|
||||
if (APPLE)
|
||||
find_package(date 3.0.1 CONFIG)
|
||||
endif()
|
||||
list(POP_BACK CMAKE_MODULE_PATH)
|
||||
|
||||
# Note: Windows always has these functions through winpthreads
|
||||
include(CheckSymbolExists)
|
||||
|
@ -451,8 +450,6 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
|
|||
src/core/libraries/audio3d/audio3d.cpp
|
||||
src/core/libraries/audio3d/audio3d.h
|
||||
src/core/libraries/audio3d/audio3d_error.h
|
||||
src/core/libraries/audio3d/audio3d_impl.cpp
|
||||
src/core/libraries/audio3d/audio3d_impl.h
|
||||
src/core/libraries/game_live_streaming/gamelivestreaming.cpp
|
||||
src/core/libraries/game_live_streaming/gamelivestreaming.h
|
||||
src/core/libraries/remote_play/remoteplay.cpp
|
||||
|
@ -1173,7 +1170,7 @@ target_include_directories(shadps4 PRIVATE ${HOST_SHADERS_INCLUDE})
|
|||
|
||||
# embed resources
|
||||
|
||||
include(CMakeRC)
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/CMakeRC.cmake")
|
||||
cmrc_add_resource_library(embedded-resources
|
||||
ALIAS res::embedded
|
||||
NAMESPACE res
|
||||
|
|
21
README.md
|
@ -122,6 +122,27 @@ R3 | M |
|
|||
Keyboard and mouse inputs can be customized in the settings menu by clicking the Controller button, and further details and help on controls are also found there. Custom bindings are saved per-game. Inputs support up to three keys per binding, mouse buttons, mouse movement mapped to joystick input, and more.
|
||||
|
||||
|
||||
# Firmware files
|
||||
|
||||
shadPS4 can load some PlayStation 4 firmware files, these must be dumped from your legally owned PlayStation 4 console.\
|
||||
The following firmware modules are supported and must be placed in shadPS4's `user/sys_modules` folder.
|
||||
|
||||
<div align="center">
|
||||
|
||||
| Modules | Modules | Modules | Modules |
|
||||
|-------------------------|-------------------------|-------------------------|-------------------------|
|
||||
| libSceCesCs.sprx | libSceFont.sprx | libSceFontFt.sprx | libSceFreeTypeOt.sprx |
|
||||
| libSceJson.sprx | libSceJson2.sprx | libSceLibcInternal.sprx | libSceNgs2.sprx |
|
||||
| libSceRtc.sprx | libSceUlt.sprx | | |
|
||||
|
||||
</div>
|
||||
|
||||
> [!Caution]
|
||||
> The above modules are required to run the games properly and must be extracted from your PlayStation 4.\
|
||||
> **We do not provide any information or support on how to do this**.
|
||||
|
||||
|
||||
|
||||
# Main team
|
||||
|
||||
- [**georgemoralis**](https://github.com/georgemoralis)
|
||||
|
|
|
@ -57,11 +57,18 @@ path = [
|
|||
"src/images/utils_icon.png",
|
||||
"src/images/shadPS4.icns",
|
||||
"src/images/shadps4.ico",
|
||||
"src/images/shadps4.png",
|
||||
"src/images/net.shadps4.shadPS4.svg",
|
||||
"src/images/themes_icon.png",
|
||||
"src/images/update_icon.png",
|
||||
"src/images/youtube.png",
|
||||
"src/images/website.png",
|
||||
"src/images/discord.svg",
|
||||
"src/images/github.svg",
|
||||
"src/images/ko-fi.svg",
|
||||
"src/images/shadps4.svg",
|
||||
"src/images/website.svg",
|
||||
"src/images/youtube.svg",
|
||||
"src/shadps4.qrc",
|
||||
"src/shadps4.rc",
|
||||
"src/qt_gui/translations/update_translation.sh",
|
||||
|
|
|
@ -24,7 +24,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||
- A CPU supporting the following instruction sets: MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, F16C, CLMUL, AES, BMI1, MOVBE, XSAVE, ABM
|
||||
- **Intel**: Haswell generation or newer
|
||||
- **AMD**: Jaguar generation or newer
|
||||
- **Apple**: Rosetta 2 on macOS 15 or newer
|
||||
- **Apple**: Rosetta 2 on macOS 15.4 or newer
|
||||
|
||||
### GPU
|
||||
|
||||
|
|
2
externals/MoltenVK/SPIRV-Cross
vendored
|
@ -1 +1 @@
|
|||
Subproject commit cb71abe3063094bf383379b15473d39cb1144120
|
||||
Subproject commit 68300dc07ac3dc592dbbdb87e02d5180f984ad12
|
2
externals/MoltenVK/cereal
vendored
|
@ -1 +1 @@
|
|||
Subproject commit d1fcec807b372f04e4c1041b3058e11c12853e6e
|
||||
Subproject commit a56bad8bbb770ee266e930c95d37fff2a5be7fea
|
2
externals/date
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 28b7b232521ace2c8ef3f2ad4126daec3569c14f
|
||||
Subproject commit a45ea7c17b4a7f320e199b71436074bd624c9e15
|
2
externals/dear_imgui
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 636cd4a7d623a2bc9bf59bb3acbb4ca075befba3
|
||||
Subproject commit f4d9359095eff3eb03f685921edc1cf0e37b1687
|
2
externals/discord-rpc
vendored
|
@ -1 +1 @@
|
|||
Subproject commit d3b5af8827031f3bccbf8c15d5dc1bfdc9467f17
|
||||
Subproject commit 19f66e6dcabb2268965f453db9e5774ede43238f
|
2
externals/ffmpeg-core
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 27de97c826b6b40c255891c37ac046a25836a575
|
||||
Subproject commit b0de1dcca26c0ebfb8011b8e59dd17fc399db0ff
|
2
externals/fmt
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 8ee89546ffcf046309d1f0d38c0393f02fde56c8
|
||||
Subproject commit 64db979e38ec644b1798e41610b28c8d2c8a2739
|
2
externals/glslang
vendored
|
@ -1 +1 @@
|
|||
Subproject commit a0995c49ebcaca2c6d3b03efbabf74f3843decdb
|
||||
Subproject commit ba1640446f3826a518721d1f083f3a8cca1120c3
|
2
externals/libusb
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 8f0b4a38fc3eefa2b26a99dff89e1c12bf37afd4
|
||||
Subproject commit a63a7e43e0950a595cf4b98a0eaf4051749ace5f
|
2
externals/magic_enum
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 1a1824df7ac798177a521eed952720681b0bf482
|
||||
Subproject commit a413fcc9c46a020a746907136a384c227f3cd095
|
2
externals/pugixml
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 4bc14418d12d289dd9978fdce9490a45deeb653e
|
||||
Subproject commit caade5a28aad86b92a4b5337a9dc70c4ba73c5eb
|
2
externals/robin-map
vendored
|
@ -1 +1 @@
|
|||
Subproject commit fe845fd7852ef541c5479ae23b3d36b57f8608ee
|
||||
Subproject commit 4ec1bf19c6a96125ea22062f38c2cf5b958e448e
|
2
externals/sdl3
vendored
|
@ -1 +1 @@
|
|||
Subproject commit a336b62d8b0b97b09214e053203e442e2b6e2be5
|
||||
Subproject commit 4093e4a193971ef1d4928158e0a1832be42e4599
|
2
externals/toml11
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 7f6c574ff5aa1053534e7e19c0a4f22bf4c6aaca
|
||||
Subproject commit a01fe3b4c14c6d7b99ee3f07c9e80058c6403097
|
2
externals/vma
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 5a53a198945ba8260fbc58fadb788745ce6aa263
|
||||
Subproject commit f378e7b3f18f6e2b06b957f6ba7b1c7207d2a536
|
2
externals/vulkan-headers
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 952f776f6573aafbb62ea717d871cd1d6816c387
|
||||
Subproject commit 5ceb9ed481e58e705d0d9b5326537daedd06b97d
|
2
externals/winpthreads
vendored
|
@ -1 +1 @@
|
|||
Subproject commit f00c973a6ab2a23573708568b8ef4acc20a9d36b
|
||||
Subproject commit f35b0948d36a736e6a2d052ae295a3ffde09703f
|
2
externals/xbyak
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 4e44f4614ddbf038f2a6296f5b906d5c72691e0f
|
||||
Subproject commit 44a72f369268f7d552650891b296693e91db86bb
|
2
externals/xxhash
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 2bf8313b934633b2a5b7e8fd239645b85e10c852
|
||||
Subproject commit 953a09abc39096da9e216b6eb0002c681cdc1199
|
2
externals/zlib-ng
vendored
|
@ -1 +1 @@
|
|||
Subproject commit d54e3769be0c522015b784eca2af258b1c026107
|
||||
Subproject commit fd0d263cedab1a136f40d65199987e3eaeecfcbd
|
2
externals/zydis
vendored
|
@ -1 +1 @@
|
|||
Subproject commit bffbb610cfea643b98e87658b9058382f7522807
|
||||
Subproject commit 120e0e705f8e3b507dc49377ac2879979f0d545c
|
|
@ -627,65 +627,56 @@ void TextEditor::HandleKeyboardInputs() {
|
|||
io.WantCaptureKeyboard = true;
|
||||
io.WantTextInput = true;
|
||||
|
||||
if (!IsReadOnly() && ctrl && !shift && !alt &&
|
||||
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Z)))
|
||||
if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Z))
|
||||
Undo();
|
||||
else if (!IsReadOnly() && !ctrl && !shift && alt &&
|
||||
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace)))
|
||||
else if (!IsReadOnly() && !ctrl && !shift && alt && ImGui::IsKeyPressed(ImGuiKey_Backspace))
|
||||
Undo();
|
||||
else if (!IsReadOnly() && ctrl && !shift && !alt &&
|
||||
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Y)))
|
||||
else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Y))
|
||||
Redo();
|
||||
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)))
|
||||
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_UpArrow))
|
||||
MoveUp(1, shift);
|
||||
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)))
|
||||
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_DownArrow))
|
||||
MoveDown(1, shift);
|
||||
else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)))
|
||||
else if (!alt && ImGui::IsKeyPressed(ImGuiKey_LeftArrow))
|
||||
MoveLeft(1, shift, ctrl);
|
||||
else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_RightArrow)))
|
||||
else if (!alt && ImGui::IsKeyPressed(ImGuiKey_RightArrow))
|
||||
MoveRight(1, shift, ctrl);
|
||||
else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageUp)))
|
||||
else if (!alt && ImGui::IsKeyPressed(ImGuiKey_PageUp))
|
||||
MoveUp(GetPageSize() - 4, shift);
|
||||
else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageDown)))
|
||||
else if (!alt && ImGui::IsKeyPressed(ImGuiKey_PageDown))
|
||||
MoveDown(GetPageSize() - 4, shift);
|
||||
else if (!alt && ctrl && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)))
|
||||
else if (!alt && ctrl && ImGui::IsKeyPressed(ImGuiKey_Home))
|
||||
MoveTop(shift);
|
||||
else if (ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)))
|
||||
else if (ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_End))
|
||||
MoveBottom(shift);
|
||||
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)))
|
||||
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_Home))
|
||||
MoveHome(shift);
|
||||
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)))
|
||||
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_End))
|
||||
MoveEnd(shift);
|
||||
else if (!IsReadOnly() && !ctrl && !shift && !alt &&
|
||||
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)))
|
||||
else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Delete))
|
||||
Delete();
|
||||
else if (!IsReadOnly() && !ctrl && !shift && !alt &&
|
||||
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace)))
|
||||
ImGui::IsKeyPressed(ImGuiKey_Backspace))
|
||||
Backspace();
|
||||
else if (!ctrl && !shift && !alt &&
|
||||
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
|
||||
else if (!ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Insert))
|
||||
mOverwrite ^= true;
|
||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
|
||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Insert))
|
||||
Copy();
|
||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_C)))
|
||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_C))
|
||||
Copy();
|
||||
else if (!IsReadOnly() && !ctrl && shift && !alt &&
|
||||
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
|
||||
else if (!IsReadOnly() && !ctrl && shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Insert))
|
||||
Paste();
|
||||
else if (!IsReadOnly() && ctrl && !shift && !alt &&
|
||||
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_V)))
|
||||
else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_V))
|
||||
Paste();
|
||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_X)))
|
||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_X))
|
||||
Cut();
|
||||
else if (!ctrl && shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)))
|
||||
else if (!ctrl && shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Delete))
|
||||
Cut();
|
||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_A)))
|
||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_A))
|
||||
SelectAll();
|
||||
else if (!IsReadOnly() && !ctrl && !shift && !alt &&
|
||||
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Enter)))
|
||||
else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Enter))
|
||||
EnterCharacter('\n', false);
|
||||
else if (!IsReadOnly() && !ctrl && !alt &&
|
||||
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Tab)))
|
||||
else if (!IsReadOnly() && !ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_Tab))
|
||||
EnterCharacter('\t', shift);
|
||||
|
||||
if (!IsReadOnly() && !io.InputQueueCharacters.empty()) {
|
||||
|
|
|
@ -191,6 +191,7 @@ int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* sta
|
|||
case OrbisAudioOutPort::Main:
|
||||
case OrbisAudioOutPort::Bgm:
|
||||
case OrbisAudioOutPort::Voice:
|
||||
case OrbisAudioOutPort::Audio3d:
|
||||
state->output = 1;
|
||||
state->channel = port.format_info.num_channels > 2 ? 2 : port.format_info.num_channels;
|
||||
break;
|
||||
|
@ -316,7 +317,7 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
|
|||
return ORBIS_AUDIO_OUT_ERROR_NOT_INIT;
|
||||
}
|
||||
if ((port_type < OrbisAudioOutPort::Main || port_type > OrbisAudioOutPort::Padspk) &&
|
||||
(port_type != OrbisAudioOutPort::Aux)) {
|
||||
(port_type != OrbisAudioOutPort::Audio3d && port_type != OrbisAudioOutPort::Aux)) {
|
||||
LOG_ERROR(Lib_AudioOut, "Invalid port type");
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT_TYPE;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,15 @@ class PortBackend;
|
|||
constexpr s32 SCE_AUDIO_OUT_NUM_PORTS = 22;
|
||||
constexpr s32 SCE_AUDIO_OUT_VOLUME_0DB = 32768; // max volume value
|
||||
|
||||
enum class OrbisAudioOutPort { Main = 0, Bgm = 1, Voice = 2, Personal = 3, Padspk = 4, Aux = 127 };
|
||||
enum class OrbisAudioOutPort {
|
||||
Main = 0,
|
||||
Bgm = 1,
|
||||
Voice = 2,
|
||||
Personal = 3,
|
||||
Padspk = 4,
|
||||
Audio3d = 126,
|
||||
Aux = 127,
|
||||
};
|
||||
|
||||
enum class OrbisAudioOutParamFormat : u32 {
|
||||
S16Mono = 0,
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <SDL3/SDL_audio.h>
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/audio/audioout.h"
|
||||
#include "core/libraries/audio/audioout_error.h"
|
||||
#include "core/libraries/audio3d/audio3d.h"
|
||||
#include "core/libraries/audio3d/audio3d_error.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
|
@ -10,331 +15,577 @@
|
|||
|
||||
namespace Libraries::Audio3d {
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dInitialize(s64 iReserved) {
|
||||
LOG_INFO(Lib_Audio3d, "iReserved = {}", iReserved);
|
||||
return ORBIS_OK;
|
||||
static constexpr u32 AUDIO3D_SAMPLE_RATE = 48000;
|
||||
|
||||
static constexpr AudioOut::OrbisAudioOutParamFormat AUDIO3D_OUTPUT_FORMAT =
|
||||
AudioOut::OrbisAudioOutParamFormat::S16Stereo;
|
||||
static constexpr u32 AUDIO3D_OUTPUT_NUM_CHANNELS = 2;
|
||||
static constexpr u32 AUDIO3D_OUTPUT_BUFFER_FRAMES = 0x100;
|
||||
|
||||
static std::unique_ptr<Audio3dState> state;
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutClose(const s32 handle) {
|
||||
LOG_INFO(Lib_Audio3d, "called, handle = {}", handle);
|
||||
return AudioOut::sceAudioOutClose(handle);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dTerminate() {
|
||||
// TODO: When not initialized or some ports still open, return ORBIS_AUDIO3D_ERROR_NOT_READY
|
||||
LOG_INFO(Lib_Audio3d, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void PS4_SYSV_ABI sceAudio3dGetDefaultOpenParameters(OrbisAudio3dOpenParameters* parameters) {
|
||||
if (parameters == nullptr) {
|
||||
LOG_ERROR(Lib_Audio3d, "Invalid OpenParameters ptr");
|
||||
return;
|
||||
}
|
||||
|
||||
parameters->size_this = sizeof(OrbisAudio3dOpenParameters);
|
||||
parameters->granularity = 256;
|
||||
parameters->rate = OrbisAudio3dRate::Rate48000;
|
||||
parameters->max_objects = 512;
|
||||
parameters->queue_depth = 2;
|
||||
parameters->buffer_mode = OrbisAudio3dBufferMode::AdvanceAndPush;
|
||||
parameters->num_beds = 2;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortOpen(OrbisUserServiceUserId iUserId,
|
||||
const OrbisAudio3dOpenParameters* pParameters,
|
||||
OrbisAudio3dPortId* pId) {
|
||||
LOG_INFO(Lib_Audio3d, "iUserId = {}", iUserId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortClose(OrbisAudio3dPortId uiPortId) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortSetAttribute(OrbisAudio3dPortId uiPortId,
|
||||
OrbisAudio3dAttributeId uiAttributeId,
|
||||
const void* pAttribute, size_t szAttribute) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}, uiAttributeId = {}, szAttribute = {}", uiPortId,
|
||||
uiAttributeId, szAttribute);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortFlush(OrbisAudio3dPortId uiPortId) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortAdvance(OrbisAudio3dPortId uiPortId) {
|
||||
LOG_TRACE(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortPush(OrbisAudio3dPortId uiPortId, OrbisAudio3dBlocking eBlocking) {
|
||||
LOG_TRACE(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortGetAttributesSupported(OrbisAudio3dPortId uiPortId,
|
||||
OrbisAudio3dAttributeId* pCapabilities,
|
||||
u32* pNumCapabilities) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortGetQueueLevel(OrbisAudio3dPortId uiPortId, u32* pQueueLevel,
|
||||
u32* pQueueAvailable) {
|
||||
LOG_TRACE(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dObjectReserve(OrbisAudio3dPortId uiPortId, OrbisAudio3dObjectId* pId) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dObjectUnreserve(OrbisAudio3dPortId uiPortId,
|
||||
OrbisAudio3dObjectId uiObjectId) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}, uiObjectId = {}", uiPortId, uiObjectId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dObjectSetAttributes(OrbisAudio3dPortId uiPortId,
|
||||
OrbisAudio3dObjectId uiObjectId,
|
||||
size_t szNumAttributes,
|
||||
const OrbisAudio3dAttribute* pAttributeArray) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}, uiObjectId = {}, szNumAttributes = {}", uiPortId,
|
||||
uiObjectId, szNumAttributes);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dBedWrite(OrbisAudio3dPortId uiPortId, u32 uiNumChannels,
|
||||
OrbisAudio3dFormat eFormat, const void* pBuffer,
|
||||
u32 uiNumSamples) {
|
||||
LOG_TRACE(Lib_Audio3d, "uiPortId = {}, uiNumChannels = {}, uiNumSamples = {}", uiPortId,
|
||||
uiNumChannels, uiNumSamples);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dBedWrite2(OrbisAudio3dPortId uiPortId, u32 uiNumChannels,
|
||||
OrbisAudio3dFormat eFormat, const void* pBuffer,
|
||||
u32 uiNumSamples, OrbisAudio3dOutputRoute eOutputRoute,
|
||||
bool bRestricted) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}, uiNumChannels = {}, uiNumSamples = {}, bRestricted = {}",
|
||||
uiPortId, uiNumChannels, uiNumSamples, bRestricted);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
size_t PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMemorySize(u32 uiNumSpeakers, bool bIs3d) {
|
||||
LOG_INFO(Lib_Audio3d, "uiNumSpeakers = {}, bIs3d = {}", uiNumSpeakers, bIs3d);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI
|
||||
sceAudio3dCreateSpeakerArray(OrbisAudio3dSpeakerArrayHandle* pHandle,
|
||||
const OrbisAudio3dSpeakerArrayParameters* pParameters) {
|
||||
if (pHandle == nullptr || pParameters == nullptr) {
|
||||
LOG_ERROR(Lib_Audio3d, "invalid SpeakerArray parameters");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
LOG_INFO(Lib_Audio3d, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dDeleteSpeakerArray(OrbisAudio3dSpeakerArrayHandle handle) {
|
||||
if (handle == nullptr) {
|
||||
LOG_ERROR(Lib_Audio3d, "invalid SpeakerArrayHandle");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
LOG_INFO(Lib_Audio3d, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients(OrbisAudio3dSpeakerArrayHandle handle,
|
||||
OrbisAudio3dPosition pos, float fSpread,
|
||||
float* pCoefficients,
|
||||
u32 uiNumCoefficients) {
|
||||
LOG_INFO(Lib_Audio3d, "fSpread = {}, uiNumCoefficients = {}", fSpread, uiNumCoefficients);
|
||||
if (handle == nullptr) {
|
||||
LOG_ERROR(Lib_Audio3d, "invalid SpeakerArrayHandle");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients2(OrbisAudio3dSpeakerArrayHandle handle,
|
||||
OrbisAudio3dPosition pos, float fSpread,
|
||||
float* pCoefficients,
|
||||
u32 uiNumCoefficients, bool bHeightAware,
|
||||
float fDownmixSpreadRadius) {
|
||||
s32 PS4_SYSV_ABI
|
||||
sceAudio3dAudioOutOpen(const OrbisAudio3dPortId port_id, const OrbisUserServiceUserId user_id,
|
||||
s32 type, const s32 index, const u32 len, const u32 freq,
|
||||
const AudioOut::OrbisAudioOutParamExtendedInformation param) {
|
||||
LOG_INFO(Lib_Audio3d,
|
||||
"fSpread = {}, uiNumCoefficients = {}, bHeightAware = {}, fDownmixSpreadRadius = {}",
|
||||
fSpread, uiNumCoefficients, bHeightAware, fDownmixSpreadRadius);
|
||||
if (handle == nullptr) {
|
||||
LOG_ERROR(Lib_Audio3d, "invalid SpeakerArrayHandle");
|
||||
"called, port_id = {}, user_id = {}, type = {}, index = {}, len = {}, freq = {}",
|
||||
port_id, user_id, type, index, len, freq);
|
||||
|
||||
if (!state->ports.contains(port_id)) {
|
||||
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
if (len != state->ports[port_id].parameters.granularity) {
|
||||
LOG_ERROR(Lib_Audio3d, "len != state->ports[port_id].parameters.granularity");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return sceAudioOutOpen(user_id, static_cast<AudioOut::OrbisAudioOutPort>(type), index, len,
|
||||
freq, param);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutOutput(const s32 handle, void* ptr) {
|
||||
LOG_DEBUG(Lib_Audio3d, "called, handle = {}, ptr = {}", handle, ptr);
|
||||
|
||||
if (!ptr) {
|
||||
LOG_ERROR(Lib_Audio3d, "!ptr");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (handle < 0 || (handle & 0xFFFF) > 25) {
|
||||
LOG_ERROR(Lib_Audio3d, "handle < 0 || (handle & 0xFFFF) > 25");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
return AudioOut::sceAudioOutOutput(handle, ptr);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutOutputs(AudioOut::OrbisAudioOutOutputParam* param,
|
||||
const u32 num) {
|
||||
LOG_DEBUG(Lib_Audio3d, "called, param = {}, num = {}", static_cast<void*>(param), num);
|
||||
|
||||
if (!param || !num) {
|
||||
LOG_ERROR(Lib_Audio3d, "!param || !num");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return AudioOut::sceAudioOutOutputs(param, num);
|
||||
}
|
||||
|
||||
static s32 PortQueueAudio(Port& port, const OrbisAudio3dPcm& pcm, const u32 num_channels) {
|
||||
// Audio3d output is configured for stereo signed 16-bit PCM. Convert the data to match.
|
||||
const SDL_AudioSpec src_spec = {
|
||||
.format = pcm.format == OrbisAudio3dFormat::ORBIS_AUDIO3D_FORMAT_S16 ? SDL_AUDIO_S16LE
|
||||
: SDL_AUDIO_F32LE,
|
||||
.channels = static_cast<int>(num_channels),
|
||||
.freq = AUDIO3D_SAMPLE_RATE,
|
||||
};
|
||||
constexpr SDL_AudioSpec dst_spec = {
|
||||
.format = SDL_AUDIO_S16LE,
|
||||
.channels = AUDIO3D_OUTPUT_NUM_CHANNELS,
|
||||
.freq = AUDIO3D_SAMPLE_RATE,
|
||||
};
|
||||
const auto src_size = pcm.num_samples *
|
||||
(pcm.format == OrbisAudio3dFormat::ORBIS_AUDIO3D_FORMAT_S16 ? 2 : 4) *
|
||||
num_channels;
|
||||
|
||||
u8* dst_data;
|
||||
int dst_len;
|
||||
if (!SDL_ConvertAudioSamples(&src_spec, static_cast<u8*>(pcm.sample_buffer),
|
||||
static_cast<int>(src_size), &dst_spec, &dst_data, &dst_len)) {
|
||||
LOG_ERROR(Lib_Audio3d, "SDL_ConvertAudioSamples failed: {}", SDL_GetError());
|
||||
return ORBIS_AUDIO3D_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
port.queue.emplace_back(AudioData{
|
||||
.sample_buffer = dst_data,
|
||||
.num_samples = pcm.num_samples,
|
||||
});
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dBedWrite(const OrbisAudio3dPortId port_id, const u32 num_channels,
|
||||
const OrbisAudio3dFormat format, void* buffer,
|
||||
const u32 num_samples) {
|
||||
return sceAudio3dBedWrite2(port_id, num_channels, format, buffer, num_samples,
|
||||
OrbisAudio3dOutputRoute::ORBIS_AUDIO3D_OUTPUT_BOTH, false);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dBedWrite2(const OrbisAudio3dPortId port_id, const u32 num_channels,
|
||||
const OrbisAudio3dFormat format, void* buffer,
|
||||
const u32 num_samples,
|
||||
const OrbisAudio3dOutputRoute output_route,
|
||||
const bool restricted) {
|
||||
LOG_DEBUG(
|
||||
Lib_Audio3d,
|
||||
"called, port_id = {}, num_channels = {}, format = {}, num_samples = {}, output_route "
|
||||
"= {}, restricted = {}",
|
||||
port_id, num_channels, magic_enum::enum_name(format), num_samples,
|
||||
magic_enum::enum_name(output_route), restricted);
|
||||
|
||||
if (!state->ports.contains(port_id)) {
|
||||
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
if (output_route > OrbisAudio3dOutputRoute::ORBIS_AUDIO3D_OUTPUT_BOTH) {
|
||||
LOG_ERROR(Lib_Audio3d, "output_route > ORBIS_AUDIO3D_OUTPUT_BOTH");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (format > OrbisAudio3dFormat::ORBIS_AUDIO3D_FORMAT_FLOAT) {
|
||||
LOG_ERROR(Lib_Audio3d, "format > ORBIS_AUDIO3D_FORMAT_FLOAT");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (num_channels != 2 && num_channels != 8) {
|
||||
LOG_ERROR(Lib_Audio3d, "num_channels != 2 && num_channels != 8");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (!buffer || !num_samples) {
|
||||
LOG_ERROR(Lib_Audio3d, "!buffer || !num_samples");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (format == OrbisAudio3dFormat::ORBIS_AUDIO3D_FORMAT_FLOAT) {
|
||||
if ((reinterpret_cast<uintptr_t>(buffer) & 3) != 0) {
|
||||
LOG_ERROR(Lib_Audio3d, "buffer & 3 != 0");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
} else if (format == OrbisAudio3dFormat::ORBIS_AUDIO3D_FORMAT_S16) {
|
||||
if ((reinterpret_cast<uintptr_t>(buffer) & 1) != 0) {
|
||||
LOG_ERROR(Lib_Audio3d, "buffer & 1 != 0");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
return PortQueueAudio(state->ports[port_id],
|
||||
OrbisAudio3dPcm{
|
||||
.format = format,
|
||||
.sample_buffer = buffer,
|
||||
.num_samples = num_samples,
|
||||
},
|
||||
num_channels);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dCreateSpeakerArray() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dDeleteSpeakerArray() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dGetDefaultOpenParameters(OrbisAudio3dOpenParameters* params) {
|
||||
LOG_DEBUG(Lib_Audio3d, "called");
|
||||
if (params) {
|
||||
*params = OrbisAudio3dOpenParameters{
|
||||
.size_this = 0x20,
|
||||
.granularity = 0x100,
|
||||
.rate = OrbisAudio3dRate::ORBIS_AUDIO3D_RATE_48000,
|
||||
.max_objects = 512,
|
||||
.queue_depth = 2,
|
||||
.buffer_mode = OrbisAudio3dBufferMode::ORBIS_AUDIO3D_BUFFER_ADVANCE_AND_PUSH,
|
||||
};
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutOpen(OrbisAudio3dPortId uiPortId, OrbisUserServiceUserId userId,
|
||||
s32 type, s32 index, u32 len, u32 freq, u32 param) {
|
||||
s32 PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMemorySize() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients2() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dInitialize(const s64 reserved) {
|
||||
LOG_INFO(Lib_Audio3d, "called, reserved = {}", reserved);
|
||||
|
||||
if (reserved != 0) {
|
||||
LOG_ERROR(Lib_Audio3d, "reserved != 0");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (state) {
|
||||
LOG_ERROR(Lib_Audio3d, "already initialized");
|
||||
return ORBIS_AUDIO3D_ERROR_NOT_READY;
|
||||
}
|
||||
|
||||
state = std::make_unique<Audio3dState>();
|
||||
|
||||
if (const auto init_ret = AudioOut::sceAudioOutInit();
|
||||
init_ret < 0 && init_ret != ORBIS_AUDIO_OUT_ERROR_ALREADY_INIT) {
|
||||
return init_ret;
|
||||
}
|
||||
|
||||
AudioOut::OrbisAudioOutParamExtendedInformation ext_info{};
|
||||
ext_info.data_format.Assign(AUDIO3D_OUTPUT_FORMAT);
|
||||
state->audio_out_handle =
|
||||
AudioOut::sceAudioOutOpen(0xFF, AudioOut::OrbisAudioOutPort::Audio3d, 0,
|
||||
AUDIO3D_OUTPUT_BUFFER_FRAMES, AUDIO3D_SAMPLE_RATE, ext_info);
|
||||
if (state->audio_out_handle < 0) {
|
||||
return state->audio_out_handle;
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dObjectReserve(const OrbisAudio3dPortId port_id,
|
||||
OrbisAudio3dObjectId* object_id) {
|
||||
LOG_INFO(Lib_Audio3d, "called, port_id = {}, object_id = {}", port_id,
|
||||
static_cast<void*>(object_id));
|
||||
|
||||
if (!state->ports.contains(port_id)) {
|
||||
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
if (!object_id) {
|
||||
LOG_ERROR(Lib_Audio3d, "!object_id");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
static int last_id = 0;
|
||||
*object_id = ++last_id;
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dObjectSetAttributes(const OrbisAudio3dPortId port_id,
|
||||
OrbisAudio3dObjectId object_id,
|
||||
const u64 num_attributes,
|
||||
const OrbisAudio3dAttribute* attribute_array) {
|
||||
LOG_DEBUG(Lib_Audio3d,
|
||||
"called, port_id = {}, object_id = {}, num_attributes = {}, attribute_array = {}",
|
||||
port_id, object_id, num_attributes, fmt::ptr(attribute_array));
|
||||
|
||||
if (!state->ports.contains(port_id)) {
|
||||
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
auto& port = state->ports[port_id];
|
||||
|
||||
for (u64 i = 0; i < num_attributes; i++) {
|
||||
const auto& attribute = attribute_array[i];
|
||||
|
||||
switch (attribute.attribute_id) {
|
||||
case OrbisAudio3dAttributeId::ORBIS_AUDIO3D_ATTRIBUTE_PCM: {
|
||||
const auto pcm = static_cast<OrbisAudio3dPcm*>(attribute.value);
|
||||
// Object audio has 1 channel.
|
||||
if (const auto ret = PortQueueAudio(port, *pcm, 1); ret != ORBIS_OK) {
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_ERROR(Lib_Audio3d, "Unsupported attribute ID: {:#x}",
|
||||
static_cast<u32>(attribute.attribute_id));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dObjectUnreserve() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortAdvance(const OrbisAudio3dPortId port_id) {
|
||||
LOG_DEBUG(Lib_Audio3d, "called, port_id = {}", port_id);
|
||||
|
||||
if (!state->ports.contains(port_id)) {
|
||||
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
if (state->ports[port_id].parameters.buffer_mode ==
|
||||
OrbisAudio3dBufferMode::ORBIS_AUDIO3D_BUFFER_NO_ADVANCE) {
|
||||
LOG_ERROR(Lib_Audio3d, "port doesn't have advance capability");
|
||||
return ORBIS_AUDIO3D_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
auto& port = state->ports[port_id];
|
||||
if (port.current_buffer.has_value()) {
|
||||
// Free existing buffer before replacing.
|
||||
SDL_free(port.current_buffer->sample_buffer);
|
||||
}
|
||||
|
||||
if (!port.queue.empty()) {
|
||||
port.current_buffer = port.queue.front();
|
||||
port.queue.pop_front();
|
||||
} else {
|
||||
// Nothing to advance to.
|
||||
LOG_DEBUG(Lib_Audio3d, "Port advance with no buffer queued");
|
||||
port.current_buffer = std::nullopt;
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortClose() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortCreate() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortDestroy() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortFlush() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortFreeState() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetAttributesSupported() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetList() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetParameters() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetQueueLevel(const OrbisAudio3dPortId port_id, u32* queue_level,
|
||||
u32* queue_available) {
|
||||
LOG_DEBUG(Lib_Audio3d, "called, port_id = {}, queue_level = {}, queue_available = {}", port_id,
|
||||
static_cast<void*>(queue_level), static_cast<void*>(queue_available));
|
||||
|
||||
if (!state->ports.contains(port_id)) {
|
||||
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
if (!queue_level && !queue_available) {
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
const auto port = state->ports[port_id];
|
||||
const size_t size = port.queue.size();
|
||||
|
||||
if (queue_level) {
|
||||
*queue_level = size;
|
||||
}
|
||||
|
||||
if (queue_available) {
|
||||
*queue_available = port.parameters.queue_depth - size;
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetState() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetStatus() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortOpen(const OrbisUserServiceUserId user_id,
|
||||
const OrbisAudio3dOpenParameters* parameters,
|
||||
OrbisAudio3dPortId* port_id) {
|
||||
LOG_INFO(Lib_Audio3d, "called, user_id = {}, parameters = {}, id = {}", user_id,
|
||||
static_cast<const void*>(parameters), static_cast<void*>(port_id));
|
||||
|
||||
if (!state) {
|
||||
LOG_ERROR(Lib_Audio3d, "!initialized");
|
||||
return ORBIS_AUDIO3D_ERROR_NOT_READY;
|
||||
}
|
||||
|
||||
if (!parameters || !port_id) {
|
||||
LOG_ERROR(Lib_Audio3d, "!parameters || !id");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
const int id = static_cast<int>(state->ports.size()) + 1;
|
||||
|
||||
if (id > 3) {
|
||||
LOG_ERROR(Lib_Audio3d, "id > 3");
|
||||
return ORBIS_AUDIO3D_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
*port_id = id;
|
||||
std::memcpy(&state->ports[id].parameters, parameters, sizeof(OrbisAudio3dOpenParameters));
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortPush(const OrbisAudio3dPortId port_id,
|
||||
const OrbisAudio3dBlocking blocking) {
|
||||
LOG_DEBUG(Lib_Audio3d, "called, port_id = {}, blocking = {}", port_id,
|
||||
magic_enum::enum_name(blocking));
|
||||
|
||||
if (!state->ports.contains(port_id)) {
|
||||
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
const auto& port = state->ports[port_id];
|
||||
if (port.parameters.buffer_mode !=
|
||||
OrbisAudio3dBufferMode::ORBIS_AUDIO3D_BUFFER_ADVANCE_AND_PUSH) {
|
||||
LOG_ERROR(Lib_Audio3d, "port doesn't have push capability");
|
||||
return ORBIS_AUDIO3D_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (!port.current_buffer.has_value()) {
|
||||
// Nothing to push.
|
||||
LOG_DEBUG(Lib_Audio3d, "Port push with no buffer ready");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
// TODO: Implement asynchronous blocking mode.
|
||||
const auto& [sample_buffer, num_samples] = port.current_buffer.value();
|
||||
return AudioOut::sceAudioOutOutput(state->audio_out_handle, sample_buffer);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortQueryDebug() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortSetAttribute(const OrbisAudio3dPortId port_id,
|
||||
const OrbisAudio3dAttributeId attribute_id,
|
||||
void* attribute, const u64 attribute_size) {
|
||||
LOG_INFO(Lib_Audio3d,
|
||||
"uiPortId = {}, userId = {}, type = {}, index = {}, len = {}, freq = {}, param = {}",
|
||||
uiPortId, userId, type, index, len, freq, param);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
"called, port_id = {}, attribute_id = {}, attribute = {}, attribute_size = {}",
|
||||
port_id, static_cast<u32>(attribute_id), attribute, attribute_size);
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutClose(s32 handle) {
|
||||
LOG_INFO(Lib_Audio3d, "handle = {}", handle);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
if (!state->ports.contains(port_id)) {
|
||||
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutOutput(s32 handle, const void* ptr) {
|
||||
LOG_TRACE(Lib_Audio3d, "handle = {}", handle);
|
||||
if (ptr == nullptr) {
|
||||
LOG_ERROR(Lib_Audio3d, "invalid Output ptr");
|
||||
if (!attribute) {
|
||||
LOG_ERROR(Lib_Audio3d, "!attribute");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutOutputs(::Libraries::AudioOut::OrbisAudioOutOutputParam* param,
|
||||
s32 num) {
|
||||
LOG_INFO(Lib_Audio3d, "num = {}", num);
|
||||
if (param == nullptr) {
|
||||
LOG_ERROR(Lib_Audio3d, "invalid OutputParam ptr");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortCreate(u32 uiGranularity, OrbisAudio3dRate eRate, s64 iReserved,
|
||||
OrbisAudio3dPortId* pId) {
|
||||
LOG_INFO(Lib_Audio3d, "uiGranularity = {}, iReserved = {}", uiGranularity, iReserved);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortDestroy(OrbisAudio3dPortId uiPortId) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
// Audio3dPrivate
|
||||
|
||||
const char* PS4_SYSV_ABI sceAudio3dStrError(int iErrorCode) {
|
||||
LOG_ERROR(Lib_Audio3d, "(PRIVATE) called, iErrorCode = {}", iErrorCode);
|
||||
return "NOT_IMPLEMENTED";
|
||||
}
|
||||
|
||||
// Audio3dDebug
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortQueryDebug() {
|
||||
LOG_WARNING(Lib_Audio3d, "(DEBUG) sceAudio3dPortQueryDebug called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortGetList() {
|
||||
LOG_WARNING(Lib_Audio3d, "(DEBUG) sceAudio3dPortGetList called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortGetParameters() {
|
||||
LOG_WARNING(Lib_Audio3d, "(DEBUG) sceAudio3dPortGetParameters called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortGetState() {
|
||||
LOG_WARNING(Lib_Audio3d, "(DEBUG) sceAudio3dPortGetState called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortFreeState() {
|
||||
LOG_WARNING(Lib_Audio3d, "(DEBUG) sceAudio3dPortFreeState called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
// Unknown
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortGetBufferLevel() {
|
||||
s32 PS4_SYSV_ABI sceAudio3dReportRegisterHandler() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortGetStatus() {
|
||||
s32 PS4_SYSV_ABI sceAudio3dReportUnregisterHandler() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dReportRegisterHandler() {
|
||||
s32 PS4_SYSV_ABI sceAudio3dSetGpuRenderer() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dReportUnregisterHandler() {
|
||||
s32 PS4_SYSV_ABI sceAudio3dStrError() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dSetGpuRenderer() {
|
||||
s32 PS4_SYSV_ABI sceAudio3dTerminate() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void RegisterlibSceAudio3d(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("pZlOm1aF3aA", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dAudioOutClose);
|
||||
LIB_FUNCTION("ucEsi62soTo", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dAudioOutOpen);
|
||||
LIB_FUNCTION("7NYEzJ9SJbM", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dAudioOutOutput);
|
||||
LIB_FUNCTION("HbxYY27lK6E", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dAudioOutOutputs);
|
||||
LIB_FUNCTION("9tEwE0GV0qo", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dBedWrite);
|
||||
LIB_FUNCTION("xH4Q9UILL3o", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dBedWrite2);
|
||||
LIB_FUNCTION("lvWMW6vEqFU", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dCreateSpeakerArray);
|
||||
LIB_FUNCTION("8hm6YdoQgwg", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dDeleteSpeakerArray);
|
||||
LIB_FUNCTION("Im+jOoa5WAI", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dGetDefaultOpenParameters);
|
||||
LIB_FUNCTION("kEqqyDkmgdI", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dGetSpeakerArrayMemorySize);
|
||||
LIB_FUNCTION("-R1DukFq7Dk", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dGetSpeakerArrayMixCoefficients);
|
||||
LIB_FUNCTION("-Re+pCWvwjQ", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dGetSpeakerArrayMixCoefficients2);
|
||||
LIB_FUNCTION("-pzYDZozm+M", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dPortQueryDebug);
|
||||
LIB_FUNCTION("1HXxo-+1qCw", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dObjectUnreserve);
|
||||
LIB_FUNCTION("UmCvjSmuZIw", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dInitialize);
|
||||
LIB_FUNCTION("jO2tec4dJ2M", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dObjectReserve);
|
||||
LIB_FUNCTION("4uyHN9q4ZeU", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dObjectSetAttributes);
|
||||
LIB_FUNCTION("7NYEzJ9SJbM", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dAudioOutOutput);
|
||||
LIB_FUNCTION("8hm6YdoQgwg", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dDeleteSpeakerArray);
|
||||
LIB_FUNCTION("1HXxo-+1qCw", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dObjectUnreserve);
|
||||
LIB_FUNCTION("lw0qrdSjZt8", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortAdvance);
|
||||
LIB_FUNCTION("OyVqOeVNtSk", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortClose);
|
||||
LIB_FUNCTION("UHFOgVNz0kk", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortCreate);
|
||||
LIB_FUNCTION("Mw9mRQtWepY", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortDestroy);
|
||||
LIB_FUNCTION("ZOGrxWLgQzE", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortFlush);
|
||||
LIB_FUNCTION("uJ0VhGcxCTQ", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortFreeState);
|
||||
LIB_FUNCTION("9ZA23Ia46Po", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dPortGetAttributesSupported);
|
||||
LIB_FUNCTION("9tEwE0GV0qo", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dBedWrite);
|
||||
LIB_FUNCTION("Aacl5qkRU6U", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dStrError);
|
||||
LIB_FUNCTION("CKHlRW2E9dA", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortGetState);
|
||||
LIB_FUNCTION("HbxYY27lK6E", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dAudioOutOutputs);
|
||||
LIB_FUNCTION("Im+jOoa5WAI", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dGetDefaultOpenParameters);
|
||||
LIB_FUNCTION("Mw9mRQtWepY", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortDestroy);
|
||||
LIB_FUNCTION("OyVqOeVNtSk", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortClose);
|
||||
LIB_FUNCTION("QfNXBrKZeI0", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dReportRegisterHandler);
|
||||
LIB_FUNCTION("QqgTQQdzEMY", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dPortGetBufferLevel);
|
||||
LIB_FUNCTION("SEggctIeTcI", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortGetList);
|
||||
LIB_FUNCTION("UHFOgVNz0kk", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortCreate);
|
||||
LIB_FUNCTION("UmCvjSmuZIw", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dInitialize);
|
||||
LIB_FUNCTION("VEVhZ9qd4ZY", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortPush);
|
||||
LIB_FUNCTION("WW1TS2iz5yc", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dTerminate);
|
||||
LIB_FUNCTION("XeDDK0xJWQA", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortOpen);
|
||||
LIB_FUNCTION("YaaDbDwKpFM", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dPortGetQueueLevel);
|
||||
LIB_FUNCTION("Yq9bfUQ0uJg", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dPortSetAttribute);
|
||||
LIB_FUNCTION("ZOGrxWLgQzE", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortFlush);
|
||||
LIB_FUNCTION("flPcUaXVXcw", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dPortGetParameters);
|
||||
LIB_FUNCTION("YaaDbDwKpFM", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dPortGetQueueLevel);
|
||||
LIB_FUNCTION("CKHlRW2E9dA", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortGetState);
|
||||
LIB_FUNCTION("iRX6GJs9tvE", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortGetStatus);
|
||||
LIB_FUNCTION("jO2tec4dJ2M", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dObjectReserve);
|
||||
LIB_FUNCTION("kEqqyDkmgdI", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dGetSpeakerArrayMemorySize);
|
||||
LIB_FUNCTION("lvWMW6vEqFU", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dCreateSpeakerArray);
|
||||
LIB_FUNCTION("lw0qrdSjZt8", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortAdvance);
|
||||
LIB_FUNCTION("pZlOm1aF3aA", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dAudioOutClose);
|
||||
LIB_FUNCTION("XeDDK0xJWQA", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortOpen);
|
||||
LIB_FUNCTION("VEVhZ9qd4ZY", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortPush);
|
||||
LIB_FUNCTION("-pzYDZozm+M", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dPortQueryDebug);
|
||||
LIB_FUNCTION("Yq9bfUQ0uJg", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dPortSetAttribute);
|
||||
LIB_FUNCTION("QfNXBrKZeI0", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dReportRegisterHandler);
|
||||
LIB_FUNCTION("psv2gbihC1A", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dReportUnregisterHandler);
|
||||
LIB_FUNCTION("uJ0VhGcxCTQ", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortFreeState);
|
||||
LIB_FUNCTION("ucEsi62soTo", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dAudioOutOpen);
|
||||
LIB_FUNCTION("xH4Q9UILL3o", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dBedWrite2);
|
||||
LIB_FUNCTION("yEYXcbAGK14", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dSetGpuRenderer);
|
||||
LIB_FUNCTION("Aacl5qkRU6U", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dStrError);
|
||||
LIB_FUNCTION("WW1TS2iz5yc", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dTerminate);
|
||||
};
|
||||
|
||||
} // namespace Libraries::Audio3d
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
|
||||
#include <stddef.h>
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/audio/audioout.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
|
@ -13,123 +15,131 @@ class SymbolsResolver;
|
|||
|
||||
namespace Libraries::Audio3d {
|
||||
|
||||
class Audio3d;
|
||||
|
||||
using OrbisUserServiceUserId = s32;
|
||||
using OrbisAudio3dPortId = u32;
|
||||
using OrbisAudio3dObjectId = u32;
|
||||
using OrbisAudio3dAttributeId = u32;
|
||||
|
||||
enum class OrbisAudio3dFormat {
|
||||
S16 = 0,
|
||||
Float = 1,
|
||||
enum class OrbisAudio3dRate : u32 {
|
||||
ORBIS_AUDIO3D_RATE_48000 = 0,
|
||||
};
|
||||
|
||||
enum class OrbisAudio3dRate {
|
||||
Rate48000 = 0,
|
||||
enum class OrbisAudio3dBufferMode : u32 {
|
||||
ORBIS_AUDIO3D_BUFFER_NO_ADVANCE = 0,
|
||||
ORBIS_AUDIO3D_BUFFER_ADVANCE_NO_PUSH = 1,
|
||||
ORBIS_AUDIO3D_BUFFER_ADVANCE_AND_PUSH = 2,
|
||||
};
|
||||
|
||||
enum class OrbisAudio3dBufferMode { NoAdvance = 0, AdvanceNoPush = 1, AdvanceAndPush = 2 };
|
||||
|
||||
enum class OrbisAudio3dBlocking {
|
||||
Async = 0,
|
||||
Sync = 1,
|
||||
};
|
||||
|
||||
enum class OrbisAudio3dPassthrough {
|
||||
None = 0,
|
||||
Left = 1,
|
||||
Right = 2,
|
||||
};
|
||||
|
||||
enum class OrbisAudio3dOutputRoute {
|
||||
Both = 0,
|
||||
HmuOnly = 1,
|
||||
TvOnly = 2,
|
||||
};
|
||||
|
||||
enum class OrbisAudio3dAmbisonics : u32 {
|
||||
None = ~0U,
|
||||
W = 0,
|
||||
X = 1,
|
||||
Y = 2,
|
||||
Z = 3,
|
||||
R = 4,
|
||||
S = 5,
|
||||
T = 6,
|
||||
U = 7,
|
||||
V = 8,
|
||||
K = 9,
|
||||
L = 10,
|
||||
M = 11,
|
||||
N = 12,
|
||||
O = 13,
|
||||
P = 14,
|
||||
Q = 15
|
||||
};
|
||||
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributePcm = 0x00000001;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributePriority = 0x00000002;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributePosition = 0x00000003;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeSpread = 0x00000004;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeGain = 0x00000005;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributePassthrough = 0x00000006;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeResetState = 0x00000007;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeApplicationSpecific = 0x00000008;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeAmbisonics = 0x00000009;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeRestricted = 0x0000000A;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeOutputRoute = 0x0000000B;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeLateReverbLevel = 0x00010001;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeDownmixSpreadRadius = 0x00010002;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeDownmixSpreadHeightAware = 0x00010003;
|
||||
|
||||
struct OrbisAudio3dSpeakerArray;
|
||||
using OrbisAudio3dSpeakerArrayHandle = OrbisAudio3dSpeakerArray*; // head
|
||||
|
||||
struct OrbisAudio3dOpenParameters {
|
||||
size_t size_this;
|
||||
u64 size_this;
|
||||
u32 granularity;
|
||||
OrbisAudio3dRate rate;
|
||||
u32 max_objects;
|
||||
u32 queue_depth;
|
||||
OrbisAudio3dBufferMode buffer_mode;
|
||||
char padding[32];
|
||||
int : 32;
|
||||
u32 num_beds;
|
||||
};
|
||||
|
||||
struct OrbisAudio3dAttribute {
|
||||
OrbisAudio3dAttributeId attribute_id;
|
||||
char padding[32];
|
||||
const void* p_value;
|
||||
size_t value;
|
||||
enum class OrbisAudio3dFormat : u32 {
|
||||
ORBIS_AUDIO3D_FORMAT_S16 = 0,
|
||||
ORBIS_AUDIO3D_FORMAT_FLOAT = 1,
|
||||
};
|
||||
|
||||
struct OrbisAudio3dPosition {
|
||||
float fX;
|
||||
float fY;
|
||||
float fZ;
|
||||
enum class OrbisAudio3dOutputRoute : u32 {
|
||||
ORBIS_AUDIO3D_OUTPUT_BOTH = 0,
|
||||
ORBIS_AUDIO3D_OUTPUT_HMU_ONLY = 1,
|
||||
ORBIS_AUDIO3D_OUTPUT_TV_ONLY = 2,
|
||||
};
|
||||
|
||||
enum class OrbisAudio3dBlocking : u32 {
|
||||
ORBIS_AUDIO3D_BLOCKING_ASYNC = 0,
|
||||
ORBIS_AUDIO3D_BLOCKING_SYNC = 1,
|
||||
};
|
||||
|
||||
struct OrbisAudio3dPcm {
|
||||
OrbisAudio3dFormat format;
|
||||
const void* sample_buffer;
|
||||
void* sample_buffer;
|
||||
u32 num_samples;
|
||||
};
|
||||
|
||||
struct OrbisAudio3dSpeakerArrayParameters {
|
||||
OrbisAudio3dPosition* speaker_position;
|
||||
u32 num_speakers;
|
||||
bool is_3d;
|
||||
void* buffer;
|
||||
size_t size;
|
||||
enum class OrbisAudio3dAttributeId : u32 {
|
||||
ORBIS_AUDIO3D_ATTRIBUTE_PCM = 1,
|
||||
};
|
||||
|
||||
struct OrbisAudio3dApplicationSpecific {
|
||||
size_t size_this;
|
||||
u8 application_specific[32];
|
||||
using OrbisAudio3dPortId = u32;
|
||||
using OrbisAudio3dObjectId = u32;
|
||||
|
||||
struct OrbisAudio3dAttribute {
|
||||
OrbisAudio3dAttributeId attribute_id;
|
||||
int : 32;
|
||||
void* value;
|
||||
u64 value_size;
|
||||
};
|
||||
|
||||
void PS4_SYSV_ABI sceAudio3dGetDefaultOpenParameters(OrbisAudio3dOpenParameters* sParameters);
|
||||
struct AudioData {
|
||||
u8* sample_buffer;
|
||||
u32 num_samples;
|
||||
};
|
||||
|
||||
struct Port {
|
||||
OrbisAudio3dOpenParameters parameters{};
|
||||
std::deque<AudioData> queue; // Only stores PCM buffers for now
|
||||
std::optional<AudioData> current_buffer{};
|
||||
};
|
||||
|
||||
struct Audio3dState {
|
||||
std::unordered_map<OrbisAudio3dPortId, Port> ports;
|
||||
s32 audio_out_handle;
|
||||
};
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutClose(s32 handle);
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutOpen(OrbisAudio3dPortId port_id, OrbisUserServiceUserId user_id,
|
||||
s32 type, s32 index, u32 len, u32 freq,
|
||||
AudioOut::OrbisAudioOutParamExtendedInformation param);
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutOutput(s32 handle, void* ptr);
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutOutputs(AudioOut::OrbisAudioOutOutputParam* param, u32 num);
|
||||
s32 PS4_SYSV_ABI sceAudio3dBedWrite(OrbisAudio3dPortId port_id, u32 num_channels,
|
||||
OrbisAudio3dFormat format, void* buffer, u32 num_samples);
|
||||
s32 PS4_SYSV_ABI sceAudio3dBedWrite2(OrbisAudio3dPortId port_id, u32 num_channels,
|
||||
OrbisAudio3dFormat format, void* buffer, u32 num_samples,
|
||||
OrbisAudio3dOutputRoute output_route, bool restricted);
|
||||
s32 PS4_SYSV_ABI sceAudio3dCreateSpeakerArray();
|
||||
s32 PS4_SYSV_ABI sceAudio3dDeleteSpeakerArray();
|
||||
s32 PS4_SYSV_ABI sceAudio3dGetDefaultOpenParameters(OrbisAudio3dOpenParameters* params);
|
||||
s32 PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMemorySize();
|
||||
s32 PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients();
|
||||
s32 PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients2();
|
||||
s32 PS4_SYSV_ABI sceAudio3dInitialize(s64 reserved);
|
||||
s32 PS4_SYSV_ABI sceAudio3dObjectReserve(OrbisAudio3dPortId port_id,
|
||||
OrbisAudio3dObjectId* object_id);
|
||||
s32 PS4_SYSV_ABI sceAudio3dObjectSetAttributes(OrbisAudio3dPortId port_id,
|
||||
OrbisAudio3dObjectId object_id, u64 num_attributes,
|
||||
const OrbisAudio3dAttribute* attribute_array);
|
||||
s32 PS4_SYSV_ABI sceAudio3dObjectUnreserve();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortAdvance(OrbisAudio3dPortId port_id);
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortClose();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortCreate();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortDestroy();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortFlush();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortFreeState();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetAttributesSupported();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetList();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetParameters();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetQueueLevel(OrbisAudio3dPortId port_id, u32* queue_level,
|
||||
u32* queue_available);
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetState();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetStatus();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortOpen(OrbisUserServiceUserId user_id,
|
||||
const OrbisAudio3dOpenParameters* parameters,
|
||||
OrbisAudio3dPortId* port_id);
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortPush(OrbisAudio3dPortId port_id, OrbisAudio3dBlocking blocking);
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortQueryDebug();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortSetAttribute(OrbisAudio3dPortId port_id,
|
||||
OrbisAudio3dAttributeId attribute_id, void* attribute,
|
||||
u64 attribute_size);
|
||||
s32 PS4_SYSV_ABI sceAudio3dReportRegisterHandler();
|
||||
s32 PS4_SYSV_ABI sceAudio3dReportUnregisterHandler();
|
||||
s32 PS4_SYSV_ABI sceAudio3dSetGpuRenderer();
|
||||
s32 PS4_SYSV_ABI sceAudio3dStrError();
|
||||
s32 PS4_SYSV_ABI sceAudio3dTerminate();
|
||||
|
||||
void RegisterlibSceAudio3d(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::Audio3d
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "core/libraries/error_codes.h"
|
||||
|
||||
constexpr int ORBIS_AUDIO3D_ERROR_UNKNOWN = 0x80EA0001;
|
||||
constexpr int ORBIS_AUDIO3D_ERROR_INVALID_PORT = 0x80EA0002;
|
||||
constexpr int ORBIS_AUDIO3D_ERROR_INVALID_OBJECT = 0x80EA0003;
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio3d_error.h"
|
||||
#include "audio3d_impl.h"
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/kernel/kernel.h"
|
||||
|
||||
using namespace Libraries::Kernel;
|
||||
|
||||
namespace Libraries::Audio3d {} // namespace Libraries::Audio3d
|
|
@ -1,16 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "audio3d.h"
|
||||
|
||||
namespace Libraries::Audio3d {
|
||||
|
||||
class Audio3d {
|
||||
public:
|
||||
private:
|
||||
using OrbisAudio3dPluginId = u32;
|
||||
};
|
||||
|
||||
} // namespace Libraries::Audio3d
|
|
@ -9,7 +9,7 @@
|
|||
namespace Libraries::Move {
|
||||
|
||||
int PS4_SYSV_ABI sceMoveOpen() {
|
||||
LOG_ERROR(Lib_Move, "(STUBBED) called");
|
||||
LOG_TRACE(Lib_Move, "(STUBBED) called");
|
||||
return ORBIS_FAIL;
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,11 @@ int PS4_SYSV_ABI sceMoveGetDeviceInfo() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceMoveReadStateLatest() {
|
||||
LOG_TRACE(Lib_Move, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceMoveReadStateRecent() {
|
||||
LOG_TRACE(Lib_Move, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
|
@ -36,6 +41,7 @@ int PS4_SYSV_ABI sceMoveInit() {
|
|||
void RegisterlibSceMove(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("HzC60MfjJxU", "libSceMove", 1, "libSceMove", 1, 1, sceMoveOpen);
|
||||
LIB_FUNCTION("GWXTyxs4QbE", "libSceMove", 1, "libSceMove", 1, 1, sceMoveGetDeviceInfo);
|
||||
LIB_FUNCTION("ttU+JOhShl4", "libSceMove", 1, "libSceMove", 1, 1, sceMoveReadStateLatest);
|
||||
LIB_FUNCTION("f2bcpK6kJfg", "libSceMove", 1, "libSceMove", 1, 1, sceMoveReadStateRecent);
|
||||
LIB_FUNCTION("tsZi60H4ypY", "libSceMove", 1, "libSceMove", 1, 1, sceMoveTerm);
|
||||
LIB_FUNCTION("j1ITE-EoJmE", "libSceMove", 1, "libSceMove", 1, 1, sceMoveInit);
|
||||
|
|
|
@ -250,7 +250,6 @@ int PS4_SYSV_ABI scePadMbusTerm() {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI scePadOpen(s32 userId, s32 type, s32 index, const OrbisPadOpenParam* pParam) {
|
||||
LOG_INFO(Lib_Pad, "(DUMMY) called user_id = {} type = {} index = {}", userId, type, index);
|
||||
if (userId == -1) {
|
||||
return ORBIS_PAD_ERROR_DEVICE_NO_HANDLE;
|
||||
}
|
||||
|
@ -261,6 +260,7 @@ int PS4_SYSV_ABI scePadOpen(s32 userId, s32 type, s32 index, const OrbisPadOpenP
|
|||
if (type != ORBIS_PAD_PORT_TYPE_STANDARD && type != ORBIS_PAD_PORT_TYPE_REMOTE_CONTROL)
|
||||
return ORBIS_PAD_ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
LOG_INFO(Lib_Pad, "(DUMMY) called user_id = {} type = {} index = {}", userId, type, index);
|
||||
scePadResetLightBar(1);
|
||||
return 1; // dummy
|
||||
}
|
||||
|
|
|
@ -104,6 +104,20 @@ s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::SceKernelEqueue eq, s32 handl
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideoOutDeleteVblankEvent(Kernel::SceKernelEqueue eq, s32 handle) {
|
||||
auto* port = driver->GetPort(handle);
|
||||
if (port == nullptr) {
|
||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (eq == nullptr) {
|
||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
|
||||
}
|
||||
eq->RemoveEvent(handle, Kernel::SceKernelEvent::Filter::VideoOut);
|
||||
port->vblank_events.erase(find(port->vblank_events.begin(), port->vblank_events.end(), eq));
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* const* addresses,
|
||||
s32 bufferNum, const BufferAttribute* attribute) {
|
||||
if (!addresses || !attribute) {
|
||||
|
@ -166,7 +180,7 @@ s32 PS4_SYSV_ABI sceVideoOutSubmitFlip(s32 handle, s32 bufferIndex, s32 flipMode
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceVideoOutGetEventId(const Kernel::SceKernelEvent* ev) {
|
||||
s32 PS4_SYSV_ABI sceVideoOutGetEventId(const Kernel::SceKernelEvent* ev) {
|
||||
if (ev == nullptr) {
|
||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_ADDRESS;
|
||||
}
|
||||
|
@ -194,7 +208,7 @@ int PS4_SYSV_ABI sceVideoOutGetEventId(const Kernel::SceKernelEvent* ev) {
|
|||
}
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceVideoOutGetEventData(const Kernel::SceKernelEvent* ev, int64_t* data) {
|
||||
s32 PS4_SYSV_ABI sceVideoOutGetEventData(const Kernel::SceKernelEvent* ev, s64* data) {
|
||||
if (ev == nullptr || data == nullptr) {
|
||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_ADDRESS;
|
||||
}
|
||||
|
@ -211,6 +225,17 @@ int PS4_SYSV_ABI sceVideoOutGetEventData(const Kernel::SceKernelEvent* ev, int64
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideoOutGetEventCount(const Kernel::SceKernelEvent* ev) {
|
||||
if (ev == nullptr) {
|
||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_ADDRESS;
|
||||
}
|
||||
if (ev->filter != Kernel::SceKernelEvent::Filter::VideoOut) {
|
||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT;
|
||||
}
|
||||
|
||||
return (ev->data >> 0xc) & 0xf;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideoOutGetFlipStatus(s32 handle, FlipStatus* status) {
|
||||
if (!status) {
|
||||
LOG_ERROR(Lib_VideoOut, "Flip status is null");
|
||||
|
@ -447,12 +472,16 @@ void RegisterLib(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("U2JJtSqNKZI", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutGetEventId);
|
||||
LIB_FUNCTION("rWUTcKdkUzQ", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||
sceVideoOutGetEventData);
|
||||
LIB_FUNCTION("Mt4QHHkxkOc", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||
sceVideoOutGetEventCount);
|
||||
LIB_FUNCTION("DYhhWbJSeRg", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||
sceVideoOutColorSettingsSetGamma);
|
||||
LIB_FUNCTION("pv9CI5VC+R0", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||
sceVideoOutAdjustColor);
|
||||
LIB_FUNCTION("-Ozn0F1AFRg", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||
sceVideoOutDeleteFlipEvent);
|
||||
LIB_FUNCTION("oNOQn3knW6s", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||
sceVideoOutDeleteVblankEvent);
|
||||
LIB_FUNCTION("pjkDsgxli6c", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||
sceVideoOutModeSetAny_);
|
||||
LIB_FUNCTION("N1bEoJ4SRw4", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||
|
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 43 KiB |
24
src/images/discord.svg
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="270.93332mm"
|
||||
height="270.93332mm"
|
||||
viewBox="0 0 270.93332 270.93332"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xml:space="preserve"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs1" /><g
|
||||
id="layer1"><circle
|
||||
style="fill:#000000;stroke-width:0.333618;fill-opacity:1"
|
||||
id="path1"
|
||||
cx="135.46666"
|
||||
cy="135.46666"
|
||||
r="135.46666" /><path
|
||||
d="m 194.12363,81.01373 c -10.93928,-5.11822 -22.63609,-8.83793 -34.86478,-10.95597 -1.50182,2.71524 -3.2564,6.36731 -4.46607,9.27253 -12.99943,-1.95495 -25.87929,-1.95495 -38.63961,0 -1.20947,-2.90522 -3.00389,-6.55729 -4.51915,-9.27253 -12.241889,2.11804 -23.952119,5.85142 -34.891409,10.98307 -22.06463,33.34254 -28.045983,65.85691 -25.055298,97.90961 14.634418,10.92863 28.816948,17.56744 42.760118,21.91169 3.44265,-4.73808 6.513019,-9.77474 9.158059,-15.08293 -5.037579,-1.91418 -9.862539,-4.27637 -14.421539,-7.01873 1.20947,-0.89604 2.39255,-1.83288 3.53556,-2.79678 27.806639,13.00588 58.019289,13.00588 85.493719,0 1.15643,0.9639 2.33926,1.90074 3.53556,2.79678 -4.57246,2.75579 -9.41061,5.11798 -14.4482,7.03241 2.64504,5.29451 5.70223,10.34483 9.15805,15.08268 13.95665,-4.34425 28.1523,-10.98282 42.78675,-21.92512 3.50912,-37.15724 -5.99459,-69.37299 -25.12176,-97.93671 z m -86.72985,78.22459 c -8.347289,0 -15.192739,-7.79268 -15.192739,-17.28227 0,-9.48958 6.69928,-17.29569 15.192739,-17.29569 8.49367,0 15.33891,7.79244 15.19272,17.29569 0.0124,9.48959 -6.69905,17.28227 -15.19272,17.28227 z m 56.14517,0 c -8.34727,0 -15.19272,-7.79268 -15.19272,-17.28227 0,-9.48958 6.69904,-17.29569 15.19272,-17.29569 8.49344,0 15.3389,7.79244 15.19272,17.29569 0,9.48959 -6.69928,17.28227 -15.19272,17.28227 z"
|
||||
fill="#5865F2"
|
||||
fill-rule="nonzero"
|
||||
id="path1-1"
|
||||
style="fill:#ffffff;stroke-width:0.660131" /></g></svg>
|
After Width: | Height: | Size: 2 KiB |
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 42 KiB |
22
src/images/github.svg
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="270.93332mm"
|
||||
height="270.93332mm"
|
||||
viewBox="0 0 270.93332 270.93332"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xml:space="preserve"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs1" /><g
|
||||
id="layer1"><circle
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.638749"
|
||||
id="path6"
|
||||
cx="135.46666"
|
||||
cy="135.46666"
|
||||
r="135.46666" /><path
|
||||
d="m 169.16642,266.41733 0.03,-25.82065 c 0.0275,-14.56818 0.019,-22.82654 -0.0238,-23.70553 -0.45287,-9.28878 -3.18131,-16.59646 -8.00675,-21.44417 -0.51833,-0.52073 -0.93407,-0.95373 -0.92397,-0.96273 0.0101,-0.009 0.44777,-0.0663 0.97255,-0.12764 37.08454,-4.33929 55.61974,-20.97235 59.5452,-53.43395 2.47353,-20.45482 -1.25492,-35.28308 -11.991,-47.687007 -0.441,-0.50949 -0.85644,-0.996495 -0.92294,-1.082105 -0.11924,-0.153612 -0.11632,-0.168083 0.21291,-1.092956 3.48926,-9.801891 3.08146,-21.84476 -1.12293,-33.147331 -0.65397,-1.758042 -0.47565,-1.634201 -2.5709,-1.78077 -7.91812,-0.553905 -20.35359,4.335862 -33.80673,13.293762 l -1.15135,0.766879 -0.52658,-0.150896 c -12.92077,-3.704851 -29.09272,-5.157035 -43.79112,-3.932576 -7.21573,0.601112 -14.83438,1.91638 -21.45193,3.70365 l -1.41438,0.381889 -0.95446,-0.635621 C 86.99336,60.049959 72.837429,54.806634 65.589795,56.343848 l -0.309542,0.06563 -0.326595,0.837675 c -4.332806,11.118399 -4.907871,23.48198 -1.547192,33.270837 0.236072,0.687637 0.444934,1.31371 0.464054,1.39113 0.02704,0.109638 -0.130307,0.328834 -0.711584,0.990637 -9.160582,10.429614 -13.392033,22.887494 -12.958383,38.152714 1.106869,38.96344 19.486075,58.39373 59.852157,63.27469 0.65144,0.0787 1.19093,0.14903 1.19993,0.15503 0.008,0.007 -0.42227,0.45425 -0.95705,0.99477 -3.85869,3.90015 -6.54793,9.80164 -7.46414,16.38039 l -0.0827,0.59221 -0.36174,0.17829 c -1.57996,0.77769 -4.999926,1.92702 -7.319448,2.4598 -12.017875,2.76038 -22.054909,-0.77155 -29.200801,-10.27535 -0.611821,-0.81369 -1.002109,-1.39605 -2.631881,-3.92379 -6.342866,-9.8377 -15.85558,-14.92007 -24.055896,-12.85296 -4.140227,1.04365 -2.520489,4.818 3.538802,8.24704 4.584375,2.59434 11.458806,12.02482 14.328324,19.65565 5.313949,14.13125 20.872615,19.63362 43.89345,15.52308 0.48859,-0.0872 0.93963,-0.15902 1.00303,-0.15916 0.10915,-2.5e-4 0.11524,0.79731 0.11524,15.82539 v 19.35334 a 135.46666,135.46666 0 0 0 33.40882,4.45244 135.46666,135.46666 0 0 0 33.69975,-4.516 z"
|
||||
style="fill:#ffffff;stroke-width:0.777192"
|
||||
id="path5" /></g></svg>
|
After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
22
src/images/ko-fi.svg
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="270.93332mm"
|
||||
height="270.93332mm"
|
||||
viewBox="0 0 270.93332 270.93332"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xml:space="preserve"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs1" /><g
|
||||
id="layer1"><circle
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.638749"
|
||||
id="path6"
|
||||
cx="135.46666"
|
||||
cy="135.46666"
|
||||
r="135.46666" /><path
|
||||
d="M 245.29662,112.91788 C 238.59944,77.525962 203.19888,73.124713 203.19888,73.124713 H 44.658761 c -5.232973,0 -5.882763,6.913782 -5.882763,6.913782 0,0 -0.710438,63.454165 -0.190612,102.424225 1.420874,21.00124 22.404764,23.14987 22.404764,23.14987 0,0 71.62419,-0.19923 103.67183,-0.42453 21.12252,-3.69082 23.24517,-22.23147 23.02856,-32.35089 37.70517,2.07933 64.30326,-24.52739 57.60608,-59.91929 z m -95.83971,30.41882 c -10.79518,12.58861 -34.75078,34.44754 -34.75078,34.44754 0,0 -1.04833,1.031 -2.6858,0.19924 -0.65845,-0.49382 -0.93569,-0.77972 -0.93569,-0.77972 -3.83809,-3.82079 -29.179908,-26.41616 -34.950046,-34.25694 -6.14268,-8.36065 -9.019085,-23.39244 -0.788412,-32.14296 8.239342,-8.75052 26.034928,-9.40895 37.800448,3.5262 0,0 13.55896,-15.439026 30.0463,-8.34332 16.49601,7.1044 15.8722,26.0869 6.26398,37.34992 z m 53.48205,4.14135 c -8.04007,1.00499 -14.57263,0.24252 -14.57263,0.24252 V 98.501153 h 15.33506 c 0,0 17.07647,4.773777 17.07647,22.855257 0,16.57399 -8.53391,23.10655 -17.8389,26.12157 z"
|
||||
id="path1"
|
||||
style="fill:#ffffff;stroke-width:8.66388" /></g></svg>
|
After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 401 KiB |
BIN
src/images/shadps4.png
Normal file
After Width: | Height: | Size: 34 KiB |
105
src/images/shadps4.svg
Normal file
|
@ -0,0 +1,105 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
version="1.1"
|
||||
viewBox="0 0 256 256"
|
||||
xml:space="preserve"
|
||||
id="svg10"
|
||||
width="256"
|
||||
height="256"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs3"><linearGradient
|
||||
id="linearGradient1"><stop
|
||||
stop-color="#0b034f"
|
||||
offset="0"
|
||||
id="stop1" /><stop
|
||||
stop-color="#4461f2"
|
||||
offset="1"
|
||||
id="stop2" /></linearGradient><linearGradient
|
||||
id="linearGradient2"
|
||||
x1="100"
|
||||
x2="100"
|
||||
y1="185.84"
|
||||
y2="14.157"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
xlink:href="#linearGradient1"
|
||||
gradientTransform="matrix(1.4489308,0,0,1.4489308,-16.890188,-16.890188)" /><mask
|
||||
id="mask9"
|
||||
maskUnits="userSpaceOnUse"><path
|
||||
d="m -4.1597,120.43 65.304,22.774 -20.899,59.926 -65.304,-22.774 z"
|
||||
fill="none"
|
||||
stroke="#149ffb"
|
||||
stroke-linecap="square"
|
||||
stroke-width="11"
|
||||
style="paint-order:markers fill stroke"
|
||||
id="path2" /></mask><mask
|
||||
id="mask10"
|
||||
maskUnits="userSpaceOnUse"><path
|
||||
d="M 178.79,52.448 133.386,71.834 139.2995,22.82 Z"
|
||||
fill="none"
|
||||
stroke="#149ffb"
|
||||
stroke-linecap="square"
|
||||
stroke-width="6.75"
|
||||
style="paint-order:markers fill stroke"
|
||||
id="path3" /></mask><linearGradient
|
||||
xlink:href="#linearGradient1"
|
||||
id="linearGradient10"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="100"
|
||||
y1="185.84"
|
||||
x2="100"
|
||||
y2="14.157"
|
||||
gradientTransform="matrix(1.4489308,0,0,1.4489308,-16.890188,-16.890188)" /></defs><path
|
||||
d="M 53.640867,3.6223249 H 202.35913 c 27.70935,0 50.01854,22.3077391 50.01854,50.0185421 V 202.35913 c 0,27.70935 -22.30774,50.01854 -50.01854,50.01854 H 53.640867 c -27.709354,0 -50.0185421,-22.30774 -50.0185421,-50.01854 V 53.640867 c 0,-27.709354 22.3077391,-50.0185421 50.0185421,-50.0185421 z"
|
||||
fill="url(#linearGradient2)"
|
||||
stroke="#ffffff"
|
||||
stroke-linecap="square"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="7.24465"
|
||||
style="fill:url(#linearGradient10);paint-order:markers fill stroke"
|
||||
id="path4" /><path
|
||||
d="M 53.640867,3.6223249 H 202.35913 c 27.70935,0 50.01854,22.3077391 50.01854,50.0185421 V 202.35913 c 0,27.70935 -22.30774,50.01854 -50.01854,50.01854 H 53.640867 c -27.709354,0 -50.0185421,-22.30774 -50.0185421,-50.01854 V 53.640867 c 0,-27.709354 22.3077391,-50.0185421 50.0185421,-50.0185421 z"
|
||||
fill="url(#linearGradient2)"
|
||||
stroke="#ffffff"
|
||||
stroke-linecap="square"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="7.24465"
|
||||
style="fill:url(#linearGradient2);paint-order:markers fill stroke"
|
||||
id="path5" /><path
|
||||
d="m 50.17,16.403 h 99.848 c 18.603,0 33.58,14.977 33.58,33.58 v 99.848 c 0,18.603 -14.977,33.58 -33.58,33.58 H 50.17 c -18.603,0 -33.58,-14.977 -33.58,-33.58 V 49.983 c 0,-18.603 14.977,-33.58 33.58,-33.58 z"
|
||||
fill="#00ffff"
|
||||
mask="url(#mask9)"
|
||||
style="paint-order:markers fill stroke"
|
||||
id="path6"
|
||||
transform="matrix(1.4489308,0,0,1.4489308,-16.890189,-16.890189)" /><path
|
||||
d="m 50.076,16.496 h 99.848 c 18.603,0 33.58,14.977 33.58,33.58 v 99.848 c 0,18.603 -14.977,33.58 -33.58,33.58 H 50.076 c -18.603,0 -33.58,-14.977 -33.58,-33.58 V 50.076 c 0,-18.603 14.977,-33.58 33.58,-33.58 z"
|
||||
fill="#00ffff"
|
||||
mask="url(#mask10)"
|
||||
style="paint-order:markers fill stroke"
|
||||
id="path7"
|
||||
transform="matrix(1.4489308,0,0,1.4489308,-16.890189,-16.890189)" /><g
|
||||
fill="none"
|
||||
id="g10"
|
||||
transform="matrix(1.4489308,0,0,1.4489308,-16.890189,-16.890189)"><path
|
||||
transform="matrix(0.91041,0.0063593,-0.0063593,0.91041,28.548,42.178)"
|
||||
d="m 166.13,88.68 -23.677,14.288 13.949,23.879 -14.288,-23.677 -23.879,13.949 23.677,-14.288 -13.949,-23.879 14.288,23.677 z"
|
||||
stroke="#139ffb"
|
||||
stroke-linecap="square"
|
||||
stroke-width="12.43"
|
||||
style="paint-order:markers fill stroke"
|
||||
id="path8" /><path
|
||||
d="M 117.98,135.88 V 47.598 l -65.093,69.568 h 83.807"
|
||||
stroke="#ffffff"
|
||||
stroke-linecap="square"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="10"
|
||||
style="font-variation-settings:normal;paint-order:markers fill stroke"
|
||||
id="path9" /><path
|
||||
d="M 69.923,56.468 A 20.994,21.009 0 0 1 49.012,77.477 20.994,21.009 0 0 1 27.936,56.634 20.994,21.009 0 0 1 48.68,35.46 20.994,21.009 0 0 1 69.92,56.135"
|
||||
stop-color="#000000"
|
||||
stroke="#139ffb"
|
||||
stroke-linecap="round"
|
||||
stroke-width="9.4488"
|
||||
style="paint-order:markers fill stroke"
|
||||
id="path10" /></g></svg>
|
After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 72 KiB |
22
src/images/website.svg
Normal file
After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 32 KiB |
28
src/images/youtube.svg
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="270.93332mm"
|
||||
height="270.93332mm"
|
||||
viewBox="0 0 270.93332 270.93332"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xml:space="preserve"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs1" /><g
|
||||
id="layer1"><circle
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.638749"
|
||||
id="path6"
|
||||
cx="135.46666"
|
||||
cy="135.46666"
|
||||
r="135.46666" /><g
|
||||
style="fill:#ffffff;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none"
|
||||
transform="matrix(1.8837557,0,0,1.8837557,50.69765,50.69765)"
|
||||
id="g1">
|
||||
<path
|
||||
d="M 88.119,23.338 C 87.084,19.466 84.034,16.416 80.162,15.381 73.144,13.5 45,13.5 45,13.5 c 0,0 -28.144,0 -35.162,1.881 C 5.966,16.416 2.916,19.466 1.881,23.338 0,30.356 0,45 0,45 0,45 0,59.644 1.881,66.662 2.916,70.534 5.966,73.584 9.838,74.619 16.856,76.5 45,76.5 45,76.5 c 0,0 28.144,0 35.162,-1.881 3.872,-1.035 6.922,-4.085 7.957,-7.957 C 90,59.644 90,45 90,45 90,45 90,30.356 88.119,23.338 Z M 36,58.5 v -27 L 59.382,45 Z"
|
||||
style="opacity:1;fill:#ffffff;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none"
|
||||
stroke-linecap="round"
|
||||
id="path1" />
|
||||
</g></g></svg>
|
After Width: | Height: | Size: 1.4 KiB |
|
@ -50,14 +50,14 @@ inline void KeepWindowInside(ImVec2 display_size = GetIO().DisplaySize) {
|
|||
}
|
||||
|
||||
inline void KeepNavHighlight() {
|
||||
GetCurrentContext()->NavDisableHighlight = false;
|
||||
GetCurrentContext()->NavCursorVisible = true;
|
||||
}
|
||||
|
||||
inline void SetItemCurrentNavFocus(const ImGuiID id = -1) {
|
||||
const auto ctx = GetCurrentContext();
|
||||
SetFocusID(id == -1 ? ctx->LastItemData.ID : id, ctx->CurrentWindow);
|
||||
ctx->NavInitResult.Clear();
|
||||
ctx->NavDisableHighlight = false;
|
||||
ctx->NavCursorVisible = true;
|
||||
}
|
||||
|
||||
inline void DrawPrettyBackground() {
|
||||
|
|
|
@ -550,18 +550,18 @@ void ControllerOutput::FinalizeUpdate() {
|
|||
break;
|
||||
case Axis::TriggerLeft:
|
||||
ApplyDeadzone(new_param, lefttrigger_deadzone);
|
||||
controller->Axis(0, c_axis, GetAxis(0x0, 0x80, *new_param));
|
||||
controller->Axis(0, c_axis, GetAxis(0x0, 0x7f, *new_param));
|
||||
controller->CheckButton(0, OrbisPadButtonDataOffset::L2, *new_param > 0x20);
|
||||
return;
|
||||
case Axis::TriggerRight:
|
||||
ApplyDeadzone(new_param, righttrigger_deadzone);
|
||||
controller->Axis(0, c_axis, GetAxis(0x0, 0x80, *new_param));
|
||||
controller->Axis(0, c_axis, GetAxis(0x0, 0x7f, *new_param));
|
||||
controller->CheckButton(0, OrbisPadButtonDataOffset::R2, *new_param > 0x20);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
controller->Axis(0, c_axis, GetAxis(-0x80, 0x80, *new_param * multiplier));
|
||||
controller->Axis(0, c_axis, GetAxis(-0x80, 0x7f, *new_param * multiplier));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,11 +61,11 @@ Uint32 MousePolling(void* param, Uint32 id, Uint32 interval) {
|
|||
float a_x = cos(angle) * output_speed, a_y = sin(angle) * output_speed;
|
||||
|
||||
if (d_x != 0 && d_y != 0) {
|
||||
controller->Axis(0, axis_x, GetAxis(-0x80, 0x80, a_x));
|
||||
controller->Axis(0, axis_y, GetAxis(-0x80, 0x80, a_y));
|
||||
controller->Axis(0, axis_x, GetAxis(-0x80, 0x7f, a_x));
|
||||
controller->Axis(0, axis_y, GetAxis(-0x80, 0x7f, a_y));
|
||||
} else {
|
||||
controller->Axis(0, axis_x, GetAxis(-0x80, 0x80, 0));
|
||||
controller->Axis(0, axis_y, GetAxis(-0x80, 0x80, 0));
|
||||
controller->Axis(0, axis_x, GetAxis(-0x80, 0x7f, 0));
|
||||
controller->Axis(0, axis_y, GetAxis(-0x80, 0x7f, 0));
|
||||
}
|
||||
|
||||
return interval;
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap>:/images/shadps4.ico</pixmap>
|
||||
<pixmap>:/images/shadps4.png</pixmap>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>true</bool>
|
||||
|
|
|
@ -188,7 +188,7 @@ void CheckUpdate::setupUI(const QString& downloadUrl, const QString& latestDate,
|
|||
QHBoxLayout* titleLayout = new QHBoxLayout();
|
||||
|
||||
QLabel* imageLabel = new QLabel(this);
|
||||
QPixmap pixmap(":/images/shadps4.ico");
|
||||
QPixmap pixmap(":/images/shadps4.png");
|
||||
imageLabel->setPixmap(pixmap);
|
||||
imageLabel->setScaledContents(true);
|
||||
imageLabel->setFixedSize(50, 50);
|
||||
|
|
|
@ -516,9 +516,11 @@ void MainWindow::CreateConnects() {
|
|||
Config::setIconSize(36);
|
||||
Config::setSliderPosition(0);
|
||||
} else {
|
||||
m_game_grid_frame->icon_size = 69;
|
||||
ui->sizeSlider->setValue(0); // icone_size - 36
|
||||
Config::setIconSizeGrid(69);
|
||||
Config::setSliderPositionGrid(0);
|
||||
m_game_grid_frame->PopulateGameGrid(m_game_info->m_games, false);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -529,9 +531,11 @@ void MainWindow::CreateConnects() {
|
|||
Config::setIconSize(64);
|
||||
Config::setSliderPosition(28);
|
||||
} else {
|
||||
m_game_grid_frame->icon_size = 97;
|
||||
ui->sizeSlider->setValue(28);
|
||||
Config::setIconSizeGrid(97);
|
||||
Config::setSliderPositionGrid(28);
|
||||
m_game_grid_frame->PopulateGameGrid(m_game_info->m_games, false);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -542,9 +546,11 @@ void MainWindow::CreateConnects() {
|
|||
Config::setIconSize(128);
|
||||
Config::setSliderPosition(92);
|
||||
} else {
|
||||
m_game_grid_frame->icon_size = 161;
|
||||
ui->sizeSlider->setValue(92);
|
||||
Config::setIconSizeGrid(160);
|
||||
Config::setSliderPositionGrid(91);
|
||||
Config::setIconSizeGrid(161);
|
||||
Config::setSliderPositionGrid(92);
|
||||
m_game_grid_frame->PopulateGameGrid(m_game_info->m_games, false);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -555,9 +561,11 @@ void MainWindow::CreateConnects() {
|
|||
Config::setIconSize(256);
|
||||
Config::setSliderPosition(220);
|
||||
} else {
|
||||
m_game_grid_frame->icon_size = 256;
|
||||
ui->sizeSlider->setValue(220);
|
||||
Config::setIconSizeGrid(256);
|
||||
Config::setSliderPositionGrid(220);
|
||||
m_game_grid_frame->PopulateGameGrid(m_game_info->m_games, false);
|
||||
}
|
||||
});
|
||||
// List
|
||||
|
@ -577,6 +585,7 @@ void MainWindow::CreateConnects() {
|
|||
ui->sizeSlider->setEnabled(true);
|
||||
ui->sizeSlider->setSliderPosition(slider_pos);
|
||||
ui->mw_searchbar->setText("");
|
||||
SetLastIconSizeBullet();
|
||||
});
|
||||
// Grid
|
||||
connect(ui->setlistModeGridAct, &QAction::triggered, m_dock_widget.data(), [this]() {
|
||||
|
@ -595,6 +604,7 @@ void MainWindow::CreateConnects() {
|
|||
ui->sizeSlider->setEnabled(true);
|
||||
ui->sizeSlider->setSliderPosition(slider_pos_grid);
|
||||
ui->mw_searchbar->setText("");
|
||||
SetLastIconSizeBullet();
|
||||
});
|
||||
// Elf Viewer
|
||||
connect(ui->setlistElfAct, &QAction::triggered, m_dock_widget.data(), [this]() {
|
||||
|
@ -606,6 +616,7 @@ void MainWindow::CreateConnects() {
|
|||
isTableList = false;
|
||||
ui->sizeSlider->setDisabled(true);
|
||||
Config::setTableMode(2);
|
||||
SetLastIconSizeBullet();
|
||||
});
|
||||
|
||||
// Cheats/Patches Download.
|
||||
|
@ -1031,19 +1042,37 @@ void MainWindow::SetLastUsedTheme() {
|
|||
void MainWindow::SetLastIconSizeBullet() {
|
||||
// set QAction bullet point if applicable
|
||||
int lastSize = Config::getIconSize();
|
||||
switch (lastSize) {
|
||||
case 36:
|
||||
ui->setIconSizeTinyAct->setChecked(true);
|
||||
break;
|
||||
case 64:
|
||||
ui->setIconSizeSmallAct->setChecked(true);
|
||||
break;
|
||||
case 128:
|
||||
ui->setIconSizeMediumAct->setChecked(true);
|
||||
break;
|
||||
case 256:
|
||||
ui->setIconSizeLargeAct->setChecked(true);
|
||||
break;
|
||||
int lastSizeGrid = Config::getIconSizeGrid();
|
||||
if (isTableList) {
|
||||
switch (lastSize) {
|
||||
case 36:
|
||||
ui->setIconSizeTinyAct->setChecked(true);
|
||||
break;
|
||||
case 64:
|
||||
ui->setIconSizeSmallAct->setChecked(true);
|
||||
break;
|
||||
case 128:
|
||||
ui->setIconSizeMediumAct->setChecked(true);
|
||||
break;
|
||||
case 256:
|
||||
ui->setIconSizeLargeAct->setChecked(true);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (lastSizeGrid) {
|
||||
case 69:
|
||||
ui->setIconSizeTinyAct->setChecked(true);
|
||||
break;
|
||||
case 97:
|
||||
ui->setIconSizeSmallAct->setChecked(true);
|
||||
break;
|
||||
case 161:
|
||||
ui->setIconSizeMediumAct->setChecked(true);
|
||||
break;
|
||||
case 256:
|
||||
ui->setIconSizeLargeAct->setChecked(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1892,43 +1892,43 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</source>
|
||||
<translation type="unfinished">Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
<translation>نسخ مخازن الذاكرة الخاصة بالـ GPU:\nيتجاوز مشكلة التزامن المتعلقة بتقديمات GPU.\n قد يساعد أو لا يساعد في حل أعطال PM4 من النوع 0.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</source>
|
||||
<translation type="unfinished">Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
<translation>علامات تصحيح الأخطاء للمضيف:\nقوم بإدراج معلومات في المحاكي مثل علامات للأوامر AMDGPU المرتبطة بأوامر فولكن، إضافةً إلى تخصيص أسماء لتصحيح الأخطاء للموارد.\nمن الأفضل تفعيل تشخيص الأعطال عند تفعيل هذه الخاصية.\nمفيد لبرامج مثل أداة تصحيح الأخطاء الرسومية.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</source>
|
||||
<translation type="unfinished">Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
<translation>علامات تصحيح الضيف:\nيُدخل أي علامات تصحيح أضافتها اللعبة بنفسها إلى ذاكرة أوامر الرسوميات.\nإذا تم التفعيل الأفضل تمكين "تشخيص الأعطال".\nمفيد لبرامج مثل دوك.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save Data Path:\nThe folder where game save data will be saved.</source>
|
||||
<translation type="unfinished">Save Data Path:\nThe folder where game save data will be saved.</translation>
|
||||
<translation>مسار حفظ البيانات:\nالمجلد الذي سيتم فيه حفظ بيانات تخزين اللعبة.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Browse:\nBrowse for a folder to set as the save data path.</source>
|
||||
<translation type="unfinished">Browse:\nBrowse for a folder to set as the save data path.</translation>
|
||||
<translation>تصفح:\nاختر مجلدًا لتحديده كمكان لحفظ بيانات التخزين.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Release</source>
|
||||
<translation type="unfinished">Release</translation>
|
||||
<translation>إصدار</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Nightly</source>
|
||||
<translation type="unfinished">Nightly</translation>
|
||||
<translation>إصدار ليلي</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Set the volume of the background music.</source>
|
||||
<translation type="unfinished">Set the volume of the background music.</translation>
|
||||
<translation>ضبط صوت الموسيقى في الخلفية.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Motion Controls</source>
|
||||
<translation type="unfinished">Enable Motion Controls</translation>
|
||||
<translation>تفعيل التحكم بالحركة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save Data Path</source>
|
||||
<translation type="unfinished">Save Data Path</translation>
|
||||
<translation>مسار بيانات الحفظ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Browse</source>
|
||||
|
@ -1936,15 +1936,15 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>async</source>
|
||||
<translation type="unfinished">async</translation>
|
||||
<translation>غير متزامن</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sync</source>
|
||||
<translation type="unfinished">sync</translation>
|
||||
<translation>متزامن</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Auto Select</source>
|
||||
<translation type="unfinished">Auto Select</translation>
|
||||
<translation>تلقائي</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Directory to install games</source>
|
||||
|
@ -1952,11 +1952,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Directory to save data</source>
|
||||
<translation type="unfinished">Directory to save data</translation>
|
||||
<translation>مسار الحفظ لبيانات الألعاب</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Video</source>
|
||||
<translation type="unfinished">Video</translation>
|
||||
<translation>الفيديو</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Display Mode</source>
|
||||
|
@ -1992,7 +1992,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Separate Log Files:\nWrites a separate logfile for each game.</source>
|
||||
<translation type="unfinished">Separate Log Files:\nWrites a separate logfile for each game.</translation>
|
||||
<translation>ملفات السجل المنفصلة:\nيتم كتابة سجل منفصل لكل لعبه.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trophy Notification Position</source>
|
||||
|
@ -2028,7 +2028,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Portable user folder:\nStores shadPS4 settings and data that will be applied only to the shadPS4 build located in the current folder. Restart the app after creating the portable user folder to begin using it.</source>
|
||||
<translation type="unfinished">Portable user folder:\nStores shadPS4 settings and data that will be applied only to the shadPS4 build located in the current folder. Restart the app after creating the portable user folder to begin using it.</translation>
|
||||
<translation>مجلد المستخدم القابل للنقل:\nتخزين إعدادات وبيانات المحاكي التي ستُطبق فقط على هذا الإصدار في المجلد الحالي. بعد إنشاء مجلد المستخدم القابل للنقل، يجب إعادة تشغيل التطبيق للبدء في استخدامه.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cannot create portable user folder</source>
|
||||
|
@ -2040,7 +2040,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Portable user folder created</source>
|
||||
<translation type="unfinished">Portable user folder created</translation>
|
||||
<translation>تم إنشاء مجلد مستخدم محمول</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 successfully created.</source>
|
||||
|
@ -2048,7 +2048,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Open the custom trophy images/sounds folder:\nYou can add custom images to the trophies and an audio.\nAdd the files to custom_trophy with the following names:\ntrophy.wav OR trophy.mp3, bronze.png, gold.png, platinum.png, silver.png\nNote: The sound will only work in QT versions.</source>
|
||||
<translation type="unfinished">Open the custom trophy images/sounds folder:\nYou can add custom images to the trophies and an audio.\nAdd the files to custom_trophy with the following names:\ntrophy.wav OR trophy.mp3, bronze.png, gold.png, platinum.png, silver.png\nNote: The sound will only work in QT versions.</translation>
|
||||
<translation>افتح مجلد الصور/الأصوات الخاصة بالجوائز المخصصة:\nيمكنك إضافة صور مخصصة للجوائز وصوت مرفق.\nأضف الملفات إلى مجلد custom_trophy بالأسماء التالية:\ntrophy.wav أو trophy.mp3، bronze.png، gold.png، platinum.png، silver.png\nملاحظة: الصوت سيعمل فقط في الإصدارات التي تستخدم QT.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<name>AboutDialog</name>
|
||||
<message>
|
||||
<source>About shadPS4</source>
|
||||
<translation type="unfinished">About shadPS4</translation>
|
||||
<translation>Over shadPS4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>shadPS4 is an experimental open-source emulator for the PlayStation 4.</source>
|
||||
|
@ -582,7 +582,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Could not open the file for reading</source>
|
||||
<translation type="unfinished">Could not open the file for reading</translation>
|
||||
<translation/>
|
||||
</message>
|
||||
<message>
|
||||
<source>Could not open the file for writing</source>
|
||||
|
|
2081
src/qt_gui/translations/sl_SI.ts
Normal file
|
@ -267,12 +267,12 @@ Id EmitFPFrexpSig64(EmitContext& ctx, Id value) {
|
|||
|
||||
Id EmitFPFrexpExp32(EmitContext& ctx, Id value) {
|
||||
const auto frexp = ctx.OpFrexpStruct(ctx.frexp_result_f32, value);
|
||||
return ctx.OpCompositeExtract(ctx.U32[1], frexp, 1);
|
||||
return ctx.OpBitcast(ctx.U32[1], ctx.OpCompositeExtract(ctx.S32[1], frexp, 1));
|
||||
}
|
||||
|
||||
Id EmitFPFrexpExp64(EmitContext& ctx, Id value) {
|
||||
const auto frexp = ctx.OpFrexpStruct(ctx.frexp_result_f64, value);
|
||||
return ctx.OpCompositeExtract(ctx.U32[1], frexp, 1);
|
||||
return ctx.OpBitcast(ctx.U32[1], ctx.OpCompositeExtract(ctx.S32[1], frexp, 1));
|
||||
}
|
||||
|
||||
Id EmitFPOrdEqual16(EmitContext& ctx, Id lhs, Id rhs) {
|
||||
|
|
|
@ -153,9 +153,9 @@ void EmitContext::DefineArithmeticTypes() {
|
|||
|
||||
full_result_i32x2 = Name(TypeStruct(S32[1], S32[1]), "full_result_i32x2");
|
||||
full_result_u32x2 = Name(TypeStruct(U32[1], U32[1]), "full_result_u32x2");
|
||||
frexp_result_f32 = Name(TypeStruct(F32[1], U32[1]), "frexp_result_f32");
|
||||
frexp_result_f32 = Name(TypeStruct(F32[1], S32[1]), "frexp_result_f32");
|
||||
if (info.uses_fp64) {
|
||||
frexp_result_f64 = Name(TypeStruct(F64[1], U32[1]), "frexp_result_f64");
|
||||
frexp_result_f64 = Name(TypeStruct(F64[1], S32[1]), "frexp_result_f64");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2784,8 +2784,7 @@ constexpr std::array<InstFormat, 256> InstructionFormatDS = {{
|
|||
// 62 = DS_APPEND
|
||||
{InstClass::DsAppendCon, InstCategory::DataShare, 3, 1, ScalarType::Uint32, ScalarType::Uint32},
|
||||
// 63 = DS_ORDERED_COUNT
|
||||
{InstClass::GdsOrdCnt, InstCategory::DataShare, 3, 1, ScalarType::Undefined,
|
||||
ScalarType::Undefined},
|
||||
{InstClass::GdsOrdCnt, InstCategory::DataShare, 3, 1, ScalarType::Uint32, ScalarType::Uint32},
|
||||
// 64 = DS_ADD_U64
|
||||
{InstClass::DsAtomicArith64, InstCategory::DataShare, 3, 1, ScalarType::Uint64,
|
||||
ScalarType::Uint64},
|
||||
|
|
|
@ -1010,8 +1010,10 @@ void Translator::V_CMP_CLASS_F32(const GcnInst& inst) {
|
|||
value = ir.FPIsNan(src0);
|
||||
} else if ((class_mask & IR::FloatClassFunc::Infinity) == IR::FloatClassFunc::Infinity) {
|
||||
value = ir.FPIsInf(src0);
|
||||
} else if ((class_mask & IR::FloatClassFunc::Negative) == IR::FloatClassFunc::Negative) {
|
||||
value = ir.FPLessThanEqual(src0, ir.Imm32(-0.f));
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
UNREACHABLE_MSG("Unsupported float class mask: {:#x}", static_cast<u32>(class_mask));
|
||||
}
|
||||
} else {
|
||||
// We don't know the type yet, delay its resolution.
|
||||
|
|
|
@ -235,9 +235,12 @@ std::pair<const IR::Inst*, bool> TryDisableAnisoLod0(const IR::Inst* inst) {
|
|||
return {prod2, true};
|
||||
}
|
||||
|
||||
SharpLocation TrackSharp(const IR::Inst* inst, const Shader::Info& info) {
|
||||
SharpLocation AttemptTrackSharp(const IR::Inst* inst, auto& visited_insts) {
|
||||
// Search until we find a potential sharp source.
|
||||
const auto pred = [](const IR::Inst* inst) -> std::optional<const IR::Inst*> {
|
||||
const auto pred = [&visited_insts](const IR::Inst* inst) -> std::optional<const IR::Inst*> {
|
||||
if (std::ranges::find(visited_insts, inst) != visited_insts.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (inst->GetOpcode() == IR::Opcode::GetUserData ||
|
||||
inst->GetOpcode() == IR::Opcode::ReadConst) {
|
||||
return inst;
|
||||
|
@ -247,6 +250,7 @@ SharpLocation TrackSharp(const IR::Inst* inst, const Shader::Info& info) {
|
|||
const auto result = IR::BreadthFirstSearch(inst, pred);
|
||||
ASSERT_MSG(result, "Unable to track sharp source");
|
||||
inst = result.value();
|
||||
visited_insts.emplace_back(inst);
|
||||
if (inst->GetOpcode() == IR::Opcode::GetUserData) {
|
||||
return static_cast<u32>(inst->Arg(0).ScalarReg());
|
||||
} else {
|
||||
|
@ -256,6 +260,29 @@ SharpLocation TrackSharp(const IR::Inst* inst, const Shader::Info& info) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Tracks a sharp with validation of the chosen data type.
|
||||
template <typename DataType>
|
||||
std::pair<SharpLocation, DataType> TrackSharp(const IR::Inst* inst, const Info& info) {
|
||||
boost::container::small_vector<const IR::Inst*, 4> visited_insts{};
|
||||
while (true) {
|
||||
const auto prev_size = visited_insts.size();
|
||||
const auto sharp = AttemptTrackSharp(inst, visited_insts);
|
||||
if (const auto data = info.ReadUdSharp<DataType>(sharp); data.Valid()) {
|
||||
return std::make_pair(sharp, data);
|
||||
}
|
||||
if (prev_size == visited_insts.size()) {
|
||||
// No change in visited instructions, we've run out of paths.
|
||||
UNREACHABLE_MSG("Unable to find valid sharp.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks a sharp without data validation.
|
||||
SharpLocation TrackSharp(const IR::Inst* inst, const Info& info) {
|
||||
boost::container::static_vector<const IR::Inst*, 1> visited_insts{};
|
||||
return AttemptTrackSharp(inst, visited_insts);
|
||||
}
|
||||
|
||||
s32 TryHandleInlineCbuf(IR::Inst& inst, Info& info, Descriptors& descriptors,
|
||||
AmdGpu::Buffer& cbuf) {
|
||||
|
||||
|
@ -293,8 +320,8 @@ void PatchBufferSharp(IR::Block& block, IR::Inst& inst, Info& info, Descriptors&
|
|||
if (binding = TryHandleInlineCbuf(inst, info, descriptors, buffer); binding == -1) {
|
||||
IR::Inst* handle = inst.Arg(0).InstRecursive();
|
||||
IR::Inst* producer = handle->Arg(0).InstRecursive();
|
||||
const auto sharp = TrackSharp(producer, info);
|
||||
buffer = info.ReadUdSharp<AmdGpu::Buffer>(sharp);
|
||||
SharpLocation sharp;
|
||||
std::tie(sharp, buffer) = TrackSharp<AmdGpu::Buffer>(producer, info);
|
||||
binding = descriptors.Add(BufferResource{
|
||||
.sharp_idx = sharp,
|
||||
.used_types = BufferDataType(inst, buffer.GetNumberFmt()),
|
||||
|
|
|
@ -25,6 +25,7 @@ enum class FloatClassFunc : u32 {
|
|||
|
||||
NaN = SignalingNan | QuietNan,
|
||||
Infinity = PositiveInfinity | NegativeInfinity,
|
||||
Negative = NegativeInfinity | NegativeNormal | NegativeDenorm | NegativeZero,
|
||||
Finite = NegativeNormal | NegativeDenorm | NegativeZero | PositiveNormal | PositiveDenorm |
|
||||
PositiveZero,
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>images/shadps4.ico</file>
|
||||
<file>images/shadps4.png</file>
|
||||
<file>images/about_icon.png</file>
|
||||
<file>images/dump_icon.png</file>
|
||||
<file>images/play_icon.png</file>
|
||||
|
|
|
@ -156,6 +156,18 @@ vk::CullModeFlags CullMode(Liverpool::CullMode mode) {
|
|||
}
|
||||
}
|
||||
|
||||
vk::FrontFace FrontFace(Liverpool::FrontFace face) {
|
||||
switch (face) {
|
||||
case Liverpool::FrontFace::Clockwise:
|
||||
return vk::FrontFace::eClockwise;
|
||||
case Liverpool::FrontFace::CounterClockwise:
|
||||
return vk::FrontFace::eCounterClockwise;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return vk::FrontFace::eClockwise;
|
||||
}
|
||||
}
|
||||
|
||||
vk::BlendFactor BlendFactor(Liverpool::BlendControl::BlendFactor factor) {
|
||||
using BlendFactor = Liverpool::BlendControl::BlendFactor;
|
||||
switch (factor) {
|
||||
|
|
|
@ -26,6 +26,8 @@ vk::PolygonMode PolygonMode(Liverpool::PolygonMode mode);
|
|||
|
||||
vk::CullModeFlags CullMode(Liverpool::CullMode mode);
|
||||
|
||||
vk::FrontFace FrontFace(Liverpool::FrontFace mode);
|
||||
|
||||
vk::BlendFactor BlendFactor(Liverpool::BlendControl::BlendFactor factor);
|
||||
|
||||
vk::BlendOp BlendOp(Liverpool::BlendControl::BlendFunc func);
|
||||
|
|
|
@ -28,6 +28,15 @@ static constexpr std::array LogicalStageToStageBit = {
|
|||
vk::ShaderStageFlagBits::eCompute,
|
||||
};
|
||||
|
||||
static bool IsPrimitiveTopologyList(const vk::PrimitiveTopology topology) {
|
||||
return topology == vk::PrimitiveTopology::ePointList ||
|
||||
topology == vk::PrimitiveTopology::eLineList ||
|
||||
topology == vk::PrimitiveTopology::eTriangleList ||
|
||||
topology == vk::PrimitiveTopology::eLineListWithAdjacency ||
|
||||
topology == vk::PrimitiveTopology::eTriangleListWithAdjacency ||
|
||||
topology == vk::PrimitiveTopology::ePatchList;
|
||||
}
|
||||
|
||||
GraphicsPipeline::GraphicsPipeline(
|
||||
const Instance& instance, Scheduler& scheduler, DescriptorHeap& desc_heap,
|
||||
const Shader::Profile& profile, const GraphicsPipelineKey& key_,
|
||||
|
@ -75,19 +84,15 @@ GraphicsPipeline::GraphicsPipeline(
|
|||
.pVertexAttributeDescriptions = vertex_attributes.data(),
|
||||
};
|
||||
|
||||
auto prim_restart = key.enable_primitive_restart != 0;
|
||||
if (prim_restart && IsPrimitiveListTopology() && !instance.IsListRestartSupported()) {
|
||||
LOG_DEBUG(Render_Vulkan,
|
||||
"Primitive restart is enabled for list topology but not supported by driver.");
|
||||
prim_restart = false;
|
||||
}
|
||||
const auto topology = LiverpoolToVK::PrimitiveType(key.prim_type);
|
||||
const vk::PipelineInputAssemblyStateCreateInfo input_assembly = {
|
||||
.topology = LiverpoolToVK::PrimitiveType(key.prim_type),
|
||||
.primitiveRestartEnable = prim_restart,
|
||||
.topology = topology,
|
||||
// Avoid warning spam on all pipelines about unsupported restart disable, if not supported.
|
||||
// However, must be false for list topologies to avoid validation errors.
|
||||
.primitiveRestartEnable =
|
||||
!instance.IsPrimitiveRestartDisableSupported() && !IsPrimitiveTopologyList(topology),
|
||||
};
|
||||
ASSERT_MSG(!prim_restart || key.primitive_restart_index == 0xFFFF ||
|
||||
key.primitive_restart_index == 0xFFFFFFFF,
|
||||
"Primitive restart index other than -1 is not supported yet");
|
||||
|
||||
const bool is_rect_list = key.prim_type == AmdGpu::PrimitiveType::RectList;
|
||||
const bool is_quad_list = key.prim_type == AmdGpu::PrimitiveType::QuadList;
|
||||
const auto& fs_info = runtime_infos[u32(Shader::LogicalStage::Fragment)].fs_info;
|
||||
|
@ -99,12 +104,6 @@ GraphicsPipeline::GraphicsPipeline(
|
|||
.depthClampEnable = false,
|
||||
.rasterizerDiscardEnable = false,
|
||||
.polygonMode = LiverpoolToVK::PolygonMode(key.polygon_mode),
|
||||
.cullMode = LiverpoolToVK::IsPrimitiveCulled(key.prim_type)
|
||||
? LiverpoolToVK::CullMode(key.cull_mode)
|
||||
: vk::CullModeFlagBits::eNone,
|
||||
.frontFace = key.front_face == Liverpool::FrontFace::Clockwise
|
||||
? vk::FrontFace::eClockwise
|
||||
: vk::FrontFace::eCounterClockwise,
|
||||
.lineWidth = 1.0f,
|
||||
};
|
||||
|
||||
|
@ -122,16 +121,20 @@ GraphicsPipeline::GraphicsPipeline(
|
|||
.pNext = instance.IsDepthClipControlSupported() ? &clip_control : nullptr,
|
||||
};
|
||||
|
||||
boost::container::static_vector<vk::DynamicState, 17> dynamic_states = {
|
||||
boost::container::static_vector<vk::DynamicState, 20> dynamic_states = {
|
||||
vk::DynamicState::eViewportWithCountEXT, vk::DynamicState::eScissorWithCountEXT,
|
||||
vk::DynamicState::eBlendConstants, vk::DynamicState::eDepthTestEnableEXT,
|
||||
vk::DynamicState::eDepthWriteEnableEXT, vk::DynamicState::eDepthCompareOpEXT,
|
||||
vk::DynamicState::eDepthBiasEnableEXT, vk::DynamicState::eDepthBias,
|
||||
vk::DynamicState::eStencilTestEnableEXT, vk::DynamicState::eStencilReference,
|
||||
vk::DynamicState::eStencilCompareMask, vk::DynamicState::eStencilWriteMask,
|
||||
vk::DynamicState::eStencilOpEXT,
|
||||
vk::DynamicState::eStencilOpEXT, vk::DynamicState::eCullModeEXT,
|
||||
vk::DynamicState::eFrontFaceEXT,
|
||||
};
|
||||
|
||||
if (instance.IsPrimitiveRestartDisableSupported()) {
|
||||
dynamic_states.push_back(vk::DynamicState::ePrimitiveRestartEnableEXT);
|
||||
}
|
||||
if (instance.IsDepthBoundsSupported()) {
|
||||
dynamic_states.push_back(vk::DynamicState::eDepthBoundsTestEnableEXT);
|
||||
dynamic_states.push_back(vk::DynamicState::eDepthBounds);
|
||||
|
|
|
@ -42,11 +42,7 @@ struct GraphicsPipelineKey {
|
|||
u32 num_samples;
|
||||
u32 mrt_mask;
|
||||
AmdGpu::PrimitiveType prim_type;
|
||||
u32 enable_primitive_restart;
|
||||
u32 primitive_restart_index;
|
||||
Liverpool::PolygonMode polygon_mode;
|
||||
Liverpool::CullMode cull_mode;
|
||||
Liverpool::FrontFace front_face;
|
||||
Liverpool::ClipSpace clip_space;
|
||||
Liverpool::ColorBufferMask cb_shader_mask;
|
||||
std::array<Liverpool::BlendControl, Liverpool::NumColorBuffers> blend_controls;
|
||||
|
@ -82,16 +78,6 @@ public:
|
|||
return key.mrt_mask;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsPrimitiveListTopology() const {
|
||||
return key.prim_type == AmdGpu::PrimitiveType::PointList ||
|
||||
key.prim_type == AmdGpu::PrimitiveType::LineList ||
|
||||
key.prim_type == AmdGpu::PrimitiveType::TriangleList ||
|
||||
key.prim_type == AmdGpu::PrimitiveType::AdjLineList ||
|
||||
key.prim_type == AmdGpu::PrimitiveType::AdjTriangleList ||
|
||||
key.prim_type == AmdGpu::PrimitiveType::RectList ||
|
||||
key.prim_type == AmdGpu::PrimitiveType::QuadList;
|
||||
}
|
||||
|
||||
/// Gets the attributes and bindings for vertex inputs.
|
||||
template <typename Attribute, typename Binding>
|
||||
void GetVertexInputs(VertexInputs<Attribute>& attributes, VertexInputs<Binding>& bindings,
|
||||
|
|
|
@ -292,6 +292,11 @@ public:
|
|||
properties.limits.framebufferStencilSampleCounts;
|
||||
}
|
||||
|
||||
/// Returns whether disabling primitive restart is supported.
|
||||
bool IsPrimitiveRestartDisableSupported() const {
|
||||
return driver_id != vk::DriverId::eMoltenvk;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Creates the logical device opportunistically enabling extensions
|
||||
bool CreateDevice();
|
||||
|
|
|
@ -283,12 +283,8 @@ bool PipelineCache::RefreshGraphicsKey() {
|
|||
}
|
||||
|
||||
key.prim_type = regs.primitive_type;
|
||||
key.enable_primitive_restart = regs.enable_primitive_restart & 1;
|
||||
key.primitive_restart_index = regs.primitive_restart_index;
|
||||
key.polygon_mode = regs.polygon_control.PolyMode();
|
||||
key.cull_mode = regs.polygon_control.CullingMode();
|
||||
key.clip_space = regs.clipper_control.clip_space;
|
||||
key.front_face = regs.polygon_control.front_face;
|
||||
key.num_samples = regs.NumSamples();
|
||||
|
||||
const bool skip_cb_binding =
|
||||
|
|
|
@ -930,12 +930,17 @@ bool Rasterizer::IsMapped(VAddr addr, u64 size) {
|
|||
// There is no memory, so not mapped.
|
||||
return false;
|
||||
}
|
||||
return mapped_ranges.find(boost::icl::interval<VAddr>::right_open(addr, addr + size)) !=
|
||||
mapped_ranges.end();
|
||||
const auto range = decltype(mapped_ranges)::interval_type::right_open(addr, addr + size);
|
||||
|
||||
std::shared_lock lock{mapped_ranges_mutex};
|
||||
return boost::icl::contains(mapped_ranges, range);
|
||||
}
|
||||
|
||||
void Rasterizer::MapMemory(VAddr addr, u64 size) {
|
||||
mapped_ranges += boost::icl::interval<VAddr>::right_open(addr, addr + size);
|
||||
{
|
||||
std::unique_lock lock{mapped_ranges_mutex};
|
||||
mapped_ranges += decltype(mapped_ranges)::interval_type::right_open(addr, addr + size);
|
||||
}
|
||||
page_manager.OnGpuMap(addr, size);
|
||||
}
|
||||
|
||||
|
@ -943,22 +948,26 @@ void Rasterizer::UnmapMemory(VAddr addr, u64 size) {
|
|||
buffer_cache.InvalidateMemory(addr, size);
|
||||
texture_cache.UnmapMemory(addr, size);
|
||||
page_manager.OnGpuUnmap(addr, size);
|
||||
mapped_ranges -= boost::icl::interval<VAddr>::right_open(addr, addr + size);
|
||||
}
|
||||
|
||||
void Rasterizer::UpdateDynamicState(const GraphicsPipeline& pipeline) {
|
||||
UpdateViewportScissorState();
|
||||
UpdateDepthStencilState();
|
||||
|
||||
const auto& regs = liverpool->regs;
|
||||
const auto cmdbuf = scheduler.CommandBuffer();
|
||||
cmdbuf.setBlendConstants(®s.blend_constants.red);
|
||||
if (instance.IsDynamicColorWriteMaskSupported()) {
|
||||
cmdbuf.setColorWriteMaskEXT(0, pipeline.GetWriteMasks());
|
||||
{
|
||||
std::unique_lock lock{mapped_ranges_mutex};
|
||||
mapped_ranges -= decltype(mapped_ranges)::interval_type::right_open(addr, addr + size);
|
||||
}
|
||||
}
|
||||
|
||||
void Rasterizer::UpdateViewportScissorState() {
|
||||
void Rasterizer::UpdateDynamicState(const GraphicsPipeline& pipeline) const {
|
||||
UpdateViewportScissorState();
|
||||
UpdateDepthStencilState();
|
||||
UpdatePrimitiveState();
|
||||
|
||||
auto& dynamic_state = scheduler.GetDynamicState();
|
||||
dynamic_state.SetBlendConstants(&liverpool->regs.blend_constants.red);
|
||||
dynamic_state.SetColorWriteMasks(pipeline.GetWriteMasks());
|
||||
|
||||
// Commit new dynamic state to the command buffer.
|
||||
dynamic_state.Commit(instance, scheduler.CommandBuffer());
|
||||
}
|
||||
|
||||
void Rasterizer::UpdateViewportScissorState() const {
|
||||
const auto& regs = liverpool->regs;
|
||||
|
||||
const auto combined_scissor_value_tl = [](s16 scr, s16 win, s16 gen, s16 win_offset) {
|
||||
|
@ -1071,95 +1080,86 @@ void Rasterizer::UpdateViewportScissorState() {
|
|||
scissors.push_back(empty_scissor);
|
||||
}
|
||||
|
||||
const auto cmdbuf = scheduler.CommandBuffer();
|
||||
cmdbuf.setViewportWithCountEXT(viewports);
|
||||
cmdbuf.setScissorWithCountEXT(scissors);
|
||||
auto& dynamic_state = scheduler.GetDynamicState();
|
||||
dynamic_state.SetViewports(viewports);
|
||||
dynamic_state.SetScissors(scissors);
|
||||
}
|
||||
|
||||
void Rasterizer::UpdateDepthStencilState() {
|
||||
auto& regs = liverpool->regs;
|
||||
const auto cmdbuf = scheduler.CommandBuffer();
|
||||
void Rasterizer::UpdateDepthStencilState() const {
|
||||
const auto& regs = liverpool->regs;
|
||||
auto& dynamic_state = scheduler.GetDynamicState();
|
||||
|
||||
bool depth_test = regs.depth_control.depth_enable && regs.depth_buffer.DepthValid();
|
||||
cmdbuf.setDepthTestEnableEXT(depth_test);
|
||||
cmdbuf.setDepthWriteEnableEXT(regs.depth_control.depth_write_enable &&
|
||||
!regs.depth_render_control.depth_clear_enable);
|
||||
if (depth_test) {
|
||||
cmdbuf.setDepthCompareOpEXT(LiverpoolToVK::CompareOp(regs.depth_control.depth_func));
|
||||
const auto depth_test_enabled =
|
||||
regs.depth_control.depth_enable && regs.depth_buffer.DepthValid();
|
||||
dynamic_state.SetDepthTestEnabled(depth_test_enabled);
|
||||
if (depth_test_enabled) {
|
||||
dynamic_state.SetDepthWriteEnabled(regs.depth_control.depth_write_enable &&
|
||||
!regs.depth_render_control.depth_clear_enable);
|
||||
dynamic_state.SetDepthCompareOp(LiverpoolToVK::CompareOp(regs.depth_control.depth_func));
|
||||
}
|
||||
|
||||
if (instance.IsDepthBoundsSupported()) {
|
||||
cmdbuf.setDepthBoundsTestEnableEXT(regs.depth_control.depth_bounds_enable);
|
||||
if (regs.depth_control.depth_bounds_enable) {
|
||||
cmdbuf.setDepthBounds(regs.depth_bounds_min, regs.depth_bounds_max);
|
||||
}
|
||||
const auto depth_bounds_test_enabled = regs.depth_control.depth_bounds_enable;
|
||||
dynamic_state.SetDepthBoundsTestEnabled(depth_bounds_test_enabled);
|
||||
if (depth_bounds_test_enabled) {
|
||||
dynamic_state.SetDepthBounds(regs.depth_bounds_min, regs.depth_bounds_max);
|
||||
}
|
||||
|
||||
cmdbuf.setDepthBiasEnableEXT(regs.polygon_control.NeedsBias());
|
||||
if (regs.polygon_control.enable_polygon_offset_front) {
|
||||
cmdbuf.setDepthBias(regs.poly_offset.front_offset, regs.poly_offset.depth_bias,
|
||||
regs.poly_offset.front_scale / 16.f);
|
||||
} else if (regs.polygon_control.enable_polygon_offset_back) {
|
||||
cmdbuf.setDepthBias(regs.poly_offset.back_offset, regs.poly_offset.depth_bias,
|
||||
regs.poly_offset.back_scale / 16.f);
|
||||
const auto depth_bias_enabled = regs.polygon_control.NeedsBias();
|
||||
dynamic_state.SetDepthBiasEnabled(depth_bias_enabled);
|
||||
if (depth_bias_enabled) {
|
||||
const bool front = regs.polygon_control.enable_polygon_offset_front;
|
||||
dynamic_state.SetDepthBias(
|
||||
front ? regs.poly_offset.front_offset : regs.poly_offset.back_offset,
|
||||
regs.poly_offset.depth_bias,
|
||||
(front ? regs.poly_offset.front_scale : regs.poly_offset.back_scale) / 16.f);
|
||||
}
|
||||
|
||||
cmdbuf.setStencilTestEnableEXT(regs.depth_control.stencil_enable &&
|
||||
regs.depth_buffer.StencilValid());
|
||||
if (regs.depth_control.stencil_enable) {
|
||||
const auto front_fail_op =
|
||||
LiverpoolToVK::StencilOp(regs.stencil_control.stencil_fail_front);
|
||||
const auto front_pass_op =
|
||||
LiverpoolToVK::StencilOp(regs.stencil_control.stencil_zpass_front);
|
||||
const auto front_depth_fail_op =
|
||||
LiverpoolToVK::StencilOp(regs.stencil_control.stencil_zfail_front);
|
||||
const auto front_compare_op = LiverpoolToVK::CompareOp(regs.depth_control.stencil_ref_func);
|
||||
if (regs.depth_control.backface_enable) {
|
||||
const auto back_fail_op =
|
||||
LiverpoolToVK::StencilOp(regs.stencil_control.stencil_fail_back);
|
||||
const auto back_pass_op =
|
||||
LiverpoolToVK::StencilOp(regs.stencil_control.stencil_zpass_back);
|
||||
const auto back_depth_fail_op =
|
||||
LiverpoolToVK::StencilOp(regs.stencil_control.stencil_zfail_back);
|
||||
const auto back_compare_op =
|
||||
LiverpoolToVK::CompareOp(regs.depth_control.stencil_bf_func);
|
||||
cmdbuf.setStencilOpEXT(vk::StencilFaceFlagBits::eFront, front_fail_op, front_pass_op,
|
||||
front_depth_fail_op, front_compare_op);
|
||||
cmdbuf.setStencilOpEXT(vk::StencilFaceFlagBits::eBack, back_fail_op, back_pass_op,
|
||||
back_depth_fail_op, back_compare_op);
|
||||
} else {
|
||||
cmdbuf.setStencilOpEXT(vk::StencilFaceFlagBits::eFrontAndBack, front_fail_op,
|
||||
front_pass_op, front_depth_fail_op, front_compare_op);
|
||||
}
|
||||
const auto stencil_test_enabled =
|
||||
regs.depth_control.stencil_enable && regs.depth_buffer.StencilValid();
|
||||
dynamic_state.SetStencilTestEnabled(stencil_test_enabled);
|
||||
if (stencil_test_enabled) {
|
||||
const StencilOps front_ops{
|
||||
.fail_op = LiverpoolToVK::StencilOp(regs.stencil_control.stencil_fail_front),
|
||||
.pass_op = LiverpoolToVK::StencilOp(regs.stencil_control.stencil_zpass_front),
|
||||
.depth_fail_op = LiverpoolToVK::StencilOp(regs.stencil_control.stencil_zfail_front),
|
||||
.compare_op = LiverpoolToVK::CompareOp(regs.depth_control.stencil_ref_func),
|
||||
};
|
||||
const StencilOps back_ops = regs.depth_control.backface_enable ? StencilOps{
|
||||
.fail_op = LiverpoolToVK::StencilOp(regs.stencil_control.stencil_fail_back),
|
||||
.pass_op = LiverpoolToVK::StencilOp(regs.stencil_control.stencil_zpass_back),
|
||||
.depth_fail_op = LiverpoolToVK::StencilOp(regs.stencil_control.stencil_zfail_back),
|
||||
.compare_op = LiverpoolToVK::CompareOp(regs.depth_control.stencil_bf_func),
|
||||
} : front_ops;
|
||||
dynamic_state.SetStencilOps(front_ops, back_ops);
|
||||
|
||||
const auto front = regs.stencil_ref_front;
|
||||
const auto back = regs.stencil_ref_back;
|
||||
if (front.stencil_test_val == back.stencil_test_val) {
|
||||
cmdbuf.setStencilReference(vk::StencilFaceFlagBits::eFrontAndBack,
|
||||
front.stencil_test_val);
|
||||
} else {
|
||||
cmdbuf.setStencilReference(vk::StencilFaceFlagBits::eFront, front.stencil_test_val);
|
||||
cmdbuf.setStencilReference(vk::StencilFaceFlagBits::eBack, back.stencil_test_val);
|
||||
}
|
||||
|
||||
if (front.stencil_write_mask == back.stencil_write_mask) {
|
||||
cmdbuf.setStencilWriteMask(vk::StencilFaceFlagBits::eFrontAndBack,
|
||||
front.stencil_write_mask);
|
||||
} else {
|
||||
cmdbuf.setStencilWriteMask(vk::StencilFaceFlagBits::eFront, front.stencil_write_mask);
|
||||
cmdbuf.setStencilWriteMask(vk::StencilFaceFlagBits::eBack, back.stencil_write_mask);
|
||||
}
|
||||
|
||||
if (front.stencil_mask == back.stencil_mask) {
|
||||
cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack,
|
||||
front.stencil_mask);
|
||||
} else {
|
||||
cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eFront, front.stencil_mask);
|
||||
cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eBack, back.stencil_mask);
|
||||
}
|
||||
const auto back =
|
||||
regs.depth_control.backface_enable ? regs.stencil_ref_back : regs.stencil_ref_front;
|
||||
dynamic_state.SetStencilReferences(front.stencil_test_val, back.stencil_test_val);
|
||||
dynamic_state.SetStencilWriteMasks(front.stencil_write_mask, back.stencil_write_mask);
|
||||
dynamic_state.SetStencilCompareMasks(front.stencil_mask, back.stencil_mask);
|
||||
}
|
||||
}
|
||||
|
||||
void Rasterizer::UpdatePrimitiveState() const {
|
||||
const auto& regs = liverpool->regs;
|
||||
auto& dynamic_state = scheduler.GetDynamicState();
|
||||
|
||||
const auto prim_restart = (regs.enable_primitive_restart & 1) != 0;
|
||||
ASSERT_MSG(!prim_restart || regs.primitive_restart_index == 0xFFFF ||
|
||||
regs.primitive_restart_index == 0xFFFFFFFF,
|
||||
"Primitive restart index other than -1 is not supported yet");
|
||||
|
||||
const auto cull_mode = LiverpoolToVK::IsPrimitiveCulled(regs.primitive_type)
|
||||
? LiverpoolToVK::CullMode(regs.polygon_control.CullingMode())
|
||||
: vk::CullModeFlagBits::eNone;
|
||||
const auto front_face = LiverpoolToVK::FrontFace(regs.polygon_control.front_face);
|
||||
|
||||
dynamic_state.SetPrimitiveRestartEnabled(prim_restart);
|
||||
dynamic_state.SetCullMode(cull_mode);
|
||||
dynamic_state.SetFrontFace(front_face);
|
||||
}
|
||||
|
||||
void Rasterizer::ScopeMarkerBegin(const std::string_view& str, bool from_guest) {
|
||||
if ((from_guest && !Config::getVkGuestMarkersEnabled()) ||
|
||||
(!from_guest && !Config::getVkHostMarkersEnabled())) {
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <shared_mutex>
|
||||
|
||||
#include "video_core/buffer_cache/buffer_cache.h"
|
||||
#include "video_core/page_manager.h"
|
||||
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
|
||||
|
@ -75,9 +77,10 @@ private:
|
|||
void DepthStencilCopy(bool is_depth, bool is_stencil);
|
||||
void EliminateFastClear();
|
||||
|
||||
void UpdateDynamicState(const GraphicsPipeline& pipeline);
|
||||
void UpdateViewportScissorState();
|
||||
void UpdateDepthStencilState();
|
||||
void UpdateDynamicState(const GraphicsPipeline& pipeline) const;
|
||||
void UpdateViewportScissorState() const;
|
||||
void UpdateDepthStencilState() const;
|
||||
void UpdatePrimitiveState() const;
|
||||
|
||||
bool FilterDraw();
|
||||
|
||||
|
@ -105,6 +108,7 @@ private:
|
|||
AmdGpu::Liverpool* liverpool;
|
||||
Core::MemoryManager* memory;
|
||||
boost::icl::interval_set<VAddr> mapped_ranges;
|
||||
std::shared_mutex mapped_ranges_mutex;
|
||||
PipelineCache pipeline_cache;
|
||||
|
||||
boost::container::static_vector<
|
||||
|
|
|
@ -97,6 +97,9 @@ void Scheduler::AllocateWorkerCommandBuffers() {
|
|||
ASSERT_MSG(begin_result == vk::Result::eSuccess, "Failed to begin command buffer: {}",
|
||||
vk::to_string(begin_result));
|
||||
|
||||
// Invalidate dynamic state so it gets applied to the new command buffer.
|
||||
dynamic_state.Invalidate();
|
||||
|
||||
#if TRACY_GPU_ENABLED
|
||||
auto* profiler_ctx = instance.GetProfilerContext();
|
||||
if (profiler_ctx) {
|
||||
|
@ -164,4 +167,151 @@ void Scheduler::SubmitExecution(SubmitInfo& info) {
|
|||
}
|
||||
}
|
||||
|
||||
void DynamicState::Commit(const Instance& instance, const vk::CommandBuffer& cmdbuf) {
|
||||
if (dirty_state.viewports) {
|
||||
dirty_state.viewports = false;
|
||||
cmdbuf.setViewportWithCountEXT(viewports);
|
||||
}
|
||||
if (dirty_state.scissors) {
|
||||
dirty_state.scissors = false;
|
||||
cmdbuf.setScissorWithCountEXT(scissors);
|
||||
}
|
||||
if (dirty_state.depth_test_enabled) {
|
||||
dirty_state.depth_test_enabled = false;
|
||||
cmdbuf.setDepthTestEnableEXT(depth_test_enabled);
|
||||
}
|
||||
if (dirty_state.depth_write_enabled) {
|
||||
dirty_state.depth_write_enabled = false;
|
||||
// Note that this must be set in a command buffer even if depth test is disabled.
|
||||
cmdbuf.setDepthWriteEnableEXT(depth_write_enabled);
|
||||
}
|
||||
if (depth_test_enabled && dirty_state.depth_compare_op) {
|
||||
dirty_state.depth_compare_op = false;
|
||||
cmdbuf.setDepthCompareOpEXT(depth_compare_op);
|
||||
}
|
||||
if (dirty_state.depth_bounds_test_enabled) {
|
||||
dirty_state.depth_bounds_test_enabled = false;
|
||||
if (instance.IsDepthBoundsSupported()) {
|
||||
cmdbuf.setDepthBoundsTestEnableEXT(depth_bounds_test_enabled);
|
||||
}
|
||||
}
|
||||
if (depth_bounds_test_enabled && dirty_state.depth_bounds) {
|
||||
dirty_state.depth_bounds = false;
|
||||
if (instance.IsDepthBoundsSupported()) {
|
||||
cmdbuf.setDepthBounds(depth_bounds_min, depth_bounds_max);
|
||||
}
|
||||
}
|
||||
if (dirty_state.depth_bias_enabled) {
|
||||
dirty_state.depth_bias_enabled = false;
|
||||
cmdbuf.setDepthBiasEnableEXT(depth_bias_enabled);
|
||||
}
|
||||
if (depth_bias_enabled && dirty_state.depth_bias) {
|
||||
dirty_state.depth_bias = false;
|
||||
cmdbuf.setDepthBias(depth_bias_constant, depth_bias_clamp, depth_bias_slope);
|
||||
}
|
||||
if (dirty_state.stencil_test_enabled) {
|
||||
dirty_state.stencil_test_enabled = false;
|
||||
cmdbuf.setStencilTestEnableEXT(stencil_test_enabled);
|
||||
}
|
||||
if (stencil_test_enabled) {
|
||||
if (dirty_state.stencil_front_ops && dirty_state.stencil_back_ops &&
|
||||
stencil_front_ops == stencil_back_ops) {
|
||||
dirty_state.stencil_front_ops = false;
|
||||
dirty_state.stencil_back_ops = false;
|
||||
cmdbuf.setStencilOpEXT(vk::StencilFaceFlagBits::eFrontAndBack,
|
||||
stencil_front_ops.fail_op, stencil_front_ops.pass_op,
|
||||
stencil_front_ops.depth_fail_op, stencil_front_ops.compare_op);
|
||||
} else {
|
||||
if (dirty_state.stencil_front_ops) {
|
||||
dirty_state.stencil_front_ops = false;
|
||||
cmdbuf.setStencilOpEXT(vk::StencilFaceFlagBits::eFront, stencil_front_ops.fail_op,
|
||||
stencil_front_ops.pass_op, stencil_front_ops.depth_fail_op,
|
||||
stencil_front_ops.compare_op);
|
||||
}
|
||||
if (dirty_state.stencil_back_ops) {
|
||||
dirty_state.stencil_back_ops = false;
|
||||
cmdbuf.setStencilOpEXT(vk::StencilFaceFlagBits::eBack, stencil_back_ops.fail_op,
|
||||
stencil_back_ops.pass_op, stencil_back_ops.depth_fail_op,
|
||||
stencil_back_ops.compare_op);
|
||||
}
|
||||
}
|
||||
if (dirty_state.stencil_front_reference && dirty_state.stencil_back_reference &&
|
||||
stencil_front_reference == stencil_back_reference) {
|
||||
dirty_state.stencil_front_reference = false;
|
||||
dirty_state.stencil_back_reference = false;
|
||||
cmdbuf.setStencilReference(vk::StencilFaceFlagBits::eFrontAndBack,
|
||||
stencil_front_reference);
|
||||
} else {
|
||||
if (dirty_state.stencil_front_reference) {
|
||||
dirty_state.stencil_front_reference = false;
|
||||
cmdbuf.setStencilReference(vk::StencilFaceFlagBits::eFront,
|
||||
stencil_front_reference);
|
||||
}
|
||||
if (dirty_state.stencil_back_reference) {
|
||||
dirty_state.stencil_back_reference = false;
|
||||
cmdbuf.setStencilReference(vk::StencilFaceFlagBits::eBack, stencil_back_reference);
|
||||
}
|
||||
}
|
||||
if (dirty_state.stencil_front_write_mask && dirty_state.stencil_back_write_mask &&
|
||||
stencil_front_write_mask == stencil_back_write_mask) {
|
||||
dirty_state.stencil_front_write_mask = false;
|
||||
dirty_state.stencil_back_write_mask = false;
|
||||
cmdbuf.setStencilWriteMask(vk::StencilFaceFlagBits::eFrontAndBack,
|
||||
stencil_front_write_mask);
|
||||
} else {
|
||||
if (dirty_state.stencil_front_write_mask) {
|
||||
dirty_state.stencil_front_write_mask = false;
|
||||
cmdbuf.setStencilWriteMask(vk::StencilFaceFlagBits::eFront,
|
||||
stencil_front_write_mask);
|
||||
}
|
||||
if (dirty_state.stencil_back_write_mask) {
|
||||
dirty_state.stencil_back_write_mask = false;
|
||||
cmdbuf.setStencilWriteMask(vk::StencilFaceFlagBits::eBack, stencil_back_write_mask);
|
||||
}
|
||||
}
|
||||
if (dirty_state.stencil_front_compare_mask && dirty_state.stencil_back_compare_mask &&
|
||||
stencil_front_compare_mask == stencil_back_compare_mask) {
|
||||
dirty_state.stencil_front_compare_mask = false;
|
||||
dirty_state.stencil_back_compare_mask = false;
|
||||
cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack,
|
||||
stencil_front_compare_mask);
|
||||
} else {
|
||||
if (dirty_state.stencil_front_compare_mask) {
|
||||
dirty_state.stencil_front_compare_mask = false;
|
||||
cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eFront,
|
||||
stencil_front_compare_mask);
|
||||
}
|
||||
if (dirty_state.stencil_back_compare_mask) {
|
||||
dirty_state.stencil_back_compare_mask = false;
|
||||
cmdbuf.setStencilCompareMask(vk::StencilFaceFlagBits::eBack,
|
||||
stencil_back_compare_mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dirty_state.primitive_restart_enable) {
|
||||
dirty_state.primitive_restart_enable = false;
|
||||
if (instance.IsPrimitiveRestartDisableSupported()) {
|
||||
cmdbuf.setPrimitiveRestartEnableEXT(primitive_restart_enable);
|
||||
}
|
||||
}
|
||||
if (dirty_state.cull_mode) {
|
||||
dirty_state.cull_mode = false;
|
||||
cmdbuf.setCullModeEXT(cull_mode);
|
||||
}
|
||||
if (dirty_state.front_face) {
|
||||
dirty_state.front_face = false;
|
||||
cmdbuf.setFrontFaceEXT(front_face);
|
||||
}
|
||||
if (dirty_state.blend_constants) {
|
||||
dirty_state.blend_constants = false;
|
||||
cmdbuf.setBlendConstants(blend_constants);
|
||||
}
|
||||
if (dirty_state.color_write_masks) {
|
||||
dirty_state.color_write_masks = false;
|
||||
if (instance.IsDynamicColorWriteMaskSupported()) {
|
||||
cmdbuf.setColorWriteMaskEXT(0, color_write_masks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <boost/container/static_vector.hpp>
|
||||
#include "common/types.h"
|
||||
#include "common/unique_function.h"
|
||||
#include "video_core/amdgpu/liverpool.h"
|
||||
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
|
||||
#include "video_core/renderer_vulkan/vk_resource_pool.h"
|
||||
|
||||
|
@ -55,6 +56,248 @@ struct SubmitInfo {
|
|||
}
|
||||
};
|
||||
|
||||
using Viewports = boost::container::static_vector<vk::Viewport, AmdGpu::Liverpool::NumViewports>;
|
||||
using Scissors = boost::container::static_vector<vk::Rect2D, AmdGpu::Liverpool::NumViewports>;
|
||||
using ColorWriteMasks = std::array<vk::ColorComponentFlags, AmdGpu::Liverpool::NumColorBuffers>;
|
||||
struct StencilOps {
|
||||
vk::StencilOp fail_op{};
|
||||
vk::StencilOp pass_op{};
|
||||
vk::StencilOp depth_fail_op{};
|
||||
vk::CompareOp compare_op{};
|
||||
|
||||
bool operator==(const StencilOps& other) const {
|
||||
return fail_op == other.fail_op && pass_op == other.pass_op &&
|
||||
depth_fail_op == other.depth_fail_op && compare_op == other.compare_op;
|
||||
}
|
||||
};
|
||||
struct DynamicState {
|
||||
struct {
|
||||
bool viewports : 1;
|
||||
bool scissors : 1;
|
||||
|
||||
bool depth_test_enabled : 1;
|
||||
bool depth_write_enabled : 1;
|
||||
bool depth_compare_op : 1;
|
||||
|
||||
bool depth_bounds_test_enabled : 1;
|
||||
bool depth_bounds : 1;
|
||||
|
||||
bool depth_bias_enabled : 1;
|
||||
bool depth_bias : 1;
|
||||
|
||||
bool stencil_test_enabled : 1;
|
||||
bool stencil_front_ops : 1;
|
||||
bool stencil_front_reference : 1;
|
||||
bool stencil_front_write_mask : 1;
|
||||
bool stencil_front_compare_mask : 1;
|
||||
bool stencil_back_ops : 1;
|
||||
bool stencil_back_reference : 1;
|
||||
bool stencil_back_write_mask : 1;
|
||||
bool stencil_back_compare_mask : 1;
|
||||
|
||||
bool primitive_restart_enable : 1;
|
||||
bool cull_mode : 1;
|
||||
bool front_face : 1;
|
||||
|
||||
bool blend_constants : 1;
|
||||
bool color_write_masks : 1;
|
||||
} dirty_state{};
|
||||
|
||||
Viewports viewports{};
|
||||
Scissors scissors{};
|
||||
|
||||
bool depth_test_enabled{};
|
||||
bool depth_write_enabled{};
|
||||
vk::CompareOp depth_compare_op{};
|
||||
|
||||
bool depth_bounds_test_enabled{};
|
||||
float depth_bounds_min{};
|
||||
float depth_bounds_max{};
|
||||
|
||||
bool depth_bias_enabled{};
|
||||
float depth_bias_constant{};
|
||||
float depth_bias_clamp{};
|
||||
float depth_bias_slope{};
|
||||
|
||||
bool stencil_test_enabled{};
|
||||
StencilOps stencil_front_ops{};
|
||||
u32 stencil_front_reference{};
|
||||
u32 stencil_front_write_mask{};
|
||||
u32 stencil_front_compare_mask{};
|
||||
StencilOps stencil_back_ops{};
|
||||
u32 stencil_back_reference{};
|
||||
u32 stencil_back_write_mask{};
|
||||
u32 stencil_back_compare_mask{};
|
||||
|
||||
bool primitive_restart_enable{};
|
||||
vk::CullModeFlags cull_mode{};
|
||||
vk::FrontFace front_face{};
|
||||
|
||||
float blend_constants[4]{};
|
||||
ColorWriteMasks color_write_masks{};
|
||||
|
||||
/// Commits the dynamic state to the provided command buffer.
|
||||
void Commit(const Instance& instance, const vk::CommandBuffer& cmdbuf);
|
||||
|
||||
/// Invalidates all dynamic state to be flushed into the next command buffer.
|
||||
void Invalidate() {
|
||||
std::memset(&dirty_state, 0xFF, sizeof(dirty_state));
|
||||
}
|
||||
|
||||
void SetViewports(const Viewports& viewports_) {
|
||||
if (!std::ranges::equal(viewports, viewports_)) {
|
||||
viewports = viewports_;
|
||||
dirty_state.viewports = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SetScissors(const Scissors& scissors_) {
|
||||
if (!std::ranges::equal(scissors, scissors_)) {
|
||||
scissors = scissors_;
|
||||
dirty_state.scissors = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SetDepthTestEnabled(const bool enabled) {
|
||||
if (depth_test_enabled != enabled) {
|
||||
depth_test_enabled = enabled;
|
||||
dirty_state.depth_test_enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SetDepthWriteEnabled(const bool enabled) {
|
||||
if (depth_write_enabled != enabled) {
|
||||
depth_write_enabled = enabled;
|
||||
dirty_state.depth_write_enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SetDepthCompareOp(const vk::CompareOp compare_op) {
|
||||
if (depth_compare_op != compare_op) {
|
||||
depth_compare_op = compare_op;
|
||||
dirty_state.depth_compare_op = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SetDepthBoundsTestEnabled(const bool enabled) {
|
||||
if (depth_bounds_test_enabled != enabled) {
|
||||
depth_bounds_test_enabled = enabled;
|
||||
dirty_state.depth_bounds_test_enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SetDepthBounds(const float min, const float max) {
|
||||
if (depth_bounds_min != min || depth_bounds_max != max) {
|
||||
depth_bounds_min = min;
|
||||
depth_bounds_max = max;
|
||||
dirty_state.depth_bounds = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SetDepthBiasEnabled(const bool enabled) {
|
||||
if (depth_bias_enabled != enabled) {
|
||||
depth_bias_enabled = enabled;
|
||||
dirty_state.depth_bias_enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SetDepthBias(const float constant, const float clamp, const float slope) {
|
||||
if (depth_bias_constant != constant || depth_bias_clamp != clamp ||
|
||||
depth_bias_slope != slope) {
|
||||
depth_bias_constant = constant;
|
||||
depth_bias_clamp = clamp;
|
||||
depth_bias_slope = slope;
|
||||
dirty_state.depth_bias = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SetStencilTestEnabled(const bool enabled) {
|
||||
if (stencil_test_enabled != enabled) {
|
||||
stencil_test_enabled = enabled;
|
||||
dirty_state.stencil_test_enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SetStencilOps(const StencilOps& front_ops, const StencilOps& back_ops) {
|
||||
if (stencil_front_ops != front_ops) {
|
||||
stencil_front_ops = front_ops;
|
||||
dirty_state.stencil_front_ops = true;
|
||||
}
|
||||
if (stencil_back_ops != back_ops) {
|
||||
stencil_back_ops = back_ops;
|
||||
dirty_state.stencil_back_ops = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SetStencilReferences(const u32 front_reference, const u32 back_reference) {
|
||||
if (stencil_front_reference != front_reference) {
|
||||
stencil_front_reference = front_reference;
|
||||
dirty_state.stencil_front_reference = true;
|
||||
}
|
||||
if (stencil_back_reference != back_reference) {
|
||||
stencil_back_reference = back_reference;
|
||||
dirty_state.stencil_back_reference = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SetStencilWriteMasks(const u32 front_write_mask, const u32 back_write_mask) {
|
||||
if (stencil_front_write_mask != front_write_mask) {
|
||||
stencil_front_write_mask = front_write_mask;
|
||||
dirty_state.stencil_front_write_mask = true;
|
||||
}
|
||||
if (stencil_back_write_mask != back_write_mask) {
|
||||
stencil_back_write_mask = back_write_mask;
|
||||
dirty_state.stencil_back_write_mask = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SetStencilCompareMasks(const u32 front_compare_mask, const u32 back_compare_mask) {
|
||||
if (stencil_front_compare_mask != front_compare_mask) {
|
||||
stencil_front_compare_mask = front_compare_mask;
|
||||
dirty_state.stencil_front_compare_mask = true;
|
||||
}
|
||||
if (stencil_back_compare_mask != back_compare_mask) {
|
||||
stencil_back_compare_mask = back_compare_mask;
|
||||
dirty_state.stencil_back_compare_mask = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SetPrimitiveRestartEnabled(const bool enabled) {
|
||||
if (primitive_restart_enable != enabled) {
|
||||
primitive_restart_enable = enabled;
|
||||
dirty_state.primitive_restart_enable = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SetCullMode(const vk::CullModeFlags cull_mode_) {
|
||||
if (cull_mode != cull_mode_) {
|
||||
cull_mode = cull_mode_;
|
||||
dirty_state.cull_mode = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SetFrontFace(const vk::FrontFace front_face_) {
|
||||
if (front_face != front_face_) {
|
||||
front_face = front_face_;
|
||||
dirty_state.front_face = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SetBlendConstants(const float blend_constants_[4]) {
|
||||
if (!std::equal(blend_constants, std::end(blend_constants), blend_constants_)) {
|
||||
std::memcpy(blend_constants, blend_constants_, sizeof(blend_constants));
|
||||
dirty_state.blend_constants = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SetColorWriteMasks(const ColorWriteMasks& color_write_masks_) {
|
||||
if (!std::ranges::equal(color_write_masks, color_write_masks_)) {
|
||||
color_write_masks = color_write_masks_;
|
||||
dirty_state.color_write_masks = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Scheduler {
|
||||
public:
|
||||
explicit Scheduler(const Instance& instance);
|
||||
|
@ -81,6 +324,10 @@ public:
|
|||
return render_state;
|
||||
}
|
||||
|
||||
DynamicState& GetDynamicState() {
|
||||
return dynamic_state;
|
||||
}
|
||||
|
||||
/// Returns the current command buffer.
|
||||
vk::CommandBuffer CommandBuffer() const {
|
||||
return current_cmdbuf;
|
||||
|
@ -125,6 +372,7 @@ private:
|
|||
};
|
||||
std::queue<PendingOp> pending_ops;
|
||||
RenderState render_state;
|
||||
DynamicState dynamic_state;
|
||||
bool is_rendering = false;
|
||||
tracy::VkCtxScope* profiler_scope{};
|
||||
};
|
||||
|
|