mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-25 12:26:51 +01:00
shader: read S_MEMREALTIME from the host device clock shifted to about 100 MHz
This commit is contained in:
@@ -13,6 +13,8 @@ namespace Libs::Graphics::ShaderRecompiler::Spirv {
|
||||
struct Profile {
|
||||
bool maintenance8 = false; // Dynamic texel offsets on image samples.
|
||||
bool native_float_min_max = false; // NMin/NMax give the guest's NaN and signed-zero results.
|
||||
// OpReadClockKHR Device tick in picoseconds; 0 without shaderDeviceClock.
|
||||
uint32_t device_clock_period_ps = 0;
|
||||
};
|
||||
|
||||
inline constexpr Profile DefaultProfile {};
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <bit>
|
||||
#include <optional>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter {
|
||||
@@ -881,6 +882,22 @@ uint32_t EmitGetShaderBase(ValueEmitContext& ctx) {
|
||||
return ctx.Def(IR::Value(uint64_t {0}));
|
||||
}
|
||||
|
||||
uint32_t EmitReadRealtimeClock(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
auto& state = ctx.state;
|
||||
const auto period = state.profile.device_clock_period_ps;
|
||||
if (period == 0u) {
|
||||
ctx.Fail(inst, "requires shaderDeviceClock");
|
||||
}
|
||||
state.builder.RequireExtension("SPV_KHR_shader_clock");
|
||||
state.builder.RequireCapability(spv::CapabilityShaderClockKHR);
|
||||
const auto clock =
|
||||
Unary(state, spv::OpReadClockKHR, TypeU64(state), ConstantU32(state, spv::ScopeDevice));
|
||||
// S_MEMREALTIME counts at 100 MHz. Shift the host clock by the most bits that keep its tick at
|
||||
// most 15000 ps (2/3 of 100 MHz): 1 GHz shifts by 3 to 125 MHz; 100 MHz and slower stay.
|
||||
const uint32_t shift = std::bit_width(7500u / period);
|
||||
return EmitShiftRightLogical64(ctx, clock, IR::Value(shift));
|
||||
}
|
||||
|
||||
void EmitUnreachable(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
ctx.Fail(inst, "must be lowered before SPIR-V emission");
|
||||
}
|
||||
|
||||
@@ -240,6 +240,7 @@ uint32_t EmitGetAttributeF16(ValueEmitContext& ctx, const IR::Inst&
|
||||
uint32_t EmitGetInterpolationParameter(ValueEmitContext& ctx, const IR::Inst& inst);
|
||||
void EmitSetAttribute(ValueEmitContext& ctx, const IR::Inst& inst);
|
||||
uint32_t EmitGetShaderBase(ValueEmitContext& ctx);
|
||||
uint32_t EmitReadRealtimeClock(ValueEmitContext& ctx, const IR::Inst& inst);
|
||||
inline constexpr auto EmitGetSrtResource = EmitVoid;
|
||||
inline constexpr auto EmitGetBufferResource = EmitGetSrtResource;
|
||||
uint32_t EmitGetBufferResourceIndex(ValueEmitContext& ctx, const IR::Inst& inst);
|
||||
|
||||
@@ -235,9 +235,9 @@ void EmitDirectInstruction(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto op = inst.GetOpcode();
|
||||
if (ctx.half != 0 &&
|
||||
(op == Op::Ballot || op == Op::ReadFirstLane || op == Op::SubgroupUMinU32 ||
|
||||
op == Op::ReadConstBuffer ||
|
||||
op == Op::ReadConstBuffer || op == Op::ReadRealtimeClock ||
|
||||
(op == Op::LoadAddressU32 && ctx.Memory(inst).kind == IR::ResourceKind::ScalarAddress))) {
|
||||
// Whole-wave results and SMEM loads (SGPR operands, no EXEC) are identical in both halves.
|
||||
// Whole-wave results, clocks and SMEM loads (SGPR operands, no EXEC) match in both halves.
|
||||
ctx.Define(inst, ctx.other_half->Result(inst));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "graphics/shader/recompiler/frontend/translate/Translator.h"
|
||||
#include "graphics/shader/recompiler/frontend/decode/ImageOps.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend {
|
||||
|
||||
@@ -969,17 +967,9 @@ void Translator::EmitMemory(const Decoder::Instruction& inst) {
|
||||
case Decoder::Opcode::S_BUFFER_LOAD_DWORDX4:
|
||||
case Decoder::Opcode::S_BUFFER_LOAD_DWORDX8:
|
||||
case Decoder::Opcode::S_BUFFER_LOAD_DWORDX16: return S_LOAD(inst, false);
|
||||
case Decoder::Opcode::S_MEMREALTIME: {
|
||||
static std::atomic_flag warned = ATOMIC_FLAG_INIT;
|
||||
if (!warned.test_and_set(std::memory_order_relaxed)) {
|
||||
Log::WriteToConsoleAndLog(
|
||||
"Warning: S_MEMREALTIME uses placeholder UINT64_MAX; real-time clock not implemented.\n");
|
||||
}
|
||||
for (uint32_t component = 0; component < 2; component++) {
|
||||
WriteOperand(ScalarDestinationOperand(inst.dst, component), IR::Value(UINT32_MAX));
|
||||
}
|
||||
return;
|
||||
}
|
||||
case Decoder::Opcode::S_MEMREALTIME:
|
||||
return WriteU32Pair(inst.dst,
|
||||
ExtractU64(IR::U64(ir.Emit(IR::ValueOpcode::ReadRealtimeClock))));
|
||||
|
||||
case Decoder::Opcode::BUFFER_LOAD_UBYTE:
|
||||
case Decoder::Opcode::BUFFER_LOAD_UBYTE_D16:
|
||||
|
||||
@@ -10,6 +10,7 @@ VALUE_OPCODE(ConditionRef, U1, U1)
|
||||
VALUE_OPCODE(GetUserData, U32, ScalarReg)
|
||||
VALUE_OPCODE(GetDispatchThreadExtent, U32, U32)
|
||||
VALUE_OPCODE(GetShaderBase, U64)
|
||||
VALUE_OPCODE(ReadRealtimeClock, U64)
|
||||
VALUE_OPCODE(MeshDrawParameter, U32, U32)
|
||||
VALUE_OPCODE(MeshAllocate, Void, U32)
|
||||
VALUE_OPCODE(TessellationBase, U32, U32)
|
||||
|
||||
Reference in New Issue
Block a user