Repository navigation
Port upstream AGC driver shared slice (U5) #475
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
8492706
772940b
981ccc5
103b634
3c544e2
03f59ba
c402998
32d0106
845cab4
b2bd9ce
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -133,9 +133,12 @@ void copyMemory(std::uint64_t source, std::uint64_t destination, std::size_t byt | |
| GuestMemory::Write(destination, copySource(source, bytes, immediate)); | ||
| } | ||
|
|
||
| constexpr std::uint32_t CopyDataRegisterSource = 0; | ||
| constexpr std::uint32_t CopyDataGpuClockSource = 18; | ||
| constexpr std::uint32_t CopyDataCachePolicy = (3u << 13u) | (3u << 25u); | ||
| constexpr std::uint32_t ShaderRegisterBase = 0x2c00; | ||
| constexpr std::uint32_t ContextRegisterBase = 0xa000; | ||
| constexpr std::uint32_t UserConfigRegisterBase = 0xc000; | ||
|
|
||
| bool copyDataToRegister(std::span<const std::uint32_t> packet) { | ||
| return ((packet[1] >> 8u) & 0xfu) == 0; | ||
|
|
@@ -149,8 +152,27 @@ std::uint64_t gpuClockCount() { | |
| return static_cast<std::uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch()).count() / 10); | ||
| } | ||
|
|
||
| std::vector<std::byte> copyDataSource(std::span<const std::uint32_t> packet, std::size_t bytes) { | ||
| std::uint32_t registerBankBase(std::uint32_t offset) { | ||
| if (offset - ShaderRegisterBase < 0x400u) return ShaderRegisterBase; | ||
| if (offset - ContextRegisterBase < 0x400u) return ContextRegisterBase; | ||
| if (offset - UserConfigRegisterBase < 0x4000u) return UserConfigRegisterBase; | ||
| return 0; | ||
| } | ||
|
|
||
| std::vector<std::byte> copyDataSource(std::span<const std::uint32_t> packet, const QueueState& queue, std::size_t bytes) { | ||
| const auto source = ((packet[1] & 0xfu) << 1u) | ((packet[1] >> 30u) & 1u); | ||
| if (source == CopyDataRegisterSource) { | ||
| std::vector<std::byte> data(bytes); | ||
| for (std::size_t word = 0; word < bytes / 4; ++word) { | ||
| const auto offset = packet[2] + static_cast<std::uint32_t>(word); | ||
| const auto base = registerBankBase(offset); | ||
| const auto& bank = base == ShaderRegisterBase ? queue.shader : base == ContextRegisterBase ? queue.context : queue.userConfig; | ||
| if (base == 0 || !bank.contains(offset - base)) throw std::runtime_error("COPY_DATA source register 0x" + ToHex(offset) + " has no known value"); | ||
| const auto value = bank.at(offset - base); | ||
| for (std::size_t i = 0; i < 4; ++i) data[word * 4 + i] = static_cast<std::byte>(value >> (i * 8)); | ||
| } | ||
| return data; | ||
| } | ||
| if (source != CopyDataGpuClockSource) return copySource(address(packet[2], packet[3]), bytes, source >= 10); | ||
| const auto value = gpuClockCount(); | ||
| std::vector<std::byte> data(bytes); | ||
|
|
@@ -467,7 +489,8 @@ void Validate(std::span<const std::uint32_t> packet, std::uint32_t queue) { | |
| break; | ||
| } | ||
| require(destination == 2 || destination == 4 || destination == 10, "COPY_DATA GDS or performance-counter destination is not implemented"); | ||
| require(source == 2 || source == 4 || source == 5 || source == 10 || source == 11 || source == CopyDataGpuClockSource, "COPY_DATA register, GDS or reference-clock source is not implemented"); | ||
| require(source == 2 || source == 4 || source == 5 || source == 10 || source == 11 || source == CopyDataGpuClockSource || source == CopyDataRegisterSource, "COPY_DATA GDS or reference-clock source is not implemented"); | ||
| require(source != CopyDataRegisterSource || (packet[3] == 0 && registerBankBase(packet[2]) != 0 && registerBankBase(packet[2]) == registerBankBase(packet[2] + copyDataCount(packet) - 1)), "COPY_DATA from a register outside the shader, context and user config registers is not implemented"); | ||
| require(source < 10 || source == CopyDataGpuClockSource || ((packet[1] & 0x10000u) == 0 && packet[3] == 0), "64-bit immediate COPY_DATA is not implemented"); | ||
| break; | ||
| } | ||
|
|
@@ -594,10 +617,11 @@ std::optional<StoreWrite> ResolveStore(std::span<const std::uint32_t> packet, co | |
| case 0x40: { | ||
| if (packet.size() < 6 || copyDataToRegister(packet)) return std::nullopt; | ||
| const auto source = ((packet[1] & 0xfu) << 1u) | ((packet[1] >> 30u) & 1u); | ||
| if (source == CopyDataRegisterSource) return std::nullopt; | ||
| const std::size_t bytes = (packet[1] & 0x10000u) != 0 ? 8 : 4; | ||
| const auto destination = address(packet[4], packet[5]); | ||
| if (!fits(destination, bytes)) return std::nullopt; | ||
| return StoreWrite{destination, {}, copyDataSource(packet, bytes)}; | ||
| return StoreWrite{destination, {}, copyDataSource(packet, queue, bytes)}; | ||
| } | ||
| case 0x50: { | ||
| if (packet.size() < 7 || dmaDestination(packet) == DmaSelectGds) return std::nullopt; | ||
|
|
@@ -816,6 +840,15 @@ std::vector<std::uint32_t> ReadIndirectRegisters(std::span<const std::uint32_t> | |
| return pairs; | ||
| } | ||
|
|
||
| void NoteDispatchRegisters(std::span<const std::uint32_t> packet, QueueState& queue) { | ||
| const bool direct = ((packet[0] >> 8u) & 0xffu) == 0x15u; | ||
| queue.shader.insert_or_assign(0x200, packet.back()); | ||
|
Comment on lines
+843
to
+845
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When the Metal backend is enabled, Useful? React with 👍 / 👎. |
||
| for (std::uint32_t i = 0; i < 3; ++i) { | ||
| if (direct) queue.shader.insert_or_assign(0x201 + i, packet[1 + i]); | ||
| else queue.shader.erase(0x201 + i); | ||
| } | ||
| } | ||
|
|
||
| void ExecuteIndirectRegisters(std::span<const std::uint32_t> packet, std::span<const std::uint32_t> pairs, QueueState& queue) { | ||
| const auto opcode = (packet[0] >> 8u) & 0xffu; | ||
| require(packet.size() == 5 && IndirectRegisterOpcode(opcode), "expected indirect register packet"); | ||
|
|
@@ -945,7 +978,7 @@ void Execute(std::span<const std::uint32_t> packet, QueueState& queue) { | |
| return; | ||
| } | ||
| const auto destination = address(packet[4], packet[5]); | ||
| const auto data = copyDataSource(packet, (packet[1] & 0x10000u) != 0 ? 8 : 4); | ||
| const auto data = copyDataSource(packet, queue, (packet[1] & 0x10000u) != 0 ? 8 : 4); | ||
| GuestMemory::CheckRange(reinterpret_cast<void*>(destination), data.size(), 1, true); | ||
| GuestMemory::Write(destination, data); | ||
| return; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -50,6 +50,13 @@ TextureDimension resolveDimension(std::uint32_t raw) { | |
|
|
||
| } | ||
|
|
||
| bool IsNullTextureResource(std::span<const std::uint32_t> words) { | ||
| Require(words.size() == 8, "guest texture descriptor must contain 8 dwords"); | ||
| const auto base40 = (static_cast<std::uint64_t>(words[0]) | (static_cast<std::uint64_t>(words[1]) << 32u)) & 0xffffffffffull; | ||
| const auto type = (words[3] >> 28u) & 0xfu; | ||
| return base40 == 0 || type == 0; | ||
|
Comment on lines
+53
to
+57
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For Metal draws containing a type-0 texture descriptor with a nonzero base, Useful? React with 👍 / 👎. |
||
| } | ||
|
|
||
| GuestTextureResource DecodeTextureResource(std::span<const std::uint32_t> words) { | ||
| Require(words.size() == 8, "guest texture descriptor must contain 8 dwords"); | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On Metal,
Execution/Metal/MetalPacketExecution.mm:739-745still sends every counted NOP throughPm4::Validateand laterPm4::Executeinstead of checking this predicate. Besides missing the intended fast path, a pure NOP whose ignored payload begins with0x6875still triggers the typed-user-data rejection inValidate, so command streams accepted by the shared executor can fail on Metal; applyPureNopPacketbefore Metal validation as well.Useful? React with 👍 / 👎.