Merge pull request #4518 from AlxcBTW/fix/bda-unaligned-dword-write
fix(shader): store unaligned 32-bit BDA writes byte by byte
This commit is contained in:
commit
c90404f97a
|
|
@ -9,6 +9,7 @@
|
|||
#include <limits>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
|
@ -345,15 +346,16 @@ void RunBdaStoreExecutionTests(const Context& context) {
|
|||
constexpr std::uint32_t writable = Abi::Read | Abi::Write;
|
||||
const Abi::Header header{Abi::Version, 2, sizeof(Abi::Range), 0};
|
||||
std::array<Abi::Range, 2> ranges{};
|
||||
bool runtime = false;
|
||||
const auto run = [&](const char* name, std::uint64_t address, std::uint32_t bits, bool coherent, const std::array<std::uint8_t, 5>& expected, std::initializer_list<std::uint64_t> writtenAddresses, Abi::FaultReason reason = {}, std::uint64_t faultAddress = 0, std::uint32_t faultBytes = 0) {
|
||||
const std::string label = std::string("BDA store ") + name + (coherent ? " coherent: " : ": ");
|
||||
const std::string label = std::string(runtime ? "BDA runtime write " : "BDA store ") + name + (coherent ? " coherent: " : ": ");
|
||||
std::memset(first.Bytes().data(), 0xcd, first.Bytes().size());
|
||||
std::memset(second.Bytes().data(), 0xcd, second.Bytes().size());
|
||||
std::memcpy(table.Bytes().data(), &header, sizeof(header));
|
||||
std::memcpy(table.Bytes().data() + sizeof(header), ranges.data(), sizeof(ranges));
|
||||
std::memset(fault.Bytes().data(), 0, fault.Bytes().size());
|
||||
std::memset(output.Bytes().data(), 0, output.Bytes().size());
|
||||
Pipeline pipeline(context, MakeBdaStoreTestShader(address, 0xa1b2c3d4u, bits, coherent), {&table, &fault, &output});
|
||||
Pipeline pipeline(context, runtime ? MakeBdaWriteTestShader(address, 0xa1b2c3d4u, bits, coherent) : MakeBdaStoreTestShader(address, 0xa1b2c3d4u, bits, coherent), {&table, &fault, &output});
|
||||
pipeline.Run(1);
|
||||
std::array<std::uint8_t, 5> actual{};
|
||||
std::memcpy(actual.data(), first.Bytes().data(), 2);
|
||||
|
|
@ -387,7 +389,8 @@ void RunBdaStoreExecutionTests(const Context& context) {
|
|||
std::memcpy(&completed, output.Bytes().data(), sizeof(completed));
|
||||
Require(completed == 1, label + "store did not finish its per-byte accesses");
|
||||
};
|
||||
for (const bool coherent : {false, true}) {
|
||||
for (const auto& [coherent, writes] : std::initializer_list<std::pair<bool, bool>>{{false, false}, {false, true}, {true, false}, {true, true}}) {
|
||||
runtime = writes;
|
||||
ranges = {{{guest, guest + 2, first.DeviceAddress(), writable, 0}, {guest + 2, guest + 5, second.DeviceAddress(), writable, 0}}};
|
||||
run("byte", guest + 1, 8, coherent, {0xcd, 0xd4, 0xcd, 0xcd, 0xcd}, {guest + 1});
|
||||
run("split short", guest + 1, 16, coherent, {0xcd, 0xd4, 0xc3, 0xcd, 0xcd}, {guest + 1, guest + 2});
|
||||
|
|
|
|||
|
|
@ -121,3 +121,15 @@ std::vector<std::uint32_t> MakeBdaStoreTestShader(std::uint64_t address, std::ui
|
|||
#endif
|
||||
return shader;
|
||||
}
|
||||
|
||||
std::vector<std::uint32_t> MakeBdaWriteTestShader(std::uint64_t address, std::uint32_t value, std::uint32_t bits, bool coherent) {
|
||||
using namespace ShaderRecompiler;
|
||||
auto shader = MakeShader(address, coherent, true, [&](SpirvValueEmitContext& ctx, const IrValue& instruction, std::uint32_t base) {
|
||||
EmitBdaWrite(ctx, instruction, base, ConstantU32(ctx.state, value), bits);
|
||||
return std::vector<std::uint32_t>{ConstantU32(ctx.state, 1u)};
|
||||
}, 0u, true);
|
||||
#if ANYPS5_ENABLE_SPIRV_TOOLS
|
||||
shader = ValidateAndOptimizeSpirv(shader, VK_API_VERSION_1_1, shader[1], false, false);
|
||||
#endif
|
||||
return shader;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ std::vector<std::uint32_t> MakeBdaDwordReadTestShader(std::uint64_t address, std
|
|||
std::vector<std::uint32_t> MakeBdaSpanReadTestShader(std::uint64_t address, std::uint32_t offset, std::uint32_t extracted, bool coherent, bool stops);
|
||||
std::vector<std::uint32_t> MakeBdaDwordWriteTestShader(std::uint64_t address, std::uint32_t dwords, const std::uint32_t* values);
|
||||
std::vector<std::uint32_t> MakeBdaStoreTestShader(std::uint64_t address, std::uint32_t value, std::uint32_t bits, bool coherent);
|
||||
std::vector<std::uint32_t> MakeBdaWriteTestShader(std::uint64_t address, std::uint32_t value, std::uint32_t bits, bool coherent);
|
||||
void RunBdaStoreExecutionTests(const AgcDriver::Graphics::Context& context);
|
||||
void RunBdaExecutionTests(const AgcDriver::Graphics::Context& context);
|
||||
void RunBdaContractTests();
|
||||
|
|
|
|||
|
|
@ -358,7 +358,7 @@ void EmitBdaWrite(SpirvValueEmitContext& ctx, const IrValue& inst, std::uint32_t
|
|||
if (state.bdaWritePointerFunction == 0 || state.bdaNoteWriteFunction == 0) ctx.Fail(inst, "BDA write functions are missing");
|
||||
const auto instruction = BdaInstructionPc(state, inst);
|
||||
if (bits != 8u && bits != 16u && bits != 32u) ctx.Fail(inst, "unsupported BDA write width");
|
||||
if (bits != 32u) {
|
||||
const auto storeBytes = [&] {
|
||||
EmitBdaOverflowCheck(state, address, bits / 8u, instruction);
|
||||
for (std::uint32_t byte = 0u; byte < bits / 8u; ++byte) {
|
||||
const auto guest = Binary(state, spv::OpIAdd, TypeScalarU64(state), address, BdaConstant(state, byte));
|
||||
|
|
@ -373,10 +373,13 @@ void EmitBdaWrite(SpirvValueEmitContext& ctx, const IrValue& inst, std::uint32_t
|
|||
state.module.AddFunction(spv::OpFunctionCall, state.module.Type(spv::OpTypeVoid), state.module.AllocateId(), state.bdaNoteWriteFunction, guest);
|
||||
});
|
||||
}
|
||||
};
|
||||
if (bits != 32u) {
|
||||
storeBytes();
|
||||
return;
|
||||
}
|
||||
const auto unaligned = BdaAddressUnaligned(state, address);
|
||||
EmitIfCondition(state, unaligned, [&] { RecordBdaFault(state, address, ConstantU32(state, 4u), instruction, BdaAbi::FaultReason::Unaligned); });
|
||||
EmitIfCondition(state, unaligned, storeBytes);
|
||||
EmitIfCondition(state, Unary(state, spv::OpLogicalNot, TypeBool(state), unaligned), [&] {
|
||||
EmitBdaStoreAt(state, address, 4u, TypePhysicalU32Pointer(state), value, instruction, BdaAccessMask(state, inst));
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue