#include "BdaShader.hpp" #include "SpirvBackend/SpirvBda.hpp" #include "SpirvBackend/SpirvMemory/SpirvTypes.hpp" #include "SpirvBackend/SpirvMemory/SpirvConstants.hpp" #include "IntermediateRepresentation/IrBuilder.hpp" namespace { template std::vector MakeShader(std::uint64_t address, bool coherent, bool stops, const TEmit& emit, std::uint32_t extracted = 0) { using namespace ShaderRecompiler; IrProgram program; program.Resources().stage = IrShaderStage::Compute; program.Info().usesDma = true; if (coherent) { MemoryInfo memory; memory.coherent = true; program.Resources().memoryInfo = {memory}; } SpirvEmitterState state(program, {}); EmitBaseHeader(state.module, program); const auto define = [&](std::uint32_t binding) { const auto variable = state.module.DefineGlobalVariable(TypeStorageBufferPointer(state), spv::StorageClassStorageBuffer); state.module.AddAnnotation(spv::OpDecorate, variable, spv::DecorationDescriptorSet, 0u); state.module.AddAnnotation(spv::OpDecorate, variable, spv::DecorationBinding, binding); return variable; }; state.bdaPagetableVariable = define(0); state.faultBufferVariable = define(1); const auto output = define(2); std::vector interfaceVariables; if (!stops) { interfaceVariables.push_back(state.module.DefineGlobalVariable(TypePointer(state, spv::StorageClassInput, TypeU32(state)), spv::StorageClassInput)); state.module.AddAnnotation(spv::OpDecorate, interfaceVariables[0], spv::DecorationBuiltIn, spv::BuiltInLocalInvocationIndex); } state.bdaStopsInvocations = stops; DefineGetBdaPointer(state); const auto main = state.module.AllocateId(); state.module.AddFunction(spv::OpFunction, TypeVoid(state), main, spv::FunctionControlMaskNone, TypeFunction(state)); EmitLabel(state, state.module.AllocateId()); SpirvValueEmitContext ctx(state); auto& instruction = extracted != 0u ? program.CreateValue(IrOpcode::LoadAddressU32x4, IrType::U32x4) : program.CreateValue(IrOpcode::LoadAddressU32, IrType::U32); IrBuilder ir(program); for (std::uint32_t dword = 0; dword < 4u; ++dword) { if ((extracted & (1u << dword)) == 0u) continue; auto& extract = program.CreateValue(IrOpcode::CompositeExtractU32x4, IrType::U32); extract.AddArgument(&instruction); extract.AddArgument(&ir.Constant(dword)); } MemoryFlags flags{}; flags.pc = 0x1234; instruction.SetFlags(flags); auto base = BdaConstant(state, address); if (!stops) { const auto index = state.module.AllocateId(); state.module.AddFunction(spv::OpLoad, TypeU32(state), index, interfaceVariables[0]); base = Binary(state, spv::OpIAdd, TypeScalarU64(state), base, Unary(state, spv::OpUConvert, TypeScalarU64(state), index)); } const auto values = emit(ctx, instruction, base); for (std::uint32_t index = 0; index < values.size(); ++index) state.module.AddFunction(spv::OpStore, BdaWord(state, output, ConstantU32(state, index)), values[index]); state.module.AddFunction(spv::OpReturn); state.module.AddFunction(spv::OpFunctionEnd); state.module.AddExecutionMode(main, spv::ExecutionModeLocalSize, 1u, 1u, 1u); state.module.EmitEntryPoint(spv::ExecutionModelGLCompute, main, "main", interfaceVariables); return state.module.Finalize(); } } std::vector MakeBdaTestShader(std::uint64_t address, std::uint32_t bits, std::int64_t offset) { using namespace ShaderRecompiler; return MakeShader(address, false, true, [&](SpirvValueEmitContext& ctx, const IrValue& instruction, std::uint32_t base) { if (offset != 0) base = AddBdaAddress(ctx, instruction, base, BdaConstant(ctx.state, offset < 0 ? std::uint64_t{0} - static_cast(offset) : static_cast(offset)), offset < 0); return std::vector{EmitBdaRead(ctx, instruction, base, bits)}; }); } std::vector MakeBdaSpanReadTestShader(std::uint64_t address, std::uint32_t offset, std::uint32_t extracted, bool coherent, bool stops) { using namespace ShaderRecompiler; return MakeShader(address, coherent, stops, [&](SpirvValueEmitContext& ctx, const IrValue& instruction, std::uint32_t base) { const auto values = EmitBdaDwordReads(ctx, instruction, base, offset, 4u); return std::vector(values.begin(), values.end()); }, extracted); } std::vector MakeBdaDwordReadTestShader(std::uint64_t address, std::uint32_t dwords, bool coherent, bool stops) { using namespace ShaderRecompiler; return MakeShader(address, coherent, stops, [&](SpirvValueEmitContext& ctx, const IrValue& instruction, std::uint32_t base) { const auto values = EmitBdaDwordReads(ctx, instruction, base, 0u, dwords, true); return std::vector(values.begin(), values.begin() + dwords); }); }