shadPS4/src/core/devtools/widget/common.h
Vinicius Rangel 0835dc71b3
More devtools stuff (#1637)
* devtools: memory map viewer

* devtools: batch highlight only for non-group viewer

* devtools: fix not showing entire user data

* devtools: shader debug viewer

* devtools: add more reg naming
2024-12-01 19:34:29 +01:00

166 lines
No EOL
4.4 KiB
C++

// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <filesystem>
#include <string>
#include <type_traits>
#include <variant>
#include <magic_enum.hpp>
#include "common/bit_field.h"
#include "common/io_file.h"
#include "common/types.h"
#include "core/debug_state.h"
#include "video_core/amdgpu/pm4_opcodes.h"
#if defined(_WIN32)
#define popen _popen
#define pclose _pclose
#endif
namespace Core::Devtools::Widget {
/*
* Generic PM4 header
*/
union PM4Header {
struct {
u32 reserved : 16;
u32 count : 14;
u32 type : 2; // PM4_TYPE
};
u32 u32All;
};
struct PushMarker {
std::string name{};
};
struct PopMarker {};
struct BatchBegin {
u32 id;
};
struct BatchInfo {
u32 id;
std::string marker{};
size_t start_addr;
size_t end_addr;
size_t command_addr;
AmdGpu::PM4ItOpcode type;
bool bypass{false};
};
using GPUEvent = std::variant<PushMarker, PopMarker, BatchBegin, BatchInfo>;
template <typename... Args>
void DrawRow(const char* text, const char* fmt, Args... args) {
ImGui::TableNextColumn();
ImGui::TextUnformatted(text);
ImGui::TableNextColumn();
char buf[128];
snprintf(buf, sizeof(buf), fmt, args...);
ImGui::TextUnformatted(buf);
}
template <typename T>
void DrawValueRow(const char* text, T value) {
if constexpr (std::is_enum_v<T>) {
return DrawRow(text, "%X (%s)", value, magic_enum::enum_name(value).data());
} else if constexpr (std::is_integral_v<T>) {
return DrawRow(text, "%X", value);
} else if constexpr (std::is_base_of_v<BitField<T::position, T::bits, typename T::Type>, T>) {
return DrawValueRow(text, value.Value());
} else {
static_assert(false, "Unsupported type");
}
}
template <typename V, typename... Extra>
void DrawValueRowList(const char* text, V arg, Extra&&... extra_args) {
DrawValueRow(text, arg);
if constexpr (sizeof...(extra_args) > 0) {
DrawValueRowList(std::forward<Extra>(extra_args)...);
}
}
template <typename... Args>
static void DoTooltip(const char* str_id, Args&&... args) {
if (ImGui::BeginTooltip()) {
if (ImGui::BeginTable(str_id, 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
DrawMultipleRow(std::forward<Args>(args)...);
ImGui::EndTable();
}
ImGui::EndTooltip();
}
}
static bool IsDrawCall(AmdGpu::PM4ItOpcode opcode) {
using AmdGpu::PM4ItOpcode;
switch (opcode) {
case PM4ItOpcode::DrawIndex2:
case PM4ItOpcode::DrawIndexOffset2:
case PM4ItOpcode::DrawIndexAuto:
case PM4ItOpcode::DrawIndirect:
case PM4ItOpcode::DrawIndexIndirect:
case PM4ItOpcode::DispatchDirect:
case PM4ItOpcode::DispatchIndirect:
return true;
default:
return false;
}
}
inline std::optional<std::string> exec_cli(const char* cli) {
std::array<char, 64> buffer{};
std::string output;
const auto f = popen(cli, "r");
if (!f) {
pclose(f);
return {};
}
while (fgets(buffer.data(), buffer.size(), f)) {
output += buffer.data();
}
pclose(f);
return output;
}
inline std::string RunDisassembler(const std::string& disassembler_cli,
const std::vector<u32>& shader_code) {
std::string shader_dis;
if (disassembler_cli.empty()) {
shader_dis = "No disassembler set";
} else {
auto bin_path = std::filesystem::temp_directory_path() / "shadps4_tmp_shader.bin";
constexpr std::string_view src_arg = "{src}";
std::string cli = disassembler_cli;
const auto pos = cli.find(src_arg);
if (pos == std::string::npos) {
DebugState.ShowDebugMessage("Disassembler CLI does not contain {src} argument\n" +
disassembler_cli);
} else {
cli.replace(pos, src_arg.size(), "\"" + bin_path.string() + "\"");
Common::FS::IOFile file(bin_path, Common::FS::FileAccessMode::Write);
file.Write(shader_code);
file.Close();
auto result = exec_cli(cli.c_str());
shader_dis = result.value_or("Could not disassemble shader");
if (shader_dis.empty()) {
shader_dis = "Disassembly empty or failed";
}
std::filesystem::remove(bin_path);
}
}
return shader_dis;
}
} // namespace Core::Devtools::Widget