77 lines
3.9 KiB
C++
77 lines
3.9 KiB
C++
#include "BdaShader.hpp"
|
|
#include "SpirvBackend/SpirvBda.hpp"
|
|
#include "SpirvBackend/SpirvMemory/SpirvTypes.hpp"
|
|
#include "SpirvBackend/SpirvMemory/SpirvConstants.hpp"
|
|
|
|
namespace {
|
|
|
|
template<typename TEmit>
|
|
std::vector<std::uint32_t> MakeShader(std::uint64_t address, bool coherent, bool stops, const TEmit& emit) {
|
|
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<std::uint32_t> 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 = program.CreateValue(IrOpcode::LoadAddressU32, IrType::U32);
|
|
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<std::uint32_t> 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<std::uint64_t>(offset) : static_cast<std::uint64_t>(offset)), offset < 0);
|
|
return std::vector<std::uint32_t>{EmitBdaRead(ctx, instruction, base, bits)};
|
|
});
|
|
}
|
|
|
|
std::vector<std::uint32_t> 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<std::uint32_t>(values.begin(), values.begin() + dwords);
|
|
});
|
|
}
|