Merge remote-tracking branch 'origin/main' into kbm-only

This commit is contained in:
kalaposfos13 2025-01-17 16:46:23 +01:00
commit 4ac5d171c9
65 changed files with 2058 additions and 337 deletions

View File

@ -390,7 +390,7 @@ jobs:
- name: Cache CMake Configuration - name: Cache CMake Configuration
uses: actions/cache@v4 uses: actions/cache@v4
env: env:
cache-name: ${{ runner.os }}-sdl-cache-cmake-configuration cache-name: ${{ runner.os }}-sdl-gcc-cache-cmake-configuration
with: with:
path: | path: |
${{github.workspace}}/build ${{github.workspace}}/build
@ -401,7 +401,7 @@ jobs:
- name: Cache CMake Build - name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.14 uses: hendrikmuhs/ccache-action@v1.2.14
env: env:
cache-name: ${{ runner.os }}-sdl-cache-cmake-build cache-name: ${{ runner.os }}-sdl-gcc-cache-cmake-build
with: with:
append-timestamp: false append-timestamp: false
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }} key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
@ -426,7 +426,7 @@ jobs:
- name: Cache CMake Configuration - name: Cache CMake Configuration
uses: actions/cache@v4 uses: actions/cache@v4
env: env:
cache-name: ${{ runner.os }}-qt-cache-cmake-configuration cache-name: ${{ runner.os }}-qt-gcc-cache-cmake-configuration
with: with:
path: | path: |
${{github.workspace}}/build ${{github.workspace}}/build
@ -437,7 +437,7 @@ jobs:
- name: Cache CMake Build - name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.14 uses: hendrikmuhs/ccache-action@v1.2.14
env: env:
cache-name: ${{ runner.os }}-qt-cache-cmake-build cache-name: ${{ runner.os }}-qt-gcc-cache-cmake-build
with: with:
append-timestamp: false append-timestamp: false
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }} key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}

View File

@ -250,6 +250,8 @@ set(KERNEL_LIB src/core/libraries/kernel/sync/mutex.cpp
src/core/libraries/kernel/time.h src/core/libraries/kernel/time.h
src/core/libraries/kernel/orbis_error.h src/core/libraries/kernel/orbis_error.h
src/core/libraries/kernel/posix_error.h src/core/libraries/kernel/posix_error.h
src/core/libraries/kernel/aio.cpp
src/core/libraries/kernel/aio.h
) )
set(NETWORK_LIBS src/core/libraries/network/http.cpp set(NETWORK_LIBS src/core/libraries/network/http.cpp
@ -430,6 +432,8 @@ set(NP_LIBS src/core/libraries/np_common/np_common.cpp
src/core/libraries/np_trophy/trophy_ui.cpp src/core/libraries/np_trophy/trophy_ui.cpp
src/core/libraries/np_trophy/trophy_ui.h src/core/libraries/np_trophy/trophy_ui.h
src/core/libraries/np_trophy/np_trophy_error.h src/core/libraries/np_trophy/np_trophy_error.h
src/core/libraries/np_web_api/np_web_api.cpp
src/core/libraries/np_web_api/np_web_api.h
) )
set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp

View File

@ -61,9 +61,10 @@ static u32 vblankDivider = 1;
static bool vkValidation = false; static bool vkValidation = false;
static bool vkValidationSync = false; static bool vkValidationSync = false;
static bool vkValidationGpu = false; static bool vkValidationGpu = false;
static bool rdocEnable = false;
static bool vkMarkers = false;
static bool vkCrashDiagnostic = false; static bool vkCrashDiagnostic = false;
static bool vkHostMarkers = false;
static bool vkGuestMarkers = false;
static bool rdocEnable = false;
static s16 cursorState = HideCursorState::Idle; static s16 cursorState = HideCursorState::Idle;
static int cursorHideTimeout = 5; // 5 seconds (default) static int cursorHideTimeout = 5; // 5 seconds (default)
static bool separateupdatefolder = false; static bool separateupdatefolder = false;
@ -227,10 +228,6 @@ bool isRdocEnabled() {
return rdocEnable; return rdocEnable;
} }
bool isMarkersEnabled() {
return vkMarkers;
}
u32 vblankDiv() { u32 vblankDiv() {
return vblankDivider; return vblankDivider;
} }
@ -247,14 +244,20 @@ bool vkValidationGpuEnabled() {
return vkValidationGpu; return vkValidationGpu;
} }
bool vkMarkersEnabled() {
return vkMarkers || vkCrashDiagnostic; // Crash diagnostic forces markers on
}
bool vkCrashDiagnosticEnabled() { bool vkCrashDiagnosticEnabled() {
return vkCrashDiagnostic; return vkCrashDiagnostic;
} }
bool vkHostMarkersEnabled() {
// Forced on when crash diagnostic enabled.
return vkHostMarkers || vkCrashDiagnostic;
}
bool vkGuestMarkersEnabled() {
// Forced on when crash diagnostic enabled.
return vkGuestMarkers || vkCrashDiagnostic;
}
bool getSeparateUpdateEnabled() { bool getSeparateUpdateEnabled() {
return separateupdatefolder; return separateupdatefolder;
} }
@ -644,9 +647,10 @@ void load(const std::filesystem::path& path) {
vkValidation = toml::find_or<bool>(vk, "validation", false); vkValidation = toml::find_or<bool>(vk, "validation", false);
vkValidationSync = toml::find_or<bool>(vk, "validation_sync", false); vkValidationSync = toml::find_or<bool>(vk, "validation_sync", false);
vkValidationGpu = toml::find_or<bool>(vk, "validation_gpu", true); vkValidationGpu = toml::find_or<bool>(vk, "validation_gpu", true);
rdocEnable = toml::find_or<bool>(vk, "rdocEnable", false);
vkMarkers = toml::find_or<bool>(vk, "rdocMarkersEnable", false);
vkCrashDiagnostic = toml::find_or<bool>(vk, "crashDiagnostic", false); vkCrashDiagnostic = toml::find_or<bool>(vk, "crashDiagnostic", false);
vkHostMarkers = toml::find_or<bool>(vk, "hostMarkers", false);
vkGuestMarkers = toml::find_or<bool>(vk, "guestMarkers", false);
rdocEnable = toml::find_or<bool>(vk, "rdocEnable", false);
} }
if (data.contains("Debug")) { if (data.contains("Debug")) {
@ -752,9 +756,10 @@ void save(const std::filesystem::path& path) {
data["Vulkan"]["validation"] = vkValidation; data["Vulkan"]["validation"] = vkValidation;
data["Vulkan"]["validation_sync"] = vkValidationSync; data["Vulkan"]["validation_sync"] = vkValidationSync;
data["Vulkan"]["validation_gpu"] = vkValidationGpu; data["Vulkan"]["validation_gpu"] = vkValidationGpu;
data["Vulkan"]["rdocEnable"] = rdocEnable;
data["Vulkan"]["rdocMarkersEnable"] = vkMarkers;
data["Vulkan"]["crashDiagnostic"] = vkCrashDiagnostic; data["Vulkan"]["crashDiagnostic"] = vkCrashDiagnostic;
data["Vulkan"]["hostMarkers"] = vkHostMarkers;
data["Vulkan"]["guestMarkers"] = vkGuestMarkers;
data["Vulkan"]["rdocEnable"] = rdocEnable;
data["Debug"]["DebugDump"] = isDebugDump; data["Debug"]["DebugDump"] = isDebugDump;
data["Debug"]["CollectShader"] = isShaderDebug; data["Debug"]["CollectShader"] = isShaderDebug;
@ -852,9 +857,10 @@ void setDefaultValues() {
vkValidation = false; vkValidation = false;
vkValidationSync = false; vkValidationSync = false;
vkValidationGpu = false; vkValidationGpu = false;
rdocEnable = false;
vkMarkers = false;
vkCrashDiagnostic = false; vkCrashDiagnostic = false;
vkHostMarkers = false;
vkGuestMarkers = false;
rdocEnable = false;
emulator_language = "en"; emulator_language = "en";
m_language = 1; m_language = 1;
gpuId = -1; gpuId = -1;

View File

@ -100,8 +100,9 @@ void setRdocEnabled(bool enable);
bool vkValidationEnabled(); bool vkValidationEnabled();
bool vkValidationSyncEnabled(); bool vkValidationSyncEnabled();
bool vkValidationGpuEnabled(); bool vkValidationGpuEnabled();
bool vkMarkersEnabled();
bool vkCrashDiagnosticEnabled(); bool vkCrashDiagnosticEnabled();
bool vkHostMarkersEnabled();
bool vkGuestMarkersEnabled();
// Gui // Gui
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h); void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h);

View File

@ -104,6 +104,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
SUB(Lib, NpManager) \ SUB(Lib, NpManager) \
SUB(Lib, NpScore) \ SUB(Lib, NpScore) \
SUB(Lib, NpTrophy) \ SUB(Lib, NpTrophy) \
SUB(Lib, NpWebApi) \
SUB(Lib, Screenshot) \ SUB(Lib, Screenshot) \
SUB(Lib, LibCInternal) \ SUB(Lib, LibCInternal) \
SUB(Lib, AppContent) \ SUB(Lib, AppContent) \

View File

@ -71,6 +71,7 @@ enum class Class : u8 {
Lib_NpManager, ///< The LibSceNpManager implementation Lib_NpManager, ///< The LibSceNpManager implementation
Lib_NpScore, ///< The LibSceNpScore implementation Lib_NpScore, ///< The LibSceNpScore implementation
Lib_NpTrophy, ///< The LibSceNpTrophy implementation Lib_NpTrophy, ///< The LibSceNpTrophy implementation
Lib_NpWebApi, ///< The LibSceWebApi implementation
Lib_Screenshot, ///< The LibSceScreenshot implementation Lib_Screenshot, ///< The LibSceScreenshot implementation
Lib_LibCInternal, ///< The LibCInternal implementation. Lib_LibCInternal, ///< The LibCInternal implementation.
Lib_AppContent, ///< The LibSceAppContent implementation. Lib_AppContent, ///< The LibSceAppContent implementation.

View File

@ -37,6 +37,10 @@ public:
void Start(); void Start();
void End(); void End();
std::chrono::nanoseconds GetTotalWait() const {
return total_wait;
}
}; };
} // namespace Common } // namespace Common

View File

