Compare commits

...

10 Commits

Author SHA1 Message Date
nmzik e9425e101d shader: add missing RDNA2 ALU opcodes
Add missing scalar and vector opcodes with compute tests.

Original work by @Pouare514 in #176.

Co-authored-by: Pouare514 <julienaulycee@gmail.com>
2026-09-02 01:56:55 +04:00
CheesyPoofs3460 04b404f3c9 controller: enable the DualSense HIDAPI driver, light bar and adaptive triggers (#437)
* controller: enable the DualSense HIDAPI driver, light bar and adaptive triggers

Three additions. SDL was opening a DualSense through the generic gamepad path, so SDL_GameControllerHasLED and SDL_GameControllerGetNumTouchpads both reported nothing and no touchpad events ever arrived - enabling the PS5 HIDAPI driver before SDL_InitSubSystem is what makes the light bar and the existing touchpad support reachable. PadSetLightBar validated its arguments and returned OK without touching the pad; it now drives the LED. PadSetTriggerEffect did the same; it now translates the mode and parameters into a DualSense trigger block and sends it.

* controller: fix DualSense effects

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
2026-09-02 00:53:19 +04:00
nmzik 80225015c5 renderer: enable storage for color images 2026-09-01 23:54:17 +04:00
nmzik 0c4dfd565e renderer: emulate clip-disabled screen-space positions 2026-09-01 21:39:11 +04:00
nmzik 0c8d7a1e49 shader: DPP row-xmask 2026-09-01 21:02:19 +04:00
nmzik a2150c70bb network: implement Linux getsockname 2026-09-01 20:50:57 +04:00
nmzik 160cf5352c http: new abi 2026-09-01 20:50:57 +04:00
nmzik 3b6b3c2040 pm4: handle reserved depth control fields 2026-09-01 20:50:57 +04:00
nmzik 63dd3917e2 reduce runtime logging 2026-09-01 20:50:57 +04:00
nmzik 2333c235f1 loader: TLS patch fix 2026-09-01 20:50:57 +04:00
31 changed files with 675 additions and 107 deletions
@@ -136,7 +136,6 @@ static HW::ColorControl DecodeColorControl(uint32_t value) {
static HW::DepthControl DecodeDepthControl(uint32_t value) {
HW::DepthControl r {};
EXIT_NOT_IMPLEMENTED((value & 0xc0000000u) != 0);
r.stencil_enable = KYTY_PM4_GET(value, DB_DEPTH_CONTROL, STENCIL_ENABLE) != 0;
r.z_enable = KYTY_PM4_GET(value, DB_DEPTH_CONTROL, Z_ENABLE) != 0;
+2 -2
View File
@@ -490,7 +490,7 @@ static void ClipCheck(const HW::ClipControl& c) {
// dx_linear_attr_clip_enable preserves linear (noperspective) attributes at clip-generated
// vertices, which Vulkan provides as part of clipping and interpolation.
EXIT_NOT_IMPLEMENTED(c.user_clip_planes != 0 || c.user_clip_plane_mode != 0 ||
c.vertex_kill_any || c.user_clip_plane_negate_y || c.clip_disable ||
c.vertex_kill_any || c.user_clip_plane_negate_y ||
c.user_clip_plane_cull_only || c.cull_on_clipping_error_disable ||
c.force_viewport_index_from_vs_enable);
}
@@ -1079,7 +1079,7 @@ void hw_check(const CommandBuffer& buffer) {
AaCheck(aa, ac);
log_phase("done");
if (RenderTargetMaskHasBoundMrt(buffer)) {
if (graphics_debug_dump_enabled() && RenderTargetMaskHasBoundMrt(buffer)) {
LOGF("MRT render target mask: 0x%08" PRIx32 "\n", hw.GetRenderTargetMask());
for (uint32_t i = 0; i < 8; i++) {
const auto& mrt = hw.GetRenderTarget(i);
@@ -59,16 +59,8 @@ namespace {
if (HasFormatFeature(properties, vk::FormatFeatureFlagBits::eColorAttachment)) {
usage |= vk::ImageUsageFlagBits::eColorAttachment;
}
if (info.samples == 1 &&
HasFormatFeature(properties, vk::FormatFeatureFlagBits::eStorageImage)) {
if (info.samples == 1) {
usage |= vk::ImageUsageFlagBits::eStorage;
} else if (info.samples == 1) {
const auto compatible = SrgbStorageViewFormat(info.pixel_format);
if (compatible != vk::Format::eUndefined &&
HasFormatFeature(graphics.GetFormatProperties(compatible),
vk::FormatFeatureFlagBits::eStorageImage)) {
usage |= vk::ImageUsageFlagBits::eStorage;
}
}
return usage;
}
@@ -116,7 +116,7 @@ struct PipelineCache::ProgramCache {
}
static constexpr std::size_t MaxStaticKeyWords =
5 + ShaderVertexInputInfo::RES_MAX * 17;
12 + ShaderVertexInputInfo::RES_MAX * 17;
template <typename InputInfo>
ShaderProgram Get(const ShaderParams& params, InputInfo& input_info) {
@@ -340,8 +340,23 @@ void PipelineCache::Save() {
ShaderProgram PipelineCache::GetVertexProgram(const HW::VertexShaderInfo& regs,
const HW::ShaderRegisters& sh,
const HW::Context& context,
ShaderVertexInputInfo& input_info) {
const auto params = PrepareProgram(regs, sh, input_info);
if (context.GetClipControl().clip_disable) {
const auto& viewport = context.GetScreenViewport().viewports[0];
const auto& limits = m_graphics.GetPhysicalDeviceProperties().limits;
auto& clip = input_info.clip_space;
clip.scale[0] = viewport.xscale;
clip.scale[1] = viewport.yscale;
clip.offset[0] = viewport.xoffset;
clip.offset[1] = viewport.yoffset;
clip.half_extent[0] =
static_cast<float>(std::min(limits.maxViewportDimensions[0], 16384u)) * 0.5f;
clip.half_extent[1] =
static_cast<float>(std::min(limits.maxViewportDimensions[1], 16384u)) * 0.5f;
clip.enabled = true;
}
Common::LockGuard lock(m_mutex);
return m_program_cache->Get(params, input_info);
}
@@ -130,6 +130,7 @@ public:
ShaderProgram GetVertexProgram(const HW::VertexShaderInfo& regs,
const HW::ShaderRegisters& sh,
const HW::Context& context,
ShaderVertexInputInfo& input_info);
ShaderProgram
GetPixelProgram(const HW::PixelShaderInfo& regs, const HW::ShaderRegisters& sh,
+14 -6
View File
@@ -331,10 +331,18 @@ static void SetGraphicsDynamicParams(const CommandBuffer& buffer, vk::CommandBuf
const auto final_scissor = calc_final_scissor(vp, ctx.GetScanModeControl(), framebuffer_extent);
vk::Viewport viewport {};
viewport.x = vp.viewports[0].xoffset - vp.viewports[0].xscale;
viewport.y = vp.viewports[0].yoffset - vp.viewports[0].yscale;
viewport.width = vp.viewports[0].xscale * 2.0f;
viewport.height = vp.viewports[0].yscale * 2.0f;
if (ctx.GetClipControl().clip_disable) {
const auto& limits = buffer.GetGraphics().GetPhysicalDeviceProperties().limits;
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = static_cast<float>(std::min(limits.maxViewportDimensions[0], 16384u));
viewport.height = static_cast<float>(std::min(limits.maxViewportDimensions[1], 16384u));
} else {
viewport.x = vp.viewports[0].xoffset - vp.viewports[0].xscale;
viewport.y = vp.viewports[0].yoffset - vp.viewports[0].yscale;
viewport.width = vp.viewports[0].xscale * 2.0f;
viewport.height = vp.viewports[0].yscale * 2.0f;
}
viewport.minDepth = vp.viewports[0].zoffset;
viewport.maxDepth = vp.viewports[0].zscale + vp.viewports[0].zoffset;
vk_buffer.setViewport(0, 1, &viewport);
@@ -1013,8 +1021,8 @@ static void RefreshShaders(CommandBuffer& buffer, const DrawCallInfo& draw, bool
LogDrawPhase(draw.name, "GetVertexProgram");
}
auto& pipeline_cache = buffer.GetContext().GetPipelineCache();
state.vertex_program =
pipeline_cache.GetVertexProgram(vertex_shader_info, shader_regs, state.vs_input_info);
state.vertex_program = pipeline_cache.GetVertexProgram(vertex_shader_info, shader_regs, ctx,
state.vs_input_info);
if (!state.ps_active) {
return;
@@ -814,6 +814,7 @@ static void WindowCreate(WindowContext& context) {
int width = static_cast<int>(context.graphic_ctx.screen_width);
int height = static_cast<int>(context.graphic_ctx.screen_height);
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
SDL_SetHint(SDL_HINT_WINDOWS_DPI_SCALING, "0");
#endif
@@ -408,6 +408,41 @@ void EmitAuxPositionExport(ValueEmitContext& ctx, uint32_t data, const IR::Expor
}
}
uint32_t ConvertClipCoordinate(EmitterState& state, uint32_t coordinate, float scale,
float offset, float half_extent) {
const auto window = state.builder.AllocateId();
const auto biased = state.builder.AllocateId();
const auto divided = state.builder.AllocateId();
const auto ndc = state.builder.AllocateId();
state.builder.AddFunction(
{OpFMul, TypeF32(state), window, coordinate, ConstantF32Value(state, scale)});
state.builder.AddFunction(
{OpFAdd, TypeF32(state), biased, window, ConstantF32Value(state, offset)});
state.builder.AddFunction(
{OpFDiv, TypeF32(state), divided, biased, ConstantF32Value(state, half_extent)});
state.builder.AddFunction(
{OpFSub, TypeF32(state), ndc, divided, ConstantF32Value(state, 1.0f)});
return ndc;
}
uint32_t ConvertPositionToClipSpace(EmitterState& state, uint32_t position) {
const auto& transform = state.input_info.vertex->clip_space;
uint32_t components[4] {};
for (uint32_t i = 0; i < 4; i++) {
components[i] = state.builder.AllocateId();
state.builder.AddFunction(
{OpCompositeExtract, TypeF32(state), components[i], position, i});
}
components[0] = ConvertClipCoordinate(state, components[0], transform.scale[0],
transform.offset[0], transform.half_extent[0]);
components[1] = ConvertClipCoordinate(state, components[1], transform.scale[1],
transform.offset[1], transform.half_extent[1]);
const auto converted = state.builder.AllocateId();
state.builder.AddFunction({OpCompositeConstruct, TypeF32Vector(state, 4), converted,
components[0], components[1], components[2], components[3]});
return converted;
}
void EmitExport(ValueEmitContext& ctx, const IR::Inst& inst) {
auto& state = ctx.state;
const auto& exp = ctx.Export(inst);
@@ -467,6 +502,9 @@ void EmitExport(ValueEmitContext& ctx, const IR::Inst& inst) {
}
}
if (exp.kind == IR::ExportTargetKind::Position) {
if (state.stage == ShaderType::Vertex && state.input_info.vertex->clip_space.enabled) {
value = ConvertPositionToClipSpace(state, value);
}
const auto pointer = state.builder.AllocateId();
state.builder.AddFunction(
{OpAccessChain, TypePointer(state, StorageClassOutput, TypeF32Vector(state, 4)),
@@ -110,6 +110,12 @@ DppTargetLane EmitDppTargetLane(EmitterState& state, uint32_t control) {
if (control == 0x141u) {
return EmitDppMirrorTargetLane(state, subid, true);
}
if (control >= 0x160u && control <= 0x16fu) {
const auto target = state.builder.AllocateId();
state.builder.AddFunction(
{OpBitwiseXor, TypeU32(state), target, subid, ConstantU32(state, control & 0xfu)});
return {target, EmitTrueBool(state)};
}
return {subid, EmitTrueBool(state)};
}
@@ -27,7 +27,8 @@ constexpr OpcodeMap SOP2_OPCODE_LIST[] = {
{0x22u, Opcode::S_ASHR_I32}, {0x24u, Opcode::S_BFM_B32},
{0x25u, Opcode::S_BFM_B64}, {0x26u, Opcode::S_MUL_I32},
{0x27u, Opcode::S_BFE_U32}, {0x28u, Opcode::S_BFE_I32},
{0x29u, Opcode::S_BFE_U64}, {0x2eu, Opcode::S_LSHL1_ADD_U32},
{0x29u, Opcode::S_BFE_U64}, {0x2cu, Opcode::S_ABSDIFF_I32},
{0x2eu, Opcode::S_LSHL1_ADD_U32},
{0x2fu, Opcode::S_LSHL2_ADD_U32}, {0x30u, Opcode::S_LSHL3_ADD_U32},
{0x31u, Opcode::S_LSHL4_ADD_U32}, {0x32u, Opcode::S_PACK_LL_B32_B16},
{0x33u, Opcode::S_PACK_LH_B32_B16}, {0x34u, Opcode::S_PACK_HH_B32_B16},
@@ -48,7 +49,9 @@ constexpr OpcodeMap SOP1_OPCODE_LIST[] = {
{0x15u, Opcode::S_FLBIT_I32_B32},
{0x16u, Opcode::S_FLBIT_I32_B64},
{0x1bu, Opcode::S_BITSET0_B32},
{0x1cu, Opcode::S_BITSET0_B64},
{0x1du, Opcode::S_BITSET1_B32},
{0x1eu, Opcode::S_BITSET1_B64},
{0x1fu, Opcode::S_GETPC_B64},
{0x20u, Opcode::S_SETPC_B64},
{0x24u, Opcode::S_AND_SAVEEXEC_B64},
@@ -93,6 +96,7 @@ constexpr OpcodeMap SOPP_OPCODE_LIST[] = {
{0x0au, Opcode::S_BARRIER},
{0x0cu, Opcode::S_WAITCNT},
{0x0eu, Opcode::S_SLEEP},
{0x0fu, Opcode::S_SETPRIO},
{0x10u, Opcode::S_SENDMSG},
{0x12u, Opcode::S_TRAP},
{0x16u, Opcode::S_TTRACEDATA},
@@ -276,6 +280,7 @@ void DecodeSopp(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
: static_cast<int32_t>(static_cast<int16_t>(simm));
inst.src_count = (inst.opcode == Opcode::S_NOP || inst.opcode == Opcode::S_WAITCNT ||
inst.opcode == Opcode::S_WAITCNT_DEPCTR || inst.opcode == Opcode::S_SLEEP ||
inst.opcode == Opcode::S_SETPRIO ||
inst.opcode == Opcode::S_SENDMSG || inst.opcode == Opcode::S_TRAP ||
inst.opcode == Opcode::S_TTRACEDATA || inst.opcode == Opcode::S_INST_PREFETCH)
? 1
@@ -479,6 +479,8 @@ std::string InstructionToString(const Instruction& inst) {
case Opcode::S_FLBIT_I32_B32:
case Opcode::S_FF1_I32_B32:
case Opcode::S_FF1_I32_B64:
case Opcode::S_BITSET0_B64:
case Opcode::S_BITSET1_B64:
case Opcode::S_NOT_B64:
case Opcode::S_WQM_B64:
case Opcode::S_QUADMASK_B64:
@@ -505,6 +507,7 @@ std::string InstructionToString(const Instruction& inst) {
case Opcode::S_WAITCNT:
case Opcode::S_WAITCNT_DEPCTR:
case Opcode::S_SLEEP:
case Opcode::S_SETPRIO:
case Opcode::S_TRAP:
case Opcode::S_SENDMSG:
case Opcode::S_TTRACEDATA:
@@ -40,6 +40,7 @@ enum class Opcode {
S_MOV_B64,
S_MOVK_I32,
S_ABS_I32,
S_ABSDIFF_I32,
S_BREV_B32,
S_BCNT1_I32_B32,
S_BCNT1_I32_B64,
@@ -69,6 +70,8 @@ enum class Opcode {
S_BITCMP1_B32,
S_BITSET0_B32,
S_BITSET1_B32,
S_BITSET0_B64,
S_BITSET1_B64,
S_MIN_I32,
S_MAX_I32,
S_MIN_U32,
@@ -108,6 +111,7 @@ enum class Opcode {
S_BFM_B64,
S_CSELECT_B32,
S_CSELECT_B64,
S_SETPRIO,
S_PACK_LL_B32_B16,
S_PACK_LH_B32_B16,
S_PACK_HH_B32_B16,
@@ -282,6 +286,7 @@ enum class Opcode {
V_MAD_MIXHI_F16,
V_ADD_NC_U32,
V_ADDC_U32,
V_SUB_CO_CI_U32,
V_SUBREV_CO_CI_U32,
V_SUB_NC_U32,
V_SUBREV_NC_U32,
@@ -61,6 +61,7 @@ constexpr Vop2OpcodeInfo VOP2_OPCODE_LIST[] = {
{0x24u, Opcode::V_MBCNT_HI_U32_B32},
{0x25u, Opcode::V_ADD_NC_U32, Vop2SdwaProfile::IntegerPartialDestination},
{0x28u, Opcode::V_ADDC_U32, Vop2SdwaProfile::IntegerFullDestination},
{0x29u, Opcode::V_SUB_CO_CI_U32},
{0x2au, Opcode::V_SUBREV_CO_CI_U32},
{0x26u, Opcode::V_SUB_NC_U32, Vop2SdwaProfile::IntegerPartialDestination},
{0x27u, Opcode::V_SUBREV_NC_U32, Vop2SdwaProfile::IntegerFullDestination},
@@ -1033,6 +1034,7 @@ void FinalizeVop2Instruction(std::span<const uint32_t> code, uint32_t word_index
inst.src_count = 3;
break;
case Opcode::V_ADDC_U32:
case Opcode::V_SUB_CO_CI_U32:
case Opcode::V_SUBREV_CO_CI_U32:
inst.dst2.kind = OperandKind::VccLo;
inst.src2.kind = OperandKind::VccLo;
@@ -1643,6 +1645,7 @@ void DecodeVop3(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
SetRawWords(inst, code, word_index, 2);
const bool carry_in_out = (inst.opcode == Opcode::V_ADDC_U32 && opcode == 0x128u) ||
(inst.opcode == Opcode::V_SUB_CO_CI_U32 && opcode == 0x129u) ||
(inst.opcode == Opcode::V_SUBREV_CO_CI_U32 && opcode == 0x12au);
const bool vop3b_carry_out = IsVop3BCarryOutOpcode(inst.opcode);
const bool vop3b_mad_u64 = IsVop3BMadU64Opcode(inst.opcode);
@@ -76,9 +76,9 @@ void Translator::SUB_U32(const Decoder::Instruction& inst, bool vector, bool rev
}
}
void Translator::SUBB_U32(const Decoder::Instruction& inst, bool vector) {
const auto lhs = ReadU32(vector ? inst.src1 : inst.src0);
const auto rhs = ReadU32(vector ? inst.src0 : inst.src1);
void Translator::SUBB_U32(const Decoder::Instruction& inst, bool vector, bool reverse) {
const auto lhs = ReadU32(reverse ? inst.src1 : inst.src0);
const auto rhs = ReadU32(reverse ? inst.src0 : inst.src1);
const auto borrow_in = vector ? ConditionBit(inst.src2)
: ConditionBit(ConditionOperand(Decoder::OperandKind::Scc));
const auto partial = ir.ISub(lhs, rhs);
@@ -94,6 +94,13 @@ void Translator::SUBB_U32(const Decoder::Instruction& inst, bool vector) {
}
}
void Translator::S_ABSDIFF_I32(const Decoder::Instruction& inst) {
const auto difference = ir.ISub(ReadU32(inst.src0), ReadU32(inst.src1));
const auto result = IR::U32(ir.Emit(IR::ValueOpcode::IAbs32, {difference}));
WriteOperand(DestinationOperand(inst), result);
ir.SetScc(ir.INotEqual(result, IR::U32(IR::Value(0u))));
}
void Translator::S_ADD_SUB_I32(const Decoder::Instruction& inst, bool subtract) {
const auto lhs = ReadU32(inst.src0);
const auto rhs = ReadU32(inst.src1);
@@ -312,6 +312,22 @@ bool Translator::S_BITSET_B32(const Decoder::Instruction& inst, bool set) {
return true;
}
bool Translator::S_BITSET_B64(const Decoder::Instruction& inst, bool set) {
const auto offset = ir.BitwiseAnd(ReadU32(inst.src0), IR::U32(IR::Value(63u)));
const auto word_bit = ir.BitwiseAnd(offset, IR::U32(IR::Value(31u)));
const auto bit = ir.ShiftLeftLogical(IR::U32(IR::Value(1u)), word_bit);
const auto old = ReadU32Pair(inst.dst);
const auto low_value = set ? ir.BitwiseOr(old[0], bit)
: ir.BitwiseAnd(old[0], ir.BitwiseNot(bit));
const auto high_value = set ? ir.BitwiseOr(old[1], bit)
: ir.BitwiseAnd(old[1], ir.BitwiseNot(bit));
const auto high = IR::U1(ir.Emit(IR::ValueOpcode::UGreaterThanEqual32,
{offset, IR::Value(32u)}));
WriteU32Pair(inst.dst,
{ir.Select(high, old[0], low_value), ir.Select(high, high_value, old[1])});
return true;
}
bool Translator::V_BCNT_U32_B32(const Decoder::Instruction& inst) {
const auto count = IR::U32(ir.Emit(IR::ValueOpcode::BitCount32, {ReadU32(inst.src0)}));
WriteOperand(DestinationOperand(inst), ir.IAdd(count, ReadU32(inst.src1)));
@@ -34,7 +34,8 @@ bool Translator::EmitScalar(const Decoder::Instruction& inst) {
case O::S_ADD_U32: ADD_U32(inst, false, false); return true;
case O::S_ADDC_U32: ADD_U32(inst, false, true); return true;
case O::S_SUB_U32: SUB_U32(inst, false, false); return true;
case O::S_SUBB_U32: SUBB_U32(inst, false); return true;
case O::S_SUBB_U32: SUBB_U32(inst, false, false); return true;
case O::S_ABSDIFF_I32: S_ABSDIFF_I32(inst); return true;
case O::S_ADD_I32: S_ADD_SUB_I32(inst, false); return true;
case O::S_SUB_I32: S_ADD_SUB_I32(inst, true); return true;
case O::S_LSHL1_ADD_U32: S_LSHL_ADD_U32(inst, 1u); return true;
@@ -186,6 +187,8 @@ bool Translator::EmitScalar(const Decoder::Instruction& inst) {
case O::S_BITSET0_B32: return S_BITSET_B32(inst, false);
case O::S_BITSET1_B32: return S_BITSET_B32(inst, true);
case O::S_BITSET0_B64: return S_BITSET_B64(inst, false);
case O::S_BITSET1_B64: return S_BITSET_B64(inst, true);
case O::S_BITREPLICATE_B64_B32: return S_BITREPLICATE_B64_B32(inst);
case O::S_QUADMASK_B64: return S_QUADMASK_B64(inst);
case O::S_BFM_B32: return BFM_B32(inst);
@@ -201,6 +204,7 @@ bool Translator::EmitScalar(const Decoder::Instruction& inst) {
case O::S_NOP:
case O::S_SLEEP:
case O::S_SETPRIO:
case O::S_TRAP: EmitControlNop(); return true;
case O::S_WAITCNT_DEPCTR: EmitWaitcnt(); return true;
case O::S_BARRIER: S_BARRIER(); return true;
@@ -192,6 +192,7 @@ private:
bool V_SAD_U32(const Decoder::Instruction& inst);
bool V_ADD3_U32(const Decoder::Instruction& inst);
bool S_BITSET_B32(const Decoder::Instruction& inst, bool set);
bool S_BITSET_B64(const Decoder::Instruction& inst, bool set);
bool V_BCNT_U32_B32(const Decoder::Instruction& inst);
bool V_MBCNT_U32_B32(const Decoder::Instruction& inst, bool low);
bool S_BITREPLICATE_B64_B32(const Decoder::Instruction& inst);
@@ -218,7 +219,8 @@ private:
bool negate_source, bool write_64);
void ADD_U32(const Decoder::Instruction& inst, bool vector, bool use_carry_in);
void SUB_U32(const Decoder::Instruction& inst, bool vector, bool reverse);
void SUBB_U32(const Decoder::Instruction& inst, bool vector);
void SUBB_U32(const Decoder::Instruction& inst, bool vector, bool reverse);
void S_ABSDIFF_I32(const Decoder::Instruction& inst);
void S_ADD_SUB_I32(const Decoder::Instruction& inst, bool subtract);
void S_LSHL_ADD_U32(const Decoder::Instruction& inst, uint32_t shift_amount);
void ScalarMinMax32(const Decoder::Instruction& inst, IR::ValueOpcode value_opcode,
@@ -10,7 +10,8 @@ bool Translator::EmitVector(const Decoder::Instruction& inst) {
case O::V_ADDC_U32: ADD_U32(inst, true, true); return true;
case O::V_SUB_I32: SUB_U32(inst, true, false); return true;
case O::V_SUBREV_I32: SUB_U32(inst, true, true); return true;
case O::V_SUBREV_CO_CI_U32: SUBB_U32(inst, true); return true;
case O::V_SUB_CO_CI_U32: SUBB_U32(inst, true, false); return true;
case O::V_SUBREV_CO_CI_U32: SUBB_U32(inst, true, true); return true;
case O::V_MOV_B32: MOV_B32(inst, true); return true;
case O::V_MOVRELS_B32: V_MOVRELS_B32(inst); return true;
+17 -1
View File
@@ -25,6 +25,7 @@
#include <algorithm>
#include <atomic>
#include <bit>
#include <cstdio>
#include <filesystem>
#include <fmt/format.h>
@@ -571,7 +572,10 @@ static void ShaderApplyAttribSemantics(ShaderVertexInputInfo& info,
uint32_t reg = in.hardware_mapping;
uint32_t size = in.size_in_elements;
LOGF("reg = %u, size = %u, va[%u] = 0x%08" PRIx32 "\n", reg, size, i, attrib[in.semantic]);
if (Config::GraphicsDebugDumpEnabled()) {
LOGF("reg = %u, size = %u, va[%u] = 0x%08" PRIx32 "\n", reg, size, i,
attrib[in.semantic]);
}
size_t index = attrib[in.semantic] & 0x1fu;
auto format =
@@ -894,6 +898,18 @@ void BuildStageStaticKey(const ShaderVertexInputInfo& info, std::vector<uint32_t
key.push_back(info.resources_num);
key.push_back(info.scratch_size_dwords);
key.push_back(info.pa_cl_vs_out_cntl);
key.push_back(static_cast<uint32_t>(info.clip_space.enabled));
if (info.clip_space.enabled) {
for (const float value: info.clip_space.scale) {
key.push_back(std::bit_cast<uint32_t>(value));
}
for (const float value: info.clip_space.offset) {
key.push_back(std::bit_cast<uint32_t>(value));
}
for (const float value: info.clip_space.half_extent) {
key.push_back(std::bit_cast<uint32_t>(value));
}
}
for (int i = 0; i < info.resources_num; i++) {
const auto& resource = info.resources[i];
+8
View File
@@ -68,6 +68,13 @@ inline uint8_t GetDstSel(uint32_t swizzle, uint32_t channel) {
return (swizzle >> (channel * 3u)) & 0x7u;
}
struct ShaderClipSpaceTransform {
float scale[2] = {};
float offset[2] = {};
float half_extent[2] = {};
bool enabled = false;
};
struct ShaderVertexInputInfo {
static constexpr int RES_MAX = 32;
@@ -84,6 +91,7 @@ struct ShaderVertexInputInfo {
uint32_t scratch_size_dwords = 0;
uint32_t param_export_mask = 0;
uint32_t pa_cl_vs_out_cntl = 0;
ShaderClipSpaceTransform clip_space;
bool fetch_external = false;
bool fetch_embedded = false;
};
+47 -36
View File
@@ -44,6 +44,13 @@ namespace Libs::Graphics {
static RenderContext* g_renderer = nullptr;
template <typename... Args>
static void AgcTrace(const char* format, const Args&... args) {
if (Config::GraphicsDebugDumpEnabled()) {
LOGF(format, args...);
}
}
void Initialize() {
// Some games lock up if this is not called first
if (Config::RenderDocEnabled()) {
@@ -363,6 +370,10 @@ void* KYTY_SYSV_ABI AgcGetRegisterDefaults2Internal(uint32_t ver) {
}
static void dbg_dump_shader(const Shader* h) {
if (!Config::GraphicsDebugDumpEnabled()) {
return;
}
LOGF("\t file_header = 0x%08" PRIx32 "\n"
"\t version = 0x%08" PRIx32 "\n"
"\t user_data = 0x%016" PRIx64 "\n",
@@ -952,7 +963,7 @@ int KYTY_SYSV_ABI AgcSetCxRegIndirectPatchSetAddress(uint32_t*
const volatile ShaderRegister* regs) {
PRINT_NAME();
LOGF("\t cmd = 0x%016" PRIx64 "\n"
AgcTrace("\t cmd = 0x%016" PRIx64 "\n"
"\t regs = 0x%016" PRIx64 "\n",
reinterpret_cast<uint64_t>(cmd), reinterpret_cast<uint64_t>(regs));
@@ -968,7 +979,7 @@ int KYTY_SYSV_ABI AgcSetShRegIndirectPatchSetAddress(uint32_t*
const volatile ShaderRegister* regs) {
PRINT_NAME();
LOGF("\t cmd = 0x%016" PRIx64 "\n"
AgcTrace("\t cmd = 0x%016" PRIx64 "\n"
"\t regs = 0x%016" PRIx64 "\n",
reinterpret_cast<uint64_t>(cmd), reinterpret_cast<uint64_t>(regs));
@@ -984,7 +995,7 @@ int KYTY_SYSV_ABI AgcSetUcRegIndirectPatchSetAddress(uint32_t*
const volatile ShaderRegister* regs) {
PRINT_NAME();
LOGF("\t cmd = 0x%016" PRIx64 "\n"
AgcTrace("\t cmd = 0x%016" PRIx64 "\n"
"\t regs = 0x%016" PRIx64 "\n",
reinterpret_cast<uint64_t>(cmd), reinterpret_cast<uint64_t>(regs));
@@ -999,7 +1010,7 @@ int KYTY_SYSV_ABI AgcSetUcRegIndirectPatchSetAddress(uint32_t*
int KYTY_SYSV_ABI AgcSetCxRegIndirectPatchSetNumRegisters(uint32_t* cmd, uint32_t num_regs) {
PRINT_NAME();
LOGF("\t cmd = 0x%016" PRIx64 "\n"
AgcTrace("\t cmd = 0x%016" PRIx64 "\n"
"\t num_regs = %" PRIu32 "\n",
reinterpret_cast<uint64_t>(cmd), num_regs);
@@ -1011,7 +1022,7 @@ int KYTY_SYSV_ABI AgcSetCxRegIndirectPatchSetNumRegisters(uint32_t* cmd, uint32_
int KYTY_SYSV_ABI AgcSetShRegIndirectPatchSetNumRegisters(uint32_t* cmd, uint32_t num_regs) {
PRINT_NAME();
LOGF("\t cmd = 0x%016" PRIx64 "\n"
AgcTrace("\t cmd = 0x%016" PRIx64 "\n"
"\t num_regs = %" PRIu32 "\n",
reinterpret_cast<uint64_t>(cmd), num_regs);
@@ -1023,7 +1034,7 @@ int KYTY_SYSV_ABI AgcSetShRegIndirectPatchSetNumRegisters(uint32_t* cmd, uint32_
int KYTY_SYSV_ABI AgcSetUcRegIndirectPatchSetNumRegisters(uint32_t* cmd, uint32_t num_regs) {
PRINT_NAME();
LOGF("\t cmd = 0x%016" PRIx64 "\n"
AgcTrace("\t cmd = 0x%016" PRIx64 "\n"
"\t num_regs = %" PRIu32 "\n",
reinterpret_cast<uint64_t>(cmd), num_regs);
@@ -1035,7 +1046,7 @@ int KYTY_SYSV_ABI AgcSetUcRegIndirectPatchSetNumRegisters(uint32_t* cmd, uint32_
int KYTY_SYSV_ABI AgcSetCxRegIndirectPatchAddRegisters(uint32_t* cmd, uint32_t num_regs) {
PRINT_NAME();
LOGF("\t cmd = 0x%016" PRIx64 "\n"
AgcTrace("\t cmd = 0x%016" PRIx64 "\n"
"\t num_regs = %" PRIu32 "\n",
reinterpret_cast<uint64_t>(cmd), num_regs);
@@ -1047,7 +1058,7 @@ int KYTY_SYSV_ABI AgcSetCxRegIndirectPatchAddRegisters(uint32_t* cmd, uint32_t n
int KYTY_SYSV_ABI AgcSetShRegIndirectPatchAddRegisters(uint32_t* cmd, uint32_t num_regs) {
PRINT_NAME();
LOGF("\t cmd = 0x%016" PRIx64 "\n"
AgcTrace("\t cmd = 0x%016" PRIx64 "\n"
"\t num_regs = %" PRIu32 "\n",
reinterpret_cast<uint64_t>(cmd), num_regs);
@@ -1059,7 +1070,7 @@ int KYTY_SYSV_ABI AgcSetShRegIndirectPatchAddRegisters(uint32_t* cmd, uint32_t n
int KYTY_SYSV_ABI AgcSetUcRegIndirectPatchAddRegisters(uint32_t* cmd, uint32_t num_regs) {
PRINT_NAME();
LOGF("\t cmd = 0x%016" PRIx64 "\n"
AgcTrace("\t cmd = 0x%016" PRIx64 "\n"
"\t num_regs = %" PRIu32 "\n",
reinterpret_cast<uint64_t>(cmd), num_regs);
@@ -1090,7 +1101,7 @@ int KYTY_SYSV_ABI AgcCreatePrimState(ShaderRegister* cx_regs, ShaderRegister* uc
const Shader* hs, const Shader* gs, uint32_t prim_type) {
PRINT_NAME();
LOGF("\t cx_regs = 0x%016" PRIx64 "\n"
AgcTrace("\t cx_regs = 0x%016" PRIx64 "\n"
"\t uc_regs = 0x%016" PRIx64 "\n"
"\t hs = 0x%016" PRIx64 "\n"
"\t gs = 0x%016" PRIx64 "\n"
@@ -1158,7 +1169,7 @@ int KYTY_SYSV_ABI AgcUpdatePrimState(ShaderRegister* cx_regs, ShaderRegister* uc
uint32_t prim_type) {
PRINT_NAME();
LOGF("\t cx_regs = 0x%016" PRIx64 "\n"
AgcTrace("\t cx_regs = 0x%016" PRIx64 "\n"
"\t uc_regs = 0x%016" PRIx64 "\n"
"\t prim_type = %" PRIu32 "\n",
reinterpret_cast<uint64_t>(cx_regs), reinterpret_cast<uint64_t>(uc_regs), prim_type);
@@ -1363,7 +1374,7 @@ int KYTY_SYSV_ABI AgcCreateInterpolantMapping(ShaderRegister* regs, const Shader
const Shader* ps) {
PRINT_NAME();
LOGF("\t regs = 0x%016" PRIx64 "\n"
AgcTrace("\t regs = 0x%016" PRIx64 "\n"
"\t gs = 0x%016" PRIx64 "\n"
"\t ps = 0x%016" PRIx64 "\n",
reinterpret_cast<uint64_t>(regs), reinterpret_cast<uint64_t>(gs),
@@ -1419,7 +1430,7 @@ int KYTY_SYSV_ABI AgcCreateInterpolantMapping2(ShaderRegister* regs, const Shade
const Shader* ps) {
PRINT_NAME();
LOGF("\t regs = 0x%016" PRIx64 "\n"
AgcTrace("\t regs = 0x%016" PRIx64 "\n"
"\t gs = 0x%016" PRIx64 "\n"
"\t ps = 0x%016" PRIx64 "\n",
reinterpret_cast<uint64_t>(regs), reinterpret_cast<uint64_t>(gs),
@@ -1942,7 +1953,7 @@ uint32_t* KYTY_SYSV_ABI AgcCbSetShRegistersDirect(CommandBuffer*
uint32_t num_regs) {
PRINT_NAME();
LOGF("\t regs = 0x%016" PRIx64 "\n"
AgcTrace("\t regs = 0x%016" PRIx64 "\n"
"\t num_regs = %" PRIu32 "\n",
reinterpret_cast<uint64_t>(regs), num_regs);
@@ -2009,7 +2020,7 @@ uint32_t* KYTY_SYSV_ABI AgcCbSetUcRegistersDirect(CommandBuffer*
uint32_t num_regs) {
PRINT_NAME();
LOGF("\t regs = 0x%016" PRIx64 "\n"
AgcTrace("\t regs = 0x%016" PRIx64 "\n"
"\t num_regs = %" PRIu32 "\n",
reinterpret_cast<uint64_t>(regs), num_regs);
@@ -2396,7 +2407,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbSetCxRegistersIndirect(CommandBuffer*
uint32_t num_regs) {
PRINT_NAME();
LOGF("\t regs = 0x%016" PRIx64 "\n"
AgcTrace("\t regs = 0x%016" PRIx64 "\n"
"\t num_regs = %" PRIu32 "\n",
reinterpret_cast<uint64_t>(regs), num_regs);
@@ -2420,7 +2431,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbSetShRegistersIndirect(CommandBuffer*
uint32_t num_regs) {
PRINT_NAME();
LOGF("\t regs = 0x%016" PRIx64 "\n"
AgcTrace("\t regs = 0x%016" PRIx64 "\n"
"\t num_regs = %" PRIu32 "\n",
reinterpret_cast<uint64_t>(regs), num_regs);
@@ -2444,7 +2455,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbSetUcRegistersIndirect(CommandBuffer*
uint32_t num_regs) {
PRINT_NAME();
LOGF("\t regs = 0x%016" PRIx64 "\n"
AgcTrace("\t regs = 0x%016" PRIx64 "\n"
"\t num_regs = %" PRIu32 "\n",
reinterpret_cast<uint64_t>(regs), num_regs);
@@ -2467,7 +2478,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbSetIndexSize(CommandBuffer* buf, uint8_t index_siz
uint8_t cache_policy) {
PRINT_NAME();
LOGF("\t index_size = 0x%" PRIx8 "\n"
AgcTrace("\t index_size = 0x%" PRIx8 "\n"
"\t cache_policy = 0x%" PRIx8 "\n",
index_size, cache_policy);
@@ -2488,7 +2499,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbSetIndexSize(CommandBuffer* buf, uint8_t index_siz
uint32_t* KYTY_SYSV_ABI AgcDcbSetIndexBuffer(CommandBuffer* buf, uint64_t index_addr) {
PRINT_NAME();
LOGF("\t index_addr = 0x%016" PRIx64 "\n", index_addr);
AgcTrace("\t index_addr = 0x%016" PRIx64 "\n", index_addr);
EXIT_NOT_IMPLEMENTED(buf == nullptr);
EXIT_NOT_IMPLEMENTED((index_addr & 1u) != 0);
@@ -2509,7 +2520,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbSetIndexBuffer(CommandBuffer* buf, uint64_t index_
uint32_t* KYTY_SYSV_ABI AgcDcbSetIndexCount(CommandBuffer* buf, uint32_t index_count) {
PRINT_NAME();
LOGF("\t index_count = 0x%" PRIx32 "\n", index_count);
AgcTrace("\t index_count = 0x%" PRIx32 "\n", index_count);
EXIT_NOT_IMPLEMENTED(buf == nullptr);
@@ -2528,7 +2539,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbSetIndexCount(CommandBuffer* buf, uint32_t index_c
uint32_t* KYTY_SYSV_ABI AgcDcbSetNumInstances(CommandBuffer* buf, uint32_t num_instances) {
PRINT_NAME();
LOGF("\t num_instances = 0x%" PRIx32 "\n", num_instances);
AgcTrace("\t num_instances = 0x%" PRIx32 "\n", num_instances);
if (buf == nullptr) {
return nullptr;
@@ -2624,7 +2635,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbDrawIndex(CommandBuffer* buf, uint32_t index_count
const volatile void* index_addr, uint64_t modifier) {
PRINT_NAME();
LOGF("\t index_count = 0x%" PRIx32 "\n"
AgcTrace("\t index_count = 0x%" PRIx32 "\n"
"\t index_addr = 0x%016" PRIx64 "\n"
"\t modifier = 0x%016" PRIx64 "\n",
index_count, reinterpret_cast<uint64_t>(index_addr), modifier);
@@ -2663,7 +2674,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbDrawIndexMultiInstanced(CommandBuffer* buf, uint32
uint32_t instance_count, uint64_t modifier) {
PRINT_NAME();
LOGF("\t index_count = 0x%" PRIx32 "\n"
AgcTrace("\t index_count = 0x%" PRIx32 "\n"
"\t index_addr = 0x%016" PRIx64 "\n"
"\t instance_count = 0x%" PRIx32 "\n"
"\t object_ids = 0x%016" PRIx64 "\n"
@@ -2739,7 +2750,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbDrawIndexAuto(CommandBuffer* buf, uint32_t index_c
uint64_t modifier) {
PRINT_NAME();
LOGF("\t index_count = 0x%" PRIx32 "\n"
AgcTrace("\t index_count = 0x%" PRIx32 "\n"
"\t modifier = 0x%016" PRIx64 "\n",
index_count, modifier);
@@ -2768,7 +2779,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbDrawIndexOffset(CommandBuffer* buf, uint32_t index
uint32_t index_count, uint64_t modifier) {
PRINT_NAME();
LOGF("\t index_offset = 0x%" PRIx32 "\n"
AgcTrace("\t index_offset = 0x%" PRIx32 "\n"
"\t index_count = 0x%" PRIx32 "\n"
"\t modifier = 0x%016" PRIx64 "\n",
index_offset, index_count, modifier);
@@ -2826,7 +2837,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbDrawIndexIndirect(CommandBuffer* buf, uint32_t dat
uint64_t modifier) {
PRINT_NAME();
LOGF("\t data_offset = 0x%" PRIx32 "\n"
AgcTrace("\t data_offset = 0x%" PRIx32 "\n"
"\t modifier = 0x%016" PRIx64 "\n",
data_offset_in_bytes, modifier);
@@ -2853,7 +2864,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbDrawIndirect(CommandBuffer* buf, uint32_t data_off
uint64_t modifier) {
PRINT_NAME();
LOGF("\t data_offset = 0x%" PRIx32 "\n"
AgcTrace("\t data_offset = 0x%" PRIx32 "\n"
"\t modifier = 0x%016" PRIx64 "\n",
data_offset_in_bytes, modifier);
@@ -2884,7 +2895,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbDrawIndirectMulti(CommandBuffer* buf,
uint32_t stride_in_bytes, uint64_t modifier) {
PRINT_NAME();
LOGF("\t data_offset = 0x%" PRIx32 "\n"
AgcTrace("\t data_offset = 0x%" PRIx32 "\n"
"\t count_indirect = 0x%" PRIx32 "\n"
"\t max_count_or_count = 0x%" PRIx32 "\n"
"\t count_addr = 0x%016" PRIx64 "\n"
@@ -2947,7 +2958,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbDrawIndexIndirectMulti(CommandBuffer* buf,
uint32_t stride_in_bytes, uint64_t modifier) {
PRINT_NAME();
LOGF("\t data_offset = 0x%" PRIx32 "\n"
AgcTrace("\t data_offset = 0x%" PRIx32 "\n"
"\t count_indirect = 0x%" PRIx32 "\n"
"\t max_count_or_count = 0x%" PRIx32 "\n"
"\t count_addr = 0x%016" PRIx64 "\n"
@@ -3801,7 +3812,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbWriteData(CommandBuffer* buf, uint8_t dst, uint8_t
uint8_t write_confirm) {
PRINT_NAME();
LOGF("\t dst = 0x%02" PRIx8 "\n"
AgcTrace("\t dst = 0x%02" PRIx8 "\n"
"\t cache_policy = 0x%02" PRIx8 "\n"
"\t address_or_offset = 0x%016" PRIx64 "\n"
"\t data = 0x%016" PRIx64 "\n"
@@ -4054,7 +4065,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbWaitRegMem(CommandBuffer* buf, uint8_t size, uint8
uint64_t mask, uint32_t poll_cycles) {
PRINT_NAME();
LOGF("\t size = 0x%02" PRIx8 "\n"
AgcTrace("\t size = 0x%02" PRIx8 "\n"
"\t compare_function = 0x%02" PRIx8 "\n"
"\t op = 0x%02" PRIx8 "\n"
"\t cache_policy = 0x%02" PRIx8 "\n"
@@ -4201,7 +4212,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbSetFlip(CommandBuffer* buf, uint32_t video_out_han
int64_t flip_arg) {
PRINT_NAME();
LOGF("\t video_out_handle = %" PRIu32 "\n"
AgcTrace("\t video_out_handle = %" PRIu32 "\n"
"\t display_buffer_index = %" PRId32 "\n"
"\t flip_mode = %" PRIu32 "\n"
"\t flip_arg = %" PRId64 "\n",
@@ -4252,7 +4263,7 @@ int KYTY_SYSV_ABI AgcDriverSubmitDcb(const Packet* packet) {
EXIT_NOT_IMPLEMENTED(packet == nullptr);
LOGF("\t addr = 0x%016" PRIx64 "\n"
AgcTrace("\t addr = 0x%016" PRIx64 "\n"
"\t dw_num = 0x%08" PRIx32 "\n"
"\t flags = 0x%02" PRIx8 "\n",
reinterpret_cast<uint64_t>(packet->addr), packet->dw_num, packet->flags);
@@ -4266,7 +4277,7 @@ int KYTY_SYSV_ABI AgcDriverSubmitMultiDcbs(uint32_t* const* dcb_gpu_addrs,
const uint32_t* dcb_sizes_in_dwords, uint32_t count) {
PRINT_NAME();
LOGF("\t count = %" PRIu32 "\n", count);
AgcTrace("\t count = %" PRIu32 "\n", count);
if (count == 0) {
return OK;
@@ -4279,7 +4290,7 @@ int KYTY_SYSV_ABI AgcDriverSubmitMultiDcbs(uint32_t* const* dcb_gpu_addrs,
auto* dcb = dcb_gpu_addrs[i];
uint32_t size_in_dwords = dcb_sizes_in_dwords[i];
LOGF("\t dcb[%" PRIu32 "] = 0x%016" PRIx64 "\n"
AgcTrace("\t dcb[%" PRIu32 "] = 0x%016" PRIx64 "\n"
"\t size[%" PRIu32 "] = 0x%08" PRIx32 "\n",
i, reinterpret_cast<uint64_t>(dcb), i, size_in_dwords);
-6
View File
@@ -2931,7 +2931,6 @@ int KYTY_SYSV_ABI Ngs2VoiceGetState(uintptr_t voice_handle, Ngs2VoiceState* stat
auto* submixer = reinterpret_cast<Ngs2SubmixerVoiceState*>(state);
*submixer = {};
submixer->voice_state.state_flags = Ngs2GetStateFlags(voice);
LOGF("\t state_flags = %u\n", submixer->voice_state.state_flags);
break;
}
case Ngs2RackType::CustomMastering: {
@@ -2942,7 +2941,6 @@ int KYTY_SYSV_ABI Ngs2VoiceGetState(uintptr_t voice_handle, Ngs2VoiceState* stat
std::memset(state, 0, state_size);
auto* mastering = reinterpret_cast<Ngs2CustomMasteringVoiceState*>(state);
mastering->voice_state.state_flags = Ngs2GetStateFlags(voice);
LOGF("\t state_flags = %u\n", mastering->voice_state.state_flags);
break;
}
case Ngs2RackType::Sampler:
@@ -2957,7 +2955,6 @@ int KYTY_SYSV_ABI Ngs2VoiceGetState(uintptr_t voice_handle, Ngs2VoiceState* stat
state->state_flags = Ngs2GetStateFlags(voice);
if (state_size < sizeof(Ngs2SamplerVoiceState)) {
LOGF("\t state_flags = %u\n", state->state_flags);
break;
}
@@ -2968,7 +2965,6 @@ int KYTY_SYSV_ABI Ngs2VoiceGetState(uintptr_t voice_handle, Ngs2VoiceState* stat
sampler->num_decoded_samples = 0;
sampler->user_data = 0;
sampler->waveform_data = nullptr;
LOGF("\t state_flags = %u\n", sampler->voice_state.state_flags);
break;
}
default: EXIT("unknown type: %s\n", Common::EnumName(voice->rack->type).c_str());
@@ -2989,8 +2985,6 @@ int KYTY_SYSV_ABI Ngs2VoiceGetStateFlags(uintptr_t voice_handle, uint32_t* state
*state_flags = Ngs2GetStateFlags(voice);
LOGF("\t state_flags = %u\n", *state_flags);
return OK;
}
+174
View File
@@ -39,11 +39,42 @@ struct PadControllerInformation {
uint8_t reserve[8];
};
struct PadLightBarParam {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t reserve;
};
struct PadVibrationParam {
uint8_t large_motor;
uint8_t small_motor;
};
struct PadTriggerEffectCommand {
uint32_t mode;
uint8_t reserve[4];
uint8_t data[48];
};
struct PadTriggerEffectParam {
uint8_t trigger_mask;
uint8_t reserve[7];
PadTriggerEffectCommand command[2];
};
static_assert(sizeof(PadTriggerEffectCommand) == 56);
static_assert(sizeof(PadTriggerEffectParam) == 120);
struct DualSenseEffects {
uint8_t enable_bits;
uint8_t reserve[9];
uint8_t right_trigger[11];
uint8_t left_trigger[11];
};
static_assert(sizeof(DualSenseEffects) == 32);
struct ControllerState {
struct Touch {
uint8_t id = 0;
@@ -73,6 +104,8 @@ public:
void ResetInputState();
void GetConnectionInfo(bool* flag, int* count);
void SetVibration(uint8_t large_motor, uint8_t small_motor);
void SetLightBar(uint8_t r, uint8_t g, uint8_t b);
bool SetTriggerEffect(const PadTriggerEffectParam& param);
void ReadState(ControllerState* state, bool* flag, int* count);
int ReadStates(ControllerState* states, int states_num, bool* flag, int* count);
@@ -125,6 +158,92 @@ static void pad_fill_data(PadData* data, const ControllerState& state, bool conn
data->device_unique_data_len = 0;
}
static bool trigger_effect_zones(uint8_t* effect, const uint8_t* strengths, uint8_t type,
uint8_t frequency = 0) {
uint16_t active = 0;
uint32_t packed = 0;
for (int i = 0; i < 10; i++) {
if (strengths[i] > 8) {
return false;
}
if (strengths[i] != 0) {
active |= static_cast<uint16_t>(1u << i);
packed |= static_cast<uint32_t>(strengths[i] - 1u) << (3 * i);
}
}
effect[0] = active != 0 && (type != 0x26 || frequency != 0) ? type : 0x05;
effect[1] = static_cast<uint8_t>(active);
effect[2] = static_cast<uint8_t>(active >> 8u);
effect[3] = static_cast<uint8_t>(packed);
effect[4] = static_cast<uint8_t>(packed >> 8u);
effect[5] = static_cast<uint8_t>(packed >> 16u);
effect[6] = static_cast<uint8_t>(packed >> 24u);
effect[9] = frequency;
return true;
}
static bool trigger_effect_to_dualsense(const PadTriggerEffectCommand& command, uint8_t* effect) {
std::memset(effect, 0, 11);
effect[0] = 0x05;
uint8_t strengths[10] = {};
switch (command.mode) {
case 0: return true;
case 1:
if (command.data[0] > 9 || command.data[1] > 8) {
return false;
}
std::fill(strengths + command.data[0], strengths + 10, command.data[1]);
return trigger_effect_zones(effect, strengths, 0x21);
case 2: {
const auto start = command.data[0];
const auto end = command.data[1];
const auto strength = command.data[2];
if (start < 2 || start > 7 || end <= start || end > 8 || strength > 8) {
return false;
}
if (strength == 0) {
return true;
}
const uint16_t zones = static_cast<uint16_t>((1u << start) | (1u << end));
effect[0] = 0x25;
effect[1] = static_cast<uint8_t>(zones);
effect[2] = static_cast<uint8_t>(zones >> 8u);
effect[3] = strength - 1u;
return true;
}
case 3:
if (command.data[0] > 9 || command.data[1] > 8) {
return false;
}
std::fill(strengths + command.data[0], strengths + 10, command.data[1]);
return trigger_effect_zones(effect, strengths, 0x26, command.data[2]);
case 4: return trigger_effect_zones(effect, command.data, 0x21);
case 5: {
const int start = command.data[0];
const int end = command.data[1];
const int start_strength = command.data[2];
const int end_strength = command.data[3];
if (start > 8 || end <= start || end > 9 || start_strength < 1 || start_strength > 8 ||
end_strength < 1 || end_strength > 8) {
return false;
}
for (int i = start; i < 10; i++) {
const int delta = (end_strength - start_strength) * (i - start);
const int length = end - start;
strengths[i] = static_cast<uint8_t>(
i >= end ? end_strength
: start_strength +
(delta + (delta < 0 ? -length / 2 : length / 2)) / length);
}
return trigger_effect_zones(effect, strengths, 0x21);
}
case 6: return trigger_effect_zones(effect, command.data + 1, 0x26, command.data[0]);
default: return false;
}
}
void Initialize() {
EXIT_IF(g_controller != nullptr);
@@ -304,6 +423,44 @@ void GameController::SetVibration(uint8_t large_motor, uint8_t small_motor) {
}
}
void GameController::SetLightBar(uint8_t r, uint8_t g, uint8_t b) {
Common::LockGuard lock(m_mutex);
if (auto* pad = SDL_GameControllerFromInstanceID(static_cast<SDL_JoystickID>(m_active_id));
pad != nullptr) {
(void)SDL_GameControllerSetLED(pad, r, g, b);
}
}
bool GameController::SetTriggerEffect(const PadTriggerEffectParam& param) {
if ((param.trigger_mask & ~0x03u) != 0) {
return false;
}
DualSenseEffects effect {};
if ((param.trigger_mask & 0x01u) != 0) {
effect.enable_bits |= 0x08;
if (!trigger_effect_to_dualsense(param.command[0], effect.left_trigger)) {
return false;
}
}
if ((param.trigger_mask & 0x02u) != 0) {
effect.enable_bits |= 0x04;
if (!trigger_effect_to_dualsense(param.command[1], effect.right_trigger)) {
return false;
}
}
if (effect.enable_bits == 0) {
return true;
}
Common::LockGuard lock(m_mutex);
auto* pad = SDL_GameControllerFromInstanceID(static_cast<SDL_JoystickID>(m_active_id));
if (pad != nullptr && SDL_GameControllerGetType(pad) == SDL_CONTROLLER_TYPE_PS5) {
(void)SDL_GameControllerSendEffect(pad, &effect, sizeof(effect));
}
return true;
}
void GameController::GetConnectionInfo(bool* flag, int* count) {
EXIT_IF(flag == nullptr);
EXIT_IF(count == nullptr);
@@ -617,7 +774,24 @@ int KYTY_SYSV_ABI PadSetLightBar(int handle, const PadLightBarParam* param) {
return PAD_ERROR_INVALID_ARG;
}
EXIT_IF(g_controller == nullptr);
g_controller->SetLightBar(param->r, param->g, param->b);
return OK;
}
int KYTY_SYSV_ABI PadSetTriggerEffect(int handle, const PadTriggerEffectParam* param) {
PRINT_NAME();
if (handle != 1) {
return PAD_ERROR_INVALID_HANDLE;
}
if (param == nullptr) {
return PAD_ERROR_INVALID_ARG;
}
EXIT_IF(g_controller == nullptr);
return g_controller->SetTriggerEffect(*param) ? OK : PAD_ERROR_INVALID_ARG;
}
} // namespace Libs::Controller
+2
View File
@@ -48,6 +48,7 @@ struct PadControllerInformation;
struct PadData;
struct PadVibrationParam;
struct PadLightBarParam;
struct PadTriggerEffectParam;
inline int controller_get_axis(int min, int max, int value) {
int v = (255 * (value - min)) / (max - min);
@@ -78,6 +79,7 @@ int KYTY_SYSV_ABI PadGetControllerInformation(int handle, PadControllerInformati
int KYTY_SYSV_ABI PadReadState(int handle, PadData* data);
int KYTY_SYSV_ABI PadRead(int handle, PadData* data, int num);
int KYTY_SYSV_ABI PadSetVibration(int handle, const PadVibrationParam* param);
int KYTY_SYSV_ABI PadSetTriggerEffect(int handle, const PadTriggerEffectParam* param);
int KYTY_SYSV_ABI PadResetLightBar(int handle);
int KYTY_SYSV_ABI PadSetLightBar(int handle, const PadLightBarParam* param);
+1
View File
@@ -635,6 +635,7 @@ LIB_DEFINE(InitNet_1_Http) {
LIB_FUNC("P6A3ytpsiYc", Http::HttpDeleteConnection);
LIB_FUNC("tsGVru3hCe8", Http::HttpCreateRequest);
LIB_FUNC("Aeu5wVKkF9w", Http::HttpCreateRequest);
LIB_FUNC("rGNm+FjIXKk", Http::HttpCreateRequest2);
LIB_FUNC("Cnp77podkCU", Http::HttpCreateRequestWithURL2);
LIB_FUNC("qe7oZ+v4PWA", Http::HttpDeleteRequest);
LIB_FUNC("PTiFIUxCpJc", Http::HttpSetRequestContentLength);
+1 -18
View File
@@ -42,23 +42,6 @@ static int KYTY_SYSV_ABI PadGetTriggerEffectState(int
return 0;
}
static int KYTY_SYSV_ABI PadSetTriggerEffect(int handle, const void* param) {
PRINT_NAME();
LOGF("\t handle = %d\n"
"\t param = 0x%016" PRIx64 "\n",
handle, reinterpret_cast<uint64_t>(param));
if (handle != 1) {
return -2137915389; /* 0x80920003 */
}
if (param == nullptr) {
return -2137915391; /* 0x80920001 */
}
return OK;
}
static int KYTY_SYSV_ABI PadSetVibrationTriggerEffectWeakWhileEmbeddedMicInUse(bool enabled) {
PRINT_NAME();
@@ -198,7 +181,7 @@ LIB_DEFINE(InitPad_1) {
LIB_FUNC("rIZnR6eSpvk", Controller::PadResetOrientation);
LIB_FUNC("vDLMoJLde8I", PadSetTiltCorrectionState);
LIB_FUNC("gjP9-KQzoUk", Controller::PadGetControllerInformation);
LIB_FUNC("2JgFB2n9oUM", PadSetTriggerEffect);
LIB_FUNC("2JgFB2n9oUM", Controller::PadSetTriggerEffect);
LIB_FUNC("YndgXqQVV7c", Controller::PadReadState);
LIB_FUNC("q1cHNfGycLI", Controller::PadRead);
LIB_FUNC("yFVnOdGxvZY", Controller::PadSetVibration);
+26 -12
View File
@@ -1055,8 +1055,7 @@ static int ConvertGuestSockaddr(const void* addr, uint32_t addrlen, sockaddr_sto
return 0;
}
#if defined(_WIN32)
static int ConvertHostSockaddr(const sockaddr_storage* addr, int addrlen, void* out,
static int ConvertHostSockaddr(const sockaddr_storage* addr, SocketLength addrlen, void* out,
uint32_t* out_len) {
EXIT_IF(addr == nullptr);
EXIT_IF(out_len == nullptr);
@@ -1066,7 +1065,8 @@ static int ConvertHostSockaddr(const sockaddr_storage* addr, int addrlen, void*
return -1;
}
if (addr->ss_family != AF_INET || addrlen < static_cast<int>(sizeof(sockaddr_in))) {
if (addr->ss_family != AF_INET ||
addrlen < static_cast<SocketLength>(sizeof(sockaddr_in))) {
*Posix::GetErrorAddr() = Posix::POSIX_EOPNOTSUPP;
return -1;
}
@@ -1088,7 +1088,6 @@ static int ConvertHostSockaddr(const sockaddr_storage* addr, int addrlen, void*
*out_len = guest_addrlen;
return 0;
}
#endif
static bool GetSocketBackend(int guest_fd, NativeSocket* out) {
EXIT_IF(out == nullptr);
@@ -1851,19 +1850,13 @@ int KYTY_SYSV_ABI Getsockname(int s, void* addr, uint32_t* addrlen) {
return -1;
}
#if defined(_WIN32)
sockaddr_storage host_addr {};
int host_addrlen = sizeof(host_addr);
if (::getsockname(socket, reinterpret_cast<sockaddr*>(&host_addr), &host_addrlen) ==
SOCKET_ERROR) {
SocketLength host_addrlen = sizeof(host_addr);
if (::getsockname(socket, reinterpret_cast<sockaddr*>(&host_addr), &host_addrlen) != 0) {
return SetHostSocketError();
}
return ConvertHostSockaddr(&host_addr, host_addrlen, addr, addrlen);
#else
*Posix::GetErrorAddr() = Posix::POSIX_ENOSYS;
return -1;
#endif
}
int KYTY_SYSV_ABI Getsockopt(int s, int level, int optname, void* optval, uint32_t* optlen) {
@@ -2818,6 +2811,27 @@ int KYTY_SYSV_ABI HttpCreateRequest(int conn_id, int method, const char* path,
return id.ToInt();
}
int KYTY_SYSV_ABI HttpCreateRequest2(int conn_id, const char* method, const char* path,
uint64_t content_length) {
PRINT_NAME();
LOGF("\t conn_id = %d\n"
"\t method = %s\n"
"\t path = %s\n"
"\t content_length = %" PRIu64 "\n",
conn_id, method, path, content_length);
EXIT_IF(g_net == nullptr);
if (method == nullptr || path == nullptr) {
return HTTP_ERROR_INVALID_VALUE;
}
auto id =
g_net->HttpCreateRequestWithURL2(Network::Id(conn_id), method, path, content_length);
return id.IsValid() ? id.ToInt() : HTTP_ERROR_OUT_OF_MEMORY;
}
int KYTY_SYSV_ABI HttpCreateRequestWithURL2(int conn_id, const char* method, const char* url,
uint64_t content_length) {
PRINT_NAME();
+2
View File
@@ -106,6 +106,8 @@ int KYTY_SYSV_ABI HttpCreateConnectionWithURL(int tmpl_id, const char* url, int
int KYTY_SYSV_ABI HttpDeleteConnection(int conn_id);
int KYTY_SYSV_ABI HttpCreateRequest(int conn_id, int method, const char* path,
uint64_t content_length);
int KYTY_SYSV_ABI HttpCreateRequest2(int conn_id, const char* method, const char* path,
uint64_t content_length);
int KYTY_SYSV_ABI HttpCreateRequestWithURL2(int conn_id, const char* method, const char* url,
uint64_t content_length);
int KYTY_SYSV_ABI HttpSetRequestContentLength(int request_id, uint64_t content_length);
+5 -8
View File
@@ -1166,7 +1166,6 @@ static void PatchProgram(Program* program, uint64_t address, uint64_t size) {
prefix_count++;
}
const size_t inst_size = prefix_count + Jit::Call9::GetSize();
if (inst_ptr + Jit::Call9::GetSize() > start_ptr + size) {
break;
}
@@ -1175,20 +1174,18 @@ static void PatchProgram(Program* program, uint64_t address, uint64_t size) {
if (memcmp(inst_ptr, tls_pattern, 3) == 0 && (modrm & 0xc7u) == 0x04u &&
inst_ptr[4] == tls_pattern[4] &&
*reinterpret_cast<const uint32_t*>(inst_ptr + 5) == 0) {
LOGF("Patch tls at addr: [%016" PRIx64 "]\n", reinterpret_cast<uint64_t>(ptr));
LOGF("Patch tls at addr: [%016" PRIx64 "]\n",
reinterpret_cast<uint64_t>(inst_ptr));
const auto reg = (modrm >> 3u) & 7u;
EXIT_NOT_IMPLEMENTED(reg == 4u);
auto* code = new (ptr) Jit::Call9;
// A raw scan can encounter a 0x66 in the preceding instruction.
auto* code = new (inst_ptr) Jit::Call9;
code->SetFunc(reg == 0
? program->tls.handler_vaddr
: program->tls.handler_vaddr + Jit::TlsRegStub::GetOffset(reg));
if (inst_size > Jit::Call9::GetSize()) {
std::memset(ptr + Jit::Call9::GetSize(), 0x90,
inst_size - Jit::Call9::GetSize());
}
ptr += inst_size - 1;
ptr += prefix_count + Jit::Call9::GetSize() - 1;
}
}
}
+220
View File
@@ -2950,6 +2950,28 @@ public:
"dynamic view identity omitted mapping, format, mip, layer, type, "
"or storage usage");
auto video_out_info = color_info;
video_out_info.pixel_format = vk::Format::eA2R10G10B10UnormPack32;
video_out_info.guest_format = Prospero::BufferFormat::k10_10_10_2UNorm;
Libs::Graphics::Image video_out(m_runtime_context, scheduler,
video_out_info);
auto video_out_view_info = sampled;
video_out_view_info.format = video_out_info.pixel_format;
video_out_view_info.usage = vk::ImageUsageFlagBits::eTransferSrc;
const auto video_out_view = video_out.FindView(video_out_view_info);
auto storage_alias_info = video_out_view_info;
storage_alias_info.format = vk::Format::eA2B10G10R10UnormPack32;
storage_alias_info.usage = vk::ImageUsageFlagBits::eStorage;
const auto storage_alias_view = video_out.FindView(storage_alias_info);
Require(
name, "video-out storage alias usage",
ImageViewOps::FormatsCompatible(video_out_info.pixel_format,
storage_alias_info.format) &&
static_cast<bool>(video_out.backing.usage &
vk::ImageUsageFlagBits::eStorage) &&
video_out_view != nullptr && storage_alias_view != nullptr,
"compatible video-out backing was created without storage usage");
ImageInfo depth_info{};
depth_info.pixel_format = vk::Format::eD32Sfloat;
depth_info.guest_format = Prospero::BufferFormat::k32Float;
@@ -12655,6 +12677,76 @@ TestCase ScalarAbsI32UpdatesScc() {
O::V_MOV_B32, O::BUFFER_STORE_DWORD, O::S_ENDPGM}};
}
TestCase ScalarAbsdiffBitset64AndSetprio() {
using O = ShaderOpcode;
std::vector<u32> code;
auto capture_scc = [&](u32 dst_sgpr) {
code.push_back(
EncodeSop2(0x0a, dst_sgpr, InlineU32(1), InlineU32(0)));
};
code.push_back(EncodeSMovB32(0, InlineU32(2)));
code.push_back(EncodeSMovB32(1, InlineU32(5)));
code.push_back(EncodeSop2(0x2c, 10, 0, 1));
capture_scc(20);
AppendSMovLiteral(&code, 0, 0xffffffffu);
code.push_back(EncodeSMovB32(1, InlineU32(0)));
code.push_back(EncodeSop2(0x2c, 11, 0, 1));
capture_scc(21);
AppendSMovLiteral(&code, 0, 0x80000000u);
code.push_back(EncodeSop2(0x2c, 12, 0, 1));
capture_scc(22);
code.push_back(EncodeSMovB32(1, InlineU32(1)));
code.push_back(EncodeSop2(0x2c, 13, 0, 1));
capture_scc(23);
code.push_back(EncodeSop2(0x2c, 14, 0, 0));
capture_scc(24);
AppendSMovLiteral(&code, 2, 65u);
AppendSMovLiteral(&code, 3, 101u);
code.push_back(EncodeSMovB32(4, InlineU32(0)));
code.push_back(EncodeSMovB32(5, InlineU32(0)));
code.push_back(EncodeSop1(0x1e, 4, 2));
AppendStoreSgprPair(&code, 4, 10);
code.push_back(EncodeSop1(0x1e, 4, 3));
AppendStoreSgprPair(&code, 4, 12);
code.push_back(EncodeSop1(0x1c, 4, 2));
AppendStoreSgprPair(&code, 4, 14);
code.push_back(EncodeSop1(0x1c, 4, 3));
AppendStoreSgprPair(&code, 4, 16);
code.push_back(EncodeSopp(0x0f, 3));
AppendStoreSgpr(&code, 10, 0);
AppendStoreSgpr(&code, 11, 1);
AppendStoreSgpr(&code, 12, 2);
AppendStoreSgpr(&code, 13, 3);
AppendStoreSgpr(&code, 14, 4);
AppendStoreSgpr(&code, 20, 5);
AppendStoreSgpr(&code, 21, 6);
AppendStoreSgpr(&code, 22, 7);
AppendStoreSgpr(&code, 23, 8);
AppendStoreSgpr(&code, 24, 9);
AppendEnd(&code);
TestCase test;
test.name = "ScalarAbsdiffBitset64AndSetprio";
test.code = std::move(code);
test.expected = {3u, 1u, 0x80000000u, 0x7fffffffu, 0u,
1u, 1u, 1u, 1u, 0u,
2u, 0u, 2u, 32u, 0u,
32u, 0u, 0u};
test.opcodes = {O::S_MOV_B32, O::S_ABSDIFF_I32, O::S_CSELECT_B32,
O::S_BITSET1_B64, O::S_BITSET0_B64, O::S_SETPRIO,
O::V_MOV_B32,
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
test.decoded_counts = {{"S_ABSDIFF_I32", 5},
{"S_BITSET1_B64", 2},
{"S_BITSET0_B64", 2},
{"S_SETPRIO 0x00000003", 1}};
return test;
}
TestCase ScalarShiftLeftAddSccCarryEdges() {
using O = ShaderOpcode;
@@ -14155,6 +14247,55 @@ TestCase VectorAddcWritesPerLaneCarryOut() {
return test;
}
TestCase VectorSubCoCiU32CompactAndVop3() {
using O = ShaderOpcode;
std::vector<u32> code;
code.push_back(EncodeVop2(0x1a, 4, InlineU32(2), 0));
AppendBufferLoadDword(&code, 1, 4);
code.push_back(EncodeVop2(0x25, 5, InlineU32(16), 4));
AppendBufferLoadDword(&code, 2, 5);
code.push_back(EncodeVop2(0x1b, 3, InlineU32(1), 0));
code.push_back(EncodeVopc(0xc5, InlineU32(0), 3));
code.push_back(EncodeSop1(0x04, 20, 106));
code.push_back(EncodeVop2(0x29, 10, Vgpr(1), 2));
AppendVMovU32(&code, 6, 1);
code.push_back(EncodeVop2(0x01, 11, InlineU32(0), 6));
AppendStoreVgprAtLaneDwordOffset(&code, 10, 0, 0);
AppendStoreVgprAtLaneDwordOffset(&code, 11, 0, 4);
code.push_back(EncodeVopc(0xc2, InlineU32(0), 6));
AppendVop3B(&code, 0x129u, 12, 22, Vgpr(1), Vgpr(2), 20);
AppendVop3(&code, 0x101u, 13, InlineU32(0), Vgpr(6), 22);
code.push_back(EncodeVop2(0x01, 14, InlineU32(0), 6));
AppendStoreVgprAtLaneDwordOffset(&code, 12, 0, 8);
AppendStoreVgprAtLaneDwordOffset(&code, 13, 0, 12);
AppendStoreVgprAtLaneDwordOffset(&code, 14, 0, 16);
AppendEnd(&code);
TestCase test;
test.name = "VectorSubCoCiU32CompactAndVop3";
test.code = std::move(code);
test.initial = {5u, 5u, 3u, 3u, 3u, 3u, 5u, 3u, 0u, 0u,
0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u};
test.expected = {2u, 1u, 0xfffffffeu, 0xffffffffu, 0u, 0u, 1u,
1u, 2u, 1u, 0xfffffffeu, 0xffffffffu, 0u, 0u,
1u, 1u, 0u, 0u, 0u, 0u};
test.opcodes = {O::V_MOV_B32, O::V_LSHLREV_B32, O::V_ADD_NC_U32,
O::V_AND_B32, O::V_CMP_NE_U32, O::V_CMP_EQ_U32,
O::V_SUB_CO_CI_U32, O::V_CNDMASK_B32, O::S_MOV_B64,
O::BUFFER_LOAD_DWORD, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
test.decoded_counts = {{"V_SUB_CO_CI_U32", 2}};
test.required_spirv = {"OpISub", "OpUGreaterThan", "OpLogicalOr"};
test.compute_info.threads_num[0] = 4;
test.compute_info.threads_num[1] = 1;
test.compute_info.threads_num[2] = 1;
test.compute_info.thread_ids_num = 1;
test.compute_info.wave_size = 32;
test.has_compute_info = true;
return test;
}
TestCase VectorSubrevCoCiU32ExactRawOnGpu() {
using O = ShaderOpcode;
@@ -15121,6 +15262,31 @@ TestCase VectorDppQuadPermuteReverse() {
return test;
}
TestCase VectorDppRowXmask() {
using O = ShaderOpcode;
std::vector<u32> code;
AppendVMovU32(&code, 1, 100);
code.push_back(EncodeVop2(0x25, 2, 250, 1));
code.push_back(EncodeVop2Dpp(0, 0x164));
code.push_back(EncodeVop2(0x1a, 3, InlineU32(2), 0));
AppendBufferStoreDword(&code, 2, 3);
AppendEnd(&code);
TestCase test;
test.name = "VectorDppRowXmask";
test.code = code;
test.expected = {104, 105, 106, 107, 100, 101, 102, 103};
test.opcodes = {O::V_MOV_B32, O::V_ADD_NC_U32, O::V_LSHLREV_B32,
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
test.compute_info.threads_num[0] = 8;
test.compute_info.threads_num[1] = 1;
test.compute_info.threads_num[2] = 1;
test.compute_info.thread_ids_num = 1;
test.has_compute_info = true;
return test;
}
TestCase VectorDppBankMaskPreservesDestination() {
using O = ShaderOpcode;
@@ -21121,6 +21287,7 @@ std::vector<TestCase> MakeCases() {
AddCase(ScalarArithmeticSccCarryBorrowOverflow);
AddCase(ScalarMinMaxSccComparisonEdges);
AddCase(ScalarAbsI32UpdatesScc);
AddCase(ScalarAbsdiffBitset64AndSetprio);
AddCase(ScalarShiftLeftAddSccCarryEdges);
AddCase(ScalarCompareOps);
AddCase(ScalarShiftAddAndMaskOps);
@@ -21166,6 +21333,7 @@ std::vector<TestCase> MakeCases() {
AddCase(VectorMbcntUsesThreadMask);
AddCase(VectorAddcWritesPerLaneCarryOut);
AddCase(VectorAddcUsesPerLaneCarryIn);
AddCase(VectorSubCoCiU32CompactAndVop3);
AddCase(VectorSubrevCoCiU32ExactRawOnGpu);
AddCase(VectorVop3BSubrevCoCiUsesEncodedMasks);
AddCase(VectorVop3BCarryOutWritesSgprMask);
@@ -21194,6 +21362,7 @@ std::vector<TestCase> MakeCases() {
AddCase(VectorPermlane16FetchInactiveZero);
AddCase(VectorPermlane16FetchInactiveFi);
AddCase(VectorDppQuadPermuteReverse);
AddCase(VectorDppRowXmask);
AddCase(VectorDppBankMaskPreservesDestination);
AddCase(VectorDppBoundsControlZeroPreservesDestination);
AddCase(Vop3LdexpSourceModifier);
@@ -23413,6 +23582,7 @@ void CheckStorageTextureDepthTileUploadLayout() {
"1x1 R8_UINT depth tile lost its 64 KiB source footprint");
std::printf("[host] %-32s ok\n", "StorageTextureDepthTileUpload");
}
void CheckImageSamplerSpecialization() {
ShaderSamplerResource filtered_sampler{};
filtered_sampler.fields[2] =
@@ -24723,6 +24893,54 @@ void CheckPm4PolygonOffsetRegisters(RenderContext &renderer) {
std::printf("[host] %-32s ok\n", "Pm4PolygonOffset");
}
void CheckPm4DepthControlHighBits(RenderContext &renderer) {
GraphicsInitJmpTables();
CommandProcessor processor(renderer, 0);
std::array<uint32_t, 3> direct{
KYTY_PM4(3, Pm4::IT_SET_CONTEXT_REG, Pm4::R_ZERO),
Pm4::DB_DEPTH_CONTROL,
0x80000072u,
};
Pm4Execution direct_execution;
const bool direct_complete =
processor.Process(direct_execution, direct) == Pm4ProcessResult::Complete;
const auto &direct_control = processor.GetCtx().GetDepthControl();
const bool direct_decoded =
!direct_control.stencil_enable && direct_control.z_enable &&
!direct_control.z_write_enable && !direct_control.depth_bounds_enable &&
direct_control.zfunc == 7u && !direct_control.backface_enable &&
direct_control.stencilfunc == 0u && direct_control.stencilfunc_bf == 0u;
std::array<uint32_t, 2> registers{
Pm4::DB_DEPTH_CONTROL,
0x4070078du,
};
const auto address = reinterpret_cast<uint64_t>(registers.data());
std::array<uint32_t, 5> indirect{
KYTY_PM4(5, Pm4::IT_SET_CONTEXT_REG_INDIRECT, Pm4::R_ZERO),
static_cast<uint32_t>(address), static_cast<uint32_t>(address >> 32u),
0x80000000u, 1u,
};
Pm4Execution indirect_execution;
const bool indirect_complete =
processor.Process(indirect_execution, indirect) ==
Pm4ProcessResult::Complete;
const auto &indirect_control = processor.GetCtx().GetDepthControl();
const bool indirect_decoded =
indirect_control.stencil_enable && !indirect_control.z_enable &&
indirect_control.z_write_enable && indirect_control.depth_bounds_enable &&
indirect_control.zfunc == 0u && indirect_control.backface_enable &&
indirect_control.stencilfunc == 7u &&
indirect_control.stencilfunc_bf == 7u;
Require("Pm4DepthControlHighBits", "preserved high bits",
direct_complete && direct_decoded && indirect_complete &&
indirect_decoded,
"DB_DEPTH_CONTROL high bits rejected or changed decoded PS5 state");
std::printf("[host] %-32s ok\n", "Pm4DepthControlHighBits");
}
struct AgcCommandBufferLayout {
using Callback = KYTY_SYSV_ABI bool (*)(Gen5::CommandBuffer *, uint32_t,
void *);
@@ -25325,6 +25543,7 @@ int main(int argc, char **argv) {
CheckPm4PrivateAgcUconfigRegisters(vulkan.RuntimeRenderer());
CheckPm4BlendColorRegisterRanges(vulkan.RuntimeRenderer());
CheckPm4PolygonOffsetRegisters(vulkan.RuntimeRenderer());
CheckPm4DepthControlHighBits(vulkan.RuntimeRenderer());
CheckPm4ContextStateOperations(vulkan.RuntimeRenderer());
return 0;
}
@@ -25514,6 +25733,7 @@ int main(int argc, char **argv) {
CheckPm4GuardBandRegisterRanges(vulkan.RuntimeRenderer());
CheckPm4BlendColorRegisterRanges(vulkan.RuntimeRenderer());
CheckPm4PolygonOffsetRegisters(vulkan.RuntimeRenderer());
CheckPm4DepthControlHighBits(vulkan.RuntimeRenderer());
CheckAgcWaitPackets(vulkan.RuntimeRenderer());
CheckAgcDrawIndirectMultiPacket(vulkan.RuntimeRenderer());
CheckPm4ContextStateOperations(vulkan.RuntimeRenderer());
+40
View File
@@ -8811,6 +8811,45 @@ void TestNewShaderRecompilerExpVertexOutputs() {
CheckSpirvBinaryValidates(result.spirv);
}
void TestNewShaderRecompilerClipDisabledPosition() {
const uint32_t shader[] = {
EncodeExp0(0x0c, 0xf), EncodeExp1(0, 1, 2, 3), 0xbf810000u,
};
const auto compile = [&](const ShaderVertexInputInfo &vertex) {
auto options = MakeCompileOptions(ShaderType::Vertex);
options.input_info.vertex = &vertex;
return ShaderRecompiler::Recompile(shader, options);
};
ShaderVertexInputInfo regular{};
auto clipped = regular;
clipped.clip_space = {
.scale = {640.0f, 360.0f},
.offset = {640.0f, 360.0f},
.half_extent = {8192.0f, 8192.0f},
.enabled = true,
};
const auto regular_result = compile(regular);
const auto clipped_result = compile(clipped);
CheckSpirvBinaryValidates(clipped_result.spirv);
Check(SpirvInstructionOpcodeCount(regular_result.spirv, 136u) == 0u &&
SpirvInstructionOpcodeCount(clipped_result.spirv, 133u) == 2u &&
SpirvInstructionOpcodeCount(clipped_result.spirv, 129u) == 2u &&
SpirvInstructionOpcodeCount(clipped_result.spirv, 136u) == 2u &&
SpirvInstructionOpcodeCount(clipped_result.spirv, 131u) == 2u,
"clip-disabled position export did not convert both screen coordinates to NDC");
Check(MakeStageStaticKey(regular) != MakeStageStaticKey(clipped),
"clip-disabled vertex shader shared the regular shader cache key");
auto disabled = clipped;
disabled.clip_space.enabled = false;
Check(MakeStageStaticKey(regular) == MakeStageStaticKey(disabled),
"disabled clip-space payload affected the shader cache key");
auto shifted = clipped;
shifted.clip_space.offset[0] += 1.0f;
Check(MakeStageStaticKey(clipped) != MakeStageStaticKey(shifted),
"clip-disabled viewport transform is absent from the shader cache key");
}
void TestNewShaderRecompilerAuxPositionExports() {
const auto compile = [](std::span<const uint32_t> shader, uint32_t control) {
ShaderVertexInputInfo vertex{};
@@ -11908,6 +11947,7 @@ int main() {
TestNewShaderRecompilerSpirvSizeBaselines();
TestDemandDrivenSpirvDeclarations();
TestNewShaderRecompilerSMovB32();
TestNewShaderRecompilerClipDisabledPosition();
TestNewShaderRecompilerAuxPositionExports();
TestNewShaderRecompilerNativeWideScalarMemoryIr();
TestNewShaderRecompilerNativeWideBufferIr();