mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 22:06:59 +01:00
fix fetch shader V_SAD_U32, video-out buffer overlap
This commit is contained in:
@@ -1142,23 +1142,6 @@ void CommandProcessor::DrawIndex(uint32_t index_count, const void* index_addr, u
|
|||||||
"\n",
|
"\n",
|
||||||
vertex_offset_add, first_instance);
|
vertex_offset_add, first_instance);
|
||||||
}
|
}
|
||||||
const auto frame_num = GraphicsRunGetFrameNum();
|
|
||||||
if (frame_num >= 480) {
|
|
||||||
static std::atomic<uint32_t> log_count {0};
|
|
||||||
if (log_count.fetch_add(1, std::memory_order_relaxed) < 512) {
|
|
||||||
const auto& oa = m_ucfg.GetGdsOaCounter(m_ucfg.GetGdsOaState().GetIndex());
|
|
||||||
LOGF("QueuePoint DrawIndex: frame=%u submit=%" PRIu64
|
|
||||||
" queue=%d index_count=%u instances=%u prim=%u "
|
|
||||||
"es=0x%016" PRIx64 " ps=0x%016" PRIx64
|
|
||||||
" oa_index=%u oa_enabled=%s oa_addr=0x%04" PRIx32 " oa_space=0x%08" PRIx32 "\n",
|
|
||||||
frame_num, m_submit_id, m_scheduler.Queue(), index_count, instance_count,
|
|
||||||
m_ucfg.GetPrimType(), m_sh_ctx.GetVs().es_regs.data_addr,
|
|
||||||
m_sh_ctx.GetPs().ps_regs.data_addr, m_ucfg.GetGdsOaState().GetIndex(),
|
|
||||||
oa.IsCounterEnabled() ? "true" : "false", oa.GetAddressBytes(),
|
|
||||||
oa.GetSpaceAvailable());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderDrawIndex(m_submit_id, CurrentBuffer(), &m_ctx, &m_ucfg, &m_sh_ctx, m_index_type_and_size,
|
RenderDrawIndex(m_submit_id, CurrentBuffer(), &m_ctx, &m_ucfg, &m_sh_ctx, m_index_type_and_size,
|
||||||
index_count, index_addr, flags, type, instance_count,
|
index_count, index_addr, flags, type, instance_count,
|
||||||
render_target_slice_offset, vertex_offset_add, first_instance);
|
render_target_slice_offset, vertex_offset_add, first_instance);
|
||||||
@@ -1458,22 +1441,6 @@ void CommandProcessor::DrawIndexAuto(uint32_t index_count, uint32_t flags,
|
|||||||
Common::LockGuard lock(m_mutex);
|
Common::LockGuard lock(m_mutex);
|
||||||
|
|
||||||
CheckBuffer();
|
CheckBuffer();
|
||||||
const auto frame_num = GraphicsRunGetFrameNum();
|
|
||||||
if (frame_num >= 480) {
|
|
||||||
static std::atomic<uint32_t> log_count {0};
|
|
||||||
if (log_count.fetch_add(1, std::memory_order_relaxed) < 512) {
|
|
||||||
const auto& oa = m_ucfg.GetGdsOaCounter(m_ucfg.GetGdsOaState().GetIndex());
|
|
||||||
LOGF("QueuePoint DrawIndexAuto: frame=%u submit=%" PRIu64
|
|
||||||
" queue=%d index_count=%u instances=%u prim=%u "
|
|
||||||
"first_vertex=%u first_instance=%u es=0x%016" PRIx64 " ps=0x%016" PRIx64
|
|
||||||
" oa_index=%u oa_enabled=%s oa_addr=0x%04" PRIx32 " oa_space=0x%08" PRIx32 "\n",
|
|
||||||
frame_num, m_submit_id, m_scheduler.Queue(), index_count, instance_count,
|
|
||||||
m_ucfg.GetPrimType(), first_vertex, first_instance,
|
|
||||||
m_sh_ctx.GetVs().es_regs.data_addr, m_sh_ctx.GetPs().ps_regs.data_addr,
|
|
||||||
m_ucfg.GetGdsOaState().GetIndex(), oa.IsCounterEnabled() ? "true" : "false",
|
|
||||||
oa.GetAddressBytes(), oa.GetSpaceAvailable());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderDrawIndexAuto(m_submit_id, CurrentBuffer(), &m_ctx, &m_ucfg, &m_sh_ctx, index_count,
|
RenderDrawIndexAuto(m_submit_id, CurrentBuffer(), &m_ctx, &m_ucfg, &m_sh_ctx, index_count,
|
||||||
flags, render_target_slice_offset, instance_count, first_vertex,
|
flags, render_target_slice_offset, instance_count, first_vertex,
|
||||||
|
|||||||
@@ -2578,11 +2578,13 @@ void TextureCache::RefreshVideoOut(VideoOutVulkanImage* image, bool render_targe
|
|||||||
if (cached.gpu_modified) {
|
if (cached.gpu_modified) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto& info = cached.video_out;
|
const auto& info = cached.video_out;
|
||||||
const bool image_dirty = m_memory_tracker.IsRegionCpuModified(info.address, info.size);
|
const bool image_dirty = m_memory_tracker.IsRegionCpuModified(info.address, info.size);
|
||||||
const bool buffer_dirty = cached.buffer_modified ||
|
const bool buffer_overlap = m_buffer_cache.HasPageOverlap(info.address, info.size);
|
||||||
m_buffer_cache.IsRegionCpuModified(info.address, info.size) ||
|
const bool buffer_dirty =
|
||||||
m_buffer_cache.IsRegionGpuModified(info.address, info.size);
|
cached.buffer_modified ||
|
||||||
|
(buffer_overlap && (m_buffer_cache.IsRegionCpuModified(info.address, info.size) ||
|
||||||
|
m_buffer_cache.IsRegionGpuModified(info.address, info.size)));
|
||||||
if (!image_dirty && !buffer_dirty) {
|
if (!image_dirty && !buffer_dirty) {
|
||||||
if (info.compression == VideoOutCompression::Uncompressed ||
|
if (info.compression == VideoOutCompression::Uncompressed ||
|
||||||
CanUseVideoOutNativeWithoutUpload(info.compression, render_target, false, false)) {
|
CanUseVideoOutNativeWithoutUpload(info.compression, render_target, false, false)) {
|
||||||
|
|||||||
@@ -336,9 +336,21 @@ EmbeddedFetchData DetectEmbeddedVertexFetch(const Decoder::Program& decoded
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& inst: decoded.instructions) {
|
for (const auto& inst: decoded.instructions) {
|
||||||
if (data.loads.empty() && inst.opcode == Decoder::Opcode::VAddI32 &&
|
// Fetch shaders accumulate the draw's vertex offset in v0. The PS5 NGG ABI
|
||||||
IsDecodedVgpr(inst.dst) && inst.dst.reg == 0 && IsDecodedSgpr(inst.src0) &&
|
// seeds S_NGG_VERTEX_INDEX in v5 and applies the same offset there before fetching.
|
||||||
IsDecodedVgpr(inst.src1) && inst.src1.reg == 0) {
|
const bool vertex_index_accumulator =
|
||||||
|
IsDecodedVgpr(inst.dst) &&
|
||||||
|
(inst.dst.reg == 0 || (user_data_base == 8 && inst.dst.reg == 5));
|
||||||
|
uint32_t sad_zero = 0;
|
||||||
|
const bool vertex_offset_add =
|
||||||
|
vertex_index_accumulator && IsDecodedSgpr(inst.src0) &&
|
||||||
|
((inst.opcode == Decoder::Opcode::VAddI32 && IsDecodedVgpr(inst.src1) &&
|
||||||
|
inst.src1.reg == inst.dst.reg) ||
|
||||||
|
(user_data_base == 8 && inst.dst.reg == 5 &&
|
||||||
|
inst.opcode == Decoder::Opcode::VSadU32 && IsDecodedVgpr(inst.src2) &&
|
||||||
|
inst.src2.reg == inst.dst.reg &&
|
||||||
|
TryDecodedOperandConstant(sgprs, inst.src1, sad_zero) && sad_zero == 0));
|
||||||
|
if (data.loads.empty() && vertex_offset_add) {
|
||||||
const auto reg = DecodedSgprReg(inst.src0);
|
const auto reg = DecodedSgprReg(inst.src0);
|
||||||
if (reg >= user_data_base && reg - user_data_base < user_data_count) {
|
if (reg >= user_data_base && reg - user_data_base < user_data_count) {
|
||||||
if (offset_candidate >= 0 && offset_candidate != static_cast<int32_t>(reg)) {
|
if (offset_candidate >= 0 && offset_candidate != static_cast<int32_t>(reg)) {
|
||||||
|
|||||||
@@ -9009,14 +9009,29 @@ void CheckPs5GameExampleImageClearRuntimeShape() {
|
|||||||
|
|
||||||
void CheckEmbeddedFetchVertexOffset() {
|
void CheckEmbeddedFetchVertexOffset() {
|
||||||
const auto MakeFetch = [](std::initializer_list<std::pair<u32, u32>> adds,
|
const auto MakeFetch = [](std::initializer_list<std::pair<u32, u32>> adds,
|
||||||
std::optional<std::pair<u32, u32>> late_add = {}) {
|
std::optional<std::pair<u32, u32>> late_add = {},
|
||||||
|
u32 accumulator_vgpr = 0, bool ngg_sad = false) {
|
||||||
std::vector<u32> code;
|
std::vector<u32> code;
|
||||||
code.push_back(EncodeSMovB32(0, InlineU32(0)));
|
code.push_back(EncodeSMovB32(0, InlineU32(0)));
|
||||||
code.push_back(EncodeSmem0(0x02u, 20, 4));
|
code.push_back(EncodeSmem0(0x02u, 20, 4));
|
||||||
code.push_back(EncodeSmem1(0));
|
code.push_back(EncodeSmem1(0));
|
||||||
|
const auto AppendOffsets = [&]() {
|
||||||
|
for (const auto [sgpr, index_vgpr] : adds) {
|
||||||
|
if (ngg_sad) {
|
||||||
|
AppendVop3(&code, 0x15du, accumulator_vgpr, sgpr, InlineU32(0),
|
||||||
|
Vgpr(index_vgpr));
|
||||||
|
} else {
|
||||||
|
AppendVop3B(&code, 0x30fu, accumulator_vgpr, 0, sgpr,
|
||||||
|
Vgpr(index_vgpr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (ngg_sad) {
|
||||||
|
AppendOffsets();
|
||||||
|
}
|
||||||
code.push_back(EncodeVop2(0x01u, 0, Vgpr(8), 5));
|
code.push_back(EncodeVop2(0x01u, 0, Vgpr(8), 5));
|
||||||
for (const auto [sgpr, index_vgpr] : adds) {
|
if (!ngg_sad) {
|
||||||
AppendVop3B(&code, 0x30fu, 0, 0, sgpr, Vgpr(index_vgpr));
|
AppendOffsets();
|
||||||
}
|
}
|
||||||
code.push_back(EncodeMubuf0(0x03u, 0, true));
|
code.push_back(EncodeMubuf0(0x03u, 0, true));
|
||||||
code.push_back(EncodeMubuf1(9, 5, 0));
|
code.push_back(EncodeMubuf1(9, 5, 0));
|
||||||
@@ -9076,6 +9091,18 @@ void CheckEmbeddedFetchVertexOffset() {
|
|||||||
Resolve(valid, 5) == 5,
|
Resolve(valid, 5) == 5,
|
||||||
"canonical fetch offset or register index-offset precedence is wrong");
|
"canonical fetch offset or register index-offset precedence is wrong");
|
||||||
|
|
||||||
|
const auto ngg_code = MakeFetch({{18, 5}}, {}, 5, true);
|
||||||
|
Require("EmbeddedFetchNggVertexOffset", "encoding",
|
||||||
|
ngg_code[3] == 0xd55d0005u && ngg_code[4] == 0x04150012u,
|
||||||
|
"test does not encode the PS5 V_SAD_U32 vertex-offset prolog");
|
||||||
|
const auto ngg =
|
||||||
|
Compile("EmbeddedFetchNggVertexOffset", ngg_code, 8);
|
||||||
|
Require("EmbeddedFetchNggVertexOffset", "parse",
|
||||||
|
ngg.program.info.vertex_offset_sgpr == 18 && Resolve(ngg, 0) == 8 &&
|
||||||
|
Resolve(ngg, 5) == 5,
|
||||||
|
"PS5 NGG vertex-index offset or register index-offset precedence is "
|
||||||
|
"wrong");
|
||||||
|
|
||||||
const auto pointer = 0x5b7c5100u;
|
const auto pointer = 0x5b7c5100u;
|
||||||
const auto late = Compile("EmbeddedFetchLateOffset",
|
const auto late = Compile("EmbeddedFetchLateOffset",
|
||||||
MakeFetch({}, std::pair<u32, u32>{18, 0}), pointer);
|
MakeFetch({}, std::pair<u32, u32>{18, 0}), pointer);
|
||||||
|
|||||||
Reference in New Issue
Block a user