@ -131,6 +131,8 @@ class DebugStateImpl {
friend class Core::Devtools::Widget::FrameGraph; friend class Core::Devtools::Widget::FrameGraph;
friend class Core::Devtools::Widget::ShaderList; friend class Core::Devtools::Widget::ShaderList;
bool showing_debug_menu_bar = false;
std::queue<std::string> debug_message_popup; std::queue<std::string> debug_message_popup;
std::mutex guest_threads_mutex{}; std::mutex guest_threads_mutex{};
@ -153,6 +155,9 @@ class DebugStateImpl {
std::vector<ShaderDump> shader_dump_list{}; std::vector<ShaderDump> shader_dump_list{};
public: public:
float Framerate = 1.0f / 60.0f;
float FrameDeltaTime;
void ShowDebugMessage(std::string message) { void ShowDebugMessage(std::string message) {
if (message.empty()) { if (message.empty()) {
return; return;
@ -160,6 +165,10 @@ public:
debug_message_popup.push(std::move(message)); debug_message_popup.push(std::move(message));
} }
bool& IsShowingDebugMenuBar() {
return showing_debug_menu_bar;
}
void AddCurrentThreadToGuestList(); void AddCurrentThreadToGuestList();
void RemoveCurrentThreadFromGuestList(); void RemoveCurrentThreadFromGuestList();

View File

@ -28,7 +28,6 @@ static bool show_simple_fps = false;
static bool visibility_toggled = false; static bool visibility_toggled = false;
static float fps_scale = 1.0f; static float fps_scale = 1.0f;
static bool show_advanced_debug = false;
static int dump_frame_count = 1; static int dump_frame_count = 1;
static Widget::FrameGraph frame_graph; static Widget::FrameGraph frame_graph;
@ -253,8 +252,8 @@ void L::DrawAdvanced() {
} }
void L::DrawSimple() { void L::DrawSimple() {
const auto io = GetIO(); const float frameRate = DebugState.Framerate;
Text("%.1f FPS (%.2f ms)", io.Framerate, 1000.0f / io.Framerate); Text("%d FPS (%.1f ms)", static_cast<int>(std::round(frameRate)), 1000.0f / frameRate);
} }
static void LoadSettings(const char* line) { static void LoadSettings(const char* line) {
@ -265,7 +264,7 @@ static void LoadSettings(const char* line) {
return; return;
} }
if (sscanf(line, "show_advanced_debug=%d", &i) == 1) { if (sscanf(line, "show_advanced_debug=%d", &i) == 1) {
show_advanced_debug = i != 0; DebugState.IsShowingDebugMenuBar() = i != 0;
return; return;
} }
if (sscanf(line, "show_frame_graph=%d", &i) == 1) { if (sscanf(line, "show_frame_graph=%d", &i) == 1) {
@ -310,7 +309,7 @@ void L::SetupSettings() {
handler.WriteAllFn = [](ImGuiContext*, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) { handler.WriteAllFn = [](ImGuiContext*, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) {
buf->appendf("[%s][Data]\n", handler->TypeName); buf->appendf("[%s][Data]\n", handler->TypeName);
buf->appendf("fps_scale=%f\n", fps_scale); buf->appendf("fps_scale=%f\n", fps_scale);
buf->appendf("show_advanced_debug=%d\n", show_advanced_debug); buf->appendf("show_advanced_debug=%d\n", DebugState.IsShowingDebugMenuBar());
buf->appendf("show_frame_graph=%d\n", frame_graph.is_open); buf->appendf("show_frame_graph=%d\n", frame_graph.is_open);
buf->appendf("dump_frame_count=%d\n", dump_frame_count); buf->appendf("dump_frame_count=%d\n", dump_frame_count);
buf->append("\n"); buf->append("\n");
@ -336,12 +335,12 @@ void L::Draw() {
if (!DebugState.IsGuestThreadsPaused()) { if (!DebugState.IsGuestThreadsPaused()) {
const auto fn = DebugState.flip_frame_count.load(); const auto fn = DebugState.flip_frame_count.load();
frame_graph.AddFrame(fn, io.DeltaTime); frame_graph.AddFrame(fn, DebugState.FrameDeltaTime);
} }
if (IsKeyPressed(ImGuiKey_F10, false)) { if (IsKeyPressed(ImGuiKey_F10, false)) {
if (io.KeyCtrl) { if (io.KeyCtrl) {
show_advanced_debug = !show_advanced_debug; DebugState.IsShowingDebugMenuBar() ^= true;
} else { } else {
show_simple_fps = !show_simple_fps; show_simple_fps = !show_simple_fps;
} }
@ -376,7 +375,7 @@ void L::Draw() {
End(); End();
} }
if (show_advanced_debug) { if (DebugState.IsShowingDebugMenuBar()) {
PushFont(io.Fonts->Fonts[IMGUI_FONT_MONO]); PushFont(io.Fonts->Fonts[IMGUI_FONT_MONO]);
PushID("DevtoolsLayer"); PushID("DevtoolsLayer");
DrawAdvanced(); DrawAdvanced();

View File

@ -83,15 +83,13 @@ void FrameGraph::Draw() {
auto isSystemPaused = DebugState.IsGuestThreadsPaused(); auto isSystemPaused = DebugState.IsGuestThreadsPaused();
static float deltaTime;
static float frameRate;
if (!isSystemPaused) { if (!isSystemPaused) {
deltaTime = io.DeltaTime * 1000.0f; deltaTime = DebugState.FrameDeltaTime * 1000.0f;
frameRate = 1000.0f / deltaTime; frameRate = 1000.0f / deltaTime;
} }
Text("Frame time: %.3f ms (%.1f FPS)", deltaTime, frameRate); Text("Frame time: %.3f ms (%.1f FPS)", deltaTime, frameRate);
Text("Presenter time: %.3f ms (%.1f FPS)", io.DeltaTime * 1000.0f, 1.0f / io.DeltaTime);
Text("Flip frame: %d Gnm submit frame: %d", DebugState.flip_frame_count.load(), Text("Flip frame: %d Gnm submit frame: %d", DebugState.flip_frame_count.load(),
DebugState.gnm_frame_count.load()); DebugState.gnm_frame_count.load());

View File

@ -16,6 +16,9 @@ class FrameGraph {
std::array<FrameInfo, FRAME_BUFFER_SIZE> frame_list{}; std::array<FrameInfo, FRAME_BUFFER_SIZE> frame_list{};
float deltaTime{};
float frameRate{};
void DrawFrameGraph(); void DrawFrameGraph();
public: public:

View File

@ -105,7 +105,8 @@ void RegPopup::DrawDepthBuffer(const DepthBuffer& depth_data) {
"DEPTH_SLICE.TILE_MAX", depth_buffer.depth_slice.tile_max, "DEPTH_SLICE.TILE_MAX", depth_buffer.depth_slice.tile_max,
"Pitch()", depth_buffer.Pitch(), "Pitch()", depth_buffer.Pitch(),
"Height()", depth_buffer.Height(), "Height()", depth_buffer.Height(),
"Address()", depth_buffer.Address(), "DepthAddress()", depth_buffer.DepthAddress(),
"StencilAddress()", depth_buffer.StencilAddress(),
"NumSamples()", depth_buffer.NumSamples(), "NumSamples()", depth_buffer.NumSamples(),
"NumBits()", depth_buffer.NumBits(), "NumBits()", depth_buffer.NumBits(),
"GetDepthSliceSize()", depth_buffer.GetDepthSliceSize() "GetDepthSliceSize()", depth_buffer.GetDepthSliceSize()

View File

@ -155,7 +155,7 @@ void RegView::DrawGraphicsRegs() {
TableNextColumn(); TableNextColumn();
TextUnformatted("Depth buffer"); TextUnformatted("Depth buffer");
TableNextColumn(); TableNextColumn();
if (regs.depth_buffer.Address() == 0 || !regs.depth_control.depth_enable) { if (regs.depth_buffer.DepthAddress() == 0 || !regs.depth_control.depth_enable) {
TextUnformatted("N/A"); TextUnformatted("N/A");
} else { } else {
const char* text = last_selected_cb == depth_id && default_reg_popup.open ? "x" : "->"; const char* text = last_selected_cb == depth_id && default_reg_popup.open ? "x" : "->";
@ -241,7 +241,7 @@ void RegView::SetData(DebugStateType::RegDump _data, const std::string& base_tit
default_reg_popup.open = false; default_reg_popup.open = false;
if (last_selected_cb == depth_id) { if (last_selected_cb == depth_id) {
const auto& has_depth = const auto& has_depth =
regs.depth_buffer.Address() != 0 && regs.depth_control.depth_enable; regs.depth_buffer.DepthAddress() != 0 && regs.depth_control.depth_enable;
if (has_depth) { if (has_depth) {
default_reg_popup.SetData(title, regs.depth_buffer, regs.depth_control); default_reg_popup.SetData(title, regs.depth_buffer, regs.depth_control);
default_reg_popup.open = true; default_reg_popup.open = true;

View File

@ -0,0 +1,339 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <thread>
#include "aio.h"
#include "common/assert.h"
#include "common/debug.h"
#include "common/logging/log.h"
#include "core/libraries/kernel/equeue.h"
#include "core/libraries/kernel/orbis_error.h"
#include "core/libraries/libs.h"
#include "file_system.h"
namespace Libraries::Kernel {
#define MAX_QUEUE 512
static s32* id_state;
static s32 id_index;
s32 sceKernelAioInitializeImpl(void* p, s32 size) {
return 0;
}
s32 PS4_SYSV_ABI sceKernelAioDeleteRequest(OrbisKernelAioSubmitId id, s32* ret) {
if (ret == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
id_state[id] = ORBIS_KERNEL_AIO_STATE_ABORTED;
*ret = 0;
return 0;
}
s32 PS4_SYSV_ABI sceKernelAioDeleteRequests(OrbisKernelAioSubmitId id[], s32 num, s32 ret[]) {
if (ret == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
for (s32 i = 0; i < num; i++) {
id_state[id[i]] = ORBIS_KERNEL_AIO_STATE_ABORTED;
ret[i] = 0;
}
return 0;
}
s32 PS4_SYSV_ABI sceKernelAioPollRequest(OrbisKernelAioSubmitId id, s32* state) {
if (state == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
*state = id_state[id];
return 0;
}
s32 PS4_SYSV_ABI sceKernelAioPollRequests(OrbisKernelAioSubmitId id[], s32 num, s32 state[]) {
if (state == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
for (s32 i = 0; i < num; i++) {
state[i] = id_state[id[i]];
}
return 0;
}
s32 PS4_SYSV_ABI sceKernelAioCancelRequest(OrbisKernelAioSubmitId id, s32* state) {
if (state == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
if (id) {
id_state[id] = ORBIS_KERNEL_AIO_STATE_ABORTED;
*state = ORBIS_KERNEL_AIO_STATE_ABORTED;
} else {
*state = ORBIS_KERNEL_AIO_STATE_PROCESSING;
}
return 0;
}
s32 PS4_SYSV_ABI sceKernelAioCancelRequests(OrbisKernelAioSubmitId id[], s32 num, s32 state[]) {
if (state == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
for (s32 i = 0; i < num; i++) {
if (id[i]) {
id_state[id[i]] = ORBIS_KERNEL_AIO_STATE_ABORTED;
state[i] = ORBIS_KERNEL_AIO_STATE_ABORTED;
} else {
state[i] = ORBIS_KERNEL_AIO_STATE_PROCESSING;
}
}
return 0;
}
s32 PS4_SYSV_ABI sceKernelAioWaitRequest(OrbisKernelAioSubmitId id, s32* state, u32* usec) {
if (state == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
u32 timer = 0;
s32 timeout = 0;
while (id_state[id] == ORBIS_KERNEL_AIO_STATE_PROCESSING) {
sceKernelUsleep(10);
timer += 10;
if (*usec) {
if (timer > *usec) {
timeout = 1;
break;
}
}
}
*state = id_state[id];
if (timeout)
return ORBIS_KERNEL_ERROR_ETIMEDOUT;
return 0;
}
s32 PS4_SYSV_ABI sceKernelAioWaitRequests(OrbisKernelAioSubmitId id[], s32 num, s32 state[],
u32 mode, u32* usec) {
if (state == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
u32 timer = 0;
s32 timeout = 0;
s32 completion = 0;
for (s32 i = 0; i < num; i++) {
if (!completion && !timeout) {
while (id_state[id[i]] == ORBIS_KERNEL_AIO_STATE_PROCESSING) {
sceKernelUsleep(10);
timer += 10;
if (*usec) {
if (timer > *usec) {
timeout = 1;
break;
}
}
}
}
if (mode == 0x02) {
if (id_state[id[i]] == ORBIS_KERNEL_AIO_STATE_COMPLETED)
completion = 1;
}
state[i] = id_state[id[i]];
}
if (timeout)
return ORBIS_KERNEL_ERROR_ETIMEDOUT;
return 0;
}
s32 PS4_SYSV_ABI sceKernelAioSubmitReadCommands(OrbisKernelAioRWRequest req[], s32 size, s32 prio,
OrbisKernelAioSubmitId* id) {
if (req == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
if (id == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
id_state[id_index] = ORBIS_KERNEL_AIO_STATE_PROCESSING;
for (s32 i = 0; i < size; i++) {
s64 ret = sceKernelPread(req[i].fd, req[i].buf, req[i].nbyte, req[i].offset);
if (ret < 0) {
req[i].result->state = ORBIS_KERNEL_AIO_STATE_ABORTED;
req[i].result->returnValue = ret;
} else {
req[i].result->state = ORBIS_KERNEL_AIO_STATE_COMPLETED;
req[i].result->returnValue = ret;
}
}
id_state[id_index] = ORBIS_KERNEL_AIO_STATE_COMPLETED;
*id = id_index;
id_index = (id_index + 1) % MAX_QUEUE;
if (!id_index)
id_index++;
return 0;
}
s32 PS4_SYSV_ABI sceKernelAioSubmitReadCommandsMultiple(OrbisKernelAioRWRequest req[], s32 size,
s32 prio, OrbisKernelAioSubmitId id[]) {
if (req == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
if (id == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
for (s32 i = 0; i < size; i++) {
id_state[id_index] = ORBIS_KERNEL_AIO_STATE_PROCESSING;
s64 ret = sceKernelPread(req[i].fd, req[i].buf, req[i].nbyte, req[i].offset);
if (ret < 0) {
req[i].result->state = ORBIS_KERNEL_AIO_STATE_ABORTED;
req[i].result->returnValue = ret;
id_state[id_index] = ORBIS_KERNEL_AIO_STATE_ABORTED;
} else {
req[i].result->state = ORBIS_KERNEL_AIO_STATE_COMPLETED;
req[i].result->returnValue = ret;
id_state[id_index] = ORBIS_KERNEL_AIO_STATE_COMPLETED;
}
id[i] = id_index;
id_index = (id_index + 1) % MAX_QUEUE;
if (!id_index)
id_index++;
}
return 0;
}
s32 PS4_SYSV_ABI sceKernelAioSubmitWriteCommands(OrbisKernelAioRWRequest req[], s32 size, s32 prio,
OrbisKernelAioSubmitId* id) {
if (req == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
if (id == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
for (s32 i = 0; i < size; i++) {
id_state[id_index] = ORBIS_KERNEL_AIO_STATE_PROCESSING;
s64 ret = sceKernelPwrite(req[i].fd, req[i].buf, req[i].nbyte, req[i].offset);
if (ret < 0) {
req[i].result->state = ORBIS_KERNEL_AIO_STATE_ABORTED;
req[i].result->returnValue = ret;
id_state[id_index] = ORBIS_KERNEL_AIO_STATE_ABORTED;
} else {
req[i].result->state = ORBIS_KERNEL_AIO_STATE_COMPLETED;
req[i].result->returnValue = ret;
id_state[id_index] = ORBIS_KERNEL_AIO_STATE_COMPLETED;
}
}
*id = id_index;
id_index = (id_index + 1) % MAX_QUEUE;
// skip id_index equals 0 , because sceKernelAioCancelRequest will submit id
// equal to 0
if (!id_index)
id_index++;
return 0;
}
s32 PS4_SYSV_ABI sceKernelAioSubmitWriteCommandsMultiple(OrbisKernelAioRWRequest req[], s32 size,
s32 prio, OrbisKernelAioSubmitId id[]) {
if (req == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
if (id == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
for (s32 i = 0; i < size; i++) {
id_state[id_index] = ORBIS_KERNEL_AIO_STATE_PROCESSING;
s64 ret = sceKernelPwrite(req[i].fd, req[i].buf, req[i].nbyte, req[i].offset);
if (ret < 0) {
req[i].result->state = ORBIS_KERNEL_AIO_STATE_ABORTED;
req[i].result->returnValue = ret;
id_state[id_index] = ORBIS_KERNEL_AIO_STATE_ABORTED;
} else {
req[i].result->state = ORBIS_KERNEL_AIO_STATE_COMPLETED;
req[i].result->returnValue = ret;
id_state[id_index] = ORBIS_KERNEL_AIO_STATE_COMPLETED;
}
id[i] = id_index;
id_index = (id_index + 1) % MAX_QUEUE;
if (!id_index)
id_index++;
}
return 0;
}
s32 PS4_SYSV_ABI sceKernelAioSetParam() {
LOG_ERROR(Kernel, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceKernelAioInitializeParam() {
LOG_ERROR(Kernel, "(STUBBED) called");
return ORBIS_OK;
}
void RegisterAio(Core::Loader::SymbolsResolver* sym) {
id_index = 1;
id_state = (int*)malloc(sizeof(int) * MAX_QUEUE);
memset(id_state, 0, sizeof(sizeof(int) * MAX_QUEUE));
LIB_FUNCTION("fR521KIGgb8", "libkernel", 1, "libkernel", 1, 1, sceKernelAioCancelRequest);
LIB_FUNCTION("3Lca1XBrQdY", "libkernel", 1, "libkernel", 1, 1, sceKernelAioCancelRequests);
LIB_FUNCTION("5TgME6AYty4", "libkernel", 1, "libkernel", 1, 1, sceKernelAioDeleteRequest);
LIB_FUNCTION("Ft3EtsZzAoY", "libkernel", 1, "libkernel", 1, 1, sceKernelAioDeleteRequests);
LIB_FUNCTION("vYU8P9Td2Zo", "libkernel", 1, "libkernel", 1, 1, sceKernelAioInitializeImpl);
LIB_FUNCTION("nu4a0-arQis", "libkernel", 1, "libkernel", 1, 1, sceKernelAioInitializeParam);
LIB_FUNCTION("2pOuoWoCxdk", "libkernel", 1, "libkernel", 1, 1, sceKernelAioPollRequest);
LIB_FUNCTION("o7O4z3jwKzo", "libkernel", 1, "libkernel", 1, 1, sceKernelAioPollRequests);
LIB_FUNCTION("9WK-vhNXimw", "libkernel", 1, "libkernel", 1, 1, sceKernelAioSetParam);
LIB_FUNCTION("HgX7+AORI58", "libkernel", 1, "libkernel", 1, 1, sceKernelAioSubmitReadCommands);
LIB_FUNCTION("lXT0m3P-vs4", "libkernel", 1, "libkernel", 1, 1,
sceKernelAioSubmitReadCommandsMultiple);
LIB_FUNCTION("XQ8C8y+de+E", "libkernel", 1, "libkernel", 1, 1, sceKernelAioSubmitWriteCommands);
LIB_FUNCTION("xT3Cpz0yh6Y", "libkernel", 1, "libkernel", 1, 1,
sceKernelAioSubmitWriteCommandsMultiple);
LIB_FUNCTION("KOF-oJbQVvc", "libkernel", 1, "libkernel", 1, 1, sceKernelAioWaitRequest);
LIB_FUNCTION("lgK+oIWkJyA", "libkernel", 1, "libkernel", 1, 1, sceKernelAioWaitRequests);
}
} // namespace Libraries::Kernel

View File

@ -0,0 +1,43 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <condition_variable>
#include <mutex>
#include <string>
#include <vector>
#include <boost/asio/steady_timer.hpp>
#include "common/types.h"
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::Kernel {
enum AioState {
ORBIS_KERNEL_AIO_STATE_SUBMITTED = 1,
ORBIS_KERNEL_AIO_STATE_PROCESSING = 2,
ORBIS_KERNEL_AIO_STATE_COMPLETED = 3,
ORBIS_KERNEL_AIO_STATE_ABORTED = 4
};
struct OrbisKernelAioResult {
s64 returnValue;
u32 state;
};
typedef s32 OrbisKernelAioSubmitId;
struct OrbisKernelAioRWRequest {
s64 offset;
s64 nbyte;
void* buf;
OrbisKernelAioResult* result;
s32 fd;
};
void RegisterAio(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Kernel

View File

@ -67,7 +67,8 @@ constexpr int ORBIS_KERNEL_O_DIRECTORY = 0x00020000;
s64 PS4_SYSV_ABI sceKernelWrite(int d, const void* buf, size_t nbytes); s64 PS4_SYSV_ABI sceKernelWrite(int d, const void* buf, size_t nbytes);
s64 PS4_SYSV_ABI sceKernelRead(int d, void* buf, size_t nbytes); s64 PS4_SYSV_ABI sceKernelRead(int d, void* buf, size_t nbytes);
s64 PS4_SYSV_ABI sceKernelPread(int d, void* buf, size_t nbytes, s64 offset);
s64 PS4_SYSV_ABI sceKernelPwrite(int d, void* buf, size_t nbytes, s64 offset);
void RegisterFileSystem(Core::Loader::SymbolsResolver* sym); void RegisterFileSystem(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Kernel } // namespace Libraries::Kernel

View File

@ -28,6 +28,7 @@
#include <Rpc.h> #include <Rpc.h>
#endif #endif
#include <common/singleton.h> #include <common/singleton.h>
#include "aio.h"
namespace Libraries::Kernel { namespace Libraries::Kernel {
@ -218,6 +219,7 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
Libraries::Kernel::RegisterEventQueue(sym); Libraries::Kernel::RegisterEventQueue(sym);
Libraries::Kernel::RegisterProcess(sym); Libraries::Kernel::RegisterProcess(sym);
Libraries::Kernel::RegisterException(sym); Libraries::Kernel::RegisterException(sym);
Libraries::Kernel::RegisterAio(sym);
LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard); LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard);
LIB_FUNCTION("PfccT7qURYE", "libkernel", 1, "libkernel", 1, 1, kernel_ioctl); LIB_FUNCTION("PfccT7qURYE", "libkernel", 1, "libkernel", 1, 1, kernel_ioctl);

View File

@ -339,6 +339,8 @@ int PS4_SYSV_ABI posix_pthread_condattr_setpshared(PthreadCondAttrT* attr, int p
void RegisterCond(Core::Loader::SymbolsResolver* sym) { void RegisterCond(Core::Loader::SymbolsResolver* sym) {
// Posix // Posix
LIB_FUNCTION("mKoTx03HRWA", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_condattr_init); LIB_FUNCTION("mKoTx03HRWA", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_condattr_init);
LIB_FUNCTION("dJcuQVn6-Iw", "libScePosix", 1, "libkernel", 1, 1,
posix_pthread_condattr_destroy);
LIB_FUNCTION("0TyVk4MSLt0", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_init); LIB_FUNCTION("0TyVk4MSLt0", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_init);
LIB_FUNCTION("2MOy+rUfuhQ", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_signal); LIB_FUNCTION("2MOy+rUfuhQ", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_signal);
LIB_FUNCTION("RXXqi4CtF8w", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_destroy); LIB_FUNCTION("RXXqi4CtF8w", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_destroy);
@ -347,8 +349,11 @@ void RegisterCond(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("mkx2fVhNMsg", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_broadcast); LIB_FUNCTION("mkx2fVhNMsg", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_broadcast);
// Posix-Kernel // Posix-Kernel
LIB_FUNCTION("0TyVk4MSLt0", "libkernel", 1, "libkernel", 1, 1, posix_pthread_cond_init);
LIB_FUNCTION("Op8TBGY5KHg", "libkernel", 1, "libkernel", 1, 1, posix_pthread_cond_wait); LIB_FUNCTION("Op8TBGY5KHg", "libkernel", 1, "libkernel", 1, 1, posix_pthread_cond_wait);
LIB_FUNCTION("mkx2fVhNMsg", "libkernel", 1, "libkernel", 1, 1, posix_pthread_cond_broadcast); LIB_FUNCTION("mkx2fVhNMsg", "libkernel", 1, "libkernel", 1, 1, posix_pthread_cond_broadcast);
LIB_FUNCTION("mKoTx03HRWA", "libkernel", 1, "libkernel", 1, 1, posix_pthread_condattr_init);
LIB_FUNCTION("dJcuQVn6-Iw", "libkernel", 1, "libkernel", 1, 1, posix_pthread_condattr_destroy);
// Orbis // Orbis
LIB_FUNCTION("2Tb92quprl0", "libkernel", 1, "libkernel", 1, 1, ORBIS(scePthreadCondInit)); LIB_FUNCTION("2Tb92quprl0", "libkernel", 1, "libkernel", 1, 1, ORBIS(scePthreadCondInit));

View File

@ -153,6 +153,11 @@ int PS4_SYSV_ABI sceKernelDebugRaiseException() {
return 0; return 0;
} }
int PS4_SYSV_ABI sceKernelDebugRaiseExceptionOnReleaseMode() {
UNREACHABLE();
return 0;
}
void RegisterException(Core::Loader::SymbolsResolver* sym) { void RegisterException(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("il03nluKfMk", "libkernel_unity", 1, "libkernel", 1, 1, sceKernelRaiseException); LIB_FUNCTION("il03nluKfMk", "libkernel_unity", 1, "libkernel", 1, 1, sceKernelRaiseException);
LIB_FUNCTION("WkwEd3N7w0Y", "libkernel_unity", 1, "libkernel", 1, 1, LIB_FUNCTION("WkwEd3N7w0Y", "libkernel_unity", 1, "libkernel", 1, 1,
@ -160,6 +165,8 @@ void RegisterException(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("Qhv5ARAoOEc", "libkernel_unity", 1, "libkernel", 1, 1, LIB_FUNCTION("Qhv5ARAoOEc", "libkernel_unity", 1, "libkernel", 1, 1,
sceKernelRemoveExceptionHandler) sceKernelRemoveExceptionHandler)
LIB_FUNCTION("OMDRKKAZ8I4", "libkernel", 1, "libkernel", 1, 1, sceKernelDebugRaiseException); LIB_FUNCTION("OMDRKKAZ8I4", "libkernel", 1, "libkernel", 1, 1, sceKernelDebugRaiseException);
LIB_FUNCTION("zE-wXIZjLoM", "libkernel", 1, "libkernel", 1, 1,
sceKernelDebugRaiseExceptionOnReleaseMode);
} }
} // namespace Libraries::Kernel } // namespace Libraries::Kernel

View File

@ -438,8 +438,11 @@ void RegisterMutex(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("K-jXhbt2gn4", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_mutex_trylock); LIB_FUNCTION("K-jXhbt2gn4", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_mutex_trylock);
// Posix-Kernel // Posix-Kernel
LIB_FUNCTION("ttHNfU+qDBU", "libkernel", 1, "libkernel", 1, 1, posix_pthread_mutex_init);
LIB_FUNCTION("7H0iTOciTLo", "libkernel", 1, "libkernel", 1, 1, posix_pthread_mutex_lock); LIB_FUNCTION("7H0iTOciTLo", "libkernel", 1, "libkernel", 1, 1, posix_pthread_mutex_lock);
LIB_FUNCTION("2Z+PpY6CaJg", "libkernel", 1, "libkernel", 1, 1, posix_pthread_mutex_unlock); LIB_FUNCTION("2Z+PpY6CaJg", "libkernel", 1, "libkernel", 1, 1, posix_pthread_mutex_unlock);
LIB_FUNCTION("dQHWEsJtoE4", "libkernel", 1, "libkernel", 1, 1, posix_pthread_mutexattr_init);
LIB_FUNCTION("mDmgMOGVUqg", "libkernel", 1, "libkernel", 1, 1, posix_pthread_mutexattr_settype);
// Orbis // Orbis
LIB_FUNCTION("cmo1RIYva9o", "libkernel", 1, "libkernel", 1, 1, ORBIS(scePthreadMutexInit)); LIB_FUNCTION("cmo1RIYva9o", "libkernel", 1, "libkernel", 1, 1, ORBIS(scePthreadMutexInit));

View File

@ -538,6 +538,7 @@ void RegisterThread(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("6XG4B33N09g", "libScePosix", 1, "libkernel", 1, 1, sched_yield); LIB_FUNCTION("6XG4B33N09g", "libScePosix", 1, "libkernel", 1, 1, sched_yield);
// Posix-Kernel // Posix-Kernel
LIB_FUNCTION("Z4QosVuAsA0", "libkernel", 1, "libkernel", 1, 1, posix_pthread_once);
LIB_FUNCTION("EotR8a3ASf4", "libkernel", 1, "libkernel", 1, 1, posix_pthread_self); LIB_FUNCTION("EotR8a3ASf4", "libkernel", 1, "libkernel", 1, 1, posix_pthread_self);
LIB_FUNCTION("OxhIB8LB-PQ", "libkernel", 1, "libkernel", 1, 1, posix_pthread_create); LIB_FUNCTION("OxhIB8LB-PQ", "libkernel", 1, "libkernel", 1, 1, posix_pthread_create);

View File

@ -82,6 +82,7 @@ int PS4_SYSV_ABI sceKernelConvertLocaltimeToUtc(time_t param_1, int64_t param_2,
int PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time, OrbisTimesec* st, int PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time, OrbisTimesec* st,
u64* dst_sec); u64* dst_sec);
int PS4_SYSV_ABI sceKernelUsleep(u32 microseconds);
void RegisterTime(Core::Loader::SymbolsResolver* sym); void RegisterTime(Core::Loader::SymbolsResolver* sym);

View File

@ -30,6 +30,7 @@
#include "core/libraries/np_manager/np_manager.h" #include "core/libraries/np_manager/np_manager.h"
#include "core/libraries/np_score/np_score.h" #include "core/libraries/np_score/np_score.h"
#include "core/libraries/np_trophy/np_trophy.h" #include "core/libraries/np_trophy/np_trophy.h"
#include "core/libraries/np_web_api/np_web_api.h"
#include "core/libraries/pad/pad.h" #include "core/libraries/pad/pad.h"
#include "core/libraries/playgo/playgo.h" #include "core/libraries/playgo/playgo.h"
#include "core/libraries/playgo/playgo_dialog.h" #include "core/libraries/playgo/playgo_dialog.h"
@ -81,6 +82,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
Libraries::NpManager::RegisterlibSceNpManager(sym); Libraries::NpManager::RegisterlibSceNpManager(sym);
Libraries::NpScore::RegisterlibSceNpScore(sym); Libraries::NpScore::RegisterlibSceNpScore(sym);
Libraries::NpTrophy::RegisterlibSceNpTrophy(sym); Libraries::NpTrophy::RegisterlibSceNpTrophy(sym);
Libraries::NpWebApi::RegisterlibSceNpWebApi(sym);
Libraries::ScreenShot::RegisterlibSceScreenShot(sym); Libraries::ScreenShot::RegisterlibSceScreenShot(sym);
Libraries::AppContent::RegisterlibSceAppContent(sym); Libraries::AppContent::RegisterlibSceAppContent(sym);
Libraries::PngDec::RegisterlibScePngDec(sym); Libraries::PngDec::RegisterlibScePngDec(sym);

View File

@ -93,7 +93,7 @@ int PS4_SYSV_ABI sceNetCtlUnregisterCallbackV6() {
} }
int PS4_SYSV_ABI sceNetCtlCheckCallback() { int PS4_SYSV_ABI sceNetCtlCheckCallback() {
netctl.CheckCallback(); LOG_DEBUG(Lib_NetCtl, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
@ -373,7 +373,7 @@ int PS4_SYSV_ABI Func_D8DCB6973537A3DC() {
} }
int PS4_SYSV_ABI sceNetCtlCheckCallbackForNpToolkit() { int PS4_SYSV_ABI sceNetCtlCheckCallbackForNpToolkit() {
netctl.CheckNpToolkitCallback(); LOG_DEBUG(Lib_NetCtl, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }

View File

@ -2509,7 +2509,7 @@ struct NpStateCallbackForNpToolkit {
NpStateCallbackForNpToolkit NpStateCbForNp; NpStateCallbackForNpToolkit NpStateCbForNp;
int PS4_SYSV_ABI sceNpCheckCallbackForLib() { int PS4_SYSV_ABI sceNpCheckCallbackForLib() {
Core::ExecuteGuest(NpStateCbForNp.func, 1, OrbisNpState::SignedOut, NpStateCbForNp.userdata); LOG_DEBUG(Lib_NpManager, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }

View File

@ -0,0 +1,692 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
#include "core/libraries/np_web_api/np_web_api.h"
namespace Libraries::NpWebApi {
s32 PS4_SYSV_ABI sceNpWebApiCreateContext() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiCreatePushEventFilter() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiCreateServicePushEventFilter() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiDeletePushEventFilter() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiDeleteServicePushEventFilter() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiRegisterExtdPushEventCallback() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiRegisterNotificationCallback() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiRegisterPushEventCallback() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiRegisterServicePushEventCallback() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiUnregisterNotificationCallback() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiUnregisterPushEventCallback() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiUnregisterServicePushEventCallback() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiAbortHandle() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiAbortRequest() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiAddHttpRequestHeader() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiAddMultipartPart() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiCheckTimeout() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiClearAllUnusedConnection() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiClearUnusedConnection() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiCreateContextA() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiCreateExtdPushEventFilter() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiCreateHandle() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiCreateMultipartRequest() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiCreateRequest() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiDeleteContext() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiDeleteExtdPushEventFilter() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiDeleteHandle() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiDeleteRequest() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiGetConnectionStats() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiGetErrorCode() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiGetHttpResponseHeaderValue() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiGetHttpResponseHeaderValueLength() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiGetHttpStatusCode() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiGetMemoryPoolStats() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiInitialize() {
LOG_ERROR(Lib_NpWebApi, "(DUMMY) called");
static s32 id = 0;
return ++id;
}
s32 PS4_SYSV_ABI sceNpWebApiInitializeForPresence() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiIntCreateCtxIndExtdPushEventFilter() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiIntCreateRequest() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiIntCreateServicePushEventFilter() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiIntInitialize() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiIntRegisterServicePushEventCallback() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiIntRegisterServicePushEventCallbackA() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiReadData() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiRegisterExtdPushEventCallbackA() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiSendMultipartRequest() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiSendMultipartRequest2() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiSendRequest() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiSendRequest2() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiSetHandleTimeout() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiSetMaxConnection() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiSetMultipartContentType() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiSetRequestTimeout() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiTerminate() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiUnregisterExtdPushEventCallback() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiUtilityParseNpId() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpWebApiVshInitialize() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_064C4ED1EDBEB9E8() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_0783955D4E9563DA() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_1A6D77F3FD8323A8() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_1E0693A26FE0F954() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_24A9B5F1D77000CF() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_24AAA6F50E4C2361() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_24D8853D6B47FC79() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_279B3E9C7C4A9DC5() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_28461E29E9F8D697() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_3C29624704FAB9E0() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_3F027804ED2EC11E() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_4066C94E782997CD() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_47C85356815DBE90() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_4FCE8065437E3B87() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_536280BE3DABB521() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_57A0E1BC724219F3() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_5819749C040B6637() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_6198D0C825E86319() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_61F2B9E8AB093743() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_6BC388E6113F0D44() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_7500F0C4F8DC2D16() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_75A03814C7E9039F() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_789D6026C521416E() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_7DED63D06399EFFF() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_7E55A2DCC03D395A() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_7E6C8F9FB86967F4() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_7F04B7D4A7D41E80() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_8E167252DFA5C957() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_95D0046E504E3B09() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_97284BFDA4F18FDF() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_99E32C1F4737EAB4() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_9CFF661EA0BCBF83() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_9EB0E1F467AC3B29() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_A2318FE6FBABFAA3() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_BA07A2E1BF7B3971() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_BD0803EEE0CC29A0() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_BE6F4E5524BB135F() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_C0D490EB481EA4D0() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_C175D392CA6D084A() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_CD0136AF165D2F2F() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_D1C0ADB7B52FEAB5() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_E324765D18EE4D12() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_E789F980D907B653() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_F9A32E8685627436() {
LOG_ERROR(Lib_NpWebApi, "(STUBBED) called");
return ORBIS_OK;
}
void RegisterlibSceNpWebApi(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("x1Y7yiYSk7c", "libSceNpWebApiCompat", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiCreateContext);
LIB_FUNCTION("y5Ta5JCzQHY", "libSceNpWebApiCompat", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiCreatePushEventFilter);
LIB_FUNCTION("sIFx734+xys", "libSceNpWebApiCompat", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiCreateServicePushEventFilter);
LIB_FUNCTION("zE+R6Rcx3W0", "libSceNpWebApiCompat", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiDeletePushEventFilter);
LIB_FUNCTION("PfQ+f6ws764", "libSceNpWebApiCompat", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiDeleteServicePushEventFilter);
LIB_FUNCTION("vrM02A5Gy1M", "libSceNpWebApiCompat", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiRegisterExtdPushEventCallback);
LIB_FUNCTION("HVgWmGIOKdk", "libSceNpWebApiCompat", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiRegisterNotificationCallback);
LIB_FUNCTION("PfSTDCgNMgc", "libSceNpWebApiCompat", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiRegisterPushEventCallback);
LIB_FUNCTION("kJQJE0uKm5w", "libSceNpWebApiCompat", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiRegisterServicePushEventCallback);
LIB_FUNCTION("wjYEvo4xbcA", "libSceNpWebApiCompat", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiUnregisterNotificationCallback);
LIB_FUNCTION("qK4o2656W4w", "libSceNpWebApiCompat", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiUnregisterPushEventCallback);
LIB_FUNCTION("2edrkr0c-wg", "libSceNpWebApiCompat", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiUnregisterServicePushEventCallback);
LIB_FUNCTION("WKcm4PeyJww", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiAbortHandle);
LIB_FUNCTION("JzhYTP2fG18", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiAbortRequest);
LIB_FUNCTION("joRjtRXTFoc", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiAddHttpRequestHeader);
LIB_FUNCTION("19KgfJXgM+U", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiAddMultipartPart);
LIB_FUNCTION("gVNNyxf-1Sg", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiCheckTimeout);
LIB_FUNCTION("KQIkDGf80PQ", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiClearAllUnusedConnection);
LIB_FUNCTION("f-pgaNSd1zc", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiClearUnusedConnection);
LIB_FUNCTION("x1Y7yiYSk7c", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiCreateContext);
LIB_FUNCTION("zk6c65xoyO0", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiCreateContextA);
LIB_FUNCTION("M2BUB+DNEGE", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiCreateExtdPushEventFilter);
LIB_FUNCTION("79M-JqvvGo0", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiCreateHandle);
LIB_FUNCTION("KBxgeNpoRIQ", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiCreateMultipartRequest);
LIB_FUNCTION("y5Ta5JCzQHY", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiCreatePushEventFilter);
LIB_FUNCTION("rdgs5Z1MyFw", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiCreateRequest);
LIB_FUNCTION("sIFx734+xys", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiCreateServicePushEventFilter);
LIB_FUNCTION("XUjdsSTTZ3U", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiDeleteContext);
LIB_FUNCTION("pfaJtb7SQ80", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiDeleteExtdPushEventFilter);
LIB_FUNCTION("5Mn7TYwpl30", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiDeleteHandle);
LIB_FUNCTION("zE+R6Rcx3W0", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiDeletePushEventFilter);
LIB_FUNCTION("noQgleu+KLE", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiDeleteRequest);
LIB_FUNCTION("PfQ+f6ws764", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiDeleteServicePushEventFilter);
LIB_FUNCTION("UJ8H+7kVQUE", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiGetConnectionStats);
LIB_FUNCTION("2qSZ0DgwTsc", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiGetErrorCode);
LIB_FUNCTION("VwJ5L0Higg0", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiGetHttpResponseHeaderValue);
LIB_FUNCTION("743ZzEBzlV8", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiGetHttpResponseHeaderValueLength);
LIB_FUNCTION("k210oKgP80Y", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiGetHttpStatusCode);
LIB_FUNCTION("3OnubUs02UM", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiGetMemoryPoolStats);
LIB_FUNCTION("G3AnLNdRBjE", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, sceNpWebApiInitialize);
LIB_FUNCTION("FkuwsD64zoQ", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiInitializeForPresence);
LIB_FUNCTION("c1pKoztonB8", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiIntCreateCtxIndExtdPushEventFilter);
LIB_FUNCTION("N2Jbx4tIaQ4", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiIntCreateRequest);
LIB_FUNCTION("TZSep4xB4EY", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiIntCreateServicePushEventFilter);
LIB_FUNCTION("8Vjplhyyc44", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiIntInitialize);
LIB_FUNCTION("VjVukb2EWPc", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiIntRegisterServicePushEventCallback);
LIB_FUNCTION("sfq23ZVHVEw", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiIntRegisterServicePushEventCallbackA);
LIB_FUNCTION("CQtPRSF6Ds8", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, sceNpWebApiReadData);
LIB_FUNCTION("vrM02A5Gy1M", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiRegisterExtdPushEventCallback);
LIB_FUNCTION("jhXKGQJ4egI", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiRegisterExtdPushEventCallbackA);
LIB_FUNCTION("HVgWmGIOKdk", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiRegisterNotificationCallback);
LIB_FUNCTION("PfSTDCgNMgc", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiRegisterPushEventCallback);
LIB_FUNCTION("kJQJE0uKm5w", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiRegisterServicePushEventCallback);
LIB_FUNCTION("KCItz6QkeGs", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiSendMultipartRequest);
LIB_FUNCTION("DsPOTEvSe7M", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiSendMultipartRequest2);
LIB_FUNCTION("kVbL4hL3K7w", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiSendRequest);
LIB_FUNCTION("KjNeZ-29ysQ", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiSendRequest2);
LIB_FUNCTION("6g6q-g1i4XU", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiSetHandleTimeout);
LIB_FUNCTION("gRiilVCvfAI", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiSetMaxConnection);
LIB_FUNCTION("i0dr6grIZyc", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiSetMultipartContentType);
LIB_FUNCTION("qWcbJkBj1Lg", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiSetRequestTimeout);
LIB_FUNCTION("asz3TtIqGF8", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, sceNpWebApiTerminate);
LIB_FUNCTION("PqCY25FMzPs", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiUnregisterExtdPushEventCallback);
LIB_FUNCTION("wjYEvo4xbcA", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiUnregisterNotificationCallback);
LIB_FUNCTION("qK4o2656W4w", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiUnregisterPushEventCallback);
LIB_FUNCTION("2edrkr0c-wg", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiUnregisterServicePushEventCallback);
LIB_FUNCTION("or0e885BlXo", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiUtilityParseNpId);
LIB_FUNCTION("uRsskUhAfnM", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1,
sceNpWebApiVshInitialize);
LIB_FUNCTION("BkxO0e2+ueg", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_064C4ED1EDBEB9E8);
LIB_FUNCTION("B4OVXU6VY9o", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_0783955D4E9563DA);
LIB_FUNCTION("Gm138-2DI6g", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_1A6D77F3FD8323A8);
LIB_FUNCTION("HgaTom-g+VQ", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_1E0693A26FE0F954);
LIB_FUNCTION("JKm18ddwAM8", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_24A9B5F1D77000CF);
LIB_FUNCTION("JKqm9Q5MI2E", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_24AAA6F50E4C2361);
LIB_FUNCTION("JNiFPWtH-Hk", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_24D8853D6B47FC79);
LIB_FUNCTION("J5s+nHxKncU", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_279B3E9C7C4A9DC5);
LIB_FUNCTION("KEYeKen41pc", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_28461E29E9F8D697);
LIB_FUNCTION("PCliRwT6ueA", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_3C29624704FAB9E0);
LIB_FUNCTION("PwJ4BO0uwR4", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_3F027804ED2EC11E);
LIB_FUNCTION("QGbJTngpl80", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_4066C94E782997CD);
LIB_FUNCTION("R8hTVoFdvpA", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_47C85356815DBE90);
LIB_FUNCTION("T86AZUN+O4c", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_4FCE8065437E3B87);
LIB_FUNCTION("U2KAvj2rtSE", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_536280BE3DABB521);
LIB_FUNCTION("V6DhvHJCGfM", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_57A0E1BC724219F3);
LIB_FUNCTION("WBl0nAQLZjc", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_5819749C040B6637);
LIB_FUNCTION("YZjQyCXoYxk", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_6198D0C825E86319);
LIB_FUNCTION("YfK56KsJN0M", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_61F2B9E8AB093743);
LIB_FUNCTION("a8OI5hE-DUQ", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_6BC388E6113F0D44);
LIB_FUNCTION("dQDwxPjcLRY", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_7500F0C4F8DC2D16);
LIB_FUNCTION("daA4FMfpA58", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_75A03814C7E9039F);
LIB_FUNCTION("eJ1gJsUhQW4", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_789D6026C521416E);
LIB_FUNCTION("fe1j0GOZ7-8", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_7DED63D06399EFFF);
LIB_FUNCTION("flWi3MA9OVo", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_7E55A2DCC03D395A);
LIB_FUNCTION("fmyPn7hpZ-Q", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_7E6C8F9FB86967F4);
LIB_FUNCTION("fwS31KfUHoA", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_7F04B7D4A7D41E80);
LIB_FUNCTION("jhZyUt+lyVc", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_8E167252DFA5C957);
LIB_FUNCTION("ldAEblBOOwk", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_95D0046E504E3B09);
LIB_FUNCTION("lyhL-aTxj98", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_97284BFDA4F18FDF);
LIB_FUNCTION("meMsH0c36rQ", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_99E32C1F4737EAB4);
LIB_FUNCTION("nP9mHqC8v4M", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_9CFF661EA0BCBF83);
LIB_FUNCTION("nrDh9GesOyk", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_9EB0E1F467AC3B29);
LIB_FUNCTION("ojGP5vur+qM", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_A2318FE6FBABFAA3);
LIB_FUNCTION("ugei4b97OXE", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_BA07A2E1BF7B3971);
LIB_FUNCTION("vQgD7uDMKaA", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_BD0803EEE0CC29A0);
LIB_FUNCTION("vm9OVSS7E18", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_BE6F4E5524BB135F);
LIB_FUNCTION("wNSQ60gepNA", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_C0D490EB481EA4D0);
LIB_FUNCTION("wXXTksptCEo", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_C175D392CA6D084A);
LIB_FUNCTION("zQE2rxZdLy8", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_CD0136AF165D2F2F);
LIB_FUNCTION("0cCtt7Uv6rU", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_D1C0ADB7B52FEAB5);
LIB_FUNCTION("4yR2XRjuTRI", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_E324765D18EE4D12);
LIB_FUNCTION("54n5gNkHtlM", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_E789F980D907B653);
LIB_FUNCTION("+aMuhoVidDY", "libSceNpWebApi", 1, "libSceNpWebApi", 1, 1, Func_F9A32E8685627436);
};
} // namespace Libraries::NpWebApi

View File

@ -0,0 +1,116 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/types.h"
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::NpWebApi {
s32 PS4_SYSV_ABI sceNpWebApiCreateContext();
s32 PS4_SYSV_ABI sceNpWebApiCreatePushEventFilter();
s32 PS4_SYSV_ABI sceNpWebApiCreateServicePushEventFilter();
s32 PS4_SYSV_ABI sceNpWebApiDeletePushEventFilter();
s32 PS4_SYSV_ABI sceNpWebApiDeleteServicePushEventFilter();
s32 PS4_SYSV_ABI sceNpWebApiRegisterExtdPushEventCallback();
s32 PS4_SYSV_ABI sceNpWebApiRegisterNotificationCallback();
s32 PS4_SYSV_ABI sceNpWebApiRegisterPushEventCallback();
s32 PS4_SYSV_ABI sceNpWebApiRegisterServicePushEventCallback();
s32 PS4_SYSV_ABI sceNpWebApiUnregisterNotificationCallback();
s32 PS4_SYSV_ABI sceNpWebApiUnregisterPushEventCallback();
s32 PS4_SYSV_ABI sceNpWebApiUnregisterServicePushEventCallback();
s32 PS4_SYSV_ABI sceNpWebApiAbortHandle();
s32 PS4_SYSV_ABI sceNpWebApiAbortRequest();
s32 PS4_SYSV_ABI sceNpWebApiAddHttpRequestHeader();
s32 PS4_SYSV_ABI sceNpWebApiAddMultipartPart();
s32 PS4_SYSV_ABI sceNpWebApiCheckTimeout();
s32 PS4_SYSV_ABI sceNpWebApiClearAllUnusedConnection();
s32 PS4_SYSV_ABI sceNpWebApiClearUnusedConnection();
s32 PS4_SYSV_ABI sceNpWebApiCreateContextA();
s32 PS4_SYSV_ABI sceNpWebApiCreateExtdPushEventFilter();
s32 PS4_SYSV_ABI sceNpWebApiCreateHandle();
s32 PS4_SYSV_ABI sceNpWebApiCreateMultipartRequest();
s32 PS4_SYSV_ABI sceNpWebApiCreateRequest();
s32 PS4_SYSV_ABI sceNpWebApiDeleteContext();
s32 PS4_SYSV_ABI sceNpWebApiDeleteExtdPushEventFilter();
s32 PS4_SYSV_ABI sceNpWebApiDeleteHandle();
s32 PS4_SYSV_ABI sceNpWebApiDeleteRequest();
s32 PS4_SYSV_ABI sceNpWebApiGetConnectionStats();
s32 PS4_SYSV_ABI sceNpWebApiGetErrorCode();
s32 PS4_SYSV_ABI sceNpWebApiGetHttpResponseHeaderValue();
s32 PS4_SYSV_ABI sceNpWebApiGetHttpResponseHeaderValueLength();
s32 PS4_SYSV_ABI sceNpWebApiGetHttpStatusCode();
s32 PS4_SYSV_ABI sceNpWebApiGetMemoryPoolStats();
s32 PS4_SYSV_ABI sceNpWebApiInitialize();
s32 PS4_SYSV_ABI sceNpWebApiInitializeForPresence();
s32 PS4_SYSV_ABI sceNpWebApiIntCreateCtxIndExtdPushEventFilter();
s32 PS4_SYSV_ABI sceNpWebApiIntCreateRequest();
s32 PS4_SYSV_ABI sceNpWebApiIntCreateServicePushEventFilter();
s32 PS4_SYSV_ABI sceNpWebApiIntInitialize();
s32 PS4_SYSV_ABI sceNpWebApiIntRegisterServicePushEventCallback();
s32 PS4_SYSV_ABI sceNpWebApiIntRegisterServicePushEventCallbackA();
s32 PS4_SYSV_ABI sceNpWebApiReadData();
s32 PS4_SYSV_ABI sceNpWebApiRegisterExtdPushEventCallbackA();
s32 PS4_SYSV_ABI sceNpWebApiSendMultipartRequest();
s32 PS4_SYSV_ABI sceNpWebApiSendMultipartRequest2();
s32 PS4_SYSV_ABI sceNpWebApiSendRequest();
s32 PS4_SYSV_ABI sceNpWebApiSendRequest2();
s32 PS4_SYSV_ABI sceNpWebApiSetHandleTimeout();
s32 PS4_SYSV_ABI sceNpWebApiSetMaxConnection();
s32 PS4_SYSV_ABI sceNpWebApiSetMultipartContentType();
s32 PS4_SYSV_ABI sceNpWebApiSetRequestTimeout();
s32 PS4_SYSV_ABI sceNpWebApiTerminate();
s32 PS4_SYSV_ABI sceNpWebApiUnregisterExtdPushEventCallback();
s32 PS4_SYSV_ABI sceNpWebApiUtilityParseNpId();
s32 PS4_SYSV_ABI sceNpWebApiVshInitialize();
s32 PS4_SYSV_ABI Func_064C4ED1EDBEB9E8();
s32 PS4_SYSV_ABI Func_0783955D4E9563DA();
s32 PS4_SYSV_ABI Func_1A6D77F3FD8323A8();
s32 PS4_SYSV_ABI Func_1E0693A26FE0F954();
s32 PS4_SYSV_ABI Func_24A9B5F1D77000CF();
s32 PS4_SYSV_ABI Func_24AAA6F50E4C2361();
s32 PS4_SYSV_ABI Func_24D8853D6B47FC79();
s32 PS4_SYSV_ABI Func_279B3E9C7C4A9DC5();
s32 PS4_SYSV_ABI Func_28461E29E9F8D697();
s32 PS4_SYSV_ABI Func_3C29624704FAB9E0();
s32 PS4_SYSV_ABI Func_3F027804ED2EC11E();
s32 PS4_SYSV_ABI Func_4066C94E782997CD();
s32 PS4_SYSV_ABI Func_47C85356815DBE90();
s32 PS4_SYSV_ABI Func_4FCE8065437E3B87();
s32 PS4_SYSV_ABI Func_536280BE3DABB521();
s32 PS4_SYSV_ABI Func_57A0E1BC724219F3();
s32 PS4_SYSV_ABI Func_5819749C040B6637();
s32 PS4_SYSV_ABI Func_6198D0C825E86319();
s32 PS4_SYSV_ABI Func_61F2B9E8AB093743();
s32 PS4_SYSV_ABI Func_6BC388E6113F0D44();
s32 PS4_SYSV_ABI Func_7500F0C4F8DC2D16();
s32 PS4_SYSV_ABI Func_75A03814C7E9039F();
s32 PS4_SYSV_ABI Func_789D6026C521416E();
s32 PS4_SYSV_ABI Func_7DED63D06399EFFF();
s32 PS4_SYSV_ABI Func_7E55A2DCC03D395A();
s32 PS4_SYSV_ABI Func_7E6C8F9FB86967F4();
s32 PS4_SYSV_ABI Func_7F04B7D4A7D41E80();
s32 PS4_SYSV_ABI Func_8E167252DFA5C957();
s32 PS4_SYSV_ABI Func_95D0046E504E3B09();
s32 PS4_SYSV_ABI Func_97284BFDA4F18FDF();
s32 PS4_SYSV_ABI Func_99E32C1F4737EAB4();
s32 PS4_SYSV_ABI Func_9CFF661EA0BCBF83();
s32 PS4_SYSV_ABI Func_9EB0E1F467AC3B29();
s32 PS4_SYSV_ABI Func_A2318FE6FBABFAA3();
s32 PS4_SYSV_ABI Func_BA07A2E1BF7B3971();
s32 PS4_SYSV_ABI Func_BD0803EEE0CC29A0();
s32 PS4_SYSV_ABI Func_BE6F4E5524BB135F();
s32 PS4_SYSV_ABI Func_C0D490EB481EA4D0();
s32 PS4_SYSV_ABI Func_C175D392CA6D084A();
s32 PS4_SYSV_ABI Func_CD0136AF165D2F2F();
s32 PS4_SYSV_ABI Func_D1C0ADB7B52FEAB5();
s32 PS4_SYSV_ABI Func_E324765D18EE4D12();
s32 PS4_SYSV_ABI Func_E789F980D907B653();
s32 PS4_SYSV_ABI Func_F9A32E8685627436();
void RegisterlibSceNpWebApi(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::NpWebApi

View File

@ -1,8 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <imgui.h>
#include "common/assert.h" #include "common/assert.h"
#include "common/config.h" #include "common/config.h"
#include "common/debug.h" #include "common/debug.h"
@ -11,6 +9,7 @@
#include "core/libraries/kernel/time.h" #include "core/libraries/kernel/time.h"
#include "core/libraries/videoout/driver.h" #include "core/libraries/videoout/driver.h"
#include "core/libraries/videoout/videoout_error.h" #include "core/libraries/videoout/videoout_error.h"
#include "imgui/renderer/imgui_core.h"
#include "video_core/renderer_vulkan/vk_presenter.h" #include "video_core/renderer_vulkan/vk_presenter.h"
extern std::unique_ptr<Vulkan::Presenter> presenter; extern std::unique_ptr<Vulkan::Presenter> presenter;
@ -207,6 +206,13 @@ void VideoOutDriver::DrawBlankFrame() {
presenter->Present(empty_frame); presenter->Present(empty_frame);
} }
void VideoOutDriver::DrawLastFrame() {
const auto frame = presenter->PrepareLastFrame();
if (frame != nullptr) {
presenter->Present(frame, true);
}
}
bool VideoOutDriver::SubmitFlip(VideoOutPort* port, s32 index, s64 flip_arg, bool VideoOutDriver::SubmitFlip(VideoOutPort* port, s32 index, s64 flip_arg,
bool is_eop /*= false*/) { bool is_eop /*= false*/) {
{ {
@ -278,17 +284,26 @@ void VideoOutDriver::PresentThread(std::stop_token token) {
return {}; return {};
}; };
auto delay = std::chrono::microseconds{0};
while (!token.stop_requested()) { while (!token.stop_requested()) {
timer.Start(); timer.Start();
if (DebugState.IsGuestThreadsPaused()) {
DrawLastFrame();
timer.End();
continue;
}
// Check if it's time to take a request. // Check if it's time to take a request.
auto& vblank_status = main_port.vblank_status; auto& vblank_status = main_port.vblank_status;
if (vblank_status.count % (main_port.flip_rate + 1) == 0) { if (vblank_status.count % (main_port.flip_rate + 1) == 0) {
const auto request = receive_request(); const auto request = receive_request();
if (!request) { if (!request) {
if (!main_port.is_open || DebugState.IsGuestThreadsPaused()) { if (timer.GetTotalWait().count() < 0) { // Dont draw too fast
if (!main_port.is_open) {
DrawBlankFrame(); DrawBlankFrame();
} else if (ImGui::Core::MustKeepDrawing()) {
DrawLastFrame();
}
} }
} else { } else {
Flip(request); Flip(request);

View File

@ -102,7 +102,8 @@ private:
}; };
void Flip(const Request& req); void Flip(const Request& req);
void DrawBlankFrame(); // Used when there is no flip request to keep ImGui up to date void DrawBlankFrame(); // Video port out not open
void DrawLastFrame(); // Used when there is no flip request
void SubmitFlipInternal(VideoOutPort* port, s32 index, s64 flip_arg, bool is_eop = false); void SubmitFlipInternal(VideoOutPort* port, s32 index, s64 flip_arg, bool is_eop = false);
void PresentThread(std::stop_token token); void PresentThread(std::stop_token token);

View File

@ -66,9 +66,10 @@ Emulator::Emulator() {
LOG_INFO(Config, "Vulkan vkValidation: {}", Config::vkValidationEnabled()); LOG_INFO(Config, "Vulkan vkValidation: {}", Config::vkValidationEnabled());
LOG_INFO(Config, "Vulkan vkValidationSync: {}", Config::vkValidationSyncEnabled()); LOG_INFO(Config, "Vulkan vkValidationSync: {}", Config::vkValidationSyncEnabled());
LOG_INFO(Config, "Vulkan vkValidationGpu: {}", Config::vkValidationGpuEnabled()); LOG_INFO(Config, "Vulkan vkValidationGpu: {}", Config::vkValidationGpuEnabled());
LOG_INFO(Config, "Vulkan rdocEnable: {}", Config::isRdocEnabled());
LOG_INFO(Config, "Vulkan rdocMarkersEnable: {}", Config::vkMarkersEnabled());
LOG_INFO(Config, "Vulkan crashDiagnostics: {}", Config::vkCrashDiagnosticEnabled()); LOG_INFO(Config, "Vulkan crashDiagnostics: {}", Config::vkCrashDiagnosticEnabled());
LOG_INFO(Config, "Vulkan hostMarkers: {}", Config::vkHostMarkersEnabled());
LOG_INFO(Config, "Vulkan guestMarkers: {}", Config::vkGuestMarkersEnabled());
LOG_INFO(Config, "Vulkan rdocEnable: {}", Config::isRdocEnabled());
// Create stdin/stdout/stderr // Create stdin/stdout/stderr
Common::Singleton<FileSys::HandleTable>::Instance()->CreateStdHandles(); Common::Singleton<FileSys::HandleTable>::Instance()->CreateStdHandles();

View File

@ -30,6 +30,12 @@ extern void assert_fail_debug_msg(const char* msg);
#define IM_VEC4_CLASS_EXTRA \ #define IM_VEC4_CLASS_EXTRA \
constexpr ImVec4(float _v) : x(_v), y(_v), z(_v), w(_v) {} constexpr ImVec4(float _v) : x(_v), y(_v), z(_v), w(_v) {}
namespace ImGui {
struct Texture;
}
#define ImTextureID ImTextureID
using ImTextureID = ::ImGui::Texture*;
#ifdef IMGUI_USE_WCHAR32 #ifdef IMGUI_USE_WCHAR32
#error "This project uses 16 bits wchar standard like Orbis" #error "This project uses 16 bits wchar standard like Orbis"
#endif #endif

View File

@ -6,6 +6,7 @@
#include "common/config.h" #include "common/config.h"
#include "common/path_util.h" #include "common/path_util.h"
#include "core/debug_state.h"
#include "core/devtools/layer.h" #include "core/devtools/layer.h"
#include "imgui/imgui_layer.h" #include "imgui/imgui_layer.h"
#include "imgui_core.h" #include "imgui_core.h"
@ -167,7 +168,7 @@ bool ProcessEvent(SDL_Event* event) {
} }
} }
void NewFrame() { ImGuiID NewFrame(bool is_reusing_frame) {
{ {
std::scoped_lock lock{change_layers_mutex}; std::scoped_lock lock{change_layers_mutex};
while (!change_layers.empty()) { while (!change_layers.empty()) {
@ -182,24 +183,31 @@ void NewFrame() {
} }
} }
Sdl::NewFrame(); Sdl::NewFrame(is_reusing_frame);
ImGui::NewFrame(); ImGui::NewFrame();
DockSpaceOverViewport(0, GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode); ImGuiWindowFlags flags = ImGuiDockNodeFlags_PassthruCentralNode;
if (!DebugState.IsShowingDebugMenuBar()) {
flags |= ImGuiDockNodeFlags_NoTabBar;
}
ImGuiID dockId = DockSpaceOverViewport(0, GetMainViewport(), flags);
for (auto* layer : layers) { for (auto* layer : layers) {
layer->Draw(); layer->Draw();
} }
return dockId;
} }
void Render(const vk::CommandBuffer& cmdbuf, ::Vulkan::Frame* frame) { void Render(const vk::CommandBuffer& cmdbuf, const vk::ImageView& image_view,
const vk::Extent2D& extent) {
ImGui::Render(); ImGui::Render();
ImDrawData* draw_data = GetDrawData(); ImDrawData* draw_data = GetDrawData();
if (draw_data->CmdListsCount == 0) { if (draw_data->CmdListsCount == 0) {
return; return;
} }
if (Config::vkMarkersEnabled()) { if (Config::vkHostMarkersEnabled()) {
cmdbuf.beginDebugUtilsLabelEXT(vk::DebugUtilsLabelEXT{ cmdbuf.beginDebugUtilsLabelEXT(vk::DebugUtilsLabelEXT{
.pLabelName = "ImGui Render", .pLabelName = "ImGui Render",
}); });
@ -207,16 +215,16 @@ void Render(const vk::CommandBuffer& cmdbuf, ::Vulkan::Frame* frame) {
vk::RenderingAttachmentInfo color_attachments[1]{ vk::RenderingAttachmentInfo color_attachments[1]{
{ {
.imageView = frame->image_view, .imageView = image_view,
.imageLayout = vk::ImageLayout::eColorAttachmentOptimal, .imageLayout = vk::ImageLayout::eColorAttachmentOptimal,
.loadOp = vk::AttachmentLoadOp::eLoad, .loadOp = vk::AttachmentLoadOp::eClear,
.storeOp = vk::AttachmentStoreOp::eStore, .storeOp = vk::AttachmentStoreOp::eStore,
}, },
}; };
vk::RenderingInfo render_info{}; vk::RenderingInfo render_info{};
render_info.renderArea = vk::Rect2D{ render_info.renderArea = vk::Rect2D{
.offset = {0, 0}, .offset = {0, 0},
.extent = {frame->width, frame->height}, .extent = extent,
}; };
render_info.layerCount = 1; render_info.layerCount = 1;
render_info.colorAttachmentCount = 1; render_info.colorAttachmentCount = 1;
@ -224,11 +232,15 @@ void Render(const vk::CommandBuffer& cmdbuf, ::Vulkan::Frame* frame) {
cmdbuf.beginRendering(render_info); cmdbuf.beginRendering(render_info);
Vulkan::RenderDrawData(*draw_data, cmdbuf); Vulkan::RenderDrawData(*draw_data, cmdbuf);
cmdbuf.endRendering(); cmdbuf.endRendering();
if (Config::vkMarkersEnabled()) { if (Config::vkHostMarkersEnabled()) {
cmdbuf.endDebugUtilsLabelEXT(); cmdbuf.endDebugUtilsLabelEXT();
} }
} }
bool MustKeepDrawing() {
return layers.size() > 1 || DebugState.IsShowingDebugMenuBar();
}
} // namespace Core } // namespace Core
void Layer::AddLayer(Layer* layer) { void Layer::AddLayer(Layer* layer) {

View File

@ -3,6 +3,8 @@
#pragma once #pragma once
#include <imgui.h>
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "vulkan/vulkan_handles.hpp" #include "vulkan/vulkan_handles.hpp"
@ -24,8 +26,11 @@ void Shutdown(const vk::Device& device);
bool ProcessEvent(SDL_Event* event); bool ProcessEvent(SDL_Event* event);
void NewFrame(); ImGuiID NewFrame(bool is_reusing_frame = false);
void Render(const vk::CommandBuffer& cmdbuf, Vulkan::Frame* frame); void Render(const vk::CommandBuffer& cmdbuf, const vk::ImageView& image_view,
const vk::Extent2D& extent);
bool MustKeepDrawing(); // Force the emulator redraw
} // namespace ImGui::Core } // namespace ImGui::Core

View File

@ -5,6 +5,7 @@
#include <imgui.h> #include <imgui.h>
#include "common/config.h" #include "common/config.h"
#include "core/debug_state.h"
#include "imgui_impl_sdl3.h" #include "imgui_impl_sdl3.h"
// SDL // SDL
@ -26,6 +27,7 @@ struct SdlData {
SDL_Window* window{}; SDL_Window* window{};
SDL_WindowID window_id{}; SDL_WindowID window_id{};
Uint64 time{}; Uint64 time{};
Uint64 nonReusedtime{};
const char* clipboard_text_data{}; const char* clipboard_text_data{};
// IME handling // IME handling
@ -44,6 +46,11 @@ struct SdlData {
ImVector<SDL_Gamepad*> gamepads{}; ImVector<SDL_Gamepad*> gamepads{};
GamepadMode gamepad_mode{}; GamepadMode gamepad_mode{};
bool want_update_gamepads_list{}; bool want_update_gamepads_list{};
// Framerate counting (based on ImGui impl)
std::array<float, 60> framerateSecPerFrame;
int framerateSecPerFrameIdx{};
float framerateSecPerFrameAcc{};
}; };
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui // Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui
@ -785,7 +792,7 @@ static void UpdateGamepads() {
+thumb_dead_zone, +32767); +thumb_dead_zone, +32767);
} }
void NewFrame() { void NewFrame(bool is_reusing_frame) {
SdlData* bd = GetBackendData(); SdlData* bd = GetBackendData();
IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?"); IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
@ -798,9 +805,29 @@ void NewFrame() {
if (current_time <= bd->time) if (current_time <= bd->time)
current_time = bd->time + 1; current_time = bd->time + 1;
io.DeltaTime = bd->time > 0 ? (float)((double)(current_time - bd->time) / (double)frequency) io.DeltaTime = bd->time > 0 ? (float)((double)(current_time - bd->time) / (double)frequency)
: (float)(1.0f / 60.0f); : 1.0f / 60.0f;
bd->time = current_time; bd->time = current_time;
if (!is_reusing_frame) {
if (current_time <= bd->nonReusedtime)
current_time = bd->nonReusedtime + 1;
float deltaTime =
bd->nonReusedtime > 0
? (float)((double)(current_time - bd->nonReusedtime) / (double)frequency)
: 1.0f / 60.0f;
bd->nonReusedtime = current_time;
DebugState.FrameDeltaTime = deltaTime;
int& frameIdx = bd->framerateSecPerFrameIdx;
float& framerateSec = bd->framerateSecPerFrame[frameIdx];
float& acc = bd->framerateSecPerFrameAcc;
int count = bd->framerateSecPerFrame.size();
acc += deltaTime - framerateSec;
framerateSec = deltaTime;
frameIdx = (frameIdx + 1) % count;
DebugState.Framerate = acc > 0.0f ? 1.0f / (acc / (float)count) : FLT_MAX;
}
if (bd->mouse_pending_leave_frame && bd->mouse_pending_leave_frame >= ImGui::GetFrameCount() && if (bd->mouse_pending_leave_frame && bd->mouse_pending_leave_frame >= ImGui::GetFrameCount() &&
bd->mouse_buttons_down == 0) { bd->mouse_buttons_down == 0) {
bd->mouse_window_id = 0; bd->mouse_window_id = 0;

View File

@ -14,7 +14,7 @@ namespace ImGui::Sdl {
bool Init(SDL_Window* window); bool Init(SDL_Window* window);
void Shutdown(); void Shutdown();
void NewFrame(); void NewFrame(bool is_reusing);
bool ProcessEvent(const SDL_Event* event); bool ProcessEvent(const SDL_Event* event);
void OnResize(); void OnResize();

View File

@ -57,11 +57,12 @@ struct VkData {
vk::DeviceMemory font_memory{}; vk::DeviceMemory font_memory{};
vk::Image font_image{}; vk::Image font_image{};
vk::ImageView font_view{}; vk::ImageView font_view{};
vk::DescriptorSet font_descriptor_set{}; ImTextureID font_texture{};
vk::CommandBuffer font_command_buffer{}; vk::CommandBuffer font_command_buffer{};
// Render buffers // Render buffers
WindowRenderBuffers render_buffers{}; WindowRenderBuffers render_buffers{};
bool enabled_blending{true};
VkData(const InitInfo init_info) : init_info(init_info) { VkData(const InitInfo init_info) : init_info(init_info) {
render_buffers.count = init_info.image_count; render_buffers.count = init_info.image_count;
@ -252,8 +253,8 @@ void UploadTextureData::Destroy() {
const InitInfo& v = bd->init_info; const InitInfo& v = bd->init_info;
CheckVkErr(v.device.waitIdle()); CheckVkErr(v.device.waitIdle());
RemoveTexture(descriptor_set); RemoveTexture(im_texture);
descriptor_set = VK_NULL_HANDLE; im_texture = nullptr;
v.device.destroyImageView(image_view, v.allocator); v.device.destroyImageView(image_view, v.allocator);
image_view = VK_NULL_HANDLE; image_view = VK_NULL_HANDLE;
@ -264,7 +265,7 @@ void UploadTextureData::Destroy() {
} }
// Register a texture // Register a texture
vk::DescriptorSet AddTexture(vk::ImageView image_view, vk::ImageLayout image_layout, ImTextureID AddTexture(vk::ImageView image_view, vk::ImageLayout image_layout,
vk::Sampler sampler) { vk::Sampler sampler) {
VkData* bd = GetBackendData(); VkData* bd = GetBackendData();
const InitInfo& v = bd->init_info; const InitInfo& v = bd->init_info;
@ -303,7 +304,9 @@ vk::DescriptorSet AddTexture(vk::ImageView image_view, vk::ImageLayout image_lay
}; };
v.device.updateDescriptorSets({write_desc}, {}); v.device.updateDescriptorSets({write_desc}, {});
} }
return descriptor_set; return new Texture{
.descriptor_set = descriptor_set,
};
} }
UploadTextureData UploadTexture(const void* data, vk::Format format, u32 width, u32 height, UploadTextureData UploadTexture(const void* data, vk::Format format, u32 width, u32 height,
size_t size) { size_t size) {
@ -370,7 +373,7 @@ UploadTextureData UploadTexture(const void* data, vk::Format format, u32 width,
} }
// Create descriptor set (ImTextureID) // Create descriptor set (ImTextureID)
info.descriptor_set = AddTexture(info.image_view, vk::ImageLayout::eShaderReadOnlyOptimal); info.im_texture = AddTexture(info.image_view, vk::ImageLayout::eShaderReadOnlyOptimal);
// Create Upload Buffer // Create Upload Buffer
{ {
@ -464,10 +467,12 @@ UploadTextureData UploadTexture(const void* data, vk::Format format, u32 width,
return info; return info;
} }
void RemoveTexture(vk::DescriptorSet descriptor_set) { void RemoveTexture(ImTextureID texture) {
IM_ASSERT(texture != nullptr);
VkData* bd = GetBackendData(); VkData* bd = GetBackendData();
const InitInfo& v = bd->init_info; const InitInfo& v = bd->init_info;
v.device.freeDescriptorSets(bd->descriptor_pool, {descriptor_set}); v.device.freeDescriptorSets(bd->descriptor_pool, {texture->descriptor_set});
delete texture;
} }
static void CreateOrResizeBuffer(RenderBuffer& rb, size_t new_size, vk::BufferUsageFlagBits usage) { static void CreateOrResizeBuffer(RenderBuffer& rb, size_t new_size, vk::BufferUsageFlagBits usage) {
@ -679,13 +684,7 @@ void RenderDrawData(ImDrawData& draw_data, vk::CommandBuffer command_buffer,
command_buffer.setScissor(0, 1, &scissor); command_buffer.setScissor(0, 1, &scissor);
// Bind DescriptorSet with font or user texture // Bind DescriptorSet with font or user texture
vk::DescriptorSet desc_set[1]{(VkDescriptorSet)pcmd->TextureId}; vk::DescriptorSet desc_set[1]{pcmd->TextureId->descriptor_set};
if (sizeof(ImTextureID) < sizeof(ImU64)) {
// We don't support texture switches if ImTextureID hasn't been redefined to be
// 64-bit. Do a flaky check that other textures haven't been used.
IM_ASSERT(pcmd->TextureId == (ImTextureID)bd->font_descriptor_set);
desc_set[0] = bd->font_descriptor_set;
}
command_buffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, command_buffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
bd->pipeline_layout, 0, {desc_set}, {}); bd->pipeline_layout, 0, {desc_set}, {});
@ -709,7 +708,7 @@ static bool CreateFontsTexture() {
const InitInfo& v = bd->init_info; const InitInfo& v = bd->init_info;
// Destroy existing texture (if any) // Destroy existing texture (if any)
if (bd->font_view || bd->font_image || bd->font_memory || bd->font_descriptor_set) { if (bd->font_view || bd->font_image || bd->font_memory || bd->font_texture) {
CheckVkErr(v.queue.waitIdle()); CheckVkErr(v.queue.waitIdle());
DestroyFontsTexture(); DestroyFontsTexture();
} }
@ -782,7 +781,7 @@ static bool CreateFontsTexture() {
} }
// Create the Descriptor Set: // Create the Descriptor Set:
bd->font_descriptor_set = AddTexture(bd->font_view, vk::ImageLayout::eShaderReadOnlyOptimal); bd->font_texture = AddTexture(bd->font_view, vk::ImageLayout::eShaderReadOnlyOptimal);
// Create the Upload Buffer: // Create the Upload Buffer:
vk::DeviceMemory upload_buffer_memory{}; vk::DeviceMemory upload_buffer_memory{};
@ -874,7 +873,7 @@ static bool CreateFontsTexture() {
} }
// Store our identifier // Store our identifier
io.Fonts->SetTexID(bd->font_descriptor_set); io.Fonts->SetTexID(bd->font_texture);
// End command buffer // End command buffer
vk::SubmitInfo end_info = {}; vk::SubmitInfo end_info = {};
@ -898,9 +897,9 @@ static void DestroyFontsTexture() {
VkData* bd = GetBackendData(); VkData* bd = GetBackendData();
const InitInfo& v = bd->init_info; const InitInfo& v = bd->init_info;
if (bd->font_descriptor_set) { if (bd->font_texture) {
RemoveTexture(bd->font_descriptor_set); RemoveTexture(bd->font_texture);
bd->font_descriptor_set = VK_NULL_HANDLE; bd->font_texture = nullptr;
io.Fonts->SetTexID(nullptr); io.Fonts->SetTexID(nullptr);
} }

View File

@ -10,6 +10,12 @@
struct ImDrawData; struct ImDrawData;
namespace ImGui {
struct Texture {
vk::DescriptorSet descriptor_set{nullptr};
};
} // namespace ImGui
namespace ImGui::Vulkan { namespace ImGui::Vulkan {
struct InitInfo { struct InitInfo {
@ -34,29 +40,32 @@ struct InitInfo {
struct UploadTextureData { struct UploadTextureData {
vk::Image image; vk::Image image;
vk::ImageView image_view; vk::ImageView image_view;
vk::DescriptorSet descriptor_set;
vk::DeviceMemory image_memory; vk::DeviceMemory image_memory;
vk::CommandBuffer command_buffer; // Submit to the queue vk::CommandBuffer command_buffer; // Submit to the queue
vk::Buffer upload_buffer; vk::Buffer upload_buffer;
vk::DeviceMemory upload_buffer_memory; vk::DeviceMemory upload_buffer_memory;
ImTextureID im_texture;
void Upload(); void Upload();
void Destroy(); void Destroy();
}; };
vk::DescriptorSet AddTexture(vk::ImageView image_view, vk::ImageLayout image_layout, ImTextureID AddTexture(vk::ImageView image_view, vk::ImageLayout image_layout,
vk::Sampler sampler = VK_NULL_HANDLE); vk::Sampler sampler = VK_NULL_HANDLE);
UploadTextureData UploadTexture(const void* data, vk::Format format, u32 width, u32 height, UploadTextureData UploadTexture(const void* data, vk::Format format, u32 width, u32 height,
size_t size); size_t size);
void RemoveTexture(vk::DescriptorSet descriptor_set); void RemoveTexture(ImTextureID descriptor_set);
bool Init(InitInfo info); bool Init(InitInfo info);
void Shutdown(); void Shutdown();
void RenderDrawData(ImDrawData& draw_data, vk::CommandBuffer command_buffer, void RenderDrawData(ImDrawData& draw_data, vk::CommandBuffer command_buffer,
vk::Pipeline pipeline = VK_NULL_HANDLE); vk::Pipeline pipeline = VK_NULL_HANDLE);
void SetBlendEnabled(bool enabled);
} // namespace ImGui::Vulkan } // namespace ImGui::Vulkan

View File

@ -4,6 +4,7 @@
#include <deque> #include <deque>
#include <utility> #include <utility>
#include <imgui.h>
#include "common/assert.h" #include "common/assert.h"
#include "common/config.h" #include "common/config.h"
#include "common/io_file.h" #include "common/io_file.h"
@ -123,7 +124,7 @@ static std::deque<UploadJob> g_upload_list;
namespace Core::TextureManager { namespace Core::TextureManager {
Inner::~Inner() { Inner::~Inner() {
if (upload_data.descriptor_set != nullptr) { if (upload_data.im_texture != nullptr) {
std::unique_lock lk{g_upload_mtx}; std::unique_lock lk{g_upload_mtx};
g_upload_list.emplace_back(UploadJob{ g_upload_list.emplace_back(UploadJob{
.data = this->upload_data, .data = this->upload_data,
@ -239,7 +240,7 @@ void Submit() {
} }
if (upload.core != nullptr) { if (upload.core != nullptr) {
upload.core->upload_data.Upload(); upload.core->upload_data.Upload();
upload.core->texture_id = upload.core->upload_data.descriptor_set; upload.core->texture_id = upload.core->upload_data.im_texture;
if (upload.core->count.fetch_sub(1) == 1) { if (upload.core->count.fetch_sub(1) == 1) {
delete upload.core; delete upload.core;
} }

View File

@ -395,7 +395,7 @@ void EmitContext::DefineInputs() {
DefineVariable(U32[1], spv::BuiltIn::PatchVertices, spv::StorageClass::Input); DefineVariable(U32[1], spv::BuiltIn::PatchVertices, spv::StorageClass::Input);
primitive_id = DefineVariable(U32[1], spv::BuiltIn::PrimitiveId, spv::StorageClass::Input); primitive_id = DefineVariable(U32[1], spv::BuiltIn::PrimitiveId, spv::StorageClass::Input);
const u32 num_attrs = runtime_info.hs_info.ls_stride >> 4; const u32 num_attrs = Common::AlignUp(runtime_info.hs_info.ls_stride, 16) >> 4;
if (num_attrs > 0) { if (num_attrs > 0) {
const Id per_vertex_type{TypeArray(F32[4], ConstU32(num_attrs))}; const Id per_vertex_type{TypeArray(F32[4], ConstU32(num_attrs))};
// The input vertex count isn't statically known, so make length 32 (what glslang does) // The input vertex count isn't statically known, so make length 32 (what glslang does)
@ -409,7 +409,7 @@ void EmitContext::DefineInputs() {
tess_coord = DefineInput(F32[3], std::nullopt, spv::BuiltIn::TessCoord); tess_coord = DefineInput(F32[3], std::nullopt, spv::BuiltIn::TessCoord);
primitive_id = DefineVariable(U32[1], spv::BuiltIn::PrimitiveId, spv::StorageClass::Input); primitive_id = DefineVariable(U32[1], spv::BuiltIn::PrimitiveId, spv::StorageClass::Input);
const u32 num_attrs = runtime_info.vs_info.hs_output_cp_stride >> 4; const u32 num_attrs = Common::AlignUp(runtime_info.vs_info.hs_output_cp_stride, 16) >> 4;
if (num_attrs > 0) { if (num_attrs > 0) {
const Id per_vertex_type{TypeArray(F32[4], ConstU32(num_attrs))}; const Id per_vertex_type{TypeArray(F32[4], ConstU32(num_attrs))};
// The input vertex count isn't statically known, so make length 32 (what glslang does) // The input vertex count isn't statically known, so make length 32 (what glslang does)
@ -418,7 +418,7 @@ void EmitContext::DefineInputs() {
Name(input_attr_array, "in_attrs"); Name(input_attr_array, "in_attrs");
} }
u32 patch_base_location = runtime_info.vs_info.hs_output_cp_stride >> 4; const u32 patch_base_location = num_attrs;
for (size_t index = 0; index < 30; ++index) { for (size_t index = 0; index < 30; ++index) {
if (!(info.uses_patches & (1U << index))) { if (!(info.uses_patches & (1U << index))) {
continue; continue;
@ -453,7 +453,7 @@ void EmitContext::DefineOutputs() {
DefineVariable(type, spv::BuiltIn::CullDistance, spv::StorageClass::Output); DefineVariable(type, spv::BuiltIn::CullDistance, spv::StorageClass::Output);
} }
if (stage == Shader::Stage::Local && runtime_info.ls_info.links_with_tcs) { if (stage == Shader::Stage::Local && runtime_info.ls_info.links_with_tcs) {
const u32 num_attrs = runtime_info.ls_info.ls_stride >> 4; const u32 num_attrs = Common::AlignUp(runtime_info.ls_info.ls_stride, 16) >> 4;
if (num_attrs > 0) { if (num_attrs > 0) {
const Id type{TypeArray(F32[4], ConstU32(num_attrs))}; const Id type{TypeArray(F32[4], ConstU32(num_attrs))};
output_attr_array = DefineOutput(type, 0); output_attr_array = DefineOutput(type, 0);
@ -488,7 +488,7 @@ void EmitContext::DefineOutputs() {
Decorate(output_tess_level_inner, spv::Decoration::Patch); Decorate(output_tess_level_inner, spv::Decoration::Patch);
} }
const u32 num_attrs = runtime_info.hs_info.hs_output_cp_stride >> 4; const u32 num_attrs = Common::AlignUp(runtime_info.hs_info.hs_output_cp_stride, 16) >> 4;
if (num_attrs > 0) { if (num_attrs > 0) {
const Id per_vertex_type{TypeArray(F32[4], ConstU32(num_attrs))}; const Id per_vertex_type{TypeArray(F32[4], ConstU32(num_attrs))};
// The input vertex count isn't statically known, so make length 32 (what glslang does) // The input vertex count isn't statically known, so make length 32 (what glslang does)
@ -498,7 +498,7 @@ void EmitContext::DefineOutputs() {
Name(output_attr_array, "out_attrs"); Name(output_attr_array, "out_attrs");
} }
u32 patch_base_location = runtime_info.hs_info.hs_output_cp_stride >> 4; const u32 patch_base_location = num_attrs;
for (size_t index = 0; index < 30; ++index) { for (size_t index = 0; index < 30; ++index) {
if (!(info.uses_patches & (1U << index))) { if (!(info.uses_patches & (1U << index))) {
continue; continue;

View File

@ -844,7 +844,7 @@ void Translator::V_FREXP_MANT_F64(const GcnInst& inst) {
} }
void Translator::V_FRACT_F64(const GcnInst& inst) { void Translator::V_FRACT_F64(const GcnInst& inst) {
const IR::F32 src0{GetSrc64<IR::F64>(inst.src[0])}; const IR::F64 src0{GetSrc64<IR::F64>(inst.src[0])};
SetDst64(inst.dst[0], ir.FPFract(src0)); SetDst64(inst.dst[0], ir.FPFract(src0));
} }

View File

@ -164,8 +164,8 @@ void Translator::EmitVectorMemory(const GcnInst& inst) {
} }
void Translator::BUFFER_LOAD(u32 num_dwords, bool is_typed, const GcnInst& inst) { void Translator::BUFFER_LOAD(u32 num_dwords, bool is_typed, const GcnInst& inst) {
const auto& mtbuf = inst.control.mtbuf; const auto& mubuf = inst.control.mubuf;
const bool is_ring = mtbuf.glc && mtbuf.slc; const bool is_ring = mubuf.glc && mubuf.slc;
const IR::VectorReg vaddr{inst.src[0].code}; const IR::VectorReg vaddr{inst.src[0].code};
const IR::ScalarReg sharp{inst.src[2].code * 4}; const IR::ScalarReg sharp{inst.src[2].code * 4};
const IR::Value soffset{GetSrc(inst.src[3])}; const IR::Value soffset{GetSrc(inst.src[3])};
@ -178,22 +178,23 @@ void Translator::BUFFER_LOAD(u32 num_dwords, bool is_typed, const GcnInst& inst)
if (is_ring) { if (is_ring) {
return ir.CompositeConstruct(ir.GetVectorReg(vaddr), soffset); return ir.CompositeConstruct(ir.GetVectorReg(vaddr), soffset);
} }
if (mtbuf.idxen && mtbuf.offen) { if (mubuf.idxen && mubuf.offen) {
return ir.CompositeConstruct(ir.GetVectorReg(vaddr), ir.GetVectorReg(vaddr + 1)); return ir.CompositeConstruct(ir.GetVectorReg(vaddr), ir.GetVectorReg(vaddr + 1));
} }
if (mtbuf.idxen || mtbuf.offen) { if (mubuf.idxen || mubuf.offen) {
return ir.GetVectorReg(vaddr); return ir.GetVectorReg(vaddr);
} }
return {}; return {};
}(); }();
IR::BufferInstInfo buffer_info{}; IR::BufferInstInfo buffer_info{};
buffer_info.index_enable.Assign(mtbuf.idxen); buffer_info.index_enable.Assign(mubuf.idxen);
buffer_info.offset_enable.Assign(mtbuf.offen); buffer_info.offset_enable.Assign(mubuf.offen);
buffer_info.inst_offset.Assign(mtbuf.offset); buffer_info.inst_offset.Assign(mubuf.offset);
buffer_info.globally_coherent.Assign(mtbuf.glc); buffer_info.globally_coherent.Assign(mubuf.glc);
buffer_info.system_coherent.Assign(mtbuf.slc); buffer_info.system_coherent.Assign(mubuf.slc);
if (is_typed) { if (is_typed) {
const auto& mtbuf = inst.control.mtbuf;
const auto dmft = static_cast<AmdGpu::DataFormat>(mtbuf.dfmt); const auto dmft = static_cast<AmdGpu::DataFormat>(mtbuf.dfmt);
const auto nfmt = static_cast<AmdGpu::NumberFormat>(mtbuf.nfmt); const auto nfmt = static_cast<AmdGpu::NumberFormat>(mtbuf.nfmt);
ASSERT(nfmt == AmdGpu::NumberFormat::Float && ASSERT(nfmt == AmdGpu::NumberFormat::Float &&
@ -220,9 +221,11 @@ void Translator::BUFFER_LOAD_FORMAT(u32 num_dwords, const GcnInst& inst) {
const auto& mubuf = inst.control.mubuf; const auto& mubuf = inst.control.mubuf;
const IR::VectorReg vaddr{inst.src[0].code}; const IR::VectorReg vaddr{inst.src[0].code};
const IR::ScalarReg sharp{inst.src[2].code * 4}; const IR::ScalarReg sharp{inst.src[2].code * 4};
ASSERT_MSG(!mubuf.offen && mubuf.offset == 0, "Offsets for image buffers are not supported");
const IR::Value address = [&] -> IR::Value { const IR::Value address = [&] -> IR::Value {
if (mubuf.idxen) { if (mubuf.idxen && mubuf.offen) {
return ir.CompositeConstruct(ir.GetVectorReg(vaddr), ir.GetVectorReg(vaddr + 1));
}
if (mubuf.idxen || mubuf.offen) {
return ir.GetVectorReg(vaddr); return ir.GetVectorReg(vaddr);
} }
return {}; return {};
@ -230,13 +233,17 @@ void Translator::BUFFER_LOAD_FORMAT(u32 num_dwords, const GcnInst& inst) {
const IR::Value soffset{GetSrc(inst.src[3])}; const IR::Value soffset{GetSrc(inst.src[3])};
ASSERT_MSG(soffset.IsImmediate() && soffset.U32() == 0, "Non immediate offset not supported"); ASSERT_MSG(soffset.IsImmediate() && soffset.U32() == 0, "Non immediate offset not supported");
IR::BufferInstInfo info{}; IR::BufferInstInfo buffer_info{};
info.index_enable.Assign(mubuf.idxen); buffer_info.index_enable.Assign(mubuf.idxen);
buffer_info.offset_enable.Assign(mubuf.offen);
buffer_info.inst_offset.Assign(mubuf.offset);
buffer_info.globally_coherent.Assign(mubuf.glc);
buffer_info.system_coherent.Assign(mubuf.slc);
const IR::Value handle = const IR::Value handle =
ir.CompositeConstruct(ir.GetScalarReg(sharp), ir.GetScalarReg(sharp + 1), ir.CompositeConstruct(ir.GetScalarReg(sharp), ir.GetScalarReg(sharp + 1),
ir.GetScalarReg(sharp + 2), ir.GetScalarReg(sharp + 3)); ir.GetScalarReg(sharp + 2), ir.GetScalarReg(sharp + 3));
const IR::Value value = ir.LoadBufferFormat(handle, address, info); const IR::Value value = ir.LoadBufferFormat(handle, address, buffer_info);
const IR::VectorReg dst_reg{inst.src[1].code}; const IR::VectorReg dst_reg{inst.src[1].code};
for (u32 i = 0; i < num_dwords; i++) { for (u32 i = 0; i < num_dwords; i++) {
ir.SetVectorReg(dst_reg + i, IR::F32{ir.CompositeExtract(value, i)}); ir.SetVectorReg(dst_reg + i, IR::F32{ir.CompositeExtract(value, i)});
@ -244,8 +251,8 @@ void Translator::BUFFER_LOAD_FORMAT(u32 num_dwords, const GcnInst& inst) {
} }
void Translator::BUFFER_STORE(u32 num_dwords, bool is_typed, const GcnInst& inst) { void Translator::BUFFER_STORE(u32 num_dwords, bool is_typed, const GcnInst& inst) {
const auto& mtbuf = inst.control.mtbuf; const auto& mubuf = inst.control.mubuf;
const bool is_ring = mtbuf.glc && mtbuf.slc; const bool is_ring = mubuf.glc && mubuf.slc;
const IR::VectorReg vaddr{inst.src[0].code}; const IR::VectorReg vaddr{inst.src[0].code};
const IR::ScalarReg sharp{inst.src[2].code * 4}; const IR::ScalarReg sharp{inst.src[2].code * 4};
const IR::Value soffset{GetSrc(inst.src[3])}; const IR::Value soffset{GetSrc(inst.src[3])};
@ -259,22 +266,23 @@ void Translator::BUFFER_STORE(u32 num_dwords, bool is_typed, const GcnInst& inst
if (is_ring) { if (is_ring) {
return ir.CompositeConstruct(ir.GetVectorReg(vaddr), soffset); return ir.CompositeConstruct(ir.GetVectorReg(vaddr), soffset);
} }
if (mtbuf.idxen && mtbuf.offen) { if (mubuf.idxen && mubuf.offen) {
return ir.CompositeConstruct(ir.GetVectorReg(vaddr), ir.GetVectorReg(vaddr + 1)); return ir.CompositeConstruct(ir.GetVectorReg(vaddr), ir.GetVectorReg(vaddr + 1));
} }
if (mtbuf.idxen || mtbuf.offen) { if (mubuf.idxen || mubuf.offen) {
return ir.GetVectorReg(vaddr); return ir.GetVectorReg(vaddr);
} }
return {}; return {};
}(); }();
IR::BufferInstInfo buffer_info{}; IR::BufferInstInfo buffer_info{};
buffer_info.index_enable.Assign(mtbuf.idxen); buffer_info.index_enable.Assign(mubuf.idxen);
buffer_info.offset_enable.Assign(mtbuf.offen); buffer_info.offset_enable.Assign(mubuf.offen);
buffer_info.inst_offset.Assign(mtbuf.offset); buffer_info.inst_offset.Assign(mubuf.offset);
buffer_info.globally_coherent.Assign(mtbuf.glc); buffer_info.globally_coherent.Assign(mubuf.glc);
buffer_info.system_coherent.Assign(mtbuf.slc); buffer_info.system_coherent.Assign(mubuf.slc);
if (is_typed) { if (is_typed) {
const auto& mtbuf = inst.control.mtbuf;
const auto dmft = static_cast<AmdGpu::DataFormat>(mtbuf.dfmt); const auto dmft = static_cast<AmdGpu::DataFormat>(mtbuf.dfmt);
const auto nfmt = static_cast<AmdGpu::NumberFormat>(mtbuf.nfmt); const auto nfmt = static_cast<AmdGpu::NumberFormat>(mtbuf.nfmt);
ASSERT(nfmt == AmdGpu::NumberFormat::Float && ASSERT(nfmt == AmdGpu::NumberFormat::Float &&
@ -321,8 +329,12 @@ void Translator::BUFFER_STORE_FORMAT(u32 num_dwords, const GcnInst& inst) {
const IR::Value soffset{GetSrc(inst.src[3])}; const IR::Value soffset{GetSrc(inst.src[3])};
ASSERT_MSG(soffset.IsImmediate() && soffset.U32() == 0, "Non immediate offset not supported"); ASSERT_MSG(soffset.IsImmediate() && soffset.U32() == 0, "Non immediate offset not supported");
IR::BufferInstInfo info{}; IR::BufferInstInfo buffer_info{};
info.index_enable.Assign(mubuf.idxen); buffer_info.index_enable.Assign(mubuf.idxen);
buffer_info.offset_enable.Assign(mubuf.offen);
buffer_info.inst_offset.Assign(mubuf.offset);
buffer_info.globally_coherent.Assign(mubuf.glc);
buffer_info.system_coherent.Assign(mubuf.slc);
const IR::VectorReg src_reg{inst.src[1].code}; const IR::VectorReg src_reg{inst.src[1].code};
@ -338,7 +350,7 @@ void Translator::BUFFER_STORE_FORMAT(u32 num_dwords, const GcnInst& inst) {
const IR::Value handle = const IR::Value handle =
ir.CompositeConstruct(ir.GetScalarReg(sharp), ir.GetScalarReg(sharp + 1), ir.CompositeConstruct(ir.GetScalarReg(sharp), ir.GetScalarReg(sharp + 1),
ir.GetScalarReg(sharp + 2), ir.GetScalarReg(sharp + 3)); ir.GetScalarReg(sharp + 2), ir.GetScalarReg(sharp + 3));
ir.StoreBufferFormat(handle, address, value, info); ir.StoreBufferFormat(handle, address, value, buffer_info);
} }
void Translator::BUFFER_ATOMIC(AtomicOp op, const GcnInst& inst) { void Translator::BUFFER_ATOMIC(AtomicOp op, const GcnInst& inst) {
@ -358,10 +370,12 @@ void Translator::BUFFER_ATOMIC(AtomicOp op, const GcnInst& inst) {
const IR::U32 soffset{GetSrc(inst.src[3])}; const IR::U32 soffset{GetSrc(inst.src[3])};
ASSERT_MSG(soffset.IsImmediate() && soffset.U32() == 0, "Non immediate offset not supported"); ASSERT_MSG(soffset.IsImmediate() && soffset.U32() == 0, "Non immediate offset not supported");
IR::BufferInstInfo info{}; IR::BufferInstInfo buffer_info{};
info.index_enable.Assign(mubuf.idxen); buffer_info.index_enable.Assign(mubuf.idxen);
info.inst_offset.Assign(mubuf.offset); buffer_info.offset_enable.Assign(mubuf.offen);
info.offset_enable.Assign(mubuf.offen); buffer_info.inst_offset.Assign(mubuf.offset);
buffer_info.globally_coherent.Assign(mubuf.glc);
buffer_info.system_coherent.Assign(mubuf.slc);
IR::Value vdata_val = ir.GetVectorReg<Shader::IR::U32>(vdata); IR::Value vdata_val = ir.GetVectorReg<Shader::IR::U32>(vdata);
const IR::Value handle = const IR::Value handle =
@ -371,27 +385,27 @@ void Translator::BUFFER_ATOMIC(AtomicOp op, const GcnInst& inst) {
const IR::Value original_val = [&] { const IR::Value original_val = [&] {
switch (op) { switch (op) {
case AtomicOp::Swap: case AtomicOp::Swap:
return ir.BufferAtomicSwap(handle, address, vdata_val, info); return ir.BufferAtomicSwap(handle, address, vdata_val, buffer_info);
case AtomicOp::Add: case AtomicOp::Add:
return ir.BufferAtomicIAdd(handle, address, vdata_val, info); return ir.BufferAtomicIAdd(handle, address, vdata_val, buffer_info);
case AtomicOp::Smin: case AtomicOp::Smin:
return ir.BufferAtomicIMin(handle, address, vdata_val, true, info); return ir.BufferAtomicIMin(handle, address, vdata_val, true, buffer_info);
case AtomicOp::Umin: case AtomicOp::Umin:
return ir.BufferAtomicIMin(handle, address, vdata_val, false, info); return ir.BufferAtomicIMin(handle, address, vdata_val, false, buffer_info);
case AtomicOp::Smax: case AtomicOp::Smax:
return ir.BufferAtomicIMax(handle, address, vdata_val, true, info); return ir.BufferAtomicIMax(handle, address, vdata_val, true, buffer_info);
case AtomicOp::Umax: case AtomicOp::Umax:
return ir.BufferAtomicIMax(handle, address, vdata_val, false, info); return ir.BufferAtomicIMax(handle, address, vdata_val, false, buffer_info);
case AtomicOp::And: case AtomicOp::And:
return ir.BufferAtomicAnd(handle, address, vdata_val, info); return ir.BufferAtomicAnd(handle, address, vdata_val, buffer_info);
case AtomicOp::Or: case AtomicOp::Or:
return ir.BufferAtomicOr(handle, address, vdata_val, info); return ir.BufferAtomicOr(handle, address, vdata_val, buffer_info);
case AtomicOp::Xor: case AtomicOp::Xor:
return ir.BufferAtomicXor(handle, address, vdata_val, info); return ir.BufferAtomicXor(handle, address, vdata_val, buffer_info);
case AtomicOp::Inc: case AtomicOp::Inc:
return ir.BufferAtomicInc(handle, address, vdata_val, info); return ir.BufferAtomicInc(handle, address, vdata_val, buffer_info);
case AtomicOp::Dec: case AtomicOp::Dec:
return ir.BufferAtomicDec(handle, address, vdata_val, info); return ir.BufferAtomicDec(handle, address, vdata_val, buffer_info);
default: default:
UNREACHABLE(); UNREACHABLE();
} }

View File

@ -222,10 +222,16 @@ void FoldMul(IR::Block& block, IR::Inst& inst) {
return; return;
} }
const IR::Value rhs{inst.Arg(1)}; const IR::Value rhs{inst.Arg(1)};
if (rhs.IsImmediate() && Arg<T>(rhs) == 0) { if (rhs.IsImmediate()) {
if (Arg<T>(rhs) == 0) {
inst.ReplaceUsesWithAndRemove(IR::Value(0u)); inst.ReplaceUsesWithAndRemove(IR::Value(0u));
return; return;
} }
if (Arg<T>(rhs) == 1) {
inst.ReplaceUsesWithAndRemove(inst.Arg(0));
return;
}
}
} }
void FoldCmpClass(IR::Block& block, IR::Inst& inst) { void FoldCmpClass(IR::Block& block, IR::Inst& inst) {

View File

@ -349,11 +349,11 @@ static IR::F32 ReadTessControlPointAttribute(IR::U32 addr, const u32 stride, IR:
addr = ir.IAdd(addr, ir.Imm32(off_dw)); addr = ir.IAdd(addr, ir.Imm32(off_dw));
} }
const IR::U32 control_point_index = ir.IDiv(addr, ir.Imm32(stride)); const IR::U32 control_point_index = ir.IDiv(addr, ir.Imm32(stride));
const IR::U32 addr_for_attrs = TryOptimizeAddressModulo(addr, stride, ir); const IR::U32 opt_addr = TryOptimizeAddressModulo(addr, stride, ir);
const IR::U32 attr_index = const IR::U32 offset = ir.IMod(opt_addr, ir.Imm32(stride));
ir.ShiftRightLogical(ir.IMod(addr_for_attrs, ir.Imm32(stride)), ir.Imm32(4u)); const IR::U32 attr_index = ir.ShiftRightLogical(offset, ir.Imm32(4u));
const IR::U32 comp_index = const IR::U32 comp_index =
ir.ShiftRightLogical(ir.BitwiseAnd(addr_for_attrs, ir.Imm32(0xFU)), ir.Imm32(2u)); ir.ShiftRightLogical(ir.BitwiseAnd(offset, ir.Imm32(0xFU)), ir.Imm32(2u));
if (is_output_read_in_tcs) { if (is_output_read_in_tcs) {
return ir.ReadTcsGenericOuputAttribute(control_point_index, attr_index, comp_index); return ir.ReadTcsGenericOuputAttribute(control_point_index, attr_index, comp_index);
} else { } else {
@ -452,13 +452,13 @@ void HullShaderTransform(IR::Program& program, RuntimeInfo& runtime_info) {
if (off_dw > 0) { if (off_dw > 0) {
addr = ir.IAdd(addr, ir.Imm32(off_dw)); addr = ir.IAdd(addr, ir.Imm32(off_dw));
} }
u32 stride = runtime_info.hs_info.hs_output_cp_stride; const u32 stride = runtime_info.hs_info.hs_output_cp_stride;
// Invocation ID array index is implicit, handled by SPIRV backend // Invocation ID array index is implicit, handled by SPIRV backend
const IR::U32 addr_for_attrs = TryOptimizeAddressModulo(addr, stride, ir); const IR::U32 opt_addr = TryOptimizeAddressModulo(addr, stride, ir);
const IR::U32 attr_index = ir.ShiftRightLogical( const IR::U32 offset = ir.IMod(opt_addr, ir.Imm32(stride));
ir.IMod(addr_for_attrs, ir.Imm32(stride)), ir.Imm32(4u)); const IR::U32 attr_index = ir.ShiftRightLogical(offset, ir.Imm32(4u));
const IR::U32 comp_index = ir.ShiftRightLogical( const IR::U32 comp_index = ir.ShiftRightLogical(
ir.BitwiseAnd(addr_for_attrs, ir.Imm32(0xFU)), ir.Imm32(2u)); ir.BitwiseAnd(offset, ir.Imm32(0xFU)), ir.Imm32(2u));
ir.SetTcsGenericAttribute(data_component, attr_index, comp_index); ir.SetTcsGenericAttribute(data_component, attr_index, comp_index);
} else { } else {
ASSERT(output_kind == AttributeRegion::PatchConst); ASSERT(output_kind == AttributeRegion::PatchConst);
@ -535,8 +535,7 @@ void HullShaderTransform(IR::Program& program, RuntimeInfo& runtime_info) {
// ... // ...
IR::IREmitter ir{*entry_block, it}; IR::IREmitter ir{*entry_block, it};
ASSERT(runtime_info.hs_info.ls_stride % 16 == 0); u32 num_attributes = Common::AlignUp(runtime_info.hs_info.ls_stride, 16) >> 4;
u32 num_attributes = runtime_info.hs_info.ls_stride / 16;
const auto invocation_id = ir.GetAttributeU32(IR::Attribute::InvocationId); const auto invocation_id = ir.GetAttributeU32(IR::Attribute::InvocationId);
for (u32 attr_no = 0; attr_no < num_attributes; attr_no++) { for (u32 attr_no = 0; attr_no < num_attributes; attr_no++) {
for (u32 comp = 0; comp < 4; comp++) { for (u32 comp = 0; comp < 4; comp++) {

View File

@ -164,6 +164,7 @@ public:
return desc.sharp_idx == existing.sharp_idx && desc.is_array == existing.is_array; return desc.sharp_idx == existing.sharp_idx && desc.is_array == existing.is_array;
})}; })};
auto& image = image_resources[index]; auto& image = image_resources[index];
image.is_atomic |= desc.is_atomic;
image.is_written |= desc.is_written; image.is_written |= desc.is_written;
return index; return index;
} }
@ -483,55 +484,73 @@ void PatchDataRingAccess(IR::Block& block, IR::Inst& inst, Info& info, Descripto
inst.SetArg(1, ir.Imm32(binding)); inst.SetArg(1, ir.Imm32(binding));
} }
IR::U32 CalculateBufferAddress(IR::IREmitter& ir, const IR::Inst& inst, const Info& info,
const AmdGpu::Buffer& buffer, u32 stride) {
const auto inst_info = inst.Flags<IR::BufferInstInfo>();
// index = (inst_idxen ? vgpr_index : 0) + (const_add_tid_enable ? thread_id[5:0] : 0)
IR::U32 index = ir.Imm32(0U);
if (inst_info.index_enable) {
const IR::U32 vgpr_index{inst_info.offset_enable
? IR::U32{ir.CompositeExtract(inst.Arg(1), 0)}
: IR::U32{inst.Arg(1)}};
index = ir.IAdd(index, vgpr_index);
}
if (buffer.add_tid_enable) {
ASSERT_MSG(info.l_stage == LogicalStage::Compute,
"Thread ID buffer addressing is not supported outside of compute.");
const IR::U32 thread_id{ir.LaneId()};
index = ir.IAdd(index, thread_id);
}
// offset = (inst_offen ? vgpr_offset : 0) + inst_offset
IR::U32 offset = ir.Imm32(inst_info.inst_offset.Value());
if (inst_info.offset_enable) {
const IR::U32 vgpr_offset = inst_info.index_enable
? IR::U32{ir.CompositeExtract(inst.Arg(1), 1)}
: IR::U32{inst.Arg(1)};
offset = ir.IAdd(offset, vgpr_offset);
}
const IR::U32 const_stride = ir.Imm32(stride);
IR::U32 buffer_offset;
if (buffer.swizzle_enable) {
const IR::U32 const_index_stride = ir.Imm32(buffer.GetIndexStride());
const IR::U32 const_element_size = ir.Imm32(buffer.GetElementSize());
// index_msb = index / const_index_stride
const IR::U32 index_msb{ir.IDiv(index, const_index_stride)};
// index_lsb = index % const_index_stride
const IR::U32 index_lsb{ir.IMod(index, const_index_stride)};
// offset_msb = offset / const_element_size
const IR::U32 offset_msb{ir.IDiv(offset, const_element_size)};
// offset_lsb = offset % const_element_size
const IR::U32 offset_lsb{ir.IMod(offset, const_element_size)};
// buffer_offset =
// (index_msb * const_stride + offset_msb * const_element_size) * const_index_stride
// + index_lsb * const_element_size + offset_lsb
const IR::U32 buffer_offset_msb = ir.IMul(
ir.IAdd(ir.IMul(index_msb, const_stride), ir.IMul(offset_msb, const_element_size)),
const_index_stride);
const IR::U32 buffer_offset_lsb =
ir.IAdd(ir.IMul(index_lsb, const_element_size), offset_lsb);
buffer_offset = ir.IAdd(buffer_offset_msb, buffer_offset_lsb);
} else {
// buffer_offset = index * const_stride + offset
buffer_offset = ir.IAdd(ir.IMul(index, const_stride), offset);
}
return buffer_offset;
}
void PatchBufferArgs(IR::Block& block, IR::Inst& inst, Info& info) { void PatchBufferArgs(IR::Block& block, IR::Inst& inst, Info& info) {
const auto handle = inst.Arg(0); const auto handle = inst.Arg(0);
const auto buffer_res = info.buffers[handle.U32()]; const auto buffer_res = info.buffers[handle.U32()];
const auto buffer = buffer_res.GetSharp(info); const auto buffer = buffer_res.GetSharp(info);
ASSERT(!buffer.add_tid_enable);
// Address of constant buffer reads can be calculated at IR emission time. // Address of constant buffer reads can be calculated at IR emission time.
if (inst.GetOpcode() == IR::Opcode::ReadConstBuffer) { if (inst.GetOpcode() == IR::Opcode::ReadConstBuffer) {
return; return;
} }
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
const auto inst_info = inst.Flags<IR::BufferInstInfo>(); inst.SetArg(1, CalculateBufferAddress(ir, inst, info, buffer, buffer.stride));
const IR::U32 index_stride = ir.Imm32(buffer.index_stride);
const IR::U32 element_size = ir.Imm32(buffer.element_size);
// Compute address of the buffer using the stride.
IR::U32 address = ir.Imm32(inst_info.inst_offset.Value());
if (inst_info.index_enable) {
const IR::U32 index = inst_info.offset_enable ? IR::U32{ir.CompositeExtract(inst.Arg(1), 0)}
: IR::U32{inst.Arg(1)};
if (buffer.swizzle_enable) {
const IR::U32 stride_index_stride =
ir.Imm32(static_cast<u32>(buffer.stride * buffer.index_stride));
const IR::U32 index_msb = ir.IDiv(index, index_stride);
const IR::U32 index_lsb = ir.IMod(index, index_stride);
address = ir.IAdd(address, ir.IAdd(ir.IMul(index_msb, stride_index_stride),
ir.IMul(index_lsb, element_size)));
} else {
address = ir.IAdd(address, ir.IMul(index, ir.Imm32(buffer.GetStride())));
}
}
if (inst_info.offset_enable) {
const IR::U32 offset = inst_info.index_enable ? IR::U32{ir.CompositeExtract(inst.Arg(1), 1)}
: IR::U32{inst.Arg(1)};
if (buffer.swizzle_enable) {
const IR::U32 element_size_index_stride =
ir.Imm32(buffer.element_size * buffer.index_stride);
const IR::U32 offset_msb = ir.IDiv(offset, element_size);
const IR::U32 offset_lsb = ir.IMod(offset, element_size);
address = ir.IAdd(address,
ir.IAdd(ir.IMul(offset_msb, element_size_index_stride), offset_lsb));
} else {
address = ir.IAdd(address, offset);
}
}
inst.SetArg(1, address);
} }
void PatchTextureBufferArgs(IR::Block& block, IR::Inst& inst, Info& info) { void PatchTextureBufferArgs(IR::Block& block, IR::Inst& inst, Info& info) {
@ -539,8 +558,15 @@ void PatchTextureBufferArgs(IR::Block& block, IR::Inst& inst, Info& info) {
const auto buffer_res = info.texture_buffers[handle.U32()]; const auto buffer_res = info.texture_buffers[handle.U32()];
const auto buffer = buffer_res.GetSharp(info); const auto buffer = buffer_res.GetSharp(info);
ASSERT(!buffer.swizzle_enable && !buffer.add_tid_enable); // Only linear addressing with index is supported currently, since we cannot yet
// address with sub-texel granularity.
const auto inst_info = inst.Flags<IR::BufferInstInfo>();
ASSERT_MSG(!buffer.swizzle_enable && !inst_info.offset_enable && inst_info.inst_offset == 0,
"Unsupported texture buffer address mode.");
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
// Stride of 1 to get an index into formatted data. See above addressing limitations.
inst.SetArg(1, CalculateBufferAddress(ir, inst, info, buffer, 1U));
if (inst.GetOpcode() == IR::Opcode::StoreBufferFormatF32) { if (inst.GetOpcode() == IR::Opcode::StoreBufferFormatF32) {
const auto swizzled = ApplySwizzle(ir, inst.Arg(2), buffer.DstSelect()); const auto swizzled = ApplySwizzle(ir, inst.Arg(2), buffer.DstSelect());

View File

@ -21,10 +21,16 @@ struct VsAttribSpecialization {
struct BufferSpecialization { struct BufferSpecialization {
u16 stride : 14; u16 stride : 14;
u16 is_storage : 1; u16 is_storage : 1;
u16 swizzle_enable : 1;
u8 index_stride : 2 = 0;
u8 element_size : 2 = 0;
u32 size = 0; u32 size = 0;
bool operator==(const BufferSpecialization& other) const { bool operator==(const BufferSpecialization& other) const {
return stride == other.stride && is_storage == other.is_storage && return stride == other.stride && is_storage == other.is_storage &&
swizzle_enable == other.swizzle_enable &&
(!swizzle_enable ||
(index_stride == other.index_stride && element_size == other.element_size)) &&
(size >= other.is_storage || is_storage); (size >= other.is_storage || is_storage);
} }
}; };
@ -101,6 +107,11 @@ struct StageSpecialization {
[](auto& spec, const auto& desc, AmdGpu::Buffer sharp) { [](auto& spec, const auto& desc, AmdGpu::Buffer sharp) {
spec.stride = sharp.GetStride(); spec.stride = sharp.GetStride();
spec.is_storage = desc.IsStorage(sharp); spec.is_storage = desc.IsStorage(sharp);
spec.swizzle_enable = sharp.swizzle_enable;
if (spec.swizzle_enable) {
spec.index_stride = sharp.index_stride;
spec.element_size = sharp.element_size;
}
if (!spec.is_storage) { if (!spec.is_storage) {
spec.size = sharp.GetSize(); spec.size = sharp.GetSize();
} }

View File

@ -260,7 +260,7 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
const std::string_view label{reinterpret_cast<const char*>(&nop->data_block[1]), const std::string_view label{reinterpret_cast<const char*>(&nop->data_block[1]),
marker_sz}; marker_sz};
if (rasterizer) { if (rasterizer) {
rasterizer->ScopeMarkerBegin(label); rasterizer->ScopeMarkerBegin(label, true);
} }
break; break;
} }
@ -271,13 +271,13 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
const u32 color = *reinterpret_cast<const u32*>( const u32 color = *reinterpret_cast<const u32*>(
reinterpret_cast<const u8*>(&nop->data_block[1]) + marker_sz); reinterpret_cast<const u8*>(&nop->data_block[1]) + marker_sz);
if (rasterizer) { if (rasterizer) {
rasterizer->ScopedMarkerInsertColor(label, color); rasterizer->ScopedMarkerInsertColor(label, color, true);
} }
break; break;
} }
case PM4CmdNop::PayloadType::DebugMarkerPop: { case PM4CmdNop::PayloadType::DebugMarkerPop: {
if (rasterizer) { if (rasterizer) {
rasterizer->ScopeMarkerEnd(); rasterizer->ScopeMarkerEnd(true);
} }
break; break;
} }
@ -412,7 +412,7 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
} }
if (rasterizer) { if (rasterizer) {
const auto cmd_address = reinterpret_cast<const void*>(header); const auto cmd_address = reinterpret_cast<const void*>(header);
rasterizer->ScopeMarkerBegin(fmt::format("dcb:{}:DrawIndex2", cmd_address)); rasterizer->ScopeMarkerBegin(fmt::format("gfx:{}:DrawIndex2", cmd_address));
rasterizer->Draw(true); rasterizer->Draw(true);
rasterizer->ScopeMarkerEnd(); rasterizer->ScopeMarkerEnd();
} }
@ -430,7 +430,7 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
if (rasterizer) { if (rasterizer) {
const auto cmd_address = reinterpret_cast<const void*>(header); const auto cmd_address = reinterpret_cast<const void*>(header);
rasterizer->ScopeMarkerBegin( rasterizer->ScopeMarkerBegin(
fmt::format("dcb:{}:DrawIndexOffset2", cmd_address)); fmt::format("gfx:{}:DrawIndexOffset2", cmd_address));
rasterizer->Draw(true, draw_index_off->index_offset); rasterizer->Draw(true, draw_index_off->index_offset);
rasterizer->ScopeMarkerEnd(); rasterizer->ScopeMarkerEnd();
} }
@ -445,7 +445,7 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
} }
if (rasterizer) { if (rasterizer) {
const auto cmd_address = reinterpret_cast<const void*>(header); const auto cmd_address = reinterpret_cast<const void*>(header);
rasterizer->ScopeMarkerBegin(fmt::format("dcb:{}:DrawIndexAuto", cmd_address)); rasterizer->ScopeMarkerBegin(fmt::format("gfx:{}:DrawIndexAuto", cmd_address));
rasterizer->Draw(false); rasterizer->Draw(false);
rasterizer->ScopeMarkerEnd(); rasterizer->ScopeMarkerEnd();
} }
@ -460,7 +460,7 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
} }
if (rasterizer) { if (rasterizer) {
const auto cmd_address = reinterpret_cast<const void*>(header); const auto cmd_address = reinterpret_cast<const void*>(header);
rasterizer->ScopeMarkerBegin(fmt::format("dcb:{}:DrawIndirect", cmd_address)); rasterizer->ScopeMarkerBegin(fmt::format("gfx:{}:DrawIndirect", cmd_address));
rasterizer->DrawIndirect(false, indirect_args_addr, offset, size, 1, 0); rasterizer->DrawIndirect(false, indirect_args_addr, offset, size, 1, 0);
rasterizer->ScopeMarkerEnd(); rasterizer->ScopeMarkerEnd();
} }
@ -477,7 +477,7 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
if (rasterizer) { if (rasterizer) {
const auto cmd_address = reinterpret_cast<const void*>(header); const auto cmd_address = reinterpret_cast<const void*>(header);
rasterizer->ScopeMarkerBegin( rasterizer->ScopeMarkerBegin(
fmt::format("dcb:{}:DrawIndexIndirect", cmd_address)); fmt::format("gfx:{}:DrawIndexIndirect", cmd_address));
rasterizer->DrawIndirect(true, indirect_args_addr, offset, size, 1, 0); rasterizer->DrawIndirect(true, indirect_args_addr, offset, size, 1, 0);
rasterizer->ScopeMarkerEnd(); rasterizer->ScopeMarkerEnd();
} }
@ -493,7 +493,7 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
if (rasterizer) { if (rasterizer) {
const auto cmd_address = reinterpret_cast<const void*>(header); const auto cmd_address = reinterpret_cast<const void*>(header);
rasterizer->ScopeMarkerBegin( rasterizer->ScopeMarkerBegin(
fmt::format("dcb:{}:DrawIndexIndirectCountMulti", cmd_address)); fmt::format("gfx:{}:DrawIndexIndirectCountMulti", cmd_address));
rasterizer->DrawIndirect( rasterizer->DrawIndirect(
true, indirect_args_addr, offset, draw_index_indirect->stride, true, indirect_args_addr, offset, draw_index_indirect->stride,
draw_index_indirect->count, draw_index_indirect->countAddr); draw_index_indirect->count, draw_index_indirect->countAddr);
@ -514,7 +514,7 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
} }
if (rasterizer && (cs_program.dispatch_initiator & 1)) { if (rasterizer && (cs_program.dispatch_initiator & 1)) {
const auto cmd_address = reinterpret_cast<const void*>(header); const auto cmd_address = reinterpret_cast<const void*>(header);
rasterizer->ScopeMarkerBegin(fmt::format("dcb:{}:Dispatch", cmd_address)); rasterizer->ScopeMarkerBegin(fmt::format("gfx:{}:DispatchDirect", cmd_address));
rasterizer->DispatchDirect(); rasterizer->DispatchDirect();
rasterizer->ScopeMarkerEnd(); rasterizer->ScopeMarkerEnd();
} }
@ -533,7 +533,7 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
if (rasterizer && (cs_program.dispatch_initiator & 1)) { if (rasterizer && (cs_program.dispatch_initiator & 1)) {
const auto cmd_address = reinterpret_cast<const void*>(header); const auto cmd_address = reinterpret_cast<const void*>(header);
rasterizer->ScopeMarkerBegin( rasterizer->ScopeMarkerBegin(
fmt::format("dcb:{}:DispatchIndirect", cmd_address)); fmt::format("gfx:{}:DispatchIndirect", cmd_address));
rasterizer->DispatchIndirect(indirect_args_addr, offset, size); rasterizer->DispatchIndirect(indirect_args_addr, offset, size);
rasterizer->ScopeMarkerEnd(); rasterizer->ScopeMarkerEnd();
} }
@ -812,7 +812,7 @@ Liverpool::Task Liverpool::ProcessCompute(std::span<const u32> acb, u32 vqid) {
if (rasterizer && (cs_program.dispatch_initiator & 1)) { if (rasterizer && (cs_program.dispatch_initiator & 1)) {
const auto cmd_address = reinterpret_cast<const void*>(header); const auto cmd_address = reinterpret_cast<const void*>(header);
rasterizer->ScopeMarkerBegin( rasterizer->ScopeMarkerBegin(
fmt::format("acb[{}]:{}:DispatchIndirect", vqid, cmd_address)); fmt::format("asc[{}]:{}:DispatchDirect", vqid, cmd_address));
rasterizer->DispatchDirect(); rasterizer->DispatchDirect();
rasterizer->ScopeMarkerEnd(); rasterizer->ScopeMarkerEnd();
} }
@ -830,7 +830,8 @@ Liverpool::Task Liverpool::ProcessCompute(std::span<const u32> acb, u32 vqid) {
} }
if (rasterizer && (cs_program.dispatch_initiator & 1)) { if (rasterizer && (cs_program.dispatch_initiator & 1)) {
const auto cmd_address = reinterpret_cast<const void*>(header); const auto cmd_address = reinterpret_cast<const void*>(header);
rasterizer->ScopeMarkerBegin(fmt::format("acb[{}]:{}:Dispatch", vqid, cmd_address)); rasterizer->ScopeMarkerBegin(
fmt::format("asc[{}]:{}:DispatchIndirect", vqid, cmd_address));
rasterizer->DispatchIndirect(ib_address, 0, size); rasterizer->DispatchIndirect(ib_address, 0, size);
rasterizer->ScopeMarkerEnd(); rasterizer->ScopeMarkerEnd();
} }

View File

@ -429,11 +429,19 @@ struct Liverpool {
} depth_slice; } depth_slice;
bool DepthValid() const { bool DepthValid() const {
return Address() != 0 && z_info.format != ZFormat::Invalid; return DepthAddress() != 0 && z_info.format != ZFormat::Invalid;
} }
bool StencilValid() const { bool StencilValid() const {
return Address() != 0 && stencil_info.format != StencilFormat::Invalid; return StencilAddress() != 0 && stencil_info.format != StencilFormat::Invalid;
}
bool DepthWriteValid() const {
return DepthWriteAddress() != 0 && z_info.format != ZFormat::Invalid;
}
bool StencilWriteValid() const {
return StencilWriteAddress() != 0 && stencil_info.format != StencilFormat::Invalid;
} }
u32 Pitch() const { u32 Pitch() const {
@ -444,7 +452,7 @@ struct Liverpool {
return (depth_size.height_tile_max + 1) << 3; return (depth_size.height_tile_max + 1) << 3;
} }
u64 Address() const { u64 DepthAddress() const {
return u64(z_read_base) << 8; return u64(z_read_base) << 8;
} }
@ -452,6 +460,14 @@ struct Liverpool {
return u64(stencil_read_base) << 8; return u64(stencil_read_base) << 8;
} }
u64 DepthWriteAddress() const {
return u64(z_write_base) << 8;
}
u64 StencilWriteAddress() const {
return u64(stencil_write_base) << 8;
}
u32 NumSamples() const { u32 NumSamples() const {
return 1u << z_info.num_samples; // spec doesn't say it is a log2 return 1u << z_info.num_samples; // spec doesn't say it is a log2
} }
@ -1008,6 +1024,46 @@ struct Liverpool {
} }
}; };
enum class ForceEnable : u32 {
Off = 0,
Enable = 1,
Disable = 2,
};
enum class ForceSumm : u32 {
Off = 0,
MinZ = 1,
MaxZ = 2,
Both = 3,
};
union DepthRenderOverride {
u32 raw;
BitField<0, 2, ForceEnable> force_hiz_enable;
BitField<2, 2, ForceEnable> force_his_enable0;
BitField<4, 2, ForceEnable> force_his_enable1;
BitField<6, 1, u32> force_shader_z_order;
BitField<7, 1, u32> fast_z_disable;
BitField<8, 1, u32> fast_stencil_disable;
BitField<9, 1, u32> noop_cull_disable;
BitField<10, 1, u32> force_color_kill;
BitField<11, 1, u32> force_z_read;
BitField<12, 1, u32> force_stencil_read;
BitField<13, 2, ForceEnable> force_full_z_range;
BitField<15, 1, u32> force_qc_smask_conflict;
BitField<16, 1, u32> disable_viewport_clamp;
BitField<17, 1, u32> ignore_sc_zrange;
BitField<18, 1, u32> disable_fully_covered;
BitField<19, 2, ForceSumm> force_z_limit_summ;
BitField<21, 5, u32> max_tiles_in_dtt;
BitField<26, 1, u32> disable_tile_rate_tiles;
BitField<27, 1, u32> force_z_dirty;
BitField<28, 1, u32> force_stencil_dirty;
BitField<29, 1, u32> force_z_valid;
BitField<30, 1, u32> force_stencil_valid;
BitField<31, 1, u32> preserve_compression;
};
union AaConfig { union AaConfig {
BitField<0, 3, u32> msaa_num_samples; BitField<0, 3, u32> msaa_num_samples;
BitField<4, 1, u32> aa_mask_centroid_dtmn; BitField<4, 1, u32> aa_mask_centroid_dtmn;
@ -1209,7 +1265,8 @@ struct Liverpool {
DepthRenderControl depth_render_control; DepthRenderControl depth_render_control;
INSERT_PADDING_WORDS(1); INSERT_PADDING_WORDS(1);
DepthView depth_view; DepthView depth_view;
INSERT_PADDING_WORDS(2); DepthRenderOverride depth_render_override;
INSERT_PADDING_WORDS(1);
Address depth_htile_data_base; Address depth_htile_data_base;
INSERT_PADDING_WORDS(2); INSERT_PADDING_WORDS(2);
float depth_bounds_min; float depth_bounds_min;

View File

@ -76,6 +76,16 @@ struct Buffer {
u32 GetSize() const noexcept { u32 GetSize() const noexcept {
return stride == 0 ? num_records : (stride * num_records); return stride == 0 ? num_records : (stride * num_records);
} }
u32 GetIndexStride() const noexcept {
// Index stride is 2 bits, meaning 8, 16, 32, or 64.
return 8 << index_stride;
}
u32 GetElementSize() const noexcept {
// Element size is 2 bits, meaning 2, 4, 8, or 16.
return 2 << element_size;
}
}; };
static_assert(sizeof(Buffer) == 16); // 128bits static_assert(sizeof(Buffer) == 16); // 128bits

View File

@ -131,6 +131,8 @@ vk::BufferView Buffer::View(u32 offset, u32 size, bool is_written, AmdGpu::DataF
vk::to_string(view_result)); vk::to_string(view_result));
scheduler->DeferOperation( scheduler->DeferOperation(
[view, device = instance->GetDevice()] { device.destroyBufferView(view); }); [view, device = instance->GetDevice()] { device.destroyBufferView(view); });
Vulkan::SetObjectName(instance->GetDevice(), view, "BufferView {:#x}:{:#x}", cpu_addr + offset,
size);
return view; return view;
} }

View File

@ -71,8 +71,35 @@ vk::ClearValue ColorBufferClearValue(const AmdGpu::Liverpool::ColorBuffer& color
vk::SampleCountFlagBits NumSamples(u32 num_samples, vk::SampleCountFlags supported_flags); vk::SampleCountFlagBits NumSamples(u32 num_samples, vk::SampleCountFlags supported_flags);
static inline bool IsFormatDepthCompatible(vk::Format fmt) {
switch (fmt) {
// 32-bit float compatible
case vk::Format::eD32Sfloat:
case vk::Format::eR32Sfloat:
case vk::Format::eR32Uint:
// 16-bit unorm compatible
case vk::Format::eD16Unorm:
case vk::Format::eR16Unorm:
return true;
default:
return false;
}
}
static inline bool IsFormatStencilCompatible(vk::Format fmt) {
switch (fmt) {
// 8-bit uint compatible
case vk::Format::eS8Uint:
case vk::Format::eR8Uint:
case vk::Format::eR8Unorm:
return true;
default:
return false;
}
}
static inline vk::Format PromoteFormatToDepth(vk::Format fmt) { static inline vk::Format PromoteFormatToDepth(vk::Format fmt) {
if (fmt == vk::Format::eR32Sfloat) { if (fmt == vk::Format::eR32Sfloat || fmt == vk::Format::eR32Uint) {
return vk::Format::eD32Sfloat; return vk::Format::eD32Sfloat;
} else if (fmt == vk::Format::eR16Unorm) { } else if (fmt == vk::Format::eR16Unorm) {
return vk::Format::eD16Unorm; return vk::Format::eD16Unorm;

View File

@ -92,15 +92,13 @@ std::string GetReadableVersion(u32 version) {
Instance::Instance(bool enable_validation, bool enable_crash_diagnostic) Instance::Instance(bool enable_validation, bool enable_crash_diagnostic)
: instance{CreateInstance(Frontend::WindowSystemType::Headless, enable_validation, : instance{CreateInstance(Frontend::WindowSystemType::Headless, enable_validation,
enable_crash_diagnostic)}, enable_crash_diagnostic)},
physical_devices{EnumeratePhysicalDevices(instance)}, physical_devices{EnumeratePhysicalDevices(instance)} {}
crash_diagnostic{enable_crash_diagnostic} {}
Instance::Instance(Frontend::WindowSDL& window, s32 physical_device_index, Instance::Instance(Frontend::WindowSDL& window, s32 physical_device_index,
bool enable_validation /*= false*/, bool enable_crash_diagnostic /*= false*/) bool enable_validation /*= false*/, bool enable_crash_diagnostic /*= false*/)
: instance{CreateInstance(window.GetWindowInfo().type, enable_validation, : instance{CreateInstance(window.GetWindowInfo().type, enable_validation,
enable_crash_diagnostic)}, enable_crash_diagnostic)},
physical_devices{EnumeratePhysicalDevices(instance)}, physical_devices{EnumeratePhysicalDevices(instance)} {
crash_diagnostic{enable_crash_diagnostic} {
if (enable_validation) { if (enable_validation) {
debug_callback = CreateDebugCallback(*instance); debug_callback = CreateDebugCallback(*instance);
} }
@ -272,6 +270,7 @@ bool Instance::CreateDevice() {
legacy_vertex_attributes = add_extension(VK_EXT_LEGACY_VERTEX_ATTRIBUTES_EXTENSION_NAME); legacy_vertex_attributes = add_extension(VK_EXT_LEGACY_VERTEX_ATTRIBUTES_EXTENSION_NAME);
image_load_store_lod = add_extension(VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_EXTENSION_NAME); image_load_store_lod = add_extension(VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_EXTENSION_NAME);
amd_gcn_shader = add_extension(VK_AMD_GCN_SHADER_EXTENSION_NAME); amd_gcn_shader = add_extension(VK_AMD_GCN_SHADER_EXTENSION_NAME);
add_extension(VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME);
// These extensions are promoted by Vulkan 1.3, but for greater compatibility we use Vulkan 1.2 // These extensions are promoted by Vulkan 1.3, but for greater compatibility we use Vulkan 1.2
// with extensions. // with extensions.
@ -562,10 +561,7 @@ void Instance::CollectToolingInfo() {
return; return;
} }
for (const vk::PhysicalDeviceToolProperties& tool : tools) { for (const vk::PhysicalDeviceToolProperties& tool : tools) {
const std::string_view name = tool.name; LOG_INFO(Render_Vulkan, "Attached debugging tool: {}", tool.name);
LOG_INFO(Render_Vulkan, "Attached debugging tool: {}", name);
has_renderdoc = has_renderdoc || name == "RenderDoc";
has_nsight_graphics = has_nsight_graphics || name == "NVIDIA Nsight Graphics";
} }
} }

View File

@ -79,11 +79,6 @@ public:
return profiler_context; return profiler_context;
} }
/// Returns true when a known debugging tool is attached.
bool HasDebuggingToolAttached() const {
return crash_diagnostic || has_renderdoc || has_nsight_graphics;
}
/// Returns true if anisotropic filtering is supported /// Returns true if anisotropic filtering is supported
bool IsAnisotropicFilteringSupported() const { bool IsAnisotropicFilteringSupported() const {
return features.samplerAnisotropy; return features.samplerAnisotropy;
@ -340,13 +335,9 @@ private:
bool legacy_vertex_attributes{}; bool legacy_vertex_attributes{};
bool image_load_store_lod{}; bool image_load_store_lod{};
bool amd_gcn_shader{}; bool amd_gcn_shader{};
bool tooling_info{};
u64 min_imported_host_pointer_alignment{}; u64 min_imported_host_pointer_alignment{};
u32 subgroup_size{}; u32 subgroup_size{};
bool tooling_info{};
bool debug_utils_supported{};
bool crash_diagnostic{};
bool has_nsight_graphics{};
bool has_renderdoc{};
}; };
} // namespace Vulkan } // namespace Vulkan

View File

@ -31,17 +31,6 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL DebugUtilsCallback(
VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT type, VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT type,
const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data) { const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data) {
switch (static_cast<u32>(callback_data->messageIdNumber)) {
case 0x609a13b: // Vertex attribute at location not consumed by shader
case 0xc81ad50e:
case 0xb7c39078:
case 0x32868fde: // vkCreateBufferView(): pCreateInfo->range does not equal VK_WHOLE_SIZE
case 0x1012616b: // `VK_FORMAT_UNDEFINED` does not match fragment shader output type
return VK_FALSE;
default:
break;
}
Common::Log::Level level{}; Common::Log::Level level{};
switch (severity) { switch (severity) {
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:

View File

@ -7,6 +7,7 @@
#include <variant> #include <variant>
#include <fmt/format.h> #include <fmt/format.h>
#include "common/config.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/types.h" #include "common/types.h"
#include "video_core/renderer_vulkan/vk_common.h" #include "video_core/renderer_vulkan/vk_common.h"
@ -32,6 +33,9 @@ concept VulkanHandleType = vk::isVulkanHandleType<T>::value;
template <VulkanHandleType HandleType> template <VulkanHandleType HandleType>
void SetObjectName(vk::Device device, const HandleType& handle, std::string_view debug_name) { void SetObjectName(vk::Device device, const HandleType& handle, std::string_view debug_name) {
if (!Config::vkHostMarkersEnabled()) {
return;
}
const vk::DebugUtilsObjectNameInfoEXT name_info = { const vk::DebugUtilsObjectNameInfoEXT name_info = {
.objectType = HandleType::objectType, .objectType = HandleType::objectType,
.objectHandle = reinterpret_cast<u64>(static_cast<typename HandleType::NativeType>(handle)), .objectHandle = reinterpret_cast<u64>(static_cast<typename HandleType::NativeType>(handle)),
@ -46,6 +50,9 @@ void SetObjectName(vk::Device device, const HandleType& handle, std::string_view
template <VulkanHandleType HandleType, typename... Args> template <VulkanHandleType HandleType, typename... Args>
void SetObjectName(vk::Device device, const HandleType& handle, const char* format, void SetObjectName(vk::Device device, const HandleType& handle, const char* format,
const Args&... args) { const Args&... args) {
if (!Config::vkHostMarkersEnabled()) {
return;
}
const std::string debug_name = fmt::vformat(format, fmt::make_format_args(args...)); const std::string debug_name = fmt::vformat(format, fmt::make_format_args(args...));
SetObjectName(device, handle, debug_name); SetObjectName(device, handle, debug_name);
} }

View File

@ -20,6 +20,9 @@
#include <vk_mem_alloc.h> #include <vk_mem_alloc.h>
#include <imgui.h>
#include "imgui/renderer/imgui_impl_vulkan.h"
namespace Vulkan { namespace Vulkan {
bool CanBlitToSwapchain(const vk::PhysicalDevice physical_device, vk::Format format) { bool CanBlitToSwapchain(const vk::PhysicalDevice physical_device, vk::Format format) {
@ -103,17 +106,6 @@ static vk::Rect2D FitImage(s32 frame_width, s32 frame_height, s32 swapchain_widt
dst_rect.offset.x, dst_rect.offset.y); dst_rect.offset.x, dst_rect.offset.y);
} }
static vk::Format FormatToUnorm(vk::Format fmt) {
switch (fmt) {
case vk::Format::eR8G8B8A8Srgb:
return vk::Format::eR8G8B8A8Unorm;
case vk::Format::eB8G8R8A8Srgb:
return vk::Format::eB8G8R8A8Unorm;
default:
UNREACHABLE();
}
}
void Presenter::CreatePostProcessPipeline() { void Presenter::CreatePostProcessPipeline() {
static const std::array pp_shaders{ static const std::array pp_shaders{
HostShaders::FS_TRI_VERT, HostShaders::FS_TRI_VERT,
@ -324,9 +316,6 @@ Presenter::Presenter(Frontend::WindowSDL& window_, AmdGpu::Liverpool* liverpool_
CreatePostProcessPipeline(); CreatePostProcessPipeline();
// Setup ImGui
ImGui::Core::Initialize(instance, window, num_images,
FormatToUnorm(swapchain.GetSurfaceFormat().format));
ImGui::Layer::AddLayer(Common::Singleton<Core::Devtools::Layer>::Instance()); ImGui::Layer::AddLayer(Common::Singleton<Core::Devtools::Layer>::Instance());
} }
@ -344,6 +333,9 @@ Presenter::~Presenter() {
void Presenter::RecreateFrame(Frame* frame, u32 width, u32 height) { void Presenter::RecreateFrame(Frame* frame, u32 width, u32 height) {
const vk::Device device = instance.GetDevice(); const vk::Device device = instance.GetDevice();
if (frame->imgui_texture) {
ImGui::Vulkan::RemoveTexture(frame->imgui_texture);
}
if (frame->image_view) { if (frame->image_view) {
device.destroyImageView(frame->image_view); device.destroyImageView(frame->image_view);
} }
@ -361,7 +353,7 @@ void Presenter::RecreateFrame(Frame* frame, u32 width, u32 height) {
.arrayLayers = 1, .arrayLayers = 1,
.samples = vk::SampleCountFlagBits::e1, .samples = vk::SampleCountFlagBits::e1,
.usage = vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferDst | .usage = vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferDst |
vk::ImageUsageFlagBits::eTransferSrc, vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eSampled,
}; };
const VmaAllocationCreateInfo alloc_info = { const VmaAllocationCreateInfo alloc_info = {
@ -388,7 +380,7 @@ void Presenter::RecreateFrame(Frame* frame, u32 width, u32 height) {
const vk::ImageViewCreateInfo view_info = { const vk::ImageViewCreateInfo view_info = {
.image = frame->image, .image = frame->image,
.viewType = vk::ImageViewType::e2D, .viewType = vk::ImageViewType::e2D,
.format = FormatToUnorm(format), .format = swapchain.GetViewFormat(),
.subresourceRange{ .subresourceRange{
.aspectMask = vk::ImageAspectFlagBits::eColor, .aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0, .baseMipLevel = 0,
@ -403,6 +395,63 @@ void Presenter::RecreateFrame(Frame* frame, u32 width, u32 height) {
frame->image_view = view; frame->image_view = view;
frame->width = width; frame->width = width;
frame->height = height; frame->height = height;
frame->imgui_texture = ImGui::Vulkan::AddTexture(view, vk::ImageLayout::eShaderReadOnlyOptimal);
}
Frame* Presenter::PrepareLastFrame() {
if (last_submit_frame == nullptr) {
return nullptr;
}
Frame* frame = last_submit_frame;
while (true) {
vk::Result result = instance.GetDevice().waitForFences(frame->present_done, false,
std::numeric_limits<u64>::max());
if (result == vk::Result::eSuccess) {
break;
}
if (result == vk::Result::eTimeout) {
continue;
}
ASSERT_MSG(result != vk::Result::eErrorDeviceLost,
"Device lost during waiting for a frame");
}
auto& scheduler = flip_scheduler;
scheduler.EndRendering();
const auto cmdbuf = scheduler.CommandBuffer();
const auto frame_subresources = vk::ImageSubresourceRange{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
};
const auto pre_barrier =
vk::ImageMemoryBarrier2{.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
.srcAccessMask = vk::AccessFlagBits2::eColorAttachmentRead,
.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
.dstAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
.oldLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
.newLayout = vk::ImageLayout::eGeneral,
.image = frame->image,
.subresourceRange{frame_subresources}};
cmdbuf.pipelineBarrier2(vk::DependencyInfo{
.imageMemoryBarrierCount = 1,
.pImageMemoryBarriers = &pre_barrier,
});
// Flush frame creation commands.
frame->ready_semaphore = scheduler.GetMasterSemaphore()->Handle();
frame->ready_tick = scheduler.CurrentTick();
SubmitInfo info{};
scheduler.Flush(info);
return frame;
} }
bool Presenter::ShowSplash(Frame* frame /*= nullptr*/) { bool Presenter::ShowSplash(Frame* frame /*= nullptr*/) {
@ -418,6 +467,12 @@ bool Presenter::ShowSplash(Frame* frame /*= nullptr*/) {
draw_scheduler.EndRendering(); draw_scheduler.EndRendering();
const auto cmdbuf = draw_scheduler.CommandBuffer(); const auto cmdbuf = draw_scheduler.CommandBuffer();
if (Config::vkHostMarkersEnabled()) {
cmdbuf.beginDebugUtilsLabelEXT(vk::DebugUtilsLabelEXT{
.pLabelName = "ShowSplash",
});
}
if (!frame) { if (!frame) {
if (!splash_img.has_value()) { if (!splash_img.has_value()) {
VideoCore::ImageInfo info{}; VideoCore::ImageInfo info{};
@ -485,6 +540,10 @@ bool Presenter::ShowSplash(Frame* frame /*= nullptr*/) {
.pImageMemoryBarriers = &post_barrier, .pImageMemoryBarriers = &post_barrier,
}); });
if (Config::vkHostMarkersEnabled()) {
cmdbuf.endDebugUtilsLabelEXT();
}
// Flush frame creation commands. // Flush frame creation commands.
frame->ready_semaphore = draw_scheduler.GetMasterSemaphore()->Handle(); frame->ready_semaphore = draw_scheduler.GetMasterSemaphore()->Handle();
frame->ready_tick = draw_scheduler.CurrentTick(); frame->ready_tick = draw_scheduler.CurrentTick();
@ -499,12 +558,26 @@ Frame* Presenter::PrepareFrameInternal(VideoCore::ImageId image_id, bool is_eop)
// Request a free presentation frame. // Request a free presentation frame.
Frame* frame = GetRenderFrame(); Frame* frame = GetRenderFrame();
if (image_id != VideoCore::NULL_IMAGE_ID) {
const auto& image = texture_cache.GetImage(image_id);
const auto extent = image.info.size;
if (frame->width != extent.width || frame->height != extent.height) {
RecreateFrame(frame, extent.width, extent.height);
}
}
// EOP flips are triggered from GPU thread so use the drawing scheduler to record // EOP flips are triggered from GPU thread so use the drawing scheduler to record
// commands. Otherwise we are dealing with a CPU flip which could have arrived // commands. Otherwise we are dealing with a CPU flip which could have arrived
// from any guest thread. Use a separate scheduler for that. // from any guest thread. Use a separate scheduler for that.
auto& scheduler = is_eop ? draw_scheduler : flip_scheduler; auto& scheduler = is_eop ? draw_scheduler : flip_scheduler;
scheduler.EndRendering(); scheduler.EndRendering();
const auto cmdbuf = scheduler.CommandBuffer(); const auto cmdbuf = scheduler.CommandBuffer();
if (Config::vkHostMarkersEnabled()) {
const auto label = fmt::format("PrepareFrameInternal:{}", image_id.index);
cmdbuf.beginDebugUtilsLabelEXT(vk::DebugUtilsLabelEXT{
.pLabelName = label.c_str(),
});
}
const auto frame_subresources = vk::ImageSubresourceRange{ const auto frame_subresources = vk::ImageSubresourceRange{
.aspectMask = vk::ImageAspectFlagBits::eColor, .aspectMask = vk::ImageAspectFlagBits::eColor,
@ -515,8 +588,8 @@ Frame* Presenter::PrepareFrameInternal(VideoCore::ImageId image_id, bool is_eop)
}; };
const auto pre_barrier = const auto pre_barrier =
vk::ImageMemoryBarrier2{.srcStageMask = vk::PipelineStageFlagBits2::eTransfer, vk::ImageMemoryBarrier2{.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
.srcAccessMask = vk::AccessFlagBits2::eTransferRead, .srcAccessMask = vk::AccessFlagBits2::eColorAttachmentRead,
.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput, .dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
.dstAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite, .dstAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
.oldLayout = vk::ImageLayout::eUndefined, .oldLayout = vk::ImageLayout::eUndefined,
@ -541,6 +614,13 @@ Frame* Presenter::PrepareFrameInternal(VideoCore::ImageId image_id, bool is_eop)
VideoCore::ImageViewInfo info{}; VideoCore::ImageViewInfo info{};
info.format = image.info.pixel_format; info.format = image.info.pixel_format;
// Exclude alpha from output frame to avoid blending with UI.
info.mapping = vk::ComponentMapping{
.r = vk::ComponentSwizzle::eIdentity,
.g = vk::ComponentSwizzle::eIdentity,
.b = vk::ComponentSwizzle::eIdentity,
.a = vk::ComponentSwizzle::eOne,
};
if (auto view = image.FindView(info)) { if (auto view = image.FindView(info)) {
image_info.imageView = *texture_cache.GetImageView(view).image_view; image_info.imageView = *texture_cache.GetImageView(view).image_view;
} else { } else {
@ -619,6 +699,10 @@ Frame* Presenter::PrepareFrameInternal(VideoCore::ImageId image_id, bool is_eop)
.pImageMemoryBarriers = &post_barrier, .pImageMemoryBarriers = &post_barrier,
}); });
if (Config::vkHostMarkersEnabled()) {
cmdbuf.endDebugUtilsLabelEXT();
}
// Flush frame creation commands. // Flush frame creation commands.
frame->ready_semaphore = scheduler.GetMasterSemaphore()->Handle(); frame->ready_semaphore = scheduler.GetMasterSemaphore()->Handle();
frame->ready_tick = scheduler.CurrentTick(); frame->ready_tick = scheduler.CurrentTick();
@ -627,17 +711,19 @@ Frame* Presenter::PrepareFrameInternal(VideoCore::ImageId image_id, bool is_eop)
return frame; return frame;
} }
void Presenter::Present(Frame* frame) { void Presenter::Present(Frame* frame, bool is_reusing_frame) {
// Free the frame for reuse // Free the frame for reuse
const auto free_frame = [&] { const auto free_frame = [&] {
if (!is_reusing_frame) {
last_submit_frame = frame;
std::scoped_lock fl{free_mutex}; std::scoped_lock fl{free_mutex};
free_queue.push(frame); free_queue.push(frame);
free_cv.notify_one(); free_cv.notify_one();
}
}; };
// Recreate the swapchain if the window was resized. // Recreate the swapchain if the window was resized.
if (window.GetWidth() != swapchain.GetExtent().width || if (window.GetWidth() != swapchain.GetWidth() || window.GetHeight() != swapchain.GetHeight()) {
window.GetHeight() != swapchain.GetExtent().height) {
swapchain.Recreate(window.GetWidth(), window.GetHeight()); swapchain.Recreate(window.GetWidth(), window.GetHeight());
} }
@ -656,14 +742,19 @@ void Presenter::Present(Frame* frame) {
// the frame's present fence and future GetRenderFrame() call will hang waiting for this frame. // the frame's present fence and future GetRenderFrame() call will hang waiting for this frame.
instance.GetDevice().resetFences(frame->present_done); instance.GetDevice().resetFences(frame->present_done);
ImGui::Core::NewFrame(); ImGuiID dockId = ImGui::Core::NewFrame(is_reusing_frame);
const vk::Image swapchain_image = swapchain.Image(); const vk::Image swapchain_image = swapchain.Image();
const vk::ImageView swapchain_image_view = swapchain.ImageView();
auto& scheduler = present_scheduler; auto& scheduler = present_scheduler;
const auto cmdbuf = scheduler.CommandBuffer(); const auto cmdbuf = scheduler.CommandBuffer();
ImGui::Core::Render(cmdbuf, frame); if (Config::vkHostMarkersEnabled()) {
cmdbuf.beginDebugUtilsLabelEXT(vk::DebugUtilsLabelEXT{
.pLabelName = "Present",
});
}
{ {
auto* profiler_ctx = instance.GetProfilerContext(); auto* profiler_ctx = instance.GetProfilerContext();
@ -674,9 +765,9 @@ void Presenter::Present(Frame* frame) {
const std::array pre_barriers{ const std::array pre_barriers{
vk::ImageMemoryBarrier{ vk::ImageMemoryBarrier{
.srcAccessMask = vk::AccessFlagBits::eNone, .srcAccessMask = vk::AccessFlagBits::eNone,
.dstAccessMask = vk::AccessFlagBits::eTransferWrite, .dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite,
.oldLayout = vk::ImageLayout::eUndefined, .oldLayout = vk::ImageLayout::eUndefined,
.newLayout = vk::ImageLayout::eTransferDstOptimal, .newLayout = vk::ImageLayout::eColorAttachmentOptimal,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = swapchain_image, .image = swapchain_image,
@ -690,9 +781,9 @@ void Presenter::Present(Frame* frame) {
}, },
vk::ImageMemoryBarrier{ vk::ImageMemoryBarrier{
.srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite, .srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite,
.dstAccessMask = vk::AccessFlagBits::eTransferRead, .dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead,
.oldLayout = vk::ImageLayout::eGeneral, .oldLayout = vk::ImageLayout::eGeneral,
.newLayout = vk::ImageLayout::eTransferSrcOptimal, .newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = frame->image, .image = frame->image,
@ -705,10 +796,11 @@ void Presenter::Present(Frame* frame) {
}, },
}, },
}; };
const vk::ImageMemoryBarrier post_barrier{ const vk::ImageMemoryBarrier post_barrier{
.srcAccessMask = vk::AccessFlagBits::eTransferWrite, .srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite,
.dstAccessMask = vk::AccessFlagBits::eMemoryRead, .dstAccessMask = vk::AccessFlagBits::eMemoryRead,
.oldLayout = vk::ImageLayout::eTransferDstOptimal, .oldLayout = vk::ImageLayout::eColorAttachmentOptimal,
.newLayout = vk::ImageLayout::ePresentSrcKHR, .newLayout = vk::ImageLayout::ePresentSrcKHR,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
@ -723,14 +815,29 @@ void Presenter::Present(Frame* frame) {
}; };
cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput, cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput,
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eColorAttachmentOutput,
vk::DependencyFlagBits::eByRegion, {}, {}, pre_barriers); vk::DependencyFlagBits::eByRegion, {}, {}, pre_barriers);
cmdbuf.blitImage( { // Draw the game
frame->image, vk::ImageLayout::eTransferSrcOptimal, swapchain_image, ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{0.0f});
vk::ImageLayout::eTransferDstOptimal, ImGui::SetNextWindowDockID(dockId, ImGuiCond_Once);
MakeImageBlitStretch(frame->width, frame->height, extent.width, extent.height), ImGui::Begin("Display##game_display", nullptr, ImGuiWindowFlags_NoNav);
vk::Filter::eLinear);
ImVec2 contentArea = ImGui::GetContentRegionAvail();
const vk::Rect2D imgRect =
FitImage(frame->width, frame->height, (s32)contentArea.x, (s32)contentArea.y);
ImGui::SetCursorPos(ImGui::GetCursorStartPos() + ImVec2{
(float)imgRect.offset.x,
(float)imgRect.offset.y,
});
ImGui::Image(frame->imgui_texture, {
static_cast<float>(imgRect.extent.width),
static_cast<float>(imgRect.extent.height),
});
ImGui::End();
ImGui::PopStyleVar();
}
ImGui::Core::Render(cmdbuf, swapchain_image_view, swapchain.GetExtent());
cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eAllCommands,
@ -741,6 +848,10 @@ void Presenter::Present(Frame* frame) {
} }
} }
if (Config::vkHostMarkersEnabled()) {
cmdbuf.endDebugUtilsLabelEXT();
}
// Flush vulkan commands. // Flush vulkan commands.
SubmitInfo info{}; SubmitInfo info{};
info.AddWait(swapchain.GetImageAcquiredSemaphore()); info.AddWait(swapchain.GetImageAcquiredSemaphore());
@ -756,8 +867,10 @@ void Presenter::Present(Frame* frame) {
} }
free_frame(); free_frame();
if (!is_reusing_frame) {
DebugState.IncFlipFrameNum(); DebugState.IncFlipFrameNum();
} }
}
Frame* Presenter::GetRenderFrame() { Frame* Presenter::GetRenderFrame() {
// Wait for free presentation frames // Wait for free presentation frames
@ -790,9 +903,9 @@ Frame* Presenter::GetRenderFrame() {
} }
} }
// If the window dimensions changed, recreate this frame // Initialize default frame image
if (frame->width != window.GetWidth() || frame->height != window.GetHeight()) { if (frame->width == 0 || frame->height == 0) {
RecreateFrame(frame, window.GetWidth(), window.GetHeight()); RecreateFrame(frame, 1920, 1080);
} }
return frame; return frame;

View File

@ -5,6 +5,7 @@
#include <condition_variable> #include <condition_variable>
#include "imgui/imgui_config.h"
#include "video_core/amdgpu/liverpool.h" #include "video_core/amdgpu/liverpool.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
@ -30,6 +31,8 @@ struct Frame {
vk::Fence present_done; vk::Fence present_done;
vk::Semaphore ready_semaphore; vk::Semaphore ready_semaphore;
u64 ready_tick; u64 ready_tick;
ImTextureID imgui_texture;
}; };
enum SchedulerType { enum SchedulerType {
@ -86,8 +89,9 @@ public:
} }
bool ShowSplash(Frame* frame = nullptr); bool ShowSplash(Frame* frame = nullptr);
void Present(Frame* frame); void Present(Frame* frame, bool is_reusing_frame = false);
void RecreateFrame(Frame* frame, u32 width, u32 height); void RecreateFrame(Frame* frame, u32 width, u32 height);
Frame* PrepareLastFrame();
void FlushDraw() { void FlushDraw() {
SubmitInfo info{}; SubmitInfo info{};
@ -121,6 +125,7 @@ private:
vk::UniqueCommandPool command_pool; vk::UniqueCommandPool command_pool;
std::vector<Frame> present_frames; std::vector<Frame> present_frames;
std::queue<Frame*> free_queue; std::queue<Frame*> free_queue;
Frame* last_submit_frame;
std::mutex free_mutex; std::mutex free_mutex;
std::condition_variable free_cv; std::condition_variable free_cv;
std::condition_variable_any frame_cv; std::condition_variable_any frame_cv;

View File

@ -58,6 +58,7 @@ bool Rasterizer::FilterDraw() {
if (regs.color_control.mode == Liverpool::ColorControl::OperationMode::FmaskDecompress) { if (regs.color_control.mode == Liverpool::ColorControl::OperationMode::FmaskDecompress) {
// TODO: check for a valid MRT1 to promote the draw to the resolve pass. // TODO: check for a valid MRT1 to promote the draw to the resolve pass.
LOG_TRACE(Render_Vulkan, "FMask decompression pass skipped"); LOG_TRACE(Render_Vulkan, "FMask decompression pass skipped");
ScopedMarkerInsert("FmaskDecompress");
return false; return false;
} }
if (regs.color_control.mode == Liverpool::ColorControl::OperationMode::Resolve) { if (regs.color_control.mode == Liverpool::ColorControl::OperationMode::Resolve) {
@ -67,6 +68,27 @@ bool Rasterizer::FilterDraw() {
} }
if (regs.primitive_type == AmdGpu::PrimitiveType::None) { if (regs.primitive_type == AmdGpu::PrimitiveType::None) {
LOG_TRACE(Render_Vulkan, "Primitive type 'None' skipped"); LOG_TRACE(Render_Vulkan, "Primitive type 'None' skipped");
ScopedMarkerInsert("PrimitiveTypeNone");
return false;
}
const bool cb_disabled =
regs.color_control.mode == AmdGpu::Liverpool::ColorControl::OperationMode::Disable;
const auto depth_copy =
regs.depth_render_override.force_z_dirty && regs.depth_render_override.force_z_valid &&
regs.depth_buffer.DepthValid() && regs.depth_buffer.DepthWriteValid() &&
regs.depth_buffer.DepthAddress() != regs.depth_buffer.DepthWriteAddress();
const auto stencil_copy =
regs.depth_render_override.force_stencil_dirty &&
regs.depth_render_override.force_stencil_valid && regs.depth_buffer.StencilValid() &&
regs.depth_buffer.StencilWriteValid() &&
regs.depth_buffer.StencilAddress() != regs.depth_buffer.StencilWriteAddress();
if (cb_disabled && (depth_copy || stencil_copy)) {
// Games may disable color buffer and enable force depth/stencil dirty and valid to
// do a copy from one depth-stencil surface to another, without a pixel shader.
// We need to detect this case and perform the copy, otherwise it will have no effect.
LOG_TRACE(Render_Vulkan, "Performing depth-stencil override copy");
DepthStencilCopy(depth_copy, stencil_copy);
return false; return false;
} }
@ -224,10 +246,13 @@ void Rasterizer::EliminateFastClear() {
.layerCount = col_buf.view.slice_max - col_buf.view.slice_start + 1, .layerCount = col_buf.view.slice_max - col_buf.view.slice_start + 1,
}; };
scheduler.EndRendering(); scheduler.EndRendering();
ScopeMarkerBegin(fmt::format("EliminateFastClear:MRT={:#x}:M={:#x}", col_buf.Address(),
col_buf.CmaskAddress()));
image.Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits2::eTransferWrite, {}); image.Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits2::eTransferWrite, {});
scheduler.CommandBuffer().clearColorImage(image.image, image.last_state.layout, scheduler.CommandBuffer().clearColorImage(image.image, image.last_state.layout,
LiverpoolToVK::ColorBufferClearValue(col_buf).color, LiverpoolToVK::ColorBufferClearValue(col_buf).color,
range); range);
ScopeMarkerEnd();
} }
void Rasterizer::Draw(bool is_indexed, u32 index_offset) { void Rasterizer::Draw(bool is_indexed, u32 index_offset) {
@ -822,8 +847,6 @@ void Rasterizer::BeginRendering(const GraphicsPipeline& pipeline, RenderState& s
} }
void Rasterizer::Resolve() { void Rasterizer::Resolve() {
const auto cmdbuf = scheduler.CommandBuffer();
// Read from MRT0, average all samples, and write to MRT1, which is one-sample // Read from MRT0, average all samples, and write to MRT1, which is one-sample
const auto& mrt0_hint = liverpool->last_cb_extent[0]; const auto& mrt0_hint = liverpool->last_cb_extent[0];
const auto& mrt1_hint = liverpool->last_cb_extent[1]; const auto& mrt1_hint = liverpool->last_cb_extent[1];
@ -843,9 +866,12 @@ void Rasterizer::Resolve() {
mrt1_range.base.layer = liverpool->regs.color_buffers[1].view.slice_start; mrt1_range.base.layer = liverpool->regs.color_buffers[1].view.slice_start;
mrt1_range.extent.layers = liverpool->regs.color_buffers[1].NumSlices() - mrt1_range.base.layer; mrt1_range.extent.layers = liverpool->regs.color_buffers[1].NumSlices() - mrt1_range.base.layer;
ScopeMarkerBegin(fmt::format("Resolve:MRT0={:#x}:MRT1={:#x}",
liverpool->regs.color_buffers[0].Address(),
liverpool->regs.color_buffers[1].Address()));
mrt0_image.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits2::eTransferRead, mrt0_image.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits2::eTransferRead,
mrt0_range); mrt0_range);
mrt1_image.Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits2::eTransferWrite, mrt1_image.Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits2::eTransferWrite,
mrt1_range); mrt1_range);
@ -872,8 +898,9 @@ void Rasterizer::Resolve() {
.dstOffset = {0, 0, 0}, .dstOffset = {0, 0, 0},
.extent = {mrt1_image.info.size.width, mrt1_image.info.size.height, 1}, .extent = {mrt1_image.info.size.width, mrt1_image.info.size.height, 1},
}; };
cmdbuf.copyImage(mrt0_image.image, vk::ImageLayout::eTransferSrcOptimal, mrt1_image.image, scheduler.CommandBuffer().copyImage(mrt0_image.image, vk::ImageLayout::eTransferSrcOptimal,
vk::ImageLayout::eTransferDstOptimal, region); mrt1_image.image, vk::ImageLayout::eTransferDstOptimal,
region);
} else { } else {
vk::ImageResolve region = { vk::ImageResolve region = {
.srcSubresource = .srcSubresource =
@ -894,9 +921,72 @@ void Rasterizer::Resolve() {
.dstOffset = {0, 0, 0}, .dstOffset = {0, 0, 0},
.extent = {mrt1_image.info.size.width, mrt1_image.info.size.height, 1}, .extent = {mrt1_image.info.size.width, mrt1_image.info.size.height, 1},
}; };
cmdbuf.resolveImage(mrt0_image.image, vk::ImageLayout::eTransferSrcOptimal, scheduler.CommandBuffer().resolveImage(
mrt1_image.image, vk::ImageLayout::eTransferDstOptimal, region); mrt0_image.image, vk::ImageLayout::eTransferSrcOptimal, mrt1_image.image,
vk::ImageLayout::eTransferDstOptimal, region);
} }
ScopeMarkerEnd();
}
void Rasterizer::DepthStencilCopy(bool is_depth, bool is_stencil) {
auto& regs = liverpool->regs;
auto read_desc = VideoCore::TextureCache::DepthTargetDesc(
regs.depth_buffer, regs.depth_view, regs.depth_control,
regs.depth_htile_data_base.GetAddress(), liverpool->last_db_extent, false);
auto write_desc = VideoCore::TextureCache::DepthTargetDesc(
regs.depth_buffer, regs.depth_view, regs.depth_control,
regs.depth_htile_data_base.GetAddress(), liverpool->last_db_extent, true);
auto& read_image = texture_cache.GetImage(texture_cache.FindImage(read_desc));
auto& write_image = texture_cache.GetImage(texture_cache.FindImage(write_desc));
VideoCore::SubresourceRange sub_range;
sub_range.base.layer = liverpool->regs.depth_view.slice_start;
sub_range.extent.layers = liverpool->regs.depth_view.NumSlices() - sub_range.base.layer;
ScopeMarkerBegin(fmt::format(
"DepthStencilCopy:DR={:#x}:SR={:#x}:DW={:#x}:SW={:#x}", regs.depth_buffer.DepthAddress(),
regs.depth_buffer.StencilAddress(), regs.depth_buffer.DepthWriteAddress(),
regs.depth_buffer.StencilWriteAddress()));
read_image.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits2::eTransferRead,
sub_range);
write_image.Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits2::eTransferWrite,
sub_range);
auto aspect_mask = vk::ImageAspectFlags(0);
if (is_depth) {
aspect_mask |= vk::ImageAspectFlagBits::eDepth;
}
if (is_stencil) {
aspect_mask |= vk::ImageAspectFlagBits::eStencil;
}
vk::ImageCopy region = {
.srcSubresource =
{
.aspectMask = aspect_mask,
.mipLevel = 0,
.baseArrayLayer = sub_range.base.layer,
.layerCount = sub_range.extent.layers,
},
.srcOffset = {0, 0, 0},
.dstSubresource =
{
.aspectMask = aspect_mask,
.mipLevel = 0,
.baseArrayLayer = sub_range.base.layer,
.layerCount = sub_range.extent.layers,
},
.dstOffset = {0, 0, 0},
.extent = {write_image.info.size.width, write_image.info.size.height, 1},
};
scheduler.CommandBuffer().copyImage(read_image.image, vk::ImageLayout::eTransferSrcOptimal,
write_image.image, vk::ImageLayout::eTransferDstOptimal,
region);
ScopeMarkerEnd();
} }
void Rasterizer::InlineData(VAddr address, const void* value, u32 num_bytes, bool is_gds) { void Rasterizer::InlineData(VAddr address, const void* value, u32 num_bytes, bool is_gds) {
@ -1122,42 +1212,43 @@ void Rasterizer::UpdateViewportScissorState() {
cmdbuf.setScissorWithCountEXT(scissors); cmdbuf.setScissorWithCountEXT(scissors);
} }
void Rasterizer::ScopeMarkerBegin(const std::string_view& str) { void Rasterizer::ScopeMarkerBegin(const std::string_view& str, bool from_guest) {
if (Config::nullGpu() || !Config::vkMarkersEnabled()) { if ((from_guest && !Config::vkGuestMarkersEnabled()) ||
(!from_guest && !Config::vkHostMarkersEnabled())) {
return; return;
} }
const auto cmdbuf = scheduler.CommandBuffer(); const auto cmdbuf = scheduler.CommandBuffer();
cmdbuf.beginDebugUtilsLabelEXT(vk::DebugUtilsLabelEXT{ cmdbuf.beginDebugUtilsLabelEXT(vk::DebugUtilsLabelEXT{
.pLabelName = str.data(), .pLabelName = str.data(),
}); });
} }
void Rasterizer::ScopeMarkerEnd() { void Rasterizer::ScopeMarkerEnd(bool from_guest) {
if (Config::nullGpu() || !Config::vkMarkersEnabled()) { if ((from_guest && !Config::vkGuestMarkersEnabled()) ||
(!from_guest && !Config::vkHostMarkersEnabled())) {
return; return;
} }
const auto cmdbuf = scheduler.CommandBuffer(); const auto cmdbuf = scheduler.CommandBuffer();
cmdbuf.endDebugUtilsLabelEXT(); cmdbuf.endDebugUtilsLabelEXT();
} }
void Rasterizer::ScopedMarkerInsert(const std::string_view& str) { void Rasterizer::ScopedMarkerInsert(const std::string_view& str, bool from_guest) {
if (Config::nullGpu() || !Config::vkMarkersEnabled()) { if ((from_guest && !Config::vkGuestMarkersEnabled()) ||
(!from_guest && !Config::vkHostMarkersEnabled())) {
return; return;
} }
const auto cmdbuf = scheduler.CommandBuffer(); const auto cmdbuf = scheduler.CommandBuffer();
cmdbuf.insertDebugUtilsLabelEXT(vk::DebugUtilsLabelEXT{ cmdbuf.insertDebugUtilsLabelEXT(vk::DebugUtilsLabelEXT{
.pLabelName = str.data(), .pLabelName = str.data(),
}); });
} }
void Rasterizer::ScopedMarkerInsertColor(const std::string_view& str, const u32 color) { void Rasterizer::ScopedMarkerInsertColor(const std::string_view& str, const u32 color,
if (Config::nullGpu() || !Config::vkMarkersEnabled()) { bool from_guest) {
if ((from_guest && !Config::vkGuestMarkersEnabled()) ||
(!from_guest && !Config::vkHostMarkersEnabled())) {
return; return;
} }
const auto cmdbuf = scheduler.CommandBuffer(); const auto cmdbuf = scheduler.CommandBuffer();
cmdbuf.insertDebugUtilsLabelEXT(vk::DebugUtilsLabelEXT{ cmdbuf.insertDebugUtilsLabelEXT(vk::DebugUtilsLabelEXT{
.pLabelName = str.data(), .pLabelName = str.data(),

View File

@ -47,10 +47,11 @@ public:
void DispatchDirect(); void DispatchDirect();
void DispatchIndirect(VAddr address, u32 offset, u32 size); void DispatchIndirect(VAddr address, u32 offset, u32 size);
void ScopeMarkerBegin(const std::string_view& str); void ScopeMarkerBegin(const std::string_view& str, bool from_guest = false);
void ScopeMarkerEnd(); void ScopeMarkerEnd(bool from_guest = false);
void ScopedMarkerInsert(const std::string_view& str); void ScopedMarkerInsert(const std::string_view& str, bool from_guest = false);
void ScopedMarkerInsertColor(const std::string_view& str, const u32 color); void ScopedMarkerInsertColor(const std::string_view& str, const u32 color,
bool from_guest = false);
void InlineData(VAddr address, const void* value, u32 num_bytes, bool is_gds); void InlineData(VAddr address, const void* value, u32 num_bytes, bool is_gds);
u32 ReadDataFromGds(u32 gsd_offset); u32 ReadDataFromGds(u32 gsd_offset);
@ -71,6 +72,7 @@ private:
RenderState PrepareRenderState(u32 mrt_mask); RenderState PrepareRenderState(u32 mrt_mask);
void BeginRendering(const GraphicsPipeline& pipeline, RenderState& state); void BeginRendering(const GraphicsPipeline& pipeline, RenderState& state);
void Resolve(); void Resolve();
void DepthStencilCopy(bool is_depth, bool is_stencil);
void EliminateFastClear(); void EliminateFastClear();
void UpdateDynamicState(const GraphicsPipeline& pipeline); void UpdateDynamicState(const GraphicsPipeline& pipeline);

View File

@ -73,10 +73,8 @@ CommandPool::CommandPool(const Instance& instance, MasterSemaphore* master_semap
ASSERT_MSG(pool_result == vk::Result::eSuccess, "Failed to create command pool: {}", ASSERT_MSG(pool_result == vk::Result::eSuccess, "Failed to create command pool: {}",
vk::to_string(pool_result)); vk::to_string(pool_result));
cmd_pool = std::move(pool); cmd_pool = std::move(pool);
if (instance.HasDebuggingToolAttached()) {
SetObjectName(device, *cmd_pool, "CommandPool"); SetObjectName(device, *cmd_pool, "CommandPool");
} }
}
CommandPool::~CommandPool() = default; CommandPool::~CommandPool() = default;
@ -94,12 +92,10 @@ void CommandPool::Allocate(std::size_t begin, std::size_t end) {
device.allocateCommandBuffers(&buffer_alloc_info, cmd_buffers.data() + begin); device.allocateCommandBuffers(&buffer_alloc_info, cmd_buffers.data() + begin);
ASSERT(result == vk::Result::eSuccess); ASSERT(result == vk::Result::eSuccess);
if (instance.HasDebuggingToolAttached()) {
for (std::size_t i = begin; i < end; ++i) { for (std::size_t i = begin; i < end; ++i) {
SetObjectName(device, cmd_buffers[i], "CommandPool: Command Buffer {}", i); SetObjectName(device, cmd_buffers[i], "CommandPool: Command Buffer {}", i);
} }
} }
}
vk::CommandBuffer CommandPool::Commit() { vk::CommandBuffer CommandPool::Commit() {
const std::size_t index = CommitResource(); const std::size_t index = CommitResource();

View File

@ -5,6 +5,7 @@
#include <limits> #include <limits>
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "imgui/renderer/imgui_core.h"
#include "sdl_window.h" #include "sdl_window.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_swapchain.h" #include "video_core/renderer_vulkan/vk_swapchain.h"
@ -14,7 +15,9 @@ namespace Vulkan {
Swapchain::Swapchain(const Instance& instance_, const Frontend::WindowSDL& window) Swapchain::Swapchain(const Instance& instance_, const Frontend::WindowSDL& window)
: instance{instance_}, surface{CreateSurface(instance.GetInstance(), window)} { : instance{instance_}, surface{CreateSurface(instance.GetInstance(), window)} {
FindPresentFormat(); FindPresentFormat();
Create(window.GetWidth(), window.GetHeight(), surface);
Create(window.GetWidth(), window.GetHeight());
ImGui::Core::Initialize(instance, window, image_count, view_format);
} }
Swapchain::~Swapchain() { Swapchain::~Swapchain() {
@ -22,10 +25,9 @@ Swapchain::~Swapchain() {
instance.GetInstance().destroySurfaceKHR(surface); instance.GetInstance().destroySurfaceKHR(surface);
} }
void Swapchain::Create(u32 width_, u32 height_, vk::SurfaceKHR surface_) { void Swapchain::Create(u32 width_, u32 height_) {
width = width_; width = width_;
height = height_; height = height_;
surface = surface_;
needs_recreation = false; needs_recreation = false;
Destroy(); Destroy();
@ -55,7 +57,17 @@ void Swapchain::Create(u32 width_, u32 height_, vk::SurfaceKHR surface_) {
const u32 queue_family_indices_count = exclusive ? 1u : 2u; const u32 queue_family_indices_count = exclusive ? 1u : 2u;
const vk::SharingMode sharing_mode = const vk::SharingMode sharing_mode =
exclusive ? vk::SharingMode::eExclusive : vk::SharingMode::eConcurrent; exclusive ? vk::SharingMode::eExclusive : vk::SharingMode::eConcurrent;
const vk::Format view_formats[2] = {
surface_format.format,
view_format,
};
const vk::ImageFormatListCreateInfo format_list = {
.viewFormatCount = 2,
.pViewFormats = view_formats,
};
const vk::SwapchainCreateInfoKHR swapchain_info = { const vk::SwapchainCreateInfoKHR swapchain_info = {
.pNext = &format_list,
.flags = vk::SwapchainCreateFlagBitsKHR::eMutableFormat,
.surface = surface, .surface = surface,
.minImageCount = image_count, .minImageCount = image_count,
.imageFormat = surface_format.format, .imageFormat = surface_format.format,
@ -85,7 +97,7 @@ void Swapchain::Create(u32 width_, u32 height_, vk::SurfaceKHR surface_) {
void Swapchain::Recreate(u32 width_, u32 height_) { void Swapchain::Recreate(u32 width_, u32 height_) {
LOG_DEBUG(Render_Vulkan, "Recreate the swapchain: width={} height={}", width_, height_); LOG_DEBUG(Render_Vulkan, "Recreate the swapchain: width={} height={}", width_, height_);
Create(width_, height_, surface); Create(width_, height_);
} }
bool Swapchain::AcquireNextImage() { bool Swapchain::AcquireNextImage() {
@ -147,6 +159,7 @@ void Swapchain::FindPresentFormat() {
if (formats[0].format == vk::Format::eUndefined) { if (formats[0].format == vk::Format::eUndefined) {
surface_format.format = vk::Format::eR8G8B8A8Srgb; surface_format.format = vk::Format::eR8G8B8A8Srgb;
surface_format.colorSpace = vk::ColorSpaceKHR::eSrgbNonlinear; surface_format.colorSpace = vk::ColorSpaceKHR::eSrgbNonlinear;
view_format = FormatToUnorm(surface_format.format);
return; return;
} }
@ -159,6 +172,7 @@ void Swapchain::FindPresentFormat() {
surface_format.format = format; surface_format.format = format;
surface_format.colorSpace = sformat.colorSpace; surface_format.colorSpace = sformat.colorSpace;
view_format = FormatToUnorm(surface_format.format);
return; return;
} }
@ -208,10 +222,14 @@ void Swapchain::Destroy() {
if (swapchain) { if (swapchain) {
device.destroySwapchainKHR(swapchain); device.destroySwapchainKHR(swapchain);
} }
for (u32 i = 0; i < image_count; i++) {
device.destroySemaphore(image_acquired[i]); for (const auto& sem : image_acquired) {
device.destroySemaphore(present_ready[i]); device.destroySemaphore(sem);
} }
for (const auto& sem : present_ready) {
device.destroySemaphore(sem);
}
image_acquired.clear(); image_acquired.clear();
present_ready.clear(); present_ready.clear();
} }
@ -235,13 +253,11 @@ void Swapchain::RefreshSemaphores() {
semaphore = sem; semaphore = sem;
} }
if (instance.HasDebuggingToolAttached()) {
for (u32 i = 0; i < image_count; ++i) { for (u32 i = 0; i < image_count; ++i) {
SetObjectName(device, image_acquired[i], "Swapchain Semaphore: image_acquired {}", i); SetObjectName(device, image_acquired[i], "Swapchain Semaphore: image_acquired {}", i);
SetObjectName(device, present_ready[i], "Swapchain Semaphore: present_ready {}", i); SetObjectName(device, present_ready[i], "Swapchain Semaphore: present_ready {}", i);
} }
} }
}
void Swapchain::SetupImages() { void Swapchain::SetupImages() {
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
@ -250,11 +266,30 @@ void Swapchain::SetupImages() {
vk::to_string(images_result)); vk::to_string(images_result));
images = std::move(imgs); images = std::move(imgs);
image_count = static_cast<u32>(images.size()); image_count = static_cast<u32>(images.size());
images_view.resize(image_count);
for (u32 i = 0; i < image_count; ++i) {
if (images_view[i]) {
device.destroyImageView(images_view[i]);
}
auto [im_view_result, im_view] = device.createImageView(vk::ImageViewCreateInfo{
.image = images[i],
.viewType = vk::ImageViewType::e2D,
.format = FormatToUnorm(surface_format.format),
.subresourceRange =
{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.levelCount = 1,
.layerCount = 1,
},
});
ASSERT_MSG(im_view_result == vk::Result::eSuccess, "Failed to create image view: {}",
vk::to_string(im_view_result));
images_view[i] = im_view;
}
if (instance.HasDebuggingToolAttached()) {
for (u32 i = 0; i < image_count; ++i) { for (u32 i = 0; i < image_count; ++i) {
SetObjectName(device, images[i], "Swapchain Image {}", i); SetObjectName(device, images[i], "Swapchain Image {}", i);
} SetObjectName(device, images_view[i], "Swapchain ImageView {}", i);
} }
} }

View File

@ -17,13 +17,24 @@ namespace Vulkan {
class Instance; class Instance;
class Scheduler; class Scheduler;
inline vk::Format FormatToUnorm(vk::Format fmt) {
switch (fmt) {
case vk::Format::eR8G8B8A8Srgb:
return vk::Format::eR8G8B8A8Unorm;
case vk::Format::eB8G8R8A8Srgb:
return vk::Format::eB8G8R8A8Unorm;
default:
UNREACHABLE();
}
}
class Swapchain { class Swapchain {
public: public:
explicit Swapchain(const Instance& instance, const Frontend::WindowSDL& window); explicit Swapchain(const Instance& instance, const Frontend::WindowSDL& window);
~Swapchain(); ~Swapchain();
/// Creates (or recreates) the swapchain with a given size. /// Creates (or recreates) the swapchain with a given size.
void Create(u32 width, u32 height, vk::SurfaceKHR surface); void Create(u32 width, u32 height);
/// Recreates the swapchain with a given size and current surface. /// Recreates the swapchain with a given size and current surface.
void Recreate(u32 width, u32 height); void Recreate(u32 width, u32 height);
@ -42,10 +53,18 @@ public:
return images[image_index]; return images[image_index];
} }
vk::ImageView ImageView() const {
return images_view[image_index];
}
vk::SurfaceFormatKHR GetSurfaceFormat() const { vk::SurfaceFormatKHR GetSurfaceFormat() const {
return surface_format; return surface_format;
} }
vk::Format GetViewFormat() const {
return view_format;
}
vk::SwapchainKHR GetHandle() const { vk::SwapchainKHR GetHandle() const {
return swapchain; return swapchain;
} }
@ -99,10 +118,12 @@ private:
vk::SwapchainKHR swapchain{}; vk::SwapchainKHR swapchain{};
vk::SurfaceKHR surface{}; vk::SurfaceKHR surface{};
vk::SurfaceFormatKHR surface_format; vk::SurfaceFormatKHR surface_format;
vk::Format view_format;
vk::Extent2D extent; vk::Extent2D extent;
vk::SurfaceTransformFlagBitsKHR transform; vk::SurfaceTransformFlagBitsKHR transform;
vk::CompositeAlphaFlagBitsKHR composite_alpha; vk::CompositeAlphaFlagBitsKHR composite_alpha;
std::vector<vk::Image> images; std::vector<vk::Image> images;
std::vector<vk::ImageView> images_view;
std::vector<vk::Semaphore> image_acquired; std::vector<vk::Semaphore> image_acquired;
std::vector<vk::Semaphore> present_ready; std::vector<vk::Semaphore> present_ready;
u32 width = 0; u32 width = 0;

View File

@ -98,7 +98,8 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer,
} }
ImageInfo::ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer, u32 num_slices, ImageInfo::ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer, u32 num_slices,
VAddr htile_address, const AmdGpu::Liverpool::CbDbExtent& hint) noexcept { VAddr htile_address, const AmdGpu::Liverpool::CbDbExtent& hint,
bool write_buffer) noexcept {
props.is_tiled = false; props.is_tiled = false;
pixel_format = LiverpoolToVK::DepthFormat(buffer.z_info.format, buffer.stencil_info.format); pixel_format = LiverpoolToVK::DepthFormat(buffer.z_info.format, buffer.stencil_info.format);
type = vk::ImageType::e2D; type = vk::ImageType::e2D;
@ -111,10 +112,10 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer, u32 num_slice
resources.layers = num_slices; resources.layers = num_slices;
meta_info.htile_addr = buffer.z_info.tile_surface_en ? htile_address : 0; meta_info.htile_addr = buffer.z_info.tile_surface_en ? htile_address : 0;
stencil_addr = buffer.StencilAddress(); stencil_addr = write_buffer ? buffer.StencilWriteAddress() : buffer.StencilAddress();
stencil_size = pitch * size.height * sizeof(u8); stencil_size = pitch * size.height * sizeof(u8);
guest_address = buffer.Address(); guest_address = write_buffer ? buffer.DepthWriteAddress() : buffer.DepthAddress();
const auto depth_slice_sz = buffer.GetDepthSliceSize(); const auto depth_slice_sz = buffer.GetDepthSliceSize();
guest_size = depth_slice_sz * num_slices; guest_size = depth_slice_sz * num_slices;
mips_layout.emplace_back(depth_slice_sz, pitch, 0); mips_layout.emplace_back(depth_slice_sz, pitch, 0);

View File

@ -19,7 +19,7 @@ struct ImageInfo {
ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer, ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer,
const AmdGpu::Liverpool::CbDbExtent& hint = {}) noexcept; const AmdGpu::Liverpool::CbDbExtent& hint = {}) noexcept;
ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer, u32 num_slices, VAddr htile_address, ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer, u32 num_slices, VAddr htile_address,
const AmdGpu::Liverpool::CbDbExtent& hint = {}) noexcept; const AmdGpu::Liverpool::CbDbExtent& hint = {}, bool write_buffer = false) noexcept;
ImageInfo(const AmdGpu::Image& image, const Shader::ImageResource& desc) noexcept; ImageInfo(const AmdGpu::Image& image, const Shader::ImageResource& desc) noexcept;
bool IsTiled() const { bool IsTiled() const {

View File

@ -82,13 +82,12 @@ ImageView::ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info
vk::Format format = info.format; vk::Format format = info.format;
vk::ImageAspectFlags aspect = image.aspect_mask; vk::ImageAspectFlags aspect = image.aspect_mask;
if (image.aspect_mask & vk::ImageAspectFlagBits::eDepth && if (image.aspect_mask & vk::ImageAspectFlagBits::eDepth &&
(format == vk::Format::eR32Sfloat || format == vk::Format::eD32Sfloat || Vulkan::LiverpoolToVK::IsFormatDepthCompatible(format)) {
format == vk::Format::eR16Unorm || format == vk::Format::eD16Unorm)) {
format = image.info.pixel_format; format = image.info.pixel_format;
aspect = vk::ImageAspectFlagBits::eDepth; aspect = vk::ImageAspectFlagBits::eDepth;
} }
if (image.aspect_mask & vk::ImageAspectFlagBits::eStencil && if (image.aspect_mask & vk::ImageAspectFlagBits::eStencil &&
(format == vk::Format::eR8Uint || format == vk::Format::eR8Unorm)) { Vulkan::LiverpoolToVK::IsFormatStencilCompatible(format)) {
format = image.info.pixel_format; format = image.info.pixel_format;
aspect = vk::ImageAspectFlagBits::eStencil; aspect = vk::ImageAspectFlagBits::eStencil;
} }
@ -111,6 +110,13 @@ ImageView::ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info
ASSERT_MSG(view_result == vk::Result::eSuccess, "Failed to create image view: {}", ASSERT_MSG(view_result == vk::Result::eSuccess, "Failed to create image view: {}",
vk::to_string(view_result)); vk::to_string(view_result));
image_view = std::move(view); image_view = std::move(view);
const auto view_aspect = aspect & vk::ImageAspectFlagBits::eDepth ? "Depth"
: aspect & vk::ImageAspectFlagBits::eStencil ? "Stencil"
: "Color";
Vulkan::SetObjectName(instance.GetDevice(), *image_view, "ImageView {}x{}x{} {:#x}:{:#x} ({})",
image.info.size.width, image.info.size.height, image.info.size.depth,
image.info.guest_address, image.info.guest_size, view_aspect);
} }
ImageView::~ImageView() = default; ImageView::~ImageView() = default;

View File

@ -79,9 +79,9 @@ public:
DepthTargetDesc(const AmdGpu::Liverpool::DepthBuffer& buffer, DepthTargetDesc(const AmdGpu::Liverpool::DepthBuffer& buffer,
const AmdGpu::Liverpool::DepthView& view, const AmdGpu::Liverpool::DepthView& view,
const AmdGpu::Liverpool::DepthControl& ctl, VAddr htile_address, const AmdGpu::Liverpool::DepthControl& ctl, VAddr htile_address,
const AmdGpu::Liverpool::CbDbExtent& hint = {}) const AmdGpu::Liverpool::CbDbExtent& hint = {}, bool write_buffer = false)
: BaseDesc{BindingType::DepthTarget, : BaseDesc{BindingType::DepthTarget,
ImageInfo{buffer, view.NumSlices(), htile_address, hint}, ImageInfo{buffer, view.NumSlices(), htile_address, hint, write_buffer},
ImageViewInfo{buffer, view, ctl}} {} ImageViewInfo{buffer, view, ctl}} {}
}; };