[Agc] Emit addressed draw events for occlusion query counters
This commit is contained in:
parent
a9356eb8d2
commit
aaed66bf83
|
|
@ -64,14 +64,24 @@ public static partial class AgcExports
|
|||
var commandBufferAddress = ctx[CpuRegister.Rdi];
|
||||
var eventType = (uint)(ctx[CpuRegister.Rsi] & 0xFF);
|
||||
var eventAddress = ctx[CpuRegister.Rdx];
|
||||
if (commandBufferAddress == 0 || eventType > 0x3F || eventAddress != 0)
|
||||
if (commandBufferAddress == 0 || eventType > 0x3F || (eventAddress != 0 && (eventType & ~1u) != 0x38))
|
||||
{
|
||||
return ReturnPointer(ctx, 0);
|
||||
}
|
||||
|
||||
if (!TryAllocateCommandDwords(ctx, commandBufferAddress, 2, out var commandAddress) ||
|
||||
!TryWriteUInt32(ctx, commandAddress, Pm4(2, ItEventWrite, 0)) ||
|
||||
!TryWriteUInt32(ctx, commandAddress + 4, eventType))
|
||||
// Counter selection and counter dumps carry a payload in the address fields.
|
||||
var hasAddress = (eventType & ~1u) == 0x38;
|
||||
var packetDwords = hasAddress ? 4u : 2u;
|
||||
if (!TryAllocateCommandDwords(ctx, commandBufferAddress, packetDwords, out var commandAddress) ||
|
||||
!TryWriteUInt32(ctx, commandAddress, Pm4(packetDwords, ItEventWrite, 0)) ||
|
||||
!TryWriteUInt32(ctx, commandAddress + 4, hasAddress ? eventType | 0x100u : eventType))
|
||||
{
|
||||
return ReturnPointer(ctx, 0);
|
||||
}
|
||||
|
||||
if (hasAddress &&
|
||||
(!TryWriteUInt32(ctx, commandAddress + 8, (uint)eventAddress & ~7u) ||
|
||||
!TryWriteUInt32(ctx, commandAddress + 12, (uint)(eventAddress >> 32))))
|
||||
{
|
||||
return ReturnPointer(ctx, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
// Copyright (C) 2026 SharpEmu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
using System.Buffers.Binary;
|
||||
using SharpEmu.HLE;
|
||||
using SharpEmu.Libs.Agc;
|
||||
using SharpEmu.Libs.Gpu.GpuCommands;
|
||||
using SharpEmu.Libs.Tests.Gpu.GpuCommands;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpEmu.Libs.Tests.Agc;
|
||||
|
||||
public sealed class AgcEventWriteTests
|
||||
{
|
||||
[Fact]
|
||||
public void DrawCounterDumpsPublishBothHalvesOfQueryResults()
|
||||
{
|
||||
var runner = new StreamRunner();
|
||||
var begin = Build(0x39, StreamRunner.LabelAddress);
|
||||
var end = Build(0x39, StreamRunner.LabelAddress + 8);
|
||||
|
||||
Assert.Equal(0x139u, begin[1]);
|
||||
Assert.Equal(SubmissionProgress.Complete, runner.Run(begin, end));
|
||||
for (var block = 0u; block < 16; block++)
|
||||
{
|
||||
var address = StreamRunner.LabelAddress + block * 16;
|
||||
var first = runner.Host.ReadQword(address);
|
||||
var last = runner.Host.ReadQword(address + 8);
|
||||
Assert.NotEqual(0UL, first & last & (1UL << 63));
|
||||
Assert.True(last > first);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0x38u, 0x1234567800UL, 4)]
|
||||
[InlineData(0x39u, 0x1234567800UL, 4)]
|
||||
[InlineData(0x3Au, 0UL, 2)]
|
||||
[InlineData(0x10u, 0UL, 2)]
|
||||
public void DrawEventsPreservePayloadAndAdvanceCursor(uint eventType, ulong payload, int words)
|
||||
{
|
||||
var packet = Build(eventType, payload);
|
||||
Assert.Equal(words, packet.Length);
|
||||
Assert.Equal(eventType | (words == 4 ? 0x100u : 0), packet[1]);
|
||||
if (words == 4)
|
||||
{
|
||||
Assert.Equal((uint)payload, packet[2]);
|
||||
Assert.Equal((uint)(payload >> 32), packet[3]);
|
||||
}
|
||||
}
|
||||
|
||||
private static uint[] Build(uint eventType, ulong payload)
|
||||
{
|
||||
const ulong memoryAddress = 0x2_1000_0000;
|
||||
const ulong commandBuffer = memoryAddress + 0x80;
|
||||
const ulong packetAddress = memoryAddress + 0x200;
|
||||
var memory = new FakeCpuMemory(memoryAddress, 0x1000);
|
||||
var context = new CpuContext(memory, Generation.Gen5);
|
||||
Span<byte> bytes = stackalloc byte[16];
|
||||
BinaryPrimitives.WriteUInt64LittleEndian(bytes, packetAddress);
|
||||
BinaryPrimitives.WriteUInt64LittleEndian(bytes[8..], packetAddress + 0x100);
|
||||
Assert.True(memory.TryWrite(commandBuffer + 0x10, bytes));
|
||||
context[CpuRegister.Rdi] = commandBuffer;
|
||||
context[CpuRegister.Rsi] = eventType;
|
||||
context[CpuRegister.Rdx] = payload;
|
||||
|
||||
AgcExports.DcbEventWrite(context);
|
||||
Assert.Equal(packetAddress, context[CpuRegister.Rax]);
|
||||
Assert.True(memory.TryRead(commandBuffer + 0x10, bytes[..8]));
|
||||
var length = checked((int)(BinaryPrimitives.ReadUInt64LittleEndian(bytes) - packetAddress));
|
||||
Assert.InRange(length, 8, 16);
|
||||
Assert.True(memory.TryRead(packetAddress, bytes[..length]));
|
||||
var packet = new uint[length / 4];
|
||||
for (var i = 0; i < packet.Length; i++)
|
||||
packet[i] = BinaryPrimitives.ReadUInt32LittleEndian(bytes[(i * 4)..]);
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue