diff --git a/src/graphics/guest_gpu/graphicsRun.cpp b/src/graphics/guest_gpu/graphicsRun.cpp index 2316fc7..00f2c6f 100644 --- a/src/graphics/guest_gpu/graphicsRun.cpp +++ b/src/graphics/guest_gpu/graphicsRun.cpp @@ -1142,23 +1142,6 @@ void CommandProcessor::DrawIndex(uint32_t index_count, const void* index_addr, u "\n", vertex_offset_add, first_instance); } - const auto frame_num = GraphicsRunGetFrameNum(); - if (frame_num >= 480) { - static std::atomic 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, index_count, index_addr, flags, type, instance_count, 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); CheckBuffer(); - const auto frame_num = GraphicsRunGetFrameNum(); - if (frame_num >= 480) { - static std::atomic 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, flags, render_target_slice_offset, instance_count, first_vertex, diff --git a/src/graphics/host_gpu/renderer/textureCache.cpp b/src/graphics/host_gpu/renderer/textureCache.cpp index 4449e51..ee24f10 100644 --- a/src/graphics/host_gpu/renderer/textureCache.cpp +++ b/src/graphics/host_gpu/renderer/textureCache.cpp @@ -2578,11 +2578,13 @@ void TextureCache::RefreshVideoOut(VideoOutVulkanImage* image, bool render_targe if (cached.gpu_modified) { return; } - const auto& info = cached.video_out; - const bool image_dirty = m_memory_tracker.IsRegionCpuModified(info.address, info.size); - const bool buffer_dirty = cached.buffer_modified || - m_buffer_cache.IsRegionCpuModified(info.address, info.size) || - m_buffer_cache.IsRegionGpuModified(info.address, info.size); + const auto& info = cached.video_out; + const bool image_dirty = m_memory_tracker.IsRegionCpuModified(info.address, info.size); + const bool buffer_overlap = m_buffer_cache.HasPageOverlap(info.address, info.size); + const bool buffer_dirty = + 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 (info.compression == VideoOutCompression::Uncompressed || CanUseVideoOutNativeWithoutUpload(info.compression, render_target, false, false)) { diff --git a/src/graphics/shader/recompiler/ShaderRecompiler.cpp b/src/graphics/shader/recompiler/ShaderRecompiler.cpp index d22d9b9..f730569 100644 --- a/src/graphics/shader/recompiler/ShaderRecompiler.cpp +++ b/src/graphics/shader/recompiler/ShaderRecompiler.cpp @@ -336,9 +336,21 @@ EmbeddedFetchData DetectEmbeddedVertexFetch(const Decoder::Program& decoded } for (const auto& inst: decoded.instructions) { - if (data.loads.empty() && inst.opcode == Decoder::Opcode::VAddI32 && - IsDecodedVgpr(inst.dst) && inst.dst.reg == 0 && IsDecodedSgpr(inst.src0) && - IsDecodedVgpr(inst.src1) && inst.src1.reg == 0) { + // Fetch shaders accumulate the draw's vertex offset in v0. The PS5 NGG ABI + // seeds S_NGG_VERTEX_INDEX in v5 and applies the same offset there before fetching. + 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); if (reg >= user_data_base && reg - user_data_base < user_data_count) { if (offset_candidate >= 0 && offset_candidate != static_cast(reg)) { diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index cd8e089..2f975a1 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -9009,14 +9009,29 @@ void CheckPs5GameExampleImageClearRuntimeShape() { void CheckEmbeddedFetchVertexOffset() { const auto MakeFetch = [](std::initializer_list> adds, - std::optional> late_add = {}) { + std::optional> late_add = {}, + u32 accumulator_vgpr = 0, bool ngg_sad = false) { std::vector code; code.push_back(EncodeSMovB32(0, InlineU32(0))); code.push_back(EncodeSmem0(0x02u, 20, 4)); 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)); - for (const auto [sgpr, index_vgpr] : adds) { - AppendVop3B(&code, 0x30fu, 0, 0, sgpr, Vgpr(index_vgpr)); + if (!ngg_sad) { + AppendOffsets(); } code.push_back(EncodeMubuf0(0x03u, 0, true)); code.push_back(EncodeMubuf1(9, 5, 0)); @@ -9076,6 +9091,18 @@ void CheckEmbeddedFetchVertexOffset() { Resolve(valid, 5) == 5, "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 late = Compile("EmbeddedFetchLateOffset", MakeFetch({}, std::pair{18, 0}), pointer);