mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-04-28 21:38:03 +03:00

* gnm_driver: added `sceGnmRegisterOwner` and `sceGnmRegisterResource` * video_out: `sceVideoOutGetDeviceCapabilityInfo` for sdk runtime * gnm_driver: correct vqid index range * amdgpu: indirect buffer, release mem and some additional irq modes * amdgpu: added ASC commands processor * shader_recompiler: added support for fetch instance id * amdgpu: classic bitfields for T# representation (debugging experience) * renderer_vulkan: skip zero sized VBs from binding * texture_cache: image upload logic moved into `Image` object * gnm_driver: `sceGnmDingDong` implementation * texture_cache: `Image` usage flags moved; correct VO buffer pitch
86 lines
3 KiB
C++
86 lines
3 KiB
C++
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include <boost/container/static_vector.hpp>
|
|
#include "shader_recompiler/frontend/decode.h"
|
|
#include "shader_recompiler/frontend/fetch_shader.h"
|
|
|
|
namespace Shader::Gcn {
|
|
|
|
/**
|
|
* s_load_dwordx4 s[8:11], s[2:3], 0x00
|
|
* s_load_dwordx4 s[12:15], s[2:3], 0x04
|
|
* s_load_dwordx4 s[16:19], s[2:3], 0x08
|
|
* s_waitcnt lgkmcnt(0)
|
|
* buffer_load_format_xyzw v[4:7], v0, s[8:11], 0 idxen
|
|
* buffer_load_format_xyz v[8:10], v0, s[12:15], 0 idxen
|
|
* buffer_load_format_xy v[12:13], v0, s[16:19], 0 idxen
|
|
* s_waitcnt 0
|
|
* s_setpc_b64 s[0:1]
|
|
|
|
* s_load_dwordx4 s[4:7], s[2:3], 0x0
|
|
* s_waitcnt lgkmcnt(0)
|
|
* buffer_load_format_xyzw v[4:7], v0, s[4:7], 0 idxen
|
|
* s_load_dwordx4 s[4:7], s[2:3], 0x8
|
|
* s_waitcnt lgkmcnt(0)
|
|
* buffer_load_format_xyzw v[8:11], v0, s[4:7], 0 idxen
|
|
* s_waitcnt vmcnt(0) & expcnt(0) & lgkmcnt(0)
|
|
* s_setpc_b64 s[0:1]
|
|
|
|
* A normal fetch shader looks like the above, the instructions are generated
|
|
* using input semantics on cpu side. Load instructions can either be separate or interleaved
|
|
* We take the reverse way, extract the original input semantics from these instructions.
|
|
**/
|
|
|
|
std::vector<VertexAttribute> ParseFetchShader(const u32* code) {
|
|
std::vector<VertexAttribute> attributes;
|
|
GcnCodeSlice code_slice(code, code + std::numeric_limits<u32>::max());
|
|
GcnDecodeContext decoder;
|
|
|
|
struct VsharpLoad {
|
|
u32 dword_offset{};
|
|
s32 base_sgpr{};
|
|
s32 dst_reg{-1};
|
|
};
|
|
boost::container::static_vector<VsharpLoad, 16> loads;
|
|
|
|
u32 semantic_index = 0;
|
|
while (!code_slice.atEnd()) {
|
|
const auto inst = decoder.decodeInstruction(code_slice);
|
|
if (inst.opcode == Opcode::S_SETPC_B64) {
|
|
break;
|
|
}
|
|
|
|
if (inst.inst_class == InstClass::ScalarMemRd) {
|
|
loads.emplace_back(inst.control.smrd.offset, inst.src[0].code * 2, inst.dst[0].code);
|
|
continue;
|
|
}
|
|
|
|
if (inst.inst_class == InstClass::VectorMemBufFmt) {
|
|
// SRSRC is in units of 4 SPGRs while SBASE is in pairs of SGPRs
|
|
const u32 base_sgpr = inst.src[2].code * 4;
|
|
|
|
// Find the load instruction that loaded the V# to the SPGR.
|
|
// This is so we can determine its index in the vertex table.
|
|
const auto it = std::ranges::find_if(
|
|
loads, [&](VsharpLoad& load) { return load.dst_reg == base_sgpr; });
|
|
|
|
auto& attrib = attributes.emplace_back();
|
|
attrib.semantic = semantic_index++;
|
|
attrib.dest_vgpr = inst.src[1].code;
|
|
attrib.num_elements = inst.control.mubuf.count;
|
|
attrib.sgpr_base = it->base_sgpr;
|
|
attrib.dword_offset = it->dword_offset;
|
|
|
|
// Store instance id rate
|
|
attrib.instance_data = inst.src[0].code;
|
|
|
|
// Mark load as used.
|
|
it->dst_reg = -1;
|
|
}
|
|
}
|
|
|
|
return attributes;
|
|
}
|
|
|
|
} // namespace Shader::Gcn
|