mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-08-19 06:52:36 +00:00
4157 lines
138 KiB
C++
4157 lines
138 KiB
C++
#include "libs/agc.h"
|
|
|
|
#include "common/assert.h"
|
|
#include "common/emulatorConfig.h"
|
|
#include "common/file.h"
|
|
#include "common/logging/log.h"
|
|
#include "common/stringUtils.h"
|
|
#include "common/virtualMemory.h"
|
|
#include "graphics/guest_gpu/command_processor/commandProcessor.h"
|
|
#include "graphics/guest_gpu/gpu_defs.h"
|
|
#include "graphics/guest_gpu/graphicsRun.h"
|
|
#include "graphics/guest_gpu/hardwareContext.h"
|
|
#include "graphics/guest_gpu/pm4.h"
|
|
#include "graphics/guest_gpu/tile.h"
|
|
#include "graphics/host_gpu/renderer/render.h"
|
|
#include "graphics/host_gpu/renderer/renderContext.h"
|
|
#include "graphics/host_gpu/renderer/sync.h"
|
|
#include "graphics/presentation/presenter.h"
|
|
#include "graphics/presentation/renderDoc.h"
|
|
#include "graphics/presentation/videoOut.h"
|
|
#include "graphics/presentation/window.h"
|
|
#include "graphics/shader/shader.h"
|
|
#include "kernel/pthread.h"
|
|
#include "libs/errno.h"
|
|
#include "libs/libs.h"
|
|
|
|
#include <algorithm>
|
|
#include <atomic>
|
|
#include <cmath>
|
|
#include <cstddef>
|
|
#include <cstring>
|
|
#include <mutex>
|
|
#include <vector>
|
|
|
|
#ifdef min
|
|
#undef min
|
|
#endif
|
|
#ifdef max
|
|
#undef max
|
|
#endif
|
|
|
|
namespace Libs::Graphics {
|
|
|
|
static RenderContext* g_renderer = nullptr;
|
|
|
|
KYTY_SUBSYSTEM_INIT(Graphics) {
|
|
// Some games lock up if this is not called first
|
|
if (Config::RenderDocEnabled()) {
|
|
RenderDocInit();
|
|
}
|
|
|
|
auto width = Config::GetScreenWidth();
|
|
auto height = Config::GetScreenHeight();
|
|
|
|
auto& presenter = WindowInit(width, height);
|
|
auto& video_out = VideoOut::VideoOutInit(width, height, presenter);
|
|
g_renderer = &presenter.Renderer();
|
|
g_renderer->InitializeGpu(&video_out);
|
|
ShaderInit();
|
|
}
|
|
|
|
KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Graphics) {}
|
|
|
|
KYTY_SUBSYSTEM_DESTROY(Graphics) {
|
|
EXIT_IF(g_renderer == nullptr);
|
|
g_renderer->ShutdownGpu();
|
|
VideoOut::VideoOutShutdown();
|
|
WindowShutdown();
|
|
g_renderer = nullptr;
|
|
}
|
|
|
|
void GraphicsDbgDumpDcb(const char* type, uint32_t num_dw, uint32_t* cmd_buffer) {
|
|
EXIT_IF(type == nullptr);
|
|
|
|
static std::atomic_int id = 0;
|
|
|
|
if (Config::CommandBufferDumpEnabled() && num_dw > 0 && cmd_buffer != nullptr) {
|
|
Common::File f;
|
|
auto file_name = Config::GetCommandBufferDumpFolder() /
|
|
fmt::format("{:04d}_{:04d}_buffer_{}.log",
|
|
g_renderer->GetGpu().GetFrameNum(), id++, type);
|
|
Common::File::CreateDirectories(file_name.parent_path());
|
|
f.Create(file_name);
|
|
if (f.IsInvalid()) {
|
|
auto file_name_text = Common::PathToString(file_name);
|
|
LOGF_COLOR(Log::Color::BrightRed, "Can't create file: %s\n", file_name_text.c_str());
|
|
return;
|
|
}
|
|
Pm4::DumpPm4PacketStream(&f, cmd_buffer, 0, num_dw);
|
|
f.Close();
|
|
}
|
|
}
|
|
|
|
namespace Gen5 {
|
|
|
|
LIB_NAME("Graphics5", "Graphics5");
|
|
|
|
struct RegisterDefaults {
|
|
ShaderRegister** tbl0 = nullptr;
|
|
ShaderRegister** tbl1 = nullptr;
|
|
ShaderRegister** tbl2 = nullptr;
|
|
ShaderRegister** tbl3 = nullptr;
|
|
uint32_t tbl0_register_count = 0;
|
|
uint32_t tbl1_register_count = 0;
|
|
uint32_t tbl2_register_count = 0;
|
|
uint32_t tbl3_register_count = 0;
|
|
uint32_t* types = nullptr;
|
|
uint32_t count = 0;
|
|
};
|
|
|
|
static_assert(offsetof(RegisterDefaults, count) == 0x38);
|
|
|
|
struct CompactRegisterDefaults {
|
|
ShaderRegister* tbl0_regs = nullptr;
|
|
uint32_t tbl0_register_count = 0;
|
|
const uint16_t* tbl0_pointer_offsets = nullptr;
|
|
uint32_t tbl0_pointer_count = 0;
|
|
ShaderRegister* tbl1_regs = nullptr;
|
|
uint32_t tbl1_register_count = 0;
|
|
const uint16_t* tbl1_pointer_offsets = nullptr;
|
|
uint32_t tbl1_pointer_count = 0;
|
|
ShaderRegister* tbl2_regs = nullptr;
|
|
uint32_t tbl2_register_count = 0;
|
|
const uint16_t* tbl2_pointer_offsets = nullptr;
|
|
uint32_t tbl2_pointer_count = 0;
|
|
ShaderRegister* tbl3_regs = nullptr;
|
|
uint32_t tbl3_register_count = 0;
|
|
const uint16_t* tbl3_pointer_offsets = nullptr;
|
|
uint32_t tbl3_pointer_count = 0;
|
|
uint32_t* types = nullptr;
|
|
uint32_t count = 0;
|
|
};
|
|
|
|
struct RegisterDefaultsStorage {
|
|
RegisterDefaults defaults;
|
|
std::vector<ShaderRegister*> tbl0;
|
|
std::vector<ShaderRegister*> tbl1;
|
|
std::vector<ShaderRegister*> tbl2;
|
|
std::vector<ShaderRegister*> tbl3;
|
|
bool initialized = false;
|
|
};
|
|
|
|
#include "libs/agcRegisterDefaults.inc"
|
|
|
|
#include <fmt/format.h>
|
|
|
|
static constexpr uint32_t GRAPHICS_REGISTER_DEFAULTS_MAX_VERSION = 12;
|
|
static constexpr uint32_t GRAPHICS_REGISTER_DEFAULTS_FALLBACK_VERSION = 11;
|
|
static constexpr uint32_t GRAPHICS_INIT_NO_FEATURE_STATE = 0;
|
|
|
|
static std::mutex g_register_defaults_mutex;
|
|
|
|
static ShaderRegister** init_register_default_pointer_table(std::vector<ShaderRegister*>* table,
|
|
ShaderRegister* regs,
|
|
uint32_t register_count,
|
|
const uint16_t* offsets,
|
|
uint32_t pointer_count) {
|
|
EXIT_IF(table == nullptr);
|
|
|
|
table->clear();
|
|
if (pointer_count == 0) {
|
|
return nullptr;
|
|
}
|
|
|
|
EXIT_IF(regs == nullptr);
|
|
EXIT_IF(offsets == nullptr);
|
|
|
|
table->resize(pointer_count);
|
|
for (uint32_t i = 0; i < pointer_count; i++) {
|
|
EXIT_IF(offsets[i] >= register_count);
|
|
(*table)[i] = regs + offsets[i];
|
|
}
|
|
|
|
return table->data();
|
|
}
|
|
|
|
static RegisterDefaults* get_register_defaults(CompactRegisterDefaults* compact,
|
|
RegisterDefaultsStorage* storage) {
|
|
EXIT_IF(compact == nullptr);
|
|
EXIT_IF(storage == nullptr);
|
|
|
|
std::lock_guard lock(g_register_defaults_mutex);
|
|
if (!storage->initialized) {
|
|
storage->defaults.tbl0 = init_register_default_pointer_table(
|
|
&storage->tbl0, compact->tbl0_regs, compact->tbl0_register_count,
|
|
compact->tbl0_pointer_offsets, compact->tbl0_pointer_count);
|
|
storage->defaults.tbl1 = init_register_default_pointer_table(
|
|
&storage->tbl1, compact->tbl1_regs, compact->tbl1_register_count,
|
|
compact->tbl1_pointer_offsets, compact->tbl1_pointer_count);
|
|
storage->defaults.tbl2 = init_register_default_pointer_table(
|
|
&storage->tbl2, compact->tbl2_regs, compact->tbl2_register_count,
|
|
compact->tbl2_pointer_offsets, compact->tbl2_pointer_count);
|
|
storage->defaults.tbl3 = init_register_default_pointer_table(
|
|
&storage->tbl3, compact->tbl3_regs, compact->tbl3_register_count,
|
|
compact->tbl3_pointer_offsets, compact->tbl3_pointer_count);
|
|
storage->defaults.tbl0_register_count = compact->tbl0_register_count;
|
|
storage->defaults.tbl1_register_count = compact->tbl1_register_count;
|
|
storage->defaults.tbl2_register_count = compact->tbl2_register_count;
|
|
storage->defaults.tbl3_register_count = compact->tbl3_register_count;
|
|
storage->defaults.types = compact->types;
|
|
storage->defaults.count = compact->count;
|
|
storage->initialized = true;
|
|
}
|
|
|
|
return &storage->defaults;
|
|
}
|
|
|
|
static uint32_t normalize_register_defaults_version(uint32_t ver) {
|
|
return ver <= GRAPHICS_REGISTER_DEFAULTS_MAX_VERSION
|
|
? ver
|
|
: GRAPHICS_REGISTER_DEFAULTS_FALLBACK_VERSION;
|
|
}
|
|
|
|
static RegisterDefaults* get_public_register_defaults(uint32_t ver) {
|
|
static RegisterDefaultsStorage storage[GRAPHICS_REGISTER_DEFAULTS_MAX_VERSION + 1] = {};
|
|
const auto index = normalize_register_defaults_version(ver);
|
|
return get_register_defaults(g_agc_public_reg_defaults_by_version[index], &storage[index]);
|
|
}
|
|
|
|
static RegisterDefaults* get_internal_register_defaults(uint32_t ver) {
|
|
static RegisterDefaultsStorage storage[GRAPHICS_REGISTER_DEFAULTS_MAX_VERSION + 1] = {};
|
|
const auto index = normalize_register_defaults_version(ver);
|
|
return get_register_defaults(g_agc_internal_reg_defaults_by_version[index], &storage[index]);
|
|
}
|
|
|
|
struct CommandBuffer {
|
|
using Callback = KYTY_SYSV_ABI bool (*)(CommandBuffer*, uint32_t, void*);
|
|
|
|
uint32_t* bottom;
|
|
uint32_t* top;
|
|
uint32_t* cursor_up;
|
|
uint32_t* cursor_down;
|
|
Callback callback;
|
|
void* user_data;
|
|
uint32_t reserved_dw;
|
|
|
|
void DbgDump() const {
|
|
if (!Config::GraphicsDebugDumpEnabled() ||
|
|
Config::GetPrintfDirection() == Config::OutputDirection::Silent) {
|
|
return;
|
|
}
|
|
static std::atomic<uint32_t> log_count {0};
|
|
if (log_count.fetch_add(1) >= 64) {
|
|
return;
|
|
}
|
|
|
|
LOGF("\t bottom = 0x%016" PRIx64 "\n"
|
|
"\t top = 0x%016" PRIx64 "\n"
|
|
"\t cursor_up = 0x%016" PRIx64 "\n"
|
|
"\t cursor_down = 0x%016" PRIx64 "\n"
|
|
"\t callback = 0x%016" PRIx64 "\n"
|
|
"\t user_data = 0x%016" PRIx64 "\n"
|
|
"\t reserved_dw = %" PRIu32 "\n",
|
|
reinterpret_cast<uint64_t>(bottom), reinterpret_cast<uint64_t>(top),
|
|
reinterpret_cast<uint64_t>(cursor_up), reinterpret_cast<uint64_t>(cursor_down),
|
|
reinterpret_cast<uint64_t>(callback), reinterpret_cast<uint64_t>(user_data),
|
|
reserved_dw);
|
|
}
|
|
|
|
[[nodiscard]] KYTY_SYSV_ABI uint32_t GetAvailableSizeDW() const {
|
|
if (cursor_up == nullptr || cursor_down == nullptr || cursor_down <= cursor_up) {
|
|
return 0;
|
|
}
|
|
|
|
auto available = static_cast<uint64_t>(cursor_down - cursor_up);
|
|
if (available <= reserved_dw) {
|
|
return 0;
|
|
}
|
|
if (available - reserved_dw > UINT32_MAX) {
|
|
LOGF_COLOR(
|
|
Log::Color::Red,
|
|
"\t command buffer has suspiciously large free space: cursor_up = 0x%016" PRIx64
|
|
", cursor_down = 0x%016" PRIx64 ", reserved_dw = %" PRIu32 "\n",
|
|
reinterpret_cast<uint64_t>(cursor_up), reinterpret_cast<uint64_t>(cursor_down),
|
|
reserved_dw);
|
|
return UINT32_MAX;
|
|
}
|
|
return static_cast<uint32_t>(available - reserved_dw);
|
|
}
|
|
|
|
KYTY_SYSV_ABI bool ReserveDW(uint32_t num_dw) {
|
|
uint32_t remaining = GetAvailableSizeDW();
|
|
if (num_dw > remaining) {
|
|
if (callback == nullptr) {
|
|
LOGF_COLOR(
|
|
Log::Color::Red,
|
|
"\t command buffer exhausted and has no grow callback: requested = %" PRIu32
|
|
", remaining = %" PRIu32 ", reserved_dw = %" PRIu32 "\n",
|
|
num_dw, remaining, reserved_dw);
|
|
DbgDump();
|
|
return false;
|
|
}
|
|
|
|
bool result = callback(this, num_dw + reserved_dw, user_data);
|
|
if (!result) {
|
|
LOGF_COLOR(Log::Color::Red,
|
|
"\t command buffer grow callback failed: requested = %" PRIu32
|
|
", remaining = %" PRIu32 ", reserved_dw = %" PRIu32 "\n",
|
|
num_dw, remaining, reserved_dw);
|
|
DbgDump();
|
|
return false;
|
|
}
|
|
if (GetAvailableSizeDW() < num_dw) {
|
|
LOGF_COLOR(Log::Color::Red,
|
|
"\t command buffer grow callback did not provide enough space: "
|
|
"requested = %" PRIu32 ", remaining = %" PRIu32
|
|
", reserved_dw = %" PRIu32 "\n",
|
|
num_dw, GetAvailableSizeDW(), reserved_dw);
|
|
DbgDump();
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
KYTY_SYSV_ABI uint32_t* AllocateDW(uint32_t size_dw) {
|
|
if (size_dw == 0 || !ReserveDW(size_dw)) {
|
|
LOGF_COLOR(Log::Color::Red,
|
|
"\t command buffer AllocateDW failed: size_dw = %" PRIu32 "\n", size_dw);
|
|
return nullptr;
|
|
}
|
|
auto* ret_ptr = cursor_up;
|
|
cursor_up += size_dw;
|
|
return ret_ptr;
|
|
}
|
|
};
|
|
|
|
struct Label {
|
|
volatile uint64_t m_value;
|
|
uint64_t m_reserved[3];
|
|
};
|
|
|
|
int KYTY_SYSV_ABI GraphicsInit(uint32_t* state, uint32_t ver) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t state = 0x%016" PRIx64 "\n"
|
|
"\t ver = %u\n",
|
|
reinterpret_cast<uint64_t>(state), ver);
|
|
|
|
if (state == nullptr) {
|
|
LOGF_COLOR(Log::Color::Red, "\t state is null\n");
|
|
return OK;
|
|
}
|
|
|
|
if (ver > GRAPHICS_REGISTER_DEFAULTS_MAX_VERSION) {
|
|
LOGF_COLOR(Log::Color::Red, "\t unsupported version %u\n", ver);
|
|
}
|
|
|
|
printf("version = %u\n", ver);
|
|
|
|
state[0] = ver;
|
|
state[1] = GRAPHICS_INIT_NO_FEATURE_STATE;
|
|
|
|
return OK;
|
|
}
|
|
|
|
void* KYTY_SYSV_ABI GraphicsGetRegisterDefaults2(uint32_t ver) {
|
|
PRINT_NAME();
|
|
|
|
if (ver > GRAPHICS_REGISTER_DEFAULTS_MAX_VERSION) {
|
|
LOGF_COLOR(Log::Color::Red, "\t unsupported version %u\n", ver);
|
|
}
|
|
return get_public_register_defaults(ver);
|
|
}
|
|
|
|
void* KYTY_SYSV_ABI GraphicsGetRegisterDefaults2Internal(uint32_t ver) {
|
|
PRINT_NAME();
|
|
|
|
if (ver > GRAPHICS_REGISTER_DEFAULTS_MAX_VERSION) {
|
|
LOGF_COLOR(Log::Color::Red, "\t unsupported version %u\n", ver);
|
|
}
|
|
return get_internal_register_defaults(ver);
|
|
}
|
|
|
|
static void dbg_dump_shader(const Shader* h) {
|
|
LOGF("\t file_header = 0x%08" PRIx32 "\n"
|
|
"\t version = 0x%08" PRIx32 "\n"
|
|
"\t user_data = 0x%016" PRIx64 "\n",
|
|
h->file_header, h->version, reinterpret_cast<uint64_t>(h->user_data));
|
|
if (h->user_data != nullptr) {
|
|
LOGF("\t\t direct_resource_count = 0x%04" PRIx16 "\n"
|
|
"\t\t direct_resource_offset = 0x%016" PRIx64 "\n",
|
|
h->user_data->direct_resource_count,
|
|
reinterpret_cast<uint64_t>(h->user_data->direct_resource_offset));
|
|
for (int i = 0; i < static_cast<int>(h->user_data->direct_resource_count); i++) {
|
|
LOGF("\t\t\t offset[%02d] = %04" PRIx16 "\n", i,
|
|
h->user_data->direct_resource_offset[i]);
|
|
}
|
|
for (int imm = 0; imm < 4; imm++) {
|
|
LOGF("\t\t sharp_resource_count [%d] = 0x%04" PRIx16 "\n", imm,
|
|
h->user_data->sharp_resource_count[imm]);
|
|
LOGF("\t\t sharp_resource_offset [%d] = 0x%016" PRIx64 "\n", imm,
|
|
reinterpret_cast<uint64_t>(h->user_data->sharp_resource_offset[imm]));
|
|
for (int i = 0; i < static_cast<int>(h->user_data->sharp_resource_count[imm]); i++) {
|
|
LOGF("\t\t\t offset_dw[%d] = %04" PRIx16 ", size = %" PRIu16 "\n", i,
|
|
static_cast<uint16_t>(h->user_data->sharp_resource_offset[imm][i].offset_dw),
|
|
static_cast<uint16_t>(h->user_data->sharp_resource_offset[imm][i].size));
|
|
}
|
|
}
|
|
LOGF("\t\t eud_size_dw = 0x%04" PRIx16 "\n"
|
|
"\t\t srt_size_dw = 0x%04" PRIx16 "\n",
|
|
h->user_data->eud_size_dw, h->user_data->srt_size_dw);
|
|
}
|
|
LOGF("\t code = 0x%016" PRIx64 "\n"
|
|
"\t num_cx_registers = 0x%02" PRIx8 "\n"
|
|
"\t cx_registers = 0x%016" PRIx64 "\n",
|
|
reinterpret_cast<uint64_t>(h->code), h->num_cx_registers,
|
|
reinterpret_cast<uint64_t>(h->cx_registers));
|
|
for (int i = 0; i < static_cast<int>(h->num_cx_registers); i++) {
|
|
LOGF("\t\t cx[%d]: offset = %08" PRIx32 ", value = %08" PRIx32 "\n", i,
|
|
h->cx_registers[i].offset, h->cx_registers[i].value);
|
|
}
|
|
LOGF("\t num_sh_registers = 0x%02" PRIx8 "\n"
|
|
"\t sh_registers = 0x%016" PRIx64 "\n",
|
|
h->num_sh_registers, reinterpret_cast<uint64_t>(h->sh_registers));
|
|
for (int i = 0; i < static_cast<int>(h->num_sh_registers); i++) {
|
|
LOGF("\t\t sh[%d]: offset = %08" PRIx32 ", value = %08" PRIx32 "\n", i,
|
|
h->sh_registers[i].offset, h->sh_registers[i].value);
|
|
}
|
|
LOGF("\t specials = 0x%016" PRIx64 "\n",
|
|
reinterpret_cast<uint64_t>(h->specials));
|
|
LOGF("\t\t ge_cntl: offset = %08" PRIx32 ", value = %08" PRIx32 "\n",
|
|
h->specials->ge_cntl.offset, h->specials->ge_cntl.value);
|
|
LOGF("\t\t vgt_shader_stages_en: offset = %08" PRIx32 ", value = %08" PRIx32 "\n",
|
|
h->specials->vgt_shader_stages_en.offset, h->specials->vgt_shader_stages_en.value);
|
|
LOGF("\t\t vgt_gs_out_prim_type: offset = %08" PRIx32 ", value = %08" PRIx32 "\n",
|
|
h->specials->vgt_gs_out_prim_type.offset, h->specials->vgt_gs_out_prim_type.value);
|
|
LOGF("\t\t ge_user_vgpr_en: offset = %08" PRIx32 ", value = %08" PRIx32 "\n",
|
|
h->specials->ge_user_vgpr_en.offset, h->specials->ge_user_vgpr_en.value);
|
|
LOGF("\t\t dispatch_modifier = %08" PRIx32 "\n", h->specials->dispatch_modifier);
|
|
LOGF("\t\t user_data_range: start = %08" PRIx32 ", end = %08" PRIx32 "\n",
|
|
h->specials->user_data_range.start, h->specials->user_data_range.end);
|
|
LOGF("\t\t draw_modifier: enbl_start_vertex_offset = %08" PRIx32 "\n"
|
|
"\t\t draw_modifier: enbl_start_index_offset = %08" PRIx32 "\n"
|
|
"\t\t draw_modifier: enbl_start_instance_offset = %08" PRIx32 "\n"
|
|
"\t\t draw_modifier: enbl_draw_index = %08" PRIx32 "\n"
|
|
"\t\t draw_modifier: enbl_user_vgprs = %08" PRIx32 "\n"
|
|
"\t\t draw_modifier: render_target_slice_offset = %08" PRIx32 "\n"
|
|
"\t\t draw_modifier: fuse_draws = %08" PRIx32 "\n"
|
|
"\t\t draw_modifier: compiler_flags = %08" PRIx32 "\n"
|
|
"\t\t draw_modifier: is_default = %08" PRIx32 "\n"
|
|
"\t\t draw_modifier: reserved = %08" PRIx32 "\n"
|
|
"\t num_input_semantics = 0x%08" PRIx32 "\n"
|
|
"\t input_semantics = 0x%016" PRIx64 "\n",
|
|
static_cast<uint32_t>(h->specials->draw_modifier.enbl_start_vertex_offset),
|
|
static_cast<uint32_t>(h->specials->draw_modifier.enbl_start_index_offset),
|
|
static_cast<uint32_t>(h->specials->draw_modifier.enbl_start_instance_offset),
|
|
static_cast<uint32_t>(h->specials->draw_modifier.enbl_draw_index),
|
|
static_cast<uint32_t>(h->specials->draw_modifier.enbl_user_vgprs),
|
|
static_cast<uint32_t>(h->specials->draw_modifier.render_target_slice_offset),
|
|
static_cast<uint32_t>(h->specials->draw_modifier.fuse_draws),
|
|
static_cast<uint32_t>(h->specials->draw_modifier.compiler_flags),
|
|
static_cast<uint32_t>(h->specials->draw_modifier.is_default),
|
|
static_cast<uint32_t>(h->specials->draw_modifier.reserved), h->num_input_semantics,
|
|
reinterpret_cast<uint64_t>(h->input_semantics));
|
|
for (int i = 0; i < static_cast<int>(h->num_input_semantics); i++) {
|
|
LOGF("\t\t input_semantics[%d]: semantic = %08" PRIx32 "\n"
|
|
"\t\t input_semantics[%d]: hardware_mapping = %08" PRIx32 "\n"
|
|
"\t\t input_semantics[%d]: size_in_elements = %08" PRIx32 "\n"
|
|
"\t\t input_semantics[%d]: is_f16 = %08" PRIx32 "\n"
|
|
"\t\t input_semantics[%d]: is_flat_shaded = %08" PRIx32 "\n"
|
|
"\t\t input_semantics[%d]: is_linear = %08" PRIx32 "\n"
|
|
"\t\t input_semantics[%d]: is_custom = %08" PRIx32 "\n"
|
|
"\t\t input_semantics[%d]: static_vb_index = %08" PRIx32 "\n"
|
|
"\t\t input_semantics[%d]: static_attribute = %08" PRIx32 "\n"
|
|
"\t\t input_semantics[%d]: reserved = %08" PRIx32 "\n"
|
|
"\t\t input_semantics[%d]: default_value = %08" PRIx32 "\n"
|
|
"\t\t input_semantics[%d]: default_value_hi = %08" PRIx32 "\n",
|
|
i, static_cast<uint32_t>(h->input_semantics[i].semantic), i,
|
|
static_cast<uint32_t>(h->input_semantics[i].hardware_mapping), i,
|
|
static_cast<uint32_t>(h->input_semantics[i].size_in_elements), i,
|
|
static_cast<uint32_t>(h->input_semantics[i].is_f16), i,
|
|
static_cast<uint32_t>(h->input_semantics[i].is_flat_shaded), i,
|
|
static_cast<uint32_t>(h->input_semantics[i].is_linear), i,
|
|
static_cast<uint32_t>(h->input_semantics[i].is_custom), i,
|
|
static_cast<uint32_t>(h->input_semantics[i].static_vb_index), i,
|
|
static_cast<uint32_t>(h->input_semantics[i].static_attribute), i,
|
|
static_cast<uint32_t>(h->input_semantics[i].reserved), i,
|
|
static_cast<uint32_t>(h->input_semantics[i].default_value), i,
|
|
static_cast<uint32_t>(h->input_semantics[i].default_value_hi));
|
|
}
|
|
LOGF("\t num_output_semantics = 0x%04" PRIx16 "\n"
|
|
"\t output_semantics = 0x%016" PRIx64 "\n",
|
|
h->num_output_semantics, reinterpret_cast<uint64_t>(h->output_semantics));
|
|
for (int i = 0; i < static_cast<int>(h->num_output_semantics); i++) {
|
|
LOGF("\t\t output_semantics[%d]: semantic = %08" PRIx32 "\n"
|
|
"\t\t output_semantics[%d]: hardware_mapping = %08" PRIx32 "\n"
|
|
"\t\t output_semantics[%d]: size_in_elements = %08" PRIx32 "\n"
|
|
"\t\t output_semantics[%d]: is_f16 = %08" PRIx32 "\n"
|
|
"\t\t output_semantics[%d]: is_flat_shaded = %08" PRIx32 "\n"
|
|
"\t\t output_semantics[%d]: is_linear = %08" PRIx32 "\n"
|
|
"\t\t output_semantics[%d]: is_custom = %08" PRIx32 "\n"
|
|
"\t\t output_semantics[%d]: static_vb_index = %08" PRIx32 "\n"
|
|
"\t\t output_semantics[%d]: static_attribute = %08" PRIx32 "\n"
|
|
"\t\t output_semantics[%d]: reserved = %08" PRIx32 "\n"
|
|
"\t\t output_semantics[%d]: default_value = %08" PRIx32 "\n"
|
|
"\t\t output_semantics[%d]: default_value_hi = %08" PRIx32 "\n",
|
|
i, static_cast<uint32_t>(h->output_semantics[i].semantic), i,
|
|
static_cast<uint32_t>(h->output_semantics[i].hardware_mapping), i,
|
|
static_cast<uint32_t>(h->output_semantics[i].size_in_elements), i,
|
|
static_cast<uint32_t>(h->output_semantics[i].is_f16), i,
|
|
static_cast<uint32_t>(h->output_semantics[i].is_flat_shaded), i,
|
|
static_cast<uint32_t>(h->output_semantics[i].is_linear), i,
|
|
static_cast<uint32_t>(h->output_semantics[i].is_custom), i,
|
|
static_cast<uint32_t>(h->output_semantics[i].static_vb_index), i,
|
|
static_cast<uint32_t>(h->output_semantics[i].static_attribute), i,
|
|
static_cast<uint32_t>(h->output_semantics[i].reserved), i,
|
|
static_cast<uint32_t>(h->output_semantics[i].default_value), i,
|
|
static_cast<uint32_t>(h->output_semantics[i].default_value_hi));
|
|
}
|
|
LOGF("\t header_size = 0x%08" PRIx32 "\n"
|
|
"\t shader_size = 0x%08" PRIx32 "\n"
|
|
"\t embedded_constant_buffer_size_dqw = 0x%08" PRIx32 "\n"
|
|
"\t target = 0x%08" PRIx32 "\n"
|
|
"\t scratch_size_dw_per_thread = 0x%04" PRIx16 "\n"
|
|
"\t special_sizes_bytes = 0x%04" PRIx16 "\n"
|
|
"\t type = 0x%02" PRIx8 "\n",
|
|
h->header_size, h->shader_size, h->embedded_constant_buffer_size_dqw, h->target,
|
|
h->scratch_size_dw_per_thread, h->special_sizes_bytes, h->type);
|
|
}
|
|
|
|
static constexpr int GRAPHICS5_ERROR_INVALID_SHADER_PROGRAM = static_cast<int>(0x8a6c0005u);
|
|
static constexpr int GRAPHICS5_ERROR_INVALID_SHADER_HALVES = static_cast<int>(0x8a6c0008u);
|
|
|
|
static bool get_shader_program_address_register(uint8_t type, uint32_t* lo_offset) {
|
|
if (lo_offset == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
switch (static_cast<Prospero::ShaderBinaryType>(type)) {
|
|
case Prospero::ShaderBinaryType::kCs: *lo_offset = Pm4::COMPUTE_PGM_LO; return true;
|
|
case Prospero::ShaderBinaryType::kPs: *lo_offset = Pm4::SPI_SHADER_PGM_LO_PS; return true;
|
|
case Prospero::ShaderBinaryType::kGs: *lo_offset = Pm4::SPI_SHADER_PGM_LO_ES; return true;
|
|
case Prospero::ShaderBinaryType::kHs: *lo_offset = Pm4::SPI_SHADER_PGM_LO_LS; return true;
|
|
case Prospero::ShaderBinaryType::kGsBack:
|
|
*lo_offset = Pm4::SPI_SHADER_PGM_LO_GS;
|
|
return true;
|
|
case Prospero::ShaderBinaryType::kHsBack:
|
|
*lo_offset = Pm4::SPI_SHADER_PGM_LO_HS;
|
|
return true;
|
|
case Prospero::ShaderBinaryType::kGsFront:
|
|
case Prospero::ShaderBinaryType::kHsFront:
|
|
case Prospero::ShaderBinaryType::kFs: return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static int patch_program_address_register(ShaderRegister* regs, uint32_t num_regs, uint8_t type,
|
|
uint64_t base) {
|
|
uint32_t lo_offset = 0;
|
|
if (!get_shader_program_address_register(type, &lo_offset)) {
|
|
return OK;
|
|
}
|
|
|
|
if (regs == nullptr || num_regs == 0) {
|
|
return GRAPHICS5_ERROR_INVALID_SHADER_PROGRAM;
|
|
}
|
|
|
|
for (auto lo_index = 0u; lo_index < num_regs; lo_index++) {
|
|
if (regs[lo_index].offset != lo_offset) {
|
|
continue;
|
|
}
|
|
|
|
const auto hi_index = lo_index + 1u;
|
|
const auto hi_offset = lo_offset + 1u;
|
|
if (hi_index >= num_regs || regs[hi_index].offset != hi_offset) {
|
|
return GRAPHICS5_ERROR_INVALID_SHADER_PROGRAM;
|
|
}
|
|
|
|
const auto shader_offset = (static_cast<uint64_t>(regs[lo_index].value) << 8u) |
|
|
((static_cast<uint64_t>(regs[hi_index].value) & 0xffu) << 40u);
|
|
const auto addr = base + shader_offset;
|
|
|
|
regs[lo_index].value = static_cast<uint32_t>((addr >> 8u) & 0xffffffffu);
|
|
regs[hi_index].value &= 0xffffff00u;
|
|
regs[hi_index].value |= static_cast<uint32_t>((addr >> 40u) & 0xffu);
|
|
return OK;
|
|
}
|
|
|
|
return GRAPHICS5_ERROR_INVALID_SHADER_PROGRAM;
|
|
}
|
|
|
|
static ShaderRegister* find_shader_register(ShaderRegister* regs, uint32_t num_regs,
|
|
uint32_t offset, uint32_t occurrence = 0) {
|
|
if (regs == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
for (uint32_t i = 0; i < num_regs; i++) {
|
|
if (regs[i].offset != offset) {
|
|
continue;
|
|
}
|
|
if (occurrence == 0) {
|
|
return regs + i;
|
|
}
|
|
occurrence--;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
static void patch_shader_register_address(ShaderRegister* regs, uint32_t num_regs,
|
|
uint32_t lo_offset, uint64_t address) {
|
|
auto* lo = find_shader_register(regs, num_regs, lo_offset);
|
|
if (lo == nullptr) {
|
|
return;
|
|
}
|
|
|
|
auto* hi = (lo + 1 < regs + num_regs && (lo + 1)->offset == lo_offset + 1u ? lo + 1 : nullptr);
|
|
if (hi == nullptr) {
|
|
return;
|
|
}
|
|
|
|
lo->value = static_cast<uint32_t>((address >> 8u) & 0xffffffffu);
|
|
hi->value &= 0xffffff00u;
|
|
hi->value |= static_cast<uint32_t>((address >> 40u) & 0xffu);
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsCreateShader(Shader** dst, void* header, const volatile void* code) {
|
|
PRINT_NAME();
|
|
|
|
EXIT_NOT_IMPLEMENTED(dst == nullptr);
|
|
EXIT_NOT_IMPLEMENTED(header == nullptr);
|
|
EXIT_NOT_IMPLEMENTED(code == nullptr);
|
|
|
|
LOGF("\t header = 0x%016" PRIx64 "\n"
|
|
"\t code = 0x%016" PRIx64 "\n",
|
|
reinterpret_cast<uint64_t>(header), reinterpret_cast<uint64_t>(code));
|
|
|
|
auto* h = static_cast<Shader*>(header);
|
|
|
|
auto update_addr = [](auto& m) {
|
|
if (m != nullptr) {
|
|
m = reinterpret_cast<typename std::remove_reference<decltype(m)>::type>(
|
|
reinterpret_cast<uintptr_t>(m) + reinterpret_cast<uintptr_t>(&m));
|
|
}
|
|
};
|
|
|
|
update_addr(h->cx_registers);
|
|
update_addr(h->sh_registers);
|
|
update_addr(h->user_data);
|
|
update_addr(h->specials);
|
|
update_addr(h->input_semantics);
|
|
update_addr(h->output_semantics);
|
|
if (h->user_data != nullptr) {
|
|
update_addr(h->user_data->direct_resource_offset);
|
|
update_addr(h->user_data->sharp_resource_offset[0]);
|
|
update_addr(h->user_data->sharp_resource_offset[1]);
|
|
update_addr(h->user_data->sharp_resource_offset[2]);
|
|
update_addr(h->user_data->sharp_resource_offset[3]);
|
|
}
|
|
|
|
h->code = code;
|
|
|
|
EXIT_NOT_IMPLEMENTED(h->file_header != 0x34333231);
|
|
EXIT_NOT_IMPLEMENTED(h->version != 0x00000018);
|
|
|
|
auto base = reinterpret_cast<uint64_t>(code);
|
|
|
|
LOGF("\t base = 0x%016" PRIx64 "\n", base);
|
|
|
|
ShaderMappedData map;
|
|
map.user_data = h->user_data;
|
|
map.input_semantics = h->input_semantics;
|
|
map.num_input_semantics = h->num_input_semantics;
|
|
map.code_size_bytes = h->shader_size;
|
|
|
|
ShaderMapUserData(base, map);
|
|
|
|
EXIT_NOT_IMPLEMENTED((base & 0xFFFF0000000000FFull) != 0);
|
|
|
|
auto patch_result =
|
|
patch_program_address_register(h->sh_registers, h->num_sh_registers, h->type, base);
|
|
if (patch_result != OK) {
|
|
return patch_result;
|
|
}
|
|
|
|
*dst = h;
|
|
|
|
dbg_dump_shader(h);
|
|
|
|
return OK;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsUnknownGetFusedShaderSize(SizeAlign* dst, const Shader* front,
|
|
const Shader* back) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t dst = 0x%016" PRIx64 "\n"
|
|
"\t front = 0x%016" PRIx64 "\n"
|
|
"\t back = 0x%016" PRIx64 "\n",
|
|
reinterpret_cast<uint64_t>(dst), reinterpret_cast<uint64_t>(front),
|
|
reinterpret_cast<uint64_t>(back));
|
|
|
|
EXIT_NOT_IMPLEMENTED(dst == nullptr);
|
|
EXIT_NOT_IMPLEMENTED(front == nullptr);
|
|
EXIT_NOT_IMPLEMENTED(back == nullptr);
|
|
|
|
const auto front_type = static_cast<Prospero::ShaderBinaryType>(front->type);
|
|
const auto back_type = static_cast<Prospero::ShaderBinaryType>(back->type);
|
|
if (!((front_type == Prospero::ShaderBinaryType::kGsFront &&
|
|
back_type == Prospero::ShaderBinaryType::kGsBack) ||
|
|
(front_type == Prospero::ShaderBinaryType::kHsFront &&
|
|
back_type == Prospero::ShaderBinaryType::kHsBack))) {
|
|
return GRAPHICS5_ERROR_INVALID_SHADER_HALVES;
|
|
}
|
|
|
|
dst->m_size = static_cast<uint64_t>(back->num_sh_registers) * sizeof(ShaderRegister);
|
|
dst->m_align = 4;
|
|
|
|
return OK;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsUnknownFuseShaderHalves(Shader* fused_result, const Shader* front,
|
|
const Shader* back, void* scratch_mem) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t fused_result = 0x%016" PRIx64 "\n"
|
|
"\t front = 0x%016" PRIx64 "\n"
|
|
"\t back = 0x%016" PRIx64 "\n"
|
|
"\t scratch_mem = 0x%016" PRIx64 "\n",
|
|
reinterpret_cast<uint64_t>(fused_result), reinterpret_cast<uint64_t>(front),
|
|
reinterpret_cast<uint64_t>(back), reinterpret_cast<uint64_t>(scratch_mem));
|
|
|
|
EXIT_NOT_IMPLEMENTED(fused_result == nullptr);
|
|
EXIT_NOT_IMPLEMENTED(front == nullptr);
|
|
EXIT_NOT_IMPLEMENTED(back == nullptr);
|
|
|
|
const auto front_type = static_cast<Prospero::ShaderBinaryType>(front->type);
|
|
const auto back_type = static_cast<Prospero::ShaderBinaryType>(back->type);
|
|
if (!((front_type == Prospero::ShaderBinaryType::kGsFront &&
|
|
back_type == Prospero::ShaderBinaryType::kGsBack) ||
|
|
(front_type == Prospero::ShaderBinaryType::kHsFront &&
|
|
back_type == Prospero::ShaderBinaryType::kHsBack))) {
|
|
return GRAPHICS5_ERROR_INVALID_SHADER_HALVES;
|
|
}
|
|
|
|
*fused_result = *back;
|
|
fused_result->type = static_cast<uint8_t>(front_type == Prospero::ShaderBinaryType::kGsFront
|
|
? Prospero::ShaderBinaryType::kGs
|
|
: Prospero::ShaderBinaryType::kHs);
|
|
|
|
if (front->specials != nullptr && back->specials != nullptr) {
|
|
const auto front_stages = front->specials->vgt_shader_stages_en.value;
|
|
const auto back_stages = back->specials->vgt_shader_stages_en.value;
|
|
const auto mismatch_bit =
|
|
(front_type == Prospero::ShaderBinaryType::kGsFront ? (1u << 22u) : (1u << 21u));
|
|
if (((front_stages ^ back_stages) & mismatch_bit) != 0) {
|
|
return GRAPHICS5_ERROR_INVALID_SHADER_HALVES;
|
|
}
|
|
}
|
|
|
|
if (scratch_mem != nullptr && back->sh_registers != nullptr && back->num_sh_registers != 0) {
|
|
auto* sh_registers = static_cast<ShaderRegister*>(scratch_mem);
|
|
memcpy(sh_registers, back->sh_registers,
|
|
static_cast<size_t>(back->num_sh_registers) * sizeof(ShaderRegister));
|
|
fused_result->sh_registers = sh_registers;
|
|
}
|
|
|
|
auto* fused_regs = fused_result->sh_registers;
|
|
const auto fused_reg_count = static_cast<uint32_t>(fused_result->num_sh_registers);
|
|
const auto front_reg_count = static_cast<uint32_t>(front->num_sh_registers);
|
|
|
|
if (front_type == Prospero::ShaderBinaryType::kGsFront) {
|
|
for (uint32_t occurrence = 0; occurrence < 2; occurrence++) {
|
|
auto* dst = find_shader_register(fused_regs, fused_reg_count,
|
|
Pm4::SPI_SHADER_PGM_CHKSUM_GS, occurrence);
|
|
const auto* src = find_shader_register(front->sh_registers, front_reg_count,
|
|
Pm4::SPI_SHADER_PGM_CHKSUM_GS, occurrence);
|
|
if (dst != nullptr && src != nullptr) {
|
|
dst->value = src->value;
|
|
}
|
|
}
|
|
patch_shader_register_address(fused_regs, fused_reg_count, Pm4::SPI_SHADER_PGM_LO_ES,
|
|
reinterpret_cast<uint64_t>(front->code));
|
|
} else {
|
|
patch_shader_register_address(fused_regs, fused_reg_count, Pm4::SPI_SHADER_PGM_LO_LS,
|
|
reinterpret_cast<uint64_t>(front->code));
|
|
}
|
|
|
|
fused_result->user_data = nullptr;
|
|
|
|
return OK;
|
|
}
|
|
|
|
static void merge_shader_register_max_field(ShaderRegister* dst, const ShaderRegister* src,
|
|
uint32_t shift, uint32_t mask) {
|
|
const auto dst_field = (dst->value >> shift) & mask;
|
|
const auto src_field = (src->value >> shift) & mask;
|
|
const auto field = std::max(dst_field, src_field);
|
|
|
|
dst->value &= ~(mask << shift);
|
|
dst->value |= field << shift;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsUnknownNApJjpKNBl4(Shader* fused_result, const Shader* front,
|
|
const Shader* back, void* scratch_mem) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t fused_result = 0x%016" PRIx64 "\n"
|
|
"\t front = 0x%016" PRIx64 "\n"
|
|
"\t back = 0x%016" PRIx64 "\n"
|
|
"\t scratch_mem = 0x%016" PRIx64 "\n",
|
|
reinterpret_cast<uint64_t>(fused_result), reinterpret_cast<uint64_t>(front),
|
|
reinterpret_cast<uint64_t>(back), reinterpret_cast<uint64_t>(scratch_mem));
|
|
|
|
const auto front_type = static_cast<Prospero::ShaderBinaryType>(front->type);
|
|
const auto is_gs = front_type == Prospero::ShaderBinaryType::kGsFront;
|
|
const auto is_hs = front_type == Prospero::ShaderBinaryType::kHsFront;
|
|
if ((!is_gs && !is_hs) ||
|
|
(is_gs && back->type != static_cast<uint8_t>(Prospero::ShaderBinaryType::kGsBack)) ||
|
|
(is_hs && back->type != static_cast<uint8_t>(Prospero::ShaderBinaryType::kHsBack))) {
|
|
return GRAPHICS5_ERROR_INVALID_SHADER_HALVES;
|
|
}
|
|
|
|
*fused_result = *back;
|
|
fused_result->type = static_cast<uint8_t>(is_gs ? Prospero::ShaderBinaryType::kGs
|
|
: Prospero::ShaderBinaryType::kHs);
|
|
|
|
const auto back_stages = back->specials->vgt_shader_stages_en.value;
|
|
const auto front_stages = front->specials->vgt_shader_stages_en.value;
|
|
const auto mismatch_bit = is_gs ? (1u << 22u) : (1u << 21u);
|
|
if (((front_stages ^ back_stages) & mismatch_bit) != 0) {
|
|
return GRAPHICS5_ERROR_INVALID_SHADER_HALVES;
|
|
}
|
|
|
|
if (scratch_mem != nullptr) {
|
|
auto* sh_registers = static_cast<ShaderRegister*>(scratch_mem);
|
|
memcpy(sh_registers, back->sh_registers,
|
|
static_cast<size_t>(back->num_sh_registers) * sizeof(ShaderRegister));
|
|
fused_result->sh_registers = sh_registers;
|
|
}
|
|
|
|
auto* fused_regs = fused_result->sh_registers;
|
|
const auto fused_reg_count = static_cast<uint32_t>(fused_result->num_sh_registers);
|
|
const auto front_reg_count = static_cast<uint32_t>(front->num_sh_registers);
|
|
const auto checksum_offset =
|
|
is_gs ? Pm4::SPI_SHADER_PGM_CHKSUM_GS : Pm4::SPI_SHADER_PGM_CHKSUM_HS;
|
|
const auto* front_checksum0 =
|
|
find_shader_register(front->sh_registers, front_reg_count, checksum_offset, 0);
|
|
const auto* front_checksum1 =
|
|
find_shader_register(front->sh_registers, front_reg_count, checksum_offset, 1);
|
|
auto* fused_checksum0 = find_shader_register(fused_regs, fused_reg_count, checksum_offset, 0);
|
|
auto* fused_checksum1 = find_shader_register(fused_regs, fused_reg_count, checksum_offset, 1);
|
|
fused_checksum0->value = front_checksum0->value;
|
|
fused_checksum1->value = front_checksum1->value;
|
|
|
|
const auto rsrc1_offset = is_gs ? Pm4::SPI_SHADER_PGM_RSRC1_GS : Pm4::SPI_SHADER_PGM_RSRC1_HS;
|
|
const auto rsrc2_offset = is_gs ? Pm4::SPI_SHADER_PGM_RSRC2_GS : Pm4::SPI_SHADER_PGM_RSRC2_HS;
|
|
const auto* front_rsrc1 =
|
|
find_shader_register(front->sh_registers, front_reg_count, rsrc1_offset);
|
|
const auto* front_rsrc2 =
|
|
find_shader_register(front->sh_registers, front_reg_count, rsrc2_offset);
|
|
auto* fused_rsrc1 = find_shader_register(fused_regs, fused_reg_count, rsrc1_offset);
|
|
auto* fused_rsrc2 = find_shader_register(fused_regs, fused_reg_count, rsrc2_offset);
|
|
|
|
merge_shader_register_max_field(fused_rsrc1, front_rsrc1, 0, 0x3fu);
|
|
merge_shader_register_max_field(fused_rsrc2, front_rsrc2, 28, 0x0fu);
|
|
if (is_gs) {
|
|
merge_shader_register_max_field(fused_rsrc1, front_rsrc1, 29, 0x03u);
|
|
merge_shader_register_max_field(fused_rsrc2, front_rsrc2, 16, 0x03u);
|
|
fused_rsrc2->value =
|
|
(fused_rsrc2->value & 0xf7ffffc1u) | (front_rsrc2->value & 0x0800003eu);
|
|
fused_rsrc2->value =
|
|
(fused_rsrc2->value & 0xfffbffffu) | (front_rsrc2->value & 0x00040000u);
|
|
} else {
|
|
merge_shader_register_max_field(fused_rsrc1, front_rsrc1, 28, 0x03u);
|
|
fused_rsrc2->value =
|
|
(fused_rsrc2->value & 0xf7ffffc1u) | (front_rsrc2->value & 0x0800003eu);
|
|
}
|
|
|
|
const auto program_lo_offset = is_gs ? Pm4::SPI_SHADER_PGM_LO_ES : Pm4::SPI_SHADER_PGM_LO_LS;
|
|
auto* program_lo = find_shader_register(fused_regs, fused_reg_count, program_lo_offset);
|
|
const auto address = reinterpret_cast<uint64_t>(front->code);
|
|
program_lo->value = static_cast<uint32_t>(address >> 8u);
|
|
(program_lo + 1)->value &= 0xffffff00u;
|
|
(program_lo + 1)->value |= static_cast<uint32_t>((address >> 40u) & 0xffu);
|
|
|
|
fused_result->user_data = front->user_data;
|
|
|
|
return OK;
|
|
}
|
|
|
|
static constexpr int GRAPHICS5_ERROR_INVALID_PACKET = static_cast<int>(0x8a6c000cu);
|
|
|
|
enum class RegIndirectPacket : uint32_t {
|
|
Cx,
|
|
Sh,
|
|
Uc,
|
|
};
|
|
|
|
static uint32_t reg_indirect_native_op(RegIndirectPacket type) {
|
|
switch (type) {
|
|
case RegIndirectPacket::Cx: return Pm4::IT_SET_CONTEXT_REG_INDIRECT;
|
|
case RegIndirectPacket::Sh: return Pm4::IT_SET_SH_REG_INDIRECT;
|
|
case RegIndirectPacket::Uc: return Pm4::IT_SET_UCONFIG_REG_INDIRECT;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static bool is_native_reg_indirect_packet(const uint32_t* cmd, RegIndirectPacket type) {
|
|
return ((cmd[0] >> 8u) & 0xffu) == reg_indirect_native_op(type);
|
|
}
|
|
|
|
static uint32_t reg_indirect_pm4_r(RegIndirectPacket type) {
|
|
return (type == RegIndirectPacket::Uc && GraphicsGetIsTrinityMode() != 0 ? 1u : 0u);
|
|
}
|
|
|
|
static void reg_indirect_write_packet(uint32_t* cmd, uint64_t vaddr, uint32_t num_regs,
|
|
RegIndirectPacket type) {
|
|
cmd[0] = KYTY_PM4(5, reg_indirect_native_op(type), reg_indirect_pm4_r(type));
|
|
cmd[1] = static_cast<uint32_t>(vaddr) & 0xfffffffcu;
|
|
cmd[2] = static_cast<uint32_t>(vaddr >> 32u);
|
|
cmd[3] = 0x80000000u;
|
|
cmd[4] = num_regs & 0x3fffu;
|
|
}
|
|
|
|
static int reg_indirect_patch_set_address(uint32_t* cmd, uint64_t vaddr, RegIndirectPacket type) {
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
if (is_native_reg_indirect_packet(cmd, type)) {
|
|
cmd[1] = (cmd[1] & 0x3u) | (static_cast<uint32_t>(vaddr) & 0xfffffffcu);
|
|
cmd[2] = static_cast<uint32_t>(vaddr >> 32u);
|
|
return OK;
|
|
}
|
|
|
|
return GRAPHICS5_ERROR_INVALID_PACKET;
|
|
}
|
|
|
|
static int reg_indirect_patch_set_num_registers(uint32_t* cmd, uint32_t num_regs,
|
|
RegIndirectPacket type) {
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
if (is_native_reg_indirect_packet(cmd, type)) {
|
|
cmd[4] = (cmd[4] & ~0x3fffu) | (num_regs & 0x3fffu);
|
|
return OK;
|
|
}
|
|
|
|
return GRAPHICS5_ERROR_INVALID_PACKET;
|
|
}
|
|
|
|
static int reg_indirect_patch_add_registers(uint32_t* cmd, uint32_t num_regs,
|
|
RegIndirectPacket type) {
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
if (is_native_reg_indirect_packet(cmd, type)) {
|
|
auto new_num_regs = ((cmd[4] & 0x3fffu) + num_regs) & 0x3fffu;
|
|
cmd[4] = (cmd[4] & ~0x3fffu) | new_num_regs;
|
|
return OK;
|
|
}
|
|
|
|
return GRAPHICS5_ERROR_INVALID_PACKET;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsSetCxRegIndirectPatchSetAddress(uint32_t* cmd,
|
|
const volatile ShaderRegister* regs) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t cmd = 0x%016" PRIx64 "\n"
|
|
"\t regs = 0x%016" PRIx64 "\n",
|
|
reinterpret_cast<uint64_t>(cmd), reinterpret_cast<uint64_t>(regs));
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
EXIT_NOT_IMPLEMENTED(regs == nullptr);
|
|
|
|
auto vaddr = reinterpret_cast<uint64_t>(regs);
|
|
|
|
return reg_indirect_patch_set_address(cmd, vaddr, RegIndirectPacket::Cx);
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsSetShRegIndirectPatchSetAddress(uint32_t* cmd,
|
|
const volatile ShaderRegister* regs) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t cmd = 0x%016" PRIx64 "\n"
|
|
"\t regs = 0x%016" PRIx64 "\n",
|
|
reinterpret_cast<uint64_t>(cmd), reinterpret_cast<uint64_t>(regs));
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
EXIT_NOT_IMPLEMENTED(regs == nullptr);
|
|
|
|
auto vaddr = reinterpret_cast<uint64_t>(regs);
|
|
|
|
return reg_indirect_patch_set_address(cmd, vaddr, RegIndirectPacket::Sh);
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsSetUcRegIndirectPatchSetAddress(uint32_t* cmd,
|
|
const volatile ShaderRegister* regs) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t cmd = 0x%016" PRIx64 "\n"
|
|
"\t regs = 0x%016" PRIx64 "\n",
|
|
reinterpret_cast<uint64_t>(cmd), reinterpret_cast<uint64_t>(regs));
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
EXIT_NOT_IMPLEMENTED(regs == nullptr);
|
|
|
|
auto vaddr = reinterpret_cast<uint64_t>(regs);
|
|
|
|
return reg_indirect_patch_set_address(cmd, vaddr, RegIndirectPacket::Uc);
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsSetCxRegIndirectPatchSetNumRegisters(uint32_t* cmd, uint32_t num_regs) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t cmd = 0x%016" PRIx64 "\n"
|
|
"\t num_regs = %" PRIu32 "\n",
|
|
reinterpret_cast<uint64_t>(cmd), num_regs);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
return reg_indirect_patch_set_num_registers(cmd, num_regs, RegIndirectPacket::Cx);
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsSetShRegIndirectPatchSetNumRegisters(uint32_t* cmd, uint32_t num_regs) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t cmd = 0x%016" PRIx64 "\n"
|
|
"\t num_regs = %" PRIu32 "\n",
|
|
reinterpret_cast<uint64_t>(cmd), num_regs);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
return reg_indirect_patch_set_num_registers(cmd, num_regs, RegIndirectPacket::Sh);
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsSetUcRegIndirectPatchSetNumRegisters(uint32_t* cmd, uint32_t num_regs) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t cmd = 0x%016" PRIx64 "\n"
|
|
"\t num_regs = %" PRIu32 "\n",
|
|
reinterpret_cast<uint64_t>(cmd), num_regs);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
return reg_indirect_patch_set_num_registers(cmd, num_regs, RegIndirectPacket::Uc);
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsSetCxRegIndirectPatchAddRegisters(uint32_t* cmd, uint32_t num_regs) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t cmd = 0x%016" PRIx64 "\n"
|
|
"\t num_regs = %" PRIu32 "\n",
|
|
reinterpret_cast<uint64_t>(cmd), num_regs);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
return reg_indirect_patch_add_registers(cmd, num_regs, RegIndirectPacket::Cx);
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsSetShRegIndirectPatchAddRegisters(uint32_t* cmd, uint32_t num_regs) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t cmd = 0x%016" PRIx64 "\n"
|
|
"\t num_regs = %" PRIu32 "\n",
|
|
reinterpret_cast<uint64_t>(cmd), num_regs);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
return reg_indirect_patch_add_registers(cmd, num_regs, RegIndirectPacket::Sh);
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsSetUcRegIndirectPatchAddRegisters(uint32_t* cmd, uint32_t num_regs) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t cmd = 0x%016" PRIx64 "\n"
|
|
"\t num_regs = %" PRIu32 "\n",
|
|
reinterpret_cast<uint64_t>(cmd), num_regs);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
return reg_indirect_patch_add_registers(cmd, num_regs, RegIndirectPacket::Uc);
|
|
}
|
|
|
|
static uint32_t GraphicsPrimitiveTypeToGsOut(uint32_t prim_type) {
|
|
switch (static_cast<Prospero::PrimitiveType>(prim_type)) {
|
|
case Prospero::PrimitiveType::kPointList:
|
|
return Prospero::GpuEnumValue(Prospero::GsOutputPrimitiveType::kPoints);
|
|
case Prospero::PrimitiveType::kLineList:
|
|
case Prospero::PrimitiveType::kLineStrip:
|
|
case Prospero::PrimitiveType::kLineListAdjacency:
|
|
case Prospero::PrimitiveType::kLineStripAdjacency:
|
|
case Prospero::PrimitiveType::kLineLoop:
|
|
return Prospero::GpuEnumValue(Prospero::GsOutputPrimitiveType::kLines);
|
|
case Prospero::PrimitiveType::kRectList:
|
|
return Prospero::GpuEnumValue(Prospero::GsOutputPrimitiveType::k2dRectangle);
|
|
case Prospero::PrimitiveType::kRectListLegacy:
|
|
return Prospero::GpuEnumValue(Prospero::GsOutputPrimitiveType::kRectList);
|
|
default: return Prospero::GpuEnumValue(Prospero::GsOutputPrimitiveType::kTriangles);
|
|
}
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsCreatePrimState(ShaderRegister* cx_regs, ShaderRegister* uc_regs,
|
|
const Shader* hs, const Shader* gs, uint32_t prim_type) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t cx_regs = 0x%016" PRIx64 "\n"
|
|
"\t uc_regs = 0x%016" PRIx64 "\n"
|
|
"\t hs = 0x%016" PRIx64 "\n"
|
|
"\t gs = 0x%016" PRIx64 "\n"
|
|
"\t prim_type = %" PRIu32 "\n",
|
|
reinterpret_cast<uint64_t>(cx_regs), reinterpret_cast<uint64_t>(uc_regs),
|
|
reinterpret_cast<uint64_t>(hs), reinterpret_cast<uint64_t>(gs), prim_type);
|
|
|
|
if (cx_regs == nullptr && uc_regs == nullptr) {
|
|
return OK;
|
|
}
|
|
|
|
EXIT_NOT_IMPLEMENTED(gs == nullptr);
|
|
|
|
EXIT_NOT_IMPLEMENTED(hs != nullptr && static_cast<Prospero::ShaderBinaryType>(hs->type) !=
|
|
Prospero::ShaderBinaryType::kHs);
|
|
EXIT_NOT_IMPLEMENTED(static_cast<Prospero::ShaderBinaryType>(gs->type) !=
|
|
Prospero::ShaderBinaryType::kGs);
|
|
|
|
if (cx_regs != nullptr) {
|
|
EXIT_NOT_IMPLEMENTED(hs != nullptr && hs->specials->vgt_shader_stages_en.offset !=
|
|
Pm4::VGT_SHADER_STAGES_EN);
|
|
EXIT_NOT_IMPLEMENTED(hs != nullptr && hs->specials->vgt_gs_out_prim_type.offset !=
|
|
Pm4::VGT_GS_OUT_PRIM_TYPE);
|
|
EXIT_NOT_IMPLEMENTED(gs->specials->vgt_shader_stages_en.offset !=
|
|
Pm4::VGT_SHADER_STAGES_EN);
|
|
EXIT_NOT_IMPLEMENTED(gs->specials->vgt_gs_out_prim_type.offset !=
|
|
Pm4::VGT_GS_OUT_PRIM_TYPE);
|
|
|
|
cx_regs[0] = gs->specials->vgt_shader_stages_en;
|
|
if ((cx_regs[0].value & 0x20u) != 0) {
|
|
cx_regs[1] = gs->specials->vgt_gs_out_prim_type;
|
|
} else {
|
|
cx_regs[1].offset = Pm4::VGT_GS_OUT_PRIM_TYPE;
|
|
cx_regs[1].value = GraphicsPrimitiveTypeToGsOut(prim_type);
|
|
}
|
|
|
|
if (hs != nullptr) {
|
|
cx_regs[0].value |= hs->specials->vgt_shader_stages_en.value;
|
|
if ((cx_regs[0].value & 0x20u) == 0) {
|
|
cx_regs[1] = hs->specials->vgt_gs_out_prim_type;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (uc_regs != nullptr) {
|
|
EXIT_NOT_IMPLEMENTED(gs->specials->ge_cntl.offset != Pm4::GE_CNTL);
|
|
EXIT_NOT_IMPLEMENTED(gs->specials->ge_user_vgpr_en.offset != Pm4::GE_USER_VGPR_EN);
|
|
EXIT_NOT_IMPLEMENTED(hs != nullptr &&
|
|
hs->specials->ge_user_vgpr_en.offset != Pm4::GE_USER_VGPR_EN);
|
|
|
|
uc_regs[0] = gs->specials->ge_cntl;
|
|
uc_regs[1] = gs->specials->ge_user_vgpr_en;
|
|
uc_regs[2].offset = Pm4::VGT_PRIMITIVE_TYPE;
|
|
uc_regs[2].value = prim_type;
|
|
|
|
if (hs != nullptr) {
|
|
uc_regs[1] = hs->specials->ge_user_vgpr_en;
|
|
}
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsUpdatePrimState(ShaderRegister* cx_regs, ShaderRegister* uc_regs,
|
|
uint32_t prim_type) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t cx_regs = 0x%016" PRIx64 "\n"
|
|
"\t uc_regs = 0x%016" PRIx64 "\n"
|
|
"\t prim_type = %" PRIu32 "\n",
|
|
reinterpret_cast<uint64_t>(cx_regs), reinterpret_cast<uint64_t>(uc_regs), prim_type);
|
|
|
|
if (cx_regs != nullptr && (cx_regs[0].value & 0x24u) == 0) {
|
|
cx_regs[1].value &= ~0x7u;
|
|
cx_regs[1].value |= GraphicsPrimitiveTypeToGsOut(prim_type);
|
|
}
|
|
|
|
if (uc_regs != nullptr) {
|
|
uc_regs[2].value &= ~0x1fu;
|
|
uc_regs[2].value |= prim_type;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
struct GsOccupancyLimits {
|
|
uint32_t vertex;
|
|
uint32_t export_count;
|
|
};
|
|
|
|
static GsOccupancyLimits get_gs_occupancy_limits(const Shader* gs, uint32_t vertex_capacity,
|
|
uint32_t export_capacity) {
|
|
const auto* onchip =
|
|
find_shader_register(gs->cx_registers, gs->num_cx_registers, Pm4::VGT_GS_ONCHIP_CNTL);
|
|
const auto* subgroup =
|
|
find_shader_register(gs->cx_registers, gs->num_cx_registers, Pm4::GE_NGG_SUBGRP_CNTL);
|
|
const auto* vs_out =
|
|
find_shader_register(gs->cx_registers, gs->num_cx_registers, Pm4::SPI_VS_OUT_CONFIG);
|
|
const auto* cl_out =
|
|
find_shader_register(gs->cx_registers, gs->num_cx_registers, Pm4::PA_CL_VS_OUT_CNTL);
|
|
const auto* max_output = find_shader_register(gs->cx_registers, gs->num_cx_registers,
|
|
Pm4::GE_MAX_OUTPUT_PER_SUBGROUP);
|
|
|
|
const uint32_t output_words = ((max_output->value & 0x3ffu) + 31u) >> 5u;
|
|
const uint32_t subgroup_work =
|
|
((((onchip->value >> 11u) & 0x7ffu) * (subgroup->value & 0x1ffu)) + 31u) >> 5u;
|
|
uint32_t waves = std::max(subgroup_work, output_words);
|
|
if ((gs->specials->vgt_shader_stages_en.value & 0x00400000u) == 0) {
|
|
waves >>= 1u;
|
|
}
|
|
waves = std::max(waves, 1u);
|
|
|
|
const uint32_t exports = 1u + ((cl_out->value >> 21u) & 1u) + ((cl_out->value >> 22u) & 1u) +
|
|
((cl_out->value >> 23u) & 1u);
|
|
const uint32_t export_limit = (export_capacity / exports) * 4u;
|
|
const uint32_t vertex_limit = (vs_out->value & 0x80u) != 0
|
|
? 2048u
|
|
: vertex_capacity / (((vs_out->value >> 2u) & 0xfu) + 1u);
|
|
|
|
return {waves * (vertex_limit / output_words), waves * (export_limit / output_words)};
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsGetGsOversubscription(ShaderRegister* regs, const Shader* gs,
|
|
uint32_t budget, float factor) {
|
|
PRINT_NAME();
|
|
|
|
constexpr uint32_t FULL_PC_OVERSUBSCRIPTION = 0x7ffu;
|
|
constexpr uint32_t FULL_SH_OVERSUBSCRIPTION = 0x007f0000u;
|
|
|
|
regs[0] = {Pm4::GE_PC_ALLOC, 0u};
|
|
regs[1] = {Pm4::SPI_SHADER_PGM_RSRC4_GS, 0u};
|
|
|
|
if (budget == 0u) {
|
|
return OK;
|
|
}
|
|
if (budget == UINT32_MAX) {
|
|
regs[0].value |= FULL_PC_OVERSUBSCRIPTION;
|
|
regs[1].value |= FULL_SH_OVERSUBSCRIPTION;
|
|
return OK;
|
|
}
|
|
|
|
const auto base = get_gs_occupancy_limits(gs, 1024u, 128u);
|
|
const auto expanded = get_gs_occupancy_limits(gs, 2048u, 382u);
|
|
const auto base_min = std::min(base.vertex, base.export_count);
|
|
const auto limit_shift =
|
|
(gs->specials->vgt_shader_stages_en.value & 0x00400000u) != 0 ? 5u : 6u;
|
|
const auto expanded_limit =
|
|
std::min({expanded.vertex, expanded.export_count, budget >> limit_shift, 1024u});
|
|
const auto headroom = expanded_limit > base_min ? expanded_limit - base_min : 0u;
|
|
const auto target = static_cast<uint32_t>(
|
|
std::fma(factor, static_cast<float>(headroom), static_cast<float>(base_min)));
|
|
|
|
if (target <= base_min) {
|
|
return OK;
|
|
}
|
|
if (target < base.export_count) {
|
|
const auto range = std::max(expanded.vertex - base.vertex, 1u);
|
|
auto value = static_cast<uint32_t>(
|
|
std::min((static_cast<uint64_t>(target - base.vertex) << 10u) / range, 1024ull));
|
|
value = std::max(value, 1u);
|
|
regs[0].value = (regs[0].value & ~FULL_PC_OVERSUBSCRIPTION) |
|
|
(((value << 1u) - 1u) & FULL_PC_OVERSUBSCRIPTION);
|
|
regs[1].value |= FULL_SH_OVERSUBSCRIPTION;
|
|
} else {
|
|
const auto range = std::max(expanded.export_count - base.export_count, 1u);
|
|
const auto value = static_cast<uint32_t>(
|
|
std::min((static_cast<uint64_t>(target - base.export_count) * 127u) / range, 127ull));
|
|
regs[0].value |= FULL_PC_OVERSUBSCRIPTION;
|
|
regs[1].value = (regs[1].value & ~FULL_SH_OVERSUBSCRIPTION) | (value << 16u);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
static uint32_t shader_semantic_word(const ShaderSemantic& semantic) {
|
|
return ((semantic.semantic & 0xffu) << 0u) | ((semantic.hardware_mapping & 0xffu) << 8u) |
|
|
((semantic.size_in_elements & 0xfu) << 16u) | ((semantic.is_f16 & 0x3u) << 20u) |
|
|
((semantic.is_flat_shaded & 0x1u) << 22u) | ((semantic.is_linear & 0x1u) << 23u) |
|
|
((semantic.is_custom & 0x1u) << 24u) | ((semantic.static_vb_index & 0x1u) << 25u) |
|
|
((semantic.static_attribute & 0x1u) << 26u) | ((semantic.reserved & 0x1u) << 27u) |
|
|
((semantic.default_value & 0x3u) << 28u) | ((semantic.default_value_hi & 0x3u) << 30u);
|
|
}
|
|
|
|
static uint32_t apply_interpolant_default_value(uint32_t value, uint32_t ps_word) {
|
|
value &= ~0x00000300u;
|
|
value |= ((ps_word >> 28u) & 0x3u) << 8u;
|
|
return value;
|
|
}
|
|
|
|
static uint32_t apply_interpolant_default_value_hi(uint32_t value, uint32_t ps_word) {
|
|
value &= ~0x00600000u;
|
|
value |= ((ps_word >> 30u) & 0x3u) << 21u;
|
|
return value;
|
|
}
|
|
|
|
static uint32_t create_interpolant_mapping_value(uint32_t value, uint32_t ps_word,
|
|
uint32_t gs_word) {
|
|
const uint32_t flat_shade =
|
|
((ps_word & 0x00400000u) != 0 || (ps_word & 0x01000000u) != 0 ? 0x00000400u : 0u);
|
|
|
|
value &= ~0x0000001fu;
|
|
value |= (gs_word >> 8u) & 0x1fu;
|
|
value &= ~0x00000400u;
|
|
value |= flat_shade;
|
|
|
|
return apply_interpolant_default_value(value, ps_word);
|
|
}
|
|
|
|
static uint32_t create_interpolant_default_value(uint32_t value, uint32_t ps_word) {
|
|
value &= ~0x0000001fu;
|
|
value &= ~0x00000400u;
|
|
|
|
return apply_interpolant_default_value(value, ps_word);
|
|
}
|
|
|
|
static uint32_t create_interpolant_f16_value(uint32_t ps_word, const ShaderSemantic* gs_semantic) {
|
|
uint32_t value = (ps_word << 4u) & 0x03000000u;
|
|
|
|
if (gs_semantic == nullptr) {
|
|
value |= 0x00180020u;
|
|
} else {
|
|
const uint32_t common_word = ps_word & shader_semantic_word(*gs_semantic);
|
|
|
|
value &= 0xfff7ffdfu;
|
|
value |= (common_word >> 15u) & 0x20u;
|
|
value ^= 0x00080020u;
|
|
value &= ~0x00100000u;
|
|
value |= (~common_word >> 1u) & 0x00100000u;
|
|
}
|
|
|
|
return apply_interpolant_default_value_hi(value, ps_word);
|
|
}
|
|
|
|
static uint32_t create_interpolant_non_f16_value(uint32_t ps_word,
|
|
const ShaderSemantic* gs_semantic) {
|
|
uint32_t value = 0;
|
|
if ((ps_word & 0x01000000u) != 0 || gs_semantic == nullptr) {
|
|
value |= 0x20u;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
static const ShaderSemantic* find_interpolant_output_semantic(const Shader* gs, uint32_t semantic) {
|
|
if (gs == nullptr || gs->output_semantics == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
for (uint16_t i = 0; i < gs->num_output_semantics; i++) {
|
|
if (gs->output_semantics[i].semantic == semantic) {
|
|
return &gs->output_semantics[i];
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
static void set_interpolant_register(ShaderRegister* regs, uint32_t index, uint32_t value) {
|
|
// Interpolant mappings contain encoded Cx descriptors. Indirect PM4 ingestion resolves
|
|
// this selector and slot to the physical SPI_PS_INPUT_CNTL register.
|
|
regs[index].offset = Pm4::CX_PS_SHADER_USAGE_BASE + index;
|
|
regs[index].value = value;
|
|
}
|
|
|
|
static void set_identity_interpolant_registers(ShaderRegister* regs, uint32_t first_index) {
|
|
for (uint32_t i = first_index; i < 32u; i++) {
|
|
set_interpolant_register(regs, i, i);
|
|
}
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsCreateInterpolantMapping(ShaderRegister* regs, const Shader* gs,
|
|
const Shader* ps) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t regs = 0x%016" PRIx64 "\n"
|
|
"\t gs = 0x%016" PRIx64 "\n"
|
|
"\t ps = 0x%016" PRIx64 "\n",
|
|
reinterpret_cast<uint64_t>(regs), reinterpret_cast<uint64_t>(gs),
|
|
reinterpret_cast<uint64_t>(ps));
|
|
|
|
EXIT_NOT_IMPLEMENTED(regs == nullptr);
|
|
EXIT_NOT_IMPLEMENTED(ps != nullptr && ps->num_input_semantics != 0 &&
|
|
ps->input_semantics == nullptr);
|
|
|
|
if (ps == nullptr || ps->num_input_semantics == 0) {
|
|
set_identity_interpolant_registers(regs, 0);
|
|
return OK;
|
|
}
|
|
|
|
EXIT_NOT_IMPLEMENTED(gs == nullptr);
|
|
EXIT_NOT_IMPLEMENTED(gs->num_output_semantics != 0 && gs->output_semantics == nullptr);
|
|
|
|
for (uint32_t ps_index = 0; ps_index < ps->num_input_semantics; ps_index++) {
|
|
const auto& ps_semantic = ps->input_semantics[ps_index];
|
|
const auto* gs_semantic = find_interpolant_output_semantic(gs, ps_semantic.semantic);
|
|
const auto ps_word = shader_semantic_word(ps_semantic);
|
|
|
|
auto value =
|
|
((ps_word & 0x00300000u) != 0 ? create_interpolant_f16_value(ps_word, gs_semantic)
|
|
: create_interpolant_non_f16_value(ps_word, gs_semantic));
|
|
value = (gs_semantic == nullptr ? create_interpolant_default_value(value, ps_word)
|
|
: create_interpolant_mapping_value(
|
|
value, ps_word, shader_semantic_word(*gs_semantic)));
|
|
|
|
set_interpolant_register(regs, ps_index, value);
|
|
}
|
|
|
|
set_identity_interpolant_registers(regs, ps->num_input_semantics);
|
|
|
|
return OK;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsGetDataPacketPayloadAddress(uint32_t** addr, uint32_t* cmd, int type) {
|
|
PRINT_NAME();
|
|
|
|
static std::atomic<uint32_t> log_count {0};
|
|
if (log_count.fetch_add(1) < 64) {
|
|
LOGF("\t addr = 0x%016" PRIx64 "\n"
|
|
"\t cmd = 0x%016" PRIx64 "\n"
|
|
"\t type = %d\n",
|
|
reinterpret_cast<uint64_t>(addr), reinterpret_cast<uint64_t>(cmd), type);
|
|
}
|
|
|
|
EXIT_NOT_IMPLEMENTED(addr == nullptr);
|
|
|
|
if (type != 0) {
|
|
*addr = cmd + 2;
|
|
return OK;
|
|
}
|
|
|
|
auto cmd_id = cmd[0];
|
|
*addr = ((~cmd_id & 0x3fff0000u) != 0 ? cmd + 1 : nullptr);
|
|
|
|
return OK;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsGetDataPacketPayloadRange(MemoryRange* range, uint32_t* cmd, int type) {
|
|
PRINT_NAME();
|
|
|
|
static std::atomic<uint32_t> log_count {0};
|
|
const bool should_log = (log_count.fetch_add(1) < 64);
|
|
if (should_log) {
|
|
LOGF("\t range = 0x%016" PRIx64 "\n"
|
|
"\t cmd = 0x%016" PRIx64 "\n"
|
|
"\t type = %d\n",
|
|
reinterpret_cast<uint64_t>(range), reinterpret_cast<uint64_t>(cmd), type);
|
|
}
|
|
|
|
EXIT_NOT_IMPLEMENTED(range == nullptr);
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
const auto cmd_id = cmd[0];
|
|
const auto len = KYTY_PM4_LEN(cmd_id);
|
|
|
|
if (type != 0) {
|
|
range->m_base = cmd + 2;
|
|
range->m_size = static_cast<uint64_t>((cmd_id >> 14u) & 0xfffcu);
|
|
} else {
|
|
if ((~cmd_id & 0x3fff0000u) == 0) {
|
|
range->m_base = nullptr;
|
|
range->m_size = 0;
|
|
} else {
|
|
range->m_base = cmd + 1;
|
|
range->m_size = static_cast<uint64_t>((cmd_id >> 14u) & 0xfffcu) + sizeof(uint32_t);
|
|
}
|
|
}
|
|
|
|
if (should_log) {
|
|
LOGF("\t cmd_id = 0x%08" PRIx32 ", len = %" PRIu32 "\n"
|
|
"\t base = 0x%016" PRIx64 "\n"
|
|
"\t size = 0x%016" PRIx64 "\n",
|
|
cmd_id, len, reinterpret_cast<uint64_t>(range->m_base), range->m_size);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsWriteDataPatchSetAddressOrOffset(uint32_t* cmd,
|
|
uint64_t address_or_offset) {
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
auto op = (cmd[0] >> 8u) & 0xffu;
|
|
if (op == Pm4::IT_WRITE_DATA) {
|
|
cmd[2] = static_cast<uint32_t>(address_or_offset & 0xffffffffu);
|
|
cmd[3] = static_cast<uint32_t>((address_or_offset >> 32u) & 0xffffffffu);
|
|
return OK;
|
|
}
|
|
|
|
return GRAPHICS5_ERROR_INVALID_PACKET;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsUnknownJumpPatchSetTarget(uint32_t* cmd, const volatile uint32_t* target,
|
|
uint32_t size_in_dwords) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("Calling unknown stub");
|
|
|
|
return GraphicsJumpPatchSetTarget(cmd, target, size_in_dwords);
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsJumpPatchSetTarget(uint32_t* cmd, const volatile uint32_t* target,
|
|
uint32_t size_in_dwords) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t cmd = 0x%016" PRIx64 "\n"
|
|
"\t target = 0x%016" PRIx64 "\n"
|
|
"\t size_in_dwords = %" PRIu32 "\n",
|
|
reinterpret_cast<uint64_t>(cmd), reinterpret_cast<uint64_t>(target), size_in_dwords);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
auto cmd_id = cmd[0];
|
|
auto op = (cmd_id >> 8u) & 0xffu;
|
|
|
|
LOGF("\t cmd_id = 0x%08" PRIx32 ", op = 0x%02" PRIx32 ", len = %" PRIu32 "\n", cmd_id,
|
|
op, KYTY_PM4_LEN(cmd_id));
|
|
|
|
if (op != Pm4::IT_INDIRECT_BUFFER) {
|
|
return GRAPHICS5_ERROR_INVALID_PACKET;
|
|
}
|
|
|
|
auto vaddr = reinterpret_cast<uint64_t>(target);
|
|
|
|
cmd[1] = static_cast<uint32_t>(vaddr & 0xffffffffu);
|
|
cmd[2] = (cmd[2] & 0xffff0000u) | static_cast<uint32_t>((vaddr >> 32u) & 0xffffu);
|
|
cmd[3] = (cmd[3] & 0xfff00000u) | (size_in_dwords & 0xfffffu);
|
|
|
|
return OK;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsSuspendPoint() {
|
|
PRINT_NAME();
|
|
|
|
EXIT_IF(g_renderer == nullptr);
|
|
g_renderer->GetGpu().Done();
|
|
|
|
return OK;
|
|
}
|
|
|
|
[[nodiscard]] static constexpr uint32_t context_state_op_size_dw(uint32_t operation) {
|
|
switch (static_cast<ContextStateOperation>(operation)) {
|
|
case ContextStateOperation::Clear: return 5;
|
|
case ContextStateOperation::Push:
|
|
case ContextStateOperation::Pop: return 27;
|
|
case ContextStateOperation::PushClear: return 32;
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbContextStateOp(CommandBuffer* buf, uint32_t operation) {
|
|
PRINT_NAME();
|
|
LOGF("\t operation = 0x%08" PRIx32 "\n", operation);
|
|
|
|
const auto size_dw = context_state_op_size_dw(operation);
|
|
if (buf == nullptr || size_dw == 0) {
|
|
return nullptr;
|
|
}
|
|
|
|
buf->DbgDump();
|
|
|
|
uint32_t* first = nullptr;
|
|
const auto append = [&](uint32_t segment_size_dw) {
|
|
auto* segment = buf->AllocateDW(segment_size_dw);
|
|
if (segment == nullptr) {
|
|
return false;
|
|
}
|
|
std::fill_n(segment, segment_size_dw, 0u);
|
|
if (first == nullptr) {
|
|
first = segment;
|
|
segment[0] = KYTY_PM4(segment_size_dw, Pm4::IT_NOP, Pm4::R_CONTEXT_STATE);
|
|
segment[1] = operation;
|
|
} else {
|
|
segment[0] = KYTY_PM4(segment_size_dw, Pm4::IT_NOP, Pm4::R_ZERO);
|
|
}
|
|
return true;
|
|
};
|
|
const auto append_save_restore = [&] {
|
|
// The native helper reserves 22 dwords, then emits 5-, 8-, and 9-dword packets.
|
|
return buf->ReserveDW(22) && append(5) && append(8) && append(9);
|
|
};
|
|
|
|
// Preserve native packet sizes, allocation boundaries, Push/Pop ordering, and
|
|
// returned first-packet address. The native packets reference process-private state buffers,
|
|
// so their net Cx operation is represented by the first HLE packet and type-3 NOPs.
|
|
bool complete = false;
|
|
switch (static_cast<ContextStateOperation>(operation)) {
|
|
case ContextStateOperation::Clear: complete = append(5); break;
|
|
case ContextStateOperation::Push:
|
|
complete = append_save_restore() && append(3) && append(2);
|
|
break;
|
|
case ContextStateOperation::Pop:
|
|
complete = append(3) && append_save_restore() && append(2);
|
|
break;
|
|
case ContextStateOperation::PushClear:
|
|
complete = append_save_restore() && append(3) && append(2) && append(5);
|
|
break;
|
|
default: break;
|
|
}
|
|
|
|
return complete ? first : nullptr;
|
|
}
|
|
|
|
uint64_t KYTY_SYSV_ABI GraphicsDcbContextStateOpGetSize(uint32_t operation) {
|
|
PRINT_NAME();
|
|
return static_cast<uint64_t>(context_state_op_size_dw(operation)) * sizeof(uint32_t);
|
|
}
|
|
|
|
uint64_t KYTY_SYSV_ABI GraphicsGetIsTrinityMode() {
|
|
// PS5 Pro?
|
|
return 0;
|
|
}
|
|
|
|
static constexpr int GRAPHICS5_DRIVER_ERROR_INVALID_VALUE = static_cast<int>(0x8a6c0033u);
|
|
static constexpr int GRAPHICS5_DRIVER_ERROR_INVALID_ARGUMENT = static_cast<int>(0x8a6c0035u);
|
|
static constexpr uint32_t WORKLOAD_STREAM_RECORD_SIZE = 32;
|
|
static constexpr uint32_t WORKLOAD_ACTIVE_PACKET_SIZE_DW = 18;
|
|
static constexpr uint32_t WORKLOAD_COMPLETE_PACKET_SIZE_DW = 12;
|
|
static constexpr uint32_t WORKLOAD_STREAM_MIN_ID = 1;
|
|
static constexpr uint32_t WORKLOAD_STREAM_MAX_ID = 31;
|
|
static constexpr uint32_t WORKLOAD_ID_MAX = 63;
|
|
static constexpr uint32_t WORKLOAD_ACTIVE_COUNT_MAX = 63;
|
|
|
|
static std::mutex g_workload_stream_mutex;
|
|
static uint32_t g_workload_stream_mask = 0;
|
|
static uint8_t g_workload_streams[WORKLOAD_STREAM_MAX_ID + 1][WORKLOAD_STREAM_RECORD_SIZE] {};
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsDriverGetDefaultOwner() {
|
|
PRINT_NAME();
|
|
|
|
return 0x8a6c9018u;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsDriverGetResourceRegistrationMaxNameLength() {
|
|
PRINT_NAME();
|
|
|
|
return 0x8a6c9018u;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsDriverInitResourceRegistration() {
|
|
PRINT_NAME();
|
|
|
|
return 0x8a6c9018u;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI
|
|
GraphicsDriverQueryResourceRegistrationUserMemoryRequirements(uint64_t* size_in_bytes) {
|
|
PRINT_NAME();
|
|
|
|
if (size_in_bytes != nullptr) {
|
|
*size_in_bytes = 0;
|
|
}
|
|
|
|
return 0x8a6c9018u;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsDriverRegisterOwner() {
|
|
PRINT_NAME();
|
|
|
|
return static_cast<int>(0x8a6c9018u);
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsDriverRegisterResource() {
|
|
PRINT_NAME();
|
|
|
|
return static_cast<int>(0x8a6c9018u);
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsDriverUnregisterResource() {
|
|
PRINT_NAME();
|
|
|
|
return static_cast<int>(0x8a6c9018u);
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsDriverRegisterWorkloadStream(uint32_t stream_id, const void* stream) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t stream_id = %" PRIu32 "\n"
|
|
"\t stream = 0x%016" PRIx64 "\n",
|
|
stream_id, reinterpret_cast<uint64_t>(stream));
|
|
|
|
if (stream_id < WORKLOAD_STREAM_MIN_ID || stream_id > WORKLOAD_STREAM_MAX_ID) {
|
|
return GRAPHICS5_DRIVER_ERROR_INVALID_VALUE;
|
|
}
|
|
|
|
if (stream == nullptr) {
|
|
return GRAPHICS5_DRIVER_ERROR_INVALID_ARGUMENT;
|
|
}
|
|
|
|
std::lock_guard lock(g_workload_stream_mutex);
|
|
|
|
const uint32_t stream_bit = 1u << stream_id;
|
|
if ((g_workload_stream_mask & stream_bit) != 0) {
|
|
return GRAPHICS5_DRIVER_ERROR_INVALID_VALUE;
|
|
}
|
|
|
|
std::memset(g_workload_streams[stream_id], 0, WORKLOAD_STREAM_RECORD_SIZE);
|
|
std::memcpy(g_workload_streams[stream_id], stream, WORKLOAD_STREAM_RECORD_SIZE);
|
|
g_workload_stream_mask |= stream_bit;
|
|
|
|
return OK;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsCbNop(CommandBuffer* buf, uint32_t size_in_dwords) {
|
|
if (buf == nullptr || size_in_dwords < 2) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto* cmd = buf->AllocateDW(size_in_dwords);
|
|
|
|
if (cmd == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
cmd[0] = KYTY_PM4(size_in_dwords, Pm4::IT_NOP, Pm4::R_ZERO);
|
|
if (size_in_dwords > 1) {
|
|
memset(cmd + 1, 0, static_cast<size_t>(size_in_dwords - 1) * 4);
|
|
}
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsCbNopGetSize(uint32_t size_in_dwords) {
|
|
return 4u * size_in_dwords;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsCbDispatch(CommandBuffer* buf, uint32_t thread_group_x,
|
|
uint32_t thread_group_y, uint32_t thread_group_z,
|
|
uint32_t modifier) {
|
|
PRINT_NAME();
|
|
|
|
static std::atomic<uint32_t> log_count {0};
|
|
if (log_count.fetch_add(1) < 64) {
|
|
LOGF("\t thread_group_x = %" PRIu32 "\n"
|
|
"\t thread_group_y = %" PRIu32 "\n"
|
|
"\t thread_group_z = %" PRIu32 "\n"
|
|
"\t modifier = 0x%08" PRIx32 "\n",
|
|
thread_group_x, thread_group_y, thread_group_z, modifier);
|
|
}
|
|
|
|
if (buf == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto* cmd = buf->AllocateDW(5);
|
|
|
|
if (cmd == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
cmd[0] = KYTY_PM4(5, Pm4::IT_DISPATCH_DIRECT, 0u);
|
|
cmd[1] = thread_group_x;
|
|
cmd[2] = thread_group_y;
|
|
cmd[3] = thread_group_z;
|
|
cmd[4] = (modifier & 0xa038u) | 0x41u;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsCbDispatchGetSize() {
|
|
PRINT_NAME();
|
|
|
|
return 20;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsCbBranch(CommandBuffer* buf, uint8_t mode, uint8_t compare_function,
|
|
const volatile uint64_t* compare_addr, uint64_t mask,
|
|
uint64_t reference, uint8_t cache_policy1,
|
|
const volatile uint32_t* buffer1, uint32_t size_in_dwords1,
|
|
uint8_t cache_policy2, const volatile uint32_t* buffer2,
|
|
uint32_t size_in_dwords2) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t mode = 0x%02" PRIx8 "\n"
|
|
"\t compare_function = 0x%02" PRIx8 "\n"
|
|
"\t compare_addr = 0x%016" PRIx64 "\n"
|
|
"\t mask = 0x%016" PRIx64 "\n"
|
|
"\t reference = 0x%016" PRIx64 "\n"
|
|
"\t cache_policy1 = 0x%02" PRIx8 "\n"
|
|
"\t buffer1 = 0x%016" PRIx64 "\n"
|
|
"\t size_in_dwords1 = %" PRIu32 "\n"
|
|
"\t cache_policy2 = 0x%02" PRIx8 "\n"
|
|
"\t buffer2 = 0x%016" PRIx64 "\n"
|
|
"\t size_in_dwords2 = %" PRIu32 "\n",
|
|
mode, compare_function, reinterpret_cast<uint64_t>(compare_addr), mask, reference,
|
|
cache_policy1, reinterpret_cast<uint64_t>(buffer1), size_in_dwords1, cache_policy2,
|
|
reinterpret_cast<uint64_t>(buffer2), size_in_dwords2);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
|
|
auto* cmd = buf->AllocateDW(14);
|
|
|
|
if (cmd == nullptr) {
|
|
LOGF_COLOR(Log::Color::Red, "\t failed to allocate branch packet\n");
|
|
return nullptr;
|
|
}
|
|
|
|
const auto compare_vaddr = reinterpret_cast<uint64_t>(compare_addr);
|
|
const auto then_vaddr = reinterpret_cast<uint64_t>(buffer1);
|
|
const auto else_vaddr = reinterpret_cast<uint64_t>(buffer2);
|
|
|
|
cmd[0] = KYTY_PM4(14, Pm4::IT_INDIRECT_BUFFER, 0u);
|
|
cmd[1] = (mode & 0x3u) | ((static_cast<uint32_t>(compare_function) & 0x7u) << 8u);
|
|
cmd[2] = static_cast<uint32_t>(compare_vaddr & 0xfffffff8u);
|
|
cmd[3] = static_cast<uint32_t>((compare_vaddr >> 32u) & 0xffffffffu);
|
|
cmd[4] = static_cast<uint32_t>(mask & 0xffffffffu);
|
|
cmd[5] = static_cast<uint32_t>((mask >> 32u) & 0xffffffffu);
|
|
cmd[6] = static_cast<uint32_t>(reference & 0xffffffffu);
|
|
cmd[7] = static_cast<uint32_t>((reference >> 32u) & 0xffffffffu);
|
|
cmd[8] = static_cast<uint32_t>(then_vaddr & 0xfffffffcu);
|
|
cmd[9] = static_cast<uint32_t>((then_vaddr >> 32u) & 0xffffffffu);
|
|
cmd[10] = (size_in_dwords1 & 0xfffffu) | ((static_cast<uint32_t>(cache_policy1) & 0x3u) << 28u);
|
|
cmd[11] = static_cast<uint32_t>(else_vaddr & 0xfffffffcu);
|
|
cmd[12] = static_cast<uint32_t>((else_vaddr >> 32u) & 0xffffffffu);
|
|
cmd[13] = (size_in_dwords2 & 0xfffffu) | ((static_cast<uint32_t>(cache_policy2) & 0x3u) << 28u);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsCbSetShRegisterRangeDirect(CommandBuffer* buf, uint32_t offset,
|
|
const uint32_t* values,
|
|
uint32_t num_values) {
|
|
PRINT_NAME();
|
|
|
|
static std::atomic<uint32_t> log_count {0};
|
|
if (log_count.fetch_add(1) < 64) {
|
|
LOGF("\t buf = 0x%016" PRIx64 "\n"
|
|
"\t offset = %" PRIx32 "\n"
|
|
"\t values = 0x%016" PRIx64 "\n"
|
|
"\t num_values = %" PRIu32 "\n",
|
|
reinterpret_cast<uint64_t>(buf), offset, reinterpret_cast<uint64_t>(values),
|
|
num_values);
|
|
}
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(num_values + 2);
|
|
|
|
if (cmd == nullptr) {
|
|
LOGF_COLOR(Log::Color::Red, "\t failed to allocate set-register-range command\n");
|
|
return nullptr;
|
|
}
|
|
|
|
cmd[0] = KYTY_PM4(num_values + 2, Pm4::IT_SET_SH_REG, 0u);
|
|
cmd[1] = offset & 0xffffu;
|
|
|
|
if (values != nullptr) {
|
|
memcpy(cmd + 2, values, static_cast<size_t>(num_values) * 4);
|
|
}
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsCbSetShRegisterRangeDirectGetSize(uint32_t num_values) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t num_values = %" PRIu32 "\n", num_values);
|
|
|
|
return 4u * num_values + 8u;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsCbSetShRegistersDirect(CommandBuffer* buf,
|
|
const volatile ShaderRegister* regs,
|
|
uint32_t num_regs) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t regs = 0x%016" PRIx64 "\n"
|
|
"\t num_regs = %" PRIu32 "\n",
|
|
reinterpret_cast<uint64_t>(regs), num_regs);
|
|
|
|
if (num_regs == 0) {
|
|
return nullptr;
|
|
}
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
EXIT_NOT_IMPLEMENTED(regs == nullptr);
|
|
|
|
buf->DbgDump();
|
|
|
|
std::vector<ShaderRegister> local_regs(num_regs);
|
|
for (uint32_t i = 0; i < num_regs; i++) {
|
|
local_regs[i].offset = regs[i].offset;
|
|
local_regs[i].value = regs[i].value;
|
|
}
|
|
|
|
uint32_t* first_cmd = nullptr;
|
|
uint32_t run_start_index = 0;
|
|
uint32_t run_start_offset = local_regs[0].offset;
|
|
uint32_t prev_offset = run_start_offset;
|
|
|
|
for (uint32_t i = 1; i <= num_regs; i++) {
|
|
const bool flush = (i == num_regs || local_regs[i].offset != prev_offset + 1u);
|
|
|
|
if (flush) {
|
|
const auto run_count = i - run_start_index;
|
|
auto* cmd = buf->AllocateDW(run_count + 2u);
|
|
|
|
if (cmd == nullptr) {
|
|
LOGF_COLOR(Log::Color::Red,
|
|
"\t failed to allocate set-sh-registers-direct command\n");
|
|
return first_cmd;
|
|
}
|
|
|
|
if (first_cmd == nullptr) {
|
|
first_cmd = cmd;
|
|
}
|
|
|
|
cmd[0] = KYTY_PM4(run_count + 2u, Pm4::IT_SET_SH_REG, 0u);
|
|
cmd[1] = run_start_offset & 0xffffu;
|
|
|
|
for (uint32_t j = 0; j < run_count; j++) {
|
|
cmd[j + 2u] = local_regs[run_start_index + j].value;
|
|
}
|
|
|
|
if (i < num_regs) {
|
|
run_start_index = i;
|
|
run_start_offset = local_regs[i].offset;
|
|
}
|
|
}
|
|
|
|
if (i < num_regs) {
|
|
prev_offset = local_regs[i].offset;
|
|
}
|
|
}
|
|
|
|
return first_cmd;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsDebugRaiseException(uint32_t exception_id) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t exception_id = 0x%08" PRIx32 "\n", exception_id);
|
|
|
|
return OK;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsCbReleaseMem(CommandBuffer* buf, uint8_t action, uint16_t gcr_cntl,
|
|
uint8_t dst, uint8_t cache_policy,
|
|
const volatile Label* address, uint8_t data_sel,
|
|
uint64_t data, uint16_t gds_offset, uint16_t gds_size,
|
|
uint8_t interrupt, uint32_t interrupt_ctx_id) {
|
|
PRINT_NAME();
|
|
|
|
static std::atomic<uint32_t> log_count {0};
|
|
if (log_count.fetch_add(1) < 64) {
|
|
LOGF("\t action = 0x%02" PRIx8 "\n"
|
|
"\t gcr_cntl = 0x%04" PRIx16 "\n"
|
|
"\t dst = %" PRIu8 "\n"
|
|
"\t cache_policy = 0x%02" PRIx8 "\n"
|
|
"\t address = 0x%016" PRIx64 "\n"
|
|
"\t data_sel = 0x%02" PRIx8 "\n"
|
|
"\t data = 0x%016" PRIx64 "\n"
|
|
"\t gds_offset = %" PRIu16 "\n"
|
|
"\t gds_size = %" PRIu16 "\n"
|
|
"\t interrupt = 0x%02" PRIx8 "\n"
|
|
"\t interrupt_ctx_id = %" PRIu32 "\n",
|
|
action, gcr_cntl, dst, cache_policy, reinterpret_cast<uint64_t>(address), data_sel,
|
|
data, gds_offset, gds_size, interrupt, interrupt_ctx_id);
|
|
}
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
EXIT_NOT_IMPLEMENTED(dst > 1);
|
|
EXIT_NOT_IMPLEMENTED(data_sel != 0 && data_sel != 1 && data_sel != 2 && data_sel != 3 &&
|
|
data_sel != 5);
|
|
EXIT_NOT_IMPLEMENTED(interrupt > 4);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(8);
|
|
|
|
if (cmd == nullptr) {
|
|
LOGF_COLOR(Log::Color::Red, "\t failed to allocate release_mem packet\n");
|
|
return nullptr;
|
|
}
|
|
|
|
auto packet_gcr_cntl = static_cast<uint32_t>(gcr_cntl);
|
|
if ((packet_gcr_cntl & 0x300u) == 0x100u) {
|
|
packet_gcr_cntl |= 0x200u;
|
|
}
|
|
|
|
auto address_value = reinterpret_cast<uint64_t>(address);
|
|
auto packet_data = data;
|
|
if ((interrupt & 0x7u) == 4u) {
|
|
address_value = 0;
|
|
packet_data = 0;
|
|
} else if ((data_sel & 0x7u) == 5u) {
|
|
packet_data = static_cast<uint64_t>(gds_offset) | (static_cast<uint64_t>(gds_size) << 16u);
|
|
}
|
|
|
|
const uint32_t packet_action = static_cast<uint32_t>(action) & 0x3fu;
|
|
const uint32_t packet_event_index = (action >= 0x2fu ? 6u : 5u);
|
|
|
|
cmd[0] = KYTY_PM4(8, Pm4::IT_NOP, Pm4::R_RELEASE_MEM);
|
|
cmd[1] = packet_action | (packet_event_index << 8u) | ((packet_gcr_cntl & 0xfffu) << 12u) |
|
|
((static_cast<uint32_t>(cache_policy) & 0x3u) << 25u);
|
|
cmd[2] = ((static_cast<uint32_t>(dst) & 0x3u) << 16u) |
|
|
((static_cast<uint32_t>(interrupt) & 0x7u) << 24u) |
|
|
((static_cast<uint32_t>(data_sel) & 0x7u) << 29u);
|
|
cmd[3] = static_cast<uint32_t>(address_value & 0xfffffffcu);
|
|
cmd[4] = static_cast<uint32_t>((address_value >> 32u) & 0xffffffffu);
|
|
cmd[5] = static_cast<uint32_t>(packet_data & 0xffffffffu);
|
|
cmd[6] = static_cast<uint32_t>((packet_data >> 32u) & 0xffffffffu);
|
|
cmd[7] = interrupt_ctx_id & 0x07ffffffu;
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsCbQueueEndOfPipeActionGetSize() {
|
|
PRINT_NAME();
|
|
|
|
return 32;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsAcbResetQueue(CommandBuffer* buf, uint32_t op) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t op = 0x%08" PRIx32 "\n", op);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
EXIT_NOT_IMPLEMENTED((op & ~0x1c2u) != 0);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(2);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
cmd[0] = KYTY_PM4(2, Pm4::IT_NOP, Pm4::R_DISPATCH_RESET);
|
|
cmd[1] = 0;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbResetQueue(CommandBuffer* buf, uint32_t op, uint32_t state) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t op = 0x%08" PRIx32 "\n"
|
|
"\t state = 0x%08" PRIx32 "\n",
|
|
op, state);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
EXIT_NOT_IMPLEMENTED((op & ~0xfffu) != 0);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(2);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
cmd[0] = KYTY_PM4(2, Pm4::IT_CLEAR_STATE, 0u);
|
|
cmd[1] = state & 0xfu;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbWaitUntilSafeForRendering(CommandBuffer* buf,
|
|
uint32_t video_out_handle,
|
|
uint32_t display_buffer_index) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t video_out_handle = %" PRIu32 "\n"
|
|
"\t display_buffer_index = %" PRIu32 "\n",
|
|
video_out_handle, display_buffer_index);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(7);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
cmd[0] = KYTY_PM4(7, Pm4::IT_NOP, Pm4::R_WAIT_FLIP_DONE);
|
|
cmd[1] = video_out_handle;
|
|
cmd[2] = display_buffer_index;
|
|
cmd[3] = 0;
|
|
cmd[4] = 0;
|
|
cmd[5] = 0;
|
|
cmd[6] = 0;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetWorkloadsActive(CommandBuffer* buf, uint32_t stream_id,
|
|
const uint32_t* workload_ids,
|
|
uint32_t workload_count) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t stream_id = %" PRIu32 "\n"
|
|
"\t workload_ids = 0x%016" PRIx64 "\n"
|
|
"\t workload_count = %" PRIu32 "\n",
|
|
stream_id, reinterpret_cast<uint64_t>(workload_ids), workload_count);
|
|
|
|
if (buf == nullptr || workload_ids == nullptr || workload_count == 0 ||
|
|
workload_count > WORKLOAD_ACTIVE_COUNT_MAX || stream_id < WORKLOAD_STREAM_MIN_ID ||
|
|
stream_id > WORKLOAD_STREAM_MAX_ID) {
|
|
return nullptr;
|
|
}
|
|
|
|
uint64_t workload_mask = 0;
|
|
for (uint32_t i = 0; i < workload_count; i++) {
|
|
const auto workload_id = workload_ids[i];
|
|
if (workload_id > WORKLOAD_ID_MAX) {
|
|
return nullptr;
|
|
}
|
|
|
|
const uint64_t workload_bit = 1ull << workload_id;
|
|
if ((workload_mask & workload_bit) != 0) {
|
|
return nullptr;
|
|
}
|
|
workload_mask |= workload_bit;
|
|
}
|
|
|
|
{
|
|
std::lock_guard lock(g_workload_stream_mutex);
|
|
if ((g_workload_stream_mask & (1u << stream_id)) == 0) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(WORKLOAD_ACTIVE_PACKET_SIZE_DW);
|
|
if (cmd == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
cmd[0] = KYTY_PM4(WORKLOAD_ACTIVE_PACKET_SIZE_DW, Pm4::IT_NOP, Pm4::R_ZERO);
|
|
std::memset(cmd + 1, 0,
|
|
static_cast<size_t>(WORKLOAD_ACTIVE_PACKET_SIZE_DW - 1) * sizeof(uint32_t));
|
|
cmd[1] = stream_id;
|
|
cmd[2] = static_cast<uint32_t>(workload_mask & 0xffffffffu);
|
|
cmd[3] = static_cast<uint32_t>((workload_mask >> 32u) & 0xffffffffu);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetWorkloadComplete(CommandBuffer* buf, uint32_t stream_id,
|
|
uint32_t workload_id) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t stream_id = %" PRIu32 "\n"
|
|
"\t workload_id = %" PRIu32 "\n",
|
|
stream_id, workload_id);
|
|
|
|
if (buf == nullptr || stream_id < WORKLOAD_STREAM_MIN_ID ||
|
|
stream_id > WORKLOAD_STREAM_MAX_ID || workload_id > WORKLOAD_ID_MAX) {
|
|
return nullptr;
|
|
}
|
|
|
|
{
|
|
std::lock_guard lock(g_workload_stream_mutex);
|
|
if ((g_workload_stream_mask & (1u << stream_id)) == 0) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(WORKLOAD_COMPLETE_PACKET_SIZE_DW);
|
|
if (cmd == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
const uint64_t workload_clear_mask = ~(1ull << workload_id);
|
|
|
|
cmd[0] = KYTY_PM4(WORKLOAD_COMPLETE_PACKET_SIZE_DW, Pm4::IT_NOP, Pm4::R_ZERO);
|
|
std::memset(cmd + 1, 0,
|
|
static_cast<size_t>(WORKLOAD_COMPLETE_PACKET_SIZE_DW - 1) * sizeof(uint32_t));
|
|
cmd[1] = stream_id;
|
|
cmd[2] = workload_id;
|
|
cmd[3] = static_cast<uint32_t>(workload_clear_mask & 0xffffffffu);
|
|
cmd[4] = static_cast<uint32_t>((workload_clear_mask >> 32u) & 0xffffffffu);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetShRegisterDirect(CommandBuffer* buf, ShaderRegister reg) {
|
|
PRINT_NAME();
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(3);
|
|
|
|
if (cmd == nullptr) {
|
|
LOGF_COLOR(Log::Color::Red, "\t failed to allocate set-sh-register-direct command\n");
|
|
return nullptr;
|
|
}
|
|
|
|
cmd[0] = KYTY_PM4(3, Pm4::IT_SET_SH_REG, 0u);
|
|
cmd[1] = reg.offset & 0xffffu;
|
|
cmd[2] = reg.value;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetCxRegisterDirect(CommandBuffer* buf, ShaderRegister reg) {
|
|
PRINT_NAME();
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(3);
|
|
|
|
if (cmd == nullptr) {
|
|
LOGF_COLOR(Log::Color::Red, "\t failed to allocate set-cx-register-direct command\n");
|
|
return nullptr;
|
|
}
|
|
|
|
cmd[0] = KYTY_PM4(3, Pm4::IT_SET_CONTEXT_REG, 0u);
|
|
cmd[1] = reg.offset & 0xffffu;
|
|
cmd[2] = reg.value;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsDcbSetCxRegisterDirectGetSize() {
|
|
PRINT_NAME();
|
|
|
|
return 12;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetUcRegisterDirect(CommandBuffer* buf, ShaderRegister reg) {
|
|
PRINT_NAME();
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(3);
|
|
|
|
if (cmd == nullptr) {
|
|
LOGF_COLOR(Log::Color::Red, "\t failed to allocate set-uc-register-direct command\n");
|
|
return nullptr;
|
|
}
|
|
|
|
cmd[0] = KYTY_PM4(3, Pm4::IT_SET_UCONFIG_REG, 0u);
|
|
cmd[1] = reg.offset & 0xffffu;
|
|
cmd[2] = reg.value;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetCxRegistersIndirect(CommandBuffer* buf,
|
|
const volatile ShaderRegister* regs,
|
|
uint32_t num_regs) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t regs = 0x%016" PRIx64 "\n"
|
|
"\t num_regs = %" PRIu32 "\n",
|
|
reinterpret_cast<uint64_t>(regs), num_regs);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(5);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
auto vaddr = reinterpret_cast<uint64_t>(regs);
|
|
|
|
reg_indirect_write_packet(cmd, vaddr, num_regs, RegIndirectPacket::Cx);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetShRegistersIndirect(CommandBuffer* buf,
|
|
const volatile ShaderRegister* regs,
|
|
uint32_t num_regs) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t regs = 0x%016" PRIx64 "\n"
|
|
"\t num_regs = %" PRIu32 "\n",
|
|
reinterpret_cast<uint64_t>(regs), num_regs);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(5);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
auto vaddr = reinterpret_cast<uint64_t>(regs);
|
|
|
|
reg_indirect_write_packet(cmd, vaddr, num_regs, RegIndirectPacket::Sh);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetUcRegistersIndirect(CommandBuffer* buf,
|
|
const volatile ShaderRegister* regs,
|
|
uint32_t num_regs) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t regs = 0x%016" PRIx64 "\n"
|
|
"\t num_regs = %" PRIu32 "\n",
|
|
reinterpret_cast<uint64_t>(regs), num_regs);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(5);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
auto vaddr = reinterpret_cast<uint64_t>(regs);
|
|
|
|
reg_indirect_write_packet(cmd, vaddr, num_regs, RegIndirectPacket::Uc);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetIndexSize(CommandBuffer* buf, uint8_t index_size,
|
|
uint8_t cache_policy) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t index_size = 0x%" PRIx8 "\n"
|
|
"\t cache_policy = 0x%" PRIx8 "\n",
|
|
index_size, cache_policy);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(3);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
cmd[0] = KYTY_PM4(3, Pm4::IT_SET_UCONFIG_REG_INDEX, 0u);
|
|
cmd[1] = 0x20000000u | Pm4::VGT_INDEX_TYPE;
|
|
cmd[2] = 0x400u | (index_size & 0x3u) | ((cache_policy & 0x3u) << 6u);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetIndexBuffer(CommandBuffer* buf, uint64_t index_addr) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t index_addr = 0x%016" PRIx64 "\n", index_addr);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
EXIT_NOT_IMPLEMENTED((index_addr & 1u) != 0);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(3);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
cmd[0] = KYTY_PM4(3, Pm4::IT_INDEX_BASE, 0u);
|
|
cmd[1] = static_cast<uint32_t>(index_addr & 0xffffffffu);
|
|
cmd[2] = static_cast<uint32_t>((index_addr >> 32u) & 0xffffffffu);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetIndexCount(CommandBuffer* buf, uint32_t index_count) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t index_count = 0x%" PRIx32 "\n", index_count);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(2);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
cmd[0] = KYTY_PM4(2, Pm4::IT_INDEX_BUFFER_SIZE, 0u);
|
|
cmd[1] = index_count;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetNumInstances(CommandBuffer* buf, uint32_t num_instances) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t num_instances = 0x%" PRIx32 "\n", num_instances);
|
|
|
|
if (buf == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(2);
|
|
|
|
if (cmd == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
cmd[0] = KYTY_PM4(2, Pm4::IT_NUM_INSTANCES, 0u);
|
|
cmd[1] = num_instances;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsDcbSetNumInstancesGetSize() {
|
|
PRINT_NAME();
|
|
|
|
return 8;
|
|
}
|
|
|
|
static uint32_t extract_modifier_bits(uint32_t modifier, uint32_t start, uint32_t count) {
|
|
return (modifier >> start) & ((1u << count) - 1u);
|
|
}
|
|
|
|
static uint32_t indirect_modifier_sgpr_base(uint32_t modifier) {
|
|
const auto stage = modifier >> 29u;
|
|
return ((stage == 3u || stage == 5u) ? 0x80u : 0u) + 0x8cu;
|
|
}
|
|
|
|
static uint64_t decode_indirect_modifier_patch_offsets(uint64_t modifier, bool indexed) {
|
|
const auto low = static_cast<uint32_t>(modifier);
|
|
const auto sgpr_base = indirect_modifier_sgpr_base(low);
|
|
|
|
uint64_t base_vtx_loc = 0x280u;
|
|
if ((low & 0x1u) != 0) {
|
|
base_vtx_loc = sgpr_base + extract_modifier_bits(low, 9u, 5u);
|
|
}
|
|
|
|
uint64_t start_inst_loc = 0x280u;
|
|
if ((low & 0x4u) != 0) {
|
|
start_inst_loc = sgpr_base + extract_modifier_bits(low, 19u, 5u);
|
|
}
|
|
|
|
if (indexed && (low & 0x2u) != 0) {
|
|
base_vtx_loc |= static_cast<uint64_t>(sgpr_base + extract_modifier_bits(low, 14u, 5u))
|
|
<< 16u;
|
|
base_vtx_loc |= 1ull << 59u;
|
|
}
|
|
|
|
return base_vtx_loc | (start_inst_loc << 32u);
|
|
}
|
|
|
|
static uint32_t decode_indirect_draw_initiator(uint64_t modifier) {
|
|
const auto low = static_cast<uint32_t>(modifier);
|
|
uint32_t initiator = 2u;
|
|
|
|
if ((modifier & (1ull << 32u)) == 0) {
|
|
initiator = ((low >> 3u) & 0x20u) | 2u;
|
|
}
|
|
|
|
return initiator;
|
|
}
|
|
|
|
static uint32_t decode_draw_index_initiator(uint64_t modifier) {
|
|
if ((modifier & (1ull << 32u)) != 0) {
|
|
return 0;
|
|
}
|
|
|
|
return (static_cast<uint32_t>(modifier) >> 3u) & 0x20u;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbDrawIndex(CommandBuffer* buf, uint32_t index_count,
|
|
const volatile void* index_addr, uint64_t modifier) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t index_count = 0x%" PRIx32 "\n"
|
|
"\t index_addr = 0x%016" PRIx64 "\n"
|
|
"\t modifier = 0x%016" PRIx64 "\n",
|
|
index_count, reinterpret_cast<uint64_t>(index_addr), modifier);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
EXIT_NOT_IMPLEMENTED(index_addr == nullptr);
|
|
EXIT_NOT_IMPLEMENTED((reinterpret_cast<uint64_t>(index_addr) & 1u) != 0);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(6);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
auto vaddr = reinterpret_cast<uint64_t>(index_addr);
|
|
|
|
cmd[0] = KYTY_PM4(6, Pm4::IT_DRAW_INDEX_2, 0u);
|
|
cmd[1] = (index_count == 0 ? 1u : index_count);
|
|
cmd[2] = static_cast<uint32_t>(vaddr & 0xffffffffu);
|
|
cmd[3] = static_cast<uint32_t>((vaddr >> 32u) & 0xffffffffu);
|
|
cmd[4] = index_count;
|
|
cmd[5] = decode_draw_index_initiator(modifier);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsDcbDrawIndexGetSize() {
|
|
PRINT_NAME();
|
|
|
|
return 6u * 4u;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbDrawIndexMultiInstanced(CommandBuffer* buf, uint32_t index_count,
|
|
const volatile void* index_addr,
|
|
const volatile void* object_ids,
|
|
uint32_t instance_count,
|
|
uint64_t modifier) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t index_count = 0x%" PRIx32 "\n"
|
|
"\t index_addr = 0x%016" PRIx64 "\n"
|
|
"\t instance_count = 0x%" PRIx32 "\n"
|
|
"\t object_ids = 0x%016" PRIx64 "\n"
|
|
"\t modifier = 0x%016" PRIx64 "\n",
|
|
index_count, reinterpret_cast<uint64_t>(index_addr), instance_count,
|
|
reinterpret_cast<uint64_t>(object_ids), modifier);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
EXIT_NOT_IMPLEMENTED(index_addr == nullptr);
|
|
EXIT_NOT_IMPLEMENTED(object_ids == nullptr);
|
|
EXIT_NOT_IMPLEMENTED((reinterpret_cast<uint64_t>(index_addr) & 1u) != 0);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(9);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
auto index_vaddr = reinterpret_cast<uint64_t>(index_addr);
|
|
auto object_vaddr = reinterpret_cast<uint64_t>(object_ids);
|
|
|
|
cmd[0] = KYTY_PM4(9, Pm4::IT_DISPATCH_DRAW_PREAMBLE, 0u);
|
|
cmd[1] = index_count;
|
|
cmd[2] = static_cast<uint32_t>(index_vaddr & 0xffffffffu);
|
|
cmd[3] = static_cast<uint32_t>((index_vaddr >> 32u) & 0xffffffffu);
|
|
cmd[4] = (instance_count == 0 ? 1u : instance_count);
|
|
cmd[5] = static_cast<uint32_t>(object_vaddr & 0xffffffffu);
|
|
cmd[6] = static_cast<uint32_t>((object_vaddr >> 32u) & 0xffffffffu);
|
|
cmd[7] = instance_count;
|
|
cmd[8] = decode_draw_index_initiator(modifier) | 0x80u;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsDcbDrawIndexMultiInstancedGetSize() {
|
|
PRINT_NAME();
|
|
|
|
return 9u * 4u;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsUnknownIkfdtRIqCE(uint32_t* cmd, uint64_t arg1,
|
|
const volatile uint32_t* target,
|
|
uint32_t size_in_dwords, uint64_t arg4, uint64_t arg5) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t cmd = 0x%016" PRIx64 "\n"
|
|
"\t arg1 = 0x%016" PRIx64 "\n"
|
|
"\t target = 0x%016" PRIx64 "\n"
|
|
"\t size_in_dwords = %" PRIu32 "\n"
|
|
"\t arg4 = 0x%016" PRIx64 "\n"
|
|
"\t arg5 = 0x%016" PRIx64 "\n",
|
|
reinterpret_cast<uint64_t>(cmd), arg1, reinterpret_cast<uint64_t>(target), size_in_dwords,
|
|
arg4, arg5);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
auto op = (cmd[0] >> 8u) & 0xffu;
|
|
if (op != Pm4::IT_INDIRECT_BUFFER) {
|
|
return GRAPHICS5_ERROR_INVALID_PACKET;
|
|
}
|
|
|
|
auto vaddr = reinterpret_cast<uint64_t>(target);
|
|
auto cache_policy = static_cast<uint32_t>(arg1) & 0x3u;
|
|
|
|
cmd[1] = (cmd[1] & 0x3u) | (static_cast<uint32_t>(vaddr) & 0xfffffffcu);
|
|
cmd[2] = static_cast<uint32_t>(vaddr >> 32u);
|
|
cmd[3] = (cmd[3] & 0xcff00000u) | (cache_policy << 28u) | (size_in_dwords & 0xfffffu);
|
|
|
|
return OK;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbDrawIndexAuto(CommandBuffer* buf, uint32_t index_count,
|
|
uint64_t modifier) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t index_count = 0x%" PRIx32 "\n"
|
|
"\t modifier = 0x%016" PRIx64 "\n",
|
|
index_count, modifier);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(3);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
cmd[0] = KYTY_PM4(3, Pm4::IT_DRAW_INDEX_AUTO, 0u);
|
|
cmd[1] = index_count;
|
|
cmd[2] = decode_draw_index_initiator(modifier) | 0x2u;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsDcbDrawIndexAutoGetSize() {
|
|
PRINT_NAME();
|
|
|
|
return 3u * 4u;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbDrawIndexOffset(CommandBuffer* buf, uint32_t index_offset,
|
|
uint32_t index_count, uint64_t modifier) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t index_offset = 0x%" PRIx32 "\n"
|
|
"\t index_count = 0x%" PRIx32 "\n"
|
|
"\t modifier = 0x%016" PRIx64 "\n",
|
|
index_offset, index_count, modifier);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(5);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
cmd[0] = KYTY_PM4(5, Pm4::IT_DRAW_INDEX_OFFSET_2, 0u);
|
|
cmd[1] = (index_count == 0 ? 1u : index_count);
|
|
cmd[2] = index_offset;
|
|
cmd[3] = index_count;
|
|
cmd[4] = decode_draw_index_initiator(modifier);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsDcbDrawIndexOffsetGetSize() {
|
|
PRINT_NAME();
|
|
|
|
return 5u * 4u;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetBaseIndirectArgs(CommandBuffer* buf, uint32_t shader_type,
|
|
const volatile void* indirect_base_addr) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t shader_type = %" PRIu32 "\n"
|
|
"\t indirect_base_addr = 0x%016" PRIx64 "\n",
|
|
shader_type, reinterpret_cast<uint64_t>(indirect_base_addr));
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(4);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
const auto addr = reinterpret_cast<uint64_t>(indirect_base_addr);
|
|
|
|
cmd[0] = KYTY_PM4(4, Pm4::IT_SET_BASE, 0u) | (shader_type << 1u);
|
|
cmd[1] = 1u;
|
|
cmd[2] = static_cast<uint32_t>(addr) & ~0x7u;
|
|
cmd[3] = static_cast<uint32_t>(addr >> 32u);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbDrawIndexIndirect(CommandBuffer* buf,
|
|
uint32_t data_offset_in_bytes,
|
|
uint64_t modifier) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t data_offset = 0x%" PRIx32 "\n"
|
|
"\t modifier = 0x%016" PRIx64 "\n",
|
|
data_offset_in_bytes, modifier);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(5);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
const auto patch_offsets = decode_indirect_modifier_patch_offsets(modifier, true);
|
|
|
|
cmd[0] = KYTY_PM4(5, Pm4::IT_DRAW_INDEX_INDIRECT, 0u);
|
|
cmd[1] = data_offset_in_bytes;
|
|
cmd[2] = static_cast<uint32_t>(patch_offsets);
|
|
cmd[3] = static_cast<uint32_t>(patch_offsets >> 32u);
|
|
cmd[4] = decode_indirect_draw_initiator(modifier);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbDrawIndirect(CommandBuffer* buf, uint32_t data_offset_in_bytes,
|
|
uint64_t modifier) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t data_offset = 0x%" PRIx32 "\n"
|
|
"\t modifier = 0x%016" PRIx64 "\n",
|
|
data_offset_in_bytes, modifier);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(5);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
const auto patch_offsets = decode_indirect_modifier_patch_offsets(modifier, false);
|
|
|
|
cmd[0] = KYTY_PM4(5, Pm4::IT_DRAW_INDIRECT, 0u);
|
|
cmd[1] = data_offset_in_bytes;
|
|
cmd[2] = static_cast<uint32_t>(patch_offsets);
|
|
cmd[3] = static_cast<uint32_t>(patch_offsets >> 32u);
|
|
cmd[4] = decode_indirect_draw_initiator(modifier);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbDrawIndexIndirectMulti(
|
|
CommandBuffer* buf, uint32_t data_offset_in_bytes, uint32_t count_indirect,
|
|
uint32_t max_count_or_count, const volatile void* count_addr, uint32_t stride_in_bytes,
|
|
uint64_t modifier) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t data_offset = 0x%" PRIx32 "\n"
|
|
"\t count_indirect = 0x%" PRIx32 "\n"
|
|
"\t max_count_or_count = 0x%" PRIx32 "\n"
|
|
"\t count_addr = 0x%016" PRIx64 "\n"
|
|
"\t stride_in_bytes = 0x%" PRIx32 "\n"
|
|
"\t modifier = 0x%016" PRIx64 "\n",
|
|
data_offset_in_bytes, count_indirect, max_count_or_count,
|
|
reinterpret_cast<uint64_t>(count_addr), stride_in_bytes, modifier);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
EXIT_NOT_IMPLEMENTED((count_indirect & ~1u) != 0);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(10);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
const auto patch_offsets = decode_indirect_modifier_patch_offsets(modifier, true);
|
|
const auto count_vaddr = reinterpret_cast<uint64_t>(count_addr);
|
|
|
|
cmd[0] = KYTY_PM4(10, Pm4::IT_DRAW_INDEX_INDIRECT_MULTI, 0u);
|
|
cmd[1] = data_offset_in_bytes;
|
|
cmd[2] = static_cast<uint32_t>(patch_offsets);
|
|
cmd[3] = static_cast<uint32_t>(patch_offsets >> 32u);
|
|
cmd[4] = (count_indirect & 1u) << 30u;
|
|
cmd[5] = max_count_or_count;
|
|
cmd[6] = static_cast<uint32_t>(count_vaddr) & ~0x3u;
|
|
cmd[7] = static_cast<uint32_t>(count_vaddr >> 32u);
|
|
cmd[8] = stride_in_bytes;
|
|
cmd[9] = decode_indirect_draw_initiator(modifier);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsDcbDrawIndirectGetSize() {
|
|
PRINT_NAME();
|
|
|
|
return 5u * 4u;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbDispatchIndirect(CommandBuffer* buf,
|
|
uint32_t data_offset_in_bytes, uint32_t flags) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t data_offset = 0x%" PRIx32 "\n"
|
|
"\t flags = 0x%08" PRIx32 "\n",
|
|
data_offset_in_bytes, flags);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(3);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
cmd[0] = KYTY_PM4(3, Pm4::IT_DISPATCH_INDIRECT, 0u);
|
|
cmd[1] = data_offset_in_bytes;
|
|
cmd[2] = (flags & 0xa038u) | 0x41u;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsDcbDispatchIndirectGetSize() {
|
|
PRINT_NAME();
|
|
|
|
return 3u * 4u;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbEventWrite(CommandBuffer* buf, uint8_t event_type,
|
|
const volatile void* address) {
|
|
PRINT_NAME();
|
|
|
|
static std::atomic<uint32_t> log_count {0};
|
|
if (log_count.fetch_add(1) < 64) {
|
|
LOGF("\t event_type = 0x%02" PRIx8 "\n"
|
|
"\t address = 0x%016" PRIx64 "\n",
|
|
event_type, reinterpret_cast<uint64_t>(address));
|
|
}
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
EXIT_NOT_IMPLEMENTED(event_type > 0x3fu);
|
|
|
|
buf->DbgDump();
|
|
|
|
const bool addressed_event = ((event_type & 0xfeu) == 0x38u);
|
|
auto* cmd = buf->AllocateDW(addressed_event ? 4u : 2u);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
cmd[0] = KYTY_PM4(addressed_event ? 4u : 2u, Pm4::IT_EVENT_WRITE, 0u);
|
|
|
|
if (event_type == 7u || event_type == 15u || event_type == 16u) {
|
|
cmd[1] = 0x400u | event_type;
|
|
} else if (addressed_event) {
|
|
auto addr = reinterpret_cast<uint64_t>(address);
|
|
|
|
cmd[1] = 0x100u | event_type;
|
|
cmd[2] = static_cast<uint32_t>(addr) & 0xfffffff8u;
|
|
cmd[3] = static_cast<uint32_t>(addr >> 32u);
|
|
} else {
|
|
cmd[1] = event_type & 0x3fu;
|
|
}
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsAcbEventWrite(CommandBuffer* buf, uint8_t event_type,
|
|
const volatile void* address) {
|
|
return GraphicsDcbEventWrite(buf, event_type, address);
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbAcquireMem(CommandBuffer* buf, uint8_t engine, uint32_t cb_db_op,
|
|
uint32_t gcr_cntl, const volatile void* base,
|
|
uint64_t size_bytes, uint32_t poll_cycles) {
|
|
PRINT_NAME();
|
|
|
|
static std::atomic<uint32_t> log_count {0};
|
|
if (log_count.fetch_add(1) < 64) {
|
|
LOGF("\t engine = 0x%02" PRIx8 "\n"
|
|
"\t cb_db_op = 0x%08" PRIx32 "\n"
|
|
"\t gcr_cntl = 0x%08" PRIx32 "\n"
|
|
"\t base = 0x%016" PRIx64 "\n"
|
|
"\t size_bytes = 0x%016" PRIx64 "\n"
|
|
"\t poll_cycles = %" PRIu32 "\n",
|
|
engine, cb_db_op, gcr_cntl, reinterpret_cast<uint64_t>(base), size_bytes, poll_cycles);
|
|
}
|
|
|
|
bool no_size = (static_cast<int64_t>(size_bytes) == -1);
|
|
auto vaddr = reinterpret_cast<uint64_t>(base);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
|
|
static std::atomic<uint32_t> warning_log_count {0};
|
|
const bool log_warning = (warning_log_count.fetch_add(1) < 64);
|
|
if (!no_size && (size_bytes & 0xffu) != 0) {
|
|
if (log_warning) {
|
|
LOGF_COLOR(Log::Color::Red, "\t warning: size_bytes is not 256-byte aligned\n");
|
|
}
|
|
}
|
|
if (!no_size && (size_bytes >> 40u) != 0) {
|
|
if (log_warning) {
|
|
LOGF_COLOR(Log::Color::Red, "\t warning: size_bytes is too large\n");
|
|
}
|
|
}
|
|
if ((vaddr & 0xffu) != 0) {
|
|
if (log_warning) {
|
|
LOGF_COLOR(Log::Color::Red, "\t warning: base is not 256-byte aligned\n");
|
|
}
|
|
}
|
|
if ((vaddr >> 40u) != 0) {
|
|
if (log_warning) {
|
|
LOGF_COLOR(Log::Color::Red, "\t warning: base is too high\n");
|
|
}
|
|
}
|
|
if (engine > 1) {
|
|
if (log_warning) {
|
|
LOGF_COLOR(Log::Color::Red, "\t warning: unsupported engine 0x%02" PRIx8 "\n", engine);
|
|
}
|
|
}
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(8);
|
|
|
|
if (cmd == nullptr) {
|
|
LOGF_COLOR(Log::Color::Red, "\t failed to allocate acquire_mem packet\n");
|
|
return nullptr;
|
|
}
|
|
|
|
cmd[0] = KYTY_PM4(8, Pm4::IT_NOP, Pm4::R_ACQUIRE_MEM);
|
|
cmd[1] = (static_cast<uint32_t>(engine & 1u) << 31u) | cb_db_op;
|
|
cmd[2] = (no_size ? 0 : static_cast<uint32_t>(size_bytes >> 8u));
|
|
cmd[3] = 0;
|
|
cmd[4] = static_cast<uint32_t>(vaddr >> 8u);
|
|
cmd[5] = 0;
|
|
cmd[6] = poll_cycles / 40;
|
|
cmd[7] = gcr_cntl;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsDcbAcquireMemGetSize() {
|
|
PRINT_NAME();
|
|
|
|
return 8u * 4u;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsAcbAcquireMem(CommandBuffer* buf, uint32_t gcr_cntl,
|
|
const volatile void* base, uint64_t size_bytes,
|
|
uint32_t poll_cycles) {
|
|
return GraphicsDcbAcquireMem(buf, 1, 0, gcr_cntl, base, size_bytes, poll_cycles);
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsAcbAcquireMemGetSize() {
|
|
PRINT_NAME();
|
|
|
|
return GraphicsDcbAcquireMemGetSize();
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbCondExec(CommandBuffer* buf, const volatile uint32_t* address,
|
|
uint32_t num_dwords) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t address = 0x%016" PRIx64 "\n"
|
|
"\t num_dwords = %" PRIu32 "\n",
|
|
reinterpret_cast<uint64_t>(address), num_dwords);
|
|
|
|
if (buf == nullptr || address == nullptr) {
|
|
LOGF_COLOR(Log::Color::Red, "\t invalid arguments\n");
|
|
return nullptr;
|
|
}
|
|
if ((reinterpret_cast<uintptr_t>(address) & 0x3u) != 0) {
|
|
LOGF_COLOR(Log::Color::Red, "\t condExec command address is not 4-byte aligned\n");
|
|
return nullptr;
|
|
}
|
|
if (num_dwords > 0x3fffu) {
|
|
LOGF_COLOR(Log::Color::Red, "\t condExec range is too large: %" PRIu32 "\n", num_dwords);
|
|
return nullptr;
|
|
}
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(5);
|
|
|
|
if (cmd == nullptr) {
|
|
LOGF_COLOR(Log::Color::Red, "\t failed to allocate condExec packet\n");
|
|
return nullptr;
|
|
}
|
|
|
|
auto addr = reinterpret_cast<uint64_t>(address);
|
|
|
|
cmd[0] = KYTY_PM4(5, Pm4::IT_COND_EXEC, 0u);
|
|
cmd[1] = static_cast<uint32_t>(addr) & 0xfffffffcu;
|
|
cmd[2] = static_cast<uint32_t>(addr >> 32u);
|
|
cmd[3] = 0;
|
|
cmd[4] = num_dwords & 0x3fffu;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsDcbCondExecGetSize() {
|
|
PRINT_NAME();
|
|
|
|
return 20;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsAcbCondExec(CommandBuffer* buf, const volatile uint32_t* address,
|
|
uint32_t num_dwords) {
|
|
return GraphicsDcbCondExec(buf, address, num_dwords);
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsAcbCondExecGetSize() {
|
|
PRINT_NAME();
|
|
|
|
return GraphicsDcbCondExecGetSize();
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsAcbJumpGetSize() {
|
|
return 0x10u;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsAcbWaitRegMem(CommandBuffer* buf, uint8_t size,
|
|
uint8_t compare_function, uint8_t cache_policy,
|
|
const volatile void* address, uint64_t reference,
|
|
uint64_t mask, uint32_t poll_cycles) {
|
|
return GraphicsDcbWaitRegMem(buf, size, compare_function, 0, cache_policy, address, reference,
|
|
mask, poll_cycles);
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsAcbDmaData(CommandBuffer* buf, uint8_t engine, uint8_t dst,
|
|
uint8_t dst_cache_policy, uint64_t dst_address_or_offset,
|
|
uint8_t src, uint8_t src_cache_policy,
|
|
uint64_t src_address_or_offset_or_immediate,
|
|
uint32_t num_bytes, uint8_t wait_for_previous,
|
|
uint8_t write_confirm, uint8_t block_engine) {
|
|
return GraphicsDcbDmaData(buf, engine, dst, dst_cache_policy, dst_address_or_offset, src,
|
|
src_cache_policy, src_address_or_offset_or_immediate, num_bytes,
|
|
wait_for_previous, write_confirm, block_engine);
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsAcbCopyData(CommandBuffer* buf, uint8_t dst,
|
|
uint8_t dst_cache_policy, uint64_t dst_address,
|
|
uint8_t src, uint8_t src_cache_policy,
|
|
uint64_t src_address_or_immediate, uint8_t item_size,
|
|
uint8_t write_confirm) {
|
|
const auto dcb_src = (src == 5 ? static_cast<uint8_t>(5u << 1u) : src);
|
|
return GraphicsDcbCopyData(buf, dst, dst_cache_policy, dst_address, dcb_src, src_cache_policy,
|
|
src_address_or_immediate, item_size, write_confirm);
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsAcbDispatchIndirect(CommandBuffer* buf,
|
|
const volatile void* indirect_args,
|
|
uint32_t modifier) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t indirect_args = 0x%016" PRIx64 "\n"
|
|
"\t modifier = 0x%08" PRIx32 "\n",
|
|
reinterpret_cast<uint64_t>(indirect_args), modifier);
|
|
|
|
if (buf == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(4);
|
|
|
|
if (cmd == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
const auto args_addr = reinterpret_cast<uint64_t>(indirect_args);
|
|
|
|
cmd[0] = KYTY_PM4(4, Pm4::IT_DISPATCH_INDIRECT, 0u);
|
|
cmd[1] = static_cast<uint32_t>(args_addr & 0xffffffffu);
|
|
cmd[2] = static_cast<uint32_t>((args_addr >> 32u) & 0xffffffffu);
|
|
cmd[3] = (modifier & 0xa038u) | 0x41u;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsAcbWriteData(CommandBuffer* buf, uint8_t dst, uint8_t cache_policy,
|
|
uint64_t address_or_offset, const void* data,
|
|
uint32_t num_dwords, uint8_t increment,
|
|
uint8_t write_confirm) {
|
|
return GraphicsDcbWriteData(buf, dst, cache_policy, address_or_offset, data, num_dwords,
|
|
increment, write_confirm);
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbStallCommandBufferParser(CommandBuffer* buf) {
|
|
PRINT_NAME();
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(2);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
cmd[0] = KYTY_PM4(2, Pm4::IT_PFP_SYNC_ME, 0u);
|
|
cmd[1] = 0;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbCopyData(CommandBuffer* buf, uint8_t dst,
|
|
uint8_t dst_cache_policy, uint64_t dst_address,
|
|
uint8_t src, uint8_t src_cache_policy,
|
|
uint64_t src_address_or_immediate, uint8_t item_size,
|
|
uint8_t write_confirm) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t dst = 0x%02" PRIx8 "\n"
|
|
"\t dst_cache_policy = 0x%02" PRIx8 "\n"
|
|
"\t dst_address = 0x%016" PRIx64 "\n"
|
|
"\t src = 0x%02" PRIx8 "\n"
|
|
"\t src_cache_policy = 0x%02" PRIx8 "\n"
|
|
"\t src_address_or_immediate = 0x%016" PRIx64 "\n"
|
|
"\t item_size = 0x%02" PRIx8 "\n"
|
|
"\t write_confirm = 0x%02" PRIx8 "\n",
|
|
dst, dst_cache_policy, dst_address, src, src_cache_policy, src_address_or_immediate,
|
|
item_size, write_confirm);
|
|
|
|
if (buf == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto* cmd = buf->AllocateDW(6);
|
|
|
|
if (cmd == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
cmd[0] = KYTY_PM4(6, Pm4::IT_COPY_DATA, 0u);
|
|
cmd[1] = ((static_cast<uint32_t>(src) >> 1u) & 0xfu) |
|
|
(((static_cast<uint32_t>(dst) >> 1u) & 0xfu) << 8u) |
|
|
((static_cast<uint32_t>(src_cache_policy) & 0x3u) << 13u) |
|
|
((static_cast<uint32_t>(item_size) & 0x1u) << 16u) |
|
|
((static_cast<uint32_t>(write_confirm) & 0x1u) << 20u) |
|
|
((static_cast<uint32_t>(dst_cache_policy) & 0x3u) << 25u) |
|
|
((static_cast<uint32_t>(src) & 0x1u) << 30u);
|
|
cmd[2] = static_cast<uint32_t>(src_address_or_immediate & 0xffffffffu);
|
|
cmd[3] = static_cast<uint32_t>((src_address_or_immediate >> 32u) & 0xffffffffu);
|
|
cmd[4] = static_cast<uint32_t>(dst_address & 0xffffffffu);
|
|
cmd[5] = static_cast<uint32_t>((dst_address >> 32u) & 0xffffffffu);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbDmaData(CommandBuffer* buf, uint8_t engine, uint8_t dst,
|
|
uint8_t dst_cache_policy, uint64_t dst_address_or_offset,
|
|
uint8_t src, uint8_t src_cache_policy,
|
|
uint64_t src_address_or_offset_or_immediate,
|
|
uint32_t num_bytes, uint8_t wait_for_previous,
|
|
uint8_t write_confirm, uint8_t block_engine) {
|
|
if (buf == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto src_address = src_address_or_offset_or_immediate;
|
|
switch (src) {
|
|
case 0x14: src_address = (engine == 1u ? 0x30148u : 0x30174u); break;
|
|
case 0x24: src_address = (engine == 1u ? 0x30150u : 0x3017cu); break;
|
|
case 0x64: src_address = (engine == 1u ? 0x30158u : 0x30184u); break;
|
|
default: break;
|
|
}
|
|
|
|
auto* cmd = buf->AllocateDW(7);
|
|
|
|
if (cmd == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
cmd[0] = KYTY_PM4(7, Pm4::IT_DMA_DATA, 0u);
|
|
cmd[1] = (static_cast<uint32_t>(engine) & 0x1u) |
|
|
((static_cast<uint32_t>(src_cache_policy) & 0x3u) << 13u) |
|
|
((static_cast<uint32_t>(dst) & 0x3u) << 20u) |
|
|
((static_cast<uint32_t>(dst_cache_policy) & 0x3u) << 25u) |
|
|
((static_cast<uint32_t>(src) & 0x3u) << 29u) |
|
|
((static_cast<uint32_t>(block_engine) & 0x1u) << 31u);
|
|
cmd[2] = static_cast<uint32_t>(src_address & 0xffffffffu);
|
|
cmd[3] = static_cast<uint32_t>((src_address >> 32u) & 0xffffffffu);
|
|
cmd[4] = static_cast<uint32_t>(dst_address_or_offset & 0xffffffffu);
|
|
cmd[5] = static_cast<uint32_t>((dst_address_or_offset >> 32u) & 0xffffffffu);
|
|
cmd[6] = (num_bytes & 0x03ffffffu) | ((static_cast<uint32_t>(src) & 0x4u) << 24u) |
|
|
((static_cast<uint32_t>(dst) & 0x4u) << 25u) |
|
|
((static_cast<uint32_t>(src) & 0x8u) << 25u) |
|
|
((static_cast<uint32_t>(dst) & 0x8u) << 26u) |
|
|
((static_cast<uint32_t>(wait_for_previous) & 0x1u) << 30u) |
|
|
((static_cast<uint32_t>(write_confirm) & 0x1u) << 31u);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbJump(CommandBuffer* buf, uint8_t mode, uint8_t cache_policy,
|
|
const uint32_t* target, uint32_t size_in_dwords) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t mode = 0x%02" PRIx8 "\n"
|
|
"\t cache_policy = 0x%02" PRIx8 "\n"
|
|
"\t target = 0x%016" PRIx64 "\n"
|
|
"\t size_in_dwords = %" PRIu32 "\n",
|
|
mode, cache_policy, reinterpret_cast<uint64_t>(target), size_in_dwords);
|
|
|
|
if (buf == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto* cmd = buf->AllocateDW(4);
|
|
|
|
if (cmd == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto vaddr = reinterpret_cast<uint64_t>(target);
|
|
|
|
cmd[0] = KYTY_PM4(4, Pm4::IT_INDIRECT_BUFFER, 0u);
|
|
cmd[1] = static_cast<uint32_t>(vaddr) & ~0x3u;
|
|
cmd[2] = static_cast<uint32_t>(vaddr >> 32u);
|
|
cmd[3] = 0x0f200000u | ((static_cast<uint32_t>(cache_policy) & 0x3u) << 28u) |
|
|
((static_cast<uint32_t>(mode) & 0x1u) << 20u) | (size_in_dwords & 0xfffffu);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsDcbJumpGetSize() {
|
|
PRINT_NAME();
|
|
|
|
return 16;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsDcbRewindGetSize() {
|
|
PRINT_NAME();
|
|
|
|
return 8;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbRewind(CommandBuffer* buf, uint32_t initial_state) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t initial_state = 0x%08" PRIx32 "\n", initial_state);
|
|
|
|
if (buf == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto* cmd = buf->AllocateDW(2);
|
|
|
|
if (cmd == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
cmd[0] = KYTY_PM4(2, Pm4::IT_REWIND, 0u);
|
|
cmd[1] = (initial_state & 0x1u) << 31u;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetPredication(CommandBuffer* buf, uint8_t condition, uint8_t op,
|
|
uint8_t wait_op, const volatile void* address,
|
|
uint32_t count_in_dwords) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t condition = 0x%02" PRIx8 "\n"
|
|
"\t op = 0x%02" PRIx8 "\n"
|
|
"\t wait_op = 0x%02" PRIx8 "\n"
|
|
"\t address = 0x%016" PRIx64 "\n"
|
|
"\t count_in_dwords = %" PRIu32 "\n",
|
|
condition, op, wait_op, reinterpret_cast<uint64_t>(address), count_in_dwords);
|
|
|
|
if (buf == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto* cmd = buf->AllocateDW(4);
|
|
|
|
if (cmd == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto addr = reinterpret_cast<uint64_t>(address);
|
|
|
|
cmd[0] = KYTY_PM4(4, Pm4::IT_SET_PREDICATION, 0u);
|
|
cmd[1] = ((static_cast<uint32_t>(condition) & 0x1u) << 8u) |
|
|
((static_cast<uint32_t>(wait_op) & 0x1u) << 12u) |
|
|
((static_cast<uint32_t>(op) & 0x7u) << 16u);
|
|
cmd[2] = static_cast<uint32_t>(addr) & ~0xfu;
|
|
cmd[3] = static_cast<uint32_t>(addr >> 32u);
|
|
|
|
(void)count_in_dwords;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsUnknownKRzWekV120(CommandBuffer* buf, uint32_t arg1, uint32_t arg2,
|
|
uint32_t arg3) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t argc = 4\n"
|
|
"\t arg0 = 0x%016" PRIx64 "\n"
|
|
"\t arg1 = 0x%08" PRIx32 "\n"
|
|
"\t arg2 = 0x%08" PRIx32 "\n"
|
|
"\t arg3 = 0x%08" PRIx32 "\n",
|
|
reinterpret_cast<uint64_t>(buf), arg1, arg2, arg3);
|
|
|
|
if (buf == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto* cmd = buf->AllocateDW(3);
|
|
|
|
if (cmd == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
cmd[0] = 0xc0017a00u;
|
|
cmd[1] = 0x20000243u;
|
|
|
|
uint32_t word8 = 0x400u;
|
|
word8 |= (arg1 & 0x3u);
|
|
word8 |= (arg2 & 0x3u) << 6u;
|
|
word8 |= (arg3 & 0x1u) << 14u;
|
|
|
|
cmd[2] = word8;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsDmaDataPatchSetDstAddressOrOffset(uint32_t* cmd,
|
|
uint64_t dst_address_or_offset) {
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
auto op = (cmd[0] >> 8u) & 0xffu;
|
|
if (op == Pm4::IT_DMA_DATA) {
|
|
cmd[4] = static_cast<uint32_t>(dst_address_or_offset & 0xffffffffu);
|
|
cmd[5] = static_cast<uint32_t>((dst_address_or_offset >> 32u) & 0xffffffffu);
|
|
return OK;
|
|
}
|
|
|
|
return GRAPHICS5_ERROR_INVALID_PACKET;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsDmaDataPatchSetSrcAddressOrOffsetOrImmediate(
|
|
uint32_t* cmd, uint64_t src_address_or_offset_or_immediate) {
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
auto op = (cmd[0] >> 8u) & 0xffu;
|
|
if (op == Pm4::IT_DMA_DATA) {
|
|
cmd[2] = static_cast<uint32_t>(src_address_or_offset_or_immediate & 0xffffffffu);
|
|
cmd[3] = static_cast<uint32_t>((src_address_or_offset_or_immediate >> 32u) & 0xffffffffu);
|
|
return OK;
|
|
}
|
|
|
|
return GRAPHICS5_ERROR_INVALID_PACKET;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsGetPacketSize(uint32_t* packet) {
|
|
const auto cmd_id = packet[0];
|
|
if ((cmd_id & 0x3fffff00u) == 0x3fff1000u) {
|
|
return 1;
|
|
}
|
|
|
|
return KYTY_PM4_LEN(cmd_id);
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsSetPacketPredication(uint32_t* packet, uint32_t predication) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t packet = 0x%016" PRIx64 "\n"
|
|
"\t predication = 0x%08" PRIx32 "\n",
|
|
reinterpret_cast<uint64_t>(packet), predication);
|
|
|
|
LOGF("\t packet0 = 0x%08" PRIx32 ", op = 0x%02" PRIx32 ", r = 0x%02" PRIx32
|
|
", len = %" PRIu32 "\n",
|
|
packet[0], (packet[0] >> 8u) & 0xffu, KYTY_PM4_R(packet[0]),
|
|
GraphicsGetPacketSize(packet));
|
|
|
|
packet[0] = (packet[0] & ~1u) | (static_cast<uint8_t>(predication) == 1 ? 1u : 0u);
|
|
|
|
return OK;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsSetRangePredication(uint32_t* start, const volatile uint32_t* end,
|
|
uint32_t predication) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t start = 0x%016" PRIx64 "\n"
|
|
"\t end = 0x%016" PRIx64 "\n"
|
|
"\t predication = 0x%08" PRIx32 "\n",
|
|
reinterpret_cast<uint64_t>(start), reinterpret_cast<uint64_t>(end), predication);
|
|
|
|
auto* packet = start;
|
|
auto* range_end = const_cast<uint32_t*>(reinterpret_cast<const volatile uint32_t*>(end));
|
|
auto packet_va = reinterpret_cast<uintptr_t>(packet);
|
|
auto end_va = reinterpret_cast<uintptr_t>(range_end);
|
|
|
|
if (packet_va >= end_va) {
|
|
return OK;
|
|
}
|
|
|
|
const uint32_t predication_bit = (static_cast<uint8_t>(predication) == 1 ? 1u : 0u);
|
|
while (packet_va < end_va) {
|
|
const auto cmd_id = packet[0];
|
|
packet[0] = (cmd_id & ~1u) | predication_bit;
|
|
|
|
auto size = KYTY_PM4_LEN(cmd_id);
|
|
if ((cmd_id & 0x3fffff00u) == 0x3fff1000u) {
|
|
size = 1;
|
|
}
|
|
|
|
packet_va += size * sizeof(uint32_t);
|
|
packet = reinterpret_cast<uint32_t*>(packet_va);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsRewindPatchSetRewindState(uint32_t* cmd, uint8_t state) {
|
|
if (((cmd[0] >> 8u) & 0xffu) != Pm4::IT_REWIND) {
|
|
return GRAPHICS5_ERROR_INVALID_PACKET;
|
|
}
|
|
|
|
cmd[1] = (cmd[1] & 0x7fffffffu) | (static_cast<uint32_t>(state) << 31u);
|
|
return OK;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsCondExecPatchSetEnd(uint32_t* cmd, const volatile uint32_t* buffer) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t cmd = 0x%016" PRIx64 "\n"
|
|
"\t buffer = 0x%016" PRIx64 "\n",
|
|
reinterpret_cast<uint64_t>(cmd), reinterpret_cast<uint64_t>(buffer));
|
|
|
|
if (cmd == nullptr || buffer == nullptr) {
|
|
return GRAPHICS5_ERROR_INVALID_PACKET;
|
|
}
|
|
|
|
auto op = (cmd[0] >> 8u) & 0xffu;
|
|
if (op != Pm4::IT_COND_EXEC) {
|
|
return GRAPHICS5_ERROR_INVALID_PACKET;
|
|
}
|
|
|
|
auto* packet_end = cmd + 5;
|
|
auto* range_end = const_cast<uint32_t*>(reinterpret_cast<const volatile uint32_t*>(buffer));
|
|
if (range_end < packet_end) {
|
|
return GRAPHICS5_ERROR_INVALID_PACKET;
|
|
}
|
|
|
|
auto num_dwords = static_cast<uint64_t>(range_end - packet_end);
|
|
if (num_dwords > 0x3fffu) {
|
|
return GRAPHICS5_ERROR_INVALID_PACKET;
|
|
}
|
|
|
|
cmd[4] = (cmd[4] & ~0x3fffu) | static_cast<uint32_t>(num_dwords);
|
|
return OK;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsCondExecPatchSetCommandAddress(uint32_t* cmd,
|
|
const volatile uint32_t* command) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t cmd = 0x%016" PRIx64 "\n"
|
|
"\t command = 0x%016" PRIx64 "\n",
|
|
reinterpret_cast<uint64_t>(cmd), reinterpret_cast<uint64_t>(command));
|
|
|
|
if (cmd == nullptr || command == nullptr) {
|
|
return GRAPHICS5_ERROR_INVALID_PACKET;
|
|
}
|
|
|
|
auto op = (cmd[0] >> 8u) & 0xffu;
|
|
if (op != Pm4::IT_COND_EXEC || (reinterpret_cast<uintptr_t>(command) & 0x3u) != 0) {
|
|
return GRAPHICS5_ERROR_INVALID_PACKET;
|
|
}
|
|
|
|
auto addr = reinterpret_cast<uint64_t>(command);
|
|
cmd[1] = (cmd[1] & 0x3u) | (static_cast<uint32_t>(addr) & 0xfffffffcu);
|
|
cmd[2] = static_cast<uint32_t>(addr >> 32u);
|
|
|
|
return OK;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbWriteData(CommandBuffer* buf, uint8_t dst, uint8_t cache_policy,
|
|
uint64_t address_or_offset, const void* data,
|
|
uint32_t num_dwords, uint8_t increment,
|
|
uint8_t write_confirm) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t dst = 0x%02" PRIx8 "\n"
|
|
"\t cache_policy = 0x%02" PRIx8 "\n"
|
|
"\t address_or_offset = 0x%016" PRIx64 "\n"
|
|
"\t data = 0x%016" PRIx64 "\n"
|
|
"\t num_dwords = %" PRIu32 "\n"
|
|
"\t increment = 0x%02" PRIx8 "\n"
|
|
"\t write_confirm = 0x%02" PRIx8 "\n",
|
|
dst, cache_policy, address_or_offset, reinterpret_cast<uint64_t>(data), num_dwords,
|
|
increment, write_confirm);
|
|
|
|
if (buf == nullptr || data == nullptr) {
|
|
LOGF_COLOR(Log::Color::Red, "\t invalid arguments\n");
|
|
return nullptr;
|
|
}
|
|
if ((4 + num_dwords - 2u) > 0x3fffu) {
|
|
LOGF_COLOR(Log::Color::Red, "\t packet is too large\n");
|
|
return nullptr;
|
|
}
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(4 + num_dwords);
|
|
|
|
if (cmd == nullptr) {
|
|
LOGF_COLOR(Log::Color::Red, "\t failed to allocate command\n");
|
|
return nullptr;
|
|
}
|
|
|
|
const auto dst_value = static_cast<uint32_t>(dst);
|
|
const auto write_confirm_value =
|
|
(dst == 0u ? 0u : (static_cast<uint32_t>(write_confirm) & 0x1u));
|
|
|
|
cmd[0] = KYTY_PM4(4 + num_dwords, Pm4::IT_WRITE_DATA, 0u);
|
|
cmd[1] = ((dst_value & 0x1u) << 30u) | ((dst_value & 0x1eu) << 7u) |
|
|
((static_cast<uint32_t>(increment) & 0x1u) << 16u) | (write_confirm_value << 20u) |
|
|
((static_cast<uint32_t>(cache_policy) & 0x3u) << 25u);
|
|
cmd[2] = static_cast<uint32_t>(address_or_offset) & ~0x3u;
|
|
cmd[3] = static_cast<uint32_t>(address_or_offset >> 32u);
|
|
|
|
memcpy(cmd + 4, data, static_cast<size_t>(num_dwords) * 4);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsDcbWriteDataGetSize(uint32_t num_dwords) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t num_dwords = %" PRIu32 "\n", num_dwords);
|
|
|
|
return 4u * num_dwords + 16u;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbGetLodStats(CommandBuffer* buf, uint8_t cache_policy,
|
|
const volatile void* buffer,
|
|
uint32_t buffer_size_in_bytes, uint32_t reset_count,
|
|
uint8_t force_reset, uint8_t report_and_reset,
|
|
uint32_t reporting_interval_in_100k_clocks) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t cache_policy = 0x%02" PRIx8 "\n"
|
|
"\t buffer = 0x%016" PRIx64 "\n"
|
|
"\t buffer_size_in_bytes = %" PRIu32 "\n"
|
|
"\t reset_count = %" PRIu32 "\n"
|
|
"\t force_reset = 0x%02" PRIx8 "\n"
|
|
"\t report_and_reset = 0x%02" PRIx8 "\n"
|
|
"\t reporting_interval_in_100k_clocks = %" PRIu32 "\n",
|
|
cache_policy, reinterpret_cast<uint64_t>(buffer), buffer_size_in_bytes, reset_count,
|
|
force_reset, report_and_reset, reporting_interval_in_100k_clocks);
|
|
|
|
if (buf == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(5);
|
|
|
|
if (cmd == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
const auto buffer_addr = reinterpret_cast<uint64_t>(buffer);
|
|
|
|
cmd[0] = KYTY_PM4(5, Pm4::IT_GET_LOD_STATS, 0u);
|
|
cmd[1] = buffer_size_in_bytes;
|
|
cmd[2] = static_cast<uint32_t>(buffer_addr & 0xffffffc0u);
|
|
cmd[3] = static_cast<uint32_t>((buffer_addr >> 32u) & 0xffffffffu);
|
|
cmd[4] = ((static_cast<uint32_t>(cache_policy) & 0x3u) << 28u) |
|
|
((static_cast<uint32_t>(report_and_reset) & 0x1u) << 19u) |
|
|
((static_cast<uint32_t>(force_reset) & 0x1u) << 18u) | ((reset_count & 0xffu) << 10u) |
|
|
((reporting_interval_in_100k_clocks & 0xffu) << 2u);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsWaitRegMemPatchAddress(uint32_t* cmd, const volatile void* address) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t cmd = 0x%016" PRIx64 "\n"
|
|
"\t address = 0x%016" PRIx64 "\n",
|
|
reinterpret_cast<uint64_t>(cmd), reinterpret_cast<uint64_t>(address));
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
auto vaddr = reinterpret_cast<uint64_t>(address);
|
|
auto op = (cmd[0] >> 8u) & 0xffu;
|
|
|
|
if (op == Pm4::IT_NOP && KYTY_PM4_R(cmd[0]) == Pm4::R_WAIT_MEM_32) {
|
|
cmd[1] = static_cast<uint32_t>(vaddr) & ~0x3u;
|
|
cmd[2] = static_cast<uint32_t>(vaddr >> 32u) & 0x3ffffu;
|
|
} else if (op == Pm4::IT_NOP && KYTY_PM4_R(cmd[0]) == Pm4::R_WAIT_MEM_64) {
|
|
cmd[1] = static_cast<uint32_t>(vaddr) & ~0x7u;
|
|
cmd[2] = static_cast<uint32_t>(vaddr >> 32u) & 0x3ffffu;
|
|
} else {
|
|
EXIT("unsupported waitOnAddress packet for address patch: 0x%08" PRIx32 "\n", cmd[0]);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsWaitRegMemPatchReference(uint32_t* cmd, uint64_t reference) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t cmd = 0x%016" PRIx64 "\n"
|
|
"\t reference = 0x%016" PRIx64 "\n",
|
|
reinterpret_cast<uint64_t>(cmd), reference);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
auto op = (cmd[0] >> 8u) & 0xffu;
|
|
|
|
if (op == Pm4::IT_NOP && KYTY_PM4_R(cmd[0]) == Pm4::R_WAIT_MEM_32) {
|
|
cmd[4] = static_cast<uint32_t>(reference & 0xffffffffu);
|
|
} else if (op == Pm4::IT_NOP && KYTY_PM4_R(cmd[0]) == Pm4::R_WAIT_MEM_64) {
|
|
cmd[5] = static_cast<uint32_t>(reference & 0xffffffffu);
|
|
cmd[6] = static_cast<uint32_t>((reference >> 32u) & 0xffffffffu);
|
|
} else {
|
|
EXIT("unsupported waitOnAddress packet for reference patch: 0x%08" PRIx32 "\n", cmd[0]);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsQueueEndOfPipeActionPatchAddress(uint32_t* cmd,
|
|
const volatile Label* address) {
|
|
PRINT_NAME();
|
|
|
|
// Not sure
|
|
|
|
LOGF("\t cmd = 0x%016" PRIx64 "\n"
|
|
"\t address = 0x%016" PRIx64 "\n",
|
|
reinterpret_cast<uint64_t>(cmd), reinterpret_cast<uint64_t>(address));
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
auto vaddr = reinterpret_cast<uint64_t>(address);
|
|
auto op = (cmd[0] >> 8u) & 0xffu;
|
|
|
|
if ((op == Pm4::IT_NOP && KYTY_PM4_R(cmd[0]) == Pm4::R_RELEASE_MEM) ||
|
|
op == Pm4::IT_RELEASE_MEM) {
|
|
cmd[3] = static_cast<uint32_t>(vaddr & 0xffffffffu);
|
|
cmd[4] = static_cast<uint32_t>((vaddr >> 32u) & 0xffffffffu);
|
|
} else if (op == Pm4::IT_EVENT_WRITE_EOP) {
|
|
cmd[2] = static_cast<uint32_t>(vaddr & 0xffffffffu);
|
|
cmd[3] = (cmd[3] & 0xffff0000u) | static_cast<uint32_t>((vaddr >> 32u) & 0xffffu);
|
|
} else {
|
|
EXIT("unsupported queueEndOfPipeAction packet for address patch: 0x%08" PRIx32 "\n",
|
|
cmd[0]);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsQueueEndOfPipeActionPatchData(uint32_t* cmd, uint32_t context_id,
|
|
uint32_t data_sel, uint64_t data) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t cmd = 0x%016" PRIx64 "\n"
|
|
"\t context_id = 0x%08" PRIx32 "\n"
|
|
"\t data_sel = 0x%08" PRIx32 "\n"
|
|
"\t data = 0x%016" PRIx64 "\n",
|
|
reinterpret_cast<uint64_t>(cmd), context_id, data_sel, data);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
auto op = (cmd[0] >> 8u) & 0xffu;
|
|
|
|
if ((op == Pm4::IT_NOP && KYTY_PM4_R(cmd[0]) == Pm4::R_RELEASE_MEM) ||
|
|
op == Pm4::IT_RELEASE_MEM) {
|
|
uint64_t packet_data = data;
|
|
if (op == Pm4::IT_NOP && KYTY_PM4_R(cmd[0]) == Pm4::R_RELEASE_MEM && context_id > 1 &&
|
|
data_sel == 1) {
|
|
// Agc Core ring-buffer release packets pack the segment generation
|
|
// into bits 24..31 and wrap that byte every 256 submissions. The
|
|
// patch context carries the monotonic generation, so expand the
|
|
// packed value before it reaches the command processor.
|
|
packet_data = (static_cast<uint64_t>(context_id - 2u) << 24u) | (data & 0x00ffffffull);
|
|
}
|
|
|
|
cmd[5] = static_cast<uint32_t>(packet_data & 0xffffffffu);
|
|
cmd[6] = static_cast<uint32_t>((packet_data >> 32u) & 0xffffffffu);
|
|
} else if (op == Pm4::IT_EVENT_WRITE_EOP) {
|
|
cmd[4] = static_cast<uint32_t>(data & 0xffffffffu);
|
|
cmd[5] = static_cast<uint32_t>((data >> 32u) & 0xffffffffu);
|
|
} else {
|
|
EXIT("unsupported queueEndOfPipeAction packet for data patch: 0x%08" PRIx32 "\n", cmd[0]);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
static uint32_t wait_reg_mem_poll_cycles_to_packet(uint32_t poll_cycles) {
|
|
return std::min(poll_cycles >> 4u, 0xffffu);
|
|
}
|
|
|
|
static uint32_t wait_reg_mem32_control(uint8_t compare_function, uint8_t op, uint8_t cache_policy) {
|
|
return 0x10u | (static_cast<uint32_t>(compare_function) & 0x7u) |
|
|
((static_cast<uint32_t>(op) & 0x3u) << 8u) | ((static_cast<uint32_t>(op) & 0xcu) << 4u) |
|
|
((static_cast<uint32_t>(cache_policy) & 0x3u) << 25u);
|
|
}
|
|
|
|
static uint32_t wait_reg_mem64_control(uint8_t compare_function, uint8_t op, uint8_t cache_policy) {
|
|
return 0x10u | (static_cast<uint32_t>(compare_function) & 0x7u) |
|
|
((static_cast<uint32_t>(op) & 0x1u) << 8u) | ((static_cast<uint32_t>(op) & 0x6u) << 5u) |
|
|
((static_cast<uint32_t>(cache_policy) & 0x3u) << 25u);
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbWaitRegMem(CommandBuffer* buf, uint8_t size,
|
|
uint8_t compare_function, uint8_t op,
|
|
uint8_t cache_policy, const volatile void* address,
|
|
uint64_t reference, uint64_t mask,
|
|
uint32_t poll_cycles) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t size = 0x%02" PRIx8 "\n"
|
|
"\t compare_function = 0x%02" PRIx8 "\n"
|
|
"\t op = 0x%02" PRIx8 "\n"
|
|
"\t cache_policy = 0x%02" PRIx8 "\n"
|
|
"\t address = 0x%016" PRIx64 "\n"
|
|
"\t reference = 0x%016" PRIx64 "\n"
|
|
"\t mask = 0x%016" PRIx64 "\n"
|
|
"\t poll_cycles = %" PRIu32 "\n",
|
|
size, compare_function, op, cache_policy, reinterpret_cast<uint64_t>(address), reference,
|
|
mask, poll_cycles);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
if (size != 0 && size != 1) {
|
|
LOGF_COLOR(Log::Color::Red,
|
|
"\t warning: unsupported size 0x%02" PRIx8 ", expected 0 (32b) or 1 (64b)\n",
|
|
size);
|
|
return nullptr;
|
|
}
|
|
if (cache_policy > 3) {
|
|
LOGF_COLOR(Log::Color::Red,
|
|
"\t warning: unsupported cache_policy 0x%02" PRIx8 ", expected 0..3\n",
|
|
cache_policy);
|
|
}
|
|
|
|
buf->DbgDump();
|
|
|
|
auto address_value = reinterpret_cast<uint64_t>(address);
|
|
bool wait32 = (size == 0);
|
|
auto poll = wait_reg_mem_poll_cycles_to_packet(poll_cycles);
|
|
|
|
auto* cmd = buf->AllocateDW(wait32 ? 7 : 9);
|
|
|
|
if (cmd == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (wait32) {
|
|
cmd[0] = KYTY_PM4(7, Pm4::IT_NOP, Pm4::R_WAIT_MEM_32);
|
|
cmd[1] = static_cast<uint32_t>(address_value) & ~0x3u;
|
|
cmd[2] = static_cast<uint32_t>(address_value >> 32u) & 0x3ffffu;
|
|
cmd[3] = static_cast<uint32_t>(mask & 0xffffffffu);
|
|
cmd[4] = static_cast<uint32_t>(reference & 0xffffffffu);
|
|
cmd[5] = wait_reg_mem32_control(compare_function, op, cache_policy);
|
|
cmd[6] = poll;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
cmd[0] = KYTY_PM4(9, Pm4::IT_NOP, Pm4::R_WAIT_MEM_64);
|
|
cmd[1] = static_cast<uint32_t>(address_value) & ~0x7u;
|
|
cmd[2] = static_cast<uint32_t>(address_value >> 32u) & 0x3ffffu;
|
|
cmd[3] = static_cast<uint32_t>(reinterpret_cast<uint64_t>(mask) & 0xffffffffu);
|
|
cmd[4] = static_cast<uint32_t>((reinterpret_cast<uint64_t>(mask) >> 32u) & 0xffffffffu);
|
|
cmd[5] = static_cast<uint32_t>(reinterpret_cast<uint64_t>(reference) & 0xffffffffu);
|
|
cmd[6] = static_cast<uint32_t>((reinterpret_cast<uint64_t>(reference) >> 32u) & 0xffffffffu);
|
|
cmd[7] = wait_reg_mem64_control(compare_function, op, cache_policy);
|
|
cmd[8] = poll;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsDcbWaitOnAddressGetSize(uint32_t size) {
|
|
PRINT_NAME();
|
|
|
|
switch (size) {
|
|
case 0: return 14u * 4u;
|
|
case 1: return 16u * 4u;
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbPushMarker(CommandBuffer* buf, const char* str,
|
|
uint32_t /*color*/) {
|
|
if (buf == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (str == nullptr) {
|
|
str = "";
|
|
}
|
|
|
|
const auto len = strlen(str) + 1;
|
|
const auto payload_dwords = static_cast<uint32_t>((len + 3) / 4);
|
|
const auto size = 1u + (payload_dwords == 0 ? 1u : payload_dwords);
|
|
auto* cmd = buf->AllocateDW(size);
|
|
|
|
if (cmd == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
cmd[0] = KYTY_PM4(size, Pm4::IT_NOP, Pm4::R_PUSH_MARKER);
|
|
memset(cmd + 1, 0, static_cast<size_t>(size - 1) * sizeof(uint32_t));
|
|
memcpy(cmd + 1, str, len);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetMarker(CommandBuffer* buf, const char* str, uint32_t color) {
|
|
return GraphicsDcbPushMarker(buf, str, color);
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsAcbSetMarker(CommandBuffer* buf, const char* str, uint32_t color) {
|
|
return GraphicsDcbSetMarker(buf, str, color);
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsAcbPushMarker(CommandBuffer* buf, const char* str, uint32_t color) {
|
|
return GraphicsDcbPushMarker(buf, str, color);
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbPopMarker(CommandBuffer* buf) {
|
|
if (buf == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto* cmd = buf->AllocateDW(2);
|
|
|
|
if (cmd == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
cmd[0] = KYTY_PM4(2, Pm4::IT_NOP, Pm4::R_POP_MARKER);
|
|
cmd[1] = 0;
|
|
|
|
return cmd;
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsAcbPopMarker(CommandBuffer* buf) {
|
|
return GraphicsDcbPopMarker(buf);
|
|
}
|
|
|
|
uint32_t* KYTY_SYSV_ABI GraphicsDcbSetFlip(CommandBuffer* buf, uint32_t video_out_handle,
|
|
int32_t display_buffer_index, uint32_t flip_mode,
|
|
int64_t flip_arg) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t video_out_handle = %" PRIu32 "\n"
|
|
"\t display_buffer_index = %" PRId32 "\n"
|
|
"\t flip_mode = %" PRIu32 "\n"
|
|
"\t flip_arg = %" PRId64 "\n",
|
|
video_out_handle, display_buffer_index, flip_mode, flip_arg);
|
|
|
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
|
|
|
buf->DbgDump();
|
|
|
|
auto* cmd = buf->AllocateDW(6);
|
|
|
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
|
|
|
cmd[0] = KYTY_PM4(6, Pm4::IT_NOP, Pm4::R_FLIP);
|
|
cmd[1] = video_out_handle;
|
|
cmd[2] = display_buffer_index;
|
|
cmd[3] = flip_mode;
|
|
cmd[4] = static_cast<uint32_t>(static_cast<uint64_t>(flip_arg) & 0xffffffffu);
|
|
cmd[5] = static_cast<uint32_t>((static_cast<uint64_t>(flip_arg) >> 32u) & 0xffffffffu);
|
|
|
|
return cmd;
|
|
}
|
|
|
|
} // namespace Gen5
|
|
|
|
namespace Gen5Driver {
|
|
|
|
LIB_NAME("Graphics5Driver", "Graphics5Driver");
|
|
|
|
struct TessellationDriverState {
|
|
uint64_t tf_ring_base = 0;
|
|
uint32_t tf_ring_size = 0;
|
|
uint64_t hs_offchip_value0 = 0;
|
|
uint64_t hs_offchip_value1 = 0;
|
|
uint64_t hs_offchip_value2 = 0;
|
|
};
|
|
|
|
static TessellationDriverState g_tessellation_driver_state {};
|
|
|
|
struct Packet {
|
|
uint32_t* addr;
|
|
uint32_t dw_num;
|
|
uint8_t pad[4];
|
|
};
|
|
|
|
static bool dcb_has_queued_interrupt(const uint32_t* dcb, uint32_t size_in_dwords) {
|
|
if (dcb == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
for (uint32_t offset = 0; offset < size_in_dwords;) {
|
|
auto cmd_id = dcb[offset];
|
|
auto len = KYTY_PM4_LEN(cmd_id);
|
|
if (len == 0 || len > size_in_dwords - offset) {
|
|
return false;
|
|
}
|
|
|
|
auto op = (cmd_id >> 8u) & 0xffu;
|
|
if (op == Pm4::IT_NOP && KYTY_PM4_R(cmd_id) == Pm4::R_RELEASE_MEM && len >= 6) {
|
|
auto interrupt = (dcb[offset + 2] >> 24u) & 0x7u;
|
|
if (interrupt == 1 || interrupt == 2 || interrupt >= 4) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
offset += len;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static void submit_dcb(uint32_t* dcb, uint32_t size_in_dwords) {
|
|
GraphicsDbgDumpDcb("d", size_in_dwords, dcb);
|
|
EXIT_IF(g_renderer == nullptr);
|
|
g_renderer->GetGpu().Submit(dcb, size_in_dwords, nullptr, 0,
|
|
!dcb_has_queued_interrupt(dcb, size_in_dwords));
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsDriverSubmitDcb(const Packet* packet) {
|
|
PRINT_NAME();
|
|
|
|
EXIT_NOT_IMPLEMENTED(packet == nullptr);
|
|
EXIT_NOT_IMPLEMENTED(packet->pad[0] != 0);
|
|
|
|
LOGF("\t addr = 0x%016" PRIx64 "\n"
|
|
"\t dw_num = 0x%08" PRIx32 "\n",
|
|
reinterpret_cast<uint64_t>(packet->addr), packet->dw_num);
|
|
|
|
submit_dcb(packet->addr, packet->dw_num);
|
|
|
|
return OK;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsDriverSubmitMultiDcbs(uint32_t* const* dcb_gpu_addrs,
|
|
const uint32_t* dcb_sizes_in_dwords,
|
|
uint32_t count) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t count = %" PRIu32 "\n", count);
|
|
|
|
if (count == 0) {
|
|
return OK;
|
|
}
|
|
if (dcb_gpu_addrs == nullptr || dcb_sizes_in_dwords == nullptr) {
|
|
return LibKernel::KERNEL_ERROR_EINVAL;
|
|
}
|
|
|
|
for (uint32_t i = 0; i < count; i++) {
|
|
auto* dcb = dcb_gpu_addrs[i];
|
|
uint32_t size_in_dwords = dcb_sizes_in_dwords[i];
|
|
|
|
LOGF("\t dcb[%" PRIu32 "] = 0x%016" PRIx64 "\n"
|
|
"\t size[%" PRIu32 "] = 0x%08" PRIx32 "\n",
|
|
i, reinterpret_cast<uint64_t>(dcb), i, size_in_dwords);
|
|
|
|
if (dcb == nullptr) {
|
|
continue;
|
|
}
|
|
submit_dcb(dcb, size_in_dwords);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsDriverSubmitCommandBuffer(uint32_t queue, uint32_t* dcb,
|
|
uint32_t size_in_dwords) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t queue = 0x%08" PRIx32 "\n"
|
|
"\t dcb = 0x%016" PRIx64 "\n"
|
|
"\t size = 0x%08" PRIx32 "\n",
|
|
queue, reinterpret_cast<uint64_t>(dcb), size_in_dwords);
|
|
|
|
if (dcb == nullptr || size_in_dwords == 0) {
|
|
return OK;
|
|
}
|
|
|
|
submit_dcb(dcb, size_in_dwords);
|
|
|
|
return OK;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsDriverSubmitMultiCommandBuffers(uint32_t queue, uint32_t* const* dcbs,
|
|
const uint32_t* sizes_in_dwords,
|
|
uint32_t count) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t queue = 0x%08" PRIx32 "\n"
|
|
"\t count = %" PRIu32 "\n",
|
|
queue, count);
|
|
|
|
if (count == 0) {
|
|
return OK;
|
|
}
|
|
if (dcbs == nullptr || sizes_in_dwords == nullptr) {
|
|
return LibKernel::KERNEL_ERROR_EINVAL;
|
|
}
|
|
|
|
for (uint32_t i = 0; i < count; i++) {
|
|
GraphicsDriverSubmitCommandBuffer(queue, dcbs[i], sizes_in_dwords[i]);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
static void submit_acb(uint32_t queue, uint32_t* acb, uint32_t size_in_dwords) {
|
|
if (acb != nullptr && size_in_dwords >= 5) {
|
|
auto descriptor_addr =
|
|
static_cast<uint64_t>(acb[0]) | (static_cast<uint64_t>(acb[1]) << 32u);
|
|
auto descriptor_size = acb[2];
|
|
auto descriptor_flags = acb[3];
|
|
auto descriptor_magic = acb[4];
|
|
if (descriptor_addr != 0 && descriptor_size != 0 && descriptor_flags == 0 &&
|
|
descriptor_magic == 0x5533ccaau) {
|
|
LOGF("\t descriptor addr = 0x%016" PRIx64 "\n"
|
|
"\t descriptor size = 0x%08" PRIx32 "\n"
|
|
"\t descriptor magic = 0x%08" PRIx32 "\n",
|
|
descriptor_addr, descriptor_size, descriptor_magic);
|
|
acb = reinterpret_cast<uint32_t*>(descriptor_addr);
|
|
size_in_dwords = descriptor_size;
|
|
}
|
|
}
|
|
|
|
if (acb == nullptr || size_in_dwords == 0) {
|
|
return;
|
|
}
|
|
|
|
for (uint32_t i = 0; i < std::min<uint32_t>(size_in_dwords, 8); i++) {
|
|
LOGF("\t acb[%u] = 0x%08" PRIx32 "\n", i, acb[i]);
|
|
}
|
|
|
|
GraphicsDbgDumpDcb("a", size_in_dwords, acb);
|
|
|
|
const bool trigger_interrupt_on_done = !dcb_has_queued_interrupt(acb, size_in_dwords);
|
|
EXIT_IF(g_renderer == nullptr);
|
|
g_renderer->GetGpu().SubmitCompute(queue, acb, size_in_dwords, trigger_interrupt_on_done);
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsDriverSubmitAcb(uint32_t queue, const Packet* packet) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t queue = 0x%08" PRIx32 "\n"
|
|
"\t packet = 0x%016" PRIx64 "\n",
|
|
queue, reinterpret_cast<uint64_t>(packet));
|
|
|
|
if (packet == nullptr) {
|
|
return OK;
|
|
}
|
|
LOGF("\t acb = 0x%016" PRIx64 "\n"
|
|
"\t size = 0x%08" PRIx32 "\n"
|
|
"\t flags = 0x%02" PRIx8 "\n",
|
|
reinterpret_cast<uint64_t>(packet->addr), packet->dw_num, packet->pad[0]);
|
|
|
|
submit_acb(queue, packet->addr, packet->dw_num);
|
|
|
|
return OK;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsDriverSubmitMultiAcbs(uint32_t queue, uint32_t* const* acbs,
|
|
const uint32_t* sizes_in_dwords, uint32_t count) {
|
|
PRINT_NAME();
|
|
|
|
LOGF("\t queue = 0x%08" PRIx32 "\n"
|
|
"\t count = %" PRIu32 "\n",
|
|
queue, count);
|
|
|
|
if (count == 0) {
|
|
return OK;
|
|
}
|
|
if (acbs == nullptr || sizes_in_dwords == nullptr) {
|
|
return LibKernel::KERNEL_ERROR_EINVAL;
|
|
}
|
|
|
|
for (uint32_t i = 0; i < count; i++) {
|
|
submit_acb(queue, acbs[i], sizes_in_dwords[i]);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsDriverAddEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id,
|
|
void* udata) {
|
|
PRINT_NAME();
|
|
|
|
if (eq == LibKernel::EventQueue::KERNEL_EQUEUE_INVALID) {
|
|
return LibKernel::KERNEL_ERROR_EBADF;
|
|
}
|
|
|
|
EXIT_IF(g_renderer == nullptr);
|
|
return Sync::AddEqEvent(*g_renderer, eq, id, udata);
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsDriverDeleteEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id) {
|
|
PRINT_NAME();
|
|
|
|
if (eq == LibKernel::EventQueue::KERNEL_EQUEUE_INVALID) {
|
|
return LibKernel::KERNEL_ERROR_EBADF;
|
|
}
|
|
|
|
return Sync::DeleteEqEvent(eq, id);
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsDriverGetEqEventType(const LibKernel::EventQueue::KernelEvent* ev) {
|
|
PRINT_NAME();
|
|
|
|
if (ev == nullptr) {
|
|
return 0;
|
|
}
|
|
|
|
if (ev->filter == LibKernel::EventQueue::KERNEL_EVFILT_GRAPHICS) {
|
|
return static_cast<int>(ev->ident);
|
|
}
|
|
|
|
return static_cast<int>(ev->data);
|
|
}
|
|
|
|
uint32_t KYTY_SYSV_ABI GraphicsDriverGetEqContextId(const LibKernel::EventQueue::KernelEvent* ev) {
|
|
PRINT_NAME();
|
|
|
|
if (ev == nullptr) {
|
|
return 0;
|
|
}
|
|
|
|
if (ev->filter == LibKernel::EventQueue::KERNEL_EVFILT_GRAPHICS) {
|
|
return static_cast<uint32_t>(ev->data);
|
|
}
|
|
|
|
return static_cast<uint32_t>(ev->ident);
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsDriverSetTFRing(const volatile void* base, uint32_t size) {
|
|
PRINT_NAME();
|
|
|
|
g_tessellation_driver_state.tf_ring_base = reinterpret_cast<uint64_t>(base);
|
|
g_tessellation_driver_state.tf_ring_size = size;
|
|
|
|
LOGF("\t base = 0x%016" PRIx64 "\n"
|
|
"\t size = 0x%08" PRIx32 "\n",
|
|
g_tessellation_driver_state.tf_ring_base, g_tessellation_driver_state.tf_ring_size);
|
|
|
|
return OK;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsDriverSetHsOffchipParam(uint64_t value0, uint64_t value1,
|
|
uint64_t value2) {
|
|
PRINT_NAME();
|
|
|
|
g_tessellation_driver_state.hs_offchip_value0 = value0;
|
|
g_tessellation_driver_state.hs_offchip_value1 = value1;
|
|
g_tessellation_driver_state.hs_offchip_value2 = value2;
|
|
|
|
LOGF("\t value0 = 0x%016" PRIx64 "\n"
|
|
"\t value1 = 0x%016" PRIx64 "\n"
|
|
"\t value2 = 0x%016" PRIx64 "\n",
|
|
value0, value1, value2);
|
|
|
|
return OK;
|
|
}
|
|
|
|
bool KYTY_SYSV_ABI GraphicsDriverIsCaptureInProgress() {
|
|
PRINT_NAME();
|
|
|
|
return false;
|
|
}
|
|
|
|
int KYTY_SYSV_ABI GraphicsDriverUnknownU9ueyEhSkF4() {
|
|
PRINT_NAME();
|
|
|
|
return static_cast<int>(0x8a6c9018u);
|
|
}
|
|
|
|
} // namespace Gen5Driver
|
|
|
|
} // namespace Libs::Graphics
|