mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-23 12:26:56 +02:00
graphics: synthesize always-visible occlusion query results
This commit is contained in:
@@ -103,7 +103,7 @@ public:
|
|||||||
uint32_t mode);
|
uint32_t mode);
|
||||||
void DispatchIndirect(uint32_t data_offset, uint32_t mode);
|
void DispatchIndirect(uint32_t data_offset, uint32_t mode);
|
||||||
void WaitFlipDone(uint32_t video_out_handle, uint32_t display_buffer_index);
|
void WaitFlipDone(uint32_t video_out_handle, uint32_t display_buffer_index);
|
||||||
void TriggerEvent(uint32_t event_type, uint32_t event_index);
|
void TriggerEvent(uint32_t event_type, uint32_t event_index, uint64_t event_address = 0);
|
||||||
|
|
||||||
void SetUserDataMarker(HW::UserSgprType type) { m_user_data_marker = type; }
|
void SetUserDataMarker(HW::UserSgprType type) { m_user_data_marker = type; }
|
||||||
[[nodiscard]] HW::UserSgprType GetUserDataMarker() const { return m_user_data_marker; }
|
[[nodiscard]] HW::UserSgprType GetUserDataMarker() const { return m_user_data_marker; }
|
||||||
@@ -178,8 +178,9 @@ private:
|
|||||||
uint32_t m_const_ram[0x3000] = {0};
|
uint32_t m_const_ram[0x3000] = {0};
|
||||||
|
|
||||||
FlipInfo m_flip;
|
FlipInfo m_flip;
|
||||||
uint64_t m_submit_id = 0;
|
uint64_t m_submit_id = 0;
|
||||||
bool m_predicate_skip = false;
|
uint64_t m_synthetic_occlusion_counter = 0;
|
||||||
|
bool m_predicate_skip = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Libs::Graphics
|
} // namespace Libs::Graphics
|
||||||
|
|||||||
@@ -2147,12 +2147,19 @@ KYTY_CP_OP_PARSER(CpOpEventWrite) {
|
|||||||
|
|
||||||
EXIT_NOT_IMPLEMENTED(((cmd_id >> 8u) & 0xffu) != Pm4::IT_EVENT_WRITE);
|
EXIT_NOT_IMPLEMENTED(((cmd_id >> 8u) & 0xffu) != Pm4::IT_EVENT_WRITE);
|
||||||
|
|
||||||
uint32_t event_index = (buffer[0] >> 8u) & 0x7u;
|
const auto packet_size_dw = KYTY_PM4_LEN(cmd_id);
|
||||||
uint32_t event_type = (buffer[0]) & 0x3fu;
|
uint32_t event_index = (buffer[0] >> 8u) & 0x7u;
|
||||||
|
uint32_t event_type = (buffer[0]) & 0x3fu;
|
||||||
|
uint64_t event_address = 0;
|
||||||
|
|
||||||
cp.TriggerEvent(event_type, event_index);
|
if (event_type == 0x39u) {
|
||||||
|
EXIT_NOT_IMPLEMENTED(packet_size_dw != 4u);
|
||||||
|
event_address = buffer[1] | (static_cast<uint64_t>(buffer[2]) << 32u);
|
||||||
|
}
|
||||||
|
|
||||||
return KYTY_PM4_LEN(cmd_id) - 1u;
|
cp.TriggerEvent(event_type, event_index, event_address);
|
||||||
|
|
||||||
|
return packet_size_dw - 1u;
|
||||||
}
|
}
|
||||||
|
|
||||||
KYTY_CP_OP_PARSER(CpOpEventWriteEop) {
|
KYTY_CP_OP_PARSER(CpOpEventWriteEop) {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
#include <semaphore>
|
#include <semaphore>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -1467,12 +1468,14 @@ void CommandProcessor::TriggerEopEventAtEndOfPipe(uint32_t interrupt_context_id)
|
|||||||
Sync::TriggerEopEventAtEndOfPipe(CurrentBuffer(), interrupt_context_id);
|
Sync::TriggerEopEventAtEndOfPipe(CurrentBuffer(), interrupt_context_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandProcessor::TriggerEvent(uint32_t event_type, uint32_t event_index) {
|
void CommandProcessor::TriggerEvent(uint32_t event_type, uint32_t event_index,
|
||||||
|
uint64_t event_address) {
|
||||||
if (GraphicsRunDebugDumpEnabled()) {
|
if (GraphicsRunDebugDumpEnabled()) {
|
||||||
LOGF("CommandProcessor::TriggerEvent()\n"
|
LOGF("CommandProcessor::TriggerEvent()\n"
|
||||||
"\t event_type = 0x%08" PRIx32 "\n"
|
"\t event_type = 0x%08" PRIx32 "\n"
|
||||||
"\t event_index = 0x%08" PRIx32 "\n",
|
"\t event_index = 0x%08" PRIx32 "\n"
|
||||||
event_type, event_index);
|
"\t address = 0x%016" PRIx64 "\n",
|
||||||
|
event_type, event_index, event_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto valid_cache_event_index = event_index == 0x00000000 || event_index == 0x00000007;
|
const auto valid_cache_event_index = event_index == 0x00000000 || event_index == 0x00000007;
|
||||||
@@ -1509,12 +1512,36 @@ void CommandProcessor::TriggerEvent(uint32_t event_type, uint32_t event_index) {
|
|||||||
case 0x0000001a:
|
case 0x0000001a:
|
||||||
case 0x0000001b:
|
case 0x0000001b:
|
||||||
case 0x00000038:
|
case 0x00000038:
|
||||||
case 0x00000039:
|
|
||||||
case 0x0000003a:
|
case 0x0000003a:
|
||||||
LOGF("\t temporary: ignoring unsupported event_write type 0x%08" PRIx32
|
LOGF("\t temporary: ignoring unsupported event_write type 0x%08" PRIx32
|
||||||
", index 0x%08" PRIx32 "\n",
|
", index 0x%08" PRIx32 "\n",
|
||||||
event_type, event_index);
|
event_type, event_index);
|
||||||
break;
|
break;
|
||||||
|
case 0x00000039: {
|
||||||
|
if (event_index != 0x00000001 || event_address == 0 || (event_address & 0x7u) != 0) {
|
||||||
|
EXIT("invalid occlusion-counter dump: index=0x%08" PRIx32 ", address=0x%016" PRIx64
|
||||||
|
"\n",
|
||||||
|
event_index, event_address);
|
||||||
|
}
|
||||||
|
static std::once_flag warning_once;
|
||||||
|
std::call_once(warning_once, [] {
|
||||||
|
std::printf("Warning: game uses occlusion queries, which are currently treated as "
|
||||||
|
"always visible; GPU usage may be higher and FPS may be lower.\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Until host occlusion queries are implemented, publish an always-visible result. The
|
||||||
|
// PS5 layout contains one interleaved begin/end pair per DB, and bit 63 marks a result
|
||||||
|
// ready.
|
||||||
|
constexpr uint64_t ready_bit = 1ull << 63u;
|
||||||
|
constexpr uint64_t counter_mask = ready_bit - 1u;
|
||||||
|
auto* results = reinterpret_cast<volatile uint64_t*>(event_address);
|
||||||
|
const auto value = ready_bit | m_synthetic_occlusion_counter;
|
||||||
|
for (uint32_t db = 0; db < 16u; db++) {
|
||||||
|
results[db * 2u] = value;
|
||||||
|
}
|
||||||
|
m_synthetic_occlusion_counter = (m_synthetic_occlusion_counter + 1u) & counter_mask;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
EXIT("unknown event type: 0x%08" PRIx32 ", 0x%08" PRIx32 "\n", event_type, event_index);
|
EXIT("unknown event type: 0x%08" PRIx32 ", 0x%08" PRIx32 "\n", event_type, event_index);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22706,6 +22706,47 @@ void CheckPm4AcquireMemNoOp(RenderContext &renderer) {
|
|||||||
std::printf("[host] %-32s ok\n", "Pm4AcquireMemNoOp");
|
std::printf("[host] %-32s ok\n", "Pm4AcquireMemNoOp");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckPm4SyntheticOcclusionCounterDump(RenderContext &renderer) {
|
||||||
|
GraphicsInitJmpTables();
|
||||||
|
CommandProcessor processor(renderer);
|
||||||
|
constexpr uint64_t untouched = 0x1122334455667788ull;
|
||||||
|
constexpr uint64_t ready_bit = 1ull << 63u;
|
||||||
|
alignas(16) std::array<std::array<uint64_t, 2>, 16> results;
|
||||||
|
for (auto &pair : results) {
|
||||||
|
pair.fill(untouched);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto dump = [&](uint64_t *address) {
|
||||||
|
const auto raw_address = reinterpret_cast<uint64_t>(address);
|
||||||
|
std::array<uint32_t, 4> packet{
|
||||||
|
KYTY_PM4(4, Pm4::IT_EVENT_WRITE, Pm4::R_ZERO), 0x00000139u,
|
||||||
|
static_cast<uint32_t>(raw_address),
|
||||||
|
static_cast<uint32_t>(raw_address >> 32u)};
|
||||||
|
Pm4Execution execution;
|
||||||
|
return processor.Process(execution, packet.data(), packet.size());
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto begin_result = dump(&results[0][0]);
|
||||||
|
bool begin_written = begin_result == Pm4ProcessResult::Complete;
|
||||||
|
for (const auto &pair : results) {
|
||||||
|
begin_written &= pair[0] == ready_bit && pair[1] == untouched;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto end_result = dump(&results[0][1]);
|
||||||
|
bool end_written = end_result == Pm4ProcessResult::Complete;
|
||||||
|
uint64_t visible_samples = 0;
|
||||||
|
for (const auto &pair : results) {
|
||||||
|
end_written &= pair[0] == ready_bit && pair[1] == (ready_bit | 1u);
|
||||||
|
visible_samples += pair[1] - pair[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
Require("Pm4SyntheticOcclusionCounterDump", "always-visible result",
|
||||||
|
begin_written && end_written && visible_samples == results.size(),
|
||||||
|
"EVENT_WRITE did not publish valid nonzero begin/end counters to "
|
||||||
|
"every PS5 DB");
|
||||||
|
std::printf("[host] %-32s ok\n", "Pm4SyntheticOcclusionCounterDump");
|
||||||
|
}
|
||||||
|
|
||||||
void CheckPm4StencilInfoValueLane(RenderContext &renderer) {
|
void CheckPm4StencilInfoValueLane(RenderContext &renderer) {
|
||||||
CommandProcessor processor(renderer);
|
CommandProcessor processor(renderer);
|
||||||
constexpr std::array<uint32_t, 2> payload{0x00100801u, 0x28000000u};
|
constexpr std::array<uint32_t, 2> payload{0x00100801u, 0x28000000u};
|
||||||
@@ -23409,6 +23450,11 @@ int main(int argc, char **argv) {
|
|||||||
vulkan.CheckSchedulerTimeline();
|
vulkan.CheckSchedulerTimeline();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (argc == 2 && std::strcmp(argv[1], "--occlusion-dump-only") == 0) {
|
||||||
|
VulkanHarness vulkan;
|
||||||
|
CheckPm4SyntheticOcclusionCounterDump(vulkan.RuntimeRenderer());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (argc == 2 && std::strcmp(argv[1], "--descriptor-heap-only") == 0) {
|
if (argc == 2 && std::strcmp(argv[1], "--descriptor-heap-only") == 0) {
|
||||||
VulkanHarness vulkan;
|
VulkanHarness vulkan;
|
||||||
vulkan.CheckDescriptorHeapLargeSet();
|
vulkan.CheckDescriptorHeapLargeSet();
|
||||||
@@ -23651,6 +23697,7 @@ int main(int argc, char **argv) {
|
|||||||
CheckReferenceClockScale();
|
CheckReferenceClockScale();
|
||||||
CheckVulkan13FeatureRequirements();
|
CheckVulkan13FeatureRequirements();
|
||||||
CheckPm4AcquireMemNoOp(vulkan.RuntimeRenderer());
|
CheckPm4AcquireMemNoOp(vulkan.RuntimeRenderer());
|
||||||
|
CheckPm4SyntheticOcclusionCounterDump(vulkan.RuntimeRenderer());
|
||||||
CheckPm4StencilInfoValueLane(vulkan.RuntimeRenderer());
|
CheckPm4StencilInfoValueLane(vulkan.RuntimeRenderer());
|
||||||
CheckPm4DirectShaderRegisterFallback(vulkan.RuntimeRenderer());
|
CheckPm4DirectShaderRegisterFallback(vulkan.RuntimeRenderer());
|
||||||
CheckPm4GuardBandRegisterRanges(vulkan.RuntimeRenderer());
|
CheckPm4GuardBandRegisterRanges(vulkan.RuntimeRenderer());
|
||||||
|
|||||||
Reference in New Issue
Block a user